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 #include <drm/drmP.h> 29f40f5b87SLinus Walleij #include <drm/drm_panel.h> 30f40f5b87SLinus Walleij 31f40f5b87SLinus Walleij #include <linux/bitops.h> 32f40f5b87SLinus Walleij #include <linux/init.h> 33f40f5b87SLinus Walleij #include <linux/kernel.h> 34f40f5b87SLinus Walleij #include <linux/mfd/syscon.h> 35f40f5b87SLinus Walleij #include <linux/module.h> 36f40f5b87SLinus Walleij #include <linux/platform_device.h> 37f40f5b87SLinus Walleij #include <linux/regmap.h> 38f40f5b87SLinus Walleij 39f40f5b87SLinus Walleij #include <video/of_videomode.h> 40f40f5b87SLinus Walleij #include <video/videomode.h> 41f40f5b87SLinus Walleij 42f40f5b87SLinus Walleij /* 43f40f5b87SLinus Walleij * This configuration register in the Versatile and RealView 44f40f5b87SLinus Walleij * family is uniformly present but appears more and more 45f40f5b87SLinus Walleij * unutilized starting with the RealView series. 46f40f5b87SLinus Walleij */ 47f40f5b87SLinus Walleij #define SYS_CLCD 0x50 48f40f5b87SLinus Walleij 49f40f5b87SLinus Walleij /* The Versatile can detect the connected panel type */ 50f40f5b87SLinus Walleij #define SYS_CLCD_CLCDID_MASK (BIT(8)|BIT(9)|BIT(10)|BIT(11)|BIT(12)) 51f40f5b87SLinus Walleij #define SYS_CLCD_ID_SANYO_3_8 (0x00 << 8) 52f40f5b87SLinus Walleij #define SYS_CLCD_ID_SHARP_8_4 (0x01 << 8) 53f40f5b87SLinus Walleij #define SYS_CLCD_ID_EPSON_2_2 (0x02 << 8) 54f40f5b87SLinus Walleij #define SYS_CLCD_ID_SANYO_2_5 (0x07 << 8) 55f40f5b87SLinus Walleij #define SYS_CLCD_ID_VGA (0x1f << 8) 56f40f5b87SLinus Walleij 57f40f5b87SLinus Walleij /* IB2 control register for the Versatile daughterboard */ 58f40f5b87SLinus Walleij #define IB2_CTRL 0x00 59f40f5b87SLinus Walleij #define IB2_CTRL_LCD_SD BIT(1) /* 1 = shut down LCD */ 60f40f5b87SLinus Walleij #define IB2_CTRL_LCD_BL_ON BIT(0) 61f40f5b87SLinus Walleij #define IB2_CTRL_LCD_MASK (BIT(0)|BIT(1)) 62f40f5b87SLinus Walleij 63f40f5b87SLinus Walleij /** 64f40f5b87SLinus Walleij * struct versatile_panel_type - lookup struct for the supported panels 65f40f5b87SLinus Walleij */ 66f40f5b87SLinus Walleij struct versatile_panel_type { 67f40f5b87SLinus Walleij /** 68f40f5b87SLinus Walleij * @name: the name of this panel 69f40f5b87SLinus Walleij */ 70f40f5b87SLinus Walleij const char *name; 71f40f5b87SLinus Walleij /** 72f40f5b87SLinus Walleij * @magic: the magic value from the detection register 73f40f5b87SLinus Walleij */ 74f40f5b87SLinus Walleij u32 magic; 75f40f5b87SLinus Walleij /** 76f40f5b87SLinus Walleij * @mode: the DRM display mode for this panel 77f40f5b87SLinus Walleij */ 78f40f5b87SLinus Walleij struct drm_display_mode mode; 79f40f5b87SLinus Walleij /** 80f40f5b87SLinus Walleij * @bus_flags: the DRM bus flags for this panel e.g. inverted clock 81f40f5b87SLinus Walleij */ 82f40f5b87SLinus Walleij u32 bus_flags; 83f40f5b87SLinus Walleij /** 84f40f5b87SLinus Walleij * @width_mm: the panel width in mm 85f40f5b87SLinus Walleij */ 86f40f5b87SLinus Walleij u32 width_mm; 87f40f5b87SLinus Walleij /** 88f40f5b87SLinus Walleij * @height_mm: the panel height in mm 89f40f5b87SLinus Walleij */ 90f40f5b87SLinus Walleij u32 height_mm; 91f40f5b87SLinus Walleij /** 92f40f5b87SLinus Walleij * @ib2: the panel may be connected on an IB2 daughterboard 93f40f5b87SLinus Walleij */ 94f40f5b87SLinus Walleij bool ib2; 95f40f5b87SLinus Walleij }; 96f40f5b87SLinus Walleij 97f40f5b87SLinus Walleij /** 98f40f5b87SLinus Walleij * struct versatile_panel - state container for the Versatile panels 99f40f5b87SLinus Walleij */ 100f40f5b87SLinus Walleij struct versatile_panel { 101f40f5b87SLinus Walleij /** 102f40f5b87SLinus Walleij * @dev: the container device 103f40f5b87SLinus Walleij */ 104f40f5b87SLinus Walleij struct device *dev; 105f40f5b87SLinus Walleij /** 106f40f5b87SLinus Walleij * @panel: the DRM panel instance for this device 107f40f5b87SLinus Walleij */ 108f40f5b87SLinus Walleij struct drm_panel panel; 109f40f5b87SLinus Walleij /** 110f40f5b87SLinus Walleij * @panel_type: the Versatile panel type as detected 111f40f5b87SLinus Walleij */ 112f40f5b87SLinus Walleij const struct versatile_panel_type *panel_type; 113f40f5b87SLinus Walleij /** 114f40f5b87SLinus Walleij * @map: map to the parent syscon where the main register reside 115f40f5b87SLinus Walleij */ 116f40f5b87SLinus Walleij struct regmap *map; 117f40f5b87SLinus Walleij /** 118f40f5b87SLinus Walleij * @ib2_map: map to the IB2 syscon, if applicable 119f40f5b87SLinus Walleij */ 120f40f5b87SLinus Walleij struct regmap *ib2_map; 121f40f5b87SLinus Walleij }; 122f40f5b87SLinus Walleij 123f40f5b87SLinus Walleij static const struct versatile_panel_type versatile_panels[] = { 124f40f5b87SLinus Walleij /* 125f40f5b87SLinus Walleij * Sanyo TM38QV67A02A - 3.8 inch QVGA (320x240) Color TFT 126f40f5b87SLinus Walleij * found on the Versatile AB IB1 connector or the Versatile 127f40f5b87SLinus Walleij * PB adaptor board connector. 128f40f5b87SLinus Walleij */ 129f40f5b87SLinus Walleij { 130f40f5b87SLinus Walleij .name = "Sanyo TM38QV67A02A", 131f40f5b87SLinus Walleij .magic = SYS_CLCD_ID_SANYO_3_8, 132f40f5b87SLinus Walleij .width_mm = 79, 133f40f5b87SLinus Walleij .height_mm = 54, 134f40f5b87SLinus Walleij .mode = { 135*fd9b503dSLinus Walleij .clock = 10000, 136f40f5b87SLinus Walleij .hdisplay = 320, 137f40f5b87SLinus Walleij .hsync_start = 320 + 6, 138f40f5b87SLinus Walleij .hsync_end = 320 + 6 + 6, 139f40f5b87SLinus Walleij .htotal = 320 + 6 + 6 + 6, 140f40f5b87SLinus Walleij .vdisplay = 240, 141f40f5b87SLinus Walleij .vsync_start = 240 + 5, 142f40f5b87SLinus Walleij .vsync_end = 240 + 5 + 6, 143f40f5b87SLinus Walleij .vtotal = 240 + 5 + 6 + 5, 144f40f5b87SLinus Walleij .vrefresh = 116, 145f40f5b87SLinus Walleij .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, 146f40f5b87SLinus Walleij }, 147f40f5b87SLinus Walleij }, 148f40f5b87SLinus Walleij /* 149f40f5b87SLinus Walleij * Sharp LQ084V1DG21 640x480 VGA Color TFT module 150f40f5b87SLinus Walleij * found on the Versatile AB IB1 connector or the Versatile 151f40f5b87SLinus Walleij * PB adaptor board connector. 152f40f5b87SLinus Walleij */ 153f40f5b87SLinus Walleij { 154f40f5b87SLinus Walleij .name = "Sharp LQ084V1DG21", 155f40f5b87SLinus Walleij .magic = SYS_CLCD_ID_SHARP_8_4, 156f40f5b87SLinus Walleij .width_mm = 171, 157f40f5b87SLinus Walleij .height_mm = 130, 158f40f5b87SLinus Walleij .mode = { 159*fd9b503dSLinus Walleij .clock = 25000, 160f40f5b87SLinus Walleij .hdisplay = 640, 161f40f5b87SLinus Walleij .hsync_start = 640 + 24, 162f40f5b87SLinus Walleij .hsync_end = 640 + 24 + 96, 163f40f5b87SLinus Walleij .htotal = 640 + 24 + 96 + 24, 164f40f5b87SLinus Walleij .vdisplay = 480, 165f40f5b87SLinus Walleij .vsync_start = 480 + 11, 166f40f5b87SLinus Walleij .vsync_end = 480 + 11 + 2, 167f40f5b87SLinus Walleij .vtotal = 480 + 11 + 2 + 32, 168f40f5b87SLinus Walleij .vrefresh = 60, 169f40f5b87SLinus Walleij .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, 170f40f5b87SLinus Walleij }, 171f40f5b87SLinus Walleij }, 172f40f5b87SLinus Walleij /* 173f40f5b87SLinus Walleij * Epson L2F50113T00 - 2.2 inch QCIF 176x220 Color TFT 174f40f5b87SLinus Walleij * found on the Versatile PB adaptor board connector. 175f40f5b87SLinus Walleij */ 176f40f5b87SLinus Walleij { 177f40f5b87SLinus Walleij .name = "Epson L2F50113T00", 178f40f5b87SLinus Walleij .magic = SYS_CLCD_ID_EPSON_2_2, 179f40f5b87SLinus Walleij .width_mm = 34, 180f40f5b87SLinus Walleij .height_mm = 45, 181f40f5b87SLinus Walleij .mode = { 182*fd9b503dSLinus Walleij .clock = 62500, 183f40f5b87SLinus Walleij .hdisplay = 176, 184f40f5b87SLinus Walleij .hsync_start = 176 + 2, 185f40f5b87SLinus Walleij .hsync_end = 176 + 2 + 3, 186f40f5b87SLinus Walleij .htotal = 176 + 2 + 3 + 3, 187f40f5b87SLinus Walleij .vdisplay = 220, 188f40f5b87SLinus Walleij .vsync_start = 220 + 0, 189f40f5b87SLinus Walleij .vsync_end = 220 + 0 + 2, 190f40f5b87SLinus Walleij .vtotal = 220 + 0 + 2 + 1, 191f40f5b87SLinus Walleij .vrefresh = 390, 192f40f5b87SLinus Walleij .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, 193f40f5b87SLinus Walleij }, 194f40f5b87SLinus Walleij .bus_flags = DRM_BUS_FLAG_PIXDATA_NEGEDGE, 195f40f5b87SLinus Walleij }, 196f40f5b87SLinus Walleij /* 197f40f5b87SLinus Walleij * Sanyo ALR252RGT 240x320 portrait display found on the 198f40f5b87SLinus Walleij * Versatile AB IB2 daughterboard for GSM prototyping. 199f40f5b87SLinus Walleij */ 200f40f5b87SLinus Walleij { 201f40f5b87SLinus Walleij .name = "Sanyo ALR252RGT", 202f40f5b87SLinus Walleij .magic = SYS_CLCD_ID_SANYO_2_5, 203f40f5b87SLinus Walleij .width_mm = 37, 204f40f5b87SLinus Walleij .height_mm = 50, 205f40f5b87SLinus Walleij .mode = { 206*fd9b503dSLinus Walleij .clock = 5400, 207f40f5b87SLinus Walleij .hdisplay = 240, 208f40f5b87SLinus Walleij .hsync_start = 240 + 10, 209f40f5b87SLinus Walleij .hsync_end = 240 + 10 + 10, 210f40f5b87SLinus Walleij .htotal = 240 + 10 + 10 + 20, 211f40f5b87SLinus Walleij .vdisplay = 320, 212f40f5b87SLinus Walleij .vsync_start = 320 + 2, 213f40f5b87SLinus Walleij .vsync_end = 320 + 2 + 2, 214f40f5b87SLinus Walleij .vtotal = 320 + 2 + 2 + 2, 215f40f5b87SLinus Walleij .vrefresh = 116, 216f40f5b87SLinus Walleij .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, 217f40f5b87SLinus Walleij }, 218f40f5b87SLinus Walleij .bus_flags = DRM_BUS_FLAG_PIXDATA_NEGEDGE, 219f40f5b87SLinus Walleij .ib2 = true, 220f40f5b87SLinus Walleij }, 221f40f5b87SLinus Walleij }; 222f40f5b87SLinus Walleij 223f40f5b87SLinus Walleij static inline struct versatile_panel * 224f40f5b87SLinus Walleij to_versatile_panel(struct drm_panel *panel) 225f40f5b87SLinus Walleij { 226f40f5b87SLinus Walleij return container_of(panel, struct versatile_panel, panel); 227f40f5b87SLinus Walleij } 228f40f5b87SLinus Walleij 229f40f5b87SLinus Walleij static int versatile_panel_disable(struct drm_panel *panel) 230f40f5b87SLinus Walleij { 231f40f5b87SLinus Walleij struct versatile_panel *vpanel = to_versatile_panel(panel); 232f40f5b87SLinus Walleij 233f40f5b87SLinus Walleij /* If we're on an IB2 daughterboard, turn off display */ 234f40f5b87SLinus Walleij if (vpanel->ib2_map) { 235f40f5b87SLinus Walleij dev_dbg(vpanel->dev, "disable IB2 display\n"); 236f40f5b87SLinus Walleij regmap_update_bits(vpanel->ib2_map, 237f40f5b87SLinus Walleij IB2_CTRL, 238f40f5b87SLinus Walleij IB2_CTRL_LCD_MASK, 239f40f5b87SLinus Walleij IB2_CTRL_LCD_SD); 240f40f5b87SLinus Walleij } 241f40f5b87SLinus Walleij 242f40f5b87SLinus Walleij return 0; 243f40f5b87SLinus Walleij } 244f40f5b87SLinus Walleij 245f40f5b87SLinus Walleij static int versatile_panel_enable(struct drm_panel *panel) 246f40f5b87SLinus Walleij { 247f40f5b87SLinus Walleij struct versatile_panel *vpanel = to_versatile_panel(panel); 248f40f5b87SLinus Walleij 249f40f5b87SLinus Walleij /* If we're on an IB2 daughterboard, turn on display */ 250f40f5b87SLinus Walleij if (vpanel->ib2_map) { 251f40f5b87SLinus Walleij dev_dbg(vpanel->dev, "enable IB2 display\n"); 252f40f5b87SLinus Walleij regmap_update_bits(vpanel->ib2_map, 253f40f5b87SLinus Walleij IB2_CTRL, 254f40f5b87SLinus Walleij IB2_CTRL_LCD_MASK, 255f40f5b87SLinus Walleij IB2_CTRL_LCD_BL_ON); 256f40f5b87SLinus Walleij } 257f40f5b87SLinus Walleij 258f40f5b87SLinus Walleij return 0; 259f40f5b87SLinus Walleij } 260f40f5b87SLinus Walleij 261f40f5b87SLinus Walleij static int versatile_panel_get_modes(struct drm_panel *panel) 262f40f5b87SLinus Walleij { 263f40f5b87SLinus Walleij struct drm_connector *connector = panel->connector; 264f40f5b87SLinus Walleij struct versatile_panel *vpanel = to_versatile_panel(panel); 265f40f5b87SLinus Walleij struct drm_display_mode *mode; 266f40f5b87SLinus Walleij 267f40f5b87SLinus Walleij strncpy(connector->display_info.name, vpanel->panel_type->name, 268f40f5b87SLinus Walleij DRM_DISPLAY_INFO_LEN); 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 353f40f5b87SLinus Walleij drm_panel_init(&vpanel->panel); 354f40f5b87SLinus Walleij vpanel->panel.dev = dev; 355f40f5b87SLinus Walleij vpanel->panel.funcs = &versatile_panel_drm_funcs; 356f40f5b87SLinus Walleij 357f40f5b87SLinus Walleij return drm_panel_add(&vpanel->panel); 358f40f5b87SLinus Walleij } 359f40f5b87SLinus Walleij 360f40f5b87SLinus Walleij static const struct of_device_id versatile_panel_match[] = { 361f40f5b87SLinus Walleij { .compatible = "arm,versatile-tft-panel", }, 362f40f5b87SLinus Walleij {}, 363f40f5b87SLinus Walleij }; 364f40f5b87SLinus Walleij MODULE_DEVICE_TABLE(of, versatile_panel_match); 365f40f5b87SLinus Walleij 366f40f5b87SLinus Walleij static struct platform_driver versatile_panel_driver = { 367f40f5b87SLinus Walleij .probe = versatile_panel_probe, 368f40f5b87SLinus Walleij .driver = { 369f40f5b87SLinus Walleij .name = "versatile-tft-panel", 370f40f5b87SLinus Walleij .of_match_table = versatile_panel_match, 371f40f5b87SLinus Walleij }, 372f40f5b87SLinus Walleij }; 373f40f5b87SLinus Walleij module_platform_driver(versatile_panel_driver); 374f40f5b87SLinus Walleij 375f40f5b87SLinus Walleij MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); 376f40f5b87SLinus Walleij MODULE_DESCRIPTION("ARM Versatile panel driver"); 377f40f5b87SLinus Walleij MODULE_LICENSE("GPL v2"); 378