1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * i2c-ali1563.c - i2c driver for the ALi 1563 Southbridge |
4 | * |
5 | * Copyright (C) 2004 Patrick Mochel |
6 | * 2005 Rudolf Marek <r.marek@assembler.cz> |
7 | * |
8 | * The 1563 southbridge is deceptively similar to the 1533, with a |
9 | * few notable exceptions. One of those happens to be the fact they |
10 | * upgraded the i2c core to be 2.0 compliant, and happens to be almost |
11 | * identical to the i2c controller found in the Intel 801 south |
12 | * bridges. |
13 | * |
14 | * This driver is based on a mix of the 15x3, 1535, and i801 drivers, |
15 | * with a little help from the ALi 1563 spec. |
16 | */ |
17 | |
18 | #include <linux/module.h> |
19 | #include <linux/delay.h> |
20 | #include <linux/i2c.h> |
21 | #include <linux/pci.h> |
22 | #include <linux/acpi.h> |
23 | |
24 | #define ALI1563_MAX_TIMEOUT 500 |
25 | #define ALI1563_SMBBA 0x80 |
26 | #define ALI1563_SMB_IOEN 1 |
27 | #define ALI1563_SMB_HOSTEN 2 |
28 | #define ALI1563_SMB_IOSIZE 16 |
29 | |
30 | #define SMB_HST_STS (ali1563_smba + 0) |
31 | #define SMB_HST_CNTL1 (ali1563_smba + 1) |
32 | #define SMB_HST_CNTL2 (ali1563_smba + 2) |
33 | #define SMB_HST_CMD (ali1563_smba + 3) |
34 | #define SMB_HST_ADD (ali1563_smba + 4) |
35 | #define SMB_HST_DAT0 (ali1563_smba + 5) |
36 | #define SMB_HST_DAT1 (ali1563_smba + 6) |
37 | #define SMB_BLK_DAT (ali1563_smba + 7) |
38 | |
39 | #define HST_STS_BUSY 0x01 |
40 | #define HST_STS_INTR 0x02 |
41 | #define HST_STS_DEVERR 0x04 |
42 | #define HST_STS_BUSERR 0x08 |
43 | #define HST_STS_FAIL 0x10 |
44 | #define HST_STS_DONE 0x80 |
45 | #define HST_STS_BAD 0x1c |
46 | |
47 | |
48 | #define HST_CNTL1_TIMEOUT 0x80 |
49 | #define HST_CNTL1_LAST 0x40 |
50 | |
51 | #define HST_CNTL2_KILL 0x04 |
52 | #define HST_CNTL2_START 0x40 |
53 | #define HST_CNTL2_QUICK 0x00 |
54 | #define HST_CNTL2_BYTE 0x01 |
55 | #define HST_CNTL2_BYTE_DATA 0x02 |
56 | #define HST_CNTL2_WORD_DATA 0x03 |
57 | #define HST_CNTL2_BLOCK 0x05 |
58 | |
59 | |
60 | #define HST_CNTL2_SIZEMASK 0x38 |
61 | |
62 | static struct pci_driver ali1563_pci_driver; |
63 | static unsigned short ali1563_smba; |
64 | |
65 | static int ali1563_transaction(struct i2c_adapter *a, int size) |
66 | { |
67 | u32 data; |
68 | int timeout; |
69 | int status = -EIO; |
70 | |
71 | dev_dbg(&a->dev, "Transaction (pre): STS=%02x, CNTL1=%02x, " |
72 | "CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n" , |
73 | inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2), |
74 | inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0), |
75 | inb_p(SMB_HST_DAT1)); |
76 | |
77 | data = inb_p(SMB_HST_STS); |
78 | if (data & HST_STS_BAD) { |
79 | dev_err(&a->dev, "ali1563: Trying to reset busy device\n" ); |
80 | outb_p(value: data | HST_STS_BAD, SMB_HST_STS); |
81 | data = inb_p(SMB_HST_STS); |
82 | if (data & HST_STS_BAD) |
83 | return -EBUSY; |
84 | } |
85 | outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_START, SMB_HST_CNTL2); |
86 | |
87 | timeout = ALI1563_MAX_TIMEOUT; |
88 | do { |
89 | msleep(msecs: 1); |
90 | } while (((data = inb_p(SMB_HST_STS)) & HST_STS_BUSY) && --timeout); |
91 | |
92 | dev_dbg(&a->dev, "Transaction (post): STS=%02x, CNTL1=%02x, " |
93 | "CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n" , |
94 | inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2), |
95 | inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0), |
96 | inb_p(SMB_HST_DAT1)); |
97 | |
98 | if (timeout && !(data & HST_STS_BAD)) |
99 | return 0; |
100 | |
101 | if (!timeout) { |
102 | dev_err(&a->dev, "Timeout - Trying to KILL transaction!\n" ); |
103 | /* Issue 'kill' to host controller */ |
104 | outb_p(HST_CNTL2_KILL, SMB_HST_CNTL2); |
105 | data = inb_p(SMB_HST_STS); |
106 | status = -ETIMEDOUT; |
107 | } |
108 | |
109 | /* device error - no response, ignore the autodetection case */ |
110 | if (data & HST_STS_DEVERR) { |
111 | if (size != HST_CNTL2_QUICK) |
112 | dev_err(&a->dev, "Device error!\n" ); |
113 | status = -ENXIO; |
114 | } |
115 | /* bus collision */ |
116 | if (data & HST_STS_BUSERR) { |
117 | dev_err(&a->dev, "Bus collision!\n" ); |
118 | /* Issue timeout, hoping it helps */ |
119 | outb_p(HST_CNTL1_TIMEOUT, SMB_HST_CNTL1); |
120 | } |
121 | |
122 | if (data & HST_STS_FAIL) { |
123 | dev_err(&a->dev, "Cleaning fail after KILL!\n" ); |
124 | outb_p(value: 0x0, SMB_HST_CNTL2); |
125 | } |
126 | |
127 | return status; |
128 | } |
129 | |
130 | static int ali1563_block_start(struct i2c_adapter *a) |
131 | { |
132 | u32 data; |
133 | int timeout; |
134 | int status = -EIO; |
135 | |
136 | dev_dbg(&a->dev, "Block (pre): STS=%02x, CNTL1=%02x, " |
137 | "CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n" , |
138 | inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2), |
139 | inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0), |
140 | inb_p(SMB_HST_DAT1)); |
141 | |
142 | data = inb_p(SMB_HST_STS); |
143 | if (data & HST_STS_BAD) { |
144 | dev_warn(&a->dev, "ali1563: Trying to reset busy device\n" ); |
145 | outb_p(value: data | HST_STS_BAD, SMB_HST_STS); |
146 | data = inb_p(SMB_HST_STS); |
147 | if (data & HST_STS_BAD) |
148 | return -EBUSY; |
149 | } |
150 | |
151 | /* Clear byte-ready bit */ |
152 | outb_p(value: data | HST_STS_DONE, SMB_HST_STS); |
153 | |
154 | /* Start transaction and wait for byte-ready bit to be set */ |
155 | outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_START, SMB_HST_CNTL2); |
156 | |
157 | timeout = ALI1563_MAX_TIMEOUT; |
158 | do { |
159 | msleep(msecs: 1); |
160 | } while (!((data = inb_p(SMB_HST_STS)) & HST_STS_DONE) && --timeout); |
161 | |
162 | dev_dbg(&a->dev, "Block (post): STS=%02x, CNTL1=%02x, " |
163 | "CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n" , |
164 | inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2), |
165 | inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0), |
166 | inb_p(SMB_HST_DAT1)); |
167 | |
168 | if (timeout && !(data & HST_STS_BAD)) |
169 | return 0; |
170 | |
171 | if (timeout == 0) |
172 | status = -ETIMEDOUT; |
173 | |
174 | if (data & HST_STS_DEVERR) |
175 | status = -ENXIO; |
176 | |
177 | dev_err(&a->dev, "SMBus Error: %s%s%s%s%s\n" , |
178 | timeout ? "" : "Timeout " , |
179 | data & HST_STS_FAIL ? "Transaction Failed " : "" , |
180 | data & HST_STS_BUSERR ? "No response or Bus Collision " : "" , |
181 | data & HST_STS_DEVERR ? "Device Error " : "" , |
182 | !(data & HST_STS_DONE) ? "Transaction Never Finished " : "" ); |
183 | return status; |
184 | } |
185 | |
186 | static int ali1563_block(struct i2c_adapter *a, |
187 | union i2c_smbus_data *data, u8 rw) |
188 | { |
189 | int i, len; |
190 | int error = 0; |
191 | |
192 | /* Do we need this? */ |
193 | outb_p(HST_CNTL1_LAST, SMB_HST_CNTL1); |
194 | |
195 | if (rw == I2C_SMBUS_WRITE) { |
196 | len = data->block[0]; |
197 | if (len < 1) |
198 | len = 1; |
199 | else if (len > 32) |
200 | len = 32; |
201 | outb_p(value: len, SMB_HST_DAT0); |
202 | outb_p(value: data->block[1], SMB_BLK_DAT); |
203 | } else |
204 | len = 32; |
205 | |
206 | outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_BLOCK, SMB_HST_CNTL2); |
207 | |
208 | for (i = 0; i < len; i++) { |
209 | if (rw == I2C_SMBUS_WRITE) { |
210 | outb_p(value: data->block[i + 1], SMB_BLK_DAT); |
211 | error = ali1563_block_start(a); |
212 | if (error) |
213 | break; |
214 | } else { |
215 | error = ali1563_block_start(a); |
216 | if (error) |
217 | break; |
218 | if (i == 0) { |
219 | len = inb_p(SMB_HST_DAT0); |
220 | if (len < 1) |
221 | len = 1; |
222 | else if (len > 32) |
223 | len = 32; |
224 | } |
225 | data->block[i+1] = inb_p(SMB_BLK_DAT); |
226 | } |
227 | } |
228 | /* Do we need this? */ |
229 | outb_p(HST_CNTL1_LAST, SMB_HST_CNTL1); |
230 | return error; |
231 | } |
232 | |
233 | static s32 ali1563_access(struct i2c_adapter *a, u16 addr, |
234 | unsigned short flags, char rw, u8 cmd, |
235 | int size, union i2c_smbus_data *data) |
236 | { |
237 | int error = 0; |
238 | int timeout; |
239 | u32 reg; |
240 | |
241 | for (timeout = ALI1563_MAX_TIMEOUT; timeout; timeout--) { |
242 | reg = inb_p(SMB_HST_STS); |
243 | if (!(reg & HST_STS_BUSY)) |
244 | break; |
245 | } |
246 | if (!timeout) |
247 | dev_warn(&a->dev, "SMBus not idle. HST_STS = %02x\n" , reg); |
248 | outb_p(value: 0xff, SMB_HST_STS); |
249 | |
250 | /* Map the size to what the chip understands */ |
251 | switch (size) { |
252 | case I2C_SMBUS_QUICK: |
253 | size = HST_CNTL2_QUICK; |
254 | break; |
255 | case I2C_SMBUS_BYTE: |
256 | size = HST_CNTL2_BYTE; |
257 | break; |
258 | case I2C_SMBUS_BYTE_DATA: |
259 | size = HST_CNTL2_BYTE_DATA; |
260 | break; |
261 | case I2C_SMBUS_WORD_DATA: |
262 | size = HST_CNTL2_WORD_DATA; |
263 | break; |
264 | case I2C_SMBUS_BLOCK_DATA: |
265 | size = HST_CNTL2_BLOCK; |
266 | break; |
267 | default: |
268 | dev_warn(&a->dev, "Unsupported transaction %d\n" , size); |
269 | error = -EOPNOTSUPP; |
270 | goto Done; |
271 | } |
272 | |
273 | outb_p(value: ((addr & 0x7f) << 1) | (rw & 0x01), SMB_HST_ADD); |
274 | outb_p(value: (inb_p(SMB_HST_CNTL2) & ~HST_CNTL2_SIZEMASK) | |
275 | (size << 3), SMB_HST_CNTL2); |
276 | |
277 | /* Write the command register */ |
278 | |
279 | switch (size) { |
280 | case HST_CNTL2_BYTE: |
281 | if (rw == I2C_SMBUS_WRITE) |
282 | /* Beware it uses DAT0 register and not CMD! */ |
283 | outb_p(value: cmd, SMB_HST_DAT0); |
284 | break; |
285 | case HST_CNTL2_BYTE_DATA: |
286 | outb_p(value: cmd, SMB_HST_CMD); |
287 | if (rw == I2C_SMBUS_WRITE) |
288 | outb_p(value: data->byte, SMB_HST_DAT0); |
289 | break; |
290 | case HST_CNTL2_WORD_DATA: |
291 | outb_p(value: cmd, SMB_HST_CMD); |
292 | if (rw == I2C_SMBUS_WRITE) { |
293 | outb_p(value: data->word & 0xff, SMB_HST_DAT0); |
294 | outb_p(value: (data->word & 0xff00) >> 8, SMB_HST_DAT1); |
295 | } |
296 | break; |
297 | case HST_CNTL2_BLOCK: |
298 | outb_p(value: cmd, SMB_HST_CMD); |
299 | error = ali1563_block(a, data, rw); |
300 | goto Done; |
301 | } |
302 | |
303 | error = ali1563_transaction(a, size); |
304 | if (error) |
305 | goto Done; |
306 | |
307 | if ((rw == I2C_SMBUS_WRITE) || (size == HST_CNTL2_QUICK)) |
308 | goto Done; |
309 | |
310 | switch (size) { |
311 | case HST_CNTL2_BYTE: /* Result put in SMBHSTDAT0 */ |
312 | data->byte = inb_p(SMB_HST_DAT0); |
313 | break; |
314 | case HST_CNTL2_BYTE_DATA: |
315 | data->byte = inb_p(SMB_HST_DAT0); |
316 | break; |
317 | case HST_CNTL2_WORD_DATA: |
318 | data->word = inb_p(SMB_HST_DAT0) + (inb_p(SMB_HST_DAT1) << 8); |
319 | break; |
320 | } |
321 | Done: |
322 | return error; |
323 | } |
324 | |
325 | static u32 ali1563_func(struct i2c_adapter *a) |
326 | { |
327 | return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | |
328 | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | |
329 | I2C_FUNC_SMBUS_BLOCK_DATA; |
330 | } |
331 | |
332 | |
333 | static int ali1563_setup(struct pci_dev *dev) |
334 | { |
335 | u16 ctrl; |
336 | |
337 | pci_read_config_word(dev, ALI1563_SMBBA, val: &ctrl); |
338 | |
339 | /* SMB I/O Base in high 12 bits and must be aligned with the |
340 | * size of the I/O space. */ |
341 | ali1563_smba = ctrl & ~(ALI1563_SMB_IOSIZE - 1); |
342 | if (!ali1563_smba) { |
343 | dev_warn(&dev->dev, "ali1563_smba Uninitialized\n" ); |
344 | goto Err; |
345 | } |
346 | |
347 | /* Check if device is enabled */ |
348 | if (!(ctrl & ALI1563_SMB_HOSTEN)) { |
349 | dev_warn(&dev->dev, "Host Controller not enabled\n" ); |
350 | goto Err; |
351 | } |
352 | if (!(ctrl & ALI1563_SMB_IOEN)) { |
353 | dev_warn(&dev->dev, "I/O space not enabled, trying manually\n" ); |
354 | pci_write_config_word(dev, ALI1563_SMBBA, |
355 | val: ctrl | ALI1563_SMB_IOEN); |
356 | pci_read_config_word(dev, ALI1563_SMBBA, val: &ctrl); |
357 | if (!(ctrl & ALI1563_SMB_IOEN)) { |
358 | dev_err(&dev->dev, |
359 | "I/O space still not enabled, giving up\n" ); |
360 | goto Err; |
361 | } |
362 | } |
363 | |
364 | if (acpi_check_region(start: ali1563_smba, ALI1563_SMB_IOSIZE, |
365 | name: ali1563_pci_driver.name)) |
366 | goto Err; |
367 | |
368 | if (!request_region(ali1563_smba, ALI1563_SMB_IOSIZE, |
369 | ali1563_pci_driver.name)) { |
370 | dev_err(&dev->dev, "Could not allocate I/O space at 0x%04x\n" , |
371 | ali1563_smba); |
372 | goto Err; |
373 | } |
374 | dev_info(&dev->dev, "Found ALi1563 SMBus at 0x%04x\n" , ali1563_smba); |
375 | |
376 | return 0; |
377 | Err: |
378 | return -ENODEV; |
379 | } |
380 | |
381 | static void ali1563_shutdown(struct pci_dev *dev) |
382 | { |
383 | release_region(ali1563_smba, ALI1563_SMB_IOSIZE); |
384 | } |
385 | |
386 | static const struct i2c_algorithm ali1563_algorithm = { |
387 | .smbus_xfer = ali1563_access, |
388 | .functionality = ali1563_func, |
389 | }; |
390 | |
391 | static struct i2c_adapter ali1563_adapter = { |
392 | .owner = THIS_MODULE, |
393 | .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, |
394 | .algo = &ali1563_algorithm, |
395 | }; |
396 | |
397 | static int ali1563_probe(struct pci_dev *dev, |
398 | const struct pci_device_id *id_table) |
399 | { |
400 | int error; |
401 | |
402 | error = ali1563_setup(dev); |
403 | if (error) |
404 | goto exit; |
405 | ali1563_adapter.dev.parent = &dev->dev; |
406 | snprintf(buf: ali1563_adapter.name, size: sizeof(ali1563_adapter.name), |
407 | fmt: "SMBus ALi 1563 Adapter @ %04x" , ali1563_smba); |
408 | error = i2c_add_adapter(adap: &ali1563_adapter); |
409 | if (error) |
410 | goto exit_shutdown; |
411 | return 0; |
412 | |
413 | exit_shutdown: |
414 | ali1563_shutdown(dev); |
415 | exit: |
416 | dev_warn(&dev->dev, "ALi1563 SMBus probe failed (%d)\n" , error); |
417 | return error; |
418 | } |
419 | |
420 | static void ali1563_remove(struct pci_dev *dev) |
421 | { |
422 | i2c_del_adapter(adap: &ali1563_adapter); |
423 | ali1563_shutdown(dev); |
424 | } |
425 | |
426 | static const struct pci_device_id ali1563_id_table[] = { |
427 | { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1563) }, |
428 | {}, |
429 | }; |
430 | |
431 | MODULE_DEVICE_TABLE(pci, ali1563_id_table); |
432 | |
433 | static struct pci_driver ali1563_pci_driver = { |
434 | .name = "ali1563_smbus" , |
435 | .id_table = ali1563_id_table, |
436 | .probe = ali1563_probe, |
437 | .remove = ali1563_remove, |
438 | }; |
439 | |
440 | module_pci_driver(ali1563_pci_driver); |
441 | |
442 | MODULE_LICENSE("GPL" ); |
443 | |