--- ft2232h_0/src/jtag/ft2232.c	Thu Aug 13 12:41:31 2009
+++ ft2232h_1/src/jtag/ft2232.c	Thu Aug 13 12:32:11 2009
@@ -65,6 +65,10 @@
 
 /* max TCK for the high speed devices 30000 kHz */
 #define	FTDI_2232H_4232H_MAX_TCK	30000
+/* max TCK for the full speed devices 6000 kHz */
+#define	FTDI_2232C_MAX_TCK 6000
+/* this speed value tells that RTCK is requested */
+#define RTCK_SPEED -1
 
 static int ft2232_execute_queue(void);
 
@@ -94,15 +98,12 @@
  */
 static int ft2232_stableclocks(int num_cycles, jtag_command_t* cmd);
 
-/* max TCK for the high speed devices 30000 kHz */
-#define	FTDI_2232H_4232H_MAX_TCK	30000
-
 static char *       ft2232_device_desc_A = NULL;
 static char*        ft2232_device_desc = NULL;
 static char*        ft2232_serial  = NULL;
 static char*        ft2232_layout  = NULL;
 static uint8_t		ft2232_latency = 2;
-static unsigned		ft2232_max_tck = 6000;
+static unsigned		ft2232_max_tck = FTDI_2232C_MAX_TCK;
 
 
 #define MAX_USB_IDS 8
@@ -182,6 +183,7 @@
 static FT_DEVICE	ftdi_device = 0;
 #elif BUILD_FT2232_LIBFTDI == 1
 static struct ftdi_context ftdic;
+static enum ftdi_chip_type ftdi_device;
 #endif
 
 
@@ -424,41 +426,56 @@
 #ifdef BUILD_FTD2XX_HIGHSPEED
 static bool ft2232_device_is_highspeed(void)
 {
+#if BUILD_FT2232_FTD2XX == 1
 	return (ftdi_device == FT_DEVICE_2232H) || (ftdi_device == FT_DEVICE_4232H);
+#elif BUILD_FT2232_LIBFTDI == 1
+	return (ftdi_device == TYPE_2232H || ftdi_device == TYPE_4232H);
+#endif
 }
 
-static int ft2232_adaptive_clocking(int speed)
-{
-	bool use_adaptive_clocking = FALSE;
-	if (0 == speed)
-	{
-		if (ft2232_device_is_highspeed())
-			use_adaptive_clocking = TRUE;
-		else
-		{
-			LOG_ERROR("ft2232 device %lu does not support RTCK", ftdi_device);
-			return ERROR_OK;
-		}
-	}
+/*
+ * Commands that only apply to the FT2232H and FT4232H devices.
+ * See chapter 6 in http://www.ftdichip.com/Documents/AppNotes/
+ * AN_108_Command_Processor_for_MPSSE_and_MCU_Host_Bus_Emulation_Modes.pdf
+ */
 
-	uint8_t  buf = use_adaptive_clocking ? 0x96 : 0x97;
+static int ft2232h_ft4232h_adaptive_clocking(bool enable)
+{
+	uint8_t buf = enable ? 0x96 : 0x97;
 	LOG_DEBUG("%2.2x", buf);
 
 	uint32_t bytes_written;
 	int retval = ft2232_write(&buf, 1, &bytes_written);
-	if (ERROR_OK != retval || bytes_written != 1)
+	if ((ERROR_OK != retval) || (bytes_written != 1))
 	{
-		LOG_ERROR("unable to set adative clocking: %d", retval);
+		LOG_ERROR("couldn't write command to %s adaptive clocking"
+			, enable ? "enable" : "disable");
 		return retval;
 	}
 
 	return ERROR_OK;
 }
-#else
-static int ft2232_adaptive_clocking(int speed)
+
+/**
+ * Enable/disable the clk divide by 5 of the 60MHz master clock.
+ * This result in a JTAG clock speed range of 91.553Hz-6MHz
+ * respective 457.763Hz-30MHz.
+ */
+static int ft2232h_ft4232h_clk_divide_by_5(bool enable)
 {
-	// not implemented on low-speed devices
-	return speed ? ERROR_OK : -1234;
+	uint32_t bytes_written;
+	uint8_t buf = enable ?  0x8b : 0x8a;
+	int retval = ft2232_write(&buf, 1, &bytes_written);
+	if ((ERROR_OK != retval) || (bytes_written != 1))
+	{
+		LOG_ERROR("couldn't write command to %s clk divide by 5"
+			, enable ? "enable" : "disable");
+		return ERROR_JTAG_INIT_FAILED;
+	}
+	ft2232_max_tck = enable ? FTDI_2232C_MAX_TCK : FTDI_2232H_4232H_MAX_TCK;
+	LOG_INFO("max TCK change to: %u kHz", ft2232_max_tck);
+
+	return ERROR_OK;
 }
 #endif
 
@@ -468,8 +485,21 @@
 	int retval;
 	uint32_t bytes_written;
 
-	ft2232_adaptive_clocking(speed);
+#ifdef BUILD_FTD2XX_HIGHSPEED
+	retval = ERROR_OK;
+	bool enable_adaptive_clocking = (RTCK_SPEED == speed);
+	if (ft2232_device_is_highspeed())
+		retval = ft2232h_ft4232h_adaptive_clocking(enable_adaptive_clocking);
+	else if (enable_adaptive_clocking)
+	{
+		LOG_ERROR("ft2232 device %lu does not support RTCK"
+			, (long unsigned int)ftdi_device);
+		return ERROR_FAIL;
+	}
 
+	if ((enable_adaptive_clocking) || (ERROR_OK != retval))
+		return retval;
+#endif
 	buf[0] = 0x86;			/* command "set divisor" */
 	buf[1] = speed & 0xff;          /* valueL (0 = 6MHz, 1 = 3MHz, 2 = 2.0MHz, ...*/
 	buf[2] = (speed >> 8) & 0xff;   /* valueH */
@@ -491,7 +521,7 @@
 	 * AN2232C-01 Command Processor for
 	 * MPSSE and MCU Host Bus. Chapter 3.8 */
 
-	*khz = ft2232_max_tck / (1 + speed);
+	*khz = (RTCK_SPEED == speed) ? 0 : ft2232_max_tck / (1 + speed);
 
 	return ERROR_OK;
 }
