+// SPDX-License-Identifier: GPL-2.0
 /*
  * KFR2R09 board support code
  *
  * Copyright (C) 2009 Magnus Damm
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
  */
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/mmc/host.h>
-#include <linux/mfd/tmio.h>
-#include <linux/mtd/physmap.h>
-#include <linux/mtd/onenand.h>
+
+#include <asm/clock.h>
+#include <asm/io.h>
+#include <asm/machvec.h>
+#include <asm/suspend.h>
+
+#include <cpu/sh7724.h>
+
+#include <linux/clkdev.h>
 #include <linux/delay.h>
-#include <linux/clk.h>
+#include <linux/dma-mapping.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
 #include <linux/input.h>
 #include <linux/input/sh_keysc.h>
-#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/memblock.h>
+#include <linux/mfd/tmio.h>
+#include <linux/mmc/host.h>
+#include <linux/mtd/onenand.h>
+#include <linux/mtd/physmap.h>
 #include <linux/platform_data/lv5207lp.h>
+#include <linux/platform_device.h>
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
+#include <linux/sh_intc.h>
 #include <linux/usb/r8a66597.h>
 #include <linux/videodev2.h>
-#include <linux/sh_intc.h>
+
+#include <mach/kfr2r09.h>
+
+#include <media/drv-intf/renesas-ceu.h>
 #include <media/i2c/rj54n1cb0c.h>
-#include <media/soc_camera.h>
-#include <media/drv-intf/sh_mobile_ceu.h>
+
 #include <video/sh_mobile_lcdc.h>
-#include <asm/suspend.h>
-#include <asm/clock.h>
-#include <asm/machvec.h>
-#include <asm/io.h>
-#include <cpu/sh7724.h>
-#include <mach/kfr2r09.h>
+
+#define CEU_BUFFER_MEMORY_SIZE         (4 << 20)
+static phys_addr_t ceu_dma_membase;
+
+/* set VIO_CKO clock to 25MHz */
+#define CEU_MCLK_FREQ                  25000000
+#define DRVCRB                         0xA405018C
 
 static struct mtd_partition kfr2r09_nor_flash_partitions[] =
 {
        .resource       = kfr2r09_usb0_gadget_resources,
 };
 
-static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
-       .flags = SH_CEU_FLAG_USE_8BIT_BUS,
+static struct ceu_platform_data ceu_pdata = {
+       .num_subdevs                    = 1,
+       .subdevs = {
+               { /* [0] = rj54n1cb0c */
+                       .flags          = 0,
+                       .bus_width      = 8,
+                       .bus_shift      = 0,
+                       .i2c_adapter_id = 1,
+                       .i2c_address    = 0x50,
+               },
+       },
 };
 
 static struct resource kfr2r09_ceu_resources[] = {
                .end    = evt2irq(0x880),
                .flags  = IORESOURCE_IRQ,
        },
-       [2] = {
-               /* place holder for contiguous memory */
-       },
 };
 
 static struct platform_device kfr2r09_ceu_device = {
-       .name           = "sh_mobile_ceu",
+       .name           = "renesas-ceu",
        .id             = 0, /* "ceu0" clock */
        .num_resources  = ARRAY_SIZE(kfr2r09_ceu_resources),
        .resource       = kfr2r09_ceu_resources,
        .dev    = {
-               .platform_data  = &sh_mobile_ceu_info,
+               .platform_data  = &ceu_pdata,
        },
 };
 
-static struct i2c_board_info kfr2r09_i2c_camera = {
-       I2C_BOARD_INFO("rj54n1cb0c", 0x50),
-};
-
-static struct clk *camera_clk;
-
-/* set VIO_CKO clock to 25MHz */
-#define CEU_MCLK_FREQ 25000000
-
-#define DRVCRB 0xA405018C
-static int camera_power(struct device *dev, int mode)
-{
-       int ret;
-
-       if (mode) {
-               long rate;
-
-               camera_clk = clk_get(NULL, "video_clk");
-               if (IS_ERR(camera_clk))
-                       return PTR_ERR(camera_clk);
-
-               rate = clk_round_rate(camera_clk, CEU_MCLK_FREQ);
-               ret = clk_set_rate(camera_clk, rate);
-               if (ret < 0)
-                       goto eclkrate;
-
-               /* set DRVCRB
-                *
-                * use 1.8 V for VccQ_VIO
-                * use 2.85V for VccQ_SR
-                */
-               __raw_writew((__raw_readw(DRVCRB) & ~0x0003) | 0x0001, DRVCRB);
-
-               /* reset clear */
-               ret = gpio_request(GPIO_PTB4, NULL);
-               if (ret < 0)
-                       goto eptb4;
-               ret = gpio_request(GPIO_PTB7, NULL);
-               if (ret < 0)
-                       goto eptb7;
-
-               ret = gpio_direction_output(GPIO_PTB4, 1);
-               if (!ret)
-                       ret = gpio_direction_output(GPIO_PTB7, 1);
-               if (ret < 0)
-                       goto egpioout;
-               msleep(1);
-
-               ret = clk_enable(camera_clk);   /* start VIO_CKO */
-               if (ret < 0)
-                       goto eclkon;
-
-               return 0;
-       }
-
-       ret = 0;
-
-       clk_disable(camera_clk);
-eclkon:
-       gpio_set_value(GPIO_PTB7, 0);
-egpioout:
-       gpio_set_value(GPIO_PTB4, 0);
-       gpio_free(GPIO_PTB7);
-eptb7:
-       gpio_free(GPIO_PTB4);
-eptb4:
-eclkrate:
-       clk_put(camera_clk);
-       return ret;
-}
-
 static struct rj54n1_pdata rj54n1_priv = {
        .mclk_freq      = CEU_MCLK_FREQ,
        .ioctl_high     = false,
 };
 
