qcom平台LK 阶段配置IIC

版本号:V 1.0

作者:Leo

目录

目录... 1

前言... 4

1.      确定硬件... 4

2.      LK I2C 函数接口... 5

2.1 qup irq 中断号赋值... 6

2.2 qup base addr 赋值... 6

2.3 blsp6 gpio 初始化... 7

2.4 blsp6 时钟源的配置... 9

3.      总结... 11

前言

本文着重介绍,如何在qcom 平台的LK 阶段配置和使用I2C。

硬件平台:msm8909

软件平台:Android5.0、Android8.0

I2C设备:ADV7533

参考博客和文档:

80-np408-2x_c_msm8909_msm8209_msm8208_hardware_register_description_document_for_oems.pdf

80-nu767-1_h_linux_bam_low-speed_peripherals_configuration_and_debug_guide.pdf

https://blog.csdn.net/eliot_shao/article/details/53351759

1. 确定硬件

查看原理图确定gpio

确定芯片I2C内部的qup地址、中断号、通道等参数

根据文档:80-nu767-1_h_linux_bam_low-speed_peripherals_configuration_and_debug_guide.pdf

从以上信息可以确定:

  1. 我们要使用的是 gpio10、gpio11对应的IIC
  2. 芯片内部参数是
    1. QUP ID: BLSP6
    2. QUP BASE Addr: 78BA000
    3. IRQ#: 100
    4. src clk:qup6_i2c_apps_clk

2.  LK I2C 函数接口

根据qcom文档:

80-nu767-1_h_linux_bam_low-speed_peripherals_configuration_and_debug_guide.pdf

可知:qcom LK 阶段的I2C 函数接口为:qup_blsp_i2c_init

函数定义:

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)

参数含义:

uint8_t blsp_id: (msm8909 上用 BLSP_ID_1)

enum {BLSP_ID_1 = 1,BLSP_ID_2,
} blsp_instance;

uint8_t qup_id:

enum {QUP_ID_0 = 0,QUP_ID_1,QUP_ID_2,QUP_ID_3,QUP_ID_4,QUP_ID_5,
} qup_instance;

(具体多少,以qup的base addr 为准。如使用IIC-6对应地址78ba000,那么传参QUP_ID_5)

uint32_t clk_freq:

IIC总线速率,默认 100K

uint32_t src_clk_freq:

时钟源频率,默认19.2MHz

老规矩,先分析下这个函数的实现流程。

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

从以上流程看,有5个需要关注的地方

1. dev->qup_irq = BLSP_QUP_IRQ(blsp_id, qup_id);
2. dev->qup_base = BLSP_QUP_BASE(blsp_id, qup_id);
3. gpio_config_blsp_i2c(blsp_id, qup_id);
4. clock_config_blsp_i2c(blsp_id, qup_id);
5. qup_i2c_sec_init(dev, clk_freq, src_clk_freq);  // 略过,I2C的初始化过程

一个一个分析:

2.1 qup irq 中断号赋值

dev->qup_irq = BLSP_QUP_IRQ(blsp_id, qup_id);

中断号,使用 BLSP_QUP_IRQ 这个宏来赋值,那么找到它的定义:

bootable\bootloader\lk\platform\msm8909\include\platform\irqs.h#define GIC_SPI_START                          32#define BLSP_QUP_IRQ(blsp_id, qup_id)          (GIC_SPI_START + 95 + qup_id)

从章节1的qup 信息可知,qup6的中断号为100,那么传参qup_id 为5,中断号为

GIC_SPI_START + 95 + 5, GIC_SPI_START 是一个偏移量,不用管它。

这里大概可以推测,qup_id 应该传参为5。

2.2 qup base addr 赋值

dev->qup_base = BLSP_QUP_BASE(blsp_id, qup_id);

qup 基地址的赋值,使用 BLSP_QUP_BASE来赋值,找到它的定义

bootable\bootloader\lk\platform\msm8909\include\platform\iomap.h#define PERIPH_SS_BASE              0x07800000bootable\bootloader\lk\platform\msm8909\include\platform\iomap.h#define BLSP_QUP_BASE(blsp_id, qup_id) (PERIPH_SS_BASE + 0xB5000 + 0x1000 * qup_id)

