* [PATCH 0/4] Prepare consoles, add fb flush and Solomon SSD1307 OLED controller support @ 2017-02-24 14:24 Bastian Stender 2017-02-24 14:24 ` [PATCH 1/4] console: replace set_active by open/close Bastian Stender ` (3 more replies) 0 siblings, 4 replies; 15+ messages in thread From: Bastian Stender @ 2017-02-24 14:24 UTC (permalink / raw) To: barebox; +Cc: Bastian Stender Hi, This patch set basically adds support for the Solomon SSD1307 OLED controller family along with some framebuffer and console features needed. To enable opening and closing consoles regardless of stdin, stdout and stderr the open and close methods were introduced. In combination with the 2nd patch it is now possible to display text with 'echo -o <console device> abcdef'. The 3rd patch adds a flush method for drivers using a virtual framebuffer - like the SSD1307 OLED controller. It is called at appropriate times. The 4th patch finally adds Solomon SSD1307 OLED controller support. Regards, Bastian Bastian Stender (4): console: replace set_active by open/close console: expose consoles in devfs fb: introduce flush for virtual framebuffer video: add support for Solomon SSD1307 OLED controller family commands/fbtest.c | 1 + common/console.c | 71 +++++- drivers/video/Kconfig | 4 + drivers/video/Makefile | 1 + drivers/video/fb.c | 26 +++ drivers/video/fbconsole.c | 31 ++- drivers/video/ssd1307fb.c | 569 ++++++++++++++++++++++++++++++++++++++++++++++ include/console.h | 6 +- include/fb.h | 2 + net/netconsole.c | 27 ++- 10 files changed, 713 insertions(+), 25 deletions(-) create mode 100644 drivers/video/ssd1307fb.c -- 2.11.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 1/4] console: replace set_active by open/close 2017-02-24 14:24 [PATCH 0/4] Prepare consoles, add fb flush and Solomon SSD1307 OLED controller support Bastian Stender @ 2017-02-24 14:24 ` Bastian Stender 2017-02-27 9:54 ` Sascha Hauer 2017-02-24 14:24 ` [PATCH 2/4] console: expose consoles in devfs Bastian Stender ` (2 subsequent siblings) 3 siblings, 1 reply; 15+ messages in thread From: Bastian Stender @ 2017-02-24 14:24 UTC (permalink / raw) To: barebox; +Cc: Bastian Stender Opening and closing consoles should be independent from setting them active. This way it is possible to open e.g. a framebuffer console and display text on it without showing stdout/stderr. Signed-off-by: Bastian Stender <bst@pengutronix.de> --- common/console.c | 19 +++++++++++++++---- drivers/video/fbconsole.c | 28 ++++++++++++++++++---------- include/console.h | 3 ++- net/netconsole.c | 27 +++++++++++++++++---------- 4 files changed, 52 insertions(+), 25 deletions(-) diff --git a/common/console.c b/common/console.c index 74ccfcfc3e..43890b3da8 100644 --- a/common/console.c +++ b/common/console.c @@ -71,10 +71,21 @@ int console_set_active(struct console_device *cdev, unsigned flag) if (!flag && cdev->f_active && cdev->flush) cdev->flush(cdev); - if (cdev->set_active) { - ret = cdev->set_active(cdev, flag); - if (ret) - return ret; + if (flag == cdev->f_active) + return 0; + + if (!flag) { + if (cdev->close) { + ret = cdev->close(cdev); + if (ret) + return ret; + } + } else { + if (cdev->open) { + ret = cdev->open(cdev); + if (ret) + return ret; + } } cdev->f_active = flag; diff --git a/drivers/video/fbconsole.c b/drivers/video/fbconsole.c index 693c21f547..64f7d7364e 100644 --- a/drivers/video/fbconsole.c +++ b/drivers/video/fbconsole.c @@ -365,21 +365,13 @@ static int setup_font(struct fbc_priv *priv) return 0; } -static int fbc_set_active(struct console_device *cdev, unsigned flags) +static int fbc_open(struct console_device *cdev) { struct fbc_priv *priv = container_of(cdev, struct fbc_priv, cdev); struct fb_info *fb = priv->fb; int ret; - if (priv->active) { - fb_close(priv->sc); - priv->active = false; - } - - if (!(flags & (CONSOLE_STDOUT | CONSOLE_STDERR))) - return 0; - ret = setup_font(priv); if (ret) return ret; @@ -400,6 +392,21 @@ static int fbc_set_active(struct console_device *cdev, unsigned flags) return 0; } +static int fbc_close(struct console_device *cdev) +{ + struct fbc_priv *priv = container_of(cdev, + struct fbc_priv, cdev); + + if (priv->active) { + fb_close(priv->sc); + priv->active = false; + + return 0; + } + + return -EINVAL; +} + static int set_font(struct param_d *p, void *vpriv) { struct fbc_priv *priv = vpriv; @@ -434,7 +441,8 @@ int register_fbconsole(struct fb_info *fb) cdev->getc = fbc_getc; cdev->devname = "fbconsole"; cdev->devid = DEVICE_ID_DYNAMIC; - cdev->set_active = fbc_set_active; + cdev->open = fbc_open; + cdev->close = fbc_close; ret = console_register(cdev); if (ret) { diff --git a/include/console.h b/include/console.h index 4b2f134a4c..53f6e47fcc 100644 --- a/include/console.h +++ b/include/console.h @@ -44,7 +44,8 @@ struct console_device { int (*setbrg)(struct console_device *cdev, int baudrate); void (*flush)(struct console_device *cdev); int (*set_mode)(struct console_device *cdev, enum console_mode mode); - int (*set_active)(struct console_device *cdev, unsigned active); + int (*open)(struct console_device *cdev); + int (*close)(struct console_device *cdev); char *devname; int devid; diff --git a/net/netconsole.c b/net/netconsole.c index ce3c418798..ef8b1856b6 100644 --- a/net/netconsole.c +++ b/net/netconsole.c @@ -105,19 +105,11 @@ static void nc_putc(struct console_device *cdev, char c) priv->busy = 0; } -static int nc_set_active(struct console_device *cdev, unsigned flags) +static int nc_open(struct console_device *cdev) { struct nc_priv *priv = container_of(cdev, struct nc_priv, cdev); - if (priv->con) { - net_unregister(priv->con); - priv->con = NULL; - } - - if (!flags) - return 0; - if (!priv->port) { pr_err("port not set\n"); return -EINVAL; @@ -142,6 +134,20 @@ static int nc_set_active(struct console_device *cdev, unsigned flags) return 0; } +static int nc_close(struct console_device *cdev) +{ + struct nc_priv *priv = container_of(cdev, + struct nc_priv, cdev); + + if (priv->con) { + net_unregister(priv->con); + priv->con = NULL; + return 0; + } + + return -EINVAL; +} + static int netconsole_init(void) { struct nc_priv *priv; @@ -155,7 +161,8 @@ static int netconsole_init(void) cdev->getc = nc_getc; cdev->devname = "netconsole"; cdev->devid = DEVICE_ID_SINGLE; - cdev->set_active = nc_set_active; + cdev->open = nc_open; + cdev->close = nc_close; g_priv = priv; -- 2.11.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/4] console: replace set_active by open/close 2017-02-24 14:24 ` [PATCH 1/4] console: replace set_active by open/close Bastian Stender @ 2017-02-27 9:54 ` Sascha Hauer 2017-02-27 15:56 ` [PATCH v2] " Bastian Stender 0 siblings, 1 reply; 15+ messages in thread From: Sascha Hauer @ 2017-02-27 9:54 UTC (permalink / raw) To: Bastian Stender; +Cc: barebox On Fri, Feb 24, 2017 at 03:24:58PM +0100, Bastian Stender wrote: > Opening and closing consoles should be independent from setting them > active. This way it is possible to open e.g. a framebuffer console and > display text on it without showing stdout/stderr. > > Signed-off-by: Bastian Stender <bst@pengutronix.de> > --- > common/console.c | 19 +++++++++++++++---- > drivers/video/fbconsole.c | 28 ++++++++++++++++++---------- > include/console.h | 3 ++- > net/netconsole.c | 27 +++++++++++++++++---------- > 4 files changed, 52 insertions(+), 25 deletions(-) > > diff --git a/common/console.c b/common/console.c > index 74ccfcfc3e..43890b3da8 100644 > --- a/common/console.c > +++ b/common/console.c > @@ -71,10 +71,21 @@ int console_set_active(struct console_device *cdev, unsigned flag) > if (!flag && cdev->f_active && cdev->flush) > cdev->flush(cdev); > > - if (cdev->set_active) { > - ret = cdev->set_active(cdev, flag); > - if (ret) > - return ret; > + if (flag == cdev->f_active) > + return 0; > + > + if (!flag) { > + if (cdev->close) { > + ret = cdev->close(cdev); > + if (ret) > + return ret; > + } > + } else { > + if (cdev->open) { > + ret = cdev->open(cdev); > + if (ret) > + return ret; > + } > } instead of calling into cdev->open/close directly here I would prefer console_open() / console_close() functions which get called here. In these functions you can call the driver hooks on first open and last close. Sascha -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2] console: replace set_active by open/close 2017-02-27 9:54 ` Sascha Hauer @ 2017-02-27 15:56 ` Bastian Stender 2017-02-28 7:41 ` Sascha Hauer 0 siblings, 1 reply; 15+ messages in thread From: Bastian Stender @ 2017-02-27 15:56 UTC (permalink / raw) To: Sascha Hauer; +Cc: barebox, Bastian Stender Opening and closing consoles should be independent from setting them active. This way it is possible to open e.g. a framebuffer console and display text on it without showing stdout/stderr. Signed-off-by: Bastian Stender <bst@pengutronix.de> --- common/console.c | 31 +++++++++++++++++++++++++++++-- drivers/video/fbconsole.c | 28 ++++++++++++++++++---------- include/console.h | 9 ++++++++- net/netconsole.c | 27 +++++++++++++++++---------- 4 files changed, 72 insertions(+), 23 deletions(-) diff --git a/common/console.c b/common/console.c index 74ccfcfc3e..3ff32b8327 100644 --- a/common/console.c +++ b/common/console.c @@ -59,6 +59,26 @@ static struct kfifo __console_output_fifo; static struct kfifo *console_input_fifo = &__console_input_fifo; static struct kfifo *console_output_fifo = &__console_output_fifo; +int console_open(struct console_device *cdev) +{ + if (cdev->open && !(cdev-> flags & FLAG_CONSOLE_OPEN)) { + cdev->flags |= FLAG_CONSOLE_OPEN; + return cdev->open(cdev); + } + + return 0; +} + +int console_close(struct console_device *cdev) +{ + if (cdev->close && cdev-> flags & FLAG_CONSOLE_OPEN) { + cdev->flags &= ~FLAG_CONSOLE_OPEN; + return cdev->close(cdev); + } + + return 0; +} + int console_set_active(struct console_device *cdev, unsigned flag) { int ret, i; @@ -71,8 +91,15 @@ int console_set_active(struct console_device *cdev, unsigned flag) if (!flag && cdev->f_active && cdev->flush) cdev->flush(cdev); - if (cdev->set_active) { - ret = cdev->set_active(cdev, flag); + if (flag == cdev->f_active) + return 0; + + if (!flag) { + ret = console_close(cdev); + if (ret) + return ret; + } else { + ret = console_open(cdev); if (ret) return ret; } diff --git a/drivers/video/fbconsole.c b/drivers/video/fbconsole.c index 693c21f547..64f7d7364e 100644 --- a/drivers/video/fbconsole.c +++ b/drivers/video/fbconsole.c @@ -365,21 +365,13 @@ static int setup_font(struct fbc_priv *priv) return 0; } -static int fbc_set_active(struct console_device *cdev, unsigned flags) +static int fbc_open(struct console_device *cdev) { struct fbc_priv *priv = container_of(cdev, struct fbc_priv, cdev); struct fb_info *fb = priv->fb; int ret; - if (priv->active) { - fb_close(priv->sc); - priv->active = false; - } - - if (!(flags & (CONSOLE_STDOUT | CONSOLE_STDERR))) - return 0; - ret = setup_font(priv); if (ret) return ret; @@ -400,6 +392,21 @@ static int fbc_set_active(struct console_device *cdev, unsigned flags) return 0; } +static int fbc_close(struct console_device *cdev) +{ + struct fbc_priv *priv = container_of(cdev, + struct fbc_priv, cdev); + + if (priv->active) { + fb_close(priv->sc); + priv->active = false; + + return 0; + } + + return -EINVAL; +} + static int set_font(struct param_d *p, void *vpriv) { struct fbc_priv *priv = vpriv; @@ -434,7 +441,8 @@ int register_fbconsole(struct fb_info *fb) cdev->getc = fbc_getc; cdev->devname = "fbconsole"; cdev->devid = DEVICE_ID_DYNAMIC; - cdev->set_active = fbc_set_active; + cdev->open = fbc_open; + cdev->close = fbc_close; ret = console_register(cdev); if (ret) { diff --git a/include/console.h b/include/console.h index 4b2f134a4c..85e15cad67 100644 --- a/include/console.h +++ b/include/console.h @@ -28,6 +28,8 @@ #define CONSOLE_STDOUT (1 << 1) #define CONSOLE_STDERR (1 << 2) +#define FLAG_CONSOLE_OPEN (1 << 0) + enum console_mode { CONSOLE_MODE_NORMAL, CONSOLE_MODE_RS485, @@ -44,7 +46,8 @@ struct console_device { int (*setbrg)(struct console_device *cdev, int baudrate); void (*flush)(struct console_device *cdev); int (*set_mode)(struct console_device *cdev, enum console_mode mode); - int (*set_active)(struct console_device *cdev, unsigned active); + int (*open)(struct console_device *cdev); + int (*close)(struct console_device *cdev); char *devname; int devid; @@ -54,6 +57,8 @@ struct console_device { unsigned char f_active; char active[4]; + unsigned flags; + unsigned int baudrate; unsigned int baudrate_param; @@ -75,6 +80,8 @@ extern int barebox_loglevel; struct console_device *console_get_first_active(void); +int console_open(struct console_device *cdev); +int console_close(struct console_device *cdev); int console_set_active(struct console_device *cdev, unsigned active); unsigned console_get_active(struct console_device *cdev); int console_set_baudrate(struct console_device *cdev, unsigned baudrate); diff --git a/net/netconsole.c b/net/netconsole.c index ce3c418798..ef8b1856b6 100644 --- a/net/netconsole.c +++ b/net/netconsole.c @@ -105,19 +105,11 @@ static void nc_putc(struct console_device *cdev, char c) priv->busy = 0; } -static int nc_set_active(struct console_device *cdev, unsigned flags) +static int nc_open(struct console_device *cdev) { struct nc_priv *priv = container_of(cdev, struct nc_priv, cdev); - if (priv->con) { - net_unregister(priv->con); - priv->con = NULL; - } - - if (!flags) - return 0; - if (!priv->port) { pr_err("port not set\n"); return -EINVAL; @@ -142,6 +134,20 @@ static int nc_set_active(struct console_device *cdev, unsigned flags) return 0; } +static int nc_close(struct console_device *cdev) +{ + struct nc_priv *priv = container_of(cdev, + struct nc_priv, cdev); + + if (priv->con) { + net_unregister(priv->con); + priv->con = NULL; + return 0; + } + + return -EINVAL; +} + static int netconsole_init(void) { struct nc_priv *priv; @@ -155,7 +161,8 @@ static int netconsole_init(void) cdev->getc = nc_getc; cdev->devname = "netconsole"; cdev->devid = DEVICE_ID_SINGLE; - cdev->set_active = nc_set_active; + cdev->open = nc_open; + cdev->close = nc_close; g_priv = priv; -- 2.11.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2] console: replace set_active by open/close 2017-02-27 15:56 ` [PATCH v2] " Bastian Stender @ 2017-02-28 7:41 ` Sascha Hauer 0 siblings, 0 replies; 15+ messages in thread From: Sascha Hauer @ 2017-02-28 7:41 UTC (permalink / raw) To: Bastian Stender; +Cc: barebox On Mon, Feb 27, 2017 at 04:56:16PM +0100, Bastian Stender wrote: > Opening and closing consoles should be independent from setting them > active. This way it is possible to open e.g. a framebuffer console and > display text on it without showing stdout/stderr. > > Signed-off-by: Bastian Stender <bst@pengutronix.de> > --- > common/console.c | 31 +++++++++++++++++++++++++++++-- > drivers/video/fbconsole.c | 28 ++++++++++++++++++---------- > include/console.h | 9 ++++++++- > net/netconsole.c | 27 +++++++++++++++++---------- > 4 files changed, 72 insertions(+), 23 deletions(-) > > diff --git a/common/console.c b/common/console.c > index 74ccfcfc3e..3ff32b8327 100644 > --- a/common/console.c > +++ b/common/console.c > @@ -59,6 +59,26 @@ static struct kfifo __console_output_fifo; > static struct kfifo *console_input_fifo = &__console_input_fifo; > static struct kfifo *console_output_fifo = &__console_output_fifo; > > +int console_open(struct console_device *cdev) > +{ > + if (cdev->open && !(cdev-> flags & FLAG_CONSOLE_OPEN)) { > + cdev->flags |= FLAG_CONSOLE_OPEN; > + return cdev->open(cdev); > + } What if cdev->open() fails? In this case the flag is still set, but the console is not opened. Also please set the FLAG_CONSOLE_OPEN independent of the presence of the cdev->open() hook. > diff --git a/include/console.h b/include/console.h > index 4b2f134a4c..85e15cad67 100644 > --- a/include/console.h > +++ b/include/console.h > @@ -28,6 +28,8 @@ > #define CONSOLE_STDOUT (1 << 1) > #define CONSOLE_STDERR (1 << 2) > > +#define FLAG_CONSOLE_OPEN (1 << 0) > + > enum console_mode { > CONSOLE_MODE_NORMAL, > CONSOLE_MODE_RS485, > @@ -44,7 +46,8 @@ struct console_device { > int (*setbrg)(struct console_device *cdev, int baudrate); > void (*flush)(struct console_device *cdev); > int (*set_mode)(struct console_device *cdev, enum console_mode mode); > - int (*set_active)(struct console_device *cdev, unsigned active); > + int (*open)(struct console_device *cdev); > + int (*close)(struct console_device *cdev); > > char *devname; > int devid; > @@ -54,6 +57,8 @@ struct console_device { > unsigned char f_active; > char active[4]; > > + unsigned flags; > + Flags often have the problem that you do not know which flag define belong to which flag field in which structure. One thing we can do is to add the flag #defines directly above the struct member they belong to in the source code. In this case here we should use a counter rather than flags. Consider two users opening the console at the same time. Now when one of the users closes the console, it must still remain opened for the other user. Sascha -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 2/4] console: expose consoles in devfs 2017-02-24 14:24 [PATCH 0/4] Prepare consoles, add fb flush and Solomon SSD1307 OLED controller support Bastian Stender 2017-02-24 14:24 ` [PATCH 1/4] console: replace set_active by open/close Bastian Stender @ 2017-02-24 14:24 ` Bastian Stender 2017-02-27 9:55 ` Sascha Hauer 2017-02-24 14:25 ` [PATCH 3/4] fb: introduce flush for virtual framebuffer Bastian Stender 2017-02-24 14:25 ` [PATCH 4/4] video: add support for Solomon SSD1307 OLED controller family Bastian Stender 3 siblings, 1 reply; 15+ messages in thread From: Bastian Stender @ 2017-02-24 14:24 UTC (permalink / raw) To: barebox; +Cc: Bastian Stender This enables displaying text on e.g. a framebuffer console by issueing echo -o /dev/fbconsole0 abc123 Signed-off-by: Bastian Stender <bst@pengutronix.de> --- common/console.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ include/console.h | 3 +++ 2 files changed, 55 insertions(+) diff --git a/common/console.c b/common/console.c index 43890b3da8..dcd67afe20 100644 --- a/common/console.c +++ b/common/console.c @@ -243,6 +243,39 @@ static int __console_puts(struct console_device *cdev, const char *s) return n; } +static int fops_open(struct cdev *cdev, unsigned long flags) +{ + struct console_device *priv = cdev->priv; + + return priv->open(priv); +} + +static int fops_close(struct cdev *dev) +{ + struct console_device *priv = dev->priv; + + return priv->close(priv); +} + +static int fops_flush(struct cdev *dev) +{ + struct console_device *priv = dev->priv; + + priv->flush(priv); + + return 0; +} + +static int fops_write(struct cdev* dev, const void* buf, size_t count, + loff_t offset, ulong flags) +{ + struct console_device *priv = dev->priv; + + priv->puts(priv, buf); + + return 0; +} + int console_register(struct console_device *newcdev) { struct device_d *dev = &newcdev->class_dev; @@ -295,6 +328,25 @@ int console_register(struct console_device *newcdev) console_set_active(newcdev, CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR); + /* expose console as device in fs */ + newcdev->devfs.name = basprintf("%s%d", newcdev->class_dev.name, + newcdev->class_dev.id); + newcdev->devfs.priv = newcdev; + newcdev->devfs.dev = dev; + newcdev->devfs.ops = &newcdev->fops; + newcdev->devfs.flags = DEVFS_IS_CHARACTER_DEV; + newcdev->fops.open = fops_open; + newcdev->fops.close = fops_close; + newcdev->fops.flush = fops_flush; + newcdev->fops.write = fops_write; + + ret = devfs_create(&newcdev->devfs); + + if (ret) { + pr_err("device creation failed with %s\n", strerror(-ret)); + return ret; + } + return 0; } EXPORT_SYMBOL(console_register); diff --git a/include/console.h b/include/console.h index 53f6e47fcc..d9fa05c2ce 100644 --- a/include/console.h +++ b/include/console.h @@ -59,6 +59,9 @@ struct console_device { unsigned int baudrate_param; const char *linux_console_name; + + struct cdev devfs; + struct file_operations fops; }; int console_register(struct console_device *cdev); -- 2.11.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/4] console: expose consoles in devfs 2017-02-24 14:24 ` [PATCH 2/4] console: expose consoles in devfs Bastian Stender @ 2017-02-27 9:55 ` Sascha Hauer 2017-02-27 16:01 ` [PATCH v2] " Bastian Stender 0 siblings, 1 reply; 15+ messages in thread From: Sascha Hauer @ 2017-02-27 9:55 UTC (permalink / raw) To: Bastian Stender; +Cc: barebox On Fri, Feb 24, 2017 at 03:24:59PM +0100, Bastian Stender wrote: > This enables displaying text on e.g. a framebuffer console by issueing > > echo -o /dev/fbconsole0 abc123 > > Signed-off-by: Bastian Stender <bst@pengutronix.de> > --- > common/console.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ > include/console.h | 3 +++ > 2 files changed, 55 insertions(+) > > diff --git a/common/console.c b/common/console.c > index 43890b3da8..dcd67afe20 100644 > --- a/common/console.c > +++ b/common/console.c > @@ -243,6 +243,39 @@ static int __console_puts(struct console_device *cdev, const char *s) > return n; > } > > +static int fops_open(struct cdev *cdev, unsigned long flags) > +{ > + struct console_device *priv = cdev->priv; > + > + return priv->open(priv); > +} You do not check if this hook exists in the driver, but this will be solved when you follow what I suggested in 1/4. Sascha -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2] console: expose consoles in devfs 2017-02-27 9:55 ` Sascha Hauer @ 2017-02-27 16:01 ` Bastian Stender 2017-02-28 7:50 ` Sascha Hauer 0 siblings, 1 reply; 15+ messages in thread From: Bastian Stender @ 2017-02-27 16:01 UTC (permalink / raw) To: Sascha Hauer; +Cc: barebox, Bastian Stender This enables displaying text on e.g. a framebuffer console by issueing echo -o /dev/fbconsole0 abc123 Signed-off-by: Bastian Stender <bst@pengutronix.de> --- common/console.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ include/console.h | 3 +++ 2 files changed, 55 insertions(+) diff --git a/common/console.c b/common/console.c index 3ff32b8327..bde4c08414 100644 --- a/common/console.c +++ b/common/console.c @@ -259,6 +259,39 @@ static int __console_puts(struct console_device *cdev, const char *s) return n; } +static int fops_open(struct cdev *cdev, unsigned long flags) +{ + struct console_device *priv = cdev->priv; + + return console_open(priv); +} + +static int fops_close(struct cdev *dev) +{ + struct console_device *priv = dev->priv; + + return console_close(priv); +} + +static int fops_flush(struct cdev *dev) +{ + struct console_device *priv = dev->priv; + + priv->flush(priv); + + return 0; +} + +static int fops_write(struct cdev* dev, const void* buf, size_t count, + loff_t offset, ulong flags) +{ + struct console_device *priv = dev->priv; + + priv->puts(priv, buf); + + return 0; +} + int console_register(struct console_device *newcdev) { struct device_d *dev = &newcdev->class_dev; @@ -311,6 +344,25 @@ int console_register(struct console_device *newcdev) console_set_active(newcdev, CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR); + /* expose console as device in fs */ + newcdev->devfs.name = basprintf("%s%d", newcdev->class_dev.name, + newcdev->class_dev.id); + newcdev->devfs.priv = newcdev; + newcdev->devfs.dev = dev; + newcdev->devfs.ops = &newcdev->fops; + newcdev->devfs.flags = DEVFS_IS_CHARACTER_DEV; + newcdev->fops.open = fops_open; + newcdev->fops.close = fops_close; + newcdev->fops.flush = fops_flush; + newcdev->fops.write = fops_write; + + ret = devfs_create(&newcdev->devfs); + + if (ret) { + pr_err("device creation failed with %s\n", strerror(-ret)); + return ret; + } + return 0; } EXPORT_SYMBOL(console_register); diff --git a/include/console.h b/include/console.h index 85e15cad67..68edc3aaf1 100644 --- a/include/console.h +++ b/include/console.h @@ -63,6 +63,9 @@ struct console_device { unsigned int baudrate_param; const char *linux_console_name; + + struct cdev devfs; + struct file_operations fops; }; int console_register(struct console_device *cdev); -- 2.11.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2] console: expose consoles in devfs 2017-02-27 16:01 ` [PATCH v2] " Bastian Stender @ 2017-02-28 7:50 ` Sascha Hauer 0 siblings, 0 replies; 15+ messages in thread From: Sascha Hauer @ 2017-02-28 7:50 UTC (permalink / raw) To: Bastian Stender; +Cc: barebox On Mon, Feb 27, 2017 at 05:01:08PM +0100, Bastian Stender wrote: > This enables displaying text on e.g. a framebuffer console by issueing > > echo -o /dev/fbconsole0 abc123 > > Signed-off-by: Bastian Stender <bst@pengutronix.de> > --- > common/console.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ > include/console.h | 3 +++ > 2 files changed, 55 insertions(+) > > diff --git a/common/console.c b/common/console.c > index 3ff32b8327..bde4c08414 100644 > --- a/common/console.c > +++ b/common/console.c > @@ -259,6 +259,39 @@ static int __console_puts(struct console_device *cdev, const char *s) > return n; > } > > +static int fops_open(struct cdev *cdev, unsigned long flags) > +{ > + struct console_device *priv = cdev->priv; > + > + return console_open(priv); > +} > + > +static int fops_close(struct cdev *dev) > +{ > + struct console_device *priv = dev->priv; > + > + return console_close(priv); > +} > + > +static int fops_flush(struct cdev *dev) > +{ > + struct console_device *priv = dev->priv; > + > + priv->flush(priv); cdev->flush() is optional, you have to test for presence before using it. When you have to resend patches from a series, please resend the whole series. Scanning different mail threads to find the newest version of the patches can get cumbersome quite fast. Sascha -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 3/4] fb: introduce flush for virtual framebuffer 2017-02-24 14:24 [PATCH 0/4] Prepare consoles, add fb flush and Solomon SSD1307 OLED controller support Bastian Stender 2017-02-24 14:24 ` [PATCH 1/4] console: replace set_active by open/close Bastian Stender 2017-02-24 14:24 ` [PATCH 2/4] console: expose consoles in devfs Bastian Stender @ 2017-02-24 14:25 ` Bastian Stender 2017-02-24 14:25 ` [PATCH 4/4] video: add support for Solomon SSD1307 OLED controller family Bastian Stender 3 siblings, 0 replies; 15+ messages in thread From: Bastian Stender @ 2017-02-24 14:25 UTC (permalink / raw) To: barebox; +Cc: Bastian Stender Some drivers need an explicit sync method to flush the virtual framebuffer to the display. It is called fb_flush(). fb_flush() gets called on fbc_putc, on fb_close and in the pattern cycle in the fbtest command. Signed-off-by: Bastian Stender <bst@pengutronix.de> --- commands/fbtest.c | 1 + drivers/video/fb.c | 26 ++++++++++++++++++++++++++ drivers/video/fbconsole.c | 3 +++ include/fb.h | 2 ++ 4 files changed, 32 insertions(+) diff --git a/commands/fbtest.c b/commands/fbtest.c index bd0e140d07..ca6ec21991 100644 --- a/commands/fbtest.c +++ b/commands/fbtest.c @@ -169,6 +169,7 @@ static int do_fbtest(int argc, char *argv[]) pattern = patterns[i++ % ARRAY_SIZE(patterns)].func; pattern(sc, color); gu_screen_blit(sc); + fb_flush(sc->info); start = get_time_ns(); while (!is_timeout(start, 2 * SECOND)) diff --git a/drivers/video/fb.c b/drivers/video/fb.c index 4d2d3aa650..6b88f2df97 100644 --- a/drivers/video/fb.c +++ b/drivers/video/fb.c @@ -31,6 +31,30 @@ static int fb_ioctl(struct cdev* cdev, int req, void *data) return 0; } +static int fb_close(struct cdev *cdev) +{ + struct fb_info *info = cdev->priv; + + if (info->fbops->fb_flush) + info->fbops->fb_flush(info); + return 0; +} + +static int fb_op_flush(struct cdev *cdev) +{ + struct fb_info *info = cdev->priv; + + if (info->fbops->fb_flush) + info->fbops->fb_flush(info); + return 0; +} + +void fb_flush(struct fb_info *info) +{ + if (info->fbops->fb_flush) + info->fbops->fb_flush(info); +} + static void fb_release_shadowfb(struct fb_info *info) { free(info->screen_base_shadow); @@ -199,6 +223,8 @@ static struct file_operations fb_ops = { .memmap = generic_memmap_rw, .lseek = dev_lseek_default, .ioctl = fb_ioctl, + .close = fb_close, + .flush = fb_op_flush, }; static void fb_print_mode(struct fb_videomode *mode) diff --git a/drivers/video/fbconsole.c b/drivers/video/fbconsole.c index 64f7d7364e..4cf8338ed8 100644 --- a/drivers/video/fbconsole.c +++ b/drivers/video/fbconsole.c @@ -292,6 +292,7 @@ static void fbc_putc(struct console_device *cdev, char c) { struct fbc_priv *priv = container_of(cdev, struct fbc_priv, cdev); + struct fb_info *fb = priv->fb; if (priv->in_console) return; @@ -345,6 +346,8 @@ static void fbc_putc(struct console_device *cdev, char c) break; } priv->in_console = 0; + + fb_flush(fb); } static int setup_font(struct fbc_priv *priv) diff --git a/include/fb.h b/include/fb.h index b2a9c7152b..271b939968 100644 --- a/include/fb.h +++ b/include/fb.h @@ -86,6 +86,7 @@ struct fb_ops { void (*fb_enable)(struct fb_info *info); void (*fb_disable)(struct fb_info *info); int (*fb_activate_var)(struct fb_info *info); + void (*fb_flush)(struct fb_info *info); }; /* @@ -152,6 +153,7 @@ int register_framebuffer(struct fb_info *info); int fb_enable(struct fb_info *info); int fb_disable(struct fb_info *info); +void fb_flush(struct fb_info *info); #define FBIOGET_SCREENINFO _IOR('F', 1, loff_t) #define FBIO_ENABLE _IO('F', 2) -- 2.11.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 4/4] video: add support for Solomon SSD1307 OLED controller family 2017-02-24 14:24 [PATCH 0/4] Prepare consoles, add fb flush and Solomon SSD1307 OLED controller support Bastian Stender ` (2 preceding siblings ...) 2017-02-24 14:25 ` [PATCH 3/4] fb: introduce flush for virtual framebuffer Bastian Stender @ 2017-02-24 14:25 ` Bastian Stender 2017-02-24 16:10 ` Bastian Stender 2017-02-27 10:08 ` Sascha Hauer 3 siblings, 2 replies; 15+ messages in thread From: Bastian Stender @ 2017-02-24 14:25 UTC (permalink / raw) To: barebox; +Cc: Bastian Stender It was ported from linux v4.10. Like the kernel driver only communication via I2C is supported. It has only been tested with a SSD1306 and a 96x16 OLED display: &i2c0 { status = "okay"; ssd1306: oled@3c { compatible = "solomon,ssd1306fb-i2c"; reg = <0x3c>; reset-gpios = <&gpio1 1 0>; solomon,height = <16>; solomon,width = <96>; solomon,page-offset = <0>; solomon,com-invdir; solomon,com-seq; }; Signed-off-by: Bastian Stender <bst@pengutronix.de> --- drivers/video/Kconfig | 4 + drivers/video/Makefile | 1 + drivers/video/ssd1307fb.c | 569 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 574 insertions(+) create mode 100644 drivers/video/ssd1307fb.c diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 8f31f5af74..50a876acb1 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -12,6 +12,10 @@ config FRAMEBUFFER_CONSOLE select FONTS prompt "framebuffer console support" +config DRIVER_VIDEO_FB_SSD1307 + bool "Solomon SSD1307 framebuffer support" + depends on PWM && I2C && GPIOLIB + config VIDEO_VPL depends on OFTREE bool diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 1bf2e1f3ca..e23c9c37b6 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -21,3 +21,4 @@ obj-$(CONFIG_DRIVER_VIDEO_OMAP) += omap.o obj-$(CONFIG_DRIVER_VIDEO_BCM283X) += bcm2835.o obj-$(CONFIG_DRIVER_VIDEO_SIMPLEFB) += simplefb.o obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += imx-ipu-v3/ +obj-$(CONFIG_DRIVER_VIDEO_FB_SSD1307) += ssd1307fb.o diff --git a/drivers/video/ssd1307fb.c b/drivers/video/ssd1307fb.c new file mode 100644 index 0000000000..0dfdcc2232 --- /dev/null +++ b/drivers/video/ssd1307fb.c @@ -0,0 +1,569 @@ +/* + * Driver for the Solomon SSD1307 OLED controller family + * + * Supports: + * - SSD1305 (untested) + * - SSD1306 + * - SSD1307 (untested) + * - SSD1309 (untested) + * + * Copyright 2012 Maxime Ripard <maxime.ripard@free-electrons.com>, Free Electrons + * + * Ported to barebox from linux v4.10 + * Copyright (C) 2017 Pengutronix, Bastian Stender <kernel@pengutronix.de> + * + * Licensed under the GPLv2 or later. + */ + +#include <common.h> +#include <init.h> +#include <fb.h> +#include <i2c/i2c.h> +#include <of_device.h> +#include <gpio.h> +#include <of_gpio.h> +#include <printk.h> + +#define SSD1307FB_DATA 0x40 +#define SSD1307FB_COMMAND 0x80 + +#define SSD1307FB_SET_ADDRESS_MODE 0x20 +#define SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL (0x00) +#define SSD1307FB_SET_ADDRESS_MODE_VERTICAL (0x01) +#define SSD1307FB_SET_ADDRESS_MODE_PAGE (0x02) +#define SSD1307FB_SET_COL_RANGE 0x21 +#define SSD1307FB_SET_PAGE_RANGE 0x22 +#define SSD1307FB_CONTRAST 0x81 +#define SSD1307FB_CHARGE_PUMP 0x8d +#define SSD1307FB_SEG_REMAP_ON 0xa1 +#define SSD1307FB_DISPLAY_OFF 0xae +#define SSD1307FB_SET_MULTIPLEX_RATIO 0xa8 +#define SSD1307FB_DISPLAY_ON 0xaf +#define SSD1307FB_START_PAGE_ADDRESS 0xb0 +#define SSD1307FB_SET_DISPLAY_OFFSET 0xd3 +#define SSD1307FB_SET_CLOCK_FREQ 0xd5 +#define SSD1307FB_SET_PRECHARGE_PERIOD 0xd9 +#define SSD1307FB_SET_COM_PINS_CONFIG 0xda +#define SSD1307FB_SET_VCOMH 0xdb + +struct ssd1307fb_par; + +struct ssd1307fb_deviceinfo { + u32 default_vcomh; + u32 default_dclk_div; + u32 default_dclk_frq; + int need_chargepump; +}; + +struct ssd1307fb_par { + u32 com_invdir; + u32 com_lrremap; + u32 com_offset; + u32 com_seq; + u32 contrast; + u32 dclk_div; + u32 dclk_frq; + const struct ssd1307fb_deviceinfo *device_info; + struct i2c_client *client; + u32 height; + struct fb_info *info; + u32 page_offset; + u32 prechargep1; + u32 prechargep2; + int reset; + u32 seg_remap; + u32 vcomh; + u32 width; +}; + +struct ssd1307fb_array { + u8 type; + u8 data[0]; +}; + +static struct ssd1307fb_array *ssd1307fb_alloc_array(u32 len, u8 type) +{ + struct ssd1307fb_array *array; + + array = kzalloc(sizeof(struct ssd1307fb_array) + len, GFP_KERNEL); + if (!array) + return NULL; + + array->type = type; + + return array; +} + +static int ssd1307fb_write_array(struct i2c_client *client, + struct ssd1307fb_array *array, u32 len) +{ + int ret; + + len += sizeof(struct ssd1307fb_array); + + ret = i2c_master_send(client, (u8 *)array, len); + if (ret != len) { + dev_err(&client->dev, "Couldn't send I2C command.\n"); + return ret; + } + + return 0; +} + +static inline int ssd1307fb_write_cmd(struct i2c_client *client, u8 cmd) +{ + struct ssd1307fb_array *array; + int ret; + + array = ssd1307fb_alloc_array(1, SSD1307FB_COMMAND); + if (!array) + return -ENOMEM; + + array->data[0] = cmd; + + ret = ssd1307fb_write_array(client, array, 1); + kfree(array); + + return ret; +} + +static void ssd1307fb_update_display(struct ssd1307fb_par *par) +{ + struct ssd1307fb_array *array; + u8 *vmem = par->info->screen_base; + int i, j, k; + + array = ssd1307fb_alloc_array(par->width * par->height / 8, + SSD1307FB_DATA); + if (!array) + return; + + /* + * The screen is divided in pages, each having a height of 8 + * pixels, and the width of the screen. When sending a byte of + * data to the controller, it gives the 8 bits for the current + * column. I.e, the first byte are the 8 bits of the first + * column, then the 8 bits for the second column, etc. + * + * + * Representation of the screen, assuming it is 5 bits + * wide. Each letter-number combination is a bit that controls + * one pixel. + * + * A0 A1 A2 A3 A4 + * B0 B1 B2 B3 B4 + * C0 C1 C2 C3 C4 + * D0 D1 D2 D3 D4 + * E0 E1 E2 E3 E4 + * F0 F1 F2 F3 F4 + * G0 G1 G2 G3 G4 + * H0 H1 H2 H3 H4 + * + * If you want to update this screen, you need to send 5 bytes: + * (1) A0 B0 C0 D0 E0 F0 G0 H0 + * (2) A1 B1 C1 D1 E1 F1 G1 H1 + * (3) A2 B2 C2 D2 E2 F2 G2 H2 + * (4) A3 B3 C3 D3 E3 F3 G3 H3 + * (5) A4 B4 C4 D4 E4 F4 G4 H4 + */ + + for (i = 0; i < (par->height / 8); i++) { + for (j = 0; j < par->width; j++) { + u32 array_idx = i * par->width + j; + array->data[array_idx] = 0; + for (k = 0; k < 8; k++) { + u32 page_length = par->width * i * 8; + u32 index = page_length + (par->width * k + j); + u8 byte = *(vmem + index); + /* convert to 1 bit per pixel */ + u8 bit = byte > 0; + array->data[array_idx] |= bit << k; + } + } + } + + ssd1307fb_write_array(par->client, array, par->width * par->height / 8); + kfree(array); +} + +static void ssd1307fb_enable(struct fb_info *info) +{ + struct ssd1307fb_par *par = info->priv; + ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON); +} + +static void ssd1307fb_disable(struct fb_info *info) +{ + struct ssd1307fb_par *par = info->priv; + ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_OFF); +} + +static void ssd1307fb_flush(struct fb_info *info) +{ + struct ssd1307fb_par *par = info->priv; + ssd1307fb_update_display(par); +} + +static struct fb_ops ssd1307fb_ops = { + .fb_enable = ssd1307fb_enable, + .fb_disable = ssd1307fb_disable, + .fb_flush = ssd1307fb_flush, +}; + +static int ssd1307fb_init(struct ssd1307fb_par *par) +{ + int ret; + u32 precharge, dclk, com_invdir, compins; + + /* Set initial contrast */ + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CONTRAST); + if (ret < 0) + return ret; + + ret = ssd1307fb_write_cmd(par->client, par->contrast); + if (ret < 0) + return ret; + + /* Set segment re-map */ + if (par->seg_remap) { + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SEG_REMAP_ON); + if (ret < 0) + return ret; + }; + + /* Set COM direction */ + com_invdir = 0xc0 | (par->com_invdir & 0x1) << 3; + ret = ssd1307fb_write_cmd(par->client, com_invdir); + if (ret < 0) + return ret; + + /* Set multiplex ratio value */ + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_MULTIPLEX_RATIO); + if (ret < 0) + return ret; + + ret = ssd1307fb_write_cmd(par->client, par->height - 1); + if (ret < 0) + return ret; + + /* set display offset value */ + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_DISPLAY_OFFSET); + if (ret < 0) + return ret; + + ret = ssd1307fb_write_cmd(par->client, par->com_offset); + if (ret < 0) + return ret; + + /* Set clock frequency */ + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_CLOCK_FREQ); + if (ret < 0) + return ret; + + dclk = ((par->dclk_div - 1) & 0xf) | (par->dclk_frq & 0xf) << 4; + ret = ssd1307fb_write_cmd(par->client, dclk); + if (ret < 0) + return ret; + + /* Set precharge period in number of ticks from the internal clock */ + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PRECHARGE_PERIOD); + if (ret < 0) + return ret; + + precharge = (par->prechargep1 & 0xf) | (par->prechargep2 & 0xf) << 4; + ret = ssd1307fb_write_cmd(par->client, precharge); + if (ret < 0) + return ret; + + /* Set COM pins configuration */ + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COM_PINS_CONFIG); + if (ret < 0) + return ret; + + compins = 0x02 | !(par->com_seq & 0x1) << 4 + | (par->com_lrremap & 0x1) << 5; + ret = ssd1307fb_write_cmd(par->client, compins); + if (ret < 0) + return ret; + + /* Set VCOMH */ + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_VCOMH); + if (ret < 0) + return ret; + + ret = ssd1307fb_write_cmd(par->client, par->vcomh); + if (ret < 0) + return ret; + + /* Turn on the DC-DC Charge Pump */ + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CHARGE_PUMP); + if (ret < 0) + return ret; + + ret = ssd1307fb_write_cmd(par->client, + BIT(4) | (par->device_info->need_chargepump ? BIT(2) : 0)); + if (ret < 0) + return ret; + + /* Switch to horizontal addressing mode */ + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_ADDRESS_MODE); + if (ret < 0) + return ret; + + ret = ssd1307fb_write_cmd(par->client, + SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL); + if (ret < 0) + return ret; + + /* Set column range */ + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COL_RANGE); + if (ret < 0) + return ret; + + ret = ssd1307fb_write_cmd(par->client, 0x0); + if (ret < 0) + return ret; + + ret = ssd1307fb_write_cmd(par->client, par->width - 1); + if (ret < 0) + return ret; + + /* Set page range */ + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PAGE_RANGE); + if (ret < 0) + return ret; + + ret = ssd1307fb_write_cmd(par->client, 0x0); + if (ret < 0) + return ret; + + ret = ssd1307fb_write_cmd(par->client, + par->page_offset + (par->height / 8) - 1); + if (ret < 0) + return ret; + + /* Turn on the display */ + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON); + if (ret < 0) + return ret; + + return 0; +} + +static struct ssd1307fb_deviceinfo ssd1307fb_ssd1305_deviceinfo = { + .default_vcomh = 0x34, + .default_dclk_div = 1, + .default_dclk_frq = 7, +}; + +static struct ssd1307fb_deviceinfo ssd1307fb_ssd1306_deviceinfo = { + .default_vcomh = 0x20, + .default_dclk_div = 1, + .default_dclk_frq = 8, + .need_chargepump = 1, +}; + +static struct ssd1307fb_deviceinfo ssd1307fb_ssd1307_deviceinfo = { + .default_vcomh = 0x20, + .default_dclk_div = 2, + .default_dclk_frq = 12, +}; + +static struct ssd1307fb_deviceinfo ssd1307fb_ssd1309_deviceinfo = { + .default_vcomh = 0x34, + .default_dclk_div = 1, + .default_dclk_frq = 10, +}; + +static const struct of_device_id ssd1307fb_of_match[] = { + { + .compatible = "solomon,ssd1305fb-i2c", + .data = (void *)&ssd1307fb_ssd1305_deviceinfo, + }, + { + .compatible = "solomon,ssd1306fb-i2c", + .data = (void *)&ssd1307fb_ssd1306_deviceinfo, + }, + { + .compatible = "solomon,ssd1307fb-i2c", + .data = (void *)&ssd1307fb_ssd1307_deviceinfo, + }, + { + .compatible = "solomon,ssd1309fb-i2c", + .data = (void *)&ssd1307fb_ssd1309_deviceinfo, + }, + {}, +}; + +static int ssd1307fb_probe(struct device_d *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct fb_info *info; + struct device_node *node = dev->device_node; + const struct of_device_id *match = + of_match_node(ssd1307fb_of_match, dev->device_node); + u32 vmem_size; + struct ssd1307fb_par *par; + struct ssd1307fb_array *array; + u8 *vmem; + int ret; + int i, j; + + if (!node) { + dev_err(&client->dev, "No device tree data found!\n"); + return -EINVAL; + } + + info = xzalloc(sizeof(struct fb_info)); + if (!info) { + dev_err(&client->dev, "Couldn't allocate framebuffer.\n"); + return -ENOMEM; + } + + par = info->priv; + par->info = info; + par->client = client; + + par->device_info = (struct ssd1307fb_deviceinfo *)match->data; + + par->reset = of_get_named_gpio(node, + "reset-gpios", 0); + if (!gpio_is_valid(par->reset)) { + dev_err(&client->dev, + "Couldn't get named gpio 'reset-gpios' %d.\n", + par->reset); + ret = par->reset; + goto fb_alloc_error; + } + + if (of_property_read_u32(node, "solomon,width", &par->width)) + par->width = 96; + + if (of_property_read_u32(node, "solomon,height", &par->height)) + par->height = 16; + + if (of_property_read_u32(node, "solomon,page-offset", + &par->page_offset)) + par->page_offset = 1; + + if (of_property_read_u32(node, "solomon,com-offset", &par->com_offset)) + par->com_offset = 0; + + if (of_property_read_u32(node, "solomon,prechargep1", + &par->prechargep1)) + par->prechargep1 = 2; + + if (of_property_read_u32(node, "solomon,prechargep2", + &par->prechargep2)) + par->prechargep2 = 2; + + par->seg_remap = !of_property_read_bool(node, + "solomon,segment-no-remap"); + par->com_seq = of_property_read_bool(node, "solomon,com-seq"); + par->com_lrremap = of_property_read_bool(node, "solomon,com-lrremap"); + par->com_invdir = of_property_read_bool(node, "solomon,com-invdir"); + + par->contrast = 127; + par->vcomh = par->device_info->default_vcomh; + + /* Setup display timing */ + par->dclk_div = par->device_info->default_dclk_div; + par->dclk_frq = par->device_info->default_dclk_frq; + + vmem_size = par->width * par->height; + + vmem = malloc(vmem_size); + if (!vmem) { + dev_err(&client->dev, "Couldn't allocate graphical memory.\n"); + ret = -ENOMEM; + goto fb_alloc_error; + } + + info->fbops = &ssd1307fb_ops; + info->line_length = par->width; + + info->xres = par->width; + info->yres = par->height; + + /* emulate 8 bit per pixel */ + info->bits_per_pixel = 8; + + info->red.length = 3; + info->red.offset = 0; + info->green.length = 3; + info->green.offset = 0; + info->blue.length = 2; + info->blue.offset = 0; + + info->screen_base = (u8 __force __iomem *)vmem; + + ret = gpio_request_one(par->reset, + GPIOF_OUT_INIT_HIGH, + "oled-reset"); + if (ret) { + dev_err(&client->dev, + "failed to request gpio %d: %d\n", + par->reset, ret); + goto reset_oled_error; + } + + i2c_set_clientdata(client, info); + + /* Reset the screen */ + gpio_set_value(par->reset, 0); + udelay(4); + gpio_set_value(par->reset, 1); + udelay(4); + + ret = ssd1307fb_init(par); + if (ret) + goto reset_oled_error; + + ret = register_framebuffer(info); + if (ret) { + dev_err(&client->dev, "Couldn't register the framebuffer\n"); + goto panel_init_error; + } + + /* clear display */ + array = ssd1307fb_alloc_array(par->width * par->height / 8, + SSD1307FB_DATA); + if (!array) + return -ENOMEM; + + for (i = 0; i < (par->height / 8); i++) { + for (j = 0; j < par->width; j++) { + u32 array_idx = i * par->width + j; + array->data[array_idx] = 0; + } + } + + ssd1307fb_write_array(par->client, array, par->width * par->height / 8); + kfree(array); + + dev_info(&client->dev, + "ssd1307 framebuffer device registered, using %d bytes of video memory\n", + vmem_size); + + return 0; + +panel_init_error: +reset_oled_error: +fb_alloc_error: + free(info); + return ret; +} + +static struct driver_d ssd1307fb_driver = { + .name = "ssd1307fb", + .probe = ssd1307fb_probe, + .of_compatible = DRV_OF_COMPAT(ssd1307fb_of_match), +}; + +static int ssd1307_init(void) +{ + i2c_driver_register(&ssd1307fb_driver); + return 0; +} + +device_initcall(ssd1307_init); -- 2.11.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 4/4] video: add support for Solomon SSD1307 OLED controller family 2017-02-24 14:25 ` [PATCH 4/4] video: add support for Solomon SSD1307 OLED controller family Bastian Stender @ 2017-02-24 16:10 ` Bastian Stender 2017-02-27 10:08 ` Sascha Hauer 1 sibling, 0 replies; 15+ messages in thread From: Bastian Stender @ 2017-02-24 16:10 UTC (permalink / raw) To: barebox On 02/24/2017 03:25 PM, Bastian Stender wrote: > It was ported from linux v4.10. Like the kernel driver only > communication via I2C is supported. > > It has only been tested with a SSD1306 and a 96x16 OLED display: > > &i2c0 { > status = "okay"; > > ssd1306: oled@3c { > compatible = "solomon,ssd1306fb-i2c"; > reg = <0x3c>; > reset-gpios = <&gpio1 1 0>; > solomon,height = <16>; > solomon,width = <96>; > solomon,page-offset = <0>; > solomon,com-invdir; > solomon,com-seq; > }; > > Signed-off-by: Bastian Stender <bst@pengutronix.de> > --- > drivers/video/Kconfig | 4 + > drivers/video/Makefile | 1 + > drivers/video/ssd1307fb.c | 569 ++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 574 insertions(+) > create mode 100644 drivers/video/ssd1307fb.c > > diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig > index 8f31f5af74..50a876acb1 100644 > --- a/drivers/video/Kconfig > +++ b/drivers/video/Kconfig > @@ -12,6 +12,10 @@ config FRAMEBUFFER_CONSOLE > select FONTS > prompt "framebuffer console support" > > +config DRIVER_VIDEO_FB_SSD1307 > + bool "Solomon SSD1307 framebuffer support" > + depends on PWM && I2C && GPIOLIB Oops, it actually does not depend on PWM. Only the SSD1307 needs PWM, but I did not port that part as I have no way to test it. I should probably mention that. > + > config VIDEO_VPL > depends on OFTREE > bool > diff --git a/drivers/video/Makefile b/drivers/video/Makefile > index 1bf2e1f3ca..e23c9c37b6 100644 > --- a/drivers/video/Makefile > +++ b/drivers/video/Makefile > @@ -21,3 +21,4 @@ obj-$(CONFIG_DRIVER_VIDEO_OMAP) += omap.o > obj-$(CONFIG_DRIVER_VIDEO_BCM283X) += bcm2835.o > obj-$(CONFIG_DRIVER_VIDEO_SIMPLEFB) += simplefb.o > obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += imx-ipu-v3/ > +obj-$(CONFIG_DRIVER_VIDEO_FB_SSD1307) += ssd1307fb.o > diff --git a/drivers/video/ssd1307fb.c b/drivers/video/ssd1307fb.c > new file mode 100644 > index 0000000000..0dfdcc2232 > --- /dev/null > +++ b/drivers/video/ssd1307fb.c > @@ -0,0 +1,569 @@ > +/* > + * Driver for the Solomon SSD1307 OLED controller family > + * > + * Supports: > + * - SSD1305 (untested) > + * - SSD1306 > + * - SSD1307 (untested) Remove that for now. > + * - SSD1309 (untested) > + * > + * Copyright 2012 Maxime Ripard <maxime.ripard@free-electrons.com>, Free Electrons > + * > + * Ported to barebox from linux v4.10 > + * Copyright (C) 2017 Pengutronix, Bastian Stender <kernel@pengutronix.de> > + * > + * Licensed under the GPLv2 or later. > + */ > + > +#include <common.h> > +#include <init.h> > +#include <fb.h> > +#include <i2c/i2c.h> > +#include <of_device.h> > +#include <gpio.h> > +#include <of_gpio.h> > +#include <printk.h> > + > +#define SSD1307FB_DATA 0x40 > +#define SSD1307FB_COMMAND 0x80 > + > +#define SSD1307FB_SET_ADDRESS_MODE 0x20 > +#define SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL (0x00) > +#define SSD1307FB_SET_ADDRESS_MODE_VERTICAL (0x01) > +#define SSD1307FB_SET_ADDRESS_MODE_PAGE (0x02) > +#define SSD1307FB_SET_COL_RANGE 0x21 > +#define SSD1307FB_SET_PAGE_RANGE 0x22 > +#define SSD1307FB_CONTRAST 0x81 > +#define SSD1307FB_CHARGE_PUMP 0x8d > +#define SSD1307FB_SEG_REMAP_ON 0xa1 > +#define SSD1307FB_DISPLAY_OFF 0xae > +#define SSD1307FB_SET_MULTIPLEX_RATIO 0xa8 > +#define SSD1307FB_DISPLAY_ON 0xaf > +#define SSD1307FB_START_PAGE_ADDRESS 0xb0 > +#define SSD1307FB_SET_DISPLAY_OFFSET 0xd3 > +#define SSD1307FB_SET_CLOCK_FREQ 0xd5 > +#define SSD1307FB_SET_PRECHARGE_PERIOD 0xd9 > +#define SSD1307FB_SET_COM_PINS_CONFIG 0xda > +#define SSD1307FB_SET_VCOMH 0xdb > + > +struct ssd1307fb_par; > + > +struct ssd1307fb_deviceinfo { > + u32 default_vcomh; > + u32 default_dclk_div; > + u32 default_dclk_frq; > + int need_chargepump; > +}; > + > +struct ssd1307fb_par { > + u32 com_invdir; > + u32 com_lrremap; > + u32 com_offset; > + u32 com_seq; > + u32 contrast; > + u32 dclk_div; > + u32 dclk_frq; > + const struct ssd1307fb_deviceinfo *device_info; > + struct i2c_client *client; > + u32 height; > + struct fb_info *info; > + u32 page_offset; > + u32 prechargep1; > + u32 prechargep2; > + int reset; > + u32 seg_remap; > + u32 vcomh; > + u32 width; > +}; > + > +struct ssd1307fb_array { > + u8 type; > + u8 data[0]; > +}; > + > +static struct ssd1307fb_array *ssd1307fb_alloc_array(u32 len, u8 type) > +{ > + struct ssd1307fb_array *array; > + > + array = kzalloc(sizeof(struct ssd1307fb_array) + len, GFP_KERNEL); > + if (!array) > + return NULL; > + > + array->type = type; > + > + return array; > +} > + > +static int ssd1307fb_write_array(struct i2c_client *client, > + struct ssd1307fb_array *array, u32 len) > +{ > + int ret; > + > + len += sizeof(struct ssd1307fb_array); > + > + ret = i2c_master_send(client, (u8 *)array, len); > + if (ret != len) { > + dev_err(&client->dev, "Couldn't send I2C command.\n"); > + return ret; > + } > + > + return 0; > +} > + > +static inline int ssd1307fb_write_cmd(struct i2c_client *client, u8 cmd) > +{ > + struct ssd1307fb_array *array; > + int ret; > + > + array = ssd1307fb_alloc_array(1, SSD1307FB_COMMAND); > + if (!array) > + return -ENOMEM; > + > + array->data[0] = cmd; > + > + ret = ssd1307fb_write_array(client, array, 1); > + kfree(array); > + > + return ret; > +} > + > +static void ssd1307fb_update_display(struct ssd1307fb_par *par) > +{ > + struct ssd1307fb_array *array; > + u8 *vmem = par->info->screen_base; > + int i, j, k; > + > + array = ssd1307fb_alloc_array(par->width * par->height / 8, > + SSD1307FB_DATA); > + if (!array) > + return; > + > + /* > + * The screen is divided in pages, each having a height of 8 > + * pixels, and the width of the screen. When sending a byte of > + * data to the controller, it gives the 8 bits for the current > + * column. I.e, the first byte are the 8 bits of the first > + * column, then the 8 bits for the second column, etc. > + * > + * > + * Representation of the screen, assuming it is 5 bits > + * wide. Each letter-number combination is a bit that controls > + * one pixel. > + * > + * A0 A1 A2 A3 A4 > + * B0 B1 B2 B3 B4 > + * C0 C1 C2 C3 C4 > + * D0 D1 D2 D3 D4 > + * E0 E1 E2 E3 E4 > + * F0 F1 F2 F3 F4 > + * G0 G1 G2 G3 G4 > + * H0 H1 H2 H3 H4 > + * > + * If you want to update this screen, you need to send 5 bytes: > + * (1) A0 B0 C0 D0 E0 F0 G0 H0 > + * (2) A1 B1 C1 D1 E1 F1 G1 H1 > + * (3) A2 B2 C2 D2 E2 F2 G2 H2 > + * (4) A3 B3 C3 D3 E3 F3 G3 H3 > + * (5) A4 B4 C4 D4 E4 F4 G4 H4 > + */ > + > + for (i = 0; i < (par->height / 8); i++) { > + for (j = 0; j < par->width; j++) { > + u32 array_idx = i * par->width + j; > + array->data[array_idx] = 0; > + for (k = 0; k < 8; k++) { > + u32 page_length = par->width * i * 8; > + u32 index = page_length + (par->width * k + j); > + u8 byte = *(vmem + index); > + /* convert to 1 bit per pixel */ > + u8 bit = byte > 0; > + array->data[array_idx] |= bit << k; > + } > + } > + } > + > + ssd1307fb_write_array(par->client, array, par->width * par->height / 8); > + kfree(array); > +} > + > +static void ssd1307fb_enable(struct fb_info *info) > +{ > + struct ssd1307fb_par *par = info->priv; > + ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON); > +} > + > +static void ssd1307fb_disable(struct fb_info *info) > +{ > + struct ssd1307fb_par *par = info->priv; > + ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_OFF); > +} > + > +static void ssd1307fb_flush(struct fb_info *info) > +{ > + struct ssd1307fb_par *par = info->priv; > + ssd1307fb_update_display(par); > +} > + > +static struct fb_ops ssd1307fb_ops = { > + .fb_enable = ssd1307fb_enable, > + .fb_disable = ssd1307fb_disable, > + .fb_flush = ssd1307fb_flush, > +}; > + > +static int ssd1307fb_init(struct ssd1307fb_par *par) > +{ > + int ret; > + u32 precharge, dclk, com_invdir, compins; > + > + /* Set initial contrast */ > + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CONTRAST); > + if (ret < 0) > + return ret; > + > + ret = ssd1307fb_write_cmd(par->client, par->contrast); > + if (ret < 0) > + return ret; > + > + /* Set segment re-map */ > + if (par->seg_remap) { > + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SEG_REMAP_ON); > + if (ret < 0) > + return ret; > + }; > + > + /* Set COM direction */ > + com_invdir = 0xc0 | (par->com_invdir & 0x1) << 3; > + ret = ssd1307fb_write_cmd(par->client, com_invdir); > + if (ret < 0) > + return ret; > + > + /* Set multiplex ratio value */ > + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_MULTIPLEX_RATIO); > + if (ret < 0) > + return ret; > + > + ret = ssd1307fb_write_cmd(par->client, par->height - 1); > + if (ret < 0) > + return ret; > + > + /* set display offset value */ > + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_DISPLAY_OFFSET); > + if (ret < 0) > + return ret; > + > + ret = ssd1307fb_write_cmd(par->client, par->com_offset); > + if (ret < 0) > + return ret; > + > + /* Set clock frequency */ > + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_CLOCK_FREQ); > + if (ret < 0) > + return ret; > + > + dclk = ((par->dclk_div - 1) & 0xf) | (par->dclk_frq & 0xf) << 4; > + ret = ssd1307fb_write_cmd(par->client, dclk); > + if (ret < 0) > + return ret; > + > + /* Set precharge period in number of ticks from the internal clock */ > + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PRECHARGE_PERIOD); > + if (ret < 0) > + return ret; > + > + precharge = (par->prechargep1 & 0xf) | (par->prechargep2 & 0xf) << 4; > + ret = ssd1307fb_write_cmd(par->client, precharge); > + if (ret < 0) > + return ret; > + > + /* Set COM pins configuration */ > + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COM_PINS_CONFIG); > + if (ret < 0) > + return ret; > + > + compins = 0x02 | !(par->com_seq & 0x1) << 4 > + | (par->com_lrremap & 0x1) << 5; > + ret = ssd1307fb_write_cmd(par->client, compins); > + if (ret < 0) > + return ret; > + > + /* Set VCOMH */ > + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_VCOMH); > + if (ret < 0) > + return ret; > + > + ret = ssd1307fb_write_cmd(par->client, par->vcomh); > + if (ret < 0) > + return ret; > + > + /* Turn on the DC-DC Charge Pump */ > + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CHARGE_PUMP); > + if (ret < 0) > + return ret; > + > + ret = ssd1307fb_write_cmd(par->client, > + BIT(4) | (par->device_info->need_chargepump ? BIT(2) : 0)); > + if (ret < 0) > + return ret; > + > + /* Switch to horizontal addressing mode */ > + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_ADDRESS_MODE); > + if (ret < 0) > + return ret; > + > + ret = ssd1307fb_write_cmd(par->client, > + SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL); > + if (ret < 0) > + return ret; > + > + /* Set column range */ > + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COL_RANGE); > + if (ret < 0) > + return ret; > + > + ret = ssd1307fb_write_cmd(par->client, 0x0); > + if (ret < 0) > + return ret; > + > + ret = ssd1307fb_write_cmd(par->client, par->width - 1); > + if (ret < 0) > + return ret; > + > + /* Set page range */ > + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PAGE_RANGE); > + if (ret < 0) > + return ret; > + > + ret = ssd1307fb_write_cmd(par->client, 0x0); > + if (ret < 0) > + return ret; > + > + ret = ssd1307fb_write_cmd(par->client, > + par->page_offset + (par->height / 8) - 1); > + if (ret < 0) > + return ret; > + > + /* Turn on the display */ > + ret = ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON); > + if (ret < 0) > + return ret; > + > + return 0; > +} > + > +static struct ssd1307fb_deviceinfo ssd1307fb_ssd1305_deviceinfo = { > + .default_vcomh = 0x34, > + .default_dclk_div = 1, > + .default_dclk_frq = 7, > +}; > + > +static struct ssd1307fb_deviceinfo ssd1307fb_ssd1306_deviceinfo = { > + .default_vcomh = 0x20, > + .default_dclk_div = 1, > + .default_dclk_frq = 8, > + .need_chargepump = 1, > +}; > + > +static struct ssd1307fb_deviceinfo ssd1307fb_ssd1307_deviceinfo = { > + .default_vcomh = 0x20, > + .default_dclk_div = 2, > + .default_dclk_frq = 12, > +}; Remove this too. > + > +static struct ssd1307fb_deviceinfo ssd1307fb_ssd1309_deviceinfo = { > + .default_vcomh = 0x34, > + .default_dclk_div = 1, > + .default_dclk_frq = 10, > +}; > + > +static const struct of_device_id ssd1307fb_of_match[] = { > + { > + .compatible = "solomon,ssd1305fb-i2c", > + .data = (void *)&ssd1307fb_ssd1305_deviceinfo, > + }, > + { > + .compatible = "solomon,ssd1306fb-i2c", > + .data = (void *)&ssd1307fb_ssd1306_deviceinfo, > + }, > + { > + .compatible = "solomon,ssd1307fb-i2c", > + .data = (void *)&ssd1307fb_ssd1307_deviceinfo, > + }, Remove this too. > + { > + .compatible = "solomon,ssd1309fb-i2c", > + .data = (void *)&ssd1307fb_ssd1309_deviceinfo, > + }, > + {}, > +}; > + > +static int ssd1307fb_probe(struct device_d *dev) > +{ > + struct i2c_client *client = to_i2c_client(dev); > + struct fb_info *info; > + struct device_node *node = dev->device_node; > + const struct of_device_id *match = > + of_match_node(ssd1307fb_of_match, dev->device_node); > + u32 vmem_size; > + struct ssd1307fb_par *par; > + struct ssd1307fb_array *array; > + u8 *vmem; > + int ret; > + int i, j; > + > + if (!node) { > + dev_err(&client->dev, "No device tree data found!\n"); > + return -EINVAL; > + } > + > + info = xzalloc(sizeof(struct fb_info)); > + if (!info) { > + dev_err(&client->dev, "Couldn't allocate framebuffer.\n"); > + return -ENOMEM; > + } > + > + par = info->priv; > + par->info = info; > + par->client = client; > + > + par->device_info = (struct ssd1307fb_deviceinfo *)match->data; > + > + par->reset = of_get_named_gpio(node, > + "reset-gpios", 0); > + if (!gpio_is_valid(par->reset)) { > + dev_err(&client->dev, > + "Couldn't get named gpio 'reset-gpios' %d.\n", > + par->reset); > + ret = par->reset; > + goto fb_alloc_error; > + } > + > + if (of_property_read_u32(node, "solomon,width", &par->width)) > + par->width = 96; > + > + if (of_property_read_u32(node, "solomon,height", &par->height)) > + par->height = 16; > + > + if (of_property_read_u32(node, "solomon,page-offset", > + &par->page_offset)) > + par->page_offset = 1; > + > + if (of_property_read_u32(node, "solomon,com-offset", &par->com_offset)) > + par->com_offset = 0; > + > + if (of_property_read_u32(node, "solomon,prechargep1", > + &par->prechargep1)) > + par->prechargep1 = 2; > + > + if (of_property_read_u32(node, "solomon,prechargep2", > + &par->prechargep2)) > + par->prechargep2 = 2; > + > + par->seg_remap = !of_property_read_bool(node, > + "solomon,segment-no-remap"); > + par->com_seq = of_property_read_bool(node, "solomon,com-seq"); > + par->com_lrremap = of_property_read_bool(node, "solomon,com-lrremap"); > + par->com_invdir = of_property_read_bool(node, "solomon,com-invdir"); > + > + par->contrast = 127; > + par->vcomh = par->device_info->default_vcomh; > + > + /* Setup display timing */ > + par->dclk_div = par->device_info->default_dclk_div; > + par->dclk_frq = par->device_info->default_dclk_frq; > + > + vmem_size = par->width * par->height; > + > + vmem = malloc(vmem_size); > + if (!vmem) { > + dev_err(&client->dev, "Couldn't allocate graphical memory.\n"); > + ret = -ENOMEM; > + goto fb_alloc_error; > + } > + > + info->fbops = &ssd1307fb_ops; > + info->line_length = par->width; > + > + info->xres = par->width; > + info->yres = par->height; > + > + /* emulate 8 bit per pixel */ > + info->bits_per_pixel = 8; > + > + info->red.length = 3; > + info->red.offset = 0; > + info->green.length = 3; > + info->green.offset = 0; > + info->blue.length = 2; > + info->blue.offset = 0; > + > + info->screen_base = (u8 __force __iomem *)vmem; > + > + ret = gpio_request_one(par->reset, > + GPIOF_OUT_INIT_HIGH, > + "oled-reset"); > + if (ret) { > + dev_err(&client->dev, > + "failed to request gpio %d: %d\n", > + par->reset, ret); > + goto reset_oled_error; > + } > + > + i2c_set_clientdata(client, info); > + > + /* Reset the screen */ > + gpio_set_value(par->reset, 0); > + udelay(4); > + gpio_set_value(par->reset, 1); > + udelay(4); > + > + ret = ssd1307fb_init(par); > + if (ret) > + goto reset_oled_error; > + > + ret = register_framebuffer(info); > + if (ret) { > + dev_err(&client->dev, "Couldn't register the framebuffer\n"); > + goto panel_init_error; > + } > + > + /* clear display */ > + array = ssd1307fb_alloc_array(par->width * par->height / 8, > + SSD1307FB_DATA); > + if (!array) > + return -ENOMEM; > + > + for (i = 0; i < (par->height / 8); i++) { > + for (j = 0; j < par->width; j++) { > + u32 array_idx = i * par->width + j; > + array->data[array_idx] = 0; > + } > + } > + > + ssd1307fb_write_array(par->client, array, par->width * par->height / 8); > + kfree(array); > + > + dev_info(&client->dev, > + "ssd1307 framebuffer device registered, using %d bytes of video memory\n", > + vmem_size); > + > + return 0; > + > +panel_init_error: > +reset_oled_error: > +fb_alloc_error: > + free(info); > + return ret; > +} > + > +static struct driver_d ssd1307fb_driver = { > + .name = "ssd1307fb", > + .probe = ssd1307fb_probe, > + .of_compatible = DRV_OF_COMPAT(ssd1307fb_of_match), > +}; > + > +static int ssd1307_init(void) > +{ > + i2c_driver_register(&ssd1307fb_driver); > + return 0; > +} > + > +device_initcall(ssd1307_init); > If anybody is confident enough to port the pwm parts or can actually test this, we can add SSD1307 compatability again. I will send a reworked version of this patch, but for now I'll wait for some more review. Regards, Bastian -- Pengutronix e.K. Industrial Linux Solutions http://www.pengutronix.de/ Peiner Str. 6-8, 31137 Hildesheim, Germany Amtsgericht Hildesheim, HRA 2686 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 4/4] video: add support for Solomon SSD1307 OLED controller family 2017-02-24 14:25 ` [PATCH 4/4] video: add support for Solomon SSD1307 OLED controller family Bastian Stender 2017-02-24 16:10 ` Bastian Stender @ 2017-02-27 10:08 ` Sascha Hauer 2017-02-27 15:45 ` Bastian Stender 1 sibling, 1 reply; 15+ messages in thread From: Sascha Hauer @ 2017-02-27 10:08 UTC (permalink / raw) To: Bastian Stender; +Cc: barebox On Fri, Feb 24, 2017 at 03:25:01PM +0100, Bastian Stender wrote: > It was ported from linux v4.10. Like the kernel driver only > communication via I2C is supported. > > It has only been tested with a SSD1306 and a 96x16 OLED display: > > &i2c0 { > status = "okay"; > > ssd1306: oled@3c { > compatible = "solomon,ssd1306fb-i2c"; > reg = <0x3c>; > reset-gpios = <&gpio1 1 0>; > solomon,height = <16>; > solomon,width = <96>; > solomon,page-offset = <0>; > solomon,com-invdir; > solomon,com-seq; > }; > > Signed-off-by: Bastian Stender <bst@pengutronix.de> > --- > drivers/video/Kconfig | 4 + > drivers/video/Makefile | 1 + > drivers/video/ssd1307fb.c | 569 ++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 574 insertions(+) > create mode 100644 drivers/video/ssd1307fb.c > > diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig > index 8f31f5af74..50a876acb1 100644 > --- a/drivers/video/Kconfig > +++ b/drivers/video/Kconfig > @@ -12,6 +12,10 @@ config FRAMEBUFFER_CONSOLE > select FONTS > prompt "framebuffer console support" > > +config DRIVER_VIDEO_FB_SSD1307 > + bool "Solomon SSD1307 framebuffer support" > + depends on PWM && I2C && GPIOLIB > + > config VIDEO_VPL > depends on OFTREE > bool > diff --git a/drivers/video/Makefile b/drivers/video/Makefile > index 1bf2e1f3ca..e23c9c37b6 100644 > --- a/drivers/video/Makefile > +++ b/drivers/video/Makefile > @@ -21,3 +21,4 @@ obj-$(CONFIG_DRIVER_VIDEO_OMAP) += omap.o > obj-$(CONFIG_DRIVER_VIDEO_BCM283X) += bcm2835.o > obj-$(CONFIG_DRIVER_VIDEO_SIMPLEFB) += simplefb.o > obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += imx-ipu-v3/ > +obj-$(CONFIG_DRIVER_VIDEO_FB_SSD1307) += ssd1307fb.o > diff --git a/drivers/video/ssd1307fb.c b/drivers/video/ssd1307fb.c > new file mode 100644 > index 0000000000..0dfdcc2232 > --- /dev/null > +++ b/drivers/video/ssd1307fb.c > @@ -0,0 +1,569 @@ > +/* > + * Driver for the Solomon SSD1307 OLED controller family > + * > + * Supports: > + * - SSD1305 (untested) > + * - SSD1306 > + * - SSD1307 (untested) > + * - SSD1309 (untested) > + * > + * Copyright 2012 Maxime Ripard <maxime.ripard@free-electrons.com>, Free Electrons > + * > + * Ported to barebox from linux v4.10 > + * Copyright (C) 2017 Pengutronix, Bastian Stender <kernel@pengutronix.de> > + * > + * Licensed under the GPLv2 or later. > + */ > + > +#include <common.h> > +#include <init.h> > +#include <fb.h> > +#include <i2c/i2c.h> > +#include <of_device.h> > +#include <gpio.h> > +#include <of_gpio.h> > +#include <printk.h> > + > +#define SSD1307FB_DATA 0x40 > +#define SSD1307FB_COMMAND 0x80 > + > +#define SSD1307FB_SET_ADDRESS_MODE 0x20 > +#define SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL (0x00) > +#define SSD1307FB_SET_ADDRESS_MODE_VERTICAL (0x01) > +#define SSD1307FB_SET_ADDRESS_MODE_PAGE (0x02) > +#define SSD1307FB_SET_COL_RANGE 0x21 > +#define SSD1307FB_SET_PAGE_RANGE 0x22 > +#define SSD1307FB_CONTRAST 0x81 > +#define SSD1307FB_CHARGE_PUMP 0x8d > +#define SSD1307FB_SEG_REMAP_ON 0xa1 > +#define SSD1307FB_DISPLAY_OFF 0xae > +#define SSD1307FB_SET_MULTIPLEX_RATIO 0xa8 > +#define SSD1307FB_DISPLAY_ON 0xaf > +#define SSD1307FB_START_PAGE_ADDRESS 0xb0 > +#define SSD1307FB_SET_DISPLAY_OFFSET 0xd3 > +#define SSD1307FB_SET_CLOCK_FREQ 0xd5 > +#define SSD1307FB_SET_PRECHARGE_PERIOD 0xd9 > +#define SSD1307FB_SET_COM_PINS_CONFIG 0xda > +#define SSD1307FB_SET_VCOMH 0xdb please consistently use spaces after #define > + > +struct ssd1307fb_par; Unnecessary. > + > +struct ssd1307fb_deviceinfo { > + u32 default_vcomh; > + u32 default_dclk_div; > + u32 default_dclk_frq; > + int need_chargepump; > +}; > + [...] > +static int ssd1307fb_probe(struct device_d *dev) > +{ > + struct i2c_client *client = to_i2c_client(dev); > + struct fb_info *info; > + struct device_node *node = dev->device_node; > + const struct of_device_id *match = > + of_match_node(ssd1307fb_of_match, dev->device_node); > + u32 vmem_size; > + struct ssd1307fb_par *par; > + struct ssd1307fb_array *array; > + u8 *vmem; > + int ret; > + int i, j; > + > + if (!node) { > + dev_err(&client->dev, "No device tree data found!\n"); > + return -EINVAL; > + } > + > + info = xzalloc(sizeof(struct fb_info)); > + if (!info) { > + dev_err(&client->dev, "Couldn't allocate framebuffer.\n"); > + return -ENOMEM; > + } xzalloc always returns succesfully, no need to check. > + > + par = info->priv; > + par->info = info; > + par->client = client; > + > + par->device_info = (struct ssd1307fb_deviceinfo *)match->data; > + > + par->reset = of_get_named_gpio(node, > + "reset-gpios", 0); > + if (!gpio_is_valid(par->reset)) { > + dev_err(&client->dev, > + "Couldn't get named gpio 'reset-gpios' %d.\n", > + par->reset); > + ret = par->reset; > + goto fb_alloc_error; > + } Is this gpio really mandatory? > + > + if (of_property_read_u32(node, "solomon,width", &par->width)) > + par->width = 96; > + > + if (of_property_read_u32(node, "solomon,height", &par->height)) > + par->height = 16; These defaults only work for you. You should bail out with an error if the devicetree does not contain values for these instead. Sascha -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 4/4] video: add support for Solomon SSD1307 OLED controller family 2017-02-27 10:08 ` Sascha Hauer @ 2017-02-27 15:45 ` Bastian Stender 2017-02-28 7:57 ` Sascha Hauer 0 siblings, 1 reply; 15+ messages in thread From: Bastian Stender @ 2017-02-27 15:45 UTC (permalink / raw) To: Sascha Hauer; +Cc: barebox On 02/27/2017 11:08 AM, Sascha Hauer wrote: > On Fri, Feb 24, 2017 at 03:25:01PM +0100, Bastian Stender wrote: >> It was ported from linux v4.10. Like the kernel driver only >> communication via I2C is supported. >> >> It has only been tested with a SSD1306 and a 96x16 OLED display: >> >> &i2c0 { >> status = "okay"; >> >> ssd1306: oled@3c { >> compatible = "solomon,ssd1306fb-i2c"; >> reg = <0x3c>; >> reset-gpios = <&gpio1 1 0>; >> solomon,height = <16>; >> solomon,width = <96>; >> solomon,page-offset = <0>; >> solomon,com-invdir; >> solomon,com-seq; >> }; >> >> Signed-off-by: Bastian Stender <bst@pengutronix.de> >> --- >> drivers/video/Kconfig | 4 + >> drivers/video/Makefile | 1 + >> drivers/video/ssd1307fb.c | 569 ++++++++++++++++++++++++++++++++++++++++++++++ >> 3 files changed, 574 insertions(+) >> create mode 100644 drivers/video/ssd1307fb.c >> >> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig >> index 8f31f5af74..50a876acb1 100644 >> --- a/drivers/video/Kconfig >> +++ b/drivers/video/Kconfig >> @@ -12,6 +12,10 @@ config FRAMEBUFFER_CONSOLE >> select FONTS >> prompt "framebuffer console support" >> >> +config DRIVER_VIDEO_FB_SSD1307 >> + bool "Solomon SSD1307 framebuffer support" >> + depends on PWM && I2C && GPIOLIB >> + >> config VIDEO_VPL >> depends on OFTREE >> bool >> diff --git a/drivers/video/Makefile b/drivers/video/Makefile >> index 1bf2e1f3ca..e23c9c37b6 100644 >> --- a/drivers/video/Makefile >> +++ b/drivers/video/Makefile >> @@ -21,3 +21,4 @@ obj-$(CONFIG_DRIVER_VIDEO_OMAP) += omap.o >> obj-$(CONFIG_DRIVER_VIDEO_BCM283X) += bcm2835.o >> obj-$(CONFIG_DRIVER_VIDEO_SIMPLEFB) += simplefb.o >> obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += imx-ipu-v3/ >> +obj-$(CONFIG_DRIVER_VIDEO_FB_SSD1307) += ssd1307fb.o >> diff --git a/drivers/video/ssd1307fb.c b/drivers/video/ssd1307fb.c >> new file mode 100644 >> index 0000000000..0dfdcc2232 >> --- /dev/null >> +++ b/drivers/video/ssd1307fb.c >> @@ -0,0 +1,569 @@ >> +/* >> + * Driver for the Solomon SSD1307 OLED controller family >> + * >> + * Supports: >> + * - SSD1305 (untested) >> + * - SSD1306 >> + * - SSD1307 (untested) >> + * - SSD1309 (untested) >> + * >> + * Copyright 2012 Maxime Ripard <maxime.ripard@free-electrons.com>, Free Electrons >> + * >> + * Ported to barebox from linux v4.10 >> + * Copyright (C) 2017 Pengutronix, Bastian Stender <kernel@pengutronix.de> >> + * >> + * Licensed under the GPLv2 or later. >> + */ >> + >> +#include <common.h> >> +#include <init.h> >> +#include <fb.h> >> +#include <i2c/i2c.h> >> +#include <of_device.h> >> +#include <gpio.h> >> +#include <of_gpio.h> >> +#include <printk.h> >> + >> +#define SSD1307FB_DATA 0x40 >> +#define SSD1307FB_COMMAND 0x80 >> + >> +#define SSD1307FB_SET_ADDRESS_MODE 0x20 >> +#define SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL (0x00) >> +#define SSD1307FB_SET_ADDRESS_MODE_VERTICAL (0x01) >> +#define SSD1307FB_SET_ADDRESS_MODE_PAGE (0x02) >> +#define SSD1307FB_SET_COL_RANGE 0x21 >> +#define SSD1307FB_SET_PAGE_RANGE 0x22 >> +#define SSD1307FB_CONTRAST 0x81 >> +#define SSD1307FB_CHARGE_PUMP 0x8d >> +#define SSD1307FB_SEG_REMAP_ON 0xa1 >> +#define SSD1307FB_DISPLAY_OFF 0xae >> +#define SSD1307FB_SET_MULTIPLEX_RATIO 0xa8 >> +#define SSD1307FB_DISPLAY_ON 0xaf >> +#define SSD1307FB_START_PAGE_ADDRESS 0xb0 >> +#define SSD1307FB_SET_DISPLAY_OFFSET 0xd3 >> +#define SSD1307FB_SET_CLOCK_FREQ 0xd5 >> +#define SSD1307FB_SET_PRECHARGE_PERIOD 0xd9 >> +#define SSD1307FB_SET_COM_PINS_CONFIG 0xda >> +#define SSD1307FB_SET_VCOMH 0xdb > > please consistently use spaces after #define Will do. > >> + >> +struct ssd1307fb_par; > > Unnecessary. Ok. > >> + >> +struct ssd1307fb_deviceinfo { >> + u32 default_vcomh; >> + u32 default_dclk_div; >> + u32 default_dclk_frq; >> + int need_chargepump; >> +}; >> + > > [...] > >> +static int ssd1307fb_probe(struct device_d *dev) >> +{ >> + struct i2c_client *client = to_i2c_client(dev); >> + struct fb_info *info; >> + struct device_node *node = dev->device_node; >> + const struct of_device_id *match = >> + of_match_node(ssd1307fb_of_match, dev->device_node); >> + u32 vmem_size; >> + struct ssd1307fb_par *par; >> + struct ssd1307fb_array *array; >> + u8 *vmem; >> + int ret; >> + int i, j; >> + >> + if (!node) { >> + dev_err(&client->dev, "No device tree data found!\n"); >> + return -EINVAL; >> + } >> + >> + info = xzalloc(sizeof(struct fb_info)); >> + if (!info) { >> + dev_err(&client->dev, "Couldn't allocate framebuffer.\n"); >> + return -ENOMEM; >> + } > > xzalloc always returns succesfully, no need to check. Ok. > >> + >> + par = info->priv; >> + par->info = info; >> + par->client = client; >> + >> + par->device_info = (struct ssd1307fb_deviceinfo *)match->data; >> + >> + par->reset = of_get_named_gpio(node, >> + "reset-gpios", 0); >> + if (!gpio_is_valid(par->reset)) { >> + dev_err(&client->dev, >> + "Couldn't get named gpio 'reset-gpios' %d.\n", >> + par->reset); >> + ret = par->reset; >> + goto fb_alloc_error; >> + } > > Is this gpio really mandatory? This is the corresponding snippet from the kernel in drivers/video/fbdev/ssd1307fb.c, line 564 ff. (v4.10): par->reset = of_get_named_gpio(client->dev.of_node, "reset-gpios", 0); if (!gpio_is_valid(par->reset)) { ret = -EINVAL; goto fb_alloc_error; } "reset-gpios" is one of the required properties, see Documentation/devicetree/bindings/display/ssd1307fb.txt or in barebox: dts/Bindings/display/ssd1307fb.txt > >> + >> + if (of_property_read_u32(node, "solomon,width", &par->width)) >> + par->width = 96; >> + >> + if (of_property_read_u32(node, "solomon,height", &par->height)) >> + par->height = 16; > > These defaults only work for you. You should bail out with an error if > the devicetree does not contain values for these instead. This part was ported 1:1 from linux. As solomon,width and solomon,height are required properties also, should I bail out nonetheless? Regards, Bastian -- Pengutronix e.K. Industrial Linux Solutions http://www.pengutronix.de/ Peiner Str. 6-8, 31137 Hildesheim, Germany Amtsgericht Hildesheim, HRA 2686 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 4/4] video: add support for Solomon SSD1307 OLED controller family 2017-02-27 15:45 ` Bastian Stender @ 2017-02-28 7:57 ` Sascha Hauer 0 siblings, 0 replies; 15+ messages in thread From: Sascha Hauer @ 2017-02-28 7:57 UTC (permalink / raw) To: Bastian Stender; +Cc: barebox On Mon, Feb 27, 2017 at 04:45:43PM +0100, Bastian Stender wrote: > On 02/27/2017 11:08 AM, Sascha Hauer wrote: > > On Fri, Feb 24, 2017 at 03:25:01PM +0100, Bastian Stender wrote: > > > It was ported from linux v4.10. Like the kernel driver only > > > communication via I2C is supported. > > > > > > It has only been tested with a SSD1306 and a 96x16 OLED display: > > > > > > &i2c0 { > > > status = "okay"; > > > > > > ssd1306: oled@3c { > > > compatible = "solomon,ssd1306fb-i2c"; > > > reg = <0x3c>; > > > reset-gpios = <&gpio1 1 0>; > > > solomon,height = <16>; > > > solomon,width = <96>; > > > solomon,page-offset = <0>; > > > solomon,com-invdir; > > > solomon,com-seq; > > > }; > > > > > > Signed-off-by: Bastian Stender <bst@pengutronix.de> > > > --- > > > drivers/video/Kconfig | 4 + > > > drivers/video/Makefile | 1 + > > > drivers/video/ssd1307fb.c | 569 ++++++++++++++++++++++++++++++++++++++++++++++ > > > 3 files changed, 574 insertions(+) > > > create mode 100644 drivers/video/ssd1307fb.c > > > > > > diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig > > > index 8f31f5af74..50a876acb1 100644 > > > --- a/drivers/video/Kconfig > > > +++ b/drivers/video/Kconfig > > > @@ -12,6 +12,10 @@ config FRAMEBUFFER_CONSOLE > > > select FONTS > > > prompt "framebuffer console support" > > > > > > +config DRIVER_VIDEO_FB_SSD1307 > > > + bool "Solomon SSD1307 framebuffer support" > > > + depends on PWM && I2C && GPIOLIB > > > + > > > config VIDEO_VPL > > > depends on OFTREE > > > bool > > > diff --git a/drivers/video/Makefile b/drivers/video/Makefile > > > index 1bf2e1f3ca..e23c9c37b6 100644 > > > --- a/drivers/video/Makefile > > > +++ b/drivers/video/Makefile > > > @@ -21,3 +21,4 @@ obj-$(CONFIG_DRIVER_VIDEO_OMAP) += omap.o > > > obj-$(CONFIG_DRIVER_VIDEO_BCM283X) += bcm2835.o > > > obj-$(CONFIG_DRIVER_VIDEO_SIMPLEFB) += simplefb.o > > > obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += imx-ipu-v3/ > > > +obj-$(CONFIG_DRIVER_VIDEO_FB_SSD1307) += ssd1307fb.o > > > diff --git a/drivers/video/ssd1307fb.c b/drivers/video/ssd1307fb.c > > > new file mode 100644 > > > index 0000000000..0dfdcc2232 > > > --- /dev/null > > > +++ b/drivers/video/ssd1307fb.c > > > @@ -0,0 +1,569 @@ > > > +/* > > > + * Driver for the Solomon SSD1307 OLED controller family > > > + * > > > + * Supports: > > > + * - SSD1305 (untested) > > > + * - SSD1306 > > > + * - SSD1307 (untested) > > > + * - SSD1309 (untested) > > > + * > > > + * Copyright 2012 Maxime Ripard <maxime.ripard@free-electrons.com>, Free Electrons > > > + * > > > + * Ported to barebox from linux v4.10 > > > + * Copyright (C) 2017 Pengutronix, Bastian Stender <kernel@pengutronix.de> > > > + * > > > + * Licensed under the GPLv2 or later. > > > + */ > > > + > > > +#include <common.h> > > > +#include <init.h> > > > +#include <fb.h> > > > +#include <i2c/i2c.h> > > > +#include <of_device.h> > > > +#include <gpio.h> > > > +#include <of_gpio.h> > > > +#include <printk.h> > > > + > > > +#define SSD1307FB_DATA 0x40 > > > +#define SSD1307FB_COMMAND 0x80 > > > + > > > +#define SSD1307FB_SET_ADDRESS_MODE 0x20 > > > +#define SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL (0x00) > > > +#define SSD1307FB_SET_ADDRESS_MODE_VERTICAL (0x01) > > > +#define SSD1307FB_SET_ADDRESS_MODE_PAGE (0x02) > > > +#define SSD1307FB_SET_COL_RANGE 0x21 > > > +#define SSD1307FB_SET_PAGE_RANGE 0x22 > > > +#define SSD1307FB_CONTRAST 0x81 > > > +#define SSD1307FB_CHARGE_PUMP 0x8d > > > +#define SSD1307FB_SEG_REMAP_ON 0xa1 > > > +#define SSD1307FB_DISPLAY_OFF 0xae > > > +#define SSD1307FB_SET_MULTIPLEX_RATIO 0xa8 > > > +#define SSD1307FB_DISPLAY_ON 0xaf > > > +#define SSD1307FB_START_PAGE_ADDRESS 0xb0 > > > +#define SSD1307FB_SET_DISPLAY_OFFSET 0xd3 > > > +#define SSD1307FB_SET_CLOCK_FREQ 0xd5 > > > +#define SSD1307FB_SET_PRECHARGE_PERIOD 0xd9 > > > +#define SSD1307FB_SET_COM_PINS_CONFIG 0xda > > > +#define SSD1307FB_SET_VCOMH 0xdb > > > > please consistently use spaces after #define > > Will do. > > > > > > + > > > +struct ssd1307fb_par; > > > > Unnecessary. > > Ok. > > > > > > + > > > +struct ssd1307fb_deviceinfo { > > > + u32 default_vcomh; > > > + u32 default_dclk_div; > > > + u32 default_dclk_frq; > > > + int need_chargepump; > > > +}; > > > + > > > > [...] > > > > > +static int ssd1307fb_probe(struct device_d *dev) > > > +{ > > > + struct i2c_client *client = to_i2c_client(dev); > > > + struct fb_info *info; > > > + struct device_node *node = dev->device_node; > > > + const struct of_device_id *match = > > > + of_match_node(ssd1307fb_of_match, dev->device_node); > > > + u32 vmem_size; > > > + struct ssd1307fb_par *par; > > > + struct ssd1307fb_array *array; > > > + u8 *vmem; > > > + int ret; > > > + int i, j; > > > + > > > + if (!node) { > > > + dev_err(&client->dev, "No device tree data found!\n"); > > > + return -EINVAL; > > > + } > > > + > > > + info = xzalloc(sizeof(struct fb_info)); > > > + if (!info) { > > > + dev_err(&client->dev, "Couldn't allocate framebuffer.\n"); > > > + return -ENOMEM; > > > + } > > > > xzalloc always returns succesfully, no need to check. > > Ok. > > > > > > + > > > + par = info->priv; > > > + par->info = info; > > > + par->client = client; > > > + > > > + par->device_info = (struct ssd1307fb_deviceinfo *)match->data; > > > + > > > + par->reset = of_get_named_gpio(node, > > > + "reset-gpios", 0); > > > + if (!gpio_is_valid(par->reset)) { > > > + dev_err(&client->dev, > > > + "Couldn't get named gpio 'reset-gpios' %d.\n", > > > + par->reset); > > > + ret = par->reset; > > > + goto fb_alloc_error; > > > + } > > > > Is this gpio really mandatory? > > > This is the corresponding snippet from the kernel in > drivers/video/fbdev/ssd1307fb.c, line 564 ff. (v4.10): > > par->reset = of_get_named_gpio(client->dev.of_node, > "reset-gpios", 0); > if (!gpio_is_valid(par->reset)) { > ret = -EINVAL; > goto fb_alloc_error; > } > > "reset-gpios" is one of the required properties, see > > Documentation/devicetree/bindings/display/ssd1307fb.txt > > or in barebox: > > dts/Bindings/display/ssd1307fb.txt Ok. > > > > > > + > > > + if (of_property_read_u32(node, "solomon,width", &par->width)) > > > + par->width = 96; > > > + > > > + if (of_property_read_u32(node, "solomon,height", &par->height)) > > > + par->height = 16; > > > > These defaults only work for you. You should bail out with an error if > > the devicetree does not contain values for these instead. > > This part was ported 1:1 from linux. As solomon,width and solomon,height are > required properties also, should I bail out nonetheless? Yes, please. The resolution of the framebuffer must be explicitly given in the device tree. If it's not then the user gets a better clue what's wrong when the driver does not successfully probe. Sascha -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2017-02-28 7:58 UTC | newest] Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2017-02-24 14:24 [PATCH 0/4] Prepare consoles, add fb flush and Solomon SSD1307 OLED controller support Bastian Stender 2017-02-24 14:24 ` [PATCH 1/4] console: replace set_active by open/close Bastian Stender 2017-02-27 9:54 ` Sascha Hauer 2017-02-27 15:56 ` [PATCH v2] " Bastian Stender 2017-02-28 7:41 ` Sascha Hauer 2017-02-24 14:24 ` [PATCH 2/4] console: expose consoles in devfs Bastian Stender 2017-02-27 9:55 ` Sascha Hauer 2017-02-27 16:01 ` [PATCH v2] " Bastian Stender 2017-02-28 7:50 ` Sascha Hauer 2017-02-24 14:25 ` [PATCH 3/4] fb: introduce flush for virtual framebuffer Bastian Stender 2017-02-24 14:25 ` [PATCH 4/4] video: add support for Solomon SSD1307 OLED controller family Bastian Stender 2017-02-24 16:10 ` Bastian Stender 2017-02-27 10:08 ` Sascha Hauer 2017-02-27 15:45 ` Bastian Stender 2017-02-28 7:57 ` Sascha Hauer
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox