i2c_adapter

版权声明:本文为博主原创文章,未经博主允许不得转载。
https://blog.csdn.net/huangweiqing80/article/details/82838644

1、adapter client 简介

在内核里,i2c 驱动框架大概分为两层,adapter 驱动 和 设备驱动,adapter 英文翻译过来为 “适配器”,适配器并不恰当,根据我的理解,adapter 指的是我们 mcu 里的 i2c 控制模块,就是那堆寄存器,因为一个 mcu 里的i2c控制模块是固定的(寄存器参数、以及收发数据的方法),因此大多数情况下,它们都有芯片厂商写好了,然而我们学习的过程中自己动手写一写也并不困难。对于s3c2440仅仅有一个i2c_adapter,但是别的Mcu可能有多个。至于Client,它对应于muc外围的I2c设备,每一个i2c设备都由一个唯一的client来描述。

在这里插入图片描述

    struct i2c_adapter {
	struct module *owner;
	unsigned int id;
	unsigned int class;		  /* classes to allow probing for */
	const struct i2c_algorithm *algo; /* the algorithm to access the bus */
	void *algo_data;
 
	/* data fields that are valid for all devices	*/
	u8 level; 			/* nesting level for lockdep */
	struct mutex bus_lock;
 
	int timeout;			/* in jiffies */
	int retries;
	struct device dev;		/* the adapter device */
 
	int nr;
	char name[48];
	struct completion dev_released;
};

简单扫一眼,i2c_adapter 封装了 struct device ,因此它是作为一个设备注册到内核中去的(稍后我们会知道,它是注册到i2c_bus_type里),也就是说他对应的就是总线驱动模型中的device,此外非常重要的一个成员struct i2c_algorithm *algo ,这就是我们上边提到的 i2c 控制器收发数据的方法。

    struct i2c_algorithm {
     
    	int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
    			   int num);
    	int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
    			   unsigned short flags, char read_write,
    			   u8 command, int size, union i2c_smbus_data *data);
     
    	/* To determine what the adapter supports */
    	u32 (*functionality) (struct i2c_adapter *);
    };

master_xfer 对应于i2c协议子集 smbus ,有些设备只支持这个协议

smbus_xfer 对应于普通的 i2c 传输协议

functionality 用来描述,adapter 所具有的功能,比如是否支持 smbus

    struct i2c_client {
    	unsigned short flags;		/* div., see below		*/
    	unsigned short addr;		/* chip address - NOTE: 7bit	*/
    					/* addresses are stored in the	*/
    					/* _LOWER_ 7 bits		*/
    	char name[I2C_NAME_SIZE];
    	struct i2c_adapter *adapter;	/* the adapter we sit on	*/
    	struct i2c_driver *driver;	/* and our access routines	*/
    	struct device dev;		/* the device structure		*/
    	int irq;			/* irq issued by device		*/
    	struct list_head detected;
    };

i2c_client 本质上是一个 i2c_“dev”, 它包含了与它配对的 driver ,以及它所在的 adapter(i2c设备在物理连接上,连接到了哪个adapter),后面分析时会看到,它也是作为设备注册到i2c_bus_type

总结:

adapter和client都遵循Linux中的总线设备模型,他们对对应的是设备模型中的device,他们都有对用的driver和bus

2、adapter 驱动框架

根据设备总线驱动模型的分层思想,将一个驱动程序分为 device 和 driver 两层。在我所使用的这个内核里,2440的i2c_adapter框架是基于 platform_bus_type 的,即device是platform_device ,driver是platform_driver,bus 是platform_bus_type 。关于 platform_bus_type 别的文章已经分析过了,这里不做赘述,只简单提一下,当设备或驱动注册到 platform_bus_type 时,首先会查找驱动是否有id_table,如果有根据id_table进行匹配(就是看id_table里有无设备的名字),否则匹配设备名字和驱动名字。匹配成功则调用驱动里的probe函数。

2.1 设备侧

在device 里提供底层的硬件资源,在 driver 中取出这些资源进行使用。那么我们就可以猜测到 i2c_adapter 驱动的设备侧 至少应该含有哪些资源?
1、存器地址必须有吧,因为我们要使用这些寄存器,不然怎么传输。
2、中断必须有吧,i2c传输过程中可是离不开中断的。

下面,我们就来详细的看一看,i2c_adapter 驱动的设备侧提供了哪些设备资源。

arch/arm/plat-samsung/devs.c

struct platform_device s3c_device_i2c0 = {
	.name		  = "s3c2410-i2c",
#ifdef CONFIG_S3C_DEV_I2C1
	.id		  = 0,
#else
	.id		  = -1,
#endif
	.num_resources	  = ARRAY_SIZE(s3c_i2c_resource),
	.resource	  = s3c_i2c_resource,
};

static struct resource s3c_i2c_resource[] = {
	[0] = {
		.start = S3C_PA_IIC1,
		.end   = S3C_PA_IIC1 + SZ_4K - 1,
		.flags = IORESOURCE_MEM,
	},
	[1] = {
		.start = IRQ_IIC1,
		.end   = IRQ_IIC1,
		.flags = IORESOURCE_IRQ,
	},
};

s3c_device_i2c0是放到smdk2410_devices结构体,然后在统一注册到platform_bus中的,这个我们在前面已经讲过,忘记可以回去看platform总线、设备与驱动
arch/arm/mach-s3c24xx/mach-smdk2410.c

static struct platform_device *smdk2410_devices[] __initdata = {
	&s3c_device_usb,
	&s3c_device_lcd,
	&s3c_device_wdt,
	&s3c_device_i2c0,
	&s3c_device_iis,
};

所以,在资源文件中提供了 物理寄存器 以及 中断资源。Mach-smdk2410.c (arch\arm\mach-s3c2410),将 s3c_device_i2c0 注册到 平台设备总线上去
下面我们来看看怎么将他注册到平台设备总线上去的
arch/arm/mach-s3c24xx/mach-smdk2410.c

static void __init smdk2410_init(void)
{
	s3c_i2c0_set_platdata(NULL);
	platform_add_devices(smdk2410_devices, ARRAY_SIZE(smdk2410_devices));
	smdk_machine_init();
}

可以看到是通过smdk2410_init --> platform_add_devices注册到platform_bus中的,我们再看看smdk2410_init 中跟i2c有关的函数s3c_i2c0_set_platdata
arch/arm/plat-samsung/devs.c

