summaryrefslogtreecommitdiff
path: root/include/linux/i2c/i2c-msm-v2.h
blob: 54974c02725d66ac896e49b01210aabc96c9852b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */
/*
 * I2C controller driver for Qualcomm Technologies Inc platforms
 */

#ifndef _I2C_MSM_V2_H
#define _I2C_MSM_V2_H

#include <linux/bitops.h>
#include <linux/dmaengine.h>

enum msm_i2_debug_level {
	MSM_ERR,	/* Error messages only. Always on */
	MSM_PROF,	/* High level events. Use for profiling */
	MSM_DBG,	/* Low level details. Use for debugging */
};

#define i2c_msm_dbg(ctrl, dbg_level, fmt, ...) do {\
		if (ctrl->dbgfs.dbg_lvl >= dbg_level)\
			dev_info(ctrl->dev, pr_fmt(fmt), ##__VA_ARGS__);\
	} while (0)

#define BIT_IS_SET(val, idx)        ((val >> idx) & 0x1)
#define BITS_AT(val, idx, n_bits)(((val) & (((1 << n_bits) - 1) << idx)) >> idx)
#define MASK_IS_SET(val, mask)      ((val & mask) == mask)
#define MASK_IS_SET_BOOL(val, mask) (MASK_IS_SET(val, mask) ? 1 : 0)
#define KHz(freq) (1000 * freq)
#define I2C_MSM_CLK_FAST_PLUS_FREQ  (1000000)

/* QUP Registers */
enum {
	QUP_CONFIG              = 0x0,
	QUP_STATE               = 0x4,
	QUP_IO_MODES            = 0x8,
	QUP_SW_RESET            = 0xC,
	QUP_OPERATIONAL         = 0x18,
	QUP_ERROR_FLAGS         = 0x1C,
	QUP_ERROR_FLAGS_EN      = 0x20,
	QUP_TEST_CTRL           = 0x24,
	QUP_OPERATIONAL_MASK    = 0x28,
	QUP_HW_VERSION          = 0x30,
	QUP_MX_READ_COUNT       = 0x208,
	QUP_MX_WRITE_COUNT      = 0x150,
	QUP_MX_OUTPUT_COUNT     = 0x100,
	QUP_MX_INPUT_COUNT      = 0x200,
	QUP_MX_WR_CNT           = 0x100,
	QUP_OUT_DEBUG           = 0x108,
	QUP_OUT_FIFO_CNT        = 0x10C,
	QUP_OUT_FIFO_BASE       = 0x110,
	QUP_IN_READ_CUR         = 0x20C,
	QUP_IN_DEBUG            = 0x210,
	QUP_IN_FIFO_CNT         = 0x214,
	QUP_IN_FIFO_BASE        = 0x218,
	QUP_I2C_MASTER_CLK_CTL  = 0x400,
	QUP_I2C_STATUS          = 0x404,
	QUP_I2C_MASTER_CONFIG   = 0x408,
	QUP_I2C_MASTER_BUS_CLR  = 0x40C,
};

/* Register:QUP_STATE state field values */
enum i2c_msm_qup_state {
	QUP_STATE_RESET         = 0,
	QUP_STATE_RUN           = 1U,
	QUP_STATE_PAUSE         = 3U,
};

/* Register:QUP_STATE fields */
enum {
	QUP_STATE_MASK          = 3U,
	QUP_STATE_VALID         = BIT(2),
	QUP_I2C_MAST_GEN        = BIT(4),
	QUP_I2C_FLUSH           = BIT(6),
	QUP_I2C_STATUS_RESET    = 0x42,
};


/* Register:QUP_CONFIG fields */
enum {
	QUP_MINI_CORE_MASK      = 0xF00,
	QUP_MINI_CORE_I2C_VAL   = 0x200,
	QUP_N_MASK              = 0x1F,
	QUP_N_VAL               = 0x7, /* 0xF for A family */
	QUP_NO_OUPUT            = BIT(6),
	QUP_NO_INPUT            = BIT(7),
	QUP_APP_CLK_ON_EN       = BIT(12),
	QUP_CORE_CLK_ON_EN      = BIT(13),
	QUP_FIFO_CLK_GATE_EN    = BIT(14),
};

