/*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ typedef struct i2c_int_status { unsigned char *dp; unsigned int length; unsigned int is_write; unsigned int status; /* TRUE = ok, FALSE = error */ } I2C_STATUS_t; extern int i2c_debug; #define DEB_INFO(...) if(i2c_debug) printk(KERN_INFO __VA_ARGS__) #define DEB_ERR(...) printk(KERN_ERR __VA_ARGS__) /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static unsigned int i2c_write_wait(void); static unsigned int i2c_data_wait(void); /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void i2c_wait_msec(unsigned int msec) { DEB_INFO("\n[i2c] wait (%u ms)\n", msec); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout((HZ / 1000) * msec); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static unsigned int i2c_data_wait(void) { unsigned int reg_value; signed int start = jiffies; while((jiffies - start) < 2) { reg_value = I2C_DATA_READ; DEB_INFO("\n[i2c_data_wait] reg_value=0x%x\n", reg_value); if(reg_value & I2C_DATA_READ_ERROR) { /*--- Error Flag noch gesetzt ---*/ return I2C_DATA_READ_ERROR | 0x30; } if(reg_value & I2C_DATA_READ_IRQ) { return reg_value; } /*--- DEB_INFO("\n[i2c_data_wait] wait (10 ms)\n"); ---*/ /*--- set_current_state(TASK_INTERRUPTIBLE); ---*/ /*--- schedule_timeout(HZ / 100); ---*/ /*--- schedule(); ---*/ } return I2C_DATA_READ_ERROR | 0x40; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static unsigned int i2c_write_wait(void) { unsigned short reg_value; signed int start = jiffies; while((jiffies - start) < 2) { reg_value = I2C_DATA_READ; DEB_INFO("\n[i2c_write_wait] reg_value=0x%x\n", reg_value); /*----------------------------------------------------------------------------------*\ * in den Texas Sourcen des avalanche_i2c wird das ERROR bit nicht getestet, * wenn WRIE_ALLOWD ist \*----------------------------------------------------------------------------------*/ if((reg_value & I2C_DATA_READ_WRITE_NOT_ALLOWED) == 0) { DEB_INFO("[i2c]: i2c_write_wait: reg_value=0x%x\n", reg_value); return reg_value; } if(reg_value & I2C_DATA_READ_ERROR) { /*--- Error Flag noch gesetzt ---*/ DEB_INFO("[i2c]: i2c_write_wait: error 0x10\n"); return I2C_DATA_READ_ERROR | 0x10; } /*--- DEB_INFO("\n[i2c_write_wait] wait (10 ms)\n"); ---*/ /*--- set_current_state(TASK_INTERRUPTIBLE); ---*/ /*--- schedule_timeout(HZ / 100); ---*/ /*--- schedule(); ---*/ } DEB_INFO("[i2c]: i2c_write_wait: error: (0x20)\n"); return I2C_DATA_READ_ERROR | 0x20; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ unsigned int i2c_hw_set_speed(unsigned int i2c_frequency) { unsigned int divisor; if((i2c_frequency > I2C_CLOCK_DIV_MAX_CLOCK) || (i2c_frequency == 0)) i2c_frequency = I2C_CLOCK_DIV_MAX_CLOCK; divisor = avm_get_clock(avm_clock_id_system) / i2c_frequency; /* Set the divisor of VBUS to the maximum speed allowed*/ I2C_CLOCK_DIV = divisor; I2C_CONFIG = I2C_CONFIG_SPIKE_MASK(0) | I2C_CONFIG_IRQ_MASK; /*--- DEB_INFO("[i2c]: i2c_hw_init done (frequenz=%u divisor=0x%x, config=0x%x)\n", ---*/ /*--- avalanche_get_vbus_freq(), divisor, ---*/ /*--- I2C_CONFIG_SPIKE_MASK(0) | I2C_CONFIG_IRQ_MASK); ---*/ return 0; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ unsigned int i2c_hw_init(unsigned int i2c_frequency) { avm_reset_device(IIC_RESET_BIT, 1); avm_gpio_ctrl(GPIO_BIT_FSER_D, FUNCTION_PIN, GPIO_OUTPUT_PIN); avm_gpio_ctrl(GPIO_BIT_FSER_CLK, FUNCTION_PIN, GPIO_OUTPUT_PIN); /*--- DEB_INFO("[i2c]: i2c_hw_init(%u) : RESET=0x%x CLK_PDCR=0x%x GPIO_EN=0x%x (Mask 0x%x)\n", ---*/ /*--- i2c_frequency, RESET->Reg, CLK_PDCR, GPIO_EN, (1 << 4) | (1 << 5)); ---*/ i2c_wait_msec(10); /* In theory the write allowed bit is cleared if the bus master can * twidle the data line, if not we have a bus fault */ if((i2c_write_wait() & I2C_DATA_READ_ERROR) == 0) { return i2c_hw_set_speed(i2c_frequency); } DEB_ERR("[i2c]: i2c_hw_init failed\n"); return 1; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void i2c_hw_deinit(void) { avm_put_device_into_reset(IIC_RESET_BIT); /*--- CLK_PDCR |= (PDCR_BIT_IIC | PDCR_BIT_UART1); ---*/ } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ unsigned int i2c_block_read(struct _i2c_cmd *Cmd) { unsigned int addr_len; unsigned int ret; unsigned char pRegAddr[4]; DEB_INFO("[i2c]: i2c_block_read \n"); switch(Cmd->device_type) { case avm_i2c_type_16_bit: addr_len = 2; pRegAddr[0] = (Cmd->register_address >> 0) & 0xFF; pRegAddr[1] = (Cmd->register_address >> 8) & 0xFF; break; case avm_i2c_type_8_bit: pRegAddr[0] = (Cmd->register_address >> 0) & 0xFF; addr_len = 1; break; default: DEB_INFO("[i2c]: i2c_block_read invallid type %u\n", Cmd->device_type); return -1; } ret = i2c_hw_write(Cmd->device_address, pRegAddr, addr_len); if(ret != 0) { DEB_ERR("[i2c]: i2c_block_read: addr write failed \n"); return ret; } /*--- i2c_wait_msec(1); ---*/ ret = i2c_hw_read(Cmd->device_address, Cmd->Buffer, Cmd->data_length); if(ret != 0) { DEB_ERR("[i2c]: i2c_block_read: failed\n"); } return ret; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ unsigned int i2c_block_write(struct _i2c_cmd *Cmd) { unsigned write_len = 0; unsigned int ret; unsigned char pRegAddr[4]; unsigned char WriteBuffer[sizeof(Cmd->Buffer) + 2]; DEB_INFO("[i2c]: i2c_block_write \n"); switch(Cmd->device_type) { case avm_i2c_type_16_bit: case avm_i2c_type_12_bit: pRegAddr[0] = (Cmd->register_address >> 0) & 0xFF; pRegAddr[1] = (Cmd->register_address >> 8) & 0xFF; write_len = 2; break; case avm_i2c_type_8_bit: pRegAddr[0] = (Cmd->register_address >> 0) & 0xFF; write_len = 1; break; default: DEB_INFO("[i2c]: i2c_block_write invallid type %u\n", Cmd->device_type); return -1; } memcpy(WriteBuffer, pRegAddr, write_len); memcpy(WriteBuffer + write_len, Cmd->Buffer, Cmd->data_length); ret = i2c_hw_write(Cmd->device_address, WriteBuffer, write_len + Cmd->data_length); if(ret != 0) { DEB_ERR("[i2c]: i2c_block_write: failed\n"); } return ret; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ unsigned int i2c_hw_read(unsigned int dev_address, unsigned char *ReadData, unsigned int ReadLength) { register unsigned short reg_value; unsigned int error = 0; DEB_INFO("[i2c]: i2c_hw_read: DeviceAddr=0x%x ReadBuffer=0x%p is_write=%s ReadLength=%u \n", dev_address, ReadData, "false", ReadLength); /*--------------------------------------------------------------------------------------*\ * wait for WRITE READY (write device addr) \*--------------------------------------------------------------------------------------*/ if(i2c_write_wait() & I2C_DATA_READ_ERROR) { DEB_ERR("[i2c]: i2c_hw_read: wait for ready failed\n"); return I2C_DATA_READ_ERROR; } DEB_INFO("[i2c]: I2C_DATA_HI=0x%x\n", dev_address | I2C_DATA_HI_READ_MODE); I2C_DATA_HI = (unsigned short)dev_address | I2C_DATA_HI_READ_MODE; /*--------------------------------------------------------------------------------------*\ * wait for WRITE READY (write dummy data 0xFF) \*--------------------------------------------------------------------------------------*/ reg_value = i2c_write_wait(); if(reg_value & I2C_DATA_READ_ERROR) { DEB_ERR("[i2c]: i2c_hw_read: error (0x%x) (wait after write DATA_HI)\n", reg_value); return I2C_DATA_READ_ERROR; } printk("reg_value=0x%x\n", reg_value); #if 0 I2C_DATA_LOW = 0x00FF; /*--------------------------------------------------------------------------------------*\ * wait for WRITE READY (read data) \*--------------------------------------------------------------------------------------*/ reg_value = i2c_write_wait(); if(reg_value & I2C_DATA_READ_ERROR) { DEB_ERR("[i2c]: i2c_hw_read: error (0x%x) (wait after write DATA_LOW)\n", reg_value); return I2C_DATA_READ_ERROR; } #endif /*--------------------------------------------------------------------------------------*\ * read bytes from Device \*--------------------------------------------------------------------------------------*/ while(ReadLength-- && (error == 0)) { /*--- DEB_INFO("[i2c]: i2c_hw_read: write byte I2C_DATA_LOW=0x%x\n", 0x00FF); ---*/ I2C_DATA_LOW = 0x00FF; /*--------------------------------------------------------------------------------------*\ * wait for Data READY \*--------------------------------------------------------------------------------------*/ reg_value = i2c_data_wait(); if(reg_value & I2C_DATA_READ_ERROR) { DEB_ERR("[i2c]: i2c_hw_read: error (0x%x) (wait before read data)\n", reg_value); error = reg_value | 0x03; } *ReadData++ = (unsigned char)(reg_value & I2C_DATA_READ_DATA_MASK); } reg_value = I2C_DATA_HI | I2C_DATA_HI_END_BUSRT; I2C_DATA_HI = reg_value; I2C_DATA_READ = 0; DEB_INFO("[i2c]: i2c_hw_read: write end mark I2C_DATA_HI=0x%x I2C_DATA_READ=0\n", reg_value); DEB_INFO("[i2c]: i2c_hw_read: error 0x%x\n", error); return error; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ unsigned int i2c_hw_write(unsigned int dev_address, unsigned char *WriteData, unsigned int WriteLength) { unsigned int error = 0; unsigned int reg_value; DEB_INFO("[i2c]: i2c_hw_write: DeviceAddr=0x%x WriteBuffer=0x%p is_write=%s WriteLength=%u \n", dev_address, WriteData, "true", WriteLength); /*--------------------------------------------------------------------------------------*\ * wait for WRITE READY (write device addr) \*--------------------------------------------------------------------------------------*/ if((i2c_write_wait() & I2C_DATA_READ_ERROR)) { DEB_ERR("[i2c]: i2c_hw_write: wait for ready failed\n"); return I2C_DATA_READ_ERROR; } DEB_INFO("[i2c]: I2C_DATA_HI=0x%x\n", dev_address | I2C_DATA_HI_WRITE_MODE); I2C_DATA_HI = (unsigned short)dev_address | I2C_DATA_HI_WRITE_MODE; /*--------------------------------------------------------------------------------------*\ * write all Bytes to device \*--------------------------------------------------------------------------------------*/ while(WriteLength-- && (error == 0)) { /*----------------------------------------------------------------------------------*\ * wait for WRITE READY \*----------------------------------------------------------------------------------*/ reg_value = i2c_write_wait(); if(reg_value & I2C_DATA_READ_ERROR) { DEB_INFO("[i2c]: i2c_hw_write: error 0x01\n"); break; } DEB_INFO("[i2c]: i2c_hw_write: write byte I2C_DATA_LOW=0x%x\n", *WriteData); I2C_DATA_LOW = (unsigned short)*WriteData++; } /*--------------------------------------------------------------------------------------*\ * wait for: data transfer complete \*--------------------------------------------------------------------------------------*/ reg_value = i2c_data_wait(); if(reg_value & I2C_DATA_READ_ERROR) { error = reg_value | 0x02; } reg_value = I2C_DATA_HI | I2C_DATA_HI_END_BUSRT; I2C_DATA_HI = reg_value; I2C_DATA_READ = 0; DEB_INFO("[i2c]: i2c_hw_write: write end mark I2C_DATA_HI=0x%x I2C_DATA_READ=0 error=0x%x\n", reg_value, error); return error; }