blob: a49a1a8be7f25f928ec49204f78dcc039dd659cb [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/of.h>
9#include <linux/spi/spi.h>
10#include <linux/clk.h>
11#include <linux/platform_data/spi-mt65xx.h>
12#include <linux/random.h>
13#include <linux/clk.h>
14#include <linux/gpio/consumer.h>
15#include <linux/kernel.h> /* printk */
16#include <linux/pinctrl/consumer.h>
17
18
19static bool spi_auto_test_flag;
20static struct pinctrl *pinctrl_spi;
21static struct pinctrl_state *default_spi;
22#define SPI_DEBUG(fmt, args...) pr_info(fmt, ##args)
23
24struct mtk_spi {
25 void __iomem *base;
26 u32 state;
27 int pad_num;
28 u32 *pad_sel;
29 struct clk *parent_clk, *sel_clk, *spi_clk, *spare_clk;
30 struct spi_transfer *cur_transfer;
31 u32 xfer_len;
32 u32 num_xfered;
33 struct scatterlist *tx_sgl, *rx_sgl;
34 u32 tx_sgl_len, rx_sgl_len;
35 const struct mtk_spi_compatible *dev_comp;
36};
37
38static int secspi_enable_clk(struct spi_device *spidev)
39{
40 int ret;
41 struct spi_master *master;
42 struct mtk_spi *ms;
43
44 master = spidev->master;
45 ms = spi_master_get_devdata(master);
46
47 ret = clk_prepare_enable(ms->spi_clk);
48
49 if (ret < 0) {
50 SPI_DEBUG("failed to enable spi_clk (%d)\n", ret);
51 return ret;
52 }
53
54 if (!IS_ERR(ms->spare_clk)) {
55 ret = clk_prepare_enable(ms->spare_clk);
56 if (ret < 0) {
57 clk_disable_unprepare(ms->spi_clk);
58 SPI_DEBUG("failed to disable spi_clk (%d)\n", ret);
59 return ret;
60 }
61 }
62
63 return 0;
64
65}
66
67void secspi_disable_clk(struct spi_device *spidev)
68{
69
70 struct spi_master *master;
71 struct mtk_spi *ms;
72
73 master = spidev->master;
74 ms = spi_master_get_devdata(master);
75
76 clk_disable_unprepare(ms->spi_clk);
77 if (!IS_ERR(ms->spare_clk))
78 clk_disable_unprepare(ms->spare_clk);
79}
80
81void spi_transfer_malloc(struct spi_transfer *trans, int is2spis)
82{
83 int i;
84
85 trans->tx_buf = kzalloc(trans->len, GFP_KERNEL);
86 trans->rx_buf = kzalloc(trans->len, GFP_KERNEL);
87 memset(trans->rx_buf, 0, trans->len);
88/*zhengzhou 2021.03.03 modify +++++ */
89 //if (is2spis) {
90 // i = 1;
91 // *((char *)trans->tx_buf) = 0x55;
92 //} else
93/*zhengzhou 2021.03.03 modify ------ */
94 i = 0;
95
96 for (; i < trans->len; i++)
97 *((char *)trans->tx_buf + i) = i;
98}
99
100void spi_transfer_free(struct spi_transfer *trans)
101{
102 kfree(trans->tx_buf);
103 kfree(trans->rx_buf);
104}
105
106static void debug_packet(char *name, u8 *ptr, int len)
107{
108 int i;
109
110 SPI_DEBUG("%s: ", name);
111 for (i = 0; i < len; i++)
112 SPI_DEBUG(" %02x", ptr[i]);
113 SPI_DEBUG("\n");
114}
115
116int spi_loopback_check(struct spi_device *spi,
117 struct spi_transfer *trans, int is2spis)
118{
119 int i, value, err = 0;
120
121 //if (is2spis)//zhengzhou 2021.03.03 modify
122 // i = 1;//zhengzhou 2021.03.03 modify
123 //else//zhengzhou 2021.03.03 modify
124 i = 0;
125
126 for (; i < trans->len; i++) {
127 value = *((u8 *) trans->tx_buf + i);
128 if (value != *((char *) trans->rx_buf + i))
129 err++;
130 }
131
132 if (err) {
133 SPI_DEBUG("spim_len:%d, err %d\n", trans->len, err);
134 debug_packet("spim_tx_buf", (void *)trans->tx_buf, trans->len);
135 debug_packet("spim_rx_buf", trans->rx_buf, trans->len);
136 SPI_DEBUG("spim test fail.\n");
137 spi_auto_test_flag = false;
138 } else {
139 SPI_DEBUG("spim_len:%d, err %d\n", trans->len, err);
140 SPI_DEBUG("spim test pass.\n");
141 spi_auto_test_flag = true;
142 }
143
144 if (err)
145 return -1;
146 else
147 return 0;
148}
149
150int spi_loopback_transfer(struct spi_device *spi, int len, int is2spis)
151{
152 struct spi_transfer trans;
153 struct spi_message msg;
154 int ret = 0;
155
156 memset(&trans, 0, sizeof(struct spi_transfer));
157 spi_message_init(&msg);
158
159 if (is2spis) {
160 trans.speed_hz = 13000000;
161 trans.len = len;//zhengzhou 2021.03.03 modify
162 } else
163 trans.len = len;
164 trans.cs_change = 0;
165 spi_transfer_malloc(&trans, is2spis);
166 spi_message_add_tail(&trans, &msg);
167 ret = spi_sync(spi, &msg);
168 if (ret < 0)
169 SPI_DEBUG("Message transfer err,line(%d):%d\n", __LINE__, ret);
170 spi_loopback_check(spi, &trans, is2spis);
171 spi_transfer_free(&trans);
172
173 return ret;
174}
175
176static ssize_t spi_show(struct device *dev,
177 struct device_attribute *attr, char *buf)
178{
179 char *bp = buf;
180
181 if (spi_auto_test_flag)
182 bp += sprintf(bp, "spim talk with spis pass\n");
183 else
184 bp += sprintf(bp, "spim talk with spis fail\n");
185
186 *bp++ = '\n';
187
188 return bp - buf;
189}
190
191static ssize_t spi_store(struct device *dev,
192 struct device_attribute *attr,
193 const char *buf, size_t count)
194{
195 int len;
196 struct spi_device *spi;
197
198 spi = container_of(dev, struct spi_device, dev);
199
200 if (!strncmp(buf, "-w", 2)) {
201 buf += 3;
202
203 if (!strncmp(buf, "len=", 4) &&
204 (sscanf(buf + 4, "%d", &len) == 1)) {
205 spi_loopback_transfer(spi, len, 0);
206 }
207 }
208
209 if (!strncmp(buf, "spim2spis", 9)) {
210 buf += 10;
211
212 if (!strncmp(buf, "len=", 4) &&
213 (sscanf(buf + 4, "%d", &len) == 1)) {
214 spi_loopback_transfer(spi, len, 1);
215 }
216 }
217
218 if (!strncmp(buf, "enableclk", 9))
219 secspi_enable_clk(spi);
220 if (!strncmp(buf, "disableclk", 10))
221 secspi_disable_clk(spi);
222
223 return count;
224}
225
226static DEVICE_ATTR_RW(spi);
227
228static struct device_attribute *spi_attribute[] = {
229 &dev_attr_spi,
230};
231
232static int spi_create_attribute(struct device *dev)
233{
234 int i, size, idx;
235 int res = 0;
236
237 size = ARRAY_SIZE(spi_attribute);
238 for (idx = 0; idx < size; idx++) {
239 res = device_create_file(dev, spi_attribute[idx]);
240 if (res)
241 goto err;
242 }
243 return res;
244err:
245 for (i = 0; i < idx; i++)
246 device_remove_file(dev, spi_attribute[idx]);
247 return res;
248}
249//zhengzhou 2021.03.03 modify +++++
250static int spi_get_pinctrl_info(struct spi_device *spi)
251{
252 int ret;
253
254 pinctrl_spi = devm_pinctrl_get(&spi->dev);
255 if (IS_ERR(pinctrl_spi)) {
256 ret = PTR_ERR(pinctrl_spi);
257 pr_notice("Cannot find pinctrl_spi!\n");
258 return ret;
259 }
260
261 default_spi = pinctrl_lookup_state(pinctrl_spi, "default");
262 if (IS_ERR(default_spi)) {
263 ret = PTR_ERR(default_spi);
264 pr_notice("Cannot find pinctrl default %d!\n", ret);
265 }
266
267 //spi_gpio = pinctrl_lookup_state(pinctrl_spi, "spi_gpio_mode");
268 //if (IS_ERR(spi_gpio)) {
269 // ret = PTR_ERR(spi_gpio);
270 // pr_notice("Cannot find pinctrl spi_gpio_mode %d!\n", ret);
271 //}
272
273 return 0;
274}
275//zhengzhou 2021.03.03 modify ------
276static int spi_mt65xx_dev_probe(struct spi_device *spi)
277{
278 spi_get_pinctrl_info(spi);//zhengzhou 2021.03.03 modify +++++
279 spi_create_attribute(&spi->dev);
280 return 0;
281}
282
283static int spi_mt65xx_dev_remove(struct spi_device *spi)
284{
285 return 0;
286}
287
288static const struct of_device_id spi_mt65xx_dev_dt_ids[] = {
289 { .compatible = "mediatek,spi-mt65xx-dev" },//zhengzhou 2021.03.03 modify
290 { .compatible = "mediatek,spi-slave-autotest" },//zhengzhou 2021.03.03 modify
291 {},
292};
293MODULE_DEVICE_TABLE(of, spi_mt65xx_dev_dt_ids);
294
295static struct spi_driver spi_mt65xx_dev_driver = {
296 .driver = {
297 .name = "spi-mt65xx-dev",
298 .of_match_table = of_match_ptr(spi_mt65xx_dev_dt_ids),
299 },
300 .probe = spi_mt65xx_dev_probe,
301 .remove = spi_mt65xx_dev_remove,
302};
303module_spi_driver(spi_mt65xx_dev_driver);
304
305MODULE_AUTHOR("Mediatek");
306MODULE_LICENSE("GPL v2");