blackfin i2cudong驅動以及採集驅動分析(1)

來源:互聯網
上載者:User

快樂蝦

http://blog.csdn.net/lights_joy/

lights@hb165.com

 

 

 

 

 

 

 

 

 

本文適用於

ADSP-BF561

uclinux-2008r1.5-rc3 (smp patch)

Visual DSP++ 5.0(update 5)

BF561-EZKIT

 

歡迎轉載,但請保留作者資訊

1       整體結構
在uclinux核心的documentation/i2c目錄下,提供了i2c驅動的簡單說明,其summary檔案這樣解釋i2c驅動的幾個組成部分:

When we talk about I2C, we use the following terms:

  Bus    -> Algorithm

            Adapter

  Device -> Driver

            Client

 

An Algorithm driver contains general code that can be used for a whole class

of I2C adapters. Each specific adapter driver depends on one algorithm

driver.

 

A Driver driver (yes, this sounds ridiculous, sorry) contains the general

code to access some type of device. Each detected device gets its own

data in the Client structure. Usually, Driver and Client are more closely

integrated than Algorithm and Adapter.

 

For a given configuration, you will need a driver for your I2C bus (usually

a separate Adapter and Algorithm driver), and drivers for your I2C devices

(usually one driver for each device). There are no I2C device drivers

in this package. See the lm_sensors project http://www.lm-sensors.nu

for device drivers.

 

At this time, Linux only operates I2C (or SMBus) in master mode; you can't

use these APIs to make a Linux system behave as a slave/device, either to

speak a custom protocol or to emulate some other device.

從這段話讓人留下幾個印象:

l         在i2c匯流排上,可以實現i2c或者SMBus協議,對於每一種協議都用一種algorithm進行表示。

l         每一種algorithm都必須和一個adapter相關連,這個adapter應該就是指CPU實現I2C匯流排的方式,比如對於561,它的實現方式是通過GPIO來類比的,因而就用一個adapter來表示它。

l         對於掛在i2c匯流排上的裝置,每一個裝置都必須有一個驅動,此裝置稱之為Client。

l         由於這些匯流排上的裝置操作相似,其驅動也類似,因此用一個模組來對這些驅動進行統一管理,這個模組可以看成是這些I2C裝置驅動程式的驅動,也就是文中的Driver driver。

也不知道猜得準不準,看代碼,驗證一下。

2       adapter驅動
在drivers/i2c/buses目錄下,有一個叫i2c-gpio.c的檔案,猜測這個檔案就是561平台上的adapter驅動,看看它的初始化函數:

static int __init i2c_gpio_init(void)

{

     int ret;

 

     ret = platform_driver_probe(&i2c_gpio_driver, i2c_gpio_probe);

     if (ret)

         printk(KERN_ERR "i2c-gpio: probe failed: %d/n", ret);

 

     return ret;

}

怎麼這麼熟悉啊!

原來它使用了platform driver和platform device結合的驅動結構,這裡i2c_gpio_driver定義為:

static struct platform_driver i2c_gpio_driver = {

     .driver       = {

         .name    = "i2c-gpio",

         .owner   = THIS_MODULE,

     },

     .remove       = __exit_p(i2c_gpio_remove),

};

 

趕緊地到arch/mach-bf561/boards/ezkit.c中看看它對應的資源定義:

static struct i2c_gpio_platform_data i2c_gpio_data = {

     .sda_pin      = CONFIG_SDA_PIN,

     .scl_pin      = CONFIG_SCL_PIN,

     .sda_is_open_drain = 0,

     .scl_is_open_drain = 0,

     .udelay            = 40,

};

 

static struct platform_device i2c_gpio_device = {

     .name         = "i2c-gpio",

     .id      = 0,

     .dev     = {

         .platform_data     = &i2c_gpio_data,

     },

};

在platform_driver_probe的運作下,此驅動的初始化函數將轉向執行i2c_gpio_probe:

static int __init i2c_gpio_probe(struct platform_device *pdev)

{

     struct i2c_gpio_platform_data *pdata;

     struct i2c_algo_bit_data *bit_data;

     struct i2c_adapter *adap;

     int ret;

 

     pdata = pdev->dev.platform_data;

     if (!pdata)

         return -ENXIO;

 

     ret = -ENOMEM;

     adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);

     if (!adap)

         goto err_alloc_adap;

     bit_data = kzalloc(sizeof(struct i2c_algo_bit_data), GFP_KERNEL);

     if (!bit_data)

         goto err_alloc_bit_data;

 

     ret = gpio_request(pdata->sda_pin, "sda");

     if (ret)

         goto err_request_sda;

     ret = gpio_request(pdata->scl_pin, "scl");

     if (ret)

         goto err_request_scl;

……………..

 

     adap->owner = THIS_MODULE;

     snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id);

     adap->algo_data = bit_data;

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

 

     ret = i2c_bit_add_bus(adap);

     if (ret)

         goto err_add_bus;

………………….

}

這個函數主要做了三件事,首先構造了一個i2c_adapter結構體,然後申請gpio資源,最後進行了一個關鍵調用i2c_bit_add_bus,這是一個在drivers/i2c/algos/i2c-algo-bit.c中定義的函數,猜測就是通過這樣的一個調用,將adapter和algorithm結合起來!

3       algorithm驅動
i2c中的algorithm實現都放在drivers/i2c/algos目錄下,在此採用i2c-algo-bit.c檔案。前面說道在adapter初始化時會調用i2c_bit_add_bus,姑且先看看這個函數:

 

