Linux IICフレームワーク(上)


IICのフレームワーク構造はSPIと類似しており、バス駆動層(IICメインコントローラ駆動層)、コア層、スレーブデバイス駆動層を有している.このセクションでは、主にIICマスターコントローラの登録およびスレーブデバイスの登録手順について説明します.まず、IICメインコントローラの構造struct i 2 c_について説明するadapterと説明IICスレーブデバイスの構造struct i 2 c_client
struct i2c_adapterの定義は次のとおりです.
struct i2c_adapter {
	struct module *owner;  /*    */
	unsigned int id;        /*algorithm   */
	unsigned int class;	    /* classes to allow probing for */
	const struct i2c_algorithm *algo; /*      */
	void *algo_data;       /*algorithm   */

	/* --- administration stuff. */
	/*        */
	int (*client_register)(struct i2c_client *) __deprecated;
	/*        */
	int (*client_unregister)(struct i2c_client *) __deprecated;

	/* data fields that are valid for all devices	*/
	u8 level; 			/* nesting level for lockdep */
	struct mutex bus_lock;
	struct mutex clist_lock;

	int timeout;			/* in jiffies */
	int retries;           /*    */
	struct device dev;		

	int nr;                     /*       */
	struct list_head clients;	/*           */
	char name[48];              /*    */
	struct completion dev_released;/*        */
};

Algoでは、プライマリコントローラのデータ伝送方式が定義されており、clientはチェーンヘッダであり、複数のスレーブデバイスがバスに接続されている可能性があるため、clientはコントローラの下のスレーブデバイスをリンクするために使用される
 
SPIコントローラと同様にIICコントローラもプラットフォームリソースなのでplatformでカーネルに登録
static int __init i2c_adap_s3c_init(void)
{
	int ret;

	ret = platform_driver_register(&s3c2410_i2c_driver);
	if (ret == 0) {
		ret = platform_driver_register(&s3c2440_i2c_driver);
		if (ret)
			platform_driver_unregister(&s3c2410_i2c_driver);
	}

	return ret;
}

s3c2410_i2c_driverとs 3 c 2440_i2c_driverの定義はnameフィールドが異なる以外は同じです
static struct platform_driver s3c2410_i2c_driver = {
	.probe		= s3c24xx_i2c_probe,
	.remove		= s3c24xx_i2c_remove,
	.suspend_late	= s3c24xx_i2c_suspend_late,
	.resume		= s3c24xx_i2c_resume,
	.driver		= {
		.owner	= THIS_MODULE,
		.name	= "s3c2410-i2c",
	},
};

static struct platform_driver s3c2440_i2c_driver = {
	.probe		= s3c24xx_i2c_probe,
	.remove		= s3c24xx_i2c_remove,
	.suspend_late	= s3c24xx_i2c_suspend_late,
	.resume		= s3c24xx_i2c_resume,
	.driver		= {
		.owner	= THIS_MODULE,
		.name	= "s3c2440-i2c",
	},
};

とplatform_デバイスマッチングに成功すると、s 3 c 24 xx_が呼び出されます.i2c_probe()関数
static int s3c24xx_i2c_probe(struct platform_device *pdev)
{
	struct s3c24xx_i2c *i2c;
	struct s3c2410_platform_i2c *pdata;
	struct resource *res;
	int ret;

	pdata = pdev->dev.platform_data;//    IIC  
	if (!pdata) {
		dev_err(&pdev->dev, "no platform data
"); return -EINVAL; } /* struct s3c24xx_i2c*/ i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL); if (!i2c) { dev_err(&pdev->dev, "no memory for state
"); return -ENOMEM; } /* IIC */ strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name)); i2c->adap.owner = THIS_MODULE; i2c->adap.algo = &s3c24xx_i2c_algorithm; i2c->adap.retries = 2; i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; i2c->tx_setup = 50; spin_lock_init(&i2c->lock); init_waitqueue_head(&i2c->wait);// /* find the clock and enable it */ i2c->dev = &pdev->dev; i2c->clk = clk_get(&pdev->dev, "i2c"); if (IS_ERR(i2c->clk)) { dev_err(&pdev->dev, "cannot get clock
"); ret = -ENOENT; goto err_noclk; } dev_dbg(&pdev->dev, "clock source %p
", i2c->clk); clk_enable(i2c->clk); /* map the registers */ /* IIC */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(&pdev->dev, "cannot find IO resource
"); ret = -ENOENT; goto err_clk; } /* IIC */ i2c->ioarea = request_mem_region(res->start, (res->end-res->start)+1, pdev->name); if (i2c->ioarea == NULL) { dev_err(&pdev->dev, "cannot request IO
"); ret = -ENXIO; goto err_clk; } /* IIC */ i2c->regs = ioremap(res->start, (res->end-res->start)+1); if (i2c->regs == NULL) { dev_err(&pdev->dev, "cannot map IO
"); ret = -ENXIO; goto err_ioarea; } dev_dbg(&pdev->dev, "registers %p (%p, %p)
", i2c->regs, i2c->ioarea, res); /* setup info block for the i2c core */ i2c->adap.algo_data = i2c; i2c->adap.dev.parent = &pdev->dev; /* initialise the i2c controller */ /* s3c24xx IIC */ ret = s3c24xx_i2c_init(i2c); if (ret != 0) goto err_iomap; /* find the IRQ for this unit (note, this relies on the init call to * ensure no current IRQs pending */ i2c->irq = ret = platform_get_irq(pdev, 0); if (ret <= 0) { dev_err(&pdev->dev, "cannot find IRQ
"); goto err_iomap; } /* IIC */ ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED, dev_name(&pdev->dev), i2c); if (ret != 0) { dev_err(&pdev->dev, "cannot claim IRQ %d
", i2c->irq); goto err_iomap; } ret = s3c24xx_i2c_register_cpufreq(i2c); if (ret < 0) { dev_err(&pdev->dev, "failed to register cpufreq notifier
"); goto err_irq; } /* 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 = pdata->bus_num; /* IIC IIC */ ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) { dev_err(&pdev->dev, "failed to add bus to i2c core
"); goto err_cpufreq; } platform_set_drvdata(pdev, i2c); dev_info(&pdev->dev, "%s: S3C I2C adapter
", dev_name(&i2c->adap.dev)); return 0; err_cpufreq: s3c24xx_i2c_deregister_cpufreq(i2c); err_irq: free_irq(i2c->irq, i2c); err_iomap: iounmap(i2c->regs); err_ioarea: release_resource(i2c->ioarea); kfree(i2c->ioarea); err_clk: clk_disable(i2c->clk); clk_put(i2c->clk); err_noclk: kfree(i2c); return ret; }

i2c_add_numbered_adapter()はi 2 c_を呼び出すregister_adapter()は実際の登録作業を完了する
static int i2c_register_adapter(struct i2c_adapter *adap)
{
	int res = 0, dummy;

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

	mutex_init(&adap->bus_lock);
	mutex_init(&adap->clist_lock);
	INIT_LIST_HEAD(&adap->clients);//             

	mutex_lock(&core_lock);

	/* Add the adapter to the driver core.
	 * If the parent pointer is not set up,
	 * we add this adapter to the host bus.
	 */
	if (adap->dev.parent == NULL) {
		adap->dev.parent = &platform_bus;
		pr_debug("I2C adapter driver [%s] forgot to specify "
			 "physical device
", adap->name); } /* Set default timeout to 1 second if not already set */ if (adap->timeout == 0) adap->timeout = HZ; dev_set_name(&adap->dev, "i2c-%d", adap->nr); adap->dev.release = &i2c_adapter_dev_release; adap->dev.class = &i2c_adapter_class;// i2c_adaoter_class res = device_register(&adap->dev);// if (res) goto out_list; dev_dbg(&adap->dev, "adapter [%s] registered
", adap->name); /* create pre-declared device nodes for new-style drivers */ /* */ if (adap->nr < __i2c_first_dynamic_bus_num) i2c_scan_static_board_info(adap); /* Notify drivers */ dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap, i2c_do_add_adapter); out_unlock: mutex_unlock(&core_lock); return res; out_list: idr_remove(&i2c_adapter_idr, adap->nr); goto out_unlock; }

 
static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
{
	struct i2c_devinfo	*devinfo;

	mutex_lock(&__i2c_board_lock);
	/*  IIC      */
	list_for_each_entry(devinfo, &__i2c_board_list, list) {
		/*             IIC            */
		if (devinfo->busnum == adapter->nr
				&& !i2c_new_device(adapter,
						&devinfo->board_info))
			dev_err(&adapter->dev,
				"Can't create device at 0x%02x
", devinfo->board_info.addr); } mutex_unlock(&__i2c_board_lock); }

 
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;//        IIC   

	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));

	/* a new style driver may be bound to this device when we
	 * return from this function, or any later moment (e.g. maybe
	 * hotplugging will load the driver module).  and the device
	 * refcount model is the standard driver model one.
	 */
	status = i2c_attach_client(client);
	if (status < 0) {
		kfree(client);
		client = NULL;
	}
	return client;
}

 
int i2c_attach_client(struct i2c_client *client)
{
	struct i2c_adapter *adapter = client->adapter;
	int res;

	/* Check for address business */
	/*                      */
	res = i2c_check_addr(adapter, client->addr);
	if (res)
		return res;

	client->dev.parent = &client->adapter->dev;
	client->dev.bus = &i2c_bus_type;//            

	if (client->driver)
		client->dev.driver = &client->driver->driver;

	if (client->driver && !is_newstyle_driver(client->driver)) {
		client->dev.release = i2c_client_release;
		dev_set_uevent_suppress(&client->dev, 1);
	} else
		client->dev.release = i2c_client_dev_release;

	dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adapter),
		     client->addr);//          +  
	res = device_register(&client->dev);//    
	if (res)
		goto out_err;

	mutex_lock(&adapter->clist_lock);
	list_add_tail(&client->list, &adapter->clients);//      IIC   
	mutex_unlock(&adapter->clist_lock);

	dev_dbg(&adapter->dev, "client [%s] registered with bus id %s
", client->name, dev_name(&client->dev)); /* adapter , ,s3c24xx */ if (adapter->client_register) { if (adapter->client_register(client)) { dev_dbg(&adapter->dev, "client_register " "failed for client [%s] at 0x%02x
", client->name, client->addr); } } return 0; out_err: dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x " "(%d)
", client->name, client->addr, res); return res; }