1169 lines · 26.9 KB · C
RawDownload
/* * broadsheetfb.c -- FB driver for E-Ink Broadsheet controller * * Copyright (C) 2008, Jaya Kumar * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. * * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. * * This driver is written to be used with the Broadsheet display controller. * * It is intended to be architecture independent. A board specific driver * must be used to perform all the physical IO interactions. * */ #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/vmalloc.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/fb.h>#include <linux/init.h>#include <linux/platform_device.h>#include <linux/list.h>#include <linux/firmware.h>#include <linux/uaccess.h> #include <video/broadsheetfb.h> /* track panel specific parameters */struct panel_info {	int w;	int h;	u16 sdcfg;	u16 gdcfg;	u16 lutfmt;	u16 fsynclen;	u16 fendfbegin;	u16 lsynclen;	u16 lendlbegin;	u16 pixclk;}; /* table of panel specific parameters to be indexed into by the board drivers */static struct panel_info panel_table[] = {	{	/* standard 6" on TFT backplane */		.w = 800,		.h = 600,		.sdcfg = (100 | (1 << 8) | (1 << 9)),		.gdcfg = 2,		.lutfmt = (4 | (1 << 7)),		.fsynclen = 4,		.fendfbegin = (10 << 8) | 4,		.lsynclen = 10,		.lendlbegin = (100 << 8) | 4,		.pixclk = 6,	},	{	/* custom 3.7" flexible on PET or steel */		.w = 320,		.h = 240,		.sdcfg = (67 | (0 << 8) | (0 << 9) | (0 << 10) | (0 << 12)),		.gdcfg = 3,		.lutfmt = (4 | (1 << 7)),		.fsynclen = 0,		.fendfbegin = (80 << 8) | 4,		.lsynclen = 10,		.lendlbegin = (80 << 8) | 20,		.pixclk = 14,	},	{	/* standard 9.7" on TFT backplane */		.w = 1200,		.h = 825,		.sdcfg = (100 | (1 << 8) | (1 << 9) | (0 << 10) | (0 << 12)),		.gdcfg = 2,		.lutfmt = (4 | (1 << 7)),		.fsynclen = 0,		.fendfbegin = (4 << 8) | 4,		.lsynclen = 4,		.lendlbegin = (60 << 8) | 10,		.pixclk = 3,	},}; #define DPY_W 800#define DPY_H 600 static struct fb_fix_screeninfo broadsheetfb_fix = {	.id =		"broadsheetfb",	.type =		FB_TYPE_PACKED_PIXELS,	.visual =	FB_VISUAL_STATIC_PSEUDOCOLOR,	.xpanstep =	0,	.ypanstep =	0,	.ywrapstep =	0,	.line_length =	DPY_W,	.accel =	FB_ACCEL_NONE,}; static struct fb_var_screeninfo broadsheetfb_var = {	.xres		= DPY_W,	.yres		= DPY_H,	.xres_virtual	= DPY_W,	.yres_virtual	= DPY_H,	.bits_per_pixel	= 8,	.grayscale	= 1,	.red =		{ 0, 4, 0 },	.green =	{ 0, 4, 0 },	.blue =		{ 0, 4, 0 },	.transp =	{ 0, 0, 0 },}; /* main broadsheetfb functions */static void broadsheet_gpio_issue_data(struct broadsheetfb_par *par, u16 data){	par->board->set_ctl(par, BS_WR, 0);	par->board->set_hdb(par, data);	par->board->set_ctl(par, BS_WR, 1);} static void broadsheet_gpio_issue_cmd(struct broadsheetfb_par *par, u16 data){	par->board->set_ctl(par, BS_DC, 0);	broadsheet_gpio_issue_data(par, data);} static void broadsheet_gpio_send_command(struct broadsheetfb_par *par, u16 data){	par->board->wait_for_rdy(par); 	par->board->set_ctl(par, BS_CS, 0);	broadsheet_gpio_issue_cmd(par, data);	par->board->set_ctl(par, BS_DC, 1);	par->board->set_ctl(par, BS_CS, 1);} static void broadsheet_gpio_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,					int argc, u16 *argv){	int i; 	par->board->wait_for_rdy(par); 	par->board->set_ctl(par, BS_CS, 0);	broadsheet_gpio_issue_cmd(par, cmd);	par->board->set_ctl(par, BS_DC, 1); 	for (i = 0; i < argc; i++)		broadsheet_gpio_issue_data(par, argv[i]);	par->board->set_ctl(par, BS_CS, 1);} static void broadsheet_mmio_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,				    int argc, u16 *argv){	int i; 	par->board->mmio_write(par, BS_MMIO_CMD, cmd); 	for (i = 0; i < argc; i++)		par->board->mmio_write(par, BS_MMIO_DATA, argv[i]);} static void broadsheet_send_command(struct broadsheetfb_par *par, u16 data){	if (par->board->mmio_write)		par->board->mmio_write(par, BS_MMIO_CMD, data);	else		broadsheet_gpio_send_command(par, data);} static void broadsheet_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,				    int argc, u16 *argv){	if (par->board->mmio_write)		broadsheet_mmio_send_cmdargs(par, cmd, argc, argv);	else		broadsheet_gpio_send_cmdargs(par, cmd, argc, argv);} static void broadsheet_gpio_burst_write(struct broadsheetfb_par *par, int size,					u16 *data){	int i;	u16 tmp; 	par->board->set_ctl(par, BS_CS, 0);	par->board->set_ctl(par, BS_DC, 1); 	for (i = 0; i < size; i++) {		par->board->set_ctl(par, BS_WR, 0);		tmp = (data[i] & 0x0F) << 4;		tmp |= (data[i] & 0x0F00) << 4;		par->board->set_hdb(par, tmp);		par->board->set_ctl(par, BS_WR, 1);	} 	par->board->set_ctl(par, BS_CS, 1);} static void broadsheet_mmio_burst_write(struct broadsheetfb_par *par, int size,				   u16 *data){	int i;	u16 tmp; 	for (i = 0; i < size; i++) {		tmp = (data[i] & 0x0F) << 4;		tmp |= (data[i] & 0x0F00) << 4;		par->board->mmio_write(par, BS_MMIO_DATA, tmp);	} } static void broadsheet_burst_write(struct broadsheetfb_par *par, int size,				   u16 *data){	if (par->board->mmio_write)		broadsheet_mmio_burst_write(par, size, data);	else		broadsheet_gpio_burst_write(par, size, data);} static u16 broadsheet_gpio_get_data(struct broadsheetfb_par *par){	u16 res;	/* wait for ready to go hi. (lo is busy) */	par->board->wait_for_rdy(par); 	/* cs lo, dc lo for cmd, we lo for each data, db as usual */	par->board->set_ctl(par, BS_DC, 1);	par->board->set_ctl(par, BS_CS, 0);	par->board->set_ctl(par, BS_WR, 0); 	res = par->board->get_hdb(par); 	/* strobe wr */	par->board->set_ctl(par, BS_WR, 1);	par->board->set_ctl(par, BS_CS, 1); 	return res;}  static u16 broadsheet_get_data(struct broadsheetfb_par *par){	if (par->board->mmio_read)		return par->board->mmio_read(par);	else		return broadsheet_gpio_get_data(par);} static void broadsheet_gpio_write_reg(struct broadsheetfb_par *par, u16 reg,					u16 data){	/* wait for ready to go hi. (lo is busy) */	par->board->wait_for_rdy(par); 	/* cs lo, dc lo for cmd, we lo for each data, db as usual */	par->board->set_ctl(par, BS_CS, 0); 	broadsheet_gpio_issue_cmd(par, BS_CMD_WR_REG); 	par->board->set_ctl(par, BS_DC, 1); 	broadsheet_gpio_issue_data(par, reg);	broadsheet_gpio_issue_data(par, data); 	par->board->set_ctl(par, BS_CS, 1);} static void broadsheet_mmio_write_reg(struct broadsheetfb_par *par, u16 reg,				 u16 data){	par->board->mmio_write(par, BS_MMIO_CMD, BS_CMD_WR_REG);	par->board->mmio_write(par, BS_MMIO_DATA, reg);	par->board->mmio_write(par, BS_MMIO_DATA, data); } static void broadsheet_write_reg(struct broadsheetfb_par *par, u16 reg,					u16 data){	if (par->board->mmio_write)		broadsheet_mmio_write_reg(par, reg, data);	else		broadsheet_gpio_write_reg(par, reg, data);} static void broadsheet_write_reg32(struct broadsheetfb_par *par, u16 reg,					u32 data){	broadsheet_write_reg(par, reg, cpu_to_le32(data) & 0xFFFF);	broadsheet_write_reg(par, reg + 2, (cpu_to_le32(data) >> 16) & 0xFFFF);}  static u16 broadsheet_read_reg(struct broadsheetfb_par *par, u16 reg){	broadsheet_send_cmdargs(par, BS_CMD_RD_REG, 1, &reg);	par->board->wait_for_rdy(par);	return broadsheet_get_data(par);} /* functions for waveform manipulation */static int is_broadsheet_pll_locked(struct broadsheetfb_par *par){	return broadsheet_read_reg(par, 0x000A) & 0x0001;} static int broadsheet_setup_plls(struct broadsheetfb_par *par){	int retry_count = 0;	u16 tmp; 	/* disable arral saemipu mode */	broadsheet_write_reg(par, 0x0006, 0x0000); 	broadsheet_write_reg(par, 0x0010, 0x0004);	broadsheet_write_reg(par, 0x0012, 0x5949);	broadsheet_write_reg(par, 0x0014, 0x0040);	broadsheet_write_reg(par, 0x0016, 0x0000); 	do {		if (retry_count++ > 100)			return -ETIMEDOUT;		mdelay(1);	} while (!is_broadsheet_pll_locked(par)); 	tmp = broadsheet_read_reg(par, 0x0006);	tmp &= ~0x1;	broadsheet_write_reg(par, 0x0006, tmp); 	return 0;} static int broadsheet_setup_spi(struct broadsheetfb_par *par){ 	broadsheet_write_reg(par, 0x0204, ((3 << 3) | 1));	broadsheet_write_reg(par, 0x0208, 0x0001); 	return 0;} static int broadsheet_setup_spiflash(struct broadsheetfb_par *par,						u16 *orig_sfmcd){ 	*orig_sfmcd = broadsheet_read_reg(par, 0x0204);	broadsheet_write_reg(par, 0x0208, 0);	broadsheet_write_reg(par, 0x0204, 0);	broadsheet_write_reg(par, 0x0204, ((3 << 3) | 1)); 	return 0;} static int broadsheet_spiflash_wait_for_bit(struct broadsheetfb_par *par,						u16 reg, int bitnum, int val,						int timeout){	u16 tmp; 	do {		tmp = broadsheet_read_reg(par, reg);		if (((tmp >> bitnum) & 1) == val)			return 0;		mdelay(1);	} while (timeout--); 	return -ETIMEDOUT;} static int broadsheet_spiflash_write_byte(struct broadsheetfb_par *par, u8 data){	broadsheet_write_reg(par, 0x0202, (data | 0x100)); 	return broadsheet_spiflash_wait_for_bit(par, 0x0206, 3, 0, 100);} static int broadsheet_spiflash_read_byte(struct broadsheetfb_par *par, u8 *data){	int err;	u16 tmp; 	broadsheet_write_reg(par, 0x0202, 0); 	err = broadsheet_spiflash_wait_for_bit(par, 0x0206, 3, 0, 100);	if (err)		return err; 	tmp = broadsheet_read_reg(par, 0x200); 	*data = tmp & 0xFF; 	return 0;} static int broadsheet_spiflash_wait_for_status(struct broadsheetfb_par *par,								int timeout){	u8 tmp;	int err; 	do {		broadsheet_write_reg(par, 0x0208, 1); 		err = broadsheet_spiflash_write_byte(par, 0x05);		if (err)			goto failout; 		err = broadsheet_spiflash_read_byte(par, &tmp);		if (err)			goto failout; 		broadsheet_write_reg(par, 0x0208, 0); 		if (!(tmp & 0x1))			return 0; 		mdelay(5);	} while (timeout--); 	dev_err(par->info->device, "Timed out waiting for spiflash status\n");	return -ETIMEDOUT; failout:	broadsheet_write_reg(par, 0x0208, 0);	return err;} static int broadsheet_spiflash_op_on_address(struct broadsheetfb_par *par,							u8 op, u32 addr){	int i;	u8 tmp;	int err; 	broadsheet_write_reg(par, 0x0208, 1); 	err = broadsheet_spiflash_write_byte(par, op);	if (err)		return err; 	for (i = 2; i >= 0; i--) {		tmp = ((addr >> (i * 8)) & 0xFF);		err = broadsheet_spiflash_write_byte(par, tmp);		if (err)			return err;	} 	return err;} static int broadsheet_verify_spiflash(struct broadsheetfb_par *par,						int *flash_type){	int err = 0;	u8 sig; 	err = broadsheet_spiflash_op_on_address(par, 0xAB, 0x00000000);	if (err)		goto failout; 	err = broadsheet_spiflash_read_byte(par, &sig);	if (err)		goto failout; 	if ((sig != 0x10) && (sig != 0x11)) {		dev_err(par->info->device, "Unexpected flash type\n");		err = -EINVAL;		goto failout;	} 	*flash_type = sig; failout:	broadsheet_write_reg(par, 0x0208, 0);	return err;} static int broadsheet_setup_for_wfm_write(struct broadsheetfb_par *par,					u16 *initial_sfmcd, int *flash_type) {	int err; 	err = broadsheet_setup_plls(par);	if (err)		return err; 	broadsheet_write_reg(par, 0x0106, 0x0203); 	err = broadsheet_setup_spi(par);	if (err)

Lines 1–500 of 1169.