/* Register:QUP_OPERATIONAL fields */
enum {
	QUP_INPUT_FIFO_NOT_EMPTY = BIT(5),
	QUP_OUTPUT_SERVICE_FLAG  = BIT(8),
	QUP_INPUT_SERVICE_FLAG   = BIT(9),
	QUP_MAX_OUTPUT_DONE_FLAG = BIT(10),
	QUP_MAX_INPUT_DONE_FLAG  = BIT(11),
	QUP_OUT_BLOCK_WRITE_REQ  = BIT(12),
	QUP_IN_BLOCK_READ_REQ    = BIT(13),
};

/* Register:QUP_OPERATIONAL_MASK fields */
enum {
	QUP_INPUT_SERVICE_MASK  = BIT(9),
	QUP_OUTPUT_SERVICE_MASK = BIT(8),
};

/* Register:QUP_IO_MODES fields */
enum {
	QUP_OUTPUT_MODE         = BIT(10) | BIT(11),
	QUP_INPUT_MODE          = BIT(12) | BIT(13),
	QUP_UNPACK_EN           = BIT(14),
	QUP_PACK_EN             = BIT(15),
	QUP_OUTPUT_BIT_SHIFT_EN = BIT(16),
};

/* Register:QUP_I2C_STATUS (a.k.a I2C_MASTER_STATUS) fields */
enum {
	QUP_BUS_ERROR           = BIT(2),
	QUP_PACKET_NACKED       = BIT(3),
	QUP_ARB_LOST            = BIT(4),
	QUP_INVALID_WRITE       = BIT(5),
	QUP_FAILED              = BIT(6),
	QUP_BUS_ACTIVE          = BIT(8),
	QUP_BUS_MASTER          = BIT(9),
	QUP_INVALID_TAG         = BIT(23),
	QUP_INVALID_READ_ADDR   = BIT(24),
	QUP_INVALID_READ_SEQ    = BIT(25),
	QUP_I2C_SDA             = BIT(26),
	QUP_I2C_SCL             = BIT(27),
	QUP_MSTR_STTS_ERR_MASK  = 0x380003C,
};

/* Register:QUP_I2C_MASTER_CONFIG fields */
enum {
	QUP_EN_VERSION_TWO_TAG  = 1U,
};

/* Register:QUP_I2C_MASTER_CLK_CTL field setters */
#define I2C_MSM_SCL_NOISE_REJECTION(reg_val, noise_rej_val) \
		(((reg_val) & ~(0x3 << 24)) | (((noise_rej_val) & 0x3) << 24))
#define I2C_MSM_SDA_NOISE_REJECTION(reg_val, noise_rej_val) \
		(((reg_val) & ~(0x3 << 26)) | (((noise_rej_val) & 0x3) << 26))

/* Register:QUP_ERROR_FLAGS_EN flags */
enum {
	QUP_OUTPUT_OVER_RUN_ERR_EN  = BIT(5),
	QUP_INPUT_UNDER_RUN_ERR_EN  = BIT(4),
	QUP_OUTPUT_UNDER_RUN_ERR_EN = BIT(3),
	QUP_INPUT_OVER_RUN_ERR_EN   = BIT(2),
};

/* Status, Error flags */
enum {
	I2C_STATUS_WR_BUFFER_FULL  = BIT(0),
	I2C_STATUS_BUS_ACTIVE      = BIT(8),
	I2C_STATUS_BUS_MASTER      = BIT(9),
	I2C_STATUS_ERROR_MASK      = 0x38000FC,
	QUP_I2C_NACK_FLAG          = BIT(3),
	QUP_IN_NOT_EMPTY           = BIT(5),
	QUP_ERR_FLGS_MASK           = 0x3C,
};

/* Master status clock states */
enum {
	I2C_CLK_RESET_BUSIDLE_STATE = 0,
	I2C_CLK_FORCED_LOW_STATE    = 5,
};

