]> sigrok.org Git - libsigrok.git/blob - hardware/sysclk-lwla/lwla.c
sysclk-lwla: Implement support for the LWLA1034.
[libsigrok.git] / hardware / sysclk-lwla / lwla.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2014 Daniel Elstner <daniel.kitta@gmail.com>
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 3 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  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "lwla.h"
21 #include "protocol.h"
22 #include "libsigrok-internal.h"
23
24 SR_PRIV int lwla_send_bitstream(const struct sr_usb_dev_inst *usb,
25                                 const char *filename)
26 {
27         GMappedFile *file;
28         GError *error;
29         char *stream;
30         size_t length;
31         int ret;
32         int xfer_len;
33
34         if (usb == NULL || filename == NULL)
35                 return SR_ERR_ARG;
36
37         sr_info("Downloading FPGA bitstream at '%s'.", filename);
38
39         /* Map bitstream file into memory. */
40         error = NULL;
41         file = g_mapped_file_new(filename, FALSE, &error);
42         if (!file) {
43                 sr_err("Unable to open bitstream file: %s.", error->message);
44                 g_error_free(error);
45                 return SR_ERR;
46         }
47         stream = g_mapped_file_get_contents(file);
48         length = g_mapped_file_get_length(file);
49
50         /* Sanity check. */
51         if (!stream || length < 4 || RB32(stream) != length) {
52                 sr_err("Invalid FPGA bitstream.");
53                 g_mapped_file_unref(file);
54                 return SR_ERR;
55         }
56
57         /* Transfer the entire bitstream in one URB. */
58         ret = libusb_bulk_transfer(usb->devhdl, EP_BITSTREAM,
59                                    (unsigned char *)stream, length,
60                                    &xfer_len, USB_TIMEOUT);
61         if (ret != 0) {
62                 sr_err("Failed to transfer bitstream: %s.",
63                        libusb_error_name(ret));
64                 g_mapped_file_unref(file);
65                 return SR_ERR;
66         }
67         if (xfer_len != (int)length) {
68                 sr_err("Failed to transfer bitstream: incorrect length "
69                        "%d != %d.", xfer_len, (int)length);
70                 g_mapped_file_unref(file);
71                 return SR_ERR;
72         }
73         g_mapped_file_unref(file);
74         sr_info("FPGA bitstream download of %d bytes done.", xfer_len);
75
76         /* This delay appears to be necessary for reliable operation. */
77         g_usleep(30000);
78
79         return SR_OK;
80 }
81
82 SR_PRIV int lwla_send_command(const struct sr_usb_dev_inst *usb,
83                               const uint16_t *command, int cmd_len)
84 {
85         int ret;
86         int xfer_len = 0;
87
88         if (usb == NULL || command == NULL || cmd_len < 1)
89                 return SR_ERR_ARG;
90
91         ret = libusb_bulk_transfer(usb->devhdl, EP_COMMAND,
92                                    (unsigned char *)command, cmd_len * 2,
93                                    &xfer_len, USB_TIMEOUT);
94         if (ret != 0) {
95                 sr_dbg("Failed to send command %u: %s.",
96                        LWLA_READ16(command), libusb_error_name(ret));
97                 return SR_ERR;
98         }
99         if (xfer_len != cmd_len * 2) {
100                 sr_dbg("Failed to send command %u: incorrect length %d != %d.",
101                        LWLA_READ16(command), xfer_len, cmd_len * 2);
102                 return SR_ERR;
103         }
104         return SR_OK;
105 }
106
107 SR_PRIV int lwla_receive_reply(const struct sr_usb_dev_inst *usb,
108                                uint16_t *reply, int reply_len, int expect_len)
109 {
110         int ret;
111         int xfer_len = 0;
112
113         if (reply_len == 0)
114                 return SR_OK;
115
116         if (usb == NULL || reply == NULL || reply_len < 0)
117                 return SR_ERR_ARG;
118
119         ret = libusb_bulk_transfer(usb->devhdl, EP_REPLY,
120                                    (unsigned char *)reply, reply_len * 2,
121                                    &xfer_len, USB_TIMEOUT);
122         if (ret != 0) {
123                 sr_dbg("Failed to receive reply: %s.", libusb_error_name(ret));
124                 return SR_ERR;
125         }
126         if (xfer_len != expect_len * 2) {
127                 sr_dbg("Failed to receive reply: incorrect length %d != %d.",
128                        xfer_len, expect_len * 2);
129                 return SR_ERR;
130         }
131         return SR_OK;
132 }
133
134 SR_PRIV int lwla_read_reg(const struct sr_usb_dev_inst *usb,
135                           uint16_t reg, uint32_t *value)
136 {
137         int ret;
138         uint16_t command[2];
139         uint16_t reply[256];
140
141         command[0] = LWLA_WORD(CMD_READ_REG);
142         command[1] = LWLA_WORD(reg);
143
144         ret = lwla_send_command(usb, command, G_N_ELEMENTS(command));
145
146         if (ret != SR_OK)
147                 return ret;
148
149         ret = lwla_receive_reply(usb, reply, G_N_ELEMENTS(reply), 2);
150
151         if (ret == SR_OK)
152                 *value = LWLA_READ32(reply);
153
154         return ret;
155 }
156
157 SR_PRIV int lwla_write_reg(const struct sr_usb_dev_inst *usb,
158                            uint16_t reg, uint32_t value)
159 {
160         uint16_t command[4];
161
162         command[0] = LWLA_WORD(CMD_WRITE_REG);
163         command[1] = LWLA_WORD(reg);
164         command[2] = LWLA_WORD_0(value);
165         command[3] = LWLA_WORD_1(value);
166
167         return lwla_send_command(usb, command, G_N_ELEMENTS(command));
168 }
169
170 SR_PRIV int lwla_write_regs(const struct sr_usb_dev_inst *usb,
171                             const struct regval_pair *regvals, int count)
172 {
173         int i;
174         int ret;
175
176         ret = SR_OK;
177
178         for (i = 0; i < count; ++i) {
179                 ret = lwla_write_reg(usb, regvals[i].reg, regvals[i].val);
180
181                 if (ret != SR_OK)
182                         break;
183         }
184
185         return ret;
186 }