162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * cs35l34.c -- CS35l34 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 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/moduleparam.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/init.h> 1462306a36Sopenharmony_ci#include <linux/delay.h> 1562306a36Sopenharmony_ci#include <linux/i2c.h> 1662306a36Sopenharmony_ci#include <linux/slab.h> 1762306a36Sopenharmony_ci#include <linux/workqueue.h> 1862306a36Sopenharmony_ci#include <linux/platform_device.h> 1962306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 2062306a36Sopenharmony_ci#include <linux/regulator/machine.h> 2162306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2262306a36Sopenharmony_ci#include <linux/of_device.h> 2362306a36Sopenharmony_ci#include <linux/of_irq.h> 2462306a36Sopenharmony_ci#include <sound/core.h> 2562306a36Sopenharmony_ci#include <sound/pcm.h> 2662306a36Sopenharmony_ci#include <sound/pcm_params.h> 2762306a36Sopenharmony_ci#include <sound/soc.h> 2862306a36Sopenharmony_ci#include <sound/soc-dapm.h> 2962306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 3062306a36Sopenharmony_ci#include <sound/initval.h> 3162306a36Sopenharmony_ci#include <sound/tlv.h> 3262306a36Sopenharmony_ci#include <sound/cs35l34.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include "cs35l34.h" 3562306a36Sopenharmony_ci#include "cirrus_legacy.h" 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define PDN_DONE_ATTEMPTS 10 3862306a36Sopenharmony_ci#define CS35L34_START_DELAY 50 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistruct cs35l34_private { 4162306a36Sopenharmony_ci struct snd_soc_component *component; 4262306a36Sopenharmony_ci struct cs35l34_platform_data pdata; 4362306a36Sopenharmony_ci struct regmap *regmap; 4462306a36Sopenharmony_ci struct regulator_bulk_data core_supplies[2]; 4562306a36Sopenharmony_ci int num_core_supplies; 4662306a36Sopenharmony_ci int mclk_int; 4762306a36Sopenharmony_ci bool tdm_mode; 4862306a36Sopenharmony_ci struct gpio_desc *reset_gpio; /* Active-low reset GPIO */ 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic const struct reg_default cs35l34_reg[] = { 5262306a36Sopenharmony_ci {CS35L34_PWRCTL1, 0x01}, 5362306a36Sopenharmony_ci {CS35L34_PWRCTL2, 0x19}, 5462306a36Sopenharmony_ci {CS35L34_PWRCTL3, 0x01}, 5562306a36Sopenharmony_ci {CS35L34_ADSP_CLK_CTL, 0x08}, 5662306a36Sopenharmony_ci {CS35L34_MCLK_CTL, 0x11}, 5762306a36Sopenharmony_ci {CS35L34_AMP_INP_DRV_CTL, 0x01}, 5862306a36Sopenharmony_ci {CS35L34_AMP_DIG_VOL_CTL, 0x12}, 5962306a36Sopenharmony_ci {CS35L34_AMP_DIG_VOL, 0x00}, 6062306a36Sopenharmony_ci {CS35L34_AMP_ANLG_GAIN_CTL, 0x0F}, 6162306a36Sopenharmony_ci {CS35L34_PROTECT_CTL, 0x06}, 6262306a36Sopenharmony_ci {CS35L34_AMP_KEEP_ALIVE_CTL, 0x04}, 6362306a36Sopenharmony_ci {CS35L34_BST_CVTR_V_CTL, 0x00}, 6462306a36Sopenharmony_ci {CS35L34_BST_PEAK_I, 0x10}, 6562306a36Sopenharmony_ci {CS35L34_BST_RAMP_CTL, 0x87}, 6662306a36Sopenharmony_ci {CS35L34_BST_CONV_COEF_1, 0x24}, 6762306a36Sopenharmony_ci {CS35L34_BST_CONV_COEF_2, 0x24}, 6862306a36Sopenharmony_ci {CS35L34_BST_CONV_SLOPE_COMP, 0x4E}, 6962306a36Sopenharmony_ci {CS35L34_BST_CONV_SW_FREQ, 0x08}, 7062306a36Sopenharmony_ci {CS35L34_CLASS_H_CTL, 0x0D}, 7162306a36Sopenharmony_ci {CS35L34_CLASS_H_HEADRM_CTL, 0x0D}, 7262306a36Sopenharmony_ci {CS35L34_CLASS_H_RELEASE_RATE, 0x08}, 7362306a36Sopenharmony_ci {CS35L34_CLASS_H_FET_DRIVE_CTL, 0x41}, 7462306a36Sopenharmony_ci {CS35L34_CLASS_H_STATUS, 0x05}, 7562306a36Sopenharmony_ci {CS35L34_VPBR_CTL, 0x0A}, 7662306a36Sopenharmony_ci {CS35L34_VPBR_VOL_CTL, 0x90}, 7762306a36Sopenharmony_ci {CS35L34_VPBR_TIMING_CTL, 0x6A}, 7862306a36Sopenharmony_ci {CS35L34_PRED_MAX_ATTEN_SPK_LOAD, 0x95}, 7962306a36Sopenharmony_ci {CS35L34_PRED_BROWNOUT_THRESH, 0x1C}, 8062306a36Sopenharmony_ci {CS35L34_PRED_BROWNOUT_VOL_CTL, 0x00}, 8162306a36Sopenharmony_ci {CS35L34_PRED_BROWNOUT_RATE_CTL, 0x10}, 8262306a36Sopenharmony_ci {CS35L34_PRED_WAIT_CTL, 0x10}, 8362306a36Sopenharmony_ci {CS35L34_PRED_ZVP_INIT_IMP_CTL, 0x08}, 8462306a36Sopenharmony_ci {CS35L34_PRED_MAN_SAFE_VPI_CTL, 0x80}, 8562306a36Sopenharmony_ci {CS35L34_VPBR_ATTEN_STATUS, 0x00}, 8662306a36Sopenharmony_ci {CS35L34_PRED_BRWNOUT_ATT_STATUS, 0x00}, 8762306a36Sopenharmony_ci {CS35L34_SPKR_MON_CTL, 0xC6}, 8862306a36Sopenharmony_ci {CS35L34_ADSP_I2S_CTL, 0x00}, 8962306a36Sopenharmony_ci {CS35L34_ADSP_TDM_CTL, 0x00}, 9062306a36Sopenharmony_ci {CS35L34_TDM_TX_CTL_1_VMON, 0x00}, 9162306a36Sopenharmony_ci {CS35L34_TDM_TX_CTL_2_IMON, 0x04}, 9262306a36Sopenharmony_ci {CS35L34_TDM_TX_CTL_3_VPMON, 0x03}, 9362306a36Sopenharmony_ci {CS35L34_TDM_TX_CTL_4_VBSTMON, 0x07}, 9462306a36Sopenharmony_ci {CS35L34_TDM_TX_CTL_5_FLAG1, 0x08}, 9562306a36Sopenharmony_ci {CS35L34_TDM_TX_CTL_6_FLAG2, 0x09}, 9662306a36Sopenharmony_ci {CS35L34_TDM_TX_SLOT_EN_1, 0x00}, 9762306a36Sopenharmony_ci {CS35L34_TDM_TX_SLOT_EN_2, 0x00}, 9862306a36Sopenharmony_ci {CS35L34_TDM_TX_SLOT_EN_3, 0x00}, 9962306a36Sopenharmony_ci {CS35L34_TDM_TX_SLOT_EN_4, 0x00}, 10062306a36Sopenharmony_ci {CS35L34_TDM_RX_CTL_1_AUDIN, 0x40}, 10162306a36Sopenharmony_ci {CS35L34_TDM_RX_CTL_3_ALIVE, 0x04}, 10262306a36Sopenharmony_ci {CS35L34_MULT_DEV_SYNCH1, 0x00}, 10362306a36Sopenharmony_ci {CS35L34_MULT_DEV_SYNCH2, 0x80}, 10462306a36Sopenharmony_ci {CS35L34_PROT_RELEASE_CTL, 0x00}, 10562306a36Sopenharmony_ci {CS35L34_DIAG_MODE_REG_LOCK, 0x00}, 10662306a36Sopenharmony_ci {CS35L34_DIAG_MODE_CTL_1, 0x00}, 10762306a36Sopenharmony_ci {CS35L34_DIAG_MODE_CTL_2, 0x00}, 10862306a36Sopenharmony_ci {CS35L34_INT_MASK_1, 0xFF}, 10962306a36Sopenharmony_ci {CS35L34_INT_MASK_2, 0xFF}, 11062306a36Sopenharmony_ci {CS35L34_INT_MASK_3, 0xFF}, 11162306a36Sopenharmony_ci {CS35L34_INT_MASK_4, 0xFF}, 11262306a36Sopenharmony_ci {CS35L34_INT_STATUS_1, 0x30}, 11362306a36Sopenharmony_ci {CS35L34_INT_STATUS_2, 0x05}, 11462306a36Sopenharmony_ci {CS35L34_INT_STATUS_3, 0x00}, 11562306a36Sopenharmony_ci {CS35L34_INT_STATUS_4, 0x00}, 11662306a36Sopenharmony_ci {CS35L34_OTP_TRIM_STATUS, 0x00}, 11762306a36Sopenharmony_ci}; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic bool cs35l34_volatile_register(struct device *dev, unsigned int reg) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci switch (reg) { 12262306a36Sopenharmony_ci case CS35L34_DEVID_AB: 12362306a36Sopenharmony_ci case CS35L34_DEVID_CD: 12462306a36Sopenharmony_ci case CS35L34_DEVID_E: 12562306a36Sopenharmony_ci case CS35L34_FAB_ID: 12662306a36Sopenharmony_ci case CS35L34_REV_ID: 12762306a36Sopenharmony_ci case CS35L34_INT_STATUS_1: 12862306a36Sopenharmony_ci case CS35L34_INT_STATUS_2: 12962306a36Sopenharmony_ci case CS35L34_INT_STATUS_3: 13062306a36Sopenharmony_ci case CS35L34_INT_STATUS_4: 13162306a36Sopenharmony_ci case CS35L34_CLASS_H_STATUS: 13262306a36Sopenharmony_ci case CS35L34_VPBR_ATTEN_STATUS: 13362306a36Sopenharmony_ci case CS35L34_OTP_TRIM_STATUS: 13462306a36Sopenharmony_ci return true; 13562306a36Sopenharmony_ci default: 13662306a36Sopenharmony_ci return false; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic bool cs35l34_readable_register(struct device *dev, unsigned int reg) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci switch (reg) { 14362306a36Sopenharmony_ci case CS35L34_DEVID_AB: 14462306a36Sopenharmony_ci case CS35L34_DEVID_CD: 14562306a36Sopenharmony_ci case CS35L34_DEVID_E: 14662306a36Sopenharmony_ci case CS35L34_FAB_ID: 14762306a36Sopenharmony_ci case CS35L34_REV_ID: 14862306a36Sopenharmony_ci case CS35L34_PWRCTL1: 14962306a36Sopenharmony_ci case CS35L34_PWRCTL2: 15062306a36Sopenharmony_ci case CS35L34_PWRCTL3: 15162306a36Sopenharmony_ci case CS35L34_ADSP_CLK_CTL: 15262306a36Sopenharmony_ci case CS35L34_MCLK_CTL: 15362306a36Sopenharmony_ci case CS35L34_AMP_INP_DRV_CTL: 15462306a36Sopenharmony_ci case CS35L34_AMP_DIG_VOL_CTL: 15562306a36Sopenharmony_ci case CS35L34_AMP_DIG_VOL: 15662306a36Sopenharmony_ci case CS35L34_AMP_ANLG_GAIN_CTL: 15762306a36Sopenharmony_ci case CS35L34_PROTECT_CTL: 15862306a36Sopenharmony_ci case CS35L34_AMP_KEEP_ALIVE_CTL: 15962306a36Sopenharmony_ci case CS35L34_BST_CVTR_V_CTL: 16062306a36Sopenharmony_ci case CS35L34_BST_PEAK_I: 16162306a36Sopenharmony_ci case CS35L34_BST_RAMP_CTL: 16262306a36Sopenharmony_ci case CS35L34_BST_CONV_COEF_1: 16362306a36Sopenharmony_ci case CS35L34_BST_CONV_COEF_2: 16462306a36Sopenharmony_ci case CS35L34_BST_CONV_SLOPE_COMP: 16562306a36Sopenharmony_ci case CS35L34_BST_CONV_SW_FREQ: 16662306a36Sopenharmony_ci case CS35L34_CLASS_H_CTL: 16762306a36Sopenharmony_ci case CS35L34_CLASS_H_HEADRM_CTL: 16862306a36Sopenharmony_ci case CS35L34_CLASS_H_RELEASE_RATE: 16962306a36Sopenharmony_ci case CS35L34_CLASS_H_FET_DRIVE_CTL: 17062306a36Sopenharmony_ci case CS35L34_CLASS_H_STATUS: 17162306a36Sopenharmony_ci case CS35L34_VPBR_CTL: 17262306a36Sopenharmony_ci case CS35L34_VPBR_VOL_CTL: 17362306a36Sopenharmony_ci case CS35L34_VPBR_TIMING_CTL: 17462306a36Sopenharmony_ci case CS35L34_PRED_MAX_ATTEN_SPK_LOAD: 17562306a36Sopenharmony_ci case CS35L34_PRED_BROWNOUT_THRESH: 17662306a36Sopenharmony_ci case CS35L34_PRED_BROWNOUT_VOL_CTL: 17762306a36Sopenharmony_ci case CS35L34_PRED_BROWNOUT_RATE_CTL: 17862306a36Sopenharmony_ci case CS35L34_PRED_WAIT_CTL: 17962306a36Sopenharmony_ci case CS35L34_PRED_ZVP_INIT_IMP_CTL: 18062306a36Sopenharmony_ci case CS35L34_PRED_MAN_SAFE_VPI_CTL: 18162306a36Sopenharmony_ci case CS35L34_VPBR_ATTEN_STATUS: 18262306a36Sopenharmony_ci case CS35L34_PRED_BRWNOUT_ATT_STATUS: 18362306a36Sopenharmony_ci case CS35L34_SPKR_MON_CTL: 18462306a36Sopenharmony_ci case CS35L34_ADSP_I2S_CTL: 18562306a36Sopenharmony_ci case CS35L34_ADSP_TDM_CTL: 18662306a36Sopenharmony_ci case CS35L34_TDM_TX_CTL_1_VMON: 18762306a36Sopenharmony_ci case CS35L34_TDM_TX_CTL_2_IMON: 18862306a36Sopenharmony_ci case CS35L34_TDM_TX_CTL_3_VPMON: 18962306a36Sopenharmony_ci case CS35L34_TDM_TX_CTL_4_VBSTMON: 19062306a36Sopenharmony_ci case CS35L34_TDM_TX_CTL_5_FLAG1: 19162306a36Sopenharmony_ci case CS35L34_TDM_TX_CTL_6_FLAG2: 19262306a36Sopenharmony_ci case CS35L34_TDM_TX_SLOT_EN_1: 19362306a36Sopenharmony_ci case CS35L34_TDM_TX_SLOT_EN_2: 19462306a36Sopenharmony_ci case CS35L34_TDM_TX_SLOT_EN_3: 19562306a36Sopenharmony_ci case CS35L34_TDM_TX_SLOT_EN_4: 19662306a36Sopenharmony_ci case CS35L34_TDM_RX_CTL_1_AUDIN: 19762306a36Sopenharmony_ci case CS35L34_TDM_RX_CTL_3_ALIVE: 19862306a36Sopenharmony_ci case CS35L34_MULT_DEV_SYNCH1: 19962306a36Sopenharmony_ci case CS35L34_MULT_DEV_SYNCH2: 20062306a36Sopenharmony_ci case CS35L34_PROT_RELEASE_CTL: 20162306a36Sopenharmony_ci case CS35L34_DIAG_MODE_REG_LOCK: 20262306a36Sopenharmony_ci case CS35L34_DIAG_MODE_CTL_1: 20362306a36Sopenharmony_ci case CS35L34_DIAG_MODE_CTL_2: 20462306a36Sopenharmony_ci case CS35L34_INT_MASK_1: 20562306a36Sopenharmony_ci case CS35L34_INT_MASK_2: 20662306a36Sopenharmony_ci case CS35L34_INT_MASK_3: 20762306a36Sopenharmony_ci case CS35L34_INT_MASK_4: 20862306a36Sopenharmony_ci case CS35L34_INT_STATUS_1: 20962306a36Sopenharmony_ci case CS35L34_INT_STATUS_2: 21062306a36Sopenharmony_ci case CS35L34_INT_STATUS_3: 21162306a36Sopenharmony_ci case CS35L34_INT_STATUS_4: 21262306a36Sopenharmony_ci case CS35L34_OTP_TRIM_STATUS: 21362306a36Sopenharmony_ci return true; 21462306a36Sopenharmony_ci default: 21562306a36Sopenharmony_ci return false; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic bool cs35l34_precious_register(struct device *dev, unsigned int reg) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci switch (reg) { 22262306a36Sopenharmony_ci case CS35L34_INT_STATUS_1: 22362306a36Sopenharmony_ci case CS35L34_INT_STATUS_2: 22462306a36Sopenharmony_ci case CS35L34_INT_STATUS_3: 22562306a36Sopenharmony_ci case CS35L34_INT_STATUS_4: 22662306a36Sopenharmony_ci return true; 22762306a36Sopenharmony_ci default: 22862306a36Sopenharmony_ci return false; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic int cs35l34_sdin_event(struct snd_soc_dapm_widget *w, 23362306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 23662306a36Sopenharmony_ci struct cs35l34_private *priv = snd_soc_component_get_drvdata(component); 23762306a36Sopenharmony_ci int ret; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci switch (event) { 24062306a36Sopenharmony_ci case SND_SOC_DAPM_PRE_PMU: 24162306a36Sopenharmony_ci if (priv->tdm_mode) 24262306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L34_PWRCTL3, 24362306a36Sopenharmony_ci CS35L34_PDN_TDM, 0x00); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci ret = regmap_update_bits(priv->regmap, CS35L34_PWRCTL1, 24662306a36Sopenharmony_ci CS35L34_PDN_ALL, 0); 24762306a36Sopenharmony_ci if (ret < 0) { 24862306a36Sopenharmony_ci dev_err(component->dev, "Cannot set Power bits %d\n", ret); 24962306a36Sopenharmony_ci return ret; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci usleep_range(5000, 5100); 25262306a36Sopenharmony_ci break; 25362306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMD: 25462306a36Sopenharmony_ci if (priv->tdm_mode) { 25562306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L34_PWRCTL3, 25662306a36Sopenharmony_ci CS35L34_PDN_TDM, CS35L34_PDN_TDM); 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci ret = regmap_update_bits(priv->regmap, CS35L34_PWRCTL1, 25962306a36Sopenharmony_ci CS35L34_PDN_ALL, CS35L34_PDN_ALL); 26062306a36Sopenharmony_ci break; 26162306a36Sopenharmony_ci default: 26262306a36Sopenharmony_ci pr_err("Invalid event = 0x%x\n", event); 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci return 0; 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic int cs35l34_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, 26862306a36Sopenharmony_ci unsigned int rx_mask, int slots, int slot_width) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 27162306a36Sopenharmony_ci struct cs35l34_private *priv = snd_soc_component_get_drvdata(component); 27262306a36Sopenharmony_ci unsigned int reg, bit_pos; 27362306a36Sopenharmony_ci int slot, slot_num; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (slot_width != 8) 27662306a36Sopenharmony_ci return -EINVAL; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci priv->tdm_mode = true; 27962306a36Sopenharmony_ci /* scan rx_mask for aud slot */ 28062306a36Sopenharmony_ci slot = ffs(rx_mask) - 1; 28162306a36Sopenharmony_ci if (slot >= 0) 28262306a36Sopenharmony_ci snd_soc_component_update_bits(component, CS35L34_TDM_RX_CTL_1_AUDIN, 28362306a36Sopenharmony_ci CS35L34_X_LOC, slot); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci /* scan tx_mask: vmon(2 slots); imon (2 slots); vpmon (1 slot) 28662306a36Sopenharmony_ci * vbstmon (1 slot) 28762306a36Sopenharmony_ci */ 28862306a36Sopenharmony_ci slot = ffs(tx_mask) - 1; 28962306a36Sopenharmony_ci slot_num = 0; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci /* disable vpmon/vbstmon: enable later if set in tx_mask */ 29262306a36Sopenharmony_ci snd_soc_component_update_bits(component, CS35L34_TDM_TX_CTL_3_VPMON, 29362306a36Sopenharmony_ci CS35L34_X_STATE | CS35L34_X_LOC, 29462306a36Sopenharmony_ci CS35L34_X_STATE | CS35L34_X_LOC); 29562306a36Sopenharmony_ci snd_soc_component_update_bits(component, CS35L34_TDM_TX_CTL_4_VBSTMON, 29662306a36Sopenharmony_ci CS35L34_X_STATE | CS35L34_X_LOC, 29762306a36Sopenharmony_ci CS35L34_X_STATE | CS35L34_X_LOC); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci /* disconnect {vp,vbst}_mon routes: eanble later if set in tx_mask*/ 30062306a36Sopenharmony_ci while (slot >= 0) { 30162306a36Sopenharmony_ci /* configure VMON_TX_LOC */ 30262306a36Sopenharmony_ci if (slot_num == 0) 30362306a36Sopenharmony_ci snd_soc_component_update_bits(component, CS35L34_TDM_TX_CTL_1_VMON, 30462306a36Sopenharmony_ci CS35L34_X_STATE | CS35L34_X_LOC, slot); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci /* configure IMON_TX_LOC */ 30762306a36Sopenharmony_ci if (slot_num == 4) { 30862306a36Sopenharmony_ci snd_soc_component_update_bits(component, CS35L34_TDM_TX_CTL_2_IMON, 30962306a36Sopenharmony_ci CS35L34_X_STATE | CS35L34_X_LOC, slot); 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci /* configure VPMON_TX_LOC */ 31262306a36Sopenharmony_ci if (slot_num == 3) { 31362306a36Sopenharmony_ci snd_soc_component_update_bits(component, CS35L34_TDM_TX_CTL_3_VPMON, 31462306a36Sopenharmony_ci CS35L34_X_STATE | CS35L34_X_LOC, slot); 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci /* configure VBSTMON_TX_LOC */ 31762306a36Sopenharmony_ci if (slot_num == 7) { 31862306a36Sopenharmony_ci snd_soc_component_update_bits(component, 31962306a36Sopenharmony_ci CS35L34_TDM_TX_CTL_4_VBSTMON, 32062306a36Sopenharmony_ci CS35L34_X_STATE | CS35L34_X_LOC, slot); 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* Enable the relevant tx slot */ 32462306a36Sopenharmony_ci reg = CS35L34_TDM_TX_SLOT_EN_4 - (slot/8); 32562306a36Sopenharmony_ci bit_pos = slot - ((slot / 8) * (8)); 32662306a36Sopenharmony_ci snd_soc_component_update_bits(component, reg, 32762306a36Sopenharmony_ci 1 << bit_pos, 1 << bit_pos); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci tx_mask &= ~(1 << slot); 33062306a36Sopenharmony_ci slot = ffs(tx_mask) - 1; 33162306a36Sopenharmony_ci slot_num++; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci return 0; 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic int cs35l34_main_amp_event(struct snd_soc_dapm_widget *w, 33862306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 34162306a36Sopenharmony_ci struct cs35l34_private *priv = snd_soc_component_get_drvdata(component); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci switch (event) { 34462306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 34562306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L34_BST_CVTR_V_CTL, 34662306a36Sopenharmony_ci CS35L34_BST_CVTL_MASK, priv->pdata.boost_vtge); 34762306a36Sopenharmony_ci usleep_range(5000, 5100); 34862306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L34_PROTECT_CTL, 34962306a36Sopenharmony_ci CS35L34_MUTE, 0); 35062306a36Sopenharmony_ci break; 35162306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMD: 35262306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L34_BST_CVTR_V_CTL, 35362306a36Sopenharmony_ci CS35L34_BST_CVTL_MASK, 0); 35462306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L34_PROTECT_CTL, 35562306a36Sopenharmony_ci CS35L34_MUTE, CS35L34_MUTE); 35662306a36Sopenharmony_ci usleep_range(5000, 5100); 35762306a36Sopenharmony_ci break; 35862306a36Sopenharmony_ci default: 35962306a36Sopenharmony_ci pr_err("Invalid event = 0x%x\n", event); 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci return 0; 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(dig_vol_tlv, -10200, 50, 0); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(amp_gain_tlv, 300, 100, 0); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic const struct snd_kcontrol_new cs35l34_snd_controls[] = { 37062306a36Sopenharmony_ci SOC_SINGLE_SX_TLV("Digital Volume", CS35L34_AMP_DIG_VOL, 37162306a36Sopenharmony_ci 0, 0x34, 0xE4, dig_vol_tlv), 37262306a36Sopenharmony_ci SOC_SINGLE_TLV("Amp Gain Volume", CS35L34_AMP_ANLG_GAIN_CTL, 37362306a36Sopenharmony_ci 0, 0xF, 0, amp_gain_tlv), 37462306a36Sopenharmony_ci}; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic int cs35l34_mclk_event(struct snd_soc_dapm_widget *w, 37862306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 38162306a36Sopenharmony_ci struct cs35l34_private *priv = snd_soc_component_get_drvdata(component); 38262306a36Sopenharmony_ci int ret, i; 38362306a36Sopenharmony_ci unsigned int reg; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci switch (event) { 38662306a36Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 38762306a36Sopenharmony_ci ret = regmap_read(priv->regmap, CS35L34_AMP_DIG_VOL_CTL, 38862306a36Sopenharmony_ci ®); 38962306a36Sopenharmony_ci if (ret != 0) { 39062306a36Sopenharmony_ci pr_err("%s regmap read failure %d\n", __func__, ret); 39162306a36Sopenharmony_ci return ret; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci if (reg & CS35L34_AMP_DIGSFT) 39462306a36Sopenharmony_ci msleep(40); 39562306a36Sopenharmony_ci else 39662306a36Sopenharmony_ci usleep_range(2000, 2100); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci for (i = 0; i < PDN_DONE_ATTEMPTS; i++) { 39962306a36Sopenharmony_ci ret = regmap_read(priv->regmap, CS35L34_INT_STATUS_2, 40062306a36Sopenharmony_ci ®); 40162306a36Sopenharmony_ci if (ret != 0) { 40262306a36Sopenharmony_ci pr_err("%s regmap read failure %d\n", 40362306a36Sopenharmony_ci __func__, ret); 40462306a36Sopenharmony_ci return ret; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci if (reg & CS35L34_PDN_DONE) 40762306a36Sopenharmony_ci break; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci usleep_range(5000, 5100); 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci if (i == PDN_DONE_ATTEMPTS) 41262306a36Sopenharmony_ci pr_err("%s Device did not power down properly\n", 41362306a36Sopenharmony_ci __func__); 41462306a36Sopenharmony_ci break; 41562306a36Sopenharmony_ci default: 41662306a36Sopenharmony_ci pr_err("Invalid event = 0x%x\n", event); 41762306a36Sopenharmony_ci break; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci return 0; 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget cs35l34_dapm_widgets[] = { 42362306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN_E("SDIN", NULL, 0, CS35L34_PWRCTL3, 42462306a36Sopenharmony_ci 1, 1, cs35l34_sdin_event, 42562306a36Sopenharmony_ci SND_SOC_DAPM_PRE_PMU | 42662306a36Sopenharmony_ci SND_SOC_DAPM_POST_PMD), 42762306a36Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L34_PWRCTL3, 2, 1), 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci SND_SOC_DAPM_SUPPLY("EXTCLK", CS35L34_PWRCTL3, 7, 1, 43062306a36Sopenharmony_ci cs35l34_mclk_event, SND_SOC_DAPM_PRE_PMD), 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("SPK"), 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("VP"), 43562306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("VPST"), 43662306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("ISENSE"), 43762306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("VSENSE"), 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci SND_SOC_DAPM_ADC("VMON ADC", NULL, CS35L34_PWRCTL2, 7, 1), 44062306a36Sopenharmony_ci SND_SOC_DAPM_ADC("IMON ADC", NULL, CS35L34_PWRCTL2, 6, 1), 44162306a36Sopenharmony_ci SND_SOC_DAPM_ADC("VPMON ADC", NULL, CS35L34_PWRCTL3, 3, 1), 44262306a36Sopenharmony_ci SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, CS35L34_PWRCTL3, 4, 1), 44362306a36Sopenharmony_ci SND_SOC_DAPM_ADC("CLASS H", NULL, CS35L34_PWRCTL2, 5, 1), 44462306a36Sopenharmony_ci SND_SOC_DAPM_ADC("BOOST", NULL, CS35L34_PWRCTL2, 2, 1), 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci SND_SOC_DAPM_OUT_DRV_E("Main AMP", CS35L34_PWRCTL2, 0, 1, NULL, 0, 44762306a36Sopenharmony_ci cs35l34_main_amp_event, SND_SOC_DAPM_POST_PMU | 44862306a36Sopenharmony_ci SND_SOC_DAPM_POST_PMD), 44962306a36Sopenharmony_ci}; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic const struct snd_soc_dapm_route cs35l34_audio_map[] = { 45262306a36Sopenharmony_ci {"SDIN", NULL, "AMP Playback"}, 45362306a36Sopenharmony_ci {"BOOST", NULL, "SDIN"}, 45462306a36Sopenharmony_ci {"CLASS H", NULL, "BOOST"}, 45562306a36Sopenharmony_ci {"Main AMP", NULL, "CLASS H"}, 45662306a36Sopenharmony_ci {"SPK", NULL, "Main AMP"}, 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci {"VPMON ADC", NULL, "CLASS H"}, 45962306a36Sopenharmony_ci {"VBSTMON ADC", NULL, "CLASS H"}, 46062306a36Sopenharmony_ci {"SPK", NULL, "VPMON ADC"}, 46162306a36Sopenharmony_ci {"SPK", NULL, "VBSTMON ADC"}, 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci {"IMON ADC", NULL, "ISENSE"}, 46462306a36Sopenharmony_ci {"VMON ADC", NULL, "VSENSE"}, 46562306a36Sopenharmony_ci {"SDOUT", NULL, "IMON ADC"}, 46662306a36Sopenharmony_ci {"SDOUT", NULL, "VMON ADC"}, 46762306a36Sopenharmony_ci {"AMP Capture", NULL, "SDOUT"}, 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci {"SDIN", NULL, "EXTCLK"}, 47062306a36Sopenharmony_ci {"SDOUT", NULL, "EXTCLK"}, 47162306a36Sopenharmony_ci}; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistruct cs35l34_mclk_div { 47462306a36Sopenharmony_ci int mclk; 47562306a36Sopenharmony_ci int srate; 47662306a36Sopenharmony_ci u8 adsp_rate; 47762306a36Sopenharmony_ci}; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic struct cs35l34_mclk_div cs35l34_mclk_coeffs[] = { 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci /* MCLK, Sample Rate, adsp_rate */ 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci {5644800, 11025, 0x1}, 48462306a36Sopenharmony_ci {5644800, 22050, 0x4}, 48562306a36Sopenharmony_ci {5644800, 44100, 0x7}, 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci {6000000, 8000, 0x0}, 48862306a36Sopenharmony_ci {6000000, 11025, 0x1}, 48962306a36Sopenharmony_ci {6000000, 12000, 0x2}, 49062306a36Sopenharmony_ci {6000000, 16000, 0x3}, 49162306a36Sopenharmony_ci {6000000, 22050, 0x4}, 49262306a36Sopenharmony_ci {6000000, 24000, 0x5}, 49362306a36Sopenharmony_ci {6000000, 32000, 0x6}, 49462306a36Sopenharmony_ci {6000000, 44100, 0x7}, 49562306a36Sopenharmony_ci {6000000, 48000, 0x8}, 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci {6144000, 8000, 0x0}, 49862306a36Sopenharmony_ci {6144000, 11025, 0x1}, 49962306a36Sopenharmony_ci {6144000, 12000, 0x2}, 50062306a36Sopenharmony_ci {6144000, 16000, 0x3}, 50162306a36Sopenharmony_ci {6144000, 22050, 0x4}, 50262306a36Sopenharmony_ci {6144000, 24000, 0x5}, 50362306a36Sopenharmony_ci {6144000, 32000, 0x6}, 50462306a36Sopenharmony_ci {6144000, 44100, 0x7}, 50562306a36Sopenharmony_ci {6144000, 48000, 0x8}, 50662306a36Sopenharmony_ci}; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_cistatic int cs35l34_get_mclk_coeff(int mclk, int srate) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci int i; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cs35l34_mclk_coeffs); i++) { 51362306a36Sopenharmony_ci if (cs35l34_mclk_coeffs[i].mclk == mclk && 51462306a36Sopenharmony_ci cs35l34_mclk_coeffs[i].srate == srate) 51562306a36Sopenharmony_ci return i; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci return -EINVAL; 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic int cs35l34_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 52362306a36Sopenharmony_ci struct cs35l34_private *priv = snd_soc_component_get_drvdata(component); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 52662306a36Sopenharmony_ci case SND_SOC_DAIFMT_CBM_CFM: 52762306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L34_ADSP_CLK_CTL, 52862306a36Sopenharmony_ci 0x80, 0x80); 52962306a36Sopenharmony_ci break; 53062306a36Sopenharmony_ci case SND_SOC_DAIFMT_CBS_CFS: 53162306a36Sopenharmony_ci regmap_update_bits(priv->regmap, CS35L34_ADSP_CLK_CTL, 53262306a36Sopenharmony_ci 0x80, 0x00); 53362306a36Sopenharmony_ci break; 53462306a36Sopenharmony_ci default: 53562306a36Sopenharmony_ci return -EINVAL; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci return 0; 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic int cs35l34_pcm_hw_params(struct snd_pcm_substream *substream, 54162306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 54262306a36Sopenharmony_ci struct snd_soc_dai *dai) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 54562306a36Sopenharmony_ci struct cs35l34_private *priv = snd_soc_component_get_drvdata(component); 54662306a36Sopenharmony_ci int srate = params_rate(params); 54762306a36Sopenharmony_ci int ret; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci int coeff = cs35l34_get_mclk_coeff(priv->mclk_int, srate); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci if (coeff < 0) { 55262306a36Sopenharmony_ci dev_err(component->dev, "ERROR: Invalid mclk %d and/or srate %d\n", 55362306a36Sopenharmony_ci priv->mclk_int, srate); 55462306a36Sopenharmony_ci return coeff; 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci ret = regmap_update_bits(priv->regmap, CS35L34_ADSP_CLK_CTL, 55862306a36Sopenharmony_ci CS35L34_ADSP_RATE, cs35l34_mclk_coeffs[coeff].adsp_rate); 55962306a36Sopenharmony_ci if (ret != 0) 56062306a36Sopenharmony_ci dev_err(component->dev, "Failed to set clock state %d\n", ret); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci return ret; 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic const unsigned int cs35l34_src_rates[] = { 56662306a36Sopenharmony_ci 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 56762306a36Sopenharmony_ci}; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list cs35l34_constraints = { 57162306a36Sopenharmony_ci .count = ARRAY_SIZE(cs35l34_src_rates), 57262306a36Sopenharmony_ci .list = cs35l34_src_rates, 57362306a36Sopenharmony_ci}; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_cistatic int cs35l34_pcm_startup(struct snd_pcm_substream *substream, 57662306a36Sopenharmony_ci struct snd_soc_dai *dai) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci snd_pcm_hw_constraint_list(substream->runtime, 0, 58062306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, &cs35l34_constraints); 58162306a36Sopenharmony_ci return 0; 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_cistatic int cs35l34_set_tristate(struct snd_soc_dai *dai, int tristate) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci if (tristate) 59162306a36Sopenharmony_ci snd_soc_component_update_bits(component, CS35L34_PWRCTL3, 59262306a36Sopenharmony_ci CS35L34_PDN_SDOUT, CS35L34_PDN_SDOUT); 59362306a36Sopenharmony_ci else 59462306a36Sopenharmony_ci snd_soc_component_update_bits(component, CS35L34_PWRCTL3, 59562306a36Sopenharmony_ci CS35L34_PDN_SDOUT, 0); 59662306a36Sopenharmony_ci return 0; 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic int cs35l34_dai_set_sysclk(struct snd_soc_dai *dai, 60062306a36Sopenharmony_ci int clk_id, unsigned int freq, int dir) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 60362306a36Sopenharmony_ci struct cs35l34_private *cs35l34 = snd_soc_component_get_drvdata(component); 60462306a36Sopenharmony_ci unsigned int value; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci switch (freq) { 60762306a36Sopenharmony_ci case CS35L34_MCLK_5644: 60862306a36Sopenharmony_ci value = CS35L34_MCLK_RATE_5P6448; 60962306a36Sopenharmony_ci cs35l34->mclk_int = freq; 61062306a36Sopenharmony_ci break; 61162306a36Sopenharmony_ci case CS35L34_MCLK_6: 61262306a36Sopenharmony_ci value = CS35L34_MCLK_RATE_6P0000; 61362306a36Sopenharmony_ci cs35l34->mclk_int = freq; 61462306a36Sopenharmony_ci break; 61562306a36Sopenharmony_ci case CS35L34_MCLK_6144: 61662306a36Sopenharmony_ci value = CS35L34_MCLK_RATE_6P1440; 61762306a36Sopenharmony_ci cs35l34->mclk_int = freq; 61862306a36Sopenharmony_ci break; 61962306a36Sopenharmony_ci case CS35L34_MCLK_11289: 62062306a36Sopenharmony_ci value = CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_5P6448; 62162306a36Sopenharmony_ci cs35l34->mclk_int = freq / 2; 62262306a36Sopenharmony_ci break; 62362306a36Sopenharmony_ci case CS35L34_MCLK_12: 62462306a36Sopenharmony_ci value = CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_6P0000; 62562306a36Sopenharmony_ci cs35l34->mclk_int = freq / 2; 62662306a36Sopenharmony_ci break; 62762306a36Sopenharmony_ci case CS35L34_MCLK_12288: 62862306a36Sopenharmony_ci value = CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_6P1440; 62962306a36Sopenharmony_ci cs35l34->mclk_int = freq / 2; 63062306a36Sopenharmony_ci break; 63162306a36Sopenharmony_ci default: 63262306a36Sopenharmony_ci dev_err(component->dev, "ERROR: Invalid Frequency %d\n", freq); 63362306a36Sopenharmony_ci cs35l34->mclk_int = 0; 63462306a36Sopenharmony_ci return -EINVAL; 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, CS35L34_MCLK_CTL, 63762306a36Sopenharmony_ci CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_MASK, value); 63862306a36Sopenharmony_ci return 0; 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cistatic const struct snd_soc_dai_ops cs35l34_ops = { 64262306a36Sopenharmony_ci .startup = cs35l34_pcm_startup, 64362306a36Sopenharmony_ci .set_tristate = cs35l34_set_tristate, 64462306a36Sopenharmony_ci .set_fmt = cs35l34_set_dai_fmt, 64562306a36Sopenharmony_ci .hw_params = cs35l34_pcm_hw_params, 64662306a36Sopenharmony_ci .set_sysclk = cs35l34_dai_set_sysclk, 64762306a36Sopenharmony_ci .set_tdm_slot = cs35l34_set_tdm_slot, 64862306a36Sopenharmony_ci}; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_cistatic struct snd_soc_dai_driver cs35l34_dai = { 65162306a36Sopenharmony_ci .name = "cs35l34", 65262306a36Sopenharmony_ci .id = 0, 65362306a36Sopenharmony_ci .playback = { 65462306a36Sopenharmony_ci .stream_name = "AMP Playback", 65562306a36Sopenharmony_ci .channels_min = 1, 65662306a36Sopenharmony_ci .channels_max = 8, 65762306a36Sopenharmony_ci .rates = CS35L34_RATES, 65862306a36Sopenharmony_ci .formats = CS35L34_FORMATS, 65962306a36Sopenharmony_ci }, 66062306a36Sopenharmony_ci .capture = { 66162306a36Sopenharmony_ci .stream_name = "AMP Capture", 66262306a36Sopenharmony_ci .channels_min = 1, 66362306a36Sopenharmony_ci .channels_max = 8, 66462306a36Sopenharmony_ci .rates = CS35L34_RATES, 66562306a36Sopenharmony_ci .formats = CS35L34_FORMATS, 66662306a36Sopenharmony_ci }, 66762306a36Sopenharmony_ci .ops = &cs35l34_ops, 66862306a36Sopenharmony_ci .symmetric_rate = 1, 66962306a36Sopenharmony_ci}; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_cistatic int cs35l34_boost_inductor(struct cs35l34_private *cs35l34, 67262306a36Sopenharmony_ci unsigned int inductor) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci struct snd_soc_component *component = cs35l34->component; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci switch (inductor) { 67762306a36Sopenharmony_ci case 1000: /* 1 uH */ 67862306a36Sopenharmony_ci regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x24); 67962306a36Sopenharmony_ci regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x24); 68062306a36Sopenharmony_ci regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP, 68162306a36Sopenharmony_ci 0x4E); 68262306a36Sopenharmony_ci regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 0); 68362306a36Sopenharmony_ci break; 68462306a36Sopenharmony_ci case 1200: /* 1.2 uH */ 68562306a36Sopenharmony_ci regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x20); 68662306a36Sopenharmony_ci regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x20); 68762306a36Sopenharmony_ci regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP, 68862306a36Sopenharmony_ci 0x47); 68962306a36Sopenharmony_ci regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 1); 69062306a36Sopenharmony_ci break; 69162306a36Sopenharmony_ci case 1500: /* 1.5uH */ 69262306a36Sopenharmony_ci regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x20); 69362306a36Sopenharmony_ci regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x20); 69462306a36Sopenharmony_ci regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP, 69562306a36Sopenharmony_ci 0x3C); 69662306a36Sopenharmony_ci regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 2); 69762306a36Sopenharmony_ci break; 69862306a36Sopenharmony_ci case 2200: /* 2.2uH */ 69962306a36Sopenharmony_ci regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x19); 70062306a36Sopenharmony_ci regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x25); 70162306a36Sopenharmony_ci regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP, 70262306a36Sopenharmony_ci 0x23); 70362306a36Sopenharmony_ci regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 3); 70462306a36Sopenharmony_ci break; 70562306a36Sopenharmony_ci default: 70662306a36Sopenharmony_ci dev_err(component->dev, "%s Invalid Inductor Value %d uH\n", 70762306a36Sopenharmony_ci __func__, inductor); 70862306a36Sopenharmony_ci return -EINVAL; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci return 0; 71162306a36Sopenharmony_ci} 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_cistatic int cs35l34_probe(struct snd_soc_component *component) 71462306a36Sopenharmony_ci{ 71562306a36Sopenharmony_ci int ret = 0; 71662306a36Sopenharmony_ci struct cs35l34_private *cs35l34 = snd_soc_component_get_drvdata(component); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci pm_runtime_get_sync(component->dev); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci /* Set over temperature warning attenuation to 6 dB */ 72162306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL, 72262306a36Sopenharmony_ci CS35L34_OTW_ATTN_MASK, 0x8); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci /* Set Power control registers 2 and 3 to have everything 72562306a36Sopenharmony_ci * powered down at initialization 72662306a36Sopenharmony_ci */ 72762306a36Sopenharmony_ci regmap_write(cs35l34->regmap, CS35L34_PWRCTL2, 0xFD); 72862306a36Sopenharmony_ci regmap_write(cs35l34->regmap, CS35L34_PWRCTL3, 0x1F); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci /* Set mute bit at startup */ 73162306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL, 73262306a36Sopenharmony_ci CS35L34_MUTE, CS35L34_MUTE); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci /* Set Platform Data */ 73562306a36Sopenharmony_ci if (cs35l34->pdata.boost_peak) 73662306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, CS35L34_BST_PEAK_I, 73762306a36Sopenharmony_ci CS35L34_BST_PEAK_MASK, 73862306a36Sopenharmony_ci cs35l34->pdata.boost_peak); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci if (cs35l34->pdata.gain_zc_disable) 74162306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL, 74262306a36Sopenharmony_ci CS35L34_GAIN_ZC_MASK, 0); 74362306a36Sopenharmony_ci else 74462306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL, 74562306a36Sopenharmony_ci CS35L34_GAIN_ZC_MASK, CS35L34_GAIN_ZC_MASK); 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci if (cs35l34->pdata.aif_half_drv) 74862306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, CS35L34_ADSP_CLK_CTL, 74962306a36Sopenharmony_ci CS35L34_ADSP_DRIVE, 0); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci if (cs35l34->pdata.digsft_disable) 75262306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, CS35L34_AMP_DIG_VOL_CTL, 75362306a36Sopenharmony_ci CS35L34_AMP_DIGSFT, 0); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci if (cs35l34->pdata.amp_inv) 75662306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, CS35L34_AMP_DIG_VOL_CTL, 75762306a36Sopenharmony_ci CS35L34_INV, CS35L34_INV); 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci if (cs35l34->pdata.boost_ind) 76062306a36Sopenharmony_ci ret = cs35l34_boost_inductor(cs35l34, cs35l34->pdata.boost_ind); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci if (cs35l34->pdata.i2s_sdinloc) 76362306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, CS35L34_ADSP_I2S_CTL, 76462306a36Sopenharmony_ci CS35L34_I2S_LOC_MASK, 76562306a36Sopenharmony_ci cs35l34->pdata.i2s_sdinloc << CS35L34_I2S_LOC_SHIFT); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci if (cs35l34->pdata.tdm_rising_edge) 76862306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, CS35L34_ADSP_TDM_CTL, 76962306a36Sopenharmony_ci 1, 1); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci pm_runtime_put_sync(component->dev); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci return ret; 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_dev_cs35l34 = { 77862306a36Sopenharmony_ci .probe = cs35l34_probe, 77962306a36Sopenharmony_ci .dapm_widgets = cs35l34_dapm_widgets, 78062306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(cs35l34_dapm_widgets), 78162306a36Sopenharmony_ci .dapm_routes = cs35l34_audio_map, 78262306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(cs35l34_audio_map), 78362306a36Sopenharmony_ci .controls = cs35l34_snd_controls, 78462306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(cs35l34_snd_controls), 78562306a36Sopenharmony_ci .idle_bias_on = 1, 78662306a36Sopenharmony_ci .use_pmdown_time = 1, 78762306a36Sopenharmony_ci .endianness = 1, 78862306a36Sopenharmony_ci}; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_cistatic struct regmap_config cs35l34_regmap = { 79162306a36Sopenharmony_ci .reg_bits = 8, 79262306a36Sopenharmony_ci .val_bits = 8, 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci .max_register = CS35L34_MAX_REGISTER, 79562306a36Sopenharmony_ci .reg_defaults = cs35l34_reg, 79662306a36Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(cs35l34_reg), 79762306a36Sopenharmony_ci .volatile_reg = cs35l34_volatile_register, 79862306a36Sopenharmony_ci .readable_reg = cs35l34_readable_register, 79962306a36Sopenharmony_ci .precious_reg = cs35l34_precious_register, 80062306a36Sopenharmony_ci .cache_type = REGCACHE_MAPLE, 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci .use_single_read = true, 80362306a36Sopenharmony_ci .use_single_write = true, 80462306a36Sopenharmony_ci}; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_cistatic int cs35l34_handle_of_data(struct i2c_client *i2c_client, 80762306a36Sopenharmony_ci struct cs35l34_platform_data *pdata) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci struct device_node *np = i2c_client->dev.of_node; 81062306a36Sopenharmony_ci unsigned int val; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci if (of_property_read_u32(np, "cirrus,boost-vtge-millivolt", 81362306a36Sopenharmony_ci &val) >= 0) { 81462306a36Sopenharmony_ci /* Boost Voltage has a maximum of 8V */ 81562306a36Sopenharmony_ci if (val > 8000 || (val < 3300 && val > 0)) { 81662306a36Sopenharmony_ci dev_err(&i2c_client->dev, 81762306a36Sopenharmony_ci "Invalid Boost Voltage %d mV\n", val); 81862306a36Sopenharmony_ci return -EINVAL; 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci if (val == 0) 82162306a36Sopenharmony_ci pdata->boost_vtge = 0; /* Use VP */ 82262306a36Sopenharmony_ci else 82362306a36Sopenharmony_ci pdata->boost_vtge = ((val - 3300)/100) + 1; 82462306a36Sopenharmony_ci } else { 82562306a36Sopenharmony_ci dev_warn(&i2c_client->dev, 82662306a36Sopenharmony_ci "Boost Voltage not specified. Using VP\n"); 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci if (of_property_read_u32(np, "cirrus,boost-ind-nanohenry", &val) >= 0) { 83062306a36Sopenharmony_ci pdata->boost_ind = val; 83162306a36Sopenharmony_ci } else { 83262306a36Sopenharmony_ci dev_err(&i2c_client->dev, "Inductor not specified.\n"); 83362306a36Sopenharmony_ci return -EINVAL; 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci if (of_property_read_u32(np, "cirrus,boost-peak-milliamp", &val) >= 0) { 83762306a36Sopenharmony_ci if (val > 3840 || val < 1200) { 83862306a36Sopenharmony_ci dev_err(&i2c_client->dev, 83962306a36Sopenharmony_ci "Invalid Boost Peak Current %d mA\n", val); 84062306a36Sopenharmony_ci return -EINVAL; 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci pdata->boost_peak = ((val - 1200)/80) + 1; 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci pdata->aif_half_drv = of_property_read_bool(np, 84662306a36Sopenharmony_ci "cirrus,aif-half-drv"); 84762306a36Sopenharmony_ci pdata->digsft_disable = of_property_read_bool(np, 84862306a36Sopenharmony_ci "cirrus,digsft-disable"); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci pdata->gain_zc_disable = of_property_read_bool(np, 85162306a36Sopenharmony_ci "cirrus,gain-zc-disable"); 85262306a36Sopenharmony_ci pdata->amp_inv = of_property_read_bool(np, "cirrus,amp-inv"); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci if (of_property_read_u32(np, "cirrus,i2s-sdinloc", &val) >= 0) 85562306a36Sopenharmony_ci pdata->i2s_sdinloc = val; 85662306a36Sopenharmony_ci if (of_property_read_u32(np, "cirrus,tdm-rising-edge", &val) >= 0) 85762306a36Sopenharmony_ci pdata->tdm_rising_edge = val; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci return 0; 86062306a36Sopenharmony_ci} 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_cistatic irqreturn_t cs35l34_irq_thread(int irq, void *data) 86362306a36Sopenharmony_ci{ 86462306a36Sopenharmony_ci struct cs35l34_private *cs35l34 = data; 86562306a36Sopenharmony_ci struct snd_soc_component *component = cs35l34->component; 86662306a36Sopenharmony_ci unsigned int sticky1, sticky2, sticky3, sticky4; 86762306a36Sopenharmony_ci unsigned int mask1, mask2, mask3, mask4, current1; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci /* ack the irq by reading all status registers */ 87162306a36Sopenharmony_ci regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_4, &sticky4); 87262306a36Sopenharmony_ci regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_3, &sticky3); 87362306a36Sopenharmony_ci regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_2, &sticky2); 87462306a36Sopenharmony_ci regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_1, &sticky1); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci regmap_read(cs35l34->regmap, CS35L34_INT_MASK_4, &mask4); 87762306a36Sopenharmony_ci regmap_read(cs35l34->regmap, CS35L34_INT_MASK_3, &mask3); 87862306a36Sopenharmony_ci regmap_read(cs35l34->regmap, CS35L34_INT_MASK_2, &mask2); 87962306a36Sopenharmony_ci regmap_read(cs35l34->regmap, CS35L34_INT_MASK_1, &mask1); 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci if (!(sticky1 & ~mask1) && !(sticky2 & ~mask2) && !(sticky3 & ~mask3) 88262306a36Sopenharmony_ci && !(sticky4 & ~mask4)) 88362306a36Sopenharmony_ci return IRQ_NONE; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_1, ¤t1); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci if (sticky1 & CS35L34_CAL_ERR) { 88862306a36Sopenharmony_ci dev_err(component->dev, "Cal error\n"); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci /* error is no longer asserted; safe to reset */ 89162306a36Sopenharmony_ci if (!(current1 & CS35L34_CAL_ERR)) { 89262306a36Sopenharmony_ci dev_dbg(component->dev, "Cal error release\n"); 89362306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, 89462306a36Sopenharmony_ci CS35L34_PROT_RELEASE_CTL, 89562306a36Sopenharmony_ci CS35L34_CAL_ERR_RLS, 0); 89662306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, 89762306a36Sopenharmony_ci CS35L34_PROT_RELEASE_CTL, 89862306a36Sopenharmony_ci CS35L34_CAL_ERR_RLS, 89962306a36Sopenharmony_ci CS35L34_CAL_ERR_RLS); 90062306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, 90162306a36Sopenharmony_ci CS35L34_PROT_RELEASE_CTL, 90262306a36Sopenharmony_ci CS35L34_CAL_ERR_RLS, 0); 90362306a36Sopenharmony_ci /* note: amp will re-calibrate on next resume */ 90462306a36Sopenharmony_ci } 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci if (sticky1 & CS35L34_ALIVE_ERR) 90862306a36Sopenharmony_ci dev_err(component->dev, "Alive error\n"); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci if (sticky1 & CS35L34_AMP_SHORT) { 91162306a36Sopenharmony_ci dev_crit(component->dev, "Amp short error\n"); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci /* error is no longer asserted; safe to reset */ 91462306a36Sopenharmony_ci if (!(current1 & CS35L34_AMP_SHORT)) { 91562306a36Sopenharmony_ci dev_dbg(component->dev, 91662306a36Sopenharmony_ci "Amp short error release\n"); 91762306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, 91862306a36Sopenharmony_ci CS35L34_PROT_RELEASE_CTL, 91962306a36Sopenharmony_ci CS35L34_SHORT_RLS, 0); 92062306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, 92162306a36Sopenharmony_ci CS35L34_PROT_RELEASE_CTL, 92262306a36Sopenharmony_ci CS35L34_SHORT_RLS, 92362306a36Sopenharmony_ci CS35L34_SHORT_RLS); 92462306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, 92562306a36Sopenharmony_ci CS35L34_PROT_RELEASE_CTL, 92662306a36Sopenharmony_ci CS35L34_SHORT_RLS, 0); 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci if (sticky1 & CS35L34_OTW) { 93162306a36Sopenharmony_ci dev_crit(component->dev, "Over temperature warning\n"); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci /* error is no longer asserted; safe to reset */ 93462306a36Sopenharmony_ci if (!(current1 & CS35L34_OTW)) { 93562306a36Sopenharmony_ci dev_dbg(component->dev, 93662306a36Sopenharmony_ci "Over temperature warning release\n"); 93762306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, 93862306a36Sopenharmony_ci CS35L34_PROT_RELEASE_CTL, 93962306a36Sopenharmony_ci CS35L34_OTW_RLS, 0); 94062306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, 94162306a36Sopenharmony_ci CS35L34_PROT_RELEASE_CTL, 94262306a36Sopenharmony_ci CS35L34_OTW_RLS, 94362306a36Sopenharmony_ci CS35L34_OTW_RLS); 94462306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, 94562306a36Sopenharmony_ci CS35L34_PROT_RELEASE_CTL, 94662306a36Sopenharmony_ci CS35L34_OTW_RLS, 0); 94762306a36Sopenharmony_ci } 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci if (sticky1 & CS35L34_OTE) { 95162306a36Sopenharmony_ci dev_crit(component->dev, "Over temperature error\n"); 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci /* error is no longer asserted; safe to reset */ 95462306a36Sopenharmony_ci if (!(current1 & CS35L34_OTE)) { 95562306a36Sopenharmony_ci dev_dbg(component->dev, 95662306a36Sopenharmony_ci "Over temperature error release\n"); 95762306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, 95862306a36Sopenharmony_ci CS35L34_PROT_RELEASE_CTL, 95962306a36Sopenharmony_ci CS35L34_OTE_RLS, 0); 96062306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, 96162306a36Sopenharmony_ci CS35L34_PROT_RELEASE_CTL, 96262306a36Sopenharmony_ci CS35L34_OTE_RLS, 96362306a36Sopenharmony_ci CS35L34_OTE_RLS); 96462306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, 96562306a36Sopenharmony_ci CS35L34_PROT_RELEASE_CTL, 96662306a36Sopenharmony_ci CS35L34_OTE_RLS, 0); 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci } 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci if (sticky3 & CS35L34_BST_HIGH) { 97162306a36Sopenharmony_ci dev_crit(component->dev, "VBST too high error; powering off!\n"); 97262306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL2, 97362306a36Sopenharmony_ci CS35L34_PDN_AMP, CS35L34_PDN_AMP); 97462306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL1, 97562306a36Sopenharmony_ci CS35L34_PDN_ALL, CS35L34_PDN_ALL); 97662306a36Sopenharmony_ci } 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci if (sticky3 & CS35L34_LBST_SHORT) { 97962306a36Sopenharmony_ci dev_crit(component->dev, "LBST short error; powering off!\n"); 98062306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL2, 98162306a36Sopenharmony_ci CS35L34_PDN_AMP, CS35L34_PDN_AMP); 98262306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL1, 98362306a36Sopenharmony_ci CS35L34_PDN_ALL, CS35L34_PDN_ALL); 98462306a36Sopenharmony_ci } 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci return IRQ_HANDLED; 98762306a36Sopenharmony_ci} 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_cistatic const char * const cs35l34_core_supplies[] = { 99062306a36Sopenharmony_ci "VA", 99162306a36Sopenharmony_ci "VP", 99262306a36Sopenharmony_ci}; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_cistatic int cs35l34_i2c_probe(struct i2c_client *i2c_client) 99562306a36Sopenharmony_ci{ 99662306a36Sopenharmony_ci struct cs35l34_private *cs35l34; 99762306a36Sopenharmony_ci struct cs35l34_platform_data *pdata = 99862306a36Sopenharmony_ci dev_get_platdata(&i2c_client->dev); 99962306a36Sopenharmony_ci int i, devid; 100062306a36Sopenharmony_ci int ret; 100162306a36Sopenharmony_ci unsigned int reg; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci cs35l34 = devm_kzalloc(&i2c_client->dev, sizeof(*cs35l34), GFP_KERNEL); 100462306a36Sopenharmony_ci if (!cs35l34) 100562306a36Sopenharmony_ci return -ENOMEM; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci i2c_set_clientdata(i2c_client, cs35l34); 100862306a36Sopenharmony_ci cs35l34->regmap = devm_regmap_init_i2c(i2c_client, &cs35l34_regmap); 100962306a36Sopenharmony_ci if (IS_ERR(cs35l34->regmap)) { 101062306a36Sopenharmony_ci ret = PTR_ERR(cs35l34->regmap); 101162306a36Sopenharmony_ci dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); 101262306a36Sopenharmony_ci return ret; 101362306a36Sopenharmony_ci } 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci cs35l34->num_core_supplies = ARRAY_SIZE(cs35l34_core_supplies); 101662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cs35l34_core_supplies); i++) 101762306a36Sopenharmony_ci cs35l34->core_supplies[i].supply = cs35l34_core_supplies[i]; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci ret = devm_regulator_bulk_get(&i2c_client->dev, 102062306a36Sopenharmony_ci cs35l34->num_core_supplies, 102162306a36Sopenharmony_ci cs35l34->core_supplies); 102262306a36Sopenharmony_ci if (ret != 0) { 102362306a36Sopenharmony_ci dev_err(&i2c_client->dev, 102462306a36Sopenharmony_ci "Failed to request core supplies %d\n", ret); 102562306a36Sopenharmony_ci return ret; 102662306a36Sopenharmony_ci } 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci ret = regulator_bulk_enable(cs35l34->num_core_supplies, 102962306a36Sopenharmony_ci cs35l34->core_supplies); 103062306a36Sopenharmony_ci if (ret != 0) { 103162306a36Sopenharmony_ci dev_err(&i2c_client->dev, 103262306a36Sopenharmony_ci "Failed to enable core supplies: %d\n", ret); 103362306a36Sopenharmony_ci return ret; 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci if (pdata) { 103762306a36Sopenharmony_ci cs35l34->pdata = *pdata; 103862306a36Sopenharmony_ci } else { 103962306a36Sopenharmony_ci pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata), 104062306a36Sopenharmony_ci GFP_KERNEL); 104162306a36Sopenharmony_ci if (!pdata) { 104262306a36Sopenharmony_ci ret = -ENOMEM; 104362306a36Sopenharmony_ci goto err_regulator; 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci if (i2c_client->dev.of_node) { 104762306a36Sopenharmony_ci ret = cs35l34_handle_of_data(i2c_client, pdata); 104862306a36Sopenharmony_ci if (ret != 0) 104962306a36Sopenharmony_ci goto err_regulator; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci } 105262306a36Sopenharmony_ci cs35l34->pdata = *pdata; 105362306a36Sopenharmony_ci } 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq, NULL, 105662306a36Sopenharmony_ci cs35l34_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW, 105762306a36Sopenharmony_ci "cs35l34", cs35l34); 105862306a36Sopenharmony_ci if (ret != 0) 105962306a36Sopenharmony_ci dev_err(&i2c_client->dev, "Failed to request IRQ: %d\n", ret); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci cs35l34->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, 106262306a36Sopenharmony_ci "reset", GPIOD_OUT_LOW); 106362306a36Sopenharmony_ci if (IS_ERR(cs35l34->reset_gpio)) { 106462306a36Sopenharmony_ci ret = PTR_ERR(cs35l34->reset_gpio); 106562306a36Sopenharmony_ci goto err_regulator; 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci gpiod_set_value_cansleep(cs35l34->reset_gpio, 1); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci msleep(CS35L34_START_DELAY); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci devid = cirrus_read_device_id(cs35l34->regmap, CS35L34_DEVID_AB); 107362306a36Sopenharmony_ci if (devid < 0) { 107462306a36Sopenharmony_ci ret = devid; 107562306a36Sopenharmony_ci dev_err(&i2c_client->dev, "Failed to read device ID: %d\n", ret); 107662306a36Sopenharmony_ci goto err_reset; 107762306a36Sopenharmony_ci } 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci if (devid != CS35L34_CHIP_ID) { 108062306a36Sopenharmony_ci dev_err(&i2c_client->dev, 108162306a36Sopenharmony_ci "CS35l34 Device ID (%X). Expected ID %X\n", 108262306a36Sopenharmony_ci devid, CS35L34_CHIP_ID); 108362306a36Sopenharmony_ci ret = -ENODEV; 108462306a36Sopenharmony_ci goto err_reset; 108562306a36Sopenharmony_ci } 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci ret = regmap_read(cs35l34->regmap, CS35L34_REV_ID, ®); 108862306a36Sopenharmony_ci if (ret < 0) { 108962306a36Sopenharmony_ci dev_err(&i2c_client->dev, "Get Revision ID failed\n"); 109062306a36Sopenharmony_ci goto err_reset; 109162306a36Sopenharmony_ci } 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci dev_info(&i2c_client->dev, 109462306a36Sopenharmony_ci "Cirrus Logic CS35l34 (%x), Revision: %02X\n", devid, 109562306a36Sopenharmony_ci reg & 0xFF); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci /* Unmask critical interrupts */ 109862306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, CS35L34_INT_MASK_1, 109962306a36Sopenharmony_ci CS35L34_M_CAL_ERR | CS35L34_M_ALIVE_ERR | 110062306a36Sopenharmony_ci CS35L34_M_AMP_SHORT | CS35L34_M_OTW | 110162306a36Sopenharmony_ci CS35L34_M_OTE, 0); 110262306a36Sopenharmony_ci regmap_update_bits(cs35l34->regmap, CS35L34_INT_MASK_3, 110362306a36Sopenharmony_ci CS35L34_M_BST_HIGH | CS35L34_M_LBST_SHORT, 0); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(&i2c_client->dev, 100); 110662306a36Sopenharmony_ci pm_runtime_use_autosuspend(&i2c_client->dev); 110762306a36Sopenharmony_ci pm_runtime_set_active(&i2c_client->dev); 110862306a36Sopenharmony_ci pm_runtime_enable(&i2c_client->dev); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci ret = devm_snd_soc_register_component(&i2c_client->dev, 111162306a36Sopenharmony_ci &soc_component_dev_cs35l34, &cs35l34_dai, 1); 111262306a36Sopenharmony_ci if (ret < 0) { 111362306a36Sopenharmony_ci dev_err(&i2c_client->dev, 111462306a36Sopenharmony_ci "%s: Register component failed\n", __func__); 111562306a36Sopenharmony_ci goto err_reset; 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci return 0; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_cierr_reset: 112162306a36Sopenharmony_ci gpiod_set_value_cansleep(cs35l34->reset_gpio, 0); 112262306a36Sopenharmony_cierr_regulator: 112362306a36Sopenharmony_ci regulator_bulk_disable(cs35l34->num_core_supplies, 112462306a36Sopenharmony_ci cs35l34->core_supplies); 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci return ret; 112762306a36Sopenharmony_ci} 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_cistatic void cs35l34_i2c_remove(struct i2c_client *client) 113062306a36Sopenharmony_ci{ 113162306a36Sopenharmony_ci struct cs35l34_private *cs35l34 = i2c_get_clientdata(client); 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci gpiod_set_value_cansleep(cs35l34->reset_gpio, 0); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci pm_runtime_disable(&client->dev); 113662306a36Sopenharmony_ci regulator_bulk_disable(cs35l34->num_core_supplies, 113762306a36Sopenharmony_ci cs35l34->core_supplies); 113862306a36Sopenharmony_ci} 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_cistatic int __maybe_unused cs35l34_runtime_resume(struct device *dev) 114162306a36Sopenharmony_ci{ 114262306a36Sopenharmony_ci struct cs35l34_private *cs35l34 = dev_get_drvdata(dev); 114362306a36Sopenharmony_ci int ret; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci ret = regulator_bulk_enable(cs35l34->num_core_supplies, 114662306a36Sopenharmony_ci cs35l34->core_supplies); 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci if (ret != 0) { 114962306a36Sopenharmony_ci dev_err(dev, "Failed to enable core supplies: %d\n", 115062306a36Sopenharmony_ci ret); 115162306a36Sopenharmony_ci return ret; 115262306a36Sopenharmony_ci } 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci regcache_cache_only(cs35l34->regmap, false); 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci gpiod_set_value_cansleep(cs35l34->reset_gpio, 1); 115762306a36Sopenharmony_ci msleep(CS35L34_START_DELAY); 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci ret = regcache_sync(cs35l34->regmap); 116062306a36Sopenharmony_ci if (ret != 0) { 116162306a36Sopenharmony_ci dev_err(dev, "Failed to restore register cache\n"); 116262306a36Sopenharmony_ci goto err; 116362306a36Sopenharmony_ci } 116462306a36Sopenharmony_ci return 0; 116562306a36Sopenharmony_cierr: 116662306a36Sopenharmony_ci regcache_cache_only(cs35l34->regmap, true); 116762306a36Sopenharmony_ci regulator_bulk_disable(cs35l34->num_core_supplies, 116862306a36Sopenharmony_ci cs35l34->core_supplies); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci return ret; 117162306a36Sopenharmony_ci} 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_cistatic int __maybe_unused cs35l34_runtime_suspend(struct device *dev) 117462306a36Sopenharmony_ci{ 117562306a36Sopenharmony_ci struct cs35l34_private *cs35l34 = dev_get_drvdata(dev); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci regcache_cache_only(cs35l34->regmap, true); 117862306a36Sopenharmony_ci regcache_mark_dirty(cs35l34->regmap); 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci gpiod_set_value_cansleep(cs35l34->reset_gpio, 0); 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci regulator_bulk_disable(cs35l34->num_core_supplies, 118362306a36Sopenharmony_ci cs35l34->core_supplies); 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci return 0; 118662306a36Sopenharmony_ci} 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_cistatic const struct dev_pm_ops cs35l34_pm_ops = { 118962306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(cs35l34_runtime_suspend, 119062306a36Sopenharmony_ci cs35l34_runtime_resume, 119162306a36Sopenharmony_ci NULL) 119262306a36Sopenharmony_ci}; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_cistatic const struct of_device_id cs35l34_of_match[] = { 119562306a36Sopenharmony_ci {.compatible = "cirrus,cs35l34"}, 119662306a36Sopenharmony_ci {}, 119762306a36Sopenharmony_ci}; 119862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, cs35l34_of_match); 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_cistatic const struct i2c_device_id cs35l34_id[] = { 120162306a36Sopenharmony_ci {"cs35l34", 0}, 120262306a36Sopenharmony_ci {} 120362306a36Sopenharmony_ci}; 120462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, cs35l34_id); 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_cistatic struct i2c_driver cs35l34_i2c_driver = { 120762306a36Sopenharmony_ci .driver = { 120862306a36Sopenharmony_ci .name = "cs35l34", 120962306a36Sopenharmony_ci .pm = &cs35l34_pm_ops, 121062306a36Sopenharmony_ci .of_match_table = cs35l34_of_match, 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci }, 121362306a36Sopenharmony_ci .id_table = cs35l34_id, 121462306a36Sopenharmony_ci .probe = cs35l34_i2c_probe, 121562306a36Sopenharmony_ci .remove = cs35l34_i2c_remove, 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci}; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_cistatic int __init cs35l34_modinit(void) 122062306a36Sopenharmony_ci{ 122162306a36Sopenharmony_ci int ret; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci ret = i2c_add_driver(&cs35l34_i2c_driver); 122462306a36Sopenharmony_ci if (ret != 0) { 122562306a36Sopenharmony_ci pr_err("Failed to register CS35l34 I2C driver: %d\n", ret); 122662306a36Sopenharmony_ci return ret; 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci return 0; 122962306a36Sopenharmony_ci} 123062306a36Sopenharmony_cimodule_init(cs35l34_modinit); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_cistatic void __exit cs35l34_exit(void) 123362306a36Sopenharmony_ci{ 123462306a36Sopenharmony_ci i2c_del_driver(&cs35l34_i2c_driver); 123562306a36Sopenharmony_ci} 123662306a36Sopenharmony_cimodule_exit(cs35l34_exit); 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ciMODULE_DESCRIPTION("ASoC CS35l34 driver"); 123962306a36Sopenharmony_ciMODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <Paul.Handrigan@cirrus.com>"); 124062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1241