A 平台I2C 的使用

下面分享一下amlogic 平台I2C 使用的一点心得。

  1. I2C controllers 概述
    I2C 是Inter-Integrated Circuit的缩写,发音为"eye-squared cee" or “eye-two-cee” , 它是一种两线接口。I2C 只是用两条双向的线,一条 Serial Data Line (SDA) ,另一条Serial Clock (SCL)。
    SCL:上升沿将数据输入到每个EEPROM器件中;下降沿驱动EEPROM器件输出数据。(边沿触发)
    SDA:双向数据线,为OD门,与其它任意数量的OD与OC门成"线与"关系。

详细协议可以参详:https://blog.csdn.net/qq_37600027/article/details/82119906

  1. I2C controllers 基地址
    g12a/g12b 平台如下:
    在这里插入图片描述
    txlx 平台如下:
    在这里插入图片描述
    axg 平台如下:
    在这里插入图片描述
    从截图我们可以看到i2c controller 的base address,offset,size,这几个都会在dts 中设置。

  2. I2C 总线在DTS 中定义
    我们可以先看一下i2c 定义的基本格式:

Amlogic Meson I2C controller
Required properties:
 - compatible: must be "amlogic,meson6-i2c"
					or "amlogic,meson-gx-i2c"
					or "amlogic,meson-axg-i2c"
					or "amlogic,meson-txlx-i2c"
					or "amlogic,meson8b-i2c"
 - reg: physical address and length of the device registers
 - interrupts: a single interrupt specifier
 - clocks: clock for the device
 - #address-cells: should be <1>
 - #size-cells: should be <0>

Optional properties:
- clock-frequency: the desired I2C bus clock frequency in Hz; in
  absence of this property the default value is used (100 kHz).

Examples:
	i2c@c8100500 {
		compatible = "amlogic,meson6-i2c";
		reg = <0xc8100500 0x20>;
		interrupts = <0 92 1>;
		clocks = <&clk81>;
		#address-cells = <1>;
		#size-cells = <0>;
	};

compatible,reg,interrupts,clocks 都是必须设置的。例如AO总线(i2cAO) 在mesonaxg.dtsi定义

		i2c_AO: i2c@5000 {
			compatible = "amlogic,meson-axg-i2c";
			status = "disabled";
			reg = < 0x0 0x05000 0x0 0x20>;
			interrupts = < GIC_SPI 195 IRQ_TYPE_EDGE_RISING>;
			#address-cells = <1>;
			#size-cells = <0>;
			clocks = <&clkc CLKID_I2C>;
			clock-names = "clk_i2c";
		};

compatible 为“amlogic meson-axg-i2c” 表示是axg 平台;
status 为disable表示为关闭状态,如果开启在通过&i2c_AO,然后内部添加
status = “okay” 即可开启;
reg 为< 0x0 0x05000 0x0 0x20>,其中0x05000 是基地址,0x20 是size 大小,此处多了两个0x0 与demo有稍许差异,可能跟内核版本及i2c 驱动版本有关系;
interrupts 为 < GIC_SPI 195 IRQ_TYPE_EDGE_RISING>
第一个参数表示是IPI、PPI、SPI、SGI其中的一个

IPI:inter-processer interrupt   中断号0~15
PPI:per processor interrupts    中断号16~31
SPI:shared processor interrupts  中断号 32 ~32+224
SGI:software generated interrupts (SGI).

第二个参数195 表示中断号
第三个参数表示中断触发的类型(上升沿,下降沿等)

#define IRQ_TYPE_NONE        0
#define IRQ_TYPE_EDGE_RISING    1
#define IRQ_TYPE_EDGE_FALLING    2
#define IRQ_TYPE_EDGE_BOTH    (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
#define IRQ_TYPE_LEVEL_HIGH    4
#define IRQ_TYPE_LEVEL_LOW    8

