drivers/counter/rz-mtu3-cnt.c

Source file repositories/reference/linux-study-clean/drivers/counter/rz-mtu3-cnt.c

File Facts

System
Linux kernel
Corpus path
drivers/counter/rz-mtu3-cnt.c
Extension
.c
Size
24483 bytes
Lines
910
Domain
Driver Families
Bucket
drivers/counter
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 rz_mtu3_cnt {
	struct clk *clk;
	struct mutex lock;
	struct rz_mtu3_channel *ch;
	bool count_is_enabled[RZ_MTU3_MAX_LOGICAL_CNTR_CHANNELS];
	union {
		u16 mtu_16bit_max[RZ_MTU3_MAX_HW_CNTR_CHANNELS];
		u32 mtu_32bit_max;
	};
};

static const enum counter_function rz_mtu3_count_functions[] = {
	COUNTER_FUNCTION_QUADRATURE_X4,
	COUNTER_FUNCTION_PULSE_DIRECTION,
	COUNTER_FUNCTION_QUADRATURE_X2_B,
};

static inline size_t rz_mtu3_get_hw_ch(const size_t id)
{
	return (id == RZ_MTU3_32_BIT_CH) ? 0 : id;
}

static inline struct rz_mtu3_channel *rz_mtu3_get_ch(struct counter_device *counter, int id)
{
	struct rz_mtu3_cnt *const priv = counter_priv(counter);
	const size_t ch_id = rz_mtu3_get_hw_ch(id);

	return &priv->ch[ch_id];
}

static bool rz_mtu3_is_counter_invalid(struct counter_device *counter, int id)
{
	struct rz_mtu3_cnt *const priv = counter_priv(counter);
	unsigned long tmdr;

	pm_runtime_get_sync(counter->parent);
	tmdr = rz_mtu3_shared_reg_read(priv->ch, RZ_MTU3_TMDR3);
	pm_runtime_put(counter->parent);

	if (id == RZ_MTU3_32_BIT_CH && test_bit(RZ_MTU3_TMDR3_LWA, &tmdr))
		return false;

	if (id != RZ_MTU3_32_BIT_CH && !test_bit(RZ_MTU3_TMDR3_LWA, &tmdr))
		return false;

	return true;
}

static int rz_mtu3_lock_if_counter_is_valid(struct counter_device *counter,
					    struct rz_mtu3_channel *const ch,
					    struct rz_mtu3_cnt *const priv,
					    int id)
{
	mutex_lock(&priv->lock);

	if (ch->is_busy && !priv->count_is_enabled[id]) {
		mutex_unlock(&priv->lock);
		return -EINVAL;
	}

	if (rz_mtu3_is_counter_invalid(counter, id)) {
		mutex_unlock(&priv->lock);
		return -EBUSY;
	}

	return 0;
}

static int rz_mtu3_lock_if_count_is_enabled(struct rz_mtu3_channel *const ch,
					    struct rz_mtu3_cnt *const priv,
					    int id)
{
	mutex_lock(&priv->lock);

	if (ch->is_busy && !priv->count_is_enabled[id]) {
		mutex_unlock(&priv->lock);
		return -EINVAL;
	}

	return 0;
}

static int rz_mtu3_count_read(struct counter_device *counter,
			      struct counter_count *count, u64 *val)
{
	struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id);
	struct rz_mtu3_cnt *const priv = counter_priv(counter);
	int ret;

	ret = rz_mtu3_lock_if_counter_is_valid(counter, ch, priv, count->id);

Annotation

Implementation Notes