1/*
2 * arch/arm/mach-lpc32xx/common.c
3 *
4 * Author: Kevin Wells <kevin.wells@nxp.com>
5 *
6 * Copyright (C) 2010 NXP Semiconductors
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 */
18
19#include <linux/init.h>
20#include <linux/platform_device.h>
21#include <linux/interrupt.h>
22#include <linux/irq.h>
23#include <linux/err.h>
24#include <linux/i2c.h>
25#include <linux/i2c-pnx.h>
26#include <linux/io.h>
27
28#include <asm/mach/map.h>
29
30#include <mach/i2c.h>
31#include <mach/hardware.h>
32#include <mach/platform.h>
33#include "common.h"
34
35/*
36 * Watchdog timer
37 */
38static struct resource watchdog_resources[] = {
39	[0] = {
40		.start = LPC32XX_WDTIM_BASE,
41		.end = LPC32XX_WDTIM_BASE + SZ_4K - 1,
42		.flags = IORESOURCE_MEM,
43	},
44};
45
46struct platform_device lpc32xx_watchdog_device = {
47	.name = "pnx4008-watchdog",
48	.id = -1,
49	.num_resources = ARRAY_SIZE(watchdog_resources),
50	.resource = watchdog_resources,
51};
52
53/*
54 * I2C busses
55 */
56static struct i2c_pnx_data i2c0_data = {
57	.name = I2C_CHIP_NAME "1",
58	.base = LPC32XX_I2C1_BASE,
59	.irq = IRQ_LPC32XX_I2C_1,
60};
61
62static struct i2c_pnx_data i2c1_data = {
63	.name = I2C_CHIP_NAME "2",
64	.base = LPC32XX_I2C2_BASE,
65	.irq = IRQ_LPC32XX_I2C_2,
66};
67
68static struct i2c_pnx_data i2c2_data = {
69	.name = "USB-I2C",
70	.base = LPC32XX_OTG_I2C_BASE,
71	.irq = IRQ_LPC32XX_USB_I2C,
72};
73
74struct platform_device lpc32xx_i2c0_device = {
75	.name = "pnx-i2c",
76	.id = 0,
77	.dev = {
78		.platform_data = &i2c0_data,
79	},
80};
81
82struct platform_device lpc32xx_i2c1_device = {
83	.name = "pnx-i2c",
84	.id = 1,
85	.dev = {
86		.platform_data = &i2c1_data,
87	},
88};
89
90struct platform_device lpc32xx_i2c2_device = {
91	.name = "pnx-i2c",
92	.id = 2,
93	.dev = {
94		.platform_data = &i2c2_data,
95	},
96};
97
98/* TSC (Touch Screen Controller) */
99
100static struct resource lpc32xx_tsc_resources[] = {
101	{
102		.start = LPC32XX_ADC_BASE,
103		.end = LPC32XX_ADC_BASE + SZ_4K - 1,
104		.flags = IORESOURCE_MEM,
105	}, {
106		.start = IRQ_LPC32XX_TS_IRQ,
107		.end = IRQ_LPC32XX_TS_IRQ,
108		.flags = IORESOURCE_IRQ,
109	},
110};
111
112struct platform_device lpc32xx_tsc_device = {
113	.name =  "ts-lpc32xx",
114	.id = -1,
115	.num_resources = ARRAY_SIZE(lpc32xx_tsc_resources),
116	.resource = lpc32xx_tsc_resources,
117};
118
119/* RTC */
120
121static struct resource lpc32xx_rtc_resources[] = {
122	{
123		.start = LPC32XX_RTC_BASE,
124		.end = LPC32XX_RTC_BASE + SZ_4K - 1,
125		.flags = IORESOURCE_MEM,
126	},{
127		.start = IRQ_LPC32XX_RTC,
128		.end = IRQ_LPC32XX_RTC,
129		.flags = IORESOURCE_IRQ,
130	},
131};
132
133struct platform_device lpc32xx_rtc_device = {
134	.name =  "rtc-lpc32xx",
135	.id = -1,
136	.num_resources = ARRAY_SIZE(lpc32xx_rtc_resources),
137	.resource = lpc32xx_rtc_resources,
138};
139
140/*
141 * ADC support
142 */
143static struct resource adc_resources[] = {
144	{
145		.start = LPC32XX_ADC_BASE,
146		.end = LPC32XX_ADC_BASE + SZ_4K - 1,
147		.flags = IORESOURCE_MEM,
148	}, {
149		.start = IRQ_LPC32XX_TS_IRQ,
150		.end = IRQ_LPC32XX_TS_IRQ,
151		.flags = IORESOURCE_IRQ,
152	},
153};
154
155struct platform_device lpc32xx_adc_device = {
156	.name =  "lpc32xx-adc",
157	.id = -1,
158	.num_resources = ARRAY_SIZE(adc_resources),
159	.resource = adc_resources,
160};
161
162/*
163 * USB support
164 */
165/* The dmamask must be set for OHCI to work */
166static u64 ohci_dmamask = ~(u32) 0;
167static struct resource ohci_resources[] = {
168	{
169		.start = IO_ADDRESS(LPC32XX_USB_BASE),
170		.end = IO_ADDRESS(LPC32XX_USB_BASE + 0x100 - 1),
171		.flags = IORESOURCE_MEM,
172	}, {
173		.start = IRQ_LPC32XX_USB_HOST,
174		.flags = IORESOURCE_IRQ,
175	},
176};
177struct platform_device lpc32xx_ohci_device = {
178	.name = "usb-ohci",
179	.id = -1,
180	.dev = {
181		.dma_mask = &ohci_dmamask,
182		.coherent_dma_mask = 0xFFFFFFFF,
183	},
184	.num_resources = ARRAY_SIZE(ohci_resources),
185	.resource = ohci_resources,
186};
187
188/*
189 * Network Support
190 */
191static struct resource net_resources[] = {
192	[0] = DEFINE_RES_MEM(LPC32XX_ETHERNET_BASE, SZ_4K),
193	[1] = DEFINE_RES_MEM(LPC32XX_IRAM_BASE, SZ_128K),
194	[2] = DEFINE_RES_IRQ(IRQ_LPC32XX_ETHERNET),
195};
196
197static u64 lpc32xx_mac_dma_mask = 0xffffffffUL;
198struct platform_device lpc32xx_net_device = {
199	.name = "lpc-eth",
200	.id = 0,
201	.dev = {
202		.dma_mask = &lpc32xx_mac_dma_mask,
203		.coherent_dma_mask = 0xffffffffUL,
204	},
205	.num_resources = ARRAY_SIZE(net_resources),
206	.resource = net_resources,
207};
208
209/*
210 * Returns the unique ID for the device
211 */
212void lpc32xx_get_uid(u32 devid[4])
213{
214	int i;
215
216	for (i = 0; i < 4; i++)
217		devid[i] = __raw_readl(LPC32XX_CLKPWR_DEVID(i << 2));
218}
219
220/*
221 * Returns SYSCLK source
222 * 0 = PLL397, 1 = main oscillator
223 */
224int clk_is_sysclk_mainosc(void)
225{
226	if ((__raw_readl(LPC32XX_CLKPWR_SYSCLK_CTRL) &
227		LPC32XX_CLKPWR_SYSCTRL_SYSCLKMUX) == 0)
228		return 1;
229
230	return 0;
231}
232
233/*
234 * System reset via the watchdog timer
235 */
236static void lpc32xx_watchdog_reset(void)
237{
238	/* Make sure WDT clocks are enabled */
239	__raw_writel(LPC32XX_CLKPWR_PWMCLK_WDOG_EN,
240		LPC32XX_CLKPWR_TIMER_CLK_CTRL);
241
242	/* Instant assert of RESETOUT_N with pulse length 1mS */
243	__raw_writel(13000, io_p2v(LPC32XX_WDTIM_BASE + 0x18));
244	__raw_writel(0x70, io_p2v(LPC32XX_WDTIM_BASE + 0xC));
245}
246
247/*
248 * Detects and returns IRAM size for the device variation
249 */
250#define LPC32XX_IRAM_BANK_SIZE SZ_128K
251static u32 iram_size;
252u32 lpc32xx_return_iram_size(void)
253{
254	if (iram_size == 0) {
255		u32 savedval1, savedval2;
256		void __iomem *iramptr1, *iramptr2;
257
258		iramptr1 = io_p2v(LPC32XX_IRAM_BASE);
259		iramptr2 = io_p2v(LPC32XX_IRAM_BASE + LPC32XX_IRAM_BANK_SIZE);
260		savedval1 = __raw_readl(iramptr1);
261		savedval2 = __raw_readl(iramptr2);
262
263		if (savedval1 == savedval2) {
264			__raw_writel(savedval2 + 1, iramptr2);
265			if (__raw_readl(iramptr1) == savedval2 + 1)
266				iram_size = LPC32XX_IRAM_BANK_SIZE;
267			else
268				iram_size = LPC32XX_IRAM_BANK_SIZE * 2;
269			__raw_writel(savedval2, iramptr2);
270		} else
271			iram_size = LPC32XX_IRAM_BANK_SIZE * 2;
272	}
273
274	return iram_size;
275}
276
277/*
278 * Computes PLL rate from PLL register and input clock
279 */
280u32 clk_check_pll_setup(u32 ifreq, struct clk_pll_setup *pllsetup)
281{
282	u32 ilfreq, p, m, n, fcco, fref, cfreq;
283	int mode;
284
285	/*
286	 * PLL requirements
287	 * ifreq must be >= 1MHz and <= 20MHz
288	 * FCCO must be >= 156MHz and <= 320MHz
289	 * FREF must be >= 1MHz and <= 27MHz
290	 * Assume the passed input data is not valid
291	 */
292
293	ilfreq = ifreq;
294	m = pllsetup->pll_m;
295	n = pllsetup->pll_n;
296	p = pllsetup->pll_p;
297
298	mode = (pllsetup->cco_bypass_b15 << 2) |
299		(pllsetup->direct_output_b14 << 1) |
300	pllsetup->fdbk_div_ctrl_b13;
301
302	switch (mode) {
303	case 0x0: /* Non-integer mode */
304		cfreq = (m * ilfreq) / (2 * p * n);
305		fcco = (m * ilfreq) / n;
306		fref = ilfreq / n;
307		break;
308
309	case 0x1: /* integer mode */
310		cfreq = (m * ilfreq) / n;
311		fcco = (m * ilfreq) / (n * 2 * p);
312		fref = ilfreq / n;
313		break;
314
315	case 0x2:
316	case 0x3: /* Direct mode */
317		cfreq = (m * ilfreq) / n;
318		fcco = cfreq;
319		fref = ilfreq / n;
320		break;
321
322	case 0x4:
323	case 0x5: /* Bypass mode */
324		cfreq = ilfreq / (2 * p);
325		fcco = 156000000;
326		fref = 1000000;
327		break;
328
329	case 0x6:
330	case 0x7: /* Direct bypass mode */
331	default:
332		cfreq = ilfreq;
333		fcco = 156000000;
334		fref = 1000000;
335		break;
336	}
337
338	if (fcco < 156000000 || fcco > 320000000)
339		cfreq = 0;
340
341	if (fref < 1000000 || fref > 27000000)
342		cfreq = 0;
343
344	return (u32) cfreq;
345}
346
347u32 clk_get_pclk_div(void)
348{
349	return 1 + ((__raw_readl(LPC32XX_CLKPWR_HCLK_DIV) >> 2) & 0x1F);
350}
351
352static struct map_desc lpc32xx_io_desc[] __initdata = {
353	{
354		.virtual	= IO_ADDRESS(LPC32XX_AHB0_START),
355		.pfn		= __phys_to_pfn(LPC32XX_AHB0_START),
356		.length		= LPC32XX_AHB0_SIZE,
357		.type		= MT_DEVICE
358	},
359	{
360		.virtual	= IO_ADDRESS(LPC32XX_AHB1_START),
361		.pfn		= __phys_to_pfn(LPC32XX_AHB1_START),
362		.length		= LPC32XX_AHB1_SIZE,
363		.type		= MT_DEVICE
364	},
365	{
366		.virtual	= IO_ADDRESS(LPC32XX_FABAPB_START),
367		.pfn		= __phys_to_pfn(LPC32XX_FABAPB_START),
368		.length		= LPC32XX_FABAPB_SIZE,
369		.type		= MT_DEVICE
370	},
371	{
372		.virtual	= IO_ADDRESS(LPC32XX_IRAM_BASE),
373		.pfn		= __phys_to_pfn(LPC32XX_IRAM_BASE),
374		.length		= (LPC32XX_IRAM_BANK_SIZE * 2),
375		.type		= MT_DEVICE
376	},
377};
378
379void __init lpc32xx_map_io(void)
380{
381	iotable_init(lpc32xx_io_desc, ARRAY_SIZE(lpc32xx_io_desc));
382}
383
384void lpc23xx_restart(char mode, const char *cmd)
385{
386	switch (mode) {
387	case 's':
388	case 'h':
389		lpc32xx_watchdog_reset();
390		break;
391
392	default:
393		/* Do nothing */
394		break;
395	}
396
397	/* Wait for watchdog to reset system */
398	while (1)
399		;
400}
401