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