Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // JZ4725B CODEC driver
0004 //
0005 // Copyright (C) 2019, Paul Cercueil <paul@crapouillou.net>
0006 
0007 #include <linux/kernel.h>
0008 #include <linux/module.h>
0009 #include <linux/platform_device.h>
0010 #include <linux/slab.h>
0011 #include <linux/io.h>
0012 #include <linux/iopoll.h>
0013 #include <linux/regmap.h>
0014 #include <linux/clk.h>
0015 
0016 #include <linux/delay.h>
0017 
0018 #include <sound/core.h>
0019 #include <sound/pcm.h>
0020 #include <sound/pcm_params.h>
0021 #include <sound/initval.h>
0022 #include <sound/soc.h>
0023 #include <sound/tlv.h>
0024 
0025 #define ICDC_RGADW_OFFSET       0x00
0026 #define ICDC_RGDATA_OFFSET      0x04
0027 
0028 /* ICDC internal register access control register(RGADW) */
0029 #define ICDC_RGADW_RGWR         BIT(16)
0030 
0031 #define ICDC_RGADW_RGADDR_OFFSET    8
0032 #define ICDC_RGADW_RGADDR_MASK      GENMASK(14, ICDC_RGADW_RGADDR_OFFSET)
0033 
0034 #define ICDC_RGADW_RGDIN_OFFSET     0
0035 #define ICDC_RGADW_RGDIN_MASK       GENMASK(7, ICDC_RGADW_RGDIN_OFFSET)
0036 
0037 /* ICDC internal register data output register (RGDATA)*/
0038 #define ICDC_RGDATA_IRQ         BIT(8)
0039 
0040 #define ICDC_RGDATA_RGDOUT_OFFSET   0
0041 #define ICDC_RGDATA_RGDOUT_MASK     GENMASK(7, ICDC_RGDATA_RGDOUT_OFFSET)
0042 
0043 /* JZ internal register space */
0044 enum {
0045     JZ4725B_CODEC_REG_AICR,
0046     JZ4725B_CODEC_REG_CR1,
0047     JZ4725B_CODEC_REG_CR2,
0048     JZ4725B_CODEC_REG_CCR1,
0049     JZ4725B_CODEC_REG_CCR2,
0050     JZ4725B_CODEC_REG_PMR1,
0051     JZ4725B_CODEC_REG_PMR2,
0052     JZ4725B_CODEC_REG_CRR,
0053     JZ4725B_CODEC_REG_ICR,
0054     JZ4725B_CODEC_REG_IFR,
0055     JZ4725B_CODEC_REG_CGR1,
0056     JZ4725B_CODEC_REG_CGR2,
0057     JZ4725B_CODEC_REG_CGR3,
0058     JZ4725B_CODEC_REG_CGR4,
0059     JZ4725B_CODEC_REG_CGR5,
0060     JZ4725B_CODEC_REG_CGR6,
0061     JZ4725B_CODEC_REG_CGR7,
0062     JZ4725B_CODEC_REG_CGR8,
0063     JZ4725B_CODEC_REG_CGR9,
0064     JZ4725B_CODEC_REG_CGR10,
0065     JZ4725B_CODEC_REG_TR1,
0066     JZ4725B_CODEC_REG_TR2,
0067     JZ4725B_CODEC_REG_CR3,
0068     JZ4725B_CODEC_REG_AGC1,
0069     JZ4725B_CODEC_REG_AGC2,
0070     JZ4725B_CODEC_REG_AGC3,
0071     JZ4725B_CODEC_REG_AGC4,
0072     JZ4725B_CODEC_REG_AGC5,
0073 };
0074 
0075 #define REG_AICR_CONFIG1_OFFSET     0
0076 #define REG_AICR_CONFIG1_MASK       (0xf << REG_AICR_CONFIG1_OFFSET)
0077 
0078 #define REG_CR1_SB_MICBIAS_OFFSET   7
0079 #define REG_CR1_MONO_OFFSET     6
0080 #define REG_CR1_DAC_MUTE_OFFSET     5
0081 #define REG_CR1_HP_DIS_OFFSET       4
0082 #define REG_CR1_DACSEL_OFFSET       3
0083 #define REG_CR1_BYPASS_OFFSET       2
0084 
0085 #define REG_CR2_DAC_DEEMP_OFFSET    7
0086 #define REG_CR2_DAC_ADWL_OFFSET     5
0087 #define REG_CR2_DAC_ADWL_MASK       (0x3 << REG_CR2_DAC_ADWL_OFFSET)
0088 #define REG_CR2_ADC_ADWL_OFFSET     3
0089 #define REG_CR2_ADC_ADWL_MASK       (0x3 << REG_CR2_ADC_ADWL_OFFSET)
0090 #define REG_CR2_ADC_HPF_OFFSET      2
0091 
0092 #define REG_CR3_SB_MIC1_OFFSET      7
0093 #define REG_CR3_SB_MIC2_OFFSET      6
0094 #define REG_CR3_SIDETONE1_OFFSET    5
0095 #define REG_CR3_SIDETONE2_OFFSET    4
0096 #define REG_CR3_MICDIFF_OFFSET      3
0097 #define REG_CR3_MICSTEREO_OFFSET    2
0098 #define REG_CR3_INSEL_OFFSET        0
0099 #define REG_CR3_INSEL_MASK      (0x3 << REG_CR3_INSEL_OFFSET)
0100 
0101 #define REG_CCR1_CONFIG4_OFFSET     0
0102 #define REG_CCR1_CONFIG4_MASK       (0xf << REG_CCR1_CONFIG4_OFFSET)
0103 
0104 #define REG_CCR2_DFREQ_OFFSET       4
0105 #define REG_CCR2_DFREQ_MASK     (0xf << REG_CCR2_DFREQ_OFFSET)
0106 #define REG_CCR2_AFREQ_OFFSET       0
0107 #define REG_CCR2_AFREQ_MASK     (0xf << REG_CCR2_AFREQ_OFFSET)
0108 
0109 #define REG_PMR1_SB_DAC_OFFSET      7
0110 #define REG_PMR1_SB_OUT_OFFSET      6
0111 #define REG_PMR1_SB_MIX_OFFSET      5
0112 #define REG_PMR1_SB_ADC_OFFSET      4
0113 #define REG_PMR1_SB_LIN_OFFSET      3
0114 #define REG_PMR1_SB_IND_OFFSET      0
0115 
0116 #define REG_PMR2_LRGI_OFFSET        7
0117 #define REG_PMR2_RLGI_OFFSET        6
0118 #define REG_PMR2_LRGOD_OFFSET       5
0119 #define REG_PMR2_RLGOD_OFFSET       4
0120 #define REG_PMR2_GIM_OFFSET     3
0121 #define REG_PMR2_SB_MC_OFFSET       2
0122 #define REG_PMR2_SB_OFFSET      1
0123 #define REG_PMR2_SB_SLEEP_OFFSET    0
0124 
0125 #define REG_IFR_RAMP_UP_DONE_OFFSET 3
0126 #define REG_IFR_RAMP_DOWN_DONE_OFFSET   2
0127 
0128 #define REG_CGR1_GODL_OFFSET        4
0129 #define REG_CGR1_GODL_MASK      (0xf << REG_CGR1_GODL_OFFSET)
0130 #define REG_CGR1_GODR_OFFSET        0
0131 #define REG_CGR1_GODR_MASK      (0xf << REG_CGR1_GODR_OFFSET)
0132 
0133 #define REG_CGR2_GO1R_OFFSET        0
0134 #define REG_CGR2_GO1R_MASK      (0x1f << REG_CGR2_GO1R_OFFSET)
0135 
0136 #define REG_CGR3_GO1L_OFFSET        0
0137 #define REG_CGR3_GO1L_MASK      (0x1f << REG_CGR3_GO1L_OFFSET)
0138 
0139 struct jz_icdc {
0140     struct regmap *regmap;
0141     void __iomem *base;
0142     struct clk *clk;
0143 };
0144 
0145 static const SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(jz4725b_dac_tlv, -2250, 0);
0146 static const SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(jz4725b_line_tlv, -1500, 600);
0147 
0148 static const struct snd_kcontrol_new jz4725b_codec_controls[] = {
0149     SOC_DOUBLE_TLV("Master Playback Volume",
0150                JZ4725B_CODEC_REG_CGR1,
0151                REG_CGR1_GODL_OFFSET,
0152                REG_CGR1_GODR_OFFSET,
0153                0xf, 1, jz4725b_dac_tlv),
0154     SOC_DOUBLE_R_TLV("Master Capture Volume",
0155              JZ4725B_CODEC_REG_CGR3,
0156              JZ4725B_CODEC_REG_CGR2,
0157              REG_CGR2_GO1R_OFFSET,
0158              0x1f, 1, jz4725b_line_tlv),
0159 
0160     SOC_SINGLE("Master Playback Switch", JZ4725B_CODEC_REG_CR1,
0161            REG_CR1_DAC_MUTE_OFFSET, 1, 1),
0162 
0163     SOC_SINGLE("Deemphasize Filter Playback Switch",
0164            JZ4725B_CODEC_REG_CR2,
0165            REG_CR2_DAC_DEEMP_OFFSET, 1, 0),
0166 
0167     SOC_SINGLE("High-Pass Filter Capture Switch",
0168            JZ4725B_CODEC_REG_CR2,
0169            REG_CR2_ADC_HPF_OFFSET, 1, 0),
0170 };
0171 
0172 static const char * const jz4725b_codec_adc_src_texts[] = {
0173     "Mic 1", "Mic 2", "Line In", "Mixer",
0174 };
0175 static const unsigned int jz4725b_codec_adc_src_values[] = { 0, 1, 2, 3, };
0176 static SOC_VALUE_ENUM_SINGLE_DECL(jz4725b_codec_adc_src_enum,
0177                   JZ4725B_CODEC_REG_CR3,
0178                   REG_CR3_INSEL_OFFSET,
0179                   REG_CR3_INSEL_MASK,
0180                   jz4725b_codec_adc_src_texts,
0181                   jz4725b_codec_adc_src_values);
0182 static const struct snd_kcontrol_new jz4725b_codec_adc_src_ctrl =
0183             SOC_DAPM_ENUM("Route", jz4725b_codec_adc_src_enum);
0184 
0185 static const struct snd_kcontrol_new jz4725b_codec_mixer_controls[] = {
0186     SOC_DAPM_SINGLE("Line In Bypass", JZ4725B_CODEC_REG_CR1,
0187             REG_CR1_BYPASS_OFFSET, 1, 0),
0188 };
0189 
0190 static int jz4725b_out_stage_enable(struct snd_soc_dapm_widget *w,
0191                     struct snd_kcontrol *kcontrol,
0192                     int event)
0193 {
0194     struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
0195     struct jz_icdc *icdc = snd_soc_component_get_drvdata(codec);
0196     struct regmap *map = icdc->regmap;
0197     unsigned int val;
0198 
0199     switch (event) {
0200     case SND_SOC_DAPM_PRE_PMU:
0201         return regmap_clear_bits(map, JZ4725B_CODEC_REG_IFR,
0202                      BIT(REG_IFR_RAMP_UP_DONE_OFFSET));
0203     case SND_SOC_DAPM_POST_PMU:
0204         return regmap_read_poll_timeout(map, JZ4725B_CODEC_REG_IFR,
0205                    val, val & BIT(REG_IFR_RAMP_UP_DONE_OFFSET),
0206                    100000, 500000);
0207     case SND_SOC_DAPM_PRE_PMD:
0208         return regmap_clear_bits(map, JZ4725B_CODEC_REG_IFR,
0209                 BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET));
0210     case SND_SOC_DAPM_POST_PMD:
0211         return regmap_read_poll_timeout(map, JZ4725B_CODEC_REG_IFR,
0212                    val, val & BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET),
0213                    100000, 500000);
0214     default:
0215         return -EINVAL;
0216     }
0217 }
0218 
0219 static const struct snd_soc_dapm_widget jz4725b_codec_dapm_widgets[] = {
0220     /* DAC */
0221     SND_SOC_DAPM_DAC("DAC", "Playback",
0222              JZ4725B_CODEC_REG_PMR1, REG_PMR1_SB_DAC_OFFSET, 1),
0223 
0224     /* ADC */
0225     SND_SOC_DAPM_ADC("ADC", "Capture",
0226              JZ4725B_CODEC_REG_PMR1, REG_PMR1_SB_ADC_OFFSET, 1),
0227 
0228     SND_SOC_DAPM_MUX("ADC Source", SND_SOC_NOPM, 0, 0,
0229              &jz4725b_codec_adc_src_ctrl),
0230 
0231     /* Mixer */
0232     SND_SOC_DAPM_MIXER("Mixer", JZ4725B_CODEC_REG_PMR1,
0233                REG_PMR1_SB_MIX_OFFSET, 1,
0234                jz4725b_codec_mixer_controls,
0235                ARRAY_SIZE(jz4725b_codec_mixer_controls)),
0236     SND_SOC_DAPM_MIXER("DAC to Mixer", JZ4725B_CODEC_REG_CR1,
0237                REG_CR1_DACSEL_OFFSET, 0, NULL, 0),
0238 
0239     SND_SOC_DAPM_MIXER("Line In", SND_SOC_NOPM, 0, 0, NULL, 0),
0240     SND_SOC_DAPM_MIXER("HP Out", JZ4725B_CODEC_REG_CR1,
0241                REG_CR1_HP_DIS_OFFSET, 1, NULL, 0),
0242 
0243     SND_SOC_DAPM_MIXER("Mic 1", JZ4725B_CODEC_REG_CR3,
0244                REG_CR3_SB_MIC1_OFFSET, 1, NULL, 0),
0245     SND_SOC_DAPM_MIXER("Mic 2", JZ4725B_CODEC_REG_CR3,
0246                REG_CR3_SB_MIC2_OFFSET, 1, NULL, 0),
0247 
0248     SND_SOC_DAPM_MIXER_E("Out Stage", JZ4725B_CODEC_REG_PMR1,
0249                  REG_PMR1_SB_OUT_OFFSET, 1, NULL, 0,
0250                  jz4725b_out_stage_enable,
0251                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
0252                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
0253     SND_SOC_DAPM_MIXER("Mixer to ADC", JZ4725B_CODEC_REG_PMR1,
0254                REG_PMR1_SB_IND_OFFSET, 1, NULL, 0),
0255 
0256     SND_SOC_DAPM_SUPPLY("Mic Bias", JZ4725B_CODEC_REG_CR1,
0257                 REG_CR1_SB_MICBIAS_OFFSET, 1, NULL, 0),
0258 
0259     /* Pins */
0260     SND_SOC_DAPM_INPUT("MIC1P"),
0261     SND_SOC_DAPM_INPUT("MIC1N"),
0262     SND_SOC_DAPM_INPUT("MIC2P"),
0263     SND_SOC_DAPM_INPUT("MIC2N"),
0264 
0265     SND_SOC_DAPM_INPUT("LLINEIN"),
0266     SND_SOC_DAPM_INPUT("RLINEIN"),
0267 
0268     SND_SOC_DAPM_OUTPUT("LHPOUT"),
0269     SND_SOC_DAPM_OUTPUT("RHPOUT"),
0270 };
0271 
0272 static const struct snd_soc_dapm_route jz4725b_codec_dapm_routes[] = {
0273     {"Mic 1", NULL, "MIC1P"},
0274     {"Mic 1", NULL, "MIC1N"},
0275     {"Mic 2", NULL, "MIC2P"},
0276     {"Mic 2", NULL, "MIC2N"},
0277 
0278     {"Line In", NULL, "LLINEIN"},
0279     {"Line In", NULL, "RLINEIN"},
0280 
0281     {"Mixer", "Line In Bypass", "Line In"},
0282     {"DAC to Mixer", NULL, "DAC"},
0283     {"Mixer", NULL, "DAC to Mixer"},
0284 
0285     {"Mixer to ADC", NULL, "Mixer"},
0286     {"ADC Source", "Mixer", "Mixer to ADC"},
0287     {"ADC Source", "Line In", "Line In"},
0288     {"ADC Source", "Mic 1", "Mic 1"},
0289     {"ADC Source", "Mic 2", "Mic 2"},
0290     {"ADC", NULL, "ADC Source"},
0291 
0292     {"Out Stage", NULL, "Mixer"},
0293     {"HP Out", NULL, "Out Stage"},
0294     {"LHPOUT", NULL, "HP Out"},
0295     {"RHPOUT", NULL, "HP Out"},
0296 };
0297 
0298 static int jz4725b_codec_set_bias_level(struct snd_soc_component *component,
0299                     enum snd_soc_bias_level level)
0300 {
0301     struct jz_icdc *icdc = snd_soc_component_get_drvdata(component);
0302     struct regmap *map = icdc->regmap;
0303 
0304     switch (level) {
0305     case SND_SOC_BIAS_ON:
0306         regmap_clear_bits(map, JZ4725B_CODEC_REG_PMR2,
0307                   BIT(REG_PMR2_SB_SLEEP_OFFSET));
0308         break;
0309     case SND_SOC_BIAS_PREPARE:
0310         /* Enable sound hardware */
0311         regmap_clear_bits(map, JZ4725B_CODEC_REG_PMR2,
0312                   BIT(REG_PMR2_SB_OFFSET));
0313         msleep(224);
0314         break;
0315     case SND_SOC_BIAS_STANDBY:
0316         regmap_set_bits(map, JZ4725B_CODEC_REG_PMR2,
0317                 BIT(REG_PMR2_SB_SLEEP_OFFSET));
0318         break;
0319     case SND_SOC_BIAS_OFF:
0320         regmap_set_bits(map, JZ4725B_CODEC_REG_PMR2,
0321                 BIT(REG_PMR2_SB_OFFSET));
0322         break;
0323     }
0324 
0325     return 0;
0326 }
0327 
0328 static int jz4725b_codec_dev_probe(struct snd_soc_component *component)
0329 {
0330     struct jz_icdc *icdc = snd_soc_component_get_drvdata(component);
0331     struct regmap *map = icdc->regmap;
0332 
0333     clk_prepare_enable(icdc->clk);
0334 
0335     /* Write CONFIGn (n=1 to 8) bits.
0336      * The value 0x0f is specified in the datasheet as a requirement.
0337      */
0338     regmap_write(map, JZ4725B_CODEC_REG_AICR,
0339              0xf << REG_AICR_CONFIG1_OFFSET);
0340     regmap_write(map, JZ4725B_CODEC_REG_CCR1,
0341              0x0 << REG_CCR1_CONFIG4_OFFSET);
0342 
0343     return 0;
0344 }
0345 
0346 static void jz4725b_codec_dev_remove(struct snd_soc_component *component)
0347 {
0348     struct jz_icdc *icdc = snd_soc_component_get_drvdata(component);
0349 
0350     clk_disable_unprepare(icdc->clk);
0351 }
0352 
0353 static const struct snd_soc_component_driver jz4725b_codec = {
0354     .probe          = jz4725b_codec_dev_probe,
0355     .remove         = jz4725b_codec_dev_remove,
0356     .set_bias_level     = jz4725b_codec_set_bias_level,
0357     .controls       = jz4725b_codec_controls,
0358     .num_controls       = ARRAY_SIZE(jz4725b_codec_controls),
0359     .dapm_widgets       = jz4725b_codec_dapm_widgets,
0360     .num_dapm_widgets   = ARRAY_SIZE(jz4725b_codec_dapm_widgets),
0361     .dapm_routes        = jz4725b_codec_dapm_routes,
0362     .num_dapm_routes    = ARRAY_SIZE(jz4725b_codec_dapm_routes),
0363     .suspend_bias_off   = 1,
0364     .use_pmdown_time    = 1,
0365 };
0366 
0367 static const unsigned int jz4725b_codec_sample_rates[] = {
0368     96000, 48000, 44100, 32000,
0369     24000, 22050, 16000, 12000,
0370     11025, 9600, 8000,
0371 };
0372 
0373 static int jz4725b_codec_hw_params(struct snd_pcm_substream *substream,
0374     struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
0375 {
0376     struct jz_icdc *icdc = snd_soc_component_get_drvdata(dai->component);
0377     unsigned int rate, bit_width;
0378 
0379     switch (params_format(params)) {
0380     case SNDRV_PCM_FORMAT_S16_LE:
0381         bit_width = 0;
0382         break;
0383     case SNDRV_PCM_FORMAT_S18_3LE:
0384         bit_width = 1;
0385         break;
0386     case SNDRV_PCM_FORMAT_S20_3LE:
0387         bit_width = 2;
0388         break;
0389     case SNDRV_PCM_FORMAT_S24_3LE:
0390         bit_width = 3;
0391         break;
0392     default:
0393         return -EINVAL;
0394     }
0395 
0396     for (rate = 0; rate < ARRAY_SIZE(jz4725b_codec_sample_rates); rate++) {
0397         if (jz4725b_codec_sample_rates[rate] == params_rate(params))
0398             break;
0399     }
0400 
0401     if (rate == ARRAY_SIZE(jz4725b_codec_sample_rates))
0402         return -EINVAL;
0403 
0404     if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0405         regmap_update_bits(icdc->regmap,
0406                    JZ4725B_CODEC_REG_CR2,
0407                    REG_CR2_DAC_ADWL_MASK,
0408                    bit_width << REG_CR2_DAC_ADWL_OFFSET);
0409 
0410         regmap_update_bits(icdc->regmap,
0411                    JZ4725B_CODEC_REG_CCR2,
0412                    REG_CCR2_DFREQ_MASK,
0413                    rate << REG_CCR2_DFREQ_OFFSET);
0414     } else {
0415         regmap_update_bits(icdc->regmap,
0416                    JZ4725B_CODEC_REG_CR2,
0417                    REG_CR2_ADC_ADWL_MASK,
0418                    bit_width << REG_CR2_ADC_ADWL_OFFSET);
0419 
0420         regmap_update_bits(icdc->regmap,
0421                    JZ4725B_CODEC_REG_CCR2,
0422                    REG_CCR2_AFREQ_MASK,
0423                    rate << REG_CCR2_AFREQ_OFFSET);
0424     }
0425 
0426     return 0;
0427 }
0428 
0429 static const struct snd_soc_dai_ops jz4725b_codec_dai_ops = {
0430     .hw_params = jz4725b_codec_hw_params,
0431 };
0432 
0433 #define JZ_ICDC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S18_3LE | \
0434              SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_3LE)
0435 
0436 static struct snd_soc_dai_driver jz4725b_codec_dai = {
0437     .name = "jz4725b-hifi",
0438     .playback = {
0439         .stream_name = "Playback",
0440         .channels_min = 2,
0441         .channels_max = 2,
0442         .rates = SNDRV_PCM_RATE_8000_96000,
0443         .formats = JZ_ICDC_FORMATS,
0444     },
0445     .capture = {
0446         .stream_name = "Capture",
0447         .channels_min = 2,
0448         .channels_max = 2,
0449         .rates = SNDRV_PCM_RATE_8000_96000,
0450         .formats = JZ_ICDC_FORMATS,
0451     },
0452     .ops = &jz4725b_codec_dai_ops,
0453 };
0454 
0455 static bool jz4725b_codec_volatile(struct device *dev, unsigned int reg)
0456 {
0457     return reg == JZ4725B_CODEC_REG_IFR;
0458 }
0459 
0460 static bool jz4725b_codec_can_access_reg(struct device *dev, unsigned int reg)
0461 {
0462     return (reg != JZ4725B_CODEC_REG_TR1) && (reg != JZ4725B_CODEC_REG_TR2);
0463 }
0464 
0465 static int jz4725b_codec_io_wait(struct jz_icdc *icdc)
0466 {
0467     u32 reg;
0468 
0469     return readl_poll_timeout(icdc->base + ICDC_RGADW_OFFSET, reg,
0470                   !(reg & ICDC_RGADW_RGWR), 1000, 10000);
0471 }
0472 
0473 static int jz4725b_codec_reg_read(void *context, unsigned int reg,
0474                   unsigned int *val)
0475 {
0476     struct jz_icdc *icdc = context;
0477     unsigned int i;
0478     u32 tmp;
0479     int ret;
0480 
0481     ret = jz4725b_codec_io_wait(icdc);
0482     if (ret)
0483         return ret;
0484 
0485     tmp = readl(icdc->base + ICDC_RGADW_OFFSET);
0486     tmp = (tmp & ~ICDC_RGADW_RGADDR_MASK)
0487         | (reg << ICDC_RGADW_RGADDR_OFFSET);
0488     writel(tmp, icdc->base + ICDC_RGADW_OFFSET);
0489 
0490     /* wait 6+ cycles */
0491     for (i = 0; i < 6; i++)
0492         *val = readl(icdc->base + ICDC_RGDATA_OFFSET) &
0493             ICDC_RGDATA_RGDOUT_MASK;
0494 
0495     return 0;
0496 }
0497 
0498 static int jz4725b_codec_reg_write(void *context, unsigned int reg,
0499                    unsigned int val)
0500 {
0501     struct jz_icdc *icdc = context;
0502     int ret;
0503 
0504     ret = jz4725b_codec_io_wait(icdc);
0505     if (ret)
0506         return ret;
0507 
0508     writel(ICDC_RGADW_RGWR | (reg << ICDC_RGADW_RGADDR_OFFSET) | val,
0509             icdc->base + ICDC_RGADW_OFFSET);
0510 
0511     ret = jz4725b_codec_io_wait(icdc);
0512     if (ret)
0513         return ret;
0514 
0515     return 0;
0516 }
0517 
0518 static const u8 jz4725b_codec_reg_defaults[] = {
0519     0x0c, 0xaa, 0x78, 0x00, 0x00, 0xff, 0x03, 0x51,
0520     0x3f, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04,
0521     0x04, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0xc0, 0x34,
0522     0x07, 0x44, 0x1f, 0x00,
0523 };
0524 
0525 static const struct regmap_config jz4725b_codec_regmap_config = {
0526     .reg_bits = 7,
0527     .val_bits = 8,
0528 
0529     .max_register = JZ4725B_CODEC_REG_AGC5,
0530     .volatile_reg = jz4725b_codec_volatile,
0531     .readable_reg = jz4725b_codec_can_access_reg,
0532     .writeable_reg = jz4725b_codec_can_access_reg,
0533 
0534     .reg_read = jz4725b_codec_reg_read,
0535     .reg_write = jz4725b_codec_reg_write,
0536 
0537     .reg_defaults_raw = jz4725b_codec_reg_defaults,
0538     .num_reg_defaults_raw = ARRAY_SIZE(jz4725b_codec_reg_defaults),
0539     .cache_type = REGCACHE_FLAT,
0540 };
0541 
0542 static int jz4725b_codec_probe(struct platform_device *pdev)
0543 {
0544     struct device *dev = &pdev->dev;
0545     struct jz_icdc *icdc;
0546     int ret;
0547 
0548     icdc = devm_kzalloc(dev, sizeof(*icdc), GFP_KERNEL);
0549     if (!icdc)
0550         return -ENOMEM;
0551 
0552     icdc->base = devm_platform_ioremap_resource(pdev, 0);
0553     if (IS_ERR(icdc->base))
0554         return PTR_ERR(icdc->base);
0555 
0556     icdc->regmap = devm_regmap_init(dev, NULL, icdc,
0557                     &jz4725b_codec_regmap_config);
0558     if (IS_ERR(icdc->regmap))
0559         return PTR_ERR(icdc->regmap);
0560 
0561     icdc->clk = devm_clk_get(&pdev->dev, "aic");
0562     if (IS_ERR(icdc->clk))
0563         return PTR_ERR(icdc->clk);
0564 
0565     platform_set_drvdata(pdev, icdc);
0566 
0567     ret = devm_snd_soc_register_component(dev, &jz4725b_codec,
0568                           &jz4725b_codec_dai, 1);
0569     if (ret)
0570         dev_err(dev, "Failed to register codec\n");
0571 
0572     return ret;
0573 }
0574 
0575 static const struct of_device_id jz4725b_codec_of_matches[] = {
0576     { .compatible = "ingenic,jz4725b-codec", },
0577     { }
0578 };
0579 MODULE_DEVICE_TABLE(of, jz4725b_codec_of_matches);
0580 
0581 static struct platform_driver jz4725b_codec_driver = {
0582     .probe = jz4725b_codec_probe,
0583     .driver = {
0584         .name = "jz4725b-codec",
0585         .of_match_table = jz4725b_codec_of_matches,
0586     },
0587 };
0588 module_platform_driver(jz4725b_codec_driver);
0589 
0590 MODULE_DESCRIPTION("JZ4725B SoC internal codec driver");
0591 MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
0592 MODULE_LICENSE("GPL v2");