0001
0002
0003
0004
0005
0006
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
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
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
0083 gpiod_set_value(data->gpiod_tg, 0);
0084
0085 mdelay(60);
0086
0087
0088 tosa_tg_send(data->spi, TG_TPOSCTL, 0x00);
0089
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
0104 tosa_tg_send(spi, TG_PINICTL, 0x4);
0105 mdelay(50);
0106
0107
0108 tosa_tg_send(spi, TG_PINICTL, 0x0);
0109
0110 if (IS_ERR_OR_NULL(data->i2c)) {
0111
0112
0113
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
0131 tosa_tg_send(spi, TG_PINICTL, 0x4);
0132 mdelay(50);
0133
0134
0135 tosa_tg_send(spi, TG_PINICTL, 0x6);
0136 mdelay(50);
0137
0138
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;
0196
0197
0198
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");