Merge pull request #1100 from s-wakaba/sunxi_linuxspi_support
add extended parameter "disable_no_sc" for linuxspi programmer
This commit is contained in:
commit
9a59941dfe
2
build.sh
2
build.sh
|
@ -37,7 +37,7 @@ case "${ostype}" in
|
||||||
# try to find out whether this is an Embedded Linux
|
# try to find out whether this is an Embedded Linux
|
||||||
# platform (e.g. Raspberry Pi)
|
# platform (e.g. Raspberry Pi)
|
||||||
machine=$(uname -m)
|
machine=$(uname -m)
|
||||||
if expr "${machine}" : 'arm' >/dev/null
|
if expr "${machine}" : '^\(arm\|aarch\)' >/dev/null
|
||||||
then
|
then
|
||||||
extra_enable="${extra_enable} -D HAVE_LINUXGPIO=ON -D HAVE_LINUXSPI=ON"
|
extra_enable="${extra_enable} -D HAVE_LINUXGPIO=ON -D HAVE_LINUXSPI=ON"
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1228,6 +1228,14 @@ specific.
|
||||||
.Pp
|
.Pp
|
||||||
When not provided, driver/OS default value will be used.
|
When not provided, driver/OS default value will be used.
|
||||||
.El
|
.El
|
||||||
|
.It Ar linuxspi
|
||||||
|
Extended parameter:
|
||||||
|
.Bl -tag -offset indent -width indent
|
||||||
|
.It Ar disable_no_cs
|
||||||
|
Ensures the programmer does not use the SPI_NO_CS bit for the SPI
|
||||||
|
driver. This parameter is useful for kernels that do not support
|
||||||
|
the CS line being managed outside the application.
|
||||||
|
.El
|
||||||
.El
|
.El
|
||||||
.Sh FILES
|
.Sh FILES
|
||||||
.Bl -tag -offset indent -width /dev/ppi0XXX
|
.Bl -tag -offset indent -width /dev/ppi0XXX
|
||||||
|
|
|
@ -1121,6 +1121,16 @@ specific.
|
||||||
When not provided, driver/OS default value will be used.
|
When not provided, driver/OS default value will be used.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
|
@cindex @code{-x} linuxspi
|
||||||
|
@item linuxspi
|
||||||
|
Extended parameter:
|
||||||
|
@table @code
|
||||||
|
@item @samp{disable_no_cs}
|
||||||
|
Ensures the programmer does not use the SPI_NO_CS bit for the SPI
|
||||||
|
driver. This parameter is useful for kernels that do not support
|
||||||
|
the CS line being managed outside the application.
|
||||||
|
@end table
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@page
|
@page
|
||||||
|
|
|
@ -62,6 +62,15 @@
|
||||||
|
|
||||||
#define LINUXSPI "linuxspi"
|
#define LINUXSPI "linuxspi"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Private data for this programmer.
|
||||||
|
*/
|
||||||
|
struct pdata {
|
||||||
|
int disable_no_cs;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PDATA(pgm) ((struct pdata *)(pgm->cookie))
|
||||||
|
|
||||||
static int fd_spidev, fd_gpiochip, fd_linehandle;
|
static int fd_spidev, fd_gpiochip, fd_linehandle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -77,21 +86,28 @@ static int linuxspi_spi_duplex(const PROGRAMMER *pgm, const unsigned char *tx, u
|
||||||
.rx_buf = (unsigned long)rx,
|
.rx_buf = (unsigned long)rx,
|
||||||
.len = len,
|
.len = len,
|
||||||
.delay_usecs = 1,
|
.delay_usecs = 1,
|
||||||
.speed_hz = 1.0 / pgm->bitclock, // seconds to Hz
|
.speed_hz = 1.0 / pgm->bitclock,
|
||||||
.bits_per_word = 8,
|
.bits_per_word = 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
ret = ioctl(fd_spidev, SPI_IOC_MESSAGE(1), &tr);
|
ret = ioctl(fd_spidev, SPI_IOC_MESSAGE(1), &tr);
|
||||||
if (ret != len)
|
if (ret != len) {
|
||||||
avrdude_message(MSG_INFO, "\n%s: error: Unable to send SPI message\n", progname);
|
avrdude_message(MSG_INFO, "\n%s: unable to send SPI message", progname);
|
||||||
|
if (errno)
|
||||||
|
avrdude_message(MSG_INFO, ". %s", strerror(errno));
|
||||||
|
avrdude_message(MSG_INFO, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
return (ret == -1) ? -1 : 0;
|
return ret == -1? -1: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void linuxspi_setup(PROGRAMMER *pgm) {
|
static void linuxspi_setup(PROGRAMMER *pgm) {
|
||||||
|
pgm->cookie = cfg_malloc("linuxspi_setup()", sizeof(struct pdata));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void linuxspi_teardown(PROGRAMMER* pgm) {
|
static void linuxspi_teardown(PROGRAMMER* pgm) {
|
||||||
|
free(pgm->cookie);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int linuxspi_reset_mcu(const PROGRAMMER *pgm, bool active) {
|
static int linuxspi_reset_mcu(const PROGRAMMER *pgm, bool active) {
|
||||||
|
@ -116,8 +132,8 @@ static int linuxspi_reset_mcu(const PROGRAMMER *pgm, bool active) {
|
||||||
#endif
|
#endif
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
avrdude_message(MSG_INFO, "%s error: Unable to set GPIO line %d value\n",
|
avrdude_message(MSG_INFO, "%s: unable to set GPIO line %d value. %s\n",
|
||||||
progname, pgm->pinno[PIN_AVR_RESET] & ~PIN_INVERSE);
|
progname, pgm->pinno[PIN_AVR_RESET] & ~PIN_INVERSE, strerror(errno));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,8 +142,8 @@ static int linuxspi_reset_mcu(const PROGRAMMER *pgm, bool active) {
|
||||||
|
|
||||||
static int linuxspi_open(PROGRAMMER *pgm, const char *pt) {
|
static int linuxspi_open(PROGRAMMER *pgm, const char *pt) {
|
||||||
const char *port_error =
|
const char *port_error =
|
||||||
"%s: error: Unknown port specification. "
|
"%s: error, unknown port specification; "
|
||||||
"Please use the format /dev/spidev:/dev/gpiochip[:resetno]\n";
|
"please use the format /dev/spidev:/dev/gpiochip[:resetno]\n";
|
||||||
char port_default[] = "/dev/spidev0.0:/dev/gpiochip0";
|
char port_default[] = "/dev/spidev0.0:/dev/gpiochip0";
|
||||||
char *spidev, *gpiochip, *reset_pin;
|
char *spidev, *gpiochip, *reset_pin;
|
||||||
char *port = cfg_strdup("linuxspi_open()", pt);
|
char *port = cfg_strdup("linuxspi_open()", pt);
|
||||||
|
@ -158,20 +174,28 @@ static int linuxspi_open(PROGRAMMER *pgm, const char *pt) {
|
||||||
strcpy(pgm->port, port);
|
strcpy(pgm->port, port);
|
||||||
fd_spidev = open(pgm->port, O_RDWR);
|
fd_spidev = open(pgm->port, O_RDWR);
|
||||||
if (fd_spidev < 0) {
|
if (fd_spidev < 0) {
|
||||||
avrdude_message(MSG_INFO, "\n%s: error: Unable to open the spidev device %s", progname, pgm->port);
|
avrdude_message(MSG_INFO, "\n%s: unable to open the spidev device %s. %s",
|
||||||
|
progname, pgm->port, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t mode = SPI_MODE_0 | SPI_NO_CS;
|
uint32_t mode = SPI_MODE_0;
|
||||||
|
if (!PDATA(pgm)->disable_no_cs)
|
||||||
|
mode |= SPI_NO_CS;
|
||||||
|
|
||||||
ret = ioctl(fd_spidev, SPI_IOC_WR_MODE32, &mode);
|
ret = ioctl(fd_spidev, SPI_IOC_WR_MODE32, &mode);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
avrdude_message(MSG_INFO, "%s: error: Unable to set SPI mode %0X on %s\n",
|
int ioctl_errno = errno;
|
||||||
progname, mode, spidev);
|
avrdude_message(MSG_INFO, "%s: unable to set SPI mode %02X on %s. %s\n",
|
||||||
|
progname, mode, spidev, strerror(errno));
|
||||||
|
if(ioctl_errno == EINVAL && !PDATA(pgm)->disable_no_cs)
|
||||||
|
avrdude_message(MSG_INFO, "%s: try -x disable_no_cs\n", progname);
|
||||||
goto close_spidev;
|
goto close_spidev;
|
||||||
}
|
}
|
||||||
fd_gpiochip = open(gpiochip, 0);
|
fd_gpiochip = open(gpiochip, 0);
|
||||||
if (fd_gpiochip < 0) {
|
if (fd_gpiochip < 0) {
|
||||||
avrdude_message(MSG_INFO, "\n%s error: Unable to open the gpiochip %s", progname, gpiochip);
|
avrdude_message(MSG_INFO, "\n%s: unable to open the gpiochip %s. %s\n",
|
||||||
|
progname, gpiochip, strerror(errno));
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto close_spidev;
|
goto close_spidev;
|
||||||
}
|
}
|
||||||
|
@ -206,8 +230,8 @@ static int linuxspi_open(PROGRAMMER *pgm, const char *pt) {
|
||||||
#endif
|
#endif
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
avrdude_message(MSG_INFO, "%s error: Unable to get GPIO line %d\n",
|
avrdude_message(MSG_INFO, "%s: unable to get GPIO line %d. %s\n",
|
||||||
progname, pgm->pinno[PIN_AVR_RESET] & ~PIN_INVERSE);
|
progname, pgm->pinno[PIN_AVR_RESET] & ~PIN_INVERSE, strerror(errno));
|
||||||
goto close_gpiochip;
|
goto close_gpiochip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,8 +247,7 @@ static int linuxspi_open(PROGRAMMER *pgm, const char *pt) {
|
||||||
}
|
}
|
||||||
if (pgm->bitclock == 0) {
|
if (pgm->bitclock == 0) {
|
||||||
avrdude_message(MSG_NOTICE,
|
avrdude_message(MSG_NOTICE,
|
||||||
"%s: defaulting bit clock to 200 kHz\n",
|
"%s: defaulting bit clock to 200 kHz\n", progname);
|
||||||
progname);
|
|
||||||
pgm->bitclock = 5E-6; // 200 kHz - 5 µs
|
pgm->bitclock = 5E-6; // 200 kHz - 5 µs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,7 +295,7 @@ static int linuxspi_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
|
||||||
|
|
||||||
if (p->prog_modes & PM_TPI) {
|
if (p->prog_modes & PM_TPI) {
|
||||||
/* We do not support TPI. This is a dedicated SPI thing */
|
/* 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);
|
avrdude_message(MSG_INFO, "%s: error, programmer " LINUXSPI " does not support TPI\n", progname);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,7 +309,7 @@ static int linuxspi_initialize(const PROGRAMMER *pgm, const AVRPART *p) {
|
||||||
} while(tries++ < 65);
|
} while(tries++ < 65);
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
avrdude_message(MSG_INFO, "%s: error: AVR device not responding\n", progname);
|
avrdude_message(MSG_INFO, "%s: error, AVR device not responding\n", progname);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -300,7 +323,7 @@ static int linuxspi_program_enable(const PROGRAMMER *pgm, const AVRPART *p) {
|
||||||
unsigned char cmd[4], res[4];
|
unsigned char cmd[4], res[4];
|
||||||
|
|
||||||
if (!p->op[AVR_OP_PGM_ENABLE]) {
|
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);
|
avrdude_message(MSG_INFO, "%s: error, program enable instruction not defined for part %s\n", progname, p->desc);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,7 +366,7 @@ static int linuxspi_chip_erase(const PROGRAMMER *pgm, const AVRPART *p) {
|
||||||
unsigned char cmd[4], res[4];
|
unsigned char cmd[4], res[4];
|
||||||
|
|
||||||
if (!p->op[AVR_OP_CHIP_ERASE]) {
|
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);
|
avrdude_message(MSG_INFO, "%s: error, chip erase instruction not defined for part %s\n", progname, p->desc);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,6 +401,27 @@ static int linuxspi_parseexitspecs(PROGRAMMER *pgm, const char *sp) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int linuxspi_parseextparams(const PROGRAMMER *pgm, const LISTID extparms) {
|
||||||
|
LNODEID ln;
|
||||||
|
const char *extended_param;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
for (ln = lfirst(extparms); ln; ln = lnext(ln)) {
|
||||||
|
extended_param = ldata(ln);
|
||||||
|
|
||||||
|
if (strcmp(extended_param, "disable_no_cs") == 0) {
|
||||||
|
PDATA(pgm)->disable_no_cs = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
avrdude_message(MSG_INFO, "%s: linuxspi_parseextparams(): "
|
||||||
|
"invalid extended parameter '%s'\n", progname, extended_param);
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
void linuxspi_initpgm(PROGRAMMER *pgm) {
|
void linuxspi_initpgm(PROGRAMMER *pgm) {
|
||||||
strcpy(pgm->type, LINUXSPI);
|
strcpy(pgm->type, LINUXSPI);
|
||||||
|
|
||||||
|
@ -400,6 +444,7 @@ void linuxspi_initpgm(PROGRAMMER *pgm) {
|
||||||
pgm->setup = linuxspi_setup;
|
pgm->setup = linuxspi_setup;
|
||||||
pgm->teardown = linuxspi_teardown;
|
pgm->teardown = linuxspi_teardown;
|
||||||
pgm->parseexitspecs = linuxspi_parseexitspecs;
|
pgm->parseexitspecs = linuxspi_parseexitspecs;
|
||||||
|
pgm->parseextparams = linuxspi_parseextparams;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char linuxspi_desc[] = "SPI using Linux spidev driver";
|
const char linuxspi_desc[] = "SPI using Linux spidev driver";
|
||||||
|
|
Loading…
Reference in New Issue