linux/drivers/iio/adc/mcp3564.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * IIO driver for MCP356X/MCP356XR and MCP346X/MCP346XR series ADC chip family
 *
 * Copyright (C) 2022-2023 Microchip Technology Inc. and its subsidiaries
 *
 * Author: Marius Cristea <[email protected]>
 *
 * Datasheet for MCP3561, MCP3562, MCP3564 can be found here:
 * https://ww1.microchip.com/downloads/aemDocuments/documents/MSLD/ProductDocuments/DataSheets/MCP3561-2-4-Family-Data-Sheet-DS20006181C.pdf
 * Datasheet for MCP3561R, MCP3562R, MCP3564R can be found here:
 * https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/MCP3561_2_4R-Data-Sheet-DS200006391C.pdf
 * Datasheet for MCP3461, MCP3462, MCP3464 can be found here:
 * https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/MCP3461-2-4-Two-Four-Eight-Channel-153.6-ksps-Low-Noise-16-Bit-Delta-Sigma-ADC-Data-Sheet-20006180D.pdf
 * Datasheet for MCP3461R, MCP3462R, MCP3464R can be found here:
 * https://ww1.microchip.com/downloads/aemDocuments/documents/APID/ProductDocuments/DataSheets/MCP3461-2-4R-Family-Data-Sheet-DS20006404C.pdf
 */

#include <linux/bitfield.h>
#include <linux/iopoll.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#include <linux/units.h>
#include <linux/util_macros.h>

#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>

#define MCP3564_ADCDATA_REG

#define MCP3564_CONFIG0_REG
#define MCP3564_CONFIG0_ADC_MODE_MASK
/* Current Source/Sink Selection Bits for Sensor Bias */
#define MCP3564_CONFIG0_CS_SEL_MASK
/* Internal clock is selected and AMCLK is present on the analog master clock output pin */
#define MCP3564_CONFIG0_USE_INT_CLK_OUTPUT_EN
/* Internal clock is selected and no clock output is present on the CLK pin */
#define MCP3564_CONFIG0_USE_INT_CLK
/* External digital clock */
#define MCP3564_CONFIG0_USE_EXT_CLK
/* External digital clock (default) */
#define MCP3564_CONFIG0_USE_EXT_CLK_DEFAULT
#define MCP3564_CONFIG0_CLK_SEL_MASK
#define MCP3456_CONFIG0_BIT6_DEFAULT
#define MCP3456_CONFIG0_VREF_MASK

#define MCP3564_CONFIG1_REG
#define MCP3564_CONFIG1_OVERSPL_RATIO_MASK

#define MCP3564_CONFIG2_REG
#define MCP3564_CONFIG2_AZ_REF_MASK
#define MCP3564_CONFIG2_AZ_MUX_MASK

#define MCP3564_CONFIG2_HARDWARE_GAIN_MASK
#define MCP3564_DEFAULT_HARDWARE_GAIN
#define MCP3564_CONFIG2_BOOST_CURRENT_MASK

#define MCP3564_CONFIG3_REG
#define MCP3464_CONFIG3_EN_GAINCAL_MASK
#define MCP3464_CONFIG3_EN_OFFCAL_MASK
#define MCP3464_CONFIG3_EN_CRCCOM_MASK
#define MCP3464_CONFIG3_CRC_FORMAT_MASK
/*
 * ADC Output Data Format 32-bit (25-bit right justified data + Channel ID):
 *                CHID[3:0] + SGN extension (4 bits) + 24-bit ADC data.
 *        It allows overrange with the SGN extension.
 */
#define MCP3464_CONFIG3_DATA_FMT_32B_WITH_CH_ID
/*
 * ADC Output Data Format 32-bit (25-bit right justified data):
 *                SGN extension (8-bit) + 24-bit ADC data.
 *        It allows overrange with the SGN extension.
 */
