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) 2022 Nicholas Chin <[email protected]>
5*0d6140beSAndroid Build Coastguard Worker *
6*0d6140beSAndroid Build Coastguard Worker * This program is free software; you can redistribute it and/or modify
7*0d6140beSAndroid Build Coastguard Worker * it under the terms of the GNU General Public License as published by
8*0d6140beSAndroid Build Coastguard Worker * the Free Software Foundation; either version 2 of the License, or
9*0d6140beSAndroid Build Coastguard Worker * (at your option) any later version.
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 #include <string.h>
18*0d6140beSAndroid Build Coastguard Worker #include <stdlib.h>
19*0d6140beSAndroid Build Coastguard Worker #include <libusb.h>
20*0d6140beSAndroid Build Coastguard Worker #include "platform.h"
21*0d6140beSAndroid Build Coastguard Worker #include "programmer.h"
22*0d6140beSAndroid Build Coastguard Worker #include "flash.h"
23*0d6140beSAndroid Build Coastguard Worker
24*0d6140beSAndroid Build Coastguard Worker #define CH347_CMD_SPI_SET_CFG 0xC0
25*0d6140beSAndroid Build Coastguard Worker #define CH347_CMD_SPI_CS_CTRL 0xC1
26*0d6140beSAndroid Build Coastguard Worker #define CH347_CMD_SPI_OUT_IN 0xC2
27*0d6140beSAndroid Build Coastguard Worker #define CH347_CMD_SPI_IN 0xC3
28*0d6140beSAndroid Build Coastguard Worker #define CH347_CMD_SPI_OUT 0xC4
29*0d6140beSAndroid Build Coastguard Worker #define CH347_CMD_SPI_GET_CFG 0xCA
30*0d6140beSAndroid Build Coastguard Worker
31*0d6140beSAndroid Build Coastguard Worker #define CH347_CS_ASSERT 0x00
32*0d6140beSAndroid Build Coastguard Worker #define CH347_CS_DEASSERT 0x40
33*0d6140beSAndroid Build Coastguard Worker #define CH347_CS_CHANGE 0x80
34*0d6140beSAndroid Build Coastguard Worker #define CH347_CS_IGNORE 0x00
35*0d6140beSAndroid Build Coastguard Worker
36*0d6140beSAndroid Build Coastguard Worker #define WRITE_EP 0x06
37*0d6140beSAndroid Build Coastguard Worker #define READ_EP 0x86
38*0d6140beSAndroid Build Coastguard Worker
39*0d6140beSAndroid Build Coastguard Worker #define CH347T_IFACE 2
40*0d6140beSAndroid Build Coastguard Worker #define CH347F_IFACE 4
41*0d6140beSAndroid Build Coastguard Worker
42*0d6140beSAndroid Build Coastguard Worker /* The USB descriptor says the max transfer size is 512 bytes, but the
43*0d6140beSAndroid Build Coastguard Worker * vendor driver only seems to transfer a maximum of 510 bytes at once,
44*0d6140beSAndroid Build Coastguard Worker * leaving 507 bytes for data as the command + length take up 3 bytes
45*0d6140beSAndroid Build Coastguard Worker */
46*0d6140beSAndroid Build Coastguard Worker #define CH347_PACKET_SIZE 510
47*0d6140beSAndroid Build Coastguard Worker #define CH347_MAX_DATA_LEN (CH347_PACKET_SIZE - 3)
48*0d6140beSAndroid Build Coastguard Worker
49*0d6140beSAndroid Build Coastguard Worker struct ch347_spi_data {
50*0d6140beSAndroid Build Coastguard Worker struct libusb_device_handle *handle;
51*0d6140beSAndroid Build Coastguard Worker int interface;
52*0d6140beSAndroid Build Coastguard Worker };
53*0d6140beSAndroid Build Coastguard Worker
54*0d6140beSAndroid Build Coastguard Worker struct device_speeds {
55*0d6140beSAndroid Build Coastguard Worker const char *name;
56*0d6140beSAndroid Build Coastguard Worker const int divisor;
57*0d6140beSAndroid Build Coastguard Worker };
58*0d6140beSAndroid Build Coastguard Worker
59*0d6140beSAndroid Build Coastguard Worker /* TODO: Add support for HID mode */
60*0d6140beSAndroid Build Coastguard Worker static const struct dev_entry devs_ch347_spi[] = {
61*0d6140beSAndroid Build Coastguard Worker {0x1A86, 0x55DB, OK, "QinHeng Electronics", "USB To UART+SPI+I2C"}, /* CH347T */
62*0d6140beSAndroid Build Coastguard Worker {0x1A86, 0x55DE, OK, "QinHeng Electronics", "USB To UART+SPI+I2C"}, /* CH347F */
63*0d6140beSAndroid Build Coastguard Worker {0}
64*0d6140beSAndroid Build Coastguard Worker };
65*0d6140beSAndroid Build Coastguard Worker
66*0d6140beSAndroid Build Coastguard Worker static int ch347_interface[] = {
67*0d6140beSAndroid Build Coastguard Worker CH347T_IFACE,
68*0d6140beSAndroid Build Coastguard Worker CH347F_IFACE,
69*0d6140beSAndroid Build Coastguard Worker };
70*0d6140beSAndroid Build Coastguard Worker
71*0d6140beSAndroid Build Coastguard Worker static const struct device_speeds spispeeds[] = {
72*0d6140beSAndroid Build Coastguard Worker {"60M", 0},
73*0d6140beSAndroid Build Coastguard Worker {"30M", 1},
74*0d6140beSAndroid Build Coastguard Worker {"15M", 2},
75*0d6140beSAndroid Build Coastguard Worker {"7.5M", 3},
76*0d6140beSAndroid Build Coastguard Worker {"3.75M", 4},
77*0d6140beSAndroid Build Coastguard Worker {"1.875M", 5},
78*0d6140beSAndroid Build Coastguard Worker {"937.5K", 6},
79*0d6140beSAndroid Build Coastguard Worker {"468.75K", 7},
80*0d6140beSAndroid Build Coastguard Worker {NULL, 0}
81*0d6140beSAndroid Build Coastguard Worker };
82*0d6140beSAndroid Build Coastguard Worker
ch347_spi_shutdown(void * data)83*0d6140beSAndroid Build Coastguard Worker static int ch347_spi_shutdown(void *data)
84*0d6140beSAndroid Build Coastguard Worker {
85*0d6140beSAndroid Build Coastguard Worker struct ch347_spi_data *ch347_data = data;
86*0d6140beSAndroid Build Coastguard Worker int spi_interface = ch347_data->interface;
87*0d6140beSAndroid Build Coastguard Worker libusb_release_interface(ch347_data->handle, spi_interface);
88*0d6140beSAndroid Build Coastguard Worker libusb_attach_kernel_driver(ch347_data->handle, spi_interface);
89*0d6140beSAndroid Build Coastguard Worker libusb_close(ch347_data->handle);
90*0d6140beSAndroid Build Coastguard Worker libusb_exit(NULL);
91*0d6140beSAndroid Build Coastguard Worker free(data);
92*0d6140beSAndroid Build Coastguard Worker return 0;
93*0d6140beSAndroid Build Coastguard Worker }
94*0d6140beSAndroid Build Coastguard Worker
ch347_cs_control(struct ch347_spi_data * ch347_data,uint8_t cs1,uint8_t cs2)95*0d6140beSAndroid Build Coastguard Worker static int ch347_cs_control(struct ch347_spi_data *ch347_data, uint8_t cs1, uint8_t cs2)
96*0d6140beSAndroid Build Coastguard Worker {
97*0d6140beSAndroid Build Coastguard Worker uint8_t cmd[13] = {
98*0d6140beSAndroid Build Coastguard Worker [0] = CH347_CMD_SPI_CS_CTRL,
99*0d6140beSAndroid Build Coastguard Worker /* payload length, uint16 LSB: 10 */
100*0d6140beSAndroid Build Coastguard Worker [1] = 10,
101*0d6140beSAndroid Build Coastguard Worker [3] = cs1,
102*0d6140beSAndroid Build Coastguard Worker [8] = cs2
103*0d6140beSAndroid Build Coastguard Worker };
104*0d6140beSAndroid Build Coastguard Worker
105*0d6140beSAndroid Build Coastguard Worker int32_t ret = libusb_bulk_transfer(ch347_data->handle, WRITE_EP, cmd, sizeof(cmd), NULL, 1000);
106*0d6140beSAndroid Build Coastguard Worker if (ret < 0) {
107*0d6140beSAndroid Build Coastguard Worker msg_perr("Could not change CS!\n");
108*0d6140beSAndroid Build Coastguard Worker return -1;
109*0d6140beSAndroid Build Coastguard Worker }
110*0d6140beSAndroid Build Coastguard Worker return 0;
111*0d6140beSAndroid Build Coastguard Worker }
112*0d6140beSAndroid Build Coastguard Worker
113*0d6140beSAndroid Build Coastguard Worker
ch347_write(struct ch347_spi_data * ch347_data,unsigned int writecnt,const uint8_t * writearr)114*0d6140beSAndroid Build Coastguard Worker static int ch347_write(struct ch347_spi_data *ch347_data, unsigned int writecnt, const uint8_t *writearr)
115*0d6140beSAndroid Build Coastguard Worker {
116*0d6140beSAndroid Build Coastguard Worker unsigned int data_len;
117*0d6140beSAndroid Build Coastguard Worker int packet_len;
118*0d6140beSAndroid Build Coastguard Worker int transferred;
119*0d6140beSAndroid Build Coastguard Worker int ret;
120*0d6140beSAndroid Build Coastguard Worker uint8_t resp_buf[4] = {0};
121*0d6140beSAndroid Build Coastguard Worker uint8_t buffer[CH347_PACKET_SIZE] = {0};
122*0d6140beSAndroid Build Coastguard Worker unsigned int bytes_written = 0;
123*0d6140beSAndroid Build Coastguard Worker
124*0d6140beSAndroid Build Coastguard Worker while (bytes_written < writecnt) {
125*0d6140beSAndroid Build Coastguard Worker data_len = min(CH347_MAX_DATA_LEN, writecnt - bytes_written );
126*0d6140beSAndroid Build Coastguard Worker packet_len = data_len + 3;
127*0d6140beSAndroid Build Coastguard Worker
128*0d6140beSAndroid Build Coastguard Worker buffer[0] = CH347_CMD_SPI_OUT;
129*0d6140beSAndroid Build Coastguard Worker buffer[1] = (data_len) & 0xFF;
130*0d6140beSAndroid Build Coastguard Worker buffer[2] = ((data_len) & 0xFF00) >> 8;
131*0d6140beSAndroid Build Coastguard Worker memcpy(buffer + 3, writearr + bytes_written, data_len);
132*0d6140beSAndroid Build Coastguard Worker
133*0d6140beSAndroid Build Coastguard Worker ret = libusb_bulk_transfer(ch347_data->handle, WRITE_EP, buffer, packet_len, &transferred, 1000);
134*0d6140beSAndroid Build Coastguard Worker if (ret < 0 || transferred != packet_len) {
135*0d6140beSAndroid Build Coastguard Worker msg_perr("Could not send write command\n");
136*0d6140beSAndroid Build Coastguard Worker return -1;
137*0d6140beSAndroid Build Coastguard Worker }
138*0d6140beSAndroid Build Coastguard Worker
139*0d6140beSAndroid Build Coastguard Worker ret = libusb_bulk_transfer(ch347_data->handle, READ_EP, resp_buf, sizeof(resp_buf), NULL, 1000);
140*0d6140beSAndroid Build Coastguard Worker if (ret < 0) {
141*0d6140beSAndroid Build Coastguard Worker msg_perr("Could not receive write command response\n");
142*0d6140beSAndroid Build Coastguard Worker return -1;
143*0d6140beSAndroid Build Coastguard Worker }
144*0d6140beSAndroid Build Coastguard Worker bytes_written += data_len;
145*0d6140beSAndroid Build Coastguard Worker }
146*0d6140beSAndroid Build Coastguard Worker return 0;
147*0d6140beSAndroid Build Coastguard Worker }
148*0d6140beSAndroid Build Coastguard Worker
ch347_read(struct ch347_spi_data * ch347_data,unsigned int readcnt,uint8_t * readarr)149*0d6140beSAndroid Build Coastguard Worker static int ch347_read(struct ch347_spi_data *ch347_data, unsigned int readcnt, uint8_t *readarr)
150*0d6140beSAndroid Build Coastguard Worker {
151*0d6140beSAndroid Build Coastguard Worker uint8_t *read_ptr = readarr;
152*0d6140beSAndroid Build Coastguard Worker int ret;
153*0d6140beSAndroid Build Coastguard Worker int transferred;
154*0d6140beSAndroid Build Coastguard Worker unsigned int bytes_read = 0;
155*0d6140beSAndroid Build Coastguard Worker uint8_t buffer[CH347_PACKET_SIZE] = {0};
156*0d6140beSAndroid Build Coastguard Worker uint8_t command_buf[7] = {
157*0d6140beSAndroid Build Coastguard Worker [0] = CH347_CMD_SPI_IN,
158*0d6140beSAndroid Build Coastguard Worker [1] = 4,
159*0d6140beSAndroid Build Coastguard Worker [2] = 0,
160*0d6140beSAndroid Build Coastguard Worker [3] = readcnt & 0xFF,
161*0d6140beSAndroid Build Coastguard Worker [4] = (readcnt & 0xFF00) >> 8,
162*0d6140beSAndroid Build Coastguard Worker [5] = (readcnt & 0xFF0000) >> 16,
163*0d6140beSAndroid Build Coastguard Worker [6] = (readcnt & 0xFF000000) >> 24
164*0d6140beSAndroid Build Coastguard Worker };
165*0d6140beSAndroid Build Coastguard Worker
166*0d6140beSAndroid Build Coastguard Worker ret = libusb_bulk_transfer(ch347_data->handle, WRITE_EP, command_buf, sizeof(command_buf), &transferred, 1000);
167*0d6140beSAndroid Build Coastguard Worker if (ret < 0 || transferred != sizeof(command_buf)) {
168*0d6140beSAndroid Build Coastguard Worker msg_perr("Could not send read command\n");
169*0d6140beSAndroid Build Coastguard Worker return -1;
170*0d6140beSAndroid Build Coastguard Worker }
171*0d6140beSAndroid Build Coastguard Worker
172*0d6140beSAndroid Build Coastguard Worker while (bytes_read < readcnt) {
173*0d6140beSAndroid Build Coastguard Worker ret = libusb_bulk_transfer(ch347_data->handle, READ_EP, buffer, CH347_PACKET_SIZE, &transferred, 1000);
174*0d6140beSAndroid Build Coastguard Worker if (ret < 0) {
175*0d6140beSAndroid Build Coastguard Worker msg_perr("Could not read data\n");
176*0d6140beSAndroid Build Coastguard Worker return -1;
177*0d6140beSAndroid Build Coastguard Worker }
178*0d6140beSAndroid Build Coastguard Worker if (transferred > CH347_PACKET_SIZE) {
179*0d6140beSAndroid Build Coastguard Worker msg_perr("libusb bug: bytes received overflowed buffer\n");
180*0d6140beSAndroid Build Coastguard Worker return -1;
181*0d6140beSAndroid Build Coastguard Worker }
182*0d6140beSAndroid Build Coastguard Worker /* Response: u8 command, u16 data length, then the data that was read */
183*0d6140beSAndroid Build Coastguard Worker if (transferred < 3) {
184*0d6140beSAndroid Build Coastguard Worker msg_perr("CH347 returned an invalid response to read command\n");
185*0d6140beSAndroid Build Coastguard Worker return -1;
186*0d6140beSAndroid Build Coastguard Worker }
187*0d6140beSAndroid Build Coastguard Worker int ch347_data_length = read_le16(buffer, 1);
188*0d6140beSAndroid Build Coastguard Worker if (transferred - 3 < ch347_data_length) {
189*0d6140beSAndroid Build Coastguard Worker msg_perr("CH347 returned less data than data length header indicates\n");
190*0d6140beSAndroid Build Coastguard Worker return -1;
191*0d6140beSAndroid Build Coastguard Worker }
192*0d6140beSAndroid Build Coastguard Worker bytes_read += ch347_data_length;
193*0d6140beSAndroid Build Coastguard Worker if (bytes_read > readcnt) {
194*0d6140beSAndroid Build Coastguard Worker msg_perr("CH347 returned more bytes than requested\n");
195*0d6140beSAndroid Build Coastguard Worker return -1;
196*0d6140beSAndroid Build Coastguard Worker }
197*0d6140beSAndroid Build Coastguard Worker memcpy(read_ptr, buffer + 3, ch347_data_length);
198*0d6140beSAndroid Build Coastguard Worker read_ptr += ch347_data_length;
199*0d6140beSAndroid Build Coastguard Worker }
200*0d6140beSAndroid Build Coastguard Worker return 0;
201*0d6140beSAndroid Build Coastguard Worker }
202*0d6140beSAndroid Build Coastguard Worker
ch347_spi_send_command(const struct flashctx * flash,unsigned int writecnt,unsigned int readcnt,const unsigned char * writearr,unsigned char * readarr)203*0d6140beSAndroid Build Coastguard Worker static int ch347_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
204*0d6140beSAndroid Build Coastguard Worker unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr)
205*0d6140beSAndroid Build Coastguard Worker {
206*0d6140beSAndroid Build Coastguard Worker struct ch347_spi_data *ch347_data = flash->mst->spi.data;
207*0d6140beSAndroid Build Coastguard Worker int ret = 0;
208*0d6140beSAndroid Build Coastguard Worker
209*0d6140beSAndroid Build Coastguard Worker ch347_cs_control(ch347_data, CH347_CS_ASSERT | CH347_CS_CHANGE, CH347_CS_IGNORE);
210*0d6140beSAndroid Build Coastguard Worker if (writecnt) {
211*0d6140beSAndroid Build Coastguard Worker ret = ch347_write(ch347_data, writecnt, writearr);
212*0d6140beSAndroid Build Coastguard Worker if (ret < 0) {
213*0d6140beSAndroid Build Coastguard Worker msg_perr("CH347 write error\n");
214*0d6140beSAndroid Build Coastguard Worker return -1;
215*0d6140beSAndroid Build Coastguard Worker }
216*0d6140beSAndroid Build Coastguard Worker }
217*0d6140beSAndroid Build Coastguard Worker if (readcnt) {
218*0d6140beSAndroid Build Coastguard Worker ret = ch347_read(ch347_data, readcnt, readarr);
219*0d6140beSAndroid Build Coastguard Worker if (ret < 0) {
220*0d6140beSAndroid Build Coastguard Worker msg_perr("CH347 read error\n");
221*0d6140beSAndroid Build Coastguard Worker return -1;
222*0d6140beSAndroid Build Coastguard Worker }
223*0d6140beSAndroid Build Coastguard Worker }
224*0d6140beSAndroid Build Coastguard Worker ch347_cs_control(ch347_data, CH347_CS_DEASSERT | CH347_CS_CHANGE, CH347_CS_IGNORE);
225*0d6140beSAndroid Build Coastguard Worker
226*0d6140beSAndroid Build Coastguard Worker return 0;
227*0d6140beSAndroid Build Coastguard Worker }
228*0d6140beSAndroid Build Coastguard Worker
ch347_spi_config(struct ch347_spi_data * ch347_data,uint8_t divisor)229*0d6140beSAndroid Build Coastguard Worker static int32_t ch347_spi_config(struct ch347_spi_data *ch347_data, uint8_t divisor)
230*0d6140beSAndroid Build Coastguard Worker {
231*0d6140beSAndroid Build Coastguard Worker int32_t ret;
232*0d6140beSAndroid Build Coastguard Worker uint8_t buff[29] = {
233*0d6140beSAndroid Build Coastguard Worker [0] = CH347_CMD_SPI_SET_CFG,
234*0d6140beSAndroid Build Coastguard Worker [1] = (sizeof(buff) - 3) & 0xFF,
235*0d6140beSAndroid Build Coastguard Worker [2] = ((sizeof(buff) - 3) & 0xFF00) >> 8,
236*0d6140beSAndroid Build Coastguard Worker /* Not sure what these two bytes do, but the vendor
237*0d6140beSAndroid Build Coastguard Worker * drivers seem to unconditionally set these values
238*0d6140beSAndroid Build Coastguard Worker */
239*0d6140beSAndroid Build Coastguard Worker [5] = 4,
240*0d6140beSAndroid Build Coastguard Worker [6] = 1,
241*0d6140beSAndroid Build Coastguard Worker /* Clock polarity: bit 1 */
242*0d6140beSAndroid Build Coastguard Worker [9] = 0,
243*0d6140beSAndroid Build Coastguard Worker /* Clock phase: bit 0 */
244*0d6140beSAndroid Build Coastguard Worker [11] = 0,
245*0d6140beSAndroid Build Coastguard Worker /* Another mystery byte */
246*0d6140beSAndroid Build Coastguard Worker [14] = 2,
247*0d6140beSAndroid Build Coastguard Worker /* Clock divisor: bits 5:3 */
248*0d6140beSAndroid Build Coastguard Worker [15] = (divisor & 0x7) << 3,
249*0d6140beSAndroid Build Coastguard Worker /* Bit order: bit 7, 0=MSB */
250*0d6140beSAndroid Build Coastguard Worker [17] = 0,
251*0d6140beSAndroid Build Coastguard Worker /* Yet another mystery byte */
252*0d6140beSAndroid Build Coastguard Worker [19] = 7,
253*0d6140beSAndroid Build Coastguard Worker /* CS polarity: bit 7 CS2, bit 6 CS1. 0 = active low */
254*0d6140beSAndroid Build Coastguard Worker [24] = 0
255*0d6140beSAndroid Build Coastguard Worker };
256*0d6140beSAndroid Build Coastguard Worker
257*0d6140beSAndroid Build Coastguard Worker ret = libusb_bulk_transfer(ch347_data->handle, WRITE_EP, buff, sizeof(buff), NULL, 1000);
258*0d6140beSAndroid Build Coastguard Worker if (ret < 0) {
259*0d6140beSAndroid Build Coastguard Worker msg_perr("Could not configure SPI interface\n");
260*0d6140beSAndroid Build Coastguard Worker }
261*0d6140beSAndroid Build Coastguard Worker
262*0d6140beSAndroid Build Coastguard Worker /* FIXME: Not sure if the CH347 sends error responses for
263*0d6140beSAndroid Build Coastguard Worker * invalid config data, if so the code should check
264*0d6140beSAndroid Build Coastguard Worker */
265*0d6140beSAndroid Build Coastguard Worker ret = libusb_bulk_transfer(ch347_data->handle, READ_EP, buff, sizeof(buff), NULL, 1000);
266*0d6140beSAndroid Build Coastguard Worker if (ret < 0) {
267*0d6140beSAndroid Build Coastguard Worker msg_perr("Could not receive configure SPI command response\n");
268*0d6140beSAndroid Build Coastguard Worker }
269*0d6140beSAndroid Build Coastguard Worker return ret;
270*0d6140beSAndroid Build Coastguard Worker }
271*0d6140beSAndroid Build Coastguard Worker
272*0d6140beSAndroid Build Coastguard Worker static const struct spi_master spi_master_ch347_spi = {
273*0d6140beSAndroid Build Coastguard Worker .features = SPI_MASTER_4BA,
274*0d6140beSAndroid Build Coastguard Worker .max_data_read = MAX_DATA_READ_UNLIMITED,
275*0d6140beSAndroid Build Coastguard Worker .max_data_write = MAX_DATA_WRITE_UNLIMITED,
276*0d6140beSAndroid Build Coastguard Worker .command = ch347_spi_send_command,
277*0d6140beSAndroid Build Coastguard Worker .read = default_spi_read,
278*0d6140beSAndroid Build Coastguard Worker .write_256 = default_spi_write_256,
279*0d6140beSAndroid Build Coastguard Worker .write_aai = default_spi_write_aai,
280*0d6140beSAndroid Build Coastguard Worker .shutdown = ch347_spi_shutdown,
281*0d6140beSAndroid Build Coastguard Worker };
282*0d6140beSAndroid Build Coastguard Worker
283*0d6140beSAndroid Build Coastguard Worker /* Largely copied from ch341a_spi.c */
ch347_spi_init(const struct programmer_cfg * cfg)284*0d6140beSAndroid Build Coastguard Worker static int ch347_spi_init(const struct programmer_cfg *cfg)
285*0d6140beSAndroid Build Coastguard Worker {
286*0d6140beSAndroid Build Coastguard Worker char *arg;
287*0d6140beSAndroid Build Coastguard Worker uint16_t vid = devs_ch347_spi[0].vendor_id;
288*0d6140beSAndroid Build Coastguard Worker uint16_t pid = 0;
289*0d6140beSAndroid Build Coastguard Worker int index = 0;
290*0d6140beSAndroid Build Coastguard Worker int speed_index = 2;
291*0d6140beSAndroid Build Coastguard Worker struct ch347_spi_data *ch347_data = calloc(1, sizeof(*ch347_data));
292*0d6140beSAndroid Build Coastguard Worker if (!ch347_data) {
293*0d6140beSAndroid Build Coastguard Worker msg_perr("Could not allocate space for SPI data\n");
294*0d6140beSAndroid Build Coastguard Worker return 1;
295*0d6140beSAndroid Build Coastguard Worker }
296*0d6140beSAndroid Build Coastguard Worker
297*0d6140beSAndroid Build Coastguard Worker int32_t ret = libusb_init(NULL);
298*0d6140beSAndroid Build Coastguard Worker if (ret < 0) {
299*0d6140beSAndroid Build Coastguard Worker msg_perr("Could not initialize libusb!\n");
300*0d6140beSAndroid Build Coastguard Worker free(ch347_data);
301*0d6140beSAndroid Build Coastguard Worker return 1;
302*0d6140beSAndroid Build Coastguard Worker }
303*0d6140beSAndroid Build Coastguard Worker /* Enable information, warning, and error messages (only). */
304*0d6140beSAndroid Build Coastguard Worker #if LIBUSB_API_VERSION < 0x01000106
305*0d6140beSAndroid Build Coastguard Worker libusb_set_debug(NULL, 3);
306*0d6140beSAndroid Build Coastguard Worker #else
307*0d6140beSAndroid Build Coastguard Worker libusb_set_option(NULL, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO);
308*0d6140beSAndroid Build Coastguard Worker #endif
309*0d6140beSAndroid Build Coastguard Worker while (devs_ch347_spi[index].vendor_id != 0) {
310*0d6140beSAndroid Build Coastguard Worker vid = devs_ch347_spi[index].vendor_id;
311*0d6140beSAndroid Build Coastguard Worker pid = devs_ch347_spi[index].device_id;
312*0d6140beSAndroid Build Coastguard Worker ch347_data->handle = libusb_open_device_with_vid_pid(NULL, vid, pid);
313*0d6140beSAndroid Build Coastguard Worker if (ch347_data->handle) {
314*0d6140beSAndroid Build Coastguard Worker ch347_data->interface = ch347_interface[index];
315*0d6140beSAndroid Build Coastguard Worker break;
316*0d6140beSAndroid Build Coastguard Worker }
317*0d6140beSAndroid Build Coastguard Worker index++;
318*0d6140beSAndroid Build Coastguard Worker }
319*0d6140beSAndroid Build Coastguard Worker if (!ch347_data->handle) {
320*0d6140beSAndroid Build Coastguard Worker msg_perr("Couldn't find CH347.\n");
321*0d6140beSAndroid Build Coastguard Worker free(ch347_data);
322*0d6140beSAndroid Build Coastguard Worker return 1;
323*0d6140beSAndroid Build Coastguard Worker }
324*0d6140beSAndroid Build Coastguard Worker
325*0d6140beSAndroid Build Coastguard Worker ret = libusb_detach_kernel_driver(ch347_data->handle, ch347_data->interface);
326*0d6140beSAndroid Build Coastguard Worker if (ret != 0 && ret != LIBUSB_ERROR_NOT_FOUND)
327*0d6140beSAndroid Build Coastguard Worker msg_pwarn("Cannot detach the existing USB driver. Claiming the interface may fail. %s\n",
328*0d6140beSAndroid Build Coastguard Worker libusb_error_name(ret));
329*0d6140beSAndroid Build Coastguard Worker
330*0d6140beSAndroid Build Coastguard Worker ret = libusb_claim_interface(ch347_data->handle, ch347_data->interface);
331*0d6140beSAndroid Build Coastguard Worker if (ret != 0) {
332*0d6140beSAndroid Build Coastguard Worker msg_perr("Failed to claim interface %d: '%s'\n", ch347_data->interface, libusb_error_name(ret));
333*0d6140beSAndroid Build Coastguard Worker goto error_exit;
334*0d6140beSAndroid Build Coastguard Worker }
335*0d6140beSAndroid Build Coastguard Worker
336*0d6140beSAndroid Build Coastguard Worker struct libusb_device *dev;
337*0d6140beSAndroid Build Coastguard Worker if (!(dev = libusb_get_device(ch347_data->handle))) {
338*0d6140beSAndroid Build Coastguard Worker msg_perr("Failed to get device from device handle.\n");
339*0d6140beSAndroid Build Coastguard Worker goto error_exit;
340*0d6140beSAndroid Build Coastguard Worker }
341*0d6140beSAndroid Build Coastguard Worker
342*0d6140beSAndroid Build Coastguard Worker struct libusb_device_descriptor desc;
343*0d6140beSAndroid Build Coastguard Worker ret = libusb_get_device_descriptor(dev, &desc);
344*0d6140beSAndroid Build Coastguard Worker if (ret < 0) {
345*0d6140beSAndroid Build Coastguard Worker msg_perr("Failed to get device descriptor: '%s'\n", libusb_error_name(ret));
346*0d6140beSAndroid Build Coastguard Worker goto error_exit;
347*0d6140beSAndroid Build Coastguard Worker }
348*0d6140beSAndroid Build Coastguard Worker
349*0d6140beSAndroid Build Coastguard Worker msg_pdbg("Device revision is %d.%01d.%01d\n",
350*0d6140beSAndroid Build Coastguard Worker (desc.bcdDevice >> 8) & 0x00FF,
351*0d6140beSAndroid Build Coastguard Worker (desc.bcdDevice >> 4) & 0x000F,
352*0d6140beSAndroid Build Coastguard Worker (desc.bcdDevice >> 0) & 0x000F);
353*0d6140beSAndroid Build Coastguard Worker
354*0d6140beSAndroid Build Coastguard Worker /* set CH347 clock division */
355*0d6140beSAndroid Build Coastguard Worker arg = extract_programmer_param_str(cfg, "spispeed");
356*0d6140beSAndroid Build Coastguard Worker if (arg) {
357*0d6140beSAndroid Build Coastguard Worker for (speed_index = 0; spispeeds[speed_index].name; speed_index++) {
358*0d6140beSAndroid Build Coastguard Worker if (!strncasecmp(spispeeds[speed_index].name, arg, strlen(spispeeds[speed_index].name))) {
359*0d6140beSAndroid Build Coastguard Worker break;
360*0d6140beSAndroid Build Coastguard Worker }
361*0d6140beSAndroid Build Coastguard Worker }
362*0d6140beSAndroid Build Coastguard Worker }
363*0d6140beSAndroid Build Coastguard Worker if (!spispeeds[speed_index].name || !arg) {
364*0d6140beSAndroid Build Coastguard Worker msg_perr("Unknown value of spispeed parameter, using default 15MHz clock spi.\n");
365*0d6140beSAndroid Build Coastguard Worker speed_index = 2;
366*0d6140beSAndroid Build Coastguard Worker }
367*0d6140beSAndroid Build Coastguard Worker free(arg);
368*0d6140beSAndroid Build Coastguard Worker if (ch347_spi_config(ch347_data, spispeeds[speed_index].divisor) < 0) {
369*0d6140beSAndroid Build Coastguard Worker goto error_exit;
370*0d6140beSAndroid Build Coastguard Worker } else {
371*0d6140beSAndroid Build Coastguard Worker msg_pinfo("CH347 SPI clock set to %sHz.\n", spispeeds[speed_index].name);
372*0d6140beSAndroid Build Coastguard Worker }
373*0d6140beSAndroid Build Coastguard Worker
374*0d6140beSAndroid Build Coastguard Worker return register_spi_master(&spi_master_ch347_spi, ch347_data);
375*0d6140beSAndroid Build Coastguard Worker
376*0d6140beSAndroid Build Coastguard Worker error_exit:
377*0d6140beSAndroid Build Coastguard Worker ch347_spi_shutdown(ch347_data);
378*0d6140beSAndroid Build Coastguard Worker return 1;
379*0d6140beSAndroid Build Coastguard Worker }
380*0d6140beSAndroid Build Coastguard Worker
381*0d6140beSAndroid Build Coastguard Worker const struct programmer_entry programmer_ch347_spi = {
382*0d6140beSAndroid Build Coastguard Worker .name = "ch347_spi",
383*0d6140beSAndroid Build Coastguard Worker .type = USB,
384*0d6140beSAndroid Build Coastguard Worker .devs.dev = devs_ch347_spi,
385*0d6140beSAndroid Build Coastguard Worker .init = ch347_spi_init,
386*0d6140beSAndroid Build Coastguard Worker };