提交 83e416f4 编写于 作者: M Michael Hennerich 提交者: Greg Kroah-Hartman

staging: iio: adc: Replace, rewrite ad7745 from scratch.

The existing ad7745 driver didn't conform with the IIO spec for such devices.
It was way simpler to rewrite the existing driver, than actually fixing it.
Signed-off-by: NMichael Hennerich <michael.hennerich@analog.com>
Signed-off-by: NJonathan Cameron <jic23@cam.ac.uk>
Signed-off-by: NGreg Kroah-Hartman <gregkh@suse.de>
上级 5bf8ebc5
......@@ -144,7 +144,7 @@ config AD7793
To compile this driver as a module, choose M here: the
module will be called AD7793.
config AD7745
config AD7746
tristate "Analog Devices AD7745, AD7746 AD7747 capacitive sensor driver"
depends on I2C
help
......
......@@ -33,7 +33,7 @@ obj-$(CONFIG_AD7150) += ad7150.o
obj-$(CONFIG_AD7152) += ad7152.o
obj-$(CONFIG_AD7291) += ad7291.o
obj-$(CONFIG_AD7314) += ad7314.o
obj-$(CONFIG_AD7745) += ad7745.o
obj-$(CONFIG_AD7746) += ad7746.o
obj-$(CONFIG_AD7780) += ad7780.o
obj-$(CONFIG_AD7793) += ad7793.o
obj-$(CONFIG_AD7816) += ad7816.o
......
/*
* AD774X capacitive sensor driver supporting AD7745/6/7
*
* Copyright 2010 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/list.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include "../iio.h"
#include "../sysfs.h"
/*
* AD774X registers definition
*/
#define AD774X_STATUS 0
#define AD774X_STATUS_RDY (1 << 2)
#define AD774X_STATUS_RDYVT (1 << 1)
#define AD774X_STATUS_RDYCAP (1 << 0)
#define AD774X_CAP_DATA_HIGH 1
#define AD774X_CAP_DATA_MID 2
#define AD774X_CAP_DATA_LOW 3
#define AD774X_VT_DATA_HIGH 4
#define AD774X_VT_DATA_MID 5
#define AD774X_VT_DATA_LOW 6
#define AD774X_CAP_SETUP 7
#define AD774X_VT_SETUP 8
#define AD774X_EXEC_SETUP 9
#define AD774X_CFG 10
#define AD774X_CAPDACA 11
#define AD774X_CAPDACB 12
#define AD774X_CAPDAC_EN (1 << 7)
#define AD774X_CAP_OFFH 13
#define AD774X_CAP_OFFL 14
#define AD774X_CAP_GAINH 15
#define AD774X_CAP_GAINL 16
#define AD774X_VOLT_GAINH 17
#define AD774X_VOLT_GAINL 18
#define AD774X_MAX_CONV_MODE 6
/*
* struct ad774x_chip_info - chip specifc information
*/
struct ad774x_chip_info {
struct i2c_client *client;
bool inter;
u16 cap_offs; /* Capacitive offset */
u16 cap_gain; /* Capacitive gain calibration */
u16 volt_gain; /* Voltage gain calibration */
u8 cap_setup;
u8 vt_setup;
u8 exec_setup;
char *conversion_mode;
};
struct ad774x_conversion_mode {
char *name;
u8 reg_cfg;
};
static struct ad774x_conversion_mode
ad774x_conv_mode_table[AD774X_MAX_CONV_MODE] = {
{ "idle", 0 },
{ "continuous-conversion", 1 },
{ "single-conversion", 2 },
{ "power-down", 3 },
{ "offset-calibration", 5 },
{ "gain-calibration", 6 },
};
/*
* ad774x register access by I2C
*/
static int ad774x_i2c_read(struct ad774x_chip_info *chip, u8 reg, u8 *data, int len)
{
struct i2c_client *client = chip->client;
int ret;
ret = i2c_master_send(client, &reg, 1);
if (ret < 0) {
dev_err(&client->dev, "I2C write error\n");
return ret;
}
ret = i2c_master_recv(client, data, len);
if (ret < 0) {
dev_err(&client->dev, "I2C read error\n");
return ret;
}
return ret;
}
static int ad774x_i2c_write(struct ad774x_chip_info *chip, u8 reg, u8 data)
{
struct i2c_client *client = chip->client;
int ret;
u8 tx[2] = {
reg,
data,
};
ret = i2c_master_send(client, tx, 2);
if (ret < 0)
dev_err(&client->dev, "I2C write error\n");
return ret;
}
/*
* sysfs nodes
*/
#define IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(_show) \
IIO_DEVICE_ATTR(available_conversion_modes, S_IRUGO, _show, NULL, 0)
#define IIO_DEV_ATTR_CONVERSION_MODE(_mode, _show, _store) \
IIO_DEVICE_ATTR(conversion_mode, _mode, _show, _store, 0)
#define IIO_DEV_ATTR_CAP_SETUP(_mode, _show, _store) \
IIO_DEVICE_ATTR(in_capacitance_setup, _mode, _show, _store, 0)
#define IIO_DEV_ATTR_VT_SETUP(_mode, _show, _store) \
IIO_DEVICE_ATTR(in_voltage0_setup, _mode, _show, _store, 0)
#define IIO_DEV_ATTR_EXEC_SETUP(_mode, _show, _store) \
IIO_DEVICE_ATTR(exec_setup, _mode, _show, _store, 0)
#define IIO_DEV_ATTR_VOLT_GAIN(_mode, _show, _store) \
IIO_DEVICE_ATTR(in_voltage0_gain, _mode, _show, _store, 0)
#define IIO_DEV_ATTR_CAP_OFFS(_mode, _show, _store) \
IIO_DEVICE_ATTR(in_capacitance_offs, _mode, _show, _store, 0)
#define IIO_DEV_ATTR_CAP_GAIN(_mode, _show, _store) \
IIO_DEVICE_ATTR(in_capacitance_gain, _mode, _show, _store, 0)
#define IIO_DEV_ATTR_CAP_DATA(_show) \
IIO_DEVICE_ATTR(in_capacitance0_raw, S_IRUGO, _show, NULL, 0)
#define IIO_DEV_ATTR_VT_DATA(_show) \
IIO_DEVICE_ATTR(in_voltage0_raw, S_IRUGO, _show, NULL, 0)
static ssize_t ad774x_show_conversion_modes(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int i;
int len = 0;
for (i = 0; i < AD774X_MAX_CONV_MODE; i++)
len += sprintf(buf + len, "%s ", ad774x_conv_mode_table[i].name);
len += sprintf(buf + len, "\n");
return len;
}
static IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(ad774x_show_conversion_modes);
static ssize_t ad774x_show_conversion_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct ad774x_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "%s\n", chip->conversion_mode);
}
static ssize_t ad774x_store_conversion_mode(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct ad774x_chip_info *chip = iio_priv(dev_info);
u8 cfg;
int i;
ad774x_i2c_read(chip, AD774X_CFG, &cfg, 1);
for (i = 0; i < AD774X_MAX_CONV_MODE; i++) {
if (strncmp(buf, ad774x_conv_mode_table[i].name,
strlen(ad774x_conv_mode_table[i].name) - 1) == 0) {
chip->conversion_mode = ad774x_conv_mode_table[i].name;
cfg |= 0x18 | ad774x_conv_mode_table[i].reg_cfg;
ad774x_i2c_write(chip, AD774X_CFG, cfg);
return len;
}
}
dev_err(dev, "not supported conversion mode\n");
return -EINVAL;
}
static IIO_DEV_ATTR_CONVERSION_MODE(S_IRUGO | S_IWUSR,
ad774x_show_conversion_mode,
ad774x_store_conversion_mode);
static ssize_t ad774x_show_dac_value(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct ad774x_chip_info *chip = iio_priv(dev_info);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
u8 data;
ad774x_i2c_read(chip, this_attr->address, &data, 1);
return sprintf(buf, "%02x\n", data & 0x7F);
}
static ssize_t ad774x_store_dac_value(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct ad774x_chip_info *chip = iio_priv(dev_info);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
unsigned long data;
int ret;
ret = strict_strtoul(buf, 10, &data);
if (!ret) {
ad774x_i2c_write(chip, this_attr->address,
(data ? AD774X_CAPDAC_EN : 0) | (data & 0x7F));
return len;
}
return -EINVAL;
}
static IIO_DEVICE_ATTR(out_capacitance0_raw, S_IRUGO | S_IWUSR,
ad774x_show_dac_value,
ad774x_store_dac_value,
AD774X_CAPDACA);
static IIO_DEVICE_ATTR(out_capacitance1_raw, S_IRUGO | S_IWUSR,
ad774x_show_dac_value,
ad774x_store_dac_value,
AD774X_CAPDACB);
static ssize_t ad774x_show_cap_setup(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct ad774x_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "0x%02x\n", chip->cap_setup);
}
static ssize_t ad774x_store_cap_setup(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct ad774x_chip_info *chip = iio_priv(dev_info);
unsigned long data;
int ret;
ret = strict_strtoul(buf, 10, &data);
if ((!ret) && (data < 0x100)) {
ad774x_i2c_write(chip, AD774X_CAP_SETUP, data);
chip->cap_setup = data;
return len;
}
return -EINVAL;
}
static IIO_DEV_ATTR_CAP_SETUP(S_IRUGO | S_IWUSR,
ad774x_show_cap_setup,
ad774x_store_cap_setup);
static ssize_t ad774x_show_vt_setup(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct ad774x_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "0x%02x\n", chip->vt_setup);
}
static ssize_t ad774x_store_vt_setup(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct ad774x_chip_info *chip = iio_priv(dev_info);
unsigned long data;
int ret;
ret = strict_strtoul(buf, 10, &data);
if ((!ret) && (data < 0x100)) {
ad774x_i2c_write(chip, AD774X_VT_SETUP, data);
chip->vt_setup = data;
return len;
}
return -EINVAL;
}
static IIO_DEV_ATTR_VT_SETUP(S_IRUGO | S_IWUSR,
ad774x_show_vt_setup,
ad774x_store_vt_setup);
static ssize_t ad774x_show_exec_setup(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct ad774x_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "0x%02x\n", chip->exec_setup);
}
static ssize_t ad774x_store_exec_setup(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct ad774x_chip_info *chip = iio_priv(dev_info);
unsigned long data;
int ret;
ret = strict_strtoul(buf, 10, &data);
if ((!ret) && (data < 0x100)) {
ad774x_i2c_write(chip, AD774X_EXEC_SETUP, data);
chip->exec_setup = data;
return len;
}
return -EINVAL;
}
static IIO_DEV_ATTR_EXEC_SETUP(S_IRUGO | S_IWUSR,
ad774x_show_exec_setup,
ad774x_store_exec_setup);
static ssize_t ad774x_show_volt_gain(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct ad774x_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "%d\n", chip->volt_gain);
}
static ssize_t ad774x_store_volt_gain(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct ad774x_chip_info *chip = iio_priv(dev_info);
unsigned long data;
int ret;
ret = strict_strtoul(buf, 10, &data);
if ((!ret) && (data < 0x10000)) {
ad774x_i2c_write(chip, AD774X_VOLT_GAINH, data >> 8);
ad774x_i2c_write(chip, AD774X_VOLT_GAINL, data);
chip->volt_gain = data;
return len;
}
return -EINVAL;
}
static IIO_DEV_ATTR_VOLT_GAIN(S_IRUGO | S_IWUSR,
ad774x_show_volt_gain,
ad774x_store_volt_gain);
static ssize_t ad774x_show_cap_data(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct ad774x_chip_info *chip = iio_priv(dev_info);
unsigned long data;
char tmp[3];
ad774x_i2c_read(chip, AD774X_CAP_DATA_HIGH, tmp, 3);
data = ((int)tmp[0] << 16) | ((int)tmp[1] << 8) | (int)tmp[2];
return sprintf(buf, "%ld\n", data);
}
static IIO_DEV_ATTR_CAP_DATA(ad774x_show_cap_data);
static ssize_t ad774x_show_vt_data(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct ad774x_chip_info *chip = iio_priv(dev_info);
unsigned long data;
char tmp[3];
ad774x_i2c_read(chip, AD774X_VT_DATA_HIGH, tmp, 3);
data = ((int)tmp[0] << 16) | ((int)tmp[1] << 8) | (int)tmp[2];
return sprintf(buf, "%ld\n", data);
}
static IIO_DEV_ATTR_VT_DATA(ad774x_show_vt_data);
static ssize_t ad774x_show_cap_offs(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct ad774x_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "%d\n", chip->cap_offs);
}
static ssize_t ad774x_store_cap_offs(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct ad774x_chip_info *chip = iio_priv(dev_info);
unsigned long data;
int ret;
ret = strict_strtoul(buf, 10, &data);
if ((!ret) && (data < 0x10000)) {
ad774x_i2c_write(chip, AD774X_CAP_OFFH, data >> 8);
ad774x_i2c_write(chip, AD774X_CAP_OFFL, data);
chip->cap_offs = data;
return len;
}
return -EINVAL;
}
static IIO_DEV_ATTR_CAP_OFFS(S_IRUGO | S_IWUSR,
ad774x_show_cap_offs,
ad774x_store_cap_offs);
static ssize_t ad774x_show_cap_gain(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct ad774x_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "%d\n", chip->cap_gain);
}
static ssize_t ad774x_store_cap_gain(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct ad774x_chip_info *chip = iio_priv(dev_info);
unsigned long data;
int ret;
ret = strict_strtoul(buf, 10, &data);
if ((!ret) && (data < 0x10000)) {
ad774x_i2c_write(chip, AD774X_CAP_GAINH, data >> 8);
ad774x_i2c_write(chip, AD774X_CAP_GAINL, data);
chip->cap_gain = data;
return len;
}
return -EINVAL;
}
static IIO_DEV_ATTR_CAP_GAIN(S_IRUGO | S_IWUSR,
ad774x_show_cap_gain,
ad774x_store_cap_gain);
static struct attribute *ad774x_attributes[] = {
&iio_dev_attr_available_conversion_modes.dev_attr.attr,
&iio_dev_attr_conversion_mode.dev_attr.attr,
&iio_dev_attr_in_capacitance_setup.dev_attr.attr,
&iio_dev_attr_in_voltage0_setup.dev_attr.attr,
&iio_dev_attr_exec_setup.dev_attr.attr,
&iio_dev_attr_in_capacitance_offs.dev_attr.attr,
&iio_dev_attr_in_capacitance_gain.dev_attr.attr,
&iio_dev_attr_in_voltage0_gain.dev_attr.attr,
&iio_dev_attr_in_voltage0_raw.dev_attr.attr,
&iio_dev_attr_in_capacitance0_raw.dev_attr.attr,
&iio_dev_attr_out_capacitance0_raw.dev_attr.attr,
&iio_dev_attr_out_capacitance1_raw.dev_attr.attr,
NULL,
};
static const struct attribute_group ad774x_attribute_group = {
.attrs = ad774x_attributes,
};
/*
* data ready events
*/
#define IIO_EVENT_CODE_CAP_RDY 0
#define IIO_EVENT_CODE_VT_RDY 1
#define IIO_EVENT_ATTR_CAP_RDY_SH(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(cap_rdy, _evlist, _show, _store, _mask)
#define IIO_EVENT_ATTR_VT_RDY_SH(_evlist, _show, _store, _mask) \
IIO_EVENT_ATTR_SH(vt_rdy, _evlist, _show, _store, _mask)
static irqreturn_t ad774x_event_handler(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct ad774x_chip_info *chip = iio_priv(indio_dev);
u8 int_status;
ad774x_i2c_read(chip, AD774X_STATUS, &int_status, 1);
if (int_status & AD774X_STATUS_RDYCAP)
iio_push_event(indio_dev,
IIO_EVENT_CODE_CAP_RDY,
iio_get_time_ns());
if (int_status & AD774X_STATUS_RDYVT)
iio_push_event(indio_dev,
IIO_EVENT_CODE_VT_RDY,
iio_get_time_ns());
return IRQ_HANDLED;
}
static IIO_CONST_ATTR(cap_rdy_en, "1");
static IIO_CONST_ATTR(vt_rdy_en, "1");
static struct attribute *ad774x_event_attributes[] = {
&iio_const_attr_cap_rdy_en.dev_attr.attr,
&iio_const_attr_vt_rdy_en.dev_attr.attr,
NULL,
};
static struct attribute_group ad774x_event_attribute_group = {
.attrs = ad774x_event_attributes,
.name = "events",
};
static const struct iio_info ad774x_info = {
.attrs = &ad774x_event_attribute_group,
.event_attrs = &ad774x_event_attribute_group,
.driver_module = THIS_MODULE,
};
/*
* device probe and remove
*/
static int __devinit ad774x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct ad774x_chip_info *chip;
struct iio_dev *indio_dev;
indio_dev = iio_allocate_device(sizeof(*chip));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
}
chip = iio_priv(indio_dev);
/* this is only used for device removal purposes */
i2c_set_clientdata(client, indio_dev);
chip->client = client;
/* Establish that the iio_dev is a child of the i2c device */
indio_dev->name = id->name;
indio_dev->dev.parent = &client->dev;
indio_dev->info = &ad774x_info;
indio_dev->modes = INDIO_DIRECT_MODE;
if (client->irq) {
ret = request_threaded_irq(client->irq,
NULL,
&ad774x_event_handler,
IRQF_TRIGGER_FALLING,
"ad774x",
indio_dev);
if (ret)
goto error_free_dev;
}
ret = iio_device_register(indio_dev);
if (ret)
goto error_free_irq;
dev_err(&client->dev, "%s capacitive sensor registered, irq: %d\n", id->name, client->irq);
return 0;
error_free_irq:
free_irq(client->irq, indio_dev);
error_free_dev:
iio_free_device(indio_dev);
error_ret:
return ret;
}
static int __devexit ad774x_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
if (client->irq)
free_irq(client->irq, indio_dev);
iio_device_unregister(indio_dev);
return 0;
}
static const struct i2c_device_id ad774x_id[] = {
{ "ad7745", 0 },
{ "ad7746", 0 },
{ "ad7747", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, ad774x_id);
static struct i2c_driver ad774x_driver = {
.driver = {
.name = "ad774x",
},
.probe = ad774x_probe,
.remove = __devexit_p(ad774x_remove),
.id_table = ad774x_id,
};
static __init int ad774x_init(void)
{
return i2c_add_driver(&ad774x_driver);
}
static __exit void ad774x_exit(void)
{
i2c_del_driver(&ad774x_driver);
}
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
MODULE_DESCRIPTION("Analog Devices ad7745/6/7 capacitive sensor driver");
MODULE_LICENSE("GPL v2");
module_init(ad774x_init);
module_exit(ad774x_exit);
此差异已折叠。
/*
* AD7746 capacitive sensor driver supporting AD7745, AD7746 and AD7747
*
* Copyright 2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#ifndef IIO_CDC_AD7746_H_
#define IIO_CDC_AD7746_H_
/*
* TODO: struct ad7746_platform_data needs to go into include/linux/iio
*/
#define AD7466_EXCLVL_0 0 /* +-VDD/8 */
#define AD7466_EXCLVL_1 1 /* +-VDD/4 */
#define AD7466_EXCLVL_2 2 /* +-VDD * 3/8 */
#define AD7466_EXCLVL_3 3 /* +-VDD/2 */
struct ad7746_platform_data {
unsigned char exclvl; /*Excitation Voltage Level */
bool exca_en; /* enables EXCA pin as the excitation output */
bool exca_inv_en; /* enables /EXCA pin as the excitation output */
bool excb_en; /* enables EXCB pin as the excitation output */
bool excb_inv_en; /* enables /EXCB pin as the excitation output */
};
#endif /* IIO_CDC_AD7746_H_ */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册