1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * lm70.c 4 * 5 * The LM70 is a temperature sensor chip from National Semiconductor (NS). 6 * Copyright (C) 2006 Kaiwan N Billimoria <kaiwan@designergraphix.com> 7 * 8 * The LM70 communicates with a host processor via an SPI/Microwire Bus 9 * interface. The complete datasheet is available at National's website 10 * here: 11 * http://www.national.com/pf/LM/LM70.html 12 */ 13 14 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 15 16 #include <linux/init.h> 17 #include <linux/module.h> 18 #include <linux/kernel.h> 19 #include <linux/device.h> 20 #include <linux/err.h> 21 #include <linux/sysfs.h> 22 #include <linux/hwmon.h> 23 #include <linux/mutex.h> 24 #include <linux/mod_devicetable.h> 25 #include <linux/spi/spi.h> 26 #include <linux/slab.h> 27 #include <linux/of_device.h> 28 #include <linux/acpi.h> 29 30 #define DRVNAME "lm70" 31 32 #define LM70_CHIP_LM70 0 /* original NS LM70 */ 33 #define LM70_CHIP_TMP121 1 /* TI TMP121/TMP123 */ 34 #define LM70_CHIP_LM71 2 /* NS LM71 */ 35 #define LM70_CHIP_LM74 3 /* NS LM74 */ 36 #define LM70_CHIP_TMP122 4 /* TI TMP122/TMP124 */ 37 38 struct lm70 { 39 struct spi_device *spi; 40 struct mutex lock; 41 unsigned int chip; 42 }; 43 44 /* sysfs hook function */ 45 static ssize_t temp1_input_show(struct device *dev, 46 struct device_attribute *attr, char *buf) 47 { 48 struct lm70 *p_lm70 = dev_get_drvdata(dev); 49 struct spi_device *spi = p_lm70->spi; 50 int status, val = 0; 51 u8 rxbuf[2]; 52 s16 raw = 0; 53 54 if (mutex_lock_interruptible(&p_lm70->lock)) 55 return -ERESTARTSYS; 56 57 /* 58 * spi_read() requires a DMA-safe buffer; so we use 59 * spi_write_then_read(), transmitting 0 bytes. 60 */ 61 status = spi_write_then_read(spi, NULL, 0, &rxbuf[0], 2); 62 if (status < 0) { 63 dev_warn(dev, "spi_write_then_read failed with status %d\n", 64 status); 65 goto out; 66 } 67 raw = (rxbuf[0] << 8) + rxbuf[1]; 68 dev_dbg(dev, "rxbuf[0] : 0x%02x rxbuf[1] : 0x%02x raw=0x%04x\n", 69 rxbuf[0], rxbuf[1], raw); 70 71 /* 72 * LM70: 73 * The "raw" temperature read into rxbuf[] is a 16-bit signed 2's 74 * complement value. Only the MSB 11 bits (1 sign + 10 temperature 75 * bits) are meaningful; the LSB 5 bits are to be discarded. 76 * See the datasheet. 77 * 78 * Further, each bit represents 0.25 degrees Celsius; so, multiply 79 * by 0.25. Also multiply by 1000 to represent in millidegrees 80 * Celsius. 81 * So it's equivalent to multiplying by 0.25 * 1000 = 250. 82 * 83 * LM74 and TMP121/TMP122/TMP123/TMP124: 84 * 13 bits of 2's complement data, discard LSB 3 bits, 85 * resolution 0.0625 degrees celsius. 86 * 87 * LM71: 88 * 14 bits of 2's complement data, discard LSB 2 bits, 89 * resolution 0.0312 degrees celsius. 90 */ 91 switch (p_lm70->chip) { 92 case LM70_CHIP_LM70: 93 val = ((int)raw / 32) * 250; 94 break; 95 96 case LM70_CHIP_TMP121: 97 case LM70_CHIP_TMP122: 98 case LM70_CHIP_LM74: 99 val = ((int)raw / 8) * 625 / 10; 100 break; 101 102 case LM70_CHIP_LM71: 103 val = ((int)raw / 4) * 3125 / 100; 104 break; 105 } 106 107 status = sprintf(buf, "%d\n", val); /* millidegrees Celsius */ 108 out: 109 mutex_unlock(&p_lm70->lock); 110 return status; 111 } 112 113 static DEVICE_ATTR_RO(temp1_input); 114 115 static struct attribute *lm70_attrs[] = { 116 &dev_attr_temp1_input.attr, 117 NULL 118 }; 119 120 ATTRIBUTE_GROUPS(lm70); 121 122 /*----------------------------------------------------------------------*/ 123 124 #ifdef CONFIG_OF 125 static const struct of_device_id lm70_of_ids[] = { 126 { 127 .compatible = "ti,lm70", 128 .data = (void *) LM70_CHIP_LM70, 129 }, 130 { 131 .compatible = "ti,tmp121", 132 .data = (void *) LM70_CHIP_TMP121, 133 }, 134 { 135 .compatible = "ti,tmp122", 136 .data = (void *) LM70_CHIP_TMP122, 137 }, 138 { 139 .compatible = "ti,lm71", 140 .data = (void *) LM70_CHIP_LM71, 141 }, 142 { 143 .compatible = "ti,lm74", 144 .data = (void *) LM70_CHIP_LM74, 145 }, 146 {}, 147 }; 148 MODULE_DEVICE_TABLE(of, lm70_of_ids); 149 #endif 150 151 #ifdef CONFIG_ACPI 152 static const struct acpi_device_id lm70_acpi_ids[] = { 153 { 154 .id = "LM000070", 155 .driver_data = LM70_CHIP_LM70, 156 }, 157 { 158 .id = "TMP00121", 159 .driver_data = LM70_CHIP_TMP121, 160 }, 161 { 162 .id = "LM000071", 163 .driver_data = LM70_CHIP_LM71, 164 }, 165 { 166 .id = "LM000074", 167 .driver_data = LM70_CHIP_LM74, 168 }, 169 {}, 170 }; 171 MODULE_DEVICE_TABLE(acpi, lm70_acpi_ids); 172 #endif 173 174 static int lm70_probe(struct spi_device *spi) 175 { 176 const struct of_device_id *of_match; 177 struct device *hwmon_dev; 178 struct lm70 *p_lm70; 179 int chip; 180 181 of_match = of_match_device(lm70_of_ids, &spi->dev); 182 if (of_match) 183 chip = (int)(uintptr_t)of_match->data; 184 else { 185 #ifdef CONFIG_ACPI 186 const struct acpi_device_id *acpi_match; 187 188 acpi_match = acpi_match_device(lm70_acpi_ids, &spi->dev); 189 if (acpi_match) 190 chip = (int)(uintptr_t)acpi_match->driver_data; 191 else 192 #endif 193 chip = spi_get_device_id(spi)->driver_data; 194 } 195 196 /* signaling is SPI_MODE_0 */ 197 if (spi->mode & (SPI_CPOL | SPI_CPHA)) 198 return -EINVAL; 199 200 /* NOTE: we assume 8-bit words, and convert to 16 bits manually */ 201 202 p_lm70 = devm_kzalloc(&spi->dev, sizeof(*p_lm70), GFP_KERNEL); 203 if (!p_lm70) 204 return -ENOMEM; 205 206 mutex_init(&p_lm70->lock); 207 p_lm70->chip = chip; 208 p_lm70->spi = spi; 209 210 hwmon_dev = devm_hwmon_device_register_with_groups(&spi->dev, 211 spi->modalias, 212 p_lm70, lm70_groups); 213 return PTR_ERR_OR_ZERO(hwmon_dev); 214 } 215 216 static const struct spi_device_id lm70_ids[] = { 217 { "lm70", LM70_CHIP_LM70 }, 218 { "tmp121", LM70_CHIP_TMP121 }, 219 { "tmp122", LM70_CHIP_TMP122 }, 220 { "lm71", LM70_CHIP_LM71 }, 221 { "lm74", LM70_CHIP_LM74 }, 222 { }, 223 }; 224 MODULE_DEVICE_TABLE(spi, lm70_ids); 225 226 static struct spi_driver lm70_driver = { 227 .driver = { 228 .name = "lm70", 229 .of_match_table = of_match_ptr(lm70_of_ids), 230 .acpi_match_table = ACPI_PTR(lm70_acpi_ids), 231 }, 232 .id_table = lm70_ids, 233 .probe = lm70_probe, 234 }; 235 236 module_spi_driver(lm70_driver); 237 238 MODULE_AUTHOR("Kaiwan N Billimoria"); 239 MODULE_DESCRIPTION("NS LM70 and compatibles Linux driver"); 240 MODULE_LICENSE("GPL"); 241