162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Based on drivers/video/omap/lcd_inn1510.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * LCD panel support for the Amstrad E3 (Delta) videophone. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2006 Jonathan McDowell <noodles@earth.li> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/platform_device.h> 1262306a36Sopenharmony_ci#include <linux/io.h> 1362306a36Sopenharmony_ci#include <linux/delay.h> 1462306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1562306a36Sopenharmony_ci#include <linux/lcd.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/soc/ti/omap1-io.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "omapfb.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define AMS_DELTA_DEFAULT_CONTRAST 112 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define AMS_DELTA_MAX_CONTRAST 0x00FF 2462306a36Sopenharmony_ci#define AMS_DELTA_LCD_POWER 0x0100 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* LCD class device section */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic int ams_delta_lcd; 3062306a36Sopenharmony_cistatic struct gpio_desc *gpiod_vblen; 3162306a36Sopenharmony_cistatic struct gpio_desc *gpiod_ndisp; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic int ams_delta_lcd_set_power(struct lcd_device *dev, int power) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci if (power == FB_BLANK_UNBLANK) { 3662306a36Sopenharmony_ci if (!(ams_delta_lcd & AMS_DELTA_LCD_POWER)) { 3762306a36Sopenharmony_ci omap_writeb(ams_delta_lcd & AMS_DELTA_MAX_CONTRAST, 3862306a36Sopenharmony_ci OMAP_PWL_ENABLE); 3962306a36Sopenharmony_ci omap_writeb(1, OMAP_PWL_CLK_ENABLE); 4062306a36Sopenharmony_ci ams_delta_lcd |= AMS_DELTA_LCD_POWER; 4162306a36Sopenharmony_ci } 4262306a36Sopenharmony_ci } else { 4362306a36Sopenharmony_ci if (ams_delta_lcd & AMS_DELTA_LCD_POWER) { 4462306a36Sopenharmony_ci omap_writeb(0, OMAP_PWL_ENABLE); 4562306a36Sopenharmony_ci omap_writeb(0, OMAP_PWL_CLK_ENABLE); 4662306a36Sopenharmony_ci ams_delta_lcd &= ~AMS_DELTA_LCD_POWER; 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci return 0; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic int ams_delta_lcd_set_contrast(struct lcd_device *dev, int value) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci if ((value >= 0) && (value <= AMS_DELTA_MAX_CONTRAST)) { 5562306a36Sopenharmony_ci omap_writeb(value, OMAP_PWL_ENABLE); 5662306a36Sopenharmony_ci ams_delta_lcd &= ~AMS_DELTA_MAX_CONTRAST; 5762306a36Sopenharmony_ci ams_delta_lcd |= value; 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci return 0; 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#ifdef CONFIG_LCD_CLASS_DEVICE 6362306a36Sopenharmony_cistatic int ams_delta_lcd_get_power(struct lcd_device *dev) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci if (ams_delta_lcd & AMS_DELTA_LCD_POWER) 6662306a36Sopenharmony_ci return FB_BLANK_UNBLANK; 6762306a36Sopenharmony_ci else 6862306a36Sopenharmony_ci return FB_BLANK_POWERDOWN; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic int ams_delta_lcd_get_contrast(struct lcd_device *dev) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci if (!(ams_delta_lcd & AMS_DELTA_LCD_POWER)) 7462306a36Sopenharmony_ci return 0; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci return ams_delta_lcd & AMS_DELTA_MAX_CONTRAST; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic struct lcd_ops ams_delta_lcd_ops = { 8062306a36Sopenharmony_ci .get_power = ams_delta_lcd_get_power, 8162306a36Sopenharmony_ci .set_power = ams_delta_lcd_set_power, 8262306a36Sopenharmony_ci .get_contrast = ams_delta_lcd_get_contrast, 8362306a36Sopenharmony_ci .set_contrast = ams_delta_lcd_set_contrast, 8462306a36Sopenharmony_ci}; 8562306a36Sopenharmony_ci#endif 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci/* omapfb panel section */ 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic int ams_delta_panel_enable(struct lcd_panel *panel) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci gpiod_set_value(gpiod_ndisp, 1); 9362306a36Sopenharmony_ci gpiod_set_value(gpiod_vblen, 1); 9462306a36Sopenharmony_ci return 0; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic void ams_delta_panel_disable(struct lcd_panel *panel) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci gpiod_set_value(gpiod_vblen, 0); 10062306a36Sopenharmony_ci gpiod_set_value(gpiod_ndisp, 0); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic struct lcd_panel ams_delta_panel = { 10462306a36Sopenharmony_ci .name = "ams-delta", 10562306a36Sopenharmony_ci .config = 0, 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci .bpp = 12, 10862306a36Sopenharmony_ci .data_lines = 16, 10962306a36Sopenharmony_ci .x_res = 480, 11062306a36Sopenharmony_ci .y_res = 320, 11162306a36Sopenharmony_ci .pixel_clock = 4687, 11262306a36Sopenharmony_ci .hsw = 3, 11362306a36Sopenharmony_ci .hfp = 1, 11462306a36Sopenharmony_ci .hbp = 1, 11562306a36Sopenharmony_ci .vsw = 1, 11662306a36Sopenharmony_ci .vfp = 0, 11762306a36Sopenharmony_ci .vbp = 0, 11862306a36Sopenharmony_ci .pcd = 0, 11962306a36Sopenharmony_ci .acb = 37, 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci .enable = ams_delta_panel_enable, 12262306a36Sopenharmony_ci .disable = ams_delta_panel_disable, 12362306a36Sopenharmony_ci}; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/* platform driver section */ 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic int ams_delta_panel_probe(struct platform_device *pdev) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct lcd_device *lcd_device = NULL; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci gpiod_vblen = devm_gpiod_get(&pdev->dev, "vblen", GPIOD_OUT_LOW); 13362306a36Sopenharmony_ci if (IS_ERR(gpiod_vblen)) 13462306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, PTR_ERR(gpiod_vblen), 13562306a36Sopenharmony_ci "VBLEN GPIO request failed\n"); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci gpiod_ndisp = devm_gpiod_get(&pdev->dev, "ndisp", GPIOD_OUT_LOW); 13862306a36Sopenharmony_ci if (IS_ERR(gpiod_ndisp)) 13962306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, PTR_ERR(gpiod_ndisp), 14062306a36Sopenharmony_ci "NDISP GPIO request failed\n"); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci#ifdef CONFIG_LCD_CLASS_DEVICE 14362306a36Sopenharmony_ci lcd_device = lcd_device_register("omapfb", &pdev->dev, NULL, 14462306a36Sopenharmony_ci &ams_delta_lcd_ops); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (IS_ERR(lcd_device)) { 14762306a36Sopenharmony_ci int ret = PTR_ERR(lcd_device); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to register device\n"); 15062306a36Sopenharmony_ci return ret; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci platform_set_drvdata(pdev, lcd_device); 15462306a36Sopenharmony_ci lcd_device->props.max_contrast = AMS_DELTA_MAX_CONTRAST; 15562306a36Sopenharmony_ci#endif 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci ams_delta_lcd_set_contrast(lcd_device, AMS_DELTA_DEFAULT_CONTRAST); 15862306a36Sopenharmony_ci ams_delta_lcd_set_power(lcd_device, FB_BLANK_UNBLANK); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci omapfb_register_panel(&ams_delta_panel); 16162306a36Sopenharmony_ci return 0; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic struct platform_driver ams_delta_panel_driver = { 16562306a36Sopenharmony_ci .probe = ams_delta_panel_probe, 16662306a36Sopenharmony_ci .driver = { 16762306a36Sopenharmony_ci .name = "lcd_ams_delta", 16862306a36Sopenharmony_ci }, 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cimodule_platform_driver(ams_delta_panel_driver); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ciMODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>"); 17462306a36Sopenharmony_ciMODULE_DESCRIPTION("LCD panel support for the Amstrad E3 (Delta) videophone"); 17562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 176