xref: /openbmc/linux/drivers/i2c/busses/i2c-brcmstb.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
12aec85b2SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
22aec85b2SThomas Gleixner // Copyright (C) 2014 Broadcom Corporation
3dd1aa252SKamal Dasu 
4dd1aa252SKamal Dasu #include <linux/clk.h>
5dd1aa252SKamal Dasu #include <linux/delay.h>
6dd1aa252SKamal Dasu #include <linux/device.h>
7dd1aa252SKamal Dasu #include <linux/i2c.h>
8dd1aa252SKamal Dasu #include <linux/interrupt.h>
9dd1aa252SKamal Dasu #include <linux/io.h>
10dd1aa252SKamal Dasu #include <linux/kernel.h>
11dd1aa252SKamal Dasu #include <linux/module.h>
12dd1aa252SKamal Dasu #include <linux/platform_device.h>
13dd1aa252SKamal Dasu #include <linux/sched.h>
14dd1aa252SKamal Dasu #include <linux/slab.h>
15dd1aa252SKamal Dasu 
16dd1aa252SKamal Dasu #define N_DATA_REGS					8
17dd1aa252SKamal Dasu 
18e2e5a2c6SKamal Dasu /*
19e2e5a2c6SKamal Dasu  * PER_I2C/BSC count register mask depends on 1 byte/4 byte data register
20e2e5a2c6SKamal Dasu  * size. Cable modem and DSL SoCs with Peripheral i2c cores use 1 byte per
21e2e5a2c6SKamal Dasu  * data register whereas STB SoCs use 4 byte per data register transfer,
22e2e5a2c6SKamal Dasu  * account for this difference in total count per transaction and mask to
23e2e5a2c6SKamal Dasu  * use.
24e2e5a2c6SKamal Dasu  */
25e2e5a2c6SKamal Dasu #define BSC_CNT_REG1_MASK(nb)	(nb == 1 ? GENMASK(3, 0) : GENMASK(5, 0))
26dd1aa252SKamal Dasu #define BSC_CNT_REG1_SHIFT	0
27dd1aa252SKamal Dasu 
28dd1aa252SKamal Dasu /* BSC CTL register field definitions */
29dd1aa252SKamal Dasu #define BSC_CTL_REG_DTF_MASK				0x00000003
30dd1aa252SKamal Dasu #define BSC_CTL_REG_SCL_SEL_MASK			0x00000030
31dd1aa252SKamal Dasu #define BSC_CTL_REG_SCL_SEL_SHIFT			4
32dd1aa252SKamal Dasu #define BSC_CTL_REG_INT_EN_MASK				0x00000040
33dd1aa252SKamal Dasu #define BSC_CTL_REG_INT_EN_SHIFT			6
34dd1aa252SKamal Dasu #define BSC_CTL_REG_DIV_CLK_MASK			0x00000080
35dd1aa252SKamal Dasu 
36e2e5a2c6SKamal Dasu /* BSC_IIC_ENABLE r/w enable and interrupt field definitions */
37dd1aa252SKamal Dasu #define BSC_IIC_EN_RESTART_MASK				0x00000040
38dd1aa252SKamal Dasu #define BSC_IIC_EN_NOSTART_MASK				0x00000020
39dd1aa252SKamal Dasu #define BSC_IIC_EN_NOSTOP_MASK				0x00000010
40dd1aa252SKamal Dasu #define BSC_IIC_EN_NOACK_MASK				0x00000004
41dd1aa252SKamal Dasu #define BSC_IIC_EN_INTRP_MASK				0x00000002
42dd1aa252SKamal Dasu #define BSC_IIC_EN_ENABLE_MASK				0x00000001
43dd1aa252SKamal Dasu 
44dd1aa252SKamal Dasu /* BSC_CTLHI control register field definitions */
45dd1aa252SKamal Dasu #define BSC_CTLHI_REG_INPUT_SWITCHING_LEVEL_MASK	0x00000080
46dd1aa252SKamal Dasu #define BSC_CTLHI_REG_DATAREG_SIZE_MASK			0x00000040
47dd1aa252SKamal Dasu #define BSC_CTLHI_REG_IGNORE_ACK_MASK			0x00000002
48dd1aa252SKamal Dasu #define BSC_CTLHI_REG_WAIT_DIS_MASK			0x00000001
49dd1aa252SKamal Dasu 
50dd1aa252SKamal Dasu #define I2C_TIMEOUT					100 /* msecs */
51dd1aa252SKamal Dasu 
52dd1aa252SKamal Dasu /* Condition mask used for non combined transfer */
53dd1aa252SKamal Dasu #define COND_RESTART		BSC_IIC_EN_RESTART_MASK
54dd1aa252SKamal Dasu #define COND_NOSTART		BSC_IIC_EN_NOSTART_MASK
55dd1aa252SKamal Dasu #define COND_NOSTOP		BSC_IIC_EN_NOSTOP_MASK
56dd1aa252SKamal Dasu #define COND_START_STOP		(COND_RESTART | COND_NOSTART | COND_NOSTOP)
57dd1aa252SKamal Dasu 
58dd1aa252SKamal Dasu /* BSC data transfer direction */
59dd1aa252SKamal Dasu #define DTF_WR_MASK		0x00000000
60dd1aa252SKamal Dasu #define DTF_RD_MASK		0x00000001
61dd1aa252SKamal Dasu /* BSC data transfer direction combined format */
62dd1aa252SKamal Dasu #define DTF_RD_WR_MASK		0x00000002
63dd1aa252SKamal Dasu #define DTF_WR_RD_MASK		0x00000003
64dd1aa252SKamal Dasu 
65dd1aa252SKamal Dasu #define INT_ENABLE		true
66dd1aa252SKamal Dasu #define INT_DISABLE		false
67dd1aa252SKamal Dasu 
68dd1aa252SKamal Dasu /* BSC block register map structure to cache fields to be written */
69dd1aa252SKamal Dasu struct bsc_regs {
70dd1aa252SKamal Dasu 	u32	chip_address;           /* slave address */
71dd1aa252SKamal Dasu 	u32	data_in[N_DATA_REGS];   /* tx data buffer*/
72dd1aa252SKamal Dasu 	u32	cnt_reg;		/* rx/tx data length */
73dd1aa252SKamal Dasu 	u32	ctl_reg;		/* control register */
74dd1aa252SKamal Dasu 	u32	iic_enable;		/* xfer enable and status */
75dd1aa252SKamal Dasu 	u32	data_out[N_DATA_REGS];  /* rx data buffer */
76dd1aa252SKamal Dasu 	u32	ctlhi_reg;		/* more control fields */
77dd1aa252SKamal Dasu 	u32	scl_param;		/* reserved */
78dd1aa252SKamal Dasu };
79dd1aa252SKamal Dasu 
80dd1aa252SKamal Dasu struct bsc_clk_param {
81dd1aa252SKamal Dasu 	u32 hz;
82dd1aa252SKamal Dasu 	u32 scl_mask;
83dd1aa252SKamal Dasu 	u32 div_mask;
84dd1aa252SKamal Dasu };
85dd1aa252SKamal Dasu 
86dd1aa252SKamal Dasu enum bsc_xfer_cmd {
87dd1aa252SKamal Dasu 	CMD_WR,
88dd1aa252SKamal Dasu 	CMD_RD,
89dd1aa252SKamal Dasu 	CMD_WR_NOACK,
90dd1aa252SKamal Dasu 	CMD_RD_NOACK,
91dd1aa252SKamal Dasu };
92dd1aa252SKamal Dasu 
93dd1aa252SKamal Dasu static char const *cmd_string[] = {
94dd1aa252SKamal Dasu 	[CMD_WR] = "WR",
95dd1aa252SKamal Dasu 	[CMD_RD] = "RD",
96dd1aa252SKamal Dasu 	[CMD_WR_NOACK] = "WR NOACK",
97dd1aa252SKamal Dasu 	[CMD_RD_NOACK] = "RD NOACK",
98dd1aa252SKamal Dasu };
99dd1aa252SKamal Dasu 
100dd1aa252SKamal Dasu enum bus_speeds {
101dd1aa252SKamal Dasu 	SPD_375K,
102dd1aa252SKamal Dasu 	SPD_390K,
103dd1aa252SKamal Dasu 	SPD_187K,
104dd1aa252SKamal Dasu 	SPD_200K,
105dd1aa252SKamal Dasu 	SPD_93K,
106dd1aa252SKamal Dasu 	SPD_97K,
107dd1aa252SKamal Dasu 	SPD_46K,
108dd1aa252SKamal Dasu 	SPD_50K
109dd1aa252SKamal Dasu };
110dd1aa252SKamal Dasu 
111dd1aa252SKamal Dasu static const struct bsc_clk_param bsc_clk[] = {
112dd1aa252SKamal Dasu 	[SPD_375K] = {
113dd1aa252SKamal Dasu 		.hz = 375000,
114dd1aa252SKamal Dasu 		.scl_mask = SPD_375K << BSC_CTL_REG_SCL_SEL_SHIFT,
115dd1aa252SKamal Dasu 		.div_mask = 0
116dd1aa252SKamal Dasu 	},
117dd1aa252SKamal Dasu 	[SPD_390K] = {
118dd1aa252SKamal Dasu 		.hz = 390000,
119dd1aa252SKamal Dasu 		.scl_mask = SPD_390K << BSC_CTL_REG_SCL_SEL_SHIFT,
120dd1aa252SKamal Dasu 		.div_mask = 0
121dd1aa252SKamal Dasu 	},
122dd1aa252SKamal Dasu 	[SPD_187K] = {
123dd1aa252SKamal Dasu 		.hz = 187500,
124dd1aa252SKamal Dasu 		.scl_mask = SPD_187K << BSC_CTL_REG_SCL_SEL_SHIFT,
125dd1aa252SKamal Dasu 		.div_mask = 0
126dd1aa252SKamal Dasu 	},
127dd1aa252SKamal Dasu 	[SPD_200K] = {
128dd1aa252SKamal Dasu 		.hz = 200000,
129dd1aa252SKamal Dasu 		.scl_mask = SPD_200K << BSC_CTL_REG_SCL_SEL_SHIFT,
130dd1aa252SKamal Dasu 		.div_mask = 0
131dd1aa252SKamal Dasu 	},
132dd1aa252SKamal Dasu 	[SPD_93K]  = {
133dd1aa252SKamal Dasu 		.hz = 93750,
134dd1aa252SKamal Dasu 		.scl_mask = SPD_375K << BSC_CTL_REG_SCL_SEL_SHIFT,
135dd1aa252SKamal Dasu 		.div_mask = BSC_CTL_REG_DIV_CLK_MASK
136dd1aa252SKamal Dasu 	},
137dd1aa252SKamal Dasu 	[SPD_97K]  = {
138dd1aa252SKamal Dasu 		.hz = 97500,
139dd1aa252SKamal Dasu 		.scl_mask = SPD_390K << BSC_CTL_REG_SCL_SEL_SHIFT,
140dd1aa252SKamal Dasu 		.div_mask = BSC_CTL_REG_DIV_CLK_MASK
141dd1aa252SKamal Dasu 	},
142dd1aa252SKamal Dasu 	[SPD_46K]  = {
143dd1aa252SKamal Dasu 		.hz = 46875,
144dd1aa252SKamal Dasu 		.scl_mask = SPD_187K << BSC_CTL_REG_SCL_SEL_SHIFT,
145dd1aa252SKamal Dasu 		.div_mask = BSC_CTL_REG_DIV_CLK_MASK
146dd1aa252SKamal Dasu 	},
147dd1aa252SKamal Dasu 	[SPD_50K]  = {
148dd1aa252SKamal Dasu 		.hz = 50000,
149dd1aa252SKamal Dasu 		.scl_mask = SPD_200K << BSC_CTL_REG_SCL_SEL_SHIFT,
150dd1aa252SKamal Dasu 		.div_mask = BSC_CTL_REG_DIV_CLK_MASK
151dd1aa252SKamal Dasu 	}
152dd1aa252SKamal Dasu };
153dd1aa252SKamal Dasu 
154dd1aa252SKamal Dasu struct brcmstb_i2c_dev {
155dd1aa252SKamal Dasu 	struct device *device;
156dd1aa252SKamal Dasu 	void __iomem *base;
157dd1aa252SKamal Dasu 	int irq;
158dd1aa252SKamal Dasu 	struct bsc_regs *bsc_regmap;
159dd1aa252SKamal Dasu 	struct i2c_adapter adapter;
160dd1aa252SKamal Dasu 	struct completion done;
161dd1aa252SKamal Dasu 	u32 clk_freq_hz;
162e2e5a2c6SKamal Dasu 	int data_regsz;
163dd1aa252SKamal Dasu };
164dd1aa252SKamal Dasu 
165dd1aa252SKamal Dasu /* register accessors for both be and le cpu arch */
166dd1aa252SKamal Dasu #ifdef CONFIG_CPU_BIG_ENDIAN
167dd1aa252SKamal Dasu #define __bsc_readl(_reg) ioread32be(_reg)
168dd1aa252SKamal Dasu #define __bsc_writel(_val, _reg) iowrite32be(_val, _reg)
169dd1aa252SKamal Dasu #else
170dd1aa252SKamal Dasu #define __bsc_readl(_reg) ioread32(_reg)
171dd1aa252SKamal Dasu #define __bsc_writel(_val, _reg) iowrite32(_val, _reg)
172dd1aa252SKamal Dasu #endif
173dd1aa252SKamal Dasu 
174dd1aa252SKamal Dasu #define bsc_readl(_dev, _reg)						\
175dd1aa252SKamal Dasu 	__bsc_readl(_dev->base + offsetof(struct bsc_regs, _reg))
176dd1aa252SKamal Dasu 
177dd1aa252SKamal Dasu #define bsc_writel(_dev, _val, _reg)					\
178dd1aa252SKamal Dasu 	__bsc_writel(_val, _dev->base + offsetof(struct bsc_regs, _reg))
179dd1aa252SKamal Dasu 
brcmstb_i2c_get_xfersz(struct brcmstb_i2c_dev * dev)180e2e5a2c6SKamal Dasu static inline int brcmstb_i2c_get_xfersz(struct brcmstb_i2c_dev *dev)
181e2e5a2c6SKamal Dasu {
182e2e5a2c6SKamal Dasu 	return (N_DATA_REGS * dev->data_regsz);
183e2e5a2c6SKamal Dasu }
184e2e5a2c6SKamal Dasu 
brcmstb_i2c_get_data_regsz(struct brcmstb_i2c_dev * dev)185e2e5a2c6SKamal Dasu static inline int brcmstb_i2c_get_data_regsz(struct brcmstb_i2c_dev *dev)
186e2e5a2c6SKamal Dasu {
187e2e5a2c6SKamal Dasu 	return dev->data_regsz;
188e2e5a2c6SKamal Dasu }
189e2e5a2c6SKamal Dasu 
brcmstb_i2c_enable_disable_irq(struct brcmstb_i2c_dev * dev,bool int_en)190dd1aa252SKamal Dasu static void brcmstb_i2c_enable_disable_irq(struct brcmstb_i2c_dev *dev,
191dd1aa252SKamal Dasu 					   bool int_en)
192dd1aa252SKamal Dasu {
193dd1aa252SKamal Dasu 
194dd1aa252SKamal Dasu 	if (int_en)
195dd1aa252SKamal Dasu 		/* Enable BSC  CTL interrupt line */
196dd1aa252SKamal Dasu 		dev->bsc_regmap->ctl_reg |= BSC_CTL_REG_INT_EN_MASK;
197dd1aa252SKamal Dasu 	else
198dd1aa252SKamal Dasu 		/* Disable BSC CTL interrupt line */
199dd1aa252SKamal Dasu 		dev->bsc_regmap->ctl_reg &= ~BSC_CTL_REG_INT_EN_MASK;
200dd1aa252SKamal Dasu 
201dd1aa252SKamal Dasu 	barrier();
202dd1aa252SKamal Dasu 	bsc_writel(dev, dev->bsc_regmap->ctl_reg, ctl_reg);
203dd1aa252SKamal Dasu }
204dd1aa252SKamal Dasu 
brcmstb_i2c_isr(int irq,void * devid)205dd1aa252SKamal Dasu static irqreturn_t brcmstb_i2c_isr(int irq, void *devid)
206dd1aa252SKamal Dasu {
207dd1aa252SKamal Dasu 	struct brcmstb_i2c_dev *dev = devid;
208dd1aa252SKamal Dasu 	u32 status_bsc_ctl = bsc_readl(dev, ctl_reg);
209dd1aa252SKamal Dasu 	u32 status_iic_intrp = bsc_readl(dev, iic_enable);
210dd1aa252SKamal Dasu 
211dd1aa252SKamal Dasu 	dev_dbg(dev->device, "isr CTL_REG %x IIC_EN %x\n",
212dd1aa252SKamal Dasu 		status_bsc_ctl, status_iic_intrp);
213dd1aa252SKamal Dasu 
214dd1aa252SKamal Dasu 	if (!(status_bsc_ctl & BSC_CTL_REG_INT_EN_MASK))
215dd1aa252SKamal Dasu 		return IRQ_NONE;
216dd1aa252SKamal Dasu 
217dd1aa252SKamal Dasu 	brcmstb_i2c_enable_disable_irq(dev, INT_DISABLE);
218fea03a6aSDaniel Wagner 	complete(&dev->done);
219dd1aa252SKamal Dasu 
220dd1aa252SKamal Dasu 	dev_dbg(dev->device, "isr handled");
221dd1aa252SKamal Dasu 	return IRQ_HANDLED;
222dd1aa252SKamal Dasu }
223dd1aa252SKamal Dasu 
224dd1aa252SKamal Dasu /* Wait for device to be ready */
brcmstb_i2c_wait_if_busy(struct brcmstb_i2c_dev * dev)225dd1aa252SKamal Dasu static int brcmstb_i2c_wait_if_busy(struct brcmstb_i2c_dev *dev)
226dd1aa252SKamal Dasu {
227dd1aa252SKamal Dasu 	unsigned long timeout = jiffies + msecs_to_jiffies(I2C_TIMEOUT);
228dd1aa252SKamal Dasu 
229dd1aa252SKamal Dasu 	while ((bsc_readl(dev, iic_enable) & BSC_IIC_EN_INTRP_MASK)) {
230dd1aa252SKamal Dasu 		if (time_after(jiffies, timeout))
231dd1aa252SKamal Dasu 			return -ETIMEDOUT;
232dd1aa252SKamal Dasu 		cpu_relax();
233dd1aa252SKamal Dasu 	}
234dd1aa252SKamal Dasu 	return 0;
235dd1aa252SKamal Dasu }
236dd1aa252SKamal Dasu 
237dd1aa252SKamal Dasu /* i2c xfer completion function, handles both irq and polling mode */
brcmstb_i2c_wait_for_completion(struct brcmstb_i2c_dev * dev)238dd1aa252SKamal Dasu static int brcmstb_i2c_wait_for_completion(struct brcmstb_i2c_dev *dev)
239dd1aa252SKamal Dasu {
240dd1aa252SKamal Dasu 	int ret = 0;
241dd1aa252SKamal Dasu 	unsigned long timeout = msecs_to_jiffies(I2C_TIMEOUT);
242dd1aa252SKamal Dasu 
243dd1aa252SKamal Dasu 	if (dev->irq >= 0) {
244dd1aa252SKamal Dasu 		if (!wait_for_completion_timeout(&dev->done, timeout))
245dd1aa252SKamal Dasu 			ret = -ETIMEDOUT;
246dd1aa252SKamal Dasu 	} else {
247dd1aa252SKamal Dasu 		/* we are in polling mode */
248dd1aa252SKamal Dasu 		u32 bsc_intrp;
249dd1aa252SKamal Dasu 		unsigned long time_left = jiffies + timeout;
250dd1aa252SKamal Dasu 
251dd1aa252SKamal Dasu 		do {
252dd1aa252SKamal Dasu 			bsc_intrp = bsc_readl(dev, iic_enable) &
253dd1aa252SKamal Dasu 				BSC_IIC_EN_INTRP_MASK;
254dd1aa252SKamal Dasu 			if (time_after(jiffies, time_left)) {
255dd1aa252SKamal Dasu 				ret = -ETIMEDOUT;
256dd1aa252SKamal Dasu 				break;
257dd1aa252SKamal Dasu 			}
258dd1aa252SKamal Dasu 			cpu_relax();
259dd1aa252SKamal Dasu 		} while (!bsc_intrp);
260dd1aa252SKamal Dasu 	}
261dd1aa252SKamal Dasu 
262dd1aa252SKamal Dasu 	if (dev->irq < 0 || ret == -ETIMEDOUT)
263dd1aa252SKamal Dasu 		brcmstb_i2c_enable_disable_irq(dev, INT_DISABLE);
264dd1aa252SKamal Dasu 
265dd1aa252SKamal Dasu 	return ret;
266dd1aa252SKamal Dasu }
267dd1aa252SKamal Dasu 
268dd1aa252SKamal Dasu /* Set xfer START/STOP conditions for subsequent transfer */
brcmstb_set_i2c_start_stop(struct brcmstb_i2c_dev * dev,u32 cond_flag)269dd1aa252SKamal Dasu static void brcmstb_set_i2c_start_stop(struct brcmstb_i2c_dev *dev,
270dd1aa252SKamal Dasu 				       u32 cond_flag)
271dd1aa252SKamal Dasu {
272dd1aa252SKamal Dasu 	u32 regval = dev->bsc_regmap->iic_enable;
273dd1aa252SKamal Dasu 
274dd1aa252SKamal Dasu 	dev->bsc_regmap->iic_enable = (regval & ~COND_START_STOP) | cond_flag;
275dd1aa252SKamal Dasu }
276dd1aa252SKamal Dasu 
277dd1aa252SKamal Dasu /* Send I2C request check completion */
brcmstb_send_i2c_cmd(struct brcmstb_i2c_dev * dev,enum bsc_xfer_cmd cmd)278dd1aa252SKamal Dasu static int brcmstb_send_i2c_cmd(struct brcmstb_i2c_dev *dev,
279dd1aa252SKamal Dasu 				enum bsc_xfer_cmd cmd)
280dd1aa252SKamal Dasu {
281dd1aa252SKamal Dasu 	int rc = 0;
282dd1aa252SKamal Dasu 	struct bsc_regs *pi2creg = dev->bsc_regmap;
283dd1aa252SKamal Dasu 
284dd1aa252SKamal Dasu 	/* Make sure the hardware is ready */
285dd1aa252SKamal Dasu 	rc = brcmstb_i2c_wait_if_busy(dev);
286dd1aa252SKamal Dasu 	if (rc < 0)
287dd1aa252SKamal Dasu 		return rc;
288dd1aa252SKamal Dasu 
289dd1aa252SKamal Dasu 	/* only if we are in interrupt mode */
290dd1aa252SKamal Dasu 	if (dev->irq >= 0)
291dd1aa252SKamal Dasu 		reinit_completion(&dev->done);
292dd1aa252SKamal Dasu 
293dd1aa252SKamal Dasu 	/* enable BSC CTL interrupt line */
294dd1aa252SKamal Dasu 	brcmstb_i2c_enable_disable_irq(dev, INT_ENABLE);
295dd1aa252SKamal Dasu 
296dd1aa252SKamal Dasu 	/* initiate transfer by setting iic_enable */
297dd1aa252SKamal Dasu 	pi2creg->iic_enable |= BSC_IIC_EN_ENABLE_MASK;
298dd1aa252SKamal Dasu 	bsc_writel(dev, pi2creg->iic_enable, iic_enable);
299dd1aa252SKamal Dasu 
300dd1aa252SKamal Dasu 	/* Wait for transaction to finish or timeout */
301dd1aa252SKamal Dasu 	rc = brcmstb_i2c_wait_for_completion(dev);
302dd1aa252SKamal Dasu 	if (rc) {
303dd1aa252SKamal Dasu 		dev_dbg(dev->device, "intr timeout for cmd %s\n",
304dd1aa252SKamal Dasu 			cmd_string[cmd]);
305dd1aa252SKamal Dasu 		goto cmd_out;
306dd1aa252SKamal Dasu 	}
307dd1aa252SKamal Dasu 
308a1858ce0SMaxime Ripard 	if ((cmd == CMD_RD || cmd == CMD_WR) &&
309dd1aa252SKamal Dasu 	    bsc_readl(dev, iic_enable) & BSC_IIC_EN_NOACK_MASK) {
310dd1aa252SKamal Dasu 		rc = -EREMOTEIO;
311dd1aa252SKamal Dasu 		dev_dbg(dev->device, "controller received NOACK intr for %s\n",
312dd1aa252SKamal Dasu 			cmd_string[cmd]);
313dd1aa252SKamal Dasu 	}
314dd1aa252SKamal Dasu 
315dd1aa252SKamal Dasu cmd_out:
316dd1aa252SKamal Dasu 	bsc_writel(dev, 0, cnt_reg);
317dd1aa252SKamal Dasu 	bsc_writel(dev, 0, iic_enable);
318dd1aa252SKamal Dasu 
319dd1aa252SKamal Dasu 	return rc;
320dd1aa252SKamal Dasu }
321dd1aa252SKamal Dasu 
322dd1aa252SKamal Dasu /* Actual data transfer through the BSC master */
brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev * dev,u8 * buf,unsigned int len,struct i2c_msg * pmsg)323dd1aa252SKamal Dasu static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev,
324dd1aa252SKamal Dasu 				     u8 *buf, unsigned int len,
325dd1aa252SKamal Dasu 				     struct i2c_msg *pmsg)
326dd1aa252SKamal Dasu {
327e2e5a2c6SKamal Dasu 	int cnt, byte, i, rc;
328dd1aa252SKamal Dasu 	enum bsc_xfer_cmd cmd;
329dd1aa252SKamal Dasu 	u32 ctl_reg;
330dd1aa252SKamal Dasu 	struct bsc_regs *pi2creg = dev->bsc_regmap;
331dd1aa252SKamal Dasu 	int no_ack = pmsg->flags & I2C_M_IGNORE_NAK;
332e2e5a2c6SKamal Dasu 	int data_regsz = brcmstb_i2c_get_data_regsz(dev);
333dd1aa252SKamal Dasu 
334dd1aa252SKamal Dasu 	/* see if the transaction needs to check NACK conditions */
33594a0b0b9SJaedon Shin 	if (no_ack) {
336dd1aa252SKamal Dasu 		cmd = (pmsg->flags & I2C_M_RD) ? CMD_RD_NOACK
337dd1aa252SKamal Dasu 			: CMD_WR_NOACK;
338dd1aa252SKamal Dasu 		pi2creg->ctlhi_reg |= BSC_CTLHI_REG_IGNORE_ACK_MASK;
339dd1aa252SKamal Dasu 	} else {
340dd1aa252SKamal Dasu 		cmd = (pmsg->flags & I2C_M_RD) ? CMD_RD : CMD_WR;
341dd1aa252SKamal Dasu 		pi2creg->ctlhi_reg &= ~BSC_CTLHI_REG_IGNORE_ACK_MASK;
342dd1aa252SKamal Dasu 	}
343dd1aa252SKamal Dasu 	bsc_writel(dev, pi2creg->ctlhi_reg, ctlhi_reg);
344dd1aa252SKamal Dasu 
345dd1aa252SKamal Dasu 	/* set data transfer direction */
346dd1aa252SKamal Dasu 	ctl_reg = pi2creg->ctl_reg & ~BSC_CTL_REG_DTF_MASK;
347dd1aa252SKamal Dasu 	if (cmd == CMD_WR || cmd == CMD_WR_NOACK)
348dd1aa252SKamal Dasu 		pi2creg->ctl_reg = ctl_reg | DTF_WR_MASK;
349dd1aa252SKamal Dasu 	else
350dd1aa252SKamal Dasu 		pi2creg->ctl_reg = ctl_reg | DTF_RD_MASK;
351dd1aa252SKamal Dasu 
352dd1aa252SKamal Dasu 	/* set the read/write length */
353e2e5a2c6SKamal Dasu 	bsc_writel(dev, BSC_CNT_REG1_MASK(data_regsz) &
354e2e5a2c6SKamal Dasu 		   (len << BSC_CNT_REG1_SHIFT), cnt_reg);
355dd1aa252SKamal Dasu 
356dd1aa252SKamal Dasu 	/* Write data into data_in register */
357e2e5a2c6SKamal Dasu 
358dd1aa252SKamal Dasu 	if (cmd == CMD_WR || cmd == CMD_WR_NOACK) {
359e2e5a2c6SKamal Dasu 		for (cnt = 0, i = 0; cnt < len; cnt += data_regsz, i++) {
360dd1aa252SKamal Dasu 			u32 word = 0;
361dd1aa252SKamal Dasu 
362e2e5a2c6SKamal Dasu 			for (byte = 0; byte < data_regsz; byte++) {
363e2e5a2c6SKamal Dasu 				word >>= BITS_PER_BYTE;
364dd1aa252SKamal Dasu 				if ((cnt + byte) < len)
365e2e5a2c6SKamal Dasu 					word |= buf[cnt + byte] <<
366e2e5a2c6SKamal Dasu 					(BITS_PER_BYTE * (data_regsz - 1));
367dd1aa252SKamal Dasu 			}
368e2e5a2c6SKamal Dasu 			bsc_writel(dev, word, data_in[i]);
369dd1aa252SKamal Dasu 		}
370dd1aa252SKamal Dasu 	}
371dd1aa252SKamal Dasu 
372dd1aa252SKamal Dasu 	/* Initiate xfer, the function will return on completion */
373dd1aa252SKamal Dasu 	rc = brcmstb_send_i2c_cmd(dev, cmd);
374dd1aa252SKamal Dasu 
375dd1aa252SKamal Dasu 	if (rc != 0) {
376dd1aa252SKamal Dasu 		dev_dbg(dev->device, "%s failure", cmd_string[cmd]);
377dd1aa252SKamal Dasu 		return rc;
378dd1aa252SKamal Dasu 	}
379dd1aa252SKamal Dasu 
380e2e5a2c6SKamal Dasu 	/* Read data from data_out register */
381dd1aa252SKamal Dasu 	if (cmd == CMD_RD || cmd == CMD_RD_NOACK) {
382e2e5a2c6SKamal Dasu 		for (cnt = 0, i = 0; cnt < len; cnt += data_regsz, i++) {
383e2e5a2c6SKamal Dasu 			u32 data = bsc_readl(dev, data_out[i]);
384dd1aa252SKamal Dasu 
385e2e5a2c6SKamal Dasu 			for (byte = 0; byte < data_regsz &&
386dd1aa252SKamal Dasu 				     (byte + cnt) < len; byte++) {
387dd1aa252SKamal Dasu 				buf[cnt + byte] = data & 0xff;
388e2e5a2c6SKamal Dasu 				data >>= BITS_PER_BYTE;
389dd1aa252SKamal Dasu 			}
390dd1aa252SKamal Dasu 		}
391dd1aa252SKamal Dasu 	}
392dd1aa252SKamal Dasu 
393dd1aa252SKamal Dasu 	return 0;
394dd1aa252SKamal Dasu }
395dd1aa252SKamal Dasu 
396dd1aa252SKamal Dasu /* Write a single byte of data to the i2c bus */
brcmstb_i2c_write_data_byte(struct brcmstb_i2c_dev * dev,u8 * buf,unsigned int nak_expected)397dd1aa252SKamal Dasu static int brcmstb_i2c_write_data_byte(struct brcmstb_i2c_dev *dev,
398dd1aa252SKamal Dasu 				       u8 *buf, unsigned int nak_expected)
399dd1aa252SKamal Dasu {
400dd1aa252SKamal Dasu 	enum bsc_xfer_cmd cmd = nak_expected ? CMD_WR : CMD_WR_NOACK;
401dd1aa252SKamal Dasu 
402dd1aa252SKamal Dasu 	bsc_writel(dev, 1, cnt_reg);
403dd1aa252SKamal Dasu 	bsc_writel(dev, *buf, data_in);
404dd1aa252SKamal Dasu 
405dd1aa252SKamal Dasu 	return brcmstb_send_i2c_cmd(dev, cmd);
406dd1aa252SKamal Dasu }
407dd1aa252SKamal Dasu 
408dd1aa252SKamal Dasu /* Send i2c address */
brcmstb_i2c_do_addr(struct brcmstb_i2c_dev * dev,struct i2c_msg * msg)409dd1aa252SKamal Dasu static int brcmstb_i2c_do_addr(struct brcmstb_i2c_dev *dev,
410dd1aa252SKamal Dasu 			       struct i2c_msg *msg)
411dd1aa252SKamal Dasu {
412dd1aa252SKamal Dasu 	unsigned char addr;
413dd1aa252SKamal Dasu 
414dd1aa252SKamal Dasu 	if (msg->flags & I2C_M_TEN) {
415dd1aa252SKamal Dasu 		/* First byte is 11110XX0 where XX is upper 2 bits */
416dd1aa252SKamal Dasu 		addr = 0xF0 | ((msg->addr & 0x300) >> 7);
417dd1aa252SKamal Dasu 		bsc_writel(dev, addr, chip_address);
418dd1aa252SKamal Dasu 
419dd1aa252SKamal Dasu 		/* Second byte is the remaining 8 bits */
420dd1aa252SKamal Dasu 		addr = msg->addr & 0xFF;
421dd1aa252SKamal Dasu 		if (brcmstb_i2c_write_data_byte(dev, &addr, 0) < 0)
422dd1aa252SKamal Dasu 			return -EREMOTEIO;
423dd1aa252SKamal Dasu 
424dd1aa252SKamal Dasu 		if (msg->flags & I2C_M_RD) {
425dd1aa252SKamal Dasu 			/* For read, send restart without stop condition */
426dd1aa252SKamal Dasu 			brcmstb_set_i2c_start_stop(dev, COND_RESTART
427dd1aa252SKamal Dasu 						   | COND_NOSTOP);
428dd1aa252SKamal Dasu 			/* Then re-send the first byte with the read bit set */
429dd1aa252SKamal Dasu 			addr = 0xF0 | ((msg->addr & 0x300) >> 7) | 0x01;
430dd1aa252SKamal Dasu 			if (brcmstb_i2c_write_data_byte(dev, &addr, 0) < 0)
431dd1aa252SKamal Dasu 				return -EREMOTEIO;
432dd1aa252SKamal Dasu 
433dd1aa252SKamal Dasu 		}
434dd1aa252SKamal Dasu 	} else {
435fa5ce47aSWolfram Sang 		addr = i2c_8bit_addr_from_msg(msg);
436dd1aa252SKamal Dasu 
437dd1aa252SKamal Dasu 		bsc_writel(dev, addr, chip_address);
438dd1aa252SKamal Dasu 	}
439dd1aa252SKamal Dasu 
440dd1aa252SKamal Dasu 	return 0;
441dd1aa252SKamal Dasu }
442dd1aa252SKamal Dasu 
443dd1aa252SKamal Dasu /* Master transfer function */
brcmstb_i2c_xfer(struct i2c_adapter * adapter,struct i2c_msg msgs[],int num)444dd1aa252SKamal Dasu static int brcmstb_i2c_xfer(struct i2c_adapter *adapter,
445dd1aa252SKamal Dasu 			    struct i2c_msg msgs[], int num)
446dd1aa252SKamal Dasu {
447dd1aa252SKamal Dasu 	struct brcmstb_i2c_dev *dev = i2c_get_adapdata(adapter);
448dd1aa252SKamal Dasu 	struct i2c_msg *pmsg;
449dd1aa252SKamal Dasu 	int rc = 0;
450dd1aa252SKamal Dasu 	int i;
451dd1aa252SKamal Dasu 	int bytes_to_xfer;
452dd1aa252SKamal Dasu 	u8 *tmp_buf;
453dd1aa252SKamal Dasu 	int len = 0;
454e2e5a2c6SKamal Dasu 	int xfersz = brcmstb_i2c_get_xfersz(dev);
4552de3ec4fSJaedon Shin 	u32 cond, cond_per_msg;
456dd1aa252SKamal Dasu 
457dd1aa252SKamal Dasu 	/* Loop through all messages */
458dd1aa252SKamal Dasu 	for (i = 0; i < num; i++) {
459dd1aa252SKamal Dasu 		pmsg = &msgs[i];
460dd1aa252SKamal Dasu 		len = pmsg->len;
461dd1aa252SKamal Dasu 		tmp_buf = pmsg->buf;
462dd1aa252SKamal Dasu 
463dd1aa252SKamal Dasu 		dev_dbg(dev->device,
464dd1aa252SKamal Dasu 			"msg# %d/%d flg %x buf %x len %d\n", i,
465dd1aa252SKamal Dasu 			num - 1, pmsg->flags,
466dd1aa252SKamal Dasu 			pmsg->buf ? pmsg->buf[0] : '0', pmsg->len);
467dd1aa252SKamal Dasu 
468dd1aa252SKamal Dasu 		if (i < (num - 1) && (msgs[i + 1].flags & I2C_M_NOSTART))
4692de3ec4fSJaedon Shin 			cond = ~COND_START_STOP;
470dd1aa252SKamal Dasu 		else
4712de3ec4fSJaedon Shin 			cond = COND_RESTART | COND_NOSTOP;
4722de3ec4fSJaedon Shin 
4732de3ec4fSJaedon Shin 		brcmstb_set_i2c_start_stop(dev, cond);
474dd1aa252SKamal Dasu 
475dd1aa252SKamal Dasu 		/* Send slave address */
476dd1aa252SKamal Dasu 		if (!(pmsg->flags & I2C_M_NOSTART)) {
477dd1aa252SKamal Dasu 			rc = brcmstb_i2c_do_addr(dev, pmsg);
478dd1aa252SKamal Dasu 			if (rc < 0) {
479dd1aa252SKamal Dasu 				dev_dbg(dev->device,
480dd1aa252SKamal Dasu 					"NACK for addr %2.2x msg#%d rc = %d\n",
481dd1aa252SKamal Dasu 					pmsg->addr, i, rc);
482dd1aa252SKamal Dasu 				goto out;
483dd1aa252SKamal Dasu 			}
484dd1aa252SKamal Dasu 		}
485dd1aa252SKamal Dasu 
4862de3ec4fSJaedon Shin 		cond_per_msg = cond;
4872de3ec4fSJaedon Shin 
488dd1aa252SKamal Dasu 		/* Perform data transfer */
489dd1aa252SKamal Dasu 		while (len) {
490e2e5a2c6SKamal Dasu 			bytes_to_xfer = min(len, xfersz);
491dd1aa252SKamal Dasu 
4922de3ec4fSJaedon Shin 			if (len <= xfersz) {
4932de3ec4fSJaedon Shin 				if (i == (num - 1))
4942de3ec4fSJaedon Shin 					cond_per_msg = cond_per_msg &
4952de3ec4fSJaedon Shin 						~(COND_RESTART | COND_NOSTOP);
4962de3ec4fSJaedon Shin 				else
4972de3ec4fSJaedon Shin 					cond_per_msg = cond;
4982de3ec4fSJaedon Shin 			} else {
4992de3ec4fSJaedon Shin 				cond_per_msg = (cond_per_msg & ~COND_RESTART) |
5002de3ec4fSJaedon Shin 					COND_NOSTOP;
5012de3ec4fSJaedon Shin 			}
5022de3ec4fSJaedon Shin 
5032de3ec4fSJaedon Shin 			brcmstb_set_i2c_start_stop(dev, cond_per_msg);
504dd1aa252SKamal Dasu 
505dd1aa252SKamal Dasu 			rc = brcmstb_i2c_xfer_bsc_data(dev, tmp_buf,
506dd1aa252SKamal Dasu 						       bytes_to_xfer, pmsg);
507dd1aa252SKamal Dasu 			if (rc < 0)
508dd1aa252SKamal Dasu 				goto out;
509dd1aa252SKamal Dasu 
510dd1aa252SKamal Dasu 			len -=  bytes_to_xfer;
511dd1aa252SKamal Dasu 			tmp_buf += bytes_to_xfer;
5122de3ec4fSJaedon Shin 
5132de3ec4fSJaedon Shin 			cond_per_msg = COND_NOSTART | COND_NOSTOP;
514dd1aa252SKamal Dasu 		}
515dd1aa252SKamal Dasu 	}
516dd1aa252SKamal Dasu 
517dd1aa252SKamal Dasu 	rc = num;
518dd1aa252SKamal Dasu out:
519dd1aa252SKamal Dasu 	return rc;
520dd1aa252SKamal Dasu 
521dd1aa252SKamal Dasu }
522dd1aa252SKamal Dasu 
brcmstb_i2c_functionality(struct i2c_adapter * adap)523dd1aa252SKamal Dasu static u32 brcmstb_i2c_functionality(struct i2c_adapter *adap)
524dd1aa252SKamal Dasu {
525dd1aa252SKamal Dasu 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR
526dd1aa252SKamal Dasu 		| I2C_FUNC_NOSTART | I2C_FUNC_PROTOCOL_MANGLING;
527dd1aa252SKamal Dasu }
528dd1aa252SKamal Dasu 
529dd1aa252SKamal Dasu static const struct i2c_algorithm brcmstb_i2c_algo = {
530dd1aa252SKamal Dasu 	.master_xfer = brcmstb_i2c_xfer,
531dd1aa252SKamal Dasu 	.functionality = brcmstb_i2c_functionality,
532dd1aa252SKamal Dasu };
533dd1aa252SKamal Dasu 
brcmstb_i2c_set_bus_speed(struct brcmstb_i2c_dev * dev)534dd1aa252SKamal Dasu static void brcmstb_i2c_set_bus_speed(struct brcmstb_i2c_dev *dev)
535dd1aa252SKamal Dasu {
536dd1aa252SKamal Dasu 	int i = 0, num_speeds = ARRAY_SIZE(bsc_clk);
537dd1aa252SKamal Dasu 	u32 clk_freq_hz = dev->clk_freq_hz;
538dd1aa252SKamal Dasu 
539dd1aa252SKamal Dasu 	for (i = 0; i < num_speeds; i++) {
540dd1aa252SKamal Dasu 		if (bsc_clk[i].hz == clk_freq_hz) {
541dd1aa252SKamal Dasu 			dev->bsc_regmap->ctl_reg &= ~(BSC_CTL_REG_SCL_SEL_MASK
542dd1aa252SKamal Dasu 						| BSC_CTL_REG_DIV_CLK_MASK);
543dd1aa252SKamal Dasu 			dev->bsc_regmap->ctl_reg |= (bsc_clk[i].scl_mask |
544dd1aa252SKamal Dasu 						     bsc_clk[i].div_mask);
545dd1aa252SKamal Dasu 			bsc_writel(dev, dev->bsc_regmap->ctl_reg, ctl_reg);
546dd1aa252SKamal Dasu 			break;
547dd1aa252SKamal Dasu 		}
548dd1aa252SKamal Dasu 	}
549dd1aa252SKamal Dasu 
550dd1aa252SKamal Dasu 	/* in case we did not get find a valid speed */
551dd1aa252SKamal Dasu 	if (i == num_speeds) {
552dd1aa252SKamal Dasu 		i = (bsc_readl(dev, ctl_reg) & BSC_CTL_REG_SCL_SEL_MASK) >>
553dd1aa252SKamal Dasu 			BSC_CTL_REG_SCL_SEL_SHIFT;
554dd1aa252SKamal Dasu 		dev_warn(dev->device, "leaving current clock-frequency @ %dHz\n",
555dd1aa252SKamal Dasu 			bsc_clk[i].hz);
556dd1aa252SKamal Dasu 	}
557dd1aa252SKamal Dasu }
558dd1aa252SKamal Dasu 
brcmstb_i2c_set_bsc_reg_defaults(struct brcmstb_i2c_dev * dev)559dd1aa252SKamal Dasu static void brcmstb_i2c_set_bsc_reg_defaults(struct brcmstb_i2c_dev *dev)
560dd1aa252SKamal Dasu {
561e2e5a2c6SKamal Dasu 	if (brcmstb_i2c_get_data_regsz(dev) == sizeof(u32))
562e2e5a2c6SKamal Dasu 		/* set 4 byte data in/out xfers  */
563dd1aa252SKamal Dasu 		dev->bsc_regmap->ctlhi_reg = BSC_CTLHI_REG_DATAREG_SIZE_MASK;
564e2e5a2c6SKamal Dasu 	else
565e2e5a2c6SKamal Dasu 		dev->bsc_regmap->ctlhi_reg &= ~BSC_CTLHI_REG_DATAREG_SIZE_MASK;
566e2e5a2c6SKamal Dasu 
567dd1aa252SKamal Dasu 	bsc_writel(dev, dev->bsc_regmap->ctlhi_reg, ctlhi_reg);
568dd1aa252SKamal Dasu 	/* set bus speed */
569dd1aa252SKamal Dasu 	brcmstb_i2c_set_bus_speed(dev);
570dd1aa252SKamal Dasu }
571dd1aa252SKamal Dasu 
572d31f59eaSMaxime Ripard #define AUTOI2C_CTRL0		0x26c
573d31f59eaSMaxime Ripard #define AUTOI2C_CTRL0_RELEASE_BSC	BIT(1)
574d31f59eaSMaxime Ripard 
bcm2711_release_bsc(struct brcmstb_i2c_dev * dev)575d31f59eaSMaxime Ripard static int bcm2711_release_bsc(struct brcmstb_i2c_dev *dev)
576d31f59eaSMaxime Ripard {
577d31f59eaSMaxime Ripard 	struct platform_device *pdev = to_platform_device(dev->device);
578d31f59eaSMaxime Ripard 	void __iomem *autoi2c;
579d31f59eaSMaxime Ripard 
580d31f59eaSMaxime Ripard 	/* Map hardware registers */
5812a37dec1SYe Xingchen 	autoi2c = devm_platform_ioremap_resource_byname(pdev, "auto-i2c");
582d31f59eaSMaxime Ripard 	if (IS_ERR(autoi2c))
583d31f59eaSMaxime Ripard 		return PTR_ERR(autoi2c);
584d31f59eaSMaxime Ripard 
585d31f59eaSMaxime Ripard 	writel(AUTOI2C_CTRL0_RELEASE_BSC, autoi2c + AUTOI2C_CTRL0);
586d31f59eaSMaxime Ripard 	devm_iounmap(&pdev->dev, autoi2c);
587d31f59eaSMaxime Ripard 
588d31f59eaSMaxime Ripard 	/* We need to reset the controller after the release */
589d31f59eaSMaxime Ripard 	dev->bsc_regmap->iic_enable = 0;
590d31f59eaSMaxime Ripard 	bsc_writel(dev, dev->bsc_regmap->iic_enable, iic_enable);
591d31f59eaSMaxime Ripard 
592d31f59eaSMaxime Ripard 	return 0;
593d31f59eaSMaxime Ripard }
594d31f59eaSMaxime Ripard 
brcmstb_i2c_probe(struct platform_device * pdev)595dd1aa252SKamal Dasu static int brcmstb_i2c_probe(struct platform_device *pdev)
596dd1aa252SKamal Dasu {
597dd1aa252SKamal Dasu 	struct brcmstb_i2c_dev *dev;
598dd1aa252SKamal Dasu 	struct i2c_adapter *adap;
599dd1aa252SKamal Dasu 	const char *int_name;
600*f9dce8d6SYangtao Li 	int rc;
601dd1aa252SKamal Dasu 
602dd1aa252SKamal Dasu 	/* Allocate memory for private data structure */
603dd1aa252SKamal Dasu 	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
604dd1aa252SKamal Dasu 	if (!dev)
605dd1aa252SKamal Dasu 		return -ENOMEM;
606dd1aa252SKamal Dasu 
6077314d22aSWolfram Sang 	dev->bsc_regmap = devm_kzalloc(&pdev->dev, sizeof(*dev->bsc_regmap), GFP_KERNEL);
608dd1aa252SKamal Dasu 	if (!dev->bsc_regmap)
609dd1aa252SKamal Dasu 		return -ENOMEM;
610dd1aa252SKamal Dasu 
611dd1aa252SKamal Dasu 	platform_set_drvdata(pdev, dev);
612dd1aa252SKamal Dasu 	dev->device = &pdev->dev;
613dd1aa252SKamal Dasu 	init_completion(&dev->done);
614dd1aa252SKamal Dasu 
615dd1aa252SKamal Dasu 	/* Map hardware registers */
616*f9dce8d6SYangtao Li 	dev->base = devm_platform_ioremap_resource(pdev, 0);
617*f9dce8d6SYangtao Li 	if (IS_ERR(dev->base))
618*f9dce8d6SYangtao Li 		return PTR_ERR(dev->base);
619dd1aa252SKamal Dasu 
620d31f59eaSMaxime Ripard 	if (of_device_is_compatible(dev->device->of_node,
621d31f59eaSMaxime Ripard 				    "brcm,bcm2711-hdmi-i2c")) {
622d31f59eaSMaxime Ripard 		rc = bcm2711_release_bsc(dev);
623d31f59eaSMaxime Ripard 		if (rc)
624*f9dce8d6SYangtao Li 			return rc;
625d31f59eaSMaxime Ripard 	}
626d31f59eaSMaxime Ripard 
627dd1aa252SKamal Dasu 	rc = of_property_read_string(dev->device->of_node, "interrupt-names",
628dd1aa252SKamal Dasu 				     &int_name);
629dd1aa252SKamal Dasu 	if (rc < 0)
630dd1aa252SKamal Dasu 		int_name = NULL;
631dd1aa252SKamal Dasu 
632dd1aa252SKamal Dasu 	/* Get the interrupt number */
633aef6f2e7SDave Stevenson 	dev->irq = platform_get_irq_optional(pdev, 0);
634dd1aa252SKamal Dasu 
635dd1aa252SKamal Dasu 	/* disable the bsc interrupt line */
636dd1aa252SKamal Dasu 	brcmstb_i2c_enable_disable_irq(dev, INT_DISABLE);
637dd1aa252SKamal Dasu 
638dd1aa252SKamal Dasu 	/* register the ISR handler */
639aef6f2e7SDave Stevenson 	if (dev->irq >= 0) {
640dd1aa252SKamal Dasu 		rc = devm_request_irq(&pdev->dev, dev->irq, brcmstb_i2c_isr,
641dd1aa252SKamal Dasu 				      IRQF_SHARED,
642dd1aa252SKamal Dasu 				      int_name ? int_name : pdev->name,
643dd1aa252SKamal Dasu 				      dev);
644dd1aa252SKamal Dasu 
645dd1aa252SKamal Dasu 		if (rc) {
646dd1aa252SKamal Dasu 			dev_dbg(dev->device, "falling back to polling mode");
647dd1aa252SKamal Dasu 			dev->irq = -1;
648dd1aa252SKamal Dasu 		}
649aef6f2e7SDave Stevenson 	}
650dd1aa252SKamal Dasu 
651dd1aa252SKamal Dasu 	if (of_property_read_u32(dev->device->of_node,
652dd1aa252SKamal Dasu 				 "clock-frequency", &dev->clk_freq_hz)) {
653dd1aa252SKamal Dasu 		dev_warn(dev->device, "setting clock-frequency@%dHz\n",
654dd1aa252SKamal Dasu 			 bsc_clk[0].hz);
655dd1aa252SKamal Dasu 		dev->clk_freq_hz = bsc_clk[0].hz;
656dd1aa252SKamal Dasu 	}
657dd1aa252SKamal Dasu 
658e2e5a2c6SKamal Dasu 	/* set the data in/out register size for compatible SoCs */
659e2e5a2c6SKamal Dasu 	if (of_device_is_compatible(dev->device->of_node,
660834cea3aSRafał Miłecki 				    "brcm,brcmper-i2c"))
661e2e5a2c6SKamal Dasu 		dev->data_regsz = sizeof(u8);
662e2e5a2c6SKamal Dasu 	else
663e2e5a2c6SKamal Dasu 		dev->data_regsz = sizeof(u32);
664e2e5a2c6SKamal Dasu 
665dd1aa252SKamal Dasu 	brcmstb_i2c_set_bsc_reg_defaults(dev);
666dd1aa252SKamal Dasu 
667dd1aa252SKamal Dasu 	/* Add the i2c adapter */
668dd1aa252SKamal Dasu 	adap = &dev->adapter;
669dd1aa252SKamal Dasu 	i2c_set_adapdata(adap, dev);
670dd1aa252SKamal Dasu 	adap->owner = THIS_MODULE;
671ea1558ceSWolfram Sang 	strscpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name));
672dd1aa252SKamal Dasu 	adap->algo = &brcmstb_i2c_algo;
673dd1aa252SKamal Dasu 	adap->dev.parent = &pdev->dev;
674dd1aa252SKamal Dasu 	adap->dev.of_node = pdev->dev.of_node;
675dd1aa252SKamal Dasu 	rc = i2c_add_adapter(adap);
676ea734404SWolfram Sang 	if (rc)
677*f9dce8d6SYangtao Li 		return rc;
678dd1aa252SKamal Dasu 
679dd1aa252SKamal Dasu 	dev_info(dev->device, "%s@%dhz registered in %s mode\n",
680dd1aa252SKamal Dasu 		 int_name ? int_name : " ", dev->clk_freq_hz,
681dd1aa252SKamal Dasu 		 (dev->irq >= 0) ? "interrupt" : "polling");
682dd1aa252SKamal Dasu 
683dd1aa252SKamal Dasu 	return 0;
684dd1aa252SKamal Dasu }
685dd1aa252SKamal Dasu 
brcmstb_i2c_remove(struct platform_device * pdev)686e190a0c3SUwe Kleine-König static void brcmstb_i2c_remove(struct platform_device *pdev)
687dd1aa252SKamal Dasu {
688dd1aa252SKamal Dasu 	struct brcmstb_i2c_dev *dev = platform_get_drvdata(pdev);
689dd1aa252SKamal Dasu 
690dd1aa252SKamal Dasu 	i2c_del_adapter(&dev->adapter);
691dd1aa252SKamal Dasu }
692dd1aa252SKamal Dasu 
brcmstb_i2c_suspend(struct device * dev)693dd1aa252SKamal Dasu static int brcmstb_i2c_suspend(struct device *dev)
694dd1aa252SKamal Dasu {
695dd1aa252SKamal Dasu 	struct brcmstb_i2c_dev *i2c_dev = dev_get_drvdata(dev);
696dd1aa252SKamal Dasu 
697f2e0d28cSWolfram Sang 	i2c_mark_adapter_suspended(&i2c_dev->adapter);
698dd1aa252SKamal Dasu 	return 0;
699dd1aa252SKamal Dasu }
700dd1aa252SKamal Dasu 
brcmstb_i2c_resume(struct device * dev)701dd1aa252SKamal Dasu static int brcmstb_i2c_resume(struct device *dev)
702dd1aa252SKamal Dasu {
703dd1aa252SKamal Dasu 	struct brcmstb_i2c_dev *i2c_dev = dev_get_drvdata(dev);
704dd1aa252SKamal Dasu 
705dd1aa252SKamal Dasu 	brcmstb_i2c_set_bsc_reg_defaults(i2c_dev);
706f2e0d28cSWolfram Sang 	i2c_mark_adapter_resumed(&i2c_dev->adapter);
707dd1aa252SKamal Dasu 
708dd1aa252SKamal Dasu 	return 0;
709dd1aa252SKamal Dasu }
710dd1aa252SKamal Dasu 
711bb48aa5fSPaul Cercueil static DEFINE_SIMPLE_DEV_PM_OPS(brcmstb_i2c_pm, brcmstb_i2c_suspend,
712dd1aa252SKamal Dasu 				brcmstb_i2c_resume);
713dd1aa252SKamal Dasu 
714dd1aa252SKamal Dasu static const struct of_device_id brcmstb_i2c_of_match[] = {
715dd1aa252SKamal Dasu 	{.compatible = "brcm,brcmstb-i2c"},
716e2e5a2c6SKamal Dasu 	{.compatible = "brcm,brcmper-i2c"},
717d31f59eaSMaxime Ripard 	{.compatible = "brcm,bcm2711-hdmi-i2c"},
718dd1aa252SKamal Dasu 	{},
719dd1aa252SKamal Dasu };
720dd1aa252SKamal Dasu MODULE_DEVICE_TABLE(of, brcmstb_i2c_of_match);
721dd1aa252SKamal Dasu 
722dd1aa252SKamal Dasu static struct platform_driver brcmstb_i2c_driver = {
723dd1aa252SKamal Dasu 	.driver = {
724dd1aa252SKamal Dasu 		   .name = "brcmstb-i2c",
725dd1aa252SKamal Dasu 		   .of_match_table = brcmstb_i2c_of_match,
726bb48aa5fSPaul Cercueil 		   .pm = pm_sleep_ptr(&brcmstb_i2c_pm),
727dd1aa252SKamal Dasu 		   },
728dd1aa252SKamal Dasu 	.probe = brcmstb_i2c_probe,
729e190a0c3SUwe Kleine-König 	.remove_new = brcmstb_i2c_remove,
730dd1aa252SKamal Dasu };
731dd1aa252SKamal Dasu module_platform_driver(brcmstb_i2c_driver);
732dd1aa252SKamal Dasu 
733dd1aa252SKamal Dasu MODULE_AUTHOR("Kamal Dasu <kdasu@broadcom.com>");
734dd1aa252SKamal Dasu MODULE_DESCRIPTION("Broadcom Settop I2C Driver");
735dd1aa252SKamal Dasu MODULE_LICENSE("GPL v2");
736