File Index
Files and directories
Sign in
FILE

panel-renesas-r69328.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/panel/panel-renesas-r69328.c C
  1// SPDX-License-Identifier: GPL-2.0
  2
  3#include <linux/array_size.h>
  4#include <linux/delay.h>
  5#include <linux/err.h>
  6#include <linux/gpio/consumer.h>
  7#include <linux/mod_devicetable.h>
  8#include <linux/module.h>
  9#include <linux/property.h>
 10#include <linux/regulator/consumer.h>
 11
 12#include <video/mipi_display.h>
 13
 14#include <drm/drm_mipi_dsi.h>
 15#include <drm/drm_modes.h>
 16#include <drm/drm_panel.h>
 17
 18#define R69328_MACP		0xb0 /* Manufacturer Access CMD Protect */
 19#define   R69328_MACP_ON	0x03
 20#define   R69328_MACP_OFF	0x04
 21
 22#define R69328_GAMMA_SET_A	0xc8 /* Gamma Setting A */
 23#define R69328_GAMMA_SET_B	0xc9 /* Gamma Setting B */
 24#define R69328_GAMMA_SET_C	0xca /* Gamma Setting C */
 25
 26#define R69328_POWER_SET	0xd1
 27
 28struct renesas_r69328 {
 29	struct drm_panel panel;
 30	struct mipi_dsi_device *dsi;
 31
 32	struct regulator *vdd_supply;
 33	struct regulator *vddio_supply;
 34	struct gpio_desc *reset_gpio;
 35
 36	bool prepared;
 37};
 38
 39static inline struct renesas_r69328 *to_renesas_r69328(struct drm_panel *panel)
 40{
 41	return container_of(panel, struct renesas_r69328, panel);
 42}
 43
 44static void renesas_r69328_reset(struct renesas_r69328 *priv)
 45{
 46	gpiod_set_value_cansleep(priv->reset_gpio, 1);
 47	usleep_range(10000, 11000);
 48	gpiod_set_value_cansleep(priv->reset_gpio, 0);
 49	usleep_range(2000, 3000);
 50}
 51
 52static int renesas_r69328_prepare(struct drm_panel *panel)
 53{
 54	struct renesas_r69328 *priv = to_renesas_r69328(panel);
 55	struct device *dev = &priv->dsi->dev;
 56	int ret;
 57
 58	if (priv->prepared)
 59		return 0;
 60
 61	ret = regulator_enable(priv->vdd_supply);
 62	if (ret) {
 63		dev_err(dev, "failed to enable vdd power supply\n");
 64		return ret;
 65	}
 66
 67	usleep_range(10000, 11000);
 68
 69	ret = regulator_enable(priv->vddio_supply);
 70	if (ret < 0) {
 71		dev_err(dev, "failed to enable vddio power supply\n");
 72		return ret;
 73	}
 74
 75	usleep_range(10000, 11000);
 76
 77	renesas_r69328_reset(priv);
 78
 79	priv->prepared = true;
 80	return 0;
 81}
 82
 83static int renesas_r69328_enable(struct drm_panel *panel)
 84{
 85	struct renesas_r69328 *priv = to_renesas_r69328(panel);
 86	struct mipi_dsi_multi_context ctx = { .dsi = priv->dsi };
 87
 88	/* Set address mode */
 89	mipi_dsi_dcs_write_seq_multi(&ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x00);
 90	mipi_dsi_dcs_set_pixel_format_multi(&ctx, MIPI_DCS_PIXEL_FMT_24BIT << 4);
 91	mipi_dsi_dcs_exit_sleep_mode_multi(&ctx);
 92
 93	mipi_dsi_msleep(&ctx, 100);
 94
 95	/* MACP Off */
 96	mipi_dsi_generic_write_seq_multi(&ctx, R69328_MACP, R69328_MACP_OFF);
 97
 98	mipi_dsi_generic_write_seq_multi(&ctx, R69328_POWER_SET, 0x14, 0x1d,
 99					 0x21, 0x67, 0x11, 0x9a);
100
101	mipi_dsi_generic_write_seq_multi(&ctx, R69328_GAMMA_SET_A, 0x00, 0x1a,
102					 0x20, 0x28, 0x25, 0x24, 0x26, 0x15, 0x13,
103					 0x11, 0x18, 0x1e, 0x1c, 0x00, 0x00, 0x1a,
104					 0x20, 0x28, 0x25, 0x24, 0x26, 0x15, 0x13,
105					 0x11, 0x18, 0x1e, 0x1c, 0x00);
106
107	mipi_dsi_generic_write_seq_multi(&ctx, R69328_GAMMA_SET_B, 0x00, 0x1a,
108					 0x20, 0x28, 0x25, 0x24, 0x26, 0x15, 0x13,
109					 0x11, 0x18, 0x1e, 0x1c, 0x00, 0x00, 0x1a,
110					 0x20, 0x28, 0x25, 0x24, 0x26, 0x15, 0x13,
111					 0x11, 0x18, 0x1e, 0x1c, 0x00);
112
113	mipi_dsi_generic_write_seq_multi(&ctx, R69328_GAMMA_SET_C, 0x00, 0x1a,
114					 0x20, 0x28, 0x25, 0x24, 0x26, 0x15, 0x13,
115					 0x11, 0x18, 0x1e, 0x1c, 0x00, 0x00, 0x1a,
116					 0x20, 0x28, 0x25, 0x24, 0x26, 0x15, 0x13,
117					 0x11, 0x18, 0x1e, 0x1c, 0x00);
118
119	/* MACP On */
120	mipi_dsi_generic_write_seq_multi(&ctx, R69328_MACP, R69328_MACP_ON);
121
122	mipi_dsi_dcs_set_display_on_multi(&ctx);
123	mipi_dsi_msleep(&ctx, 50);
124
125	return 0;
126}
127
128static int renesas_r69328_disable(struct drm_panel *panel)
129{
130	struct renesas_r69328 *priv = to_renesas_r69328(panel);
131	struct mipi_dsi_multi_context ctx = { .dsi = priv->dsi };
132
133	mipi_dsi_dcs_set_display_off_multi(&ctx);
134	mipi_dsi_msleep(&ctx, 60);
135	mipi_dsi_dcs_enter_sleep_mode_multi(&ctx);
136
137	return 0;
138}
139
140static int renesas_r69328_unprepare(struct drm_panel *panel)
141{
142	struct renesas_r69328 *priv = to_renesas_r69328(panel);
143
144	if (!priv->prepared)
145		return 0;
146
147	gpiod_set_value_cansleep(priv->reset_gpio, 1);
148
149	usleep_range(5000, 6000);
150
151	regulator_disable(priv->vddio_supply);
152	regulator_disable(priv->vdd_supply);
153
154	priv->prepared = false;
155	return 0;
156}
157
158static const struct drm_display_mode renesas_r69328_mode = {
159	.clock = (720 + 92 + 62 + 4) * (1280 + 6 + 3 + 1) * 60 / 1000,
160	.hdisplay = 720,
161	.hsync_start = 720 + 92,
162	.hsync_end = 720 + 92 + 62,
163	.htotal = 720 + 92 + 62 + 4,
164	.vdisplay = 1280,
165	.vsync_start = 1280 + 6,
166	.vsync_end = 1280 + 6 + 3,
167	.vtotal = 1280 + 6 + 3 + 1,
168	.width_mm = 59,
169	.height_mm = 105,
170};
171
172static int renesas_r69328_get_modes(struct drm_panel *panel,
173				    struct drm_connector *connector)
174{
175	struct drm_display_mode *mode;
176
177	mode = drm_mode_duplicate(connector->dev, &renesas_r69328_mode);
178	if (!mode)
179		return -ENOMEM;
180
181	drm_mode_set_name(mode);
182
183	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
184	connector->display_info.width_mm = mode->width_mm;
185	connector->display_info.height_mm = mode->height_mm;
186	drm_mode_probed_add(connector, mode);
187
188	return 1;
189}
190
191static const struct drm_panel_funcs renesas_r69328_panel_funcs = {
192	.prepare = renesas_r69328_prepare,
193	.enable = renesas_r69328_enable,
194	.disable = renesas_r69328_disable,
195	.unprepare = renesas_r69328_unprepare,
196	.get_modes = renesas_r69328_get_modes,
197};
198
199static int renesas_r69328_probe(struct mipi_dsi_device *dsi)
200{
201	struct device *dev = &dsi->dev;
202	struct renesas_r69328 *priv;
203	int ret;
204
205	priv = devm_drm_panel_alloc(dev, struct renesas_r69328, panel,
206				    &renesas_r69328_panel_funcs,
207				    DRM_MODE_CONNECTOR_DSI);
208	if (IS_ERR(priv))
209		return PTR_ERR(priv);
210
211	priv->vdd_supply = devm_regulator_get(dev, "vdd");
212	if (IS_ERR(priv->vdd_supply))
213		return dev_err_probe(dev, PTR_ERR(priv->vdd_supply),
214				     "Failed to get vdd-supply\n");
215
216	priv->vddio_supply = devm_regulator_get(dev, "vddio");
217	if (IS_ERR(priv->vddio_supply))
218		return dev_err_probe(dev, PTR_ERR(priv->vddio_supply),
219				     "Failed to get vddio-supply\n");
220
221	priv->reset_gpio = devm_gpiod_get_optional(dev, "reset",
222						   GPIOD_OUT_LOW);
223	if (IS_ERR(priv->reset_gpio))
224		return dev_err_probe(dev, PTR_ERR(priv->reset_gpio),
225				     "Failed to get reset-gpios\n");
226
227	priv->dsi = dsi;
228	mipi_dsi_set_drvdata(dsi, priv);
229
230	dsi->lanes = 4;
231	dsi->format = MIPI_DSI_FMT_RGB888;
232	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
233			  MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM;
234
235	ret = drm_panel_of_backlight(&priv->panel);
236	if (ret)
237		return dev_err_probe(dev, ret, "Failed to get backlight\n");
238
239	drm_panel_add(&priv->panel);
240
241	ret = mipi_dsi_attach(dsi);
242	if (ret) {
243		drm_panel_remove(&priv->panel);
244		return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
245	}
246
247	return 0;
248}
249
250static void renesas_r69328_remove(struct mipi_dsi_device *dsi)
251{
252	struct renesas_r69328 *priv = mipi_dsi_get_drvdata(dsi);
253	int ret;
254
255	ret = mipi_dsi_detach(dsi);
256	if (ret)
257		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
258
259	drm_panel_remove(&priv->panel);
260}
261
262static const struct of_device_id renesas_r69328_of_match[] = {
263	{ .compatible = "jdi,dx12d100vm0eaa" },
264	{ /* sentinel */ }
265};
266MODULE_DEVICE_TABLE(of, renesas_r69328_of_match);
267
268static struct mipi_dsi_driver renesas_r69328_driver = {
269	.probe = renesas_r69328_probe,
270	.remove = renesas_r69328_remove,
271	.driver = {
272		.name = "panel-renesas-r69328",
273		.of_match_table = renesas_r69328_of_match,
274	},
275};
276module_mipi_dsi_driver(renesas_r69328_driver);
277
278MODULE_AUTHOR("Maxim Schwalm <maxim.schwalm@gmail.com>");
279MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>");
280MODULE_DESCRIPTION("Renesas R69328-based panel driver");
281MODULE_LICENSE("GPL");
~/ Read-only file preview.