linux/drivers/iio/industrialio-gts-helper.c

// SPDX-License-Identifier: GPL-2.0-only
/* gain-time-scale conversion helpers for IIO light sensors
 *
 * Copyright (c) 2023 Matti Vaittinen <[email protected]>
 */

#include <linux/device.h>
#include <linux/errno.h>
#include <linux/export.h>
#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/overflow.h>
#include <linux/slab.h>
#include <linux/sort.h>
#include <linux/types.h>
#include <linux/units.h>

#include <linux/iio/iio-gts-helper.h>
#include <linux/iio/types.h>

/**
 * iio_gts_get_gain - Convert scale to total gain
 *
 * Internal helper for converting scale to total gain.
 *
 * @max:	Maximum linearized scale. As an example, when scale is created
 *		in magnitude of NANOs and max scale is 64.1 - The linearized
 *		scale is 64 100 000 000.
 * @scale:	Linearized scale to compute the gain for.
 *
 * Return:	(floored) gain corresponding to the scale. -EINVAL if scale
 *		is invalid.
 */
static int iio_gts_get_gain(const u64 max, const u64 scale)
{}

/**
 * gain_get_scale_fraction - get the gain or time based on scale and known one
 *
 * @max:	Maximum linearized scale. As an example, when scale is created
 *		in magnitude of NANOs and max scale is 64.1 - The linearized
 *		scale is 64 100 000 000.
 * @scale:	Linearized scale to compute the gain/time for.
 * @known:	Either integration time or gain depending on which one is known
 * @unknown:	Pointer to variable where the computed gain/time is stored
 *
 * Internal helper for computing unknown fraction of total gain.
 * Compute either gain or time based on scale and either the gain or time
 * depending on which one is known.
 *
 * Return:	0 on success.
 */
static int gain_get_scale_fraction(const u64 max, u64 scale, int known,
				   int *unknown)
{}

static int iio_gts_delinearize(u64 lin_scale, unsigned long scaler,
			       int *scale_whole, int *scale_nano)
{}

static int iio_gts_linearize(int scale_whole, int scale_nano,
			     unsigned long scaler, u64 *lin_scale)
{}

/**
 * iio_gts_total_gain_to_scale - convert gain to scale
 * @gts:	Gain time scale descriptor
 * @total_gain:	the gain to be converted
 * @scale_int:	Pointer to integral part of the scale (typically val1)
 * @scale_nano:	Pointer to fractional part of the scale (nano or ppb)
 *
 * Convert the total gain value to scale. NOTE: This does not separate gain
 * generated by HW-gain or integration time. It is up to caller to decide what
 * part of the total gain is due to integration time and what due to HW-gain.
 *
 * Return: 0 on success. Negative errno on failure.
 */
int iio_gts_total_gain_to_scale(struct iio_gts *gts, int total_gain,
				int *scale_int, int *scale_nano)
{}
EXPORT_SYMBOL_NS_GPL();

/**
 * iio_gts_purge_avail_scale_table - free-up the available scale tables
 * @gts:	Gain time scale descriptor
 *
 * Free the space reserved by iio_gts_build_avail_scale_table().
 */
static void iio_gts_purge_avail_scale_table(struct iio_gts *gts)
{}

static int iio_gts_gain_cmp(const void *a, const void *b)
{}

static int gain_to_scaletables(struct iio_gts *gts, int **gains, int **scales)
{}

/**
 * iio_gts_build_avail_scale_table - create tables of available scales
 * @gts:	Gain time scale descriptor
 *
 * Build the tables which can represent the available scales based on the
 * originally given gain and time tables. When both time and gain tables are
 * given this results:
 * 1. A set of tables representing available scales for each supported
 *    integration time.
 * 2. A single table listing all the unique scales that any combination of
 *    supported gains and times can provide.
 *
 * NOTE: Space allocated for the tables must be freed using
 * iio_gts_purge_avail_scale_table() when the tables are no longer needed.
 *
 * Return: 0 on success.
 */
static int iio_gts_build_avail_scale_table(struct iio_gts *gts)
{}

static void iio_gts_us_to_int_micro(int *time_us, int *int_micro_times,
				    int num_times)
{}

/**
 * iio_gts_build_avail_time_table - build table of available integration times
 * @gts:	Gain time scale descriptor
 *
 * Build the table which can represent the available times to be returned
 * to users using the read_avail-callback.
 *
 * NOTE: Space allocated for the tables must be freed using
 * iio_gts_purge_avail_time_table() when the tables are no longer needed.
 *
 * Return: 0 on success.
 */
