xref: /OK3568_Linux_fs/kernel/drivers/spi/spi-rockchip-test.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*drivers/spi/spi-rockchip-test.c -spi test driver
2  *
3  *
4  * This program is distributed in the hope that it will be useful,
5  * but WITHOUT ANY WARRANTY; without even the implied warranty of
6  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
7  * GNU General Public License for more details.
8  */
9 
10 /* how to test spi
11 * echo write 0 10 255 > /dev/spi_misc_test
12 * echo write 0 10 255 init.rc > /dev/spi_misc_test
13 * echo read 0 10 255 > /dev/spi_misc_test
14 * echo loop 0 10 255 > /dev/spi_misc_test
15 * echo setspeed 0 1000000 > /dev/spi_misc_test
16 */
17 
18 #include <linux/interrupt.h>
19 #include <linux/slab.h>
20 #include <linux/init.h>
21 #include <linux/module.h>
22 #include <linux/workqueue.h>
23 #include <linux/interrupt.h>
24 #include <linux/delay.h>
25 #include <linux/clk.h>
26 #include <linux/dma-mapping.h>
27 #include <linux/dmaengine.h>
28 #include <linux/platform_device.h>
29 #include <linux/pm_runtime.h>
30 #include <linux/spi/spi.h>
31 #include <linux/gpio.h>
32 #include <linux/of.h>
33 #include <linux/of_gpio.h>
34 #include <linux/miscdevice.h>
35 #include <linux/hrtimer.h>
36 #include <linux/platform_data/spi-rockchip.h>
37 #include <linux/uaccess.h>
38 #include <linux/syscalls.h>
39 
40 #define MAX_SPI_DEV_NUM 10
41 #define SPI_MAX_SPEED_HZ	12000000
42 
43 struct spi_test_data {
44 	struct device	*dev;
45 	struct spi_device *spi;
46 	char *rx_buf;
47 	int rx_len;
48 	char *tx_buf;
49 	int tx_len;
50 };
51 
52 static struct spi_test_data *g_spi_test_data[MAX_SPI_DEV_NUM];
53 static u32 bit_per_word = 8;
54 
spi_write_slt(int id,const void * txbuf,size_t n)55 int spi_write_slt(int id, const void *txbuf, size_t n)
56 {
57 	int ret = -1;
58 	struct spi_device *spi = NULL;
59 	struct spi_transfer     t = {
60 			.tx_buf         = txbuf,
61 			.len            = n,
62 			.bits_per_word = bit_per_word,
63 		};
64 	struct spi_message      m;
65 
66 	if (id >= MAX_SPI_DEV_NUM)
67 		return ret;
68 	if (!g_spi_test_data[id]) {
69 		pr_err("g_spi.%d is NULL\n", id);
70 		return ret;
71 	} else {
72 		spi = g_spi_test_data[id]->spi;
73 	}
74 
75 	spi_message_init(&m);
76 	spi_message_add_tail(&t, &m);
77 	ret = spi_sync(spi, &m);
78 	if (m.actual_length && m.actual_length != n)
79 		pr_err("%s len=%d actual_length=%d\n", __func__, n, m.actual_length);
80 
81 	return ret;
82 }
83 
spi_read_slt(int id,void * rxbuf,size_t n)84 int spi_read_slt(int id, void *rxbuf, size_t n)
85 {
86 	int ret = -1;
87 	struct spi_device *spi = NULL;
88 	struct spi_transfer     t = {
89 			.rx_buf         = rxbuf,
90 			.len            = n,
91 			.bits_per_word = bit_per_word,
92 		};
93 	struct spi_message      m;
94 
95 	if (id >= MAX_SPI_DEV_NUM)
96 		return ret;
97 	if (!g_spi_test_data[id]) {
98 		pr_err("g_spi.%d is NULL\n", id);
99 		return ret;
100 	} else {
101 		spi = g_spi_test_data[id]->spi;
102 	}
103 
104 	spi_message_init(&m);
105 	spi_message_add_tail(&t, &m);
106 	ret = spi_sync(spi, &m);
107 	if (m.actual_length && m.actual_length != n)
108 		pr_err("%s len=%d actual_length=%d\n", __func__, n, m.actual_length);
109 
110 	return ret;
111 }
112 
spi_write_then_read_slt(int id,const void * txbuf,unsigned n_tx,void * rxbuf,unsigned n_rx)113 int spi_write_then_read_slt(int id, const void *txbuf, unsigned n_tx,
114 		void *rxbuf, unsigned n_rx)
115 {
116 	int ret = -1;
117 	struct spi_device *spi = NULL;
118 
119 	if (id >= MAX_SPI_DEV_NUM)
120 		return ret;
121 	if (!g_spi_test_data[id]) {
122 		pr_err("g_spi.%d is NULL\n", id);
123 		return ret;
124 	} else {
125 		spi = g_spi_test_data[id]->spi;
126 	}
127 
128 	ret = spi_write_then_read(spi, txbuf, n_tx, rxbuf, n_rx);
129 	return ret;
130 }
131 
spi_write_and_read_slt(int id,const void * tx_buf,void * rx_buf,size_t len)132 int spi_write_and_read_slt(int id, const void *tx_buf,
133 			void *rx_buf, size_t len)
134 {
135 	int ret = -1;
136 	struct spi_device *spi = NULL;
137 	struct spi_transfer     t = {
138 			.tx_buf         = tx_buf,
139 			.rx_buf         = rx_buf,
140 			.len            = len,
141 		};
142 	struct spi_message      m;
143 
144 	if (id >= MAX_SPI_DEV_NUM)
145 		return ret;
146 	if (!g_spi_test_data[id]) {
147 		pr_err("g_spi.%d is NULL\n", id);
148 		return ret;
149 	} else {
150 		spi = g_spi_test_data[id]->spi;
151 	}
152 
153 	spi_message_init(&m);
154 	spi_message_add_tail(&t, &m);
155 	return spi_sync(spi, &m);
156 }
157 
spi_test_write(struct file * file,const char __user * buf,size_t n,loff_t * offset)158 static ssize_t spi_test_write(struct file *file,
159 			const char __user *buf, size_t n, loff_t *offset)
160 {
161 	int argc = 0, i;
162 	char tmp[64];
163 	char *argv[16];
164 	char *cmd, *data;
165 	unsigned int id = 0, times = 0, size = 0;
166 	unsigned long us = 0, bytes = 0;
167 	char *txbuf = NULL, *rxbuf = NULL;
168 	ktime_t start_time;
169 	ktime_t end_time;
170 	ktime_t cost_time;
171 
172 	memset(tmp, 0, sizeof(tmp));
173 	if (copy_from_user(tmp, buf, n))
174 		return -EFAULT;
175 	cmd = tmp;
176 	data = tmp;
177 
178 	while (data < (tmp + n)) {
179 		data = strstr(data, " ");
180 		if (!data)
181 			break;
182 		*data = 0;
183 		argv[argc] = ++data;
184 		argc++;
185 		if (argc >= 16)
186 			break;
187 	}
188 
189 	tmp[n - 1] = 0;
190 
191 	if (!strcmp(cmd, "setspeed")) {
192 		int id = 0, val;
193 		struct spi_device *spi = NULL;
194 
195 		sscanf(argv[0], "%d", &id);
196 		sscanf(argv[1], "%d", &val);
197 
198 		if (id >= MAX_SPI_DEV_NUM)
199 			return n;
200 		if (!g_spi_test_data[id]) {
201 			pr_err("g_spi.%d is NULL\n", id);
202 			return n;
203 		} else {
204 			spi = g_spi_test_data[id]->spi;
205 		}
206 		spi->max_speed_hz = val;
207 	} else if (!strcmp(cmd, "write")) {
208 		sscanf(argv[0], "%d", &id);
209 		sscanf(argv[1], "%d", &times);
210 		sscanf(argv[2], "%d", &size);
211 
212 		txbuf = kzalloc(size, GFP_KERNEL);
213 		if (!txbuf) {
214 			printk("spi write alloc buf size %d fail\n", size);
215 			return n;
216 		}
217 
218 		for (i = 0; i < size; i++)
219 			txbuf[i] = i % 256;
220 
221 		start_time = ktime_get();
222 		for (i = 0; i < times; i++)
223 			spi_write_slt(id, txbuf, size);
224 		end_time = ktime_get();
225 		cost_time = ktime_sub(end_time, start_time);
226 		us = ktime_to_us(cost_time);
227 
228 		bytes = size * times * 1;
229 		bytes = bytes * 1000 / us;
230 		printk("spi write %d*%d cost %ldus speed:%ldKB/S\n", size, times, us, bytes);
231 
232 		kfree(txbuf);
233 	} else if (!strcmp(cmd, "read")) {
234 		sscanf(argv[0], "%d", &id);
235 		sscanf(argv[1], "%d", &times);
236 		sscanf(argv[2], "%d", &size);
237 
238 		rxbuf = kzalloc(size, GFP_KERNEL);
239 		if (!rxbuf) {
240 			printk("spi read alloc buf size %d fail\n", size);
241 			return n;
242 		}
243 
244 		start_time = ktime_get();
245 		for (i = 0; i < times; i++)
246 			spi_read_slt(id, rxbuf, size);
247 		end_time = ktime_get();
248 		cost_time = ktime_sub(end_time, start_time);
249 		us = ktime_to_us(cost_time);
250 
251 		bytes = size * times * 1;
252 		bytes = bytes * 1000 / us;
253 		printk("spi read %d*%d cost %ldus speed:%ldKB/S\n", size, times, us, bytes);
254 		print_hex_dump(KERN_ERR, "SPI RX: ",
255 			       DUMP_PREFIX_OFFSET,
256 			       16,
257 			       1,
258 			       rxbuf,
259 			       size,
260 			       1);
261 
262 		kfree(rxbuf);
263 	} else if (!strcmp(cmd, "loop")) {
264 		sscanf(argv[0], "%d", &id);
265 		sscanf(argv[1], "%d", &times);
266 		sscanf(argv[2], "%d", &size);
267 
268 		txbuf = kzalloc(size, GFP_KERNEL);
269 		if (!txbuf) {
270 			printk("spi tx alloc buf size %d fail\n", size);
271 			return n;
272 		}
273 
274 		rxbuf = kzalloc(size, GFP_KERNEL);
275 		if (!rxbuf) {
276 			kfree(txbuf);
277 			printk("spi rx alloc buf size %d fail\n", size);
278 			return n;
279 		}
280 
281 		for (i = 0; i < size; i++)
282 			txbuf[i] = i % 256;
283 
284 		start_time = ktime_get();
285 		for (i = 0; i < times; i++) {
286 			spi_write_and_read_slt(id, txbuf, rxbuf, size);
287 			if (memcmp(txbuf, rxbuf, size)) {
288 				printk("spi loop test fail\n");
289 				break;
290 			}
291 		}
292 
293 		end_time = ktime_get();
294 		cost_time = ktime_sub(end_time, start_time);
295 		us = ktime_to_us(cost_time);
296 
297 		bytes = size * times;
298 		bytes = bytes * 1000 / us;
299 		printk("spi loop %d*%d cost %ldus speed:%ldKB/S\n", size, times, us, bytes);
300 
301 		kfree(txbuf);
302 		kfree(rxbuf);
303 	} else if (!strcmp(cmd, "config")) {
304 		int width;
305 
306 		sscanf(argv[0], "%d", &width);
307 
308 		if (width == 16)
309 			bit_per_word = 16;
310 		else
311 			bit_per_word = 8;
312 	} else {
313 		printk("echo id number size > /dev/spi_misc_test\n");
314 		printk("echo write 0 10 255 > /dev/spi_misc_test\n");
315 		printk("echo write 0 10 255 init.rc > /dev/spi_misc_test\n");
316 		printk("echo read 0 10 255 > /dev/spi_misc_test\n");
317 		printk("echo loop 0 10 255 > /dev/spi_misc_test\n");
318 		printk("echo setspeed 0 1000000 > /dev/spi_misc_test\n");
319 		printk("echo config 8 > /dev/spi_misc_test\n");
320 	}
321 
322 	return n;
323 }
324 
325 static const struct file_operations spi_test_fops = {
326 	.write = spi_test_write,
327 };
328 
329 static struct miscdevice spi_test_misc = {
330 	.minor = MISC_DYNAMIC_MINOR,
331 	.name = "spi_misc_test",
332 	.fops = &spi_test_fops,
333 };
334 
rockchip_spi_test_probe(struct spi_device * spi)335 static int rockchip_spi_test_probe(struct spi_device *spi)
336 {
337 	int ret;
338 	int id = 0;
339 	struct spi_test_data *spi_test_data = NULL;
340 
341 	if (!spi)
342 		return -ENOMEM;
343 
344 	spi_test_data = (struct spi_test_data *)kzalloc(sizeof(struct spi_test_data), GFP_KERNEL);
345 	if (!spi_test_data) {
346 		dev_err(&spi->dev, "ERR: no memory for spi_test_data\n");
347 		return -ENOMEM;
348 	}
349 	spi->bits_per_word = 8;
350 
351 	spi_test_data->spi = spi;
352 	spi_test_data->dev = &spi->dev;
353 
354 	ret = spi_setup(spi);
355 	if (ret < 0) {
356 		dev_err(spi_test_data->dev, "ERR: fail to setup spi\n");
357 		return -1;
358 	}
359 
360 	if (device_property_read_u32(&spi->dev, "id", &id)) {
361 		dev_warn(&spi->dev, "fail to get id, default set 0\n");
362 		id = 0;
363 	}
364 
365 	g_spi_test_data[id] = spi_test_data;
366 
367 	printk("%s:name=%s,bus_num=%d,cs=%d,mode=%d,speed=%d\n", __func__, spi->modalias, spi->master->bus_num, spi->chip_select, spi->mode, spi->max_speed_hz);
368 
369 	return ret;
370 }
371 
rockchip_spi_test_remove(struct spi_device * spi)372 static int rockchip_spi_test_remove(struct spi_device *spi)
373 {
374 	printk("%s\n", __func__);
375 	return 0;
376 }
377 
378 #ifdef CONFIG_OF
379 static const struct of_device_id rockchip_spi_test_dt_match[] = {
380 	{ .compatible = "rockchip,spi_test_bus0_cs0", },
381 	{ .compatible = "rockchip,spi_test_bus0_cs1", },
382 	{ .compatible = "rockchip,spi_test_bus1_cs0", },
383 	{ .compatible = "rockchip,spi_test_bus1_cs1", },
384 	{ .compatible = "rockchip,spi_test_bus2_cs0", },
385 	{ .compatible = "rockchip,spi_test_bus2_cs1", },
386 	{ .compatible = "rockchip,spi_test_bus3_cs0", },
387 	{ .compatible = "rockchip,spi_test_bus3_cs1", },
388 	{ .compatible = "rockchip,spi_test_bus4_cs0", },
389 	{ .compatible = "rockchip,spi_test_bus4_cs1", },
390 	{},
391 };
392 MODULE_DEVICE_TABLE(of, rockchip_spi_test_dt_match);
393 
394 #endif /* CONFIG_OF */
395 
396 static struct spi_driver spi_rockchip_test_driver = {
397 	.driver = {
398 		.name	= "spi_test",
399 		.owner = THIS_MODULE,
400 		.of_match_table = of_match_ptr(rockchip_spi_test_dt_match),
401 	},
402 	.probe = rockchip_spi_test_probe,
403 	.remove = rockchip_spi_test_remove,
404 };
405 
spi_rockchip_test_init(void)406 static int __init spi_rockchip_test_init(void)
407 {
408 	int ret = 0;
409 
410 	misc_register(&spi_test_misc);
411 	ret = spi_register_driver(&spi_rockchip_test_driver);
412 	return ret;
413 }
414 module_init(spi_rockchip_test_init);
415 
spi_rockchip_test_exit(void)416 static void __exit spi_rockchip_test_exit(void)
417 {
418 	misc_deregister(&spi_test_misc);
419 	return spi_unregister_driver(&spi_rockchip_test_driver);
420 }
421 module_exit(spi_rockchip_test_exit);
422 
423 MODULE_AUTHOR("Luo Wei <lw@rock-chips.com>");
424 MODULE_AUTHOR("Huibin Hong <hhb@rock-chips.com>");
425 MODULE_DESCRIPTION("ROCKCHIP SPI TEST Driver");
426 MODULE_LICENSE("GPL");
427 MODULE_ALIAS("spi:spi_test");
428