1a3a5f9d0SLinus Walleij // SPDX-License-Identifier: GPL-2.0 2a3a5f9d0SLinus Walleij /* 3a3a5f9d0SLinus Walleij * Panel driver for the Samsung LMS397KF04 480x800 DPI RGB panel. 4a3a5f9d0SLinus Walleij * According to the data sheet the display controller is called DB7430. 5a3a5f9d0SLinus Walleij * Found in the Samsung Galaxy Beam GT-I8350 mobile phone. 6a3a5f9d0SLinus Walleij * Linus Walleij <linus.walleij@linaro.org> 7a3a5f9d0SLinus Walleij */ 8a3a5f9d0SLinus Walleij #include <drm/drm_mipi_dbi.h> 9a3a5f9d0SLinus Walleij #include <drm/drm_modes.h> 10a3a5f9d0SLinus Walleij #include <drm/drm_panel.h> 11a3a5f9d0SLinus Walleij 12a3a5f9d0SLinus Walleij #include <linux/delay.h> 13a3a5f9d0SLinus Walleij #include <linux/gpio/consumer.h> 14a3a5f9d0SLinus Walleij #include <linux/init.h> 15a3a5f9d0SLinus Walleij #include <linux/kernel.h> 16a3a5f9d0SLinus Walleij #include <linux/media-bus-format.h> 17a3a5f9d0SLinus Walleij #include <linux/module.h> 18a3a5f9d0SLinus Walleij #include <linux/of.h> 19a3a5f9d0SLinus Walleij #include <linux/regulator/consumer.h> 20a3a5f9d0SLinus Walleij #include <linux/spi/spi.h> 21a3a5f9d0SLinus Walleij 22a3a5f9d0SLinus Walleij #include <video/mipi_display.h> 23a3a5f9d0SLinus Walleij 24a3a5f9d0SLinus Walleij #define DB7430_ACCESS_PROT_OFF 0xb0 25a3a5f9d0SLinus Walleij #define DB7430_UNKNOWN_B4 0xb4 26a3a5f9d0SLinus Walleij #define DB7430_USER_SELECT 0xb5 27a3a5f9d0SLinus Walleij #define DB7430_UNKNOWN_B7 0xb7 28a3a5f9d0SLinus Walleij #define DB7430_UNKNOWN_B8 0xb8 29a3a5f9d0SLinus Walleij #define DB7430_PANEL_DRIVING 0xc0 30a3a5f9d0SLinus Walleij #define DB7430_SOURCE_CONTROL 0xc1 31a3a5f9d0SLinus Walleij #define DB7430_GATE_INTERFACE 0xc4 32a3a5f9d0SLinus Walleij #define DB7430_DISPLAY_H_TIMING 0xc5 33a3a5f9d0SLinus Walleij #define DB7430_RGB_SYNC_OPTION 0xc6 34a3a5f9d0SLinus Walleij #define DB7430_GAMMA_SET_RED 0xc8 35a3a5f9d0SLinus Walleij #define DB7430_GAMMA_SET_GREEN 0xc9 36a3a5f9d0SLinus Walleij #define DB7430_GAMMA_SET_BLUE 0xca 37a3a5f9d0SLinus Walleij #define DB7430_BIAS_CURRENT_CTRL 0xd1 38a3a5f9d0SLinus Walleij #define DB7430_DDV_CTRL 0xd2 39a3a5f9d0SLinus Walleij #define DB7430_GAMMA_CTRL_REF 0xd3 40a3a5f9d0SLinus Walleij #define DB7430_UNKNOWN_D4 0xd4 41a3a5f9d0SLinus Walleij #define DB7430_DCDC_CTRL 0xd5 42a3a5f9d0SLinus Walleij #define DB7430_VCL_CTRL 0xd6 43a3a5f9d0SLinus Walleij #define DB7430_UNKNOWN_F8 0xf8 44a3a5f9d0SLinus Walleij #define DB7430_UNKNOWN_FC 0xfc 45a3a5f9d0SLinus Walleij 46a3a5f9d0SLinus Walleij #define DATA_MASK 0x100 47a3a5f9d0SLinus Walleij 48a3a5f9d0SLinus Walleij /** 49a3a5f9d0SLinus Walleij * struct db7430 - state container for a panel controlled by the DB7430 50a3a5f9d0SLinus Walleij * controller 51a3a5f9d0SLinus Walleij */ 52a3a5f9d0SLinus Walleij struct db7430 { 53a3a5f9d0SLinus Walleij /** @dev: the container device */ 54a3a5f9d0SLinus Walleij struct device *dev; 55a3a5f9d0SLinus Walleij /** @dbi: the DBI bus abstraction handle */ 56a3a5f9d0SLinus Walleij struct mipi_dbi dbi; 57a3a5f9d0SLinus Walleij /** @panel: the DRM panel instance for this device */ 58a3a5f9d0SLinus Walleij struct drm_panel panel; 59a3a5f9d0SLinus Walleij /** @width: the width of this panel in mm */ 60a3a5f9d0SLinus Walleij u32 width; 61a3a5f9d0SLinus Walleij /** @height: the height of this panel in mm */ 62a3a5f9d0SLinus Walleij u32 height; 63a3a5f9d0SLinus Walleij /** @reset: reset GPIO line */ 64a3a5f9d0SLinus Walleij struct gpio_desc *reset; 65a3a5f9d0SLinus Walleij /** @regulators: VCCIO and VIO supply regulators */ 66a3a5f9d0SLinus Walleij struct regulator_bulk_data regulators[2]; 67a3a5f9d0SLinus Walleij }; 68a3a5f9d0SLinus Walleij 69a3a5f9d0SLinus Walleij static const struct drm_display_mode db7430_480_800_mode = { 70a3a5f9d0SLinus Walleij /* 71a3a5f9d0SLinus Walleij * 31 ns period min (htotal*vtotal*vrefresh)/1000 72a3a5f9d0SLinus Walleij * gives a Vrefresh of ~71 Hz. 73a3a5f9d0SLinus Walleij */ 74a3a5f9d0SLinus Walleij .clock = 32258, 75a3a5f9d0SLinus Walleij .hdisplay = 480, 76a3a5f9d0SLinus Walleij .hsync_start = 480 + 10, 77a3a5f9d0SLinus Walleij .hsync_end = 480 + 10 + 4, 78a3a5f9d0SLinus Walleij .htotal = 480 + 10 + 4 + 40, 79a3a5f9d0SLinus Walleij .vdisplay = 800, 80a3a5f9d0SLinus Walleij .vsync_start = 800 + 6, 81a3a5f9d0SLinus Walleij .vsync_end = 800 + 6 + 1, 82a3a5f9d0SLinus Walleij .vtotal = 800 + 6 + 1 + 7, 83a3a5f9d0SLinus Walleij .width_mm = 53, 84a3a5f9d0SLinus Walleij .height_mm = 87, 85a3a5f9d0SLinus Walleij .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, 86a3a5f9d0SLinus Walleij }; 87a3a5f9d0SLinus Walleij 88a3a5f9d0SLinus Walleij static inline struct db7430 *to_db7430(struct drm_panel *panel) 89a3a5f9d0SLinus Walleij { 90a3a5f9d0SLinus Walleij return container_of(panel, struct db7430, panel); 91a3a5f9d0SLinus Walleij } 92a3a5f9d0SLinus Walleij 93a3a5f9d0SLinus Walleij static int db7430_power_on(struct db7430 *db) 94a3a5f9d0SLinus Walleij { 95a3a5f9d0SLinus Walleij struct mipi_dbi *dbi = &db->dbi; 96a3a5f9d0SLinus Walleij int ret; 97a3a5f9d0SLinus Walleij 98a3a5f9d0SLinus Walleij /* Power up */ 99a3a5f9d0SLinus Walleij ret = regulator_bulk_enable(ARRAY_SIZE(db->regulators), 100a3a5f9d0SLinus Walleij db->regulators); 101a3a5f9d0SLinus Walleij if (ret) { 102a3a5f9d0SLinus Walleij dev_err(db->dev, "failed to enable regulators: %d\n", ret); 103a3a5f9d0SLinus Walleij return ret; 104a3a5f9d0SLinus Walleij } 105a3a5f9d0SLinus Walleij msleep(50); 106a3a5f9d0SLinus Walleij 107a3a5f9d0SLinus Walleij /* Assert reset >=1 ms */ 108a3a5f9d0SLinus Walleij gpiod_set_value_cansleep(db->reset, 1); 109a3a5f9d0SLinus Walleij usleep_range(1000, 5000); 110a3a5f9d0SLinus Walleij /* De-assert reset */ 111a3a5f9d0SLinus Walleij gpiod_set_value_cansleep(db->reset, 0); 112a3a5f9d0SLinus Walleij /* Wait >= 10 ms */ 113a3a5f9d0SLinus Walleij msleep(10); 114a3a5f9d0SLinus Walleij dev_dbg(db->dev, "de-asserted RESET\n"); 115a3a5f9d0SLinus Walleij 116a3a5f9d0SLinus Walleij /* 117a3a5f9d0SLinus Walleij * This is set to 0x0a (RGB/BGR order + horizontal flip) in order 118a3a5f9d0SLinus Walleij * to make the display behave normally. If this is not set the displays 119a3a5f9d0SLinus Walleij * normal output behaviour is horizontally flipped and BGR ordered. Do 120a3a5f9d0SLinus Walleij * it twice because the first message doesn't always "take". 121a3a5f9d0SLinus Walleij */ 122a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, 0x0a); 123a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, 0x0a); 124a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, DB7430_ACCESS_PROT_OFF, 0x00); 125a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, DB7430_PANEL_DRIVING, 0x28, 0x08); 126a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, DB7430_SOURCE_CONTROL, 127a3a5f9d0SLinus Walleij 0x01, 0x30, 0x15, 0x05, 0x22); 128a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, DB7430_GATE_INTERFACE, 129a3a5f9d0SLinus Walleij 0x10, 0x01, 0x00); 130a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, DB7430_DISPLAY_H_TIMING, 131a3a5f9d0SLinus Walleij 0x06, 0x55, 0x03, 0x07, 0x0b, 132a3a5f9d0SLinus Walleij 0x33, 0x00, 0x01, 0x03); 133a3a5f9d0SLinus Walleij /* 134a3a5f9d0SLinus Walleij * 0x00 in datasheet 0x01 in vendor code 0x00, it seems 0x01 means 135a3a5f9d0SLinus Walleij * DE active high and 0x00 means DE active low. 136a3a5f9d0SLinus Walleij */ 137a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, DB7430_RGB_SYNC_OPTION, 0x01); 138a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, DB7430_GAMMA_SET_RED, 139a3a5f9d0SLinus Walleij /* R positive gamma */ 0x00, 140a3a5f9d0SLinus Walleij 0x0A, 0x31, 0x3B, 0x4E, 0x58, 0x59, 0x5B, 0x58, 0x5E, 0x62, 141a3a5f9d0SLinus Walleij 0x60, 0x61, 0x5E, 0x62, 0x55, 0x55, 0x7F, 0x08, 142a3a5f9d0SLinus Walleij /* R negative gamma */ 0x00, 143a3a5f9d0SLinus Walleij 0x0A, 0x31, 0x3B, 0x4E, 0x58, 0x59, 0x5B, 0x58, 0x5E, 0x62, 144a3a5f9d0SLinus Walleij 0x60, 0x61, 0x5E, 0x62, 0x55, 0x55, 0x7F, 0x08); 145a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, DB7430_GAMMA_SET_GREEN, 146a3a5f9d0SLinus Walleij /* G positive gamma */ 0x00, 147a3a5f9d0SLinus Walleij 0x25, 0x15, 0x28, 0x3D, 0x4A, 0x48, 0x4C, 0x4A, 0x52, 0x59, 148a3a5f9d0SLinus Walleij 0x59, 0x5B, 0x56, 0x60, 0x5D, 0x55, 0x7F, 0x0A, 149a3a5f9d0SLinus Walleij /* G negative gamma */ 0x00, 150a3a5f9d0SLinus Walleij 0x25, 0x15, 0x28, 0x3D, 0x4A, 0x48, 0x4C, 0x4A, 0x52, 0x59, 151a3a5f9d0SLinus Walleij 0x59, 0x5B, 0x56, 0x60, 0x5D, 0x55, 0x7F, 0x0A); 152a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, DB7430_GAMMA_SET_BLUE, 153a3a5f9d0SLinus Walleij /* B positive gamma */ 0x00, 154a3a5f9d0SLinus Walleij 0x48, 0x10, 0x1F, 0x2F, 0x35, 0x38, 0x3D, 0x3C, 0x45, 0x4D, 155a3a5f9d0SLinus Walleij 0x4E, 0x52, 0x51, 0x60, 0x7F, 0x7E, 0x7F, 0x0C, 156a3a5f9d0SLinus Walleij /* B negative gamma */ 0x00, 157a3a5f9d0SLinus Walleij 0x48, 0x10, 0x1F, 0x2F, 0x35, 0x38, 0x3D, 0x3C, 0x45, 0x4D, 158a3a5f9d0SLinus Walleij 0x4E, 0x52, 0x51, 0x60, 0x7F, 0x7E, 0x7F, 0x0C); 159a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, DB7430_BIAS_CURRENT_CTRL, 0x33, 0x13); 160a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, DB7430_DDV_CTRL, 0x11, 0x00, 0x00); 161a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, DB7430_GAMMA_CTRL_REF, 0x50, 0x50); 162a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, DB7430_DCDC_CTRL, 0x2f, 0x11, 0x1e, 0x46); 163a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, DB7430_VCL_CTRL, 0x11, 0x0a); 164a3a5f9d0SLinus Walleij 165a3a5f9d0SLinus Walleij return 0; 166a3a5f9d0SLinus Walleij } 167a3a5f9d0SLinus Walleij 168a3a5f9d0SLinus Walleij static int db7430_power_off(struct db7430 *db) 169a3a5f9d0SLinus Walleij { 170a3a5f9d0SLinus Walleij /* Go into RESET and disable regulators */ 171a3a5f9d0SLinus Walleij gpiod_set_value_cansleep(db->reset, 1); 172a3a5f9d0SLinus Walleij return regulator_bulk_disable(ARRAY_SIZE(db->regulators), 173a3a5f9d0SLinus Walleij db->regulators); 174a3a5f9d0SLinus Walleij } 175a3a5f9d0SLinus Walleij 176a3a5f9d0SLinus Walleij static int db7430_unprepare(struct drm_panel *panel) 177a3a5f9d0SLinus Walleij { 178a3a5f9d0SLinus Walleij return db7430_power_off(to_db7430(panel)); 179a3a5f9d0SLinus Walleij } 180a3a5f9d0SLinus Walleij 181a3a5f9d0SLinus Walleij static int db7430_disable(struct drm_panel *panel) 182a3a5f9d0SLinus Walleij { 183a3a5f9d0SLinus Walleij struct db7430 *db = to_db7430(panel); 184a3a5f9d0SLinus Walleij struct mipi_dbi *dbi = &db->dbi; 185a3a5f9d0SLinus Walleij 186a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_OFF); 187a3a5f9d0SLinus Walleij msleep(25); 188a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, MIPI_DCS_ENTER_SLEEP_MODE); 189a3a5f9d0SLinus Walleij msleep(120); 190a3a5f9d0SLinus Walleij 191a3a5f9d0SLinus Walleij return 0; 192a3a5f9d0SLinus Walleij } 193a3a5f9d0SLinus Walleij 194a3a5f9d0SLinus Walleij static int db7430_prepare(struct drm_panel *panel) 195a3a5f9d0SLinus Walleij { 196a3a5f9d0SLinus Walleij return db7430_power_on(to_db7430(panel)); 197a3a5f9d0SLinus Walleij } 198a3a5f9d0SLinus Walleij 199a3a5f9d0SLinus Walleij static int db7430_enable(struct drm_panel *panel) 200a3a5f9d0SLinus Walleij { 201a3a5f9d0SLinus Walleij struct db7430 *db = to_db7430(panel); 202a3a5f9d0SLinus Walleij struct mipi_dbi *dbi = &db->dbi; 203a3a5f9d0SLinus Walleij 204a3a5f9d0SLinus Walleij /* Exit sleep mode */ 205a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE); 206a3a5f9d0SLinus Walleij msleep(20); 207a3a5f9d0SLinus Walleij 208a3a5f9d0SLinus Walleij /* NVM (non-volatile memory) load sequence */ 209a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, DB7430_UNKNOWN_D4, 0x52, 0x5e); 210a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, DB7430_UNKNOWN_F8, 0x01, 0xf5, 0xf2, 0x71, 0x44); 211a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, DB7430_UNKNOWN_FC, 0x00, 0x08); 212a3a5f9d0SLinus Walleij msleep(150); 213a3a5f9d0SLinus Walleij 214a3a5f9d0SLinus Walleij /* CABC turn on sequence (BC = backlight control) */ 215a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, DB7430_UNKNOWN_B4, 0x0f, 0x00, 0x50); 216a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, DB7430_USER_SELECT, 0x80); 217a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, DB7430_UNKNOWN_B7, 0x24); 218a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, DB7430_UNKNOWN_B8, 0x01); 219a3a5f9d0SLinus Walleij 220a3a5f9d0SLinus Walleij /* Turn on display */ 221a3a5f9d0SLinus Walleij mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON); 222a3a5f9d0SLinus Walleij 223a3a5f9d0SLinus Walleij return 0; 224a3a5f9d0SLinus Walleij } 225a3a5f9d0SLinus Walleij 226a3a5f9d0SLinus Walleij /** 227a3a5f9d0SLinus Walleij * db7430_get_modes() - return the mode 228a3a5f9d0SLinus Walleij * @panel: the panel to get the mode for 229a3a5f9d0SLinus Walleij * @connector: reference to the central DRM connector control structure 230a3a5f9d0SLinus Walleij */ 231a3a5f9d0SLinus Walleij static int db7430_get_modes(struct drm_panel *panel, 232a3a5f9d0SLinus Walleij struct drm_connector *connector) 233a3a5f9d0SLinus Walleij { 234a3a5f9d0SLinus Walleij struct db7430 *db = to_db7430(panel); 235a3a5f9d0SLinus Walleij struct drm_display_mode *mode; 236a3a5f9d0SLinus Walleij static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; 237a3a5f9d0SLinus Walleij 238a3a5f9d0SLinus Walleij mode = drm_mode_duplicate(connector->dev, &db7430_480_800_mode); 239a3a5f9d0SLinus Walleij if (!mode) { 240a3a5f9d0SLinus Walleij dev_err(db->dev, "failed to add mode\n"); 241a3a5f9d0SLinus Walleij return -ENOMEM; 242a3a5f9d0SLinus Walleij } 243a3a5f9d0SLinus Walleij 244a3a5f9d0SLinus Walleij connector->display_info.bpc = 8; 245a3a5f9d0SLinus Walleij connector->display_info.width_mm = mode->width_mm; 246a3a5f9d0SLinus Walleij connector->display_info.height_mm = mode->height_mm; 247a3a5f9d0SLinus Walleij connector->display_info.bus_flags = 248a3a5f9d0SLinus Walleij DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE; 249a3a5f9d0SLinus Walleij drm_display_info_set_bus_formats(&connector->display_info, 250a3a5f9d0SLinus Walleij &bus_format, 1); 251a3a5f9d0SLinus Walleij 252a3a5f9d0SLinus Walleij drm_mode_set_name(mode); 253a3a5f9d0SLinus Walleij mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 254a3a5f9d0SLinus Walleij 255a3a5f9d0SLinus Walleij drm_mode_probed_add(connector, mode); 256a3a5f9d0SLinus Walleij 257a3a5f9d0SLinus Walleij return 1; 258a3a5f9d0SLinus Walleij } 259a3a5f9d0SLinus Walleij 260a3a5f9d0SLinus Walleij static const struct drm_panel_funcs db7430_drm_funcs = { 261a3a5f9d0SLinus Walleij .disable = db7430_disable, 262a3a5f9d0SLinus Walleij .unprepare = db7430_unprepare, 263a3a5f9d0SLinus Walleij .prepare = db7430_prepare, 264a3a5f9d0SLinus Walleij .enable = db7430_enable, 265a3a5f9d0SLinus Walleij .get_modes = db7430_get_modes, 266a3a5f9d0SLinus Walleij }; 267a3a5f9d0SLinus Walleij 268a3a5f9d0SLinus Walleij static int db7430_probe(struct spi_device *spi) 269a3a5f9d0SLinus Walleij { 270a3a5f9d0SLinus Walleij struct device *dev = &spi->dev; 271a3a5f9d0SLinus Walleij struct db7430 *db; 272a3a5f9d0SLinus Walleij int ret; 273a3a5f9d0SLinus Walleij 274a3a5f9d0SLinus Walleij db = devm_kzalloc(dev, sizeof(*db), GFP_KERNEL); 275a3a5f9d0SLinus Walleij if (!db) 276a3a5f9d0SLinus Walleij return -ENOMEM; 277a3a5f9d0SLinus Walleij db->dev = dev; 278a3a5f9d0SLinus Walleij 279a3a5f9d0SLinus Walleij /* 280a3a5f9d0SLinus Walleij * VCI is the analog voltage supply 281a3a5f9d0SLinus Walleij * VCCIO is the digital I/O voltage supply 282a3a5f9d0SLinus Walleij */ 283a3a5f9d0SLinus Walleij db->regulators[0].supply = "vci"; 284a3a5f9d0SLinus Walleij db->regulators[1].supply = "vccio"; 285a3a5f9d0SLinus Walleij ret = devm_regulator_bulk_get(dev, 286a3a5f9d0SLinus Walleij ARRAY_SIZE(db->regulators), 287a3a5f9d0SLinus Walleij db->regulators); 288a3a5f9d0SLinus Walleij if (ret) 289a3a5f9d0SLinus Walleij return dev_err_probe(dev, ret, "failed to get regulators\n"); 290a3a5f9d0SLinus Walleij 291a3a5f9d0SLinus Walleij db->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 292a3a5f9d0SLinus Walleij if (IS_ERR(db->reset)) { 293a3a5f9d0SLinus Walleij ret = PTR_ERR(db->reset); 294a3a5f9d0SLinus Walleij return dev_err_probe(dev, ret, "no RESET GPIO\n"); 295a3a5f9d0SLinus Walleij } 296a3a5f9d0SLinus Walleij 297a3a5f9d0SLinus Walleij ret = mipi_dbi_spi_init(spi, &db->dbi, NULL); 298a3a5f9d0SLinus Walleij if (ret) 299a3a5f9d0SLinus Walleij return dev_err_probe(dev, ret, "MIPI DBI init failed\n"); 300a3a5f9d0SLinus Walleij 301a3a5f9d0SLinus Walleij drm_panel_init(&db->panel, dev, &db7430_drm_funcs, 302a3a5f9d0SLinus Walleij DRM_MODE_CONNECTOR_DPI); 303a3a5f9d0SLinus Walleij 304a3a5f9d0SLinus Walleij /* FIXME: if no external backlight, use internal backlight */ 305a3a5f9d0SLinus Walleij ret = drm_panel_of_backlight(&db->panel); 306a3a5f9d0SLinus Walleij if (ret) 307a3a5f9d0SLinus Walleij return dev_err_probe(dev, ret, "failed to add backlight\n"); 308a3a5f9d0SLinus Walleij 309a3a5f9d0SLinus Walleij spi_set_drvdata(spi, db); 310a3a5f9d0SLinus Walleij 311a3a5f9d0SLinus Walleij drm_panel_add(&db->panel); 312a3a5f9d0SLinus Walleij dev_dbg(dev, "added panel\n"); 313a3a5f9d0SLinus Walleij 314a3a5f9d0SLinus Walleij return 0; 315a3a5f9d0SLinus Walleij } 316a3a5f9d0SLinus Walleij 317a0386bbaSUwe Kleine-König static void db7430_remove(struct spi_device *spi) 318a3a5f9d0SLinus Walleij { 319a3a5f9d0SLinus Walleij struct db7430 *db = spi_get_drvdata(spi); 320a3a5f9d0SLinus Walleij 321a3a5f9d0SLinus Walleij drm_panel_remove(&db->panel); 322a3a5f9d0SLinus Walleij } 323a3a5f9d0SLinus Walleij 324a3a5f9d0SLinus Walleij /* 325a3a5f9d0SLinus Walleij * The DB7430 display controller may be used in several display products, 326a3a5f9d0SLinus Walleij * so list the different variants here and add per-variant data if needed. 327a3a5f9d0SLinus Walleij */ 328a3a5f9d0SLinus Walleij static const struct of_device_id db7430_match[] = { 329a3a5f9d0SLinus Walleij { .compatible = "samsung,lms397kf04", }, 330a3a5f9d0SLinus Walleij {}, 331a3a5f9d0SLinus Walleij }; 332a3a5f9d0SLinus Walleij MODULE_DEVICE_TABLE(of, db7430_match); 333a3a5f9d0SLinus Walleij 334*bd8eb086SWei Yongjun static const struct spi_device_id db7430_ids[] = { 335*bd8eb086SWei Yongjun { "lms397kf04" }, 336*bd8eb086SWei Yongjun { }, 337*bd8eb086SWei Yongjun }; 338*bd8eb086SWei Yongjun MODULE_DEVICE_TABLE(spi, db7430_ids); 339*bd8eb086SWei Yongjun 340a3a5f9d0SLinus Walleij static struct spi_driver db7430_driver = { 341a3a5f9d0SLinus Walleij .probe = db7430_probe, 342a3a5f9d0SLinus Walleij .remove = db7430_remove, 343*bd8eb086SWei Yongjun .id_table = db7430_ids, 344a3a5f9d0SLinus Walleij .driver = { 345a3a5f9d0SLinus Walleij .name = "db7430-panel", 346a3a5f9d0SLinus Walleij .of_match_table = db7430_match, 347a3a5f9d0SLinus Walleij }, 348a3a5f9d0SLinus Walleij }; 349a3a5f9d0SLinus Walleij module_spi_driver(db7430_driver); 350a3a5f9d0SLinus Walleij 351a3a5f9d0SLinus Walleij MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); 352a3a5f9d0SLinus Walleij MODULE_DESCRIPTION("Samsung DB7430 panel driver"); 353a3a5f9d0SLinus Walleij MODULE_LICENSE("GPL v2"); 354