207 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			207 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* SPDX-License-Identifier: GPL-2.0-only */
 | |
| /* gain-time-scale conversion helpers for IIO light sensors
 | |
|  *
 | |
|  * Copyright (c) 2023 Matti Vaittinen <mazziesaccount@gmail.com>
 | |
|  */
 | |
| 
 | |
| #ifndef __IIO_GTS_HELPER__
 | |
| #define __IIO_GTS_HELPER__
 | |
| 
 | |
| #include <linux/types.h>
 | |
| 
 | |
| struct device;
 | |
| 
 | |
| /**
 | |
|  * struct iio_gain_sel_pair - gain - selector values
 | |
|  *
 | |
|  * In many cases devices like light sensors allow setting signal amplification
 | |
|  * (gain) using a register interface. This structure describes amplification
 | |
|  * and corresponding selector (register value)
 | |
|  *
 | |
|  * @gain:	Gain (multiplication) value. Gain must be positive, negative
 | |
|  *		values are reserved for error handling.
 | |
|  * @sel:	Selector (usually register value) used to indicate this gain.
 | |
|  *		NOTE: Only selectors >= 0 supported.
 | |
|  */
 | |
| struct iio_gain_sel_pair {
 | |
| 	int gain;
 | |
| 	int sel;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * struct iio_itime_sel_mul - integration time description
 | |
|  *
 | |
|  * In many cases devices like light sensors allow setting the duration of
 | |
|  * collecting data. Typically this duration has also an impact to the magnitude
 | |
|  * of measured values (gain). This structure describes the relation of
 | |
|  * integration time and amplification as well as corresponding selector
 | |
|  * (register value).
 | |
|  *
 | |
|  * An example could be a sensor allowing 50, 100, 200 and 400 mS times. The
 | |
|  * respective multiplication values could be 50 mS => 1, 100 mS => 2,
 | |
|  * 200 mS => 4 and 400 mS => 8 assuming the impact of integration time would be
 | |
|  * linear in a way that when collecting data for 50 mS caused value X, doubling
 | |
|  * the data collection time caused value 2X etc.
 | |
|  *
 | |
|  * @time_us:	Integration time in microseconds. Time values must be positive,
 | |
|  *		negative values are reserved for error handling.
 | |
|  * @sel:	Selector (usually register value) used to indicate this time
 | |
|  *		NOTE: Only selectors >= 0 supported.
 | |
|  * @mul:	Multiplication to the values caused by this time.
 | |
|  *		NOTE: Only multipliers > 0 supported.
 | |
|  */
 | |
| struct iio_itime_sel_mul {
 | |
| 	int time_us;
 | |
| 	int sel;
 | |
| 	int mul;
 | |
| };
 | |
| 
 | |
| struct iio_gts {
 | |
| 	u64 max_scale;
 | |
| 	const struct iio_gain_sel_pair *hwgain_table;
 | |
| 	int num_hwgain;
 | |
| 	const struct iio_itime_sel_mul *itime_table;
 | |
| 	int num_itime;
 | |
| 	int **per_time_avail_scale_tables;
 | |
| 	int *avail_all_scales_table;
 | |
| 	int num_avail_all_scales;
 | |
| 	int *avail_time_tables;
 | |
| 	int num_avail_time_tables;
 | |
| };
 | |
| 
 | |
| #define GAIN_SCALE_GAIN(_gain, _sel)			\
 | |
| {							\
 | |
| 	.gain = (_gain),				\
 | |
| 	.sel = (_sel),					\
 | |
| }
 | |
| 
 | |
| #define GAIN_SCALE_ITIME_US(_itime, _sel, _mul)		\
 | |
| {							\
 | |
| 	.time_us = (_itime),				\
 | |
| 	.sel = (_sel),					\
 | |
| 	.mul = (_mul),					\
 | |
| }
 | |
| 
 | |
| static inline const struct iio_itime_sel_mul *
 | |
| iio_gts_find_itime_by_time(struct iio_gts *gts, int time)
 | |
| {
 | |
| 	int i;
 | |
| 
 | |
| 	if (!gts->num_itime)
 | |
| 		return NULL;
 | |
| 
 | |
| 	for (i = 0; i < gts->num_itime; i++)
 | |
| 		if (gts->itime_table[i].time_us == time)
 | |
| 			return >s->itime_table[i];
 | |
| 
 | |
| 	return NULL;
 | |
| }
 | |
| 
 | |
| static inline const struct iio_itime_sel_mul *
 | |
| iio_gts_find_itime_by_sel(struct iio_gts *gts, int sel)
 | |
| {
 | |
| 	int i;
 | |
| 
 | |
| 	for (i = 0; i < gts->num_itime; i++)
 | |
| 		if (gts->itime_table[i].sel == sel)
 | |
| 			return >s->itime_table[i];
 | |
| 
 | |
| 	return NULL;
 | |
| }
 | |
| 
 | |
| 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);
 | |
