drivers/iio/chemical/sgp40.c

Source file repositories/reference/linux-study-clean/drivers/iio/chemical/sgp40.c

File Facts

System
Linux kernel
Corpus path
drivers/iio/chemical/sgp40.c
Extension
.c
Size
9736 bytes
Lines
384
Domain
Driver Families
Bucket
drivers/iio
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct sgp40_data {
	struct device		*dev;
	struct i2c_client	*client;
	int			rht;
	int			temp;
	int			res_calibbias;
	/* Prevent concurrent access to rht, tmp, calibbias */
	struct mutex		lock;
};

struct sgp40_tg_measure {
	u8	command[2];
	__be16	rht_ticks;
	u8	rht_crc;
	__be16	temp_ticks;
	u8	temp_crc;
} __packed;

struct sgp40_tg_result {
	__be16	res_ticks;
	u8	res_crc;
} __packed;

static const struct iio_chan_spec sgp40_channels[] = {
	{
		.type = IIO_CONCENTRATION,
		.channel2 = IIO_MOD_VOC,
		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
	},
	{
		.type = IIO_RESISTANCE,
		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
			BIT(IIO_CHAN_INFO_CALIBBIAS),
	},
	{
		.type = IIO_TEMP,
		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
		.output = 1,
	},
	{
		.type = IIO_HUMIDITYRELATIVE,
		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
		.output = 1,
	},
};

/*
 * taylor approximation of e^x:
 * y = 1 + x + x^2 / 2 + x^3 / 6 + x^4 / 24 + ... + x^n / n!
 *
 * Because we are calculating x real value multiplied by 2^power we get
 * an additional 2^power^n to divide for every element. For a reasonable
 * precision this would overflow after a few iterations. Therefore we
 * divide the x^n part whenever its about to overflow (xmax).
 */

static u32 sgp40_exp(int exp, u32 power, u32 rounds)
{
        u32 x, y, xp;
        u32 factorial, divider, xmax;
        int sign = 1;
	int i;

        if (exp == 0)
                return 1 << power;
        else if (exp < 0) {
                sign = -1;
                exp *= -1;
        }

        xmax = 0x7FFFFFFF / exp;
        x = exp;
        xp = 1;
        factorial = 1;
        y = 1 << power;
        divider = 0;

        for (i = 1; i <= rounds; i++) {
                xp *= x;
                factorial *= i;
                y += (xp >> divider) / factorial;
                divider += power;
                /* divide when next multiplication would overflow */
                if (xp >= xmax) {
                        xp >>= power;
                        divider -= power;
                }
        }

        if (sign == -1)

Annotation

Implementation Notes