转自:http://blog.csdn.net/lugandong/article/details/48092397

目录(?)[-]

  1. 前言
  2. 方式一
  3. 方式二
  4. 方式三
  5. 方式四
  6. 方式五
  7. 方式六

前言:

因为工作是音频驱动,所以经常涉及到I2C、I2S等常用的总线,想将I2C相关的东西总结一下,让自己更加了解I2C。

  • 基于:Linux3.10

方式一:

使用arch/arm/mach-s3c24xx/mach-mini2440.c举例:

static struct i2c_board_info mini2440_i2c_devs[] __initdata = {{
/* 遇到与”24c08一样的名称”的驱动就会与之绑定,0x50是I2C设备的地址 */I2C_BOARD_INFO("24c08", 0x50), .platform_data = &at24c08, }, }; /* 这里的0代表:i2c-0总线 */ i2c_register_board_info(0, mini2440_i2c_devs, ARRAY_SIZE(mini2440_i2c_devs));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 到这里我们可以说就完成了第一种方式的实例化。

  • 使用i2c_register_board_info去实例化必须知道我们使用的I2C设备是挂载到哪个总线上,并知道设备的地址。

  • 在Linux启动的时候会将信息进行收集,i2c适配器会扫描已经静态注册的i2c_board_info,通过调用i2c_register_board_info函数将包含所有I2C设备的i2c_board_info信息的i2c_devinfo变量加入到__i2c_board_list链表中,并调用i2c_new_device为其实例化一个i2c_client。在驱动加载的时候遇到同名的i2c_board_info就会将i2c_client和driver绑定,并且执行driver的probe函数。

  • 这种方式一般放在平台的代码中。

struct i2c_board_info :

/*** struct i2c_board_info - template for device creation* @type: chip type, to initialize i2c_client.name* @flags: to initialize i2c_client.flags* @addr: stored in i2c_client.addr * @platform_data: stored in i2c_client.dev.platform_data * @archdata: copied into i2c_client.dev.archdata * @of_node: pointer to OpenFirmware device node * @acpi_node: ACPI device node * @irq: stored in i2c_client.irq * * I2C doesn't actually support hardware probing, although controllers and * devices may be able to use I2C_SMBUS_QUICK to tell whether or not there's * a device at a given address. Drivers commonly need more information than * that, such as chip type, configuration, associated IRQ, and so on. * * i2c_board_info is used to build tables of information listing I2C devices * that are present. This information is used to grow the driver model tree. * For mainboards this is done statically using i2c_register_board_info(); * bus numbers identify adapters that aren't yet available. For add-on boards, * i2c_new_device() does this dynamically with the adapter already known. */ struct i2c_board_info { char type[I2C_NAME_SIZE]; unsigned short flags; unsigned short addr; void *platform_data; struct dev_archdata *archdata; struct device_node *of_node; struct acpi_dev_node acpi_node; int irq; };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 3

i2c_register_board_info:

/*** i2c_register_board_info - statically declare I2C devices* @busnum: identifies the bus to which these devices belong* @info: vector of i2c device descriptors* @len: how many descriptors in the vector; may be zero to reserve * the specified bus number. * * Systems using the Linux I2C driver stack can declare tables of board info * while they initialize. This should be done in board-specific init code * near arch_initcall() time, or equivalent, before any I2C adapter driver is * registered. For example, mainboard init code could define several devices, * as could the init code for each daughtercard in a board stack. * * The I2C devices will be created later, after the adapter for the relevant * bus has been registered. After that moment, standard driver model tools * are used to bind "new style" I2C drivers to the devices. The bus number * for any device declared using this routine is not available for dynamic * allocation. * * The board info passed can safely be __initdata, but be careful of embedded * pointers (for platform_data, functions, etc) since that won't be copied. */ int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len) { int status; down_write(&__i2c_board_lock); /* dynamic bus numbers will be assigned after the last static one */ if (busnum >= __i2c_first_dynamic_bus_num) __i2c_first_dynamic_bus_num = busnum + 1; for (status = 0; len; len--, info++) { struct i2c_devinfo *devinfo; devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL); if (!devinfo) { pr_debug("i2c-core: can't register boardinfo!\n"); status = -ENOMEM; break; } devinfo->busnum = busnum; devinfo->board_info = *info; list_add_tail(&devinfo->list, &__i2c_board_list); } up_write(&__i2c_board_lock); return status; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

