Re: [PATCH v3 3/7] drm: Add driver for Solomon SSD130X OLED displays

From: Javier Martinez Canillas
Date: Wed Feb 09 2022 - 10:54:12 EST


Hello Andy,

Thanks for your feedback.

On 2/9/22 16:12, Andy Shevchenko wrote:
> On Wed, Feb 09, 2022 at 10:03:10AM +0100, Javier Martinez Canillas wrote:
>> This adds a DRM driver for SSD1305, SSD1306, SSD1307 and SSD1309 Solomon
>> OLED display controllers.
>>
>> It's only the core part of the driver and a bus specific driver is needed
>> for each transport interface supported by the display controllers.
>
> Thank you for the update, my comments below.
>
> ...
>
>> source "drivers/gpu/drm/sprd/Kconfig"
>>
>> +source "drivers/gpu/drm/solomon/Kconfig"
>
> 'o' before 'p' ?
>

The Kconfig was not sorted alphabetically so I just added it at
the end. Same for the Makefile. But I will change it in v4 just
to not keep adding unsorted entries.

[snip]

>> +/*
>> + * DRM driver for Solomon SSD130X OLED displays
>
> Solomon SSD130x (with lower letter it's easy to read and realize that it's
> not a model name).
>

Ok.

>> + * Copyright 2022 Red Hat Inc.
>> + * Authors: Javier Martinez Canillas <javierm@xxxxxxxxxx>
>> + *
>> + * Based on drivers/video/fbdev/ssd1307fb.c
>> + * Copyright 2012 Free Electrons
>> + */
>
>> +#include <linux/backlight.h>
>> +#include <linux/delay.h>
>> +#include <linux/gpio/consumer.h>
>> +#include <linux/property.h>
>> +#include <linux/pwm.h>
>> +#include <linux/regulator/consumer.h>
>
> ...
>
>> +#define DRIVER_NAME "ssd130x"
>> +#define DRIVER_DESC "DRM driver for Solomon SSD130X OLED displays"
>> +#define DRIVER_DATE "20220131"
>> +#define DRIVER_MAJOR 1
>> +#define DRIVER_MINOR 0
>
> Not sure it has a value when being defined. Only one string is reused and even
> if hard coded twice linker will optimize it.
>

I like to have all this at the beginning, it makes easier to read IMO.

[snip]

>> +
>> + do {
>> + value = va_arg(ap, int);
>> + ret = regmap_write(ssd130x->regmap, SSD130X_COMMAND, (u8)value);
>> + if (ret)
>> + goto out_end;
>> + } while (--count);
>> +
>> +out_end:
>> + va_end(ap);
>> +
>> + return ret;
>
> Can bulk operation be used in the callers instead?
>

I'm using bulk writes for the data but not for the commands. Because I
tried to do that before and didn't work. But I'll give it a try again
now that I switched to regmap. Maybe it was some mistake on my end.

> I have noticed that all of the callers are using
> - 1 -- makes no sense at all, can be replaced with regmap_write()

Yes, I just used for consistency. That way all the places sending a
command would use the same function call.

> - 2
> - 3
>
> Can be helpers for two and three arguments, with use of bulk call.
>
> What do you think?
>

Agreed, as mentioned I'll give it a try to sending all the data as a
bulk write with regmap.

>> +}
>
> ...
>
>> +static void ssd130x_reset(struct ssd130x_device *ssd130x)
>> +{
>> + /* Reset the screen */
>> + gpiod_set_value_cansleep(ssd130x->reset, 1);
>> + udelay(4);
>> + gpiod_set_value_cansleep(ssd130x->reset, 0);
>> + udelay(4);
>
> I don't remember if reset pin is mandatory. fbtft does
>
> if (!gpiod->reset)
> return;
>
> ...do reset...
>
>> +}
>
> ...
>
>> + if (ssd130x->reset)
>
> A-ha, why not in the callee?
>

I think is easier to read when doing it in the caller, specially since there
is only a single call. Than calling it unconditionally and making it a no-op
if there isn't a reset GPIO.

>> + ssd130x_reset(ssd130x);
>
> ...
>
>> + /* Set COM direction */
>> + com_invdir = 0xc0 | ssd130x->com_invdir << 3;
>
> Can 0xc0 and 3 be GENMASK()'ed and defined?
>

