1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * AD7314 digital temperature sensor driver for AD7314, ADT7301 and ADT7302 |
4 | * |
5 | * Copyright 2010 Analog Devices Inc. |
6 | * |
7 | * Conversion to hwmon from IIO done by Jonathan Cameron <jic23@cam.ac.uk> |
8 | */ |
9 | #include <linux/device.h> |
10 | #include <linux/kernel.h> |
11 | #include <linux/slab.h> |
12 | #include <linux/sysfs.h> |
13 | #include <linux/spi/spi.h> |
14 | #include <linux/module.h> |
15 | #include <linux/err.h> |
16 | #include <linux/hwmon.h> |
17 | #include <linux/hwmon-sysfs.h> |
18 | #include <linux/bitops.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 | u16 rx ____cacheline_aligned; |
40 | }; |
41 | |
42 | static int ad7314_spi_read(struct ad7314_data *chip) |
43 | { |
44 | int ret; |
45 | |
46 | ret = spi_read(spi: chip->spi_dev, buf: (u8 *)&chip->rx, len: sizeof(chip->rx)); |
47 | if (ret < 0) { |
48 | dev_err(&chip->spi_dev->dev, "SPI read error\n" ); |
49 | return ret; |
50 | } |
51 | |
52 | return be16_to_cpu(chip->rx); |
53 | } |
54 | |
55 | static ssize_t ad7314_temperature_show(struct device *dev, |
56 | struct device_attribute *attr, |
57 | char *buf) |
58 | { |
59 | struct ad7314_data *chip = dev_get_drvdata(dev); |
60 | s16 data; |
61 | int ret; |
62 | |
63 | ret = ad7314_spi_read(chip); |
64 | if (ret < 0) |
65 | return ret; |
66 | switch (spi_get_device_id(sdev: chip->spi_dev)->driver_data) { |
67 | case ad7314: |
68 | data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_SHIFT; |
69 | data = sign_extend32(value: data, index: 9); |
70 | |
71 | return sprintf(buf, fmt: "%d\n" , 250 * data); |
72 | case adt7301: |
73 | case adt7302: |
74 | /* |
75 | * Documented as a 13 bit twos complement register |
76 | * with a sign bit - which is a 14 bit 2's complement |
77 | * register. 1lsb - 31.25 milli degrees centigrade |
78 | */ |
79 | data = ret & ADT7301_TEMP_MASK; |
80 | data = sign_extend32(value: data, index: 13); |
81 | |
82 | return sprintf(buf, fmt: "%d\n" , |
83 | DIV_ROUND_CLOSEST(data * 3125, 100)); |
84 | default: |
85 | return -EINVAL; |
86 | } |
87 | } |
88 | |
89 | static SENSOR_DEVICE_ATTR_RO(temp1_input, ad7314_temperature, 0); |
90 | |
91 | static struct attribute *ad7314_attrs[] = { |
92 | &sensor_dev_attr_temp1_input.dev_attr.attr, |
93 | NULL, |
94 | }; |
95 | |
96 | ATTRIBUTE_GROUPS(ad7314); |
97 | |
98 | static int ad7314_probe(struct spi_device *spi_dev) |
99 | { |
100 | struct ad7314_data *chip; |
101 | struct device *hwmon_dev; |
102 | |
103 | chip = devm_kzalloc(dev: &spi_dev->dev, size: sizeof(*chip), GFP_KERNEL); |
104 | if (chip == NULL) |
105 | return -ENOMEM; |
106 | |
107 | chip->spi_dev = spi_dev; |
108 | hwmon_dev = devm_hwmon_device_register_with_groups(dev: &spi_dev->dev, |
109 | name: spi_dev->modalias, |
110 | drvdata: chip, groups: ad7314_groups); |
111 | return PTR_ERR_OR_ZERO(ptr: hwmon_dev); |
112 | } |
113 | |
114 | static const struct spi_device_id ad7314_id[] = { |
115 | { "adt7301" , adt7301 }, |
116 | { "adt7302" , adt7302 }, |
117 | { "ad7314" , ad7314 }, |
118 | { } |
119 | }; |
120 | MODULE_DEVICE_TABLE(spi, ad7314_id); |
121 | |
122 | static struct spi_driver ad7314_driver = { |
123 | .driver = { |
124 | .name = "ad7314" , |
125 | }, |
126 | .probe = ad7314_probe, |
127 | .id_table = ad7314_id, |
128 | }; |
129 | |
130 | module_spi_driver(ad7314_driver); |
131 | |
132 | MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>" ); |
133 | MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital temperature sensor driver" ); |
134 | MODULE_LICENSE("GPL v2" ); |
135 | |