]>
Commit | Line | Data |
---|---|---|
4f3a6595 JC |
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 | ||
eae1415d | 50 | static int ad7314_spi_read(struct ad7314_data *chip) |
4f3a6595 JC |
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 | ||
eae1415d | 60 | return be16_to_cpu(chip->rx); |
4f3a6595 JC |
61 | } |
62 | ||
63 | static ssize_t ad7314_show_temperature(struct device *dev, | |
64 | struct device_attribute *attr, | |
65 | char *buf) | |
66 | { | |
67 | struct ad7314_data *chip = dev_get_drvdata(dev); | |
68 | s16 data; | |
69 | int ret; | |
70 | ||
eae1415d | 71 | ret = ad7314_spi_read(chip); |
4f3a6595 JC |
72 | if (ret < 0) |
73 | return ret; | |
74 | switch (spi_get_device_id(chip->spi_dev)->driver_data) { | |
75 | case ad7314: | |
eae1415d | 76 | data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_OFFSET; |
4f3a6595 JC |
77 | data = (data << 6) >> 6; |
78 | ||
79 | return sprintf(buf, "%d\n", 250 * data); | |
80 | case adt7301: | |
81 | case adt7302: | |
82 | /* | |
83 | * Documented as a 13 bit twos complement register | |
84 | * with a sign bit - which is a 14 bit 2's complement | |
85 | * register. 1lsb - 31.25 milli degrees centigrade | |
86 | */ | |
eae1415d | 87 | data = ret & ADT7301_TEMP_MASK; |
4f3a6595 JC |
88 | data = (data << 2) >> 2; |
89 | ||
90 | return sprintf(buf, "%d\n", | |
91 | DIV_ROUND_CLOSEST(data * 3125, 100)); | |
92 | default: | |
93 | return -EINVAL; | |
94 | } | |
95 | } | |
96 | ||
97 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, | |
98 | ad7314_show_temperature, NULL, 0); | |
99 | ||
100 | static struct attribute *ad7314_attributes[] = { | |
101 | &sensor_dev_attr_temp1_input.dev_attr.attr, | |
102 | NULL, | |
103 | }; | |
104 | ||
105 | static const struct attribute_group ad7314_group = { | |
106 | .attrs = ad7314_attributes, | |
107 | }; | |
108 | ||
109 | static int __devinit ad7314_probe(struct spi_device *spi_dev) | |
110 | { | |
111 | int ret; | |
112 | struct ad7314_data *chip; | |
113 | ||
114 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | |
115 | if (chip == NULL) { | |
116 | ret = -ENOMEM; | |
117 | goto error_ret; | |
118 | } | |
119 | dev_set_drvdata(&spi_dev->dev, chip); | |
120 | ||
121 | ret = sysfs_create_group(&spi_dev->dev.kobj, &ad7314_group); | |
122 | if (ret < 0) | |
123 | goto error_free_chip; | |
124 | chip->hwmon_dev = hwmon_device_register(&spi_dev->dev); | |
125 | if (IS_ERR(chip->hwmon_dev)) { | |
126 | ret = PTR_ERR(chip->hwmon_dev); | |
127 | goto error_remove_group; | |
128 | } | |
e16de913 | 129 | chip->spi_dev = spi_dev; |
4f3a6595 JC |
130 | |
131 | return 0; | |
132 | error_remove_group: | |
133 | sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group); | |
134 | error_free_chip: | |
135 | kfree(chip); | |
136 | error_ret: | |
137 | return ret; | |
138 | } | |
139 | ||
140 | static int __devexit ad7314_remove(struct spi_device *spi_dev) | |
141 | { | |
142 | struct ad7314_data *chip = dev_get_drvdata(&spi_dev->dev); | |
143 | ||
144 | hwmon_device_unregister(chip->hwmon_dev); | |
145 | sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group); | |
146 | kfree(chip); | |
147 | ||
148 | return 0; | |
149 | } | |
150 | ||
151 | static const struct spi_device_id ad7314_id[] = { | |
152 | { "adt7301", adt7301 }, | |
153 | { "adt7302", adt7302 }, | |
154 | { "ad7314", ad7314 }, | |
155 | { } | |
156 | }; | |
157 | MODULE_DEVICE_TABLE(spi, ad7314_id); | |
158 | ||
159 | static struct spi_driver ad7314_driver = { | |
160 | .driver = { | |
161 | .name = "ad7314", | |
4f3a6595 JC |
162 | .owner = THIS_MODULE, |
163 | }, | |
164 | .probe = ad7314_probe, | |
165 | .remove = __devexit_p(ad7314_remove), | |
166 | .id_table = ad7314_id, | |
167 | }; | |
168 | ||
91efffe2 | 169 | module_spi_driver(ad7314_driver); |
4f3a6595 JC |
170 | |
171 | MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>"); | |
172 | MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital" | |
173 | " temperature sensor driver"); | |
174 | MODULE_LICENSE("GPL v2"); |