2 * drivers/video/backlight/ubicom32bl.c
3 * Backlight driver for the Ubicom32 platform
5 * (C) Copyright 2009, Ubicom, Inc.
7 * This file is part of the Ubicom32 Linux Kernel Port.
9 * The Ubicom32 Linux Kernel Port is free software: you can redistribute
10 * it and/or modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation, either version 2 of the
12 * License, or (at your option) any later version.
14 * The Ubicom32 Linux Kernel Port is distributed in the hope that it
15 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
16 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with the Ubicom32 Linux Kernel Port. If not,
21 * see <http://www.gnu.org/licenses/>.
23 * Ubicom32 implementation derived from (with many thanks):
28 #include <linux/init.h>
29 #include <linux/kernel.h>
30 #include <linux/module.h>
31 #include <linux/platform_device.h>
32 #include <linux/backlight.h>
35 #include <asm/ubicom32bl.h>
36 #include <asm/ip5000.h>
38 #define DRIVER_NAME "ubicom32bl"
39 #define UBICOM32BL_MAX_BRIGHTNESS 255
41 struct ubicom32bl_data
{
43 * Pointer to the platform data structure. Keep this around since we need values
44 * from it to set the backlight intensity.
46 const struct ubicom32bl_platform_data
*pdata
;
49 * Backlight device, we have to save this for use when we remove ourselves.
51 struct backlight_device
*bldev
;
54 * Current intensity, used for get_intensity.
59 * Init function for PWM
61 int (*init_fn
)(struct ubicom32bl_data
*);
64 * Set intensity function depending on the backlight type
66 int (*set_intensity_fn
)(struct ubicom32bl_data
*, int);
70 * ubicom32bl_set_intensity_gpio
72 static int ubicom32bl_set_intensity_gpio(struct ubicom32bl_data
*ud
, int intensity
)
74 ud
->cur_intensity
= intensity
? 255 : 0;
86 * ubicom32bl_set_intensity_hw
88 static int ubicom32bl_set_intensity_hw(struct ubicom32bl_data
*ud
, int intensity
)
90 u16_t period
= ud
->pdata
->pwm_period
;
94 * Calculate the new duty cycle
96 duty
= (period
* intensity
) / (UBICOM32BL_MAX_BRIGHTNESS
+ 1);
99 * Set the new duty cycle
101 switch (ud
->pdata
->pwm_channel
) {
104 * Channel 0 is in the lower half of PORT C ctl0 and ctl1
106 UBICOM32_IO_PORT(RC
)->ctl1
= (ud
->pdata
->pwm_period
<< 16) | duty
;
111 * Channel 1 is in the upper half of PORT C ctl0 and ctl2
113 UBICOM32_IO_PORT(RC
)->ctl2
= (ud
->pdata
->pwm_period
<< 16) | duty
;
118 * Channel 2 is in PORT H ctl0 and ctl1
120 UBICOM32_IO_PORT(RH
)->ctl1
= (ud
->pdata
->pwm_period
<< 16) | duty
;
124 ud
->cur_intensity
= intensity
;
130 * ubicom32bl_set_intensity
132 static int ubicom32bl_set_intensity(struct backlight_device
*bd
)
134 struct ubicom32bl_data
*ud
= (struct ubicom32bl_data
*)bl_get_data(bd
);
135 int intensity
= bd
->props
.brightness
;
138 * If we're blanked the the intensity doesn't matter.
140 if ((bd
->props
.power
!= FB_BLANK_UNBLANK
) || (bd
->props
.fb_blank
!= FB_BLANK_UNBLANK
)) {
145 * Check for inverted backlight.
147 if (ud
->pdata
->invert
) {
148 intensity
= UBICOM32BL_MAX_BRIGHTNESS
- intensity
;
151 if (ud
->set_intensity_fn
) {
152 return ud
->set_intensity_fn(ud
, intensity
);
159 * ubicom32bl_get_intensity
160 * Return the current intensity of the backlight.
162 static int ubicom32bl_get_intensity(struct backlight_device
*bd
)
164 struct ubicom32bl_data
*ud
= (struct ubicom32bl_data
*)bl_get_data(bd
);
166 return ud
->cur_intensity
;
170 * ubicom32bl_init_hw_pwm
171 * Set the appropriate PWM registers
173 static int ubicom32bl_init_hw_pwm(struct ubicom32bl_data
*ud
)
178 u16_t pwm_cfg
= (1 << 13) | (ud
->pdata
->pwm_prescale
<< 8) ;
180 switch (ud
->pdata
->pwm_channel
) {
183 * Channel 0 is in the lower half of PORT C ctl0 and ctl1 (PA5)
185 UBICOM32_IO_PORT(RC
)->ctl0
&= ~0xFFFF;
186 UBICOM32_IO_PORT(RC
)->ctl0
|= pwm_cfg
;
187 UBICOM32_IO_PORT(RC
)->ctl1
= ud
->pdata
->pwm_period
<< 16;
190 * If the port function is not set, set it to GPIO/PWM
192 if (!UBICOM32_IO_PORT(RA
)->function
) {
193 UBICOM32_IO_PORT(RA
)->function
= 3;
199 * Channel 1 is in the upper half of PORT C ctl0 and ctl2 (PE4)
201 UBICOM32_IO_PORT(RC
)->ctl0
&= ~0xFFFF0000;
202 UBICOM32_IO_PORT(RC
)->ctl0
|= (pwm_cfg
<< 16);
203 UBICOM32_IO_PORT(RC
)->ctl2
= ud
->pdata
->pwm_period
<< 16;
206 * If the port function is not set, set it to GPIO/ExtIOInt
208 if (!UBICOM32_IO_PORT(RE
)->function
) {
209 UBICOM32_IO_PORT(RE
)->function
= 3;
215 * Channel 2 is in PORT H ctl0 and ctl1 (PD0)
217 UBICOM32_IO_PORT(RH
)->ctl0
&= ~0xFFFF0000;
218 UBICOM32_IO_PORT(RH
)->ctl0
= pwm_cfg
;
219 UBICOM32_IO_PORT(RH
)->ctl1
= ud
->pdata
->pwm_period
<< 16;
222 * If the port function is not set, set it to GPIO
224 if (!UBICOM32_IO_PORT(RD
)->function
) {
225 UBICOM32_IO_PORT(RD
)->function
= 3;
234 * ubicom32bl_init_gpio
235 * Allocate the appropriate GPIO
237 static int ubicom32bl_init_gpio(struct ubicom32bl_data
*ud
)
242 static struct backlight_ops ubicom32bl_ops
= {
243 .get_brightness
= ubicom32bl_get_intensity
,
244 .update_status
= ubicom32bl_set_intensity
,
250 static int ubicom32bl_probe(struct platform_device
*pdev
)
252 const struct ubicom32bl_platform_data
*pdata
= pdev
->dev
.platform_data
;
253 struct ubicom32bl_data
*ud
;
254 struct backlight_device
*bldev
;
258 * Check to see if we have any platform data, if we don't then the backlight is not
259 * configured on this device.
266 * Allocate our private data
268 ud
= kzalloc(sizeof(struct ubicom32bl_data
), GFP_KERNEL
);
276 * Check to see that the platform data is valid for this driver
278 switch (pdata
->type
) {
279 case UBICOM32BL_TYPE_PWM
:
282 * Make sure we have a PWM peripheral
286 "move.4 %0, CHIP_ID \n\t"
289 if (chipid
!= 0x00030001) {
294 if (pdata
->pwm_channel
> 3) {
298 if (pdata
->pwm_prescale
> 16) {
303 ud
->init_fn
= ubicom32bl_init_hw_pwm
;
304 ud
->set_intensity_fn
= ubicom32bl_set_intensity_hw
;
308 case UBICOM32BL_TYPE_PWM_HRT
:
309 // For now, PWM HRT devices are treated as binary lights.
311 case UBICOM32BL_TYPE_BINARY
:
312 ud
->init_fn
= ubicom32bl_init_gpio
;
313 ud
->set_intensity_fn
= ubicom32bl_set_intensity_gpio
;
318 * Register our backlight device
320 bldev
= backlight_device_register(DRIVER_NAME
, &pdev
->dev
, ud
, &ubicom32bl_ops
);
322 retval
= PTR_ERR(bldev
);
327 ud
->cur_intensity
= pdata
->default_intensity
;
328 platform_set_drvdata(pdev
, ud
);
331 * Start up the backlight at the prescribed default intensity
333 bldev
->props
.power
= FB_BLANK_UNBLANK
;
334 bldev
->props
.max_brightness
= UBICOM32BL_MAX_BRIGHTNESS
;
335 bldev
->props
.brightness
= pdata
->default_intensity
;
338 if (ud
->init_fn(ud
) != 0) {
340 backlight_device_unregister(ud
->bldev
);
344 ubicom32bl_set_intensity(bldev
);
346 printk(KERN_INFO DRIVER_NAME
": Backlight driver started\n");
351 platform_set_drvdata(pdev
, NULL
);
359 static int __exit
ubicom32bl_remove(struct platform_device
*pdev
)
361 struct ubicom32bl_data
*ud
= platform_get_drvdata(pdev
);
363 backlight_device_unregister(ud
->bldev
);
364 platform_set_drvdata(pdev
, NULL
);
370 static struct platform_driver ubicom32bl_driver
= {
373 .owner
= THIS_MODULE
,
376 .remove
= __exit_p(ubicom32bl_remove
),
382 static int __init
ubicom32bl_init(void)
384 return platform_driver_probe(&ubicom32bl_driver
, ubicom32bl_probe
);
386 module_init(ubicom32bl_init
);
391 static void __exit
ubicom32bl_exit(void)
393 platform_driver_unregister(&ubicom32bl_driver
);
395 module_exit(ubicom32bl_exit
);
397 MODULE_AUTHOR("Patrick Tjin <@ubicom.com>");
398 MODULE_DESCRIPTION("Ubicom32 backlight driver");
399 MODULE_LICENSE("GPL");