Skip to content

Commit

Permalink
iio: adc: ad4630: update to use pwm waveforms API
Browse files Browse the repository at this point in the history
Reserve setting of PWMs for ad4630_buffer_preenable(), and
ad4630_update_sample_fetch_trigger(). Disable them with pwm_disable() in
two places: ad4630_pwm_get() (so that the PWM outputs aren't on after
initialization) and ad4630_buffer_postdisable().

Some instances of the driver state had the const qualifiers removed
since they now actually need to be modified.

Also change AD4630_TQUIET_CNV_DELAY_PS to AD4630_TQUIET_CNV_DELAY_NS and
the nearest appropriate value, so that we don't have to round when
calculating PWM offsets now.

Signed-off-by: Trevor Gamblin <[email protected]>
  • Loading branch information
threexc committed Dec 13, 2024
1 parent 4bb71b7 commit 8ea2bf4
Showing 1 changed file with 66 additions and 51 deletions.
117 changes: 66 additions & 51 deletions drivers/iio/adc/ad4630.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,10 @@
/* sequence starting with "1 0 1" to enable reg access */
#define AD4630_REG_ACCESS 0x2000
/* Sampling timing */
#define AD4630_TQUIET_CNV_DELAY_PS 9800
#define AD4630_MAX_RATE_1_LANE 1750000
#define AD4630_MAX_RATE 2000000
/* Datasheet says 9.8ns, so use the closest integer value */
#define AD4630_TQUIET_CNV_DELAY_NS 10

