基于Dragonboard 410c的总线控制之I2C(二)

    在上篇博客中已经介绍了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;

    /* Initialize 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 %d\n",qup_id);
                ASSERT(0);
        };
    } else {
        dprintf(CRITICAL, "Incorrect BLSP id %d\n",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 configuration\n", 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 clock\n", 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 %s\n", clk_name);
        return;
    }

    ret = clk_enable(qup_clk);

    if (ret) {
        dprintf(CRITICAL, "Failed to enable %s\n", 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就可以工作了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值