// SPDX-License-Identifier: GPL-2.0-only /* * Ilitek ILI9322 TFT LCD drm_panel driver. * * This panel can be configured to support: * - 8-bit serial RGB interface * - 24-bit parallel RGB interface * - 8-bit ITU-R BT.601 interface * - 8-bit ITU-R BT.656 interface * - Up to 320RGBx240 dots resolution TFT LCD displays * - Scaling, brightness and contrast * * The scaling means that the display accepts a 640x480 or 720x480 * input and rescales it to fit to the 320x240 display. So what we * present to the system is something else than what comes out on the * actual display. * * Copyright (C) 2017 Linus Walleij <[email protected]> * Derived from drivers/drm/gpu/panel/panel-samsung-ld9040.c */ #include <linux/bitops.h> #include <linux/gpio/consumer.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/spi/spi.h> #include <video/mipi_display.h> #include <video/of_videomode.h> #include <video/videomode.h> #include <drm/drm_modes.h> #include <drm/drm_panel.h> #define ILI9322_CHIP_ID … #define ILI9322_CHIP_ID_MAGIC … /* * Voltage on the communication interface, from 0.7 (0x00) * to 1.32 (0x1f) times the VREG1OUT voltage in 2% increments. * 1.00 (0x0f) is the default. */ #define ILI9322_VCOM_AMP … /* * High voltage on the communication signals, from 0.37 (0x00) to * 1.0 (0x3f) times the VREGOUT1 voltage in 1% increments. * 0.83 (0x2e) is the default. */ #define ILI9322_VCOM_HIGH … /* * VREG1 voltage regulator from 3.6V (0x00) to 6.0V (0x18) in 0.1V * increments. 5.4V (0x12) is the default. This is the reference * voltage for the VCOM levels and the greyscale level. */ #define ILI9322_VREG1_VOLTAGE … /* Describes the incoming signal */ #define ILI9322_ENTRY … /* 0 = right-to-left, 1 = left-to-right (default), horizontal flip */ #define ILI9322_ENTRY_HDIR … /* 0 = down-to-up, 1 = up-to-down (default), vertical flip */ #define ILI9322_ENTRY_VDIR … /* NTSC, PAL or autodetect */ #define ILI9322_ENTRY_NTSC … #define ILI9322_ENTRY_PAL … #define ILI9322_ENTRY_AUTODETECT … /* Input format */ #define ILI9322_ENTRY_SERIAL_RGB_THROUGH … #define ILI9322_ENTRY_SERIAL_RGB_ALIGNED … #define ILI9322_ENTRY_SERIAL_RGB_DUMMY_320X240 … #define ILI9322_ENTRY_SERIAL_RGB_DUMMY_360X240 … #define ILI9322_ENTRY_DISABLE_1 … #define ILI9322_ENTRY_PARALLEL_RGB_THROUGH … #define ILI9322_ENTRY_PARALLEL_RGB_ALIGNED … #define ILI9322_ENTRY_YUV_640Y_320CBCR_25_54_MHZ … #define ILI9322_ENTRY_YUV_720Y_360CBCR_27_MHZ … #define ILI9322_ENTRY_DISABLE_2 … #define ILI9322_ENTRY_ITU_R_BT_656_720X360 … #define ILI9322_ENTRY_ITU_R_BT_656_640X320 … /* Power control */ #define ILI9322_POW_CTRL … #define ILI9322_POW_CTRL_STB … #define ILI9322_POW_CTRL_VGL … #define ILI9322_POW_CTRL_VGH … #define ILI9322_POW_CTRL_DDVDH … #define ILI9322_POW_CTRL_VCOM … #define ILI9322_POW_CTRL_VCL … #define ILI9322_POW_CTRL_AUTO … #define ILI9322_POW_CTRL_STANDBY … #define ILI9322_POW_CTRL_DEFAULT … /* Vertical back porch bits 0..5 */ #define ILI9322_VBP … /* Horizontal back porch, 8 bits */ #define ILI9322_HBP … /* * Polarity settings: * 1 = positive polarity * 0 = negative polarity */ #define ILI9322_POL … #define ILI9322_POL_DCLK … #define ILI9322_POL_HSYNC … #define ILI9322_POL_VSYNC … #define ILI9322_POL_DE … /* * 0 means YCBCR are ordered Cb0,Y0,Cr0,Y1,Cb2,Y2,Cr2,Y3 (default) * in RGB mode this means RGB comes in RGBRGB * 1 means YCBCR are ordered Cr0,Y0,Cb0,Y1,Cr2,Y2,Cb2,Y3 * in RGB mode this means RGB comes in BGRBGR */ #define ILI9322_POL_YCBCR_MODE … /* Formula A for YCbCR->RGB = 0, Formula B = 1 */ #define ILI9322_POL_FORMULA … /* Reverse polarity: 0 = 0..255, 1 = 255..0 */ #define ILI9322_POL_REV … #define ILI9322_IF_CTRL … #define ILI9322_IF_CTRL_HSYNC_VSYNC … #define ILI9322_IF_CTRL_HSYNC_VSYNC_DE … #define ILI9322_IF_CTRL_DE_ONLY … #define ILI9322_IF_CTRL_SYNC_DISABLED … #define ILI9322_IF_CTRL_LINE_INVERSION … #define ILI9322_GLOBAL_RESET … #define ILI9322_GLOBAL_RESET_ASSERT … /* * 4+4 bits of negative and positive gamma correction * Upper nybble, bits 4-7 are negative gamma * Lower nybble, bits 0-3 are positive gamma */ #define ILI9322_GAMMA_1 … #define ILI9322_GAMMA_2 … #define ILI9322_GAMMA_3 … #define ILI9322_GAMMA_4 … #define ILI9322_GAMMA_5 … #define ILI9322_GAMMA_6 … #define ILI9322_GAMMA_7 … #define ILI9322_GAMMA_8 … /* * enum ili9322_input - the format of the incoming signal to the panel * * The panel can be connected to various input streams and four of them can * be selected by electronic straps on the display. However it is possible * to select another mode or override the electronic default with this * setting. */ enum ili9322_input { … }; static const char * const ili9322_inputs[] = …; /** * struct ili9322_config - the system specific ILI9322 configuration * @width_mm: physical panel width [mm] * @height_mm: physical panel height [mm] * @flip_horizontal: flip the image horizontally (right-to-left scan) * (only in RGB and YUV modes) * @flip_vertical: flip the image vertically (down-to-up scan) * (only in RGB and YUV modes) * @input: the input/entry type used in this system, if this is set to * ILI9322_INPUT_UNKNOWN the driver will try to figure it out by probing * the hardware * @vreg1out_mv: the output in microvolts for the VREGOUT1 regulator used * to drive the physical display. Valid ranges are 3600 thru 6000 in 100 * microvolt increments. If not specified, hardware defaults will be * used (4.5V). * @vcom_high_percent: the percentage of VREGOUT1 used for the peak * voltage on the communications link. Valid ranges are 37 thru 100 * percent. If not specified, hardware defaults will be used (91%). * @vcom_amplitude_percent: the percentage of VREGOUT1 used for the * peak-to-peak amplitude of the communcation signals to the physical * display. Valid ranges are 70 thru 132 percent in increments if two * percent. Odd percentages will be truncated. If not specified, hardware * defaults will be used (114%). * @dclk_active_high: data/pixel clock active high, data will be clocked * in on the rising edge of the DCLK (this is usually the case). * @syncmode: The synchronization mode, what sync signals are emitted. * See the enum for details. * @de_active_high: DE (data entry) is active high * @hsync_active_high: HSYNC is active high * @vsync_active_high: VSYNC is active high * @gamma_corr_pos: a set of 8 nybbles describing positive * gamma correction for voltages V1 thru V8. Valid range 0..15 * @gamma_corr_neg: a set of 8 nybbles describing negative * gamma correction for voltages V1 thru V8. Valid range 0..15 * * These adjust what grayscale voltage will be output for input data V1 = 0, * V2 = 16, V3 = 48, V4 = 96, V5 = 160, V6 = 208, V7 = 240 and V8 = 255. * The curve is shaped like this: * * ^ * | V8 * | V7 * | V6 * | V5 * | V4 * | V3 * | V2 * | V1 * +-----------------------------------------------------------> * 0 16 48 96 160 208 240 255 * * The negative and postive gamma values adjust the V1 thru V8 up/down * according to the datasheet specifications. This is a property of the * physical display connected to the display controller and may vary. * If defined, both arrays must be supplied in full. If the properties * are not supplied, hardware defaults will be used. */ struct ili9322_config { … }; struct ili9322 { … }; static inline struct ili9322 *panel_to_ili9322(struct drm_panel *panel) { … } static int ili9322_regmap_spi_write(void *context, const void *data, size_t count) { … } static int ili9322_regmap_spi_read(void *context, const void *reg, size_t reg_size, void *val, size_t val_size) { … } static struct regmap_bus ili9322_regmap_bus = …; static bool ili9322_writeable_reg(struct device *dev, unsigned int reg) { … } static const struct regmap_config ili9322_regmap_config = …; static int ili9322_init(struct drm_panel *panel, struct ili9322 *ili) { … } /* * This power-on sequence if from the datasheet, page 57. */ static int ili9322_power_on(struct ili9322 *ili) { … } static int ili9322_power_off(struct ili9322 *ili) { … } static int ili9322_disable(struct drm_panel *panel) { … } static int ili9322_unprepare(struct drm_panel *panel) { … } static int ili9322_prepare(struct drm_panel *panel) { … } static int ili9322_enable(struct drm_panel *panel) { … } /* Serial RGB modes */ static const struct drm_display_mode srgb_320x240_mode = …; static const struct drm_display_mode srgb_360x240_mode = …; /* This is the only mode listed for parallel RGB in the datasheet */ static const struct drm_display_mode prgb_320x240_mode = …; /* YUV modes */ static const struct drm_display_mode yuv_640x320_mode = …; static const struct drm_display_mode yuv_720x360_mode = …; /* BT.656 VGA mode, 640x480 */ static const struct drm_display_mode itu_r_bt_656_640_mode = …; /* BT.656 D1 mode 720x480 */ static const struct drm_display_mode itu_r_bt_656_720_mode = …; static int ili9322_get_modes(struct drm_panel *panel, struct drm_connector *connector) { … } static const struct drm_panel_funcs ili9322_drm_funcs = …; static int ili9322_probe(struct spi_device *spi) { … } static void ili9322_remove(struct spi_device *spi) { … } /* * The D-Link DIR-685 panel is marked LM918A01-1A SY-B4-091116-E0199 */ static const struct ili9322_config ili9322_dir_685 = …; static const struct of_device_id ili9322_of_match[] = …; MODULE_DEVICE_TABLE(of, ili9322_of_match); static struct spi_driver ili9322_driver = …; module_spi_driver(…) …; MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;