void __init s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *pd)
{
	struct s3c2410_platform_i2c *npd;

	if (!pd) {
		pd = &default_i2c_data;
		pd->bus_num = 0;
	}

	npd = s3c_set_platdata(pd, sizeof(struct s3c2410_platform_i2c),
			       &s3c_device_i2c0);

	if (!npd->cfg_gpio)
		npd->cfg_gpio = s3c_i2c0_cfg_gpio;
}

s3c_i2c0_set_platdata里面有几个重要的结构体和函数
arch/arm/plat-samsung/devs.c

struct s3c2410_platform_i2c default_i2c_data __initdata = {
	.flags		= 0,
	.slave_addr	= 0x10,
	.frequency	= 100*1000,
	.sda_delay	= 100,
};

arch/arm/plat-samsung/platformdata.c

void __init *s3c_set_platdata(void *pd, size_t pdsize,
			      struct platform_device *pdev)
{
	void *npd;

	if (!pd) {
		/* too early to use dev_name(), may not be registered */
		printk(KERN_ERR "%s: no platform data supplied\n", pdev->name);
		return NULL;
	}

	npd = kmemdup(pd, pdsize, GFP_KERNEL);
	if (!npd) {
		printk(KERN_ERR "%s: cannot clone platform data\n", pdev->name);
		return NULL;
	}

	pdev->dev.platform_data = npd;
	return npd;
}

arch/arm/mach-s3c24xx/setup-i2c.c

void s3c_i2c0_cfg_gpio(struct platform_device *dev)
{
	s3c_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPE15_IICSDA);
	s3c_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPE14_IICSCL);
}

arch/arm/mach-s3c24xx/s3c244x.c

void __init s3c244x_map_io(void)
{
	/* register our io-tables */

	iotable_init(s3c244x_iodesc, ARRAY_SIZE(s3c244x_iodesc));

	/* rename any peripherals used differing from the s3c2410 */

	s3c_device_sdi.name  = "s3c2440-sdi";
	s3c_device_i2c0.name  = "s3c2440-i2c";
	s3c_nand_setname("s3c2440-nand");
	s3c_device_ts.name = "s3c2440-ts";
	s3c_device_usbgadget.name = "s3c2440-usbgadget";
}

在将 s3c_device_i2c0 注册到 平台设备总线上去之前,还提供了以上的其它信息,包括i2c控制器作为从机的默认slave_addr等(default_i2c_data ),以及引脚的配置函数(s3c_i2c0_cfg_gpio)。注意,s3c_device_i2c0.name = “s3c2440-i2c”;

2.2 驱动侧

驱动侧的工作大概是取出设备侧的资源进行利用,比如Ioremap,配置寄存器,注册中断等等

先来看一下platform_driver结构体的定义
drivers/i2c/busses/i2c-s3c2410.c

static struct platform_device_id s3c24xx_driver_ids[] = {
	{
		.name		= "s3c2410-i2c",
		.driver_data	= 0,
	}, {
		.name		= "s3c2440-i2c",
		.driver_data	= QUIRK_S3C2440,
	}, {
		.name		= "s3c2440-hdmiphy-i2c",
		.driver_data	= QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO,
	}, { },
};
...
static struct platform_driver s3c24xx_i2c_driver = {
	.probe		= s3c24xx_i2c_probe,
	.remove		= s3c24xx_i2c_remove,
	.id_table	= s3c24xx_driver_ids,
	.driver		= {
		.owner	= THIS_MODULE,
		.name	= "s3c-i2c",
		.pm	= S3C24XX_DEV_PM_OPS,
		.of_match_table = of_match_ptr(s3c24xx_i2c_match),
	},
};

static int __init i2c_adap_s3c_init(void)
{
	return platform_driver_register(&s3c24xx_i2c_driver);
}
subsys_initcall(i2c_adap_s3c_init);

subsys_initcall 相当于module_init,即在子系统初始化的时候通过platform_driver_register(&s3c24xx_i2c_driver);将s3c24xx_i2c_driver注册到平台总线中。

我们在分析platform总线模型的时候,我们知道platform_bus_type->match函数是首先根据 driver->id_table 来进行匹配device的,前面讲了s3c_device_i2c0.name = “s3c2440-i2c”,因此,匹配成功会调用 s3c24xx_i2c_driver->probe 函数,也就是 s3c24xx_i2c_probe ,它是个重点。

2.2.1 probe 函数分析

下面我们来看一下这个probe 函数

static int s3c24xx_i2c_probe(struct platform_device *pdev)
{
	struct s3c24xx_i2c *i2c;
	struct s3c2410_platform_i2c *pdata = NULL;
	struct resource *res;
	int ret;

	if (!pdev->dev.of_node) {
	    // 我们在 device 里放的platform_data就是在这里取出来的
		pdata = dev_get_platdata(&pdev->dev); 
		if (!pdata) {
			dev_err(&pdev->dev, "no platform data\n");
			return -EINVAL;
		}
	}

	i2c = devm_kzalloc(&pdev->dev, sizeof(struct s3c24xx_i2c), GFP_KERNEL);
	if (!i2c) {
		dev_err(&pdev->dev, "no memory for state\n");
		return -ENOMEM;
	}

	i2c->pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
	if (!i2c->pdata) {
		dev_err(&pdev->dev, "no memory for platform data\n");
		return -ENOMEM;
	}

	i2c->quirks = s3c24xx_get_device_quirks(pdev);
	if (pdata)
		memcpy(i2c->pdata, pdata, sizeof(*pdata));
	else
		s3c24xx_i2c_parse_dt(pdev->dev.of_node, i2c);
		
     /* 3、设置adap的相关信息 */
	strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));
	i2c->adap.owner   = THIS_MODULE;
	i2c->adap.algo    = &s3c24xx_i2c_algorithm;   //i2c适配器的收发函数
	i2c->adap.retries = 2;
	i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;
	i2c->tx_setup     = 50;

	init_waitqueue_head(&i2c->wait);

	/* find the clock and enable it 使能i2c时钟*/

	i2c->dev = &pdev->dev;
	i2c->clk = devm_clk_get(&pdev->dev, "i2c");
	if (IS_ERR(i2c->clk)) {
		dev_err(&pdev->dev, "cannot get clock\n");
		return -ENOENT;
	}

	dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);


	/* map the registers  IO内存映射*/

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	i2c->regs = devm_ioremap_resource(&pdev->dev, res);

	if (IS_ERR(i2c->regs))
		return PTR_ERR(i2c->regs);

	dev_dbg(&pdev->dev, "registers %p (%p)\n",
		i2c->regs, res);

	/* setup info block for the i2c core */

	i2c->adap.algo_data = i2c;
	i2c->adap.dev.parent = &pdev->dev;

	i2c->pctrl = devm_pinctrl_get_select_default(i2c->dev);

	/* inititalise the i2c gpio lines */

	if (i2c->pdata->cfg_gpio) {
		i2c->pdata->cfg_gpio(to_platform_device(i2c->dev));
	} else if (IS_ERR(i2c->pctrl) && s3c24xx_i2c_parse_dt_gpio(i2c)) {
		return -EINVAL;
	}

	/* initialise the i2c controller */

	clk_prepare_enable(i2c->clk);
	ret = s3c24xx_i2c_init(i2c);
	clk_disable_unprepare(i2c->clk);
	if (ret != 0) {
		dev_err(&pdev->dev, "I2C controller init failed\n");
		return ret;
	}
	/* find the IRQ for this unit (note, this relies on the init call to
	 * ensure no current IRQs pending
	 */

	if (!(i2c->quirks & QUIRK_POLL)) {
		i2c->irq = ret = platform_get_irq(pdev, 0);
		if (ret <= 0) {
			dev_err(&pdev->dev, "cannot find IRQ\n");
			return ret;
		}

	ret = devm_request_irq(&pdev->dev, i2c->irq, s3c24xx_i2c_irq, 0,
				dev_name(&pdev->dev), i2c);

		if (ret != 0) {
			dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
			return ret;
		}
	}

	ret = s3c24xx_i2c_register_cpufreq(i2c);
	if (ret < 0) {
		dev_err(&pdev->dev, "failed to register cpufreq notifier\n");
		return ret;
	}

	/* Note, previous versions of the driver used i2c_add_adapter()
	 * to add the bus at any number. We now pass the bus number via
	 * the platform data, so if unset it will now default to always
	 * being bus 0.
	 */

	i2c->adap.nr = i2c->pdata->bus_num;  //适配器编号,阅读上面的英文,大概意思就是device侧pdata中没设置bus_num,那么就默认为0,显然这里是0
	i2c->adap.dev.of_node = pdev->dev.of_node;

	ret = i2c_add_numbered_adapter(&i2c->adap);    //注册adapter
	if (ret < 0) {
		dev_err(&pdev->dev, "failed to add bus to i2c core\n");
		s3c24xx_i2c_deregister_cpufreq(i2c);
		return ret;
	}

	platform_set_drvdata(pdev, i2c);

	pm_runtime_enable(&pdev->dev);
	pm_runtime_enable(&i2c->adap.dev);

	dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
	return 0;
}

下面我们来看一下上面一个重要的函数;
注册adapter函数:i2c_add_numbered_adapter --> i2c_add_adapter --> i2c_register_adapter
所以我们直接分析i2c_register_adapter这个函数
drivers/i2c/i2c-core.c

static int i2c_register_adapter(struct i2c_adapter *adap)
{
	int res = 0;

	/* Can't register until after driver model init */
	if (unlikely(WARN_ON(!i2c_bus_type.p))) {
		res = -EAGAIN;
		goto out_list;
	}

	/* Sanity checks */
	if (unlikely(adap->name[0] == '\0')) {
		pr_err("i2c-core: Attempt to register an adapter with "
		       "no name!\n");
		return -EINVAL;
	}
	if (unlikely(!adap->algo)) {
		pr_err("i2c-core: Attempt to register adapter '%s' with "
		       "no algo!\n", adap->name);
		return -EINVAL;
	}

	rt_mutex_init(&adap->bus_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;

    /* 设置 adap->dev.kobj.name 为 i2c-0 ,它将出现在 sysfs 中 */
	dev_set_name(&adap->dev, "i2c-%d", adap->nr);
	/* 设置它所属的总线 i2c_bus_type */
	adap->dev.bus = &i2c_bus_type;
	/* 重点: 设置属性,用户空间创建 device 就靠它了 */
	adap->dev.type = &i2c_adapter_type;
	/* 将 adap->dev注册到 i2c_bus_type */
	res = device_register(&adap->dev);
	if (res)
		goto out_list;

	dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);

/* 大概是创建 devices 目录 到class 目录的符号连接 */
#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

	/* bus recovery specific initialization */
	if (adap->bus_recovery_info) {
		struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;

		if (!bri->recover_bus) {
			dev_err(&adap->dev, "No recover_bus() found, not using recovery\n");
			adap->bus_recovery_info = NULL;
			goto exit_recovery;
		}

		/* Generic GPIO recovery */
		if (bri->recover_bus == i2c_generic_gpio_recovery) {
			if (!gpio_is_valid(bri->scl_gpio)) {
				dev_err(&adap->dev, "Invalid SCL gpio, not using recovery\n");
				adap->bus_recovery_info = NULL;
				goto exit_recovery;
			}

			if (gpio_is_valid(bri->sda_gpio))
				bri->get_sda = get_sda_gpio_value;
			else
				bri->get_sda = NULL;

			bri->get_scl = get_scl_gpio_value;
			bri->set_scl = set_scl_gpio_value;
		} else if (!bri->set_scl || !bri->get_scl) {
			/* Generic SCL recovery */
			dev_err(&adap->dev, "No {get|set}_gpio() found, not using recovery\n");
			adap->bus_recovery_info = NULL;
		}
	}

exit_recovery:
	/* create pre-declared device nodes */
	of_i2c_register_devices(adap);
	acpi_i2c_register_devices(adap);

    /* 重点: 扫描 __i2c_board_list 链表里的设备信息,自动创建 client ,并注册到 i2c_bus_type */
	if (adap->nr < __i2c_first_dynamic_bus_num)
		i2c_scan_static_board_info(adap);

	/* Notify drivers */
	/* 重点: 遍历 i2c_bus_type的driver 链表,取出每一个driver 调用 i2c_do_add_adapter */
	mutex_lock(&core_lock);
	bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
	mutex_unlock(&core_lock);

	return 0;

out_list:
	mutex_lock(&core_lock);
	idr_remove(&i2c_adapter_idr, adap->nr);
	mutex_unlock(&core_lock);
	return res;
}

