The Adafuit SSD1306 based displays comes in either 128x32 or 128x64 resolutions and uses I2C or SPI interface. This driver has support for the I2C interface. Support for SPI can be added when lcdreg has SPI support. Signed-off-by: Noralf Trønnes <noralf@xxxxxxxxxxx> --- drivers/staging/fbtft/Kconfig | 9 ++ drivers/staging/fbtft/Makefile | 3 + drivers/staging/fbtft/ada-ssd1306fb.c | 173 ++++++++++++++++++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 drivers/staging/fbtft/ada-ssd1306fb.c diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig index 0ac1b41..b53ed5b 100644 --- a/drivers/staging/fbtft/Kconfig +++ b/drivers/staging/fbtft/Kconfig @@ -168,5 +168,14 @@ config FB_TFT_FBTFT_DEVICE tristate "Module to for adding FBTFT devices" depends on FB_TFT +config FB_ADA_SSD1306 + tristate "Framebuffer driver for Adafruit SSD1306 displays" + depends on FB_TFT && I2C + select LCDREG_I2C + select LCDCTRL_SSD1306 + help + Framebuffer Driver for Adafruit SSD1306 based + Monochrome OLED displays + source "drivers/staging/fbtft/lcdctrl/Kconfig" source "drivers/staging/fbtft/lcdreg/Kconfig" diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile index 6f002a6..f862810 100644 --- a/drivers/staging/fbtft/Makefile +++ b/drivers/staging/fbtft/Makefile @@ -36,3 +36,6 @@ obj-$(CONFIG_FB_FLEX) += flexfb.o # Device modules obj-$(CONFIG_FB_TFT_FBTFT_DEVICE) += fbtft_device.o + +# Display drivers +obj-$(CONFIG_FB_ADA_SSD1306) += ada-ssd1306fb.o diff --git a/drivers/staging/fbtft/ada-ssd1306fb.c b/drivers/staging/fbtft/ada-ssd1306fb.c new file mode 100644 index 0000000..eea5978 --- /dev/null +++ b/drivers/staging/fbtft/ada-ssd1306fb.c @@ -0,0 +1,173 @@ +/* + * Framebuffer Driver for Adafruit SSD1306 based Monochrome OLED displays + * + * Copyright 2015 Noralf Trønnes + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/regulator/consumer.h> + +#include "fbtft.h" +#include "lcdreg/lcdreg.h" +#include "lcdctrl/ssd1306.h" + + +/* Init sequence from github.com/adafruit/Adafruit_SSD1306 */ +static int ada_ssd1306_poweron(struct lcdctrl *ctrl) +{ + struct lcdreg *reg = ctrl->lcdreg; + int ret; + + lcdreg_reset(reg); + + ret = lcdreg_writereg(reg, SSD1306_DISPLAY_OFF); + if (ret) { + dev_err(reg->dev, + "lcdreg_writereg failed: %d\n", ret); + return ret; + } + + if (lcdreg_is_readable(reg)) + ssd1306_check_status(reg, false); + + lcdreg_writereg(reg, SSD1306_CLOCK_FREQ); + lcdreg_writereg(reg, 0x80); + + lcdreg_writereg(reg, SSD1306_MULTIPLEX_RATIO); + if (lcdctrl_yres(ctrl) == 64) + lcdreg_writereg(reg, 0x3f); + else + lcdreg_writereg(reg, 0x1f); + + lcdreg_writereg(reg, SSD1306_DISPLAY_OFFSET); + lcdreg_writereg(reg, 0x0); + + lcdreg_writereg(reg, SSD1306_DISPLAY_START_LINE); + + lcdreg_writereg(reg, SSD1306_CHARGE_PUMP); + lcdreg_writereg(reg, 0x14); + + lcdreg_writereg(reg, SSD1306_ADDRESS_MODE); + lcdreg_writereg(reg, 0x01); /* vertical */ + + lcdreg_writereg(reg, SSD1306_COL_RANGE); + lcdreg_writereg(reg, 0x00); + lcdreg_writereg(reg, lcdctrl_xres(ctrl) - 1); + + lcdreg_writereg(reg, SSD1306_PAGE_RANGE); + lcdreg_writereg(reg, 0x00); + lcdreg_writereg(reg, (lcdctrl_yres(ctrl) / 8) - 1); + + lcdreg_writereg(reg, SSD1306_SEG_REMAP_ON); + + lcdreg_writereg(reg, SSD1306_COM_SCAN_REMAP); + + lcdreg_writereg(reg, SSD1306_COM_PINS_CONFIG); + if (lcdctrl_yres(ctrl) == 64) + lcdreg_writereg(reg, 0x12); + else + lcdreg_writereg(reg, 0x02); + + lcdreg_writereg(reg, SSD1306_PRECHARGE_PERIOD); + lcdreg_writereg(reg, 0xf1); + + lcdreg_writereg(reg, SSD1306_VCOMH); + lcdreg_writereg(reg, 0x40); + + lcdreg_writereg(reg, SSD1306_RESUME_TO_RAM); + + lcdreg_writereg(reg, SSD1306_NORMAL_DISPLAY); + + lcdreg_writereg(reg, SSD1306_CONTRAST); + if (lcdctrl_yres(ctrl) == 64) + lcdreg_writereg(reg, 0xcf); + else + lcdreg_writereg(reg, 0x8f); + + /* The display is turned on later by core */ + + return 0; +} + +static const struct of_device_id ada_ssd1306_ids[] = { + { .compatible = "ada,ssd1306-128x32", .data = (void *)32 }, + { .compatible = "ada,ssd1306-128x64", .data = (void *)64 }, + {}, +}; +MODULE_DEVICE_TABLE(of, ada_ssd1306_ids); + +static int ada_ssd1306_probe_common(struct lcdreg *reg) +{ + const struct of_device_id *of_id; + struct device *dev = reg->dev; + struct lcdctrl *ctrl; + struct ssd1306_config cfg = { + .width = 128, + }; + + of_id = of_match_device(ada_ssd1306_ids, dev); + if (!of_id) + return -EINVAL; + + cfg.height = (u32)of_id->data; + ctrl = devm_ssd1306_init(reg, &cfg); + if (IS_ERR(ctrl)) + return PTR_ERR(ctrl); + + ctrl->poweron = ada_ssd1306_poweron; + + return devm_fbtft_lcdctrl_of_register(ctrl); +} + +static int ada_ssd1306_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct lcdreg *reg; + + reg = devm_lcdreg_i2c_init(client); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + return ada_ssd1306_probe_common(reg); +} + +static void ada_ssd1306_shutdown(struct i2c_client *client) +{ + struct fb_info *info = dev_get_drvdata(&client->dev); + struct fbtft_par *par = info->par; + + lcdctrl_disable(par->lcdctrl); +} + +static const struct i2c_device_id ssd1307fb_i2c_id[] = { + { "ada-ssd1306fb", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, ssd1307fb_i2c_id); + +static struct i2c_driver ada_ssd1306_i2c_driver = { + .driver = { + .name = "ada-ssd1306fb", + .pm = FBTFT_PM_OPS, + .of_match_table = ada_ssd1306_ids, + }, + .id_table = ssd1307fb_i2c_id, + .probe = ada_ssd1306_i2c_probe, + .shutdown = ada_ssd1306_shutdown, +}; +module_i2c_driver(ada_ssd1306_i2c_driver); + +MODULE_ALIAS("i2c:ssd1306-128x32"); +MODULE_ALIAS("i2c:ssd1306-128x64"); + +MODULE_DESCRIPTION("Framebuffer Driver for Adafruit Monochrome OLED displays"); +MODULE_AUTHOR("Noralf Trønnes"); +MODULE_LICENSE("GPL"); -- 2.2.2 _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel