#include <linux/clk.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/iio/backend.h>
#include <linux/iio/iio.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pwm.h>
#include <linux/regulator/consumer.h>
#include <linux/units.h>
#define AD7625_INTERNAL_REF_MV 4096
#define AD7960_MAX_NBW_FREQ (2 * MEGA)
struct ad7625_timing_spec {
unsigned int conv_high_ns;
unsigned int conv_msb_ns;
};
struct ad7625_chip_info {
const char *name;
const unsigned int max_sample_freq_hz;
const struct ad7625_timing_spec *timing_spec;
const struct iio_chan_spec chan_spec;
const bool has_power_down_state;
const bool has_bandwidth_control;
const bool has_internal_vref;
};
#define AD7625_CHAN_SPEC(_bits) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.differential = 1, \
.channel = 0, \
.channel2 = 1, \
.info_mask_separate = BIT(IIO_CHAN_INFO_SCALE), \
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.scan_index = 0, \
.scan_type.sign = 's', \
.scan_type.storagebits = (_bits) > 16 ? 32 : 16, \
.scan_type.realbits = (_bits), \
}
struct ad7625_state {
const struct ad7625_chip_info *info;
struct iio_backend *back;
u32 ref_clk_rate_hz;
struct pwm_device *clk_gate_pwm;
struct pwm_device *cnv_pwm;
struct pwm_waveform clk_gate_wf;
struct pwm_waveform cnv_wf;
unsigned int vref_mv;
u32 sampling_freq_hz;
struct gpio_desc *en_gpios[4];
bool can_power_down;
bool can_refin;
bool can_ref_4v096;
bool can_narrow_bandwidth;
bool can_wide_bandwidth;
bool can_ref_5v;
bool can_snooze;
bool can_test_pattern;
bool have_refin;
};
static const struct ad7625_timing_spec ad7625_timing_spec = {
.conv_high_ns = 40,
.conv_msb_ns = 145,
};
static const struct ad7625_timing_spec ad7626_timing_spec = {
.conv_high_ns = 40,
.conv_msb_ns = 80,
};
static const struct ad7625_timing_spec ad7960_timing_spec = {
.conv_high_ns = 80,
.conv_msb_ns = 0,
};
static const struct ad7625_chip_info ad7625_chip_info = {
.name = "ad7625",
.max_sample_freq_hz = 6 * MEGA,
.timing_spec = &ad7625_timing_spec,
.chan_spec = AD7625_CHAN_SPEC(16),
.has_power_down_state = false,
.has_bandwidth_control = false,
.has_internal_vref = true,
};
static const struct ad7625_chip_info ad7626_chip_info = {
.name = "ad7626",
.max_sample_freq_hz = 10 * MEGA,
.timing_spec = &ad7626_timing_spec,
.chan_spec = AD7625_CHAN_SPEC(16),
.has_power_down_state = true,
.has_bandwidth_control = false,
.has_internal_vref = true,
};
static const struct ad7625_chip_info ad7960_chip_info = {
.name = "ad7960",
.max_sample_freq_hz = 5 * MEGA,
.timing_spec = &ad7960_timing_spec,
.chan_spec = AD7625_CHAN_SPEC(18),
.has_power_down_state = true,
.has_bandwidth_control = true,
.has_internal_vref = false,
};
static const struct ad7625_chip_info ad7961_chip_info = {
.name = "ad7961",
.max_sample_freq_hz = 5 * MEGA,
.timing_spec = &ad7960_timing_spec,
.chan_spec = AD7625_CHAN_SPEC(16),
.has_power_down_state = true,
.has_bandwidth_control = true,
.has_internal_vref = false,
};
enum ad7960_mode {
AD7960_MODE_POWER_DOWN,
AD7960_MODE_SNOOZE,
AD7960_MODE_NARROW_BANDWIDTH,
AD7960_MODE_WIDE_BANDWIDTH,
AD7960_MODE_TEST_PATTERN,
};
static int ad7625_set_sampling_freq(struct ad7625_state *st, u32 freq)
{
u32 target;
struct pwm_waveform clk_gate_wf = { }, cnv_wf = { };
int ret;
target = DIV_ROUND_UP(NSEC_PER_SEC, freq);
cnv_wf.period_length_ns = clamp(target, 100, 10 * KILO);
cnv_wf.duty_length_ns = st->info->timing_spec->conv_high_ns;
ret = pwm_round_waveform_might_sleep(st->cnv_pwm, &cnv_wf);
if (ret)
return ret;
clk_gate_wf.period_length_ns = cnv_wf.period_length_ns;
clk_gate_wf.duty_length_ns = DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC *
st->info->chan_spec.scan_type.realbits,
st->ref_clk_rate_hz);
clk_gate_wf.duty_offset_ns = st->info->timing_spec->conv_msb_ns;
ret = pwm_round_waveform_might_sleep(st->clk_gate_pwm, &clk_gate_wf);
if (ret)
return ret;
st->cnv_wf = cnv_wf;
st->clk_gate_wf = clk_gate_wf;
target = DIV_ROUND_CLOSEST(st->ref_clk_rate_hz, freq);
st->sampling_freq_hz = DIV_ROUND_CLOSEST(st->ref_clk_rate_hz,
target);
return 0;
}
static int ad7625_read_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
int *val, int *val2, long info)
{
struct ad7625_state *st = iio_priv(indio_dev);
switch (info) {
case IIO_CHAN_INFO_SAMP_FREQ:
*val = st->sampling_freq_hz;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = st->vref_mv;
*val2 = chan->scan_type.realbits - 1;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
}
static int ad7625_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long info)
{
struct ad7625_state *st = iio_priv(indio_dev);
int ret;
switch (info) {
case IIO_CHAN_INFO_SAMP_FREQ:
if (!iio_device_claim_direct(indio_dev))
return -EBUSY;
ret = ad7625_set_sampling_freq(st, val);
iio_device_release_direct(indio_dev);
return ret;
default:
return -EINVAL;
}
}
static int ad7625_parse_mode(struct device *dev, struct ad7625_state *st,
int num_gpios)
{
bool en_always_on[4], en_always_off[4];
bool en_may_be_on[4], en_may_be_off[4];
char en_gpio_buf[4];
char always_on_buf[18];
int i;
for (i = 0; i < num_gpios; i++) {
snprintf(en_gpio_buf, sizeof(en_gpio_buf), "en%d", i);
snprintf(always_on_buf, sizeof(always_on_buf),
"adi,en%d-always-on", i);
st->en_gpios[i] = devm_gpiod_get_optional(dev, en_gpio_buf,
GPIOD_OUT_LOW);
if (IS_ERR(st->en_gpios[i]))
return dev_err_probe(dev, PTR_ERR(st->en_gpios[i]),
"failed to get EN%d GPIO\n", i);
en_always_on[i] = device_property_read_bool(dev, always_on_buf);
if (st->en_gpios[i] && en_always_on[i])
return dev_err_probe(dev, -EINVAL,
"cannot have adi,en%d-always-on and en%d-gpios\n", i, i);
en_may_be_off[i] = !en_always_on[i];
en_may_be_on[i] = en_always_on[i] || st->en_gpios[i];
en_always_off[i] = !en_always_on[i] && !st->en_gpios[i];
}
st->can_power_down = en_may_be_off[1] && en_may_be_off[0] &&
st->info->has_power_down_state;
st->can_refin = en_may_be_off[1] && en_may_be_on[0];
st->can_ref_4v096 = en_may_be_on[1] && en_may_be_off[0];
if (num_gpios == 2)
return 0;
if (en_always_on[3] && en_always_on[2] &&
en_always_off[1] && en_always_off[0])
return dev_err_probe(dev, -EINVAL,
"EN GPIOs set to invalid mode 0b1100\n");
st->can_ref_5v = st->can_refin;
st->can_narrow_bandwidth = en_may_be_on[2];
st->can_wide_bandwidth = en_may_be_off[2];
st->can_snooze = en_may_be_on[1] && en_may_be_on[0];
st->can_test_pattern = en_may_be_off[3] && en_may_be_on[2] &&
en_may_be_off[1] && en_may_be_off[0];
return 0;
}
static void ad7625_set_en_gpios_for_vref(struct ad7625_state *st,
bool have_refin, int ref_mv)
{
if (have_refin || ref_mv == 5000) {
gpiod_set_value_cansleep(st->en_gpios[1], 0);
gpiod_set_value_cansleep(st->en_gpios[0], 1);
} else if (ref_mv == 4096) {
gpiod_set_value_cansleep(st->en_gpios[1], 1);
gpiod_set_value_cansleep(st->en_gpios[0], 0);
} else {
gpiod_set_value_cansleep(st->en_gpios[1], 1);
gpiod_set_value_cansleep(st->en_gpios[0], 1);
}
}
static int ad7960_set_mode(struct ad7625_state *st, enum ad7960_mode mode,
bool have_refin, int ref_mv)
{
switch (mode) {
case AD7960_MODE_POWER_DOWN:
if (!st->can_power_down)
return -EINVAL;
gpiod_set_value_cansleep(st->en_gpios[2], 0);
gpiod_set_value_cansleep(st->en_gpios[1], 0);
gpiod_set_value_cansleep(st->en_gpios[0], 0);
return 0;
case AD7960_MODE_SNOOZE:
if (!st->can_snooze)
return -EINVAL;
gpiod_set_value_cansleep(st->en_gpios[1], 1);
gpiod_set_value_cansleep(st->en_gpios[0], 1);
return 0;
case AD7960_MODE_NARROW_BANDWIDTH:
if (!st->can_narrow_bandwidth)
return -EINVAL;
gpiod_set_value_cansleep(st->en_gpios[2], 1);
ad7625_set_en_gpios_for_vref(st, have_refin, ref_mv);
return 0;
case AD7960_MODE_WIDE_BANDWIDTH:
if (!st->can_wide_bandwidth)
return -EINVAL;
gpiod_set_value_cansleep(st->en_gpios[2], 0);
ad7625_set_en_gpios_for_vref(st, have_refin, ref_mv);
return 0;
case AD7960_MODE_TEST_PATTERN:
if (!st->can_test_pattern)
return -EINVAL;
gpiod_set_value_cansleep(st->en_gpios[3], 0);
gpiod_set_value_cansleep(st->en_gpios[2], 1);
gpiod_set_value_cansleep(st->en_gpios[1], 0);
gpiod_set_value_cansleep(st->en_gpios[0], 0);
return 0;
default:
return -EINVAL;
}
}
static int ad7625_buffer_preenable(struct iio_dev *indio_dev)
{
struct ad7625_state *st = iio_priv(indio_dev);
int ret;
ret = pwm_set_waveform_might_sleep(st->cnv_pwm, &st->cnv_wf, false);
if (ret)
return ret;
ret = pwm_set_waveform_might_sleep(st->clk_gate_pwm,
&st->clk_gate_wf, false);
if (ret) {
pwm_disable(st->cnv_pwm);
return ret;
}
return 0;
}
static int ad7625_buffer_postdisable(struct iio_dev *indio_dev)
{
struct ad7625_state *st = iio_priv(indio_dev);
pwm_disable(st->clk_gate_pwm);
pwm_disable(st->cnv_pwm);
return 0;
}
static const struct iio_info ad7625_info = {
.read_raw = ad7625_read_raw,
.write_raw = ad7625_write_raw,
};
static const struct iio_buffer_setup_ops ad7625_buffer_setup_ops = {
.preenable = &ad7625_buffer_preenable,
.postdisable = &ad7625_buffer_postdisable,
};
static int devm_ad7625_pwm_get(struct device *dev,
struct ad7625_state *st)
{
struct clk *ref_clk;
u32 ref_clk_rate_hz;
st->cnv_pwm = devm_pwm_get(dev, "cnv");
if (IS_ERR(st->cnv_pwm))
return dev_err_probe(dev, PTR_ERR(st->cnv_pwm),
"failed to get cnv pwm\n");
pwm_disable(st->cnv_pwm);
st->clk_gate_pwm = devm_pwm_get(dev, "clk_gate");
if (IS_ERR(st->clk_gate_pwm))
return dev_err_probe(dev, PTR_ERR(st->clk_gate_pwm),
"failed to get clk_gate pwm\n");
pwm_disable(st->clk_gate_pwm);
ref_clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(ref_clk))
return dev_err_probe(dev, PTR_ERR(ref_clk),
"failed to get ref_clk\n");
ref_clk_rate_hz = clk_get_rate(ref_clk);
if (!ref_clk_rate_hz)
return dev_err_probe(dev, -EINVAL,
"failed to get ref_clk rate\n");
st->ref_clk_rate_hz = ref_clk_rate_hz;
return 0;
}
static int devm_ad7625_regulator_setup(struct device *dev,
struct ad7625_state *st)
{
static const char * const regulator_names[] = { "vio", "vdd2", "vdd1" };
int ret, ref_mv;
ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names),
regulator_names);
if (ret)
return ret;
ret = devm_regulator_get_enable_read_voltage(dev, "ref");
if (ret < 0 && ret != -ENODEV)
return dev_err_probe(dev, ret, "failed to get REF voltage\n");
ref_mv = ret == -ENODEV ? 0 : ret / 1000;
ret = devm_regulator_get_enable_optional(dev, "refin");
if (ret < 0 && ret != -ENODEV)
return dev_err_probe(dev, ret, "failed to get REFIN voltage\n");
st->have_refin = ret != -ENODEV;
if (st->have_refin && !st->can_refin)
return dev_err_probe(dev, -EINVAL,
"REFIN provided in unsupported mode\n");
if (!st->info->has_internal_vref && !st->have_refin && !ref_mv)
return dev_err_probe(dev, -EINVAL,
"Need either REFIN or REF\n");
if (st->have_refin && ref_mv)
return dev_err_probe(dev, -EINVAL,
"cannot have both REFIN and REF supplies\n");
if (ref_mv == 4096 && !st->can_ref_4v096)
return dev_err_probe(dev, -EINVAL,
"REF is 4.096V in unsupported mode\n");
if (ref_mv == 5000 && !st->can_ref_5v)
return dev_err_probe(dev, -EINVAL,
"REF is 5V in unsupported mode\n");
st->vref_mv = ref_mv ?: AD7625_INTERNAL_REF_MV;
return 0;
}
static int ad7625_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct iio_dev *indio_dev;
struct ad7625_state *st;
int ret;
u32 default_sample_freq;
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
st->info = device_get_match_data(dev);
if (!st->info)
return dev_err_probe(dev, -EINVAL, "no chip info\n");
if (device_property_read_bool(dev, "adi,no-dco"))
return dev_err_probe(dev, -EINVAL,
"self-clocked mode not supported\n");
if (st->info->has_bandwidth_control)
ret = ad7625_parse_mode(dev, st, 4);
else
ret = ad7625_parse_mode(dev, st, 2);
if (ret)
return ret;
ret = devm_ad7625_regulator_setup(dev, st);
if (ret)
return ret;
if (!st->info->has_bandwidth_control) {
ad7625_set_en_gpios_for_vref(st, st->have_refin, st->vref_mv);
} else {
if (st->can_wide_bandwidth) {
ret = ad7960_set_mode(st, AD7960_MODE_WIDE_BANDWIDTH,
st->have_refin, st->vref_mv);
} else if (st->can_narrow_bandwidth) {
ret = ad7960_set_mode(st, AD7960_MODE_NARROW_BANDWIDTH,
st->have_refin, st->vref_mv);
} else {
return dev_err_probe(dev, -EINVAL,
"couldn't set device to wide or narrow bandwidth modes\n");
}
if (ret)
return dev_err_probe(dev, -EINVAL,
"failed to set EN pins\n");
}
ret = devm_ad7625_pwm_get(dev, st);
if (ret)
return ret;
indio_dev->channels = &st->info->chan_spec;
indio_dev->num_channels = 1;
indio_dev->name = st->info->name;
indio_dev->info = &ad7625_info;
indio_dev->setup_ops = &ad7625_buffer_setup_ops;
st->back = devm_iio_backend_get(dev, NULL);
if (IS_ERR(st->back))
return dev_err_probe(dev, PTR_ERR(st->back),
"failed to get IIO backend\n");
ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev);
if (ret)
return ret;
ret = devm_iio_backend_enable(dev, st->back);
if (ret)
return ret;
default_sample_freq = st->info->max_sample_freq_hz;
if (st->info->has_bandwidth_control && !st->can_wide_bandwidth)
default_sample_freq = AD7960_MAX_NBW_FREQ;
ret = ad7625_set_sampling_freq(st, default_sample_freq);
if (ret)
dev_err_probe(dev, ret,
"failed to set valid sampling frequency\n");
return devm_iio_device_register(dev, indio_dev);
}
static const struct of_device_id ad7625_of_match[] = {
{ .compatible = "adi,ad7625", .data = &ad7625_chip_info },
{ .compatible = "adi,ad7626", .data = &ad7626_chip_info },
{ .compatible = "adi,ad7960", .data = &ad7960_chip_info },
{ .compatible = "adi,ad7961", .data = &ad7961_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, ad7625_of_match);
static const struct platform_device_id ad7625_device_ids[] = {
{ .name = "ad7625", .driver_data = (kernel_ulong_t)&ad7625_chip_info },
{ .name = "ad7626", .driver_data = (kernel_ulong_t)&ad7626_chip_info },
{ .name = "ad7960", .driver_data = (kernel_ulong_t)&ad7960_chip_info },
{ .name = "ad7961", .driver_data = (kernel_ulong_t)&ad7961_chip_info },
{ }
};
MODULE_DEVICE_TABLE(platform, ad7625_device_ids);
static struct platform_driver ad7625_driver = {
.probe = ad7625_probe,
.driver = {
.name = "ad7625",
.of_match_table = ad7625_of_match,
},
.id_table = ad7625_device_ids,
};
module_platform_driver(ad7625_driver);
MODULE_AUTHOR("Trevor Gamblin <tgamblin@baylibre.com>");
MODULE_DESCRIPTION("Analog Devices AD7625 ADC");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS("IIO_BACKEND");