Root/
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 temperature masks |
22 | */ |
23 | #define AD7314_TEMP_MASK 0x7FE0 |
24 | #define AD7314_TEMP_SHIFT 5 |
25 | |
26 | /* |
27 | * ADT7301 and ADT7302 temperature masks |
28 | */ |
29 | #define ADT7301_TEMP_MASK 0x3FFF |
30 | |
31 | enum ad7314_variant { |
32 | adt7301, |
33 | adt7302, |
34 | ad7314, |
35 | }; |
36 | |
37 | struct ad7314_data { |
38 | struct spi_device *spi_dev; |
39 | struct device *hwmon_dev; |
40 | u16 rx ____cacheline_aligned; |
41 | }; |
42 | |
43 | static int ad7314_spi_read(struct ad7314_data *chip) |
44 | { |
45 | int ret; |
46 | |
47 | ret = spi_read(chip->spi_dev, (u8 *)&chip->rx, sizeof(chip->rx)); |
48 | if (ret < 0) { |
49 | dev_err(&chip->spi_dev->dev, "SPI read error\n"); |
50 | return ret; |
51 | } |
52 | |
53 | return be16_to_cpu(chip->rx); |
54 | } |
55 | |
56 | static ssize_t ad7314_show_temperature(struct device *dev, |
57 | struct device_attribute *attr, |
58 | char *buf) |
59 | { |
60 | struct ad7314_data *chip = dev_get_drvdata(dev); |
61 | s16 data; |
62 | int ret; |
63 | |
64 | ret = ad7314_spi_read(chip); |
65 | if (ret < 0) |
66 | return ret; |
67 | switch (spi_get_device_id(chip->spi_dev)->driver_data) { |
68 | case ad7314: |
69 | data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_SHIFT; |
70 | data = (data << 6) >> 6; |
71 | |
72 | return sprintf(buf, "%d\n", 250 * data); |
73 | case adt7301: |
74 | case adt7302: |
75 | /* |
76 | * Documented as a 13 bit twos complement register |
77 | * with a sign bit - which is a 14 bit 2's complement |
78 | * register. 1lsb - 31.25 milli degrees centigrade |
79 | */ |
80 | data = ret & ADT7301_TEMP_MASK; |
81 | data = (data << 2) >> 2; |
82 | |
83 | return sprintf(buf, "%d\n", |
84 | DIV_ROUND_CLOSEST(data * 3125, 100)); |
85 | default: |
86 | return -EINVAL; |
87 | } |
88 | } |
89 | |
90 | static ssize_t ad7314_show_name(struct device *dev, |
91 | struct device_attribute *devattr, char *buf) |
92 | { |
93 | return sprintf(buf, "%s\n", to_spi_device(dev)->modalias); |
94 | } |
95 | |
96 | static DEVICE_ATTR(name, S_IRUGO, ad7314_show_name, NULL); |
97 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, |
98 | ad7314_show_temperature, NULL, 0); |
99 | |
100 | static struct attribute *ad7314_attributes[] = { |
101 | &dev_attr_name.attr, |
102 | &sensor_dev_attr_temp1_input.dev_attr.attr, |
103 | NULL, |
104 | }; |
105 | |
106 | static const struct attribute_group ad7314_group = { |
107 | .attrs = ad7314_attributes, |
108 | }; |
109 | |
110 | static int ad7314_probe(struct spi_device *spi_dev) |
111 | { |
112 | int ret; |
113 | struct ad7314_data *chip; |
114 | |
115 | chip = devm_kzalloc(&spi_dev->dev, sizeof(*chip), GFP_KERNEL); |
116 | if (chip == NULL) |
117 | return -ENOMEM; |
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 | return ret; |
124 | |
125 | chip->hwmon_dev = hwmon_device_register(&spi_dev->dev); |
126 | if (IS_ERR(chip->hwmon_dev)) { |
127 | ret = PTR_ERR(chip->hwmon_dev); |
128 | goto error_remove_group; |
129 | } |
130 | chip->spi_dev = spi_dev; |
131 | |
132 | return 0; |
133 | error_remove_group: |
134 | sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group); |
135 | return ret; |
136 | } |
137 | |
138 | static int ad7314_remove(struct spi_device *spi_dev) |
139 | { |
140 | struct ad7314_data *chip = dev_get_drvdata(&spi_dev->dev); |
141 | |
142 | hwmon_device_unregister(chip->hwmon_dev); |
143 | sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group); |
144 | |
145 | return 0; |
146 | } |
147 | |
148 | static const struct spi_device_id ad7314_id[] = { |
149 | { "adt7301", adt7301 }, |
150 | { "adt7302", adt7302 }, |
151 | { "ad7314", ad7314 }, |
152 | { } |
153 | }; |
154 | MODULE_DEVICE_TABLE(spi, ad7314_id); |
155 | |
156 | static struct spi_driver ad7314_driver = { |
157 | .driver = { |
158 | .name = "ad7314", |
159 | .owner = THIS_MODULE, |
160 | }, |
161 | .probe = ad7314_probe, |
162 | .remove = ad7314_remove, |
163 | .id_table = ad7314_id, |
164 | }; |
165 | |
166 | module_spi_driver(ad7314_driver); |
167 | |
168 | MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>"); |
169 | MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital" |
170 | " temperature sensor driver"); |
171 | MODULE_LICENSE("GPL v2"); |
172 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9