static void process_channel_reply( struct i2c_engine *engine, struct i2c_reply_transaction_data *reply) { uint32_t length = reply->length; uint8_t *buffer = reply->data; struct i2c_hw_engine_dce110 *hw_engine = FROM_I2C_ENGINE(engine); REG_SET_3(DC_I2C_DATA, 0, DC_I2C_INDEX, hw_engine->buffer_used_write, DC_I2C_DATA_RW, 1, DC_I2C_INDEX_WRITE, 1); while (length) { /* after reading the status, * if the I2C operation executed successfully * (i.e. DC_I2C_STATUS_DONE = 1) then the I2C controller * should read data bytes from I2C circular data buffer */ uint32_t i2c_data; REG_GET(DC_I2C_DATA, DC_I2C_DATA, &i2c_data); *buffer++ = i2c_data; --length; } }
static enum i2c_channel_operation_result get_channel_status( struct i2c_engine *i2c_engine, uint8_t *returned_bytes) { uint32_t i2c_sw_status = 0; struct i2c_hw_engine_dce110 *hw_engine = FROM_I2C_ENGINE(i2c_engine); uint32_t value = REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status); if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_SW) return I2C_CHANNEL_OPERATION_ENGINE_BUSY; else if (value & hw_engine->i2c_mask->DC_I2C_SW_STOPPED_ON_NACK) return I2C_CHANNEL_OPERATION_NO_RESPONSE; else if (value & hw_engine->i2c_mask->DC_I2C_SW_TIMEOUT) return I2C_CHANNEL_OPERATION_TIMEOUT; else if (value & hw_engine->i2c_mask->DC_I2C_SW_ABORTED) return I2C_CHANNEL_OPERATION_FAILED; else if (value & hw_engine->i2c_mask->DC_I2C_SW_DONE) return I2C_CHANNEL_OPERATION_SUCCEEDED; /* * this is the case when HW used for communication, I2C_SW_STATUS * could be zero */ return I2C_CHANNEL_OPERATION_SUCCEEDED; }
static bool setup_engine( struct i2c_engine *i2c_engine) { struct i2c_hw_engine_dce110 *hw_engine = FROM_I2C_ENGINE(i2c_engine); /* Program pin select */ REG_UPDATE_6( DC_I2C_CONTROL, DC_I2C_GO, 0, DC_I2C_SOFT_RESET, 0, DC_I2C_SEND_RESET, 0, DC_I2C_SW_STATUS_RESET, 1, DC_I2C_TRANSACTION_COUNT, 0, DC_I2C_DDC_SELECT, hw_engine->engine_id); /* Program time limit */ REG_UPDATE_N( SETUP, 2, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_TIME_LIMIT), I2C_SETUP_TIME_LIMIT, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE), 1); /* Program HW priority * set to High - interrupt software I2C at any time * Enable restart of SW I2C that was interrupted by HW * disable queuing of software while I2C is in use by HW */ REG_UPDATE_2( DC_I2C_ARBITRATION, DC_I2C_NO_QUEUED_SW_GO, 0, DC_I2C_SW_PRIORITY, DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_NORMAL); return true; }
static void submit_channel_request( struct i2c_engine *engine, struct i2c_request_transaction_data *request) { request->status = I2C_CHANNEL_OPERATION_SUCCEEDED; if (!process_transaction(FROM_I2C_ENGINE(engine), request)) return; if (is_hw_busy(&engine->base)) { request->status = I2C_CHANNEL_OPERATION_ENGINE_BUSY; return; } execute_transaction(FROM_I2C_ENGINE(engine)); }
static void destroy( struct i2c_engine **ptr) { dal_i2c_sw_engine_destruct(FROM_I2C_ENGINE(*ptr)); dm_free(*ptr); *ptr = NULL; }
static void destroy( struct i2c_engine **engine) { struct i2c_sw_engine_dce110 *sw_engine = FROM_I2C_ENGINE(*engine); destruct(sw_engine); dm_free(sw_engine); *engine = NULL; }
static void destroy( struct i2c_engine **i2c_engine) { struct i2c_hw_engine_dce110 *engine_dce110 = FROM_I2C_ENGINE(*i2c_engine); dal_i2c_hw_engine_destruct(&engine_dce110->base); kfree(engine_dce110); *i2c_engine = NULL; }
static uint32_t get_speed( const struct i2c_engine *i2c_engine) { const struct i2c_hw_engine_dce110 *hw_engine = FROM_I2C_ENGINE(i2c_engine); uint32_t pre_scale = 0; REG_GET(SPEED, DC_I2C_DDC1_PRESCALE, &pre_scale); /* [anaumov] it seems following is unnecessary */ /*ASSERT(value.bits.DC_I2C_DDC1_PRESCALE);*/ return pre_scale ? hw_engine->reference_frequency / pre_scale : hw_engine->base.default_speed; }
void dal_i2c_sw_engine_set_speed( struct i2c_engine *engine, uint32_t speed) { struct i2c_sw_engine *sw_engine = FROM_I2C_ENGINE(engine); ASSERT(speed); sw_engine->speed = speed ? speed : I2CAUX_DEFAULT_I2C_SW_SPEED; sw_engine->clock_delay = 1000 / sw_engine->speed; if (sw_engine->clock_delay < 12) sw_engine->clock_delay = 12; }
static void process_channel_reply( struct i2c_engine *engine, struct i2c_reply_transaction_data *reply) { uint8_t length = reply->length; uint8_t *buffer = reply->data; struct i2c_hw_engine_dce110 *i2c_hw_engine_dce110 = FROM_I2C_ENGINE(engine); uint32_t value = dal_read_reg(engine->base.ctx, mmDC_I2C_DATA); /*set index*/ set_reg_field_value( value, i2c_hw_engine_dce110->buffer_used_write, DC_I2C_DATA, DC_I2C_INDEX); set_reg_field_value( value, 1, DC_I2C_DATA, DC_I2C_DATA_RW); set_reg_field_value( value, 1, DC_I2C_DATA, DC_I2C_INDEX_WRITE); dal_write_reg(engine->base.ctx, mmDC_I2C_DATA, value); while (length) { /* after reading the status, * if the I2C operation executed successfully * (i.e. DC_I2C_STATUS_DONE = 1) then the I2C controller * should read data bytes from I2C circular data buffer */ value = dal_read_reg(engine->base.ctx, mmDC_I2C_DATA); *buffer++ = get_reg_field_value( value, DC_I2C_DATA, DC_I2C_DATA); --length; } }
void dal_i2c_sw_engine_submit_channel_request( struct i2c_engine *engine, struct i2c_request_transaction_data *req) { struct i2c_sw_engine *sw_engine = FROM_I2C_ENGINE(engine); struct ddc *ddc = engine->base.ddc; uint16_t clock_delay_div_4 = sw_engine->clock_delay >> 2; /* send sync (start / repeated start) */ bool result = start_sync(engine->base.ctx, ddc, clock_delay_div_4); /* process payload */ if (result) { switch (req->action) { case I2CAUX_TRANSACTION_ACTION_I2C_WRITE: case I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT: result = i2c_write(engine->base.ctx, ddc, clock_delay_div_4, req->address, req->length, req->data); break; case I2CAUX_TRANSACTION_ACTION_I2C_READ: case I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT: result = i2c_read(engine->base.ctx, ddc, clock_delay_div_4, req->address, req->length, req->data); break; default: result = false; break; } } /* send stop if not 'mot' or operation failed */ if (!result || (req->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) || (req->action == I2CAUX_TRANSACTION_ACTION_I2C_READ)) if (!stop_sync(engine->base.ctx, ddc, clock_delay_div_4)) result = false; req->status = result ? I2C_CHANNEL_OPERATION_SUCCEEDED : I2C_CHANNEL_OPERATION_FAILED; }
static void set_speed( struct i2c_engine *i2c_engine, uint32_t speed) { struct i2c_hw_engine_dce110 *hw_engine = FROM_I2C_ENGINE(i2c_engine); if (speed) { if (hw_engine->i2c_mask->DC_I2C_DDC1_START_STOP_TIMING_CNTL) REG_UPDATE_N( SPEED, 3, FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_PRESCALE), hw_engine->reference_frequency / speed, FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_THRESHOLD), 2, FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_START_STOP_TIMING_CNTL), speed > 50 ? 2:1); else REG_UPDATE_N( SPEED, 2, FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_PRESCALE), hw_engine->reference_frequency / speed, FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_THRESHOLD), 2); } }
static void set_speed( struct i2c_engine *i2c_engine, uint32_t speed) { struct i2c_hw_engine_dce110 *engine = FROM_I2C_ENGINE(i2c_engine); if (speed) { const uint32_t addr = engine->addr.DC_I2C_DDCX_SPEED; uint32_t value = dal_read_reg(i2c_engine->base.ctx, addr); set_reg_field_value( value, engine->reference_frequency / speed, DC_I2C_DDC1_SPEED, DC_I2C_DDC1_PRESCALE); set_reg_field_value( value, 2, DC_I2C_DDC1_SPEED, DC_I2C_DDC1_THRESHOLD); /*DCE11, HW add 100Khz support for I2c*/ if (speed > 50) { set_reg_field_value( value, 2, DC_I2C_DDC1_SPEED, DC_I2C_DDC1_START_STOP_TIMING_CNTL); } else { set_reg_field_value( value, 1, DC_I2C_DDC1_SPEED, DC_I2C_DDC1_START_STOP_TIMING_CNTL); } dal_write_reg(i2c_engine->base.ctx, addr, value); } }
static uint32_t get_speed( const struct i2c_engine *i2c_engine) { const struct i2c_hw_engine_dce110 *engine = FROM_I2C_ENGINE(i2c_engine); const uint32_t addr = engine->addr.DC_I2C_DDCX_SPEED; uint32_t pre_scale = 0; uint32_t value = dal_read_reg(i2c_engine->base.ctx, addr); pre_scale = get_reg_field_value( value, DC_I2C_DDC1_SPEED, DC_I2C_DDC1_PRESCALE); /* [anaumov] it seems following is unnecessary */ /*ASSERT(value.bits.DC_I2C_DDC1_PRESCALE);*/ return pre_scale ? engine->reference_frequency / pre_scale : engine->base.default_speed; }
uint32_t dal_i2c_sw_engine_get_speed( const struct i2c_engine *engine) { return FROM_I2C_ENGINE(engine)->speed; }
static bool setup_engine( struct i2c_engine *i2c_engine) { uint32_t value = 0; struct i2c_hw_engine_dce110 *engine = FROM_I2C_ENGINE(i2c_engine); /* Program pin select */ { const uint32_t addr = mmDC_I2C_CONTROL; value = dal_read_reg(i2c_engine->base.ctx, addr); set_reg_field_value( value, 0, DC_I2C_CONTROL, DC_I2C_GO); set_reg_field_value( value, 0, DC_I2C_CONTROL, DC_I2C_SOFT_RESET); set_reg_field_value( value, 0, DC_I2C_CONTROL, DC_I2C_SEND_RESET); set_reg_field_value( value, 0, DC_I2C_CONTROL, DC_I2C_SW_STATUS_RESET); set_reg_field_value( value, 0, DC_I2C_CONTROL, DC_I2C_TRANSACTION_COUNT); set_reg_field_value( value, engine->engine_id, DC_I2C_CONTROL, DC_I2C_DDC_SELECT); dal_write_reg(i2c_engine->base.ctx, addr, value); } /* Program time limit */ { const uint32_t addr = engine->addr.DC_I2C_DDCX_SETUP; value = dal_read_reg(i2c_engine->base.ctx, addr); set_reg_field_value( value, I2C_SETUP_TIME_LIMIT, DC_I2C_DDC1_SETUP, DC_I2C_DDC1_TIME_LIMIT); set_reg_field_value( value, 1, DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE); dal_write_reg(i2c_engine->base.ctx, addr, value); } /* Program HW priority * set to High - interrupt software I2C at any time * Enable restart of SW I2C that was interrupted by HW * disable queuing of software while I2C is in use by HW */ { value = dal_read_reg(i2c_engine->base.ctx, mmDC_I2C_ARBITRATION); set_reg_field_value( value, 0, DC_I2C_ARBITRATION, DC_I2C_NO_QUEUED_SW_GO); set_reg_field_value( value, DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_NORMAL, DC_I2C_ARBITRATION, DC_I2C_SW_PRIORITY); dal_write_reg(i2c_engine->base.ctx, mmDC_I2C_ARBITRATION, value); } return true; }