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", ×);
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", ×);
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", ×);
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