Test modalias with spi_tty
authorPeter Henn <Peter.Henn@web.de>
Wed, 31 Dec 2008 16:06:21 +0000 (17:06 +0100)
committerPeter Henn <Peter.Henn@web.de>
Wed, 31 Dec 2008 16:06:21 +0000 (17:06 +0100)
Also add some comments and marks things, which currently unclear.
Spi_tty is just a test driver to become more comfortable with the
SPI master controller and the parport.

spi_tty.c

index 1a80bea..02e26e1 100644 (file)
--- a/spi_tty.c
+++ b/spi_tty.c
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * idea:
+ * separate the butterfly driver into a hotpluggable SPI master controller
+ * use a board description file, which loads the:
+ * - the SPI master controller
+ * - the SPI protocoll driver
+ * call spi_new_device with 
+   - spi_master = butterfly parport driver (or parameter configurable)
+   - spi_board_info = infos about Mauro-Lite
+
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
  */
 
 /* DATA output bits (pins 2..9 == D0..D7) */
  */
 
 /* DATA output bits (pins 2..9 == D0..D7) */
+#define MODALIASLEN     10
+#define DRVNAME                "spi_butterfly"
+#define DRIVER_VERSION  "0.2"
+
 #define        butterfly_nreset (1 << 1)               /* pin 3 */
 
 #define        spi_sck_bit     (1 << 0)                /* pin 2 */
 #define        butterfly_nreset (1 << 1)               /* pin 3 */
 
 #define        spi_sck_bit     (1 << 0)                /* pin 2 */
 /* CONTROL output bits */
 #define        spi_cs_bit      PARPORT_CONTROL_SELECT  /* pin 17 */
 
 /* CONTROL output bits */
 #define        spi_cs_bit      PARPORT_CONTROL_SELECT  /* pin 17 */
 
+/*
+ *   Parallel                
+ *     Port      Direction   Signal
+ *  -----------  ---------  ------------
+ *      D0    2     -->       SCLK
+ *      D1    3     -->      nRESET
+ *      D2    4     -->        --
+ *      D3    5     -->        --
+ *      D4    6     -->        --
+ *      D5    7     -->        --
+ *      D6    8     -->        --
+ *      D7    9     -->       MOSI
+ *     GND   25      -        GND
+ *    Busy   11     <--       MISO  
+ *    Paper  12     <--        --
+ *    Select 13     <--        --
+ *    Feed   14     -->        --
+ *    Error  15     <--        --
+ *    Init   16     -->        --
+ *    Select 17     -->      nCS
+ */
 
 
+//*****************************************************************************
+// Globals
+//*****************************************************************************
+/* module parameters */
+static  char                   modalias[MODALIASLEN] = "maurol";
 
 static inline struct butterfly *spidev_to_pp(struct spi_device *spi)
 {
 
 static inline struct butterfly *spidev_to_pp(struct spi_device *spi)
 {
@@ -76,16 +116,17 @@ struct butterfly {
        struct parport          *port;
        struct pardevice        *pd;
 
        struct parport          *port;
        struct pardevice        *pd;
 
-       u8                      lastbyte;
+        u8                     lastbyte; /* hold copy of partport to be faster */
 
         struct spi_message      *msg;
        struct spi_device       *butterfly;
 
         struct spi_message      *msg;
        struct spi_device       *butterfly;
-       struct spi_board_info   info[2];
+       struct spi_board_info   info;
 
 };
 
 /*----------------------------------------------------------------------*/
 
 
 };
 
 /*----------------------------------------------------------------------*/
 
+
 static inline void
 setsck(struct spi_device *spi, int is_on)
 {
 static inline void
 setsck(struct spi_device *spi, int is_on)
 {
@@ -99,7 +140,7 @@ setsck(struct spi_device *spi, int is_on)
        else
                byte &= ~bit;
        parport_write_data(pp->port, byte);
        else
                byte &= ~bit;
        parport_write_data(pp->port, byte);
-       pp->lastbyte = byte;
+       pp->lastbyte = byte;   /* use parport mirror to be faster */
 }
 
 static inline void
 }
 
 static inline void
@@ -115,7 +156,7 @@ setmosi(struct spi_device *spi, int is_on)
        else
                byte &= ~bit;
        parport_write_data(pp->port, byte);
        else
                byte &= ~bit;
        parport_write_data(pp->port, byte);
-       pp->lastbyte = byte;
+       pp->lastbyte = byte;   /* use parport mirror to be faster */
 }
 
 static inline int getmiso(struct spi_device *spi)
 }
 
 static inline int getmiso(struct spi_device *spi)
