Liang Hua

i.mx6的IOMUX代码不够直观

Discussion created by Liang Hua on Mar 13, 2014

第一次接触飞思卡尔i.mx6,但觉得IOMUX代码不够直观。

不能很直观的知道一个signal使用哪个pad的ALT。而且目前代码的可扩展性不好。

目前寄存器是32位还好,使用了64位来组合起来。如果是64位呢?找不到128位变量类型吧?


我写了一个,大家不要拍砖啊。

 

#include <stdio.h>
#include <stdlib.h>
#include <linux/kernel.h>
#include <linux/slab.h>


/* 
    this demo suitable for i.MX6Q
*/



enum{
    MODE_ALT0=0,
    MODE_ALT1,
    MODE_ALT2,
    MODE_ALT3,
    MODE_ALT4,
    MODE_ALT5,
    MODE_ALT6,
    MODE_ALT7,
};



#define iomux_reg32                    unsigned int
#define TO_NAME(_x)                    #_x
#define INVALID_INPUT_REG                ~0

struct pad_reg_detail{//e.g. IOMUXC_SW_PAD_CTL_PAD_SD1_DATA2
        unsigned SRE:1;//bit0
        unsigned reserved_2_1:2;//reserved bit[2:1]
        unsigned DSE:3;//bit[5:3]
        unsigned SPEED:2;//bit[7:6]
        unsigned reserved_10_8:2;//reserved bit[10:8]
        unsigned ODE:1;//bit11
        unsigned PKE:1;//bit12
        unsigned PUE:1;//bit13
        unsigned PUS:2;//bit[15:14]
        unsigned HYS:1;//bit16
        unsigned reserved_31_17:15;//bit[31:17]
};

struct mux_reg_detail {
    unsigned ALT:3;//mode, bit[2:0]
    unsigned reserved_3:1;//bit3
    unsigned SION:1;//bit4
    unsigned reserved_31_5:27;//bit[31:5]
};    

struct  input_reg_detail{
    unsigned DAISY:1;//bit0
    unsigned reserved_31_1:31;//bit[31:1]
}detail;    

struct IOMUX_pad_signal_cfg{
    char *pad_name;//pad name(e.g. SD1_DAT2)
    char *signal_name;//signal name(e.g. PWM2_OUT)

    /* Pad/Group Register */
    unsigned int pad_group_reg_addr;//register address or offset(e.g. IOMUXC_SW_PAD_CTL_PAD_SD1_DATA2)
    union{
        unsigned int value;//pad group reg value
        struct pad_reg_detail detail;//pad group reg value
    }pad_group_reg_data;

    /* Mux Select Register */
    unsigned int mux_reg_addr;//register address or offset(e.g. IOMUXC_SW_MUX_CTL_PAD_SD1_DATA2)
    union{
        unsigned int value;//value
        struct mux_reg_detail detail;//value    
    }mux_reg_data;
    
    /* Input Select Register */
    unsigned int input_reg_addr;////register address or offset(e.g. IOMUXC_ECSPI5_SS1_SELECT_INPUT)
    union{
        unsigned int value;//value
        struct input_reg_detail detail;//value
    }input_reg_data;
};

