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> | |
984faa1f | 19 | #include <linux/bitops.h> |
4f3a6595 | 20 | |
4f3a6595 JC |
21 | /* |
22 | * AD7314 temperature masks | |
23 | */ | |
4f3a6595 | 24 | #define AD7314_TEMP_MASK 0x7FE0 |
1137a9a6 | 25 | #define AD7314_TEMP_SHIFT 5 |
4f3a6595 JC |
26 | |
27 | /* | |
28 | * ADT7301 and ADT7302 temperature masks | |
29 | */ | |
4f3a6595 JC |
30 | #define ADT7301_TEMP_MASK 0x3FFF |
31 | ||
32 | enum ad7314_variant { | |
33 | adt7301, | |
34 | adt7302, | |
35 | ad7314, | |
36 | }; | |
37 | ||
38 | struct ad7314_data { | |
39 | struct spi_device *spi_dev; | |
40 | struct device *hwmon_dev; | |
41 | u16 rx ____cacheline_aligned; | |
42 | }; | |
43 | ||
eae1415d | 44 | static int ad7314_spi_read(struct ad7314_data *chip) |
4f3a6595 JC |
45 | { |
46 | int ret; | |
47 | ||
48 | ret = spi_read(chip->spi_dev, (u8 *)&chip->rx, sizeof(chip->rx)); | |
49 | if (ret < 0) { | |
50 | dev_err(&chip->spi_dev->dev, "SPI read error\n"); | |
51 | return ret; | |
52 | } | |
53 | ||
eae1415d | 54 | return be16_to_cpu(chip->rx); |
4f3a6595 JC |
55 | } |
56 | ||
57 | static ssize_t ad7314_show_temperature(struct device *dev, | |
58 | struct device_attribute *attr, | |
59 | char *buf) | |
60 | { | |
61 | struct ad7314_data *chip = dev_get_drvdata(dev); | |
62 | s16 data; | |
63 | int ret; | |
64 | ||
eae1415d | 65 | ret = ad7314_spi_read(chip); |
4f3a6595 JC |
66 | if (ret < 0) |
67 | return ret; | |
68 | switch (spi_get_device_id(chip->spi_dev)->driver_data) { | |
69 | case ad7314: | |
1137a9a6 | 70 | data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_SHIFT; |
984faa1f | 71 | data = sign_extend32(data, 9); |
4f3a6595 JC |
72 | |
73 | return sprintf(buf, "%d\n", 250 * data); | |
74 | case adt7301: | |
75 | case adt7302: | |
76 | /* | |
77 | * Documented as a 13 bit twos complement register | |
78 | * with a sign bit - which is a 14 bit 2's complement | |
79 | * register. 1lsb - 31.25 milli degrees centigrade | |
80 | */ | |
eae1415d | 81 | data = ret & ADT7301_TEMP_MASK; |
984faa1f | 82 | data = sign_extend32(data, 13); |
4f3a6595 JC |
83 | |
84 | return sprintf(buf, "%d\n", | |
85 | DIV_ROUND_CLOSEST(data * 3125, 100)); | |
86 | default: | |
87 | return -EINVAL; | |
88 | } | |
89 | } | |
90 | ||
3ceefe43 GR |
91 | static ssize_t ad7314_show_name(struct device *dev, |
92 | struct device_attribute *devattr, char *buf) | |
93 | { | |
94 | return sprintf(buf, "%s\n", to_spi_device(dev)->modalias); | |
95 | } | |
96 | ||
97 | static DEVICE_ATTR(name, S_IRUGO, ad7314_show_name, NULL); | |
4f3a6595 JC |
98 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, |
99 | ad7314_show_temperature, NULL, 0); | |
100 | ||
101 | static struct attribute *ad7314_attributes[] = { | |
3ceefe43 | 102 | &dev_attr_name.attr, |
4f3a6595 JC |
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 | ||
6c931ae1 | 111 | static int ad7314_probe(struct spi_device *spi_dev) |
4f3a6595 JC |
112 | { |
113 | int ret; | |
114 | struct ad7314_data *chip; | |
115 | ||
be923040 GR |
116 | chip = devm_kzalloc(&spi_dev->dev, sizeof(*chip), GFP_KERNEL); |
117 | if (chip == NULL) | |
118 | return -ENOMEM; | |
119 | ||
debe597c | 120 | spi_set_drvdata(spi_dev, chip); |
4f3a6595 JC |
121 | |
122 | ret = sysfs_create_group(&spi_dev->dev.kobj, &ad7314_group); | |
123 | if (ret < 0) | |
be923040 GR |
124 | return ret; |
125 | ||
4f3a6595 JC |
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 | } | |
e16de913 | 131 | chip->spi_dev = spi_dev; |
4f3a6595 JC |
132 | |
133 | return 0; | |
134 | error_remove_group: | |
135 | sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group); | |
4f3a6595 JC |
136 | return ret; |
137 | } | |
138 | ||
281dfd0b | 139 | static int ad7314_remove(struct spi_device *spi_dev) |
4f3a6595 | 140 | { |
debe597c | 141 | struct ad7314_data *chip = spi_get_drvdata(spi_dev); |
4f3a6595 JC |
142 | |
143 | hwmon_device_unregister(chip->hwmon_dev); | |
144 | sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group); | |
4f3a6595 JC |
145 | |
146 | return 0; | |
147 | } | |
148 | ||
149 | static const struct spi_device_id ad7314_id[] = { | |
150 | { "adt7301", adt7301 }, | |
151 | { "adt7302", adt7302 }, | |
152 | { "ad7314", ad7314 }, | |
153 | { } | |
154 | }; | |
155 | MODULE_DEVICE_TABLE(spi, ad7314_id); | |
156 | ||
157 | static struct spi_driver ad7314_driver = { | |
158 | .driver = { | |
159 | .name = "ad7314", | |
4f3a6595 JC |
160 | }, |
161 | .probe = ad7314_probe, | |
9e5e9b7a | 162 | .remove = ad7314_remove, |
4f3a6595 JC |
163 | .id_table = ad7314_id, |
164 | }; | |
165 | ||
91efffe2 | 166 | module_spi_driver(ad7314_driver); |
4f3a6595 JC |
167 | |
168 | MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>"); | |
b55f3757 | 169 | MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital temperature sensor driver"); |
4f3a6595 | 170 | MODULE_LICENSE("GPL v2"); |