@@ -135,6 +176,7 @@ static void butterfly_chipselect(struct spi_device *spi, int value)
 {
        struct butterfly        *pp = spidev_to_pp(spi);
 
 {
        struct butterfly        *pp = spidev_to_pp(spi);
 
+#if 0
        /* set default clock polarity */
        if (value != BITBANG_CS_INACTIVE)
                setsck(spi, spi->mode & SPI_CPOL);
        /* set default clock polarity */
        if (value != BITBANG_CS_INACTIVE)
                setsck(spi, spi->mode & SPI_CPOL);
@@ -147,6 +189,18 @@ static void butterfly_chipselect(struct spi_device *spi, int value)
                value = !value;
 
        parport_frob_control(pp->port, spi_cs_bit, value ? spi_cs_bit : 0);
                value = !value;
 
        parport_frob_control(pp->port, spi_cs_bit, value ? spi_cs_bit : 0);
+#else
+       u8                      bit, byte = pp->lastbyte;
+
+       bit = butterfly_nreset;
+
+       if (value)
+               byte &= ~bit;
+       else
+               byte |= bit;
+       parport_write_data(pp->port, byte);
+       pp->lastbyte = byte;   /* use parport mirror to be faster */
+#endif
 }
 
 
 }
 
 
@@ -193,26 +247,27 @@ static void butterfly_attach(struct parport *p)
        }
        pp = spi_master_get_devdata(master);
 
        }
        pp = spi_master_get_devdata(master);
 
+       master->bus_num = -1;       /* dynamic alloc of a bus number */
+       master->num_chipselect = 1;
+
        /*
         * SPI and bitbang hookup
        /*
         * SPI and bitbang hookup
-        *
+         *
         * use default setup(), cleanup(), and transfer() methods; and
         * only bother implementing mode 0.  Start it later.
         */
         * use default setup(), cleanup(), and transfer() methods; and
         * only bother implementing mode 0.  Start it later.
         */
-       master->bus_num = 42;                                       // hard coded?!?
-       master->num_chipselect = 2;                                 // hard coded?!?
-
        pp->bitbang.master = spi_master_get(master);
        pp->bitbang.chipselect = butterfly_chipselect;
        pp->bitbang.txrx_word[SPI_MODE_0] = butterfly_txrx_word_mode0;
        pp->bitbang.master = spi_master_get(master);
        pp->bitbang.chipselect = butterfly_chipselect;
        pp->bitbang.txrx_word[SPI_MODE_0] = butterfly_txrx_word_mode0;
-
+       pp->bitbang.flags = SPI_3WIRE;              // ####################################
+       
        /*
         * parport hookup
         */
        pp->port = p;
        /*
         * parport hookup
         */
        pp->port = p;
-       pd = parport_register_device(p, "spi_butterfly",
+       pd = parport_register_device(p, DRVNAME,
                        NULL, NULL, NULL,
                        NULL, NULL, NULL,
-                       0 /* FLAGS */, pp);
+                                    0 /* FLAGS */, pp); //PARPORT_FLAG_EXCL, pp);
        if (!pd) {
                status = -ENOMEM;
                goto clean0;
        if (!pd) {
                status = -ENOMEM;
                goto clean0;
@@ -223,10 +278,13 @@ static void butterfly_attach(struct parport *p)
        if (status < 0)
                goto clean1;
 
        if (status < 0)
                goto clean1;
 
+       pp->lastbyte = 0;
+       parport_write_data(pp->port, pp->lastbyte);
+
        /*
         * Butterfly reset, powerup, run firmware
         */
        /*
         * Butterfly reset, powerup, run firmware
         */
-       pr_debug("%s: powerup/reset Butterfly\n", p->name);
+       pr_debug("%s: powerup/reset Butterfly\n", DRVNAME);
 
        /* nCS for dataflash (this bit is inverted on output) */
        parport_frob_control(pp->port, spi_cs_bit, 0);
 
        /* nCS for dataflash (this bit is inverted on output) */
        parport_frob_control(pp->port, spi_cs_bit, 0);
@@ -238,38 +296,58 @@ static void butterfly_attach(struct parport *p)
        parport_write_data(pp->port, pp->lastbyte);
        msleep(5);
 
        parport_write_data(pp->port, pp->lastbyte);
        msleep(5);
 
+#if 0
        /* take it out of reset; assume long reset delay */
        pp->lastbyte |= butterfly_nreset;
        parport_write_data(pp->port, pp->lastbyte);
        /* take it out of reset; assume long reset delay */
        pp->lastbyte |= butterfly_nreset;
        parport_write_data(pp->port, pp->lastbyte);
-       msleep(100);
+       msleep(10);
 
 
+       /* take reset as trigger signal ############# */
+       pp->lastbyte &= ~butterfly_nreset;
+       parport_write_data(pp->port, pp->lastbyte);
+#endif
 
        /*
         * Start SPI ... for now, hide that we're two physical busses.
         */
        status = spi_bitbang_start(&pp->bitbang);
 
        /*
         * Start SPI ... for now, hide that we're two physical busses.
         */
        status = spi_bitbang_start(&pp->bitbang);
-       if (status < 0)
+       if (status < 0) {
+               pr_warning("%s: spi_bitbang_start failed with status %d\n",
+                       DRVNAME, status);
                goto clean2;
                goto clean2;
+       }
 
 
-       /* Bus 1 lets us talk to at45db041b (firmware disables AVR SPI), AVR
-        * (firmware resets at45, acts as spi slave) or neither (we ignore
-        * both, AVR uses AT45).  Here we expect firmware for the first option.
+       /*
+        * 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.
         */
         */
-
-       pp->info[0].max_speed_hz = 15 * 1000 * 1000;
-       
-       strcpy(pp->info[0].modalias, "spi_tty");                       // name length check ! < KOBJ_NAME_LEN
-       pp->info[0].platform_data = NULL;                              // here we should add data structures for subsystem driver ???
-       pp->info[0].chip_select = 1;                                   // 0: .. 1:
-       pp->info[0].controller_data = pp;        /* save my structure for later use */
-       pp->butterfly = spi_new_device(pp->bitbang.master, &pp->info[0]);
+       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_3WIRE | SPI_MODE_0;                     // ################
+
+       /* 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->butterfly = spi_new_device(pp->bitbang.master, &pp->info);
        if (pp->butterfly)
        if (pp->butterfly)
-               pr_debug("%s: dataflash at %s\n", p->name,
+               pr_info("%s: SPI tty at %s\n", DRVNAME,
                                pp->butterfly->dev.bus_id);
                                pp->butterfly->dev.bus_id);
-
-       // dev_info(_what?_, ...)
-       pr_info("%s: AVR Butterfly\n", p->name);
-
+       else {
+               pr_warning("%s: spi_new_device failed\n", DRVNAME);
+               status = -ENODEV;
+               goto out_bitbang_stop;
+       }
+       //        pp->butterfly->bits_per_word=16;                             // ###############
 
        /* get spi_bitbang_transfer either via global Symbol, or better 
          * ask it from the driver structure
 
        /* get spi_bitbang_transfer either via global Symbol, or better 
          * ask it from the driver structure
@@ -300,6 +378,8 @@ static void butterfly_attach(struct parport *p)
        butterfly = pp;
        return;
 
        butterfly = pp;
        return;
 
+out_bitbang_stop:
+       spi_bitbang_stop(&pp->bitbang);
 clean2:
        /* turn off VCC */
        parport_write_data(pp->port, 0);
 clean2:
        /* turn off VCC */
        parport_write_data(pp->port, 0);
@@ -310,7 +390,7 @@ clean1:
 clean0:
        (void) spi_master_put(pp->bitbang.master);
 done:
 clean0:
        (void) spi_master_put(pp->bitbang.master);
 done:
-       pr_debug("%s: butterfly probe, fail %d\n", p->name, status);
+       pr_debug("%s: butterfly probe, fail %d\n", DRVNAME, status);
 }
 
 static void butterfly_detach(struct parport *p)
 }
 
 static void butterfly_detach(struct parport *p)
@@ -329,7 +409,6 @@ static void butterfly_detach(struct parport *p)
                spi_message_free(pp->msg);
                pr_info("Dealloc SPI message buffer\n");
        }
                spi_message_free(pp->msg);
                pr_info("Dealloc SPI message buffer\n");
        }
-       butterfly = NULL;
 
        /* stop() unregisters child devices too */
        status = spi_bitbang_stop(&pp->bitbang);
 
        /* stop() unregisters child devices too */
        status = spi_bitbang_stop(&pp->bitbang);
@@ -342,10 +421,12 @@ static void butterfly_detach(struct parport *p)
        parport_unregister_device(pp->pd);
 
        (void) spi_master_put(pp->bitbang.master);
        parport_unregister_device(pp->pd);
 
        (void) spi_master_put(pp->bitbang.master);
+
+       butterfly = NULL;
 }
 
 static struct parport_driver butterfly_driver = {
 }
 
 static struct parport_driver butterfly_driver = {
-       .name =         "spi_butterfly",
+       .name =         DRVNAME,
        .attach =       butterfly_attach,
        .detach =       butterfly_detach,
 };
        .attach =       butterfly_attach,
        .detach =       butterfly_detach,
 };
@@ -365,3 +446,8 @@ module_exit(butterfly_exit);
 
 MODULE_DESCRIPTION("Parport Adapter driver for SPI tty Butterfly");
 MODULE_LICENSE("GPL");
 
 MODULE_DESCRIPTION("Parport Adapter driver for SPI tty Butterfly");
 MODULE_LICENSE("GPL");
+
+module_param_string(spi_pdrv, modalias, sizeof(modalias), S_IRUGO);
+MODULE_PARM_DESC(spi_pdrv, "spi protocol driver name");
+
+MODULE_INFO(Version, DRIVER_VERSION);