dri-devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Thierry Reding <thierry.reding@gmail.com>
To: Hyungwon Hwang <human.hwang@samsung.com>
Cc: Sangbae Lee <sangbae90.lee@samsung.com>,
	Donghwa Lee <dh09.lee@samsung.com>,
	dri-devel@lists.freedesktop.org
Subject: Re: [PATCH v3] drm/panel: add s6e3ha2 AMOLED panel driver
Date: Tue, 3 Feb 2015 13:51:52 +0100	[thread overview]
Message-ID: <20150203125150.GD15068@ulmo.nvidia.com> (raw)
In-Reply-To: <1422323312-13306-1-git-send-email-human.hwang@samsung.com>


[-- Attachment #1.1: Type: text/plain, Size: 9077 bytes --]

On Tue, Jan 27, 2015 at 10:48:32AM +0900, Hyungwon Hwang wrote:
> From: Donghwa Lee <dh09.lee@samsung.com>
> 
> This patch adds MIPI-DSI based S6E3HA2 panel driver. This panel has
> 1440x2560 resolution in 5.7-inch physical panel.
> 
> Signed-off-by: Donghwa Lee <dh09.lee@samsung.com>
> Signed-off-by: Hyungwon Hwang <human.hwang@samsung.com>
> Cc: Inki Dae <inki.dae@samsung.com>
> Cc: Sangbae Lee <sangbae90.lee@samsung.com>
> ---
> Changes for v2:
> - Fix errata in documentation and source code comments
> Changes for v3:
> - Remove the term LCD to clarify the sort of this panel
> - Rename lcd-en-gpios to panel-en-gpios to clarify the sort of this panel
> - Fix errata in documentation and source code comments
>  .../devicetree/bindings/panel/samsung,s6e3ha2.txt  |  49 ++
>  drivers/gpu/drm/panel/Kconfig                      |   6 +
>  drivers/gpu/drm/panel/Makefile                     |   1 +
>  drivers/gpu/drm/panel/panel-s6e3ha2.c              | 513 +++++++++++++++++++++
>  4 files changed, 569 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/panel/samsung,s6e3ha2.txt
>  create mode 100644 drivers/gpu/drm/panel/panel-s6e3ha2.c
> 
> diff --git a/Documentation/devicetree/bindings/panel/samsung,s6e3ha2.txt b/Documentation/devicetree/bindings/panel/samsung,s6e3ha2.txt
> new file mode 100644
> index 0000000..5210926
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/panel/samsung,s6e3ha2.txt
> @@ -0,0 +1,49 @@
> +Samsung S6E3HA2 5.7" 1440x2560 AMOLED panel
> +
> +Required properties:
> +  - compatible: "samsung,s6e3ha2"
> +  - reg: the virtual channel number of a DSI peripheral
> +  - vdd3-supply: core voltage supply
> +  - vci-supply: voltage supply for analog circuits
> +  - reset-gpios: a GPIO spec for the reset pin
> +  - panel-en-gpios: a GPIO spec for the panel enable pin

Why not "enable-gpios"? That would be much more in line with the
reset-gpios property.

> +  - te-gpios: a GPIO spec for the tearing effect synchronization signal gpio pin

s/gpio/GPIO/

> +
> +Optional properties:
> +  - display-timings: timings for the connected panel as described by [1]
> +  - panel-width-mm: physical panel width [mm]
> +  - panel-height-mm: physical panel height [mm]

If these are optional, what happens if they aren't there? The panel is
not likely to work in that case.

Also I think these should be hard-coded in the driver, because they are
implied by the "compatible" string.

> +The device node can contain one 'port' child node with one child
> +'endpoint' node, according to the bindings defined in [2]. This
> +node should describe panel's video bus.

The example doesn't show how to use that, why is it necessary?

> diff --git a/drivers/gpu/drm/panel/panel-s6e3ha2.c b/drivers/gpu/drm/panel/panel-s6e3ha2.c
[...]
> +struct s6e3ha2 {
> +	struct device *dev;
> +	struct drm_panel panel;
> +
> +	struct regulator_bulk_data supplies[2];
> +	struct gpio_desc *reset_gpio;
> +	struct gpio_desc *panel_en_gpio;
> +	struct videomode vm;
> +	u32 width_mm;
> +	u32 height_mm;
> +
> +	/* This field is tested by functions directly accessing DSI bus before
> +	 * transfer, transfer is skipped if it is set. In case of transfer
> +	 * failure or unexpected response the field is set to error value.
> +	 * Such construct allows to eliminate many checks in higher level
> +	 * functions.
> +	 */
> +	int error;

I hate myself for not NAK'ing the first patch that introduced this idiom
stronger. I think it's a really bad concept and you're not doing
yourself any favours by using it.

> +static void s6e3ha2_te_start_setting(struct s6e3ha2 *ctx)
> +{
> +	s6e3ha2_dcs_write_seq_static(ctx, 0xb9, 0x10, 0x09, 0xff, 0x00, 0x09);
> +}
> +
> +

Gratuituous blank line.

> +static void s6e3ha2_panel_init(struct s6e3ha2 *ctx)
> +{
> +	s6e3ha2_dcs_write_seq_static(ctx, MIPI_DCS_EXIT_SLEEP_MODE);

We have a standard function for this, please use it.

> +	/* common setting */
> +	s6e3ha2_dcs_write_seq_static(ctx, MIPI_DCS_SET_TEAR_ON);

Same here.

> +	s6e3ha2_test_key_off_f0(ctx);
> +	s6e3ha2_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_ON);

And here.

> +static int s6e3ha2_unprepare(struct drm_panel *panel)
> +{
> +	struct s6e3ha2 *ctx = panel_to_s6e3ha2(panel);
> +
> +	s6e3ha2_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE);
> +	s6e3ha2_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_OFF);

More standard functions.

> +	msleep(40);
> +
> +	s6e3ha2_clear_error(ctx);
> +
> +	return s6e3ha2_power_off(ctx);
> +}
> +
> +static int s6e3ha2_power_on(struct s6e3ha2 *ctx)
> +{
> +	int ret;
> +
> +	ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
> +	if (ret < 0)
> +		return ret;
> +
> +	msleep(25);
> +
> +	gpiod_set_value(ctx->panel_en_gpio, 0);
> +	usleep_range(5000, 6000);
> +	gpiod_set_value(ctx->panel_en_gpio, 1);
> +
> +	gpiod_set_value(ctx->reset_gpio, 1);
> +	usleep_range(5000, 6000);
> +	gpiod_set_value(ctx->reset_gpio, 0);
> +	usleep_range(5000, 6000);
> +	gpiod_set_value(ctx->reset_gpio, 1);

I would expect the value after power on to be 0 for reset. Perhaps you
need GPIO_ACTIVE_LOW in your device tree? Also why do you toggle thrice?
I would assume that putting the peripheral into reset and taking it out
again would be enough.

> +static int s6e3ha2_prepare(struct drm_panel *panel)
> +{
> +	struct s6e3ha2 *ctx = panel_to_s6e3ha2(panel);
> +	int ret;
> +
> +	ret = s6e3ha2_power_on(ctx);
> +	if (ret < 0)
> +		return ret;
> +
> +	s6e3ha2_panel_init(ctx);
> +	if (ctx->error < 0)

This is one of the reasons why ctx->error is a bad idea. It's completely
unintuitive to check ctx->error here because nobody's actually setting
it in this context.

> +		s6e3ha2_unprepare(panel);

This is somewhat asymmetric. I would expect the s6e3ha2_panel_init() to
undo what it did on failure, so that you would only have to call
s6e3ha2_power_off() here and undo what you did in *this* function.

> +static int s6e3ha2_enable(struct drm_panel *panel)
> +{
> +	return 0;
> +}

This is really where you're supposed to turn on the backlight or
similar. Where does that happen?

> +static int s6e3ha2_get_modes(struct drm_panel *panel)
> +{
> +	struct drm_connector *connector = panel->connector;
> +	struct s6e3ha2 *ctx = panel_to_s6e3ha2(panel);
> +	struct drm_display_mode *mode;
> +
> +	mode = drm_mode_create(connector->dev);
> +	if (!mode) {
> +		DRM_ERROR("failed to create a new display mode\n");
> +		return 0;
> +	}
> +
> +	drm_display_mode_from_videomode(&ctx->vm, mode);
> +	mode->width_mm = ctx->width_mm;
> +	mode->height_mm = ctx->height_mm;
> +	connector->display_info.width_mm = mode->width_mm;
> +	connector->display_info.height_mm = mode->height_mm;
> +
> +	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
> +	drm_mode_probed_add(connector, mode);
> +
> +	return 1;
> +}

Like I said before, the mode is implied by the compatible value, so no
need to parse it from device tree.

> +static int s6e3ha2_probe(struct mipi_dsi_device *dsi)
> +{
> +	struct device *dev = &dsi->dev;
> +	struct s6e3ha2 *ctx;
> +	int ret;
> +
> +	ctx = devm_kzalloc(dev, sizeof(struct s6e3ha2), GFP_KERNEL);

sizeof(*ctx) is much shorter.

> +	ctx->reset_gpio = devm_gpiod_get(dev, "reset");
> +	if (IS_ERR(ctx->reset_gpio)) {
> +		dev_err(dev, "cannot get reset-gpios %ld\n",
> +			PTR_ERR(ctx->reset_gpio));
> +		return PTR_ERR(ctx->reset_gpio);
> +	}
> +	ret = gpiod_direction_output(ctx->reset_gpio, 1);

For consistency the above two lines should be separated by a blank line.

> +	if (ret < 0) {
> +		dev_err(dev, "cannot configure reset-gpios %d\n", ret);
> +		return ret;
> +	}
> +
> +	ctx->panel_en_gpio = devm_gpiod_get(dev, "panel-en");
> +	if (IS_ERR(ctx->panel_en_gpio)) {
> +		dev_err(dev, "cannot get panel-en-gpios %ld\n",
> +			PTR_ERR(ctx->panel_en_gpio));
> +		return PTR_ERR(ctx->panel_en_gpio);
> +	}
> +	ret = gpiod_direction_output(ctx->panel_en_gpio, 1);

Same here.

> +	if (ret < 0) {
> +		dev_err(dev, "cannot configure panel-en-gpios %d\n", ret);
> +		return ret;
> +	}

You seem to be turning on the panel here. That's wrong because you're
supposed to wait for the display driver to tell you to turn it on via
->prepare() and ->enable().

> +
> +	drm_panel_init(&ctx->panel);
> +	ctx->panel.dev = dev;
> +	ctx->panel.funcs = &s6e3ha2_drm_funcs;

I don't see a use for the _drm in here.

> +static struct of_device_id s6e3ha2_of_match[] = {

static const, please.

> +	{ .compatible = "samsung,s6e3ha2" },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, s6e3ha2_of_match);
> +
> +static struct mipi_dsi_driver s6e3ha2_driver = {
> +	.probe = s6e3ha2_probe,
> +	.remove = s6e3ha2_remove,
> +	.driver = {
> +		.name = "panel_s6e3ha2",

Please use a - instead of an _ here, for consistency with other drivers.

> +		.owner = THIS_MODULE,

No need for this anymore.

Thierry

[-- Attachment #1.2: Type: application/pgp-signature, Size: 819 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

  reply	other threads:[~2015-02-03 12:51 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-01-27  1:48 [PATCH v3] drm/panel: add s6e3ha2 AMOLED panel driver Hyungwon Hwang
2015-02-03 12:51 ` Thierry Reding [this message]
2015-02-05 11:17   ` Andrzej Hajda

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20150203125150.GD15068@ulmo.nvidia.com \
    --to=thierry.reding@gmail.com \
    --cc=dh09.lee@samsung.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=human.hwang@samsung.com \
    --cc=sangbae90.lee@samsung.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox