1*8ad52948SAlexey Klimov // SPDX-License-Identifier: GPL-2.0-only 2*8ad52948SAlexey Klimov // Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. 3*8ad52948SAlexey Klimov // Copyright, 2025 Linaro Ltd 4*8ad52948SAlexey Klimov 5*8ad52948SAlexey Klimov #include <linux/component.h> 6*8ad52948SAlexey Klimov #include <linux/device.h> 7*8ad52948SAlexey Klimov #include <linux/irq.h> 8*8ad52948SAlexey Klimov #include <linux/irqdomain.h> 9*8ad52948SAlexey Klimov #include <linux/kernel.h> 10*8ad52948SAlexey Klimov #include <linux/module.h> 11*8ad52948SAlexey Klimov #include <linux/of.h> 12*8ad52948SAlexey Klimov #include <linux/platform_device.h> 13*8ad52948SAlexey Klimov #include <linux/pm_runtime.h> 14*8ad52948SAlexey Klimov #include <linux/regmap.h> 15*8ad52948SAlexey Klimov #include <linux/slab.h> 16*8ad52948SAlexey Klimov #include <linux/soundwire/sdw.h> 17*8ad52948SAlexey Klimov #include <linux/soundwire/sdw_registers.h> 18*8ad52948SAlexey Klimov #include <linux/soundwire/sdw_type.h> 19*8ad52948SAlexey Klimov #include <sound/soc-dapm.h> 20*8ad52948SAlexey Klimov #include <sound/soc.h> 21*8ad52948SAlexey Klimov #include "pm4125.h" 22*8ad52948SAlexey Klimov 23*8ad52948SAlexey Klimov static struct pm4125_sdw_ch_info pm4125_sdw_rx_ch_info[] = { 24*8ad52948SAlexey Klimov WCD_SDW_CH(PM4125_HPH_L, PM4125_HPH_PORT, BIT(0)), 25*8ad52948SAlexey Klimov WCD_SDW_CH(PM4125_HPH_R, PM4125_HPH_PORT, BIT(1)), 26*8ad52948SAlexey Klimov }; 27*8ad52948SAlexey Klimov 28*8ad52948SAlexey Klimov static struct pm4125_sdw_ch_info pm4125_sdw_tx_ch_info[] = { 29*8ad52948SAlexey Klimov WCD_SDW_CH(PM4125_ADC1, PM4125_ADC_1_2_DMIC1L_BCS_PORT, BIT(0)), 30*8ad52948SAlexey Klimov WCD_SDW_CH(PM4125_ADC2, PM4125_ADC_1_2_DMIC1L_BCS_PORT, BIT(1)), 31*8ad52948SAlexey Klimov }; 32*8ad52948SAlexey Klimov 33*8ad52948SAlexey Klimov static struct sdw_dpn_prop pm4125_dpn_prop[PM4125_MAX_SWR_PORTS] = { 34*8ad52948SAlexey Klimov { 35*8ad52948SAlexey Klimov .num = 1, 36*8ad52948SAlexey Klimov .type = SDW_DPN_SIMPLE, 37*8ad52948SAlexey Klimov .min_ch = 1, 38*8ad52948SAlexey Klimov .max_ch = 8, 39*8ad52948SAlexey Klimov .simple_ch_prep_sm = true, 40*8ad52948SAlexey Klimov }, { 41*8ad52948SAlexey Klimov .num = 2, 42*8ad52948SAlexey Klimov .type = SDW_DPN_SIMPLE, 43*8ad52948SAlexey Klimov .min_ch = 1, 44*8ad52948SAlexey Klimov .max_ch = 4, 45*8ad52948SAlexey Klimov .simple_ch_prep_sm = true, 46*8ad52948SAlexey Klimov } 47*8ad52948SAlexey Klimov }; 48*8ad52948SAlexey Klimov 49*8ad52948SAlexey Klimov struct device *pm4125_sdw_device_get(struct device_node *np) 50*8ad52948SAlexey Klimov { 51*8ad52948SAlexey Klimov return bus_find_device_by_of_node(&sdw_bus_type, np); 52*8ad52948SAlexey Klimov } 53*8ad52948SAlexey Klimov EXPORT_SYMBOL_GPL(pm4125_sdw_device_get); 54*8ad52948SAlexey Klimov 55*8ad52948SAlexey Klimov int pm4125_sdw_hw_params(struct pm4125_sdw_priv *priv, struct snd_pcm_substream *substream, 56*8ad52948SAlexey Klimov struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) 57*8ad52948SAlexey Klimov { 58*8ad52948SAlexey Klimov struct sdw_port_config port_config[PM4125_MAX_SWR_PORTS]; 59*8ad52948SAlexey Klimov unsigned long ch_mask; 60*8ad52948SAlexey Klimov int i, j; 61*8ad52948SAlexey Klimov 62*8ad52948SAlexey Klimov priv->sconfig.ch_count = 1; 63*8ad52948SAlexey Klimov priv->active_ports = 0; 64*8ad52948SAlexey Klimov for (i = 0; i < PM4125_MAX_SWR_PORTS; i++) { 65*8ad52948SAlexey Klimov ch_mask = priv->port_config[i].ch_mask; 66*8ad52948SAlexey Klimov if (!ch_mask) 67*8ad52948SAlexey Klimov continue; 68*8ad52948SAlexey Klimov 69*8ad52948SAlexey Klimov for_each_set_bit(j, &ch_mask, 4) 70*8ad52948SAlexey Klimov priv->sconfig.ch_count++; 71*8ad52948SAlexey Klimov 72*8ad52948SAlexey Klimov port_config[priv->active_ports] = priv->port_config[i]; 73*8ad52948SAlexey Klimov priv->active_ports++; 74*8ad52948SAlexey Klimov } 75*8ad52948SAlexey Klimov 76*8ad52948SAlexey Klimov priv->sconfig.bps = 1; 77*8ad52948SAlexey Klimov priv->sconfig.frame_rate = params_rate(params); 78*8ad52948SAlexey Klimov priv->sconfig.direction = priv->is_tx ? SDW_DATA_DIR_TX : SDW_DATA_DIR_RX; 79*8ad52948SAlexey Klimov priv->sconfig.type = SDW_STREAM_PCM; 80*8ad52948SAlexey Klimov 81*8ad52948SAlexey Klimov return sdw_stream_add_slave(priv->sdev, &priv->sconfig, &port_config[0], priv->active_ports, 82*8ad52948SAlexey Klimov priv->sruntime); 83*8ad52948SAlexey Klimov } 84*8ad52948SAlexey Klimov EXPORT_SYMBOL_GPL(pm4125_sdw_hw_params); 85*8ad52948SAlexey Klimov 86*8ad52948SAlexey Klimov static int pm4125_update_status(struct sdw_slave *slave, enum sdw_slave_status status) 87*8ad52948SAlexey Klimov { 88*8ad52948SAlexey Klimov struct pm4125_sdw_priv *priv = dev_get_drvdata(&slave->dev); 89*8ad52948SAlexey Klimov 90*8ad52948SAlexey Klimov if (priv->regmap && status == SDW_SLAVE_ATTACHED) { 91*8ad52948SAlexey Klimov /* Write out any cached changes that happened between probe and attach */ 92*8ad52948SAlexey Klimov regcache_cache_only(priv->regmap, false); 93*8ad52948SAlexey Klimov return regcache_sync(priv->regmap); 94*8ad52948SAlexey Klimov } 95*8ad52948SAlexey Klimov 96*8ad52948SAlexey Klimov return 0; 97*8ad52948SAlexey Klimov } 98*8ad52948SAlexey Klimov 99*8ad52948SAlexey Klimov /* 100*8ad52948SAlexey Klimov * Handle Soundwire out-of-band interrupt event by triggering the first irq of the slave_irq 101*8ad52948SAlexey Klimov * irq domain, which then will be handled by the regmap_irq threaded irq. 102*8ad52948SAlexey Klimov * Looping is to ensure no interrupts were missed in the process. 103*8ad52948SAlexey Klimov */ 104*8ad52948SAlexey Klimov static int pm4125_interrupt_callback(struct sdw_slave *slave, struct sdw_slave_intr_status *status) 105*8ad52948SAlexey Klimov { 106*8ad52948SAlexey Klimov struct pm4125_sdw_priv *priv = dev_get_drvdata(&slave->dev); 107*8ad52948SAlexey Klimov struct irq_domain *slave_irq = priv->slave_irq; 108*8ad52948SAlexey Klimov u32 sts1, sts2, sts3; 109*8ad52948SAlexey Klimov 110*8ad52948SAlexey Klimov do { 111*8ad52948SAlexey Klimov handle_nested_irq(irq_find_mapping(slave_irq, 0)); 112*8ad52948SAlexey Klimov regmap_read(priv->regmap, PM4125_DIG_SWR_INTR_STATUS_0, &sts1); 113*8ad52948SAlexey Klimov regmap_read(priv->regmap, PM4125_DIG_SWR_INTR_STATUS_1, &sts2); 114*8ad52948SAlexey Klimov regmap_read(priv->regmap, PM4125_DIG_SWR_INTR_STATUS_2, &sts3); 115*8ad52948SAlexey Klimov 116*8ad52948SAlexey Klimov } while (sts1 || sts2 || sts3); 117*8ad52948SAlexey Klimov 118*8ad52948SAlexey Klimov return IRQ_HANDLED; 119*8ad52948SAlexey Klimov } 120*8ad52948SAlexey Klimov 121*8ad52948SAlexey Klimov static const struct reg_default pm4125_defaults[] = { 122*8ad52948SAlexey Klimov { PM4125_ANA_MICBIAS_MICB_1_2_EN, 0x01 }, 123*8ad52948SAlexey Klimov { PM4125_ANA_MICBIAS_MICB_3_EN, 0x00 }, 124*8ad52948SAlexey Klimov { PM4125_ANA_MICBIAS_LDO_1_SETTING, 0x21 }, 125*8ad52948SAlexey Klimov { PM4125_ANA_MICBIAS_LDO_1_CTRL, 0x01 }, 126*8ad52948SAlexey Klimov { PM4125_ANA_TX_AMIC1, 0x00 }, 127*8ad52948SAlexey Klimov { PM4125_ANA_TX_AMIC2, 0x00 }, 128*8ad52948SAlexey Klimov { PM4125_ANA_MBHC_MECH, 0x39 }, 129*8ad52948SAlexey Klimov { PM4125_ANA_MBHC_ELECT, 0x08 }, 130*8ad52948SAlexey Klimov { PM4125_ANA_MBHC_ZDET, 0x10 }, 131*8ad52948SAlexey Klimov { PM4125_ANA_MBHC_RESULT_1, 0x00 }, 132*8ad52948SAlexey Klimov { PM4125_ANA_MBHC_RESULT_2, 0x00 }, 133*8ad52948SAlexey Klimov { PM4125_ANA_MBHC_RESULT_3, 0x00 }, 134*8ad52948SAlexey Klimov { PM4125_ANA_MBHC_BTN0_ZDET_VREF1, 0x00 }, 135*8ad52948SAlexey Klimov { PM4125_ANA_MBHC_BTN1_ZDET_VREF2, 0x10 }, 136*8ad52948SAlexey Klimov { PM4125_ANA_MBHC_BTN2_ZDET_VREF3, 0x20 }, 137*8ad52948SAlexey Klimov { PM4125_ANA_MBHC_BTN3_ZDET_DBG_400, 0x30 }, 138*8ad52948SAlexey Klimov { PM4125_ANA_MBHC_BTN4_ZDET_DBG_1400, 0x40 }, 139*8ad52948SAlexey Klimov { PM4125_ANA_MBHC_MICB2_RAMP, 0x00 }, 140*8ad52948SAlexey Klimov { PM4125_ANA_MBHC_CTL_1, 0x02 }, 141*8ad52948SAlexey Klimov { PM4125_ANA_MBHC_CTL_2, 0x05 }, 142*8ad52948SAlexey Klimov { PM4125_ANA_MBHC_PLUG_DETECT_CTL, 0xE9 }, 143*8ad52948SAlexey Klimov { PM4125_ANA_MBHC_ZDET_ANA_CTL, 0x0F }, 144*8ad52948SAlexey Klimov { PM4125_ANA_MBHC_ZDET_RAMP_CTL, 0x00 }, 145*8ad52948SAlexey Klimov { PM4125_ANA_MBHC_FSM_STATUS, 0x00 }, 146*8ad52948SAlexey Klimov { PM4125_ANA_MBHC_ADC_RESULT, 0x00 }, 147*8ad52948SAlexey Klimov { PM4125_ANA_MBHC_CTL_CLK, 0x30 }, 148*8ad52948SAlexey Klimov { PM4125_ANA_MBHC_ZDET_CALIB_RESULT, 0x00 }, 149*8ad52948SAlexey Klimov { PM4125_ANA_NCP_EN, 0x00 }, 150*8ad52948SAlexey Klimov { PM4125_ANA_NCP_VCTRL, 0xA7 }, 151*8ad52948SAlexey Klimov { PM4125_ANA_HPHPA_CNP_CTL_1, 0x54 }, 152*8ad52948SAlexey Klimov { PM4125_ANA_HPHPA_CNP_CTL_2, 0x2B }, 153*8ad52948SAlexey Klimov { PM4125_ANA_HPHPA_PA_STATUS, 0x00 }, 154*8ad52948SAlexey Klimov { PM4125_ANA_HPHPA_FSM_CLK, 0x12 }, 155*8ad52948SAlexey Klimov { PM4125_ANA_HPHPA_L_GAIN, 0x00 }, 156*8ad52948SAlexey Klimov { PM4125_ANA_HPHPA_R_GAIN, 0x00 }, 157*8ad52948SAlexey Klimov { PM4125_SWR_HPHPA_HD2, 0x1B }, 158*8ad52948SAlexey Klimov { PM4125_ANA_HPHPA_SPARE_CTL, 0x02 }, 159*8ad52948SAlexey Klimov { PM4125_ANA_SURGE_EN, 0x38 }, 160*8ad52948SAlexey Klimov { PM4125_ANA_COMBOPA_CTL, 0x35 }, 161*8ad52948SAlexey Klimov { PM4125_ANA_COMBOPA_CTL_4, 0x84 }, 162*8ad52948SAlexey Klimov { PM4125_ANA_COMBOPA_CTL_5, 0x05 }, 163*8ad52948SAlexey Klimov { PM4125_ANA_RXLDO_CTL, 0x86 }, 164*8ad52948SAlexey Klimov { PM4125_ANA_MBIAS_EN, 0x00 }, 165*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CHIP_ID0, 0x00 }, 166*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CHIP_ID1, 0x00 }, 167*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CHIP_ID2, 0x0C }, 168*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CHIP_ID3, 0x01 }, 169*8ad52948SAlexey Klimov { PM4125_DIG_SWR_SWR_TX_CLK_RATE, 0x00 }, 170*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_RST_CTL, 0x03 }, 171*8ad52948SAlexey Klimov { PM4125_DIG_SWR_TOP_CLK_CFG, 0x00 }, 172*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_RX_CLK_CTL, 0x00 }, 173*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_TX_CLK_CTL, 0x33 }, 174*8ad52948SAlexey Klimov { PM4125_DIG_SWR_SWR_RST_EN, 0x00 }, 175*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_RX_RST, 0x00 }, 176*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_RX0_CTL, 0xFC }, 177*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_RX1_CTL, 0xFC }, 178*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_TX_ANA_MODE_0_1, 0x00 }, 179*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_COMP_CTL_0, 0x00 }, 180*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_RX_DELAY_CTL, 0x66 }, 181*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_RX_GAIN_0, 0x55 }, 182*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_RX_GAIN_1, 0xA9 }, 183*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_RX_GAIN_CTL, 0x00 }, 184*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_TX0_CTL, 0x68 }, 185*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_TX1_CTL, 0x68 }, 186*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_TX_RST, 0x00 }, 187*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_REQ0_CTL, 0x01 }, 188*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_REQ1_CTL, 0x01 }, 189*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_RST, 0x00 }, 190*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_AMIC_CTL, 0x02 }, 191*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_DMIC_CTL, 0x00 }, 192*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_DMIC1_CTL, 0x00 }, 193*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_DMIC1_RATE, 0x01 }, 194*8ad52948SAlexey Klimov { PM4125_DIG_SWR_PDM_WD_CTL0, 0x00 }, 195*8ad52948SAlexey Klimov { PM4125_DIG_SWR_PDM_WD_CTL1, 0x00 }, 196*8ad52948SAlexey Klimov { PM4125_DIG_SWR_INTR_MODE, 0x00 }, 197*8ad52948SAlexey Klimov { PM4125_DIG_SWR_INTR_MASK_0, 0xFF }, 198*8ad52948SAlexey Klimov { PM4125_DIG_SWR_INTR_MASK_1, 0x7F }, 199*8ad52948SAlexey Klimov { PM4125_DIG_SWR_INTR_MASK_2, 0x0C }, 200*8ad52948SAlexey Klimov { PM4125_DIG_SWR_INTR_STATUS_0, 0x00 }, 201*8ad52948SAlexey Klimov { PM4125_DIG_SWR_INTR_STATUS_1, 0x00 }, 202*8ad52948SAlexey Klimov { PM4125_DIG_SWR_INTR_STATUS_2, 0x00 }, 203*8ad52948SAlexey Klimov { PM4125_DIG_SWR_INTR_CLEAR_0, 0x00 }, 204*8ad52948SAlexey Klimov { PM4125_DIG_SWR_INTR_CLEAR_1, 0x00 }, 205*8ad52948SAlexey Klimov { PM4125_DIG_SWR_INTR_CLEAR_2, 0x00 }, 206*8ad52948SAlexey Klimov { PM4125_DIG_SWR_INTR_LEVEL_0, 0x00 }, 207*8ad52948SAlexey Klimov { PM4125_DIG_SWR_INTR_LEVEL_1, 0x2A }, 208*8ad52948SAlexey Klimov { PM4125_DIG_SWR_INTR_LEVEL_2, 0x00 }, 209*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_CONN_RX0_CTL, 0x00 }, 210*8ad52948SAlexey Klimov { PM4125_DIG_SWR_CDC_CONN_RX1_CTL, 0x00 }, 211*8ad52948SAlexey Klimov { PM4125_DIG_SWR_LOOP_BACK_MODE, 0x00 }, 212*8ad52948SAlexey Klimov { PM4125_DIG_SWR_DRIVE_STRENGTH_0, 0x00 }, 213*8ad52948SAlexey Klimov { PM4125_DIG_SWR_DIG_DEBUG_CTL, 0x00 }, 214*8ad52948SAlexey Klimov { PM4125_DIG_SWR_DIG_DEBUG_EN, 0x00 }, 215*8ad52948SAlexey Klimov { PM4125_DIG_SWR_DEM_BYPASS_DATA0, 0x55 }, 216*8ad52948SAlexey Klimov { PM4125_DIG_SWR_DEM_BYPASS_DATA1, 0x55 }, 217*8ad52948SAlexey Klimov { PM4125_DIG_SWR_DEM_BYPASS_DATA2, 0x55 }, 218*8ad52948SAlexey Klimov { PM4125_DIG_SWR_DEM_BYPASS_DATA3, 0x01 }, 219*8ad52948SAlexey Klimov }; 220*8ad52948SAlexey Klimov 221*8ad52948SAlexey Klimov static bool pm4125_rdwr_register(struct device *dev, unsigned int reg) 222*8ad52948SAlexey Klimov { 223*8ad52948SAlexey Klimov switch (reg) { 224*8ad52948SAlexey Klimov case PM4125_ANA_MICBIAS_MICB_1_2_EN: 225*8ad52948SAlexey Klimov case PM4125_ANA_MICBIAS_MICB_3_EN: 226*8ad52948SAlexey Klimov case PM4125_ANA_MICBIAS_LDO_1_SETTING: 227*8ad52948SAlexey Klimov case PM4125_ANA_MICBIAS_LDO_1_CTRL: 228*8ad52948SAlexey Klimov case PM4125_ANA_TX_AMIC1: 229*8ad52948SAlexey Klimov case PM4125_ANA_TX_AMIC2: 230*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_MECH: 231*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_ELECT: 232*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_ZDET: 233*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_BTN0_ZDET_VREF1: 234*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_BTN1_ZDET_VREF2: 235*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_BTN2_ZDET_VREF3: 236*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_BTN3_ZDET_DBG_400: 237*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_BTN4_ZDET_DBG_1400: 238*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_MICB2_RAMP: 239*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_CTL_1: 240*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_CTL_2: 241*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_PLUG_DETECT_CTL: 242*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_ZDET_ANA_CTL: 243*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_ZDET_RAMP_CTL: 244*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_CTL_CLK: 245*8ad52948SAlexey Klimov case PM4125_ANA_NCP_EN: 246*8ad52948SAlexey Klimov case PM4125_ANA_NCP_VCTRL: 247*8ad52948SAlexey Klimov case PM4125_ANA_HPHPA_CNP_CTL_1: 248*8ad52948SAlexey Klimov case PM4125_ANA_HPHPA_CNP_CTL_2: 249*8ad52948SAlexey Klimov case PM4125_ANA_HPHPA_FSM_CLK: 250*8ad52948SAlexey Klimov case PM4125_ANA_HPHPA_L_GAIN: 251*8ad52948SAlexey Klimov case PM4125_ANA_HPHPA_R_GAIN: 252*8ad52948SAlexey Klimov case PM4125_ANA_HPHPA_SPARE_CTL: 253*8ad52948SAlexey Klimov case PM4125_SWR_HPHPA_HD2: 254*8ad52948SAlexey Klimov case PM4125_ANA_SURGE_EN: 255*8ad52948SAlexey Klimov case PM4125_ANA_COMBOPA_CTL: 256*8ad52948SAlexey Klimov case PM4125_ANA_COMBOPA_CTL_4: 257*8ad52948SAlexey Klimov case PM4125_ANA_COMBOPA_CTL_5: 258*8ad52948SAlexey Klimov case PM4125_ANA_RXLDO_CTL: 259*8ad52948SAlexey Klimov case PM4125_ANA_MBIAS_EN: 260*8ad52948SAlexey Klimov case PM4125_DIG_SWR_SWR_TX_CLK_RATE: 261*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_RST_CTL: 262*8ad52948SAlexey Klimov case PM4125_DIG_SWR_TOP_CLK_CFG: 263*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_RX_CLK_CTL: 264*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_TX_CLK_CTL: 265*8ad52948SAlexey Klimov case PM4125_DIG_SWR_SWR_RST_EN: 266*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_RX_RST: 267*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_RX0_CTL: 268*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_RX1_CTL: 269*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_TX_ANA_MODE_0_1: 270*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_COMP_CTL_0: 271*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_RX_DELAY_CTL: 272*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_RX_GAIN_0: 273*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_RX_GAIN_1: 274*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_RX_GAIN_CTL: 275*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_TX0_CTL: 276*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_TX1_CTL: 277*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_TX_RST: 278*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_REQ0_CTL: 279*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_REQ1_CTL: 280*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_RST: 281*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_AMIC_CTL: 282*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_DMIC_CTL: 283*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_DMIC1_CTL: 284*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_DMIC1_RATE: 285*8ad52948SAlexey Klimov case PM4125_DIG_SWR_PDM_WD_CTL0: 286*8ad52948SAlexey Klimov case PM4125_DIG_SWR_PDM_WD_CTL1: 287*8ad52948SAlexey Klimov case PM4125_DIG_SWR_INTR_MODE: 288*8ad52948SAlexey Klimov case PM4125_DIG_SWR_INTR_MASK_0: 289*8ad52948SAlexey Klimov case PM4125_DIG_SWR_INTR_MASK_1: 290*8ad52948SAlexey Klimov case PM4125_DIG_SWR_INTR_MASK_2: 291*8ad52948SAlexey Klimov case PM4125_DIG_SWR_INTR_CLEAR_0: 292*8ad52948SAlexey Klimov case PM4125_DIG_SWR_INTR_CLEAR_1: 293*8ad52948SAlexey Klimov case PM4125_DIG_SWR_INTR_CLEAR_2: 294*8ad52948SAlexey Klimov case PM4125_DIG_SWR_INTR_LEVEL_0: 295*8ad52948SAlexey Klimov case PM4125_DIG_SWR_INTR_LEVEL_1: 296*8ad52948SAlexey Klimov case PM4125_DIG_SWR_INTR_LEVEL_2: 297*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_CONN_RX0_CTL: 298*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CDC_CONN_RX1_CTL: 299*8ad52948SAlexey Klimov case PM4125_DIG_SWR_LOOP_BACK_MODE: 300*8ad52948SAlexey Klimov case PM4125_DIG_SWR_DRIVE_STRENGTH_0: 301*8ad52948SAlexey Klimov case PM4125_DIG_SWR_DIG_DEBUG_CTL: 302*8ad52948SAlexey Klimov case PM4125_DIG_SWR_DIG_DEBUG_EN: 303*8ad52948SAlexey Klimov case PM4125_DIG_SWR_DEM_BYPASS_DATA0: 304*8ad52948SAlexey Klimov case PM4125_DIG_SWR_DEM_BYPASS_DATA1: 305*8ad52948SAlexey Klimov case PM4125_DIG_SWR_DEM_BYPASS_DATA2: 306*8ad52948SAlexey Klimov case PM4125_DIG_SWR_DEM_BYPASS_DATA3: 307*8ad52948SAlexey Klimov return true; 308*8ad52948SAlexey Klimov } 309*8ad52948SAlexey Klimov 310*8ad52948SAlexey Klimov return false; 311*8ad52948SAlexey Klimov } 312*8ad52948SAlexey Klimov 313*8ad52948SAlexey Klimov static bool pm4125_readable_register(struct device *dev, unsigned int reg) 314*8ad52948SAlexey Klimov { 315*8ad52948SAlexey Klimov switch (reg) { 316*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_RESULT_1: 317*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_RESULT_2: 318*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_RESULT_3: 319*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_FSM_STATUS: 320*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_ADC_RESULT: 321*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_ZDET_CALIB_RESULT: 322*8ad52948SAlexey Klimov case PM4125_ANA_HPHPA_PA_STATUS: 323*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CHIP_ID0: 324*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CHIP_ID1: 325*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CHIP_ID2: 326*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CHIP_ID3: 327*8ad52948SAlexey Klimov case PM4125_DIG_SWR_INTR_STATUS_0: 328*8ad52948SAlexey Klimov case PM4125_DIG_SWR_INTR_STATUS_1: 329*8ad52948SAlexey Klimov case PM4125_DIG_SWR_INTR_STATUS_2: 330*8ad52948SAlexey Klimov return true; 331*8ad52948SAlexey Klimov } 332*8ad52948SAlexey Klimov return pm4125_rdwr_register(dev, reg); 333*8ad52948SAlexey Klimov } 334*8ad52948SAlexey Klimov 335*8ad52948SAlexey Klimov static bool pm4125_volatile_register(struct device *dev, unsigned int reg) 336*8ad52948SAlexey Klimov { 337*8ad52948SAlexey Klimov switch (reg) { 338*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_RESULT_1: 339*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_RESULT_2: 340*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_RESULT_3: 341*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_FSM_STATUS: 342*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_ADC_RESULT: 343*8ad52948SAlexey Klimov case PM4125_ANA_MBHC_ZDET_CALIB_RESULT: 344*8ad52948SAlexey Klimov case PM4125_ANA_HPHPA_PA_STATUS: 345*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CHIP_ID0: 346*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CHIP_ID1: 347*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CHIP_ID2: 348*8ad52948SAlexey Klimov case PM4125_DIG_SWR_CHIP_ID3: 349*8ad52948SAlexey Klimov case PM4125_DIG_SWR_INTR_STATUS_0: 350*8ad52948SAlexey Klimov case PM4125_DIG_SWR_INTR_STATUS_1: 351*8ad52948SAlexey Klimov case PM4125_DIG_SWR_INTR_STATUS_2: 352*8ad52948SAlexey Klimov return true; 353*8ad52948SAlexey Klimov } 354*8ad52948SAlexey Klimov 355*8ad52948SAlexey Klimov return false; 356*8ad52948SAlexey Klimov } 357*8ad52948SAlexey Klimov 358*8ad52948SAlexey Klimov static const struct regmap_config pm4125_regmap_config = { 359*8ad52948SAlexey Klimov .name = "pm4125_csr", 360*8ad52948SAlexey Klimov .reg_bits = 32, 361*8ad52948SAlexey Klimov .val_bits = 8, 362*8ad52948SAlexey Klimov .cache_type = REGCACHE_MAPLE, 363*8ad52948SAlexey Klimov .reg_defaults = pm4125_defaults, 364*8ad52948SAlexey Klimov .num_reg_defaults = ARRAY_SIZE(pm4125_defaults), 365*8ad52948SAlexey Klimov .max_register = PM4125_MAX_REGISTER, 366*8ad52948SAlexey Klimov .readable_reg = pm4125_readable_register, 367*8ad52948SAlexey Klimov .writeable_reg = pm4125_rdwr_register, 368*8ad52948SAlexey Klimov .volatile_reg = pm4125_volatile_register, 369*8ad52948SAlexey Klimov }; 370*8ad52948SAlexey Klimov 371*8ad52948SAlexey Klimov static const struct sdw_slave_ops pm4125_slave_ops = { 372*8ad52948SAlexey Klimov .update_status = pm4125_update_status, 373*8ad52948SAlexey Klimov .interrupt_callback = pm4125_interrupt_callback, 374*8ad52948SAlexey Klimov }; 375*8ad52948SAlexey Klimov 376*8ad52948SAlexey Klimov static int pm4125_sdw_component_bind(struct device *dev, struct device *master, void *data) 377*8ad52948SAlexey Klimov { 378*8ad52948SAlexey Klimov pm_runtime_set_autosuspend_delay(dev, 3000); 379*8ad52948SAlexey Klimov pm_runtime_use_autosuspend(dev); 380*8ad52948SAlexey Klimov pm_runtime_set_active(dev); 381*8ad52948SAlexey Klimov pm_runtime_enable(dev); 382*8ad52948SAlexey Klimov 383*8ad52948SAlexey Klimov return 0; 384*8ad52948SAlexey Klimov } 385*8ad52948SAlexey Klimov 386*8ad52948SAlexey Klimov static void pm4125_sdw_component_unbind(struct device *dev, struct device *master, void *data) 387*8ad52948SAlexey Klimov { 388*8ad52948SAlexey Klimov pm_runtime_disable(dev); 389*8ad52948SAlexey Klimov pm_runtime_set_suspended(dev); 390*8ad52948SAlexey Klimov pm_runtime_dont_use_autosuspend(dev); 391*8ad52948SAlexey Klimov } 392*8ad52948SAlexey Klimov 393*8ad52948SAlexey Klimov static const struct component_ops pm4125_sdw_component_ops = { 394*8ad52948SAlexey Klimov .bind = pm4125_sdw_component_bind, 395*8ad52948SAlexey Klimov .unbind = pm4125_sdw_component_unbind, 396*8ad52948SAlexey Klimov }; 397*8ad52948SAlexey Klimov 398*8ad52948SAlexey Klimov static int pm4125_probe(struct sdw_slave *pdev, const struct sdw_device_id *id) 399*8ad52948SAlexey Klimov { 400*8ad52948SAlexey Klimov struct device *dev = &pdev->dev; 401*8ad52948SAlexey Klimov struct pm4125_sdw_priv *priv; 402*8ad52948SAlexey Klimov u8 master_ch_mask[PM4125_MAX_SWR_CH_IDS]; 403*8ad52948SAlexey Klimov int master_ch_mask_size = 0; 404*8ad52948SAlexey Klimov int ret, i; 405*8ad52948SAlexey Klimov 406*8ad52948SAlexey Klimov priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 407*8ad52948SAlexey Klimov if (!priv) 408*8ad52948SAlexey Klimov return -ENOMEM; 409*8ad52948SAlexey Klimov 410*8ad52948SAlexey Klimov /* Port map index starts at 0, however the data port for this codec starts at index 1 */ 411*8ad52948SAlexey Klimov if (of_property_present(dev->of_node, "qcom,tx-port-mapping")) { 412*8ad52948SAlexey Klimov priv->is_tx = true; 413*8ad52948SAlexey Klimov ret = of_property_read_u32_array(dev->of_node, "qcom,tx-port-mapping", 414*8ad52948SAlexey Klimov &pdev->m_port_map[1], PM4125_MAX_TX_SWR_PORTS); 415*8ad52948SAlexey Klimov } else { 416*8ad52948SAlexey Klimov ret = of_property_read_u32_array(dev->of_node, "qcom,rx-port-mapping", 417*8ad52948SAlexey Klimov &pdev->m_port_map[1], PM4125_MAX_SWR_PORTS); 418*8ad52948SAlexey Klimov } 419*8ad52948SAlexey Klimov 420*8ad52948SAlexey Klimov if (ret < 0) 421*8ad52948SAlexey Klimov dev_info(dev, "Error getting static port mapping for %s (%d)\n", 422*8ad52948SAlexey Klimov priv->is_tx ? "TX" : "RX", ret); 423*8ad52948SAlexey Klimov 424*8ad52948SAlexey Klimov priv->sdev = pdev; 425*8ad52948SAlexey Klimov dev_set_drvdata(dev, priv); 426*8ad52948SAlexey Klimov 427*8ad52948SAlexey Klimov pdev->prop.scp_int1_mask = SDW_SCP_INT1_IMPL_DEF | 428*8ad52948SAlexey Klimov SDW_SCP_INT1_BUS_CLASH | 429*8ad52948SAlexey Klimov SDW_SCP_INT1_PARITY; 430*8ad52948SAlexey Klimov pdev->prop.lane_control_support = true; 431*8ad52948SAlexey Klimov pdev->prop.simple_clk_stop_capable = true; 432*8ad52948SAlexey Klimov 433*8ad52948SAlexey Klimov memset(master_ch_mask, 0, PM4125_MAX_SWR_CH_IDS); 434*8ad52948SAlexey Klimov 435*8ad52948SAlexey Klimov if (priv->is_tx) { 436*8ad52948SAlexey Klimov master_ch_mask_size = of_property_count_u8_elems(dev->of_node, 437*8ad52948SAlexey Klimov "qcom,tx-channel-mapping"); 438*8ad52948SAlexey Klimov 439*8ad52948SAlexey Klimov if (master_ch_mask_size) 440*8ad52948SAlexey Klimov ret = of_property_read_u8_array(dev->of_node, "qcom,tx-channel-mapping", 441*8ad52948SAlexey Klimov master_ch_mask, master_ch_mask_size); 442*8ad52948SAlexey Klimov } else { 443*8ad52948SAlexey Klimov master_ch_mask_size = of_property_count_u8_elems(dev->of_node, 444*8ad52948SAlexey Klimov "qcom,rx-channel-mapping"); 445*8ad52948SAlexey Klimov 446*8ad52948SAlexey Klimov if (master_ch_mask_size) 447*8ad52948SAlexey Klimov ret = of_property_read_u8_array(dev->of_node, "qcom,rx-channel-mapping", 448*8ad52948SAlexey Klimov master_ch_mask, master_ch_mask_size); 449*8ad52948SAlexey Klimov } 450*8ad52948SAlexey Klimov 451*8ad52948SAlexey Klimov if (ret < 0) 452*8ad52948SAlexey Klimov dev_info(dev, "Static channel mapping not specified using device channel maps\n"); 453*8ad52948SAlexey Klimov 454*8ad52948SAlexey Klimov if (priv->is_tx) { 455*8ad52948SAlexey Klimov pdev->prop.source_ports = GENMASK(PM4125_MAX_TX_SWR_PORTS, 0); 456*8ad52948SAlexey Klimov pdev->prop.src_dpn_prop = pm4125_dpn_prop; 457*8ad52948SAlexey Klimov priv->ch_info = &pm4125_sdw_tx_ch_info[0]; 458*8ad52948SAlexey Klimov 459*8ad52948SAlexey Klimov for (i = 0; i < master_ch_mask_size; i++) 460*8ad52948SAlexey Klimov priv->ch_info[i].master_ch_mask = PM4125_SWRM_CH_MASK(master_ch_mask[i]); 461*8ad52948SAlexey Klimov 462*8ad52948SAlexey Klimov pdev->prop.wake_capable = true; 463*8ad52948SAlexey Klimov 464*8ad52948SAlexey Klimov priv->regmap = devm_regmap_init_sdw(pdev, &pm4125_regmap_config); 465*8ad52948SAlexey Klimov if (IS_ERR(priv->regmap)) 466*8ad52948SAlexey Klimov return dev_err_probe(dev, PTR_ERR(priv->regmap), "regmap init failed\n"); 467*8ad52948SAlexey Klimov 468*8ad52948SAlexey Klimov /* Start in cache-only until device is enumerated */ 469*8ad52948SAlexey Klimov regcache_cache_only(priv->regmap, true); 470*8ad52948SAlexey Klimov } else { 471*8ad52948SAlexey Klimov pdev->prop.sink_ports = GENMASK(PM4125_MAX_SWR_PORTS - 1, 0); 472*8ad52948SAlexey Klimov pdev->prop.sink_dpn_prop = pm4125_dpn_prop; 473*8ad52948SAlexey Klimov priv->ch_info = &pm4125_sdw_rx_ch_info[0]; 474*8ad52948SAlexey Klimov 475*8ad52948SAlexey Klimov for (i = 0; i < master_ch_mask_size; i++) 476*8ad52948SAlexey Klimov priv->ch_info[i].master_ch_mask = PM4125_SWRM_CH_MASK(master_ch_mask[i]); 477*8ad52948SAlexey Klimov } 478*8ad52948SAlexey Klimov 479*8ad52948SAlexey Klimov ret = component_add(dev, &pm4125_sdw_component_ops); 480*8ad52948SAlexey Klimov if (ret) 481*8ad52948SAlexey Klimov return ret; 482*8ad52948SAlexey Klimov 483*8ad52948SAlexey Klimov /* Set suspended until aggregate device is bind */ 484*8ad52948SAlexey Klimov pm_runtime_set_suspended(dev); 485*8ad52948SAlexey Klimov 486*8ad52948SAlexey Klimov return 0; 487*8ad52948SAlexey Klimov } 488*8ad52948SAlexey Klimov 489*8ad52948SAlexey Klimov static int pm4125_remove(struct sdw_slave *pdev) 490*8ad52948SAlexey Klimov { 491*8ad52948SAlexey Klimov struct device *dev = &pdev->dev; 492*8ad52948SAlexey Klimov 493*8ad52948SAlexey Klimov component_del(dev, &pm4125_sdw_component_ops); 494*8ad52948SAlexey Klimov 495*8ad52948SAlexey Klimov return 0; 496*8ad52948SAlexey Klimov } 497*8ad52948SAlexey Klimov 498*8ad52948SAlexey Klimov static const struct sdw_device_id pm4125_slave_id[] = { 499*8ad52948SAlexey Klimov SDW_SLAVE_ENTRY(0x0217, 0x10c, 0), /* Soundwire pm4125 RX/TX Device ID */ 500*8ad52948SAlexey Klimov { } 501*8ad52948SAlexey Klimov }; 502*8ad52948SAlexey Klimov MODULE_DEVICE_TABLE(sdw, pm4125_slave_id); 503*8ad52948SAlexey Klimov 504*8ad52948SAlexey Klimov static int __maybe_unused pm4125_sdw_runtime_suspend(struct device *dev) 505*8ad52948SAlexey Klimov { 506*8ad52948SAlexey Klimov struct pm4125_sdw_priv *priv = dev_get_drvdata(dev); 507*8ad52948SAlexey Klimov 508*8ad52948SAlexey Klimov if (priv->regmap) { 509*8ad52948SAlexey Klimov regcache_cache_only(priv->regmap, true); 510*8ad52948SAlexey Klimov regcache_mark_dirty(priv->regmap); 511*8ad52948SAlexey Klimov } 512*8ad52948SAlexey Klimov 513*8ad52948SAlexey Klimov return 0; 514*8ad52948SAlexey Klimov } 515*8ad52948SAlexey Klimov 516*8ad52948SAlexey Klimov static int __maybe_unused pm4125_sdw_runtime_resume(struct device *dev) 517*8ad52948SAlexey Klimov { 518*8ad52948SAlexey Klimov struct pm4125_sdw_priv *priv = dev_get_drvdata(dev); 519*8ad52948SAlexey Klimov 520*8ad52948SAlexey Klimov if (priv->regmap) { 521*8ad52948SAlexey Klimov regcache_cache_only(priv->regmap, false); 522*8ad52948SAlexey Klimov regcache_sync(priv->regmap); 523*8ad52948SAlexey Klimov } 524*8ad52948SAlexey Klimov 525*8ad52948SAlexey Klimov return 0; 526*8ad52948SAlexey Klimov } 527*8ad52948SAlexey Klimov 528*8ad52948SAlexey Klimov static const struct dev_pm_ops pm4125_sdw_pm_ops = { 529*8ad52948SAlexey Klimov SET_RUNTIME_PM_OPS(pm4125_sdw_runtime_suspend, pm4125_sdw_runtime_resume, NULL) 530*8ad52948SAlexey Klimov }; 531*8ad52948SAlexey Klimov 532*8ad52948SAlexey Klimov static struct sdw_driver pm4125_codec_driver = { 533*8ad52948SAlexey Klimov .probe = pm4125_probe, 534*8ad52948SAlexey Klimov .remove = pm4125_remove, 535*8ad52948SAlexey Klimov .ops = &pm4125_slave_ops, 536*8ad52948SAlexey Klimov .id_table = pm4125_slave_id, 537*8ad52948SAlexey Klimov .driver = { 538*8ad52948SAlexey Klimov .name = "pm4125-codec", 539*8ad52948SAlexey Klimov .pm = &pm4125_sdw_pm_ops, 540*8ad52948SAlexey Klimov } 541*8ad52948SAlexey Klimov }; 542*8ad52948SAlexey Klimov module_sdw_driver(pm4125_codec_driver); 543*8ad52948SAlexey Klimov 544*8ad52948SAlexey Klimov MODULE_DESCRIPTION("PM4125 SDW codec driver"); 545*8ad52948SAlexey Klimov MODULE_LICENSE("GPL"); 546