spi_parport with proper irq support master
authorPeter Henn <Peter.Henn@web.de>
Mon, 5 Jan 2009 03:13:24 +0000 (04:13 +0100)
committerPeter Henn <Peter.Henn@web.de>
Mon, 5 Jan 2009 03:20:29 +0000 (04:20 +0100)
- use irq array parameter to set irq line for each SPI device
  separate either by using an explicit irq number
  or by using 'auto' to reuse the irq or parport pin 10
  or by using 'none' or '-1' or just nothing, if no irq is
  required.
- remove check for open bits parameters, because we can not
  distinguish if all or no parameters are set in the array.
- start changing description format to be more kernel compliant.

spi_parport.c

index 527630d..f88d635 100644 (file)
 #endif
 
 /* ToDo
 #endif
 
 /* ToDo
- * 0. Setup of the parport mode must be done. Therefore we read the
+ * 1. Setup of the parport mode must be done. Therefore we read the
  *    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)
  *    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. support better irq via array load parameter and values like AUTO, NONE. Additionally
- *    don't free any interrupt, if no interrupt might be requested
  *
  * 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
  *
  * 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
 #define SPI_DEV_MAX                         4   /* maximum number of supported SPI devices and CS */
 #define SPI_MODALIAS_LEN                   32   /* spi protocol module alias name length, not defined in spi.h */
 
 #define SPI_DEV_MAX                         4   /* maximum number of supported SPI devices and CS */
 #define SPI_MODALIAS_LEN                   32   /* spi protocol module alias name length, not defined in spi.h */
 
+
 /* Module load parameter */
 /* Module load parameter */
-static  int irq=-1;                             /* force irq for parport pin 10 */
 static  char spi_modalias[SPI_DEV_MAX*(SPI_MODALIAS_LEN+1)]="";
 static  unsigned int spi_mode[SPI_DEV_MAX] = {SPI_MODE_0, SPI_MODE_0, SPI_MODE_0, SPI_MODE_0};
 static  int spi_mode_cnt = SPI_DEV_MAX;
 static  unsigned int spi_bits[SPI_DEV_MAX] = {8, 8, 8, 8};
 static  int spi_bits_cnt = SPI_DEV_MAX;
 static  char spi_modalias[SPI_DEV_MAX*(SPI_MODALIAS_LEN+1)]="";
 static  unsigned int spi_mode[SPI_DEV_MAX] = {SPI_MODE_0, SPI_MODE_0, SPI_MODE_0, SPI_MODE_0};
 static  int spi_mode_cnt = SPI_DEV_MAX;
 static  unsigned int spi_bits[SPI_DEV_MAX] = {8, 8, 8, 8};
 static  int spi_bits_cnt = SPI_DEV_MAX;
+static  int spi_irq[SPI_DEV_MAX] = {-1, -1, -1, -1};
+static  int spi_irq_cnt = SPI_DEV_MAX;
 
 struct spi_parport {
        struct spi_bitbang      bitbang;  /* SPI bitbang controller data, must be the first item */
        struct pardevice        *dev;     /* parport device entry */
         struct parport         *port;    /* parport port entry */
         u8                     dcache;   /* parport data port mirror bits */
 
 struct spi_parport {
        struct spi_bitbang      bitbang;  /* SPI bitbang controller data, must be the first item */
        struct pardevice        *dev;     /* parport device entry */
         struct parport         *port;    /* parport port entry */
         u8                     dcache;   /* parport data port mirror bits */
-        int                     irq;      /* parport interrupt */
         struct list_head        list;    /* spi_parport host controller list */
 };
 
         struct list_head        list;    /* spi_parport host controller list */
 };
 
@@ -147,9 +146,9 @@ static inline struct spi_parport *spidev_to_pp(struct spi_device *spi)
 /*----------------------------------------------------------------------*/
 /* spi_parport to spi_bitbang interface functions */
 
 /*----------------------------------------------------------------------*/
 /* spi_parport to spi_bitbang interface functions */
 
-/*
-** parport data bit output function
-*/
+/**
+ * parport data bit output function
+ */
 static inline void spi_parport_data_set(struct spi_parport *pp, unsigned mask, int value)
 {
         u8 byte = pp->dcache; // use old value from cache
 static inline void spi_parport_data_set(struct spi_parport *pp, unsigned mask, int value)
 {
         u8 byte = pp->dcache; // use old value from cache
@@ -161,18 +160,18 @@ static inline void spi_parport_data_set(struct spi_parport *pp, unsigned mask, i
        return parport_write_data(pp->port, byte);
 }
 
        return parport_write_data(pp->port, byte);
 }
 
-/*
-** set clock signal
-*/
+/**
+ * set clock signal
+ */
 static inline void setsck(struct spi_device *spi, int value)
 {
         struct spi_parport *pp = spidev_to_pp(spi);
        return spi_parport_data_set(pp, SPI_PARPORT_SCLK, value);
 }
 
 static inline void setsck(struct spi_device *spi, int value)
 {
         struct spi_parport *pp = spidev_to_pp(spi);
        return spi_parport_data_set(pp, SPI_PARPORT_SCLK, value);
 }
 
-/*
-** set MOSI signal
-*/
+/**
+ * set MOSI signal
+ */
 static inline void setmosi(struct spi_device *spi, int value)
 {
        struct spi_parport *pp = spidev_to_pp(spi);
 static inline void setmosi(struct spi_device *spi, int value)
 {
        struct spi_parport *pp = spidev_to_pp(spi);
@@ -180,30 +179,30 @@ static inline void setmosi(struct spi_device *spi, int value)
 }
 
 /*----------------------------------------------------------------------*/
 }
 
 /*----------------------------------------------------------------------*/
-/*
-** parport status bit input function
-*/
+/**
+ * parport status bit input function
+ */
 static inline int spi_parport_status_get(struct spi_parport *pp, unsigned mask)
 {
        u8 byte = SPI_PARPORT_STATUS_INV ^ parport_read_status(pp->port);
        return ((byte & mask) != 0);
 }
 
 static inline int spi_parport_status_get(struct spi_parport *pp, unsigned mask)
 {
        u8 byte = SPI_PARPORT_STATUS_INV ^ parport_read_status(pp->port);
        return ((byte & mask) != 0);
 }
 
-/*
-** parport data bit input function, only need for loop back 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.
-*/
+/**
+ * parport data bit input function, only need for loop back 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)
 {
         u8 byte = parport_read_data(pp->port);
        return ((byte & mask) != 0);
 }
 
 static inline int spi_parport_data_get(struct spi_parport *pp, unsigned mask)
 {
         u8 byte = parport_read_data(pp->port);
        return ((byte & mask) != 0);
 }
 
-/*
-** get MISO signal
-** supports also loop back mode in master controller
-*/
+/**
+ * get MISO signal
+ * supports also loop back mode in master controller
+ */
 static inline int getmiso(struct spi_device *spi)
 {
         int value;
 static inline int getmiso(struct spi_device *spi)
 {
         int value;
@@ -219,10 +218,10 @@ static inline int getmiso(struct spi_device *spi)
        return value;
 }
 
        return value;
 }
 
-/*
-** set chipselects
-** sets corresponding CSx and CLK, depending on its polarity and mode
-*/
+/**
+ * set chipselects
+ * sets corresponding CSx and CLK, depending on its polarity and mode
+ */
 static void spi_parport_chipselect(struct spi_device *spi, int value)
 {
        struct spi_parport *pp = spidev_to_pp(spi);
 static void spi_parport_chipselect(struct spi_device *spi, int value)
 {
        struct spi_parport *pp = spidev_to_pp(spi);
@@ -282,12 +281,59 @@ static u32 spi_parport_txrx_word_mode3(struct spi_device *spi,
 
 
 /*----------------------------------------------------------------------*/
 
 
 /*----------------------------------------------------------------------*/
-/*
-** copies src to dest string up to count characters or until a character is found
-** which matches the delim string set. As the return value will be returned the next
-** address of src, which can be used for the next stnarr of NULL if the found string
-** was longer than count.
-*/
+#define param_check_irq(name, p)                /* define own irq type */
+#define PARAM_IRQ_VAL_NONE -1                   /* value, if 'none' irq is used */
+#define PARAM_IRQ_VAL_AUTO -2                   /* value, if 'auto' irq is used */
+#define PARAM_IRQ_NAME_NONE "none"              /* string, if no irq is used */
+#define PARAM_IRQ_NAME_AUTO "auto"              /* string, if irq is automatically determined by the parport irq line */
+
+/**
+ * special irq parameter type
+ * The irq type allows setting of irq numbers in the range of all positive integer values
+ * and additionally the values "none" and "auto". These extra values will be converted into
+ * corresponding negative values -1 and -2. As exception is also the value -1 allowed, which
+ * will be seen as "none".
+ */
+int param_set_irq(const char *pbuf, struct kernel_param *kp)
+{
+        int number;
+
+        if (0 == strncmp(pbuf, PARAM_IRQ_NAME_NONE, sizeof(PARAM_IRQ_NAME_NONE))) {
+              number = PARAM_IRQ_VAL_NONE;
+        } else if (0 == strncmp(pbuf, PARAM_IRQ_NAME_AUTO, sizeof(PARAM_IRQ_NAME_AUTO))) {
+              number = PARAM_IRQ_VAL_AUTO;
+        } else {
+              char *ep;
+              number = simple_strtol(pbuf, &ep, 0);
+              if (ep != pbuf) {
+                    if ((0 > number) && (PARAM_IRQ_VAL_NONE != number))
+                            return -EINVAL;
+              } else
+                    return -EINVAL;
+        }
+        *(int *)kp->arg = number;
+        return 0;
+}
+
+int param_get_irq(char *pbuf, struct kernel_param *kp)
+{
+        int value = *(int *)kp->arg;
+        if (PARAM_IRQ_VAL_NONE == value)
+              return sprintf((char *)pbuf, "%s", PARAM_IRQ_NAME_NONE);
+        else if (PARAM_IRQ_VAL_AUTO == value)
+              return sprintf((char *)pbuf, "%s", PARAM_IRQ_NAME_AUTO);
+        else if (0 <= value)
+              return sprintf((char *)pbuf, "%d", value);
+        else
+              return -EINVAL;
+}
+
+/**
+ * copies src to dest string up to count characters or until a character is found
+ * which matches the delim string set. As the return value will be returned the next
+ * address of src, which can be used for the next stnarr of NULL if the found string
+ * was longer than count.
+ */
 const char *strnarr(char *dst, const char *src, const char *dlim, size_t count)
 {
         int i;
 const char *strnarr(char *dst, const char *src, const char *dlim, size_t count)
 {
         int i;
@@ -307,53 +353,27 @@ const char *strnarr(char *dst, const char *src, const char *dlim, size_t count)
 }
 
 
 }
 
 
-#if 0
-void parse_irqs(int nports, const char *irqstr, int irqval[])
-{
-  unsigned int i;
-  for (i=0; i<nports && irgstr; i++){
-    if (!strncmp(irqstr, "auto", 4))
-      irqval[i] = AUTO;
-    else if (!strncmp(irqstr, "none", 4))
-      irqval[i] = NONE;
-    else {
-      char *ep;
-      unsigned long r = simple_strtoul(irqstr, &ep, 0);
-      if (ep != irqstr)
-       irqval[i] = r;
-      else {
-       printk("... bad irq specifier '%s'\n", irqstr);
-      return;
-      }
-    }
-    irqstr = strchr(irqstr, ',');
-    if (irqstr) irqstr++;
-  }
-}
-#endif
-
-
-/*
-** 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.
-*/
+/**
+ * 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;
         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 */
 static int spi_parport_register_spi_devices(struct spi_parport *pp)
 {
        const char *modalias_param=spi_modalias;
         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 */
        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 */
        /* loop over all SPI device informations found in module parameter 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 */
@@ -388,7 +408,7 @@ static int spi_parport_register_spi_devices(struct spi_parport *pp)
                 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]->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]->irq = spi_irq[i];
                 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 */
                 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 */
@@ -409,13 +429,9 @@ static int spi_parport_register_spi_devices(struct spi_parport *pp)
                            DRVNAME, SPI_DEV_MAX);
         }
        if (spi_mode_cnt > i) {
                            DRVNAME, SPI_DEV_MAX);
         }
        if (spi_mode_cnt > i) {
-                pr_warning("%s: Found further %d mode parameters than SPI devices used!\n",
+                pr_warning("%s: Found further %d mode parameters than SPI devices used or no SPI mode defined!\n",
                      DRVNAME, spi_mode_cnt-i);
        }
                      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
        /*
         * Now all spi device structures are setup and all used
         * chipselects are initialized. We will now add the
@@ -439,59 +455,16 @@ static int spi_parport_register_spi_devices(struct spi_parport *pp)
                          pr_err("%s: spi_new_device failed!\n", DRVNAME);
                          return -ENODEV;
                 }
                          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);
-                       return -EINVAL;
-               }
-
-               /*
-                * The modalias name MUST match the device_driver name
-                * for the bus glue code to match and subsequently bind them.
-                */
-               chip.max_speed_hz = SPI_PARPORT_MAX_SPEED;
-               chip.chip_select = i;
-               chip.mode = spi_mode[i];
-               chip.irq = pp->irq;
-               chip.controller_data = pp;      /* enable access to primary controller data */
-               chip.platform_data = NULL;      /* data area of SPI protocol driver */
-               /* chip.bus_num = master->bus_num;      // not needed for spi_new_device */
-               i++; /* found new SPI protocol driver */
-
-               if (spi_mode_cnt < i) {
-                       pr_warning("%s: No spi mode parameter given for device %d with driver '%s'. "
-                                  "Will use default setting: %d\n",
-                                  DRVNAME, i, chip.modalias, chip.mode);
-               }
-               pr_info("%s: Will load protocol driver: '%s' on CS%d with mode 0x%02x!\n",
-                       DRVNAME, chip.modalias, chip.chip_select, chip.mode);
-
-               /*
-                * Register spi device from board info settings.
-                * Note that this will also call the probe inside the SPI protocall driver
-                */
-               proxy = spi_new_device(pp->bitbang.master, &chip);
-               if (!proxy) {
-                         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,
-                       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);
+                if (0 <= spi[i]->irq) {
+                        pr_info("%s: SPI device successfully registered at bus %s as device %s with mode 0x%x,"
+                                " %d bits/word, irq %d\n", DRVNAME, spi[i]->dev.bus_id, spi[i]->modalias,
+                                spi[i]->mode, spi[i]->bits_per_word, spi[i]->irq);
+                } else {
+                        pr_info("%s: SPI device successfully registered at bus %s as device %s with mode 0x%x,"
+                                " %d bits/word, no irq\n", DRVNAME, spi[i]->dev.bus_id, spi[i]->modalias,
+                                spi[i]->mode, spi[i]->bits_per_word);
+                }
         }
         }
-#endif
         return i;
 }
 
         return i;
 }
 
@@ -501,18 +474,19 @@ static int spi_parport_register_spi_devices(struct spi_parport *pp)
 
 static LIST_HEAD(spi_parport_hosts);
 
 
 static LIST_HEAD(spi_parport_hosts);
 
-/*
-** If attaching the driver to parport is done with exclusive access, the driver
-** is still loaded, although the attach might not be done successful.
-** If you have already registered e.g. the lp driver, please unload any drivers
-** first as long as you use exclusive access.
-*/
+/**
+ * If attaching the driver to parport is done with exclusive access, the driver
+ * is still loaded, although the attach might not be done successful.
+ * If you have already registered e.g. the lp driver, please unload any drivers
+ * first as long as you use exclusive access.
+ */
 static int __spi_parport_attach(struct parport *pb)
 {
         struct spi_master *master; /* is only temporary need */
        struct device *dev = pb->physport->dev;
         struct spi_parport *pp;
        int err;
 static int __spi_parport_attach(struct parport *pb)
 {
         struct spi_master *master; /* is only temporary need */
        struct device *dev = pb->physport->dev;
         struct spi_parport *pp;
        int err;
+        int i, use_irq;
 
        if (dev == NULL) {
                return -ENODEV;
 
        if (dev == NULL) {
                return -ENODEV;
@@ -579,23 +553,31 @@ static int __spi_parport_attach(struct parport *pb)
        /* cache initialization just preventing changing unused bits */
        pp->dcache = parport_read_data(pp->port);
 
        /* cache initialization just preventing changing unused bits */
        pp->dcache = parport_read_data(pp->port);
 
-       if(irq >= 0) {
-                pp->irq = irq;
-               pr_info("%s: force usage IRQ %d\n", DRVNAME, pp->irq);
-               if(pp->port->irq == pp->irq) {
-                       /* we free the standard parport handler, because we want to use our own later */
-                       free_irq(pp->irq, pp->port);
-                       pr_info("%s: Note parport driver will claim later irq as already freed during its module unload\n",
-                               DRVNAME);
-               }
-       } else if(pp->port->irq != PARPORT_IRQ_NONE) {
-                pp->irq = pp->port->irq;
-               /* we free the standard parport handler, because we want to use our own later */
-               free_irq(pp->irq, pp->port);
-               pr_info("%s: will use IRQ %d exclusive\n", DRVNAME, pp->irq);
-               pr_info("%s: Note parport driver will claim later irq as already freed during its module unload\n", DRVNAME);
-       } else {
-               pp->irq = -ENXIO;
+       /*
+        * loop over all irq module parameter, which must be exchanged by
+        * the parport irq, if value requires PARAM_IRQ_VAL_AUTO
+        */
+       for (use_irq = 0, i=0; i < spi_irq_cnt; i++) {
+              if (PARAM_IRQ_VAL_AUTO == spi_irq[i]) {
+                      if (PARPORT_IRQ_NONE != pp->port->irq) {
+                              spi_irq[i] = pp->port->irq; /* use parport irq */
+                              use_irq = 1;
+                      } else {
+                              pr_warning("%s: Can not auto resolve IRQ, because parport has no valid IRQ\n",
+                                         DRVNAME);
+                              break; /* further replacement makes no sense */
+                      }
+              } else if (PARAM_IRQ_VAL_NONE != spi_irq[i]) {
+                      if ((PARPORT_IRQ_NONE != pp->port->irq) && (spi_irq[i] == pp->port->irq))
+                              use_irq = 1;
+              }
+       }
+       if (use_irq) {
+              /* we free the standard parport handler, because we want to use our own later */
+              free_irq(pp->port->irq, pp->port);
+              pr_info("%s: will use IRQ %d exclusive\n", DRVNAME, pp->port->irq);
+              pr_info("%s: Note parport driver will claim later irq as already freed during its module unload\n",
+                      DRVNAME);
        }
 
        err = spi_bitbang_start(&pp->bitbang);
        }
 
        err = spi_bitbang_start(&pp->bitbang);
@@ -688,8 +670,8 @@ MODULE_AUTHOR("Option Wireless");
 MODULE_DESCRIPTION("SPI master controller driver for Parport Adapter");
 MODULE_LICENSE("GPL");
 
 MODULE_DESCRIPTION("SPI master controller driver for Parport Adapter");
 MODULE_LICENSE("GPL");
 
-module_param(irq, uint, S_IRUGO);
-MODULE_PARM_DESC(irq, "Force IRQ for parport pin 10");
+module_param_array_named(irq, spi_irq, irq, &spi_irq_cnt, S_IRUGO);
+MODULE_PARM_DESC(irq, "array of irq numbers for each driver");
 
 module_param_string(pdrv, spi_modalias, sizeof(spi_modalias), S_IRUGO);
 MODULE_PARM_DESC(pdrv, "array of spi protocol driver names");
 
 module_param_string(pdrv, spi_modalias, sizeof(spi_modalias), S_IRUGO);
 MODULE_PARM_DESC(pdrv, "array of spi protocol driver names");