libftdi Archives

Subject: [PATCH 4/6] Completed the support for the FT4232H chip

From: Anders Larsen <al@xxxxxxxxxxx>
To: libftdi@xxxxxxxxxxxxxxxxxxxxxxx
Date: Mon, 9 Apr 2012 17:29:22 +0200
Added missing fields to the ftdi_eeprom structure and the encoding and
decoding functions.

The ftdi_eeprom utility forces DRIVER_VCP on and RS485 off for all channels,
but this could easily be made configurable, should the need arise.

Signed-off-by: Anders Larsen <al@xxxxxxxxxxx>
---
 doc/EEPROM-structure |   40 ++++++++-------
 ftdi_eeprom/main.c   |    9 +++
 src/ftdi.c           |  134 +++++++++++++++++++++++++++++++++++++++++++++++---
 src/ftdi.h           |   10 +++-
 src/ftdi_i.h         |    9 +++-
 5 files changed, 175 insertions(+), 27 deletions(-)

diff --git a/doc/EEPROM-structure b/doc/EEPROM-structure
index c83337e..a1e9b02 100644
--- a/doc/EEPROM-structure
+++ b/doc/EEPROM-structure
@@ -9,27 +9,27 @@ Type   |  Use extra EEPROM space
 FT2XXB |  No
 
 Byte.BIT| TYPE_AM TYPE_BM   TYPE_2232C       TYPE_R          TYPE_2232H       
TYPE_4232H
-00.0    |      0       0   channel_a_type                    channel_a_type   
channel_a_type
-00.1    |      0       0   channel_a_type                    channel_a_type   
channel_a_type
-00.2    |      0       0   channel_a_type   high_current     channel_a_type   
channel_a_type
+00.0    |      0       0   channel_a_type                    channel_a_type   0
+00.1    |      0       0   channel_a_type                    channel_a_type   0
+00.2    |      0       0   channel_a_type   high_current     channel_a_type   0
 00.3    |      0       0   channel_a_driver channel_a_driver channel_a_driver 
channel_a_driver
 00.4    |      0       0   high_current_a   0                0                0
 00.5    |      0       0   0                0                0                0
 00.6    |      0       0   0                0                0                0
-00.7    |      0       0   0                0                SUSPEND_DBUS7    0
+00.7    |      0       0   0                0                SUSPEND_DBUS7    
channel_c_driver
 
 On TYPE_R 00.3 set mean D2XX, on other devices VCP
 
-01.0    |      0       0   channel_b_type                    channel_b_type   
channel_b_type
-01.1    |      0       0   channel_b_type                    channel_b_type   
channel_b_type
-01.2    |      0       0   channel_b_type   0                channel_b_type   
channel_b_type
+01.0    |      0       0   channel_b_type                    channel_b_type   0
+01.1    |      0       0   channel_b_type                    channel_b_type   0
+01.2    |      0       0   channel_b_type   0                channel_b_type   0
 01.3    |      0       0   channel_b_driver 0                channel_b_driver 
channel_b_driver
 01.4    |      0       0   high_current_b   0                0                0
 01.5    |      0       0   0                0                0                0
 01.6    |      0       0   0                                 0                0
-01.7    |      0       0   0                0                0                0
+01.7    |      0       0   0                0                0                
channel_d_driver
 
-Fixme: Missing 4232H validation and channel_c_driver, channel_d_driver, 
channel_a|b|c|d_rs484enable
+Fixme: Missing 4232H validation
 
 02     | Vendor ID (VID) LSB (all)
 03     | Vendor ID (VID) MSB (all)
@@ -45,18 +45,22 @@ Fixme: Missing 4232H validation and channel_c_driver, 
channel_d_driver, channel_
        |
 09     | Max power (mA/2)
        |
-Byte.BIT| TYPE_AM TYPE_BM            TYPE_2232C        TYPE_R       TYPE_2232H 
      TYPE_4232H
-0a.0    | 0       IsoIn              IsoIn part A      0            0          
      0
-0a.1    | 0       IsoOut             IsoOut part A     0            0          
      0
-0a.2    | 0       suspend_pull_down suspend_pull_down               
suspend_pull_down
-0a.3    | 0       use_serial                                        use_serial
+Byte.BIT| TYPE_AM TYPE_BM            TYPE_2232C         TYPE_R       
TYPE_2232H        TYPE_4232H
+0a.0    | 0       IsoIn              IsoIn part A       0            0         
        0
+0a.1    | 0       IsoOut             IsoOut part A      0            0         
        0
+0a.2    | 0       suspend_pull_down  suspend_pull_down               
suspend_pull_down suspend_pull_down
+0a.3    | 0       use_serial                                         
use_serial        use_serial
 0a.4    | 0       change_usb_version change_usb_version
-0a.5    | 0       0                  IsoIn part B      0            0          
      0
-0a.6    | 0       0                  IsoOut part B     0            0          
      0
+0a.5    | 0       0                  IsoIn part B       0            0         
        0
+0a.6    | 0       0                  IsoOut part B      0            0         
        0
 0a.7    | 0 - reserved
 
-       |
-0b     | TYPE_R Bitmask Invert, 0 else
+0b      | TYPE_R Bitmask Invert, 0 else
+Byte.BIT| TYPE_4232H
+0b.4    | channel_a_rs485enable
+0b.5    | channel_b_rs485enable
+0b.6    | channel_c_rs485enable
+0b.7    | channel_d_rs485enable
 
 Byte   | TYPE_AM TYPE_BM     TYPE_2232C   TYPE_R       TYPE_2232H       
TYPE_4232H
 0c     | 0       USB-VER-LSB USB-VER-LSB  0            ?                ?
diff --git a/ftdi_eeprom/main.c b/ftdi_eeprom/main.c
index 48ed273..aa80992 100644
--- a/ftdi_eeprom/main.c
+++ b/ftdi_eeprom/main.c
@@ -297,6 +297,15 @@ int main(int argc, char *argv[])
     if (cfg_getbool(cfg, "invert_ri")) invert |= INVERT_RI;
     eeprom_set_value(ftdi, INVERT, invert);
 
+    eeprom_set_value(ftdi, CHANNEL_A_DRIVER, DRIVER_VCP);
+    eeprom_set_value(ftdi, CHANNEL_B_DRIVER, DRIVER_VCP);
+    eeprom_set_value(ftdi, CHANNEL_C_DRIVER, DRIVER_VCP);
+    eeprom_set_value(ftdi, CHANNEL_D_DRIVER, DRIVER_VCP);
+    eeprom_set_value(ftdi, CHANNEL_A_RS485, 0);
+    eeprom_set_value(ftdi, CHANNEL_B_RS485, 0);
+    eeprom_set_value(ftdi, CHANNEL_C_RS485, 0);
+    eeprom_set_value(ftdi, CHANNEL_D_RS485, 0);
+
     if (_erase > 0)
     {
         printf("FTDI erase eeprom: %d\n", ftdi_erase_eeprom(ftdi));
diff --git a/src/ftdi.c b/src/ftdi.c
index 59a9eea..8650be2 100644
--- a/src/ftdi.c
+++ b/src/ftdi.c
@@ -2369,7 +2369,6 @@ int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, 
char * manufacturer,
             strcpy(eeprom->serial, serial);
     }
 
