diff --git a/src/avrcache.c b/src/avrcache.c
index 98370827..c7bfae3a 100644
--- a/src/avrcache.c
+++ b/src/avrcache.c
@@ -372,6 +372,9 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) {
     AVRMEM *mem = mems[i].mem;
     AVR_Cache *cp = mems[i].cp;
 
+    if(!mem)
+      continue;
+
     if(!cp->cont)           // Ensure cache is initialised from now on
       if(initCache(cp, pgm, p) < 0) {
         if(quell_progress)
@@ -380,7 +383,7 @@ int avr_flush_cache(const PROGRAMMER *pgm, const AVRPART *p) {
         return LIBAVRDUDE_GENERAL_FAILURE;
       }
 
-    if(chiperase || !mem || mems[i].zopaddr < 0)
+    if(chiperase || mems[i].zopaddr < 0)
       continue;
 
     int n=mems[i].zopaddr;
diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in
index cdc7fff1..11da317f 100644
--- a/src/avrdude.conf.in
+++ b/src/avrdude.conf.in
@@ -2131,6 +2131,19 @@ programmer
     hvupdi_support         = 1;
 ;
 
+#------------------------------------------------------------
+# xplainedmini_tpi
+#------------------------------------------------------------
+
+programmer
+    id                     = "xplainedmini_tpi";
+    desc                   = "Atmel AVR XplainedMini in TPI mode";
+    type                   = "jtagice3_tpi";
+    prog_modes             = PM_TPI;
+    connection_type        = usb;
+    usbpid                 = 0x2145;
+;
+
 #------------------------------------------------------------
 # atmelice
 #------------------------------------------------------------
@@ -2197,6 +2210,19 @@ programmer
     usbpid                 = 0x2141;
 ;
 
+#------------------------------------------------------------
+# atmelice_tpi
+#------------------------------------------------------------
+
+programmer
+    id                     = "atmelice_tpi";
+    desc                   = "Atmel-ICE (ARM/AVR) in TPI mode";
+    type                   = "jtagice3_tpi";
+    prog_modes             = PM_TPI;
+    connection_type        = usb;
+    usbpid                 = 0x2141;
+;
+
 #------------------------------------------------------------
 # powerdebugger
 #------------------------------------------------------------
@@ -2263,6 +2289,19 @@ programmer
     usbpid                 = 0x2144;
 ;
 
+#------------------------------------------------------------
+# powerdebugger_tpi
+#------------------------------------------------------------
+
+programmer
+    id                     = "powerdebugger_tpi";
+    desc                   = "Atmel PowerDebugger (ARM/AVR) in TPI mode";
+    type                   = "jtagice3_tpi";
+    prog_modes             = PM_TPI;
+    connection_type        = usb;
+    usbpid                 = 0x2144;
+;
+
 #------------------------------------------------------------
 # pickit4_updi
 #------------------------------------------------------------
@@ -2303,6 +2342,19 @@ programmer
     usbpid                 = 0x2177, 0x2178, 0x2179;
 ;
 
+#------------------------------------------------------------
+# pickit4_tpi
+#------------------------------------------------------------
+
+programmer
+    id                     = "pickit4_tpi";
+    desc                   = "MPLAB(R) PICkit 4 in TPI mode";
+    type                   = "jtagice3_tpi";
+    prog_modes             = PM_TPI;
+    connection_type        = usb;
+    usbpid                 = 0x2177, 0x2178, 0x2179;
+;
+
 #------------------------------------------------------------
 # snap_updi
 #------------------------------------------------------------
@@ -2343,6 +2395,19 @@ programmer
     usbpid                 = 0x2180, 0x217f, 0x2181;
 ;
 
+#------------------------------------------------------------
+# snap_tpi
+#------------------------------------------------------------
+
+programmer
+    id                     = "snap_tpi";
+    desc                   = "MPLAB(R) SNAP in TPI mode";
+    type                   = "jtagice3_tpi";
+    prog_modes             = PM_TPI;
+    connection_type        = usb;
+    usbpid                 = 0x2180, 0x217f, 0x2181;
+;
+
 #------------------------------------------------------------
 # pkobn_updi
 #------------------------------------------------------------
@@ -13440,12 +13505,6 @@ part
         offset             = 0x3f00;
     ;
 
-    memory "lockbits"
-        size               = 1;
-        page_size          = 16;
-        offset             = 0x3f00;
-    ;
-
     memory "signature"
         size               = 3;
         page_size          = 16;
@@ -13539,6 +13598,14 @@ part parent ".reduced_core_tiny"
         offset             = 0x4000;
         blocksize          = 128;
     ;
+
+    memory "fuse"
+        size               = 1;
+        page_size          = 16;
+        n_word_writes      = 2;
+        offset             = 0x3f40;
+        blocksize          = 4;
+    ;
 ;
 
 #------------------------------------------------------------
@@ -13559,6 +13626,14 @@ part parent ".reduced_core_tiny"
         offset             = 0x4000;
         blocksize          = 128;
     ;
+
+    memory "fuse"
+        size               = 1;
+        page_size          = 16;
+        n_word_writes      = 4;
+        offset             = 0x3f40;
+        blocksize          = 4;
+    ;
 ;
 
 #------------------------------------------------------------
@@ -13578,6 +13653,12 @@ part parent ".reduced_core_tiny"
         offset             = 0x4000;
         blocksize          = 128;
     ;
+
+    memory "sigrow"
+        size               = 16;
+        page_size          = 16;
+        offset             = 0x3fc6;
+    ;
 ;
 
 #------------------------------------------------------------
@@ -13597,6 +13678,12 @@ part parent ".reduced_core_tiny"
         offset             = 0x4000;
         blocksize          = 128;
     ;
+
+    memory "sigrow"
+        size               = 16;
+        page_size          = 16;
+        offset             = 0x3fc6;
+    ;
 ;
 
 #------------------------------------------------------------
diff --git a/src/jtag3.c b/src/jtag3.c
index 146bed4b..7e660b92 100644
--- a/src/jtag3.c
+++ b/src/jtag3.c
@@ -63,7 +63,7 @@ struct pdata
   unsigned long eeprom_pageaddr;
   unsigned int eeprom_pagesize;
 
-  int prog_enabled;	     /* Cached value of PROGRAMMING status. */
+  int prog_enabled;         /* Cached value of PROGRAMMING status. */
 
   /* JTAG chain stuff */
   unsigned char jtagchain[4];
@@ -84,11 +84,12 @@ struct pdata
  * pgm->flag is marked as "for private use of the programmer".
  * The following defines this programmer's use of that field.
  */
-#define PGM_FL_IS_DW		(0x0001)
+#define PGM_FL_IS_DW            (0x0001)
 #define PGM_FL_IS_PDI           (0x0002)
 #define PGM_FL_IS_JTAG          (0x0004)
 #define PGM_FL_IS_EDBG          (0x0008)
 #define PGM_FL_IS_UPDI          (0x0010)
+#define PGM_FL_IS_TPI           (0x0020)
 
 static int jtag3_open(PROGRAMMER *pgm, const char *port);
 static int jtag3_edbg_prepare(const PROGRAMMER *pgm);
@@ -164,6 +165,22 @@ u16_to_b2(unsigned char *b, unsigned short l)
   b[1] = (l >> 8) & 0xff;
 }
 
+static void
+u32_to_b4_big_endian(unsigned char *b, unsigned long l)
+{
+  b[0] = (l >> 24) & 0xff;
+  b[1] = (l >> 16) & 0xff;
+  b[2] = (l >> 8) & 0xff;
+  b[3] = l & 0xff;
+}
+
+static void
+u16_to_b2_big_endian(unsigned char *b, unsigned short l)
+{
+  b[0] = (l >> 8) & 0xff;
+  b[1] = l & 0xff;
+}
+
 static bool matches(const char *s, const char *pat)
 {
   return strncmp(s, pat, strlen(pat)) == 0;
@@ -196,9 +213,9 @@ static void jtag3_prmsg(const PROGRAMMER *pgm, unsigned char *data, size_t len)
     for (i = 0; i < len; i++) {
       msg_trace("%02x ", data[i]);
       if (i % 16 == 15)
-	msg_trace("\n");
+        msg_trace("\n");
       else
-	msg_trace(" ");
+        msg_trace(" ");
     }
     if (i % 16 != 0)
       msg_trace("\n");
@@ -236,47 +253,45 @@ static void jtag3_prmsg(const PROGRAMMER *pgm, unsigned char *data, size_t len)
       msg_info("FAILED");
       if (len > 3)
       {
-	char reason[50];
-	sprintf(reason, "0x%02x", data[3]);
-	switch (data[3])
-	{
-	  case RSP3_FAIL_NO_ANSWER:
-	    strcpy(reason, "target does not answer");
-	    break;
+        char reason[50];
+        sprintf(reason, "0x%02x", data[3]);
+        switch (data[3]) {
+          case RSP3_FAIL_NO_ANSWER:
+            strcpy(reason, "target does not answer");
+            break;
 
-	  case RSP3_FAIL_NO_TARGET_POWER:
-	    strcpy(reason, "no target power");
-	    break;
+          case RSP3_FAIL_NO_TARGET_POWER:
+            strcpy(reason, "no target power");
+            break;
 
-	  case RSP3_FAIL_NOT_UNDERSTOOD:
-	    strcpy(reason, "command not understood");
-	    break;
+          case RSP3_FAIL_NOT_UNDERSTOOD:
+            strcpy(reason, "command not understood");
+            break;
 
-	  case RSP3_FAIL_WRONG_MODE:
-	    strcpy(reason, "wrong (programming) mode");
-	    break;
+          case RSP3_FAIL_WRONG_MODE:
+            strcpy(reason, "wrong (programming) mode");
+            break;
 
-	  case RSP3_FAIL_PDI:
-	    strcpy(reason, "PDI failure");
-	    break;
+          case RSP3_FAIL_PDI:
+            strcpy(reason, "PDI failure");
+            break;
 
-	  case RSP3_FAIL_UNSUPP_MEMORY:
-	    strcpy(reason, "unsupported memory type");
-	    break;
+          case RSP3_FAIL_UNSUPP_MEMORY:
+            strcpy(reason, "unsupported memory type");
+            break;
 
-	  case RSP3_FAIL_WRONG_LENGTH:
-	    strcpy(reason, "wrong length in memory access");
-	    break;
+          case RSP3_FAIL_WRONG_LENGTH:
+            strcpy(reason, "wrong length in memory access");
+            break;
 
-	  case RSP3_FAIL_DEBUGWIRE:
-	    strcpy(reason, "debugWIRE communication failed");
-	    break;
-	}
-	msg_info(", reason: %s\n", reason);
+          case RSP3_FAIL_DEBUGWIRE:
+            strcpy(reason, "debugWIRE communication failed");
+            break;
+        }
+        msg_info(", reason: %s\n", reason);
       }
-      else
-      {
-	msg_info(", unspecified reason\n");
+      else {
+        msg_info(", unspecified reason\n");
       }
       break;
 
@@ -288,29 +303,27 @@ static void jtag3_prmsg(const PROGRAMMER *pgm, unsigned char *data, size_t len)
     case RSP3_INFO:
       msg_info("Info returned:\n");
       for (i = 2; i < len; i++) {
-	if (isprint(data[i]))
-	  msg_info("%c", data[i]);
-	else
-	  msg_info("\\%03o", data[i]);
+        if (isprint(data[i]))
+          msg_info("%c", data[i]);
+        else
+          msg_info("\\%03o", data[i]);
       }
       msg_info("\n");
       break;
 
     case RSP3_PC:
-      if (len < 7)
-      {
-	msg_info("PC reply too short\n");
+      if (len < 7) {
+        msg_info("PC reply too short\n");
       }
-      else
-      {
-	unsigned long pc = (data[6] << 24) | (data[5] << 16)
-	  | (data[4] << 8) | data[3];
-	msg_info("PC 0x%0lx\n", pc);
+      else {
+        unsigned long pc = (data[6] << 24) | (data[5] << 16)
+          | (data[4] << 8) | data[3];
+        msg_info("PC 0x%0lx\n", pc);
       }
       break;
 
-  default:
-    msg_info("unknown message 0x%02x\n", data[1]);
+    default:
+      msg_info("unknown message 0x%02x\n", data[1]);
   }
 }
 
@@ -331,9 +344,9 @@ static void jtag3_prevent(const PROGRAMMER *pgm, unsigned char *data, size_t len
     for (i = 0; i < len; i++) {
       msg_trace("%02x ", data[i]);
       if (i % 16 == 15)
-	msg_trace("\n");
+        msg_trace("\n");
       else
-	msg_trace(" ");
+        msg_trace(" ");
     }
     if (i % 16 != 0)
       msg_trace("\n");
@@ -360,58 +373,56 @@ static void jtag3_prevent(const PROGRAMMER *pgm, unsigned char *data, size_t len
   }
 
   switch (data[5]) {
-  case EVT3_BREAK:
-    msg_info("BREAK");
-    if (len >= 11) {
-      msg_info(", PC = 0x%lx, reason ", b4_to_u32(data + 6));
-      switch (data[10]) {
-      case 0x00:
-	msg_info("unspecified");
-	break;
-      case 0x01:
-	msg_info("program break");
-	break;
-      case 0x02:
-	msg_info("data break PDSB");
-	break;
-      case 0x03:
-	msg_info("data break PDMSB");
-	break;
-      default:
-	msg_info("unknown: 0x%02x", data[10]);
+    case EVT3_BREAK:
+      msg_info("BREAK");
+      if (len >= 11) {
+        msg_info(", PC = 0x%lx, reason ", b4_to_u32(data + 6));
+        switch (data[10]) {
+          case 0x00:
+            msg_info("unspecified");
+            break;
+          case 0x01:
+            msg_info("program break");
+            break;
+          case 0x02:
+            msg_info("data break PDSB");
+            break;
+          case 0x03:
+            msg_info("data break PDMSB");
+            break;
+          default:
+          msg_info("unknown: 0x%02x", data[10]);
+        }
+        /* There are two more bytes of data which always appear to be
+        * 0x01, 0x00.  Purpose unknown. */
       }
-      /* There are two more bytes of data which always appear to be
-       * 0x01, 0x00.  Purpose unknown. */
-    }
-    break;
+      break;
 
-  case EVT3_SLEEP:
-    if (len >= 8 && data[7] == 0)
-      msg_info("sleeping");
-    else if (len >= 8 && data[7] == 1)
-      msg_info("wakeup");
-    else
-      msg_info("unknown SLEEP event");
-    break;
+    case EVT3_SLEEP:
+      if (len >= 8 && data[7] == 0)
+        msg_info("sleeping");
+      else if (len >= 8 && data[7] == 1)
+        msg_info("wakeup");
+      else
+        msg_info("unknown SLEEP event");
+      break;
 
-  case EVT3_POWER:
-    if (len >= 8 && data[7] == 0)
-      msg_info("power-down");
-    else if (len >= 8 && data[7] == 1)
-      msg_info("power-up");
-    else
-      msg_info("unknown POWER event");
-    break;
+    case EVT3_POWER:
+      if (len >= 8 && data[7] == 0)
+        msg_info("power-down");
+      else if (len >= 8 && data[7] == 1)
+        msg_info("power-up");
+      else
+        msg_info("unknown POWER event");
+      break;
 
-  default:
-    msg_info("UNKNOWN 0x%02x", data[5]);
-    break;
+    default:
+      msg_info("UNKNOWN 0x%02x", data[5]);
+      break;
   }
   msg_info("\n");
 }
 
-
-
 int jtag3_send(const PROGRAMMER *pgm, unsigned char *data, size_t len) {
   unsigned char *buf;
 
@@ -421,11 +432,10 @@ int jtag3_send(const PROGRAMMER *pgm, unsigned char *data, size_t len) {
   msg_debug("\n");
   pmsg_debug("jtag3_send(): sending %lu bytes\n", (unsigned long) len);
 
-  if ((buf = malloc(len + 4)) == NULL)
-    {
-      pmsg_error("out of memory");
-      return -1;
-    }
+  if ((buf = malloc(len + 4)) == NULL) {
+    pmsg_error("out of memory");
+    return -1;
+  }
 
   buf[0] = TOKEN;
   buf[1] = 0;                   /* dummy */
@@ -448,11 +458,10 @@ static int jtag3_edbg_send(const PROGRAMMER *pgm, unsigned char *data, size_t le
   unsigned char status[USBDEV_MAX_XFER_3];
   int rv;
 
-  if (verbose >= 4)
-    {
-      memset(buf, 0, USBDEV_MAX_XFER_3);
-      memset(status, 0, USBDEV_MAX_XFER_3);
-    }
+  if (verbose >= 4) {
+    memset(buf, 0, USBDEV_MAX_XFER_3);
+    memset(status, 0, USBDEV_MAX_XFER_3);
+  }
 
   msg_debug("\n");
   pmsg_debug("jtag3_edbg_send(): sending %lu bytes\n", (unsigned long) len);
@@ -460,60 +469,55 @@ static int jtag3_edbg_send(const PROGRAMMER *pgm, unsigned char *data, size_t le
   /* 4 bytes overhead for CMD, fragment #, and length info */
   int max_xfer = pgm->fd.usb.max_xfer;
   int nfragments = (len + max_xfer - 1) / max_xfer;
-  if (nfragments > 1)
-    {
-      pmsg_debug("jtag3_edbg_send(): fragmenting into %d packets\n", nfragments);
-    }
+  if (nfragments > 1) {
+    pmsg_debug("jtag3_edbg_send(): fragmenting into %d packets\n", nfragments);
+  }
   int frag;
-  for (frag = 0; frag < nfragments; frag++)
-    {
-      int this_len;
+  for (frag = 0; frag < nfragments; frag++) {
+    int this_len;
 
-      /* All fragments have the (CMSIS-DAP layer) CMD, the fragment
-       * identifier, and the length field. */
-      buf[0] = EDBG_VENDOR_AVR_CMD;
-      buf[1] = ((frag + 1) << 4) | nfragments;
+    /* All fragments have the (CMSIS-DAP layer) CMD, the fragment
+      * identifier, and the length field. */
+    buf[0] = EDBG_VENDOR_AVR_CMD;
+    buf[1] = ((frag + 1) << 4) | nfragments;
 
-      if (frag == 0)
-        {
-          /* Only first fragment has TOKEN and seq#, thus four bytes
-           * less payload than subsequent fragments. */
-          this_len = len < max_xfer - 8? len: max_xfer - 8;
-          buf[2] = (this_len + 4) >> 8;
-          buf[3] = (this_len + 4) & 0xff;
-          buf[4] = TOKEN;
-          buf[5] = 0;                   /* dummy */
-          u16_to_b2(buf + 6, PDATA(pgm)->command_sequence);
-          memcpy(buf + 8, data, this_len);
-        }
-      else
-        {
-          this_len = len < max_xfer - 4? len: max_xfer - 4;
-          buf[2] = (this_len) >> 8;
-          buf[3] = (this_len) & 0xff;
-          memcpy(buf + 4, data, this_len);
-        }
-
-      if (serial_send(&pgm->fd, buf, max_xfer) != 0) {
-        pmsg_notice("jtag3_edbg_send(): unable to send command to serial port\n");
-        return -1;
-      }
-      rv = serial_recv(&pgm->fd, status, max_xfer);
-
-      if (rv < 0) {
-        /* timeout in receive */
-        pmsg_notice2("jtag3_edbg_send(): timeout receiving packet\n");
-        return -1;
-      }
-      if (status[0] != EDBG_VENDOR_AVR_CMD ||
-          (frag == nfragments - 1 && status[1] != 0x01))
-        {
-          /* what to do in this case? */
-          pmsg_notice("jtag3_edbg_send(): unexpected response 0x%02x, 0x%02x\n", status[0], status[1]);
-        }
-      data += this_len;
-      len -= this_len;
+    if (frag == 0) {
+      /* Only first fragment has TOKEN and seq#, thus four bytes
+        * less payload than subsequent fragments. */
+      this_len = len < max_xfer - 8? len: max_xfer - 8;
+      buf[2] = (this_len + 4) >> 8;
+      buf[3] = (this_len + 4) & 0xff;
+      buf[4] = TOKEN;
+      buf[5] = 0;                   /* dummy */
+      u16_to_b2(buf + 6, PDATA(pgm)->command_sequence);
+      memcpy(buf + 8, data, this_len);
     }
+    else {
+      this_len = len < max_xfer - 4? len: max_xfer - 4;
+      buf[2] = (this_len) >> 8;
+      buf[3] = (this_len) & 0xff;
+      memcpy(buf + 4, data, this_len);
+    }
+
+    if (serial_send(&pgm->fd, buf, max_xfer) != 0) {
+      pmsg_notice("jtag3_edbg_send(): unable to send command to serial port\n");
+      return -1;
+    }
+    rv = serial_recv(&pgm->fd, status, max_xfer);
+
+    if (rv < 0) {
+      /* timeout in receive */
+      pmsg_notice2("jtag3_edbg_send(): timeout receiving packet\n");
+      return -1;
+    }
+    if (status[0] != EDBG_VENDOR_AVR_CMD ||
+        (frag == nfragments - 1 && status[1] != 0x01)) {
+      /* what to do in this case? */
+      pmsg_notice("jtag3_edbg_send(): unexpected response 0x%02x, 0x%02x\n", status[0], status[1]);
+    }
+    data += this_len;
+    len -= this_len;
+  }
 
   return 0;
 }
@@ -771,7 +775,7 @@ int jtag3_recv(const PROGRAMMER *pgm, unsigned char **msg) {
 
     if ((rv & USB_RECV_FLAG_EVENT) != 0) {
       if (verbose >= 3)
-	jtag3_prevent(pgm, *msg, rv & USB_RECV_LENGTH_MASK);
+        jtag3_prevent(pgm, *msg, rv & USB_RECV_LENGTH_MASK);
 
       free(*msg);
       continue;
@@ -783,7 +787,7 @@ int jtag3_recv(const PROGRAMMER *pgm, unsigned char **msg) {
       "Got message seqno %d (command_sequence == %d)\n", r_seqno, PDATA(pgm)->command_sequence);
     if (r_seqno == PDATA(pgm)->command_sequence) {
       if (++(PDATA(pgm)->command_sequence) == 0xffff)
-	PDATA(pgm)->command_sequence = 0;
+        PDATA(pgm)->command_sequence = 0;
       /*
        * We move the payload to the beginning of the buffer, to make
        * the job easier for the caller.  We have to return the
@@ -802,8 +806,7 @@ int jtag3_recv(const PROGRAMMER *pgm, unsigned char **msg) {
 }
 
 int jtag3_command(const PROGRAMMER *pgm, unsigned char *cmd, unsigned int cmdlen,
-		   unsigned char **resp, const char *descr)
-{
+                  unsigned char **resp, const char *descr) {
   int status;
   unsigned char c;
 
@@ -824,8 +827,8 @@ int jtag3_command(const PROGRAMMER *pgm, unsigned char *cmd, unsigned int cmdlen
 
   c = (*resp)[1] & RSP3_STATUS_MASK;
   if (c != RSP3_OK) {
-    if ((c == RSP3_FAILED) && ((*resp)[3] == RSP3_FAIL_OCD_LOCKED ||
-			       (*resp)[3] == RSP3_FAIL_CRC_FAILURE)) {
+    if ((c == RSP3_FAILED) &&
+        ((*resp)[3] == RSP3_FAIL_OCD_LOCKED || (*resp)[3] == RSP3_FAIL_CRC_FAILURE)) {
       pmsg_error("device is locked; chip erase required to unlock\n");
     } else {
       pmsg_notice("bad response to %s command: 0x%02x\n", descr, c);
@@ -850,9 +853,9 @@ int jtag3_getsync(const PROGRAMMER *pgm, int mode) {
    * firmware bug where they complained about it. */
   if ((pgm->flag & PGM_FL_IS_EDBG) &&
       !matches(ldata(lfirst(pgm->id)), "xplainedmini")) {
-      if (jtag3_edbg_prepare(pgm) < 0) {
-        return -1;
-      }
+    if (jtag3_edbg_prepare(pgm) < 0) {
+      return -1;
+    }
   }
 
   /* Get the sign-on information. */
@@ -918,9 +921,7 @@ static int jtag3_unlock_erase_key(const PROGRAMMER *pgm, const AVRPART *p) {
  * There is no chip erase functionality in debugWire mode.
  */
 static int jtag3_chip_erase_dw(const PROGRAMMER *pgm, const AVRPART *p) {
-
   pmsg_error("chip erase not supported in debugWire mode\n");
-
   return 0;
 }
 
@@ -970,15 +971,15 @@ static int jtag3_program_disable(const PROGRAMMER *pgm) {
 }
 
 static int jtag3_set_sck_xmega_pdi(const PROGRAMMER *pgm, unsigned char *clk) {
-    return jtag3_setparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_PDI, clk, 2);
+  return jtag3_setparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_PDI, clk, 2);
 }
 
 static int jtag3_set_sck_xmega_jtag(const PROGRAMMER *pgm, unsigned char *clk) {
-    return jtag3_setparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_JTAG, clk, 2);
+  return jtag3_setparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_JTAG, clk, 2);
 }
 
 static int jtag3_set_sck_mega_jtag(const PROGRAMMER *pgm, unsigned char *clk) {
-    return jtag3_setparm(pgm, SCOPE_AVR, 1, PARM3_CLK_MEGA_PROG, clk, 2);
+  return jtag3_setparm(pgm, SCOPE_AVR, 1, PARM3_CLK_MEGA_PROG, clk, 2);
 }
 
 
@@ -1067,8 +1068,7 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
     else
       PDATA(pgm)->set_sck = jtag3_set_sck_mega_jtag;
   }
-  if (pgm->bitclock != 0.0 && PDATA(pgm)->set_sck != NULL)
-  {
+  if (pgm->bitclock != 0.0 && PDATA(pgm)->set_sck != NULL) {
     unsigned int clock = 1E-3 / pgm->bitclock; /* kHz */
     pmsg_notice2("jtag3_initialize(): "
       "trying to set JTAG clock to %u kHz\n", clock);
@@ -1078,8 +1078,7 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
       return -1;
   }
   jtag3_print_parms1(pgm, progbuf, stderr);
-  if (conn == PARM3_CONN_JTAG)
-  {
+  if (conn == PARM3_CONN_JTAG) {
     pmsg_notice2("jtag3_initialize(): "
       "trying to set JTAG daisy-chain info to %d,%d,%d,%d\n",
       PDATA(pgm)->jtagchain[0], PDATA(pgm)->jtagchain[1],
@@ -1089,8 +1088,7 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
   }
 
   /* set device descriptor data */
-  if ((p->prog_modes & PM_PDI))
-  {
+  if ((p->prog_modes & PM_PDI)) {
     struct xmega_device_desc xd;
     LNODEID ln;
     AVRMEM * m;
@@ -1101,41 +1099,40 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
     for (ln = lfirst(p->mem); ln; ln = lnext(ln)) {
       m = ldata(ln);
       if (strcmp(m->desc, "flash") == 0) {
-	if (m->readsize != 0 && m->readsize < m->page_size)
-	  PDATA(pgm)->flash_pagesize = m->readsize;
-	else
-	  PDATA(pgm)->flash_pagesize = m->page_size;
-	u16_to_b2(xd.flash_page_size, m->page_size);
+        if (m->readsize != 0 && m->readsize < m->page_size)
+          PDATA(pgm)->flash_pagesize = m->readsize;
+        else
+          PDATA(pgm)->flash_pagesize = m->page_size;
+        u16_to_b2(xd.flash_page_size, m->page_size);
       } else if (strcmp(m->desc, "eeprom") == 0) {
-	PDATA(pgm)->eeprom_pagesize = m->page_size;
-	xd.eeprom_page_size = m->page_size;
-	u16_to_b2(xd.eeprom_size, m->size);
-	u32_to_b4(xd.nvm_eeprom_offset, m->offset);
+        PDATA(pgm)->eeprom_pagesize = m->page_size;
+        xd.eeprom_page_size = m->page_size;
+        u16_to_b2(xd.eeprom_size, m->size);
+        u32_to_b4(xd.nvm_eeprom_offset, m->offset);
       } else if (strcmp(m->desc, "application") == 0) {
-	u32_to_b4(xd.app_size, m->size);
-	u32_to_b4(xd.nvm_app_offset, m->offset);
+        u32_to_b4(xd.app_size, m->size);
+        u32_to_b4(xd.nvm_app_offset, m->offset);
       } else if (strcmp(m->desc, "boot") == 0) {
-	u16_to_b2(xd.boot_size, m->size);
-	u32_to_b4(xd.nvm_boot_offset, m->offset);
+        u16_to_b2(xd.boot_size, m->size);
+        u32_to_b4(xd.nvm_boot_offset, m->offset);
       } else if (strcmp(m->desc, "fuse1") == 0) {
-	u32_to_b4(xd.nvm_fuse_offset, m->offset & ~7);
+        u32_to_b4(xd.nvm_fuse_offset, m->offset & ~7);
       } else if (matches(m->desc, "lock")) {
-	u32_to_b4(xd.nvm_lock_offset, m->offset);
+        u32_to_b4(xd.nvm_lock_offset, m->offset);
       } else if (strcmp(m->desc, "usersig") == 0 ||
                  strcmp(m->desc, "userrow") == 0) {
-	u32_to_b4(xd.nvm_user_sig_offset, m->offset);
+        u32_to_b4(xd.nvm_user_sig_offset, m->offset);
       } else if (strcmp(m->desc, "prodsig") == 0) {
-	u32_to_b4(xd.nvm_prod_sig_offset, m->offset);
+        u32_to_b4(xd.nvm_prod_sig_offset, m->offset);
       } else if (strcmp(m->desc, "data") == 0) {
-	u32_to_b4(xd.nvm_data_offset, m->offset);
+        u32_to_b4(xd.nvm_data_offset, m->offset);
       }
     }
 
     if (jtag3_setparm(pgm, SCOPE_AVR, 2, PARM3_DEVICEDESC, (unsigned char *)&xd, sizeof xd) < 0)
       return -1;
   }
-  else if ((p->prog_modes & PM_UPDI))
-  {
+  else if ((p->prog_modes & PM_UPDI)) {
     struct updi_device_desc xd;
     LNODEID ln;
     AVRMEM *m;
@@ -1144,11 +1141,9 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
     u16_to_b2(xd.ocd_base_addr, p->ocd_base);
     xd.hvupdi_variant = p->hvupdi_variant;
 
-    for (ln = lfirst(p->mem); ln; ln = lnext(ln))
-    {
+    for (ln = lfirst(p->mem); ln; ln = lnext(ln)) {
       m = ldata(ln);
-      if (strcmp(m->desc, "flash") == 0)
-      {
+      if (strcmp(m->desc, "flash") == 0) {
         u16_to_b2(xd.prog_base, m->offset&0xFFFF);
         xd.prog_base_msb = m->offset>>16;
 
@@ -1166,8 +1161,7 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
         else
           xd.address_mode = UPDI_ADDRESS_MODE_16BIT;
       }
-      else if (strcmp(m->desc, "eeprom") == 0)
-      {
+      else if (strcmp(m->desc, "eeprom") == 0) {
         PDATA(pgm)->eeprom_pagesize = m->page_size;
         xd.eeprom_page_size = m->page_size;
 
@@ -1175,24 +1169,20 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
         u16_to_b2(xd.eeprom_base, m->offset);
       }
       else if (strcmp(m->desc, "usersig") == 0 ||
-               strcmp(m->desc, "userrow") == 0)
-      {
+               strcmp(m->desc, "userrow") == 0) {
         u16_to_b2(xd.user_sig_bytes, m->size);
         u16_to_b2(xd.user_sig_base, m->offset);
       }
-      else if (strcmp(m->desc, "signature") == 0)
-      {
+      else if (strcmp(m->desc, "signature") == 0) {
         u16_to_b2(xd.signature_base, m->offset);
         xd.device_id[0] = p->signature[1];
         xd.device_id[1] = p->signature[2];
       }
-      else if (strcmp(m->desc, "fuses") == 0)
-      {
+      else if (strcmp(m->desc, "fuses") == 0) {
         xd.fuses_bytes = m->size;
         u16_to_b2(xd.fuses_base, m->offset);
       }
-      else if (strcmp(m->desc, "lock") == 0)
-      {
+      else if (strcmp(m->desc, "lock") == 0) {
         u16_to_b2(xd.lockbits_base, m->offset);
       }
     }
@@ -1205,7 +1195,7 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
       for (LNODEID ln = lfirst(pgm->hvupdi_support); ln; ln = lnext(ln)) {
         if(*(int *) ldata(ln) == p->hvupdi_variant) {
           pmsg_notice("sending HV pulse to targets %s pin\n",
-            p->hvupdi_variant == HV_UPDI_VARIANT_0? "UPDI": "RESET");
+                      p->hvupdi_variant == HV_UPDI_VARIANT_0? "UPDI": "RESET");
           parm[0] = PARM3_UPDI_HV_SIMPLE_PULSE;
           break;
         }
@@ -1250,8 +1240,7 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
     if (jtag3_setparm(pgm, SCOPE_AVR, 2, PARM3_DEVICEDESC, (unsigned char *)&xd, sizeof xd) < 0)
       return -1;
   }
-  else
-  {
+  else {
     struct mega_device_desc md;
     LNODEID ln;
     AVRMEM * m;
@@ -1262,18 +1251,18 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
     for (ln = lfirst(p->mem); ln; ln = lnext(ln)) {
       m = ldata(ln);
       if (strcmp(m->desc, "flash") == 0) {
-	if (m->readsize != 0 && m->readsize < m->page_size)
-	  PDATA(pgm)->flash_pagesize = m->readsize;
-	else
-	  PDATA(pgm)->flash_pagesize = m->page_size;
-	u16_to_b2(md.flash_page_size, m->page_size);
-	u32_to_b4(md.flash_size, (flashsize = m->size));
-	// do we need it?  just a wild guess
-	u32_to_b4(md.boot_address, (m->size - m->page_size * 4) / 2);
+        if (m->readsize != 0 && m->readsize < m->page_size)
+          PDATA(pgm)->flash_pagesize = m->readsize;
+        else
+          PDATA(pgm)->flash_pagesize = m->page_size;
+        u16_to_b2(md.flash_page_size, m->page_size);
+        u32_to_b4(md.flash_size, (flashsize = m->size));
+        // do we need it?  just a wild guess
+        u32_to_b4(md.boot_address, (m->size - m->page_size * 4) / 2);
       } else if (strcmp(m->desc, "eeprom") == 0) {
-	PDATA(pgm)->eeprom_pagesize = m->page_size;
-	md.eeprom_page_size = m->page_size;
-	u16_to_b2(md.eeprom_size, m->size);
+        PDATA(pgm)->eeprom_pagesize = m->page_size;
+        md.eeprom_page_size = m->page_size;
+        u16_to_b2(md.eeprom_size, m->size);
       }
     }
 
@@ -1283,11 +1272,11 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
 
       /* lacking a proper definition, guess the OCD revision */
       if (p->prog_modes & PM_debugWIRE)
-	ocdrev = 1;		/* exception: ATtiny13, 2313, 4313 */
+        ocdrev = 1;        /* exception: ATtiny13, 2313, 4313 */
       else if (flashsize > 128 * 1024)
-	ocdrev = 4;
+        ocdrev = 4;
       else
-	ocdrev = 3;		/* many exceptions from that, actually */
+        ocdrev = 3;        /* many exceptions from that, actually */
       pmsg_warning("part definition for %s lacks ocdrev; guessing %d\n", p->desc, ocdrev);
       md.ocd_revision = ocdrev;
     } else {
@@ -1315,7 +1304,7 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
     cmd[0] = SCOPE_AVR;
     cmd[1] = CMD3_SIGN_ON;
     cmd[2] = 0;
-    cmd[3] = use_ext_reset;			/* external reset */
+    cmd[3] = use_ext_reset;            /* external reset */
 
     if ((status = jtag3_command(pgm, cmd, 4, &resp, "AVR sign-on")) >= 0)
       break;
@@ -1324,9 +1313,9 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
   }
 
   if (use_ext_reset > 1) {
-      if(strcmp(pgm->type, "JTAGICE3") == 0 && (p->prog_modes & (PM_JTAG | PM_JTAGmkI | PM_XMEGAJTAG | PM_AVR32JTAG)))
-        pmsg_error("JTAGEN fuse disabled?\n");
-      return -1;
+    if(strcmp(pgm->type, "JTAGICE3") == 0 && (p->prog_modes & (PM_JTAG | PM_JTAGmkI | PM_XMEGAJTAG | PM_AVR32JTAG)))
+      pmsg_error("JTAGEN fuse disabled?\n");
+    return -1;
   }
 
   /*
@@ -1345,12 +1334,12 @@ static int jtag3_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
     if (p->prog_modes & PM_UPDI) {
       /* Partial Family_ID has been returned */
       pmsg_notice("partial Family_ID returned: \"%c%c%c%c\"\n",
-        resp[3], resp[4], resp[5], resp[6]);
+                  resp[3], resp[4], resp[5], resp[6]);
     }
     else
       /* JTAG ID has been returned */
       pmsg_notice("JTAG ID returned: 0x%02x 0x%02x 0x%02x 0x%02x\n",
-        resp[3], resp[4], resp[5], resp[6]);
+                  resp[3], resp[4], resp[5], resp[6]);
   }
 
   free(resp);
@@ -1412,15 +1401,14 @@ static int jtag3_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) {
 
     if (matches(extended_param, "jtagchain=")) {
       unsigned int ub, ua, bb, ba;
-      if (sscanf(extended_param, "jtagchain=%u,%u,%u,%u", &ub, &ua, &bb, &ba)
-          != 4) {
+      if (sscanf(extended_param, "jtagchain=%u,%u,%u,%u", &ub, &ua, &bb, &ba) != 4) {
         pmsg_error("invalid JTAG chain '%s'\n", extended_param);
         rv = -1;
         continue;
       }
       pmsg_notice2("jtag3_parseextparms(): JTAG chain parsed as:\n");
       imsg_notice2("%u units before, %u units after, %u bits before, %u bits after\n",
-        ub, ua, bb, ba);
+                   ub, ua, bb, ba);
       PDATA(pgm)->jtagchain[0] = ub;
       PDATA(pgm)->jtagchain[1] = ua;
       PDATA(pgm)->jtagchain[2] = bb;
@@ -1484,7 +1472,7 @@ int jtag3_open_common(PROGRAMMER *pgm, const char *port) {
     rv = serial_open(port, pinfo, &pgm->fd);
   }
   if (rv < 0) {
-#endif	/* HAVE_LIBHIDAPI */
+#endif    /* HAVE_LIBHIDAPI */
 #if defined(HAVE_LIBUSB)
     serdev = &usb_serdev_frame;
     for (usbpid = lfirst(pgm->usbpid); rv < 0 && usbpid != NULL; usbpid = lnext(usbpid)) {
@@ -1498,7 +1486,7 @@ int jtag3_open_common(PROGRAMMER *pgm, const char *port) {
       strcpy(pgm->port, port);
       rv = serial_open(port, pinfo, &pgm->fd);
     }
-#endif	/* HAVE_LIBUSB */
+#endif    /* HAVE_LIBUSB */
 #if defined(HAVE_LIBHIDAPI)
   }
 #endif
@@ -1528,7 +1516,7 @@ int jtag3_open_common(PROGRAMMER *pgm, const char *port) {
       }
     }
     pmsg_error("did not find any device matching VID 0x%04x and PID list: ",
-      (unsigned) pinfo.usbinfo.vid);
+               (unsigned) pinfo.usbinfo.vid);
     int notfirst = 0;
     for (usbpid = lfirst(pgm->usbpid); usbpid != NULL; usbpid = lnext(usbpid)) {
       if (notfirst)
@@ -1541,8 +1529,7 @@ int jtag3_open_common(PROGRAMMER *pgm, const char *port) {
     return -1;
   }
 
-  if (pgm->fd.usb.eep == 0)
-  {
+  if (pgm->fd.usb.eep == 0) {
     /* The event EP has been deleted by usb_open(), so we are
        running on a CMSIS-DAP device, using EDBG protocol */
     pgm->flag |= PGM_FL_IS_EDBG;
@@ -1613,8 +1600,7 @@ static int jtag3_open_updi(PROGRAMMER *pgm, const char *port) {
   return 0;
 }
 
-void jtag3_close(PROGRAMMER * pgm)
-{
+void jtag3_close(PROGRAMMER * pgm) {
   unsigned char buf[4], *resp;
 
   pmsg_notice2("jtag3_close()\n");
@@ -1636,7 +1622,7 @@ void jtag3_close(PROGRAMMER * pgm)
    * firmware bug where they complained about it. */
   if ((pgm->flag & PGM_FL_IS_EDBG) &&
       !matches(ldata(lfirst(pgm->id)), "xplainedmini")) {
-      jtag3_edbg_signoff(pgm);
+    jtag3_edbg_signoff(pgm);
   }
 
   serial_close(&pgm->fd);
@@ -1644,8 +1630,7 @@ void jtag3_close(PROGRAMMER * pgm)
 }
 
 static int jtag3_page_erase(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m,
-                               unsigned int addr)
-{
+                            unsigned int addr) {
   unsigned char cmd[8], *resp;
 
   pmsg_notice2("jtag3_page_erase(.., %s, 0x%x)\n", m->desc, addr);
@@ -1692,8 +1677,7 @@ static int jtag3_page_erase(const PROGRAMMER *pgm, const AVRPART *p, const AVRME
 
 static int jtag3_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m,
                                 unsigned int page_size,
-                                unsigned int addr, unsigned int n_bytes)
-{
+                                unsigned int addr, unsigned int n_bytes) {
   unsigned int block_size;
   unsigned int maxaddr = addr + n_bytes;
   unsigned char *cmd;
@@ -1711,7 +1695,8 @@ static int jtag3_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRM
   if (!(pgm->flag & PGM_FL_IS_DW) && jtag3_program_enable(pgm) < 0)
     return -1;
 
-  if (page_size == 0) page_size = 256;
+  if (page_size == 0)
+    page_size = 256;
 
   if ((cmd = malloc(page_size + 13)) == NULL) {
     pmsg_error("out of memory\n");
@@ -1734,11 +1719,11 @@ static int jtag3_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRM
        * DW mode.  Use jtag3_write_byte() instead.
        */
       for (; addr < maxaddr; addr++) {
-	status = jtag3_write_byte(pgm, p, m, addr, m->buf[addr]);
-	if (status < 0) {
-	  free(cmd);
-	  return -1;
-	}
+        status = jtag3_write_byte(pgm, p, m, addr, m->buf[addr]);
+        if (status < 0) {
+          free(cmd);
+          return -1;
+        }
       }
       free(cmd);
       return n_bytes;
@@ -1782,7 +1767,7 @@ static int jtag3_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRM
     memcpy(cmd + 13, m->buf + addr, block_size);
 
     if ((status = jtag3_command(pgm, cmd, page_size + 13,
-				&resp, "write memory")) < 0) {
+        &resp, "write memory")) < 0) {
       free(cmd);
       serial_recv_timeout = otimeout;
       return -1;
@@ -1798,9 +1783,8 @@ static int jtag3_paged_write(const PROGRAMMER *pgm, const AVRPART *p, const AVRM
 }
 
 static int jtag3_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m,
-                               unsigned int page_size,
-                               unsigned int addr, unsigned int n_bytes)
-{
+                            unsigned int page_size,
+                            unsigned int addr, unsigned int n_bytes) {
   unsigned int block_size;
   unsigned int maxaddr = addr + n_bytes;
   unsigned char cmd[12];
@@ -1809,7 +1793,7 @@ static int jtag3_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AVRME
   long otimeout = serial_recv_timeout;
 
   pmsg_notice2("jtag3_paged_load(.., %s, %d, 0x%04x, %d)\n",
-    m->desc, page_size, addr, n_bytes);
+               m->desc, page_size, addr, n_bytes);
 
   block_size = jtag3_memaddr(pgm, p, m, addr);
   if(block_size != addr)
@@ -1855,7 +1839,7 @@ static int jtag3_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AVRME
     else
       block_size = page_size;
     pmsg_debug("jtag3_paged_load(): "
-      "block_size at addr %d is %d\n", addr, block_size);
+               "block_size at addr %d is %d\n", addr, block_size);
 
     if (dynamic_memtype)
       cmd[3] = jtag3_memtype(pgm, p, addr);
@@ -1867,7 +1851,7 @@ static int jtag3_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AVRME
       return -1;
 
     if (resp[1] != RSP3_DATA ||
-	status < block_size + 4) {
+        status < block_size + 4) {
       pmsg_error("wrong/short reply to read memory command\n");
       serial_recv_timeout = otimeout;
       free(resp);
@@ -1882,8 +1866,7 @@ static int jtag3_paged_load(const PROGRAMMER *pgm, const AVRPART *p, const AVRME
 }
 
 static int jtag3_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem,
-			      unsigned long addr, unsigned char * value)
-{
+                           unsigned long addr, unsigned char * value) {
   unsigned char cmd[12];
   unsigned char *resp, *cache_ptr = NULL;
   int status, unsupp = 0;
@@ -1982,7 +1965,7 @@ static int jtag3_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
 
     if (addr == 0) {
       if ((status = jtag3_command(pgm, cmd, 12, &resp, "read memory")) < 0)
-	return status;
+        return status;
 
       signature_cache[0] = resp[4];
       signature_cache[1] = resp[5];
@@ -2053,8 +2036,7 @@ static int jtag3_read_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM
 }
 
 static int jtag3_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem,
-			       unsigned long addr, unsigned char data)
-{
+                            unsigned long addr, unsigned char data) {
   unsigned char cmd[14];
   unsigned char *resp;
   unsigned char *cache_ptr = 0;
@@ -2138,7 +2120,7 @@ static int jtag3_write_byte(const PROGRAMMER *pgm, const AVRPART *p, const AVRME
     /* step #2: update our value in page cache, and copy
      * cache to mem->buf */
     cache_ptr[addr & (pagesize - 1)] = data;
-    addr &= ~(pagesize - 1);	/* page base address */
+    addr &= ~(pagesize - 1);    /* page base address */
     memcpy(mem->buf + addr, cache_ptr, pagesize);
     /* step #3: write back */
     i = jtag3_paged_write(pgm, p, mem, pagesize, addr, pagesize);
@@ -2195,9 +2177,8 @@ static int jtag3_set_sck_period(const PROGRAMMER *pgm, double v) {
  * Read (an) emulator parameter(s).
  */
 int jtag3_getparm(const PROGRAMMER *pgm, unsigned char scope,
-		  unsigned char section, unsigned char parm,
-		  unsigned char *value, unsigned char length)
-{
+                  unsigned char section, unsigned char parm,
+                  unsigned char *value, unsigned char length) {
   int status;
   unsigned char buf[6], *resp, c;
   char descr[60];
@@ -2212,7 +2193,7 @@ int jtag3_getparm(const PROGRAMMER *pgm, unsigned char scope,
   buf[5] = length;
 
   sprintf(descr, "get parameter (scope 0x%02x, section %d, parm %d)",
-	  scope, section, parm);
+          scope, section, parm);
 
   if ((status = jtag3_command(pgm, buf, 6, &resp, descr)) < 0)
     return -1;
@@ -2235,9 +2216,8 @@ int jtag3_getparm(const PROGRAMMER *pgm, unsigned char scope,
  * Write an emulator parameter.
  */
 int jtag3_setparm(const PROGRAMMER *pgm, unsigned char scope,
-		  unsigned char section, unsigned char parm,
-		  unsigned char *value, unsigned char length)
-{
+                  unsigned char section, unsigned char parm,
+                  unsigned char *value, unsigned char length) {
   int status;
   unsigned char *buf, *resp;
   char descr[60];
@@ -2245,10 +2225,9 @@ int jtag3_setparm(const PROGRAMMER *pgm, unsigned char scope,
   pmsg_notice2("jtag3_setparm()\n");
 
   sprintf(descr, "set parameter (scope 0x%02x, section %d, parm %d)",
-	  scope, section, parm);
+          scope, section, parm);
 
-  if ((buf = malloc(6 + length)) == NULL)
-  {
+  if ((buf = malloc(6 + length)) == NULL) {
     pmsg_error("out of memory\n");
     return -1;
   }
@@ -2283,7 +2262,7 @@ int jtag3_read_sib(const PROGRAMMER *pgm, const AVRPART *p, char *sib) {
   u32_to_b4(cmd + 8, AVR_SIBLEN);
 
   if ((status = jtag3_command(pgm, cmd, 12, &resp, "read SIB")) < 0)
-	return status;
+    return status;
 
   memcpy(sib, resp+3, AVR_SIBLEN);
   sib[AVR_SIBLEN] = 0; // Zero terminate string
@@ -2348,9 +2327,8 @@ static void jtag3_display(const PROGRAMMER *pgm, const char *p) {
   resp[status - 3] = 0;
 
   msg_info("%sICE HW version  : %d\n", p, parms[0]);
-  msg_info("%sICE FW version  : %d.%02d (rel. %d)\n", p,
-	  parms[1], parms[2],
-	  (parms[3] | (parms[4] << 8)));
+  msg_info("%sICE FW version  : %d.%02d (rel. %d)\n", p, parms[1], parms[2],
+           (parms[3] | (parms[4] << 8)));
   msg_info("%sSerial number   : %s", p, resp);
   free(resp);
 }
@@ -2362,7 +2340,7 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp) {
   if (jtag3_getparm(pgm, SCOPE_GENERAL, 1, PARM3_VTARGET, buf, 2) < 0)
     return;
   fmsg_out(fp, "%sVtarget         %s: %.2f V\n", p,
-    verbose? "": "             ", b2_to_u16(buf)/1000.0);
+           verbose? "": "             ", b2_to_u16(buf)/1000.0);
 
   // Print features unique to the Power Debugger
   for(LNODEID ln=lfirst(pgm->id); ln; ln=lnext(ln)) {
@@ -2374,7 +2352,7 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp) {
         return;
       analog_raw_data = b2_to_u16(buf);
       fmsg_out(fp, "%sVout set        %s: %.2f V\n", p,
-        verbose? "": "             ", analog_raw_data / 1000.0);
+               verbose? "": "             ", analog_raw_data / 1000.0);
 
       // Read measured generator voltage value (VOUT)
       if (jtag3_getparm(pgm, SCOPE_GENERAL, 1, PARM3_TSUP_VOLTAGE_MEAS, buf, 2) < 0)
@@ -2386,7 +2364,7 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp) {
         if (analog_raw_data & 0x0800)
           analog_raw_data |= 0xF000;
         fmsg_out(fp, "%sVout measured   %s: %.02f V\n", p,
-          verbose? "": "             ", ((float) analog_raw_data / -200.0));
+                 verbose? "": "             ", ((float) analog_raw_data / -200.0));
       }
 
       // Read channel A voltage
@@ -2399,7 +2377,7 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp) {
         if (analog_raw_data & 0x0800)
           analog_raw_data |= 0xF000;
         fmsg_out(fp, "%sCh A voltage    %s: %.03f V\n", p,
-          verbose? "": "             ", ((float) analog_raw_data / -200.0));
+                 verbose? "": "             ", ((float) analog_raw_data / -200.0));
       }
 
       // Read channel A current
@@ -2410,7 +2388,7 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp) {
         pmsg_error("invalid PARM3_ANALOG_A_CURRENT data packet format\n");
       else
         fmsg_out(fp, "%sCh A current    %s: %.3f mA\n", p,
-          verbose? "": "             ", (float) analog_raw_data * 0.003472);
+                 verbose? "": "             ", (float) analog_raw_data * 0.003472);
 
       // Read channel B voltage
       if (jtag3_getparm(pgm, SCOPE_GENERAL, 1, PARM3_ANALOG_B_VOLTAGE, buf, 2) < 0)
@@ -2422,7 +2400,7 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp) {
         if (analog_raw_data & 0x0800)
           analog_raw_data |= 0xF000;
         fmsg_out(fp, "%sCh B voltage    %s: %.03f V\n", p,
-          verbose? "": "             ", (float) analog_raw_data / -200.0);
+                 verbose? "": "             ", (float) analog_raw_data / -200.0);
       }
 
       // Read channel B current
@@ -2435,38 +2413,41 @@ void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp) {
         if (analog_raw_data & 0x0800)
           analog_raw_data |= 0xF000;
         fmsg_out(fp, "%sCh B current    %s: %.3f mA\n", p,
-          verbose? "": "             ", (float) analog_raw_data * 0.555556);
+                 verbose? "": "             ", (float) analog_raw_data * 0.555556);
       }
       break;
     }
   }
 
-  if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_MEGA_PROG, buf, 2) < 0)
-    return;
+  // Print clocks if programmer typ is not TPI
+  if (strcmp(pgm->type, "JTAGICE3_TPI")) {
+    if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_MEGA_PROG, buf, 2) < 0)
+      return;
 
-  if (b2_to_u16(buf) > 0) {
-    fmsg_out(fp, "%sJTAG clock megaAVR/program   : %u kHz\n", p, b2_to_u16(buf));
-  }
+    if (b2_to_u16(buf) > 0) {
+      fmsg_out(fp, "%sJTAG clock megaAVR/program   : %u kHz\n", p, b2_to_u16(buf));
+    }
 
-  if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_MEGA_DEBUG, buf, 2) < 0)
-    return;
+    if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_MEGA_DEBUG, buf, 2) < 0)
+      return;
 
-  if (b2_to_u16(buf) > 0) {
-    fmsg_out(fp, "%sJTAG clock megaAVR/debug     : %u kHz\n", p, b2_to_u16(buf));
-  }
+    if (b2_to_u16(buf) > 0) {
+      fmsg_out(fp, "%sJTAG clock megaAVR/debug     : %u kHz\n", p, b2_to_u16(buf));
+    }
 
-  if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_JTAG, buf, 2) < 0)
-    return;
+    if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_JTAG, buf, 2) < 0)
+      return;
 
-  if (b2_to_u16(buf) > 0) {
-    fmsg_out(fp, "%sJTAG clock Xmega             : %u kHz\n", p, b2_to_u16(buf));
-  }
+    if (b2_to_u16(buf) > 0) {
+      fmsg_out(fp, "%sJTAG clock Xmega             : %u kHz\n", p, b2_to_u16(buf));
+    }
 
-  if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_PDI, buf, 2) < 0)
-    return;
+    if (jtag3_getparm(pgm, SCOPE_AVR, 1, PARM3_CLK_XMEGA_PDI, buf, 2) < 0)
+      return;
 
-  if (b2_to_u16(buf) > 0) {
-    fmsg_out(fp, "%sPDI/UPDI clock Xmega/megaAVR : %u kHz\n", p, b2_to_u16(buf));
+    if (b2_to_u16(buf) > 0) {
+      fmsg_out(fp, "%sPDI/UPDI clock Xmega/megaAVR : %u kHz\n", p, b2_to_u16(buf));
+    }
   }
 }
 
@@ -2513,6 +2494,403 @@ static unsigned int jtag3_memaddr(const PROGRAMMER *pgm, const AVRPART *p, const
   return addr;
 }
 
+unsigned char tpi_get_memtype(const AVRMEM *mem) {
+  unsigned char memtype;
+  if (strcmp(mem->desc, "fuse") == 0) {
+    memtype = XPRG_MEM_TYPE_FUSE;
+  } else if (strcmp(mem->desc, "lock") == 0) {
+    memtype = XPRG_MEM_TYPE_LOCKBITS;
+  } else if (strcmp(mem->desc, "calibration") == 0) {
+    memtype = XPRG_MEM_TYPE_LOCKBITS;
+  } else if (strcmp(mem->desc, "signature") == 0) {
+    memtype = XPRG_MEM_TYPE_LOCKBITS;
+  } else if (strcmp(mem->desc, "sigrow") == 0) {
+    memtype = XPRG_MEM_TYPE_LOCKBITS;
+  } else {
+    memtype = XPRG_MEM_TYPE_APPL;
+  }
+  return memtype;
+}
+
+/*
+ * Send the data as a JTAGICE3 encapsulated TPI packet.
+ */
+static int jtag3_send_tpi(const PROGRAMMER *pgm, unsigned char *data, size_t len) {
+  unsigned char *cmdbuf;
+  int rv;
+
+  if ((cmdbuf = malloc(len + 1)) == NULL) {
+    pmsg_error("jtag3_send_tpi(): out of memory for command packet\n");
+    exit(1);
+  }
+
+  cmdbuf[0] = SCOPE_AVR_TPI;
+  memcpy(cmdbuf + 1, data, len);
+
+  msg_trace("[TPI send] ");
+  for (size_t i=1; i<=len; i++)
+    msg_trace("0x%02x ", cmdbuf[i]);
+  msg_trace("\n");
+
+  rv = jtag3_send(pgm, cmdbuf, len + 1);
+  free(cmdbuf);
+
+  return rv;
+}
+
+int jtag3_recv_tpi(const PROGRAMMER *pgm, unsigned char **msg) {
+  int rv;
+
+  rv = jtag3_recv(pgm, msg);
+
+  if (rv <= 0) {
+    pmsg_error("jtag3_recv_tpi(): unable to receive\n");
+    return -1;
+  }
+  rv = rv - 1;
+  memcpy(*msg, *msg + 1, rv);
+
+  msg_trace("[TPI recv] ");
+  for (size_t i=0; i<rv; i++)
+    msg_trace("0x%02x ", (*msg)[i]);
+  msg_trace("\n");
+
+  return rv;
+}
+
+int jtag3_command_tpi(const PROGRAMMER *pgm, unsigned char *cmd, unsigned int cmdlen,
+                  unsigned char **resp, const char *descr) {
+  int status;
+  unsigned char c;
+
+  jtag3_send_tpi(pgm, cmd, cmdlen);
+
+  status = jtag3_recv_tpi(pgm, resp);
+  if (status <= 0) {
+    msg_notice2("\n");
+    pmsg_notice2("TPI %s command: timeout/error communicating with programmer (status %d)\n", descr, status);
+    return LIBAVRDUDE_GENERAL_FAILURE;
+  }
+
+  c = (*resp)[1];
+  if (c != XPRG_ERR_OK) {
+    pmsg_error("[TPI] command %s FAILED! Status: 0x%02x\n", descr, c);
+    status = (*resp)[3];
+    free(*resp);
+    resp = 0;
+    return LIBAVRDUDE_GENERAL_FAILURE;
+  }
+
+  return status;
+}
+
+/*
+ * initialize the AVR device and prepare it to accept commands
+ */
+static int jtag3_initialize_tpi(const PROGRAMMER *pgm, const AVRPART *p) {
+  unsigned char cmd[3];
+  unsigned char* resp;
+  int status;
+
+  pmsg_notice2("jtag3_initialize_tpi() start\n");
+
+  cmd[0] = XPRG_CMD_ENTER_PROGMODE;
+
+  if ((status = jtag3_command_tpi(pgm, cmd, 1, &resp, "Enter Progmode")) < 0)
+    return -1;
+  free(resp);
+
+  cmd[0] = XPRG_CMD_SET_PARAM;
+  cmd[1] = XPRG_PARAM_NVMCMD_ADDR;
+  cmd[2] = TPI_NVMCMD_ADDRESS;
+
+  if ((status = jtag3_command_tpi(pgm, cmd, 3, &resp, "Set NVMCMD")) < 0)
+    return -1;
+  free(resp);
+
+  cmd[0] = XPRG_CMD_SET_PARAM;
+  cmd[1] = XPRG_PARAM_NVMCSR_ADDR;
+  cmd[2] = TPI_NVMCSR_ADDRESS;
+
+  if ((status = jtag3_command_tpi(pgm, cmd, 3, &resp, "Set NVMCSR")) < 0)
+    return -1;
+  free(resp);
+
+  jtag3_print_parms(pgm, stderr);
+
+  return 0;
+}
+
+static void jtag3_enable_tpi(PROGRAMMER *pgm, const AVRPART *p) {
+  pmsg_notice2("jtag3_enable_tpi() is empty. No action necessary.\n");
+}
+
+static void jtag3_disable_tpi(const PROGRAMMER *pgm) {
+  unsigned char cmd[1];
+  unsigned char* resp;
+  int status;
+
+  cmd[0] = XPRG_CMD_LEAVE_PROGMODE;
+
+  if ((status = jtag3_command_tpi(pgm, cmd, 1, &resp, "Leave Progmode")) < 0)
+    return;
+  free(resp);
+}
+
+static int jtag3_read_byte_tpi(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem,
+                               unsigned long addr, unsigned char * value) {
+  int status;
+  const size_t len = 8;
+  unsigned char cmd[8];  // Using "len" as array length causes msvc build jobs to fail with error C2057: expected constant expression
+  unsigned char* resp;
+  unsigned long paddr = 0UL;
+
+  msg_notice2("\n");
+  pmsg_notice2("jtag3_read_byte_tpi(.., %s, 0x%lx, ...)\n", mem->desc, addr);
+
+  paddr = mem->offset + addr;
+
+  cmd[0] = XPRG_CMD_READ_MEM;
+  cmd[1] = tpi_get_memtype(mem);
+  u32_to_b4_big_endian((cmd+2), paddr);  // Address
+  u16_to_b2_big_endian((cmd+6), 1);      // Size
+
+  if ((status = jtag3_command_tpi(pgm, cmd, len, &resp, "Read Byte")) < 0)
+    return -1;
+  *value = resp[2];
+  free(resp);
+  return 0;
+}
+
+static int jtag3_erase_tpi(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem,
+                           unsigned long addr) {
+  const size_t len = 6;
+  unsigned char cmd[6];  // Using "len" as array length causes msvc build jobs to fail with error C2057: expected constant expression
+  unsigned char* resp;
+  int status;
+  unsigned long paddr = 0UL;
+
+  cmd[0] = XPRG_CMD_ERASE;
+  if (strcmp(mem->desc, "fuse") == 0) {
+    cmd[1] = XPRG_ERASE_CONFIG;
+  } else if (strcmp(mem->desc, "flash") == 0) {
+    cmd[1] = XPRG_ERASE_APP;
+  } else {
+    pmsg_error("jtag3_erase_tpi() unsupported memory: %s\n", mem->desc);
+    return -1;
+  }
+  paddr = (mem->offset + addr) | 0x01;  // An erase is triggered by an access to the hi-byte
+  u32_to_b4_big_endian((cmd+2), paddr);
+
+  if ((status = jtag3_command_tpi(pgm, cmd, len, &resp, "Erase")) < 0)
+    return -1;
+  free(resp);
+  return 0;
+}
+
+static int jtag3_write_byte_tpi(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *mem,
+                                unsigned long addr, unsigned char data) {
+  size_t len = 11;
+  size_t data_size = 2;
+  unsigned char cmd[17];
+  unsigned char* resp;
+  int status;
+  unsigned long paddr = 0UL;
+
+  status = jtag3_erase_tpi(pgm, p, mem, addr);
+  if (status < 0) {
+    pmsg_error("error in communication, received status 0x%02x\n", status);
+    return -1;
+  }
+
+  paddr = mem->offset + addr;
+
+  if (mem->n_word_writes != 0) {
+    if (mem->n_word_writes == 2) {
+      len = 13;
+      data_size = 4;
+    }
+    else if (mem->n_word_writes == 4) {
+      len = 17;
+      data_size = 8;
+    }
+  }
+
+  cmd[0] = XPRG_CMD_WRITE_MEM;
+  cmd[1] = tpi_get_memtype(mem);
+  cmd[2] = 0;  // Page Mode - Not used
+  u32_to_b4_big_endian((cmd+3), paddr);      // Address
+  u16_to_b2_big_endian((cmd+7), data_size);  // Size
+  cmd[9] = data;
+  cmd[10] = 0xFF;  // len = 11 if no n_word_writes
+  cmd[11] = 0xFF;
+  cmd[12] = 0xFF;  // len = 13 if n_word_writes == 2
+  cmd[13] = 0xFF;
+  cmd[14] = 0xFF;
+  cmd[15] = 0xFF;
+  cmd[16] = 0xFF;  // len = 17 if n_word_writes == 4
+
+  if ((status = jtag3_command_tpi(pgm, cmd, len, &resp, "Write Byte")) < 0)
+    return -1;
+  free(resp);
+  return 0;
+}
+
+static int jtag3_chip_erase_tpi(const PROGRAMMER *pgm, const AVRPART *p) {
+  const size_t len = 6;
+  unsigned char cmd[6];  // Using "len" as array length causes msvc build jobs to fail with error C2057: expected constant expression
+  unsigned char* resp;
+  int status;
+  unsigned long paddr = 0UL;
+
+  AVRMEM *m = avr_locate_mem(p, "flash");
+  if (m == NULL) {
+    pmsg_error("no flash memory for part %s\n", p->desc);
+    return LIBAVRDUDE_GENERAL_FAILURE;
+  }
+
+  // An erase is triggered by an access to the hi-byte
+  paddr = m->offset | 0x01;
+
+  cmd[0] = XPRG_CMD_ERASE;
+  cmd[1] = XPRG_ERASE_CHIP;
+  u32_to_b4_big_endian((cmd+2), paddr);
+
+  if ((status = jtag3_command_tpi(pgm, cmd, len, &resp, "Chip Erase")) < 0)
+    return -1;
+  free(resp);
+  return 0;
+}
+
+static int jtag3_open_tpi(PROGRAMMER *pgm, const char *port) {
+  pmsg_notice2("jtag3_open_tpi()\n");
+
+  if (jtag3_open_common(pgm, port) < 0)
+    return -1;
+  return 0;
+}
+
+void jtag3_close_tpi(PROGRAMMER *pgm) {
+  pmsg_notice2("jtag3_close_tpi() is empty. No action necessary.\n");
+}
+
+static int jtag3_paged_load_tpi(const PROGRAMMER *pgm, const AVRPART *p,
+                                const AVRMEM *m, unsigned int page_size,
+                                unsigned int addr, unsigned int n_bytes) {
+  unsigned int block_size = 0;
+  unsigned int maxaddr = addr + n_bytes;
+  unsigned char cmd[8];
+  unsigned char *resp;
+  int status;
+  long otimeout = serial_recv_timeout;
+
+  msg_notice2("\n");
+  pmsg_notice2("jtag3_paged_load_tpi(.., %s, %d, 0x%04x, %d)\n",
+               m->desc, page_size, addr, n_bytes);
+
+  if(m->offset)
+    imsg_notice2("mapped to address: 0x%04x\n", (addr+m->offset));
+
+  cmd[0] = XPRG_CMD_READ_MEM;
+  cmd[1] = tpi_get_memtype(m);
+
+  if(m->blocksize > page_size)
+    page_size = m->blocksize;
+
+  serial_recv_timeout = 100;
+  for (; addr < maxaddr; addr += page_size) {
+    if ((maxaddr - addr) < page_size)
+      block_size = maxaddr - addr;
+    else
+      block_size = page_size;
+    pmsg_debug("jtag3_paged_load_tpi(): "
+               "block_size at addr 0x%x is %d\n", addr, block_size);
+
+    u32_to_b4_big_endian((cmd+2), addr + m->offset);  // Address
+    u16_to_b2_big_endian((cmd+6), block_size);        // Size
+
+    if ((status = jtag3_command_tpi(pgm, cmd, 8, &resp, "Read Memory")) < 0)
+      return -1;
+
+    if (resp[1] != XPRG_ERR_OK ||
+        status < block_size + 2) {
+      pmsg_error("wrong/short reply to read memory command\n");
+      serial_recv_timeout = otimeout;
+      free(resp);
+      return -1;
+    }
+    memcpy(m->buf + addr, resp + 2, status - 2);
+    free(resp);
+  }
+  serial_recv_timeout = otimeout;
+
+  return n_bytes;
+}
+
+static int jtag3_paged_write_tpi(const PROGRAMMER *pgm, const AVRPART *p,
+                                 const AVRMEM *m, unsigned int page_size,
+                                 unsigned int addr, unsigned int n_bytes) {
+  unsigned int block_size;
+  unsigned int maxaddr = addr + n_bytes;
+  unsigned char *cmd;
+  unsigned char *resp;
+  int status;
+  long otimeout = serial_recv_timeout;
+
+  msg_notice2("\n");
+  pmsg_notice2("jtag3_paged_write_tpi(.., %s, %d, 0x%04x, %d)\n", m->desc, page_size, addr, n_bytes);
+
+  if(m->offset)
+    imsg_notice2("mapped to address: 0x%04x\n", (addr+m->offset));
+
+  if (page_size == 0)
+    page_size = m->page_size;
+
+  if ((cmd = malloc(page_size + 9)) == NULL) {
+    pmsg_error("out of memory\n");
+    return -1;
+  }
+
+  cmd[0] = XPRG_CMD_WRITE_MEM;
+  cmd[1] = tpi_get_memtype(m);
+  cmd[2] = 0;  // Page Mode; Not used - ignored
+
+  serial_recv_timeout = 100;
+  for (; addr < maxaddr; addr += page_size) {
+    if ((maxaddr - addr) < page_size)
+      block_size = maxaddr - addr;
+    else
+      block_size = page_size;
+    pmsg_debug("jtag3_paged_write(): "
+      "block_size at addr 0x%x is %d\n", addr, block_size);
+
+    u32_to_b4_big_endian((cmd+3), addr + m->offset);  // Address
+    u16_to_b2_big_endian((cmd+7), page_size);        // Size
+
+    /*
+     * If a partial page has been requested, set the remainder to 0xff.
+     * (Maybe we should rather read back the existing contents instead
+     * before?  Doesn't matter much, as bits cannot be written to 1 anyway.)
+     */
+    memset(cmd + 9, 0xff, page_size);
+    memcpy(cmd + 9, m->buf + addr, block_size);
+
+    if ((status = jtag3_command_tpi(pgm, cmd, page_size + 9,
+        &resp, "Write Memory")) < 0) {
+      free(cmd);
+      serial_recv_timeout = otimeout;
+      return -1;
+    }
+
+    free(resp);
+  }
+
+  free(cmd);
+  serial_recv_timeout = otimeout;
+
+  return n_bytes;
+}
+
 
 const char jtag3_desc[] = "Atmel JTAGICE3";
 
@@ -2677,3 +3055,33 @@ void jtag3_updi_initpgm(PROGRAMMER *pgm) {
   }
 }
 
