1f40f5b87SLinus Walleij // SPDX-License-Identifier: GPL-2.0 2f40f5b87SLinus Walleij /* 3f40f5b87SLinus Walleij * Panel driver for the ARM Versatile family reference designs from 4f40f5b87SLinus Walleij * ARM Limited. 5f40f5b87SLinus Walleij * 6f40f5b87SLinus Walleij * Author: 7f40f5b87SLinus Walleij * Linus Walleij <linus.wallei@linaro.org> 8f40f5b87SLinus Walleij * 9f40f5b87SLinus Walleij * On the Versatile AB, these panels come mounted on daughterboards 10f40f5b87SLinus Walleij * named "IB1" or "IB2" (Interface Board 1 & 2 respectively.) They 11f40f5b87SLinus Walleij * are documented in ARM DUI 0225D Appendix C and D. These daughter 12f40f5b87SLinus Walleij * boards support TFT display panels. 13f40f5b87SLinus Walleij * 14f40f5b87SLinus Walleij * - The IB1 is a passive board where the display connector defines a 15f40f5b87SLinus Walleij * few wires for encoding the display type for autodetection, 16f40f5b87SLinus Walleij * suitable display settings can then be looked up from this setting. 17f40f5b87SLinus Walleij * The magic bits can be read out from the system controller. 18f40f5b87SLinus Walleij * 19f40f5b87SLinus Walleij * - The IB2 is a more complex board intended for GSM phone development 20f40f5b87SLinus Walleij * with some logic and a control register, which needs to be accessed 21f40f5b87SLinus Walleij * and the board display needs to be turned on explicitly. 22f40f5b87SLinus Walleij * 23f40f5b87SLinus Walleij * On the Versatile PB, a special CLCD adaptor board is available 24f40f5b87SLinus Walleij * supporting the same displays as the Versatile AB, plus one more 25f40f5b87SLinus Walleij * Epson QCIF display. 26f40f5b87SLinus Walleij * 27f40f5b87SLinus Walleij */ 28f40f5b87SLinus Walleij 29f40f5b87SLinus Walleij #include <linux/bitops.h> 30f40f5b87SLinus Walleij #include <linux/init.h> 31f40f5b87SLinus Walleij #include <linux/kernel.h> 32f40f5b87SLinus Walleij #include <linux/mfd/syscon.h> 33cb23eae3SSam Ravnborg #include <linux/mod_devicetable.h> 34f40f5b87SLinus Walleij #include <linux/module.h> 35f40f5b87SLinus Walleij #include <linux/platform_device.h> 36f40f5b87SLinus Walleij #include <linux/regmap.h> 37f40f5b87SLinus Walleij 38f40f5b87SLinus Walleij #include <video/of_videomode.h> 39f40f5b87SLinus Walleij #include <video/videomode.h> 40f40f5b87SLinus Walleij 41cb23eae3SSam Ravnborg #include <drm/drm_modes.h> 42cb23eae3SSam Ravnborg #include <drm/drm_panel.h> 43cb23eae3SSam Ravnborg 44f40f5b87SLinus Walleij /* 45f40f5b87SLinus Walleij * This configuration register in the Versatile and RealView 46f40f5b87SLinus Walleij * family is uniformly present but appears more and more 47f40f5b87SLinus Walleij * unutilized starting with the RealView series. 48f40f5b87SLinus Walleij */ 49f40f5b87SLinus Walleij #define SYS_CLCD 0x50 50f40f5b87SLinus Walleij 51f40f5b87SLinus Walleij /* The Versatile can detect the connected panel type */ 52f40f5b87SLinus Walleij #define SYS_CLCD_CLCDID_MASK (BIT(8)|BIT(9)|BIT(10)|BIT(11)|BIT(12)) 53f40f5b87SLinus Walleij #define SYS_CLCD_ID_SANYO_3_8 (0x00 << 8) 54f40f5b87SLinus Walleij #define SYS_CLCD_ID_SHARP_8_4 (0x01 << 8) 55f40f5b87SLinus Walleij #define SYS_CLCD_ID_EPSON_2_2 (0x02 << 8) 56f40f5b87SLinus Walleij #define SYS_CLCD_ID_SANYO_2_5 (0x07 << 8) 57f40f5b87SLinus Walleij #define SYS_CLCD_ID_VGA (0x1f << 8) 58f40f5b87SLinus Walleij 59f40f5b87SLinus Walleij /* IB2 control register for the Versatile daughterboard */ 60f40f5b87SLinus Walleij #define IB2_CTRL 0x00 61f40f5b87SLinus Walleij #define IB2_CTRL_LCD_SD BIT(1) /* 1 = shut down LCD */ 62f40f5b87SLinus Walleij #define IB2_CTRL_LCD_BL_ON BIT(0) 63f40f5b87SLinus Walleij #define IB2_CTRL_LCD_MASK (BIT(0)|BIT(1)) 64f40f5b87SLinus Walleij 65f40f5b87SLinus Walleij /** 66f40f5b87SLinus Walleij * struct versatile_panel_type - lookup struct for the supported panels 67f40f5b87SLinus Walleij */ 68f40f5b87SLinus Walleij struct versatile_panel_type { 69f40f5b87SLinus Walleij /** 70f40f5b87SLinus Walleij * @name: the name of this panel 71f40f5b87SLinus Walleij */ 72f40f5b87SLinus Walleij const char *name; 73f40f5b87SLinus Walleij /** 74f40f5b87SLinus Walleij * @magic: the magic value from the detection register 75f40f5b87SLinus Walleij */ 76f40f5b87SLinus Walleij u32 magic; 77f40f5b87SLinus Walleij /** 78f40f5b87SLinus Walleij * @mode: the DRM display mode for this panel 79f40f5b87SLinus Walleij */ 80f40f5b87SLinus Walleij struct drm_display_mode mode; 81f40f5b87SLinus Walleij /** 82f40f5b87SLinus Walleij * @bus_flags: the DRM bus flags for this panel e.g. inverted clock 83f40f5b87SLinus Walleij */ 84f40f5b87SLinus Walleij u32 bus_flags; 85f40f5b87SLinus Walleij /** 86f40f5b87SLinus Walleij * @width_mm: the panel width in mm 87f40f5b87SLinus Walleij */ 88f40f5b87SLinus Walleij u32 width_mm; 89f40f5b87SLinus Walleij /** 90f40f5b87SLinus Walleij * @height_mm: the panel height in mm 91f40f5b87SLinus Walleij */ 92f40f5b87SLinus Walleij u32 height_mm; 93f40f5b87SLinus Walleij /** 94f40f5b87SLinus Walleij * @ib2: the panel may be connected on an IB2 daughterboard 95f40f5b87SLinus Walleij */ 96f40f5b87SLinus Walleij bool ib2; 97f40f5b87SLinus Walleij }; 98f40f5b87SLinus Walleij 99f40f5b87SLinus Walleij /** 100f40f5b87SLinus Walleij * struct versatile_panel - state container for the Versatile panels 101f40f5b87SLinus Walleij */ 102f40f5b87SLinus Walleij struct versatile_panel { 103f40f5b87SLinus Walleij /** 104f40f5b87SLinus Walleij * @dev: the container device 105f40f5b87SLinus Walleij */ 106f40f5b87SLinus Walleij struct device *dev; 107f40f5b87SLinus Walleij /** 108f40f5b87SLinus Walleij * @panel: the DRM panel instance for this device 109f40f5b87SLinus Walleij */ 110f40f5b87SLinus Walleij struct drm_panel panel; 111f40f5b87SLinus Walleij /** 112f40f5b87SLinus Walleij * @panel_type: the Versatile panel type as detected 113f40f5b87SLinus Walleij */ 114f40f5b87SLinus Walleij const struct versatile_panel_type *panel_type; 115f40f5b87SLinus Walleij /** 116f40f5b87SLinus Walleij * @map: map to the parent syscon where the main register reside 117f40f5b87SLinus Walleij */ 118f40f5b87SLinus Walleij struct regmap *map; 119f40f5b87SLinus Walleij /** 120f40f5b87SLinus Walleij * @ib2_map: map to the IB2 syscon, if applicable 121f40f5b87SLinus Walleij */ 122f40f5b87SLinus Walleij struct regmap *ib2_map; 123f40f5b87SLinus Walleij }; 124f40f5b87SLinus Walleij 125f40f5b87SLinus Walleij static const struct versatile_panel_type versatile_panels[] = { 126f40f5b87SLinus Walleij /* 127f40f5b87SLinus Walleij * Sanyo TM38QV67A02A - 3.8 inch QVGA (320x240) Color TFT 128f40f5b87SLinus Walleij * found on the Versatile AB IB1 connector or the Versatile 129f40f5b87SLinus Walleij * PB adaptor board connector. 130f40f5b87SLinus Walleij */ 131f40f5b87SLinus Walleij { 132f40f5b87SLinus Walleij .name = "Sanyo TM38QV67A02A", 133f40f5b87SLinus Walleij .magic = SYS_CLCD_ID_SANYO_3_8, 134f40f5b87SLinus Walleij .width_mm = 79, 135f40f5b87SLinus Walleij .height_mm = 54, 136f40f5b87SLinus Walleij .mode = { 137fd9b503dSLinus Walleij .clock = 10000, 138f40f5b87SLinus Walleij .hdisplay = 320, 139f40f5b87SLinus Walleij .hsync_start = 320 + 6, 140f40f5b87SLinus Walleij .hsync_end = 320 + 6 + 6, 141f40f5b87SLinus Walleij .htotal = 320 + 6 + 6 + 6, 142f40f5b87SLinus Walleij .vdisplay = 240, 143f40f5b87SLinus Walleij .vsync_start = 240 + 5, 144f40f5b87SLinus Walleij .vsync_end = 240 + 5 + 6, 145f40f5b87SLinus Walleij .vtotal = 240 + 5 + 6 + 5, 146f40f5b87SLinus Walleij .vrefresh = 116, 147f40f5b87SLinus Walleij .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, 148f40f5b87SLinus Walleij }, 149f40f5b87SLinus Walleij }, 150f40f5b87SLinus Walleij /* 151f40f5b87SLinus Walleij * Sharp LQ084V1DG21 640x480 VGA Color TFT module 152f40f5b87SLinus Walleij * found on the Versatile AB IB1 connector or the Versatile 153f40f5b87SLinus Walleij * PB adaptor board connector. 154f40f5b87SLinus Walleij */ 155f40f5b87SLinus Walleij { 156f40f5b87SLinus Walleij .name = "Sharp LQ084V1DG21", 157f40f5b87SLinus Walleij .magic = SYS_CLCD_ID_SHARP_8_4, 158f40f5b87SLinus Walleij .width_mm = 171, 159f40f5b87SLinus Walleij .height_mm = 130, 160f40f5b87SLinus Walleij .mode = { 161fd9b503dSLinus Walleij .clock = 25000, 162f40f5b87SLinus Walleij .hdisplay = 640, 163f40f5b87SLinus Walleij .hsync_start = 640 + 24, 164f40f5b87SLinus Walleij .hsync_end = 640 + 24 + 96, 165f40f5b87SLinus Walleij .htotal = 640 + 24 + 96 + 24, 166f40f5b87SLinus Walleij .vdisplay = 480, 167f40f5b87SLinus Walleij .vsync_start = 480 + 11, 168f40f5b87SLinus Walleij .vsync_end = 480 + 11 + 2, 169f40f5b87SLinus Walleij .vtotal = 480 + 11 + 2 + 32, 170f40f5b87SLinus Walleij .vrefresh = 60, 171f40f5b87SLinus Walleij .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, 172f40f5b87SLinus Walleij }, 173f40f5b87SLinus Walleij }, 174f40f5b87SLinus Walleij /* 175f40f5b87SLinus Walleij * Epson L2F50113T00 - 2.2 inch QCIF 176x220 Color TFT 176f40f5b87SLinus Walleij * found on the Versatile PB adaptor board connector. 177f40f5b87SLinus Walleij */ 178f40f5b87SLinus Walleij { 179f40f5b87SLinus Walleij .name = "Epson L2F50113T00", 180f40f5b87SLinus Walleij .magic = SYS_CLCD_ID_EPSON_2_2, 181f40f5b87SLinus Walleij .width_mm = 34, 182f40f5b87SLinus Walleij .height_mm = 45, 183f40f5b87SLinus Walleij .mode = { 184fd9b503dSLinus Walleij .clock = 62500, 185f40f5b87SLinus Walleij .hdisplay = 176, 186f40f5b87SLinus Walleij .hsync_start = 176 + 2, 187f40f5b87SLinus Walleij .hsync_end = 176 + 2 + 3, 188f40f5b87SLinus Walleij .htotal = 176 + 2 + 3 + 3, 189f40f5b87SLinus Walleij .vdisplay = 220, 190f40f5b87SLinus Walleij .vsync_start = 220 + 0, 191f40f5b87SLinus Walleij .vsync_end = 220 + 0 + 2, 192f40f5b87SLinus Walleij .vtotal = 220 + 0 + 2 + 1, 193f40f5b87SLinus Walleij .vrefresh = 390, 194f40f5b87SLinus Walleij .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, 195f40f5b87SLinus Walleij }, 19688bc4178SLaurent Pinchart .bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE, 197f40f5b87SLinus Walleij }, 198f40f5b87SLinus Walleij /* 199f40f5b87SLinus Walleij * Sanyo ALR252RGT 240x320 portrait display found on the 200f40f5b87SLinus Walleij * Versatile AB IB2 daughterboard for GSM prototyping. 201f40f5b87SLinus Walleij */ 202f40f5b87SLinus Walleij { 203f40f5b87SLinus Walleij .name = "Sanyo ALR252RGT", 204f40f5b87SLinus Walleij .magic = SYS_CLCD_ID_SANYO_2_5, 205f40f5b87SLinus Walleij .width_mm = 37, 206f40f5b87SLinus Walleij .height_mm = 50, 207f40f5b87SLinus Walleij .mode = { 208fd9b503dSLinus Walleij .clock = 5400, 209f40f5b87SLinus Walleij .hdisplay = 240, 210f40f5b87SLinus Walleij .hsync_start = 240 + 10, 211f40f5b87SLinus Walleij .hsync_end = 240 + 10 + 10, 212f40f5b87SLinus Walleij .htotal = 240 + 10 + 10 + 20, 213f40f5b87SLinus Walleij .vdisplay = 320, 214f40f5b87SLinus Walleij .vsync_start = 320 + 2, 215f40f5b87SLinus Walleij .vsync_end = 320 + 2 + 2, 216f40f5b87SLinus Walleij .vtotal = 320 + 2 + 2 + 2, 217f40f5b87SLinus Walleij .vrefresh = 116, 218f40f5b87SLinus Walleij .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, 219f40f5b87SLinus Walleij }, 22088bc4178SLaurent Pinchart .bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE, 221f40f5b87SLinus Walleij .ib2 = true, 222f40f5b87SLinus Walleij }, 223f40f5b87SLinus Walleij }; 224f40f5b87SLinus Walleij 225f40f5b87SLinus Walleij static inline struct versatile_panel * 226f40f5b87SLinus Walleij to_versatile_panel(struct drm_panel *panel) 227f40f5b87SLinus Walleij { 228f40f5b87SLinus Walleij return container_of(panel, struct versatile_panel, panel); 229f40f5b87SLinus Walleij } 230f40f5b87SLinus Walleij 231f40f5b87SLinus Walleij static int versatile_panel_disable(struct drm_panel *panel) 232f40f5b87SLinus Walleij { 233f40f5b87SLinus Walleij struct versatile_panel *vpanel = to_versatile_panel(panel); 234f40f5b87SLinus Walleij 235f40f5b87SLinus Walleij /* If we're on an IB2 daughterboard, turn off display */ 236f40f5b87SLinus Walleij if (vpanel->ib2_map) { 237f40f5b87SLinus Walleij dev_dbg(vpanel->dev, "disable IB2 display\n"); 238f40f5b87SLinus Walleij regmap_update_bits(vpanel->ib2_map, 239f40f5b87SLinus Walleij IB2_CTRL, 240f40f5b87SLinus Walleij IB2_CTRL_LCD_MASK, 241f40f5b87SLinus Walleij IB2_CTRL_LCD_SD); 242f40f5b87SLinus Walleij } 243f40f5b87SLinus Walleij 244f40f5b87SLinus Walleij return 0; 245f40f5b87SLinus Walleij } 246f40f5b87SLinus Walleij 247f40f5b87SLinus Walleij static int versatile_panel_enable(struct drm_panel *panel) 248f40f5b87SLinus Walleij { 249f40f5b87SLinus Walleij struct versatile_panel *vpanel = to_versatile_panel(panel); 250f40f5b87SLinus Walleij 251f40f5b87SLinus Walleij /* If we're on an IB2 daughterboard, turn on display */ 252f40f5b87SLinus Walleij if (vpanel->ib2_map) { 253f40f5b87SLinus Walleij dev_dbg(vpanel->dev, "enable IB2 display\n"); 254f40f5b87SLinus Walleij regmap_update_bits(vpanel->ib2_map, 255f40f5b87SLinus Walleij IB2_CTRL, 256f40f5b87SLinus Walleij IB2_CTRL_LCD_MASK, 257f40f5b87SLinus Walleij IB2_CTRL_LCD_BL_ON); 258f40f5b87SLinus Walleij } 259f40f5b87SLinus Walleij 260f40f5b87SLinus Walleij return 0; 261f40f5b87SLinus Walleij } 262f40f5b87SLinus Walleij 263f40f5b87SLinus Walleij static int versatile_panel_get_modes(struct drm_panel *panel) 264f40f5b87SLinus Walleij { 265f40f5b87SLinus Walleij struct drm_connector *connector = panel->connector; 266f40f5b87SLinus Walleij struct versatile_panel *vpanel = to_versatile_panel(panel); 267f40f5b87SLinus Walleij struct drm_display_mode *mode; 268f40f5b87SLinus Walleij 269f40f5b87SLinus Walleij connector->display_info.width_mm = vpanel->panel_type->width_mm; 270f40f5b87SLinus Walleij connector->display_info.height_mm = vpanel->panel_type->height_mm; 271f40f5b87SLinus Walleij connector->display_info.bus_flags = vpanel->panel_type->bus_flags; 272f40f5b87SLinus Walleij 273f40f5b87SLinus Walleij mode = drm_mode_duplicate(panel->drm, &vpanel->panel_type->mode); 274f40f5b87SLinus Walleij drm_mode_set_name(mode); 275f40f5b87SLinus Walleij mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 276f40f5b87SLinus Walleij 277f40f5b87SLinus Walleij mode->width_mm = vpanel->panel_type->width_mm; 278f40f5b87SLinus Walleij mode->height_mm = vpanel->panel_type->height_mm; 279f40f5b87SLinus Walleij drm_mode_probed_add(connector, mode); 280f40f5b87SLinus Walleij 281f40f5b87SLinus Walleij return 1; 282f40f5b87SLinus Walleij } 283f40f5b87SLinus Walleij 284f40f5b87SLinus Walleij static const struct drm_panel_funcs versatile_panel_drm_funcs = { 285f40f5b87SLinus Walleij .disable = versatile_panel_disable, 286f40f5b87SLinus Walleij .enable = versatile_panel_enable, 287f40f5b87SLinus Walleij .get_modes = versatile_panel_get_modes, 288f40f5b87SLinus Walleij }; 289f40f5b87SLinus Walleij 290f40f5b87SLinus Walleij static int versatile_panel_probe(struct platform_device *pdev) 291f40f5b87SLinus Walleij { 292f40f5b87SLinus Walleij struct device *dev = &pdev->dev; 293f40f5b87SLinus Walleij struct versatile_panel *vpanel; 294f40f5b87SLinus Walleij struct device *parent; 295f40f5b87SLinus Walleij struct regmap *map; 296f40f5b87SLinus Walleij int ret; 297f40f5b87SLinus Walleij u32 val; 298f40f5b87SLinus Walleij int i; 299f40f5b87SLinus Walleij 300f40f5b87SLinus Walleij parent = dev->parent; 301f40f5b87SLinus Walleij if (!parent) { 302f40f5b87SLinus Walleij dev_err(dev, "no parent for versatile panel\n"); 303f40f5b87SLinus Walleij return -ENODEV; 304f40f5b87SLinus Walleij } 305f40f5b87SLinus Walleij map = syscon_node_to_regmap(parent->of_node); 306f40f5b87SLinus Walleij if (IS_ERR(map)) { 307f40f5b87SLinus Walleij dev_err(dev, "no regmap for versatile panel parent\n"); 308f40f5b87SLinus Walleij return PTR_ERR(map); 309f40f5b87SLinus Walleij } 310f40f5b87SLinus Walleij 311f40f5b87SLinus Walleij vpanel = devm_kzalloc(dev, sizeof(*vpanel), GFP_KERNEL); 312f40f5b87SLinus Walleij if (!vpanel) 313f40f5b87SLinus Walleij return -ENOMEM; 314f40f5b87SLinus Walleij 315f40f5b87SLinus Walleij ret = regmap_read(map, SYS_CLCD, &val); 316f40f5b87SLinus Walleij if (ret) { 317f40f5b87SLinus Walleij dev_err(dev, "cannot access syscon regs\n"); 318f40f5b87SLinus Walleij return ret; 319f40f5b87SLinus Walleij } 320f40f5b87SLinus Walleij 321f40f5b87SLinus Walleij val &= SYS_CLCD_CLCDID_MASK; 322f40f5b87SLinus Walleij 323f40f5b87SLinus Walleij for (i = 0; i < ARRAY_SIZE(versatile_panels); i++) { 324f40f5b87SLinus Walleij const struct versatile_panel_type *pt; 325f40f5b87SLinus Walleij 326f40f5b87SLinus Walleij pt = &versatile_panels[i]; 327f40f5b87SLinus Walleij if (pt->magic == val) { 328f40f5b87SLinus Walleij vpanel->panel_type = pt; 329f40f5b87SLinus Walleij break; 330f40f5b87SLinus Walleij } 331f40f5b87SLinus Walleij } 332f40f5b87SLinus Walleij 333f40f5b87SLinus Walleij /* No panel detected or VGA, let's leave this show */ 334f40f5b87SLinus Walleij if (i == ARRAY_SIZE(versatile_panels)) { 335f40f5b87SLinus Walleij dev_info(dev, "no panel detected\n"); 336f40f5b87SLinus Walleij return -ENODEV; 337f40f5b87SLinus Walleij } 338f40f5b87SLinus Walleij 339f40f5b87SLinus Walleij dev_info(dev, "detected: %s\n", vpanel->panel_type->name); 340f40f5b87SLinus Walleij vpanel->dev = dev; 341f40f5b87SLinus Walleij vpanel->map = map; 342f40f5b87SLinus Walleij 343f40f5b87SLinus Walleij /* Check if the panel is mounted on an IB2 daughterboard */ 344f40f5b87SLinus Walleij if (vpanel->panel_type->ib2) { 345f40f5b87SLinus Walleij vpanel->ib2_map = syscon_regmap_lookup_by_compatible( 346f40f5b87SLinus Walleij "arm,versatile-ib2-syscon"); 347f40f5b87SLinus Walleij if (IS_ERR(vpanel->ib2_map)) 348f40f5b87SLinus Walleij vpanel->ib2_map = NULL; 349f40f5b87SLinus Walleij else 350f40f5b87SLinus Walleij dev_info(dev, "panel mounted on IB2 daughterboard\n"); 351f40f5b87SLinus Walleij } 352f40f5b87SLinus Walleij 353*9a2654c0SLaurent Pinchart drm_panel_init(&vpanel->panel, dev, &versatile_panel_drm_funcs, 354*9a2654c0SLaurent Pinchart DRM_MODE_CONNECTOR_DPI); 355f40f5b87SLinus Walleij 356f40f5b87SLinus Walleij return drm_panel_add(&vpanel->panel); 357f40f5b87SLinus Walleij } 358f40f5b87SLinus Walleij 359f40f5b87SLinus Walleij static const struct of_device_id versatile_panel_match[] = { 360f40f5b87SLinus Walleij { .compatible = "arm,versatile-tft-panel", }, 361f40f5b87SLinus Walleij {}, 362f40f5b87SLinus Walleij }; 363f40f5b87SLinus Walleij MODULE_DEVICE_TABLE(of, versatile_panel_match); 364f40f5b87SLinus Walleij 365f40f5b87SLinus Walleij static struct platform_driver versatile_panel_driver = { 366f40f5b87SLinus Walleij .probe = versatile_panel_probe, 367f40f5b87SLinus Walleij .driver = { 368f40f5b87SLinus Walleij .name = "versatile-tft-panel", 369f40f5b87SLinus Walleij .of_match_table = versatile_panel_match, 370f40f5b87SLinus Walleij }, 371f40f5b87SLinus Walleij }; 372f40f5b87SLinus Walleij module_platform_driver(versatile_panel_driver); 373f40f5b87SLinus Walleij 374f40f5b87SLinus Walleij MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); 375f40f5b87SLinus Walleij MODULE_DESCRIPTION("ARM Versatile panel driver"); 376f40f5b87SLinus Walleij MODULE_LICENSE("GPL v2"); 377