Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  LCD / Backlight control code for Sharp SL-6000x (tosa)
0004  *
0005  *  Copyright (c) 2005      Dirk Opfer
0006  *  Copyright (c) 2007,2008 Dmitry Baryshkov
0007  */
0008 
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <linux/device.h>
0012 #include <linux/spi/spi.h>
0013 #include <linux/i2c.h>
0014 #include <linux/slab.h>
0015 #include <linux/gpio/consumer.h>
0016 #include <linux/delay.h>
0017 #include <linux/lcd.h>
0018 #include <linux/fb.h>
0019 
0020 #include <asm/mach/sharpsl_param.h>
0021 
0022 #include "tosa_bl.h"
0023 
0024 #define POWER_IS_ON(pwr)    ((pwr) <= FB_BLANK_NORMAL)
0025 
0026 #define TG_REG0_VQV 0x0001
0027 #define TG_REG0_COLOR   0x0002
0028 #define TG_REG0_UD  0x0004
0029 #define TG_REG0_LR  0x0008
0030 
0031 /*
0032  * Timing Generator
0033  */
0034 #define TG_PNLCTL   0x00
0035 #define TG_TPOSCTL  0x01
0036 #define TG_DUTYCTL  0x02
0037 #define TG_GPOSR    0x03
0038 #define TG_GPODR1   0x04
0039 #define TG_GPODR2   0x05
0040 #define TG_PINICTL  0x06
0041 #define TG_HPOSCTL  0x07
0042 
0043 
0044 #define DAC_BASE    0x4e
0045 
0046 struct tosa_lcd_data {
0047     struct spi_device *spi;
0048     struct lcd_device *lcd;
0049     struct i2c_client *i2c;
0050     struct gpio_desc *gpiod_tg;
0051 
0052     int lcd_power;
0053     bool is_vga;
0054 };
0055 
0056 static int tosa_tg_send(struct spi_device *spi, int adrs, uint8_t data)
0057 {
0058     u8 buf[1];
0059     struct spi_message msg;
0060     struct spi_transfer xfer = {
0061         .len        = 1,
0062         .cs_change  = 0,
0063         .tx_buf     = buf,
0064     };
0065 
0066     buf[0] = ((adrs & 0x07) << 5) | (data & 0x1f);
0067     spi_message_init(&msg);
0068     spi_message_add_tail(&xfer, &msg);
0069 
0070     return spi_sync(spi, &msg);
0071 }
0072 
0073 int tosa_bl_enable(struct spi_device *spi, int enable)
0074 {
0075     /* bl_enable GP04=1 otherwise GP04=0*/
0076     return tosa_tg_send(spi, TG_GPODR2, enable ? 0x01 : 0x00);
0077 }
0078 EXPORT_SYMBOL(tosa_bl_enable);
0079 
0080 static void tosa_lcd_tg_init(struct tosa_lcd_data *data)
0081 {
0082     /* TG on */
0083     gpiod_set_value(data->gpiod_tg, 0);
0084 
0085     mdelay(60);
0086 
0087     /* delayed 0clk TCTL signal for VGA */
0088     tosa_tg_send(data->spi, TG_TPOSCTL, 0x00);
0089     /* GPOS0=powercontrol, GPOS1=GPIO, GPOS2=TCTL */
0090     tosa_tg_send(data->spi, TG_GPOSR, 0x02);
0091 }
0092 
0093 static void tosa_lcd_tg_on(struct tosa_lcd_data *data)
0094 {
0095     struct spi_device *spi = data->spi;
0096     int value = TG_REG0_COLOR | TG_REG0_UD | TG_REG0_LR;
0097 
0098     if (data->is_vga)
0099         value |= TG_REG0_VQV;
0100 
0101     tosa_tg_send(spi, TG_PNLCTL, value);
0102 
0103     /* TG LCD pannel power up */
0104     tosa_tg_send(spi, TG_PINICTL, 0x4);
0105     mdelay(50);
0106 
0107     /* TG LCD GVSS */
0108     tosa_tg_send(spi, TG_PINICTL, 0x0);
0109 
0110     if (IS_ERR_OR_NULL(data->i2c)) {
0111         /*
0112          * after the pannel is powered up the first time,
0113          * we can access the i2c bus so probe for the DAC
0114          */
0115         struct i2c_adapter *adap = i2c_get_adapter(0);
0116         struct i2c_board_info info = {
0117             .dev_name = "tosa-bl",
0118             .type   = "tosa-bl",
0119             .addr   = DAC_BASE,
0120             .platform_data = data->spi,
0121         };
0122         data->i2c = i2c_new_client_device(adap, &info);
0123     }
0124 }
0125 
0126 static void tosa_lcd_tg_off(struct tosa_lcd_data *data)
0127 {
0128     struct spi_device *spi = data->spi;
0129 
0130     /* TG LCD VHSA off */
0131     tosa_tg_send(spi, TG_PINICTL, 0x4);
0132     mdelay(50);
0133 
0134     /* TG LCD signal off */
0135     tosa_tg_send(spi, TG_PINICTL, 0x6);
0136     mdelay(50);
0137 
0138     /* TG Off */
0139     gpiod_set_value(data->gpiod_tg, 1);
0140     mdelay(100);
0141 }
0142 
0143 int tosa_lcd_set_power(struct lcd_device *lcd, int power)
0144 {
0145     struct tosa_lcd_data *data = lcd_get_data(lcd);
0146 
0147     if (POWER_IS_ON(power) && !POWER_IS_ON(data->lcd_power))
0148         tosa_lcd_tg_on(data);
0149 
0150     if (!POWER_IS_ON(power) && POWER_IS_ON(data->lcd_power))
0151         tosa_lcd_tg_off(data);
0152 
0153     data->lcd_power = power;
0154     return 0;
0155 }
0156 
0157 static int tosa_lcd_get_power(struct lcd_device *lcd)
0158 {
0159     struct tosa_lcd_data *data = lcd_get_data(lcd);
0160 
0161     return data->lcd_power;
0162 }
0163 
0164 static int tosa_lcd_set_mode(struct lcd_device *lcd, struct fb_videomode *mode)
0165 {
0166     struct tosa_lcd_data *data = lcd_get_data(lcd);
0167 
0168     if (mode->xres == 320 || mode->yres == 320)
0169         data->is_vga = false;
0170     else
0171         data->is_vga = true;
0172 
0173     if (POWER_IS_ON(data->lcd_power))
0174         tosa_lcd_tg_on(data);
0175 
0176     return 0;
0177 }
0178 
0179 static struct lcd_ops tosa_lcd_ops = {
0180     .set_power = tosa_lcd_set_power,
0181     .get_power = tosa_lcd_get_power,
0182     .set_mode = tosa_lcd_set_mode,
0183 };
0184 
0185 static int tosa_lcd_probe(struct spi_device *spi)
0186 {
0187     int ret;
0188     struct tosa_lcd_data *data;
0189 
0190     data = devm_kzalloc(&spi->dev, sizeof(struct tosa_lcd_data),
0191                 GFP_KERNEL);
0192     if (!data)
0193         return -ENOMEM;
0194 
0195     data->is_vga = true; /* default to VGA mode */
0196 
0197     /*
0198      * bits_per_word cannot be configured in platform data
0199      */
0200     spi->bits_per_word = 8;
0201 
0202     ret = spi_setup(spi);
0203     if (ret < 0)
0204         return ret;
0205 
0206     data->spi = spi;
0207     spi_set_drvdata(spi, data);
0208 
0209     data->gpiod_tg = devm_gpiod_get(&spi->dev, "tg #pwr", GPIOD_OUT_LOW);
0210     if (IS_ERR(data->gpiod_tg))
0211         return PTR_ERR(data->gpiod_tg);
0212 
0213     mdelay(60);
0214 
0215     tosa_lcd_tg_init(data);
0216 
0217     tosa_lcd_tg_on(data);
0218 
0219     data->lcd = devm_lcd_device_register(&spi->dev, "tosa-lcd", &spi->dev,
0220                     data, &tosa_lcd_ops);
0221 
0222     if (IS_ERR(data->lcd)) {
0223         ret = PTR_ERR(data->lcd);
0224         data->lcd = NULL;
0225         goto err_register;
0226     }
0227 
0228     return 0;
0229 
0230 err_register:
0231     tosa_lcd_tg_off(data);
0232     return ret;
0233 }
0234 
0235 static void tosa_lcd_remove(struct spi_device *spi)
0236 {
0237     struct tosa_lcd_data *data = spi_get_drvdata(spi);
0238 
0239     i2c_unregister_device(data->i2c);
0240 
0241     tosa_lcd_tg_off(data);
0242 }
0243 
0244 #ifdef CONFIG_PM_SLEEP
0245 static int tosa_lcd_suspend(struct device *dev)
0246 {
0247     struct tosa_lcd_data *data = dev_get_drvdata(dev);
0248 
0249     tosa_lcd_tg_off(data);
0250 
0251     return 0;
0252 }
0253 
0254 static int tosa_lcd_resume(struct device *dev)
0255 {
0256     struct tosa_lcd_data *data = dev_get_drvdata(dev);
0257 
0258     tosa_lcd_tg_init(data);
0259     if (POWER_IS_ON(data->lcd_power))
0260         tosa_lcd_tg_on(data);
0261     else
0262         tosa_lcd_tg_off(data);
0263 
0264     return 0;
0265 }
0266 #endif
0267 
0268 static SIMPLE_DEV_PM_OPS(tosa_lcd_pm_ops, tosa_lcd_suspend, tosa_lcd_resume);
0269 
0270 static struct spi_driver tosa_lcd_driver = {
0271     .driver = {
0272         .name       = "tosa-lcd",
0273         .pm     = &tosa_lcd_pm_ops,
0274     },
0275     .probe      = tosa_lcd_probe,
0276     .remove     = tosa_lcd_remove,
0277 };
0278 
0279 module_spi_driver(tosa_lcd_driver);
0280 
0281 MODULE_AUTHOR("Dmitry Baryshkov");
0282 MODULE_LICENSE("GPL v2");
0283 MODULE_DESCRIPTION("LCD/Backlight control for Sharp SL-6000 PDA");
0284 MODULE_ALIAS("spi:tosa-lcd");