+const char jtag3_tpi_desc[] = "Atmel JTAGICE3 in TPI mode";
+
+void jtag3_tpi_initpgm(PROGRAMMER *pgm) {
+  strcpy(pgm->type, "JTAGICE3_TPI");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = jtag3_initialize_tpi;
+  pgm->display        = jtag3_display;
+  pgm->enable         = jtag3_enable_tpi;
+  pgm->disable        = jtag3_disable_tpi;
+  pgm->program_enable = jtag3_program_enable_dummy;
+  pgm->chip_erase     = jtag3_chip_erase_tpi;
+  pgm->open           = jtag3_open_tpi;
+  pgm->close          = jtag3_close_tpi;
+  pgm->read_byte      = jtag3_read_byte_tpi;
+  pgm->write_byte     = jtag3_write_byte_tpi;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = jtag3_paged_write_tpi;
+  pgm->paged_load     = jtag3_paged_load_tpi;
+  pgm->print_parms    = jtag3_print_parms;
+  pgm->setup          = jtag3_setup;
+  pgm->teardown       = jtag3_teardown;
+  pgm->page_size      = 256;
+  pgm->flag           = PGM_FL_IS_TPI;
+}
diff --git a/src/jtag3.h b/src/jtag3.h
index 7ee95b5b..157d4982 100644
--- a/src/jtag3.h
+++ b/src/jtag3.h
@@ -31,23 +31,25 @@ int  jtag3_recv(const PROGRAMMER *pgm, unsigned char **msg);
 void jtag3_close(PROGRAMMER * pgm);
 int  jtag3_getsync(const PROGRAMMER *pgm, int mode);
 int  jtag3_getparm(const PROGRAMMER *pgm, unsigned char scope,
-		   unsigned char section, unsigned char parm,
-		   unsigned char *value, unsigned char length);
+                   unsigned char section, unsigned char parm,
+                   unsigned char *value, unsigned char length);
 int jtag3_setparm(const PROGRAMMER *pgm, unsigned char scope,
-		  unsigned char section, unsigned char parm,
-		  unsigned char *value, unsigned char length);
+                  unsigned char section, unsigned char parm,
+                  unsigned char *value, unsigned char length);
 int jtag3_command(const PROGRAMMER *pgm, unsigned char *cmd, unsigned int cmdlen,
-		  unsigned char **resp, const char *descr);
+                  unsigned char **resp, const char *descr);
 void jtag3_print_parms1(const PROGRAMMER *pgm, const char *p, FILE *fp);
 int jtag3_set_vtarget(const PROGRAMMER *pgm, double voltage);
 extern const char jtag3_desc[];
 extern const char jtag3_dw_desc[];
 extern const char jtag3_pdi_desc[];
 extern const char jtag3_updi_desc[];
