linux/drivers/video/fbdev/nvidia/nv_backlight.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Backlight code for nVidia based graphic cards
   4 *
   5 * Copyright 2004 Antonino Daplas <adaplas@pol.net>
   6 * Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
   7 */
   8
   9#include <linux/backlight.h>
  10#include <linux/fb.h>
  11#include <linux/pci.h>
  12
  13#ifdef CONFIG_PMAC_BACKLIGHT
  14#include <asm/backlight.h>
  15#endif
  16
  17#include "nv_local.h"
  18#include "nv_type.h"
  19#include "nv_proto.h"
  20
  21/* We do not have any information about which values are allowed, thus
  22 * we used safe values.
  23 */
  24#define MIN_LEVEL 0x158
  25#define MAX_LEVEL 0x534
  26#define LEVEL_STEP ((MAX_LEVEL - MIN_LEVEL) / FB_BACKLIGHT_MAX)
  27
  28static int nvidia_bl_get_level_brightness(struct nvidia_par *par,
  29                int level)
  30{
  31        struct fb_info *info = pci_get_drvdata(par->pci_dev);
  32        int nlevel;
  33
  34        /* Get and convert the value */
  35        /* No locking of bl_curve since we read a single value */
  36        nlevel = MIN_LEVEL + info->bl_curve[level] * LEVEL_STEP;
  37
  38        if (nlevel < 0)
  39                nlevel = 0;
  40        else if (nlevel < MIN_LEVEL)
  41                nlevel = MIN_LEVEL;
  42        else if (nlevel > MAX_LEVEL)
  43                nlevel = MAX_LEVEL;
  44
  45        return nlevel;
  46}
  47
  48static int nvidia_bl_update_status(struct backlight_device *bd)
  49{
  50        struct nvidia_par *par = bl_get_data(bd);
  51        u32 tmp_pcrt, tmp_pmc, fpcontrol;
  52        int level;
  53
  54        if (!par->FlatPanel)
  55                return 0;
  56
  57        if (bd->props.power != FB_BLANK_UNBLANK ||
  58            bd->props.fb_blank != FB_BLANK_UNBLANK)
  59                level = 0;
  60        else
  61                level = bd->props.brightness;
  62
  63        tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF;
  64        tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC;
  65        fpcontrol = NV_RD32(par->PRAMDAC, 0x0848) & 0xCFFFFFCC;
  66
  67        if (level > 0) {
  68                tmp_pcrt |= 0x1;
  69                tmp_pmc |= (1 << 31); /* backlight bit */
  70                tmp_pmc |= nvidia_bl_get_level_brightness(par, level) << 16;
  71                fpcontrol |= par->fpSyncs;
  72        } else
  73                fpcontrol |= 0x20000022;
  74
  75        NV_WR32(par->PCRTC0, 0x081C, tmp_pcrt);
  76        NV_WR32(par->PMC, 0x10F0, tmp_pmc);
  77        NV_WR32(par->PRAMDAC, 0x848, fpcontrol);
  78
  79        return 0;
  80}
  81
  82static const struct backlight_ops nvidia_bl_ops = {
  83        .update_status  = nvidia_bl_update_status,
  84};
  85
  86void nvidia_bl_init(struct nvidia_par *par)
  87{
  88        struct backlight_properties props;
  89        struct fb_info *info = pci_get_drvdata(par->pci_dev);
  90        struct backlight_device *bd;
  91        char name[12];
  92
  93        if (!par->FlatPanel)
  94                return;
  95
  96#ifdef CONFIG_PMAC_BACKLIGHT
  97        if (!machine_is(powermac) ||
  98            !pmac_has_backlight_type("mnca"))
  99                return;
 100#endif
 101
 102        snprintf(name, sizeof(name), "nvidiabl%d", info->node);
 103
 104        memset(&props, 0, sizeof(struct backlight_properties));
 105        props.type = BACKLIGHT_RAW;
 106        props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
 107        bd = backlight_device_register(name, info->dev, par, &nvidia_bl_ops,
 108                                       &props);
 109        if (IS_ERR(bd)) {
 110                info->bl_dev = NULL;
 111                printk(KERN_WARNING "nvidia: Backlight registration failed\n");
 112                goto error;
 113        }
 114
 115        info->bl_dev = bd;
 116        fb_bl_default_curve(info, 0,
 117                0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL,
 118                0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL);
 119
 120        bd->props.brightness = bd->props.max_brightness;
 121        bd->props.power = FB_BLANK_UNBLANK;
 122        backlight_update_status(bd);
 123
 124        printk("nvidia: Backlight initialized (%s)\n", name);
 125
 126        return;
 127
 128error:
 129        return;
 130}
 131
 132void nvidia_bl_exit(struct nvidia_par *par)
 133{
 134        struct fb_info *info = pci_get_drvdata(par->pci_dev);
 135        struct backlight_device *bd = info->bl_dev;
 136
 137        backlight_device_unregister(bd);
 138        printk("nvidia: Backlight unloaded\n");
 139}
 140