int i2c_bit_add_bus(struct i2c_adapter *adap)

{

     int err;

 

     err = i2c_bit_prepare_bus(adap);

     if (err)

         return err;

 

     return i2c_add_adapter(adap);

}

第一個函數調用i2c_bit_prepare_bus由alorithm實現:

static const struct i2c_algorithm i2c_bit_algo = {

     .master_xfer  = bit_xfer,

     .functionality     = bit_func,

};

 

/*

 * registering functions to load algorithms at runtime

 */

static int i2c_bit_prepare_bus(struct i2c_adapter *adap)

{

     struct i2c_algo_bit_data *bit_adap = adap->algo_data;

 

     if (bit_test) {

         int ret = test_bus(bit_adap, adap->name);

         if (ret<0)

              return -ENODEV;

     }

 

     /* register new adapter to i2c module... */

     adap->algo = &i2c_bit_algo;

 

     adap->timeout = 100;   /* default values, should   */

     adap->retries = 3; /* be replaced by defines   */

 

     return 0;

}

也就是說,在這裡algorithm通過i2c_bit_algo這一結構體給adapter提供了操作介面。在配置完介面後,緊接著調用i2c_add_adapter函數,由此進入到Driver driver的勢力範圍。

4       Driver driver
Driver driver的實現由drivers/i2c/i2c-core.c完成,它需要管理i2c的多種資源。

4.1    adapter註冊
當adapter初始化的時候,它需要調用i2c_add_adapter函數註冊自己:

/**

 * i2c_add_adapter - declare i2c adapter, use dynamic bus number

 * @adapter: the adapter to add

 *

 * This routine is used to declare an I2C adapter when its bus number

 * doesn't matter.  Examples: for I2C adapters dynamically added by

 * USB links or PCI plugin cards.

 *

 * When this returns zero, a new bus number was allocated and stored

 * in adap->nr, and the specified adapter became available for clients.

 * Otherwise, a negative errno value is returned.

 */

int i2c_add_adapter(struct i2c_adapter *adapter)

{

     int  id, res = 0;

 

retry:

     if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)

         return -ENOMEM;

 

     mutex_lock(&core_lists);

     /* "above" here means "above or equal to", sigh */

     res = idr_get_new_above(&i2c_adapter_idr, adapter,

                   __i2c_first_dynamic_bus_num, &id);

     mutex_unlock(&core_lists);

 

     if (res < 0) {

         if (res == -EAGAIN)

              goto retry;

         return res;

     }

 

     adapter->nr = id;

     return i2c_register_adapter(adapter);

}

很簡單地分配一個ID,然後調用i2c_register_adapter進行實際的註冊:

static int i2c_register_adapter(struct i2c_adapter *adap)

{

     int res = 0;

     struct list_head   *item;

     struct i2c_driver  *driver;

……………..

     list_add_tail(&adap->list, &adapters);

……………..

 

     /* let legacy drivers scan this bus for matching devices */

     list_for_each(item,&drivers) {

         driver = list_entry(item, struct i2c_driver, list);

         if (driver->attach_adapter)

              /* We ignore the return code; if it fails, too bad */

              driver->attach_adapter(adap);

     }

………………….

}

兩件主要的事情,先將傳入的adapter指標放到adapters這一全域鏈表中,然後針對所有已經註冊的i2c_driver調用其attach_adapter回呼函數。

4.2    i2c_driver註冊
對於每一個串連在I2C匯流排上的裝置,都必須提供一個i2c_driver並調用i2c_add_driver進行註冊:

static inline int i2c_add_driver(struct i2c_driver *driver)

{

     return i2c_register_driver(THIS_MODULE, driver);

}

很簡單,直接調用i2c_register_driver:

/*

 * An i2c_driver is used with one or more i2c_client (device) nodes to access

 * i2c slave chips, on a bus instance associated with some i2c_adapter.  There

 * are two models for binding the driver to its device:  "new style" drivers

 * follow the standard Linux driver model and just respond to probe() calls

 * issued if the driver core sees they match(); "legacy" drivers create device

 * nodes themselves.

 */

 

int i2c_register_driver(struct module *owner, struct i2c_driver *driver)

{

     int res;

………………

     list_add_tail(&driver->list,&drivers);

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

 

     /* legacy drivers scan i2c busses directly */

     if (driver->attach_adapter) {

         struct i2c_adapter *adapter;

 

         list_for_each_entry(adapter, &adapters, list) {

              driver->attach_adapter(adapter);

         }

     }

…………………

}

兩件事,先將i2c_driver放到drivers的鏈表中,然後調用i2c_driver中的attach_adapter回呼函數。

 

 

5       client driver
5.1    client driver註冊
對於I2C匯流排上的每一個裝置,都必須提供一個單獨的驅動,比如blackfin_cam.c中的驅動:

static __init int bcap_init(void)

{

     int err;

…………..

 

     err = i2c_add_driver(&sensor_driver);

     if (err) {

         printk(KERN_WARNING "%s: could not add i2c driver: %i/n",

                sensor_name, err);

         return err;

     }

……………..

}

這裡sensor_driver定義為:

static struct i2c_driver sensor_driver = {

     .driver = {

            .name = SENSOR_NAME,

            },

     .id = I2C_DRIVERID_BCAP,

     .attach_adapter = sensor_attach_adapter,

     .detach_client = sensor_detach_client,

     .command = sensor_command,

};

也就是說,每一個i2c裝置都必須提供一個i2c_driver,然後向I2C管理模組註冊。

本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/lights_joy/archive/2009/07/03/4320575.aspx

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.