linux/drivers/iio/resolver/ad2s1210.c

// SPDX-License-Identifier: GPL-2.0
/*
 * ad2s1210.c support for the ADI Resolver to Digital Converters: AD2S1210
 *
 * Copyright (c) 2010-2010 Analog Devices Inc.
 * Copyright (c) 2023 BayLibre, SAS
 *
 * Device register to IIO ABI mapping:
 *
 * Register                    | Addr | IIO ABI (sysfs)
 * ----------------------------|------|-------------------------------------------
 * DOS Overrange Threshold     | 0x89 | events/in_altvoltage0_thresh_rising_value
 * DOS Mismatch Threshold      | 0x8A | events/in_altvoltage0_mag_rising_value
 * DOS Reset Maximum Threshold | 0x8B | events/in_altvoltage0_mag_rising_reset_max
 * DOS Reset Minimum Threshold | 0x8C | events/in_altvoltage0_mag_rising_reset_min
 * LOT High Threshold          | 0x8D | events/in_angl1_thresh_rising_value
 * LOT Low Threshold [1]       | 0x8E | events/in_angl1_thresh_rising_hysteresis
 * Excitation Frequency        | 0x91 | out_altvoltage0_frequency
 * Control                     | 0x92 | *as bit fields*
 *   Phase lock range          | D5   | events/in_phase0_mag_rising_value
 *   Hysteresis                | D4   | in_angl0_hysteresis
 *   Encoder resolution        | D3:2 | *not implemented*
 *   Resolution                | D1:0 | *device tree: assigned-resolution-bits*
 * Soft Reset                  | 0xF0 | [2]
 * Fault                       | 0xFF | *not implemented*
 *
 * [1]: The value written to the LOT low register is high value minus the
 * hysteresis.
 * [2]: Soft reset is performed when `out_altvoltage0_frequency` is written.
 *
 * Fault to event mapping:
 *
 * Fault                                   |    | Channel     | Type   | Direction
 * ----------------------------------------|----|---------------------------------
 * Sine/cosine inputs clipped [3]          | D7 | altvoltage1 | mag    | either
 * Sine/cosine inputs below LOS            | D6 | altvoltage0 | thresh | falling
 * Sine/cosine inputs exceed DOS overrange | D5 | altvoltage0 | thresh | rising
 * Sine/cosine inputs exceed DOS mismatch  | D4 | altvoltage0 | mag    | rising
 * Tracking error exceeds LOT              | D3 | angl1       | thresh | rising
 * Velocity exceeds maximum tracking rate  | D2 | anglvel0    | mag    | rising
 * Phase error exceeds phase lock range    | D1 | phase0      | mag    | rising
 * Configuration parity error              | D0 | *writes to kernel log*
 *
 * [3]: The chip does not differentiate between fault on sine vs. cosine so
 * there will also be an event on the altvoltage2 channel.
 */

#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/sysfs.h>
#include <linux/types.h>

#include <linux/iio/buffer.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>

/* control register flags */
#define AD2S1210_ADDRESS_DATA
#define AD2S1210_PHASE_LOCK_RANGE_44
#define AD2S1210_ENABLE_HYSTERESIS
#define AD2S1210_SET_ENRES
#define AD2S1210_SET_RES

/* fault register flags */
#define AD2S1210_FAULT_CLIP
#define AD2S1210_FAULT_LOS
#define AD2S1210_FAULT_DOS_OVR
#define AD2S1210_FAULT_DOS_MIS
#define AD2S1210_FAULT_LOT
#define AD2S1210_FAULT_VELOCITY
#define AD2S1210_FAULT_PHASE
#define AD2S1210_FAULT_CONFIG_PARITY

#define AD2S1210_REG_POSITION_MSB
#define AD2S1210_REG_POSITION_LSB
#define AD2S1210_REG_VELOCITY_MSB
#define AD2S1210_REG_VELOCITY_LSB
#define AD2S1210_REG_LOS_THRD
#define AD2S1210_REG_DOS_OVR_THRD
#define AD2S1210_REG_DOS_MIS_THRD
#define AD2S1210_REG_DOS_RST_MAX_THRD
#define AD2S1210_REG_DOS_RST_MIN_THRD
#define AD2S1210_REG_LOT_HIGH_THRD
#define AD2S1210_REG_LOT_LOW_THRD
#define AD2S1210_REG_EXCIT_FREQ
#define AD2S1210_REG_CONTROL
#define AD2S1210_REG_SOFT_RESET
#define AD2S1210_REG_FAULT

