aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/hwmon/Kconfig9
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/lm73.c205
3 files changed, 215 insertions, 0 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 700e93adeb3..87184b5f401 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -442,6 +442,15 @@ config SENSORS_LM70
442 This driver can also be built as a module. If so, the module 442 This driver can also be built as a module. If so, the module
443 will be called lm70. 443 will be called lm70.
444 444
445config SENSORS_LM73
446 tristate "National Semiconductor LM73"
447 depends on I2C
448 help
449 If you say yes here you get support for National Semiconductor LM73
450 sensor chips.
451 This driver can also be built as a module. If so, the module
452 will be called lm73.
453
445config SENSORS_LM75 454config SENSORS_LM75
446 tristate "National Semiconductor LM75 and compatibles" 455 tristate "National Semiconductor LM75 and compatibles"
447 depends on I2C 456 depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 9f46cb019cc..a24a52d12dc 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -57,6 +57,7 @@ obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o hp_accel.o
57obj-$(CONFIG_SENSORS_LIS3_SPI) += lis3lv02d.o lis3lv02d_spi.o 57obj-$(CONFIG_SENSORS_LIS3_SPI) += lis3lv02d.o lis3lv02d_spi.o
58obj-$(CONFIG_SENSORS_LM63) += lm63.o 58obj-$(CONFIG_SENSORS_LM63) += lm63.o
59obj-$(CONFIG_SENSORS_LM70) += lm70.o 59obj-$(CONFIG_SENSORS_LM70) += lm70.o
60obj-$(CONFIG_SENSORS_LM73) += lm73.o
60obj-$(CONFIG_SENSORS_LM75) += lm75.o 61obj-$(CONFIG_SENSORS_LM75) += lm75.o
61obj-$(CONFIG_SENSORS_LM77) += lm77.o 62obj-$(CONFIG_SENSORS_LM77) += lm77.o
62obj-$(CONFIG_SENSORS_LM78) += lm78.o 63obj-$(CONFIG_SENSORS_LM78) += lm78.o
diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c
new file mode 100644
index 00000000000..0bf8b2a8e9f
--- /dev/null
+++ b/drivers/hwmon/lm73.c
@@ -0,0 +1,205 @@
1/*
2 * LM73 Sensor driver
3 * Based on LM75
4 *
5 * Copyright (C) 2007, CenoSYS (www.cenosys.com).
6 * Copyright (C) 2009, Bollore telecom (www.bolloretelecom.eu).
7 *
8 * Guillaume Ligneul <guillaume.ligneul@gmail.com>
9 * Adrien Demarez <adrien.demarez@bolloretelecom.eu>
10 * Jeremy Laine <jeremy.laine@bolloretelecom.eu>
11 *
12 * This software program is licensed subject to the GNU General Public License
13 * (GPL).Version 2,June 1991, available at
14 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
15 */
16
17#include <linux/module.h>
18#include <linux/init.h>
19#include <linux/slab.h>
20#include <linux/i2c.h>
21#include <linux/hwmon.h>
22#include <linux/hwmon-sysfs.h>
23#include <linux/err.h>
24
25
26/* Addresses scanned */
27static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4c,
28 0x4d, 0x4e, I2C_CLIENT_END };
29
30/* Insmod parameters */
31I2C_CLIENT_INSMOD_1(lm73);
32
33/* LM73 registers */
34#define LM73_REG_INPUT 0x00
35#define LM73_REG_CONF 0x01
36#define LM73_REG_MAX 0x02
37#define LM73_REG_MIN 0x03
38#define LM73_REG_CTRL 0x04
39#define LM73_REG_ID 0x07
40
41#define LM73_ID 0x9001 /* or 0x190 after a swab16() */
42#define DRVNAME "lm73"
43#define LM73_TEMP_MIN (-40)
44#define LM73_TEMP_MAX 150
45
46/*-----------------------------------------------------------------------*/
47
48
49static ssize_t set_temp(struct device *dev, struct device_attribute *da,
50 const char *buf, size_t count)
51{
52 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
53 struct i2c_client *client = to_i2c_client(dev);
54 long temp;
55 short value;
56
57 int status = strict_strtol(buf, 10, &temp);
58 if (status < 0)
59 return status;
60
61 /* Write value */
62 value = (short) SENSORS_LIMIT(temp/250, (LM73_TEMP_MIN*4),
63 (LM73_TEMP_MAX*4)) << 5;
64 i2c_smbus_write_word_data(client, attr->index, swab16(value));
65 return count;
66}
67
68static ssize_t show_temp(struct device *dev, struct device_attribute *da,
69 char *buf)
70{
71 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
72 struct i2c_client *client = to_i2c_client(dev);
73 /* use integer division instead of equivalent right shift to
74 guarantee arithmetic shift and preserve the sign */
75 int temp = ((s16) (swab16(i2c_smbus_read_word_data(client,
76 attr->index)))*250) / 32;
77 return sprintf(buf, "%d\n", temp);
78}
79
80
81/*-----------------------------------------------------------------------*/
82
83/* sysfs attributes for hwmon */
84
85static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
86 show_temp, set_temp, LM73_REG_MAX);
87static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
88 show_temp, set_temp, LM73_REG_MIN);
89static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
90 show_temp, NULL, LM73_REG_INPUT);
91
92
93static struct attribute *lm73_attributes[] = {
94 &sensor_dev_attr_temp1_input.dev_attr.attr,
95 &sensor_dev_attr_temp1_max.dev_attr.attr,
96 &sensor_dev_attr_temp1_min.dev_attr.attr,
97
98 NULL
99};
100
101static const struct attribute_group lm73_group = {
102 .attrs = lm73_attributes,
103};
104
105/*-----------------------------------------------------------------------*/
106
107/* device probe and removal */
108
109static int
110lm73_probe(struct i2c_client *client, const struct i2c_device_id *id)
111{
112 struct device *hwmon_dev;
113 int status;
114
115 /* Register sysfs hooks */
116 status = sysfs_create_group(&client->dev.kobj, &lm73_group);
117 if (status)
118 return status;
119
120 hwmon_dev = hwmon_device_register(&client->dev);
121 if (IS_ERR(hwmon_dev)) {
122 status = PTR_ERR(hwmon_dev);
123 goto exit_remove;
124 }
125 i2c_set_clientdata(client, hwmon_dev);
126
127 dev_info(&client->dev, "%s: sensor '%s'\n",
128 dev_name(hwmon_dev), client->name);
129
130 return 0;
131
132exit_remove:
133 sysfs_remove_group(&client->dev.kobj, &lm73_group);
134 return status;
135}
136
137static int lm73_remove(struct i2c_client *client)
138{
139 struct device *hwmon_dev = i2c_get_clientdata(client);
140
141 hwmon_device_unregister(hwmon_dev);
142 sysfs_remove_group(&client->dev.kobj, &lm73_group);
143 i2c_set_clientdata(client, NULL);
144 return 0;
145}
146
147static const struct i2c_device_id lm73_ids[] = {
148 { "lm73", lm73 },
149 { /* LIST END */ }
150};
151MODULE_DEVICE_TABLE(i2c, lm73_ids);
152
153/* Return 0 if detection is successful, -ENODEV otherwise */
154static int lm73_detect(struct i2c_client *new_client, int kind,
155 struct i2c_board_info *info)
156{
157 struct i2c_adapter *adapter = new_client->adapter;
158 u16 id;
159 u8 ctrl;
160
161 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
162 I2C_FUNC_SMBUS_WORD_DATA))
163 return -ENODEV;
164
165 /* Check device ID */
166 id = i2c_smbus_read_word_data(new_client, LM73_REG_ID);
167 ctrl = i2c_smbus_read_byte_data(new_client, LM73_REG_CTRL);
168 if ((id != LM73_ID) || (ctrl & 0x10))
169 return -ENODEV;
170
171 strlcpy(info->type, "lm73", I2C_NAME_SIZE);
172
173 return 0;
174}
175
176static struct i2c_driver lm73_driver = {
177 .class = I2C_CLASS_HWMON,
178 .driver = {
179 .name = "lm73",
180 },
181 .probe = lm73_probe,
182 .remove = lm73_remove,
183 .id_table = lm73_ids,
184 .detect = lm73_detect,
185 .address_data = &addr_data,
186};
187
188/* module glue */
189
190static int __init sensors_lm73_init(void)
191{
192 return i2c_add_driver(&lm73_driver);
193}
194
195static void __exit sensors_lm73_exit(void)
196{
197 i2c_del_driver(&lm73_driver);
198}
199
200MODULE_AUTHOR("Guillaume Ligneul <guillaume.ligneul@gmail.com>");
201MODULE_DESCRIPTION("LM73 driver");
202MODULE_LICENSE("GPL");
203
204module_init(sensors_lm73_init);
205module_exit(sensors_lm73_exit);