162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// JZ4725B CODEC driver 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright (C) 2019, Paul Cercueil <paul@crapouillou.net> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/platform_device.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <linux/io.h> 1262306a36Sopenharmony_ci#include <linux/iopoll.h> 1362306a36Sopenharmony_ci#include <linux/regmap.h> 1462306a36Sopenharmony_ci#include <linux/clk.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/delay.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <sound/core.h> 1962306a36Sopenharmony_ci#include <sound/pcm.h> 2062306a36Sopenharmony_ci#include <sound/pcm_params.h> 2162306a36Sopenharmony_ci#include <sound/initval.h> 2262306a36Sopenharmony_ci#include <sound/soc.h> 2362306a36Sopenharmony_ci#include <sound/tlv.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define ICDC_RGADW_OFFSET 0x00 2662306a36Sopenharmony_ci#define ICDC_RGDATA_OFFSET 0x04 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* ICDC internal register access control register(RGADW) */ 2962306a36Sopenharmony_ci#define ICDC_RGADW_RGWR BIT(16) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define ICDC_RGADW_RGADDR_OFFSET 8 3262306a36Sopenharmony_ci#define ICDC_RGADW_RGADDR_MASK GENMASK(14, ICDC_RGADW_RGADDR_OFFSET) 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define ICDC_RGADW_RGDIN_OFFSET 0 3562306a36Sopenharmony_ci#define ICDC_RGADW_RGDIN_MASK GENMASK(7, ICDC_RGADW_RGDIN_OFFSET) 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* ICDC internal register data output register (RGDATA)*/ 3862306a36Sopenharmony_ci#define ICDC_RGDATA_IRQ BIT(8) 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define ICDC_RGDATA_RGDOUT_OFFSET 0 4162306a36Sopenharmony_ci#define ICDC_RGDATA_RGDOUT_MASK GENMASK(7, ICDC_RGDATA_RGDOUT_OFFSET) 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* JZ internal register space */ 4462306a36Sopenharmony_cienum { 4562306a36Sopenharmony_ci JZ4725B_CODEC_REG_AICR, 4662306a36Sopenharmony_ci JZ4725B_CODEC_REG_CR1, 4762306a36Sopenharmony_ci JZ4725B_CODEC_REG_CR2, 4862306a36Sopenharmony_ci JZ4725B_CODEC_REG_CCR1, 4962306a36Sopenharmony_ci JZ4725B_CODEC_REG_CCR2, 5062306a36Sopenharmony_ci JZ4725B_CODEC_REG_PMR1, 5162306a36Sopenharmony_ci JZ4725B_CODEC_REG_PMR2, 5262306a36Sopenharmony_ci JZ4725B_CODEC_REG_CRR, 5362306a36Sopenharmony_ci JZ4725B_CODEC_REG_ICR, 5462306a36Sopenharmony_ci JZ4725B_CODEC_REG_IFR, 5562306a36Sopenharmony_ci JZ4725B_CODEC_REG_CGR1, 5662306a36Sopenharmony_ci JZ4725B_CODEC_REG_CGR2, 5762306a36Sopenharmony_ci JZ4725B_CODEC_REG_CGR3, 5862306a36Sopenharmony_ci JZ4725B_CODEC_REG_CGR4, 5962306a36Sopenharmony_ci JZ4725B_CODEC_REG_CGR5, 6062306a36Sopenharmony_ci JZ4725B_CODEC_REG_CGR6, 6162306a36Sopenharmony_ci JZ4725B_CODEC_REG_CGR7, 6262306a36Sopenharmony_ci JZ4725B_CODEC_REG_CGR8, 6362306a36Sopenharmony_ci JZ4725B_CODEC_REG_CGR9, 6462306a36Sopenharmony_ci JZ4725B_CODEC_REG_CGR10, 6562306a36Sopenharmony_ci JZ4725B_CODEC_REG_TR1, 6662306a36Sopenharmony_ci JZ4725B_CODEC_REG_TR2, 6762306a36Sopenharmony_ci JZ4725B_CODEC_REG_CR3, 6862306a36Sopenharmony_ci JZ4725B_CODEC_REG_AGC1, 6962306a36Sopenharmony_ci JZ4725B_CODEC_REG_AGC2, 7062306a36Sopenharmony_ci JZ4725B_CODEC_REG_AGC3, 7162306a36Sopenharmony_ci JZ4725B_CODEC_REG_AGC4, 7262306a36Sopenharmony_ci JZ4725B_CODEC_REG_AGC5, 7362306a36Sopenharmony_ci}; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#define REG_AICR_CONFIG1_OFFSET 0 7662306a36Sopenharmony_ci#define REG_AICR_CONFIG1_MASK (0xf << REG_AICR_CONFIG1_OFFSET) 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#define REG_CR1_SB_MICBIAS_OFFSET 7 7962306a36Sopenharmony_ci#define REG_CR1_MONO_OFFSET 6 8062306a36Sopenharmony_ci#define REG_CR1_DAC_MUTE_OFFSET 5 8162306a36Sopenharmony_ci#define REG_CR1_HP_DIS_OFFSET 4 8262306a36Sopenharmony_ci#define REG_CR1_DACSEL_OFFSET 3 8362306a36Sopenharmony_ci#define REG_CR1_BYPASS_OFFSET 2 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci#define REG_CR2_DAC_DEEMP_OFFSET 7 8662306a36Sopenharmony_ci#define REG_CR2_DAC_ADWL_OFFSET 5 8762306a36Sopenharmony_ci#define REG_CR2_DAC_ADWL_MASK (0x3 << REG_CR2_DAC_ADWL_OFFSET) 8862306a36Sopenharmony_ci#define REG_CR2_ADC_ADWL_OFFSET 3 8962306a36Sopenharmony_ci#define REG_CR2_ADC_ADWL_MASK (0x3 << REG_CR2_ADC_ADWL_OFFSET) 9062306a36Sopenharmony_ci#define REG_CR2_ADC_HPF_OFFSET 2 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci#define REG_CR3_SB_MIC1_OFFSET 7 9362306a36Sopenharmony_ci#define REG_CR3_SB_MIC2_OFFSET 6 9462306a36Sopenharmony_ci#define REG_CR3_SIDETONE1_OFFSET 5 9562306a36Sopenharmony_ci#define REG_CR3_SIDETONE2_OFFSET 4 9662306a36Sopenharmony_ci#define REG_CR3_MICDIFF_OFFSET 3 9762306a36Sopenharmony_ci#define REG_CR3_MICSTEREO_OFFSET 2 9862306a36Sopenharmony_ci#define REG_CR3_INSEL_OFFSET 0 9962306a36Sopenharmony_ci#define REG_CR3_INSEL_MASK (0x3 << REG_CR3_INSEL_OFFSET) 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci#define REG_CCR1_CONFIG4_OFFSET 0 10262306a36Sopenharmony_ci#define REG_CCR1_CONFIG4_MASK (0xf << REG_CCR1_CONFIG4_OFFSET) 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci#define REG_CCR2_DFREQ_OFFSET 4 10562306a36Sopenharmony_ci#define REG_CCR2_DFREQ_MASK (0xf << REG_CCR2_DFREQ_OFFSET) 10662306a36Sopenharmony_ci#define REG_CCR2_AFREQ_OFFSET 0 10762306a36Sopenharmony_ci#define REG_CCR2_AFREQ_MASK (0xf << REG_CCR2_AFREQ_OFFSET) 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci#define REG_PMR1_SB_DAC_OFFSET 7 11062306a36Sopenharmony_ci#define REG_PMR1_SB_OUT_OFFSET 6 11162306a36Sopenharmony_ci#define REG_PMR1_SB_MIX_OFFSET 5 11262306a36Sopenharmony_ci#define REG_PMR1_SB_ADC_OFFSET 4 11362306a36Sopenharmony_ci#define REG_PMR1_SB_LIN_OFFSET 3 11462306a36Sopenharmony_ci#define REG_PMR1_SB_IND_OFFSET 0 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci#define REG_PMR2_LRGI_OFFSET 7 11762306a36Sopenharmony_ci#define REG_PMR2_RLGI_OFFSET 6 11862306a36Sopenharmony_ci#define REG_PMR2_LRGOD_OFFSET 5 11962306a36Sopenharmony_ci#define REG_PMR2_RLGOD_OFFSET 4 12062306a36Sopenharmony_ci#define REG_PMR2_GIM_OFFSET 3 12162306a36Sopenharmony_ci#define REG_PMR2_SB_MC_OFFSET 2 12262306a36Sopenharmony_ci#define REG_PMR2_SB_OFFSET 1 12362306a36Sopenharmony_ci#define REG_PMR2_SB_SLEEP_OFFSET 0 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci#define REG_IFR_RAMP_UP_DONE_OFFSET 3 12662306a36Sopenharmony_ci#define REG_IFR_RAMP_DOWN_DONE_OFFSET 2 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci#define REG_CGR1_GODL_OFFSET 4 12962306a36Sopenharmony_ci#define REG_CGR1_GODL_MASK (0xf << REG_CGR1_GODL_OFFSET) 13062306a36Sopenharmony_ci#define REG_CGR1_GODR_OFFSET 0 13162306a36Sopenharmony_ci#define REG_CGR1_GODR_MASK (0xf << REG_CGR1_GODR_OFFSET) 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci#define REG_CGR2_GO1R_OFFSET 0 13462306a36Sopenharmony_ci#define REG_CGR2_GO1R_MASK (0x1f << REG_CGR2_GO1R_OFFSET) 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci#define REG_CGR3_GO1L_OFFSET 0 13762306a36Sopenharmony_ci#define REG_CGR3_GO1L_MASK (0x1f << REG_CGR3_GO1L_OFFSET) 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci#define REG_CGR4_GO2R_OFFSET 0 14062306a36Sopenharmony_ci#define REG_CGR4_GO2R_MASK (0x1f << REG_CGR4_GO2R_OFFSET) 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci#define REG_CGR5_GO2L_OFFSET 0 14362306a36Sopenharmony_ci#define REG_CGR5_GO2L_MASK (0x1f << REG_CGR5_GO2L_OFFSET) 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci#define REG_CGR6_GO3R_OFFSET 0 14662306a36Sopenharmony_ci#define REG_CGR6_GO3R_MASK (0x1f << REG_CGR6_GO3R_OFFSET) 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci#define REG_CGR7_GO3L_OFFSET 0 14962306a36Sopenharmony_ci#define REG_CGR7_GO3L_MASK (0x1f << REG_CGR7_GO3L_OFFSET) 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci#define REG_CGR8_GOR_OFFSET 0 15262306a36Sopenharmony_ci#define REG_CGR8_GOR_MASK (0x1f << REG_CGR8_GOR_OFFSET) 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci#define REG_CGR9_GOL_OFFSET 0 15562306a36Sopenharmony_ci#define REG_CGR9_GOL_MASK (0x1f << REG_CGR9_GOL_OFFSET) 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci#define REG_CGR10_GIL_OFFSET 0 15862306a36Sopenharmony_ci#define REG_CGR10_GIR_OFFSET 4 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistruct jz_icdc { 16162306a36Sopenharmony_ci struct regmap *regmap; 16262306a36Sopenharmony_ci void __iomem *base; 16362306a36Sopenharmony_ci struct clk *clk; 16462306a36Sopenharmony_ci}; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_adc_tlv, 0, 150, 0); 16762306a36Sopenharmony_cistatic const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_dac_tlv, -2250, 150, 0); 16862306a36Sopenharmony_cistatic const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(jz4725b_mix_tlv, 16962306a36Sopenharmony_ci 0, 11, TLV_DB_SCALE_ITEM(-2250, 0, 0), 17062306a36Sopenharmony_ci 12, 31, TLV_DB_SCALE_ITEM(-2250, 150, 0), 17162306a36Sopenharmony_ci); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(jz4725b_out_tlv, 17462306a36Sopenharmony_ci 0, 11, TLV_DB_SCALE_ITEM(-3350, 200, 0), 17562306a36Sopenharmony_ci 12, 23, TLV_DB_SCALE_ITEM(-1050, 100, 0), 17662306a36Sopenharmony_ci 24, 31, TLV_DB_SCALE_ITEM( 100, 50, 0), 17762306a36Sopenharmony_ci); 17862306a36Sopenharmony_cistatic const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_mic_boost_tlv, 0, 2000, 0); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic const char * const jz4725b_mic_mode_texts[] = { 18162306a36Sopenharmony_ci "Single Ended", "Differential", 18262306a36Sopenharmony_ci}; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic const struct soc_enum jz4725b_mic_mode_enum = 18562306a36Sopenharmony_ci SOC_ENUM_SINGLE(JZ4725B_CODEC_REG_CR3, REG_CR3_MICDIFF_OFFSET, 18662306a36Sopenharmony_ci 2, jz4725b_mic_mode_texts); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic const struct snd_kcontrol_new jz4725b_codec_controls[] = { 18962306a36Sopenharmony_ci SOC_DOUBLE_TLV("DAC Playback Volume", 19062306a36Sopenharmony_ci JZ4725B_CODEC_REG_CGR1, 19162306a36Sopenharmony_ci REG_CGR1_GODL_OFFSET, 19262306a36Sopenharmony_ci REG_CGR1_GODR_OFFSET, 19362306a36Sopenharmony_ci 0xf, 1, jz4725b_dac_tlv), 19462306a36Sopenharmony_ci SOC_DOUBLE_TLV("Master Capture Volume", 19562306a36Sopenharmony_ci JZ4725B_CODEC_REG_CGR10, 19662306a36Sopenharmony_ci REG_CGR10_GIL_OFFSET, 19762306a36Sopenharmony_ci REG_CGR10_GIR_OFFSET, 19862306a36Sopenharmony_ci 0xf, 0, jz4725b_adc_tlv), 19962306a36Sopenharmony_ci SOC_DOUBLE_R_TLV("Mixer Line In Bypass Playback Volume", 20062306a36Sopenharmony_ci JZ4725B_CODEC_REG_CGR3, 20162306a36Sopenharmony_ci JZ4725B_CODEC_REG_CGR2, 20262306a36Sopenharmony_ci REG_CGR2_GO1R_OFFSET, 20362306a36Sopenharmony_ci 0x1f, 1, jz4725b_mix_tlv), 20462306a36Sopenharmony_ci SOC_DOUBLE_R_TLV("Mixer Mic 1 Bypass Playback Volume", 20562306a36Sopenharmony_ci JZ4725B_CODEC_REG_CGR5, 20662306a36Sopenharmony_ci JZ4725B_CODEC_REG_CGR4, 20762306a36Sopenharmony_ci REG_CGR4_GO2R_OFFSET, 20862306a36Sopenharmony_ci 0x1f, 1, jz4725b_mix_tlv), 20962306a36Sopenharmony_ci SOC_DOUBLE_R_TLV("Mixer Mic 2 Bypass Playback Volume", 21062306a36Sopenharmony_ci JZ4725B_CODEC_REG_CGR7, 21162306a36Sopenharmony_ci JZ4725B_CODEC_REG_CGR6, 21262306a36Sopenharmony_ci REG_CGR6_GO3R_OFFSET, 21362306a36Sopenharmony_ci 0x1f, 1, jz4725b_mix_tlv), 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci SOC_DOUBLE_R_TLV("Master Playback Volume", 21662306a36Sopenharmony_ci JZ4725B_CODEC_REG_CGR9, 21762306a36Sopenharmony_ci JZ4725B_CODEC_REG_CGR8, 21862306a36Sopenharmony_ci REG_CGR8_GOR_OFFSET, 21962306a36Sopenharmony_ci 0x1f, 1, jz4725b_out_tlv), 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci SOC_SINGLE("DAC Playback Switch", JZ4725B_CODEC_REG_CR1, 22262306a36Sopenharmony_ci REG_CR1_DAC_MUTE_OFFSET, 1, 1), 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci SOC_SINGLE("Deemphasize Filter Playback Switch", 22562306a36Sopenharmony_ci JZ4725B_CODEC_REG_CR2, 22662306a36Sopenharmony_ci REG_CR2_DAC_DEEMP_OFFSET, 1, 0), 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci SOC_SINGLE("High-Pass Filter Capture Switch", 22962306a36Sopenharmony_ci JZ4725B_CODEC_REG_CR2, 23062306a36Sopenharmony_ci REG_CR2_ADC_HPF_OFFSET, 1, 0), 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci SOC_ENUM("Mic Mode Capture Switch", jz4725b_mic_mode_enum), 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci SOC_SINGLE_TLV("Mic1 Boost Capture Volume", 23562306a36Sopenharmony_ci JZ4725B_CODEC_REG_PMR2, 23662306a36Sopenharmony_ci REG_PMR2_GIM_OFFSET, 23762306a36Sopenharmony_ci 1, 0, jz4725b_mic_boost_tlv), 23862306a36Sopenharmony_ci}; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic const char * const jz4725b_codec_adc_src_texts[] = { 24162306a36Sopenharmony_ci "Mic 1", "Mic 2", "Line In", "Mixer", 24262306a36Sopenharmony_ci}; 24362306a36Sopenharmony_cistatic const unsigned int jz4725b_codec_adc_src_values[] = { 0, 1, 2, 3, }; 24462306a36Sopenharmony_cistatic SOC_VALUE_ENUM_SINGLE_DECL(jz4725b_codec_adc_src_enum, 24562306a36Sopenharmony_ci JZ4725B_CODEC_REG_CR3, 24662306a36Sopenharmony_ci REG_CR3_INSEL_OFFSET, 24762306a36Sopenharmony_ci REG_CR3_INSEL_MASK, 24862306a36Sopenharmony_ci jz4725b_codec_adc_src_texts, 24962306a36Sopenharmony_ci jz4725b_codec_adc_src_values); 25062306a36Sopenharmony_cistatic const struct snd_kcontrol_new jz4725b_codec_adc_src_ctrl = 25162306a36Sopenharmony_ci SOC_DAPM_ENUM("ADC Source Capture Route", jz4725b_codec_adc_src_enum); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic const struct snd_kcontrol_new jz4725b_codec_mixer_controls[] = { 25462306a36Sopenharmony_ci SOC_DAPM_SINGLE("Line In Bypass Playback Switch", JZ4725B_CODEC_REG_CR1, 25562306a36Sopenharmony_ci REG_CR1_BYPASS_OFFSET, 1, 0), 25662306a36Sopenharmony_ci SOC_DAPM_SINGLE("Mic 1 Bypass Playback Switch", JZ4725B_CODEC_REG_CR3, 25762306a36Sopenharmony_ci REG_CR3_SIDETONE1_OFFSET, 1, 0), 25862306a36Sopenharmony_ci SOC_DAPM_SINGLE("Mic 2 Bypass Playback Switch", JZ4725B_CODEC_REG_CR3, 25962306a36Sopenharmony_ci REG_CR3_SIDETONE2_OFFSET, 1, 0), 26062306a36Sopenharmony_ci}; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic int jz4725b_out_stage_enable(struct snd_soc_dapm_widget *w, 26362306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, 26462306a36Sopenharmony_ci int event) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm); 26762306a36Sopenharmony_ci struct jz_icdc *icdc = snd_soc_component_get_drvdata(codec); 26862306a36Sopenharmony_ci struct regmap *map = icdc->regmap; 26962306a36Sopenharmony_ci unsigned int val; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci switch (event) { 27262306a36Sopenharmony_ci case SND_SOC_DAPM_PRE_PMU: 27362306a36Sopenharmony_ci return regmap_clear_bits(map, JZ4725B_CODEC_REG_IFR, 27462306a36Sopenharmony_ci BIT(REG_IFR_RAMP_UP_DONE_OFFSET)); 27562306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 27662306a36Sopenharmony_ci return regmap_read_poll_timeout(map, JZ4725B_CODEC_REG_IFR, 27762306a36Sopenharmony_ci val, val & BIT(REG_IFR_RAMP_UP_DONE_OFFSET), 27862306a36Sopenharmony_ci 100000, 500000); 27962306a36Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 28062306a36Sopenharmony_ci return regmap_clear_bits(map, JZ4725B_CODEC_REG_IFR, 28162306a36Sopenharmony_ci BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET)); 28262306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMD: 28362306a36Sopenharmony_ci return regmap_read_poll_timeout(map, JZ4725B_CODEC_REG_IFR, 28462306a36Sopenharmony_ci val, val & BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET), 28562306a36Sopenharmony_ci 100000, 500000); 28662306a36Sopenharmony_ci default: 28762306a36Sopenharmony_ci return -EINVAL; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget jz4725b_codec_dapm_widgets[] = { 29262306a36Sopenharmony_ci /* DAC */ 29362306a36Sopenharmony_ci SND_SOC_DAPM_DAC("DAC", "Playback", 29462306a36Sopenharmony_ci JZ4725B_CODEC_REG_PMR1, REG_PMR1_SB_DAC_OFFSET, 1), 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci /* ADC */ 29762306a36Sopenharmony_ci SND_SOC_DAPM_ADC("ADC", "Capture", 29862306a36Sopenharmony_ci JZ4725B_CODEC_REG_PMR1, REG_PMR1_SB_ADC_OFFSET, 1), 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci SND_SOC_DAPM_MUX("ADC Source Capture Route", SND_SOC_NOPM, 0, 0, 30162306a36Sopenharmony_ci &jz4725b_codec_adc_src_ctrl), 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci /* Mixer */ 30462306a36Sopenharmony_ci SND_SOC_DAPM_MIXER("Mixer", JZ4725B_CODEC_REG_PMR1, 30562306a36Sopenharmony_ci REG_PMR1_SB_MIX_OFFSET, 1, 30662306a36Sopenharmony_ci jz4725b_codec_mixer_controls, 30762306a36Sopenharmony_ci ARRAY_SIZE(jz4725b_codec_mixer_controls)), 30862306a36Sopenharmony_ci SND_SOC_DAPM_MIXER("DAC to Mixer", JZ4725B_CODEC_REG_CR1, 30962306a36Sopenharmony_ci REG_CR1_DACSEL_OFFSET, 0, NULL, 0), 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci SND_SOC_DAPM_MIXER("Line In", JZ4725B_CODEC_REG_PMR1, 31262306a36Sopenharmony_ci REG_PMR1_SB_LIN_OFFSET, 1, NULL, 0), 31362306a36Sopenharmony_ci SND_SOC_DAPM_MIXER("HP Out", JZ4725B_CODEC_REG_CR1, 31462306a36Sopenharmony_ci REG_CR1_HP_DIS_OFFSET, 1, NULL, 0), 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci SND_SOC_DAPM_MIXER("Mic 1", JZ4725B_CODEC_REG_CR3, 31762306a36Sopenharmony_ci REG_CR3_SB_MIC1_OFFSET, 1, NULL, 0), 31862306a36Sopenharmony_ci SND_SOC_DAPM_MIXER("Mic 2", JZ4725B_CODEC_REG_CR3, 31962306a36Sopenharmony_ci REG_CR3_SB_MIC2_OFFSET, 1, NULL, 0), 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci SND_SOC_DAPM_MIXER_E("Out Stage", JZ4725B_CODEC_REG_PMR1, 32262306a36Sopenharmony_ci REG_PMR1_SB_OUT_OFFSET, 1, NULL, 0, 32362306a36Sopenharmony_ci jz4725b_out_stage_enable, 32462306a36Sopenharmony_ci SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 32562306a36Sopenharmony_ci SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), 32662306a36Sopenharmony_ci SND_SOC_DAPM_MIXER("Mixer to ADC", JZ4725B_CODEC_REG_PMR1, 32762306a36Sopenharmony_ci REG_PMR1_SB_IND_OFFSET, 1, NULL, 0), 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci SND_SOC_DAPM_SUPPLY("Mic Bias", JZ4725B_CODEC_REG_CR1, 33062306a36Sopenharmony_ci REG_CR1_SB_MICBIAS_OFFSET, 1, NULL, 0), 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* Pins */ 33362306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("MIC1P"), 33462306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("MIC1N"), 33562306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("MIC2P"), 33662306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("MIC2N"), 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("LLINEIN"), 33962306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("RLINEIN"), 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("LHPOUT"), 34262306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("RHPOUT"), 34362306a36Sopenharmony_ci}; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic const struct snd_soc_dapm_route jz4725b_codec_dapm_routes[] = { 34662306a36Sopenharmony_ci {"Mic 1", NULL, "MIC1P"}, 34762306a36Sopenharmony_ci {"Mic 1", NULL, "MIC1N"}, 34862306a36Sopenharmony_ci {"Mic 2", NULL, "MIC2P"}, 34962306a36Sopenharmony_ci {"Mic 2", NULL, "MIC2N"}, 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci {"Line In", NULL, "LLINEIN"}, 35262306a36Sopenharmony_ci {"Line In", NULL, "RLINEIN"}, 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci {"Mixer", "Mic 1 Bypass Playback Switch", "Mic 1"}, 35562306a36Sopenharmony_ci {"Mixer", "Mic 2 Bypass Playback Switch", "Mic 2"}, 35662306a36Sopenharmony_ci {"Mixer", "Line In Bypass Playback Switch", "Line In"}, 35762306a36Sopenharmony_ci {"DAC to Mixer", NULL, "DAC"}, 35862306a36Sopenharmony_ci {"Mixer", NULL, "DAC to Mixer"}, 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci {"Mixer to ADC", NULL, "Mixer"}, 36162306a36Sopenharmony_ci {"ADC Source Capture Route", "Mixer", "Mixer to ADC"}, 36262306a36Sopenharmony_ci {"ADC Source Capture Route", "Line In", "Line In"}, 36362306a36Sopenharmony_ci {"ADC Source Capture Route", "Mic 1", "Mic 1"}, 36462306a36Sopenharmony_ci {"ADC Source Capture Route", "Mic 2", "Mic 2"}, 36562306a36Sopenharmony_ci {"ADC", NULL, "ADC Source Capture Route"}, 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci {"Out Stage", NULL, "Mixer"}, 36862306a36Sopenharmony_ci {"HP Out", NULL, "Out Stage"}, 36962306a36Sopenharmony_ci {"LHPOUT", NULL, "HP Out"}, 37062306a36Sopenharmony_ci {"RHPOUT", NULL, "HP Out"}, 37162306a36Sopenharmony_ci}; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic int jz4725b_codec_set_bias_level(struct snd_soc_component *component, 37462306a36Sopenharmony_ci enum snd_soc_bias_level level) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci struct jz_icdc *icdc = snd_soc_component_get_drvdata(component); 37762306a36Sopenharmony_ci struct regmap *map = icdc->regmap; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci switch (level) { 38062306a36Sopenharmony_ci case SND_SOC_BIAS_ON: 38162306a36Sopenharmony_ci regmap_clear_bits(map, JZ4725B_CODEC_REG_PMR2, 38262306a36Sopenharmony_ci BIT(REG_PMR2_SB_SLEEP_OFFSET)); 38362306a36Sopenharmony_ci break; 38462306a36Sopenharmony_ci case SND_SOC_BIAS_PREPARE: 38562306a36Sopenharmony_ci /* Enable sound hardware */ 38662306a36Sopenharmony_ci regmap_clear_bits(map, JZ4725B_CODEC_REG_PMR2, 38762306a36Sopenharmony_ci BIT(REG_PMR2_SB_OFFSET)); 38862306a36Sopenharmony_ci msleep(224); 38962306a36Sopenharmony_ci break; 39062306a36Sopenharmony_ci case SND_SOC_BIAS_STANDBY: 39162306a36Sopenharmony_ci regmap_set_bits(map, JZ4725B_CODEC_REG_PMR2, 39262306a36Sopenharmony_ci BIT(REG_PMR2_SB_SLEEP_OFFSET)); 39362306a36Sopenharmony_ci break; 39462306a36Sopenharmony_ci case SND_SOC_BIAS_OFF: 39562306a36Sopenharmony_ci regmap_set_bits(map, JZ4725B_CODEC_REG_PMR2, 39662306a36Sopenharmony_ci BIT(REG_PMR2_SB_OFFSET)); 39762306a36Sopenharmony_ci break; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci return 0; 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic int jz4725b_codec_dev_probe(struct snd_soc_component *component) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci struct jz_icdc *icdc = snd_soc_component_get_drvdata(component); 40662306a36Sopenharmony_ci struct regmap *map = icdc->regmap; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci clk_prepare_enable(icdc->clk); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* Write CONFIGn (n=1 to 8) bits. 41162306a36Sopenharmony_ci * The value 0x0f is specified in the datasheet as a requirement. 41262306a36Sopenharmony_ci */ 41362306a36Sopenharmony_ci regmap_write(map, JZ4725B_CODEC_REG_AICR, 41462306a36Sopenharmony_ci 0xf << REG_AICR_CONFIG1_OFFSET); 41562306a36Sopenharmony_ci regmap_write(map, JZ4725B_CODEC_REG_CCR1, 41662306a36Sopenharmony_ci 0x0 << REG_CCR1_CONFIG4_OFFSET); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci return 0; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic void jz4725b_codec_dev_remove(struct snd_soc_component *component) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci struct jz_icdc *icdc = snd_soc_component_get_drvdata(component); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci clk_disable_unprepare(icdc->clk); 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic const struct snd_soc_component_driver jz4725b_codec = { 42962306a36Sopenharmony_ci .probe = jz4725b_codec_dev_probe, 43062306a36Sopenharmony_ci .remove = jz4725b_codec_dev_remove, 43162306a36Sopenharmony_ci .set_bias_level = jz4725b_codec_set_bias_level, 43262306a36Sopenharmony_ci .controls = jz4725b_codec_controls, 43362306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(jz4725b_codec_controls), 43462306a36Sopenharmony_ci .dapm_widgets = jz4725b_codec_dapm_widgets, 43562306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(jz4725b_codec_dapm_widgets), 43662306a36Sopenharmony_ci .dapm_routes = jz4725b_codec_dapm_routes, 43762306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(jz4725b_codec_dapm_routes), 43862306a36Sopenharmony_ci .suspend_bias_off = 1, 43962306a36Sopenharmony_ci .use_pmdown_time = 1, 44062306a36Sopenharmony_ci}; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic const unsigned int jz4725b_codec_sample_rates[] = { 44362306a36Sopenharmony_ci 96000, 48000, 44100, 32000, 44462306a36Sopenharmony_ci 24000, 22050, 16000, 12000, 44562306a36Sopenharmony_ci 11025, 9600, 8000, 44662306a36Sopenharmony_ci}; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic int jz4725b_codec_hw_params(struct snd_pcm_substream *substream, 44962306a36Sopenharmony_ci struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci struct jz_icdc *icdc = snd_soc_component_get_drvdata(dai->component); 45262306a36Sopenharmony_ci unsigned int rate, bit_width; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci switch (params_format(params)) { 45562306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 45662306a36Sopenharmony_ci bit_width = 0; 45762306a36Sopenharmony_ci break; 45862306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S18_3LE: 45962306a36Sopenharmony_ci bit_width = 1; 46062306a36Sopenharmony_ci break; 46162306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S20_3LE: 46262306a36Sopenharmony_ci bit_width = 2; 46362306a36Sopenharmony_ci break; 46462306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_3LE: 46562306a36Sopenharmony_ci bit_width = 3; 46662306a36Sopenharmony_ci break; 46762306a36Sopenharmony_ci default: 46862306a36Sopenharmony_ci return -EINVAL; 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci for (rate = 0; rate < ARRAY_SIZE(jz4725b_codec_sample_rates); rate++) { 47262306a36Sopenharmony_ci if (jz4725b_codec_sample_rates[rate] == params_rate(params)) 47362306a36Sopenharmony_ci break; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci if (rate == ARRAY_SIZE(jz4725b_codec_sample_rates)) 47762306a36Sopenharmony_ci return -EINVAL; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 48062306a36Sopenharmony_ci regmap_update_bits(icdc->regmap, 48162306a36Sopenharmony_ci JZ4725B_CODEC_REG_CR2, 48262306a36Sopenharmony_ci REG_CR2_DAC_ADWL_MASK, 48362306a36Sopenharmony_ci bit_width << REG_CR2_DAC_ADWL_OFFSET); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci regmap_update_bits(icdc->regmap, 48662306a36Sopenharmony_ci JZ4725B_CODEC_REG_CCR2, 48762306a36Sopenharmony_ci REG_CCR2_DFREQ_MASK, 48862306a36Sopenharmony_ci rate << REG_CCR2_DFREQ_OFFSET); 48962306a36Sopenharmony_ci } else { 49062306a36Sopenharmony_ci regmap_update_bits(icdc->regmap, 49162306a36Sopenharmony_ci JZ4725B_CODEC_REG_CR2, 49262306a36Sopenharmony_ci REG_CR2_ADC_ADWL_MASK, 49362306a36Sopenharmony_ci bit_width << REG_CR2_ADC_ADWL_OFFSET); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci regmap_update_bits(icdc->regmap, 49662306a36Sopenharmony_ci JZ4725B_CODEC_REG_CCR2, 49762306a36Sopenharmony_ci REG_CCR2_AFREQ_MASK, 49862306a36Sopenharmony_ci rate << REG_CCR2_AFREQ_OFFSET); 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci return 0; 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic const struct snd_soc_dai_ops jz4725b_codec_dai_ops = { 50562306a36Sopenharmony_ci .hw_params = jz4725b_codec_hw_params, 50662306a36Sopenharmony_ci}; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci#define JZ_ICDC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ 50962306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_3LE) 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_cistatic struct snd_soc_dai_driver jz4725b_codec_dai = { 51262306a36Sopenharmony_ci .name = "jz4725b-hifi", 51362306a36Sopenharmony_ci .playback = { 51462306a36Sopenharmony_ci .stream_name = "Playback", 51562306a36Sopenharmony_ci .channels_min = 2, 51662306a36Sopenharmony_ci .channels_max = 2, 51762306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_96000, 51862306a36Sopenharmony_ci .formats = JZ_ICDC_FORMATS, 51962306a36Sopenharmony_ci }, 52062306a36Sopenharmony_ci .capture = { 52162306a36Sopenharmony_ci .stream_name = "Capture", 52262306a36Sopenharmony_ci .channels_min = 2, 52362306a36Sopenharmony_ci .channels_max = 2, 52462306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_96000, 52562306a36Sopenharmony_ci .formats = JZ_ICDC_FORMATS, 52662306a36Sopenharmony_ci }, 52762306a36Sopenharmony_ci .ops = &jz4725b_codec_dai_ops, 52862306a36Sopenharmony_ci}; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic bool jz4725b_codec_volatile(struct device *dev, unsigned int reg) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci return reg == JZ4725B_CODEC_REG_IFR; 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cistatic bool jz4725b_codec_can_access_reg(struct device *dev, unsigned int reg) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci return (reg != JZ4725B_CODEC_REG_TR1) && (reg != JZ4725B_CODEC_REG_TR2); 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic int jz4725b_codec_io_wait(struct jz_icdc *icdc) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci u32 reg; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci return readl_poll_timeout(icdc->base + ICDC_RGADW_OFFSET, reg, 54562306a36Sopenharmony_ci !(reg & ICDC_RGADW_RGWR), 1000, 10000); 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic int jz4725b_codec_reg_read(void *context, unsigned int reg, 54962306a36Sopenharmony_ci unsigned int *val) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci struct jz_icdc *icdc = context; 55262306a36Sopenharmony_ci unsigned int i; 55362306a36Sopenharmony_ci u32 tmp; 55462306a36Sopenharmony_ci int ret; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci ret = jz4725b_codec_io_wait(icdc); 55762306a36Sopenharmony_ci if (ret) 55862306a36Sopenharmony_ci return ret; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci tmp = readl(icdc->base + ICDC_RGADW_OFFSET); 56162306a36Sopenharmony_ci tmp = (tmp & ~ICDC_RGADW_RGADDR_MASK) 56262306a36Sopenharmony_ci | (reg << ICDC_RGADW_RGADDR_OFFSET); 56362306a36Sopenharmony_ci writel(tmp, icdc->base + ICDC_RGADW_OFFSET); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci /* wait 6+ cycles */ 56662306a36Sopenharmony_ci for (i = 0; i < 6; i++) 56762306a36Sopenharmony_ci *val = readl(icdc->base + ICDC_RGDATA_OFFSET) & 56862306a36Sopenharmony_ci ICDC_RGDATA_RGDOUT_MASK; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci return 0; 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cistatic int jz4725b_codec_reg_write(void *context, unsigned int reg, 57462306a36Sopenharmony_ci unsigned int val) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci struct jz_icdc *icdc = context; 57762306a36Sopenharmony_ci int ret; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci ret = jz4725b_codec_io_wait(icdc); 58062306a36Sopenharmony_ci if (ret) 58162306a36Sopenharmony_ci return ret; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci writel(ICDC_RGADW_RGWR | (reg << ICDC_RGADW_RGADDR_OFFSET) | val, 58462306a36Sopenharmony_ci icdc->base + ICDC_RGADW_OFFSET); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci ret = jz4725b_codec_io_wait(icdc); 58762306a36Sopenharmony_ci if (ret) 58862306a36Sopenharmony_ci return ret; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci return 0; 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic const u8 jz4725b_codec_reg_defaults[] = { 59462306a36Sopenharmony_ci 0x0c, 0xaa, 0x78, 0x00, 0x00, 0xff, 0x03, 0x51, 59562306a36Sopenharmony_ci 0x3f, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 59662306a36Sopenharmony_ci 0x04, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0xc0, 0x34, 59762306a36Sopenharmony_ci 0x07, 0x44, 0x1f, 0x00, 59862306a36Sopenharmony_ci}; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic const struct regmap_config jz4725b_codec_regmap_config = { 60162306a36Sopenharmony_ci .reg_bits = 7, 60262306a36Sopenharmony_ci .val_bits = 8, 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci .max_register = JZ4725B_CODEC_REG_AGC5, 60562306a36Sopenharmony_ci .volatile_reg = jz4725b_codec_volatile, 60662306a36Sopenharmony_ci .readable_reg = jz4725b_codec_can_access_reg, 60762306a36Sopenharmony_ci .writeable_reg = jz4725b_codec_can_access_reg, 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci .reg_read = jz4725b_codec_reg_read, 61062306a36Sopenharmony_ci .reg_write = jz4725b_codec_reg_write, 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci .reg_defaults_raw = jz4725b_codec_reg_defaults, 61362306a36Sopenharmony_ci .num_reg_defaults_raw = ARRAY_SIZE(jz4725b_codec_reg_defaults), 61462306a36Sopenharmony_ci .cache_type = REGCACHE_FLAT, 61562306a36Sopenharmony_ci}; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cistatic int jz4725b_codec_probe(struct platform_device *pdev) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci struct device *dev = &pdev->dev; 62062306a36Sopenharmony_ci struct jz_icdc *icdc; 62162306a36Sopenharmony_ci int ret; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci icdc = devm_kzalloc(dev, sizeof(*icdc), GFP_KERNEL); 62462306a36Sopenharmony_ci if (!icdc) 62562306a36Sopenharmony_ci return -ENOMEM; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci icdc->base = devm_platform_ioremap_resource(pdev, 0); 62862306a36Sopenharmony_ci if (IS_ERR(icdc->base)) 62962306a36Sopenharmony_ci return PTR_ERR(icdc->base); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci icdc->regmap = devm_regmap_init(dev, NULL, icdc, 63262306a36Sopenharmony_ci &jz4725b_codec_regmap_config); 63362306a36Sopenharmony_ci if (IS_ERR(icdc->regmap)) 63462306a36Sopenharmony_ci return PTR_ERR(icdc->regmap); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci icdc->clk = devm_clk_get(&pdev->dev, "aic"); 63762306a36Sopenharmony_ci if (IS_ERR(icdc->clk)) 63862306a36Sopenharmony_ci return PTR_ERR(icdc->clk); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci platform_set_drvdata(pdev, icdc); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci ret = devm_snd_soc_register_component(dev, &jz4725b_codec, 64362306a36Sopenharmony_ci &jz4725b_codec_dai, 1); 64462306a36Sopenharmony_ci if (ret) 64562306a36Sopenharmony_ci dev_err(dev, "Failed to register codec\n"); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci return ret; 64862306a36Sopenharmony_ci} 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_cistatic const struct of_device_id jz4725b_codec_of_matches[] = { 65162306a36Sopenharmony_ci { .compatible = "ingenic,jz4725b-codec", }, 65262306a36Sopenharmony_ci { } 65362306a36Sopenharmony_ci}; 65462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, jz4725b_codec_of_matches); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic struct platform_driver jz4725b_codec_driver = { 65762306a36Sopenharmony_ci .probe = jz4725b_codec_probe, 65862306a36Sopenharmony_ci .driver = { 65962306a36Sopenharmony_ci .name = "jz4725b-codec", 66062306a36Sopenharmony_ci .of_match_table = jz4725b_codec_of_matches, 66162306a36Sopenharmony_ci }, 66262306a36Sopenharmony_ci}; 66362306a36Sopenharmony_cimodule_platform_driver(jz4725b_codec_driver); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ciMODULE_DESCRIPTION("JZ4725B SoC internal codec driver"); 66662306a36Sopenharmony_ciMODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>"); 66762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 668