ssd130x-spi.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * DRM driver for Solomon SSD130X OLED displays (SPI bus)
  4. *
  5. * Copyright 2022 Red Hat Inc.
  6. * Authors: Javier Martinez Canillas <[email protected]>
  7. */
  8. #include <linux/spi/spi.h>
  9. #include <linux/module.h>
  10. #include "ssd130x.h"
  11. #define DRIVER_NAME "ssd130x-spi"
  12. #define DRIVER_DESC "DRM driver for Solomon SSD130X OLED displays (SPI)"
  13. struct ssd130x_spi_transport {
  14. struct spi_device *spi;
  15. struct gpio_desc *dc;
  16. };
  17. /*
  18. * The regmap bus .write handler, it is just a wrapper around spi_write()
  19. * but toggling the Data/Command control pin (D/C#). Since for 4-wire SPI
  20. * a D/C# pin is used, in contrast with I2C where a control byte is sent,
  21. * prior to every data byte, that contains a bit with the D/C# value.
  22. *
  23. * These control bytes are considered registers by the ssd130x core driver
  24. * and can be used by the ssd130x SPI driver to determine if the data sent
  25. * is for a command register or for the Graphic Display Data RAM (GDDRAM).
  26. */
  27. static int ssd130x_spi_write(void *context, const void *data, size_t count)
  28. {
  29. struct ssd130x_spi_transport *t = context;
  30. struct spi_device *spi = t->spi;
  31. const u8 *reg = data;
  32. if (*reg == SSD130X_COMMAND)
  33. gpiod_set_value_cansleep(t->dc, 0);
  34. if (*reg == SSD130X_DATA)
  35. gpiod_set_value_cansleep(t->dc, 1);
  36. /* Remove control byte since is not used in a 4-wire SPI interface */
  37. return spi_write(spi, reg + 1, count - 1);
  38. }
  39. /* The ssd130x driver does not read registers but regmap expects a .read */
  40. static int ssd130x_spi_read(void *context, const void *reg, size_t reg_size,
  41. void *val, size_t val_size)
  42. {
  43. return -EOPNOTSUPP;
  44. }
  45. static const struct regmap_config ssd130x_spi_regmap_config = {
  46. .reg_bits = 8,
  47. .val_bits = 8,
  48. .write = ssd130x_spi_write,
  49. .read = ssd130x_spi_read,
  50. .can_multi_write = true,
  51. };
  52. static int ssd130x_spi_probe(struct spi_device *spi)
  53. {
  54. struct ssd130x_spi_transport *t;
  55. struct ssd130x_device *ssd130x;
  56. struct regmap *regmap;
  57. struct gpio_desc *dc;
  58. struct device *dev = &spi->dev;
  59. dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW);
  60. if (IS_ERR(dc))
  61. return dev_err_probe(dev, PTR_ERR(dc),
  62. "Failed to get dc gpio\n");
  63. t = devm_kzalloc(dev, sizeof(*t), GFP_KERNEL);
  64. if (!t)
  65. return dev_err_probe(dev, -ENOMEM,
  66. "Failed to allocate SPI transport data\n");
  67. t->spi = spi;
  68. t->dc = dc;
  69. regmap = devm_regmap_init(dev, NULL, t, &ssd130x_spi_regmap_config);
  70. if (IS_ERR(regmap))
  71. return PTR_ERR(regmap);
  72. ssd130x = ssd130x_probe(dev, regmap);
  73. if (IS_ERR(ssd130x))
  74. return PTR_ERR(ssd130x);
  75. spi_set_drvdata(spi, ssd130x);
  76. return 0;
  77. }
  78. static void ssd130x_spi_remove(struct spi_device *spi)
  79. {
  80. struct ssd130x_device *ssd130x = spi_get_drvdata(spi);
  81. ssd130x_remove(ssd130x);
  82. }
  83. static void ssd130x_spi_shutdown(struct spi_device *spi)
  84. {
  85. struct ssd130x_device *ssd130x = spi_get_drvdata(spi);
  86. ssd130x_shutdown(ssd130x);
  87. }
  88. static const struct of_device_id ssd130x_of_match[] = {
  89. {
  90. .compatible = "sinowealth,sh1106",
  91. .data = &ssd130x_variants[SH1106_ID],
  92. },
  93. {
  94. .compatible = "solomon,ssd1305",
  95. .data = &ssd130x_variants[SSD1305_ID],
  96. },
  97. {
  98. .compatible = "solomon,ssd1306",
  99. .data = &ssd130x_variants[SSD1306_ID],
  100. },
  101. {
  102. .compatible = "solomon,ssd1307",
  103. .data = &ssd130x_variants[SSD1307_ID],
  104. },
  105. {
  106. .compatible = "solomon,ssd1309",
  107. .data = &ssd130x_variants[SSD1309_ID],
  108. },
  109. { /* sentinel */ }
  110. };
  111. MODULE_DEVICE_TABLE(of, ssd130x_of_match);
  112. #if IS_MODULE(CONFIG_DRM_SSD130X_SPI)
  113. /*
  114. * The SPI core always reports a MODALIAS uevent of the form "spi:<dev>", even
  115. * if the device was registered via OF. This means that the module will not be
  116. * auto loaded, unless it contains an alias that matches the MODALIAS reported.
  117. *
  118. * To workaround this issue, add a SPI device ID table. Even when this should
  119. * not be needed for this driver to match the registered SPI devices.
  120. */
  121. static const struct spi_device_id ssd130x_spi_table[] = {
  122. { "sh1106", SH1106_ID },
  123. { "ssd1305", SSD1305_ID },
  124. { "ssd1306", SSD1306_ID },
  125. { "ssd1307", SSD1307_ID },
  126. { "ssd1309", SSD1309_ID },
  127. { /* sentinel */ }
  128. };
  129. MODULE_DEVICE_TABLE(spi, ssd130x_spi_table);
  130. #endif
  131. static struct spi_driver ssd130x_spi_driver = {
  132. .driver = {
  133. .name = DRIVER_NAME,
  134. .of_match_table = ssd130x_of_match,
  135. },
  136. .probe = ssd130x_spi_probe,
  137. .remove = ssd130x_spi_remove,
  138. .shutdown = ssd130x_spi_shutdown,
  139. };
  140. module_spi_driver(ssd130x_spi_driver);
  141. MODULE_DESCRIPTION(DRIVER_DESC);
  142. MODULE_AUTHOR("Javier Martinez Canillas <[email protected]>");
  143. MODULE_LICENSE("GPL");
  144. MODULE_IMPORT_NS(DRM_SSD130X);