Showing error 820

User: Jiri Slaby
Error type: Resource Leak
Error type description: The code omits to put the resource to the system for reuse
File location: drivers/video/backlight/cr_bllcd.c
Line in file: 180
Project: Linux Kernel
Project version: 2.6.28
Tools: Stanse (1.2)
Entered: 2011-11-07 22:40:13 UTC


Source:

  1/*
  2 * Copyright (c) Intel Corp. 2007.
  3 * All Rights Reserved.
  4 *
  5 * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
  6 * develop this driver.
  7 *
  8 * This file is part of the Carillo Ranch video subsystem driver.
  9 * The Carillo Ranch video subsystem driver is free software;
 10 * you can redistribute it and/or modify
 11 * it under the terms of the GNU General Public License as published by
 12 * the Free Software Foundation; either version 2 of the License, or
 13 * (at your option) any later version.
 14 *
 15 * The Carillo Ranch video subsystem driver is distributed
 16 * in the hope that it will be useful,
 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 19 * GNU General Public License for more details.
 20 *
 21 * You should have received a copy of the GNU General Public License
 22 * along with this driver; if not, write to the Free Software
 23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 24 *
 25 * Authors:
 26 *   Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
 27 *   Alan Hourihane <alanh-at-tungstengraphics-dot-com>
 28 */
 29
 30#include <linux/module.h>
 31#include <linux/kernel.h>
 32#include <linux/init.h>
 33#include <linux/platform_device.h>
 34#include <linux/mutex.h>
 35#include <linux/fb.h>
 36#include <linux/backlight.h>
 37#include <linux/lcd.h>
 38#include <linux/pci.h>
 39
 40/* The LVDS- and panel power controls sits on the
 41 * GPIO port of the ISA bridge.
 42 */
 43
 44#define CRVML_DEVICE_LPC    0x27B8
 45#define CRVML_REG_GPIOBAR   0x48
 46#define CRVML_REG_GPIOEN    0x4C
 47#define CRVML_GPIOEN_BIT    (1 << 4)
 48#define CRVML_PANEL_PORT    0x38
 49#define CRVML_LVDS_ON       0x00000001
 50#define CRVML_PANEL_ON      0x00000002
 51#define CRVML_BACKLIGHT_OFF 0x00000004
 52
 53/* The PLL Clock register sits on Host bridge */
 54#define CRVML_DEVICE_MCH   0x5001
 55#define CRVML_REG_MCHBAR   0x44
 56#define CRVML_REG_MCHEN    0x54
 57#define CRVML_MCHEN_BIT    (1 << 28)
 58#define CRVML_MCHMAP_SIZE  4096
 59#define CRVML_REG_CLOCK    0xc3c
 60#define CRVML_CLOCK_SHIFT  8
 61#define CRVML_CLOCK_MASK   0x00000f00
 62
 63static struct pci_dev *lpc_dev;
 64static u32 gpio_bar;
 65
 66struct cr_panel {
 67        struct backlight_device *cr_backlight_device;
 68        struct lcd_device *cr_lcd_device;
 69};
 70
 71static int cr_backlight_set_intensity(struct backlight_device *bd)
 72{
 73        int intensity = bd->props.brightness;
 74        u32 addr = gpio_bar + CRVML_PANEL_PORT;
 75        u32 cur = inl(addr);
 76
 77        if (bd->props.power == FB_BLANK_UNBLANK)
 78                intensity = FB_BLANK_UNBLANK;
 79        if (bd->props.fb_blank == FB_BLANK_UNBLANK)
 80                intensity = FB_BLANK_UNBLANK;
 81        if (bd->props.power == FB_BLANK_POWERDOWN)
 82                intensity = FB_BLANK_POWERDOWN;
 83        if (bd->props.fb_blank == FB_BLANK_POWERDOWN)
 84                intensity = FB_BLANK_POWERDOWN;
 85
 86        if (intensity == FB_BLANK_UNBLANK) { /* FULL ON */
 87                cur &= ~CRVML_BACKLIGHT_OFF;
 88                outl(cur, addr);
 89        } else if (intensity == FB_BLANK_POWERDOWN) { /* OFF */
 90                cur |= CRVML_BACKLIGHT_OFF;
 91                outl(cur, addr);
 92        } /* anything else, don't bother */
 93
 94        return 0;
 95}
 96
 97static int cr_backlight_get_intensity(struct backlight_device *bd)
 98{
 99        u32 addr = gpio_bar + CRVML_PANEL_PORT;
100        u32 cur = inl(addr);
101        u8 intensity;
102
103        if (cur & CRVML_BACKLIGHT_OFF)
104                intensity = FB_BLANK_POWERDOWN;
105        else
106                intensity = FB_BLANK_UNBLANK;
107
108        return intensity;
109}
110
111static struct backlight_ops cr_backlight_ops = {
112        .get_brightness = cr_backlight_get_intensity,
113        .update_status = cr_backlight_set_intensity,
114};
115
116static void cr_panel_on(void)
117{
118        u32 addr = gpio_bar + CRVML_PANEL_PORT;
119        u32 cur = inl(addr);
120
121        if (!(cur & CRVML_PANEL_ON)) {
122                /* Make sure LVDS controller is down. */
123                if (cur & 0x00000001) {
124                        cur &= ~CRVML_LVDS_ON;
125                        outl(cur, addr);
126                }
127                /* Power up Panel */
128                schedule_timeout(HZ / 10);
129                cur |= CRVML_PANEL_ON;
130                outl(cur, addr);
131        }
132
133        /* Power up LVDS controller */
134
135        if (!(cur & CRVML_LVDS_ON)) {
136                schedule_timeout(HZ / 10);
137                outl(cur | CRVML_LVDS_ON, addr);
138        }
139}
140
141static void cr_panel_off(void)
142{
143        u32 addr = gpio_bar + CRVML_PANEL_PORT;
144        u32 cur = inl(addr);
145
146        /* Power down LVDS controller first to avoid high currents */
147        if (cur & CRVML_LVDS_ON) {
148                cur &= ~CRVML_LVDS_ON;
149                outl(cur, addr);
150        }
151        if (cur & CRVML_PANEL_ON) {
152                schedule_timeout(HZ / 10);
153                outl(cur & ~CRVML_PANEL_ON, addr);
154        }
155}
156
157static int cr_lcd_set_power(struct lcd_device *ld, int power)
158{
159        if (power == FB_BLANK_UNBLANK)
160                cr_panel_on();
161        if (power == FB_BLANK_POWERDOWN)
162                cr_panel_off();
163
164        return 0;
165}
166
167static struct lcd_ops cr_lcd_ops = {
168        .set_power = cr_lcd_set_power,
169};
170
171static int cr_backlight_probe(struct platform_device *pdev)
172{
173        struct backlight_device *bdp;
174        struct lcd_device *ldp;
175        struct cr_panel *crp;
176        u8 dev_en;
177
178        lpc_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
179                                        CRVML_DEVICE_LPC, NULL);
180        if (!lpc_dev) {
181                printk("INTEL CARILLO RANCH LPC not found.\n");
182                return -ENODEV;
183        }
184
185        pci_read_config_byte(lpc_dev, CRVML_REG_GPIOEN, &dev_en);
186        if (!(dev_en & CRVML_GPIOEN_BIT)) {
187                printk(KERN_ERR
188                       "Carillo Ranch GPIO device was not enabled.\n");
189                pci_dev_put(lpc_dev);
190                return -ENODEV;
191        }
192
193        bdp = backlight_device_register("cr-backlight",
194                                        &pdev->dev, NULL, &cr_backlight_ops);
195        if (IS_ERR(bdp)) {
196                pci_dev_put(lpc_dev);
197                return PTR_ERR(bdp);
198        }
199
200        ldp = lcd_device_register("cr-lcd", &pdev->dev, NULL, &cr_lcd_ops);
201        if (IS_ERR(ldp)) {
202                backlight_device_unregister(bdp);
203                pci_dev_put(lpc_dev);
204                return PTR_ERR(bdp);
205        }
206
207        pci_read_config_dword(lpc_dev, CRVML_REG_GPIOBAR,
208                              &gpio_bar);
209        gpio_bar &= ~0x3F;
210
211        crp = kzalloc(sizeof(*crp), GFP_KERNEL);
212        if (!crp) {
213                lcd_device_unregister(ldp);
214                backlight_device_unregister(bdp);
215                pci_dev_put(lpc_dev);
216                return -ENOMEM;
217        }
218
219        crp->cr_backlight_device = bdp;
220        crp->cr_lcd_device = ldp;
221        crp->cr_backlight_device->props.power = FB_BLANK_UNBLANK;
222        crp->cr_backlight_device->props.brightness = 0;
223        crp->cr_backlight_device->props.max_brightness = 0;
224        cr_backlight_set_intensity(crp->cr_backlight_device);
225
226        cr_lcd_set_power(crp->cr_lcd_device, FB_BLANK_UNBLANK);
227
228        platform_set_drvdata(pdev, crp);
229
230        return 0;
231}
232
233static int cr_backlight_remove(struct platform_device *pdev)
234{
235        struct cr_panel *crp = platform_get_drvdata(pdev);
236        crp->cr_backlight_device->props.power = FB_BLANK_POWERDOWN;
237        crp->cr_backlight_device->props.brightness = 0;
238        crp->cr_backlight_device->props.max_brightness = 0;
239        cr_backlight_set_intensity(crp->cr_backlight_device);
240        cr_lcd_set_power(crp->cr_lcd_device, FB_BLANK_POWERDOWN);
241        backlight_device_unregister(crp->cr_backlight_device);
242        lcd_device_unregister(crp->cr_lcd_device);
243        pci_dev_put(lpc_dev);
244
245        return 0;
246}
247
248static struct platform_driver cr_backlight_driver = {
249        .probe = cr_backlight_probe,
250        .remove = cr_backlight_remove,
251        .driver = {
252                   .name = "cr_backlight",
253                   },
254};
255
256static struct platform_device *crp;
257
258static int __init cr_backlight_init(void)
259{
260        int ret = platform_driver_register(&cr_backlight_driver);
261
262        if (!ret) {
263                crp = platform_device_alloc("cr_backlight", -1);
264                if (!crp)
265                        return -ENOMEM;
266
267                ret = platform_device_add(crp);
268
269                if (ret) {
270                        platform_device_put(crp);
271                        platform_driver_unregister(&cr_backlight_driver);
272                }
273        }
274
275        printk("Carillo Ranch Backlight Driver Initialized.\n");
276
277        return ret;
278}
279
280static void __exit cr_backlight_exit(void)
281{
282        platform_device_unregister(crp);
283        platform_driver_unregister(&cr_backlight_driver);
284}
285
286module_init(cr_backlight_init);
287module_exit(cr_backlight_exit);
288
289MODULE_AUTHOR("Tungsten Graphics Inc.");
290MODULE_DESCRIPTION("Carillo Ranch Backlight Driver");
291MODULE_LICENSE("GPL");