/* Controller's power state */
enum i2c_msm_power_state {
	I2C_MSM_PM_RT_ACTIVE,
	I2C_MSM_PM_RT_SUSPENDED,
	I2C_MSM_PM_SYS_SUSPENDED
};

/*
 * The max buffer size required for tags is for holding the following sequence:
 * [start] + [start | slv-addr] + [ rd/wr | len]
 * which sum up to 6 bytes. However, we use u64 to hold the value, thus we say
 * that max length is 8 bytes.
 */
#define I2C_MSM_TAG2_MAX_LEN            (4)
#define I2C_MSM_DMA_TX_SZ             (64) /* tx chan n entries */
#define I2C_MSM_DMA_RX_SZ             (32) /* rx chan n entries */
#define I2C_MSM_DMA_DESC_ARR_SIZ  (I2C_MSM_DMA_TX_SZ + I2C_MSM_DMA_RX_SZ)
#define I2C_MSM_REG_2_STR_BUF_SZ        (128)
/* Optimal value to hold the error strings */
#define I2C_MSM_MAX_ERR_BUF_SZ		(256)
#define I2C_MSM_BUF_DUMP_MAX_BC         (20)
#define I2C_MSM_MAX_POLL_MSEC           (100)
#define I2C_MSM_TIMEOUT_SAFTY_COEF      (10)
#define I2C_MSM_TIMEOUT_MIN_USEC        (500000)
#define I2C_QUP_MAX_BUS_RECOVERY_RETRY  (10)

/* QUP v2 tags */
#define QUP_TAG2_DATA_WRITE        (0x82ULL)
#define QUP_TAG2_DATA_WRITE_N_STOP (0x83ULL)
#define QUP_TAG2_DATA_READ         (0x85ULL)
#define QUP_TAG2_DATA_READ_N_STOP  (0x87ULL)
#define QUP_TAG2_START             (0x81ULL)
#define QUP_TAG2_DATA_READ_N_NACK  (0x86ULL)
#define QUP_TAG2_START_STOP        (0x8AULL)
#define QUP_TAG2_INPUT_EOT         (0x93ULL)
#define QUP_TAG2_FLUSH_STOP        (0x96ULL)
#define QUP_BUF_OVERHD_BC          (2)
#define QUP_MAX_BUF_SZ             (256)

enum i2c_msm_clk_path_vec_idx {
	I2C_MSM_CLK_PATH_SUSPEND_VEC,
	I2C_MSM_CLK_PATH_RESUME_VEC,
};
#define I2C_MSM_CLK_PATH_AVRG_BW(ctrl) (0)
#define I2C_MSM_CLK_PATH_BRST_BW(ctrl) (ctrl->rsrcs.clk_freq_in * 8)

enum i2c_msm_gpio_name_idx {
	I2C_MSM_GPIO_SCL,
	I2C_MSM_GPIO_SDA,
};

extern const char * const i2c_msm_mode_str_tbl[];

struct i2c_msm_ctrl;

/*
 *  i2c_msm_dma_mem: utility struct which holds both physical and virtual addr
 */
struct i2c_msm_dma_mem {
	dma_addr_t               phy_addr;
	void                    *vrtl_addr;
};

/*
 * i2c_msm_tag: tag's data and its length.
 *
 * @len tag len can be two, four or six bytes.
 */
struct i2c_msm_tag {
	u64                    val;
	int                    len;
};

/*
 * i2c_msm_dma_tag: similar to struct i2c_msm_tag but holds physical address.
 *
 * @buf physical address of entry in the tag_arr of
 *          struct i2c_msm_xfer_mode_dma
 * @len tag len.
 *
 * Hold the information from i2c_msm_dma_xfer_prepare() which is used by
 * i2c_msm_dma_xfer_process() and freed by i2c_msm_dma_xfer_unprepare()
 */
struct i2c_msm_dma_tag {
	dma_addr_t             buf;
	size_t                 len;
};

/*
 * i2c_msm_dma_buf: dma mapped pointer to i2c_msg data buffer and related tag
 * @vir_addr ptr to i2c_msg buf beginning or with offset (when buf len > 256)
 */
