drivers/iio/proximity/cros_ec_mkbp_proximity.c

Source file repositories/reference/linux-study-clean/drivers/iio/proximity/cros_ec_mkbp_proximity.c

File Facts

System
Linux kernel
Corpus path
drivers/iio/proximity/cros_ec_mkbp_proximity.c
Extension
.c
Size
7301 bytes
Lines
265
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 cros_ec_mkbp_proximity_data {
	struct cros_ec_device *ec;
	struct iio_dev *indio_dev;
	struct mutex lock;
	struct notifier_block notifier;
	int last_proximity;
	bool enabled;
};

static const struct iio_event_spec cros_ec_mkbp_proximity_events[] = {
	{
		.type = IIO_EV_TYPE_THRESH,
		.dir = IIO_EV_DIR_EITHER,
		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
	},
};

static const struct iio_chan_spec cros_ec_mkbp_proximity_chan_spec[] = {
	{
		.type = IIO_PROXIMITY,
		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
		.event_spec = cros_ec_mkbp_proximity_events,
		.num_event_specs = ARRAY_SIZE(cros_ec_mkbp_proximity_events),
	},
};

static int cros_ec_mkbp_proximity_parse_state(const void *data)
{
	u32 switches = get_unaligned_le32(data);

	return !!(switches & BIT(EC_MKBP_FRONT_PROXIMITY));
}

static int cros_ec_mkbp_proximity_query(struct cros_ec_device *ec_dev,
					int *state)
{
	DEFINE_RAW_FLEX(struct cros_ec_command, buf, data,
			MAX(sizeof(u32), sizeof(struct ec_params_mkbp_info)));
	struct ec_params_mkbp_info *params = (struct ec_params_mkbp_info *)buf->data;
	struct cros_ec_command *msg = buf;
	u32 *switches = (u32 *)buf->data;
	size_t insize = sizeof(*switches);
	int ret;

	msg->command = EC_CMD_MKBP_INFO;
	msg->version = 1;
	msg->outsize = sizeof(*params);
	msg->insize = insize;

	params->info_type = EC_MKBP_INFO_CURRENT;
	params->event_type = EC_MKBP_EVENT_SWITCH;

	ret = cros_ec_cmd_xfer_status(ec_dev, msg);
	if (ret < 0)
		return ret;

	if (ret != insize) {
		dev_warn(ec_dev->dev, "wrong result size: %d != %zu\n", ret,
			 insize);
		return -EPROTO;
	}

	*state = cros_ec_mkbp_proximity_parse_state(switches);
	return IIO_VAL_INT;
}

static void cros_ec_mkbp_proximity_push_event(struct cros_ec_mkbp_proximity_data *data, int state)
{
	s64 timestamp;
	u64 ev;
	int dir;
	struct iio_dev *indio_dev = data->indio_dev;
	struct cros_ec_device *ec = data->ec;

	mutex_lock(&data->lock);
	if (state != data->last_proximity) {
		if (data->enabled) {
			timestamp = ktime_to_ns(ec->last_event_time);
			if (iio_device_get_clock(indio_dev) != CLOCK_BOOTTIME)
				timestamp = iio_get_time_ns(indio_dev);

			dir = state ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING;
			ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
						  IIO_EV_TYPE_THRESH, dir);
			iio_push_event(indio_dev, ev, timestamp);
		}
		data->last_proximity = state;
	}
	mutex_unlock(&data->lock);
}

Annotation

Implementation Notes