static int iio_gts_build_avail_time_table(struct iio_gts *gts)
{}

/**
 * iio_gts_purge_avail_time_table - free-up the available integration time table
 * @gts:	Gain time scale descriptor
 *
 * Free the space reserved by iio_gts_build_avail_time_table().
 */
static void iio_gts_purge_avail_time_table(struct iio_gts *gts)
{}

/**
 * iio_gts_build_avail_tables - create tables of available scales and int times
 * @gts:	Gain time scale descriptor
 *
 * Build the tables which can represent the available scales and available
 * integration times. Availability tables are built based on the originally
 * given gain and given time tables.
 *
 * When both time and gain tables are
 * given this results:
 * 1. A set of sorted tables representing available scales for each supported
 *    integration time.
 * 2. A single sorted table listing all the unique scales that any combination
 *    of supported gains and times can provide.
 * 3. A sorted table of supported integration times
 *
 * After these tables are built one can use the iio_gts_all_avail_scales(),
 * iio_gts_avail_scales_for_time() and iio_gts_avail_times() helpers to
 * implement the read_avail operations.
 *
 * NOTE: Space allocated for the tables must be freed using
 * iio_gts_purge_avail_tables() when the tables are no longer needed.
 *
 * Return: 0 on success.
 */
static int iio_gts_build_avail_tables(struct iio_gts *gts)
{}

/**
 * iio_gts_purge_avail_tables - free-up the availability tables
 * @gts:	Gain time scale descriptor
 *
 * Free the space reserved by iio_gts_build_avail_tables(). Frees both the
 * integration time and scale tables.
 */
static void iio_gts_purge_avail_tables(struct iio_gts *gts)
{}

static void devm_iio_gts_avail_all_drop(void *res)
{}

/**
 * devm_iio_gts_build_avail_tables - manged add availability tables
 * @dev:	Pointer to the device whose lifetime tables are bound
 * @gts:	Gain time scale descriptor
 *
 * Build the tables which can represent the available scales and available
 * integration times. Availability tables are built based on the originally
 * given gain and given time tables.
 *
 * When both time and gain tables are given this results:
 * 1. A set of sorted tables representing available scales for each supported
 *    integration time.
 * 2. A single sorted table listing all the unique scales that any combination
 *    of supported gains and times can provide.
 * 3. A sorted table of supported integration times
 *
 * After these tables are built one can use the iio_gts_all_avail_scales(),
 * iio_gts_avail_scales_for_time() and iio_gts_avail_times() helpers to
 * implement the read_avail operations.
 *
 * The tables are automatically released upon device detach.
 *
 * Return: 0 on success.
 */
static int devm_iio_gts_build_avail_tables(struct device *dev,
					   struct iio_gts *gts)
{}

static int sanity_check_time(const struct iio_itime_sel_mul *t)
{}

static int sanity_check_gain(const struct iio_gain_sel_pair *g)
{}

static int iio_gts_sanity_check(struct iio_gts *gts)
{}

static int iio_init_iio_gts(int max_scale_int, int max_scale_nano,
			const struct iio_gain_sel_pair *gain_tbl, int num_gain,
			const struct iio_itime_sel_mul *tim_tbl, int num_times,
			struct iio_gts *gts)
{}

/**
 * devm_iio_init_iio_gts - Initialize the gain-time-scale helper
 * @dev:		Pointer to the device whose lifetime gts resources are
 *			bound
 * @max_scale_int:	integer part of the maximum scale value
 * @max_scale_nano:	fraction part of the maximum scale value
 * @gain_tbl:		table describing supported gains
 * @num_gain:		number of gains in the gain table
 * @tim_tbl:		table describing supported integration times. Provide
 *			the integration time table sorted so that the preferred
 *			integration time is in the first array index. The search
 *			functions like the
 *			iio_gts_find_time_and_gain_sel_for_scale() start search
 *			from first provided time.
 * @num_times:		number of times in the time table
 * @gts:		pointer to the helper struct
 *
 * Initialize the gain-time-scale helper for use. Note, gains, times, selectors
 * and multipliers must be positive. Negative values are reserved for error
 * checking. The total gain (maximum gain * maximum time multiplier) must not
 * overflow int. The allocated resources will be released upon device detach.
 *
 * Return: 0 on success.
 */
int devm_iio_init_iio_gts(struct device *dev, int max_scale_int, int max_scale_nano,
			  const struct iio_gain_sel_pair *gain_tbl, int num_gain,
			  const struct iio_itime_sel_mul *tim_tbl, int num_times,
			  struct iio_gts *gts)
{}
EXPORT_SYMBOL_NS_GPL();

