您的位置:首页 > 其它

am335x_gpio

2016-06-03 21:37 316 查看
/************************************************************************
*                       am335x_gpio
*   本文主要记录am335x gpio初始化过程,包括设置引脚复用寄存器,驱动注册。
*   主要文件:
*      设备初始化:
*          arch/arm/mach-omap2/board_am335xevm.c
*          arch/arm/mach-omap2/io.c
*          arch/arm/mach-omap2/omap_hwmod_33xx_data.c
*          arch/arm/mach-omap2/mux.c
*      驱动初始化:
*          drivers/gpio/gpio-omap.c
*
*                                         Tony Liu, 2016-4-30, Shenzhen
***********************************************************************/
//设备注册和初始化
arch/arm/mach-omap2/board_am335xevm.c
MACHINE_START(AM335XEVM, "am335xevm")
/* Maintainer: Texas Instruments */
.atag_offset    = 0x100,
.map_io        = am335x_evm_map_io,
.init_early    = am33xx_init_early,      --------+    //GPIO寄存器地址指定
.init_irq    = ti81xx_init_irq,                  |
.handle_irq     = omap3_intc_handle_irq,         |
.timer        = &omap3_am33xx_timer,             |
.init_machine    = am335x_evm_init,      --------|------------------------+    //GPIO引脚复用配置
MACHINE_END                                          |                        |
|                        |
kernel/arch/arm/mach-omap2/io.c             <--------+                        |
void __init am33xx_init_early(void)                                           |
{                                                                             |
omap2_set_globals_am33xx();                                               |
omap3xxx_check_revision();                                                |
am33xx_check_features();                                                  |
omap_common_init_early();                                                 |
am33xx_voltagedomains_init();                                             |
omap44xx_prminst_init();                                                  |
am33xx_powerdomains_init();                                               |
omap44xx_cminst_init();                                                   |
am33xx_clockdomains_init();                                               |
am33xx_hwmod_init();                    ---------+                        |
omap_hwmod_init_postsetup();                     |                        |
omap3xxx_clk_init();                             |                        |
}                                                    |                        |
|                        |
kernel/arch/arm/mach-omap2/omap_hwmod_33xx_data.c    |                        |
int __init am33xx_hwmod_init(void)           <-------+                        |
{                                                                             |
return omap_hwmod_register(am33xx_hwmods);   ---------------------------+ |
}                                                                           | |
//将寄存器的信息添加到链表中                                                    | |
int __init omap_hwmod_register(struct omap_hwmod **ohs)                     | |
{                                                                           | |
int r, i;                                                               | |
| |
if (!ohs)                                                               | |
return 0;                                                           | |
| |
i = 0;                                                                  | |
do {                                                                    | |
r = _register(ohs[i]);                           -----------------+ | |
WARN(r, "omap_hwmod: %s: _register returned %d\n", ohs[i]->name,  | | |
r);                                                          | | |
} while (ohs[++i]);                                                   | | |
| | |
return 0;                                                             | | |
}                                                                         | | |
| | |
static int __init _register(struct omap_hwmod *oh)       <----------------+ | |
{                                                                           | |
int ms_id;                                                              | |
| |
if (!oh || !oh->name || !oh->class || !oh->class->name ||               | |
(oh->_state != _HWMOD_STATE_UNKNOWN))                               | |
return -EINVAL;                                                     | |
| |
pr_debug("omap_hwmod: %s: registering\n", oh->name);                    | |
//查找这个结构是否已经添加到双链中                                           | |
if (_lookup(oh->name))                                                  | |
return -EEXIST;                                                     | |
| |
ms_id = _find_mpu_port_index(oh);                    --------------+    | |
if (!IS_ERR_VALUE(ms_id))                                          |    | |
oh->_mpu_port_index = ms_id;                                   |    | |
else                                                               |    | |
oh->_int_flags |= _HWMOD_NO_MPU_PORT;                          |    | |
|    | |
list_add_tail(&oh->node, &omap_hwmod_list);                        |    | |
|    | |
spin_lock_init(&oh->_lock);                                        |    | |
|    | |
oh->_state = _HWMOD_STATE_REGISTERED;                              |    | |
|    | |
/*                                                                 |    | |
* XXX Rather than doing a strcmp(), this should test a flag       |    | |
* set in the hwmod data, inserted by the autogenerator code.      |    | |
*/                                                                |    | |
if (!strcmp(oh->name, MPU_INITIATOR_NAME))                         |    | |
mpu_oh = oh;                                                   |    | |
|    | |
return 0;                                                          |    | |
}                                                                      |    | |
|    | |
static int __init _find_mpu_port_index(struct omap_hwmod *oh)     <----+    | |
{                                                                           | |
int i;                                                                  | |
int found = 0;                                                          | |
| |
if (!oh || oh->slaves_cnt == 0)                                         | |
return -EINVAL;                                                     | |
| |
for (i = 0; i < oh->slaves_cnt; i++) {                                  | |
struct omap_hwmod_ocp_if *os = oh->slaves[i];                       | |
| |
if (os->user & OCP_USER_MPU) {                                      | |
found = 1;                                                      | |
break;                                                          | |
}                                                                   | |
}                                                                       | |
| |
if (found)                                                              | |
pr_debug("omap_hwmod: %s: MPU OCP slave port ID  %d\n",             | |
oh->name, i);                                                  | |
else                                                                    | |
pr_debug("omap_hwmod: %s: no MPU OCP slave port found\n",           | |
oh->name);                                                     | |
| |
return (found) ? i : -EINVAL;                                           | |
}                                                                           | |
| |
| |
//gpio                                                                      | |
static __initdata struct omap_hwmod *am33xx_hwmods[] = {         <----------+ |
......                                                                    |
/* gpio class */                                                          |
&am33xx_gpio0_hwmod,                                                      |
&am33xx_gpio1_hwmod,      -----+                                          |
&am33xx_gpio2_hwmod,           |                                          |
&am33xx_gpio3_hwmod,           |                                          |
......                         |                                          |
};                                 |                                          |
V                                          |
static struct omap_hwmod am33xx_gpio1_hwmod = {                               |
.name        = "gpio2",                                                   |
.class        = &am33xx_gpio_hwmod_class,      ------------------+        |
.clkdm_name    = "l4ls_clkdm",                                   |        |
.mpu_irqs    = am33xx_gpio1_irqs,              ----------------+ |        |
.main_clk    = "gpio1_ick",                                    | |        |
.flags        = HWMOD_CONTROL_OPT_CLKS_IN_RESET,               | |        |
.prcm        = {                                               | |        |
.omap4    = {                                              | |        |
.clkctrl_offs    = AM33XX_CM_PER_GPIO1_CLKCTRL_OFFSET, | |        |
.modulemode    = MODULEMODE_SWCTRL,                    | |        |
},                                                         | |        |
},                                                             | |        |
.opt_clks    = gpio1_opt_clks,              ----------+        | |        |
.opt_clks_cnt    = ARRAY_SIZE(gpio1_opt_clks),        |        | |        |
.dev_attr    = &gpio_dev_attr,              ------+   |        | |        |
.slaves        = am33xx_gpio1_slaves,       ------|---|--------| |-+      |
.slaves_cnt    = ARRAY_SIZE(am33xx_gpio1_slaves), |   |        | | |      |
};                                                    |   |        | | |      |
|   |        | | |      |
|   |        | | |      |
static struct omap_gpio_dev_attr gpio_dev_attr = { <--+   |        | | |      |
.bank_width    = 32,                                  |        | | |      |
.dbck_flag    = true,                                 |        | | |      |
};                                                        |        | | |      |
|        | | |      |
static struct omap_hwmod_opt_clk gpio1_opt_clks[] = {  <--+        | | |      |
{ .role = "dbclk", .clk = "gpio1_dbclk" },                     | | |      |
};                                                                 | | |      |
| | |      |
//指定irq中断号,和芯片手册中一样                                       | | |      |
| | |      |
static struct omap_hwmod_irq_info am33xx_gpio1_irqs[] = {    <-----+ | |      |
{ .irq = 98 },                                                   | |      |
{ .irq = -1 }                                                    | |      |
};                                                                   | |      |
| |      |
//所有的GPIO都有相同的am33xx_gpio_hwmod_class                          | |      |
static struct omap_hwmod_class am33xx_gpio_hwmod_class = {     <-----+ |      |
.name        = "gpio",                                             |      |
.sysc        = &am33xx_gpio_sysc,                      ----------+ |      |
.rev        = 2,                                                 | |      |
};                                                                   | |      |
| |      |
static struct omap_hwmod_class_sysconfig am33xx_gpio_sysc = {    <---+ |      |
.rev_offs    = 0x0000,    //GPIO_REVISION 寄存器                    |      |
.sysc_offs    = 0x0010,    //GPIO_SYSCONFIG                        |      |
.syss_offs    = 0x0114,    //GPIO_SYSSTATUS                        |      |
.sysc_flags    = (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |         |      |
SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |               |      |
SYSS_HAS_RESET_STATUS),                                 |      |
.idlemodes    = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |            |      |
SIDLE_SMART_WKUP),                                         |      |
.sysc_fields    = &omap_hwmod_sysc_type1,  ---+                    |      |
};                                                |                    |      |
V                    |      |
struct omap_hwmod_sysc_fields omap_hwmod_sysc_type1 = {                |      |
.midle_shift    = SYSC_TYPE1_MIDLEMODE_SHIFT,                      |      |
.clkact_shift    = SYSC_TYPE1_CLOCKACTIVITY_SHIFT,                 |      |
.sidle_shift    = SYSC_TYPE1_SIDLEMODE_SHIFT,                      |      |
.enwkup_shift    = SYSC_TYPE1_ENAWAKEUP_SHIFT,                     |      |
.srst_shift    = SYSC_TYPE1_SOFTRESET_SHIFT,                       |      |
.autoidle_shift    = SYSC_TYPE1_AUTOIDLE_SHIFT,                    |      |
};                                                                     |      |
|      |
static struct omap_hwmod_ocp_if *am33xx_gpio1_slaves[] = {      <------+      |
&am33xx_l4_per__gpio1,       ----+                                        |
};                                   |                                        |
V                                        |
static struct omap_hwmod_ocp_if am33xx_l4_per__gpio1 = {                      |
.master        = &am33xx_l4per_hwmod,   ---------+                        |
.slave        = &am33xx_gpio1_hwmod,             |                        |
.clk        = "l4ls_gclk",                       |                        |
.addr        = am33xx_gpio1_addrs,               |                        |
.user        = OCP_USER_MPU | OCP_USER_SDMA,     |                        |
};                                                   |                        |
|                        |
static struct omap_hwmod am33xx_l4per_hwmod = {   <--+                        |
.name        = "l4_per",                                                  |
.class        = &l4_hwmod_class,                                          |
.clkdm_name    = "l4ls_clkdm",                                            |
.flags        = (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET),               |
.masters    = am33xx_l4_per_masters,      -----------------+              |
.masters_cnt    = ARRAY_SIZE(am33xx_l4_per_masters),       |              |
.slaves        = am33xx_l4_per_slaves,         ------------|--+           |
.slaves_cnt    = ARRAY_SIZE(am33xx_l4_per_slaves),         |  |           |
};                                                             |  |           |
|  |           |
static struct omap_hwmod_ocp_if *am33xx_l4_per_masters[] = { <-+  |           |
&am33xx_l4_per__dcan0,                                        |           |
&am33xx_l4_per__dcan1,                                        |           |
&am33xx_l4_per__gpio1,                                        |           |
&am33xx_l4_per__gpio2,            ------+                     |           |
&am33xx_l4_per__gpio3,                  |                     |           |
};                                          |                     |           |
V                     |           |
static struct omap_hwmod_ocp_if am33xx_l4_per__gpio2 = {          |           |
.master        = &am33xx_l4per_hwmod,                         |           |
.slave        = &am33xx_gpio2_hwmod,                          |           |
.clk        = "l4ls_gclk",                                    |           |
.addr        = am33xx_gpio2_addrs,  ----------+               |           |
.user        = OCP_USER_MPU | OCP_USER_SDMA,  |               |           |
};                                                |               |           |
|               |           |
/* L4 PER -> GPIO2 */                             V               |           |
//GPIO2对应的寄存器地址                                             |           |
static struct omap_hwmod_addr_space am33xx_gpio2_addrs[] = {      |           |
{                                                             |           |
.pa_start    = 0x481AC000,                                |           |
.pa_end        = 0x481AC000 + SZ_4K - 1,                  |           |
.flags        = ADDR_TYPE_RT,                             |           |
},                                                            |           |
{ }                                                           |           |
};                                                                |           |
|           |
/* Slave interfaces on the L4_PER interconnect */                 |           |
static struct omap_hwmod_ocp_if *am33xx_l4_per_slaves[] = {    <--+           |
&am33xx_l3_slow__l4_per,    -----+                                        |
};                                   |                                        |
V                                        |
static struct omap_hwmod_ocp_if am33xx_l3_slow__l4_per = {                    |
.master     = &am33xx_l3slow_hwmod,                                       |
.slave        = &am33xx_l4per_hwmod,                                      |
.user        = OCP_USER_MPU,                                              |
};                                                                            |
|
//GPIO引脚复用配置                                                              |
static void __init am335x_evm_init(void)                 <--------------------+
{
am33xx_cpuidle_init();
am33xx_mux_init(board_mux);
omap_serial_init();
am335x_evm_i2c_init();
omap_sdrc_init(NULL, NULL);
usb_musb_init(&musb_board_data);

omap_board_config = am335x_evm_config;
omap_board_config_size = ARRAY_SIZE(am335x_evm_config);

daughter_brd_detected = false;
//自己定义的函数
setup_xxx_xxxx();                                           --------------+
|
/*create  /proc/boardname to export info to userspace*/                   |
proc_init();                                                              |
|
/* Create an alias for icss clock */                                      |
if (clk_add_alias("pruss", NULL, "pruss_uart_gclk", NULL))                |
pr_warn("failed to create an alias: icss_uart_gclk --> pruss\n");     |
/* Create an alias for gfx/sgx clock */                                   |
if (clk_add_alias("sgx_ck", NULL, "gfx_fclk", NULL))                      |
pr_warn("failed to create an alias: gfx_fclk --> sgx_ck\n");          |
}                                                                             |
|
static void setup_xxx_xxxx(void)                                <-------------+
{
/*which doesn't have Write Protect pin LAN8710A_PHY_ID */
am335x_mmc[0].gpio_wp = -EINVAL;

int ret;
+-----------------------------------------+
//配置设备所有引脚复用               |                                         |
_configure_device(EVM_SK, xxx_xxxx_dev_cfg, PROFILE_NONE);     ----------+  |
//phy配置                                                                 |  |
am33xx_cpsw_init(AM33XX_CPSW_MODE_MII, xxx_xxxx_phy1, xxx_xxxx_phy2);    |  |
phy_register_fixup_for_uid(LAN8710A_PHY_ID , AM335X_EVM_PHY_MASK,        |  |
am33xx_evm_tx_clk_dly_phy_fixup);           |  |
}                                                                            |  |
|  |
static void _configure_device(int evm_id, struct evm_dev_cfg *dev_cfg,   <---+  |
int profile)                                                                |
{                                                                               |
int i;                                                                      |
|
am335x_evm_set_id(evm_id);                                                  |
|
//循环调用结构体数组的初始化函数,设置引脚复用                                    |
if (profile == PROFILE_NONE) {                                              |
for (i = 0; dev_cfg->device_init != NULL; dev_cfg++) {                  |
if (dev_cfg->device_on == DEV_ON_BASEBOARD)                         |
dev_cfg->device_init(evm_id, profile);                          |
else if (daughter_brd_detected == true)                             |
dev_cfg->device_init(evm_id, profile);                          |
}                                                                       |
} else {                                                                    |
for (i = 0; dev_cfg->device_init != NULL; dev_cfg++) {                  |
if (dev_cfg->profile & profile) {                                   |
if (dev_cfg->device_on == DEV_ON_BASEBOARD)                     |
dev_cfg->device_init(evm_id, profile);                      |
else if (daughter_brd_detected == true)                         |
dev_cfg->device_init(evm_id, profile);                      |
}                                                                   |
}                                                                       |
}                                                                           |
}                                                                               |
|
static struct evm_dev_cfg xxx_xxxx_dev_cfg[] = {                   <------------+
......
{gpio_keys_init_forlinx,  DEV_ON_BASEBOARD, PROFILE_ALL},
{gpio_led_init,  DEV_ON_BASEBOARD, PROFILE_ALL},          ---------+
......                                                             |
{NULL, 0, 0},                                                      |
};                                                                     |
|
static void gpio_led_init(int evm_id, int profile)             <-------+
{
int err;             +--------------------------------+
|                                |
setup_pin_mux(gpio_led_mux);            --------------|----------+
err = platform_device_register(&leds_gpio);   --------|----------|------------------+
if (err)                                              |          |                  |
pr_err("failed to register gpio led device\n");   |          |                  |
}                                                         |          |                  |
|          |                  |
static struct pinmux_config gpio_led_mux[] = {      <-----+          |                  |
{"gpmc_a0.gpio1_16", OMAP_MUX_MODE7 | AM33XX_PIN_INPUT},         |                  |
{"gpmc_a1.gpio1_17", OMAP_MUX_MODE7 | AM33XX_PIN_INPUT},         |                  |
{"gpmc_a2.gpio1_18", OMAP_MUX_MODE7 | AM33XX_PIN_INPUT},         |                  |
{"gpmc_a3.gpio1_19", OMAP_MUX_MODE7 | AM33XX_PIN_INPUT},         |                  |
{"emu1.gpio3_8", OMAP_MUX_MODE7 | AM33XX_PIN_INPUT},             |                  |
{NULL, 0},                                                       |                  |
};                                                                   |                  |
|                  |
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);  ---+                 |
|                 |
}                                                                     |                 |
|                 |
arch/arm/mach-omap2/mux.c                                             |                 |
int __init omap_mux_init_signal(const char *muxname, int val)     <---+                 |
{                                                                                       |
struct omap_mux_partition *partition = NULL;                                        |
struct omap_mux *mux = NULL;                                                        |
u16 old_mode;                                                                       |
int mux_mode;                                                                       |
//确认muxname字符窜中配置的模式是否存在                                                 |
mux_mode = omap_mux_get_by_name(muxname, &partition, &mux);   ----+                 |
if (mux_mode < 0)                                                 |                 |
return mux_mode;                                              |                 |
//读取旧的模式                                                      |                 |
old_mode = omap_mux_read(partition, mux->reg_offset);        -----|------------+    |
mux_mode |= val;                                                  |            |    |
pr_debug("%s: Setting signal %s 0x%04x -> 0x%04x\n",              |            |    |
__func__, muxname, old_mode, mux_mode);                  |            |    |
//将模式和至写入寄存器中,配置引脚复用                                  |            |    |
omap_mux_write(partition, mux_mode, mux->reg_offset);        -----|------------|--+ |
|            |  | |
return 0;                                                         |            |  | |
}                                                                     |            |  | |
|            |  | |
arch/arm/mach-omap2/mux.c                                             |            |  | |
int omap_mux_get_by_name(const char *muxname,                   <-----+            |  | |
struct omap_mux_partition **found_partition,                           |  | |
struct omap_mux **found_mux)                                           |  | |
{                                                                                  |  | |
struct omap_mux_partition *partition;    +---------------------------+         |  | |
|                           |         |  | |
list_for_each_entry(partition, &mux_partitions, node) {              |         |  | |
struct omap_mux *mux = NULL;                                     |         |  | |
int mux_mode = _omap_mux_get_by_name(partition, muxname, &mux);  | -----+  |  | |
if (mux_mode < 0)                                                |      |  |  | |
continue;                                                    |      |  |  | |
|      |  |  | |
*found_partition = partition;                                    |      |  |  | |
*found_mux = mux;                                                |      |  |  | |
|      |  |  | |
return mux_mode;                                                 |      |  |  | |
}                                                                    |      |  |  | |
|      |  |  | |
return -ENODEV;                                                      |      |  |  | |
}                                                                        |      |  |  | |
|      |  |  | |
static LIST_HEAD(mux_partitions);               <------------------------+      |  |  | |
|  |  | |
|  |  | |
static int __init _omap_mux_get_by_name(struct omap_mux_partition *partition, <-+  |  | |
const char *muxname,                                           |  | |
struct omap_mux **found_mux)                                   |  | |
{                                                                                  |  | |
struct omap_mux *mux = NULL;                                                   |  | |
struct omap_mux_entry *e;                                                      |  | |
const char *mode_name;                                                         |  | |
int found = 0, found_mode = 0, mode0_len = 0;                                  |  | |
struct list_head *muxmodes = &partition->muxmodes;                             |  | |
//查找模块的名字,例如"gpmc_a0.gpio1_16",名字是 gpio1_16                            |  | |
mode_name = strchr(muxname, '.');                                              |  | |
if (mode_name) {                                                               |  | |
mode0_len = strlen(muxname) - strlen(mode_name);                           |  | |
mode_name++;                                                               |  | |
} else {                                                                       |  | |
mode_name = muxname;                                                       |  | |
}                                                                              |  | |
|  | |
list_for_each_entry(e, muxmodes, node) {                                       |  | |
char *m0_entry;                                                            |  | |
int i;                                                                     |  | |
|  | |
mux = &e->mux;                                                             |  | |
m0_entry = mux->muxnames[0];                                               |  | |
//查找例如“gpmc_a0.gpio1_16"中,是否存在 gpmc_a0这个默认的模式0                 |  | |
/* First check for full name in mode0.muxmode format */                    |  | |
if (mode0_len && strncmp(muxname, m0_entry, mode0_len))                    |  | |
continue;                                                              |  | |
/* 按照模式名称进行匹配,查找这个引脚是否有对应名称的模式                          |  | |
* 例如“gpio1_16",如果存在,返回模式对应的index                                |  | |
*/                                                                        |  | |
/* Then check for muxmode only */                                          |  | |
for (i = 0; i < OMAP_MUX_NR_MODES; i++) {                                  |  | |
char *mode_cur = mux->muxnames[i];                                     |  | |
|  | |
if (!mode_cur)                                                         |  | |
continue;                                                          |  | |
|  | |
if (!strcmp(mode_name, mode_cur)) {                                    |  | |
*found_mux = mux;                                                  |  | |
found++;                                                           |  | |
found_mode = i;                                                    |  | |
}                                                                      |  | |
}                                                                          |  | |
}                                                                              |  | |
|  | |
if (found == 1) {                                                              |  | |
return found_mode;                                                         |  | |
}                                                                              |  | |
|  | |
if (found > 1) {                                                               |  | |
pr_err("%s: Multiple signal paths (%i) for %s\n", __func__,                |  | |
found, muxname);                                                    |  | |
return -EINVAL;                                                            |  | |
}                                                                              |  | |
|  | |
pr_err("%s: Could not find signal %s\n", __func__, muxname);                   |  | |
|  | |
return -ENODEV;                                                                |  | |
}                                                                                  |  | |
|  | |
u16 omap_mux_read(struct omap_mux_partition *partition, u16 reg)          <--------+  | |
{                                                                                     | |
if (partition->flags & OMAP_MUX_REG_8BIT)                                         | |
return __raw_readb(partition->base + reg);                                    | |
else                                                                              | |
return __raw_readw(partition->base + reg);                                    | |
}                                                                                     | |
| |
void omap_mux_write(struct omap_mux_partition *partition, u16 val,            <-------+ |
u16 reg)                                                                 |
{                                                                                       |
if (partition->flags & OMAP_MUX_REG_8BIT)                                           |
__raw_writeb(val, partition->base + reg);                                       |
else                                                                                |
__raw_writew(val, partition->base + reg);                                       |
}                                                                                       |
|
|
static struct platform_device leds_gpio = {                         <-------------------+
.name    = "leds-gpio",
.id    = -1,
.dev    = {
.platform_data    = &gpio_led_info,
},                                 |
};                                     |
|
V
static struct gpio_led_platform_data gpio_led_info = {
.leds        = gpio_leds,             -------+
.num_leds    = ARRAY_SIZE(gpio_leds),        |
};                                               |
|
static struct gpio_led gpio_leds[] = {    <------+
{
.name            = "usr0",
.gpio            = GPIO_TO_PIN(1, 16),    /* D1 */
.active_low        = 1,
},
{
.name            = "usr1",
.gpio            = GPIO_TO_PIN(1, 17),    /* D2 */
.active_low        = 1,
},
{
.name            = "usr2",
.gpio            = GPIO_TO_PIN(1, 18),    /* D3 */
.active_low        = 1,
},
{
.name            = "usr3",
.gpio            = GPIO_TO_PIN(1, 19),    /* D4 */
.active_low        = 1,
},
{
.name            = "heartbeat",
.gpio            = GPIO_TO_PIN(3, 8),    /* D4 */
.default_trigger    = "heartbeat",
},
};

