/*
* spi_parport.c - SPI master controller driver based on the parallel port adapter
*
- * Copyright (C) 2005 David Brownell
- * 2008 Peter Henn
+ * Copyright (C) 2008 Peter Henn <Peter.Henn@web.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * The spi_parport is generated from the spi_butterfly driver, but with the
- * idea to isolate here only the SPI master controller part. Note that we
- * have not implement the full SPI functionality
+ * The spi_parport find its beginning in the spi_butterfly driver, but with the
+ * idea to isolate the SPI master controller part and move all additional SPI
+ * protocoll stuff into separate drivers.
+ * The most important settings can be given to the driver by module load parameter.
+ * Also the SPI-protocol driver can be configured by module load parameter. Make
+ * sure that all related SPI-protocol drivers are load before you load this SPI
+ * controller module!
+ * The SPI parport driver supports more than one SPI device. Therefore all module
+ * parameter can be given as an ARRAY with ',' as a delimiter. Starting from the
+ * first entry up to SPI_DEV_MAX devices will be handled. Therefore a successive
+ * chip selects will be reserved in the parport settings.
*
- * Some important settings can be given to the driver by module load parameter.
- * Also the refernced SPI-protocoll driver can be changed by a module load parameter.
+ * Naturally this driver should normally use its gpio_parport base driver. But just
+ * to prevent additional performace issues I decice to finish this spi_parport.
+ * Both drivers may gives you also the possibility to use them hardware shared on
+ * one parport device, as long as you never use GPIO outputs in the gpio_parport from
+ * the parport data port and move the SPI control signals in the spi_parport driver
+ * to the parport control port - and visa verse, although its not a real software
+ * shared functionality.
*/
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/delay.h>
+#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/parport.h>
+#include <linux/spinlock.h>
#include <linux/sched.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
-//#include <linux/gpio.h>
-/*
- * spi_device
- * todo:
- * - clean up
- * - test spi modes
- * - make driver possible to share the parport with a gpio_parport.c
- */
-
-/* DATA output bits (pins 2..9 == D0..D7) */
-#define MODALIASLEN 10
-#define DRVNAME "spi_parport"
-#define DRIVER_VERSION "0.2"
-
-#define spi_sck_bit (1 << 0) /* pin 2 */
-#define spi_mosi_bit (1 << 7) /* pin 9 */
-
-#define vcc_bits ((1 << 6) | (1 << 5)) /* pins 7, 8 */
-
-/* STATUS input bits */
-#define spi_miso_bit PARPORT_STATUS_BUSY /* pin 11 */
-
-/* CONTROL output bits */
-#define spi_cs_bit (1 << 1) /* pin 3 */
+#ifdef CONFIG_SPI_PARPORT_EXCLUSIVE
+#define sCONFIG_SPI_PARPORT_EXCLUSIVE " CONFIG_SPI_PARPORT_EXCLUSIVE"
+#else
+#define sCONFIG_SPI_PARPORT_EXCLUSIVE ""
+#endif
-/*
- * Parallel
+/* ToDo
+ * 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)
+ *
+ * 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
+ * - SPI_3WIRE depends on signal routing, but is in principle possible
+ * and therefore supported.
+ * - SPI_CS_HIGH is supported
+ * - Slow CPU frequencies are currently not supported. The
+ * maximum Bit rate may be around 200 kBit/sec
+ *
+ * ToDo: - support also bits of the Control port
+ * - support more than one SPI controller
+ *
+ * Parallel
* Port Direction Register Name Signal
* ----------- --------- -------- ---------------------- ------
* nStrobe 1 --> nC0 PARPORT_CONTROL_STROBE
* D0 2 --> D0 (1 << 0) SCLK
- * D1 3 --> D1 (1 << 1) nCS
- * D2 4 --> D2 (1 << 2) --
- * D3 5 --> D3 (1 << 3) --
- * D4 6 --> D4 (1 << 4) --
- * D5 7 --> D5 (1 << 5) --
+ * D1 3 --> D1 (1 << 1) MOSI
+ * D2 4 --> D2 (1 << 2) nCS0
+ * D3 5 --> D3 (1 << 3) nCS1
+ * D4 6 --> D4 (1 << 4) nCS2
+ * D5 7 --> D5 (1 << 5) nCS3
* D6 8 --> D6 (1 << 6) --
- * D7 9 --> D7 (1 << 7) MOSI
+ * D7 9 --> D7 (1 << 7) --
* nAckn 10 <-- S6 PARPORT_STATUS_ACK
- * Busy 11 <-- nS7 PARPORT_STATUS_BUSY MISO
+ * Busy 11 <-- nS7 PARPORT_STATUS_BUSY MISO
* Paper 12 <-- S5 PARPORT_STATUS_PAPEROUT --
* Sel 13 <-- S4 PARPORT_STATUS_SELECT --
* nFeed 14 --> nC1 PARPORT_CONTROL_AUTOFD --
* nError 15 <-- S3 PARPORT_STATUS_ERROR --
* nInit 16 --> C2 PARPORT_CONTROL_INIT --
- * nSelIn 17 --> nC3 PARPORT_CONTROL_SELECT --
+ * nSelIn 17 --> nC3 PARPORT_CONTROL_SELECT --
* GND 25 -- -- GND
+ *
+ * Signal:
+ * - SCLK : SPI Master Clock
+ * - MOSI : SPI Master Data Output, Slave Data Input
+ * - MISO : SPI Master Date Input, Slave Data Output
+ * - nCSx : SPI Chip Select x, default low active
+ * Note: nCSx must be in consecutive bit order!
*/
//*****************************************************************************
-// MODULE PARAMETERS
+// MODULE PARAMETERS
//*****************************************************************************
-/* module parameters */
-static char modalias[MODALIASLEN] = "gtm501l_spi";
-static unsigned int spi_mode = SPI_3WIRE | SPI_MODE_0;
-static unsigned int spi_bits = 16;
-
-static inline struct spi_parport *spidev_to_pp(struct spi_device *spi)
-{
- return spi->controller_data;
-}
+#define DRVNAME "spi_parport" /* name of the driver */
+#define DRIVER_VERSION "0.3" /* helps identifying different versions of that driver */
+#define SPI_PARPORT_SCLK (1 << 0) /* SPI Clock on parport D0 or pin 2 */
+#define SPI_PARPORT_MOSI (1 << 1) /* SPI MOSI on parport D1 or pin 3 */
+#define SPI_PARPORT_CS0 (1 << 2) /* first SPI chipselet on parport D2 or pin 4 */
+#define SPI_PARPORT_MISO PARPORT_STATUS_BUSY /* SPI MISO on parport Status Busy or pin 11 */
-typedef struct {
- struct pardevice *dev; /* Parport device entry */
- struct parport *port; /* */
- struct spi_bitbang bitbang;
- u8 lastbyte; /* hold copy of parport to be faster */
- struct spi_message *msg;
- struct spi_device *spi_parport;
- struct spi_board_info info;
- struct list_head list;
-} spi_parport_struct;
+#define SPI_PARPORT_STATUS_INV 0x80 /* invert internal bit 7 of status parport bit (Busy) */
+#define SPI_PARPORT_CONTROL_INV 0x0b /* invert internal bit 0, 1 and 3 of control parport bits
+ (Strobe, Autofd, Select) */
+#define SPI_PARPORT_MAX_SPEED 1*1000*1000 /* maximum allowed speed for any SPI device, currently not used */
+#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 */
-struct spi_parport {
- /* REVISIT ... for now, this must be first */
- struct spi_bitbang bitbang;
-
- struct parport *port;
- struct pardevice *pdev;
- u8 lastbyte; /* hold copy of parport to be faster */
+/* Module load parameter */
+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_message *msg;
- struct spi_device *spi_parport;
- struct spi_board_info info;
- struct list_head list;
+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 list_head list; /* spi_parport host controller list */
};
+/* helps accessing the spi controller stucture */
+static inline struct spi_parport *spidev_to_pp(struct spi_device *spi)
+{
+ return spi->controller_data;
+}
/*----------------------------------------------------------------------*/
+/* spi_parport to spi_bitbang interface functions */
-
-static inline void
-setsck(struct spi_device *spi, int is_on)
+/**
+ * parport data bit output function
+ */
+static inline void spi_parport_data_set(struct spi_parport *pp, unsigned mask, int value)
{
- struct spi_parport *pp = spidev_to_pp(spi);
- u8 bit, byte = pp->lastbyte;
-
- bit = spi_sck_bit;
-
- if (is_on)
- byte |= bit;
+ u8 byte = pp->dcache; // use old value from cache
+ if (value)
+ byte |= mask;
else
- byte &= ~bit;
- parport_write_data(pp->port, byte);
- pp->lastbyte = byte; /* use parport mirror to be faster */
+ byte &= ~mask;
+ pp->dcache = byte; // restore cache
+ return parport_write_data(pp->port, byte);
}
-static inline void
-setmosi(struct spi_device *spi, int is_on)
+/**
+ * set clock signal
+ */
+static inline void setsck(struct spi_device *spi, int value)
{
- struct spi_parport *pp = spidev_to_pp(spi);
- u8 bit, byte = pp->lastbyte;
-
- bit = spi_mosi_bit;
+ struct spi_parport *pp = spidev_to_pp(spi);
+ return spi_parport_data_set(pp, SPI_PARPORT_SCLK, value);
+}
- if (is_on)
- byte |= bit;
- else
- byte &= ~bit;
- parport_write_data(pp->port, byte);
- pp->lastbyte = byte; /* use parport mirror to be faster */
+/**
+ * set MOSI signal
+ */
+static inline void setmosi(struct spi_device *spi, int value)
+{
+ struct spi_parport *pp = spidev_to_pp(spi);
+ return spi_parport_data_set(pp, SPI_PARPORT_MOSI, value);
}
-static inline int getmiso(struct spi_device *spi)
+/*----------------------------------------------------------------------*/
+/**
+ * parport status bit input function
+ */
+static inline int spi_parport_status_get(struct spi_parport *pp, unsigned mask)
{
- struct spi_parport *pp = spidev_to_pp(spi);
- int value;
- u8 bit;
+ u8 byte = SPI_PARPORT_STATUS_INV ^ parport_read_status(pp->port);
+ return ((byte & mask) != 0);
+}
- bit = spi_miso_bit;
+/**
+ * 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);
+}
- /* only STATUS_BUSY is NOT negated */
- value = !(parport_read_status(pp->port) & bit);
- return (bit == PARPORT_STATUS_BUSY) ? value : !value;
+/**
+ * get MISO signal
+ * supports also loop back mode in master controller
+ */
+static inline int getmiso(struct spi_device *spi)
+{
+ int value;
+ struct spi_parport *pp = spidev_to_pp(spi);
+ if (spi->mode & SPI_LOOP) {
+ /* Loop back mode, read direct from output port is possible, */
+ /* because setmosi will be done before getmiso in txrx */
+ value = spi_parport_data_get(pp, SPI_PARPORT_MOSI);
+ } else {
+ /* default MISO read */
+ value = spi_parport_status_get(pp, SPI_PARPORT_MISO);
+ }
+ return value;
}
+/**
+ * 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);
-
-#if 0
+ struct spi_parport *pp = spidev_to_pp(spi);
/* set default clock polarity */
- if (value != BITBANG_CS_INACTIVE)
- setsck(spi, spi->mode & SPI_CPOL);
-
- /* here, value == "activate or not";
- * most PARPORT_CONTROL_* bits are negated, so we must
- * morph it to value == "bit value to write in control register"
- */
- if (spi_cs_bit == PARPORT_CONTROL_INIT)
- value = !value;
-
- parport_frob_control(pp->port, spi_cs_bit, value ? spi_cs_bit : 0);
-#else
- u8 bit, byte = pp->lastbyte;
-
- bit = spi_cs_bit;
-
- if (value)
- byte &= ~bit;
- else
- byte |= bit;
- parport_write_data(pp->port, byte);
- pp->lastbyte = byte; /* use parport mirror to be faster */
-#endif
+ if (value == BITBANG_CS_INACTIVE) {
+ /* Deselect the slaves on the SPI bus by programming CS to inactive state */
+ spi_parport_data_set(pp, SPI_PARPORT_CS0 << spi->chip_select, (spi->mode & SPI_CS_HIGH)==0);
+ } else if (value == BITBANG_CS_ACTIVE) {
+ /* Set the SPI clock phase and polarity */
+ setsck(spi, (spi->mode & SPI_CPOL)!=0);
+ /* Activate the chip select by programming CS to active state */
+ if ((spi->chip_select >= 0) && (spi->chip_select < SPI_DEV_MAX)) {
+ spi_parport_data_set(pp, SPI_PARPORT_CS0 << spi->chip_select, (spi->mode & SPI_CS_HIGH)!=0);
+ } else {
+ pr_err("%s: Use chip %sCS%d select out of range CS0 - CS%d\n",
+ DRVNAME, ((spi->mode & SPI_CS_HIGH)!=0)?"":"/", spi->chip_select, SPI_DEV_MAX);
+ }
+ }
}
-// we do not wait, because parport is even slow, but if X > 10000, this would become important
-//#define spidelay ndelay
+/* use default TXRX bitbang interface functions from header file */
+#define EXPAND_BITBANG_TXRX
+
+/* currently we omit any additional delay, because parport is even slow.
+ Naturally for X > 10000, a delay would become more important */
#define spidelay(X) do{}while(0)
-#define EXPAND_BITBANG_TXRX
#include <linux/spi/spi_bitbang.h>
-static u32
-spi_parport_txrx_word_mode0(struct spi_device *spi,
+static u32 spi_parport_txrx_word_mode0(struct spi_device *spi,
unsigned nsecs,
u32 word, u8 bits)
{
return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
}
-static u32
-spi_parport_txrx_word_mode1(struct spi_device *spi,
+static u32 spi_parport_txrx_word_mode1(struct spi_device *spi,
unsigned nsecs,
u32 word, u8 bits)
{
return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
}
-static u32
-spi_parport_txrx_word_mode2(struct spi_device *spi,
+static u32 spi_parport_txrx_word_mode2(struct spi_device *spi,
unsigned nsecs,
u32 word, u8 bits)
{
return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
}
-static u32
-spi_parport_txrx_word_mode3(struct spi_device *spi,
+static u32 spi_parport_txrx_word_mode3(struct spi_device *spi,
unsigned nsecs,
u32 word, u8 bits)
{
}
+/*----------------------------------------------------------------------*/
+#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;
+ for(i=0; i<count; i++) {
+ if (*src == '\0') {
+ *dst='\0';
+ return src;
+ }
+ if (strchr(dlim, *src)!=NULL) {
+ *dst='\0';
+ return ++src;
+ }
+ *dst++=*src++;
+ }
+ *--dst='\0'; /* add missing line end */
+ return NULL;
+}
+
+
+/**
+ * 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 */
+
+ /* 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 */
+ if (NULL == spi[i]) {
+ while (i > 0) {
+ spi_dev_put(spi[--i]); /* free all spi devices from former spi_alloc_device */
+ }
+ return -ENOMEM;
+ }
+
+ /*
+ * first copy the modalias parameter
+ */
+ modalias_param=strnarr(spi[i]->modalias, modalias_param, " ,", sizeof(spi[i]->modalias));
+ if (NULL == spi[i]->modalias) {
+ pr_err("%s: %d given modalias name is too long! See only that '%s'!\n",
+ DRVNAME, i, spi[i]->modalias);
+ while (i >= 0) {
+ spi_dev_put(spi[i--]); /* free all spi devices */
+ }
+ return -EINVAL;
+ }
+
+ /*
+ * now setup the rest as it would be done by
+ * the spi_new_device from a given board_info
+ * structure.
+ */
+ spi[i]->max_speed_hz = SPI_PARPORT_MAX_SPEED;
+ spi[i]->chip_select = i;
+ spi[i]->master = pp->bitbang.master;
+ 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 = 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 */
+ /*
+ * first only initialize the chipselect
+ * for that spi device to set it inactive
+ */
+ spi_parport_chipselect(spi[i], BITBANG_CS_INACTIVE);
+ if (spi_mode_cnt < (i+1)) {
+ pr_warning("%s: No spi mode parameter given for device %d with driver '%s'. "
+ "Will use default setting: %d\n",
+ DRVNAME, i, spi[i]->modalias, spi[i]->mode);
+ }
+ }
+ /* additional parameter checks and possibly logged warnings */
+ 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 (spi_mode_cnt > i) {
+ pr_warning("%s: Found further %d mode parameters than SPI devices used or no SPI mode defined!\n",
+ DRVNAME, spi_mode_cnt-i);
+ }
+ /*
+ * Now all spi device structures are setup and all used
+ * chipselects are initialized. We will now add the
+ * spi devices for probing and usage. We use the same
+ * ordering!
+ */
+ max = i; /* remember the last value */
+ for (i=0; i<max; i++) {
+ int err;
+
+ err = spi_add_device(spi[i]);
+ if (err < 0) {
+ /*
+ * free all further spi devices too.
+ * all already added spi devices will be freed
+ * later with the final call to spi_master_put
+ */
+ while (i<max) {
+ spi_dev_put(spi[i++]);
+ }
+ pr_err("%s: spi_new_device failed!\n", DRVNAME);
+ return -ENODEV;
+ }
+ 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);
+ }
+ }
+ return i;
+}
/***************************************************************************
- * Parallel port probing routines *
+ * Parallel port attaching and detaching routines *
***************************************************************************/
static LIST_HEAD(spi_parport_hosts);
-
-static void spi_parport_attach(struct parport *p)
+/**
+ * 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)
{
- int status;
- struct spi_parport *pp;
- struct spi_master *master;
- struct device *dev;
-
-#if 0
- *dev = p->physport->dev;
- # spi_parport no longer existing, we use now a standard list structure
- # therefore getting from p->physport->dev makes no sense any longer
- # end testing as well
- if (spi_parport || !dev)
- return;
-#endif
- /* REVISIT: this just _assumes_ a spi_parport is there ... no probe,
- * and no way to be selective about what it binds to.
- */
+ 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;
+ }
+ /* spi_alloc_master gives zero initialized structure */
master = spi_alloc_master(dev, sizeof *pp);
- if (!master) {
- status = -ENOMEM;
- goto done;
+ if (master == NULL) {
+ return -ENOMEM;
}
+ master->bus_num = -1; /* dynamic allocation of a bus number */
+ master->num_chipselect = SPI_DEV_MAX; /* setup maximum capability */
+
+ /* call the container_of fkt */
pp = spi_master_get_devdata(master);
- master->bus_num = -1; /* dynamic alloc of a bus number */
- master->num_chipselect = 1;
+ if (pp == NULL) {
+ err = -ENOMEM;
+ goto err_release_mem;
+ }
- /*
- * SPI and bitbang hookup
- *
- * use default setup(), cleanup(), and transfer() methods; and
- * only bother implementing mode 0. Start it later.
- */
- pp->bitbang.master = spi_master_get(master);
+ /* ----------------- SPI BitBang Hook ---------------- */
+ /* use default setup(), cleanup(), and transfer() methods */
+ pp->bitbang.master = spi_master_get(master); /* now pp->bitbang.master = master */
pp->bitbang.chipselect = spi_parport_chipselect;
pp->bitbang.txrx_word[SPI_MODE_0] = spi_parport_txrx_word_mode0;
pp->bitbang.txrx_word[SPI_MODE_1] = spi_parport_txrx_word_mode1;
pp->bitbang.txrx_word[SPI_MODE_2] = spi_parport_txrx_word_mode2;
pp->bitbang.txrx_word[SPI_MODE_3] = spi_parport_txrx_word_mode3;
- pp->bitbang.flags = spi_mode; //############### get info from board info would be even better
-
- /*
- * parport hookup
- */
- pp->port = p;
- //##### because we want to share with gpio_partport !!!!!
- pp->pdev = parport_register_device(p, DRVNAME,
- NULL, NULL, NULL,
- 0 /* FLAGS */, pp); //PARPORT_FLAG_EXCL, pp);
- if (!pp->pdev) {
+ pp->bitbang.flags = SPI_CS_HIGH | SPI_3WIRE | SPI_LOOP; /* setup supported mode flags */
+
+ /* ----------------- ParPort Hook -------------------- */
+ /* REVISIT: no probe, just think it is there */
+ pp->port = pb;
+
+ //ToDo: share parport with other device, but may need a mutex lock!
+ //ToDo: check supported modes are ok
+ //ToDo: PM support, e.g. Suspend and Resume
+ pp->dev = parport_register_device(pb, /* port */
+ DRVNAME, /* driver name */
+ NULL, /* preemption fkt */
+ NULL, /* wake-up fkt */
+ NULL, /* no interrupt handler used */
+ #ifdef CONFIG_SPI_PARPORT_EXCLUSIVE
+ PARPORT_FLAG_EXCL, /* flags */
+ #else
+ 0, /* flags, 0 means used port shared */
+ #endif
+ pp /* handle */ );
+ if (pp->dev == NULL) {
pr_err("%s: unable to register with parport\n", DRVNAME);
- status = -ENOMEM;
- goto clean0;
+ err = -ENOMEM;
+ goto err_release_mem;
}
- //ToDo: Check and share really parport device as it is done e.g. in ppa.c
- status = parport_claim(pp->pdev);
- if (status < 0)
- goto clean1;
+ err = parport_claim(pp->dev);
+ if (err < 0) {
+ pr_err("%s: unable to claim parport\n", DRVNAME);
+ err = -ENODEV;
+ goto err_unregister_parport;
+ }
- pp->lastbyte = 0;
- parport_write_data(pp->port, pp->lastbyte);
+ /* ----------------- SPI ParPort init ---------------- */
+ /* cache initialization just preventing changing unused bits */
+ pp->dcache = parport_read_data(pp->port);
/*
- * Spi_Parport powerup, run firmware
+ * loop over all irq module parameter, which must be exchanged by
+ * the parport irq, if value requires PARAM_IRQ_VAL_AUTO
*/
- pr_debug("%s: powerup Spi_Parport\n", DRVNAME);
-
- //##### nCS setting depends on spi_mode ....
- /* nCS for dataflash (this bit is inverted on output) */
- parport_frob_control(pp->port, spi_cs_bit, 0);
-
- /* stabilize power with spi_sck_bit clear (CPOL=0)
- */
- pp->lastbyte |= vcc_bits;
- parport_write_data(pp->port, pp->lastbyte);
- msleep(5);
+ 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);
+ }
- /*
- * Start SPI ... for now, hide that we're two physical busses.
- */
- status = spi_bitbang_start(&pp->bitbang);
- if (status < 0) {
+ err = spi_bitbang_start(&pp->bitbang);
+ if (err < 0) {
pr_warning("%s: spi_bitbang_start failed with status %d\n",
- DRVNAME, status);
- goto clean2;
+ DRVNAME, err);
+ goto err_release_parport;
}
- /*
- * The modalias name MUST match the device_driver name
- * for the bus glue code to match and subsequently bind them.
- * We are binding to the generic drivers/hwmon/lm70.c device
- * driver.
- */
- if (modalias[0]) {
- pr_info("%s: Will load protocol driver: '%s'!\n", DRVNAME, modalias);
- } else goto clean2;
-
- /* need to make this parameter loadable */
- strcpy(pp->info.modalias, modalias);
- pp->info.max_speed_hz = 15 * 1000 * 1000;
- pp->info.chip_select = 0; // 0: .. 1:
- pp->info.mode = spi_mode;
-
- /* Enable access to our primary data structure via
- * the board info's (void *)controller_data.
- */
- pp->info.platform_data = NULL; // here we should add data structures for subsystem driver ???
- pp->info.controller_data = pp; /* save my structure for later use */
- pp->spi_parport = spi_new_device(pp->bitbang.master, &pp->info);
- if (pp->spi_parport)
- pr_info("%s: SPI tty at %s\n", DRVNAME,
- pp->spi_parport->dev.bus_id);
- else {
- pr_warning("%s: spi_new_device failed\n", DRVNAME);
- status = -ENODEV;
- goto out_bitbang_stop;
- }
- pp->spi_parport->bits_per_word=spi_bits;
-
- /* get spi_bitbang_transfer either via global Symbol, or better
- * ask it from the driver structure
- */
- pp->msg = spi_message_alloc(1, GFP_KERNEL);
- if (master) { /* the same address is also saved in pp->bitbang.master or pp->spi_parport->master */
- struct spi_message *spi_msg;
- spi_msg = pp->msg;
- if (spi_msg) {
- // spi_message_init(spi_msg);
- pr_info("Alloc SPI message buffer\n");
- spi_msg->spi = pp->spi_parport;
- spi_msg->actual_length = 1;
-#if 0
- spi_msg->list_head ... Addresse der ersten SPI transfer struct
-
-
- spi_msg->tx_buf = ;
- spi_msg->len = 1;
- spi_msg->cs_change = 1;
- spi_msg->delay_usecs = 0;
-
- /* fill up message */
- master->transfer(pp->spi_parport, spi_msg);
-#endif
- }
+ /* ----------------- SPI BoardInfo init -------------- */
+ err = spi_parport_register_spi_devices(pp);
+ if (err == 0) {
+ pr_err("%s: at least one protocol driver name is needed, non found!\n", DRVNAME);
+ err = -ENODEV;
+ goto err_spi_controller_stop;
+ } else if (err < 0) {
+ goto err_spi_controller_stop;
}
list_add_tail(&pp->list, &spi_parport_hosts);
- return;
+ return 0;
-out_bitbang_stop:
+ err_spi_controller_stop:
+ /* this will unregister child SPI devices too, if there any */
spi_bitbang_stop(&pp->bitbang);
-clean2:
- /* turn off VCC */
- parport_write_data(pp->port, 0);
-
- parport_release(pp->pdev);
-clean1:
- parport_unregister_device(pp->pdev);
-clean0:
- (void) spi_master_put(pp->bitbang.master);
-done:
- pr_debug("%s: spi_parport probe, fail %d\n", DRVNAME, status);
+ err_release_parport:
+ parport_release(pp->dev);
+ err_unregister_parport:
+ parport_unregister_device(pp->dev);
+ err_release_mem:
+ spi_master_put(master); /* will release memory */
+ return err;
}
-static void spi_parport_detach(struct parport *p)
+
+static void spi_parport_attach(struct parport *pb)
{
- struct spi_parport *pp;
- int status;
+ (void)__spi_parport_attach(pb);
+}
- list_for_each_entry(pp, &spi_parport_hosts, list) {
- if (pp->pdev->port == p) {
- list_del_init(&pp->list);
- if (pp->msg) {
- spi_message_free(pp->msg);
- pr_info("Dealloc SPI message buffer\n");
- }
- /* stop() unregisters child devices too */
- status = spi_bitbang_stop(&pp->bitbang);
-
- /* turn off VCC */
- parport_write_data(pp->port, 0);
- msleep(10);
- parport_release(pp->pdev);
- parport_unregister_device(pp->pdev);
- (void) spi_master_put(pp->bitbang.master);
- kfree(pp);
- break;
- }
+
+static int spi_parport_remove(struct spi_parport *pp)
+{
+ int err;
+
+ /* stop and unregisters child devices too */
+ err = spi_bitbang_stop(&pp->bitbang);
+ if (err < 0) {
+ pr_err("%s: bitbang stop error: %d\n", DRVNAME, err);
}
+ parport_release(pp->dev);
+ parport_unregister_device(pp->dev);
+ /* this frees also the pp struct */
+ spi_master_put(pp->bitbang.master);
+ return err;
}
-#if 0
static void spi_parport_detach(struct parport *pb)
{
- spi_parport_struct *dev;
- list_for_each_entry(dev, &spi_parport_hosts, list) {
- if (dev->dev->port == pb) {
- list_del_init(&dev->list);
+ struct spi_parport *pp;
- spi_remove_host(dev->host);
- spi_host_put(dev->host);
-
- parport_release(dev->pdev);
- parport_unregister_device(dev->pdev);
- kfree(dev);
+ list_for_each_entry(pp, &spi_parport_hosts, list) {
+ if (pp->port == pb) {
+ list_del_init(&pp->list);
+ (void)spi_parport_remove(pp);
break;
}
}
}
-#endif
static struct parport_driver spi_parport_driver = {
.name = DRVNAME,
}
module_exit(spi_parport_exit);
+MODULE_AUTHOR("Option Wireless");
MODULE_DESCRIPTION("SPI master controller driver for Parport Adapter");
MODULE_LICENSE("GPL");
-module_param_string(spi_pdrv, modalias, sizeof(modalias), S_IRUGO);
-MODULE_PARM_DESC(spi_pdrv, "spi protocol driver name");
+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(spi_mode, uint, S_IRUGO);
-MODULE_PARM_DESC(spi_mode, "spi mode");
+module_param_array_named(mode, spi_mode, uint, &spi_mode_cnt, S_IRUGO);
+MODULE_PARM_DESC(mode, "array of spi modes for each driver");
-module_param(spi_bits, uint, S_IRUGO);
-MODULE_PARM_DESC(spi_bits, "spi bits per word");
+module_param_array_named(bits, spi_bits, uint, &spi_bits_cnt, S_IRUGO);
+MODULE_PARM_DESC(bits, "array of spi bits per word for each driver");
+MODULE_INFO(Flags, sCONFIG_SPI_PARPORT_EXCLUSIVE);
MODULE_INFO(Version, DRIVER_VERSION);