Merge pull request #1100 from s-wakaba/sunxi_linuxspi_support

add extended parameter "disable_no_sc" for linuxspi programmer
This commit is contained in:
Stefan Rueger 2022-09-24 13:23:38 +01:00 committed by GitHub
commit 9a59941dfe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 90 additions and 27 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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";