[Armadillo:03963] Re: armadillo-500 sysfs経由でI2Cドライバ制御

g-kihara email@hidden
2009年 1月 26日 (月) 15:32:42 JST


木原 です。
お世話になっています。

i2c_transfer()のソースを読みましたが、
弊社のセンサデバイスの仕様に従うと、
i2c通信で、任意のレジスタのデータ受信を行う場合には
ご教示いただいた処理で正常に受信が行われるように
思われます。

/* buf[0]の内容を表示 */
printk("RxData msgs[1].buf[0]=%x\n", buf[0]);

しかし、実際テストしてみると、buf[0]は0xffになっていました。

ハードウェア的要因を疑ってみたのですが、
以前、Linux標準関数を用いずにioremap(),write(),read()を
用いてi2c通信デバイスドライバを作成したことがあり、
このデバドラを用いて、任意のレジスタへの書き込みと読み込みが
できるか調べたのですが、両方とも正常に行われました。
テスト環境に問題はないようです。

i2c_probe()に成功はしているのですが、
本当に検出できているのか現在調査中です。
・・・なにが悪いのかさっぱり検討がつきません。

下記に現在用いているデバイスドライバを示しました。

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <linux/cdev.h>
#include <asm/arch/mx31_pins.h>
#include <asm/arch/gpio.h>
#include <asm/uaccess.h>

#define __KERNEL_SYSCALLS__

static char* msg = "module [ECS_iMX31.ko]";

#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/i2c.h>

#define DRIVER_NAME "i2ctest"
#define REVISION    "Rev.1 (2007/--/--)"
#define AUTHOR      "Atmark Techno, Inc."
#define DESCRIPTION "TI TLV320AIC Audio codec driver"

//#define DEBUG
#undef DEBUG
#if defined(DEBUG)
#define DEBUG_FUNC()         printk(DRIVER_NAME ": %s()\n", __FUNCTION__)
#define DEBUG_INFO(args...)  printk(DRIVER_NAME ": " args)
#else
#define DEBUG_FUNC()
#define DEBUG_INFO(args...)
#endif
#define PRINT_INFO(args...)  printk(KERN_INFO  DRIVER_NAME ": " args)
#define PRINT_DEBUG(args...) printk(KERN_DEBUG DRIVER_NAME ": " args)
#define PRINT_ERR(args...)   printk(KERN_ERR   DRIVER_NAME ": " args)

static int i2ctest_attach(struct i2c_adapter *adap);
static int i2ctest_detach(struct i2c_client *client);

static struct i2c_driver test_i2c_driver = {
 .driver = {
  .owner  = THIS_MODULE,
    .name = DRIVER_NAME,
 },
 .id  = 102,
 .attach_adapter = i2ctest_attach,
 .detach_client = i2ctest_detach,
};

static struct i2c_client test_i2c_client =
{
 .name = "TEST I2C dev",
 .driver = &test_i2c_driver,
};

static unsigned short normal_i2c[] =
{
 0x1c, // 0x38/2=0x1c
 I2C_CLIENT_END
};

I2C_CLIENT_INSMOD;

static DECLARE_MUTEX(mutex);

#define ID_I2CTEST 102

int
i2ctest_RxData(char *rxData, int length)
{
 int ret;
 u8 buf[2];
 struct i2c_msg msgs[2];

 buf[0] = 0;
 buf[1] = 0;

 msgs[0].addr = test_i2c_client.addr;
 msgs[0].len   = 1;
 msgs[0].buf   = rxData;
 msgs[0].flags = 0;

 msgs[1].addr = test_i2c_client.addr;
 msgs[1].len   = 1;
 msgs[1].buf   = buf;
 msgs[1].flags = I2C_M_RD ;

 ret = i2c_transfer(test_i2c_client.adapter, &msgs[0], 2);

 if(ret < 0){
  printk("i2c_transfer failed!!!\n");
 }

 printk("Ret = %d\n",ret);
 printk("RxData buf[0]=%x\n", buf[0]);
 printk("RxData msg[1].buf[0]=%x\n", msgs[1].buf[0]);

 return ret;
}

int
i2ctest_TxData(char *txData, int length)
{
 int ret;
 u8 buf[2];
 struct i2c_msg msgs[2];

 msgs[0].addr = test_i2c_client.addr;
 msgs[0].flags = 0;
 msgs[0].len   = length;
 msgs[0].buf   = txData;

 ret = i2c_transfer(test_i2c_client.adapter, msgs, 1);

 if(ret == 1){
  printk("TxData succedded!!!\n");
 }else if (ret >= 0){
  ret = -1;
  printk("TxData failed!!!\n");
 }

 return ret;
}


static int
i2ctest_detect_client(struct i2c_adapter *adapter, int address, int kind)
{
 int ret;

 test_i2c_client.adapter = adapter;
 test_i2c_client.addr = address;

 DEBUG_FUNC();

 printk("i2ctest_detect_client is called\n");

 ret = i2c_attach_client(&test_i2c_client);
 if (ret) {
  test_i2c_client.adapter = NULL;
  printk("i2c_detect_client() is failed!!!\n");
  return ret;
 }

 printk("i2c_detect_client() is succeeded!!!\n");

 return 0;
}

static int
i2ctest_attach(struct i2c_adapter *adap)
{
 int ret;
 char tx[2];
 char rx[2];

 rx[0]=0;
 rx[1]=0;

 DEBUG_FUNC();

 printk("i2ctest_attach is called\n");

 ret = i2c_probe(adap, &addr_data, &i2ctest_detect_client);
 printk("i2c_probe=%d\n", ret);

 // test
 tx[0] = 0xE1;
 tx[1] = 0x23;
 i2ctest_TxData(tx, 2);

 rx[0] = 0xE1;
 i2ctest_RxData(rx, 1);

 return ret;
}

