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