1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3	Mantis PCI bridge driver
4
5	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
6
7*/
8
9#include <asm/io.h>
10#include <linux/ioport.h>
11#include <linux/pci.h>
12#include <linux/i2c.h>
13
14#include <media/dmxdev.h>
15#include <media/dvbdev.h>
16#include <media/dvb_demux.h>
17#include <media/dvb_frontend.h>
18#include <media/dvb_net.h>
19
20#include "mantis_common.h"
21#include "mantis_reg.h"
22#include "mantis_i2c.h"
23
24#define TRIALS			10000
25
26static int mantis_i2c_read(struct mantis_pci *mantis, const struct i2c_msg *msg)
27{
28	u32 rxd, i, stat, trials;
29
30	dprintk(MANTIS_INFO, 0, "        %s:  Address=[0x%02x] <R>[ ",
31		__func__, msg->addr);
32
33	for (i = 0; i < msg->len; i++) {
34		rxd = (msg->addr << 25) | (1 << 24)
35					| MANTIS_I2C_RATE_3
36					| MANTIS_I2C_STOP
37					| MANTIS_I2C_PGMODE;
38
39		if (i == (msg->len - 1))
40			rxd &= ~MANTIS_I2C_STOP;
41
42		mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT);
43		mmwrite(rxd, MANTIS_I2CDATA_CTL);
44
45		/* wait for xfer completion */
46		for (trials = 0; trials < TRIALS; trials++) {
47			stat = mmread(MANTIS_INT_STAT);
48			if (stat & MANTIS_INT_I2CDONE)
49				break;
50		}
51
52		dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials);
53
54		/* wait for xfer completion */
55		for (trials = 0; trials < TRIALS; trials++) {
56			stat = mmread(MANTIS_INT_STAT);
57			if (stat & MANTIS_INT_I2CRACK)
58				break;
59		}
60
61		dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials);
62
63		rxd = mmread(MANTIS_I2CDATA_CTL);
64		msg->buf[i] = (u8)((rxd >> 8) & 0xFF);
65		dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]);
66	}
67	dprintk(MANTIS_INFO, 0, "]\n");
68
69	return 0;
70}
71
72static int mantis_i2c_write(struct mantis_pci *mantis, const struct i2c_msg *msg)
73{
74	int i;
75	u32 txd = 0, stat, trials;
76
77	dprintk(MANTIS_INFO, 0, "        %s: Address=[0x%02x] <W>[ ",
78		__func__, msg->addr);
79
80	for (i = 0; i < msg->len; i++) {
81		dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]);
82		txd = (msg->addr << 25) | (msg->buf[i] << 8)
83					| MANTIS_I2C_RATE_3
84					| MANTIS_I2C_STOP
85					| MANTIS_I2C_PGMODE;
86
87		if (i == (msg->len - 1))
88			txd &= ~MANTIS_I2C_STOP;
89
90		mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT);
91		mmwrite(txd, MANTIS_I2CDATA_CTL);
92
93		/* wait for xfer completion */
94		for (trials = 0; trials < TRIALS; trials++) {
95			stat = mmread(MANTIS_INT_STAT);
96			if (stat & MANTIS_INT_I2CDONE)
97				break;
98		}
99
100		dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials);
101
102		/* wait for xfer completion */
103		for (trials = 0; trials < TRIALS; trials++) {
104			stat = mmread(MANTIS_INT_STAT);
105			if (stat & MANTIS_INT_I2CRACK)
106				break;
107		}
108
109		dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials);
110	}
111	dprintk(MANTIS_INFO, 0, "]\n");
112
113	return 0;
114}
115
116static int mantis_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
117{
118	int ret = 0, i = 0, trials;
119	u32 stat, data, txd;
120	struct mantis_pci *mantis;
121	struct mantis_hwconfig *config;
122
123	mantis = i2c_get_adapdata(adapter);
124	BUG_ON(!mantis);
125	config = mantis->hwconfig;
126	BUG_ON(!config);
127
128	dprintk(MANTIS_DEBUG, 1, "Messages:%d", num);
129	mutex_lock(&mantis->i2c_lock);
130
131	while (i < num) {
132		/* Byte MODE */
133		if ((config->i2c_mode & MANTIS_BYTE_MODE) &&
134		    ((i + 1) < num)			&&
135		    (msgs[i].len < 2)			&&
136		    (msgs[i + 1].len < 2)		&&
137		    (msgs[i + 1].flags & I2C_M_RD)) {
138
139			dprintk(MANTIS_DEBUG, 0, "        Byte MODE:\n");
140
141			/* Read operation */
142			txd = msgs[i].addr << 25 | (0x1 << 24)
143						 | (msgs[i].buf[0] << 16)
144						 | MANTIS_I2C_RATE_3;
145
146			mmwrite(txd, MANTIS_I2CDATA_CTL);
147			/* wait for xfer completion */
148			for (trials = 0; trials < TRIALS; trials++) {
149				stat = mmread(MANTIS_INT_STAT);
150				if (stat & MANTIS_INT_I2CDONE)
151					break;
152			}
153
154			/* check for xfer completion */
155			if (stat & MANTIS_INT_I2CDONE) {
156				/* check xfer was acknowledged */
157				if (stat & MANTIS_INT_I2CRACK) {
158					data = mmread(MANTIS_I2CDATA_CTL);
159					msgs[i + 1].buf[0] = (data >> 8) & 0xff;
160					dprintk(MANTIS_DEBUG, 0, "        Byte <%d> RXD=0x%02x  [%02x]\n", 0x0, data, msgs[i + 1].buf[0]);
161				} else {
162					/* I/O error */
163					dprintk(MANTIS_ERROR, 1, "        I/O error, LINE:%d", __LINE__);
164					ret = -EIO;
165					break;
166				}
167			} else {
168				/* I/O error */
169				dprintk(MANTIS_ERROR, 1, "        I/O error, LINE:%d", __LINE__);
170				ret = -EIO;
171				break;
172			}
173			i += 2; /* Write/Read operation in one go */
174		}
175
176		if (i < num) {
177			if (msgs[i].flags & I2C_M_RD)
178				ret = mantis_i2c_read(mantis, &msgs[i]);
179			else
180				ret = mantis_i2c_write(mantis, &msgs[i]);
181
182			i++;
183			if (ret < 0)
184				goto bail_out;
185		}
186
187	}
188
189	mutex_unlock(&mantis->i2c_lock);
190
191	return num;
192
193bail_out:
194	mutex_unlock(&mantis->i2c_lock);
195	return ret;
196}
197
198static u32 mantis_i2c_func(struct i2c_adapter *adapter)
199{
200	return I2C_FUNC_SMBUS_EMUL;
201}
202
203static const struct i2c_algorithm mantis_algo = {
204	.master_xfer		= mantis_i2c_xfer,
205	.functionality		= mantis_i2c_func,
206};
207
208int mantis_i2c_init(struct mantis_pci *mantis)
209{
210	u32 intstat;
211	struct i2c_adapter *i2c_adapter = &mantis->adapter;
212	struct pci_dev *pdev		= mantis->pdev;
213
214	init_waitqueue_head(&mantis->i2c_wq);
215	mutex_init(&mantis->i2c_lock);
216	strscpy(i2c_adapter->name, "Mantis I2C", sizeof(i2c_adapter->name));
217	i2c_set_adapdata(i2c_adapter, mantis);
218
219	i2c_adapter->owner	= THIS_MODULE;
220	i2c_adapter->algo	= &mantis_algo;
221	i2c_adapter->algo_data	= NULL;
222	i2c_adapter->timeout	= 500;
223	i2c_adapter->retries	= 3;
224	i2c_adapter->dev.parent	= &pdev->dev;
225
226	mantis->i2c_rc		= i2c_add_adapter(i2c_adapter);
227	if (mantis->i2c_rc < 0)
228		return mantis->i2c_rc;
229
230	dprintk(MANTIS_DEBUG, 1, "Initializing I2C ..");
231
232	intstat = mmread(MANTIS_INT_STAT);
233	mmread(MANTIS_INT_MASK);
234	mmwrite(intstat, MANTIS_INT_STAT);
235	dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt");
236	mantis_mask_ints(mantis, MANTIS_INT_I2CDONE);
237
238	return 0;
239}
240EXPORT_SYMBOL_GPL(mantis_i2c_init);
241
242int mantis_i2c_exit(struct mantis_pci *mantis)
243{
244	dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt");
245	mantis_mask_ints(mantis, MANTIS_INT_I2CDONE);
246
247	dprintk(MANTIS_DEBUG, 1, "Removing I2C adapter");
248	i2c_del_adapter(&mantis->adapter);
249
250	return 0;
251}
252EXPORT_SYMBOL_GPL(mantis_i2c_exit);
253