spi-parport bugfixes for multiple device support
authorPeter Henn <Peter.Henn@web.de>
Sun, 4 Jan 2009 20:42:24 +0000 (21:42 +0100)
committerPeter Henn <Peter.Henn@web.de>
Sun, 4 Jan 2009 20:42:24 +0000 (21:42 +0100)
- 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

spi_parport.c

index 82c71b2..527630d 100644 (file)
  *    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
 // 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') && (i<SPI_DEV_MAX)) {
-               struct spi_board_info chip;     /* parport SPI board description placeholder*/
-               struct spi_device *proxy;       /* just need to check spi device result and add additional settings */
+       for (i=0; (modalias_param[0]!='\0') && (i<SPI_DEV_MAX); i++) {
+               spi[i] = spi_alloc_device(pp->bitbang.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; i<max; i++) {
+                int err;
+
+                err = spi_add_device(spi[i]);
+                if (err < 0) {
+                        /*
+                         * free all further spi devices too.
+                         * all already added spi devices will be freed
+                         * later with the final call to spi_master_put
+                         */
+                         while (i<max) {
+                                 spi_dev_put(spi[i++]);
+                         }
+                         pr_err("%s: spi_new_device failed!\n", DRVNAME);
+                         return -ENODEV;
+                }
+                pr_info("%s: SPI device successfully registered at bus %s as device %s with %d bits/word\n", DRVNAME,
+                        spi[i]->dev.bus_id, spi[i]->modalias, spi[i]->bits_per_word);
+        }
+ #else
+        i=0;
+        while ((modalias_param[0]!='\0') && (i<SPI_DEV_MAX)) {
+                struct spi_device *proxy;       /* just need to check spi device result and add additional settings */
+                struct spi_board_info chip;     /* parport SPI board description placeholder*/
+
                modalias_param=strnarr(chip.modalias, modalias_param, " ,", sizeof(chip.modalias));
                if (modalias_param==NULL) {
                        pr_err("%s: %d given modalias name is too long! See only that '%s'!\n",  DRVNAME, i, chip.modalias);
@@ -395,20 +484,15 @@ static int spi_parport_register_spi_devices(struct spi_parport *pp)
                          pr_err("%s: spi_new_device failed!\n", DRVNAME);
                          return -ENODEV;
                }
-               if (spi_bits_cnt < i) {
-                       pr_warning("%s: No spi bits per word parameter given for device %d with driver '%s'. "
-                                  "Will use default setting: %d\n",
-                                  DRVNAME, i, chip.modalias, spi_bits[i-1]);
-               }
-               proxy->bits_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) {