struct IOMUX_pad_signal_cfg mx6q_pad_cfgs[]={
    //----------------------------------------- pad: others ----------------------------------------------
    //......
    //----------------------------------------- pad: SD1_DAT2 ----------------------------------------------
    {//SD1_DATA2
        .pad_name = TO_NAME(SD1_DAT2),//pad: SD1_DAT2
        .signal_name = TO_NAME(SD1_DATA2),//config as SD1_DATA2
        .pad_group_reg_addr = 0x20E0734,//register address or offset of IOMUXC_SW_PAD_CTL_PAD_SD1_DATA2
        .pad_group_reg_data = {
            .value = 0,
            //or
            //.detail = {
            //    m = n,
     

       //}
        },
        .mux_reg_addr = 0x020E034C,//register address or offset of IOMUXC_SW_MUX_CTL_PAD_SD1_DATA2
        .mux_reg_data = {
            //or value = m | n | ...
            .detail={
                .ALT = MODE_ALT0,
            },
        },
        .input_reg_addr = INVALID_INPUT_REG,//no input reg    
    },{//ECSPI5_SS1
        .pad_name = TO_NAME(SD1_DAT2),//pad: SD1_DAT2
        .signal_name = TO_NAME(ECSPI5_SS1),//config as ECSPI5_SS1
        .pad_group_reg_addr = 0x20E0734,//register address or offset of IOMUXC_SW_PAD_CTL_PAD_SD1_DATA2
        .pad_group_reg_data = {
            .value = 0,
        },
        .mux_reg_addr = 0x020E034C,//register address or offset of IOMUXC_SW_MUX_CTL_PAD_SD1_DATA2
        .mux_reg_data = {
            .detail = {
                .ALT = MODE_ALT1,
            },
        },
        .input_reg_addr = 0x20E0838,//register address or offset of IOMUXC_ECSPI5_SS1_SELECT_INPUT
        .input_reg_data = {
            .detail = {
                .DAISY = 1,
            },
        },
    },{//GPT_COMPARE2
        .pad_name = TO_NAME(SD1_DAT2),//pad: SD1_DAT2
        .signal_name = TO_NAME(GPT_COMPARE2),//config as GPT_COMPARE2
        .pad_group_reg_addr = 0x20E0734,//register address or offset of IOMUXC_SW_PAD_CTL_PAD_SD1_DATA2
        .pad_group_reg_data = {
            .value = 0,
        },
        .mux_reg_addr = 0x020E034C,//register address or offset of IOMUXC_SW_MUX_CTL_PAD_SD1_DATA2
        .mux_reg_data = {
            .detail = {
                .ALT = MODE_ALT2,//mode
            },
        },
        .input_reg_addr = INVALID_INPUT_REG,//no input reg
    },{//PWM2_OUT
        .pad_name = TO_NAME(SD1_DAT2),//pad: SD1_DAT2
        .signal_name = TO_NAME(PWM2_OUT),//config as PWM2_OUT
        .pad_group_reg_addr = 0x20E0734,//register address or offset of IOMUXC_SW_PAD_CTL_PAD_SD1_DATA2
        .pad_group_reg_data={
            .value = 0,
        },
        .mux_reg_addr = 0x020E034C,//register address or offset of IOMUXC_SW_MUX_CTL_PAD_SD1_DATA2
        .mux_reg_data = {
            .detail = {
                .ALT = MODE_ALT3,
            },
        },
        .input_reg_addr = INVALID_INPUT_REG,//no input reg
    },{//WDOG1_B
        .pad_name = TO_NAME(SD1_DAT2),//pad: SD1_DAT2
        .signal_name = TO_NAME( WDOG1_B),//config as WDOG1_B
        .pad_group_reg_addr = 0x20E0734,//register address or offset of IOMUXC_SW_PAD_CTL_PAD_SD1_DATA2
        .pad_group_reg_data={
            .value = 0,
        },
        .mux_reg_addr = 0x020E034C,//register address or offset of IOMUXC_SW_MUX_CTL_PAD_SD1_DATA2
        .mux_reg_data = {
            .detail = {
                .ALT = MODE_ALT4,
            },
        },
        .input_reg_addr = INVALID_INPUT_REG,//no input reg
    },{//GPIO1_IO19
        .pad_name = TO_NAME(SD1_DAT2),//pad: SD1_DAT2
        .signal_name = TO_NAME( GPIO1_IO19),//config as GPIO1_IO19
        .pad_group_reg_addr = 0x20E0734,//register address or offset of IOMUXC_SW_PAD_CTL_PAD_SD1_DATA2
        .pad_group_reg_data={
            .value = 0,
        },
        .mux_reg_addr = 0x020E034C,//register address or offset of IOMUXC_SW_MUX_CTL_PAD_SD1_DATA2
        .mux_reg_data = {
            .detail = {
                .ALT = MODE_ALT5,
            },
        },
        .input_reg_addr = INVALID_INPUT_REG,//no input reg
    },{//WDOG1_RESET_B_DEB
        .pad_name = TO_NAME(SD1_DAT2),//pad: SD1_DAT2
        .signal_name = TO_NAME( GPIO1_IO19),//config as GPIO1_IO19
        .pad_group_reg_addr = 0x20E0734,//register address or offset of IOMUXC_SW_PAD_CTL_PAD_SD1_DATA2
        .pad_group_reg_data = {
            .value = 0,
        },
        .mux_reg_addr = 0x020E034C,//register address or offset of IOMUXC_SW_MUX_CTL_PAD_SD1_DATA2
        .mux_reg_data = {
            .detail = {
                .ALT = MODE_ALT6,
            },
        },
        .input_reg_addr = INVALID_INPUT_REG,//no input reg
    }
    
    //----------------------------------------- pad: others ----------------------------------------------
    //......
};

unsigned int *iomux_base;//IOMUX base address


int index_of_pad_cfgs(char *pad_name, char *signal_name, struct IOMUX_pad_signal_cfg *pad_cfgs)
{
    int i=0;
    int count=0;
    int ret=-1;
    
    
    if (NULL == pad_name || NULL==signal_name || NULL == pad_cfgs){
        return ret;
    }
    
    count = ARRAY_SIZE(pad_cfgs);
    
    for (i=0; i<count; i++){
        if (!strcmp(signal_name), pad_cfgs[i].signal_name && !strcmp(pad_name), pad_cfgs[i].pad_name) { //exist
            return i;
        }
    }
    
    return -1;
}

int setup_multiple_pads(int index, struct IOMUX_pad_signal_cfg *pad_cfgs)
{
    if (0 > index || NULL == pad_cfgs){
        return -1;
    }
    
    //here use base + offset address, just for demo
    *(iomux_base + pad_cfgs[index].pad_group_reg_addr) =  pad_cfgs[index].pad_group_reg_data.value;
    *(iomux_base + pad_cfgs[index].mux_reg_addr) =  pad_cfgs[index].mux_reg_data.value;
    if (INVALID_INPUT_REG != pad_cfgs[index].input_reg_addr){//some signal has no input register
        *(iomux_base + pad_cfgs[index].input_reg_addr) =  pad_cfgs[index].input_reg_data.value;
    }
    
    return 0;
}

int index_of_mx6q_pad_cfgs(char *pad_name, char *signal_name)
{
    return index_of_pad_cfgs(pad_name, signal_name, mx6q_pad_cfgs);
}

int mx6q_setup_multiple_pads(int index)
{
    return setup_multiple_pads(index, mx6q_pad_cfgs);
}

/* config the pad of SD1_DAT2 as PWM2_OUT signal */
#define MX6Q_MUX_SD1_DAT2___PWM2_OUT                index_of_mx6q_pad_cfgs("SD1_DAT2", "PWM2_OUT")        

int init_IOMUX(){
    iomux_base = kmalloc(1024 * sizeof(unsigned int), GFP_KERNEL);//no map, just for demo
    
    mx6q_setup_multiple_pads(MX6Q_MUX_SD1_DAT2___PWM2_OUT);
    
    return 0;
}

Outcomes