项目场景:
代码语言:javascript复制 因为项目需要,需要在高通MSM8953平台的LK阶段使用I2C8设备。但是MSM8953平台LK阶段并没有配置好I2C8接口,因此调试I2C8成为当务之急。本文只介绍在LK阶段配置使用I2C5的方法。
调试需要:
1、文档:BAM Low-Speed Peripherals (BLSP) User Guide 查看文档,有I2C介绍如下:
I2c3对应的物理地址为0x78B7000 , 中断IRQ:97 ,时钟信号 clk :clk_gcc_blsp1_qup3_i2c_apps_clk , I2c3对应的物理地址为0x7AF8000 , 中断IRQ:302,时钟信号 clk :clk_gcc_blsp2_qup4_i2c_apps_clk 查看产品配置表有: I2C3:gpio10&gpio11;i2c8:gpio98&gpio99;
代码语言:javascript复制I2C Description :
1、 arg: BLSP ID can be BLSP_ID_1 or BLSP_ID_2
2、 arg: QUP ID can be QUP_ID_0:QUP_ID_5
3、 arg: I2C CLK. should be 100KHZ, or 400KHz
4、 arg: Source clock, should be set @ 19.2MHz
解决方案:
1、Initialize the I2C bus.
代码语言:javascript复制//mipi_dsi_i2c.c
#define I2C_CLK_FREQ 100000
#define I2C_SRC_CLK_FREQ 19200000
int mipi_dsi_i2c_device_init(uint8_t blsp_id, uint8_t qup_id)
{
if(BLSP_ID_2 == blsp_id) {
i2c8_dev = qup_blsp_i2c_init(blsp_id, qup_id,
I2C_CLK_FREQ, I2C_SRC_CLK_FREQ);
if(!i2c8_dev) {
dprintf(CRITICAL, "mipi_dsi_i2c_device_init() failedn");
return ERR_NOT_VALID;
}
}
else
{
i2c_dev = qup_blsp_i2c_init(blsp_id, qup_id,
I2C_CLK_FREQ, I2C_SRC_CLK_FREQ);
if(!i2c_dev) {
dprintf(CRITICAL, "mipi_dsi_i2c_device_init() failedn");
return ERR_NOT_VALID;
}
}
return NO_ERROR;
}
代码语言:javascript复制//i2c_qup.c
#include <blsp_qup.h>
#include <platform.h>
static struct qup_i2c_dev *dev_addr = NULL;
static struct qup_i2c_dev *dev8_addr = NULL;
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(BLSP_ID_2 == blsp_id)
{
if (dev8_addr != NULL) {
return dev8_addr;
}
}
else
{
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. */
if(BLSP_ID_2 == blsp_id)
dev8_addr = dev;
else
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;
}
添加I2C8操作函数
代码语言:javascript复制// i2c_qup.c
int mipi_dsi_i2c8_read_bytes(uint8_t addr, uint8_t *reg, uint8_t *buf, uint8_t len)
{
if (!buf)
return ERR_INVALID_ARGS;
if(!i2c8_dev)
return ERR_NOT_VALID;
struct i2c_msg rd_buf[] = {
{
addr, I2C_M_WR, 2, reg},
{
addr, I2C_M_RD, len, buf}
};
int err = qup_i2c_xfer(i2c8_dev, rd_buf, 2);
if (err < 0) {
dprintf(CRITICAL, "Read reg %x failedn", (int)reg[0]);
return err;
}
return NO_ERROR;
}
int mipi_dsi_i2c8_write_bytes(uint8_t addr, uint8_t *reg, uint32_t len)
{
if (!i2c8_dev)
return ERR_NOT_VALID;
struct i2c_msg msg_buf[] = {
{
addr, I2C_M_WR, len, reg},
};
int err = qup_i2c_xfer(i2c8_dev, msg_buf, 1);
if (err < 0) {
dprintf(CRITICAL, "Write reg %x failedn", (int)reg[0]);
return err;
}
return NO_ERROR;
}
int mipi_dsi_i2c8_read(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t len)
{
if (!buf)
return ERR_INVALID_ARGS;
if(!i2c8_dev)
return ERR_NOT_VALID;
struct i2c_msg rd_buf[] = {
{
addr, I2C_M_WR, 1, ®},
{
addr, I2C_M_RD, len, buf}
};
int err = qup_i2c_xfer(i2c8_dev, rd_buf, 2);
if (err < 0) {
dprintf(CRITICAL, "Read reg %x failedn", reg);
return err;
}
return NO_ERROR;
}
int mipi_dsi_i2c8_read_byte(uint8_t addr, uint8_t reg, uint8_t *buf)
{
if (!buf)
return ERR_INVALID_ARGS;
return mipi_dsi_i2c8_read(addr, reg, buf, 1);
}
int mipi_dsi_i2c8_write_byte(uint8_t addr, uint8_t reg, uint8_t val)
{
if (!i2c8_dev)
return ERR_NOT_VALID;
unsigned char buf[2] = {
reg, val};
struct i2c_msg msg_buf[] = {
{
addr, I2C_M_WR, 2, buf},
};
int err = qup_i2c_xfer(i2c8_dev, msg_buf, 1);
if (err < 0) {
dprintf(CRITICAL, "Write reg %x failedn", reg);
return err;
}
return NO_ERROR;
}
声明函数
代码语言:javascript复制// mipi_dsi_i2c.h
int mipi_dsi_i2c8_read_bytes(uint8_t addr, uint8_t *reg, uint8_t *buf, uint8_t len);
int mipi_dsi_i2c8_write_bytes(uint8_t addr, uint8_t *reg, uint32_t len);
int mipi_dsi_i2c8_read_byte(uint8_t addr, uint8_t reg, uint8_t *buf);
int mipi_dsi_i2c8_write_byte(uint8_t addr, uint8_t reg, uint8_t val);
int mipi_dsi_i2c8_read(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t len);
查看文档,可以得知IRQ计算公式为:
代码语言:javascript复制#define BLSP_QUP_IRQ(blsp_id, qup_id) (GIC_SPI_START 95 (blsp_id-1)*204 qup_id)
物理地址计算公式为:
代码语言:javascript复制#define BLSP_QUP_BASE(blsp_id, qup_id) (PERIPH_SS_BASE ((blsp_id) - 1) * 0x240000 0xB5000 0x1000 * (qup_id))
2、 Configure the GPIO.
代码语言:javascript复制// bootloader/lk/platform/msm8953/gpio.c
#define GPIO_BLSP1_ACTIVE_1 10
#define GPIO_BLSP1_ACTIVE_2 11
#define GPIO_BLSP2_ACTIVE_1 98
#define GPIO_BLSP2_ACTIVE_2 99
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_2:
/* configure I2C SDA gpio */
gpio_tlmm_config(GPIO_BLSP1_ACTIVE_1, 2, GPIO_OUTPUT,
GPIO_NO_PULL, GPIO_6MA, GPIO_ENABLE);
/* configure I2C SCL gpio */
gpio_tlmm_config(GPIO_BLSP1_ACTIVE_2, 2, GPIO_OUTPUT,
GPIO_NO_PULL, GPIO_6MA, GPIO_ENABLE);
break;
default:
dprintf(CRITICAL, "Incorrect QUP id %dn", qup_id);
ASSERT(0);
};
}
else if(blsp_id == BLSP_ID_2) {
switch (qup_id) {
case QUP_ID_3:
/* configure I2C SDA gpio */
gpio_tlmm_config(GPIO_BLSP2_ACTIVE_1, 1, GPIO_OUTPUT,
GPIO_PULL_UP, GPIO_6MA, GPIO_ENABLE);
/* configure I2C SCL gpio */
gpio_tlmm_config(GPIO_BLSP2_ACTIVE_2, 1, GPIO_OUTPUT,
GPIO_PULL_UP, GPIO_6MA, GPIO_ENABLE);
break;
default:
dprintf(CRITICAL, "Incorrect QUP id %dn", qup_id);
ASSERT(0);
};
}
else {
dprintf(CRITICAL, "Incorrect BLSP id %dn",blsp_id);
ASSERT(0);
}
}
3、Register a clock.
代码语言:javascript复制// bootable/bootloader/lk/platform/msm8953/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 && blsp_id != BLSP_ID_2)) {
dprintf(CRITICAL, "Incorrect BLSP-%d or QUP-%d configurationn",
blsp_id, qup_id);
ASSERT(0);
}
if(blsp_id == BLSP_ID_1){
if (qup_id == QUP_ID_2) {
snprintf(clk_name, sizeof(clk_name), "blsp1_qup3_ahb_iface_clk");
}
else if (qup_id == QUP_ID_3) {
snprintf(clk_name, sizeof(clk_name), "blsp1_qup4_ahb_iface_clk");
}
}
if(blsp_id == BLSP_ID_2){
if (qup_id == QUP_ID_3) {
snprintf(clk_name, sizeof(clk_name), "blsp2_qup4_ahb_iface_clk");
}
}
ret = clk_get_set_enable(clk_name, 0 , 1);
if (ret) {
dprintf(CRITICAL, "Failed to enable %s clockn", clk_name);
return;
}
if(blsp_id == BLSP_ID_1){
if (qup_id == QUP_ID_2) {
snprintf(clk_name, sizeof(clk_name), "gcc_blsp1_qup3_i2c_apps_clk");
}
else if (qup_id == QUP_ID_3) {
snprintf(clk_name, sizeof(clk_name), "gcc_blsp1_qup4_i2c_apps_clk");
}
}
if(blsp_id == BLSP_ID_2){
if (qup_id == QUP_ID_3) {
snprintf(clk_name, sizeof(clk_name), "gcc_blsp2_qup4_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;
}
}
代码语言:javascript复制// bootable/bootloader/lk/platform/msm8953/msm8953-clock.c.
static struct vote_clk gcc_blsp2_ahb_clk = {
.cbcr_reg = (uint32_t *) BLSP2_AHB_CBCR,
.vote_reg = (uint32_t *) APCS_CLOCK_BRANCH_ENA_VOTE,
.en_mask = BIT(20),
.c = {
.dbg_name = "gcc_blsp2_ahb_clk",
.ops = &clk_ops_vote,
},
};
static struct clk_freq_tbl ftbl_gcc_blsp1_qup2_i2c_apps_clk_src[] = {
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_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 branch_clk gcc_blsp1_qup2_i2c_apps_clk = {
.cbcr_reg = (uint32_t *) 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_freq_tbl ftbl_gcc_blsp1_qup3_i2c_apps_clk_src[] = {
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
};
#if 0
static struct clk_freq_tbl ftbl_gcc_blsp2_qup4_i2c_apps_clk_src[] = {
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
};
#endif
static struct rcg_clk gcc_blsp1_qup3_i2c_apps_clk_src = {
.cmd_reg = (uint32_t *) GCC_BLSP1_QUP3_CMD_RCGR,
.cfg_reg = (uint32_t *) GCC_BLSP1_QUP3_CFG_RCGR,
.set_rate = clock_lib2_rcg_set_rate_hid,
.freq_tbl = ftbl_gcc_blsp1_qup3_i2c_apps_clk_src,
.current_freq = &rcg_dummy_freq,
.c = {
.dbg_name = "gcc_blsp1_qup3_i2c_apps_clk_src",
.ops = &clk_ops_rcg,
},
};
static struct rcg_clk gcc_blsp2_qup4_i2c_apps_clk_src = {
.cmd_reg = (uint32_t *) GCC_BLSP2_QUP4_CMD_RCGR,
.cfg_reg = (uint32_t *) GCC_BLSP2_QUP4_CFG_RCGR,
.set_rate = clock_lib2_rcg_set_rate_hid,
// .freq_tbl = ftbl_gcc_blsp2_qup4_i2c_apps_clk_src,
.freq_tbl = ftbl_gcc_blsp1_qup3_i2c_apps_clk_src,
.current_freq = &rcg_dummy_freq,
.c = {
.dbg_name = "gcc_blsp2_qup4_i2c_apps_clk_src",
.ops = &clk_ops_rcg,
},
};
static struct branch_clk gcc_blsp1_qup3_i2c_apps_clk = {
.cbcr_reg = (uint32_t *) GCC_BLSP1_QUP3_APPS_CBCR,
.parent = &gcc_blsp1_qup3_i2c_apps_clk_src.c,
.c = {
.dbg_name = "gcc_blsp1_qup3_i2c_apps_clk",
.ops = &clk_ops_branch,
},
};
static struct branch_clk gcc_blsp2_qup4_i2c_apps_clk = {
.cbcr_reg = (uint32_t *) GCC_BLSP2_QUP4_APPS_CBCR,
.parent = &gcc_blsp2_qup4_i2c_apps_clk_src.c,
.c = {
.dbg_name = "gcc_blsp2_qup4_i2c_apps_clk",
.ops = &clk_ops_branch,
},
};
static struct clk_freq_tbl ftbl_mdss_esc1_1_clk[] = {
F_MM(19200000, cxo, 1, 0, 0),
F_END
};
static struct rcg_clk dsi_esc1_clk_src = {
.cmd_reg = (uint32_t *) DSI_ESC1_CMD_RCGR,
.cfg_reg = (uint32_t *) DSI_ESC1_CFG_RCGR,
.set_rate = clock_lib2_rcg_set_rate_hid,
.freq_tbl = ftbl_mdss_esc1_1_clk,
.c = {
.dbg_name = "dsi_esc1_clk_src",
.ops = &clk_ops_rcg,
},
};
static struct branch_clk mdss_esc1_clk = {
.cbcr_reg = (uint32_t *) DSI_ESC1_CBCR,
.parent = &dsi_esc1_clk_src.c,
.has_sibling = 0,
.c = {
.dbg_name = "mdss_esc1_clk",
.ops = &clk_ops_branch,
},
};
static struct clk_lookup msm_clocks_8953[] =
{
...
/*add start by Yubel for blsp 20200730 */
/* BLSP CLOCKS */
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),
CLK_LOOKUP("blsp1_qup3_ahb_iface_clk", gcc_blsp1_ahb_clk.c),
CLK_LOOKUP("gcc_blsp1_qup3_i2c_apps_clk_src",
gcc_blsp1_qup3_i2c_apps_clk_src.c),
CLK_LOOKUP("gcc_blsp1_qup3_i2c_apps_clk",
gcc_blsp1_qup3_i2c_apps_clk.c),
CLK_LOOKUP("blsp2_qup4_ahb_iface_clk", gcc_blsp2_ahb_clk.c),
CLK_LOOKUP("gcc_blsp2_qup4_i2c_apps_clk_src",
gcc_blsp2_qup4_i2c_apps_clk_src.c),
CLK_LOOKUP("gcc_blsp2_qup4_i2c_apps_clk",
gcc_blsp2_qup4_i2c_apps_clk.c),
/*add end by Yubel 20200730 */
...
};
通过kernel中配置I2C的代码可知
代码语言:javascript复制#define GCC_BLSP1_QUP3_APPS_CBCR (CLK_CTL_BASE 0x04020)
#define GCC_BLSP1_QUP3_CFG_RCGR (CLK_CTL_BASE 0x04004)
#define GCC_BLSP1_QUP3_CMD_RCGR (CLK_CTL_BASE 0x04000)
#define GCC_BLSP1_QUP2_APPS_CBCR (CLK_CTL_BASE 0x03010)
#define GCC_BLSP1_QUP2_CFG_RCGR (CLK_CTL_BASE 0x03004)
#define GCC_BLSP1_QUP2_CMD_RCGR (CLK_CTL_BASE 0x03000)
#define BLSP2_AHB_CBCR (CLK_CTL_BASE 0x0B008)
#define GCC_BLSP2_QUP4_APPS_CBCR (CLK_CTL_BASE 0x18020)
#define GCC_BLSP2_QUP4_CFG_RCGR (CLK_CTL_BASE 0x18004)
#define GCC_BLSP2_QUP4_CMD_RCGR (CLK_CTL_BASE 0x18000)
测试用例
代码语言:javascript复制// bootable/bootloader/lk/app/tests/my_i2c_test.c.
#include <ctype.h>
#include <debug.h>
#include <stdlib.h>
#include <printf.h>
#include <list.h>
#include <string.h>
#include <arch/ops.h>
#include <platform.h>
#include <platform/debug.h>
#include <kernel/thread.h>
#include <kernel/timer.h>
#ifdef WITH_LIB_CONSOLE
#include <lib/console.h>
static int cmd_i2c_test(int argc, const cmd_args *argv);
STATIC_COMMAND_START
{
"i2c_test", "i2c test cmd", &cmd_i2c_test },
STATIC_COMMAND_END(my_i2c_test);
static int cmd_i2c_test(int argc, const cmd_args *argv)
{
printf("Entering i2c_testn");
return 0;
}
#endif
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/180313.html原文链接:https://javaforall.cn