1/*
2 *	linux/arch/arm/mach-nspire/clcd.c
3 *
4 *	Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
8 * published by the Free Software Foundation.
9 *
10 */
11
12#include <linux/init.h>
13#include <linux/of.h>
14#include <linux/amba/bus.h>
15#include <linux/amba/clcd.h>
16#include <linux/dma-mapping.h>
17
18static struct clcd_panel nspire_cx_lcd_panel = {
19	.mode		= {
20		.name		= "Color LCD",
21		.refresh	= 60,
22		.xres		= 320,
23		.yres		= 240,
24		.sync		= 0,
25		.vmode		= FB_VMODE_NONINTERLACED,
26		.pixclock	= 1,
27		.hsync_len	= 6,
28		.vsync_len	= 1,
29		.right_margin	= 50,
30		.left_margin	= 38,
31		.lower_margin	= 3,
32		.upper_margin	= 17,
33	},
34	.width		= 65, /* ~6.50 cm */
35	.height		= 49, /* ~4.87 cm */
36	.tim2		= TIM2_IPC,
37	.cntl		= CNTL_LCDTFT | CNTL_LCDVCOMP(1),
38	.bpp		= 16,
39	.caps		= CLCD_CAP_565,
40};
41
42static struct clcd_panel nspire_classic_lcd_panel = {
43	.mode		= {
44		.name		= "Grayscale LCD",
45		.refresh	= 60,
46		.xres		= 320,
47		.yres		= 240,
48		.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
49		.vmode		= FB_VMODE_NONINTERLACED,
50		.pixclock	= 1,
51		.hsync_len	= 6,
52		.vsync_len	= 1,
53		.right_margin	= 6,
54		.left_margin	= 6,
55	},
56	.width		= 71, /* 7.11cm */
57	.height		= 53, /* 5.33cm */
58	.tim2		= 0x80007d0,
59	.cntl		= CNTL_LCDMONO8,
60	.bpp		= 8,
61	.grayscale	= 1,
62	.caps		= CLCD_CAP_5551,
63};
64
65int nspire_clcd_setup(struct clcd_fb *fb)
66{
67	struct clcd_panel *panel;
68	size_t panel_size;
69	const char *type;
70	dma_addr_t dma;
71	int err;
72
73	BUG_ON(!fb->dev->dev.of_node);
74
75	err = of_property_read_string(fb->dev->dev.of_node, "lcd-type", &type);
76	if (err) {
77		pr_err("CLCD: Could not find lcd-type property\n");
78		return err;
79	}
80
81	if (!strcmp(type, "cx")) {
82		panel = &nspire_cx_lcd_panel;
83	} else if (!strcmp(type, "classic")) {
84		panel = &nspire_classic_lcd_panel;
85	} else {
86		pr_err("CLCD: Unknown lcd-type %s\n", type);
87		return -EINVAL;
88	}
89
90	panel_size = ((panel->mode.xres * panel->mode.yres) * panel->bpp) / 8;
91	panel_size = ALIGN(panel_size, PAGE_SIZE);
92
93	fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev,
94		panel_size, &dma, GFP_KERNEL);
95
96	if (!fb->fb.screen_base) {
97		pr_err("CLCD: unable to map framebuffer\n");
98		return -ENOMEM;
99	}
100
101	fb->fb.fix.smem_start = dma;
102	fb->fb.fix.smem_len = panel_size;
103	fb->panel = panel;
104
105	return 0;
106}
107
108int nspire_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
109{
110	return dma_mmap_writecombine(&fb->dev->dev, vma,
111		fb->fb.screen_base, fb->fb.fix.smem_start,
112		fb->fb.fix.smem_len);
113}
114
115void nspire_clcd_remove(struct clcd_fb *fb)
116{
117	dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
118		fb->fb.screen_base, fb->fb.fix.smem_start);
119}
120