qcom Display and I2C In Lk(一)

qcom Display and I2C In Lk(一)

本文主要讲述如何在在qcom平台的LK中移植Display 以及I2c驱动:

  • Display
  • I2C

I2C

1.確保 lk/platform/msm_shared/i2c_qup.c 已经被编译了,如果没有需要加入到编译选项里(同目录的rule.mk)

2.i2c_qup.c为我们提供了i2c的初始化接口:qup_blsp_i2c_init,以及i2c的read/write接口:qup_i2c_xfer

3.正常情况下qup_i2c_xfer接口不需要更改,但在qup_blsp_i2c_init里需要对我们的特定i2c进行移植

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

3.1 查看datasheet赋值正确的qup_irq和qup_base.
3.2 配置i2c所用的GPIO,配置成i2c func.platform/msmxxxx/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_3:
                                /* configure I2C SDA gpio */
                                gpio_tlmm_config(14, 3, GPIO_OUTPUT, GPIO_NO_PULL,
                                                GPIO_8MA, GPIO_DISABLE);
                                /* configure I2C SCL gpio */
                                gpio_tlmm_config(15, 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);
        }
    }

3.3 配置时钟,这里根据时钟名去搜索,并使能.platform/msmxxxx/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) && (qup_id != QUP_ID_3))) {
                dprintf(CRITICAL, "Incorrect BLSP-%d or QUP-%d configuration\n", blsp_id, qup_id);
                ASSERT(0);
        }

        if (qup_id == QUP_ID_1) {
                snprintf(clk_name, sizeof(clk_name), "blsp1_qup2_ahb_iface_clk");
        }
        else if (qup_id == QUP_ID_3) {
                snprintf(clk_name, sizeof(clk_name), "blsp1_qup4_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;
        }

        if (qup_id == QUP_ID_1) {
                snprintf(clk_name, sizeof(clk_name), "gcc_blsp1_qup2_i2c_apps_clk");
        }
        else if (qup_id == QUP_ID_3) {
                snprintf(clk_name, sizeof(clk_name), "gcc_blsp1_qup4_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;
        }
    }

3.3.1在platform/msmxxxx/msmxxxx-clock.c 中配置刚刚使用到的时钟,在msm_clocks_8952添加入口以便被查询到

    static struct clk_lookup msm_clocks_8952[] =
    {
        CLK_LOOKUP("sdc1_iface_clk", gcc_sdcc1_ahb_clk.c),
        CLK_LOOKUP("sdc1_core_clk",  gcc_sdcc1_apps_clk.c),

        CLK_LOOKUP("sdc2_iface_clk", gcc_sdcc2_ahb_clk.c),
        CLK_LOOKUP("sdc2_core_clk",  gcc_sdcc2_apps_clk.c),

        CLK_LOOKUP("uart2_iface_clk", gcc_blsp1_ahb_clk.c),
        CLK_LOOKUP("uart2_core_clk",  gcc_blsp1_uart2_apps_clk.c),

        CLK_LOOKUP("usb_iface_clk",  gcc_usb_hs_ahb_clk.c),
        CLK_LOOKUP("usb_core_clk",   gcc_usb_hs_system_clk.c),

        CLK_LOOKUP("mdp_ahb_clk",          mdp_ahb_clk.c),
        CLK_LOOKUP("mdss_esc0_clk",        mdss_esc0_clk.c),
        CLK_LOOKUP("mdss_esc1_clk",        mdss_esc1_clk.c),
        CLK_LOOKUP("mdss_axi_clk",         mdss_axi_clk.c),
        CLK_LOOKUP("mdss_vsync_clk",       mdss_vsync_clk.c),
        CLK_LOOKUP("mdss_mdp_clk_src",     mdss_mdp_clk_src.c),
        CLK_LOOKUP("mdss_mdp_clk",         mdss_mdp_clk.c),

        CLK_LOOKUP("ce1_ahb_clk",  gcc_ce1_ahb_clk.c),
        CLK_LOOKUP("ce1_axi_clk",  gcc_ce1_axi_clk.c),
        CLK_LOOKUP("ce1_core_clk", gcc_ce1_clk.c),
        CLK_LOOKUP("ce1_src_clk",  ce1_clk_src.c),

        //add for i2c
        CLK_LOOKUP("blsp1_qup4_ahb_iface_clk", gcc_blsp1_ahb_clk.c),
        CLK_LOOKUP("gcc_blsp1_qup4_i2c_apps_clk_src", gcc_blsp1_qup4_i2c_apps_clk_src.c),
        CLK_LOOKUP("gcc_blsp1_qup4_i2c_apps_clk", gcc_blsp1_qup4_i2c_apps_clk.c),
    };

3.3.2 配置刚添加的结构体,gcc_blsp1_ahb_clk、gcc_blsp1_qup4_i2c_apps_clk_src、gcc_blsp1_qup4_i2c_apps_clk. 如果没有定义需要添加

static struct clk_freq_tbl ftbl_gcc_blsp1_2_qup1_4_i2c_apps_clk[] = {
        F(      96000,    cxo,  10,   1,  2),
        F(    4800000,    cxo,   4,   0,  0),
        F(    9600000,    cxo,   2,   0,  0),
        F(   16000000,  gpll0,  10,   1,  5),
        F(   19200000,  gpll0,   1,   0,  0),
        F(   25000000,  gpll0,  16,   1,  2),
        F(   50000000,  gpll0,  16,   0,  0),
        F_END
    };


    static struct rcg_clk gcc_blsp1_qup4_i2c_apps_clk_src =
    {
        .cmd_reg      = (uint32_t *) GCC_BLSP1_QUP4_CMD_RCGR,
        //.cfg_reg      = (uint32_t *) GCC_BLSP1_QUP4_CFG_RCGR,
        .set_rate     = clock_lib2_rcg_set_rate_hid,
        .freq_tbl     = ftbl_gcc_blsp1_2_qup1_4_i2c_apps_clk,
        .current_freq = &rcg_dummy_freq,

        .c = {
                .dbg_name = "gcc_blsp1_qup4_i2c_apps_clk_src",
                .ops      = &clk_ops_rcg,
        },
    };

    static struct branch_clk gcc_blsp1_qup4_i2c_apps_clk = {
        .cbcr_reg = (uint32_t *) GCC_BLSP1_QUP4_APPS_CBCR,
        .parent   = &gcc_blsp1_qup4_i2c_apps_clk_src.c,

        .c = {
                .dbg_name = "gcc_blsp1_qup4_i2c_apps_clk",
                .ops      = &clk_ops_branch,
        },
    };

4.封装i2c的读写方法

int dlp_i2c_read(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t len)
{
    if (!buf)
            return ERR_INVALID_ARGS;

    if(!dlp_i2c_dev){
            return ERR_NOT_VALID;
    }

    struct i2c_msg rd_buf[] = { 
            {addr, I2C_M_WR, 1, &reg},
            {addr, I2C_M_RD, len, buf}
    };

    int err = qup_i2c_xfer(dlp_i2c_dev, rd_buf, 2);
    if (err < 0) {
            dprintf(CRITICAL, "Read reg failed\n");
            return err;
    }else{
            dprintf(CRITICAL, "dlp_i2c_read_ext success \n");
    }

    return NO_ERROR;
}

int dlp_i2c_write(uint8_t addr,  uint8_t* val,int len)
{
    int err;
    int num;
    struct i2c_msg msg[1];
    unsigned char data[9];
    int i;

    if (!val)
            return ERR_INVALID_ARGS;

    if(!dlp_i2c_dev){
            dprintf(CRITICAL, "--dlp_i2c_write\n");
            return ERR_NOT_VALID;
    }

    msg->addr = addr;
    msg->flags = 0;
    msg->len = len ;
    msg->buf = data;
    for(i=0;i<len;i++)
            data[i]=val[i];

    num=0;
    while(num<5){
            num++;
            err = qup_i2c_xfer(dlp_i2c_dev, msg, 1);
            //err = i2c_transfer(client->adapter, msg, 1);
            if(err>=0)
                    break;
            mdelay(50);
    }
    if (err >= 0){
            dprintf(CRITICAL, "dlp_i2c_write_reg: success \n");
            return 0;
    }else{
            dprintf(CRITICAL, "dlp_i2c_write_reg reg failed\n");
    }

    return err;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值