更多intrrupt 说明参考“https://blog.csdn.net/a3121772305/article/details/89500617”
clocks为clocks = <&clkc CLKID_I2C>,表示使用从clock 是clkc,ID 是CLKID_I2C
(@kernel\aml-4.9\include\dt-bindings\clock\amlogic,axg-clkc.h)。clkc定义 如下:

		clkc: clock-controller@0 {
			compatible = "amlogic,axg-clkc";
			#clock-cells = <1>;
			reg = <0x0 0x0 0x0 0x320>;
		};

另外几路I2c-A,I2C-B,I2C-C,I2C-D

			/*i2c-A*/
			i2c0: i2c@1f000 {
				compatible = "amlogic,meson-axg-i2c";
				status = "disabled";
				reg = <0x0 0x1f000 0x0 0x20>;
				interrupts = <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>,
					<GIC_SPI 47 IRQ_TYPE_EDGE_RISING>;
				#address-cells = <1>;
				#size-cells = <0>;
				clocks = <&clkc CLKID_I2C>;
				clock-names = "clk_i2c";
			};

			/*i2c-B*/
			i2c1: i2c@1e000 {
				compatible = "amlogic,meson-axg-i2c";
				status = "disabled";
				reg = <0x0 0x1e000 0x0 0x20>;
				interrupts = <GIC_SPI 214 IRQ_TYPE_EDGE_RISING>,
					<GIC_SPI 48 IRQ_TYPE_EDGE_RISING>;
				#address-cells = <1>;
				#size-cells = <0>;
				clocks = <&clkc CLKID_I2C>;
				clock-names = "clk_i2c";
			};

			/*i2c-C*/
			i2c2: i2c@1d000 {
				compatible = "amlogic,meson-axg-i2c";
				status = "disabled";
				reg = <0x0 0x1d000 0x0 0x20>;
				interrupts = <GIC_SPI 215 IRQ_TYPE_EDGE_RISING>,
					<GIC_SPI 49 IRQ_TYPE_EDGE_RISING>;
				#address-cells = <1>;
				#size-cells = <0>;
				clocks = <&clkc CLKID_I2C>;
				clock-names = "clk_i2c";
			};

			/*i2c-D*/
			i2c3: i2c@1c000 {
				compatible = "amlogic,meson-axg-i2c";
				status = "disabled";
				reg = <0x0 0x1c000 0x0 0x20>;
				interrupts = <GIC_SPI 39 IRQ_TYPE_EDGE_RISING>,
					<GIC_SPI 50 IRQ_TYPE_EDGE_RISING>;
				#address-cells = <1>;
				#size-cells = <0>;
				clocks = <&clkc CLKID_I2C>;
				clock-names = "clk_i2c";
			};
  1. I2C 总线设备挂载
    mesonaxg.dtsi 上面定义好了总线,就可以再对应总线上面挂载设备了,例如A113X 平台 上面(axg_s420.dts), i2c-B 总线挂载ADC,功放等
/* for spk board */
&i2c1 {
	status = "okay";
	pinctrl-names="default";
	pinctrl-0=<&b_i2c_master>;

	tlv320adc3101_32: tlv320adc3101_32@30 {
		compatible = "ti,tlv320adc3101";
		#sound-dai-cells = < 0 >;
		reg = < 0x19 >;
		differential_pair = <1>;
		status = "okay";
	};

	tas5707_36: tas5707_36@36 {
		compatible = "ti,tas5707";
		#sound-dai-cells = <0>;
		reg = < 0x1b >;
		status = "okay";
		reset_pin = <&gpio_ao GPIOAO_4 0>;
	};

	tas5707_3a: tas5707_3a@3a {
		compatible = "ti,tas5707";
		#sound-dai-cells = < 0 >;
		reg = < 0x1d >;
		status = "disable";
	};
};

通过&i2c1 引用总线,再在内部status 来开启,并定义需要挂载的ADC,功放设备,设置其I2C地址,还需要设定pinmux。

	pinctrl-names="default";
	pinctrl-0=<&b_i2c_master>;

b_i2c_master 定义了使用的i2c1 的 _z 这一组clk,data 信号

扫描二维码关注公众号,回复: 8876502 查看本文章
	b_i2c_master:b_i2c {
		mux {
			groups = "i2c1_sck_z",
				"i2c1_sda_z";
			function = "i2c1";
		};
	};

