linux-fbdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Paul Mundt <lethal@linux-sh.org>
To: linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH 5/5] S5PC110: add MIPI-DSI based sample lcd panel driver.
Date: Thu, 06 Jan 2011 05:14:58 +0000	[thread overview]
Message-ID: <20110106051458.GP23889@linux-sh.org> (raw)
In-Reply-To: <1293535595-24861-1-git-send-email-inki.dae@samsung.com>

On Tue, Dec 28, 2010 at 08:26:35PM +0900, Inki Dae wrote:
> this patch addes MIPI-DSI based sample panel driver.
> to write MIPI-DSI based lcd panel driver, you can refer to
> this sample driver.
> 
> Signed-off-by: Inki Dae <inki.dae@samsung.com>

Sample drivers are ok, but unless it has some sort of practical run-time
use you are probably better off just including this along with your
subsystem/platform documentation in Documentation somewhere. You can
search for .c files there to see how others are doing it.

Having said that ..

> diff --git a/drivers/video/s5p_mipi_sample.c b/drivers/video/s5p_mipi_sample.c
> new file mode 100644
> index 0000000..8a8abfe
> --- /dev/null
> +++ b/drivers/video/s5p_mipi_sample.c
> @@ -0,0 +1,220 @@
> +/* linux/drivers/video/sample.c
> + *
This is precisely why file comments are useless, since they invariably
fail to match up.

> + * MIPI-DSI based sample AMOLED lcd panel driver.
> + *
> + * Inki Dae, <inki.dae@samsung.com>
> + *
No Copyright notice?

> +static void sample_long_command(struct sample *lcd)
> +{
> +	struct dsim_master_ops *ops = lcd_to_master_ops(lcd);
> +	unsigned char data_to_send[5] = {
> +		0x00, 0x00, 0x00, 0x00, 0x00
> +	};
> +
> +	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
> +		(unsigned int) data_to_send, sizeof(data_to_send));
> +}
> +
> +static void sample_short_command(struct sample *lcd)
> +{
> +	struct dsim_master_ops *ops = lcd_to_master_ops(lcd);
> +
> +	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_SHORT_WRITE_PARAM,
> +				0x00, 0x00);
> +}
> +
ops->cmd_write() can fail for any number of reasons, so you will want to
change these to make sure that you are actually handling the error cases.

> +static int sample_panel_init(struct sample *lcd)
> +{
> +	sample_long_command(lcd);
> +	sample_short_command(lcd);
> +
> +	return 0;

At which point you can fail the initialization instead of just blowing up
later.

> +static int sample_gamma_ctrl(struct sample *lcd, int gamma)
> +{
> +	struct dsim_master_ops *ops = lcd_to_master_ops(lcd);
> +
> +	/* change transfer mode to LP mode */
> +	if (ops->change_dsim_transfer_mode)
> +		ops->change_dsim_transfer_mode(lcd_to_master(lcd), 0);
> +
ops->change_dsim_transfer_mode() can also fail. You could do this more
cleanly as:

enum { DSIM_XFER_LP, DSIM_XFER_HS };

static inline int dsim_set_xfer_mode(struct mipi_dsim_device *dsim, int mode)
{
	struct mipi_dsim_master_ops *ops = dsim->master_ops;

	if (!ops->change_dsim_transfer_mode)
		return -ENOSYS;	/* not implemented */

	return ops->change_dsim_transfer_mode(dsim, mode);
}

Then simply do your sample_gamma_ctrl() as:

	ret = dsim_set_xfer_mode(dsim, DSIM_XFER_LP);
	if (ret != 0)
		return ret;

> +	/* update gamma table. */
> +

	return dsim_set_xfer_mode(dsim, DSIM_XFER_HS);
> +}
> +

Or something similar. Your sample code should really be as
self-documenting and error-proof as possible. You don't really want to be
in a situation where subtle bugs leak through that then everyone who uses
this code as a reference will carry over!