方式二:

使用arch/arm/mach-ux500/board-mop500-uib.c举例:

void mop500_uib_i2c_add(int busnum, struct i2c_board_info *info,unsigned n)
{struct i2c_adapter *adap; struct i2c_client *client; int i; /* 获得一个总线,当然必须知道我们设备要挂载在哪个总线上,busnum就是总线编号 */ adap = i2c_get_adapter(busnum); if (!adap) { pr_err("failed to get adapter i2c%d\n", busnum); return; } for (i = 0; i < n; i++) { /* 将i2c_board_info所描述的器件与适配器进行关联,并实例化i2c_client */ client = i2c_new_device(adap, &info[i]); if (!client) pr_err("failed to register %s to i2c%d\n", info[i].type, busnum); } /* 与 i2c_get_adapter对应,释放资源 */ i2c_put_adapter(adap); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 别忘了在注销驱动或者出错的情况下调用i2c_unregister_device(struct i2c_client *client)去释放资源。

  • 这种方式与方式一的差别是不需要在编译内核的时候就要知道设备挂载哪个总线上、设备的地址是什么。灵活性变强了。

方式三:

如果连i2c设备的地址不知道,我们可以提供一个地址列表供系统探测。

使用drivers/media/pci/bt8xx/bttv-input.c举例:

/* Instantiate the I2C IR receiver device, if present */
void init_bttv_i2c_ir(struct bttv *btv)
{
/* 这里就是地址列表 */const unsigned short addr_list[] = { 0x1a, 0x18, 0x64, 0x30, 0x71, I2C_CLIENT_END }; struct i2c_board_info info; struct i2c_client *i2c_dev; if (0 != btv->i2c_rc) return; /* 用于存放i2c_board_info信息 */ memset(&info, 0, sizeof(struct i2c_board_info)); memset(&btv->init_data, 0, sizeof(btv->init_data)); strlcpy(info.type, "ir_video", I2C_NAME_SIZE); switch (btv->c.type) { case BTTV_BOARD_PV951: btv->init_data.name = "PV951"; btv->init_data.get_key = get_key_pv951; btv->init_data.ir_codes = RC_MAP_PV951; info.addr = 0x4b; break; } if (btv->init_data.name) { info.platform_data = &btv->init_data; i2c_dev = i2c_new_device(&btv->c.i2c_adap, &info); } else { /* * The external IR receiver is at i2c address 0x34 (0x35 for * reads). Future Hauppauge cards will have an internal * receiver at 0x30 (0x31 for reads). In theory, both can be * fitted, and Hauppauge suggest an external overrides an * internal. * That's why we probe 0x1a (~0x34) first. CB */ /* 这样就会在指定的总线上匹配addr_list中地址,将第一个匹配正确的地址保存到info->addr,然后使用i2c_device_new来实例化i2c_client */ i2c_dev = i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list, NULL); } if (NULL == i2c_dev) return; #if defined(CONFIG_MODULES) && defined(MODULE) request_module("ir-kbd-i2c"); #endif }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

i2c_new_probed_device:

struct i2c_client *i2c_new_probed_device(struct i2c_adapter *adap,struct i2c_board_info *info,unsigned short const *addr_list, int (*probe)(struct i2c_adapter *, unsigned short addr)) { int i; if (!probe) probe = i2c_default_probe; for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) { /* Check address validity */ if (i2c_check_addr_validity(addr_list[i]) < 0) { dev_warn(&adap->dev, "Invalid 7-bit address " "0x%02x\n", addr_list[i]); continue; } /* Check address availability */ if (i2c_check_addr_busy(adap, addr_list[i])) { dev_dbg(&adap->dev, "Address 0x%02x already in " "use, not probing\n", addr_list[i]); continue; } /* Test address responsiveness */ if (probe(adap, addr_list[i])) break; } if (addr_list[i] == I2C_CLIENT_END) { dev_dbg(&adap->dev, "Probing failed, no device found\n"); return NULL; } info->addr = addr_list[i]; return i2c_new_device(adap, info); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 3

方式四:

从用户空间着手,在/sys/bus/i2c/devices/i2c-0(i2c总线编号)下存在new_device(建立i2c_client)和delete_device(删除i2c_client)。

new_device方法:
echo [name] [addr:0x20] > /sys/bus/i2c/devices/i2c-0/new_device delete_device方法: echo [addr:0x20] > /sys/bus/i2c/devices/i2c-0/delete_device
  • 1
  • 2

方式五:

在dtsi中有:

/*@后面是设备的起始地址*/&i2c-0@fe {/* i2c_client的name = "hall-i2c" */compatible = "qcom, hall-i2c"; reg = <fe>; interrupts = <70>; /* 如果设置成disabled,在初始化的时候就不会被实例化,可以在linux内置文档查看更多 */ status = "disabled"; };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 其中:i2c-0中的0是总线编号,reg是设备地址,interrupts是中断号。

  • 在初始化的时候i2c总线会调用qup_i2c_probe(),接着调用of_i2c_register_devices对dtsi上所描述的设备进行实例化。并创建相应的sys文件:sys/bus/i2c/devices/0-00fe。

驱动部分代码:

/* 即使在dtsi中没有compatible 与驱动中的相对应,只要有i2c_client有与下面列表有对应的也会触发xxx_probe()函数。*/
static const struct i2c_device_id hall_id[] = {{ "hall-i2c", 0 }, { "lm82", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, hall_id);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 上面的lm83_id[] 列出的就是本驱动支持的i2c_client,哪一个i2c_client的名字与此处匹配就会调用xxx_probe()。具体的匹配函数是i2c_match_id。
static const struct of_device_id i2c_of_match[] = {{.compatible = "qcom,hall-i2c",.data = &ppdata,},{ },
};static struct platform_driver omap_i2c_driver = { .probe = xxx_probe, .remove = xxx_remove, .id_table = hall_id, .driver = { .name = "qcom_test", .owner = THIS_MODULE, .of_match_table = of_match_ptr(i2c_of_match), }, }; static int __init hall_i2c_init(void) { return i2c_add_driver(&omap_i2c_driver); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 在驱动加载的时候i2c_of_match与dtsi中的”qcom,hall-i2c”匹配成功就会调用xxx_probe函数。并发现/sys/bus/i2c/devices/0-00fe/subsystem/drivers/qcom_test,没错qcom_test就是我们驱动中的name。

of_i2c_register_devices:

void of_i2c_register_devices(struct i2c_adapter *adap)
{void *result;struct device_node *node; /* Only register child devices if the adapter has a node pointer set */ if (!adap->dev.of_node) return; dev_dbg(&adap->dev, "of_i2c: walking child nodes\n"); for_each_available_child_of_node(adap->dev.of_node, node) { struct i2c_board_info info = {}; struct dev_archdata dev_ad = {}; const __be32 *addr; int len; dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name); if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) { dev_err(&adap->dev, "of_i2c: modalias failure on %s\n", node->full_name); continue; } addr = of_get_property(node, "reg", &len); if (!addr || (len < sizeof(int))) { dev_err(&adap->dev, "of_i2c: invalid reg on %s\n", node->full_name); continue; } info.addr = be32_to_cpup(addr); if (info.addr > (1 << 10) - 1) { dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n", info.addr, node->full_name); continue; } info.irq = irq_of_parse_and_map(node, 0); info.of_node = of_node_get(node); info.archdata = &dev_ad; if (of_get_property(node, "wakeup-source", NULL)) info.flags |= I2C_CLIENT_WAKE; request_module("%s%s", I2C_MODULE_PREFIX, info.type); result = i2c_new_device(adap, &info); if (result == NULL) { dev_err(&adap->dev, "of_i2c: Failure registering %s\n", node->full_name); of_node_put(node); irq_dispose_mapping(info.irq); continue; } } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

方式六

方式三在探测到第一个可用的地址就停止探测了,且只能在一个总线上去探测。如果之前并不确定总线的编号,或者一次探测多个i2c设备,我们就可以用方式六了。

使用/drivers/hwmon/adm1026.c举例:

/* Addresses to scan ,地址列表,I2C_CLIENT_END结束标志*/
static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; /* 本驱动所支持的i2c_client */ static const struct i2c_device_id adm1026_id[] = { { "adm1026", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, adm1026_id); static struct i2c_driver adm1026_driver = { .class = I2C_CLASS_HWMON, .driver = { .name = "adm1026", }, .probe = adm1026_probe, .remove = adm1026_remove, .id_table = adm1026_id, /* 回调函数:用于自主检测,符合就返回0,不满足就返回-ENODEV */ .detect = adm1026_detect, .address_list = normal_i2c, };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 2

回调函数adm1026_detect:

/* Return 0 if detection is successful, -ENODEV otherwise */
static int adm1026_detect(struct i2c_client *client,struct i2c_board_info *info)
{struct i2c_adapter *adapter = client->adapter; int address = client->addr; int company, verstep; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { /* We need to be able to do byte I/O */ return -ENODEV; }; /* Now, we do the remaining detection. */ company = adm1026_read_value(client, ADM1026_REG_COMPANY); verstep = adm1026_read_value(client, ADM1026_REG_VERSTEP); dev_dbg(&adapter->dev, "Detecting device at %d,0x%02x with COMPANY: 0x%02x and VERSTEP: 0x%02x\n", i2c_adapter_id(client->adapter), client->addr, company, verstep); /* Determine the chip type. */ dev_dbg(&adapter->dev, "Autodetecting device at %d,0x%02x...\n", i2c_adapter_id(adapter), address); if (company == ADM1026_COMPANY_ANALOG_DEV && verstep == ADM1026_VERSTEP_ADM1026) { /* Analog Devices ADM1026 */ } else if (company == ADM1026_COMPANY_ANALOG_DEV && (verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) { dev_err(&adapter->dev, "Unrecognized stepping 0x%02x. Defaulting to ADM1026.\n", verstep); } else if ((verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) { dev_err(&adapter->dev, "Found version/stepping 0x%02x. Assuming generic ADM1026.\n", verstep); } else { dev_dbg(&adapter->dev, "Autodetection failed\n"); /* Not an ADM1026... */ return -ENODEV; } strlcpy(info->type, "adm1026", I2C_NAME_SIZE); return 0; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • i2c_driver注册的时候,i2c_core会在所有已经注册的i2c_adapter上探测address_list中的所有地址,硬件探测成功之后后调用i2c_driver的detect(这里是adm1026_detect)回调函数,如果符合我们的要求那么久填充参数info(struct i2c_board_info *info),这里填充了info->type(也就是name),至于info->addr等i2c_core会自动赋值依据我们给出的address_list。接着会根据detect填充的info建立一个i2c_client。

  • 如果多个个总线上有相同的地址的设备,那么会分别建立多个个i2c_client。如果address_list中的多个地址都有设备占用,那么会建立多个i2c_client。

本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/sky-heaven/p/7267814.html,如需转载请自行联系原作者

Linux I2C(一)之常用的几种实例化(i2c_client ) 【转】相关推荐

  1. Linux忘记密码常用的几种解决方法

    Linux忘记密码常用的几种解决方法 参考文章: (1)Linux忘记密码常用的几种解决方法 (2)https://www.cnblogs.com/vurtne-lu/p/6550590.html 备 ...

  2. shell for循环1到100_浅谈Linux下shell 编程的for循环常用的6种结构

    浅谈Linux下shell 编程的for循环常用的6种结构 1. 常用for循环结构 (1) for 变量 in 值1 值2 值3... do 程序块儿 done (2) for 变量 in `命令` ...

  3. Linux 操作系统常用以下哪种编译器,Linux 操作系统期末复习资料(Alpha版)

    Linux 操作系统期末复习资料 >>问答题 1.请列举至少4个你知道的Linux发行版? 答:RedLinux.红旗Linux.Debain.SuSE Linux等. 2.Linux支持 ...

  4. 常用的几种嵌入式Linux操作系统

    编辑器加载中...常用的几种嵌入式Linux操作系统 上海市浦东科技信息中心 石习 摘编 2010-08-13 关键字:嵌入式 操作系统 Linux 浏览量:22 以应用为中心,以计算机技术为基础,软 ...

  5. Linux常用的四种配置网卡方式

    Linux常用的四种配置网卡方式(RHEL8.5) 此方法同样适用于RHEL7 一.VIM文本编辑器 1.打开编辑器,进入此目录中,cd /etc/sysconfig/network-scripts/ ...

  6. linux查看日志常用的几种方式:less、tail、vi、more、grep

    目录 一.less(推荐使用) 二.tail(常用) 三.grep(常用) 四.vi 五.more 六.总结: 作为一个开发人员,查日志是一项必备技能,下面总结了常用的几种日志查看方式 一.less( ...

  7. linux下i2c设备驱动程序,Linux I2C 设备驱动

    I2C 设备驱动要使用 i2c_driver 和 i2c_client 数据结构并填充其中的成员函数.i2c_client 一般被包含在设备的私有信息结构体yyy_data 中,而 i2c_drive ...

  8. Linux I2C核心、总线与设备驱动

    Linux I2C核心.总线与设备驱动 I2C总线仅仅使用SCL. SDA这两根信号线就实现了设备之间的数据交互,极大地简化了对硬件资源和PCB板布线空间的占用.因此, I2C总线非常广泛地应用在EE ...

  9. Linux I2C设备驱动编写(二)

    I2C对外API I2C client的注册 i2c_register_board_info具体实现 i2c_new_device I2C driver 关于I2C设备驱动的小总结 I2C adapt ...

最新文章

  1. Python中的find()
  2. python buildin 中的一些类中为什么方法的内容都是pass?
  3. 【深度学习】Win10安装TensorFlow_gpu(避坑必看)
  4. 随想录(基于内存映射的进程通信)
  5. 贷中风控调额方法与策略详解
  6. Linux系统下从百度云快速下载文件的姿势(2020.07月更)
  7. typra + picgo + 腾讯云 配合使用编辑微信公众号内容
  8. 青年大学习里的粉色玩偶介绍
  9. Unity Rendering Mode
  10. 实验二 Java基础语法练习-基本数据类型、运算符与表达式、选择结构
  11. 以红酒数据集分类为例做决策树的可视化
  12. 阿里云网盘开始内测资格申请!
  13. HTML实现圣诞树(HTML+CSS+JavaScript)
  14. html - 移动标签 marquee 属性
  15. 计算机教学在语文中应用,计算机在语文教学中的应用.doc
  16. 颜色混合opengl
  17. 卡内基梅隆大学梁俊卫:视频中行人的多种未来轨迹预测
  18. 27.练习:多态:多态实现宠物店领养宠物
  19. python内置函数sum_python必备内置函数-sum(iterable, /, start=0)
  20. Git,哆啦A梦的时光机(二)

热门文章

  1. 2019 快过去了,自动驾驶发展得怎么样了?
  2. 人物丨深度学习大神Hinton推翻自己30年的学术成果另造新世界
  3. 解读丨从自动驾驶到学习机器学习:科技发展的15大趋势
  4. 01_字符串处理-----02_标准化
  5. 费曼:所有的科学知识都是不确定的
  6. 深度学习未来的三种方式
  7. Jürgen Schmidhuber眼中的深度学习十年,以及下一个十年展望
  8. 中国机器人产业发展报告(2019)正式发布!
  9. 美国国家科学院发布《材料研究前沿:十年调查》
  10. IBM对话智能+未来:十年提升AI性能效率千倍?