X-Git-Url: http://git.linex4red.de/pub/spi-gpio-pp.git/blobdiff_plain/e539cfa0af8f19cb21fca37079e4805935814ba5..refs/heads/master:/spi_parport.c diff --git a/spi_parport.c b/spi_parport.c index 00c6b51..f88d635 100644 --- a/spi_parport.c +++ b/spi_parport.c @@ -1,8 +1,7 @@ /* * 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 * * 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 @@ -18,237 +17,262 @@ * 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 #include -#include +#include #include #include +#include #include #include #include -//#include -/* - * spi_device - * todo: - * - implement SPI mode 1,2,3 is yet missing - * - prevent ugly handling of global spi_parport structure -//drivers/i2c/busses/i2c-parport.c -// uses one static pointer of a list: -//static struct i2c_par *adapter_list; -//drivers/scsi/ppa.c -// uses one static pointer of a list: -// static LIST_HEAD(ppa_hosts); -//the spi_parport structure has to be pushed into the heap and the pointer has to be saved into the SPI core structre ... - * - 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! */ //***************************************************************************** -// Globals +// 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 */ -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_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 */ +#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) */ -struct spi_parport { - /* REVISIT ... for now, this must be first */ - struct spi_bitbang bitbang; - - struct parport *port; - struct pardevice *pdev; +#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 */ - u8 lastbyte; /* hold copy of parport to be faster */ - struct spi_message *msg; - struct spi_device *spi_parport; - struct spi_board_info info; +/* 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_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 */ }; -static LIST_HEAD(spi_parport); - -/* REVISIT remove this ugly global and its "only one" limitation */ -static struct spi_parport *spi_parport; - +/* 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 -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) { @@ -256,217 +280,373 @@ spi_parport_txrx_word_mode3(struct spi_device *spi, } - /*----------------------------------------------------------------------*/ +#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; +} -static void spi_parport_attach(struct parport *p) +int param_get_irq(char *pbuf, struct kernel_param *kp) { - int status; - struct spi_parport *pp; - struct spi_master *master; - struct device *dev = p->physport->dev; + 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; ibitbang.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; iirq) { + 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 attaching and detaching routines * + ***************************************************************************/ + +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. + */ +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; + } + + /* 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; } - 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; } - spi_parport = pp; - return; + list_add_tail(&pp->list, &spi_parport_hosts); + 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) -{ - struct spi_parport *pp; - int status; - - /* FIXME this global is ugly ... but, how to quickly get from - * the parport to the "struct spi_parport" associated with it? - * "old school" driver-internal device lists? - */ - if (!spi_parport || spi_parport->port != p) - return; - pp = spi_parport; - 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); +static void spi_parport_attach(struct parport *pb) +{ + (void)__spi_parport_attach(pb); +} - parport_release(pp->pdev); - parport_unregister_device(pp->pdev); - (void) spi_master_put(pp->bitbang.master); +static int spi_parport_remove(struct spi_parport *pp) +{ + int err; - spi_parport = NULL; + /* 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; } static void spi_parport_detach(struct parport *pb) { - ppa_struct *dev; - list_for_each_entry(dev, &ppa_hosts, list) { - if (dev->dev->port == pb) { - list_del_init(&dev->list); - scsi_remove_host(dev->host); - scsi_host_put(dev->host); - parport_unregister_device(dev->dev); - kfree(dev); + struct spi_parport *pp; + + list_for_each_entry(pp, &spi_parport_hosts, list) { + if (pp->port == pb) { + list_del_init(&pp->list); + (void)spi_parport_remove(pp); break; } } } - static struct parport_driver spi_parport_driver = { .name = DRVNAME, .attach = spi_parport_attach, @@ -486,16 +666,21 @@ static void __exit spi_parport_exit(void) } 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_mode, "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);