hwmon: (lm70) Code streamlining and cleanup

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>
This commit is contained in:
Kaiwan N Billimoria 2009-01-07 16:37:34 +01:00 committed by Jean Delvare
parent 0589c2de64
commit 2b7300513b
4 changed files with 31 additions and 25 deletions

View 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 driver for interpretation. This driver makes use of the kernel's in-core
SPI support. 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 Thanks to
--------- ---------
Jean Delvare <khali@linux-fr.org> for mentoring the hwmon-side driver Jean Delvare <khali@linux-fr.org> for mentoring the hwmon-side driver

View file

@ -13,10 +13,20 @@ Description
This driver provides glue code connecting a National Semiconductor LM70 LLP This driver provides glue code connecting a National Semiconductor LM70 LLP
temperature sensor evaluation board to the kernel's SPI core subsystem. 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 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 into a SPI bus with a single device, which will be driven by the generic
LM70 driver (drivers/hwmon/lm70.c). 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: The hardware interfacing on the LM70 LLP eval board is as follows:
Parallel LM70 LLP Parallel LM70 LLP

View file

@ -65,10 +65,9 @@ static ssize_t lm70_sense_temp(struct device *dev,
"spi_write_then_read failed with status %d\n", status); "spi_write_then_read failed with status %d\n", status);
goto out; goto out;
} }
dev_dbg(dev, "rxbuf[1] : 0x%x rxbuf[0] : 0x%x\n", rxbuf[1], rxbuf[0]); raw = (rxbuf[0] << 8) + rxbuf[1];
dev_dbg(dev, "rxbuf[0] : 0x%02x rxbuf[1] : 0x%02x raw=0x%04x\n",
raw = (rxbuf[1] << 8) + rxbuf[0]; rxbuf[0], rxbuf[1], raw);
dev_dbg(dev, "raw=0x%x\n", raw);
/* /*
* The "raw" temperature read into rxbuf[] is a 16-bit signed 2's * 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)) if ((spi->mode & (SPI_CPOL|SPI_CPHA)) || !(spi->mode & SPI_3WIRE))
return -EINVAL; return -EINVAL;
/* NOTE: we assume 8-bit words, and convert to 16 bits manually */
p_lm70 = kzalloc(sizeof *p_lm70, GFP_KERNEL); p_lm70 = kzalloc(sizeof *p_lm70, GFP_KERNEL);
if (!p_lm70) if (!p_lm70)
return -ENOMEM; return -ENOMEM;

View 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> * Copyright (C) 2006 Kaiwan N Billimoria <kaiwan@designergraphix.com>
* *
@ -40,8 +40,12 @@
* master controller driver. The hwmon/lm70 driver is a "SPI protocol * master controller driver. The hwmon/lm70 driver is a "SPI protocol
* driver", layered on top of this one and usable without the lm70llp. * 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 * The LM70 is a temperature sensor chip from National Semiconductor; its
* datasheet is available at http://www.national.com/pf/LM/LM70.html * 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 * Also see Documentation/spi/spi-lm70llp. The SPI<->parport code here is
* (heavily) based on spi-butterfly by David Brownell. * (heavily) based on spi-butterfly by David Brownell.
@ -64,7 +68,7 @@
* *
* Note that parport pin 13 actually gets inverted by the transistor * Note that parport pin 13 actually gets inverted by the transistor
* arrangement which lets either the parport or the LM70 drive the * 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" #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) static inline void deassertCS(struct spi_lm70llp *pp)
{ {
u8 data = parport_read_data(pp->port); u8 data = parport_read_data(pp->port);
data &= ~0x80; /* pull D7/SI-out low while de-asserted */
parport_write_data(pp->port, data | nCS); parport_write_data(pp->port, data | nCS);
} }
static inline void assertCS(struct spi_lm70llp *pp) static inline void assertCS(struct spi_lm70llp *pp)
{ {
u8 data = parport_read_data(pp->port); 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); 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 lm70_txrx(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits)
{ {
static u32 sio=0; return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
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);
}
} }
static void spi_lm70llp_attach(struct parport *p) static void spi_lm70llp_attach(struct parport *p)
@ -293,10 +286,9 @@ static void spi_lm70llp_attach(struct parport *p)
status = -ENODEV; status = -ENODEV;
goto out_bitbang_stop; goto out_bitbang_stop;
} }
pp->spidev_lm70->bits_per_word = 16; pp->spidev_lm70->bits_per_word = 8;
lm70llp = pp; lm70llp = pp;
return; return;
out_bitbang_stop: out_bitbang_stop:
@ -326,7 +318,6 @@ static void spi_lm70llp_detach(struct parport *p)
/* power down */ /* power down */
parport_write_data(pp->port, 0); parport_write_data(pp->port, 0);
msleep(10);
parport_release(pp->pd); parport_release(pp->pd);
parport_unregister_device(pp->pd); parport_unregister_device(pp->pd);