xref: /OK3568_Linux_fs/kernel/drivers/spi/spidev-rkmst.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2023 Rockchip Electronics Co., Ltd.
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include <linux/delay.h>
7*4882a593Smuzhiyun #include <linux/gpio.h>
8*4882a593Smuzhiyun #include <linux/interrupt.h>
9*4882a593Smuzhiyun #include <linux/iopoll.h>
10*4882a593Smuzhiyun #include <linux/miscdevice.h>
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <linux/of.h>
13*4882a593Smuzhiyun #include <linux/of_gpio.h>
14*4882a593Smuzhiyun #include <linux/platform_device.h>
15*4882a593Smuzhiyun #include <linux/random.h>
16*4882a593Smuzhiyun #include <linux/slab.h>
17*4882a593Smuzhiyun #include <linux/spi/spi.h>
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #include <linux/platform_data/spi-rockchip.h>
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun #define SPI_OBJ_MAX_XFER_SIZE	0x1040
22*4882a593Smuzhiyun #define SPI_OBJ_APP_RAM_SIZE	0x10000
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #define SPI_OBJ_CTRL_MSG_SIZE	0x8
25*4882a593Smuzhiyun #define SPI_OBJ_CTRL_CMD_INIT	0x99
26*4882a593Smuzhiyun #define SPI_OBJ_CTRL_CMD_READ	0x3A
27*4882a593Smuzhiyun #define SPI_OBJ_CTRL_CMD_WRITE	0x4B
28*4882a593Smuzhiyun #define SPI_OBJ_CTRL_CMD_DUPLEX	0x5C
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #define SPI_OBJ_DEFAULT_TIMEOUT_US	100000
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun struct spi_obj_ctrl {
33*4882a593Smuzhiyun 	u16 cmd;
34*4882a593Smuzhiyun 	u16 addr;
35*4882a593Smuzhiyun 	u32 data;
36*4882a593Smuzhiyun };
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun struct spidev_rkmst_data {
39*4882a593Smuzhiyun 	struct device	*dev;
40*4882a593Smuzhiyun 	struct spi_device *spi;
41*4882a593Smuzhiyun 	char *ctrlbuf;
42*4882a593Smuzhiyun 	char *rxbuf;
43*4882a593Smuzhiyun 	char *txbuf;
44*4882a593Smuzhiyun 	struct gpio_desc *ready;
45*4882a593Smuzhiyun 	int ready_irqnum;
46*4882a593Smuzhiyun 	bool ready_status;
47*4882a593Smuzhiyun 	bool verbose;
48*4882a593Smuzhiyun 	struct miscdevice misc_dev;
49*4882a593Smuzhiyun };
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun static u32 bit_per_word = 8;
52*4882a593Smuzhiyun 
spidev_mst_slave_ready_status(struct spidev_rkmst_data * spidev,bool status)53*4882a593Smuzhiyun static inline void spidev_mst_slave_ready_status(struct spidev_rkmst_data *spidev, bool status)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun 	spidev->ready_status = status;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun 
spidev_mst_slave_ready_interrupt(int irq,void * arg)58*4882a593Smuzhiyun static irqreturn_t spidev_mst_slave_ready_interrupt(int irq, void *arg)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun 	struct spidev_rkmst_data *spidev = (struct spidev_rkmst_data *)arg;
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	spidev_mst_slave_ready_status(spidev, true);
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	return IRQ_HANDLED;
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun 
spidev_mst_check_slave_ready(struct spidev_rkmst_data * spidev)67*4882a593Smuzhiyun static bool spidev_mst_check_slave_ready(struct spidev_rkmst_data *spidev)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun 	return spidev->ready_status;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun 
spidev_mst_wait_for_slave_ready(struct spidev_rkmst_data * spidev,u32 timeout_us)72*4882a593Smuzhiyun static int spidev_mst_wait_for_slave_ready(struct spidev_rkmst_data *spidev,
73*4882a593Smuzhiyun 					   u32 timeout_us)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	bool ready;
76*4882a593Smuzhiyun 	int ret;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	ret = read_poll_timeout(spidev_mst_check_slave_ready, ready,
79*4882a593Smuzhiyun 				ready, 100, timeout_us + 100, false, spidev);
80*4882a593Smuzhiyun 	if (ret) {
81*4882a593Smuzhiyun 		dev_err(&spidev->spi->dev, "timeout and reset slave\n");
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 		return -ETIMEDOUT;
84*4882a593Smuzhiyun 	}
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	return true;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun 
spidev_mst_write(struct spidev_rkmst_data * spidev,const void * txbuf,size_t n)89*4882a593Smuzhiyun static int spidev_mst_write(struct spidev_rkmst_data *spidev, const void *txbuf, size_t n)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	struct spi_device *spi = spidev->spi;
92*4882a593Smuzhiyun 	struct spi_transfer t = {
93*4882a593Smuzhiyun 			.tx_buf = txbuf,
94*4882a593Smuzhiyun 			.len = n,
95*4882a593Smuzhiyun 			.bits_per_word = bit_per_word,
96*4882a593Smuzhiyun 		};
97*4882a593Smuzhiyun 	struct spi_message m;
98*4882a593Smuzhiyun 	int ret;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	spi_message_init(&m);
101*4882a593Smuzhiyun 	spi_message_add_tail(&t, &m);
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	ret = spidev_mst_wait_for_slave_ready(spidev, SPI_OBJ_DEFAULT_TIMEOUT_US);
104*4882a593Smuzhiyun 	if (ret < 0)
105*4882a593Smuzhiyun 		return ret;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	spidev_mst_slave_ready_status(spidev, false);
108*4882a593Smuzhiyun 	ret = spi_sync(spi, &m);
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	return ret;
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun 
spidev_mst_write_bypass(struct spidev_rkmst_data * spidev,const void * txbuf,size_t n)113*4882a593Smuzhiyun static int spidev_mst_write_bypass(struct spidev_rkmst_data *spidev, const void *txbuf, size_t n)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun 	struct spi_device *spi = spidev->spi;
116*4882a593Smuzhiyun 	struct spi_transfer t = {
117*4882a593Smuzhiyun 			.tx_buf = txbuf,
118*4882a593Smuzhiyun 			.len = n,
119*4882a593Smuzhiyun 			.bits_per_word = bit_per_word,
120*4882a593Smuzhiyun 		};
121*4882a593Smuzhiyun 	struct spi_message m;
122*4882a593Smuzhiyun 	int ret;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	spi_message_init(&m);
125*4882a593Smuzhiyun 	spi_message_add_tail(&t, &m);
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	ret = spi_sync(spi, &m);
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	return ret;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun 
spidev_mst_read(struct spidev_rkmst_data * spidev,void * rxbuf,size_t n)132*4882a593Smuzhiyun static int spidev_mst_read(struct spidev_rkmst_data *spidev, void *rxbuf, size_t n)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun 	struct spi_device *spi = spidev->spi;
135*4882a593Smuzhiyun 	struct spi_transfer t = {
136*4882a593Smuzhiyun 			.rx_buf = rxbuf,
137*4882a593Smuzhiyun 			.len = n,
138*4882a593Smuzhiyun 			.bits_per_word = bit_per_word,
139*4882a593Smuzhiyun 		};
140*4882a593Smuzhiyun 	struct spi_message m;
141*4882a593Smuzhiyun 	int ret;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	spi_message_init(&m);
144*4882a593Smuzhiyun 	spi_message_add_tail(&t, &m);
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	ret = spidev_mst_wait_for_slave_ready(spidev, SPI_OBJ_MAX_XFER_SIZE);
147*4882a593Smuzhiyun 	if (ret < 0)
148*4882a593Smuzhiyun 		return ret;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	spidev_mst_slave_ready_status(spidev, false);
151*4882a593Smuzhiyun 	ret = spi_sync(spi, &m);
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	return ret;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun 
spidev_slv_write_and_read(struct spidev_rkmst_data * spidev,const void * tx_buf,void * rx_buf,size_t len)156*4882a593Smuzhiyun static int spidev_slv_write_and_read(struct spidev_rkmst_data *spidev,
157*4882a593Smuzhiyun 				     const void *tx_buf, void *rx_buf,
158*4882a593Smuzhiyun 				     size_t len)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun 	struct spi_device *spi = spidev->spi;
161*4882a593Smuzhiyun 	struct spi_transfer t = {
162*4882a593Smuzhiyun 			.tx_buf = tx_buf,
163*4882a593Smuzhiyun 			.rx_buf = rx_buf,
164*4882a593Smuzhiyun 			.len = len,
165*4882a593Smuzhiyun 		};
166*4882a593Smuzhiyun 	struct spi_message m;
167*4882a593Smuzhiyun 	int ret;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	spi_message_init(&m);
170*4882a593Smuzhiyun 	spi_message_add_tail(&t, &m);
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	ret = spidev_mst_wait_for_slave_ready(spidev, SPI_OBJ_MAX_XFER_SIZE);
173*4882a593Smuzhiyun 	if (ret < 0)
174*4882a593Smuzhiyun 		return ret;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	spidev_mst_slave_ready_status(spidev, false);
177*4882a593Smuzhiyun 	ret = spi_sync(spi, &m);
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	return ret;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun 
spidev_rkmst_reset_slave(struct spidev_rkmst_data * spidev)182*4882a593Smuzhiyun static void spidev_rkmst_reset_slave(struct spidev_rkmst_data *spidev)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun 	struct spi_obj_ctrl *ctrl = (struct spi_obj_ctrl *)spidev->ctrlbuf;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	ctrl->cmd = SPI_OBJ_CTRL_CMD_INIT;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	spidev_mst_write_bypass(spidev, ctrl, SPI_OBJ_MAX_XFER_SIZE);
189*4882a593Smuzhiyun 	msleep(100);
190*4882a593Smuzhiyun 	spidev_mst_write_bypass(spidev, ctrl, SPI_OBJ_MAX_XFER_SIZE);
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 
spidev_rkmst_ctrl(struct spidev_rkmst_data * spidev,u32 cmd,u16 addr,u32 data)194*4882a593Smuzhiyun static int spidev_rkmst_ctrl(struct spidev_rkmst_data *spidev, u32 cmd, u16 addr, u32 data)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun 	struct spi_obj_ctrl *ctrl = (struct spi_obj_ctrl *)spidev->ctrlbuf;
197*4882a593Smuzhiyun 	struct spi_device *spi = spidev->spi;
198*4882a593Smuzhiyun 	int ret;
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	if (spidev->verbose)
201*4882a593Smuzhiyun 		dev_err(&spi->dev, "ctrl cmd=%x addr=0x%x data=0x%x\n", cmd, addr, data);
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	/* ctrl_xfer */
204*4882a593Smuzhiyun 	ctrl->cmd = cmd;
205*4882a593Smuzhiyun 	ctrl->addr = addr;
206*4882a593Smuzhiyun 	ctrl->data = data;
207*4882a593Smuzhiyun 	ret = spidev_mst_write(spidev, ctrl, SPI_OBJ_CTRL_MSG_SIZE);
208*4882a593Smuzhiyun 	if (ret) {
209*4882a593Smuzhiyun 		dev_err(&spi->dev, "ctrl cmd=%x addr=0x%x data=0x%x, ret=%d\n", cmd, addr, data, ret);
210*4882a593Smuzhiyun 		return -EIO;
211*4882a593Smuzhiyun 	}
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	return 0;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun 
spidev_rkmst_xfer(struct spidev_rkmst_data * spidev,void * tx,void * rx,u16 addr,u32 len)216*4882a593Smuzhiyun static int spidev_rkmst_xfer(struct spidev_rkmst_data *spidev, void *tx,
217*4882a593Smuzhiyun 			     void *rx, u16 addr, u32 len)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun 	struct spi_device *spi = spidev->spi;
220*4882a593Smuzhiyun 	int ret;
221*4882a593Smuzhiyun 	u32 cmd;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	if (tx && rx)
224*4882a593Smuzhiyun 		cmd = SPI_OBJ_CTRL_CMD_DUPLEX;
225*4882a593Smuzhiyun 	else if (rx)
226*4882a593Smuzhiyun 		cmd = SPI_OBJ_CTRL_CMD_READ;
227*4882a593Smuzhiyun 	else if (tx)
228*4882a593Smuzhiyun 		cmd = SPI_OBJ_CTRL_CMD_WRITE;
229*4882a593Smuzhiyun 	else
230*4882a593Smuzhiyun 		return -EINVAL;
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	/* ctrl_xfer */
233*4882a593Smuzhiyun 	ret = spidev_rkmst_ctrl(spidev, cmd, addr, len);
234*4882a593Smuzhiyun 	if (ret) {
235*4882a593Smuzhiyun 		spidev_rkmst_reset_slave(spidev);
236*4882a593Smuzhiyun 		return -EIO;
237*4882a593Smuzhiyun 	}
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	if (spidev->verbose)
240*4882a593Smuzhiyun 		dev_err(&spi->dev, "xfer len=0x%x\n", len);
241*4882a593Smuzhiyun 	/* data_xfer */
242*4882a593Smuzhiyun 	switch (cmd) {
243*4882a593Smuzhiyun 	case SPI_OBJ_CTRL_CMD_READ:
244*4882a593Smuzhiyun 		ret = spidev_mst_read(spidev, rx, len);
245*4882a593Smuzhiyun 		if (ret)
246*4882a593Smuzhiyun 			goto err_out;
247*4882a593Smuzhiyun 		break;
248*4882a593Smuzhiyun 	case SPI_OBJ_CTRL_CMD_WRITE:
249*4882a593Smuzhiyun 		ret = spidev_mst_write(spidev, tx, len);
250*4882a593Smuzhiyun 		if (ret)
251*4882a593Smuzhiyun 			goto err_out;
252*4882a593Smuzhiyun 		break;
253*4882a593Smuzhiyun 	case SPI_OBJ_CTRL_CMD_DUPLEX:
254*4882a593Smuzhiyun 		ret = spidev_slv_write_and_read(spidev, tx, rx, len);
255*4882a593Smuzhiyun 		if (ret)
256*4882a593Smuzhiyun 			goto err_out;
257*4882a593Smuzhiyun 		break;
258*4882a593Smuzhiyun 	default:
259*4882a593Smuzhiyun 		dev_err(&spi->dev, "%s unknown\n", __func__);
260*4882a593Smuzhiyun 	}
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	return 0;
263*4882a593Smuzhiyun err_out:
264*4882a593Smuzhiyun 	dev_err(&spi->dev, "xfer cmd=%x addr=0x%x len=0x%x, ret=%d\n",
265*4882a593Smuzhiyun 		cmd, addr, len, ret);
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	return ret;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun 
spidev_rkmst_misc_write(struct file * filp,const char __user * buf,size_t n,loff_t * offset)270*4882a593Smuzhiyun static ssize_t spidev_rkmst_misc_write(struct file *filp, const char __user *buf,
271*4882a593Smuzhiyun 				       size_t n, loff_t *offset)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun 	struct spidev_rkmst_data *spidev;
274*4882a593Smuzhiyun 	struct spi_device *spi;
275*4882a593Smuzhiyun 	int argc = 0, i;
276*4882a593Smuzhiyun 	char tmp[64];
277*4882a593Smuzhiyun 	char *argv[16];
278*4882a593Smuzhiyun 	char *cmd, *data;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	if (n >= 64)
281*4882a593Smuzhiyun 		return -EINVAL;
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	spidev = filp->private_data;
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	if (!spidev)
286*4882a593Smuzhiyun 		return -ESHUTDOWN;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	spi = spidev->spi;
289*4882a593Smuzhiyun 	memset(tmp, 0, sizeof(tmp));
290*4882a593Smuzhiyun 	if (copy_from_user(tmp, buf, n))
291*4882a593Smuzhiyun 		return -EFAULT;
292*4882a593Smuzhiyun 	cmd = tmp;
293*4882a593Smuzhiyun 	data = tmp;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	while (data < (tmp + n)) {
296*4882a593Smuzhiyun 		data = strstr(data, " ");
297*4882a593Smuzhiyun 		if (!data)
298*4882a593Smuzhiyun 			break;
299*4882a593Smuzhiyun 		*data = 0;
300*4882a593Smuzhiyun 		argv[argc] = ++data;
301*4882a593Smuzhiyun 		argc++;
302*4882a593Smuzhiyun 		if (argc >= 16)
303*4882a593Smuzhiyun 			break;
304*4882a593Smuzhiyun 	}
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	tmp[n - 1] = 0;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	if (!strcmp(cmd, "verbose")) {
309*4882a593Smuzhiyun 		int val;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 		if (argc < 1)
312*4882a593Smuzhiyun 			return -EINVAL;
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 		if (kstrtoint(argv[0], 0, &val))
315*4882a593Smuzhiyun 			return -EINVAL;
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 		if (val == 1)
318*4882a593Smuzhiyun 			spidev->verbose = true;
319*4882a593Smuzhiyun 		else
320*4882a593Smuzhiyun 			spidev->verbose = false;
321*4882a593Smuzhiyun 	} else if (!strcmp(cmd, "init")) {
322*4882a593Smuzhiyun 		spidev_rkmst_ctrl(spidev, SPI_OBJ_CTRL_CMD_INIT, 0x55AA, 0x1234567);
323*4882a593Smuzhiyun 	} else if (!strcmp(cmd, "read")) {
324*4882a593Smuzhiyun 		int addr, len;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 		if (argc < 2)
327*4882a593Smuzhiyun 			return -EINVAL;
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 		if (kstrtoint(argv[0], 0, &addr))
330*4882a593Smuzhiyun 			return -EINVAL;
331*4882a593Smuzhiyun 		if (kstrtoint(argv[1], 0, &len))
332*4882a593Smuzhiyun 			return -EINVAL;
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 		if (!len) {
335*4882a593Smuzhiyun 			dev_err(&spi->dev, "param invalid,%s %s\n", argv[0], argv[1]);
336*4882a593Smuzhiyun 			return -EINVAL;
337*4882a593Smuzhiyun 		}
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 		if (addr + len > SPI_OBJ_APP_RAM_SIZE) {
340*4882a593Smuzhiyun 			dev_err(&spi->dev, "rxbuf print out of size\n");
341*4882a593Smuzhiyun 			return -EINVAL;
342*4882a593Smuzhiyun 		}
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 		spidev_rkmst_xfer(spidev, NULL, spidev->rxbuf, addr, len);
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 		print_hex_dump(KERN_ERR, "m-r: ",
347*4882a593Smuzhiyun 			       DUMP_PREFIX_OFFSET,
348*4882a593Smuzhiyun 			       16,
349*4882a593Smuzhiyun 			       1,
350*4882a593Smuzhiyun 			       spidev->rxbuf,
351*4882a593Smuzhiyun 			       len,
352*4882a593Smuzhiyun 			       1);
353*4882a593Smuzhiyun 	} else if (!strcmp(cmd, "write")) {
354*4882a593Smuzhiyun 		int addr, len;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 		if (argc < 2)
357*4882a593Smuzhiyun 			return -EINVAL;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 		if (kstrtoint(argv[0], 0, &addr))
360*4882a593Smuzhiyun 			return -EINVAL;
361*4882a593Smuzhiyun 		if (kstrtoint(argv[1], 0, &len))
362*4882a593Smuzhiyun 			return -EINVAL;
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 		if (!len) {
365*4882a593Smuzhiyun 			dev_err(&spi->dev, "param invalid,%s %s\n", argv[0], argv[1]);
366*4882a593Smuzhiyun 			return -EINVAL;
367*4882a593Smuzhiyun 		}
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 		if (addr + len > SPI_OBJ_APP_RAM_SIZE) {
370*4882a593Smuzhiyun 			dev_err(&spi->dev, "rxbuf print out of size\n");
371*4882a593Smuzhiyun 			return -EINVAL;
372*4882a593Smuzhiyun 		}
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 		for (i = 0; i < len; i++)
375*4882a593Smuzhiyun 			spidev->txbuf[i] = i & 0xFF;
376*4882a593Smuzhiyun 		((u32 *)spidev->txbuf)[0] = addr;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 		spidev_rkmst_xfer(spidev, spidev->txbuf, NULL, addr, len);
379*4882a593Smuzhiyun 	} else if (!strcmp(cmd, "duplex")) {
380*4882a593Smuzhiyun 		int addr, len;
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 		if (argc < 2)
383*4882a593Smuzhiyun 			return -EINVAL;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 		if (kstrtoint(argv[0], 0, &addr))
386*4882a593Smuzhiyun 			return -EINVAL;
387*4882a593Smuzhiyun 		if (kstrtoint(argv[1], 0, &len))
388*4882a593Smuzhiyun 			return -EINVAL;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 		if (!len) {
391*4882a593Smuzhiyun 			dev_err(&spi->dev, "param invalid,%s %s\n", argv[0], argv[1]);
392*4882a593Smuzhiyun 			return -EINVAL;
393*4882a593Smuzhiyun 		}
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 		if (addr + len > SPI_OBJ_APP_RAM_SIZE) {
396*4882a593Smuzhiyun 			dev_err(&spi->dev, "rxbuf print out of size\n");
397*4882a593Smuzhiyun 			return -EINVAL;
398*4882a593Smuzhiyun 		}
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 		for (i = 0; i < len; i++)
401*4882a593Smuzhiyun 			spidev->txbuf[i] = i & 0xFF;
402*4882a593Smuzhiyun 		((u32 *)spidev->txbuf)[0] = addr;
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 		spidev_rkmst_xfer(spidev, spidev->txbuf, spidev->rxbuf, addr, len);
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 		print_hex_dump(KERN_ERR, "m-d: ",
407*4882a593Smuzhiyun 			       DUMP_PREFIX_OFFSET,
408*4882a593Smuzhiyun 			       16,
409*4882a593Smuzhiyun 			       1,
410*4882a593Smuzhiyun 			       spidev->rxbuf,
411*4882a593Smuzhiyun 			       len,
412*4882a593Smuzhiyun 			       1);
413*4882a593Smuzhiyun 	} else if (!strcmp(cmd, "autotest")) {
414*4882a593Smuzhiyun 		int addr = 0, len, loops, i;
415*4882a593Smuzhiyun 		unsigned long long bytes = 0;
416*4882a593Smuzhiyun 		unsigned long us = 0;
417*4882a593Smuzhiyun 		ktime_t start_time;
418*4882a593Smuzhiyun 		ktime_t end_time;
419*4882a593Smuzhiyun 		ktime_t cost_time;
420*4882a593Smuzhiyun 		char *tempbuf;
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 		if (argc < 2)
423*4882a593Smuzhiyun 			return -EINVAL;
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 		if (kstrtoint(argv[0], 0, &len))
426*4882a593Smuzhiyun 			return -EINVAL;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 		if (kstrtoint(argv[1], 0, &loops))
429*4882a593Smuzhiyun 			return -EINVAL;
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 		if (!len) {
432*4882a593Smuzhiyun 			dev_err(&spi->dev, "param invalid,%s %s\n", argv[0], argv[1]);
433*4882a593Smuzhiyun 			return -EINVAL;
434*4882a593Smuzhiyun 		}
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 		if (len > SPI_OBJ_APP_RAM_SIZE) {
437*4882a593Smuzhiyun 			dev_err(&spi->dev, "rxbuf print out of size\n");
438*4882a593Smuzhiyun 			return -EINVAL;
439*4882a593Smuzhiyun 		}
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 		tempbuf = kzalloc(len, GFP_KERNEL);
442*4882a593Smuzhiyun 		if (!tempbuf)
443*4882a593Smuzhiyun 			return -ENOMEM;
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 		prandom_bytes(tempbuf, len);
446*4882a593Smuzhiyun 		spidev_rkmst_xfer(spidev, tempbuf, NULL, addr, len);
447*4882a593Smuzhiyun 		start_time = ktime_get();
448*4882a593Smuzhiyun 		for (i = 0; i < loops; i++) {
449*4882a593Smuzhiyun 			prandom_bytes(spidev->txbuf, len);
450*4882a593Smuzhiyun 			spidev_rkmst_xfer(spidev, spidev->txbuf, spidev->rxbuf, addr, len);
451*4882a593Smuzhiyun 			if (memcmp(spidev->rxbuf, tempbuf, len)) {
452*4882a593Smuzhiyun 				dev_err(&spi->dev, "dulplex autotest failed, loops=%d\n", i);
453*4882a593Smuzhiyun 				print_hex_dump(KERN_ERR, "m-d-t: ",
454*4882a593Smuzhiyun 					       DUMP_PREFIX_OFFSET,
455*4882a593Smuzhiyun 					       16,
456*4882a593Smuzhiyun 					       1,
457*4882a593Smuzhiyun 					       spidev->txbuf,
458*4882a593Smuzhiyun 					       len,
459*4882a593Smuzhiyun 					       1);
460*4882a593Smuzhiyun 				print_hex_dump(KERN_ERR, "m-d-r: ",
461*4882a593Smuzhiyun 					       DUMP_PREFIX_OFFSET,
462*4882a593Smuzhiyun 					       16,
463*4882a593Smuzhiyun 					       1,
464*4882a593Smuzhiyun 					       spidev->rxbuf,
465*4882a593Smuzhiyun 					       len,
466*4882a593Smuzhiyun 					       1);
467*4882a593Smuzhiyun 				print_hex_dump(KERN_ERR, "m-d-c: ",
468*4882a593Smuzhiyun 					       DUMP_PREFIX_OFFSET,
469*4882a593Smuzhiyun 					       16,
470*4882a593Smuzhiyun 					       1,
471*4882a593Smuzhiyun 					       tempbuf,
472*4882a593Smuzhiyun 					       len,
473*4882a593Smuzhiyun 					       1);
474*4882a593Smuzhiyun 				break;
475*4882a593Smuzhiyun 			}
476*4882a593Smuzhiyun 			memcpy(tempbuf, spidev->txbuf, len);
477*4882a593Smuzhiyun 		}
478*4882a593Smuzhiyun 		end_time = ktime_get();
479*4882a593Smuzhiyun 		cost_time = ktime_sub(end_time, start_time);
480*4882a593Smuzhiyun 		us = ktime_to_us(cost_time);
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 		bytes = (u64)len * (u64)loops * 1000;
483*4882a593Smuzhiyun 		do_div(bytes, us);
484*4882a593Smuzhiyun 		if (i >= loops)
485*4882a593Smuzhiyun 			dev_err(&spi->dev, "dulplex test pass, cost=%ldus, speed=%lldKB/S, %ldus/loops\n",
486*4882a593Smuzhiyun 				us, bytes, us / loops);
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 		start_time = ktime_get();
489*4882a593Smuzhiyun 		for (i = 0; i < loops; i++) {
490*4882a593Smuzhiyun 			prandom_bytes(spidev->txbuf, len);
491*4882a593Smuzhiyun 			spidev_rkmst_xfer(spidev, spidev->txbuf, NULL, addr, len);
492*4882a593Smuzhiyun 			spidev_rkmst_xfer(spidev, NULL, spidev->rxbuf, addr, len);
493*4882a593Smuzhiyun 			if (memcmp(spidev->rxbuf, spidev->txbuf, len)) {
494*4882a593Smuzhiyun 				dev_err(&spi->dev, "read/write autotest failed, loops=%d\n", i);
495*4882a593Smuzhiyun 				print_hex_dump(KERN_ERR, "m-d-t: ",
496*4882a593Smuzhiyun 					       DUMP_PREFIX_OFFSET,
497*4882a593Smuzhiyun 					       16,
498*4882a593Smuzhiyun 					       1,
499*4882a593Smuzhiyun 					       spidev->txbuf,
500*4882a593Smuzhiyun 					       len,
501*4882a593Smuzhiyun 					       1);
502*4882a593Smuzhiyun 				print_hex_dump(KERN_ERR, "m-d-r: ",
503*4882a593Smuzhiyun 					       DUMP_PREFIX_OFFSET,
504*4882a593Smuzhiyun 					       16,
505*4882a593Smuzhiyun 					       1,
506*4882a593Smuzhiyun 					       spidev->rxbuf,
507*4882a593Smuzhiyun 					       len,
508*4882a593Smuzhiyun 					       1);
509*4882a593Smuzhiyun 				break;
510*4882a593Smuzhiyun 			}
511*4882a593Smuzhiyun 		}
512*4882a593Smuzhiyun 		end_time = ktime_get();
513*4882a593Smuzhiyun 		cost_time = ktime_sub(end_time, start_time);
514*4882a593Smuzhiyun 		us = ktime_to_us(cost_time);
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 		bytes = (u64)len * (u64)loops * 2 * 1000; /* multi 2 for both write and read */
517*4882a593Smuzhiyun 		do_div(bytes, us);
518*4882a593Smuzhiyun 		if (i >= loops)
519*4882a593Smuzhiyun 			dev_err(&spi->dev, "read/write test pass, cost=%ldus, speed=%lldKB/S, %ldus/loops\n",
520*4882a593Smuzhiyun 				us, bytes, us / loops);
521*4882a593Smuzhiyun 		kfree(tempbuf);
522*4882a593Smuzhiyun 	} else {
523*4882a593Smuzhiyun 		dev_err(&spi->dev, "unknown command\n");
524*4882a593Smuzhiyun 	}
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	return n;
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun 
spidev_rkmst_misc_open(struct inode * inode,struct file * filp)529*4882a593Smuzhiyun static int spidev_rkmst_misc_open(struct inode *inode, struct file *filp)
530*4882a593Smuzhiyun {
531*4882a593Smuzhiyun 	struct miscdevice *miscdev = filp->private_data;
532*4882a593Smuzhiyun 	struct spidev_rkmst_data *spidev;
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 	spidev = container_of(miscdev, struct spidev_rkmst_data, misc_dev);
535*4882a593Smuzhiyun 	filp->private_data = spidev;
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	return 0;
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun static const struct file_operations spidev_rkmst_misc_fops = {
541*4882a593Smuzhiyun 	.write = spidev_rkmst_misc_write,
542*4882a593Smuzhiyun 	.open = spidev_rkmst_misc_open,
543*4882a593Smuzhiyun };
544*4882a593Smuzhiyun 
spidev_rkmst_probe(struct spi_device * spi)545*4882a593Smuzhiyun static int spidev_rkmst_probe(struct spi_device *spi)
546*4882a593Smuzhiyun {
547*4882a593Smuzhiyun 	struct spidev_rkmst_data *spidev = NULL;
548*4882a593Smuzhiyun 	int ret;
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	if (!spi)
551*4882a593Smuzhiyun 		return -ENOMEM;
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	spidev = devm_kzalloc(&spi->dev, sizeof(struct spidev_rkmst_data), GFP_KERNEL);
554*4882a593Smuzhiyun 	if (!spidev)
555*4882a593Smuzhiyun 		return -ENOMEM;
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 	spidev->ctrlbuf = devm_kzalloc(&spi->dev, SPI_OBJ_MAX_XFER_SIZE, GFP_KERNEL);
558*4882a593Smuzhiyun 	if (!spidev->ctrlbuf)
559*4882a593Smuzhiyun 		return -ENOMEM;
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun 	spidev->rxbuf = devm_kzalloc(&spi->dev, SPI_OBJ_APP_RAM_SIZE, GFP_KERNEL | GFP_DMA);
562*4882a593Smuzhiyun 	if (!spidev->rxbuf)
563*4882a593Smuzhiyun 		return -ENOMEM;
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 	spidev->txbuf = devm_kzalloc(&spi->dev, SPI_OBJ_MAX_XFER_SIZE, GFP_KERNEL);
566*4882a593Smuzhiyun 	if (!spidev->txbuf)
567*4882a593Smuzhiyun 		return -ENOMEM;
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	spidev->spi = spi;
570*4882a593Smuzhiyun 	spidev->dev = &spi->dev;
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	spidev_mst_slave_ready_status(spidev, false);
573*4882a593Smuzhiyun 	spidev->ready = devm_gpiod_get_optional(&spi->dev, "ready", GPIOD_IN);
574*4882a593Smuzhiyun 	if (IS_ERR(spidev->ready))
575*4882a593Smuzhiyun 		return dev_err_probe(&spi->dev, PTR_ERR(spidev->ready),
576*4882a593Smuzhiyun 				     "invalid ready-gpios property in node\n");
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun 	spidev->ready_irqnum = gpiod_to_irq(spidev->ready);
579*4882a593Smuzhiyun 	ret = devm_request_irq(&spi->dev, spidev->ready_irqnum, spidev_mst_slave_ready_interrupt,
580*4882a593Smuzhiyun 		IRQF_TRIGGER_FALLING, "spidev-mst-ready-in", spidev);
581*4882a593Smuzhiyun 	if (ret < 0) {
582*4882a593Smuzhiyun 		dev_err(&spi->dev, "request ready irq failed\n");
583*4882a593Smuzhiyun 		return ret;
584*4882a593Smuzhiyun 	}
585*4882a593Smuzhiyun 	dev_set_drvdata(&spi->dev, spidev);
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 	dev_err(&spi->dev, "mode=%d, max_speed_hz=%d\n", spi->mode, spi->max_speed_hz);
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	spidev->misc_dev.minor = MISC_DYNAMIC_MINOR;
590*4882a593Smuzhiyun 	spidev->misc_dev.name = "spidev_rkmst_misc";
591*4882a593Smuzhiyun 	spidev->misc_dev.fops = &spidev_rkmst_misc_fops;
592*4882a593Smuzhiyun 	spidev->misc_dev.parent = &spi->dev;
593*4882a593Smuzhiyun 	ret = misc_register(&spidev->misc_dev);
594*4882a593Smuzhiyun 	if (ret) {
595*4882a593Smuzhiyun 		dev_err(&spi->dev, "fail to register misc device\n");
596*4882a593Smuzhiyun 		return ret;
597*4882a593Smuzhiyun 	}
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 	spidev_rkmst_reset_slave(spidev);
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	return 0;
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun 
spidev_rkmst_remove(struct spi_device * spi)604*4882a593Smuzhiyun static int spidev_rkmst_remove(struct spi_device *spi)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun 	struct spidev_rkmst_data *spidev = dev_get_drvdata(&spi->dev);
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	misc_deregister(&spidev->misc_dev);
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	return 0;
611*4882a593Smuzhiyun }
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun #ifdef CONFIG_OF
614*4882a593Smuzhiyun static const struct of_device_id spidev_rkmst_dt_match[] = {
615*4882a593Smuzhiyun 	{ .compatible = "rockchip,spi-obj-master", },
616*4882a593Smuzhiyun 	{},
617*4882a593Smuzhiyun };
618*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, spidev_rkmst_dt_match);
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun #endif /* CONFIG_OF */
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun static struct spi_driver spidev_rkmst_driver = {
623*4882a593Smuzhiyun 	.driver = {
624*4882a593Smuzhiyun 		.name	= "spidev_rkmst",
625*4882a593Smuzhiyun 		.owner = THIS_MODULE,
626*4882a593Smuzhiyun 		.of_match_table = of_match_ptr(spidev_rkmst_dt_match),
627*4882a593Smuzhiyun 	},
628*4882a593Smuzhiyun 	.probe		= spidev_rkmst_probe,
629*4882a593Smuzhiyun 	.remove		= spidev_rkmst_remove,
630*4882a593Smuzhiyun };
631*4882a593Smuzhiyun module_spi_driver(spidev_rkmst_driver);
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun MODULE_AUTHOR("Jon Lin <jon.lin@rock-chips.com>");
634*4882a593Smuzhiyun MODULE_DESCRIPTION("ROCKCHIP SPI Object Master Driver");
635*4882a593Smuzhiyun MODULE_LICENSE("GPL");
636*4882a593Smuzhiyun MODULE_ALIAS("spi:spidev_rkmst");
637