xref: /aosp_15_r20/external/flashrom/pickit2_spi.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
1*0d6140beSAndroid Build Coastguard Worker /*
2*0d6140beSAndroid Build Coastguard Worker  * This file is part of the flashrom project.
3*0d6140beSAndroid Build Coastguard Worker  *
4*0d6140beSAndroid Build Coastguard Worker  * Copyright (C) 2010 Carl-Daniel Hailfinger
5*0d6140beSAndroid Build Coastguard Worker  * Copyright (C) 2014 Justin Chevrier
6*0d6140beSAndroid Build Coastguard Worker  *
7*0d6140beSAndroid Build Coastguard Worker  * This program is free software; you can redistribute it and/or modify
8*0d6140beSAndroid Build Coastguard Worker  * it under the terms of the GNU General Public License as published by
9*0d6140beSAndroid Build Coastguard Worker  * the Free Software Foundation; version 2 of the License.
10*0d6140beSAndroid Build Coastguard Worker  *
11*0d6140beSAndroid Build Coastguard Worker  * This program is distributed in the hope that it will be useful,
12*0d6140beSAndroid Build Coastguard Worker  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*0d6140beSAndroid Build Coastguard Worker  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*0d6140beSAndroid Build Coastguard Worker  * GNU General Public License for more details.
15*0d6140beSAndroid Build Coastguard Worker  */
16*0d6140beSAndroid Build Coastguard Worker 
17*0d6140beSAndroid Build Coastguard Worker /*
18*0d6140beSAndroid Build Coastguard Worker  * Connections are as follows:
19*0d6140beSAndroid Build Coastguard Worker  *
20*0d6140beSAndroid Build Coastguard Worker  *      +------+-----+----------+
21*0d6140beSAndroid Build Coastguard Worker  *      | SPI  | Pin | PICkit2  |
22*0d6140beSAndroid Build Coastguard Worker  *      +------+-----+----------+
23*0d6140beSAndroid Build Coastguard Worker  *      | /CS  | 1   | VPP/MCLR |
24*0d6140beSAndroid Build Coastguard Worker  *      | VCC  | 2   | VDD      |
25*0d6140beSAndroid Build Coastguard Worker  *      | GND  | 3   | GND      |
26*0d6140beSAndroid Build Coastguard Worker  *      | MISO | 4   | PGD      |
27*0d6140beSAndroid Build Coastguard Worker  *      | SCLK | 5   | PDC      |
28*0d6140beSAndroid Build Coastguard Worker  *      | MOSI | 6   | AUX      |
29*0d6140beSAndroid Build Coastguard Worker  *      +------+-----+----------+
30*0d6140beSAndroid Build Coastguard Worker  *
31*0d6140beSAndroid Build Coastguard Worker  * Inspiration and some specifics of the interface came via the AVRDude
32*0d6140beSAndroid Build Coastguard Worker  * PICkit2 code: https://github.com/steve-m/avrdude/blob/master/pickit2.c
33*0d6140beSAndroid Build Coastguard Worker  */
34*0d6140beSAndroid Build Coastguard Worker 
35*0d6140beSAndroid Build Coastguard Worker #include <stdlib.h>
36*0d6140beSAndroid Build Coastguard Worker #include <stdio.h>
37*0d6140beSAndroid Build Coastguard Worker #include <string.h>
38*0d6140beSAndroid Build Coastguard Worker #include <limits.h>
39*0d6140beSAndroid Build Coastguard Worker #include <errno.h>
40*0d6140beSAndroid Build Coastguard Worker #include <libusb.h>
41*0d6140beSAndroid Build Coastguard Worker 
42*0d6140beSAndroid Build Coastguard Worker #include "flash.h"
43*0d6140beSAndroid Build Coastguard Worker #include "chipdrivers.h"
44*0d6140beSAndroid Build Coastguard Worker #include "programmer.h"
45*0d6140beSAndroid Build Coastguard Worker #include "spi.h"
46*0d6140beSAndroid Build Coastguard Worker 
47*0d6140beSAndroid Build Coastguard Worker static const struct dev_entry devs_pickit2_spi[] = {
48*0d6140beSAndroid Build Coastguard Worker 	{0x04D8, 0x0033, OK, "Microchip", "PICkit 2"},
49*0d6140beSAndroid Build Coastguard Worker 
50*0d6140beSAndroid Build Coastguard Worker 	{0}
51*0d6140beSAndroid Build Coastguard Worker };
52*0d6140beSAndroid Build Coastguard Worker 
53*0d6140beSAndroid Build Coastguard Worker struct pickit2_spi_data {
54*0d6140beSAndroid Build Coastguard Worker 	libusb_device_handle *pickit2_handle;
55*0d6140beSAndroid Build Coastguard Worker };
56*0d6140beSAndroid Build Coastguard Worker 
57*0d6140beSAndroid Build Coastguard Worker /* Default USB transaction timeout in ms */
58*0d6140beSAndroid Build Coastguard Worker #define DFLT_TIMEOUT            10000
59*0d6140beSAndroid Build Coastguard Worker 
60*0d6140beSAndroid Build Coastguard Worker #define CMD_LENGTH              64
61*0d6140beSAndroid Build Coastguard Worker #define ENDPOINT_OUT            0x01
62*0d6140beSAndroid Build Coastguard Worker #define ENDPOINT_IN             0x81
63*0d6140beSAndroid Build Coastguard Worker 
64*0d6140beSAndroid Build Coastguard Worker #define CMD_GET_VERSION         0x76
65*0d6140beSAndroid Build Coastguard Worker #define CMD_SET_VDD             0xA0
66*0d6140beSAndroid Build Coastguard Worker #define CMD_SET_VPP             0xA1
67*0d6140beSAndroid Build Coastguard Worker #define CMD_READ_VDD_VPP        0xA3
68*0d6140beSAndroid Build Coastguard Worker #define CMD_EXEC_SCRIPT         0xA6
69*0d6140beSAndroid Build Coastguard Worker #define CMD_CLR_DLOAD_BUFF      0xA7
70*0d6140beSAndroid Build Coastguard Worker #define CMD_DOWNLOAD_DATA       0xA8
71*0d6140beSAndroid Build Coastguard Worker #define CMD_CLR_ULOAD_BUFF      0xA9
72*0d6140beSAndroid Build Coastguard Worker #define CMD_UPLOAD_DATA         0xAA
73*0d6140beSAndroid Build Coastguard Worker #define CMD_END_OF_BUFFER       0xAD
74*0d6140beSAndroid Build Coastguard Worker 
75*0d6140beSAndroid Build Coastguard Worker #define SCR_SPI_READ_BUF        0xC5
76*0d6140beSAndroid Build Coastguard Worker #define SCR_SPI_WRITE_BUF       0xC6
77*0d6140beSAndroid Build Coastguard Worker #define SCR_SET_AUX             0xCF
78*0d6140beSAndroid Build Coastguard Worker #define SCR_LOOP                0xE9
79*0d6140beSAndroid Build Coastguard Worker #define SCR_SET_ICSP_CLK_PERIOD 0xEA
80*0d6140beSAndroid Build Coastguard Worker #define SCR_SET_PINS            0xF3
81*0d6140beSAndroid Build Coastguard Worker #define SCR_BUSY_LED_OFF        0xF4
82*0d6140beSAndroid Build Coastguard Worker #define SCR_BUSY_LED_ON         0xF5
83*0d6140beSAndroid Build Coastguard Worker #define SCR_MCLR_GND_OFF        0xF6
84*0d6140beSAndroid Build Coastguard Worker #define SCR_MCLR_GND_ON         0xF7
85*0d6140beSAndroid Build Coastguard Worker #define SCR_VPP_PWM_OFF         0xF8
86*0d6140beSAndroid Build Coastguard Worker #define SCR_VPP_PWM_ON          0xF9
87*0d6140beSAndroid Build Coastguard Worker #define SCR_VPP_OFF             0xFA
88*0d6140beSAndroid Build Coastguard Worker #define SCR_VPP_ON              0xFB
89*0d6140beSAndroid Build Coastguard Worker #define SCR_VDD_OFF             0xFE
90*0d6140beSAndroid Build Coastguard Worker #define SCR_VDD_ON              0xFF
91*0d6140beSAndroid Build Coastguard Worker 
pickit2_interrupt_transfer(libusb_device_handle * handle,unsigned char endpoint,unsigned char * data)92*0d6140beSAndroid Build Coastguard Worker static int pickit2_interrupt_transfer(libusb_device_handle *handle, unsigned char endpoint, unsigned char *data)
93*0d6140beSAndroid Build Coastguard Worker {
94*0d6140beSAndroid Build Coastguard Worker 	int transferred;
95*0d6140beSAndroid Build Coastguard Worker 	return libusb_interrupt_transfer(handle, endpoint, data, CMD_LENGTH, &transferred, DFLT_TIMEOUT);
96*0d6140beSAndroid Build Coastguard Worker }
97*0d6140beSAndroid Build Coastguard Worker 
pickit2_get_firmware_version(libusb_device_handle * pickit2_handle)98*0d6140beSAndroid Build Coastguard Worker static int pickit2_get_firmware_version(libusb_device_handle *pickit2_handle)
99*0d6140beSAndroid Build Coastguard Worker {
100*0d6140beSAndroid Build Coastguard Worker 	int ret;
101*0d6140beSAndroid Build Coastguard Worker 	uint8_t command[CMD_LENGTH] = {CMD_GET_VERSION, CMD_END_OF_BUFFER};
102*0d6140beSAndroid Build Coastguard Worker 
103*0d6140beSAndroid Build Coastguard Worker 	ret = pickit2_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, command);
104*0d6140beSAndroid Build Coastguard Worker 
105*0d6140beSAndroid Build Coastguard Worker 	if (ret != 0) {
106*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Command Get Firmware Version failed!\n");
107*0d6140beSAndroid Build Coastguard Worker 		return 1;
108*0d6140beSAndroid Build Coastguard Worker 	}
109*0d6140beSAndroid Build Coastguard Worker 
110*0d6140beSAndroid Build Coastguard Worker 	ret = pickit2_interrupt_transfer(pickit2_handle, ENDPOINT_IN, command);
111*0d6140beSAndroid Build Coastguard Worker 
112*0d6140beSAndroid Build Coastguard Worker 	if (ret != 0) {
113*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Command Get Firmware Version failed!\n");
114*0d6140beSAndroid Build Coastguard Worker 		return 1;
115*0d6140beSAndroid Build Coastguard Worker 	}
116*0d6140beSAndroid Build Coastguard Worker 
117*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("PICkit2 Firmware Version: %d.%d\n", (int)command[0], (int)command[1]);
118*0d6140beSAndroid Build Coastguard Worker 	return 0;
119*0d6140beSAndroid Build Coastguard Worker }
120*0d6140beSAndroid Build Coastguard Worker 
pickit2_set_spi_voltage(libusb_device_handle * pickit2_handle,int millivolt)121*0d6140beSAndroid Build Coastguard Worker static int pickit2_set_spi_voltage(libusb_device_handle *pickit2_handle, int millivolt)
122*0d6140beSAndroid Build Coastguard Worker {
123*0d6140beSAndroid Build Coastguard Worker 	double voltage_selector;
124*0d6140beSAndroid Build Coastguard Worker 	switch (millivolt) {
125*0d6140beSAndroid Build Coastguard Worker 	case 0:
126*0d6140beSAndroid Build Coastguard Worker 		/* Admittedly this one is an assumption. */
127*0d6140beSAndroid Build Coastguard Worker 		voltage_selector = 0;
128*0d6140beSAndroid Build Coastguard Worker 		break;
129*0d6140beSAndroid Build Coastguard Worker 	case 1800:
130*0d6140beSAndroid Build Coastguard Worker 		voltage_selector = 1.8;
131*0d6140beSAndroid Build Coastguard Worker 		break;
132*0d6140beSAndroid Build Coastguard Worker 	case 2500:
133*0d6140beSAndroid Build Coastguard Worker 		voltage_selector = 2.5;
134*0d6140beSAndroid Build Coastguard Worker 		break;
135*0d6140beSAndroid Build Coastguard Worker 	case 3500:
136*0d6140beSAndroid Build Coastguard Worker 		voltage_selector = 3.5;
137*0d6140beSAndroid Build Coastguard Worker 		break;
138*0d6140beSAndroid Build Coastguard Worker 	default:
139*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Unknown voltage %i mV! Aborting.\n", millivolt);
140*0d6140beSAndroid Build Coastguard Worker 		return 1;
141*0d6140beSAndroid Build Coastguard Worker 	}
142*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("Setting SPI voltage to %u.%03u V\n", millivolt / 1000,
143*0d6140beSAndroid Build Coastguard Worker 		 millivolt % 1000);
144*0d6140beSAndroid Build Coastguard Worker 
145*0d6140beSAndroid Build Coastguard Worker 	uint8_t command[CMD_LENGTH] = {
146*0d6140beSAndroid Build Coastguard Worker 		CMD_SET_VDD,
147*0d6140beSAndroid Build Coastguard Worker 		voltage_selector * 2048 + 672,
148*0d6140beSAndroid Build Coastguard Worker 		(voltage_selector * 2048 + 672) / 256,
149*0d6140beSAndroid Build Coastguard Worker 		voltage_selector * 36,
150*0d6140beSAndroid Build Coastguard Worker 		CMD_SET_VPP,
151*0d6140beSAndroid Build Coastguard Worker 		0x40,
152*0d6140beSAndroid Build Coastguard Worker 		voltage_selector * 18.61,
153*0d6140beSAndroid Build Coastguard Worker 		voltage_selector * 13,
154*0d6140beSAndroid Build Coastguard Worker 		CMD_END_OF_BUFFER
155*0d6140beSAndroid Build Coastguard Worker 	};
156*0d6140beSAndroid Build Coastguard Worker 	int ret = pickit2_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, command);
157*0d6140beSAndroid Build Coastguard Worker 
158*0d6140beSAndroid Build Coastguard Worker 	if (ret != 0) {
159*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Command Set Voltage failed!\n");
160*0d6140beSAndroid Build Coastguard Worker 		return 1;
161*0d6140beSAndroid Build Coastguard Worker 	}
162*0d6140beSAndroid Build Coastguard Worker 
163*0d6140beSAndroid Build Coastguard Worker 	return 0;
164*0d6140beSAndroid Build Coastguard Worker }
165*0d6140beSAndroid Build Coastguard Worker 
166*0d6140beSAndroid Build Coastguard Worker struct pickit2_spispeeds {
167*0d6140beSAndroid Build Coastguard Worker 	const char *const name;
168*0d6140beSAndroid Build Coastguard Worker 	const int speed;
169*0d6140beSAndroid Build Coastguard Worker };
170*0d6140beSAndroid Build Coastguard Worker 
171*0d6140beSAndroid Build Coastguard Worker static const struct pickit2_spispeeds spispeeds[] = {
172*0d6140beSAndroid Build Coastguard Worker 	{ "1M",		0x1 },
173*0d6140beSAndroid Build Coastguard Worker 	{ "500k",	0x2 },
174*0d6140beSAndroid Build Coastguard Worker 	{ "333k",	0x3 },
175*0d6140beSAndroid Build Coastguard Worker 	{ "250k",	0x4 },
176*0d6140beSAndroid Build Coastguard Worker 	{ NULL,		0x0 },
177*0d6140beSAndroid Build Coastguard Worker };
178*0d6140beSAndroid Build Coastguard Worker 
pickit2_set_spi_speed(libusb_device_handle * pickit2_handle,unsigned int spispeed_idx)179*0d6140beSAndroid Build Coastguard Worker static int pickit2_set_spi_speed(libusb_device_handle *pickit2_handle, unsigned int spispeed_idx)
180*0d6140beSAndroid Build Coastguard Worker {
181*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("SPI speed is %sHz\n", spispeeds[spispeed_idx].name);
182*0d6140beSAndroid Build Coastguard Worker 
183*0d6140beSAndroid Build Coastguard Worker 	uint8_t command[CMD_LENGTH] = {
184*0d6140beSAndroid Build Coastguard Worker 		CMD_EXEC_SCRIPT,
185*0d6140beSAndroid Build Coastguard Worker 		2,
186*0d6140beSAndroid Build Coastguard Worker 		SCR_SET_ICSP_CLK_PERIOD,
187*0d6140beSAndroid Build Coastguard Worker 		spispeed_idx,
188*0d6140beSAndroid Build Coastguard Worker 		CMD_END_OF_BUFFER
189*0d6140beSAndroid Build Coastguard Worker 	};
190*0d6140beSAndroid Build Coastguard Worker 
191*0d6140beSAndroid Build Coastguard Worker 	int ret = pickit2_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, command);
192*0d6140beSAndroid Build Coastguard Worker 
193*0d6140beSAndroid Build Coastguard Worker 	if (ret != 0) {
194*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Command Set SPI Speed failed!\n");
195*0d6140beSAndroid Build Coastguard Worker 		return 1;
196*0d6140beSAndroid Build Coastguard Worker 	}
197*0d6140beSAndroid Build Coastguard Worker 
198*0d6140beSAndroid Build Coastguard Worker 	return 0;
199*0d6140beSAndroid Build Coastguard Worker }
200*0d6140beSAndroid Build Coastguard Worker 
pickit2_spi_send_command(const struct flashctx * flash,unsigned int writecnt,unsigned int readcnt,const unsigned char * writearr,unsigned char * readarr)201*0d6140beSAndroid Build Coastguard Worker static int pickit2_spi_send_command(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
202*0d6140beSAndroid Build Coastguard Worker 				     const unsigned char *writearr, unsigned char *readarr)
203*0d6140beSAndroid Build Coastguard Worker {
204*0d6140beSAndroid Build Coastguard Worker 	struct pickit2_spi_data *pickit2_data = flash->mst->spi.data;
205*0d6140beSAndroid Build Coastguard Worker 	const unsigned int total_packetsize = writecnt + readcnt + 20;
206*0d6140beSAndroid Build Coastguard Worker 
207*0d6140beSAndroid Build Coastguard Worker 	/* Maximum number of bytes per transaction (including command overhead) is 64. Lets play it safe
208*0d6140beSAndroid Build Coastguard Worker 	 * and always assume the worst case scenario of 20 bytes command overhead.
209*0d6140beSAndroid Build Coastguard Worker 	 */
210*0d6140beSAndroid Build Coastguard Worker 	if (total_packetsize > CMD_LENGTH) {
211*0d6140beSAndroid Build Coastguard Worker 		msg_perr("\nTotal packetsize (%i) is greater than %i supported, aborting.\n",
212*0d6140beSAndroid Build Coastguard Worker 			 total_packetsize, CMD_LENGTH);
213*0d6140beSAndroid Build Coastguard Worker 		return 1;
214*0d6140beSAndroid Build Coastguard Worker 	}
215*0d6140beSAndroid Build Coastguard Worker 
216*0d6140beSAndroid Build Coastguard Worker 	uint8_t buf[CMD_LENGTH] = {CMD_DOWNLOAD_DATA, writecnt};
217*0d6140beSAndroid Build Coastguard Worker 	unsigned int i = 2;
218*0d6140beSAndroid Build Coastguard Worker 	for (; i < writecnt + 2; i++) {
219*0d6140beSAndroid Build Coastguard Worker 		buf[i] = writearr[i - 2];
220*0d6140beSAndroid Build Coastguard Worker 	}
221*0d6140beSAndroid Build Coastguard Worker 
222*0d6140beSAndroid Build Coastguard Worker 	buf[i++] = CMD_CLR_ULOAD_BUFF;
223*0d6140beSAndroid Build Coastguard Worker 	buf[i++] = CMD_EXEC_SCRIPT;
224*0d6140beSAndroid Build Coastguard Worker 
225*0d6140beSAndroid Build Coastguard Worker 	/* Determine script length based on number of bytes to be read or written */
226*0d6140beSAndroid Build Coastguard Worker 	if (writecnt == 1 && readcnt == 1)
227*0d6140beSAndroid Build Coastguard Worker 		buf[i++] = 7;
228*0d6140beSAndroid Build Coastguard Worker 	else if (writecnt == 1 || readcnt == 1)
229*0d6140beSAndroid Build Coastguard Worker 		buf[i++] = 10;
230*0d6140beSAndroid Build Coastguard Worker 	else
231*0d6140beSAndroid Build Coastguard Worker 		buf[i++] = 13;
232*0d6140beSAndroid Build Coastguard Worker 
233*0d6140beSAndroid Build Coastguard Worker 	/* Assert CS# */
234*0d6140beSAndroid Build Coastguard Worker 	buf[i++] = SCR_VPP_OFF;
235*0d6140beSAndroid Build Coastguard Worker 	buf[i++] = SCR_MCLR_GND_ON;
236*0d6140beSAndroid Build Coastguard Worker 
237*0d6140beSAndroid Build Coastguard Worker 	buf[i++] = SCR_SPI_WRITE_BUF;
238*0d6140beSAndroid Build Coastguard Worker 
239*0d6140beSAndroid Build Coastguard Worker 	if (writecnt > 1) {
240*0d6140beSAndroid Build Coastguard Worker 		buf[i++] = SCR_LOOP;
241*0d6140beSAndroid Build Coastguard Worker 		buf[i++] = 1; /* Loop back one instruction */
242*0d6140beSAndroid Build Coastguard Worker 		buf[i++] = writecnt - 1; /* Number of times to loop */
243*0d6140beSAndroid Build Coastguard Worker 	}
244*0d6140beSAndroid Build Coastguard Worker 
245*0d6140beSAndroid Build Coastguard Worker 	if (readcnt)
246*0d6140beSAndroid Build Coastguard Worker 		buf[i++] = SCR_SPI_READ_BUF;
247*0d6140beSAndroid Build Coastguard Worker 
248*0d6140beSAndroid Build Coastguard Worker 	if (readcnt > 1) {
249*0d6140beSAndroid Build Coastguard Worker 		buf[i++] = SCR_LOOP;
250*0d6140beSAndroid Build Coastguard Worker 		buf[i++] = 1; /* Loop back one instruction */
251*0d6140beSAndroid Build Coastguard Worker 		buf[i++] = readcnt - 1; /* Number of times to loop */
252*0d6140beSAndroid Build Coastguard Worker 	}
253*0d6140beSAndroid Build Coastguard Worker 
254*0d6140beSAndroid Build Coastguard Worker 	/* De-assert CS# */
255*0d6140beSAndroid Build Coastguard Worker 	buf[i++] = SCR_MCLR_GND_OFF;
256*0d6140beSAndroid Build Coastguard Worker 	buf[i++] = SCR_VPP_PWM_ON;
257*0d6140beSAndroid Build Coastguard Worker 	buf[i++] = SCR_VPP_ON;
258*0d6140beSAndroid Build Coastguard Worker 
259*0d6140beSAndroid Build Coastguard Worker 	buf[i++] = CMD_UPLOAD_DATA;
260*0d6140beSAndroid Build Coastguard Worker 	buf[i++] = CMD_END_OF_BUFFER;
261*0d6140beSAndroid Build Coastguard Worker 
262*0d6140beSAndroid Build Coastguard Worker 	int ret = pickit2_interrupt_transfer(pickit2_data->pickit2_handle, ENDPOINT_OUT, buf);
263*0d6140beSAndroid Build Coastguard Worker 
264*0d6140beSAndroid Build Coastguard Worker 	if (ret != 0) {
265*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Send SPI failed!\n");
266*0d6140beSAndroid Build Coastguard Worker 		return 1;
267*0d6140beSAndroid Build Coastguard Worker 	}
268*0d6140beSAndroid Build Coastguard Worker 
269*0d6140beSAndroid Build Coastguard Worker 	if (readcnt) {
270*0d6140beSAndroid Build Coastguard Worker 		int length = 0;
271*0d6140beSAndroid Build Coastguard Worker 		ret = libusb_interrupt_transfer(pickit2_data->pickit2_handle,
272*0d6140beSAndroid Build Coastguard Worker 					ENDPOINT_IN, buf, CMD_LENGTH, &length, DFLT_TIMEOUT);
273*0d6140beSAndroid Build Coastguard Worker 
274*0d6140beSAndroid Build Coastguard Worker 		if (length == 0 || ret != 0) {
275*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Receive SPI failed\n");
276*0d6140beSAndroid Build Coastguard Worker 			return 1;
277*0d6140beSAndroid Build Coastguard Worker 		}
278*0d6140beSAndroid Build Coastguard Worker 
279*0d6140beSAndroid Build Coastguard Worker 		/* First byte indicates number of bytes transferred from upload buffer */
280*0d6140beSAndroid Build Coastguard Worker 		if (buf[0] != readcnt) {
281*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Unexpected number of bytes transferred, expected %i, got %i!\n",
282*0d6140beSAndroid Build Coastguard Worker 				 readcnt, ret);
283*0d6140beSAndroid Build Coastguard Worker 			return 1;
284*0d6140beSAndroid Build Coastguard Worker 		}
285*0d6140beSAndroid Build Coastguard Worker 
286*0d6140beSAndroid Build Coastguard Worker 		/* Actual data starts at byte number two */
287*0d6140beSAndroid Build Coastguard Worker 		memcpy(readarr, &buf[1], readcnt);
288*0d6140beSAndroid Build Coastguard Worker 	}
289*0d6140beSAndroid Build Coastguard Worker 
290*0d6140beSAndroid Build Coastguard Worker 	return 0;
291*0d6140beSAndroid Build Coastguard Worker }
292*0d6140beSAndroid Build Coastguard Worker 
293*0d6140beSAndroid Build Coastguard Worker /* Copied from dediprog.c */
294*0d6140beSAndroid Build Coastguard Worker /* Might be useful for other USB devices as well. static for now. */
parse_voltage(char * voltage)295*0d6140beSAndroid Build Coastguard Worker static int parse_voltage(char *voltage)
296*0d6140beSAndroid Build Coastguard Worker {
297*0d6140beSAndroid Build Coastguard Worker 	char *tmp = NULL;
298*0d6140beSAndroid Build Coastguard Worker 	int i;
299*0d6140beSAndroid Build Coastguard Worker 	int millivolt = 0, fraction = 0;
300*0d6140beSAndroid Build Coastguard Worker 
301*0d6140beSAndroid Build Coastguard Worker 	if (!voltage || !strlen(voltage)) {
302*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Empty voltage= specified.\n");
303*0d6140beSAndroid Build Coastguard Worker 		return -1;
304*0d6140beSAndroid Build Coastguard Worker 	}
305*0d6140beSAndroid Build Coastguard Worker 	millivolt = (int)strtol(voltage, &tmp, 0);
306*0d6140beSAndroid Build Coastguard Worker 	voltage = tmp;
307*0d6140beSAndroid Build Coastguard Worker 	/* Handle "," and "." as decimal point. Everything after it is assumed
308*0d6140beSAndroid Build Coastguard Worker 	 * to be in decimal notation.
309*0d6140beSAndroid Build Coastguard Worker 	 */
310*0d6140beSAndroid Build Coastguard Worker 	if ((*voltage == '.') || (*voltage == ',')) {
311*0d6140beSAndroid Build Coastguard Worker 		voltage++;
312*0d6140beSAndroid Build Coastguard Worker 		for (i = 0; i < 3; i++) {
313*0d6140beSAndroid Build Coastguard Worker 			fraction *= 10;
314*0d6140beSAndroid Build Coastguard Worker 			/* Don't advance if the current character is invalid,
315*0d6140beSAndroid Build Coastguard Worker 			 * but continue multiplying.
316*0d6140beSAndroid Build Coastguard Worker 			 */
317*0d6140beSAndroid Build Coastguard Worker 			if ((*voltage < '0') || (*voltage > '9'))
318*0d6140beSAndroid Build Coastguard Worker 				continue;
319*0d6140beSAndroid Build Coastguard Worker 			fraction += *voltage - '0';
320*0d6140beSAndroid Build Coastguard Worker 			voltage++;
321*0d6140beSAndroid Build Coastguard Worker 		}
322*0d6140beSAndroid Build Coastguard Worker 		/* Throw away remaining digits. */
323*0d6140beSAndroid Build Coastguard Worker 		voltage += strspn(voltage, "0123456789");
324*0d6140beSAndroid Build Coastguard Worker 	}
325*0d6140beSAndroid Build Coastguard Worker 	/* The remaining string must be empty or "mV" or "V". */
326*0d6140beSAndroid Build Coastguard Worker 	tolower_string(voltage);
327*0d6140beSAndroid Build Coastguard Worker 
328*0d6140beSAndroid Build Coastguard Worker 	/* No unit or "V". */
329*0d6140beSAndroid Build Coastguard Worker 	if ((*voltage == '\0') || !strncmp(voltage, "v", 1)) {
330*0d6140beSAndroid Build Coastguard Worker 		millivolt *= 1000;
331*0d6140beSAndroid Build Coastguard Worker 		millivolt += fraction;
332*0d6140beSAndroid Build Coastguard Worker 	} else if (!strncmp(voltage, "mv", 2) ||
333*0d6140beSAndroid Build Coastguard Worker 		   !strncmp(voltage, "millivolt", 9)) {
334*0d6140beSAndroid Build Coastguard Worker 		/* No adjustment. fraction is discarded. */
335*0d6140beSAndroid Build Coastguard Worker 	} else {
336*0d6140beSAndroid Build Coastguard Worker 		/* Garbage at the end of the string. */
337*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Garbage voltage= specified.\n");
338*0d6140beSAndroid Build Coastguard Worker 		return -1;
339*0d6140beSAndroid Build Coastguard Worker 	}
340*0d6140beSAndroid Build Coastguard Worker 	return millivolt;
341*0d6140beSAndroid Build Coastguard Worker }
342*0d6140beSAndroid Build Coastguard Worker 
pickit2_shutdown(void * data)343*0d6140beSAndroid Build Coastguard Worker static int pickit2_shutdown(void *data)
344*0d6140beSAndroid Build Coastguard Worker {
345*0d6140beSAndroid Build Coastguard Worker 	struct pickit2_spi_data *pickit2_data = data;
346*0d6140beSAndroid Build Coastguard Worker 
347*0d6140beSAndroid Build Coastguard Worker 	/* Set all pins to float and turn voltages off */
348*0d6140beSAndroid Build Coastguard Worker 	uint8_t command[CMD_LENGTH] = {
349*0d6140beSAndroid Build Coastguard Worker 		CMD_EXEC_SCRIPT,
350*0d6140beSAndroid Build Coastguard Worker 		8,
351*0d6140beSAndroid Build Coastguard Worker 		SCR_SET_PINS,
352*0d6140beSAndroid Build Coastguard Worker 		3, /* Bit-0=1(PDC In), Bit-1=1(PGD In), Bit-2=0(PDC LL), Bit-3=0(PGD LL) */
353*0d6140beSAndroid Build Coastguard Worker 		SCR_SET_AUX,
354*0d6140beSAndroid Build Coastguard Worker 		1, /* Bit-0=1(Aux In), Bit-1=0(Aux LL) */
355*0d6140beSAndroid Build Coastguard Worker 		SCR_MCLR_GND_OFF,
356*0d6140beSAndroid Build Coastguard Worker 		SCR_VPP_OFF,
357*0d6140beSAndroid Build Coastguard Worker 		SCR_VDD_OFF,
358*0d6140beSAndroid Build Coastguard Worker 		SCR_BUSY_LED_OFF,
359*0d6140beSAndroid Build Coastguard Worker 		CMD_END_OF_BUFFER
360*0d6140beSAndroid Build Coastguard Worker 	};
361*0d6140beSAndroid Build Coastguard Worker 
362*0d6140beSAndroid Build Coastguard Worker 	int ret = pickit2_interrupt_transfer(pickit2_data->pickit2_handle, ENDPOINT_OUT, command);
363*0d6140beSAndroid Build Coastguard Worker 
364*0d6140beSAndroid Build Coastguard Worker 	if (ret != 0) {
365*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Command Shutdown failed!\n");
366*0d6140beSAndroid Build Coastguard Worker 		ret = 1;
367*0d6140beSAndroid Build Coastguard Worker 	}
368*0d6140beSAndroid Build Coastguard Worker 	if (libusb_release_interface(pickit2_data->pickit2_handle, 0) != 0) {
369*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Could not release USB interface!\n");
370*0d6140beSAndroid Build Coastguard Worker 		ret = 1;
371*0d6140beSAndroid Build Coastguard Worker 	}
372*0d6140beSAndroid Build Coastguard Worker 	libusb_close(pickit2_data->pickit2_handle);
373*0d6140beSAndroid Build Coastguard Worker 	libusb_exit(NULL);
374*0d6140beSAndroid Build Coastguard Worker 
375*0d6140beSAndroid Build Coastguard Worker 	free(data);
376*0d6140beSAndroid Build Coastguard Worker 	return ret;
377*0d6140beSAndroid Build Coastguard Worker }
378*0d6140beSAndroid Build Coastguard Worker 
379*0d6140beSAndroid Build Coastguard Worker static const struct spi_master spi_master_pickit2 = {
380*0d6140beSAndroid Build Coastguard Worker 	.max_data_read	= 40,
381*0d6140beSAndroid Build Coastguard Worker 	.max_data_write	= 40,
382*0d6140beSAndroid Build Coastguard Worker 	.command	= pickit2_spi_send_command,
383*0d6140beSAndroid Build Coastguard Worker 	.read		= default_spi_read,
384*0d6140beSAndroid Build Coastguard Worker 	.write_256	= default_spi_write_256,
385*0d6140beSAndroid Build Coastguard Worker 	.shutdown	= pickit2_shutdown,
386*0d6140beSAndroid Build Coastguard Worker };
387*0d6140beSAndroid Build Coastguard Worker 
pickit2_spi_init(const struct programmer_cfg * cfg)388*0d6140beSAndroid Build Coastguard Worker static int pickit2_spi_init(const struct programmer_cfg *cfg)
389*0d6140beSAndroid Build Coastguard Worker {
390*0d6140beSAndroid Build Coastguard Worker 	uint8_t buf[CMD_LENGTH] = {
391*0d6140beSAndroid Build Coastguard Worker 		CMD_EXEC_SCRIPT,
392*0d6140beSAndroid Build Coastguard Worker 		10,			/* Script length */
393*0d6140beSAndroid Build Coastguard Worker 		SCR_SET_PINS,
394*0d6140beSAndroid Build Coastguard Worker 		2, /* Bit-0=0(PDC Out), Bit-1=1(PGD In), Bit-2=0(PDC LL), Bit-3=0(PGD LL) */
395*0d6140beSAndroid Build Coastguard Worker 		SCR_SET_AUX,
396*0d6140beSAndroid Build Coastguard Worker 		0, /* Bit-0=0(Aux Out), Bit-1=0(Aux LL) */
397*0d6140beSAndroid Build Coastguard Worker 		SCR_VDD_ON,
398*0d6140beSAndroid Build Coastguard Worker 		SCR_MCLR_GND_OFF,	/* Let CS# float */
399*0d6140beSAndroid Build Coastguard Worker 		SCR_VPP_PWM_ON,
400*0d6140beSAndroid Build Coastguard Worker 		SCR_VPP_ON,		/* Pull CS# high */
401*0d6140beSAndroid Build Coastguard Worker 		SCR_BUSY_LED_ON,
402*0d6140beSAndroid Build Coastguard Worker 		CMD_CLR_DLOAD_BUFF,
403*0d6140beSAndroid Build Coastguard Worker 		CMD_CLR_ULOAD_BUFF,
404*0d6140beSAndroid Build Coastguard Worker 		CMD_END_OF_BUFFER
405*0d6140beSAndroid Build Coastguard Worker 	};
406*0d6140beSAndroid Build Coastguard Worker 
407*0d6140beSAndroid Build Coastguard Worker 	libusb_device_handle *pickit2_handle;
408*0d6140beSAndroid Build Coastguard Worker 	struct pickit2_spi_data *pickit2_data;
409*0d6140beSAndroid Build Coastguard Worker 	int spispeed_idx = 0;
410*0d6140beSAndroid Build Coastguard Worker 	char *param_str;
411*0d6140beSAndroid Build Coastguard Worker 
412*0d6140beSAndroid Build Coastguard Worker 	param_str = extract_programmer_param_str(cfg, "spispeed");
413*0d6140beSAndroid Build Coastguard Worker 	if (param_str != NULL) {
414*0d6140beSAndroid Build Coastguard Worker 		int i = 0;
415*0d6140beSAndroid Build Coastguard Worker 		for (; spispeeds[i].name; i++) {
416*0d6140beSAndroid Build Coastguard Worker 			if (strcasecmp(spispeeds[i].name, param_str) == 0) {
417*0d6140beSAndroid Build Coastguard Worker 				spispeed_idx = i;
418*0d6140beSAndroid Build Coastguard Worker 				break;
419*0d6140beSAndroid Build Coastguard Worker 			}
420*0d6140beSAndroid Build Coastguard Worker 		}
421*0d6140beSAndroid Build Coastguard Worker 		if (spispeeds[i].name == NULL) {
422*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: Invalid 'spispeed' value.\n");
423*0d6140beSAndroid Build Coastguard Worker 			free(param_str);
424*0d6140beSAndroid Build Coastguard Worker 			return 1;
425*0d6140beSAndroid Build Coastguard Worker 		}
426*0d6140beSAndroid Build Coastguard Worker 		free(param_str);
427*0d6140beSAndroid Build Coastguard Worker 	}
428*0d6140beSAndroid Build Coastguard Worker 
429*0d6140beSAndroid Build Coastguard Worker 	int millivolt = 3500;
430*0d6140beSAndroid Build Coastguard Worker 	param_str = extract_programmer_param_str(cfg, "voltage");
431*0d6140beSAndroid Build Coastguard Worker 	if (param_str != NULL) {
432*0d6140beSAndroid Build Coastguard Worker 		millivolt = parse_voltage(param_str);
433*0d6140beSAndroid Build Coastguard Worker 		free(param_str);
434*0d6140beSAndroid Build Coastguard Worker 		if (millivolt < 0)
435*0d6140beSAndroid Build Coastguard Worker 			return 1;
436*0d6140beSAndroid Build Coastguard Worker 	}
437*0d6140beSAndroid Build Coastguard Worker 
438*0d6140beSAndroid Build Coastguard Worker 	if (libusb_init(NULL) < 0) {
439*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Couldn't initialize libusb!\n");
440*0d6140beSAndroid Build Coastguard Worker 		return -1;
441*0d6140beSAndroid Build Coastguard Worker 	}
442*0d6140beSAndroid Build Coastguard Worker 
443*0d6140beSAndroid Build Coastguard Worker #if LIBUSB_API_VERSION < 0x01000106
444*0d6140beSAndroid Build Coastguard Worker 	libusb_set_debug(NULL, 3);
445*0d6140beSAndroid Build Coastguard Worker #else
446*0d6140beSAndroid Build Coastguard Worker 	libusb_set_option(NULL, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO);
447*0d6140beSAndroid Build Coastguard Worker #endif
448*0d6140beSAndroid Build Coastguard Worker 
449*0d6140beSAndroid Build Coastguard Worker 	const uint16_t vid = devs_pickit2_spi[0].vendor_id;
450*0d6140beSAndroid Build Coastguard Worker 	const uint16_t pid = devs_pickit2_spi[0].device_id;
451*0d6140beSAndroid Build Coastguard Worker 	pickit2_handle = libusb_open_device_with_vid_pid(NULL, vid, pid);
452*0d6140beSAndroid Build Coastguard Worker 	if (pickit2_handle == NULL) {
453*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Could not open device PICkit2!\n");
454*0d6140beSAndroid Build Coastguard Worker 		libusb_exit(NULL);
455*0d6140beSAndroid Build Coastguard Worker 		return 1;
456*0d6140beSAndroid Build Coastguard Worker 	}
457*0d6140beSAndroid Build Coastguard Worker 
458*0d6140beSAndroid Build Coastguard Worker 	if (libusb_set_configuration(pickit2_handle, 1) != 0) {
459*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Could not set USB device configuration.\n");
460*0d6140beSAndroid Build Coastguard Worker 		libusb_close(pickit2_handle);
461*0d6140beSAndroid Build Coastguard Worker 		libusb_exit(NULL);
462*0d6140beSAndroid Build Coastguard Worker 		return 1;
463*0d6140beSAndroid Build Coastguard Worker 	}
464*0d6140beSAndroid Build Coastguard Worker 	if (libusb_claim_interface(pickit2_handle, 0) != 0) {
465*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Could not claim USB device interface\n");
466*0d6140beSAndroid Build Coastguard Worker 		libusb_close(pickit2_handle);
467*0d6140beSAndroid Build Coastguard Worker 		libusb_exit(NULL);
468*0d6140beSAndroid Build Coastguard Worker 		return 1;
469*0d6140beSAndroid Build Coastguard Worker 	}
470*0d6140beSAndroid Build Coastguard Worker 
471*0d6140beSAndroid Build Coastguard Worker 	pickit2_data = calloc(1, sizeof(*pickit2_data));
472*0d6140beSAndroid Build Coastguard Worker 	if (!pickit2_data) {
473*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Unable to allocate space for SPI master data\n");
474*0d6140beSAndroid Build Coastguard Worker 		libusb_close(pickit2_handle);
475*0d6140beSAndroid Build Coastguard Worker 		libusb_exit(NULL);
476*0d6140beSAndroid Build Coastguard Worker 		return 1;
477*0d6140beSAndroid Build Coastguard Worker 	}
478*0d6140beSAndroid Build Coastguard Worker 	pickit2_data->pickit2_handle = pickit2_handle;
479*0d6140beSAndroid Build Coastguard Worker 
480*0d6140beSAndroid Build Coastguard Worker 	if (pickit2_get_firmware_version(pickit2_handle))
481*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
482*0d6140beSAndroid Build Coastguard Worker 
483*0d6140beSAndroid Build Coastguard Worker 	/* Command Set SPI Speed */
484*0d6140beSAndroid Build Coastguard Worker 	if (pickit2_set_spi_speed(pickit2_handle, spispeed_idx))
485*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
486*0d6140beSAndroid Build Coastguard Worker 
487*0d6140beSAndroid Build Coastguard Worker 	/* Command Set SPI Voltage */
488*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("Setting voltage to %i mV.\n", millivolt);
489*0d6140beSAndroid Build Coastguard Worker 	if (pickit2_set_spi_voltage(pickit2_handle, millivolt) != 0)
490*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
491*0d6140beSAndroid Build Coastguard Worker 
492*0d6140beSAndroid Build Coastguard Worker 	/* Perform basic setup.
493*0d6140beSAndroid Build Coastguard Worker 	 * Configure pin directions and logic levels, turn Vdd on, turn busy LED on and clear buffers. */
494*0d6140beSAndroid Build Coastguard Worker 	if (pickit2_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, buf) != 0) {
495*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Command Setup failed!\n");
496*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
497*0d6140beSAndroid Build Coastguard Worker 	}
498*0d6140beSAndroid Build Coastguard Worker 
499*0d6140beSAndroid Build Coastguard Worker 	return register_spi_master(&spi_master_pickit2, pickit2_data);
500*0d6140beSAndroid Build Coastguard Worker 
501*0d6140beSAndroid Build Coastguard Worker init_err_cleanup_exit:
502*0d6140beSAndroid Build Coastguard Worker 	pickit2_shutdown(pickit2_data);
503*0d6140beSAndroid Build Coastguard Worker 	return 1;
504*0d6140beSAndroid Build Coastguard Worker }
505*0d6140beSAndroid Build Coastguard Worker 
506*0d6140beSAndroid Build Coastguard Worker const struct programmer_entry programmer_pickit2_spi = {
507*0d6140beSAndroid Build Coastguard Worker 	.name			= "pickit2_spi",
508*0d6140beSAndroid Build Coastguard Worker 	.type			= USB,
509*0d6140beSAndroid Build Coastguard Worker 	.devs.dev		= devs_pickit2_spi,
510*0d6140beSAndroid Build Coastguard Worker 	.init			= pickit2_spi_init,
511*0d6140beSAndroid Build Coastguard Worker };
512