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