diff options
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/i2c-i801.c | 99 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-octeon.c | 17 | ||||
-rw-r--r-- | drivers/i2c/muxes/i2c-mux-reg.c | 1 |
3 files changed, 107 insertions, 10 deletions
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 64b1208bca5e..4a60ad214747 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c | |||
@@ -245,6 +245,13 @@ struct i801_priv { | |||
245 | struct platform_device *mux_pdev; | 245 | struct platform_device *mux_pdev; |
246 | #endif | 246 | #endif |
247 | struct platform_device *tco_pdev; | 247 | struct platform_device *tco_pdev; |
248 | |||
249 | /* | ||
250 | * If set to true the host controller registers are reserved for | ||
251 | * ACPI AML use. Protected by acpi_lock. | ||
252 | */ | ||
253 | bool acpi_reserved; | ||
254 | struct mutex acpi_lock; | ||
248 | }; | 255 | }; |
249 | 256 | ||
250 | #define FEATURE_SMBUS_PEC (1 << 0) | 257 | #define FEATURE_SMBUS_PEC (1 << 0) |
@@ -718,6 +725,12 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, | |||
718 | int ret = 0, xact = 0; | 725 | int ret = 0, xact = 0; |
719 | struct i801_priv *priv = i2c_get_adapdata(adap); | 726 | struct i801_priv *priv = i2c_get_adapdata(adap); |
720 | 727 | ||
728 | mutex_lock(&priv->acpi_lock); | ||
729 | if (priv->acpi_reserved) { | ||
730 | mutex_unlock(&priv->acpi_lock); | ||
731 | return -EBUSY; | ||
732 | } | ||
733 | |||
721 | pm_runtime_get_sync(&priv->pci_dev->dev); | 734 | pm_runtime_get_sync(&priv->pci_dev->dev); |
722 | 735 | ||
723 | hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC) | 736 | hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC) |
@@ -820,6 +833,7 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, | |||
820 | out: | 833 | out: |
821 | pm_runtime_mark_last_busy(&priv->pci_dev->dev); | 834 | pm_runtime_mark_last_busy(&priv->pci_dev->dev); |
822 | pm_runtime_put_autosuspend(&priv->pci_dev->dev); | 835 | pm_runtime_put_autosuspend(&priv->pci_dev->dev); |
836 | mutex_unlock(&priv->acpi_lock); | ||
823 | return ret; | 837 | return ret; |
824 | } | 838 | } |
825 | 839 | ||
@@ -1257,6 +1271,83 @@ static void i801_add_tco(struct i801_priv *priv) | |||
1257 | priv->tco_pdev = pdev; | 1271 | priv->tco_pdev = pdev; |
1258 | } | 1272 | } |
1259 | 1273 | ||
1274 | #ifdef CONFIG_ACPI | ||
1275 | static acpi_status | ||
1276 | i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits, | ||
1277 | u64 *value, void *handler_context, void *region_context) | ||
1278 | { | ||
1279 | struct i801_priv *priv = handler_context; | ||
1280 | struct pci_dev *pdev = priv->pci_dev; | ||
1281 | acpi_status status; | ||
1282 | |||
1283 | /* | ||
1284 | * Once BIOS AML code touches the OpRegion we warn and inhibit any | ||
1285 | * further access from the driver itself. This device is now owned | ||
1286 | * by the system firmware. | ||
1287 | */ | ||
1288 | mutex_lock(&priv->acpi_lock); | ||
1289 | |||
1290 | if (!priv->acpi_reserved) { | ||
1291 | priv->acpi_reserved = true; | ||
1292 | |||
1293 | dev_warn(&pdev->dev, "BIOS is accessing SMBus registers\n"); | ||
1294 | dev_warn(&pdev->dev, "Driver SMBus register access inhibited\n"); | ||
1295 | |||
1296 | /* | ||
1297 | * BIOS is accessing the host controller so prevent it from | ||
1298 | * suspending automatically from now on. | ||
1299 | */ | ||
1300 | pm_runtime_get_sync(&pdev->dev); | ||
1301 | } | ||
1302 | |||
1303 | if ((function & ACPI_IO_MASK) == ACPI_READ) | ||
1304 | status = acpi_os_read_port(address, (u32 *)value, bits); | ||
1305 | else | ||
1306 | status = acpi_os_write_port(address, (u32)*value, bits); | ||
1307 | |||
1308 | mutex_unlock(&priv->acpi_lock); | ||
1309 | |||
1310 | return status; | ||
1311 | } | ||
1312 | |||
1313 | static int i801_acpi_probe(struct i801_priv *priv) | ||
1314 | { | ||
1315 | struct acpi_device *adev; | ||
1316 | acpi_status status; | ||
1317 | |||
1318 | adev = ACPI_COMPANION(&priv->pci_dev->dev); | ||
1319 | if (adev) { | ||
1320 | status = acpi_install_address_space_handler(adev->handle, | ||
1321 | ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler, | ||
1322 | NULL, priv); | ||
1323 | if (ACPI_SUCCESS(status)) | ||
1324 | return 0; | ||
1325 | } | ||
1326 | |||
1327 | return acpi_check_resource_conflict(&priv->pci_dev->resource[SMBBAR]); | ||
1328 | } | ||
1329 | |||
1330 | static void i801_acpi_remove(struct i801_priv *priv) | ||
1331 | { | ||
1332 | struct acpi_device *adev; | ||
1333 | |||
1334 | adev = ACPI_COMPANION(&priv->pci_dev->dev); | ||
1335 | if (!adev) | ||
1336 | return; | ||
1337 | |||
1338 | acpi_remove_address_space_handler(adev->handle, | ||
1339 | ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler); | ||
1340 | |||
1341 | mutex_lock(&priv->acpi_lock); | ||
1342 | if (priv->acpi_reserved) | ||
1343 | pm_runtime_put(&priv->pci_dev->dev); | ||
1344 | mutex_unlock(&priv->acpi_lock); | ||
1345 | } | ||
1346 | #else | ||
1347 | static inline int i801_acpi_probe(struct i801_priv *priv) { return 0; } | ||
1348 | static inline void i801_acpi_remove(struct i801_priv *priv) { } | ||
1349 | #endif | ||
1350 | |||
1260 | static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) | 1351 | static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) |
1261 | { | 1352 | { |
1262 | unsigned char temp; | 1353 | unsigned char temp; |
@@ -1274,6 +1365,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
1274 | priv->adapter.dev.parent = &dev->dev; | 1365 | priv->adapter.dev.parent = &dev->dev; |
1275 | ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&dev->dev)); | 1366 | ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&dev->dev)); |
1276 | priv->adapter.retries = 3; | 1367 | priv->adapter.retries = 3; |
1368 | mutex_init(&priv->acpi_lock); | ||
1277 | 1369 | ||
1278 | priv->pci_dev = dev; | 1370 | priv->pci_dev = dev; |
1279 | switch (dev->device) { | 1371 | switch (dev->device) { |
@@ -1336,10 +1428,8 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
1336 | return -ENODEV; | 1428 | return -ENODEV; |
1337 | } | 1429 | } |
1338 | 1430 | ||
1339 | err = acpi_check_resource_conflict(&dev->resource[SMBBAR]); | 1431 | if (i801_acpi_probe(priv)) |
1340 | if (err) { | ||
1341 | return -ENODEV; | 1432 | return -ENODEV; |
1342 | } | ||
1343 | 1433 | ||
1344 | err = pcim_iomap_regions(dev, 1 << SMBBAR, | 1434 | err = pcim_iomap_regions(dev, 1 << SMBBAR, |
1345 | dev_driver_string(&dev->dev)); | 1435 | dev_driver_string(&dev->dev)); |
@@ -1348,6 +1438,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
1348 | "Failed to request SMBus region 0x%lx-0x%Lx\n", | 1438 | "Failed to request SMBus region 0x%lx-0x%Lx\n", |
1349 | priv->smba, | 1439 | priv->smba, |
1350 | (unsigned long long)pci_resource_end(dev, SMBBAR)); | 1440 | (unsigned long long)pci_resource_end(dev, SMBBAR)); |
1441 | i801_acpi_remove(priv); | ||
1351 | return err; | 1442 | return err; |
1352 | } | 1443 | } |
1353 | 1444 | ||
@@ -1412,6 +1503,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
1412 | err = i2c_add_adapter(&priv->adapter); | 1503 | err = i2c_add_adapter(&priv->adapter); |
1413 | if (err) { | 1504 | if (err) { |
1414 | dev_err(&dev->dev, "Failed to add SMBus adapter\n"); | 1505 | dev_err(&dev->dev, "Failed to add SMBus adapter\n"); |
1506 | i801_acpi_remove(priv); | ||
1415 | return err; | 1507 | return err; |
1416 | } | 1508 | } |
1417 | 1509 | ||
@@ -1438,6 +1530,7 @@ static void i801_remove(struct pci_dev *dev) | |||
1438 | 1530 | ||
1439 | i801_del_mux(priv); | 1531 | i801_del_mux(priv); |
1440 | i2c_del_adapter(&priv->adapter); | 1532 | i2c_del_adapter(&priv->adapter); |
1533 | i801_acpi_remove(priv); | ||
1441 | pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); | 1534 | pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); |
1442 | 1535 | ||
1443 | platform_device_unregister(priv->tco_pdev); | 1536 | platform_device_unregister(priv->tco_pdev); |
diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c index aa5f01efd826..30ae35146723 100644 --- a/drivers/i2c/busses/i2c-octeon.c +++ b/drivers/i2c/busses/i2c-octeon.c | |||
@@ -934,8 +934,15 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target, | |||
934 | return result; | 934 | return result; |
935 | 935 | ||
936 | for (i = 0; i < length; i++) { | 936 | for (i = 0; i < length; i++) { |
937 | /* for the last byte TWSI_CTL_AAK must not be set */ | 937 | /* |
938 | if (i + 1 == length) | 938 | * For the last byte to receive TWSI_CTL_AAK must not be set. |
939 | * | ||
940 | * A special case is I2C_M_RECV_LEN where we don't know the | ||
941 | * additional length yet. If recv_len is set we assume we're | ||
942 | * not reading the final byte and therefore need to set | ||
943 | * TWSI_CTL_AAK. | ||
944 | */ | ||
945 | if ((i + 1 == length) && !(recv_len && i == 0)) | ||
939 | final_read = true; | 946 | final_read = true; |
940 | 947 | ||
941 | /* clear iflg to allow next event */ | 948 | /* clear iflg to allow next event */ |
@@ -950,12 +957,8 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target, | |||
950 | 957 | ||
951 | data[i] = octeon_i2c_data_read(i2c); | 958 | data[i] = octeon_i2c_data_read(i2c); |
952 | if (recv_len && i == 0) { | 959 | if (recv_len && i == 0) { |
953 | if (data[i] > I2C_SMBUS_BLOCK_MAX + 1) { | 960 | if (data[i] > I2C_SMBUS_BLOCK_MAX + 1) |
954 | dev_err(i2c->dev, | ||
955 | "%s: read len > I2C_SMBUS_BLOCK_MAX %d\n", | ||
956 | __func__, data[i]); | ||
957 | return -EPROTO; | 961 | return -EPROTO; |
958 | } | ||
959 | length += data[i]; | 962 | length += data[i]; |
960 | } | 963 | } |
961 | 964 | ||
diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c index 6773cadf7c9f..26e7c5187a58 100644 --- a/drivers/i2c/muxes/i2c-mux-reg.c +++ b/drivers/i2c/muxes/i2c-mux-reg.c | |||
@@ -260,6 +260,7 @@ static struct platform_driver i2c_mux_reg_driver = { | |||
260 | .remove = i2c_mux_reg_remove, | 260 | .remove = i2c_mux_reg_remove, |
261 | .driver = { | 261 | .driver = { |
262 | .name = "i2c-mux-reg", | 262 | .name = "i2c-mux-reg", |
263 | .of_match_table = of_match_ptr(i2c_mux_reg_of_match), | ||
263 | }, | 264 | }, |
264 | }; | 265 | }; |
265 | 266 | ||