xref: /linux/drivers/gpu/drm/tiny/ili9163.c (revision 9acb51e9617c28a92f9ce2af767db6bd660a6d4f)
1  // SPDX-License-Identifier: GPL-2.0+
2  
3  #include <linux/backlight.h>
4  #include <linux/delay.h>
5  #include <linux/gpio/consumer.h>
6  #include <linux/module.h>
7  #include <linux/property.h>
8  #include <linux/spi/spi.h>
9  
10  #include <drm/drm_atomic_helper.h>
11  #include <drm/drm_drv.h>
12  #include <drm/drm_fbdev_dma.h>
13  #include <drm/drm_gem_atomic_helper.h>
14  #include <drm/drm_gem_dma_helper.h>
15  #include <drm/drm_mipi_dbi.h>
16  #include <drm/drm_modeset_helper.h>
17  
18  #include <video/mipi_display.h>
19  
20  #define ILI9163_FRMCTR1		0xb1
21  
22  #define ILI9163_PWCTRL1		0xc0
23  #define ILI9163_PWCTRL2		0xc1
24  #define ILI9163_VMCTRL1		0xc5
25  #define ILI9163_VMCTRL2		0xc7
26  #define ILI9163_PWCTRLA		0xcb
27  #define ILI9163_PWCTRLB		0xcf
28  
29  #define ILI9163_EN3GAM		0xf2
30  
31  #define ILI9163_MADCTL_BGR	BIT(3)
32  #define ILI9163_MADCTL_MV	BIT(5)
33  #define ILI9163_MADCTL_MX	BIT(6)
34  #define ILI9163_MADCTL_MY	BIT(7)
35  
36  static void yx240qv29_enable(struct drm_simple_display_pipe *pipe,
37  			     struct drm_crtc_state *crtc_state,
38  			     struct drm_plane_state *plane_state)
39  {
40  	struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev);
41  	struct mipi_dbi *dbi = &dbidev->dbi;
42  	u8 addr_mode;
43  	int ret, idx;
44  
45  	if (!drm_dev_enter(pipe->crtc.dev, &idx))
46  		return;
47  
48  	DRM_DEBUG_KMS("\n");
49  
50  	ret = mipi_dbi_poweron_conditional_reset(dbidev);
51  	if (ret < 0)
52  		goto out_exit;
53  	if (ret == 1)
54  		goto out_enable;
55  
56  	/* Gamma */
57  	mipi_dbi_command(dbi, MIPI_DCS_SET_GAMMA_CURVE, 0x04);
58  	mipi_dbi_command(dbi, ILI9163_EN3GAM, 0x00);
59  
60  	/* Frame Rate */
61  	mipi_dbi_command(dbi, ILI9163_FRMCTR1, 0x0a, 0x14);
62  
63  	/* Power Control */
64  	mipi_dbi_command(dbi, ILI9163_PWCTRL1, 0x0a, 0x00);
65  	mipi_dbi_command(dbi, ILI9163_PWCTRL2, 0x02);
66  
67  	/* VCOM */
68  	mipi_dbi_command(dbi, ILI9163_VMCTRL1, 0x2f, 0x3e);
69  	mipi_dbi_command(dbi, ILI9163_VMCTRL2, 0x40);
70  
71  	/* Memory Access Control */
72  	mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT);
73  
74  	mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
75  	msleep(100);
76  
77  	mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
78  	msleep(100);
79  
80  out_enable:
81  	switch (dbidev->rotation) {
82  	default:
83  		addr_mode = ILI9163_MADCTL_MX | ILI9163_MADCTL_MY;
84  		break;
85  	case 90:
86  		addr_mode = ILI9163_MADCTL_MX | ILI9163_MADCTL_MV;
87  		break;
88  	case 180:
89  		addr_mode = 0;
90  		break;
91  	case 270:
92  		addr_mode = ILI9163_MADCTL_MY | ILI9163_MADCTL_MV;
93  		break;
94  	}
95  	addr_mode |= ILI9163_MADCTL_BGR;
96  	mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
97  	mipi_dbi_enable_flush(dbidev, crtc_state, plane_state);
98  out_exit:
99  	drm_dev_exit(idx);
100  }
101  
102  static const struct drm_simple_display_pipe_funcs ili9163_pipe_funcs = {
103  	DRM_MIPI_DBI_SIMPLE_DISPLAY_PIPE_FUNCS(yx240qv29_enable),
104  };
105  
106  static const struct drm_display_mode yx240qv29_mode = {
107  	DRM_SIMPLE_MODE(128, 160, 28, 35),
108  };
109  
110  DEFINE_DRM_GEM_DMA_FOPS(ili9163_fops);
111  
112  static struct drm_driver ili9163_driver = {
113  	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
114  	.fops			= &ili9163_fops,
115  	DRM_GEM_DMA_DRIVER_OPS_VMAP,
116  	.debugfs_init		= mipi_dbi_debugfs_init,
117  	.name			= "ili9163",
118  	.desc			= "Ilitek ILI9163",
119  	.date			= "20210208",
120  	.major			= 1,
121  	.minor			= 0,
122  };
123  
124  static const struct of_device_id ili9163_of_match[] = {
125  	{ .compatible = "newhaven,1.8-128160EF" },
126  	{ }
127  };
128  MODULE_DEVICE_TABLE(of, ili9163_of_match);
129  
130  static const struct spi_device_id ili9163_id[] = {
131  	{ "nhd-1.8-128160EF", 0 },
132  	{ }
133  };
134  MODULE_DEVICE_TABLE(spi, ili9163_id);
135  
136  static int ili9163_probe(struct spi_device *spi)
137  {
138  	struct device *dev = &spi->dev;
139  	struct mipi_dbi_dev *dbidev;
140  	struct drm_device *drm;
141  	struct mipi_dbi *dbi;
142  	struct gpio_desc *dc;
143  	u32 rotation = 0;
144  	int ret;
145  
146  	dbidev = devm_drm_dev_alloc(dev, &ili9163_driver,
147  				    struct mipi_dbi_dev, drm);
148  	if (IS_ERR(dbidev))
149  		return PTR_ERR(dbidev);
150  
151  	dbi = &dbidev->dbi;
152  	drm = &dbidev->drm;
153  
154  	spi_set_drvdata(spi, drm);
155  
156  	dbi->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
157  	if (IS_ERR(dbi->reset)) {
158  		DRM_DEV_ERROR(dev, "Failed to get gpio 'reset'\n");
159  		return PTR_ERR(dbi->reset);
160  	}
161  
162  	dc = devm_gpiod_get_optional(dev, "dc", GPIOD_OUT_LOW);
163  	if (IS_ERR(dc)) {
164  		DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n");
165  		return PTR_ERR(dc);
166  	}
167  
168  	dbidev->backlight = devm_of_find_backlight(dev);
169  	if (IS_ERR(dbidev->backlight))
170  		return PTR_ERR(dbidev->backlight);
171  
172  	device_property_read_u32(dev, "rotation", &rotation);
173  
174  	ret = mipi_dbi_spi_init(spi, dbi, dc);
175  	if (ret)
176  		return ret;
177  
178  	ret = mipi_dbi_dev_init(dbidev, &ili9163_pipe_funcs, &yx240qv29_mode, rotation);
179  	if (ret)
180  		return ret;
181  
182  	drm_mode_config_reset(drm);
183  
184  	ret = drm_dev_register(drm, 0);
185  	if (ret)
186  		return ret;
187  
188  	drm_fbdev_dma_setup(drm, 0);
189  
190  	return 0;
191  }
192  
193  static void ili9163_remove(struct spi_device *spi)
194  {
195  	struct drm_device *drm = spi_get_drvdata(spi);
196  
197  	drm_dev_unplug(drm);
198  	drm_atomic_helper_shutdown(drm);
199  }
200  
201  static void ili9163_shutdown(struct spi_device *spi)
202  {
203  	drm_atomic_helper_shutdown(spi_get_drvdata(spi));
204  }
205  
206  static struct spi_driver ili9163_spi_driver = {
207  	.driver = {
208  		.name = "ili9163",
209  		.of_match_table = ili9163_of_match,
210  	},
211  	.id_table = ili9163_id,
212  	.probe = ili9163_probe,
213  	.remove = ili9163_remove,
214  	.shutdown = ili9163_shutdown,
215  };
216  module_spi_driver(ili9163_spi_driver);
217  
218  MODULE_DESCRIPTION("Ilitek ILI9163 DRM driver");
219  MODULE_AUTHOR("Daniel Mack <daniel@zonque.org>");
220  MODULE_LICENSE("GPL");
221