-
     if (ftdi->type == TYPE_R)
     {
         eeprom->max_power = 90;
@@ -2840,8 +2839,83 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
 
             break;
         case TYPE_4232H:
+            if (eeprom->channel_a_driver == DRIVER_VCP)
+                output[0x00] |= DRIVER_VCP;
+            else
+                output[0x00] &= ~DRIVER_VCP;
+            if (eeprom->channel_b_driver == DRIVER_VCP)
+                output[0x01] |= DRIVER_VCP;
+            else
+                output[0x01] &= ~DRIVER_VCP;
+            if (eeprom->channel_c_driver == DRIVER_VCP)
+                output[0x00] |= (DRIVER_VCP << 4);
+            else
+                output[0x00] &= ~(DRIVER_VCP << 4);
+            if (eeprom->channel_d_driver == DRIVER_VCP)
+                output[0x01] |= (DRIVER_VCP << 4);
+            else
+                output[0x01] &= ~(DRIVER_VCP << 4);
+
+            if (eeprom->suspend_pull_downs == 1)
+                output[0x0a] |= 0x4;
+            else
+                output[0x0a] &= ~0x4;
+
+            if (eeprom->channel_a_rs485enable)
+                output[0x0b] |= CHANNEL_IS_RS485 << 0;
+            else
+                output[0x0b] &= ~(CHANNEL_IS_RS485 << 0);
+            if (eeprom->channel_b_rs485enable)
+                output[0x0b] |= CHANNEL_IS_RS485 << 1;
+            else
+                output[0x0b] &= ~(CHANNEL_IS_RS485 << 1);
+            if (eeprom->channel_c_rs485enable)
+                output[0x0b] |= CHANNEL_IS_RS485 << 2;
+            else
+                output[0x0b] &= ~(CHANNEL_IS_RS485 << 2);
+            if (eeprom->channel_d_rs485enable)
+                output[0x0b] |= CHANNEL_IS_RS485 << 3;
+            else
+                output[0x0b] &= ~(CHANNEL_IS_RS485 << 3);
+
+            if (eeprom->group0_drive > DRIVE_16MA)
+                output[0x0c] |= DRIVE_16MA;
+            else
+                output[0x0c] |= eeprom->group0_drive;
+            if (eeprom->group0_schmitt == IS_SCHMITT)
+                output[0x0c] |= IS_SCHMITT;
+            if (eeprom->group0_slew == SLOW_SLEW)
+                output[0x0c] |= SLOW_SLEW;
+
+            if (eeprom->group1_drive > DRIVE_16MA)
+                output[0x0c] |= DRIVE_16MA<<4;
+            else
+                output[0x0c] |= eeprom->group1_drive<<4;
+            if (eeprom->group1_schmitt == IS_SCHMITT)
+                output[0x0c] |= IS_SCHMITT<<4;
+            if (eeprom->group1_slew == SLOW_SLEW)
+                output[0x0c] |= SLOW_SLEW<<4;
+
+            if (eeprom->group2_drive > DRIVE_16MA)
+                output[0x0d] |= DRIVE_16MA;
+            else
+                output[0x0d] |= eeprom->group2_drive;
+            if (eeprom->group2_schmitt == IS_SCHMITT)
+                output[0x0d] |= IS_SCHMITT;
+            if (eeprom->group2_slew == SLOW_SLEW)
+                output[0x0d] |= SLOW_SLEW;
+
+            if (eeprom->group3_drive > DRIVE_16MA)
+                output[0x0d] |= DRIVE_16MA<<4;
+            else
+                output[0x0d] |= eeprom->group3_drive<<4;
+            if (eeprom->group3_schmitt == IS_SCHMITT)
+                output[0x0d] |= IS_SCHMITT<<4;
+            if (eeprom->group3_slew == SLOW_SLEW)
+                output[0x0d] |= SLOW_SLEW<<4;
+
             output[0x18] = eeprom->chip;
-            fprintf(stderr,"FIXME: Build FT4232H specific EEPROM settings\n");
+
             break;
         case TYPE_232H:
             output[0x00] = type2bit(eeprom->channel_a_type, TYPE_232H);
@@ -3097,7 +3171,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int 
verbose)
     else if (ftdi->type == TYPE_R)
     {
         /* TYPE_R flags D2XX, not VCP as all others*/
-        eeprom->channel_a_driver = (~buf[0x00]) & DRIVER_VCP;
+        eeprom->channel_a_driver = ~buf[0x00] & DRIVER_VCP;
         eeprom->high_current     = buf[0x00] & HIGH_CURRENT_DRIVE_R;
         if ( (buf[0x01]&0x40) != 0x40)
             fprintf(stderr,
@@ -3119,15 +3193,26 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int 
verbose)
         eeprom->cbus_function[3] = (buf[0x15] >> 4) & 0x0f;
         eeprom->cbus_function[4] = buf[0x16] & 0x0f;
     }
-    else if ((ftdi->type == TYPE_2232H) ||(ftdi->type == TYPE_4232H))
+    else if ((ftdi->type == TYPE_2232H) || (ftdi->type == TYPE_4232H))
     {
-        eeprom->channel_a_type   = bit2type(buf[0x00] & 0x7);
         eeprom->channel_a_driver = buf[0x00] & DRIVER_VCP;
-        eeprom->channel_b_type   = bit2type(buf[0x01] & 0x7);
         eeprom->channel_b_driver = buf[0x01] & DRIVER_VCP;
 
         if (ftdi->type == TYPE_2232H)
+        {
+            eeprom->channel_a_type   = bit2type(buf[0x00] & 0x7);
+            eeprom->channel_b_type   = bit2type(buf[0x01] & 0x7);
             eeprom->suspend_dbus7    = buf[0x01] & SUSPEND_DBUS7_BIT;
+        }
+        else
+        {
+            eeprom->channel_c_driver = (buf[0x00] >> 4) & DRIVER_VCP;
+            eeprom->channel_d_driver = (buf[0x01] >> 4) & DRIVER_VCP;
+            eeprom->channel_a_rs485enable = buf[0x0b] & (CHANNEL_IS_RS485 << 
0);
+            eeprom->channel_b_rs485enable = buf[0x0b] & (CHANNEL_IS_RS485 << 
1);
+            eeprom->channel_c_rs485enable = buf[0x0b] & (CHANNEL_IS_RS485 << 
2);
+            eeprom->channel_d_rs485enable = buf[0x0b] & (CHANNEL_IS_RS485 << 
3);
+        }
 
         eeprom->chip = buf[0x18];
         eeprom->group0_drive   =  buf[0x0c]       & DRIVE_16MA;
@@ -3269,7 +3354,6 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int 
verbose)
                     fprintf(stdout,"C%d Function: %s\n", i,
                             cbush_mux[eeprom->cbus_function[i]]);
             }
-
         }
 
         if (ftdi->type == TYPE_R)