struct i2c_msm_dma_buf {
	struct i2c_msm_dma_mem   ptr;
	enum dma_data_direction  dma_dir;
	size_t                   len;
	bool                     is_rx;
	bool                     is_last;
	struct i2c_msm_dma_tag   tag;
	/* DMA API */
	struct scatterlist	sg_list[2];
};

/*
 * i2c_msm_dma_chan: per channel info
 *
 * @is_init true when the channel is initialized and requires eventual teardown.
 * @name channel name (tx/rx) for debugging.
 * @desc_cnt_cur number of occupied descriptors
 */
struct i2c_msm_dma_chan {
	bool                     is_init;
	const char              *name;
	size_t                   desc_cnt_cur;
	struct dma_chan         *dma_chan;
	enum dma_transfer_direction dir;
};

enum i2c_msm_dma_chan_dir {
	I2C_MSM_DMA_TX,
	I2C_MSM_DMA_RX,
	I2C_MSM_DMA_CNT,
};

enum i2c_msm_dma_state {
	I2C_MSM_DMA_INIT_NONE, /* Uninitialized  DMA */
	I2C_MSM_DMA_INIT_CORE, /* Core init not channels, memory Allocated */
	I2C_MSM_DMA_INIT_CHAN, /* Both Core and channels are init */
};

/*
 * struct i2c_msm_xfer_mode_dma: DMA mode configuration and work space
 *
 * @state   specifies the DMA core and channel initialization states.
 * @buf_arr_cnt current number of valid buffers in buf_arr. The valid buffers
 *          are at index 0..buf_arr_cnt excluding buf_arr_cnt.
 * @buf_arr array of descriptors which point to the user's buffer
 *     virtual and physical address, and hold meta data about the buffer
 *     and respective tag.
 * @tag_arr array of tags in DMAable memory. Holds a tag per buffer of the same
 *          index, that is tag_arr[i] is related to buf_arr[i]. Also, tag_arr[i]
 *          is queued in the tx channel just befor buf_arr[i] is queued in
 *          the tx (output buf) or rx channel (input buffer).
 * @eot_n_flush_stop_tags EOT and flush-stop tags to be queued to the tx
 *          DMA channel after the last transfer when it is a read.
 * @input_tag hw is placing input tags in the rx channel on read operations.
 *          The value of these tags is "don't care" from DMA transfer
 *          perspective. Thus, this single buffer is used for all the input
 *          tags. The field is used as write only.
 */
struct i2c_msm_xfer_mode_dma {
	enum i2c_msm_dma_state   state;
	size_t                   buf_arr_cnt;
	struct i2c_msm_dma_buf   buf_arr[I2C_MSM_DMA_DESC_ARR_SIZ];
	struct i2c_msm_dma_mem   tag_arr;
	struct i2c_msm_dma_mem   eot_n_flush_stop_tags;
	struct i2c_msm_dma_mem   input_tag;
	struct i2c_msm_dma_chan  chan[I2C_MSM_DMA_CNT];
};

/*
 * I2C_MSM_DMA_TAG_MEM_SZ includes the following fields of
 * struct i2c_msm_xfer_mode_dma (in order):
 *
 * Buffer of DMA memory:
 * +-----------+---------+-----------+-----------+----+-----------+
 * | input_tag | eot_... | tag_arr 0 | tag_arr 1 | .. | tag_arr n |
 * +-----------+---------+-----------+-----------+----+-----------+
 *
 * Why +2?
 * One tag buffer for the input tags. This is a write only buffer for DMA, it is
 *    used to read the tags of the input fifo. We let them overwrite each other,
 *    since it is a throw-away from the driver's perspective.
 * Second tag buffer for the EOT and flush-stop tags. This is a read only
 *    buffer (from DMA perspective). It is used to put EOT and flush-stop at the
 *    end of every transaction.
 */
#define I2C_MSM_DMA_TAG_MEM_SZ  \
	((I2C_MSM_DMA_DESC_ARR_SIZ + 2) * I2C_MSM_TAG2_MAX_LEN)

