From 60ffccb8e4aab07066a931aa70f1b84a975f44eb Mon Sep 17 00:00:00 2001 From: Peter Henn Date: Mon, 5 Jan 2009 04:13:24 +0100 Subject: [PATCH] spi_parport with proper irq support - 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 | 302 +++++++++++++++++++++++++++------------------------------- 1 file changed, 142 insertions(+), 160 deletions(-) diff --git a/spi_parport.c b/spi_parport.c index 527630d..f88d635 100644 --- a/spi_parport.c +++ b/spi_parport.c @@ -55,12 +55,10 @@ #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 @@ -122,20 +120,21 @@ #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; ibitbang.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') && (iirq; - 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"); -- 2.11.0