X-Git-Url: http://git.linex4red.de/pub/spi-gpio-pp.git/blobdiff_plain/2f47f01754ecb24b9d3755bc35697971f43627d3..refs/heads/master:/spi_parport.c 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");