linux/drivers/video/backlight/pwm_bl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Simple PWM based backlight control, board code has to setup
   4 * 1) pin configuration so PWM waveforms can output
   5 * 2) platform_data being correctly configured
   6 */
   7
   8#include <linux/delay.h>
   9#include <linux/gpio/consumer.h>
  10#include <linux/module.h>
  11#include <linux/kernel.h>
  12#include <linux/init.h>
  13#include <linux/platform_device.h>
  14#include <linux/fb.h>
  15#include <linux/backlight.h>
  16#include <linux/err.h>
  17#include <linux/pwm.h>
  18#include <linux/pwm_backlight.h>
  19#include <linux/regulator/consumer.h>
  20#include <linux/slab.h>
  21
  22struct pwm_bl_data {
  23        struct pwm_device       *pwm;
  24        struct device           *dev;
  25        unsigned int            lth_brightness;
  26        unsigned int            *levels;
  27        bool                    enabled;
  28        struct regulator        *power_supply;
  29        struct gpio_desc        *enable_gpio;
  30        unsigned int            scale;
  31        bool                    legacy;
  32        unsigned int            post_pwm_on_delay;
  33        unsigned int            pwm_off_delay;
  34        int                     (*notify)(struct device *,
  35                                          int brightness);
  36        void                    (*notify_after)(struct device *,
  37                                        int brightness);
  38        int                     (*check_fb)(struct device *, struct fb_info *);
  39        void                    (*exit)(struct device *);
  40};
  41
  42static void pwm_backlight_power_on(struct pwm_bl_data *pb)
  43{
  44        struct pwm_state state;
  45        int err;
  46
  47        pwm_get_state(pb->pwm, &state);
  48        if (pb->enabled)
  49                return;
  50
  51        err = regulator_enable(pb->power_supply);
  52        if (err < 0)
  53                dev_err(pb->dev, "failed to enable power supply\n");
  54
  55        state.enabled = true;
  56        pwm_apply_state(pb->pwm, &state);
  57
  58        if (pb->post_pwm_on_delay)
  59                msleep(pb->post_pwm_on_delay);
  60
  61        if (pb->enable_gpio)
  62                gpiod_set_value_cansleep(pb->enable_gpio, 1);
  63
  64        pb->enabled = true;
  65}
  66
  67static void pwm_backlight_power_off(struct pwm_bl_data *pb)
  68{
  69        struct pwm_state state;
  70
  71        pwm_get_state(pb->pwm, &state);
  72        if (!pb->enabled)
  73                return;
  74
  75        if (pb->enable_gpio)
  76                gpiod_set_value_cansleep(pb->enable_gpio, 0);
  77
  78        if (pb->pwm_off_delay)
  79                msleep(pb->pwm_off_delay);
  80
  81        state.enabled = false;
  82        state.duty_cycle = 0;
  83        pwm_apply_state(pb->pwm, &state);
  84
  85        regulator_disable(pb->power_supply);
  86        pb->enabled = false;
  87}
  88
  89static int compute_duty_cycle(struct pwm_bl_data *pb, int brightness)
  90{
  91        unsigned int lth = pb->lth_brightness;
  92        struct pwm_state state;
  93        u64 duty_cycle;
  94
  95        pwm_get_state(pb->pwm, &state);
  96
  97        if (pb->levels)
  98                duty_cycle = pb->levels[brightness];
  99        else
 100                duty_cycle = brightness;
 101
 102        duty_cycle *= state.period - lth;
 103        do_div(duty_cycle, pb->scale);
 104
 105        return duty_cycle + lth;
 106}
 107
 108static int pwm_backlight_update_status(struct backlight_device *bl)
 109{
 110        struct pwm_bl_data *pb = bl_get_data(bl);
 111        int brightness = bl->props.brightness;
 112        struct pwm_state state;
 113
 114        if (bl->props.power != FB_BLANK_UNBLANK ||
 115            bl->props.fb_blank != FB_BLANK_UNBLANK ||
 116            bl->props.state & BL_CORE_FBBLANK)
 117                brightness = 0;
 118
 119        if (pb->notify)
 120                brightness = pb->notify(pb->dev, brightness);
 121
 122        if (brightness > 0) {
 123                pwm_get_state(pb->pwm, &state);
 124                state.duty_cycle = compute_duty_cycle(pb, brightness);
 125                pwm_apply_state(pb->pwm, &state);
 126                pwm_backlight_power_on(pb);
 127        } else {
 128                pwm_backlight_power_off(pb);
 129        }
 130
 131        if (pb->notify_after)
 132                pb->notify_after(pb->dev, brightness);
 133
 134        return 0;
 135}
 136
 137static int pwm_backlight_check_fb(struct backlight_device *bl,
 138                                  struct fb_info *info)
 139{
 140        struct pwm_bl_data *pb = bl_get_data(bl);
 141
 142        return !pb->check_fb || pb->check_fb(pb->dev, info);
 143}
 144
 145static const struct backlight_ops pwm_backlight_ops = {
 146        .update_status  = pwm_backlight_update_status,
 147        .check_fb       = pwm_backlight_check_fb,
 148};
 149
 150#ifdef CONFIG_OF
 151#define PWM_LUMINANCE_SHIFT     16
 152#define PWM_LUMINANCE_SCALE     (1 << PWM_LUMINANCE_SHIFT) /* luminance scale */
 153
 154/*
 155 * CIE lightness to PWM conversion.
 156 *
 157 * The CIE 1931 lightness formula is what actually describes how we perceive
 158 * light:
 159 *          Y = (L* / 903.3)           if L* ≤ 8
 160 *          Y = ((L* + 16) / 116)^3    if L* > 8
 161 *
 162 * Where Y is the luminance, the amount of light coming out of the screen, and
 163 * is a number between 0.0 and 1.0; and L* is the lightness, how bright a human
 164 * perceives the screen to be, and is a number between 0 and 100.
 165 *
 166 * The following function does the fixed point maths needed to implement the
 167 * above formula.
 168 */
 169static u64 cie1931(unsigned int lightness)
 170{
 171        u64 retval;
 172
 173        /*
 174         * @lightness is given as a number between 0 and 1, expressed
 175         * as a fixed-point number in scale
 176         * PWM_LUMINANCE_SCALE. Convert to a percentage, still
 177         * expressed as a fixed-point number, so the above formulas
 178         * can be applied.
 179         */
 180        lightness *= 100;
 181        if (lightness <= (8 * PWM_LUMINANCE_SCALE)) {
 182                retval = DIV_ROUND_CLOSEST(lightness * 10, 9033);
 183        } else {
 184                retval = (lightness + (16 * PWM_LUMINANCE_SCALE)) / 116;
 185                retval *= retval * retval;
 186                retval += 1ULL << (2*PWM_LUMINANCE_SHIFT - 1);
 187                retval >>= 2*PWM_LUMINANCE_SHIFT;
 188        }
 189
 190        return retval;
 191}
 192
 193/*
 194 * Create a default correction table for PWM values to create linear brightness
 195 * for LED based backlights using the CIE1931 algorithm.
 196 */
 197static
 198int pwm_backlight_brightness_default(struct device *dev,
 199                                     struct platform_pwm_backlight_data *data,
 200                                     unsigned int period)
 201{
 202        unsigned int i;
 203        u64 retval;
 204
 205        /*
 206         * Once we have 4096 levels there's little point going much higher...
 207         * neither interactive sliders nor animation benefits from having
 208         * more values in the table.
 209         */
 210        data->max_brightness =
 211                min((int)DIV_ROUND_UP(period, fls(period)), 4096);
 212
 213        data->levels = devm_kcalloc(dev, data->max_brightness,
 214                                    sizeof(*data->levels), GFP_KERNEL);
 215        if (!data->levels)
 216                return -ENOMEM;
 217
 218        /* Fill the table using the cie1931 algorithm */
 219        for (i = 0; i < data->max_brightness; i++) {
 220                retval = cie1931((i * PWM_LUMINANCE_SCALE) /
 221                                 data->max_brightness) * period;
 222                retval = DIV_ROUND_CLOSEST_ULL(retval, PWM_LUMINANCE_SCALE);
 223                if (retval > UINT_MAX)
 224                        return -EINVAL;
 225                data->levels[i] = (unsigned int)retval;
 226        }
 227
 228        data->dft_brightness = data->max_brightness / 2;
 229        data->max_brightness--;
 230
 231        return 0;
 232}
 233
 234static int pwm_backlight_parse_dt(struct device *dev,
 235                                  struct platform_pwm_backlight_data *data)
 236{
 237        struct device_node *node = dev->of_node;
 238        unsigned int num_levels = 0;
 239        unsigned int levels_count;
 240        unsigned int num_steps = 0;
 241        struct property *prop;
 242        unsigned int *table;
 243        int length;
 244        u32 value;
 245        int ret;
 246
 247        if (!node)
 248                return -ENODEV;
 249
 250        memset(data, 0, sizeof(*data));
 251
 252        /*
 253         * These values are optional and set as 0 by default, the out values
 254         * are modified only if a valid u32 value can be decoded.
 255         */
 256        of_property_read_u32(node, "post-pwm-on-delay-ms",
 257                             &data->post_pwm_on_delay);
 258        of_property_read_u32(node, "pwm-off-delay-ms", &data->pwm_off_delay);
 259
 260        /*
 261         * Determine the number of brightness levels, if this property is not
 262         * set a default table of brightness levels will be used.
 263         */
 264        prop = of_find_property(node, "brightness-levels", &length);
 265        if (!prop)
 266                return 0;
 267
 268        data->max_brightness = length / sizeof(u32);
 269
 270        /* read brightness levels from DT property */
 271        if (data->max_brightness > 0) {
 272                size_t size = sizeof(*data->levels) * data->max_brightness;
 273                unsigned int i, j, n = 0;
 274
 275                data->levels = devm_kzalloc(dev, size, GFP_KERNEL);
 276                if (!data->levels)
 277                        return -ENOMEM;
 278
 279                ret = of_property_read_u32_array(node, "brightness-levels",
 280                                                 data->levels,
 281                                                 data->max_brightness);
 282                if (ret < 0)
 283                        return ret;
 284
 285                ret = of_property_read_u32(node, "default-brightness-level",
 286                                           &value);
 287                if (ret < 0)
 288                        return ret;
 289
 290                data->dft_brightness = value;
 291
 292                /*
 293                 * This property is optional, if is set enables linear
 294                 * interpolation between each of the values of brightness levels
 295                 * and creates a new pre-computed table.
 296                 */
 297                of_property_read_u32(node, "num-interpolated-steps",
 298                                     &num_steps);
 299
 300                /*
 301                 * Make sure that there is at least two entries in the
 302                 * brightness-levels table, otherwise we can't interpolate
 303                 * between two points.
 304                 */
 305                if (num_steps) {
 306                        if (data->max_brightness < 2) {
 307                                dev_err(dev, "can't interpolate\n");
 308                                return -EINVAL;
 309                        }
 310
 311                        /*
 312                         * Recalculate the number of brightness levels, now
 313                         * taking in consideration the number of interpolated
 314                         * steps between two levels.
 315                         */
 316                        for (i = 0; i < data->max_brightness - 1; i++) {
 317                                if ((data->levels[i + 1] - data->levels[i]) /
 318                                   num_steps)
 319                                        num_levels += num_steps;
 320                                else
 321                                        num_levels++;
 322                        }
 323                        num_levels++;
 324                        dev_dbg(dev, "new number of brightness levels: %d\n",
 325                                num_levels);
 326
 327                        /*
 328                         * Create a new table of brightness levels with all the
 329                         * interpolated steps.
 330                         */
 331                        size = sizeof(*table) * num_levels;
 332                        table = devm_kzalloc(dev, size, GFP_KERNEL);
 333                        if (!table)
 334                                return -ENOMEM;
 335
 336                        /* Fill the interpolated table. */
 337                        levels_count = 0;
 338                        for (i = 0; i < data->max_brightness - 1; i++) {
 339                                value = data->levels[i];
 340                                n = (data->levels[i + 1] - value) / num_steps;
 341                                if (n > 0) {
 342                                        for (j = 0; j < num_steps; j++) {
 343                                                table[levels_count] = value;
 344                                                value += n;
 345                                                levels_count++;
 346                                        }
 347                                } else {
 348                                        table[levels_count] = data->levels[i];
 349                                        levels_count++;
 350                                }
 351                        }
 352                        table[levels_count] = data->levels[i];
 353
 354                        /*
 355                         * As we use interpolation lets remove current
 356                         * brightness levels table and replace for the
 357                         * new interpolated table.
 358                         */
 359                        devm_kfree(dev, data->levels);
 360                        data->levels = table;
 361
 362                        /*
 363                         * Reassign max_brightness value to the new total number
 364                         * of brightness levels.
 365                         */
 366                        data->max_brightness = num_levels;
 367                }
 368
 369                data->max_brightness--;
 370        }
 371
 372        return 0;
 373}
 374
 375static const struct of_device_id pwm_backlight_of_match[] = {
 376        { .compatible = "pwm-backlight" },
 377        { }
 378};
 379
 380MODULE_DEVICE_TABLE(of, pwm_backlight_of_match);
 381#else
 382static int pwm_backlight_parse_dt(struct device *dev,
 383                                  struct platform_pwm_backlight_data *data)
 384{
 385        return -ENODEV;
 386}
 387
 388static
 389int pwm_backlight_brightness_default(struct device *dev,
 390                                     struct platform_pwm_backlight_data *data,
 391                                     unsigned int period)
 392{
 393        return -ENODEV;
 394}
 395#endif
 396
 397static bool pwm_backlight_is_linear(struct platform_pwm_backlight_data *data)
 398{
 399        unsigned int nlevels = data->max_brightness + 1;
 400        unsigned int min_val = data->levels[0];
 401        unsigned int max_val = data->levels[nlevels - 1];
 402        /*
 403         * Multiplying by 128 means that even in pathological cases such
 404         * as (max_val - min_val) == nlevels the error at max_val is less
 405         * than 1%.
 406         */
 407        unsigned int slope = (128 * (max_val - min_val)) / nlevels;
 408        unsigned int margin = (max_val - min_val) / 20; /* 5% */
 409        int i;
 410
 411        for (i = 1; i < nlevels; i++) {
 412                unsigned int linear_value = min_val + ((i * slope) / 128);
 413                unsigned int delta = abs(linear_value - data->levels[i]);
 414
 415                if (delta > margin)
 416                        return false;
 417        }
 418
 419        return true;
 420}
 421
 422static int pwm_backlight_initial_power_state(const struct pwm_bl_data *pb)
 423{
 424        struct device_node *node = pb->dev->of_node;
 425
 426        /* Not booted with device tree or no phandle link to the node */
 427        if (!node || !node->phandle)
 428                return FB_BLANK_UNBLANK;
 429
 430        /*
 431         * If the driver is probed from the device tree and there is a
 432         * phandle link pointing to the backlight node, it is safe to
 433         * assume that another driver will enable the backlight at the
 434         * appropriate time. Therefore, if it is disabled, keep it so.
 435         */
 436
 437        /* if the enable GPIO is disabled, do not enable the backlight */
 438        if (pb->enable_gpio && gpiod_get_value_cansleep(pb->enable_gpio) == 0)
 439                return FB_BLANK_POWERDOWN;
 440
 441        /* The regulator is disabled, do not enable the backlight */
 442        if (!regulator_is_enabled(pb->power_supply))
 443                return FB_BLANK_POWERDOWN;
 444
 445        /* The PWM is disabled, keep it like this */
 446        if (!pwm_is_enabled(pb->pwm))
 447                return FB_BLANK_POWERDOWN;
 448
 449        return FB_BLANK_UNBLANK;
 450}
 451
 452static int pwm_backlight_probe(struct platform_device *pdev)
 453{
 454        struct platform_pwm_backlight_data *data = dev_get_platdata(&pdev->dev);
 455        struct platform_pwm_backlight_data defdata;
 456        struct backlight_properties props;
 457        struct backlight_device *bl;
 458        struct device_node *node = pdev->dev.of_node;
 459        struct pwm_bl_data *pb;
 460        struct pwm_state state;
 461        unsigned int i;
 462        int ret;
 463
 464        if (!data) {
 465                ret = pwm_backlight_parse_dt(&pdev->dev, &defdata);
 466                if (ret < 0) {
 467                        dev_err(&pdev->dev, "failed to find platform data\n");
 468                        return ret;
 469                }
 470
 471                data = &defdata;
 472        }
 473
 474        if (data->init) {
 475                ret = data->init(&pdev->dev);
 476                if (ret < 0)
 477                        return ret;
 478        }
 479
 480        pb = devm_kzalloc(&pdev->dev, sizeof(*pb), GFP_KERNEL);
 481        if (!pb) {
 482                ret = -ENOMEM;
 483                goto err_alloc;
 484        }
 485
 486        pb->notify = data->notify;
 487        pb->notify_after = data->notify_after;
 488        pb->check_fb = data->check_fb;
 489        pb->exit = data->exit;
 490        pb->dev = &pdev->dev;
 491        pb->enabled = false;
 492        pb->post_pwm_on_delay = data->post_pwm_on_delay;
 493        pb->pwm_off_delay = data->pwm_off_delay;
 494
 495        pb->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
 496                                                  GPIOD_ASIS);
 497        if (IS_ERR(pb->enable_gpio)) {
 498                ret = PTR_ERR(pb->enable_gpio);
 499                goto err_alloc;
 500        }
 501
 502        /*
 503         * If the GPIO is not known to be already configured as output, that
 504         * is, if gpiod_get_direction returns either 1 or -EINVAL, change the
 505         * direction to output and set the GPIO as active.
 506         * Do not force the GPIO to active when it was already output as it
 507         * could cause backlight flickering or we would enable the backlight too
 508         * early. Leave the decision of the initial backlight state for later.
 509         */
 510        if (pb->enable_gpio &&
 511            gpiod_get_direction(pb->enable_gpio) != 0)
 512                gpiod_direction_output(pb->enable_gpio, 1);
 513
 514        pb->power_supply = devm_regulator_get(&pdev->dev, "power");
 515        if (IS_ERR(pb->power_supply)) {
 516                ret = PTR_ERR(pb->power_supply);
 517                goto err_alloc;
 518        }
 519
 520        pb->pwm = devm_pwm_get(&pdev->dev, NULL);
 521        if (IS_ERR(pb->pwm) && PTR_ERR(pb->pwm) != -EPROBE_DEFER && !node) {
 522                dev_err(&pdev->dev, "unable to request PWM, trying legacy API\n");
 523                pb->legacy = true;
 524                pb->pwm = pwm_request(data->pwm_id, "pwm-backlight");
 525        }
 526
 527        if (IS_ERR(pb->pwm)) {
 528                ret = PTR_ERR(pb->pwm);
 529                if (ret != -EPROBE_DEFER)
 530                        dev_err(&pdev->dev, "unable to request PWM\n");
 531                goto err_alloc;
 532        }
 533
 534        dev_dbg(&pdev->dev, "got pwm for backlight\n");
 535
 536        /* Sync up PWM state. */
 537        pwm_init_state(pb->pwm, &state);
 538
 539        /*
 540         * The DT case will set the pwm_period_ns field to 0 and store the
 541         * period, parsed from the DT, in the PWM device. For the non-DT case,
 542         * set the period from platform data if it has not already been set
 543         * via the PWM lookup table.
 544         */
 545        if (!state.period && (data->pwm_period_ns > 0))
 546                state.period = data->pwm_period_ns;
 547
 548        ret = pwm_apply_state(pb->pwm, &state);
 549        if (ret) {
 550                dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n",
 551                        ret);
 552                goto err_alloc;
 553        }
 554
 555        memset(&props, 0, sizeof(struct backlight_properties));
 556
 557        if (data->levels) {
 558                pb->levels = data->levels;
 559
 560                /*
 561                 * For the DT case, only when brightness levels is defined
 562                 * data->levels is filled. For the non-DT case, data->levels
 563                 * can come from platform data, however is not usual.
 564                 */
 565                for (i = 0; i <= data->max_brightness; i++)
 566                        if (data->levels[i] > pb->scale)
 567                                pb->scale = data->levels[i];
 568
 569                if (pwm_backlight_is_linear(data))
 570                        props.scale = BACKLIGHT_SCALE_LINEAR;
 571                else
 572                        props.scale = BACKLIGHT_SCALE_NON_LINEAR;
 573        } else if (!data->max_brightness) {
 574                /*
 575                 * If no brightness levels are provided and max_brightness is
 576                 * not set, use the default brightness table. For the DT case,
 577                 * max_brightness is set to 0 when brightness levels is not
 578                 * specified. For the non-DT case, max_brightness is usually
 579                 * set to some value.
 580                 */
 581
 582                /* Get the PWM period (in nanoseconds) */
 583                pwm_get_state(pb->pwm, &state);
 584
 585                ret = pwm_backlight_brightness_default(&pdev->dev, data,
 586                                                       state.period);
 587                if (ret < 0) {
 588                        dev_err(&pdev->dev,
 589                                "failed to setup default brightness table\n");
 590                        goto err_alloc;
 591                }
 592
 593                for (i = 0; i <= data->max_brightness; i++) {
 594                        if (data->levels[i] > pb->scale)
 595                                pb->scale = data->levels[i];
 596
 597                        pb->levels = data->levels;
 598                }
 599
 600                props.scale = BACKLIGHT_SCALE_NON_LINEAR;
 601        } else {
 602                /*
 603                 * That only happens for the non-DT case, where platform data
 604                 * sets the max_brightness value.
 605                 */
 606                pb->scale = data->max_brightness;
 607        }
 608
 609        pb->lth_brightness = data->lth_brightness * (state.period / pb->scale);
 610
 611        props.type = BACKLIGHT_RAW;
 612        props.max_brightness = data->max_brightness;
 613        bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, pb,
 614                                       &pwm_backlight_ops, &props);
 615        if (IS_ERR(bl)) {
 616                dev_err(&pdev->dev, "failed to register backlight\n");
 617                ret = PTR_ERR(bl);
 618                if (pb->legacy)
 619                        pwm_free(pb->pwm);
 620                goto err_alloc;
 621        }
 622
 623        if (data->dft_brightness > data->max_brightness) {
 624                dev_warn(&pdev->dev,
 625                         "invalid default brightness level: %u, using %u\n",
 626                         data->dft_brightness, data->max_brightness);
 627                data->dft_brightness = data->max_brightness;
 628        }
 629
 630        bl->props.brightness = data->dft_brightness;
 631        bl->props.power = pwm_backlight_initial_power_state(pb);
 632        backlight_update_status(bl);
 633
 634        platform_set_drvdata(pdev, bl);
 635        return 0;
 636
 637err_alloc:
 638        if (data->exit)
 639                data->exit(&pdev->dev);
 640        return ret;
 641}
 642
 643static int pwm_backlight_remove(struct platform_device *pdev)
 644{
 645        struct backlight_device *bl = platform_get_drvdata(pdev);
 646        struct pwm_bl_data *pb = bl_get_data(bl);
 647
 648        backlight_device_unregister(bl);
 649        pwm_backlight_power_off(pb);
 650
 651        if (pb->exit)
 652                pb->exit(&pdev->dev);
 653        if (pb->legacy)
 654                pwm_free(pb->pwm);
 655
 656        return 0;
 657}
 658
 659static void pwm_backlight_shutdown(struct platform_device *pdev)
 660{
 661        struct backlight_device *bl = platform_get_drvdata(pdev);
 662        struct pwm_bl_data *pb = bl_get_data(bl);
 663
 664        pwm_backlight_power_off(pb);
 665}
 666
 667#ifdef CONFIG_PM_SLEEP
 668static int pwm_backlight_suspend(struct device *dev)
 669{
 670        struct backlight_device *bl = dev_get_drvdata(dev);
 671        struct pwm_bl_data *pb = bl_get_data(bl);
 672
 673        if (pb->notify)
 674                pb->notify(pb->dev, 0);
 675
 676        pwm_backlight_power_off(pb);
 677
 678        if (pb->notify_after)
 679                pb->notify_after(pb->dev, 0);
 680
 681        return 0;
 682}
 683
 684static int pwm_backlight_resume(struct device *dev)
 685{
 686        struct backlight_device *bl = dev_get_drvdata(dev);
 687
 688        backlight_update_status(bl);
 689
 690        return 0;
 691}
 692#endif
 693
 694static const struct dev_pm_ops pwm_backlight_pm_ops = {
 695#ifdef CONFIG_PM_SLEEP
 696        .suspend = pwm_backlight_suspend,
 697        .resume = pwm_backlight_resume,
 698        .poweroff = pwm_backlight_suspend,
 699        .restore = pwm_backlight_resume,
 700#endif
 701};
 702
 703static struct platform_driver pwm_backlight_driver = {
 704        .driver         = {
 705                .name           = "pwm-backlight",
 706                .pm             = &pwm_backlight_pm_ops,
 707                .of_match_table = of_match_ptr(pwm_backlight_of_match),
 708        },
 709        .probe          = pwm_backlight_probe,
 710        .remove         = pwm_backlight_remove,
 711        .shutdown       = pwm_backlight_shutdown,
 712};
 713
 714module_platform_driver(pwm_backlight_driver);
 715
 716MODULE_DESCRIPTION("PWM based Backlight Driver");
 717MODULE_LICENSE("GPL v2");
 718MODULE_ALIAS("platform:pwm-backlight");
 719