可以看到,在i2c_register_adapter函数中有调用了res = device_register(&adap->dev)来 将 adapter注册到 i2c_bus_type,device_register又是总线模型中的设备注册函数,所以i2c_adapter是在platform总线模型中有嵌套了一个总线模型,即在probe函数中调用i2c_register_adapter来注册i2c_adapter

总结:s3c24xx_i2c_probe函数的流程如下
在这里插入图片描述

3. 创建i2c_device

在内核帮助文档Documentation/i2c/instantiating-devices中说,有4种方法可以创建 i2c_device ,其中第四种是在用户空间命令行创建的:

3.1 命令行创建

 # echo eeprom 0x50 > /sys/bus/i2c/devices/i2c-0/new_device

分析过设备模型的都知道,i2c-0 是我们上面i2c_register_adapter中设置的 dev_set_name(&adap->dev, “i2c-%d”, adap->nr),new_device 就是它的一个属性了,这个属性在哪里?在i2c_adapter_type (dev->type )中。

drivers/i2c/i2c-core.c

static struct device_type i2c_adapter_type = {
	.groups		= i2c_adapter_attr_groups,
	.release	= i2c_adapter_dev_release,
};
static const struct attribute_group *i2c_adapter_attr_groups[] = {
	&i2c_adapter_attr_group,
	NULL
};
static struct attribute_group i2c_adapter_attr_group = {
	.attrs		= i2c_adapter_attrs,
};
 
static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device);
static DEVICE_ATTR(delete_device, S_IWUSR, NULL, i2c_sysfs_delete_device);
static struct attribute *i2c_adapter_attrs[] = {
	&dev_attr_name.attr,
	&dev_attr_new_device.attr,
	&dev_attr_delete_device.attr,
	NULL
};
  1. 当 device_register 注册 device 时,会设置dev.kobj.ktype = device_ktype, device_ktype 提供通用的属性show 与 store函数,当用户空间访问属性文件时,通用的 show 与 store 就会 调用具体的show 与 store。

  2. DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device),这个宏会创建一个device_attribute结构体,这个结构体的name = “new_device”,.mode = S_IWUSR , show = NULL ,store = i2c_sysfs_new_device

  3. 所以上面 echo eeprom 0x50 > /sys/bus/i2c/devices/i2c-0/new_device ,就会调用 i2c_sysfs_new_device 函数了,i2c_sysfs_new_device 这个函数来创建i2c_device,下面我们来看一下i2c_sysfs_new_device 这个函数

drivers/i2c/i2c-core.c

static ssize_t
i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr,
		     const char *buf, size_t count)
{
	struct i2c_adapter *adap = to_i2c_adapter(dev);
	struct i2c_board_info info;
	struct i2c_client *client;
	char *blank, end;
	int res;

	memset(&info, 0, sizeof(struct i2c_board_info));

	blank = strchr(buf, ' ');
	if (!blank) {
		dev_err(dev, "%s: Missing parameters\n", "new_device");
		return -EINVAL;
	}
	if (blank - buf > I2C_NAME_SIZE - 1) {
		dev_err(dev, "%s: Invalid device name\n", "new_device");
		return -EINVAL;
	}
	memcpy(info.type, buf, blank - buf);

	/* Parse remaining parameters, reject extra parameters */
	res = sscanf(++blank, "%hi%c", &info.addr, &end);
	if (res < 1) {
		dev_err(dev, "%s: Can't parse I2C address\n", "new_device");
		return -EINVAL;
	}
	if (res > 1  && end != '\n') {
		dev_err(dev, "%s: Extra parameters\n", "new_device");
		return -EINVAL;
	}

	client = i2c_new_device(adap, &info);
	if (!client)
		return -EINVAL;

	/* Keep track of the added device */
	mutex_lock(&adap->userspace_clients_lock);
	list_add_tail(&client->detected, &adap->userspace_clients);
	mutex_unlock(&adap->userspace_clients_lock);
	dev_info(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device",
		 info.type, info.addr);

	return count;
}

可以看到i2c_sysfs_new_device最终调用到的就是i2c_new_device

drivers/i2c/i2c-core.c

struct i2c_client *
i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
{
	struct i2c_client	*client;
	int			status;

	client = kzalloc(sizeof *client, GFP_KERNEL);
	if (!client)
		return NULL;

	client->adapter = adap;

	client->dev.platform_data = info->platform_data;

	if (info->archdata)
		client->dev.archdata = *info->archdata;

	client->flags = info->flags;
	client->addr = info->addr;   //设备地址
	client->irq = info->irq;

	strlcpy(client->name, info->type, sizeof(client->name));

	/* Check for address validity */
	status = i2c_check_client_addr_validity(client);
	if (status) {
		dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n",
			client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr);
		goto out_err_silent;
	}

	/* Check for address business */
	status = i2c_check_addr_busy(adap, client->addr);  //名字很重要
	if (status)
		goto out_err;

	client->dev.parent = &client->adapter->dev;
	client->dev.bus = &i2c_bus_type;
	client->dev.type = &i2c_client_type;
	client->dev.of_node = info->of_node;
	ACPI_COMPANION_SET(&client->dev, info->acpi_node.companion);

	i2c_dev_set_name(adap, client);
	status = device_register(&client->dev);
	if (status)
		goto out_err;

	dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n",
		client->name, dev_name(&client->dev));

	return client;

out_err:
	dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x "
		"(%d)\n", client->name, client->addr, status);
out_err_silent:
	kfree(client);
	return NULL;
}

i2c_sysfs_new_device 函数,将用户空间传递进来的命令进行解析 生成info结构体(addr ,type),然后调用 i2c_new_device, 在 i2c_new_device 中构造client ,设置它的属性并将它注册到 i2c_bus_type,其中两个必须提的属性 client->name = info->type ,为什么说名字重要,如果看i2c_bus_type的match函数就可以知道,driver是根据client的名字是否在其driver->id_table中判断是否支持这个client的。另外一个就是addr了,不用多说,每一个i2c设备必须都有个地址。空说无凭,看代码。
下面我们来看一下i2c_bus_type的match函数
drivers/i2c/i2c-core.c

struct bus_type i2c_bus_type = {
	.name		= "i2c",
	.match		= i2c_device_match,
	.probe		= i2c_device_probe,
	.remove		= i2c_device_remove,
	.shutdown	= i2c_device_shutdown,
	.pm		= &i2c_device_pm_ops,
};
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
	struct i2c_client	*client = i2c_verify_client(dev);
	struct i2c_driver	*driver;

	if (!client)
		return 0;

	/* Attempt an OF style match */
	if (of_driver_match_device(dev, drv))
		return 1;

	/* Then ACPI style match */
	if (acpi_driver_match_device(dev, drv))
		return 1;

	driver = to_i2c_driver(drv);
	/* match on an id table if there is one */
	if (driver->id_table)
		return i2c_match_id(driver->id_table, client) != NULL;

	return 0;
}
static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
						const struct i2c_client *client)
{
	while (id->name[0]) {
		if (strcmp(client->name, id->name) == 0)
			return id;
		id++;
	}
	return NULL;
}

3.2 i2c_scan_static_board_info

分析一下 i2c_scan_static_board_info创建 device 的方式

drivers/i2c/i2c-core.c

static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
{
	struct i2c_devinfo	*devinfo;
 
	down_read(&__i2c_board_lock);
	/* 遍历__i2c_board_list链表 取出每一个 devinfo */
	list_for_each_entry(devinfo, &__i2c_board_list, list) {
		/* adapter->nr == 0 devinfo->busnum 还不知道,如果相等
		   取出 devinfo->board_info 调用 i2c_new_device ,前面分析过了哦 */
		if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter, &devinfo->board_info))
			dev_err(&adapter->dev,
				"Can't create device at 0x%02x\n",
				devinfo->board_info.addr);
	}
	up_read(&__i2c_board_lock);
}

来看一下 __i2c_board_list 这个链表是哪里填充的。
mach-mini2440.c (arch\arm\mach-s3c2440)

static struct i2c_board_info i2c_devs[] __initdata = {
	{ I2C_BOARD_INFO("eeprom", 0x50), },
};
#define I2C_BOARD_INFO(dev_type, dev_addr) \
	.type = dev_type, .addr = (dev_addr)
static void __init mini2440_machine_init(void)
{
	i2c_register_board_info(0, i2c_devs, ARRAY_SIZE(i2c_devs));
	....
}
int __init i2c_register_board_info(int busnum,
	struct i2c_board_info const *info, unsigned len)
{
	int status;
 
	down_write(&__i2c_board_lock);
 
	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);
 
		devinfo->busnum = busnum;	// busnum == 0
		devinfo->board_info = *info;
		list_add_tail(&devinfo->list, &__i2c_board_list); // 添加到 __i2c_board_list 链表中
	}
 
	up_write(&__i2c_board_lock);
 
	return status;
}

可以看到是在mini2440_machine_init --> i2c_register_board_info,在i2c_register_board_info里面去添加的
这种方法与第一种用户空间创建device的方法相类似,都是提供一个addr 和 名字,只不过这种方法还有一个限制,前面看代码的时候我们知道,在注册adapter的时候,它会去访问__i2c_board_list链表,那么如果想成功创建,你必须在注册adater之前i2c_register_board_info

3. 3 bus_for_each_drv

bus_for_each_drv(&i2c_bus_type, NULL, adap, i2c_do_add_adapter)
这个函数的操作就是取出 i2c_bus_type 每一个driver 调用 i2c_do_add_adapter

static int i2c_do_add_adapter(struct device_driver *d, void *data)
{
	struct i2c_driver *driver = to_i2c_driver(d);
	struct i2c_adapter *adap = data;
 
	/* Detect supported devices on that bus, and instantiate them */
	i2c_detect(adap, driver);
 
	/* Let legacy drivers scan this bus for matching devices */
	if (driver->attach_adapter) {
		/* We ignore the return code; if it fails, too bad */
		driver->attach_adapter(adap);
	}
	return 0;
}
static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
{
	const struct i2c_client_address_data *address_data;
	struct i2c_client *temp_client;
	int i, err = 0;
	int adap_id = i2c_adapter_id(adapter);
	// driver中 设置了 address_data 是创建device的前提,因为 address_data 中保存了设备的addr 与 名字,看设备驱动的时候会知道
	address_data = driver->address_data;
	if (!driver->detect || !address_data)
		return 0;
 
	/* Set up a temporary client to help detect callback */
	temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
	if (!temp_client)
		return -ENOMEM;
	temp_client->adapter = adapter;
 
	/* Force entries are done first, and are not affected by ignore
	   entries */
	if (address_data->forces) {
		.....
	}
 
	/* Stop here if the classes do not match */
	if (!(adapter->class & driver->class))
		goto exit_free;
 
	/* Stop here if we can't use SMBUS_QUICK */
	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) {
		......
	}
 
	/* Probe entries are done second, and are not affected by ignore
	   entries either */
	for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) {
		......
	}
 
	/* Normal entries are done last, unless shadowed by an ignore entry */
	for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) {
		int j, ignore;
 
		ignore = 0;
		......
		temp_client->addr = address_data->normal_i2c[i];
		err = i2c_detect_address(temp_client, -1, driver);
	}
}
static int i2c_detect_address(struct i2c_client *temp_client, int kind,
  struct i2c_driver *driver)
{
	struct i2c_board_info info;
	struct i2c_adapter *adapter = temp_client->adapter;
	int addr = temp_client->addr;
	int err;
 
	/* 发送 start 信号 以及 i2c设备地址,看是否能收到 ack 信号,判断设备是否存在,不存在返回 */
	if (kind < 0) {
		if (i2c_smbus_xfer(adapter, addr, 0, 0, 0,
				   I2C_SMBUS_QUICK, NULL) < 0)	// 最终就会调用到adapter驱动中我们设置的 i2c_algorithm
			return 0;
	}
 
	/* Finally call the custom detection function */
	memset(&info, 0, sizeof(struct i2c_board_info));
	info.addr = addr;
	// 要在 driver->detect 设置 info->type 
	err = driver->detect(temp_client, kind, &info);
 
	/* 如果设置了 info.type,创建 client 调用 i2c_new_device */
	if (info.type[0] == '\0') {
		......
	} else {
		struct i2c_client *client;
 
		/* Detection succeeded, instantiate the device */						
		client = i2c_new_device(adapter, &info);
		if (client)
			list_add_tail(&client->detected, &driver->clients);
	}
	return 0;
}

3.4 bus_for_each_dev

我们在 向i2c_bus_type 注册driver时,与上面的方法是一样的,因此,我们可以动态加载driver时,创建对应的device,但是并不推荐这样做。
i2c_add_driver-》i2c_register_driver-》bus_for_each_dev(&i2c_bus_type, NULL, driver, __attach_adapter);
__attach_adapter 和 i2c_do_add_adapter 内容是同理的。

