在上篇博客中已经介绍了I2C的协议和要主要的地方,接下来看一下,在lk中的i2c配置
我们都知道,启动的时候会先跑lk然后再跑kernel,所以这里的配置就要小心了,一不留神可能就不能开机了。
直接以lk中已有的i2c来举例说明,其他的i2c可以仿照这个去添加和修改。
路径:/bootloader/lk/app/tests/i2c_test.c
void eeprom_read_test()
{
...............
dev = qup_blsp_i2c_init(BLSP_ID_2, QUP_ID_4, 100000, 19200000);
................
}
这里调用qup_blsp_i2c_init
路径:/bootloader/lk/platform/msm_shared/i2c_qup.c
struct qup_i2c_dev *qup_blsp_i2c_init(uint8_t blsp_id, uint8_t qup_id,
uint32_t clk_freq, uint32_t src_clk_freq)
{
struct qup_i2c_dev *dev;
if (dev_addr != NULL) {
return dev_addr;
}
dev = malloc(sizeof(struct qup_i2c_dev));
if (!dev) {
return NULL;
}
dev = memset(dev, 0, sizeof(struct qup_i2c_dev));
/* Platform uses BLSP */
dev->qup_irq = BLSP_QUP_IRQ(blsp_id, qup_id);
dev->qup_base = BLSP_QUP_BASE(blsp_id, qup_id);
/* This must be done for qup_i2c_interrupt to work. */
dev_addr = dev;
/* Ini
tialize the GPIO for BLSP i2c */
gpio_config_blsp_i2c(blsp_id, qup_id);
clock_config_blsp_i2c(blsp_id, qup_id);
qup_i2c_sec_init(dev, clk_freq, src_clk_freq);
return dev;
}
这里是i2c初始化的地方,下面主要看一下BLSP_QUP_BASE,gpio_config_blsp_i2c,clock_config_blsp_i2c这几个地方,因为在添加其他i2c的时候,主要修改和添加的就是这三个地方里面的内容,其他函数或定义基本上可以直接调用了。
路径:/bootloader/lk/platform/msm8916/include/platform/iomap.h
/* I2C */
#define BLSP_QUP_BASE(blsp_id, qup_id) (PERIPH_SS_BASE + 0xB5000 + 0x1000 * qup_id)
#define GCC_BLSP1_QUP2_APPS_CBCR (CLK_CTL_BASE + 0x3010)
#define GCC_BLSP1_QUP2_CFG_RCGR (CLK_CTL_BASE + 0x3018)
#define GCC_BLSP1_QUP2_CMD_RCGR (CLK_CTL_BASE + 0x3014)
这是i2c需要的地址,不同的i2c,地址不一样。
路径:/bootloader/lk/platform/msm8916/gpio.c
void gpio_config_blsp_i2c(uint8_t blsp_id, uint8_t qup_id)
{
if(blsp_id == BLSP_ID_1) {
switch (qup_id) {
case QUP_ID_1:
/* configure I2C SDA gpio */
gpio_tlmm_config(6, 3, GPIO_OUTPUT, GPIO_NO_PULL,
GPIO_8MA, GPIO_DISABLE);
/* configure I2C SCL gpio */
gpio_tlmm_config(7, 3, GPIO_OUTPUT, GPIO_NO_PULL,
GPIO_8MA, GPIO_DISABLE);
break;
default:
dprintf(CRITICAL, "Incorrect QUP id %dn",qup_id);
ASSERT(0);
};
} else {
dprintf(CRITICAL, "Incorrect BLSP id %dn",blsp_id);
ASSERT(0);
}
}
这个函数主要是对i2c的gpio进行配置,在msm8916里面有2个QUP,每个QUP又包含6个BLSP,每个BLSP可以对应一个i2c。
路径:/bootloader/lk/platform/msm_shared/include/blsp_qup.h
enum {
QUP_ID_0 = 0,
QUP_ID_1,
QUP_ID_2,
QUP_ID_3,
QUP_ID_4,
QUP_ID_5,
} qup_instance;
enum {
BLSP_ID_1 = 1,
BLSP_ID_2,
} blsp_instance;
最后看一下clock_config_blsp_i2c这个函数
路径:/bootloader/lk/platform/msm8916/acpuclock.c
void clock_config_blsp_i2c(uint8_t blsp_id, uint8_t qup_id)
{
uint8_t ret = 0;
char clk_name[64];
struct clk *qup_clk;
if((blsp_id != BLSP_ID_1) || (qup_id != QUP_ID_1)) {
dprintf(CRITICAL, "Incorrect BLSP-%d or QUP-%d configurationn", blsp_id, qup_id);
ASSERT(0);
}
snprintf(clk_name, sizeof(clk_name), "blsp1_qup2_ahb_iface_clk");
ret = clk_get_set_enable(clk_name, 0 , 1);
if (ret) {
dprintf(CRITICAL, "Failed to enable %s clockn", clk_name);
return;
}
snprintf(clk_name, sizeof(clk_name), "gcc_blsp1_qup2_i2c_apps_clk");
qup_clk = clk_get(clk_name);
if (!qup_clk) {
dprintf(CRITICAL, "Failed to get %sn", clk_name);
return;
}
ret = clk_enable(qup_clk);
if (ret) {
dprintf(CRITICAL, "Failed to enable %sn", clk_name);
return;
}
}
我们可以看到这里面有用到blsp1_qup2_ahb_iface_clk和gcc_blsp1_qup2_i2c_apps_clk,接下来搜一下,可以在下面路径找到。
路径:/bootloader/lk/platform/msm8916/msm8916-clock.c
static struct clk_lookup msm_clocks_8916[] =
{
.......
CLK_LOOKUP("blsp1_qup2_ahb_iface_clk", gcc_blsp1_ahb_clk.c),
CLK_LOOKUP("gcc_blsp1_qup2_i2c_apps_clk_src", gcc_blsp1_qup2_i2c_apps_clk_src.c),
CLK_LOOKUP("gcc_blsp1_qup2_i2c_apps_clk", gcc_blsp1_qup2_i2c_apps_clk.c),
}
继续跟踪gcc_blsp1_ahb_clk.c,gcc_blsp1_qup2_i2c_apps_clk_src.c,gcc_blsp1_qup2_i2c_apps_clk.c
路径:/bootloader/lk/platform/msm8916/msm8916-clock.c
static struct vote_clk gcc_blsp1_ahb_clk = {
.cbcr_reg = (uint32_t *) BLSP1_AHB_CBCR,
.vote_reg = (uint32_t *) APCS_CLOCK_BRANCH_ENA_VOTE,
.en_mask = BIT(10),
.c = {
.dbg_name = "gcc_blsp1_ahb_clk",
.ops = &clk_ops_vote,
},
};
static struct clk_ops clk_ops_vote =
{
.enable = clock_lib2_vote_clk_enable,
.disable = clock_lib2_vote_clk_disable,
};
这个函数就到这了,更详细的地方就不说了。
路径:/bootloader/lk/platform/msm8916/msm8916-clock.c
static struct rcg_clk gcc_blsp1_qup2_i2c_apps_clk_src =
{
.cmd_reg = (uint32_t *) GCC_BLSP1_QUP2_CMD_RCGR,
.cfg_reg = (uint32_t *) GCC_BLSP1_QUP2_CFG_RCGR,
.set_rate = clock_lib2_rcg_set_rate_hid,
.freq_tbl = ftbl_gcc_blsp1_qup2_i2c_apps_clk_src,
.current_freq = &rcg_dummy_freq,
.c = {
.dbg_name = "gcc_blsp1_qup2_i2c_apps_clk_src",
.ops = &clk_ops_rcg,
},
};
static struct clk_ops clk_ops_rcg =
{
.enable = clock_lib2_rcg_enable,
.set_rate = clock_lib2_rcg_set_rate,
};
这个函数就到这了,更详细的地方就不说了。
路径:/bootloader/lk/platform/msm8916/msm8916-clock.c
static struct branch_clk gcc_blsp1_qup2_i2c_apps_clk = {
.cbcr_reg = GCC_BLSP1_QUP2_APPS_CBCR,
.parent = &gcc_blsp1_qup2_i2c_apps_clk_src.c,
.c = {
.dbg_name = "gcc_blsp1_qup2_i2c_apps_clk",
.ops = &clk_ops_branch,
},
};
static struct clk_ops clk_ops_branch =
{
.enable = clock_lib2_branch_clk_enable,
.disable = clock_lib2_branch_clk_disable,
.set_rate = clock_lib2_branch_set_rate,
};
到此,lk中的i2c配置就说完了,只要这些都按照寄存器手册配置好,i2c就可以工作了。