1/* 2 * Copyright (C) 2009 Red Hat <mjg@redhat.com> 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining 5 * a copy of this software and associated documentation files (the 6 * "Software"), to deal in the Software without restriction, including 7 * without limitation the rights to use, copy, modify, merge, publish, 8 * distribute, sublicense, and/or sell copies of the Software, and to 9 * permit persons to whom the Software is furnished to do so, subject to 10 * the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the 13 * next paragraph) shall be included in all copies or substantial 14 * portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 * 24 */ 25 26/* 27 * Authors: 28 * Matthew Garrett <mjg@redhat.com> 29 * 30 * Register locations derived from NVClock by Roderick Colenbrander 31 */ 32 33#include <linux/backlight.h> 34 35#include "drmP.h" 36#include "nouveau_drv.h" 37#include "nouveau_drm.h" 38#include "nouveau_reg.h" 39 40static int nv40_get_intensity(struct backlight_device *bd) 41{ 42 struct drm_device *dev = bl_get_data(bd); 43 int val = (nv_rd32(dev, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK) 44 >> 16; 45 46 return val; 47} 48 49static int nv40_set_intensity(struct backlight_device *bd) 50{ 51 struct drm_device *dev = bl_get_data(bd); 52 int val = bd->props.brightness; 53 int reg = nv_rd32(dev, NV40_PMC_BACKLIGHT); 54 55 nv_wr32(dev, NV40_PMC_BACKLIGHT, 56 (val << 16) | (reg & ~NV40_PMC_BACKLIGHT_MASK)); 57 58 return 0; 59} 60 61static struct backlight_ops nv40_bl_ops = { 62 .options = BL_CORE_SUSPENDRESUME, 63 .get_brightness = nv40_get_intensity, 64 .update_status = nv40_set_intensity, 65}; 66 67static int nv50_get_intensity(struct backlight_device *bd) 68{ 69 struct drm_device *dev = bl_get_data(bd); 70 71 return nv_rd32(dev, NV50_PDISPLAY_SOR_BACKLIGHT); 72} 73 74static int nv50_set_intensity(struct backlight_device *bd) 75{ 76 struct drm_device *dev = bl_get_data(bd); 77 int val = bd->props.brightness; 78 79 nv_wr32(dev, NV50_PDISPLAY_SOR_BACKLIGHT, 80 val | NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE); 81 return 0; 82} 83 84static struct backlight_ops nv50_bl_ops = { 85 .options = BL_CORE_SUSPENDRESUME, 86 .get_brightness = nv50_get_intensity, 87 .update_status = nv50_set_intensity, 88}; 89 90static int nouveau_nv40_backlight_init(struct drm_device *dev) 91{ 92 struct backlight_properties props; 93 struct drm_nouveau_private *dev_priv = dev->dev_private; 94 struct backlight_device *bd; 95 96 if (!(nv_rd32(dev, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK)) 97 return 0; 98 99 memset(&props, 0, sizeof(struct backlight_properties)); 100 props.max_brightness = 31; 101 bd = backlight_device_register("nv_backlight", &dev->pdev->dev, dev, 102 &nv40_bl_ops, &props); 103 if (IS_ERR(bd)) 104 return PTR_ERR(bd); 105 106 dev_priv->backlight = bd; 107 bd->props.brightness = nv40_get_intensity(bd); 108 backlight_update_status(bd); 109 110 return 0; 111} 112 113static int nouveau_nv50_backlight_init(struct drm_device *dev) 114{ 115 struct backlight_properties props; 116 struct drm_nouveau_private *dev_priv = dev->dev_private; 117 struct backlight_device *bd; 118 119 if (!nv_rd32(dev, NV50_PDISPLAY_SOR_BACKLIGHT)) 120 return 0; 121 122 memset(&props, 0, sizeof(struct backlight_properties)); 123 props.max_brightness = 1025; 124 bd = backlight_device_register("nv_backlight", &dev->pdev->dev, dev, 125 &nv50_bl_ops, &props); 126 if (IS_ERR(bd)) 127 return PTR_ERR(bd); 128 129 dev_priv->backlight = bd; 130 bd->props.brightness = nv50_get_intensity(bd); 131 backlight_update_status(bd); 132 return 0; 133} 134 135int nouveau_backlight_init(struct drm_device *dev) 136{ 137 struct drm_nouveau_private *dev_priv = dev->dev_private; 138 139 switch (dev_priv->card_type) { 140 case NV_40: 141 return nouveau_nv40_backlight_init(dev); 142 case NV_50: 143 return nouveau_nv50_backlight_init(dev); 144 default: 145 break; 146 } 147 148 return 0; 149} 150 151void nouveau_backlight_exit(struct drm_device *dev) 152{ 153 struct drm_nouveau_private *dev_priv = dev->dev_private; 154 155 if (dev_priv->backlight) { 156 backlight_device_unregister(dev_priv->backlight); 157 dev_priv->backlight = NULL; 158 } 159} 160