xref: /aosp_15_r20/external/flashrom/stlinkv3_spi.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
1 /*
2  * This file is part of the flashrom project.
3  *
4  * Copyright (C) 2019 Miklós Márton [email protected]
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  */
17 
18 /*
19  * Driver for programming SPI flash chips using the SPI port
20  * of the STMicroelectronics's STLINK-V3 programmer/debugger.
21  *
22  * The implementation is inspired by the ST's STLINK-V3-BRIDGE C++ API:
23  * https://www.st.com/en/development-tools/stlink-v3-bridge.html
24  */
25 
26 #include "flash.h"
27 #include "programmer.h"
28 #include "spi.h"
29 
30 #include <libusb.h>
31 #include <limits.h>
32 #include <stdint.h>
33 #include <stdlib.h>
34 #include <string.h>
35 
36 enum fw_version_check_result {
37 	FW_VERSION_OK,
38 	FW_VERSION_OLD,
39 };
40 
41 enum spi_prescaler {
42 	SPI_BAUDRATEPRESCALER_2 = 0,
43 	SPI_BAUDRATEPRESCALER_4 = 1,
44 	SPI_BAUDRATEPRESCALER_8 = 2,
45 	SPI_BAUDRATEPRESCALER_16 = 3,
46 	SPI_BAUDRATEPRESCALER_32 = 4,
47 	SPI_BAUDRATEPRESCALER_64 = 5,
48 	SPI_BAUDRATEPRESCALER_128 = 6,
49 	SPI_BAUDRATEPRESCALER_256 = 7
50 };
51 
52 enum spi_dir {
53 	SPI_DIRECTION_2LINES_FULLDUPLEX = 0,
54 	SPI_DIRECTION_2LINES_RXONLY = 1,
55 	SPI_DIRECTION_1LINE_RX = 2,
56 	SPI_DIRECTION_1LINE_TX = 3
57 };
58 
59 enum spi_mode {
60 	SPI_MODE_SLAVE = 0,
61 	SPI_MODE_MASTER = 1
62 };
63 
64 enum spi_datasize {
65 	SPI_DATASIZE_16B = 0,
66 	SPI_DATASIZE_8B = 1
67 };
68 
69 enum spi_cpol {
70 	SPI_CPOL_LOW = 0,
71 	SPI_CPOL_HIGH = 1
72 };
73 
74 enum spi_cpha {
75 	SPI_CPHA_1EDGE = 0,
76 	SPI_CPHA_2EDGE = 1
77 };
78 
79 enum spi_firstbit {
80 	SPI_FIRSTBIT_LSB = 0,
81 	SPI_FIRSTBIT_MSB = 1
82 };
83 
84 // ST calls the Chip select (CS) NSS == Negated Slave Select
85 enum spi_nss {
86 	SPI_NSS_SOFT = 0,
87 	SPI_NSS_HARD = 1
88 };
89 
90 enum spi_nss_level {
91 	SPI_NSS_LOW = 0,
92 	SPI_NSS_HIGH = 1
93 };
94 
95 #define ST_GETVERSION_EXT					0xFB
96 
97 #define STLINK_BRIDGE_COMMAND					0xFC
98 #define STLINK_BRIDGE_CLOSE					0x01
99 #define STLINK_BRIDGE_GET_RWCMD_STATUS				0x02
100 #define STLINK_BRIDGE_GET_CLOCK					0x03
101 #define STLINK_BRIDGE_INIT_SPI					0x20
102 #define STLINK_BRIDGE_WRITE_SPI					0x21
103 #define STLINK_BRIDGE_READ_SPI					0x22
104 #define STLINK_BRIDGE_CS_SPI					0x23
105 
106 #define STLINK_BRIDGE_SPI_ERROR					0x02
107 
108 #define STLINK_SPI_COM						0x02
109 
110 #define STLINK_EP_OUT						0x06
111 #define STLINK_EP_IN						0x86
112 
113 #define FIRST_COMPATIBLE_BRIDGE_FW_VERSION			3
114 
115 #define USB_TIMEOUT_IN_MS					5000
116 
117 static const struct dev_entry devs_stlinkv3_spi[] = {
118 	{0x0483, 0x374E, BAD, "STMicroelectronics", "STLINK-V3E"},
119 	{0x0483, 0x374F, OK, "STMicroelectronics", "STLINK-V3S"},
120 	{0x0483, 0x3753, OK, "STMicroelectronics", "STLINK-V3 dual VCP"},
121 	{0x0483, 0x3754, NT, "STMicroelectronics", "STLINK-V3 no MSD"},
122 	{0}
123 };
124 
125 struct stlinkv3_spi_data {
126 	struct libusb_context *usb_ctx;
127 	libusb_device_handle *handle;
128 };
129 
stlinkv3_command(uint8_t * command,size_t command_length,uint8_t * answer,size_t answer_length,const char * command_name,libusb_device_handle * stlinkv3_handle)130 static int stlinkv3_command(uint8_t *command, size_t command_length,
131 		     uint8_t *answer, size_t answer_length, const char *command_name,
132 		     libusb_device_handle *stlinkv3_handle)
133 {
134 	int actual_length = 0;
135 	int rc = libusb_bulk_transfer(stlinkv3_handle, STLINK_EP_OUT,
136 				  command, command_length,
137 				  &actual_length, USB_TIMEOUT_IN_MS);
138 	if (rc != LIBUSB_TRANSFER_COMPLETED || (size_t)actual_length != command_length) {
139 		msg_perr("Failed to issue the %s command: '%s'\n",
140 			 command_name,
141 			 libusb_error_name(rc));
142 		return -1;
143 	}
144 
145 	rc = libusb_bulk_transfer(stlinkv3_handle, STLINK_EP_IN,
146 				  answer, answer_length,
147 				  &actual_length, USB_TIMEOUT_IN_MS);
148 	if (rc != LIBUSB_TRANSFER_COMPLETED || (size_t)actual_length != answer_length) {
149 		msg_perr("Failed to get %s answer: '%s'\n",
150 			 command_name,
151 			 libusb_error_name(rc));
152 		return -1;
153 	}
154 	return 0;
155 }
156 
157 /**
158  * @param[out] bridge_input_clk Current input frequency in kHz of the given com.
159  */
stlinkv3_get_clk(uint32_t * bridge_input_clk,libusb_device_handle * stlinkv3_handle)160 static int stlinkv3_get_clk(uint32_t *bridge_input_clk, libusb_device_handle *stlinkv3_handle)
161 {
162 	uint8_t command[16] = { 0 };
163 	uint8_t answer[12];
164 
165 	if (bridge_input_clk == NULL)
166 		return -1;
167 
168 	command[0] = STLINK_BRIDGE_COMMAND;
169 	command[1] = STLINK_BRIDGE_GET_CLOCK;
170 	command[2] = STLINK_SPI_COM;
171 
172 	if (stlinkv3_command(command, sizeof(command),
173 				answer, sizeof(answer),
174 				"STLINK_BRIDGE_GET_CLOCK",
175 				stlinkv3_handle) != 0)
176 		return -1;
177 
178 	*bridge_input_clk = (uint32_t)answer[4]
179 			  | (uint32_t)answer[5]<<8
180 			  | (uint32_t)answer[6]<<16
181 			  | (uint32_t)answer[7]<<24;
182 	return 0;
183 
184 }
185 
stlinkv3_spi_calc_prescaler(uint16_t reqested_freq_in_kHz,enum spi_prescaler * prescaler,uint16_t * calculated_freq_in_kHz,libusb_device_handle * stlinkv3_handle)186 static int stlinkv3_spi_calc_prescaler(uint16_t reqested_freq_in_kHz,
187 				       enum spi_prescaler *prescaler,
188 				       uint16_t *calculated_freq_in_kHz,
189 				       libusb_device_handle *stlinkv3_handle)
190 {
191 	uint32_t bridge_clk_in_kHz;
192 	uint32_t calculated_prescaler = 1;
193 	uint16_t prescaler_value;
194 
195 	if (stlinkv3_get_clk(&bridge_clk_in_kHz, stlinkv3_handle))
196 		return -1;
197 
198 	calculated_prescaler  = bridge_clk_in_kHz/reqested_freq_in_kHz;
199 	// Apply a smaller frequency if not exact
200 	if (calculated_prescaler  <= 2) {
201 		*prescaler = SPI_BAUDRATEPRESCALER_2;
202 		prescaler_value = 2;
203 	} else if (calculated_prescaler  <= 4) {
204 		*prescaler = SPI_BAUDRATEPRESCALER_4;
205 		prescaler_value = 4;
206 	} else if (calculated_prescaler  <= 8) {
207 		*prescaler = SPI_BAUDRATEPRESCALER_8;
208 		prescaler_value = 8;
209 	} else if (calculated_prescaler  <= 16) {
210 		*prescaler = SPI_BAUDRATEPRESCALER_16;
211 		prescaler_value = 16;
212 	} else if (calculated_prescaler  <= 32) {
213 		*prescaler = SPI_BAUDRATEPRESCALER_32;
214 		prescaler_value = 32;
215 	} else if (calculated_prescaler  <= 64) {
216 		*prescaler = SPI_BAUDRATEPRESCALER_64;
217 		prescaler_value = 64;
218 	} else if (calculated_prescaler  <= 128) {
219 		*prescaler = SPI_BAUDRATEPRESCALER_128;
220 		prescaler_value = 128;
221 	} else if (calculated_prescaler  <= 256) {
222 		*prescaler = SPI_BAUDRATEPRESCALER_256;
223 		prescaler_value = 256;
224 	} else {
225 		// smaller frequency not possible
226 		*prescaler = SPI_BAUDRATEPRESCALER_256;
227 		prescaler_value = 256;
228 	}
229 
230 	*calculated_freq_in_kHz = bridge_clk_in_kHz / prescaler_value;
231 
232 	return 0;
233 }
234 
stlinkv3_check_version(enum fw_version_check_result * result,libusb_device_handle * stlinkv3_handle)235 static int stlinkv3_check_version(enum fw_version_check_result *result, libusb_device_handle *stlinkv3_handle)
236 {
237 	uint8_t answer[12];
238 	uint8_t command[16] = { 0 };
239 
240 	command[0] = ST_GETVERSION_EXT;
241 	command[1] = 0x80;
242 
243 	if (stlinkv3_command(command, sizeof(command),
244 				answer, sizeof(answer),
245 				"ST_GETVERSION_EXT",
246 				stlinkv3_handle) != 0)
247 		return -1;
248 
249 	msg_pinfo("Connected to STLink V3 with bridge FW version: %d\n", answer[4]);
250 	*result = answer[4] >= FIRST_COMPATIBLE_BRIDGE_FW_VERSION
251 			? FW_VERSION_OK
252 			: FW_VERSION_OLD;
253 	return 0;
254 }
255 
stlinkv3_spi_open(uint16_t reqested_freq_in_kHz,libusb_device_handle * stlinkv3_handle)256 static int stlinkv3_spi_open(uint16_t reqested_freq_in_kHz, libusb_device_handle *stlinkv3_handle)
257 {
258 	uint8_t command[16] = { 0 };
259 	uint8_t answer[2];
260 	uint16_t SCK_freq_in_kHz;
261 	enum spi_prescaler prescaler;
262 	enum fw_version_check_result fw_check_result;
263 
264 	if (stlinkv3_check_version(&fw_check_result, stlinkv3_handle)) {
265 		msg_perr("Failed to query FW version\n");
266 		return -1;
267 	}
268 
269 	if (fw_check_result != FW_VERSION_OK) {
270 		msg_pinfo("Your STLink V3 has a too old version of the bridge interface\n"
271 			  "Please update the firmware to version 2.33.25 or newer of the STSW-LINK007\n"
272 			  "which can be downloaded from here:\n"
273 			  "https://www.st.com/en/development-tools/stsw-link007.html\n");
274 		return -1;
275 	}
276 
277 	if (stlinkv3_spi_calc_prescaler(reqested_freq_in_kHz,
278 					&prescaler,
279 					&SCK_freq_in_kHz,
280 					stlinkv3_handle)) {
281 		msg_perr("Failed to calculate SPI clock prescaler\n");
282 		return -1;
283 	}
284 	msg_pinfo("SCK frequency set to %d kHz\n", SCK_freq_in_kHz);
285 
286 	command[0] = STLINK_BRIDGE_COMMAND;
287 	command[1] = STLINK_BRIDGE_INIT_SPI;
288 	command[2] = SPI_DIRECTION_2LINES_FULLDUPLEX;
289 	command[3] = (SPI_MODE_MASTER
290 		      | (SPI_CPHA_1EDGE << 1)
291 		      | (SPI_CPOL_LOW << 2)
292 		      | (SPI_FIRSTBIT_MSB << 3));
293 	command[4] = SPI_DATASIZE_8B;
294 	command[5] = SPI_NSS_SOFT;
295 	command[6] = (uint8_t)prescaler;
296 
297 	return stlinkv3_command(command, sizeof(command),
298 				answer, sizeof(answer),
299 				"STLINK_BRIDGE_INIT_SPI",
300 				stlinkv3_handle);
301 }
302 
stlinkv3_get_last_readwrite_status(uint32_t * status,libusb_device_handle * stlinkv3_handle)303 static int stlinkv3_get_last_readwrite_status(uint32_t *status, libusb_device_handle *stlinkv3_handle)
304 {
305 	uint8_t command[16] = { 0 };
306 	uint16_t answer[4];
307 
308 	command[0] = STLINK_BRIDGE_COMMAND;
309 	command[1] = STLINK_BRIDGE_GET_RWCMD_STATUS;
310 
311 	if (stlinkv3_command(command, sizeof(command),
312 			     (uint8_t *)answer, sizeof(answer),
313 			     "STLINK_BRIDGE_GET_RWCMD_STATUS",
314 			     stlinkv3_handle) != 0)
315 		return -1;
316 
317 	*status = (uint32_t)answer[2] | (uint32_t)answer[3]<<16;
318 	return 0;
319 }
320 
stlinkv3_spi_set_SPI_NSS(enum spi_nss_level nss_level,libusb_device_handle * stlinkv3_handle)321 static int stlinkv3_spi_set_SPI_NSS(enum spi_nss_level nss_level, libusb_device_handle *stlinkv3_handle)
322 {
323 	uint8_t command[16] = { 0 };
324 	uint8_t answer[2];
325 
326 	command[0] = STLINK_BRIDGE_COMMAND;
327 	command[1] = STLINK_BRIDGE_CS_SPI;
328 	command[2] = (uint8_t) (nss_level);
329 
330 	if (stlinkv3_command(command, sizeof(command),
331 				answer, sizeof(answer),
332 				"STLINK_BRIDGE_CS_SPI",
333 				stlinkv3_handle) != 0)
334 		return -1;
335 	return 0;
336 }
337 
stlinkv3_spi_transmit(const struct flashctx * flash,unsigned int write_cnt,unsigned int read_cnt,const unsigned char * write_arr,unsigned char * read_arr)338 static int stlinkv3_spi_transmit(const struct flashctx *flash,
339 				 unsigned int write_cnt,
340 				 unsigned int read_cnt,
341 				 const unsigned char *write_arr,
342 				 unsigned char *read_arr)
343 {
344 	struct stlinkv3_spi_data *stlinkv3_data = flash->mst->spi.data;
345 	libusb_device_handle *stlinkv3_handle = stlinkv3_data->handle;
346 	uint8_t command[16] = { 0 };
347 	int rc = 0;
348 	int actual_length = 0;
349 	uint32_t rw_status = 0;
350 	unsigned int i;
351 
352 	if (stlinkv3_spi_set_SPI_NSS(SPI_NSS_LOW, stlinkv3_handle)) {
353 		msg_perr("Failed to set the NSS pin to low\n");
354 		return -1;
355 	}
356 
357 	command[0] = STLINK_BRIDGE_COMMAND;
358 	command[1] = STLINK_BRIDGE_WRITE_SPI;
359 	command[2] = (uint8_t)write_cnt;
360 	command[3] = (uint8_t)(write_cnt >> 8);
361 
362 	for (i = 0; (i < 8) && (i < write_cnt); i++)
363 		command[4+i] = write_arr[i];
364 
365 	rc = libusb_bulk_transfer(stlinkv3_handle, STLINK_EP_OUT,
366 				  command, sizeof(command),
367 				  &actual_length, USB_TIMEOUT_IN_MS);
368 	if (rc != LIBUSB_TRANSFER_COMPLETED || actual_length != sizeof(command)) {
369 		msg_perr("Failed to issue the STLINK_BRIDGE_WRITE_SPI command: '%s'\n",
370 			 libusb_error_name(rc));
371 		goto transmit_err;
372 	}
373 
374 	if (write_cnt > 8) {
375 		rc = libusb_bulk_transfer(stlinkv3_handle,
376 					  STLINK_EP_OUT,
377 					  (unsigned char *)&write_arr[8],
378 					  (unsigned int)(write_cnt - 8),
379 					  &actual_length,
380 					  USB_TIMEOUT_IN_MS);
381 		if (rc != LIBUSB_TRANSFER_COMPLETED || (unsigned int)actual_length != (write_cnt - 8)) {
382 			msg_perr("Failed to send the  data after the  STLINK_BRIDGE_WRITE_SPI command: '%s'\n",
383 				 libusb_error_name(rc));
384 			goto transmit_err;
385 		}
386 	}
387 
388 	if (stlinkv3_get_last_readwrite_status(&rw_status, stlinkv3_handle))
389 		return -1;
390 
391 	if (rw_status != 0) {
392 		msg_perr("SPI read/write failure: %d\n", rw_status);
393 		goto transmit_err;
394 	}
395 
396 	if (read_cnt) {
397 		command[1] = STLINK_BRIDGE_READ_SPI;
398 		command[2] = (uint8_t)read_cnt;
399 		command[3] = (uint8_t)(read_cnt >> 8);
400 
401 		rc = libusb_bulk_transfer(stlinkv3_handle, STLINK_EP_OUT,
402 					  command, sizeof(command),
403 					  &actual_length, USB_TIMEOUT_IN_MS);
404 		if (rc != LIBUSB_TRANSFER_COMPLETED || (unsigned int)actual_length != sizeof(command)) {
405 			msg_perr("Failed to issue the STLINK_BRIDGE_READ_SPI command: '%s'\n",
406 				 libusb_error_name(rc));
407 			goto transmit_err;
408 		}
409 
410 		rc = libusb_bulk_transfer(stlinkv3_handle,
411 					  STLINK_EP_IN,
412 					  (unsigned char *)read_arr,
413 					  (int)read_cnt,
414 					  &actual_length,
415 					  USB_TIMEOUT_IN_MS);
416 		if (rc != LIBUSB_TRANSFER_COMPLETED || (unsigned int)actual_length != read_cnt) {
417 			msg_perr("Failed to retrieve the STLINK_BRIDGE_READ_SPI answer: '%s'\n",
418 				 libusb_error_name(rc));
419 			goto transmit_err;
420 		}
421 	}
422 
423 	if (stlinkv3_get_last_readwrite_status(&rw_status, stlinkv3_handle))
424 		goto transmit_err;
425 
426 	if (rw_status != 0) {
427 		msg_perr("SPI read/write failure: %d\n", rw_status);
428 		goto transmit_err;
429 	}
430 
431 	if (stlinkv3_spi_set_SPI_NSS(SPI_NSS_HIGH, stlinkv3_handle)) {
432 		msg_perr("Failed to set the NSS pin to high\n");
433 		return -1;
434 	}
435 	return 0;
436 
437 transmit_err:
438 	if (stlinkv3_spi_set_SPI_NSS(SPI_NSS_HIGH, stlinkv3_handle))
439 		msg_perr("Failed to set the NSS pin to high\n");
440 	return -1;
441 }
442 
stlinkv3_spi_shutdown(void * data)443 static int stlinkv3_spi_shutdown(void *data)
444 {
445 	struct stlinkv3_spi_data *stlinkv3_data = data;
446 	uint8_t command[16] = { 0 };
447 	uint8_t answer[2];
448 
449 	command[0] = STLINK_BRIDGE_COMMAND;
450 	command[1] = STLINK_BRIDGE_CLOSE;
451 	command[2] = STLINK_SPI_COM;
452 
453 	stlinkv3_command(command, sizeof(command),
454 				answer, sizeof(answer),
455 				"STLINK_BRIDGE_CLOSE",
456 				stlinkv3_data->handle);
457 
458 	libusb_close(stlinkv3_data->handle);
459 	libusb_exit(stlinkv3_data->usb_ctx);
460 
461 	free(data);
462 	return 0;
463 }
464 
465 static const struct spi_master spi_programmer_stlinkv3 = {
466 	.max_data_read	= UINT16_MAX,
467 	.max_data_write	= UINT16_MAX,
468 	.command	= stlinkv3_spi_transmit,
469 	.read		= default_spi_read,
470 	.write_256	= default_spi_write_256,
471 	.shutdown	= stlinkv3_spi_shutdown,
472 };
473 
stlinkv3_spi_init(const struct programmer_cfg * cfg)474 static int stlinkv3_spi_init(const struct programmer_cfg *cfg)
475 {
476 	uint16_t sck_freq_kHz = 1000;	// selecting 1 MHz SCK is a good bet
477 	char *param_str;
478 	char *endptr = NULL;
479 	int ret = 1;
480 	int devIndex = 0;
481 	struct libusb_context *usb_ctx;
482 	/* Initialize stlinkv3_handle to NULL for suppressing scan-build false positive core.uninitialized.Branch */
483 	libusb_device_handle *stlinkv3_handle = NULL;
484 	struct stlinkv3_spi_data *stlinkv3_data;
485 
486 	if (libusb_init(&usb_ctx)) {
487 		msg_perr("Could not initialize libusb!\n");
488 		return 1;
489 	}
490 
491 	param_str = extract_programmer_param_str(cfg, "serial");
492 	if (param_str)
493 		msg_pdbg("Opening STLINK-V3 with serial: %s\n", param_str);
494 
495 
496 	while (devs_stlinkv3_spi[devIndex].vendor_id != 0) {
497 		stlinkv3_handle = usb_dev_get_by_vid_pid_serial(usb_ctx,
498 								devs_stlinkv3_spi[devIndex].vendor_id,
499 								devs_stlinkv3_spi[devIndex].device_id,
500 								param_str);
501 		if (stlinkv3_handle) {
502 			if (devs_stlinkv3_spi[devIndex].status == BAD) {
503 				msg_perr("The STLINK-V3 Mini/MiniE does not support the bridge interface\n");
504 				free(param_str);
505 				goto init_err_exit;
506 			}
507 			break;
508 		}
509 		devIndex++;
510 	}
511 
512 	if (!stlinkv3_handle) {
513 		if (param_str)
514 			msg_perr("No STLINK-V3 seems to be connected with serial %s\n", param_str);
515 		else
516 			msg_perr("Could not find any connected STLINK-V3\n");
517 		free(param_str);
518 		goto init_err_exit;
519 	}
520 	free(param_str);
521 
522 	param_str = extract_programmer_param_str(cfg, "spispeed");
523 	if (param_str) {
524 		sck_freq_kHz = strtoul(param_str, &endptr, 0);
525 		if (*endptr || sck_freq_kHz == 0) {
526 			msg_perr("The spispeed parameter passed with invalid format: %s\n",
527 				 param_str);
528 			msg_perr("Please pass the parameter "
529 				 "with a simple non-zero number in kHz\n");
530 			free(param_str);
531 			ret = -1;
532 			goto init_err_exit;
533 		}
534 		free(param_str);
535 	}
536 
537 	if (stlinkv3_spi_open(sck_freq_kHz, stlinkv3_handle))
538 		goto init_err_exit;
539 
540 	stlinkv3_data = calloc(1, sizeof(*stlinkv3_data));
541 	if (!stlinkv3_data) {
542 		msg_perr("Unable to allocate space for SPI master data\n");
543 		goto init_err_exit;
544 	}
545 
546 	stlinkv3_data->usb_ctx = usb_ctx;
547 	stlinkv3_data->handle = stlinkv3_handle;
548 
549 	return register_spi_master(&spi_programmer_stlinkv3, stlinkv3_data);
550 
551 init_err_exit:
552 	if (stlinkv3_handle)
553 		libusb_close(stlinkv3_handle);
554 	libusb_exit(usb_ctx);
555 	return ret;
556 }
557 
558 const struct programmer_entry programmer_stlinkv3_spi = {
559 	.name			= "stlinkv3_spi",
560 	.type			= USB,
561 	.devs.dev		= devs_stlinkv3_spi,
562 	.init			= stlinkv3_spi_init,
563 };
564