drivers/iio/light/al3010.c

Source file repositories/reference/linux-study-clean/drivers/iio/light/al3010.c

File Facts

System
Linux kernel
Corpus path
drivers/iio/light/al3010.c
Extension
.c
Size
6144 bytes
Lines
247
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 al3010_data {
	struct regmap *regmap;
};

static const struct iio_chan_spec al3010_channels[] = {
	{
		.type	= IIO_LIGHT,
		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
				      BIT(IIO_CHAN_INFO_SCALE),
	}
};

static IIO_CONST_ATTR(in_illuminance_scale_available, AL3010_SCALE_AVAILABLE);

static struct attribute *al3010_attributes[] = {
	&iio_const_attr_in_illuminance_scale_available.dev_attr.attr,
	NULL,
};

static const struct attribute_group al3010_attribute_group = {
	.attrs = al3010_attributes,
};

static int al3010_set_pwr_on(struct al3010_data *data)
{
	return regmap_write(data->regmap, AL3010_REG_SYSTEM, AL3010_CONFIG_ENABLE);
}

static void al3010_set_pwr_off(void *_data)
{
	struct al3010_data *data = _data;
	struct device *dev = regmap_get_device(data->regmap);
	int ret;

	ret = regmap_write(data->regmap, AL3010_REG_SYSTEM, AL3010_CONFIG_DISABLE);
	if (ret)
		dev_err(dev, "failed to write system register\n");
}

static int al3010_init(struct al3010_data *data)
{
	struct device *dev = regmap_get_device(data->regmap);
	int ret;

	ret = al3010_set_pwr_on(data);
	if (ret)
		return ret;

	ret = devm_add_action_or_reset(dev, al3010_set_pwr_off, data);
	if (ret)
		return ret;
	return regmap_write(data->regmap, AL3010_REG_CONFIG,
			    FIELD_PREP(AL3010_GAIN_MASK, AL3XXX_RANGE_3));
}

static int al3010_read_raw(struct iio_dev *indio_dev,
			   struct iio_chan_spec const *chan, int *val,
			   int *val2, long mask)
{
	struct al3010_data *data = iio_priv(indio_dev);
	int ret, gain, raw;

	switch (mask) {
	case IIO_CHAN_INFO_RAW:
		/*
		 * ALS ADC value is stored in two adjacent registers:
		 * - low byte of output is stored at AL3010_REG_DATA_LOW
		 * - high byte of output is stored at AL3010_REG_DATA_LOW + 1
		 */
		ret = regmap_read(data->regmap, AL3010_REG_DATA_LOW, &raw);
		if (ret)
			return ret;

		*val = raw;

		return IIO_VAL_INT;
	case IIO_CHAN_INFO_SCALE:
		ret = regmap_read(data->regmap, AL3010_REG_CONFIG, &gain);
		if (ret)
			return ret;

		gain = FIELD_GET(AL3010_GAIN_MASK, gain);
		*val = al3010_scales[gain][0];
		*val2 = al3010_scales[gain][1];

		return IIO_VAL_INT_PLUS_MICRO;
	}
	return -EINVAL;
}

Annotation

Implementation Notes