162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * PCM3168A codec driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2015 Imagination Technologies Ltd. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Damien Horsley <Damien.Horsley@imgtec.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/clk.h> 1162306a36Sopenharmony_ci#include <linux/delay.h> 1262306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/of_gpio.h> 1562306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1662306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <sound/pcm_params.h> 1962306a36Sopenharmony_ci#include <sound/soc.h> 2062306a36Sopenharmony_ci#include <sound/tlv.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "pcm3168a.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define PCM3168A_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 2562306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_3LE | \ 2662306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE) 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define PCM3168A_FMT_I2S 0x0 2962306a36Sopenharmony_ci#define PCM3168A_FMT_LEFT_J 0x1 3062306a36Sopenharmony_ci#define PCM3168A_FMT_RIGHT_J 0x2 3162306a36Sopenharmony_ci#define PCM3168A_FMT_RIGHT_J_16 0x3 3262306a36Sopenharmony_ci#define PCM3168A_FMT_DSP_A 0x4 3362306a36Sopenharmony_ci#define PCM3168A_FMT_DSP_B 0x5 3462306a36Sopenharmony_ci#define PCM3168A_FMT_I2S_TDM 0x6 3562306a36Sopenharmony_ci#define PCM3168A_FMT_LEFT_J_TDM 0x7 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic const char *const pcm3168a_supply_names[] = { 3862306a36Sopenharmony_ci "VDD1", 3962306a36Sopenharmony_ci "VDD2", 4062306a36Sopenharmony_ci "VCCAD1", 4162306a36Sopenharmony_ci "VCCAD2", 4262306a36Sopenharmony_ci "VCCDA1", 4362306a36Sopenharmony_ci "VCCDA2" 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define PCM3168A_DAI_DAC 0 4762306a36Sopenharmony_ci#define PCM3168A_DAI_ADC 1 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* ADC/DAC side parameters */ 5062306a36Sopenharmony_cistruct pcm3168a_io_params { 5162306a36Sopenharmony_ci bool provider_mode; 5262306a36Sopenharmony_ci unsigned int format; 5362306a36Sopenharmony_ci int tdm_slots; 5462306a36Sopenharmony_ci u32 tdm_mask; 5562306a36Sopenharmony_ci int slot_width; 5662306a36Sopenharmony_ci}; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistruct pcm3168a_priv { 5962306a36Sopenharmony_ci struct regulator_bulk_data supplies[ARRAY_SIZE(pcm3168a_supply_names)]; 6062306a36Sopenharmony_ci struct regmap *regmap; 6162306a36Sopenharmony_ci struct clk *scki; 6262306a36Sopenharmony_ci struct gpio_desc *gpio_rst; 6362306a36Sopenharmony_ci unsigned long sysclk; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci struct pcm3168a_io_params io_params[2]; 6662306a36Sopenharmony_ci struct snd_soc_dai_driver dai_drv[2]; 6762306a36Sopenharmony_ci}; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic const char *const pcm3168a_roll_off[] = { "Sharp", "Slow" }; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_d1_roll_off, PCM3168A_DAC_OP_FLT, 7262306a36Sopenharmony_ci PCM3168A_DAC_FLT_SHIFT, pcm3168a_roll_off); 7362306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_d2_roll_off, PCM3168A_DAC_OP_FLT, 7462306a36Sopenharmony_ci PCM3168A_DAC_FLT_SHIFT + 1, pcm3168a_roll_off); 7562306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_d3_roll_off, PCM3168A_DAC_OP_FLT, 7662306a36Sopenharmony_ci PCM3168A_DAC_FLT_SHIFT + 2, pcm3168a_roll_off); 7762306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_d4_roll_off, PCM3168A_DAC_OP_FLT, 7862306a36Sopenharmony_ci PCM3168A_DAC_FLT_SHIFT + 3, pcm3168a_roll_off); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic const char *const pcm3168a_volume_type[] = { 8162306a36Sopenharmony_ci "Individual", "Master + Individual" }; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_dac_volume_type, PCM3168A_DAC_ATT_DEMP_ZF, 8462306a36Sopenharmony_ci PCM3168A_DAC_ATMDDA_SHIFT, pcm3168a_volume_type); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic const char *const pcm3168a_att_speed_mult[] = { "2048", "4096" }; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_dac_att_mult, PCM3168A_DAC_ATT_DEMP_ZF, 8962306a36Sopenharmony_ci PCM3168A_DAC_ATSPDA_SHIFT, pcm3168a_att_speed_mult); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic const char *const pcm3168a_demp[] = { 9262306a36Sopenharmony_ci "Disabled", "48khz", "44.1khz", "32khz" }; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_dac_demp, PCM3168A_DAC_ATT_DEMP_ZF, 9562306a36Sopenharmony_ci PCM3168A_DAC_DEMP_SHIFT, pcm3168a_demp); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic const char *const pcm3168a_zf_func[] = { 9862306a36Sopenharmony_ci "DAC 1/2/3/4 AND", "DAC 1/2/3/4 OR", "DAC 1/2/3 AND", 9962306a36Sopenharmony_ci "DAC 1/2/3 OR", "DAC 4 AND", "DAC 4 OR" }; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_dac_zf_func, PCM3168A_DAC_ATT_DEMP_ZF, 10262306a36Sopenharmony_ci PCM3168A_DAC_AZRO_SHIFT, pcm3168a_zf_func); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic const char *const pcm3168a_pol[] = { "Active High", "Active Low" }; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_dac_zf_pol, PCM3168A_DAC_ATT_DEMP_ZF, 10762306a36Sopenharmony_ci PCM3168A_DAC_ATSPDA_SHIFT, pcm3168a_pol); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic const char *const pcm3168a_con[] = { "Differential", "Single-Ended" }; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic SOC_ENUM_DOUBLE_DECL(pcm3168a_adc1_con, PCM3168A_ADC_SEAD, 11262306a36Sopenharmony_ci 0, 1, pcm3168a_con); 11362306a36Sopenharmony_cistatic SOC_ENUM_DOUBLE_DECL(pcm3168a_adc2_con, PCM3168A_ADC_SEAD, 11462306a36Sopenharmony_ci 2, 3, pcm3168a_con); 11562306a36Sopenharmony_cistatic SOC_ENUM_DOUBLE_DECL(pcm3168a_adc3_con, PCM3168A_ADC_SEAD, 11662306a36Sopenharmony_ci 4, 5, pcm3168a_con); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_adc_volume_type, PCM3168A_ADC_ATT_OVF, 11962306a36Sopenharmony_ci PCM3168A_ADC_ATMDAD_SHIFT, pcm3168a_volume_type); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_adc_att_mult, PCM3168A_ADC_ATT_OVF, 12262306a36Sopenharmony_ci PCM3168A_ADC_ATSPAD_SHIFT, pcm3168a_att_speed_mult); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_adc_ov_pol, PCM3168A_ADC_ATT_OVF, 12562306a36Sopenharmony_ci PCM3168A_ADC_OVFP_SHIFT, pcm3168a_pol); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/* -100db to 0db, register values 0-54 cause mute */ 12862306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(pcm3168a_dac_tlv, -10050, 50, 1); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci/* -100db to 20db, register values 0-14 cause mute */ 13162306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(pcm3168a_adc_tlv, -10050, 50, 1); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic const struct snd_kcontrol_new pcm3168a_snd_controls[] = { 13462306a36Sopenharmony_ci SOC_SINGLE("DAC Power-Save Switch", PCM3168A_DAC_PWR_MST_FMT, 13562306a36Sopenharmony_ci PCM3168A_DAC_PSMDA_SHIFT, 1, 1), 13662306a36Sopenharmony_ci SOC_ENUM("DAC1 Digital Filter roll-off", pcm3168a_d1_roll_off), 13762306a36Sopenharmony_ci SOC_ENUM("DAC2 Digital Filter roll-off", pcm3168a_d2_roll_off), 13862306a36Sopenharmony_ci SOC_ENUM("DAC3 Digital Filter roll-off", pcm3168a_d3_roll_off), 13962306a36Sopenharmony_ci SOC_ENUM("DAC4 Digital Filter roll-off", pcm3168a_d4_roll_off), 14062306a36Sopenharmony_ci SOC_DOUBLE("DAC1 Invert Switch", PCM3168A_DAC_INV, 0, 1, 1, 0), 14162306a36Sopenharmony_ci SOC_DOUBLE("DAC2 Invert Switch", PCM3168A_DAC_INV, 2, 3, 1, 0), 14262306a36Sopenharmony_ci SOC_DOUBLE("DAC3 Invert Switch", PCM3168A_DAC_INV, 4, 5, 1, 0), 14362306a36Sopenharmony_ci SOC_DOUBLE("DAC4 Invert Switch", PCM3168A_DAC_INV, 6, 7, 1, 0), 14462306a36Sopenharmony_ci SOC_ENUM("DAC Volume Control Type", pcm3168a_dac_volume_type), 14562306a36Sopenharmony_ci SOC_ENUM("DAC Volume Rate Multiplier", pcm3168a_dac_att_mult), 14662306a36Sopenharmony_ci SOC_ENUM("DAC De-Emphasis", pcm3168a_dac_demp), 14762306a36Sopenharmony_ci SOC_ENUM("DAC Zero Flag Function", pcm3168a_dac_zf_func), 14862306a36Sopenharmony_ci SOC_ENUM("DAC Zero Flag Polarity", pcm3168a_dac_zf_pol), 14962306a36Sopenharmony_ci SOC_SINGLE_RANGE_TLV("Master Playback Volume", 15062306a36Sopenharmony_ci PCM3168A_DAC_VOL_MASTER, 0, 54, 255, 0, 15162306a36Sopenharmony_ci pcm3168a_dac_tlv), 15262306a36Sopenharmony_ci SOC_DOUBLE_R_RANGE_TLV("DAC1 Playback Volume", 15362306a36Sopenharmony_ci PCM3168A_DAC_VOL_CHAN_START, 15462306a36Sopenharmony_ci PCM3168A_DAC_VOL_CHAN_START + 1, 15562306a36Sopenharmony_ci 0, 54, 255, 0, pcm3168a_dac_tlv), 15662306a36Sopenharmony_ci SOC_DOUBLE_R_RANGE_TLV("DAC2 Playback Volume", 15762306a36Sopenharmony_ci PCM3168A_DAC_VOL_CHAN_START + 2, 15862306a36Sopenharmony_ci PCM3168A_DAC_VOL_CHAN_START + 3, 15962306a36Sopenharmony_ci 0, 54, 255, 0, pcm3168a_dac_tlv), 16062306a36Sopenharmony_ci SOC_DOUBLE_R_RANGE_TLV("DAC3 Playback Volume", 16162306a36Sopenharmony_ci PCM3168A_DAC_VOL_CHAN_START + 4, 16262306a36Sopenharmony_ci PCM3168A_DAC_VOL_CHAN_START + 5, 16362306a36Sopenharmony_ci 0, 54, 255, 0, pcm3168a_dac_tlv), 16462306a36Sopenharmony_ci SOC_DOUBLE_R_RANGE_TLV("DAC4 Playback Volume", 16562306a36Sopenharmony_ci PCM3168A_DAC_VOL_CHAN_START + 6, 16662306a36Sopenharmony_ci PCM3168A_DAC_VOL_CHAN_START + 7, 16762306a36Sopenharmony_ci 0, 54, 255, 0, pcm3168a_dac_tlv), 16862306a36Sopenharmony_ci SOC_SINGLE("ADC1 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB, 16962306a36Sopenharmony_ci PCM3168A_ADC_BYP_SHIFT, 1, 1), 17062306a36Sopenharmony_ci SOC_SINGLE("ADC2 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB, 17162306a36Sopenharmony_ci PCM3168A_ADC_BYP_SHIFT + 1, 1, 1), 17262306a36Sopenharmony_ci SOC_SINGLE("ADC3 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB, 17362306a36Sopenharmony_ci PCM3168A_ADC_BYP_SHIFT + 2, 1, 1), 17462306a36Sopenharmony_ci SOC_ENUM("ADC1 Connection Type", pcm3168a_adc1_con), 17562306a36Sopenharmony_ci SOC_ENUM("ADC2 Connection Type", pcm3168a_adc2_con), 17662306a36Sopenharmony_ci SOC_ENUM("ADC3 Connection Type", pcm3168a_adc3_con), 17762306a36Sopenharmony_ci SOC_DOUBLE("ADC1 Invert Switch", PCM3168A_ADC_INV, 0, 1, 1, 0), 17862306a36Sopenharmony_ci SOC_DOUBLE("ADC2 Invert Switch", PCM3168A_ADC_INV, 2, 3, 1, 0), 17962306a36Sopenharmony_ci SOC_DOUBLE("ADC3 Invert Switch", PCM3168A_ADC_INV, 4, 5, 1, 0), 18062306a36Sopenharmony_ci SOC_DOUBLE("ADC1 Mute Switch", PCM3168A_ADC_MUTE, 0, 1, 1, 0), 18162306a36Sopenharmony_ci SOC_DOUBLE("ADC2 Mute Switch", PCM3168A_ADC_MUTE, 2, 3, 1, 0), 18262306a36Sopenharmony_ci SOC_DOUBLE("ADC3 Mute Switch", PCM3168A_ADC_MUTE, 4, 5, 1, 0), 18362306a36Sopenharmony_ci SOC_ENUM("ADC Volume Control Type", pcm3168a_adc_volume_type), 18462306a36Sopenharmony_ci SOC_ENUM("ADC Volume Rate Multiplier", pcm3168a_adc_att_mult), 18562306a36Sopenharmony_ci SOC_ENUM("ADC Overflow Flag Polarity", pcm3168a_adc_ov_pol), 18662306a36Sopenharmony_ci SOC_SINGLE_RANGE_TLV("Master Capture Volume", 18762306a36Sopenharmony_ci PCM3168A_ADC_VOL_MASTER, 0, 14, 255, 0, 18862306a36Sopenharmony_ci pcm3168a_adc_tlv), 18962306a36Sopenharmony_ci SOC_DOUBLE_R_RANGE_TLV("ADC1 Capture Volume", 19062306a36Sopenharmony_ci PCM3168A_ADC_VOL_CHAN_START, 19162306a36Sopenharmony_ci PCM3168A_ADC_VOL_CHAN_START + 1, 19262306a36Sopenharmony_ci 0, 14, 255, 0, pcm3168a_adc_tlv), 19362306a36Sopenharmony_ci SOC_DOUBLE_R_RANGE_TLV("ADC2 Capture Volume", 19462306a36Sopenharmony_ci PCM3168A_ADC_VOL_CHAN_START + 2, 19562306a36Sopenharmony_ci PCM3168A_ADC_VOL_CHAN_START + 3, 19662306a36Sopenharmony_ci 0, 14, 255, 0, pcm3168a_adc_tlv), 19762306a36Sopenharmony_ci SOC_DOUBLE_R_RANGE_TLV("ADC3 Capture Volume", 19862306a36Sopenharmony_ci PCM3168A_ADC_VOL_CHAN_START + 4, 19962306a36Sopenharmony_ci PCM3168A_ADC_VOL_CHAN_START + 5, 20062306a36Sopenharmony_ci 0, 14, 255, 0, pcm3168a_adc_tlv) 20162306a36Sopenharmony_ci}; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget pcm3168a_dapm_widgets[] = { 20462306a36Sopenharmony_ci SND_SOC_DAPM_DAC("DAC1", "Playback", PCM3168A_DAC_OP_FLT, 20562306a36Sopenharmony_ci PCM3168A_DAC_OPEDA_SHIFT, 1), 20662306a36Sopenharmony_ci SND_SOC_DAPM_DAC("DAC2", "Playback", PCM3168A_DAC_OP_FLT, 20762306a36Sopenharmony_ci PCM3168A_DAC_OPEDA_SHIFT + 1, 1), 20862306a36Sopenharmony_ci SND_SOC_DAPM_DAC("DAC3", "Playback", PCM3168A_DAC_OP_FLT, 20962306a36Sopenharmony_ci PCM3168A_DAC_OPEDA_SHIFT + 2, 1), 21062306a36Sopenharmony_ci SND_SOC_DAPM_DAC("DAC4", "Playback", PCM3168A_DAC_OP_FLT, 21162306a36Sopenharmony_ci PCM3168A_DAC_OPEDA_SHIFT + 3, 1), 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("AOUT1L"), 21462306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("AOUT1R"), 21562306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("AOUT2L"), 21662306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("AOUT2R"), 21762306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("AOUT3L"), 21862306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("AOUT3R"), 21962306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("AOUT4L"), 22062306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("AOUT4R"), 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci SND_SOC_DAPM_ADC("ADC1", "Capture", PCM3168A_ADC_PWR_HPFB, 22362306a36Sopenharmony_ci PCM3168A_ADC_PSVAD_SHIFT, 1), 22462306a36Sopenharmony_ci SND_SOC_DAPM_ADC("ADC2", "Capture", PCM3168A_ADC_PWR_HPFB, 22562306a36Sopenharmony_ci PCM3168A_ADC_PSVAD_SHIFT + 1, 1), 22662306a36Sopenharmony_ci SND_SOC_DAPM_ADC("ADC3", "Capture", PCM3168A_ADC_PWR_HPFB, 22762306a36Sopenharmony_ci PCM3168A_ADC_PSVAD_SHIFT + 2, 1), 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("AIN1L"), 23062306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("AIN1R"), 23162306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("AIN2L"), 23262306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("AIN2R"), 23362306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("AIN3L"), 23462306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("AIN3R") 23562306a36Sopenharmony_ci}; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic const struct snd_soc_dapm_route pcm3168a_dapm_routes[] = { 23862306a36Sopenharmony_ci /* Playback */ 23962306a36Sopenharmony_ci { "AOUT1L", NULL, "DAC1" }, 24062306a36Sopenharmony_ci { "AOUT1R", NULL, "DAC1" }, 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci { "AOUT2L", NULL, "DAC2" }, 24362306a36Sopenharmony_ci { "AOUT2R", NULL, "DAC2" }, 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci { "AOUT3L", NULL, "DAC3" }, 24662306a36Sopenharmony_ci { "AOUT3R", NULL, "DAC3" }, 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci { "AOUT4L", NULL, "DAC4" }, 24962306a36Sopenharmony_ci { "AOUT4R", NULL, "DAC4" }, 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* Capture */ 25262306a36Sopenharmony_ci { "ADC1", NULL, "AIN1L" }, 25362306a36Sopenharmony_ci { "ADC1", NULL, "AIN1R" }, 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci { "ADC2", NULL, "AIN2L" }, 25662306a36Sopenharmony_ci { "ADC2", NULL, "AIN2R" }, 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci { "ADC3", NULL, "AIN3L" }, 25962306a36Sopenharmony_ci { "ADC3", NULL, "AIN3R" } 26062306a36Sopenharmony_ci}; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic unsigned int pcm3168a_scki_ratios[] = { 26362306a36Sopenharmony_ci 768, 26462306a36Sopenharmony_ci 512, 26562306a36Sopenharmony_ci 384, 26662306a36Sopenharmony_ci 256, 26762306a36Sopenharmony_ci 192, 26862306a36Sopenharmony_ci 128 26962306a36Sopenharmony_ci}; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci#define PCM3168A_NUM_SCKI_RATIOS_DAC ARRAY_SIZE(pcm3168a_scki_ratios) 27262306a36Sopenharmony_ci#define PCM3168A_NUM_SCKI_RATIOS_ADC (ARRAY_SIZE(pcm3168a_scki_ratios) - 2) 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci#define PCM3168A_MAX_SYSCLK 36864000 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic int pcm3168a_reset(struct pcm3168a_priv *pcm3168a) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci int ret; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci ret = regmap_write(pcm3168a->regmap, PCM3168A_RST_SMODE, 0); 28162306a36Sopenharmony_ci if (ret) 28262306a36Sopenharmony_ci return ret; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* Internal reset is de-asserted after 3846 SCKI cycles */ 28562306a36Sopenharmony_ci msleep(DIV_ROUND_UP(3846 * 1000, pcm3168a->sysclk)); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci return regmap_write(pcm3168a->regmap, PCM3168A_RST_SMODE, 28862306a36Sopenharmony_ci PCM3168A_MRST_MASK | PCM3168A_SRST_MASK); 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic int pcm3168a_mute(struct snd_soc_dai *dai, int mute, int direction) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 29462306a36Sopenharmony_ci struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci regmap_write(pcm3168a->regmap, PCM3168A_DAC_MUTE, mute ? 0xff : 0); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci return 0; 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai, 30262306a36Sopenharmony_ci int clk_id, unsigned int freq, int dir) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(dai->component); 30562306a36Sopenharmony_ci int ret; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci /* 30862306a36Sopenharmony_ci * Some sound card sets 0 Hz as reset, 30962306a36Sopenharmony_ci * but it is impossible to set. Ignore it here 31062306a36Sopenharmony_ci */ 31162306a36Sopenharmony_ci if (freq == 0) 31262306a36Sopenharmony_ci return 0; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (freq > PCM3168A_MAX_SYSCLK) 31562306a36Sopenharmony_ci return -EINVAL; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci ret = clk_set_rate(pcm3168a->scki, freq); 31862306a36Sopenharmony_ci if (ret) 31962306a36Sopenharmony_ci return ret; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci pcm3168a->sysclk = freq; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci return 0; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic void pcm3168a_update_fixup_pcm_stream(struct snd_soc_dai *dai) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 32962306a36Sopenharmony_ci struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); 33062306a36Sopenharmony_ci struct pcm3168a_io_params *io_params = &pcm3168a->io_params[dai->id]; 33162306a36Sopenharmony_ci u64 formats = SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE; 33262306a36Sopenharmony_ci unsigned int channel_max = dai->id == PCM3168A_DAI_DAC ? 8 : 6; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (io_params->format == SND_SOC_DAIFMT_RIGHT_J) { 33562306a36Sopenharmony_ci /* S16_LE is only supported in RIGHT_J mode */ 33662306a36Sopenharmony_ci formats |= SNDRV_PCM_FMTBIT_S16_LE; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* 33962306a36Sopenharmony_ci * If multi DIN/DOUT is not selected, RIGHT_J can only support 34062306a36Sopenharmony_ci * two channels (no TDM support) 34162306a36Sopenharmony_ci */ 34262306a36Sopenharmony_ci if (io_params->tdm_slots != 2) 34362306a36Sopenharmony_ci channel_max = 2; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (dai->id == PCM3168A_DAI_DAC) { 34762306a36Sopenharmony_ci dai->driver->playback.channels_max = channel_max; 34862306a36Sopenharmony_ci dai->driver->playback.formats = formats; 34962306a36Sopenharmony_ci } else { 35062306a36Sopenharmony_ci dai->driver->capture.channels_max = channel_max; 35162306a36Sopenharmony_ci dai->driver->capture.formats = formats; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 35862306a36Sopenharmony_ci struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); 35962306a36Sopenharmony_ci struct pcm3168a_io_params *io_params = &pcm3168a->io_params[dai->id]; 36062306a36Sopenharmony_ci bool provider_mode; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { 36362306a36Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 36462306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 36562306a36Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 36662306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 36762306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_B: 36862306a36Sopenharmony_ci break; 36962306a36Sopenharmony_ci default: 37062306a36Sopenharmony_ci dev_err(component->dev, "unsupported dai format\n"); 37162306a36Sopenharmony_ci return -EINVAL; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci switch (format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 37562306a36Sopenharmony_ci case SND_SOC_DAIFMT_CBC_CFC: 37662306a36Sopenharmony_ci provider_mode = false; 37762306a36Sopenharmony_ci break; 37862306a36Sopenharmony_ci case SND_SOC_DAIFMT_CBP_CFP: 37962306a36Sopenharmony_ci provider_mode = true; 38062306a36Sopenharmony_ci break; 38162306a36Sopenharmony_ci default: 38262306a36Sopenharmony_ci dev_err(component->dev, "unsupported provider mode\n"); 38362306a36Sopenharmony_ci return -EINVAL; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci switch (format & SND_SOC_DAIFMT_INV_MASK) { 38762306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 38862306a36Sopenharmony_ci break; 38962306a36Sopenharmony_ci default: 39062306a36Sopenharmony_ci return -EINVAL; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci io_params->provider_mode = provider_mode; 39462306a36Sopenharmony_ci io_params->format = format & SND_SOC_DAIFMT_FORMAT_MASK; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci pcm3168a_update_fixup_pcm_stream(dai); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci return 0; 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic int pcm3168a_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, 40262306a36Sopenharmony_ci unsigned int rx_mask, int slots, 40362306a36Sopenharmony_ci int slot_width) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 40662306a36Sopenharmony_ci struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); 40762306a36Sopenharmony_ci struct pcm3168a_io_params *io_params = &pcm3168a->io_params[dai->id]; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (tx_mask >= (1<<slots) || rx_mask >= (1<<slots)) { 41062306a36Sopenharmony_ci dev_err(component->dev, 41162306a36Sopenharmony_ci "Bad tdm mask tx: 0x%08x rx: 0x%08x slots %d\n", 41262306a36Sopenharmony_ci tx_mask, rx_mask, slots); 41362306a36Sopenharmony_ci return -EINVAL; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (slot_width && 41762306a36Sopenharmony_ci (slot_width != 16 && slot_width != 24 && slot_width != 32 )) { 41862306a36Sopenharmony_ci dev_err(component->dev, "Unsupported slot_width %d\n", 41962306a36Sopenharmony_ci slot_width); 42062306a36Sopenharmony_ci return -EINVAL; 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci io_params->tdm_slots = slots; 42462306a36Sopenharmony_ci io_params->slot_width = slot_width; 42562306a36Sopenharmony_ci /* Ignore the not relevant mask for the DAI/direction */ 42662306a36Sopenharmony_ci if (dai->id == PCM3168A_DAI_DAC) 42762306a36Sopenharmony_ci io_params->tdm_mask = tx_mask; 42862306a36Sopenharmony_ci else 42962306a36Sopenharmony_ci io_params->tdm_mask = rx_mask; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci pcm3168a_update_fixup_pcm_stream(dai); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci return 0; 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic int pcm3168a_hw_params(struct snd_pcm_substream *substream, 43762306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 43862306a36Sopenharmony_ci struct snd_soc_dai *dai) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 44162306a36Sopenharmony_ci struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component); 44262306a36Sopenharmony_ci struct pcm3168a_io_params *io_params = &pcm3168a->io_params[dai->id]; 44362306a36Sopenharmony_ci bool provider_mode, tdm_mode; 44462306a36Sopenharmony_ci unsigned int format; 44562306a36Sopenharmony_ci unsigned int reg, mask, ms, ms_shift, fmt, fmt_shift, ratio, tdm_slots; 44662306a36Sopenharmony_ci int i, num_scki_ratios, slot_width; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci if (dai->id == PCM3168A_DAI_DAC) { 44962306a36Sopenharmony_ci num_scki_ratios = PCM3168A_NUM_SCKI_RATIOS_DAC; 45062306a36Sopenharmony_ci reg = PCM3168A_DAC_PWR_MST_FMT; 45162306a36Sopenharmony_ci mask = PCM3168A_DAC_MSDA_MASK | PCM3168A_DAC_FMT_MASK; 45262306a36Sopenharmony_ci ms_shift = PCM3168A_DAC_MSDA_SHIFT; 45362306a36Sopenharmony_ci fmt_shift = PCM3168A_DAC_FMT_SHIFT; 45462306a36Sopenharmony_ci } else { 45562306a36Sopenharmony_ci num_scki_ratios = PCM3168A_NUM_SCKI_RATIOS_ADC; 45662306a36Sopenharmony_ci reg = PCM3168A_ADC_MST_FMT; 45762306a36Sopenharmony_ci mask = PCM3168A_ADC_MSAD_MASK | PCM3168A_ADC_FMTAD_MASK; 45862306a36Sopenharmony_ci ms_shift = PCM3168A_ADC_MSAD_SHIFT; 45962306a36Sopenharmony_ci fmt_shift = PCM3168A_ADC_FMTAD_SHIFT; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci provider_mode = io_params->provider_mode; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci if (provider_mode) { 46562306a36Sopenharmony_ci ratio = pcm3168a->sysclk / params_rate(params); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci for (i = 0; i < num_scki_ratios; i++) { 46862306a36Sopenharmony_ci if (pcm3168a_scki_ratios[i] == ratio) 46962306a36Sopenharmony_ci break; 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci if (i == num_scki_ratios) { 47362306a36Sopenharmony_ci dev_err(component->dev, "unsupported sysclk ratio\n"); 47462306a36Sopenharmony_ci return -EINVAL; 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci ms = (i + 1); 47862306a36Sopenharmony_ci } else { 47962306a36Sopenharmony_ci ms = 0; 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci format = io_params->format; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci if (io_params->slot_width) 48562306a36Sopenharmony_ci slot_width = io_params->slot_width; 48662306a36Sopenharmony_ci else 48762306a36Sopenharmony_ci slot_width = params_width(params); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci switch (slot_width) { 49062306a36Sopenharmony_ci case 16: 49162306a36Sopenharmony_ci if (provider_mode || (format != SND_SOC_DAIFMT_RIGHT_J)) { 49262306a36Sopenharmony_ci dev_err(component->dev, "16-bit slots are supported only for consumer mode using right justified\n"); 49362306a36Sopenharmony_ci return -EINVAL; 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci break; 49662306a36Sopenharmony_ci case 24: 49762306a36Sopenharmony_ci if (provider_mode || (format == SND_SOC_DAIFMT_DSP_A) || 49862306a36Sopenharmony_ci (format == SND_SOC_DAIFMT_DSP_B)) { 49962306a36Sopenharmony_ci dev_err(component->dev, "24-bit slots not supported in provider mode, or consumer mode using DSP\n"); 50062306a36Sopenharmony_ci return -EINVAL; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci break; 50362306a36Sopenharmony_ci case 32: 50462306a36Sopenharmony_ci break; 50562306a36Sopenharmony_ci default: 50662306a36Sopenharmony_ci dev_err(component->dev, "unsupported frame size: %d\n", slot_width); 50762306a36Sopenharmony_ci return -EINVAL; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (io_params->tdm_slots) 51162306a36Sopenharmony_ci tdm_slots = io_params->tdm_slots; 51262306a36Sopenharmony_ci else 51362306a36Sopenharmony_ci tdm_slots = params_channels(params); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci /* 51662306a36Sopenharmony_ci * Switch the codec to TDM mode when more than 2 TDM slots are needed 51762306a36Sopenharmony_ci * for the stream. 51862306a36Sopenharmony_ci * If pcm3168a->tdm_slots is not set or set to more than 2 (8/6 usually) 51962306a36Sopenharmony_ci * then DIN1/DOUT1 is used in TDM mode. 52062306a36Sopenharmony_ci * If pcm3168a->tdm_slots is set to 2 then DIN1/2/3/4 and DOUT1/2/3 is 52162306a36Sopenharmony_ci * used in normal mode, no need to switch to TDM modes. 52262306a36Sopenharmony_ci */ 52362306a36Sopenharmony_ci tdm_mode = (tdm_slots > 2); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci if (tdm_mode) { 52662306a36Sopenharmony_ci switch (format) { 52762306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 52862306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 52962306a36Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 53062306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_B: 53162306a36Sopenharmony_ci break; 53262306a36Sopenharmony_ci default: 53362306a36Sopenharmony_ci dev_err(component->dev, 53462306a36Sopenharmony_ci "TDM is supported under DSP/I2S/Left_J only\n"); 53562306a36Sopenharmony_ci return -EINVAL; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci switch (format) { 54062306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 54162306a36Sopenharmony_ci fmt = tdm_mode ? PCM3168A_FMT_I2S_TDM : PCM3168A_FMT_I2S; 54262306a36Sopenharmony_ci break; 54362306a36Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 54462306a36Sopenharmony_ci fmt = tdm_mode ? PCM3168A_FMT_LEFT_J_TDM : PCM3168A_FMT_LEFT_J; 54562306a36Sopenharmony_ci break; 54662306a36Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 54762306a36Sopenharmony_ci fmt = (slot_width == 16) ? PCM3168A_FMT_RIGHT_J_16 : 54862306a36Sopenharmony_ci PCM3168A_FMT_RIGHT_J; 54962306a36Sopenharmony_ci break; 55062306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 55162306a36Sopenharmony_ci fmt = tdm_mode ? PCM3168A_FMT_I2S_TDM : PCM3168A_FMT_DSP_A; 55262306a36Sopenharmony_ci break; 55362306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_B: 55462306a36Sopenharmony_ci fmt = tdm_mode ? PCM3168A_FMT_LEFT_J_TDM : PCM3168A_FMT_DSP_B; 55562306a36Sopenharmony_ci break; 55662306a36Sopenharmony_ci default: 55762306a36Sopenharmony_ci return -EINVAL; 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci regmap_update_bits(pcm3168a->regmap, reg, mask, 56162306a36Sopenharmony_ci (ms << ms_shift) | (fmt << fmt_shift)); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci return 0; 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_cistatic u64 pcm3168a_dai_formats[] = { 56762306a36Sopenharmony_ci /* 56862306a36Sopenharmony_ci * Select below from Sound Card, not here 56962306a36Sopenharmony_ci * SND_SOC_DAIFMT_CBC_CFC 57062306a36Sopenharmony_ci * SND_SOC_DAIFMT_CBP_CFP 57162306a36Sopenharmony_ci */ 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci /* 57462306a36Sopenharmony_ci * First Priority 57562306a36Sopenharmony_ci */ 57662306a36Sopenharmony_ci SND_SOC_POSSIBLE_DAIFMT_I2S | 57762306a36Sopenharmony_ci SND_SOC_POSSIBLE_DAIFMT_LEFT_J, 57862306a36Sopenharmony_ci /* 57962306a36Sopenharmony_ci * Second Priority 58062306a36Sopenharmony_ci * 58162306a36Sopenharmony_ci * These have picky limitation. 58262306a36Sopenharmony_ci * see 58362306a36Sopenharmony_ci * pcm3168a_hw_params() 58462306a36Sopenharmony_ci */ 58562306a36Sopenharmony_ci SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | 58662306a36Sopenharmony_ci SND_SOC_POSSIBLE_DAIFMT_DSP_A | 58762306a36Sopenharmony_ci SND_SOC_POSSIBLE_DAIFMT_DSP_B, 58862306a36Sopenharmony_ci}; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cistatic const struct snd_soc_dai_ops pcm3168a_dai_ops = { 59162306a36Sopenharmony_ci .set_fmt = pcm3168a_set_dai_fmt, 59262306a36Sopenharmony_ci .set_sysclk = pcm3168a_set_dai_sysclk, 59362306a36Sopenharmony_ci .hw_params = pcm3168a_hw_params, 59462306a36Sopenharmony_ci .mute_stream = pcm3168a_mute, 59562306a36Sopenharmony_ci .set_tdm_slot = pcm3168a_set_tdm_slot, 59662306a36Sopenharmony_ci .no_capture_mute = 1, 59762306a36Sopenharmony_ci .auto_selectable_formats = pcm3168a_dai_formats, 59862306a36Sopenharmony_ci .num_auto_selectable_formats = ARRAY_SIZE(pcm3168a_dai_formats), 59962306a36Sopenharmony_ci}; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistatic struct snd_soc_dai_driver pcm3168a_dais[] = { 60262306a36Sopenharmony_ci { 60362306a36Sopenharmony_ci .name = "pcm3168a-dac", 60462306a36Sopenharmony_ci .id = PCM3168A_DAI_DAC, 60562306a36Sopenharmony_ci .playback = { 60662306a36Sopenharmony_ci .stream_name = "Playback", 60762306a36Sopenharmony_ci .channels_min = 1, 60862306a36Sopenharmony_ci .channels_max = 8, 60962306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_192000, 61062306a36Sopenharmony_ci .formats = PCM3168A_FORMATS 61162306a36Sopenharmony_ci }, 61262306a36Sopenharmony_ci .ops = &pcm3168a_dai_ops 61362306a36Sopenharmony_ci }, 61462306a36Sopenharmony_ci { 61562306a36Sopenharmony_ci .name = "pcm3168a-adc", 61662306a36Sopenharmony_ci .id = PCM3168A_DAI_ADC, 61762306a36Sopenharmony_ci .capture = { 61862306a36Sopenharmony_ci .stream_name = "Capture", 61962306a36Sopenharmony_ci .channels_min = 1, 62062306a36Sopenharmony_ci .channels_max = 6, 62162306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_96000, 62262306a36Sopenharmony_ci .formats = PCM3168A_FORMATS 62362306a36Sopenharmony_ci }, 62462306a36Sopenharmony_ci .ops = &pcm3168a_dai_ops 62562306a36Sopenharmony_ci }, 62662306a36Sopenharmony_ci}; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_cistatic const struct reg_default pcm3168a_reg_default[] = { 62962306a36Sopenharmony_ci { PCM3168A_RST_SMODE, PCM3168A_MRST_MASK | PCM3168A_SRST_MASK }, 63062306a36Sopenharmony_ci { PCM3168A_DAC_PWR_MST_FMT, 0x00 }, 63162306a36Sopenharmony_ci { PCM3168A_DAC_OP_FLT, 0x00 }, 63262306a36Sopenharmony_ci { PCM3168A_DAC_INV, 0x00 }, 63362306a36Sopenharmony_ci { PCM3168A_DAC_MUTE, 0x00 }, 63462306a36Sopenharmony_ci { PCM3168A_DAC_ZERO, 0x00 }, 63562306a36Sopenharmony_ci { PCM3168A_DAC_ATT_DEMP_ZF, 0x00 }, 63662306a36Sopenharmony_ci { PCM3168A_DAC_VOL_MASTER, 0xff }, 63762306a36Sopenharmony_ci { PCM3168A_DAC_VOL_CHAN_START, 0xff }, 63862306a36Sopenharmony_ci { PCM3168A_DAC_VOL_CHAN_START + 1, 0xff }, 63962306a36Sopenharmony_ci { PCM3168A_DAC_VOL_CHAN_START + 2, 0xff }, 64062306a36Sopenharmony_ci { PCM3168A_DAC_VOL_CHAN_START + 3, 0xff }, 64162306a36Sopenharmony_ci { PCM3168A_DAC_VOL_CHAN_START + 4, 0xff }, 64262306a36Sopenharmony_ci { PCM3168A_DAC_VOL_CHAN_START + 5, 0xff }, 64362306a36Sopenharmony_ci { PCM3168A_DAC_VOL_CHAN_START + 6, 0xff }, 64462306a36Sopenharmony_ci { PCM3168A_DAC_VOL_CHAN_START + 7, 0xff }, 64562306a36Sopenharmony_ci { PCM3168A_ADC_SMODE, 0x00 }, 64662306a36Sopenharmony_ci { PCM3168A_ADC_MST_FMT, 0x00 }, 64762306a36Sopenharmony_ci { PCM3168A_ADC_PWR_HPFB, 0x00 }, 64862306a36Sopenharmony_ci { PCM3168A_ADC_SEAD, 0x00 }, 64962306a36Sopenharmony_ci { PCM3168A_ADC_INV, 0x00 }, 65062306a36Sopenharmony_ci { PCM3168A_ADC_MUTE, 0x00 }, 65162306a36Sopenharmony_ci { PCM3168A_ADC_OV, 0x00 }, 65262306a36Sopenharmony_ci { PCM3168A_ADC_ATT_OVF, 0x00 }, 65362306a36Sopenharmony_ci { PCM3168A_ADC_VOL_MASTER, 0xd3 }, 65462306a36Sopenharmony_ci { PCM3168A_ADC_VOL_CHAN_START, 0xd3 }, 65562306a36Sopenharmony_ci { PCM3168A_ADC_VOL_CHAN_START + 1, 0xd3 }, 65662306a36Sopenharmony_ci { PCM3168A_ADC_VOL_CHAN_START + 2, 0xd3 }, 65762306a36Sopenharmony_ci { PCM3168A_ADC_VOL_CHAN_START + 3, 0xd3 }, 65862306a36Sopenharmony_ci { PCM3168A_ADC_VOL_CHAN_START + 4, 0xd3 }, 65962306a36Sopenharmony_ci { PCM3168A_ADC_VOL_CHAN_START + 5, 0xd3 } 66062306a36Sopenharmony_ci}; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_cistatic bool pcm3168a_readable_register(struct device *dev, unsigned int reg) 66362306a36Sopenharmony_ci{ 66462306a36Sopenharmony_ci if (reg >= PCM3168A_RST_SMODE) 66562306a36Sopenharmony_ci return true; 66662306a36Sopenharmony_ci else 66762306a36Sopenharmony_ci return false; 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_cistatic bool pcm3168a_volatile_register(struct device *dev, unsigned int reg) 67162306a36Sopenharmony_ci{ 67262306a36Sopenharmony_ci switch (reg) { 67362306a36Sopenharmony_ci case PCM3168A_RST_SMODE: 67462306a36Sopenharmony_ci case PCM3168A_DAC_ZERO: 67562306a36Sopenharmony_ci case PCM3168A_ADC_OV: 67662306a36Sopenharmony_ci return true; 67762306a36Sopenharmony_ci default: 67862306a36Sopenharmony_ci return false; 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic bool pcm3168a_writeable_register(struct device *dev, unsigned int reg) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci if (reg < PCM3168A_RST_SMODE) 68562306a36Sopenharmony_ci return false; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci switch (reg) { 68862306a36Sopenharmony_ci case PCM3168A_DAC_ZERO: 68962306a36Sopenharmony_ci case PCM3168A_ADC_OV: 69062306a36Sopenharmony_ci return false; 69162306a36Sopenharmony_ci default: 69262306a36Sopenharmony_ci return true; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ciconst struct regmap_config pcm3168a_regmap = { 69762306a36Sopenharmony_ci .reg_bits = 8, 69862306a36Sopenharmony_ci .val_bits = 8, 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci .max_register = PCM3168A_ADC_VOL_CHAN_START + 5, 70162306a36Sopenharmony_ci .reg_defaults = pcm3168a_reg_default, 70262306a36Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(pcm3168a_reg_default), 70362306a36Sopenharmony_ci .readable_reg = pcm3168a_readable_register, 70462306a36Sopenharmony_ci .volatile_reg = pcm3168a_volatile_register, 70562306a36Sopenharmony_ci .writeable_reg = pcm3168a_writeable_register, 70662306a36Sopenharmony_ci .cache_type = REGCACHE_FLAT 70762306a36Sopenharmony_ci}; 70862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pcm3168a_regmap); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cistatic const struct snd_soc_component_driver pcm3168a_driver = { 71162306a36Sopenharmony_ci .controls = pcm3168a_snd_controls, 71262306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(pcm3168a_snd_controls), 71362306a36Sopenharmony_ci .dapm_widgets = pcm3168a_dapm_widgets, 71462306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(pcm3168a_dapm_widgets), 71562306a36Sopenharmony_ci .dapm_routes = pcm3168a_dapm_routes, 71662306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(pcm3168a_dapm_routes), 71762306a36Sopenharmony_ci .use_pmdown_time = 1, 71862306a36Sopenharmony_ci .endianness = 1, 71962306a36Sopenharmony_ci}; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ciint pcm3168a_probe(struct device *dev, struct regmap *regmap) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci struct pcm3168a_priv *pcm3168a; 72462306a36Sopenharmony_ci int ret, i; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci pcm3168a = devm_kzalloc(dev, sizeof(*pcm3168a), GFP_KERNEL); 72762306a36Sopenharmony_ci if (pcm3168a == NULL) 72862306a36Sopenharmony_ci return -ENOMEM; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci dev_set_drvdata(dev, pcm3168a); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci /* 73362306a36Sopenharmony_ci * Request the reset (connected to RST pin) gpio line as non exclusive 73462306a36Sopenharmony_ci * as the same reset line might be connected to multiple pcm3168a codec 73562306a36Sopenharmony_ci * 73662306a36Sopenharmony_ci * The RST is low active, we want the GPIO line to be high initially, so 73762306a36Sopenharmony_ci * request the initial level to LOW which in practice means DEASSERTED: 73862306a36Sopenharmony_ci * The deasserted level of GPIO_ACTIVE_LOW is HIGH. 73962306a36Sopenharmony_ci */ 74062306a36Sopenharmony_ci pcm3168a->gpio_rst = devm_gpiod_get_optional(dev, "reset", 74162306a36Sopenharmony_ci GPIOD_OUT_LOW | 74262306a36Sopenharmony_ci GPIOD_FLAGS_BIT_NONEXCLUSIVE); 74362306a36Sopenharmony_ci if (IS_ERR(pcm3168a->gpio_rst)) 74462306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(pcm3168a->gpio_rst), 74562306a36Sopenharmony_ci "failed to acquire RST gpio\n"); 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci pcm3168a->scki = devm_clk_get(dev, "scki"); 74862306a36Sopenharmony_ci if (IS_ERR(pcm3168a->scki)) 74962306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(pcm3168a->scki), 75062306a36Sopenharmony_ci "failed to acquire clock 'scki'\n"); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci ret = clk_prepare_enable(pcm3168a->scki); 75362306a36Sopenharmony_ci if (ret) { 75462306a36Sopenharmony_ci dev_err(dev, "Failed to enable mclk: %d\n", ret); 75562306a36Sopenharmony_ci return ret; 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci pcm3168a->sysclk = clk_get_rate(pcm3168a->scki); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pcm3168a->supplies); i++) 76162306a36Sopenharmony_ci pcm3168a->supplies[i].supply = pcm3168a_supply_names[i]; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci ret = devm_regulator_bulk_get(dev, 76462306a36Sopenharmony_ci ARRAY_SIZE(pcm3168a->supplies), pcm3168a->supplies); 76562306a36Sopenharmony_ci if (ret) { 76662306a36Sopenharmony_ci dev_err_probe(dev, ret, "failed to request supplies\n"); 76762306a36Sopenharmony_ci goto err_clk; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci ret = regulator_bulk_enable(ARRAY_SIZE(pcm3168a->supplies), 77162306a36Sopenharmony_ci pcm3168a->supplies); 77262306a36Sopenharmony_ci if (ret) { 77362306a36Sopenharmony_ci dev_err(dev, "failed to enable supplies: %d\n", ret); 77462306a36Sopenharmony_ci goto err_clk; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci pcm3168a->regmap = regmap; 77862306a36Sopenharmony_ci if (IS_ERR(pcm3168a->regmap)) { 77962306a36Sopenharmony_ci ret = PTR_ERR(pcm3168a->regmap); 78062306a36Sopenharmony_ci dev_err(dev, "failed to allocate regmap: %d\n", ret); 78162306a36Sopenharmony_ci goto err_regulator; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci if (pcm3168a->gpio_rst) { 78562306a36Sopenharmony_ci /* 78662306a36Sopenharmony_ci * The device is taken out from reset via GPIO line, wait for 78762306a36Sopenharmony_ci * 3846 SCKI clock cycles for the internal reset de-assertion 78862306a36Sopenharmony_ci */ 78962306a36Sopenharmony_ci msleep(DIV_ROUND_UP(3846 * 1000, pcm3168a->sysclk)); 79062306a36Sopenharmony_ci } else { 79162306a36Sopenharmony_ci ret = pcm3168a_reset(pcm3168a); 79262306a36Sopenharmony_ci if (ret) { 79362306a36Sopenharmony_ci dev_err(dev, "Failed to reset device: %d\n", ret); 79462306a36Sopenharmony_ci goto err_regulator; 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci pm_runtime_set_active(dev); 79962306a36Sopenharmony_ci pm_runtime_enable(dev); 80062306a36Sopenharmony_ci pm_runtime_idle(dev); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci memcpy(pcm3168a->dai_drv, pcm3168a_dais, sizeof(pcm3168a->dai_drv)); 80362306a36Sopenharmony_ci ret = devm_snd_soc_register_component(dev, &pcm3168a_driver, 80462306a36Sopenharmony_ci pcm3168a->dai_drv, 80562306a36Sopenharmony_ci ARRAY_SIZE(pcm3168a->dai_drv)); 80662306a36Sopenharmony_ci if (ret) { 80762306a36Sopenharmony_ci dev_err(dev, "failed to register component: %d\n", ret); 80862306a36Sopenharmony_ci goto err_regulator; 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci return 0; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_cierr_regulator: 81462306a36Sopenharmony_ci regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies), 81562306a36Sopenharmony_ci pcm3168a->supplies); 81662306a36Sopenharmony_cierr_clk: 81762306a36Sopenharmony_ci clk_disable_unprepare(pcm3168a->scki); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci return ret; 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pcm3168a_probe); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_cistatic void pcm3168a_disable(struct device *dev) 82462306a36Sopenharmony_ci{ 82562306a36Sopenharmony_ci struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies), 82862306a36Sopenharmony_ci pcm3168a->supplies); 82962306a36Sopenharmony_ci clk_disable_unprepare(pcm3168a->scki); 83062306a36Sopenharmony_ci} 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_civoid pcm3168a_remove(struct device *dev) 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci /* 83762306a36Sopenharmony_ci * The RST is low active, we want the GPIO line to be low when the 83862306a36Sopenharmony_ci * driver is removed, so set level to 1 which in practice means 83962306a36Sopenharmony_ci * ASSERTED: 84062306a36Sopenharmony_ci * The asserted level of GPIO_ACTIVE_LOW is LOW. 84162306a36Sopenharmony_ci */ 84262306a36Sopenharmony_ci gpiod_set_value_cansleep(pcm3168a->gpio_rst, 1); 84362306a36Sopenharmony_ci pm_runtime_disable(dev); 84462306a36Sopenharmony_ci#ifndef CONFIG_PM 84562306a36Sopenharmony_ci pcm3168a_disable(dev); 84662306a36Sopenharmony_ci#endif 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pcm3168a_remove); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci#ifdef CONFIG_PM 85162306a36Sopenharmony_cistatic int pcm3168a_rt_resume(struct device *dev) 85262306a36Sopenharmony_ci{ 85362306a36Sopenharmony_ci struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev); 85462306a36Sopenharmony_ci int ret; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci ret = clk_prepare_enable(pcm3168a->scki); 85762306a36Sopenharmony_ci if (ret) { 85862306a36Sopenharmony_ci dev_err(dev, "Failed to enable mclk: %d\n", ret); 85962306a36Sopenharmony_ci return ret; 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci ret = regulator_bulk_enable(ARRAY_SIZE(pcm3168a->supplies), 86362306a36Sopenharmony_ci pcm3168a->supplies); 86462306a36Sopenharmony_ci if (ret) { 86562306a36Sopenharmony_ci dev_err(dev, "Failed to enable supplies: %d\n", ret); 86662306a36Sopenharmony_ci goto err_clk; 86762306a36Sopenharmony_ci } 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci ret = pcm3168a_reset(pcm3168a); 87062306a36Sopenharmony_ci if (ret) { 87162306a36Sopenharmony_ci dev_err(dev, "Failed to reset device: %d\n", ret); 87262306a36Sopenharmony_ci goto err_regulator; 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci regcache_cache_only(pcm3168a->regmap, false); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci regcache_mark_dirty(pcm3168a->regmap); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci ret = regcache_sync(pcm3168a->regmap); 88062306a36Sopenharmony_ci if (ret) { 88162306a36Sopenharmony_ci dev_err(dev, "Failed to sync regmap: %d\n", ret); 88262306a36Sopenharmony_ci goto err_regulator; 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci return 0; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_cierr_regulator: 88862306a36Sopenharmony_ci regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies), 88962306a36Sopenharmony_ci pcm3168a->supplies); 89062306a36Sopenharmony_cierr_clk: 89162306a36Sopenharmony_ci clk_disable_unprepare(pcm3168a->scki); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci return ret; 89462306a36Sopenharmony_ci} 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_cistatic int pcm3168a_rt_suspend(struct device *dev) 89762306a36Sopenharmony_ci{ 89862306a36Sopenharmony_ci struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci regcache_cache_only(pcm3168a->regmap, true); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci pcm3168a_disable(dev); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci return 0; 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci#endif 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ciconst struct dev_pm_ops pcm3168a_pm_ops = { 90962306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(pcm3168a_rt_suspend, pcm3168a_rt_resume, NULL) 91062306a36Sopenharmony_ci}; 91162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pcm3168a_pm_ops); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ciMODULE_DESCRIPTION("PCM3168A codec driver"); 91462306a36Sopenharmony_ciMODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>"); 91562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 916