From 5120a083e797aec3180fbda9ab845486da990909 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Wed, 7 Feb 2018 10:44:45 +0100 Subject: [PATCH] timer: stm32: Add timer support for STM32 SoCs family This timer driver is using GPT Timer (General Purpose Timer) available on all STM32 SOCs family. This driver can be used on STM32F4/F7 and H7 SoCs family Signed-off-by: Patrice Chotard --- drivers/timer/Kconfig | 7 +++ drivers/timer/Makefile | 1 + drivers/timer/stm32_timer.c | 138 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 drivers/timer/stm32_timer.c diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 3a1f831..2c96896 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -119,4 +119,11 @@ config ROCKCHIP_TIMER Select this to enable support for the timer found on Rockchip devices. +config STM32_TIMER + bool "STM32 timer support" + depends on TIMER + help + Select this to enable support for the timer found on + STM32 devices. + endmenu diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index 15e5154..a6e7832 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_AG101P_TIMER) += ag101p_timer.o obj-$(CONFIG_ATCPIT100_TIMER) += atcpit100_timer.o obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o obj-$(CONFIG_ATMEL_PIT_TIMER) += atmel_pit_timer.o +obj-$(CONFIG_STM32_TIMER) += stm32_timer.o diff --git a/drivers/timer/stm32_timer.c b/drivers/timer/stm32_timer.c new file mode 100644 index 0000000..344e6fb --- /dev/null +++ b/drivers/timer/stm32_timer.c @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * Author(s): Patrice Chotard, for STMicroelectronics. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#include + +/* Timer control1 register */ +#define CR1_CEN BIT(0) +#define CR1_ARPE BIT(7) + +/* Event Generation Register register */ +#define EGR_UG BIT(0) + +/* Auto reload register for free running config */ +#define GPT_FREE_RUNNING 0xFFFFFFFF + +struct stm32_timer_regs { + u32 cr1; + u32 cr2; + u32 smcr; + u32 dier; + u32 sr; + u32 egr; + u32 ccmr1; + u32 ccmr2; + u32 ccer; + u32 cnt; + u32 psc; + u32 arr; + u32 reserved; + u32 ccr1; + u32 ccr2; + u32 ccr3; + u32 ccr4; + u32 reserved1; + u32 dcr; + u32 dmar; + u32 tim2_5_or; +}; + +struct stm32_timer_priv { + struct stm32_timer_regs *base; +}; + +static int stm32_timer_get_count(struct udevice *dev, u64 *count) +{ + struct stm32_timer_priv *priv = dev_get_priv(dev); + struct stm32_timer_regs *regs = priv->base; + + *count = readl(®s->cnt); + + return 0; +} + +static int stm32_timer_probe(struct udevice *dev) +{ + struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct stm32_timer_priv *priv = dev_get_priv(dev); + struct stm32_timer_regs *regs; + struct clk clk; + fdt_addr_t addr; + int ret; + u32 rate, psc; + + addr = dev_read_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->base = (struct stm32_timer_regs *)addr; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret < 0) + return ret; + + ret = clk_enable(&clk); + if (ret) { + dev_err(dev, "failed to enable clock\n"); + return ret; + } + + regs = priv->base; + + /* Stop the timer */ + clrbits_le32(®s->cr1, CR1_CEN); + + /* get timer clock */ + rate = clk_get_rate(&clk); + + /* we set timer prescaler to obtain a 1MHz timer counter frequency */ + psc = (rate / CONFIG_SYS_HZ_CLOCK) - 1; + writel(psc, ®s->psc); + + /* Set timer frequency to 1MHz */ + uc_priv->clock_rate = CONFIG_SYS_HZ_CLOCK; + + /* Configure timer for auto-reload */ + setbits_le32(®s->cr1, CR1_ARPE); + + /* load value for auto reload */ + writel(GPT_FREE_RUNNING, ®s->arr); + + /* start timer */ + setbits_le32(®s->cr1, CR1_CEN); + + /* Update generation */ + setbits_le32(®s->egr, EGR_UG); + + return 0; +} + +static const struct timer_ops stm32_timer_ops = { + .get_count = stm32_timer_get_count, +}; + +static const struct udevice_id stm32_timer_ids[] = { + { .compatible = "st,stm32-timer" }, + {} +}; + +U_BOOT_DRIVER(stm32_timer) = { + .name = "stm32_timer", + .id = UCLASS_TIMER, + .of_match = stm32_timer_ids, + .priv_auto_alloc_size = sizeof(struct stm32_timer_priv), + .probe = stm32_timer_probe, + .ops = &stm32_timer_ops, + .flags = DM_FLAG_PRE_RELOC, +}; +