diff options
Diffstat (limited to 'arch/sh/boards/mach-migor/setup.c')
-rw-r--r-- | arch/sh/boards/mach-migor/setup.c | 225 |
1 files changed, 100 insertions, 125 deletions
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index 0bcbe58b11e9..271dfc260e82 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c | |||
@@ -1,17 +1,16 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * Renesas System Solutions Asia Pte. Ltd - Migo-R | 3 | * Renesas System Solutions Asia Pte. Ltd - Migo-R |
3 | * | 4 | * |
4 | * Copyright (C) 2008 Magnus Damm | 5 | * Copyright (C) 2008 Magnus Damm |
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | 6 | */ |
7 | #include <linux/clkdev.h> | ||
10 | #include <linux/init.h> | 8 | #include <linux/init.h> |
11 | #include <linux/platform_device.h> | 9 | #include <linux/platform_device.h> |
12 | #include <linux/interrupt.h> | 10 | #include <linux/interrupt.h> |
13 | #include <linux/input.h> | 11 | #include <linux/input.h> |
14 | #include <linux/input/sh_keysc.h> | 12 | #include <linux/input/sh_keysc.h> |
13 | #include <linux/memblock.h> | ||
15 | #include <linux/mmc/host.h> | 14 | #include <linux/mmc/host.h> |
16 | #include <linux/mtd/physmap.h> | 15 | #include <linux/mtd/physmap.h> |
17 | #include <linux/mfd/tmio.h> | 16 | #include <linux/mfd/tmio.h> |
@@ -23,10 +22,11 @@ | |||
23 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
24 | #include <linux/clk.h> | 23 | #include <linux/clk.h> |
25 | #include <linux/gpio.h> | 24 | #include <linux/gpio.h> |
25 | #include <linux/gpio/machine.h> | ||
26 | #include <linux/videodev2.h> | 26 | #include <linux/videodev2.h> |
27 | #include <linux/sh_intc.h> | 27 | #include <linux/sh_intc.h> |
28 | #include <video/sh_mobile_lcdc.h> | 28 | #include <video/sh_mobile_lcdc.h> |
29 | #include <media/drv-intf/sh_mobile_ceu.h> | 29 | #include <media/drv-intf/renesas-ceu.h> |
30 | #include <media/i2c/ov772x.h> | 30 | #include <media/i2c/ov772x.h> |
31 | #include <media/soc_camera.h> | 31 | #include <media/soc_camera.h> |
32 | #include <media/i2c/tw9910.h> | 32 | #include <media/i2c/tw9910.h> |
@@ -45,6 +45,9 @@ | |||
45 | * 0x18000000 8GB 8 NAND Flash (K9K8G08U0A) | 45 | * 0x18000000 8GB 8 NAND Flash (K9K8G08U0A) |
46 | */ | 46 | */ |
47 | 47 | ||
48 | #define CEU_BUFFER_MEMORY_SIZE (4 << 20) | ||
49 | static phys_addr_t ceu_dma_membase; | ||
50 | |||
48 | static struct smc91x_platdata smc91x_info = { | 51 | static struct smc91x_platdata smc91x_info = { |
49 | .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT, | 52 | .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT, |
50 | }; | 53 | }; |
@@ -301,65 +304,24 @@ static struct platform_device migor_lcdc_device = { | |||
301 | }, | 304 | }, |
302 | }; | 305 | }; |
303 | 306 | ||
304 | static struct clk *camera_clk; | 307 | static struct ceu_platform_data ceu_pdata = { |
305 | static DEFINE_MUTEX(camera_lock); | 308 | .num_subdevs = 2, |
306 | 309 | .subdevs = { | |
307 | static void camera_power_on(int is_tw) | 310 | { /* [0] = ov772x */ |
308 | { | 311 | .flags = 0, |
309 | mutex_lock(&camera_lock); | 312 | .bus_width = 8, |
310 | 313 | .bus_shift = 0, | |
311 | /* Use 10 MHz VIO_CKO instead of 24 MHz to work | 314 | .i2c_adapter_id = 0, |
312 | * around signal quality issues on Panel Board V2.1. | 315 | .i2c_address = 0x21, |
313 | */ | 316 | }, |
314 | camera_clk = clk_get(NULL, "video_clk"); | 317 | { /* [1] = tw9910 */ |
315 | clk_set_rate(camera_clk, 10000000); | 318 | .flags = 0, |
316 | clk_enable(camera_clk); /* start VIO_CKO */ | 319 | .bus_width = 8, |
317 | 320 | .bus_shift = 0, | |
318 | /* use VIO_RST to take camera out of reset */ | 321 | .i2c_adapter_id = 0, |
319 | mdelay(10); | 322 | .i2c_address = 0x45, |
320 | if (is_tw) { | 323 | }, |
321 | gpio_set_value(GPIO_PTT2, 0); | 324 | }, |
322 | gpio_set_value(GPIO_PTT0, 0); | ||
323 | } else { | ||
324 | gpio_set_value(GPIO_PTT0, 1); | ||
325 | } | ||
326 | gpio_set_value(GPIO_PTT3, 0); | ||
327 | mdelay(10); | ||
328 | gpio_set_value(GPIO_PTT3, 1); | ||
329 | mdelay(10); /* wait to let chip come out of reset */ | ||
330 | } | ||
331 | |||
332 | static void camera_power_off(void) | ||
333 | { | ||
334 | clk_disable(camera_clk); /* stop VIO_CKO */ | ||
335 | clk_put(camera_clk); | ||
336 | |||
337 | gpio_set_value(GPIO_PTT3, 0); | ||
338 | mutex_unlock(&camera_lock); | ||
339 | } | ||
340 | |||
341 | static int ov7725_power(struct device *dev, int mode) | ||
342 | { | ||
343 | if (mode) | ||
344 | camera_power_on(0); | ||
345 | else | ||
346 | camera_power_off(); | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static int tw9910_power(struct device *dev, int mode) | ||
352 | { | ||
353 | if (mode) | ||
354 | camera_power_on(1); | ||
355 | else | ||
356 | camera_power_off(); | ||
357 | |||
358 | return 0; | ||
359 | } | ||
360 | |||
361 | static struct sh_mobile_ceu_info sh_mobile_ceu_info = { | ||
362 | .flags = SH_CEU_FLAG_USE_8BIT_BUS, | ||
363 | }; | 325 | }; |
364 | 326 | ||
365 | static struct resource migor_ceu_resources[] = { | 327 | static struct resource migor_ceu_resources[] = { |
@@ -373,18 +335,32 @@ static struct resource migor_ceu_resources[] = { | |||
373 | .start = evt2irq(0x880), | 335 | .start = evt2irq(0x880), |
374 | .flags = IORESOURCE_IRQ, | 336 | .flags = IORESOURCE_IRQ, |
375 | }, | 337 | }, |
376 | [2] = { | ||
377 | /* place holder for contiguous memory */ | ||
378 | }, | ||
379 | }; | 338 | }; |
380 | 339 | ||
381 | static struct platform_device migor_ceu_device = { | 340 | static struct platform_device migor_ceu_device = { |
382 | .name = "sh_mobile_ceu", | 341 | .name = "renesas-ceu", |
383 | .id = 0, /* "ceu0" clock */ | 342 | .id = 0, /* ceu.0 */ |
384 | .num_resources = ARRAY_SIZE(migor_ceu_resources), | 343 | .num_resources = ARRAY_SIZE(migor_ceu_resources), |
385 | .resource = migor_ceu_resources, | 344 | .resource = migor_ceu_resources, |
386 | .dev = { | 345 | .dev = { |
387 | .platform_data = &sh_mobile_ceu_info, | 346 | .platform_data = &ceu_pdata, |
347 | }, | ||
348 | }; | ||
349 | |||
350 | /* Powerdown/reset gpios for CEU image sensors */ | ||
351 | static struct gpiod_lookup_table ov7725_gpios = { | ||
352 | .dev_id = "0-0021", | ||
353 | .table = { | ||
354 | GPIO_LOOKUP("sh7722_pfc", GPIO_PTT0, "pwdn", GPIO_ACTIVE_HIGH), | ||
355 | GPIO_LOOKUP("sh7722_pfc", GPIO_PTT3, "rstb", GPIO_ACTIVE_LOW), | ||
356 | }, | ||
357 | }; | ||
358 | |||
359 | static struct gpiod_lookup_table tw9910_gpios = { | ||
360 | .dev_id = "0-0045", | ||
361 | .table = { | ||
362 | GPIO_LOOKUP("sh7722_pfc", GPIO_PTT2, "pdn", GPIO_ACTIVE_HIGH), | ||
363 | GPIO_LOOKUP("sh7722_pfc", GPIO_PTT3, "rstb", GPIO_ACTIVE_LOW), | ||
388 | }, | 364 | }, |
389 | }; | 365 | }; |
390 | 366 | ||
@@ -423,6 +399,15 @@ static struct platform_device sdhi_cn9_device = { | |||
423 | }, | 399 | }, |
424 | }; | 400 | }; |
425 | 401 | ||
402 | static struct ov772x_camera_info ov7725_info = { | ||
403 | .flags = 0, | ||
404 | }; | ||
405 | |||
406 | static struct tw9910_video_info tw9910_info = { | ||
407 | .buswidth = 8, | ||
408 | .mpout = TW9910_MPO_FIELD, | ||
409 | }; | ||
410 | |||
426 | static struct i2c_board_info migor_i2c_devices[] = { | 411 | static struct i2c_board_info migor_i2c_devices[] = { |
427 | { | 412 | { |
428 | I2C_BOARD_INFO("rs5c372b", 0x32), | 413 | I2C_BOARD_INFO("rs5c372b", 0x32), |
@@ -434,51 +419,13 @@ static struct i2c_board_info migor_i2c_devices[] = { | |||
434 | { | 419 | { |
435 | I2C_BOARD_INFO("wm8978", 0x1a), | 420 | I2C_BOARD_INFO("wm8978", 0x1a), |
436 | }, | 421 | }, |
437 | }; | ||
438 | |||
439 | static struct i2c_board_info migor_i2c_camera[] = { | ||
440 | { | 422 | { |
441 | I2C_BOARD_INFO("ov772x", 0x21), | 423 | I2C_BOARD_INFO("ov772x", 0x21), |
424 | .platform_data = &ov7725_info, | ||
442 | }, | 425 | }, |
443 | { | 426 | { |
444 | I2C_BOARD_INFO("tw9910", 0x45), | 427 | I2C_BOARD_INFO("tw9910", 0x45), |
445 | }, | 428 | .platform_data = &tw9910_info, |
446 | }; | ||
447 | |||
448 | static struct ov772x_camera_info ov7725_info; | ||
449 | |||
450 | static struct soc_camera_link ov7725_link = { | ||
451 | .power = ov7725_power, | ||
452 | .board_info = &migor_i2c_camera[0], | ||
453 | .i2c_adapter_id = 0, | ||
454 | .priv = &ov7725_info, | ||
455 | }; | ||
456 | |||
457 | static struct tw9910_video_info tw9910_info = { | ||
458 | .buswidth = SOCAM_DATAWIDTH_8, | ||
459 | .mpout = TW9910_MPO_FIELD, | ||
460 | }; | ||
461 | |||
462 | static struct soc_camera_link tw9910_link = { | ||
463 | .power = tw9910_power, | ||
464 | .board_info = &migor_i2c_camera[1], | ||
465 | .i2c_adapter_id = 0, | ||
466 | .priv = &tw9910_info, | ||
467 | }; | ||
468 | |||
469 | static struct platform_device migor_camera[] = { | ||
470 | { | ||
471 | .name = "soc-camera-pdrv", | ||
472 | .id = 0, | ||
473 | .dev = { | ||
474 | .platform_data = &ov7725_link, | ||
475 | }, | ||
476 | }, { | ||
477 | .name = "soc-camera-pdrv", | ||
478 | .id = 1, | ||
479 | .dev = { | ||
480 | .platform_data = &tw9910_link, | ||
481 | }, | ||
482 | }, | 429 | }, |
483 | }; | 430 | }; |
484 | 431 | ||
@@ -486,12 +433,9 @@ static struct platform_device *migor_devices[] __initdata = { | |||
486 | &smc91x_eth_device, | 433 | &smc91x_eth_device, |
487 | &sh_keysc_device, | 434 | &sh_keysc_device, |
488 | &migor_lcdc_device, | 435 | &migor_lcdc_device, |
489 | &migor_ceu_device, | ||
490 | &migor_nor_flash_device, | 436 | &migor_nor_flash_device, |
491 | &migor_nand_flash_device, | 437 | &migor_nand_flash_device, |
492 | &sdhi_cn9_device, | 438 | &sdhi_cn9_device, |
493 | &migor_camera[0], | ||
494 | &migor_camera[1], | ||
495 | }; | 439 | }; |
496 | 440 | ||
497 | extern char migor_sdram_enter_start; | 441 | extern char migor_sdram_enter_start; |
@@ -501,6 +445,8 @@ extern char migor_sdram_leave_end; | |||
501 | 445 | ||
502 | static int __init migor_devices_setup(void) | 446 | static int __init migor_devices_setup(void) |
503 | { | 447 | { |
448 | struct clk *video_clk; | ||
449 | |||
504 | /* register board specific self-refresh code */ | 450 | /* register board specific self-refresh code */ |
505 | sh_mobile_register_self_refresh(SUSP_SH_STANDBY | SUSP_SH_SF, | 451 | sh_mobile_register_self_refresh(SUSP_SH_STANDBY | SUSP_SH_SF, |
506 | &migor_sdram_enter_start, | 452 | &migor_sdram_enter_start, |
@@ -620,20 +566,8 @@ static int __init migor_devices_setup(void) | |||
620 | gpio_request(GPIO_FN_VIO_D9, NULL); | 566 | gpio_request(GPIO_FN_VIO_D9, NULL); |
621 | gpio_request(GPIO_FN_VIO_D8, NULL); | 567 | gpio_request(GPIO_FN_VIO_D8, NULL); |
622 | 568 | ||
623 | gpio_request(GPIO_PTT3, NULL); /* VIO_RST */ | ||
624 | gpio_direction_output(GPIO_PTT3, 0); | ||
625 | gpio_request(GPIO_PTT2, NULL); /* TV_IN_EN */ | ||
626 | gpio_direction_output(GPIO_PTT2, 1); | ||
627 | gpio_request(GPIO_PTT0, NULL); /* CAM_EN */ | ||
628 | #ifdef CONFIG_SH_MIGOR_RTA_WVGA | ||
629 | gpio_direction_output(GPIO_PTT0, 0); | ||
630 | #else | ||
631 | gpio_direction_output(GPIO_PTT0, 1); | ||
632 | #endif | ||
633 | __raw_writew(__raw_readw(PORT_MSELCRB) | 0x2000, PORT_MSELCRB); /* D15->D8 */ | 569 | __raw_writew(__raw_readw(PORT_MSELCRB) | 0x2000, PORT_MSELCRB); /* D15->D8 */ |
634 | 570 | ||
635 | platform_resource_setup_memory(&migor_ceu_device, "ceu", 4 << 20); | ||
636 | |||
637 | /* SIU: Port B */ | 571 | /* SIU: Port B */ |
638 | gpio_request(GPIO_FN_SIUBOLR, NULL); | 572 | gpio_request(GPIO_FN_SIUBOLR, NULL); |
639 | gpio_request(GPIO_FN_SIUBOBT, NULL); | 573 | gpio_request(GPIO_FN_SIUBOBT, NULL); |
@@ -647,9 +581,36 @@ static int __init migor_devices_setup(void) | |||
647 | */ | 581 | */ |
648 | __raw_writew(__raw_readw(PORT_MSELCRA) | 1, PORT_MSELCRA); | 582 | __raw_writew(__raw_readw(PORT_MSELCRA) | 1, PORT_MSELCRA); |
649 | 583 | ||
584 | /* | ||
585 | * Use 10 MHz VIO_CKO instead of 24 MHz to work around signal quality | ||
586 | * issues on Panel Board V2.1. | ||
587 | */ | ||
588 | video_clk = clk_get(NULL, "video_clk"); | ||
589 | if (!IS_ERR(video_clk)) { | ||
590 | clk_set_rate(video_clk, clk_round_rate(video_clk, 10000000)); | ||
591 | clk_put(video_clk); | ||
592 | } | ||
593 | |||
594 | /* Add a clock alias for ov7725 xclk source. */ | ||
595 | clk_add_alias("xclk", "0-0021", "video_clk", NULL); | ||
596 | |||
597 | /* Register GPIOs for video sources. */ | ||
598 | gpiod_add_lookup_table(&ov7725_gpios); | ||
599 | gpiod_add_lookup_table(&tw9910_gpios); | ||
600 | |||
650 | i2c_register_board_info(0, migor_i2c_devices, | 601 | i2c_register_board_info(0, migor_i2c_devices, |
651 | ARRAY_SIZE(migor_i2c_devices)); | 602 | ARRAY_SIZE(migor_i2c_devices)); |
652 | 603 | ||
604 | /* Initialize CEU platform device separately to map memory first */ | ||
605 | device_initialize(&migor_ceu_device.dev); | ||
606 | arch_setup_pdev_archdata(&migor_ceu_device); | ||
607 | dma_declare_coherent_memory(&migor_ceu_device.dev, | ||
608 | ceu_dma_membase, ceu_dma_membase, | ||
609 | ceu_dma_membase + CEU_BUFFER_MEMORY_SIZE - 1, | ||
610 | DMA_MEMORY_EXCLUSIVE); | ||
611 | |||
612 | platform_device_add(&migor_ceu_device); | ||
613 | |||
653 | return platform_add_devices(migor_devices, ARRAY_SIZE(migor_devices)); | 614 | return platform_add_devices(migor_devices, ARRAY_SIZE(migor_devices)); |
654 | } | 615 | } |
655 | arch_initcall(migor_devices_setup); | 616 | arch_initcall(migor_devices_setup); |
@@ -665,10 +626,24 @@ static int migor_mode_pins(void) | |||
665 | return MODE_PIN0 | MODE_PIN1 | MODE_PIN5; | 626 | return MODE_PIN0 | MODE_PIN1 | MODE_PIN5; |
666 | } | 627 | } |
667 | 628 | ||
629 | /* Reserve a portion of memory for CEU buffers */ | ||
630 | static void __init migor_mv_mem_reserve(void) | ||
631 | { | ||
632 | phys_addr_t phys; | ||
633 | phys_addr_t size = CEU_BUFFER_MEMORY_SIZE; | ||
634 | |||
635 | phys = memblock_alloc_base(size, PAGE_SIZE, MEMBLOCK_ALLOC_ANYWHERE); | ||
636 | memblock_free(phys, size); | ||
637 | memblock_remove(phys, size); | ||
638 | |||
639 | ceu_dma_membase = phys; | ||
640 | } | ||
641 | |||
668 | /* | 642 | /* |
669 | * The Machine Vector | 643 | * The Machine Vector |
670 | */ | 644 | */ |
671 | static struct sh_machine_vector mv_migor __initmv = { | 645 | static struct sh_machine_vector mv_migor __initmv = { |
672 | .mv_name = "Migo-R", | 646 | .mv_name = "Migo-R", |
673 | .mv_mode_pins = migor_mode_pins, | 647 | .mv_mode_pins = migor_mode_pins, |
648 | .mv_mem_reserve = migor_mv_mem_reserve, | ||
674 | }; | 649 | }; |