blob: 9c78138b7b14315d7e468bdf963316055c02d502 [file] [log] [blame]
Justin Chevrier66e554b2015-02-08 21:58:10 +00001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2010 Carl-Daniel Hailfinger
5 * Copyright (C) 2014 Justin Chevrier
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
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.
Justin Chevrier66e554b2015-02-08 21:58:10 +000015 */
16
17/*
18 * Connections are as follows:
19 *
20 * +------+-----+----------+
21 * | SPI | Pin | PICkit2 |
22 * +------+-----+----------+
23 * | /CS | 1 | VPP/MCLR |
24 * | VCC | 2 | VDD |
25 * | GND | 3 | GND |
26 * | MISO | 4 | PGD |
27 * | SCLK | 5 | PDC |
28 * | MOSI | 6 | AUX |
29 * +------+-----+----------+
30 *
31 * Inspiration and some specifics of the interface came via the AVRDude
32 * PICkit2 code: https://github.com/steve-m/avrdude/blob/master/pickit2.c
33 */
34
35#include "platform.h"
36
37#include <stdlib.h>
38#include <stdio.h>
39#include <string.h>
40#include <limits.h>
41#include <errno.h>
Thomas Heijligenb221cd72019-04-05 15:08:35 +020042#include <libusb.h>
Justin Chevrier66e554b2015-02-08 21:58:10 +000043
44#include "flash.h"
45#include "chipdrivers.h"
46#include "programmer.h"
47#include "spi.h"
48
Thomas Heijligencc853d82021-05-04 15:32:17 +020049static const struct dev_entry devs_pickit2_spi[] = {
Stefan Taunerf31fe842016-02-22 08:59:15 +000050 {0x04D8, 0x0033, OK, "Microchip", "PICkit 2"},
51
Evgeny Zinoviev83c56b82019-11-05 17:47:43 +030052 {0}
Stefan Taunerf31fe842016-02-22 08:59:15 +000053};
54
Anastasia Klimchuk47e7d472021-04-30 14:10:04 +100055struct pickit2_spi_data {
56 libusb_device_handle *pickit2_handle;
57};
Justin Chevrier66e554b2015-02-08 21:58:10 +000058
59/* Default USB transaction timeout in ms */
60#define DFLT_TIMEOUT 10000
61
62#define CMD_LENGTH 64
63#define ENDPOINT_OUT 0x01
64#define ENDPOINT_IN 0x81
65
Justin Chevrier66e554b2015-02-08 21:58:10 +000066#define CMD_GET_VERSION 0x76
67#define CMD_SET_VDD 0xA0
68#define CMD_SET_VPP 0xA1
69#define CMD_READ_VDD_VPP 0xA3
70#define CMD_EXEC_SCRIPT 0xA6
71#define CMD_CLR_DLOAD_BUFF 0xA7
72#define CMD_DOWNLOAD_DATA 0xA8
73#define CMD_CLR_ULOAD_BUFF 0xA9
74#define CMD_UPLOAD_DATA 0xAA
75#define CMD_END_OF_BUFFER 0xAD
76
77#define SCR_SPI_READ_BUF 0xC5
78#define SCR_SPI_WRITE_BUF 0xC6
79#define SCR_SET_AUX 0xCF
80#define SCR_LOOP 0xE9
81#define SCR_SET_ICSP_CLK_PERIOD 0xEA
82#define SCR_SET_PINS 0xF3
83#define SCR_BUSY_LED_OFF 0xF4
84#define SCR_BUSY_LED_ON 0xF5
85#define SCR_MCLR_GND_OFF 0xF6
86#define SCR_MCLR_GND_ON 0xF7
87#define SCR_VPP_PWM_OFF 0xF8
88#define SCR_VPP_PWM_ON 0xF9
89#define SCR_VPP_OFF 0xFA
90#define SCR_VPP_ON 0xFB
91#define SCR_VDD_OFF 0xFE
92#define SCR_VDD_ON 0xFF
93
Angel Pons75d6ec62022-07-16 12:12:50 +020094static int pickit2_interrupt_transfer(libusb_device_handle *handle, unsigned char endpoint, unsigned char *data)
95{
96 int transferred;
97 return libusb_interrupt_transfer(handle, endpoint, data, CMD_LENGTH, &transferred, DFLT_TIMEOUT);
98}
99
Anastasia Klimchuk47e7d472021-04-30 14:10:04 +1000100static int pickit2_get_firmware_version(libusb_device_handle *pickit2_handle)
Justin Chevrier66e554b2015-02-08 21:58:10 +0000101{
102 int ret;
103 uint8_t command[CMD_LENGTH] = {CMD_GET_VERSION, CMD_END_OF_BUFFER};
Elyes HAOUAS0cacb112019-02-04 12:16:38 +0100104
Angel Pons75d6ec62022-07-16 12:12:50 +0200105 ret = pickit2_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, command);
Elyes HAOUAS3384fb62019-07-18 14:00:13 +0200106
Thomas Heijligenb221cd72019-04-05 15:08:35 +0200107 if (ret != 0) {
108 msg_perr("Command Get Firmware Version failed!\n");
Justin Chevrier66e554b2015-02-08 21:58:10 +0000109 return 1;
110 }
111
Angel Pons75d6ec62022-07-16 12:12:50 +0200112 ret = pickit2_interrupt_transfer(pickit2_handle, ENDPOINT_IN, command);
Elyes HAOUAS3384fb62019-07-18 14:00:13 +0200113
114 if (ret != 0) {
115 msg_perr("Command Get Firmware Version failed!\n");
116 return 1;
117 }
118
119 msg_pdbg("PICkit2 Firmware Version: %d.%d\n", (int)command[0], (int)command[1]);
Justin Chevrier66e554b2015-02-08 21:58:10 +0000120 return 0;
121}
122
Anastasia Klimchuk47e7d472021-04-30 14:10:04 +1000123static int pickit2_set_spi_voltage(libusb_device_handle *pickit2_handle, int millivolt)
Justin Chevrier66e554b2015-02-08 21:58:10 +0000124{
125 double voltage_selector;
126 switch (millivolt) {
127 case 0:
128 /* Admittedly this one is an assumption. */
129 voltage_selector = 0;
130 break;
131 case 1800:
132 voltage_selector = 1.8;
133 break;
134 case 2500:
135 voltage_selector = 2.5;
136 break;
137 case 3500:
138 voltage_selector = 3.5;
139 break;
140 default:
141 msg_perr("Unknown voltage %i mV! Aborting.\n", millivolt);
142 return 1;
143 }
144 msg_pdbg("Setting SPI voltage to %u.%03u V\n", millivolt / 1000,
145 millivolt % 1000);
146
147 uint8_t command[CMD_LENGTH] = {
148 CMD_SET_VDD,
149 voltage_selector * 2048 + 672,
150 (voltage_selector * 2048 + 672) / 256,
151 voltage_selector * 36,
152 CMD_SET_VPP,
153 0x40,
154 voltage_selector * 18.61,
155 voltage_selector * 13,
156 CMD_END_OF_BUFFER
157 };
Angel Pons75d6ec62022-07-16 12:12:50 +0200158 int ret = pickit2_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, command);
Justin Chevrier66e554b2015-02-08 21:58:10 +0000159
Thomas Heijligenb221cd72019-04-05 15:08:35 +0200160 if (ret != 0) {
161 msg_perr("Command Set Voltage failed!\n");
Justin Chevrier66e554b2015-02-08 21:58:10 +0000162 return 1;
163 }
164
165 return 0;
166}
167
168struct pickit2_spispeeds {
169 const char *const name;
170 const int speed;
171};
172
173static const struct pickit2_spispeeds spispeeds[] = {
174 { "1M", 0x1 },
175 { "500k", 0x2 },
176 { "333k", 0x3 },
177 { "250k", 0x4 },
178 { NULL, 0x0 },
179};
180
Anastasia Klimchuk47e7d472021-04-30 14:10:04 +1000181static int pickit2_set_spi_speed(libusb_device_handle *pickit2_handle, unsigned int spispeed_idx)
Justin Chevrier66e554b2015-02-08 21:58:10 +0000182{
183 msg_pdbg("SPI speed is %sHz\n", spispeeds[spispeed_idx].name);
184
185 uint8_t command[CMD_LENGTH] = {
186 CMD_EXEC_SCRIPT,
187 2,
188 SCR_SET_ICSP_CLK_PERIOD,
189 spispeed_idx,
190 CMD_END_OF_BUFFER
191 };
192
Angel Pons75d6ec62022-07-16 12:12:50 +0200193 int ret = pickit2_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, command);
Justin Chevrier66e554b2015-02-08 21:58:10 +0000194
Thomas Heijligenb221cd72019-04-05 15:08:35 +0200195 if (ret != 0) {
196 msg_perr("Command Set SPI Speed failed!\n");
Justin Chevrier66e554b2015-02-08 21:58:10 +0000197 return 1;
198 }
199
200 return 0;
201}
202
Edward O'Callaghan5eca4272020-04-12 17:27:53 +1000203static int pickit2_spi_send_command(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
Justin Chevrier66e554b2015-02-08 21:58:10 +0000204 const unsigned char *writearr, unsigned char *readarr)
205{
Felix Singer48c3f182022-07-29 03:16:19 +0200206 const unsigned int total_packetsize = writecnt + readcnt + 20;
Anastasia Klimchuk47e7d472021-04-30 14:10:04 +1000207 struct pickit2_spi_data *pickit2_data = flash->mst->spi.data;
Justin Chevrier66e554b2015-02-08 21:58:10 +0000208
209 /* Maximum number of bytes per transaction (including command overhead) is 64. Lets play it safe
210 * and always assume the worst case scenario of 20 bytes command overhead.
211 */
Felix Singer48c3f182022-07-29 03:16:19 +0200212 if (total_packetsize > CMD_LENGTH) {
Felix Singerd07c4a42022-07-29 03:09:02 +0200213 msg_perr("\nTotal packetsize (%i) is greater than %i supported, aborting.\n",
Felix Singer48c3f182022-07-29 03:16:19 +0200214 total_packetsize, CMD_LENGTH);
Justin Chevrier66e554b2015-02-08 21:58:10 +0000215 return 1;
216 }
217
218 uint8_t buf[CMD_LENGTH] = {CMD_DOWNLOAD_DATA, writecnt};
Nico Huber519be662018-12-23 20:03:35 +0100219 unsigned int i = 2;
Justin Chevrier66e554b2015-02-08 21:58:10 +0000220 for (; i < writecnt + 2; i++) {
221 buf[i] = writearr[i - 2];
222 }
223
224 buf[i++] = CMD_CLR_ULOAD_BUFF;
225 buf[i++] = CMD_EXEC_SCRIPT;
226
227 /* Determine script length based on number of bytes to be read or written */
228 if (writecnt == 1 && readcnt == 1)
229 buf[i++] = 7;
230 else if (writecnt == 1 || readcnt == 1)
231 buf[i++] = 10;
232 else
233 buf[i++] = 13;
Elyes HAOUAS0cacb112019-02-04 12:16:38 +0100234
Justin Chevrier66e554b2015-02-08 21:58:10 +0000235 /* Assert CS# */
236 buf[i++] = SCR_VPP_OFF;
237 buf[i++] = SCR_MCLR_GND_ON;
238
239 buf[i++] = SCR_SPI_WRITE_BUF;
240
241 if (writecnt > 1) {
242 buf[i++] = SCR_LOOP;
243 buf[i++] = 1; /* Loop back one instruction */
244 buf[i++] = writecnt - 1; /* Number of times to loop */
245 }
246
247 if (readcnt)
248 buf[i++] = SCR_SPI_READ_BUF;
249
250 if (readcnt > 1) {
251 buf[i++] = SCR_LOOP;
252 buf[i++] = 1; /* Loop back one instruction */
253 buf[i++] = readcnt - 1; /* Number of times to loop */
254 }
255
256 /* De-assert CS# */
257 buf[i++] = SCR_MCLR_GND_OFF;
258 buf[i++] = SCR_VPP_PWM_ON;
259 buf[i++] = SCR_VPP_ON;
260
261 buf[i++] = CMD_UPLOAD_DATA;
262 buf[i++] = CMD_END_OF_BUFFER;
263
Anastasia Klimchuk47e7d472021-04-30 14:10:04 +1000264 int ret = pickit2_interrupt_transfer(pickit2_data->pickit2_handle, ENDPOINT_OUT, buf);
Justin Chevrier66e554b2015-02-08 21:58:10 +0000265
Thomas Heijligenb221cd72019-04-05 15:08:35 +0200266 if (ret != 0) {
267 msg_perr("Send SPI failed!\n");
Justin Chevrier66e554b2015-02-08 21:58:10 +0000268 return 1;
269 }
270
271 if (readcnt) {
Thomas Heijligenb221cd72019-04-05 15:08:35 +0200272 int length = 0;
Anastasia Klimchuk47e7d472021-04-30 14:10:04 +1000273 ret = libusb_interrupt_transfer(pickit2_data->pickit2_handle,
274 ENDPOINT_IN, buf, CMD_LENGTH, &length, DFLT_TIMEOUT);
Justin Chevrier66e554b2015-02-08 21:58:10 +0000275
Thomas Heijligenb221cd72019-04-05 15:08:35 +0200276 if (length == 0 || ret != 0) {
277 msg_perr("Receive SPI failed\n");
Justin Chevrier66e554b2015-02-08 21:58:10 +0000278 return 1;
279 }
280
281 /* First byte indicates number of bytes transferred from upload buffer */
282 if (buf[0] != readcnt) {
283 msg_perr("Unexpected number of bytes transferred, expected %i, got %i!\n",
284 readcnt, ret);
285 return 1;
286 }
Elyes HAOUAS0cacb112019-02-04 12:16:38 +0100287
Justin Chevrier66e554b2015-02-08 21:58:10 +0000288 /* Actual data starts at byte number two */
289 memcpy(readarr, &buf[1], readcnt);
290 }
291
292 return 0;
293}
294
295/* Copied from dediprog.c */
296/* Might be useful for other USB devices as well. static for now. */
297static int parse_voltage(char *voltage)
298{
299 char *tmp = NULL;
300 int i;
301 int millivolt = 0, fraction = 0;
302
303 if (!voltage || !strlen(voltage)) {
304 msg_perr("Empty voltage= specified.\n");
305 return -1;
306 }
307 millivolt = (int)strtol(voltage, &tmp, 0);
308 voltage = tmp;
309 /* Handle "," and "." as decimal point. Everything after it is assumed
310 * to be in decimal notation.
311 */
312 if ((*voltage == '.') || (*voltage == ',')) {
313 voltage++;
314 for (i = 0; i < 3; i++) {
315 fraction *= 10;
316 /* Don't advance if the current character is invalid,
317 * but continue multiplying.
318 */
319 if ((*voltage < '0') || (*voltage > '9'))
320 continue;
321 fraction += *voltage - '0';
322 voltage++;
323 }
324 /* Throw away remaining digits. */
325 voltage += strspn(voltage, "0123456789");
326 }
327 /* The remaining string must be empty or "mV" or "V". */
328 tolower_string(voltage);
329
330 /* No unit or "V". */
331 if ((*voltage == '\0') || !strncmp(voltage, "v", 1)) {
332 millivolt *= 1000;
333 millivolt += fraction;
334 } else if (!strncmp(voltage, "mv", 2) ||
335 !strncmp(voltage, "millivolt", 9)) {
336 /* No adjustment. fraction is discarded. */
337 } else {
338 /* Garbage at the end of the string. */
339 msg_perr("Garbage voltage= specified.\n");
340 return -1;
341 }
342 return millivolt;
343}
344
Anastasia Klimchuk47e7d472021-04-30 14:10:04 +1000345static struct spi_master spi_master_pickit2 = {
Justin Chevrier66e554b2015-02-08 21:58:10 +0000346 .max_data_read = 40,
347 .max_data_write = 40,
348 .command = pickit2_spi_send_command,
349 .multicommand = default_spi_send_multicommand,
350 .read = default_spi_read,
351 .write_256 = default_spi_write_256,
352 .write_aai = default_spi_write_aai,
353};
354
355static int pickit2_shutdown(void *data)
356{
Anastasia Klimchuk47e7d472021-04-30 14:10:04 +1000357 struct pickit2_spi_data *pickit2_data = data;
358
Justin Chevrier66e554b2015-02-08 21:58:10 +0000359 /* Set all pins to float and turn voltages off */
360 uint8_t command[CMD_LENGTH] = {
361 CMD_EXEC_SCRIPT,
362 8,
363 SCR_SET_PINS,
364 3, /* Bit-0=1(PDC In), Bit-1=1(PGD In), Bit-2=0(PDC LL), Bit-3=0(PGD LL) */
365 SCR_SET_AUX,
366 1, /* Bit-0=1(Aux In), Bit-1=0(Aux LL) */
367 SCR_MCLR_GND_OFF,
368 SCR_VPP_OFF,
369 SCR_VDD_OFF,
370 SCR_BUSY_LED_OFF,
371 CMD_END_OF_BUFFER
372 };
373
Anastasia Klimchuk47e7d472021-04-30 14:10:04 +1000374 int ret = pickit2_interrupt_transfer(pickit2_data->pickit2_handle, ENDPOINT_OUT, command);
Justin Chevrier66e554b2015-02-08 21:58:10 +0000375
Thomas Heijligenb221cd72019-04-05 15:08:35 +0200376 if (ret != 0) {
377 msg_perr("Command Shutdown failed!\n");
Justin Chevrier66e554b2015-02-08 21:58:10 +0000378 ret = 1;
379 }
Anastasia Klimchuk47e7d472021-04-30 14:10:04 +1000380 if (libusb_release_interface(pickit2_data->pickit2_handle, 0) != 0) {
Justin Chevrier66e554b2015-02-08 21:58:10 +0000381 msg_perr("Could not release USB interface!\n");
382 ret = 1;
383 }
Anastasia Klimchuk47e7d472021-04-30 14:10:04 +1000384 libusb_close(pickit2_data->pickit2_handle);
Thomas Heijligenb221cd72019-04-05 15:08:35 +0200385 libusb_exit(NULL);
Anastasia Klimchuk47e7d472021-04-30 14:10:04 +1000386
387 free(data);
Justin Chevrier66e554b2015-02-08 21:58:10 +0000388 return ret;
389}
390
Thomas Heijligencc853d82021-05-04 15:32:17 +0200391static int pickit2_spi_init(void)
Justin Chevrier66e554b2015-02-08 21:58:10 +0000392{
Justin Chevrier66e554b2015-02-08 21:58:10 +0000393 uint8_t buf[CMD_LENGTH] = {
394 CMD_EXEC_SCRIPT,
395 10, /* Script length */
396 SCR_SET_PINS,
397 2, /* Bit-0=0(PDC Out), Bit-1=1(PGD In), Bit-2=0(PDC LL), Bit-3=0(PGD LL) */
398 SCR_SET_AUX,
399 0, /* Bit-0=0(Aux Out), Bit-1=0(Aux LL) */
400 SCR_VDD_ON,
401 SCR_MCLR_GND_OFF, /* Let CS# float */
402 SCR_VPP_PWM_ON,
403 SCR_VPP_ON, /* Pull CS# high */
404 SCR_BUSY_LED_ON,
405 CMD_CLR_DLOAD_BUFF,
406 CMD_CLR_ULOAD_BUFF,
407 CMD_END_OF_BUFFER
408 };
409
Anastasia Klimchuk47e7d472021-04-30 14:10:04 +1000410 libusb_device_handle *pickit2_handle;
411 struct pickit2_spi_data *pickit2_data;
Justin Chevrier66e554b2015-02-08 21:58:10 +0000412 int spispeed_idx = 0;
413 char *spispeed = extract_programmer_param("spispeed");
414 if (spispeed != NULL) {
415 int i = 0;
416 for (; spispeeds[i].name; i++) {
417 if (strcasecmp(spispeeds[i].name, spispeed) == 0) {
418 spispeed_idx = i;
419 break;
420 }
421 }
422 if (spispeeds[i].name == NULL) {
423 msg_perr("Error: Invalid 'spispeed' value.\n");
424 free(spispeed);
425 return 1;
426 }
427 free(spispeed);
428 }
429
430 int millivolt = 3500;
431 char *voltage = extract_programmer_param("voltage");
432 if (voltage != NULL) {
433 millivolt = parse_voltage(voltage);
434 free(voltage);
435 if (millivolt < 0)
436 return 1;
437 }
438
Thomas Heijligenb221cd72019-04-05 15:08:35 +0200439 if (libusb_init(NULL) < 0) {
440 msg_perr("Couldn't initialize libusb!\n");
441 return -1;
442 }
443
444#if LIBUSB_API_VERSION < 0x01000106
445 libusb_set_debug(NULL, 3);
446#else
447 libusb_set_option(NULL, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO);
448#endif
449
Stefan Taunerf31fe842016-02-22 08:59:15 +0000450 const uint16_t vid = devs_pickit2_spi[0].vendor_id;
451 const uint16_t pid = devs_pickit2_spi[0].device_id;
Thomas Heijligenb221cd72019-04-05 15:08:35 +0200452 pickit2_handle = libusb_open_device_with_vid_pid(NULL, vid, pid);
453 if (pickit2_handle == NULL) {
454 msg_perr("Could not open device PICkit2!\n");
455 libusb_exit(NULL);
Justin Chevrier66e554b2015-02-08 21:58:10 +0000456 return 1;
457 }
Justin Chevrier66e554b2015-02-08 21:58:10 +0000458
Thomas Heijligenb221cd72019-04-05 15:08:35 +0200459 if (libusb_set_configuration(pickit2_handle, 1) != 0) {
460 msg_perr("Could not set USB device configuration.\n");
461 libusb_close(pickit2_handle);
462 libusb_exit(NULL);
Justin Chevrier66e554b2015-02-08 21:58:10 +0000463 return 1;
464 }
Thomas Heijligenb221cd72019-04-05 15:08:35 +0200465 if (libusb_claim_interface(pickit2_handle, 0) != 0) {
466 msg_perr("Could not claim USB device interface\n");
467 libusb_close(pickit2_handle);
468 libusb_exit(NULL);
Justin Chevrier66e554b2015-02-08 21:58:10 +0000469 return 1;
470 }
471
Anastasia Klimchuk47e7d472021-04-30 14:10:04 +1000472 pickit2_data = calloc(1, sizeof(*pickit2_data));
473 if (!pickit2_data) {
474 msg_perr("Unable to allocate space for SPI master data\n");
475 libusb_close(pickit2_handle);
476 libusb_exit(NULL);
477 return 1;
478 }
479 pickit2_data->pickit2_handle = pickit2_handle;
480 spi_master_pickit2.data = pickit2_data;
481
482 if (pickit2_get_firmware_version(pickit2_handle))
Anastasia Klimchuk1c9c73a2021-04-30 11:25:44 +1000483 goto init_err_cleanup_exit;
Justin Chevrier66e554b2015-02-08 21:58:10 +0000484
485 /* Command Set SPI Speed */
Anastasia Klimchuk47e7d472021-04-30 14:10:04 +1000486 if (pickit2_set_spi_speed(pickit2_handle, spispeed_idx))
Anastasia Klimchuk1c9c73a2021-04-30 11:25:44 +1000487 goto init_err_cleanup_exit;
Justin Chevrier66e554b2015-02-08 21:58:10 +0000488
489 /* Command Set SPI Voltage */
490 msg_pdbg("Setting voltage to %i mV.\n", millivolt);
Anastasia Klimchuk47e7d472021-04-30 14:10:04 +1000491 if (pickit2_set_spi_voltage(pickit2_handle, millivolt) != 0)
Anastasia Klimchuk1c9c73a2021-04-30 11:25:44 +1000492 goto init_err_cleanup_exit;
Justin Chevrier66e554b2015-02-08 21:58:10 +0000493
494 /* Perform basic setup.
495 * Configure pin directions and logic levels, turn Vdd on, turn busy LED on and clear buffers. */
Angel Pons75d6ec62022-07-16 12:12:50 +0200496 if (pickit2_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, buf) != 0) {
Thomas Heijligenb221cd72019-04-05 15:08:35 +0200497 msg_perr("Command Setup failed!\n");
Anastasia Klimchuk1c9c73a2021-04-30 11:25:44 +1000498 goto init_err_cleanup_exit;
Justin Chevrier66e554b2015-02-08 21:58:10 +0000499 }
500
Anastasia Klimchuk47e7d472021-04-30 14:10:04 +1000501 if (register_shutdown(pickit2_shutdown, pickit2_data))
Anastasia Klimchuk1c9c73a2021-04-30 11:25:44 +1000502 goto init_err_cleanup_exit;
Justin Chevrier66e554b2015-02-08 21:58:10 +0000503 register_spi_master(&spi_master_pickit2);
504
505 return 0;
Anastasia Klimchuk1c9c73a2021-04-30 11:25:44 +1000506
507init_err_cleanup_exit:
Anastasia Klimchuk47e7d472021-04-30 14:10:04 +1000508 pickit2_shutdown(pickit2_data);
Anastasia Klimchuk1c9c73a2021-04-30 11:25:44 +1000509 return 1;
Justin Chevrier66e554b2015-02-08 21:58:10 +0000510}
Thomas Heijligencc853d82021-05-04 15:32:17 +0200511
512const struct programmer_entry programmer_pickit2_spi = {
513 .name = "pickit2_spi",
514 .type = USB,
515 .devs.dev = devs_pickit2_spi,
516 .init = pickit2_spi_init,
517 .map_flash_region = fallback_map,
518 .unmap_flash_region = fallback_unmap,
519 .delay = internal_delay,
520};