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.

PWM problem on DM365

Hello everyone! I encountered a strange problem with pwm driver on DM365 ,the kernel version is 2.6.37. I added a configuration function in file arch\arm\mach-davinci\Board-dm365-ipnc.c as below:

static void dm365_init_pwm(void)
{
unsigned int temp1 = 0;
unsigned int temp2 = 0;

//config pinmux1 to enable pwm0 and pwm1
davinci_cfg_reg(DM365_PWM0);
davinci_cfg_reg(DM365_PWM1);

//enable pwm0
davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, 0, DAVINCI_LPSC_PWM0, PSC_STATE_SYNCRST, 1);
davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, 0, DAVINCI_LPSC_PWM0, PSC_STATE_ENABLE, 1);

//enable pwm1
davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, 0, DAVINCI_LPSC_PWM1, PSC_STATE_SYNCRST, 1);
davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, 0, DAVINCI_LPSC_PWM1, PSC_STATE_ENABLE, 1);

//config pwm0
void __iomem *pwm0_PER = (void __iomem *)IO_ADDRESS(0x01c22000+0x14);
void __iomem *pwm0_PH1D = (void __iomem *)IO_ADDRESS(0x01c22000+0x18);
void __iomem *pwm0_CFG = (void __iomem *)IO_ADDRESS(0x01c22000+0x08);
void __iomem *pwm0_START = (void __iomem *)IO_ADDRESS(0x01c22000+0x0c);

//print its virtual addr
temp2 = (unsigned int)pwm0_PER;
printk(KERN_INFO "kernel:dm365_init_pwm(),pwm0_PER=0x%x\n",temp2);
temp1 = __raw_readl(pwm0_PER);
printk(KERN_INFO "kernel:dm365_init_pwm(),Former pwm0_PER=%d\n",temp1);
temp1 = 80000;
__raw_writel(temp1,pwm0_PER);
temp1 = __raw_readl(pwm0_PER);
printk(KERN_INFO "kernel:dm365_init_pwm(),NOW pwm0_PER=%d\n",temp1);


temp2 = (unsigned int)pwm0_CFG;
printk(KERN_INFO "kernel:dm365_init_pwm(),pwm0_CFG=0x%x\n",temp2);
temp1 = __raw_readl(pwm0_CFG);
printk(KERN_INFO "kernel:dm365_init_pwm(),Former pwm0_CFG=%d\n",temp1);
temp1 = 0x001;
__raw_writel(temp1,pwm0_CFG);
temp1 = __raw_readl(pwm0_CFG);
printk(KERN_INFO "kernel:dm365_init_pwm(),NOW pwm0_CFG=%d\n",temp1);

temp2 = (unsigned int)pwm0_PH1D;
printk(KERN_INFO "kernel:dm365_init_pwm(),pwm0_PH1D=0x%x\n",temp2);
temp1 = __raw_readl(pwm0_PH1D);
printk(KERN_INFO "kernel:dm365_init_pwm(),Former pwm0_PH1D=%d\n",temp1);
__raw_writel(20000,pwm0_PH1D);
temp1 = __raw_readl(pwm0_PH1D);
printk(KERN_INFO "kernel:dm365_init_pwm(),NOW pwm0_PH1D=%d\n",temp1);


temp2 = (unsigned int)pwm0_START;
printk(KERN_INFO "kernel:dm365_init_pwm(),pwm0_START=0x%x\n",temp2);
temp1 = __raw_readl(pwm0_START);
printk(KERN_INFO "kernel:dm365_init_pwm(),Former pwm0_Start=%d\n",temp1);
__raw_writel(0x001,pwm0_START);
temp1 = __raw_readl(pwm0_START);
printk(KERN_INFO "kernel:dm365_init_pwm(),NOW pwm0_START=%d\n",temp1);


//config pwm1
void __iomem *pwm1_PER = (void __iomem *)IO_ADDRESS(0x01c22400+0x14);
void __iomem *pwm1_PH1D = (void __iomem *)IO_ADDRESS(0x01c22400+0x18);
void __iomem *pwm1_CFG = (void __iomem *)IO_ADDRESS(0x01c22400+0x08);
void __iomem *pwm1_START = (void __iomem *)IO_ADDRESS(0x01c22400+0x0c);

temp2 = (unsigned int)pwm0_PER;
printk(KERN_INFO "kernel:dm365_init_pwm(),pwm1_PER=0x%x\n",temp2);
temp1 = __raw_readl(pwm1_PER);
printk(KERN_INFO "kernel:dm365_init_pwm(),Former pwm1_PER=%d\n",temp1);
temp1 = 80000;
__raw_writel(temp1,pwm1_PER);
temp1 = __raw_readl(pwm1_PER);
printk(KERN_INFO "kernel:dm365_init_pwm(),NOW pwm1_PER=%d\n",temp1);


