xref: /linux/arch/arm/mach-lpc32xx/common.c (revision b23fcd9035a35b032c624ac2f23f40ea941d5355)
1fc982e1cSKevin Wells /*
2fc982e1cSKevin Wells  * arch/arm/mach-lpc32xx/common.c
3fc982e1cSKevin Wells  *
4fc982e1cSKevin Wells  * Author: Kevin Wells <kevin.wells@nxp.com>
5fc982e1cSKevin Wells  *
6fc982e1cSKevin Wells  * Copyright (C) 2010 NXP Semiconductors
7fc982e1cSKevin Wells  *
8fc982e1cSKevin Wells  * This program is free software; you can redistribute it and/or modify
9fc982e1cSKevin Wells  * it under the terms of the GNU General Public License as published by
10fc982e1cSKevin Wells  * the Free Software Foundation; either version 2 of the License, or
11fc982e1cSKevin Wells  * (at your option) any later version.
12fc982e1cSKevin Wells  *
13fc982e1cSKevin Wells  * This program is distributed in the hope that it will be useful,
14fc982e1cSKevin Wells  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15fc982e1cSKevin Wells  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16fc982e1cSKevin Wells  * GNU General Public License for more details.
17fc982e1cSKevin Wells  */
18fc982e1cSKevin Wells 
19fc982e1cSKevin Wells #include <linux/init.h>
20fc982e1cSKevin Wells #include <linux/platform_device.h>
21fc982e1cSKevin Wells #include <linux/interrupt.h>
22fc982e1cSKevin Wells #include <linux/irq.h>
23fc982e1cSKevin Wells #include <linux/err.h>
24fc982e1cSKevin Wells #include <linux/i2c.h>
25fc982e1cSKevin Wells #include <linux/i2c-pnx.h>
26fc982e1cSKevin Wells #include <linux/io.h>
27fc982e1cSKevin Wells 
28fc982e1cSKevin Wells #include <asm/mach/map.h>
29fc982e1cSKevin Wells 
30fc982e1cSKevin Wells #include <mach/i2c.h>
31fc982e1cSKevin Wells #include <mach/hardware.h>
32fc982e1cSKevin Wells #include <mach/platform.h>
33fc982e1cSKevin Wells #include "common.h"
34fc982e1cSKevin Wells 
35fc982e1cSKevin Wells /*
36fc982e1cSKevin Wells  * Watchdog timer
37fc982e1cSKevin Wells  */
38fc982e1cSKevin Wells static struct resource watchdog_resources[] = {
39fc982e1cSKevin Wells 	[0] = {
40fc982e1cSKevin Wells 		.start = LPC32XX_WDTIM_BASE,
41fc982e1cSKevin Wells 		.end = LPC32XX_WDTIM_BASE + SZ_4K - 1,
42fc982e1cSKevin Wells 		.flags = IORESOURCE_MEM,
43fc982e1cSKevin Wells 	},
44fc982e1cSKevin Wells };
45fc982e1cSKevin Wells 
46fc982e1cSKevin Wells struct platform_device lpc32xx_watchdog_device = {
47fc982e1cSKevin Wells 	.name = "pnx4008-watchdog",
48fc982e1cSKevin Wells 	.id = -1,
49fc982e1cSKevin Wells 	.num_resources = ARRAY_SIZE(watchdog_resources),
50fc982e1cSKevin Wells 	.resource = watchdog_resources,
51fc982e1cSKevin Wells };
52fc982e1cSKevin Wells 
53fc982e1cSKevin Wells /*
54fc982e1cSKevin Wells  * I2C busses
55fc982e1cSKevin Wells  */
56fc982e1cSKevin Wells static struct i2c_pnx_data i2c0_data = {
57fc982e1cSKevin Wells 	.name = I2C_CHIP_NAME "1",
58fc982e1cSKevin Wells 	.base = LPC32XX_I2C1_BASE,
59fc982e1cSKevin Wells 	.irq = IRQ_LPC32XX_I2C_1,
60fc982e1cSKevin Wells };
61fc982e1cSKevin Wells 
62fc982e1cSKevin Wells static struct i2c_pnx_data i2c1_data = {
63fc982e1cSKevin Wells 	.name = I2C_CHIP_NAME "2",
64fc982e1cSKevin Wells 	.base = LPC32XX_I2C2_BASE,
65fc982e1cSKevin Wells 	.irq = IRQ_LPC32XX_I2C_2,
66fc982e1cSKevin Wells };
67fc982e1cSKevin Wells 
68fc982e1cSKevin Wells static struct i2c_pnx_data i2c2_data = {
69fc982e1cSKevin Wells 	.name = "USB-I2C",
70fc982e1cSKevin Wells 	.base = LPC32XX_OTG_I2C_BASE,
71fc982e1cSKevin Wells 	.irq = IRQ_LPC32XX_USB_I2C,
72fc982e1cSKevin Wells };
73fc982e1cSKevin Wells 
74fc982e1cSKevin Wells struct platform_device lpc32xx_i2c0_device = {
75fc982e1cSKevin Wells 	.name = "pnx-i2c",
76fc982e1cSKevin Wells 	.id = 0,
77fc982e1cSKevin Wells 	.dev = {
78fc982e1cSKevin Wells 		.platform_data = &i2c0_data,
79fc982e1cSKevin Wells 	},
80fc982e1cSKevin Wells };
81fc982e1cSKevin Wells 
82fc982e1cSKevin Wells struct platform_device lpc32xx_i2c1_device = {
83fc982e1cSKevin Wells 	.name = "pnx-i2c",
84fc982e1cSKevin Wells 	.id = 1,
85fc982e1cSKevin Wells 	.dev = {
86fc982e1cSKevin Wells 		.platform_data = &i2c1_data,
87fc982e1cSKevin Wells 	},
88fc982e1cSKevin Wells };
89fc982e1cSKevin Wells 
90fc982e1cSKevin Wells struct platform_device lpc32xx_i2c2_device = {
91fc982e1cSKevin Wells 	.name = "pnx-i2c",
92fc982e1cSKevin Wells 	.id = 2,
93fc982e1cSKevin Wells 	.dev = {
94fc982e1cSKevin Wells 		.platform_data = &i2c2_data,
95fc982e1cSKevin Wells 	},
96fc982e1cSKevin Wells };
97fc982e1cSKevin Wells 
987db2b377SWolfram Sang /* TSC (Touch Screen Controller) */
997db2b377SWolfram Sang 
1007db2b377SWolfram Sang static struct resource lpc32xx_tsc_resources[] = {
1017db2b377SWolfram Sang 	{
1027db2b377SWolfram Sang 		.start = LPC32XX_ADC_BASE,
1037db2b377SWolfram Sang 		.end = LPC32XX_ADC_BASE + SZ_4K - 1,
1047db2b377SWolfram Sang 		.flags = IORESOURCE_MEM,
1057db2b377SWolfram Sang 	}, {
1067db2b377SWolfram Sang 		.start = IRQ_LPC32XX_TS_IRQ,
1077db2b377SWolfram Sang 		.end = IRQ_LPC32XX_TS_IRQ,
1087db2b377SWolfram Sang 		.flags = IORESOURCE_IRQ,
1097db2b377SWolfram Sang 	},
1107db2b377SWolfram Sang };
1117db2b377SWolfram Sang 
1127db2b377SWolfram Sang struct platform_device lpc32xx_tsc_device = {
1137db2b377SWolfram Sang 	.name =  "ts-lpc32xx",
1147db2b377SWolfram Sang 	.id = -1,
1157db2b377SWolfram Sang 	.num_resources = ARRAY_SIZE(lpc32xx_tsc_resources),
1167db2b377SWolfram Sang 	.resource = lpc32xx_tsc_resources,
1177db2b377SWolfram Sang };
1187db2b377SWolfram Sang 
1191c72f9eaSWolfram Sang /* RTC */
1201c72f9eaSWolfram Sang 
1211c72f9eaSWolfram Sang static struct resource lpc32xx_rtc_resources[] = {
1221c72f9eaSWolfram Sang 	{
1231c72f9eaSWolfram Sang 		.start = LPC32XX_RTC_BASE,
1241c72f9eaSWolfram Sang 		.end = LPC32XX_RTC_BASE + SZ_4K - 1,
1251c72f9eaSWolfram Sang 		.flags = IORESOURCE_MEM,
1261c72f9eaSWolfram Sang 	},{
1271c72f9eaSWolfram Sang 		.start = IRQ_LPC32XX_RTC,
1281c72f9eaSWolfram Sang 		.end = IRQ_LPC32XX_RTC,
1291c72f9eaSWolfram Sang 		.flags = IORESOURCE_IRQ,
1301c72f9eaSWolfram Sang 	},
1311c72f9eaSWolfram Sang };
1321c72f9eaSWolfram Sang 
1331c72f9eaSWolfram Sang struct platform_device lpc32xx_rtc_device = {
1341c72f9eaSWolfram Sang 	.name =  "rtc-lpc32xx",
1351c72f9eaSWolfram Sang 	.id = -1,
1361c72f9eaSWolfram Sang 	.num_resources = ARRAY_SIZE(lpc32xx_rtc_resources),
1371c72f9eaSWolfram Sang 	.resource = lpc32xx_rtc_resources,
1381c72f9eaSWolfram Sang };
1391c72f9eaSWolfram Sang 
140fc982e1cSKevin Wells /*
141fc982e1cSKevin Wells  * Returns the unique ID for the device
142fc982e1cSKevin Wells  */
143fc982e1cSKevin Wells void lpc32xx_get_uid(u32 devid[4])
144fc982e1cSKevin Wells {
145fc982e1cSKevin Wells 	int i;
146fc982e1cSKevin Wells 
147fc982e1cSKevin Wells 	for (i = 0; i < 4; i++)
148fc982e1cSKevin Wells 		devid[i] = __raw_readl(LPC32XX_CLKPWR_DEVID(i << 2));
149fc982e1cSKevin Wells }
150fc982e1cSKevin Wells 
151fc982e1cSKevin Wells /*
152fc982e1cSKevin Wells  * Returns SYSCLK source
153fc982e1cSKevin Wells  * 0 = PLL397, 1 = main oscillator
154fc982e1cSKevin Wells  */
155fc982e1cSKevin Wells int clk_is_sysclk_mainosc(void)
156fc982e1cSKevin Wells {
157fc982e1cSKevin Wells 	if ((__raw_readl(LPC32XX_CLKPWR_SYSCLK_CTRL) &
158fc982e1cSKevin Wells 		LPC32XX_CLKPWR_SYSCTRL_SYSCLKMUX) == 0)
159fc982e1cSKevin Wells 		return 1;
160fc982e1cSKevin Wells 
161fc982e1cSKevin Wells 	return 0;
162fc982e1cSKevin Wells }
163fc982e1cSKevin Wells 
164fc982e1cSKevin Wells /*
165fc982e1cSKevin Wells  * System reset via the watchdog timer
166fc982e1cSKevin Wells  */
167*b23fcd90SRussell King static void lpc32xx_watchdog_reset(void)
168fc982e1cSKevin Wells {
169fc982e1cSKevin Wells 	/* Make sure WDT clocks are enabled */
170fc982e1cSKevin Wells 	__raw_writel(LPC32XX_CLKPWR_PWMCLK_WDOG_EN,
171fc982e1cSKevin Wells 		LPC32XX_CLKPWR_TIMER_CLK_CTRL);
172fc982e1cSKevin Wells 
173fc982e1cSKevin Wells 	/* Instant assert of RESETOUT_N with pulse length 1mS */
174fc982e1cSKevin Wells 	__raw_writel(13000, io_p2v(LPC32XX_WDTIM_BASE + 0x18));
175fc982e1cSKevin Wells 	__raw_writel(0x70, io_p2v(LPC32XX_WDTIM_BASE + 0xC));
176fc982e1cSKevin Wells }
177fc982e1cSKevin Wells 
178fc982e1cSKevin Wells /*
179fc982e1cSKevin Wells  * Detects and returns IRAM size for the device variation
180fc982e1cSKevin Wells  */
181fc982e1cSKevin Wells #define LPC32XX_IRAM_BANK_SIZE SZ_128K
182fc982e1cSKevin Wells static u32 iram_size;
183fc982e1cSKevin Wells u32 lpc32xx_return_iram_size(void)
184fc982e1cSKevin Wells {
185fc982e1cSKevin Wells 	if (iram_size == 0) {
186fc982e1cSKevin Wells 		u32 savedval1, savedval2;
187fc982e1cSKevin Wells 		void __iomem *iramptr1, *iramptr2;
188fc982e1cSKevin Wells 
189fc982e1cSKevin Wells 		iramptr1 = io_p2v(LPC32XX_IRAM_BASE);
190fc982e1cSKevin Wells 		iramptr2 = io_p2v(LPC32XX_IRAM_BASE + LPC32XX_IRAM_BANK_SIZE);
191fc982e1cSKevin Wells 		savedval1 = __raw_readl(iramptr1);
192fc982e1cSKevin Wells 		savedval2 = __raw_readl(iramptr2);
193fc982e1cSKevin Wells 
194fc982e1cSKevin Wells 		if (savedval1 == savedval2) {
195fc982e1cSKevin Wells 			__raw_writel(savedval2 + 1, iramptr2);
196fc982e1cSKevin Wells 			if (__raw_readl(iramptr1) == savedval2 + 1)
197fc982e1cSKevin Wells 				iram_size = LPC32XX_IRAM_BANK_SIZE;
198fc982e1cSKevin Wells 			else
199fc982e1cSKevin Wells 				iram_size = LPC32XX_IRAM_BANK_SIZE * 2;
200fc982e1cSKevin Wells 			__raw_writel(savedval2, iramptr2);
201fc982e1cSKevin Wells 		} else
202fc982e1cSKevin Wells 			iram_size = LPC32XX_IRAM_BANK_SIZE * 2;
203fc982e1cSKevin Wells 	}
204fc982e1cSKevin Wells 
205fc982e1cSKevin Wells 	return iram_size;
206fc982e1cSKevin Wells }
207fc982e1cSKevin Wells 
208fc982e1cSKevin Wells /*
209fc982e1cSKevin Wells  * Computes PLL rate from PLL register and input clock
210fc982e1cSKevin Wells  */
211fc982e1cSKevin Wells u32 clk_check_pll_setup(u32 ifreq, struct clk_pll_setup *pllsetup)
212fc982e1cSKevin Wells {
213fc982e1cSKevin Wells 	u32 ilfreq, p, m, n, fcco, fref, cfreq;
214fc982e1cSKevin Wells 	int mode;
215fc982e1cSKevin Wells 
216fc982e1cSKevin Wells 	/*
217fc982e1cSKevin Wells 	 * PLL requirements
218fc982e1cSKevin Wells 	 * ifreq must be >= 1MHz and <= 20MHz
219fc982e1cSKevin Wells 	 * FCCO must be >= 156MHz and <= 320MHz
220fc982e1cSKevin Wells 	 * FREF must be >= 1MHz and <= 27MHz
221fc982e1cSKevin Wells 	 * Assume the passed input data is not valid
222fc982e1cSKevin Wells 	 */
223fc982e1cSKevin Wells 
224fc982e1cSKevin Wells 	ilfreq = ifreq;
225fc982e1cSKevin Wells 	m = pllsetup->pll_m;
226fc982e1cSKevin Wells 	n = pllsetup->pll_n;
227fc982e1cSKevin Wells 	p = pllsetup->pll_p;
228fc982e1cSKevin Wells 
229fc982e1cSKevin Wells 	mode = (pllsetup->cco_bypass_b15 << 2) |
230fc982e1cSKevin Wells 		(pllsetup->direct_output_b14 << 1) |
231fc982e1cSKevin Wells 	pllsetup->fdbk_div_ctrl_b13;
232fc982e1cSKevin Wells 
233fc982e1cSKevin Wells 	switch (mode) {
234fc982e1cSKevin Wells 	case 0x0: /* Non-integer mode */
235fc982e1cSKevin Wells 		cfreq = (m * ilfreq) / (2 * p * n);
236fc982e1cSKevin Wells 		fcco = (m * ilfreq) / n;
237fc982e1cSKevin Wells 		fref = ilfreq / n;
238fc982e1cSKevin Wells 		break;
239fc982e1cSKevin Wells 
240fc982e1cSKevin Wells 	case 0x1: /* integer mode */
241fc982e1cSKevin Wells 		cfreq = (m * ilfreq) / n;
242fc982e1cSKevin Wells 		fcco = (m * ilfreq) / (n * 2 * p);
243fc982e1cSKevin Wells 		fref = ilfreq / n;
244fc982e1cSKevin Wells 		break;
245fc982e1cSKevin Wells 
246fc982e1cSKevin Wells 	case 0x2:
247fc982e1cSKevin Wells 	case 0x3: /* Direct mode */
248fc982e1cSKevin Wells 		cfreq = (m * ilfreq) / n;
249fc982e1cSKevin Wells 		fcco = cfreq;
250fc982e1cSKevin Wells 		fref = ilfreq / n;
251fc982e1cSKevin Wells 		break;
252fc982e1cSKevin Wells 
253fc982e1cSKevin Wells 	case 0x4:
254fc982e1cSKevin Wells 	case 0x5: /* Bypass mode */
255fc982e1cSKevin Wells 		cfreq = ilfreq / (2 * p);
256fc982e1cSKevin Wells 		fcco = 156000000;
257fc982e1cSKevin Wells 		fref = 1000000;
258fc982e1cSKevin Wells 		break;
259fc982e1cSKevin Wells 
260fc982e1cSKevin Wells 	case 0x6:
261fc982e1cSKevin Wells 	case 0x7: /* Direct bypass mode */
262fc982e1cSKevin Wells 	default:
263fc982e1cSKevin Wells 		cfreq = ilfreq;
264fc982e1cSKevin Wells 		fcco = 156000000;
265fc982e1cSKevin Wells 		fref = 1000000;
266fc982e1cSKevin Wells 		break;
267fc982e1cSKevin Wells 	}
268fc982e1cSKevin Wells 
269fc982e1cSKevin Wells 	if (fcco < 156000000 || fcco > 320000000)
270fc982e1cSKevin Wells 		cfreq = 0;
271fc982e1cSKevin Wells 
272fc982e1cSKevin Wells 	if (fref < 1000000 || fref > 27000000)
273fc982e1cSKevin Wells 		cfreq = 0;
274fc982e1cSKevin Wells 
275fc982e1cSKevin Wells 	return (u32) cfreq;
276fc982e1cSKevin Wells }
277fc982e1cSKevin Wells 
278fc982e1cSKevin Wells u32 clk_get_pclk_div(void)
279fc982e1cSKevin Wells {
280fc982e1cSKevin Wells 	return 1 + ((__raw_readl(LPC32XX_CLKPWR_HCLK_DIV) >> 2) & 0x1F);
281fc982e1cSKevin Wells }
282fc982e1cSKevin Wells 
283fc982e1cSKevin Wells static struct map_desc lpc32xx_io_desc[] __initdata = {
284fc982e1cSKevin Wells 	{
285fc982e1cSKevin Wells 		.virtual	= IO_ADDRESS(LPC32XX_AHB0_START),
286fc982e1cSKevin Wells 		.pfn		= __phys_to_pfn(LPC32XX_AHB0_START),
287fc982e1cSKevin Wells 		.length		= LPC32XX_AHB0_SIZE,
288fc982e1cSKevin Wells 		.type		= MT_DEVICE
289fc982e1cSKevin Wells 	},
290fc982e1cSKevin Wells 	{
291fc982e1cSKevin Wells 		.virtual	= IO_ADDRESS(LPC32XX_AHB1_START),
292fc982e1cSKevin Wells 		.pfn		= __phys_to_pfn(LPC32XX_AHB1_START),
293fc982e1cSKevin Wells 		.length		= LPC32XX_AHB1_SIZE,
294fc982e1cSKevin Wells 		.type		= MT_DEVICE
295fc982e1cSKevin Wells 	},
296fc982e1cSKevin Wells 	{
297fc982e1cSKevin Wells 		.virtual	= IO_ADDRESS(LPC32XX_FABAPB_START),
298fc982e1cSKevin Wells 		.pfn		= __phys_to_pfn(LPC32XX_FABAPB_START),
299fc982e1cSKevin Wells 		.length		= LPC32XX_FABAPB_SIZE,
300fc982e1cSKevin Wells 		.type		= MT_DEVICE
301fc982e1cSKevin Wells 	},
302fc982e1cSKevin Wells 	{
303fc982e1cSKevin Wells 		.virtual	= IO_ADDRESS(LPC32XX_IRAM_BASE),
304fc982e1cSKevin Wells 		.pfn		= __phys_to_pfn(LPC32XX_IRAM_BASE),
305fc982e1cSKevin Wells 		.length		= (LPC32XX_IRAM_BANK_SIZE * 2),
306fc982e1cSKevin Wells 		.type		= MT_DEVICE
307fc982e1cSKevin Wells 	},
308fc982e1cSKevin Wells };
309fc982e1cSKevin Wells 
310fc982e1cSKevin Wells void __init lpc32xx_map_io(void)
311fc982e1cSKevin Wells {
312fc982e1cSKevin Wells 	iotable_init(lpc32xx_io_desc, ARRAY_SIZE(lpc32xx_io_desc));
313fc982e1cSKevin Wells }
314*b23fcd90SRussell King 
315*b23fcd90SRussell King void lpc23xx_restart(char mode, const char *cmd)
316*b23fcd90SRussell King {
317*b23fcd90SRussell King 	switch (mode) {
318*b23fcd90SRussell King 	case 's':
319*b23fcd90SRussell King 	case 'h':
320*b23fcd90SRussell King 		printk(KERN_CRIT "RESET: Rebooting system\n");
321*b23fcd90SRussell King 
322*b23fcd90SRussell King 		lpc32xx_watchdog_reset();
323*b23fcd90SRussell King 		break;
324*b23fcd90SRussell King 
325*b23fcd90SRussell King 	default:
326*b23fcd90SRussell King 		/* Do nothing */
327*b23fcd90SRussell King 		break;
328*b23fcd90SRussell King 	}
329*b23fcd90SRussell King 
330*b23fcd90SRussell King 	/* Wait for watchdog to reset system */
331*b23fcd90SRussell King 	while (1)
332*b23fcd90SRussell King 		;
333*b23fcd90SRussell King }
334