Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/panel: p079zca: Refactor panel driver to support multiple panels

Refactor Innolux P079ZCA panel driver, let it support multi panels from
Innolux that share similar power sequences.

Panels may require different power supplies so use regulator bulk
interfaces and define per panel supply-names.

Changes in v2:
- Change regulator property name to meet the panel datasheet
Changes in v3:
- this patch only refactor P079ZCA panel to support multi panel,
support P097PFG panel in another patch
Changes in v4:
- Modify the patch which suggest by Thierry
Changes in v5:
- use regulator_bulk to handle different supply number

Signed-off-by: Lin Huang <hl@rock-chips.com>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Thierry Reding <treding@nvidia.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180702102721.3546-2-heiko@sntech.de

authored by

Lin Huang and committed by
Thierry Reding
7ad4e463 3d5664f9

+102 -41
+102 -41
drivers/gpu/drm/panel/panel-innolux-p079zca.c
··· 20 20 21 21 #include <video/mipi_display.h> 22 22 23 + struct panel_desc { 24 + const struct drm_display_mode *mode; 25 + unsigned int bpc; 26 + struct { 27 + unsigned int width; 28 + unsigned int height; 29 + } size; 30 + 31 + unsigned long flags; 32 + enum mipi_dsi_pixel_format format; 33 + unsigned int lanes; 34 + const char * const *supply_names; 35 + unsigned int num_supplies; 36 + }; 37 + 23 38 struct innolux_panel { 24 39 struct drm_panel base; 25 40 struct mipi_dsi_device *link; 41 + const struct panel_desc *desc; 26 42 27 43 struct backlight_device *backlight; 28 - struct regulator *supply; 44 + struct regulator_bulk_data *supplies; 45 + unsigned int num_supplies; 29 46 struct gpio_desc *enable_gpio; 30 47 31 48 bool prepared; ··· 94 77 /* T8: 80ms - 1000ms */ 95 78 msleep(80); 96 79 97 - err = regulator_disable(innolux->supply); 80 + err = regulator_bulk_disable(innolux->desc->num_supplies, 81 + innolux->supplies); 98 82 if (err < 0) 99 83 return err; 100 84 ··· 107 89 static int innolux_panel_prepare(struct drm_panel *panel) 108 90 { 109 91 struct innolux_panel *innolux = to_innolux_panel(panel); 110 - int err, regulator_err; 92 + int err; 111 93 112 94 if (innolux->prepared) 113 95 return 0; 114 96 115 97 gpiod_set_value_cansleep(innolux->enable_gpio, 0); 116 98 117 - err = regulator_enable(innolux->supply); 99 + err = regulator_bulk_enable(innolux->desc->num_supplies, 100 + innolux->supplies); 118 101 if (err < 0) 119 102 return err; 120 103 ··· 152 133 return 0; 153 134 154 135 poweroff: 155 - regulator_err = regulator_disable(innolux->supply); 156 - if (regulator_err) 157 - DRM_DEV_ERROR(panel->dev, "failed to disable regulator: %d\n", 158 - regulator_err); 159 - 160 136 gpiod_set_value_cansleep(innolux->enable_gpio, 0); 137 + regulator_bulk_disable(innolux->desc->num_supplies, innolux->supplies); 138 + 161 139 return err; 162 140 } 163 141 ··· 178 162 return 0; 179 163 } 180 164 181 - static const struct drm_display_mode default_mode = { 165 + static const char * const innolux_p079zca_supply_names[] = { 166 + "power", 167 + }; 168 + 169 + static const struct drm_display_mode innolux_p079zca_mode = { 182 170 .clock = 56900, 183 171 .hdisplay = 768, 184 172 .hsync_start = 768 + 40, ··· 195 175 .vrefresh = 60, 196 176 }; 197 177 178 + static const struct panel_desc innolux_p079zca_panel_desc = { 179 + .mode = &innolux_p079zca_mode, 180 + .bpc = 8, 181 + .size = { 182 + .width = 120, 183 + .height = 160, 184 + }, 185 + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | 186 + MIPI_DSI_MODE_LPM, 187 + .format = MIPI_DSI_FMT_RGB888, 188 + .lanes = 4, 189 + .supply_names = innolux_p079zca_supply_names, 190 + .num_supplies = ARRAY_SIZE(innolux_p079zca_supply_names), 191 + }; 192 + 198 193 static int innolux_panel_get_modes(struct drm_panel *panel) 199 194 { 195 + struct innolux_panel *innolux = to_innolux_panel(panel); 196 + const struct drm_display_mode *m = innolux->desc->mode; 200 197 struct drm_display_mode *mode; 201 198 202 - mode = drm_mode_duplicate(panel->drm, &default_mode); 199 + mode = drm_mode_duplicate(panel->drm, m); 203 200 if (!mode) { 204 201 DRM_DEV_ERROR(panel->drm->dev, "failed to add mode %ux%ux@%u\n", 205 - default_mode.hdisplay, default_mode.vdisplay, 206 - default_mode.vrefresh); 202 + m->hdisplay, m->vdisplay, m->vrefresh); 207 203 return -ENOMEM; 208 204 } 209 205 ··· 227 191 228 192 drm_mode_probed_add(panel->connector, mode); 229 193 230 - panel->connector->display_info.width_mm = 120; 231 - panel->connector->display_info.height_mm = 160; 232 - panel->connector->display_info.bpc = 8; 194 + panel->connector->display_info.width_mm = 195 + innolux->desc->size.width; 196 + panel->connector->display_info.height_mm = 197 + innolux->desc->size.height; 198 + panel->connector->display_info.bpc = innolux->desc->bpc; 233 199 234 200 return 1; 235 201 } ··· 245 207 }; 246 208 247 209 static const struct of_device_id innolux_of_match[] = { 248 - { .compatible = "innolux,p079zca", }, 210 + { .compatible = "innolux,p079zca", 211 + .data = &innolux_p079zca_panel_desc 212 + }, 249 213 { } 250 214 }; 251 215 MODULE_DEVICE_TABLE(of, innolux_of_match); 252 216 253 - static int innolux_panel_add(struct innolux_panel *innolux) 217 + static int innolux_panel_add(struct mipi_dsi_device *dsi, 218 + const struct panel_desc *desc) 254 219 { 255 - struct device *dev = &innolux->link->dev; 256 - int err; 220 + struct innolux_panel *innolux; 221 + struct device *dev = &dsi->dev; 222 + int err, i; 257 223 258 - innolux->supply = devm_regulator_get(dev, "power"); 259 - if (IS_ERR(innolux->supply)) 260 - return PTR_ERR(innolux->supply); 224 + innolux = devm_kzalloc(dev, sizeof(*innolux), GFP_KERNEL); 225 + if (!innolux) 226 + return -ENOMEM; 227 + 228 + innolux->desc = desc; 229 + 230 + innolux->supplies = devm_kcalloc(dev, desc->num_supplies, 231 + sizeof(*innolux->supplies), 232 + GFP_KERNEL); 233 + if (!innolux->supplies) 234 + return -ENOMEM; 235 + 236 + for (i = 0; i < desc->num_supplies; i++) 237 + innolux->supplies[i].supply = desc->supply_names[i]; 238 + 239 + err = devm_regulator_bulk_get(dev, desc->num_supplies, 240 + innolux->supplies); 241 + if (err < 0) 242 + return err; 261 243 262 244 innolux->enable_gpio = devm_gpiod_get_optional(dev, "enable", 263 245 GPIOD_OUT_HIGH); ··· 288 230 } 289 231 290 232 innolux->backlight = devm_of_find_backlight(dev); 291 - 292 233 if (IS_ERR(innolux->backlight)) 293 234 return PTR_ERR(innolux->backlight); 294 235 295 236 drm_panel_init(&innolux->base); 296 237 innolux->base.funcs = &innolux_panel_funcs; 297 - innolux->base.dev = &innolux->link->dev; 238 + innolux->base.dev = dev; 298 239 299 - return drm_panel_add(&innolux->base); 240 + err = drm_panel_add(&innolux->base); 241 + if (err < 0) 242 + return err; 243 + 244 + mipi_dsi_set_drvdata(dsi, innolux); 245 + innolux->link = dsi; 246 + 247 + return 0; 300 248 } 301 249 302 250 static void innolux_panel_del(struct innolux_panel *innolux) ··· 313 249 314 250 static int innolux_panel_probe(struct mipi_dsi_device *dsi) 315 251 { 316 - struct innolux_panel *innolux; 252 + const struct panel_desc *desc; 253 + const struct of_device_id *id; 317 254 int err; 318 255 319 - dsi->lanes = 4; 320 - dsi->format = MIPI_DSI_FMT_RGB888; 321 - dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | 322 - MIPI_DSI_MODE_LPM; 256 + id = of_match_node(innolux_of_match, dsi->dev.of_node); 257 + if (!id) 258 + return -ENODEV; 323 259 324 - innolux = devm_kzalloc(&dsi->dev, sizeof(*innolux), GFP_KERNEL); 325 - if (!innolux) 326 - return -ENOMEM; 260 + desc = id->data; 261 + dsi->mode_flags = desc->flags; 262 + dsi->format = desc->format; 263 + dsi->lanes = desc->lanes; 327 264 328 - mipi_dsi_set_drvdata(dsi, innolux); 329 - 330 - innolux->link = dsi; 331 - 332 - err = innolux_panel_add(innolux); 265 + err = innolux_panel_add(dsi, desc); 333 266 if (err < 0) 334 267 return err; 335 268 336 - err = mipi_dsi_attach(dsi); 337 - return err; 269 + return mipi_dsi_attach(dsi); 338 270 } 339 271 340 272 static int innolux_panel_remove(struct mipi_dsi_device *dsi) ··· 377 317 module_mipi_dsi_driver(innolux_panel_driver); 378 318 379 319 MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>"); 320 + MODULE_AUTHOR("Lin Huang <hl@rock-chips.com>"); 380 321 MODULE_DESCRIPTION("Innolux P079ZCA panel driver"); 381 322 MODULE_LICENSE("GPL v2");