]>
Commit | Line | Data |
---|---|---|
74ba9207 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
41e840b1 MA |
2 | /* |
3 | Mantis PCI bridge driver | |
4 | ||
8825a097 | 5 | Copyright (C) Manu Abraham (abraham.manu@gmail.com) |
41e840b1 | 6 | |
41e840b1 MA |
7 | */ |
8 | ||
41e840b1 MA |
9 | #include <asm/io.h> |
10 | #include <linux/ioport.h> | |
b3b96144 MA |
11 | #include <linux/pci.h> |
12 | #include <linux/i2c.h> | |
13 | ||
fada1935 MCC |
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> | |
b3b96144 | 19 | |
41e840b1 | 20 | #include "mantis_common.h" |
b3b96144 MA |
21 | #include "mantis_reg.h" |
22 | #include "mantis_i2c.h" | |
41e840b1 | 23 | |
bc832fa2 MA |
24 | #define TRIALS 10000 |
25 | ||
41e840b1 MA |
26 | static int mantis_i2c_read(struct mantis_pci *mantis, const struct i2c_msg *msg) |
27 | { | |
3e978a82 | 28 | u32 rxd, i, stat, trials; |
41e840b1 | 29 | |
b3b96144 | 30 | dprintk(MANTIS_INFO, 0, " %s: Address=[0x%02x] <R>[ ", |
715d341c MA |
31 | __func__, msg->addr); |
32 | ||
41e840b1 MA |
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 | ||
df0cca17 | 42 | mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT); |
41e840b1 | 43 | mmwrite(rxd, MANTIS_I2CDATA_CTL); |
3e978a82 MA |
44 | |
45 | /* wait for xfer completion */ | |
bc832fa2 | 46 | for (trials = 0; trials < TRIALS; trials++) { |
3e978a82 MA |
47 | stat = mmread(MANTIS_INT_STAT); |
48 | if (stat & MANTIS_INT_I2CDONE) | |
49 | break; | |
41e840b1 | 50 | } |
3e978a82 | 51 | |
bc832fa2 MA |
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; | |
bc832fa2 MA |
59 | } |
60 | ||
61 | dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials); | |
62 | ||
41e840b1 MA |
63 | rxd = mmread(MANTIS_I2CDATA_CTL); |
64 | msg->buf[i] = (u8)((rxd >> 8) & 0xFF); | |
b3b96144 | 65 | dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]); |
41e840b1 | 66 | } |
b3b96144 | 67 | dprintk(MANTIS_INFO, 0, "]\n"); |
41e840b1 MA |
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; | |
3e978a82 | 75 | u32 txd = 0, stat, trials; |
41e840b1 | 76 | |
b3b96144 | 77 | dprintk(MANTIS_INFO, 0, " %s: Address=[0x%02x] <W>[ ", |
715d341c MA |
78 | __func__, msg->addr); |
79 | ||
41e840b1 | 80 | for (i = 0; i < msg->len; i++) { |
b3b96144 | 81 | dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]); |
41e840b1 MA |
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 | ||
df0cca17 | 90 | mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT); |
41e840b1 | 91 | mmwrite(txd, MANTIS_I2CDATA_CTL); |
3e978a82 MA |
92 | |
93 | /* wait for xfer completion */ | |
bc832fa2 | 94 | for (trials = 0; trials < TRIALS; trials++) { |
3e978a82 MA |
95 | stat = mmread(MANTIS_INT_STAT); |
96 | if (stat & MANTIS_INT_I2CDONE) | |
97 | break; | |
41e840b1 | 98 | } |
bc832fa2 MA |
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; | |
bc832fa2 MA |
107 | } |
108 | ||
109 | dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials); | |
41e840b1 | 110 | } |
b3b96144 | 111 | dprintk(MANTIS_INFO, 0, "]\n"); |
41e840b1 MA |
112 | |
113 | return 0; | |
114 | } | |
115 | ||
116 | static int mantis_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) | |
117 | { | |
3e978a82 MA |
118 | int ret = 0, i = 0, trials; |
119 | u32 stat, data, txd; | |
41e840b1 | 120 | struct mantis_pci *mantis; |
3e978a82 | 121 | struct mantis_hwconfig *config; |
41e840b1 MA |
122 | |
123 | mantis = i2c_get_adapdata(adapter); | |
3e978a82 MA |
124 | BUG_ON(!mantis); |
125 | config = mantis->hwconfig; | |
126 | BUG_ON(!config); | |
127 | ||
128 | dprintk(MANTIS_DEBUG, 1, "Messages:%d", num); | |
e2f67e4f | 129 | mutex_lock(&mantis->i2c_lock); |
3e978a82 MA |
130 | |
131 | while (i < num) { | |
132 | /* Byte MODE */ | |
bc832fa2 MA |
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)) { | |
3e978a82 MA |
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 */ | |
bc832fa2 | 148 | for (trials = 0; trials < TRIALS; trials++) { |
3e978a82 MA |
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 | ||
41e840b1 | 187 | } |
3e978a82 | 188 | |
e2f67e4f | 189 | mutex_unlock(&mantis->i2c_lock); |
41e840b1 MA |
190 | |
191 | return num; | |
99d96e4e MA |
192 | |
193 | bail_out: | |
194 | mutex_unlock(&mantis->i2c_lock); | |
195 | return ret; | |
41e840b1 MA |
196 | } |
197 | ||
198 | static u32 mantis_i2c_func(struct i2c_adapter *adapter) | |
199 | { | |
200 | return I2C_FUNC_SMBUS_EMUL; | |
201 | } | |
202 | ||
e46ab9dc | 203 | static const struct i2c_algorithm mantis_algo = { |
41e840b1 MA |
204 | .master_xfer = mantis_i2c_xfer, |
205 | .functionality = mantis_i2c_func, | |
206 | }; | |
207 | ||
4c62e976 | 208 | int mantis_i2c_init(struct mantis_pci *mantis) |
41e840b1 | 209 | { |
6fe2d69c | 210 | u32 intstat; |
8154bad4 MA |
211 | struct i2c_adapter *i2c_adapter = &mantis->adapter; |
212 | struct pci_dev *pdev = mantis->pdev; | |
41e840b1 | 213 | |
b3b96144 | 214 | init_waitqueue_head(&mantis->i2c_wq); |
e2f67e4f | 215 | mutex_init(&mantis->i2c_lock); |
85709cbf | 216 | strscpy(i2c_adapter->name, "Mantis I2C", sizeof(i2c_adapter->name)); |
8154bad4 MA |
217 | i2c_set_adapdata(i2c_adapter, mantis); |
218 | ||
b3b96144 | 219 | i2c_adapter->owner = THIS_MODULE; |
b3b96144 MA |
220 | i2c_adapter->algo = &mantis_algo; |
221 | i2c_adapter->algo_data = NULL; | |
b3b96144 MA |
222 | i2c_adapter->timeout = 500; |
223 | i2c_adapter->retries = 3; | |
224 | i2c_adapter->dev.parent = &pdev->dev; | |
225 | ||
8154bad4 | 226 | mantis->i2c_rc = i2c_add_adapter(i2c_adapter); |
41e840b1 MA |
227 | if (mantis->i2c_rc < 0) |
228 | return mantis->i2c_rc; | |
229 | ||
b3b96144 | 230 | dprintk(MANTIS_DEBUG, 1, "Initializing I2C .."); |
41e840b1 | 231 | |
41e840b1 | 232 | intstat = mmread(MANTIS_INT_STAT); |
6fe2d69c | 233 | mmread(MANTIS_INT_MASK); |
41e840b1 | 234 | mmwrite(intstat, MANTIS_INT_STAT); |
3e978a82 | 235 | dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt"); |
a96762da | 236 | mantis_mask_ints(mantis, MANTIS_INT_I2CDONE); |
41e840b1 MA |
237 | |
238 | return 0; | |
239 | } | |
b3b96144 | 240 | EXPORT_SYMBOL_GPL(mantis_i2c_init); |
41e840b1 | 241 | |
4cf0b3f1 | 242 | int mantis_i2c_exit(struct mantis_pci *mantis) |
41e840b1 | 243 | { |
3e978a82 | 244 | dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt"); |
a96762da | 245 | mantis_mask_ints(mantis, MANTIS_INT_I2CDONE); |
3e978a82 | 246 | |
b3b96144 | 247 | dprintk(MANTIS_DEBUG, 1, "Removing I2C adapter"); |
bf51a8c5 LPC |
248 | i2c_del_adapter(&mantis->adapter); |
249 | ||
250 | return 0; | |
41e840b1 | 251 | } |
b3b96144 | 252 | EXPORT_SYMBOL_GPL(mantis_i2c_exit); |