从章节1的qup信息图得知,qup6的 base addr 为78ba000,那么这里qup_id 传参应该为5

即:0x70800000 + 0x0B5000 + 0x1000 * 5 = 0x78bA000

到此为止,从qup irq的信息和qup base addr的信息确认,那么I2C-6(gpio10、gpio11)对应的qup 传参应该是 QUP_ID_5。

2.3 blsp6 gpio 初始化

/* Initialize the GPIO for BLSP i2c */gpio_config_blsp_i2c(blsp_id, qup_id);

看gpio_config_blsp_i2c函数定义.

void gpio_config_blsp_i2c(uint8_t blsp_id, uint8_t qup_id)
{
#if DSI2DPI_TC358762uint32_t hw_id = board_hardware_id();uint32_t hw_subtype = board_hardware_subtype();
#endifif(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;case QUP_ID_2:/* configure I2C SDA gpio */gpio_tlmm_config(111, 3, GPIO_OUTPUT, GPIO_NO_PULL,GPIO_8MA, GPIO_DISABLE);/* configure I2C SCL gpio */gpio_tlmm_config(112, 3, GPIO_OUTPUT, GPIO_NO_PULL,GPIO_8MA, GPIO_DISABLE);break;case QUP_ID_3:/* configure I2C SDA gpio */gpio_tlmm_config(29, 3, GPIO_OUTPUT, GPIO_NO_PULL,GPIO_8MA, GPIO_DISABLE);/* configure I2C SCL gpio */gpio_tlmm_config(30, 3, GPIO_OUTPUT, GPIO_NO_PULL,GPIO_8MA, GPIO_DISABLE);break;case QUP_ID_4:
#if DSI2DPI_TC358762if ((HW_PLATFORM_SUBTYPE_LR3001 == hw_subtype)&& (HW_PLATFORM_MTP == hw_id)) {/* configure I2C SDA gpio */gpio_tlmm_config(18, 2, GPIO_OUTPUT, GPIO_NO_PULL,GPIO_2MA, GPIO_DISABLE);/* configure I2C SCL gpio */gpio_tlmm_config(19, 2, GPIO_OUTPUT, GPIO_NO_PULL,GPIO_2MA, GPIO_DISABLE);} else {
#endif/* 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);
#if DSI2DPI_TC358762}
#endifbreak;case QUP_ID_5:/* configure I2C SDA gpio */gpio_tlmm_config(18, 3, GPIO_OUTPUT, GPIO_NO_PULL,GPIO_8MA, GPIO_DISABLE);/* configure I2C SCL gpio */gpio_tlmm_config(19, 3, GPIO_OUTPUT, GPIO_NO_PULL,GPIO_8MA, GPIO_DISABLE);
/* Begin: add by leo for add i2c-6(gpio_10 & gpio_11) */
#if 1/* configure I2C SDA gpio */gpio_tlmm_config(10, 2, GPIO_OUTPUT, GPIO_NO_PULL,GPIO_8MA, GPIO_DISABLE);/* configure I2C SCL gpio */gpio_tlmm_config(11, 2, GPIO_OUTPUT, GPIO_NO_PULL,GPIO_8MA, GPIO_DISABLE);dprintf(CRITICAL, "leo i2c-%d (gpio10 & gpio11)\n", qup_id + 1);
#endif
/* End: add by leo for add i2c-6(gpio_10 & gpio_11) */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);}
}

从以上调用流程可以看出,整个流程就是根据BLSP_ID 和QUP_ID 去初始化不同的gpio。

所以在这里,需要判断在 case QUP_ID_5 中是否已经包含我们需要的gpio管脚(gpio10、gpio11)的初配置。

代码修改:

/* Begin: add by leo for add i2c-6(gpio_10 & gpio_11) */
#if 1/* configure I2C SDA gpio */gpio_tlmm_config(10, 2, GPIO_OUTPUT, GPIO_NO_PULL,GPIO_8MA, GPIO_DISABLE);/* configure I2C SCL gpio */gpio_tlmm_config(11, 2, GPIO_OUTPUT, GPIO_NO_PULL,GPIO_8MA, GPIO_DISABLE);dprintf(CRITICAL, "leo i2c-%d (gpio10 & gpio11)\n", qup_id + 1);
#endif
/* End: add by leo for add i2c-6(gpio_10 & gpio_11) */

