xref: /linux/drivers/i3c/master/adi-i3c-master.c (revision ec2e0fb07d789976c601bec19ecced7a501c3705)
1a79ac2cdSJorge Marques // SPDX-License-Identifier: GPL-2.0-only
2a79ac2cdSJorge Marques /*
3a79ac2cdSJorge Marques  * I3C Controller driver
4a79ac2cdSJorge Marques  * Copyright 2025 Analog Devices Inc.
5a79ac2cdSJorge Marques  * Author: Jorge Marques <jorge.marques@analog.com>
6a79ac2cdSJorge Marques  */
7a79ac2cdSJorge Marques 
8a79ac2cdSJorge Marques #include <linux/bitops.h>
9a79ac2cdSJorge Marques #include <linux/bitfield.h>
10a79ac2cdSJorge Marques #include <linux/clk.h>
11a79ac2cdSJorge Marques #include <linux/err.h>
12a79ac2cdSJorge Marques #include <linux/errno.h>
133ab1da26SAlexandre Belloni #include <linux/adi-axi-common.h>
14a79ac2cdSJorge Marques #include <linux/i3c/master.h>
15a79ac2cdSJorge Marques #include <linux/interrupt.h>
16a79ac2cdSJorge Marques #include <linux/io.h>
17a79ac2cdSJorge Marques #include <linux/module.h>
18a79ac2cdSJorge Marques #include <linux/of.h>
19a79ac2cdSJorge Marques #include <linux/platform_device.h>
20a79ac2cdSJorge Marques 
21a79ac2cdSJorge Marques #include "../internals.h"
22a79ac2cdSJorge Marques 
23a79ac2cdSJorge Marques #define ADI_MAX_DEVS			16
24a79ac2cdSJorge Marques #define ADI_HAS_MDB_FROM_BCR(x)		(FIELD_GET(BIT(2), (x)))
25a79ac2cdSJorge Marques 
26a79ac2cdSJorge Marques #define REG_ENABLE			0x040
27a79ac2cdSJorge Marques 
28a79ac2cdSJorge Marques #define REG_PID_L			0x054
29a79ac2cdSJorge Marques #define REG_PID_H			0x058
30a79ac2cdSJorge Marques #define REG_DCR_BCR_DA			0x05c
31a79ac2cdSJorge Marques #define   REG_DCR_BCR_DA_GET_DA(x)	FIELD_GET(GENMASK(22, 16), (x))
32a79ac2cdSJorge Marques #define   REG_DCR_BCR_DA_GET_BCR(x)	FIELD_GET(GENMASK(15, 8), (x))
33a79ac2cdSJorge Marques #define   REG_DCR_BCR_DA_GET_DCR(x)	FIELD_GET(GENMASK(7, 0), (x))
34a79ac2cdSJorge Marques 
35a79ac2cdSJorge Marques #define REG_IRQ_MASK			0x080
36a79ac2cdSJorge Marques #define REG_IRQ_PENDING			0x084
37a79ac2cdSJorge Marques #define   REG_IRQ_PENDING_DAA		BIT(7)
38a79ac2cdSJorge Marques #define   REG_IRQ_PENDING_IBI		BIT(6)
39a79ac2cdSJorge Marques #define   REG_IRQ_PENDING_CMDR		BIT(5)
40a79ac2cdSJorge Marques 
41a79ac2cdSJorge Marques #define REG_CMD_FIFO			0x0d4
42a79ac2cdSJorge Marques #define   REG_CMD_FIFO_0_IS_CCC		BIT(22)
43a79ac2cdSJorge Marques #define   REG_CMD_FIFO_0_BCAST		BIT(21)
44a79ac2cdSJorge Marques #define   REG_CMD_FIFO_0_SR		BIT(20)
45a79ac2cdSJorge Marques #define   REG_CMD_FIFO_0_LEN(l)		FIELD_PREP(GENMASK(19, 8), (l))
46a79ac2cdSJorge Marques #define   REG_CMD_FIFO_0_DEV_ADDR(a)	FIELD_PREP(GENMASK(7, 1), (a))
47a79ac2cdSJorge Marques #define   REG_CMD_FIFO_0_RNW		BIT(0)
48a79ac2cdSJorge Marques #define   REG_CMD_FIFO_1_CCC(id)	FIELD_PREP(GENMASK(7, 0), (id))
49a79ac2cdSJorge Marques 
50a79ac2cdSJorge Marques #define REG_CMD_FIFO_ROOM		0x0c0
51a79ac2cdSJorge Marques #define REG_CMDR_FIFO			0x0d8
52a79ac2cdSJorge Marques #define   REG_CMDR_FIFO_UDA_ERROR	8
53a79ac2cdSJorge Marques #define   REG_CMDR_FIFO_NACK_RESP	6
54a79ac2cdSJorge Marques #define   REG_CMDR_FIFO_CE2_ERROR	4
55a79ac2cdSJorge Marques #define   REG_CMDR_FIFO_CE0_ERROR	1
56a79ac2cdSJorge Marques #define   REG_CMDR_FIFO_NO_ERROR	0
57a79ac2cdSJorge Marques #define   REG_CMDR_FIFO_ERROR(x)	FIELD_GET(GENMASK(23, 20), (x))
58a79ac2cdSJorge Marques #define   REG_CMDR_FIFO_XFER_BYTES(x)	FIELD_GET(GENMASK(19, 8), (x))
59a79ac2cdSJorge Marques 
60a79ac2cdSJorge Marques #define REG_SDO_FIFO			0x0dc
61a79ac2cdSJorge Marques #define REG_SDO_FIFO_ROOM		0x0c8
62a79ac2cdSJorge Marques #define REG_SDI_FIFO			0x0e0
63a79ac2cdSJorge Marques #define REG_IBI_FIFO			0x0e4
64a79ac2cdSJorge Marques #define REG_FIFO_STATUS			0x0e8
65a79ac2cdSJorge Marques #define   REG_FIFO_STATUS_CMDR_EMPTY	BIT(0)
66a79ac2cdSJorge Marques #define   REG_FIFO_STATUS_IBI_EMPTY	BIT(1)
67a79ac2cdSJorge Marques 
68a79ac2cdSJorge Marques #define REG_OPS				0x100
69a79ac2cdSJorge Marques #define   REG_OPS_PP_SG_MASK		GENMASK(6, 5)
70a79ac2cdSJorge Marques #define   REG_OPS_SET_SG(x)		FIELD_PREP(REG_OPS_PP_SG_MASK, (x))
71a79ac2cdSJorge Marques 
72a79ac2cdSJorge Marques #define REG_IBI_CONFIG			0x140
73a79ac2cdSJorge Marques #define   REG_IBI_CONFIG_ENABLE		BIT(0)
74a79ac2cdSJorge Marques #define   REG_IBI_CONFIG_LISTEN		BIT(1)
75a79ac2cdSJorge Marques 
76a79ac2cdSJorge Marques #define REG_DEV_CHAR			0x180
77a79ac2cdSJorge Marques #define   REG_DEV_CHAR_IS_I2C		BIT(0)
78a79ac2cdSJorge Marques #define   REG_DEV_CHAR_IS_ATTACHED	BIT(1)
79a79ac2cdSJorge Marques #define   REG_DEV_CHAR_BCR_IBI(x)	FIELD_PREP(GENMASK(3, 2), (x))
80a79ac2cdSJorge Marques #define   REG_DEV_CHAR_WEN		BIT(8)
81a79ac2cdSJorge Marques #define   REG_DEV_CHAR_ADDR(x)		FIELD_PREP(GENMASK(15, 9), (x))
82a79ac2cdSJorge Marques 
83a79ac2cdSJorge Marques enum speed_grade {PP_SG_UNSET, PP_SG_1MHZ, PP_SG_3MHZ, PP_SG_6MHZ, PP_SG_12MHZ};
84a79ac2cdSJorge Marques 
85a79ac2cdSJorge Marques struct adi_i3c_cmd {
86a79ac2cdSJorge Marques 	u32 cmd0;
87a79ac2cdSJorge Marques 	u32 cmd1;
88a79ac2cdSJorge Marques 	u32 tx_len;
89a79ac2cdSJorge Marques 	const void *tx_buf;
90a79ac2cdSJorge Marques 	u32 rx_len;
91a79ac2cdSJorge Marques 	void *rx_buf;
92a79ac2cdSJorge Marques 	u32 error;
93a79ac2cdSJorge Marques };
94a79ac2cdSJorge Marques 
95a79ac2cdSJorge Marques struct adi_i3c_xfer {
96a79ac2cdSJorge Marques 	struct list_head node;
97a79ac2cdSJorge Marques 	struct completion comp;
98a79ac2cdSJorge Marques 	int ret;
99a79ac2cdSJorge Marques 	unsigned int ncmds;
100a79ac2cdSJorge Marques 	unsigned int ncmds_comp;
101a79ac2cdSJorge Marques 	struct adi_i3c_cmd cmds[] __counted_by(ncmds);
102a79ac2cdSJorge Marques };
103a79ac2cdSJorge Marques 
104a79ac2cdSJorge Marques struct adi_i3c_master {
105a79ac2cdSJorge Marques 	struct i3c_master_controller base;
106a79ac2cdSJorge Marques 	u32 free_rr_slots;
107a79ac2cdSJorge Marques 	struct {
108a79ac2cdSJorge Marques 		unsigned int num_slots;
109a79ac2cdSJorge Marques 		struct i3c_dev_desc **slots;
110a79ac2cdSJorge Marques 		spinlock_t lock; /* Protect IBI slot access */
111a79ac2cdSJorge Marques 	} ibi;
112a79ac2cdSJorge Marques 	struct {
113a79ac2cdSJorge Marques 		struct list_head list;
114a79ac2cdSJorge Marques 		struct adi_i3c_xfer *cur;
115a79ac2cdSJorge Marques 		spinlock_t lock; /* Protect transfer */
116a79ac2cdSJorge Marques 	} xferqueue;
117a79ac2cdSJorge Marques 	void __iomem *regs;
118a79ac2cdSJorge Marques 	struct clk *clk;
119a79ac2cdSJorge Marques 	unsigned long i3c_scl_lim;
120a79ac2cdSJorge Marques 	struct {
121a79ac2cdSJorge Marques 		u8 addrs[ADI_MAX_DEVS];
122a79ac2cdSJorge Marques 		u8 index;
123a79ac2cdSJorge Marques 	} daa;
124a79ac2cdSJorge Marques };
125a79ac2cdSJorge Marques 
to_adi_i3c_master(struct i3c_master_controller * master)126a79ac2cdSJorge Marques static inline struct adi_i3c_master *to_adi_i3c_master(struct i3c_master_controller *master)
127a79ac2cdSJorge Marques {
128a79ac2cdSJorge Marques 	return container_of(master, struct adi_i3c_master, base);
129a79ac2cdSJorge Marques }
130a79ac2cdSJorge Marques 
adi_i3c_master_wr_to_tx_fifo(struct adi_i3c_master * master,const u8 * buf,unsigned int nbytes)131a79ac2cdSJorge Marques static void adi_i3c_master_wr_to_tx_fifo(struct adi_i3c_master *master,
132a79ac2cdSJorge Marques 					 const u8 *buf, unsigned int nbytes)
133a79ac2cdSJorge Marques {
134a79ac2cdSJorge Marques 	unsigned int n, m;
135a79ac2cdSJorge Marques 
136a79ac2cdSJorge Marques 	n = readl(master->regs + REG_SDO_FIFO_ROOM);
137a79ac2cdSJorge Marques 	m = min(n, nbytes);
138*8a1f3fd1SAlexandre Belloni 	i3c_writel_fifo(master->regs + REG_SDO_FIFO, buf, m);
139a79ac2cdSJorge Marques }
140a79ac2cdSJorge Marques 
adi_i3c_master_rd_from_rx_fifo(struct adi_i3c_master * master,u8 * buf,unsigned int nbytes)141a79ac2cdSJorge Marques static void adi_i3c_master_rd_from_rx_fifo(struct adi_i3c_master *master,
142a79ac2cdSJorge Marques 					   u8 *buf, unsigned int nbytes)
143a79ac2cdSJorge Marques {
144a79ac2cdSJorge Marques 	i3c_readl_fifo(master->regs + REG_SDI_FIFO, buf, nbytes);
145a79ac2cdSJorge Marques }
146a79ac2cdSJorge Marques 
adi_i3c_master_supports_ccc_cmd(struct i3c_master_controller * m,const struct i3c_ccc_cmd * cmd)147a79ac2cdSJorge Marques static bool adi_i3c_master_supports_ccc_cmd(struct i3c_master_controller *m,
148a79ac2cdSJorge Marques 					    const struct i3c_ccc_cmd *cmd)
149a79ac2cdSJorge Marques {
150a79ac2cdSJorge Marques 	if (cmd->ndests > 1)
151a79ac2cdSJorge Marques 		return false;
152a79ac2cdSJorge Marques 
153a79ac2cdSJorge Marques 	switch (cmd->id) {
154a79ac2cdSJorge Marques 	case I3C_CCC_ENEC(true):
155a79ac2cdSJorge Marques 	case I3C_CCC_ENEC(false):
156a79ac2cdSJorge Marques 	case I3C_CCC_DISEC(true):
157a79ac2cdSJorge Marques 	case I3C_CCC_DISEC(false):
158a79ac2cdSJorge Marques 	case I3C_CCC_RSTDAA(true):
159a79ac2cdSJorge Marques 	case I3C_CCC_RSTDAA(false):
160a79ac2cdSJorge Marques 	case I3C_CCC_ENTDAA:
161a79ac2cdSJorge Marques 	case I3C_CCC_SETDASA:
162a79ac2cdSJorge Marques 	case I3C_CCC_SETNEWDA:
163a79ac2cdSJorge Marques 	case I3C_CCC_GETMWL:
164a79ac2cdSJorge Marques 	case I3C_CCC_GETMRL:
165a79ac2cdSJorge Marques 	case I3C_CCC_GETPID:
166a79ac2cdSJorge Marques 	case I3C_CCC_GETBCR:
167a79ac2cdSJorge Marques 	case I3C_CCC_GETDCR:
168a79ac2cdSJorge Marques 	case I3C_CCC_GETSTATUS:
169a79ac2cdSJorge Marques 	case I3C_CCC_GETHDRCAP:
170a79ac2cdSJorge Marques 		return true;
171a79ac2cdSJorge Marques 	default:
172a79ac2cdSJorge Marques 		break;
173a79ac2cdSJorge Marques 	}
174a79ac2cdSJorge Marques 
175a79ac2cdSJorge Marques 	return false;
176a79ac2cdSJorge Marques }
177a79ac2cdSJorge Marques 
adi_i3c_master_disable(struct adi_i3c_master * master)178a79ac2cdSJorge Marques static int adi_i3c_master_disable(struct adi_i3c_master *master)
179a79ac2cdSJorge Marques {
180a79ac2cdSJorge Marques 	writel(0, master->regs + REG_IBI_CONFIG);
181a79ac2cdSJorge Marques 
182a79ac2cdSJorge Marques 	return 0;
183a79ac2cdSJorge Marques }
184a79ac2cdSJorge Marques 
adi_i3c_master_alloc_xfer(struct adi_i3c_master * master,unsigned int ncmds)185a79ac2cdSJorge Marques static struct adi_i3c_xfer *adi_i3c_master_alloc_xfer(struct adi_i3c_master *master,
186a79ac2cdSJorge Marques 						      unsigned int ncmds)
187a79ac2cdSJorge Marques {
188a79ac2cdSJorge Marques 	struct adi_i3c_xfer *xfer;
189a79ac2cdSJorge Marques 
190a79ac2cdSJorge Marques 	xfer = kzalloc(struct_size(xfer, cmds, ncmds), GFP_KERNEL);
191a79ac2cdSJorge Marques 	if (!xfer)
192a79ac2cdSJorge Marques 		return NULL;
193a79ac2cdSJorge Marques 
194a79ac2cdSJorge Marques 	INIT_LIST_HEAD(&xfer->node);
195a79ac2cdSJorge Marques 	xfer->ncmds = ncmds;
196a79ac2cdSJorge Marques 	xfer->ret = -ETIMEDOUT;
197a79ac2cdSJorge Marques 
198a79ac2cdSJorge Marques 	return xfer;
199a79ac2cdSJorge Marques }
200a79ac2cdSJorge Marques 
adi_i3c_master_start_xfer_locked(struct adi_i3c_master * master)201a79ac2cdSJorge Marques static void adi_i3c_master_start_xfer_locked(struct adi_i3c_master *master)
202a79ac2cdSJorge Marques {
203a79ac2cdSJorge Marques 	struct adi_i3c_xfer *xfer = master->xferqueue.cur;
204a79ac2cdSJorge Marques 	unsigned int i, n, m;
205a79ac2cdSJorge Marques 
206a79ac2cdSJorge Marques 	if (!xfer)
207a79ac2cdSJorge Marques 		return;
208a79ac2cdSJorge Marques 
209a79ac2cdSJorge Marques 	for (i = 0; i < xfer->ncmds; i++) {
210a79ac2cdSJorge Marques 		struct adi_i3c_cmd *cmd = &xfer->cmds[i];
211a79ac2cdSJorge Marques 
212a79ac2cdSJorge Marques 		if (!(cmd->cmd0 & REG_CMD_FIFO_0_RNW))
213a79ac2cdSJorge Marques 			adi_i3c_master_wr_to_tx_fifo(master, cmd->tx_buf, cmd->tx_len);
214a79ac2cdSJorge Marques 	}
215a79ac2cdSJorge Marques 
216a79ac2cdSJorge Marques 	n = readl(master->regs + REG_CMD_FIFO_ROOM);
217a79ac2cdSJorge Marques 	for (i = 0; i < xfer->ncmds; i++) {
218a79ac2cdSJorge Marques 		struct adi_i3c_cmd *cmd = &xfer->cmds[i];
219a79ac2cdSJorge Marques 
220a79ac2cdSJorge Marques 		m = cmd->cmd0 & REG_CMD_FIFO_0_IS_CCC ? 2 : 1;
221a79ac2cdSJorge Marques 		if (m > n)
222a79ac2cdSJorge Marques 			break;
223a79ac2cdSJorge Marques 		writel(cmd->cmd0, master->regs + REG_CMD_FIFO);
224a79ac2cdSJorge Marques 		if (cmd->cmd0 & REG_CMD_FIFO_0_IS_CCC)
225a79ac2cdSJorge Marques 			writel(cmd->cmd1, master->regs + REG_CMD_FIFO);
226a79ac2cdSJorge Marques 		n -= m;
227a79ac2cdSJorge Marques 	}
228a79ac2cdSJorge Marques }
229a79ac2cdSJorge Marques 
adi_i3c_master_end_xfer_locked(struct adi_i3c_master * master,u32 pending)230a79ac2cdSJorge Marques static void adi_i3c_master_end_xfer_locked(struct adi_i3c_master *master,
231a79ac2cdSJorge Marques 					   u32 pending)
232a79ac2cdSJorge Marques {
233a79ac2cdSJorge Marques 	struct adi_i3c_xfer *xfer = master->xferqueue.cur;
234a79ac2cdSJorge Marques 	int i, ret = 0;
235a79ac2cdSJorge Marques 
236a79ac2cdSJorge Marques 	if (!xfer)
237a79ac2cdSJorge Marques 		return;
238a79ac2cdSJorge Marques 
239a79ac2cdSJorge Marques 	while (!(readl(master->regs + REG_FIFO_STATUS) & REG_FIFO_STATUS_CMDR_EMPTY)) {
240a79ac2cdSJorge Marques 		struct adi_i3c_cmd *cmd;
241a79ac2cdSJorge Marques 		u32 cmdr, rx_len;
242a79ac2cdSJorge Marques 
243a79ac2cdSJorge Marques 		cmdr = readl(master->regs + REG_CMDR_FIFO);
244a79ac2cdSJorge Marques 
245a79ac2cdSJorge Marques 		cmd = &xfer->cmds[xfer->ncmds_comp++];
246a79ac2cdSJorge Marques 		if (cmd->cmd0 & REG_CMD_FIFO_0_RNW) {
247a79ac2cdSJorge Marques 			rx_len = min_t(u32, REG_CMDR_FIFO_XFER_BYTES(cmdr), cmd->rx_len);
248a79ac2cdSJorge Marques 			adi_i3c_master_rd_from_rx_fifo(master, cmd->rx_buf, rx_len);
249a79ac2cdSJorge Marques 		}
250a79ac2cdSJorge Marques 		cmd->error = REG_CMDR_FIFO_ERROR(cmdr);
251a79ac2cdSJorge Marques 	}
252a79ac2cdSJorge Marques 
253a79ac2cdSJorge Marques 	for (i = 0; i < xfer->ncmds_comp; i++) {
254a79ac2cdSJorge Marques 		switch (xfer->cmds[i].error) {
255a79ac2cdSJorge Marques 		case REG_CMDR_FIFO_NO_ERROR:
256a79ac2cdSJorge Marques 			break;
257a79ac2cdSJorge Marques 
258a79ac2cdSJorge Marques 		case REG_CMDR_FIFO_CE0_ERROR:
259a79ac2cdSJorge Marques 		case REG_CMDR_FIFO_CE2_ERROR:
260a79ac2cdSJorge Marques 		case REG_CMDR_FIFO_NACK_RESP:
261a79ac2cdSJorge Marques 		case REG_CMDR_FIFO_UDA_ERROR:
262a79ac2cdSJorge Marques 			ret = -EIO;
263a79ac2cdSJorge Marques 			break;
264a79ac2cdSJorge Marques 
265a79ac2cdSJorge Marques 		default:
266a79ac2cdSJorge Marques 			ret = -EINVAL;
267a79ac2cdSJorge Marques 			break;
268a79ac2cdSJorge Marques 		}
269a79ac2cdSJorge Marques 	}
270a79ac2cdSJorge Marques 
271a79ac2cdSJorge Marques 	xfer->ret = ret;
272a79ac2cdSJorge Marques 
273a79ac2cdSJorge Marques 	if (xfer->ncmds_comp != xfer->ncmds)
274a79ac2cdSJorge Marques 		return;
275a79ac2cdSJorge Marques 
276a79ac2cdSJorge Marques 	complete(&xfer->comp);
277a79ac2cdSJorge Marques 
278a79ac2cdSJorge Marques 	xfer = list_first_entry_or_null(&master->xferqueue.list,
279a79ac2cdSJorge Marques 					struct adi_i3c_xfer, node);
280a79ac2cdSJorge Marques 	if (xfer)
281a79ac2cdSJorge Marques 		list_del_init(&xfer->node);
282a79ac2cdSJorge Marques 
283a79ac2cdSJorge Marques 	master->xferqueue.cur = xfer;
284a79ac2cdSJorge Marques 	adi_i3c_master_start_xfer_locked(master);
285a79ac2cdSJorge Marques }
286a79ac2cdSJorge Marques 
adi_i3c_master_queue_xfer(struct adi_i3c_master * master,struct adi_i3c_xfer * xfer)287a79ac2cdSJorge Marques static void adi_i3c_master_queue_xfer(struct adi_i3c_master *master,
288a79ac2cdSJorge Marques 				      struct adi_i3c_xfer *xfer)
289a79ac2cdSJorge Marques {
290a79ac2cdSJorge Marques 	init_completion(&xfer->comp);
291a79ac2cdSJorge Marques 	guard(spinlock_irqsave)(&master->xferqueue.lock);
292a79ac2cdSJorge Marques 	if (master->xferqueue.cur) {
293a79ac2cdSJorge Marques 		list_add_tail(&xfer->node, &master->xferqueue.list);
294a79ac2cdSJorge Marques 	} else {
295a79ac2cdSJorge Marques 		master->xferqueue.cur = xfer;
296a79ac2cdSJorge Marques 		adi_i3c_master_start_xfer_locked(master);
297a79ac2cdSJorge Marques 	}
298a79ac2cdSJorge Marques }
299a79ac2cdSJorge Marques 
adi_i3c_master_unqueue_xfer(struct adi_i3c_master * master,struct adi_i3c_xfer * xfer)300a79ac2cdSJorge Marques static void adi_i3c_master_unqueue_xfer(struct adi_i3c_master *master,
301a79ac2cdSJorge Marques 					struct adi_i3c_xfer *xfer)
302a79ac2cdSJorge Marques {
303a79ac2cdSJorge Marques 	guard(spinlock_irqsave)(&master->xferqueue.lock);
304a79ac2cdSJorge Marques 	if (master->xferqueue.cur == xfer)
305a79ac2cdSJorge Marques 		master->xferqueue.cur = NULL;
306a79ac2cdSJorge Marques 	else
307a79ac2cdSJorge Marques 		list_del_init(&xfer->node);
308a79ac2cdSJorge Marques 
309a79ac2cdSJorge Marques 	writel(0x01, master->regs + REG_ENABLE);
310a79ac2cdSJorge Marques 	writel(0x00, master->regs + REG_ENABLE);
311a79ac2cdSJorge Marques 	writel(REG_IRQ_PENDING_CMDR, master->regs + REG_IRQ_MASK);
312a79ac2cdSJorge Marques }
313a79ac2cdSJorge Marques 
adi_i3c_cmd_get_err(struct adi_i3c_cmd * cmd)314a79ac2cdSJorge Marques static enum i3c_error_code adi_i3c_cmd_get_err(struct adi_i3c_cmd *cmd)
315a79ac2cdSJorge Marques {
316a79ac2cdSJorge Marques 	switch (cmd->error) {
317a79ac2cdSJorge Marques 	case REG_CMDR_FIFO_CE0_ERROR:
318a79ac2cdSJorge Marques 		return I3C_ERROR_M0;
319a79ac2cdSJorge Marques 
320a79ac2cdSJorge Marques 	case REG_CMDR_FIFO_CE2_ERROR:
321a79ac2cdSJorge Marques 	case REG_CMDR_FIFO_NACK_RESP:
322a79ac2cdSJorge Marques 		return I3C_ERROR_M2;
323a79ac2cdSJorge Marques 
324a79ac2cdSJorge Marques 	default:
325a79ac2cdSJorge Marques 		break;
326a79ac2cdSJorge Marques 	}
327a79ac2cdSJorge Marques 
328a79ac2cdSJorge Marques 	return I3C_ERROR_UNKNOWN;
329a79ac2cdSJorge Marques }
330a79ac2cdSJorge Marques 
adi_i3c_master_send_ccc_cmd(struct i3c_master_controller * m,struct i3c_ccc_cmd * cmd)331a79ac2cdSJorge Marques static int adi_i3c_master_send_ccc_cmd(struct i3c_master_controller *m,
332a79ac2cdSJorge Marques 				       struct i3c_ccc_cmd *cmd)
333a79ac2cdSJorge Marques {
334a79ac2cdSJorge Marques 	struct adi_i3c_master *master = to_adi_i3c_master(m);
335a79ac2cdSJorge Marques 	struct adi_i3c_xfer *xfer __free(kfree) = NULL;
336a79ac2cdSJorge Marques 	struct adi_i3c_cmd *ccmd;
337a79ac2cdSJorge Marques 
338a79ac2cdSJorge Marques 	xfer = adi_i3c_master_alloc_xfer(master, 1);
339a79ac2cdSJorge Marques 	if (!xfer)
340a79ac2cdSJorge Marques 		return -ENOMEM;
341a79ac2cdSJorge Marques 
342a79ac2cdSJorge Marques 	ccmd = xfer->cmds;
343a79ac2cdSJorge Marques 	ccmd->cmd1 = REG_CMD_FIFO_1_CCC(cmd->id);
344a79ac2cdSJorge Marques 	ccmd->cmd0 = REG_CMD_FIFO_0_IS_CCC |
345a79ac2cdSJorge Marques 		     REG_CMD_FIFO_0_LEN(cmd->dests[0].payload.len);
346a79ac2cdSJorge Marques 
347a79ac2cdSJorge Marques 	if (cmd->id & I3C_CCC_DIRECT)
348a79ac2cdSJorge Marques 		ccmd->cmd0 |= REG_CMD_FIFO_0_DEV_ADDR(cmd->dests[0].addr);
349a79ac2cdSJorge Marques 
350a79ac2cdSJorge Marques 	if (cmd->rnw) {
351a79ac2cdSJorge Marques 		ccmd->cmd0 |= REG_CMD_FIFO_0_RNW;
352a79ac2cdSJorge Marques 		ccmd->rx_buf = cmd->dests[0].payload.data;
353a79ac2cdSJorge Marques 		ccmd->rx_len = cmd->dests[0].payload.len;
354a79ac2cdSJorge Marques 	} else {
355a79ac2cdSJorge Marques 		ccmd->tx_buf = cmd->dests[0].payload.data;
356a79ac2cdSJorge Marques 		ccmd->tx_len = cmd->dests[0].payload.len;
357a79ac2cdSJorge Marques 	}
358a79ac2cdSJorge Marques 
359a79ac2cdSJorge Marques 	adi_i3c_master_queue_xfer(master, xfer);
360a79ac2cdSJorge Marques 	if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000)))
361a79ac2cdSJorge Marques 		adi_i3c_master_unqueue_xfer(master, xfer);
362a79ac2cdSJorge Marques 
363a79ac2cdSJorge Marques 	cmd->err = adi_i3c_cmd_get_err(&xfer->cmds[0]);
364a79ac2cdSJorge Marques 
365a79ac2cdSJorge Marques 	return 0;
366a79ac2cdSJorge Marques }
367a79ac2cdSJorge Marques 
adi_i3c_master_priv_xfers(struct i3c_dev_desc * dev,struct i3c_priv_xfer * xfers,int nxfers)368a79ac2cdSJorge Marques static int adi_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
369a79ac2cdSJorge Marques 				     struct i3c_priv_xfer *xfers,
370a79ac2cdSJorge Marques 				     int nxfers)
371a79ac2cdSJorge Marques {
372a79ac2cdSJorge Marques 	struct i3c_master_controller *m = i3c_dev_get_master(dev);
373a79ac2cdSJorge Marques 	struct adi_i3c_master *master = to_adi_i3c_master(m);
374a79ac2cdSJorge Marques 	struct adi_i3c_xfer *xfer __free(kfree) = NULL;
375a79ac2cdSJorge Marques 	int i, ret;
376a79ac2cdSJorge Marques 
377a79ac2cdSJorge Marques 	if (!nxfers)
378a79ac2cdSJorge Marques 		return 0;
379a79ac2cdSJorge Marques 
380a79ac2cdSJorge Marques 	xfer = adi_i3c_master_alloc_xfer(master, nxfers);
381a79ac2cdSJorge Marques 	if (!xfer)
382a79ac2cdSJorge Marques 		return -ENOMEM;
383a79ac2cdSJorge Marques 
384a79ac2cdSJorge Marques 	for (i = 0; i < nxfers; i++) {
385a79ac2cdSJorge Marques 		struct adi_i3c_cmd *ccmd = &xfer->cmds[i];
386a79ac2cdSJorge Marques 
387a79ac2cdSJorge Marques 		ccmd->cmd0 = REG_CMD_FIFO_0_DEV_ADDR(dev->info.dyn_addr);
388a79ac2cdSJorge Marques 
389a79ac2cdSJorge Marques 		if (xfers[i].rnw) {
390a79ac2cdSJorge Marques 			ccmd->cmd0 |= REG_CMD_FIFO_0_RNW;
391a79ac2cdSJorge Marques 			ccmd->rx_buf = xfers[i].data.in;
392a79ac2cdSJorge Marques 			ccmd->rx_len = xfers[i].len;
393a79ac2cdSJorge Marques 		} else {
394a79ac2cdSJorge Marques 			ccmd->tx_buf = xfers[i].data.out;
395a79ac2cdSJorge Marques 			ccmd->tx_len = xfers[i].len;
396a79ac2cdSJorge Marques 		}
397a79ac2cdSJorge Marques 
398a79ac2cdSJorge Marques 		ccmd->cmd0 |= REG_CMD_FIFO_0_LEN(xfers[i].len);
399a79ac2cdSJorge Marques 
400a79ac2cdSJorge Marques 		if (i < nxfers - 1)
401a79ac2cdSJorge Marques 			ccmd->cmd0 |= REG_CMD_FIFO_0_SR;
402a79ac2cdSJorge Marques 
403a79ac2cdSJorge Marques 		if (!i)
404a79ac2cdSJorge Marques 			ccmd->cmd0 |= REG_CMD_FIFO_0_BCAST;
405a79ac2cdSJorge Marques 	}
406a79ac2cdSJorge Marques 
407a79ac2cdSJorge Marques 	adi_i3c_master_queue_xfer(master, xfer);
408a79ac2cdSJorge Marques 	if (!wait_for_completion_timeout(&xfer->comp,
409a79ac2cdSJorge Marques 					 msecs_to_jiffies(1000)))
410a79ac2cdSJorge Marques 		adi_i3c_master_unqueue_xfer(master, xfer);
411a79ac2cdSJorge Marques 
412a79ac2cdSJorge Marques 	ret = xfer->ret;
413a79ac2cdSJorge Marques 
414a79ac2cdSJorge Marques 	for (i = 0; i < nxfers; i++)
415a79ac2cdSJorge Marques 		xfers[i].err = adi_i3c_cmd_get_err(&xfer->cmds[i]);
416a79ac2cdSJorge Marques 
417a79ac2cdSJorge Marques 	return ret;
418a79ac2cdSJorge Marques }
419a79ac2cdSJorge Marques 
420a79ac2cdSJorge Marques struct adi_i3c_i2c_dev_data {
421a79ac2cdSJorge Marques 	struct i3c_generic_ibi_pool *ibi_pool;
422a79ac2cdSJorge Marques 	u16 id;
423a79ac2cdSJorge Marques 	s16 ibi;
424a79ac2cdSJorge Marques };
425a79ac2cdSJorge Marques 
adi_i3c_master_get_rr_slot(struct adi_i3c_master * master,u8 dyn_addr)426a79ac2cdSJorge Marques static int adi_i3c_master_get_rr_slot(struct adi_i3c_master *master,
427a79ac2cdSJorge Marques 				      u8 dyn_addr)
428a79ac2cdSJorge Marques {
429a79ac2cdSJorge Marques 	if (!master->free_rr_slots)
430a79ac2cdSJorge Marques 		return -ENOSPC;
431a79ac2cdSJorge Marques 
432a79ac2cdSJorge Marques 	return ffs(master->free_rr_slots) - 1;
433a79ac2cdSJorge Marques }
434a79ac2cdSJorge Marques 
adi_i3c_master_reattach_i3c_dev(struct i3c_dev_desc * dev,u8 dyn_addr)435a79ac2cdSJorge Marques static int adi_i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev, u8 dyn_addr)
436a79ac2cdSJorge Marques {
437a79ac2cdSJorge Marques 	struct i3c_master_controller *m = i3c_dev_get_master(dev);
438a79ac2cdSJorge Marques 	struct adi_i3c_master *master = to_adi_i3c_master(m);
439a79ac2cdSJorge Marques 	u8 addr;
440a79ac2cdSJorge Marques 
441a79ac2cdSJorge Marques 	addr = dev->info.dyn_addr ? dev->info.dyn_addr : dev->info.static_addr;
442a79ac2cdSJorge Marques 
443a79ac2cdSJorge Marques 	writel(REG_DEV_CHAR_ADDR(dyn_addr), master->regs + REG_DEV_CHAR);
444a79ac2cdSJorge Marques 	writel((readl(master->regs + REG_DEV_CHAR) &
445a79ac2cdSJorge Marques 		~REG_DEV_CHAR_IS_ATTACHED) | REG_DEV_CHAR_WEN,
446a79ac2cdSJorge Marques 	       master->regs + REG_DEV_CHAR);
447a79ac2cdSJorge Marques 
448a79ac2cdSJorge Marques 	writel(REG_DEV_CHAR_ADDR(addr), master->regs + REG_DEV_CHAR);
449a79ac2cdSJorge Marques 	writel(readl(master->regs + REG_DEV_CHAR) |
450a79ac2cdSJorge Marques 	       REG_DEV_CHAR_IS_ATTACHED | REG_DEV_CHAR_WEN,
451a79ac2cdSJorge Marques 	       master->regs + REG_DEV_CHAR);
452a79ac2cdSJorge Marques 
453a79ac2cdSJorge Marques 	return 0;
454a79ac2cdSJorge Marques }
455a79ac2cdSJorge Marques 
adi_i3c_master_attach_i3c_dev(struct i3c_dev_desc * dev)456a79ac2cdSJorge Marques static int adi_i3c_master_attach_i3c_dev(struct i3c_dev_desc *dev)
457a79ac2cdSJorge Marques {
458a79ac2cdSJorge Marques 	struct i3c_master_controller *m = i3c_dev_get_master(dev);
459a79ac2cdSJorge Marques 	struct adi_i3c_master *master = to_adi_i3c_master(m);
460a79ac2cdSJorge Marques 	struct adi_i3c_i2c_dev_data *data;
461a79ac2cdSJorge Marques 	int slot;
462a79ac2cdSJorge Marques 	u8 addr;
463a79ac2cdSJorge Marques 
464a79ac2cdSJorge Marques 	data = kzalloc(sizeof(*data), GFP_KERNEL);
465a79ac2cdSJorge Marques 	if (!data)
466a79ac2cdSJorge Marques 		return -ENOMEM;
467a79ac2cdSJorge Marques 
468a79ac2cdSJorge Marques 	slot = adi_i3c_master_get_rr_slot(master, dev->info.dyn_addr);
469a79ac2cdSJorge Marques 	if (slot < 0) {
470a79ac2cdSJorge Marques 		kfree(data);
471a79ac2cdSJorge Marques 		return slot;
472a79ac2cdSJorge Marques 	}
473a79ac2cdSJorge Marques 
474a79ac2cdSJorge Marques 	data->id = slot;
475a79ac2cdSJorge Marques 	i3c_dev_set_master_data(dev, data);
476a79ac2cdSJorge Marques 	master->free_rr_slots &= ~BIT(slot);
477a79ac2cdSJorge Marques 
478a79ac2cdSJorge Marques 	addr = dev->info.dyn_addr ? dev->info.dyn_addr : dev->info.static_addr;
479a79ac2cdSJorge Marques 
480a79ac2cdSJorge Marques 	writel(REG_DEV_CHAR_ADDR(addr), master->regs + REG_DEV_CHAR);
481a79ac2cdSJorge Marques 	writel(readl(master->regs + REG_DEV_CHAR) |
482a79ac2cdSJorge Marques 	       REG_DEV_CHAR_IS_ATTACHED | REG_DEV_CHAR_WEN,
483a79ac2cdSJorge Marques 	       master->regs + REG_DEV_CHAR);
484a79ac2cdSJorge Marques 
485a79ac2cdSJorge Marques 	return 0;
486a79ac2cdSJorge Marques }
487a79ac2cdSJorge Marques 
adi_i3c_master_sync_dev_char(struct i3c_master_controller * m)488a79ac2cdSJorge Marques static void adi_i3c_master_sync_dev_char(struct i3c_master_controller *m)
489a79ac2cdSJorge Marques {
490a79ac2cdSJorge Marques 	struct adi_i3c_master *master = to_adi_i3c_master(m);
491a79ac2cdSJorge Marques 	struct i3c_dev_desc *i3cdev;
492a79ac2cdSJorge Marques 	u32 bcr_ibi;
493a79ac2cdSJorge Marques 	u8 addr;
494a79ac2cdSJorge Marques 
495a79ac2cdSJorge Marques 	i3c_bus_for_each_i3cdev(&m->bus, i3cdev) {
496a79ac2cdSJorge Marques 		addr = i3cdev->info.dyn_addr ?
497a79ac2cdSJorge Marques 		       i3cdev->info.dyn_addr : i3cdev->info.static_addr;
498a79ac2cdSJorge Marques 		writel(REG_DEV_CHAR_ADDR(addr), master->regs + REG_DEV_CHAR);
499a79ac2cdSJorge Marques 		bcr_ibi = FIELD_GET(I3C_BCR_IBI_PAYLOAD | I3C_BCR_IBI_REQ_CAP, (i3cdev->info.bcr));
500a79ac2cdSJorge Marques 		writel(readl(master->regs + REG_DEV_CHAR) |
501a79ac2cdSJorge Marques 		       REG_DEV_CHAR_BCR_IBI(bcr_ibi) | REG_DEV_CHAR_WEN,
502a79ac2cdSJorge Marques 		       master->regs + REG_DEV_CHAR);
503a79ac2cdSJorge Marques 	}
504a79ac2cdSJorge Marques }
505a79ac2cdSJorge Marques 
adi_i3c_master_detach_i3c_dev(struct i3c_dev_desc * dev)506a79ac2cdSJorge Marques static void adi_i3c_master_detach_i3c_dev(struct i3c_dev_desc *dev)
507a79ac2cdSJorge Marques {
508a79ac2cdSJorge Marques 	struct i3c_master_controller *m = i3c_dev_get_master(dev);
509a79ac2cdSJorge Marques 	struct adi_i3c_master *master = to_adi_i3c_master(m);
510a79ac2cdSJorge Marques 	struct adi_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
511a79ac2cdSJorge Marques 	u8 addr;
512a79ac2cdSJorge Marques 
513a79ac2cdSJorge Marques 	addr = dev->info.dyn_addr ? dev->info.dyn_addr : dev->info.static_addr;
514a79ac2cdSJorge Marques 
515a79ac2cdSJorge Marques 	writel(REG_DEV_CHAR_ADDR(addr), master->regs + REG_DEV_CHAR);
516a79ac2cdSJorge Marques 	writel((readl(master->regs + REG_DEV_CHAR) &
517a79ac2cdSJorge Marques 		~REG_DEV_CHAR_IS_ATTACHED) | REG_DEV_CHAR_WEN,
518a79ac2cdSJorge Marques 	       master->regs + REG_DEV_CHAR);
519a79ac2cdSJorge Marques 
520a79ac2cdSJorge Marques 	i3c_dev_set_master_data(dev, NULL);
521a79ac2cdSJorge Marques 	master->free_rr_slots |= BIT(data->id);
522a79ac2cdSJorge Marques 	kfree(data);
523a79ac2cdSJorge Marques }
524a79ac2cdSJorge Marques 
adi_i3c_master_attach_i2c_dev(struct i2c_dev_desc * dev)525a79ac2cdSJorge Marques static int adi_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev)
526a79ac2cdSJorge Marques {
527a79ac2cdSJorge Marques 	struct i3c_master_controller *m = i2c_dev_get_master(dev);
528a79ac2cdSJorge Marques 	struct adi_i3c_master *master = to_adi_i3c_master(m);
529a79ac2cdSJorge Marques 	struct adi_i3c_i2c_dev_data *data;
530a79ac2cdSJorge Marques 	int slot;
531a79ac2cdSJorge Marques 
532a79ac2cdSJorge Marques 	slot = adi_i3c_master_get_rr_slot(master, 0);
533a79ac2cdSJorge Marques 	if (slot < 0)
534a79ac2cdSJorge Marques 		return slot;
535a79ac2cdSJorge Marques 
536a79ac2cdSJorge Marques 	data = kzalloc(sizeof(*data), GFP_KERNEL);
537a79ac2cdSJorge Marques 	if (!data)
538a79ac2cdSJorge Marques 		return -ENOMEM;
539a79ac2cdSJorge Marques 
540a79ac2cdSJorge Marques 	data->id = slot;
541a79ac2cdSJorge Marques 	master->free_rr_slots &= ~BIT(slot);
542a79ac2cdSJorge Marques 	i2c_dev_set_master_data(dev, data);
543a79ac2cdSJorge Marques 
544a79ac2cdSJorge Marques 	writel(REG_DEV_CHAR_ADDR(dev->addr) |
545a79ac2cdSJorge Marques 	       REG_DEV_CHAR_IS_I2C | REG_DEV_CHAR_IS_ATTACHED | REG_DEV_CHAR_WEN,
546a79ac2cdSJorge Marques 	       master->regs + REG_DEV_CHAR);
547a79ac2cdSJorge Marques 
548a79ac2cdSJorge Marques 	return 0;
549a79ac2cdSJorge Marques }
550a79ac2cdSJorge Marques 
adi_i3c_master_detach_i2c_dev(struct i2c_dev_desc * dev)551a79ac2cdSJorge Marques static void adi_i3c_master_detach_i2c_dev(struct i2c_dev_desc *dev)
552a79ac2cdSJorge Marques {
553a79ac2cdSJorge Marques 	struct i3c_master_controller *m = i2c_dev_get_master(dev);
554a79ac2cdSJorge Marques 	struct adi_i3c_master *master = to_adi_i3c_master(m);
555a79ac2cdSJorge Marques 	struct adi_i3c_i2c_dev_data *data = i2c_dev_get_master_data(dev);
556a79ac2cdSJorge Marques 
557a79ac2cdSJorge Marques 	writel(REG_DEV_CHAR_ADDR(dev->addr) |
558a79ac2cdSJorge Marques 	       REG_DEV_CHAR_IS_I2C | REG_DEV_CHAR_WEN,
559a79ac2cdSJorge Marques 	       master->regs + REG_DEV_CHAR);
560a79ac2cdSJorge Marques 
561a79ac2cdSJorge Marques 	i2c_dev_set_master_data(dev, NULL);
562a79ac2cdSJorge Marques 	master->free_rr_slots |= BIT(data->id);
563a79ac2cdSJorge Marques 	kfree(data);
564a79ac2cdSJorge Marques }
565a79ac2cdSJorge Marques 
adi_i3c_master_bus_cleanup(struct i3c_master_controller * m)566a79ac2cdSJorge Marques static void adi_i3c_master_bus_cleanup(struct i3c_master_controller *m)
567a79ac2cdSJorge Marques {
568a79ac2cdSJorge Marques 	struct adi_i3c_master *master = to_adi_i3c_master(m);
569a79ac2cdSJorge Marques 
570a79ac2cdSJorge Marques 	adi_i3c_master_disable(master);
571a79ac2cdSJorge Marques }
572a79ac2cdSJorge Marques 
adi_i3c_master_upd_i3c_scl_lim(struct adi_i3c_master * master)573a79ac2cdSJorge Marques static void adi_i3c_master_upd_i3c_scl_lim(struct adi_i3c_master *master)
574a79ac2cdSJorge Marques {
575a79ac2cdSJorge Marques 	struct i3c_master_controller *m = &master->base;
576a79ac2cdSJorge Marques 	struct i3c_bus *bus = i3c_master_get_bus(m);
577a79ac2cdSJorge Marques 	u8 i3c_scl_lim = 0;
578a79ac2cdSJorge Marques 	struct i3c_dev_desc *dev;
579a79ac2cdSJorge Marques 	u8 pp_sg;
580a79ac2cdSJorge Marques 
581a79ac2cdSJorge Marques 	i3c_bus_for_each_i3cdev(bus, dev) {
582a79ac2cdSJorge Marques 		u8 max_fscl;
583a79ac2cdSJorge Marques 
584a79ac2cdSJorge Marques 		max_fscl = max(I3C_CCC_MAX_SDR_FSCL(dev->info.max_read_ds),
585a79ac2cdSJorge Marques 			       I3C_CCC_MAX_SDR_FSCL(dev->info.max_write_ds));
586a79ac2cdSJorge Marques 
587a79ac2cdSJorge Marques 		switch (max_fscl) {
588a79ac2cdSJorge Marques 		case I3C_SDR1_FSCL_8MHZ:
589a79ac2cdSJorge Marques 			max_fscl = PP_SG_6MHZ;
590a79ac2cdSJorge Marques 			break;
591a79ac2cdSJorge Marques 		case I3C_SDR2_FSCL_6MHZ:
592a79ac2cdSJorge Marques 			max_fscl = PP_SG_3MHZ;
593a79ac2cdSJorge Marques 			break;
594a79ac2cdSJorge Marques 		case I3C_SDR3_FSCL_4MHZ:
595a79ac2cdSJorge Marques 			max_fscl = PP_SG_3MHZ;
596a79ac2cdSJorge Marques 			break;
597a79ac2cdSJorge Marques 		case I3C_SDR4_FSCL_2MHZ:
598a79ac2cdSJorge Marques 			max_fscl = PP_SG_1MHZ;
599a79ac2cdSJorge Marques 			break;
600a79ac2cdSJorge Marques 		case I3C_SDR0_FSCL_MAX:
601a79ac2cdSJorge Marques 		default:
602a79ac2cdSJorge Marques 			max_fscl = PP_SG_12MHZ;
603a79ac2cdSJorge Marques 			break;
604a79ac2cdSJorge Marques 		}
605a79ac2cdSJorge Marques 
606a79ac2cdSJorge Marques 		if (max_fscl &&
607a79ac2cdSJorge Marques 		    (i3c_scl_lim > max_fscl || !i3c_scl_lim))
608a79ac2cdSJorge Marques 			i3c_scl_lim = max_fscl;
609a79ac2cdSJorge Marques 	}
610a79ac2cdSJorge Marques 
611a79ac2cdSJorge Marques 	if (!i3c_scl_lim)
612a79ac2cdSJorge Marques 		return;
613a79ac2cdSJorge Marques 
614a79ac2cdSJorge Marques 	master->i3c_scl_lim = i3c_scl_lim - 1;
615a79ac2cdSJorge Marques 
616a79ac2cdSJorge Marques 	pp_sg = readl(master->regs + REG_OPS) & ~REG_OPS_PP_SG_MASK;
617a79ac2cdSJorge Marques 	pp_sg |= REG_OPS_SET_SG(master->i3c_scl_lim);
618a79ac2cdSJorge Marques 
619a79ac2cdSJorge Marques 	writel(pp_sg, master->regs + REG_OPS);
620a79ac2cdSJorge Marques }
621a79ac2cdSJorge Marques 
adi_i3c_master_get_features(struct adi_i3c_master * master,unsigned int slot,struct i3c_device_info * info)622a79ac2cdSJorge Marques static void adi_i3c_master_get_features(struct adi_i3c_master *master,
623a79ac2cdSJorge Marques 					unsigned int slot,
624a79ac2cdSJorge Marques 					struct i3c_device_info *info)
625a79ac2cdSJorge Marques {
626a79ac2cdSJorge Marques 	u32 buf;
627a79ac2cdSJorge Marques 
628a79ac2cdSJorge Marques 	/* Dynamic address and PID are for identification only */
629a79ac2cdSJorge Marques 	memset(info, 0, sizeof(*info));
630a79ac2cdSJorge Marques 	buf = readl(master->regs + REG_DCR_BCR_DA);
631a79ac2cdSJorge Marques 	info->dyn_addr = REG_DCR_BCR_DA_GET_DA(buf);
632a79ac2cdSJorge Marques 	info->dcr = REG_DCR_BCR_DA_GET_DCR(buf);
633a79ac2cdSJorge Marques 	info->bcr = REG_DCR_BCR_DA_GET_BCR(buf);
634a79ac2cdSJorge Marques 	info->pid = readl(master->regs + REG_PID_L);
635a79ac2cdSJorge Marques 	info->pid |= (u64)readl(master->regs + REG_PID_H) << 32;
636a79ac2cdSJorge Marques }
637a79ac2cdSJorge Marques 
adi_i3c_master_do_daa(struct i3c_master_controller * m)638a79ac2cdSJorge Marques static int adi_i3c_master_do_daa(struct i3c_master_controller *m)
639a79ac2cdSJorge Marques {
640a79ac2cdSJorge Marques 	struct adi_i3c_master *master = to_adi_i3c_master(m);
641a79ac2cdSJorge Marques 	int ret, addr = 0;
642a79ac2cdSJorge Marques 	u32 irq_mask;
643a79ac2cdSJorge Marques 
644a79ac2cdSJorge Marques 	for (u8 i = 0; i < ADI_MAX_DEVS; i++) {
645a79ac2cdSJorge Marques 		addr = i3c_master_get_free_addr(m, addr);
646a79ac2cdSJorge Marques 		if (addr < 0)
647a79ac2cdSJorge Marques 			return addr;
648a79ac2cdSJorge Marques 		master->daa.addrs[i] = addr;
649a79ac2cdSJorge Marques 	}
650a79ac2cdSJorge Marques 
651a79ac2cdSJorge Marques 	irq_mask = readl(master->regs + REG_IRQ_MASK);
652a79ac2cdSJorge Marques 	writel(irq_mask | REG_IRQ_PENDING_DAA,
653a79ac2cdSJorge Marques 	       master->regs + REG_IRQ_MASK);
654a79ac2cdSJorge Marques 
655a79ac2cdSJorge Marques 	master->daa.index = 0;
656a79ac2cdSJorge Marques 	ret = i3c_master_entdaa_locked(&master->base);
657a79ac2cdSJorge Marques 
658a79ac2cdSJorge Marques 	writel(irq_mask, master->regs + REG_IRQ_MASK);
659a79ac2cdSJorge Marques 
660a79ac2cdSJorge Marques 	/* DAA always finishes with CE2_ERROR or NACK_RESP */
661a79ac2cdSJorge Marques 	if (ret && ret != I3C_ERROR_M2)
662a79ac2cdSJorge Marques 		return ret;
663a79ac2cdSJorge Marques 
664a79ac2cdSJorge Marques 	/* Add I3C devices discovered */
665a79ac2cdSJorge Marques 	for (u8 i = 0; i < master->daa.index; i++)
666a79ac2cdSJorge Marques 		i3c_master_add_i3c_dev_locked(m, master->daa.addrs[i]);
667a79ac2cdSJorge Marques 	/* Sync retrieved devs info with the IP */
668a79ac2cdSJorge Marques 	adi_i3c_master_sync_dev_char(m);
669a79ac2cdSJorge Marques 
670a79ac2cdSJorge Marques 	i3c_master_defslvs_locked(&master->base);
671a79ac2cdSJorge Marques 
672a79ac2cdSJorge Marques 	adi_i3c_master_upd_i3c_scl_lim(master);
673a79ac2cdSJorge Marques 
674a79ac2cdSJorge Marques 	return 0;
675a79ac2cdSJorge Marques }
676a79ac2cdSJorge Marques 
adi_i3c_master_bus_init(struct i3c_master_controller * m)677a79ac2cdSJorge Marques static int adi_i3c_master_bus_init(struct i3c_master_controller *m)
678a79ac2cdSJorge Marques {
679a79ac2cdSJorge Marques 	struct adi_i3c_master *master = to_adi_i3c_master(m);
680a79ac2cdSJorge Marques 	struct i3c_device_info info = { };
681a79ac2cdSJorge Marques 	int ret;
682a79ac2cdSJorge Marques 
683a79ac2cdSJorge Marques 	ret = i3c_master_get_free_addr(m, 0);
684a79ac2cdSJorge Marques 	if (ret < 0)
685a79ac2cdSJorge Marques 		return ret;
686a79ac2cdSJorge Marques 
687a79ac2cdSJorge Marques 	adi_i3c_master_get_features(master, 0, &info);
688a79ac2cdSJorge Marques 	ret = i3c_master_set_info(&master->base, &info);
689a79ac2cdSJorge Marques 	if (ret)
690a79ac2cdSJorge Marques 		return ret;
691a79ac2cdSJorge Marques 
692a79ac2cdSJorge Marques 	writel(REG_IBI_CONFIG_LISTEN,
693a79ac2cdSJorge Marques 	       master->regs + REG_IBI_CONFIG);
694a79ac2cdSJorge Marques 
695a79ac2cdSJorge Marques 	return 0;
696a79ac2cdSJorge Marques }
697a79ac2cdSJorge Marques 
adi_i3c_master_handle_ibi(struct adi_i3c_master * master,u32 raw)698a79ac2cdSJorge Marques static void adi_i3c_master_handle_ibi(struct adi_i3c_master *master,
699a79ac2cdSJorge Marques 				      u32 raw)
700a79ac2cdSJorge Marques {
701a79ac2cdSJorge Marques 	struct adi_i3c_i2c_dev_data *data;
702a79ac2cdSJorge Marques 	struct i3c_ibi_slot *slot;
703a79ac2cdSJorge Marques 	struct i3c_dev_desc *dev;
704a79ac2cdSJorge Marques 	u8 da, id, mdb, len;
705a79ac2cdSJorge Marques 	u8 *buf;
706a79ac2cdSJorge Marques 
707a79ac2cdSJorge Marques 	da = FIELD_GET(GENMASK(23, 17), raw);
708a79ac2cdSJorge Marques 	mdb = FIELD_GET(GENMASK(15, 8), raw);
709a79ac2cdSJorge Marques 	for (id = 0; id < master->ibi.num_slots; id++) {
710a79ac2cdSJorge Marques 		if (master->ibi.slots[id] &&
711a79ac2cdSJorge Marques 		    master->ibi.slots[id]->info.dyn_addr == da)
712a79ac2cdSJorge Marques 			break;
713a79ac2cdSJorge Marques 	}
714a79ac2cdSJorge Marques 
715a79ac2cdSJorge Marques 	if (id == master->ibi.num_slots)
716a79ac2cdSJorge Marques 		return;
717a79ac2cdSJorge Marques 
718a79ac2cdSJorge Marques 	dev = master->ibi.slots[id];
719a79ac2cdSJorge Marques 	len = ADI_HAS_MDB_FROM_BCR(dev->info.bcr);
720a79ac2cdSJorge Marques 	data = i3c_dev_get_master_data(dev);
721a79ac2cdSJorge Marques 
722a79ac2cdSJorge Marques 	guard(spinlock)(&master->ibi.lock);
723a79ac2cdSJorge Marques 	slot = i3c_generic_ibi_get_free_slot(data->ibi_pool);
724a79ac2cdSJorge Marques 	if (!slot)
725a79ac2cdSJorge Marques 		return;
726a79ac2cdSJorge Marques 
727a79ac2cdSJorge Marques 	slot->len = len;
728a79ac2cdSJorge Marques 	buf = slot->data;
729a79ac2cdSJorge Marques 	buf[0] = mdb;
730a79ac2cdSJorge Marques 	i3c_master_queue_ibi(dev, slot);
731a79ac2cdSJorge Marques }
732a79ac2cdSJorge Marques 
adi_i3c_master_demux_ibis(struct adi_i3c_master * master)733a79ac2cdSJorge Marques static void adi_i3c_master_demux_ibis(struct adi_i3c_master *master)
734a79ac2cdSJorge Marques {
735a79ac2cdSJorge Marques 	while (!(readl(master->regs + REG_FIFO_STATUS) & REG_FIFO_STATUS_IBI_EMPTY)) {
736a79ac2cdSJorge Marques 		u32 raw = readl(master->regs + REG_IBI_FIFO);
737a79ac2cdSJorge Marques 
738a79ac2cdSJorge Marques 		adi_i3c_master_handle_ibi(master, raw);
739a79ac2cdSJorge Marques 	}
740a79ac2cdSJorge Marques }
741a79ac2cdSJorge Marques 
adi_i3c_master_handle_da_req(struct adi_i3c_master * master)742a79ac2cdSJorge Marques static void adi_i3c_master_handle_da_req(struct adi_i3c_master *master)
743a79ac2cdSJorge Marques {
744a79ac2cdSJorge Marques 	u8 payload0[8];
745a79ac2cdSJorge Marques 	u32 addr;
746a79ac2cdSJorge Marques 
747a79ac2cdSJorge Marques 	adi_i3c_master_rd_from_rx_fifo(master, payload0, 6);
748a79ac2cdSJorge Marques 	addr = master->daa.addrs[master->daa.index++];
749a79ac2cdSJorge Marques 	addr = (addr << 1) | (parity8(addr) ? 0 : 1);
750a79ac2cdSJorge Marques 
751a79ac2cdSJorge Marques 	writel(addr, master->regs + REG_SDO_FIFO);
752a79ac2cdSJorge Marques }
753a79ac2cdSJorge Marques 
adi_i3c_master_irq(int irq,void * data)754a79ac2cdSJorge Marques static irqreturn_t adi_i3c_master_irq(int irq, void *data)
755a79ac2cdSJorge Marques {
756a79ac2cdSJorge Marques 	struct adi_i3c_master *master = data;
757a79ac2cdSJorge Marques 	u32 pending;
758a79ac2cdSJorge Marques 
759a79ac2cdSJorge Marques 	pending = readl(master->regs + REG_IRQ_PENDING);
760a79ac2cdSJorge Marques 	writel(pending, master->regs + REG_IRQ_PENDING);
761a79ac2cdSJorge Marques 	if (pending & REG_IRQ_PENDING_CMDR) {
762a79ac2cdSJorge Marques 		scoped_guard(spinlock_irqsave, &master->xferqueue.lock) {
763a79ac2cdSJorge Marques 			adi_i3c_master_end_xfer_locked(master, pending);
764a79ac2cdSJorge Marques 		}
765a79ac2cdSJorge Marques 	}
766a79ac2cdSJorge Marques 	if (pending & REG_IRQ_PENDING_IBI)
767a79ac2cdSJorge Marques 		adi_i3c_master_demux_ibis(master);
768a79ac2cdSJorge Marques 	if (pending & REG_IRQ_PENDING_DAA)
769a79ac2cdSJorge Marques 		adi_i3c_master_handle_da_req(master);
770a79ac2cdSJorge Marques 
771a79ac2cdSJorge Marques 	return IRQ_HANDLED;
772a79ac2cdSJorge Marques }
773a79ac2cdSJorge Marques 
adi_i3c_master_i2c_xfers(struct i2c_dev_desc * dev,struct i2c_msg * xfers,int nxfers)774a79ac2cdSJorge Marques static int adi_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
775a79ac2cdSJorge Marques 				    struct i2c_msg *xfers,
776a79ac2cdSJorge Marques 				    int nxfers)
777a79ac2cdSJorge Marques {
778a79ac2cdSJorge Marques 	struct i3c_master_controller *m = i2c_dev_get_master(dev);
779a79ac2cdSJorge Marques 	struct adi_i3c_master *master = to_adi_i3c_master(m);
780a79ac2cdSJorge Marques 	struct adi_i3c_xfer *xfer __free(kfree) = NULL;
781a79ac2cdSJorge Marques 	int i;
782a79ac2cdSJorge Marques 
783a79ac2cdSJorge Marques 	if (!nxfers)
784a79ac2cdSJorge Marques 		return 0;
785a79ac2cdSJorge Marques 	for (i = 0; i < nxfers; i++) {
786a79ac2cdSJorge Marques 		if (xfers[i].flags & I2C_M_TEN)
787a79ac2cdSJorge Marques 			return -EOPNOTSUPP;
788a79ac2cdSJorge Marques 	}
789a79ac2cdSJorge Marques 	xfer = adi_i3c_master_alloc_xfer(master, nxfers);
790a79ac2cdSJorge Marques 	if (!xfer)
791a79ac2cdSJorge Marques 		return -ENOMEM;
792a79ac2cdSJorge Marques 
793a79ac2cdSJorge Marques 	for (i = 0; i < nxfers; i++) {
794a79ac2cdSJorge Marques 		struct adi_i3c_cmd *ccmd = &xfer->cmds[i];
795a79ac2cdSJorge Marques 
796a79ac2cdSJorge Marques 		ccmd->cmd0 = REG_CMD_FIFO_0_DEV_ADDR(xfers[i].addr);
797a79ac2cdSJorge Marques 
798a79ac2cdSJorge Marques 		if (xfers[i].flags & I2C_M_RD) {
799a79ac2cdSJorge Marques 			ccmd->cmd0 |= REG_CMD_FIFO_0_RNW;
800a79ac2cdSJorge Marques 			ccmd->rx_buf = xfers[i].buf;
801a79ac2cdSJorge Marques 			ccmd->rx_len = xfers[i].len;
802a79ac2cdSJorge Marques 		} else {
803a79ac2cdSJorge Marques 			ccmd->tx_buf = xfers[i].buf;
804a79ac2cdSJorge Marques 			ccmd->tx_len = xfers[i].len;
805a79ac2cdSJorge Marques 		}
806a79ac2cdSJorge Marques 
807a79ac2cdSJorge Marques 		ccmd->cmd0 |= REG_CMD_FIFO_0_LEN(xfers[i].len);
808a79ac2cdSJorge Marques 	}
809a79ac2cdSJorge Marques 
810a79ac2cdSJorge Marques 	adi_i3c_master_queue_xfer(master, xfer);
811a79ac2cdSJorge Marques 	if (!wait_for_completion_timeout(&xfer->comp,
812a79ac2cdSJorge Marques 					 m->i2c.timeout))
813a79ac2cdSJorge Marques 		adi_i3c_master_unqueue_xfer(master, xfer);
814a79ac2cdSJorge Marques 
815a79ac2cdSJorge Marques 	return xfer->ret;
816a79ac2cdSJorge Marques }
817a79ac2cdSJorge Marques 
adi_i3c_master_disable_ibi(struct i3c_dev_desc * dev)818a79ac2cdSJorge Marques static int adi_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
819a79ac2cdSJorge Marques {
820a79ac2cdSJorge Marques 	struct i3c_master_controller *m = i3c_dev_get_master(dev);
821a79ac2cdSJorge Marques 	struct adi_i3c_master *master = to_adi_i3c_master(m);
822a79ac2cdSJorge Marques 	struct i3c_dev_desc *i3cdev;
823a79ac2cdSJorge Marques 	u32 enabled = 0;
824a79ac2cdSJorge Marques 	int ret;
825a79ac2cdSJorge Marques 
826a79ac2cdSJorge Marques 	ret = i3c_master_disec_locked(m, dev->info.dyn_addr,
827a79ac2cdSJorge Marques 				      I3C_CCC_EVENT_SIR);
828a79ac2cdSJorge Marques 
829a79ac2cdSJorge Marques 	i3c_bus_for_each_i3cdev(&m->bus, i3cdev) {
830a79ac2cdSJorge Marques 		if (dev != i3cdev && i3cdev->ibi)
831a79ac2cdSJorge Marques 			enabled |= i3cdev->ibi->enabled;
832a79ac2cdSJorge Marques 	}
833a79ac2cdSJorge Marques 	if (!enabled) {
834a79ac2cdSJorge Marques 		writel(REG_IBI_CONFIG_LISTEN,
835a79ac2cdSJorge Marques 		       master->regs + REG_IBI_CONFIG);
836a79ac2cdSJorge Marques 		writel(readl(master->regs + REG_IRQ_MASK) & ~REG_IRQ_PENDING_IBI,
837a79ac2cdSJorge Marques 		       master->regs + REG_IRQ_MASK);
838a79ac2cdSJorge Marques 	}
839a79ac2cdSJorge Marques 
840a79ac2cdSJorge Marques 	return ret;
841a79ac2cdSJorge Marques }
842a79ac2cdSJorge Marques 
adi_i3c_master_enable_ibi(struct i3c_dev_desc * dev)843a79ac2cdSJorge Marques static int adi_i3c_master_enable_ibi(struct i3c_dev_desc *dev)
844a79ac2cdSJorge Marques {
845a79ac2cdSJorge Marques 	struct i3c_master_controller *m = i3c_dev_get_master(dev);
846a79ac2cdSJorge Marques 	struct adi_i3c_master *master = to_adi_i3c_master(m);
847a79ac2cdSJorge Marques 
848a79ac2cdSJorge Marques 	writel(REG_IBI_CONFIG_LISTEN | REG_IBI_CONFIG_ENABLE,
849a79ac2cdSJorge Marques 	       master->regs + REG_IBI_CONFIG);
850a79ac2cdSJorge Marques 
851a79ac2cdSJorge Marques 	writel(readl(master->regs + REG_IRQ_MASK) | REG_IRQ_PENDING_IBI,
852a79ac2cdSJorge Marques 	       master->regs + REG_IRQ_MASK);
853a79ac2cdSJorge Marques 
854a79ac2cdSJorge Marques 	return i3c_master_enec_locked(m, dev->info.dyn_addr,
855a79ac2cdSJorge Marques 				      I3C_CCC_EVENT_SIR);
856a79ac2cdSJorge Marques }
857a79ac2cdSJorge Marques 
adi_i3c_master_request_ibi(struct i3c_dev_desc * dev,const struct i3c_ibi_setup * req)858a79ac2cdSJorge Marques static int adi_i3c_master_request_ibi(struct i3c_dev_desc *dev,
859a79ac2cdSJorge Marques 				      const struct i3c_ibi_setup *req)
860a79ac2cdSJorge Marques {
861a79ac2cdSJorge Marques 	struct i3c_master_controller *m = i3c_dev_get_master(dev);
862a79ac2cdSJorge Marques 	struct adi_i3c_master *master = to_adi_i3c_master(m);
863a79ac2cdSJorge Marques 	struct adi_i3c_i2c_dev_data *data;
864a79ac2cdSJorge Marques 	unsigned int i;
865a79ac2cdSJorge Marques 
866a79ac2cdSJorge Marques 	data = i3c_dev_get_master_data(dev);
867a79ac2cdSJorge Marques 	data->ibi_pool = i3c_generic_ibi_alloc_pool(dev, req);
868a79ac2cdSJorge Marques 	if (IS_ERR(data->ibi_pool))
869a79ac2cdSJorge Marques 		return PTR_ERR(data->ibi_pool);
870a79ac2cdSJorge Marques 
871a79ac2cdSJorge Marques 	scoped_guard(spinlock_irqsave, &master->ibi.lock) {
872a79ac2cdSJorge Marques 		for (i = 0; i < master->ibi.num_slots; i++) {
873a79ac2cdSJorge Marques 			if (!master->ibi.slots[i]) {
874a79ac2cdSJorge Marques 				data->ibi = i;
875a79ac2cdSJorge Marques 				master->ibi.slots[i] = dev;
876a79ac2cdSJorge Marques 				break;
877a79ac2cdSJorge Marques 			}
878a79ac2cdSJorge Marques 		}
879a79ac2cdSJorge Marques 	}
880a79ac2cdSJorge Marques 
881a79ac2cdSJorge Marques 	if (i < master->ibi.num_slots)
882a79ac2cdSJorge Marques 		return 0;
883a79ac2cdSJorge Marques 
884a79ac2cdSJorge Marques 	i3c_generic_ibi_free_pool(data->ibi_pool);
885a79ac2cdSJorge Marques 	data->ibi_pool = NULL;
886a79ac2cdSJorge Marques 
887a79ac2cdSJorge Marques 	return -ENOSPC;
888a79ac2cdSJorge Marques }
889a79ac2cdSJorge Marques 
adi_i3c_master_free_ibi(struct i3c_dev_desc * dev)890a79ac2cdSJorge Marques static void adi_i3c_master_free_ibi(struct i3c_dev_desc *dev)
891a79ac2cdSJorge Marques {
892a79ac2cdSJorge Marques 	struct i3c_master_controller *m = i3c_dev_get_master(dev);
893a79ac2cdSJorge Marques 	struct adi_i3c_master *master = to_adi_i3c_master(m);
894a79ac2cdSJorge Marques 	struct adi_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
895a79ac2cdSJorge Marques 
896a79ac2cdSJorge Marques 	scoped_guard(spinlock_irqsave, &master->ibi.lock) {
897a79ac2cdSJorge Marques 		master->ibi.slots[data->ibi] = NULL;
898a79ac2cdSJorge Marques 	}
899a79ac2cdSJorge Marques 
900a79ac2cdSJorge Marques 	i3c_generic_ibi_free_pool(data->ibi_pool);
901a79ac2cdSJorge Marques }
902a79ac2cdSJorge Marques 
adi_i3c_master_recycle_ibi_slot(struct i3c_dev_desc * dev,struct i3c_ibi_slot * slot)903a79ac2cdSJorge Marques static void adi_i3c_master_recycle_ibi_slot(struct i3c_dev_desc *dev,
904a79ac2cdSJorge Marques 					    struct i3c_ibi_slot *slot)
905a79ac2cdSJorge Marques {
906a79ac2cdSJorge Marques 	struct adi_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
907a79ac2cdSJorge Marques 
908a79ac2cdSJorge Marques 	i3c_generic_ibi_recycle_slot(data->ibi_pool, slot);
909a79ac2cdSJorge Marques }
910a79ac2cdSJorge Marques 
911a79ac2cdSJorge Marques static const struct i3c_master_controller_ops adi_i3c_master_ops = {
912a79ac2cdSJorge Marques 	.bus_init = adi_i3c_master_bus_init,
913a79ac2cdSJorge Marques 	.bus_cleanup = adi_i3c_master_bus_cleanup,
914a79ac2cdSJorge Marques 	.attach_i3c_dev = adi_i3c_master_attach_i3c_dev,
915a79ac2cdSJorge Marques 	.reattach_i3c_dev = adi_i3c_master_reattach_i3c_dev,
916a79ac2cdSJorge Marques 	.detach_i3c_dev = adi_i3c_master_detach_i3c_dev,
917a79ac2cdSJorge Marques 	.attach_i2c_dev = adi_i3c_master_attach_i2c_dev,
918a79ac2cdSJorge Marques 	.detach_i2c_dev = adi_i3c_master_detach_i2c_dev,
919a79ac2cdSJorge Marques 	.do_daa = adi_i3c_master_do_daa,
920a79ac2cdSJorge Marques 	.supports_ccc_cmd = adi_i3c_master_supports_ccc_cmd,
921a79ac2cdSJorge Marques 	.send_ccc_cmd = adi_i3c_master_send_ccc_cmd,
922a79ac2cdSJorge Marques 	.priv_xfers = adi_i3c_master_priv_xfers,
923a79ac2cdSJorge Marques 	.i2c_xfers = adi_i3c_master_i2c_xfers,
924a79ac2cdSJorge Marques 	.request_ibi = adi_i3c_master_request_ibi,
925a79ac2cdSJorge Marques 	.enable_ibi = adi_i3c_master_enable_ibi,
926a79ac2cdSJorge Marques 	.disable_ibi = adi_i3c_master_disable_ibi,
927a79ac2cdSJorge Marques 	.free_ibi = adi_i3c_master_free_ibi,
928a79ac2cdSJorge Marques 	.recycle_ibi_slot = adi_i3c_master_recycle_ibi_slot,
929a79ac2cdSJorge Marques };
930a79ac2cdSJorge Marques 
931a79ac2cdSJorge Marques static const struct of_device_id adi_i3c_master_of_match[] = {
932a79ac2cdSJorge Marques 	{ .compatible = "adi,i3c-master-v1" },
933a79ac2cdSJorge Marques 	{}
934a79ac2cdSJorge Marques };
935a79ac2cdSJorge Marques 
adi_i3c_master_probe(struct platform_device * pdev)936a79ac2cdSJorge Marques static int adi_i3c_master_probe(struct platform_device *pdev)
937a79ac2cdSJorge Marques {
938a79ac2cdSJorge Marques 	struct adi_i3c_master *master;
939a79ac2cdSJorge Marques 	struct clk_bulk_data *clk;
940a79ac2cdSJorge Marques 	unsigned int version;
941a79ac2cdSJorge Marques 	int ret, irq;
942a79ac2cdSJorge Marques 
943a79ac2cdSJorge Marques 	master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
944a79ac2cdSJorge Marques 	if (!master)
945a79ac2cdSJorge Marques 		return -ENOMEM;
946a79ac2cdSJorge Marques 
947a79ac2cdSJorge Marques 	master->regs = devm_platform_ioremap_resource(pdev, 0);
948a79ac2cdSJorge Marques 	if (IS_ERR(master->regs))
949a79ac2cdSJorge Marques 		return PTR_ERR(master->regs);
950a79ac2cdSJorge Marques 
951a79ac2cdSJorge Marques 	ret = devm_clk_bulk_get_all_enabled(&pdev->dev, &clk);
952a79ac2cdSJorge Marques 	if (ret < 0)
953a79ac2cdSJorge Marques 		return dev_err_probe(&pdev->dev, ret,
954a79ac2cdSJorge Marques 				     "Failed to get clocks\n");
955a79ac2cdSJorge Marques 
956a79ac2cdSJorge Marques 	irq = platform_get_irq(pdev, 0);
957a79ac2cdSJorge Marques 	if (irq < 0)
958a79ac2cdSJorge Marques 		return irq;
959a79ac2cdSJorge Marques 
960a79ac2cdSJorge Marques 	version = readl(master->regs + ADI_AXI_REG_VERSION);
961a79ac2cdSJorge Marques 	if (ADI_AXI_PCORE_VER_MAJOR(version) != 1)
962a79ac2cdSJorge Marques 		dev_err_probe(&pdev->dev, -ENODEV, "Unsupported peripheral version %u.%u.%u\n",
963a79ac2cdSJorge Marques 			      ADI_AXI_PCORE_VER_MAJOR(version),
964a79ac2cdSJorge Marques 			      ADI_AXI_PCORE_VER_MINOR(version),
965a79ac2cdSJorge Marques 			      ADI_AXI_PCORE_VER_PATCH(version));
966a79ac2cdSJorge Marques 
967a79ac2cdSJorge Marques 	writel(0x00, master->regs + REG_ENABLE);
968a79ac2cdSJorge Marques 	writel(0x00, master->regs + REG_IRQ_MASK);
969a79ac2cdSJorge Marques 
970a79ac2cdSJorge Marques 	ret = devm_request_irq(&pdev->dev, irq, adi_i3c_master_irq, 0,
971a79ac2cdSJorge Marques 			       dev_name(&pdev->dev), master);
972a79ac2cdSJorge Marques 	if (ret)
973a79ac2cdSJorge Marques 		return ret;
974a79ac2cdSJorge Marques 
975a79ac2cdSJorge Marques 	platform_set_drvdata(pdev, master);
976a79ac2cdSJorge Marques 
977a79ac2cdSJorge Marques 	master->free_rr_slots = GENMASK(ADI_MAX_DEVS, 1);
978a79ac2cdSJorge Marques 
979a79ac2cdSJorge Marques 	writel(REG_IRQ_PENDING_CMDR, master->regs + REG_IRQ_MASK);
980a79ac2cdSJorge Marques 
981a79ac2cdSJorge Marques 	spin_lock_init(&master->ibi.lock);
982a79ac2cdSJorge Marques 	master->ibi.num_slots = 15;
983a79ac2cdSJorge Marques 	master->ibi.slots = devm_kcalloc(&pdev->dev, master->ibi.num_slots,
984a79ac2cdSJorge Marques 					 sizeof(*master->ibi.slots),
985a79ac2cdSJorge Marques 					 GFP_KERNEL);
986a79ac2cdSJorge Marques 	if (!master->ibi.slots)
987a79ac2cdSJorge Marques 		return -ENOMEM;
988a79ac2cdSJorge Marques 
989a79ac2cdSJorge Marques 	spin_lock_init(&master->xferqueue.lock);
990a79ac2cdSJorge Marques 	INIT_LIST_HEAD(&master->xferqueue.list);
991a79ac2cdSJorge Marques 
992a79ac2cdSJorge Marques 	return i3c_master_register(&master->base, &pdev->dev,
993a79ac2cdSJorge Marques 				   &adi_i3c_master_ops, false);
994a79ac2cdSJorge Marques }
995a79ac2cdSJorge Marques 
adi_i3c_master_remove(struct platform_device * pdev)996a79ac2cdSJorge Marques static void adi_i3c_master_remove(struct platform_device *pdev)
997a79ac2cdSJorge Marques {
998a79ac2cdSJorge Marques 	struct adi_i3c_master *master = platform_get_drvdata(pdev);
999a79ac2cdSJorge Marques 
1000a79ac2cdSJorge Marques 	writel(0xff, master->regs + REG_IRQ_PENDING);
1001a79ac2cdSJorge Marques 	writel(0x00, master->regs + REG_IRQ_MASK);
1002a79ac2cdSJorge Marques 	writel(0x01, master->regs + REG_ENABLE);
1003a79ac2cdSJorge Marques 
1004a79ac2cdSJorge Marques 	i3c_master_unregister(&master->base);
1005a79ac2cdSJorge Marques }
1006a79ac2cdSJorge Marques 
1007a79ac2cdSJorge Marques static struct platform_driver adi_i3c_master = {
1008a79ac2cdSJorge Marques 	.probe = adi_i3c_master_probe,
1009a79ac2cdSJorge Marques 	.remove = adi_i3c_master_remove,
1010a79ac2cdSJorge Marques 	.driver = {
1011a79ac2cdSJorge Marques 		.name = "adi-i3c-master",
1012a79ac2cdSJorge Marques 		.of_match_table = adi_i3c_master_of_match,
1013a79ac2cdSJorge Marques 	},
1014a79ac2cdSJorge Marques };
1015a79ac2cdSJorge Marques module_platform_driver(adi_i3c_master);
1016a79ac2cdSJorge Marques 
1017a79ac2cdSJorge Marques MODULE_AUTHOR("Jorge Marques <jorge.marques@analog.com>");
1018a79ac2cdSJorge Marques MODULE_DESCRIPTION("Analog Devices I3C master driver");
1019a79ac2cdSJorge Marques MODULE_LICENSE("GPL");
1020