/* * 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, ®); 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. Load more
/* * 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, ®); 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)