| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 1 | /* | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 2 | *  Freescale i.MX Frame Buffer device driver | 
|  | 3 | * | 
|  | 4 | *  Copyright (C) 2004 Sascha Hauer, Pengutronix | 
|  | 5 | *   Based on acornfb.c Copyright (C) Russell King. | 
|  | 6 | * | 
|  | 7 | * This file is subject to the terms and conditions of the GNU General Public | 
|  | 8 | * License.  See the file COPYING in the main directory of this archive for | 
|  | 9 | * more details. | 
|  | 10 | * | 
|  | 11 | * Please direct your questions and comments on this driver to the following | 
|  | 12 | * email address: | 
|  | 13 | * | 
|  | 14 | *	linux-arm-kernel@lists.arm.linux.org.uk | 
|  | 15 | */ | 
|  | 16 |  | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 17 | #include <linux/module.h> | 
|  | 18 | #include <linux/kernel.h> | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 19 | #include <linux/errno.h> | 
|  | 20 | #include <linux/string.h> | 
|  | 21 | #include <linux/interrupt.h> | 
|  | 22 | #include <linux/slab.h> | 
| Andrea Righi | 27ac792 | 2008-07-23 21:28:13 -0700 | [diff] [blame] | 23 | #include <linux/mm.h> | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 24 | #include <linux/fb.h> | 
|  | 25 | #include <linux/delay.h> | 
|  | 26 | #include <linux/init.h> | 
|  | 27 | #include <linux/ioport.h> | 
|  | 28 | #include <linux/cpufreq.h> | 
| Sascha Hauer | f909ef6 | 2009-01-15 15:21:00 +0100 | [diff] [blame] | 29 | #include <linux/clk.h> | 
| Russell King | d052d1b | 2005-10-29 19:07:23 +0100 | [diff] [blame] | 30 | #include <linux/platform_device.h> | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 31 | #include <linux/dma-mapping.h> | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 32 | #include <linux/io.h> | 
| Sascha Hauer | f909ef6 | 2009-01-15 15:21:00 +0100 | [diff] [blame] | 33 | #include <linux/math64.h> | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 34 |  | 
| Russell King | a09e64f | 2008-08-05 16:14:15 +0100 | [diff] [blame] | 35 | #include <mach/imxfb.h> | 
| Sascha Hauer | f497d01 | 2009-03-18 11:29:31 +0100 | [diff] [blame] | 36 | #include <mach/hardware.h> | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 37 |  | 
|  | 38 | /* | 
|  | 39 | * Complain if VAR is out of range. | 
|  | 40 | */ | 
|  | 41 | #define DEBUG_VAR 1 | 
|  | 42 |  | 
| Eric Bénard | 81ef806 | 2010-08-02 08:39:55 +0100 | [diff] [blame] | 43 | #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || \ | 
|  | 44 | (defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) && \ | 
|  | 45 | defined(CONFIG_FB_IMX_MODULE)) | 
|  | 46 | #define PWMR_BACKLIGHT_AVAILABLE | 
|  | 47 | #endif | 
|  | 48 |  | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 49 | #define DRIVER_NAME "imx-fb" | 
|  | 50 |  | 
|  | 51 | #define LCDC_SSA	0x00 | 
|  | 52 |  | 
|  | 53 | #define LCDC_SIZE	0x04 | 
|  | 54 | #define SIZE_XMAX(x)	((((x) >> 4) & 0x3f) << 20) | 
| Sascha Hauer | 1d0f987 | 2009-01-26 17:29:10 +0100 | [diff] [blame] | 55 |  | 
| Fabio Estevam | 6032891 | 2010-12-24 10:28:24 -0200 | [diff] [blame] | 56 | #define YMAX_MASK       (cpu_is_mx1() ? 0x1ff : 0x3ff) | 
|  | 57 | #define SIZE_YMAX(y)	((y) & YMAX_MASK) | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 58 |  | 
|  | 59 | #define LCDC_VPW	0x08 | 
|  | 60 | #define VPW_VPW(x)	((x) & 0x3ff) | 
|  | 61 |  | 
|  | 62 | #define LCDC_CPOS	0x0C | 
|  | 63 | #define CPOS_CC1	(1<<31) | 
|  | 64 | #define CPOS_CC0	(1<<30) | 
|  | 65 | #define CPOS_OP		(1<<28) | 
|  | 66 | #define CPOS_CXP(x)	(((x) & 3ff) << 16) | 
| Sascha Hauer | 1d0f987 | 2009-01-26 17:29:10 +0100 | [diff] [blame] | 67 |  | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 68 | #define LCDC_LCWHB	0x10 | 
|  | 69 | #define LCWHB_BK_EN	(1<<31) | 
|  | 70 | #define LCWHB_CW(w)	(((w) & 0x1f) << 24) | 
|  | 71 | #define LCWHB_CH(h)	(((h) & 0x1f) << 16) | 
|  | 72 | #define LCWHB_BD(x)	((x) & 0xff) | 
|  | 73 |  | 
|  | 74 | #define LCDC_LCHCC	0x14 | 
| Sascha Hauer | 1d0f987 | 2009-01-26 17:29:10 +0100 | [diff] [blame] | 75 |  | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 76 | #define LCDC_PCR	0x18 | 
|  | 77 |  | 
|  | 78 | #define LCDC_HCR	0x1C | 
|  | 79 | #define HCR_H_WIDTH(x)	(((x) & 0x3f) << 26) | 
|  | 80 | #define HCR_H_WAIT_1(x)	(((x) & 0xff) << 8) | 
|  | 81 | #define HCR_H_WAIT_2(x)	((x) & 0xff) | 
|  | 82 |  | 
|  | 83 | #define LCDC_VCR	0x20 | 
|  | 84 | #define VCR_V_WIDTH(x)	(((x) & 0x3f) << 26) | 
|  | 85 | #define VCR_V_WAIT_1(x)	(((x) & 0xff) << 8) | 
|  | 86 | #define VCR_V_WAIT_2(x)	((x) & 0xff) | 
|  | 87 |  | 
|  | 88 | #define LCDC_POS	0x24 | 
|  | 89 | #define POS_POS(x)	((x) & 1f) | 
|  | 90 |  | 
|  | 91 | #define LCDC_LSCR1	0x28 | 
|  | 92 | /* bit fields in imxfb.h */ | 
|  | 93 |  | 
|  | 94 | #define LCDC_PWMR	0x2C | 
|  | 95 | /* bit fields in imxfb.h */ | 
|  | 96 |  | 
|  | 97 | #define LCDC_DMACR	0x30 | 
|  | 98 | /* bit fields in imxfb.h */ | 
|  | 99 |  | 
|  | 100 | #define LCDC_RMCR	0x34 | 
| Sascha Hauer | 1d0f987 | 2009-01-26 17:29:10 +0100 | [diff] [blame] | 101 |  | 
| Sascha Hauer | f142b61 | 2011-03-03 15:12:44 +0100 | [diff] [blame] | 102 | #define RMCR_LCDC_EN_MX1	(1<<1) | 
| Sascha Hauer | 1d0f987 | 2009-01-26 17:29:10 +0100 | [diff] [blame] | 103 |  | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 104 | #define RMCR_SELF_REF	(1<<0) | 
|  | 105 |  | 
|  | 106 | #define LCDC_LCDICR	0x38 | 
|  | 107 | #define LCDICR_INT_SYN	(1<<2) | 
|  | 108 | #define LCDICR_INT_CON	(1) | 
|  | 109 |  | 
|  | 110 | #define LCDC_LCDISR	0x40 | 
|  | 111 | #define LCDISR_UDR_ERR	(1<<3) | 
|  | 112 | #define LCDISR_ERR_RES	(1<<2) | 
|  | 113 | #define LCDISR_EOF	(1<<1) | 
|  | 114 | #define LCDISR_BOF	(1<<0) | 
|  | 115 |  | 
| Sascha Hauer | 343684f | 2009-03-19 08:25:41 +0100 | [diff] [blame] | 116 | /* Used fb-mode. Can be set on kernel command line, therefore file-static. */ | 
|  | 117 | static const char *fb_mode; | 
|  | 118 |  | 
|  | 119 |  | 
| Sascha Hauer | 24b9baf | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 120 | /* | 
|  | 121 | * These are the bitfields for each | 
|  | 122 | * display depth that we support. | 
|  | 123 | */ | 
|  | 124 | struct imxfb_rgb { | 
|  | 125 | struct fb_bitfield	red; | 
|  | 126 | struct fb_bitfield	green; | 
|  | 127 | struct fb_bitfield	blue; | 
|  | 128 | struct fb_bitfield	transp; | 
|  | 129 | }; | 
|  | 130 |  | 
| Sascha Hauer | 24b9baf | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 131 | struct imxfb_info { | 
|  | 132 | struct platform_device  *pdev; | 
|  | 133 | void __iomem		*regs; | 
| Sascha Hauer | 13aaea0 | 2012-03-07 09:30:36 +0100 | [diff] [blame] | 134 | struct clk		*clk_ipg; | 
|  | 135 | struct clk		*clk_ahb; | 
|  | 136 | struct clk		*clk_per; | 
| Sascha Hauer | 24b9baf | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 137 |  | 
| Sascha Hauer | 24b9baf | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 138 | /* | 
|  | 139 | * These are the addresses we mapped | 
|  | 140 | * the framebuffer memory region to. | 
|  | 141 | */ | 
|  | 142 | dma_addr_t		map_dma; | 
|  | 143 | u_char			*map_cpu; | 
|  | 144 | u_int			map_size; | 
|  | 145 |  | 
|  | 146 | u_char			*screen_cpu; | 
|  | 147 | dma_addr_t		screen_dma; | 
|  | 148 | u_int			palette_size; | 
|  | 149 |  | 
|  | 150 | dma_addr_t		dbar1; | 
|  | 151 | dma_addr_t		dbar2; | 
|  | 152 |  | 
|  | 153 | u_int			pcr; | 
|  | 154 | u_int			pwmr; | 
|  | 155 | u_int			lscr1; | 
|  | 156 | u_int			dmacr; | 
|  | 157 | u_int			cmap_inverse:1, | 
|  | 158 | cmap_static:1, | 
|  | 159 | unused:30; | 
|  | 160 |  | 
| Sascha Hauer | 343684f | 2009-03-19 08:25:41 +0100 | [diff] [blame] | 161 | struct imx_fb_videomode *mode; | 
|  | 162 | int			num_modes; | 
| Eric Bénard | 81ef806 | 2010-08-02 08:39:55 +0100 | [diff] [blame] | 163 | #ifdef PWMR_BACKLIGHT_AVAILABLE | 
| Eric Bénard | 7a2bb23 | 2010-07-16 15:09:07 +0200 | [diff] [blame] | 164 | struct backlight_device *bl; | 
| Eric Bénard | 81ef806 | 2010-08-02 08:39:55 +0100 | [diff] [blame] | 165 | #endif | 
| Sascha Hauer | 343684f | 2009-03-19 08:25:41 +0100 | [diff] [blame] | 166 |  | 
| Sascha Hauer | 24b9baf | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 167 | void (*lcd_power)(int); | 
|  | 168 | void (*backlight_power)(int); | 
|  | 169 | }; | 
|  | 170 |  | 
|  | 171 | #define IMX_NAME	"IMX" | 
|  | 172 |  | 
|  | 173 | /* | 
|  | 174 | * Minimum X and Y resolutions | 
|  | 175 | */ | 
|  | 176 | #define MIN_XRES	64 | 
|  | 177 | #define MIN_YRES	64 | 
|  | 178 |  | 
| Sascha Hauer | 1512222 | 2009-01-26 17:31:02 +0100 | [diff] [blame] | 179 | /* Actually this really is 18bit support, the lowest 2 bits of each colour | 
|  | 180 | * are unused in hardware. We claim to have 24bit support to make software | 
|  | 181 | * like X work, which does not support 18bit. | 
|  | 182 | */ | 
|  | 183 | static struct imxfb_rgb def_rgb_18 = { | 
|  | 184 | .red	= {.offset = 16, .length = 8,}, | 
|  | 185 | .green	= {.offset = 8, .length = 8,}, | 
|  | 186 | .blue	= {.offset = 0, .length = 8,}, | 
|  | 187 | .transp = {.offset = 0, .length = 0,}, | 
|  | 188 | }; | 
|  | 189 |  | 
| Sascha Hauer | 80eee6b | 2008-12-16 11:44:09 +0100 | [diff] [blame] | 190 | static struct imxfb_rgb def_rgb_16_tft = { | 
|  | 191 | .red	= {.offset = 11, .length = 5,}, | 
|  | 192 | .green	= {.offset = 5, .length = 6,}, | 
|  | 193 | .blue	= {.offset = 0, .length = 5,}, | 
|  | 194 | .transp = {.offset = 0, .length = 0,}, | 
|  | 195 | }; | 
|  | 196 |  | 
|  | 197 | static struct imxfb_rgb def_rgb_16_stn = { | 
| Sascha Hauer | 66c8719 | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 198 | .red	= {.offset = 8, .length = 4,}, | 
|  | 199 | .green	= {.offset = 4, .length = 4,}, | 
|  | 200 | .blue	= {.offset = 0, .length = 4,}, | 
|  | 201 | .transp = {.offset = 0, .length = 0,}, | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 202 | }; | 
|  | 203 |  | 
|  | 204 | static struct imxfb_rgb def_rgb_8 = { | 
| Sascha Hauer | 66c8719 | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 205 | .red	= {.offset = 0, .length = 8,}, | 
|  | 206 | .green	= {.offset = 0, .length = 8,}, | 
|  | 207 | .blue	= {.offset = 0, .length = 8,}, | 
|  | 208 | .transp = {.offset = 0, .length = 0,}, | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 209 | }; | 
|  | 210 |  | 
| Sascha Hauer | 66c8719 | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 211 | static int imxfb_activate_var(struct fb_var_screeninfo *var, | 
|  | 212 | struct fb_info *info); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 213 |  | 
|  | 214 | static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf) | 
|  | 215 | { | 
|  | 216 | chan &= 0xffff; | 
|  | 217 | chan >>= 16 - bf->length; | 
|  | 218 | return chan << bf->offset; | 
|  | 219 | } | 
|  | 220 |  | 
| Sascha Hauer | 66c8719 | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 221 | static int imxfb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue, | 
|  | 222 | u_int trans, struct fb_info *info) | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 223 | { | 
|  | 224 | struct imxfb_info *fbi = info->par; | 
|  | 225 | u_int val, ret = 1; | 
|  | 226 |  | 
|  | 227 | #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) | 
|  | 228 | if (regno < fbi->palette_size) { | 
|  | 229 | val = (CNVT_TOHW(red, 4) << 8) | | 
|  | 230 | (CNVT_TOHW(green,4) << 4) | | 
|  | 231 | CNVT_TOHW(blue,  4); | 
|  | 232 |  | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 233 | writel(val, fbi->regs + 0x800 + (regno << 2)); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 234 | ret = 0; | 
|  | 235 | } | 
|  | 236 | return ret; | 
|  | 237 | } | 
|  | 238 |  | 
| Sascha Hauer | 66c8719 | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 239 | static int imxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 240 | u_int trans, struct fb_info *info) | 
|  | 241 | { | 
|  | 242 | struct imxfb_info *fbi = info->par; | 
|  | 243 | unsigned int val; | 
|  | 244 | int ret = 1; | 
|  | 245 |  | 
|  | 246 | /* | 
|  | 247 | * If inverse mode was selected, invert all the colours | 
|  | 248 | * rather than the register number.  The register number | 
|  | 249 | * is what you poke into the framebuffer to produce the | 
|  | 250 | * colour you requested. | 
|  | 251 | */ | 
|  | 252 | if (fbi->cmap_inverse) { | 
|  | 253 | red   = 0xffff - red; | 
|  | 254 | green = 0xffff - green; | 
|  | 255 | blue  = 0xffff - blue; | 
|  | 256 | } | 
|  | 257 |  | 
|  | 258 | /* | 
|  | 259 | * If greyscale is true, then we convert the RGB value | 
|  | 260 | * to greyscale no mater what visual we are using. | 
|  | 261 | */ | 
|  | 262 | if (info->var.grayscale) | 
|  | 263 | red = green = blue = (19595 * red + 38470 * green + | 
|  | 264 | 7471 * blue) >> 16; | 
|  | 265 |  | 
|  | 266 | switch (info->fix.visual) { | 
|  | 267 | case FB_VISUAL_TRUECOLOR: | 
|  | 268 | /* | 
|  | 269 | * 12 or 16-bit True Colour.  We encode the RGB value | 
|  | 270 | * according to the RGB bitfield information. | 
|  | 271 | */ | 
|  | 272 | if (regno < 16) { | 
|  | 273 | u32 *pal = info->pseudo_palette; | 
|  | 274 |  | 
|  | 275 | val  = chan_to_field(red, &info->var.red); | 
|  | 276 | val |= chan_to_field(green, &info->var.green); | 
|  | 277 | val |= chan_to_field(blue, &info->var.blue); | 
|  | 278 |  | 
|  | 279 | pal[regno] = val; | 
|  | 280 | ret = 0; | 
|  | 281 | } | 
|  | 282 | break; | 
|  | 283 |  | 
|  | 284 | case FB_VISUAL_STATIC_PSEUDOCOLOR: | 
|  | 285 | case FB_VISUAL_PSEUDOCOLOR: | 
|  | 286 | ret = imxfb_setpalettereg(regno, red, green, blue, trans, info); | 
|  | 287 | break; | 
|  | 288 | } | 
|  | 289 |  | 
|  | 290 | return ret; | 
|  | 291 | } | 
|  | 292 |  | 
| Sascha Hauer | 343684f | 2009-03-19 08:25:41 +0100 | [diff] [blame] | 293 | static const struct imx_fb_videomode *imxfb_find_mode(struct imxfb_info *fbi) | 
|  | 294 | { | 
|  | 295 | struct imx_fb_videomode *m; | 
|  | 296 | int i; | 
|  | 297 |  | 
|  | 298 | for (i = 0, m = &fbi->mode[0]; i < fbi->num_modes; i++, m++) { | 
|  | 299 | if (!strcmp(m->mode.name, fb_mode)) | 
|  | 300 | return m; | 
|  | 301 | } | 
|  | 302 | return NULL; | 
|  | 303 | } | 
|  | 304 |  | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 305 | /* | 
|  | 306 | *  imxfb_check_var(): | 
|  | 307 | *    Round up in the following order: bits_per_pixel, xres, | 
|  | 308 | *    yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale, | 
|  | 309 | *    bitfields, horizontal timing, vertical timing. | 
|  | 310 | */ | 
| Sascha Hauer | 66c8719 | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 311 | static int imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 312 | { | 
|  | 313 | struct imxfb_info *fbi = info->par; | 
| Sascha Hauer | 80eee6b | 2008-12-16 11:44:09 +0100 | [diff] [blame] | 314 | struct imxfb_rgb *rgb; | 
| Sascha Hauer | 343684f | 2009-03-19 08:25:41 +0100 | [diff] [blame] | 315 | const struct imx_fb_videomode *imxfb_mode; | 
|  | 316 | unsigned long lcd_clk; | 
|  | 317 | unsigned long long tmp; | 
|  | 318 | u32 pcr = 0; | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 319 |  | 
|  | 320 | if (var->xres < MIN_XRES) | 
|  | 321 | var->xres = MIN_XRES; | 
|  | 322 | if (var->yres < MIN_YRES) | 
|  | 323 | var->yres = MIN_YRES; | 
| Sascha Hauer | 343684f | 2009-03-19 08:25:41 +0100 | [diff] [blame] | 324 |  | 
|  | 325 | imxfb_mode = imxfb_find_mode(fbi); | 
|  | 326 | if (!imxfb_mode) | 
|  | 327 | return -EINVAL; | 
|  | 328 |  | 
|  | 329 | var->xres		= imxfb_mode->mode.xres; | 
|  | 330 | var->yres		= imxfb_mode->mode.yres; | 
|  | 331 | var->bits_per_pixel	= imxfb_mode->bpp; | 
|  | 332 | var->pixclock		= imxfb_mode->mode.pixclock; | 
|  | 333 | var->hsync_len		= imxfb_mode->mode.hsync_len; | 
|  | 334 | var->left_margin	= imxfb_mode->mode.left_margin; | 
|  | 335 | var->right_margin	= imxfb_mode->mode.right_margin; | 
|  | 336 | var->vsync_len		= imxfb_mode->mode.vsync_len; | 
|  | 337 | var->upper_margin	= imxfb_mode->mode.upper_margin; | 
|  | 338 | var->lower_margin	= imxfb_mode->mode.lower_margin; | 
|  | 339 | var->sync		= imxfb_mode->mode.sync; | 
|  | 340 | var->xres_virtual	= max(var->xres_virtual, var->xres); | 
|  | 341 | var->yres_virtual	= max(var->yres_virtual, var->yres); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 342 |  | 
|  | 343 | pr_debug("var->bits_per_pixel=%d\n", var->bits_per_pixel); | 
| Sascha Hauer | 343684f | 2009-03-19 08:25:41 +0100 | [diff] [blame] | 344 |  | 
| Sascha Hauer | 13aaea0 | 2012-03-07 09:30:36 +0100 | [diff] [blame] | 345 | lcd_clk = clk_get_rate(fbi->clk_per); | 
| Sascha Hauer | 343684f | 2009-03-19 08:25:41 +0100 | [diff] [blame] | 346 |  | 
|  | 347 | tmp = var->pixclock * (unsigned long long)lcd_clk; | 
|  | 348 |  | 
|  | 349 | do_div(tmp, 1000000); | 
|  | 350 |  | 
|  | 351 | if (do_div(tmp, 1000000) > 500000) | 
|  | 352 | tmp++; | 
|  | 353 |  | 
|  | 354 | pcr = (unsigned int)tmp; | 
|  | 355 |  | 
|  | 356 | if (--pcr > 0x3F) { | 
|  | 357 | pcr = 0x3F; | 
|  | 358 | printk(KERN_WARNING "Must limit pixel clock to %luHz\n", | 
|  | 359 | lcd_clk / pcr); | 
|  | 360 | } | 
|  | 361 |  | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 362 | switch (var->bits_per_pixel) { | 
| Sascha Hauer | 1512222 | 2009-01-26 17:31:02 +0100 | [diff] [blame] | 363 | case 32: | 
| Sascha Hauer | 343684f | 2009-03-19 08:25:41 +0100 | [diff] [blame] | 364 | pcr |= PCR_BPIX_18; | 
| Sascha Hauer | 1512222 | 2009-01-26 17:31:02 +0100 | [diff] [blame] | 365 | rgb = &def_rgb_18; | 
|  | 366 | break; | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 367 | case 16: | 
| Sascha Hauer | 80eee6b | 2008-12-16 11:44:09 +0100 | [diff] [blame] | 368 | default: | 
| Sascha Hauer | 343684f | 2009-03-19 08:25:41 +0100 | [diff] [blame] | 369 | if (cpu_is_mx1()) | 
|  | 370 | pcr |= PCR_BPIX_12; | 
|  | 371 | else | 
|  | 372 | pcr |= PCR_BPIX_16; | 
|  | 373 |  | 
|  | 374 | if (imxfb_mode->pcr & PCR_TFT) | 
| Sascha Hauer | 80eee6b | 2008-12-16 11:44:09 +0100 | [diff] [blame] | 375 | rgb = &def_rgb_16_tft; | 
|  | 376 | else | 
|  | 377 | rgb = &def_rgb_16_stn; | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 378 | break; | 
|  | 379 | case 8: | 
| Sascha Hauer | 343684f | 2009-03-19 08:25:41 +0100 | [diff] [blame] | 380 | pcr |= PCR_BPIX_8; | 
| Sascha Hauer | 80eee6b | 2008-12-16 11:44:09 +0100 | [diff] [blame] | 381 | rgb = &def_rgb_8; | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 382 | break; | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 383 | } | 
|  | 384 |  | 
| Sascha Hauer | 343684f | 2009-03-19 08:25:41 +0100 | [diff] [blame] | 385 | /* add sync polarities */ | 
|  | 386 | pcr |= imxfb_mode->pcr & ~(0x3f | (7 << 25)); | 
|  | 387 |  | 
|  | 388 | fbi->pcr = pcr; | 
|  | 389 |  | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 390 | /* | 
|  | 391 | * Copy the RGB parameters for this display | 
|  | 392 | * from the machine specific parameters. | 
|  | 393 | */ | 
| Sascha Hauer | 80eee6b | 2008-12-16 11:44:09 +0100 | [diff] [blame] | 394 | var->red    = rgb->red; | 
|  | 395 | var->green  = rgb->green; | 
|  | 396 | var->blue   = rgb->blue; | 
|  | 397 | var->transp = rgb->transp; | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 398 |  | 
|  | 399 | pr_debug("RGBT length = %d:%d:%d:%d\n", | 
|  | 400 | var->red.length, var->green.length, var->blue.length, | 
|  | 401 | var->transp.length); | 
|  | 402 |  | 
|  | 403 | pr_debug("RGBT offset = %d:%d:%d:%d\n", | 
|  | 404 | var->red.offset, var->green.offset, var->blue.offset, | 
|  | 405 | var->transp.offset); | 
|  | 406 |  | 
|  | 407 | return 0; | 
|  | 408 | } | 
|  | 409 |  | 
|  | 410 | /* | 
|  | 411 | * imxfb_set_par(): | 
|  | 412 | *	Set the user defined part of the display for the specified console | 
|  | 413 | */ | 
|  | 414 | static int imxfb_set_par(struct fb_info *info) | 
|  | 415 | { | 
|  | 416 | struct imxfb_info *fbi = info->par; | 
|  | 417 | struct fb_var_screeninfo *var = &info->var; | 
|  | 418 |  | 
| Sascha Hauer | 1512222 | 2009-01-26 17:31:02 +0100 | [diff] [blame] | 419 | if (var->bits_per_pixel == 16 || var->bits_per_pixel == 32) | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 420 | info->fix.visual = FB_VISUAL_TRUECOLOR; | 
|  | 421 | else if (!fbi->cmap_static) | 
|  | 422 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; | 
|  | 423 | else { | 
|  | 424 | /* | 
|  | 425 | * Some people have weird ideas about wanting static | 
|  | 426 | * pseudocolor maps.  I suspect their user space | 
|  | 427 | * applications are broken. | 
|  | 428 | */ | 
|  | 429 | info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR; | 
|  | 430 | } | 
|  | 431 |  | 
| Sascha Hauer | 66c8719 | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 432 | info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8; | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 433 | fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16; | 
|  | 434 |  | 
|  | 435 | imxfb_activate_var(var, info); | 
|  | 436 |  | 
|  | 437 | return 0; | 
|  | 438 | } | 
|  | 439 |  | 
| Eric Bénard | 81ef806 | 2010-08-02 08:39:55 +0100 | [diff] [blame] | 440 | #ifdef PWMR_BACKLIGHT_AVAILABLE | 
| Eric Bénard | 7a2bb23 | 2010-07-16 15:09:07 +0200 | [diff] [blame] | 441 | static int imxfb_bl_get_brightness(struct backlight_device *bl) | 
|  | 442 | { | 
|  | 443 | struct imxfb_info *fbi = bl_get_data(bl); | 
|  | 444 |  | 
|  | 445 | return readl(fbi->regs + LCDC_PWMR) & 0xFF; | 
|  | 446 | } | 
|  | 447 |  | 
|  | 448 | static int imxfb_bl_update_status(struct backlight_device *bl) | 
|  | 449 | { | 
|  | 450 | struct imxfb_info *fbi = bl_get_data(bl); | 
|  | 451 | int brightness = bl->props.brightness; | 
|  | 452 |  | 
|  | 453 | if (bl->props.power != FB_BLANK_UNBLANK) | 
|  | 454 | brightness = 0; | 
|  | 455 | if (bl->props.fb_blank != FB_BLANK_UNBLANK) | 
|  | 456 | brightness = 0; | 
|  | 457 |  | 
|  | 458 | fbi->pwmr = (fbi->pwmr & ~0xFF) | brightness; | 
|  | 459 |  | 
| Sascha Hauer | 13aaea0 | 2012-03-07 09:30:36 +0100 | [diff] [blame] | 460 | if (bl->props.fb_blank != FB_BLANK_UNBLANK) { | 
|  | 461 | clk_prepare_enable(fbi->clk_ipg); | 
|  | 462 | clk_prepare_enable(fbi->clk_ahb); | 
|  | 463 | clk_prepare_enable(fbi->clk_per); | 
|  | 464 | } | 
| Eric Bénard | 7a2bb23 | 2010-07-16 15:09:07 +0200 | [diff] [blame] | 465 | writel(fbi->pwmr, fbi->regs + LCDC_PWMR); | 
| Sascha Hauer | 13aaea0 | 2012-03-07 09:30:36 +0100 | [diff] [blame] | 466 | if (bl->props.fb_blank != FB_BLANK_UNBLANK) { | 
|  | 467 | clk_disable_unprepare(fbi->clk_per); | 
|  | 468 | clk_disable_unprepare(fbi->clk_ahb); | 
|  | 469 | clk_disable_unprepare(fbi->clk_ipg); | 
|  | 470 | } | 
| Eric Bénard | 7a2bb23 | 2010-07-16 15:09:07 +0200 | [diff] [blame] | 471 |  | 
|  | 472 | return 0; | 
|  | 473 | } | 
|  | 474 |  | 
|  | 475 | static const struct backlight_ops imxfb_lcdc_bl_ops = { | 
|  | 476 | .update_status = imxfb_bl_update_status, | 
|  | 477 | .get_brightness = imxfb_bl_get_brightness, | 
|  | 478 | }; | 
|  | 479 |  | 
|  | 480 | static void imxfb_init_backlight(struct imxfb_info *fbi) | 
|  | 481 | { | 
|  | 482 | struct backlight_properties props; | 
|  | 483 | struct backlight_device	*bl; | 
|  | 484 |  | 
|  | 485 | if (fbi->bl) | 
|  | 486 | return; | 
|  | 487 |  | 
|  | 488 | memset(&props, 0, sizeof(struct backlight_properties)); | 
|  | 489 | props.max_brightness = 0xff; | 
| Matthew Garrett | bb7ca74 | 2011-03-22 16:30:21 -0700 | [diff] [blame] | 490 | props.type = BACKLIGHT_RAW; | 
| Eric Bénard | 7a2bb23 | 2010-07-16 15:09:07 +0200 | [diff] [blame] | 491 | writel(fbi->pwmr, fbi->regs + LCDC_PWMR); | 
|  | 492 |  | 
|  | 493 | bl = backlight_device_register("imxfb-bl", &fbi->pdev->dev, fbi, | 
|  | 494 | &imxfb_lcdc_bl_ops, &props); | 
|  | 495 | if (IS_ERR(bl)) { | 
|  | 496 | dev_err(&fbi->pdev->dev, "error %ld on backlight register\n", | 
|  | 497 | PTR_ERR(bl)); | 
|  | 498 | return; | 
|  | 499 | } | 
|  | 500 |  | 
|  | 501 | fbi->bl = bl; | 
|  | 502 | bl->props.power = FB_BLANK_UNBLANK; | 
|  | 503 | bl->props.fb_blank = FB_BLANK_UNBLANK; | 
|  | 504 | bl->props.brightness = imxfb_bl_get_brightness(bl); | 
|  | 505 | } | 
|  | 506 |  | 
|  | 507 | static void imxfb_exit_backlight(struct imxfb_info *fbi) | 
|  | 508 | { | 
|  | 509 | if (fbi->bl) | 
|  | 510 | backlight_device_unregister(fbi->bl); | 
|  | 511 | } | 
| Eric Bénard | 81ef806 | 2010-08-02 08:39:55 +0100 | [diff] [blame] | 512 | #endif | 
| Eric Bénard | 7a2bb23 | 2010-07-16 15:09:07 +0200 | [diff] [blame] | 513 |  | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 514 | static void imxfb_enable_controller(struct imxfb_info *fbi) | 
|  | 515 | { | 
|  | 516 | pr_debug("Enabling LCD controller\n"); | 
|  | 517 |  | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 518 | writel(fbi->screen_dma, fbi->regs + LCDC_SSA); | 
|  | 519 |  | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 520 | /* panning offset 0 (0 pixel offset)        */ | 
|  | 521 | writel(0x00000000, fbi->regs + LCDC_POS); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 522 |  | 
|  | 523 | /* disable hardware cursor */ | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 524 | writel(readl(fbi->regs + LCDC_CPOS) & ~(CPOS_CC0 | CPOS_CC1), | 
|  | 525 | fbi->regs + LCDC_CPOS); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 526 |  | 
| Sascha Hauer | f142b61 | 2011-03-03 15:12:44 +0100 | [diff] [blame] | 527 | /* | 
|  | 528 | * RMCR_LCDC_EN_MX1 is present on i.MX1 only, but doesn't hurt | 
|  | 529 | * on other SoCs | 
|  | 530 | */ | 
|  | 531 | writel(RMCR_LCDC_EN_MX1, fbi->regs + LCDC_RMCR); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 532 |  | 
| Sascha Hauer | 13aaea0 | 2012-03-07 09:30:36 +0100 | [diff] [blame] | 533 | clk_prepare_enable(fbi->clk_ipg); | 
|  | 534 | clk_prepare_enable(fbi->clk_ahb); | 
|  | 535 | clk_prepare_enable(fbi->clk_per); | 
| Sascha Hauer | f909ef6 | 2009-01-15 15:21:00 +0100 | [diff] [blame] | 536 |  | 
| Sascha Hauer | 66c8719 | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 537 | if (fbi->backlight_power) | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 538 | fbi->backlight_power(1); | 
| Sascha Hauer | 66c8719 | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 539 | if (fbi->lcd_power) | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 540 | fbi->lcd_power(1); | 
|  | 541 | } | 
|  | 542 |  | 
|  | 543 | static void imxfb_disable_controller(struct imxfb_info *fbi) | 
|  | 544 | { | 
|  | 545 | pr_debug("Disabling LCD controller\n"); | 
|  | 546 |  | 
| Sascha Hauer | 66c8719 | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 547 | if (fbi->backlight_power) | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 548 | fbi->backlight_power(0); | 
| Sascha Hauer | 66c8719 | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 549 | if (fbi->lcd_power) | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 550 | fbi->lcd_power(0); | 
|  | 551 |  | 
| Sascha Hauer | 13aaea0 | 2012-03-07 09:30:36 +0100 | [diff] [blame] | 552 | clk_disable_unprepare(fbi->clk_per); | 
|  | 553 | clk_disable_unprepare(fbi->clk_ipg); | 
|  | 554 | clk_disable_unprepare(fbi->clk_ahb); | 
| Sascha Hauer | f909ef6 | 2009-01-15 15:21:00 +0100 | [diff] [blame] | 555 |  | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 556 | writel(0, fbi->regs + LCDC_RMCR); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 557 | } | 
|  | 558 |  | 
|  | 559 | static int imxfb_blank(int blank, struct fb_info *info) | 
|  | 560 | { | 
|  | 561 | struct imxfb_info *fbi = info->par; | 
|  | 562 |  | 
|  | 563 | pr_debug("imxfb_blank: blank=%d\n", blank); | 
|  | 564 |  | 
|  | 565 | switch (blank) { | 
|  | 566 | case FB_BLANK_POWERDOWN: | 
|  | 567 | case FB_BLANK_VSYNC_SUSPEND: | 
|  | 568 | case FB_BLANK_HSYNC_SUSPEND: | 
|  | 569 | case FB_BLANK_NORMAL: | 
|  | 570 | imxfb_disable_controller(fbi); | 
|  | 571 | break; | 
|  | 572 |  | 
|  | 573 | case FB_BLANK_UNBLANK: | 
|  | 574 | imxfb_enable_controller(fbi); | 
|  | 575 | break; | 
|  | 576 | } | 
|  | 577 | return 0; | 
|  | 578 | } | 
|  | 579 |  | 
|  | 580 | static struct fb_ops imxfb_ops = { | 
|  | 581 | .owner		= THIS_MODULE, | 
|  | 582 | .fb_check_var	= imxfb_check_var, | 
|  | 583 | .fb_set_par	= imxfb_set_par, | 
|  | 584 | .fb_setcolreg	= imxfb_setcolreg, | 
|  | 585 | .fb_fillrect	= cfb_fillrect, | 
|  | 586 | .fb_copyarea	= cfb_copyarea, | 
|  | 587 | .fb_imageblit	= cfb_imageblit, | 
|  | 588 | .fb_blank	= imxfb_blank, | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 589 | }; | 
|  | 590 |  | 
|  | 591 | /* | 
|  | 592 | * imxfb_activate_var(): | 
|  | 593 | *	Configures LCD Controller based on entries in var parameter.  Settings are | 
|  | 594 | *	only written to the controller if changes were made. | 
|  | 595 | */ | 
|  | 596 | static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info) | 
|  | 597 | { | 
|  | 598 | struct imxfb_info *fbi = info->par; | 
| Sascha Hauer | f909ef6 | 2009-01-15 15:21:00 +0100 | [diff] [blame] | 599 |  | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 600 | pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n", | 
|  | 601 | var->xres, var->hsync_len, | 
|  | 602 | var->left_margin, var->right_margin); | 
|  | 603 | pr_debug("var: yres=%d vslen=%d um=%d bm=%d\n", | 
|  | 604 | var->yres, var->vsync_len, | 
|  | 605 | var->upper_margin, var->lower_margin); | 
|  | 606 |  | 
|  | 607 | #if DEBUG_VAR | 
|  | 608 | if (var->xres < 16        || var->xres > 1024) | 
|  | 609 | printk(KERN_ERR "%s: invalid xres %d\n", | 
|  | 610 | info->fix.id, var->xres); | 
|  | 611 | if (var->hsync_len < 1    || var->hsync_len > 64) | 
|  | 612 | printk(KERN_ERR "%s: invalid hsync_len %d\n", | 
|  | 613 | info->fix.id, var->hsync_len); | 
|  | 614 | if (var->left_margin > 255) | 
|  | 615 | printk(KERN_ERR "%s: invalid left_margin %d\n", | 
|  | 616 | info->fix.id, var->left_margin); | 
|  | 617 | if (var->right_margin > 255) | 
|  | 618 | printk(KERN_ERR "%s: invalid right_margin %d\n", | 
|  | 619 | info->fix.id, var->right_margin); | 
| Fabio Estevam | 6032891 | 2010-12-24 10:28:24 -0200 | [diff] [blame] | 620 | if (var->yres < 1 || var->yres > YMAX_MASK) | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 621 | printk(KERN_ERR "%s: invalid yres %d\n", | 
|  | 622 | info->fix.id, var->yres); | 
|  | 623 | if (var->vsync_len > 100) | 
|  | 624 | printk(KERN_ERR "%s: invalid vsync_len %d\n", | 
|  | 625 | info->fix.id, var->vsync_len); | 
|  | 626 | if (var->upper_margin > 63) | 
|  | 627 | printk(KERN_ERR "%s: invalid upper_margin %d\n", | 
|  | 628 | info->fix.id, var->upper_margin); | 
|  | 629 | if (var->lower_margin > 255) | 
|  | 630 | printk(KERN_ERR "%s: invalid lower_margin %d\n", | 
|  | 631 | info->fix.id, var->lower_margin); | 
|  | 632 | #endif | 
|  | 633 |  | 
| Sascha Hauer | 343684f | 2009-03-19 08:25:41 +0100 | [diff] [blame] | 634 | /* physical screen start address	    */ | 
|  | 635 | writel(VPW_VPW(var->xres * var->bits_per_pixel / 8 / 4), | 
|  | 636 | fbi->regs + LCDC_VPW); | 
|  | 637 |  | 
| Sascha Hauer | 7e8549b | 2009-02-14 16:29:38 +0100 | [diff] [blame] | 638 | writel(HCR_H_WIDTH(var->hsync_len - 1) | | 
|  | 639 | HCR_H_WAIT_1(var->right_margin - 1) | | 
|  | 640 | HCR_H_WAIT_2(var->left_margin - 3), | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 641 | fbi->regs + LCDC_HCR); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 642 |  | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 643 | writel(VCR_V_WIDTH(var->vsync_len) | | 
| Sascha Hauer | d6ed575 | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 644 | VCR_V_WAIT_1(var->lower_margin) | | 
|  | 645 | VCR_V_WAIT_2(var->upper_margin), | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 646 | fbi->regs + LCDC_VCR); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 647 |  | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 648 | writel(SIZE_XMAX(var->xres) | SIZE_YMAX(var->yres), | 
|  | 649 | fbi->regs + LCDC_SIZE); | 
| Sascha Hauer | f909ef6 | 2009-01-15 15:21:00 +0100 | [diff] [blame] | 650 |  | 
| Sascha Hauer | 343684f | 2009-03-19 08:25:41 +0100 | [diff] [blame] | 651 | writel(fbi->pcr, fbi->regs + LCDC_PCR); | 
| Eric Bénard | 81ef806 | 2010-08-02 08:39:55 +0100 | [diff] [blame] | 652 | #ifndef PWMR_BACKLIGHT_AVAILABLE | 
|  | 653 | writel(fbi->pwmr, fbi->regs + LCDC_PWMR); | 
|  | 654 | #endif | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 655 | writel(fbi->lscr1, fbi->regs + LCDC_LSCR1); | 
|  | 656 | writel(fbi->dmacr, fbi->regs + LCDC_DMACR); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 657 |  | 
|  | 658 | return 0; | 
|  | 659 | } | 
|  | 660 |  | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 661 | #ifdef CONFIG_PM | 
|  | 662 | /* | 
|  | 663 | * Power management hooks.  Note that we won't be called from IRQ context, | 
|  | 664 | * unlike the blank functions above, so we may sleep. | 
|  | 665 | */ | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 666 | static int imxfb_suspend(struct platform_device *dev, pm_message_t state) | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 667 | { | 
| Uwe Kleine-König | 1ec5620 | 2010-02-02 13:44:10 -0800 | [diff] [blame] | 668 | struct fb_info *info = platform_get_drvdata(dev); | 
|  | 669 | struct imxfb_info *fbi = info->par; | 
| Sascha Hauer | 66c8719 | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 670 |  | 
|  | 671 | pr_debug("%s\n", __func__); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 672 |  | 
| Russell King | 9480e30 | 2005-10-28 09:52:56 -0700 | [diff] [blame] | 673 | imxfb_disable_controller(fbi); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 674 | return 0; | 
|  | 675 | } | 
|  | 676 |  | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 677 | static int imxfb_resume(struct platform_device *dev) | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 678 | { | 
| Uwe Kleine-König | 1ec5620 | 2010-02-02 13:44:10 -0800 | [diff] [blame] | 679 | struct fb_info *info = platform_get_drvdata(dev); | 
|  | 680 | struct imxfb_info *fbi = info->par; | 
| Sascha Hauer | 66c8719 | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 681 |  | 
|  | 682 | pr_debug("%s\n", __func__); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 683 |  | 
| Russell King | 9480e30 | 2005-10-28 09:52:56 -0700 | [diff] [blame] | 684 | imxfb_enable_controller(fbi); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 685 | return 0; | 
|  | 686 | } | 
|  | 687 | #else | 
|  | 688 | #define imxfb_suspend	NULL | 
|  | 689 | #define imxfb_resume	NULL | 
|  | 690 | #endif | 
|  | 691 |  | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 692 | static int __init imxfb_init_fbinfo(struct platform_device *pdev) | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 693 | { | 
| Sascha Hauer | 2788927 | 2008-12-16 11:44:09 +0100 | [diff] [blame] | 694 | struct imx_fb_platform_data *pdata = pdev->dev.platform_data; | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 695 | struct fb_info *info = dev_get_drvdata(&pdev->dev); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 696 | struct imxfb_info *fbi = info->par; | 
| Sascha Hauer | 343684f | 2009-03-19 08:25:41 +0100 | [diff] [blame] | 697 | struct imx_fb_videomode *m; | 
|  | 698 | int i; | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 699 |  | 
| Harvey Harrison | 5ae1217 | 2008-04-28 02:15:47 -0700 | [diff] [blame] | 700 | pr_debug("%s\n",__func__); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 701 |  | 
| Sascha Hauer | 66c8719 | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 702 | info->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 703 | if (!info->pseudo_palette) | 
|  | 704 | return -ENOMEM; | 
|  | 705 |  | 
|  | 706 | memset(fbi, 0, sizeof(struct imxfb_info)); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 707 |  | 
|  | 708 | strlcpy(info->fix.id, IMX_NAME, sizeof(info->fix.id)); | 
|  | 709 |  | 
| Sascha Hauer | 66c8719 | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 710 | info->fix.type			= FB_TYPE_PACKED_PIXELS; | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 711 | info->fix.type_aux		= 0; | 
|  | 712 | info->fix.xpanstep		= 0; | 
|  | 713 | info->fix.ypanstep		= 0; | 
|  | 714 | info->fix.ywrapstep		= 0; | 
| Sascha Hauer | 66c8719 | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 715 | info->fix.accel			= FB_ACCEL_NONE; | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 716 |  | 
|  | 717 | info->var.nonstd		= 0; | 
|  | 718 | info->var.activate		= FB_ACTIVATE_NOW; | 
|  | 719 | info->var.height		= -1; | 
|  | 720 | info->var.width	= -1; | 
|  | 721 | info->var.accel_flags		= 0; | 
| Sascha Hauer | 66c8719 | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 722 | info->var.vmode			= FB_VMODE_NONINTERLACED; | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 723 |  | 
|  | 724 | info->fbops			= &imxfb_ops; | 
| Sascha Hauer | 66c8719 | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 725 | info->flags			= FBINFO_FLAG_DEFAULT | | 
|  | 726 | FBINFO_READS_FAST; | 
| Sascha Hauer | 2788927 | 2008-12-16 11:44:09 +0100 | [diff] [blame] | 727 | info->var.grayscale		= pdata->cmap_greyscale; | 
|  | 728 | fbi->cmap_inverse		= pdata->cmap_inverse; | 
|  | 729 | fbi->cmap_static		= pdata->cmap_static; | 
| Sascha Hauer | 2788927 | 2008-12-16 11:44:09 +0100 | [diff] [blame] | 730 | fbi->lscr1			= pdata->lscr1; | 
|  | 731 | fbi->dmacr			= pdata->dmacr; | 
|  | 732 | fbi->pwmr			= pdata->pwmr; | 
|  | 733 | fbi->lcd_power			= pdata->lcd_power; | 
|  | 734 | fbi->backlight_power		= pdata->backlight_power; | 
| Sascha Hauer | 343684f | 2009-03-19 08:25:41 +0100 | [diff] [blame] | 735 |  | 
|  | 736 | for (i = 0, m = &pdata->mode[0]; i < pdata->num_modes; i++, m++) | 
|  | 737 | info->fix.smem_len = max_t(size_t, info->fix.smem_len, | 
|  | 738 | m->mode.xres * m->mode.yres * m->bpp / 8); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 739 |  | 
|  | 740 | return 0; | 
|  | 741 | } | 
|  | 742 |  | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 743 | static int __init imxfb_probe(struct platform_device *pdev) | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 744 | { | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 745 | struct imxfb_info *fbi; | 
|  | 746 | struct fb_info *info; | 
| Sascha Hauer | 2788927 | 2008-12-16 11:44:09 +0100 | [diff] [blame] | 747 | struct imx_fb_platform_data *pdata; | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 748 | struct resource *res; | 
| Sascha Hauer | 343684f | 2009-03-19 08:25:41 +0100 | [diff] [blame] | 749 | int ret, i; | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 750 |  | 
| Sascha Hauer | d6b5150 | 2009-06-29 11:41:09 +0200 | [diff] [blame] | 751 | dev_info(&pdev->dev, "i.MX Framebuffer driver\n"); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 752 |  | 
|  | 753 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 
| Sascha Hauer | 66c8719 | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 754 | if (!res) | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 755 | return -ENODEV; | 
|  | 756 |  | 
| Sascha Hauer | 2788927 | 2008-12-16 11:44:09 +0100 | [diff] [blame] | 757 | pdata = pdev->dev.platform_data; | 
|  | 758 | if (!pdata) { | 
| Pavel Pisa | f99c892 | 2006-01-07 10:44:32 +0000 | [diff] [blame] | 759 | dev_err(&pdev->dev,"No platform_data available\n"); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 760 | return -ENOMEM; | 
|  | 761 | } | 
|  | 762 |  | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 763 | info = framebuffer_alloc(sizeof(struct imxfb_info), &pdev->dev); | 
| Sascha Hauer | 66c8719 | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 764 | if (!info) | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 765 | return -ENOMEM; | 
|  | 766 |  | 
|  | 767 | fbi = info->par; | 
|  | 768 |  | 
| Sascha Hauer | 343684f | 2009-03-19 08:25:41 +0100 | [diff] [blame] | 769 | if (!fb_mode) | 
|  | 770 | fb_mode = pdata->mode[0].mode.name; | 
|  | 771 |  | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 772 | platform_set_drvdata(pdev, info); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 773 |  | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 774 | ret = imxfb_init_fbinfo(pdev); | 
| Sascha Hauer | 66c8719 | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 775 | if (ret < 0) | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 776 | goto failed_init; | 
|  | 777 |  | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 778 | res = request_mem_region(res->start, resource_size(res), | 
|  | 779 | DRIVER_NAME); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 780 | if (!res) { | 
|  | 781 | ret = -EBUSY; | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 782 | goto failed_req; | 
|  | 783 | } | 
|  | 784 |  | 
| Sascha Hauer | 13aaea0 | 2012-03-07 09:30:36 +0100 | [diff] [blame] | 785 | fbi->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); | 
|  | 786 | if (IS_ERR(fbi->clk_ipg)) { | 
|  | 787 | ret = PTR_ERR(fbi->clk_ipg); | 
|  | 788 | goto failed_getclock; | 
|  | 789 | } | 
|  | 790 |  | 
|  | 791 | fbi->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); | 
|  | 792 | if (IS_ERR(fbi->clk_ahb)) { | 
|  | 793 | ret = PTR_ERR(fbi->clk_ahb); | 
|  | 794 | goto failed_getclock; | 
|  | 795 | } | 
|  | 796 |  | 
|  | 797 | fbi->clk_per = devm_clk_get(&pdev->dev, "per"); | 
|  | 798 | if (IS_ERR(fbi->clk_per)) { | 
|  | 799 | ret = PTR_ERR(fbi->clk_per); | 
| Sascha Hauer | f909ef6 | 2009-01-15 15:21:00 +0100 | [diff] [blame] | 800 | goto failed_getclock; | 
|  | 801 | } | 
|  | 802 |  | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 803 | fbi->regs = ioremap(res->start, resource_size(res)); | 
|  | 804 | if (fbi->regs == NULL) { | 
| Sascha Hauer | d6b5150 | 2009-06-29 11:41:09 +0200 | [diff] [blame] | 805 | dev_err(&pdev->dev, "Cannot map frame buffer registers\n"); | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 806 | goto failed_ioremap; | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 807 | } | 
|  | 808 |  | 
| Sascha Hauer | 2788927 | 2008-12-16 11:44:09 +0100 | [diff] [blame] | 809 | if (!pdata->fixed_screen_cpu) { | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 810 | fbi->map_size = PAGE_ALIGN(info->fix.smem_len); | 
|  | 811 | fbi->map_cpu = dma_alloc_writecombine(&pdev->dev, | 
|  | 812 | fbi->map_size, &fbi->map_dma, GFP_KERNEL); | 
|  | 813 |  | 
|  | 814 | if (!fbi->map_cpu) { | 
| Pavel Pisa | f99c892 | 2006-01-07 10:44:32 +0000 | [diff] [blame] | 815 | dev_err(&pdev->dev, "Failed to allocate video RAM: %d\n", ret); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 816 | ret = -ENOMEM; | 
|  | 817 | goto failed_map; | 
|  | 818 | } | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 819 |  | 
|  | 820 | info->screen_base = fbi->map_cpu; | 
|  | 821 | fbi->screen_cpu = fbi->map_cpu; | 
|  | 822 | fbi->screen_dma = fbi->map_dma; | 
|  | 823 | info->fix.smem_start = fbi->screen_dma; | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 824 | } else { | 
|  | 825 | /* Fixed framebuffer mapping enables location of the screen in eSRAM */ | 
| Sascha Hauer | 2788927 | 2008-12-16 11:44:09 +0100 | [diff] [blame] | 826 | fbi->map_cpu = pdata->fixed_screen_cpu; | 
|  | 827 | fbi->map_dma = pdata->fixed_screen_dma; | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 828 | info->screen_base = fbi->map_cpu; | 
|  | 829 | fbi->screen_cpu = fbi->map_cpu; | 
|  | 830 | fbi->screen_dma = fbi->map_dma; | 
|  | 831 | info->fix.smem_start = fbi->screen_dma; | 
|  | 832 | } | 
|  | 833 |  | 
| Sascha Hauer | c0b90a3 | 2009-01-15 15:37:22 +0100 | [diff] [blame] | 834 | if (pdata->init) { | 
|  | 835 | ret = pdata->init(fbi->pdev); | 
|  | 836 | if (ret) | 
|  | 837 | goto failed_platform_init; | 
|  | 838 | } | 
|  | 839 |  | 
| Sascha Hauer | 343684f | 2009-03-19 08:25:41 +0100 | [diff] [blame] | 840 | fbi->mode = pdata->mode; | 
|  | 841 | fbi->num_modes = pdata->num_modes; | 
|  | 842 |  | 
|  | 843 | INIT_LIST_HEAD(&info->modelist); | 
|  | 844 | for (i = 0; i < pdata->num_modes; i++) | 
|  | 845 | fb_add_videomode(&pdata->mode[i].mode, &info->modelist); | 
|  | 846 |  | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 847 | /* | 
|  | 848 | * This makes sure that our colour bitfield | 
|  | 849 | * descriptors are correctly initialised. | 
|  | 850 | */ | 
|  | 851 | imxfb_check_var(&info->var, info); | 
|  | 852 |  | 
| Sascha Hauer | 66c8719 | 2008-12-16 11:44:08 +0100 | [diff] [blame] | 853 | ret = fb_alloc_cmap(&info->cmap, 1 << info->var.bits_per_pixel, 0); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 854 | if (ret < 0) | 
|  | 855 | goto failed_cmap; | 
|  | 856 |  | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 857 | imxfb_set_par(info); | 
|  | 858 | ret = register_framebuffer(info); | 
|  | 859 | if (ret < 0) { | 
| Pavel Pisa | f99c892 | 2006-01-07 10:44:32 +0000 | [diff] [blame] | 860 | dev_err(&pdev->dev, "failed to register framebuffer\n"); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 861 | goto failed_register; | 
|  | 862 | } | 
|  | 863 |  | 
|  | 864 | imxfb_enable_controller(fbi); | 
| Eric Bénard | 7a2bb23 | 2010-07-16 15:09:07 +0200 | [diff] [blame] | 865 | fbi->pdev = pdev; | 
| Eric Bénard | 81ef806 | 2010-08-02 08:39:55 +0100 | [diff] [blame] | 866 | #ifdef PWMR_BACKLIGHT_AVAILABLE | 
| Eric Bénard | 7a2bb23 | 2010-07-16 15:09:07 +0200 | [diff] [blame] | 867 | imxfb_init_backlight(fbi); | 
| Eric Bénard | 81ef806 | 2010-08-02 08:39:55 +0100 | [diff] [blame] | 868 | #endif | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 869 |  | 
|  | 870 | return 0; | 
|  | 871 |  | 
|  | 872 | failed_register: | 
|  | 873 | fb_dealloc_cmap(&info->cmap); | 
|  | 874 | failed_cmap: | 
| Sascha Hauer | c0b90a3 | 2009-01-15 15:37:22 +0100 | [diff] [blame] | 875 | if (pdata->exit) | 
|  | 876 | pdata->exit(fbi->pdev); | 
|  | 877 | failed_platform_init: | 
| Sascha Hauer | 2788927 | 2008-12-16 11:44:09 +0100 | [diff] [blame] | 878 | if (!pdata->fixed_screen_cpu) | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 879 | dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu, | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 880 | fbi->map_dma); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 881 | failed_map: | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 882 | iounmap(fbi->regs); | 
|  | 883 | failed_ioremap: | 
| Julia Lawall | 609d3bb | 2011-06-01 17:10:11 +0000 | [diff] [blame] | 884 | failed_getclock: | 
| Sascha Hauer | d6b5150 | 2009-06-29 11:41:09 +0200 | [diff] [blame] | 885 | release_mem_region(res->start, resource_size(res)); | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 886 | failed_req: | 
|  | 887 | kfree(info->pseudo_palette); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 888 | failed_init: | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 889 | platform_set_drvdata(pdev, NULL); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 890 | framebuffer_release(info); | 
|  | 891 | return ret; | 
|  | 892 | } | 
|  | 893 |  | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 894 | static int __devexit imxfb_remove(struct platform_device *pdev) | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 895 | { | 
| Sascha Hauer | c0b90a3 | 2009-01-15 15:37:22 +0100 | [diff] [blame] | 896 | struct imx_fb_platform_data *pdata; | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 897 | struct fb_info *info = platform_get_drvdata(pdev); | 
| Sascha Hauer | 772a9e6 | 2005-07-17 20:15:36 +0100 | [diff] [blame] | 898 | struct imxfb_info *fbi = info->par; | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 899 | struct resource *res; | 
|  | 900 |  | 
|  | 901 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 
|  | 902 |  | 
| Sascha Hauer | 772a9e6 | 2005-07-17 20:15:36 +0100 | [diff] [blame] | 903 | imxfb_disable_controller(fbi); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 904 |  | 
| Eric Bénard | 81ef806 | 2010-08-02 08:39:55 +0100 | [diff] [blame] | 905 | #ifdef PWMR_BACKLIGHT_AVAILABLE | 
| Eric Bénard | 7a2bb23 | 2010-07-16 15:09:07 +0200 | [diff] [blame] | 906 | imxfb_exit_backlight(fbi); | 
| Eric Bénard | 81ef806 | 2010-08-02 08:39:55 +0100 | [diff] [blame] | 907 | #endif | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 908 | unregister_framebuffer(info); | 
|  | 909 |  | 
| Sascha Hauer | c0b90a3 | 2009-01-15 15:37:22 +0100 | [diff] [blame] | 910 | pdata = pdev->dev.platform_data; | 
|  | 911 | if (pdata->exit) | 
|  | 912 | pdata->exit(fbi->pdev); | 
|  | 913 |  | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 914 | fb_dealloc_cmap(&info->cmap); | 
|  | 915 | kfree(info->pseudo_palette); | 
|  | 916 | framebuffer_release(info); | 
|  | 917 |  | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 918 | iounmap(fbi->regs); | 
| Sascha Hauer | d6b5150 | 2009-06-29 11:41:09 +0200 | [diff] [blame] | 919 | release_mem_region(res->start, resource_size(res)); | 
| Sascha Hauer | f909ef6 | 2009-01-15 15:21:00 +0100 | [diff] [blame] | 920 |  | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 921 | platform_set_drvdata(pdev, NULL); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 922 |  | 
|  | 923 | return 0; | 
|  | 924 | } | 
|  | 925 |  | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 926 | void  imxfb_shutdown(struct platform_device * dev) | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 927 | { | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 928 | struct fb_info *info = platform_get_drvdata(dev); | 
| Sascha Hauer | 772a9e6 | 2005-07-17 20:15:36 +0100 | [diff] [blame] | 929 | struct imxfb_info *fbi = info->par; | 
|  | 930 | imxfb_disable_controller(fbi); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 931 | } | 
|  | 932 |  | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 933 | static struct platform_driver imxfb_driver = { | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 934 | .suspend	= imxfb_suspend, | 
|  | 935 | .resume		= imxfb_resume, | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 936 | .remove		= __devexit_p(imxfb_remove), | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 937 | .shutdown	= imxfb_shutdown, | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 938 | .driver		= { | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 939 | .name	= DRIVER_NAME, | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 940 | }, | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 941 | }; | 
|  | 942 |  | 
| Sascha Hauer | 343684f | 2009-03-19 08:25:41 +0100 | [diff] [blame] | 943 | static int imxfb_setup(void) | 
|  | 944 | { | 
|  | 945 | #ifndef MODULE | 
|  | 946 | char *opt, *options = NULL; | 
|  | 947 |  | 
|  | 948 | if (fb_get_options("imxfb", &options)) | 
|  | 949 | return -ENODEV; | 
|  | 950 |  | 
|  | 951 | if (!options || !*options) | 
|  | 952 | return 0; | 
|  | 953 |  | 
|  | 954 | while ((opt = strsep(&options, ",")) != NULL) { | 
|  | 955 | if (!*opt) | 
|  | 956 | continue; | 
|  | 957 | else | 
|  | 958 | fb_mode = opt; | 
|  | 959 | } | 
|  | 960 | #endif | 
|  | 961 | return 0; | 
|  | 962 | } | 
|  | 963 |  | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 964 | int __init imxfb_init(void) | 
|  | 965 | { | 
| Sascha Hauer | 343684f | 2009-03-19 08:25:41 +0100 | [diff] [blame] | 966 | int ret = imxfb_setup(); | 
|  | 967 |  | 
|  | 968 | if (ret < 0) | 
|  | 969 | return ret; | 
|  | 970 |  | 
| Juergen Beisert | 72330b0 | 2008-12-16 11:44:07 +0100 | [diff] [blame] | 971 | return platform_driver_probe(&imxfb_driver, imxfb_probe); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 972 | } | 
|  | 973 |  | 
|  | 974 | static void __exit imxfb_cleanup(void) | 
|  | 975 | { | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 976 | platform_driver_unregister(&imxfb_driver); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 977 | } | 
|  | 978 |  | 
|  | 979 | module_init(imxfb_init); | 
|  | 980 | module_exit(imxfb_cleanup); | 
|  | 981 |  | 
| Fabio Estevam | e3d5fb7 | 2011-01-10 09:47:41 -0200 | [diff] [blame] | 982 | MODULE_DESCRIPTION("Freescale i.MX framebuffer driver"); | 
| Sascha Hauer | 7c2f891c | 2005-05-01 08:59:24 -0700 | [diff] [blame] | 983 | MODULE_AUTHOR("Sascha Hauer, Pengutronix"); | 
|  | 984 | MODULE_LICENSE("GPL"); |