@@ -3375,6 +3459,24 @@ int ftdi_get_eeprom_value(struct ftdi_context *ftdi, 
enum ftdi_eeprom_value valu
         case CHANNEL_B_DRIVER:
             *value = ftdi->eeprom->channel_b_driver;
             break;
+        case CHANNEL_C_DRIVER:
+            *value = ftdi->eeprom->channel_c_driver;
+            break;
+        case CHANNEL_D_DRIVER:
+            *value = ftdi->eeprom->channel_d_driver;
+            break;
+        case CHANNEL_A_RS485:
+            *value = ftdi->eeprom->channel_a_rs485enable;
+            break;
+        case CHANNEL_B_RS485:
+            *value = ftdi->eeprom->channel_b_rs485enable;
+            break;
+        case CHANNEL_C_RS485:
+            *value = ftdi->eeprom->channel_c_rs485enable;
+            break;
+        case CHANNEL_D_RS485:
+            *value = ftdi->eeprom->channel_d_rs485enable;
+            break;
         case CBUS_FUNCTION_0:
             *value = ftdi->eeprom->cbus_function[0];
             break;
@@ -3544,6 +3646,24 @@ int ftdi_set_eeprom_value(struct ftdi_context *ftdi, 
enum ftdi_eeprom_value valu
         case CHANNEL_B_DRIVER:
             ftdi->eeprom->channel_b_driver = value;
             break;
+        case CHANNEL_C_DRIVER:
+            ftdi->eeprom->channel_c_driver = value;
+            break;
+        case CHANNEL_D_DRIVER:
+            ftdi->eeprom->channel_d_driver = value;
+            break;
+        case CHANNEL_A_RS485:
+            ftdi->eeprom->channel_a_rs485enable = value;
+            break;
+        case CHANNEL_B_RS485:
+            ftdi->eeprom->channel_b_rs485enable = value;
+            break;
+        case CHANNEL_C_RS485:
+            ftdi->eeprom->channel_c_rs485enable = value;
+            break;
+        case CHANNEL_D_RS485:
+            ftdi->eeprom->channel_d_rs485enable = value;
+            break;
         case CBUS_FUNCTION_0:
             ftdi->eeprom->cbus_function[0] = value;
             break;
diff --git a/src/ftdi.h b/src/ftdi.h
index 7bf5b6e..38b0668 100644
--- a/src/ftdi.h
+++ b/src/ftdi.h
@@ -301,7 +301,13 @@ enum ftdi_eeprom_value
     POWER_SAVE         = 45,
     CLOCK_POLARITY     = 46,
     DATA_ORDER         = 47,
-    FLOW_CONTROL       = 48
+    FLOW_CONTROL       = 48,
+    CHANNEL_C_DRIVER   = 49,
+    CHANNEL_D_DRIVER   = 50,
+    CHANNEL_A_RS485    = 51,
+    CHANNEL_B_RS485    = 52,
+    CHANNEL_C_RS485    = 53,
+    CHANNEL_D_RS485    = 54,
 };
 
 /**
@@ -354,6 +360,8 @@ enum ftdi_cbush_func {/* FIXME: Recheck value, especially 
the last */
 #define CHANNEL_IS_CPU  0x4
 #define CHANNEL_IS_FT1284 0x8
 
+#define CHANNEL_IS_RS485 0x10
+
 #define DRIVE_4MA  0
 #define DRIVE_8MA  1
 #define DRIVE_12MA 2
diff --git a/src/ftdi_i.h b/src/ftdi_i.h
index dd2d29b..8d8c77e 100644
--- a/src/ftdi_i.h
+++ b/src/ftdi_i.h
@@ -68,7 +68,7 @@ struct ftdi_eeprom
     /** serial number */
     char *serial;
 
-    /* 2232D/H(/FT4432H?) specific */
+    /* 2232D/H specific */
     /* Hardware type, 0 = RS232 Uart, 1 = 245 FIFO, 2 = CPU FIFO, 
        4 = OPTO Isolate */
     int channel_a_type;
@@ -76,6 +76,13 @@ struct ftdi_eeprom
     /*  Driver Type, 1 = VCP */
     int channel_a_driver;
     int channel_b_driver;
+    int channel_c_driver;
+    int channel_d_driver;
+    /* 4232H specific */
+    int channel_a_rs485enable;
+    int channel_b_rs485enable;
+    int channel_c_rs485enable;
+    int channel_d_rs485enable;
 
     /* Special function of FT232R/FT232H devices (and possibly others as well) 
*/
     /** CBUS pin function. See CBUS_xxx defines. */
-- 
1.7.0.4


--
libftdi - see http://www.intra2net.com/en/developer/libftdi for details.
To unsubscribe send a mail to libftdi+unsubscribe@xxxxxxxxxxxxxxxxxxxxxxx   

Current Thread