总结:
我们可以知道前面的三种方法最后调用都是i2c_new_device来创建i2c_device

4. i2c_bus_type

从前面分析可以知道我们在s3c24xx_i2c_probe --> i2c_register_adapter.在i2c_register_adapter函数中有调用了res = device_register(&adap->dev)来 将 adapter注册到 i2c_bus_type,那么i2c_bus_type和driver又是在哪里注册的呢
drivers/i2c/i2c-core.c

struct bus_type i2c_bus_type = {
	.name		= "i2c",
	.match		= i2c_device_match,
	.probe		= i2c_device_probe,
	.remove		= i2c_device_remove,
	.shutdown	= i2c_device_shutdown,
	.pm		= &i2c_device_pm_ops,
};
static int __init i2c_init(void)
{
	int retval;

	retval = bus_register(&i2c_bus_type);
	if (retval)
		return retval;
#ifdef CONFIG_I2C_COMPAT
	i2c_adapter_compat_class = class_compat_register("i2c-adapter");
	if (!i2c_adapter_compat_class) {
		retval = -ENOMEM;
		goto bus_err;
	}
#endif
	retval = i2c_add_driver(&dummy_driver);
	if (retval)
		goto class_err;
	return 0;

class_err:
#ifdef CONFIG_I2C_COMPAT
	class_compat_unregister(i2c_adapter_compat_class);
bus_err:
#endif
	bus_unregister(&i2c_bus_type);
	return retval;
}

postcore_initcall(i2c_init);
module_exit(i2c_exit);

可以看到i2c子系统加载的时候就已经注册了i2c_bus_type和driver

  1. bus_register(&i2c_bus_type)
  2. retval = i2c_add_driver(&dummy_driver);
    i2c_add_driver --> i2c_register_driver --> driver_register(&driver->driver);
    下面我们来看一下
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
	int res;

	/* Can't register until after driver model init */
	if (unlikely(WARN_ON(!i2c_bus_type.p)))
		return -EAGAIN;

	/* add the driver to the list of i2c drivers in the driver core */
	driver->driver.owner = owner;
	driver->driver.bus = &i2c_bus_type;

	/* When registration returns, the driver core
	 * will have called probe() for all matching-but-unbound devices.
	 */
	res = driver_register(&driver->driver);
	if (res)
		return res;

	/* Drivers should switch to dev_pm_ops instead. */
	if (driver->suspend)
		pr_warn("i2c-core: driver [%s] using legacy suspend method\n",
			driver->driver.name);
	if (driver->resume)
		pr_warn("i2c-core: driver [%s] using legacy resume method\n",
			driver->driver.name);

	pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);

	INIT_LIST_HEAD(&driver->clients);
	/* Walk the adapters that are already present */
	i2c_for_each_dev(driver, __process_new_driver);

	return 0;
}

可以看到注册的驱动是
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type;
res = driver_register(&driver->driver);
可以看到这里并没有实现driver->driver.probe函数,根据我们之前分析的总线模型可以知道,当匹配成功是,调用的i2c_bus_type->.probe

struct bus_type i2c_bus_type = {
	.name		= "i2c",
	.match		= i2c_device_match,
	.probe		= i2c_device_probe,
	.remove		= i2c_device_remove,
	.shutdown	= i2c_device_shutdown,
	.pm		= &i2c_device_pm_ops,
};

5. 自己实现adapter驱动程序

这里,我们主要分析驱动里的发送核心算法,至于注册中断,IO内存映射,设置寄存器不在讨论。

static int xxx_i2c_xfer(struct i2c_adapter *adpap, struct i2c_msg *msg,int num)

这个算法函数的作用就是将上层封装好的一些i2c_msg 进行解析,将数据写入寄存器,发送出去。
在设备驱动层,我们使用了类似i2c_smbus_write_byte 等函数,类似的函数有很多,它们的作用就是封装i2c_msg 结构(比如读和写的 msg 肯定不一样,读一个字节和读多个字节也不一样),然后调用 i2c_smbus_xfer_emulated->i2c_transfer,最终调用到我们的xxx_i2c_xfer函数进行传输。通过分析i2c_smbus_xfer_emulated函数,我们可以了解i2c_msg是如何封装的。下面,我们简单分析一下,知道最上层想干什么,我们才能知道实现哪些底层的功能不是。

struct i2c_msg {
	__u16 addr;		//从机地址
	__u16 flags;
	__u16 len;		// buf 里 有多少个字节
	__u8 *buf;		// 本 msg 含有的数据,可能是1个字节,可有可能是多个字节
};	

此函数,省略了很多内容,举例分析而已~,细节请看源码

static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
                                   unsigned short flags,
                                   char read_write, u8 command, int size,
                                   union i2c_smbus_data * data)
{	
	unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3];
	unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2];
	int num = read_write == I2C_SMBUS_READ?2:1;	// 写操作两个Msg 读操作一个msg 这和我们前面分析AT24c08是一致的
	struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 },
	                          { addr, flags | I2C_M_RD, 0, msgbuf1 }
	                        };
	msgbuf0[0] = command;	// 从机地址右移1位得到的,比如AT24C08  为 0x50
	switch(size) {
	case I2C_SMBUS_BYTE_DATA:	// 单字节读写
		if (read_write == I2C_SMBUS_READ)
			msg[1].len = 1;
			/*
			 * 读:	
			 *	msgbuf0[0] = command
			 *  msg[1].len = 1	,数据会读到 msgbuf0[1] 里
			 */
		else {
			msg[0].len = 2;
			msgbuf0[1] = data->byte;
			/*
			 * 写:
			 *	msgbuf0[0] = command
			 *	msgbuf0[1] = data->byte
			 */
		}
		break;
	}
	status = i2c_transfer(adapter, msg, num);
}

上面代码跟我们分析AT24C08裸机的时候如出一辙,对于一个写操作,我们只需要一个2440的写流程对应于这里的一个Msg,然而对于读操作,我们需要2440的两个流程,对应于这里的两个Msg。那么,我们底层控制器驱动需要做的工作就是,取出所有的Msg,将每一个Msg里buf里的数据发送出去,如果有下一个Msg,
那么再将下一个Msg里的buf发送完毕,最后发出P停止信号。还有一点,每发送一个Msg都要先发出S开始信号。

