This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM3359: dm timer

Part Number: AM3359


kann someone help to Programm hadware timer with kernel 4.19 for am335xx target. I found some example here, by this is for old Linux kernel.

  • #include <linux/module.h>		
    #include <linux/kernel.h>		
    #include <linux/init.h>			
    #include <linux/clk.h>		
    #include <linux/irq.h>
    #include <linux/interrupt.h>
    #include <asm/io.h>
    #include <linux/types.h>			
    #include <linux/platform_device.h>
    #include <linux/platform_data/dmtimer-omap.h>
    #include <linux/sched_clock.h>
    #include </opt/work/trunk/BSP/AM335X/Linux/linux-3.14.26-g2489c02/arch/arm/plat-omap/include/plat/counter-32k.h>
    #include </opt/work/trunk/BSP/AM335X/Linux/linux-3.14.26-g2489c02/arch/arm/plat-omap/include/plat/dmtimer.h>
    #include <linux/gpio.h>
    
    #define DRIVER_NAME "test_dev"
    #define TIMER_MAX 0xFFFFFFFF
    static struct omap_dm_timer *timer_ptr = NULL;
    static struct omap_dm_timer *timer_ptr1 = NULL;
    static int32_t timer_irq;
    static int32_t timer_irq1;
    static uint32_t timer_rate;
    u32 irq_count =0;
    
    
    static irqreturn_t timer_irq_handler( int irq, void * dev_id)
    {
    	unsigned int retval;
    
    	retval = omap_dm_timer_read_status(timer_ptr);
    	if (!retval)
    		return IRQ_NONE;
    
    	if (retval & ~OMAP_TIMER_INT_MATCH)
    		printk("Unexpected interrupt source: %x\n", retval);
    
    	omap_dm_timer_write_status(timer_ptr,
    				OMAP_TIMER_INT_MATCH	|
    				OMAP_TIMER_INT_OVERFLOW	|
    				OMAP_TIMER_INT_CAPTURE);
    
    	omap_dm_timer_read_status(timer_ptr);
    	
    	irq_count++;
    	omap_dm_timer_start(timer_ptr1);
    	if(irq_count > 100)
    	{
    	
    		omap_dm_timer_stop(timer_ptr);		
    		omap_dm_timer_stop(timer_ptr1);
    		printk("________________DM Timer Count  %d\n", irq_count );
    		irq_count =0;
    	}
    
    	return IRQ_HANDLED;
    }
    
    static irqreturn_t timer_irq_handler1( int irq, void * dev_id)
    {
    	unsigned int retval;
    
    
    	retval = omap_dm_timer_read_status(timer_ptr1);
    	if (!retval)
    		return IRQ_NONE;
    
    	if (retval & ~OMAP_TIMER_INT_MATCH)
    		printk("Unexpected interrupt source: %x\n", retval);
    
    	omap_dm_timer_write_status(timer_ptr1,
    				OMAP_TIMER_INT_MATCH	|
    				OMAP_TIMER_INT_OVERFLOW	|
    				OMAP_TIMER_INT_CAPTURE);
    
    	omap_dm_timer_read_status(timer_ptr1);
    
    	omap_dm_timer_stop(timer_ptr1);
    
    	return IRQ_HANDLED;
    }
    
    static int init_timing(struct omap_dm_timer *timer,unsigned int on_time,unsigned int off_time)
    {
    		
    	u32 load, match;
    	load = timer_rate * (on_time + off_time) / 1000;
    	match = timer_rate * on_time / 1000;
    	
    	omap_dm_timer_set_load(timer, 1, -load);
    	omap_dm_timer_set_match(timer, 1, -match); 
    	omap_dm_timer_write_counter(timer, - 2);
    	omap_dm_timer_set_pwm(timer, 1, 1, OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
    	omap_dm_timer_set_int_enable(timer, OMAP_TIMER_INT_MATCH);
    	return 0;
    }
    
    static int test_module_init(struct platform_device *pdev)
    {
    	int ret = 1,i;
    	struct clk *timer_clk;  
    
    	struct device_node *timer_device_node; 
    	struct device_node *timer_device_node1; 
    	printk(KERN_INFO " INIT  DM Timer\n");   
    	
    	timer_device_node = of_parse_phandle(pdev->dev.of_node, "DMtimer", 0); 
    
    	timer_ptr = omap_dm_timer_request_by_node(timer_device_node);
    	if(timer_ptr == NULL)
    	{
    		/* no timers available */
    		printk(KERN_INFO "Can't request specified DM Timer 4\n");
    		return -1;
    	}   
    
    	timer_device_node1 = of_parse_phandle(pdev->dev.of_node, "DMtimer1", 0); 
    
    	timer_ptr1 = omap_dm_timer_request_by_node(timer_device_node1);
    	if(timer_ptr1 == NULL)
    	{
    		/* no timers available */
    		printk(KERN_INFO "Can't request specified DM Timer 7\n");
    		return -1;
    	}   
    
    
    	/* Set the Clock source to the System Clock */
    	ret = omap_dm_timer_set_source(timer_ptr, OMAP_TIMER_SRC_SYS_CLK);
    	ret = omap_dm_timer_set_source(timer_ptr1, OMAP_TIMER_SRC_SYS_CLK);
    	// set prescalar to 1:1
    	//omap_dm_timer_set_prescaler(timer_ptr, 0); 
    
    	omap_dm_timer_enable(timer_ptr);
    	omap_dm_timer_enable(timer_ptr1);
    
    	/* Determine what IRQ the timer triggers */
    	timer_irq = omap_dm_timer_get_irq(timer_ptr);
    	timer_irq1 = omap_dm_timer_get_irq(timer_ptr1);
    	/* Setup the IRQ handler */
    	ret = request_irq(timer_irq, timer_irq_handler, IRQF_TIMER, "DMTimer 4", NULL);
    	/* Setup the IRQ handler */
    	ret = request_irq(timer_irq1, timer_irq_handler1, IRQF_TIMER, "DMTimer 7", NULL);
    
    	/* Get the Clock rate in Hz */
    	timer_clk = omap_dm_timer_get_fclk(timer_ptr);
    	timer_rate = clk_get_rate(timer_clk)/1000;
    
    	init_timing(timer_ptr,180,5);  //180 microsec
    	init_timing(timer_ptr1,100,5);   // 100 microsec
    
    
    	/* Start the timer */
    	omap_dm_timer_start(timer_ptr);
    	//omap_dm_timer_start(timer_ptr1);
    	
    	return 0;
    }
    
    
    static int test_module_exit(struct platform_device *pdev)
    {
    	int ret = 1;
    
    	/* stop the timer */
    	ret = omap_dm_timer_stop(timer_ptr);
    	printk(KERN_INFO "Timer Stop ret = %d\n", ret); 
    	ret = omap_dm_timer_stop(timer_ptr1);
    	printk(KERN_INFO "Timer Stop ret = %d\n", ret); 
    	/* Release the IRQ handler */
    	free_irq(timer_irq, NULL);
    	free_irq(timer_irq1, NULL);
    	printk(KERN_INFO "Free IRQ Done\n");    
    
    	/* Release the timer */
    	ret = omap_dm_timer_free(timer_ptr);
    	printk(KERN_INFO "Timer Free ret = %d\n", ret); 
    	ret = omap_dm_timer_free(timer_ptr1);
    	printk(KERN_INFO "Timer Free ret = %d\n", ret); 
    
    	return 0;
    }
    
    static const struct of_device_id test_module_timer_of_match[] = {
        { .compatible   ="ti,am335x-timer" },
        {},
    };
    
    static struct platform_driver test_module_timer_driver = {
        .driver = {
            .name   = DRIVER_NAME,
            .of_match_table = test_module_timer_of_match,
        },
        .probe  = test_module_init,
        .remove = test_module_exit,
    };
    
    module_platform_driver(test_module_timer_driver);
    
    MODULE_LICENSE("GPL");            
    MODULE_AUTHOR("Sahaya Darcius");    
    MODULE_DESCRIPTION("Sample DMTimer Test Driver");  
    MODULE_VERSION("0.1"); 
    

    I use this example, but it's not work. I have this error : 

    Can't request specified DM Timer 4

  • Hello Neguimeya,

    You posted a custom kernel driver. Note that the .probe function is set to test_module_init. That means that during bootup, when Linux is reading through the device tree and finds a node with compatible = ti,am335x-timer, then it will go to this driver and run function test_module_init. Note that in Linux Processor SDK 6.3, driver timer-ti-dm.c also lists compatible = "ti,am335x-timer'. I am not sure what happens when two different drivers list the same compatible string.

    1) Are you trying to create a custom kernel driver, or just access a timer from user space?

    2) What are you trying to do with the timer?

    Regards,

    Nick

  • Hello Nick,

    I have to programm a custom kernel driver. I will be use it to generated 400 nicrosecond PWM and I want to use timer dmtimer nummer 4. I have also change the name of timer for to compatible = "ti,am335x-timer-hadware" , but this does'nt work.