Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Driver for LM70EVAL-LLP board for the LM70 sensor
0004  *
0005  * Copyright (C) 2006 Kaiwan N Billimoria <kaiwan@designergraphix.com>
0006  */
0007 
0008 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0009 
0010 #include <linux/init.h>
0011 #include <linux/module.h>
0012 #include <linux/kernel.h>
0013 #include <linux/delay.h>
0014 #include <linux/device.h>
0015 #include <linux/parport.h>
0016 #include <linux/sysfs.h>
0017 #include <linux/workqueue.h>
0018 
0019 #include <linux/spi/spi.h>
0020 #include <linux/spi/spi_bitbang.h>
0021 
0022 /*
0023  * The LM70 communicates with a host processor using a 3-wire variant of
0024  * the SPI/Microwire bus interface. This driver specifically supports an
0025  * NS LM70 LLP Evaluation Board, interfacing to a PC using its parallel
0026  * port to bitbang an SPI-parport bridge.  Accordingly, this is an SPI
0027  * master controller driver.  The hwmon/lm70 driver is a "SPI protocol
0028  * driver", layered on top of this one and usable without the lm70llp.
0029  *
0030  * Datasheet and Schematic:
0031  * The LM70 is a temperature sensor chip from National Semiconductor; its
0032  * datasheet is available at http://www.national.com/pf/LM/LM70.html
0033  * The schematic for this particular board (the LM70EVAL-LLP) is
0034  * available (on page 4) here:
0035  *  http://www.national.com/appinfo/tempsensors/files/LM70LLPEVALmanual.pdf
0036  *
0037  * Also see Documentation/spi/spi-lm70llp.rst.  The SPI<->parport code here is
0038  * (heavily) based on spi-butterfly by David Brownell.
0039  *
0040  * The LM70 LLP connects to the PC parallel port in the following manner:
0041  *
0042  *   Parallel                 LM70 LLP
0043  *     Port      Direction   JP2 Header
0044  *  -----------  ---------  ------------
0045  *      D0    2      -         -
0046  *      D1    3     -->      V+   5
0047  *      D2    4     -->      V+   5
0048  *      D3    5     -->      V+   5
0049  *      D4    6     -->      V+   5
0050  *      D5    7     -->      nCS  8
0051  *      D6    8     -->      SCLK 3
0052  *      D7    9     -->      SI/O 5
0053  *     GND   25      -       GND  7
0054  *    Select 13     <--      SI/O 1
0055  *
0056  * Note that parport pin 13 actually gets inverted by the transistor
0057  * arrangement which lets either the parport or the LM70 drive the
0058  * SI/SO signal (see the schematic for details).
0059  */
0060 
0061 #define DRVNAME     "spi-lm70llp"
0062 
0063 #define lm70_INIT   0xBE
0064 #define SIO     0x10
0065 #define nCS     0x20
0066 #define SCLK        0x40
0067 
0068 /*-------------------------------------------------------------------------*/
0069 
0070 struct spi_lm70llp {
0071     struct spi_bitbang  bitbang;
0072     struct parport      *port;
0073     struct pardevice    *pd;
0074     struct spi_device   *spidev_lm70;
0075     struct spi_board_info   info;
0076     //struct device     *dev;
0077 };
0078 
0079 /* REVISIT : ugly global ; provides "exclusive open" facility */
0080 static struct spi_lm70llp *lm70llp;
0081 
0082 /*-------------------------------------------------------------------*/
0083 
0084 static inline struct spi_lm70llp *spidev_to_pp(struct spi_device *spi)
0085 {
0086     return spi->controller_data;
0087 }
0088 
0089 /*---------------------- LM70 LLP eval board-specific inlines follow */
0090 
0091 /* NOTE:  we don't actually need to reread the output values, since they'll
0092  * still be what we wrote before.  Plus, going through parport builds in
0093  * a ~1ms/operation delay; these SPI transfers could easily be faster.
0094  */
0095 
0096 static inline void deassertCS(struct spi_lm70llp *pp)
0097 {
0098     u8 data = parport_read_data(pp->port);
0099 
0100     data &= ~0x80;      /* pull D7/SI-out low while de-asserted */
0101     parport_write_data(pp->port, data | nCS);
0102 }
0103 
0104 static inline void assertCS(struct spi_lm70llp *pp)
0105 {
0106     u8 data = parport_read_data(pp->port);
0107 
0108     data |= 0x80;       /* pull D7/SI-out high so lm70 drives SO-in */
0109     parport_write_data(pp->port, data & ~nCS);
0110 }
0111 
0112 static inline void clkHigh(struct spi_lm70llp *pp)
0113 {
0114     u8 data = parport_read_data(pp->port);
0115 
0116     parport_write_data(pp->port, data | SCLK);
0117 }
0118 
0119 static inline void clkLow(struct spi_lm70llp *pp)
0120 {
0121     u8 data = parport_read_data(pp->port);
0122 
0123     parport_write_data(pp->port, data & ~SCLK);
0124 }
0125 
0126 /*------------------------- SPI-LM70-specific inlines ----------------------*/
0127 
0128 static inline void spidelay(unsigned d)
0129 {
0130     udelay(d);
0131 }
0132 
0133 static inline void setsck(struct spi_device *s, int is_on)
0134 {
0135     struct spi_lm70llp *pp = spidev_to_pp(s);
0136 
0137     if (is_on)
0138         clkHigh(pp);
0139     else
0140         clkLow(pp);
0141 }
0142 
0143 static inline void setmosi(struct spi_device *s, int is_on)
0144 {
0145     /* FIXME update D7 ... this way we can put the chip
0146      * into shutdown mode and read the manufacturer ID,
0147      * but we can't put it back into operational mode.
0148      */
0149 }
0150 
0151 /*
0152  * getmiso:
0153  * Why do we return 0 when the SIO line is high and vice-versa?
0154  * The fact is, the lm70 eval board from NS (which this driver drives),
0155  * is wired in just such a way : when the lm70's SIO goes high, a transistor
0156  * switches it to low reflecting this on the parport (pin 13), and vice-versa.
0157  */
0158 static inline int getmiso(struct spi_device *s)
0159 {
0160     struct spi_lm70llp *pp = spidev_to_pp(s);
0161 
0162     return ((SIO == (parport_read_status(pp->port) & SIO)) ? 0 : 1);
0163 }
0164 
0165 /*--------------------------------------------------------------------*/
0166 
0167 #include "spi-bitbang-txrx.h"
0168 
0169 static void lm70_chipselect(struct spi_device *spi, int value)
0170 {
0171     struct spi_lm70llp *pp = spidev_to_pp(spi);
0172 
0173     if (value)
0174         assertCS(pp);
0175     else
0176         deassertCS(pp);
0177 }
0178 
0179 /*
0180  * Our actual bitbanger routine.
0181  */
0182 static u32 lm70_txrx(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits,
0183              unsigned flags)
0184 {
0185     return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits);
0186 }
0187 
0188 static void spi_lm70llp_attach(struct parport *p)
0189 {
0190     struct pardevice    *pd;
0191     struct spi_lm70llp  *pp;
0192     struct spi_master   *master;
0193     int         status;
0194     struct pardev_cb    lm70llp_cb;
0195 
0196     if (lm70llp) {
0197         pr_warn("spi_lm70llp instance already loaded. Aborting.\n");
0198         return;
0199     }
0200 
0201     /* TODO:  this just _assumes_ a lm70 is there ... no probe;
0202      * the lm70 driver could verify it, reading the manf ID.
0203      */
0204 
0205     master = spi_alloc_master(p->physport->dev, sizeof(*pp));
0206     if (!master) {
0207         status = -ENOMEM;
0208         goto out_fail;
0209     }
0210     pp = spi_master_get_devdata(master);
0211 
0212     /*
0213      * SPI and bitbang hookup.
0214      */
0215     pp->bitbang.master = master;
0216     pp->bitbang.chipselect = lm70_chipselect;
0217     pp->bitbang.txrx_word[SPI_MODE_0] = lm70_txrx;
0218     pp->bitbang.flags = SPI_3WIRE;
0219 
0220     /*
0221      * Parport hookup
0222      */
0223     pp->port = p;
0224     memset(&lm70llp_cb, 0, sizeof(lm70llp_cb));
0225     lm70llp_cb.private = pp;
0226     lm70llp_cb.flags = PARPORT_FLAG_EXCL;
0227     pd = parport_register_dev_model(p, DRVNAME, &lm70llp_cb, 0);
0228 
0229     if (!pd) {
0230         status = -ENOMEM;
0231         goto out_free_master;
0232     }
0233     pp->pd = pd;
0234 
0235     status = parport_claim(pd);
0236     if (status < 0)
0237         goto out_parport_unreg;
0238 
0239     /*
0240      * Start SPI ...
0241      */
0242     status = spi_bitbang_start(&pp->bitbang);
0243     if (status < 0) {
0244         dev_warn(&pd->dev, "spi_bitbang_start failed with status %d\n",
0245              status);
0246         goto out_off_and_release;
0247     }
0248 
0249     /*
0250      * The modalias name MUST match the device_driver name
0251      * for the bus glue code to match and subsequently bind them.
0252      * We are binding to the generic drivers/hwmon/lm70.c device
0253      * driver.
0254      */
0255     strcpy(pp->info.modalias, "lm70");
0256     pp->info.max_speed_hz = 6 * 1000 * 1000;
0257     pp->info.chip_select = 0;
0258     pp->info.mode = SPI_3WIRE | SPI_MODE_0;
0259 
0260     /* power up the chip, and let the LM70 control SI/SO */
0261     parport_write_data(pp->port, lm70_INIT);
0262 
0263     /* Enable access to our primary data structure via
0264      * the board info's (void *)controller_data.
0265      */
0266     pp->info.controller_data = pp;
0267     pp->spidev_lm70 = spi_new_device(pp->bitbang.master, &pp->info);
0268     if (pp->spidev_lm70)
0269         dev_dbg(&pp->spidev_lm70->dev, "spidev_lm70 at %s\n",
0270             dev_name(&pp->spidev_lm70->dev));
0271     else {
0272         dev_warn(&pd->dev, "spi_new_device failed\n");
0273         status = -ENODEV;
0274         goto out_bitbang_stop;
0275     }
0276     pp->spidev_lm70->bits_per_word = 8;
0277 
0278     lm70llp = pp;
0279     return;
0280 
0281 out_bitbang_stop:
0282     spi_bitbang_stop(&pp->bitbang);
0283 out_off_and_release:
0284     /* power down */
0285     parport_write_data(pp->port, 0);
0286     mdelay(10);
0287     parport_release(pp->pd);
0288 out_parport_unreg:
0289     parport_unregister_device(pd);
0290 out_free_master:
0291     spi_master_put(master);
0292 out_fail:
0293     pr_info("spi_lm70llp probe fail, status %d\n", status);
0294 }
0295 
0296 static void spi_lm70llp_detach(struct parport *p)
0297 {
0298     struct spi_lm70llp      *pp;
0299 
0300     if (!lm70llp || lm70llp->port != p)
0301         return;
0302 
0303     pp = lm70llp;
0304     spi_bitbang_stop(&pp->bitbang);
0305 
0306     /* power down */
0307     parport_write_data(pp->port, 0);
0308 
0309     parport_release(pp->pd);
0310     parport_unregister_device(pp->pd);
0311 
0312     spi_master_put(pp->bitbang.master);
0313 
0314     lm70llp = NULL;
0315 }
0316 
0317 static struct parport_driver spi_lm70llp_drv = {
0318     .name =     DRVNAME,
0319     .match_port =   spi_lm70llp_attach,
0320     .detach =   spi_lm70llp_detach,
0321     .devmodel = true,
0322 };
0323 module_parport_driver(spi_lm70llp_drv);
0324 
0325 MODULE_AUTHOR("Kaiwan N Billimoria <kaiwan@designergraphix.com>");
0326 MODULE_DESCRIPTION(
0327     "Parport adapter for the National Semiconductor LM70 LLP eval board");
0328 MODULE_LICENSE("GPL");