#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 */
};
/*----------------------------------------------------------------------*/
/* 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
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);
}
/*----------------------------------------------------------------------*/
-/*
-** 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;
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);
/*----------------------------------------------------------------------*/
-/*
-** 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;
}
-#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 */
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 */
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
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;
}
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;
/* 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);
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");