linux/drivers/hwmon/lm70.c
<<
>>
Prefs
   1/*
   2 * lm70.c
   3 *
   4 * The LM70 is a temperature sensor chip from National Semiconductor (NS).
   5 * Copyright (C) 2006 Kaiwan N Billimoria <kaiwan@designergraphix.com>
   6 *
   7 * The LM70 communicates with a host processor via an SPI/Microwire Bus
   8 * interface. The complete datasheet is available at National's website
   9 * here:
  10 * http://www.national.com/pf/LM/LM70.html
  11 *
  12 * This program is free software; you can redistribute it and/or modify
  13 * it under the terms of the GNU General Public License as published by
  14 * the Free Software Foundation; either version 2 of the License, or
  15 * (at your option) any later version.
  16 *
  17 * This program is distributed in the hope that it will be useful,
  18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20 * GNU General Public License for more details.
  21 *
  22 * You should have received a copy of the GNU General Public License
  23 * along with this program; if not, write to the Free Software
  24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25 */
  26
  27#include <linux/init.h>
  28#include <linux/module.h>
  29#include <linux/kernel.h>
  30#include <linux/device.h>
  31#include <linux/err.h>
  32#include <linux/sysfs.h>
  33#include <linux/hwmon.h>
  34#include <linux/mutex.h>
  35#include <linux/mod_devicetable.h>
  36#include <linux/spi/spi.h>
  37
  38
  39#define DRVNAME         "lm70"
  40
  41#define LM70_CHIP_LM70          0       /* original NS LM70 */
  42#define LM70_CHIP_TMP121        1       /* TI TMP121/TMP123 */
  43
  44struct lm70 {
  45        struct device *hwmon_dev;
  46        struct mutex lock;
  47        unsigned int chip;
  48};
  49
  50/* sysfs hook function */
  51static ssize_t lm70_sense_temp(struct device *dev,
  52                struct device_attribute *attr, char *buf)
  53{
  54        struct spi_device *spi = to_spi_device(dev);
  55        int status, val = 0;
  56        u8 rxbuf[2];
  57        s16 raw=0;
  58        struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev);
  59
  60        if (mutex_lock_interruptible(&p_lm70->lock))
  61                return -ERESTARTSYS;
  62
  63        /*
  64         * spi_read() requires a DMA-safe buffer; so we use
  65         * spi_write_then_read(), transmitting 0 bytes.
  66         */
  67        status = spi_write_then_read(spi, NULL, 0, &rxbuf[0], 2);
  68        if (status < 0) {
  69                printk(KERN_WARNING
  70                "spi_write_then_read failed with status %d\n", status);
  71                goto out;
  72        }
  73        raw = (rxbuf[0] << 8) + rxbuf[1];
  74        dev_dbg(dev, "rxbuf[0] : 0x%02x rxbuf[1] : 0x%02x raw=0x%04x\n",
  75                rxbuf[0], rxbuf[1], raw);
  76
  77        /*
  78         * LM70:
  79         * The "raw" temperature read into rxbuf[] is a 16-bit signed 2's
  80         * complement value. Only the MSB 11 bits (1 sign + 10 temperature
  81         * bits) are meaningful; the LSB 5 bits are to be discarded.
  82         * See the datasheet.
  83         *
  84         * Further, each bit represents 0.25 degrees Celsius; so, multiply
  85         * by 0.25. Also multiply by 1000 to represent in millidegrees
  86         * Celsius.
  87         * So it's equivalent to multiplying by 0.25 * 1000 = 250.
  88         *
  89         * TMP121/TMP123:
  90         * 13 bits of 2's complement data, discard LSB 3 bits,
  91         * resolution 0.0625 degrees celsius.
  92         */
  93        switch (p_lm70->chip) {
  94        case LM70_CHIP_LM70:
  95                val = ((int)raw / 32) * 250;
  96                break;
  97
  98        case LM70_CHIP_TMP121:
  99                val = ((int)raw / 8) * 625 / 10;
 100                break;
 101        }
 102
 103        status = sprintf(buf, "%d\n", val); /* millidegrees Celsius */
 104out:
 105        mutex_unlock(&p_lm70->lock);
 106        return status;
 107}
 108
 109static DEVICE_ATTR(temp1_input, S_IRUGO, lm70_sense_temp, NULL);
 110
 111static ssize_t lm70_show_name(struct device *dev, struct device_attribute
 112                              *devattr, char *buf)
 113{
 114        struct lm70 *p_lm70 = dev_get_drvdata(dev);
 115        int ret;
 116
 117        switch (p_lm70->chip) {
 118        case LM70_CHIP_LM70:
 119                ret = sprintf(buf, "lm70\n");
 120                break;
 121        case LM70_CHIP_TMP121:
 122                ret = sprintf(buf, "tmp121\n");
 123                break;
 124        default:
 125                ret = -EINVAL;
 126        }
 127        return ret;
 128}
 129
 130static DEVICE_ATTR(name, S_IRUGO, lm70_show_name, NULL);
 131
 132/*----------------------------------------------------------------------*/
 133
 134static int __devinit lm70_probe(struct spi_device *spi)
 135{
 136        int chip = spi_get_device_id(spi)->driver_data;
 137        struct lm70 *p_lm70;
 138        int status;
 139
 140        /* signaling is SPI_MODE_0 for both LM70 and TMP121 */
 141        if (spi->mode & (SPI_CPOL | SPI_CPHA))
 142                return -EINVAL;
 143
 144        /* 3-wire link (shared SI/SO) for LM70 */
 145        if (chip == LM70_CHIP_LM70 && !(spi->mode & SPI_3WIRE))
 146                return -EINVAL;
 147
 148        /* NOTE:  we assume 8-bit words, and convert to 16 bits manually */
 149
 150        p_lm70 = kzalloc(sizeof *p_lm70, GFP_KERNEL);
 151        if (!p_lm70)
 152                return -ENOMEM;
 153
 154        mutex_init(&p_lm70->lock);
 155        p_lm70->chip = chip;
 156
 157        /* sysfs hook */
 158        p_lm70->hwmon_dev = hwmon_device_register(&spi->dev);
 159        if (IS_ERR(p_lm70->hwmon_dev)) {
 160                dev_dbg(&spi->dev, "hwmon_device_register failed.\n");
 161                status = PTR_ERR(p_lm70->hwmon_dev);
 162                goto out_dev_reg_failed;
 163        }
 164        dev_set_drvdata(&spi->dev, p_lm70);
 165
 166        if ((status = device_create_file(&spi->dev, &dev_attr_temp1_input))
 167         || (status = device_create_file(&spi->dev, &dev_attr_name))) {
 168                dev_dbg(&spi->dev, "device_create_file failure.\n");
 169                goto out_dev_create_file_failed;
 170        }
 171
 172        return 0;
 173
 174out_dev_create_file_failed:
 175        device_remove_file(&spi->dev, &dev_attr_temp1_input);
 176        hwmon_device_unregister(p_lm70->hwmon_dev);
 177out_dev_reg_failed:
 178        dev_set_drvdata(&spi->dev, NULL);
 179        kfree(p_lm70);
 180        return status;
 181}
 182
 183static int __devexit lm70_remove(struct spi_device *spi)
 184{
 185        struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev);
 186
 187        device_remove_file(&spi->dev, &dev_attr_temp1_input);
 188        device_remove_file(&spi->dev, &dev_attr_name);
 189        hwmon_device_unregister(p_lm70->hwmon_dev);
 190        dev_set_drvdata(&spi->dev, NULL);
 191        kfree(p_lm70);
 192
 193        return 0;
 194}
 195
 196
 197static const struct spi_device_id lm70_ids[] = {
 198        { "lm70",   LM70_CHIP_LM70 },
 199        { "tmp121", LM70_CHIP_TMP121 },
 200        { },
 201};
 202MODULE_DEVICE_TABLE(spi, lm70_ids);
 203
 204static struct spi_driver lm70_driver = {
 205        .driver = {
 206                .name   = "lm70",
 207                .owner  = THIS_MODULE,
 208        },
 209        .id_table = lm70_ids,
 210        .probe  = lm70_probe,
 211        .remove = __devexit_p(lm70_remove),
 212};
 213
 214static int __init init_lm70(void)
 215{
 216        return spi_register_driver(&lm70_driver);
 217}
 218
 219static void __exit cleanup_lm70(void)
 220{
 221        spi_unregister_driver(&lm70_driver);
 222}
 223
 224module_init(init_lm70);
 225module_exit(cleanup_lm70);
 226
 227MODULE_AUTHOR("Kaiwan N Billimoria");
 228MODULE_DESCRIPTION("NS LM70 / TI TMP121/TMP123 Linux driver");
 229MODULE_LICENSE("GPL");
 230