diff -Naur --exclude .git avrdude.orig/avrdude/avrdude.conf.in avrdude/avrdude/avrdude.conf.in
--- avrdude.orig/avrdude/avrdude.conf.in	2019-06-14 20:26:16.302287722 +0200
+++ avrdude/avrdude/avrdude.conf.in	2019-06-14 19:49:16.667305926 +0200
@@ -1479,6 +1479,20 @@
 #  miso  = ?;
 #;
 
+
+#This programmer uses the built in linux SPI bus devices to program an
+#attached AVR. A GPIO accessed through the sysfs GPIO interface needs to
+#be specified for a reset pin since the linux SPI userspace functions do
+#not allow for control over the slave select/chip select signal.
+#
+programmer
+  id = "linuxspi";
+  desc = "Use Linux SPI device in /dev/spidev*";
+  type = "linuxspi";
+  reset = 25;
+  baudrate=400000;
+;
+
 # some ultra cheap programmers use bitbanging on the 
 # serialport.
 #
diff -Naur --exclude .git avrdude.orig/avrdude/configure.ac avrdude/avrdude/configure.ac
--- avrdude.orig/avrdude/configure.ac	2019-06-14 20:26:16.312287872 +0200
+++ avrdude/avrdude/configure.ac	2019-06-14 19:49:17.037264031 +0200
@@ -219,7 +219,6 @@
 AC_CHECK_HEADERS([ddk/hidsdi.h],,,[#include <windows.h>
 #include <setupapi.h>])
 
-
 # Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
 AC_HEADER_TIME
@@ -336,6 +335,18 @@
 		esac],
 	[enabled_linuxgpio=no])	
 
+AC_ARG_ENABLE(
+	[linuxspi],
+	AC_HELP_STRING(
+		[--enable-linuxspi],
+		[Enable the Linux SPIDEV interface programmer type]),
+	[case "${enableval}" in
+		yes) enabled_linuxspi=yes ;;
+		no)  enabled_linuxspi=no ;;
+		*)   AC_MSG_ERROR(bad value ${enableval} for enable-linuxspi option) ;;
+		esac],
+	[enabled_linuxspi=no])
+
 DIST_SUBDIRS_AC='doc windows'
 
 if test "$enabled_doc" = "yes"; then
@@ -413,6 +424,14 @@
 fi
 
 
+if test "$enabled_linuxspi" = "yes"; then
+	AC_DEFINE(HAVE_LINUXSPI, 1, [Linux SPI support enabled])
+	confsubst="$confsubst -e /^@HAVE_LINUXSPI_/d"
+else
+	confsubst="$confsubst -e /^@HAVE_LINUXSPI_BEGIN@/,/^@HAVE_LINUXSPI_END@/d"
+fi
+
+
 # If we are compiling with gcc, enable all warning and make warnings errors.
 if test "$GCC" = yes; then
     ENABLE_WARNINGS="-Wall"
@@ -590,3 +609,9 @@
    echo "DISABLED   linuxgpio"
 fi
 
+if test x$enabled_linuxspi = xyes; then
+   echo "ENABLED    linuxspi"
+else
+   echo "DISABLED   linuxspi"
+fi
+
diff -Naur --exclude .git avrdude.orig/avrdude/doc/avrdude.texi avrdude/avrdude/doc/avrdude.texi
--- avrdude.orig/avrdude/doc/avrdude.texi	2019-06-14 20:26:16.312287872 +0200
+++ avrdude/avrdude/doc/avrdude.texi	2019-06-14 19:49:17.047262911 +0200
@@ -180,6 +180,26 @@
 the 74HC244. Have a look at http://kolev.info/avrdude-linuxgpio for a more
 detailed tutorial about using this programmer type.
 
+Under a Linux installation with direct access to the SPI bus and GPIO pins,
+such as would be found on a Raspberry Pi, the linuxspi programmer type can be
+used to directly connect to and program a chip using the built in interfaces on
+the computer. The requirements to use this type are that an SPI interface is
+exposed along with one GPIO pin. The GPIO serves as the reset output since the
+Linux SPI drivers do not hold slave select down when a transfer is not occuring
+and thus it cannot be used as the reset pin. A readily available level
+translator should be used between the SPI bus/reset GPIO and the chip to avoid
+potentially damaging the computer's SPI controller in the event that the chip
+is running at 5V and the SPI runs at 3.3V. The GPIO chosen for reset can be
+configured in the avrdude configuration file using the 'reset' entry under the
+linuxspi programmer, or directly in the port specification. An external pull-up
+resistor should be connected between the AVR's reset pin and Vcc. If Vcc is not
+the same as the SPI voltage, this should be done on the AVR side of the level
+translator to protect the hardware from damage. By default, this programmer is
+commented out in the avrdude configuration file due to the lack of a reliable
+way to determine if GPIOs are available. To use it, uncomment the applicable
+lines and set the 'reset' GPIO number accordingly. Linuxspi can be used as follows:
+  avrdude -c linuxspi -P /dev/spidev:/dev/gpiochip[:resetpin]
+
 The STK500, JTAG ICE, avr910, and avr109/butterfly use the serial port to communicate with the PC.
 The STK600, JTAG ICE mkII/3, AVRISP mkII, USBasp, avrftdi (and derivatives), and USBtinyISP
 programmers communicate through the USB, using @code{libusb} as a