/*
 * i2c_msm_xfer_mode_fifo: operations and state of FIFO mode
 *
 * @ops     "base class" of i2c_msm_xfer_mode_dma. Contains the operations while
 *          the rest of the fields contain the data.
 * @input_fifo_sz input fifo size in bytes
 * @output_fifo_sz output fifo size in bytes
 * @in_rem  remaining u32 entries in input FIFO before empty
 * @out_rem remaining u32 entries in output FIFO before full
 * @out_buf buffer for collecting bytes to four bytes groups (u32) before
 *          writing them to the output fifo.
 * @out_buf_idx next free index in out_buf. 0..3
 */
struct i2c_msm_xfer_mode_fifo {
	size_t                   input_fifo_sz;
	size_t                   output_fifo_sz;
	size_t                   in_rem;
	size_t                   out_rem;
	u8                       out_buf[4];
	int                      out_buf_idx;
};

/* i2c_msm_xfer_mode_blk: operations and state of Block mode
 *
 * @is_init when true, struct is initialized and requires mem free on exit
 * @in_blk_sz size of input/rx block
 * @out_blk_sz size of output/tx block
 * @tx_cache internal buffer to store tx data
 * @rx_cache internal buffer to store rx data
 * @rx_cache_idx points to the next unread index in rx cache
 * @tx_cache_idx points to the next unwritten index in tx cache
 * @wait_rx_blk completion object to wait on for end of blk rx transfer.
 * @wait_tx_blk completion object to wait on for end of blk tx transfer.
 * @complete_mask applied to QUP_OPERATIONAL to determine when blk
 *  xfer is complete.
 */
struct i2c_msm_xfer_mode_blk {
	bool                     is_init;
	size_t                   in_blk_sz;
	size_t                   out_blk_sz;
	u8                       *tx_cache;
	u8                       *rx_cache;
	int                      rx_cache_idx;
	int                      tx_cache_idx;
	struct completion        wait_rx_blk;
	struct completion        wait_tx_blk;
	u32                      complete_mask;
};

/* INPUT_MODE and OUTPUT_MODE filds of QUP_IO_MODES register */
enum i2c_msm_xfer_mode_id {
	I2C_MSM_XFER_MODE_FIFO,
	I2C_MSM_XFER_MODE_BLOCK,
	I2C_MSM_XFER_MODE_DMA,
	I2C_MSM_XFER_MODE_NONE, /* keep last as a counter */
};


struct i2c_msm_dbgfs {
	struct dentry             *root;
	enum msm_i2_debug_level    dbg_lvl;
	enum i2c_msm_xfer_mode_id  force_xfer_mode;
};

/*
 * qup_i2c_clk_path_vote: data to use bus scaling driver for clock path vote
 *
 * @mstr_id master id number of the i2c core or its wrapper (BLSP/GSBI).
 *       When zero, clock path voting is disabled.
 * @client_hdl when zero, client is not registered with the bus scaling driver,
 *      and bus scaling functionality should not be used. When non zero, it
 *      is a bus scaling client id and may be used to vote for clock path.
 * @reg_err when true, registration error was detected and an error message was
 *      logged. i2c will attempt to re-register but will log error only once.
 *      once registration succeed, the flag is set to false.
 * @actv_only when set, votes when system active and removes the vote when
 *       system goes idle (optimises for performance). When unset, voting using
 *       runtime pm (optimizes for power).
 */
struct qup_i2c_clk_path_vote {
	u32                         mstr_id;
	u32                         client_hdl;
	struct msm_bus_scale_pdata *pdata;
	bool                        reg_err;
	bool                        actv_only;
};

/*
 * i2c_msm_resources: OS resources
 *
 * @mem  I2C controller memory resource from platform data.
 * @base I2C controller virtual base address
 * @clk_freq_in core clock frequency in Hz
 * @clk_freq_out bus clock frequency in Hz
 */
