Den 10.01.2019 20.30, skrev Linus Walleij: > The TPO (Toppoly) TPG110 is a pretty generic display driver > similar in vein to the Ilitek 93xx devices. It is not a panel > per se but a driver used with several low-cost noname panels. > > This is used on the Nomadik NHK15 combined with a OSD > OSD057VA01CT display for WVGA 800x480. > > The driver is pretty minimalistic right now but can be > extended to handle non-default polarities, gamma correction > etc. > > The driver is based on the baked-in code in > drivers/video/fbdev/amba-clcd-nomadik.c which will be > decomissioned once this us upstream. > > Acked-by: Sam Ravnborg <sam@xxxxxxxxxxxx> > Signed-off-by: Linus Walleij <linus.walleij@xxxxxxxxxx> > --- > ChangeLog v6->v7: > - Drop the video mode helpers. > - Do not include <drm/drmP.h> but instead the granular APIs. > - Switch dev_info() and dev_err() for DRM_DEV_INFO() > and DRM_DEV_ERROR(). > - Switch mdelay(1) for usleep_range(1000,2000) so we don't > spin unecessarily during boot. > - Use DRM_DEV_DEBUG() for information about deasserted reset. > - Make a proper DRM_DEV_ERROR() for illegal resolution settings. > - Simplify the inlined backlight enable/disable code by using > the existing inline helpers. > - Add a few missing stray \n's > ChangeLog v5->v6: > - Collected Sam's ACK. > ChangeLog v4->v5: > - Assign proper bus_flags. > - This is now the only remaining patch. > ChangeLog v3->v4: > - Tag on the SPI_3WIRE_HIZ flag to the SPI slave mode. > ChangeLog v2->v3: > - Rewrite as an SPI child device. > --- <snip> > diff --git a/drivers/gpu/drm/panel/panel-tpo-tpg110.c b/drivers/gpu/drm/panel/panel-tpo-tpg110.c <snip> > +static int tpg110_disable(struct drm_panel *panel) > +{ > + struct tpg110 *tpg = to_tpg110(panel); > + u8 val; > + > + /* Put chip into standby */ > + val = tpg110_read_reg(tpg, TPG110_CTRL2_PM); > + val &= ~TPG110_CTRL2_PM; > + tpg110_write_reg(tpg, TPG110_CTRL2_PM, val); > + > + if (tpg->backlight) > + backlight_disable(tpg->backlight); backlight_disable() and backlight_enable() is NULL tolerant, so the conditional is not necessary. > + > + return 0; > +} > + > +static int tpg110_enable(struct drm_panel *panel) > +{ > + struct tpg110 *tpg = to_tpg110(panel); > + u8 val; > + > + if (tpg->backlight) > + backlight_enable(tpg->backlight); > + > + /* Take chip out of standby */ > + val = tpg110_read_reg(tpg, TPG110_CTRL2_PM); > + val |= TPG110_CTRL2_PM; > + tpg110_write_reg(tpg, TPG110_CTRL2_PM, val); > + > + return 0; > +} <snip> > +static int tpg110_probe(struct spi_device *spi) > +{ > + struct device *dev = &spi->dev; > + struct device_node *np = dev->of_node; > + struct device_node *backlight; > + struct tpg110 *tpg; > + int ret; > + > + tpg = devm_kzalloc(dev, sizeof(*tpg), GFP_KERNEL); > + if (!tpg) > + return -ENOMEM; > + tpg->dev = dev; > + > + /* We get the physical display dimensions from the DT */ > + ret = of_property_read_u32(np, "width-mm", &tpg->width); > + if (ret) > + DRM_DEV_ERROR(dev, "no panel width specified\n"); > + ret = of_property_read_u32(np, "height-mm", &tpg->height); > + if (ret) > + DRM_DEV_ERROR(dev, "no panel height specified\n"); > + > + /* Look for some optional backlight */ > + backlight = of_parse_phandle(np, "backlight", 0); > + if (backlight) { > + tpg->backlight = of_find_backlight_by_node(backlight); > + of_node_put(backlight); > + > + if (!tpg->backlight) > + return -EPROBE_DEFER; > + } You have forgotten to put the backlight device on device removal. Here's one way to fix it: tpg->backlight = devm_of_find_backlight(dev); if (IS_ERR(tpg->backlight)) return PTR_ERR(tpg->backlight); tpg->backlight will be NULL if there's no backlight node and -EPROBE_DEFER if the node is there but the device is not yet available. Noralf. > + > + /* This asserts the GRESTB signal, putting the display into reset */ > + tpg->grestb = devm_gpiod_get(dev, "grestb", GPIOD_OUT_HIGH); > + if (IS_ERR(tpg->grestb)) { > + DRM_DEV_ERROR(dev, "no GRESTB GPIO\n"); > + return -ENODEV; > + } > + > + spi->bits_per_word = 8; > + spi->mode |= SPI_3WIRE_HIZ; > + ret = spi_setup(spi); > + if (ret < 0) { > + DRM_DEV_ERROR(dev, "spi setup failed.\n"); > + return ret; > + } > + tpg->spi = spi; > + > + ret = tpg110_startup(tpg); > + if (ret) > + return ret; > + > + drm_panel_init(&tpg->panel); > + tpg->panel.dev = dev; > + tpg->panel.funcs = &tpg110_drm_funcs; > + spi_set_drvdata(spi, tpg); > + > + return drm_panel_add(&tpg->panel); > +} > + > +static int tpg110_remove(struct spi_device *spi) > +{ > + struct tpg110 *tpg = spi_get_drvdata(spi); > + > + drm_panel_remove(&tpg->panel); > + return 0; > +} > + > +static const struct of_device_id tpg110_match[] = { > + { .compatible = "tpo,tpg110", }, > + {}, > +}; > +MODULE_DEVICE_TABLE(of, tpg110_match); > + > +static struct spi_driver tpg110_driver = { > + .probe = tpg110_probe, > + .remove = tpg110_remove, > + .driver = { > + .name = "tpo-tpg110-panel", > + .of_match_table = tpg110_match, > + }, > +}; > +module_spi_driver(tpg110_driver); > + > +MODULE_AUTHOR("Linus Walleij <linus.walleij@xxxxxxxxxx>"); > +MODULE_DESCRIPTION("TPO TPG110 panel driver"); > +MODULE_LICENSE("GPL v2"); > _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel