Qualcomm技术论坛
直播中

刘琬婷

7年用户 141经验值
私信 关注
[经验]

基于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 %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就可以工作了。

更多回帖

发帖
×
20
完善资料,
赚取积分