diff -Naur --exclude .git avrdude.orig/avrdude/linuxspi.c avrdude/avrdude/linuxspi.c
--- avrdude.orig/avrdude/linuxspi.c	1970-01-01 01:00:00.000000000 +0100
+++ avrdude/avrdude/linuxspi.c	2019-06-14 19:49:17.057261792 +0200
@@ -0,0 +1,302 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Support for using spidev userspace drivers to communicate directly over SPI
+ *
+ * Copyright (C) 2013 Kevin Cuzner <kevin@kevincuzner.com>
+ * Copyright (C) 2018 Ralf Ramsauer <ralf@vmexit.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Support for inversion of reset pin, Tim Chilton 02/05/2014
+ * Review code, rebase to latest trunk, add linux/gpio.h support, Ralf Ramsauer 2018-09-07
+ */
+
+
+#include "ac_cfg.h"
+
+#include "avrdude.h"
+#include "libavrdude.h"
+
+#include "linuxspi.h"
+
+#if HAVE_LINUXSPI
+
+/**
+ * Linux Kernel SPI Drivers
+ *
+ * Copyright (C) 2006 SWAPP
+ *      Andrea Paterniani <a.paterniani@swapp-eng.it>
+ * Copyright (C) 2007 David Brownell (simplification, cleanup)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <linux/types.h>
+#include <linux/spi/spidev.h>
+#include <linux/gpio.h>
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#define LINUXSPI "linuxspi"
+
+static int fd_spidev, fd_gpiochip, fd_linehandle;
+
+/**
+ * @brief Sends/receives a message in full duplex mode
+ * @return -1 on failure, otherwise number of bytes sent/recieved
+ */
+static int linuxspi_spi_duplex(PROGRAMMER *pgm, const unsigned char *tx, unsigned char *rx, int len)
+{
+    struct spi_ioc_transfer tr;
+    int ret;
+
+    tr = (struct spi_ioc_transfer) {
+        .tx_buf = (unsigned long)tx,
+        .rx_buf = (unsigned long)rx,
+        .len = len,
+        .delay_usecs = 1,
+        //should settle around 400Khz, a standard SPI speed. Adjust using baud parameter (-b)
+	.speed_hz = pgm->baudrate == 0 ? 400000 : pgm->baudrate,
+        .bits_per_word = 8,
+    };
+
+    ret = ioctl(fd_spidev, SPI_IOC_MESSAGE(1), &tr);
+    if (ret != len)
+        avrdude_message(MSG_INFO, "\n%s: error: Unable to send SPI message\n", progname);
+
+    return (ret == -1) ? -1 : 0;
+}
+
+static void linuxspi_setup(PROGRAMMER *pgm)
+{
+}
+
+static void linuxspi_teardown(PROGRAMMER* pgm)
+{
+}
+
+static int linuxspi_open(PROGRAMMER *pgm, char *port)
+{
+    const char *port_error = "%s: error: Unknown port specification. Please use the format /dev/spidev:/dev/gpiochip[:resetno]\n";
+    char *spidev, *gpiochip, *reset_pin;
+    struct gpiohandle_request req;
+    struct gpiohandle_data data;
+    int ret;
+
+    if (!port || !strcmp(port, "unknown")) {
+        avrdude_message(MSG_INFO, "%s: error: No port specified. Port should point to an spidev device.\n", progname);
+        return -1;
+    }
+
+    spidev = strtok(port, ":");
+    if (!spidev) {
+        avrdude_message(MSG_INFO, port_error, progname);
+        return -1;
+    }
+
+    gpiochip = strtok(NULL, ":");
+    if (!gpiochip) {
+        avrdude_message(MSG_INFO, port_error, progname);
+        return -1;
+    }
+
+    /* optional: override reset pin in configuration */
+    reset_pin = strtok(NULL, ":");
+    if (reset_pin)
+        pgm->pinno[PIN_AVR_RESET] = strtoul(reset_pin, NULL, 0);
+
+    strcpy(pgm->port, port);
+    fd_spidev = open(pgm->port, O_RDWR);
+    if (fd_spidev < 0) {
+        avrdude_message(MSG_INFO, "\n%s: error: Unable to open the spidev device %s", progname, pgm->port);
+        return -1;
+    }
+
+    fd_gpiochip = open(gpiochip, 0);
+    if (fd_gpiochip < 0) {
+        close(fd_spidev);
+        avrdude_message(MSG_INFO, "\n%s error: Unable to open the gpiochip %s", progname, gpiochip);
+        ret = -1;
+        goto close_spidev;
+    }
+
+    strcpy(req.consumer_label, progname);
+    req.lines = 1;
+    req.lineoffsets[0] = pgm->pinno[PIN_AVR_RESET];
+    req.flags = GPIOHANDLE_REQUEST_OUTPUT;
+
+    ret = ioctl(fd_gpiochip, GPIO_GET_LINEHANDLE_IOCTL, &req);
+    if (ret == -1) {
+        ret = -errno;
+        goto close_gpiochip;
+    }
+
+    fd_linehandle = req.fd;
+
+    /*
+     * Set the reset state and keep it. The pin will be released and set back to
+     * its initial value, once the fd_gpiochip is closed.
+     */
+    data.values[0] = !!(pgm->pinno[PIN_AVR_RESET] & PIN_INVERSE);
+    ret = ioctl(fd_linehandle, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data);
+    if (ret == -1) {
+        ret = -errno;
+        goto close_out;
+    }
+
+    return 0;
+
+close_out:
+    close(fd_linehandle);
+close_gpiochip:
+    close(fd_gpiochip);
+close_spidev:
+    close(fd_spidev);
+    return ret;
+}
+
+static void linuxspi_close(PROGRAMMER *pgm)
+{
+    close(fd_spidev);
+    close(fd_gpiochip);
+}
+
+static void linuxspi_disable(PROGRAMMER* pgm)
+{
+}
+
+static void linuxspi_enable(PROGRAMMER* pgm)
+{
+}
+
+static void linuxspi_display(PROGRAMMER* pgm, const char* p)
+{
+}
+
+static int linuxspi_initialize(PROGRAMMER *pgm, AVRPART *p)
+{
+    int tries, ret;
+
+    if (p->flags & AVRPART_HAS_TPI) {
+        /* We do not support tpi. This is a dedicated SPI thing */
+        avrdude_message(MSG_INFO, "%s: error: Programmer " LINUXSPI " does not support TPI\n", progname);
+        return -1;
+    }
+
+    //enable programming on the part
+    tries = 0;
+    do
+    {
+        ret = pgm->program_enable(pgm, p);
+        if (ret == 0 || ret == -1)
+            break;
+    } while(tries++ < 65);
+
+    if (ret)
+        avrdude_message(MSG_INFO, "%s: error: AVR device not responding\n", progname);
+
+    return ret;
+}
+
+static int linuxspi_cmd(PROGRAMMER *pgm, const unsigned char *cmd, unsigned char *res)
+{
+    return linuxspi_spi_duplex(pgm, cmd, res, 4);
+}
+
+static int linuxspi_program_enable(PROGRAMMER *pgm, AVRPART *p)
+{
+    unsigned char cmd[4], res[4];
+
+    if (!p->op[AVR_OP_PGM_ENABLE]) {
+        avrdude_message(MSG_INFO, "%s: error: program enable instruction not defined for part \"%s\"\n", progname, p->desc);
+        return -1;
+    }
+
+    memset(cmd, 0, sizeof(cmd));
+    avr_set_bits(p->op[AVR_OP_PGM_ENABLE], cmd); //set the cmd
+    pgm->cmd(pgm, cmd, res);
+
+    if (res[2] != cmd[1])
+        return -2;
+
+    return 0;
+}
+
+static int linuxspi_chip_erase(PROGRAMMER *pgm, AVRPART *p)
+{
+    unsigned char cmd[4], res[4];
+
+    if (!p->op[AVR_OP_CHIP_ERASE]) {
+        avrdude_message(MSG_INFO, "%s: error: chip erase instruction not defined for part \"%s\"\n", progname, p->desc);
+        return -1;
+    }
+
+    memset(cmd, 0, sizeof(cmd));
+    avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd);
+    pgm->cmd(pgm, cmd, res);
+    usleep(p->chip_erase_delay);
+    pgm->initialize(pgm, p);
+
+    return 0;
+}
+
+void linuxspi_initpgm(PROGRAMMER *pgm)
+{
+    strcpy(pgm->type, LINUXSPI);
+
+    pgm_fill_old_pins(pgm); // TODO to be removed if old pin data no longer needed
+
+    /* mandatory functions */
+    pgm->initialize     = linuxspi_initialize;
+    pgm->display        = linuxspi_display;
+    pgm->enable         = linuxspi_enable;
+    pgm->disable        = linuxspi_disable;
+    pgm->program_enable = linuxspi_program_enable;
+    pgm->chip_erase     = linuxspi_chip_erase;
+    pgm->cmd            = linuxspi_cmd;
+    pgm->open           = linuxspi_open;
+    pgm->close          = linuxspi_close;
+    pgm->read_byte      = avr_read_byte_default;
+    pgm->write_byte     = avr_write_byte_default;
+
+    /* optional functions */
+    pgm->setup          = linuxspi_setup;
+    pgm->teardown       = linuxspi_teardown;
+}
+
+const char linuxspi_desc[] = "SPI using Linux spidev driver";
+
+#else /* !HAVE_LINUXSPI */
+
+void linuxspi_initpgm(PROGRAMMER * pgm)
+{
+    avrdude_message(MSG_INFO, "%s: Linux SPI driver not available in this configuration\n",
+                    progname);
+}
+
+const char linuxspi_desc[] = "SPI using Linux spidev driver (not available)";
+
+#endif /* HAVE_LINUXSPI */
diff -Naur --exclude .git avrdude.orig/avrdude/linuxspi.h avrdude/avrdude/linuxspi.h
--- avrdude.orig/avrdude/linuxspi.h	1970-01-01 01:00:00.000000000 +0100
+++ avrdude/avrdude/linuxspi.h	2019-06-14 19:49:16.837286658 +0200
@@ -0,0 +1,35 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2013 Kevin Cuzner <kevin@kevincuner.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef linuxspi_h
+#define linuxspi_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const char linuxspi_desc[];
+void linuxspi_initpgm        (PROGRAMMER * pgm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //linuxspi_h
+
diff -Naur --exclude .git avrdude.orig/avrdude/Makefile.am avrdude/avrdude/Makefile.am
--- avrdude.orig/avrdude/Makefile.am	2019-06-14 20:26:16.252286973 +0200
+++ avrdude/avrdude/Makefile.am	2019-06-14 19:49:16.267351263 +0200
@@ -149,6 +149,8 @@
 	libavrdude.h \
 	linuxgpio.c \
 	linuxgpio.h \
+	linuxspi.c \
+	linuxspi.h \
 	linux_ppdev.h \
 	lists.c \
 	my_ddk_hidsdi.h \
diff -Naur --exclude .git avrdude.orig/avrdude/pgm_type.c avrdude/avrdude/pgm_type.c
--- avrdude.orig/avrdude/pgm_type.c	2019-06-14 20:26:16.312287872 +0200
+++ avrdude/avrdude/pgm_type.c	2019-06-14 19:49:16.277350130 +0200
@@ -40,6 +40,7 @@
 #include "jtagmkII.h"
 #include "jtag3.h"
 #include "linuxgpio.h"
+#include "linuxspi.h"
 #include "par.h"
 #include "pickit2.h"
 #include "ppi.h"
@@ -81,6 +82,7 @@
         {"jtagice3_dw", jtag3_dw_initpgm, jtag3_dw_desc},
         {"jtagice3_isp", stk500v2_jtag3_initpgm, stk500v2_jtag3_desc},
         {"linuxgpio", linuxgpio_initpgm, linuxgpio_desc},
+        {"linuxspi", linuxspi_initpgm, linuxspi_desc},
         {"par", par_initpgm, par_desc},
         {"pickit2", pickit2_initpgm, pickit2_desc},
         {"serbb", serbb_initpgm, serbb_desc},
