mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 18:43:33 +02:00
iio: adc: ad7768-1: add regulator to control VCM output
The VCM output voltage can be used as a common-mode voltage within the amplifier preconditioning circuits external to the AD7768-1. This change allows the user to configure VCM output using the regulator framework. Acked-by: Marcelo Schmitt <marcelo.schmitt@analog.com> Reviewed-by: David Lechner <dlechner@baylibre.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Jonathan Santos <Jonathan.Santos@analog.com> Link: https://patch.msgid.link/1f02312fdc4131168b194d59f4b1688dc68ea36e.1749569957.git.Jonathan.Santos@analog.com Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
This commit is contained in:
parent
1905e6c9ce
commit
96b6e814af
|
|
@ -354,6 +354,7 @@ config AD7766
|
|||
config AD7768_1
|
||||
tristate "Analog Devices AD7768-1 ADC driver"
|
||||
depends on SPI
|
||||
select REGULATOR
|
||||
select REGMAP_SPI
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGER
|
||||
|
|
|
|||
|
|
@ -13,9 +13,11 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
|
|
@ -82,6 +84,12 @@
|
|||
#define AD7768_CONV_MODE_MSK GENMASK(2, 0)
|
||||
#define AD7768_CONV_MODE(x) FIELD_PREP(AD7768_CONV_MODE_MSK, x)
|
||||
|
||||
/* AD7768_REG_ANALOG2 */
|
||||
#define AD7768_REG_ANALOG2_VCM_MSK GENMASK(2, 0)
|
||||
#define AD7768_REG_ANALOG2_VCM(x) FIELD_PREP(AD7768_REG_ANALOG2_VCM_MSK, (x))
|
||||
|
||||
#define AD7768_VCM_OFF 0x07
|
||||
|
||||
enum ad7768_conv_mode {
|
||||
AD7768_CONTINUOUS,
|
||||
AD7768_ONE_SHOT,
|
||||
|
|
@ -159,6 +167,8 @@ struct ad7768_state {
|
|||
struct regmap *regmap;
|
||||
struct regmap *regmap24;
|
||||
struct regulator *vref;
|
||||
struct regulator_dev *vcm_rdev;
|
||||
unsigned int vcm_output_sel;
|
||||
struct clk *mclk;
|
||||
unsigned int mclk_freq;
|
||||
unsigned int samp_freq;
|
||||
|
|
@ -662,6 +672,150 @@ static int ad7768_triggered_buffer_alloc(struct iio_dev *indio_dev)
|
|||
&ad7768_buffer_ops);
|
||||
}
|
||||
|
||||
static int ad7768_vcm_enable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct iio_dev *indio_dev = rdev_get_drvdata(rdev);
|
||||
struct ad7768_state *st = iio_priv(indio_dev);
|
||||
int ret, regval;
|
||||
|
||||
if (!iio_device_claim_direct(indio_dev))
|
||||
return -EBUSY;
|
||||
|
||||
/* To enable, set the last selected output */
|
||||
regval = AD7768_REG_ANALOG2_VCM(st->vcm_output_sel + 1);
|
||||
ret = regmap_update_bits(st->regmap, AD7768_REG_ANALOG2,
|
||||
AD7768_REG_ANALOG2_VCM_MSK, regval);
|
||||
iio_device_release_direct(indio_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad7768_vcm_disable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct iio_dev *indio_dev = rdev_get_drvdata(rdev);
|
||||
struct ad7768_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
if (!iio_device_claim_direct(indio_dev))
|
||||
return -EBUSY;
|
||||
|
||||
ret = regmap_update_bits(st->regmap, AD7768_REG_ANALOG2,
|
||||
AD7768_REG_ANALOG2_VCM_MSK, AD7768_VCM_OFF);
|
||||
iio_device_release_direct(indio_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad7768_vcm_is_enabled(struct regulator_dev *rdev)
|
||||
{
|
||||
struct iio_dev *indio_dev = rdev_get_drvdata(rdev);
|
||||
struct ad7768_state *st = iio_priv(indio_dev);
|
||||
int ret, val;
|
||||
|
||||
if (!iio_device_claim_direct(indio_dev))
|
||||
return -EBUSY;
|
||||
|
||||
ret = regmap_read(st->regmap, AD7768_REG_ANALOG2, &val);
|
||||
iio_device_release_direct(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return FIELD_GET(AD7768_REG_ANALOG2_VCM_MSK, val) != AD7768_VCM_OFF;
|
||||
}
|
||||
|
||||
static int ad7768_set_voltage_sel(struct regulator_dev *rdev,
|
||||
unsigned int selector)
|
||||
{
|
||||
unsigned int regval = AD7768_REG_ANALOG2_VCM(selector + 1);
|
||||
struct iio_dev *indio_dev = rdev_get_drvdata(rdev);
|
||||
struct ad7768_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
if (!iio_device_claim_direct(indio_dev))
|
||||
return -EBUSY;
|
||||
|
||||
ret = regmap_update_bits(st->regmap, AD7768_REG_ANALOG2,
|
||||
AD7768_REG_ANALOG2_VCM_MSK, regval);
|
||||
iio_device_release_direct(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
st->vcm_output_sel = selector;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7768_get_voltage_sel(struct regulator_dev *rdev)
|
||||
{
|
||||
struct iio_dev *indio_dev = rdev_get_drvdata(rdev);
|
||||
struct ad7768_state *st = iio_priv(indio_dev);
|
||||
int ret, val;
|
||||
|
||||
if (!iio_device_claim_direct(indio_dev))
|
||||
return -EBUSY;
|
||||
|
||||
ret = regmap_read(st->regmap, AD7768_REG_ANALOG2, &val);
|
||||
iio_device_release_direct(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val = FIELD_GET(AD7768_REG_ANALOG2_VCM_MSK, val);
|
||||
|
||||
return clamp(val, 1, rdev->desc->n_voltages) - 1;
|
||||
}
|
||||
|
||||
static const struct regulator_ops vcm_regulator_ops = {
|
||||
.enable = ad7768_vcm_enable,
|
||||
.disable = ad7768_vcm_disable,
|
||||
.is_enabled = ad7768_vcm_is_enabled,
|
||||
.list_voltage = regulator_list_voltage_table,
|
||||
.set_voltage_sel = ad7768_set_voltage_sel,
|
||||
.get_voltage_sel = ad7768_get_voltage_sel,
|
||||
};
|
||||
|
||||
static const unsigned int vcm_voltage_table[] = {
|
||||
2500000,
|
||||
2050000,
|
||||
1650000,
|
||||
1900000,
|
||||
1100000,
|
||||
900000,
|
||||
};
|
||||
|
||||
static const struct regulator_desc vcm_desc = {
|
||||
.name = "ad7768-1-vcm",
|
||||
.of_match = "vcm-output",
|
||||
.regulators_node = "regulators",
|
||||
.n_voltages = ARRAY_SIZE(vcm_voltage_table),
|
||||
.volt_table = vcm_voltage_table,
|
||||
.ops = &vcm_regulator_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int ad7768_register_regulators(struct device *dev, struct ad7768_state *st,
|
||||
struct iio_dev *indio_dev)
|
||||
{
|
||||
struct regulator_config config = {
|
||||
.dev = dev,
|
||||
.driver_data = indio_dev,
|
||||
};
|
||||
int ret;
|
||||
|
||||
/* Disable the regulator before registering it */
|
||||
ret = regmap_update_bits(st->regmap, AD7768_REG_ANALOG2,
|
||||
AD7768_REG_ANALOG2_VCM_MSK, AD7768_VCM_OFF);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
st->vcm_rdev = devm_regulator_register(dev, &vcm_desc, &config);
|
||||
if (IS_ERR(st->vcm_rdev))
|
||||
return dev_err_probe(dev, PTR_ERR(st->vcm_rdev),
|
||||
"failed to register VCM regulator\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7768_probe(struct spi_device *spi)
|
||||
{
|
||||
struct ad7768_state *st;
|
||||
|
|
@ -726,6 +880,11 @@ static int ad7768_probe(struct spi_device *spi)
|
|||
indio_dev->info = &ad7768_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
/* Register VCM output regulator */
|
||||
ret = ad7768_register_regulators(&spi->dev, st, indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ad7768_setup(st);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "AD7768 setup failed\n");
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user