diff --git a/ChangeLog b/ChangeLog
index bbc84fd2..102f03e6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2011-05-28  Thomas Fischl <tfischl@gmx.de>
+
+	Based on patch #7440 commited by Slawomir Fraƛ:
+	* usbasp.c: added TPI support for USBasp
+	* usbasp.h: (Ditto.)
+
 2011-05-11  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
 
 	* avrdude.conf.in: Add support for ATmega168P.
diff --git a/avrdude.conf.in b/avrdude.conf.in
index 67034604..56071860 100644
--- a/avrdude.conf.in
+++ b/avrdude.conf.in
@@ -16641,22 +16641,26 @@ part
     memory "signature"
         size		= 3;
         offset		= 0x3fc0;
+        page_size	= 16;
     ;
 
     memory "fuse"
         size		= 1;
         offset		= 0x3f40;
+        page_size	= 16;
 	blocksize	= 4;
     ;
 
     memory "calibration"
         size		= 1;
         offset		= 0x3f80;
+        page_size	= 16;
     ;
 
     memory "lockbits"
         size		= 1;
         offset		= 0x3f00;
+        page_size	= 16;
     ;
 ;
 
@@ -16681,22 +16685,26 @@ part
     memory "signature"
         size		= 3;
         offset		= 0x3fc0;
+        page_size	= 16;
     ;
 
     memory "fuse"
         size		= 1;
         offset		= 0x3f40;
+        page_size	= 16;
 	blocksize	= 4;
     ;
 
     memory "calibration"
         size		= 1;
         offset		= 0x3f80;
+        page_size	= 16;
     ;
 
     memory "lockbits"
         size		= 1;
         offset		= 0x3f00;
+        page_size	= 16;
     ;
 ;
 
@@ -16721,22 +16729,26 @@ part
     memory "signature"
         size		= 3;
         offset		= 0x3fc0;
+        page_size	= 16;
     ;
 
     memory "fuse"
         size		= 1;
         offset		= 0x3f40;
+        page_size	= 16;
 	blocksize	= 4;
     ;
 
     memory "calibration"
         size		= 1;
         offset		= 0x3f80;
+        page_size	= 16;
     ;
 
     memory "lockbits"
         size		= 1;
         offset		= 0x3f00;
+        page_size	= 16;
     ;
 ;
 
@@ -16761,22 +16773,26 @@ part
     memory "signature"
         size		= 3;
         offset		= 0x3fc0;
+        page_size	= 16;
     ;
 
     memory "fuse"
         size		= 1;
         offset		= 0x3f40;
+        page_size	= 16;
 	blocksize	= 4;
     ;
 
     memory "calibration"
         size		= 1;
         offset		= 0x3f80;
+        page_size	= 16;
     ;
 
     memory "lockbits"
         size		= 1;
         offset		= 0x3f00;
+        page_size	= 16;
     ;
 ;
 
diff --git a/usbasp.c b/usbasp.c
index c8ae501f..d2695bdb 100644
--- a/usbasp.c
+++ b/usbasp.c
@@ -106,11 +106,56 @@ struct pdata
 #else
   usb_dev_handle *usbhandle;
 #endif
-  int sckfreq_hz; 
+  int sckfreq_hz;
+  unsigned int capabilities;
+  int use_tpi;
 };
 
 #define PDATA(pgm) ((struct pdata *)(pgm->cookie))
+#define IMPORT_PDATA(pgm) struct pdata *pdata = PDATA(pgm)
 
+
+
+/* Prototypes */
+// interface - management
+static void usbasp_setup(PROGRAMMER * pgm);
+static void usbasp_teardown(PROGRAMMER * pgm);
+// internal functions
+static int usbasp_transmit(PROGRAMMER * pgm, unsigned char receive, unsigned char functionid, unsigned char send[4], unsigned char * buffer, int buffersize);
+#ifdef USE_LIBUSB_1_0
+static int usbOpenDevice(libusb_device_handle **device, int vendor, char *vendorName, int product, char *productName);
+#else
+static int usbOpenDevice(usb_dev_handle **device, int vendor, char *vendorName, int product, char *productName);
+#endif
+// interface - prog.
+static int usbasp_open(PROGRAMMER * pgm, char * port);
+static void usbasp_close(PROGRAMMER * pgm);
+// dummy functions
+static void usbasp_disable(PROGRAMMER * pgm);
+static void usbasp_enable(PROGRAMMER * pgm);
+static void usbasp_display(PROGRAMMER * pgm, const char * p);
+// universal functions
+static int usbasp_initialize(PROGRAMMER * pgm, AVRPART * p);
+// SPI specific functions
+static int usbasp_spi_cmd(PROGRAMMER * pgm, unsigned char cmd[4], unsigned char res[4]);
+static int usbasp_spi_program_enable(PROGRAMMER * pgm, AVRPART * p);
+static int usbasp_spi_chip_erase(PROGRAMMER * pgm, AVRPART * p);
+static int usbasp_spi_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, int page_size, int n_bytes);
+static int usbasp_spi_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, int page_size, int n_bytes);
+static int usbasp_spi_set_sck_period(PROGRAMMER *pgm, double sckperiod);
+// TPI specific functions
+static void usbasp_tpi_send_byte(PROGRAMMER * pgm, uint8_t b);
+static int usbasp_tpi_cmd(PROGRAMMER * pgm, unsigned char cmd[4], unsigned char res[4]);
+static int usbasp_tpi_program_enable(PROGRAMMER * pgm, AVRPART * p);
+static int usbasp_tpi_chip_erase(PROGRAMMER * pgm, AVRPART * p);
+static int usbasp_tpi_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, int page_size, int n_bytes);
+static int usbasp_tpi_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, int page_size, int n_bytes);
+static int usbasp_tpi_set_sck_period(PROGRAMMER *pgm, double sckperiod);
+static int usbasp_tpi_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned long addr, unsigned char * value);
+static int usbasp_tpi_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned long addr, unsigned char data);
+
+
+/* Interface - management */
 static void usbasp_setup(PROGRAMMER * pgm)
 {
   if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0) {
@@ -127,7 +172,7 @@ static void usbasp_teardown(PROGRAMMER * pgm)
   free(pgm->cookie);
 }
 
-
+/* Internal functions */
 /*
  * wrapper for usb_control_msg call
  */
@@ -333,6 +378,8 @@ static int           didUsbInit = 0;
 }
 #endif
 
+
+/* Interface - prog. */
 static int usbasp_open(PROGRAMMER * pgm, char * port)
 {
 #ifdef USE_LIBUSB_1_0
@@ -377,13 +424,18 @@ static int usbasp_open(PROGRAMMER * pgm, char * port)
   return 0;
 }
 
