linux/drivers/iio/dac/ad5504.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

373 lines
8.5 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* AD5504, AD5501 High Voltage Digital to Analog Converter
*
* Copyright 2011 Analog Devices Inc.
*/
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/regulator/consumer.h>
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
#include <linux/iio/dac/ad5504.h>
#define AD5504_RES_MASK GENMASK(11, 0)
#define AD5504_CMD_READ BIT(15)
#define AD5504_CMD_WRITE 0
#define AD5504_ADDR(addr) ((addr) << 12)
/* Registers */
#define AD5504_ADDR_NOOP 0
#define AD5504_ADDR_DAC(x) ((x) + 1)
#define AD5504_ADDR_ALL_DAC 5
#define AD5504_ADDR_CTRL 7
/* Control Register */
#define AD5504_DAC_PWR(ch) ((ch) << 2)
#define AD5504_DAC_PWRDWN_MODE(mode) ((mode) << 6)
#define AD5504_DAC_PWRDN_20K 0
#define AD5504_DAC_PWRDN_3STATE 1
/**
* struct ad5446_state - driver instance specific data
* @spi: spi_device
* @reg: supply regulator
* @vref_mv: actual reference voltage used
* @pwr_down_mask power down mask
* @pwr_down_mode current power down mode
* @data: transfer buffer
*/
struct ad5504_state {
struct spi_device *spi;
struct regulator *reg;
unsigned short vref_mv;
unsigned pwr_down_mask;
unsigned pwr_down_mode;
__be16 data[2] ____cacheline_aligned;
};
/**
* ad5504_supported_device_ids:
*/
enum ad5504_supported_device_ids {
ID_AD5504,
ID_AD5501,
};
static int ad5504_spi_write(struct ad5504_state *st, u8 addr, u16 val)
{
st->data[0] = cpu_to_be16(AD5504_CMD_WRITE | AD5504_ADDR(addr) |
(val & AD5504_RES_MASK));
return spi_write(st->spi, &st->data[0], 2);
}
static int ad5504_spi_read(struct ad5504_state *st, u8 addr)
{
int ret;
struct spi_transfer t = {
.tx_buf = &st->data[0],
.rx_buf = &st->data[1],
.len = 2,
};
st->data[0] = cpu_to_be16(AD5504_CMD_READ | AD5504_ADDR(addr));
ret = spi_sync_transfer(st->spi, &t, 1);
if (ret < 0)
return ret;
return be16_to_cpu(st->data[1]) & AD5504_RES_MASK;
}
static int ad5504_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
struct ad5504_state *st = iio_priv(indio_dev);
int ret;
switch (m) {
case IIO_CHAN_INFO_RAW:
ret = ad5504_spi_read(st, chan->address);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = st->vref_mv;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
}
return -EINVAL;
}
static int ad5504_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long mask)
{
struct ad5504_state *st = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (val >= (1 << chan->scan_type.realbits) || val < 0)
return -EINVAL;
return ad5504_spi_write(st, chan->address, val);
default:
return -EINVAL;
}
}
static const char * const ad5504_powerdown_modes[] = {
"20kohm_to_gnd",
"three_state",
};
static int ad5504_get_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct ad5504_state *st = iio_priv(indio_dev);
return st->pwr_down_mode;
}
static int ad5504_set_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, unsigned int mode)
{
struct ad5504_state *st = iio_priv(indio_dev);
st->pwr_down_mode = mode;
return 0;
}
static const struct iio_enum ad5504_powerdown_mode_enum = {
.items = ad5504_powerdown_modes,
.num_items = ARRAY_SIZE(ad5504_powerdown_modes),
.get = ad5504_get_powerdown_mode,
.set = ad5504_set_powerdown_mode,
};
static ssize_t ad5504_read_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private, const struct iio_chan_spec *chan, char *buf)
{
struct ad5504_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n",
!(st->pwr_down_mask & (1 << chan->channel)));
}
static ssize_t ad5504_write_dac_powerdown(struct iio_dev *indio_dev,
uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
size_t len)
{
bool pwr_down;
int ret;
struct ad5504_state *st = iio_priv(indio_dev);
ret = strtobool(buf, &pwr_down);
if (ret)
return ret;
if (pwr_down)
st->pwr_down_mask |= (1 << chan->channel);
else
st->pwr_down_mask &= ~(1 << chan->channel);
ret = ad5504_spi_write(st, AD5504_ADDR_CTRL,
AD5504_DAC_PWRDWN_MODE(st->pwr_down_mode) |
AD5504_DAC_PWR(st->pwr_down_mask));
/* writes to the CTRL register must be followed by a NOOP */
ad5504_spi_write(st, AD5504_ADDR_NOOP, 0);
return ret ? ret : len;
}
static IIO_CONST_ATTR(temp0_thresh_rising_value, "110000");
static IIO_CONST_ATTR(temp0_thresh_rising_en, "1");
static struct attribute *ad5504_ev_attributes[] = {
&iio_const_attr_temp0_thresh_rising_value.dev_attr.attr,
&iio_const_attr_temp0_thresh_rising_en.dev_attr.attr,
NULL,
};
static const struct attribute_group ad5504_ev_attribute_group = {
.attrs = ad5504_ev_attributes,
};
static irqreturn_t ad5504_event_handler(int irq, void *private)
{
iio_push_event(private,
IIO_UNMOD_EVENT_CODE(IIO_TEMP,
0,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
iio_get_time_ns(private));
return IRQ_HANDLED;
}
static const struct iio_info ad5504_info = {
.write_raw = ad5504_write_raw,
.read_raw = ad5504_read_raw,
.event_attrs = &ad5504_ev_attribute_group,
};
static const struct iio_chan_spec_ext_info ad5504_ext_info[] = {
{
.name = "powerdown",
.read = ad5504_read_dac_powerdown,
.write = ad5504_write_dac_powerdown,
.shared = IIO_SEPARATE,
},
IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE,
&ad5504_powerdown_mode_enum),
IIO_ENUM_AVAILABLE("powerdown_mode", &ad5504_powerdown_mode_enum),
{ },
};
#define AD5504_CHANNEL(_chan) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.channel = (_chan), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = AD5504_ADDR_DAC(_chan), \
.scan_type = { \
.sign = 'u', \
.realbits = 12, \
.storagebits = 16, \
}, \
.ext_info = ad5504_ext_info, \
}
static const struct iio_chan_spec ad5504_channels[] = {
AD5504_CHANNEL(0),
AD5504_CHANNEL(1),
AD5504_CHANNEL(2),
AD5504_CHANNEL(3),
};
static int ad5504_probe(struct spi_device *spi)
{
struct ad5504_platform_data *pdata = spi->dev.platform_data;
struct iio_dev *indio_dev;
struct ad5504_state *st;
struct regulator *reg;
int ret, voltage_uv = 0;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
reg = devm_regulator_get(&spi->dev, "vcc");
if (!IS_ERR(reg)) {
ret = regulator_enable(reg);
if (ret)
return ret;
ret = regulator_get_voltage(reg);
if (ret < 0)
goto error_disable_reg;
voltage_uv = ret;
}
spi_set_drvdata(spi, indio_dev);
st = iio_priv(indio_dev);
if (voltage_uv)
st->vref_mv = voltage_uv / 1000;
else if (pdata)
st->vref_mv = pdata->vref_mv;
else
dev_warn(&spi->dev, "reference voltage unspecified\n");
st->reg = reg;
st->spi = spi;
indio_dev->name = spi_get_device_id(st->spi)->name;
indio_dev->info = &ad5504_info;
if (spi_get_device_id(st->spi)->driver_data == ID_AD5501)
indio_dev->num_channels = 1;
else
indio_dev->num_channels = 4;
indio_dev->channels = ad5504_channels;
indio_dev->modes = INDIO_DIRECT_MODE;
if (spi->irq) {
ret = devm_request_threaded_irq(&spi->dev, spi->irq,
NULL,
&ad5504_event_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
spi_get_device_id(st->spi)->name,
indio_dev);
if (ret)
goto error_disable_reg;
}
ret = iio_device_register(indio_dev);
if (ret)
goto error_disable_reg;
return 0;
error_disable_reg:
if (!IS_ERR(reg))
regulator_disable(reg);
return ret;
}
static int ad5504_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad5504_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return 0;
}
static const struct spi_device_id ad5504_id[] = {
{"ad5504", ID_AD5504},
{"ad5501", ID_AD5501},
{}
};
MODULE_DEVICE_TABLE(spi, ad5504_id);
static struct spi_driver ad5504_driver = {
.driver = {
.name = "ad5504",
},
.probe = ad5504_probe,
.remove = ad5504_remove,
.id_table = ad5504_id,
};
module_spi_driver(ad5504_driver);
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD5501/AD5501 DAC");
MODULE_LICENSE("GPL v2");