驱动注册
// linux/drivers/gpio/gpio-omap.c
static int __init omap_gpio_drv_reg(void)
{
return platform_driver_register(&omap_gpio_driver);    -----------+
}                                                                     |
postcore_initcall(omap_gpio_drv_reg);                                 |
|
static int __init omap_gpio_sysinit(void)                             |
{                                                                     |
mpuio_init();                                                     |
|
#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS)   |
if (cpu_is_omap16xx() || cpu_class_is_omap2())                    |
register_syscore_ops(&omap_gpio_syscore_ops);                 |
#endif                                                                |
|
return 0;                                                         |
}                                                                     |
|
arch_initcall(omap_gpio_sysinit);                                     |
|
|
static struct platform_driver omap_gpio_driver = {        <-----------+
.probe        = omap_gpio_probe,   -----+
.driver        = {                      |
.name    = "omap_gpio",             |
},                                      |
};                                          |
V
static int __devinit omap_gpio_probe(struct platform_device *pdev)
{
static int gpio_init_done;
struct omap_gpio_platform_data *pdata;
struct resource *res;
int id;
struct gpio_bank *bank;

if (!pdev->dev.platform_data)
return -EINVAL;

pdata = pdev->dev.platform_data;

if (!gpio_init_done) {
int ret;

ret = init_gpio_info(pdev);
if (ret)
return ret;
}

id = pdev->id;
bank = &gpio_bank[id];

res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (unlikely(!res)) {
dev_err(&pdev->dev, "GPIO Bank %i Invalid IRQ resource\n", id);
return -ENODEV;
}

bank->irq = res->start;
bank->virtual_irq_start = pdata->virtual_irq_start;
bank->method = pdata->bank_type;
bank->dev = &pdev->dev;
bank->dbck_flag = pdata->dbck_flag;
bank->stride = pdata->bank_stride;
bank->width = pdata->bank_width;

bank->regs = pdata->regs;       //将寄存器地址复制给bank->regs结构体

if (bank->regs->set_dataout && bank->regs->clr_dataout)
bank->set_dataout = _set_gpio_dataout_reg;
else
bank->set_dataout = _set_gpio_dataout_mask;

spin_lock_init(&bank->lock);

/* Static mapping, never released */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (unlikely(!res)) {
dev_err(&pdev->dev, "GPIO Bank %i Invalid mem resource\n", id);
return -ENODEV;
}

bank->base = ioremap(res->start, resource_size(res));
if (!bank->base) {
dev_err(&pdev->dev, "Could not ioremap gpio bank%i\n", id);
return -ENOMEM;
}

pm_runtime_enable(bank->dev);
pm_runtime_get_sync(bank->dev);

omap_gpio_mod_init(bank, id);         -----------------------------------+
omap_gpio_chip_init(bank);        ------------------------------+        |
omap_gpio_show_rev(bank);  ---+                                 |        |
|                                 |        |
if (!gpio_init_done)          |                                 |        |
gpio_init_done = 1;       |                                 |        |
|                                 |        |
return 0;                     |                                 |        |
}                                 |                                 |        |
//查看版本号并打印                  V                                 |        |
static void __init omap_gpio_show_rev(struct gpio_bank *bank)       |        |
{                                                                   |        |
static bool called;                                             |        |
u32 rev;                                                        |        |
|        |
if (called || bank->regs->revision == USHRT_MAX)                |        |
return;                                                     |        |
|        |
rev = __raw_readw(bank->base + bank->regs->revision);           |        |
pr_info("OMAP GPIO hardware version %d.%d\n",                   |        |
(rev >> 4) & 0x0f, rev & 0x0f);                             |        |
|        |
called = true;                                                  |        |
}                                                                   |        |
|        |
static void __devinit omap_gpio_chip_init(struct gpio_bank *bank) <-+        |
{                                                                            |
int j;                                                                   |
static int gpio;                                                         |
|
bank->mod_usage = 0;                                                     |
/*                                                                       |
* REVISIT eventually switch from OMAP-specific gpio structs             |
* over to the generic ones                                              |
*/                                                                      |
bank->chip.request = omap_gpio_request;                                  |
bank->chip.free = omap_gpio_free;                                        |
bank->chip.direction_input = gpio_input;             ----------+         |
bank->chip.get = gpio_get;                                     |         |
bank->chip.direction_output = gpio_output;                     |         |
bank->chip.set_debounce = gpio_debounce;                       |         |
bank->chip.set = gpio_set;                                     |         |
bank->chip.to_irq = gpio_2irq;                                 |         |
if (bank_is_mpuio(bank)) {                                     |         |
bank->chip.label = "mpuio";                                |         |
#ifdef CONFIG_ARCH_OMAP16XX                                        |         |
bank->chip.dev = &omap_mpuio_device.dev;                   |         |
#endif                                                             |         |
bank->chip.base = OMAP_MPUIO(0);                           |         |
} else {                                                       |         |
bank->chip.label = "gpio";                                 |         |
bank->chip.base = gpio;                                    |         |
gpio += bank->width;                                       |         |
}                                                              |         |
bank->chip.ngpio = bank->width;                                |         |
|         |
gpiochip_add(&bank->chip);                                     |         |
|         |
for (j = bank->virtual_irq_start;                              |         |
j < bank->virtual_irq_start + bank->width; j++) {     |         |
irq_set_lockdep_class(j, &gpio_lock_class);                |         |
irq_set_chip_data(j, bank);                                |         |
if (bank_is_mpuio(bank)) {                                 |         |
omap_mpuio_alloc_gc(bank, j, bank->width);             |         |
} else {                                                   |         |
irq_set_chip(j, &gpio_irq_chip);                       |         |
irq_set_handler(j, handle_simple_irq);                 |         |
set_irq_flags(j, IRQF_VALID);                          |         |
}                                                          |         |
}                                                              |         |
irq_set_chained_handler(bank->irq, gpio_irq_handler);          |         |
irq_set_handler_data(bank->irq, bank);                         |         |
}                                                                  |         |
|         |
static int gpio_input(struct gpio_chip *chip, unsigned offset)  <--+         |
{                                                                            |
struct gpio_bank *bank;                                                  |
unsigned long flags;                                                     |
|
bank = container_of(chip, struct gpio_bank, chip);                       |
spin_lock_irqsave(&bank->lock, flags);                                   |
_set_gpio_direction(bank, offset, 1);                          --------+ |
spin_unlock_irqrestore(&bank->lock, flags);                            | |
return 0;                                                              | |
}                                                                          | |
| |
static void _set_gpio_direction(struct gpio_chip *chip, unsigned offset, <-+ |
int dir)                                                     |
{                                                                            |
unsigned int base = GPIO_BASE(offset / 32);                              |
unsigned int reg;                                                        |
|
reg = __raw_readl(base + GPIO_DIR);                                      |
if (dir)                                                                 |
reg |= 1 << (offset % 32);                                           |
else                                                                     |
reg &= ~(1 << (offset % 32));                                        |
__raw_writel(reg, base + GPIO_DIR);                                      |
}                                                                            |
|
static void omap_gpio_mod_init(struct gpio_bank *bank, int id)         <-----+
{
if (cpu_class_is_omap2()) {
if (cpu_is_omap44xx() || cpu_is_am33xx()) {
__raw_writel(0xffffffff, bank->base +
OMAP4_GPIO_IRQSTATUSCLR0);
__raw_writel(0x00000000, bank->base +
OMAP4_GPIO_DEBOUNCENABLE);
/* Initialize interface clk ungated, module enabled */
__raw_writel(0, bank->base + OMAP4_GPIO_CTRL);
} else if (cpu_is_omap34xx()) {
__raw_writel(0x00000000, bank->base +
OMAP24XX_GPIO_IRQENABLE1);
__raw_writel(0xffffffff, bank->base +
OMAP24XX_GPIO_IRQSTATUS1);
__raw_writel(0x00000000, bank->base +
OMAP24XX_GPIO_DEBOUNCE_EN);

/* Initialize interface clk ungated, module enabled */
__raw_writel(0, bank->base + OMAP24XX_GPIO_CTRL);
} else if (cpu_is_omap24xx()) {
static const u32 non_wakeup_gpios[] = {
0xe203ffc0, 0x08700040
};
if (id < ARRAY_SIZE(non_wakeup_gpios))
bank->non_wakeup_gpios = non_wakeup_gpios[id];
}
} else if (cpu_class_is_omap1()) {
if (bank_is_mpuio(bank))
__raw_writew(0xffff, bank->base +
OMAP_MPUIO_GPIO_MASKIT / bank->stride);
if (cpu_is_omap15xx() && bank->method == METHOD_GPIO_1510) {
__raw_writew(0xffff, bank->base
+ OMAP1510_GPIO_INT_MASK);
__raw_writew(0x0000, bank->base
+ OMAP1510_GPIO_INT_STATUS);
}
if (cpu_is_omap16xx() && bank->method == METHOD_GPIO_1610) {
__raw_writew(0x0000, bank->base
+ OMAP1610_GPIO_IRQENABLE1);
__raw_writew(0xffff, bank->base
+ OMAP1610_GPIO_IRQSTATUS1);
__raw_writew(0x0014, bank->base
+ OMAP1610_GPIO_SYSCONFIG);

/*
* Enable system clock for GPIO module.
* The CAM_CLK_CTRL *is* really the right place.
*/
omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04,
ULPD_CAM_CLK_CTRL);
}
if (cpu_is_omap7xx() && bank->method == METHOD_GPIO_7XX) {
__raw_writel(0xffffffff, bank->base
+ OMAP7XX_GPIO_INT_MASK);
__raw_writel(0x00000000, bank->base
+ OMAP7XX_GPIO_INT_STATUS);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: