dm: implement a Timer uclass
Implement a Timer uclass to work with lib/time.c. Signed-off-by: Thomas Chou <thomas@wytron.com.tw> Acked-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
		
							parent
							
								
									bcae80e955
								
							
						
					
					
						commit
						c8a7ba9e6a
					
				|  | @ -58,6 +58,8 @@ source "drivers/spi/Kconfig" | ||||||
| 
 | 
 | ||||||
| source "drivers/thermal/Kconfig" | source "drivers/thermal/Kconfig" | ||||||
| 
 | 
 | ||||||
|  | source "drivers/timer/Kconfig" | ||||||
|  | 
 | ||||||
| source "drivers/tpm/Kconfig" | source "drivers/tpm/Kconfig" | ||||||
| 
 | 
 | ||||||
| source "drivers/usb/Kconfig" | source "drivers/usb/Kconfig" | ||||||
|  |  | ||||||
|  | @ -48,6 +48,7 @@ obj-y += pcmcia/ | ||||||
| obj-y += dfu/ | obj-y += dfu/ | ||||||
| obj-y += rtc/ | obj-y += rtc/ | ||||||
| obj-y += sound/ | obj-y += sound/ | ||||||
|  | obj-y += timer/ | ||||||
| obj-y += tpm/ | obj-y += tpm/ | ||||||
| obj-y += twserial/ | obj-y += twserial/ | ||||||
| obj-y += video/ | obj-y += video/ | ||||||
|  |  | ||||||
|  | @ -0,0 +1,12 @@ | ||||||
|  | menu "Timer Support" | ||||||
|  | 
 | ||||||
|  | config TIMER | ||||||
|  | 	bool "Enable Driver Model for Timer drivers" | ||||||
|  | 	depends on DM | ||||||
|  | 	help | ||||||
|  | 	  Enable driver model for Timer access. It uses the same API as | ||||||
|  | 	  lib/time.c. But now implemented by the uclass. The first timer | ||||||
|  | 	  will be used. The timer is usually a 32 bits free-running up | ||||||
|  | 	  counter. There may be no real tick, and no timer interrupt. | ||||||
|  | 
 | ||||||
|  | endmenu | ||||||
|  | @ -0,0 +1,7 @@ | ||||||
|  | #
 | ||||||
|  | # Copyright (C) 2015 Thomas Chou <thomas@wytron.com.tw>
 | ||||||
|  | #
 | ||||||
|  | # SPDX-License-Identifier:	GPL-2.0+
 | ||||||
|  | #
 | ||||||
|  | 
 | ||||||
