drivers/input/misc/cma3000_d0x.c

Source file repositories/reference/linux-study-clean/drivers/input/misc/cma3000_d0x.c

File Facts

System
Linux kernel
Corpus path
drivers/input/misc/cma3000_d0x.c
Extension
.c
Size
8785 bytes
Lines
380
Domain
Driver Families
Bucket
drivers/input
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 cma3000_accl_data {
	const struct cma3000_bus_ops *bus_ops;
	const struct cma3000_platform_data *pdata;

	struct device *dev;
	struct input_dev *input_dev;

	int bit_to_mg;
	int irq;

	int g_range;
	u8 mode;

	struct mutex mutex;
	bool opened;
	bool suspended;
};

#define CMA3000_READ(data, reg, msg) \
	(data->bus_ops->read(data->dev, reg, msg))
#define CMA3000_SET(data, reg, val, msg) \
	((data)->bus_ops->write(data->dev, reg, val, msg))

/*
 * Conversion for each of the eight modes to g, depending
 * on G range i.e 2G or 8G. Some modes always operate in
 * 8G.
 */

static int mode_to_mg[8][2] = {
	{ 0, 0 },
	{ BIT_TO_8G, BIT_TO_2G },
	{ BIT_TO_8G, BIT_TO_2G },
	{ BIT_TO_8G, BIT_TO_8G },
	{ BIT_TO_8G, BIT_TO_8G },
	{ BIT_TO_8G, BIT_TO_2G },
	{ BIT_TO_8G, BIT_TO_2G },
	{ 0, 0},
};

static void decode_mg(struct cma3000_accl_data *data, int *datax,
				int *datay, int *dataz)
{
	/* Data in 2's complement, convert to mg */
	*datax = ((s8)*datax) * data->bit_to_mg;
	*datay = ((s8)*datay) * data->bit_to_mg;
	*dataz = ((s8)*dataz) * data->bit_to_mg;
}

static irqreturn_t cma3000_thread_irq(int irq, void *dev_id)
{
	struct cma3000_accl_data *data = dev_id;
	int datax, datay, dataz, intr_status;
	u8 ctrl, mode, range;

	intr_status = CMA3000_READ(data, CMA3000_INTSTATUS, "interrupt status");
	if (intr_status < 0)
		return IRQ_NONE;

	/* Check if free fall is detected, report immediately */
	if (intr_status & CMA3000_INTSTATUS_FFDET) {
		input_report_abs(data->input_dev, ABS_MISC, 1);
		input_sync(data->input_dev);
	} else {
		input_report_abs(data->input_dev, ABS_MISC, 0);
	}

	datax = CMA3000_READ(data, CMA3000_DOUTX, "X");
	datay = CMA3000_READ(data, CMA3000_DOUTY, "Y");
	dataz = CMA3000_READ(data, CMA3000_DOUTZ, "Z");

	ctrl = CMA3000_READ(data, CMA3000_CTRL, "ctrl");
	mode = (ctrl & CMA3000_MODEMASK) >> 1;
	range = (ctrl & CMA3000_GRANGEMASK) >> 7;

	data->bit_to_mg = mode_to_mg[mode][range];

	/* Interrupt not for this device */
	if (data->bit_to_mg == 0)
		return IRQ_NONE;

	/* Decode register values to milli g */
	decode_mg(data, &datax, &datay, &dataz);

	input_report_abs(data->input_dev, ABS_X, datax);
	input_report_abs(data->input_dev, ABS_Y, datay);
	input_report_abs(data->input_dev, ABS_Z, dataz);
	input_sync(data->input_dev);

	return IRQ_HANDLED;

Annotation

Implementation Notes