0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/module.h>
0015 #include <linux/kernel.h>
0016 #include <linux/init.h>
0017 #include <linux/delay.h>
0018 #include <linux/gpio/consumer.h>
0019 #include <linux/fb.h>
0020 #include <linux/lcd.h>
0021 #include <linux/spi/spi.h>
0022 #include <linux/spi/corgi_lcd.h>
0023 #include <linux/slab.h>
0024 #include <asm/mach/sharpsl_param.h>
0025
0026 #define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL)
0027
0028
0029 #define RESCTL_ADRS 0x00
0030 #define PHACTRL_ADRS 0x01
0031 #define DUTYCTRL_ADRS 0x02
0032 #define POWERREG0_ADRS 0x03
0033 #define POWERREG1_ADRS 0x04
0034 #define GPOR3_ADRS 0x05
0035 #define PICTRL_ADRS 0x06
0036 #define POLCTRL_ADRS 0x07
0037
0038
0039 #define RESCTL_QVGA 0x01
0040 #define RESCTL_VGA 0x00
0041
0042 #define POWER1_VW_ON 0x01
0043 #define POWER1_GVSS_ON 0x02
0044 #define POWER1_VDD_ON 0x04
0045
0046 #define POWER1_VW_OFF 0x00
0047 #define POWER1_GVSS_OFF 0x00
0048 #define POWER1_VDD_OFF 0x00
0049
0050 #define POWER0_COM_DCLK 0x01
0051 #define POWER0_COM_DOUT 0x02
0052 #define POWER0_DAC_ON 0x04
0053 #define POWER0_COM_ON 0x08
0054 #define POWER0_VCC5_ON 0x10
0055
0056 #define POWER0_DAC_OFF 0x00
0057 #define POWER0_COM_OFF 0x00
0058 #define POWER0_VCC5_OFF 0x00
0059
0060 #define PICTRL_INIT_STATE 0x01
0061 #define PICTRL_INIOFF 0x02
0062 #define PICTRL_POWER_DOWN 0x04
0063 #define PICTRL_COM_SIGNAL_OFF 0x08
0064 #define PICTRL_DAC_SIGNAL_OFF 0x10
0065
0066 #define POLCTRL_SYNC_POL_FALL 0x01
0067 #define POLCTRL_EN_POL_FALL 0x02
0068 #define POLCTRL_DATA_POL_FALL 0x04
0069 #define POLCTRL_SYNC_ACT_H 0x08
0070 #define POLCTRL_EN_ACT_L 0x10
0071
0072 #define POLCTRL_SYNC_POL_RISE 0x00
0073 #define POLCTRL_EN_POL_RISE 0x00
0074 #define POLCTRL_DATA_POL_RISE 0x00
0075 #define POLCTRL_SYNC_ACT_L 0x00
0076 #define POLCTRL_EN_ACT_H 0x00
0077
0078 #define PHACTRL_PHASE_MANUAL 0x01
0079 #define DEFAULT_PHAD_QVGA (9)
0080 #define DEFAULT_COMADJ (125)
0081
0082 struct corgi_lcd {
0083 struct spi_device *spi_dev;
0084 struct lcd_device *lcd_dev;
0085 struct backlight_device *bl_dev;
0086
0087 int limit_mask;
0088 int intensity;
0089 int power;
0090 int mode;
0091 char buf[2];
0092
0093 struct gpio_desc *backlight_on;
0094 struct gpio_desc *backlight_cont;
0095
0096 void (*kick_battery)(void);
0097 };
0098
0099 static int corgi_ssp_lcdtg_send(struct corgi_lcd *lcd, int reg, uint8_t val);
0100
0101 static struct corgi_lcd *the_corgi_lcd;
0102 static unsigned long corgibl_flags;
0103 #define CORGIBL_SUSPENDED 0x01
0104 #define CORGIBL_BATTLOW 0x02
0105
0106
0107
0108
0109
0110 static void lcdtg_ssp_i2c_send(struct corgi_lcd *lcd, uint8_t data)
0111 {
0112 corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS, data);
0113 udelay(10);
0114 }
0115
0116 static void lcdtg_i2c_send_bit(struct corgi_lcd *lcd, uint8_t data)
0117 {
0118 lcdtg_ssp_i2c_send(lcd, data);
0119 lcdtg_ssp_i2c_send(lcd, data | POWER0_COM_DCLK);
0120 lcdtg_ssp_i2c_send(lcd, data);
0121 }
0122
0123 static void lcdtg_i2c_send_start(struct corgi_lcd *lcd, uint8_t base)
0124 {
0125 lcdtg_ssp_i2c_send(lcd, base | POWER0_COM_DCLK | POWER0_COM_DOUT);
0126 lcdtg_ssp_i2c_send(lcd, base | POWER0_COM_DCLK);
0127 lcdtg_ssp_i2c_send(lcd, base);
0128 }
0129
0130 static void lcdtg_i2c_send_stop(struct corgi_lcd *lcd, uint8_t base)
0131 {
0132 lcdtg_ssp_i2c_send(lcd, base);
0133 lcdtg_ssp_i2c_send(lcd, base | POWER0_COM_DCLK);
0134 lcdtg_ssp_i2c_send(lcd, base | POWER0_COM_DCLK | POWER0_COM_DOUT);
0135 }
0136
0137 static void lcdtg_i2c_send_byte(struct corgi_lcd *lcd,
0138 uint8_t base, uint8_t data)
0139 {
0140 int i;
0141
0142 for (i = 0; i < 8; i++) {
0143 if (data & 0x80)
0144 lcdtg_i2c_send_bit(lcd, base | POWER0_COM_DOUT);
0145 else
0146 lcdtg_i2c_send_bit(lcd, base);
0147 data <<= 1;
0148 }
0149 }
0150
0151 static void lcdtg_i2c_wait_ack(struct corgi_lcd *lcd, uint8_t base)
0152 {
0153 lcdtg_i2c_send_bit(lcd, base);
0154 }
0155
0156 static void lcdtg_set_common_voltage(struct corgi_lcd *lcd,
0157 uint8_t base_data, uint8_t data)
0158 {
0159
0160 lcdtg_i2c_send_start(lcd, base_data);
0161 lcdtg_i2c_send_byte(lcd, base_data, 0x9c);
0162 lcdtg_i2c_wait_ack(lcd, base_data);
0163 lcdtg_i2c_send_byte(lcd, base_data, 0x00);
0164 lcdtg_i2c_wait_ack(lcd, base_data);
0165 lcdtg_i2c_send_byte(lcd, base_data, data);
0166 lcdtg_i2c_wait_ack(lcd, base_data);
0167 lcdtg_i2c_send_stop(lcd, base_data);
0168 }
0169
0170 static int corgi_ssp_lcdtg_send(struct corgi_lcd *lcd, int adrs, uint8_t data)
0171 {
0172 struct spi_message msg;
0173 struct spi_transfer xfer = {
0174 .len = 1,
0175 .cs_change = 0,
0176 .tx_buf = lcd->buf,
0177 };
0178
0179 lcd->buf[0] = ((adrs & 0x07) << 5) | (data & 0x1f);
0180 spi_message_init(&msg);
0181 spi_message_add_tail(&xfer, &msg);
0182
0183 return spi_sync(lcd->spi_dev, &msg);
0184 }
0185
0186
0187 static void lcdtg_set_phadadj(struct corgi_lcd *lcd, int mode)
0188 {
0189 int adj;
0190
0191 switch (mode) {
0192 case CORGI_LCD_MODE_VGA:
0193
0194 adj = sharpsl_param.phadadj;
0195 adj = (adj < 0) ? PHACTRL_PHASE_MANUAL :
0196 PHACTRL_PHASE_MANUAL | ((adj & 0xf) << 1);
0197 break;
0198 case CORGI_LCD_MODE_QVGA:
0199 default:
0200
0201 adj = (DEFAULT_PHAD_QVGA << 1) | PHACTRL_PHASE_MANUAL;
0202 break;
0203 }
0204
0205 corgi_ssp_lcdtg_send(lcd, PHACTRL_ADRS, adj);
0206 }
0207
0208 static void corgi_lcd_power_on(struct corgi_lcd *lcd)
0209 {
0210 int comadj;
0211
0212
0213 corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS,
0214 PICTRL_POWER_DOWN | PICTRL_INIOFF |
0215 PICTRL_INIT_STATE | PICTRL_COM_SIGNAL_OFF |
0216 PICTRL_DAC_SIGNAL_OFF);
0217
0218 corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
0219 POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_OFF |
0220 POWER0_COM_OFF | POWER0_VCC5_OFF);
0221
0222 corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
0223 POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF);
0224
0225
0226 corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
0227 POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON);
0228 mdelay(3);
0229
0230
0231 corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
0232 POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON |
0233 POWER0_COM_OFF | POWER0_VCC5_OFF);
0234
0235
0236
0237 corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS,
0238 PICTRL_INIT_STATE | PICTRL_COM_SIGNAL_OFF);
0239
0240
0241 comadj = sharpsl_param.comadj;
0242 if (comadj < 0)
0243 comadj = DEFAULT_COMADJ;
0244
0245 lcdtg_set_common_voltage(lcd, POWER0_DAC_ON | POWER0_COM_OFF |
0246 POWER0_VCC5_OFF, comadj);
0247
0248
0249 corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
0250 POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON |
0251 POWER0_COM_OFF | POWER0_VCC5_ON);
0252
0253
0254 corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
0255 POWER1_VW_OFF | POWER1_GVSS_ON | POWER1_VDD_ON);
0256 mdelay(2);
0257
0258
0259 corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS, PICTRL_INIT_STATE);
0260
0261
0262 corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
0263 POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON |
0264 POWER0_COM_ON | POWER0_VCC5_ON);
0265
0266
0267 corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
0268 POWER1_VW_ON | POWER1_GVSS_ON | POWER1_VDD_ON);
0269
0270
0271 corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS, 0);
0272
0273
0274 lcdtg_set_phadadj(lcd, lcd->mode);
0275
0276
0277 corgi_ssp_lcdtg_send(lcd, POLCTRL_ADRS,
0278 POLCTRL_SYNC_POL_RISE | POLCTRL_EN_POL_RISE |
0279 POLCTRL_DATA_POL_RISE | POLCTRL_SYNC_ACT_L |
0280 POLCTRL_EN_ACT_H);
0281 udelay(1000);
0282
0283 switch (lcd->mode) {
0284 case CORGI_LCD_MODE_VGA:
0285 corgi_ssp_lcdtg_send(lcd, RESCTL_ADRS, RESCTL_VGA);
0286 break;
0287 case CORGI_LCD_MODE_QVGA:
0288 default:
0289 corgi_ssp_lcdtg_send(lcd, RESCTL_ADRS, RESCTL_QVGA);
0290 break;
0291 }
0292 }
0293
0294 static void corgi_lcd_power_off(struct corgi_lcd *lcd)
0295 {
0296
0297 msleep(34);
0298
0299
0300 corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
0301 POWER1_VW_OFF | POWER1_GVSS_ON | POWER1_VDD_ON);
0302
0303
0304 corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS, PICTRL_COM_SIGNAL_OFF);
0305 corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
0306 POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_ON);
0307
0308
0309 lcdtg_set_common_voltage(lcd, POWER0_DAC_ON | POWER0_COM_OFF |
0310 POWER0_VCC5_ON, 0);
0311
0312
0313 corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
0314 POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON);
0315
0316
0317 corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
0318 POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_OFF);
0319
0320
0321 corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS,
0322 PICTRL_INIOFF | PICTRL_DAC_SIGNAL_OFF |
0323 PICTRL_POWER_DOWN | PICTRL_COM_SIGNAL_OFF);
0324
0325
0326 corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
0327 POWER0_DAC_OFF | POWER0_COM_OFF | POWER0_VCC5_OFF);
0328
0329
0330 corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
0331 POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF);
0332 }
0333
0334 static int corgi_lcd_set_mode(struct lcd_device *ld, struct fb_videomode *m)
0335 {
0336 struct corgi_lcd *lcd = lcd_get_data(ld);
0337 int mode = CORGI_LCD_MODE_QVGA;
0338
0339 if (m->xres == 640 || m->xres == 480)
0340 mode = CORGI_LCD_MODE_VGA;
0341
0342 if (lcd->mode == mode)
0343 return 0;
0344
0345 lcdtg_set_phadadj(lcd, mode);
0346
0347 switch (mode) {
0348 case CORGI_LCD_MODE_VGA:
0349 corgi_ssp_lcdtg_send(lcd, RESCTL_ADRS, RESCTL_VGA);
0350 break;
0351 case CORGI_LCD_MODE_QVGA:
0352 default:
0353 corgi_ssp_lcdtg_send(lcd, RESCTL_ADRS, RESCTL_QVGA);
0354 break;
0355 }
0356
0357 lcd->mode = mode;
0358 return 0;
0359 }
0360
0361 static int corgi_lcd_set_power(struct lcd_device *ld, int power)
0362 {
0363 struct corgi_lcd *lcd = lcd_get_data(ld);
0364
0365 if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
0366 corgi_lcd_power_on(lcd);
0367
0368 if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power))
0369 corgi_lcd_power_off(lcd);
0370
0371 lcd->power = power;
0372 return 0;
0373 }
0374
0375 static int corgi_lcd_get_power(struct lcd_device *ld)
0376 {
0377 struct corgi_lcd *lcd = lcd_get_data(ld);
0378
0379 return lcd->power;
0380 }
0381
0382 static struct lcd_ops corgi_lcd_ops = {
0383 .get_power = corgi_lcd_get_power,
0384 .set_power = corgi_lcd_set_power,
0385 .set_mode = corgi_lcd_set_mode,
0386 };
0387
0388 static int corgi_bl_get_intensity(struct backlight_device *bd)
0389 {
0390 struct corgi_lcd *lcd = bl_get_data(bd);
0391
0392 return lcd->intensity;
0393 }
0394
0395 static int corgi_bl_set_intensity(struct corgi_lcd *lcd, int intensity)
0396 {
0397 int cont;
0398
0399 if (intensity > 0x10)
0400 intensity += 0x10;
0401
0402 corgi_ssp_lcdtg_send(lcd, DUTYCTRL_ADRS, intensity);
0403
0404
0405 cont = !!(intensity & 0x20);
0406
0407 if (lcd->backlight_cont)
0408 gpiod_set_value_cansleep(lcd->backlight_cont, cont);
0409
0410 if (lcd->backlight_on)
0411 gpiod_set_value_cansleep(lcd->backlight_on, intensity);
0412
0413 if (lcd->kick_battery)
0414 lcd->kick_battery();
0415
0416 lcd->intensity = intensity;
0417 return 0;
0418 }
0419
0420 static int corgi_bl_update_status(struct backlight_device *bd)
0421 {
0422 struct corgi_lcd *lcd = bl_get_data(bd);
0423 int intensity = backlight_get_brightness(bd);
0424
0425 if (corgibl_flags & CORGIBL_SUSPENDED)
0426 intensity = 0;
0427
0428 if ((corgibl_flags & CORGIBL_BATTLOW) && intensity > lcd->limit_mask)
0429 intensity = lcd->limit_mask;
0430
0431 return corgi_bl_set_intensity(lcd, intensity);
0432 }
0433
0434 void corgi_lcd_limit_intensity(int limit)
0435 {
0436 if (limit)
0437 corgibl_flags |= CORGIBL_BATTLOW;
0438 else
0439 corgibl_flags &= ~CORGIBL_BATTLOW;
0440
0441 backlight_update_status(the_corgi_lcd->bl_dev);
0442 }
0443 EXPORT_SYMBOL(corgi_lcd_limit_intensity);
0444
0445 static const struct backlight_ops corgi_bl_ops = {
0446 .get_brightness = corgi_bl_get_intensity,
0447 .update_status = corgi_bl_update_status,
0448 };
0449
0450 #ifdef CONFIG_PM_SLEEP
0451 static int corgi_lcd_suspend(struct device *dev)
0452 {
0453 struct corgi_lcd *lcd = dev_get_drvdata(dev);
0454
0455 corgibl_flags |= CORGIBL_SUSPENDED;
0456 corgi_bl_set_intensity(lcd, 0);
0457 corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_POWERDOWN);
0458 return 0;
0459 }
0460
0461 static int corgi_lcd_resume(struct device *dev)
0462 {
0463 struct corgi_lcd *lcd = dev_get_drvdata(dev);
0464
0465 corgibl_flags &= ~CORGIBL_SUSPENDED;
0466 corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_UNBLANK);
0467 backlight_update_status(lcd->bl_dev);
0468 return 0;
0469 }
0470 #endif
0471
0472 static SIMPLE_DEV_PM_OPS(corgi_lcd_pm_ops, corgi_lcd_suspend, corgi_lcd_resume);
0473
0474 static int setup_gpio_backlight(struct corgi_lcd *lcd,
0475 struct corgi_lcd_platform_data *pdata)
0476 {
0477 struct spi_device *spi = lcd->spi_dev;
0478
0479 lcd->backlight_on = devm_gpiod_get_optional(&spi->dev,
0480 "BL_ON", GPIOD_OUT_LOW);
0481 if (IS_ERR(lcd->backlight_on))
0482 return PTR_ERR(lcd->backlight_on);
0483
0484 lcd->backlight_cont = devm_gpiod_get_optional(&spi->dev, "BL_CONT",
0485 GPIOD_OUT_LOW);
0486 if (IS_ERR(lcd->backlight_cont))
0487 return PTR_ERR(lcd->backlight_cont);
0488
0489 return 0;
0490 }
0491
0492 static int corgi_lcd_probe(struct spi_device *spi)
0493 {
0494 struct backlight_properties props;
0495 struct corgi_lcd_platform_data *pdata = dev_get_platdata(&spi->dev);
0496 struct corgi_lcd *lcd;
0497 int ret = 0;
0498
0499 if (pdata == NULL) {
0500 dev_err(&spi->dev, "platform data not available\n");
0501 return -EINVAL;
0502 }
0503
0504 lcd = devm_kzalloc(&spi->dev, sizeof(struct corgi_lcd), GFP_KERNEL);
0505 if (!lcd)
0506 return -ENOMEM;
0507
0508 lcd->spi_dev = spi;
0509
0510 lcd->lcd_dev = devm_lcd_device_register(&spi->dev, "corgi_lcd",
0511 &spi->dev, lcd, &corgi_lcd_ops);
0512 if (IS_ERR(lcd->lcd_dev))
0513 return PTR_ERR(lcd->lcd_dev);
0514
0515 lcd->power = FB_BLANK_POWERDOWN;
0516 lcd->mode = (pdata) ? pdata->init_mode : CORGI_LCD_MODE_VGA;
0517
0518 memset(&props, 0, sizeof(struct backlight_properties));
0519 props.type = BACKLIGHT_RAW;
0520 props.max_brightness = pdata->max_intensity;
0521 lcd->bl_dev = devm_backlight_device_register(&spi->dev, "corgi_bl",
0522 &spi->dev, lcd, &corgi_bl_ops,
0523 &props);
0524 if (IS_ERR(lcd->bl_dev))
0525 return PTR_ERR(lcd->bl_dev);
0526
0527 lcd->bl_dev->props.brightness = pdata->default_intensity;
0528 lcd->bl_dev->props.power = FB_BLANK_UNBLANK;
0529
0530 ret = setup_gpio_backlight(lcd, pdata);
0531 if (ret)
0532 return ret;
0533
0534 lcd->kick_battery = pdata->kick_battery;
0535
0536 spi_set_drvdata(spi, lcd);
0537 corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_UNBLANK);
0538 backlight_update_status(lcd->bl_dev);
0539
0540 lcd->limit_mask = pdata->limit_mask;
0541 the_corgi_lcd = lcd;
0542 return 0;
0543 }
0544
0545 static void corgi_lcd_remove(struct spi_device *spi)
0546 {
0547 struct corgi_lcd *lcd = spi_get_drvdata(spi);
0548
0549 lcd->bl_dev->props.power = FB_BLANK_UNBLANK;
0550 lcd->bl_dev->props.brightness = 0;
0551 backlight_update_status(lcd->bl_dev);
0552 corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_POWERDOWN);
0553 }
0554
0555 static struct spi_driver corgi_lcd_driver = {
0556 .driver = {
0557 .name = "corgi-lcd",
0558 .pm = &corgi_lcd_pm_ops,
0559 },
0560 .probe = corgi_lcd_probe,
0561 .remove = corgi_lcd_remove,
0562 };
0563
0564 module_spi_driver(corgi_lcd_driver);
0565
0566 MODULE_DESCRIPTION("LCD and backlight driver for SHARP C7x0/Cxx00");
0567 MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>");
0568 MODULE_LICENSE("GPL");
0569 MODULE_ALIAS("spi:corgi-lcd");