2 * Copyright 2012-15 Advanced Micro Devices, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
26 #include "dm_services.h"
29 * Pre-requisites: headers required by header of this unit
31 #include "include/i2caux_interface.h"
33 #include "i2c_engine.h"
39 #include "i2c_hw_engine.h"
42 * Post-requisites: headers required by this unit
51 * Cast 'struct i2c_engine *'
52 * to 'struct i2c_hw_engine *'
54 #define FROM_I2C_ENGINE(ptr) \
55 container_of((ptr), struct i2c_hw_engine, base)
59 * Cast 'struct engine *'
60 * to 'struct i2c_hw_engine *'
62 #define FROM_ENGINE(ptr) \
63 FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base))
65 enum i2caux_engine_type dal_i2c_hw_engine_get_engine_type(
66 const struct engine *engine)
68 return I2CAUX_ENGINE_TYPE_I2C_DDC_HW;
71 bool dal_i2c_hw_engine_submit_request(
72 struct engine *engine,
73 struct i2caux_transaction_request *i2caux_request,
74 bool middle_of_transaction)
76 struct i2c_hw_engine *hw_engine = FROM_ENGINE(engine);
78 struct i2c_request_transaction_data request;
80 uint32_t transaction_timeout;
82 enum i2c_channel_operation_result operation_result;
87 * transaction length will not exceed
88 * the number of free bytes in HW buffer (minus one for address)*/
90 if (i2caux_request->payload.length >=
91 hw_engine->funcs->get_hw_buffer_available_size(hw_engine)) {
92 i2caux_request->status =
93 I2CAUX_TRANSACTION_STATUS_FAILED_BUFFER_OVERFLOW;
97 if (i2caux_request->operation == I2CAUX_TRANSACTION_READ)
98 request.action = middle_of_transaction ?
99 I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT :
100 I2CAUX_TRANSACTION_ACTION_I2C_READ;
101 else if (i2caux_request->operation == I2CAUX_TRANSACTION_WRITE)
102 request.action = middle_of_transaction ?
103 I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT :
104 I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
106 i2caux_request->status =
107 I2CAUX_TRANSACTION_STATUS_FAILED_INVALID_OPERATION;
108 /* [anaumov] in DAL2, there was no "return false" */
112 request.address = (uint8_t)i2caux_request->payload.address;
113 request.length = i2caux_request->payload.length;
114 request.data = i2caux_request->payload.data;
116 /* obtain timeout value before submitting request */
118 transaction_timeout = hw_engine->funcs->get_transaction_timeout(
119 hw_engine, i2caux_request->payload.length + 1);
121 hw_engine->base.funcs->submit_channel_request(
122 &hw_engine->base, &request);
124 if ((request.status == I2C_CHANNEL_OPERATION_FAILED) ||
125 (request.status == I2C_CHANNEL_OPERATION_ENGINE_BUSY)) {
126 i2caux_request->status =
127 I2CAUX_TRANSACTION_STATUS_FAILED_CHANNEL_BUSY;
131 /* wait until transaction proceed */
133 operation_result = hw_engine->funcs->wait_on_operation_result(
136 I2C_CHANNEL_OPERATION_ENGINE_BUSY);
138 /* update transaction status */
140 switch (operation_result) {
141 case I2C_CHANNEL_OPERATION_SUCCEEDED:
142 i2caux_request->status =
143 I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
146 case I2C_CHANNEL_OPERATION_NO_RESPONSE:
147 i2caux_request->status =
148 I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
150 case I2C_CHANNEL_OPERATION_TIMEOUT:
151 i2caux_request->status =
152 I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
154 case I2C_CHANNEL_OPERATION_FAILED:
155 i2caux_request->status =
156 I2CAUX_TRANSACTION_STATUS_FAILED_INCOMPLETE;
159 i2caux_request->status =
160 I2CAUX_TRANSACTION_STATUS_FAILED_OPERATION;
163 if (result && (i2caux_request->operation == I2CAUX_TRANSACTION_READ)) {
164 struct i2c_reply_transaction_data reply;
166 reply.data = i2caux_request->payload.data;
167 reply.length = i2caux_request->payload.length;
169 hw_engine->base.funcs->
170 process_channel_reply(&hw_engine->base, &reply);
176 bool dal_i2c_hw_engine_acquire_engine(
177 struct i2c_engine *engine,
180 enum gpio_result result;
181 uint32_t current_speed;
183 result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
184 GPIO_DDC_CONFIG_TYPE_MODE_I2C);
186 if (result != GPIO_RESULT_OK)
189 engine->base.ddc = ddc;
191 current_speed = engine->funcs->get_speed(engine);
194 FROM_I2C_ENGINE(engine)->original_speed = current_speed;
200 * Queries in a loop for current engine status
201 * until retrieved status matches 'expected_result', or timeout occurs.
202 * Timeout given in microseconds
203 * and the status query frequency is also one per microsecond.
205 enum i2c_channel_operation_result dal_i2c_hw_engine_wait_on_operation_result(
206 struct i2c_hw_engine *engine,
208 enum i2c_channel_operation_result expected_result)
210 enum i2c_channel_operation_result result;
214 return I2C_CHANNEL_OPERATION_SUCCEEDED;
217 result = engine->base.funcs->get_channel_status(
218 &engine->base, NULL);
220 if (result != expected_result)
226 } while (i < timeout);
231 void dal_i2c_hw_engine_construct(
232 struct i2c_hw_engine *engine,
233 struct dc_context *ctx)
235 dal_i2c_engine_construct(&engine->base, ctx);
236 engine->original_speed = I2CAUX_DEFAULT_I2C_HW_SPEED;
237 engine->default_speed = I2CAUX_DEFAULT_I2C_HW_SPEED;
240 void dal_i2c_hw_engine_destruct(
241 struct i2c_hw_engine *engine)
243 dal_i2c_engine_destruct(&engine->base);