转自 http://blog.chinaunix.net/uid-20543672-id-3067021.html

 

在移植内核的时候经常会遇到管脚复用(mux)的配置问题。在现在的linux内核中,TI的ARM芯片已经有比较通用的架构,这对于很多TI芯片都是通用的,这次以AM335X为例分析,以备后用。

1.硬件

对于许多TI的芯片来说,引脚复用的配置是在,Control Module(配置模块)的寄存器里配置的,(这个和三星的CPU不同,三星一般在GPIO的寄存器中配置)。所以当你需要配置这些寄存器的时候,青岛数据手册的Control Module的Pad Control Registers查找。

TI的CPU芯片手册有两种

一种是DataSheet(DS:数据手册),较小,只是大概介绍下芯片的结构;

另一种是Technical Reference Manual (TRM:技术参考手册)。较大,详细介绍芯片的各部分功能原理和寄存器定义。

在开发过程中,这两个手册都需要参考的,是互补的。

对于AM335X,关于引脚复用的列表及模式号用功能的对应可以再数据手册中找到:

2 Terminal Description:

2.2 Ball Characteristics

关于引脚复用寄存器定义及各引脚相应寄存器的偏移可以再TRM中找到:

9 Control Module

9.2 Functional Description

9.2.2 Pad Control Registers(包含引脚复用寄存器定义)

9.3 Control_Module Registers(包含引脚相应寄存器的偏移)

2.软件

由于TI的芯片架构类似,对于Linux内核来说,早就已经为这个做好了一个软件上的框架,无论在启动的初始化阶段还是在系统运行时,都可以通过这个框架提供的接口函数配置芯片的mux。下面就来简要分析一下。

以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节点链表头

*@nade :分区链表头

*/

struct omap_mux_partition{

const char    * name;

u32 flags;

u32          phys;

u32 size;

void __iomem *base;

struct   list_head muxmodes;

struct   list_head node;

};

这个数据结构中包含了芯片中几乎所有定义好的mux数据,它在mux数据初始化函数omap_mux_init中初始化,并添加到全局mux_partitions链表中(通过const成员)。而其中的muxmodes是所有mux信息节点的链表头,用来链接一下数据结构:

/**

*struct omap_mux_entry -mux信息节点

*@mux:omap_mux结构体

*@node:链表节点

*/

struct omap_mux_entry{

struct omap_mux         mux;

struct list_head    node;

};

而在以上数据结构中,struct   omap_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

};

而struct mux_partition中muxmodes链表及节点数据的初始化都是在omap_mux_init初始化函数中(omap_mux_init_list(partition,superset);),而struct omap_mux节点数据中信息是由mux33xx.h和mux33xx.c中提供的。你可以再mux33xx.c中看到一个巨大的struct omap_mux结构体数组的初始化代码,这个代码一看就明了。不同的芯片只需要根据芯片资料修改这个结构体就好了,但是am33xx这个结构体(当前)还不完善,gpio的数据还都是0.值得一提的是其中用到了一个宏:

#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;

};

以在最上层的板级初始化文件(board-am335xevm.c)中定义一个这样的结构体数组,确定所要初始化的引脚复用寄存器,交由omap_mux_init_signals(partition,board_mux);使用。例如:

#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_SLEWCRTL_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):((max_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_mux_modes,

NULL,board_subset,NULL

);

}

有了已经初始化好的struct mux_partition结构体,我们可以利用mux.h提供的许多函数方便的初始化各mux寄存器:

/**
 * 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);

但是am33xx的gpio成员(当前)还都是0,所有这些函数没法使用。

此外,在mux.h中还导出了其他的软件接口和数据结构,这些在am33xx中没有使用,有需要的时候再看。

在板级初始化代码(比如board-am335xevm.c)运行完芯片特定的MUX初始化函数(am33xx_mux_init(board_mux);)之后,也可以在各子系统初始化时通过上面的接口函数修改配置MUX,比如在am33xx中使用了自己封装的一个函数和结构体:

/* 模块引脚复用结构体 */
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;
    }
}
三、使用注意

上面初始化过的结构体和接口函数的定义都是带有"__init"和“__initdata”的,所以这些都只能在内核初始化代码中使用,一旦系统初始化结束并进入了文件系统,这些定义都会被free。所有它们不能在内核模块(.ok)中被调用,否则你就等着Oops吧。因为一个芯片的引脚复用一般是硬件设计的时候定死的,一般不可能在启动后更改。如果你是在要在模块中改变引脚复用配置,你只能通过自己ioremap相关寄存器再修改它们来实现。

Linux TI omap芯片 pinmux分析(以AM335X为例)相关推荐

  1. Linux下TI omap芯片 MUX 配置分析(以AM335X芯片为例)

    在移植内核的时候,通常会遇到引脚复用(MUX)的配置问题.在现在的Linux内核中,对于TI的ARM芯片,早已经有了比较通用的MUX配置框架.这对于许多TI的芯片都是通用的,这次看AM335X的代码顺 ...

  2. 安卓 体验linux mux,Linux下TI omap芯片 MUX 配置分析(以AM335X芯片为例)

    对于许多TI的芯片来说,引脚复用的配置是在Control Module(配置模块)的寄存器里配置的,(这个和三星的CPU有点不同,三星的一般在GPIO的寄存器中配置).所以当你需要配置这些寄存器的时候 ...

  3. TI OMAP MUX configure

    Linux下TI omap芯片 MUX 配置分析(以AM335X芯片为例) 在移植内核的时候,通常会遇到引脚复用(MUX)的配置问题.在现在的Linux内核中,对于TI的ARM芯片,早已经有了比较通用 ...

  4. Linux下TInbsp;omap芯片nbsp;MUX…

    原文地址 : http://blog.chinaunix.net/uid-20543672-id-3067021.html 感谢原作者 一.硬件   对于许多TI的芯片来说,引脚复用的配置是在 Con ...

  5. linux 电源管理源码分析,Linux 3.8.1 电源管理之OMAP Voltage Domain分析

    本系列文章将分析Linux对于OMAP的电源管理功能,以AM33XX作为实例(目前的硬件平台先主要关注AM335xStarterKit开发板),在必要时穿插其他相关内容. 在linux-3.8.1/a ...

  6. Linux USB On-The-Go(OTG) on OMAP H2 软件架构分析(一)

    原帖地址:http://blog.csdn.net/zkami/article/details/2508136 Linux USB "On-The-Go"(OTG) on OMAP ...

  7. Linux下TIomap芯片MUX配置

    在移植内核的时候,通常会遇到引脚复用(MUX)的配置问题.在现在的Linux内核中,对于TI的arm芯片,早已经有了比较通用的MUX配置框架.这对于许多TI的芯片都是通用的,这次看AM335X的代码顺 ...

  8. linux i2c 读写函数,Linux下读写芯片的I2C寄存器

    要想在Linux下读写芯片的I2C寄存器,一般需要在Linux编写一份该芯片的I2C驱动,关于Linux下如何编写I2C驱动,前一篇文章<手把手教你写Linux I2C设备驱动>已经做了初 ...

  9. Linux下读写芯片的I2C寄存器

    Linux下读写芯片的I2C寄存器 2012-01-10 11:40:18 标签:Linux 寄存器 驱动 读写 I2C 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本 ...

最新文章

  1. BZOJ 4025 二分图
  2. NUnit2.0详细使用方法
  3. Js_学无止境之延迟加载
  4. Wince程序内存和存储内存
  5. 1个价值80亿美元的iPod
  6. 工作166:错误的处理方式
  7. 高精除(信息学奥赛一本通-T1308)
  8. 企业如何才能选到最好的邮件系统合作伙伴?
  9. c++以空格分开的输入数组_技术贴,MATLAB矩阵与数组汇总讲解!
  10. python如何统计累计每日的人数‘’_每日一练 | Data Scientist amp; Business Analyst amp; Leetcode 面试题 902...
  11. 赣南师范大学科技学院计算机科学与技术,2021江西独立学院转设最新消息(新增两所):赣南师范大学科技学院转设公办?...
  12. 尴尬的风险管理如何深入下去-某公司为例
  13. Spring Boot 知识笔记(集成zookeeper)
  14. python arp 网关_python arp欺骗伪造网关代码
  15. VoLTE 信令分析手册
  16. CodeForces比赛规则
  17. 福昕阅读器无法添加书签
  18. 钣金缺口lisp_钣金件的编程展开及切割系统
  19. CSDN知识库构建,我以我血荐轩辕
  20. 国产智多晶FPGA 带Cortex-M3硬核CPU的FPGA器件简介

热门文章

  1. 91版本Chrome跨域解决办法
  2. 渲染引擎分析 - 鸿蒙(OpenHarmony) JS UI 源码阅读笔记
  3. 【向上取整/向下取整】C语言向上或向下取整 函数
  4. search语句的用法c语言,各位高手,search怎么用啊?我是新手,在这里多谢啦!!!...
  5. 双摄测距原理_技术科普 | 一颗不够就再来一颗!双摄手机原理解析
  6. 机器人操作系统ROS(23)关于导航路径优化
  7. HDU 3625 Examining the Rooms(10年天津网赛,斯特灵数)
  8. 【零基础强化学习】强化学习中的有模型和无模型
  9. BMP24位照片格式
  10. 【C语言】确定乒乓球比赛对战赛手名单