/**
 * iio_gts_all_avail_scales - helper for listing all available scales
 * @gts:	Gain time scale descriptor
 * @vals:	Returned array of supported scales
 * @type:	Type of returned scale values
 * @length:	Amount of returned values in array
 *
 * Return: a value suitable to be returned from read_avail or a negative error.
 */
int iio_gts_all_avail_scales(struct iio_gts *gts, const int **vals, int *type,
			     int *length)
{}
EXPORT_SYMBOL_NS_GPL();

/**
 * iio_gts_avail_scales_for_time - list scales for integration time
 * @gts:	Gain time scale descriptor
 * @time:	Integration time for which the scales are listed
 * @vals:	Returned array of supported scales
 * @type:	Type of returned scale values
 * @length:	Amount of returned values in array
 *
 * Drivers which do not allow scale setting to change integration time can
 * use this helper to list only the scales which are valid for given integration
 * time.
 *
 * Return: a value suitable to be returned from read_avail or a negative error.
 */
int iio_gts_avail_scales_for_time(struct iio_gts *gts, int time,
				  const int **vals, int *type, int *length)
{}
EXPORT_SYMBOL_NS_GPL();

/**
 * iio_gts_avail_times - helper for listing available integration times
 * @gts:	Gain time scale descriptor
 * @vals:	Returned array of supported times
 * @type:	Type of returned scale values
 * @length:	Amount of returned values in array
 *
 * Return: a value suitable to be returned from read_avail or a negative error.
 */
int iio_gts_avail_times(struct iio_gts *gts,  const int **vals, int *type,
			int *length)
{}
EXPORT_SYMBOL_NS_GPL();

/**
 * iio_gts_find_sel_by_gain - find selector corresponding to a HW-gain
 * @gts:	Gain time scale descriptor
 * @gain:	HW-gain for which matching selector is searched for
 *
 * Return:	a selector matching given HW-gain or -EINVAL if selector was
 *		not found.
 */
int iio_gts_find_sel_by_gain(struct iio_gts *gts, int gain)
{}
EXPORT_SYMBOL_NS_GPL();

/**
 * iio_gts_find_gain_by_sel - find HW-gain corresponding to a selector
 * @gts:	Gain time scale descriptor
 * @sel:	selector for which matching HW-gain is searched for
 *
 * Return:	a HW-gain matching given selector or -EINVAL if HW-gain was not
 *		found.
 */
int iio_gts_find_gain_by_sel(struct iio_gts *gts, int sel)
{}
EXPORT_SYMBOL_NS_GPL();

/**
 * iio_gts_get_min_gain - find smallest valid HW-gain
 * @gts:	Gain time scale descriptor
 *
 * Return:	The smallest HW-gain -EINVAL if no HW-gains were in the tables.
 */
int iio_gts_get_min_gain(struct iio_gts *gts)
{}
EXPORT_SYMBOL_NS_GPL();

/**
 * iio_find_closest_gain_low - Find the closest lower matching gain
 * @gts:	Gain time scale descriptor
 * @gain:	HW-gain for which the closest match is searched
 * @in_range:	indicate if the @gain was actually in the range of
 *		supported gains.
 *
 * Search for closest supported gain that is lower than or equal to the
 * gain given as a parameter. This is usable for drivers which do not require
 * user to request exact matching gain but rather for rounding to a supported
 * gain value which is equal or lower (setting lower gain is typical for
 * avoiding saturation)
 *
 * Return:	The closest matching supported gain or -EINVAL if @gain
 *		was smaller than the smallest supported gain.
 */
int iio_find_closest_gain_low(struct iio_gts *gts, int gain, bool *in_range)
{}
EXPORT_SYMBOL_NS_GPL();

static int iio_gts_get_int_time_gain_multiplier_by_sel(struct iio_gts *gts,
						       int sel)
{}

/**
 * iio_gts_find_gain_for_scale_using_time - Find gain by time and scale
 * @gts:	Gain time scale descriptor
 * @time_sel:	Integration time selector corresponding to the time gain is
 *		searched for
 * @scale_int:	Integral part of the scale (typically val1)
 * @scale_nano:	Fractional part of the scale (nano or ppb)
 * @gain:	Pointer to value where gain is stored.
 *
 * In some cases the light sensors may want to find a gain setting which
 * corresponds given scale and integration time. Sensors which fill the
 * gain and time tables may use this helper to retrieve the gain.
 *
 * Return:	0 on success. -EINVAL if gain matching the parameters is not
 *		found.
 */
