93
93
* @base: pointer to register struct
94
94
* @dev: device reference
95
95
* @i2c_clk: clock reference for i2c input clock
96
+ * @msg_queue: pointer to the messages requiring sending
96
97
* @buf: pointer to msg buffer for easier use
97
98
* @msg_complete: xfer completion object
98
99
* @adapter: core i2c abstraction
99
100
* @msg_err: error code for completed message
100
101
* @bus_clk_rate: current i2c bus clock rate
101
102
* @isr_status: cached copy of local ISR status
103
+ * @total_num: total number of messages to be sent/received
104
+ * @current_num: index of the current message being sent/received
102
105
* @msg_len: number of bytes transferred in msg
103
106
* @addr: address of the current slave
107
+ * @restart_needed: whether or not a repeated start is required after current message
104
108
*/
105
109
struct mchp_corei2c_dev {
106
110
void __iomem * base ;
107
111
struct device * dev ;
108
112
struct clk * i2c_clk ;
113
+ struct i2c_msg * msg_queue ;
109
114
u8 * buf ;
110
115
struct completion msg_complete ;
111
116
struct i2c_adapter adapter ;
112
117
int msg_err ;
118
+ int total_num ;
119
+ int current_num ;
113
120
u32 bus_clk_rate ;
114
121
u32 isr_status ;
115
122
u16 msg_len ;
116
123
u8 addr ;
124
+ bool restart_needed ;
117
125
};
118
126
119
127
static void mchp_corei2c_core_disable (struct mchp_corei2c_dev * idev )
@@ -222,6 +230,47 @@ static int mchp_corei2c_fill_tx(struct mchp_corei2c_dev *idev)
222
230
return 0 ;
223
231
}
224
232
233
+ static void mchp_corei2c_next_msg (struct mchp_corei2c_dev * idev )
234
+ {
235
+ struct i2c_msg * this_msg ;
236
+ u8 ctrl ;
237
+
238
+ if (idev -> current_num >= idev -> total_num ) {
239
+ complete (& idev -> msg_complete );
240
+ return ;
241
+ }
242
+
243
+ /*
244
+ * If there's been an error, the isr needs to return control
245
+ * to the "main" part of the driver, so as not to keep sending
246
+ * messages once it completes and clears the SI bit.
247
+ */
248
+ if (idev -> msg_err ) {
249
+ complete (& idev -> msg_complete );
250
+ return ;
251
+ }
252
+
253
+ this_msg = idev -> msg_queue ++ ;
254
+
255
+ if (idev -> current_num < (idev -> total_num - 1 )) {
256
+ struct i2c_msg * next_msg = idev -> msg_queue ;
257
+
258
+ idev -> restart_needed = next_msg -> flags & I2C_M_RD ;
259
+ } else {
260
+ idev -> restart_needed = false;
261
+ }
262
+
263
+ idev -> addr = i2c_8bit_addr_from_msg (this_msg );
264
+ idev -> msg_len = this_msg -> len ;
265
+ idev -> buf = this_msg -> buf ;
266
+
267
+ ctrl = readb (idev -> base + CORE_I2C_CTRL );
268
+ ctrl |= CTRL_STA ;
269
+ writeb (ctrl , idev -> base + CORE_I2C_CTRL );
270
+
271
+ idev -> current_num ++ ;
272
+ }
273
+
225
274
static irqreturn_t mchp_corei2c_handle_isr (struct mchp_corei2c_dev * idev )
226
275
{
227
276
u32 status = idev -> isr_status ;
@@ -247,10 +296,14 @@ static irqreturn_t mchp_corei2c_handle_isr(struct mchp_corei2c_dev *idev)
247
296
break ;
248
297
case STATUS_M_SLAW_ACK :
249
298
case STATUS_M_TX_DATA_ACK :
250
- if (idev -> msg_len > 0 )
299
+ if (idev -> msg_len > 0 ) {
251
300
mchp_corei2c_fill_tx (idev );
252
- else
253
- last_byte = true;
301
+ } else {
302
+ if (idev -> restart_needed )
303
+ finished = true;
304
+ else
305
+ last_byte = true;
306
+ }
254
307
break ;
255
308
case STATUS_M_TX_DATA_NACK :
256
309
case STATUS_M_SLAR_NACK :
@@ -287,7 +340,7 @@ static irqreturn_t mchp_corei2c_handle_isr(struct mchp_corei2c_dev *idev)
287
340
mchp_corei2c_stop (idev );
288
341
289
342
if (last_byte || finished )
290
- complete ( & idev -> msg_complete );
343
+ mchp_corei2c_next_msg ( idev );
291
344
292
345
return IRQ_HANDLED ;
293
346
}
@@ -311,21 +364,48 @@ static irqreturn_t mchp_corei2c_isr(int irq, void *_dev)
311
364
return ret ;
312
365
}
313
366
314
- static int mchp_corei2c_xfer_msg (struct mchp_corei2c_dev * idev ,
315
- struct i2c_msg * msg )
367
+ static int mchp_corei2c_xfer (struct i2c_adapter * adap , struct i2c_msg * msgs ,
368
+ int num )
316
369
{
317
- u8 ctrl ;
370
+ struct mchp_corei2c_dev * idev = i2c_get_adapdata (adap );
371
+ struct i2c_msg * this_msg = msgs ;
318
372
unsigned long time_left ;
373
+ u8 ctrl ;
374
+
375
+ mchp_corei2c_core_enable (idev );
376
+
377
+ /*
378
+ * The isr controls the flow of a transfer, this info needs to be saved
379
+ * to a location that it can access the queue information from.
380
+ */
381
+ idev -> restart_needed = false;
382
+ idev -> msg_queue = msgs ;
383
+ idev -> total_num = num ;
384
+ idev -> current_num = 0 ;
319
385
320
- idev -> addr = i2c_8bit_addr_from_msg (msg );
321
- idev -> msg_len = msg -> len ;
322
- idev -> buf = msg -> buf ;
386
+ /*
387
+ * But the first entry to the isr is triggered by the start in this
388
+ * function, so the first message needs to be "dequeued".
389
+ */
390
+ idev -> addr = i2c_8bit_addr_from_msg (this_msg );
391
+ idev -> msg_len = this_msg -> len ;
392
+ idev -> buf = this_msg -> buf ;
323
393
idev -> msg_err = 0 ;
324
394
325
- reinit_completion (& idev -> msg_complete );
395
+ if (idev -> total_num > 1 ) {
396
+ struct i2c_msg * next_msg = msgs + 1 ;
326
397
327
- mchp_corei2c_core_enable (idev );
398
+ idev -> restart_needed = next_msg -> flags & I2C_M_RD ;
399
+ }
328
400
401
+ idev -> current_num ++ ;
402
+ idev -> msg_queue ++ ;
403
+
404
+ reinit_completion (& idev -> msg_complete );
405
+
406
+ /*
407
+ * Send the first start to pass control to the isr
408
+ */
329
409
ctrl = readb (idev -> base + CORE_I2C_CTRL );
330
410
ctrl |= CTRL_STA ;
331
411
writeb (ctrl , idev -> base + CORE_I2C_CTRL );
@@ -335,20 +415,8 @@ static int mchp_corei2c_xfer_msg(struct mchp_corei2c_dev *idev,
335
415
if (!time_left )
336
416
return - ETIMEDOUT ;
337
417
338
- return idev -> msg_err ;
339
- }
340
-
341
- static int mchp_corei2c_xfer (struct i2c_adapter * adap , struct i2c_msg * msgs ,
342
- int num )
343
- {
344
- struct mchp_corei2c_dev * idev = i2c_get_adapdata (adap );
345
- int i , ret ;
346
-
347
- for (i = 0 ; i < num ; i ++ ) {
348
- ret = mchp_corei2c_xfer_msg (idev , msgs ++ );
349
- if (ret )
350
- return ret ;
351
- }
418
+ if (idev -> msg_err )
419
+ return idev -> msg_err ;
352
420
353
421
return num ;
354
422
}
0 commit comments