linux/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2017-2018, Bootlin
   4 */
   5
   6#include <linux/delay.h>
   7#include <linux/device.h>
   8#include <linux/err.h>
   9#include <linux/errno.h>
  10#include <linux/fb.h>
  11#include <linux/kernel.h>
  12#include <linux/module.h>
  13
  14#include <linux/gpio/consumer.h>
  15#include <linux/regulator/consumer.h>
  16
  17#include <drm/drm_mipi_dsi.h>
  18#include <drm/drm_modes.h>
  19#include <drm/drm_panel.h>
  20
  21#include <video/mipi_display.h>
  22
  23struct ili9881c {
  24        struct drm_panel        panel;
  25        struct mipi_dsi_device  *dsi;
  26
  27        struct regulator        *power;
  28        struct gpio_desc        *reset;
  29};
  30
  31enum ili9881c_op {
  32        ILI9881C_SWITCH_PAGE,
  33        ILI9881C_COMMAND,
  34};
  35
  36struct ili9881c_instr {
  37        enum ili9881c_op        op;
  38
  39        union arg {
  40                struct cmd {
  41                        u8      cmd;
  42                        u8      data;
  43                } cmd;
  44                u8      page;
  45        } arg;
  46};
  47
  48#define ILI9881C_SWITCH_PAGE_INSTR(_page)       \
  49        {                                       \
  50                .op = ILI9881C_SWITCH_PAGE,     \
  51                .arg = {                        \
  52                        .page = (_page),        \
  53                },                              \
  54        }
  55
  56#define ILI9881C_COMMAND_INSTR(_cmd, _data)             \
  57        {                                               \
  58                .op = ILI9881C_COMMAND,         \
  59                .arg = {                                \
  60                        .cmd = {                        \
  61                                .cmd = (_cmd),          \
  62                                .data = (_data),        \
  63                        },                              \
  64                },                                      \
  65        }
  66
  67static const struct ili9881c_instr ili9881c_init[] = {
  68        ILI9881C_SWITCH_PAGE_INSTR(3),
  69        ILI9881C_COMMAND_INSTR(0x01, 0x00),
  70        ILI9881C_COMMAND_INSTR(0x02, 0x00),
  71        ILI9881C_COMMAND_INSTR(0x03, 0x73),
  72        ILI9881C_COMMAND_INSTR(0x04, 0x03),
  73        ILI9881C_COMMAND_INSTR(0x05, 0x00),
  74        ILI9881C_COMMAND_INSTR(0x06, 0x06),
  75        ILI9881C_COMMAND_INSTR(0x07, 0x06),
  76        ILI9881C_COMMAND_INSTR(0x08, 0x00),
  77        ILI9881C_COMMAND_INSTR(0x09, 0x18),
  78        ILI9881C_COMMAND_INSTR(0x0a, 0x04),
  79        ILI9881C_COMMAND_INSTR(0x0b, 0x00),
  80        ILI9881C_COMMAND_INSTR(0x0c, 0x02),
  81        ILI9881C_COMMAND_INSTR(0x0d, 0x03),
  82        ILI9881C_COMMAND_INSTR(0x0e, 0x00),
  83        ILI9881C_COMMAND_INSTR(0x0f, 0x25),
  84        ILI9881C_COMMAND_INSTR(0x10, 0x25),
  85        ILI9881C_COMMAND_INSTR(0x11, 0x00),
  86        ILI9881C_COMMAND_INSTR(0x12, 0x00),
  87        ILI9881C_COMMAND_INSTR(0x13, 0x00),
  88        ILI9881C_COMMAND_INSTR(0x14, 0x00),
  89        ILI9881C_COMMAND_INSTR(0x15, 0x00),
  90        ILI9881C_COMMAND_INSTR(0x16, 0x0C),
  91        ILI9881C_COMMAND_INSTR(0x17, 0x00),
  92        ILI9881C_COMMAND_INSTR(0x18, 0x00),
  93        ILI9881C_COMMAND_INSTR(0x19, 0x00),
  94        ILI9881C_COMMAND_INSTR(0x1a, 0x00),
  95        ILI9881C_COMMAND_INSTR(0x1b, 0x00),
  96        ILI9881C_COMMAND_INSTR(0x1c, 0x00),
  97        ILI9881C_COMMAND_INSTR(0x1d, 0x00),
  98        ILI9881C_COMMAND_INSTR(0x1e, 0xC0),
  99        ILI9881C_COMMAND_INSTR(0x1f, 0x80),
 100        ILI9881C_COMMAND_INSTR(0x20, 0x04),
 101        ILI9881C_COMMAND_INSTR(0x21, 0x01),
 102        ILI9881C_COMMAND_INSTR(0x22, 0x00),
 103        ILI9881C_COMMAND_INSTR(0x23, 0x00),
 104        ILI9881C_COMMAND_INSTR(0x24, 0x00),
 105        ILI9881C_COMMAND_INSTR(0x25, 0x00),
 106        ILI9881C_COMMAND_INSTR(0x26, 0x00),
 107        ILI9881C_COMMAND_INSTR(0x27, 0x00),
 108        ILI9881C_COMMAND_INSTR(0x28, 0x33),
 109        ILI9881C_COMMAND_INSTR(0x29, 0x03),
 110        ILI9881C_COMMAND_INSTR(0x2a, 0x00),
 111        ILI9881C_COMMAND_INSTR(0x2b, 0x00),
 112        ILI9881C_COMMAND_INSTR(0x2c, 0x00),
 113        ILI9881C_COMMAND_INSTR(0x2d, 0x00),
 114        ILI9881C_COMMAND_INSTR(0x2e, 0x00),
 115        ILI9881C_COMMAND_INSTR(0x2f, 0x00),
 116        ILI9881C_COMMAND_INSTR(0x30, 0x00),
 117        ILI9881C_COMMAND_INSTR(0x31, 0x00),
 118        ILI9881C_COMMAND_INSTR(0x32, 0x00),
 119        ILI9881C_COMMAND_INSTR(0x33, 0x00),
 120        ILI9881C_COMMAND_INSTR(0x34, 0x04),
 121        ILI9881C_COMMAND_INSTR(0x35, 0x00),
 122        ILI9881C_COMMAND_INSTR(0x36, 0x00),
 123        ILI9881C_COMMAND_INSTR(0x37, 0x00),
 124        ILI9881C_COMMAND_INSTR(0x38, 0x3C),
 125        ILI9881C_COMMAND_INSTR(0x39, 0x00),
 126        ILI9881C_COMMAND_INSTR(0x3a, 0x00),
 127        ILI9881C_COMMAND_INSTR(0x3b, 0x00),
 128        ILI9881C_COMMAND_INSTR(0x3c, 0x00),
 129        ILI9881C_COMMAND_INSTR(0x3d, 0x00),
 130        ILI9881C_COMMAND_INSTR(0x3e, 0x00),
 131        ILI9881C_COMMAND_INSTR(0x3f, 0x00),
 132        ILI9881C_COMMAND_INSTR(0x40, 0x00),
 133        ILI9881C_COMMAND_INSTR(0x41, 0x00),
 134        ILI9881C_COMMAND_INSTR(0x42, 0x00),
 135        ILI9881C_COMMAND_INSTR(0x43, 0x00),
 136        ILI9881C_COMMAND_INSTR(0x44, 0x00),
 137        ILI9881C_COMMAND_INSTR(0x50, 0x01),
 138        ILI9881C_COMMAND_INSTR(0x51, 0x23),
 139        ILI9881C_COMMAND_INSTR(0x52, 0x45),
 140        ILI9881C_COMMAND_INSTR(0x53, 0x67),
 141        ILI9881C_COMMAND_INSTR(0x54, 0x89),
 142        ILI9881C_COMMAND_INSTR(0x55, 0xab),
 143        ILI9881C_COMMAND_INSTR(0x56, 0x01),
 144        ILI9881C_COMMAND_INSTR(0x57, 0x23),
 145        ILI9881C_COMMAND_INSTR(0x58, 0x45),
 146        ILI9881C_COMMAND_INSTR(0x59, 0x67),
 147        ILI9881C_COMMAND_INSTR(0x5a, 0x89),
 148        ILI9881C_COMMAND_INSTR(0x5b, 0xab),
 149        ILI9881C_COMMAND_INSTR(0x5c, 0xcd),
 150        ILI9881C_COMMAND_INSTR(0x5d, 0xef),
 151        ILI9881C_COMMAND_INSTR(0x5e, 0x11),
 152        ILI9881C_COMMAND_INSTR(0x5f, 0x02),
 153        ILI9881C_COMMAND_INSTR(0x60, 0x02),
 154        ILI9881C_COMMAND_INSTR(0x61, 0x02),
 155        ILI9881C_COMMAND_INSTR(0x62, 0x02),
 156        ILI9881C_COMMAND_INSTR(0x63, 0x02),
 157        ILI9881C_COMMAND_INSTR(0x64, 0x02),
 158        ILI9881C_COMMAND_INSTR(0x65, 0x02),
 159        ILI9881C_COMMAND_INSTR(0x66, 0x02),
 160        ILI9881C_COMMAND_INSTR(0x67, 0x02),
 161        ILI9881C_COMMAND_INSTR(0x68, 0x02),
 162        ILI9881C_COMMAND_INSTR(0x69, 0x02),
 163        ILI9881C_COMMAND_INSTR(0x6a, 0x0C),
 164        ILI9881C_COMMAND_INSTR(0x6b, 0x02),
 165        ILI9881C_COMMAND_INSTR(0x6c, 0x0F),
 166        ILI9881C_COMMAND_INSTR(0x6d, 0x0E),
 167        ILI9881C_COMMAND_INSTR(0x6e, 0x0D),
 168        ILI9881C_COMMAND_INSTR(0x6f, 0x06),
 169        ILI9881C_COMMAND_INSTR(0x70, 0x07),
 170        ILI9881C_COMMAND_INSTR(0x71, 0x02),
 171        ILI9881C_COMMAND_INSTR(0x72, 0x02),
 172        ILI9881C_COMMAND_INSTR(0x73, 0x02),
 173        ILI9881C_COMMAND_INSTR(0x74, 0x02),
 174        ILI9881C_COMMAND_INSTR(0x75, 0x02),
 175        ILI9881C_COMMAND_INSTR(0x76, 0x02),
 176        ILI9881C_COMMAND_INSTR(0x77, 0x02),
 177        ILI9881C_COMMAND_INSTR(0x78, 0x02),
 178        ILI9881C_COMMAND_INSTR(0x79, 0x02),
 179        ILI9881C_COMMAND_INSTR(0x7a, 0x02),
 180        ILI9881C_COMMAND_INSTR(0x7b, 0x02),
 181        ILI9881C_COMMAND_INSTR(0x7c, 0x02),
 182        ILI9881C_COMMAND_INSTR(0x7d, 0x02),
 183        ILI9881C_COMMAND_INSTR(0x7e, 0x02),
 184        ILI9881C_COMMAND_INSTR(0x7f, 0x02),
 185        ILI9881C_COMMAND_INSTR(0x80, 0x0C),
 186        ILI9881C_COMMAND_INSTR(0x81, 0x02),
 187        ILI9881C_COMMAND_INSTR(0x82, 0x0F),
 188        ILI9881C_COMMAND_INSTR(0x83, 0x0E),
 189        ILI9881C_COMMAND_INSTR(0x84, 0x0D),
 190        ILI9881C_COMMAND_INSTR(0x85, 0x06),
 191        ILI9881C_COMMAND_INSTR(0x86, 0x07),
 192        ILI9881C_COMMAND_INSTR(0x87, 0x02),
 193        ILI9881C_COMMAND_INSTR(0x88, 0x02),
 194        ILI9881C_COMMAND_INSTR(0x89, 0x02),
 195        ILI9881C_COMMAND_INSTR(0x8A, 0x02),
 196        ILI9881C_SWITCH_PAGE_INSTR(4),
 197        ILI9881C_COMMAND_INSTR(0x6C, 0x15),
 198        ILI9881C_COMMAND_INSTR(0x6E, 0x22),
 199        ILI9881C_COMMAND_INSTR(0x6F, 0x33),
 200        ILI9881C_COMMAND_INSTR(0x3A, 0xA4),
 201        ILI9881C_COMMAND_INSTR(0x8D, 0x0D),
 202        ILI9881C_COMMAND_INSTR(0x87, 0xBA),
 203        ILI9881C_COMMAND_INSTR(0x26, 0x76),
 204        ILI9881C_COMMAND_INSTR(0xB2, 0xD1),
 205        ILI9881C_SWITCH_PAGE_INSTR(1),
 206        ILI9881C_COMMAND_INSTR(0x22, 0x0A),
 207        ILI9881C_COMMAND_INSTR(0x53, 0xDC),
 208        ILI9881C_COMMAND_INSTR(0x55, 0xA7),
 209        ILI9881C_COMMAND_INSTR(0x50, 0x78),
 210        ILI9881C_COMMAND_INSTR(0x51, 0x78),
 211        ILI9881C_COMMAND_INSTR(0x31, 0x02),
 212        ILI9881C_COMMAND_INSTR(0x60, 0x14),
 213        ILI9881C_COMMAND_INSTR(0xA0, 0x2A),
 214        ILI9881C_COMMAND_INSTR(0xA1, 0x39),
 215        ILI9881C_COMMAND_INSTR(0xA2, 0x46),
 216        ILI9881C_COMMAND_INSTR(0xA3, 0x0e),
 217        ILI9881C_COMMAND_INSTR(0xA4, 0x12),
 218        ILI9881C_COMMAND_INSTR(0xA5, 0x25),
 219        ILI9881C_COMMAND_INSTR(0xA6, 0x19),
 220        ILI9881C_COMMAND_INSTR(0xA7, 0x1d),
 221        ILI9881C_COMMAND_INSTR(0xA8, 0xa6),
 222        ILI9881C_COMMAND_INSTR(0xA9, 0x1C),
 223        ILI9881C_COMMAND_INSTR(0xAA, 0x29),
 224        ILI9881C_COMMAND_INSTR(0xAB, 0x85),
 225        ILI9881C_COMMAND_INSTR(0xAC, 0x1C),
 226        ILI9881C_COMMAND_INSTR(0xAD, 0x1B),
 227        ILI9881C_COMMAND_INSTR(0xAE, 0x51),
 228        ILI9881C_COMMAND_INSTR(0xAF, 0x22),
 229        ILI9881C_COMMAND_INSTR(0xB0, 0x2d),
 230        ILI9881C_COMMAND_INSTR(0xB1, 0x4f),
 231        ILI9881C_COMMAND_INSTR(0xB2, 0x59),
 232        ILI9881C_COMMAND_INSTR(0xB3, 0x3F),
 233        ILI9881C_COMMAND_INSTR(0xC0, 0x2A),
 234        ILI9881C_COMMAND_INSTR(0xC1, 0x3a),
 235        ILI9881C_COMMAND_INSTR(0xC2, 0x45),
 236        ILI9881C_COMMAND_INSTR(0xC3, 0x0e),
 237        ILI9881C_COMMAND_INSTR(0xC4, 0x11),
 238        ILI9881C_COMMAND_INSTR(0xC5, 0x24),
 239        ILI9881C_COMMAND_INSTR(0xC6, 0x1a),
 240        ILI9881C_COMMAND_INSTR(0xC7, 0x1c),
 241        ILI9881C_COMMAND_INSTR(0xC8, 0xaa),
 242        ILI9881C_COMMAND_INSTR(0xC9, 0x1C),
 243        ILI9881C_COMMAND_INSTR(0xCA, 0x29),
 244        ILI9881C_COMMAND_INSTR(0xCB, 0x96),
 245        ILI9881C_COMMAND_INSTR(0xCC, 0x1C),
 246        ILI9881C_COMMAND_INSTR(0xCD, 0x1B),
 247        ILI9881C_COMMAND_INSTR(0xCE, 0x51),
 248        ILI9881C_COMMAND_INSTR(0xCF, 0x22),
 249        ILI9881C_COMMAND_INSTR(0xD0, 0x2b),
 250        ILI9881C_COMMAND_INSTR(0xD1, 0x4b),
 251        ILI9881C_COMMAND_INSTR(0xD2, 0x59),
 252        ILI9881C_COMMAND_INSTR(0xD3, 0x3F),
 253};
 254
 255static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel)
 256{
 257        return container_of(panel, struct ili9881c, panel);
 258}
 259
 260/*
 261 * The panel seems to accept some private DCS commands that map
 262 * directly to registers.
 263 *
 264 * It is organised by page, with each page having its own set of
 265 * registers, and the first page looks like it's holding the standard
 266 * DCS commands.
 267 *
 268 * So before any attempt at sending a command or data, we have to be
 269 * sure if we're in the right page or not.
 270 */
 271static int ili9881c_switch_page(struct ili9881c *ctx, u8 page)
 272{
 273        u8 buf[4] = { 0xff, 0x98, 0x81, page };
 274        int ret;
 275
 276        ret = mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
 277        if (ret < 0)
 278                return ret;
 279
 280        return 0;
 281}
 282
 283static int ili9881c_send_cmd_data(struct ili9881c *ctx, u8 cmd, u8 data)
 284{
 285        u8 buf[2] = { cmd, data };
 286        int ret;
 287
 288        ret = mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
 289        if (ret < 0)
 290                return ret;
 291
 292        return 0;
 293}
 294
 295static int ili9881c_prepare(struct drm_panel *panel)
 296{
 297        struct ili9881c *ctx = panel_to_ili9881c(panel);
 298        unsigned int i;
 299        int ret;
 300
 301        /* Power the panel */
 302        ret = regulator_enable(ctx->power);
 303        if (ret)
 304                return ret;
 305        msleep(5);
 306
 307        /* And reset it */
 308        gpiod_set_value(ctx->reset, 1);
 309        msleep(20);
 310
 311        gpiod_set_value(ctx->reset, 0);
 312        msleep(20);
 313
 314        for (i = 0; i < ARRAY_SIZE(ili9881c_init); i++) {
 315                const struct ili9881c_instr *instr = &ili9881c_init[i];
 316
 317                if (instr->op == ILI9881C_SWITCH_PAGE)
 318                        ret = ili9881c_switch_page(ctx, instr->arg.page);
 319                else if (instr->op == ILI9881C_COMMAND)
 320                        ret = ili9881c_send_cmd_data(ctx, instr->arg.cmd.cmd,
 321                                                      instr->arg.cmd.data);
 322
 323                if (ret)
 324                        return ret;
 325        }
 326
 327        ret = ili9881c_switch_page(ctx, 0);
 328        if (ret)
 329                return ret;
 330
 331        ret = mipi_dsi_dcs_set_tear_on(ctx->dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
 332        if (ret)
 333                return ret;
 334
 335        ret = mipi_dsi_dcs_exit_sleep_mode(ctx->dsi);
 336        if (ret)
 337                return ret;
 338
 339        return 0;
 340}
 341
 342static int ili9881c_enable(struct drm_panel *panel)
 343{
 344        struct ili9881c *ctx = panel_to_ili9881c(panel);
 345
 346        msleep(120);
 347
 348        mipi_dsi_dcs_set_display_on(ctx->dsi);
 349
 350        return 0;
 351}
 352
 353static int ili9881c_disable(struct drm_panel *panel)
 354{
 355        struct ili9881c *ctx = panel_to_ili9881c(panel);
 356
 357        return mipi_dsi_dcs_set_display_off(ctx->dsi);
 358}
 359
 360static int ili9881c_unprepare(struct drm_panel *panel)
 361{
 362        struct ili9881c *ctx = panel_to_ili9881c(panel);
 363
 364        mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
 365        regulator_disable(ctx->power);
 366        gpiod_set_value(ctx->reset, 1);
 367
 368        return 0;
 369}
 370
 371static const struct drm_display_mode bananapi_default_mode = {
 372        .clock          = 62000,
 373
 374        .hdisplay       = 720,
 375        .hsync_start    = 720 + 10,
 376        .hsync_end      = 720 + 10 + 20,
 377        .htotal         = 720 + 10 + 20 + 30,
 378
 379        .vdisplay       = 1280,
 380        .vsync_start    = 1280 + 10,
 381        .vsync_end      = 1280 + 10 + 10,
 382        .vtotal         = 1280 + 10 + 10 + 20,
 383};
 384
 385static int ili9881c_get_modes(struct drm_panel *panel,
 386                              struct drm_connector *connector)
 387{
 388        struct ili9881c *ctx = panel_to_ili9881c(panel);
 389        struct drm_display_mode *mode;
 390
 391        mode = drm_mode_duplicate(connector->dev, &bananapi_default_mode);
 392        if (!mode) {
 393                dev_err(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n",
 394                        bananapi_default_mode.hdisplay,
 395                        bananapi_default_mode.vdisplay,
 396                        drm_mode_vrefresh(&bananapi_default_mode));
 397                return -ENOMEM;
 398        }
 399
 400        drm_mode_set_name(mode);
 401
 402        mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
 403        drm_mode_probed_add(connector, mode);
 404
 405        connector->display_info.width_mm = 62;
 406        connector->display_info.height_mm = 110;
 407
 408        return 1;
 409}
 410
 411static const struct drm_panel_funcs ili9881c_funcs = {
 412        .prepare        = ili9881c_prepare,
 413        .unprepare      = ili9881c_unprepare,
 414        .enable         = ili9881c_enable,
 415        .disable        = ili9881c_disable,
 416        .get_modes      = ili9881c_get_modes,
 417};
 418
 419static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi)
 420{
 421        struct ili9881c *ctx;
 422        int ret;
 423
 424        ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);
 425        if (!ctx)
 426                return -ENOMEM;
 427        mipi_dsi_set_drvdata(dsi, ctx);
 428        ctx->dsi = dsi;
 429
 430        drm_panel_init(&ctx->panel, &dsi->dev, &ili9881c_funcs,
 431                       DRM_MODE_CONNECTOR_DSI);
 432
 433        ctx->power = devm_regulator_get(&dsi->dev, "power");
 434        if (IS_ERR(ctx->power)) {
 435                dev_err(&dsi->dev, "Couldn't get our power regulator\n");
 436                return PTR_ERR(ctx->power);
 437        }
 438
 439        ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
 440        if (IS_ERR(ctx->reset)) {
 441                dev_err(&dsi->dev, "Couldn't get our reset GPIO\n");
 442                return PTR_ERR(ctx->reset);
 443        }
 444
 445        ret = drm_panel_of_backlight(&ctx->panel);
 446        if (ret)
 447                return ret;
 448
 449        ret = drm_panel_add(&ctx->panel);
 450        if (ret < 0)
 451                return ret;
 452
 453        dsi->mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
 454        dsi->format = MIPI_DSI_FMT_RGB888;
 455        dsi->lanes = 4;
 456
 457        return mipi_dsi_attach(dsi);
 458}
 459
 460static int ili9881c_dsi_remove(struct mipi_dsi_device *dsi)
 461{
 462        struct ili9881c *ctx = mipi_dsi_get_drvdata(dsi);
 463
 464        mipi_dsi_detach(dsi);
 465        drm_panel_remove(&ctx->panel);
 466
 467        return 0;
 468}
 469
 470static const struct of_device_id ili9881c_of_match[] = {
 471        { .compatible = "bananapi,lhr050h41" },
 472        { }
 473};
 474MODULE_DEVICE_TABLE(of, ili9881c_of_match);
 475
 476static struct mipi_dsi_driver ili9881c_dsi_driver = {
 477        .probe          = ili9881c_dsi_probe,
 478        .remove         = ili9881c_dsi_remove,
 479        .driver = {
 480                .name           = "ili9881c-dsi",
 481                .of_match_table = ili9881c_of_match,
 482        },
 483};
 484module_mipi_dsi_driver(ili9881c_dsi_driver);
 485
 486MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
 487MODULE_DESCRIPTION("Ilitek ILI9881C Controller Driver");
 488MODULE_LICENSE("GPL v2");
 489