-
 static void usbasp_close(PROGRAMMER * pgm)
 {
   if (PDATA(pgm)->usbhandle!=NULL) {
     unsigned char temp[4];
     memset(temp, 0, sizeof(temp));
-    usbasp_transmit(pgm, 1, USBASP_FUNC_DISCONNECT, temp, temp, sizeof(temp));
+
+    if (PDATA(pgm)->use_tpi) {
+        usbasp_transmit(pgm, 1, USBASP_FUNC_TPI_DISCONNECT, temp, temp, sizeof(temp));
+    } else {
+        usbasp_transmit(pgm, 1, USBASP_FUNC_DISCONNECT, temp, temp, sizeof(temp));
+    }
+
 #ifdef USE_LIBUSB_1_0
     libusb_close(PDATA(pgm)->usbhandle);
 #else
@@ -393,24 +445,7 @@ static void usbasp_close(PROGRAMMER * pgm)
 }
 
 
-static int usbasp_initialize(PROGRAMMER * pgm, AVRPART * p)
-{
-
-  unsigned char temp[4];
-  memset(temp, 0, sizeof(temp));
-
-  /* set sck period */
-  pgm->set_sck_period(pgm, pgm->bitclock);
-
-  /* connect to target device */
-  usbasp_transmit(pgm, 1, USBASP_FUNC_CONNECT, temp, temp, sizeof(temp));
-
-  /* wait, so device is ready to receive commands */
-  usleep(100000);
-
-  return pgm->program_enable(pgm, p);
-}
-
+/* Dummy functions */
 static void usbasp_disable(PROGRAMMER * pgm)
 {
   /* Do nothing. */
@@ -431,7 +466,75 @@ static void usbasp_display(PROGRAMMER * pgm, const char * p)
 }
 
 
-static int usbasp_cmd(PROGRAMMER * pgm, unsigned char cmd[4],
+/* Universal functions: for both SPI and TPI */
+static int usbasp_initialize(PROGRAMMER * pgm, AVRPART * p)
+{
+  int dly;
+  unsigned char temp[4];
+  unsigned char res[4];
+  IMPORT_PDATA(pgm);
+
+
+  /* get capabilities */
+  memset(temp, 0, sizeof(temp));
+  if(usbasp_transmit(pgm, 1, USBASP_FUNC_GETCAPABILITIES, temp, res, sizeof(res)) == 4)
+    pdata->capabilities = res[0] | ((unsigned int)res[1] << 8) | ((unsigned int)res[2] << 16) | ((unsigned int)res[3] << 24);
+  else
+    pdata->capabilities = 0;
+
+  pdata->use_tpi = ((pdata->capabilities & USBASP_CAP_TPI) != 0 && (p->flags & AVRPART_HAS_TPI) != 0) ? 1 : 0;
+
+  if(pdata->use_tpi)
+  {
+    /* calc tpiclk delay */
+    dly = 1500000.0 * pgm->bitclock;
+    if(dly < 1)
+        dly = 1;
+    else if(dly > 2047)
+        dly = 2047;
+    temp[0] = dly;
+    temp[1] = dly >> 8;
+
+    /* connect */
+    usbasp_transmit(pgm, 1, USBASP_FUNC_TPI_CONNECT, temp, res, sizeof(res));
+    
+    /* change interface */
+    pgm->program_enable = usbasp_tpi_program_enable;
+    pgm->chip_erase     = usbasp_tpi_chip_erase;
+    pgm->cmd            = usbasp_tpi_cmd;
+    pgm->read_byte      = usbasp_tpi_read_byte;
+    pgm->write_byte     = usbasp_tpi_write_byte;
+    pgm->paged_write    = usbasp_tpi_paged_write;
+    pgm->paged_load     = usbasp_tpi_paged_load;
+    pgm->set_sck_period	= usbasp_tpi_set_sck_period;
+  }
+  else
+  {
+    /* set sck period */
+    pgm->set_sck_period(pgm, pgm->bitclock);
+
+    /* connect to target device */
+    usbasp_transmit(pgm, 1, USBASP_FUNC_CONNECT, temp, res, sizeof(res));
+
+    /* change interface */
+    pgm->program_enable = usbasp_spi_program_enable;
+    pgm->chip_erase     = usbasp_spi_chip_erase;
+    pgm->cmd            = usbasp_spi_cmd;
+    pgm->read_byte      = avr_read_byte_default;
+    pgm->write_byte     = avr_write_byte_default;
+    pgm->paged_write    = usbasp_spi_paged_write;
+    pgm->paged_load     = usbasp_spi_paged_load;
+    pgm->set_sck_period	= usbasp_spi_set_sck_period;
+  }
+
+  /* wait, so device is ready to receive commands */
+  usleep(100000);
+
+  return pgm->program_enable(pgm, p);
+}
+
+/* SPI specific functions */
+static int usbasp_spi_cmd(PROGRAMMER * pgm, unsigned char cmd[4],
                    unsigned char res[4])
 {
   int nbytes =
@@ -446,8 +549,7 @@ static int usbasp_cmd(PROGRAMMER * pgm, unsigned char cmd[4],
   return 0;
 }
 
-
-static int usbasp_program_enable(PROGRAMMER * pgm, AVRPART * p)
+static int usbasp_spi_program_enable(PROGRAMMER * pgm, AVRPART * p)
 {
   unsigned char res[4];
   unsigned char cmd[4];
@@ -468,8 +570,7 @@ static int usbasp_program_enable(PROGRAMMER * pgm, AVRPART * p)
   return 0;
 }
 
-
-static int usbasp_chip_erase(PROGRAMMER * pgm, AVRPART * p)
+static int usbasp_spi_chip_erase(PROGRAMMER * pgm, AVRPART * p)
 {
   unsigned char cmd[4];
   unsigned char res[4];
@@ -490,8 +591,7 @@ static int usbasp_chip_erase(PROGRAMMER * pgm, AVRPART * p)
   return 0;
 }
 
-
-static int usbasp_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+static int usbasp_spi_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
                              int page_size, int n_bytes)
 {
   int n;
@@ -557,7 +657,7 @@ static int usbasp_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
   return n_bytes;
 }
 
-static int usbasp_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+static int usbasp_spi_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
                               int page_size, int n_bytes)
 {
   int n;
@@ -630,7 +730,6 @@ static int usbasp_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
   return n_bytes;
 }
 
-
 /* The list of SCK frequencies in Hz supported by USBasp */
 static struct sckoptions_t usbaspSCKoptions[] = {
   { USBASP_ISP_SCK_1500, 1500000 },
@@ -647,12 +746,11 @@ static struct sckoptions_t usbaspSCKoptions[] = {
   { USBASP_ISP_SCK_0_5, 500 }
 };
 
-
 /*
  * Set sck period (in seconds)
  * Find next possible sck period and write it to the programmer.
  */
-static int usbasp_set_sck_period(PROGRAMMER *pgm, double sckperiod)
+static int usbasp_spi_set_sck_period(PROGRAMMER *pgm, double sckperiod)
 {
   char clockoption = USBASP_ISP_SCK_AUTO;
   unsigned char res[4];
@@ -714,6 +812,266 @@ static int usbasp_set_sck_period(PROGRAMMER *pgm, double sckperiod)
   return 0;
 }
 
+/* TPI specific functions */
+static void usbasp_tpi_send_byte(PROGRAMMER * pgm, uint8_t b)
+{
+  unsigned char temp[4];
+  memset(temp, 0, sizeof(temp));
+
+  temp[0] = b;
+
+  usbasp_transmit(pgm, 1, USBASP_FUNC_TPI_RAWWRITE, temp, temp, sizeof(temp));
+}
+
+
+static int usbasp_tpi_recv_byte(PROGRAMMER * pgm)
+{
+  unsigned char temp[4];
+  memset(temp, 0, sizeof(temp));
+
+  if(usbasp_transmit(pgm, 1, USBASP_FUNC_TPI_RAWREAD, temp, temp, sizeof(temp)) != 1)
+  {
+    fprintf(stderr, "%s: error: wrong responds size\n", progname);
+    return -1;
+  }
+
+  return temp[0];
+}
+
+
+static int usbasp_tpi_nvm_waitbusy(PROGRAMMER * pgm)
+{
+  int retry;
+
+
+  for(retry=50; retry>0; retry--)
+  {
+    usbasp_tpi_send_byte(pgm, TPI_OP_SIN(NVMCSR));
+    if(usbasp_tpi_recv_byte(pgm) & NVMCSR_BSY)
+      continue;
+    return 0;
+  }
+  return -1;
+}
+
+static int usbasp_tpi_cmd(PROGRAMMER * pgm, unsigned char cmd[4], unsigned char res[4])
+{
+  fprintf(stderr, "%s: error: spi_cmd used in TPI mode: not allowed\n", progname);
+  return -1;
+}
+
+static int usbasp_tpi_program_enable(PROGRAMMER * pgm, AVRPART * p)
+{
+  int retry;
+
+  
+  /* change guard time */
+  usbasp_tpi_send_byte(pgm, TPI_OP_SSTCS(TPIPCR));
+  usbasp_tpi_send_byte(pgm, TPIPCR_GT_2b);
+
+  /* send SKEY */
+  usbasp_tpi_send_byte(pgm, 0xE0);
+  usbasp_tpi_send_byte(pgm, 0xFF);
+  usbasp_tpi_send_byte(pgm, 0x88);
+  usbasp_tpi_send_byte(pgm, 0xD8);
+  usbasp_tpi_send_byte(pgm, 0xCD);
+  usbasp_tpi_send_byte(pgm, 0x45);
+  usbasp_tpi_send_byte(pgm, 0xAB);
+  usbasp_tpi_send_byte(pgm, 0x89);
+  usbasp_tpi_send_byte(pgm, 0x12);
+
+  /* check if device is ready */
+  for(retry=0; retry<10; retry++)
+  {
+    usbasp_tpi_send_byte(pgm, TPI_OP_SLDCS(TPIIR));
+    if(usbasp_tpi_recv_byte(pgm) != 0x80)
+      continue;
+    usbasp_tpi_send_byte(pgm, TPI_OP_SLDCS(TPISR));
+    if((usbasp_tpi_recv_byte(pgm) & TPISR_NVMEN) == 0)
+      continue;
+    break;
+  }
+  if(retry >= 10)
+  {
+    fprintf(stderr, "%s: error: programm enable: target doesn't answer.\n", progname);
+    return -1;
+  }
+
+  return 0;
+}
+
+static int usbasp_tpi_chip_erase(PROGRAMMER * pgm, AVRPART * p)
+{
+  /* Set PR to flash */
+  usbasp_tpi_send_byte(pgm, TPI_OP_SSTPR(0));
+  usbasp_tpi_send_byte(pgm, 0x01);
+  usbasp_tpi_send_byte(pgm, TPI_OP_SSTPR(1));
+  usbasp_tpi_send_byte(pgm, 0x40);
+  /* select ERASE */
+  usbasp_tpi_send_byte(pgm, TPI_OP_SOUT(NVMCMD));
+  usbasp_tpi_send_byte(pgm, NVMCMD_CHIP_ERASE);
+  /* dummy write */
+  usbasp_tpi_send_byte(pgm, TPI_OP_SST_INC);
+  usbasp_tpi_send_byte(pgm, 0x00);
+  usbasp_tpi_nvm_waitbusy(pgm);
+  
+  usleep(p->chip_erase_delay);
+  pgm->initialize(pgm, p);
+
+  return 0;
+}
+
+static int usbasp_tpi_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, int page_size, int n_bytes)
+{
+  unsigned char cmd[4];
+  unsigned char* dptr;
+  int readed, clen, n;
+  uint16_t pr;
+
+
+  dptr = m->buf;
+  pr = m->offset;
+  readed = 0;
+
+  while(readed < n_bytes)
+  {
+    clen = n_bytes - readed;
+    if(clen > 32)
+      clen = 32;
+
+    /* prepare READBLOCK cmd */
+    cmd[0] = pr & 0xFF;
+    cmd[1] = pr >> 8;
+    cmd[2] = 0;
+    cmd[3] = 0;
+    n = usbasp_transmit(pgm, 1, USBASP_FUNC_TPI_READBLOCK, cmd, dptr, clen);
+    if(n != clen)
+    {
+      fprintf(stderr, "%s: error: wrong reading bytes %x\n", progname, n);
+      return -3;
+    }
+    
+    readed += clen;
+    pr += clen;
+    dptr += clen;
+
+    report_progress(readed, n_bytes, NULL);
+  }
+
+  return n_bytes;
+}
+
+static int usbasp_tpi_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, int page_size, int n_bytes)
+{
+  unsigned char cmd[4];
+  unsigned char dummy[8];
+  unsigned char* sptr;
+  int writed, clen, n;
+  uint16_t pr;
+
+
+  sptr = m->buf;
+  pr = m->offset;
+  writed = 0;
+
+  /* Set PR to flash */
+  usbasp_tpi_send_byte(pgm, TPI_OP_SSTPR(0));
+  usbasp_tpi_send_byte(pgm, (pr & 0xFF) | 1 );
+  usbasp_tpi_send_byte(pgm, TPI_OP_SSTPR(1));
+  usbasp_tpi_send_byte(pgm, (pr >> 8) );
+  /* select SECTIONERASE */
+  usbasp_tpi_send_byte(pgm, TPI_OP_SOUT(NVMCMD));
+  usbasp_tpi_send_byte(pgm, NVMCMD_SECTION_ERASE);
+  /* dummy write */
+  usbasp_tpi_send_byte(pgm, TPI_OP_SST);
+  usbasp_tpi_send_byte(pgm, 0x00);
+  usbasp_tpi_nvm_waitbusy(pgm);
+
+  usleep(p->chip_erase_delay);
+
+  while(writed < n_bytes)
+  {
+    clen = n_bytes - writed;
+    if(clen > 32)
+      clen = 32;
+
+    /* prepare WRITEBLOCK cmd */
+    cmd[0] = pr & 0xFF;
+    cmd[1] = pr >> 8;
+    cmd[2] = 0;
+    cmd[3] = 0;
+    n = usbasp_transmit(pgm, 0, USBASP_FUNC_TPI_WRITEBLOCK, cmd, sptr, clen);
+    if(n != clen)
+    {
+      fprintf(stderr, "%s: error: wrong count at writing %x\n", progname, n);
+      return -3;
+    }
+    
+    writed += clen;
+    pr += clen;
+    sptr += clen;
+
+    report_progress(writed, n_bytes, NULL);
+  }
+  
+  /* finishing write */
+  while((  clen = (-pr) & (m->page_size-1)  ) != 0)
+  {
+    if(clen > 8)
+      clen = 8;
+
+    memset(dummy, 0xFF, clen);
+
+    cmd[0] = pr & 0xFF;
+    cmd[1] = pr >> 8;
+    cmd[2] = 0;
+    cmd[3] = 0;
+    n = usbasp_transmit(pgm, 0, USBASP_FUNC_TPI_WRITEBLOCK, cmd, dummy, clen);
+    if(n != clen)
+    {
+      fprintf(stderr, "%s: error: wrong count at writing %x\n", progname, n);
+      return -3;
+    }
+
+    pr += clen;
+  }
+
+  return n_bytes;
+}
+
+static int usbasp_tpi_set_sck_period(PROGRAMMER *pgm, double sckperiod)
+{
+  return 0;
+}
+static int usbasp_tpi_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned long addr, unsigned char * value)
+{
+  unsigned char cmd[4];
+  int n;
+  uint16_t pr;
+
+
+  pr = m->offset + addr;
+
+  /* READBLOCK */
+  cmd[0] = pr & 0xFF;
+  cmd[1] = pr >> 8;
+  cmd[2] = 0;
+  cmd[3] = 0;
+  n = usbasp_transmit(pgm, 1, USBASP_FUNC_TPI_READBLOCK, cmd, value, 1);
+  if(n != 1)
+  {
+    fprintf(stderr, "%s: error: wrong reading bytes %x\n", progname, n);
+    return -3;
+  }
+  return 0;
+}
+
+static int usbasp_tpi_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, unsigned long addr, unsigned char data)
+{
+  fprintf(stderr, "%s: error: usbasp_write_byte in TPI mode: all writes have to be done at page level\n", progname);
+  return -1;
+}
+
 
 void usbasp_initpgm(PROGRAMMER * pgm)
 {
@@ -727,9 +1085,9 @@ void usbasp_initpgm(PROGRAMMER * pgm)
   pgm->display        = usbasp_display;
   pgm->enable         = usbasp_enable;
   pgm->disable        = usbasp_disable;
-  pgm->program_enable = usbasp_program_enable;
-  pgm->chip_erase     = usbasp_chip_erase;
-  pgm->cmd            = usbasp_cmd;
+  pgm->program_enable = usbasp_spi_program_enable;
+  pgm->chip_erase     = usbasp_spi_chip_erase;
+  pgm->cmd            = usbasp_spi_cmd;
   pgm->open           = usbasp_open;
   pgm->close          = usbasp_close;
   pgm->read_byte      = avr_read_byte_default;
@@ -739,11 +1097,11 @@ void usbasp_initpgm(PROGRAMMER * pgm)
    * optional functions
    */
 
-  pgm->paged_write    = usbasp_paged_write;
-  pgm->paged_load     = usbasp_paged_load;
+  pgm->paged_write    = usbasp_spi_paged_write;
+  pgm->paged_load     = usbasp_spi_paged_load;
   pgm->setup          = usbasp_setup;
   pgm->teardown       = usbasp_teardown;
-  pgm->set_sck_period = usbasp_set_sck_period;
+  pgm->set_sck_period = usbasp_spi_set_sck_period;
 
 }
 
