Problems using TC on 9260 (for PWM-like generation) [SOLVED]

Hi all,

I’m trying to write a linux kernel module, that should activate the TIOA3 and TIOB3, to output a pulse train. Later on, I’ll add a sysfs interface to control the pulse width and possibly the frequency.

However, I’m not able to get anything out on TIOA3 and TIOB3…

And I’ve probably got even worse problems, as it seems that I can’t read back any values at all from the TC-registers…

insmod ./atmel_tc_beeper_pwm.ko

register TC_BMR (0x000000C4) = 0x00000000

register TC_CMR (0x00000004) = 0x00000000

register TC_RC (0x0000001C) = 0x00000000

register TC_RB (0x00000018) = 0x00000000

register TC_RA (0x00000014) = 0x00000000

The code:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/clk.h>
#include <asm/io.h>
#include <mach/at91sam9260.h>
#include <mach/at91_tc.h>
#include <mach/gpio.h>


static volatile __iomem *tc_base;
struct clk *tc_clk;

static inline u32 at91_tc_read(unsigned int offset)
{
	return __raw_readl(tc_base + offset);
}

static inline void at91_tc_write(unsigned int offset, u32 value)
{
	__raw_writel(value, tc_base + offset);
}


static int __init beeper_init()
{
	at91_set_B_periph(AT91_PIN_PB0, 0);
	at91_set_B_periph(AT91_PIN_PB1, 0);

	tc_clk = clk_get(NULL, "tc3_clk");
	clk_enable(tc_clk);

	tc_base = ioremap(AT91SAM9260_BASE_TC3, 0xFC);
	if (!tc_base){
		printk("ERROR\n");
		goto unmap;
	}

	at91_tc_write(AT91_TC_CCR,
		      AT91_TC_CLKDIS);

	at91_tc_write(AT91_TC_BMR,
		      AT91_TC_TC0XC0S_NONE |
		      AT91_TC_TC1XC1S_NONE |
		      AT91_TC_TC2XC2S_NONE);

	printk(KERN_ALERT "register TC_BMR (0x%08X) = 0x%08X\n",
	       AT91_TC_BMR,
	       at91_tc_read(AT91_TC_BMR));

	at91_tc_write(AT91_TC_CMR,
		      AT91_TC_TIMER_CLOCK5 | /* slow clock, 32 kHz */
		      AT91_TC_WAVE | /* waveform mode */
		      AT91_TC_EEVTEDG_NONE | /* must be disabled for TIOB output */
		      AT91_TC_WAVESEL_UP); /* count up and wrap back to zero */

	wmb();

	printk(KERN_ALERT "register TC_CMR (0x%08X) = 0x%08X\n",
	       AT91_TC_CMR,
	       at91_tc_read(AT91_TC_CMR));

#define TIMER_COUNTER_MAX_DUTY 0x4000
	at91_tc_write(AT91_TC_RC,
		      TIMER_COUNTER_MAX_DUTY);

	wmb();

	printk(KERN_ALERT "register TC_RC (0x%08X) = 0x%08X\n",
	       AT91_TC_RC,
	       at91_tc_read(AT91_TC_RC));

	wmb();

/* Enable TC */
	at91_tc_write(AT91_TC_CCR,
		      AT91_TC_SWTRG | AT91_TC_CLKEN);

	wmb();

	at91_tc_write(AT91_TC_RB,
		      TIMER_COUNTER_MAX_DUTY/2);
	wmb();
	printk(KERN_ALERT "register TC_RB (0x%08X) = 0x%08X\n",
	       AT91_TC_RB,
	       at91_tc_read(AT91_TC_RB));

	at91_tc_write(AT91_TC_RA,
		      TIMER_COUNTER_MAX_DUTY/3);
	wmb();
	printk(KERN_ALERT "register TC_RA (0x%08X) = 0x%08X\n",
	       AT91_TC_RA,
	       at91_tc_read(AT91_TC_RA));

unmap:
	return 0;
}

static void __exit beeper_exit(void)
{
	printk("Removing beeper.\n");

	at91_tc_write(AT91_TC_CCR,
		      AT91_TC_CLKDIS);

	wmb();

	clk_disable(tc_clk);
	clk_put(tc_clk);
	iounmap(tc_base);
}

module_init(beeper_init);
module_exit(beeper_exit);

MODULE_AUTHOR("Author");
MODULE_DESCRIPTION("Use TC to create PWM for beeper");
MODULE_LICENSE("GPL");

Which results in:

# insmod ./atmel_tc_beeper_pwm.ko 
register TC_BMR (0x000000C4) = 0x00000000                                   
register TC_CMR (0x00000004) = 0x00000000                                   
register TC_RC (0x0000001C) = 0x00000000                                    
register TC_RB (0x00000018) = 0x00000000                                    
register TC_RA (0x00000014) = 0x00000000  
#

Thus, I’m not able to read out anything from the controllling registers. (And/or I’m not able to write to them).

I’m sure that I’m missing something simple…

Is there anyone that can spot something obvious? Or lead me in the correct path?

Thanks in advance!

Regards,

Problem solved. For some reason I didn’t see that I missed the type when declaring tv_base. It should be eg.```
static void volatile __iomem *tc_base;