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