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