static inline void reset_hw_engine(struct engine *engine) { struct i2c_hw_engine_dce110 *hw_engine = FROM_ENGINE(engine); REG_UPDATE_2( DC_I2C_CONTROL, DC_I2C_SW_STATUS_RESET, 1, DC_I2C_SW_STATUS_RESET, 1); }
static bool is_hw_busy(struct engine *engine) { struct i2c_hw_engine_dce110 *hw_engine = FROM_ENGINE(engine); uint32_t i2c_sw_status = 0; REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status); if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_IDLE) return false; reset_hw_engine(engine); REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status); return i2c_sw_status != DC_I2C_STATUS__DC_I2C_STATUS_IDLE; }
static void keep_power_up_count( struct engine *engine, bool keep_power_up) { struct i2c_hw_engine_dce110 *hw_engine = FROM_ENGINE(engine); if (keep_power_up) ++hw_engine->engine_keep_power_up_count; else { --hw_engine->engine_keep_power_up_count; if (!hw_engine->engine_keep_power_up_count) disable_i2c_hw_engine(hw_engine); } }
static void release_engine( struct engine *engine) { struct i2c_hw_engine_dce110 *hw_engine = FROM_ENGINE(engine); struct i2c_engine *base = NULL; bool safe_to_reset; base = &hw_engine->base.base; /* Restore original HW engine speed */ base->funcs->set_speed(base, hw_engine->base.original_speed); /* Release I2C */ REG_UPDATE(DC_I2C_ARBITRATION, DC_I2C_SW_DONE_USING_I2C_REG, 1); /* Reset HW engine */ { uint32_t i2c_sw_status = 0; REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status); /* if used by SW, safe to reset */ safe_to_reset = (i2c_sw_status == 1); } if (safe_to_reset) REG_UPDATE_2( DC_I2C_CONTROL, DC_I2C_SOFT_RESET, 1, DC_I2C_SW_STATUS_RESET, 1); else REG_UPDATE(DC_I2C_CONTROL, DC_I2C_SW_STATUS_RESET, 1); /* HW I2c engine - clock gating feature */ if (!hw_engine->engine_keep_power_up_count) disable_i2c_hw_engine(hw_engine); }
bool dal_i2c_sw_engine_submit_request( struct engine *engine, struct i2caux_transaction_request *i2caux_request, bool middle_of_transaction) { struct i2c_sw_engine *sw_engine = FROM_ENGINE(engine); struct i2c_engine *base = &sw_engine->base; struct i2c_request_transaction_data request; bool operation_succeeded = false; if (i2caux_request->operation == I2CAUX_TRANSACTION_READ) request.action = middle_of_transaction ? I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT : I2CAUX_TRANSACTION_ACTION_I2C_READ; else if (i2caux_request->operation == I2CAUX_TRANSACTION_WRITE) request.action = middle_of_transaction ? I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT : I2CAUX_TRANSACTION_ACTION_I2C_WRITE; else { i2caux_request->status = I2CAUX_TRANSACTION_STATUS_FAILED_INVALID_OPERATION; /* in DAL2, there was no "return false" */ return false; } request.address = (uint8_t)i2caux_request->payload.address; request.length = i2caux_request->payload.length; request.data = i2caux_request->payload.data; base->funcs->submit_channel_request(base, &request); if ((request.status == I2C_CHANNEL_OPERATION_ENGINE_BUSY) || (request.status == I2C_CHANNEL_OPERATION_FAILED)) i2caux_request->status = I2CAUX_TRANSACTION_STATUS_FAILED_CHANNEL_BUSY; else { enum i2c_channel_operation_result operation_result; do { operation_result = base->funcs->get_channel_status(base, NULL); switch (operation_result) { case I2C_CHANNEL_OPERATION_SUCCEEDED: i2caux_request->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED; operation_succeeded = true; break; case I2C_CHANNEL_OPERATION_NO_RESPONSE: i2caux_request->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK; break; case I2C_CHANNEL_OPERATION_TIMEOUT: i2caux_request->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; break; case I2C_CHANNEL_OPERATION_FAILED: i2caux_request->status = I2CAUX_TRANSACTION_STATUS_FAILED_INCOMPLETE; break; default: i2caux_request->status = I2CAUX_TRANSACTION_STATUS_FAILED_OPERATION; break; } } while (operation_result == I2C_CHANNEL_OPERATION_ENGINE_BUSY); } return operation_succeeded; }
static void release_engine( struct engine *engine) { struct i2c_hw_engine_dce110 *hw_engine = FROM_ENGINE(engine); struct i2c_engine *base = NULL; bool safe_to_reset; uint32_t value = 0; base = &hw_engine->base.base; /* Restore original HW engine speed */ base->funcs->set_speed(base, hw_engine->base.original_speed); /* Release I2C */ { value = dal_read_reg(engine->ctx, mmDC_I2C_ARBITRATION); set_reg_field_value( value, 1, DC_I2C_ARBITRATION, DC_I2C_SW_DONE_USING_I2C_REG); dal_write_reg(engine->ctx, mmDC_I2C_ARBITRATION, value); } /* Reset HW engine */ { uint32_t i2c_sw_status = 0; value = dal_read_reg(engine->ctx, mmDC_I2C_SW_STATUS); i2c_sw_status = get_reg_field_value( value, DC_I2C_SW_STATUS, DC_I2C_SW_STATUS); /* if used by SW, safe to reset */ safe_to_reset = (i2c_sw_status == 1); } { value = dal_read_reg(engine->ctx, mmDC_I2C_CONTROL); if (safe_to_reset) set_reg_field_value( value, 1, DC_I2C_CONTROL, DC_I2C_SOFT_RESET); set_reg_field_value( value, 1, DC_I2C_CONTROL, DC_I2C_SW_STATUS_RESET); dal_write_reg(engine->ctx, mmDC_I2C_CONTROL, value); } /* HW I2c engine - clock gating feature */ if (!hw_engine->engine_keep_power_up_count) disable_i2c_hw_engine(hw_engine); }