📄 i2c-imx.c
字号:
}/*----------------------------------------------------------------------------- * void i2c_imx_isr (s16 irq, void * dev_id, struct pt_regs * reg) * This function deals with the interrupt for the I2C module. * * Parameters: irq the interrupt number * dev_id device id * reg processor register * Return: IRQ_HANDLED the own irq was handled *----------------------------------------------------------------------------*/static irqreturn_t i2c_imx_isr (s16 irq, void *dev_id, struct pt_regs * reg){ /* safe status register */ i2c_imx_i2sr = i2c_imx_reg->i2sr; /* if data transfer is complete set ok */ if (i2c_imx_i2sr & (u32)0x80) /* [I2SR:ICF] TX complete */ i2c_imx_irq_ok = 1; /* clear irq */ i2c_imx_reg->i2sr &= ~(u32)0x02; /* clear [I2SR:IIF] Interrupt */ return IRQ_HANDLED;}/*----------------------------------------------------------------------------- * int i2c_imx_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[ ], * SINT16 num) * This function is responsible for the transfer of the data through the * I2C bus * * Parameter: i2c_adap associated with the related hardware * msgs[ ] the body of the message to be send out * num number of message * Return: Success Number of message has been transferred * Failure -err (error code) *----------------------------------------------------------------------------*/static int i2c_imx_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num){ int i, count=0, err=0; unsigned long jif = i2c_imx_slp[msgs[0].addr-1].jif; int slp_time = i2c_imx_slp[msgs[0].addr-1].slp_time; int slp = slp_time * HZ / 1000 - (jiffies - jif); DECLARE_WAIT_QUEUE_HEAD(wait); /* scheduler: sleep while chip not ready */ if ((slp > 1) && (msgs[0].flags & I2C_M_RD)) { up(&i2c_adap->bus_lock); sleep_on_timeout(&wait, slp); down(&i2c_adap->bus_lock); } /* enable the i2c-bus, disable the I2C transmit ACK */ if(i2c_imx_bus_busy()) goto ERROR; i2c_imx_reg->i2cr |= (u32)0x80; i2c_imx_reg->i2cr |= (u32)0x08; for ( i = 0; i < num; i ++) { /* repeat start else start the bus-transfer */ if(i) { i2c_imx_reg->i2cr |= (u32)0x04; } else { if ((err = i2c_imx_start())) goto ERROR; } /* enable interrupt, enable master transmit */ i2c_imx_reg->i2cr |= (u32)0x40; i2c_imx_reg->i2cr |= (u32)0x10; /* write/read data */ if (!(msgs[i].flags & I2C_M_RD )) { if ((err = i2c_imx_write(i, &count, &msgs[i]))) goto ERROR; } else { if ((err = i2c_imx_read(i, &count, &msgs[i]))) goto ERROR; } } /*exit function and error handler */ i2c_imx_reg->i2cr &= ~((u32)0x20); /* bus stop */ i2c_imx_bus_release(); i2c_imx_reg->i2cr &= ~((u32)0x80); /* disable I2C */ if (!(msgs[0].flags & I2C_M_RD )) chip_slp(&msgs[0]); i2c_imx_slp[msgs[0].addr-1].jif = jiffies; return count; ERROR:#ifdef DEBUG printk("ERROR%d\n", err); if(err == 1) i2c_imx_errs_rxack++; if(err == 2) i2c_imx_errs_txcomplete++; if(err == 3) i2c_imx_errs_busbusy++; if(err == 4) i2c_imx_errs_busgrab++;#endif /* reset the i2c-bus (hopefully not needed */ i2c_imx_reg->i2cr = (u32)0x00; GIUS(0) |= 0x00018000; udelay(100); imx_gpio_mode(PA15_PF_I2C_SDA); mdelay(1); i2c_imx_slp[msgs[0].addr-1].jif = jiffies; return -err;}/*----------------------------------------------------------------------------- * int i2c_smbus_imx_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[ ], * SINT16 num) * This function is responsible for the transfer of the data through the * I2C-bus * * Parameter : i2c_adap the structure associated with the related hardware * msgs[ ] the body of the message to be send out * num number of message * Return : Success Number of message has been transferred * Failure -1 *----------------------------------------------------------------------------*/static int i2c_imx_smbus(struct i2c_adapter * adapter, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data){ char msgbuf0[34]; char msgbuf1[34]; int num = read_write == I2C_SMBUS_READ?2:1; struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, { addr, flags | I2C_M_RD, 10, msgbuf1 } }; int i; msgbuf0[0] = command; /* select the smbus-command and create the message */ switch(size) { case I2C_SMBUS_QUICK: msg[0].len = 0; msg[0].flags=flags|(read_write==I2C_SMBUS_READ)?I2C_M_RD:0; num = 1; break; case I2C_SMBUS_BYTE: if (read_write == I2C_SMBUS_READ) { msg[0].flags = I2C_M_RD | flags; num = 1; } break; case I2C_SMBUS_BYTE_DATA: if (read_write == I2C_SMBUS_READ) msg[1].len = 1; else { msg[0].len = 2; msgbuf0[1] = data->byte; } break; case I2C_SMBUS_WORD_DATA: if (read_write == I2C_SMBUS_READ) msg[1].len = 2; else { msg[0].len=3; msgbuf0[1] = data->word & 0xff; msgbuf0[2] = (data->word >> 8) & 0xff; } break; case I2C_SMBUS_PROC_CALL: num = 2; msg[0].len = 3; msg[1].len = 2; msgbuf0[1] = data->word & 0xff; msgbuf0[2] = (data->word >> 8) & 0xff; break; case I2C_SMBUS_BLOCK_DATA: if (read_write == I2C_SMBUS_READ) { return -1; } else { msg[0].len = data->block[0] + 2; if (msg[0].len > 34) { return -1; } for (i = 1; i <= msg[0].len; i++) msgbuf0[i] = data->block[i-1]; } break; default: return -1; } /* call the bus access routine */ if (i2c_imx_xfer(adapter, msg, num) < 0) return -1; /* copy the readed bytes to the data-field */ if (read_write == I2C_SMBUS_READ) switch(size) { case I2C_SMBUS_BYTE: data->byte = msgbuf0[0]; break; case I2C_SMBUS_BYTE_DATA: data->byte = msgbuf1[0]; break; case I2C_SMBUS_WORD_DATA: case I2C_SMBUS_PROC_CALL: data->word = msgbuf1[0] | (msgbuf1[1] << 8); break; } return 0;}/*----------------------------------------------------------------------------- * int i2c_imx_ioctl(struct i2c_adapter * adapter, unsigned int cmd, * unsigned long arg) * This function control the I2C module itself * * Parameters: Adapter the adapter associated to the I2C module * Cmd IO control command * Arg argument associated with the command * Return : Success 0 *----------------------------------------------------------------------------*/static int i2c_imx_ioctl(struct i2c_adapter * adapter, unsigned int cmd, unsigned long arg){ switch( cmd ) { case I2C_IO_CHANGE_FREQ: i2c_imx_reg->ifdr = (u32)(arg & 0x003f); break; case I2C_IO_GET_STATUS: arg = i2c_imx_reg->i2sr; break; } return 0;}/*----------------------------------------------------------------------------- * int __init i2c_imx_init(void) * initializes the I2C module in the DBIMX, and registers itself to the * Linux I2C system * * Parameters: None * Return: 0: indicates SUCCESS * -1: indicates FAILURE *----------------------------------------------------------------------------*/static int __init i2c_imx_init(void){ /* Pin Configuration for I2C: * 2 Pins are available for the I2C-Module. These Pins are multiplexed * with other functions on the device and must be configured for SPI- * Operation. * The Data Direction Bits in the GPIO Data Direction Register Port A * must be set for Output. * The Function Bits in the GPIO In Use Register Port A must be set * for Multiplexed. * Data Direction (DDIR): Output * GPIO-Function (GIUS): SPI-Operation * GPR, PUEN: for Interrupt operations */ imx_gpio_mode(PA15_PF_I2C_SDA); imx_gpio_mode(PA16_PF_I2C_SCL); /* install the I2C_IMX ISR to the Linux Kernel */ if(request_irq(I2C_INT, (void *)i2c_imx_isr, SA_INTERRUPT, "I2C_IMX", "i2c_bus")<0) return -1; /* Set clock Freq. */ i2c_imx_reg->ifdr = (u32)DEFAULT_FREQ; /* add the I2C adapter/algorithm driver to the linux kernel */ if (i2c_add_adapter(&i2c_imx_adapter)) return -1;#ifdef DEBUG printk("I2C-Adapter %d installed. use device with Minor %d\n", i2c_imx_adapter.nr, i2c_imx_adapter.nr);#endif /* define ms to sleep after read from chip*/ i2c_imx_slp[0x48-1].jif = jiffies; i2c_imx_slp[0x48-1].slp_time = 1; i2c_imx_slp[0x68-1].jif = jiffies; i2c_imx_slp[0x68-1].slp_time = 200; return 0;}/*----------------------------------------------------------------------------- * void __exit i2c_imx_cleanup(void) * This routine is called when the driver is unloaded * * Parameters: None * Return: None *----------------------------------------------------------------------------*/static void __exit i2c_imx_cleanup(void){#ifdef DEBUG printk("RX ACK ERRORs: %d\n", i2c_imx_errs_rxack); printk("TX COMPLETE ERRORs: %d\n", i2c_imx_errs_txcomplete); printk("BUS BUSY ERRORs: %d\n", i2c_imx_errs_busbusy); printk("BUS GRAB ERRORs: %d\n", i2c_imx_errs_busgrab);#endif /* unset IEN[I2CR:7] (I2C Disable) */ i2c_imx_reg->i2cr = (u32)0x00; /* Free IRQ */ free_irq (I2C_INT, "i2c_bus"); /* Delete Adapter from Kernel */ i2c_del_adapter(&i2c_imx_adapter); }/****************************************************************************** * Module Init/Exit ******************************************************************************/MODULE_AUTHOR("GSG China");MODULE_DESCRIPTION("I2C Adapter/Algorithm driver");MODULE_LICENSE("GPL");module_init(i2c_imx_init);module_exit(i2c_imx_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -