diff options
author | Jonathan Cameron <jic23@cam.ac.uk> | 2011-09-29 12:50:04 -0400 |
---|---|---|
committer | Guenter Roeck <guenter.roeck@ericsson.com> | 2011-10-24 14:09:41 -0400 |
commit | 4f3a659581cabf1be441d6467b523be914615496 (patch) | |
tree | 7d5d581f10409b883fab255f7ccede8692497b2b /drivers/hwmon/ad7314.c | |
parent | 200855e52db1b1834121ba57fbd89c5b4911e02c (diff) |
hwmon: AD7314 driver (ported from IIO)
Driver for AD7314, ADT7301, and ADT7302, ported from IIO.
Currently dropped power down mode support.
Signed-off-by: Jonathan Cameron <jic23@cam.ac.uk>
[guenter.roeck@ericsson.com: Added MODULE_DEVICE_TABLE]
Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
Diffstat (limited to 'drivers/hwmon/ad7314.c')
-rw-r--r-- | drivers/hwmon/ad7314.c | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/drivers/hwmon/ad7314.c b/drivers/hwmon/ad7314.c new file mode 100644 index 000000000000..318e38e85376 --- /dev/null +++ b/drivers/hwmon/ad7314.c | |||
@@ -0,0 +1,186 @@ | |||
1 | /* | ||
2 | * AD7314 digital temperature sensor driver for AD7314, ADT7301 and ADT7302 | ||
3 | * | ||
4 | * Copyright 2010 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2 or later. | ||
7 | * | ||
8 | * Conversion to hwmon from IIO done by Jonathan Cameron <jic23@cam.ac.uk> | ||
9 | */ | ||
10 | #include <linux/device.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/slab.h> | ||
13 | #include <linux/sysfs.h> | ||
14 | #include <linux/spi/spi.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/hwmon.h> | ||
18 | #include <linux/hwmon-sysfs.h> | ||
19 | |||
20 | /* | ||
21 | * AD7314 power mode | ||
22 | */ | ||
23 | #define AD7314_PD 0x2000 | ||
24 | |||
25 | /* | ||
26 | * AD7314 temperature masks | ||
27 | */ | ||
28 | #define AD7314_TEMP_SIGN 0x200 | ||
29 | #define AD7314_TEMP_MASK 0x7FE0 | ||
30 | #define AD7314_TEMP_OFFSET 5 | ||
31 | |||
32 | /* | ||
33 | * ADT7301 and ADT7302 temperature masks | ||
34 | */ | ||
35 | #define ADT7301_TEMP_SIGN 0x2000 | ||
36 | #define ADT7301_TEMP_MASK 0x3FFF | ||
37 | |||
38 | enum ad7314_variant { | ||
39 | adt7301, | ||
40 | adt7302, | ||
41 | ad7314, | ||
42 | }; | ||
43 | |||
44 | struct ad7314_data { | ||
45 | struct spi_device *spi_dev; | ||
46 | struct device *hwmon_dev; | ||
47 | u16 rx ____cacheline_aligned; | ||
48 | }; | ||
49 | |||
50 | static int ad7314_spi_read(struct ad7314_data *chip, s16 *data) | ||
51 | { | ||
52 | int ret; | ||
53 | |||
54 | ret = spi_read(chip->spi_dev, (u8 *)&chip->rx, sizeof(chip->rx)); | ||
55 | if (ret < 0) { | ||
56 | dev_err(&chip->spi_dev->dev, "SPI read error\n"); | ||
57 | return ret; | ||
58 | } | ||
59 | |||
60 | *data = be16_to_cpu(chip->rx); | ||
61 | |||
62 | return ret; | ||
63 | } | ||
64 | |||
65 | static ssize_t ad7314_show_temperature(struct device *dev, | ||
66 | struct device_attribute *attr, | ||
67 | char *buf) | ||
68 | { | ||
69 | struct ad7314_data *chip = dev_get_drvdata(dev); | ||
70 | s16 data; | ||
71 | int ret; | ||
72 | |||
73 | ret = ad7314_spi_read(chip, &data); | ||
74 | if (ret < 0) | ||
75 | return ret; | ||
76 | switch (spi_get_device_id(chip->spi_dev)->driver_data) { | ||
77 | case ad7314: | ||
78 | data = (data & AD7314_TEMP_MASK) >> AD7314_TEMP_OFFSET; | ||
79 | data = (data << 6) >> 6; | ||
80 | |||
81 | return sprintf(buf, "%d\n", 250 * data); | ||
82 | case adt7301: | ||
83 | case adt7302: | ||
84 | /* | ||
85 | * Documented as a 13 bit twos complement register | ||
86 | * with a sign bit - which is a 14 bit 2's complement | ||
87 | * register. 1lsb - 31.25 milli degrees centigrade | ||
88 | */ | ||
89 | data &= ADT7301_TEMP_MASK; | ||
90 | data = (data << 2) >> 2; | ||
91 | |||
92 | return sprintf(buf, "%d\n", | ||
93 | DIV_ROUND_CLOSEST(data * 3125, 100)); | ||
94 | default: | ||
95 | return -EINVAL; | ||
96 | } | ||
97 | } | ||
98 | |||
99 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, | ||
100 | ad7314_show_temperature, NULL, 0); | ||
101 | |||
102 | static struct attribute *ad7314_attributes[] = { | ||
103 | &sensor_dev_attr_temp1_input.dev_attr.attr, | ||
104 | NULL, | ||
105 | }; | ||
106 | |||
107 | static const struct attribute_group ad7314_group = { | ||
108 | .attrs = ad7314_attributes, | ||
109 | }; | ||
110 | |||
111 | static int __devinit ad7314_probe(struct spi_device *spi_dev) | ||
112 | { | ||
113 | int ret; | ||
114 | struct ad7314_data *chip; | ||
115 | |||
116 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | ||
117 | if (chip == NULL) { | ||
118 | ret = -ENOMEM; | ||
119 | goto error_ret; | ||
120 | } | ||
121 | dev_set_drvdata(&spi_dev->dev, chip); | ||
122 | |||
123 | ret = sysfs_create_group(&spi_dev->dev.kobj, &ad7314_group); | ||
124 | if (ret < 0) | ||
125 | goto error_free_chip; | ||
126 | chip->hwmon_dev = hwmon_device_register(&spi_dev->dev); | ||
127 | if (IS_ERR(chip->hwmon_dev)) { | ||
128 | ret = PTR_ERR(chip->hwmon_dev); | ||
129 | goto error_remove_group; | ||
130 | } | ||
131 | |||
132 | return 0; | ||
133 | error_remove_group: | ||
134 | sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group); | ||
135 | error_free_chip: | ||
136 | kfree(chip); | ||
137 | error_ret: | ||
138 | return ret; | ||
139 | } | ||
140 | |||
141 | static int __devexit ad7314_remove(struct spi_device *spi_dev) | ||
142 | { | ||
143 | struct ad7314_data *chip = dev_get_drvdata(&spi_dev->dev); | ||
144 | |||
145 | hwmon_device_unregister(chip->hwmon_dev); | ||
146 | sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group); | ||
147 | kfree(chip); | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static const struct spi_device_id ad7314_id[] = { | ||
153 | { "adt7301", adt7301 }, | ||
154 | { "adt7302", adt7302 }, | ||
155 | { "ad7314", ad7314 }, | ||
156 | { } | ||
157 | }; | ||
158 | MODULE_DEVICE_TABLE(spi, ad7314_id); | ||
159 | |||
160 | static struct spi_driver ad7314_driver = { | ||
161 | .driver = { | ||
162 | .name = "ad7314", | ||
163 | .bus = &spi_bus_type, | ||
164 | .owner = THIS_MODULE, | ||
165 | }, | ||
166 | .probe = ad7314_probe, | ||
167 | .remove = __devexit_p(ad7314_remove), | ||
168 | .id_table = ad7314_id, | ||
169 | }; | ||
170 | |||
171 | static __init int ad7314_init(void) | ||
172 | { | ||
173 | return spi_register_driver(&ad7314_driver); | ||
174 | } | ||
175 | module_init(ad7314_init); | ||
176 | |||
177 | static __exit void ad7314_exit(void) | ||
178 | { | ||
179 | spi_unregister_driver(&ad7314_driver); | ||
180 | } | ||
181 | module_exit(ad7314_exit); | ||
182 | |||
183 | MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>"); | ||
184 | MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital" | ||
185 | " temperature sensor driver"); | ||
186 | MODULE_LICENSE("GPL v2"); | ||