int i2c_init(uint32_t base, uint32_t baud) { int instance; // Accept either an instance or base address for the base param. if (base >= 1 && base <= HW_I2C_INSTANCE_COUNT) { instance = base; } else { instance = REGS_I2C_INSTANCE(base); } // enable the source clocks to the I2C port clock_gating_config(REGS_I2C_BASE(instance), CLOCK_ON); // Set iomux configuration i2c_iomux_config(instance); // reset I2C HW_I2C_I2CR_WR(instance, 0); // Set clock. set_i2c_clock(instance, baud); // set an I2C slave address // HW_I2C_IADR_WR(instance, IMX6_DEFAULT_SLAVE_ID); // clear the status register HW_I2C_I2SR_WR(instance, 0); // enable the I2C controller HW_I2C_I2CR_WR(instance, BM_I2C_I2CR_IEN); return 0; }
int i2c_xfer(const imx_i2c_request_t *rq, int dir) { uint32_t reg; uint32_t ret = 0; uint16_t i2cr; uint8_t i; uint8_t data; uint32_t instance = i2c_get_request_instance(rq); uint8_t address = (rq->device ? rq->device->address : rq->dev_addr) << 1; if (rq->buffer_sz == 0 || rq->buffer == NULL) { debug_printf("Invalid register address size=%x, buffer size=%x, buffer=%x\n", rq->reg_addr_sz, rq->buffer_sz, (unsigned int)rq->buffer); return ERR_INVALID_REQUEST; } // clear the status register HW_I2C_I2SR_WR(instance, 0); // enable the I2C controller HW_I2C_I2CR_WR(instance, BM_I2C_I2CR_IEN); // Check if bus is free, if not return error if (is_bus_free(instance) != 0) { return -1; } // If the request has device info attached and it has a non-zero bit rate, then // change the clock to the specified rate. if (rq->device && rq->device->freq) { set_i2c_clock(instance, rq->device->freq); } // Step 1: Select master mode, assert START signal and also indicate TX mode HW_I2C_I2CR_WR(instance, BM_I2C_I2CR_IEN | BM_I2C_I2CR_MSTA | BM_I2C_I2CR_MTX); // make sure bus is busy after the START signal if (wait_till_busy(instance) != 0) { debug_printf("1\n"); return -1; } // Step 2: send slave address + read/write at the LSB data = address | I2C_WRITE; if ((ret = tx_byte(&data, instance)) != 0) { debug_printf("START TX ERR %d\n", ret); if (ret == ERR_NO_ACK) { return ERR_NO_ACK_ON_START; } else { return ret; } } // Step 3: send I2C device register address if (rq->reg_addr_sz > 4) { debug_printf("Warning register address size %d should less than 4\n", rq->reg_addr_sz); return ERR_INVALID_REQUEST; } reg = rq->reg_addr; for (i = 0; i < rq->reg_addr_sz; i++, reg >>= 8) { data = reg & 0xFF; #if TRACE_I2C debug_printf("sending I2C=%d device register: data=0x%x, byte %d\n", instance, data, i); #endif // TRACE_I2C if (tx_byte(&data, instance) != 0) { return -1; } } // Step 4: read/write data if (dir == I2C_READ) { // do repeat-start HW_I2C_I2CR(instance).B.RSTA = 1; // make sure bus is busy after the REPEATED START signal if (wait_till_busy(instance) != 0) { return ERR_TX; } // send slave address again, but indicate read operation data = address | I2C_READ; if (tx_byte(&data, instance) != 0) { return -1; } // change to receive mode i2cr = HW_I2C_I2CR_RD(instance) & ~BM_I2C_I2CR_MTX; // if only one byte to read, make sure don't send ack if (rq->buffer_sz == 1) { i2cr |= BM_I2C_I2CR_TXAK; } HW_I2C_I2CR_WR(instance, i2cr); // dummy read data = HW_I2C_I2DR_RD(instance); // now reading ... if (rx_bytes(rq->buffer, instance, rq->buffer_sz) != 0) { return -1; } } else { // I2C_WRITE for (i = 0; i < rq->buffer_sz; i++) { // send device register value data = rq->buffer[i]; if ((ret = tx_byte(&data, instance)) != 0) { break; } } } // generate STOP by clearing MSTA bit imx_send_stop(instance); // Check if bus is free, if not return error if (is_bus_free(instance) != 0) { debug_printf("WARNING: bus is not free\n"); } // disable the controller HW_I2C_I2CR_WR(instance, 0); return ret; }
/* ********************************************************************************************************************** * i2c_init * * Description: * * Arguments : * * Returns : none * * Notes : none * ********************************************************************************************************************** */ void i2c_init(int speed, int slaveaddr) { int i, clk_n, clk_m; int i2c_nodeoffset; /*set gpio and clock*/ #ifndef CONFIG_CPUS_I2C i2c_nodeoffset = fdt_path_offset(working_fdt,"/soc/twi_para"); if(i2c_nodeoffset < 0) { printf("axp: get node[%s] error\n",PMU_SCRIPT_NAME); return ; } //if(script_parser_fetch(PMU_SCRIPT_NAME, "pmu_pwron_vol", &vol_value, 1)) if(fdt_getprop_u32(working_fdt,i2c_nodeoffset,"twi_port", (uint32_t*)&bus_num)<0) { printf("can not get i2c bus num \n"); } if(bus_num > SUNXI_I2C_CONTROLLER) { printf("can not support i2c bus num %d \n",bus_num); return ; } set_i2c_clock(); if(0 != fdt_set_all_pin_by_offset(i2c_nodeoffset,"pinctrl-0")) { printf("set pin for i2c bus num %d error\n",bus_num); return ; } i2c = (struct sunxi_twi_reg *)(SUNXI_TWI0_BASE + (bus_num * TWI_CONTROL_OFFSET)); #else set_cpus_i2c_clock(); fdt_set_all_pin("/soc/s_twi0","pinctrl-0"); #endif /* reset i2c control */ i = 0xffff; i2c->srst = 1; while((i2c->srst) && (i)) { i --; } if((i2c->lcr & 0x30) != 0x30 ) { /* toggle I2CSCL until bus idle */ i2c->lcr = 0x05; __usdelay(500); i = 10; while ((i > 0) && ((i2c->lcr & 0x02) != 2)) { i2c->lcr |= 0x08; __usdelay(1000); i2c->lcr &= ~0x08; __usdelay(1000); i--; } i2c->lcr = 0x0; __usdelay(500); } if(speed < 100) { speed = 100; } else if(speed > 400) { speed = 400; } clk_n = 1; clk_m = (24000/10)/((2^clk_n) * speed) - 1; i2c->clk = (clk_m<<3) | clk_n; i2c->ctl = 0x40; i2c->eft = 0; return ; }