struct i2c_msm_resources {
	struct resource             *mem;
	void __iomem                *base; /* virtual */
	struct clk                  *core_clk;
	struct clk                  *iface_clk;
	int                          clk_freq_in;
	int                          clk_freq_out;
	struct qup_i2c_clk_path_vote clk_path_vote;
	int                          irq;
	bool                         disable_dma;
	struct pinctrl              *pinctrl;
	struct pinctrl_state        *gpio_state_active;
	struct pinctrl_state        *gpio_state_suspend;
};

#define I2C_MSM_PINCTRL_ACTIVE       "i2c_active"
#define I2C_MSM_PINCTRL_SUSPEND      "i2c_sleep"

/*
 * i2c_msm_xfer_buf: current xfer position and preprocessed tags
 *
 * @is_init the buf is marked initialized by the first call to
 *          i2c_msm_xfer_next_buf()
 * @msg_idx   index of the message that the buffer is pointing to
 * @byte_idx  index of first byte in the current buffer
 * @end_idx   count of bytes processed from the current message. This value
 *            is compared against len to find out if buffer is done processing.
 * @len       number of bytes in current buffer.
 * @is_rx when true, current buffer is pointing to a i2c read operation.
 * @slv_addr 8 bit address. This is the i2c_msg->addr + rd/wr bit.
 *
 * Keep track of current position in the client's transfer request and
 * pre-process a transfer's buffer and tags.
 */
struct i2c_msm_xfer_buf {
	bool                       is_init;
	int                        msg_idx;
	int                        byte_idx;
	int                        end_idx;
	int                        len;
	bool                       is_rx;
	bool                       is_last;
	u16                        slv_addr;
	struct i2c_msm_tag         in_tag;
	struct i2c_msm_tag         out_tag;
};

#ifdef DEBUG
#define I2C_MSM_PROF_MAX_EVNTS   (64)
#else
#define I2C_MSM_PROF_MAX_EVNTS   (16)
#endif

/*
 * i2c_msm_prof_event: profiling event
 *
 * @data Additional data about the event. The interpretation of the data is
 *       dependant on the type field.
 * @type event type (see enum i2c_msm_prof_event_type)
 */
struct i2c_msm_prof_event {
	struct timespec time;
	u64             data0;
	u32             data1;
	u32             data2;
	u8              type;
	u8              dump_func_id;
};

enum i2c_msm_err {
	I2C_MSM_NO_ERR = 0,
	I2C_MSM_ERR_NACK,
	I2C_MSM_ERR_ARB_LOST,
	I2C_MSM_ERR_BUS_ERR,
	I2C_MSM_ERR_TIMEOUT,
	I2C_MSM_ERR_CORE_CLK,
	I2C_MSM_ERR_OVR_UNDR_RUN,
};

/*
 * i2c_msm_xfer: A client transfer request. A list of one or more i2c messages
 *
 * @msgs         NULL when no active xfer. Points to array of i2c_msgs
 *               given by the client.
 * @msg_cnt      number of messages in msgs array.
 * @complete     completion object to wait on for end of transfer.
 * @rx_cnt       number of input  bytes in the client's request.
 * @tx_cnt       number of output bytes in the client's request.
 * @rx_ovrhd_cnt number of input  bytes due to tags.
 * @tx_ovrhd_cnt number of output bytes due to tags.
 * @event        profiling data. An array of timestamps of transfer events
 * @event_cnt    number of items in event array.
 * @is_active    true during xfer process and false after xfer end
 * @mtx          mutex to solve multithreaded problem in xfer
 */
struct i2c_msm_xfer {
	struct i2c_msg            *msgs;
	int                        msg_cnt;
	enum i2c_msm_xfer_mode_id  mode_id;
	struct completion          complete;
	size_t                     rx_cnt;
	size_t                     tx_cnt;
	size_t                     rx_ovrhd_cnt;
	size_t                     tx_ovrhd_cnt;
	struct i2c_msm_xfer_buf    cur_buf;
	u32                        timeout;
	bool                       last_is_rx;
	enum i2c_msm_err           err;
	struct i2c_msm_prof_event  event[I2C_MSM_PROF_MAX_EVNTS];
	atomic_t                   event_cnt;
	atomic_t                   is_active;
	struct mutex               mtx;
	struct i2c_msm_xfer_mode_fifo	fifo;
	struct i2c_msm_xfer_mode_blk	blk;
	struct i2c_msm_xfer_mode_dma	dma;
};

