diff options
author | Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 2011-11-10 21:46:23 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2011-11-11 02:55:35 -0500 |
commit | 6831f3a9184a1c5400e4fa2f2d3172b6dfb2c805 (patch) | |
tree | fa8387979cf64074448cb028daf785f2d87c91e1 /arch/arm/mach-shmobile/setup-r8a7740.c | |
parent | 5ade0672f2a2142de216ca705692c9d3238ee650 (diff) |
ARM: mach-shmobile: r8a7740: add i2c support
This patch adds I2C support to r8a7740 CPU
which has lasting errata on I2C I/O pad reset.
This patch is including work-around.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/arm/mach-shmobile/setup-r8a7740.c')
-rw-r--r-- | arch/arm/mach-shmobile/setup-r8a7740.c | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c index 55485187f0c7..e16860f04934 100644 --- a/arch/arm/mach-shmobile/setup-r8a7740.c +++ b/arch/arm/mach-shmobile/setup-r8a7740.c | |||
@@ -17,8 +17,10 @@ | |||
17 | * along with this program; if not, write to the Free Software | 17 | * along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
19 | */ | 19 | */ |
20 | #include <linux/delay.h> | ||
20 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
21 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/io.h> | ||
22 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
23 | #include <linux/serial_sci.h> | 25 | #include <linux/serial_sci.h> |
24 | #include <linux/sh_timer.h> | 26 | #include <linux/sh_timer.h> |
@@ -233,10 +235,114 @@ static struct platform_device *r8a7740_early_devices[] __initdata = { | |||
233 | &cmt10_device, | 235 | &cmt10_device, |
234 | }; | 236 | }; |
235 | 237 | ||
238 | /* I2C */ | ||
239 | static struct resource i2c0_resources[] = { | ||
240 | [0] = { | ||
241 | .name = "IIC0", | ||
242 | .start = 0xfff20000, | ||
243 | .end = 0xfff20425 - 1, | ||
244 | .flags = IORESOURCE_MEM, | ||
245 | }, | ||
246 | [1] = { | ||
247 | .start = gic_spi(201), | ||
248 | .end = gic_spi(204), | ||
249 | .flags = IORESOURCE_IRQ, | ||
250 | }, | ||
251 | }; | ||
252 | |||
253 | static struct resource i2c1_resources[] = { | ||
254 | [0] = { | ||
255 | .name = "IIC1", | ||
256 | .start = 0xe6c20000, | ||
257 | .end = 0xe6c20425 - 1, | ||
258 | .flags = IORESOURCE_MEM, | ||
259 | }, | ||
260 | [1] = { | ||
261 | .start = gic_spi(70), | ||
262 | .end = gic_spi(73), | ||
263 | .flags = IORESOURCE_IRQ, | ||
264 | }, | ||
265 | }; | ||
266 | |||
267 | static struct platform_device i2c0_device = { | ||
268 | .name = "i2c-sh_mobile", | ||
269 | .id = 0, | ||
270 | .resource = i2c0_resources, | ||
271 | .num_resources = ARRAY_SIZE(i2c0_resources), | ||
272 | }; | ||
273 | |||
274 | static struct platform_device i2c1_device = { | ||
275 | .name = "i2c-sh_mobile", | ||
276 | .id = 1, | ||
277 | .resource = i2c1_resources, | ||
278 | .num_resources = ARRAY_SIZE(i2c1_resources), | ||
279 | }; | ||
280 | |||
281 | static struct platform_device *r8a7740_late_devices[] __initdata = { | ||
282 | &i2c0_device, | ||
283 | &i2c1_device, | ||
284 | }; | ||
285 | |||
286 | #define ICCR 0x0004 | ||
287 | #define ICSTART 0x0070 | ||
288 | |||
289 | #define i2c_read(reg, offset) ioread8(reg + offset) | ||
290 | #define i2c_write(reg, offset, data) iowrite8(data, reg + offset) | ||
291 | |||
292 | /* | ||
293 | * r8a7740 chip has lasting errata on I2C I/O pad reset. | ||
294 | * this is work-around for it. | ||
295 | */ | ||
296 | static void r8a7740_i2c_workaround(struct platform_device *pdev) | ||
297 | { | ||
298 | struct resource *res; | ||
299 | void __iomem *reg; | ||
300 | |||
301 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
302 | if (unlikely(!res)) { | ||
303 | pr_err("r8a7740 i2c workaround fail (cannot find resource)\n"); | ||
304 | return; | ||
305 | } | ||
306 | |||
307 | reg = ioremap(res->start, resource_size(res)); | ||
308 | if (unlikely(!reg)) { | ||
309 | pr_err("r8a7740 i2c workaround fail (cannot map IO)\n"); | ||
310 | return; | ||
311 | } | ||
312 | |||
313 | i2c_write(reg, ICCR, i2c_read(reg, ICCR) | 0x80); | ||
314 | i2c_read(reg, ICCR); /* dummy read */ | ||
315 | |||
316 | i2c_write(reg, ICSTART, i2c_read(reg, ICSTART) | 0x10); | ||
317 | i2c_read(reg, ICSTART); /* dummy read */ | ||
318 | |||
319 | mdelay(100); | ||
320 | |||
321 | i2c_write(reg, ICCR, 0x01); | ||
322 | i2c_read(reg, ICCR); | ||
323 | i2c_write(reg, ICSTART, 0x00); | ||
324 | i2c_read(reg, ICSTART); | ||
325 | |||
326 | i2c_write(reg, ICCR, 0x10); | ||
327 | mdelay(100); | ||
328 | i2c_write(reg, ICCR, 0x00); | ||
329 | mdelay(100); | ||
330 | i2c_write(reg, ICCR, 0x10); | ||
331 | mdelay(100); | ||
332 | |||
333 | iounmap(reg); | ||
334 | } | ||
335 | |||
236 | void __init r8a7740_add_standard_devices(void) | 336 | void __init r8a7740_add_standard_devices(void) |
237 | { | 337 | { |
338 | /* I2C work-around */ | ||
339 | r8a7740_i2c_workaround(&i2c0_device); | ||
340 | r8a7740_i2c_workaround(&i2c1_device); | ||
341 | |||
238 | platform_add_devices(r8a7740_early_devices, | 342 | platform_add_devices(r8a7740_early_devices, |
239 | ARRAY_SIZE(r8a7740_early_devices)); | 343 | ARRAY_SIZE(r8a7740_early_devices)); |
344 | platform_add_devices(r8a7740_late_devices, | ||
345 | ARRAY_SIZE(r8a7740_late_devices)); | ||
240 | } | 346 | } |
241 | 347 | ||
242 | void __init r8a7740_add_early_devices(void) | 348 | void __init r8a7740_add_early_devices(void) |