1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Backlight control code for Sharp Zaurus SL-5500 |
4 | * |
5 | * Copyright 2005 John Lenz <lenz@cs.wisc.edu> |
6 | * Maintainer: Pavel Machek <pavel@ucw.cz> (unless John wants to :-) |
7 | * |
8 | * This driver assumes single CPU. That's okay, because collie is |
9 | * slightly old hardware, and no one is going to retrofit second CPU to |
10 | * old PDA. |
11 | */ |
12 | |
13 | /* LCD power functions */ |
14 | #include <linux/module.h> |
15 | #include <linux/init.h> |
16 | #include <linux/delay.h> |
17 | #include <linux/device.h> |
18 | #include <linux/interrupt.h> |
19 | #include <linux/fb.h> |
20 | #include <linux/backlight.h> |
21 | |
22 | #include <asm/hardware/locomo.h> |
23 | #include <asm/irq.h> |
24 | #include <asm/mach/sharpsl_param.h> |
25 | #include <asm/mach-types.h> |
26 | |
27 | #include "../../../arch/arm/mach-sa1100/generic.h" |
28 | |
29 | static struct backlight_device *locomolcd_bl_device; |
30 | static struct locomo_dev *locomolcd_dev; |
31 | static unsigned long locomolcd_flags; |
32 | #define LOCOMOLCD_SUSPENDED 0x01 |
33 | |
34 | static void locomolcd_on(int comadj) |
35 | { |
36 | locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 0); |
37 | locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 1); |
38 | mdelay(2); |
39 | |
40 | locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 0); |
41 | locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 1); |
42 | mdelay(2); |
43 | |
44 | locomo_m62332_senddata(locomolcd_dev, comadj, 0); |
45 | mdelay(5); |
46 | |
47 | locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 0); |
48 | locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 1); |
49 | mdelay(10); |
50 | |
51 | /* TFTCRST | CPSOUT=0 | CPSEN */ |
52 | locomo_writel(0x01, locomolcd_dev->mapbase + LOCOMO_TC); |
53 | |
54 | /* Set CPSD */ |
55 | locomo_writel(6, locomolcd_dev->mapbase + LOCOMO_CPSD); |
56 | |
57 | /* TFTCRST | CPSOUT=0 | CPSEN */ |
58 | locomo_writel((0x04 | 0x01), locomolcd_dev->mapbase + LOCOMO_TC); |
59 | mdelay(10); |
60 | |
61 | locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 0); |
62 | locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 1); |
63 | } |
64 | |
65 | static void locomolcd_off(int comadj) |
66 | { |
67 | /* TFTCRST=1 | CPSOUT=1 | CPSEN = 0 */ |
68 | locomo_writel(0x06, locomolcd_dev->mapbase + LOCOMO_TC); |
69 | mdelay(1); |
70 | |
71 | locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 0); |
72 | mdelay(110); |
73 | |
74 | locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 0); |
75 | mdelay(700); |
76 | |
77 | /* TFTCRST=0 | CPSOUT=0 | CPSEN = 0 */ |
78 | locomo_writel(0, locomolcd_dev->mapbase + LOCOMO_TC); |
79 | locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 0); |
80 | locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 0); |
81 | } |
82 | |
83 | void locomolcd_power(int on) |
84 | { |
85 | int comadj = sharpsl_param.comadj; |
86 | unsigned long flags; |
87 | |
88 | local_irq_save(flags); |
89 | |
90 | if (!locomolcd_dev) { |
91 | local_irq_restore(flags); |
92 | return; |
93 | } |
94 | |
95 | /* read comadj */ |
96 | if (comadj == -1 && machine_is_collie()) |
97 | comadj = 128; |
98 | |
99 | if (on) |
100 | locomolcd_on(comadj); |
101 | else |
102 | locomolcd_off(comadj); |
103 | |
104 | local_irq_restore(flags); |
105 | } |
106 | EXPORT_SYMBOL(locomolcd_power); |
107 | |
108 | static int current_intensity; |
109 | |
110 | static int locomolcd_set_intensity(struct backlight_device *bd) |
111 | { |
112 | int intensity = backlight_get_brightness(bd); |
113 | |
114 | if (locomolcd_flags & LOCOMOLCD_SUSPENDED) |
115 | intensity = 0; |
116 | |
117 | switch (intensity) { |
118 | /* |
119 | * AC and non-AC are handled differently, |
120 | * but produce same results in sharp code? |
121 | */ |
122 | case 0: |
123 | locomo_frontlight_set(locomolcd_dev, 0, 0, 161); |
124 | break; |
125 | case 1: |
126 | locomo_frontlight_set(locomolcd_dev, 117, 0, 161); |
127 | break; |
128 | case 2: |
129 | locomo_frontlight_set(locomolcd_dev, 163, 0, 148); |
130 | break; |
131 | case 3: |
132 | locomo_frontlight_set(locomolcd_dev, 194, 0, 161); |
133 | break; |
134 | case 4: |
135 | locomo_frontlight_set(locomolcd_dev, 194, 1, 161); |
136 | break; |
137 | default: |
138 | return -ENODEV; |
139 | } |
140 | current_intensity = intensity; |
141 | return 0; |
142 | } |
143 | |
144 | static int locomolcd_get_intensity(struct backlight_device *bd) |
145 | { |
146 | return current_intensity; |
147 | } |
148 | |
149 | static const struct backlight_ops locomobl_data = { |
150 | .get_brightness = locomolcd_get_intensity, |
151 | .update_status = locomolcd_set_intensity, |
152 | }; |
153 | |
154 | #ifdef CONFIG_PM_SLEEP |
155 | static int locomolcd_suspend(struct device *dev) |
156 | { |
157 | locomolcd_flags |= LOCOMOLCD_SUSPENDED; |
158 | locomolcd_set_intensity(bd: locomolcd_bl_device); |
159 | return 0; |
160 | } |
161 | |
162 | static int locomolcd_resume(struct device *dev) |
163 | { |
164 | locomolcd_flags &= ~LOCOMOLCD_SUSPENDED; |
165 | locomolcd_set_intensity(bd: locomolcd_bl_device); |
166 | return 0; |
167 | } |
168 | #endif |
169 | |
170 | static SIMPLE_DEV_PM_OPS(locomolcd_pm_ops, locomolcd_suspend, locomolcd_resume); |
171 | |
172 | static int locomolcd_probe(struct locomo_dev *ldev) |
173 | { |
174 | struct backlight_properties props; |
175 | unsigned long flags; |
176 | |
177 | local_irq_save(flags); |
178 | locomolcd_dev = ldev; |
179 | |
180 | locomo_gpio_set_dir(ldev->dev.parent, LOCOMO_GPIO_FL_VR, 0); |
181 | |
182 | local_irq_restore(flags); |
183 | |
184 | memset(&props, 0, sizeof(struct backlight_properties)); |
185 | props.type = BACKLIGHT_RAW; |
186 | props.max_brightness = 4; |
187 | locomolcd_bl_device = backlight_device_register(name: "locomo-bl" , |
188 | dev: &ldev->dev, NULL, |
189 | ops: &locomobl_data, props: &props); |
190 | |
191 | if (IS_ERR(ptr: locomolcd_bl_device)) |
192 | return PTR_ERR(ptr: locomolcd_bl_device); |
193 | |
194 | /* Set up frontlight so that screen is readable */ |
195 | locomolcd_bl_device->props.brightness = 2; |
196 | locomolcd_set_intensity(bd: locomolcd_bl_device); |
197 | |
198 | return 0; |
199 | } |
200 | |
201 | static void locomolcd_remove(struct locomo_dev *dev) |
202 | { |
203 | unsigned long flags; |
204 | |
205 | locomolcd_bl_device->props.brightness = 0; |
206 | locomolcd_bl_device->props.power = 0; |
207 | locomolcd_set_intensity(bd: locomolcd_bl_device); |
208 | |
209 | backlight_device_unregister(bd: locomolcd_bl_device); |
210 | local_irq_save(flags); |
211 | locomolcd_dev = NULL; |
212 | local_irq_restore(flags); |
213 | } |
214 | |
215 | static struct locomo_driver poodle_lcd_driver = { |
216 | .drv = { |
217 | .name = "locomo-backlight" , |
218 | .pm = &locomolcd_pm_ops, |
219 | }, |
220 | .devid = LOCOMO_DEVID_BACKLIGHT, |
221 | .probe = locomolcd_probe, |
222 | .remove = locomolcd_remove, |
223 | }; |
224 | |
225 | static int __init locomolcd_init(void) |
226 | { |
227 | return locomo_driver_register(&poodle_lcd_driver); |
228 | } |
229 | |
230 | static void __exit locomolcd_exit(void) |
231 | { |
232 | locomo_driver_unregister(&poodle_lcd_driver); |
233 | } |
234 | |
235 | module_init(locomolcd_init); |
236 | module_exit(locomolcd_exit); |
237 | |
238 | MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>, Pavel Machek <pavel@ucw.cz>" ); |
239 | MODULE_DESCRIPTION("Collie LCD driver" ); |
240 | MODULE_LICENSE("GPL" ); |
241 | |