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