aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/backlight/tegra_pwm_bl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/backlight/tegra_pwm_bl.c')
-rw-r--r--drivers/video/backlight/tegra_pwm_bl.c177
1 files changed, 177 insertions, 0 deletions
diff --git a/drivers/video/backlight/tegra_pwm_bl.c b/drivers/video/backlight/tegra_pwm_bl.c
new file mode 100644
index 00000000000..4be691c54d3
--- /dev/null
+++ b/drivers/video/backlight/tegra_pwm_bl.c
@@ -0,0 +1,177 @@
1/*
2 * linux/drivers/video/backlight/tegra_pwm_bl.c
3 *
4 * Tegra pwm backlight driver
5 *
6 * Copyright (C) 2011 NVIDIA Corporation
7 * Author: Renuka Apte <rapte@nvidia.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/platform_device.h>
18#include <linux/fb.h>
19#include <linux/backlight.h>
20#include <linux/err.h>
21#include <linux/slab.h>
22#include <linux/tegra_pwm_bl.h>
23#include <mach/dc.h>
24
25struct tegra_pwm_bl_data {
26 struct device *dev;
27 int which_dc;
28 int (*notify)(struct device *, int brightness);
29 struct tegra_dc_pwm_params params;
30 int (*check_fb)(struct device *dev, struct fb_info *info);
31};
32
33static int tegra_pwm_backlight_update_status(struct backlight_device *bl)
34{
35 struct tegra_pwm_bl_data *tbl = dev_get_drvdata(&bl->dev);
36 int brightness = bl->props.brightness;
37 int max = bl->props.max_brightness;
38 struct tegra_dc *dc;
39
40 if (bl->props.power != FB_BLANK_UNBLANK)
41 brightness = 0;
42
43 if (bl->props.fb_blank != FB_BLANK_UNBLANK)
44 brightness = 0;
45
46 if (tbl->notify)
47 brightness = tbl->notify(tbl->dev, brightness);
48
49 if (brightness > max)
50 dev_err(&bl->dev, "Invalid brightness value: %d max: %d\n",
51 brightness, max);
52
53#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
54 /* map API brightness range from (0~255) to hw range (0~128) */
55 tbl->params.duty_cycle = (brightness * 128) / 255;
56#else
57 tbl->params.duty_cycle = brightness & 0xFF;
58#endif
59
60 /* Call tegra display controller function to update backlight */
61 dc = tegra_dc_get_dc(tbl->which_dc);
62 if (dc)
63 tegra_dc_config_pwm(dc, &tbl->params);
64 else
65 dev_err(&bl->dev, "tegra display controller not available\n");
66
67 return 0;
68}
69
70static int tegra_pwm_backlight_get_brightness(struct backlight_device *bl)
71{
72 return bl->props.brightness;
73}
74
75static int tegra_pwm_backlight_check_fb(struct backlight_device *bl,
76 struct fb_info *info)
77{
78 struct tegra_pwm_bl_data *tbl = dev_get_drvdata(&bl->dev);
79 return !tbl->check_fb || tbl->check_fb(tbl->dev, info);
80}
81
82static const struct backlight_ops tegra_pwm_backlight_ops = {
83 .update_status = tegra_pwm_backlight_update_status,
84 .get_brightness = tegra_pwm_backlight_get_brightness,
85 .check_fb = tegra_pwm_backlight_check_fb,
86};
87
88static int tegra_pwm_backlight_probe(struct platform_device *pdev)
89{
90 struct backlight_properties props;
91 struct platform_tegra_pwm_backlight_data *data;
92 struct backlight_device *bl;
93 struct tegra_pwm_bl_data *tbl;
94 int ret;
95
96 data = pdev->dev.platform_data;
97 if (!data) {
98 dev_err(&pdev->dev, "failed to find platform data\n");
99 return -EINVAL;
100 }
101
102 tbl = kzalloc(sizeof(*tbl), GFP_KERNEL);
103 if (!tbl) {
104 dev_err(&pdev->dev, "no memory for state\n");
105 ret = -ENOMEM;
106 goto err_alloc;
107 }
108
109 tbl->dev = &pdev->dev;
110 tbl->which_dc = data->which_dc;
111 tbl->notify = data->notify;
112 tbl->check_fb = data->check_fb;
113 tbl->params.which_pwm = data->which_pwm;
114 tbl->params.gpio_conf_to_sfio = data->gpio_conf_to_sfio;
115 tbl->params.switch_to_sfio = data->switch_to_sfio;
116 tbl->params.period = data->period;
117 tbl->params.clk_div = data->clk_div;
118 tbl->params.clk_select = data->clk_select;
119
120 memset(&props, 0, sizeof(struct backlight_properties));
121 props.type = BACKLIGHT_RAW;
122 props.max_brightness = data->max_brightness;
123 bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, tbl,
124 &tegra_pwm_backlight_ops, &props);
125 if (IS_ERR(bl)) {
126 dev_err(&pdev->dev, "failed to register backlight\n");
127 ret = PTR_ERR(bl);
128 goto err_bl;
129 }
130
131 bl->props.brightness = data->dft_brightness;
132 backlight_update_status(bl);
133
134 platform_set_drvdata(pdev, bl);
135 return 0;
136
137err_bl:
138 kfree(tbl);
139err_alloc:
140 return ret;
141}
142
143static int tegra_pwm_backlight_remove(struct platform_device *pdev)
144{
145 struct backlight_device *bl = platform_get_drvdata(pdev);
146 struct tegra_pwm_bl_data *tbl = dev_get_drvdata(&bl->dev);
147
148 backlight_device_unregister(bl);
149 kfree(tbl);
150 return 0;
151}
152
153static struct platform_driver tegra_pwm_backlight_driver = {
154 .driver = {
155 .name = "tegra-pwm-bl",
156 .owner = THIS_MODULE,
157 },
158 .probe = tegra_pwm_backlight_probe,
159 .remove = tegra_pwm_backlight_remove,
160};
161
162static int __init tegra_pwm_backlight_init(void)
163{
164 return platform_driver_register(&tegra_pwm_backlight_driver);
165}
166late_initcall(tegra_pwm_backlight_init);
167
168static void __exit tegra_pwm_backlight_exit(void)
169{
170 platform_driver_unregister(&tegra_pwm_backlight_driver);
171}
172module_exit(tegra_pwm_backlight_exit);
173
174MODULE_DESCRIPTION("Tegra PWM Backlight Driver");
175MODULE_LICENSE("GPL");
176MODULE_ALIAS("platform:tegra-pwm-backlight");
177