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