#define MCP3464_CONFIG3_DATA_FMT_32B_SGN_EXT
/*
 * ADC Output Data Format 32-bit (24-bit left justified data):
 *                24-bit ADC data + 0x00 (8-bit).
 *        It does not allow overrange (ADC code locked to 0xFFFFFF or 0x800000).
 */
#define MCP3464_CONFIG3_DATA_FMT_32B_LEFT_JUSTIFIED
/*
 * ADC Output Data Format 24-bit (default ADC coding):
 *                24-bit ADC data.
 *        It does not allow overrange (ADC code locked to 0xFFFFFF or 0x800000).
 */
#define MCP3464_CONFIG3_DATA_FMT_24B
#define MCP3464_CONFIG3_DATA_FORMAT_MASK

/* Continuous Conversion mode or continuous conversion cycle in SCAN mode. */
#define MCP3464_CONFIG3_CONV_MODE_CONTINUOUS
/*
 * One-shot conversion or one-shot cycle in SCAN mode. It sets ADC_MODE[1:0] to ‘10’
 * (standby) at the end of the conversion or at the end of the conversion cycle in SCAN mode.
 */
#define MCP3464_CONFIG3_CONV_MODE_ONE_SHOT_STANDBY
/*
 * One-shot conversion or one-shot cycle in SCAN mode. It sets ADC_MODE[1:0] to ‘0x’ (ADC
 * Shutdown) at the end of the conversion or at the end of the conversion cycle in SCAN
 * mode (default).
 */
#define MCP3464_CONFIG3_CONV_MODE_ONE_SHOT_SHUTDOWN
#define MCP3464_CONFIG3_CONV_MODE_MASK

#define MCP3564_IRQ_REG
#define MCP3464_EN_STP_MASK
#define MCP3464_EN_FASTCMD_MASK
#define MCP3464_IRQ_MODE_0_MASK
#define MCP3464_IRQ_MODE_1_MASK
#define MCP3564_POR_STATUS_MASK
#define MCP3564_CRCCFG_STATUS_MASK
#define MCP3564_DATA_READY_MASK

#define MCP3564_MUX_REG
#define MCP3564_MUX_VIN_P_MASK
#define MCP3564_MUX_VIN_N_MASK
#define MCP3564_MUX_SET(x, y)

#define MCP3564_SCAN_REG
#define MCP3564_SCAN_CH_SEL_MASK
#define MCP3564_SCAN_CH_SEL_SET(x)
#define MCP3564_SCAN_DELAY_TIME_MASK
#define MCP3564_SCAN_DELAY_TIME_SET(x)
#define MCP3564_SCAN_DEFAULT_VALUE

#define MCP3564_TIMER_REG
#define MCP3564_TIMER_DEFAULT_VALUE

#define MCP3564_OFFSETCAL_REG
#define MCP3564_DEFAULT_OFFSETCAL

#define MCP3564_GAINCAL_REG
#define MCP3564_DEFAULT_GAINCAL

#define MCP3564_RESERVED_B_REG

#define MCP3564_RESERVED_C_REG
#define MCP3564_C_REG_DEFAULT
#define MCP3564R_C_REG_DEFAULT

#define MCP3564_LOCK_REG
#define MCP3564_LOCK_WRITE_ACCESS_PASSWORD
#define MCP3564_RESERVED_E_REG
#define MCP3564_CRCCFG_REG

#define MCP3564_CMD_HW_ADDR_MASK
#define MCP3564_CMD_ADDR_MASK

#define MCP3564_HW_ADDR_MASK

#define MCP3564_FASTCMD_START
#define MCP3564_FASTCMD_RESET

#define MCP3461_HW_ID
#define MCP3462_HW_ID
#define MCP3464_HW_ID

#define MCP3561_HW_ID
#define MCP3562_HW_ID
#define MCP3564_HW_ID
#define MCP3564_HW_ID_MASK

#define MCP3564R_INT_VREF_MV

#define MCP3564_DATA_READY_TIMEOUT_MS

#define MCP3564_MAX_PGA
#define MCP3564_MAX_BURNOUT_IDX
#define MCP3564_MAX_CHANNELS

