]>
Commit | Line | Data |
---|---|---|
02bf6cc7 PM |
1 | /* |
2 | * Renesas Technology Europe SDK7786 Support. | |
3 | * | |
4 | * Copyright (C) 2010 Matt Fleming | |
5 | * Copyright (C) 2010 Paul Mundt | |
6 | * | |
7 | * This file is subject to the terms and conditions of the GNU General Public | |
8 | * License. See the file "COPYING" in the main directory of this archive | |
9 | * for more details. | |
10 | */ | |
11 | #include <linux/init.h> | |
12 | #include <linux/platform_device.h> | |
13 | #include <linux/io.h> | |
2fcfe22a GL |
14 | #include <linux/regulator/fixed.h> |
15 | #include <linux/regulator/machine.h> | |
02bf6cc7 PM |
16 | #include <linux/smsc911x.h> |
17 | #include <linux/i2c.h> | |
18 | #include <linux/irq.h> | |
c8098218 | 19 | #include <linux/clk.h> |
3bd75e5e | 20 | #include <linux/clkdev.h> |
5f240718 PM |
21 | #include <mach/fpga.h> |
22 | #include <mach/irq.h> | |
02bf6cc7 | 23 | #include <asm/machvec.h> |
2267c787 | 24 | #include <asm/heartbeat.h> |
02bf6cc7 | 25 | #include <asm/sizes.h> |
b6b77b2d | 26 | #include <asm/clock.h> |
b51989b8 | 27 | #include <asm/reboot.h> |
3366e358 | 28 | #include <asm/smp-ops.h> |
02bf6cc7 | 29 | |
2267c787 PM |
30 | static struct resource heartbeat_resource = { |
31 | .start = 0x07fff8b0, | |
32 | .end = 0x07fff8b0 + sizeof(u16) - 1, | |
33 | .flags = IORESOURCE_MEM | IORESOURCE_MEM_16BIT, | |
34 | }; | |
35 | ||
36 | static struct platform_device heartbeat_device = { | |
37 | .name = "heartbeat", | |
38 | .id = -1, | |
39 | .num_resources = 1, | |
40 | .resource = &heartbeat_resource, | |
41 | }; | |
42 | ||
2fcfe22a GL |
43 | /* Dummy supplies, where voltage doesn't matter */ |
44 | static struct regulator_consumer_supply dummy_supplies[] = { | |
45 | REGULATOR_SUPPLY("vddvario", "smsc911x"), | |
46 | REGULATOR_SUPPLY("vdd33a", "smsc911x"), | |
47 | }; | |
48 | ||
02bf6cc7 PM |
49 | static struct resource smsc911x_resources[] = { |
50 | [0] = { | |
51 | .name = "smsc911x-memory", | |
52 | .start = 0x07ffff00, | |
53 | .end = 0x07ffff00 + SZ_256 - 1, | |
54 | .flags = IORESOURCE_MEM, | |
55 | }, | |
56 | [1] = { | |
57 | .name = "smsc911x-irq", | |
58 | .start = evt2irq(0x2c0), | |
59 | .end = evt2irq(0x2c0), | |
60 | .flags = IORESOURCE_IRQ, | |
61 | }, | |
62 | }; | |
63 | ||
64 | static struct smsc911x_platform_config smsc911x_config = { | |
65 | .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, | |
66 | .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN, | |
67 | .flags = SMSC911X_USE_32BIT, | |
68 | .phy_interface = PHY_INTERFACE_MODE_MII, | |
69 | }; | |
70 | ||
71 | static struct platform_device smsc911x_device = { | |
72 | .name = "smsc911x", | |
73 | .id = -1, | |
74 | .num_resources = ARRAY_SIZE(smsc911x_resources), | |
75 | .resource = smsc911x_resources, | |
76 | .dev = { | |
77 | .platform_data = &smsc911x_config, | |
78 | }, | |
79 | }; | |
80 | ||
81 | static struct resource smbus_fpga_resource = { | |
82 | .start = 0x07fff9e0, | |
83 | .end = 0x07fff9e0 + SZ_32 - 1, | |
84 | .flags = IORESOURCE_MEM, | |
85 | }; | |
86 | ||
87 | static struct platform_device smbus_fpga_device = { | |
88 | .name = "i2c-sdk7786", | |
89 | .id = 0, | |
90 | .num_resources = 1, | |
91 | .resource = &smbus_fpga_resource, | |
92 | }; | |
93 | ||
94 | static struct resource smbus_pcie_resource = { | |
95 | .start = 0x07fffc30, | |
96 | .end = 0x07fffc30 + SZ_32 - 1, | |
97 | .flags = IORESOURCE_MEM, | |
98 | }; | |
99 | ||
100 | static struct platform_device smbus_pcie_device = { | |
101 | .name = "i2c-sdk7786", | |
102 | .id = 1, | |
103 | .num_resources = 1, | |
104 | .resource = &smbus_pcie_resource, | |
105 | }; | |
106 | ||
107 | static struct i2c_board_info __initdata sdk7786_i2c_devices[] = { | |
108 | { | |
109 | I2C_BOARD_INFO("max6900", 0x68), | |
110 | }, | |
111 | }; | |
112 | ||
113 | static struct platform_device *sh7786_devices[] __initdata = { | |
2267c787 | 114 | &heartbeat_device, |
02bf6cc7 PM |
115 | &smsc911x_device, |
116 | &smbus_fpga_device, | |
117 | &smbus_pcie_device, | |
118 | }; | |
119 | ||
02bf6cc7 PM |
120 | static int sdk7786_i2c_setup(void) |
121 | { | |
02bf6cc7 PM |
122 | unsigned int tmp; |
123 | ||
02bf6cc7 PM |
124 | /* |
125 | * Hand over I2C control to the FPGA. | |
126 | */ | |
efd590d5 | 127 | tmp = fpga_read_reg(SBCR); |
02bf6cc7 PM |
128 | tmp &= ~SCBR_I2CCEN; |
129 | tmp |= SCBR_I2CMEN; | |
efd590d5 | 130 | fpga_write_reg(tmp, SBCR); |
02bf6cc7 PM |
131 | |
132 | return i2c_register_board_info(0, sdk7786_i2c_devices, | |
133 | ARRAY_SIZE(sdk7786_i2c_devices)); | |
134 | } | |
135 | ||
136 | static int __init sdk7786_devices_setup(void) | |
137 | { | |
138 | int ret; | |
139 | ||
140 | ret = platform_add_devices(sh7786_devices, ARRAY_SIZE(sh7786_devices)); | |
141 | if (unlikely(ret != 0)) | |
142 | return ret; | |
143 | ||
144 | return sdk7786_i2c_setup(); | |
145 | } | |
95d210ce | 146 | device_initcall(sdk7786_devices_setup); |
02bf6cc7 | 147 | |
6f832e8a PM |
148 | static int sdk7786_mode_pins(void) |
149 | { | |
efd590d5 | 150 | return fpga_read_reg(MODSWR); |
6f832e8a PM |
151 | } |
152 | ||
b6b77b2d PM |
153 | /* |
154 | * FPGA-driven PCIe clocks | |
155 | * | |
156 | * Historically these include the oscillator, clock B (slots 2/3/4) and | |
157 | * clock A (slot 1 and the CPU clock). Newer revs of the PCB shove | |
158 | * everything under a single PCIe clocks enable bit that happens to map | |
159 | * to the same bit position as the oscillator bit for earlier FPGA | |
160 | * versions. | |
161 | * | |
162 | * Given that the legacy clocks have the side-effect of shutting the CPU | |
163 | * off through the FPGA along with the PCI slots, we simply leave them in | |
164 | * their initial state and don't bother registering them with the clock | |
165 | * framework. | |
166 | */ | |
167 | static int sdk7786_pcie_clk_enable(struct clk *clk) | |
168 | { | |
169 | fpga_write_reg(fpga_read_reg(PCIECR) | PCIECR_CLKEN, PCIECR); | |
170 | return 0; | |
171 | } | |
172 | ||
173 | static void sdk7786_pcie_clk_disable(struct clk *clk) | |
174 | { | |
175 | fpga_write_reg(fpga_read_reg(PCIECR) & ~PCIECR_CLKEN, PCIECR); | |
176 | } | |
177 | ||
c953efdb | 178 | static struct sh_clk_ops sdk7786_pcie_clk_ops = { |
b6b77b2d PM |
179 | .enable = sdk7786_pcie_clk_enable, |
180 | .disable = sdk7786_pcie_clk_disable, | |
181 | }; | |
182 | ||
183 | static struct clk sdk7786_pcie_clk = { | |
184 | .ops = &sdk7786_pcie_clk_ops, | |
185 | }; | |
186 | ||
187 | static struct clk_lookup sdk7786_pcie_cl = { | |
188 | .con_id = "pcie_plat_clk", | |
189 | .clk = &sdk7786_pcie_clk, | |
190 | }; | |
191 | ||
c8098218 PM |
192 | static int sdk7786_clk_init(void) |
193 | { | |
194 | struct clk *clk; | |
195 | int ret; | |
196 | ||
197 | /* | |
198 | * Only handle the EXTAL case, anyone interfacing a crystal | |
199 | * resonator will need to provide their own input clock. | |
200 | */ | |
201 | if (test_mode_pin(MODE_PIN9)) | |
202 | return -EINVAL; | |
203 | ||
204 | clk = clk_get(NULL, "extal"); | |
7912825d | 205 | if (IS_ERR(clk)) |
c8098218 PM |
206 | return PTR_ERR(clk); |
207 | ret = clk_set_rate(clk, 33333333); | |
208 | clk_put(clk); | |
209 | ||
b6b77b2d PM |
210 | /* |
211 | * Setup the FPGA clocks. | |
212 | */ | |
213 | ret = clk_register(&sdk7786_pcie_clk); | |
214 | if (unlikely(ret)) { | |
215 | pr_err("FPGA clock registration failed\n"); | |
216 | return ret; | |
217 | } | |
218 | ||
219 | clkdev_add(&sdk7786_pcie_cl); | |
220 | ||
221 | return 0; | |
c8098218 PM |
222 | } |
223 | ||
b51989b8 PM |
224 | static void sdk7786_restart(char *cmd) |
225 | { | |
226 | fpga_write_reg(0xa5a5, SRSTR); | |
227 | } | |
228 | ||
d9c94446 PM |
229 | static void sdk7786_power_off(void) |
230 | { | |
231 | fpga_write_reg(fpga_read_reg(PWRCR) | PWRCR_PDWNREQ, PWRCR); | |
232 | ||
233 | /* | |
234 | * It can take up to 20us for the R8C to do its job, back off and | |
235 | * wait a bit until we've been shut off. Even though newer FPGA | |
236 | * versions don't set the ACK bit, the latency issue remains. | |
237 | */ | |
238 | while ((fpga_read_reg(PWRCR) & PWRCR_PDWNACK) == 0) | |
239 | cpu_sleep(); | |
240 | } | |
241 | ||
02bf6cc7 PM |
242 | /* Initialize the board */ |
243 | static void __init sdk7786_setup(char **cmdline_p) | |
244 | { | |
efd590d5 PM |
245 | pr_info("Renesas Technology Europe SDK7786 support:\n"); |
246 | ||
2fcfe22a GL |
247 | regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies)); |
248 | ||
efd590d5 | 249 | sdk7786_fpga_init(); |
76496f8f | 250 | sdk7786_nmi_init(); |
efd590d5 PM |
251 | |
252 | pr_info("\tPCB revision:\t%d\n", fpga_read_reg(PCBRR) & 0xf); | |
b51989b8 PM |
253 | |
254 | machine_ops.restart = sdk7786_restart; | |
d9c94446 | 255 | pm_power_off = sdk7786_power_off; |
3366e358 PM |
256 | |
257 | register_smp_ops(&shx3_smp_ops); | |
02bf6cc7 PM |
258 | } |
259 | ||
260 | /* | |
261 | * The Machine Vector | |
262 | */ | |
263 | static struct sh_machine_vector mv_sdk7786 __initmv = { | |
264 | .mv_name = "SDK7786", | |
265 | .mv_setup = sdk7786_setup, | |
6f832e8a | 266 | .mv_mode_pins = sdk7786_mode_pins, |
c8098218 | 267 | .mv_clk_init = sdk7786_clk_init, |
5f240718 | 268 | .mv_init_irq = sdk7786_init_irq, |
02bf6cc7 | 269 | }; |