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 | ||
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"); |