-static struct soc_camera_link rj54n1_link = {
-       .power          = camera_power,
-       .board_info     = &kfr2r09_i2c_camera,
-       .i2c_adapter_id = 1,
-       .priv           = &rj54n1_priv,
+static struct i2c_board_info kfr2r09_i2c_camera = {
+       I2C_BOARD_INFO("rj54n1cb0c", 0x50),
+       .platform_data = &rj54n1_priv,
 };
 
-static struct platform_device kfr2r09_camera = {
-       .name   = "soc-camera-pdrv",
-       .id     = 0,
-       .dev    = {
-               .platform_data = &rj54n1_link,
+static struct gpiod_lookup_table rj54n1_gpios = {
+       .dev_id         = "1-0050",
+       .table          = {
+               GPIO_LOOKUP("sh7724_pfc", GPIO_PTB4, "poweron",
+                           GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("sh7724_pfc", GPIO_PTB7, "enable",
+                           GPIO_ACTIVE_HIGH),
        },
 };
 
        &kfr2r09_nand_flash_device,
        &kfr2r09_sh_keysc_device,
        &kfr2r09_sh_lcdc_device,
-       &kfr2r09_ceu_device,
-       &kfr2r09_camera,
        &kfr2r09_sh_sdhi0_device,
 };
 
 
 static int __init kfr2r09_devices_setup(void)
 {
+       static struct clk *camera_clk;
+
        /* register board specific self-refresh code */
        sh_mobile_register_self_refresh(SUSP_SH_STANDBY | SUSP_SH_SF |
                                        SUSP_SH_RSTANDBY,
        gpio_request(GPIO_FN_VIO0_D1, NULL);
        gpio_request(GPIO_FN_VIO0_D0, NULL);
 
-       platform_resource_setup_memory(&kfr2r09_ceu_device, "ceu", 4 << 20);
-
        /* SDHI0 connected to yc304 */
        gpio_request(GPIO_FN_SDHI0CD, NULL);
        gpio_request(GPIO_FN_SDHI0D3, NULL);
 
        i2c_register_board_info(0, &kfr2r09_backlight_board_info, 1);
 
+       /* Set camera clock frequency and register and alias for rj54n1. */
+       camera_clk = clk_get(NULL, "video_clk");
+       if (!IS_ERR(camera_clk)) {
+               clk_set_rate(camera_clk,
+                            clk_round_rate(camera_clk, CEU_MCLK_FREQ));
+               clk_put(camera_clk);
+       }
+       clk_add_alias(NULL, "1-0050", "video_clk", NULL);
+
+       /* set DRVCRB
+        *
+        * use 1.8 V for VccQ_VIO
+        * use 2.85V for VccQ_SR
+        */
+       __raw_writew((__raw_readw(DRVCRB) & ~0x0003) | 0x0001, DRVCRB);
+
+       gpiod_add_lookup_table(&rj54n1_gpios);
+
+       i2c_register_board_info(1, &kfr2r09_i2c_camera, 1);
+
+       /* Initialize CEU platform device separately to map memory first */
+       device_initialize(&kfr2r09_ceu_device.dev);
+       arch_setup_pdev_archdata(&kfr2r09_ceu_device);
+       dma_declare_coherent_memory(&kfr2r09_ceu_device.dev,
+                                   ceu_dma_membase, ceu_dma_membase,
+                                   ceu_dma_membase + CEU_BUFFER_MEMORY_SIZE - 1,
+                                   DMA_MEMORY_EXCLUSIVE);
+
+       platform_device_add(&kfr2r09_ceu_device);
+
        return platform_add_devices(kfr2r09_devices,
                                    ARRAY_SIZE(kfr2r09_devices));
 }
        return MODE_PIN0 | MODE_PIN1 | MODE_PIN5 | MODE_PIN8;
 }
 
+/* Reserve a portion of memory for CEU buffers */
+static void __init kfr2r09_mv_mem_reserve(void)
+{
+       phys_addr_t phys;
+       phys_addr_t size = CEU_BUFFER_MEMORY_SIZE;
+
+       phys = memblock_alloc_base(size, PAGE_SIZE, MEMBLOCK_ALLOC_ANYWHERE);
+       memblock_free(phys, size);
+       memblock_remove(phys, size);
+
+       ceu_dma_membase = phys;
+}
+
 /*
  * The Machine Vector
  */
 static struct sh_machine_vector mv_kfr2r09 __initmv = {
        .mv_name                = "kfr2r09",
        .mv_mode_pins           = kfr2r09_mode_pins,
+       .mv_mem_reserve         = kfr2r09_mv_mem_reserve,
 };