| /**
 | |
|  * iio_gts_find_int_time_by_sel - find integration time matching a selector
 | |
|  * @gts:	Gain time scale descriptor
 | |
|  * @sel:	selector for which matching integration time is searched for
 | |
|  *
 | |
|  * Return:	integration time matching given selector or -EINVAL if
 | |
|  *		integration time was not found.
 | |
|  */
 | |
| static inline int iio_gts_find_int_time_by_sel(struct iio_gts *gts, int sel)
 | |
| {
 | |
| 	const struct iio_itime_sel_mul *itime;
 | |
| 
 | |
| 	itime = iio_gts_find_itime_by_sel(gts, sel);
 | |
| 	if (!itime)
 | |
| 		return -EINVAL;
 | |
| 
 | |
| 	return itime->time_us;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * iio_gts_find_sel_by_int_time - find selector matching integration time
 | |
|  * @gts:	Gain time scale descriptor
 | |
|  * @time:	Integration time for which matching selector is searched for
 | |
|  *
 | |
|  * Return:	a selector matching given integration time or -EINVAL if
 | |
|  *		selector was not found.
 | |
|  */
 | |
| static inline int iio_gts_find_sel_by_int_time(struct iio_gts *gts, int time)
 | |
| {
 | |
| 	const struct iio_itime_sel_mul *itime;
 | |
| 
 | |
| 	itime = iio_gts_find_itime_by_time(gts, time);
 | |
| 	if (!itime)
 | |
| 		return -EINVAL;
 | |
| 
 | |
| 	return itime->sel;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * iio_gts_valid_time - check if given integration time is valid
 | |
|  * @gts:	Gain time scale descriptor
 | |
|  * @time_us:	Integration time to check
 | |
|  *
 | |
|  * Return:	True if given time is supported by device. False if not.
 | |
|  */
 | |
| static inline bool iio_gts_valid_time(struct iio_gts *gts, int time_us)
 | |
| {
 | |
| 	return iio_gts_find_itime_by_time(gts, time_us) != NULL;
 | |
| }
 | |
| 
 | |
| int iio_gts_find_sel_by_gain(struct iio_gts *gts, int gain);
 | |
| 
 | |
| /**
 | |
|  * iio_gts_valid_gain - check if given HW-gain is valid
 | |
|  * @gts:	Gain time scale descriptor
 | |
|  * @gain:	HW-gain to check
 | |
|  *
 | |
|  * Return:	True if given time is supported by device. False if not.
 | |
|  */
 | |
| static inline bool iio_gts_valid_gain(struct iio_gts *gts, int gain)
 | |
| {
 | |
| 	return iio_gts_find_sel_by_gain(gts, gain) >= 0;
 | |
| }
 | |
| 
 | |
| int iio_find_closest_gain_low(struct iio_gts *gts, int gain, bool *in_range);
 | |
| int iio_gts_find_gain_by_sel(struct iio_gts *gts, int sel);
 | |
| int iio_gts_get_min_gain(struct iio_gts *gts);
 | |
| int iio_gts_find_int_time_by_sel(struct iio_gts *gts, int sel);
 | |
| int iio_gts_find_sel_by_int_time(struct iio_gts *gts, int time);
 | |
| 
 | |
| int iio_gts_total_gain_to_scale(struct iio_gts *gts, int total_gain,
 | |
| 				int *scale_int, int *scale_nano);
 | |
| 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);
 | |
| int iio_gts_get_scale(struct iio_gts *gts, int gain, int time, int *scale_int,
 | |
| 		      int *scale_nano);
 | |
| 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);
 | |
| 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);
 | |
| int iio_gts_avail_times(struct iio_gts *gts,  const int **vals, int *type,
 | |
| 			int *length);
 | |
| int iio_gts_all_avail_scales(struct iio_gts *gts, const int **vals, int *type,
 | |
| 			     int *length);
 | |
| int iio_gts_avail_scales_for_time(struct iio_gts *gts, int time,
 | |
| 				  const int **vals, int *type, int *length);
 | |
| 
 | |
| #endif
 |