1/*
2 *  Backlight Driver for Sharp Zaurus Handhelds (various models)
3 *
4 *  Copyright (c) 2004-2006 Richard Purdie
5 *
6 *  Based on Sharp's 2.4 Backlight Driver
7 *
8 *  This program is free software; you can redistribute it and/or modify
9 *  it under the terms of the GNU General Public License version 2 as
10 *  published by the Free Software Foundation.
11 *
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/mutex.h>
19#include <linux/fb.h>
20#include <linux/backlight.h>
21#include <asm/arch/sharpsl.h>
22#include <asm/hardware/sharpsl_pm.h>
23
24static int corgibl_intensity;
25static struct backlight_properties corgibl_data;
26static struct backlight_device *corgi_backlight_device;
27static struct corgibl_machinfo *bl_machinfo;
28
29static unsigned long corgibl_flags;
30#define CORGIBL_SUSPENDED     0x01
31#define CORGIBL_BATTLOW       0x02
32
33static int corgibl_send_intensity(struct backlight_device *bd)
34{
35	void (*corgi_kick_batt)(void);
36	int intensity = bd->props.brightness;
37
38	if (bd->props.power != FB_BLANK_UNBLANK)
39		intensity = 0;
40	if (bd->props.fb_blank != FB_BLANK_UNBLANK)
41		intensity = 0;
42	if (corgibl_flags & CORGIBL_SUSPENDED)
43		intensity = 0;
44	if (corgibl_flags & CORGIBL_BATTLOW)
45		intensity &= bl_machinfo->limit_mask;
46
47	bl_machinfo->set_bl_intensity(intensity);
48
49	corgibl_intensity = intensity;
50
51 	corgi_kick_batt = symbol_get(sharpsl_battery_kick);
52 	if (corgi_kick_batt) {
53 		corgi_kick_batt();
54 		symbol_put(sharpsl_battery_kick);
55 	}
56
57	return 0;
58}
59
60#ifdef CONFIG_PM
61static int corgibl_suspend(struct platform_device *pdev, pm_message_t state)
62{
63	struct backlight_device *bd = platform_get_drvdata(pdev);
64
65	corgibl_flags |= CORGIBL_SUSPENDED;
66	backlight_update_status(bd);
67	return 0;
68}
69
70static int corgibl_resume(struct platform_device *pdev)
71{
72	struct backlight_device *bd = platform_get_drvdata(pdev);
73
74	corgibl_flags &= ~CORGIBL_SUSPENDED;
75	backlight_update_status(bd);
76	return 0;
77}
78#else
79#define corgibl_suspend	NULL
80#define corgibl_resume	NULL
81#endif
82
83static int corgibl_get_intensity(struct backlight_device *bd)
84{
85	return corgibl_intensity;
86}
87
88/*
89 * Called when the battery is low to limit the backlight intensity.
90 * If limit==0 clear any limit, otherwise limit the intensity
91 */
92void corgibl_limit_intensity(int limit)
93{
94	if (limit)
95		corgibl_flags |= CORGIBL_BATTLOW;
96	else
97		corgibl_flags &= ~CORGIBL_BATTLOW;
98	backlight_update_status(corgi_backlight_device);
99}
100EXPORT_SYMBOL(corgibl_limit_intensity);
101
102
103static struct backlight_ops corgibl_ops = {
104	.get_brightness = corgibl_get_intensity,
105	.update_status  = corgibl_send_intensity,
106};
107
108static int corgibl_probe(struct platform_device *pdev)
109{
110	struct corgibl_machinfo *machinfo = pdev->dev.platform_data;
111
112	bl_machinfo = machinfo;
113	if (!machinfo->limit_mask)
114		machinfo->limit_mask = -1;
115
116	corgi_backlight_device = backlight_device_register ("corgi-bl",
117		&pdev->dev, NULL, &corgibl_ops);
118	if (IS_ERR (corgi_backlight_device))
119		return PTR_ERR (corgi_backlight_device);
120
121	platform_set_drvdata(pdev, corgi_backlight_device);
122
123	corgi_backlight_device->props.max_brightness = machinfo->max_intensity;
124	corgi_backlight_device->props.power = FB_BLANK_UNBLANK;
125	corgi_backlight_device->props.brightness = machinfo->default_intensity;
126	backlight_update_status(corgi_backlight_device);
127
128	printk("Corgi Backlight Driver Initialized.\n");
129	return 0;
130}
131
132static int corgibl_remove(struct platform_device *pdev)
133{
134	struct backlight_device *bd = platform_get_drvdata(pdev);
135
136	corgibl_data.power = 0;
137	corgibl_data.brightness = 0;
138	backlight_update_status(bd);
139
140	backlight_device_unregister(bd);
141
142	printk("Corgi Backlight Driver Unloaded\n");
143	return 0;
144}
145
146static struct platform_driver corgibl_driver = {
147	.probe		= corgibl_probe,
148	.remove		= corgibl_remove,
149	.suspend	= corgibl_suspend,
150	.resume		= corgibl_resume,
151	.driver		= {
152		.name	= "corgi-bl",
153	},
154};
155
156static int __init corgibl_init(void)
157{
158	return platform_driver_register(&corgibl_driver);
159}
160
161static void __exit corgibl_exit(void)
162{
163	platform_driver_unregister(&corgibl_driver);
164}
165
166module_init(corgibl_init);
167module_exit(corgibl_exit);
168
169MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
170MODULE_DESCRIPTION("Corgi Backlight Driver");
171MODULE_LICENSE("GPL");
172