i2c1_sck_z 和 i2c1_sda_z 的定义

i2c1 有两组信号出来
static const char * const i2c1_groups[] = {
	"i2c1_sck_z", "i2c1_sda_z",
	"i2c1_sck_x", "i2c1_sda_x",
};

/* i2c1  _z*/
static const unsigned int i2c1_sck_z_pins[] = {GPIOZ_8};
static const unsigned int i2c1_sda_z_pins[] = {GPIOZ_9};
/* i2c1  _x*/
static const unsigned int i2c1_sck_x_pins[] = {GPIOX_16};
static const unsigned int i2c1_sda_x_pins[] = {GPIOX_17};

GROUP(i2c1_sck_x,		1),
GROUP(i2c1_sck_z,		1),
通过GROUP 定义一组GROUP 最后形成一个BANK
#define GROUP(grp, f)							\
	{								\
		.name = #grp,						\
		.pins = grp ## _pins,                                   \
		.num_pins = ARRAY_SIZE(grp ## _pins),			\
		.data = (const struct meson_pmx_axg_data[]){		\
			PMX_DATA(f),					\
		},							\
	}

更多pin 的定义可以看文件kernel\aml-4.9\drivers\amlogic\pinctrl\pinctrl-meson-axg.c。

  1. I2C 的统一命名
    在这里插入图片描述
  2. linux 下I2C 调试工具
    i2c tools 命令有 i2cdetect,i2cset,i2cget,i2cdump 四组,
    i2cdetect 检测挂在总线上的设备;
    i2cset 写命令;
    i2cget 读命令;
    i2cdump 批量读命令,可以将 i2cdetect ,i2cset 等可执行文件拷贝到开发板 data 目录下。

i2cdetect 命令

#./i2cdetect -l
查看注册到内核的 i2c 控制器
#./i2cdetect -y -r 4
查看挂在 i2c-4 总线上的设备地址

i2cdump命令

#./i2cdump -f -y 4 0x66
查看挂在总线 i2c-4 上设备地址为 0x66 的内部寄存器存储值
在这里插入图片描述

i2cset 命令

#./i2cset -f -y 4 0x66 0x2 0xff
i2c 总线为 4,0x66 为设备地址, 0x2 设备寄存器地址, 0xff 为写进的值

i2cget 命令

#./i2cget -f -y 4 0x66 0x2
读取寄存器地址 0x2 的值

  1. I2C 属性配置

i2c 速率

在实际 i2c 从设备应用中, 经常会根据 i2c 从设备 Spec 来配置适合的速率, 这里说明两种改变 i2c 速率的方式,
第一种, 改变 dts 中 clock-frequency 关键字;
第二种, kernel 4.9 提供了在线修改 i2c 速率的调试接口, 供在线调试 i2c 速率
在这里插入图片描述
第二种在线修改方法:
以修改 i2c1 控制器为例:
echo 400000 > /sys/class/i2c-adapter/i2c-1/device/speed
修改 i2c1 控制器速率为 400kHZ.

  1. uboot 下i2c 使用
    在 uboot 下执行 i2c, 可以看到所有 i2c 命令, 常用的命令有 i2c dev, i2c probe, i2c mw, i2c md, i2c speed等命令
    在i2c driver 支持的情况下

切换 i2c 控制器

i2c dev 0 切换到 i2c0 控制器
i2c dev 1 切换到 i2c1 控制器

i2c 设备探测

i2c probe

i2c 写

i2c mw 0x50 0 0x11 向从设备的 0x0 地址写 0x11
0x50 是从设备地址, 0x0 是从设备里寄存器地址, 0x11 是要写的数据

i2c 读

在这里插入图片描述

i2c speed

设置 i2c 控制器时钟速率
i2c speed 100000 设置时钟速率为 100kHZ
i2c speed 400000 设置时钟速率为 400kHZ

发布了101 篇原创文章 · 获赞 19 · 访问量 33万+

猜你喜欢

转载自blog.csdn.net/kehyuanyu/article/details/100134538