#define AD2S1210_MIN_CLKIN
#define AD2S1210_MAX_CLKIN
#define AD2S1210_MIN_EXCIT
#define AD2S1210_DEF_EXCIT
#define AD2S1210_MAX_EXCIT
#define AD2S1210_MIN_FCW
#define AD2S1210_MAX_FCW

/* 44 degrees ~= 0.767945 radians */
#define PHASE_44_DEG_TO_RAD_INT
#define PHASE_44_DEG_TO_RAD_MICRO
/* 360 degrees ~= 6.283185 radians */
#define PHASE_360_DEG_TO_RAD_INT
#define PHASE_360_DEG_TO_RAD_MICRO

/* Threshold voltage registers have 1 LSB == 38 mV */
#define THRESHOLD_MILLIVOLT_PER_LSB
/* max voltage for threshold registers is 0x7F * 38 mV */
#define THRESHOLD_RANGE_STR

#define FAULT_ONESHOT(bit, new, old)

enum ad2s1210_mode {};

enum ad2s1210_resolution {};

struct ad2s1210_state {};

static int ad2s1210_set_mode(struct ad2s1210_state *st, enum ad2s1210_mode mode)
{}

/*
 * Writes the given data to the given register address.
 *
 * If the mode is configurable, the device will first be placed in
 * configuration mode.
 */
static int ad2s1210_regmap_reg_write(void *context, unsigned int reg,
				     unsigned int val)
{}

/*
 * Reads value from one of the registers.
 *
 * If the mode is configurable, the device will first be placed in
 * configuration mode.
 */
static int ad2s1210_regmap_reg_read(void *context, unsigned int reg,
				    unsigned int *val)
{}

/*
 * Toggles the SAMPLE line on the AD2S1210 to latch in the current position,
 * velocity, and faults.
 *
 * Must be called with lock held.
 */
static void ad2s1210_toggle_sample_line(struct ad2s1210_state *st)
{}

/*
 * Sets the excitation frequency and performs software reset.
 *
 * Must be called with lock held.
 */
static int ad2s1210_reinit_excitation_frequency(struct ad2s1210_state *st,
						u16 fexcit)
{}

static void ad2s1210_push_events(struct iio_dev *indio_dev,
				 u8 flags, s64 timestamp)
{}

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

static int ad2s1210_get_hysteresis(struct ad2s1210_state *st, int *val)
{}

static int ad2s1210_set_hysteresis(struct ad2s1210_state *st, int val)
{}

static int ad2s1210_get_phase_lock_range(struct ad2s1210_state *st,
					 int *val, int *val2)
{}

static int ad2s1210_set_phase_lock_range(struct ad2s1210_state *st,
					 int val, int val2)
{}

/* map resolution to microradians/LSB for LOT registers */
static const int ad2s1210_lot_threshold_urad_per_lsb[] =;

static int ad2s1210_get_voltage_threshold(struct ad2s1210_state *st,
					  unsigned int reg, int *val)
{}

static int ad2s1210_set_voltage_threshold(struct ad2s1210_state *st,
					  unsigned int reg, int val)
{}

static int ad2s1210_get_lot_high_threshold(struct ad2s1210_state *st,
					   int *val, int *val2)
{}

static int ad2s1210_set_lot_high_threshold(struct ad2s1210_state *st,
					   int val, int val2)
{}

static int ad2s1210_get_lot_low_threshold(struct ad2s1210_state *st,
					  int *val, int *val2)
{}

static int ad2s1210_set_lot_low_threshold(struct ad2s1210_state *st,
					  int val, int val2)
{}

static int ad2s1210_get_excitation_frequency(struct ad2s1210_state *st, int *val)
{}

static int ad2s1210_set_excitation_frequency(struct ad2s1210_state *st, int val)
{}

static const int ad2s1210_velocity_scale[] =;

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

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

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

static const struct iio_event_spec ad2s1210_position_event_spec[] =;