显然没有,那么就需要在case QUP_ID_5:新增 gpio10、gpio11的初始化。

注意这里:这里配置为功能2,是复用为i2c功能

依据:

80-np408-2x_c_msm8909_msm8209_msm8208_hardware_register_description_document_for_oems.pdf

page-2624 介绍:

配置为功能 2 是 IIC功能。

2.4 blsp6 时钟源的配置

clock_config_blsp_i2c(blsp_id, qup_id);

看函数定义:

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;qup_id = qup_id + 1;if((blsp_id != BLSP_ID_1)) {dprintf(CRITICAL, "Incorrect BLSP-%d configuration\n", blsp_id);ASSERT(0);}snprintf(clk_name, sizeof(clk_name), "blsp1_qup%u_ahb_iface_clk", qup_id);dprintf(CRITICAL, "leo i2c-%d clk_name=%s \n", qup_id, clk_name);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_qup%u_i2c_apps_clk", qup_id);dprintf(CRITICAL, "leo i2c-%d clk_name=%s \n", qup_id, clk_name);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;}
}

首先,qup_id = qup_id + 1; 这里,对qup进行了自加1,那么下面对应的时钟源参数就变成了blsp6。

且能看出,需要的是 blsp1_qup6_ahb_iface_clk 和 gcc_blsp1_qup6_i2c_apps_clk,这两个时钟源。

 snprintf(clk_name, sizeof(clk_name), "blsp1_qup%u_ahb_iface_clk", qup_id);dprintf(CRITICAL, "leo i2c-%d clk_name=%s \n", qup_id, clk_name);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_qup%u_i2c_apps_clk", qup_id);dprintf(CRITICAL, "leo i2c-%d clk_name=%s \n", qup_id, clk_name);qup_clk = clk_get(clk_name);

可以看clk_get_set_enable 和 clk_get 的定义

clk_get_set_enable:

bootable\bootloader\lk\platform\msm_shared\clock.c

函数定义略

clk_get:

bootable\bootloader\lk\platform\msm_shared\clock.c

struct clk *clk_get (const char * cid)
{unsigned i;struct clk_lookup *cl= msm_clk_list.clist;unsigned num = msm_clk_list.num;if(!cl || !num){dprintf (CRITICAL, "Alert!! clock list not defined!\n");return NULL;}for(i=0; i < num; i++, cl++){if(!strcmp(cl->con_id, cid)){return cl->clk;}}dprintf(CRITICAL, "Alert!! Requested clock \"%s\" is not supported!\n", cid);return NULL;
}

分析:都是从 bootable\bootloader\lk\platform\msm_shared\clock.c 中的static struct clk_list msm_clk_list; 全局clk list 中获取的信息。

找到在哪初始化的:

路径:
bootable\bootloader\lk\platform\msm_shared\clock.cvoid clk_init(struct clk_lookup *clist, unsigned num)
{if(clist && num){msm_clk_list.clist = (struct clk_lookup *)clist;msm_clk_list.num = num;}
}

找到在哪调用的:

路径:bootable\bootloader\lk\platform\msm8909\msm8909-clock.cvoid platform_clock_init(void)
{clk_init(msm_clocks_msm8909, ARRAY_SIZE(msm_clocks_msm8909));
}

其中msm_clocks_msm8909 这个clk 结构体数组,就是我们要修改的目标 。

此处需对应 clock_config_blsp_i2c 函数中的分析。

最终我们需要的有三个时钟源配置,根据实际代码去修改。

bootable\bootloader\lk\platform\msm8909\msm8909-clock.c
msm_clocks_msm8909 数组中#elseCLK_LOOKUP("blsp1_qup6_ahb_iface_clk", gcc_blsp1_ahb_clk.c),CLK_LOOKUP("gcc_blsp1_qup6_i2c_apps_clk_src", gcc_blsp1_qup6_i2c_apps_clk_src.c),CLK_LOOKUP("gcc_blsp1_qup6_i2c_apps_clk", gcc_blsp1_qup6_i2c_apps_clk.c),
#endif

4. 总结

那么总结下,所有的配置修改。

1. 调用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)

2. 检查gpio配置

查看I2C对应的gpio配置是否包含,否则去添加

/* Begin: add by leo for add i2c-6(gpio_10 & gpio_11) */
#if 1/* configure I2C SDA gpio */gpio_tlmm_config(10, 2, GPIO_OUTPUT, GPIO_NO_PULL,GPIO_8MA, GPIO_DISABLE);/* configure I2C SCL gpio */gpio_tlmm_config(11, 2, GPIO_OUTPUT, GPIO_NO_PULL,GPIO_8MA, GPIO_DISABLE);dprintf(CRITICAL, "leo i2c-%d (gpio10 & gpio11)\n", qup_id + 1);
#endif
/* End: add by leo for add i2c-6(gpio_10 & gpio_11) */

3. 检查I2C src clk 配置,没有则添加

bootable\bootloader\lk\platform\msm8909\msm8909-clock.c
msm_clocks_msm8909 数组中#elseCLK_LOOKUP("blsp1_qup6_ahb_iface_clk", gcc_blsp1_ahb_clk.c),CLK_LOOKUP("gcc_blsp1_qup6_i2c_apps_clk_src", gcc_blsp1_qup6_i2c_apps_clk_src.c),CLK_LOOKUP("gcc_blsp1_qup6_i2c_apps_clk", gcc_blsp1_qup6_i2c_apps_clk.c),
#endif

4. I2C 读函数demo。 (寄存器地址和数据都以8bit为例)

static uint8_t adv7533_i2c_read(uint8_t slave_addr, uint8_t reg)
{int ret;int err_return = -1;uint8_t value;dprintf(SPEW, "%s: Leo enter \n", __func__);uint8_t tx_data[] = {reg & 0xff,};uint8_t rx_data[1];struct i2c_msg msgs[] = {{.addr = slave_addr,.flags = I2C_M_WR,.buf = tx_data,.len = ADV_ARRAY_SIZE(tx_data),},{.addr = slave_addr,.flags = I2C_M_RD,.buf = rx_data,.len = ADV_ARRAY_SIZE(rx_data),}};ret = qup_i2c_xfer(i2c6_dev, msgs, ADV_ARRAY_SIZE(msgs));if (ret < 0) {dprintf(CRITICAL, "%s: reg 0x%04x error %d\n", __func__, reg, ret);return ret;}if (ret < ADV_ARRAY_SIZE(msgs)) {dprintf(CRITICAL, "%s: reg 0x%04x msgs %d\n", __func__, reg, ret);return err_return;}value = rx_data[0];dprintf(CRITICAL, "%s: reg 0x%x 0x%x\n", __func__, reg, value);return value;
}

5. I2C 写函数 demo

static int adv7533_i2c_write(uint8_t slave_addr, uint8_t reg, uint8_t value)
{int ret = 0;uint8_t tx_data[2] = {reg, value};/* Send commands via I2C */struct i2c_msg msgs[1] = {{.addr = slave_addr,.flags = I2C_M_WR, // 0.len = 2,.buf = tx_data,},};ret = qup_i2c_xfer(i2c6_dev, msgs, 1);if (ret < 0) {dprintf(CRITICAL, "%s failed ret=%d\n", __func__, ret);return ret;}mdelay(2);return 0;
}

Qcom 平台 LK 阶段配置 I2C相关推荐

  1. 高通MSM8953 LK阶段配置使用I2C8

    项目场景: 因为项目需要,需要在高通MSM8953平台的LK阶段使用I2C8设备.但是MSM8953平台LK阶段并没有配置好I2C8接口,因此调试I2C8成为当务之急.本文只介绍在LK阶段配置使用I2 ...

  2. 高通平台lk阶段logo修改

    高通平台lk阶段logo修改: 1.通过logo图片得到要显示的数组: 运行"ffmpeg -i logo.png -f rawvideo -pix_fmt bgr24 logo.raw&q ...

  3. Qcom LK阶段如何使用ADC介绍

    点击打开链接 摘要 本文叙述了在高通平台LK阶段读取mpp2引脚电平的实现过程,附上实现代码.主要实现过程包括配置引脚功能,读取引脚电压.需要特别注意配置mpp2通道和AIN route的选择. 需要 ...

  4. MTK平台 在lk阶段,读取IMEI号

    MTK平台 在lk阶段,读取IMEI号 MTK的写号工具"SN_WITER tool",在写IMEI和SN的时候,会往"proinfo"分区里面也写一份IMEI ...

  5. Qcom平台 ADV7533 调试指南

    前言 本文着重介绍 ADV7533 芯片在高通 msm8909 平台上调通的经验 硬件平台:msm8909 软件平台:Android5.0 Android8.0 (均已经调通) 芯片IC:ADV753 ...

  6. 定制LK阶段开机LOGO

    文档说明 本文档以SC806-CN-00-04为例(8909平台),描述如何定制LK阶段开机logo图片. LOGO图片要求 图片后缀为 .png,颜色位深8/24/32都可以. 图片分辨率和屏的实际 ...

  7. MSM8953配置I2C及SPI

    此次完成的任务是要使能高通8953平台的i2c和spi,主要做的工作就是在设备树文件中添加节点信息.主要的工作在于对设备树文件的修改,主要修改了msm8953-pinctrl.dtsi和msm8953 ...

  8. TM034XVZP01 mipi屏 高通8909平台lk和kernel驱动 基于ili9881驱动

    效果图如上. 所需的时序文件链接 https://download.csdn.net/download/jxhln/11120468 大家可以下载参考 上述是最终的成果,该文章只着重讲述lk阶段的调试 ...

  9. 零基础学习MTK平台camera引脚配置

    目录 一.MTK平台的GPIO配置 1. MTK平台GPIO驱动程序提供了两个接口: 2.配置dws文件 3.配置dts文件 二.MTK平台camera模块的GPIO配置 一.MTK平台的GPIO配置 ...

最新文章

  1. Clusterware 和 RAC 中的域名解析的配置校验和检查 (文档 ID 1945838.1)
  2. SqlDataReader.GetSchemaTable
  3. PowerDesigner的逆向工程.
  4. Android:Application
  5. Docker(4)-容器互联与端口映射
  6. jqgrid 批量启动所有行为可编辑状态
  7. 这位硬核程序员,想好怎么过春节了吗?
  8. 零基础学Python--------第3章 流程控制语句
  9. matlab实现sift,SIFT算法的Matlab实现
  10. android 换机 软件 评比,安卓一键换机软件哪个好?手机换机软件排行榜TOP3推荐...
  11. typedef的使用详解
  12. Python自动化办公实战:包含Word、Excel、Pdf和Email邮件案例
  13. PX4源码学习一--Pix和APM的区别
  14. 蓝牙耳机哪款音质好?高人气低延迟十五款游戏蓝牙耳机推荐
  15. 简单典型二阶系统_【文献选译】二阶弹性波动方程PML的简单实现
  16. 计算机软件与硬件系统基础知识,计算机软硬件系统基础知识.pdf
  17. C++简单程序编写和操作步骤
  18. cygwin安装linux教程,Cygwin,让你拥有Windows下的Linux环境
  19. wireshark解析信令tshark
  20. 《薛兆丰的经济学课》课程总结4--相互依赖

热门文章

  1. 【翻译】Adventuring to Spur Creativity at Work【通过探险激发工作中的创造力】
  2. linux基础教程课后答案,Linux教材课后习题答案.pdf
  3. Business Insider报告:聊天工具比社交网络发展得更加壮大
  4. 核心坚果计划互相监督跟踪平台 (New)
  5. win10系统C盘瘦身记录
  6. Python之路【第二十三篇】:数据库基础
  7. 股神巴菲特忠告中国股民及巴菲特忠告中国股民把控风险
  8. 推荐几款常用的企业网盘软件,你喜欢哪一款?
  9. 一个可能的visual studio 的 cl.exe可能的地址
  10. 同步,异步,并行概念的歪解