491 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * SMBus 2.0 driver for AMD-8111 IO-Hub.4 *5 * Copyright (c) 2002 Vojtech Pavlik6 */7 8#include <linux/module.h>9#include <linux/pci.h>10#include <linux/kernel.h>11#include <linux/stddef.h>12#include <linux/ioport.h>13#include <linux/i2c.h>14#include <linux/delay.h>15#include <linux/acpi.h>16#include <linux/slab.h>17#include <linux/io.h>18 19MODULE_LICENSE("GPL");20MODULE_AUTHOR ("Vojtech Pavlik <vojtech@suse.cz>");21MODULE_DESCRIPTION("AMD8111 SMBus 2.0 driver");22 23struct amd_smbus {24 struct pci_dev *dev;25 struct i2c_adapter adapter;26 int base;27 int size;28};29 30static struct pci_driver amd8111_driver;31 32/*33 * AMD PCI control registers definitions.34 */35 36#define AMD_PCI_MISC 0x4837 38#define AMD_PCI_MISC_SCI 0x04 /* deliver SCI */39#define AMD_PCI_MISC_INT 0x02 /* deliver PCI IRQ */40#define AMD_PCI_MISC_SPEEDUP 0x01 /* 16x clock speedup */41 42/*43 * ACPI 2.0 chapter 13 PCI interface definitions.44 */45 46#define AMD_EC_DATA 0x00 /* data register */47#define AMD_EC_SC 0x04 /* status of controller */48#define AMD_EC_CMD 0x04 /* command register */49#define AMD_EC_ICR 0x08 /* interrupt control register */50 51#define AMD_EC_SC_SMI 0x04 /* smi event pending */52#define AMD_EC_SC_SCI 0x02 /* sci event pending */53#define AMD_EC_SC_BURST 0x01 /* burst mode enabled */54#define AMD_EC_SC_CMD 0x08 /* byte in data reg is command */55#define AMD_EC_SC_IBF 0x02 /* data ready for embedded controller */56#define AMD_EC_SC_OBF 0x01 /* data ready for host */57 58#define AMD_EC_CMD_RD 0x80 /* read EC */59#define AMD_EC_CMD_WR 0x81 /* write EC */60#define AMD_EC_CMD_BE 0x82 /* enable burst mode */61#define AMD_EC_CMD_BD 0x83 /* disable burst mode */62#define AMD_EC_CMD_QR 0x84 /* query EC */63 64/*65 * ACPI 2.0 chapter 13 access of registers of the EC66 */67 68static int amd_ec_wait_write(struct amd_smbus *smbus)69{70 int timeout = 500;71 72 while ((inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_IBF) && --timeout)73 udelay(1);74 75 if (!timeout) {76 dev_warn(&smbus->dev->dev,77 "Timeout while waiting for IBF to clear\n");78 return -ETIMEDOUT;79 }80 81 return 0;82}83 84static int amd_ec_wait_read(struct amd_smbus *smbus)85{86 int timeout = 500;87 88 while ((~inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_OBF) && --timeout)89 udelay(1);90 91 if (!timeout) {92 dev_warn(&smbus->dev->dev,93 "Timeout while waiting for OBF to set\n");94 return -ETIMEDOUT;95 }96 97 return 0;98}99 100static int amd_ec_read(struct amd_smbus *smbus, unsigned char address,101 unsigned char *data)102{103 int status;104 105 status = amd_ec_wait_write(smbus);106 if (status)107 return status;108 outb(AMD_EC_CMD_RD, smbus->base + AMD_EC_CMD);109 110 status = amd_ec_wait_write(smbus);111 if (status)112 return status;113 outb(address, smbus->base + AMD_EC_DATA);114 115 status = amd_ec_wait_read(smbus);116 if (status)117 return status;118 *data = inb(smbus->base + AMD_EC_DATA);119 120 return 0;121}122 123static int amd_ec_write(struct amd_smbus *smbus, unsigned char address,124 unsigned char data)125{126 int status;127 128 status = amd_ec_wait_write(smbus);129 if (status)130 return status;131 outb(AMD_EC_CMD_WR, smbus->base + AMD_EC_CMD);132 133 status = amd_ec_wait_write(smbus);134 if (status)135 return status;136 outb(address, smbus->base + AMD_EC_DATA);137 138 status = amd_ec_wait_write(smbus);139 if (status)140 return status;141 outb(data, smbus->base + AMD_EC_DATA);142 143 return 0;144}145 146/*147 * ACPI 2.0 chapter 13 SMBus 2.0 EC register model148 */149 150#define AMD_SMB_PRTCL 0x00 /* protocol, PEC */151#define AMD_SMB_STS 0x01 /* status */152#define AMD_SMB_ADDR 0x02 /* address */153#define AMD_SMB_CMD 0x03 /* command */154#define AMD_SMB_DATA 0x04 /* 32 data registers */155#define AMD_SMB_BCNT 0x24 /* number of data bytes */156#define AMD_SMB_ALRM_A 0x25 /* alarm address */157#define AMD_SMB_ALRM_D 0x26 /* 2 bytes alarm data */158 159#define AMD_SMB_STS_DONE 0x80160#define AMD_SMB_STS_ALRM 0x40161#define AMD_SMB_STS_RES 0x20162#define AMD_SMB_STS_STATUS 0x1f163 164#define AMD_SMB_STATUS_OK 0x00165#define AMD_SMB_STATUS_FAIL 0x07166#define AMD_SMB_STATUS_DNAK 0x10167#define AMD_SMB_STATUS_DERR 0x11168#define AMD_SMB_STATUS_CMD_DENY 0x12169#define AMD_SMB_STATUS_UNKNOWN 0x13170#define AMD_SMB_STATUS_ACC_DENY 0x17171#define AMD_SMB_STATUS_TIMEOUT 0x18172#define AMD_SMB_STATUS_NOTSUP 0x19173#define AMD_SMB_STATUS_BUSY 0x1A174#define AMD_SMB_STATUS_PEC 0x1F175 176#define AMD_SMB_PRTCL_WRITE 0x00177#define AMD_SMB_PRTCL_READ 0x01178#define AMD_SMB_PRTCL_QUICK 0x02179#define AMD_SMB_PRTCL_BYTE 0x04180#define AMD_SMB_PRTCL_BYTE_DATA 0x06181#define AMD_SMB_PRTCL_WORD_DATA 0x08182#define AMD_SMB_PRTCL_BLOCK_DATA 0x0a183#define AMD_SMB_PRTCL_PROC_CALL 0x0c184#define AMD_SMB_PRTCL_BLOCK_PROC_CALL 0x0d185#define AMD_SMB_PRTCL_I2C_BLOCK_DATA 0x4a186#define AMD_SMB_PRTCL_PEC 0x80187 188 189static s32 amd8111_access(struct i2c_adapter *adap, u16 addr,190 unsigned short flags, char read_write, u8 command, int size,191 union i2c_smbus_data *data)192{193 struct amd_smbus *smbus = adap->algo_data;194 unsigned char protocol, len, pec, temp[2];195 int i, status;196 197 protocol = (read_write == I2C_SMBUS_READ) ? AMD_SMB_PRTCL_READ198 : AMD_SMB_PRTCL_WRITE;199 pec = (flags & I2C_CLIENT_PEC) ? AMD_SMB_PRTCL_PEC : 0;200 201 switch (size) {202 case I2C_SMBUS_QUICK:203 protocol |= AMD_SMB_PRTCL_QUICK;204 read_write = I2C_SMBUS_WRITE;205 break;206 207 case I2C_SMBUS_BYTE:208 if (read_write == I2C_SMBUS_WRITE) {209 status = amd_ec_write(smbus, AMD_SMB_CMD,210 command);211 if (status)212 return status;213 }214 protocol |= AMD_SMB_PRTCL_BYTE;215 break;216 217 case I2C_SMBUS_BYTE_DATA:218 status = amd_ec_write(smbus, AMD_SMB_CMD, command);219 if (status)220 return status;221 if (read_write == I2C_SMBUS_WRITE) {222 status = amd_ec_write(smbus, AMD_SMB_DATA,223 data->byte);224 if (status)225 return status;226 }227 protocol |= AMD_SMB_PRTCL_BYTE_DATA;228 break;229 230 case I2C_SMBUS_WORD_DATA:231 status = amd_ec_write(smbus, AMD_SMB_CMD, command);232 if (status)233 return status;234 if (read_write == I2C_SMBUS_WRITE) {235 status = amd_ec_write(smbus, AMD_SMB_DATA,236 data->word & 0xff);237 if (status)238 return status;239 status = amd_ec_write(smbus, AMD_SMB_DATA + 1,240 data->word >> 8);241 if (status)242 return status;243 }244 protocol |= AMD_SMB_PRTCL_WORD_DATA | pec;245 break;246 247 case I2C_SMBUS_BLOCK_DATA:248 status = amd_ec_write(smbus, AMD_SMB_CMD, command);249 if (status)250 return status;251 if (read_write == I2C_SMBUS_WRITE) {252 len = min_t(u8, data->block[0],253 I2C_SMBUS_BLOCK_MAX);254 status = amd_ec_write(smbus, AMD_SMB_BCNT, len);255 if (status)256 return status;257 for (i = 0; i < len; i++) {258 status =259 amd_ec_write(smbus, AMD_SMB_DATA + i,260 data->block[i + 1]);261 if (status)262 return status;263 }264 }265 protocol |= AMD_SMB_PRTCL_BLOCK_DATA | pec;266 break;267 268 case I2C_SMBUS_I2C_BLOCK_DATA:269 len = min_t(u8, data->block[0],270 I2C_SMBUS_BLOCK_MAX);271 status = amd_ec_write(smbus, AMD_SMB_CMD, command);272 if (status)273 return status;274 status = amd_ec_write(smbus, AMD_SMB_BCNT, len);275 if (status)276 return status;277 if (read_write == I2C_SMBUS_WRITE)278 for (i = 0; i < len; i++) {279 status =280 amd_ec_write(smbus, AMD_SMB_DATA + i,281 data->block[i + 1]);282 if (status)283 return status;284 }285 protocol |= AMD_SMB_PRTCL_I2C_BLOCK_DATA;286 break;287 288 case I2C_SMBUS_PROC_CALL:289 status = amd_ec_write(smbus, AMD_SMB_CMD, command);290 if (status)291 return status;292 status = amd_ec_write(smbus, AMD_SMB_DATA,293 data->word & 0xff);294 if (status)295 return status;296 status = amd_ec_write(smbus, AMD_SMB_DATA + 1,297 data->word >> 8);298 if (status)299 return status;300 protocol = AMD_SMB_PRTCL_PROC_CALL | pec;301 read_write = I2C_SMBUS_READ;302 break;303 304 case I2C_SMBUS_BLOCK_PROC_CALL:305 len = min_t(u8, data->block[0],306 I2C_SMBUS_BLOCK_MAX - 1);307 status = amd_ec_write(smbus, AMD_SMB_CMD, command);308 if (status)309 return status;310 status = amd_ec_write(smbus, AMD_SMB_BCNT, len);311 if (status)312 return status;313 for (i = 0; i < len; i++) {314 status = amd_ec_write(smbus, AMD_SMB_DATA + i,315 data->block[i + 1]);316 if (status)317 return status;318 }319 protocol = AMD_SMB_PRTCL_BLOCK_PROC_CALL | pec;320 read_write = I2C_SMBUS_READ;321 break;322 323 default:324 dev_warn(&adap->dev, "Unsupported transaction %d\n", size);325 return -EOPNOTSUPP;326 }327 328 status = amd_ec_write(smbus, AMD_SMB_ADDR, addr << 1);329 if (status)330 return status;331 status = amd_ec_write(smbus, AMD_SMB_PRTCL, protocol);332 if (status)333 return status;334 335 status = amd_ec_read(smbus, AMD_SMB_STS, temp + 0);336 if (status)337 return status;338 339 if (~temp[0] & AMD_SMB_STS_DONE) {340 udelay(500);341 status = amd_ec_read(smbus, AMD_SMB_STS, temp + 0);342 if (status)343 return status;344 }345 346 if (~temp[0] & AMD_SMB_STS_DONE) {347 msleep(1);348 status = amd_ec_read(smbus, AMD_SMB_STS, temp + 0);349 if (status)350 return status;351 }352 353 if ((~temp[0] & AMD_SMB_STS_DONE) || (temp[0] & AMD_SMB_STS_STATUS))354 return -EIO;355 356 if (read_write == I2C_SMBUS_WRITE)357 return 0;358 359 switch (size) {360 case I2C_SMBUS_BYTE:361 case I2C_SMBUS_BYTE_DATA:362 status = amd_ec_read(smbus, AMD_SMB_DATA, &data->byte);363 if (status)364 return status;365 break;366 367 case I2C_SMBUS_WORD_DATA:368 case I2C_SMBUS_PROC_CALL:369 status = amd_ec_read(smbus, AMD_SMB_DATA, temp + 0);370 if (status)371 return status;372 status = amd_ec_read(smbus, AMD_SMB_DATA + 1, temp + 1);373 if (status)374 return status;375 data->word = (temp[1] << 8) | temp[0];376 break;377 378 case I2C_SMBUS_BLOCK_DATA:379 case I2C_SMBUS_BLOCK_PROC_CALL:380 status = amd_ec_read(smbus, AMD_SMB_BCNT, &len);381 if (status)382 return status;383 len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX);384 fallthrough;385 case I2C_SMBUS_I2C_BLOCK_DATA:386 for (i = 0; i < len; i++) {387 status = amd_ec_read(smbus, AMD_SMB_DATA + i,388 data->block + i + 1);389 if (status)390 return status;391 }392 data->block[0] = len;393 break;394 }395 396 return 0;397}398 399 400static u32 amd8111_func(struct i2c_adapter *adapter)401{402 return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |403 I2C_FUNC_SMBUS_BYTE_DATA |404 I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA |405 I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_PROC_CALL |406 I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_PEC;407}408 409static const struct i2c_algorithm smbus_algorithm = {410 .smbus_xfer = amd8111_access,411 .functionality = amd8111_func,412};413 414 415static const struct pci_device_id amd8111_ids[] = {416 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS2) },417 { 0, }418};419 420MODULE_DEVICE_TABLE (pci, amd8111_ids);421 422static int amd8111_probe(struct pci_dev *dev, const struct pci_device_id *id)423{424 struct amd_smbus *smbus;425 int error;426 427 if (!(pci_resource_flags(dev, 0) & IORESOURCE_IO))428 return -ENODEV;429 430 smbus = kzalloc(sizeof(struct amd_smbus), GFP_KERNEL);431 if (!smbus)432 return -ENOMEM;433 434 smbus->dev = dev;435 smbus->base = pci_resource_start(dev, 0);436 smbus->size = pci_resource_len(dev, 0);437 438 error = acpi_check_resource_conflict(&dev->resource[0]);439 if (error) {440 error = -ENODEV;441 goto out_kfree;442 }443 444 if (!request_region(smbus->base, smbus->size, amd8111_driver.name)) {445 error = -EBUSY;446 goto out_kfree;447 }448 449 smbus->adapter.owner = THIS_MODULE;450 snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),451 "SMBus2 AMD8111 adapter at %04x", smbus->base);452 smbus->adapter.class = I2C_CLASS_HWMON;453 smbus->adapter.algo = &smbus_algorithm;454 smbus->adapter.algo_data = smbus;455 456 /* set up the sysfs linkage to our parent device */457 smbus->adapter.dev.parent = &dev->dev;458 459 pci_write_config_dword(smbus->dev, AMD_PCI_MISC, 0);460 error = i2c_add_adapter(&smbus->adapter);461 if (error)462 goto out_release_region;463 464 pci_set_drvdata(dev, smbus);465 return 0;466 467 out_release_region:468 release_region(smbus->base, smbus->size);469 out_kfree:470 kfree(smbus);471 return error;472}473 474static void amd8111_remove(struct pci_dev *dev)475{476 struct amd_smbus *smbus = pci_get_drvdata(dev);477 478 i2c_del_adapter(&smbus->adapter);479 release_region(smbus->base, smbus->size);480 kfree(smbus);481}482 483static struct pci_driver amd8111_driver = {484 .name = "amd8111_smbus2",485 .id_table = amd8111_ids,486 .probe = amd8111_probe,487 .remove = amd8111_remove,488};489 490module_pci_driver(amd8111_driver);491