root/drivers/spi/spi-lm70llp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. spidev_to_pp
  2. deassertCS
  3. assertCS
  4. clkHigh
  5. clkLow
  6. spidelay
  7. setsck
  8. setmosi
  9. getmiso
  10. lm70_chipselect
  11. lm70_txrx
  12. spi_lm70llp_attach
  13. spi_lm70llp_detach
  14. init_spi_lm70llp
  15. cleanup_spi_lm70llp

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Driver for LM70EVAL-LLP board for the LM70 sensor
   4  *
   5  * Copyright (C) 2006 Kaiwan N Billimoria <kaiwan@designergraphix.com>
   6  */
   7 
   8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   9 
  10 #include <linux/init.h>
  11 #include <linux/module.h>
  12 #include <linux/kernel.h>
  13 #include <linux/delay.h>
  14 #include <linux/device.h>
  15 #include <linux/parport.h>
  16 #include <linux/sysfs.h>
  17 #include <linux/workqueue.h>
  18 
  19 #include <linux/spi/spi.h>
  20 #include <linux/spi/spi_bitbang.h>
  21 
  22 /*
  23  * The LM70 communicates with a host processor using a 3-wire variant of
  24  * the SPI/Microwire bus interface. This driver specifically supports an
  25  * NS LM70 LLP Evaluation Board, interfacing to a PC using its parallel
  26  * port to bitbang an SPI-parport bridge.  Accordingly, this is an SPI
  27  * master controller driver.  The hwmon/lm70 driver is a "SPI protocol
  28  * driver", layered on top of this one and usable without the lm70llp.
  29  *
  30  * Datasheet and Schematic:
  31  * The LM70 is a temperature sensor chip from National Semiconductor; its
  32  * datasheet is available at http://www.national.com/pf/LM/LM70.html
  33  * The schematic for this particular board (the LM70EVAL-LLP) is
  34  * available (on page 4) here:
  35  *  http://www.national.com/appinfo/tempsensors/files/LM70LLPEVALmanual.pdf
  36  *
  37  * Also see Documentation/spi/spi-lm70llp.rst.  The SPI<->parport code here is
  38  * (heavily) based on spi-butterfly by David Brownell.
  39  *
  40  * The LM70 LLP connects to the PC parallel port in the following manner:
  41  *
  42  *   Parallel                 LM70 LLP
  43  *     Port      Direction   JP2 Header
  44  *  -----------  ---------  ------------
  45  *      D0    2      -         -
  46  *      D1    3     -->      V+   5
  47  *      D2    4     -->      V+   5
  48  *      D3    5     -->      V+   5
  49  *      D4    6     -->      V+   5
  50  *      D5    7     -->      nCS  8
  51  *      D6    8     -->      SCLK 3
  52  *      D7    9     -->      SI/O 5
  53  *     GND   25      -       GND  7
  54  *    Select 13     <--      SI/O 1
  55  *
  56  * Note that parport pin 13 actually gets inverted by the transistor
  57  * arrangement which lets either the parport or the LM70 drive the
  58  * SI/SO signal (see the schematic for details).
  59  */
  60 
  61 #define DRVNAME         "spi-lm70llp"
  62 
  63 #define lm70_INIT       0xBE
  64 #define SIO             0x10
  65 #define nCS             0x20
  66 #define SCLK            0x40
  67 
  68 /*-------------------------------------------------------------------------*/
  69 
  70 struct spi_lm70llp {
  71         struct spi_bitbang      bitbang;
  72         struct parport          *port;
  73         struct pardevice        *pd;
  74         struct spi_device       *spidev_lm70;
  75         struct spi_board_info   info;
  76         //struct device         *dev;
  77 };
  78 
  79 /* REVISIT : ugly global ; provides "exclusive open" facility */
  80 static struct spi_lm70llp *lm70llp;
  81 
  82 /*-------------------------------------------------------------------*/
  83 
  84 static inline struct spi_lm70llp *spidev_to_pp(struct spi_device *spi)
  85 {
  86         return spi->controller_data;
  87 }
  88 
  89 /*---------------------- LM70 LLP eval board-specific inlines follow */
  90 
  91 /* NOTE:  we don't actually need to reread the output values, since they'll
  92  * still be what we wrote before.  Plus, going through parport builds in
  93  * a ~1ms/operation delay; these SPI transfers could easily be faster.
  94  */
  95 
  96 static inline void deassertCS(struct spi_lm70llp *pp)
  97 {
  98         u8 data = parport_read_data(pp->port);
  99 
 100         data &= ~0x80;          /* pull D7/SI-out low while de-asserted */
 101         parport_write_data(pp->port, data | nCS);
 102 }
 103 
 104 static inline void assertCS(struct spi_lm70llp *pp)
 105 {
 106         u8 data = parport_read_data(pp->port);
 107 
 108         data |= 0x80;           /* pull D7/SI-out high so lm70 drives SO-in */
 109         parport_write_data(pp->port, data & ~nCS);
 110 }
 111 
 112 static inline void clkHigh(struct spi_lm70llp *pp)
 113 {
 114         u8 data = parport_read_data(pp->port);
 115 
 116         parport_write_data(pp->port, data | SCLK);
 117 }
 118 
 119 static inline void clkLow(struct spi_lm70llp *pp)
 120 {
 121         u8 data = parport_read_data(pp->port);
 122 
 123         parport_write_data(pp->port, data & ~SCLK);
 124 }
 125 
 126 /*------------------------- SPI-LM70-specific inlines ----------------------*/
 127 
 128 static inline void spidelay(unsigned d)
 129 {
 130         udelay(d);
 131 }
 132 
 133 static inline void setsck(struct spi_device *s, int is_on)
 134 {
 135         struct spi_lm70llp *pp = spidev_to_pp(s);
 136 
 137         if (is_on)
 138                 clkHigh(pp);
 139         else
 140                 clkLow(pp);
 141 }
 142 
 143 static inline void setmosi(struct spi_device *s, int is_on)
 144 {
 145         /* FIXME update D7 ... this way we can put the chip
 146          * into shutdown mode and read the manufacturer ID,
 147          * but we can't put it back into operational mode.
 148          */
 149 }
 150 
 151 /*
 152  * getmiso:
 153  * Why do we return 0 when the SIO line is high and vice-versa?
 154  * The fact is, the lm70 eval board from NS (which this driver drives),
 155  * is wired in just such a way : when the lm70's SIO goes high, a transistor
 156  * switches it to low reflecting this on the parport (pin 13), and vice-versa.
 157  */
 158 static inline int getmiso(struct spi_device *s)
 159 {
 160         struct spi_lm70llp *pp = spidev_to_pp(s);
 161 
 162         return ((SIO == (parport_read_status(pp->port) & SIO)) ? 0 : 1);
 163 }
 164 
 165 /*--------------------------------------------------------------------*/
 166 
 167 #include "spi-bitbang-txrx.h"
 168 
 169 static void lm70_chipselect(struct spi_device *spi, int value)
 170 {
 171         struct spi_lm70llp *pp = spidev_to_pp(spi);
 172 
 173         if (value)
 174                 assertCS(pp);
 175         else
 176                 deassertCS(pp);
 177 }
 178 
 179 /*
 180  * Our actual bitbanger routine.
 181  */
 182 static u32 lm70_txrx(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits,
 183                      unsigned flags)
 184 {
 185         return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits);
 186 }
 187 
 188 static void spi_lm70llp_attach(struct parport *p)
 189 {
 190         struct pardevice        *pd;
 191         struct spi_lm70llp      *pp;
 192         struct spi_master       *master;
 193         int                     status;
 194         struct pardev_cb        lm70llp_cb;
 195 
 196         if (lm70llp) {
 197                 pr_warn("spi_lm70llp instance already loaded. Aborting.\n");
 198                 return;
 199         }
 200 
 201         /* TODO:  this just _assumes_ a lm70 is there ... no probe;
 202          * the lm70 driver could verify it, reading the manf ID.
 203          */
 204 
 205         master = spi_alloc_master(p->physport->dev, sizeof *pp);
 206         if (!master) {
 207                 status = -ENOMEM;
 208                 goto out_fail;
 209         }
 210         pp = spi_master_get_devdata(master);
 211 
 212         /*
 213          * SPI and bitbang hookup.
 214          */
 215         pp->bitbang.master = master;
 216         pp->bitbang.chipselect = lm70_chipselect;
 217         pp->bitbang.txrx_word[SPI_MODE_0] = lm70_txrx;
 218         pp->bitbang.flags = SPI_3WIRE;
 219 
 220         /*
 221          * Parport hookup
 222          */
 223         pp->port = p;
 224         memset(&lm70llp_cb, 0, sizeof(lm70llp_cb));
 225         lm70llp_cb.private = pp;
 226         lm70llp_cb.flags = PARPORT_FLAG_EXCL;
 227         pd = parport_register_dev_model(p, DRVNAME, &lm70llp_cb, 0);
 228 
 229         if (!pd) {
 230                 status = -ENOMEM;
 231                 goto out_free_master;
 232         }
 233         pp->pd = pd;
 234 
 235         status = parport_claim(pd);
 236         if (status < 0)
 237                 goto out_parport_unreg;
 238 
 239         /*
 240          * Start SPI ...
 241          */
 242         status = spi_bitbang_start(&pp->bitbang);
 243         if (status < 0) {
 244                 dev_warn(&pd->dev, "spi_bitbang_start failed with status %d\n",
 245                          status);
 246                 goto out_off_and_release;
 247         }
 248 
 249         /*
 250          * The modalias name MUST match the device_driver name
 251          * for the bus glue code to match and subsequently bind them.
 252          * We are binding to the generic drivers/hwmon/lm70.c device
 253          * driver.
 254          */
 255         strcpy(pp->info.modalias, "lm70");
 256         pp->info.max_speed_hz = 6 * 1000 * 1000;
 257         pp->info.chip_select = 0;
 258         pp->info.mode = SPI_3WIRE | SPI_MODE_0;
 259 
 260         /* power up the chip, and let the LM70 control SI/SO */
 261         parport_write_data(pp->port, lm70_INIT);
 262 
 263         /* Enable access to our primary data structure via
 264          * the board info's (void *)controller_data.
 265          */
 266         pp->info.controller_data = pp;
 267         pp->spidev_lm70 = spi_new_device(pp->bitbang.master, &pp->info);
 268         if (pp->spidev_lm70)
 269                 dev_dbg(&pp->spidev_lm70->dev, "spidev_lm70 at %s\n",
 270                         dev_name(&pp->spidev_lm70->dev));
 271         else {
 272                 dev_warn(&pd->dev, "spi_new_device failed\n");
 273                 status = -ENODEV;
 274                 goto out_bitbang_stop;
 275         }
 276         pp->spidev_lm70->bits_per_word = 8;
 277 
 278         lm70llp = pp;
 279         return;
 280 
 281 out_bitbang_stop:
 282         spi_bitbang_stop(&pp->bitbang);
 283 out_off_and_release:
 284         /* power down */
 285         parport_write_data(pp->port, 0);
 286         mdelay(10);
 287         parport_release(pp->pd);
 288 out_parport_unreg:
 289         parport_unregister_device(pd);
 290 out_free_master:
 291         spi_master_put(master);
 292 out_fail:
 293         pr_info("spi_lm70llp probe fail, status %d\n", status);
 294 }
 295 
 296 static void spi_lm70llp_detach(struct parport *p)
 297 {
 298         struct spi_lm70llp              *pp;
 299 
 300         if (!lm70llp || lm70llp->port != p)
 301                 return;
 302 
 303         pp = lm70llp;
 304         spi_bitbang_stop(&pp->bitbang);
 305 
 306         /* power down */
 307         parport_write_data(pp->port, 0);
 308 
 309         parport_release(pp->pd);
 310         parport_unregister_device(pp->pd);
 311 
 312         spi_master_put(pp->bitbang.master);
 313 
 314         lm70llp = NULL;
 315 }
 316 
 317 static struct parport_driver spi_lm70llp_drv = {
 318         .name =         DRVNAME,
 319         .match_port =   spi_lm70llp_attach,
 320         .detach =       spi_lm70llp_detach,
 321         .devmodel =     true,
 322 };
 323 
 324 static int __init init_spi_lm70llp(void)
 325 {
 326         return parport_register_driver(&spi_lm70llp_drv);
 327 }
 328 module_init(init_spi_lm70llp);
 329 
 330 static void __exit cleanup_spi_lm70llp(void)
 331 {
 332         parport_unregister_driver(&spi_lm70llp_drv);
 333 }
 334 module_exit(cleanup_spi_lm70llp);
 335 
 336 MODULE_AUTHOR("Kaiwan N Billimoria <kaiwan@designergraphix.com>");
 337 MODULE_DESCRIPTION(
 338         "Parport adapter for the National Semiconductor LM70 LLP eval board");
 339 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */