1031 lines
26 KiB
C
1031 lines
26 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* NXP SAR-ADC driver (adapted from Freescale Vybrid vf610 ADC driver
|
|
* by Fugang Duan <B38611@freescale.com>)
|
|
*
|
|
* Copyright 2013 Freescale Semiconductor, Inc.
|
|
* Copyright 2017, 2020-2025 NXP
|
|
* Copyright 2025, Linaro Ltd
|
|
*/
|
|
#include <linux/bitfield.h>
|
|
#include <linux/bitops.h>
|
|
#include <linux/circ_buf.h>
|
|
#include <linux/cleanup.h>
|
|
#include <linux/clk.h>
|
|
#include <linux/completion.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/dmaengine.h>
|
|
#include <linux/err.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/iopoll.h>
|
|
#include <linux/math64.h>
|
|
#include <linux/minmax.h>
|
|
#include <linux/module.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/pm.h>
|
|
#include <linux/property.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/time.h>
|
|
#include <linux/types.h>
|
|
#include <linux/units.h>
|
|
|
|
#include <linux/iio/iio.h>
|
|
#include <linux/iio/triggered_buffer.h>
|
|
#include <linux/iio/trigger_consumer.h>
|
|
|
|
/* SAR ADC registers. */
|
|
#define NXP_SAR_ADC_CDR(__base, __channel) (((__base) + 0x100) + ((__channel) * 0x4))
|
|
|
|
#define NXP_SAR_ADC_CDR_CDATA_MASK GENMASK(11, 0)
|
|
#define NXP_SAR_ADC_CDR_VALID BIT(19)
|
|
|
|
/* Main Configuration Register */
|
|
#define NXP_SAR_ADC_MCR(__base) ((__base) + 0x00)
|
|
|
|
#define NXP_SAR_ADC_MCR_PWDN BIT(0)
|
|
#define NXP_SAR_ADC_MCR_ACKO BIT(5)
|
|
#define NXP_SAR_ADC_MCR_ADCLKSEL BIT(8)
|
|
#define NXP_SAR_ADC_MCR_TSAMP_MASK GENMASK(10, 9)
|
|
#define NXP_SAR_ADC_MCR_NRSMPL_MASK GENMASK(12, 11)
|
|
#define NXP_SAR_ADC_MCR_AVGEN BIT(13)
|
|
#define NXP_SAR_ADC_MCR_CALSTART BIT(14)
|
|
#define NXP_SAR_ADC_MCR_NSTART BIT(24)
|
|
#define NXP_SAR_ADC_MCR_MODE BIT(29)
|
|
#define NXP_SAR_ADC_MCR_OWREN BIT(31)
|
|
|
|
/* Main Status Register */
|
|
#define NXP_SAR_ADC_MSR(__base) ((__base) + 0x04)
|
|
|
|
#define NXP_SAR_ADC_MSR_CALBUSY BIT(29)
|
|
#define NXP_SAR_ADC_MSR_CALFAIL BIT(30)
|
|
|
|
/* Interrupt Status Register */
|
|
#define NXP_SAR_ADC_ISR(__base) ((__base) + 0x10)
|
|
|
|
#define NXP_SAR_ADC_ISR_ECH BIT(0)
|
|
|
|
/* Channel Pending Register */
|
|
#define NXP_SAR_ADC_CEOCFR0(__base) ((__base) + 0x14)
|
|
#define NXP_SAR_ADC_CEOCFR1(__base) ((__base) + 0x18)
|
|
|
|
#define NXP_SAR_ADC_EOC_CH(c) BIT(c)
|
|
|
|
/* Interrupt Mask Register */
|
|
#define NXP_SAR_ADC_IMR(__base) ((__base) + 0x20)
|
|
|
|
/* Channel Interrupt Mask Register */
|
|
#define NXP_SAR_ADC_CIMR0(__base) ((__base) + 0x24)
|
|
#define NXP_SAR_ADC_CIMR1(__base) ((__base) + 0x28)
|
|
|
|
/* DMA Setting Register */
|
|
#define NXP_SAR_ADC_DMAE(__base) ((__base) + 0x40)
|
|
|
|
#define NXP_SAR_ADC_DMAE_DMAEN BIT(0)
|
|
#define NXP_SAR_ADC_DMAE_DCLR BIT(1)
|
|
|
|
/* DMA Control register */
|
|
#define NXP_SAR_ADC_DMAR0(__base) ((__base) + 0x44)
|
|
#define NXP_SAR_ADC_DMAR1(__base) ((__base) + 0x48)
|
|
|
|
/* Conversion Timing Register */
|
|
#define NXP_SAR_ADC_CTR0(__base) ((__base) + 0x94)
|
|
#define NXP_SAR_ADC_CTR1(__base) ((__base) + 0x98)
|
|
|
|
#define NXP_SAR_ADC_CTR_INPSAMP_MIN 0x08
|
|
#define NXP_SAR_ADC_CTR_INPSAMP_MAX 0xff
|
|
|
|
/* Normal Conversion Mask Register */
|
|
#define NXP_SAR_ADC_NCMR0(__base) ((__base) + 0xa4)
|
|
#define NXP_SAR_ADC_NCMR1(__base) ((__base) + 0xa8)
|
|
|
|
/* Normal Conversion Mask Register field define */
|
|
#define NXP_SAR_ADC_CH_MASK GENMASK(7, 0)
|
|
|
|
/* Other field define */
|
|
#define NXP_SAR_ADC_CONV_TIMEOUT (msecs_to_jiffies(100))
|
|
#define NXP_SAR_ADC_CAL_TIMEOUT_US (100 * USEC_PER_MSEC)
|
|
#define NXP_SAR_ADC_WAIT_US (2 * USEC_PER_MSEC)
|
|
#define NXP_SAR_ADC_RESOLUTION 12
|
|
|
|
/* Duration of conversion phases */
|
|
#define NXP_SAR_ADC_TPT 2
|
|
#define NXP_SAR_ADC_DP 2
|
|
#define NXP_SAR_ADC_CT ((NXP_SAR_ADC_RESOLUTION + 2) * 4)
|
|
#define NXP_SAR_ADC_CONV_TIME (NXP_SAR_ADC_TPT + NXP_SAR_ADC_CT + NXP_SAR_ADC_DP)
|
|
|
|
#define NXP_SAR_ADC_NR_CHANNELS 8
|
|
|
|
#define NXP_PAGE_SIZE SZ_4K
|
|
#define NXP_SAR_ADC_DMA_SAMPLE_SZ DMA_SLAVE_BUSWIDTH_4_BYTES
|
|
#define NXP_SAR_ADC_DMA_BUFF_SZ (NXP_PAGE_SIZE * NXP_SAR_ADC_DMA_SAMPLE_SZ)
|
|
#define NXP_SAR_ADC_DMA_SAMPLE_CNT (NXP_SAR_ADC_DMA_BUFF_SZ / NXP_SAR_ADC_DMA_SAMPLE_SZ)
|
|
|
|
struct nxp_sar_adc {
|
|
void __iomem *regs;
|
|
phys_addr_t regs_phys;
|
|
u8 current_channel;
|
|
u8 channels_used;
|
|
u16 value;
|
|
u32 vref_mV;
|
|
|
|
/* Save and restore context. */
|
|
u32 inpsamp;
|
|
u32 pwdn;
|
|
|
|
struct clk *clk;
|
|
struct dma_chan *dma_chan;
|
|
struct completion completion;
|
|
struct circ_buf dma_buf;
|
|
|
|
dma_addr_t rx_dma_buf;
|
|
dma_cookie_t cookie;
|
|
|
|
/* Protect circular buffers access. */
|
|
spinlock_t lock;
|
|
|
|
/* Array of enabled channels. */
|
|
u16 buffered_chan[NXP_SAR_ADC_NR_CHANNELS];
|
|
|
|
/* Buffer to be filled by the DMA. */
|
|
IIO_DECLARE_BUFFER_WITH_TS(u16, buffer, NXP_SAR_ADC_NR_CHANNELS);
|
|
};
|
|
|
|
struct nxp_sar_adc_data {
|
|
u32 vref_mV;
|
|
const char *model;
|
|
};
|
|
|
|
#define ADC_CHAN(_idx, _chan_type) { \
|
|
.type = (_chan_type), \
|
|
.indexed = 1, \
|
|
.channel = (_idx), \
|
|
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
|
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
|
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
|
.scan_index = (_idx), \
|
|
.scan_type = { \
|
|
.sign = 'u', \
|
|
.realbits = 12, \
|
|
.storagebits = 16, \
|
|
}, \
|
|
}
|
|
|
|
static const struct iio_chan_spec nxp_sar_adc_iio_channels[] = {
|
|
ADC_CHAN(0, IIO_VOLTAGE),
|
|
ADC_CHAN(1, IIO_VOLTAGE),
|
|
ADC_CHAN(2, IIO_VOLTAGE),
|
|
ADC_CHAN(3, IIO_VOLTAGE),
|
|
ADC_CHAN(4, IIO_VOLTAGE),
|
|
ADC_CHAN(5, IIO_VOLTAGE),
|
|
ADC_CHAN(6, IIO_VOLTAGE),
|
|
ADC_CHAN(7, IIO_VOLTAGE),
|
|
/*
|
|
* The NXP SAR ADC documentation marks the channels 8 to 31 as
|
|
* "Reserved". Reflect the same in the driver in case new ADC
|
|
* variants comes with more channels.
|
|
*/
|
|
IIO_CHAN_SOFT_TIMESTAMP(32),
|
|
};
|
|
|
|
static void nxp_sar_adc_irq_cfg(struct nxp_sar_adc *info, bool enable)
|
|
{
|
|
if (enable)
|
|
writel(NXP_SAR_ADC_ISR_ECH, NXP_SAR_ADC_IMR(info->regs));
|
|
else
|
|
writel(0, NXP_SAR_ADC_IMR(info->regs));
|
|
}
|
|
|
|
static void nxp_sar_adc_wait_for(struct nxp_sar_adc *info, u64 cycles)
|
|
{
|
|
u64 rate;
|
|
|
|
rate = clk_get_rate(info->clk);
|
|
if (rate)
|
|
ndelay(div64_u64(NSEC_PER_SEC * cycles, rate));
|
|
}
|
|
|
|
static bool nxp_sar_adc_set_enabled(struct nxp_sar_adc *info, bool enable)
|
|
{
|
|
u32 mcr;
|
|
bool pwdn;
|
|
|
|
mcr = readl(NXP_SAR_ADC_MCR(info->regs));
|
|
|
|
/*
|
|
* Get the current state and return it later. This is used for
|
|
* suspend/resume to get the power state
|
|
*/
|
|
pwdn = FIELD_GET(NXP_SAR_ADC_MCR_PWDN, mcr);
|
|
|
|
/* When the enabled flag is not set, we set the power down bit */
|
|
FIELD_MODIFY(NXP_SAR_ADC_MCR_PWDN, &mcr, !enable);
|
|
|
|
writel(mcr, NXP_SAR_ADC_MCR(info->regs));
|
|
|
|
/*
|
|
* Ensure there are at least three cycles between the
|
|
* configuration of NCMR and the setting of NSTART.
|
|
*/
|
|
if (enable)
|
|
nxp_sar_adc_wait_for(info, 3);
|
|
|
|
return pwdn;
|
|
}
|
|
|
|
static inline bool nxp_sar_adc_enable(struct nxp_sar_adc *info)
|
|
{
|
|
return nxp_sar_adc_set_enabled(info, true);
|
|
}
|
|
|
|
static inline bool nxp_sar_adc_disable(struct nxp_sar_adc *info)
|
|
{
|
|
return nxp_sar_adc_set_enabled(info, false);
|
|
}
|
|
|
|
static inline void nxp_sar_adc_calibration_start(void __iomem *base)
|
|
{
|
|
u32 mcr = readl(NXP_SAR_ADC_MCR(base));
|
|
|
|
FIELD_MODIFY(NXP_SAR_ADC_MCR_CALSTART, &mcr, 0x1);
|
|
|
|
writel(mcr, NXP_SAR_ADC_MCR(base));
|
|
}
|
|
|
|
static inline int nxp_sar_adc_calibration_wait(void __iomem *base)
|
|
{
|
|
u32 msr;
|
|
int ret;
|
|
|
|
ret = readl_poll_timeout(NXP_SAR_ADC_MSR(base), msr,
|
|
!FIELD_GET(NXP_SAR_ADC_MSR_CALBUSY, msr),
|
|
NXP_SAR_ADC_WAIT_US,
|
|
NXP_SAR_ADC_CAL_TIMEOUT_US);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if (FIELD_GET(NXP_SAR_ADC_MSR_CALFAIL, msr)) {
|
|
/*
|
|
* If the calibration fails, the status register bit must be
|
|
* cleared.
|
|
*/
|
|
FIELD_MODIFY(NXP_SAR_ADC_MSR_CALFAIL, &msr, 0x0);
|
|
writel(msr, NXP_SAR_ADC_MSR(base));
|
|
|
|
return -EAGAIN;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nxp_sar_adc_calibration(struct nxp_sar_adc *info)
|
|
{
|
|
int ret;
|
|
|
|
/* Calibration works only if the ADC is powered up. */
|
|
nxp_sar_adc_enable(info);
|
|
|
|
/* The calibration operation starts. */
|
|
nxp_sar_adc_calibration_start(info->regs);
|
|
|
|
ret = nxp_sar_adc_calibration_wait(info->regs);
|
|
|
|
/*
|
|
* Calibration works only if the ADC is powered up. However
|
|
* the calibration is called from the probe function where the
|
|
* iio is not enabled, so we disable after the calibration.
|
|
*/
|
|
nxp_sar_adc_disable(info);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void nxp_sar_adc_conversion_timing_set(struct nxp_sar_adc *info, u32 inpsamp)
|
|
{
|
|
inpsamp = clamp(inpsamp, NXP_SAR_ADC_CTR_INPSAMP_MIN, NXP_SAR_ADC_CTR_INPSAMP_MAX);
|
|
|
|
writel(inpsamp, NXP_SAR_ADC_CTR0(info->regs));
|
|
}
|
|
|
|
static u32 nxp_sar_adc_conversion_timing_get(struct nxp_sar_adc *info)
|
|
{
|
|
return readl(NXP_SAR_ADC_CTR0(info->regs));
|
|
}
|
|
|
|
static void nxp_sar_adc_read_notify(struct nxp_sar_adc *info)
|
|
{
|
|
writel(NXP_SAR_ADC_CH_MASK, NXP_SAR_ADC_CEOCFR0(info->regs));
|
|
writel(NXP_SAR_ADC_CH_MASK, NXP_SAR_ADC_CEOCFR1(info->regs));
|
|
}
|
|
|
|
static int nxp_sar_adc_read_data(struct nxp_sar_adc *info, unsigned int chan)
|
|
{
|
|
u32 ceocfr, cdr;
|
|
|
|
ceocfr = readl(NXP_SAR_ADC_CEOCFR0(info->regs));
|
|
|
|
if (!field_get(NXP_SAR_ADC_EOC_CH(chan), ceocfr))
|
|
return -EIO;
|
|
|
|
cdr = readl(NXP_SAR_ADC_CDR(info->regs, chan));
|
|
if (!(FIELD_GET(NXP_SAR_ADC_CDR_VALID, cdr)))
|
|
return -EIO;
|
|
|
|
return FIELD_GET(NXP_SAR_ADC_CDR_CDATA_MASK, cdr);
|
|
}
|
|
|
|
static void nxp_sar_adc_isr_buffer(struct iio_dev *indio_dev)
|
|
{
|
|
struct nxp_sar_adc *info = iio_priv(indio_dev);
|
|
unsigned int i;
|
|
int ret;
|
|
|
|
for (i = 0; i < info->channels_used; i++) {
|
|
ret = nxp_sar_adc_read_data(info, info->buffered_chan[i]);
|
|
if (ret < 0) {
|
|
nxp_sar_adc_read_notify(info);
|
|
iio_trigger_notify_done(indio_dev->trig);
|
|
return;
|
|
}
|
|
|
|
info->buffer[i] = ret;
|
|
}
|
|
|
|
nxp_sar_adc_read_notify(info);
|
|
|
|
iio_push_to_buffers_with_ts(indio_dev, info->buffer, sizeof(info->buffer),
|
|
iio_get_time_ns(indio_dev));
|
|
|
|
iio_trigger_notify_done(indio_dev->trig);
|
|
}
|
|
|
|
static void nxp_sar_adc_isr_read_raw(struct iio_dev *indio_dev)
|
|
{
|
|
struct nxp_sar_adc *info = iio_priv(indio_dev);
|
|
int ret;
|
|
|
|
ret = nxp_sar_adc_read_data(info, info->current_channel);
|
|
nxp_sar_adc_read_notify(info);
|
|
if (ret < 0)
|
|
return;
|
|
|
|
info->value = ret;
|
|
complete(&info->completion);
|
|
}
|
|
|
|
static irqreturn_t nxp_sar_adc_isr(int irq, void *dev_id)
|
|
{
|
|
struct iio_dev *indio_dev = dev_id;
|
|
struct nxp_sar_adc *info = iio_priv(indio_dev);
|
|
int isr;
|
|
|
|
isr = readl(NXP_SAR_ADC_ISR(info->regs));
|
|
if (!(FIELD_GET(NXP_SAR_ADC_ISR_ECH, isr)))
|
|
return IRQ_NONE;
|
|
|
|
if (iio_buffer_enabled(indio_dev))
|
|
nxp_sar_adc_isr_buffer(indio_dev);
|
|
else
|
|
nxp_sar_adc_isr_read_raw(indio_dev);
|
|
|
|
writel(NXP_SAR_ADC_ISR_ECH, NXP_SAR_ADC_ISR(info->regs));
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static void nxp_sar_adc_channels_disable(struct nxp_sar_adc *info, u32 mask)
|
|
{
|
|
u32 ncmr, cimr;
|
|
|
|
ncmr = readl(NXP_SAR_ADC_NCMR0(info->regs));
|
|
cimr = readl(NXP_SAR_ADC_CIMR0(info->regs));
|
|
|
|
/* FIELD_MODIFY() can not be used because the mask is not constant */
|
|
ncmr &= ~mask;
|
|
cimr &= ~mask;
|
|
|
|
writel(ncmr, NXP_SAR_ADC_NCMR0(info->regs));
|
|
writel(cimr, NXP_SAR_ADC_CIMR0(info->regs));
|
|
}
|
|
|
|
static void nxp_sar_adc_channels_enable(struct nxp_sar_adc *info, u32 mask)
|
|
{
|
|
u32 ncmr, cimr;
|
|
|
|
ncmr = readl(NXP_SAR_ADC_NCMR0(info->regs));
|
|
cimr = readl(NXP_SAR_ADC_CIMR0(info->regs));
|
|
|
|
ncmr |= mask;
|
|
cimr |= mask;
|
|
|
|
writel(ncmr, NXP_SAR_ADC_NCMR0(info->regs));
|
|
writel(cimr, NXP_SAR_ADC_CIMR0(info->regs));
|
|
}
|
|
|
|
static void nxp_sar_adc_dma_channels_enable(struct nxp_sar_adc *info, u32 mask)
|
|
{
|
|
u32 dmar;
|
|
|
|
dmar = readl(NXP_SAR_ADC_DMAR0(info->regs));
|
|
|
|
dmar |= mask;
|
|
|
|
writel(dmar, NXP_SAR_ADC_DMAR0(info->regs));
|
|
}
|
|
|
|
static void nxp_sar_adc_dma_channels_disable(struct nxp_sar_adc *info, u32 mask)
|
|
{
|
|
u32 dmar;
|
|
|
|
dmar = readl(NXP_SAR_ADC_DMAR0(info->regs));
|
|
|
|
dmar &= ~mask;
|
|
|
|
writel(dmar, NXP_SAR_ADC_DMAR0(info->regs));
|
|
}
|
|
|
|
static void nxp_sar_adc_dma_cfg(struct nxp_sar_adc *info, bool enable)
|
|
{
|
|
u32 dmae;
|
|
|
|
dmae = readl(NXP_SAR_ADC_DMAE(info->regs));
|
|
|
|
FIELD_MODIFY(NXP_SAR_ADC_DMAE_DMAEN, &dmae, enable);
|
|
|
|
writel(dmae, NXP_SAR_ADC_DMAE(info->regs));
|
|
}
|
|
|
|
static void nxp_sar_adc_stop_conversion(struct nxp_sar_adc *info)
|
|
{
|
|
u32 mcr;
|
|
|
|
mcr = readl(NXP_SAR_ADC_MCR(info->regs));
|
|
|
|
FIELD_MODIFY(NXP_SAR_ADC_MCR_NSTART, &mcr, 0x0);
|
|
|
|
writel(mcr, NXP_SAR_ADC_MCR(info->regs));
|
|
|
|
/*
|
|
* On disable, we have to wait for the transaction to finish.
|
|
* ADC does not abort the transaction if a chain conversion is
|
|
* in progress. Wait for the worst case scenario - 80 ADC clk
|
|
* cycles. The clock rate is 80MHz, this routine is called
|
|
* only when the capture finishes. The delay will be very
|
|
* short, usec-ish, which is acceptable in the atomic context.
|
|
*/
|
|
nxp_sar_adc_wait_for(info, 80);
|
|
}
|
|
|
|
static int nxp_sar_adc_start_conversion(struct nxp_sar_adc *info, bool raw)
|
|
{
|
|
u32 mcr;
|
|
|
|
mcr = readl(NXP_SAR_ADC_MCR(info->regs));
|
|
|
|
FIELD_MODIFY(NXP_SAR_ADC_MCR_NSTART, &mcr, 0x1);
|
|
FIELD_MODIFY(NXP_SAR_ADC_MCR_MODE, &mcr, raw ? 0 : 1);
|
|
|
|
writel(mcr, NXP_SAR_ADC_MCR(info->regs));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nxp_sar_adc_read_channel(struct nxp_sar_adc *info, int channel)
|
|
{
|
|
int ret;
|
|
|
|
info->current_channel = channel;
|
|
nxp_sar_adc_channels_enable(info, BIT(channel));
|
|
nxp_sar_adc_irq_cfg(info, true);
|
|
nxp_sar_adc_enable(info);
|
|
|
|
reinit_completion(&info->completion);
|
|
ret = nxp_sar_adc_start_conversion(info, true);
|
|
if (ret < 0)
|
|
goto out_disable;
|
|
|
|
if (!wait_for_completion_interruptible_timeout(&info->completion,
|
|
NXP_SAR_ADC_CONV_TIMEOUT))
|
|
ret = -ETIMEDOUT;
|
|
|
|
nxp_sar_adc_stop_conversion(info);
|
|
|
|
out_disable:
|
|
nxp_sar_adc_channels_disable(info, BIT(channel));
|
|
nxp_sar_adc_irq_cfg(info, false);
|
|
nxp_sar_adc_disable(info);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int nxp_sar_adc_read_raw(struct iio_dev *indio_dev,
|
|
struct iio_chan_spec const *chan, int *val,
|
|
int *val2, long mask)
|
|
{
|
|
struct nxp_sar_adc *info = iio_priv(indio_dev);
|
|
u32 inpsamp;
|
|
int ret;
|
|
|
|
switch (mask) {
|
|
case IIO_CHAN_INFO_RAW:
|
|
if (!iio_device_claim_direct(indio_dev))
|
|
return -EBUSY;
|
|
|
|
ret = nxp_sar_adc_read_channel(info, chan->channel);
|
|
|
|
iio_device_release_direct(indio_dev);
|
|
|
|
if (ret)
|
|
return ret;
|
|
|
|
*val = info->value;
|
|
return IIO_VAL_INT;
|
|
|
|
case IIO_CHAN_INFO_SCALE:
|
|
*val = info->vref_mV;
|
|
*val2 = NXP_SAR_ADC_RESOLUTION;
|
|
return IIO_VAL_FRACTIONAL_LOG2;
|
|
|
|
case IIO_CHAN_INFO_SAMP_FREQ:
|
|
inpsamp = nxp_sar_adc_conversion_timing_get(info);
|
|
*val = clk_get_rate(info->clk) / (inpsamp + NXP_SAR_ADC_CONV_TIME);
|
|
return IIO_VAL_INT;
|
|
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
static int nxp_sar_adc_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
|
|
int val, int val2, long mask)
|
|
{
|
|
struct nxp_sar_adc *info = iio_priv(indio_dev);
|
|
u32 inpsamp;
|
|
|
|
switch (mask) {
|
|
case IIO_CHAN_INFO_SAMP_FREQ:
|
|
if (val <= 0)
|
|
return -EINVAL;
|
|
|
|
/*
|
|
* Configures the sample period duration in terms of the SAR
|
|
* controller clock. The minimum acceptable value is 8.
|
|
* Configuring it to a value lower than 8 sets the sample period
|
|
* to 8 cycles. We read the clock value and divide by the
|
|
* sampling timing which gives us the number of cycles expected.
|
|
* The value is 8-bit wide, consequently the max value is 0xFF.
|
|
*/
|
|
inpsamp = clk_get_rate(info->clk) / val;
|
|
if (inpsamp < NXP_SAR_ADC_CONV_TIME)
|
|
return -EINVAL;
|
|
|
|
inpsamp -= NXP_SAR_ADC_CONV_TIME;
|
|
nxp_sar_adc_conversion_timing_set(info, inpsamp);
|
|
return 0;
|
|
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
static void nxp_sar_adc_dma_cb(void *data)
|
|
{
|
|
struct iio_dev *indio_dev = data;
|
|
struct nxp_sar_adc *info = iio_priv(indio_dev);
|
|
struct dma_tx_state state;
|
|
struct circ_buf *dma_buf;
|
|
struct device *dev_dma;
|
|
u32 *dma_samples;
|
|
s64 timestamp;
|
|
int idx, ret;
|
|
|
|
guard(spinlock_irqsave)(&info->lock);
|
|
|
|
dma_buf = &info->dma_buf;
|
|
dma_samples = (u32 *)dma_buf->buf;
|
|
dev_dma = info->dma_chan->device->dev;
|
|
|
|
/*
|
|
* DMA in some corner cases might have already be charged for
|
|
* the next transfer. Potentially there can be a race where
|
|
* the residue changes while the dma engine updates the
|
|
* buffer. That could be handled by using the
|
|
* callback_result() instead of callback() because the residue
|
|
* will be passed as a parameter to the function. However this
|
|
* new callback is pretty new and the backend does not update
|
|
* the residue. So let's stick to the version other drivers do
|
|
* which has proven running well in production since several
|
|
* years.
|
|
*/
|
|
dmaengine_tx_status(info->dma_chan, info->cookie, &state);
|
|
|
|
dma_sync_single_for_cpu(dev_dma, info->rx_dma_buf,
|
|
NXP_SAR_ADC_DMA_BUFF_SZ, DMA_FROM_DEVICE);
|
|
|
|
/* Current head position. */
|
|
dma_buf->head = (NXP_SAR_ADC_DMA_BUFF_SZ - state.residue) /
|
|
NXP_SAR_ADC_DMA_SAMPLE_SZ;
|
|
|
|
/* If everything was transferred, avoid an off by one error. */
|
|
if (!state.residue)
|
|
dma_buf->head--;
|
|
|
|
/* Something went wrong and nothing transferred. */
|
|
if (state.residue != NXP_SAR_ADC_DMA_BUFF_SZ) {
|
|
/* Make sure that head is multiple of info->channels_used. */
|
|
dma_buf->head -= dma_buf->head % info->channels_used;
|
|
|
|
/*
|
|
* dma_buf->tail != dma_buf->head condition will become false
|
|
* because dma_buf->tail will be incremented with 1.
|
|
*/
|
|
while (dma_buf->tail != dma_buf->head) {
|
|
idx = dma_buf->tail % info->channels_used;
|
|
info->buffer[idx] = dma_samples[dma_buf->tail];
|
|
dma_buf->tail = (dma_buf->tail + 1) % NXP_SAR_ADC_DMA_SAMPLE_CNT;
|
|
if (idx != info->channels_used - 1)
|
|
continue;
|
|
|
|
/*
|
|
* iio_push_to_buffers_with_ts() should not be
|
|
* called with dma_samples as parameter. The samples
|
|
* will be smashed if timestamp is enabled.
|
|
*/
|
|
timestamp = iio_get_time_ns(indio_dev);
|
|
ret = iio_push_to_buffers_with_ts(indio_dev, info->buffer,
|
|
sizeof(info->buffer),
|
|
timestamp);
|
|
if (ret < 0 && ret != -EBUSY)
|
|
dev_err_ratelimited(&indio_dev->dev,
|
|
"failed to push iio buffer: %d",
|
|
ret);
|
|
}
|
|
|
|
dma_buf->tail = dma_buf->head;
|
|
}
|
|
|
|
dma_sync_single_for_device(dev_dma, info->rx_dma_buf,
|
|
NXP_SAR_ADC_DMA_BUFF_SZ, DMA_FROM_DEVICE);
|
|
}
|
|
|
|
static int nxp_sar_adc_start_cyclic_dma(struct iio_dev *indio_dev)
|
|
{
|
|
struct nxp_sar_adc *info = iio_priv(indio_dev);
|
|
struct dma_slave_config config = { };
|
|
struct dma_async_tx_descriptor *desc;
|
|
int ret;
|
|
|
|
info->dma_buf.head = 0;
|
|
info->dma_buf.tail = 0;
|
|
|
|
config.direction = DMA_DEV_TO_MEM;
|
|
config.src_addr_width = NXP_SAR_ADC_DMA_SAMPLE_SZ;
|
|
config.src_addr = NXP_SAR_ADC_CDR(info->regs_phys, info->buffered_chan[0]);
|
|
config.src_port_window_size = info->channels_used;
|
|
config.src_maxburst = info->channels_used;
|
|
ret = dmaengine_slave_config(info->dma_chan, &config);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
desc = dmaengine_prep_dma_cyclic(info->dma_chan,
|
|
info->rx_dma_buf,
|
|
NXP_SAR_ADC_DMA_BUFF_SZ,
|
|
NXP_SAR_ADC_DMA_BUFF_SZ / 2,
|
|
DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
|
|
if (!desc)
|
|
return -EINVAL;
|
|
|
|
desc->callback = nxp_sar_adc_dma_cb;
|
|
desc->callback_param = indio_dev;
|
|
info->cookie = dmaengine_submit(desc);
|
|
ret = dma_submit_error(info->cookie);
|
|
if (ret) {
|
|
dmaengine_terminate_async(info->dma_chan);
|
|
return ret;
|
|
}
|
|
|
|
dma_async_issue_pending(info->dma_chan);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void nxp_sar_adc_buffer_software_do_predisable(struct iio_dev *indio_dev)
|
|
{
|
|
struct nxp_sar_adc *info = iio_priv(indio_dev);
|
|
|
|
/*
|
|
* The ADC DMAEN bit should be cleared before DMA transaction
|
|
* is canceled.
|
|
*/
|
|
nxp_sar_adc_stop_conversion(info);
|
|
dmaengine_terminate_sync(info->dma_chan);
|
|
nxp_sar_adc_dma_cfg(info, false);
|
|
nxp_sar_adc_dma_channels_disable(info, *indio_dev->active_scan_mask);
|
|
|
|
dma_release_channel(info->dma_chan);
|
|
}
|
|
|
|
static int nxp_sar_adc_buffer_software_do_postenable(struct iio_dev *indio_dev)
|
|
{
|
|
struct nxp_sar_adc *info = iio_priv(indio_dev);
|
|
int ret;
|
|
|
|
info->dma_chan = dma_request_chan(indio_dev->dev.parent, "rx");
|
|
if (IS_ERR(info->dma_chan))
|
|
return PTR_ERR(info->dma_chan);
|
|
|
|
nxp_sar_adc_dma_channels_enable(info, *indio_dev->active_scan_mask);
|
|
|
|
nxp_sar_adc_dma_cfg(info, true);
|
|
|
|
ret = nxp_sar_adc_start_cyclic_dma(indio_dev);
|
|
if (ret)
|
|
goto out_dma_channels_disable;
|
|
|
|
ret = nxp_sar_adc_start_conversion(info, false);
|
|
if (ret)
|
|
goto out_stop_cyclic_dma;
|
|
|
|
return 0;
|
|
|
|
out_stop_cyclic_dma:
|
|
dmaengine_terminate_sync(info->dma_chan);
|
|
|
|
out_dma_channels_disable:
|
|
nxp_sar_adc_dma_cfg(info, false);
|
|
nxp_sar_adc_dma_channels_disable(info, *indio_dev->active_scan_mask);
|
|
dma_release_channel(info->dma_chan);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void nxp_sar_adc_buffer_trigger_do_predisable(struct iio_dev *indio_dev)
|
|
{
|
|
struct nxp_sar_adc *info = iio_priv(indio_dev);
|
|
|
|
nxp_sar_adc_irq_cfg(info, false);
|
|
}
|
|
|
|
static int nxp_sar_adc_buffer_trigger_do_postenable(struct iio_dev *indio_dev)
|
|
{
|
|
struct nxp_sar_adc *info = iio_priv(indio_dev);
|
|
|
|
nxp_sar_adc_irq_cfg(info, true);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nxp_sar_adc_buffer_postenable(struct iio_dev *indio_dev)
|
|
{
|
|
struct nxp_sar_adc *info = iio_priv(indio_dev);
|
|
int current_mode = iio_device_get_current_mode(indio_dev);
|
|
unsigned long channel;
|
|
int ret;
|
|
|
|
info->channels_used = 0;
|
|
|
|
/*
|
|
* The SAR-ADC has two groups of channels.
|
|
*
|
|
* - Group #0:
|
|
* * bit 0-7 : channel 0 -> channel 7
|
|
* * bit 8-31 : reserved
|
|
*
|
|
* - Group #32:
|
|
* * bit 0-7 : Internal
|
|
* * bit 8-31 : reserved
|
|
*
|
|
* The 8 channels from group #0 are used in this driver for
|
|
* ADC as described when declaring the IIO device and the
|
|
* mapping is the same. That means the active_scan_mask can be
|
|
* used directly to write the channel interrupt mask.
|
|
*/
|
|
nxp_sar_adc_channels_enable(info, *indio_dev->active_scan_mask);
|
|
|
|
for_each_set_bit(channel, indio_dev->active_scan_mask, NXP_SAR_ADC_NR_CHANNELS)
|
|
info->buffered_chan[info->channels_used++] = channel;
|
|
|
|
nxp_sar_adc_enable(info);
|
|
|
|
if (current_mode == INDIO_BUFFER_SOFTWARE)
|
|
ret = nxp_sar_adc_buffer_software_do_postenable(indio_dev);
|
|
else
|
|
ret = nxp_sar_adc_buffer_trigger_do_postenable(indio_dev);
|
|
if (ret)
|
|
goto out_postenable;
|
|
|
|
return 0;
|
|
|
|
out_postenable:
|
|
nxp_sar_adc_disable(info);
|
|
nxp_sar_adc_channels_disable(info, *indio_dev->active_scan_mask);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int nxp_sar_adc_buffer_predisable(struct iio_dev *indio_dev)
|
|
{
|
|
struct nxp_sar_adc *info = iio_priv(indio_dev);
|
|
int currentmode = iio_device_get_current_mode(indio_dev);
|
|
|
|
if (currentmode == INDIO_BUFFER_SOFTWARE)
|
|
nxp_sar_adc_buffer_software_do_predisable(indio_dev);
|
|
else
|
|
nxp_sar_adc_buffer_trigger_do_predisable(indio_dev);
|
|
|
|
nxp_sar_adc_disable(info);
|
|
|
|
nxp_sar_adc_channels_disable(info, *indio_dev->active_scan_mask);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static irqreturn_t nxp_sar_adc_trigger_handler(int irq, void *p)
|
|
{
|
|
struct iio_poll_func *pf = p;
|
|
struct iio_dev *indio_dev = pf->indio_dev;
|
|
struct nxp_sar_adc *info = iio_priv(indio_dev);
|
|
int ret;
|
|
|
|
ret = nxp_sar_adc_start_conversion(info, true);
|
|
if (ret < 0)
|
|
dev_dbg(&indio_dev->dev, "Failed to start conversion\n");
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = {
|
|
.postenable = nxp_sar_adc_buffer_postenable,
|
|
.predisable = nxp_sar_adc_buffer_predisable,
|
|
};
|
|
|
|
static const struct iio_info nxp_sar_adc_iio_info = {
|
|
.read_raw = nxp_sar_adc_read_raw,
|
|
.write_raw = nxp_sar_adc_write_raw,
|
|
};
|
|
|
|
static int nxp_sar_adc_dma_probe(struct device *dev, struct nxp_sar_adc *info)
|
|
{
|
|
u8 *rx_buf;
|
|
|
|
rx_buf = dmam_alloc_coherent(dev, NXP_SAR_ADC_DMA_BUFF_SZ,
|
|
&info->rx_dma_buf, GFP_KERNEL);
|
|
if (!rx_buf)
|
|
return -ENOMEM;
|
|
|
|
info->dma_buf.buf = rx_buf;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* The documentation describes the reset values for the registers.
|
|
* However some registers do not have these values after a reset. It
|
|
* is not a desirable situation. In some other SoC family
|
|
* documentation NXP recommends not assuming the default values are
|
|
* set and to initialize the registers conforming to the documentation
|
|
* reset information to prevent this situation. Assume the same rule
|
|
* applies here as there is a discrepancy between what is read from
|
|
* the registers at reset time and the documentation.
|
|
*/
|
|
static void nxp_sar_adc_set_default_values(struct nxp_sar_adc *info)
|
|
{
|
|
writel(0x00003901, NXP_SAR_ADC_MCR(info->regs));
|
|
writel(0x00000001, NXP_SAR_ADC_MSR(info->regs));
|
|
writel(0x00000014, NXP_SAR_ADC_CTR0(info->regs));
|
|
writel(0x00000014, NXP_SAR_ADC_CTR1(info->regs));
|
|
writel(0x00000000, NXP_SAR_ADC_CIMR0(info->regs));
|
|
writel(0x00000000, NXP_SAR_ADC_CIMR1(info->regs));
|
|
writel(0x00000000, NXP_SAR_ADC_NCMR0(info->regs));
|
|
writel(0x00000000, NXP_SAR_ADC_NCMR1(info->regs));
|
|
}
|
|
|
|
static int nxp_sar_adc_probe(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
const struct nxp_sar_adc_data *data = device_get_match_data(dev);
|
|
struct nxp_sar_adc *info;
|
|
struct iio_dev *indio_dev;
|
|
struct resource *mem;
|
|
int irq, ret;
|
|
|
|
indio_dev = devm_iio_device_alloc(dev, sizeof(*info));
|
|
if (!indio_dev)
|
|
return -ENOMEM;
|
|
|
|
info = iio_priv(indio_dev);
|
|
info->vref_mV = data->vref_mV;
|
|
spin_lock_init(&info->lock);
|
|
info->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);
|
|
if (IS_ERR(info->regs))
|
|
return dev_err_probe(dev, PTR_ERR(info->regs),
|
|
"Failed to get and remap resource");
|
|
|
|
info->regs_phys = mem->start;
|
|
|
|
irq = platform_get_irq(pdev, 0);
|
|
if (irq < 0)
|
|
return irq;
|
|
|
|
ret = devm_request_irq(dev, irq, nxp_sar_adc_isr, 0, dev_name(dev),
|
|
indio_dev);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
info->clk = devm_clk_get_enabled(dev, NULL);
|
|
if (IS_ERR(info->clk))
|
|
return dev_err_probe(dev, PTR_ERR(info->clk),
|
|
"Failed to get the clock\n");
|
|
|
|
platform_set_drvdata(pdev, indio_dev);
|
|
|
|
init_completion(&info->completion);
|
|
|
|
indio_dev->name = data->model;
|
|
indio_dev->info = &nxp_sar_adc_iio_info;
|
|
indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
|
|
indio_dev->channels = nxp_sar_adc_iio_channels;
|
|
indio_dev->num_channels = ARRAY_SIZE(nxp_sar_adc_iio_channels);
|
|
|
|
nxp_sar_adc_set_default_values(info);
|
|
|
|
ret = nxp_sar_adc_calibration(info);
|
|
if (ret)
|
|
dev_err_probe(dev, ret, "Calibration failed\n");
|
|
|
|
ret = nxp_sar_adc_dma_probe(dev, info);
|
|
if (ret)
|
|
return dev_err_probe(dev, ret, "Failed to initialize the DMA\n");
|
|
|
|
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
|
|
&iio_pollfunc_store_time,
|
|
&nxp_sar_adc_trigger_handler,
|
|
&iio_triggered_buffer_setup_ops);
|
|
if (ret < 0)
|
|
return dev_err_probe(dev, ret, "Couldn't initialise the buffer\n");
|
|
|
|
ret = devm_iio_device_register(dev, indio_dev);
|
|
if (ret)
|
|
return dev_err_probe(dev, ret, "Couldn't register the device\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nxp_sar_adc_suspend(struct device *dev)
|
|
{
|
|
struct nxp_sar_adc *info = iio_priv(dev_get_drvdata(dev));
|
|
|
|
info->pwdn = nxp_sar_adc_disable(info);
|
|
info->inpsamp = nxp_sar_adc_conversion_timing_get(info);
|
|
|
|
clk_disable_unprepare(info->clk);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nxp_sar_adc_resume(struct device *dev)
|
|
{
|
|
struct nxp_sar_adc *info = iio_priv(dev_get_drvdata(dev));
|
|
int ret;
|
|
|
|
ret = clk_prepare_enable(info->clk);
|
|
if (ret)
|
|
return ret;
|
|
|
|
nxp_sar_adc_conversion_timing_set(info, info->inpsamp);
|
|
|
|
if (!info->pwdn)
|
|
nxp_sar_adc_enable(info);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static DEFINE_SIMPLE_DEV_PM_OPS(nxp_sar_adc_pm_ops, nxp_sar_adc_suspend,
|
|
nxp_sar_adc_resume);
|
|
|
|
static const struct nxp_sar_adc_data s32g2_sar_adc_data = {
|
|
.vref_mV = 1800,
|
|
.model = "s32g2-sar-adc",
|
|
};
|
|
|
|
static const struct of_device_id nxp_sar_adc_match[] = {
|
|
{ .compatible = "nxp,s32g2-sar-adc", .data = &s32g2_sar_adc_data },
|
|
{ }
|
|
};
|
|
MODULE_DEVICE_TABLE(of, nxp_sar_adc_match);
|
|
|
|
static struct platform_driver nxp_sar_adc_driver = {
|
|
.probe = nxp_sar_adc_probe,
|
|
.driver = {
|
|
.name = "nxp-sar-adc",
|
|
.of_match_table = nxp_sar_adc_match,
|
|
.pm = pm_sleep_ptr(&nxp_sar_adc_pm_ops),
|
|
},
|
|
};
|
|
module_platform_driver(nxp_sar_adc_driver);
|
|
|
|
MODULE_AUTHOR("NXP");
|
|
MODULE_DESCRIPTION("NXP SAR-ADC driver");
|
|
MODULE_LICENSE("GPL");
|