enum mcp3564_ids {};

enum mcp3564_delay_time {};

enum mcp3564_adc_conversion_mode {};

enum mcp3564_adc_bias_current {};

enum mcp3564_burnout {};

enum mcp3564_channel_names {};

enum mcp3564_oversampling {};

static const unsigned int mcp3564_oversampling_avail[] =;

/*
 * Current Source/Sink Selection Bits for Sensor Bias (source on VIN+/sink on VIN-)
 */
static const int mcp3564_burnout_avail[][2] =;

/*
 * BOOST[1:0]: ADC Bias Current Selection
 */
static const char * const mcp3564_boost_current_avail[] =;

/*
 * Calibration bias values
 */
static const int mcp3564_calib_bias[] =;

/*
 * Calibration scale values
 * The Gain Error Calibration register (GAINCAL) is an
 * unsigned 24-bit register that holds the digital gain error
 * calibration value, GAINCAL which could be calculated by
 * GAINCAL (V/V) = (GAINCAL[23:0])/8388608
 * The gain error calibration value range in equivalent voltage is [0; 2-2^(-23)]
 */
static const unsigned int mcp3564_calib_scale[] =;

/* Programmable hardware gain x1/3, x1, x2, x4, x8, x16, x32, x64 */
static const int mcp3564_hwgain_frac[] =;

static const char *mcp3564_channel_labels[2] =;

/**
 * struct mcp3564_chip_info - chip specific data
 * @name:		device name
 * @num_channels:	number of channels
 * @resolution:		ADC resolution
 * @have_vref:		does the hardware have an internal voltage reference?
 */
struct mcp3564_chip_info {};

/**
 * struct mcp3564_state - working data for a ADC device
 * @chip_info:		chip specific data
 * @spi:		SPI device structure
 * @vref_mv:		voltage reference value in miliVolts
 * @lock:		synchronize access to driver's state members
 * @dev_addr:		hardware device address
 * @oversampling:	the index inside oversampling list of the ADC
 * @hwgain:		the index inside hardware gain list of the ADC
 * @scale_tbls:		table with precalculated scale
 * @calib_bias:		calibration bias value
 * @calib_scale:	calibration scale value
 * @current_boost_mode:	the index inside current boost list of the ADC
 * @burnout_mode:	the index inside current bias list of the ADC
 * @auto_zeroing_mux:	set if ADC auto-zeroing algorithm is enabled
 * @auto_zeroing_ref:	set if ADC auto-Zeroing Reference Buffer Setting is enabled
 * @have_vref:		does the ADC have an internal voltage reference?
 * @labels:		table with channels labels
 */
struct mcp3564_state {};

static inline u8 mcp3564_cmd_write(u8 chip_addr, u8 reg)
{}

static inline u8 mcp3564_cmd_read(u8 chip_addr, u8 reg)
{}

static int mcp3564_read_8bits(struct mcp3564_state *adc, u8 reg, u8 *val)
{}

static int mcp3564_read_16bits(struct mcp3564_state *adc, u8 reg, u16 *val)
{}

static int mcp3564_read_32bits(struct mcp3564_state *adc, u8 reg, u32 *val)
{}

static int mcp3564_write_8bits(struct mcp3564_state *adc, u8 reg, u8 val)
{}

static int mcp3564_write_24bits(struct mcp3564_state *adc, u8 reg, u32 val)
{}

static int mcp3564_fast_cmd(struct mcp3564_state *adc, u8 fast_cmd)
{}

static int mcp3564_update_8bits(struct mcp3564_state *adc, u8 reg, u32 mask, u8 val)
{}

static int mcp3564_set_current_boost_mode(struct iio_dev *indio_dev,
					  const struct iio_chan_spec *chan,
					  unsigned int mode)
{}

static int mcp3564_get_current_boost_mode(struct iio_dev *indio_dev,
					  const struct iio_chan_spec *chan)
{}

static const struct iio_enum mcp3564_current_boost_mode_enum =;

