原文地址 : http://blog.chinaunix.net/uid-20543672-id-3067021.html
感谢原作者
一、硬件
- TI的CPU芯片手册有两种:
- 一种是datasheet(DS:数据手册),较小,只是大概介绍下芯片的结构;
- 另一种是Technical Reference Manual(TRM:技术参考手册),较大,详细介绍芯片的各部分功能原理和寄存器定义。
- 在开发过程中,这两个手册都需要参考,是互补的。
对于AM335X,关于引脚复用的列表及模式号与功能的对应可以在数据手册中找到:
2 Terminal Description:
2.2 Ball Characteristics
关于引脚复用寄存器定义及各引脚相应寄存器的偏移可以在TRM中找到:
9 Control Module
9.1 Control Module
9.1.3 Functional Description
9.1.3.2 Pad Control Registers (包含引脚复用寄存器定义)
9.1.5 Registers
9.1.5.1 CONTROL_MODULE Registers (包含引脚相应寄存器的偏移)
二、软件
以AM335X为例,相关代码位置:arch/arm/mach-omap2
- mux.h
- mux.c
- mux33xx.h
- mux33xx.c
- board-am335xevm.c
- (还有一些用到了:arch/arm/plat-omap/include/plat/omap_hwmod.h)
其中他们的层次关系是:
(1)重要的数据结构
- /**
-
* struct mux_partition - 包含分区相关信息 -
* @name: 当前分区名 -
* @flags: 本分区的特定标志 -
* @phys: 物理地址 -
* @size: 分区大小 -
* @base: ioremap 映射过的虚拟地址 -
* @muxmodes: 本分区mux节点链表头
-
* @node: 分区链表头 -
*/ - struct omap_mux_partition
{ -
const char *name;
-
u32 flags;
-
u32 phys;
-
u32 size;
-
void __iomem *base;
-
struct list_head muxmodes;
-
struct list_head node;
- };
- /**
-
* struct omap_mux_entry - mux信息节点 -
* @mux: omap_mux结构体
-
* @node: 链表节点 -
*/ - struct omap_mux_entry
{ -
struct omap_mux mux;
-
struct list_head node;
- };
而在以上数据结构中,struct omap_mux是记录单个mux节点数据的结构体:
- /**
-
* struct omap_mux - omap mux 寄存器偏移和值的数据 -
* @reg_offset: 从Control Module寄存器基地址算起的mux寄存器偏移 -
* @gpio: GPIO 编号 -
* @muxnames: 引脚可用的信号模式字符串指针数组
-
* @balls: 封装中可用的引脚
-
*/ - struct omap_mux
{ -
u16 reg_offset;
-
u16 gpio;
- #ifdef CONFIG_OMAP_MUX
-
char *muxnames[OMAP_MUX_NR_MODES];
- #ifdef CONFIG_DEBUG_FS
-
char *balls[OMAP_MUX_NR_SIDES];
- #endif
- #endif
- };
- #define _AM33XX_MUXENTRY(M0,
g, m0, m1, m2, m3, m4, m5, m6, m7) \
- {
\
-
.reg_offset = (AM33XX_CONTROL_PADCONF_##M0##_OFFSET), \
-
.gpio = (g), \
-
.muxnames = { m0, m1, m2, m3, m4, m5, m6, m7 }, \
- }
这个宏使得这个结构体数组的初始化变得清晰明了。
以上的数据结构是在系统初始化的时候使用的,在struct omap_mux_partition完成初始化后,omap_mux_init初始化函数最后会根据不同的板子初始化部分mux寄存器(omap_mux_init_signals(partition, board_mux);),其中牵涉到了以下结构体:
- /**
-
* struct omap_board_mux - 初始化mux寄存器的数据
-
* @reg_offset: 从Control Module寄存器基地址算起的mux寄存器偏移 -
* @mux_value: 希望设置的mux寄存器值
-
*/ - struct omap_board_mux
{ -
u16 reg_offset;
-
u16 value;
- };
- #ifdef CONFIG_OMAP_MUX
- static
struct omap_board_mux board_mux[] __initdata = {
-
AM33XX_MUX(I2C0_SDA, OMAP_MUX_MODE0 | AM33XX_SLEWCTRL_SLOW |
-
AM33XX_INPUT_EN | AM33XX_PIN_OUTPUT),
-
AM33XX_MUX(I2C0_SCL, OMAP_MUX_MODE0 | AM33XX_SLEWCTRL_SLOW |
-
AM33XX_INPUT_EN | AM33XX_PIN_OUTPUT),
-
{ .reg_offset = OMAP_MUX_TERMINATOR },
- };
- #else
- #define
board_mux NULL
- #endif
其中用到了一个宏:
- /*
如果引脚没有定义为输入,拉动电阻将会被禁用
-
* 如果定义为输入,所提供的标志位将确定拉动电阻的配置
-
*/ - #define AM33XX_MUX(mode0,
mux_value) \
- {
\
-
.reg_offset = (AM33XX_CONTROL_PADCONF_##mode0##_OFFSET), \
-
.value = (((mux_value) & AM33XX_INPUT_EN) ? (mux_value)\
-
: ((mux_value) | AM33XX_PULL_DISA)), \
- }
注意_AM33XX_MUXENTRY和AM33XX_MUX这两个宏,前者是用于struct omap_mux的;后者是用于struct omap_board_mux的。
(2)重要的接口函数
- /**
-
* omap_mux_init - MUX初始化的私有函数,请勿使用
-
* 由各板级特定的MUX初始化函数调用
-
*/ - int
omap_mux_init(const char *name, u32 flags, -
u32 mux_pbase, u32 mux_size, -
struct omap_mux *superset,
-
struct omap_mux *package_subset,
-
struct omap_board_mux *board_mux,
-
struct omap_ball *package_balls);
这个函数是内部用于初始化struct mux_partition的最总要的函数,但是这个函数并不作为接口函数使用,而是供各芯片初始化函数“*_mux_init”所使用的。比如AM33XX芯片:
- /**
-
* am33xx_mux_init() - 用板级特定的设置来初始化MUX系统
-
* @board_mux: 板级特定的MUX配置表
-
*/ - int
__init am33xx_mux_init(struct omap_board_mux *board_subset)
- {
-
return omap_mux_init("core", 0, AM33XX_CONTROL_PADCONF_MUX_PBASE,
-
AM33XX_CONTROL_PADCONF_MUX_SIZE, am33xx_muxmodes,
-
NULL, board_subset, NULL);
- }
- /**
-
* omap_mux_init_signal - 根据信号名字符串初始化一个引脚的mux
-
* @muxname: mode0_name.signal_name的格式的Mux名称
-
* @val: mux寄存器值
-
*/ - int
omap_mux_init_signal(const char *muxname, int val);
-
- /**
-
* omap_mux_get() - 通过名字返回一个mux分区
-
* @name: mux分区名
-
* -
*/ - struct omap_mux_partition
*omap_mux_get(const char *name);
-
- /**
-
* omap_mux_read() - 读取mux寄存器(通过分区结构体指针和寄存器偏移值)
-
* @partition: Mux分区
-
* @mux_offset: mux寄存器偏移
-
* -
*/ - u16 omap_mux_read(struct omap_mux_partition
*p, u16 mux_offset); -
- /**
-
* omap_mux_write() - 写mux寄存器(通过分区结构体指针和寄存器偏移值)
-
* @partition: Mux分区
-
* @val: 新的mux寄存器值
-
* @mux_offset: mux寄存器偏移
-
* -
* 这个函数仅有在非GPIO信号的动态复用需要
-
*/ - void omap_mux_write(struct omap_mux_partition
*p, u16 val, u16 mux_offset); -
- /**
-
* omap_mux_write_array() - 写mux寄存器阵列
-
* @partition: Mux分区
-
* @board_mux: mux寄存器阵列 (用MAP_MUX_TERMINATOR结尾) -
* -
* 这个函数仅有在非GPIO信号的动态复用需要
-
*/ - void omap_mux_write_array(struct omap_mux_partition
*p, -
struct omap_board_mux *board_mux);
在代码比较完备的芯片中,struct omap_mux中的gpio成员有被初始化过,这样就可以使用以下接口函数:
- /**
-
* omap_mux_init_gpio - 根据GPIO编号初始化一个信号引脚
-
* @gpio: GPIO编号
-
* @val: mux寄存器值
-
*/ - int
omap_mux_init_gpio(int gpio, int val);
-
- /**
-
* omap_mux_get_gpio() - 根据GPIO编号获取一个mux寄存器值
-
* @gpio: GPIO编号
-
* -
*/ - u16 omap_mux_get_gpio(int
gpio); -
- /**
-
* omap_mux_set_gpio() - 根据GPIO编号设定一个mux寄存器值
-
* @val: 新的mux寄存器值
-
* @gpio: GPIO编号
-
* -
*/ - void omap_mux_set_gpio(u16 val,
int gpio);
- /*
模块引脚复用结构体 */
- struct pinmux_config
{ -
const char *string_name; /* 信号名格式化字符串,“模式0字符串.目标模式字符串“ */
-
int val; /* 其他mux寄存器可选配置值 */
- };
-
- /*
- *
@pin_mux - 单个模块引脚复用结构体
- *
其中定义了本模块所有引脚复用细节.
- */
- static void setup_pin_mux(struct pinmux_config
*pin_mux)
- {
-
int i;
-
-
for (i = 0; pin_mux->string_name != NULL; pin_mux++)
-
omap_mux_init_signal(pin_mux->string_name, pin_mux->val);
-
- }
你可以在board-am335xevm.c中看到如下的代码:
- static struct pinmux_config
d_can_ia_pin_mux[] = { -
{"uart0_rxd.d_can0_tx", OMAP_MUX_MODE2 | AM33XX_PULL_ENBL},
-
{"uart0_txd.d_can0_rx", OMAP_MUX_MODE2 | AM33XX_PIN_INPUT_PULLUP},
-
{NULL, 0},
- };
-
- ......
- static void d_can_init(int
evm_id, int profile)
- {
-
switch (evm_id) {
-
case IND_AUT_MTR_EVM:
-
if ((profile == PROFILE_0) || (profile == PROFILE_1)) {
-
setup_pin_mux(d_can_ia_pin_mux);
-
/* Instance Zero */ -
am33xx_d_can_init(0);
-
}
-
break;
-
case GEN_PURP_EVM:
-
if (profile == PROFILE_1) {
-
setup_pin_mux(d_can_gp_pin_mux);
-
/* Instance One */ -
am33xx_d_can_init(1);
-
}
-
break;
-
default:
-
break;
-
}
- }
三、使用注意