1b7b23e44SLinus Walleij // SPDX-License-Identifier: GPL-2.0 2b7b23e44SLinus Walleij 3b7b23e44SLinus Walleij #include <linux/device.h> 4b7b23e44SLinus Walleij #include <linux/module.h> 5b7b23e44SLinus Walleij #include <linux/spi/spi.h> 6b7b23e44SLinus Walleij #include <linux/delay.h> 7b7b23e44SLinus Walleij 8b7b23e44SLinus Walleij #include <drm/drm_print.h> 9b7b23e44SLinus Walleij 10b7b23e44SLinus Walleij #include "panel-samsung-s6e63m0.h" 11b7b23e44SLinus Walleij 12b7b23e44SLinus Walleij #define DATA_MASK 0x100 13b7b23e44SLinus Walleij 14*91867ac7SLinus Walleij static int s6e63m0_spi_dcs_read(struct device *dev, const u8 cmd, u8 *data) 15*91867ac7SLinus Walleij { 16*91867ac7SLinus Walleij /* 17*91867ac7SLinus Walleij * FIXME: implement reading DCS commands over SPI so we can 18*91867ac7SLinus Walleij * properly identify which physical panel is connected. 19*91867ac7SLinus Walleij */ 20*91867ac7SLinus Walleij *data = 0; 21*91867ac7SLinus Walleij 22*91867ac7SLinus Walleij return 0; 23*91867ac7SLinus Walleij } 24*91867ac7SLinus Walleij 25b7b23e44SLinus Walleij static int s6e63m0_spi_write_word(struct device *dev, u16 data) 26b7b23e44SLinus Walleij { 27b7b23e44SLinus Walleij struct spi_device *spi = to_spi_device(dev); 28b7b23e44SLinus Walleij struct spi_transfer xfer = { 29b7b23e44SLinus Walleij .len = 2, 30b7b23e44SLinus Walleij .tx_buf = &data, 31b7b23e44SLinus Walleij }; 32b7b23e44SLinus Walleij struct spi_message msg; 33b7b23e44SLinus Walleij 34b7b23e44SLinus Walleij spi_message_init(&msg); 35b7b23e44SLinus Walleij spi_message_add_tail(&xfer, &msg); 36b7b23e44SLinus Walleij 37b7b23e44SLinus Walleij return spi_sync(spi, &msg); 38b7b23e44SLinus Walleij } 39b7b23e44SLinus Walleij 40b7b23e44SLinus Walleij static int s6e63m0_spi_dcs_write(struct device *dev, const u8 *data, size_t len) 41b7b23e44SLinus Walleij { 42b7b23e44SLinus Walleij int ret = 0; 43b7b23e44SLinus Walleij 44b7b23e44SLinus Walleij DRM_DEV_DEBUG(dev, "SPI writing dcs seq: %*ph\n", (int)len, data); 45b7b23e44SLinus Walleij ret = s6e63m0_spi_write_word(dev, *data); 46b7b23e44SLinus Walleij 47b7b23e44SLinus Walleij while (!ret && --len) { 48b7b23e44SLinus Walleij ++data; 49b7b23e44SLinus Walleij ret = s6e63m0_spi_write_word(dev, *data | DATA_MASK); 50b7b23e44SLinus Walleij } 51b7b23e44SLinus Walleij 52b7b23e44SLinus Walleij if (ret) { 53b7b23e44SLinus Walleij DRM_DEV_ERROR(dev, "SPI error %d writing dcs seq: %*ph\n", ret, 54b7b23e44SLinus Walleij (int)len, data); 55b7b23e44SLinus Walleij } 56b7b23e44SLinus Walleij 57b7b23e44SLinus Walleij usleep_range(300, 310); 58b7b23e44SLinus Walleij 59b7b23e44SLinus Walleij return ret; 60b7b23e44SLinus Walleij } 61b7b23e44SLinus Walleij 62b7b23e44SLinus Walleij static int s6e63m0_spi_probe(struct spi_device *spi) 63b7b23e44SLinus Walleij { 64b7b23e44SLinus Walleij struct device *dev = &spi->dev; 65b7b23e44SLinus Walleij int ret; 66b7b23e44SLinus Walleij 67b7b23e44SLinus Walleij spi->bits_per_word = 9; 68b7b23e44SLinus Walleij spi->mode = SPI_MODE_3; 69b7b23e44SLinus Walleij ret = spi_setup(spi); 70b7b23e44SLinus Walleij if (ret < 0) { 71b7b23e44SLinus Walleij DRM_DEV_ERROR(dev, "spi setup failed.\n"); 72b7b23e44SLinus Walleij return ret; 73b7b23e44SLinus Walleij } 74*91867ac7SLinus Walleij return s6e63m0_probe(dev, s6e63m0_spi_dcs_read, s6e63m0_spi_dcs_write, 75*91867ac7SLinus Walleij false); 76b7b23e44SLinus Walleij } 77b7b23e44SLinus Walleij 78b7b23e44SLinus Walleij static int s6e63m0_spi_remove(struct spi_device *spi) 79b7b23e44SLinus Walleij { 80b7b23e44SLinus Walleij return s6e63m0_remove(&spi->dev); 81b7b23e44SLinus Walleij } 82b7b23e44SLinus Walleij 83b7b23e44SLinus Walleij static const struct of_device_id s6e63m0_spi_of_match[] = { 84b7b23e44SLinus Walleij { .compatible = "samsung,s6e63m0" }, 85b7b23e44SLinus Walleij { /* sentinel */ } 86b7b23e44SLinus Walleij }; 87b7b23e44SLinus Walleij MODULE_DEVICE_TABLE(of, s6e63m0_spi_of_match); 88b7b23e44SLinus Walleij 89b7b23e44SLinus Walleij static struct spi_driver s6e63m0_spi_driver = { 90b7b23e44SLinus Walleij .probe = s6e63m0_spi_probe, 91b7b23e44SLinus Walleij .remove = s6e63m0_spi_remove, 92b7b23e44SLinus Walleij .driver = { 93b7b23e44SLinus Walleij .name = "panel-samsung-s6e63m0", 94b7b23e44SLinus Walleij .of_match_table = s6e63m0_spi_of_match, 95b7b23e44SLinus Walleij }, 96b7b23e44SLinus Walleij }; 97b7b23e44SLinus Walleij module_spi_driver(s6e63m0_spi_driver); 98b7b23e44SLinus Walleij 99b7b23e44SLinus Walleij MODULE_AUTHOR("Paweł Chmiel <pawel.mikolaj.chmiel@gmail.com>"); 100b7b23e44SLinus Walleij MODULE_DESCRIPTION("s6e63m0 LCD SPI Driver"); 101b7b23e44SLinus Walleij MODULE_LICENSE("GPL v2"); 102