/*
 * i2c_msm_ctrl: the driver's main struct
 *
 * @is_init true when
 * @ver info that is different between i2c controller versions
 * @ver_num  ha
 * @xfer     state of the currently processed transfer.
 * @dbgfs    debug-fs root and values that may be set via debug-fs.
 * @rsrcs    resources from platform data including clocks, gpios, irqs, and
 *           memory regions.
 * @mstr_clk_ctl cached value for programming to mstr_clk_ctl register
 */
struct i2c_msm_ctrl {
	struct device             *dev;
	struct i2c_adapter         adapter;
	struct i2c_msm_xfer        xfer;
	struct i2c_msm_dbgfs       dbgfs;
	struct i2c_msm_resources   rsrcs;
	u32                        mstr_clk_ctl;
	enum i2c_msm_power_state   pwr_state;
};

/* Enum for the profiling event types */
enum i2c_msm_prof_evnt_type {
	I2C_MSM_VALID_END,
	I2C_MSM_PIP_DSCN,
	I2C_MSM_PIP_CNCT,
	I2C_MSM_ACTV_END,
	I2C_MSM_IRQ_BGN,
	I2C_MSM_IRQ_END,
	I2C_MSM_XFER_BEG,
	I2C_MSM_XFER_END,
	I2C_MSM_SCAN_SUM,
	I2C_MSM_NEXT_BUF,
	I2C_MSM_COMPLT_OK,
	I2C_MSM_COMPLT_FL,
	I2C_MSM_PROF_RESET,
};

#ifdef CONFIG_I2C_MSM_PROF_DBG
void i2c_msm_dbgfs_init(struct i2c_msm_ctrl *ctrl);

void i2c_msm_dbgfs_teardown(struct i2c_msm_ctrl *ctrl);

/* diagonisis the i2c registers and dump the errors accordingly */
const char *i2c_msm_dbg_tag_to_str(const struct i2c_msm_tag *tag,
						char *buf, size_t buf_len);

void i2c_msm_prof_evnt_dump(struct i2c_msm_ctrl *ctrl);

/* function definitions to be used from the i2c-msm-v2-debug file */
void i2c_msm_prof_evnt_add(struct i2c_msm_ctrl *ctrl,
				enum msm_i2_debug_level dbg_level,
				enum i2c_msm_prof_evnt_type event,
				u64 data0, u32 data1, u32 data2);

int i2c_msm_dbg_qup_reg_dump(struct i2c_msm_ctrl *ctrl);

const char *
i2c_msm_dbg_dma_tag_to_str(const struct i2c_msm_dma_tag *dma_tag, char *buf,
								size_t buf_len);
#else
/* use dummy functions */
static inline void i2c_msm_dbgfs_init(struct i2c_msm_ctrl *ctrl) {}
static inline void i2c_msm_dbgfs_teardown(struct i2c_msm_ctrl *ctrl) {}

static inline const char *i2c_msm_dbg_tag_to_str(const struct i2c_msm_tag *tag,
						char *buf, size_t buf_len)
{
	return NULL;
}
static inline void i2c_msm_prof_evnt_dump(struct i2c_msm_ctrl *ctrl) {}

/* function definitions to be used from the i2c-msm-v2-debug file */
static inline void i2c_msm_prof_evnt_add(struct i2c_msm_ctrl *ctrl,
				enum msm_i2_debug_level dbg_level,
				enum i2c_msm_prof_evnt_type event,
				u64 data0, u32 data1, u32 data2) {}

static inline int i2c_msm_dbg_qup_reg_dump(struct i2c_msm_ctrl *ctrl)
{
	return true;
}
static inline const char *i2c_msm_dbg_dma_tag_to_str(const struct
			i2c_msm_dma_tag * dma_tag, char *buf, size_t buf_len)
{
	return NULL;
}
#endif /* I2C_MSM_V2_PROF_DBG */
#endif /* _I2C_MSM_V2_H */