diff --git a/ChangeLog b/ChangeLog
index fc412090..eddb33ed 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2006-08-17 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Submitted by Neil Davey:
+	patch #4539: Ability to control the bit clock (usleep) delay
+	for ppi interface
+	* bitbang.c: Implement bitbang_delay() and its calibration.
+	* bitbang.h: Declare bitbang_delay().
+	* main.c: Add the ispdelay option (-i).
+	* pgm.h (struct programmer_t): Add the ispdelay parameter.
+	* par.c: Add calls to bitbang_delay() when requested.
+	* serbb_posix.c: (Ditto.)
+	* serbb_win32.c: (Ditto.)
+	* avrdude.1: Document the new -i option.
+	* doc/avrdude.texi: (Ditto.)
+
 2006-08-14 Joerg Wunsch <j@uriah.heep.sax.de>
 
 	Submitted by <chris@awaretechs.com>:
diff --git a/NEWS b/NEWS
index c7aee8b3..8e43b640 100644
--- a/NEWS
+++ b/NEWS
@@ -22,6 +22,9 @@ Current:
   * Add high-voltage mode programming for the STK500 (both,
     parallel, and high-voltage serial programming).
 
+  * Allow for specifying the ISP clock delay as an option for
+    bit-bang programming adapters.
+
 Version 5.1:
 
   * New devices supported:
diff --git a/avrdude.1 b/avrdude.1
index 94fa5977..3e86ed4a 100644
--- a/avrdude.1
+++ b/avrdude.1
@@ -19,7 +19,7 @@
 .\"
 .\" $Id$
 .\"
-.Dd DATE July 19, 2006
+.Dd DATE August 16, 2006
 .Os
 .Dt AVRDUDE 1
 .Sh NAME
@@ -38,6 +38,7 @@
 .Op \&, Ns Ar exitspec
 .Oc
 .Op Fl F
+.Op Fl i Ar delay
 .Op Fl n
 .Op Fl P Ar port
 .Op Fl q
@@ -330,6 +331,24 @@ reasonable before continuing.  Since it can happen from time to time
 that a device has a broken (erased or overwritten) device signature
 but is otherwise operating normally, this options is provided to
 override the check.
