Skip to content

Commit e0c70b8

Browse files
pthomastorvalds
authored andcommitted
hwmon: add TI ads7871 a/d converter driver
[akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Paul Thomas <pthomas8589@gmail.com> Cc: Jonathan Cameron <jic23@cam.ac.uk> Cc: Jean Delvare <khali@linux-fr.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 4a70a41 commit e0c70b8

File tree

3 files changed

+263
-0
lines changed

3 files changed

+263
-0
lines changed

drivers/hwmon/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,15 @@ config SENSORS_ADS7828
802802
This driver can also be built as a module. If so, the module
803803
will be called ads7828.
804804

805+
config SENSORS_ADS7871
806+
tristate "Texas Instruments ADS7871 A/D converter"
807+
depends on SPI
808+
help
809+
If you say yes here you get support for TI ADS7871 & ADS7870
810+
811+
This driver can also be built as a module. If so, the module
812+
will be called ads7871.
813+
805814
config SENSORS_AMC6821
806815
tristate "Texas Instruments AMC6821"
807816
depends on I2C && EXPERIMENTAL

drivers/hwmon/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o
2929
obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o
3030
obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
3131
obj-$(CONFIG_SENSORS_ADS7828) += ads7828.o
32+
obj-$(CONFIG_SENSORS_ADS7871) += ads7871.o
3233
obj-$(CONFIG_SENSORS_ADT7411) += adt7411.o
3334
obj-$(CONFIG_SENSORS_ADT7462) += adt7462.o
3435
obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o

drivers/hwmon/ads7871.c

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
/*
2+
* ads7871 - driver for TI ADS7871 A/D converter
3+
*
4+
* Copyright (c) 2010 Paul Thomas <pthomas8589@gmail.com>
5+
*
6+
* This program is distributed in the hope that it will be useful,
7+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
8+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9+
* GNU General Public License for more details.
10+
*
11+
* This program is free software; you can redistribute it and/or modify
12+
* it under the terms of the GNU General Public License version 2 or
13+
* later as publishhed by the Free Software Foundation.
14+
*
15+
* You need to have something like this in struct spi_board_info
16+
* {
17+
* .modalias = "ads7871",
18+
* .max_speed_hz = 2*1000*1000,
19+
* .chip_select = 0,
20+
* .bus_num = 1,
21+
* },
22+
*/
23+
24+
/*From figure 18 in the datasheet*/
25+
/*Register addresses*/
26+
#define REG_LS_BYTE 0 /*A/D Output Data, LS Byte*/
27+
#define REG_MS_BYTE 1 /*A/D Output Data, MS Byte*/
28+
#define REG_PGA_VALID 2 /*PGA Valid Register*/
29+
#define REG_AD_CONTROL 3 /*A/D Control Register*/
30+
#define REG_GAIN_MUX 4 /*Gain/Mux Register*/
31+
#define REG_IO_STATE 5 /*Digital I/O State Register*/
32+
#define REG_IO_CONTROL 6 /*Digital I/O Control Register*/
33+
#define REG_OSC_CONTROL 7 /*Rev/Oscillator Control Register*/
34+
#define REG_SER_CONTROL 24 /*Serial Interface Control Register*/
35+
#define REG_ID 31 /*ID Register*/
36+
37+
/*From figure 17 in the datasheet
38+
* These bits get ORed with the address to form
39+
* the instruction byte */
40+
/*Instruction Bit masks*/
41+
#define INST_MODE_bm (1<<7)
42+
#define INST_READ_bm (1<<6)
43+
#define INST_16BIT_bm (1<<5)
44+
45+
/*From figure 18 in the datasheet*/
46+
/*bit masks for Rev/Oscillator Control Register*/
47+
#define MUX_CNV_bv 7
48+
#define MUX_CNV_bm (1<<MUX_CNV_bv)
49+
#define MUX_M3_bm (1<<3) /*M3 selects single ended*/
50+
#define MUX_G_bv 4 /*allows for reg = (gain << MUX_G_bv) | ...*/
51+
52+
/*From figure 18 in the datasheet*/
53+
/*bit masks for Rev/Oscillator Control Register*/
54+
#define OSC_OSCR_bm (1<<5)
55+
#define OSC_OSCE_bm (1<<4)
56+
#define OSC_REFE_bm (1<<3)
57+
#define OSC_BUFE_bm (1<<2)
58+
#define OSC_R2V_bm (1<<1)
59+
#define OSC_RBG_bm (1<<0)
60+
61+
#include <linux/module.h>
62+
#include <linux/init.h>
63+
#include <linux/spi/spi.h>
64+
#include <linux/hwmon.h>
65+
#include <linux/hwmon-sysfs.h>
66+
#include <linux/err.h>
67+
#include <linux/mutex.h>
68+
#include <linux/delay.h>
69+
70+
#define DEVICE_NAME "ads7871"
71+
72+
struct ads7871_data {
73+
struct device *hwmon_dev;
74+
struct mutex update_lock;
75+
};
76+
77+
static int ads7871_read_reg8(struct spi_device *spi, int reg)
78+
{
79+
int ret;
80+
reg = reg | INST_READ_bm;
81+
ret = spi_w8r8(spi, reg);
82+
return ret;
83+
}
84+
85+
static int ads7871_read_reg16(struct spi_device *spi, int reg)
86+
{
87+
int ret;
88+
reg = reg | INST_READ_bm | INST_16BIT_bm;
89+
ret = spi_w8r16(spi, reg);
90+
return ret;
91+
}
92+
93+
static int ads7871_write_reg8(struct spi_device *spi, int reg, u8 val)
94+
{
95+
u8 tmp[2] = {reg, val};
96+
return spi_write(spi, tmp, sizeof(tmp));
97+
}
98+
99+
static ssize_t show_voltage(struct device *dev,
100+
struct device_attribute *da, char *buf)
101+
{
102+
struct spi_device *spi = to_spi_device(dev);
103+
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
104+
int ret, val, i = 0;
105+
uint8_t channel, mux_cnv;
106+
107+
channel = attr->index;
108+
/*TODO: add support for conversions
109+
*other than single ended with a gain of 1*/
110+
/*MUX_M3_bm forces single ended*/
111+
/*This is also where the gain of the PGA would be set*/
112+
ads7871_write_reg8(spi, REG_GAIN_MUX,
113+
(MUX_CNV_bm | MUX_M3_bm | channel));
114+
115+
ret = ads7871_read_reg8(spi, REG_GAIN_MUX);
116+
mux_cnv = ((ret & MUX_CNV_bm)>>MUX_CNV_bv);
117+
/*on 400MHz arm9 platform the conversion
118+
*is already done when we do this test*/
119+
while ((i < 2) && mux_cnv) {
120+
i++;
121+
ret = ads7871_read_reg8(spi, REG_GAIN_MUX);
122+
mux_cnv = ((ret & MUX_CNV_bm)>>MUX_CNV_bv);
123+
msleep_interruptible(1);
124+
}
125+
126+
if (mux_cnv == 0) {
127+
val = ads7871_read_reg16(spi, REG_LS_BYTE);
128+
/*result in volts*10000 = (val/8192)*2.5*10000*/
129+
val = ((val>>2) * 25000) / 8192;
130+
return sprintf(buf, "%d\n", val);
131+
} else {
132+
return -1;
133+
}
134+
}
135+
136+
static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_voltage, NULL, 0);
137+
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_voltage, NULL, 1);
138+
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_voltage, NULL, 2);
139+
static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_voltage, NULL, 3);
140+
static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_voltage, NULL, 4);
141+
static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_voltage, NULL, 5);
142+
static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_voltage, NULL, 6);
143+
static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_voltage, NULL, 7);
144+
145+
static struct attribute *ads7871_attributes[] = {
146+
&sensor_dev_attr_in0_input.dev_attr.attr,
147+
&sensor_dev_attr_in1_input.dev_attr.attr,
148+
&sensor_dev_attr_in2_input.dev_attr.attr,
149+
&sensor_dev_attr_in3_input.dev_attr.attr,
150+
&sensor_dev_attr_in4_input.dev_attr.attr,
151+
&sensor_dev_attr_in5_input.dev_attr.attr,
152+
&sensor_dev_attr_in6_input.dev_attr.attr,
153+
&sensor_dev_attr_in7_input.dev_attr.attr,
154+
NULL
155+
};
156+
157+
static const struct attribute_group ads7871_group = {
158+
.attrs = ads7871_attributes,
159+
};
160+
161+
static int __devinit ads7871_probe(struct spi_device *spi)
162+
{
163+
int status, ret, err = 0;
164+
uint8_t val;
165+
struct ads7871_data *pdata;
166+
167+
dev_dbg(&spi->dev, "probe\n");
168+
169+
pdata = kzalloc(sizeof(struct ads7871_data), GFP_KERNEL);
170+
if (!pdata) {
171+
err = -ENOMEM;
172+
goto exit;
173+
}
174+
175+
status = sysfs_create_group(&spi->dev.kobj, &ads7871_group);
176+
if (status < 0)
177+
goto error_free;
178+
179+
pdata->hwmon_dev = hwmon_device_register(&spi->dev);
180+
if (IS_ERR(pdata->hwmon_dev)) {
181+
err = PTR_ERR(pdata->hwmon_dev);
182+
goto error_remove;
183+
}
184+
185+
spi_set_drvdata(spi, pdata);
186+
187+
/* Configure the SPI bus */
188+
spi->mode = (SPI_MODE_0);
189+
spi->bits_per_word = 8;
190+
spi_setup(spi);
191+
192+
ads7871_write_reg8(spi, REG_SER_CONTROL, 0);
193+
ads7871_write_reg8(spi, REG_AD_CONTROL, 0);
194+
195+
val = (OSC_OSCR_bm | OSC_OSCE_bm | OSC_REFE_bm | OSC_BUFE_bm);
196+
ads7871_write_reg8(spi, REG_OSC_CONTROL, val);
197+
ret = ads7871_read_reg8(spi, REG_OSC_CONTROL);
198+
199+
dev_dbg(&spi->dev, "REG_OSC_CONTROL write:%x, read:%x\n", val, ret);
200+
/*because there is no other error checking on an SPI bus
201+
we need to make sure we really have a chip*/
202+
if (val != ret) {
203+
err = -ENODEV;
204+
goto error_remove;
205+
}
206+
207+
return 0;
208+
209+
error_remove:
210+
sysfs_remove_group(&spi->dev.kobj, &ads7871_group);
211+
error_free:
212+
kfree(pdata);
213+
exit:
214+
return err;
215+
}
216+
217+
static int __devexit ads7871_remove(struct spi_device *spi)
218+
{
219+
struct ads7871_data *pdata = spi_get_drvdata(spi);
220+
221+
hwmon_device_unregister(pdata->hwmon_dev);
222+
sysfs_remove_group(&spi->dev.kobj, &ads7871_group);
223+
kfree(pdata);
224+
return 0;
225+
}
226+
227+
static struct spi_driver ads7871_driver = {
228+
.driver = {
229+
.name = DEVICE_NAME,
230+
.bus = &spi_bus_type,
231+
.owner = THIS_MODULE,
232+
},
233+
234+
.probe = ads7871_probe,
235+
.remove = __devexit_p(ads7871_remove),
236+
};
237+
238+
static int __init ads7871_init(void)
239+
{
240+
return spi_register_driver(&ads7871_driver);
241+
}
242+
243+
static void __exit ads7871_exit(void)
244+
{
245+
spi_unregister_driver(&ads7871_driver);
246+
}
247+
248+
module_init(ads7871_init);
249+
module_exit(ads7871_exit);
250+
251+
MODULE_AUTHOR("Paul Thomas <pthomas8589@gmail.com>");
252+
MODULE_DESCRIPTION("TI ADS7871 A/D driver");
253+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)