]>
Commit | Line | Data |
---|---|---|
02efb49a SK |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (c) 2019, Linaro Limited | |
3 | ||
4 | #include <linux/clk.h> | |
5 | #include <linux/completion.h> | |
6 | #include <linux/interrupt.h> | |
7 | #include <linux/io.h> | |
8 | #include <linux/kernel.h> | |
9 | #include <linux/module.h> | |
10 | #include <linux/of.h> | |
11 | #include <linux/of_irq.h> | |
12 | #include <linux/of_device.h> | |
13 | #include <linux/regmap.h> | |
14 | #include <linux/slab.h> | |
15 | #include <linux/slimbus.h> | |
16 | #include <linux/soundwire/sdw.h> | |
17 | #include <linux/soundwire/sdw_registers.h> | |
18 | #include <sound/pcm_params.h> | |
19 | #include <sound/soc.h> | |
20 | #include "bus.h" | |
21 | ||
22 | #define SWRM_COMP_HW_VERSION 0x00 | |
23 | #define SWRM_COMP_CFG_ADDR 0x04 | |
24 | #define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK BIT(1) | |
25 | #define SWRM_COMP_CFG_ENABLE_MSK BIT(0) | |
26 | #define SWRM_COMP_PARAMS 0x100 | |
27 | #define SWRM_COMP_PARAMS_DOUT_PORTS_MASK GENMASK(4, 0) | |
28 | #define SWRM_COMP_PARAMS_DIN_PORTS_MASK GENMASK(9, 5) | |
29 | #define SWRM_INTERRUPT_STATUS 0x200 | |
30 | #define SWRM_INTERRUPT_STATUS_RMSK GENMASK(16, 0) | |
31 | #define SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED BIT(1) | |
32 | #define SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS BIT(2) | |
33 | #define SWRM_INTERRUPT_STATUS_CMD_ERROR BIT(7) | |
34 | #define SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED BIT(10) | |
35 | #define SWRM_INTERRUPT_MASK_ADDR 0x204 | |
36 | #define SWRM_INTERRUPT_CLEAR 0x208 | |
82f5c70c | 37 | #define SWRM_INTERRUPT_CPU_EN 0x210 |
02efb49a SK |
38 | #define SWRM_CMD_FIFO_WR_CMD 0x300 |
39 | #define SWRM_CMD_FIFO_RD_CMD 0x304 | |
40 | #define SWRM_CMD_FIFO_CMD 0x308 | |
41 | #define SWRM_CMD_FIFO_STATUS 0x30C | |
42 | #define SWRM_CMD_FIFO_CFG_ADDR 0x314 | |
43 | #define SWRM_RD_WR_CMD_RETRIES 0x7 | |
44 | #define SWRM_CMD_FIFO_RD_FIFO_ADDR 0x318 | |
45 | #define SWRM_ENUMERATOR_CFG_ADDR 0x500 | |
46 | #define SWRM_MCP_FRAME_CTRL_BANK_ADDR(m) (0x101C + 0x40 * (m)) | |
02efb49a SK |
47 | #define SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK GENMASK(2, 0) |
48 | #define SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK GENMASK(7, 3) | |
02efb49a SK |
49 | #define SWRM_MCP_CFG_ADDR 0x1048 |
50 | #define SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK GENMASK(21, 17) | |
02efb49a SK |
51 | #define SWRM_DEF_CMD_NO_PINGS 0x1f |
52 | #define SWRM_MCP_STATUS 0x104C | |
53 | #define SWRM_MCP_STATUS_BANK_NUM_MASK BIT(0) | |
54 | #define SWRM_MCP_SLV_STATUS 0x1090 | |
55 | #define SWRM_MCP_SLV_STATUS_MASK GENMASK(1, 0) | |
56 | #define SWRM_DP_PORT_CTRL_BANK(n, m) (0x1124 + 0x100 * (n - 1) + 0x40 * m) | |
5ffba1fb | 57 | #define SWRM_DP_BLOCK_CTRL3_BANK(n, m) (0x1138 + 0x100 * (n - 1) + 0x40 * m) |
02efb49a SK |
58 | #define SWRM_DP_PORT_CTRL_EN_CHAN_SHFT 0x18 |
59 | #define SWRM_DP_PORT_CTRL_OFFSET2_SHFT 0x10 | |
60 | #define SWRM_DP_PORT_CTRL_OFFSET1_SHFT 0x08 | |
61 | #define SWRM_AHB_BRIDGE_WR_DATA_0 0xc85 | |
62 | #define SWRM_AHB_BRIDGE_WR_ADDR_0 0xc89 | |
63 | #define SWRM_AHB_BRIDGE_RD_ADDR_0 0xc8d | |
64 | #define SWRM_AHB_BRIDGE_RD_DATA_0 0xc91 | |
65 | ||
66 | #define SWRM_REG_VAL_PACK(data, dev, id, reg) \ | |
67 | ((reg) | ((id) << 16) | ((dev) << 20) | ((data) << 24)) | |
68 | ||
02efb49a SK |
69 | #define SWRM_SPECIAL_CMD_ID 0xF |
70 | #define MAX_FREQ_NUM 1 | |
71 | #define TIMEOUT_MS (2 * HZ) | |
72 | #define QCOM_SWRM_MAX_RD_LEN 0xf | |
73 | #define QCOM_SDW_MAX_PORTS 14 | |
74 | #define DEFAULT_CLK_FREQ 9600000 | |
75 | #define SWRM_MAX_DAIS 0xF | |
76 | ||
77 | struct qcom_swrm_port_config { | |
78 | u8 si; | |
79 | u8 off1; | |
80 | u8 off2; | |
5ffba1fb | 81 | u8 bp_mode; |
02efb49a SK |
82 | }; |
83 | ||
84 | struct qcom_swrm_ctrl { | |
85 | struct sdw_bus bus; | |
86 | struct device *dev; | |
87 | struct regmap *regmap; | |
82f5c70c | 88 | void __iomem *mmio; |
02efb49a SK |
89 | struct completion *comp; |
90 | struct work_struct slave_work; | |
91 | /* read/write lock */ | |
92 | spinlock_t comp_lock; | |
93 | /* Port alloc/free lock */ | |
94 | struct mutex port_lock; | |
95 | struct clk *hclk; | |
96 | u8 wr_cmd_id; | |
97 | u8 rd_cmd_id; | |
98 | int irq; | |
99 | unsigned int version; | |
100 | int num_din_ports; | |
101 | int num_dout_ports; | |
8cb3b4e7 SK |
102 | int cols_index; |
103 | int rows_index; | |
02efb49a SK |
104 | unsigned long dout_port_mask; |
105 | unsigned long din_port_mask; | |
106 | struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS]; | |
107 | struct sdw_stream_runtime *sruntime[SWRM_MAX_DAIS]; | |
108 | enum sdw_slave_status status[SDW_MAX_DEVICES]; | |
109 | int (*reg_read)(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val); | |
110 | int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val); | |
111 | }; | |
112 | ||
8cb3b4e7 SK |
113 | struct qcom_swrm_data { |
114 | u32 default_cols; | |
115 | u32 default_rows; | |
116 | }; | |
117 | ||
118 | static struct qcom_swrm_data swrm_v1_3_data = { | |
119 | .default_rows = 48, | |
120 | .default_cols = 16, | |
121 | }; | |
122 | ||
123 | static struct qcom_swrm_data swrm_v1_5_data = { | |
124 | .default_rows = 50, | |
125 | .default_cols = 16, | |
126 | }; | |
127 | ||
02efb49a SK |
128 | #define to_qcom_sdw(b) container_of(b, struct qcom_swrm_ctrl, bus) |
129 | ||
d1df23fe | 130 | static int qcom_swrm_ahb_reg_read(struct qcom_swrm_ctrl *ctrl, int reg, |
02efb49a SK |
131 | u32 *val) |
132 | { | |
133 | struct regmap *wcd_regmap = ctrl->regmap; | |
134 | int ret; | |
135 | ||
136 | /* pg register + offset */ | |
137 | ret = regmap_bulk_write(wcd_regmap, SWRM_AHB_BRIDGE_RD_ADDR_0, | |
138 | (u8 *)®, 4); | |
139 | if (ret < 0) | |
140 | return SDW_CMD_FAIL; | |
141 | ||
142 | ret = regmap_bulk_read(wcd_regmap, SWRM_AHB_BRIDGE_RD_DATA_0, | |
143 | val, 4); | |
144 | if (ret < 0) | |
145 | return SDW_CMD_FAIL; | |
146 | ||
147 | return SDW_CMD_OK; | |
148 | } | |
149 | ||
150 | static int qcom_swrm_ahb_reg_write(struct qcom_swrm_ctrl *ctrl, | |
151 | int reg, int val) | |
152 | { | |
153 | struct regmap *wcd_regmap = ctrl->regmap; | |
154 | int ret; | |
155 | /* pg register + offset */ | |
156 | ret = regmap_bulk_write(wcd_regmap, SWRM_AHB_BRIDGE_WR_DATA_0, | |
157 | (u8 *)&val, 4); | |
158 | if (ret) | |
159 | return SDW_CMD_FAIL; | |
160 | ||
161 | /* write address register */ | |
162 | ret = regmap_bulk_write(wcd_regmap, SWRM_AHB_BRIDGE_WR_ADDR_0, | |
163 | (u8 *)®, 4); | |
164 | if (ret) | |
165 | return SDW_CMD_FAIL; | |
166 | ||
167 | return SDW_CMD_OK; | |
168 | } | |
169 | ||
82f5c70c JM |
170 | static int qcom_swrm_cpu_reg_read(struct qcom_swrm_ctrl *ctrl, int reg, |
171 | u32 *val) | |
172 | { | |
173 | *val = readl(ctrl->mmio + reg); | |
174 | return SDW_CMD_OK; | |
175 | } | |
176 | ||
177 | static int qcom_swrm_cpu_reg_write(struct qcom_swrm_ctrl *ctrl, int reg, | |
178 | int val) | |
179 | { | |
180 | writel(val, ctrl->mmio + reg); | |
181 | return SDW_CMD_OK; | |
182 | } | |
183 | ||
02efb49a SK |
184 | static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl *ctrl, u8 cmd_data, |
185 | u8 dev_addr, u16 reg_addr) | |
186 | { | |
187 | DECLARE_COMPLETION_ONSTACK(comp); | |
188 | unsigned long flags; | |
189 | u32 val; | |
190 | int ret; | |
191 | ||
192 | spin_lock_irqsave(&ctrl->comp_lock, flags); | |
193 | ctrl->comp = ∁ | |
194 | spin_unlock_irqrestore(&ctrl->comp_lock, flags); | |
195 | val = SWRM_REG_VAL_PACK(cmd_data, dev_addr, | |
196 | SWRM_SPECIAL_CMD_ID, reg_addr); | |
197 | ret = ctrl->reg_write(ctrl, SWRM_CMD_FIFO_WR_CMD, val); | |
198 | if (ret) | |
199 | goto err; | |
200 | ||
201 | ret = wait_for_completion_timeout(ctrl->comp, | |
202 | msecs_to_jiffies(TIMEOUT_MS)); | |
203 | ||
204 | if (!ret) | |
205 | ret = SDW_CMD_IGNORED; | |
206 | else | |
207 | ret = SDW_CMD_OK; | |
208 | err: | |
209 | spin_lock_irqsave(&ctrl->comp_lock, flags); | |
210 | ctrl->comp = NULL; | |
211 | spin_unlock_irqrestore(&ctrl->comp_lock, flags); | |
212 | ||
213 | return ret; | |
214 | } | |
215 | ||
216 | static int qcom_swrm_cmd_fifo_rd_cmd(struct qcom_swrm_ctrl *ctrl, | |
217 | u8 dev_addr, u16 reg_addr, | |
218 | u32 len, u8 *rval) | |
219 | { | |
220 | int i, ret; | |
221 | u32 val; | |
222 | DECLARE_COMPLETION_ONSTACK(comp); | |
223 | unsigned long flags; | |
224 | ||
225 | spin_lock_irqsave(&ctrl->comp_lock, flags); | |
226 | ctrl->comp = ∁ | |
227 | spin_unlock_irqrestore(&ctrl->comp_lock, flags); | |
228 | ||
229 | val = SWRM_REG_VAL_PACK(len, dev_addr, SWRM_SPECIAL_CMD_ID, reg_addr); | |
230 | ret = ctrl->reg_write(ctrl, SWRM_CMD_FIFO_RD_CMD, val); | |
231 | if (ret) | |
232 | goto err; | |
233 | ||
234 | ret = wait_for_completion_timeout(ctrl->comp, | |
235 | msecs_to_jiffies(TIMEOUT_MS)); | |
236 | ||
237 | if (!ret) { | |
238 | ret = SDW_CMD_IGNORED; | |
239 | goto err; | |
240 | } else { | |
241 | ret = SDW_CMD_OK; | |
242 | } | |
243 | ||
244 | for (i = 0; i < len; i++) { | |
245 | ctrl->reg_read(ctrl, SWRM_CMD_FIFO_RD_FIFO_ADDR, &val); | |
246 | rval[i] = val & 0xFF; | |
247 | } | |
248 | ||
249 | err: | |
250 | spin_lock_irqsave(&ctrl->comp_lock, flags); | |
251 | ctrl->comp = NULL; | |
252 | spin_unlock_irqrestore(&ctrl->comp_lock, flags); | |
253 | ||
254 | return ret; | |
255 | } | |
256 | ||
257 | static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl) | |
258 | { | |
259 | u32 val; | |
260 | int i; | |
261 | ||
262 | ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val); | |
263 | ||
264 | for (i = 0; i < SDW_MAX_DEVICES; i++) { | |
265 | u32 s; | |
266 | ||
267 | s = (val >> (i * 2)); | |
268 | s &= SWRM_MCP_SLV_STATUS_MASK; | |
269 | ctrl->status[i] = s; | |
270 | } | |
271 | } | |
272 | ||
273 | static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id) | |
274 | { | |
275 | struct qcom_swrm_ctrl *ctrl = dev_id; | |
276 | u32 sts, value; | |
277 | unsigned long flags; | |
278 | ||
279 | ctrl->reg_read(ctrl, SWRM_INTERRUPT_STATUS, &sts); | |
280 | ||
281 | if (sts & SWRM_INTERRUPT_STATUS_CMD_ERROR) { | |
282 | ctrl->reg_read(ctrl, SWRM_CMD_FIFO_STATUS, &value); | |
283 | dev_err_ratelimited(ctrl->dev, | |
284 | "CMD error, fifo status 0x%x\n", | |
285 | value); | |
286 | ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CMD, 0x1); | |
287 | } | |
288 | ||
289 | if ((sts & SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED) || | |
290 | sts & SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS) | |
291 | schedule_work(&ctrl->slave_work); | |
292 | ||
293 | /** | |
294 | * clear the interrupt before complete() is called, as complete can | |
295 | * schedule new read/writes which require interrupts, clearing the | |
296 | * interrupt would avoid missing interrupts in such cases. | |
297 | */ | |
298 | ctrl->reg_write(ctrl, SWRM_INTERRUPT_CLEAR, sts); | |
299 | ||
300 | if (sts & SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED) { | |
301 | spin_lock_irqsave(&ctrl->comp_lock, flags); | |
302 | if (ctrl->comp) | |
303 | complete(ctrl->comp); | |
304 | spin_unlock_irqrestore(&ctrl->comp_lock, flags); | |
305 | } | |
306 | ||
307 | return IRQ_HANDLED; | |
308 | } | |
309 | static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) | |
310 | { | |
311 | u32 val; | |
312 | ||
313 | /* Clear Rows and Cols */ | |
8cb3b4e7 SK |
314 | val = FIELD_PREP(SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK, ctrl->rows_index); |
315 | val |= FIELD_PREP(SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK, ctrl->cols_index); | |
02efb49a SK |
316 | |
317 | ctrl->reg_write(ctrl, SWRM_MCP_FRAME_CTRL_BANK_ADDR(0), val); | |
318 | ||
319 | /* Disable Auto enumeration */ | |
320 | ctrl->reg_write(ctrl, SWRM_ENUMERATOR_CFG_ADDR, 0); | |
321 | ||
322 | /* Mask soundwire interrupts */ | |
323 | ctrl->reg_write(ctrl, SWRM_INTERRUPT_MASK_ADDR, | |
324 | SWRM_INTERRUPT_STATUS_RMSK); | |
325 | ||
326 | /* Configure No pings */ | |
327 | ctrl->reg_read(ctrl, SWRM_MCP_CFG_ADDR, &val); | |
578ddced | 328 | u32p_replace_bits(&val, SWRM_DEF_CMD_NO_PINGS, SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK); |
02efb49a SK |
329 | ctrl->reg_write(ctrl, SWRM_MCP_CFG_ADDR, val); |
330 | ||
331 | /* Configure number of retries of a read/write cmd */ | |
332 | ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR, SWRM_RD_WR_CMD_RETRIES); | |
333 | ||
334 | /* Set IRQ to PULSE */ | |
335 | ctrl->reg_write(ctrl, SWRM_COMP_CFG_ADDR, | |
336 | SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK | | |
337 | SWRM_COMP_CFG_ENABLE_MSK); | |
82f5c70c JM |
338 | |
339 | /* enable CPU IRQs */ | |
340 | if (ctrl->mmio) { | |
341 | ctrl->reg_write(ctrl, SWRM_INTERRUPT_CPU_EN, | |
342 | SWRM_INTERRUPT_STATUS_RMSK); | |
343 | } | |
02efb49a SK |
344 | return 0; |
345 | } | |
346 | ||
347 | static enum sdw_command_response qcom_swrm_xfer_msg(struct sdw_bus *bus, | |
348 | struct sdw_msg *msg) | |
349 | { | |
350 | struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); | |
351 | int ret, i, len; | |
352 | ||
353 | if (msg->flags == SDW_MSG_FLAG_READ) { | |
354 | for (i = 0; i < msg->len;) { | |
355 | if ((msg->len - i) < QCOM_SWRM_MAX_RD_LEN) | |
356 | len = msg->len - i; | |
357 | else | |
358 | len = QCOM_SWRM_MAX_RD_LEN; | |
359 | ||
360 | ret = qcom_swrm_cmd_fifo_rd_cmd(ctrl, msg->dev_num, | |
361 | msg->addr + i, len, | |
362 | &msg->buf[i]); | |
363 | if (ret) | |
364 | return ret; | |
365 | ||
366 | i = i + len; | |
367 | } | |
368 | } else if (msg->flags == SDW_MSG_FLAG_WRITE) { | |
369 | for (i = 0; i < msg->len; i++) { | |
370 | ret = qcom_swrm_cmd_fifo_wr_cmd(ctrl, msg->buf[i], | |
371 | msg->dev_num, | |
372 | msg->addr + i); | |
373 | if (ret) | |
374 | return SDW_CMD_IGNORED; | |
375 | } | |
376 | } | |
377 | ||
378 | return SDW_CMD_OK; | |
379 | } | |
380 | ||
381 | static int qcom_swrm_pre_bank_switch(struct sdw_bus *bus) | |
382 | { | |
383 | u32 reg = SWRM_MCP_FRAME_CTRL_BANK_ADDR(bus->params.next_bank); | |
384 | struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); | |
385 | u32 val; | |
386 | ||
387 | ctrl->reg_read(ctrl, reg, &val); | |
388 | ||
8cb3b4e7 SK |
389 | u32p_replace_bits(&val, ctrl->cols_index, SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK); |
390 | u32p_replace_bits(&val, ctrl->rows_index, SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK); | |
02efb49a SK |
391 | |
392 | return ctrl->reg_write(ctrl, reg, val); | |
393 | } | |
394 | ||
395 | static int qcom_swrm_port_params(struct sdw_bus *bus, | |
396 | struct sdw_port_params *p_params, | |
397 | unsigned int bank) | |
398 | { | |
399 | /* TBD */ | |
400 | return 0; | |
401 | } | |
402 | ||
403 | static int qcom_swrm_transport_params(struct sdw_bus *bus, | |
404 | struct sdw_transport_params *params, | |
405 | enum sdw_reg_bank bank) | |
406 | { | |
407 | struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); | |
408 | u32 value; | |
5ffba1fb SK |
409 | int reg = SWRM_DP_PORT_CTRL_BANK((params->port_num), bank); |
410 | int ret; | |
02efb49a SK |
411 | |
412 | value = params->offset1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT; | |
413 | value |= params->offset2 << SWRM_DP_PORT_CTRL_OFFSET2_SHFT; | |
414 | value |= params->sample_interval - 1; | |
415 | ||
5ffba1fb SK |
416 | ret = ctrl->reg_write(ctrl, reg, value); |
417 | ||
418 | if (!ret && params->blk_pkg_mode) { | |
419 | reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank); | |
420 | ||
421 | ret = ctrl->reg_write(ctrl, reg, 1); | |
422 | } | |
423 | ||
424 | return ret; | |
02efb49a SK |
425 | } |
426 | ||
427 | static int qcom_swrm_port_enable(struct sdw_bus *bus, | |
428 | struct sdw_enable_ch *enable_ch, | |
429 | unsigned int bank) | |
430 | { | |
431 | u32 reg = SWRM_DP_PORT_CTRL_BANK(enable_ch->port_num, bank); | |
432 | struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); | |
433 | u32 val; | |
434 | ||
435 | ctrl->reg_read(ctrl, reg, &val); | |
436 | ||
437 | if (enable_ch->enable) | |
438 | val |= (enable_ch->ch_mask << SWRM_DP_PORT_CTRL_EN_CHAN_SHFT); | |
439 | else | |
440 | val &= ~(0xff << SWRM_DP_PORT_CTRL_EN_CHAN_SHFT); | |
441 | ||
442 | return ctrl->reg_write(ctrl, reg, val); | |
443 | } | |
444 | ||
51fe3881 | 445 | static const struct sdw_master_port_ops qcom_swrm_port_ops = { |
02efb49a SK |
446 | .dpn_set_port_params = qcom_swrm_port_params, |
447 | .dpn_set_port_transport_params = qcom_swrm_transport_params, | |
448 | .dpn_port_enable_ch = qcom_swrm_port_enable, | |
449 | }; | |
450 | ||
51fe3881 | 451 | static const struct sdw_master_ops qcom_swrm_ops = { |
02efb49a SK |
452 | .xfer_msg = qcom_swrm_xfer_msg, |
453 | .pre_bank_switch = qcom_swrm_pre_bank_switch, | |
454 | }; | |
455 | ||
456 | static int qcom_swrm_compute_params(struct sdw_bus *bus) | |
457 | { | |
458 | struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); | |
459 | struct sdw_master_runtime *m_rt; | |
460 | struct sdw_slave_runtime *s_rt; | |
461 | struct sdw_port_runtime *p_rt; | |
462 | struct qcom_swrm_port_config *pcfg; | |
463 | int i = 0; | |
464 | ||
465 | list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { | |
466 | list_for_each_entry(p_rt, &m_rt->port_list, port_node) { | |
467 | pcfg = &ctrl->pconfig[p_rt->num - 1]; | |
468 | p_rt->transport_params.port_num = p_rt->num; | |
469 | p_rt->transport_params.sample_interval = pcfg->si + 1; | |
470 | p_rt->transport_params.offset1 = pcfg->off1; | |
471 | p_rt->transport_params.offset2 = pcfg->off2; | |
5ffba1fb | 472 | p_rt->transport_params.blk_pkg_mode = pcfg->bp_mode; |
02efb49a SK |
473 | } |
474 | ||
475 | list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { | |
476 | list_for_each_entry(p_rt, &s_rt->port_list, port_node) { | |
477 | pcfg = &ctrl->pconfig[i]; | |
478 | p_rt->transport_params.port_num = p_rt->num; | |
479 | p_rt->transport_params.sample_interval = | |
480 | pcfg->si + 1; | |
481 | p_rt->transport_params.offset1 = pcfg->off1; | |
482 | p_rt->transport_params.offset2 = pcfg->off2; | |
5ffba1fb | 483 | p_rt->transport_params.blk_pkg_mode = pcfg->bp_mode; |
02efb49a SK |
484 | i++; |
485 | } | |
486 | } | |
487 | } | |
488 | ||
489 | return 0; | |
490 | } | |
491 | ||
492 | static u32 qcom_swrm_freq_tbl[MAX_FREQ_NUM] = { | |
493 | DEFAULT_CLK_FREQ, | |
494 | }; | |
495 | ||
496 | static void qcom_swrm_slave_wq(struct work_struct *work) | |
497 | { | |
498 | struct qcom_swrm_ctrl *ctrl = | |
499 | container_of(work, struct qcom_swrm_ctrl, slave_work); | |
500 | ||
501 | qcom_swrm_get_device_status(ctrl); | |
502 | sdw_handle_slave_status(&ctrl->bus, ctrl->status); | |
503 | } | |
504 | ||
505 | ||
506 | static void qcom_swrm_stream_free_ports(struct qcom_swrm_ctrl *ctrl, | |
507 | struct sdw_stream_runtime *stream) | |
508 | { | |
509 | struct sdw_master_runtime *m_rt; | |
510 | struct sdw_port_runtime *p_rt; | |
511 | unsigned long *port_mask; | |
512 | ||
513 | mutex_lock(&ctrl->port_lock); | |
514 | ||
515 | list_for_each_entry(m_rt, &stream->master_list, stream_node) { | |
516 | if (m_rt->direction == SDW_DATA_DIR_RX) | |
517 | port_mask = &ctrl->dout_port_mask; | |
518 | else | |
519 | port_mask = &ctrl->din_port_mask; | |
520 | ||
521 | list_for_each_entry(p_rt, &m_rt->port_list, port_node) | |
522 | clear_bit(p_rt->num - 1, port_mask); | |
523 | } | |
524 | ||
525 | mutex_unlock(&ctrl->port_lock); | |
526 | } | |
527 | ||
528 | static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, | |
529 | struct sdw_stream_runtime *stream, | |
530 | struct snd_pcm_hw_params *params, | |
531 | int direction) | |
532 | { | |
533 | struct sdw_port_config pconfig[QCOM_SDW_MAX_PORTS]; | |
534 | struct sdw_stream_config sconfig; | |
535 | struct sdw_master_runtime *m_rt; | |
536 | struct sdw_slave_runtime *s_rt; | |
537 | struct sdw_port_runtime *p_rt; | |
538 | unsigned long *port_mask; | |
539 | int i, maxport, pn, nports = 0, ret = 0; | |
540 | ||
541 | mutex_lock(&ctrl->port_lock); | |
542 | list_for_each_entry(m_rt, &stream->master_list, stream_node) { | |
543 | if (m_rt->direction == SDW_DATA_DIR_RX) { | |
544 | maxport = ctrl->num_dout_ports; | |
545 | port_mask = &ctrl->dout_port_mask; | |
546 | } else { | |
547 | maxport = ctrl->num_din_ports; | |
548 | port_mask = &ctrl->din_port_mask; | |
549 | } | |
550 | ||
551 | list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { | |
552 | list_for_each_entry(p_rt, &s_rt->port_list, port_node) { | |
553 | /* Port numbers start from 1 - 14*/ | |
554 | pn = find_first_zero_bit(port_mask, maxport); | |
555 | if (pn > (maxport - 1)) { | |
556 | dev_err(ctrl->dev, "All ports busy\n"); | |
557 | ret = -EBUSY; | |
558 | goto err; | |
559 | } | |
560 | set_bit(pn, port_mask); | |
561 | pconfig[nports].num = pn + 1; | |
562 | pconfig[nports].ch_mask = p_rt->ch_mask; | |
563 | nports++; | |
564 | } | |
565 | } | |
566 | } | |
567 | ||
568 | if (direction == SNDRV_PCM_STREAM_CAPTURE) | |
569 | sconfig.direction = SDW_DATA_DIR_TX; | |
570 | else | |
571 | sconfig.direction = SDW_DATA_DIR_RX; | |
572 | ||
573 | /* hw parameters wil be ignored as we only support PDM */ | |
574 | sconfig.ch_count = 1; | |
575 | sconfig.frame_rate = params_rate(params); | |
576 | sconfig.type = stream->type; | |
577 | sconfig.bps = 1; | |
578 | sdw_stream_add_master(&ctrl->bus, &sconfig, pconfig, | |
579 | nports, stream); | |
580 | err: | |
581 | if (ret) { | |
582 | for (i = 0; i < nports; i++) | |
583 | clear_bit(pconfig[i].num - 1, port_mask); | |
584 | } | |
585 | ||
586 | mutex_unlock(&ctrl->port_lock); | |
587 | ||
588 | return ret; | |
589 | } | |
590 | ||
591 | static int qcom_swrm_hw_params(struct snd_pcm_substream *substream, | |
592 | struct snd_pcm_hw_params *params, | |
593 | struct snd_soc_dai *dai) | |
594 | { | |
595 | struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev); | |
596 | struct sdw_stream_runtime *sruntime = ctrl->sruntime[dai->id]; | |
597 | int ret; | |
598 | ||
599 | ret = qcom_swrm_stream_alloc_ports(ctrl, sruntime, params, | |
600 | substream->stream); | |
601 | if (ret) | |
602 | qcom_swrm_stream_free_ports(ctrl, sruntime); | |
603 | ||
604 | return ret; | |
605 | } | |
606 | ||
607 | static int qcom_swrm_hw_free(struct snd_pcm_substream *substream, | |
608 | struct snd_soc_dai *dai) | |
609 | { | |
610 | struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev); | |
611 | struct sdw_stream_runtime *sruntime = ctrl->sruntime[dai->id]; | |
612 | ||
613 | qcom_swrm_stream_free_ports(ctrl, sruntime); | |
614 | sdw_stream_remove_master(&ctrl->bus, sruntime); | |
615 | ||
616 | return 0; | |
617 | } | |
618 | ||
619 | static int qcom_swrm_set_sdw_stream(struct snd_soc_dai *dai, | |
620 | void *stream, int direction) | |
621 | { | |
622 | struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev); | |
623 | ||
624 | ctrl->sruntime[dai->id] = stream; | |
625 | ||
626 | return 0; | |
627 | } | |
628 | ||
39ec6f99 SK |
629 | static void *qcom_swrm_get_sdw_stream(struct snd_soc_dai *dai, int direction) |
630 | { | |
631 | struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev); | |
632 | ||
633 | return ctrl->sruntime[dai->id]; | |
634 | } | |
635 | ||
02efb49a SK |
636 | static int qcom_swrm_startup(struct snd_pcm_substream *substream, |
637 | struct snd_soc_dai *dai) | |
638 | { | |
639 | struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev); | |
640 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
641 | struct sdw_stream_runtime *sruntime; | |
ce83baca | 642 | struct snd_soc_dai *codec_dai; |
02efb49a SK |
643 | int ret, i; |
644 | ||
645 | sruntime = sdw_alloc_stream(dai->name); | |
646 | if (!sruntime) | |
647 | return -ENOMEM; | |
648 | ||
649 | ctrl->sruntime[dai->id] = sruntime; | |
650 | ||
c998ee30 | 651 | for_each_rtd_codec_dais(rtd, i, codec_dai) { |
ce83baca | 652 | ret = snd_soc_dai_set_sdw_stream(codec_dai, sruntime, |
02efb49a SK |
653 | substream->stream); |
654 | if (ret < 0 && ret != -ENOTSUPP) { | |
655 | dev_err(dai->dev, "Failed to set sdw stream on %s", | |
ce83baca | 656 | codec_dai->name); |
02efb49a SK |
657 | sdw_release_stream(sruntime); |
658 | return ret; | |
659 | } | |
660 | } | |
661 | ||
662 | return 0; | |
663 | } | |
664 | ||
665 | static void qcom_swrm_shutdown(struct snd_pcm_substream *substream, | |
666 | struct snd_soc_dai *dai) | |
667 | { | |
668 | struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev); | |
669 | ||
670 | sdw_release_stream(ctrl->sruntime[dai->id]); | |
671 | ctrl->sruntime[dai->id] = NULL; | |
672 | } | |
673 | ||
674 | static const struct snd_soc_dai_ops qcom_swrm_pdm_dai_ops = { | |
675 | .hw_params = qcom_swrm_hw_params, | |
676 | .hw_free = qcom_swrm_hw_free, | |
677 | .startup = qcom_swrm_startup, | |
678 | .shutdown = qcom_swrm_shutdown, | |
679 | .set_sdw_stream = qcom_swrm_set_sdw_stream, | |
39ec6f99 | 680 | .get_sdw_stream = qcom_swrm_get_sdw_stream, |
02efb49a SK |
681 | }; |
682 | ||
683 | static const struct snd_soc_component_driver qcom_swrm_dai_component = { | |
684 | .name = "soundwire", | |
685 | }; | |
686 | ||
687 | static int qcom_swrm_register_dais(struct qcom_swrm_ctrl *ctrl) | |
688 | { | |
689 | int num_dais = ctrl->num_dout_ports + ctrl->num_din_ports; | |
690 | struct snd_soc_dai_driver *dais; | |
691 | struct snd_soc_pcm_stream *stream; | |
692 | struct device *dev = ctrl->dev; | |
693 | int i; | |
694 | ||
695 | /* PDM dais are only tested for now */ | |
696 | dais = devm_kcalloc(dev, num_dais, sizeof(*dais), GFP_KERNEL); | |
697 | if (!dais) | |
698 | return -ENOMEM; | |
699 | ||
700 | for (i = 0; i < num_dais; i++) { | |
701 | dais[i].name = devm_kasprintf(dev, GFP_KERNEL, "SDW Pin%d", i); | |
702 | if (!dais[i].name) | |
703 | return -ENOMEM; | |
704 | ||
705 | if (i < ctrl->num_dout_ports) | |
706 | stream = &dais[i].playback; | |
707 | else | |
708 | stream = &dais[i].capture; | |
709 | ||
710 | stream->channels_min = 1; | |
711 | stream->channels_max = 1; | |
712 | stream->rates = SNDRV_PCM_RATE_48000; | |
713 | stream->formats = SNDRV_PCM_FMTBIT_S16_LE; | |
714 | ||
715 | dais[i].ops = &qcom_swrm_pdm_dai_ops; | |
716 | dais[i].id = i; | |
717 | } | |
718 | ||
719 | return devm_snd_soc_register_component(ctrl->dev, | |
720 | &qcom_swrm_dai_component, | |
721 | dais, num_dais); | |
722 | } | |
723 | ||
724 | static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) | |
725 | { | |
726 | struct device_node *np = ctrl->dev->of_node; | |
727 | u8 off1[QCOM_SDW_MAX_PORTS]; | |
728 | u8 off2[QCOM_SDW_MAX_PORTS]; | |
729 | u8 si[QCOM_SDW_MAX_PORTS]; | |
5ffba1fb | 730 | u8 bp_mode[QCOM_SDW_MAX_PORTS] = { 0, }; |
02efb49a SK |
731 | int i, ret, nports, val; |
732 | ||
733 | ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val); | |
734 | ||
9972b90a VK |
735 | ctrl->num_dout_ports = FIELD_GET(SWRM_COMP_PARAMS_DOUT_PORTS_MASK, val); |
736 | ctrl->num_din_ports = FIELD_GET(SWRM_COMP_PARAMS_DIN_PORTS_MASK, val); | |
02efb49a SK |
737 | |
738 | ret = of_property_read_u32(np, "qcom,din-ports", &val); | |
739 | if (ret) | |
740 | return ret; | |
741 | ||
742 | if (val > ctrl->num_din_ports) | |
743 | return -EINVAL; | |
744 | ||
745 | ctrl->num_din_ports = val; | |
746 | ||
747 | ret = of_property_read_u32(np, "qcom,dout-ports", &val); | |
748 | if (ret) | |
749 | return ret; | |
750 | ||
751 | if (val > ctrl->num_dout_ports) | |
752 | return -EINVAL; | |
753 | ||
754 | ctrl->num_dout_ports = val; | |
755 | ||
756 | nports = ctrl->num_dout_ports + ctrl->num_din_ports; | |
757 | ||
758 | ret = of_property_read_u8_array(np, "qcom,ports-offset1", | |
759 | off1, nports); | |
760 | if (ret) | |
761 | return ret; | |
762 | ||
763 | ret = of_property_read_u8_array(np, "qcom,ports-offset2", | |
764 | off2, nports); | |
765 | if (ret) | |
766 | return ret; | |
767 | ||
768 | ret = of_property_read_u8_array(np, "qcom,ports-sinterval-low", | |
769 | si, nports); | |
770 | if (ret) | |
771 | return ret; | |
772 | ||
5ffba1fb SK |
773 | ret = of_property_read_u8_array(np, "qcom,ports-block-pack-mode", |
774 | bp_mode, nports); | |
02efb49a SK |
775 | for (i = 0; i < nports; i++) { |
776 | ctrl->pconfig[i].si = si[i]; | |
777 | ctrl->pconfig[i].off1 = off1[i]; | |
778 | ctrl->pconfig[i].off2 = off2[i]; | |
5ffba1fb | 779 | ctrl->pconfig[i].bp_mode = bp_mode[i]; |
02efb49a SK |
780 | } |
781 | ||
782 | return 0; | |
783 | } | |
784 | ||
785 | static int qcom_swrm_probe(struct platform_device *pdev) | |
786 | { | |
787 | struct device *dev = &pdev->dev; | |
788 | struct sdw_master_prop *prop; | |
789 | struct sdw_bus_params *params; | |
790 | struct qcom_swrm_ctrl *ctrl; | |
8cb3b4e7 | 791 | const struct qcom_swrm_data *data; |
02efb49a SK |
792 | int ret; |
793 | u32 val; | |
794 | ||
795 | ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL); | |
796 | if (!ctrl) | |
797 | return -ENOMEM; | |
798 | ||
8cb3b4e7 SK |
799 | data = of_device_get_match_data(dev); |
800 | ctrl->rows_index = sdw_find_row_index(data->default_rows); | |
801 | ctrl->cols_index = sdw_find_col_index(data->default_cols); | |
47edc010 | 802 | #if IS_REACHABLE(CONFIG_SLIMBUS) |
02efb49a | 803 | if (dev->parent->bus == &slimbus_bus) { |
5bd77324 JM |
804 | #else |
805 | if (false) { | |
806 | #endif | |
d1df23fe | 807 | ctrl->reg_read = qcom_swrm_ahb_reg_read; |
02efb49a SK |
808 | ctrl->reg_write = qcom_swrm_ahb_reg_write; |
809 | ctrl->regmap = dev_get_regmap(dev->parent, NULL); | |
810 | if (!ctrl->regmap) | |
811 | return -EINVAL; | |
812 | } else { | |
82f5c70c JM |
813 | ctrl->reg_read = qcom_swrm_cpu_reg_read; |
814 | ctrl->reg_write = qcom_swrm_cpu_reg_write; | |
815 | ctrl->mmio = devm_platform_ioremap_resource(pdev, 0); | |
816 | if (IS_ERR(ctrl->mmio)) | |
817 | return PTR_ERR(ctrl->mmio); | |
02efb49a SK |
818 | } |
819 | ||
820 | ctrl->irq = of_irq_get(dev->of_node, 0); | |
91b5cfc0 PLB |
821 | if (ctrl->irq < 0) { |
822 | ret = ctrl->irq; | |
823 | goto err_init; | |
824 | } | |
02efb49a SK |
825 | |
826 | ctrl->hclk = devm_clk_get(dev, "iface"); | |
91b5cfc0 PLB |
827 | if (IS_ERR(ctrl->hclk)) { |
828 | ret = PTR_ERR(ctrl->hclk); | |
829 | goto err_init; | |
830 | } | |
02efb49a SK |
831 | |
832 | clk_prepare_enable(ctrl->hclk); | |
833 | ||
834 | ctrl->dev = dev; | |
835 | dev_set_drvdata(&pdev->dev, ctrl); | |
836 | spin_lock_init(&ctrl->comp_lock); | |
837 | mutex_init(&ctrl->port_lock); | |
838 | INIT_WORK(&ctrl->slave_work, qcom_swrm_slave_wq); | |
839 | ||
02efb49a SK |
840 | ctrl->bus.ops = &qcom_swrm_ops; |
841 | ctrl->bus.port_ops = &qcom_swrm_port_ops; | |
842 | ctrl->bus.compute_params = &qcom_swrm_compute_params; | |
843 | ||
844 | ret = qcom_swrm_get_port_config(ctrl); | |
845 | if (ret) | |
91b5cfc0 | 846 | goto err_clk; |
02efb49a SK |
847 | |
848 | params = &ctrl->bus.params; | |
849 | params->max_dr_freq = DEFAULT_CLK_FREQ; | |
850 | params->curr_dr_freq = DEFAULT_CLK_FREQ; | |
8cb3b4e7 SK |
851 | params->col = data->default_cols; |
852 | params->row = data->default_rows; | |
02efb49a SK |
853 | ctrl->reg_read(ctrl, SWRM_MCP_STATUS, &val); |
854 | params->curr_bank = val & SWRM_MCP_STATUS_BANK_NUM_MASK; | |
855 | params->next_bank = !params->curr_bank; | |
856 | ||
857 | prop = &ctrl->bus.prop; | |
858 | prop->max_clk_freq = DEFAULT_CLK_FREQ; | |
859 | prop->num_clk_gears = 0; | |
860 | prop->num_clk_freq = MAX_FREQ_NUM; | |
861 | prop->clk_freq = &qcom_swrm_freq_tbl[0]; | |
8cb3b4e7 SK |
862 | prop->default_col = data->default_cols; |
863 | prop->default_row = data->default_rows; | |
02efb49a SK |
864 | |
865 | ctrl->reg_read(ctrl, SWRM_COMP_HW_VERSION, &ctrl->version); | |
866 | ||
867 | ret = devm_request_threaded_irq(dev, ctrl->irq, NULL, | |
868 | qcom_swrm_irq_handler, | |
4f1738f4 SZ |
869 | IRQF_TRIGGER_RISING | |
870 | IRQF_ONESHOT, | |
02efb49a SK |
871 | "soundwire", ctrl); |
872 | if (ret) { | |
873 | dev_err(dev, "Failed to request soundwire irq\n"); | |
91b5cfc0 | 874 | goto err_clk; |
02efb49a SK |
875 | } |
876 | ||
5cab3ff2 | 877 | ret = sdw_bus_master_add(&ctrl->bus, dev, dev->fwnode); |
02efb49a SK |
878 | if (ret) { |
879 | dev_err(dev, "Failed to register Soundwire controller (%d)\n", | |
880 | ret); | |
91b5cfc0 | 881 | goto err_clk; |
02efb49a SK |
882 | } |
883 | ||
884 | qcom_swrm_init(ctrl); | |
885 | ret = qcom_swrm_register_dais(ctrl); | |
886 | if (ret) | |
91b5cfc0 | 887 | goto err_master_add; |
02efb49a SK |
888 | |
889 | dev_info(dev, "Qualcomm Soundwire controller v%x.%x.%x Registered\n", | |
890 | (ctrl->version >> 24) & 0xff, (ctrl->version >> 16) & 0xff, | |
891 | ctrl->version & 0xffff); | |
892 | ||
893 | return 0; | |
91b5cfc0 PLB |
894 | |
895 | err_master_add: | |
5cab3ff2 | 896 | sdw_bus_master_delete(&ctrl->bus); |
91b5cfc0 | 897 | err_clk: |
02efb49a | 898 | clk_disable_unprepare(ctrl->hclk); |
91b5cfc0 | 899 | err_init: |
02efb49a SK |
900 | return ret; |
901 | } | |
902 | ||
903 | static int qcom_swrm_remove(struct platform_device *pdev) | |
904 | { | |
905 | struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(&pdev->dev); | |
906 | ||
5cab3ff2 | 907 | sdw_bus_master_delete(&ctrl->bus); |
02efb49a SK |
908 | clk_disable_unprepare(ctrl->hclk); |
909 | ||
910 | return 0; | |
911 | } | |
912 | ||
913 | static const struct of_device_id qcom_swrm_of_match[] = { | |
8cb3b4e7 SK |
914 | { .compatible = "qcom,soundwire-v1.3.0", .data = &swrm_v1_3_data }, |
915 | { .compatible = "qcom,soundwire-v1.5.1", .data = &swrm_v1_5_data }, | |
02efb49a SK |
916 | {/* sentinel */}, |
917 | }; | |
918 | ||
919 | MODULE_DEVICE_TABLE(of, qcom_swrm_of_match); | |
920 | ||
921 | static struct platform_driver qcom_swrm_driver = { | |
922 | .probe = &qcom_swrm_probe, | |
923 | .remove = &qcom_swrm_remove, | |
924 | .driver = { | |
925 | .name = "qcom-soundwire", | |
926 | .of_match_table = qcom_swrm_of_match, | |
927 | } | |
928 | }; | |
929 | module_platform_driver(qcom_swrm_driver); | |
930 | ||
931 | MODULE_DESCRIPTION("Qualcomm soundwire driver"); | |
932 | MODULE_LICENSE("GPL v2"); |