#define AD4630_MAX_CHANNEL_NR 3
#define AD4630_VREF_MIN (4096 * MILLI)
Expand Down Expand Up @@ -192,6 +193,8 @@ struct ad4630_state {
struct regulator_bulk_data regulators[3];
struct pwm_device *conv_trigger;
struct pwm_device *fetch_trigger;
struct pwm_waveform conv_wf;
struct pwm_waveform fetch_wf;
struct gpio_descs *pga_gpios;
struct spi_device *spi;
struct regmap *regmap;
Expand Down Expand Up @@ -258,10 +261,7 @@ static int ad4630_reg_access(struct iio_dev *indio_dev, unsigned int reg,

static void ad4630_get_sampling_freq(const struct ad4630_state *st, int *freq)
{
struct pwm_state conversion_state;

pwm_get_state(st->conv_trigger, &conversion_state);
*freq = DIV_ROUND_CLOSEST_ULL(NANO, conversion_state.period);
*freq = DIV_ROUND_CLOSEST_ULL(NANO, st->conv_wf.period_length_ns);
}

static int ad4630_get_chan_gain(struct iio_dev *indio_dev, int ch, int *val)
Expand Down Expand Up @@ -370,26 +370,24 @@ static int ad4630_read_avail(struct iio_dev *indio_dev,
}
}

static int __ad4630_set_sampling_freq(const struct ad4630_state *st, unsigned int freq)
static int __ad4630_set_sampling_freq(struct ad4630_state *st, unsigned int freq)
{
struct pwm_state conv_state = {
.duty_cycle = 10,
.enabled = true,
}, fetch_state = {
.duty_cycle = 10,
.enabled = true,
struct pwm_waveform conv_wf = {
.duty_length_ns = 10,
}, fetch_wf = {
.duty_length_ns = 10,
};
int ret;

conv_state.period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, freq);
ret = pwm_apply_state(st->conv_trigger, &conv_state);
conv_wf.period_length_ns = DIV_ROUND_CLOSEST(NSEC_PER_SEC, freq);
ret = pwm_round_waveform_might_sleep(st->conv_trigger, &conv_wf);
if (ret)
return ret;

if (!st->fetch_trigger)
return 0;

fetch_state.period = conv_state.period;
fetch_wf.period_length_ns = conv_wf.period_length_ns;

if (st->out_data == AD4630_30_AVERAGED_DIFF) {
u32 avg;
Expand All @@ -398,23 +396,33 @@ static int __ad4630_set_sampling_freq(const struct ad4630_state *st, unsigned in
if (ret)
return ret;

fetch_state.period <<= FIELD_GET(AD4630_AVG_AVG_VAL, avg);
fetch_wf.period_length_ns <<= FIELD_GET(AD4630_AVG_AVG_VAL, avg);
}

/*
* The hardware does the capture on zone 2 (when spi trigger PWM
* is used). This means that the spi trigger signal should happen at
* tsync + tquiet_con_delay being tsync the conversion signal period
* and tquiet_con_delay 9.8ns. Hence set the PWM phase accordingly.
*
* The PWM waveform API only supports nanosecond resolution right now,
* so round this setting to the closest available value.
*/
fetch_state.phase = AD4630_TQUIET_CNV_DELAY_PS;
fetch_wf.duty_offset_ns = AD4630_TQUIET_CNV_DELAY_NS;

ret = pwm_round_waveform_might_sleep(st->fetch_trigger, &fetch_wf);
if (ret)
return ret;

st->conv_wf = conv_wf;
st->fetch_wf = fetch_wf;

return pwm_apply_state(st->fetch_trigger, &fetch_state);
return 0;
}

static int ad4630_set_sampling_freq(struct iio_dev *indio_dev, unsigned int freq)
{
const struct ad4630_state *st = iio_priv(indio_dev);
struct ad4630_state *st = iio_priv(indio_dev);
int ret;

if (!freq || freq > st->max_rate)
Expand Down Expand Up @@ -590,26 +598,32 @@ static int ad4630_write_raw(struct iio_dev *indio_dev,
}
}

static int ad4630_update_sample_fetch_trigger(const struct ad4630_state *st, u32 avg)
static int ad4630_update_sample_fetch_trigger(struct ad4630_state *st, u32 avg)
{
struct pwm_state fetch_state, conv_state;
struct pwm_waveform fetch_wf = { };
int ret;

if (!st->fetch_trigger)
return 0;

pwm_get_state(st->conv_trigger, &conv_state);
pwm_get_state(st->fetch_trigger, &fetch_state);
fetch_state.period = conv_state.period * 1 << avg;
fetch_state.phase = AD4630_TQUIET_CNV_DELAY_PS;
fetch_wf.period_length_ns = st->conv_wf.period_length_ns * 1 << avg;
fetch_wf.duty_length_ns = st->fetch_wf.duty_length_ns;
fetch_wf.duty_offset_ns = AD4630_TQUIET_CNV_DELAY_NS;

return pwm_apply_state(st->fetch_trigger, &fetch_state);
ret = pwm_round_waveform_might_sleep(st->fetch_trigger, &fetch_wf);
if (ret)
return ret;

st->fetch_wf = fetch_wf;

return 0;
}

static int ad4630_set_avg_frame_len(struct iio_dev *dev,
const struct iio_chan_spec *chan,
unsigned int avg_len)
{
const struct ad4630_state *st = iio_priv(dev);
struct ad4630_state *st = iio_priv(dev);
int ret;

ret = iio_device_claim_direct_mode(dev);
Expand All @@ -630,7 +644,7 @@ static int ad4630_set_avg_frame_len(struct iio_dev *dev,
static int ad4630_get_avg_frame_len(struct iio_dev *dev,
const struct iio_chan_spec *chan)
{
const struct ad4630_state *st = iio_priv(dev);
struct ad4630_state *st = iio_priv(dev);
unsigned int avg_len;
int ret;

Expand All @@ -646,25 +660,6 @@ static int ad4630_get_avg_frame_len(struct iio_dev *dev,
return avg_len - 1;
}

static int ad4630_sampling_enable(const struct ad4630_state *st, bool enable)
{
struct pwm_state conv_state, fetch_state;
int ret;

pwm_get_state(st->conv_trigger, &conv_state);
conv_state.enabled = enable;

ret = pwm_apply_state(st->conv_trigger, &conv_state);
if (ret)
return ret;
if (!st->fetch_trigger)
return 0;

pwm_get_state(st->fetch_trigger, &fetch_state);
fetch_state.enabled = enable;
return pwm_apply_state(st->fetch_trigger, &fetch_state);
}

static int ad4630_spi_transfer_update(struct ad4630_state *st)
{
u8 bits_per_w;
Expand Down Expand Up @@ -729,7 +724,17 @@ static int ad4630_buffer_preenable(struct iio_dev *indio_dev)
spi_bus_lock(st->spi->master);
spi_engine_ex_offload_load_msg(st->spi, &st->offload_msg);
spi_engine_ex_offload_enable(st->spi, true);
ad4630_sampling_enable(st, true);

ret = pwm_set_waveform_might_sleep(st->conv_trigger, &st->conv_wf, false);
if (ret)
return ret;

if (!st->fetch_trigger)
return 0;

ret = pwm_set_waveform_might_sleep(st->fetch_trigger, &st->fetch_wf, false);
if (ret)
return ret;

return 0;
out_error:
Expand All @@ -744,9 +749,8 @@ static int ad4630_buffer_postdisable(struct iio_dev *indio_dev)
u32 dummy;
int ret;

ret = ad4630_sampling_enable(st, false);
if (ret)
goto out_error;
pwm_disable(st->conv_trigger);
pwm_disable(st->fetch_trigger);

spi_engine_ex_offload_enable(st->spi, false);
spi_bus_unlock(st->spi->master);
Expand Down Expand Up @@ -1197,6 +1201,12 @@ static int ad4630_pwm_get(struct ad4630_state *st)
return dev_err_probe(dev, PTR_ERR(st->conv_trigger),
"Failed to get cnv pwm\n");

/*
* Preemptively disable the PWM, since we only want to enable it with
* the buffer
*/
pwm_disable(st->conv_trigger);

/*
* the trigger is optional... We can have the device BUSY pin
* acting as trigger.
Expand All @@ -1208,6 +1218,11 @@ static int ad4630_pwm_get(struct ad4630_state *st)
if (IS_ERR(st->fetch_trigger))
return dev_err_probe(dev, PTR_ERR(st->fetch_trigger),
"Failed to get spi engine pwm\n");
/*
* Preemptively disable the PWM, since we only want to enable it with
* the buffer
*/
pwm_disable(st->fetch_trigger);

out_sampling_freq:
return __ad4630_set_sampling_freq(st, st->max_rate);
Expand Down

0 comments on commit 8ea2bf4

Please sign in to comment.