+extern const char jtag3_tpi_desc[];
 void jtag3_initpgm(PROGRAMMER *pgm);
 void jtag3_dw_initpgm(PROGRAMMER *pgm);
 void jtag3_pdi_initpgm(PROGRAMMER *pgm);
 void jtag3_updi_initpgm(PROGRAMMER *pgm);
+void jtag3_tpi_initpgm(PROGRAMMER *pgm);
 
 /*
  * These functions are referenced from stk500v2.c for JTAGICE3 in
diff --git a/src/jtag3_private.h b/src/jtag3_private.h
index 2e414c71..2e971729 100644
--- a/src/jtag3_private.h
+++ b/src/jtag3_private.h
@@ -96,6 +96,7 @@
 #define SCOPE_GENERAL              0x01
 #define SCOPE_AVR_ISP              0x11
 #define SCOPE_AVR                  0x12
+#define SCOPE_AVR_TPI              0x14
 
 /* Info scope */
 #define CMD3_GET_INFO              0x00
@@ -314,6 +315,60 @@
 #define UPDI_ADDRESS_MODE_24BIT 1
 #define FUSES_SYSCFG0_OFFSET 5
 
+// TPI Protocol commands
+#define XPRG_CMD_ENTER_PROGMODE             0x01
+#define XPRG_CMD_LEAVE_PROGMODE             0x02
+#define XPRG_CMD_ERASE                      0x03
+#define XPRG_CMD_WRITE_MEM                  0x04
+#define XPRG_CMD_READ_MEM                   0x05
+#define XPRG_CMD_CRC                        0x06
+#define XPRG_CMD_SET_PARAM                  0x07
+
+// TPI Protocol responses
+// Success
+#define XPRG_ERR_OK                         0x00
+// Errors
+#define XPRG_ERR_FAILED                     0x01
+#define XPRG_ERR_COLLISION                  0x02
+#define XPRG_ERR_TIMEOUT                    0x03
+#define XPRG_ERR_ILLEGAL_PARAM              0x04
+#define XPRG_ERR_UNKNOWN_COMMAND            0x10
+
+// TPI Memory types
+#define XPRG_MEM_TYPE_APPL                  0x01
+#define XPRG_MEM_TYPE_BOOT                  0x02
+#define XPRG_MEM_TYPE_EEPROM                0x03
+#define XPRG_MEM_TYPE_FUSE                  0x04
+#define XPRG_MEM_TYPE_LOCKBITS              0x05
+#define XPRG_MEM_TYPE_USERSIG               0x06
+#define XPRG_MEM_TYPE_FACTORY_CALIBRATION   0x07
+
+// TPI Erase modes
+#define XPRG_ERASE_CHIP                     0x01
+#define XPRG_ERASE_APP                      0x02
+#define XPRG_ERASE_BOOT                     0x03
+#define XPRG_ERASE_EEPROM                   0x04
+#define XPRG_ERASE_APP_PAGE                 0x05
+#define XPRG_ERASE_BOOT_PAGE                0x06
+#define XPRG_ERASE_EEPROM_PAGE              0x07
+#define XPRG_ERASE_USERSIG                  0x08
+// Erase types for Tiny XPROG
+#define XPRG_ERASE_CONFIG                   0x09
+
+// TPI Parameters
+// XPROG parameters of different sizes
+// 4-byte address
+#define XPRG_PARAM_NVMBASE                  0x01
+// 2-byte page size
+#define XPRG_PARAM_EEPPAGESIZE              0x02
+// tiny TPI, 1-byte address
+#define XPRG_PARAM_NVMCMD_ADDR              0x03
+#define XPRG_PARAM_NVMCSR_ADDR              0x04
+
+#define TPI_NVMCMD_ADDRESS                  0x33
+#define TPI_NVMCSR_ADDRESS                  0x32
+
+
 #if !defined(JTAG3_PRIVATE_EXPORTED)
 
 struct mega_device_desc {
diff --git a/src/pgm_type.c b/src/pgm_type.c
index f14b065b..91400fea 100644
--- a/src/pgm_type.c
+++ b/src/pgm_type.c
@@ -87,6 +87,7 @@ const PROGRAMMER_TYPE programmers_types[] = { // Name(s) the programmers call th
   {"jtagice3_updi", jtag3_updi_initpgm, jtag3_updi_desc}, // "JTAGICE3_UPDI"
   {"jtagice3_dw", jtag3_dw_initpgm, jtag3_dw_desc}, // "JTAGICE3_DW"
   {"jtagice3_isp", stk500v2_jtag3_initpgm, stk500v2_jtag3_desc}, // "JTAG3_ISP"
+  {"jtagice3_tpi", jtag3_tpi_initpgm, jtag3_tpi_desc}, // "JTAGICE3_TPI"
   {"linuxgpio", linuxgpio_initpgm, linuxgpio_desc}, // "linuxgpio"
   {"linuxspi", linuxspi_initpgm, linuxspi_desc}, // LINUXSPI
   {"micronucleus", micronucleus_initpgm, micronucleus_desc}, // "micronucleus" or "Micronucleus V2.0"
diff --git a/src/stk500v2.c b/src/stk500v2.c
index bb086c10..20b8a1ac 100644
--- a/src/stk500v2.c
+++ b/src/stk500v2.c
@@ -3605,18 +3605,18 @@ static int stk600_xprog_program_enable(const PROGRAMMER *pgm, const AVRPART *p)
             return -1;
 
         buf[0] = XPRG_CMD_SET_PARAM;
-        buf[1] = XPRG_PARAM_TPI_3;
+        buf[1] = XPRG_PARAM_NVMCMD_ADDR;
         buf[2] = 51;
         if (stk600_xprog_command(pgm, buf, 3, 2) < 0) {
-            pmsg_error("XPRG_CMD_SET_PARAM(XPRG_PARAM_TPI_3) failed\n");
+            pmsg_error("XPRG_CMD_SET_PARAM(XPRG_PARAM_NVMCMD_ADDR) failed\n");
             return -1;
         }
 
         buf[0] = XPRG_CMD_SET_PARAM;
-        buf[1] = XPRG_PARAM_TPI_4;
+        buf[1] = XPRG_PARAM_NVMCSR_ADDR;
         buf[2] = 50;
         if (stk600_xprog_command(pgm, buf, 3, 2) < 0) {
-            pmsg_error("XPRG_CMD_SET_PARAM(XPRG_PARAM_TPI_4) failed\n");
+            pmsg_error("XPRG_CMD_SET_PARAM(XPRG_PARAM_NVMCSR_ADDR) failed\n");
             return -1;
         }
     } else {
diff --git a/src/stk500v2_private.h b/src/stk500v2_private.h
index 560f143e..7d55ad19 100644
--- a/src/stk500v2_private.h
+++ b/src/stk500v2_private.h
@@ -223,35 +223,6 @@
 #define XPRG_MODE_JTAG                      1
 #define XPRG_MODE_TPI                       2
 
-// XPROG commands
-#define XPRG_CMD_ENTER_PROGMODE             0x01
-#define XPRG_CMD_LEAVE_PROGMODE             0x02
-#define XPRG_CMD_ERASE                      0x03
-#define XPRG_CMD_WRITE_MEM                  0x04
-#define XPRG_CMD_READ_MEM                   0x05
-#define XPRG_CMD_CRC                        0x06
-#define XPRG_CMD_SET_PARAM                  0x07
-
-// Memory types
-#define XPRG_MEM_TYPE_APPL                   1
-#define XPRG_MEM_TYPE_BOOT                   2
-#define XPRG_MEM_TYPE_EEPROM                 3
-#define XPRG_MEM_TYPE_FUSE                   4
-#define XPRG_MEM_TYPE_LOCKBITS               5
-#define XPRG_MEM_TYPE_USERSIG                6
-#define XPRG_MEM_TYPE_FACTORY_CALIBRATION    7
-
-// Erase types
-#define XPRG_ERASE_CHIP                      1
-#define XPRG_ERASE_APP                       2
-#define XPRG_ERASE_BOOT                      3
-#define XPRG_ERASE_EEPROM                    4
-#define XPRG_ERASE_APP_PAGE                  5
-#define XPRG_ERASE_BOOT_PAGE                 6
-#define XPRG_ERASE_EEPROM_PAGE               7
-#define XPRG_ERASE_USERSIG                   8
-#define XPRG_ERASE_CONFIG                    9  // TPI only, prepare fuse write
-
 // Write mode flags
 #define XPRG_MEM_WRITE_ERASE                 0
 #define XPRG_MEM_WRITE_WRITE                 1
@@ -261,22 +232,6 @@
 #define XPRG_CRC_BOOT                        2
 #define XPRG_CRC_FLASH                       3
 
-// Error codes
-#define XPRG_ERR_OK                          0
-#define XPRG_ERR_FAILED                      1
-#define XPRG_ERR_COLLISION                   2
-#define XPRG_ERR_TIMEOUT                     3
-
-// XPROG parameters of different sizes
-// 4-byte address
-#define XPRG_PARAM_NVMBASE                  0x01
-// 2-byte page size
-#define XPRG_PARAM_EEPPAGESIZE              0x02
-// 1-byte, undocumented TPI param
-#define XPRG_PARAM_TPI_3                    0x03
-// 1-byte, undocumented TPI param
-#define XPRG_PARAM_TPI_4                    0x04
-
 // *****************[ STK answer constants ]***************************
 
 #define ANSWER_CKSUM_ERROR                  0xB0