在看adapter程序之前,我们先来简单思考一下,发出S开始信号之后,可能有以下3中情况:

  1. 当前msg.len == 0 ,如果有ACK直接发出stop信号。这种情况出现在,控制器枚举设备的时候,因为它只发送S信号以及设备地址,不发送数据。
  2. 根据msg->flags为 I2C_M_RD 等信息判断读写,msg->flags 最低位为1表示读,最低位为0表示写。
#define I2C_M_TEN0x0010          /* this is a ten bit chip address */ 
#define I2C_M_RD0x0001              /* read data, from slave to master */ 
#define I2C_M_NOSTART0x4000      /* if I2C_FUNC_PROTOCOL_MANGLING */ 
#define I2C_M_REV_DIR_ADDR0x2000       /* if I2C_FUNC_PROTOCOL_MANGLING */ 
#define I2C_M_IGNORE_NAK0x1000       /* if I2C_FUNC_PROTOCOL_MANGLING */ 
#define I2C_M_NO_RD_ACK0x0800        /* if I2C_FUNC_PROTOCOL_MANGLING */ 
#define I2C_M_RECV_LEN0x0400         /* length will be first received byte */

2.1 如果是读
恢复 IIC 传输,开始读就行了,在下一个中断里将寄存器数据取出,如果是最后一个要读取的数据,不能发送ACK(禁用ACK)。
2.2 如果是写
将数据写入 IICDS 寄存器,恢复 IIC 传输。

附上韦东山老师的程序:

看程序之前,看一个大致的流程图,对于理解程序有帮助

在这里插入图片描述

#include <linux/kernel.h>
#include <linux/module.h>
 
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/of_i2c.h>
#include <linux/of_gpio.h>
#include <plat/gpio-cfg.h>
#include <mach/regs-gpio.h>
 
#include <asm/irq.h>
 
#include <plat/regs-iic.h>
#include <plat/iic.h>
 
//#define PRINTK printk
#define PRINTK(...) 
 
enum s3c24xx_i2c_state {
	STATE_IDLE,
	STATE_START,
	STATE_READ,
	STATE_WRITE,
	STATE_STOP
};
 
struct s3c2440_i2c_regs {
	unsigned int iiccon;
	unsigned int iicstat;
	unsigned int iicadd;
	unsigned int iicds;
	unsigned int iiclc;
};
 
struct s3c2440_i2c_xfer_data {
	struct i2c_msg *msgs;
	int msn_num;
	int cur_msg;
	int cur_ptr;
	int state;
	int err;
	wait_queue_head_t wait;
};
 
static struct s3c2440_i2c_xfer_data s3c2440_i2c_xfer_data;
 
 
static struct s3c2440_i2c_regs *s3c2440_i2c_regs;
 
 
static void s3c2440_i2c_start(void)
{
	s3c2440_i2c_xfer_data.state = STATE_START;
	
	if (s3c2440_i2c_xfer_data.msgs->flags & I2C_M_RD) /* 读 */
	{
		s3c2440_i2c_regs->iicds		 = s3c2440_i2c_xfer_data.msgs->addr << 1;
		s3c2440_i2c_regs->iicstat 	 = 0xb0;	// 主机接收,启动
	}
	else /* 写 */
	{
		s3c2440_i2c_regs->iicds		 = s3c2440_i2c_xfer_data.msgs->addr << 1;
		s3c2440_i2c_regs->iicstat    = 0xf0; 		// 主机发送,启动
	}
}
 
static void s3c2440_i2c_stop(int err)
{
	s3c2440_i2c_xfer_data.state = STATE_STOP;
	s3c2440_i2c_xfer_data.err   = err;
 
	PRINTK("STATE_STOP, err = %d\n", err);
 
 
	if (s3c2440_i2c_xfer_data.msgs->flags & I2C_M_RD) /* 读 */
	{
		// 下面两行恢复I2C操作,发出P信号
		s3c2440_i2c_regs->iicstat = 0x90;
		s3c2440_i2c_regs->iiccon  = 0xaf;
		ndelay(50);  // 等待一段时间以便P信号已经发出
	}
	else /* 写 */
	{
		// 下面两行用来恢复I2C操作,发出P信号
		s3c2440_i2c_regs->iicstat = 0xd0;
		s3c2440_i2c_regs->iiccon  = 0xaf;
		ndelay(50);  // 等待一段时间以便P信号已经发出
	}
 
	/* 唤醒 */
	wake_up(&s3c2440_i2c_xfer_data.wait);
	
}
 
static int s3c2440_i2c_xfer(struct i2c_adapter *adap,
			struct i2c_msg *msgs, int num)
{
	unsigned long timeout;
	
	/* 把num个msg的I2C数据发送出去/读进来 */
	s3c2440_i2c_xfer_data.msgs    = msgs;
	s3c2440_i2c_xfer_data.msn_num = num;
	s3c2440_i2c_xfer_data.cur_msg = 0;
	s3c2440_i2c_xfer_data.cur_ptr = 0;
	s3c2440_i2c_xfer_data.err     = -ENODEV;
 
	s3c2440_i2c_start();
 
	/* 休眠 */
	timeout = wait_event_timeout(s3c2440_i2c_xfer_data.wait, (s3c2440_i2c_xfer_data.state == STATE_STOP), HZ * 5);
	if (0 == timeout)
	{
		printk("s3c2440_i2c_xfer time out\n");
		return -ETIMEDOUT;
	}
	else
	{
		return s3c2440_i2c_xfer_data.err;
	}
}
 
static u32 s3c2440_i2c_func(struct i2c_adapter *adap)
{
	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
}
 
 
static const struct i2c_algorithm s3c2440_i2c_algo = {
//	.smbus_xfer     = ,
	.master_xfer	= s3c2440_i2c_xfer,
	.functionality	= s3c2440_i2c_func,
};
 
/* 1. 分配/设置i2c_adapter
 */
static struct i2c_adapter s3c2440_i2c_adapter = {
 .name			 = "s3c2440_100ask",
 .algo			 = &s3c2440_i2c_algo,
 .owner 		 = THIS_MODULE,
};
 
static int isLastMsg(void)
{
	return (s3c2440_i2c_xfer_data.cur_msg == s3c2440_i2c_xfer_data.msn_num - 1);
}
 
static int isEndData(void)
{
	return (s3c2440_i2c_xfer_data.cur_ptr >= s3c2440_i2c_xfer_data.msgs->len);
}
 
static int isLastData(void)
{
	return (s3c2440_i2c_xfer_data.cur_ptr == s3c2440_i2c_xfer_data.msgs->len - 1);
}
 
