blob: c1c37ad95f12320b1bc61fe2a38b457a7eccfce7 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (C) 2018 MediaTek Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
12 */
13
14#include <linux/completion.h>
15#include <linux/module.h>
16//nclude <linux/sched/clock.h>
17#include <linux/spi/spi.h>
18
19#include <linux/random.h>
20
21#include <linux/clk.h>
22
23static bool spis_auto_test_flag;
24static struct pinctrl *pinctrl_spi;//zhengzhou modify 20201110 start
25static struct pinctrl_state *default_spi, *spi_gpio;//zhengzhou modify 20201110 start
26static void spi_slave_txbuf_malloc(struct spi_transfer *trans)
27{
28 int i; //random;
29
30 trans->tx_buf = kzalloc(trans->len, GFP_KERNEL);
31
32 //random = get_random_int() && 0xff;
33 for (i = 0; i < trans->len; i++)
34 *((char *)trans->tx_buf + i) = i + 1;//random + i;
35}
36
37static void spi_slave_rxbuf_malloc(struct spi_transfer *trans)
38{
39 trans->rx_buf = kzalloc(trans->len, GFP_KERNEL);
40 memset(trans->rx_buf, 0, trans->len);
41}
42
43static void spi_slave_txbuf_free(struct spi_transfer *trans)
44{
45 kfree(trans->tx_buf);
46}
47
48static void spi_slave_rxbuf_free(struct spi_transfer *trans)
49{
50 kfree(trans->rx_buf);
51}
52
53static void spi_slave_dump_packet(char *name, u8 *ptr, int len)
54{
55 int i;
56
57 pr_info("%s: ", name);
58 for (i = 0; i < len; i++)
59 pr_info(" %02x", ptr[i]);
60
61 pr_info("\n");
62}
63
64int spis_loopback_check(struct spi_transfer *trans)
65{
66 int i, err = 0;
67 pr_info("spis_loopback_check\n");
68
69 for (i = 0; i < trans->len; i++) {
70 if (*((u8 *) trans->tx_buf + i) != *((u8 *) trans->rx_buf + i))
71 err++;
72 }
73
74 if (err) {
75 pr_info("spis_len:%d, err %d\n", trans->len, err);
76 spi_slave_dump_packet("spis tx",
77 (char *)trans->tx_buf, trans->len);
78 spi_slave_dump_packet("spis rx", trans->rx_buf, trans->len);
79 pr_info("spis test fail.");
80 spis_auto_test_flag = false;
81 return -1;
82 }
83
84 pr_info("spis_len:%d, err %d\n", trans->len, err);
85 pr_info("spis test pass.");
86 spis_auto_test_flag = true;
87
88 return 0;
89}
90
91static int spi_slave_txrx_transfer(struct spi_device *spi, int len)
92{
93 int ret;
94 struct spi_transfer trans;
95 struct spi_message msg;
96
97 memset(&trans, 0, sizeof(trans));
98 trans.len = len;
99
100 spi_slave_txbuf_malloc(&trans);
101 spi_slave_rxbuf_malloc(&trans);
102
103 spi_message_init(&msg);
104 spi_message_add_tail(&trans, &msg);
105
106 ret = spi_sync(spi, &msg);
107 if (ret < 0)
108 pr_info("Message transfer err,line(%d):%d\n", __LINE__, ret);
109
110 spis_loopback_check(&trans);
111
112 spi_slave_txbuf_free(&trans);
113 spi_slave_rxbuf_free(&trans);
114
115 return ret;
116}
117
118static int spi_slave_tx_transfer(struct spi_device *spi, int len)
119{
120 int ret;
121 struct spi_transfer trans;
122 struct spi_message msg;
123
124 memset(&trans, 0, sizeof(trans));
125 trans.len = len;
126
127 spi_slave_txbuf_malloc(&trans);
128
129 spi_message_init(&msg);
130 spi_message_add_tail(&trans, &msg);
131
132 ret = spi_sync(spi, &msg);
133 if (ret < 0)
134 pr_info("Message transfer err,line(%d):%d\n", __LINE__, ret);
135
136 spi_slave_dump_packet("spis tx", (char *)trans.tx_buf, len);
137
138 spi_slave_txbuf_free(&trans);
139
140 return ret;
141}
142
143static int spi_slave_rx_transfer(struct spi_device *spi, int len)
144{
145 int ret;
146 struct spi_transfer trans;
147 struct spi_message msg;
148
149 memset(&trans, 0, sizeof(trans));
150 trans.len = len;
151
152 spi_slave_rxbuf_malloc(&trans);
153
154 spi_message_init(&msg);
155 spi_message_add_tail(&trans, &msg);
156
157 ret = spi_sync(spi, &msg);
158 if (ret < 0)
159 pr_info("Message transfer err,line(%d):%d\n", __LINE__, ret);
160
161 spi_slave_dump_packet("spis rx", trans.rx_buf, len);
162
163 spi_slave_rxbuf_free(&trans);
164
165 return ret;
166}
167
168static ssize_t spis_show(struct device *dev,
169 struct device_attribute *attr, char *buf)
170{
171 char *bp = buf;
172
173 if (spis_auto_test_flag)
174 bp += sprintf(bp, "spis talk with spim pass\n");
175 else
176 bp += sprintf(bp, "spis talk with spim fail\n");
177
178 *bp++ = '\n';
179
180 return bp - buf;
181}
182
183static ssize_t spis_store(struct device *dev,
184 struct device_attribute *attr,
185 const char *buf, size_t count)
186{
187 int len;//ret = 0;
188// int addr, old, new, reg_val;
189 struct spi_device *spi = container_of(dev, struct spi_device, dev);
190// struct mtk_spi_slave *mdata = spi_get_drvdata(spi);
191
192 if (!strncmp(buf, "txrx", 4)) {
193 buf += 5;
194 if (!strncmp(buf, "len=", 4))
195 if (sscanf(buf+4, "%d", &len) > 0)
196 spi_slave_txrx_transfer(spi, len);
197 } else if (!strncmp(buf, "onlytx", 6)) {
198 buf += 7;
199 if (!strncmp(buf, "len=", 4))
200 if (sscanf(buf+4, "%d", &len) > 0)
201 spi_slave_tx_transfer(spi, len);
202 } else if (!strncmp(buf, "onlyrx", 6)) {
203 buf += 7;
204 if (!strncmp(buf, "len=", 4))
205 if (sscanf(buf+4, "%d", &len) > 0)
206 spi_slave_rx_transfer(spi, len);
207 }
208 //else if (!strncmp(buf, "abort", 5)) {
209 // spi_slave_abort(spi);
210 //}
211
212 return count;
213}
214
215static DEVICE_ATTR(spi, 0644, spis_show, spis_store);
216
217static struct device_attribute *spi_attribute[] = {
218 &dev_attr_spi,
219};
220static void spi_create_attribute(struct device *dev)
221{
222 int size, idx;
223
224 size = ARRAY_SIZE(spi_attribute);
225 for (idx = 0; idx < size; idx++)
226 device_create_file(dev, spi_attribute[idx]);
227}
228//zhengzhou modify 20201110 start
229static int spi_get_pinctrl_info(struct spi_device *spi)
230{
231 int ret;
232
233 pinctrl_spi = devm_pinctrl_get(&spi->dev);
234 if (IS_ERR(pinctrl_spi)) {
235 ret = PTR_ERR(pinctrl_spi);
236 pr_notice("Cannot find pinctrl_spi!\n");
237 return ret;
238 }
239
240 default_spi = pinctrl_lookup_state(pinctrl_spi, "default");
241 if (IS_ERR(default_spi)) {
242 ret = PTR_ERR(default_spi);
243 pr_notice("Cannot find pinctrl default %d!\n", ret);
244 }
245
246 //spi_gpio = pinctrl_lookup_state(pinctrl_spi, "spi_gpio_mode");
247 //if (IS_ERR(spi_gpio)) {
248 // ret = PTR_ERR(spi_gpio);
249 // pr_notice("Cannot find pinctrl spi_gpio_mode %d!\n", ret);
250 //}
251
252 return 0;
253}
254//zhengzhou modify 20201110 end
255static int spi_slave_mt27xx_test_probe(struct spi_device *spi)
256{
257 spi_get_pinctrl_info(spi);//zhengzhou modify 20201110
258 pinctrl_select_state(pinctrl_spi, default_spi);//zhengzhou modify 20201110
259 spi_create_attribute(&spi->dev);
260 return 0;
261}
262
263static int spi_slave_mt27xx_test_remove(struct spi_device *spi)
264{
265 //spi_slave_abort(spi);
266 return 0;
267}
268//zhengzhou modify 20201110 start
269static const struct of_device_id spisdev_dt_ids[] = {
270 { .compatible = "mediatek,spi-slave-mt27xx-test" },
271 {},
272};
273MODULE_DEVICE_TABLE(of, spisdev_dt_ids);
274//zhengzhou modify 20201110 start end
275static struct spi_driver spi_slave_mt27xx_test_driver = {
276 .driver = {
277 .name = "spi-slave-mt27xx-test",
278 .of_match_table = spisdev_dt_ids,//zhengzhou modify 20201110
279 },
280 .probe = spi_slave_mt27xx_test_probe,
281 .remove = spi_slave_mt27xx_test_remove,
282};
283module_spi_driver(spi_slave_mt27xx_test_driver);
284
285MODULE_AUTHOR("Mediatek");
286MODULE_LICENSE("GPL v2");