sh_mobile_lcdcfb.c revision 8564557a03c12adb9c4b76ae1e86db4113a04d13
1cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm/* 2cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm * SuperH Mobile LCDC Framebuffer 3cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm * 4cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm * Copyright (c) 2008 Magnus Damm 5cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm * 6cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm * This file is subject to the terms and conditions of the GNU General Public 7cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm * License. See the file "COPYING" in the main directory of this archive 8cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm * for more details. 9cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm */ 10cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 11cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#include <linux/kernel.h> 12cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#include <linux/init.h> 13cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#include <linux/delay.h> 14cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#include <linux/mm.h> 15cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#include <linux/fb.h> 16cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#include <linux/clk.h> 17cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#include <linux/platform_device.h> 18cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#include <linux/dma-mapping.h> 198564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm#include <linux/interrupt.h> 20225c9a8d1da274bf23efec43ec28b1c9e45e12f8Paul Mundt#include <video/sh_mobile_lcdc.h> 218564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm#include <asm/atomic.h> 22cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 23cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define PALETTE_NR 16 24cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 25cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstruct sh_mobile_lcdc_priv; 26cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstruct sh_mobile_lcdc_chan { 27cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_priv *lcdc; 28cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long *reg_offs; 29cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long ldmt1r_value; 30cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long enabled; /* ME and SE in LDCNT2R */ 31cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan_cfg cfg; 32cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm u32 pseudo_palette[PALETTE_NR]; 33cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct fb_info info; 34cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dma_addr_t dma_handle; 358564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm struct fb_deferred_io defio; 36cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 37cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 38cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstruct sh_mobile_lcdc_priv { 39cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm void __iomem *base; 408564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm int irq; 41225c9a8d1da274bf23efec43ec28b1c9e45e12f8Paul Mundt#ifdef CONFIG_HAVE_CLK 428564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm atomic_t clk_usecnt; 43b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm struct clk *dot_clk; 44cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct clk *clk; 45225c9a8d1da274bf23efec43ec28b1c9e45e12f8Paul Mundt#endif 46cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long lddckr; 47cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan ch[2]; 48cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 49cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 50cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm/* shared registers */ 51cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDDCKR 0x410 52cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDDCKSTPR 0x414 53cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDINTR 0x468 54cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDSR 0x46c 55cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDCNT1R 0x470 56cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDCNT2R 0x474 57cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDDDSR 0x47c 58cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDDWD0R 0x800 59cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDDRDR 0x840 60cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDDWAR 0x900 61cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define _LDDRAR 0x904 62cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 63cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm/* per-channel registers */ 64cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammenum { LDDCKPAT1R, LDDCKPAT2R, LDMT1R, LDMT2R, LDMT3R, LDDFR, LDSM1R, 658564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm LDSM2R, LDSA1R, LDMLSR, LDHCNR, LDHSYNR, LDVLNR, LDVSYNR, LDPMR }; 66cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 67cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic unsigned long lcdc_offs_mainlcd[] = { 68cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDCKPAT1R] = 0x400, 69cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDCKPAT2R] = 0x404, 70cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT1R] = 0x418, 71cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT2R] = 0x41c, 72cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT3R] = 0x420, 73cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDFR] = 0x424, 74cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDSM1R] = 0x428, 758564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm [LDSM2R] = 0x42c, 76cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDSA1R] = 0x430, 77cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMLSR] = 0x438, 78cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDHCNR] = 0x448, 79cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDHSYNR] = 0x44c, 80cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDVLNR] = 0x450, 81cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDVSYNR] = 0x454, 82cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDPMR] = 0x460, 83cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 84cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 85cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic unsigned long lcdc_offs_sublcd[] = { 86cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDCKPAT1R] = 0x408, 87cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDCKPAT2R] = 0x40c, 88cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT1R] = 0x600, 89cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT2R] = 0x604, 90cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMT3R] = 0x608, 91cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDDFR] = 0x60c, 92cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDSM1R] = 0x610, 938564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm [LDSM2R] = 0x614, 94cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDSA1R] = 0x618, 95cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDMLSR] = 0x620, 96cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDHCNR] = 0x624, 97cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDHSYNR] = 0x628, 98cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDVLNR] = 0x62c, 99cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDVSYNR] = 0x630, 100cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm [LDPMR] = 0x63c, 101cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 102cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 103cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define START_LCDC 0x00000001 104cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define LCDC_RESET 0x00000100 105cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define DISPLAY_BEU 0x00000008 106cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm#define LCDC_ENABLE 0x00000001 1078564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm#define LDINTR_FE 0x00000400 1088564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm#define LDINTR_FS 0x00000004 109cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 110cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_write_chan(struct sh_mobile_lcdc_chan *chan, 111cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int reg_nr, unsigned long data) 112cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 113cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr]); 114cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 115cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 116cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic unsigned long lcdc_read_chan(struct sh_mobile_lcdc_chan *chan, 117cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int reg_nr) 118cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 119cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return ioread32(chan->lcdc->base + chan->reg_offs[reg_nr]); 120cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 121cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 122cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_write(struct sh_mobile_lcdc_priv *priv, 123cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long reg_offs, unsigned long data) 124cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 125cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm iowrite32(data, priv->base + reg_offs); 126cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 127cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 128cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic unsigned long lcdc_read(struct sh_mobile_lcdc_priv *priv, 129cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long reg_offs) 130cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 131cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return ioread32(priv->base + reg_offs); 132cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 133cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 134cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_wait_bit(struct sh_mobile_lcdc_priv *priv, 135cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long reg_offs, 136cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long mask, unsigned long until) 137cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 138cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm while ((lcdc_read(priv, reg_offs) & mask) != until) 139cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm cpu_relax(); 140cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 141cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 142cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int lcdc_chan_is_sublcd(struct sh_mobile_lcdc_chan *chan) 143cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 144cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return chan->cfg.chan == LCDC_CHAN_SUBLCD; 145cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 146cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 147cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_sys_write_index(void *handle, unsigned long data) 148cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 149cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan *ch = handle; 150cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 151cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(ch->lcdc, _LDDWD0R, data | 0x10000000); 152cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); 153cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(ch->lcdc, _LDDWAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0)); 154cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 155cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 156cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void lcdc_sys_write_data(void *handle, unsigned long data) 157cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 158cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan *ch = handle; 159cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 160cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(ch->lcdc, _LDDWD0R, data | 0x11000000); 161cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); 162cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(ch->lcdc, _LDDWAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0)); 163cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 164cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 165cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic unsigned long lcdc_sys_read_data(void *handle) 166cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 167cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan *ch = handle; 168cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 169cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(ch->lcdc, _LDDRDR, 0x01000000); 170cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_wait_bit(ch->lcdc, _LDSR, 2, 0); 171cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(ch->lcdc, _LDDRAR, 1 | (lcdc_chan_is_sublcd(ch) ? 2 : 0)); 172cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm udelay(1); 173cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 174cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return lcdc_read(ch->lcdc, _LDDRDR) & 0xffff; 175cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 176cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 177cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstruct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = { 178cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_sys_write_index, 179cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_sys_write_data, 180cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_sys_read_data, 181cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 182cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 1838564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm#ifdef CONFIG_HAVE_CLK 1848564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) 1858564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 1868564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (atomic_inc_and_test(&priv->clk_usecnt)) { 1878564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm clk_enable(priv->clk); 1888564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (priv->dot_clk) 1898564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm clk_enable(priv->dot_clk); 1908564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } 1918564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 1928564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 1938564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) 1948564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 1958564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (atomic_sub_return(1, &priv->clk_usecnt) == -1) { 1968564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (priv->dot_clk) 1978564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm clk_disable(priv->dot_clk); 1988564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm clk_disable(priv->clk); 1998564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } 2008564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 2018564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm#else 2028564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) {} 2038564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) {} 2048564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm#endif 2058564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 2068564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_deferred_io(struct fb_info *info, 2078564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm struct list_head *pagelist) 2088564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 2098564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm struct sh_mobile_lcdc_chan *ch = info->par; 2108564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 2118564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* enable clocks before accessing hardware */ 2128564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_clk_on(ch->lcdc); 2138564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 2148564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* trigger panel update */ 2158564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm lcdc_write_chan(ch, LDSM2R, 1); 2168564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 2178564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 2188564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info) 2198564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 2208564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm struct fb_deferred_io *fbdefio = info->fbdefio; 2218564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 2228564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (fbdefio) 2238564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm schedule_delayed_work(&info->deferred_work, fbdefio->delay); 2248564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 2258564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 2268564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic irqreturn_t sh_mobile_lcdc_irq(int irq, void *data) 2278564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 2288564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm struct sh_mobile_lcdc_priv *priv = data; 2298564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm unsigned long tmp; 2308564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 2318564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* acknowledge interrupt */ 2328564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm tmp = lcdc_read(priv, _LDINTR); 2338564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm tmp &= 0xffffff00; /* mask in high 24 bits */ 2348564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm tmp |= 0x000000ff ^ LDINTR_FS; /* status in low 8 */ 2358564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm lcdc_write(priv, _LDINTR, tmp); 2368564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 2378564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* disable clocks */ 2388564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_clk_off(priv); 2398564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm return IRQ_HANDLED; 2408564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 2418564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 242cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv, 243cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int start) 244cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 245cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long tmp = lcdc_read(priv, _LDCNT2R); 246cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int k; 247cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 248cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* start or stop the lcdc */ 249cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (start) 250cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDCNT2R, tmp | START_LCDC); 251cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm else 252cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDCNT2R, tmp & ~START_LCDC); 253cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 254cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* wait until power is applied/stopped on all channels */ 255cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) 256cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (lcdc_read(priv, _LDCNT2R) & priv->ch[k].enabled) 257cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm while (1) { 258cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp = lcdc_read_chan(&priv->ch[k], LDPMR) & 3; 259cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (start && tmp == 3) 260cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 261cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!start && tmp == 0) 262cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 263cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm cpu_relax(); 264cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 265cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 266cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!start) 267cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDDCKSTPR, 1); /* stop dotclock */ 268cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 269cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 270cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) 271cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 272cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan *ch; 273cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct fb_videomode *lcd_cfg; 274cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_board_cfg *board_cfg; 275cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unsigned long tmp; 276cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int k, m; 277cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int ret = 0; 278cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 2798564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* enable clocks before accessing the hardware */ 2808564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) 2818564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (priv->ch[k].enabled) 2828564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_clk_on(priv); 2838564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 284cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* reset */ 285cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET); 286cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_wait_bit(priv, _LDCNT2R, LCDC_RESET, 0); 287cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 288cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* enable LCDC channels */ 289cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp = lcdc_read(priv, _LDCNT2R); 290cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp |= priv->ch[0].enabled; 291cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp |= priv->ch[1].enabled; 292cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDCNT2R, tmp); 293cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 294cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* read data from external memory, avoid using the BEU for now */ 295cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~DISPLAY_BEU); 296cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 297cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* stop the lcdc first */ 298cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm sh_mobile_lcdc_start_stop(priv, 0); 299cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 300cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* configure clocks */ 301cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp = priv->lddckr; 302cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 303cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch = &priv->ch[k]; 304cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 305cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!priv->ch[k].enabled) 306cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm continue; 307cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 308cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm m = ch->cfg.clock_divider; 309cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!m) 310cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm continue; 311cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 312cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (m == 1) 313cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm m = 1 << 6; 314cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0); 315cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 316cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write_chan(ch, LDDCKPAT1R, 0x00000000); 317cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1); 318cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 319cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 320cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDDCKR, tmp); 321cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 322cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* start dotclock again */ 323cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDDCKSTPR, 0); 324cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0); 325cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 3268564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* interrupts are disabled to begin with */ 327cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDINTR, 0); 328cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 329cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 330cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch = &priv->ch[k]; 331cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcd_cfg = &ch->cfg.lcd_cfg; 332cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 333cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!ch->enabled) 334cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm continue; 335cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 336cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp = ch->ldmt1r_value; 337cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp |= (lcd_cfg->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1 << 28; 338cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp |= (lcd_cfg->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1 << 27; 339f400f510df4e29bd00ffe07981ec703070cb9e19Magnus Damm tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? 1 << 26 : 0; 340f400f510df4e29bd00ffe07981ec703070cb9e19Magnus Damm tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? 1 << 25 : 0; 341f400f510df4e29bd00ffe07981ec703070cb9e19Magnus Damm tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? 1 << 24 : 0; 342f400f510df4e29bd00ffe07981ec703070cb9e19Magnus Damm tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? 1 << 17 : 0; 343f400f510df4e29bd00ffe07981ec703070cb9e19Magnus Damm tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? 1 << 16 : 0; 344cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write_chan(ch, LDMT1R, tmp); 345cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 346cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* setup SYS bus */ 347cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write_chan(ch, LDMT2R, ch->cfg.sys_bus_cfg.ldmt2r); 348cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r); 349cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 350cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* horizontal configuration */ 351cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp = lcd_cfg->xres + lcd_cfg->hsync_len; 352cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp += lcd_cfg->left_margin; 353cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp += lcd_cfg->right_margin; 354cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp /= 8; /* HTCN */ 355cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp |= (lcd_cfg->xres / 8) << 16; /* HDCN */ 356cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write_chan(ch, LDHCNR, tmp); 357cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 358cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp = lcd_cfg->xres; 359cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp += lcd_cfg->right_margin; 360cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp /= 8; /* HSYNP */ 361cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp |= (lcd_cfg->hsync_len / 8) << 16; /* HSYNW */ 362cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write_chan(ch, LDHSYNR, tmp); 363cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 364cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* power supply */ 365cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write_chan(ch, LDPMR, 0); 366cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 367cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* vertical configuration */ 368cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp = lcd_cfg->yres + lcd_cfg->vsync_len; 369cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp += lcd_cfg->upper_margin; 370cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp += lcd_cfg->lower_margin; /* VTLN */ 371cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp |= lcd_cfg->yres << 16; /* VDLN */ 372cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write_chan(ch, LDVLNR, tmp); 373cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 374cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp = lcd_cfg->yres; 375cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp += lcd_cfg->lower_margin; /* VSYNP */ 376cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp |= lcd_cfg->vsync_len << 16; /* VSYNW */ 377cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write_chan(ch, LDVSYNR, tmp); 378cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 379cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm board_cfg = &ch->cfg.board_cfg; 380cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (board_cfg->setup_sys) 381cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ret = board_cfg->setup_sys(board_cfg->board_data, ch, 382cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm &sh_mobile_lcdc_sys_bus_ops); 383cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (ret) 384cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return ret; 385cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 386cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 387cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* word and long word swap */ 388cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 6); 389cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 390cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 391cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch = &priv->ch[k]; 392cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 393cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!priv->ch[k].enabled) 394cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm continue; 395cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 396cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* set bpp format in PKF[4:0] */ 397cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp = lcdc_read_chan(ch, LDDFR); 398cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp &= ~(0x0001001f); 399cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm tmp |= (priv->ch[k].info.var.bits_per_pixel == 16) ? 3 : 0; 400cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write_chan(ch, LDDFR, tmp); 401cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 402cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* point out our frame buffer */ 403cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write_chan(ch, LDSA1R, ch->info.fix.smem_start); 404cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 405cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* set line size */ 406cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write_chan(ch, LDMLSR, ch->info.fix.line_length); 407cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 4088564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* setup deferred io if SYS bus */ 4098564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; 4108564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (ch->ldmt1r_value & (1 << 12) && tmp) { 4118564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm ch->defio.deferred_io = sh_mobile_lcdc_deferred_io; 4128564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm ch->defio.delay = msecs_to_jiffies(tmp); 4138564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm ch->info.fbdefio = &ch->defio; 4148564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm fb_deferred_io_init(&ch->info); 4158564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 4168564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* one-shot mode */ 4178564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm lcdc_write_chan(ch, LDSM1R, 1); 4188564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 4198564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* enable "Frame End Interrupt Enable" bit */ 4208564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm lcdc_write(priv, _LDINTR, LDINTR_FE); 4218564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 4228564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } else { 4238564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* continuous read mode */ 4248564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm lcdc_write_chan(ch, LDSM1R, 0); 4258564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } 426cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 427cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 428cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* display output */ 429cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm lcdc_write(priv, _LDCNT1R, LCDC_ENABLE); 430cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 431cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* start the lcdc */ 432cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm sh_mobile_lcdc_start_stop(priv, 1); 433cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 434cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* tell the board code to enable the panel */ 435cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 436cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch = &priv->ch[k]; 437cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm board_cfg = &ch->cfg.board_cfg; 438cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (board_cfg->display_on) 439cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm board_cfg->display_on(board_cfg->board_data); 440cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 441cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 442cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 443cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 444cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 445cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) 446cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 447cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan *ch; 448cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_board_cfg *board_cfg; 4498564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm unsigned long tmp; 450cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int k; 451cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 452cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* tell the board code to disable the panel */ 453cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { 454cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch = &priv->ch[k]; 455cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm board_cfg = &ch->cfg.board_cfg; 456cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (board_cfg->display_off) 457cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm board_cfg->display_off(board_cfg->board_data); 4588564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 4598564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* cleanup deferred io if SYS bus */ 4608564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; 4618564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (ch->ldmt1r_value & (1 << 12) && tmp) { 4628564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm fb_deferred_io_cleanup(&ch->info); 4638564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm ch->info.fbdefio = NULL; 4648564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } 465cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 466cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 467cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* stop the lcdc */ 468cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm sh_mobile_lcdc_start_stop(priv, 0); 469b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm 4708564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* stop clocks */ 4718564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm for (k = 0; k < ARRAY_SIZE(priv->ch); k++) 4728564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (priv->ch[k].enabled) 4738564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_clk_off(priv); 474cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 475cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 476cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch) 477cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 478cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int ifm, miftyp; 479cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 480cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm switch (ch->cfg.interface_type) { 481cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case RGB8: ifm = 0; miftyp = 0; break; 482cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case RGB9: ifm = 0; miftyp = 4; break; 483cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case RGB12A: ifm = 0; miftyp = 5; break; 484cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case RGB12B: ifm = 0; miftyp = 6; break; 485cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case RGB16: ifm = 0; miftyp = 7; break; 486cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case RGB18: ifm = 0; miftyp = 10; break; 487cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case RGB24: ifm = 0; miftyp = 11; break; 488cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS8A: ifm = 1; miftyp = 0; break; 489cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS8B: ifm = 1; miftyp = 1; break; 490cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS8C: ifm = 1; miftyp = 2; break; 491cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS8D: ifm = 1; miftyp = 3; break; 492cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS9: ifm = 1; miftyp = 4; break; 493cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS12: ifm = 1; miftyp = 5; break; 494cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS16A: ifm = 1; miftyp = 7; break; 495cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS16B: ifm = 1; miftyp = 8; break; 496cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS16C: ifm = 1; miftyp = 9; break; 497cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS18: ifm = 1; miftyp = 10; break; 498cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case SYS24: ifm = 1; miftyp = 11; break; 499cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm default: goto bad; 500cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 501cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 502cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* SUBLCD only supports SYS interface */ 503cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (lcdc_chan_is_sublcd(ch)) { 504cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (ifm == 0) 505cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto bad; 506cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm else 507cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ifm = 0; 508cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 509cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 510cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm ch->ldmt1r_value = (ifm << 12) | miftyp; 511cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 512cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm bad: 513cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return -EINVAL; 514cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 515cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 516b51339fff240ff179730f8963a758147fd60f3ecMagnus Dammstatic int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev, 517b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm int clock_source, 518cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_priv *priv) 519cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 520b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm#ifdef CONFIG_HAVE_CLK 521b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm char clk_name[8]; 522b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm#endif 523cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm char *str; 524cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int icksel; 525cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 526cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm switch (clock_source) { 527cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case LCDC_CLK_BUS: str = "bus_clk"; icksel = 0; break; 528cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case LCDC_CLK_PERIPHERAL: str = "peripheral_clk"; icksel = 1; break; 529cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case LCDC_CLK_EXTERNAL: str = NULL; icksel = 2; break; 530cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm default: 531cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return -EINVAL; 532cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 533cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 534cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm priv->lddckr = icksel << 16; 535cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 536225c9a8d1da274bf23efec43ec28b1c9e45e12f8Paul Mundt#ifdef CONFIG_HAVE_CLK 5378564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm atomic_set(&priv->clk_usecnt, -1); 538b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm snprintf(clk_name, sizeof(clk_name), "lcdc%d", pdev->id); 539b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm priv->clk = clk_get(&pdev->dev, clk_name); 540b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm if (IS_ERR(priv->clk)) { 541b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); 542b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm return PTR_ERR(priv->clk); 543b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm } 544b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm 545cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (str) { 546b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm priv->dot_clk = clk_get(&pdev->dev, str); 547b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm if (IS_ERR(priv->dot_clk)) { 548b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm dev_err(&pdev->dev, "cannot get dot clock %s\n", str); 549b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm clk_put(priv->clk); 550b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm return PTR_ERR(priv->dot_clk); 551cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 552cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 553225c9a8d1da274bf23efec43ec28b1c9e45e12f8Paul Mundt#endif 554cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 555cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 556cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 557cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 558cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_setcolreg(u_int regno, 559cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm u_int red, u_int green, u_int blue, 560cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm u_int transp, struct fb_info *info) 561cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 562cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm u32 *palette = info->pseudo_palette; 563cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 564cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (regno >= PALETTE_NR) 565cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return -EINVAL; 566cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 567cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm /* only FB_VISUAL_TRUECOLOR supported */ 568cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 569cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm red >>= 16 - info->var.red.length; 570cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm green >>= 16 - info->var.green.length; 571cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm blue >>= 16 - info->var.blue.length; 572cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm transp >>= 16 - info->var.transp.length; 573cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 574cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm palette[regno] = (red << info->var.red.offset) | 575cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm (green << info->var.green.offset) | 576cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm (blue << info->var.blue.offset) | 577cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm (transp << info->var.transp.offset); 578cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 579cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 580cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 581cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 582cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct fb_fix_screeninfo sh_mobile_lcdc_fix = { 583cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .id = "SH Mobile LCDC", 584cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .type = FB_TYPE_PACKED_PIXELS, 585cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .visual = FB_VISUAL_TRUECOLOR, 586cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .accel = FB_ACCEL_NONE, 587cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 588cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 5898564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_fillrect(struct fb_info *info, 5908564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm const struct fb_fillrect *rect) 5918564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 5928564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sys_fillrect(info, rect); 5938564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_deferred_io_touch(info); 5948564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 5958564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 5968564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_copyarea(struct fb_info *info, 5978564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm const struct fb_copyarea *area) 5988564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 5998564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sys_copyarea(info, area); 6008564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_deferred_io_touch(info); 6018564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 6028564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 6038564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Dammstatic void sh_mobile_lcdc_imageblit(struct fb_info *info, 6048564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm const struct fb_image *image) 6058564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm{ 6068564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sys_imageblit(info, image); 6078564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_deferred_io_touch(info); 6088564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm} 6098564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 610cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct fb_ops sh_mobile_lcdc_ops = { 611cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .fb_setcolreg = sh_mobile_lcdc_setcolreg, 6122540c111ead82cad605ec2b14a1905ad914cc124Magnus Damm .fb_read = fb_sys_read, 6132540c111ead82cad605ec2b14a1905ad914cc124Magnus Damm .fb_write = fb_sys_write, 6148564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm .fb_fillrect = sh_mobile_lcdc_fillrect, 6158564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm .fb_copyarea = sh_mobile_lcdc_copyarea, 6168564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm .fb_imageblit = sh_mobile_lcdc_imageblit, 617cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 618cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 619cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp) 620cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 621cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm switch (bpp) { 622cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case 16: /* PKF[4:0] = 00011 - RGB 565 */ 623cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->red.offset = 11; 624cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->red.length = 5; 625cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->green.offset = 5; 626cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->green.length = 6; 627cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->blue.offset = 0; 628cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->blue.length = 5; 629cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->transp.offset = 0; 630cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->transp.length = 0; 631cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 632cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 633cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case 32: /* PKF[4:0] = 00000 - RGB 888 634cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm * sh7722 pdf says 00RRGGBB but reality is GGBB00RR 635cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm * this may be because LDDDSR has word swap enabled.. 636cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm */ 637cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->red.offset = 0; 638cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->red.length = 8; 639cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->green.offset = 24; 640cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->green.length = 8; 641cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->blue.offset = 16; 642cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->blue.length = 8; 643cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->transp.offset = 0; 644cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->transp.length = 0; 645cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 646cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm default: 647cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return -EINVAL; 648cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 649cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->bits_per_pixel = bpp; 650cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->red.msb_right = 0; 651cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->green.msb_right = 0; 652cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->blue.msb_right = 0; 653cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm var->transp.msb_right = 0; 654cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 655cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 656cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 657cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_remove(struct platform_device *pdev); 658cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 659cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int __init sh_mobile_lcdc_probe(struct platform_device *pdev) 660cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 661cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct fb_info *info; 662cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_priv *priv; 663cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_info *pdata; 664cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_chan_cfg *cfg; 665cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct resource *res; 666cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int error; 667cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm void *buf; 668cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int i, j; 669cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 670cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!pdev->dev.platform_data) { 671cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "no platform data defined\n"); 672cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = -EINVAL; 673cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err0; 674cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 675cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 676cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 6778564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm i = platform_get_irq(pdev, 0); 6788564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (!res || i < 0) { 6798564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm dev_err(&pdev->dev, "cannot get platform resources\n"); 680cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = -ENOENT; 681cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err0; 682cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 683cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 684cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm priv = kzalloc(sizeof(*priv), GFP_KERNEL); 685cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!priv) { 686cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "cannot allocate device data\n"); 687cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = -ENOMEM; 688cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err0; 689cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 690cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 6918564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm error = request_irq(i, sh_mobile_lcdc_irq, IRQF_DISABLED, 6928564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm pdev->dev.bus_id, priv); 6938564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (error) { 6948564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm dev_err(&pdev->dev, "unable to request irq\n"); 6958564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm goto err1; 6968564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm } 6978564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 6988564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm priv->irq = i; 699cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm platform_set_drvdata(pdev, priv); 700cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm pdata = pdev->dev.platform_data; 701cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 702cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm j = 0; 703cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (i = 0; i < ARRAY_SIZE(pdata->ch); i++) { 704cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm priv->ch[j].lcdc = priv; 705cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm memcpy(&priv->ch[j].cfg, &pdata->ch[i], sizeof(pdata->ch[i])); 706cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 707cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = sh_mobile_lcdc_check_interface(&priv->ch[i]); 708cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) { 709cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "unsupported interface type\n"); 710cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 711cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 712cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 713cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm switch (pdata->ch[i].chan) { 714cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case LCDC_CHAN_MAINLCD: 715cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm priv->ch[j].enabled = 1 << 1; 716cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm priv->ch[j].reg_offs = lcdc_offs_mainlcd; 717cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm j++; 718cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 719cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm case LCDC_CHAN_SUBLCD: 720cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm priv->ch[j].enabled = 1 << 2; 721cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm priv->ch[j].reg_offs = lcdc_offs_sublcd; 722cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm j++; 723cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 724cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 725cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 726cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 727cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!j) { 728cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "no channels defined\n"); 729cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = -EINVAL; 730cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 731cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 732cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 733b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm error = sh_mobile_lcdc_setup_clocks(pdev, pdata->clock_source, priv); 734cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) { 735cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "unable to setup clocks\n"); 736cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 737cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 738cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 739cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm priv->base = ioremap_nocache(res->start, (res->end - res->start) + 1); 740cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 741cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (i = 0; i < j; i++) { 742cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info = &priv->ch[i].info; 743cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm cfg = &priv->ch[i].cfg; 744cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 745cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->fbops = &sh_mobile_lcdc_ops; 746cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->var.xres = info->var.xres_virtual = cfg->lcd_cfg.xres; 747cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->var.yres = info->var.yres_virtual = cfg->lcd_cfg.yres; 748ce9c008c8bea25a974d9027b7c6602d535639899Magnus Damm info->var.width = cfg->lcd_size_cfg.width; 749ce9c008c8bea25a974d9027b7c6602d535639899Magnus Damm info->var.height = cfg->lcd_size_cfg.height; 750cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->var.activate = FB_ACTIVATE_NOW; 751cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = sh_mobile_lcdc_set_bpp(&info->var, cfg->bpp); 752cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) 753cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 754cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 755cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->fix = sh_mobile_lcdc_fix; 756cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->fix.line_length = cfg->lcd_cfg.xres * (cfg->bpp / 8); 757cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->fix.smem_len = info->fix.line_length * cfg->lcd_cfg.yres; 758cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 759cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len, 760cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm &priv->ch[i].dma_handle, GFP_KERNEL); 761cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!buf) { 762cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "unable to allocate buffer\n"); 763cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = -ENOMEM; 764cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 765cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 766cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 767cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->pseudo_palette = &priv->ch[i].pseudo_palette; 768cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->flags = FBINFO_FLAG_DEFAULT; 769cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 770cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0); 771cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error < 0) { 772cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "unable to allocate cmap\n"); 773cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dma_free_coherent(&pdev->dev, info->fix.smem_len, 774cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm buf, priv->ch[i].dma_handle); 775cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm break; 776cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 777cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 778cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm memset(buf, 0, info->fix.smem_len); 779cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->fix.smem_start = priv->ch[i].dma_handle; 780cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->screen_base = buf; 781cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->device = &pdev->dev; 7828564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm info->par = &priv->ch[i]; 783cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 784cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 785cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) 786cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 787cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 788cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = sh_mobile_lcdc_start(priv); 789cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error) { 790cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_err(&pdev->dev, "unable to start hardware\n"); 791cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 792cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 793cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 794cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (i = 0; i < j; i++) { 795cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm error = register_framebuffer(&priv->ch[i].info); 796cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (error < 0) 797cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm goto err1; 798cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 799cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 800cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (i = 0; i < j; i++) { 801cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info = &priv->ch[i].info; 802cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dev_info(info->dev, 803cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm "registered %s/%s as %dx%d %dbpp.\n", 804cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm pdev->name, 805cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm (priv->ch[i].cfg.chan == LCDC_CHAN_MAINLCD) ? 806cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm "mainlcd" : "sublcd", 807cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm (int) priv->ch[i].cfg.lcd_cfg.xres, 808cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm (int) priv->ch[i].cfg.lcd_cfg.yres, 809cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm priv->ch[i].cfg.bpp); 8108564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm 8118564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm /* deferred io mode: disable clock to save power */ 8128564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (info->fbdefio) 8138564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm sh_mobile_lcdc_clk_off(priv); 814cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 815cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 816cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 817cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm err1: 818cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm sh_mobile_lcdc_remove(pdev); 819cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm err0: 820cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return error; 821cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 822cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 823cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int sh_mobile_lcdc_remove(struct platform_device *pdev) 824cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 825cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev); 826cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm struct fb_info *info; 827cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm int i; 828cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 829cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (i = 0; i < ARRAY_SIZE(priv->ch); i++) 830cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (priv->ch[i].info.dev) 831cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm unregister_framebuffer(&priv->ch[i].info); 832cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 833cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm sh_mobile_lcdc_stop(priv); 834cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 835cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm for (i = 0; i < ARRAY_SIZE(priv->ch); i++) { 836cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info = &priv->ch[i].info; 837cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 838cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (!info->device) 839cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm continue; 840cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 841cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm dma_free_coherent(&pdev->dev, info->fix.smem_len, 842cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm info->screen_base, priv->ch[i].dma_handle); 843cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm fb_dealloc_cmap(&info->cmap); 844cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm } 845cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 846225c9a8d1da274bf23efec43ec28b1c9e45e12f8Paul Mundt#ifdef CONFIG_HAVE_CLK 847b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm if (priv->dot_clk) 848b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm clk_put(priv->dot_clk); 849b51339fff240ff179730f8963a758147fd60f3ecMagnus Damm clk_put(priv->clk); 850225c9a8d1da274bf23efec43ec28b1c9e45e12f8Paul Mundt#endif 851cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 852cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm if (priv->base) 853cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm iounmap(priv->base); 854cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 8558564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm if (priv->irq) 8568564557a03c12adb9c4b76ae1e86db4113a04d13Magnus Damm free_irq(priv->irq, priv); 857cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm kfree(priv); 858cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return 0; 859cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 860cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 861cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic struct platform_driver sh_mobile_lcdc_driver = { 862cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .driver = { 863cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .name = "sh_mobile_lcdc_fb", 864cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .owner = THIS_MODULE, 865cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm }, 866cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .probe = sh_mobile_lcdc_probe, 867cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm .remove = sh_mobile_lcdc_remove, 868cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm}; 869cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 870cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic int __init sh_mobile_lcdc_init(void) 871cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 872cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm return platform_driver_register(&sh_mobile_lcdc_driver); 873cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 874cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 875cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammstatic void __exit sh_mobile_lcdc_exit(void) 876cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm{ 877cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm platform_driver_unregister(&sh_mobile_lcdc_driver); 878cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm} 879cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 880cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammmodule_init(sh_mobile_lcdc_init); 881cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Dammmodule_exit(sh_mobile_lcdc_exit); 882cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus Damm 883cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_DESCRIPTION("SuperH Mobile LCDC Framebuffer driver"); 884cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_AUTHOR("Magnus Damm <damm@opensource.se>"); 885cfb4f5d1750e05f43902197713c50c29e7dfbc99Magnus DammMODULE_LICENSE("GPL v2"); 886