diff options
Diffstat (limited to 'drivers/gpu/drm/tiny/st7735r.c')
| -rw-r--r-- | drivers/gpu/drm/tiny/st7735r.c | 246 | 
1 files changed, 246 insertions, 0 deletions
diff --git a/drivers/gpu/drm/tiny/st7735r.c b/drivers/gpu/drm/tiny/st7735r.c new file mode 100644 index 000000000000..3f4487c71684 --- /dev/null +++ b/drivers/gpu/drm/tiny/st7735r.c @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * DRM driver for Sitronix ST7735R panels + * + * Copyright 2017 David Lechner <[email protected]> + */ + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/dma-buf.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/property.h> +#include <linux/spi/spi.h> +#include <video/mipi_display.h> + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_drv.h> +#include <drm/drm_fb_helper.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_mipi_dbi.h> + +#define ST7735R_FRMCTR1		0xb1 +#define ST7735R_FRMCTR2		0xb2 +#define ST7735R_FRMCTR3		0xb3 +#define ST7735R_INVCTR		0xb4 +#define ST7735R_PWCTR1		0xc0 +#define ST7735R_PWCTR2		0xc1 +#define ST7735R_PWCTR3		0xc2 +#define ST7735R_PWCTR4		0xc3 +#define ST7735R_PWCTR5		0xc4 +#define ST7735R_VMCTR1		0xc5 +#define ST7735R_GAMCTRP1	0xe0 +#define ST7735R_GAMCTRN1	0xe1 + +#define ST7735R_MY	BIT(7) +#define ST7735R_MX	BIT(6) +#define ST7735R_MV	BIT(5) + +static void jd_t18003_t01_pipe_enable(struct drm_simple_display_pipe *pipe, +				      struct drm_crtc_state *crtc_state, +				      struct drm_plane_state *plane_state) +{ +	struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev); +	struct mipi_dbi *dbi = &dbidev->dbi; +	int ret, idx; +	u8 addr_mode; + +	if (!drm_dev_enter(pipe->crtc.dev, &idx)) +		return; + +	DRM_DEBUG_KMS("\n"); + +	ret = mipi_dbi_poweron_reset(dbidev); +	if (ret) +		goto out_exit; + +	msleep(150); + +	mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE); +	msleep(500); + +	mipi_dbi_command(dbi, ST7735R_FRMCTR1, 0x01, 0x2c, 0x2d); +	mipi_dbi_command(dbi, ST7735R_FRMCTR2, 0x01, 0x2c, 0x2d); +	mipi_dbi_command(dbi, ST7735R_FRMCTR3, 0x01, 0x2c, 0x2d, 0x01, 0x2c, +			 0x2d); +	mipi_dbi_command(dbi, ST7735R_INVCTR, 0x07); +	mipi_dbi_command(dbi, ST7735R_PWCTR1, 0xa2, 0x02, 0x84); +	mipi_dbi_command(dbi, ST7735R_PWCTR2, 0xc5); +	mipi_dbi_command(dbi, ST7735R_PWCTR3, 0x0a, 0x00); +	mipi_dbi_command(dbi, ST7735R_PWCTR4, 0x8a, 0x2a); +	mipi_dbi_command(dbi, ST7735R_PWCTR5, 0x8a, 0xee); +	mipi_dbi_command(dbi, ST7735R_VMCTR1, 0x0e); +	mipi_dbi_command(dbi, MIPI_DCS_EXIT_INVERT_MODE); +	switch (dbidev->rotation) { +	default: +		addr_mode = ST7735R_MX | ST7735R_MY; +		break; +	case 90: +		addr_mode = ST7735R_MX | ST7735R_MV; +		break; +	case 180: +		addr_mode = 0; +		break; +	case 270: +		addr_mode = ST7735R_MY | ST7735R_MV; +		break; +	} +	mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode); +	mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT, +			 MIPI_DCS_PIXEL_FMT_16BIT); +	mipi_dbi_command(dbi, ST7735R_GAMCTRP1, 0x02, 0x1c, 0x07, 0x12, 0x37, +			 0x32, 0x29, 0x2d, 0x29, 0x25, 0x2b, 0x39, 0x00, 0x01, +			 0x03, 0x10); +	mipi_dbi_command(dbi, ST7735R_GAMCTRN1, 0x03, 0x1d, 0x07, 0x06, 0x2e, +			 0x2c, 0x29, 0x2d, 0x2e, 0x2e, 0x37, 0x3f, 0x00, 0x00, +			 0x02, 0x10); +	mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON); + +	msleep(100); + +	mipi_dbi_command(dbi, MIPI_DCS_ENTER_NORMAL_MODE); + +	msleep(20); + +	mipi_dbi_enable_flush(dbidev, crtc_state, plane_state); +out_exit: +	drm_dev_exit(idx); +} + +static const struct drm_simple_display_pipe_funcs jd_t18003_t01_pipe_funcs = { +	.enable		= jd_t18003_t01_pipe_enable, +	.disable	= mipi_dbi_pipe_disable, +	.update		= mipi_dbi_pipe_update, +	.prepare_fb	= drm_gem_fb_simple_display_pipe_prepare_fb, +}; + +static const struct drm_display_mode jd_t18003_t01_mode = { +	DRM_SIMPLE_MODE(128, 160, 28, 35), +}; + +DEFINE_DRM_GEM_CMA_FOPS(st7735r_fops); + +static struct drm_driver st7735r_driver = { +	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, +	.fops			= &st7735r_fops, +	.release		= mipi_dbi_release, +	DRM_GEM_CMA_VMAP_DRIVER_OPS, +	.debugfs_init		= mipi_dbi_debugfs_init, +	.name			= "st7735r", +	.desc			= "Sitronix ST7735R", +	.date			= "20171128", +	.major			= 1, +	.minor			= 0, +}; + +static const struct of_device_id st7735r_of_match[] = { +	{ .compatible = "jianda,jd-t18003-t01" }, +	{ }, +}; +MODULE_DEVICE_TABLE(of, st7735r_of_match); + +static const struct spi_device_id st7735r_id[] = { +	{ "jd-t18003-t01", 0 }, +	{ }, +}; +MODULE_DEVICE_TABLE(spi, st7735r_id); + +static int st7735r_probe(struct spi_device *spi) +{ +	struct device *dev = &spi->dev; +	struct mipi_dbi_dev *dbidev; +	struct drm_device *drm; +	struct mipi_dbi *dbi; +	struct gpio_desc *dc; +	u32 rotation = 0; +	int ret; + +	dbidev = kzalloc(sizeof(*dbidev), GFP_KERNEL); +	if (!dbidev) +		return -ENOMEM; + +	dbi = &dbidev->dbi; +	drm = &dbidev->drm; +	ret = devm_drm_dev_init(dev, drm, &st7735r_driver); +	if (ret) { +		kfree(dbidev); +		return ret; +	} + +	drm_mode_config_init(drm); + +	dbi->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); +	if (IS_ERR(dbi->reset)) { +		DRM_DEV_ERROR(dev, "Failed to get gpio 'reset'\n"); +		return PTR_ERR(dbi->reset); +	} + +	dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW); +	if (IS_ERR(dc)) { +		DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n"); +		return PTR_ERR(dc); +	} + +	dbidev->backlight = devm_of_find_backlight(dev); +	if (IS_ERR(dbidev->backlight)) +		return PTR_ERR(dbidev->backlight); + +	device_property_read_u32(dev, "rotation", &rotation); + +	ret = mipi_dbi_spi_init(spi, dbi, dc); +	if (ret) +		return ret; + +	/* Cannot read from Adafruit 1.8" display via SPI */ +	dbi->read_commands = NULL; + +	ret = mipi_dbi_dev_init(dbidev, &jd_t18003_t01_pipe_funcs, &jd_t18003_t01_mode, rotation); +	if (ret) +		return ret; + +	drm_mode_config_reset(drm); + +	ret = drm_dev_register(drm, 0); +	if (ret) +		return ret; + +	spi_set_drvdata(spi, drm); + +	drm_fbdev_generic_setup(drm, 0); + +	return 0; +} + +static int st7735r_remove(struct spi_device *spi) +{ +	struct drm_device *drm = spi_get_drvdata(spi); + +	drm_dev_unplug(drm); +	drm_atomic_helper_shutdown(drm); + +	return 0; +} + +static void st7735r_shutdown(struct spi_device *spi) +{ +	drm_atomic_helper_shutdown(spi_get_drvdata(spi)); +} + +static struct spi_driver st7735r_spi_driver = { +	.driver = { +		.name = "st7735r", +		.owner = THIS_MODULE, +		.of_match_table = st7735r_of_match, +	}, +	.id_table = st7735r_id, +	.probe = st7735r_probe, +	.remove = st7735r_remove, +	.shutdown = st7735r_shutdown, +}; +module_spi_driver(st7735r_spi_driver); + +MODULE_DESCRIPTION("Sitronix ST7735R DRM driver"); +MODULE_AUTHOR("David Lechner <[email protected]>"); +MODULE_LICENSE("GPL");  |