2 * broadsheetfb.c -- FB driver for E-Ink Broadsheet controller
4 * Copyright (C) 2008, Jaya Kumar
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive for
10 * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
12 * This driver is written to be used with the Broadsheet display controller.
14 * It is intended to be architecture independent. A board specific driver
15 * must be used to perform all the physical IO interactions.
19 #include <linux/module.h>
20 #include <linux/kernel.h>
21 #include <linux/errno.h>
22 #include <linux/string.h>
24 #include <linux/slab.h>
25 #include <linux/vmalloc.h>
26 #include <linux/delay.h>
27 #include <linux/interrupt.h>
29 #include <linux/init.h>
30 #include <linux/platform_device.h>
31 #include <linux/list.h>
32 #include <linux/firmware.h>
33 #include <linux/uaccess.h>
35 #include <video/broadsheetfb.h>
37 /* track panel specific parameters */
51 /* table of panel specific parameters to be indexed into by the board drivers */
52 static struct panel_info panel_table[] = {
53 { /* standard 6" on TFT backplane */
56 .sdcfg = (100 | (1 << 8) | (1 << 9)),
58 .lutfmt = (4 | (1 << 7)),
60 .fendfbegin = (10 << 8) | 4,
62 .lendlbegin = (100 << 8) | 4,
65 { /* custom 3.7" flexible on PET or steel */
68 .sdcfg = (67 | (0 << 8) | (0 << 9) | (0 << 10) | (0 << 12)),
70 .lutfmt = (4 | (1 << 7)),
72 .fendfbegin = (80 << 8) | 4,
74 .lendlbegin = (80 << 8) | 20,
77 { /* standard 9.7" on TFT backplane */
80 .sdcfg = (100 | (1 << 8) | (1 << 9) | (0 << 10) | (0 << 12)),
82 .lutfmt = (4 | (1 << 7)),
84 .fendfbegin = (4 << 8) | 4,
86 .lendlbegin = (60 << 8) | 10,
94 static struct fb_fix_screeninfo broadsheetfb_fix = {
96 .type = FB_TYPE_PACKED_PIXELS,
97 .visual = FB_VISUAL_STATIC_PSEUDOCOLOR,
101 .line_length = DPY_W,
102 .accel = FB_ACCEL_NONE,
105 static struct fb_var_screeninfo broadsheetfb_var = {
108 .xres_virtual = DPY_W,
109 .yres_virtual = DPY_H,
113 .green = { 0, 4, 0 },
115 .transp = { 0, 0, 0 },
118 /* main broadsheetfb functions */
119 static void broadsheet_gpio_issue_data(struct broadsheetfb_par *par, u16 data)
121 par->board->set_ctl(par, BS_WR, 0);
122 par->board->set_hdb(par, data);
123 par->board->set_ctl(par, BS_WR, 1);
126 static void broadsheet_gpio_issue_cmd(struct broadsheetfb_par *par, u16 data)
128 par->board->set_ctl(par, BS_DC, 0);
129 broadsheet_gpio_issue_data(par, data);
132 static void broadsheet_gpio_send_command(struct broadsheetfb_par *par, u16 data)
134 par->board->wait_for_rdy(par);
136 par->board->set_ctl(par, BS_CS, 0);
137 broadsheet_gpio_issue_cmd(par, data);
138 par->board->set_ctl(par, BS_DC, 1);
139 par->board->set_ctl(par, BS_CS, 1);
142 static void broadsheet_gpio_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,
147 par->board->wait_for_rdy(par);
149 par->board->set_ctl(par, BS_CS, 0);
150 broadsheet_gpio_issue_cmd(par, cmd);
151 par->board->set_ctl(par, BS_DC, 1);
153 for (i = 0; i < argc; i++)
154 broadsheet_gpio_issue_data(par, argv[i]);
155 par->board->set_ctl(par, BS_CS, 1);
158 static void broadsheet_mmio_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,
163 par->board->mmio_write(par, BS_MMIO_CMD, cmd);
165 for (i = 0; i < argc; i++)
166 par->board->mmio_write(par, BS_MMIO_DATA, argv[i]);
169 static void broadsheet_send_command(struct broadsheetfb_par *par, u16 data)
171 if (par->board->mmio_write)
172 par->board->mmio_write(par, BS_MMIO_CMD, data);
174 broadsheet_gpio_send_command(par, data);
177 static void broadsheet_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,
180 if (par->board->mmio_write)
181 broadsheet_mmio_send_cmdargs(par, cmd, argc, argv);
183 broadsheet_gpio_send_cmdargs(par, cmd, argc, argv);
186 static void broadsheet_gpio_burst_write(struct broadsheetfb_par *par, int size,
192 par->board->set_ctl(par, BS_CS, 0);
193 par->board->set_ctl(par, BS_DC, 1);
195 for (i = 0; i < size; i++) {
196 par->board->set_ctl(par, BS_WR, 0);
197 tmp = (data[i] & 0x0F) << 4;
198 tmp |= (data[i] & 0x0F00) << 4;
199 par->board->set_hdb(par, tmp);
200 par->board->set_ctl(par, BS_WR, 1);
203 par->board->set_ctl(par, BS_CS, 1);
206 static void broadsheet_mmio_burst_write(struct broadsheetfb_par *par, int size,
212 for (i = 0; i < size; i++) {
213 tmp = (data[i] & 0x0F) << 4;
214 tmp |= (data[i] & 0x0F00) << 4;
215 par->board->mmio_write(par, BS_MMIO_DATA, tmp);
220 static void broadsheet_burst_write(struct broadsheetfb_par *par, int size,
223 if (par->board->mmio_write)
224 broadsheet_mmio_burst_write(par, size, data);
226 broadsheet_gpio_burst_write(par, size, data);
229 static u16 broadsheet_gpio_get_data(struct broadsheetfb_par *par)
232 /* wait for ready to go hi. (lo is busy) */
233 par->board->wait_for_rdy(par);
235 /* cs lo, dc lo for cmd, we lo for each data, db as usual */
236 par->board->set_ctl(par, BS_DC, 1);
237 par->board->set_ctl(par, BS_CS, 0);
238 par->board->set_ctl(par, BS_WR, 0);
240 res = par->board->get_hdb(par);
243 par->board->set_ctl(par, BS_WR, 1);
244 par->board->set_ctl(par, BS_CS, 1);
250 static u16 broadsheet_get_data(struct broadsheetfb_par *par)
252 if (par->board->mmio_read)
253 return par->board->mmio_read(par);
255 return broadsheet_gpio_get_data(par);
258 static void broadsheet_gpio_write_reg(struct broadsheetfb_par *par, u16 reg,
261 /* wait for ready to go hi. (lo is busy) */
262 par->board->wait_for_rdy(par);
264 /* cs lo, dc lo for cmd, we lo for each data, db as usual */
265 par->board->set_ctl(par, BS_CS, 0);
267 broadsheet_gpio_issue_cmd(par, BS_CMD_WR_REG);
269 par->board->set_ctl(par, BS_DC, 1);
271 broadsheet_gpio_issue_data(par, reg);
272 broadsheet_gpio_issue_data(par, data);
274 par->board->set_ctl(par, BS_CS, 1);
277 static void broadsheet_mmio_write_reg(struct broadsheetfb_par *par, u16 reg,
280 par->board->mmio_write(par, BS_MMIO_CMD, BS_CMD_WR_REG);
281 par->board->mmio_write(par, BS_MMIO_DATA, reg);
282 par->board->mmio_write(par, BS_MMIO_DATA, data);
286 static void broadsheet_write_reg(struct broadsheetfb_par *par, u16 reg,
289 if (par->board->mmio_write)
290 broadsheet_mmio_write_reg(par, reg, data);
292 broadsheet_gpio_write_reg(par, reg, data);
295 static void broadsheet_write_reg32(struct broadsheetfb_par *par, u16 reg,
298 broadsheet_write_reg(par, reg, cpu_to_le32(data) & 0xFFFF);
299 broadsheet_write_reg(par, reg + 2, (cpu_to_le32(data) >> 16) & 0xFFFF);
303 static u16 broadsheet_read_reg(struct broadsheetfb_par *par, u16 reg)
305 broadsheet_send_cmdargs(par, BS_CMD_RD_REG, 1, ®);
306 par->board->wait_for_rdy(par);
307 return broadsheet_get_data(par);
310 /* functions for waveform manipulation */
311 static int is_broadsheet_pll_locked(struct broadsheetfb_par *par)
313 return broadsheet_read_reg(par, 0x000A) & 0x0001;
316 static int broadsheet_setup_plls(struct broadsheetfb_par *par)
321 /* disable arral saemipu mode */
322 broadsheet_write_reg(par, 0x0006, 0x0000);
324 broadsheet_write_reg(par, 0x0010, 0x0004);
325 broadsheet_write_reg(par, 0x0012, 0x5949);
326 broadsheet_write_reg(par, 0x0014, 0x0040);
327 broadsheet_write_reg(par, 0x0016, 0x0000);
330 if (retry_count++ > 100)
333 } while (!is_broadsheet_pll_locked(par));
335 tmp = broadsheet_read_reg(par, 0x0006);
337 broadsheet_write_reg(par, 0x0006, tmp);
342 static int broadsheet_setup_spi(struct broadsheetfb_par *par)
345 broadsheet_write_reg(par, 0x0204, ((3 << 3) | 1));
346 broadsheet_write_reg(par, 0x0208, 0x0001);
351 static int broadsheet_setup_spiflash(struct broadsheetfb_par *par,
355 *orig_sfmcd = broadsheet_read_reg(par, 0x0204);
356 broadsheet_write_reg(par, 0x0208, 0);
357 broadsheet_write_reg(par, 0x0204, 0);
358 broadsheet_write_reg(par, 0x0204, ((3 << 3) | 1));
363 static int broadsheet_spiflash_wait_for_bit(struct broadsheetfb_par *par,
364 u16 reg, int bitnum, int val,
370 tmp = broadsheet_read_reg(par, reg);
371 if (((tmp >> bitnum) & 1) == val)
379 static int broadsheet_spiflash_write_byte(struct broadsheetfb_par *par, u8 data)
381 broadsheet_write_reg(par, 0x0202, (data | 0x100));
383 return broadsheet_spiflash_wait_for_bit(par, 0x0206, 3, 0, 100);
386 static int broadsheet_spiflash_read_byte(struct broadsheetfb_par *par, u8 *data)
391 broadsheet_write_reg(par, 0x0202, 0);
393 err = broadsheet_spiflash_wait_for_bit(par, 0x0206, 3, 0, 100);
397 tmp = broadsheet_read_reg(par, 0x200);
404 static int broadsheet_spiflash_wait_for_status(struct broadsheetfb_par *par,
411 broadsheet_write_reg(par, 0x0208, 1);
413 err = broadsheet_spiflash_write_byte(par, 0x05);
417 err = broadsheet_spiflash_read_byte(par, &tmp);
421 broadsheet_write_reg(par, 0x0208, 0);
429 dev_err(par->info->device, "Timed out waiting for spiflash status\n");
433 broadsheet_write_reg(par, 0x0208, 0);
437 static int broadsheet_spiflash_op_on_address(struct broadsheetfb_par *par,
444 broadsheet_write_reg(par, 0x0208, 1);
446 err = broadsheet_spiflash_write_byte(par, op);
450 for (i = 2; i >= 0; i--) {
451 tmp = ((addr >> (i * 8)) & 0xFF);
452 err = broadsheet_spiflash_write_byte(par, tmp);
460 static int broadsheet_verify_spiflash(struct broadsheetfb_par *par,
466 err = broadsheet_spiflash_op_on_address(par, 0xAB, 0x00000000);
470 err = broadsheet_spiflash_read_byte(par, &sig);
474 if ((sig != 0x10) && (sig != 0x11)) {
475 dev_err(par->info->device, "Unexpected flash type\n");
483 broadsheet_write_reg(par, 0x0208, 0);
487 static int broadsheet_setup_for_wfm_write(struct broadsheetfb_par *par,
488 u16 *initial_sfmcd, int *flash_type)
493 err = broadsheet_setup_plls(par);
497 broadsheet_write_reg(par, 0x0106, 0x0203);
499 err = broadsheet_setup_spi(par);
503 err = broadsheet_setup_spiflash(par, initial_sfmcd);
507 return broadsheet_verify_spiflash(par, flash_type);
510 static int broadsheet_spiflash_write_control(struct broadsheetfb_par *par,
515 broadsheet_write_reg(par, 0x0208, 1);
517 err = broadsheet_spiflash_write_byte(par, 0x06);
519 err = broadsheet_spiflash_write_byte(par, 0x04);
521 broadsheet_write_reg(par, 0x0208, 0);
525 static int broadsheet_spiflash_erase_sector(struct broadsheetfb_par *par,
530 broadsheet_spiflash_write_control(par, 1);
532 err = broadsheet_spiflash_op_on_address(par, 0xD8, addr);
534 broadsheet_write_reg(par, 0x0208, 0);
539 err = broadsheet_spiflash_wait_for_status(par, 1000);
544 static int broadsheet_spiflash_read_range(struct broadsheetfb_par *par,
545 int addr, int size, char *data)
550 err = broadsheet_spiflash_op_on_address(par, 0x03, addr);
554 for (i = 0; i < size; i++) {
555 err = broadsheet_spiflash_read_byte(par, &data[i]);
561 broadsheet_write_reg(par, 0x0208, 0);
565 #define BS_SPIFLASH_PAGE_SIZE 256
566 static int broadsheet_spiflash_write_page(struct broadsheetfb_par *par,
567 int addr, const char *data)
572 broadsheet_spiflash_write_control(par, 1);
574 err = broadsheet_spiflash_op_on_address(par, 0x02, addr);
578 for (i = 0; i < BS_SPIFLASH_PAGE_SIZE; i++) {
579 err = broadsheet_spiflash_write_byte(par, data[i]);
584 broadsheet_write_reg(par, 0x0208, 0);
586 err = broadsheet_spiflash_wait_for_status(par, 100);
592 static int broadsheet_spiflash_write_sector(struct broadsheetfb_par *par,
593 int addr, const char *data, int sector_size)
598 for (i = 0; i < sector_size; i += BS_SPIFLASH_PAGE_SIZE) {
599 err = broadsheet_spiflash_write_page(par, addr + i, &data[i]);
607 * The caller must guarantee that the data to be rewritten is entirely
608 * contained within this sector. That is, data_start_addr + data_len
609 * must be less than sector_start_addr + sector_size.
611 static int broadsheet_spiflash_rewrite_sector(struct broadsheetfb_par *par,
612 int sector_size, int data_start_addr,
613 int data_len, const char *data)
618 int start_sector_addr;
620 sector_buffer = kzalloc(sizeof(char)*sector_size, GFP_KERNEL);
624 /* the start address of the sector is the 0th byte of that sector */
625 start_sector_addr = (data_start_addr / sector_size) * sector_size;
628 * check if there is head data that we need to readback into our sector
631 if (data_start_addr != start_sector_addr) {
633 * we need to read every byte up till the start address of our
634 * data and we put it into our sector buffer.
636 err = broadsheet_spiflash_read_range(par, start_sector_addr,
637 data_start_addr, sector_buffer);
642 /* now we copy our data into the right place in the sector buffer */
643 memcpy(sector_buffer + data_start_addr, data, data_len);
646 * now we check if there is a tail section of the sector that we need to
649 tail_start_addr = (data_start_addr + data_len) % sector_size;
651 if (tail_start_addr) {
654 tail_len = sector_size - tail_start_addr;
656 /* now we read this tail into our sector buffer */
657 err = broadsheet_spiflash_read_range(par, tail_start_addr,
658 tail_len, sector_buffer + tail_start_addr);
663 /* if we got here we have the full sector that we want to rewrite. */
665 /* first erase the sector */
666 err = broadsheet_spiflash_erase_sector(par, start_sector_addr);
671 err = broadsheet_spiflash_write_sector(par, start_sector_addr,
672 sector_buffer, sector_size);
676 static int broadsheet_write_spiflash(struct broadsheetfb_par *par, u32 wfm_addr,
677 const u8 *wfm, int bytecount, int flash_type)
686 switch (flash_type) {
688 sector_size = 32*1024;
692 sector_size = 64*1024;
697 cur_addr = wfm_addr + offset;
698 maxlen = roundup(cur_addr, sector_size) - cur_addr;
699 writecount = min(bytecount, maxlen);
701 err = broadsheet_spiflash_rewrite_sector(par, sector_size,
702 cur_addr, writecount, wfm + offset);
706 offset += writecount;
707 bytecount -= writecount;
713 static int broadsheet_store_waveform_to_spiflash(struct broadsheetfb_par *par,
714 const u8 *wfm, size_t wfm_size)
717 u16 initial_sfmcd = 0;
720 err = broadsheet_setup_for_wfm_write(par, &initial_sfmcd, &flash_type);
724 err = broadsheet_write_spiflash(par, 0x886, wfm, wfm_size, flash_type);
727 broadsheet_write_reg(par, 0x0204, initial_sfmcd);
731 static ssize_t broadsheet_loadstore_waveform(struct device *dev,
732 struct device_attribute *attr,
733 const char *buf, size_t len)
736 struct fb_info *info = dev_get_drvdata(dev);
737 struct broadsheetfb_par *par = info->par;
738 const struct firmware *fw_entry;
743 err = request_firmware(&fw_entry, "broadsheet.wbf", dev);
745 dev_err(dev, "Failed to get broadsheet waveform\n");
749 /* try to enforce reasonable min max on waveform */
750 if ((fw_entry->size < 8*1024) || (fw_entry->size > 64*1024)) {
751 dev_err(dev, "Invalid waveform\n");
756 mutex_lock(&(par->io_lock));
757 err = broadsheet_store_waveform_to_spiflash(par, fw_entry->data,
760 mutex_unlock(&(par->io_lock));
762 dev_err(dev, "Failed to store broadsheet waveform\n");
766 dev_info(dev, "Stored broadsheet waveform, size %zd\n", fw_entry->size);
773 static DEVICE_ATTR(loadstore_waveform, S_IWUSR, NULL,
774 broadsheet_loadstore_waveform);
776 /* upper level functions that manipulate the display and other stuff */
777 static void broadsheet_init_display(struct broadsheetfb_par *par)
780 int xres = par->info->var.xres;
781 int yres = par->info->var.yres;
783 args[0] = panel_table[par->panel_index].w;
784 args[1] = panel_table[par->panel_index].h;
785 args[2] = panel_table[par->panel_index].sdcfg;
786 args[3] = panel_table[par->panel_index].gdcfg;
787 args[4] = panel_table[par->panel_index].lutfmt;
788 broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_CFG, 5, args);
790 /* did the controller really set it? */
791 broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_CFG, 5, args);
793 args[0] = panel_table[par->panel_index].fsynclen;
794 args[1] = panel_table[par->panel_index].fendfbegin;
795 args[2] = panel_table[par->panel_index].lsynclen;
796 args[3] = panel_table[par->panel_index].lendlbegin;
797 args[4] = panel_table[par->panel_index].pixclk;
798 broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_TMG, 5, args);
800 broadsheet_write_reg32(par, 0x310, xres*yres*2);
805 broadsheet_send_cmdargs(par, BS_CMD_RD_WFM_INFO, 2, args);
807 broadsheet_send_command(par, BS_CMD_UPD_GDRV_CLR);
809 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG);
811 broadsheet_write_reg(par, 0x330, 0x84);
813 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG);
815 args[0] = (0x3 << 4);
816 broadsheet_send_cmdargs(par, BS_CMD_LD_IMG, 1, args);
819 broadsheet_send_cmdargs(par, BS_CMD_WR_REG, 1, args);
821 broadsheet_burst_write(par, (panel_table[par->panel_index].w *
822 panel_table[par->panel_index].h)/2,
823 (u16 *) par->info->screen_base);
825 broadsheet_send_command(par, BS_CMD_LD_IMG_END);
828 broadsheet_send_cmdargs(par, BS_CMD_UPD_FULL, 1, args);
830 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG);
832 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND);
834 par->board->wait_for_rdy(par);
837 static void broadsheet_identify(struct broadsheetfb_par *par)
840 struct device *dev = par->info->device;
842 rev = broadsheet_read_reg(par, BS_REG_REV);
843 prc = broadsheet_read_reg(par, BS_REG_PRC);
844 dev_info(dev, "Broadsheet Rev 0x%x, Product Code 0x%x\n", rev, prc);
847 dev_warn(dev, "Unrecognized Broadsheet Product Code\n");
849 dev_warn(dev, "Unrecognized Broadsheet Revision\n");
852 static void broadsheet_init(struct broadsheetfb_par *par)
854 broadsheet_send_command(par, BS_CMD_INIT_SYS_RUN);
855 /* the controller needs a second */
857 broadsheet_init_display(par);
860 static void broadsheetfb_dpy_update_pages(struct broadsheetfb_par *par,
864 unsigned char *buf = (unsigned char *)par->info->screen_base;
866 mutex_lock(&(par->io_lock));
867 /* y1 must be a multiple of 4 so drop the lower bits */
869 /* y2 must be a multiple of 4 , but - 1 so up the lower bits */
875 args[3] = cpu_to_le16(par->info->var.xres);
877 broadsheet_send_cmdargs(par, BS_CMD_LD_IMG_AREA, 5, args);
880 broadsheet_send_cmdargs(par, BS_CMD_WR_REG, 1, args);
882 buf += y1 * par->info->var.xres;
883 broadsheet_burst_write(par, ((1 + y2 - y1) * par->info->var.xres)/2,
886 broadsheet_send_command(par, BS_CMD_LD_IMG_END);
889 broadsheet_send_cmdargs(par, BS_CMD_UPD_FULL, 1, args);
891 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG);
893 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND);
895 par->board->wait_for_rdy(par);
896 mutex_unlock(&(par->io_lock));
900 static void broadsheetfb_dpy_update(struct broadsheetfb_par *par)
904 mutex_lock(&(par->io_lock));
906 broadsheet_send_cmdargs(par, BS_CMD_LD_IMG, 1, args);
909 broadsheet_send_cmdargs(par, BS_CMD_WR_REG, 1, args);
910 broadsheet_burst_write(par, (panel_table[par->panel_index].w *
911 panel_table[par->panel_index].h)/2,
912 (u16 *) par->info->screen_base);
914 broadsheet_send_command(par, BS_CMD_LD_IMG_END);
917 broadsheet_send_cmdargs(par, BS_CMD_UPD_FULL, 1, args);
919 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG);
921 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND);
923 par->board->wait_for_rdy(par);
924 mutex_unlock(&(par->io_lock));
927 /* this is called back from the deferred io workqueue */
928 static void broadsheetfb_dpy_deferred_io(struct fb_info *info,
929 struct list_head *pagelist)
934 struct fb_deferred_io *fbdefio = info->fbdefio;
936 u16 yres = info->var.yres;
937 u16 xres = info->var.xres;
939 /* height increment is fixed per page */
940 h_inc = DIV_ROUND_UP(PAGE_SIZE , xres);
942 /* walk the written page list and swizzle the data */
943 list_for_each_entry(cur, &fbdefio->pagelist, lru) {
944 if (prev_index < 0) {
945 /* just starting so assign first page */
946 y1 = (cur->index << PAGE_SHIFT) / xres;
948 } else if ((prev_index + 1) == cur->index) {
949 /* this page is consecutive so increase our height */
952 /* page not consecutive, issue previous update first */
953 broadsheetfb_dpy_update_pages(info->par, y1, y1 + h);
954 /* start over with our non consecutive page */
955 y1 = (cur->index << PAGE_SHIFT) / xres;
958 prev_index = cur->index;
961 /* if we still have any pages to update we do so now */
963 /* its a full screen update, just do it */
964 broadsheetfb_dpy_update(info->par);
966 broadsheetfb_dpy_update_pages(info->par, y1,
967 min((u16) (y1 + h), yres));
971 static void broadsheetfb_fillrect(struct fb_info *info,
972 const struct fb_fillrect *rect)
974 struct broadsheetfb_par *par = info->par;
976 sys_fillrect(info, rect);
978 broadsheetfb_dpy_update(par);
981 static void broadsheetfb_copyarea(struct fb_info *info,
982 const struct fb_copyarea *area)
984 struct broadsheetfb_par *par = info->par;
986 sys_copyarea(info, area);
988 broadsheetfb_dpy_update(par);
991 static void broadsheetfb_imageblit(struct fb_info *info,
992 const struct fb_image *image)
994 struct broadsheetfb_par *par = info->par;
996 sys_imageblit(info, image);
998 broadsheetfb_dpy_update(par);
1002 * this is the slow path from userspace. they can seek and write to
1003 * the fb. it's inefficient to do anything less than a full screen draw
1005 static ssize_t broadsheetfb_write(struct fb_info *info, const char __user *buf,
1006 size_t count, loff_t *ppos)
1008 struct broadsheetfb_par *par = info->par;
1009 unsigned long p = *ppos;
1012 unsigned long total_size;
1014 if (info->state != FBINFO_STATE_RUNNING)
1017 total_size = info->fix.smem_len;
1022 if (count > total_size) {
1027 if (count + p > total_size) {
1031 count = total_size - p;
1034 dst = (void *)(info->screen_base + p);
1036 if (copy_from_user(dst, buf, count))
1042 broadsheetfb_dpy_update(par);
1044 return (err) ? err : count;
1047 static struct fb_ops broadsheetfb_ops = {
1048 .owner = THIS_MODULE,
1049 .fb_read = fb_sys_read,
1050 .fb_write = broadsheetfb_write,
1051 .fb_fillrect = broadsheetfb_fillrect,
1052 .fb_copyarea = broadsheetfb_copyarea,
1053 .fb_imageblit = broadsheetfb_imageblit,
1056 static struct fb_deferred_io broadsheetfb_defio = {
1058 .deferred_io = broadsheetfb_dpy_deferred_io,
1061 static int broadsheetfb_probe(struct platform_device *dev)
1063 struct fb_info *info;
1064 struct broadsheet_board *board;
1065 int retval = -ENOMEM;
1066 int videomemorysize;
1067 unsigned char *videomemory;
1068 struct broadsheetfb_par *par;
1073 /* pick up board specific routines */
1074 board = dev->dev.platform_data;
1078 /* try to count device specific driver, if can't, platform recalls */
1079 if (!try_module_get(board->owner))
1082 info = framebuffer_alloc(sizeof(struct broadsheetfb_par), &dev->dev);
1086 switch (board->get_panel_type()) {
1099 dpyw = panel_table[panel_index].w;
1100 dpyh = panel_table[panel_index].h;
1102 videomemorysize = roundup((dpyw*dpyh), PAGE_SIZE);
1104 videomemory = vzalloc(videomemorysize);
1108 info->screen_base = (char *)videomemory;
1109 info->fbops = &broadsheetfb_ops;
1111 broadsheetfb_var.xres = dpyw;
1112 broadsheetfb_var.yres = dpyh;
1113 broadsheetfb_var.xres_virtual = dpyw;
1114 broadsheetfb_var.yres_virtual = dpyh;
1115 info->var = broadsheetfb_var;
1117 broadsheetfb_fix.line_length = dpyw;
1118 info->fix = broadsheetfb_fix;
1119 info->fix.smem_len = videomemorysize;
1121 par->panel_index = panel_index;
1124 par->write_reg = broadsheet_write_reg;
1125 par->read_reg = broadsheet_read_reg;
1126 init_waitqueue_head(&par->waitq);
1128 mutex_init(&par->io_lock);
1130 info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
1132 info->fbdefio = &broadsheetfb_defio;
1133 fb_deferred_io_init(info);
1135 retval = fb_alloc_cmap(&info->cmap, 16, 0);
1137 dev_err(&dev->dev, "Failed to allocate colormap\n");
1142 for (i = 0; i < 16; i++)
1143 info->cmap.red[i] = (((2*i)+1)*(0xFFFF))/32;
1144 memcpy(info->cmap.green, info->cmap.red, sizeof(u16)*16);
1145 memcpy(info->cmap.blue, info->cmap.red, sizeof(u16)*16);
1147 retval = par->board->setup_irq(info);
1151 /* this inits the dpy */
1152 retval = board->init(par);
1156 broadsheet_identify(par);
1158 broadsheet_init(par);
1160 retval = register_framebuffer(info);
1164 platform_set_drvdata(dev, info);
1166 retval = device_create_file(&dev->dev, &dev_attr_loadstore_waveform);
1171 "fb%d: Broadsheet frame buffer, using %dK of video memory\n",
1172 info->node, videomemorysize >> 10);
1178 unregister_framebuffer(info);
1180 board->cleanup(par);
1182 fb_dealloc_cmap(&info->cmap);
1186 framebuffer_release(info);
1188 module_put(board->owner);
1193 static int broadsheetfb_remove(struct platform_device *dev)
1195 struct fb_info *info = platform_get_drvdata(dev);
1198 struct broadsheetfb_par *par = info->par;
1200 device_remove_file(info->dev, &dev_attr_loadstore_waveform);
1201 unregister_framebuffer(info);
1202 fb_deferred_io_cleanup(info);
1203 par->board->cleanup(par);
1204 fb_dealloc_cmap(&info->cmap);
1205 vfree((void *)info->screen_base);
1206 module_put(par->board->owner);
1207 framebuffer_release(info);
1212 static struct platform_driver broadsheetfb_driver = {
1213 .probe = broadsheetfb_probe,
1214 .remove = broadsheetfb_remove,
1216 .owner = THIS_MODULE,
1217 .name = "broadsheetfb",
1221 static int __init broadsheetfb_init(void)
1223 return platform_driver_register(&broadsheetfb_driver);
1226 static void __exit broadsheetfb_exit(void)
1228 platform_driver_unregister(&broadsheetfb_driver);
1231 module_init(broadsheetfb_init);
1232 module_exit(broadsheetfb_exit);
1234 MODULE_DESCRIPTION("fbdev driver for Broadsheet controller");
1235 MODULE_AUTHOR("Jaya Kumar");
1236 MODULE_LICENSE("GPL");