Linux下DM 644 xデバイス駆動I 2 Cのバス駆動(二)詳細
本文はすべて自分でソースコードの点滴の総括を読むので、振り替えは出典を明記してありがとうございます.
皆さんとの交流を歓迎します.qq:1037701636 email:[email protected],[email protected]
I 2バス駆動のもう一つのコンテンツはアダプタ対応のalgorithm構造体であり、この構造体の主な内容はI 2 Cコントローラデータの伝送を完了することであり、受信とハードウェアと密接に関連している.
static struct i2c_algorithm i2c_davinci_algo={//主に関連するI 2 C通信プロトコルおよびデータの転送および受信に関する.name="DAVINCI I 2 C algorithm",.id=I 2 C_ALGO_EXP,.master_xfer=i 2 c_davinci_xfer,.smbus_xfer=NULL,.slave_send=NULL,.slave_recv=NULL,.algo_control=NULL,.functionality=i 2 c_davinci_func,}主にmaster_xferポインタ関数i 2 c_davinci_xfer
入力された関数パラメータから見た主な内容i 2_megというi 2伝送情報構造体および処理が必要な情報の個数
主な内容は、I 2 C伝送時:スレーブのアドレス、情報フラグ、情報の長さ、および情報の内容を含む
i 2 c_でdavinci_xfer関数内でまずi 2 c_を呼び出すdavinci_wait_for_bbはI 2 C BUSに対して忙しい検査を行う.コアコンテンツは、カーネルを呼び出すタイミングモジュールであり、所定時間内にI 2 Cを忙しく検出する
while ((i2c_davinci_dev.regs->icstr) & DAVINCI_I2C_ICSTR_BB_MASK)
コアコンテンツ呼び出しi 2 c_davinci_xfer_msgは最終的にI 2 Cデータの処理を完了する
関連内容のコードは私の注釈を見ることができて、主に相応のI 2 Cのレジスタの値を設定することを通じて、I 2 Cに対する中断配置、制御配置、動作モードの配置を完成します.最終的にI 2 Cを起動し、プロセススリープ状態に入る.
データの転送と受信処理は割り込み中に行われ、割り込み関数の内容は以下の通りである.
I 2 Cの割り込みベクトルテーブル(stat=dev->regs->icivr)の内容を読み込む.対応するアクションの選択
ここではDAVINCIをご紹介しますI2C_ICIVR_INTCODE_TDRが中断した場合、データの転送が完了し、実際にはdev->regs->icdxr=*dev->buf++になるだけです.データを書き込めばI 2 Cでのデータ転送が完了します.
皆さんとの交流を歓迎します.qq:1037701636 email:[email protected],[email protected]
I 2バス駆動のもう一つのコンテンツはアダプタ対応のalgorithm構造体であり、この構造体の主な内容はI 2 Cコントローラデータの伝送を完了することであり、受信とハードウェアと密接に関連している.
static struct i2c_algorithm i2c_davinci_algo={//主に関連するI 2 C通信プロトコルおよびデータの転送および受信に関する.name="DAVINCI I 2 C algorithm",.id=I 2 C_ALGO_EXP,.master_xfer=i 2 c_davinci_xfer,.smbus_xfer=NULL,.slave_send=NULL,.slave_recv=NULL,.algo_control=NULL,.functionality=i 2 c_davinci_func,}主にmaster_xferポインタ関数i 2 c_davinci_xfer
i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) //num=1
{
int count;
int ret = 0;
char retries = 5;
DEB1("msgs: %d", num);
if (num < 1 || num > MAX_MESSAGES)
return -EINVAL;
/* Check for valid parameters in messages */
for (count = 0; count < num; count++)
if (msgs[count].buf == NULL) //
return -EINVAL;
if ((ret = i2c_davinci_wait_for_bb(1, adap)) < 0) // I2C
return ret;
for (count = 0; count < num; count++) {
DEB1("msg: %d, addr: 0x%04x, len: %d, flags: 0x%x",
count, msgs[count].addr, msgs[count].len,
msgs[count].flags); //addr=0x1a,len=2,flags=0
do {
ret = i2c_davinci_xfer_msg(adap, &msgs[count],
(count == (num - 1)));
if (ret < 0) {
struct i2c_davinci_device *dev = i2c_get_adapdata(adap);
DEB1("i2c: retry %d - icstr = 0x%x",
retries, dev->regs->icstr);
mdelay (1);
retries--;
} else
break;
} while (retries);
DEB1("ret: %d", ret);
if (ret != msgs[count].len)
break;
}
if (ret >= 0 && num >= 1)
ret = num;
DEB1("ret: %d", ret);
return ret;
}
入力された関数パラメータから見た主な内容i 2_megというi 2伝送情報構造体および処理が必要な情報の個数
struct i2c_msg {
__u16 addr; /* slave address */
__u16 flags;
#define I2C_M_TEN 0x10 /* we have a ten bit chip address */
#define I2C_M_RD 0x01
#define I2C_M_NOSTART 0x4000
#define I2C_M_REV_DIR_ADDR 0x2000
#define I2C_M_IGNORE_NAK 0x1000
#define I2C_M_NO_RD_ACK 0x0800
__u16 len; /* msg length */
__u8 *buf; /* pointer to msg data */
};
主な内容は、I 2 C伝送時:スレーブのアドレス、情報フラグ、情報の長さ、および情報の内容を含む
i 2 c_でdavinci_xfer関数内でまずi 2 c_を呼び出すdavinci_wait_for_bbはI 2 C BUSに対して忙しい検査を行う.コアコンテンツは、カーネルを呼び出すタイミングモジュールであり、所定時間内にI 2 Cを忙しく検出する
while ((i2c_davinci_dev.regs->icstr) & DAVINCI_I2C_ICSTR_BB_MASK)
コアコンテンツ呼び出しi 2 c_davinci_xfer_msgは最終的にI 2 Cデータの処理を完了する
static int
i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) //stop=0,
{
struct i2c_davinci_device *dev = i2c_get_adapdata(adap);
u8 zero_byte = 0;
u32 flag = 0, stat = 0;
int i;
DEB1("addr: 0x%04x, len: %d, flags: 0x%x, stop: %d",
msg->addr, msg->len, msg->flags, stop);
/* Introduce a 100musec delay. Required for Davinci EVM board only */
udelay(100); // 100ms
/* set the slave address */
dev->regs->icsar = msg->addr; //0x1A
/* Sigh, seems we can't do zero length transactions. Thus, we
* can't probe for devices w/o actually sending/receiving at least
* a single byte. So we'll set count to 1 for the zero length
* transaction case and hope we don't cause grief for some
* arbitrary device due to random byte write/read during
* probes.
*/
if (msg->len == 0) {
dev->buf = &zero_byte;
dev->buf_len = 1;
} else {
dev->buf = msg->buf;
dev->buf_len = msg->len; //msg->len=2
}
dev->regs->iccnt = dev->buf_len; // ICCNT
dev->cmd_complete = 0;
dev->cmd_err = 0;
/* Clear any pending interrupts by reading the IVR */
stat = dev->regs->icivr; // ,
/* Take I2C out of reset, configure it as master and set the start bit */
flag =
DAVINCI_I2C_ICMDR_IRS_MASK | DAVINCI_I2C_ICMDR_MST_MASK |
DAVINCI_I2C_ICMDR_STT_MASK; //I2C ,Master ,
/* if the slave address is ten bit address, enable XA bit */
if (msg->flags & I2C_M_TEN)
flag |= DAVINCI_I2C_ICMDR_XA_MASK; // 10
if (!(msg->flags & I2C_M_RD))
flag |= DAVINCI_I2C_ICMDR_TRX_MASK; //
if (stop)
flag |= DAVINCI_I2C_ICMDR_STP_MASK; //
/* Enable receive and transmit interrupts */
if (msg->flags & I2C_M_RD) //
dev->regs->icimr |= DAVINCI_I2C_ICIMR_ICRRDY_MASK;
else
dev->regs->icimr |= DAVINCI_I2C_ICIMR_ICXRDY_MASK; //
/* write the data into mode register */
dev->regs->icmdr = flag; // ,
/* wait for the transaction to complete */
wait_event_timeout (dev->cmd_wait, dev->cmd_complete, DAVINCI_I2C_TIMEOUT); // dev->cmd_wait
dev->buf_len = 0;
if (!dev->cmd_complete) { //
i2c_warn("i2c: cmd complete failed: complete = 0x%x, \
icstr = 0x%x
", dev->cmd_complete,
dev->regs->icstr);
/* Send the NACK to the slave */
dev->regs->icmdr |= DAVINCI_I2C_ICMDR_NACKMOD_MASK;
/* Disable I2C */
PINMUX1 &= (~(1 << 7));
/* Set the GPIO direction register */
gpio_set_direction (43, GIO_DIR_OUTPUT);
/* Send high and low on the SCL line */
for (i = 0; i < 10; i++) {
gpio_set_value (43, GIO_STATE_HIGH);
udelay(25);
gpio_set_value (43, GIO_STATE_LOW);
udelay(25);
}
/* Re-enable I2C */
PINMUX1 |= (1 << 7);
i2c_davinci_reset(dev);
dev->cmd_complete = 0;
return -ETIMEDOUT;
}
dev->cmd_complete = 0; //
/* no error */
if (!dev->cmd_err)
return msg->len;
/* We have an error */
if (dev->cmd_err & DAVINCI_I2C_ICSTR_NACK_MASK) {
if (msg->flags & I2C_M_IGNORE_NAK)
return msg->len;
if (stop)
dev->regs->icmdr |= DAVINCI_I2C_ICMDR_STP_MASK;
return -EREMOTEIO;
}
if (dev->cmd_err & DAVINCI_I2C_ICSTR_AL_MASK) {
i2c_davinci_reset(dev);
return -EIO;
}
return msg->len;
}
/*
* Prepare controller for a transaction and call i2c_davinci_xfer_msg
関連内容のコードは私の注釈を見ることができて、主に相応のI 2 Cのレジスタの値を設定することを通じて、I 2 Cに対する中断配置、制御配置、動作モードの配置を完成します.最終的にI 2 Cを起動し、プロセススリープ状態に入る.
データの転送と受信処理は割り込み中に行われ、割り込み関数の内容は以下の通りである.
static irqreturn_t
i2c_davinci_isr(int this_irq, void *dev_id, struct pt_regs *reg) //
{
struct i2c_davinci_device *dev = dev_id;
u32 stat;
DEB1("i2c_davinci_isr()");
while ((stat = dev->regs->icivr) != 0) { // , I2C ,
switch (stat) {
case DAVINCI_I2C_ICIVR_INTCODE_AL:
dev->cmd_err |= DAVINCI_I2C_ICSTR_AL_MASK;
i2c_warn("i2c: AL detected");
i2c_davinci_complete_cmd(dev);
break;
case DAVINCI_I2C_ICIVR_INTCODE_NACK:
dev->cmd_err |= DAVINCI_I2C_ICSTR_NACK_MASK;
//i2c_warn("i2c: NACK detected");
i2c_davinci_complete_cmd(dev);
break;
case DAVINCI_I2C_ICIVR_INTCODE_RAR:
// i2c_warn("i2c: RAR detected");
dev->regs->icstr |= DAVINCI_I2C_ICSTR_ARDY_MASK;
i2c_davinci_complete_cmd(dev);
break;
case DAVINCI_I2C_ICIVR_INTCODE_RDR:
if (dev->buf_len) {
*dev->buf++ = dev->regs->icdrr;
dev->buf_len--;
if (dev->buf_len) {
continue;
} else {
dev->regs->icimr &=
~DAVINCI_I2C_ICIMR_ICRRDY_MASK;
}
}
break;
case DAVINCI_I2C_ICIVR_INTCODE_TDR: //
if (dev->buf_len) {
dev->regs->icdxr = *dev->buf++; // ICDXR
dev->buf_len--;
if (dev->buf_len)
continue; // while
else {
dev->regs->icimr &=
~DAVINCI_I2C_ICIMR_ICXRDY_MASK; // ICXRDY
}
}
break;
case DAVINCI_I2C_ICIVR_INTCODE_SCD:
dev->regs->icstr |= DAVINCI_I2C_ICSTR_SCD_MASK;
i2c_davinci_complete_cmd(dev);
break;
case DAVINCI_I2C_ICIVR_INTCODE_AAS:
i2c_warn("i2c: AAS detected");
break;
default:
i2c_warn("i2c: unknown status: %d", stat);
break;
} /* switch */
} /* while */
return IRQ_HANDLED;
}
I 2 Cの割り込みベクトルテーブル(stat=dev->regs->icivr)の内容を読み込む.対応するアクションの選択
ここではDAVINCIをご紹介しますI2C_ICIVR_INTCODE_TDRが中断した場合、データの転送が完了し、実際にはdev->regs->icdxr=*dev->buf++になるだけです.データを書き込めばI 2 Cでのデータ転送が完了します.