+.It Fl i Ar delay
+For bitbang-type programmers, delay for approximately
+.Ar delay
+microseconds between each bit state change.
+If the host system is very fast, or the target runs off a slow clock
+(like a 32 kHz crystal, or the 128 kHz internal RC oscillator), this
+can become necessary to satisfy the requirement that the ISP clock
+frequency must not be higher than 1/4 of the CPU clock frequency.
+This is implemented as a spin-loop delay to allow even for very
+short delays.
+On Unix-style operating systems, the spin loop is initially calibrated
+against a system timer, so the number of microseconds might be rather
+realistic, assuming a constant system load while
+.Nm
+is running.
+On Win32 operating systems, a preconfigured number of cycles per
+microsecond is assumed that might be off a bit for very fast or very
+slow machines.
 .It Fl n
 No-write - disables actually writing data to the MCU (useful for debugging
 .Nm avrdude
diff --git a/bitbang.c b/bitbang.c
index 6cbb1689..e6102c7f 100644
--- a/bitbang.c
+++ b/bitbang.c
@@ -28,18 +28,103 @@
 #include <unistd.h>
 #include <errno.h>
 
+#if !defined(WIN32NATIVE)
+#  include <signal.h>
+#  include <sys/time.h>
+#endif
+
 #include "avr.h"
 #include "pindefs.h"
 #include "pgm.h"
 #include "par.h"
 #include "serbb.h"
 
-#define SLOW_TOGGLE 0
-
 extern char * progname;
 extern int do_cycles;
 extern int verbose;
 
+static int delay_decrement;
+
+#if !defined(WIN32NATIVE)
+static volatile int done;
+
+typedef void (*mysighandler_t)(int);
+static mysighandler_t saved_alarmhandler;
+
+static void alarmhandler(int signo)
+{
+  done = 1;
+  signal(SIGALRM, saved_alarmhandler);
+}
+#endif /* !WIN32NATIVE */
+
+/*
+ * Calibrate the microsecond delay loop below.
+ */
+static void bitbang_calibrate_delay(void)
+{
+  /*
+   * Right now, we don't have any Win32 implementation for this, so we
+   * can only run on a preconfigured delay stepping there.  The figure
+   * below should at least be correct within an order of magnitude,
+   * judging from the auto-calibration figures seen on various Unix
+   * systems on comparable hardware.
+   */
+#if defined(WIN32NATIVE)
+  delay_decrement = 100;
+#else  /* !WIN32NATIVE */
+  struct itimerval itv;
+  volatile int i;
+
+  if (verbose >= 2)
+    fprintf(stderr,
+	    "%s: Calibrating delay loop...",
+	    progname);
+  i = 0;
+  done = 0;
+  saved_alarmhandler = signal(SIGALRM, alarmhandler);
+  /*
+   * Set ITIMER_REAL to 100 ms.  All known systems have a timer
+   * granularity of 10 ms or better, so counting the delay cycles
+   * accumulating over 100 ms should give us a rather realistic
+   * picture, without annoying the user by a lengthy startup time (as
+   * an alarm(1) would do).  Of course, if heavy system activity
+   * happens just during calibration but stops before the remaining
+   * part of AVRDUDE runs, this will yield wrong values.  There's not
+   * much we can do about this.
+   */
+  itv.it_value.tv_sec = 0;
+  itv.it_value.tv_usec = 100000;
+  itv.it_interval.tv_sec = itv.it_interval.tv_usec = 0;
+  setitimer(ITIMER_REAL, &itv, 0);
+  while (!done)
+    i--;
+  itv.it_value.tv_sec = itv.it_value.tv_usec = 0;
+  setitimer(ITIMER_REAL, &itv, 0);
+  /*
+   * Calculate back from 100 ms to 1 us.
+   */
+  delay_decrement = -i / 100000;
+  if (verbose >= 2)
+    fprintf(stderr,
+	    " calibrated to %d cycles per us\n",
+	    delay_decrement);
+#endif /* WIN32NATIVE */
+}
+
+/*
+ * Delay for approximately the number of microseconds specified.
+ * usleep()'s granularity is usually like 1 ms or 10 ms, so it's not
+ * really suitable for short delays in bit-bang algorithms.
+ */
+void bitbang_delay(int us)
+{
+  volatile int del = us * delay_decrement;
+
+  while (del > 0)
+    del--;
+}
+
 /*
  * transmit and receive a byte of data to/from the AVR device
  */
@@ -204,6 +289,8 @@ int bitbang_initialize(PROGRAMMER * pgm, AVRPART * p)
   int rc;
   int tries;
 
+  bitbang_calibrate_delay();
+
   pgm->powerup(pgm);
   usleep(20000);
 
diff --git a/bitbang.h b/bitbang.h
index b428e604..90f0d481 100644
--- a/bitbang.h
+++ b/bitbang.h
@@ -25,6 +25,7 @@
 int bitbang_setpin(int fd, int pin, int value);
 int bitbang_getpin(int fd, int pin);
 int bitbang_highpulsepin(int fd, int pin);
+void bitbang_delay(unsigned int us);
 
 int  bitbang_rdy_led        (PROGRAMMER * pgm, int value);
 int  bitbang_err_led        (PROGRAMMER * pgm, int value);
diff --git a/doc/avrdude.texi b/doc/avrdude.texi
index 5f304a47..1babea75 100644
--- a/doc/avrdude.texi
+++ b/doc/avrdude.texi
@@ -584,6 +584,23 @@ to time that a device has a broken (erased or overwritten) device
 signature but is otherwise operating normally, this options is provided
 to override the check.
 
+@item -i @var{delay}
+For bitbang-type programmers, delay for approximately
+@var{delay}
+microseconds between each bit state change.
+If the host system is very fast, or the target runs off a slow clock
+(like a 32 kHz crystal, or the 128 kHz internal RC oscillator), this
+can become necessary to satisfy the requirement that the ISP clock
+frequency must not be higher than 1/4 of the CPU clock frequency.
+This is implemented as a spin-loop delay to allow even for very
+short delays.
+On Unix-style operating systems, the spin loop is initially calibrated
+against a system timer, so the number of microseconds might be rather
+realistic, assuming a constant system load while AVRDUDE is running.
+On Win32 operating systems, a preconfigured number of cycles per
+microsecond is assumed that might be off a bit for very fast or very
+slow machines.
+
 @item -n
 No-write - disables actually writing data to the MCU (useful for
 debugging AVRDUDE).
diff --git a/main.c b/main.c
index b0a2bee3..64a11e7a 100644
--- a/main.c
+++ b/main.c
@@ -105,6 +105,7 @@ void usage(void)
  "  -C <config-file>           Specify location of configuration file.\n"
  "  -c <programmer>            Specify programmer type.\n"
  "  -D                         Disable auto erase for flash memory\n"
+ "  -i <delay>                 ISP Clock Delay [in microseconds]\n"
  "  -P <port>                  Specify connection port.\n"
  "  -F                         Override invalid signature check.\n"
  "  -e                         Perform a chip erase.\n"
@@ -695,6 +696,7 @@ int main(int argc, char * argv [])
   char  * e;           /* for strtol() error checking */
   int     baudrate;    /* override default programmer baud rate */
   double  bitclock;    /* Specify programmer bit clock (JTAG ICE) */
+  int     ispdelay;    /* Specify the delay for ISP clock */
   int     safemode;    /* Enable safemode, 1=safemode on, 0=normal */
   int     silentsafe;  /* Don't ask about fuses, 1=silent, 0=normal */
   unsigned char safemode_lfuse = 0xff;
@@ -752,6 +754,7 @@ int main(int argc, char * argv [])
   set_cycles    = -1;
   baudrate      = 0;
   bitclock      = 0.0;
+  ispdelay      = 0;
   safemode      = 1;       /* Safemode on by default */
   silentsafe    = 0;       /* Ask by default */
   
@@ -802,7 +805,7 @@ int main(int argc, char * argv [])
   /*
    * process command line arguments
    */
-  while ((ch = getopt(argc,argv,"?b:B:c:C:DeE:Fnp:P:qstU:uvVyY:")) != -1) {
+  while ((ch = getopt(argc,argv,"?b:B:c:C:DeE:Fi:np:P:qstU:uvVyY:")) != -1) {
 
     switch (ch) {
       case 'b': /* override default programmer baud rate */
@@ -823,6 +826,15 @@ int main(int argc, char * argv [])
         }
         break;
 
+      case 'i':	/* specify isp clock delay */
+	ispdelay = strtol(optarg, &e,10);
+	if ((e == optarg) || (*e != 0) || ispdelay == 0) {
+	  fprintf(stderr, "%s: invalid isp clock delay specified '%s'\n",
+                  progname, optarg);
+          exit(1);
+        }
+        break;
+
       case 'c': /* programmer id */
         programmer = optarg;
         break;
@@ -1133,6 +1145,13 @@ int main(int argc, char * argv [])
     pgm->bitclock = bitclock * 1e-6;
   }
 
+  if (ispdelay != 0) {
+    if (verbose) {
+      fprintf(stderr, "%sSetting isp clock delay: %3i\n", progbuf, ispdelay);
+    }
+    pgm->ispdelay = ispdelay;
+  }
+
   rc = pgm->open(pgm, port);
   if (rc < 0) {
     exitrc = 1;
diff --git a/par.c b/par.c
index 7b7766d5..7cc30ff4 100644
--- a/par.c
+++ b/par.c
@@ -48,8 +48,6 @@ extern int verbose;
 
 #if HAVE_PARPORT
 
-#define SLOW_TOGGLE 0
-
 struct ppipins_t {
   int pin;
   int reg;
@@ -102,9 +100,8 @@ static int par_setpin(PROGRAMMER * pgm, int pin, int value)
   else
     ppi_clr(pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
 
-#if SLOW_TOGGLE
-  usleep(1000);
-#endif
+  if (pgm->ispdelay > 1)
+    bitbang_delay(pgm->ispdelay);
 
   return 0;
 }
@@ -155,24 +152,20 @@ static int par_highpulsepin(PROGRAMMER * pgm, int pin)
 
   if (inverted) {
     ppi_clr(pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
-#if SLOW_TOGGLE
-    usleep(1000);
-#endif
-    ppi_set(pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
+    if (pgm->ispdelay > 1)
+      bitbang_delay(pgm->ispdelay);
 
-#if SLOW_TOGGLE
-    usleep(1000);
-#endif
+    ppi_set(pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
+    if (pgm->ispdelay > 1)
+      bitbang_delay(pgm->ispdelay);
   } else {
     ppi_set(pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
-#if SLOW_TOGGLE
-    usleep(1000);
-#endif
-    ppi_clr(pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
+    if (pgm->ispdelay > 1)
+      bitbang_delay(pgm->ispdelay);
 
-#if SLOW_TOGGLE
-    usleep(1000);
-#endif
+    ppi_clr(pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
+    if (pgm->ispdelay > 1)
+      bitbang_delay(pgm->ispdelay);
   }
 
   return 0;
diff --git a/pgm.h b/pgm.h
index f03fdbb2..be4bd105 100644
--- a/pgm.h
+++ b/pgm.h
@@ -48,6 +48,7 @@ typedef struct programmer_t {
   int ppictrl;
   int baudrate;
   double bitclock;    /* JTAG ICE clock period in microseconds */
+  int ispdelay;    /* ISP clock delay */
   int fd;
   int  page_size;  /* page size if the programmer supports paged write/load */
   int  (*rdy_led)        (struct programmer_t * pgm, int value);
diff --git a/serbb_posix.c b/serbb_posix.c
index b023df59..b78cddae 100644
--- a/serbb_posix.c
+++ b/serbb_posix.c
@@ -158,14 +158,12 @@ static int serbb_highpulsepin(PROGRAMMER * pgm, int pin)
     return -1;
 
   serbb_setpin(pgm, pin, 1);
-  #if SLOW_TOGGLE
-  usleep(1000);
-  #endif
-  serbb_setpin(pgm, pin, 0);
+  if (pgm->ispdelay > 1)
+    bitbang_delay(pgm->ispdelay);
 
-  #if SLOW_TOGGLE
-  usleep(1000);
-  #endif
+  serbb_setpin(pgm, pin, 0);
+  if (pgm->ispdelay > 1)
+    bitbang_delay(pgm->ispdelay);
 
   return 0;
 }
diff --git a/serbb_win32.c b/serbb_win32.c
index 9829a7e9..e4cd95d5 100644
--- a/serbb_win32.c
+++ b/serbb_win32.c
@@ -230,14 +230,12 @@ static int serbb_highpulsepin(PROGRAMMER * pgm, int pin)
                 return -1;
 
         serbb_setpin(pgm, pin, 1);
-#if SLOW_TOGGLE
-        usleep(1000);
-#endif
-        serbb_setpin(pgm, pin, 0);
+	if (pgm->ispdelay > 1)
+	  bitbang_delay(pgm->ispdelay);
 
-#if SLOW_TOGGLE
-        usleep(1000);
-#endif
+        serbb_setpin(pgm, pin, 0);
+	if (pgm->ispdelay > 1)
+	  bitbang_delay(pgm->ispdelay);
 
         return 0;
 }