1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Maxim MAX96752F GMSL2 Deserializer 4 * 5 * (C) Copyright 2022 Rockchip Electronics Co., Ltd 6 */ 7 8 #include <config.h> 9 #include <common.h> 10 #include <backlight.h> 11 #include <errno.h> 12 #include <malloc.h> 13 #include <video.h> 14 15 #include <asm/gpio.h> 16 #include <dm/device.h> 17 #include <dm/read.h> 18 #include <dm/pinctrl.h> 19 #include <dm/uclass-id.h> 20 #include <linux/media-bus-format.h> 21 22 #include "rockchip_display.h" 23 #include "rockchip_panel.h" 24 25 struct max96752f; 26 27 struct panel_desc { 28 const char *name; 29 int (*prepare)(struct max96752f *max96752f); 30 int (*unprepare)(struct max96752f *max96752f); 31 int (*enable)(struct max96752f *max96752f); 32 int (*disable)(struct max96752f *max96752f); 33 int (*backlight_enable)(struct max96752f *max96752f); 34 int (*backlight_disable)(struct max96752f *max96752f); 35 }; 36 37 struct max96752f { 38 struct udevice *dev; 39 struct udevice *serializer; 40 struct udevice *backlight; 41 42 const struct panel_desc *desc; 43 }; 44 45 static void max96752f_panel_prepare(struct rockchip_panel *panel) 46 { 47 struct max96752f *max96752f = dev_get_priv(panel->dev); 48 const struct panel_desc *desc = max96752f->desc; 49 50 if (desc->prepare) 51 desc->prepare(max96752f); 52 } 53 54 static void max96752f_panel_unprepare(struct rockchip_panel *panel) 55 { 56 struct max96752f *max96752f = dev_get_priv(panel->dev); 57 const struct panel_desc *desc = max96752f->desc; 58 59 if (desc->unprepare) 60 desc->unprepare(max96752f); 61 } 62 63 static void max96752f_panel_enable(struct rockchip_panel *panel) 64 { 65 struct max96752f *max96752f = dev_get_priv(panel->dev); 66 const struct panel_desc *desc = max96752f->desc; 67 68 if (desc->enable) 69 desc->enable(max96752f); 70 71 if (max96752f->backlight) 72 backlight_enable(max96752f->backlight); 73 74 if (desc->backlight_enable) 75 desc->backlight_enable(max96752f); 76 } 77 78 static void max96752f_panel_disable(struct rockchip_panel *panel) 79 { 80 struct max96752f *max96752f = dev_get_priv(panel->dev); 81 const struct panel_desc *desc = max96752f->desc; 82 83 if (desc->backlight_disable) 84 desc->backlight_disable(max96752f); 85 86 if (max96752f->backlight) 87 backlight_disable(max96752f->backlight); 88 89 if (desc->disable) 90 desc->disable(max96752f); 91 } 92 93 static const struct rockchip_panel_funcs max96752f_panel_funcs = { 94 .prepare = max96752f_panel_prepare, 95 .unprepare = max96752f_panel_unprepare, 96 .enable = max96752f_panel_enable, 97 .disable = max96752f_panel_disable, 98 }; 99 100 static int max96752f_probe(struct udevice *dev) 101 { 102 struct max96752f *max96752f = dev_get_priv(dev); 103 struct rockchip_panel *panel; 104 int ret; 105 106 ret = i2c_set_chip_offset_len(dev, 2); 107 if (ret) 108 return ret; 109 110 max96752f->dev = dev; 111 max96752f->serializer = dev->parent->parent; 112 max96752f->desc = (const struct panel_desc *)dev_get_driver_data(dev); 113 114 ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev, 115 "backlight", &max96752f->backlight); 116 if (ret && ret != -ENOENT) { 117 dev_err(dev, "%s: Cannot get backlight: %d\n", __func__, ret); 118 return ret; 119 } 120 121 panel = calloc(1, sizeof(*panel)); 122 if (!panel) 123 return -ENOMEM; 124 125 dev->driver_data = (ulong)panel; 126 panel->dev = dev; 127 panel->bus_format = MEDIA_BUS_FMT_RGB888_1X24; 128 panel->funcs = &max96752f_panel_funcs; 129 130 return 0; 131 } 132 133 #define maxim_serializer_write(max96752f, reg, val) do { \ 134 int ret; \ 135 ret = dm_i2c_reg_write(max96752f->serializer, \ 136 reg, val); \ 137 if (ret) \ 138 return ret; \ 139 } while (0) 140 141 #define maxim_deserializer_write(max96752f, reg, val) do { \ 142 int ret; \ 143 ret = dm_i2c_reg_write(max96752f->dev, \ 144 reg, val); \ 145 if (ret) \ 146 return ret; \ 147 } while (0) 148 149 static int boe_av156fht_l83_panel_prepare(struct max96752f *max96752f) 150 { 151 maxim_deserializer_write(max96752f, 0x0002, 0x43); 152 maxim_deserializer_write(max96752f, 0x0140, 0x20); 153 154 maxim_deserializer_write(max96752f, 0x01ce, 0x5e); /* oldi */ 155 maxim_deserializer_write(max96752f, 0x020c, 0x84); /* bl_pwm */ 156 maxim_deserializer_write(max96752f, 0x0206, 0x83); /* tp_int */ 157 158 maxim_deserializer_write(max96752f, 0x0215, 0x90); /* lcd_en */ 159 mdelay(20); 160 161 return 0; 162 } 163 164 static int boe_av156fht_l83_panel_unprepare(struct max96752f *max96752f) 165 { 166 maxim_deserializer_write(max96752f, 0x0215, 0x80); /* lcd_en */ 167 168 return 0; 169 } 170 171 static int boe_av156fht_l83_panel_enable(struct max96752f *max96752f) 172 { 173 maxim_deserializer_write(max96752f, 0x0227, 0x90); /* lcd_rst */ 174 mdelay(20); 175 maxim_deserializer_write(max96752f, 0x020f, 0x90); /* tp_rst */ 176 mdelay(100); 177 maxim_deserializer_write(max96752f, 0x0221, 0x90); /* lcd_stb */ 178 mdelay(60); 179 maxim_deserializer_write(max96752f, 0x0212, 0x90); /* bl_current_ctl */ 180 maxim_deserializer_write(max96752f, 0x0209, 0x90); /* bl_en */ 181 182 return 0; 183 } 184 185 static int boe_av156fht_l83_panel_disable(struct max96752f *max96752f) 186 { 187 maxim_deserializer_write(max96752f, 0x0209, 0x80); /* bl_en */ 188 maxim_deserializer_write(max96752f, 0x0212, 0x80); /* bl_current_ctl */ 189 maxim_deserializer_write(max96752f, 0x0221, 0x80); /* lcd_stb */ 190 maxim_deserializer_write(max96752f, 0x020f, 0x80); /* tp_rst */ 191 maxim_deserializer_write(max96752f, 0x0227, 0x80); /* lcd_rst */ 192 193 return 0; 194 } 195 196 static int boe_av156fht_l83_panel_backlight_enable(struct max96752f *max96752f) 197 { 198 maxim_deserializer_write(max96752f, 0x0212, 0x90); /* bl_current_ctl */ 199 maxim_deserializer_write(max96752f, 0x0209, 0x90); /* bl_en */ 200 201 return 0; 202 } 203 204 static int boe_av156fht_l83_panel_backlight_disable(struct max96752f *max96752f) 205 { 206 maxim_deserializer_write(max96752f, 0x0209, 0x80); /* bl_en */ 207 maxim_deserializer_write(max96752f, 0x0212, 0x80); /* bl_current_ctl */ 208 209 return 0; 210 } 211 212 static const struct panel_desc boe_av156fht_l83 = { 213 .name = "boe-av156fht-l83", 214 .prepare = boe_av156fht_l83_panel_prepare, 215 .unprepare = boe_av156fht_l83_panel_unprepare, 216 .enable = boe_av156fht_l83_panel_enable, 217 .disable = boe_av156fht_l83_panel_disable, 218 .backlight_enable = boe_av156fht_l83_panel_backlight_enable, 219 .backlight_disable = boe_av156fht_l83_panel_backlight_disable, 220 }; 221 222 static int hannstar_hsd123jpw3_a15_prepare(struct max96752f *max96752f) 223 { 224 maxim_deserializer_write(max96752f, 0x0002, 0x43); 225 maxim_deserializer_write(max96752f, 0x0140, 0x20); 226 maxim_deserializer_write(max96752f, 0x01ce, 0x5e); 227 228 maxim_deserializer_write(max96752f, 0x0203, 0x83); /* GPIO1 <- TP_INT */ 229 maxim_deserializer_write(max96752f, 0x0206, 0x84); /* GPIO2 -> TP_RST */ 230 maxim_deserializer_write(max96752f, 0x0224, 0x84); /* GPIO12 -> LCD_BL_PWM */ 231 232 return 0; 233 } 234 235 static int hannstar_hsd123jpw3_a15_unprepare(struct max96752f *max96752f) 236 { 237 return 0; 238 } 239 240 static int hannstar_hsd123jpw3_a15_enable(struct max96752f *max96752f) 241 { 242 maxim_deserializer_write(max96752f, 0x0221, 0x10); /* GPIO11 -> LCD_RESET */ 243 mdelay(20); 244 245 return 0; 246 } 247 248 static int hannstar_hsd123jpw3_a15_disable(struct max96752f *max96752f) 249 { 250 maxim_deserializer_write(max96752f, 0x0221, 0x00); /* GPIO11 -> LCD_RESET */ 251 mdelay(20); 252 253 return 0; 254 } 255 256 static const struct panel_desc hannstar_hsd123jpw3_a15 = { 257 .name = "hannstar,hsd123jpw3-a15", 258 .prepare = hannstar_hsd123jpw3_a15_prepare, 259 .unprepare = hannstar_hsd123jpw3_a15_unprepare, 260 .enable = hannstar_hsd123jpw3_a15_enable, 261 .disable = hannstar_hsd123jpw3_a15_disable, 262 }; 263 264 static int ogm_101fhbllm01_prepare(struct max96752f *max96752f) 265 { 266 maxim_deserializer_write(max96752f, 0x01ce, 0x5e); 267 268 maxim_deserializer_write(max96752f, 0x0203, 0x84); /* GPIO1 -> BL_PWM */ 269 maxim_deserializer_write(max96752f, 0x0206, 0x84); /* GPIO2 -> TP_RST */ 270 maxim_deserializer_write(max96752f, 0x0209, 0x83); /* GPIO3 <- TP_INT */ 271 272 maxim_deserializer_write(max96752f, 0x0001, 0x02); 273 274 return 0; 275 } 276 277 static int ogm_101fhbllm01_unprepare(struct max96752f *max96752f) 278 { 279 maxim_deserializer_write(max96752f, 0x0001, 0x01); 280 281 return 0; 282 } 283 284 static const struct panel_desc ogm_101fhbllm01 = { 285 .name = "ogm,101fhbllm01", 286 .prepare = ogm_101fhbllm01_prepare, 287 .unprepare = ogm_101fhbllm01_unprepare, 288 }; 289 290 static const struct udevice_id max96752f_of_match[] = { 291 { .compatible = "boe,av156fht-l83", .data = (ulong)&boe_av156fht_l83 }, 292 { .compatible = "hannstar,hsd123jpw3-a15", .data = (ulong)&hannstar_hsd123jpw3_a15 }, 293 { .compatible = "ogm,101fhbllm01", .data = (ulong)&ogm_101fhbllm01 }, 294 {} 295 }; 296 297 U_BOOT_DRIVER(max96752f) = { 298 .name = "max96752f", 299 .id = UCLASS_PANEL, 300 .of_match = max96752f_of_match, 301 .probe = max96752f_probe, 302 .priv_auto_alloc_size = sizeof(struct max96752f), 303 }; 304