diff --git a/usbasp.h b/usbasp.h
index c9610acf..91b6e8a8 100644
--- a/usbasp.h
+++ b/usbasp.h
@@ -45,6 +45,16 @@
 #define USBASP_FUNC_WRITEEEPROM 8
 #define USBASP_FUNC_SETLONGADDRESS 9
 #define USBASP_FUNC_SETISPSCK 10
+#define USBASP_FUNC_TPI_CONNECT      11
+#define USBASP_FUNC_TPI_DISCONNECT   12
+#define USBASP_FUNC_TPI_RAWREAD      13
+#define USBASP_FUNC_TPI_RAWWRITE     14
+#define USBASP_FUNC_TPI_READBLOCK    15
+#define USBASP_FUNC_TPI_WRITEBLOCK   16
+#define USBASP_FUNC_GETCAPABILITIES 127
+
+/* USBASP capabilities */
+#define USBASP_CAP_TPI    0x01
 
 /* Block mode flags */
 #define USBASP_BLOCKFLAG_FIRST    1
@@ -69,6 +79,53 @@
 #define USBASP_ISP_SCK_750    11  /* 750 kHz   */
 #define USBASP_ISP_SCK_1500   12  /* 1.5 MHz   */
 
+/* TPI instructions */
+#define TPI_OP_SLD      0x20
+#define TPI_OP_SLD_INC  0x24
+#define TPI_OP_SST      0x60
+#define TPI_OP_SST_INC  0x64
+#define TPI_OP_SSTPR(a) (0x68 | (a))
+#define TPI_OP_SIN(a)   (0x10 | (((a)<<1)&0x60) | ((a)&0x0F) )
+#define TPI_OP_SOUT(a)  (0x90 | (((a)<<1)&0x60) | ((a)&0x0F) )
+#define TPI_OP_SLDCS(a) (0x80 | ((a)&0x0F) )
+#define TPI_OP_SSTCS(a) (0xC0 | ((a)&0x0F) )
+#define TPI_OP_SKEY     0xE0
+
+/* TPI control/status registers */
+#define TPIIR  0xF
+#define TPIPCR 0x2
+#define TPISR  0x0
+
+// TPIPCR bits
+#define TPIPCR_GT_2    0x04
+#define TPIPCR_GT_1    0x02
+#define TPIPCR_GT_0    0x01
+#define TPIPCR_GT_128b 0x00
+#define TPIPCR_GT_64b  0x01
+#define TPIPCR_GT_32b  0x02
+#define TPIPCR_GT_16b  0x03
+#define TPIPCR_GT_8b   0x04
+#define TPIPCR_GT_4b   0x05
+#define TPIPCR_GT_2b   0x06
+#define TPIPCR_GT_0b   0x07
+
+// TPISR bits
+#define TPISR_NVMEN    0x02
+
+/* NVM registers */
+#define NVMCSR         0x32
+#define NVMCMD         0x33
+
+// NVMCSR bits
+#define NVMCSR_BSY     0x80
+
+// NVMCMD values
+#define NVMCMD_NOP           0x00
+#define NVMCMD_CHIP_ERASE    0x10
+#define NVMCMD_SECTION_ERASE 0x14
+#define NVMCMD_WORD_WRITE    0x1D
+
+
 typedef struct sckoptions_t {
   int id;
   double frequency;