18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Backlight control code for Sharp Zaurus SL-5500 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2005 John Lenz <lenz@cs.wisc.edu> 68c2ecf20Sopenharmony_ci * Maintainer: Pavel Machek <pavel@ucw.cz> (unless John wants to :-) 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This driver assumes single CPU. That's okay, because collie is 98c2ecf20Sopenharmony_ci * slightly old hardware, and no one is going to retrofit second CPU to 108c2ecf20Sopenharmony_ci * old PDA. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci/* LCD power functions */ 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/init.h> 168c2ecf20Sopenharmony_ci#include <linux/delay.h> 178c2ecf20Sopenharmony_ci#include <linux/device.h> 188c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 198c2ecf20Sopenharmony_ci#include <linux/fb.h> 208c2ecf20Sopenharmony_ci#include <linux/backlight.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <asm/hardware/locomo.h> 238c2ecf20Sopenharmony_ci#include <asm/irq.h> 248c2ecf20Sopenharmony_ci#include <asm/mach/sharpsl_param.h> 258c2ecf20Sopenharmony_ci#include <asm/mach-types.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include "../../../arch/arm/mach-sa1100/generic.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic struct backlight_device *locomolcd_bl_device; 308c2ecf20Sopenharmony_cistatic struct locomo_dev *locomolcd_dev; 318c2ecf20Sopenharmony_cistatic unsigned long locomolcd_flags; 328c2ecf20Sopenharmony_ci#define LOCOMOLCD_SUSPENDED 0x01 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic void locomolcd_on(int comadj) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 0); 378c2ecf20Sopenharmony_ci locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 1); 388c2ecf20Sopenharmony_ci mdelay(2); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 0); 418c2ecf20Sopenharmony_ci locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 1); 428c2ecf20Sopenharmony_ci mdelay(2); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci locomo_m62332_senddata(locomolcd_dev, comadj, 0); 458c2ecf20Sopenharmony_ci mdelay(5); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 0); 488c2ecf20Sopenharmony_ci locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 1); 498c2ecf20Sopenharmony_ci mdelay(10); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci /* TFTCRST | CPSOUT=0 | CPSEN */ 528c2ecf20Sopenharmony_ci locomo_writel(0x01, locomolcd_dev->mapbase + LOCOMO_TC); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci /* Set CPSD */ 558c2ecf20Sopenharmony_ci locomo_writel(6, locomolcd_dev->mapbase + LOCOMO_CPSD); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci /* TFTCRST | CPSOUT=0 | CPSEN */ 588c2ecf20Sopenharmony_ci locomo_writel((0x04 | 0x01), locomolcd_dev->mapbase + LOCOMO_TC); 598c2ecf20Sopenharmony_ci mdelay(10); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 0); 628c2ecf20Sopenharmony_ci locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 1); 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic void locomolcd_off(int comadj) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci /* TFTCRST=1 | CPSOUT=1 | CPSEN = 0 */ 688c2ecf20Sopenharmony_ci locomo_writel(0x06, locomolcd_dev->mapbase + LOCOMO_TC); 698c2ecf20Sopenharmony_ci mdelay(1); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 0); 728c2ecf20Sopenharmony_ci mdelay(110); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 0); 758c2ecf20Sopenharmony_ci mdelay(700); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* TFTCRST=0 | CPSOUT=0 | CPSEN = 0 */ 788c2ecf20Sopenharmony_ci locomo_writel(0, locomolcd_dev->mapbase + LOCOMO_TC); 798c2ecf20Sopenharmony_ci locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 0); 808c2ecf20Sopenharmony_ci locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 0); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_civoid locomolcd_power(int on) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci int comadj = sharpsl_param.comadj; 868c2ecf20Sopenharmony_ci unsigned long flags; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci local_irq_save(flags); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (!locomolcd_dev) { 918c2ecf20Sopenharmony_ci local_irq_restore(flags); 928c2ecf20Sopenharmony_ci return; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* read comadj */ 968c2ecf20Sopenharmony_ci if (comadj == -1 && machine_is_collie()) 978c2ecf20Sopenharmony_ci comadj = 128; 988c2ecf20Sopenharmony_ci if (comadj == -1 && machine_is_poodle()) 998c2ecf20Sopenharmony_ci comadj = 118; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (on) 1028c2ecf20Sopenharmony_ci locomolcd_on(comadj); 1038c2ecf20Sopenharmony_ci else 1048c2ecf20Sopenharmony_ci locomolcd_off(comadj); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci local_irq_restore(flags); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ciEXPORT_SYMBOL(locomolcd_power); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic int current_intensity; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic int locomolcd_set_intensity(struct backlight_device *bd) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci int intensity = backlight_get_brightness(bd); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci if (locomolcd_flags & LOCOMOLCD_SUSPENDED) 1178c2ecf20Sopenharmony_ci intensity = 0; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci switch (intensity) { 1208c2ecf20Sopenharmony_ci /* 1218c2ecf20Sopenharmony_ci * AC and non-AC are handled differently, 1228c2ecf20Sopenharmony_ci * but produce same results in sharp code? 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_ci case 0: 1258c2ecf20Sopenharmony_ci locomo_frontlight_set(locomolcd_dev, 0, 0, 161); 1268c2ecf20Sopenharmony_ci break; 1278c2ecf20Sopenharmony_ci case 1: 1288c2ecf20Sopenharmony_ci locomo_frontlight_set(locomolcd_dev, 117, 0, 161); 1298c2ecf20Sopenharmony_ci break; 1308c2ecf20Sopenharmony_ci case 2: 1318c2ecf20Sopenharmony_ci locomo_frontlight_set(locomolcd_dev, 163, 0, 148); 1328c2ecf20Sopenharmony_ci break; 1338c2ecf20Sopenharmony_ci case 3: 1348c2ecf20Sopenharmony_ci locomo_frontlight_set(locomolcd_dev, 194, 0, 161); 1358c2ecf20Sopenharmony_ci break; 1368c2ecf20Sopenharmony_ci case 4: 1378c2ecf20Sopenharmony_ci locomo_frontlight_set(locomolcd_dev, 194, 1, 161); 1388c2ecf20Sopenharmony_ci break; 1398c2ecf20Sopenharmony_ci default: 1408c2ecf20Sopenharmony_ci return -ENODEV; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci current_intensity = intensity; 1438c2ecf20Sopenharmony_ci return 0; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic int locomolcd_get_intensity(struct backlight_device *bd) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci return current_intensity; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic const struct backlight_ops locomobl_data = { 1528c2ecf20Sopenharmony_ci .get_brightness = locomolcd_get_intensity, 1538c2ecf20Sopenharmony_ci .update_status = locomolcd_set_intensity, 1548c2ecf20Sopenharmony_ci}; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 1578c2ecf20Sopenharmony_cistatic int locomolcd_suspend(struct device *dev) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci locomolcd_flags |= LOCOMOLCD_SUSPENDED; 1608c2ecf20Sopenharmony_ci locomolcd_set_intensity(locomolcd_bl_device); 1618c2ecf20Sopenharmony_ci return 0; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic int locomolcd_resume(struct device *dev) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci locomolcd_flags &= ~LOCOMOLCD_SUSPENDED; 1678c2ecf20Sopenharmony_ci locomolcd_set_intensity(locomolcd_bl_device); 1688c2ecf20Sopenharmony_ci return 0; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci#endif 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(locomolcd_pm_ops, locomolcd_suspend, locomolcd_resume); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic int locomolcd_probe(struct locomo_dev *ldev) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci struct backlight_properties props; 1778c2ecf20Sopenharmony_ci unsigned long flags; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci local_irq_save(flags); 1808c2ecf20Sopenharmony_ci locomolcd_dev = ldev; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci locomo_gpio_set_dir(ldev->dev.parent, LOCOMO_GPIO_FL_VR, 0); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci /* 1858c2ecf20Sopenharmony_ci * the poodle_lcd_power function is called for the first time 1868c2ecf20Sopenharmony_ci * from fs_initcall, which is before locomo is activated. 1878c2ecf20Sopenharmony_ci * We need to recall poodle_lcd_power here 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_ci if (machine_is_poodle()) 1908c2ecf20Sopenharmony_ci locomolcd_power(1); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci local_irq_restore(flags); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci memset(&props, 0, sizeof(struct backlight_properties)); 1958c2ecf20Sopenharmony_ci props.type = BACKLIGHT_RAW; 1968c2ecf20Sopenharmony_ci props.max_brightness = 4; 1978c2ecf20Sopenharmony_ci locomolcd_bl_device = backlight_device_register("locomo-bl", 1988c2ecf20Sopenharmony_ci &ldev->dev, NULL, 1998c2ecf20Sopenharmony_ci &locomobl_data, &props); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (IS_ERR(locomolcd_bl_device)) 2028c2ecf20Sopenharmony_ci return PTR_ERR(locomolcd_bl_device); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci /* Set up frontlight so that screen is readable */ 2058c2ecf20Sopenharmony_ci locomolcd_bl_device->props.brightness = 2; 2068c2ecf20Sopenharmony_ci locomolcd_set_intensity(locomolcd_bl_device); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci return 0; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic int locomolcd_remove(struct locomo_dev *dev) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci unsigned long flags; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci locomolcd_bl_device->props.brightness = 0; 2168c2ecf20Sopenharmony_ci locomolcd_bl_device->props.power = 0; 2178c2ecf20Sopenharmony_ci locomolcd_set_intensity(locomolcd_bl_device); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci backlight_device_unregister(locomolcd_bl_device); 2208c2ecf20Sopenharmony_ci local_irq_save(flags); 2218c2ecf20Sopenharmony_ci locomolcd_dev = NULL; 2228c2ecf20Sopenharmony_ci local_irq_restore(flags); 2238c2ecf20Sopenharmony_ci return 0; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic struct locomo_driver poodle_lcd_driver = { 2278c2ecf20Sopenharmony_ci .drv = { 2288c2ecf20Sopenharmony_ci .name = "locomo-backlight", 2298c2ecf20Sopenharmony_ci .pm = &locomolcd_pm_ops, 2308c2ecf20Sopenharmony_ci }, 2318c2ecf20Sopenharmony_ci .devid = LOCOMO_DEVID_BACKLIGHT, 2328c2ecf20Sopenharmony_ci .probe = locomolcd_probe, 2338c2ecf20Sopenharmony_ci .remove = locomolcd_remove, 2348c2ecf20Sopenharmony_ci}; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic int __init locomolcd_init(void) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci return locomo_driver_register(&poodle_lcd_driver); 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic void __exit locomolcd_exit(void) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci locomo_driver_unregister(&poodle_lcd_driver); 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cimodule_init(locomolcd_init); 2478c2ecf20Sopenharmony_cimodule_exit(locomolcd_exit); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ciMODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>, Pavel Machek <pavel@ucw.cz>"); 2508c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Collie LCD driver"); 2518c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 252