> +static int sample_set_brightness(struct backlight_device *bd)
> +{
> +	int ret = 0, brightness = bd->props.brightness;
> +	struct sample *lcd = bl_get_data(bd);
> +
> +	if (brightness < MIN_BRIGHTNESS ||
> +		brightness > bd->props.max_brightness) {
> +		dev_err(lcd->dev, "lcd brightness should be %d to %d.\n",
> +			MIN_BRIGHTNESS, MAX_BRIGHTNESS);
> +		return -EINVAL;
> +	}
> +
> +	ret = sample_gamma_ctrl(lcd, bd->props.brightness);
> +	if (ret) {
> +		dev_err(&bd->dev, "lcd brightness setting failed.\n");
> +		return -EIO;
> +	}
> +
With your current approach this error condition will never be reached,
for example.

> +static int sample_probe(struct mipi_lcd_device *mipi_dev)
> +{
> +	struct sample *lcd = NULL;
> +	struct backlight_device *bd = NULL;
> +
> +	lcd = kzalloc(sizeof(struct sample), GFP_KERNEL);
> +	if (!lcd) {
> +		dev_err(&mipi_dev->dev, "failed to allocate sample structure.\n");
> +		return -ENOMEM;
> +	}
> +
> +	lcd->mipi_dev = mipi_dev;
> +	lcd->ddi_pd > +		(struct mipi_ddi_platform_data *)device_to_ddi_pd(mipi_dev);

Does this really need to be casted?

> +	lcd->dev = &mipi_dev->dev;
> +
> +	dev_set_drvdata(&mipi_dev->dev, lcd);
> +
> +	bd = backlight_device_register("sample-bl", lcd->dev, lcd,
> +		&sample_backlight_ops, NULL);
> +
> +	lcd->bd = bd;
> +
And here you have no error checking for backlight registration, so you
will get a NULL pointer deref:

> +	bd->props.max_brightness = MAX_BRIGHTNESS;
> +	bd->props.brightness = MAX_BRIGHTNESS;
> +
here. backlight_device_register() returns an ERR_PTR(), so you will want
to do an IS_ERR() check, which you can then map back with PTR_ERR() for a
more precise idea of why it failed.

> +	/* lcd power on */
> +	if (lcd->ddi_pd->lcd_power_on)
> +		lcd->ddi_pd->lcd_power_on(NULL, 1);
> +
You may wish to use enums for this too. It's not strictly necessary, but
it does help to clarify which is the on and which is the off position.

> +	mdelay(lcd->ddi_pd->reset_delay);
> +
> +	/* lcd reset */
> +	if (lcd->ddi_pd->lcd_reset)
> +		lcd->ddi_pd->lcd_reset(NULL);
> +
Reset can fail?

> +	sample_panel_init(lcd);
> +
> +	return 0;
> +}
sample_panel_init() can fail as well, and in both cases you will need to
clean up all of the above work.

> +
> +#ifdef CONFIG_PM
> +static int sample_suspend(struct mipi_lcd_device *mipi_dev)
> +{
> +	struct sample *lcd = dev_get_drvdata(&mipi_dev->dev);
> +
> +	/* some work. */
> +
> +	mdelay(lcd->ddi_pd->power_off_delay);
> +
Adding delays in the suspend/resume path sounds like a pretty bad idea,
is there a technical reason for it? If so, please document it, so people
get some idea of where their suspend/resume latencies are coming from,
and why.

> +static struct mipi_lcd_driver sample_mipi_driver = {
> +	.name = "sample",
> +
> +	.probe = sample_probe,

No remove?

> +	.suspend = sample_suspend,
> +	.resume = sample_resume,
> +};
> +
> +static int sample_init(void)
> +{
> +	s5p_mipi_register_lcd_driver(&sample_mipi_driver);
> +
> +	return 0;
> +}
> +
This should be:

	return s5p_mipi_register_lcd_driver(&sample_mipi_driver);

And sample_init should be __init annotated.

> +static void sample_exit(void)
> +{
> +	return;
> +}
> +
This should be balanced with a

	s5p_mipi_unregister_lcd_driver(&sample_mipi_driver);

> +module_init(sample_init);
> +module_exit(sample_exit);
> +
> +MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
> +MODULE_DESCRIPTION("MIPI-DSI based sample AMOLED LCD Panel Driver");
> +MODULE_LICENSE("GPL");

Since you have a fairly complex subsystem it's probably a good idea to
work out how your MODULE_ALIAS() is going to work, so that you can handle
autoprobe for these things via udev. The fact you have no exit path
definitely suggests you haven't tested this in a modular configuration,
so there is probably going to be quite a bit of work to do here.

  parent reply	other threads:[~2011-01-06  5:14 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-12-28 11:26 [PATCH 5/5] S5PC110: add MIPI-DSI based sample lcd panel driver Inki Dae
2010-12-31  6:57 ` Kukjin Kim
2011-01-03  2:08   ` daeinki
2011-01-06  5:14 ` Paul Mundt [this message]
2011-01-06  6:31   ` InKi Dae

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=20110106051458.GP23889@linux-sh.org \
    --to=lethal@linux-sh.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    /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;
as well as URLs for NNTP newsgroup(s).