static int
i2ctest_detach(struct i2c_client *client)
{
 int ret;

 DEBUG_FUNC();
 printk("kihara i2ctest_detach is called\n");

 ret = i2c_detach_client(client);

 if(ret)
  return ret;

 return 0;
}

static int __init
i2ctest_init(void)
{
 int ret;

 DEBUG_FUNC();
 printk("kihara i2ctest_init is called\n");

 ret = i2c_add_driver(&test_i2c_driver);
 if (ret) {
  PRINT_ERR("kihara Unable to register %s driver.\n", DRIVER_NAME);
  return ret;
 }

 PRINT_INFO(DESCRIPTION " [" REVISION "], (C) 2007 " AUTHOR "\n");

 return 0;
}

static void __exit
i2ctest_exit(void)
{
 DEBUG_FUNC();
 i2c_del_driver(&test_i2c_driver);
}

module_init(i2ctest_init);
module_exit(i2ctest_exit);

MODULE_AUTHOR(AUTHOR);
MODULE_DESCRIPTION(DESCRIPTION);
MODULE_LICENSE("GPL");


以上


----- Original Message ----- 
From: "日本電子システムテクノロジー/高木" <email@hidden>
To: "Armadillo series general discussion list" 
<email@hidden>
Sent: Friday, January 23, 2009 2:40 PM
Subject: [Armadillo:03950] Re: armadillo-500 sysfs経由でI2Cドライバ制御


> 高木です
> お世話になっています。
>
>
>> 木原です。
>> お世話になっています。
>>
>> 誤記がありました。申し訳ございません。
>> 弊社のデバイスについて、
>> 任意のアドレスのデータを読む場合、
>>
>> S| Slave | R/W=0 | ack | レジスタアドレス | ack | S | Slave | R/W=1 |
>> Data(n)| ack | Data(n+1) | ack | ・・・・・|ack| Stop |
>>
>> となっています。
>
> 了解しました。
> では、i2ctest_RxDataの処理を以下のようにするとどうでしょうか?
>
> struct i2c_msg msg[2];
> char buf[2];
> int ret;
>
> /* 受信データバッファクリア */
> buf[0] = 0;
> buf[1] = 0;
>
> /* レジスタアドレス転送用 */
> msg[0].addr  = test_i2c_client.addr;
> msg[0].len   = 1;
> msg[0].buf   = rxData;
> msg[0].flags = 0;
>
> /* データ受信用 */
> msg[1].addr  = test_i2c_client.addr;
> msg[1].len   = 1;
> msg[1].buf   = buf;
> msg[1].flags = I2C_M_RD;
>
> ret = i2c_transfer(c->adapter, msg, 2);
>
> /* buf[0]の内容を表示 */
> printk("RxData msgs[1].buf[0]=%x\n", buf[0]);
>
>
>> しかし、linux-2.6.13/Documentation/i2c/i2c-protocolの
>> i2c_transferに関する説明によると、
>>
>> They are just like the above transactions, but instead of a stop bit P
>> a start bit S is sent and the transaction continues. An example of
>> a byte read, followed by a byte write:
>>
>> S Addr Rd [A] [Data] NA S Addr Wr [A] Data [A] P     
>>
>> となっており、一番初めのスレーブアドレス発行後に"Read"、
>> 次のスレーブアドレス発行後には"Write"を出力しており、
>> 弊社の仕様と異なっています。
>> I2C_M_REV_DIR_ADDR フラグを使えば、 Read/Write フラグを切り替える
>> ことができるようですが・・・
>>
>>> レジスタアドレスの送信(指定)はどこでしているのでしょうか?
>>
>> 下記のi2ctest_attach() の コメント//送信
>> 以下のところでおこなっています。
>> (テストがうまくいったら、
>> この送受信テスト箇所は切り離す予定です。)
>>
>> 0xE1がレジスタアドレスで、0x23が書き込むデータです。
>
> 送信時はtx[0]にレジスタアドレスを指定するとレジスタアドレスが送られますが、 
> 
> 今のi2ctest_RxData関数ではrx[0]にレジスタアドレスを指定しても
> デバイスにレジスタアドレスは送られません。
>
> i2c_armadillo5x0_xferのコードを確認していただくと判りますが
> flag=I2C_M_RDでi2c_transferを呼び出すと
> スレーブアドレスを転送 → Read動作となりレジスタアドレスの送信はされません。 
> 
>
>
>> static int
>> i2ctest_attach(struct i2c_adapter *adap)
>> {
>> int ret;
>> char tx[2];
>> char rx[2];
>>
>> DEBUG_FUNC();
>>
>> printk("i2ctest_attach is called\n");
>>
>> ret = i2c_probe(adap, &addr_data, &i2ctest_detect_client);
>> printk("i2c_probe=%d\n", ret);
>>
>> // 送信テスト
>> tx[0] = 0xE1;  //レジスタアドレス
>> tx[1] = 0x23;    //書き込むデータ
>> i2ctest_TxData(tx, 2);
>>
>> // 受信テスト
>> rx[0] = 0xE1;  //レジスタアドレス
>> i2ctest_RxData(rx, 1);
>> printk("rx=%x\n", rx[0]);
>> printk("rx=%x\n", rx[1]);
>>
>> return ret;
>> }
>>
>>
>> 以上
>>
>
> _______________________________________________
> armadillo mailing list
> email@hidden
> http://lists.atmark-techno.com/cgi-bin/mailman/listinfo/armadillo 




armadillo メーリングリストの案内