temp2 = (unsigned int)pwm1_CFG;
printk(KERN_INFO "kernel:dm365_init_pwm(),pwm1_CFG=0x%x\n",temp2);
temp1 = __raw_readl(pwm1_CFG);
printk(KERN_INFO "kernel:dm365_init_pwm(),Former pwm1_CFG=%d\n",temp1);
temp1 = 0x001;
__raw_writel(temp1,pwm1_CFG);
temp1 = __raw_readl(pwm1_CFG);
printk(KERN_INFO "kernel:dm365_init_pwm(),NOW pwm1_CFG=%d\n",temp1);

temp2 = (unsigned int)pwm1_PH1D;
printk(KERN_INFO "kernel:dm365_init_pwm(),pwm1_PH1D=0x%x\n",temp2);
temp1 = __raw_readl(pwm1_PH1D);
printk(KERN_INFO "kernel:dm365_init_pwm(),Former pwm1_PH1D=%d\n",temp1);
__raw_writel(20000,pwm1_PH1D);
temp1 = __raw_readl(pwm1_PH1D);
printk(KERN_INFO "kernel:dm365_init_pwm(),NOW pwm1_PH1D=%d\n",temp1);


temp2 = (unsigned int)pwm0_START;
printk(KERN_INFO "kernel:dm365_init_pwm(),pwm1_START=0x%x\n",temp2);
temp1 = __raw_readl(pwm1_START);
printk(KERN_INFO "kernel:dm365_init_pwm(),Former pwm1_Start=%d\n",temp1);
__raw_writel(0x001,pwm1_START);
temp1 = __raw_readl(pwm1_START);
printk(KERN_INFO "kernel:dm365_init_pwm(),NOW pwm1_START=%d\n",temp1);
}

This simple function is called in dm365_evm_init() ,but the message it printed out  really puzzled me a lot :

[ 0.034634] kernel:dm365_init_pwm(),pwm0_PER=0xfec22014
[ 0.034692] kernel:dm365_init_pwm(),Former pwm0_PER=0
[ 0.034731] kernel:dm365_init_pwm(),NOW pwm0_PER=80000

[ 0.034767] kernel:dm365_init_pwm(),pwm0_CFG=0xfec22008
[ 0.034804] kernel:dm365_init_pwm(),Former pwm0_CFG=0
[ 0.034840] kernel:dm365_init_pwm(),NOW pwm0_CFG=1

[ 0.034876] kernel:dm365_init_pwm(),pwm0_PH1D=0xfec22018
[ 0.034913] kernel:dm365_init_pwm(),Former pwm0_PH1D=0
[ 0.034950] kernel:dm365_init_pwm(),NOW pwm0_PH1D=20000

[ 0.034987] kernel:dm365_init_pwm(),pwm0_START=0xfec2200c
[ 0.035025] kernel:dm365_init_pwm(),Former pwm0_Start=0
[ 0.035062] kernel:dm365_init_pwm(),NOW pwm0_START=0

[ 0.035098] kernel:dm365_init_pwm(),pwm1_PER=0xfec22014
[ 0.035134] kernel:dm365_init_pwm(),Former pwm1_PER=0
[ 0.035170] kernel:dm365_init_pwm(),NOW pwm1_PER=80000

[ 0.035207] kernel:dm365_init_pwm(),pwm1_CFG=0xfec22408
[ 0.035244] kernel:dm365_init_pwm(),Former pwm1_CFG=0
[ 0.035280] kernel:dm365_init_pwm(),NOW pwm1_CFG=1

[ 0.035315] kernel:dm365_init_pwm(),pwm1_PH1D=0xfec22418
[ 0.035352] kernel:dm365_init_pwm(),Former pwm1_PH1D=0
[ 0.035389] kernel:dm365_init_pwm(),NOW pwm1_PH1D=20000

[ 0.035426] kernel:dm365_init_pwm(),pwm1_START=0xfec2240c
[ 0.035464] kernel:dm365_init_pwm(),Former pwm1_Start=0
[ 0.035500] kernel:dm365_init_pwm(),NOW pwm1_START=0


I write 0x01 to START register and then read it out , it 's also 0x00, which means i can't write this register. Who can tell me where is the problem? 

