linux-stable/drivers/staging/iio/adc/ad7816.c
Alexandru Ardelean d3be83244c iio: remove explicit IIO device parent assignment
This patch applies the semantic patch:
@@
expression I, P, SP;
@@
   I = devm_iio_device_alloc(P, SP);
   ...
-  I->dev.parent = P;

It updates 302 files and does 307 deletions.
This semantic patch also removes some comments like
'/* Establish that the iio_dev is a child of the i2c device */'

But this is is only done in case where the block is left empty.

The patch does not seem to cover all cases. It looks like in some cases a
different variable is used in some cases to assign the parent, but it
points to the same reference.
In other cases, the block covered by ... may be just too big to be covered
by the semantic patch.

However, this looks pretty good as well, as it does cover a big bulk of the
drivers that should remove the parent assignment.

Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
2020-06-14 11:49:59 +01:00

451 lines
11 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* AD7816 digital temperature sensor driver supporting AD7816/7/8
*
* Copyright 2010 Analog Devices Inc.
*/
#include <linux/interrupt.h>
#include <linux/gpio/consumer.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/list.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
/*
* AD7816 config masks
*/
#define AD7816_FULL 0x1
#define AD7816_PD 0x2
#define AD7816_CS_MASK 0x7
#define AD7816_CS_MAX 0x4
/*
* AD7816 temperature masks
*/
#define AD7816_VALUE_OFFSET 6
#define AD7816_BOUND_VALUE_BASE 0x8
#define AD7816_BOUND_VALUE_MIN -95
#define AD7816_BOUND_VALUE_MAX 152
#define AD7816_TEMP_FLOAT_OFFSET 2
#define AD7816_TEMP_FLOAT_MASK 0x3
/*
* struct ad7816_chip_info - chip specific information
*/
struct ad7816_chip_info {
kernel_ulong_t id;
struct spi_device *spi_dev;
struct gpio_desc *rdwr_pin;
struct gpio_desc *convert_pin;
struct gpio_desc *busy_pin;
u8 oti_data[AD7816_CS_MAX + 1];
u8 channel_id; /* 0 always be temperature */
u8 mode;
};
enum ad7816_type {
ID_AD7816,
ID_AD7817,
ID_AD7818,
};
/*
* ad7816 data access by SPI
*/
static int ad7816_spi_read(struct ad7816_chip_info *chip, u16 *data)
{
struct spi_device *spi_dev = chip->spi_dev;
int ret;
__be16 buf;
gpiod_set_value(chip->rdwr_pin, 1);
gpiod_set_value(chip->rdwr_pin, 0);
ret = spi_write(spi_dev, &chip->channel_id, sizeof(chip->channel_id));
if (ret < 0) {
dev_err(&spi_dev->dev, "SPI channel setting error\n");
return ret;
}
gpiod_set_value(chip->rdwr_pin, 1);
if (chip->mode == AD7816_PD) { /* operating mode 2 */
gpiod_set_value(chip->convert_pin, 1);
gpiod_set_value(chip->convert_pin, 0);
} else { /* operating mode 1 */
gpiod_set_value(chip->convert_pin, 0);
gpiod_set_value(chip->convert_pin, 1);
}
if (chip->id == ID_AD7816 || chip->id == ID_AD7817) {
while (gpiod_get_value(chip->busy_pin))
cpu_relax();
}
gpiod_set_value(chip->rdwr_pin, 0);
gpiod_set_value(chip->rdwr_pin, 1);
ret = spi_read(spi_dev, &buf, sizeof(*data));
if (ret < 0) {
dev_err(&spi_dev->dev, "SPI data read error\n");
return ret;
}
*data = be16_to_cpu(buf);
return ret;
}
static int ad7816_spi_write(struct ad7816_chip_info *chip, u8 data)
{
struct spi_device *spi_dev = chip->spi_dev;
int ret;
gpiod_set_value(chip->rdwr_pin, 1);
gpiod_set_value(chip->rdwr_pin, 0);
ret = spi_write(spi_dev, &data, sizeof(data));
if (ret < 0)
dev_err(&spi_dev->dev, "SPI oti data write error\n");
return ret;
}
static ssize_t ad7816_show_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7816_chip_info *chip = iio_priv(indio_dev);
if (chip->mode)
return sprintf(buf, "power-save\n");
return sprintf(buf, "full\n");
}
static ssize_t ad7816_store_mode(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7816_chip_info *chip = iio_priv(indio_dev);
if (strcmp(buf, "full")) {
gpiod_set_value(chip->rdwr_pin, 1);
chip->mode = AD7816_FULL;
} else {
gpiod_set_value(chip->rdwr_pin, 0);
chip->mode = AD7816_PD;
}
return len;
}
static IIO_DEVICE_ATTR(mode, 0644,
ad7816_show_mode,
ad7816_store_mode,
0);
static ssize_t ad7816_show_available_modes(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "full\npower-save\n");
}
static IIO_DEVICE_ATTR(available_modes, 0444, ad7816_show_available_modes,
NULL, 0);
static ssize_t ad7816_show_channel(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7816_chip_info *chip = iio_priv(indio_dev);
return sprintf(buf, "%d\n", chip->channel_id);
}
static ssize_t ad7816_store_channel(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7816_chip_info *chip = iio_priv(indio_dev);
unsigned long data;
int ret;
ret = kstrtoul(buf, 10, &data);
if (ret)
return ret;
if (data > AD7816_CS_MAX && data != AD7816_CS_MASK) {
dev_err(&chip->spi_dev->dev, "Invalid channel id %lu for %s.\n",
data, indio_dev->name);
return -EINVAL;
} else if (strcmp(indio_dev->name, "ad7818") == 0 && data > 1) {
dev_err(&chip->spi_dev->dev,
"Invalid channel id %lu for ad7818.\n", data);
return -EINVAL;
} else if (strcmp(indio_dev->name, "ad7816") == 0 && data > 0) {
dev_err(&chip->spi_dev->dev,
"Invalid channel id %lu for ad7816.\n", data);
return -EINVAL;
}
chip->channel_id = data;
return len;
}
static IIO_DEVICE_ATTR(channel, 0644,
ad7816_show_channel,
ad7816_store_channel,
0);
static ssize_t ad7816_show_value(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7816_chip_info *chip = iio_priv(indio_dev);
u16 data;
s8 value;
int ret;
ret = ad7816_spi_read(chip, &data);
if (ret)
return -EIO;
data >>= AD7816_VALUE_OFFSET;
if (chip->channel_id == 0) {
value = (s8)((data >> AD7816_TEMP_FLOAT_OFFSET) - 103);
data &= AD7816_TEMP_FLOAT_MASK;
if (value < 0)
data = BIT(AD7816_TEMP_FLOAT_OFFSET) - data;
return sprintf(buf, "%d.%.2d\n", value, data * 25);
}
return sprintf(buf, "%u\n", data);
}
static IIO_DEVICE_ATTR(value, 0444, ad7816_show_value, NULL, 0);
static struct attribute *ad7816_attributes[] = {
&iio_dev_attr_available_modes.dev_attr.attr,
&iio_dev_attr_mode.dev_attr.attr,
&iio_dev_attr_channel.dev_attr.attr,
&iio_dev_attr_value.dev_attr.attr,
NULL,
};
static const struct attribute_group ad7816_attribute_group = {
.attrs = ad7816_attributes,
};
/*
* temperature bound events
*/
#define IIO_EVENT_CODE_AD7816_OTI IIO_UNMOD_EVENT_CODE(IIO_TEMP, \
0, \
IIO_EV_TYPE_THRESH, \
IIO_EV_DIR_FALLING)
static irqreturn_t ad7816_event_handler(int irq, void *private)
{
iio_push_event(private, IIO_EVENT_CODE_AD7816_OTI,
iio_get_time_ns(private));
return IRQ_HANDLED;
}
static ssize_t ad7816_show_oti(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7816_chip_info *chip = iio_priv(indio_dev);
int value;
if (chip->channel_id > AD7816_CS_MAX) {
dev_err(dev, "Invalid oti channel id %d.\n", chip->channel_id);
return -EINVAL;
} else if (chip->channel_id == 0) {
value = AD7816_BOUND_VALUE_MIN +
(chip->oti_data[chip->channel_id] -
AD7816_BOUND_VALUE_BASE);
return sprintf(buf, "%d\n", value);
}
return sprintf(buf, "%u\n", chip->oti_data[chip->channel_id]);
}
static inline ssize_t ad7816_set_oti(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7816_chip_info *chip = iio_priv(indio_dev);
long value;
u8 data;
int ret;
ret = kstrtol(buf, 10, &value);
if (ret)
return ret;
if (chip->channel_id > AD7816_CS_MAX) {
dev_err(dev, "Invalid oti channel id %d.\n", chip->channel_id);
return -EINVAL;
} else if (chip->channel_id == 0) {
if (value < AD7816_BOUND_VALUE_MIN ||
value > AD7816_BOUND_VALUE_MAX)
return -EINVAL;
data = (u8)(value - AD7816_BOUND_VALUE_MIN +
AD7816_BOUND_VALUE_BASE);
} else {
if (value < AD7816_BOUND_VALUE_BASE || value > 255)
return -EINVAL;
data = (u8)value;
}
ret = ad7816_spi_write(chip, data);
if (ret)
return -EIO;
chip->oti_data[chip->channel_id] = data;
return len;
}
static IIO_DEVICE_ATTR(oti, 0644,
ad7816_show_oti, ad7816_set_oti, 0);
static struct attribute *ad7816_event_attributes[] = {
&iio_dev_attr_oti.dev_attr.attr,
NULL,
};
static const struct attribute_group ad7816_event_attribute_group = {
.attrs = ad7816_event_attributes,
.name = "events",
};
static const struct iio_info ad7816_info = {
.attrs = &ad7816_attribute_group,
.event_attrs = &ad7816_event_attribute_group,
};
/*
* device probe and remove
*/
static int ad7816_probe(struct spi_device *spi_dev)
{
struct ad7816_chip_info *chip;
struct iio_dev *indio_dev;
int i, ret;
indio_dev = devm_iio_device_alloc(&spi_dev->dev, sizeof(*chip));
if (!indio_dev)
return -ENOMEM;
chip = iio_priv(indio_dev);
/* this is only used for device removal purposes */
dev_set_drvdata(&spi_dev->dev, indio_dev);
chip->spi_dev = spi_dev;
for (i = 0; i <= AD7816_CS_MAX; i++)
chip->oti_data[i] = 203;
chip->id = spi_get_device_id(spi_dev)->driver_data;
chip->rdwr_pin = devm_gpiod_get(&spi_dev->dev, "rdwr", GPIOD_OUT_HIGH);
if (IS_ERR(chip->rdwr_pin)) {
ret = PTR_ERR(chip->rdwr_pin);
dev_err(&spi_dev->dev, "Failed to request rdwr GPIO: %d\n",
ret);
return ret;
}
chip->convert_pin = devm_gpiod_get(&spi_dev->dev, "convert",
GPIOD_OUT_HIGH);
if (IS_ERR(chip->convert_pin)) {
ret = PTR_ERR(chip->convert_pin);
dev_err(&spi_dev->dev, "Failed to request convert GPIO: %d\n",
ret);
return ret;
}
if (chip->id == ID_AD7816 || chip->id == ID_AD7817) {
chip->busy_pin = devm_gpiod_get(&spi_dev->dev, "busy",
GPIOD_IN);
if (IS_ERR(chip->busy_pin)) {
ret = PTR_ERR(chip->busy_pin);
dev_err(&spi_dev->dev, "Failed to request busy GPIO: %d\n",
ret);
return ret;
}
}
indio_dev->name = spi_get_device_id(spi_dev)->name;
indio_dev->info = &ad7816_info;
indio_dev->modes = INDIO_DIRECT_MODE;
if (spi_dev->irq) {
/* Only low trigger is supported in ad7816/7/8 */
ret = devm_request_threaded_irq(&spi_dev->dev, spi_dev->irq,
NULL,
&ad7816_event_handler,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
indio_dev->name,
indio_dev);
if (ret)
return ret;
}
ret = devm_iio_device_register(&spi_dev->dev, indio_dev);
if (ret)
return ret;
dev_info(&spi_dev->dev, "%s temperature sensor and ADC registered.\n",
indio_dev->name);
return 0;
}
static const struct of_device_id ad7816_of_match[] = {
{ .compatible = "adi,ad7816", },
{ .compatible = "adi,ad7817", },
{ .compatible = "adi,ad7818", },
{ }
};
MODULE_DEVICE_TABLE(of, ad7816_of_match);
static const struct spi_device_id ad7816_id[] = {
{ "ad7816", ID_AD7816 },
{ "ad7817", ID_AD7817 },
{ "ad7818", ID_AD7818 },
{}
};
MODULE_DEVICE_TABLE(spi, ad7816_id);
static struct spi_driver ad7816_driver = {
.driver = {
.name = "ad7816",
.of_match_table = ad7816_of_match,
},
.probe = ad7816_probe,
.id_table = ad7816_id,
};
module_spi_driver(ad7816_driver);
MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7816/7/8 digital temperature sensor driver");
MODULE_LICENSE("GPL v2");