static irqreturn_t s3c2440_i2c_xfer_irq(int irq, void *dev_id)
{
	unsigned int iicSt;
    iicSt  = s3c2440_i2c_regs->iicstat; 
 
	if(iicSt & 0x8){ printk("Bus arbitration failed\n\r"); }
 
	switch (s3c2440_i2c_xfer_data.state)
	{
		case STATE_START : /* 发出S和设备地址后,产生中断 */
		{
			PRINTK("Start\n");
			/* 如果没有ACK, 返回错误 */
			if (iicSt & S3C2410_IICSTAT_LASTBIT)
			{
				s3c2440_i2c_stop(-ENODEV);
				break;
			}
 
			if (isLastMsg() && isEndData())
			{
				s3c2440_i2c_stop(0);
				break;
			}
 
			/* 进入下一个状态 */
			if (s3c2440_i2c_xfer_data.msgs->flags & I2C_M_RD) /* 读 */
			{
				s3c2440_i2c_xfer_data.state = STATE_READ;
				goto next_read;
			}
			else
			{
				s3c2440_i2c_xfer_data.state = STATE_WRITE;
			}	
		}
 
		case STATE_WRITE:
		{
			PRINTK("STATE_WRITE\n");
			/* 如果没有ACK, 返回错误 */
			if (iicSt & S3C2410_IICSTAT_LASTBIT)
			{
				s3c2440_i2c_stop(-ENODEV);
				break;
			}
 
			if (!isEndData())  /* 如果当前msg还有数据要发送 */
			{
				s3c2440_i2c_regs->iicds = s3c2440_i2c_xfer_data.msgs->buf[s3c2440_i2c_xfer_data.cur_ptr];
				s3c2440_i2c_xfer_data.cur_ptr++;
				
				// 将数据写入IICDS后,需要一段时间才能出现在SDA线上
				ndelay(50);	
				
				s3c2440_i2c_regs->iiccon = 0xaf;		// 恢复I2C传输
				break;				
			}
			else if (!isLastMsg())
			{
				/* 开始处理下一个消息 */
				s3c2440_i2c_xfer_data.msgs++;
				s3c2440_i2c_xfer_data.cur_msg++;
				s3c2440_i2c_xfer_data.cur_ptr = 0;
				s3c2440_i2c_xfer_data.state = STATE_START;
				/* 发出START信号和发出设备地址 */
				s3c2440_i2c_start();
				break;
			}
			else
			{
				/* 是最后一个消息的最后一个数据 */
				s3c2440_i2c_stop(0);
				break;				
			}
 
			break;
		}
 
		case STATE_READ:
		{
			PRINTK("STATE_READ\n");
			/* 读出数据 */
			s3c2440_i2c_xfer_data.msgs->buf[s3c2440_i2c_xfer_data.cur_ptr] = s3c2440_i2c_regs->iicds;			
			s3c2440_i2c_xfer_data.cur_ptr++;
next_read:
			if (!isEndData()) /* 如果数据没读写, 继续发起读操作 */
			{
				if (isLastData())  /* 如果即将读的数据是最后一个, 不发ack */
				{
					s3c2440_i2c_regs->iiccon = 0x2f;   // 恢复I2C传输,接收到下一数据时无ACK
				}
				else
				{
					s3c2440_i2c_regs->iiccon = 0xaf;   // 恢复I2C传输,接收到下一数据时发出ACK
				}				
				break;
			}
			else if (!isLastMsg())
			{
				/* 开始处理下一个消息 */
				s3c2440_i2c_xfer_data.msgs++;
				s3c2440_i2c_xfer_data.cur_msg++;
				s3c2440_i2c_xfer_data.cur_ptr = 0;
				s3c2440_i2c_xfer_data.state = STATE_START;
				/* 发出START信号和发出设备地址 */
				s3c2440_i2c_start();
				break;
			}
			else
			{
				/* 是最后一个消息的最后一个数据 */
				s3c2440_i2c_stop(0);
				break;								
			}
			break;
		}
 
		default: break;
	}
 
	/* 清中断 */
	s3c2440_i2c_regs->iiccon &= ~(S3C2410_IICCON_IRQPEND);
 
	return IRQ_HANDLED;	
}
 
 
/*
 * I2C初始化
 */
static void s3c2440_i2c_init(void)
{
	struct clk *clk;
 
	clk = clk_get(NULL, "i2c");
	clk_enable(clk);
	
    // 选择引脚功能:GPE15:IICSDA, GPE14:IICSCL
    s3c_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPE14_IICSCL);
	s3c_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPE15_IICSDA);
 
    /* bit[7] = 1, 使能ACK
     * bit[6] = 0, IICCLK = PCLK/16
     * bit[5] = 1, 使能中断
     * bit[3:0] = 0xf, Tx clock = IICCLK/16
     * PCLK = 50MHz, IICCLK = 3.125MHz, Tx Clock = 0.195MHz
     */
    s3c2440_i2c_regs->iiccon = (1<<7) | (0<<6) | (1<<5) | (0xf);  // 0xaf
 
    s3c2440_i2c_regs->iicadd  = 0x10;     // S3C24xx slave address = [7:1]
    s3c2440_i2c_regs->iicstat = 0x10;     // I2C串行输出使能(Rx/Tx)
}
 
static int i2c_bus_s3c2440_init(void)
{
	/* 2. 硬件相关的设置 */
	s3c2440_i2c_regs = ioremap(0x54000000, sizeof(struct s3c2440_i2c_regs));
	
	s3c2440_i2c_init();
 
	request_irq(IRQ_IIC, s3c2440_i2c_xfer_irq, 0, "s3c2440-i2c", NULL);
 
	init_waitqueue_head(&s3c2440_i2c_xfer_data.wait);
	
	/* 3. 注册i2c_adapter */
	i2c_add_adapter(&s3c2440_i2c_adapter);
	
	return 0;
}
 
static void i2c_bus_s3c2440_exit(void)
{
	i2c_del_adapter(&s3c2440_i2c_adapter);	
	free_irq(IRQ_IIC, NULL);
	iounmap(s3c2440_i2c_regs);
}
 
module_init(i2c_bus_s3c2440_init);
module_exit(i2c_bus_s3c2440_exit);
MODULE_LICENSE("GPL");

猜你喜欢

转载自blog.csdn.net/huangweiqing80/article/details/82838644
I2C
今日推荐