Blame view

drivers/hwmon/lm70.c 5.9 KB
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  /*
   * lm70.c
   *
   * The LM70 is a temperature sensor chip from National Semiconductor (NS).
   * Copyright (C) 2006 Kaiwan N Billimoria <kaiwan@designergraphix.com>
   *
   * The LM70 communicates with a host processor via an SPI/Microwire Bus
   * interface. The complete datasheet is available at National's website
   * here:
   * http://www.national.com/pf/LM/LM70.html
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   */
5713017ec   Joe Perches   hwmon: (lm70) Use...
26
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
27
28
29
30
31
32
33
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/device.h>
  #include <linux/err.h>
  #include <linux/sysfs.h>
  #include <linux/hwmon.h>
4bfe66048   Matthias Kaehlcke   hwmon: (lm70) Con...
34
  #include <linux/mutex.h>
8cec03eee   Anton Vorontsov   hwmon: lm70: conv...
35
  #include <linux/mod_devicetable.h>
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
36
  #include <linux/spi/spi.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
37
  #include <linux/slab.h>
4bfe66048   Matthias Kaehlcke   hwmon: (lm70) Con...
38

e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
39
40
  
  #define DRVNAME		"lm70"
c8ac32e47   Manuel Lauss   hwmon: (lm70) Add...
41
42
  #define LM70_CHIP_LM70		0	/* original NS LM70 */
  #define LM70_CHIP_TMP121	1	/* TI TMP121/TMP123 */
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
43
  struct lm70 {
1beeffe43   Tony Jones   hwmon: Convert fr...
44
  	struct device *hwmon_dev;
4bfe66048   Matthias Kaehlcke   hwmon: (lm70) Con...
45
  	struct mutex lock;
c8ac32e47   Manuel Lauss   hwmon: (lm70) Add...
46
  	unsigned int chip;
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
47
48
49
50
51
52
53
  };
  
  /* sysfs hook function */
  static ssize_t lm70_sense_temp(struct device *dev,
  		struct device_attribute *attr, char *buf)
  {
  	struct spi_device *spi = to_spi_device(dev);
c8ac32e47   Manuel Lauss   hwmon: (lm70) Add...
54
  	int status, val = 0;
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
55
56
  	u8 rxbuf[2];
  	s16 raw=0;
95de3b257   Jean Delvare   hwmon: Use helper...
57
  	struct lm70 *p_lm70 = spi_get_drvdata(spi);
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
58

4bfe66048   Matthias Kaehlcke   hwmon: (lm70) Con...
59
  	if (mutex_lock_interruptible(&p_lm70->lock))
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
60
61
62
63
64
65
66
67
  		return -ERESTARTSYS;
  
  	/*
  	 * spi_read() requires a DMA-safe buffer; so we use
  	 * spi_write_then_read(), transmitting 0 bytes.
  	 */
  	status = spi_write_then_read(spi, NULL, 0, &rxbuf[0], 2);
  	if (status < 0) {
5713017ec   Joe Perches   hwmon: (lm70) Use...
68
69
  		pr_warn("spi_write_then_read failed with status %d
  ", status);
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
70
71
  		goto out;
  	}
2b7300513   Kaiwan N Billimoria   hwmon: (lm70) Cod...
72
73
74
75
  	raw = (rxbuf[0] << 8) + rxbuf[1];
  	dev_dbg(dev, "rxbuf[0] : 0x%02x rxbuf[1] : 0x%02x raw=0x%04x
  ",
  		rxbuf[0], rxbuf[1], raw);
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
76
77
  
  	/*
c8ac32e47   Manuel Lauss   hwmon: (lm70) Add...
78
  	 * LM70:
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
79
80
81
82
83
84
85
86
87
  	 * The "raw" temperature read into rxbuf[] is a 16-bit signed 2's
  	 * complement value. Only the MSB 11 bits (1 sign + 10 temperature
  	 * bits) are meaningful; the LSB 5 bits are to be discarded.
  	 * See the datasheet.
  	 *
  	 * Further, each bit represents 0.25 degrees Celsius; so, multiply
  	 * by 0.25. Also multiply by 1000 to represent in millidegrees
  	 * Celsius.
  	 * So it's equivalent to multiplying by 0.25 * 1000 = 250.
c8ac32e47   Manuel Lauss   hwmon: (lm70) Add...
88
89
90
91
  	 *
  	 * TMP121/TMP123:
  	 * 13 bits of 2's complement data, discard LSB 3 bits,
  	 * resolution 0.0625 degrees celsius.
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
92
  	 */
c8ac32e47   Manuel Lauss   hwmon: (lm70) Add...
93
94
95
96
97
98
99
100
101
  	switch (p_lm70->chip) {
  	case LM70_CHIP_LM70:
  		val = ((int)raw / 32) * 250;
  		break;
  
  	case LM70_CHIP_TMP121:
  		val = ((int)raw / 8) * 625 / 10;
  		break;
  	}
67f921d16   Jean Delvare   hwmon: (lm70) Add...
102
103
  	status = sprintf(buf, "%d
  ", val); /* millidegrees Celsius */
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
104
  out:
4bfe66048   Matthias Kaehlcke   hwmon: (lm70) Con...
105
  	mutex_unlock(&p_lm70->lock);
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
106
107
108
109
  	return status;
  }
  
  static DEVICE_ATTR(temp1_input, S_IRUGO, lm70_sense_temp, NULL);
67f921d16   Jean Delvare   hwmon: (lm70) Add...
110
111
112
  static ssize_t lm70_show_name(struct device *dev, struct device_attribute
  			      *devattr, char *buf)
  {
c8ac32e47   Manuel Lauss   hwmon: (lm70) Add...
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
  	struct lm70 *p_lm70 = dev_get_drvdata(dev);
  	int ret;
  
  	switch (p_lm70->chip) {
  	case LM70_CHIP_LM70:
  		ret = sprintf(buf, "lm70
  ");
  		break;
  	case LM70_CHIP_TMP121:
  		ret = sprintf(buf, "tmp121
  ");
  		break;
  	default:
  		ret = -EINVAL;
  	}
  	return ret;
67f921d16   Jean Delvare   hwmon: (lm70) Add...
129
130
131
  }
  
  static DEVICE_ATTR(name, S_IRUGO, lm70_show_name, NULL);
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
132
  /*----------------------------------------------------------------------*/
8cec03eee   Anton Vorontsov   hwmon: lm70: conv...
133
  static int __devinit lm70_probe(struct spi_device *spi)
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
134
  {
8cec03eee   Anton Vorontsov   hwmon: lm70: conv...
135
  	int chip = spi_get_device_id(spi)->driver_data;
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
136
137
  	struct lm70 *p_lm70;
  	int status;
8cec03eee   Anton Vorontsov   hwmon: lm70: conv...
138
139
140
141
142
143
144
  	/* signaling is SPI_MODE_0 for both LM70 and TMP121 */
  	if (spi->mode & (SPI_CPOL | SPI_CPHA))
  		return -EINVAL;
  
  	/* 3-wire link (shared SI/SO) for LM70 */
  	if (chip == LM70_CHIP_LM70 && !(spi->mode & SPI_3WIRE))
  		return -EINVAL;
2b7300513   Kaiwan N Billimoria   hwmon: (lm70) Cod...
145
  	/* NOTE:  we assume 8-bit words, and convert to 16 bits manually */
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
146
147
148
  	p_lm70 = kzalloc(sizeof *p_lm70, GFP_KERNEL);
  	if (!p_lm70)
  		return -ENOMEM;
4bfe66048   Matthias Kaehlcke   hwmon: (lm70) Con...
149
  	mutex_init(&p_lm70->lock);
c8ac32e47   Manuel Lauss   hwmon: (lm70) Add...
150
  	p_lm70->chip = chip;
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
151
152
  
  	/* sysfs hook */
1beeffe43   Tony Jones   hwmon: Convert fr...
153
154
  	p_lm70->hwmon_dev = hwmon_device_register(&spi->dev);
  	if (IS_ERR(p_lm70->hwmon_dev)) {
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
155
156
  		dev_dbg(&spi->dev, "hwmon_device_register failed.
  ");
1beeffe43   Tony Jones   hwmon: Convert fr...
157
  		status = PTR_ERR(p_lm70->hwmon_dev);
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
158
159
  		goto out_dev_reg_failed;
  	}
95de3b257   Jean Delvare   hwmon: Use helper...
160
  	spi_set_drvdata(spi, p_lm70);
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
161

67f921d16   Jean Delvare   hwmon: (lm70) Add...
162
163
  	if ((status = device_create_file(&spi->dev, &dev_attr_temp1_input))
  	 || (status = device_create_file(&spi->dev, &dev_attr_name))) {
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
164
165
166
167
168
169
170
171
  		dev_dbg(&spi->dev, "device_create_file failure.
  ");
  		goto out_dev_create_file_failed;
  	}
  
  	return 0;
  
  out_dev_create_file_failed:
67f921d16   Jean Delvare   hwmon: (lm70) Add...
172
  	device_remove_file(&spi->dev, &dev_attr_temp1_input);
1beeffe43   Tony Jones   hwmon: Convert fr...
173
  	hwmon_device_unregister(p_lm70->hwmon_dev);
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
174
  out_dev_reg_failed:
95de3b257   Jean Delvare   hwmon: Use helper...
175
  	spi_set_drvdata(spi, NULL);
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
176
177
178
  	kfree(p_lm70);
  	return status;
  }
41be722b6   Ralf Baechle   hwmon/lm70: Make ...
179
  static int __devexit lm70_remove(struct spi_device *spi)
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
180
  {
95de3b257   Jean Delvare   hwmon: Use helper...
181
  	struct lm70 *p_lm70 = spi_get_drvdata(spi);
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
182
183
  
  	device_remove_file(&spi->dev, &dev_attr_temp1_input);
67f921d16   Jean Delvare   hwmon: (lm70) Add...
184
  	device_remove_file(&spi->dev, &dev_attr_name);
1beeffe43   Tony Jones   hwmon: Convert fr...
185
  	hwmon_device_unregister(p_lm70->hwmon_dev);
95de3b257   Jean Delvare   hwmon: Use helper...
186
  	spi_set_drvdata(spi, NULL);
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
187
188
189
190
  	kfree(p_lm70);
  
  	return 0;
  }
8cec03eee   Anton Vorontsov   hwmon: lm70: conv...
191
192
193
194
195
  
  static const struct spi_device_id lm70_ids[] = {
  	{ "lm70",   LM70_CHIP_LM70 },
  	{ "tmp121", LM70_CHIP_TMP121 },
  	{ },
c8ac32e47   Manuel Lauss   hwmon: (lm70) Add...
196
  };
8cec03eee   Anton Vorontsov   hwmon: lm70: conv...
197
  MODULE_DEVICE_TABLE(spi, lm70_ids);
c8ac32e47   Manuel Lauss   hwmon: (lm70) Add...
198

e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
199
200
201
202
203
  static struct spi_driver lm70_driver = {
  	.driver = {
  		.name	= "lm70",
  		.owner	= THIS_MODULE,
  	},
8cec03eee   Anton Vorontsov   hwmon: lm70: conv...
204
  	.id_table = lm70_ids,
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
205
206
207
208
209
210
  	.probe	= lm70_probe,
  	.remove	= __devexit_p(lm70_remove),
  };
  
  static int __init init_lm70(void)
  {
8cec03eee   Anton Vorontsov   hwmon: lm70: conv...
211
  	return spi_register_driver(&lm70_driver);
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
212
213
214
215
216
217
218
219
220
221
222
  }
  
  static void __exit cleanup_lm70(void)
  {
  	spi_unregister_driver(&lm70_driver);
  }
  
  module_init(init_lm70);
  module_exit(cleanup_lm70);
  
  MODULE_AUTHOR("Kaiwan N Billimoria");
c8ac32e47   Manuel Lauss   hwmon: (lm70) Add...
223
  MODULE_DESCRIPTION("NS LM70 / TI TMP121/TMP123 Linux driver");
e1a8e913f   Kaiwan N Billimoria   [PATCH] lm70: New...
224
  MODULE_LICENSE("GPL");