| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973 |
- From c1de95e3a608c48b5576e32181480930d9106ac4 Mon Sep 17 00:00:00 2001
- From: Alison Wang <[email protected]>
- Date: Thu, 4 Aug 2011 09:59:44 +0800
- Subject: [PATCH 18/52] Add SSD1289 TFT LCD framebuffer driver on TWR-MCF5441X
- Add SSD1289 TFT LCD framebuffer driver on TWR-MCF5441X. Flexbus and spi
- interfaces are both supported.
- Signed-off-by: Alison Wang <[email protected]>
- ---
- arch/m68k/coldfire/m5441x/config.c | 1 +
- arch/m68k/coldfire/m5441x/devices.c | 1 +
- arch/m68k/include/asm/fsl-ssd1289-fb.h | 93 ++++
- drivers/video/Kconfig | 24 +
- drivers/video/Makefile | 1 +
- drivers/video/fsl-ssd1289-fb.c | 791 ++++++++++++++++++++++++++++++++
- 6 files changed, 911 insertions(+), 0 deletions(-)
- create mode 100644 arch/m68k/include/asm/fsl-ssd1289-fb.h
- create mode 100644 drivers/video/fsl-ssd1289-fb.c
- --- a/arch/m68k/coldfire/m5441x/config.c
- +++ b/arch/m68k/coldfire/m5441x/config.c
- @@ -45,6 +45,7 @@
- #include <asm/mcf5441x_fbcs.h>
- #include <asm/mcf5441x_dtim.h>
- #include <asm/mcf5441x_xbs.h>
- +#include <asm/fsl-ssd1289-fb.h>
-
- extern int get_irq_list(struct seq_file *p, void *v);
- extern char _text, _end;
- --- a/arch/m68k/coldfire/m5441x/devices.c
- +++ b/arch/m68k/coldfire/m5441x/devices.c
- @@ -33,6 +33,7 @@
- #include <asm/mcfqspi.h>
- #include <asm/mcfdspi.h>
- #include <asm/cf_io.h>
- +#include <asm/fsl-ssd1289-fb.h>
-
- /*
- * I2C: only support i2c0 module on m5441x platform
- --- /dev/null
- +++ b/arch/m68k/include/asm/fsl-ssd1289-fb.h
- @@ -0,0 +1,93 @@
- +/*
- + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
- + *
- + * Freescale MCF54418 SSD1289 TFT LCD framebuffer driver
- + *
- + * This program is free software; you can redistribute it and/or modify it
- + * under the terms of the GNU General Public License as published by the
- + * Free Software Foundation; either version 2 of the License, or (at your
- + * option) any later version.
- + */
- +
- +#ifndef __FSL_SSD1289_FB_H__
- +#define __FSL_SSD1289_FB_H__
- +
- +#define SSD1289_REG_OSCILLATION 0x00
- +#define SSD1289_REG_DRIVER_OUT_CTRL 0x01
- +#define SSD1289_REG_LCD_DRIVE_AC 0x02
- +#define SSD1289_REG_POWER_CTRL_1 0x03
- +#define SSD1289_REG_COMPARE_1 0x05
- +#define SSD1289_REG_COMPARE_2 0x06
- +#define SSD1289_REG_DISPLAY_CTRL 0x07
- +#define SSD1289_REG_FRAME_CYCLE 0x0b
- +#define SSD1289_REG_POWER_CTRL_2 0x0c
- +#define SSD1289_REG_POWER_CTRL_3 0x0d
- +#define SSD1289_REG_POWER_CTRL_4 0x0e
- +#define SSD1289_REG_GATE_SCAN_START 0x0f
- +#define SSD1289_REG_SLEEP_MODE 0x10
- +#define SSD1289_REG_ENTRY_MODE 0x11
- +#define SSD1289_REG_OPT_SPEED_3 0x12
- +#define SSD1289_REG_H_PORCH 0x16
- +#define SSD1289_REG_V_PORCH 0x17
- +#define SSD1289_REG_POWER_CTRL_5 0x1e
- +#define SSD1289_REG_GDDRAM_DATA 0x22
- +#define SSD1289_REG_WR_DATA_MASK_1 0x23
- +#define SSD1289_REG_WR_DATA_MASK_2 0x24
- +#define SSD1289_REG_FRAME_FREQUENCY 0x25
- +#define SSD1289_REG_OPT_SPEED_1 0x28
- +#define SSD1289_REG_OPT_SPEED_2 0x2f
- +#define SSD1289_REG_GAMMA_CTRL_1 0x30
- +#define SSD1289_REG_GAMMA_CTRL_2 0x31
- +#define SSD1289_REG_GAMMA_CTRL_3 0x32
- +#define SSD1289_REG_GAMMA_CTRL_4 0x33
- +#define SSD1289_REG_GAMMA_CTRL_5 0x34
- +#define SSD1289_REG_GAMMA_CTRL_6 0x35
- +#define SSD1289_REG_GAMMA_CTRL_7 0x36
- +#define SSD1289_REG_GAMMA_CTRL_8 0x37
- +#define SSD1289_REG_GAMMA_CTRL_9 0x3a
- +#define SSD1289_REG_GAMMA_CTRL_10 0x3b
- +#define SSD1289_REG_V_SCROLL_CTRL_1 0x41
- +#define SSD1289_REG_V_SCROLL_CTRL_2 0x42
- +#define SSD1289_REG_H_RAM_ADR_POS 0x44
- +#define SSD1289_REG_V_RAM_ADR_START 0x45
- +#define SSD1289_REG_V_RAM_ADR_END 0x46
- +#define SSD1289_REG_FIRST_WIN_START 0x48
- +#define SSD1289_REG_FIRST_WIN_END 0x49
- +#define SSD1289_REG_SECND_WIN_START 0x4a
- +#define SSD1289_REG_SECND_WIN_END 0x4b
- +#define SSD1289_REG_GDDRAM_X_ADDR 0x4e
- +#define SSD1289_REG_GDDRAM_Y_ADDR 0x4f
- +
- +struct ssd1289 {
- + void __iomem *cmd;
- + void __iomem *data;
- +} __packed;
- +
- +struct fsl_ssd1289_fb_info {
- + struct device *dev;
- + struct ssd1289 ssd1289_reg;
- + int openflag;
- + struct spi_device *spidev;
- +
- + struct task_struct *task;
- + unsigned long pseudo_palette[16];
- +};
- +
- +/* LCD description */
- +struct fsl_ssd1289_fb_display {
- + /* Screen size */
- + unsigned short width;
- + unsigned short height;
- +
- + /* Screen info */
- + unsigned short xres;
- + unsigned short yres;
- + unsigned short bpp;
- +};
- +
- +#define FLEXBUS_LCD_CMD_ADDRESS 0xc0000000
- +#define FLEXBUS_LCD_DATA_ADDRESS 0xc0010000
- +
- +#define SPI_LCD_BLOCK_SIZE 4096
- +#define SPI_LCD_BLOCK_HALF_SIZE 2048
- +#endif
- --- a/drivers/video/Kconfig
- +++ b/drivers/video/Kconfig
- @@ -1980,6 +1980,30 @@ config FB_FSL_DIU
- ---help---
- Framebuffer driver for the Freescale SoC DIU
-
- +config FB_FSL_SSD1289
- + tristate "SSD1289 TFT LCD (Freescale MCF54418)"
- + depends on FB && M5441X
- + select FB_CFB_FILLRECT
- + select FB_CFB_COPYAREA
- + select FB_CFB_IMAGEBLIT
- + select FB_SYS_FOPS
- + ---help---
- + This is the framebuffer device driver for a Solomon Systech 240RGBx320
- + TFT LCD SSD1289.
- +
- +choice
- + prompt "SSD1289 LCD Controller Interface mode"
- + depends on FB_FSL_SSD1289
- +
- +config SSD1289_FLEXBUS_MODE
- + bool "SSD1289 LCD Controller Flexbus Interface mode"
- +
- +config SSD1289_SPI_MODE
- + bool "SSD1289 LCD Controller SPI Interface mode"
- + depends on SPI_DSPI && DSPI0
- +
- +endchoice
- +
- config FB_W100
- tristate "W100 frame buffer support"
- depends on FB && ARCH_PXA
- --- a/drivers/video/Makefile
- +++ b/drivers/video/Makefile
- @@ -120,6 +120,7 @@ obj-$(CONFIG_FB_IMX) += imx
- obj-$(CONFIG_FB_S3C) += s3c-fb.o
- obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
- obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o
- +obj-$(CONFIG_FB_FSL_SSD1289) += fsl-ssd1289-fb.o
- obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o
- obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/
- obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/
- --- /dev/null
- +++ b/drivers/video/fsl-ssd1289-fb.c
- @@ -0,0 +1,791 @@
- +/*
- + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
- + *
- + * Freescale MCF54418 SSD1289 TFT LCD framebuffer driver
- + *
- + * Author: Alison Wang <[email protected]>
- + * Jason Jin <[email protected]>
- + *
- + * This program is free software; you can redistribute it and/or modify it
- + * under the terms of the GNU General Public License as published by the
- + * Free Software Foundation; either version 2 of the License, or (at your
- + * option) any later version.
- + */
- +
- +#include <linux/module.h>
- +#include <linux/kernel.h>
- +#include <linux/errno.h>
- +#include <linux/string.h>
- +#include <linux/mm.h>
- +#include <linux/slab.h>
- +#include <linux/delay.h>
- +#include <linux/fb.h>
- +#include <linux/init.h>
- +#include <linux/interrupt.h>
- +#include <linux/platform_device.h>
- +#include <linux/dma-mapping.h>
- +#include <linux/clk.h>
- +#include <linux/uaccess.h>
- +#include <linux/timer.h>
- +#include <linux/kthread.h>
- +#include <linux/spi/spi.h>
- +
- +#include <asm/mcf5441x_fbcs.h>
- +#include <asm/mcf5441x_dspi.h>
- +#include <asm/fsl-ssd1289-fb.h>
- +#include <asm/mcf5441x_gpio.h>
- +#include <asm/mcf5441x_ccm.h>
- +#include <asm/mcf_edma.h>
- +
- +#ifdef CONFIG_PM
- +#include <linux/pm.h>
- +#endif
- +
- +#if defined(CONFIG_SSD1289_SPI_MODE)
- +unsigned char spi_block_buffer[SPI_LCD_BLOCK_SIZE];
- +
- +static int ssd1289_spi_writeblock(struct fb_info *info,
- + unsigned char *daddr, int flag)
- +{
- + struct fsl_ssd1289_fb_info *fbinfo = info->par;
- + struct spi_device *devtmp;
- + int i;
- +
- + for (i = 0; i < SPI_LCD_BLOCK_SIZE; i++) {
- + if (i % 2 == 0)
- + spi_block_buffer[i] = 0x01;
- + else if (flag == 1)
- + spi_block_buffer[i] = *(daddr + (i >> 1));
- + else if (flag == 0)
- + spi_block_buffer[i] = 0;
- + }
- +
- + devtmp = fbinfo->spidev;
- + spi_write(devtmp, (const unsigned char *)spi_block_buffer,
- + SPI_LCD_BLOCK_SIZE);
- + return 0;
- +}
- +
- +static int ssd1289_spi_write(struct fb_info *info,
- + unsigned short value, unsigned int flag)
- +{
- + struct fsl_ssd1289_fb_info *fbinfo = info->par;
- + struct spi_device *devtmp;
- + unsigned short tmpl;
- + unsigned short tmph;
- +
- + devtmp = fbinfo->spidev;
- + if (flag == 1) {
- + /* D/C = 1 */
- + tmph = ((value >> 8) & 0xff) + 0x0100;
- + tmpl = (value & 0xff) + 0x0100;
- + spi_write(devtmp, (const u8 *)&tmph, sizeof(tmph));
- + spi_write(devtmp, (const u8 *)&tmpl, sizeof(tmpl));
- + } else {
- + /* D/C = 0 */
- + tmpl = (value & 0xff);
- + spi_write(devtmp, (const u8 *)&tmpl, sizeof(tmpl));
- + }
- + return 0;
- +}
- +#elif defined(CONFIG_SSD1289_FLEXBUS_MODE)
- +static int ssd1289_flexbus_write(struct fb_info *info, unsigned short value,
- + unsigned int flag)
- +{
- + struct fsl_ssd1289_fb_info *fbinfo = info->par;
- + void __iomem *cmd_addr, *data_addr;
- +
- + cmd_addr = fbinfo->ssd1289_reg.cmd;
- + data_addr = fbinfo->ssd1289_reg.data;
- +
- + if (flag == 0)
- + out_be16(cmd_addr, value);
- + else
- + out_be16(data_addr, value);
- +
- + return 0;
- +}
- +#endif
- +
- +static int ssd1289_write(struct fb_info *info, unsigned short value,
- + unsigned int flag)
- +{
- +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
- + ssd1289_flexbus_write(info, value, flag);
- +#elif defined(CONFIG_SSD1289_SPI_MODE)
- + ssd1289_spi_write(info, value, flag);
- +#endif
- + return 0;
- +}
- +
- +static void fsl_ssd1289_enable_lcd(struct fb_info *info)
- +{
- + int i;
- +
- +#if defined(CONFIG_SSD1289_SPI_MODE)
- + int count;
- +#elif defined(CONFIG_SSD1289_FLEXBUS_MODE)
- + /* GPIO configuration */
- + MCF_GPIO_PAR_BE = MCF_GPIO_PAR_BE_BE3_FB_A1 | MCF_GPIO_PAR_BE_BE2_FB_A0
- + | MCF_GPIO_PAR_BE_BE1_BE1 | MCF_GPIO_PAR_BE_BE0_BE0;
- + MCF_GPIO_PAR_CS |= MCF_GPIO_PAR_CS_CS0_CS0;
- +#endif
- +
- + ssd1289_write(info, SSD1289_REG_DISPLAY_CTRL, 0);
- + ssd1289_write(info, 0x0200, 1);
- +
- + ssd1289_write(info, SSD1289_REG_OSCILLATION, 0);
- + ssd1289_write(info, 0x0000, 1);
- +
- + mdelay(100);
- +
- + /* turn on the oscillator */
- + ssd1289_write(info, SSD1289_REG_OSCILLATION, 0);
- + ssd1289_write(info, 0x0001, 1);
- +
- + mdelay(100);
- + /* power control 1 */
- + ssd1289_write(info, SSD1289_REG_POWER_CTRL_1, 0);
- + ssd1289_write(info, 0xaeac, 1);
- +
- + /* power control 2 */
- + ssd1289_write(info, SSD1289_REG_POWER_CTRL_2, 0);
- + ssd1289_write(info, 0x0007, 1);
- +
- + /* power control 3 */
- + ssd1289_write(info, SSD1289_REG_POWER_CTRL_3, 0);
- + ssd1289_write(info, 0x000f, 1);
- +
- + /* power control 4 */
- + ssd1289_write(info, SSD1289_REG_POWER_CTRL_4, 0);
- + ssd1289_write(info, 0x2900, 1);
- +
- + /* power control 5 */
- + ssd1289_write(info, SSD1289_REG_POWER_CTRL_5, 0);
- + ssd1289_write(info, 0x00b3, 1);
- +
- + mdelay(15);
- + /* driver output control */
- + ssd1289_write(info, SSD1289_REG_DRIVER_OUT_CTRL, 0);
- + ssd1289_write(info, 0x2b3f, 1);
- +
- + /* lcd-driving-waveform control */
- + ssd1289_write(info, SSD1289_REG_LCD_DRIVE_AC, 0);
- + ssd1289_write(info, 0x0600, 1);
- +
- + /* sleep mode */
- + ssd1289_write(info, SSD1289_REG_SLEEP_MODE, 0);
- + ssd1289_write(info, 0x0000, 1);
- +
- + /* entry mode */
- + ssd1289_write(info, SSD1289_REG_ENTRY_MODE, 0);
- + ssd1289_write(info, 0x60a8, 1);
- +
- + mdelay(15);
- + /* compare register */
- + ssd1289_write(info, SSD1289_REG_COMPARE_1, 0);
- + ssd1289_write(info, 0x0000, 1);
- +
- + ssd1289_write(info, SSD1289_REG_COMPARE_2, 0);
- + ssd1289_write(info, 0x0000, 1);
- +
- + /* horizontal porch */
- + ssd1289_write(info, SSD1289_REG_H_PORCH, 0);
- + ssd1289_write(info, 0xef1c, 1);
- +
- + /* vertical porch */
- + ssd1289_write(info, SSD1289_REG_V_PORCH, 0);
- + ssd1289_write(info, 0x0003, 1);
- +
- + /* display control */
- + ssd1289_write(info, SSD1289_REG_DISPLAY_CTRL, 0);
- + ssd1289_write(info, 0x0233, 1);
- +
- + /* frame cycle control */
- + ssd1289_write(info, SSD1289_REG_FRAME_CYCLE, 0);
- + ssd1289_write(info, 0x5312, 1);
- +
- + /* gate scan position */
- + ssd1289_write(info, SSD1289_REG_GATE_SCAN_START, 0);
- + ssd1289_write(info, 0x0000, 1);
- +
- + mdelay(20);
- + /* vertical scroll control */
- + ssd1289_write(info, SSD1289_REG_V_SCROLL_CTRL_1, 0);
- + ssd1289_write(info, 0x0000, 1);
- +
- + ssd1289_write(info, SSD1289_REG_V_SCROLL_CTRL_2, 0);
- + ssd1289_write(info, 0x0000, 1);
- +
- + /* 1st screen driving position */
- + ssd1289_write(info, SSD1289_REG_FIRST_WIN_START, 0);
- + ssd1289_write(info, 0x0000, 1);
- +
- + ssd1289_write(info, SSD1289_REG_FIRST_WIN_END, 0);
- + ssd1289_write(info, 0x013F, 1);
- +
- + /* 2nd screen driving position */
- + ssd1289_write(info, SSD1289_REG_SECND_WIN_START, 0);
- + ssd1289_write(info, 0x0000, 1);
- +
- + ssd1289_write(info, SSD1289_REG_SECND_WIN_END, 0);
- + ssd1289_write(info, 0x0000, 1);
- +
- + mdelay(20);
- + /* gamma control */
- + ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_1, 0);
- + ssd1289_write(info, 0x0707, 1);
- +
- + ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_2, 0);
- + ssd1289_write(info, 0x0704, 1);
- +
- + ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_3, 0);
- + ssd1289_write(info, 0x0204, 1);
- +
- + ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_4, 0);
- + ssd1289_write(info, 0x0201, 1);
- +
- + ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_5, 0);
- + ssd1289_write(info, 0x0203, 1);
- +
- + ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_6, 0);
- + ssd1289_write(info, 0x0204, 1);
- +
- + ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_7, 0);
- + ssd1289_write(info, 0x0204, 1);
- +
- + ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_8, 0);
- + ssd1289_write(info, 0x0502, 1);
- +
- + ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_9, 0);
- + ssd1289_write(info, 0x0302, 1);
- +
- + ssd1289_write(info, SSD1289_REG_GAMMA_CTRL_10, 0);
- + ssd1289_write(info, 0x0500, 1);
- +
- + /* ram write data mask */
- + ssd1289_write(info, SSD1289_REG_WR_DATA_MASK_1, 0);
- + ssd1289_write(info, 0x0000, 1);
- +
- + ssd1289_write(info, SSD1289_REG_WR_DATA_MASK_2, 0);
- + ssd1289_write(info, 0x0000, 1);
- +
- + /* frame frequency control */
- + ssd1289_write(info, SSD1289_REG_FRAME_FREQUENCY, 0);
- + ssd1289_write(info, 0xe000, 1);
- +
- + /* optimize data access speed */
- + ssd1289_write(info, SSD1289_REG_OPT_SPEED_1, 0);
- + ssd1289_write(info, 0x0006, 1);
- +
- + ssd1289_write(info, SSD1289_REG_OPT_SPEED_2, 0);
- + ssd1289_write(info, 0x12ae, 1);
- +
- + ssd1289_write(info, SSD1289_REG_OPT_SPEED_3, 0);
- + ssd1289_write(info, 0x6ceb, 1);
- +
- + /* horizontal ram address position */
- + ssd1289_write(info, SSD1289_REG_H_RAM_ADR_POS, 0);
- + ssd1289_write(info, 0xef00, 1);
- +
- + /* vertical ram address position */
- + ssd1289_write(info, SSD1289_REG_V_RAM_ADR_START, 0);
- + ssd1289_write(info, 0x0000, 1);
- +
- + ssd1289_write(info, SSD1289_REG_V_RAM_ADR_END, 0);
- + ssd1289_write(info, 0x013f, 1);
- +
- + mdelay(20);
- +
- + /* set start address counter */
- + ssd1289_write(info, SSD1289_REG_GDDRAM_X_ADDR, 0);
- + ssd1289_write(info, 0x00ef, 1);
- +
- + ssd1289_write(info, SSD1289_REG_GDDRAM_Y_ADDR, 0);
- + ssd1289_write(info, 0x0000, 1);
- +
- + ssd1289_write(info, SSD1289_REG_GDDRAM_DATA, 0);
- +
- +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
- + for (i = 0; i < info->screen_size; i += 2)
- + ssd1289_write(info, 0, 1);
- +#elif defined(CONFIG_SSD1289_SPI_MODE)
- + count = info->screen_size / SPI_LCD_BLOCK_HALF_SIZE;
- + for (i = 0; i < count; i++)
- + ssd1289_spi_writeblock(info, NULL, 0);
- +#endif
- +}
- +
- +static void fsl_ssd1289_disable_lcd(struct fb_info *info)
- +{
- + ssd1289_write(info, SSD1289_REG_DISPLAY_CTRL, 0);
- + ssd1289_write(info, 0x0200, 1);
- +
- + ssd1289_write(info, SSD1289_REG_OSCILLATION, 0);
- + ssd1289_write(info, 0x0000, 1);
- +}
- +
- +static int ssd1289fbd(void *arg)
- +{
- + struct fb_info *info = arg;
- + int i;
- + unsigned short *buf_p;
- + struct fsl_ssd1289_fb_info *fbinfo = info->par;
- +#if defined(CONFIG_SSD1289_SPI_MODE)
- + unsigned char *bufspi_p;
- + int count;
- +#endif
- +
- + while (!kthread_should_stop()) {
- + set_current_state(TASK_INTERRUPTIBLE);
- +
- + if (fbinfo->openflag == 1) {
- + buf_p = (unsigned short *)(info->screen_base);
- +
- +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
- + for (i = 0; i < info->screen_size; i += 2) {
- + ssd1289_write(info, *buf_p, 1);
- + buf_p++;
- + }
- +#elif defined(CONFIG_SSD1289_SPI_MODE)
- + bufspi_p = (unsigned char *)buf_p;
- + count = info->screen_size / SPI_LCD_BLOCK_HALF_SIZE;
- + for (i = 0; i < count; i++)
- + ssd1289_spi_writeblock(info, (bufspi_p +
- + SPI_LCD_BLOCK_HALF_SIZE * i), 1);
- +#endif
- + }
- + schedule_timeout(HZ/25);
- + }
- +
- + return 0;
- +}
- +
- +static int fsl_ssd1289_check_var(struct fb_var_screeninfo *var,
- + struct fb_info *info)
- +{
- + if (var->xres_virtual < var->xres)
- + var->xres_virtual = var->xres;
- + if (var->yres_virtual < var->yres)
- + var->yres_virtual = var->yres;
- +
- + if (var->xoffset < 0)
- + var->xoffset = 0;
- +
- + if (var->yoffset < 0)
- + var->yoffset = 0;
- +
- + if (var->xoffset + info->var.xres > info->var.xres_virtual)
- + var->xoffset = info->var.xres_virtual - info->var.xres;
- +
- + if (var->yoffset + info->var.yres > info->var.yres_virtual)
- + var->yoffset = info->var.yres_virtual - info->var.yres;
- +
- + switch (var->bits_per_pixel) {
- + case 8:
- + /* 8 bpp, 332 format */
- + var->red.length = 3;
- + var->red.offset = 5;
- + var->red.msb_right = 0;
- +
- + var->green.length = 3;
- + var->green.offset = 2;
- + var->green.msb_right = 0;
- +
- + var->blue.length = 2;
- + var->blue.offset = 0;
- + var->blue.msb_right = 0;
- +
- + var->transp.length = 0;
- + var->transp.offset = 0;
- + var->transp.msb_right = 0;
- + break;
- + case 16:
- + /* 16 bpp, 565 format */
- + var->red.length = 5;
- + var->red.offset = 11;
- + var->red.msb_right = 0;
- +
- + var->green.length = 6;
- + var->green.offset = 5;
- + var->green.msb_right = 0;
- +
- + var->blue.length = 5;
- + var->blue.offset = 0;
- + var->blue.msb_right = 0;
- +
- + var->transp.length = 0;
- + var->transp.offset = 0;
- + var->transp.msb_right = 0;
- + break;
- + default:
- + printk(KERN_ERR "Depth not supported: %u BPP\n",
- + var->bits_per_pixel);
- + return -EINVAL;
- + }
- + return 0;
- +}
- +
- +static int fsl_ssd1289_set_par(struct fb_info *info)
- +{
- + struct fb_var_screeninfo *var = &info->var;
- +
- + switch (var->bits_per_pixel) {
- + case 16:
- + info->fix.visual = FB_VISUAL_TRUECOLOR;
- + break;
- + case 8:
- + info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
- + break;
- + default:
- + info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
- + break;
- + }
- +
- + return 0;
- +}
- +
- +static inline __u32 CNVT_TOHW(__u32 val, __u32 width)
- +{
- + return ((val<<width) + 0x7FFF - val)>>16;
- +}
- +
- +static int fsl_ssd1289_setcolreg(unsigned regno,
- + unsigned red, unsigned green, unsigned blue,
- + unsigned transp, struct fb_info *info)
- +{
- + int ret = 1;
- +
- + /*
- + * If greyscale is true, then we convert the RGB value
- + * to greyscale no matter what visual we are using.
- + */
- + if (info->var.grayscale)
- + red = green = blue = (19595 * red + 38470 * green +
- + 7471 * blue) >> 16;
- + switch (info->fix.visual) {
- + case FB_VISUAL_TRUECOLOR:
- + if (regno < 16) {
- + u32 *pal = info->pseudo_palette;
- + u32 value;
- +
- + red = CNVT_TOHW(red, info->var.red.length);
- + green = CNVT_TOHW(green, info->var.green.length);
- + blue = CNVT_TOHW(blue, info->var.blue.length);
- + transp = CNVT_TOHW(transp, info->var.transp.length);
- +
- + value = (red << info->var.red.offset) |
- + (green << info->var.green.offset) |
- + (blue << info->var.blue.offset) |
- + (transp << info->var.transp.offset);
- +
- + pal[regno] = value;
- + ret = 0;
- + }
- + break;
- + case FB_VISUAL_STATIC_PSEUDOCOLOR:
- + case FB_VISUAL_PSEUDOCOLOR:
- + break;
- + }
- + return ret;
- +}
- +
- +static int fsl_ssd1289_blank(int blank_mode, struct fb_info *info)
- +{
- + if (blank_mode == FB_BLANK_POWERDOWN)
- + fsl_ssd1289_disable_lcd(info);
- + else
- + fsl_ssd1289_enable_lcd(info);
- +
- + return 0;
- +}
- +
- +static int fsl_ssd1289_open(struct fb_info *info, int user)
- +{
- + struct fsl_ssd1289_fb_info *fbinfo = info->par;
- + struct task_struct *task;
- + int ret;
- +
- + if (fbinfo->openflag == 0) {
- + memset(info->screen_base, 0, info->screen_size);
- + fsl_ssd1289_enable_lcd(info);
- +
- + task = kthread_run(ssd1289fbd, info, "SSD1289 LCD");
- + if (IS_ERR(task)) {
- + ret = PTR_ERR(task);
- + return ret;
- + }
- + fbinfo->task = task;
- + }
- +
- + fbinfo->openflag = 1;
- + return 0;
- +}
- +
- +static int fsl_ssd1289_release(struct fb_info *info, int user)
- +{
- + struct fsl_ssd1289_fb_info *fbinfo = info->par;
- +
- + fbinfo->openflag = 0;
- + if (fbinfo->task) {
- + struct task_struct *task = fbinfo->task;
- + fbinfo->task = NULL;
- + kthread_stop(task);
- + }
- +
- + memset(info->screen_base, 0, info->screen_size);
- + fsl_ssd1289_disable_lcd(info);
- + return 0;
- +}
- +
- +static struct fb_ops fsl_ssd1289_ops = {
- + .owner = THIS_MODULE,
- + .fb_check_var = fsl_ssd1289_check_var,
- + .fb_set_par = fsl_ssd1289_set_par,
- + .fb_setcolreg = fsl_ssd1289_setcolreg,
- + .fb_blank = fsl_ssd1289_blank,
- + .fb_open = fsl_ssd1289_open,
- + .fb_release = fsl_ssd1289_release,
- + .fb_copyarea = cfb_copyarea,
- + .fb_fillrect = cfb_fillrect,
- + .fb_imageblit = cfb_imageblit,
- +};
- +
- +static int fsl_ssd1289_map_video_memory(struct fb_info *info)
- +{
- + unsigned int map_size = info->fix.smem_len;
- +
- +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
- + struct fsl_ssd1289_fb_info *fbinfo = info->par;
- +
- + fbinfo->ssd1289_reg.cmd =
- + ioremap_nocache(FLEXBUS_LCD_CMD_ADDRESS, 2);
- + fbinfo->ssd1289_reg.data =
- + ioremap_nocache(FLEXBUS_LCD_DATA_ADDRESS, 2);
- +#endif
- +
- + info->screen_base = kmalloc(map_size, GFP_KERNEL);
- + info->fix.smem_start = virt_to_phys(info->screen_base);
- + info->screen_size = info->fix.smem_len;
- +
- + if (info->screen_base)
- + memset(info->screen_base, 0, map_size);
- +
- + return info->screen_base ? 0 : -ENOMEM;
- +}
- +
- +static inline void fsl_ssd1289_unmap_video_memory(struct fb_info *info)
- +{
- +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
- + struct fsl_ssd1289_fb_info *fbinfo = info->par;
- +
- + iounmap(fbinfo->ssd1289_reg.cmd);
- + iounmap(fbinfo->ssd1289_reg.data);
- +#endif
- + kfree(info->screen_base);
- +}
- +
- +
- +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
- +static int fsl_ssd1289_probe(struct platform_device *pdev)
- +#elif defined(CONFIG_SSD1289_SPI_MODE)
- +static int fsl_ssd1289_probe(struct spi_device *spi)
- +#endif
- +{
- + struct fsl_ssd1289_fb_info *fbinfo;
- + struct fb_info *info;
- + struct fsl_ssd1289_fb_display *display;
- + int ret;
- + unsigned long smem_len;
- +
- +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
- + info = framebuffer_alloc(sizeof(struct fsl_ssd1289_fb_info),
- + &pdev->dev);
- + if (!info)
- + return -ENOMEM;
- +
- + platform_set_drvdata(pdev, info);
- +
- + fbinfo = info->par;
- + fbinfo->dev = &pdev->dev;
- + display = pdev->dev.platform_data;
- +#elif defined(CONFIG_SSD1289_SPI_MODE)
- + info = framebuffer_alloc(sizeof(struct fsl_ssd1289_fb_info),
- + &spi->dev);
- + if (!info)
- + return -ENOMEM;
- +
- + dev_set_drvdata(&spi->dev, info);
- +
- + fbinfo = info->par;
- + fbinfo->dev = &spi->dev;
- + fbinfo->spidev = spi;
- + display = spi->dev.platform_data;
- +#endif
- +
- + fbinfo->openflag = 0;
- + info->fix.type = FB_TYPE_PACKED_PIXELS;
- + info->fix.type_aux = 0;
- + info->fix.xpanstep = 0;
- + info->fix.ypanstep = 0;
- + info->fix.ywrapstep = 0;
- + info->fix.accel = FB_ACCEL_NONE;
- +
- + info->var.nonstd = 0;
- + info->var.activate = FB_ACTIVATE_NOW;
- + info->var.accel_flags = 0;
- + info->var.vmode = FB_VMODE_NONINTERLACED;
- +
- + info->fbops = &fsl_ssd1289_ops;
- + info->flags = FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT
- + | FBINFO_HWACCEL_COPYAREA;
- + info->pseudo_palette = &fbinfo->pseudo_palette;
- +
- + /* find maximum required memory size for display */
- + smem_len = display->xres;
- + smem_len *= display->yres;
- + smem_len *= display->bpp;
- + smem_len >>= 3;
- + if (info->fix.smem_len < smem_len)
- + info->fix.smem_len = smem_len;
- +
- + /* Intialize video memory */
- + ret = fsl_ssd1289_map_video_memory(info);
- + if (ret) {
- + printk(KERN_ERR "Failed to allocate video RAM: %d\n", ret);
- + ret = -ENOMEM;
- + goto dealloc_fb;
- + }
- +
- + info->var.xres = display->xres;
- + info->var.yres = display->yres;
- + info->var.bits_per_pixel = display->bpp;
- + info->fix.line_length = (info->var.xres * info->var.bits_per_pixel) / 8;
- +
- + fsl_ssd1289_check_var(&info->var, info);
- +
- + ret = register_framebuffer(info);
- + if (ret < 0) {
- + printk(KERN_ERR "Failed to register framebuffer device: %d\n",
- + ret);
- + goto free_video_memory;
- + }
- +
- + printk(KERN_INFO "fb: SSD1289 TFT LCD Framebuffer Driver\n");
- + return 0;
- +
- +free_video_memory:
- + fsl_ssd1289_unmap_video_memory(info);
- +dealloc_fb:
- +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
- + platform_set_drvdata(pdev, NULL);
- +#elif defined(CONFIG_SSD1289_SPI_MODE)
- + dev_set_drvdata(&spi->dev, NULL);
- +#endif
- + framebuffer_release(info);
- + return ret;
- +}
- +
- +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
- +static int fsl_ssd1289_remove(struct platform_device *pdev)
- +{
- + struct fb_info *info = platform_get_drvdata(pdev);
- +
- + platform_set_drvdata(pdev, NULL);
- +#elif defined(CONFIG_SSD1289_SPI_MODE)
- +static int fsl_ssd1289_remove(struct spi_device *spi)
- +{
- + struct fb_info *info = dev_get_drvdata(&spi->dev);
- +
- + dev_set_drvdata(&spi->dev, NULL);
- +#endif
- + unregister_framebuffer(info);
- + fsl_ssd1289_unmap_video_memory(info);
- + framebuffer_release(info);
- + return 0;
- +}
- +
- +#ifdef CONFIG_PM
- +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
- +static int fsl_ssd1289_suspend(struct platform_device *dev, pm_message_t state)
- +{
- + struct fb_info *info = platform_get_drvdata(dev);
- +#elif defined(CONFIG_SSD1289_SPI_MODE)
- +static int fsl_ssd1289_suspend(struct spi_device *spi, pm_message_t state)
- +{
- + struct fb_info *info = dev_get_drvdata(&spi->dev);
- +#endif
- + /* enter into sleep mode */
- + ssd1289_write(info, SSD1289_REG_SLEEP_MODE, 0);
- + ssd1289_write(info, 0x0001, 1);
- + return 0;
- +}
- +
- +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
- +static int fsl_ssd1289_resume(struct platform_device *dev)
- +{
- + struct fb_info *info = platform_get_drvdata(dev);
- +#elif defined(CONFIG_SSD1289_SPI_MODE)
- +static int fsl_ssd1289_resume(struct spi_device *spi)
- +{
- + struct fb_info *info = dev_get_drvdata(&spi->dev);
- +#endif
- + /* leave sleep mode */
- + ssd1289_write(info, SSD1289_REG_SLEEP_MODE, 0);
- + ssd1289_write(info, 0x0000, 1);
- + return 0;
- +}
- +#else
- +#define fsl_ssd1289_suspend NULL
- +#define fsl_ssd1289_resume NULL
- +#endif
- +
- +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
- +static struct platform_driver fsl_ssd1289_driver = {
- + .probe = fsl_ssd1289_probe,
- + .remove = fsl_ssd1289_remove,
- + .suspend = fsl_ssd1289_suspend,
- + .resume = fsl_ssd1289_resume,
- + .driver = {
- + .name = "fsl-ssd1289",
- + .owner = THIS_MODULE,
- + },
- +};
- +#elif defined(CONFIG_SSD1289_SPI_MODE)
- +static struct spi_driver spi_ssd1289_driver = {
- + .driver = {
- + .name = "spi-ssd1289",
- + .bus = &spi_bus_type,
- + .owner = THIS_MODULE,
- + },
- + .probe = fsl_ssd1289_probe,
- + .remove = fsl_ssd1289_remove,
- + .suspend = fsl_ssd1289_suspend,
- + .resume = fsl_ssd1289_resume,
- +};
- +#endif
- +
- +static int __devinit fsl_ssd1289_init(void)
- +{
- +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
- + return platform_driver_register(&fsl_ssd1289_driver);
- +#elif defined(CONFIG_SSD1289_SPI_MODE)
- + return spi_register_driver(&spi_ssd1289_driver);
- +#endif
- +}
- +
- +static void __exit fsl_ssd1289_exit(void)
- +{
- +#if defined(CONFIG_SSD1289_FLEXBUS_MODE)
- + return platform_driver_unregister(&fsl_ssd1289_driver);
- +#elif defined(CONFIG_SSD1289_SPI_MODE)
- + return spi_unregister_driver(&spi_ssd1289_driver);
- +#endif
- +}
- +
- +module_init(fsl_ssd1289_init);
- +module_exit(fsl_ssd1289_exit);
- +
- +MODULE_AUTHOR("Alison Wang <[email protected]>");
- +MODULE_DESCRIPTION("Freescale MCF54418 SSD1289 TFT LCD Framebuffer Driver");
- +MODULE_LICENSE("GPL");
|