static const struct iio_event_spec ad2s1210_velocity_event_spec[] =;

static const struct iio_event_spec ad2s1210_phase_event_spec[] =;

static const struct iio_event_spec ad2s1210_monitor_signal_event_spec[] =;

static const struct iio_event_spec ad2s1210_sin_cos_event_spec[] =;

static const struct iio_chan_spec ad2s1210_channels[] =;

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

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

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

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

static IIO_CONST_ATTR(in_phase0_mag_rising_value_available,
		      __stringify(PHASE_44_DEG_TO_RAD_INT) "."
		      __stringify(PHASE_44_DEG_TO_RAD_MICRO) " "
		      __stringify(PHASE_360_DEG_TO_RAD_INT) "."
		      __stringify(PHASE_360_DEG_TO_RAD_MICRO));
static IIO_CONST_ATTR(in_altvoltage0_thresh_falling_value_available,
		      THRESHOLD_RANGE_STR);
static IIO_CONST_ATTR(in_altvoltage0_thresh_rising_value_available,
		      THRESHOLD_RANGE_STR);
static IIO_CONST_ATTR(in_altvoltage0_mag_rising_value_available,
		      THRESHOLD_RANGE_STR);
static IIO_DEVICE_ATTR(in_altvoltage0_mag_rising_reset_max, 0644,
		       event_attr_voltage_reg_show, event_attr_voltage_reg_store,
		       AD2S1210_REG_DOS_RST_MAX_THRD);
static IIO_CONST_ATTR(in_altvoltage0_mag_rising_reset_max_available, THRESHOLD_RANGE_STR);
static IIO_DEVICE_ATTR(in_altvoltage0_mag_rising_reset_min, 0644,
		       event_attr_voltage_reg_show, event_attr_voltage_reg_store,
		       AD2S1210_REG_DOS_RST_MIN_THRD);
static IIO_CONST_ATTR(in_altvoltage0_mag_rising_reset_min_available, THRESHOLD_RANGE_STR);
static IIO_DEVICE_ATTR_RO(in_angl1_thresh_rising_value_available, 0);
static IIO_DEVICE_ATTR_RO(in_angl1_thresh_rising_hysteresis_available, 0);

static struct attribute *ad2s1210_event_attributes[] =;

static const struct attribute_group ad2s1210_event_attribute_group =;

static int ad2s1210_initial(struct ad2s1210_state *st)
{}

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

static int ad2s1210_read_event_value(struct iio_dev *indio_dev,
				     const struct iio_chan_spec *chan,
				     enum iio_event_type type,
				     enum iio_event_direction dir,
				     enum iio_event_info info,
				     int *val, int *val2)
{}

static int ad2s1210_write_event_value(struct iio_dev *indio_dev,
				      const struct iio_chan_spec *chan,
				      enum iio_event_type type,
				      enum iio_event_direction dir,
				      enum iio_event_info info,
				      int val, int val2)
{}

static int ad2s1210_read_event_label(struct iio_dev *indio_dev,
				     struct iio_chan_spec const *chan,
				     enum iio_event_type type,
				     enum iio_event_direction dir,
				     char *label)
{}

static int ad2s1210_debugfs_reg_access(struct iio_dev *indio_dev,
				       unsigned int reg, unsigned int writeval,
				       unsigned int *readval)
{}

static irqreturn_t ad2s1210_trigger_handler(int irq, void *p)
{}

static const struct iio_info ad2s1210_info =;

static int ad2s1210_setup_properties(struct ad2s1210_state *st)
{}

static int ad2s1210_setup_clocks(struct ad2s1210_state *st)
{}

static int ad2s1210_setup_gpios(struct ad2s1210_state *st)
{}

static const struct regmap_range ad2s1210_regmap_readable_ranges[] =;

static const struct regmap_access_table ad2s1210_regmap_rd_table =;

static const struct regmap_range ad2s1210_regmap_writeable_ranges[] =;

static const struct regmap_access_table ad2s1210_regmap_wr_table =;

static int ad2s1210_setup_regmap(struct ad2s1210_state *st)
{}

static int ad2s1210_probe(struct spi_device *spi)
{}

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

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

static struct spi_driver ad2s1210_driver =;
module_spi_driver();

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