Re: [PATCH v7] drm/panel: Add a driver for the TPO TPG110

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




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




[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux