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
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でのデータ転送が完了します.