drivers/iio/position/iqs624-pos.c

Source file repositories/reference/linux-study-clean/drivers/iio/position/iqs624-pos.c

File Facts

System
Linux kernel
Corpus path
drivers/iio/position/iqs624-pos.c
Extension
.c
Size
7179 bytes
Lines
286
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 iqs624_pos_private {
	struct iqs62x_core *iqs62x;
	struct iio_dev *indio_dev;
	struct notifier_block notifier;
	struct mutex lock;
	bool angle_en;
	u16 angle;
};

static int iqs624_pos_angle_en(struct iqs62x_core *iqs62x, bool angle_en)
{
	unsigned int event_mask = IQS624_HALL_UI_WHL_EVENT;

	/*
	 * The IQS625 reports angular position in the form of coarse intervals,
	 * so only interval change events are unmasked. Conversely, the IQS624
	 * reports angular position down to one degree of resolution, so wheel
	 * movement events are unmasked instead.
	 */
	if (iqs62x->dev_desc->prod_num == IQS625_PROD_NUM)
		event_mask = IQS624_HALL_UI_INT_EVENT;

	return regmap_update_bits(iqs62x->regmap, IQS624_HALL_UI, event_mask,
				  angle_en ? 0 : 0xFF);
}

static int iqs624_pos_notifier(struct notifier_block *notifier,
			       unsigned long event_flags, void *context)
{
	struct iqs62x_event_data *event_data = context;
	struct iqs624_pos_private *iqs624_pos;
	struct iqs62x_core *iqs62x;
	struct iio_dev *indio_dev;
	u16 angle = event_data->ui_data;
	s64 timestamp;
	int ret;

	iqs624_pos = container_of(notifier, struct iqs624_pos_private,
				  notifier);
	indio_dev = iqs624_pos->indio_dev;
	timestamp = iio_get_time_ns(indio_dev);

	iqs62x = iqs624_pos->iqs62x;
	if (iqs62x->dev_desc->prod_num == IQS625_PROD_NUM)
		angle = event_data->interval;

	mutex_lock(&iqs624_pos->lock);

	if (event_flags & BIT(IQS62X_EVENT_SYS_RESET)) {
		ret = iqs624_pos_angle_en(iqs62x, iqs624_pos->angle_en);
		if (ret) {
			dev_err(indio_dev->dev.parent,
				"Failed to re-initialize device: %d\n", ret);
			ret = NOTIFY_BAD;
		} else {
			ret = NOTIFY_OK;
		}
	} else if (iqs624_pos->angle_en && (angle != iqs624_pos->angle)) {
		iio_push_event(indio_dev,
			       IIO_UNMOD_EVENT_CODE(IIO_ANGL, 0,
						    IIO_EV_TYPE_CHANGE,
						    IIO_EV_DIR_NONE),
			       timestamp);

		iqs624_pos->angle = angle;
		ret = NOTIFY_OK;
	} else {
		ret = NOTIFY_DONE;
	}

	mutex_unlock(&iqs624_pos->lock);

	return ret;
}

static void iqs624_pos_notifier_unregister(void *context)
{
	struct iqs624_pos_private *iqs624_pos = context;
	struct iio_dev *indio_dev = iqs624_pos->indio_dev;
	int ret;

	ret = blocking_notifier_chain_unregister(&iqs624_pos->iqs62x->nh,
						 &iqs624_pos->notifier);
	if (ret)
		dev_err(indio_dev->dev.parent,
			"Failed to unregister notifier: %d\n", ret);
}

static int iqs624_pos_angle_get(struct iqs62x_core *iqs62x, unsigned int *val)
{

Annotation

Implementation Notes