下面分享一下amlogic 平台I2C 使用的一点心得。
- 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
-
I2C controllers 基地址
g12a/g12b 平台如下:
txlx 平台如下:
axg 平台如下:
从截图我们可以看到i2c controller 的base address,offset,size,这几个都会在dts 中设置。 -
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";
};
- 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 信号
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。
- I2C 的统一命名
- 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 的值
- 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.
- 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