static const struct iio_chan_spec_ext_info mcp3564_ext_info[] =;

static ssize_t mcp3564_auto_zeroing_mux_show(struct device *dev,
					     struct device_attribute *attr,
					     char *buf)
{}

static ssize_t mcp3564_auto_zeroing_mux_store(struct device *dev,
					      struct device_attribute *attr,
					      const char *buf, size_t len)
{}

static ssize_t mcp3564_auto_zeroing_ref_show(struct device *dev,
					     struct device_attribute *attr,
					     char *buf)
{}

static ssize_t mcp3564_auto_zeroing_ref_store(struct device *dev,
					      struct device_attribute *attr,
					      const char *buf, size_t len)
{}

static const struct iio_chan_spec mcp3564_channel_template =;

static const struct iio_chan_spec mcp3564_temp_channel_template =;

static const struct iio_chan_spec mcp3564_burnout_channel_template =;

/*
 * Number of channels could be calculated:
 * num_channels = single_ended_input + differential_input + temperature + burnout
 * Eg. for MCP3561 (only 2 channels available: CH0 and CH1)
 * single_ended_input = (CH0 - GND), (CH1 -  GND) = 2
 * differential_input = (CH0 - CH1), (CH0 -  CH0) = 2
 * num_channels = 2 + 2 + 2
 * Generic formula is:
 * num_channels = P^R(Number_of_single_ended_channels, 2) + 2 (temperature + burnout channels)
 * P^R(Number_of_single_ended_channels, 2) is Permutations with Replacement of
 *     Number_of_single_ended_channels taken by 2
 */
static const struct mcp3564_chip_info mcp3564_chip_infos_tbl[] =;

static int mcp3564_read_single_value(struct iio_dev *indio_dev,
				     struct iio_chan_spec const *channel,
				     int *val)
{}

static int mcp3564_read_avail(struct iio_dev *indio_dev,
			      struct iio_chan_spec const *channel,
			      const int **vals, int *type,
			      int *length, long mask)
{}

static int mcp3564_read_raw(struct iio_dev *indio_dev,
			    struct iio_chan_spec const *channel,
			    int *val, int *val2, long mask)
{}

static int mcp3564_write_raw_get_fmt(struct iio_dev *indio_dev,
				     struct iio_chan_spec const *chan,
				     long info)
{}

static int mcp3564_write_raw(struct iio_dev *indio_dev,
			     struct iio_chan_spec const *channel, int val,
			     int val2, long mask)
{}

static int mcp3564_read_label(struct iio_dev *indio_dev,
			      struct iio_chan_spec const *chan, char *label)
{}

static int mcp3564_parse_fw_children(struct iio_dev *indio_dev)
{}

static void mcp3564_fill_scale_tbls(struct mcp3564_state *adc)
{}

static int mcp3564_config(struct iio_dev *indio_dev, bool *use_internal_vref_attr)
{}

static IIO_DEVICE_ATTR(auto_zeroing_ref_enable, 0644,
		       mcp3564_auto_zeroing_ref_show,
		       mcp3564_auto_zeroing_ref_store, 0);

static IIO_DEVICE_ATTR(auto_zeroing_mux_enable, 0644,
		       mcp3564_auto_zeroing_mux_show,
		       mcp3564_auto_zeroing_mux_store, 0);

static struct attribute *mcp3564_attributes[] =;

static struct attribute *mcp3564r_attributes[] =;

static struct attribute_group mcp3564_attribute_group =;

static struct attribute_group mcp3564r_attribute_group =;

static const struct iio_info mcp3564_info =;

static const struct iio_info mcp3564r_info =;

static int mcp3564_probe(struct spi_device *spi)
{}

static const struct of_device_id mcp3564_dt_ids[] =;
MODULE_DEVICE_TABLE(of, mcp3564_dt_ids);

static const struct spi_device_id mcp3564_id[] =;
MODULE_DEVICE_TABLE(spi, mcp3564_id);

static struct spi_driver mcp3564_driver =;

module_spi_driver();

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();