1 /*
2  *
3  * Backlight driver for HP Jornada 700 series (710/720/728)
4  * Copyright (C) 2006-2009 Kristoffer Ericson <kristoffer.ericson@gmail.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License version
8  * 2 or any later version as published by the Free Software Foundation.
9  *
10  */
11 
12 #include <linux/backlight.h>
13 #include <linux/device.h>
14 #include <linux/fb.h>
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <linux/platform_device.h>
18 
19 #include <mach/jornada720.h>
20 #include <mach/hardware.h>
21 
22 #include <video/s1d13xxxfb.h>
23 
24 #define BL_MAX_BRIGHT	255
25 #define BL_DEF_BRIGHT	25
26 
27 static int jornada_bl_get_brightness(struct backlight_device *bd)
28 {
29 	int ret;
30 
31 	/* check if backlight is on */
32 	if (!(PPSR & PPC_LDD1))
33 		return 0;
34 
35 	jornada_ssp_start();
36 
37 	/* cmd should return txdummy */
38 	ret = jornada_ssp_byte(GETBRIGHTNESS);
39 
40 	if (jornada_ssp_byte(GETBRIGHTNESS) != TXDUMMY) {
41 		printk(KERN_ERR "bl : get brightness timeout\n");
42 		jornada_ssp_end();
43 		return -ETIMEDOUT;
44 	} else /* exchange txdummy for value */
45 		ret = jornada_ssp_byte(TXDUMMY);
46 
47 	jornada_ssp_end();
48 
49 	return (BL_MAX_BRIGHT - ret);
50 }
51 
52 static int jornada_bl_update_status(struct backlight_device *bd)
53 {
54 	int ret = 0;
55 
56 	jornada_ssp_start();
57 
58 	/* If backlight is off then really turn it off */
59 	if ((bd->props.power != FB_BLANK_UNBLANK) || (bd->props.fb_blank != FB_BLANK_UNBLANK)) {
60 		ret = jornada_ssp_byte(BRIGHTNESSOFF);
61 		if (ret != TXDUMMY) {
62 			printk(KERN_INFO "bl : brightness off timeout\n");
63 			/* turn off backlight */
64 			PPSR &= ~PPC_LDD1;
65 			PPDR |= PPC_LDD1;
66 			ret = -ETIMEDOUT;
67 		}
68 	} else  /* turn on backlight */
69 		PPSR |= PPC_LDD1;
70 
71 		/* send command to our mcu */
72 		if (jornada_ssp_byte(SETBRIGHTNESS) != TXDUMMY) {
73 			printk(KERN_INFO "bl : failed to set brightness\n");
74 			ret = -ETIMEDOUT;
75 			goto out;
76 		}
77 
78 		/* at this point we expect that the mcu has accepted
79 		   our command and is waiting for our new value
80 		   please note that maximum brightness is 255,
81 		   but due to physical layout it is equal to 0, so we simply
82 		   invert the value (MAX VALUE - NEW VALUE). */
83 		if (jornada_ssp_byte(BL_MAX_BRIGHT - bd->props.brightness) != TXDUMMY) {
84 			printk(KERN_ERR "bl : set brightness failed\n");
85 			ret = -ETIMEDOUT;
86 		}
87 
88 		/* If infact we get an TXDUMMY as output we are happy and dont
89 		   make any further comments about it */
90 out:
91 	jornada_ssp_end();
92 
93 	return ret;
94 }
95 
96 static const struct backlight_ops jornada_bl_ops = {
97 	.get_brightness = jornada_bl_get_brightness,
98 	.update_status = jornada_bl_update_status,
99 	.options = BL_CORE_SUSPENDRESUME,
100 };
101 
102 static int jornada_bl_probe(struct platform_device *pdev)
103 {
104 	struct backlight_properties props;
105 	int ret;
106 	struct backlight_device *bd;
107 
108 	memset(&props, 0, sizeof(struct backlight_properties));
109 	props.type = BACKLIGHT_RAW;
110 	props.max_brightness = BL_MAX_BRIGHT;
111 	bd = backlight_device_register(S1D_DEVICENAME, &pdev->dev, NULL,
112 				       &jornada_bl_ops, &props);
113 
114 	if (IS_ERR(bd)) {
115 		ret = PTR_ERR(bd);
116 		printk(KERN_ERR "bl : failed to register device, err=%x\n", ret);
117 		return ret;
118 	}
119 
120 	bd->props.power = FB_BLANK_UNBLANK;
121 	bd->props.brightness = BL_DEF_BRIGHT;
122 	/* note. make sure max brightness is set otherwise
123 	   you will get seemingly non-related errors when
124 	   trying to change brightness */
125 	jornada_bl_update_status(bd);
126 
127 	platform_set_drvdata(pdev, bd);
128 	printk(KERN_INFO "HP Jornada 700 series backlight driver\n");
129 
130 	return 0;
131 }
132 
133 static int jornada_bl_remove(struct platform_device *pdev)
134 {
135 	struct backlight_device *bd = platform_get_drvdata(pdev);
136 
137 	backlight_device_unregister(bd);
138 
139 	return 0;
140 }
141 
142 static struct platform_driver jornada_bl_driver = {
143 	.probe		= jornada_bl_probe,
144 	.remove		= jornada_bl_remove,
145 	.driver	= {
146 		.name	= "jornada_bl",
147 	},
148 };
149 
150 static int __init jornada_bl_init(void)
151 {
152 	return platform_driver_register(&jornada_bl_driver);
153 }
154 
155 static void __exit jornada_bl_exit(void)
156 {
157 	platform_driver_unregister(&jornada_bl_driver);
158 }
159 
160 MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson>");
161 MODULE_DESCRIPTION("HP Jornada 710/720/728 Backlight driver");
162 MODULE_LICENSE("GPL");
163 
164 module_init(jornada_bl_init);
165 module_exit(jornada_bl_exit);
166