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