i2c-pxa-pci.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * CE4100 PCI-I2C glue code for PXA's driver
  4. * Author: Sebastian Andrzej Siewior <[email protected]>
  5. *
  6. * The CE4100's I2C device is more or less the same one as found on PXA.
  7. * It does not support slave mode, the register slightly moved. This PCI
  8. * device provides three bars, every contains a single I2C controller.
  9. */
  10. #include <linux/init.h>
  11. #include <linux/pci.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/platform_data/i2c-pxa.h>
  14. #include <linux/of.h>
  15. #include <linux/of_device.h>
  16. #include <linux/of_address.h>
  17. #define CE4100_PCI_I2C_DEVS 3
  18. struct ce4100_devices {
  19. struct platform_device *pdev[CE4100_PCI_I2C_DEVS];
  20. };
  21. static struct platform_device *add_i2c_device(struct pci_dev *dev, int bar)
  22. {
  23. struct platform_device *pdev;
  24. struct i2c_pxa_platform_data pdata;
  25. struct resource res[2];
  26. struct device_node *child;
  27. static int devnum;
  28. int ret;
  29. memset(&pdata, 0, sizeof(struct i2c_pxa_platform_data));
  30. memset(&res, 0, sizeof(res));
  31. res[0].flags = IORESOURCE_MEM;
  32. res[0].start = pci_resource_start(dev, bar);
  33. res[0].end = pci_resource_end(dev, bar);
  34. res[1].flags = IORESOURCE_IRQ;
  35. res[1].start = dev->irq;
  36. res[1].end = dev->irq;
  37. for_each_child_of_node(dev->dev.of_node, child) {
  38. const void *prop;
  39. struct resource r;
  40. int ret;
  41. ret = of_address_to_resource(child, 0, &r);
  42. if (ret < 0)
  43. continue;
  44. if (r.start != res[0].start)
  45. continue;
  46. if (r.end != res[0].end)
  47. continue;
  48. if (r.flags != res[0].flags)
  49. continue;
  50. prop = of_get_property(child, "fast-mode", NULL);
  51. if (prop)
  52. pdata.fast_mode = 1;
  53. break;
  54. }
  55. if (!child) {
  56. dev_err(&dev->dev, "failed to match a DT node for bar %d.\n",
  57. bar);
  58. ret = -EINVAL;
  59. goto out;
  60. }
  61. pdev = platform_device_alloc("ce4100-i2c", devnum);
  62. if (!pdev) {
  63. of_node_put(child);
  64. ret = -ENOMEM;
  65. goto out;
  66. }
  67. pdev->dev.parent = &dev->dev;
  68. pdev->dev.of_node = child;
  69. ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res));
  70. if (ret)
  71. goto err;
  72. ret = platform_device_add_data(pdev, &pdata, sizeof(pdata));
  73. if (ret)
  74. goto err;
  75. ret = platform_device_add(pdev);
  76. if (ret)
  77. goto err;
  78. devnum++;
  79. return pdev;
  80. err:
  81. platform_device_put(pdev);
  82. out:
  83. return ERR_PTR(ret);
  84. }
  85. static int ce4100_i2c_probe(struct pci_dev *dev,
  86. const struct pci_device_id *ent)
  87. {
  88. int ret;
  89. int i;
  90. struct ce4100_devices *sds;
  91. ret = pcim_enable_device(dev);
  92. if (ret)
  93. return ret;
  94. if (!dev->dev.of_node) {
  95. dev_err(&dev->dev, "Missing device tree node.\n");
  96. return -EINVAL;
  97. }
  98. sds = kzalloc(sizeof(*sds), GFP_KERNEL);
  99. if (!sds)
  100. return -ENOMEM;
  101. for (i = 0; i < ARRAY_SIZE(sds->pdev); i++) {
  102. sds->pdev[i] = add_i2c_device(dev, i);
  103. if (IS_ERR(sds->pdev[i])) {
  104. ret = PTR_ERR(sds->pdev[i]);
  105. while (--i >= 0)
  106. platform_device_unregister(sds->pdev[i]);
  107. goto err_dev_add;
  108. }
  109. }
  110. pci_set_drvdata(dev, sds);
  111. return 0;
  112. err_dev_add:
  113. kfree(sds);
  114. return ret;
  115. }
  116. static const struct pci_device_id ce4100_i2c_devices[] = {
  117. { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e68)},
  118. { },
  119. };
  120. static struct pci_driver ce4100_i2c_driver = {
  121. .driver = {
  122. .suppress_bind_attrs = true,
  123. },
  124. .name = "ce4100_i2c",
  125. .id_table = ce4100_i2c_devices,
  126. .probe = ce4100_i2c_probe,
  127. };
  128. builtin_pci_driver(ce4100_i2c_driver);