1
2
3
4#include <linux/module.h>
5#include <linux/slab.h>
6#include <linux/platform_device.h>
7#include <linux/device.h>
8#include <linux/kernel.h>
9#include <linux/component.h>
10#include <linux/pm_runtime.h>
11#include <linux/irq.h>
12#include <linux/irqdomain.h>
13#include <linux/of.h>
14#include <linux/soundwire/sdw.h>
15#include <linux/soundwire/sdw_type.h>
16#include <linux/soundwire/sdw_registers.h>
17#include <linux/regmap.h>
18#include <sound/soc.h>
19#include <sound/soc-dapm.h>
20#include "wcd938x.h"
21
22#define SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(m) (0xE0 + 0x10 * (m))
23
24static struct wcd938x_sdw_ch_info wcd938x_sdw_rx_ch_info[] = {
25 WCD_SDW_CH(WCD938X_HPH_L, WCD938X_HPH_PORT, BIT(0)),
26 WCD_SDW_CH(WCD938X_HPH_R, WCD938X_HPH_PORT, BIT(1)),
27 WCD_SDW_CH(WCD938X_CLSH, WCD938X_CLSH_PORT, BIT(0)),
28 WCD_SDW_CH(WCD938X_COMP_L, WCD938X_COMP_PORT, BIT(0)),
29 WCD_SDW_CH(WCD938X_COMP_R, WCD938X_COMP_PORT, BIT(1)),
30 WCD_SDW_CH(WCD938X_LO, WCD938X_LO_PORT, BIT(0)),
31 WCD_SDW_CH(WCD938X_DSD_L, WCD938X_DSD_PORT, BIT(0)),
32 WCD_SDW_CH(WCD938X_DSD_R, WCD938X_DSD_PORT, BIT(1)),
33};
34
35static struct wcd938x_sdw_ch_info wcd938x_sdw_tx_ch_info[] = {
36 WCD_SDW_CH(WCD938X_ADC1, WCD938X_ADC_1_2_PORT, BIT(0)),
37 WCD_SDW_CH(WCD938X_ADC2, WCD938X_ADC_1_2_PORT, BIT(1)),
38 WCD_SDW_CH(WCD938X_ADC3, WCD938X_ADC_3_4_PORT, BIT(0)),
39 WCD_SDW_CH(WCD938X_ADC4, WCD938X_ADC_3_4_PORT, BIT(1)),
40 WCD_SDW_CH(WCD938X_DMIC0, WCD938X_DMIC_0_3_MBHC_PORT, BIT(0)),
41 WCD_SDW_CH(WCD938X_DMIC1, WCD938X_DMIC_0_3_MBHC_PORT, BIT(1)),
42 WCD_SDW_CH(WCD938X_MBHC, WCD938X_DMIC_0_3_MBHC_PORT, BIT(2)),
43 WCD_SDW_CH(WCD938X_DMIC2, WCD938X_DMIC_0_3_MBHC_PORT, BIT(2)),
44 WCD_SDW_CH(WCD938X_DMIC3, WCD938X_DMIC_0_3_MBHC_PORT, BIT(3)),
45 WCD_SDW_CH(WCD938X_DMIC4, WCD938X_DMIC_4_7_PORT, BIT(0)),
46 WCD_SDW_CH(WCD938X_DMIC5, WCD938X_DMIC_4_7_PORT, BIT(1)),
47 WCD_SDW_CH(WCD938X_DMIC6, WCD938X_DMIC_4_7_PORT, BIT(2)),
48 WCD_SDW_CH(WCD938X_DMIC7, WCD938X_DMIC_4_7_PORT, BIT(3)),
49};
50
51static struct sdw_dpn_prop wcd938x_dpn_prop[WCD938X_MAX_SWR_PORTS] = {
52 {
53 .num = 1,
54 .type = SDW_DPN_SIMPLE,
55 .min_ch = 1,
56 .max_ch = 8,
57 .simple_ch_prep_sm = true,
58 }, {
59 .num = 2,
60 .type = SDW_DPN_SIMPLE,
61 .min_ch = 1,
62 .max_ch = 4,
63 .simple_ch_prep_sm = true,
64 }, {
65 .num = 3,
66 .type = SDW_DPN_SIMPLE,
67 .min_ch = 1,
68 .max_ch = 4,
69 .simple_ch_prep_sm = true,
70 }, {
71 .num = 4,
72 .type = SDW_DPN_SIMPLE,
73 .min_ch = 1,
74 .max_ch = 4,
75 .simple_ch_prep_sm = true,
76 }, {
77 .num = 5,
78 .type = SDW_DPN_SIMPLE,
79 .min_ch = 1,
80 .max_ch = 4,
81 .simple_ch_prep_sm = true,
82 }
83};
84
85struct device *wcd938x_sdw_device_get(struct device_node *np)
86{
87 return bus_find_device_by_of_node(&sdw_bus_type, np);
88
89}
90EXPORT_SYMBOL_GPL(wcd938x_sdw_device_get);
91
92int wcd938x_swr_get_current_bank(struct sdw_slave *sdev)
93{
94 int bank;
95
96 bank = sdw_read(sdev, SDW_SCP_CTRL);
97
98 return ((bank & 0x40) ? 1 : 0);
99}
100EXPORT_SYMBOL_GPL(wcd938x_swr_get_current_bank);
101
102int wcd938x_sdw_hw_params(struct wcd938x_sdw_priv *wcd,
103 struct snd_pcm_substream *substream,
104 struct snd_pcm_hw_params *params,
105 struct snd_soc_dai *dai)
106{
107 struct sdw_port_config port_config[WCD938X_MAX_SWR_PORTS];
108 unsigned long ch_mask;
109 int i, j;
110
111 wcd->sconfig.ch_count = 1;
112 wcd->active_ports = 0;
113 for (i = 0; i < WCD938X_MAX_SWR_PORTS; i++) {
114 ch_mask = wcd->port_config[i].ch_mask;
115
116 if (!ch_mask)
117 continue;
118
119 for_each_set_bit(j, &ch_mask, 4)
120 wcd->sconfig.ch_count++;
121
122 port_config[wcd->active_ports] = wcd->port_config[i];
123 wcd->active_ports++;
124 }
125
126 wcd->sconfig.bps = 1;
127 wcd->sconfig.frame_rate = params_rate(params);
128 if (wcd->is_tx)
129 wcd->sconfig.direction = SDW_DATA_DIR_TX;
130 else
131 wcd->sconfig.direction = SDW_DATA_DIR_RX;
132
133 wcd->sconfig.type = SDW_STREAM_PCM;
134
135 return sdw_stream_add_slave(wcd->sdev, &wcd->sconfig,
136 &port_config[0], wcd->active_ports,
137 wcd->sruntime);
138}
139EXPORT_SYMBOL_GPL(wcd938x_sdw_hw_params);
140
141int wcd938x_sdw_free(struct wcd938x_sdw_priv *wcd,
142 struct snd_pcm_substream *substream,
143 struct snd_soc_dai *dai)
144{
145 sdw_stream_remove_slave(wcd->sdev, wcd->sruntime);
146
147 return 0;
148}
149EXPORT_SYMBOL_GPL(wcd938x_sdw_free);
150
151int wcd938x_sdw_set_sdw_stream(struct wcd938x_sdw_priv *wcd,
152 struct snd_soc_dai *dai,
153 void *stream, int direction)
154{
155 wcd->sruntime = stream;
156
157 return 0;
158}
159EXPORT_SYMBOL_GPL(wcd938x_sdw_set_sdw_stream);
160
161static int wcd9380_update_status(struct sdw_slave *slave,
162 enum sdw_slave_status status)
163{
164 return 0;
165}
166
167static int wcd9380_bus_config(struct sdw_slave *slave,
168 struct sdw_bus_params *params)
169{
170 sdw_write(slave, SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(params->next_bank), 0x01);
171
172 return 0;
173}
174
175static int wcd9380_interrupt_callback(struct sdw_slave *slave,
176 struct sdw_slave_intr_status *status)
177{
178 struct wcd938x_sdw_priv *wcd = dev_get_drvdata(&slave->dev);
179 struct irq_domain *slave_irq = wcd->slave_irq;
180 struct regmap *regmap = dev_get_regmap(&slave->dev, NULL);
181 u32 sts1, sts2, sts3;
182
183 do {
184 handle_nested_irq(irq_find_mapping(slave_irq, 0));
185 regmap_read(regmap, WCD938X_DIGITAL_INTR_STATUS_0, &sts1);
186 regmap_read(regmap, WCD938X_DIGITAL_INTR_STATUS_1, &sts2);
187 regmap_read(regmap, WCD938X_DIGITAL_INTR_STATUS_2, &sts3);
188
189 } while (sts1 || sts2 || sts3);
190
191 return IRQ_HANDLED;
192}
193
194static struct sdw_slave_ops wcd9380_slave_ops = {
195 .update_status = wcd9380_update_status,
196 .interrupt_callback = wcd9380_interrupt_callback,
197 .bus_config = wcd9380_bus_config,
198};
199
200static int wcd938x_sdw_component_bind(struct device *dev,
201 struct device *master, void *data)
202{
203 return 0;
204}
205
206static void wcd938x_sdw_component_unbind(struct device *dev,
207 struct device *master, void *data)
208{
209}
210
211static const struct component_ops wcd938x_sdw_component_ops = {
212 .bind = wcd938x_sdw_component_bind,
213 .unbind = wcd938x_sdw_component_unbind,
214};
215
216static int wcd9380_probe(struct sdw_slave *pdev,
217 const struct sdw_device_id *id)
218{
219 struct device *dev = &pdev->dev;
220 struct wcd938x_sdw_priv *wcd;
221 int ret;
222
223 wcd = devm_kzalloc(dev, sizeof(*wcd), GFP_KERNEL);
224 if (!wcd)
225 return -ENOMEM;
226
227
228
229
230
231 if (of_property_read_bool(dev->of_node, "qcom,tx-port-mapping")) {
232 wcd->is_tx = true;
233 ret = of_property_read_u32_array(dev->of_node, "qcom,tx-port-mapping",
234 &pdev->m_port_map[1],
235 WCD938X_MAX_TX_SWR_PORTS);
236 } else {
237 ret = of_property_read_u32_array(dev->of_node, "qcom,rx-port-mapping",
238 &pdev->m_port_map[1],
239 WCD938X_MAX_SWR_PORTS);
240 }
241
242 if (ret < 0)
243 dev_info(dev, "Static Port mapping not specified\n");
244
245 wcd->sdev = pdev;
246 dev_set_drvdata(dev, wcd);
247
248 pdev->prop.scp_int1_mask = SDW_SCP_INT1_IMPL_DEF |
249 SDW_SCP_INT1_BUS_CLASH |
250 SDW_SCP_INT1_PARITY;
251 pdev->prop.lane_control_support = true;
252 if (wcd->is_tx) {
253 pdev->prop.source_ports = GENMASK(WCD938X_MAX_SWR_PORTS, 0);
254 pdev->prop.src_dpn_prop = wcd938x_dpn_prop;
255 wcd->ch_info = &wcd938x_sdw_tx_ch_info[0];
256 pdev->prop.wake_capable = true;
257 } else {
258 pdev->prop.sink_ports = GENMASK(WCD938X_MAX_SWR_PORTS, 0);
259 pdev->prop.sink_dpn_prop = wcd938x_dpn_prop;
260 wcd->ch_info = &wcd938x_sdw_rx_ch_info[0];
261 }
262
263 pm_runtime_set_autosuspend_delay(dev, 3000);
264 pm_runtime_use_autosuspend(dev);
265 pm_runtime_mark_last_busy(dev);
266 pm_runtime_set_active(dev);
267 pm_runtime_enable(dev);
268
269 return component_add(dev, &wcd938x_sdw_component_ops);
270}
271
272static const struct sdw_device_id wcd9380_slave_id[] = {
273 SDW_SLAVE_ENTRY(0x0217, 0x10d, 0),
274 {},
275};
276MODULE_DEVICE_TABLE(sdw, wcd9380_slave_id);
277
278static int __maybe_unused wcd938x_sdw_runtime_suspend(struct device *dev)
279{
280 struct regmap *regmap = dev_get_regmap(dev, NULL);
281
282 if (regmap) {
283 regcache_cache_only(regmap, true);
284 regcache_mark_dirty(regmap);
285 }
286 return 0;
287}
288
289static int __maybe_unused wcd938x_sdw_runtime_resume(struct device *dev)
290{
291 struct regmap *regmap = dev_get_regmap(dev, NULL);
292
293 if (regmap) {
294 regcache_cache_only(regmap, false);
295 regcache_sync(regmap);
296 }
297
298 pm_runtime_mark_last_busy(dev);
299
300 return 0;
301}
302
303static const struct dev_pm_ops wcd938x_sdw_pm_ops = {
304 SET_RUNTIME_PM_OPS(wcd938x_sdw_runtime_suspend, wcd938x_sdw_runtime_resume, NULL)
305};
306
307
308static struct sdw_driver wcd9380_codec_driver = {
309 .probe = wcd9380_probe,
310 .ops = &wcd9380_slave_ops,
311 .id_table = wcd9380_slave_id,
312 .driver = {
313 .name = "wcd9380-codec",
314 .pm = &wcd938x_sdw_pm_ops,
315 }
316};
317module_sdw_driver(wcd9380_codec_driver);
318
319MODULE_DESCRIPTION("WCD938X SDW codec driver");
320MODULE_LICENSE("GPL");
321