Ok.

> ...
>
>> + /* Set clock frequency */
>> + dclk = ((ssd130x->dclk_div - 1) & 0xf) | (ssd130x->dclk_frq & 0xf) << 4;
>
> GENMASK() ?
>

Ok.

> ...
>
>> + u32 mode = ((ssd130x->area_color_enable ? 0x30 : 0) |
>> + (ssd130x->low_power ? 5 : 0));
>
> With if's it will look better.
>
> u32 mode = 0;
>
> if (ssd130x->area_color_enable)
> mode |= 0x30;
> if (ssd130x->low_power)
> mode |= 5;
>

Sure.

> ...
>
>> + /* Turn on the DC-DC Charge Pump */
>> + chargepump = BIT(4) | (ssd130x->device_info->need_chargepump ? BIT(2) : 0);
>
> Ditto.
>

Ok.

> ...
>
>> + for (i = 0; i < ARRAY_SIZE(ssd130x->lookup_table); ++i) {
>
> i++ should work as well.
>

Yeah.

>> + u8 val = ssd130x->lookup_table[i];
>> +
>> + if (val < 31 || val > 63)
>> + dev_warn(ssd130x->dev,
>> + "lookup table index %d value out of range 31 <= %d <= 63\n",
>> + i, val);
>> + ret = ssd130x_write_cmd(ssd130x, 1, val);
>> + if (ret < 0)
>> + return ret;
>> + }
>
> ...
>
>> + u8 *buf = NULL;
>
>> +
>
> Redundant blank line, not sure if checkpatch catches this.
>

Agreed.

>> + struct drm_rect fullscreen = {
>> + .x1 = 0,
>> + .x2 = ssd130x->width,
>> + .y1 = 0,
>> + .y2 = ssd130x->height,
>> + };
>
> ...
>
>> +power_off:
>
> out_power_off: ?
>

Ok.

> ...
>
>> + ret = PTR_ERR(ssd130x->vbat_reg);
>> + if (ret == -ENODEV)
>> + ssd130x->vbat_reg = NULL;
>> + else
>> + return dev_err_probe(dev, ret, "Failed to get VBAT regulator\n");
>
> Can it be
>
> ret = PTR_ERR(ssd130x->vbat_reg);
> if (ret != -ENODEV)
> return dev_err_probe(dev, ret, "Failed to get VBAT regulator\n");
>
> ssd130x->vbat_reg = NULL;
>
> ?
>

Mark mentioned that the regulator shouldn't really be optional.
So half of this part is going away.

> ...
>
>> + ssd130x = devm_drm_dev_alloc(dev, &ssd130x_drm_driver,
>> + struct ssd130x_device, drm);
>> + if (IS_ERR(ssd130x)) {
>
>> + dev_err(dev, "Failed to allocate DRM device: %d\n", ret);
>> + return ssd130x;
>
> return dev_err_probe() ?
>

No, because this isn't a resource provided by other driver. If this
failed is mostly due a memory allocation error.

>> + }
>
> ...
>
>> + bl = devm_backlight_device_register(dev, dev_name(dev), dev, ssd130x,
>> + &ssd130xfb_bl_ops, NULL);
>> + if (IS_ERR(bl)) {
>> + ret = PTR_ERR(bl);
>> + dev_err(dev, "Unable to register backlight device: %d\n", ret);
>> + return ERR_PTR(ret);
>
> Ditto.
>

Same. This is an error and not a reason to defer the probe.

>> + }
>
> ...
>
>> + ret = drm_dev_register(drm, 0);
>> + if (ret) {
>> + dev_err(dev, "DRM device register failed: %d\n", ret);
>> + return ERR_PTR(ret);
>
> Ditto.
>

And same.

>> + }
>
> ...
>
> I have feelings that half of my comments were ignored...
> Maybe I missed the discussion(s).
>

I assure you that no comments from you or anyone were ignored.

I may had missed something but if if I did was a mistake and
not intentionally. I keep a changelog for each revision in
the patches with the name of the reviewer so people can check
and compare.

If something that you mentioned is not there, I apologize and
please point me out so I can address it in v4.

Best regards,
--
Javier Martinez Canillas
Linux Engineering
Red Hat