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

source code of linux/sound/soc/codecs/pm4125-sdw.c