From: Peter Henn Date: Sun, 4 Jan 2009 20:42:24 +0000 (+0100) Subject: spi-parport bugfixes for multiple device support X-Git-Url: http://git.linex4red.de/pub/spi-gpio-pp.git/commitdiff_plain/2f47f01754ecb24b9d3755bc35697971f43627d3?ds=inline spi-parport bugfixes for multiple device support - Initialize first all chip selects before SPI device probing may use a SPI device on the bus. - Proper support of bit_per_word setting for SPI protocol drivers, which do not setup this value, but may use it during the SPI device probing. - Add more warings for unused module parameters. - correct some typos --- diff --git a/spi_parport.c b/spi_parport.c index 82c71b2..527630d 100644 --- a/spi_parport.c +++ b/spi_parport.c @@ -59,22 +59,8 @@ * supported modes: dev->dev->port->modes; Depending on the mode flags we change * the mode value in the dev->dev->port->base_hi+0x02; Register, which is the ECR * (extended control register). So first set to SPP (standard parport mode) - * 1. first setup all CS, because spi_new_device or spi_add_device will call - * probe fkt of the SPI protocoll driver. This might initiate a SPI transfer - * and triggers the SCLK, which is worse for other chips on the SPI-BUS using - * the wrong CS polarity - * 2. use spi_add_device instead of spi_new_device. That's the only chance - * to setup the also the SPI bits per word value, just before any transaction - * might be initiated with the SPI probe fkt of the SPI protocol driver. - * Setting this spi->bits_per_word value afterwards might be here too late. - * Note that bits_per_word is normally has to be set normally by the protocoll - * driver (e.g. a bad style of the lm70.c driver, which guess that the value is - * setup afterwards) - * Therefore we MUST support a mode, where NOTHING will be changed! - * 3. support better irq via array load parameter and values like AUTO, NONE. Additionally + * 1. support better irq via array load parameter and values like AUTO, NONE. Additionally * don't free any interrupt, if no interrupt might be requested - * 4. output warning, if open mode, bits values after finish init - * 5. test spi modes * * Note: - SPI_LSB_FIRST is not yet supported and would need own txrx functions * - SPI_LOOP is supported, but requires tx before rx in own transfer functions @@ -95,8 +81,8 @@ * D1 3 --> D1 (1 << 1) MOSI * D2 4 --> D2 (1 << 2) nCS0 * D3 5 --> D3 (1 << 3) nCS1 - * D4 6 --> D4 (1 << 4) -- - * D5 7 --> D5 (1 << 5) -- + * D4 6 --> D4 (1 << 4) nCS2 + * D5 7 --> D5 (1 << 5) nCS3 * D6 8 --> D6 (1 << 6) -- * D7 9 --> D7 (1 << 7) -- * nAckn 10 <-- S6 PARPORT_STATUS_ACK @@ -121,7 +107,7 @@ // MODULE PARAMETERS //***************************************************************************** #define DRVNAME "spi_parport" /* name of the driver */ -#define DRIVER_VERSION "0.2" /* helps identifing different versions of that driver */ +#define DRIVER_VERSION "0.3" /* helps identifying different versions of that driver */ #define SPI_PARPORT_SCLK (1 << 0) /* SPI Clock on parport D0 or pin 2 */ #define SPI_PARPORT_MOSI (1 << 1) /* SPI MOSI on parport D1 or pin 3 */ @@ -205,8 +191,8 @@ static inline int spi_parport_status_get(struct spi_parport *pp, unsigned mask) /* ** parport data bit input function, only need for loop back mode -** Note: Neiter the dcache is here updated nor the value is read from that dcache -** to ensure similar system timing bahaviour as in standard MISO read mode. +** Note: Neither the dcache is here updated nor the value is read from that dcache +** to ensure similar system timing behavior as in standard MISO read mode. */ static inline int spi_parport_data_get(struct spi_parport *pp, unsigned mask) { @@ -348,17 +334,120 @@ void parse_irqs(int nports, const char *irqstr, int irqval[]) /* -** spi parport registers SPI devices, defined by the given module load parameters. +** spi parport registers the SPI devices, defined by the given module load parameters. +** Although the bit_per_word value is strongly recommended to set by the protocol driver +** itself, spi_parport_register_spi_devices supports that for buggy drivers like the lm70.c +** SPI temperature driver. But that requires using spi_add_device instead of spi_new_device +** to ensure setting that bit_per_word value just before the protocol driver may change and +** use that value for probing the connected SPI device hardware. +** +** Additionally all SPI data structures will be first setup and all used spi chipselects will +** be initialized to its inactive state before the spi_add_device is called. This ensures that +** no early spi device usage by a spi protocol drivers probe sequence may toggle the spi clock, +** although there might be another spi device at the bus, which has not yet properly setup its +** chip select state as inactive. */ static int spi_parport_register_spi_devices(struct spi_parport *pp) { const char *modalias_param=spi_modalias; - int i=0; - + struct spi_device *spi[SPI_DEV_MAX]; /* fill up here all settings instead using a board_info struct */ + int i; /* loop counter */ + int max; /* maximum loop value */ +#if 1 /* loop over all SPI device informations found in module parameter settings */ - while ((modalias_param[0]!='\0') && (ibitbang.master); /* kzalloc memory and add device to master controller */ + if (NULL == spi[i]) { + while (i > 0) { + spi_dev_put(spi[--i]); /* free all spi devices from former spi_alloc_device */ + } + return -ENOMEM; + } + + /* + * first copy the modalias parameter + */ + modalias_param=strnarr(spi[i]->modalias, modalias_param, " ,", sizeof(spi[i]->modalias)); + if (NULL == spi[i]->modalias) { + pr_err("%s: %d given modalias name is too long! See only that '%s'!\n", + DRVNAME, i, spi[i]->modalias); + while (i >= 0) { + spi_dev_put(spi[i--]); /* free all spi devices */ + } + return -EINVAL; + } + + /* + * now setup the rest as it would be done by + * the spi_new_device from a given board_info + * structure. + */ + spi[i]->max_speed_hz = SPI_PARPORT_MAX_SPEED; + spi[i]->chip_select = i; + spi[i]->master = pp->bitbang.master; + spi[i]->controller_data = pp; /* enable access to primary controller data */ + spi[i]->controller_state = NULL; /* init state like in new_spi_device */ + spi[i]->mode = spi_mode[i]; + spi[i]->irq = pp->irq; /* TODO: separate IRQ setting */ + spi[i]->bits_per_word = spi_bits[i]; /* must normally be done by protocol driver */ + spi[i]->dev.platform_data = (void *)NULL; /* data area of SPI protocol driver, + hot plug drivers must do that itself */ + /* + * first only initialize the chipselect + * for that spi device to set it inactive + */ + spi_parport_chipselect(spi[i], BITBANG_CS_INACTIVE); + if (spi_mode_cnt < (i+1)) { + pr_warning("%s: No spi mode parameter given for device %d with driver '%s'. " + "Will use default setting: %d\n", + DRVNAME, i, spi[i]->modalias, spi[i]->mode); + } + } + /* additional parameter checks and possibly logged warnings */ + if (modalias_param[0]!='\0'){ + pr_warning("%s: Found more modalias parameters of SPI devices than allowed (max: %d)!\n", + DRVNAME, SPI_DEV_MAX); + } + if (spi_mode_cnt > i) { + pr_warning("%s: Found further %d mode parameters than SPI devices used!\n", + DRVNAME, spi_mode_cnt-i); + } + if (spi_bits_cnt > i) { + pr_warning("%s: Found further %d bits parameters than SPI devices used!\n", + DRVNAME, spi_bits_cnt-i); + } + /* + * Now all spi device structures are setup and all used + * chipselects are initialized. We will now add the + * spi devices for probing and usage. We use the same + * ordering! + */ + max = i; /* remember the last value */ + for (i=0; idev.bus_id, spi[i]->modalias, spi[i]->bits_per_word); + } + #else + i=0; + while ((modalias_param[0]!='\0') && (ibits_per_word=spi_bits[i-1]; pr_info("%s: SPI device successfully registered at bus %s as device %s with %d bits/word\n", DRVNAME, proxy->dev.bus_id, chip.modalias, proxy->bits_per_word); - } - if (modalias_param[0]!='\0'){ - pr_warning("%s: Found more modalias parameters of SPI devices than allowed (max: %d)!\n", - DRVNAME, SPI_DEV_MAX); - } - return i; + } + if (modalias_param[0]!='\0'){ + pr_warning("%s: Found more modalias parameters of SPI devices than allowed (max: %d)!\n", + DRVNAME, SPI_DEV_MAX); + } +#endif + return i; } /*************************************************************************** @@ -492,7 +576,7 @@ static int __spi_parport_attach(struct parport *pb) } /* ----------------- SPI ParPort init ---------------- */ - /* cache initialisation just preventing changing unused bits */ + /* cache initialization just preventing changing unused bits */ pp->dcache = parport_read_data(pp->port); if(irq >= 0) {