spi_parport with proper irq support
[pub/spi-gpio-pp.git] / spi_parport.c
index 527630d..f88d635 100644 (file)
 #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)
- * 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
 #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 */
-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  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 */
-        int                     irq;      /* parport interrupt */
         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 */
 
-/*
-** 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
@@ -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);
 }
 
-/*
-** 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);
 }
 
-/*
-** set MOSI signal
-*/
+/**
+ * set MOSI signal
+ */
 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);
 }
 
-/*
-** 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);
 }
 
-/*
-** 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;
@@ -219,10 +218,10 @@ static inline int getmiso(struct spi_device *spi)
        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);
@@ -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;
@@ -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 */
-#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 */
@@ -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]->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 */
@@ -409,13 +429,9 @@ static int spi_parport_register_spi_devices(struct spi_parport *pp)
                            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);
        }
-        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
@@ -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_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;
 }
 
@@ -501,18 +474,19 @@ static int spi_parport_register_spi_devices(struct spi_parport *pp)
 
 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;
+        int i, use_irq;
 
        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);
 
-       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);
@@ -688,8 +670,8 @@ MODULE_AUTHOR("Option Wireless");
 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");