|  | obj-$(CONFIG_TIMER)		+= timer-uclass.o | ||||||
|  | @ -0,0 +1,42 @@ | ||||||
|  | /*
 | ||||||
|  |  * Copyright (C) 2015 Thomas Chou <thomas@wytron.com.tw> | ||||||
|  |  * | ||||||
|  |  * SPDX-License-Identifier:	GPL-2.0+ | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <common.h> | ||||||
|  | #include <dm.h> | ||||||
|  | #include <errno.h> | ||||||
|  | #include <timer.h> | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Implement a Timer uclass to work with lib/time.c. The timer is usually | ||||||
|  |  * a 32 bits free-running up counter. The get_rate() method is used to get | ||||||
|  |  * the input clock frequency of the timer. The get_count() method is used | ||||||
|  |  * get the current 32 bits count value. If the hardware is counting down, | ||||||
|  |  * the value should be inversed inside the method. There may be no real | ||||||
|  |  * tick, and no timer interrupt. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | int timer_get_count(struct udevice *dev, unsigned long *count) | ||||||
|  | { | ||||||
|  | 	const struct timer_ops *ops = device_get_ops(dev); | ||||||
|  | 
 | ||||||
|  | 	if (!ops->get_count) | ||||||
|  | 		return -ENOSYS; | ||||||
|  | 
 | ||||||
|  | 	return ops->get_count(dev, count); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | unsigned long timer_get_rate(struct udevice *dev) | ||||||
|  | { | ||||||
|  | 	struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); | ||||||
|  | 
 | ||||||
|  | 	return uc_priv->clock_rate; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | UCLASS_DRIVER(timer) = { | ||||||
|  | 	.id		= UCLASS_TIMER, | ||||||
|  | 	.name		= "timer", | ||||||
|  | 	.per_device_auto_alloc_size = sizeof(struct timer_dev_priv), | ||||||
|  | }; | ||||||
|  | @ -69,6 +69,9 @@ typedef struct global_data { | ||||||
| 	struct udevice	*dm_root_f;	/* Pre-relocation root instance */ | 	struct udevice	*dm_root_f;	/* Pre-relocation root instance */ | ||||||
| 	struct list_head uclass_root;	/* Head of core tree */ | 	struct list_head uclass_root;	/* Head of core tree */ | ||||||
| #endif | #endif | ||||||
|  | #ifdef CONFIG_TIMER | ||||||
|  | 	struct udevice	*timer;	/* Timer instance for Driver Model */ | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| 	const void *fdt_blob;	/* Our device tree, NULL if none */ | 	const void *fdt_blob;	/* Our device tree, NULL if none */ | ||||||
| 	void *new_fdt;		/* Relocated FDT */ | 	void *new_fdt;		/* Relocated FDT */ | ||||||
|  |  | ||||||
|  | @ -57,6 +57,7 @@ enum uclass_id { | ||||||
| 	UCLASS_SPI_GENERIC,	/* Generic SPI flash target */ | 	UCLASS_SPI_GENERIC,	/* Generic SPI flash target */ | ||||||
| 	UCLASS_SYSCON,		/* System configuration device */ | 	UCLASS_SYSCON,		/* System configuration device */ | ||||||
| 	UCLASS_THERMAL,		/* Thermal sensor */ | 	UCLASS_THERMAL,		/* Thermal sensor */ | ||||||
|  | 	UCLASS_TIMER,		/* Timer device */ | ||||||
| 	UCLASS_TPM,		/* Trusted Platform Module TIS interface */ | 	UCLASS_TPM,		/* Trusted Platform Module TIS interface */ | ||||||
| 	UCLASS_USB,		/* USB bus */ | 	UCLASS_USB,		/* USB bus */ | ||||||
| 	UCLASS_USB_DEV_GENERIC,	/* USB generic device */ | 	UCLASS_USB_DEV_GENERIC,	/* USB generic device */ | ||||||
|  |  | ||||||
|  | @ -0,0 +1,52 @@ | ||||||
|  | /*
 | ||||||
|  |  * Copyright (C) 2015 Thomas Chou <thomas@wytron.com.tw> | ||||||
|  |  * | ||||||
|  |  * SPDX-License-Identifier:	GPL-2.0+ | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef _TIMER_H_ | ||||||
|  | #define _TIMER_H_ | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Get the current timer count | ||||||
|  |  * | ||||||
|  |  * @dev: The Timer device | ||||||
|  |  * @count: pointer that returns the current timer count | ||||||
|  |  * @return: 0 if OK, -ve on error | ||||||
|  |  */ | ||||||
|  | int timer_get_count(struct udevice *dev, unsigned long *count); | ||||||
|  | /*
 | ||||||
|  |  * Get the timer input clock frequency | ||||||
|  |  * | ||||||
|  |  * @dev: The Timer device | ||||||
|  |  * @return: the timer input clock frequency | ||||||
|  |  */ | ||||||
|  | unsigned long timer_get_rate(struct udevice *dev); | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * struct timer_ops - Driver model Timer operations | ||||||
|  |  * | ||||||
|  |  * The uclass interface is implemented by all Timer devices which use | ||||||
|  |  * driver model. | ||||||
|  |  */ | ||||||
|  | struct timer_ops { | ||||||
|  | 	/*
 | ||||||
|  | 	 * Get the current timer count | ||||||
|  | 	 * | ||||||
|  | 	 * @dev: The Timer device | ||||||
|  | 	 * @count: pointer that returns the current timer count | ||||||
|  | 	 * @return: 0 if OK, -ve on error | ||||||
|  | 	 */ | ||||||
|  | 	int (*get_count)(struct udevice *dev, unsigned long *count); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * struct timer_dev_priv - information about a device used by the uclass | ||||||
|  |  * | ||||||
|  |  * @clock_rate: the timer input clock frequency | ||||||
|  |  */ | ||||||
|  | struct timer_dev_priv { | ||||||
|  | 	unsigned long clock_rate; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #endif	/* _TIMER_H_ */ | ||||||
							
								
								
									
										49
									
								
								lib/time.c
								
								
								
								
							
							
						
						
									
										49
									
								
								lib/time.c
								
								
								
								
							|  | @ -6,6 +6,9 @@ | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include <common.h> | #include <common.h> | ||||||
|  | #include <dm.h> | ||||||
|  | #include <errno.h> | ||||||
|  | #include <timer.h> | ||||||
| #include <watchdog.h> | #include <watchdog.h> | ||||||
| #include <div64.h> | #include <div64.h> | ||||||
| #include <asm/io.h> | #include <asm/io.h> | ||||||
|  | @ -37,6 +40,52 @@ unsigned long notrace timer_read_counter(void) | ||||||
| extern unsigned long __weak timer_read_counter(void); | extern unsigned long __weak timer_read_counter(void); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_TIMER | ||||||
|  | static int notrace dm_timer_init(void) | ||||||
|  | { | ||||||
|  | 	struct udevice *dev; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	if (!gd->timer) { | ||||||
|  | 		ret = uclass_first_device(UCLASS_TIMER, &dev); | ||||||
|  | 		if (ret) | ||||||
|  | 			return ret; | ||||||
|  | 		if (!dev) | ||||||
|  | 			return -ENODEV; | ||||||
|  | 		gd->timer = dev; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ulong notrace get_tbclk(void) | ||||||
|  | { | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	ret = dm_timer_init(); | ||||||
|  | 	if (ret) | ||||||
|  | 		return ret; | ||||||
|  | 
 | ||||||
|  | 	return timer_get_rate(gd->timer); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | unsigned long notrace timer_read_counter(void) | ||||||
|  | { | ||||||
|  | 	unsigned long count; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	ret = dm_timer_init(); | ||||||
|  | 	if (ret) | ||||||
|  | 		return ret; | ||||||
|  | 
 | ||||||
|  | 	ret = timer_get_count(gd->timer, &count); | ||||||
|  | 	if (ret) | ||||||
|  | 		return ret; | ||||||
|  | 
 | ||||||
|  | 	return count; | ||||||
|  | } | ||||||
|  | #endif /* CONFIG_TIMER */ | ||||||
|  | 
 | ||||||
| uint64_t __weak notrace get_ticks(void) | uint64_t __weak notrace get_ticks(void) | ||||||
| { | { | ||||||
| 	unsigned long now = timer_read_counter(); | 	unsigned long now = timer_read_counter(); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue