i2c-simtec.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2005 Simtec Electronics
  4. * Ben Dooks <[email protected]>
  5. *
  6. * Simtec Generic I2C Controller
  7. */
  8. #include <linux/kernel.h>
  9. #include <linux/module.h>
  10. #include <linux/delay.h>
  11. #include <linux/platform_device.h>
  12. #include <linux/slab.h>
  13. #include <linux/io.h>
  14. #include <linux/i2c.h>
  15. #include <linux/i2c-algo-bit.h>
  16. struct simtec_i2c_data {
  17. struct resource *ioarea;
  18. void __iomem *reg;
  19. struct i2c_adapter adap;
  20. struct i2c_algo_bit_data bit;
  21. };
  22. #define CMD_SET_SDA (1<<2)
  23. #define CMD_SET_SCL (1<<3)
  24. #define STATE_SDA (1<<0)
  25. #define STATE_SCL (1<<1)
  26. /* i2c bit-bus functions */
  27. static void simtec_i2c_setsda(void *pw, int state)
  28. {
  29. struct simtec_i2c_data *pd = pw;
  30. writeb(CMD_SET_SDA | (state ? STATE_SDA : 0), pd->reg);
  31. }
  32. static void simtec_i2c_setscl(void *pw, int state)
  33. {
  34. struct simtec_i2c_data *pd = pw;
  35. writeb(CMD_SET_SCL | (state ? STATE_SCL : 0), pd->reg);
  36. }
  37. static int simtec_i2c_getsda(void *pw)
  38. {
  39. struct simtec_i2c_data *pd = pw;
  40. return readb(pd->reg) & STATE_SDA ? 1 : 0;
  41. }
  42. static int simtec_i2c_getscl(void *pw)
  43. {
  44. struct simtec_i2c_data *pd = pw;
  45. return readb(pd->reg) & STATE_SCL ? 1 : 0;
  46. }
  47. /* device registration */
  48. static int simtec_i2c_probe(struct platform_device *dev)
  49. {
  50. struct simtec_i2c_data *pd;
  51. struct resource *res;
  52. int size;
  53. int ret;
  54. pd = kzalloc(sizeof(struct simtec_i2c_data), GFP_KERNEL);
  55. if (pd == NULL)
  56. return -ENOMEM;
  57. platform_set_drvdata(dev, pd);
  58. res = platform_get_resource(dev, IORESOURCE_MEM, 0);
  59. if (res == NULL) {
  60. dev_err(&dev->dev, "cannot find IO resource\n");
  61. ret = -ENOENT;
  62. goto err;
  63. }
  64. size = resource_size(res);
  65. pd->ioarea = request_mem_region(res->start, size, dev->name);
  66. if (pd->ioarea == NULL) {
  67. dev_err(&dev->dev, "cannot request IO\n");
  68. ret = -ENXIO;
  69. goto err;
  70. }
  71. pd->reg = ioremap(res->start, size);
  72. if (pd->reg == NULL) {
  73. dev_err(&dev->dev, "cannot map IO\n");
  74. ret = -ENXIO;
  75. goto err_res;
  76. }
  77. /* setup the private data */
  78. pd->adap.owner = THIS_MODULE;
  79. pd->adap.algo_data = &pd->bit;
  80. pd->adap.dev.parent = &dev->dev;
  81. strscpy(pd->adap.name, "Simtec I2C", sizeof(pd->adap.name));
  82. pd->bit.data = pd;
  83. pd->bit.setsda = simtec_i2c_setsda;
  84. pd->bit.setscl = simtec_i2c_setscl;
  85. pd->bit.getsda = simtec_i2c_getsda;
  86. pd->bit.getscl = simtec_i2c_getscl;
  87. pd->bit.timeout = HZ;
  88. pd->bit.udelay = 20;
  89. ret = i2c_bit_add_bus(&pd->adap);
  90. if (ret)
  91. goto err_all;
  92. return 0;
  93. err_all:
  94. iounmap(pd->reg);
  95. err_res:
  96. release_mem_region(pd->ioarea->start, size);
  97. err:
  98. kfree(pd);
  99. return ret;
  100. }
  101. static int simtec_i2c_remove(struct platform_device *dev)
  102. {
  103. struct simtec_i2c_data *pd = platform_get_drvdata(dev);
  104. i2c_del_adapter(&pd->adap);
  105. iounmap(pd->reg);
  106. release_mem_region(pd->ioarea->start, resource_size(pd->ioarea));
  107. kfree(pd);
  108. return 0;
  109. }
  110. /* device driver */
  111. static struct platform_driver simtec_i2c_driver = {
  112. .driver = {
  113. .name = "simtec-i2c",
  114. },
  115. .probe = simtec_i2c_probe,
  116. .remove = simtec_i2c_remove,
  117. };
  118. module_platform_driver(simtec_i2c_driver);
  119. MODULE_DESCRIPTION("Simtec Generic I2C Bus driver");
  120. MODULE_AUTHOR("Ben Dooks <[email protected]>");
  121. MODULE_LICENSE("GPL");
  122. MODULE_ALIAS("platform:simtec-i2c");