linux/drivers/counter/stm32-timer-cnt.c

// SPDX-License-Identifier: GPL-2.0
/*
 * STM32 Timer Encoder and Counter driver
 *
 * Copyright (C) STMicroelectronics 2018
 *
 * Author: Benjamin Gaignard <[email protected]>
 *
 */
#include <linux/counter.h>
#include <linux/interrupt.h>
#include <linux/mfd/stm32-timers.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/types.h>

#define TIM_CCMR_CCXS
#define TIM_CCMR_MASK
#define TIM_CCER_MASK

#define STM32_CH1_SIG
#define STM32_CH2_SIG
#define STM32_CLOCK_SIG
#define STM32_CH3_SIG
#define STM32_CH4_SIG

struct stm32_timer_regs {};

struct stm32_timer_cnt {};

static const enum counter_function stm32_count_functions[] =;

static int stm32_count_read(struct counter_device *counter,
			    struct counter_count *count, u64 *val)
{}

static int stm32_count_write(struct counter_device *counter,
			     struct counter_count *count, const u64 val)
{}

static int stm32_count_function_read(struct counter_device *counter,
				     struct counter_count *count,
				     enum counter_function *function)
{}

static int stm32_count_function_write(struct counter_device *counter,
				      struct counter_count *count,
				      enum counter_function function)
{}

static int stm32_count_direction_read(struct counter_device *counter,
				      struct counter_count *count,
				      enum counter_count_direction *direction)
{}

static int stm32_count_ceiling_read(struct counter_device *counter,
				    struct counter_count *count, u64 *ceiling)
{}

static int stm32_count_ceiling_write(struct counter_device *counter,
				     struct counter_count *count, u64 ceiling)
{}

static int stm32_count_enable_read(struct counter_device *counter,
				   struct counter_count *count, u8 *enable)
{}

static int stm32_count_enable_write(struct counter_device *counter,
				    struct counter_count *count, u8 enable)
{}

static int stm32_count_prescaler_read(struct counter_device *counter,
				      struct counter_count *count, u64 *prescaler)
{}

static int stm32_count_prescaler_write(struct counter_device *counter,
				       struct counter_count *count, u64 prescaler)
{}

static int stm32_count_cap_read(struct counter_device *counter,
				struct counter_count *count,
				size_t ch, u64 *cap)
{}

static int stm32_count_nb_ovf_read(struct counter_device *counter,
				   struct counter_count *count, u64 *val)
{}

static int stm32_count_nb_ovf_write(struct counter_device *counter,
				    struct counter_count *count, u64 val)
{}

static DEFINE_COUNTER_ARRAY_CAPTURE(stm32_count_cap_array, 4);

static struct counter_comp stm32_count_ext[] =;

static const enum counter_synapse_action stm32_clock_synapse_actions[] =;

static const enum counter_synapse_action stm32_synapse_actions[] =;

static int stm32_action_read(struct counter_device *counter,
			     struct counter_count *count,
			     struct counter_synapse *synapse,
			     enum counter_synapse_action *action)
{}

struct stm32_count_cc_regs {};

static const struct stm32_count_cc_regs stm32_cc[] =;

static int stm32_count_capture_configure(struct counter_device *counter, unsigned int ch,
					 bool enable)
{}

static int stm32_count_events_configure(struct counter_device *counter)
{}

static int stm32_count_watch_validate(struct counter_device *counter,
				      const struct counter_watch *watch)
{}

static const struct counter_ops stm32_timer_cnt_ops =;

static int stm32_count_clk_get_freq(struct counter_device *counter,
				    struct counter_signal *signal, u64 *freq)
{}

static struct counter_comp stm32_count_clock_ext[] =;

static struct counter_signal stm32_signals[] =;

static struct counter_synapse stm32_count_synapses[] =;

static struct counter_count stm32_counts =;

static irqreturn_t stm32_timer_cnt_isr(int irq, void *ptr)
{
	struct counter_device *counter = ptr;
	struct stm32_timer_cnt *const priv = counter_priv(counter);
	u32 clr = GENMASK(31, 0); /* SR flags can be cleared by writing 0 (wr 1 has no effect) */
	u32 sr, dier;
	int i;

	regmap_read(priv->regmap, TIM_SR, &sr);
	regmap_read(priv->regmap, TIM_DIER, &dier);
	/*
	 * Some status bits in SR don't match with the enable bits in DIER. Only take care of
	 * the possibly enabled bits in DIER (that matches in between SR and DIER).
	 */
	dier &= (TIM_DIER_UIE | TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE | TIM_DIER_CC4IE);
	sr &= dier;

	if (sr & TIM_SR_UIF) {
		spin_lock(&priv->lock);
		priv->nb_ovf++;
		spin_unlock(&priv->lock);
		counter_push_event(counter, COUNTER_EVENT_OVERFLOW_UNDERFLOW, 0);
		dev_dbg(counter->parent, "COUNTER_EVENT_OVERFLOW_UNDERFLOW\n");
		/* SR flags can be cleared by writing 0, only clear relevant flag */
		clr &= ~TIM_SR_UIF;
	}

	/* Check capture events */
	for (i = 0 ; i < priv->nchannels; i++) {
		if (sr & TIM_SR_CC_IF(i)) {
			counter_push_event(counter, COUNTER_EVENT_CAPTURE, i);
			clr &= ~TIM_SR_CC_IF(i);
			dev_dbg(counter->parent, "COUNTER_EVENT_CAPTURE, %d\n", i);
		}
	}

	regmap_write(priv->regmap, TIM_SR, clr);

	return IRQ_HANDLED;
};

static void stm32_timer_cnt_detect_channels(struct device *dev,
					    struct stm32_timer_cnt *priv)
{}

/* encoder supported on TIM1 TIM2 TIM3 TIM4 TIM5 TIM8 */
#define STM32_TIM_ENCODER_SUPPORTED

static const char * const stm32_timer_trigger_compat[] =;

static int stm32_timer_cnt_probe_encoder(struct device *dev,
					 struct stm32_timer_cnt *priv)
{}

static int stm32_timer_cnt_probe(struct platform_device *pdev)
{}

static int __maybe_unused stm32_timer_cnt_suspend(struct device *dev)
{}

static int __maybe_unused stm32_timer_cnt_resume(struct device *dev)
{}

static SIMPLE_DEV_PM_OPS(stm32_timer_cnt_pm_ops, stm32_timer_cnt_suspend,
			 stm32_timer_cnt_resume);

static const struct of_device_id stm32_timer_cnt_of_match[] =;
MODULE_DEVICE_TABLE(of, stm32_timer_cnt_of_match);

static struct platform_driver stm32_timer_cnt_driver =;
module_platform_driver();

MODULE_AUTHOR();
MODULE_ALIAS();
MODULE_DESCRIPTION();
MODULE_LICENSE();
MODULE_IMPORT_NS();