Thanks in Advance

  • Anyone can help me to solve this problem?

  • JK,

    START is a write only register. So, you won't be able to read back the value. Please read the PWM document carefully.

  • Thank you very much for your reply! How careless I am! I use IPNC4.0 for my ip camera,and I write a pwm driver in the framework just like other modules. I am
    not sure whether I made another obvious mistake,but I can't make pwm module running successfully. Below is the pwm driver I wrote:

    CSL_Status CSL_pwmSetup(CSL_PwmHandle hndl,CSL_PwmSetPrm *data)
    {
    // CSL_Status status = CSL_SOK;
    CSL_PwmRegsOvly p=NULL;

    if(hndl == NULL || data == NULL){
    return CSL_EFAIL;
    }

    if(data->PwmID < 0 ||data->PwmID >=PWM_DEV_MAX)
    return CSL_EFAIL;

    //get virtual address of each pwm module
    switch(data->PwmID)
    {
    case 0:
    //pwm module0
    p=((CSL_PwmRegsOvly)CSL_PHYS_TO_VIRT((Uint32)CSL_PWM_PHYS_REGS));
    break;
    case 1:
    //pwm module1
    p=((CSL_PwmRegsOvly)CSL_PHYS_TO_VIRT((Uint32)CSL_PWM_PHYS_REGS+0x400));
    break;
    case 2:
    //pwm module2
    p=((CSL_PwmRegsOvly)CSL_PHYS_TO_VIRT((Uint32)CSL_PWM_PHYS_REGS+0x800));
    break;
    case 3:
    //pwm module3
    p=((CSL_PwmRegsOvly)CSL_PHYS_TO_VIRT((Uint32)CSL_PWM_PHYS_REGS+0xC00));
    break;
    default:
    return CSL_EFAIL;
    }
    printk(KERN_INFO "CSL: CSL_pwmSetup() , PwmID=%d, p = 0x%lx\n", data->PwmID,p);
    p->CFG = data->CFG;
    p->PCR = data->PCR;
    p->START = data->START;


    p->PER = data->PER;
    p->PH1D = data->PH1D;
    p->CFG = data->CFG;
    p->PCR = data->PCR;
    p->START = data->START;
    printk(KERN_INFO "\n\n");
    printk(KERN_INFO "CSL:CSL_pwmSetup(),&p->PER=%x\n",&(p->PER));
    printk(KERN_INFO "CSL:CSL_pwmSetup(),data->PER=%d\n",data->PER);
    printk(KERN_INFO "CSL:CSL_pwmSetup(),p->PER=%d\n",p->PER);

    printk(KERN_INFO "\n\n");
    printk(KERN_INFO "\n\nCSL:CSL_pwmSetup(),&p->PH1D=%x\n",&(p->PH1D));
    printk(KERN_INFO "CSL:CSL_pwmSetup(),data->PH1D=%d\n",data->PH1D);
    printk(KERN_INFO "CSL:CSL_pwmSetup(),p->PH1D=%d\n",p->PH1D);

    printk(KERN_INFO "\n\n");
    printk(KERN_INFO "\nCSL:CSL_pwmSetup(),&p->CFG=%x\n",&(p->CFG));
    printk(KERN_INFO "CSL:CSL_pwmSetup(),data->CFG=%d\n",data->CFG);
    printk(KERN_INFO "CSL:CSL_pwmSetup(),p->CFG=%d\n",p->CFG);

    printk(KERN_INFO "\n\n");
    printk(KERN_INFO "\n\nCSL:CSL_pwmSetup(),&p->PCR=%x\n",&(p->PCR));
    printk(KERN_INFO "CSL:CSL_pwmSetup(),data->PCR=%d\n",data->PCR);
    printk(KERN_INFO "CSL:CSL_pwmSetup(),p->PCR=%d\n",p->PCR);

    // printk(KERN_INFO "\n\n");
    // printk(KERN_INFO "\n\nCSL:CSL_pwmSetup(),&p->START=%x\n",&(p->START));
    // printk(KERN_INFO "CSL:CSL_pwmSetup(),data->START=%d\n",data->START);
    // printk(KERN_INFO "CSL:CSL_pwmSetup(),p->START=%d\n",p->START);
    return CSL_SOK;
    }

    I wrote a test program,Below is the result:

    [ 158.838104]
    [ 158.838161]
    [ 158.841196] CSL:CSL_pwmSetup(),&p->PER=fec22014
    [ 158.877152] CSL:CSL_pwmSetup(),data->PER=99999
    [ 158.881688] CSL:CSL_pwmSetup(),p->PER=0
    [ 158.922053]
    [ 158.922109]
    [ 158.947385]
    [ 158.947426]
    [ 158.947446] CSL:CSL_pwmSetup(),&p->PH1D=fec22018
    [ 158.962483] CSL:CSL_pwmSetup(),data->PH1D=80000
    [ 159.003132] CSL:CSL_pwmSetup(),p->PH1D=0
    [ 159.028251]
    [ 159.028297]
    [ 159.036326]
    [ 159.036358] CSL:CSL_pwmSetup(),&p->CFG=fec22008
    [ 159.042442] CSL:CSL_pwmSetup(),data->CFG=2
    [ 159.078933] CSL:CSL_pwmSetup(),p->CFG=0
    [ 159.082937]
    [ 159.082963]
    [ 159.126409]
    [ 159.126448]
    [ 159.126467] CSL:CSL_pwmSetup(),&p->PCR=fec22004
    [ 159.188122] CSL:CSL_pwmSetup(),data->PCR=1
    [ 159.192310] CSL:CSL_pwmSetup(),p->PCR=0

    From the above result we can see that all of the registers can not be written, but in the kernel code I posted first, all of these registers can be read out
    . So where is the problem?

    Thanks in advance!

  • JK,

    Print the PID register value and see whether you are getting the value mentioned in the TRM. If not there is something wrong with your physical base address or the mapping logic. 

    Also verify the CSL_PHYS_TO_VIRT() returns and uncached address as well.

  • Thanks for your reply!

    1、I printed PID of module0 out,that is:

    [ 99.721020] CSL: CSL_pwmSetup() , PwmID=0, p = 0xfec22000
    [ 99.843006] CSL:CSL_pwmSetup(),p->PID=0

    The result is not the same as the value described in the datasheet.

    2、I think there is no mistake with the physical address and the mapping logic because I also printed the virtual address out and they are all as the same as the address printed out in the file  arch\arm\mach-davinci\Board-dm365-ipnc.c, where these registers can be written or be read.

    For example,in the driver I wrote,the PER's virtual address of pwm module0 is :

    [ 158.841196] CSL:CSL_pwmSetup(),&p->PER=fec22014

    and in the kernel where PER can be written or be read it's virtual address is:

    [ 0.034634] kernel:dm365_init_pwm(),pwm0_PER=0xfec22014
    [ 0.034692] kernel:dm365_init_pwm(),Former pwm0_PER=0
    [ 0.034731] kernel:dm365_init_pwm(),NOW pwm0_PER=80000

    The two addresses are the same, so I think the mapping logic is right.

    3、" verify the CSL_PHYS_TO_VIRT() returns and uncached address as well."

    All of these registers are declared with the volatile keyword:

    typedef struct {
    volatile Uint32 PID;
    volatile Uint32 PCR;
    volatile Uint32 CFG;
    volatile Uint32 START;
    volatile Uint32 RPT;
    volatile Uint32 PER;
    volatile Uint32 PH1D;
    }CSL_PwmRegs;

    typedef volatile CSL_PwmRegs *CSL_PwmRegsOvly;

    So I think they are all uncached,but I can't get the right value from them……

    Thanks in Advance!


  • JK,

    1. PID has to be read out properly in any case.

    2. Instead of trusting the CSL_PHYS_TO_VIRT() can you simply try to do  ioremap() to get the virtual address? This will give out proper uncached virtual address for the physical address specified. Try to print the values and see.

    3. volatile and caching has no relation.

  • Hello Renjith,

    I encountered a strange problem with pwm driver on DM368 ,the kernel version is 2.6.32.17

    I want to generate pwm waveform of 200Khz - 2Mhz but i can able to generate till 100Khz above this frequency kernel crashes or processor hangs.

    Is DM368 capable of generating above freq range?

    can you please help me out to resolve this issue.

    Thanks,
    Mayur.

  • Must see, when  type next

    # cat /proc/iomem

    .

    .

    01c22c00-01c22fff : PWM3_davinci.0

    .

    .

    Above must be registered with the iomem access is available.

    First, Must add resource...

    arch/arm/mach-davinci/include/mach/dm365.h

    ---------------------------------------------------------------

    #define DM365_PWM3BASE 0x01C22C00

    arch/arm/mach-davinci/dm365.c

    --------------------------------------------

    static struct resource DM365_PWM3_Resources[]=

    {
    {
    .start=DM365_PWM3BASE,
    .end= DM365_PWM3BASE+SZ_1K-1,
    .flags=IORESOURCE_MEM,
    },
    };

    static struct platform_device DM365_PWM3_Device=
    {
    .name="PWM3_davinci",
    .id=0,
    .num_resources=ARRAY_SIZE(DM365_PWM3_Resources),
    .resource=DM365_PWM3_Resources,
    };

    void __init DM365_Init_PWM3(void)

    {
    platform_device_register(&DM365_PWM3_Device);
    }

    arch/arm/mach-davinci/board-dm368-ipnc.c

    ------------------------------------------------------------

    static __init void dm368_evm_init(void)
    {

    .

    .

    DM365_Init_PWM3();

    }