162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * cs35l33.c -- CS35L33 ALSA SoC audio driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2016 Cirrus Logic, Inc. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Paul Handrigan <paul.handrigan@cirrus.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/moduleparam.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/delay.h> 1462306a36Sopenharmony_ci#include <linux/i2c.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/workqueue.h> 1762306a36Sopenharmony_ci#include <linux/platform_device.h> 1862306a36Sopenharmony_ci#include <sound/core.h> 1962306a36Sopenharmony_ci#include <sound/pcm.h> 2062306a36Sopenharmony_ci#include <sound/pcm_params.h> 2162306a36Sopenharmony_ci#include <sound/soc.h> 2262306a36Sopenharmony_ci#include <sound/soc-dapm.h> 2362306a36Sopenharmony_ci#include <sound/initval.h> 2462306a36Sopenharmony_ci#include <sound/tlv.h> 2562306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 2662306a36Sopenharmony_ci#include <sound/cs35l33.h> 2762306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2862306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 2962306a36Sopenharmony_ci#include <linux/regulator/machine.h> 3062306a36Sopenharmony_ci#include <linux/of.h> 3162306a36Sopenharmony_ci#include <linux/of_device.h> 3262306a36Sopenharmony_ci#include <linux/of_irq.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include "cs35l33.h" 3562306a36Sopenharmony_ci#include "cirrus_legacy.h" 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define CS35L33_BOOT_DELAY 50 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistruct cs35l33_private { 4062306a36Sopenharmony_ci struct snd_soc_component *component; 4162306a36Sopenharmony_ci struct cs35l33_pdata pdata; 4262306a36Sopenharmony_ci struct regmap *regmap; 4362306a36Sopenharmony_ci struct gpio_desc *reset_gpio; 4462306a36Sopenharmony_ci bool amp_cal; 4562306a36Sopenharmony_ci int mclk_int; 4662306a36Sopenharmony_ci struct regulator_bulk_data core_supplies[2]; 4762306a36Sopenharmony_ci int num_core_supplies; 4862306a36Sopenharmony_ci bool is_tdm_mode; 4962306a36Sopenharmony_ci bool enable_soft_ramp; 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic const struct reg_default cs35l33_reg[] = { 5362306a36Sopenharmony_ci {CS35L33_PWRCTL1, 0x85}, 5462306a36Sopenharmony_ci {CS35L33_PWRCTL2, 0xFE}, 5562306a36Sopenharmony_ci {CS35L33_CLK_CTL, 0x0C}, 5662306a36Sopenharmony_ci {CS35L33_BST_PEAK_CTL, 0x90}, 5762306a36Sopenharmony_ci {CS35L33_PROTECT_CTL, 0x55}, 5862306a36Sopenharmony_ci {CS35L33_BST_CTL1, 0x00}, 5962306a36Sopenharmony_ci {CS35L33_BST_CTL2, 0x01}, 6062306a36Sopenharmony_ci {CS35L33_ADSP_CTL, 0x00}, 6162306a36Sopenharmony_ci {CS35L33_ADC_CTL, 0xC8}, 6262306a36Sopenharmony_ci {CS35L33_DAC_CTL, 0x14}, 6362306a36Sopenharmony_ci {CS35L33_DIG_VOL_CTL, 0x00}, 6462306a36Sopenharmony_ci {CS35L33_CLASSD_CTL, 0x04}, 6562306a36Sopenharmony_ci {CS35L33_AMP_CTL, 0x90}, 6662306a36Sopenharmony_ci {CS35L33_INT_MASK_1, 0xFF}, 6762306a36Sopenharmony_ci {CS35L33_INT_MASK_2, 0xFF}, 6862306a36Sopenharmony_ci {CS35L33_DIAG_LOCK, 0x00}, 6962306a36Sopenharmony_ci {CS35L33_DIAG_CTRL_1, 0x40}, 7062306a36Sopenharmony_ci {CS35L33_DIAG_CTRL_2, 0x00}, 7162306a36Sopenharmony_ci {CS35L33_HG_MEMLDO_CTL, 0x62}, 7262306a36Sopenharmony_ci {CS35L33_HG_REL_RATE, 0x03}, 7362306a36Sopenharmony_ci {CS35L33_LDO_DEL, 0x12}, 7462306a36Sopenharmony_ci {CS35L33_HG_HEAD, 0x0A}, 7562306a36Sopenharmony_ci {CS35L33_HG_EN, 0x05}, 7662306a36Sopenharmony_ci {CS35L33_TX_VMON, 0x00}, 7762306a36Sopenharmony_ci {CS35L33_TX_IMON, 0x03}, 7862306a36Sopenharmony_ci {CS35L33_TX_VPMON, 0x02}, 7962306a36Sopenharmony_ci {CS35L33_TX_VBSTMON, 0x05}, 8062306a36Sopenharmony_ci {CS35L33_TX_FLAG, 0x06}, 8162306a36Sopenharmony_ci {CS35L33_TX_EN1, 0x00}, 8262306a36Sopenharmony_ci {CS35L33_TX_EN2, 0x00}, 8362306a36Sopenharmony_ci {CS35L33_TX_EN3, 0x00}, 8462306a36Sopenharmony_ci {CS35L33_TX_EN4, 0x00}, 8562306a36Sopenharmony_ci {CS35L33_RX_AUD, 0x40}, 8662306a36Sopenharmony_ci {CS35L33_RX_SPLY, 0x03}, 8762306a36Sopenharmony_ci {CS35L33_RX_ALIVE, 0x04}, 8862306a36Sopenharmony_ci {CS35L33_BST_CTL4, 0x63}, 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic const struct reg_sequence cs35l33_patch[] = { 9262306a36Sopenharmony_ci { 0x00, 0x99, 0 }, 9362306a36Sopenharmony_ci { 0x59, 0x02, 0 }, 9462306a36Sopenharmony_ci { 0x52, 0x30, 0 }, 9562306a36Sopenharmony_ci { 0x39, 0x45, 0 }, 9662306a36Sopenharmony_ci { 0x57, 0x30, 0 }, 9762306a36Sopenharmony_ci { 0x2C, 0x68, 0 }, 9862306a36Sopenharmony_ci { 0x00, 0x00, 0 }, 9962306a36Sopenharmony_ci}; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic bool cs35l33_volatile_register(struct device *dev, unsigned int reg) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci switch (reg) { 10462306a36Sopenharmony_ci case CS35L33_DEVID_AB: 10562306a36Sopenharmony_ci case CS35L33_DEVID_CD: 10662306a36Sopenharmony_ci case CS35L33_DEVID_E: 10762306a36Sopenharmony_ci case CS35L33_REV_ID: 10862306a36Sopenharmony_ci case CS35L33_INT_STATUS_1: 10962306a36Sopenharmony_ci case CS35L33_INT_STATUS_2: 11062306a36Sopenharmony_ci case CS35L33_HG_STATUS: 11162306a36Sopenharmony_ci return true; 11262306a36Sopenharmony_ci default: 11362306a36Sopenharmony_ci return false; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic bool cs35l33_writeable_register(struct device *dev, unsigned int reg) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci switch (reg) { 12062306a36Sopenharmony_ci /* these are read only registers */ 12162306a36Sopenharmony_ci case CS35L33_DEVID_AB: 12262306a36Sopenharmony_ci case CS35L33_DEVID_CD: 12362306a36Sopenharmony_ci case CS35L33_DEVID_E: 12462306a36Sopenharmony_ci case CS35L33_REV_ID: 12562306a36Sopenharmony_ci case CS35L33_INT_STATUS_1: 12662306a36Sopenharmony_ci case CS35L33_INT_STATUS_2: 12762306a36Sopenharmony_ci case CS35L33_HG_STATUS: 12862306a36Sopenharmony_ci return false; 12962306a36Sopenharmony_ci default: 13062306a36Sopenharmony_ci return true; 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic bool cs35l33_readable_register(struct device *dev, unsigned int reg) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci switch (reg) { 13762306a36Sopenharmony_ci case CS35L33_DEVID_AB: 13862306a36Sopenharmony_ci case CS35L33_DEVID_CD: 13962306a36Sopenharmony_ci case CS35L33_DEVID_E: 14062306a36Sopenharmony_ci case CS35L33_REV_ID: 14162306a36Sopenharmony_ci case CS35L33_PWRCTL1: 14262306a36Sopenharmony_ci case CS35L33_PWRCTL2: 14362306a36Sopenharmony_ci case CS35L33_CLK_CTL: 14462306a36Sopenharmony_ci case CS35L33_BST_PEAK_CTL: 14562306a36Sopenharmony_ci case CS35L33_PROTECT_CTL: 14662306a36Sopenharmony_ci case CS35L33_BST_CTL1: 14762306a36Sopenharmony_ci case CS35L33_BST_CTL2: 14862306a36Sopenharmony_ci case CS35L33_ADSP_CTL: 14962306a36Sopenharmony_ci case CS35L33_ADC_CTL: 15062306a36Sopenharmony_ci case CS35L33_DAC_CTL: 15162306a36Sopenharmony_ci case CS35L33_DIG_VOL_CTL: 15262306a36Sopenharmony_ci case CS35L33_CLASSD_CTL: 15362306a36Sopenharmony_ci case CS35L33_AMP_CTL: 15462306a36Sopenharmony_ci case CS35L33_INT_MASK_1: 15562306a36Sopenharmony_ci case CS35L33_INT_MASK_2: 15662306a36Sopenharmony_ci case CS35L33_INT_STATUS_1: 15762306a36Sopenharmony_ci case CS35L33_INT_STATUS_2: 15862306a36Sopenharmony_ci case CS35L33_DIAG_LOCK: 15962306a36Sopenharmony_ci case CS35L33_DIAG_CTRL_1: 16062306a36Sopenharmony_ci case CS35L33_DIAG_CTRL_2: 16162306a36Sopenharmony_ci case CS35L33_HG_MEMLDO_CTL: 16262306a36Sopenharmony_ci case CS35L33_HG_REL_RATE: 16362306a36Sopenharmony_ci case CS35L33_LDO_DEL: 16462306a36Sopenharmony_ci case CS35L33_HG_HEAD: 16562306a36Sopenharmony_ci case CS35L33_HG_EN: 16662306a36Sopenharmony_ci case CS35L33_TX_VMON: 16762306a36Sopenharmony_ci case CS35L33_TX_IMON: 16862306a36Sopenharmony_ci case CS35L33_TX_VPMON: 16962306a36Sopenharmony_ci case CS35L33_TX_VBSTMON: 17062306a36Sopenharmony_ci case CS35L33_TX_FLAG: 17162306a36Sopenharmony_ci case CS35L33_TX_EN1: 17262306a36Sopenharmony_ci case CS35L33_TX_EN2: 17362306a36Sopenharmony_ci case CS35L33_TX_EN3: 17462306a36Sopenharmony_ci case CS35L33_TX_EN4: 17562306a36Sopenharmony_ci case CS35L33_RX_AUD: 17662306a36Sopenharmony_ci case CS35L33_RX_SPLY: 17762306a36Sopenharmony_ci case CS35L33_RX_ALIVE: 17862306a36Sopenharmony_ci case CS35L33_BST_CTL4: 17962306a36Sopenharmony_ci return true; 18062306a36Sopenharmony_ci default: 18162306a36Sopenharmony_ci return false; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(classd_ctl_tlv, 900, 100, 0); 18662306a36Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(dac_tlv, -10200, 50, 0); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic const struct snd_kcontrol_new cs35l33_snd_controls[] = { 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci SOC_SINGLE_TLV("SPK Amp Volume", CS35L33_AMP_CTL, 19162306a36Sopenharmony_ci 4, 0x09, 0, classd_ctl_tlv), 19262306a36Sopenharmony_ci SOC_SINGLE_SX_TLV("DAC Volume", CS35L33_DIG_VOL_CTL, 19362306a36Sopenharmony_ci 0, 0x34, 0xE4, dac_tlv), 19462306a36Sopenharmony_ci}; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic int cs35l33_spkrdrv_event(struct snd_soc_dapm_widget *w, 19762306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 20062306a36Sopenharmony_ci struct cs35l33_private *priv = snd_soc_component_get_drvdata(component); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci switch (event) { 20362306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 20462306a36Sopenharmony_ci if (!priv->amp_cal) { 20562306a36Sopenharmony_ci usleep_range(8000, 9000); 20662306a36Sopenharmony_ci priv->amp_cal = true; 20762306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_CLASSD_CTL, 20862306a36Sopenharmony_ci CS35L33_AMP_CAL, 0); 20962306a36Sopenharmony_ci dev_dbg(component->dev, "Amp calibration done\n"); 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci dev_dbg(component->dev, "Amp turned on\n"); 21262306a36Sopenharmony_ci break; 21362306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMD: 21462306a36Sopenharmony_ci dev_dbg(component->dev, "Amp turned off\n"); 21562306a36Sopenharmony_ci break; 21662306a36Sopenharmony_ci default: 21762306a36Sopenharmony_ci dev_err(component->dev, "Invalid event = 0x%x\n", event); 21862306a36Sopenharmony_ci break; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci return 0; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic int cs35l33_sdin_event(struct snd_soc_dapm_widget *w, 22562306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 22862306a36Sopenharmony_ci struct cs35l33_private *priv = snd_soc_component_get_drvdata(component); 22962306a36Sopenharmony_ci unsigned int val; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci switch (event) { 23262306a36Sopenharmony_ci case SND_SOC_DAPM_PRE_PMU: 23362306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_PWRCTL1, 23462306a36Sopenharmony_ci CS35L33_PDN_BST, 0); 23562306a36Sopenharmony_ci val = priv->is_tdm_mode ? 0 : CS35L33_PDN_TDM; 23662306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_PWRCTL2, 23762306a36Sopenharmony_ci CS35L33_PDN_TDM, val); 23862306a36Sopenharmony_ci dev_dbg(component->dev, "BST turned on\n"); 23962306a36Sopenharmony_ci break; 24062306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 24162306a36Sopenharmony_ci dev_dbg(component->dev, "SDIN turned on\n"); 24262306a36Sopenharmony_ci if (!priv->amp_cal) { 24362306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_CLASSD_CTL, 24462306a36Sopenharmony_ci CS35L33_AMP_CAL, CS35L33_AMP_CAL); 24562306a36Sopenharmony_ci dev_dbg(component->dev, "Amp calibration started\n"); 24662306a36Sopenharmony_ci usleep_range(10000, 11000); 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci break; 24962306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMD: 25062306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_PWRCTL2, 25162306a36Sopenharmony_ci CS35L33_PDN_TDM, CS35L33_PDN_TDM); 25262306a36Sopenharmony_ci usleep_range(4000, 4100); 25362306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_PWRCTL1, 25462306a36Sopenharmony_ci CS35L33_PDN_BST, CS35L33_PDN_BST); 25562306a36Sopenharmony_ci dev_dbg(component->dev, "BST and SDIN turned off\n"); 25662306a36Sopenharmony_ci break; 25762306a36Sopenharmony_ci default: 25862306a36Sopenharmony_ci dev_err(component->dev, "Invalid event = 0x%x\n", event); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci return 0; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic int cs35l33_sdout_event(struct snd_soc_dapm_widget *w, 26662306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 26962306a36Sopenharmony_ci struct cs35l33_private *priv = snd_soc_component_get_drvdata(component); 27062306a36Sopenharmony_ci unsigned int mask = CS35L33_SDOUT_3ST_I2S | CS35L33_PDN_TDM; 27162306a36Sopenharmony_ci unsigned int mask2 = CS35L33_SDOUT_3ST_TDM; 27262306a36Sopenharmony_ci unsigned int val, val2; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci switch (event) { 27562306a36Sopenharmony_ci case SND_SOC_DAPM_PRE_PMU: 27662306a36Sopenharmony_ci if (priv->is_tdm_mode) { 27762306a36Sopenharmony_ci /* set sdout_3st_i2s and reset pdn_tdm */ 27862306a36Sopenharmony_ci val = CS35L33_SDOUT_3ST_I2S; 27962306a36Sopenharmony_ci /* reset sdout_3st_tdm */ 28062306a36Sopenharmony_ci val2 = 0; 28162306a36Sopenharmony_ci } else { 28262306a36Sopenharmony_ci /* reset sdout_3st_i2s and set pdn_tdm */ 28362306a36Sopenharmony_ci val = CS35L33_PDN_TDM; 28462306a36Sopenharmony_ci /* set sdout_3st_tdm */ 28562306a36Sopenharmony_ci val2 = CS35L33_SDOUT_3ST_TDM; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci dev_dbg(component->dev, "SDOUT turned on\n"); 28862306a36Sopenharmony_ci break; 28962306a36Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 29062306a36Sopenharmony_ci val = CS35L33_SDOUT_3ST_I2S | CS35L33_PDN_TDM; 29162306a36Sopenharmony_ci val2 = CS35L33_SDOUT_3ST_TDM; 29262306a36Sopenharmony_ci dev_dbg(component->dev, "SDOUT turned off\n"); 29362306a36Sopenharmony_ci break; 29462306a36Sopenharmony_ci default: 29562306a36Sopenharmony_ci dev_err(component->dev, "Invalid event = 0x%x\n", event); 29662306a36Sopenharmony_ci return 0; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_PWRCTL2, 30062306a36Sopenharmony_ci mask, val); 30162306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_CLK_CTL, 30262306a36Sopenharmony_ci mask2, val2); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci return 0; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget cs35l33_dapm_widgets[] = { 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("SPK"), 31062306a36Sopenharmony_ci SND_SOC_DAPM_OUT_DRV_E("SPKDRV", CS35L33_PWRCTL1, 7, 1, NULL, 0, 31162306a36Sopenharmony_ci cs35l33_spkrdrv_event, 31262306a36Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), 31362306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN_E("SDIN", NULL, 0, CS35L33_PWRCTL2, 31462306a36Sopenharmony_ci 2, 1, cs35l33_sdin_event, SND_SOC_DAPM_PRE_PMU | 31562306a36Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("MON"), 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci SND_SOC_DAPM_ADC("VMON", NULL, 32062306a36Sopenharmony_ci CS35L33_PWRCTL2, CS35L33_PDN_VMON_SHIFT, 1), 32162306a36Sopenharmony_ci SND_SOC_DAPM_ADC("IMON", NULL, 32262306a36Sopenharmony_ci CS35L33_PWRCTL2, CS35L33_PDN_IMON_SHIFT, 1), 32362306a36Sopenharmony_ci SND_SOC_DAPM_ADC("VPMON", NULL, 32462306a36Sopenharmony_ci CS35L33_PWRCTL2, CS35L33_PDN_VPMON_SHIFT, 1), 32562306a36Sopenharmony_ci SND_SOC_DAPM_ADC("VBSTMON", NULL, 32662306a36Sopenharmony_ci CS35L33_PWRCTL2, CS35L33_PDN_VBSTMON_SHIFT, 1), 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci SND_SOC_DAPM_AIF_OUT_E("SDOUT", NULL, 0, SND_SOC_NOPM, 0, 0, 32962306a36Sopenharmony_ci cs35l33_sdout_event, SND_SOC_DAPM_PRE_PMU | 33062306a36Sopenharmony_ci SND_SOC_DAPM_PRE_PMD), 33162306a36Sopenharmony_ci}; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic const struct snd_soc_dapm_route cs35l33_audio_map[] = { 33462306a36Sopenharmony_ci {"SDIN", NULL, "CS35L33 Playback"}, 33562306a36Sopenharmony_ci {"SPKDRV", NULL, "SDIN"}, 33662306a36Sopenharmony_ci {"SPK", NULL, "SPKDRV"}, 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci {"VMON", NULL, "MON"}, 33962306a36Sopenharmony_ci {"IMON", NULL, "MON"}, 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci {"SDOUT", NULL, "VMON"}, 34262306a36Sopenharmony_ci {"SDOUT", NULL, "IMON"}, 34362306a36Sopenharmony_ci {"CS35L33 Capture", NULL, "SDOUT"}, 34462306a36Sopenharmony_ci}; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic const struct snd_soc_dapm_route cs35l33_vphg_auto_route[] = { 34762306a36Sopenharmony_ci {"SPKDRV", NULL, "VPMON"}, 34862306a36Sopenharmony_ci {"VPMON", NULL, "CS35L33 Playback"}, 34962306a36Sopenharmony_ci}; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic const struct snd_soc_dapm_route cs35l33_vp_vbst_mon_route[] = { 35262306a36Sopenharmony_ci {"SDOUT", NULL, "VPMON"}, 35362306a36Sopenharmony_ci {"VPMON", NULL, "MON"}, 35462306a36Sopenharmony_ci {"SDOUT", NULL, "VBSTMON"}, 35562306a36Sopenharmony_ci {"VBSTMON", NULL, "MON"}, 35662306a36Sopenharmony_ci}; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic int cs35l33_set_bias_level(struct snd_soc_component *component, 35962306a36Sopenharmony_ci enum snd_soc_bias_level level) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci unsigned int val; 36262306a36Sopenharmony_ci struct cs35l33_private *priv = snd_soc_component_get_drvdata(component); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci switch (level) { 36562306a36Sopenharmony_ci case SND_SOC_BIAS_ON: 36662306a36Sopenharmony_ci break; 36762306a36Sopenharmony_ci case SND_SOC_BIAS_PREPARE: 36862306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_PWRCTL1, 36962306a36Sopenharmony_ci CS35L33_PDN_ALL, 0); 37062306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_CLK_CTL, 37162306a36Sopenharmony_ci CS35L33_MCLKDIS, 0); 37262306a36Sopenharmony_ci break; 37362306a36Sopenharmony_ci case SND_SOC_BIAS_STANDBY: 37462306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_PWRCTL1, 37562306a36Sopenharmony_ci CS35L33_PDN_ALL, CS35L33_PDN_ALL); 37662306a36Sopenharmony_ci regmap_read(priv->regmap, CS35L33_INT_STATUS_2, &val); 37762306a36Sopenharmony_ci usleep_range(1000, 1100); 37862306a36Sopenharmony_ci if (val & CS35L33_PDN_DONE) 37962306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_CLK_CTL, 38062306a36Sopenharmony_ci CS35L33_MCLKDIS, CS35L33_MCLKDIS); 38162306a36Sopenharmony_ci break; 38262306a36Sopenharmony_ci case SND_SOC_BIAS_OFF: 38362306a36Sopenharmony_ci break; 38462306a36Sopenharmony_ci default: 38562306a36Sopenharmony_ci return -EINVAL; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci return 0; 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistruct cs35l33_mclk_div { 39262306a36Sopenharmony_ci int mclk; 39362306a36Sopenharmony_ci int srate; 39462306a36Sopenharmony_ci u8 adsp_rate; 39562306a36Sopenharmony_ci u8 int_fs_ratio; 39662306a36Sopenharmony_ci}; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic const struct cs35l33_mclk_div cs35l33_mclk_coeffs[] = { 39962306a36Sopenharmony_ci /* MCLK, Sample Rate, adsp_rate, int_fs_ratio */ 40062306a36Sopenharmony_ci {5644800, 11025, 0x4, CS35L33_INT_FS_RATE}, 40162306a36Sopenharmony_ci {5644800, 22050, 0x8, CS35L33_INT_FS_RATE}, 40262306a36Sopenharmony_ci {5644800, 44100, 0xC, CS35L33_INT_FS_RATE}, 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci {6000000, 8000, 0x1, 0}, 40562306a36Sopenharmony_ci {6000000, 11025, 0x2, 0}, 40662306a36Sopenharmony_ci {6000000, 11029, 0x3, 0}, 40762306a36Sopenharmony_ci {6000000, 12000, 0x4, 0}, 40862306a36Sopenharmony_ci {6000000, 16000, 0x5, 0}, 40962306a36Sopenharmony_ci {6000000, 22050, 0x6, 0}, 41062306a36Sopenharmony_ci {6000000, 22059, 0x7, 0}, 41162306a36Sopenharmony_ci {6000000, 24000, 0x8, 0}, 41262306a36Sopenharmony_ci {6000000, 32000, 0x9, 0}, 41362306a36Sopenharmony_ci {6000000, 44100, 0xA, 0}, 41462306a36Sopenharmony_ci {6000000, 44118, 0xB, 0}, 41562306a36Sopenharmony_ci {6000000, 48000, 0xC, 0}, 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci {6144000, 8000, 0x1, CS35L33_INT_FS_RATE}, 41862306a36Sopenharmony_ci {6144000, 12000, 0x4, CS35L33_INT_FS_RATE}, 41962306a36Sopenharmony_ci {6144000, 16000, 0x5, CS35L33_INT_FS_RATE}, 42062306a36Sopenharmony_ci {6144000, 24000, 0x8, CS35L33_INT_FS_RATE}, 42162306a36Sopenharmony_ci {6144000, 32000, 0x9, CS35L33_INT_FS_RATE}, 42262306a36Sopenharmony_ci {6144000, 48000, 0xC, CS35L33_INT_FS_RATE}, 42362306a36Sopenharmony_ci}; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic int cs35l33_get_mclk_coeff(int mclk, int srate) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci int i; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cs35l33_mclk_coeffs); i++) { 43062306a36Sopenharmony_ci if (cs35l33_mclk_coeffs[i].mclk == mclk && 43162306a36Sopenharmony_ci cs35l33_mclk_coeffs[i].srate == srate) 43262306a36Sopenharmony_ci return i; 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci return -EINVAL; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic int cs35l33_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 44062306a36Sopenharmony_ci struct cs35l33_private *priv = snd_soc_component_get_drvdata(component); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 44362306a36Sopenharmony_ci case SND_SOC_DAIFMT_CBM_CFM: 44462306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_ADSP_CTL, 44562306a36Sopenharmony_ci CS35L33_MS_MASK, CS35L33_MS_MASK); 44662306a36Sopenharmony_ci dev_dbg(component->dev, "Audio port in master mode\n"); 44762306a36Sopenharmony_ci break; 44862306a36Sopenharmony_ci case SND_SOC_DAIFMT_CBS_CFS: 44962306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_ADSP_CTL, 45062306a36Sopenharmony_ci CS35L33_MS_MASK, 0); 45162306a36Sopenharmony_ci dev_dbg(component->dev, "Audio port in slave mode\n"); 45262306a36Sopenharmony_ci break; 45362306a36Sopenharmony_ci default: 45462306a36Sopenharmony_ci return -EINVAL; 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 45862306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 45962306a36Sopenharmony_ci /* 46062306a36Sopenharmony_ci * tdm mode in cs35l33 resembles dsp-a mode very 46162306a36Sopenharmony_ci * closely, it is dsp-a with fsync shifted left by half bclk 46262306a36Sopenharmony_ci */ 46362306a36Sopenharmony_ci priv->is_tdm_mode = true; 46462306a36Sopenharmony_ci dev_dbg(component->dev, "Audio port in TDM mode\n"); 46562306a36Sopenharmony_ci break; 46662306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 46762306a36Sopenharmony_ci priv->is_tdm_mode = false; 46862306a36Sopenharmony_ci dev_dbg(component->dev, "Audio port in I2S mode\n"); 46962306a36Sopenharmony_ci break; 47062306a36Sopenharmony_ci default: 47162306a36Sopenharmony_ci return -EINVAL; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci return 0; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic int cs35l33_pcm_hw_params(struct snd_pcm_substream *substream, 47862306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 47962306a36Sopenharmony_ci struct snd_soc_dai *dai) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 48262306a36Sopenharmony_ci struct cs35l33_private *priv = snd_soc_component_get_drvdata(component); 48362306a36Sopenharmony_ci int sample_size = params_width(params); 48462306a36Sopenharmony_ci int coeff = cs35l33_get_mclk_coeff(priv->mclk_int, params_rate(params)); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (coeff < 0) 48762306a36Sopenharmony_ci return coeff; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_CLK_CTL, 49062306a36Sopenharmony_ci CS35L33_ADSP_FS | CS35L33_INT_FS_RATE, 49162306a36Sopenharmony_ci cs35l33_mclk_coeffs[coeff].int_fs_ratio 49262306a36Sopenharmony_ci | cs35l33_mclk_coeffs[coeff].adsp_rate); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (priv->is_tdm_mode) { 49562306a36Sopenharmony_ci sample_size = (sample_size / 8) - 1; 49662306a36Sopenharmony_ci if (sample_size > 2) 49762306a36Sopenharmony_ci sample_size = 2; 49862306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_RX_AUD, 49962306a36Sopenharmony_ci CS35L33_AUDIN_RX_DEPTH, 50062306a36Sopenharmony_ci sample_size << CS35L33_AUDIN_RX_DEPTH_SHIFT); 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci dev_dbg(component->dev, "sample rate=%d, bits per sample=%d\n", 50462306a36Sopenharmony_ci params_rate(params), params_width(params)); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci return 0; 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic const unsigned int cs35l33_src_rates[] = { 51062306a36Sopenharmony_ci 8000, 11025, 11029, 12000, 16000, 22050, 51162306a36Sopenharmony_ci 22059, 24000, 32000, 44100, 44118, 48000 51262306a36Sopenharmony_ci}; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list cs35l33_constraints = { 51562306a36Sopenharmony_ci .count = ARRAY_SIZE(cs35l33_src_rates), 51662306a36Sopenharmony_ci .list = cs35l33_src_rates, 51762306a36Sopenharmony_ci}; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cistatic int cs35l33_pcm_startup(struct snd_pcm_substream *substream, 52062306a36Sopenharmony_ci struct snd_soc_dai *dai) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci snd_pcm_hw_constraint_list(substream->runtime, 0, 52362306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, 52462306a36Sopenharmony_ci &cs35l33_constraints); 52562306a36Sopenharmony_ci return 0; 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic int cs35l33_set_tristate(struct snd_soc_dai *dai, int tristate) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 53162306a36Sopenharmony_ci struct cs35l33_private *priv = snd_soc_component_get_drvdata(component); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci if (tristate) { 53462306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_PWRCTL2, 53562306a36Sopenharmony_ci CS35L33_SDOUT_3ST_I2S, CS35L33_SDOUT_3ST_I2S); 53662306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_CLK_CTL, 53762306a36Sopenharmony_ci CS35L33_SDOUT_3ST_TDM, CS35L33_SDOUT_3ST_TDM); 53862306a36Sopenharmony_ci } else { 53962306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_PWRCTL2, 54062306a36Sopenharmony_ci CS35L33_SDOUT_3ST_I2S, 0); 54162306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_CLK_CTL, 54262306a36Sopenharmony_ci CS35L33_SDOUT_3ST_TDM, 0); 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci return 0; 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic int cs35l33_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, 54962306a36Sopenharmony_ci unsigned int rx_mask, int slots, int slot_width) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 55262306a36Sopenharmony_ci struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 55362306a36Sopenharmony_ci struct cs35l33_private *priv = snd_soc_component_get_drvdata(component); 55462306a36Sopenharmony_ci unsigned int reg, bit_pos, i; 55562306a36Sopenharmony_ci int slot, slot_num; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (slot_width != 8) 55862306a36Sopenharmony_ci return -EINVAL; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci /* scan rx_mask for aud slot */ 56162306a36Sopenharmony_ci slot = ffs(rx_mask) - 1; 56262306a36Sopenharmony_ci if (slot >= 0) { 56362306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_RX_AUD, 56462306a36Sopenharmony_ci CS35L33_X_LOC, slot); 56562306a36Sopenharmony_ci dev_dbg(component->dev, "Audio starts from slots %d", slot); 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci /* 56962306a36Sopenharmony_ci * scan tx_mask: vmon(2 slots); imon (2 slots); 57062306a36Sopenharmony_ci * vpmon (1 slot) vbstmon (1 slot) 57162306a36Sopenharmony_ci */ 57262306a36Sopenharmony_ci slot = ffs(tx_mask) - 1; 57362306a36Sopenharmony_ci slot_num = 0; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci for (i = 0; i < 2 ; i++) { 57662306a36Sopenharmony_ci /* disable vpmon/vbstmon: enable later if set in tx_mask */ 57762306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_TX_VPMON + i, 57862306a36Sopenharmony_ci CS35L33_X_STATE | CS35L33_X_LOC, CS35L33_X_STATE 57962306a36Sopenharmony_ci | CS35L33_X_LOC); 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci /* disconnect {vp,vbst}_mon routes: eanble later if set in tx_mask*/ 58362306a36Sopenharmony_ci snd_soc_dapm_del_routes(dapm, cs35l33_vp_vbst_mon_route, 58462306a36Sopenharmony_ci ARRAY_SIZE(cs35l33_vp_vbst_mon_route)); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci while (slot >= 0) { 58762306a36Sopenharmony_ci /* configure VMON_TX_LOC */ 58862306a36Sopenharmony_ci if (slot_num == 0) { 58962306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_TX_VMON, 59062306a36Sopenharmony_ci CS35L33_X_STATE | CS35L33_X_LOC, slot); 59162306a36Sopenharmony_ci dev_dbg(component->dev, "VMON enabled in slots %d-%d", 59262306a36Sopenharmony_ci slot, slot + 1); 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci /* configure IMON_TX_LOC */ 59662306a36Sopenharmony_ci if (slot_num == 3) { 59762306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_TX_IMON, 59862306a36Sopenharmony_ci CS35L33_X_STATE | CS35L33_X_LOC, slot); 59962306a36Sopenharmony_ci dev_dbg(component->dev, "IMON enabled in slots %d-%d", 60062306a36Sopenharmony_ci slot, slot + 1); 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci /* configure VPMON_TX_LOC */ 60462306a36Sopenharmony_ci if (slot_num == 4) { 60562306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_TX_VPMON, 60662306a36Sopenharmony_ci CS35L33_X_STATE | CS35L33_X_LOC, slot); 60762306a36Sopenharmony_ci snd_soc_dapm_add_routes(dapm, 60862306a36Sopenharmony_ci &cs35l33_vp_vbst_mon_route[0], 2); 60962306a36Sopenharmony_ci dev_dbg(component->dev, "VPMON enabled in slots %d", slot); 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci /* configure VBSTMON_TX_LOC */ 61362306a36Sopenharmony_ci if (slot_num == 5) { 61462306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_TX_VBSTMON, 61562306a36Sopenharmony_ci CS35L33_X_STATE | CS35L33_X_LOC, slot); 61662306a36Sopenharmony_ci snd_soc_dapm_add_routes(dapm, 61762306a36Sopenharmony_ci &cs35l33_vp_vbst_mon_route[2], 2); 61862306a36Sopenharmony_ci dev_dbg(component->dev, 61962306a36Sopenharmony_ci "VBSTMON enabled in slots %d", slot); 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci /* Enable the relevant tx slot */ 62362306a36Sopenharmony_ci reg = CS35L33_TX_EN4 - (slot/8); 62462306a36Sopenharmony_ci bit_pos = slot - ((slot / 8) * (8)); 62562306a36Sopenharmony_ci regmap_update_bits(priv->regmap, reg, 62662306a36Sopenharmony_ci 1 << bit_pos, 1 << bit_pos); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci tx_mask &= ~(1 << slot); 62962306a36Sopenharmony_ci slot = ffs(tx_mask) - 1; 63062306a36Sopenharmony_ci slot_num++; 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci return 0; 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistatic int cs35l33_component_set_sysclk(struct snd_soc_component *component, 63762306a36Sopenharmony_ci int clk_id, int source, unsigned int freq, int dir) 63862306a36Sopenharmony_ci{ 63962306a36Sopenharmony_ci struct cs35l33_private *cs35l33 = snd_soc_component_get_drvdata(component); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci switch (freq) { 64262306a36Sopenharmony_ci case CS35L33_MCLK_5644: 64362306a36Sopenharmony_ci case CS35L33_MCLK_6: 64462306a36Sopenharmony_ci case CS35L33_MCLK_6144: 64562306a36Sopenharmony_ci regmap_update_bits(cs35l33->regmap, CS35L33_CLK_CTL, 64662306a36Sopenharmony_ci CS35L33_MCLKDIV2, 0); 64762306a36Sopenharmony_ci cs35l33->mclk_int = freq; 64862306a36Sopenharmony_ci break; 64962306a36Sopenharmony_ci case CS35L33_MCLK_11289: 65062306a36Sopenharmony_ci case CS35L33_MCLK_12: 65162306a36Sopenharmony_ci case CS35L33_MCLK_12288: 65262306a36Sopenharmony_ci regmap_update_bits(cs35l33->regmap, CS35L33_CLK_CTL, 65362306a36Sopenharmony_ci CS35L33_MCLKDIV2, CS35L33_MCLKDIV2); 65462306a36Sopenharmony_ci cs35l33->mclk_int = freq/2; 65562306a36Sopenharmony_ci break; 65662306a36Sopenharmony_ci default: 65762306a36Sopenharmony_ci cs35l33->mclk_int = 0; 65862306a36Sopenharmony_ci return -EINVAL; 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci dev_dbg(component->dev, "external mclk freq=%d, internal mclk freq=%d\n", 66262306a36Sopenharmony_ci freq, cs35l33->mclk_int); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci return 0; 66562306a36Sopenharmony_ci} 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_cistatic const struct snd_soc_dai_ops cs35l33_ops = { 66862306a36Sopenharmony_ci .startup = cs35l33_pcm_startup, 66962306a36Sopenharmony_ci .set_tristate = cs35l33_set_tristate, 67062306a36Sopenharmony_ci .set_fmt = cs35l33_set_dai_fmt, 67162306a36Sopenharmony_ci .hw_params = cs35l33_pcm_hw_params, 67262306a36Sopenharmony_ci .set_tdm_slot = cs35l33_set_tdm_slot, 67362306a36Sopenharmony_ci}; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_cistatic struct snd_soc_dai_driver cs35l33_dai = { 67662306a36Sopenharmony_ci .name = "cs35l33-dai", 67762306a36Sopenharmony_ci .id = 0, 67862306a36Sopenharmony_ci .playback = { 67962306a36Sopenharmony_ci .stream_name = "CS35L33 Playback", 68062306a36Sopenharmony_ci .channels_min = 1, 68162306a36Sopenharmony_ci .channels_max = 1, 68262306a36Sopenharmony_ci .rates = CS35L33_RATES, 68362306a36Sopenharmony_ci .formats = CS35L33_FORMATS, 68462306a36Sopenharmony_ci }, 68562306a36Sopenharmony_ci .capture = { 68662306a36Sopenharmony_ci .stream_name = "CS35L33 Capture", 68762306a36Sopenharmony_ci .channels_min = 2, 68862306a36Sopenharmony_ci .channels_max = 2, 68962306a36Sopenharmony_ci .rates = CS35L33_RATES, 69062306a36Sopenharmony_ci .formats = CS35L33_FORMATS, 69162306a36Sopenharmony_ci }, 69262306a36Sopenharmony_ci .ops = &cs35l33_ops, 69362306a36Sopenharmony_ci .symmetric_rate = 1, 69462306a36Sopenharmony_ci}; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_cistatic int cs35l33_set_hg_data(struct snd_soc_component *component, 69762306a36Sopenharmony_ci struct cs35l33_pdata *pdata) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci struct cs35l33_hg *hg_config = &pdata->hg_config; 70062306a36Sopenharmony_ci struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 70162306a36Sopenharmony_ci struct cs35l33_private *priv = snd_soc_component_get_drvdata(component); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci if (hg_config->enable_hg_algo) { 70462306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_HG_MEMLDO_CTL, 70562306a36Sopenharmony_ci CS35L33_MEM_DEPTH_MASK, 70662306a36Sopenharmony_ci hg_config->mem_depth << CS35L33_MEM_DEPTH_SHIFT); 70762306a36Sopenharmony_ci regmap_write(priv->regmap, CS35L33_HG_REL_RATE, 70862306a36Sopenharmony_ci hg_config->release_rate); 70962306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_HG_HEAD, 71062306a36Sopenharmony_ci CS35L33_HD_RM_MASK, 71162306a36Sopenharmony_ci hg_config->hd_rm << CS35L33_HD_RM_SHIFT); 71262306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_HG_MEMLDO_CTL, 71362306a36Sopenharmony_ci CS35L33_LDO_THLD_MASK, 71462306a36Sopenharmony_ci hg_config->ldo_thld << CS35L33_LDO_THLD_SHIFT); 71562306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_HG_MEMLDO_CTL, 71662306a36Sopenharmony_ci CS35L33_LDO_DISABLE_MASK, 71762306a36Sopenharmony_ci hg_config->ldo_path_disable << 71862306a36Sopenharmony_ci CS35L33_LDO_DISABLE_SHIFT); 71962306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_LDO_DEL, 72062306a36Sopenharmony_ci CS35L33_LDO_ENTRY_DELAY_MASK, 72162306a36Sopenharmony_ci hg_config->ldo_entry_delay << 72262306a36Sopenharmony_ci CS35L33_LDO_ENTRY_DELAY_SHIFT); 72362306a36Sopenharmony_ci if (hg_config->vp_hg_auto) { 72462306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_HG_EN, 72562306a36Sopenharmony_ci CS35L33_VP_HG_AUTO_MASK, 72662306a36Sopenharmony_ci CS35L33_VP_HG_AUTO_MASK); 72762306a36Sopenharmony_ci snd_soc_dapm_add_routes(dapm, cs35l33_vphg_auto_route, 72862306a36Sopenharmony_ci ARRAY_SIZE(cs35l33_vphg_auto_route)); 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_HG_EN, 73162306a36Sopenharmony_ci CS35L33_VP_HG_MASK, 73262306a36Sopenharmony_ci hg_config->vp_hg << CS35L33_VP_HG_SHIFT); 73362306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_LDO_DEL, 73462306a36Sopenharmony_ci CS35L33_VP_HG_RATE_MASK, 73562306a36Sopenharmony_ci hg_config->vp_hg_rate << CS35L33_VP_HG_RATE_SHIFT); 73662306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_LDO_DEL, 73762306a36Sopenharmony_ci CS35L33_VP_HG_VA_MASK, 73862306a36Sopenharmony_ci hg_config->vp_hg_va << CS35L33_VP_HG_VA_SHIFT); 73962306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L33_HG_EN, 74062306a36Sopenharmony_ci CS35L33_CLASS_HG_EN_MASK, CS35L33_CLASS_HG_EN_MASK); 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci return 0; 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_cistatic int cs35l33_set_bst_ipk(struct snd_soc_component *component, unsigned int bst) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci struct cs35l33_private *cs35l33 = snd_soc_component_get_drvdata(component); 74862306a36Sopenharmony_ci int ret = 0, steps = 0; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci /* Boost current in uA */ 75162306a36Sopenharmony_ci if (bst > 3600000 || bst < 1850000) { 75262306a36Sopenharmony_ci dev_err(component->dev, "Invalid boost current %d\n", bst); 75362306a36Sopenharmony_ci ret = -EINVAL; 75462306a36Sopenharmony_ci goto err; 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci if (bst % 15625) { 75862306a36Sopenharmony_ci dev_err(component->dev, "Current not a multiple of 15625uA (%d)\n", 75962306a36Sopenharmony_ci bst); 76062306a36Sopenharmony_ci ret = -EINVAL; 76162306a36Sopenharmony_ci goto err; 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci while (bst > 1850000) { 76562306a36Sopenharmony_ci bst -= 15625; 76662306a36Sopenharmony_ci steps++; 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci regmap_write(cs35l33->regmap, CS35L33_BST_PEAK_CTL, 77062306a36Sopenharmony_ci steps+0x70); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_cierr: 77362306a36Sopenharmony_ci return ret; 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_cistatic int cs35l33_probe(struct snd_soc_component *component) 77762306a36Sopenharmony_ci{ 77862306a36Sopenharmony_ci struct cs35l33_private *cs35l33 = snd_soc_component_get_drvdata(component); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci cs35l33->component = component; 78162306a36Sopenharmony_ci pm_runtime_get_sync(component->dev); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci regmap_update_bits(cs35l33->regmap, CS35L33_PROTECT_CTL, 78462306a36Sopenharmony_ci CS35L33_ALIVE_WD_DIS, 0x8); 78562306a36Sopenharmony_ci regmap_update_bits(cs35l33->regmap, CS35L33_BST_CTL2, 78662306a36Sopenharmony_ci CS35L33_ALIVE_WD_DIS2, 78762306a36Sopenharmony_ci CS35L33_ALIVE_WD_DIS2); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci /* Set Platform Data */ 79062306a36Sopenharmony_ci regmap_update_bits(cs35l33->regmap, CS35L33_BST_CTL1, 79162306a36Sopenharmony_ci CS35L33_BST_CTL_MASK, cs35l33->pdata.boost_ctl); 79262306a36Sopenharmony_ci regmap_update_bits(cs35l33->regmap, CS35L33_CLASSD_CTL, 79362306a36Sopenharmony_ci CS35L33_AMP_DRV_SEL_MASK, 79462306a36Sopenharmony_ci cs35l33->pdata.amp_drv_sel << CS35L33_AMP_DRV_SEL_SHIFT); 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if (cs35l33->pdata.boost_ipk) 79762306a36Sopenharmony_ci cs35l33_set_bst_ipk(component, cs35l33->pdata.boost_ipk); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci if (cs35l33->enable_soft_ramp) { 80062306a36Sopenharmony_ci snd_soc_component_update_bits(component, CS35L33_DAC_CTL, 80162306a36Sopenharmony_ci CS35L33_DIGSFT, CS35L33_DIGSFT); 80262306a36Sopenharmony_ci snd_soc_component_update_bits(component, CS35L33_DAC_CTL, 80362306a36Sopenharmony_ci CS35L33_DSR_RATE, cs35l33->pdata.ramp_rate); 80462306a36Sopenharmony_ci } else { 80562306a36Sopenharmony_ci snd_soc_component_update_bits(component, CS35L33_DAC_CTL, 80662306a36Sopenharmony_ci CS35L33_DIGSFT, 0); 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci /* update IMON scaling rate if different from default of 0x8 */ 81062306a36Sopenharmony_ci if (cs35l33->pdata.imon_adc_scale != 0x8) 81162306a36Sopenharmony_ci snd_soc_component_update_bits(component, CS35L33_ADC_CTL, 81262306a36Sopenharmony_ci CS35L33_IMON_SCALE, cs35l33->pdata.imon_adc_scale); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci cs35l33_set_hg_data(component, &(cs35l33->pdata)); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci /* 81762306a36Sopenharmony_ci * unmask important interrupts that causes the chip to enter 81862306a36Sopenharmony_ci * speaker safe mode and hence deserves user attention 81962306a36Sopenharmony_ci */ 82062306a36Sopenharmony_ci regmap_update_bits(cs35l33->regmap, CS35L33_INT_MASK_1, 82162306a36Sopenharmony_ci CS35L33_M_OTE | CS35L33_M_OTW | CS35L33_M_AMP_SHORT | 82262306a36Sopenharmony_ci CS35L33_M_CAL_ERR, 0); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci pm_runtime_put_sync(component->dev); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci return 0; 82762306a36Sopenharmony_ci} 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_dev_cs35l33 = { 83062306a36Sopenharmony_ci .probe = cs35l33_probe, 83162306a36Sopenharmony_ci .set_bias_level = cs35l33_set_bias_level, 83262306a36Sopenharmony_ci .set_sysclk = cs35l33_component_set_sysclk, 83362306a36Sopenharmony_ci .controls = cs35l33_snd_controls, 83462306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(cs35l33_snd_controls), 83562306a36Sopenharmony_ci .dapm_widgets = cs35l33_dapm_widgets, 83662306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(cs35l33_dapm_widgets), 83762306a36Sopenharmony_ci .dapm_routes = cs35l33_audio_map, 83862306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(cs35l33_audio_map), 83962306a36Sopenharmony_ci .use_pmdown_time = 1, 84062306a36Sopenharmony_ci .endianness = 1, 84162306a36Sopenharmony_ci}; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_cistatic const struct regmap_config cs35l33_regmap = { 84462306a36Sopenharmony_ci .reg_bits = 8, 84562306a36Sopenharmony_ci .val_bits = 8, 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci .max_register = CS35L33_MAX_REGISTER, 84862306a36Sopenharmony_ci .reg_defaults = cs35l33_reg, 84962306a36Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(cs35l33_reg), 85062306a36Sopenharmony_ci .volatile_reg = cs35l33_volatile_register, 85162306a36Sopenharmony_ci .readable_reg = cs35l33_readable_register, 85262306a36Sopenharmony_ci .writeable_reg = cs35l33_writeable_register, 85362306a36Sopenharmony_ci .cache_type = REGCACHE_MAPLE, 85462306a36Sopenharmony_ci .use_single_read = true, 85562306a36Sopenharmony_ci .use_single_write = true, 85662306a36Sopenharmony_ci}; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_cistatic int __maybe_unused cs35l33_runtime_resume(struct device *dev) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci struct cs35l33_private *cs35l33 = dev_get_drvdata(dev); 86162306a36Sopenharmony_ci int ret; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci dev_dbg(dev, "%s\n", __func__); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci gpiod_set_value_cansleep(cs35l33->reset_gpio, 0); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci ret = regulator_bulk_enable(cs35l33->num_core_supplies, 86862306a36Sopenharmony_ci cs35l33->core_supplies); 86962306a36Sopenharmony_ci if (ret != 0) { 87062306a36Sopenharmony_ci dev_err(dev, "Failed to enable core supplies: %d\n", ret); 87162306a36Sopenharmony_ci return ret; 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci regcache_cache_only(cs35l33->regmap, false); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci gpiod_set_value_cansleep(cs35l33->reset_gpio, 1); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci msleep(CS35L33_BOOT_DELAY); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci ret = regcache_sync(cs35l33->regmap); 88162306a36Sopenharmony_ci if (ret != 0) { 88262306a36Sopenharmony_ci dev_err(dev, "Failed to restore register cache\n"); 88362306a36Sopenharmony_ci goto err; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci return 0; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_cierr: 88962306a36Sopenharmony_ci regcache_cache_only(cs35l33->regmap, true); 89062306a36Sopenharmony_ci regulator_bulk_disable(cs35l33->num_core_supplies, 89162306a36Sopenharmony_ci cs35l33->core_supplies); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci return ret; 89462306a36Sopenharmony_ci} 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_cistatic int __maybe_unused cs35l33_runtime_suspend(struct device *dev) 89762306a36Sopenharmony_ci{ 89862306a36Sopenharmony_ci struct cs35l33_private *cs35l33 = dev_get_drvdata(dev); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci dev_dbg(dev, "%s\n", __func__); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci /* redo the calibration in next power up */ 90362306a36Sopenharmony_ci cs35l33->amp_cal = false; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci regcache_cache_only(cs35l33->regmap, true); 90662306a36Sopenharmony_ci regcache_mark_dirty(cs35l33->regmap); 90762306a36Sopenharmony_ci regulator_bulk_disable(cs35l33->num_core_supplies, 90862306a36Sopenharmony_ci cs35l33->core_supplies); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci return 0; 91162306a36Sopenharmony_ci} 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_cistatic const struct dev_pm_ops cs35l33_pm_ops = { 91462306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(cs35l33_runtime_suspend, 91562306a36Sopenharmony_ci cs35l33_runtime_resume, 91662306a36Sopenharmony_ci NULL) 91762306a36Sopenharmony_ci}; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_cistatic int cs35l33_get_hg_data(const struct device_node *np, 92062306a36Sopenharmony_ci struct cs35l33_pdata *pdata) 92162306a36Sopenharmony_ci{ 92262306a36Sopenharmony_ci struct device_node *hg; 92362306a36Sopenharmony_ci struct cs35l33_hg *hg_config = &pdata->hg_config; 92462306a36Sopenharmony_ci u32 val32; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci hg = of_get_child_by_name(np, "cirrus,hg-algo"); 92762306a36Sopenharmony_ci hg_config->enable_hg_algo = hg ? true : false; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci if (hg_config->enable_hg_algo) { 93062306a36Sopenharmony_ci if (of_property_read_u32(hg, "cirrus,mem-depth", &val32) >= 0) 93162306a36Sopenharmony_ci hg_config->mem_depth = val32; 93262306a36Sopenharmony_ci if (of_property_read_u32(hg, "cirrus,release-rate", 93362306a36Sopenharmony_ci &val32) >= 0) 93462306a36Sopenharmony_ci hg_config->release_rate = val32; 93562306a36Sopenharmony_ci if (of_property_read_u32(hg, "cirrus,ldo-thld", &val32) >= 0) 93662306a36Sopenharmony_ci hg_config->ldo_thld = val32; 93762306a36Sopenharmony_ci if (of_property_read_u32(hg, "cirrus,ldo-path-disable", 93862306a36Sopenharmony_ci &val32) >= 0) 93962306a36Sopenharmony_ci hg_config->ldo_path_disable = val32; 94062306a36Sopenharmony_ci if (of_property_read_u32(hg, "cirrus,ldo-entry-delay", 94162306a36Sopenharmony_ci &val32) >= 0) 94262306a36Sopenharmony_ci hg_config->ldo_entry_delay = val32; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci hg_config->vp_hg_auto = of_property_read_bool(hg, 94562306a36Sopenharmony_ci "cirrus,vp-hg-auto"); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci if (of_property_read_u32(hg, "cirrus,vp-hg", &val32) >= 0) 94862306a36Sopenharmony_ci hg_config->vp_hg = val32; 94962306a36Sopenharmony_ci if (of_property_read_u32(hg, "cirrus,vp-hg-rate", &val32) >= 0) 95062306a36Sopenharmony_ci hg_config->vp_hg_rate = val32; 95162306a36Sopenharmony_ci if (of_property_read_u32(hg, "cirrus,vp-hg-va", &val32) >= 0) 95262306a36Sopenharmony_ci hg_config->vp_hg_va = val32; 95362306a36Sopenharmony_ci } 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci of_node_put(hg); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci return 0; 95862306a36Sopenharmony_ci} 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_cistatic irqreturn_t cs35l33_irq_thread(int irq, void *data) 96162306a36Sopenharmony_ci{ 96262306a36Sopenharmony_ci struct cs35l33_private *cs35l33 = data; 96362306a36Sopenharmony_ci struct snd_soc_component *component = cs35l33->component; 96462306a36Sopenharmony_ci unsigned int sticky_val1, sticky_val2, current_val, mask1, mask2; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci regmap_read(cs35l33->regmap, CS35L33_INT_STATUS_2, 96762306a36Sopenharmony_ci &sticky_val2); 96862306a36Sopenharmony_ci regmap_read(cs35l33->regmap, CS35L33_INT_STATUS_1, 96962306a36Sopenharmony_ci &sticky_val1); 97062306a36Sopenharmony_ci regmap_read(cs35l33->regmap, CS35L33_INT_MASK_2, &mask2); 97162306a36Sopenharmony_ci regmap_read(cs35l33->regmap, CS35L33_INT_MASK_1, &mask1); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci /* Check to see if the unmasked bits are active, 97462306a36Sopenharmony_ci * if not then exit. 97562306a36Sopenharmony_ci */ 97662306a36Sopenharmony_ci if (!(sticky_val1 & ~mask1) && !(sticky_val2 & ~mask2)) 97762306a36Sopenharmony_ci return IRQ_NONE; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci regmap_read(cs35l33->regmap, CS35L33_INT_STATUS_1, 98062306a36Sopenharmony_ci ¤t_val); 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci /* handle the interrupts */ 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci if (sticky_val1 & CS35L33_AMP_SHORT) { 98562306a36Sopenharmony_ci dev_crit(component->dev, "Amp short error\n"); 98662306a36Sopenharmony_ci if (!(current_val & CS35L33_AMP_SHORT)) { 98762306a36Sopenharmony_ci dev_dbg(component->dev, 98862306a36Sopenharmony_ci "Amp short error release\n"); 98962306a36Sopenharmony_ci regmap_update_bits(cs35l33->regmap, 99062306a36Sopenharmony_ci CS35L33_AMP_CTL, 99162306a36Sopenharmony_ci CS35L33_AMP_SHORT_RLS, 0); 99262306a36Sopenharmony_ci regmap_update_bits(cs35l33->regmap, 99362306a36Sopenharmony_ci CS35L33_AMP_CTL, 99462306a36Sopenharmony_ci CS35L33_AMP_SHORT_RLS, 99562306a36Sopenharmony_ci CS35L33_AMP_SHORT_RLS); 99662306a36Sopenharmony_ci regmap_update_bits(cs35l33->regmap, 99762306a36Sopenharmony_ci CS35L33_AMP_CTL, CS35L33_AMP_SHORT_RLS, 99862306a36Sopenharmony_ci 0); 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci } 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci if (sticky_val1 & CS35L33_CAL_ERR) { 100362306a36Sopenharmony_ci dev_err(component->dev, "Cal error\n"); 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci /* redo the calibration in next power up */ 100662306a36Sopenharmony_ci cs35l33->amp_cal = false; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci if (!(current_val & CS35L33_CAL_ERR)) { 100962306a36Sopenharmony_ci dev_dbg(component->dev, "Cal error release\n"); 101062306a36Sopenharmony_ci regmap_update_bits(cs35l33->regmap, 101162306a36Sopenharmony_ci CS35L33_AMP_CTL, CS35L33_CAL_ERR_RLS, 101262306a36Sopenharmony_ci 0); 101362306a36Sopenharmony_ci regmap_update_bits(cs35l33->regmap, 101462306a36Sopenharmony_ci CS35L33_AMP_CTL, CS35L33_CAL_ERR_RLS, 101562306a36Sopenharmony_ci CS35L33_CAL_ERR_RLS); 101662306a36Sopenharmony_ci regmap_update_bits(cs35l33->regmap, 101762306a36Sopenharmony_ci CS35L33_AMP_CTL, CS35L33_CAL_ERR_RLS, 101862306a36Sopenharmony_ci 0); 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci if (sticky_val1 & CS35L33_OTE) { 102362306a36Sopenharmony_ci dev_crit(component->dev, "Over temperature error\n"); 102462306a36Sopenharmony_ci if (!(current_val & CS35L33_OTE)) { 102562306a36Sopenharmony_ci dev_dbg(component->dev, 102662306a36Sopenharmony_ci "Over temperature error release\n"); 102762306a36Sopenharmony_ci regmap_update_bits(cs35l33->regmap, 102862306a36Sopenharmony_ci CS35L33_AMP_CTL, CS35L33_OTE_RLS, 0); 102962306a36Sopenharmony_ci regmap_update_bits(cs35l33->regmap, 103062306a36Sopenharmony_ci CS35L33_AMP_CTL, CS35L33_OTE_RLS, 103162306a36Sopenharmony_ci CS35L33_OTE_RLS); 103262306a36Sopenharmony_ci regmap_update_bits(cs35l33->regmap, 103362306a36Sopenharmony_ci CS35L33_AMP_CTL, CS35L33_OTE_RLS, 0); 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci } 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci if (sticky_val1 & CS35L33_OTW) { 103862306a36Sopenharmony_ci dev_err(component->dev, "Over temperature warning\n"); 103962306a36Sopenharmony_ci if (!(current_val & CS35L33_OTW)) { 104062306a36Sopenharmony_ci dev_dbg(component->dev, 104162306a36Sopenharmony_ci "Over temperature warning release\n"); 104262306a36Sopenharmony_ci regmap_update_bits(cs35l33->regmap, 104362306a36Sopenharmony_ci CS35L33_AMP_CTL, CS35L33_OTW_RLS, 0); 104462306a36Sopenharmony_ci regmap_update_bits(cs35l33->regmap, 104562306a36Sopenharmony_ci CS35L33_AMP_CTL, CS35L33_OTW_RLS, 104662306a36Sopenharmony_ci CS35L33_OTW_RLS); 104762306a36Sopenharmony_ci regmap_update_bits(cs35l33->regmap, 104862306a36Sopenharmony_ci CS35L33_AMP_CTL, CS35L33_OTW_RLS, 0); 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci if (CS35L33_ALIVE_ERR & sticky_val1) 105262306a36Sopenharmony_ci dev_err(component->dev, "ERROR: ADSPCLK Interrupt\n"); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci if (CS35L33_MCLK_ERR & sticky_val1) 105562306a36Sopenharmony_ci dev_err(component->dev, "ERROR: MCLK Interrupt\n"); 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci if (CS35L33_VMON_OVFL & sticky_val2) 105862306a36Sopenharmony_ci dev_err(component->dev, 105962306a36Sopenharmony_ci "ERROR: VMON Overflow Interrupt\n"); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci if (CS35L33_IMON_OVFL & sticky_val2) 106262306a36Sopenharmony_ci dev_err(component->dev, 106362306a36Sopenharmony_ci "ERROR: IMON Overflow Interrupt\n"); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci if (CS35L33_VPMON_OVFL & sticky_val2) 106662306a36Sopenharmony_ci dev_err(component->dev, 106762306a36Sopenharmony_ci "ERROR: VPMON Overflow Interrupt\n"); 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci return IRQ_HANDLED; 107062306a36Sopenharmony_ci} 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_cistatic const char * const cs35l33_core_supplies[] = { 107362306a36Sopenharmony_ci "VA", 107462306a36Sopenharmony_ci "VP", 107562306a36Sopenharmony_ci}; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_cistatic int cs35l33_of_get_pdata(struct device *dev, 107862306a36Sopenharmony_ci struct cs35l33_private *cs35l33) 107962306a36Sopenharmony_ci{ 108062306a36Sopenharmony_ci struct device_node *np = dev->of_node; 108162306a36Sopenharmony_ci struct cs35l33_pdata *pdata = &cs35l33->pdata; 108262306a36Sopenharmony_ci u32 val32; 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci if (!np) 108562306a36Sopenharmony_ci return 0; 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci if (of_property_read_u32(np, "cirrus,boost-ctl", &val32) >= 0) { 108862306a36Sopenharmony_ci pdata->boost_ctl = val32; 108962306a36Sopenharmony_ci pdata->amp_drv_sel = 1; 109062306a36Sopenharmony_ci } 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci if (of_property_read_u32(np, "cirrus,ramp-rate", &val32) >= 0) { 109362306a36Sopenharmony_ci pdata->ramp_rate = val32; 109462306a36Sopenharmony_ci cs35l33->enable_soft_ramp = true; 109562306a36Sopenharmony_ci } 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci if (of_property_read_u32(np, "cirrus,boost-ipk", &val32) >= 0) 109862306a36Sopenharmony_ci pdata->boost_ipk = val32; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci if (of_property_read_u32(np, "cirrus,imon-adc-scale", &val32) >= 0) { 110162306a36Sopenharmony_ci if ((val32 == 0x0) || (val32 == 0x7) || (val32 == 0x6)) 110262306a36Sopenharmony_ci pdata->imon_adc_scale = val32; 110362306a36Sopenharmony_ci else 110462306a36Sopenharmony_ci /* use default value */ 110562306a36Sopenharmony_ci pdata->imon_adc_scale = 0x8; 110662306a36Sopenharmony_ci } else { 110762306a36Sopenharmony_ci /* use default value */ 110862306a36Sopenharmony_ci pdata->imon_adc_scale = 0x8; 110962306a36Sopenharmony_ci } 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci cs35l33_get_hg_data(np, pdata); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci return 0; 111462306a36Sopenharmony_ci} 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_cistatic int cs35l33_i2c_probe(struct i2c_client *i2c_client) 111762306a36Sopenharmony_ci{ 111862306a36Sopenharmony_ci struct cs35l33_private *cs35l33; 111962306a36Sopenharmony_ci struct cs35l33_pdata *pdata = dev_get_platdata(&i2c_client->dev); 112062306a36Sopenharmony_ci int ret, devid, i; 112162306a36Sopenharmony_ci unsigned int reg; 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci cs35l33 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs35l33_private), 112462306a36Sopenharmony_ci GFP_KERNEL); 112562306a36Sopenharmony_ci if (!cs35l33) 112662306a36Sopenharmony_ci return -ENOMEM; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci i2c_set_clientdata(i2c_client, cs35l33); 112962306a36Sopenharmony_ci cs35l33->regmap = devm_regmap_init_i2c(i2c_client, &cs35l33_regmap); 113062306a36Sopenharmony_ci if (IS_ERR(cs35l33->regmap)) { 113162306a36Sopenharmony_ci ret = PTR_ERR(cs35l33->regmap); 113262306a36Sopenharmony_ci dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); 113362306a36Sopenharmony_ci return ret; 113462306a36Sopenharmony_ci } 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci regcache_cache_only(cs35l33->regmap, true); 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cs35l33_core_supplies); i++) 113962306a36Sopenharmony_ci cs35l33->core_supplies[i].supply 114062306a36Sopenharmony_ci = cs35l33_core_supplies[i]; 114162306a36Sopenharmony_ci cs35l33->num_core_supplies = ARRAY_SIZE(cs35l33_core_supplies); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci ret = devm_regulator_bulk_get(&i2c_client->dev, 114462306a36Sopenharmony_ci cs35l33->num_core_supplies, 114562306a36Sopenharmony_ci cs35l33->core_supplies); 114662306a36Sopenharmony_ci if (ret != 0) { 114762306a36Sopenharmony_ci dev_err(&i2c_client->dev, 114862306a36Sopenharmony_ci "Failed to request core supplies: %d\n", 114962306a36Sopenharmony_ci ret); 115062306a36Sopenharmony_ci return ret; 115162306a36Sopenharmony_ci } 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci if (pdata) { 115462306a36Sopenharmony_ci cs35l33->pdata = *pdata; 115562306a36Sopenharmony_ci } else { 115662306a36Sopenharmony_ci cs35l33_of_get_pdata(&i2c_client->dev, cs35l33); 115762306a36Sopenharmony_ci pdata = &cs35l33->pdata; 115862306a36Sopenharmony_ci } 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq, NULL, 116162306a36Sopenharmony_ci cs35l33_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW, 116262306a36Sopenharmony_ci "cs35l33", cs35l33); 116362306a36Sopenharmony_ci if (ret != 0) 116462306a36Sopenharmony_ci dev_warn(&i2c_client->dev, "Failed to request IRQ: %d\n", ret); 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci /* We could issue !RST or skip it based on AMP topology */ 116762306a36Sopenharmony_ci cs35l33->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, 116862306a36Sopenharmony_ci "reset", GPIOD_OUT_HIGH); 116962306a36Sopenharmony_ci if (IS_ERR(cs35l33->reset_gpio)) { 117062306a36Sopenharmony_ci dev_err(&i2c_client->dev, "%s ERROR: Can't get reset GPIO\n", 117162306a36Sopenharmony_ci __func__); 117262306a36Sopenharmony_ci return PTR_ERR(cs35l33->reset_gpio); 117362306a36Sopenharmony_ci } 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci ret = regulator_bulk_enable(cs35l33->num_core_supplies, 117662306a36Sopenharmony_ci cs35l33->core_supplies); 117762306a36Sopenharmony_ci if (ret != 0) { 117862306a36Sopenharmony_ci dev_err(&i2c_client->dev, 117962306a36Sopenharmony_ci "Failed to enable core supplies: %d\n", 118062306a36Sopenharmony_ci ret); 118162306a36Sopenharmony_ci return ret; 118262306a36Sopenharmony_ci } 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci gpiod_set_value_cansleep(cs35l33->reset_gpio, 1); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci msleep(CS35L33_BOOT_DELAY); 118762306a36Sopenharmony_ci regcache_cache_only(cs35l33->regmap, false); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci /* initialize codec */ 119062306a36Sopenharmony_ci devid = cirrus_read_device_id(cs35l33->regmap, CS35L33_DEVID_AB); 119162306a36Sopenharmony_ci if (devid < 0) { 119262306a36Sopenharmony_ci ret = devid; 119362306a36Sopenharmony_ci dev_err(&i2c_client->dev, "Failed to read device ID: %d\n", ret); 119462306a36Sopenharmony_ci goto err_enable; 119562306a36Sopenharmony_ci } 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci if (devid != CS35L33_CHIP_ID) { 119862306a36Sopenharmony_ci dev_err(&i2c_client->dev, 119962306a36Sopenharmony_ci "CS35L33 Device ID (%X). Expected ID %X\n", 120062306a36Sopenharmony_ci devid, CS35L33_CHIP_ID); 120162306a36Sopenharmony_ci ret = -EINVAL; 120262306a36Sopenharmony_ci goto err_enable; 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci ret = regmap_read(cs35l33->regmap, CS35L33_REV_ID, ®); 120662306a36Sopenharmony_ci if (ret < 0) { 120762306a36Sopenharmony_ci dev_err(&i2c_client->dev, "Get Revision ID failed\n"); 120862306a36Sopenharmony_ci goto err_enable; 120962306a36Sopenharmony_ci } 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci dev_info(&i2c_client->dev, 121262306a36Sopenharmony_ci "Cirrus Logic CS35L33, Revision: %02X\n", reg & 0xFF); 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci ret = regmap_register_patch(cs35l33->regmap, 121562306a36Sopenharmony_ci cs35l33_patch, ARRAY_SIZE(cs35l33_patch)); 121662306a36Sopenharmony_ci if (ret < 0) { 121762306a36Sopenharmony_ci dev_err(&i2c_client->dev, 121862306a36Sopenharmony_ci "Error in applying regmap patch: %d\n", ret); 121962306a36Sopenharmony_ci goto err_enable; 122062306a36Sopenharmony_ci } 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci /* disable mclk and tdm */ 122362306a36Sopenharmony_ci regmap_update_bits(cs35l33->regmap, CS35L33_CLK_CTL, 122462306a36Sopenharmony_ci CS35L33_MCLKDIS | CS35L33_SDOUT_3ST_TDM, 122562306a36Sopenharmony_ci CS35L33_MCLKDIS | CS35L33_SDOUT_3ST_TDM); 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(&i2c_client->dev, 100); 122862306a36Sopenharmony_ci pm_runtime_use_autosuspend(&i2c_client->dev); 122962306a36Sopenharmony_ci pm_runtime_set_active(&i2c_client->dev); 123062306a36Sopenharmony_ci pm_runtime_enable(&i2c_client->dev); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci ret = devm_snd_soc_register_component(&i2c_client->dev, 123362306a36Sopenharmony_ci &soc_component_dev_cs35l33, &cs35l33_dai, 1); 123462306a36Sopenharmony_ci if (ret < 0) { 123562306a36Sopenharmony_ci dev_err(&i2c_client->dev, "%s: Register component failed\n", 123662306a36Sopenharmony_ci __func__); 123762306a36Sopenharmony_ci goto err_enable; 123862306a36Sopenharmony_ci } 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci return 0; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_cierr_enable: 124362306a36Sopenharmony_ci gpiod_set_value_cansleep(cs35l33->reset_gpio, 0); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci regulator_bulk_disable(cs35l33->num_core_supplies, 124662306a36Sopenharmony_ci cs35l33->core_supplies); 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci return ret; 124962306a36Sopenharmony_ci} 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_cistatic void cs35l33_i2c_remove(struct i2c_client *client) 125262306a36Sopenharmony_ci{ 125362306a36Sopenharmony_ci struct cs35l33_private *cs35l33 = i2c_get_clientdata(client); 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci gpiod_set_value_cansleep(cs35l33->reset_gpio, 0); 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci pm_runtime_disable(&client->dev); 125862306a36Sopenharmony_ci regulator_bulk_disable(cs35l33->num_core_supplies, 125962306a36Sopenharmony_ci cs35l33->core_supplies); 126062306a36Sopenharmony_ci} 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_cistatic const struct of_device_id cs35l33_of_match[] = { 126362306a36Sopenharmony_ci { .compatible = "cirrus,cs35l33", }, 126462306a36Sopenharmony_ci {}, 126562306a36Sopenharmony_ci}; 126662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, cs35l33_of_match); 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_cistatic const struct i2c_device_id cs35l33_id[] = { 126962306a36Sopenharmony_ci {"cs35l33", 0}, 127062306a36Sopenharmony_ci {} 127162306a36Sopenharmony_ci}; 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, cs35l33_id); 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_cistatic struct i2c_driver cs35l33_i2c_driver = { 127662306a36Sopenharmony_ci .driver = { 127762306a36Sopenharmony_ci .name = "cs35l33", 127862306a36Sopenharmony_ci .pm = &cs35l33_pm_ops, 127962306a36Sopenharmony_ci .of_match_table = cs35l33_of_match, 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci }, 128262306a36Sopenharmony_ci .id_table = cs35l33_id, 128362306a36Sopenharmony_ci .probe = cs35l33_i2c_probe, 128462306a36Sopenharmony_ci .remove = cs35l33_i2c_remove, 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci}; 128762306a36Sopenharmony_cimodule_i2c_driver(cs35l33_i2c_driver); 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ciMODULE_DESCRIPTION("ASoC CS35L33 driver"); 129062306a36Sopenharmony_ciMODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <paul.handrigan@cirrus.com>"); 129162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1292