.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * TI OMAP I2C master mode driver |
---|
3 | 4 | * |
---|
.. | .. |
---|
12 | 13 | * Juha Yrjölä <juha.yrjola@solidboot.com> |
---|
13 | 14 | * Syed Khasim <x0khasim@ti.com> |
---|
14 | 15 | * Nishant Menon <nm@ti.com> |
---|
15 | | - * |
---|
16 | | - * This program is free software; you can redistribute it and/or modify |
---|
17 | | - * it under the terms of the GNU General Public License as published by |
---|
18 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
19 | | - * (at your option) any later version. |
---|
20 | | - * |
---|
21 | | - * This program is distributed in the hope that it will be useful, |
---|
22 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
23 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
24 | | - * GNU General Public License for more details. |
---|
25 | 16 | */ |
---|
26 | 17 | |
---|
27 | 18 | #include <linux/module.h> |
---|
.. | .. |
---|
268 | 259 | [OMAP_I2C_IP_V2_IRQENABLE_SET] = 0x2c, |
---|
269 | 260 | [OMAP_I2C_IP_V2_IRQENABLE_CLR] = 0x30, |
---|
270 | 261 | }; |
---|
| 262 | + |
---|
| 263 | +static int omap_i2c_xfer_data(struct omap_i2c_dev *omap); |
---|
271 | 264 | |
---|
272 | 265 | static inline void omap_i2c_write_reg(struct omap_i2c_dev *omap, |
---|
273 | 266 | int reg, u16 val) |
---|
.. | .. |
---|
648 | 641 | (1000 * omap->speed / 8); |
---|
649 | 642 | } |
---|
650 | 643 | |
---|
| 644 | +static void omap_i2c_wait(struct omap_i2c_dev *omap) |
---|
| 645 | +{ |
---|
| 646 | + u16 stat; |
---|
| 647 | + u16 mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG); |
---|
| 648 | + int count = 0; |
---|
| 649 | + |
---|
| 650 | + do { |
---|
| 651 | + stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG); |
---|
| 652 | + count++; |
---|
| 653 | + } while (!(stat & mask) && count < 5); |
---|
| 654 | +} |
---|
| 655 | + |
---|
651 | 656 | /* |
---|
652 | 657 | * Low level master read/write transaction. |
---|
653 | 658 | */ |
---|
654 | 659 | static int omap_i2c_xfer_msg(struct i2c_adapter *adap, |
---|
655 | | - struct i2c_msg *msg, int stop) |
---|
| 660 | + struct i2c_msg *msg, int stop, bool polling) |
---|
656 | 661 | { |
---|
657 | 662 | struct omap_i2c_dev *omap = i2c_get_adapdata(adap); |
---|
658 | 663 | unsigned long timeout; |
---|
659 | 664 | u16 w; |
---|
| 665 | + int ret; |
---|
660 | 666 | |
---|
661 | 667 | dev_dbg(omap->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n", |
---|
662 | 668 | msg->addr, msg->len, msg->flags, stop); |
---|
.. | .. |
---|
680 | 686 | w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR; |
---|
681 | 687 | omap_i2c_write_reg(omap, OMAP_I2C_BUF_REG, w); |
---|
682 | 688 | |
---|
683 | | - reinit_completion(&omap->cmd_complete); |
---|
| 689 | + if (!polling) |
---|
| 690 | + reinit_completion(&omap->cmd_complete); |
---|
684 | 691 | omap->cmd_err = 0; |
---|
685 | 692 | |
---|
686 | 693 | w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; |
---|
.. | .. |
---|
732 | 739 | * REVISIT: We should abort the transfer on signals, but the bus goes |
---|
733 | 740 | * into arbitration and we're currently unable to recover from it. |
---|
734 | 741 | */ |
---|
735 | | - timeout = wait_for_completion_timeout(&omap->cmd_complete, |
---|
736 | | - OMAP_I2C_TIMEOUT); |
---|
| 742 | + if (!polling) { |
---|
| 743 | + timeout = wait_for_completion_timeout(&omap->cmd_complete, |
---|
| 744 | + OMAP_I2C_TIMEOUT); |
---|
| 745 | + } else { |
---|
| 746 | + do { |
---|
| 747 | + omap_i2c_wait(omap); |
---|
| 748 | + ret = omap_i2c_xfer_data(omap); |
---|
| 749 | + } while (ret == -EAGAIN); |
---|
| 750 | + |
---|
| 751 | + timeout = !ret; |
---|
| 752 | + } |
---|
| 753 | + |
---|
737 | 754 | if (timeout == 0) { |
---|
738 | 755 | dev_err(omap->dev, "controller timed out\n"); |
---|
739 | 756 | omap_i2c_reset(omap); |
---|
.. | .. |
---|
772 | 789 | * to do the work during IRQ processing. |
---|
773 | 790 | */ |
---|
774 | 791 | static int |
---|
775 | | -omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) |
---|
| 792 | +omap_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg msgs[], int num, |
---|
| 793 | + bool polling) |
---|
776 | 794 | { |
---|
777 | 795 | struct omap_i2c_dev *omap = i2c_get_adapdata(adap); |
---|
778 | 796 | int i; |
---|
.. | .. |
---|
794 | 812 | omap->set_mpu_wkup_lat(omap->dev, omap->latency); |
---|
795 | 813 | |
---|
796 | 814 | for (i = 0; i < num; i++) { |
---|
797 | | - r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1))); |
---|
| 815 | + r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)), |
---|
| 816 | + polling); |
---|
798 | 817 | if (r != 0) |
---|
799 | 818 | break; |
---|
800 | 819 | } |
---|
.. | .. |
---|
811 | 830 | pm_runtime_mark_last_busy(omap->dev); |
---|
812 | 831 | pm_runtime_put_autosuspend(omap->dev); |
---|
813 | 832 | return r; |
---|
| 833 | +} |
---|
| 834 | + |
---|
| 835 | +static int |
---|
| 836 | +omap_i2c_xfer_irq(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) |
---|
| 837 | +{ |
---|
| 838 | + return omap_i2c_xfer_common(adap, msgs, num, false); |
---|
| 839 | +} |
---|
| 840 | + |
---|
| 841 | +static int |
---|
| 842 | +omap_i2c_xfer_polling(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) |
---|
| 843 | +{ |
---|
| 844 | + return omap_i2c_xfer_common(adap, msgs, num, true); |
---|
814 | 845 | } |
---|
815 | 846 | |
---|
816 | 847 | static u32 |
---|
.. | .. |
---|
1027 | 1058 | u16 stat; |
---|
1028 | 1059 | |
---|
1029 | 1060 | stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG); |
---|
1030 | | - mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG); |
---|
| 1061 | + mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG) & ~OMAP_I2C_STAT_NACK; |
---|
1031 | 1062 | |
---|
1032 | 1063 | if (stat & mask) |
---|
1033 | 1064 | ret = IRQ_WAKE_THREAD; |
---|
.. | .. |
---|
1035 | 1066 | return ret; |
---|
1036 | 1067 | } |
---|
1037 | 1068 | |
---|
1038 | | -static irqreturn_t |
---|
1039 | | -omap_i2c_isr_thread(int this_irq, void *dev_id) |
---|
| 1069 | +static int omap_i2c_xfer_data(struct omap_i2c_dev *omap) |
---|
1040 | 1070 | { |
---|
1041 | | - struct omap_i2c_dev *omap = dev_id; |
---|
1042 | 1071 | u16 bits; |
---|
1043 | 1072 | u16 stat; |
---|
1044 | 1073 | int err = 0, count = 0; |
---|
.. | .. |
---|
1056 | 1085 | |
---|
1057 | 1086 | if (!stat) { |
---|
1058 | 1087 | /* my work here is done */ |
---|
1059 | | - goto out; |
---|
| 1088 | + err = -EAGAIN; |
---|
| 1089 | + break; |
---|
1060 | 1090 | } |
---|
1061 | 1091 | |
---|
1062 | 1092 | dev_dbg(omap->dev, "IRQ (ISR = 0x%04x)\n", stat); |
---|
.. | .. |
---|
1165 | 1195 | } |
---|
1166 | 1196 | } while (stat); |
---|
1167 | 1197 | |
---|
1168 | | - omap_i2c_complete_cmd(omap, err); |
---|
| 1198 | + return err; |
---|
| 1199 | +} |
---|
1169 | 1200 | |
---|
1170 | | -out: |
---|
| 1201 | +static irqreturn_t |
---|
| 1202 | +omap_i2c_isr_thread(int this_irq, void *dev_id) |
---|
| 1203 | +{ |
---|
| 1204 | + int ret; |
---|
| 1205 | + struct omap_i2c_dev *omap = dev_id; |
---|
| 1206 | + |
---|
| 1207 | + ret = omap_i2c_xfer_data(omap); |
---|
| 1208 | + if (ret != -EAGAIN) |
---|
| 1209 | + omap_i2c_complete_cmd(omap, ret); |
---|
| 1210 | + |
---|
1171 | 1211 | return IRQ_HANDLED; |
---|
1172 | 1212 | } |
---|
1173 | 1213 | |
---|
1174 | 1214 | static const struct i2c_algorithm omap_i2c_algo = { |
---|
1175 | | - .master_xfer = omap_i2c_xfer, |
---|
| 1215 | + .master_xfer = omap_i2c_xfer_irq, |
---|
| 1216 | + .master_xfer_atomic = omap_i2c_xfer_polling, |
---|
1176 | 1217 | .functionality = omap_i2c_func, |
---|
1177 | 1218 | }; |
---|
1178 | 1219 | |
---|
.. | .. |
---|
1314 | 1355 | { |
---|
1315 | 1356 | struct omap_i2c_dev *omap; |
---|
1316 | 1357 | struct i2c_adapter *adap; |
---|
1317 | | - struct resource *mem; |
---|
1318 | 1358 | const struct omap_i2c_bus_platform_data *pdata = |
---|
1319 | 1359 | dev_get_platdata(&pdev->dev); |
---|
1320 | 1360 | struct device_node *node = pdev->dev.of_node; |
---|
.. | .. |
---|
1325 | 1365 | u16 minor, major; |
---|
1326 | 1366 | |
---|
1327 | 1367 | irq = platform_get_irq(pdev, 0); |
---|
1328 | | - if (irq < 0) { |
---|
1329 | | - dev_err(&pdev->dev, "no irq resource?\n"); |
---|
| 1368 | + if (irq < 0) |
---|
1330 | 1369 | return irq; |
---|
1331 | | - } |
---|
1332 | 1370 | |
---|
1333 | 1371 | omap = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL); |
---|
1334 | 1372 | if (!omap) |
---|
1335 | 1373 | return -ENOMEM; |
---|
1336 | 1374 | |
---|
1337 | | - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
1338 | | - omap->base = devm_ioremap_resource(&pdev->dev, mem); |
---|
| 1375 | + omap->base = devm_platform_ioremap_resource(pdev, 0); |
---|
1339 | 1376 | if (IS_ERR(omap->base)) |
---|
1340 | 1377 | return PTR_ERR(omap->base); |
---|
1341 | 1378 | |
---|
1342 | 1379 | match = of_match_device(of_match_ptr(omap_i2c_of_match), &pdev->dev); |
---|
1343 | 1380 | if (match) { |
---|
1344 | | - u32 freq = 100000; /* default to 100000 Hz */ |
---|
| 1381 | + u32 freq = I2C_MAX_STANDARD_MODE_FREQ; |
---|
1345 | 1382 | |
---|
1346 | 1383 | pdata = match->data; |
---|
1347 | 1384 | omap->flags = pdata->flags; |
---|
.. | .. |
---|
1367 | 1404 | pm_runtime_set_autosuspend_delay(omap->dev, OMAP_I2C_PM_TIMEOUT); |
---|
1368 | 1405 | pm_runtime_use_autosuspend(omap->dev); |
---|
1369 | 1406 | |
---|
1370 | | - r = pm_runtime_get_sync(omap->dev); |
---|
| 1407 | + r = pm_runtime_resume_and_get(omap->dev); |
---|
1371 | 1408 | if (r < 0) |
---|
1372 | | - goto err_free_mem; |
---|
| 1409 | + goto err_disable_pm; |
---|
1373 | 1410 | |
---|
1374 | 1411 | /* |
---|
1375 | 1412 | * Read the Rev hi bit-[15:14] ie scheme this is 1 indicates ver2. |
---|
.. | .. |
---|
1388 | 1425 | major = OMAP_I2C_REV_SCHEME_0_MAJOR(omap->rev); |
---|
1389 | 1426 | break; |
---|
1390 | 1427 | case OMAP_I2C_SCHEME_1: |
---|
1391 | | - /* FALLTHROUGH */ |
---|
1392 | 1428 | default: |
---|
1393 | 1429 | omap->regs = (u8 *)reg_map_ip_v2; |
---|
1394 | 1430 | rev = (rev << 16) | |
---|
.. | .. |
---|
1477 | 1513 | omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0); |
---|
1478 | 1514 | pm_runtime_dont_use_autosuspend(omap->dev); |
---|
1479 | 1515 | pm_runtime_put_sync(omap->dev); |
---|
| 1516 | +err_disable_pm: |
---|
1480 | 1517 | pm_runtime_disable(&pdev->dev); |
---|
1481 | | -err_free_mem: |
---|
1482 | 1518 | |
---|
1483 | 1519 | return r; |
---|
1484 | 1520 | } |
---|
.. | .. |
---|
1489 | 1525 | int ret; |
---|
1490 | 1526 | |
---|
1491 | 1527 | i2c_del_adapter(&omap->adapter); |
---|
1492 | | - ret = pm_runtime_get_sync(&pdev->dev); |
---|
| 1528 | + ret = pm_runtime_resume_and_get(&pdev->dev); |
---|
1493 | 1529 | if (ret < 0) |
---|
1494 | 1530 | return ret; |
---|
1495 | 1531 | |
---|