i2c: Add snapshot of i2c-msm-v2 driver
This commit adds a snapshot of the i2c-msm-v2 driver from kernel-3.18. Kernel-3.18 baseline: e70ad0cd5efdd9dc91a77dcdac31d6132e1315c1 Change-Id: I392a1761ecc324c4a229caf112b1dc4c32a3b9bf Signed-off-by: Girish Mahadevan <girishm@codeaurora.org>
This commit is contained in:
parent
debaf5e67f
commit
a4d4cbd049
5 changed files with 3706 additions and 0 deletions
55
Documentation/devicetree/bindings/i2c/i2c-msm-v2.txt
Normal file
55
Documentation/devicetree/bindings/i2c/i2c-msm-v2.txt
Normal file
|
@ -0,0 +1,55 @@
|
|||
Qualcomm I2C controller
|
||||
|
||||
Required properties:
|
||||
- reg : Offset and length of the register region for the device named in
|
||||
reg-names and has the same index.
|
||||
- reg-names : Register region name(s) referenced in reg above
|
||||
"qup_phys_addr" : Physical address of QUP register space.
|
||||
- compatible : should be "qcom,i2c-msm-v2"
|
||||
- interrupts : Interrupt number which correspond to the entry with the same
|
||||
index in interrupt-names.
|
||||
- interrupt-names: QUP core interrupt name(s) referenced in interrupts above
|
||||
"qup_irq" : QUP interrupt used by the controller.
|
||||
- dmas : DMA engine API's parameters for blsp.
|
||||
<[phandle of the dma controller] [pipe index] [number of descriptors]
|
||||
[sps_connect flags] [sps_register_event flags]>;
|
||||
- dma-names : dma channel names.
|
||||
- qcom,clk-freq-out : Desired I2C bus clock frequency in Hz
|
||||
- qcom,clk-freq-in : Supplied core clock frequency in Hz.
|
||||
|
||||
Required alias:
|
||||
- The desired bus-number is specified by an alias with the following format:
|
||||
'i2c{n}' where n is the bus number.
|
||||
|
||||
Optional property:
|
||||
- qcom,noise-rjct-scl : number of low samples on clock line to consider it low.
|
||||
When missing default to 0.
|
||||
- qcom,noise-rjct-sda : number of low samples on data line to consider it low.
|
||||
When missing default to 0.
|
||||
- qcom,disable-dma : disables DMA transfer mode.
|
||||
- qcom,master-id : Master-port value used on voting for the clock path.
|
||||
- qcom,high-time-clk-div : high time divider value to configure clk-ctl
|
||||
register. When missing, default to the value given in driver.
|
||||
- qcom,fs-clk-div: fs divider value to configure clk-ctl register. When
|
||||
missing, default to the value given in driver.
|
||||
|
||||
Example:
|
||||
aliases {
|
||||
i2c10 = &i2c_10;
|
||||
};
|
||||
|
||||
i2c_10: i2c@f9966000 {
|
||||
compatible = "qcom,i2c-msm-v2";
|
||||
reg-names = "qup_phys_addr", "dma_phys_addr";
|
||||
reg = <0xf9966000 0x1000>;
|
||||
interrupt-names = "qup_irq";
|
||||
interrupts = <0 104 0>;
|
||||
dmas = <&dma_blsp1 14 32 0x20000020 0x20>,
|
||||
<&dma_blsp1 15 64 0x20000020 0x20>;
|
||||
dma-names = "tx", "rx";
|
||||
qcom,clk-freq-out = <100000>;
|
||||
qcom,clk-freq-in = <24000000>;
|
||||
qcom,noise-rjct-scl = <0>;
|
||||
qcom,noise-rjct-sda = <0>;
|
||||
|
||||
};
|
|
@ -1198,4 +1198,16 @@ config I2C_OPAL
|
|||
This driver can also be built as a module. If so, the module will be
|
||||
called as i2c-opal.
|
||||
|
||||
config I2C_MSM_V2
|
||||
tristate "I2C_MSM_V2"
|
||||
depends on ARCH_QCOM
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
built-in I2C interface and its DMA engine on the MSM family
|
||||
processors.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-msm-v2.
|
||||
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -96,6 +96,7 @@ obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o
|
|||
obj-$(CONFIG_I2C_XLR) += i2c-xlr.o
|
||||
obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o
|
||||
obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o
|
||||
obj-$(CONFIG_I2C_MSM_V2) += i2c-msm-v2.o
|
||||
|
||||
# External I2C/SMBus adapter drivers
|
||||
obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o
|
||||
|
|
2977
drivers/i2c/busses/i2c-msm-v2.c
Normal file
2977
drivers/i2c/busses/i2c-msm-v2.c
Normal file
File diff suppressed because it is too large
Load diff
661
include/linux/i2c/i2c-msm-v2.h
Normal file
661
include/linux/i2c/i2c-msm-v2.h
Normal file
|
@ -0,0 +1,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 */
|
Loading…
Add table
Reference in a new issue