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