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> | |
abd9a604 | 10 | #include <linux/debugfs.h> |
02efb49a SK |
11 | #include <linux/of.h> |
12 | #include <linux/of_irq.h> | |
13 | #include <linux/of_device.h> | |
74e79da9 | 14 | #include <linux/pm_runtime.h> |
02efb49a | 15 | #include <linux/regmap.h> |
33ba0178 | 16 | #include <linux/reset.h> |
02efb49a | 17 | #include <linux/slab.h> |
04d46a7b | 18 | #include <linux/pm_wakeirq.h> |
02efb49a SK |
19 | #include <linux/slimbus.h> |
20 | #include <linux/soundwire/sdw.h> | |
21 | #include <linux/soundwire/sdw_registers.h> | |
22 | #include <sound/pcm_params.h> | |
23 | #include <sound/soc.h> | |
24 | #include "bus.h" | |
25 | ||
74e79da9 SK |
26 | #define SWRM_COMP_SW_RESET 0x008 |
27 | #define SWRM_COMP_STATUS 0x014 | |
cf43cd33 SK |
28 | #define SWRM_LINK_MANAGER_EE 0x018 |
29 | #define SWRM_EE_CPU 1 | |
74e79da9 | 30 | #define SWRM_FRM_GEN_ENABLED BIT(0) |
02efb49a SK |
31 | #define SWRM_COMP_HW_VERSION 0x00 |
32 | #define SWRM_COMP_CFG_ADDR 0x04 | |
33 | #define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK BIT(1) | |
34 | #define SWRM_COMP_CFG_ENABLE_MSK BIT(0) | |
35 | #define SWRM_COMP_PARAMS 0x100 | |
a661308c SK |
36 | #define SWRM_COMP_PARAMS_WR_FIFO_DEPTH GENMASK(14, 10) |
37 | #define SWRM_COMP_PARAMS_RD_FIFO_DEPTH GENMASK(19, 15) | |
02efb49a SK |
38 | #define SWRM_COMP_PARAMS_DOUT_PORTS_MASK GENMASK(4, 0) |
39 | #define SWRM_COMP_PARAMS_DIN_PORTS_MASK GENMASK(9, 5) | |
74e79da9 | 40 | #define SWRM_COMP_MASTER_ID 0x104 |
02efb49a SK |
41 | #define SWRM_INTERRUPT_STATUS 0x200 |
42 | #define SWRM_INTERRUPT_STATUS_RMSK GENMASK(16, 0) | |
c7d49c76 | 43 | #define SWRM_INTERRUPT_STATUS_SLAVE_PEND_IRQ BIT(0) |
02efb49a SK |
44 | #define SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED BIT(1) |
45 | #define SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS BIT(2) | |
c7d49c76 SK |
46 | #define SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET BIT(3) |
47 | #define SWRM_INTERRUPT_STATUS_RD_FIFO_OVERFLOW BIT(4) | |
48 | #define SWRM_INTERRUPT_STATUS_RD_FIFO_UNDERFLOW BIT(5) | |
49 | #define SWRM_INTERRUPT_STATUS_WR_CMD_FIFO_OVERFLOW BIT(6) | |
02efb49a | 50 | #define SWRM_INTERRUPT_STATUS_CMD_ERROR BIT(7) |
c7d49c76 SK |
51 | #define SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION BIT(8) |
52 | #define SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH BIT(9) | |
02efb49a | 53 | #define SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED BIT(10) |
c7d49c76 SK |
54 | #define SWRM_INTERRUPT_STATUS_BUS_RESET_FINISHED_V2 BIT(13) |
55 | #define SWRM_INTERRUPT_STATUS_CLK_STOP_FINISHED_V2 BIT(14) | |
56 | #define SWRM_INTERRUPT_STATUS_EXT_CLK_STOP_WAKEUP BIT(16) | |
57 | #define SWRM_INTERRUPT_MAX 17 | |
02efb49a SK |
58 | #define SWRM_INTERRUPT_MASK_ADDR 0x204 |
59 | #define SWRM_INTERRUPT_CLEAR 0x208 | |
82f5c70c | 60 | #define SWRM_INTERRUPT_CPU_EN 0x210 |
02efb49a SK |
61 | #define SWRM_CMD_FIFO_WR_CMD 0x300 |
62 | #define SWRM_CMD_FIFO_RD_CMD 0x304 | |
63 | #define SWRM_CMD_FIFO_CMD 0x308 | |
ddea6cf7 | 64 | #define SWRM_CMD_FIFO_FLUSH 0x1 |
02efb49a | 65 | #define SWRM_CMD_FIFO_STATUS 0x30C |
a661308c SK |
66 | #define SWRM_RD_CMD_FIFO_CNT_MASK GENMASK(20, 16) |
67 | #define SWRM_WR_CMD_FIFO_CNT_MASK GENMASK(12, 8) | |
02efb49a | 68 | #define SWRM_CMD_FIFO_CFG_ADDR 0x314 |
542d3491 | 69 | #define SWRM_CONTINUE_EXEC_ON_CMD_IGNORE BIT(31) |
02efb49a SK |
70 | #define SWRM_RD_WR_CMD_RETRIES 0x7 |
71 | #define SWRM_CMD_FIFO_RD_FIFO_ADDR 0x318 | |
ddea6cf7 | 72 | #define SWRM_RD_FIFO_CMD_ID_MASK GENMASK(11, 8) |
02efb49a | 73 | #define SWRM_ENUMERATOR_CFG_ADDR 0x500 |
a6e65819 SK |
74 | #define SWRM_ENUMERATOR_SLAVE_DEV_ID_1(m) (0x530 + 0x8 * (m)) |
75 | #define SWRM_ENUMERATOR_SLAVE_DEV_ID_2(m) (0x534 + 0x8 * (m)) | |
02efb49a | 76 | #define SWRM_MCP_FRAME_CTRL_BANK_ADDR(m) (0x101C + 0x40 * (m)) |
02efb49a SK |
77 | #define SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK GENMASK(2, 0) |
78 | #define SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK GENMASK(7, 3) | |
a866a049 SK |
79 | #define SWRM_MCP_BUS_CTRL 0x1044 |
80 | #define SWRM_MCP_BUS_CLK_START BIT(1) | |
02efb49a SK |
81 | #define SWRM_MCP_CFG_ADDR 0x1048 |
82 | #define SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK GENMASK(21, 17) | |
02efb49a SK |
83 | #define SWRM_DEF_CMD_NO_PINGS 0x1f |
84 | #define SWRM_MCP_STATUS 0x104C | |
85 | #define SWRM_MCP_STATUS_BANK_NUM_MASK BIT(0) | |
86 | #define SWRM_MCP_SLV_STATUS 0x1090 | |
87 | #define SWRM_MCP_SLV_STATUS_MASK GENMASK(1, 0) | |
c7d49c76 | 88 | #define SWRM_MCP_SLV_STATUS_SZ 2 |
02efb49a | 89 | #define SWRM_DP_PORT_CTRL_BANK(n, m) (0x1124 + 0x100 * (n - 1) + 0x40 * m) |
128eaf93 SK |
90 | #define SWRM_DP_PORT_CTRL_2_BANK(n, m) (0x1128 + 0x100 * (n - 1) + 0x40 * m) |
91 | #define SWRM_DP_BLOCK_CTRL_1(n) (0x112C + 0x100 * (n - 1)) | |
92 | #define SWRM_DP_BLOCK_CTRL2_BANK(n, m) (0x1130 + 0x100 * (n - 1) + 0x40 * m) | |
93 | #define SWRM_DP_PORT_HCTRL_BANK(n, m) (0x1134 + 0x100 * (n - 1) + 0x40 * m) | |
5ffba1fb | 94 | #define SWRM_DP_BLOCK_CTRL3_BANK(n, m) (0x1138 + 0x100 * (n - 1) + 0x40 * m) |
128eaf93 | 95 | #define SWRM_DIN_DPn_PCM_PORT_CTRL(n) (0x1054 + 0x100 * (n - 1)) |
abd9a604 | 96 | #define SWR_MSTR_MAX_REG_ADDR (0x1740) |
128eaf93 | 97 | |
02efb49a SK |
98 | #define SWRM_DP_PORT_CTRL_EN_CHAN_SHFT 0x18 |
99 | #define SWRM_DP_PORT_CTRL_OFFSET2_SHFT 0x10 | |
100 | #define SWRM_DP_PORT_CTRL_OFFSET1_SHFT 0x08 | |
101 | #define SWRM_AHB_BRIDGE_WR_DATA_0 0xc85 | |
102 | #define SWRM_AHB_BRIDGE_WR_ADDR_0 0xc89 | |
103 | #define SWRM_AHB_BRIDGE_RD_ADDR_0 0xc8d | |
104 | #define SWRM_AHB_BRIDGE_RD_DATA_0 0xc91 | |
105 | ||
106 | #define SWRM_REG_VAL_PACK(data, dev, id, reg) \ | |
107 | ((reg) | ((id) << 16) | ((dev) << 20) | ((data) << 24)) | |
108 | ||
02efb49a | 109 | #define MAX_FREQ_NUM 1 |
74da2724 | 110 | #define TIMEOUT_MS 100 |
ddea6cf7 | 111 | #define QCOM_SWRM_MAX_RD_LEN 0x1 |
02efb49a SK |
112 | #define QCOM_SDW_MAX_PORTS 14 |
113 | #define DEFAULT_CLK_FREQ 9600000 | |
114 | #define SWRM_MAX_DAIS 0xF | |
128eaf93 SK |
115 | #define SWR_INVALID_PARAM 0xFF |
116 | #define SWR_HSTOP_MAX_VAL 0xF | |
117 | #define SWR_HSTART_MIN_VAL 0x0 | |
ddea6cf7 SK |
118 | #define SWR_BROADCAST_CMD_ID 0x0F |
119 | #define SWR_MAX_CMD_ID 14 | |
120 | #define MAX_FIFO_RD_RETRY 3 | |
a661308c | 121 | #define SWR_OVERFLOW_RETRY_COUNT 30 |
74e79da9 SK |
122 | #define SWRM_LINK_STATUS_RETRY_CNT 100 |
123 | ||
124 | enum { | |
125 | MASTER_ID_WSA = 1, | |
126 | MASTER_ID_RX, | |
127 | MASTER_ID_TX | |
128 | }; | |
02efb49a SK |
129 | |
130 | struct qcom_swrm_port_config { | |
131 | u8 si; | |
132 | u8 off1; | |
133 | u8 off2; | |
5ffba1fb | 134 | u8 bp_mode; |
128eaf93 SK |
135 | u8 hstart; |
136 | u8 hstop; | |
137 | u8 word_length; | |
138 | u8 blk_group_count; | |
139 | u8 lane_control; | |
02efb49a SK |
140 | }; |
141 | ||
142 | struct qcom_swrm_ctrl { | |
143 | struct sdw_bus bus; | |
144 | struct device *dev; | |
145 | struct regmap *regmap; | |
82f5c70c | 146 | void __iomem *mmio; |
33ba0178 | 147 | struct reset_control *audio_cgcr; |
abd9a604 SK |
148 | #ifdef CONFIG_DEBUG_FS |
149 | struct dentry *debugfs; | |
150 | #endif | |
ddea6cf7 | 151 | struct completion broadcast; |
06dd9673 | 152 | struct completion enumeration; |
02efb49a | 153 | struct work_struct slave_work; |
02efb49a SK |
154 | /* Port alloc/free lock */ |
155 | struct mutex port_lock; | |
156 | struct clk *hclk; | |
157 | u8 wr_cmd_id; | |
158 | u8 rd_cmd_id; | |
159 | int irq; | |
160 | unsigned int version; | |
04d46a7b | 161 | int wake_irq; |
02efb49a SK |
162 | int num_din_ports; |
163 | int num_dout_ports; | |
8cb3b4e7 SK |
164 | int cols_index; |
165 | int rows_index; | |
02efb49a SK |
166 | unsigned long dout_port_mask; |
167 | unsigned long din_port_mask; | |
c7d49c76 | 168 | u32 intr_mask; |
ddea6cf7 SK |
169 | u8 rcmd_id; |
170 | u8 wcmd_id; | |
02efb49a SK |
171 | struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS]; |
172 | struct sdw_stream_runtime *sruntime[SWRM_MAX_DAIS]; | |
4ef3f2af | 173 | enum sdw_slave_status status[SDW_MAX_DEVICES + 1]; |
02efb49a SK |
174 | int (*reg_read)(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val); |
175 | int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val); | |
a6e65819 | 176 | u32 slave_status; |
a661308c SK |
177 | u32 wr_fifo_depth; |
178 | u32 rd_fifo_depth; | |
74e79da9 | 179 | bool clock_stop_not_supported; |
02efb49a SK |
180 | }; |
181 | ||
8cb3b4e7 SK |
182 | struct qcom_swrm_data { |
183 | u32 default_cols; | |
184 | u32 default_rows; | |
1fd0d85a | 185 | bool sw_clk_gate_required; |
8cb3b4e7 SK |
186 | }; |
187 | ||
35732a06 | 188 | static const struct qcom_swrm_data swrm_v1_3_data = { |
8cb3b4e7 SK |
189 | .default_rows = 48, |
190 | .default_cols = 16, | |
191 | }; | |
192 | ||
35732a06 | 193 | static const struct qcom_swrm_data swrm_v1_5_data = { |
8cb3b4e7 SK |
194 | .default_rows = 50, |
195 | .default_cols = 16, | |
196 | }; | |
197 | ||
3f4a7026 SRM |
198 | static const struct qcom_swrm_data swrm_v1_6_data = { |
199 | .default_rows = 50, | |
200 | .default_cols = 16, | |
201 | .sw_clk_gate_required = true, | |
202 | }; | |
203 | ||
02efb49a SK |
204 | #define to_qcom_sdw(b) container_of(b, struct qcom_swrm_ctrl, bus) |
205 | ||
d1df23fe | 206 | static int qcom_swrm_ahb_reg_read(struct qcom_swrm_ctrl *ctrl, int reg, |
02efb49a SK |
207 | u32 *val) |
208 | { | |
209 | struct regmap *wcd_regmap = ctrl->regmap; | |
210 | int ret; | |
211 | ||
212 | /* pg register + offset */ | |
213 | ret = regmap_bulk_write(wcd_regmap, SWRM_AHB_BRIDGE_RD_ADDR_0, | |
214 | (u8 *)®, 4); | |
215 | if (ret < 0) | |
216 | return SDW_CMD_FAIL; | |
217 | ||
218 | ret = regmap_bulk_read(wcd_regmap, SWRM_AHB_BRIDGE_RD_DATA_0, | |
219 | val, 4); | |
220 | if (ret < 0) | |
221 | return SDW_CMD_FAIL; | |
222 | ||
223 | return SDW_CMD_OK; | |
224 | } | |
225 | ||
226 | static int qcom_swrm_ahb_reg_write(struct qcom_swrm_ctrl *ctrl, | |
227 | int reg, int val) | |
228 | { | |
229 | struct regmap *wcd_regmap = ctrl->regmap; | |
230 | int ret; | |
231 | /* pg register + offset */ | |
232 | ret = regmap_bulk_write(wcd_regmap, SWRM_AHB_BRIDGE_WR_DATA_0, | |
233 | (u8 *)&val, 4); | |
234 | if (ret) | |
235 | return SDW_CMD_FAIL; | |
236 | ||
237 | /* write address register */ | |
238 | ret = regmap_bulk_write(wcd_regmap, SWRM_AHB_BRIDGE_WR_ADDR_0, | |
239 | (u8 *)®, 4); | |
240 | if (ret) | |
241 | return SDW_CMD_FAIL; | |
242 | ||
243 | return SDW_CMD_OK; | |
244 | } | |
245 | ||
82f5c70c JM |
246 | static int qcom_swrm_cpu_reg_read(struct qcom_swrm_ctrl *ctrl, int reg, |
247 | u32 *val) | |
248 | { | |
249 | *val = readl(ctrl->mmio + reg); | |
250 | return SDW_CMD_OK; | |
251 | } | |
252 | ||
253 | static int qcom_swrm_cpu_reg_write(struct qcom_swrm_ctrl *ctrl, int reg, | |
254 | int val) | |
255 | { | |
256 | writel(val, ctrl->mmio + reg); | |
257 | return SDW_CMD_OK; | |
258 | } | |
259 | ||
ddea6cf7 SK |
260 | static u32 swrm_get_packed_reg_val(u8 *cmd_id, u8 cmd_data, |
261 | u8 dev_addr, u16 reg_addr) | |
02efb49a | 262 | { |
02efb49a | 263 | u32 val; |
ddea6cf7 | 264 | u8 id = *cmd_id; |
02efb49a | 265 | |
ddea6cf7 SK |
266 | if (id != SWR_BROADCAST_CMD_ID) { |
267 | if (id < SWR_MAX_CMD_ID) | |
268 | id += 1; | |
269 | else | |
270 | id = 0; | |
271 | *cmd_id = id; | |
272 | } | |
273 | val = SWRM_REG_VAL_PACK(cmd_data, dev_addr, id, reg_addr); | |
02efb49a | 274 | |
ddea6cf7 | 275 | return val; |
02efb49a SK |
276 | } |
277 | ||
a661308c SK |
278 | static int swrm_wait_for_rd_fifo_avail(struct qcom_swrm_ctrl *swrm) |
279 | { | |
280 | u32 fifo_outstanding_data, value; | |
281 | int fifo_retry_count = SWR_OVERFLOW_RETRY_COUNT; | |
282 | ||
283 | do { | |
284 | /* Check for fifo underflow during read */ | |
285 | swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value); | |
286 | fifo_outstanding_data = FIELD_GET(SWRM_RD_CMD_FIFO_CNT_MASK, value); | |
287 | ||
288 | /* Check if read data is available in read fifo */ | |
289 | if (fifo_outstanding_data > 0) | |
290 | return 0; | |
291 | ||
292 | usleep_range(500, 510); | |
293 | } while (fifo_retry_count--); | |
294 | ||
295 | if (fifo_outstanding_data == 0) { | |
296 | dev_err_ratelimited(swrm->dev, "%s err read underflow\n", __func__); | |
297 | return -EIO; | |
298 | } | |
299 | ||
300 | return 0; | |
301 | } | |
302 | ||
303 | static int swrm_wait_for_wr_fifo_avail(struct qcom_swrm_ctrl *swrm) | |
304 | { | |
305 | u32 fifo_outstanding_cmds, value; | |
306 | int fifo_retry_count = SWR_OVERFLOW_RETRY_COUNT; | |
307 | ||
308 | do { | |
309 | /* Check for fifo overflow during write */ | |
310 | swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value); | |
311 | fifo_outstanding_cmds = FIELD_GET(SWRM_WR_CMD_FIFO_CNT_MASK, value); | |
312 | ||
313 | /* Check for space in write fifo before writing */ | |
314 | if (fifo_outstanding_cmds < swrm->wr_fifo_depth) | |
315 | return 0; | |
316 | ||
317 | usleep_range(500, 510); | |
318 | } while (fifo_retry_count--); | |
319 | ||
320 | if (fifo_outstanding_cmds == swrm->wr_fifo_depth) { | |
321 | dev_err_ratelimited(swrm->dev, "%s err write overflow\n", __func__); | |
322 | return -EIO; | |
323 | } | |
324 | ||
325 | return 0; | |
326 | } | |
ddea6cf7 SK |
327 | |
328 | static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl *swrm, u8 cmd_data, | |
329 | u8 dev_addr, u16 reg_addr) | |
02efb49a | 330 | { |
02efb49a | 331 | |
ddea6cf7 SK |
332 | u32 val; |
333 | int ret = 0; | |
334 | u8 cmd_id = 0x0; | |
02efb49a | 335 | |
ddea6cf7 SK |
336 | if (dev_addr == SDW_BROADCAST_DEV_NUM) { |
337 | cmd_id = SWR_BROADCAST_CMD_ID; | |
338 | val = swrm_get_packed_reg_val(&cmd_id, cmd_data, | |
339 | dev_addr, reg_addr); | |
340 | } else { | |
341 | val = swrm_get_packed_reg_val(&swrm->wcmd_id, cmd_data, | |
342 | dev_addr, reg_addr); | |
343 | } | |
02efb49a | 344 | |
a661308c SK |
345 | if (swrm_wait_for_wr_fifo_avail(swrm)) |
346 | return SDW_CMD_FAIL_OTHER; | |
347 | ||
f936fa7a SK |
348 | if (cmd_id == SWR_BROADCAST_CMD_ID) |
349 | reinit_completion(&swrm->broadcast); | |
350 | ||
ddea6cf7 SK |
351 | /* Its assumed that write is okay as we do not get any status back */ |
352 | swrm->reg_write(swrm, SWRM_CMD_FIFO_WR_CMD, val); | |
353 | ||
354 | /* version 1.3 or less */ | |
355 | if (swrm->version <= 0x01030000) | |
356 | usleep_range(150, 155); | |
357 | ||
358 | if (cmd_id == SWR_BROADCAST_CMD_ID) { | |
359 | /* | |
360 | * sleep for 10ms for MSM soundwire variant to allow broadcast | |
361 | * command to complete. | |
362 | */ | |
363 | ret = wait_for_completion_timeout(&swrm->broadcast, | |
364 | msecs_to_jiffies(TIMEOUT_MS)); | |
365 | if (!ret) | |
366 | ret = SDW_CMD_IGNORED; | |
367 | else | |
368 | ret = SDW_CMD_OK; | |
02efb49a | 369 | |
02efb49a SK |
370 | } else { |
371 | ret = SDW_CMD_OK; | |
372 | } | |
ddea6cf7 SK |
373 | return ret; |
374 | } | |
02efb49a | 375 | |
ddea6cf7 SK |
376 | static int qcom_swrm_cmd_fifo_rd_cmd(struct qcom_swrm_ctrl *swrm, |
377 | u8 dev_addr, u16 reg_addr, | |
378 | u32 len, u8 *rval) | |
379 | { | |
380 | u32 cmd_data, cmd_id, val, retry_attempt = 0; | |
381 | ||
382 | val = swrm_get_packed_reg_val(&swrm->rcmd_id, len, dev_addr, reg_addr); | |
383 | ||
49a46731 SK |
384 | /* |
385 | * Check for outstanding cmd wrt. write fifo depth to avoid | |
386 | * overflow as read will also increase write fifo cnt. | |
387 | */ | |
388 | swrm_wait_for_wr_fifo_avail(swrm); | |
389 | ||
ddea6cf7 SK |
390 | /* wait for FIFO RD to complete to avoid overflow */ |
391 | usleep_range(100, 105); | |
392 | swrm->reg_write(swrm, SWRM_CMD_FIFO_RD_CMD, val); | |
393 | /* wait for FIFO RD CMD complete to avoid overflow */ | |
394 | usleep_range(250, 255); | |
395 | ||
a661308c SK |
396 | if (swrm_wait_for_rd_fifo_avail(swrm)) |
397 | return SDW_CMD_FAIL_OTHER; | |
398 | ||
ddea6cf7 SK |
399 | do { |
400 | swrm->reg_read(swrm, SWRM_CMD_FIFO_RD_FIFO_ADDR, &cmd_data); | |
401 | rval[0] = cmd_data & 0xFF; | |
402 | cmd_id = FIELD_GET(SWRM_RD_FIFO_CMD_ID_MASK, cmd_data); | |
403 | ||
404 | if (cmd_id != swrm->rcmd_id) { | |
405 | if (retry_attempt < (MAX_FIFO_RD_RETRY - 1)) { | |
406 | /* wait 500 us before retry on fifo read failure */ | |
407 | usleep_range(500, 505); | |
408 | swrm->reg_write(swrm, SWRM_CMD_FIFO_CMD, | |
409 | SWRM_CMD_FIFO_FLUSH); | |
410 | swrm->reg_write(swrm, SWRM_CMD_FIFO_RD_CMD, val); | |
411 | } | |
412 | retry_attempt++; | |
413 | } else { | |
414 | return SDW_CMD_OK; | |
415 | } | |
02efb49a | 416 | |
ddea6cf7 | 417 | } while (retry_attempt < MAX_FIFO_RD_RETRY); |
02efb49a | 418 | |
ddea6cf7 SK |
419 | dev_err(swrm->dev, "failed to read fifo: reg: 0x%x, rcmd_id: 0x%x,\ |
420 | dev_num: 0x%x, cmd_data: 0x%x\n", | |
421 | reg_addr, swrm->rcmd_id, dev_addr, cmd_data); | |
422 | ||
423 | return SDW_CMD_IGNORED; | |
02efb49a SK |
424 | } |
425 | ||
c7d49c76 SK |
426 | static int qcom_swrm_get_alert_slave_dev_num(struct qcom_swrm_ctrl *ctrl) |
427 | { | |
428 | u32 val, status; | |
429 | int dev_num; | |
430 | ||
431 | ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val); | |
432 | ||
ed8d07ac | 433 | for (dev_num = 1; dev_num <= SDW_MAX_DEVICES; dev_num++) { |
c7d49c76 SK |
434 | status = (val >> (dev_num * SWRM_MCP_SLV_STATUS_SZ)); |
435 | ||
436 | if ((status & SWRM_MCP_SLV_STATUS_MASK) == SDW_SLAVE_ALERT) { | |
437 | ctrl->status[dev_num] = status; | |
438 | return dev_num; | |
439 | } | |
440 | } | |
441 | ||
442 | return -EINVAL; | |
443 | } | |
444 | ||
02efb49a SK |
445 | static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl) |
446 | { | |
447 | u32 val; | |
448 | int i; | |
449 | ||
450 | ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val); | |
a6e65819 | 451 | ctrl->slave_status = val; |
02efb49a | 452 | |
8039b6f3 | 453 | for (i = 1; i <= SDW_MAX_DEVICES; i++) { |
02efb49a SK |
454 | u32 s; |
455 | ||
456 | s = (val >> (i * 2)); | |
457 | s &= SWRM_MCP_SLV_STATUS_MASK; | |
458 | ctrl->status[i] = s; | |
459 | } | |
460 | } | |
461 | ||
a6e65819 SK |
462 | static void qcom_swrm_set_slave_dev_num(struct sdw_bus *bus, |
463 | struct sdw_slave *slave, int devnum) | |
464 | { | |
465 | struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); | |
466 | u32 status; | |
467 | ||
468 | ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &status); | |
469 | status = (status >> (devnum * SWRM_MCP_SLV_STATUS_SZ)); | |
470 | status &= SWRM_MCP_SLV_STATUS_MASK; | |
471 | ||
472 | if (status == SDW_SLAVE_ATTACHED) { | |
473 | if (slave) | |
474 | slave->dev_num = devnum; | |
475 | mutex_lock(&bus->bus_lock); | |
476 | set_bit(devnum, bus->assigned); | |
477 | mutex_unlock(&bus->bus_lock); | |
478 | } | |
479 | } | |
480 | ||
481 | static int qcom_swrm_enumerate(struct sdw_bus *bus) | |
482 | { | |
483 | struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); | |
484 | struct sdw_slave *slave, *_s; | |
485 | struct sdw_slave_id id; | |
486 | u32 val1, val2; | |
487 | bool found; | |
488 | u64 addr; | |
489 | int i; | |
490 | char *buf1 = (char *)&val1, *buf2 = (char *)&val2; | |
491 | ||
492 | for (i = 1; i <= SDW_MAX_DEVICES; i++) { | |
aa1262ca SK |
493 | /* do not continue if the status is Not Present */ |
494 | if (!ctrl->status[i]) | |
495 | continue; | |
496 | ||
a6e65819 SK |
497 | /*SCP_Devid5 - Devid 4*/ |
498 | ctrl->reg_read(ctrl, SWRM_ENUMERATOR_SLAVE_DEV_ID_1(i), &val1); | |
499 | ||
500 | /*SCP_Devid3 - DevId 2 Devid 1 Devid 0*/ | |
501 | ctrl->reg_read(ctrl, SWRM_ENUMERATOR_SLAVE_DEV_ID_2(i), &val2); | |
502 | ||
503 | if (!val1 && !val2) | |
504 | break; | |
505 | ||
506 | addr = buf2[1] | (buf2[0] << 8) | (buf1[3] << 16) | | |
507 | ((u64)buf1[2] << 24) | ((u64)buf1[1] << 32) | | |
508 | ((u64)buf1[0] << 40); | |
509 | ||
510 | sdw_extract_slave_id(bus, addr, &id); | |
511 | found = false; | |
512 | /* Now compare with entries */ | |
513 | list_for_each_entry_safe(slave, _s, &bus->slaves, node) { | |
514 | if (sdw_compare_devid(slave, id) == 0) { | |
515 | qcom_swrm_set_slave_dev_num(bus, slave, i); | |
516 | found = true; | |
517 | break; | |
518 | } | |
519 | } | |
520 | ||
521 | if (!found) { | |
522 | qcom_swrm_set_slave_dev_num(bus, NULL, i); | |
523 | sdw_slave_add(bus, &id, NULL); | |
524 | } | |
525 | } | |
526 | ||
06dd9673 | 527 | complete(&ctrl->enumeration); |
a6e65819 SK |
528 | return 0; |
529 | } | |
530 | ||
04d46a7b SK |
531 | static irqreturn_t qcom_swrm_wake_irq_handler(int irq, void *dev_id) |
532 | { | |
533 | struct qcom_swrm_ctrl *swrm = dev_id; | |
534 | int ret; | |
535 | ||
57ed510b | 536 | ret = pm_runtime_resume_and_get(swrm->dev); |
04d46a7b SK |
537 | if (ret < 0 && ret != -EACCES) { |
538 | dev_err_ratelimited(swrm->dev, | |
57ed510b | 539 | "pm_runtime_resume_and_get failed in %s, ret %d\n", |
04d46a7b | 540 | __func__, ret); |
f6ee6c84 | 541 | return ret; |
04d46a7b SK |
542 | } |
543 | ||
544 | if (swrm->wake_irq > 0) { | |
545 | if (!irqd_irq_disabled(irq_get_irq_data(swrm->wake_irq))) | |
546 | disable_irq_nosync(swrm->wake_irq); | |
547 | } | |
548 | ||
549 | pm_runtime_mark_last_busy(swrm->dev); | |
550 | pm_runtime_put_autosuspend(swrm->dev); | |
551 | ||
552 | return IRQ_HANDLED; | |
553 | } | |
554 | ||
02efb49a SK |
555 | static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id) |
556 | { | |
c7d49c76 | 557 | struct qcom_swrm_ctrl *swrm = dev_id; |
a6e65819 | 558 | u32 value, intr_sts, intr_sts_masked, slave_status; |
c7d49c76 | 559 | u32 i; |
b26b4874 | 560 | int devnum; |
c7d49c76 | 561 | int ret = IRQ_HANDLED; |
74e79da9 | 562 | clk_prepare_enable(swrm->hclk); |
02efb49a | 563 | |
c7d49c76 SK |
564 | swrm->reg_read(swrm, SWRM_INTERRUPT_STATUS, &intr_sts); |
565 | intr_sts_masked = intr_sts & swrm->intr_mask; | |
02efb49a | 566 | |
c7d49c76 SK |
567 | do { |
568 | for (i = 0; i < SWRM_INTERRUPT_MAX; i++) { | |
569 | value = intr_sts_masked & BIT(i); | |
570 | if (!value) | |
571 | continue; | |
572 | ||
573 | switch (value) { | |
574 | case SWRM_INTERRUPT_STATUS_SLAVE_PEND_IRQ: | |
575 | devnum = qcom_swrm_get_alert_slave_dev_num(swrm); | |
576 | if (devnum < 0) { | |
577 | dev_err_ratelimited(swrm->dev, | |
578 | "no slave alert found.spurious interrupt\n"); | |
579 | } else { | |
580 | sdw_handle_slave_status(&swrm->bus, swrm->status); | |
581 | } | |
582 | ||
583 | break; | |
584 | case SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED: | |
585 | case SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS: | |
ba8ec0f6 | 586 | dev_dbg_ratelimited(swrm->dev, "SWR new slave attached\n"); |
a6e65819 SK |
587 | swrm->reg_read(swrm, SWRM_MCP_SLV_STATUS, &slave_status); |
588 | if (swrm->slave_status == slave_status) { | |
ba8ec0f6 | 589 | dev_dbg(swrm->dev, "Slave status not changed %x\n", |
a6e65819 SK |
590 | slave_status); |
591 | } else { | |
592 | qcom_swrm_get_device_status(swrm); | |
593 | qcom_swrm_enumerate(&swrm->bus); | |
594 | sdw_handle_slave_status(&swrm->bus, swrm->status); | |
595 | } | |
c7d49c76 SK |
596 | break; |
597 | case SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET: | |
598 | dev_err_ratelimited(swrm->dev, | |
599 | "%s: SWR bus clsh detected\n", | |
600 | __func__); | |
601 | swrm->intr_mask &= ~SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET; | |
602 | swrm->reg_write(swrm, SWRM_INTERRUPT_CPU_EN, swrm->intr_mask); | |
603 | break; | |
604 | case SWRM_INTERRUPT_STATUS_RD_FIFO_OVERFLOW: | |
605 | swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value); | |
606 | dev_err_ratelimited(swrm->dev, | |
607 | "%s: SWR read FIFO overflow fifo status 0x%x\n", | |
608 | __func__, value); | |
609 | break; | |
610 | case SWRM_INTERRUPT_STATUS_RD_FIFO_UNDERFLOW: | |
611 | swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value); | |
612 | dev_err_ratelimited(swrm->dev, | |
613 | "%s: SWR read FIFO underflow fifo status 0x%x\n", | |
614 | __func__, value); | |
615 | break; | |
616 | case SWRM_INTERRUPT_STATUS_WR_CMD_FIFO_OVERFLOW: | |
617 | swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value); | |
618 | dev_err(swrm->dev, | |
619 | "%s: SWR write FIFO overflow fifo status %x\n", | |
620 | __func__, value); | |
621 | swrm->reg_write(swrm, SWRM_CMD_FIFO_CMD, 0x1); | |
622 | break; | |
623 | case SWRM_INTERRUPT_STATUS_CMD_ERROR: | |
624 | swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value); | |
625 | dev_err_ratelimited(swrm->dev, | |
626 | "%s: SWR CMD error, fifo status 0x%x, flushing fifo\n", | |
627 | __func__, value); | |
628 | swrm->reg_write(swrm, SWRM_CMD_FIFO_CMD, 0x1); | |
629 | break; | |
630 | case SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION: | |
631 | dev_err_ratelimited(swrm->dev, | |
632 | "%s: SWR Port collision detected\n", | |
633 | __func__); | |
634 | swrm->intr_mask &= ~SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION; | |
635 | swrm->reg_write(swrm, | |
636 | SWRM_INTERRUPT_CPU_EN, swrm->intr_mask); | |
637 | break; | |
638 | case SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH: | |
639 | dev_err_ratelimited(swrm->dev, | |
640 | "%s: SWR read enable valid mismatch\n", | |
641 | __func__); | |
642 | swrm->intr_mask &= | |
643 | ~SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH; | |
644 | swrm->reg_write(swrm, | |
645 | SWRM_INTERRUPT_CPU_EN, swrm->intr_mask); | |
646 | break; | |
647 | case SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED: | |
648 | complete(&swrm->broadcast); | |
649 | break; | |
650 | case SWRM_INTERRUPT_STATUS_BUS_RESET_FINISHED_V2: | |
651 | break; | |
652 | case SWRM_INTERRUPT_STATUS_CLK_STOP_FINISHED_V2: | |
653 | break; | |
654 | case SWRM_INTERRUPT_STATUS_EXT_CLK_STOP_WAKEUP: | |
655 | break; | |
656 | default: | |
657 | dev_err_ratelimited(swrm->dev, | |
658 | "%s: SWR unknown interrupt value: %d\n", | |
659 | __func__, value); | |
660 | ret = IRQ_NONE; | |
661 | break; | |
662 | } | |
663 | } | |
664 | swrm->reg_write(swrm, SWRM_INTERRUPT_CLEAR, intr_sts); | |
665 | swrm->reg_read(swrm, SWRM_INTERRUPT_STATUS, &intr_sts); | |
666 | intr_sts_masked = intr_sts & swrm->intr_mask; | |
667 | } while (intr_sts_masked); | |
02efb49a | 668 | |
74e79da9 | 669 | clk_disable_unprepare(swrm->hclk); |
c7d49c76 | 670 | return ret; |
02efb49a | 671 | } |
ddea6cf7 | 672 | |
02efb49a SK |
673 | static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) |
674 | { | |
675 | u32 val; | |
676 | ||
677 | /* Clear Rows and Cols */ | |
8cb3b4e7 SK |
678 | val = FIELD_PREP(SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK, ctrl->rows_index); |
679 | val |= FIELD_PREP(SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK, ctrl->cols_index); | |
02efb49a | 680 | |
33ba0178 SRM |
681 | reset_control_reset(ctrl->audio_cgcr); |
682 | ||
02efb49a SK |
683 | ctrl->reg_write(ctrl, SWRM_MCP_FRAME_CTRL_BANK_ADDR(0), val); |
684 | ||
a6e65819 SK |
685 | /* Enable Auto enumeration */ |
686 | ctrl->reg_write(ctrl, SWRM_ENUMERATOR_CFG_ADDR, 1); | |
02efb49a | 687 | |
c7d49c76 | 688 | ctrl->intr_mask = SWRM_INTERRUPT_STATUS_RMSK; |
02efb49a SK |
689 | /* Mask soundwire interrupts */ |
690 | ctrl->reg_write(ctrl, SWRM_INTERRUPT_MASK_ADDR, | |
691 | SWRM_INTERRUPT_STATUS_RMSK); | |
692 | ||
693 | /* Configure No pings */ | |
694 | ctrl->reg_read(ctrl, SWRM_MCP_CFG_ADDR, &val); | |
578ddced | 695 | u32p_replace_bits(&val, SWRM_DEF_CMD_NO_PINGS, SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK); |
02efb49a SK |
696 | ctrl->reg_write(ctrl, SWRM_MCP_CFG_ADDR, val); |
697 | ||
cf43cd33 SK |
698 | if (ctrl->version >= 0x01070000) { |
699 | ctrl->reg_write(ctrl, SWRM_LINK_MANAGER_EE, SWRM_EE_CPU); | |
700 | ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL, | |
701 | SWRM_MCP_BUS_CLK_START << SWRM_EE_CPU); | |
702 | } else { | |
703 | ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL, SWRM_MCP_BUS_CLK_START); | |
704 | } | |
705 | ||
02efb49a | 706 | /* Configure number of retries of a read/write cmd */ |
bd934f77 | 707 | if (ctrl->version >= 0x01050001) { |
542d3491 SK |
708 | /* Only for versions >= 1.5.1 */ |
709 | ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR, | |
710 | SWRM_RD_WR_CMD_RETRIES | | |
711 | SWRM_CONTINUE_EXEC_ON_CMD_IGNORE); | |
712 | } else { | |
713 | ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR, | |
714 | SWRM_RD_WR_CMD_RETRIES); | |
715 | } | |
02efb49a SK |
716 | |
717 | /* Set IRQ to PULSE */ | |
718 | ctrl->reg_write(ctrl, SWRM_COMP_CFG_ADDR, | |
719 | SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK | | |
720 | SWRM_COMP_CFG_ENABLE_MSK); | |
82f5c70c JM |
721 | |
722 | /* enable CPU IRQs */ | |
723 | if (ctrl->mmio) { | |
724 | ctrl->reg_write(ctrl, SWRM_INTERRUPT_CPU_EN, | |
725 | SWRM_INTERRUPT_STATUS_RMSK); | |
726 | } | |
a6e65819 | 727 | ctrl->slave_status = 0; |
a661308c SK |
728 | ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val); |
729 | ctrl->rd_fifo_depth = FIELD_GET(SWRM_COMP_PARAMS_RD_FIFO_DEPTH, val); | |
730 | ctrl->wr_fifo_depth = FIELD_GET(SWRM_COMP_PARAMS_WR_FIFO_DEPTH, val); | |
731 | ||
02efb49a SK |
732 | return 0; |
733 | } | |
734 | ||
735 | static enum sdw_command_response qcom_swrm_xfer_msg(struct sdw_bus *bus, | |
736 | struct sdw_msg *msg) | |
737 | { | |
738 | struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); | |
739 | int ret, i, len; | |
740 | ||
741 | if (msg->flags == SDW_MSG_FLAG_READ) { | |
742 | for (i = 0; i < msg->len;) { | |
743 | if ((msg->len - i) < QCOM_SWRM_MAX_RD_LEN) | |
744 | len = msg->len - i; | |
745 | else | |
746 | len = QCOM_SWRM_MAX_RD_LEN; | |
747 | ||
748 | ret = qcom_swrm_cmd_fifo_rd_cmd(ctrl, msg->dev_num, | |
749 | msg->addr + i, len, | |
750 | &msg->buf[i]); | |
751 | if (ret) | |
752 | return ret; | |
753 | ||
754 | i = i + len; | |
755 | } | |
756 | } else if (msg->flags == SDW_MSG_FLAG_WRITE) { | |
757 | for (i = 0; i < msg->len; i++) { | |
758 | ret = qcom_swrm_cmd_fifo_wr_cmd(ctrl, msg->buf[i], | |
759 | msg->dev_num, | |
760 | msg->addr + i); | |
761 | if (ret) | |
762 | return SDW_CMD_IGNORED; | |
763 | } | |
764 | } | |
765 | ||
766 | return SDW_CMD_OK; | |
767 | } | |
768 | ||
769 | static int qcom_swrm_pre_bank_switch(struct sdw_bus *bus) | |
770 | { | |
771 | u32 reg = SWRM_MCP_FRAME_CTRL_BANK_ADDR(bus->params.next_bank); | |
772 | struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); | |
773 | u32 val; | |
774 | ||
775 | ctrl->reg_read(ctrl, reg, &val); | |
776 | ||
8cb3b4e7 SK |
777 | u32p_replace_bits(&val, ctrl->cols_index, SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK); |
778 | u32p_replace_bits(&val, ctrl->rows_index, SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK); | |
02efb49a SK |
779 | |
780 | return ctrl->reg_write(ctrl, reg, val); | |
781 | } | |
782 | ||
783 | static int qcom_swrm_port_params(struct sdw_bus *bus, | |
784 | struct sdw_port_params *p_params, | |
785 | unsigned int bank) | |
786 | { | |
128eaf93 SK |
787 | struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); |
788 | ||
789 | return ctrl->reg_write(ctrl, SWRM_DP_BLOCK_CTRL_1(p_params->num), | |
790 | p_params->bps - 1); | |
791 | ||
02efb49a SK |
792 | } |
793 | ||
794 | static int qcom_swrm_transport_params(struct sdw_bus *bus, | |
795 | struct sdw_transport_params *params, | |
796 | enum sdw_reg_bank bank) | |
797 | { | |
798 | struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); | |
128eaf93 | 799 | struct qcom_swrm_port_config *pcfg; |
02efb49a | 800 | u32 value; |
5ffba1fb SK |
801 | int reg = SWRM_DP_PORT_CTRL_BANK((params->port_num), bank); |
802 | int ret; | |
02efb49a | 803 | |
9916c02c | 804 | pcfg = &ctrl->pconfig[params->port_num]; |
128eaf93 SK |
805 | |
806 | value = pcfg->off1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT; | |
807 | value |= pcfg->off2 << SWRM_DP_PORT_CTRL_OFFSET2_SHFT; | |
808 | value |= pcfg->si; | |
02efb49a | 809 | |
5ffba1fb | 810 | ret = ctrl->reg_write(ctrl, reg, value); |
e729e0fd SK |
811 | if (ret) |
812 | goto err; | |
5ffba1fb | 813 | |
128eaf93 SK |
814 | if (pcfg->lane_control != SWR_INVALID_PARAM) { |
815 | reg = SWRM_DP_PORT_CTRL_2_BANK(params->port_num, bank); | |
816 | value = pcfg->lane_control; | |
817 | ret = ctrl->reg_write(ctrl, reg, value); | |
e729e0fd SK |
818 | if (ret) |
819 | goto err; | |
128eaf93 | 820 | } |
5ffba1fb | 821 | |
128eaf93 SK |
822 | if (pcfg->blk_group_count != SWR_INVALID_PARAM) { |
823 | reg = SWRM_DP_BLOCK_CTRL2_BANK(params->port_num, bank); | |
824 | value = pcfg->blk_group_count; | |
825 | ret = ctrl->reg_write(ctrl, reg, value); | |
e729e0fd SK |
826 | if (ret) |
827 | goto err; | |
128eaf93 SK |
828 | } |
829 | ||
830 | if (pcfg->hstart != SWR_INVALID_PARAM | |
831 | && pcfg->hstop != SWR_INVALID_PARAM) { | |
832 | reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank); | |
833 | value = (pcfg->hstop << 4) | pcfg->hstart; | |
834 | ret = ctrl->reg_write(ctrl, reg, value); | |
835 | } else { | |
836 | reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank); | |
837 | value = (SWR_HSTOP_MAX_VAL << 4) | SWR_HSTART_MIN_VAL; | |
838 | ret = ctrl->reg_write(ctrl, reg, value); | |
839 | } | |
840 | ||
e729e0fd SK |
841 | if (ret) |
842 | goto err; | |
843 | ||
128eaf93 SK |
844 | if (pcfg->bp_mode != SWR_INVALID_PARAM) { |
845 | reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank); | |
846 | ret = ctrl->reg_write(ctrl, reg, pcfg->bp_mode); | |
5ffba1fb SK |
847 | } |
848 | ||
e729e0fd | 849 | err: |
5ffba1fb | 850 | return ret; |
02efb49a SK |
851 | } |
852 | ||
853 | static int qcom_swrm_port_enable(struct sdw_bus *bus, | |
854 | struct sdw_enable_ch *enable_ch, | |
855 | unsigned int bank) | |
856 | { | |
857 | u32 reg = SWRM_DP_PORT_CTRL_BANK(enable_ch->port_num, bank); | |
858 | struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); | |
859 | u32 val; | |
860 | ||
861 | ctrl->reg_read(ctrl, reg, &val); | |
862 | ||
863 | if (enable_ch->enable) | |
864 | val |= (enable_ch->ch_mask << SWRM_DP_PORT_CTRL_EN_CHAN_SHFT); | |
865 | else | |
866 | val &= ~(0xff << SWRM_DP_PORT_CTRL_EN_CHAN_SHFT); | |
867 | ||
868 | return ctrl->reg_write(ctrl, reg, val); | |
869 | } | |
870 | ||
51fe3881 | 871 | static const struct sdw_master_port_ops qcom_swrm_port_ops = { |
02efb49a SK |
872 | .dpn_set_port_params = qcom_swrm_port_params, |
873 | .dpn_set_port_transport_params = qcom_swrm_transport_params, | |
874 | .dpn_port_enable_ch = qcom_swrm_port_enable, | |
875 | }; | |
876 | ||
51fe3881 | 877 | static const struct sdw_master_ops qcom_swrm_ops = { |
02efb49a SK |
878 | .xfer_msg = qcom_swrm_xfer_msg, |
879 | .pre_bank_switch = qcom_swrm_pre_bank_switch, | |
880 | }; | |
881 | ||
882 | static int qcom_swrm_compute_params(struct sdw_bus *bus) | |
883 | { | |
884 | struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); | |
885 | struct sdw_master_runtime *m_rt; | |
886 | struct sdw_slave_runtime *s_rt; | |
887 | struct sdw_port_runtime *p_rt; | |
888 | struct qcom_swrm_port_config *pcfg; | |
eb5a9094 SK |
889 | struct sdw_slave *slave; |
890 | unsigned int m_port; | |
9916c02c | 891 | int i = 1; |
02efb49a SK |
892 | |
893 | list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { | |
894 | list_for_each_entry(p_rt, &m_rt->port_list, port_node) { | |
9916c02c | 895 | pcfg = &ctrl->pconfig[p_rt->num]; |
02efb49a | 896 | p_rt->transport_params.port_num = p_rt->num; |
128eaf93 SK |
897 | if (pcfg->word_length != SWR_INVALID_PARAM) { |
898 | sdw_fill_port_params(&p_rt->port_params, | |
899 | p_rt->num, pcfg->word_length + 1, | |
900 | SDW_PORT_FLOW_MODE_ISOCH, | |
901 | SDW_PORT_DATA_MODE_NORMAL); | |
902 | } | |
903 | ||
02efb49a SK |
904 | } |
905 | ||
906 | list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { | |
eb5a9094 | 907 | slave = s_rt->slave; |
02efb49a | 908 | list_for_each_entry(p_rt, &s_rt->port_list, port_node) { |
eb5a9094 SK |
909 | m_port = slave->m_port_map[p_rt->num]; |
910 | /* port config starts at offset 0 so -1 from actual port number */ | |
911 | if (m_port) | |
9916c02c | 912 | pcfg = &ctrl->pconfig[m_port]; |
eb5a9094 SK |
913 | else |
914 | pcfg = &ctrl->pconfig[i]; | |
02efb49a SK |
915 | p_rt->transport_params.port_num = p_rt->num; |
916 | p_rt->transport_params.sample_interval = | |
917 | pcfg->si + 1; | |
918 | p_rt->transport_params.offset1 = pcfg->off1; | |
919 | p_rt->transport_params.offset2 = pcfg->off2; | |
5ffba1fb | 920 | p_rt->transport_params.blk_pkg_mode = pcfg->bp_mode; |
128eaf93 SK |
921 | p_rt->transport_params.blk_grp_ctrl = pcfg->blk_group_count; |
922 | ||
923 | p_rt->transport_params.hstart = pcfg->hstart; | |
924 | p_rt->transport_params.hstop = pcfg->hstop; | |
925 | p_rt->transport_params.lane_ctrl = pcfg->lane_control; | |
926 | if (pcfg->word_length != SWR_INVALID_PARAM) { | |
927 | sdw_fill_port_params(&p_rt->port_params, | |
928 | p_rt->num, | |
929 | pcfg->word_length + 1, | |
930 | SDW_PORT_FLOW_MODE_ISOCH, | |
931 | SDW_PORT_DATA_MODE_NORMAL); | |
932 | } | |
02efb49a SK |
933 | i++; |
934 | } | |
935 | } | |
936 | } | |
937 | ||
938 | return 0; | |
939 | } | |
940 | ||
941 | static u32 qcom_swrm_freq_tbl[MAX_FREQ_NUM] = { | |
942 | DEFAULT_CLK_FREQ, | |
943 | }; | |
944 | ||
02efb49a SK |
945 | static void qcom_swrm_stream_free_ports(struct qcom_swrm_ctrl *ctrl, |
946 | struct sdw_stream_runtime *stream) | |
947 | { | |
948 | struct sdw_master_runtime *m_rt; | |
949 | struct sdw_port_runtime *p_rt; | |
950 | unsigned long *port_mask; | |
951 | ||
952 | mutex_lock(&ctrl->port_lock); | |
953 | ||
954 | list_for_each_entry(m_rt, &stream->master_list, stream_node) { | |
955 | if (m_rt->direction == SDW_DATA_DIR_RX) | |
956 | port_mask = &ctrl->dout_port_mask; | |
957 | else | |
958 | port_mask = &ctrl->din_port_mask; | |
959 | ||
960 | list_for_each_entry(p_rt, &m_rt->port_list, port_node) | |
650dfdb8 | 961 | clear_bit(p_rt->num, port_mask); |
02efb49a SK |
962 | } |
963 | ||
964 | mutex_unlock(&ctrl->port_lock); | |
965 | } | |
966 | ||
967 | static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, | |
968 | struct sdw_stream_runtime *stream, | |
969 | struct snd_pcm_hw_params *params, | |
970 | int direction) | |
971 | { | |
972 | struct sdw_port_config pconfig[QCOM_SDW_MAX_PORTS]; | |
973 | struct sdw_stream_config sconfig; | |
974 | struct sdw_master_runtime *m_rt; | |
975 | struct sdw_slave_runtime *s_rt; | |
976 | struct sdw_port_runtime *p_rt; | |
eb5a9094 | 977 | struct sdw_slave *slave; |
02efb49a SK |
978 | unsigned long *port_mask; |
979 | int i, maxport, pn, nports = 0, ret = 0; | |
eb5a9094 | 980 | unsigned int m_port; |
02efb49a SK |
981 | |
982 | mutex_lock(&ctrl->port_lock); | |
983 | list_for_each_entry(m_rt, &stream->master_list, stream_node) { | |
984 | if (m_rt->direction == SDW_DATA_DIR_RX) { | |
985 | maxport = ctrl->num_dout_ports; | |
986 | port_mask = &ctrl->dout_port_mask; | |
987 | } else { | |
988 | maxport = ctrl->num_din_ports; | |
989 | port_mask = &ctrl->din_port_mask; | |
990 | } | |
991 | ||
992 | list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { | |
eb5a9094 | 993 | slave = s_rt->slave; |
02efb49a | 994 | list_for_each_entry(p_rt, &s_rt->port_list, port_node) { |
eb5a9094 | 995 | m_port = slave->m_port_map[p_rt->num]; |
02efb49a | 996 | /* Port numbers start from 1 - 14*/ |
eb5a9094 SK |
997 | if (m_port) |
998 | pn = m_port; | |
999 | else | |
1000 | pn = find_first_zero_bit(port_mask, maxport); | |
1001 | ||
650dfdb8 | 1002 | if (pn > maxport) { |
02efb49a SK |
1003 | dev_err(ctrl->dev, "All ports busy\n"); |
1004 | ret = -EBUSY; | |
1005 | goto err; | |
1006 | } | |
1007 | set_bit(pn, port_mask); | |
650dfdb8 | 1008 | pconfig[nports].num = pn; |
02efb49a SK |
1009 | pconfig[nports].ch_mask = p_rt->ch_mask; |
1010 | nports++; | |
1011 | } | |
1012 | } | |
1013 | } | |
1014 | ||
1015 | if (direction == SNDRV_PCM_STREAM_CAPTURE) | |
1016 | sconfig.direction = SDW_DATA_DIR_TX; | |
1017 | else | |
1018 | sconfig.direction = SDW_DATA_DIR_RX; | |
1019 | ||
1020 | /* hw parameters wil be ignored as we only support PDM */ | |
1021 | sconfig.ch_count = 1; | |
1022 | sconfig.frame_rate = params_rate(params); | |
1023 | sconfig.type = stream->type; | |
1024 | sconfig.bps = 1; | |
1025 | sdw_stream_add_master(&ctrl->bus, &sconfig, pconfig, | |
1026 | nports, stream); | |
1027 | err: | |
1028 | if (ret) { | |
1029 | for (i = 0; i < nports; i++) | |
650dfdb8 | 1030 | clear_bit(pconfig[i].num, port_mask); |
02efb49a SK |
1031 | } |
1032 | ||
1033 | mutex_unlock(&ctrl->port_lock); | |
1034 | ||
1035 | return ret; | |
1036 | } | |
1037 | ||
1038 | static int qcom_swrm_hw_params(struct snd_pcm_substream *substream, | |
1039 | struct snd_pcm_hw_params *params, | |
1040 | struct snd_soc_dai *dai) | |
1041 | { | |
1042 | struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev); | |
1043 | struct sdw_stream_runtime *sruntime = ctrl->sruntime[dai->id]; | |
1044 | int ret; | |
1045 | ||
1046 | ret = qcom_swrm_stream_alloc_ports(ctrl, sruntime, params, | |
1047 | substream->stream); | |
1048 | if (ret) | |
1049 | qcom_swrm_stream_free_ports(ctrl, sruntime); | |
1050 | ||
1051 | return ret; | |
1052 | } | |
1053 | ||
1054 | static int qcom_swrm_hw_free(struct snd_pcm_substream *substream, | |
1055 | struct snd_soc_dai *dai) | |
1056 | { | |
1057 | struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev); | |
1058 | struct sdw_stream_runtime *sruntime = ctrl->sruntime[dai->id]; | |
1059 | ||
1060 | qcom_swrm_stream_free_ports(ctrl, sruntime); | |
1061 | sdw_stream_remove_master(&ctrl->bus, sruntime); | |
1062 | ||
1063 | return 0; | |
1064 | } | |
1065 | ||
1066 | static int qcom_swrm_set_sdw_stream(struct snd_soc_dai *dai, | |
1067 | void *stream, int direction) | |
1068 | { | |
1069 | struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev); | |
1070 | ||
1071 | ctrl->sruntime[dai->id] = stream; | |
1072 | ||
1073 | return 0; | |
1074 | } | |
1075 | ||
39ec6f99 SK |
1076 | static void *qcom_swrm_get_sdw_stream(struct snd_soc_dai *dai, int direction) |
1077 | { | |
1078 | struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev); | |
1079 | ||
1080 | return ctrl->sruntime[dai->id]; | |
1081 | } | |
1082 | ||
02efb49a SK |
1083 | static int qcom_swrm_startup(struct snd_pcm_substream *substream, |
1084 | struct snd_soc_dai *dai) | |
1085 | { | |
1086 | struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev); | |
1087 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
1088 | struct sdw_stream_runtime *sruntime; | |
ce83baca | 1089 | struct snd_soc_dai *codec_dai; |
02efb49a SK |
1090 | int ret, i; |
1091 | ||
57ed510b | 1092 | ret = pm_runtime_resume_and_get(ctrl->dev); |
74e79da9 SK |
1093 | if (ret < 0 && ret != -EACCES) { |
1094 | dev_err_ratelimited(ctrl->dev, | |
57ed510b | 1095 | "pm_runtime_resume_and_get failed in %s, ret %d\n", |
74e79da9 | 1096 | __func__, ret); |
74e79da9 SK |
1097 | return ret; |
1098 | } | |
1099 | ||
02efb49a SK |
1100 | sruntime = sdw_alloc_stream(dai->name); |
1101 | if (!sruntime) | |
1102 | return -ENOMEM; | |
1103 | ||
1104 | ctrl->sruntime[dai->id] = sruntime; | |
1105 | ||
c998ee30 | 1106 | for_each_rtd_codec_dais(rtd, i, codec_dai) { |
e8444560 PLB |
1107 | ret = snd_soc_dai_set_stream(codec_dai, sruntime, |
1108 | substream->stream); | |
02efb49a | 1109 | if (ret < 0 && ret != -ENOTSUPP) { |
e6cb15b5 | 1110 | dev_err(dai->dev, "Failed to set sdw stream on %s\n", |
ce83baca | 1111 | codec_dai->name); |
02efb49a SK |
1112 | sdw_release_stream(sruntime); |
1113 | return ret; | |
1114 | } | |
1115 | } | |
1116 | ||
1117 | return 0; | |
1118 | } | |
1119 | ||
1120 | static void qcom_swrm_shutdown(struct snd_pcm_substream *substream, | |
1121 | struct snd_soc_dai *dai) | |
1122 | { | |
1123 | struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev); | |
1124 | ||
1125 | sdw_release_stream(ctrl->sruntime[dai->id]); | |
1126 | ctrl->sruntime[dai->id] = NULL; | |
74e79da9 SK |
1127 | pm_runtime_mark_last_busy(ctrl->dev); |
1128 | pm_runtime_put_autosuspend(ctrl->dev); | |
1129 | ||
02efb49a SK |
1130 | } |
1131 | ||
1132 | static const struct snd_soc_dai_ops qcom_swrm_pdm_dai_ops = { | |
1133 | .hw_params = qcom_swrm_hw_params, | |
1134 | .hw_free = qcom_swrm_hw_free, | |
1135 | .startup = qcom_swrm_startup, | |
1136 | .shutdown = qcom_swrm_shutdown, | |
e8444560 PLB |
1137 | .set_stream = qcom_swrm_set_sdw_stream, |
1138 | .get_stream = qcom_swrm_get_sdw_stream, | |
02efb49a SK |
1139 | }; |
1140 | ||
1141 | static const struct snd_soc_component_driver qcom_swrm_dai_component = { | |
1142 | .name = "soundwire", | |
1143 | }; | |
1144 | ||
1145 | static int qcom_swrm_register_dais(struct qcom_swrm_ctrl *ctrl) | |
1146 | { | |
1147 | int num_dais = ctrl->num_dout_ports + ctrl->num_din_ports; | |
1148 | struct snd_soc_dai_driver *dais; | |
1149 | struct snd_soc_pcm_stream *stream; | |
1150 | struct device *dev = ctrl->dev; | |
1151 | int i; | |
1152 | ||
1153 | /* PDM dais are only tested for now */ | |
1154 | dais = devm_kcalloc(dev, num_dais, sizeof(*dais), GFP_KERNEL); | |
1155 | if (!dais) | |
1156 | return -ENOMEM; | |
1157 | ||
1158 | for (i = 0; i < num_dais; i++) { | |
1159 | dais[i].name = devm_kasprintf(dev, GFP_KERNEL, "SDW Pin%d", i); | |
1160 | if (!dais[i].name) | |
1161 | return -ENOMEM; | |
1162 | ||
1163 | if (i < ctrl->num_dout_ports) | |
1164 | stream = &dais[i].playback; | |
1165 | else | |
1166 | stream = &dais[i].capture; | |
1167 | ||
1168 | stream->channels_min = 1; | |
1169 | stream->channels_max = 1; | |
1170 | stream->rates = SNDRV_PCM_RATE_48000; | |
1171 | stream->formats = SNDRV_PCM_FMTBIT_S16_LE; | |
1172 | ||
1173 | dais[i].ops = &qcom_swrm_pdm_dai_ops; | |
1174 | dais[i].id = i; | |
1175 | } | |
1176 | ||
1177 | return devm_snd_soc_register_component(ctrl->dev, | |
1178 | &qcom_swrm_dai_component, | |
1179 | dais, num_dais); | |
1180 | } | |
1181 | ||
1182 | static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) | |
1183 | { | |
1184 | struct device_node *np = ctrl->dev->of_node; | |
1185 | u8 off1[QCOM_SDW_MAX_PORTS]; | |
1186 | u8 off2[QCOM_SDW_MAX_PORTS]; | |
1187 | u8 si[QCOM_SDW_MAX_PORTS]; | |
5ffba1fb | 1188 | u8 bp_mode[QCOM_SDW_MAX_PORTS] = { 0, }; |
128eaf93 SK |
1189 | u8 hstart[QCOM_SDW_MAX_PORTS]; |
1190 | u8 hstop[QCOM_SDW_MAX_PORTS]; | |
1191 | u8 word_length[QCOM_SDW_MAX_PORTS]; | |
1192 | u8 blk_group_count[QCOM_SDW_MAX_PORTS]; | |
1193 | u8 lane_control[QCOM_SDW_MAX_PORTS]; | |
02efb49a SK |
1194 | int i, ret, nports, val; |
1195 | ||
1196 | ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val); | |
1197 | ||
9972b90a VK |
1198 | ctrl->num_dout_ports = FIELD_GET(SWRM_COMP_PARAMS_DOUT_PORTS_MASK, val); |
1199 | ctrl->num_din_ports = FIELD_GET(SWRM_COMP_PARAMS_DIN_PORTS_MASK, val); | |
02efb49a SK |
1200 | |
1201 | ret = of_property_read_u32(np, "qcom,din-ports", &val); | |
1202 | if (ret) | |
1203 | return ret; | |
1204 | ||
1205 | if (val > ctrl->num_din_ports) | |
1206 | return -EINVAL; | |
1207 | ||
1208 | ctrl->num_din_ports = val; | |
1209 | ||
1210 | ret = of_property_read_u32(np, "qcom,dout-ports", &val); | |
1211 | if (ret) | |
1212 | return ret; | |
1213 | ||
1214 | if (val > ctrl->num_dout_ports) | |
1215 | return -EINVAL; | |
1216 | ||
1217 | ctrl->num_dout_ports = val; | |
1218 | ||
1219 | nports = ctrl->num_dout_ports + ctrl->num_din_ports; | |
650dfdb8 SK |
1220 | /* Valid port numbers are from 1-14, so mask out port 0 explicitly */ |
1221 | set_bit(0, &ctrl->dout_port_mask); | |
1222 | set_bit(0, &ctrl->din_port_mask); | |
02efb49a SK |
1223 | |
1224 | ret = of_property_read_u8_array(np, "qcom,ports-offset1", | |
1225 | off1, nports); | |
1226 | if (ret) | |
1227 | return ret; | |
1228 | ||
1229 | ret = of_property_read_u8_array(np, "qcom,ports-offset2", | |
1230 | off2, nports); | |
1231 | if (ret) | |
1232 | return ret; | |
1233 | ||
1234 | ret = of_property_read_u8_array(np, "qcom,ports-sinterval-low", | |
1235 | si, nports); | |
1236 | if (ret) | |
1237 | return ret; | |
1238 | ||
5ffba1fb SK |
1239 | ret = of_property_read_u8_array(np, "qcom,ports-block-pack-mode", |
1240 | bp_mode, nports); | |
da096fbc | 1241 | if (ret) { |
bb349fd2 | 1242 | if (ctrl->version <= 0x01030000) |
da096fbc SK |
1243 | memset(bp_mode, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); |
1244 | else | |
1245 | return ret; | |
1246 | } | |
a5943e4f | 1247 | |
128eaf93 SK |
1248 | memset(hstart, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); |
1249 | of_property_read_u8_array(np, "qcom,ports-hstart", hstart, nports); | |
1250 | ||
1251 | memset(hstop, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); | |
1252 | of_property_read_u8_array(np, "qcom,ports-hstop", hstop, nports); | |
1253 | ||
1254 | memset(word_length, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); | |
1255 | of_property_read_u8_array(np, "qcom,ports-word-length", word_length, nports); | |
1256 | ||
1257 | memset(blk_group_count, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); | |
1258 | of_property_read_u8_array(np, "qcom,ports-block-group-count", blk_group_count, nports); | |
1259 | ||
1260 | memset(lane_control, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); | |
1261 | of_property_read_u8_array(np, "qcom,ports-lane-control", lane_control, nports); | |
1262 | ||
02efb49a | 1263 | for (i = 0; i < nports; i++) { |
9916c02c SK |
1264 | /* Valid port number range is from 1-14 */ |
1265 | ctrl->pconfig[i + 1].si = si[i]; | |
1266 | ctrl->pconfig[i + 1].off1 = off1[i]; | |
1267 | ctrl->pconfig[i + 1].off2 = off2[i]; | |
1268 | ctrl->pconfig[i + 1].bp_mode = bp_mode[i]; | |
1269 | ctrl->pconfig[i + 1].hstart = hstart[i]; | |
1270 | ctrl->pconfig[i + 1].hstop = hstop[i]; | |
1271 | ctrl->pconfig[i + 1].word_length = word_length[i]; | |
1272 | ctrl->pconfig[i + 1].blk_group_count = blk_group_count[i]; | |
1273 | ctrl->pconfig[i + 1].lane_control = lane_control[i]; | |
02efb49a SK |
1274 | } |
1275 | ||
1276 | return 0; | |
1277 | } | |
1278 | ||
abd9a604 SK |
1279 | #ifdef CONFIG_DEBUG_FS |
1280 | static int swrm_reg_show(struct seq_file *s_file, void *data) | |
1281 | { | |
1282 | struct qcom_swrm_ctrl *swrm = s_file->private; | |
74e79da9 SK |
1283 | int reg, reg_val, ret; |
1284 | ||
57ed510b | 1285 | ret = pm_runtime_resume_and_get(swrm->dev); |
74e79da9 SK |
1286 | if (ret < 0 && ret != -EACCES) { |
1287 | dev_err_ratelimited(swrm->dev, | |
57ed510b | 1288 | "pm_runtime_resume_and_get failed in %s, ret %d\n", |
74e79da9 | 1289 | __func__, ret); |
f6ee6c84 | 1290 | return ret; |
74e79da9 | 1291 | } |
abd9a604 SK |
1292 | |
1293 | for (reg = 0; reg <= SWR_MSTR_MAX_REG_ADDR; reg += 4) { | |
1294 | swrm->reg_read(swrm, reg, ®_val); | |
1295 | seq_printf(s_file, "0x%.3x: 0x%.2x\n", reg, reg_val); | |
1296 | } | |
74e79da9 SK |
1297 | pm_runtime_mark_last_busy(swrm->dev); |
1298 | pm_runtime_put_autosuspend(swrm->dev); | |
1299 | ||
abd9a604 SK |
1300 | |
1301 | return 0; | |
1302 | } | |
1303 | DEFINE_SHOW_ATTRIBUTE(swrm_reg); | |
1304 | #endif | |
1305 | ||
02efb49a SK |
1306 | static int qcom_swrm_probe(struct platform_device *pdev) |
1307 | { | |
1308 | struct device *dev = &pdev->dev; | |
1309 | struct sdw_master_prop *prop; | |
1310 | struct sdw_bus_params *params; | |
1311 | struct qcom_swrm_ctrl *ctrl; | |
8cb3b4e7 | 1312 | const struct qcom_swrm_data *data; |
02efb49a SK |
1313 | int ret; |
1314 | u32 val; | |
1315 | ||
1316 | ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL); | |
1317 | if (!ctrl) | |
1318 | return -ENOMEM; | |
1319 | ||
8cb3b4e7 SK |
1320 | data = of_device_get_match_data(dev); |
1321 | ctrl->rows_index = sdw_find_row_index(data->default_rows); | |
1322 | ctrl->cols_index = sdw_find_col_index(data->default_cols); | |
47edc010 | 1323 | #if IS_REACHABLE(CONFIG_SLIMBUS) |
02efb49a | 1324 | if (dev->parent->bus == &slimbus_bus) { |
5bd77324 JM |
1325 | #else |
1326 | if (false) { | |
1327 | #endif | |
d1df23fe | 1328 | ctrl->reg_read = qcom_swrm_ahb_reg_read; |
02efb49a SK |
1329 | ctrl->reg_write = qcom_swrm_ahb_reg_write; |
1330 | ctrl->regmap = dev_get_regmap(dev->parent, NULL); | |
1331 | if (!ctrl->regmap) | |
1332 | return -EINVAL; | |
1333 | } else { | |
82f5c70c JM |
1334 | ctrl->reg_read = qcom_swrm_cpu_reg_read; |
1335 | ctrl->reg_write = qcom_swrm_cpu_reg_write; | |
1336 | ctrl->mmio = devm_platform_ioremap_resource(pdev, 0); | |
1337 | if (IS_ERR(ctrl->mmio)) | |
1338 | return PTR_ERR(ctrl->mmio); | |
02efb49a SK |
1339 | } |
1340 | ||
1fd0d85a | 1341 | if (data->sw_clk_gate_required) { |
1cdbfd4c SK |
1342 | ctrl->audio_cgcr = devm_reset_control_get_optional_exclusive(dev, "swr_audio_cgcr"); |
1343 | if (IS_ERR(ctrl->audio_cgcr)) { | |
1fd0d85a SRM |
1344 | dev_err(dev, "Failed to get cgcr reset ctrl required for SW gating\n"); |
1345 | ret = PTR_ERR(ctrl->audio_cgcr); | |
1346 | goto err_init; | |
1347 | } | |
1348 | } | |
1349 | ||
02efb49a | 1350 | ctrl->irq = of_irq_get(dev->of_node, 0); |
91b5cfc0 PLB |
1351 | if (ctrl->irq < 0) { |
1352 | ret = ctrl->irq; | |
1353 | goto err_init; | |
1354 | } | |
02efb49a SK |
1355 | |
1356 | ctrl->hclk = devm_clk_get(dev, "iface"); | |
91b5cfc0 PLB |
1357 | if (IS_ERR(ctrl->hclk)) { |
1358 | ret = PTR_ERR(ctrl->hclk); | |
1359 | goto err_init; | |
1360 | } | |
02efb49a SK |
1361 | |
1362 | clk_prepare_enable(ctrl->hclk); | |
1363 | ||
1364 | ctrl->dev = dev; | |
1365 | dev_set_drvdata(&pdev->dev, ctrl); | |
02efb49a | 1366 | mutex_init(&ctrl->port_lock); |
ddea6cf7 | 1367 | init_completion(&ctrl->broadcast); |
06dd9673 | 1368 | init_completion(&ctrl->enumeration); |
02efb49a | 1369 | |
02efb49a SK |
1370 | ctrl->bus.ops = &qcom_swrm_ops; |
1371 | ctrl->bus.port_ops = &qcom_swrm_port_ops; | |
1372 | ctrl->bus.compute_params = &qcom_swrm_compute_params; | |
74e79da9 | 1373 | ctrl->bus.clk_stop_timeout = 300; |
02efb49a SK |
1374 | |
1375 | ret = qcom_swrm_get_port_config(ctrl); | |
1376 | if (ret) | |
91b5cfc0 | 1377 | goto err_clk; |
02efb49a SK |
1378 | |
1379 | params = &ctrl->bus.params; | |
1380 | params->max_dr_freq = DEFAULT_CLK_FREQ; | |
1381 | params->curr_dr_freq = DEFAULT_CLK_FREQ; | |
8cb3b4e7 SK |
1382 | params->col = data->default_cols; |
1383 | params->row = data->default_rows; | |
02efb49a SK |
1384 | ctrl->reg_read(ctrl, SWRM_MCP_STATUS, &val); |
1385 | params->curr_bank = val & SWRM_MCP_STATUS_BANK_NUM_MASK; | |
1386 | params->next_bank = !params->curr_bank; | |
1387 | ||
1388 | prop = &ctrl->bus.prop; | |
1389 | prop->max_clk_freq = DEFAULT_CLK_FREQ; | |
1390 | prop->num_clk_gears = 0; | |
1391 | prop->num_clk_freq = MAX_FREQ_NUM; | |
1392 | prop->clk_freq = &qcom_swrm_freq_tbl[0]; | |
8cb3b4e7 SK |
1393 | prop->default_col = data->default_cols; |
1394 | prop->default_row = data->default_rows; | |
02efb49a SK |
1395 | |
1396 | ctrl->reg_read(ctrl, SWRM_COMP_HW_VERSION, &ctrl->version); | |
1397 | ||
1398 | ret = devm_request_threaded_irq(dev, ctrl->irq, NULL, | |
1399 | qcom_swrm_irq_handler, | |
4f1738f4 SZ |
1400 | IRQF_TRIGGER_RISING | |
1401 | IRQF_ONESHOT, | |
02efb49a SK |
1402 | "soundwire", ctrl); |
1403 | if (ret) { | |
1404 | dev_err(dev, "Failed to request soundwire irq\n"); | |
91b5cfc0 | 1405 | goto err_clk; |
02efb49a SK |
1406 | } |
1407 | ||
04d46a7b SK |
1408 | ctrl->wake_irq = of_irq_get(dev->of_node, 1); |
1409 | if (ctrl->wake_irq > 0) { | |
1410 | ret = devm_request_threaded_irq(dev, ctrl->wake_irq, NULL, | |
1411 | qcom_swrm_wake_irq_handler, | |
1412 | IRQF_TRIGGER_HIGH | IRQF_ONESHOT, | |
1413 | "swr_wake_irq", ctrl); | |
1414 | if (ret) { | |
1415 | dev_err(dev, "Failed to request soundwire wake irq\n"); | |
1416 | goto err_init; | |
1417 | } | |
1418 | } | |
1419 | ||
5cab3ff2 | 1420 | ret = sdw_bus_master_add(&ctrl->bus, dev, dev->fwnode); |
02efb49a SK |
1421 | if (ret) { |
1422 | dev_err(dev, "Failed to register Soundwire controller (%d)\n", | |
1423 | ret); | |
91b5cfc0 | 1424 | goto err_clk; |
02efb49a SK |
1425 | } |
1426 | ||
1427 | qcom_swrm_init(ctrl); | |
06dd9673 SK |
1428 | wait_for_completion_timeout(&ctrl->enumeration, |
1429 | msecs_to_jiffies(TIMEOUT_MS)); | |
02efb49a SK |
1430 | ret = qcom_swrm_register_dais(ctrl); |
1431 | if (ret) | |
91b5cfc0 | 1432 | goto err_master_add; |
02efb49a SK |
1433 | |
1434 | dev_info(dev, "Qualcomm Soundwire controller v%x.%x.%x Registered\n", | |
1435 | (ctrl->version >> 24) & 0xff, (ctrl->version >> 16) & 0xff, | |
1436 | ctrl->version & 0xffff); | |
1437 | ||
74e79da9 SK |
1438 | pm_runtime_set_autosuspend_delay(dev, 3000); |
1439 | pm_runtime_use_autosuspend(dev); | |
1440 | pm_runtime_mark_last_busy(dev); | |
1441 | pm_runtime_set_active(dev); | |
1442 | pm_runtime_enable(dev); | |
1443 | ||
1444 | /* Clk stop is not supported on WSA Soundwire masters */ | |
1445 | if (ctrl->version <= 0x01030000) { | |
1446 | ctrl->clock_stop_not_supported = true; | |
1447 | } else { | |
1448 | ctrl->reg_read(ctrl, SWRM_COMP_MASTER_ID, &val); | |
1449 | if (val == MASTER_ID_WSA) | |
1450 | ctrl->clock_stop_not_supported = true; | |
1451 | } | |
1452 | ||
abd9a604 SK |
1453 | #ifdef CONFIG_DEBUG_FS |
1454 | ctrl->debugfs = debugfs_create_dir("qualcomm-sdw", ctrl->bus.debugfs); | |
1455 | debugfs_create_file("qualcomm-registers", 0400, ctrl->debugfs, ctrl, | |
1456 | &swrm_reg_fops); | |
1457 | #endif | |
1458 | ||
02efb49a | 1459 | return 0; |
91b5cfc0 PLB |
1460 | |
1461 | err_master_add: | |
5cab3ff2 | 1462 | sdw_bus_master_delete(&ctrl->bus); |
91b5cfc0 | 1463 | err_clk: |
02efb49a | 1464 | clk_disable_unprepare(ctrl->hclk); |
91b5cfc0 | 1465 | err_init: |
02efb49a SK |
1466 | return ret; |
1467 | } | |
1468 | ||
1469 | static int qcom_swrm_remove(struct platform_device *pdev) | |
1470 | { | |
1471 | struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(&pdev->dev); | |
1472 | ||
5cab3ff2 | 1473 | sdw_bus_master_delete(&ctrl->bus); |
02efb49a SK |
1474 | clk_disable_unprepare(ctrl->hclk); |
1475 | ||
1476 | return 0; | |
1477 | } | |
1478 | ||
74e79da9 SK |
1479 | static bool swrm_wait_for_frame_gen_enabled(struct qcom_swrm_ctrl *swrm) |
1480 | { | |
1481 | int retry = SWRM_LINK_STATUS_RETRY_CNT; | |
1482 | int comp_sts; | |
1483 | ||
1484 | do { | |
1485 | swrm->reg_read(swrm, SWRM_COMP_STATUS, &comp_sts); | |
1486 | ||
1487 | if (comp_sts & SWRM_FRM_GEN_ENABLED) | |
1488 | return true; | |
1489 | ||
1490 | usleep_range(500, 510); | |
1491 | } while (retry--); | |
1492 | ||
1493 | dev_err(swrm->dev, "%s: link status not %s\n", __func__, | |
d146de34 | 1494 | comp_sts & SWRM_FRM_GEN_ENABLED ? "connected" : "disconnected"); |
74e79da9 SK |
1495 | |
1496 | return false; | |
1497 | } | |
1498 | ||
266fa946 | 1499 | static int __maybe_unused swrm_runtime_resume(struct device *dev) |
74e79da9 SK |
1500 | { |
1501 | struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dev); | |
1502 | int ret; | |
1503 | ||
04d46a7b SK |
1504 | if (ctrl->wake_irq > 0) { |
1505 | if (!irqd_irq_disabled(irq_get_irq_data(ctrl->wake_irq))) | |
1506 | disable_irq_nosync(ctrl->wake_irq); | |
1507 | } | |
1508 | ||
74e79da9 SK |
1509 | clk_prepare_enable(ctrl->hclk); |
1510 | ||
1511 | if (ctrl->clock_stop_not_supported) { | |
1512 | reinit_completion(&ctrl->enumeration); | |
1513 | ctrl->reg_write(ctrl, SWRM_COMP_SW_RESET, 0x01); | |
1514 | usleep_range(100, 105); | |
1515 | ||
1516 | qcom_swrm_init(ctrl); | |
1517 | ||
1518 | usleep_range(100, 105); | |
1519 | if (!swrm_wait_for_frame_gen_enabled(ctrl)) | |
1520 | dev_err(ctrl->dev, "link failed to connect\n"); | |
1521 | ||
1522 | /* wait for hw enumeration to complete */ | |
1523 | wait_for_completion_timeout(&ctrl->enumeration, | |
1524 | msecs_to_jiffies(TIMEOUT_MS)); | |
1525 | qcom_swrm_get_device_status(ctrl); | |
1526 | sdw_handle_slave_status(&ctrl->bus, ctrl->status); | |
1527 | } else { | |
33ba0178 SRM |
1528 | reset_control_reset(ctrl->audio_cgcr); |
1529 | ||
cf43cd33 SK |
1530 | if (ctrl->version >= 0x01070000) { |
1531 | ctrl->reg_write(ctrl, SWRM_LINK_MANAGER_EE, SWRM_EE_CPU); | |
1532 | ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL, | |
1533 | SWRM_MCP_BUS_CLK_START << SWRM_EE_CPU); | |
1534 | } else { | |
1535 | ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL, SWRM_MCP_BUS_CLK_START); | |
1536 | } | |
74e79da9 SK |
1537 | ctrl->reg_write(ctrl, SWRM_INTERRUPT_CLEAR, |
1538 | SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET); | |
1539 | ||
1540 | ctrl->intr_mask |= SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET; | |
1541 | ctrl->reg_write(ctrl, SWRM_INTERRUPT_MASK_ADDR, ctrl->intr_mask); | |
1542 | ctrl->reg_write(ctrl, SWRM_INTERRUPT_CPU_EN, ctrl->intr_mask); | |
1543 | ||
1544 | usleep_range(100, 105); | |
1545 | if (!swrm_wait_for_frame_gen_enabled(ctrl)) | |
1546 | dev_err(ctrl->dev, "link failed to connect\n"); | |
1547 | ||
1548 | ret = sdw_bus_exit_clk_stop(&ctrl->bus); | |
1549 | if (ret < 0) | |
1550 | dev_err(ctrl->dev, "bus failed to exit clock stop %d\n", ret); | |
1551 | } | |
1552 | ||
1553 | return 0; | |
1554 | } | |
1555 | ||
1556 | static int __maybe_unused swrm_runtime_suspend(struct device *dev) | |
1557 | { | |
1558 | struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dev); | |
1559 | int ret; | |
1560 | ||
1561 | if (!ctrl->clock_stop_not_supported) { | |
1562 | /* Mask bus clash interrupt */ | |
1563 | ctrl->intr_mask &= ~SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET; | |
1564 | ctrl->reg_write(ctrl, SWRM_INTERRUPT_MASK_ADDR, ctrl->intr_mask); | |
1565 | ctrl->reg_write(ctrl, SWRM_INTERRUPT_CPU_EN, ctrl->intr_mask); | |
1566 | /* Prepare slaves for clock stop */ | |
1567 | ret = sdw_bus_prep_clk_stop(&ctrl->bus); | |
1568 | if (ret < 0 && ret != -ENODATA) { | |
1569 | dev_err(dev, "prepare clock stop failed %d", ret); | |
1570 | return ret; | |
1571 | } | |
1572 | ||
1573 | ret = sdw_bus_clk_stop(&ctrl->bus); | |
1574 | if (ret < 0 && ret != -ENODATA) { | |
1575 | dev_err(dev, "bus clock stop failed %d", ret); | |
1576 | return ret; | |
1577 | } | |
1578 | } | |
1579 | ||
1580 | clk_disable_unprepare(ctrl->hclk); | |
1581 | ||
1582 | usleep_range(300, 305); | |
1583 | ||
04d46a7b SK |
1584 | if (ctrl->wake_irq > 0) { |
1585 | if (irqd_irq_disabled(irq_get_irq_data(ctrl->wake_irq))) | |
1586 | enable_irq(ctrl->wake_irq); | |
1587 | } | |
1588 | ||
74e79da9 SK |
1589 | return 0; |
1590 | } | |
1591 | ||
1592 | static const struct dev_pm_ops swrm_dev_pm_ops = { | |
1593 | SET_RUNTIME_PM_OPS(swrm_runtime_suspend, swrm_runtime_resume, NULL) | |
1594 | }; | |
1595 | ||
02efb49a | 1596 | static const struct of_device_id qcom_swrm_of_match[] = { |
8cb3b4e7 SK |
1597 | { .compatible = "qcom,soundwire-v1.3.0", .data = &swrm_v1_3_data }, |
1598 | { .compatible = "qcom,soundwire-v1.5.1", .data = &swrm_v1_5_data }, | |
3f4a7026 | 1599 | { .compatible = "qcom,soundwire-v1.6.0", .data = &swrm_v1_6_data }, |
cf43cd33 | 1600 | { .compatible = "qcom,soundwire-v1.7.0", .data = &swrm_v1_5_data }, |
02efb49a SK |
1601 | {/* sentinel */}, |
1602 | }; | |
1603 | ||
1604 | MODULE_DEVICE_TABLE(of, qcom_swrm_of_match); | |
1605 | ||
1606 | static struct platform_driver qcom_swrm_driver = { | |
1607 | .probe = &qcom_swrm_probe, | |
1608 | .remove = &qcom_swrm_remove, | |
1609 | .driver = { | |
1610 | .name = "qcom-soundwire", | |
1611 | .of_match_table = qcom_swrm_of_match, | |
74e79da9 | 1612 | .pm = &swrm_dev_pm_ops, |
02efb49a SK |
1613 | } |
1614 | }; | |
1615 | module_platform_driver(qcom_swrm_driver); | |
1616 | ||
1617 | MODULE_DESCRIPTION("Qualcomm soundwire driver"); | |
1618 | MODULE_LICENSE("GPL v2"); |