From: Peter Henn Date: Thu, 1 Jan 2009 11:02:53 +0000 (+0100) Subject: spi_parport and gpio_parport first release X-Git-Tag: v0.2~1 X-Git-Url: http://git.linex4red.de/pub/spi-gpio-pp.git/commitdiff_plain/64f1eafb27e338f0c16677692df232c84866cc2a spi_parport and gpio_parport first release spi_parport: - fully rework of the spi_parport - first real test done gpio_parport: - add compile feature 'use parport exclusive' - add compile feature 'claim parport' as a hack to share one parport by both drivers gpio_parport and spi_parport. - correct GPIO signals, which are inverted used - add module parameter for force setting interrupt line - add module parameter for force setting GPIO base address --- diff --git a/gpio_parport.c b/gpio_parport.c index 73a16b1..0bddbcd 100644 --- a/gpio_parport.c +++ b/gpio_parport.c @@ -43,21 +43,29 @@ #include #define sCONFIG_GPIO_PARPORT_MUTEX "" #endif - +#ifdef CONFIG_GPIO_PARPORT_EXCLUSIVE +#define sCONFIG_GPIO_PARPORT_EXCLUSIVE " CONFIG_GPIO_PARPORT_EXCLUSIVE" +#undef CONFIG_GPIO_PARPORT_NOCLAIME +#else +#define sCONFIG_GPIO_PARPORT_EXCLUSIVE "" +#endif +#ifdef CONFIG_GPIO_PARPORT_NOCLAIME +#define sCONFIG_GPIO_PARPORT_NOCLAIME " CONFIG_GPIO_PARPORT_NOCLAIME" +#else +#define sCONFIG_GPIO_PARPORT_NOCLAIME "" +#endif /* ToDo: * - proper handling error flags for gpio_to_irq ... - * - using pp->dev-port should be equal to pp->port ... * - Sharing parport with other devices controled by module load * paramter with using mutex mode ... but check with releasing parport IRQ handler * - Verifing Parport modes - * - Add sysfs Debug functionality * - Support PM functions like resume, suspend * * Parallel * Port Direction Register Name Signal * ----------- --------- -------- ---------------------- ------ - * nStrobe 1 --> nC0 PARPORT_CONTROL_STROBE nGPO08 + * nStrobe 1 --> nC0 PARPORT_CONTROL_STROBE GPO08 * D0 2 --> D0 (1 << 0) GPO00 * D1 3 --> D1 (1 << 1) GPO01 * D2 4 --> D2 (1 << 2) GPO02 @@ -67,20 +75,19 @@ * D6 8 --> D6 (1 << 6) GPO06 * D7 9 --> D7 (1 << 7) GPO07 * nAckn 10 <-- S6 PARPORT_STATUS_ACK GPI15* - * Busy 11 <-- nS7 PARPORT_STATUS_BUSY nGPI16 + * Busy 11 <-- nS7 PARPORT_STATUS_BUSY GPI16 * Paper 12 <-- S5 PARPORT_STATUS_PAPEROUT GPI14 * Sel 13 <-- S4 PARPORT_STATUS_SELECT GPI13 - * nFeed 14 --> nC1 PARPORT_CONTROL_AUTOFD nGPO09 + * nFeed 14 --> nC1 PARPORT_CONTROL_AUTOFD GPO09 * nError 15 <-- S3 PARPORT_STATUS_ERROR GPI12 * nInit 16 --> C2 PARPORT_CONTROL_INIT GPO10 - * nSelIn 17 --> nC3 PARPORT_CONTROL_SELECT nGPO11 + * nSelIn 17 --> nC3 PARPORT_CONTROL_SELECT GPO11 * GND 25 -- -- GND * * Signal: * - GPOx : general purpose output only * - GPIx : general purpose input only * - GPIx* : interrupt in - * - nGPXx : signal is inverted */ //***************************************************************************** @@ -94,9 +101,12 @@ #define GPIO_PARPORT_STAT_PORT_OFF 3 /* parport status port needs internally 3 bit offset */ #define GPIO_PARPORT_INTERRUPT 15 /* gpio offset for parport pin Acknolge, which support interrupt */ #define GPIO_PARPORT_NR_GPIOS 17 /* parport support up to 17 general purpose (dedicated) Inputs and Outputs */ +#define GPIO_PARPORT_STATUS_INV 0x80 /* invert internal bit 7 of status parport bit (Busy) */ +#define GPIO_PARPORT_CONTROL_INV 0x0b /* invert internal bit 0, 1 and 3 of control parport bits (strobe, autofd, select) */ - -static int modparam_gpiobase = -1 /* dynamic assingment */; +/* Module load parameter */ +static int irq=-1; /* force irq for parport pin 10 */ +static int gpiobase = -1 /* default dynamic assignment */; typedef struct { struct pardevice *dev; /* parport device entry */ @@ -161,7 +171,7 @@ static inline int gpio_parport_data_get(gpio_pp_struct *pp, unsigned mask) static inline int gpio_parport_ctrl_get(gpio_pp_struct *pp, unsigned mask) { // good idea to update also the cache - pp->ccache = parport_read_control(pp->port); + pp->ccache = GPIO_PARPORT_CONTROL_INV ^ parport_read_control(pp->port); return ((pp->ccache & mask) != 0); } @@ -170,7 +180,7 @@ static inline int gpio_parport_ctrl_get(gpio_pp_struct *pp, unsigned mask) */ static inline int gpio_parport_status_get(gpio_pp_struct *pp, unsigned mask) { - unsigned int cache = parport_read_status(pp->port); + unsigned int cache = GPIO_PARPORT_STATUS_INV ^ parport_read_status(pp->port); return ((cache & mask) != 0); } @@ -181,7 +191,7 @@ static inline int gpio_parport_status_get(gpio_pp_struct *pp, unsigned mask) static int gpio_parport_get(struct gpio_chip *gpio, unsigned offset) { gpio_pp_struct *pp = container_of(gpio, gpio_pp_struct, gpio); - int status = 0; /* inititalization ensures returm zero for unhandled bits */ + int status = 0; /* inititalization ensures return zero for unhandled bits */ unsigned long flags; if (offset < GPIO_PARPORT_CTRL_PORT_BITS) { @@ -232,7 +242,7 @@ static inline void gpio_parport_ctrl_set(gpio_pp_struct *pp, unsigned mask, int else byte &= ~mask; pp->ccache = byte; // restore cache - return parport_write_control(pp->port, byte); + return parport_write_control(pp->port, (GPIO_PARPORT_CONTROL_INV ^ byte)); } /* @@ -342,7 +352,7 @@ static void gpio_parport_gpio_setup(gpio_pp_struct *pp) c->free = NULL; c->to_irq = gpio_parport_gpio_to_irq; #endif - c->base = modparam_gpiobase; + c->base = gpiobase; c->ngpio = GPIO_PARPORT_NR_GPIOS; #ifdef CONFIG_GPIO_PARPORT_MUTEX c->can_sleep = 1; @@ -359,10 +369,10 @@ static void gpio_parport_gpio_setup(gpio_pp_struct *pp) static LIST_HEAD(gpio_parport_hosts); /* -** attach driver to parport is currently done with exclusive access. Unfortunately -** 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 this drivers -** first as long as no shared supported is here implemented. +** 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 __gpio_parport_attach(struct parport *pb) { @@ -394,7 +404,11 @@ static int __gpio_parport_attach(struct parport *pb) NULL, /* preemption fkt */ NULL, /* wake-up fkt */ NULL, /* interrupt handler */ - PARPORT_FLAG_EXCL, /* flags */ + #ifdef CONFIG_GPIO_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); @@ -402,25 +416,37 @@ static int __gpio_parport_attach(struct parport *pb) goto err_release_mem; } + #ifndef CONFIG_GPIO_PARPORT_NOCLAIME err = parport_claim(pp->dev); if (err < 0) { pr_err("%s: unable to claim parport\n", DRVNAME); err = -ENODEV; goto err_unregister_parport; } + #endif /* ------------- GPIO PARPORT init --------------- */ /* cache initialisation just preventing changing unused bits */ pp->dcache = parport_read_data(pp->port); - pp->ccache = parport_read_control(pp->port); - - /* interrrut initialidation */ - /* works for x86 arch, because we have nothing special to handle here */ - if(pp->dev->port->irq != PARPORT_IRQ_NONE) { - pp->irq = pp->dev->port->irq; + pp->ccache = GPIO_PARPORT_CONTROL_INV ^ parport_read_control(pp->port); + + /* interrrut initialization */ + /* tested on x86 arch, because irq has nothing special to handle here */ + 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->dev->port); - pr_info("%s: IRQ %d is available\n", DRVNAME, pp->irq); + 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; } @@ -440,8 +466,10 @@ static int __gpio_parport_attach(struct parport *pb) return 0; err_release_parport: + #ifndef CONFIG_GPIO_PARPORT_NOCLAIME parport_release(pp->dev); err_unregister_parport: + #endif parport_unregister_device(pp->dev); err_release_mem: kfree(pp); @@ -465,9 +493,10 @@ static int gpio_parport_remove(gpio_pp_struct *pp) err = gpiochip_remove(&pp->gpio); if (err < 0) pr_err("%s: gpio_remove error: %d\n", DRVNAME, err); + #ifndef CONFIG_GPIO_PARPORT_NOCLAIME parport_release(pp->dev); + #endif parport_unregister_device(pp->dev); - //ToDo: Check the unregister return value return err; } @@ -476,7 +505,7 @@ static void gpio_parport_detach(struct parport *pb) gpio_pp_struct *pp; list_for_each_entry(pp, &gpio_parport_hosts, list) { - if (pp->dev->port == pb) { + if (pp->port == pb) { (void)gpio_parport_remove(pp); list_del_init(&pp->list); kfree(pp); @@ -508,5 +537,11 @@ MODULE_AUTHOR("Option Wireless"); MODULE_DESCRIPTION("GPIO master controller driver for Parport Adapter"); MODULE_LICENSE("GPL"); -MODULE_INFO(Flags, sCONFIG_GPIO_PARPORT_MUTEX); +module_param(irq, uint, S_IRUGO); +MODULE_PARM_DESC(irq, "force set IRQ for parport pin 10"); + +module_param_named(base, gpiobase, uint, S_IRUGO); +MODULE_PARM_DESC(base, "force set GPIO base address"); + +MODULE_INFO(Flags, sCONFIG_GPIO_PARPORT_MUTEX sCONFIG_GPIO_PARPORT_EXCLUSIVE sCONFIG_GPIO_PARPORT_NOCLAIME); MODULE_INFO(Version, DRIVER_VERSION); diff --git a/spi_parport.c b/spi_parport.c index 0c2b67e..82c71b2 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,225 +17,277 @@ * 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: - * - 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 + * 0. 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. first setup all CS, because spi_new_device or spi_add_device will call + * probe fkt of the SPI protocoll driver. This might initiate a SPI transfer + * and triggers the SCLK, which is worse for other chips on the SPI-BUS using + * the wrong CS polarity + * 2. use spi_add_device instead of spi_new_device. That's the only chance + * to setup the also the SPI bits per word value, just before any transaction + * might be initiated with the SPI probe fkt of the SPI protocol driver. + * Setting this spi->bits_per_word value afterwards might be here too late. + * Note that bits_per_word is normally has to be set normally by the protocoll + * driver (e.g. a bad style of the lm70.c driver, which guess that the value is + * setup afterwards) + * Therefore we MUST support a mode, where NOTHING will be changed! + * 3. support better irq via array load parameter and values like AUTO, NONE. Additionally + * don't free any interrupt, if no interrupt might be requested + * 4. output warning, if open mode, bits values after finish init + * 5. test spi modes + * + * 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) -- + * D1 3 --> D1 (1 << 1) MOSI + * D2 4 --> D2 (1 << 2) nCS0 + * D3 5 --> D3 (1 << 3) nCS1 * D4 6 --> D4 (1 << 4) -- * D5 7 --> D5 (1 << 5) -- * 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; -} - - -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 DRVNAME "spi_parport" /* name of the driver */ +#define DRIVER_VERSION "0.2" /* helps identifing 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 */ + +#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 */ + +/* 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; 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 */ - - struct spi_message *msg; - struct spi_device *spi_parport; - struct spi_board_info info; - struct list_head list; + 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 */ }; +/* 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: Neiter the dcache is here updated nor the value is read from that dcache +** to ensure similar system timing bahaviour 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) { @@ -244,226 +295,291 @@ 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. +*/ +const char *strnarr(char *dst, const char *src, const char *dlim, size_t count) +{ + int i; + for(i=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; + } + if (spi_bits_cnt < i) { + pr_warning("%s: No spi bits per word parameter given for device %d with driver '%s'. " + "Will use default setting: %d\n", + DRVNAME, i, chip.modalias, spi_bits[i-1]); + } + proxy->bits_per_word=spi_bits[i-1]; + 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); + } + 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; + struct spi_master *master; /* is only temporary need */ + struct device *dev = pb->physport->dev; + struct spi_parport *pp; + int err; -#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. - */ + 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; - - pp->lastbyte = 0; - parport_write_data(pp->port, pp->lastbyte); - - /* - * Spi_Parport powerup, run firmware - */ - 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); - - /* - * Start SPI ... for now, hide that we're two physical busses. - */ - status = spi_bitbang_start(&pp->bitbang); - if (status < 0) { - pr_warning("%s: spi_bitbang_start failed with status %d\n", - DRVNAME, status); - goto clean2; + err = parport_claim(pp->dev); + if (err < 0) { + pr_err("%s: unable to claim parport\n", DRVNAME); + err = -ENODEV; + goto err_unregister_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; + /* ----------------- SPI ParPort init ---------------- */ + /* cache initialisation 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; } - 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 + err = spi_bitbang_start(&pp->bitbang); + if (err < 0) { + pr_warning("%s: spi_bitbang_start failed with status %d\n", + DRVNAME, err); + goto err_release_parport; + } - 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, @@ -484,16 +600,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(irq, uint, S_IRUGO); +MODULE_PARM_DESC(irq, "Force IRQ for parport pin 10"); + +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);