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 | |
26 | static 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 | |
72 | static 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 | |
116 | static 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(adap: 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, msg: &msgs[i]); |
179 | else |
180 | ret = mantis_i2c_write(mantis, msg: &msgs[i]); |
181 | |
182 | i++; |
183 | if (ret < 0) |
184 | goto bail_out; |
185 | } |
186 | |
187 | } |
188 | |
189 | mutex_unlock(lock: &mantis->i2c_lock); |
190 | |
191 | return num; |
192 | |
193 | bail_out: |
194 | mutex_unlock(lock: &mantis->i2c_lock); |
195 | return ret; |
196 | } |
197 | |
198 | static u32 mantis_i2c_func(struct i2c_adapter *adapter) |
199 | { |
200 | return I2C_FUNC_SMBUS_EMUL; |
201 | } |
202 | |
203 | static const struct i2c_algorithm mantis_algo = { |
204 | .master_xfer = mantis_i2c_xfer, |
205 | .functionality = mantis_i2c_func, |
206 | }; |
207 | |
208 | int 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(adap: i2c_adapter, data: 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(adap: 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 | } |
240 | EXPORT_SYMBOL_GPL(mantis_i2c_init); |
241 | |
242 | int 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(adap: &mantis->adapter); |
249 | |
250 | return 0; |
251 | } |
252 | EXPORT_SYMBOL_GPL(mantis_i2c_exit); |
253 | |