@@ -502,8 +532,16 @@
 	if (khz == 0)
 	{
 #ifdef BUILD_FTD2XX_HIGHSPEED
-		*jtag_speed = 0;
-		return ERROR_OK;
+		if (ft2232_device_is_highspeed())
+		{
+			*jtag_speed = RTCK_SPEED;
+			return ERROR_OK;
+		}
+		else
+		{
+			LOG_DEBUG("RCLK not supported");
+			return ERROR_FAIL;
+		}
 #else
 		LOG_DEBUG("RCLK not supported");
 		LOG_DEBUG("If you have a high-speed FTDI device, then "
@@ -1939,14 +1977,6 @@
 		LOG_INFO("deviceID: %lu", deviceID);
 		LOG_INFO("SerialNumber: %s", SerialNumber);
 		LOG_INFO("Description: %s", Description);
-
-#ifdef BUILD_FTD2XX_HIGHSPEED
-		if (ft2232_device_is_highspeed())
-		{
-			ft2232_max_tck = FTDI_2232H_4232H_MAX_TCK;
-			LOG_INFO("max TCK change to: %u kHz", ft2232_max_tck);
-		}
-#endif
 	}
 
 	return ERROR_OK;
@@ -2024,6 +2054,13 @@
 
 	ftdi_set_bitmode(&ftdic, 0x0b, 2); /* ctx, JTAG I/O mask */
 
+	ftdi_device = ftdic.type;
+	static const char* type_str[] =
+		{"AM", "BM", "2232C", "R", "2232H", "4232H", "Unknown"};
+	unsigned no_of_known_types = sizeof(type_str) / sizeof(type_str[0]) - 1;
+	unsigned type_index = ((unsigned)ftdi_device < no_of_known_types)
+		? ftdi_device : no_of_known_types;
+	LOG_DEBUG("FTDI chip type: %i \"%s\"", (int)ftdi_device, type_str[type_index]);
 	return ERROR_OK;
 }
 
@@ -2113,6 +2150,14 @@
 
 	if (layout->init() != ERROR_OK)
 		return ERROR_JTAG_INIT_FAILED;
+
+#ifdef BUILD_FTD2XX_HIGHSPEED
+	if (ft2232_device_is_highspeed())
+	{
+		if (ft2232h_ft4232h_clk_divide_by_5(false) != ERROR_OK)
+			return ERROR_JTAG_INIT_FAILED;
+	}
+#endif
 
 	ft2232_speed(jtag_get_speed());
 
