Commit | Line | Data |
---|---|---|
19d95e1a | 1 | /* |
f5c42271 | 2 | * Platform support for LPC32xx SoC |
19d95e1a KW |
3 | * |
4 | * Author: Kevin Wells <kevin.wells@nxp.com> | |
5 | * | |
f5c42271 | 6 | * Copyright (C) 2012 Roland Stigge <stigge@antcom.de> |
19d95e1a KW |
7 | * Copyright (C) 2010 NXP Semiconductors |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2 of the License, or | |
12 | * (at your option) any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | */ | |
19 | ||
20 | #include <linux/init.h> | |
21 | #include <linux/platform_device.h> | |
edbaa603 | 22 | #include <linux/device.h> |
19d95e1a KW |
23 | #include <linux/interrupt.h> |
24 | #include <linux/irq.h> | |
25 | #include <linux/dma-mapping.h> | |
26 | #include <linux/device.h> | |
19d95e1a KW |
27 | #include <linux/gpio.h> |
28 | #include <linux/amba/bus.h> | |
29 | #include <linux/amba/clcd.h> | |
291dd71f RS |
30 | #include <linux/amba/pl08x.h> |
31 | #include <linux/amba/mmci.h> | |
f5c42271 RS |
32 | #include <linux/of.h> |
33 | #include <linux/of_address.h> | |
34 | #include <linux/of_irq.h> | |
35 | #include <linux/of_platform.h> | |
36 | #include <linux/clk.h> | |
5b941238 RS |
37 | #include <linux/mtd/lpc32xx_slc.h> |
38 | #include <linux/mtd/lpc32xx_mlc.h> | |
eef80f33 | 39 | #include <linux/platform_data/gpio-lpc32xx.h> |
19d95e1a KW |
40 | |
41 | #include <asm/setup.h> | |
42 | #include <asm/mach-types.h> | |
43 | #include <asm/mach/arch.h> | |
44 | ||
45 | #include <mach/hardware.h> | |
46 | #include <mach/platform.h> | |
c20b909b | 47 | #include <mach/board.h> |
19d95e1a KW |
48 | #include "common.h" |
49 | ||
50 | /* | |
51 | * Mapped GPIOLIB GPIOs | |
52 | */ | |
291dd71f RS |
53 | #define LCD_POWER_GPIO LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 0) |
54 | #define BKL_POWER_GPIO LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 4) | |
55 | #define MMC_PWR_ENABLE_GPIO LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 5) | |
19d95e1a KW |
56 | |
57 | /* | |
58 | * AMBA LCD controller | |
59 | */ | |
60 | static struct clcd_panel conn_lcd_panel = { | |
61 | .mode = { | |
62 | .name = "QVGA portrait", | |
63 | .refresh = 60, | |
64 | .xres = 240, | |
65 | .yres = 320, | |
66 | .pixclock = 191828, | |
67 | .left_margin = 22, | |
68 | .right_margin = 11, | |
69 | .upper_margin = 2, | |
70 | .lower_margin = 1, | |
71 | .hsync_len = 5, | |
72 | .vsync_len = 2, | |
73 | .sync = 0, | |
74 | .vmode = FB_VMODE_NONINTERLACED, | |
75 | }, | |
76 | .width = -1, | |
77 | .height = -1, | |
78 | .tim2 = (TIM2_IVS | TIM2_IHS), | |
79 | .cntl = (CNTL_BGR | CNTL_LCDTFT | CNTL_LCDVCOMP(1) | | |
80 | CNTL_LCDBPP16_565), | |
81 | .bpp = 16, | |
82 | }; | |
83 | #define PANEL_SIZE (3 * SZ_64K) | |
84 | ||
85 | static int lpc32xx_clcd_setup(struct clcd_fb *fb) | |
86 | { | |
87 | dma_addr_t dma; | |
88 | ||
89 | fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, | |
90 | PANEL_SIZE, &dma, GFP_KERNEL); | |
91 | if (!fb->fb.screen_base) { | |
92 | printk(KERN_ERR "CLCD: unable to map framebuffer\n"); | |
93 | return -ENOMEM; | |
94 | } | |
95 | ||
96 | fb->fb.fix.smem_start = dma; | |
97 | fb->fb.fix.smem_len = PANEL_SIZE; | |
98 | fb->panel = &conn_lcd_panel; | |
99 | ||
100 | if (gpio_request(LCD_POWER_GPIO, "LCD power")) | |
101 | printk(KERN_ERR "Error requesting gpio %u", | |
102 | LCD_POWER_GPIO); | |
103 | else if (gpio_direction_output(LCD_POWER_GPIO, 1)) | |
104 | printk(KERN_ERR "Error setting gpio %u to output", | |
105 | LCD_POWER_GPIO); | |
106 | ||
107 | if (gpio_request(BKL_POWER_GPIO, "LCD backlight power")) | |
108 | printk(KERN_ERR "Error requesting gpio %u", | |
109 | BKL_POWER_GPIO); | |
110 | else if (gpio_direction_output(BKL_POWER_GPIO, 1)) | |
111 | printk(KERN_ERR "Error setting gpio %u to output", | |
112 | BKL_POWER_GPIO); | |
113 | ||
114 | return 0; | |
115 | } | |
116 | ||
117 | static int lpc32xx_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma) | |
118 | { | |
119 | return dma_mmap_writecombine(&fb->dev->dev, vma, | |
120 | fb->fb.screen_base, fb->fb.fix.smem_start, | |
121 | fb->fb.fix.smem_len); | |
122 | } | |
123 | ||
124 | static void lpc32xx_clcd_remove(struct clcd_fb *fb) | |
125 | { | |
126 | dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len, | |
127 | fb->fb.screen_base, fb->fb.fix.smem_start); | |
128 | } | |
129 | ||
130 | /* | |
131 | * On some early LCD modules (1307.0), the backlight logic is inverted. | |
132 | * For those board variants, swap the disable and enable states for | |
133 | * BKL_POWER_GPIO. | |
134 | */ | |
135 | static void clcd_disable(struct clcd_fb *fb) | |
136 | { | |
137 | gpio_set_value(BKL_POWER_GPIO, 0); | |
138 | gpio_set_value(LCD_POWER_GPIO, 0); | |
139 | } | |
140 | ||
141 | static void clcd_enable(struct clcd_fb *fb) | |
142 | { | |
143 | gpio_set_value(BKL_POWER_GPIO, 1); | |
144 | gpio_set_value(LCD_POWER_GPIO, 1); | |
145 | } | |
146 | ||
147 | static struct clcd_board lpc32xx_clcd_data = { | |
148 | .name = "Phytec LCD", | |
149 | .check = clcdfb_check, | |
150 | .decode = clcdfb_decode, | |
151 | .disable = clcd_disable, | |
152 | .enable = clcd_enable, | |
153 | .setup = lpc32xx_clcd_setup, | |
154 | .mmap = lpc32xx_clcd_mmap, | |
155 | .remove = lpc32xx_clcd_remove, | |
156 | }; | |
157 | ||
d807af47 RS |
158 | static struct pl08x_channel_data pl08x_slave_channels[] = { |
159 | { | |
160 | .bus_id = "nand-slc", | |
161 | .min_signal = 1, /* SLC NAND Flash */ | |
162 | .max_signal = 1, | |
163 | .periph_buses = PL08X_AHB1, | |
164 | }, | |
165 | { | |
166 | .bus_id = "nand-mlc", | |
167 | .min_signal = 12, /* MLC NAND Flash */ | |
168 | .max_signal = 12, | |
169 | .periph_buses = PL08X_AHB1, | |
170 | }, | |
171 | }; | |
172 | ||
8ba85f8b | 173 | static int pl08x_get_signal(const struct pl08x_channel_data *cd) |
d807af47 | 174 | { |
8ba85f8b | 175 | return cd->min_signal; |
d807af47 RS |
176 | } |
177 | ||
8ba85f8b | 178 | static void pl08x_put_signal(const struct pl08x_channel_data *cd, int ch) |
d807af47 RS |
179 | { |
180 | } | |
181 | ||
f5c42271 | 182 | static struct pl08x_platform_data pl08x_pd = { |
d807af47 RS |
183 | .slave_channels = &pl08x_slave_channels[0], |
184 | .num_slave_channels = ARRAY_SIZE(pl08x_slave_channels), | |
d7cabeed MB |
185 | .get_xfer_signal = pl08x_get_signal, |
186 | .put_xfer_signal = pl08x_put_signal, | |
d807af47 RS |
187 | .lli_buses = PL08X_AHB1, |
188 | .mem_buses = PL08X_AHB1, | |
19d95e1a KW |
189 | }; |
190 | ||
291dd71f RS |
191 | static int mmc_handle_ios(struct device *dev, struct mmc_ios *ios) |
192 | { | |
193 | /* Only on and off are supported */ | |
194 | if (ios->power_mode == MMC_POWER_OFF) | |
195 | gpio_set_value(MMC_PWR_ENABLE_GPIO, 0); | |
196 | else | |
197 | gpio_set_value(MMC_PWR_ENABLE_GPIO, 1); | |
198 | return 0; | |
199 | } | |
200 | ||
201 | static struct mmci_platform_data lpc32xx_mmci_data = { | |
202 | .ocr_mask = MMC_VDD_30_31 | MMC_VDD_31_32 | | |
203 | MMC_VDD_32_33 | MMC_VDD_33_34, | |
204 | .ios_handler = mmc_handle_ios, | |
291dd71f RS |
205 | }; |
206 | ||
5b941238 RS |
207 | static struct lpc32xx_slc_platform_data lpc32xx_slc_data = { |
208 | .dma_filter = pl08x_filter_id, | |
209 | }; | |
210 | ||
211 | static struct lpc32xx_mlc_platform_data lpc32xx_mlc_data = { | |
212 | .dma_filter = pl08x_filter_id, | |
213 | }; | |
214 | ||
19c233b7 | 215 | static const struct of_dev_auxdata const lpc32xx_auxdata_lookup[] __initconst = { |
a4bc7878 RS |
216 | OF_DEV_AUXDATA("arm,pl022", 0x20084000, "dev:ssp0", NULL), |
217 | OF_DEV_AUXDATA("arm,pl022", 0x2008C000, "dev:ssp1", NULL), | |
f5c42271 RS |
218 | OF_DEV_AUXDATA("arm,pl110", 0x31040000, "dev:clcd", &lpc32xx_clcd_data), |
219 | OF_DEV_AUXDATA("arm,pl080", 0x31000000, "pl08xdmac", &pl08x_pd), | |
291dd71f RS |
220 | OF_DEV_AUXDATA("arm,pl18x", 0x20098000, "20098000.sd", |
221 | &lpc32xx_mmci_data), | |
5b941238 RS |
222 | OF_DEV_AUXDATA("nxp,lpc3220-slc", 0x20020000, "20020000.flash", |
223 | &lpc32xx_slc_data), | |
224 | OF_DEV_AUXDATA("nxp,lpc3220-mlc", 0x200a8000, "200a8000.flash", | |
225 | &lpc32xx_mlc_data), | |
f5c42271 | 226 | { } |
19d95e1a KW |
227 | }; |
228 | ||
f5c42271 | 229 | static void __init lpc3250_machine_init(void) |
19d95e1a KW |
230 | { |
231 | u32 tmp; | |
19d95e1a | 232 | |
19d95e1a KW |
233 | /* Setup LCD muxing to RGB565 */ |
234 | tmp = __raw_readl(LPC32XX_CLKPWR_LCDCLK_CTRL) & | |
235 | ~(LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_MSK | | |
236 | LPC32XX_CLKPWR_LCDCTRL_PSCALE_MSK); | |
237 | tmp |= LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_TFT16; | |
238 | __raw_writel(tmp, LPC32XX_CLKPWR_LCDCLK_CTRL); | |
239 | ||
19d95e1a KW |
240 | lpc32xx_serial_init(); |
241 | ||
19d95e1a KW |
242 | /* Test clock needed for UDA1380 initial init */ |
243 | __raw_writel(LPC32XX_CLKPWR_TESTCLK2_SEL_MOSC | | |
244 | LPC32XX_CLKPWR_TESTCLK_TESTCLK2_EN, | |
245 | LPC32XX_CLKPWR_TEST_CLK_SEL); | |
246 | ||
f5c42271 RS |
247 | of_platform_populate(NULL, of_default_bus_match_table, |
248 | lpc32xx_auxdata_lookup, NULL); | |
19d95e1a KW |
249 | } |
250 | ||
19c233b7 | 251 | static const char *const lpc32xx_dt_compat[] __initconst = { |
f5c42271 RS |
252 | "nxp,lpc3220", |
253 | "nxp,lpc3230", | |
254 | "nxp,lpc3240", | |
255 | "nxp,lpc3250", | |
256 | NULL | |
257 | }; | |
258 | ||
259 | DT_MACHINE_START(LPC32XX_DT, "LPC32XX SoC (Flattened Device Tree)") | |
bdec5ddd | 260 | .atag_offset = 0x100, |
19d95e1a KW |
261 | .map_io = lpc32xx_map_io, |
262 | .init_irq = lpc32xx_init_irq, | |
6bb27d73 | 263 | .init_time = lpc32xx_timer_init, |
f5c42271 RS |
264 | .init_machine = lpc3250_machine_init, |
265 | .dt_compat = lpc32xx_dt_compat, | |
b23fcd90 | 266 | .restart = lpc23xx_restart, |
19d95e1a | 267 | MACHINE_END |