hwmon: (lm70) Code streamlining and cleanup
Kaiwan N Billimoria [Wed, 7 Jan 2009 15:37:34 +0000 (16:37 +0100)]
This fixes a byteswap bug in the LM70 temperature sensor driver,
which was previously covered up by a converse bug in the driver
for the LM70EVAL-LLP board (which is also fixed).

Other fixes:  doc updates, remove an annoying msleep(), and improve
three-wire protocol handling.

Signed-off-by: Kaiwan N Billimoria <kaiwan@designergraphix.com>
[ dbrownell@users.sourceforge.net: doc and whitespace tweaks ]
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Jean Delvare <khali@linux-fr.org>

Documentation/hwmon/lm70
Documentation/spi/spi-lm70llp
drivers/hwmon/lm70.c
drivers/spi/spi_lm70llp.c

index 2bdd3fe..b8d1a52 100644 (file)
@@ -25,6 +25,10 @@ complement digital temperature (sent via the SIO line), is available in the
 driver for interpretation. This driver makes use of the kernel's in-core
 SPI support.
 
+As a real (in-tree) example of this "SPI protocol driver" interfacing
+with a "SPI master controller driver", see drivers/spi/spi_lm70llp.c
+and its associated documentation.
+
 Thanks to
 ---------
 Jean Delvare <khali@linux-fr.org> for mentoring the hwmon-side driver
index 154bd02..34a9cfd 100644 (file)
@@ -13,10 +13,20 @@ Description
 This driver provides glue code connecting a National Semiconductor LM70 LLP
 temperature sensor evaluation board to the kernel's SPI core subsystem.
 
+This is a SPI master controller driver. It can be used in conjunction with
+(layered under) the LM70 logical driver (a "SPI protocol driver").
 In effect, this driver turns the parallel port interface on the eval board
 into a SPI bus with a single device, which will be driven by the generic
 LM70 driver (drivers/hwmon/lm70.c).
 
+
+Hardware Interfacing
+--------------------
+The schematic for this particular board (the LM70EVAL-LLP) is
+available (on page 4) here:
+
+  http://www.national.com/appinfo/tempsensors/files/LM70LLPEVALmanual.pdf
+
 The hardware interfacing on the LM70 LLP eval board is as follows:
 
    Parallel                 LM70 LLP
index d435f00..9f9741b 100644 (file)
@@ -65,10 +65,9 @@ static ssize_t lm70_sense_temp(struct device *dev,
                "spi_write_then_read failed with status %d\n", status);
                goto out;
        }
-       dev_dbg(dev, "rxbuf[1] : 0x%x rxbuf[0] : 0x%x\n", rxbuf[1], rxbuf[0]);
-
-       raw = (rxbuf[1] << 8) + rxbuf[0];
-       dev_dbg(dev, "raw=0x%x\n", raw);
+       raw = (rxbuf[0] << 8) + rxbuf[1];
+       dev_dbg(dev, "rxbuf[0] : 0x%02x rxbuf[1] : 0x%02x raw=0x%04x\n",
+               rxbuf[0], rxbuf[1], raw);
 
        /*
         * The "raw" temperature read into rxbuf[] is a 16-bit signed 2's
@@ -109,6 +108,8 @@ static int __devinit lm70_probe(struct spi_device *spi)
        if ((spi->mode & (SPI_CPOL|SPI_CPHA)) || !(spi->mode & SPI_3WIRE))
                return -EINVAL;
 
+       /* NOTE:  we assume 8-bit words, and convert to 16 bits manually */
+
        p_lm70 = kzalloc(sizeof *p_lm70, GFP_KERNEL);
        if (!p_lm70)
                return -ENOMEM;
index af65267..568c781 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * spi_lm70llp.c - driver for lm70llp eval board for the LM70 sensor
+ * spi_lm70llp.c - driver for LM70EVAL-LLP board for the LM70 sensor
  *
  * Copyright (C) 2006 Kaiwan N Billimoria <kaiwan@designergraphix.com>
  *
  * master controller driver.  The hwmon/lm70 driver is a "SPI protocol
  * driver", layered on top of this one and usable without the lm70llp.
  *
+ * Datasheet and Schematic:
  * The LM70 is a temperature sensor chip from National Semiconductor; its
  * datasheet is available at http://www.national.com/pf/LM/LM70.html
+ * The schematic for this particular board (the LM70EVAL-LLP) is
+ * available (on page 4) here:
+ *  http://www.national.com/appinfo/tempsensors/files/LM70LLPEVALmanual.pdf
  *
  * Also see Documentation/spi/spi-lm70llp.  The SPI<->parport code here is
  * (heavily) based on spi-butterfly by David Brownell.
@@ -64,7 +68,7 @@
  *
  * Note that parport pin 13 actually gets inverted by the transistor
  * arrangement which lets either the parport or the LM70 drive the
- * SI/SO signal.
+ * SI/SO signal (see the schematic for details).
  */
 
 #define DRVNAME                "spi-lm70llp"
@@ -106,12 +110,16 @@ static inline struct spi_lm70llp *spidev_to_pp(struct spi_device *spi)
 static inline void deassertCS(struct spi_lm70llp *pp)
 {
        u8 data = parport_read_data(pp->port);
+
+       data &= ~0x80;          /* pull D7/SI-out low while de-asserted */
        parport_write_data(pp->port, data | nCS);
 }
 
 static inline void assertCS(struct spi_lm70llp *pp)
 {
        u8 data = parport_read_data(pp->port);
+
+       data |= 0x80;           /* pull D7/SI-out high so lm70 drives SO-in */
        parport_write_data(pp->port, data & ~nCS);
 }
 
@@ -184,22 +192,7 @@ static void lm70_chipselect(struct spi_device *spi, int value)
  */
 static u32 lm70_txrx(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits)
 {
-       static u32 sio=0;
-       static int first_time=1;
-
-       /* First time: perform SPI bitbang and return the LSB of
-        * the result of the SPI call.
-        */
-       if (first_time) {
-               sio = bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
-               first_time=0;
-               return (sio & 0x00ff);
-       }
-       /* Return the MSB of the result of the SPI call */
-       else {
-               first_time=1;
-               return (sio >> 8);
-       }
+       return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
 }
 
 static void spi_lm70llp_attach(struct parport *p)
@@ -293,10 +286,9 @@ static void spi_lm70llp_attach(struct parport *p)
                status = -ENODEV;
                goto out_bitbang_stop;
        }
-       pp->spidev_lm70->bits_per_word = 16;
+       pp->spidev_lm70->bits_per_word = 8;
 
        lm70llp = pp;
-
        return;
 
 out_bitbang_stop:
@@ -326,7 +318,6 @@ static void spi_lm70llp_detach(struct parport *p)
 
        /* power down */
        parport_write_data(pp->port, 0);
-       msleep(10);
 
        parport_release(pp->pd);
        parport_unregister_device(pp->pd);