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.

eHRPWM linux driver for OMAP-L138

Other Parts Discussed in Thread: OMAP-L138, TPS65070, DA8XX

Hello,

i try to get the PWM running on Linux on an OMAP-L138 eXperimenter board.
The kernel is 2.6.34-rc5- (git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-davinci.git).

I configured the registers like in sprufl3b.pdf (eHRPWM User's Guide)
Figure 22. (Up, Single Edge Asymmetric Waveform, With Independent Modulation on EPWMxA and
EPWMxB Active High)

We need the EPWM1B output to control a LCD-LED, so we only added EPWM1B to the pin-mux settings.
Please see the kernel patch at the end of this message.

Looking at thread "Omap L138 eHRPWM so close...." ( http://e2e.ti.com/support/dsp/omap_applications_processors/f/42/t/43896.aspx )
i noticed to enable the pwm clk and set and clear the CFGCHIP1_TBCLKSYNC bit.

Doing this i am able to read back the pwm registers with reasonable values, but the counter never increments.
And there is no action on the EPWM1B pin (pin 29 on the board LCD connector)!

My question is:
What`s missing to get the pwm runnning?

In the DSP-PWM-Driver source at http://processors.wiki.ti.com/index.php/C6747_EHRPWM_Example
other clock sources are enabled beside the pwm clock:

      // PSC0
    PSC0_enable(0, 11); // SCR1 (BR4)
    PSC0_enable(0, 12); // SCR2 (BR3, BR5, BR6)
     // PSC1
    PSC1_enable(0, 17); // eHRPWM0/1/2
    PSC1_enable(0, 24); // SCR8 (BR15)
    PSC1_enable(0, 25); // SCR7 (BR12)
    PSC1_enable(0, 26); // SCR12 (BR18)

Is it essential to enable these clocks too?
  

Thank you!
Regards, Bastian.

P.S.

Please see the kernel patches and parts of the module driver source:


diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index 738ac47..507e0c9 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -578,7 +578,7 @@ static int __init pmic_tps65070_init(void)
 }
 
 static const short da850_evm_lcdc_pins[] = {
-    DA850_GPIO2_8, DA850_GPIO2_15,
+    DA850_GPIO2_8, DA850_GPIO2_15, DA850_EPWM1B,
     -1
 };
 
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 96bdf2c..b3f306d 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -335,6 +335,28 @@ static struct clk aemif_clk = {
     .flags        = ALWAYS_ENABLED,
 };
 
+static struct clk pwm1_clk = {
+    .name        = "pwm1",
+    .parent        = &pll0_sysclk2,
+    .lpsc        = DA8XX_LPSC1_PWM,
+    .flags        = ALWAYS_ENABLED,
+    .gpsc        = 1,
+};
+

 static struct clk_lookup da850_clks[] = {
     CLK(NULL,        "ref",        &ref_clk),
     CLK(NULL,        "pll0",        &pll0_clk),
@@ -376,6 +398,9 @@ static struct clk_lookup da850_clks[] = {
     CLK("da8xx_lcdc.0",    NULL,        &lcdc_clk),
     CLK("davinci_mmc.0",    NULL,        &mmcsd_clk),
     CLK(NULL,        "aemif",    &aemif_clk),
+    CLK(NULL,        "pwm1",        &pwm1_clk),
     CLK(NULL,        NULL,        NULL),
 };
 
@@ -538,6 +563,8 @@ static const struct mux_config da850_pins[] = {
     MUX_CFG(DA850, GPIO4_0,        10,    28,    15,    8,    false)
     MUX_CFG(DA850, GPIO4_1,        10,    24,    15,    8,    false)
     MUX_CFG(DA850, RTC_ALARM,    0,    28,    15,    2,    false)
+    MUX_CFG(DA850, EPWM1B,      5,    4,    15,    2,    false)
+
 #endif
 };
 
diff --git a/arch/arm/mach-davinci/include/mach/mux.h b/arch/arm/mach-davinci/include/mach/mux.h
index 923debe..ab7803a 100644
--- a/arch/arm/mach-davinci/include/mach/mux.h
+++ b/arch/arm/mach-davinci/include/mach/mux.h
@@ -903,6 +903,9 @@ enum davinci_da850_index {
     DA850_GPIO4_0,
     DA850_GPIO4_1,
     DA850_RTC_ALARM,
+
+    /* PWM */
+    DA850_EPWM1B,
 };
 
 enum davinci_tnetv107x_index {



kernel driver module:



#define DA8XX_LCDPWM_BASE 0x01F02000
#define TBPRD   0x0A
#define TBPHS   0x06
#define TBCNT   0x08
#define TBCTL   0x00
#define CMPA    0x12
#define CMPB    0x14
#define CMPCTL  0x0E
#define AQCTLA  0x16
#define AQCTLB  0x18

static void __iomem * da8xx_lcdpwm_base;

#define DA8XX_LCDPWM_VIRT(x)    (da8xx_lcdpwm_base + (x))

void __iomem *da8xx_syscfg0_base;

#define DA8XX_CFGCHIP1_REG    0x180
#define CFGCHIP1_TBCLKSYNC      BIT(4)
[...]

  if (davinci_cfg_reg(DA850_EPWM1B))
    {
      printk(KERN_ERR "lcd init: DA850_EPWM1B mux setup failed\n");
      return -ENOMEM;
    }

  da8xx_lcdpwm_base = ioremap(DA8XX_LCDPWM_BASE, SZ_4K);
  if (!da8xx_lcdpwm_base) {
    printk(KERN_ERR "lcdpwm init ioremap da8xx_lcdpwm_base failed:\n");
    return -ENOMEM;
  }

  da8xx_syscfg0_base = ioremap(DA8XX_SYSCFG0_BASE, SZ_4K);
  if (!da8xx_syscfg0_base) {
    printk(KERN_ERR "lcdpwm init ioremap da8xx_syscfg0_base failed:\n");
    return -ENOMEM;
  }

  //PWM user guide 2.3.4 page 24
  //  1. Enable the ePWM module clocks.
  //->2. Set TBCLKSYNC = 0. This will stop the time-base clock within
  //     any enabled ePWM module.
  //  3. Configure the prescaler values and desired ePWM modes.
  //  4. Set TBCLKSYNC = 1.
  v = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP1_REG));
  v &= ~CFGCHIP1_TBCLKSYNC;
  __raw_writel(v, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP1_REG));

  writew(600,DA8XX_LCDPWM_VIRT(TBPRD));//  600 (258h) Period = 601 TBCLK counts
  stmp = readw(DA8XX_LCDPWM_VIRT(TBPRD));
  printk(KERN_ERR "TBPRD: %i\n",stmp);

  writew(0,DA8XX_LCDPWM_VIRT(TBPHS));// TBPHS 0 Clear Phase Register to 0
  writew(0,DA8XX_LCDPWM_VIRT(TBCNT));// TBCNT 0 Clear TB counter

 //TBCTL
  stmp = 0;
 stmp |= TB_COUNT_UP<<0;//CTRMODE TB_COUNT_UP

 stmp |= TB_DISABLE<<2;//PHSEN TB_DISABLE Phase loading disabled
 stmp |= TB_SHADOW<<3;//PRDLD TB_SHADOW
 stmp |= TB_SYNC_DISABLE<<4;//SYNCOSEL TB_SYNC_DISABLE
 stmp |= TB_DIV1<<7;//HSPCLKDIV TB_DIV1 TBCLK = SYSCLK
 stmp |= TB_DIV1<<10;//CLKDIV TB_DIV1
 printk(KERN_ERR "TBCTL write: %i\n",stmp);
 writew(stmp,DA8XX_LCDPWM_VIRT(TBCTL));
 stmp = readw(DA8XX_LCDPWM_VIRT(TBCTL));
 printk(KERN_ERR "TBCTL read : %i\n",stmp);

 writew(350,DA8XX_LCDPWM_VIRT(CMPA));// CMPA 350 (15Eh) Compare A = 350 TBCLK counts
 writew(200,DA8XX_LCDPWM_VIRT(CMPB));// CMPB 200 (C8h) Compare B = 200 TBCLK counts

 //CMPCTL
 stmp = 0;
 stmp |= CC_SHADOW<<4;//SHDWAMODE CC_SHADOW
 stmp |= CC_SHADOW<<6;//SHDWBMODE CC_SHADOW
 stmp |= CC_CTR_ZERO<<0;//LOADAMODE CC_CTR_ZERO Load on CTR = 0
 stmp |= CC_CTR_ZERO<<2;//LOADBMODE CC_CTR_ZERO Load on CTR = 0
 printk(KERN_ERR "CMPCTL write: %i\n",stmp);
 writew(stmp,DA8XX_LCDPWM_VIRT(CMPCTL));
 stmp = readw(DA8XX_LCDPWM_VIRT(CMPCTL));
 printk(KERN_ERR "CMPCTL read : %i\n",stmp);

 //AQCTLA  no action
 stmp = 0;
 stmp |= AQ_SET<<0;//ZRO AQ_SET
 stmp |= AQ_CLEAR<<4;//CAU AQ_CLEAR
 printk(KERN_ERR "AQCTLA write: %i\n",stmp);
 writew(stmp,DA8XX_LCDPWM_VIRT(AQCTLA));
 stmp = readw(DA8XX_LCDPWM_VIRT(AQCTLA));
 printk(KERN_ERR "AQCTLA read : %i\n",stmp);

 //AQCTLB
 stmp = 0;
 stmp |= AQ_SET<<0;//ZRO AQ_SET
 stmp |= AQ_CLEAR<<8;//CBU AQ_CLEAR
 printk(KERN_ERR "AQCTLB write: %i\n",stmp);
 writew(stmp,DA8XX_LCDPWM_VIRT(AQCTLB));
 stmp = readw(DA8XX_LCDPWM_VIRT(AQCTLB));
 printk(KERN_ERR "AQCTLB read : %i\n",stmp);

  //PWM user guide 2.3.4 page 24
  //  1. Enable the ePWM module clocks.
  //  2. Set TBCLKSYNC = 0. This will stop the time-base clock within
  //     any enabled ePWM module.
  //  3. Configure the prescaler values and desired ePWM modes.
  //->4. Set TBCLKSYNC = 1.
  v = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP1_REG));
  v |= CFGCHIP1_TBCLKSYNC;
  __raw_writel(v, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP1_REG));

 stmp = readw(DA8XX_LCDPWM_VIRT(TBCNT));
 printk(KERN_ERR "TBCNT : %i\n",stmp);
 for(i=0;i<100000;i++)
   {
     printk(KERN_INFO "");
   }
 stmp = readw(DA8XX_LCDPWM_VIRT(TBCNT));
 printk(KERN_ERR "TBCNT : %i\n",stmp);
 for(i=0;i<100000;i++)
   {
     printk(KERN_INFO "");
   }
 stmp = readw(DA8XX_LCDPWM_VIRT(TBCNT));
 printk(KERN_ERR "TBCNT : %i\n",stmp);



The output of the driver:
TBPRD: 600
TBCTL write: 48
TBCTL read : 48
CMPCTL write: 0
CMPCTL read : 768
AQCTLA write: 18
AQCTLA read : 18
AQCTLB write: 258
AQCTLB read : 258
TBCNT : 0
TBCNT : 0
TBCNT : 0