20230414将CV1826平台的硬件I2C2配置成为模拟I2C6
2023/4/14 15:58
在公司的点读笔项目S6中,TP使用了I2C2(GPIOB13/B14),摄像头也占用了I2C2(GPIOC15/14)。但是linux的内核中只能有一个I2C总线!
由于摄像头对I2C2的使用率偏低:打开之后就不用管了!
因此公司决定让TP使用硬件I2C2,摄像头使用GPIO口模拟的I2C6。
1、【已经默认打开了】
Z:\cv1823\smartpen\build\boards\cv1826_wevb_0005a\linux\cvitek_cv1826_wevb_0005a_defconfig
#
# I2C system bus drivers (mostly embedded / system-on-chip)
#
# CONFIG_I2C_CBUS_GPIO is not set
CONFIG_I2C_DESIGNWARE_CORE=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
# CONFIG_I2C_DESIGNWARE_SLAVE is not set
# CONFIG_I2C_EMEV2 is not set
CONFIG_I2C_GPIO=y
# CONFIG_I2C_GPIO_FAULT_INJECTOR is not set
# CONFIG_I2C_NOMADIK is not set
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_PCA_PLATFORM is not set
# CONFIG_I2C_RK3X is not set
# CONFIG_I2C_SIMTEC is not set
# CONFIG_I2C_XILINX is not set
2、
Z:\cv1823\smartpen\build\boards\cv1826_wevb_0005a\u-boot\cvi_board_init.c
// set tp, i2c2 and reset irq
//PINMUX_CONFIG(VIVO_D8, IIC2_SCL);
//PINMUX_CONFIG(VIVO_D7, IIC2_SDA);
PINMUX_CONFIG(PAD_MIPI_TXP1, IIC2_SCL);
PINMUX_CONFIG(PAD_MIPI_TXM1, IIC2_SDA);
修改为:(在uboot阶段将GPIOC15/14配置为GPIO口)
// set tp, i2c2 and reset irq
//PINMUX_CONFIG(VIVO_D8, IIC2_SCL);
//PINMUX_CONFIG(VIVO_D7, IIC2_SDA);
//PINMUX_CONFIG(PAD_MIPI_TXP1, IIC2_SCL);
//PINMUX_CONFIG(PAD_MIPI_TXM1, IIC2_SDA);
//PINMUX_CONFIG(SD0_CLK, XGPIOA_7);
PINMUX_CONFIG(PAD_MIPI_TXP1, XGPIOC_15);
PINMUX_CONFIG(PAD_MIPI_TXM1, XGPIOC_14);
printf("-------------------1----------------------\n");
//sc7a20
PINMUX_CONFIG(IIC2_SDA, PWR_GPIO_13);
修改为:【可选】
//sc7a20
//PINMUX_CONFIG(IIC2_SDA, PWR_GPIO_13);
mmio_write_32(0x03001C84, 0x08); // set MIPI_TXP0 Driving Strength to 0
mmio_write_32(0x03001C80, 0x08); // set MIPI_TXM0 Driving Strength to 0
mmio_write_32(0x03001C7c, 0x08); // set MIPI_TXP1 Driving Strength to 0
mmio_write_32(0x03001C78, 0x08); // set MIPI_TXM1 Driving Strength to 0
mmio_write_32(0x03001C74, 0x08); // set MIPI_TXP2 Driving Strength to 0
mmio_write_32(0x03001C70, 0x08); // set MIPI_TXM2 Driving Strength to 0
修改为:
mmio_write_32(0x03001C84, 0x08); // set MIPI_TXP0 Driving Strength to 0
mmio_write_32(0x03001C80, 0x08); // set MIPI_TXM0 Driving Strength to 0
//mmio_write_32(0x03001C7c, 0x08); // set MIPI_TXP1 Driving Strength to 0
//mmio_write_32(0x03001C78, 0x08); // set MIPI_TXM1 Driving Strength to 0
mmio_write_32(0x03001C74, 0x08); // set MIPI_TXP2 Driving Strength to 0
mmio_write_32(0x03001C70, 0x08); // set MIPI_TXM2 Driving Strength to 0
3、
Z:\cv1823\smartpen\build\boards\cv1826_wevb_0005a_3\linux\cv1826_wevb_0005a_3.dts
/delete-node/ ethernet@4070000;
/delete-node/ cv-spinf@4060000;
/delete-node/ cvi-spif@10000000;
/delete-node/ sound_PDM;
/delete-node/ cv-sd@4310000;
// i2c5:i2c_gpio {
// compatible = "i2c-gpio";
// gpios = <&porte 2 GPIO_ACTIVE_HIGH>, /* sda PWR_GPIO2*/
// <&porte 1 GPIO_ACTIVE_HIGH>; /* scl PWR_GPIO1*/
// i2c-gpio,delay-us = <5>; /* ~100 kHz */
// };
aliases {
i2c0 = &i2c0;
i2c1 = &i2c1;
i2c2 = &i2c2;
i2c3 = &i2c3;
i2c4 = &i2c4;
i2c5 = &pwr_i2c;
#if 0
ethernet0 = ðernet0;
#endif
};
};
&uart1 {
status = "okay";
};
修改为:
/delete-node/ ethernet@4070000;
/delete-node/ cv-spinf@4060000;
/delete-node/ cvi-spif@10000000;
/delete-node/ sound_PDM;
/delete-node/ cv-sd@4310000;
//i2c_camera:i2c6 {
//i2c-gpio:i2c6 {
i2c_gpio:i2c6 {
compatible = "i2c-gpio";
gpios = <&portc 14 GPIO_ACTIVE_HIGH>, /*SDA*/
<&portc 15 GPIO_ACTIVE_HIGH>; /*SCL*/
//i2c-gpio,sda-open-drain;
//i2c-gpio,scl-open-drain;
//i2c-gpio,delay-us = <5>; /* ~100 kHz */
//i2c-gpio,delay-us = <2>; /* ~100 kHz */
//# [ 138.687847] i2c i2c-6: sendbytes: NAK bailout.
//i2c-gpio,delay-us = <20>;
i2c-gpio,delay-us = <50>;
//i2c-gpio,delay-us = <200>;
#address-cells = <1>;
#size-cells = <0>;
//status = "okay";
};
aliases {
i2c0 = &i2c0;
i2c1 = &i2c1;
i2c2 = &i2c2;
i2c3 = &i2c3;
i2c4 = &i2c4;
i2c5 = &pwr_i2c;
//i2c6 = &i2c_camera;
//i2c6 = &i2c6;
//i2c6 = &i2c-gpio;
i2c6 = &i2c_gpio;
#if 0
ethernet0 = ðernet0;
#endif
};
};
&uart1 {
status = "okay";
};
4、【请严重注意:本处内核里面的printk打印可能会被清除掉,但是本处必须修改!】
另:I2C0拿掉还是会显示/dev/i2c-0,但是不加上I2C6,肯定不会显示/dev/i2c-6!^_
Z:\cv1823\smartpen\linux\drivers\i2c\i2c-dev.c
static int i2cdev_attach_adapter(struct device *dev, void *dummy)
{
struct i2c_adapter *adap;
struct i2c_dev *i2c_dev;
int res;
if (dev->type != &i2c_adapter_type)
return 0;
adap = to_i2c_adapter(dev);
i2c_dev = get_free_i2c_dev(adap);
if (IS_ERR(i2c_dev))
return PTR_ERR(i2c_dev);
cdev_init(&i2c_dev->cdev, &i2cdev_fops);
i2c_dev->cdev.owner = THIS_MODULE;
device_initialize(&i2c_dev->dev);
i2c_dev->dev.devt = MKDEV(I2C_MAJOR, adap->nr);
i2c_dev->dev.class = i2c_dev_class;
i2c_dev->dev.parent = &adap->dev;
i2c_dev->dev.release = i2cdev_dev_release;
#if defined(CONFIG_ARCH_CVITEK)
if (!strcmp(adap->dev.of_node->full_name, I2C0))
adap->i2c_idx = 0;
if (!strcmp(adap->dev.of_node->full_name, I2C1))
adap->i2c_idx = 1;
if (!strcmp(adap->dev.of_node->full_name, I2C2))
adap->i2c_idx = 2;
if (!strcmp(adap->dev.of_node->full_name, I2C3))
adap->i2c_idx = 3;
if (!strcmp(adap->dev.of_node->full_name, I2C4))
adap->i2c_idx = 4;
if (!strcmp(adap->dev.of_node->full_name, PWRI2C))
adap->i2c_idx = 5;
dev_set_name(&i2c_dev->dev, "i2c-%d", adap->i2c_idx);
#else
dev_set_name(&i2c_dev->dev, "i2c-%d", adap->nr);
#endif
res = cdev_device_add(&i2c_dev->cdev, &i2c_dev->dev);
if (res) {
put_i2c_dev(i2c_dev, false);
return res;
}
pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
adap->name, adap->nr);
return 0;
}
修改为:
static int i2cdev_attach_adapter(struct device *dev, void *dummy)
{
struct i2c_adapter *adap;
struct i2c_dev *i2c_dev;
int res;
printk("***wyb %s:%d %s\n",__FILE__,__LINE__,__FUNCTION__);
if (dev->type != &i2c_adapter_type)
return 0;
adap = to_i2c_adapter(dev);
i2c_dev = get_free_i2c_dev(adap);
if (IS_ERR(i2c_dev))
return PTR_ERR(i2c_dev);
cdev_init(&i2c_dev->cdev, &i2cdev_fops);
i2c_dev->cdev.owner = THIS_MODULE;
device_initialize(&i2c_dev->dev);
i2c_dev->dev.devt = MKDEV(I2C_MAJOR, adap->nr);
i2c_dev->dev.class = i2c_dev_class;
i2c_dev->dev.parent = &adap->dev;
i2c_dev->dev.release = i2cdev_dev_release;
#if defined(CONFIG_ARCH_CVITEK)
//if (!strcmp(adap->dev.of_node->full_name, I2C0))
// adap->i2c_idx = 0;
if (!strcmp(adap->dev.of_node->full_name, I2C1))
adap->i2c_idx = 1;
if (!strcmp(adap->dev.of_node->full_name, I2C2))
adap->i2c_idx = 2;
if (!strcmp(adap->dev.of_node->full_name, I2C3))
adap->i2c_idx = 3;
if (!strcmp(adap->dev.of_node->full_name, I2C4))
adap->i2c_idx = 4;
if (!strcmp(adap->dev.of_node->full_name, PWRI2C))
adap->i2c_idx = 5;
if (!strcmp(adap->dev.of_node->full_name, "i2c6"))
adap->i2c_idx = 6;
//if (!strcmp(adap->dev.of_node->full_name, i2c_gpio))
// adap->i2c_idx = 6;
dev_set_name(&i2c_dev->dev, "i2c-%d", adap->i2c_idx);
printk("***wyb %s:%d %s\n",__FILE__,__LINE__,__FUNCTION__);
#else
dev_set_name(&i2c_dev->dev, "i2c-%d", adap->nr);
printk("***wyb %s:%d %s\n",__FILE__,__LINE__,__FUNCTION__);
#endif
res = cdev_device_add(&i2c_dev->cdev, &i2c_dev->dev);
if (res) {
put_i2c_dev(i2c_dev, false);
return res;
}
pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
adap->name, adap->nr);
printk("***wyb %s:%d %s\n",__FILE__,__LINE__,__FUNCTION__);
return 0;
}
5、【可选】加的printk会被打印,在SourceInsight中搜索:"i2c-"找到这里了!
有兴趣的可以了解一下!
Z:\cv1823\smartpen\linux\drivers\i2c\i2c-core-base.c
static int i2c_register_adapter(struct i2c_adapter *adap)
{
int res = -EINVAL;
printk("***wyb %s:%d %s\n",__FILE__,__LINE__,__FUNCTION__);
/* Can't register until after driver model init */
if (WARN_ON(!is_registered)) {
res = -EAGAIN;
goto out_list;
}
/* Sanity checks */
if (WARN(!adap->name[0], "i2c adapter has no name"))
goto out_list;
if (!adap->algo) {
pr_err("adapter '%s': no algo supplied!\n", adap->name);
goto out_list;
}
if (!adap->lock_ops)
adap->lock_ops = &i2c_adapter_lock_ops;
rt_mutex_init(&adap->bus_lock);
rt_mutex_init(&adap->mux_lock);
mutex_init(&adap->userspace_clients_lock);
INIT_LIST_HEAD(&adap->userspace_clients);
/* Set default timeout to 1 second if not already set */
if (adap->timeout == 0)
adap->timeout = HZ;
/* register soft irqs for Host Notify */
res = i2c_setup_host_notify_irq_domain(adap);
if (res) {
pr_err("adapter '%s': can't create Host Notify IRQs (%d)\n",
adap->name, res);
goto out_list;
}
printk("***wyb %s:%d %s i2c-%d\n",__FILE__,__LINE__,__FUNCTION__, adap->nr);
dev_set_name(&adap->dev, "i2c-%d", adap->nr);
adap->dev.bus = &i2c_bus_type;
adap->dev.type = &i2c_adapter_type;
res = device_register(&adap->dev);
if (res) {
pr_err("adapter '%s': can't register device (%d)\n", adap->name, res);
goto out_list;
}
res = of_i2c_setup_smbus_alert(adap);
if (res)
goto out_reg;
printk("***wyb %s:%d %s adapter [%s] registered\n",__FILE__,__LINE__,__FUNCTION__, adap->name);
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
pm_runtime_no_callbacks(&adap->dev);
pm_suspend_ignore_children(&adap->dev, true);
pm_runtime_enable(&adap->dev);
#ifdef CONFIG_I2C_COMPAT
res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
adap->dev.parent);
if (res)
dev_warn(&adap->dev,
"Failed to create compatibility class link\n");
#endif
i2c_init_recovery(adap);
/* create pre-declared device nodes */
of_i2c_register_devices(adap);
i2c_acpi_install_space_handler(adap);
i2c_acpi_register_devices(adap);
if (adap->nr < __i2c_first_dynamic_bus_num)
i2c_scan_static_board_info(adap);
/* Notify drivers */
mutex_lock(&core_lock);
bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
mutex_unlock(&core_lock);
printk("***wyb %s:%d %s\n",__FILE__,__LINE__,__FUNCTION__);
return 0;
out_reg:
init_completion(&adap->dev_released);
device_unregister(&adap->dev);
wait_for_completion(&adap->dev_released);
out_list:
mutex_lock(&core_lock);
idr_remove(&i2c_adapter_idr, adap->nr);
mutex_unlock(&core_lock);
return res;
}
6、确认生成/dev/i2c-6:
#
#
#
# cd /sys/class/i2c-adapter/
#
# ls -l
total 0
lrwxrwxrwx 1 root root 0 Jan 1 00:00 i2c-0 -> ../../devices/platform/4000000.i2c/i2c-0
lrwxrwxrwx 1 root root 0 Jan 1 00:00 i2c-1 -> ../../devices/platform/4010000.i2c/i2c-1
lrwxrwxrwx 1 root root 0 Jan 1 00:00 i2c-2 -> ../../devices/platform/4020000.i2c/i2c-2
lrwxrwxrwx 1 root root 0 Jan 1 00:00 i2c-3 -> ../../devices/platform/4030000.i2c/i2c-3
lrwxrwxrwx 1 root root 0 Jan 1 00:00 i2c-4 -> ../../devices/platform/4040000.i2c/i2c-4
lrwxrwxrwx 1 root root 0 Jan 1 00:00 i2c-5 -> ../../devices/platform/502b000.i2c/i2c-5
lrwxrwxrwx 1 root root 0 Jan 1 00:00 i2c-6 -> ../../devices/platform/i2c6/i2c-6
#
# cd /sys/bus/i2c/devices/
#
# ls -l
total 0
lrwxrwxrwx 1 root root 0 Jan 1 00:00 0-003d -> ../../../devices/platform/4000000.i2c/i2c-0/0-003d
lrwxrwxrwx 1 root root 0 Jan 1 00:00 1-003d -> ../../../devices/platform/4010000.i2c/i2c-1/1-003d
lrwxrwxrwx 1 root root 0 Jan 1 00:00 2-0020 -> ../../../devices/platform/4020000.i2c/i2c-2/2-0020
lrwxrwxrwx 1 root root 0 Jan 1 00:00 2-003d -> ../../../devices/platform/4020000.i2c/i2c-2/2-003d
lrwxrwxrwx 1 root root 0 Jan 1 00:00 2-0055 -> ../../../devices/platform/4020000.i2c/i2c-2/2-0055
lrwxrwxrwx 1 root root 0 Jan 1 00:00 3-0034 -> ../../../devices/platform/4030000.i2c/i2c-3/3-0034
lrwxrwxrwx 1 root root 0 Jan 1 00:00 3-0035 -> ../../../devices/platform/4030000.i2c/i2c-3/3-0035
lrwxrwxrwx 1 root root 0 Jan 1 00:00 3-003d -> ../../../devices/platform/4030000.i2c/i2c-3/3-003d
lrwxrwxrwx 1 root root 0 Jan 1 00:00 3-0062 -> ../../../devices/platform/4030000.i2c/i2c-3/3-0062
lrwxrwxrwx 1 root root 0 Jan 1 00:00 4-003d -> ../../../devices/platform/4040000.i2c/i2c-4/4-003d
lrwxrwxrwx 1 root root 0 Jan 1 00:00 4-004e -> ../../../devices/platform/4040000.i2c/i2c-4/4-004e
lrwxrwxrwx 1 root root 0 Jan 1 00:00 5-0018 -> ../../../devices/platform/502b000.i2c/i2c-5/5-0018
lrwxrwxrwx 1 root root 0 Jan 1 00:00 5-0019 -> ../../../devices/platform/502b000.i2c/i2c-5/5-0019
lrwxrwxrwx 1 root root 0 Jan 1 00:00 5-0034 -> ../../../devices/platform/502b000.i2c/i2c-5/5-0034
lrwxrwxrwx 1 root root 0 Jan 1 00:00 i2c-0 -> ../../../devices/platform/4000000.i2c/i2c-0
lrwxrwxrwx 1 root root 0 Jan 1 00:00 i2c-1 -> ../../../devices/platform/4010000.i2c/i2c-1
lrwxrwxrwx 1 root root 0 Jan 1 00:00 i2c-2 -> ../../../devices/platform/4020000.i2c/i2c-2
lrwxrwxrwx 1 root root 0 Jan 1 00:00 i2c-3 -> ../../../devices/platform/4030000.i2c/i2c-3
lrwxrwxrwx 1 root root 0 Jan 1 00:00 i2c-4 -> ../../../devices/platform/4040000.i2c/i2c-4
lrwxrwxrwx 1 root root 0 Jan 1 00:00 i2c-5 -> ../../../devices/platform/502b000.i2c/i2c-5
lrwxrwxrwx 1 root root 0 Jan 1 00:00 i2c-6 -> ../../../devices/platform/i2c6/i2c-6
#
#
# cd /dev
#
# ls -l
total 0
drwxr-xr-x 2 root root 400 Jan 1 00:00 block
drwxr-xr-x 3 root root 60 Jan 1 00:00 bus
drwxr-xr-x 2 root root 13080 Jan 1 00:00 char
crw------- 1 root root 5, 1 Jan 1 00:03 console
crw------- 1 root root 10, 60 Jan 1 00:00 cpu_dma_latency
crw------- 1 root root 10, 62 Jan 1 00:00 cv182xadc
crw------- 1 root root 10, 61 Jan 1 00:00 cv182xdac
crw------- 1 root root 10, 55 Jan 1 00:00 cvi-base
crw------- 1 root root 10, 54 Jan 1 00:00 cvi-mipi-rx
crw------- 1 root root 10, 53 Jan 1 00:00 cvi-mipi-tx
crw------- 1 root root 243, 0 Jan 1 00:00 cvi-saradc0
crw------- 1 root root 242, 0 Jan 1 00:00 cvi-tpu0
crw------- 1 root root 10, 52 Jan 1 00:00 cvi-vcodec
drwxr-xr-x 8 root root 160 Jan 1 00:00 disk
crw-rw---- 1 root video 29, 0 Jan 1 00:00 fb0
lrwxrwxrwx 1 root root 13 Jan 1 00:00 fd -> /proc/self/fd
crw-rw-rw- 1 root root 1, 7 Jan 1 00:00 full
crw------- 1 root root 254, 0 Jan 1 00:00 gpiochip0
crw------- 1 root root 254, 1 Jan 1 00:00 gpiochip1
crw------- 1 root root 254, 2 Jan 1 00:00 gpiochip2
crw------- 1 root root 254, 3 Jan 1 00:00 gpiochip3
crw------- 1 root root 254, 4 Jan 1 00:00 gpiochip4
crw------- 1 root root 10, 183 Jan 1 00:00 hwrng
crw------- 1 root root 89, 0 Jan 1 00:00 i2c-0
crw------- 1 root root 89, 1 Jan 1 00:00 i2c-1
crw------- 1 root root 89, 2 Jan 1 00:00 i2c-2
crw------- 1 root root 89, 3 Jan 1 00:00 i2c-3
crw------- 1 root root 89, 4 Jan 1 00:00 i2c-4
crw------- 1 root root 89, 5 Jan 1 00:00 i2c-5
crw------- 1 root root 89, 6 Jan 1 00:00 i2c-6
drwxr-xr-x 3 root root 120 Jan 1 00:00 input
crw------- 1 root root 10, 63 Jan 1 00:00 ion
【后记:模拟I2C的传输速度实测】
1、i2c-gpio,delay-us = <50>;
Microsoft Windows [版本 10.0.19045.2728]
(c) Microsoft Corporation。保留所有权利。
C:\Users\Sun>adb shell
/ #
/ # i2cdetect -y -r 6
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- 35 -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: 60 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
/ #
# [ 349.189520] i2c i2c-6: sendbytes: NAK bailout.
参考资料:
https://blog.csdn.net/lutao614/article/details/14452539
gslX680驱动中出现“i2c i2c-0: sendbytes: NAK bailout.”错误
https://blog.csdn.net/ch122633/article/details/120144785
使用GPIO模拟I2C的驱动程序分析
https://cloud.tencent.com/developer/article/1914841
14——使用GPIO操作I2C设备_IMX6ULL