12aec85b2SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
22aec85b2SThomas Gleixner // Copyright (C) 2014 Broadcom Corporation
3e6e5dd35SRay Jui
4e6e5dd35SRay Jui #include <linux/delay.h>
5e6e5dd35SRay Jui #include <linux/i2c.h>
6e6e5dd35SRay Jui #include <linux/interrupt.h>
7e6e5dd35SRay Jui #include <linux/io.h>
8e6e5dd35SRay Jui #include <linux/kernel.h>
9e6e5dd35SRay Jui #include <linux/module.h>
1059738ab2SRob Herring #include <linux/of.h>
11e6e5dd35SRay Jui #include <linux/platform_device.h>
12e6e5dd35SRay Jui #include <linux/slab.h>
13e6e5dd35SRay Jui
149a103872SRayagonda Kokatanur #define IDM_CTRL_DIRECT_OFFSET 0x00
15e6e5dd35SRay Jui #define CFG_OFFSET 0x00
16e6e5dd35SRay Jui #define CFG_RESET_SHIFT 31
17e6e5dd35SRay Jui #define CFG_EN_SHIFT 30
18f34b8d90SShreesha Rajashekar #define CFG_SLAVE_ADDR_0_SHIFT 28
19e6e5dd35SRay Jui #define CFG_M_RETRY_CNT_SHIFT 16
20e6e5dd35SRay Jui #define CFG_M_RETRY_CNT_MASK 0x0f
21e6e5dd35SRay Jui
22e6e5dd35SRay Jui #define TIM_CFG_OFFSET 0x04
23e6e5dd35SRay Jui #define TIM_CFG_MODE_400_SHIFT 31
24f34b8d90SShreesha Rajashekar #define TIM_RAND_SLAVE_STRETCH_SHIFT 24
25f34b8d90SShreesha Rajashekar #define TIM_RAND_SLAVE_STRETCH_MASK 0x7f
26f34b8d90SShreesha Rajashekar #define TIM_PERIODIC_SLAVE_STRETCH_SHIFT 16
27f34b8d90SShreesha Rajashekar #define TIM_PERIODIC_SLAVE_STRETCH_MASK 0x7f
28f34b8d90SShreesha Rajashekar
29f34b8d90SShreesha Rajashekar #define S_CFG_SMBUS_ADDR_OFFSET 0x08
30f34b8d90SShreesha Rajashekar #define S_CFG_EN_NIC_SMB_ADDR3_SHIFT 31
31f34b8d90SShreesha Rajashekar #define S_CFG_NIC_SMB_ADDR3_SHIFT 24
32f34b8d90SShreesha Rajashekar #define S_CFG_NIC_SMB_ADDR3_MASK 0x7f
33f34b8d90SShreesha Rajashekar #define S_CFG_EN_NIC_SMB_ADDR2_SHIFT 23
34f34b8d90SShreesha Rajashekar #define S_CFG_NIC_SMB_ADDR2_SHIFT 16
35f34b8d90SShreesha Rajashekar #define S_CFG_NIC_SMB_ADDR2_MASK 0x7f
36f34b8d90SShreesha Rajashekar #define S_CFG_EN_NIC_SMB_ADDR1_SHIFT 15
37f34b8d90SShreesha Rajashekar #define S_CFG_NIC_SMB_ADDR1_SHIFT 8
38f34b8d90SShreesha Rajashekar #define S_CFG_NIC_SMB_ADDR1_MASK 0x7f
39f34b8d90SShreesha Rajashekar #define S_CFG_EN_NIC_SMB_ADDR0_SHIFT 7
40f34b8d90SShreesha Rajashekar #define S_CFG_NIC_SMB_ADDR0_SHIFT 0
41f34b8d90SShreesha Rajashekar #define S_CFG_NIC_SMB_ADDR0_MASK 0x7f
42e6e5dd35SRay Jui
43e6e5dd35SRay Jui #define M_FIFO_CTRL_OFFSET 0x0c
44e6e5dd35SRay Jui #define M_FIFO_RX_FLUSH_SHIFT 31
45e6e5dd35SRay Jui #define M_FIFO_TX_FLUSH_SHIFT 30
46e6e5dd35SRay Jui #define M_FIFO_RX_CNT_SHIFT 16
47e6e5dd35SRay Jui #define M_FIFO_RX_CNT_MASK 0x7f
48e6e5dd35SRay Jui #define M_FIFO_RX_THLD_SHIFT 8
49e6e5dd35SRay Jui #define M_FIFO_RX_THLD_MASK 0x3f
50e6e5dd35SRay Jui
51f34b8d90SShreesha Rajashekar #define S_FIFO_CTRL_OFFSET 0x10
52f34b8d90SShreesha Rajashekar #define S_FIFO_RX_FLUSH_SHIFT 31
53f34b8d90SShreesha Rajashekar #define S_FIFO_TX_FLUSH_SHIFT 30
54f34b8d90SShreesha Rajashekar #define S_FIFO_RX_CNT_SHIFT 16
55f34b8d90SShreesha Rajashekar #define S_FIFO_RX_CNT_MASK 0x7f
56f34b8d90SShreesha Rajashekar #define S_FIFO_RX_THLD_SHIFT 8
57f34b8d90SShreesha Rajashekar #define S_FIFO_RX_THLD_MASK 0x3f
58f34b8d90SShreesha Rajashekar
59e6e5dd35SRay Jui #define M_CMD_OFFSET 0x30
60e6e5dd35SRay Jui #define M_CMD_START_BUSY_SHIFT 31
61e6e5dd35SRay Jui #define M_CMD_STATUS_SHIFT 25
62e6e5dd35SRay Jui #define M_CMD_STATUS_MASK 0x07
63e6e5dd35SRay Jui #define M_CMD_STATUS_SUCCESS 0x0
64e6e5dd35SRay Jui #define M_CMD_STATUS_LOST_ARB 0x1
65e6e5dd35SRay Jui #define M_CMD_STATUS_NACK_ADDR 0x2
66e6e5dd35SRay Jui #define M_CMD_STATUS_NACK_DATA 0x3
67e6e5dd35SRay Jui #define M_CMD_STATUS_TIMEOUT 0x4
681b23fa2eSMichael Cheng #define M_CMD_STATUS_FIFO_UNDERRUN 0x5
691b23fa2eSMichael Cheng #define M_CMD_STATUS_RX_FIFO_FULL 0x6
70e6e5dd35SRay Jui #define M_CMD_PROTOCOL_SHIFT 9
71e6e5dd35SRay Jui #define M_CMD_PROTOCOL_MASK 0xf
72e14d796dSRayagonda Kokatanur #define M_CMD_PROTOCOL_QUICK 0x0
73e6e5dd35SRay Jui #define M_CMD_PROTOCOL_BLK_WR 0x7
74e6e5dd35SRay Jui #define M_CMD_PROTOCOL_BLK_RD 0x8
755a5e277bSLori Hikichi #define M_CMD_PROTOCOL_PROCESS 0xa
76e6e5dd35SRay Jui #define M_CMD_PEC_SHIFT 8
77e6e5dd35SRay Jui #define M_CMD_RD_CNT_SHIFT 0
78e6e5dd35SRay Jui #define M_CMD_RD_CNT_MASK 0xff
79e6e5dd35SRay Jui
80f34b8d90SShreesha Rajashekar #define S_CMD_OFFSET 0x34
81f34b8d90SShreesha Rajashekar #define S_CMD_START_BUSY_SHIFT 31
82f34b8d90SShreesha Rajashekar #define S_CMD_STATUS_SHIFT 23
83f34b8d90SShreesha Rajashekar #define S_CMD_STATUS_MASK 0x07
84f34b8d90SShreesha Rajashekar #define S_CMD_STATUS_SUCCESS 0x0
85f34b8d90SShreesha Rajashekar #define S_CMD_STATUS_TIMEOUT 0x5
861ca1b451SRayagonda Kokatanur #define S_CMD_STATUS_MASTER_ABORT 0x7
87f34b8d90SShreesha Rajashekar
88e6e5dd35SRay Jui #define IE_OFFSET 0x38
89e6e5dd35SRay Jui #define IE_M_RX_FIFO_FULL_SHIFT 31
90e6e5dd35SRay Jui #define IE_M_RX_THLD_SHIFT 30
91e6e5dd35SRay Jui #define IE_M_START_BUSY_SHIFT 28
924916eb69SRay Jui #define IE_M_TX_UNDERRUN_SHIFT 27
93f34b8d90SShreesha Rajashekar #define IE_S_RX_FIFO_FULL_SHIFT 26
94f34b8d90SShreesha Rajashekar #define IE_S_RX_THLD_SHIFT 25
95f34b8d90SShreesha Rajashekar #define IE_S_RX_EVENT_SHIFT 24
96f34b8d90SShreesha Rajashekar #define IE_S_START_BUSY_SHIFT 23
97f34b8d90SShreesha Rajashekar #define IE_S_TX_UNDERRUN_SHIFT 22
98f34b8d90SShreesha Rajashekar #define IE_S_RD_EVENT_SHIFT 21
99e6e5dd35SRay Jui
100e6e5dd35SRay Jui #define IS_OFFSET 0x3c
101e6e5dd35SRay Jui #define IS_M_RX_FIFO_FULL_SHIFT 31
102e6e5dd35SRay Jui #define IS_M_RX_THLD_SHIFT 30
103e6e5dd35SRay Jui #define IS_M_START_BUSY_SHIFT 28
1044916eb69SRay Jui #define IS_M_TX_UNDERRUN_SHIFT 27
105f34b8d90SShreesha Rajashekar #define IS_S_RX_FIFO_FULL_SHIFT 26
106f34b8d90SShreesha Rajashekar #define IS_S_RX_THLD_SHIFT 25
107f34b8d90SShreesha Rajashekar #define IS_S_RX_EVENT_SHIFT 24
108f34b8d90SShreesha Rajashekar #define IS_S_START_BUSY_SHIFT 23
109f34b8d90SShreesha Rajashekar #define IS_S_TX_UNDERRUN_SHIFT 22
110f34b8d90SShreesha Rajashekar #define IS_S_RD_EVENT_SHIFT 21
111e6e5dd35SRay Jui
112e6e5dd35SRay Jui #define M_TX_OFFSET 0x40
113e6e5dd35SRay Jui #define M_TX_WR_STATUS_SHIFT 31
114e6e5dd35SRay Jui #define M_TX_DATA_SHIFT 0
115e6e5dd35SRay Jui #define M_TX_DATA_MASK 0xff
116e6e5dd35SRay Jui
117e6e5dd35SRay Jui #define M_RX_OFFSET 0x44
118e6e5dd35SRay Jui #define M_RX_STATUS_SHIFT 30
119e6e5dd35SRay Jui #define M_RX_STATUS_MASK 0x03
120e6e5dd35SRay Jui #define M_RX_PEC_ERR_SHIFT 29
121e6e5dd35SRay Jui #define M_RX_DATA_SHIFT 0
122e6e5dd35SRay Jui #define M_RX_DATA_MASK 0xff
123e6e5dd35SRay Jui
124f34b8d90SShreesha Rajashekar #define S_TX_OFFSET 0x48
125f34b8d90SShreesha Rajashekar #define S_TX_WR_STATUS_SHIFT 31
126f34b8d90SShreesha Rajashekar #define S_TX_DATA_SHIFT 0
127f34b8d90SShreesha Rajashekar #define S_TX_DATA_MASK 0xff
128f34b8d90SShreesha Rajashekar
129f34b8d90SShreesha Rajashekar #define S_RX_OFFSET 0x4c
130f34b8d90SShreesha Rajashekar #define S_RX_STATUS_SHIFT 30
131f34b8d90SShreesha Rajashekar #define S_RX_STATUS_MASK 0x03
132f34b8d90SShreesha Rajashekar #define S_RX_PEC_ERR_SHIFT 29
133f34b8d90SShreesha Rajashekar #define S_RX_DATA_SHIFT 0
134f34b8d90SShreesha Rajashekar #define S_RX_DATA_MASK 0xff
135f34b8d90SShreesha Rajashekar
1364916eb69SRay Jui #define I2C_TIMEOUT_MSEC 50000
137e6e5dd35SRay Jui #define M_TX_RX_FIFO_SIZE 64
138c24b8d57SShreesha Rajashekar #define M_RX_FIFO_MAX_THLD_VALUE (M_TX_RX_FIFO_SIZE - 1)
139c24b8d57SShreesha Rajashekar
140c24b8d57SShreesha Rajashekar #define M_RX_MAX_READ_LEN 255
141c24b8d57SShreesha Rajashekar #define M_RX_FIFO_THLD_VALUE 50
142e6e5dd35SRay Jui
143f34b8d90SShreesha Rajashekar #define IE_M_ALL_INTERRUPT_SHIFT 27
144f34b8d90SShreesha Rajashekar #define IE_M_ALL_INTERRUPT_MASK 0x1e
145f34b8d90SShreesha Rajashekar
146f34b8d90SShreesha Rajashekar #define SLAVE_READ_WRITE_BIT_MASK 0x1
147f34b8d90SShreesha Rajashekar #define SLAVE_READ_WRITE_BIT_SHIFT 0x1
148f34b8d90SShreesha Rajashekar #define SLAVE_MAX_SIZE_TRANSACTION 64
149f34b8d90SShreesha Rajashekar #define SLAVE_CLOCK_STRETCH_TIME 25
150f34b8d90SShreesha Rajashekar
151f34b8d90SShreesha Rajashekar #define IE_S_ALL_INTERRUPT_SHIFT 21
152f34b8d90SShreesha Rajashekar #define IE_S_ALL_INTERRUPT_MASK 0x3f
153e21d7977SRayagonda Kokatanur /*
154e21d7977SRayagonda Kokatanur * It takes ~18us to reading 10bytes of data, hence to keep tasklet
155e21d7977SRayagonda Kokatanur * running for less time, max slave read per tasklet is set to 10 bytes.
156e21d7977SRayagonda Kokatanur */
157e21d7977SRayagonda Kokatanur #define MAX_SLAVE_RX_PER_INT 10
158f34b8d90SShreesha Rajashekar
159f34b8d90SShreesha Rajashekar enum i2c_slave_read_status {
160f34b8d90SShreesha Rajashekar I2C_SLAVE_RX_FIFO_EMPTY = 0,
161f34b8d90SShreesha Rajashekar I2C_SLAVE_RX_START,
162f34b8d90SShreesha Rajashekar I2C_SLAVE_RX_DATA,
163f34b8d90SShreesha Rajashekar I2C_SLAVE_RX_END,
164f34b8d90SShreesha Rajashekar };
165f34b8d90SShreesha Rajashekar
166e6e5dd35SRay Jui enum bus_speed_index {
167e6e5dd35SRay Jui I2C_SPD_100K = 0,
168e6e5dd35SRay Jui I2C_SPD_400K,
169e6e5dd35SRay Jui };
170e6e5dd35SRay Jui
1719a103872SRayagonda Kokatanur enum bcm_iproc_i2c_type {
1729a103872SRayagonda Kokatanur IPROC_I2C,
1739a103872SRayagonda Kokatanur IPROC_I2C_NIC
1749a103872SRayagonda Kokatanur };
1759a103872SRayagonda Kokatanur
176e6e5dd35SRay Jui struct bcm_iproc_i2c_dev {
177e6e5dd35SRay Jui struct device *device;
1789a103872SRayagonda Kokatanur enum bcm_iproc_i2c_type type;
179e6e5dd35SRay Jui int irq;
180e6e5dd35SRay Jui
181e6e5dd35SRay Jui void __iomem *base;
1829a103872SRayagonda Kokatanur void __iomem *idm_base;
1839a103872SRayagonda Kokatanur
1849a103872SRayagonda Kokatanur u32 ape_addr_mask;
1859a103872SRayagonda Kokatanur
1869a103872SRayagonda Kokatanur /* lock for indirect access through IDM */
1879a103872SRayagonda Kokatanur spinlock_t idm_lock;
188e6e5dd35SRay Jui
189e6e5dd35SRay Jui struct i2c_adapter adapter;
1900ee04e91SRay Jui unsigned int bus_speed;
191e6e5dd35SRay Jui
192e6e5dd35SRay Jui struct completion done;
193e6e5dd35SRay Jui int xfer_is_done;
1944916eb69SRay Jui
1954916eb69SRay Jui struct i2c_msg *msg;
1964916eb69SRay Jui
197f34b8d90SShreesha Rajashekar struct i2c_client *slave;
198f34b8d90SShreesha Rajashekar
1994916eb69SRay Jui /* bytes that have been transferred */
2004916eb69SRay Jui unsigned int tx_bytes;
201c24b8d57SShreesha Rajashekar /* bytes that have been read */
202c24b8d57SShreesha Rajashekar unsigned int rx_bytes;
203c24b8d57SShreesha Rajashekar unsigned int thld_bytes;
204e21d7977SRayagonda Kokatanur
205e21d7977SRayagonda Kokatanur bool slave_rx_only;
206e21d7977SRayagonda Kokatanur bool rx_start_rcvd;
207e21d7977SRayagonda Kokatanur bool slave_read_complete;
208e21d7977SRayagonda Kokatanur u32 tx_underrun;
209e21d7977SRayagonda Kokatanur u32 slave_int_mask;
210e21d7977SRayagonda Kokatanur struct tasklet_struct slave_rx_tasklet;
211e6e5dd35SRay Jui };
212e6e5dd35SRay Jui
213e21d7977SRayagonda Kokatanur /* tasklet to process slave rx data */
214e21d7977SRayagonda Kokatanur static void slave_rx_tasklet_fn(unsigned long);
215e21d7977SRayagonda Kokatanur
216e6e5dd35SRay Jui /*
217e6e5dd35SRay Jui * Can be expanded in the future if more interrupt status bits are utilized
218e6e5dd35SRay Jui */
219c24b8d57SShreesha Rajashekar #define ISR_MASK (BIT(IS_M_START_BUSY_SHIFT) | BIT(IS_M_TX_UNDERRUN_SHIFT)\
220c24b8d57SShreesha Rajashekar | BIT(IS_M_RX_THLD_SHIFT))
221c24b8d57SShreesha Rajashekar
222f34b8d90SShreesha Rajashekar #define ISR_MASK_SLAVE (BIT(IS_S_START_BUSY_SHIFT)\
223c245d94eSRayagonda Kokatanur | BIT(IS_S_RX_EVENT_SHIFT) | BIT(IS_S_RD_EVENT_SHIFT)\
224603e77afSRayagonda Kokatanur | BIT(IS_S_TX_UNDERRUN_SHIFT) | BIT(IS_S_RX_FIFO_FULL_SHIFT)\
225603e77afSRayagonda Kokatanur | BIT(IS_S_RX_THLD_SHIFT))
226f34b8d90SShreesha Rajashekar
227f34b8d90SShreesha Rajashekar static int bcm_iproc_i2c_reg_slave(struct i2c_client *slave);
228f34b8d90SShreesha Rajashekar static int bcm_iproc_i2c_unreg_slave(struct i2c_client *slave);
229f34b8d90SShreesha Rajashekar static void bcm_iproc_i2c_enable_disable(struct bcm_iproc_i2c_dev *iproc_i2c,
230f34b8d90SShreesha Rajashekar bool enable);
231f34b8d90SShreesha Rajashekar
iproc_i2c_rd_reg(struct bcm_iproc_i2c_dev * iproc_i2c,u32 offset)232a9f0a81eSRayagonda Kokatanur static inline u32 iproc_i2c_rd_reg(struct bcm_iproc_i2c_dev *iproc_i2c,
233a9f0a81eSRayagonda Kokatanur u32 offset)
234a9f0a81eSRayagonda Kokatanur {
2359a103872SRayagonda Kokatanur u32 val;
2364caf4cb1SChengfeng Ye unsigned long flags;
2379a103872SRayagonda Kokatanur
2389a103872SRayagonda Kokatanur if (iproc_i2c->idm_base) {
2394caf4cb1SChengfeng Ye spin_lock_irqsave(&iproc_i2c->idm_lock, flags);
2409a103872SRayagonda Kokatanur writel(iproc_i2c->ape_addr_mask,
2419a103872SRayagonda Kokatanur iproc_i2c->idm_base + IDM_CTRL_DIRECT_OFFSET);
2429a103872SRayagonda Kokatanur val = readl(iproc_i2c->base + offset);
2434caf4cb1SChengfeng Ye spin_unlock_irqrestore(&iproc_i2c->idm_lock, flags);
2449a103872SRayagonda Kokatanur } else {
2459a103872SRayagonda Kokatanur val = readl(iproc_i2c->base + offset);
2469a103872SRayagonda Kokatanur }
2479a103872SRayagonda Kokatanur
2489a103872SRayagonda Kokatanur return val;
249a9f0a81eSRayagonda Kokatanur }
250a9f0a81eSRayagonda Kokatanur
iproc_i2c_wr_reg(struct bcm_iproc_i2c_dev * iproc_i2c,u32 offset,u32 val)251a9f0a81eSRayagonda Kokatanur static inline void iproc_i2c_wr_reg(struct bcm_iproc_i2c_dev *iproc_i2c,
252a9f0a81eSRayagonda Kokatanur u32 offset, u32 val)
253a9f0a81eSRayagonda Kokatanur {
2544caf4cb1SChengfeng Ye unsigned long flags;
2554caf4cb1SChengfeng Ye
2569a103872SRayagonda Kokatanur if (iproc_i2c->idm_base) {
2574caf4cb1SChengfeng Ye spin_lock_irqsave(&iproc_i2c->idm_lock, flags);
2589a103872SRayagonda Kokatanur writel(iproc_i2c->ape_addr_mask,
2599a103872SRayagonda Kokatanur iproc_i2c->idm_base + IDM_CTRL_DIRECT_OFFSET);
260a9f0a81eSRayagonda Kokatanur writel(val, iproc_i2c->base + offset);
2614caf4cb1SChengfeng Ye spin_unlock_irqrestore(&iproc_i2c->idm_lock, flags);
2629a103872SRayagonda Kokatanur } else {
2639a103872SRayagonda Kokatanur writel(val, iproc_i2c->base + offset);
2649a103872SRayagonda Kokatanur }
265a9f0a81eSRayagonda Kokatanur }
266a9f0a81eSRayagonda Kokatanur
bcm_iproc_i2c_slave_init(struct bcm_iproc_i2c_dev * iproc_i2c,bool need_reset)267f34b8d90SShreesha Rajashekar static void bcm_iproc_i2c_slave_init(
268f34b8d90SShreesha Rajashekar struct bcm_iproc_i2c_dev *iproc_i2c, bool need_reset)
269f34b8d90SShreesha Rajashekar {
270f34b8d90SShreesha Rajashekar u32 val;
271f34b8d90SShreesha Rajashekar
272e21d7977SRayagonda Kokatanur iproc_i2c->tx_underrun = 0;
273f34b8d90SShreesha Rajashekar if (need_reset) {
274f34b8d90SShreesha Rajashekar /* put controller in reset */
275a9f0a81eSRayagonda Kokatanur val = iproc_i2c_rd_reg(iproc_i2c, CFG_OFFSET);
276f34b8d90SShreesha Rajashekar val |= BIT(CFG_RESET_SHIFT);
277a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, CFG_OFFSET, val);
278f34b8d90SShreesha Rajashekar
279f34b8d90SShreesha Rajashekar /* wait 100 usec per spec */
280f34b8d90SShreesha Rajashekar udelay(100);
281f34b8d90SShreesha Rajashekar
282f34b8d90SShreesha Rajashekar /* bring controller out of reset */
283f34b8d90SShreesha Rajashekar val &= ~(BIT(CFG_RESET_SHIFT));
284a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, CFG_OFFSET, val);
285f34b8d90SShreesha Rajashekar }
286f34b8d90SShreesha Rajashekar
287f34b8d90SShreesha Rajashekar /* flush TX/RX FIFOs */
288f34b8d90SShreesha Rajashekar val = (BIT(S_FIFO_RX_FLUSH_SHIFT) | BIT(S_FIFO_TX_FLUSH_SHIFT));
289a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, S_FIFO_CTRL_OFFSET, val);
290f34b8d90SShreesha Rajashekar
291f34b8d90SShreesha Rajashekar /* Maximum slave stretch time */
292a9f0a81eSRayagonda Kokatanur val = iproc_i2c_rd_reg(iproc_i2c, TIM_CFG_OFFSET);
293f34b8d90SShreesha Rajashekar val &= ~(TIM_RAND_SLAVE_STRETCH_MASK << TIM_RAND_SLAVE_STRETCH_SHIFT);
294f34b8d90SShreesha Rajashekar val |= (SLAVE_CLOCK_STRETCH_TIME << TIM_RAND_SLAVE_STRETCH_SHIFT);
295a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, TIM_CFG_OFFSET, val);
296f34b8d90SShreesha Rajashekar
297f34b8d90SShreesha Rajashekar /* Configure the slave address */
298a9f0a81eSRayagonda Kokatanur val = iproc_i2c_rd_reg(iproc_i2c, S_CFG_SMBUS_ADDR_OFFSET);
299f34b8d90SShreesha Rajashekar val |= BIT(S_CFG_EN_NIC_SMB_ADDR3_SHIFT);
300f34b8d90SShreesha Rajashekar val &= ~(S_CFG_NIC_SMB_ADDR3_MASK << S_CFG_NIC_SMB_ADDR3_SHIFT);
301f34b8d90SShreesha Rajashekar val |= (iproc_i2c->slave->addr << S_CFG_NIC_SMB_ADDR3_SHIFT);
302a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, S_CFG_SMBUS_ADDR_OFFSET, val);
303f34b8d90SShreesha Rajashekar
304f34b8d90SShreesha Rajashekar /* clear all pending slave interrupts */
305a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, ISR_MASK_SLAVE);
306f34b8d90SShreesha Rajashekar
307f34b8d90SShreesha Rajashekar /* Enable interrupt register to indicate a valid byte in receive fifo */
308c245d94eSRayagonda Kokatanur val = BIT(IE_S_RX_EVENT_SHIFT);
3094d658451SRayagonda Kokatanur /* Enable interrupt register to indicate Slave Rx FIFO Full */
3104d658451SRayagonda Kokatanur val |= BIT(IE_S_RX_FIFO_FULL_SHIFT);
311e21d7977SRayagonda Kokatanur /* Enable interrupt register to indicate a Master read transaction */
312e21d7977SRayagonda Kokatanur val |= BIT(IE_S_RD_EVENT_SHIFT);
313f34b8d90SShreesha Rajashekar /* Enable interrupt register for the Slave BUSY command */
314f34b8d90SShreesha Rajashekar val |= BIT(IE_S_START_BUSY_SHIFT);
315e21d7977SRayagonda Kokatanur iproc_i2c->slave_int_mask = val;
316a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
317f34b8d90SShreesha Rajashekar }
318f34b8d90SShreesha Rajashekar
bcm_iproc_i2c_check_slave_status(struct bcm_iproc_i2c_dev * iproc_i2c,u32 status)319*b925c9deSRoman Bacik static bool bcm_iproc_i2c_check_slave_status
320*b925c9deSRoman Bacik (struct bcm_iproc_i2c_dev *iproc_i2c, u32 status)
321f34b8d90SShreesha Rajashekar {
322f34b8d90SShreesha Rajashekar u32 val;
323*b925c9deSRoman Bacik bool recover = false;
324f34b8d90SShreesha Rajashekar
325*b925c9deSRoman Bacik /* check slave transmit status only if slave is transmitting */
326*b925c9deSRoman Bacik if (!iproc_i2c->slave_rx_only) {
327a9f0a81eSRayagonda Kokatanur val = iproc_i2c_rd_reg(iproc_i2c, S_CMD_OFFSET);
328*b925c9deSRoman Bacik /* status is valid only when START_BUSY is cleared */
329*b925c9deSRoman Bacik if (!(val & BIT(S_CMD_START_BUSY_SHIFT))) {
330c245d94eSRayagonda Kokatanur val = (val >> S_CMD_STATUS_SHIFT) & S_CMD_STATUS_MASK;
331*b925c9deSRoman Bacik if (val == S_CMD_STATUS_TIMEOUT ||
332*b925c9deSRoman Bacik val == S_CMD_STATUS_MASTER_ABORT) {
333*b925c9deSRoman Bacik dev_warn(iproc_i2c->device,
334*b925c9deSRoman Bacik (val == S_CMD_STATUS_TIMEOUT) ?
3351ca1b451SRayagonda Kokatanur "slave random stretch time timeout\n" :
3361ca1b451SRayagonda Kokatanur "Master aborted read transaction\n");
337*b925c9deSRoman Bacik recover = true;
338*b925c9deSRoman Bacik }
339*b925c9deSRoman Bacik }
340*b925c9deSRoman Bacik }
341*b925c9deSRoman Bacik
342*b925c9deSRoman Bacik /* RX_EVENT is not valid when START_BUSY is set */
343*b925c9deSRoman Bacik if ((status & BIT(IS_S_RX_EVENT_SHIFT)) &&
344*b925c9deSRoman Bacik (status & BIT(IS_S_START_BUSY_SHIFT))) {
345*b925c9deSRoman Bacik dev_warn(iproc_i2c->device, "Slave aborted read transaction\n");
346*b925c9deSRoman Bacik recover = true;
347*b925c9deSRoman Bacik }
348*b925c9deSRoman Bacik
349*b925c9deSRoman Bacik if (recover) {
350f34b8d90SShreesha Rajashekar /* re-initialize i2c for recovery */
351f34b8d90SShreesha Rajashekar bcm_iproc_i2c_enable_disable(iproc_i2c, false);
352f34b8d90SShreesha Rajashekar bcm_iproc_i2c_slave_init(iproc_i2c, true);
353f34b8d90SShreesha Rajashekar bcm_iproc_i2c_enable_disable(iproc_i2c, true);
354f34b8d90SShreesha Rajashekar }
355*b925c9deSRoman Bacik
356*b925c9deSRoman Bacik return recover;
357f34b8d90SShreesha Rajashekar }
358f34b8d90SShreesha Rajashekar
bcm_iproc_i2c_slave_read(struct bcm_iproc_i2c_dev * iproc_i2c)359e21d7977SRayagonda Kokatanur static void bcm_iproc_i2c_slave_read(struct bcm_iproc_i2c_dev *iproc_i2c)
360e21d7977SRayagonda Kokatanur {
361e21d7977SRayagonda Kokatanur u8 rx_data, rx_status;
362e21d7977SRayagonda Kokatanur u32 rx_bytes = 0;
363e21d7977SRayagonda Kokatanur u32 val;
364e21d7977SRayagonda Kokatanur
365e21d7977SRayagonda Kokatanur while (rx_bytes < MAX_SLAVE_RX_PER_INT) {
366e21d7977SRayagonda Kokatanur val = iproc_i2c_rd_reg(iproc_i2c, S_RX_OFFSET);
367e21d7977SRayagonda Kokatanur rx_status = (val >> S_RX_STATUS_SHIFT) & S_RX_STATUS_MASK;
368e21d7977SRayagonda Kokatanur rx_data = ((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK);
369e21d7977SRayagonda Kokatanur
370e21d7977SRayagonda Kokatanur if (rx_status == I2C_SLAVE_RX_START) {
371e21d7977SRayagonda Kokatanur /* Start of SMBUS Master write */
372e21d7977SRayagonda Kokatanur i2c_slave_event(iproc_i2c->slave,
373e21d7977SRayagonda Kokatanur I2C_SLAVE_WRITE_REQUESTED, &rx_data);
374e21d7977SRayagonda Kokatanur iproc_i2c->rx_start_rcvd = true;
375e21d7977SRayagonda Kokatanur iproc_i2c->slave_read_complete = false;
376e21d7977SRayagonda Kokatanur } else if (rx_status == I2C_SLAVE_RX_DATA &&
377e21d7977SRayagonda Kokatanur iproc_i2c->rx_start_rcvd) {
378e21d7977SRayagonda Kokatanur /* Middle of SMBUS Master write */
379e21d7977SRayagonda Kokatanur i2c_slave_event(iproc_i2c->slave,
380e21d7977SRayagonda Kokatanur I2C_SLAVE_WRITE_RECEIVED, &rx_data);
381e21d7977SRayagonda Kokatanur } else if (rx_status == I2C_SLAVE_RX_END &&
382e21d7977SRayagonda Kokatanur iproc_i2c->rx_start_rcvd) {
383e21d7977SRayagonda Kokatanur /* End of SMBUS Master write */
384e21d7977SRayagonda Kokatanur if (iproc_i2c->slave_rx_only)
385e21d7977SRayagonda Kokatanur i2c_slave_event(iproc_i2c->slave,
386e21d7977SRayagonda Kokatanur I2C_SLAVE_WRITE_RECEIVED,
387e21d7977SRayagonda Kokatanur &rx_data);
388e21d7977SRayagonda Kokatanur
389e21d7977SRayagonda Kokatanur i2c_slave_event(iproc_i2c->slave, I2C_SLAVE_STOP,
390e21d7977SRayagonda Kokatanur &rx_data);
391e21d7977SRayagonda Kokatanur } else if (rx_status == I2C_SLAVE_RX_FIFO_EMPTY) {
392e21d7977SRayagonda Kokatanur iproc_i2c->rx_start_rcvd = false;
393e21d7977SRayagonda Kokatanur iproc_i2c->slave_read_complete = true;
394e21d7977SRayagonda Kokatanur break;
395e21d7977SRayagonda Kokatanur }
396e21d7977SRayagonda Kokatanur
397e21d7977SRayagonda Kokatanur rx_bytes++;
398e21d7977SRayagonda Kokatanur }
399e21d7977SRayagonda Kokatanur }
400e21d7977SRayagonda Kokatanur
slave_rx_tasklet_fn(unsigned long data)401e21d7977SRayagonda Kokatanur static void slave_rx_tasklet_fn(unsigned long data)
402e21d7977SRayagonda Kokatanur {
403e21d7977SRayagonda Kokatanur struct bcm_iproc_i2c_dev *iproc_i2c = (struct bcm_iproc_i2c_dev *)data;
404e21d7977SRayagonda Kokatanur u32 int_clr;
405e21d7977SRayagonda Kokatanur
406e21d7977SRayagonda Kokatanur bcm_iproc_i2c_slave_read(iproc_i2c);
407e21d7977SRayagonda Kokatanur
408e21d7977SRayagonda Kokatanur /* clear pending IS_S_RX_EVENT_SHIFT interrupt */
409e21d7977SRayagonda Kokatanur int_clr = BIT(IS_S_RX_EVENT_SHIFT);
410e21d7977SRayagonda Kokatanur
411e21d7977SRayagonda Kokatanur if (!iproc_i2c->slave_rx_only && iproc_i2c->slave_read_complete) {
412e21d7977SRayagonda Kokatanur /*
413e21d7977SRayagonda Kokatanur * In case of single byte master-read request,
414e21d7977SRayagonda Kokatanur * IS_S_TX_UNDERRUN_SHIFT event is generated before
415e21d7977SRayagonda Kokatanur * IS_S_START_BUSY_SHIFT event. Hence start slave data send
416e21d7977SRayagonda Kokatanur * from first IS_S_TX_UNDERRUN_SHIFT event.
417e21d7977SRayagonda Kokatanur *
418e21d7977SRayagonda Kokatanur * This means don't send any data from slave when
419e21d7977SRayagonda Kokatanur * IS_S_RD_EVENT_SHIFT event is generated else it will increment
420e21d7977SRayagonda Kokatanur * eeprom or other backend slave driver read pointer twice.
421e21d7977SRayagonda Kokatanur */
422e21d7977SRayagonda Kokatanur iproc_i2c->tx_underrun = 0;
423e21d7977SRayagonda Kokatanur iproc_i2c->slave_int_mask |= BIT(IE_S_TX_UNDERRUN_SHIFT);
424e21d7977SRayagonda Kokatanur
425e21d7977SRayagonda Kokatanur /* clear IS_S_RD_EVENT_SHIFT interrupt */
426e21d7977SRayagonda Kokatanur int_clr |= BIT(IS_S_RD_EVENT_SHIFT);
427e21d7977SRayagonda Kokatanur }
428e21d7977SRayagonda Kokatanur
429e21d7977SRayagonda Kokatanur /* clear slave interrupt */
430e21d7977SRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, int_clr);
431e21d7977SRayagonda Kokatanur /* enable slave interrupts */
432e21d7977SRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, iproc_i2c->slave_int_mask);
433e21d7977SRayagonda Kokatanur }
434e21d7977SRayagonda Kokatanur
bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev * iproc_i2c,u32 status)435f34b8d90SShreesha Rajashekar static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c,
436f34b8d90SShreesha Rajashekar u32 status)
437f34b8d90SShreesha Rajashekar {
438f34b8d90SShreesha Rajashekar u32 val;
439e21d7977SRayagonda Kokatanur u8 value;
440f34b8d90SShreesha Rajashekar
441*b925c9deSRoman Bacik
442*b925c9deSRoman Bacik if (status & BIT(IS_S_TX_UNDERRUN_SHIFT)) {
443*b925c9deSRoman Bacik iproc_i2c->tx_underrun++;
444*b925c9deSRoman Bacik if (iproc_i2c->tx_underrun == 1)
445*b925c9deSRoman Bacik /* Start of SMBUS for Master Read */
446*b925c9deSRoman Bacik i2c_slave_event(iproc_i2c->slave,
447*b925c9deSRoman Bacik I2C_SLAVE_READ_REQUESTED,
448*b925c9deSRoman Bacik &value);
449*b925c9deSRoman Bacik else
450*b925c9deSRoman Bacik /* Master read other than start */
451*b925c9deSRoman Bacik i2c_slave_event(iproc_i2c->slave,
452*b925c9deSRoman Bacik I2C_SLAVE_READ_PROCESSED,
453*b925c9deSRoman Bacik &value);
454*b925c9deSRoman Bacik
455*b925c9deSRoman Bacik iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, value);
456*b925c9deSRoman Bacik /* start transfer */
457*b925c9deSRoman Bacik val = BIT(S_CMD_START_BUSY_SHIFT);
458*b925c9deSRoman Bacik iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val);
459*b925c9deSRoman Bacik
460*b925c9deSRoman Bacik /* clear interrupt */
461*b925c9deSRoman Bacik iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET,
462*b925c9deSRoman Bacik BIT(IS_S_TX_UNDERRUN_SHIFT));
463*b925c9deSRoman Bacik }
464*b925c9deSRoman Bacik
465*b925c9deSRoman Bacik /* Stop received from master in case of master read transaction */
466*b925c9deSRoman Bacik if (status & BIT(IS_S_START_BUSY_SHIFT)) {
467*b925c9deSRoman Bacik /*
468*b925c9deSRoman Bacik * Disable interrupt for TX FIFO becomes empty and
469*b925c9deSRoman Bacik * less than PKT_LENGTH bytes were output on the SMBUS
470*b925c9deSRoman Bacik */
471*b925c9deSRoman Bacik iproc_i2c->slave_int_mask &= ~BIT(IE_S_TX_UNDERRUN_SHIFT);
472*b925c9deSRoman Bacik val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
473*b925c9deSRoman Bacik val &= ~BIT(IE_S_TX_UNDERRUN_SHIFT);
474*b925c9deSRoman Bacik iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
475*b925c9deSRoman Bacik
476*b925c9deSRoman Bacik /* End of SMBUS for Master Read */
477*b925c9deSRoman Bacik val = BIT(S_TX_WR_STATUS_SHIFT);
478*b925c9deSRoman Bacik iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, val);
479*b925c9deSRoman Bacik
480*b925c9deSRoman Bacik val = BIT(S_CMD_START_BUSY_SHIFT);
481*b925c9deSRoman Bacik iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val);
482*b925c9deSRoman Bacik
483*b925c9deSRoman Bacik /* flush TX FIFOs */
484*b925c9deSRoman Bacik val = iproc_i2c_rd_reg(iproc_i2c, S_FIFO_CTRL_OFFSET);
485*b925c9deSRoman Bacik val |= (BIT(S_FIFO_TX_FLUSH_SHIFT));
486*b925c9deSRoman Bacik iproc_i2c_wr_reg(iproc_i2c, S_FIFO_CTRL_OFFSET, val);
487*b925c9deSRoman Bacik
488*b925c9deSRoman Bacik i2c_slave_event(iproc_i2c->slave, I2C_SLAVE_STOP, &value);
489*b925c9deSRoman Bacik
490*b925c9deSRoman Bacik /* clear interrupt */
491*b925c9deSRoman Bacik iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET,
492*b925c9deSRoman Bacik BIT(IS_S_START_BUSY_SHIFT));
493*b925c9deSRoman Bacik }
494*b925c9deSRoman Bacik
495*b925c9deSRoman Bacik /* if the controller has been reset, immediately return from the ISR */
496*b925c9deSRoman Bacik if (bcm_iproc_i2c_check_slave_status(iproc_i2c, status))
497*b925c9deSRoman Bacik return true;
498*b925c9deSRoman Bacik
499c245d94eSRayagonda Kokatanur /*
500e21d7977SRayagonda Kokatanur * Slave events in case of master-write, master-write-read and,
501e21d7977SRayagonda Kokatanur * master-read
502e21d7977SRayagonda Kokatanur *
503e21d7977SRayagonda Kokatanur * Master-write : only IS_S_RX_EVENT_SHIFT event
504e21d7977SRayagonda Kokatanur * Master-write-read: both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT
505e21d7977SRayagonda Kokatanur * events
506e21d7977SRayagonda Kokatanur * Master-read : both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT
507e21d7977SRayagonda Kokatanur * events or only IS_S_RD_EVENT_SHIFT
5084d658451SRayagonda Kokatanur *
5094d658451SRayagonda Kokatanur * iproc has a slave rx fifo size of 64 bytes. Rx fifo full interrupt
5104d658451SRayagonda Kokatanur * (IS_S_RX_FIFO_FULL_SHIFT) will be generated when RX fifo becomes
5114d658451SRayagonda Kokatanur * full. This can happen if Master issues write requests of more than
5124d658451SRayagonda Kokatanur * 64 bytes.
513f34b8d90SShreesha Rajashekar */
514e21d7977SRayagonda Kokatanur if (status & BIT(IS_S_RX_EVENT_SHIFT) ||
5154d658451SRayagonda Kokatanur status & BIT(IS_S_RD_EVENT_SHIFT) ||
5164d658451SRayagonda Kokatanur status & BIT(IS_S_RX_FIFO_FULL_SHIFT)) {
517e21d7977SRayagonda Kokatanur /* disable slave interrupts */
518c245d94eSRayagonda Kokatanur val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
519e21d7977SRayagonda Kokatanur val &= ~iproc_i2c->slave_int_mask;
520c245d94eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
521e21d7977SRayagonda Kokatanur
522e21d7977SRayagonda Kokatanur if (status & BIT(IS_S_RD_EVENT_SHIFT))
523e21d7977SRayagonda Kokatanur /* Master-write-read request */
524e21d7977SRayagonda Kokatanur iproc_i2c->slave_rx_only = false;
525e21d7977SRayagonda Kokatanur else
526e21d7977SRayagonda Kokatanur /* Master-write request only */
527e21d7977SRayagonda Kokatanur iproc_i2c->slave_rx_only = true;
528e21d7977SRayagonda Kokatanur
529e21d7977SRayagonda Kokatanur /* schedule tasklet to read data later */
530e21d7977SRayagonda Kokatanur tasklet_schedule(&iproc_i2c->slave_rx_tasklet);
531e21d7977SRayagonda Kokatanur
532*b925c9deSRoman Bacik /* clear IS_S_RX_FIFO_FULL_SHIFT interrupt */
533*b925c9deSRoman Bacik if (status & BIT(IS_S_RX_FIFO_FULL_SHIFT)) {
534*b925c9deSRoman Bacik val = BIT(IS_S_RX_FIFO_FULL_SHIFT);
5354d658451SRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, val);
536c245d94eSRayagonda Kokatanur }
537f34b8d90SShreesha Rajashekar }
538f34b8d90SShreesha Rajashekar
539f34b8d90SShreesha Rajashekar return true;
540f34b8d90SShreesha Rajashekar }
541f34b8d90SShreesha Rajashekar
bcm_iproc_i2c_read_valid_bytes(struct bcm_iproc_i2c_dev * iproc_i2c)542c24b8d57SShreesha Rajashekar static void bcm_iproc_i2c_read_valid_bytes(struct bcm_iproc_i2c_dev *iproc_i2c)
543c24b8d57SShreesha Rajashekar {
544c24b8d57SShreesha Rajashekar struct i2c_msg *msg = iproc_i2c->msg;
545fd01eecdSRayagonda Kokatanur uint32_t val;
546c24b8d57SShreesha Rajashekar
547c24b8d57SShreesha Rajashekar /* Read valid data from RX FIFO */
548c24b8d57SShreesha Rajashekar while (iproc_i2c->rx_bytes < msg->len) {
549fd01eecdSRayagonda Kokatanur val = iproc_i2c_rd_reg(iproc_i2c, M_RX_OFFSET);
550fd01eecdSRayagonda Kokatanur
551fd01eecdSRayagonda Kokatanur /* rx fifo empty */
552fd01eecdSRayagonda Kokatanur if (!((val >> M_RX_STATUS_SHIFT) & M_RX_STATUS_MASK))
553c24b8d57SShreesha Rajashekar break;
554c24b8d57SShreesha Rajashekar
555c24b8d57SShreesha Rajashekar msg->buf[iproc_i2c->rx_bytes] =
556fd01eecdSRayagonda Kokatanur (val >> M_RX_DATA_SHIFT) & M_RX_DATA_MASK;
557c24b8d57SShreesha Rajashekar iproc_i2c->rx_bytes++;
558c24b8d57SShreesha Rajashekar }
559c24b8d57SShreesha Rajashekar }
560e6e5dd35SRay Jui
bcm_iproc_i2c_send(struct bcm_iproc_i2c_dev * iproc_i2c)5613f98ad45SRayagonda Kokatanur static void bcm_iproc_i2c_send(struct bcm_iproc_i2c_dev *iproc_i2c)
562e6e5dd35SRay Jui {
5634916eb69SRay Jui struct i2c_msg *msg = iproc_i2c->msg;
5644916eb69SRay Jui unsigned int tx_bytes = msg->len - iproc_i2c->tx_bytes;
5654916eb69SRay Jui unsigned int i;
5664916eb69SRay Jui u32 val;
5674916eb69SRay Jui
5684916eb69SRay Jui /* can only fill up to the FIFO size */
5694916eb69SRay Jui tx_bytes = min_t(unsigned int, tx_bytes, M_TX_RX_FIFO_SIZE);
5704916eb69SRay Jui for (i = 0; i < tx_bytes; i++) {
5714916eb69SRay Jui /* start from where we left over */
5724916eb69SRay Jui unsigned int idx = iproc_i2c->tx_bytes + i;
5734916eb69SRay Jui
5744916eb69SRay Jui val = msg->buf[idx];
5754916eb69SRay Jui
5764916eb69SRay Jui /* mark the last byte */
5774916eb69SRay Jui if (idx == msg->len - 1) {
5784916eb69SRay Jui val |= BIT(M_TX_WR_STATUS_SHIFT);
5794916eb69SRay Jui
5803f98ad45SRayagonda Kokatanur if (iproc_i2c->irq) {
5813f98ad45SRayagonda Kokatanur u32 tmp;
5823f98ad45SRayagonda Kokatanur
5834916eb69SRay Jui /*
5843f98ad45SRayagonda Kokatanur * Since this is the last byte, we should now
5853f98ad45SRayagonda Kokatanur * disable TX FIFO underrun interrupt
5864916eb69SRay Jui */
587a9f0a81eSRayagonda Kokatanur tmp = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
5884916eb69SRay Jui tmp &= ~BIT(IE_M_TX_UNDERRUN_SHIFT);
589a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET,
590a9f0a81eSRayagonda Kokatanur tmp);
5914916eb69SRay Jui }
5923f98ad45SRayagonda Kokatanur }
5934916eb69SRay Jui
5944916eb69SRay Jui /* load data into TX FIFO */
595a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, M_TX_OFFSET, val);
5964916eb69SRay Jui }
5973f98ad45SRayagonda Kokatanur
5984916eb69SRay Jui /* update number of transferred bytes */
5994916eb69SRay Jui iproc_i2c->tx_bytes += tx_bytes;
6004916eb69SRay Jui }
6014916eb69SRay Jui
bcm_iproc_i2c_read(struct bcm_iproc_i2c_dev * iproc_i2c)6023f98ad45SRayagonda Kokatanur static void bcm_iproc_i2c_read(struct bcm_iproc_i2c_dev *iproc_i2c)
6033f98ad45SRayagonda Kokatanur {
604c24b8d57SShreesha Rajashekar struct i2c_msg *msg = iproc_i2c->msg;
6053f98ad45SRayagonda Kokatanur u32 bytes_left, val;
606c24b8d57SShreesha Rajashekar
607c24b8d57SShreesha Rajashekar bcm_iproc_i2c_read_valid_bytes(iproc_i2c);
608c24b8d57SShreesha Rajashekar bytes_left = msg->len - iproc_i2c->rx_bytes;
609c24b8d57SShreesha Rajashekar if (bytes_left == 0) {
6103f98ad45SRayagonda Kokatanur if (iproc_i2c->irq) {
611c24b8d57SShreesha Rajashekar /* finished reading all data, disable rx thld event */
612a9f0a81eSRayagonda Kokatanur val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
6133f98ad45SRayagonda Kokatanur val &= ~BIT(IS_M_RX_THLD_SHIFT);
614a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
6153f98ad45SRayagonda Kokatanur }
616c24b8d57SShreesha Rajashekar } else if (bytes_left < iproc_i2c->thld_bytes) {
617c24b8d57SShreesha Rajashekar /* set bytes left as threshold */
618a9f0a81eSRayagonda Kokatanur val = iproc_i2c_rd_reg(iproc_i2c, M_FIFO_CTRL_OFFSET);
6193f98ad45SRayagonda Kokatanur val &= ~(M_FIFO_RX_THLD_MASK << M_FIFO_RX_THLD_SHIFT);
6203f98ad45SRayagonda Kokatanur val |= (bytes_left << M_FIFO_RX_THLD_SHIFT);
621a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, M_FIFO_CTRL_OFFSET, val);
622c24b8d57SShreesha Rajashekar iproc_i2c->thld_bytes = bytes_left;
623c24b8d57SShreesha Rajashekar }
624c24b8d57SShreesha Rajashekar /*
625c24b8d57SShreesha Rajashekar * bytes_left >= iproc_i2c->thld_bytes,
626c24b8d57SShreesha Rajashekar * hence no need to change the THRESHOLD SET.
627c24b8d57SShreesha Rajashekar * It will remain as iproc_i2c->thld_bytes itself
628c24b8d57SShreesha Rajashekar */
629c24b8d57SShreesha Rajashekar }
630c24b8d57SShreesha Rajashekar
bcm_iproc_i2c_process_m_event(struct bcm_iproc_i2c_dev * iproc_i2c,u32 status)6313f98ad45SRayagonda Kokatanur static void bcm_iproc_i2c_process_m_event(struct bcm_iproc_i2c_dev *iproc_i2c,
6323f98ad45SRayagonda Kokatanur u32 status)
6333f98ad45SRayagonda Kokatanur {
6343f98ad45SRayagonda Kokatanur /* TX FIFO is empty and we have more data to send */
6353f98ad45SRayagonda Kokatanur if (status & BIT(IS_M_TX_UNDERRUN_SHIFT))
6363f98ad45SRayagonda Kokatanur bcm_iproc_i2c_send(iproc_i2c);
6373f98ad45SRayagonda Kokatanur
6383f98ad45SRayagonda Kokatanur /* RX FIFO threshold is reached and data needs to be read out */
6393f98ad45SRayagonda Kokatanur if (status & BIT(IS_M_RX_THLD_SHIFT))
6403f98ad45SRayagonda Kokatanur bcm_iproc_i2c_read(iproc_i2c);
6413f98ad45SRayagonda Kokatanur
6423f98ad45SRayagonda Kokatanur /* transfer is done */
6434916eb69SRay Jui if (status & BIT(IS_M_START_BUSY_SHIFT)) {
644e6e5dd35SRay Jui iproc_i2c->xfer_is_done = 1;
6453f98ad45SRayagonda Kokatanur if (iproc_i2c->irq)
6468d263be8SDaniel Wagner complete(&iproc_i2c->done);
6474916eb69SRay Jui }
6483f98ad45SRayagonda Kokatanur }
6494916eb69SRay Jui
bcm_iproc_i2c_isr(int irq,void * data)6503f98ad45SRayagonda Kokatanur static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data)
6513f98ad45SRayagonda Kokatanur {
6523f98ad45SRayagonda Kokatanur struct bcm_iproc_i2c_dev *iproc_i2c = data;
653545f4011SRayagonda Kokatanur u32 slave_status;
654545f4011SRayagonda Kokatanur u32 status;
6553f98ad45SRayagonda Kokatanur bool ret;
6563f98ad45SRayagonda Kokatanur
657545f4011SRayagonda Kokatanur status = iproc_i2c_rd_reg(iproc_i2c, IS_OFFSET);
658545f4011SRayagonda Kokatanur /* process only slave interrupt which are enabled */
659545f4011SRayagonda Kokatanur slave_status = status & iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET) &
660545f4011SRayagonda Kokatanur ISR_MASK_SLAVE;
661545f4011SRayagonda Kokatanur
662545f4011SRayagonda Kokatanur if (slave_status) {
663545f4011SRayagonda Kokatanur ret = bcm_iproc_i2c_slave_isr(iproc_i2c, slave_status);
6643f98ad45SRayagonda Kokatanur if (ret)
6653f98ad45SRayagonda Kokatanur return IRQ_HANDLED;
6663f98ad45SRayagonda Kokatanur else
6673f98ad45SRayagonda Kokatanur return IRQ_NONE;
6683f98ad45SRayagonda Kokatanur }
6693f98ad45SRayagonda Kokatanur
6703f98ad45SRayagonda Kokatanur status &= ISR_MASK;
6713f98ad45SRayagonda Kokatanur if (!status)
6723f98ad45SRayagonda Kokatanur return IRQ_NONE;
6733f98ad45SRayagonda Kokatanur
6743f98ad45SRayagonda Kokatanur /* process all master based events */
6753f98ad45SRayagonda Kokatanur bcm_iproc_i2c_process_m_event(iproc_i2c, status);
676a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, status);
677e6e5dd35SRay Jui
678e6e5dd35SRay Jui return IRQ_HANDLED;
679e6e5dd35SRay Jui }
680e6e5dd35SRay Jui
bcm_iproc_i2c_init(struct bcm_iproc_i2c_dev * iproc_i2c)6816ee608c1SRay Jui static int bcm_iproc_i2c_init(struct bcm_iproc_i2c_dev *iproc_i2c)
6826ee608c1SRay Jui {
6836ee608c1SRay Jui u32 val;
6846ee608c1SRay Jui
6856ee608c1SRay Jui /* put controller in reset */
686a9f0a81eSRayagonda Kokatanur val = iproc_i2c_rd_reg(iproc_i2c, CFG_OFFSET);
687f34b8d90SShreesha Rajashekar val |= BIT(CFG_RESET_SHIFT);
688f34b8d90SShreesha Rajashekar val &= ~(BIT(CFG_EN_SHIFT));
689a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, CFG_OFFSET, val);
6906ee608c1SRay Jui
6916ee608c1SRay Jui /* wait 100 usec per spec */
6926ee608c1SRay Jui udelay(100);
6936ee608c1SRay Jui
6946ee608c1SRay Jui /* bring controller out of reset */
695f34b8d90SShreesha Rajashekar val &= ~(BIT(CFG_RESET_SHIFT));
696a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, CFG_OFFSET, val);
6976ee608c1SRay Jui
6986ee608c1SRay Jui /* flush TX/RX FIFOs and set RX FIFO threshold to zero */
699f34b8d90SShreesha Rajashekar val = (BIT(M_FIFO_RX_FLUSH_SHIFT) | BIT(M_FIFO_TX_FLUSH_SHIFT));
700a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, M_FIFO_CTRL_OFFSET, val);
7016ee608c1SRay Jui /* disable all interrupts */
702a9f0a81eSRayagonda Kokatanur val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
703f34b8d90SShreesha Rajashekar val &= ~(IE_M_ALL_INTERRUPT_MASK <<
704f34b8d90SShreesha Rajashekar IE_M_ALL_INTERRUPT_SHIFT);
705a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val);
7066ee608c1SRay Jui
7076ee608c1SRay Jui /* clear all pending interrupts */
708a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, 0xffffffff);
7096ee608c1SRay Jui
7106ee608c1SRay Jui return 0;
7116ee608c1SRay Jui }
7126ee608c1SRay Jui
bcm_iproc_i2c_enable_disable(struct bcm_iproc_i2c_dev * iproc_i2c,bool enable)7136ee608c1SRay Jui static void bcm_iproc_i2c_enable_disable(struct bcm_iproc_i2c_dev *iproc_i2c,
7146ee608c1SRay Jui bool enable)
7156ee608c1SRay Jui {
7166ee608c1SRay Jui u32 val;
7176ee608c1SRay Jui
718a9f0a81eSRayagonda Kokatanur val = iproc_i2c_rd_reg(iproc_i2c, CFG_OFFSET);
7196ee608c1SRay Jui if (enable)
7206ee608c1SRay Jui val |= BIT(CFG_EN_SHIFT);
7216ee608c1SRay Jui else
7226ee608c1SRay Jui val &= ~BIT(CFG_EN_SHIFT);
723a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, CFG_OFFSET, val);
7246ee608c1SRay Jui }
7256ee608c1SRay Jui
bcm_iproc_i2c_check_status(struct bcm_iproc_i2c_dev * iproc_i2c,struct i2c_msg * msg)726e6e5dd35SRay Jui static int bcm_iproc_i2c_check_status(struct bcm_iproc_i2c_dev *iproc_i2c,
727e6e5dd35SRay Jui struct i2c_msg *msg)
728e6e5dd35SRay Jui {
729e6e5dd35SRay Jui u32 val;
730e6e5dd35SRay Jui
731a9f0a81eSRayagonda Kokatanur val = iproc_i2c_rd_reg(iproc_i2c, M_CMD_OFFSET);
732e6e5dd35SRay Jui val = (val >> M_CMD_STATUS_SHIFT) & M_CMD_STATUS_MASK;
733e6e5dd35SRay Jui
734e6e5dd35SRay Jui switch (val) {
735e6e5dd35SRay Jui case M_CMD_STATUS_SUCCESS:
736e6e5dd35SRay Jui return 0;
737e6e5dd35SRay Jui
738e6e5dd35SRay Jui case M_CMD_STATUS_LOST_ARB:
739e6e5dd35SRay Jui dev_dbg(iproc_i2c->device, "lost bus arbitration\n");
740e6e5dd35SRay Jui return -EAGAIN;
741e6e5dd35SRay Jui
742e6e5dd35SRay Jui case M_CMD_STATUS_NACK_ADDR:
743e6e5dd35SRay Jui dev_dbg(iproc_i2c->device, "NAK addr:0x%02x\n", msg->addr);
744e6e5dd35SRay Jui return -ENXIO;
745e6e5dd35SRay Jui
746e6e5dd35SRay Jui case M_CMD_STATUS_NACK_DATA:
747e6e5dd35SRay Jui dev_dbg(iproc_i2c->device, "NAK data\n");
748e6e5dd35SRay Jui return -ENXIO;
749e6e5dd35SRay Jui
750e6e5dd35SRay Jui case M_CMD_STATUS_TIMEOUT:
751e6e5dd35SRay Jui dev_dbg(iproc_i2c->device, "bus timeout\n");
752e6e5dd35SRay Jui return -ETIMEDOUT;
753e6e5dd35SRay Jui
7541b23fa2eSMichael Cheng case M_CMD_STATUS_FIFO_UNDERRUN:
7551b23fa2eSMichael Cheng dev_dbg(iproc_i2c->device, "FIFO under-run\n");
7561b23fa2eSMichael Cheng return -ENXIO;
7571b23fa2eSMichael Cheng
7581b23fa2eSMichael Cheng case M_CMD_STATUS_RX_FIFO_FULL:
7591b23fa2eSMichael Cheng dev_dbg(iproc_i2c->device, "RX FIFO full\n");
7601b23fa2eSMichael Cheng return -ETIMEDOUT;
7611b23fa2eSMichael Cheng
762e6e5dd35SRay Jui default:
763e6e5dd35SRay Jui dev_dbg(iproc_i2c->device, "unknown error code=%d\n", val);
7646ee608c1SRay Jui
7656ee608c1SRay Jui /* re-initialize i2c for recovery */
7666ee608c1SRay Jui bcm_iproc_i2c_enable_disable(iproc_i2c, false);
7676ee608c1SRay Jui bcm_iproc_i2c_init(iproc_i2c);
7686ee608c1SRay Jui bcm_iproc_i2c_enable_disable(iproc_i2c, true);
7696ee608c1SRay Jui
770e6e5dd35SRay Jui return -EIO;
771e6e5dd35SRay Jui }
772e6e5dd35SRay Jui }
773e6e5dd35SRay Jui
bcm_iproc_i2c_xfer_wait(struct bcm_iproc_i2c_dev * iproc_i2c,struct i2c_msg * msg,u32 cmd)7743f98ad45SRayagonda Kokatanur static int bcm_iproc_i2c_xfer_wait(struct bcm_iproc_i2c_dev *iproc_i2c,
7753f98ad45SRayagonda Kokatanur struct i2c_msg *msg,
7763f98ad45SRayagonda Kokatanur u32 cmd)
7773f98ad45SRayagonda Kokatanur {
7783f98ad45SRayagonda Kokatanur unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT_MSEC);
7793f98ad45SRayagonda Kokatanur u32 val, status;
7803f98ad45SRayagonda Kokatanur int ret;
7813f98ad45SRayagonda Kokatanur
782a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, M_CMD_OFFSET, cmd);
7833f98ad45SRayagonda Kokatanur
7843f98ad45SRayagonda Kokatanur if (iproc_i2c->irq) {
7853f98ad45SRayagonda Kokatanur time_left = wait_for_completion_timeout(&iproc_i2c->done,
7863f98ad45SRayagonda Kokatanur time_left);
7873f98ad45SRayagonda Kokatanur /* disable all interrupts */
788a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, 0);
7893f98ad45SRayagonda Kokatanur /* read it back to flush the write */
790a9f0a81eSRayagonda Kokatanur iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
7913f98ad45SRayagonda Kokatanur /* make sure the interrupt handler isn't running */
7923f98ad45SRayagonda Kokatanur synchronize_irq(iproc_i2c->irq);
7933f98ad45SRayagonda Kokatanur
7943f98ad45SRayagonda Kokatanur } else { /* polling mode */
7953f98ad45SRayagonda Kokatanur unsigned long timeout = jiffies + time_left;
7963f98ad45SRayagonda Kokatanur
7973f98ad45SRayagonda Kokatanur do {
798a9f0a81eSRayagonda Kokatanur status = iproc_i2c_rd_reg(iproc_i2c,
799a9f0a81eSRayagonda Kokatanur IS_OFFSET) & ISR_MASK;
8003f98ad45SRayagonda Kokatanur bcm_iproc_i2c_process_m_event(iproc_i2c, status);
801a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, status);
8023f98ad45SRayagonda Kokatanur
8033f98ad45SRayagonda Kokatanur if (time_after(jiffies, timeout)) {
8043f98ad45SRayagonda Kokatanur time_left = 0;
8053f98ad45SRayagonda Kokatanur break;
8063f98ad45SRayagonda Kokatanur }
8073f98ad45SRayagonda Kokatanur
8083f98ad45SRayagonda Kokatanur cpu_relax();
8093f98ad45SRayagonda Kokatanur cond_resched();
8103f98ad45SRayagonda Kokatanur } while (!iproc_i2c->xfer_is_done);
8113f98ad45SRayagonda Kokatanur }
8123f98ad45SRayagonda Kokatanur
8133f98ad45SRayagonda Kokatanur if (!time_left && !iproc_i2c->xfer_is_done) {
8143f98ad45SRayagonda Kokatanur dev_err(iproc_i2c->device, "transaction timed out\n");
8153f98ad45SRayagonda Kokatanur
8163f98ad45SRayagonda Kokatanur /* flush both TX/RX FIFOs */
8173f98ad45SRayagonda Kokatanur val = BIT(M_FIFO_RX_FLUSH_SHIFT) | BIT(M_FIFO_TX_FLUSH_SHIFT);
818a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, M_FIFO_CTRL_OFFSET, val);
8193f98ad45SRayagonda Kokatanur return -ETIMEDOUT;
8203f98ad45SRayagonda Kokatanur }
8213f98ad45SRayagonda Kokatanur
8223f98ad45SRayagonda Kokatanur ret = bcm_iproc_i2c_check_status(iproc_i2c, msg);
8233f98ad45SRayagonda Kokatanur if (ret) {
8243f98ad45SRayagonda Kokatanur /* flush both TX/RX FIFOs */
8253f98ad45SRayagonda Kokatanur val = BIT(M_FIFO_RX_FLUSH_SHIFT) | BIT(M_FIFO_TX_FLUSH_SHIFT);
826a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, M_FIFO_CTRL_OFFSET, val);
8273f98ad45SRayagonda Kokatanur return ret;
8283f98ad45SRayagonda Kokatanur }
8293f98ad45SRayagonda Kokatanur
8303f98ad45SRayagonda Kokatanur return 0;
8313f98ad45SRayagonda Kokatanur }
8323f98ad45SRayagonda Kokatanur
8335a5e277bSLori Hikichi /*
8345a5e277bSLori Hikichi * If 'process_call' is true, then this is a multi-msg transfer that requires
8355a5e277bSLori Hikichi * a repeated start between the messages.
8365a5e277bSLori Hikichi * More specifically, it must be a write (reg) followed by a read (data).
8375a5e277bSLori Hikichi * The i2c quirks are set to enforce this rule.
8385a5e277bSLori Hikichi */
bcm_iproc_i2c_xfer_internal(struct bcm_iproc_i2c_dev * iproc_i2c,struct i2c_msg * msgs,bool process_call)8395a5e277bSLori Hikichi static int bcm_iproc_i2c_xfer_internal(struct bcm_iproc_i2c_dev *iproc_i2c,
8405a5e277bSLori Hikichi struct i2c_msg *msgs, bool process_call)
841e6e5dd35SRay Jui {
8423f98ad45SRayagonda Kokatanur int i;
843e6e5dd35SRay Jui u8 addr;
844c24b8d57SShreesha Rajashekar u32 val, tmp, val_intr_en;
8454916eb69SRay Jui unsigned int tx_bytes;
8465a5e277bSLori Hikichi struct i2c_msg *msg = &msgs[0];
847e6e5dd35SRay Jui
848e6e5dd35SRay Jui /* check if bus is busy */
849a9f0a81eSRayagonda Kokatanur if (!!(iproc_i2c_rd_reg(iproc_i2c,
850a9f0a81eSRayagonda Kokatanur M_CMD_OFFSET) & BIT(M_CMD_START_BUSY_SHIFT))) {
851e6e5dd35SRay Jui dev_warn(iproc_i2c->device, "bus is busy\n");
852e6e5dd35SRay Jui return -EBUSY;
853e6e5dd35SRay Jui }
854e6e5dd35SRay Jui
8554916eb69SRay Jui iproc_i2c->msg = msg;
8564916eb69SRay Jui
857e6e5dd35SRay Jui /* format and load slave address into the TX FIFO */
85832822bffSWolfram Sang addr = i2c_8bit_addr_from_msg(msg);
859a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, M_TX_OFFSET, addr);
860e6e5dd35SRay Jui
8614916eb69SRay Jui /*
8624916eb69SRay Jui * For a write transaction, load data into the TX FIFO. Only allow
8634916eb69SRay Jui * loading up to TX FIFO size - 1 bytes of data since the first byte
8644916eb69SRay Jui * has been used up by the slave address
8654916eb69SRay Jui */
8664916eb69SRay Jui tx_bytes = min_t(unsigned int, msg->len, M_TX_RX_FIFO_SIZE - 1);
867e6e5dd35SRay Jui if (!(msg->flags & I2C_M_RD)) {
8684916eb69SRay Jui for (i = 0; i < tx_bytes; i++) {
869e6e5dd35SRay Jui val = msg->buf[i];
870e6e5dd35SRay Jui
871e6e5dd35SRay Jui /* mark the last byte */
8725a5e277bSLori Hikichi if (!process_call && (i == msg->len - 1))
87302040811SRay Jui val |= BIT(M_TX_WR_STATUS_SHIFT);
874e6e5dd35SRay Jui
875a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, M_TX_OFFSET, val);
876e6e5dd35SRay Jui }
8774916eb69SRay Jui iproc_i2c->tx_bytes = tx_bytes;
878e6e5dd35SRay Jui }
879e6e5dd35SRay Jui
8805a5e277bSLori Hikichi /* Process the read message if this is process call */
8815a5e277bSLori Hikichi if (process_call) {
8825a5e277bSLori Hikichi msg++;
8835a5e277bSLori Hikichi iproc_i2c->msg = msg; /* point to second msg */
8845a5e277bSLori Hikichi
8855a5e277bSLori Hikichi /*
8865a5e277bSLori Hikichi * The last byte to be sent out should be a slave
8875a5e277bSLori Hikichi * address with read operation
8885a5e277bSLori Hikichi */
8895a5e277bSLori Hikichi addr = i2c_8bit_addr_from_msg(msg);
8905a5e277bSLori Hikichi /* mark it the last byte out */
89102040811SRay Jui val = addr | BIT(M_TX_WR_STATUS_SHIFT);
8925a5e277bSLori Hikichi iproc_i2c_wr_reg(iproc_i2c, M_TX_OFFSET, val);
8935a5e277bSLori Hikichi }
8945a5e277bSLori Hikichi
895e6e5dd35SRay Jui /* mark as incomplete before starting the transaction */
8963f98ad45SRayagonda Kokatanur if (iproc_i2c->irq)
897e6e5dd35SRay Jui reinit_completion(&iproc_i2c->done);
8983f98ad45SRayagonda Kokatanur
899e6e5dd35SRay Jui iproc_i2c->xfer_is_done = 0;
900e6e5dd35SRay Jui
901e6e5dd35SRay Jui /*
902e6e5dd35SRay Jui * Enable the "start busy" interrupt, which will be triggered after the
903e6e5dd35SRay Jui * transaction is done, i.e., the internal start_busy bit, transitions
904e6e5dd35SRay Jui * from 1 to 0.
905e6e5dd35SRay Jui */
906c24b8d57SShreesha Rajashekar val_intr_en = BIT(IE_M_START_BUSY_SHIFT);
9074916eb69SRay Jui
9084916eb69SRay Jui /*
9094916eb69SRay Jui * If TX data size is larger than the TX FIFO, need to enable TX
9104916eb69SRay Jui * underrun interrupt, which will be triggerred when the TX FIFO is
9114916eb69SRay Jui * empty. When that happens we can then pump more data into the FIFO
9124916eb69SRay Jui */
9135a5e277bSLori Hikichi if (!process_call && !(msg->flags & I2C_M_RD) &&
9144916eb69SRay Jui msg->len > iproc_i2c->tx_bytes)
915c24b8d57SShreesha Rajashekar val_intr_en |= BIT(IE_M_TX_UNDERRUN_SHIFT);
916e6e5dd35SRay Jui
917e6e5dd35SRay Jui /*
918e6e5dd35SRay Jui * Now we can activate the transfer. For a read operation, specify the
919e6e5dd35SRay Jui * number of bytes to read
920e6e5dd35SRay Jui */
9214916eb69SRay Jui val = BIT(M_CMD_START_BUSY_SHIFT);
922e14d796dSRayagonda Kokatanur
923e14d796dSRayagonda Kokatanur if (msg->len == 0) {
924e14d796dSRayagonda Kokatanur /* SMBUS QUICK Command (Read/Write) */
925e14d796dSRayagonda Kokatanur val |= (M_CMD_PROTOCOL_QUICK << M_CMD_PROTOCOL_SHIFT);
926e14d796dSRayagonda Kokatanur } else if (msg->flags & I2C_M_RD) {
9275a5e277bSLori Hikichi u32 protocol;
9285a5e277bSLori Hikichi
929c24b8d57SShreesha Rajashekar iproc_i2c->rx_bytes = 0;
930c24b8d57SShreesha Rajashekar if (msg->len > M_RX_FIFO_MAX_THLD_VALUE)
931c24b8d57SShreesha Rajashekar iproc_i2c->thld_bytes = M_RX_FIFO_THLD_VALUE;
932c24b8d57SShreesha Rajashekar else
933c24b8d57SShreesha Rajashekar iproc_i2c->thld_bytes = msg->len;
934c24b8d57SShreesha Rajashekar
935c24b8d57SShreesha Rajashekar /* set threshold value */
936a9f0a81eSRayagonda Kokatanur tmp = iproc_i2c_rd_reg(iproc_i2c, M_FIFO_CTRL_OFFSET);
937c24b8d57SShreesha Rajashekar tmp &= ~(M_FIFO_RX_THLD_MASK << M_FIFO_RX_THLD_SHIFT);
938c24b8d57SShreesha Rajashekar tmp |= iproc_i2c->thld_bytes << M_FIFO_RX_THLD_SHIFT;
939a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, M_FIFO_CTRL_OFFSET, tmp);
940c24b8d57SShreesha Rajashekar
941c24b8d57SShreesha Rajashekar /* enable the RX threshold interrupt */
942c24b8d57SShreesha Rajashekar val_intr_en |= BIT(IE_M_RX_THLD_SHIFT);
943c24b8d57SShreesha Rajashekar
9445a5e277bSLori Hikichi protocol = process_call ?
9455a5e277bSLori Hikichi M_CMD_PROTOCOL_PROCESS : M_CMD_PROTOCOL_BLK_RD;
9465a5e277bSLori Hikichi
9475a5e277bSLori Hikichi val |= (protocol << M_CMD_PROTOCOL_SHIFT) |
948e6e5dd35SRay Jui (msg->len << M_CMD_RD_CNT_SHIFT);
949e6e5dd35SRay Jui } else {
950e6e5dd35SRay Jui val |= (M_CMD_PROTOCOL_BLK_WR << M_CMD_PROTOCOL_SHIFT);
951e6e5dd35SRay Jui }
9523f98ad45SRayagonda Kokatanur
9533f98ad45SRayagonda Kokatanur if (iproc_i2c->irq)
954a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val_intr_en);
955e6e5dd35SRay Jui
9563f98ad45SRayagonda Kokatanur return bcm_iproc_i2c_xfer_wait(iproc_i2c, msg, val);
957e6e5dd35SRay Jui }
958e6e5dd35SRay Jui
bcm_iproc_i2c_xfer(struct i2c_adapter * adapter,struct i2c_msg msgs[],int num)959e6e5dd35SRay Jui static int bcm_iproc_i2c_xfer(struct i2c_adapter *adapter,
960e6e5dd35SRay Jui struct i2c_msg msgs[], int num)
961e6e5dd35SRay Jui {
962e6e5dd35SRay Jui struct bcm_iproc_i2c_dev *iproc_i2c = i2c_get_adapdata(adapter);
9635a5e277bSLori Hikichi bool process_call = false;
9645a5e277bSLori Hikichi int ret;
965e6e5dd35SRay Jui
9665a5e277bSLori Hikichi if (num == 2) {
9675a5e277bSLori Hikichi /* Repeated start, use process call */
9685a5e277bSLori Hikichi process_call = true;
9695a5e277bSLori Hikichi if (msgs[1].flags & I2C_M_NOSTART) {
9705a5e277bSLori Hikichi dev_err(iproc_i2c->device, "Invalid repeated start\n");
9715a5e277bSLori Hikichi return -EOPNOTSUPP;
9725a5e277bSLori Hikichi }
9735a5e277bSLori Hikichi }
9745a5e277bSLori Hikichi
9755a5e277bSLori Hikichi ret = bcm_iproc_i2c_xfer_internal(iproc_i2c, msgs, process_call);
976e6e5dd35SRay Jui if (ret) {
977e6e5dd35SRay Jui dev_dbg(iproc_i2c->device, "xfer failed\n");
978e6e5dd35SRay Jui return ret;
979e6e5dd35SRay Jui }
980e6e5dd35SRay Jui
981e6e5dd35SRay Jui return num;
982e6e5dd35SRay Jui }
983e6e5dd35SRay Jui
bcm_iproc_i2c_functionality(struct i2c_adapter * adap)984e6e5dd35SRay Jui static uint32_t bcm_iproc_i2c_functionality(struct i2c_adapter *adap)
985e6e5dd35SRay Jui {
986b3d604d4SLori Hikichi u32 val;
987b3d604d4SLori Hikichi
988e14d796dSRayagonda Kokatanur val = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
9899a103872SRayagonda Kokatanur
9909a103872SRayagonda Kokatanur if (adap->algo->reg_slave)
9919a103872SRayagonda Kokatanur val |= I2C_FUNC_SLAVE;
9929a103872SRayagonda Kokatanur
9939a103872SRayagonda Kokatanur return val;
994e6e5dd35SRay Jui }
995e6e5dd35SRay Jui
9969a103872SRayagonda Kokatanur static struct i2c_algorithm bcm_iproc_algo = {
997e6e5dd35SRay Jui .master_xfer = bcm_iproc_i2c_xfer,
998e6e5dd35SRay Jui .functionality = bcm_iproc_i2c_functionality,
999f34b8d90SShreesha Rajashekar .reg_slave = bcm_iproc_i2c_reg_slave,
1000f34b8d90SShreesha Rajashekar .unreg_slave = bcm_iproc_i2c_unreg_slave,
1001e6e5dd35SRay Jui };
1002e6e5dd35SRay Jui
100367a53081SNishka Dasgupta static const struct i2c_adapter_quirks bcm_iproc_i2c_quirks = {
10045a5e277bSLori Hikichi .flags = I2C_AQ_COMB_WRITE_THEN_READ,
10055a5e277bSLori Hikichi .max_comb_1st_msg_len = M_TX_RX_FIFO_SIZE,
1006c24b8d57SShreesha Rajashekar .max_read_len = M_RX_MAX_READ_LEN,
1007338f1ab6SWolfram Sang };
1008338f1ab6SWolfram Sang
bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev * iproc_i2c)1009e6e5dd35SRay Jui static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c)
1010e6e5dd35SRay Jui {
1011e6e5dd35SRay Jui unsigned int bus_speed;
1012e6e5dd35SRay Jui u32 val;
1013e6e5dd35SRay Jui int ret = of_property_read_u32(iproc_i2c->device->of_node,
1014e6e5dd35SRay Jui "clock-frequency", &bus_speed);
1015e6e5dd35SRay Jui if (ret < 0) {
1016e6e5dd35SRay Jui dev_info(iproc_i2c->device,
1017e6e5dd35SRay Jui "unable to interpret clock-frequency DT property\n");
101890224e64SAndy Shevchenko bus_speed = I2C_MAX_STANDARD_MODE_FREQ;
1019e6e5dd35SRay Jui }
1020e6e5dd35SRay Jui
102190224e64SAndy Shevchenko if (bus_speed < I2C_MAX_STANDARD_MODE_FREQ) {
1022e6e5dd35SRay Jui dev_err(iproc_i2c->device, "%d Hz bus speed not supported\n",
1023e6e5dd35SRay Jui bus_speed);
1024e6e5dd35SRay Jui dev_err(iproc_i2c->device,
1025e6e5dd35SRay Jui "valid speeds are 100khz and 400khz\n");
1026e6e5dd35SRay Jui return -EINVAL;
102790224e64SAndy Shevchenko } else if (bus_speed < I2C_MAX_FAST_MODE_FREQ) {
102890224e64SAndy Shevchenko bus_speed = I2C_MAX_STANDARD_MODE_FREQ;
1029e6e5dd35SRay Jui } else {
103090224e64SAndy Shevchenko bus_speed = I2C_MAX_FAST_MODE_FREQ;
1031e6e5dd35SRay Jui }
1032e6e5dd35SRay Jui
10330ee04e91SRay Jui iproc_i2c->bus_speed = bus_speed;
1034a9f0a81eSRayagonda Kokatanur val = iproc_i2c_rd_reg(iproc_i2c, TIM_CFG_OFFSET);
10358221324bSRay Jui val &= ~BIT(TIM_CFG_MODE_400_SHIFT);
103690224e64SAndy Shevchenko val |= (bus_speed == I2C_MAX_FAST_MODE_FREQ) << TIM_CFG_MODE_400_SHIFT;
1037a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, TIM_CFG_OFFSET, val);
1038e6e5dd35SRay Jui
1039e6e5dd35SRay Jui dev_info(iproc_i2c->device, "bus set to %u Hz\n", bus_speed);
1040e6e5dd35SRay Jui
1041e6e5dd35SRay Jui return 0;
1042e6e5dd35SRay Jui }
1043e6e5dd35SRay Jui
bcm_iproc_i2c_probe(struct platform_device * pdev)1044e6e5dd35SRay Jui static int bcm_iproc_i2c_probe(struct platform_device *pdev)
1045e6e5dd35SRay Jui {
1046e6e5dd35SRay Jui int irq, ret = 0;
1047e6e5dd35SRay Jui struct bcm_iproc_i2c_dev *iproc_i2c;
1048e6e5dd35SRay Jui struct i2c_adapter *adap;
1049e6e5dd35SRay Jui
1050e6e5dd35SRay Jui iproc_i2c = devm_kzalloc(&pdev->dev, sizeof(*iproc_i2c),
1051e6e5dd35SRay Jui GFP_KERNEL);
1052e6e5dd35SRay Jui if (!iproc_i2c)
1053e6e5dd35SRay Jui return -ENOMEM;
1054e6e5dd35SRay Jui
1055e6e5dd35SRay Jui platform_set_drvdata(pdev, iproc_i2c);
1056e6e5dd35SRay Jui iproc_i2c->device = &pdev->dev;
10579a103872SRayagonda Kokatanur iproc_i2c->type =
10589a103872SRayagonda Kokatanur (enum bcm_iproc_i2c_type)of_device_get_match_data(&pdev->dev);
1059e6e5dd35SRay Jui init_completion(&iproc_i2c->done);
1060e6e5dd35SRay Jui
1061c71d80d3SYangtao Li iproc_i2c->base = devm_platform_ioremap_resource(pdev, 0);
1062e6e5dd35SRay Jui if (IS_ERR(iproc_i2c->base))
1063e6e5dd35SRay Jui return PTR_ERR(iproc_i2c->base);
1064e6e5dd35SRay Jui
10659a103872SRayagonda Kokatanur if (iproc_i2c->type == IPROC_I2C_NIC) {
1066c71d80d3SYangtao Li iproc_i2c->idm_base = devm_platform_ioremap_resource(pdev, 1);
10679a103872SRayagonda Kokatanur if (IS_ERR(iproc_i2c->idm_base))
10689a103872SRayagonda Kokatanur return PTR_ERR(iproc_i2c->idm_base);
10699a103872SRayagonda Kokatanur
10709a103872SRayagonda Kokatanur ret = of_property_read_u32(iproc_i2c->device->of_node,
10719a103872SRayagonda Kokatanur "brcm,ape-hsls-addr-mask",
10729a103872SRayagonda Kokatanur &iproc_i2c->ape_addr_mask);
10739a103872SRayagonda Kokatanur if (ret < 0) {
10749a103872SRayagonda Kokatanur dev_err(iproc_i2c->device,
10759a103872SRayagonda Kokatanur "'brcm,ape-hsls-addr-mask' missing\n");
10769a103872SRayagonda Kokatanur return -EINVAL;
10779a103872SRayagonda Kokatanur }
10789a103872SRayagonda Kokatanur
10799a103872SRayagonda Kokatanur spin_lock_init(&iproc_i2c->idm_lock);
10809a103872SRayagonda Kokatanur
10819a103872SRayagonda Kokatanur /* no slave support */
10829a103872SRayagonda Kokatanur bcm_iproc_algo.reg_slave = NULL;
10839a103872SRayagonda Kokatanur bcm_iproc_algo.unreg_slave = NULL;
10849a103872SRayagonda Kokatanur }
10859a103872SRayagonda Kokatanur
1086e6e5dd35SRay Jui ret = bcm_iproc_i2c_init(iproc_i2c);
1087e6e5dd35SRay Jui if (ret)
1088e6e5dd35SRay Jui return ret;
1089e6e5dd35SRay Jui
1090e6e5dd35SRay Jui ret = bcm_iproc_i2c_cfg_speed(iproc_i2c);
1091e6e5dd35SRay Jui if (ret)
1092e6e5dd35SRay Jui return ret;
1093e6e5dd35SRay Jui
1094e6e5dd35SRay Jui irq = platform_get_irq(pdev, 0);
10953f98ad45SRayagonda Kokatanur if (irq > 0) {
10963f98ad45SRayagonda Kokatanur ret = devm_request_irq(iproc_i2c->device, irq,
10973f98ad45SRayagonda Kokatanur bcm_iproc_i2c_isr, 0, pdev->name,
10983f98ad45SRayagonda Kokatanur iproc_i2c);
1099e6e5dd35SRay Jui if (ret < 0) {
11003f98ad45SRayagonda Kokatanur dev_err(iproc_i2c->device,
11013f98ad45SRayagonda Kokatanur "unable to request irq %i\n", irq);
1102e6e5dd35SRay Jui return ret;
1103e6e5dd35SRay Jui }
1104e6e5dd35SRay Jui
11053f98ad45SRayagonda Kokatanur iproc_i2c->irq = irq;
11063f98ad45SRayagonda Kokatanur } else {
11073f98ad45SRayagonda Kokatanur dev_warn(iproc_i2c->device,
11083f98ad45SRayagonda Kokatanur "no irq resource, falling back to poll mode\n");
11093f98ad45SRayagonda Kokatanur }
11103f98ad45SRayagonda Kokatanur
1111e6e5dd35SRay Jui bcm_iproc_i2c_enable_disable(iproc_i2c, true);
1112e6e5dd35SRay Jui
1113e6e5dd35SRay Jui adap = &iproc_i2c->adapter;
1114e6e5dd35SRay Jui i2c_set_adapdata(adap, iproc_i2c);
1115539005ffSLori Hikichi snprintf(adap->name, sizeof(adap->name),
1116539005ffSLori Hikichi "Broadcom iProc (%s)",
1117539005ffSLori Hikichi of_node_full_name(iproc_i2c->device->of_node));
1118e6e5dd35SRay Jui adap->algo = &bcm_iproc_algo;
1119338f1ab6SWolfram Sang adap->quirks = &bcm_iproc_i2c_quirks;
1120e6e5dd35SRay Jui adap->dev.parent = &pdev->dev;
1121e6e5dd35SRay Jui adap->dev.of_node = pdev->dev.of_node;
1122e6e5dd35SRay Jui
1123ea734404SWolfram Sang return i2c_add_adapter(adap);
1124e6e5dd35SRay Jui }
1125e6e5dd35SRay Jui
bcm_iproc_i2c_remove(struct platform_device * pdev)1126e190a0c3SUwe Kleine-König static void bcm_iproc_i2c_remove(struct platform_device *pdev)
1127e6e5dd35SRay Jui {
1128e6e5dd35SRay Jui struct bcm_iproc_i2c_dev *iproc_i2c = platform_get_drvdata(pdev);
1129e6e5dd35SRay Jui
11303f98ad45SRayagonda Kokatanur if (iproc_i2c->irq) {
11313f98ad45SRayagonda Kokatanur /*
11323f98ad45SRayagonda Kokatanur * Make sure there's no pending interrupt when we remove the
11333f98ad45SRayagonda Kokatanur * adapter
11343f98ad45SRayagonda Kokatanur */
1135a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, 0);
1136a9f0a81eSRayagonda Kokatanur iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
1137e6e5dd35SRay Jui synchronize_irq(iproc_i2c->irq);
11383f98ad45SRayagonda Kokatanur }
1139e6e5dd35SRay Jui
1140e6e5dd35SRay Jui i2c_del_adapter(&iproc_i2c->adapter);
1141e6e5dd35SRay Jui bcm_iproc_i2c_enable_disable(iproc_i2c, false);
1142e6e5dd35SRay Jui }
1143e6e5dd35SRay Jui
bcm_iproc_i2c_suspend(struct device * dev)11440ee04e91SRay Jui static int bcm_iproc_i2c_suspend(struct device *dev)
11450ee04e91SRay Jui {
11469242e72aSMasahiro Yamada struct bcm_iproc_i2c_dev *iproc_i2c = dev_get_drvdata(dev);
11470ee04e91SRay Jui
11483f98ad45SRayagonda Kokatanur if (iproc_i2c->irq) {
11493f98ad45SRayagonda Kokatanur /*
11503f98ad45SRayagonda Kokatanur * Make sure there's no pending interrupt when we go into
11513f98ad45SRayagonda Kokatanur * suspend
11523f98ad45SRayagonda Kokatanur */
1153a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, 0);
1154a9f0a81eSRayagonda Kokatanur iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
11550ee04e91SRay Jui synchronize_irq(iproc_i2c->irq);
11563f98ad45SRayagonda Kokatanur }
11570ee04e91SRay Jui
11580ee04e91SRay Jui /* now disable the controller */
11590ee04e91SRay Jui bcm_iproc_i2c_enable_disable(iproc_i2c, false);
11600ee04e91SRay Jui
11610ee04e91SRay Jui return 0;
11620ee04e91SRay Jui }
11630ee04e91SRay Jui
bcm_iproc_i2c_resume(struct device * dev)11640ee04e91SRay Jui static int bcm_iproc_i2c_resume(struct device *dev)
11650ee04e91SRay Jui {
11669242e72aSMasahiro Yamada struct bcm_iproc_i2c_dev *iproc_i2c = dev_get_drvdata(dev);
11670ee04e91SRay Jui int ret;
11680ee04e91SRay Jui u32 val;
11690ee04e91SRay Jui
11700ee04e91SRay Jui /*
11710ee04e91SRay Jui * Power domain could have been shut off completely in system deep
11720ee04e91SRay Jui * sleep, so re-initialize the block here
11730ee04e91SRay Jui */
11740ee04e91SRay Jui ret = bcm_iproc_i2c_init(iproc_i2c);
11750ee04e91SRay Jui if (ret)
11760ee04e91SRay Jui return ret;
11770ee04e91SRay Jui
11780ee04e91SRay Jui /* configure to the desired bus speed */
1179a9f0a81eSRayagonda Kokatanur val = iproc_i2c_rd_reg(iproc_i2c, TIM_CFG_OFFSET);
11808221324bSRay Jui val &= ~BIT(TIM_CFG_MODE_400_SHIFT);
118190224e64SAndy Shevchenko val |= (iproc_i2c->bus_speed == I2C_MAX_FAST_MODE_FREQ) << TIM_CFG_MODE_400_SHIFT;
1182a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, TIM_CFG_OFFSET, val);
11830ee04e91SRay Jui
11840ee04e91SRay Jui bcm_iproc_i2c_enable_disable(iproc_i2c, true);
11850ee04e91SRay Jui
11860ee04e91SRay Jui return 0;
11870ee04e91SRay Jui }
11880ee04e91SRay Jui
11890ee04e91SRay Jui static const struct dev_pm_ops bcm_iproc_i2c_pm_ops = {
11900ee04e91SRay Jui .suspend_late = &bcm_iproc_i2c_suspend,
11910ee04e91SRay Jui .resume_early = &bcm_iproc_i2c_resume
11920ee04e91SRay Jui };
11930ee04e91SRay Jui
bcm_iproc_i2c_reg_slave(struct i2c_client * slave)1194f34b8d90SShreesha Rajashekar static int bcm_iproc_i2c_reg_slave(struct i2c_client *slave)
1195f34b8d90SShreesha Rajashekar {
1196f34b8d90SShreesha Rajashekar struct bcm_iproc_i2c_dev *iproc_i2c = i2c_get_adapdata(slave->adapter);
1197f34b8d90SShreesha Rajashekar
1198f34b8d90SShreesha Rajashekar if (iproc_i2c->slave)
1199f34b8d90SShreesha Rajashekar return -EBUSY;
1200f34b8d90SShreesha Rajashekar
1201f34b8d90SShreesha Rajashekar if (slave->flags & I2C_CLIENT_TEN)
1202f34b8d90SShreesha Rajashekar return -EAFNOSUPPORT;
1203f34b8d90SShreesha Rajashekar
1204f34b8d90SShreesha Rajashekar iproc_i2c->slave = slave;
1205e21d7977SRayagonda Kokatanur
1206e21d7977SRayagonda Kokatanur tasklet_init(&iproc_i2c->slave_rx_tasklet, slave_rx_tasklet_fn,
1207e21d7977SRayagonda Kokatanur (unsigned long)iproc_i2c);
1208e21d7977SRayagonda Kokatanur
1209f34b8d90SShreesha Rajashekar bcm_iproc_i2c_slave_init(iproc_i2c, false);
1210f34b8d90SShreesha Rajashekar return 0;
1211f34b8d90SShreesha Rajashekar }
1212f34b8d90SShreesha Rajashekar
bcm_iproc_i2c_unreg_slave(struct i2c_client * slave)1213f34b8d90SShreesha Rajashekar static int bcm_iproc_i2c_unreg_slave(struct i2c_client *slave)
1214f34b8d90SShreesha Rajashekar {
1215f34b8d90SShreesha Rajashekar u32 tmp;
1216f34b8d90SShreesha Rajashekar struct bcm_iproc_i2c_dev *iproc_i2c = i2c_get_adapdata(slave->adapter);
1217f34b8d90SShreesha Rajashekar
1218f34b8d90SShreesha Rajashekar if (!iproc_i2c->slave)
1219f34b8d90SShreesha Rajashekar return -EINVAL;
1220f34b8d90SShreesha Rajashekar
1221b1eef236SDhananjay Phadke disable_irq(iproc_i2c->irq);
1222f34b8d90SShreesha Rajashekar
1223bba676ccSDhananjay Phadke tasklet_kill(&iproc_i2c->slave_rx_tasklet);
1224bba676ccSDhananjay Phadke
1225f34b8d90SShreesha Rajashekar /* disable all slave interrupts */
1226a9f0a81eSRayagonda Kokatanur tmp = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
1227f34b8d90SShreesha Rajashekar tmp &= ~(IE_S_ALL_INTERRUPT_MASK <<
1228f34b8d90SShreesha Rajashekar IE_S_ALL_INTERRUPT_SHIFT);
1229a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, tmp);
1230f34b8d90SShreesha Rajashekar
1231f34b8d90SShreesha Rajashekar /* Erase the slave address programmed */
1232a9f0a81eSRayagonda Kokatanur tmp = iproc_i2c_rd_reg(iproc_i2c, S_CFG_SMBUS_ADDR_OFFSET);
1233f34b8d90SShreesha Rajashekar tmp &= ~BIT(S_CFG_EN_NIC_SMB_ADDR3_SHIFT);
1234a9f0a81eSRayagonda Kokatanur iproc_i2c_wr_reg(iproc_i2c, S_CFG_SMBUS_ADDR_OFFSET, tmp);
1235f34b8d90SShreesha Rajashekar
1236b1eef236SDhananjay Phadke /* flush TX/RX FIFOs */
1237b1eef236SDhananjay Phadke tmp = (BIT(S_FIFO_RX_FLUSH_SHIFT) | BIT(S_FIFO_TX_FLUSH_SHIFT));
1238b1eef236SDhananjay Phadke iproc_i2c_wr_reg(iproc_i2c, S_FIFO_CTRL_OFFSET, tmp);
1239b1eef236SDhananjay Phadke
1240b1eef236SDhananjay Phadke /* clear all pending slave interrupts */
1241b1eef236SDhananjay Phadke iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, ISR_MASK_SLAVE);
1242b1eef236SDhananjay Phadke
1243b1eef236SDhananjay Phadke iproc_i2c->slave = NULL;
1244b1eef236SDhananjay Phadke
1245b1eef236SDhananjay Phadke enable_irq(iproc_i2c->irq);
1246b1eef236SDhananjay Phadke
1247f34b8d90SShreesha Rajashekar return 0;
1248f34b8d90SShreesha Rajashekar }
1249f34b8d90SShreesha Rajashekar
1250e6e5dd35SRay Jui static const struct of_device_id bcm_iproc_i2c_of_match[] = {
12519a103872SRayagonda Kokatanur {
12529a103872SRayagonda Kokatanur .compatible = "brcm,iproc-i2c",
12539a103872SRayagonda Kokatanur .data = (int *)IPROC_I2C,
12549a103872SRayagonda Kokatanur }, {
12559a103872SRayagonda Kokatanur .compatible = "brcm,iproc-nic-i2c",
12569a103872SRayagonda Kokatanur .data = (int *)IPROC_I2C_NIC,
12579a103872SRayagonda Kokatanur },
1258e6e5dd35SRay Jui { /* sentinel */ }
1259e6e5dd35SRay Jui };
1260e6e5dd35SRay Jui MODULE_DEVICE_TABLE(of, bcm_iproc_i2c_of_match);
1261e6e5dd35SRay Jui
1262e6e5dd35SRay Jui static struct platform_driver bcm_iproc_i2c_driver = {
1263e6e5dd35SRay Jui .driver = {
1264e6e5dd35SRay Jui .name = "bcm-iproc-i2c",
1265e6e5dd35SRay Jui .of_match_table = bcm_iproc_i2c_of_match,
12669dc96b75SPaul Cercueil .pm = pm_sleep_ptr(&bcm_iproc_i2c_pm_ops),
1267e6e5dd35SRay Jui },
1268e6e5dd35SRay Jui .probe = bcm_iproc_i2c_probe,
1269e190a0c3SUwe Kleine-König .remove_new = bcm_iproc_i2c_remove,
1270e6e5dd35SRay Jui };
1271e6e5dd35SRay Jui module_platform_driver(bcm_iproc_i2c_driver);
1272e6e5dd35SRay Jui
1273e6e5dd35SRay Jui MODULE_AUTHOR("Ray Jui <rjui@broadcom.com>");
1274e6e5dd35SRay Jui MODULE_DESCRIPTION("Broadcom iProc I2C Driver");
1275e6e5dd35SRay Jui MODULE_LICENSE("GPL v2");
1276