static int iio_gts_find_gain_for_scale_using_time(struct iio_gts *gts, int time_sel,
						  int scale_int, int scale_nano,
						  int *gain)
{}

/**
 * iio_gts_find_gain_sel_for_scale_using_time - Fetch gain selector.
 * @gts:	Gain time scale descriptor
 * @time_sel:	Integration time selector corresponding to the time gain is
 *		searched for
 * @scale_int:	Integral part of the scale (typically val1)
 * @scale_nano:	Fractional part of the scale (nano or ppb)
 * @gain_sel:	Pointer to value where gain selector is stored.
 *
 * See iio_gts_find_gain_for_scale_using_time() for more information
 */
int iio_gts_find_gain_sel_for_scale_using_time(struct iio_gts *gts, int time_sel,
					       int scale_int, int scale_nano,
					       int *gain_sel)
{}
EXPORT_SYMBOL_NS_GPL();

static int iio_gts_get_total_gain(struct iio_gts *gts, int gain, int time)
{}

static int iio_gts_get_scale_linear(struct iio_gts *gts, int gain, int time,
				    u64 *scale)
{}

/**
 * iio_gts_get_scale - get scale based on integration time and HW-gain
 * @gts:	Gain time scale descriptor
 * @gain:	HW-gain for which the scale is computed
 * @time:	Integration time for which the scale is computed
 * @scale_int:	Integral part of the scale (typically val1)
 * @scale_nano:	Fractional part of the scale (nano or ppb)
 *
 * Compute scale matching the integration time and HW-gain given as parameter.
 *
 * Return: 0 on success.
 */
int iio_gts_get_scale(struct iio_gts *gts, int gain, int time, int *scale_int,
		      int *scale_nano)
{}
EXPORT_SYMBOL_NS_GPL();

/**
 * iio_gts_find_new_gain_sel_by_old_gain_time - compensate for time change
 * @gts:		Gain time scale descriptor
 * @old_gain:		Previously set gain
 * @old_time_sel:	Selector corresponding previously set time
 * @new_time_sel:	Selector corresponding new time to be set
 * @new_gain:		Pointer to value where new gain is to be written
 *
 * We may want to mitigate the scale change caused by setting a new integration
 * time (for a light sensor) by also updating the (HW)gain. This helper computes
 * new gain value to maintain the scale with new integration time.
 *
 * Return: 0 if an exactly matching supported new gain was found. When a
 * non-zero value is returned, the @new_gain will be set to a negative or
 * positive value. The negative value means that no gain could be computed.
 * Positive value will be the "best possible new gain there could be". There
 * can be two reasons why finding the "best possible" new gain is not deemed
 * successful. 1) This new value cannot be supported by the hardware. 2) The new
 * gain required to maintain the scale would not be an integer. In this case,
 * the "best possible" new gain will be a floored optimal gain, which may or
 * may not be supported by the hardware.
 */
int iio_gts_find_new_gain_sel_by_old_gain_time(struct iio_gts *gts,
					       int old_gain, int old_time_sel,
					       int new_time_sel, int *new_gain)
{}
EXPORT_SYMBOL_NS_GPL();

/**
 * iio_gts_find_new_gain_by_old_gain_time - compensate for time change
 * @gts:		Gain time scale descriptor
 * @old_gain:		Previously set gain
 * @old_time:		Selector corresponding previously set time
 * @new_time:		Selector corresponding new time to be set
 * @new_gain:		Pointer to value where new gain is to be written
 *
 * We may want to mitigate the scale change caused by setting a new integration
 * time (for a light sensor) by also updating the (HW)gain. This helper computes
 * new gain value to maintain the scale with new integration time.
 *
 * Return: 0 if an exactly matching supported new gain was found. When a
 * non-zero value is returned, the @new_gain will be set to a negative or
 * positive value. The negative value means that no gain could be computed.
 * Positive value will be the "best possible new gain there could be". There
 * can be two reasons why finding the "best possible" new gain is not deemed
 * successful. 1) This new value cannot be supported by the hardware. 2) The new
 * gain required to maintain the scale would not be an integer. In this case,
 * the "best possible" new gain will be a floored optimal gain, which may or
 * may not be supported by the hardware.
 */
int iio_gts_find_new_gain_by_old_gain_time(struct iio_gts *gts, int old_gain,
					   int old_time, int new_time,
					   int *new_gain)
{}
EXPORT_SYMBOL_NS_GPL();

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