Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/arm/mach-lpc32xx/common.c
10817 views
1
/*
2
* arch/arm/mach-lpc32xx/common.c
3
*
4
* Author: Kevin Wells <[email protected]>
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
*/
38
static 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
46
struct 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
*/
56
static 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
62
static 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
68
static struct i2c_pnx_data i2c2_data = {
69
.name = "USB-I2C",
70
.base = LPC32XX_OTG_I2C_BASE,
71
.irq = IRQ_LPC32XX_USB_I2C,
72
};
73
74
struct platform_device lpc32xx_i2c0_device = {
75
.name = "pnx-i2c",
76
.id = 0,
77
.dev = {
78
.platform_data = &i2c0_data,
79
},
80
};
81
82
struct platform_device lpc32xx_i2c1_device = {
83
.name = "pnx-i2c",
84
.id = 1,
85
.dev = {
86
.platform_data = &i2c1_data,
87
},
88
};
89
90
struct platform_device lpc32xx_i2c2_device = {
91
.name = "pnx-i2c",
92
.id = 2,
93
.dev = {
94
.platform_data = &i2c2_data,
95
},
96
};
97
98
/*
99
* Returns the unique ID for the device
100
*/
101
void lpc32xx_get_uid(u32 devid[4])
102
{
103
int i;
104
105
for (i = 0; i < 4; i++)
106
devid[i] = __raw_readl(LPC32XX_CLKPWR_DEVID(i << 2));
107
}
108
109
/*
110
* Returns SYSCLK source
111
* 0 = PLL397, 1 = main oscillator
112
*/
113
int clk_is_sysclk_mainosc(void)
114
{
115
if ((__raw_readl(LPC32XX_CLKPWR_SYSCLK_CTRL) &
116
LPC32XX_CLKPWR_SYSCTRL_SYSCLKMUX) == 0)
117
return 1;
118
119
return 0;
120
}
121
122
/*
123
* System reset via the watchdog timer
124
*/
125
void lpc32xx_watchdog_reset(void)
126
{
127
/* Make sure WDT clocks are enabled */
128
__raw_writel(LPC32XX_CLKPWR_PWMCLK_WDOG_EN,
129
LPC32XX_CLKPWR_TIMER_CLK_CTRL);
130
131
/* Instant assert of RESETOUT_N with pulse length 1mS */
132
__raw_writel(13000, io_p2v(LPC32XX_WDTIM_BASE + 0x18));
133
__raw_writel(0x70, io_p2v(LPC32XX_WDTIM_BASE + 0xC));
134
}
135
136
/*
137
* Detects and returns IRAM size for the device variation
138
*/
139
#define LPC32XX_IRAM_BANK_SIZE SZ_128K
140
static u32 iram_size;
141
u32 lpc32xx_return_iram_size(void)
142
{
143
if (iram_size == 0) {
144
u32 savedval1, savedval2;
145
void __iomem *iramptr1, *iramptr2;
146
147
iramptr1 = io_p2v(LPC32XX_IRAM_BASE);
148
iramptr2 = io_p2v(LPC32XX_IRAM_BASE + LPC32XX_IRAM_BANK_SIZE);
149
savedval1 = __raw_readl(iramptr1);
150
savedval2 = __raw_readl(iramptr2);
151
152
if (savedval1 == savedval2) {
153
__raw_writel(savedval2 + 1, iramptr2);
154
if (__raw_readl(iramptr1) == savedval2 + 1)
155
iram_size = LPC32XX_IRAM_BANK_SIZE;
156
else
157
iram_size = LPC32XX_IRAM_BANK_SIZE * 2;
158
__raw_writel(savedval2, iramptr2);
159
} else
160
iram_size = LPC32XX_IRAM_BANK_SIZE * 2;
161
}
162
163
return iram_size;
164
}
165
166
/*
167
* Computes PLL rate from PLL register and input clock
168
*/
169
u32 clk_check_pll_setup(u32 ifreq, struct clk_pll_setup *pllsetup)
170
{
171
u32 ilfreq, p, m, n, fcco, fref, cfreq;
172
int mode;
173
174
/*
175
* PLL requirements
176
* ifreq must be >= 1MHz and <= 20MHz
177
* FCCO must be >= 156MHz and <= 320MHz
178
* FREF must be >= 1MHz and <= 27MHz
179
* Assume the passed input data is not valid
180
*/
181
182
ilfreq = ifreq;
183
m = pllsetup->pll_m;
184
n = pllsetup->pll_n;
185
p = pllsetup->pll_p;
186
187
mode = (pllsetup->cco_bypass_b15 << 2) |
188
(pllsetup->direct_output_b14 << 1) |
189
pllsetup->fdbk_div_ctrl_b13;
190
191
switch (mode) {
192
case 0x0: /* Non-integer mode */
193
cfreq = (m * ilfreq) / (2 * p * n);
194
fcco = (m * ilfreq) / n;
195
fref = ilfreq / n;
196
break;
197
198
case 0x1: /* integer mode */
199
cfreq = (m * ilfreq) / n;
200
fcco = (m * ilfreq) / (n * 2 * p);
201
fref = ilfreq / n;
202
break;
203
204
case 0x2:
205
case 0x3: /* Direct mode */
206
cfreq = (m * ilfreq) / n;
207
fcco = cfreq;
208
fref = ilfreq / n;
209
break;
210
211
case 0x4:
212
case 0x5: /* Bypass mode */
213
cfreq = ilfreq / (2 * p);
214
fcco = 156000000;
215
fref = 1000000;
216
break;
217
218
case 0x6:
219
case 0x7: /* Direct bypass mode */
220
default:
221
cfreq = ilfreq;
222
fcco = 156000000;
223
fref = 1000000;
224
break;
225
}
226
227
if (fcco < 156000000 || fcco > 320000000)
228
cfreq = 0;
229
230
if (fref < 1000000 || fref > 27000000)
231
cfreq = 0;
232
233
return (u32) cfreq;
234
}
235
236
u32 clk_get_pclk_div(void)
237
{
238
return 1 + ((__raw_readl(LPC32XX_CLKPWR_HCLK_DIV) >> 2) & 0x1F);
239
}
240
241
static struct map_desc lpc32xx_io_desc[] __initdata = {
242
{
243
.virtual = IO_ADDRESS(LPC32XX_AHB0_START),
244
.pfn = __phys_to_pfn(LPC32XX_AHB0_START),
245
.length = LPC32XX_AHB0_SIZE,
246
.type = MT_DEVICE
247
},
248
{
249
.virtual = IO_ADDRESS(LPC32XX_AHB1_START),
250
.pfn = __phys_to_pfn(LPC32XX_AHB1_START),
251
.length = LPC32XX_AHB1_SIZE,
252
.type = MT_DEVICE
253
},
254
{
255
.virtual = IO_ADDRESS(LPC32XX_FABAPB_START),
256
.pfn = __phys_to_pfn(LPC32XX_FABAPB_START),
257
.length = LPC32XX_FABAPB_SIZE,
258
.type = MT_DEVICE
259
},
260
{
261
.virtual = IO_ADDRESS(LPC32XX_IRAM_BASE),
262
.pfn = __phys_to_pfn(LPC32XX_IRAM_BASE),
263
.length = (LPC32XX_IRAM_BANK_SIZE * 2),
264
.type = MT_DEVICE
265
},
266
};
267
268
void __init lpc32xx_map_io(void)
269
{
270
iotable_init(lpc32xx_io_desc, ARRAY_SIZE(lpc32xx_io_desc));
271
}
272
273