Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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
 31enum ad7314_variant {
 32	adt7301,
 33	adt7302,
 34	ad7314,
 35};
 36
 37struct ad7314_data {
 38	struct spi_device	*spi_dev;
 39	struct device		*hwmon_dev;
 40	u16 rx ____cacheline_aligned;
 41};
 42
 43static 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
 56static 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
 90static 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
 96static DEVICE_ATTR(name, S_IRUGO, ad7314_show_name, NULL);
 97static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
 98			  ad7314_show_temperature, NULL, 0);
 99
100static struct attribute *ad7314_attributes[] = {
101	&dev_attr_name.attr,
102	&sensor_dev_attr_temp1_input.dev_attr.attr,
103	NULL,
104};
105
106static const struct attribute_group ad7314_group = {
107	.attrs = ad7314_attributes,
108};
109
110static 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	spi_set_drvdata(spi_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;
133error_remove_group:
134	sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
135	return ret;
136}
137
138static int ad7314_remove(struct spi_device *spi_dev)
139{
140	struct ad7314_data *chip = spi_get_drvdata(spi_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
148static const struct spi_device_id ad7314_id[] = {
149	{ "adt7301", adt7301 },
150	{ "adt7302", adt7302 },
151	{ "ad7314", ad7314 },
152	{ }
153};
154MODULE_DEVICE_TABLE(spi, ad7314_id);
155
156static 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
166module_spi_driver(ad7314_driver);
167
168MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
169MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital temperature sensor driver");
170MODULE_LICENSE("GPL v2");