versaloon driver update
[fw/openocd] / src / jtag / drivers / versaloon / versaloon.c
diff --git a/src/jtag/drivers/versaloon/versaloon.c b/src/jtag/drivers/versaloon/versaloon.c
new file mode 100644 (file)
index 0000000..dbb8e4f
--- /dev/null
@@ -0,0 +1,398 @@
+/***************************************************************************
+ *   Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.com>     *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "versaloon_include.h"
+#include "versaloon.h"
+#include "versaloon_internal.h"
+#include "usbtoxxx/usbtoxxx.h"
+
+uint8_t *versaloon_buf = NULL;
+uint8_t *versaloon_cmd_buf = NULL;
+uint16_t versaloon_buf_size;
+
+struct versaloon_pending_t versaloon_pending[VERSALOON_MAX_PENDING_NUMBER];
+uint16_t versaloon_pending_idx = 0;
+
+usb_dev_handle *versaloon_usb_device_handle = NULL;
+static uint32_t versaloon_usb_to = VERSALOON_TIMEOUT;
+
+RESULT versaloon_init(void);
+RESULT versaloon_fini(void);
+RESULT versaloon_get_target_voltage(uint16_t *voltage);
+RESULT versaloon_set_target_voltage(uint16_t voltage);
+RESULT versaloon_delay_ms(uint16_t ms);
+RESULT versaloon_delay_us(uint16_t us);
+struct versaloon_interface_t versaloon_interface =
+{
+       .init                                   = versaloon_init,
+       .fini                                   = versaloon_fini,
+       {// adaptors
+               {// target_voltage
+                       .get                    = versaloon_get_target_voltage,
+                       .set                    = versaloon_set_target_voltage,
+               },
+               {// gpio
+                       .init                   = usbtogpio_init,
+                       .fini                   = usbtogpio_fini,
+                       .config                 = usbtogpio_config,
+                       .out                    = usbtogpio_out,
+                       .in                             = usbtogpio_in,
+               },
+               {// delay
+                       .delayms                = versaloon_delay_ms,
+                       .delayus                = versaloon_delay_us,
+               },
+               {// swd
+                       .init                   = usbtoswd_init,
+                       .fini                   = usbtoswd_fini,
+                       .config                 = usbtoswd_config,
+                       .seqout                 = usbtoswd_seqout,
+                       .seqin                  = usbtoswd_seqin,
+                       .transact               = usbtoswd_transact,
+               },
+               {// jtag_raw
+                       .init                   = usbtojtagraw_init,
+                       .fini                   = usbtojtagraw_fini,
+                       .config                 = usbtojtagraw_config,
+                       .execute                = usbtojtagraw_execute,
+               },
+               .peripheral_commit      = usbtoxxx_execute_command,
+       },
+       {// usb_setting
+               .vid                            = VERSALOON_VID,
+               .pid                            = VERSALOON_PID,
+               .ep_out                         = VERSALOON_OUTP,
+               .ep_in                          = VERSALOON_INP,
+               .interface                      = VERSALOON_IFACE,
+               .serialstring           = NULL,
+               .buf_size                       = 256,
+       }
+};
+
+// programmer_cmd
+static uint32_t versaloon_pending_id = 0;
+static versaloon_callback_t versaloon_callback = NULL;
+static void *versaloon_extra_data = NULL;
+static struct versaloon_want_pos_t *versaloon_want_pos = NULL;
+void versaloon_set_pending_id(uint32_t id)
+{
+       versaloon_pending_id = id;
+}
+void versaloon_set_callback(versaloon_callback_t callback)
+{
+       versaloon_callback = callback;
+}
+void versaloon_set_extra_data(void * p)
+{
+       versaloon_extra_data = p;
+}
+
+void versaloon_free_want_pos(void)
+{
+       uint16_t i;
+       struct versaloon_want_pos_t *tmp, *free_tmp;
+
+       tmp = versaloon_want_pos;
+       while (tmp != NULL)
+       {
+               free_tmp = tmp;
+               tmp = tmp->next;
+               free(free_tmp);
+       }
+       versaloon_want_pos = NULL;
+
+       for (i = 0; i < dimof(versaloon_pending); i++)
+       {
+               tmp = versaloon_pending[i].pos;
+               while (tmp != NULL)
+               {
+                       free_tmp = tmp;
+                       tmp = tmp->next;
+                       free(free_tmp);
+               }
+               versaloon_pending[i].pos = NULL;
+       }
+}
+
+RESULT versaloon_add_want_pos(uint16_t offset, uint16_t size, uint8_t *buff)
+{
+       struct versaloon_want_pos_t *new_pos = NULL;
+
+       new_pos = (struct versaloon_want_pos_t *)malloc(sizeof(*new_pos));
+       if (NULL == new_pos)
+       {
+               LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
+               return ERRCODE_NOT_ENOUGH_MEMORY;
+       }
+       new_pos->offset = offset;
+       new_pos->size = size;
+       new_pos->buff = buff;
+       new_pos->next = NULL;
+
+       if (NULL == versaloon_want_pos)
+       {
+               versaloon_want_pos = new_pos;
+       }
+       else
+       {
+               struct versaloon_want_pos_t *tmp = versaloon_want_pos;
+
+               while (tmp->next != NULL)
+               {
+                       tmp = tmp->next;
+               }
+               tmp->next = new_pos;
+       }
+
+       return ERROR_OK;
+}
+
+RESULT versaloon_add_pending(uint8_t type, uint8_t cmd, uint16_t actual_szie,
+       uint16_t want_pos, uint16_t want_size, uint8_t *buffer, uint8_t collect)
+{
+#if PARAM_CHECK
+       if (versaloon_pending_idx >= VERSALOON_MAX_PENDING_NUMBER)
+       {
+               LOG_BUG(ERRMSG_INVALID_INDEX, versaloon_pending_idx,
+                                       "versaloon pending data");
+               return ERROR_FAIL;
+       }
+#endif
+
+       versaloon_pending[versaloon_pending_idx].type = type;
+       versaloon_pending[versaloon_pending_idx].cmd = cmd;
+       versaloon_pending[versaloon_pending_idx].actual_data_size = actual_szie;
+       versaloon_pending[versaloon_pending_idx].want_data_pos = want_pos;
+       versaloon_pending[versaloon_pending_idx].want_data_size = want_size;
+       versaloon_pending[versaloon_pending_idx].data_buffer = buffer;
+       versaloon_pending[versaloon_pending_idx].collect = collect;
+       versaloon_pending[versaloon_pending_idx].id = versaloon_pending_id;
+       versaloon_pending_id = 0;
+       versaloon_pending[versaloon_pending_idx].extra_data = versaloon_extra_data;
+       versaloon_extra_data = NULL;
+       versaloon_pending[versaloon_pending_idx].callback = versaloon_callback;
+       versaloon_callback = NULL;
+       versaloon_pending[versaloon_pending_idx].pos = versaloon_want_pos;
+       versaloon_want_pos = NULL;
+       versaloon_pending_idx++;
+
+       return ERROR_OK;
+}
+
+RESULT versaloon_send_command(uint16_t out_len, uint16_t *inlen)
+{
+       int ret;
+
+#if PARAM_CHECK
+       if (NULL == versaloon_buf)
+       {
+               LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(versaloon_buf));
+               return ERRCODE_INVALID_BUFFER;
+       }
+       if ((0 == out_len) || (out_len > versaloon_interface.usb_setting.buf_size))
+       {
+               LOG_BUG(ERRMSG_INVALID_PARAMETER, __FUNCTION__);
+               return ERRCODE_INVALID_PARAMETER;
+       }
+#endif
+
+       ret = usb_bulk_write(versaloon_usb_device_handle,
+               versaloon_interface.usb_setting.ep_out, (char *)versaloon_buf,
+               out_len, versaloon_usb_to);
+       if (ret != out_len)
+       {
+               LOG_ERROR(ERRMSG_FAILURE_OPERATION_ERRSTRING, "send usb data",
+                       usb_strerror());
+               return ERRCODE_FAILURE_OPERATION;
+       }
+
+       if (inlen != NULL)
+       {
+               ret = usb_bulk_read(versaloon_usb_device_handle,
+                       versaloon_interface.usb_setting.ep_in, (char *)versaloon_buf,
+                       versaloon_interface.usb_setting.buf_size, versaloon_usb_to);
+               if (ret > 0)
+               {
+                       *inlen = (uint16_t)ret;
+                       return ERROR_OK;
+               }
+               else
+               {
+                       LOG_ERROR(ERRMSG_FAILURE_OPERATION_ERRSTRING, "receive usb data",
+                                               usb_strerror());
+                       return ERROR_FAIL;
+               }
+       }
+       else
+       {
+               return ERROR_OK;
+       }
+}
+
+#define VERSALOON_RETRY_CNT                            10
+RESULT versaloon_init(void)
+{
+       uint16_t ret = 0;
+       uint8_t retry;
+       uint32_t timeout_tmp;
+
+       // malloc temporary buffer
+       versaloon_buf =
+               (uint8_t *)malloc(versaloon_interface.usb_setting.buf_size);
+       if (NULL == versaloon_buf)
+       {
+               LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
+               return ERRCODE_NOT_ENOUGH_MEMORY;
+       }
+
+       // connect to versaloon
+       timeout_tmp = versaloon_usb_to;
+       // not output error message when connectting
+       // 100ms delay when connect
+       versaloon_usb_to = 100;
+       for (retry = 0; retry < VERSALOON_RETRY_CNT; retry++)
+       {
+               versaloon_buf[0] = VERSALOON_GET_INFO;
+               if ((ERROR_OK == versaloon_send_command(1, &ret)) && (ret >= 3))
+               {
+                       break;
+               }
+       }
+       versaloon_usb_to = timeout_tmp;
+       if (VERSALOON_RETRY_CNT == retry)
+       {
+               versaloon_fini();
+               LOG_ERROR(ERRMSG_FAILURE_OPERATION, "communicate with versaloon");
+               return ERRCODE_FAILURE_OPERATION;
+       }
+
+       versaloon_buf[ret] = 0;
+       versaloon_buf_size = versaloon_buf[0] + (versaloon_buf[1] << 8);
+       versaloon_interface.usb_setting.buf_size = versaloon_buf_size;
+       LOG_INFO("%s", versaloon_buf + 2);
+
+       // free temporary buffer
+       free(versaloon_buf);
+       versaloon_buf = NULL;
+
+       versaloon_buf =
+               (uint8_t *)malloc(versaloon_interface.usb_setting.buf_size);
+       if (NULL == versaloon_buf)
+       {
+               versaloon_fini();
+               LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
+               return ERRCODE_NOT_ENOUGH_MEMORY;
+       }
+       versaloon_cmd_buf =
+               (uint8_t *)malloc(versaloon_interface.usb_setting.buf_size - 3);
+       if (NULL == versaloon_cmd_buf)
+       {
+               versaloon_fini();
+               LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
+               return ERRCODE_NOT_ENOUGH_MEMORY;
+       }
+       if (ERROR_OK != usbtoxxx_init())
+       {
+               LOG_ERROR(ERRMSG_FAILURE_OPERATION, "initialize usbtoxxx");
+               return ERROR_FAIL;
+       }
+       return versaloon_get_target_voltage(&ret);
+}
+
+RESULT versaloon_fini(void)
+{
+       if (versaloon_usb_device_handle != NULL)
+       {
+               usbtoxxx_fini();
+               versaloon_free_want_pos();
+
+               versaloon_usb_device_handle = NULL;
+
+               if (versaloon_buf != NULL)
+               {
+                       free(versaloon_buf);
+                       versaloon_buf = NULL;
+               }
+               if (versaloon_cmd_buf != NULL)
+               {
+                       free(versaloon_cmd_buf);
+                       versaloon_cmd_buf = NULL;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+RESULT versaloon_set_target_voltage(uint16_t voltage)
+{
+       usbtopwr_init(0);
+       usbtopwr_config(0);
+       usbtopwr_output(0, voltage);
+       usbtopwr_fini(0);
+
+       return usbtoxxx_execute_command();
+}
+
+RESULT versaloon_get_target_voltage(uint16_t *voltage)
+{
+       uint16_t inlen;
+
+#if PARAM_CHECK
+       if (NULL == versaloon_buf)
+       {
+               LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(versaloon_buf));
+               return ERRCODE_INVALID_BUFFER;
+       }
+       if (NULL == voltage)
+       {
+               LOG_BUG(ERRMSG_INVALID_PARAMETER, __FUNCTION__);
+               return ERRCODE_INVALID_PARAMETER;
+       }
+#endif
+
+       versaloon_buf[0] = VERSALOON_GET_TVCC;
+
+       if ((ERROR_OK != versaloon_send_command(1, &inlen)) || (inlen != 2))
+       {
+               LOG_ERROR(ERRMSG_FAILURE_OPERATION, "communicate with versaloon");
+               return ERRCODE_FAILURE_OPERATION;
+       }
+       else
+       {
+               *voltage = versaloon_buf[0] + (versaloon_buf[1] << 8);
+               return ERROR_OK;
+       }
+}
+
+RESULT versaloon_delay_ms(uint16_t ms)
+{
+       return usbtodelay_delay(ms | 0x8000);
+}
+
+RESULT versaloon_delay_us(uint16_t us)
+{
+       return usbtodelay_delay(us & 0x7FFF);
+}
+