第一次接触飞思卡尔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;
}