blob: 55c39f634a170c5dae1cc9e6a7ed4bfced9bbcdf [file] [log] [blame]
xjb04a4022021-11-25 15:01:52 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2019 MediaTek Inc.
4 */
5
6#include <linux/completion.h>
7#include <linux/module.h>
8#include <linux/spi/spi.h>
9#include <linux/random.h>
10#include <linux/clk.h>
11#include <linux/gpio/consumer.h>
12#include <linux/kernel.h> /* printk */
13#include <linux/pinctrl/consumer.h>
14static bool spis_auto_test_flag;
15
16static void spi_slave_txbuf_malloc(struct spi_transfer *trans)
17{
18 int i;
19
20 trans->tx_buf = kzalloc(trans->len, GFP_KERNEL);
21 for (i = 0; i < trans->len; i++)
22 *((char *)trans->tx_buf + i) = i;//zhengzhou 2021.03.03 modify +++++
23}
24
25static void spi_slave_rxbuf_malloc(struct spi_transfer *trans)
26{
27 trans->rx_buf = kzalloc(trans->len, GFP_KERNEL);
28 memset(trans->rx_buf, 0, trans->len);
29}
30
31static void spi_slave_txbuf_free(struct spi_transfer *trans)
32{
33 kfree(trans->tx_buf);
34}
35
36static void spi_slave_rxbuf_free(struct spi_transfer *trans)
37{
38 kfree(trans->rx_buf);
39}
40
41static void spi_slave_dump_packet(char *name, u8 *ptr, int len)
42{
43 int i;
44
45 pr_info("%s: ", name);
46 for (i = 0; i < len; i++)
47 pr_info(" %02x", ptr[i]);
48
49 pr_info("\n");
50}
51
52int spis_loopback_check(struct spi_transfer *trans)
53{
54 int i, err = 0;
55
56 for (i = 0; i < trans->len; i++) {
57 if (*((u8 *) trans->tx_buf + i) != *((u8 *) trans->rx_buf + i))
58 err++;
59 }
60
61 if (err) {
62 pr_info("spis_len:%d, err %d\n", trans->len, err);
63 spi_slave_dump_packet("spis tx",
64 (char *)trans->tx_buf, trans->len);
65 spi_slave_dump_packet("spis rx", trans->rx_buf, trans->len);
66 pr_info("spis test fail.\n");
67 spis_auto_test_flag = false;
68 return -1;
69 }
70
71 pr_info("spis_len:%d, err %d\n", trans->len, err);
72 pr_info("spis test pass.\n");
73 spis_auto_test_flag = true;
74
75 return 0;
76}
77
78static int spi_slave_txrx_transfer(struct spi_device *spi, int len)
79{
80 int ret;
81 struct spi_transfer trans;
82 struct spi_message msg;
83
84 memset(&trans, 0, sizeof(trans));
85 trans.len = len;
86
87 spi_slave_txbuf_malloc(&trans);
88 spi_slave_rxbuf_malloc(&trans);
89
90 spi_message_init(&msg);
91 spi_message_add_tail(&trans, &msg);
92
93 ret = spi_sync(spi, &msg);
94 if (ret < 0)
95 pr_info("Message transfer err,line(%d):%d\n", __LINE__, ret);
96
97 spis_loopback_check(&trans);
98
99 spi_slave_txbuf_free(&trans);
100 spi_slave_rxbuf_free(&trans);
101
102 return ret;
103}
104
105static int spi_slave_tx_transfer(struct spi_device *spi, int len)
106{
107 int ret;
108 struct spi_transfer trans;
109 struct spi_message msg;
110
111 memset(&trans, 0, sizeof(trans));
112 trans.len = len;
113
114 spi_slave_txbuf_malloc(&trans);
115
116 spi_message_init(&msg);
117 spi_message_add_tail(&trans, &msg);
118
119 ret = spi_sync(spi, &msg);
120 if (ret < 0)
121 pr_info("Message transfer err,line(%d):%d\n", __LINE__, ret);
122
123 spi_slave_dump_packet("spis tx", (char *)trans.tx_buf, len);
124
125 spi_slave_txbuf_free(&trans);
126
127 return ret;
128}
129
130static int spi_slave_rx_transfer(struct spi_device *spi, int len)
131{
132 int ret;
133 struct spi_transfer trans;
134 struct spi_message msg;
135
136 memset(&trans, 0, sizeof(trans));
137 trans.len = len;
138
139 spi_slave_rxbuf_malloc(&trans);
140
141 spi_message_init(&msg);
142 spi_message_add_tail(&trans, &msg);
143
144 ret = spi_sync(spi, &msg);
145 if (ret < 0)
146 pr_info("Message transfer err,line(%d):%d\n", __LINE__, ret);
147
148 spi_slave_dump_packet("spis rx", trans.rx_buf, len);
149
150 spi_slave_rxbuf_free(&trans);
151
152 return ret;
153}
154
155static ssize_t spi_show(struct device *dev,
156 struct device_attribute *attr, char *buf)
157{
158 char *bp = buf;
159
160 if (spis_auto_test_flag)
161 bp += sprintf(bp, "spis talk with spim pass\n");
162 else
163 bp += sprintf(bp, "spis talk with spim fail\n");
164
165 *bp++ = '\n';
166
167 return bp - buf;
168}
169
170static ssize_t spi_store(struct device *dev,
171 struct device_attribute *attr,
172 const char *buf, size_t count)
173{
174 int len;
175 struct spi_device *spi = container_of(dev, struct spi_device, dev);
176
177 if (!strncmp(buf, "txrx", 4)) {
178 buf += 5;
179 if (!strncmp(buf, "len=", 4))
180 if (sscanf(buf+4, "%d", &len) > 0)
181 spi_slave_txrx_transfer(spi, len);
182 } else if (!strncmp(buf, "onlytx", 6)) {
183 buf += 7;
184 if (!strncmp(buf, "len=", 4))
185 if (sscanf(buf+4, "%d", &len) > 0)
186 spi_slave_tx_transfer(spi, len);
187 } else if (!strncmp(buf, "onlyrx", 6)) {
188 buf += 7;
189 if (!strncmp(buf, "len=", 4))
190 if (sscanf(buf+4, "%d", &len) > 0)
191 spi_slave_rx_transfer(spi, len);
192 }
193
194 return count;
195}
196
197static DEVICE_ATTR_RW(spi);
198
199static struct device_attribute *spis_attribute[] = {
200 &dev_attr_spi,
201};
202static void spis_create_attribute(struct device *dev)
203{
204 int size, idx;
205
206 size = ARRAY_SIZE(spis_attribute);
207 for (idx = 0; idx < size; idx++)
208 device_create_file(dev, spis_attribute[idx]);
209}
210
211static int spi_slave_mt27xx_test_probe(struct spi_device *spi)
212{
213 spis_create_attribute(&spi->dev);
214 return 0;
215}
216
217static int spi_slave_mt27xx_test_remove(struct spi_device *spi)
218{
219 return 0;
220}
221
222static struct spi_driver spi_slave_mt27xx_test_driver = {
223 .driver = {
224 .name = "spi-slave-mt27xx-test",
225 },
226 .probe = spi_slave_mt27xx_test_probe,
227 .remove = spi_slave_mt27xx_test_remove,
228};
229module_spi_driver(spi_slave_mt27xx_test_driver);
230
231MODULE_AUTHOR("Mediatek");
232MODULE_LICENSE("GPL v2");