linux/drivers/clk/sunxi-ng/ccu-sun4i-a10.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2017 Priit Laes <[email protected]>.
 * Copyright (c) 2017 Maxime Ripard.
 * Copyright (c) 2017 Jonathan Liu.
 */

#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>

#include "ccu_common.h"
#include "ccu_reset.h"

#include "ccu_div.h"
#include "ccu_gate.h"
#include "ccu_mp.h"
#include "ccu_mult.h"
#include "ccu_nk.h"
#include "ccu_nkm.h"
#include "ccu_nkmp.h"
#include "ccu_nm.h"
#include "ccu_phase.h"
#include "ccu_sdm.h"

#include "ccu-sun4i-a10.h"

static struct ccu_nkmp pll_core_clk =;

/*
 * The Audio PLL is supposed to have 4 outputs: 3 fixed factors from
 * the base (2x, 4x and 8x), and one variable divider (the one true
 * pll audio).
 *
 * With sigma-delta modulation for fractional-N on the audio PLL,
 * we have to use specific dividers. This means the variable divider
 * can no longer be used, as the audio codec requests the exact clock
 * rates we support through this mechanism. So we now hard code the
 * variable divider to 1. This means the clock rates will no longer
 * match the clock names.
 */
#define SUN4I_PLL_AUDIO_REG

static struct ccu_sdm_setting pll_audio_sdm_table[] =;

static struct ccu_nm pll_audio_base_clk =;

static struct ccu_mult pll_video0_clk =;

static struct ccu_nkmp pll_ve_sun4i_clk =;

static struct ccu_nk pll_ve_sun7i_clk =;

static struct ccu_nk pll_ddr_base_clk =;

static SUNXI_CCU_M(pll_ddr_clk, "pll-ddr", "pll-ddr-base", 0x020, 0, 2,
		   CLK_IS_CRITICAL);

static struct ccu_div pll_ddr_other_clk =;

static struct ccu_nk pll_periph_base_clk =;

static CLK_FIXED_FACTOR_HW(pll_periph_clk, "pll-periph",
			   &pll_periph_base_clk.common.hw,
			   2, 1, CLK_SET_RATE_PARENT);

/* Not documented on A10 */
static struct ccu_div pll_periph_sata_clk =;

static struct ccu_mult pll_video1_clk =;

/* Not present on A10 */
static struct ccu_nk pll_gpu_clk =;

static SUNXI_CCU_GATE(hosc_clk,	"hosc",	"osc24M", 0x050, BIT(0), 0);

static const char *const cpu_parents[] =;
static const struct ccu_mux_fixed_prediv cpu_predivs[] =;

#define SUN4I_AHB_REG
static struct ccu_mux cpu_clk =;

static SUNXI_CCU_M(axi_clk, "axi", "cpu", 0x054, 0, 2, 0);

static struct ccu_div ahb_sun4i_clk =;

static const char *const ahb_sun7i_parents[] =;
static const struct ccu_mux_fixed_prediv ahb_sun7i_predivs[] =;
static struct ccu_div ahb_sun7i_clk =;

static struct clk_div_table apb0_div_table[] =;
static SUNXI_CCU_DIV_TABLE(apb0_clk, "apb0", "ahb",
			   0x054, 8, 2, apb0_div_table, 0);

static const char *const apb1_parents[] =;
static SUNXI_CCU_MP_WITH_MUX(apb1_clk, "apb1", apb1_parents, 0x058,
			     0, 5,	/* M */
			     16, 2,	/* P */
			     24, 2,	/* mux */
			     0);

/* Not present on A20 */
static SUNXI_CCU_GATE(axi_dram_clk,	"axi-dram",	"ahb",
		      0x05c, BIT(31), 0);

static SUNXI_CCU_GATE(ahb_otg_clk,	"ahb-otg",	"ahb",
		      0x060, BIT(0), 0);
static SUNXI_CCU_GATE(ahb_ehci0_clk,	"ahb-ehci0",	"ahb",
		      0x060, BIT(1), 0);
static SUNXI_CCU_GATE(ahb_ohci0_clk,	"ahb-ohci0",	"ahb",
		      0x060, BIT(2), 0);
static SUNXI_CCU_GATE(ahb_ehci1_clk,	"ahb-ehci1",	"ahb",
		      0x060, BIT(3), 0);
static SUNXI_CCU_GATE(ahb_ohci1_clk,	"ahb-ohci1",	"ahb",
		      0x060, BIT(4), 0);
static SUNXI_CCU_GATE(ahb_ss_clk,	"ahb-ss",	"ahb",
		      0x060, BIT(5), 0);
static SUNXI_CCU_GATE(ahb_dma_clk,	"ahb-dma",	"ahb",
		      0x060, BIT(6), 0);
static SUNXI_CCU_GATE(ahb_bist_clk,	"ahb-bist",	"ahb",
		      0x060, BIT(7), 0);
static SUNXI_CCU_GATE(ahb_mmc0_clk,	"ahb-mmc0",	"ahb",
		      0x060, BIT(8), 0);
static SUNXI_CCU_GATE(ahb_mmc1_clk,	"ahb-mmc1",	"ahb",
		      0x060, BIT(9), 0);
static SUNXI_CCU_GATE(ahb_mmc2_clk,	"ahb-mmc2",	"ahb",
		      0x060, BIT(10), 0);
static SUNXI_CCU_GATE(ahb_mmc3_clk,	"ahb-mmc3",	"ahb",
		      0x060, BIT(11), 0);
static SUNXI_CCU_GATE(ahb_ms_clk,	"ahb-ms",	"ahb",
		      0x060, BIT(12), 0);
static SUNXI_CCU_GATE(ahb_nand_clk,	"ahb-nand",	"ahb",
		      0x060, BIT(13), 0);
static SUNXI_CCU_GATE(ahb_sdram_clk,	"ahb-sdram",	"ahb",
		      0x060, BIT(14), CLK_IS_CRITICAL);

static SUNXI_CCU_GATE(ahb_ace_clk,	"ahb-ace",	"ahb",
		      0x060, BIT(16), 0);
static SUNXI_CCU_GATE(ahb_emac_clk,	"ahb-emac",	"ahb",
		      0x060, BIT(17), 0);
static SUNXI_CCU_GATE(ahb_ts_clk,	"ahb-ts",	"ahb",
		      0x060, BIT(18), 0);
static SUNXI_CCU_GATE(ahb_spi0_clk,	"ahb-spi0",	"ahb",
		      0x060, BIT(20), 0);
static SUNXI_CCU_GATE(ahb_spi1_clk,	"ahb-spi1",	"ahb",
		      0x060, BIT(21), 0);
static SUNXI_CCU_GATE(ahb_spi2_clk,	"ahb-spi2",	"ahb",
		      0x060, BIT(22), 0);
static SUNXI_CCU_GATE(ahb_spi3_clk,	"ahb-spi3",	"ahb",
		      0x060, BIT(23), 0);
static SUNXI_CCU_GATE(ahb_pata_clk,	"ahb-pata",	"ahb",
		      0x060, BIT(24), 0);
/* Not documented on A20 */
static SUNXI_CCU_GATE(ahb_sata_clk,	"ahb-sata",	"ahb",
		      0x060, BIT(25), 0);
/* Not present on A20 */
static SUNXI_CCU_GATE(ahb_gps_clk,	"ahb-gps",	"ahb",
		      0x060, BIT(26), 0);
/* Not present on A10 */
static SUNXI_CCU_GATE(ahb_hstimer_clk,	"ahb-hstimer",	"ahb",
		      0x060, BIT(28), 0);

static SUNXI_CCU_GATE(ahb_ve_clk,	"ahb-ve",	"ahb",
		      0x064, BIT(0), 0);
static SUNXI_CCU_GATE(ahb_tvd_clk,	"ahb-tvd",	"ahb",
		      0x064, BIT(1), 0);
static SUNXI_CCU_GATE(ahb_tve0_clk,	"ahb-tve0",	"ahb",
		      0x064, BIT(2), 0);
static SUNXI_CCU_GATE(ahb_tve1_clk,	"ahb-tve1",	"ahb",
		      0x064, BIT(3), 0);
static SUNXI_CCU_GATE(ahb_lcd0_clk,	"ahb-lcd0",	"ahb",
		      0x064, BIT(4), 0);
static SUNXI_CCU_GATE(ahb_lcd1_clk,	"ahb-lcd1",	"ahb",
		      0x064, BIT(5), 0);
static SUNXI_CCU_GATE(ahb_csi0_clk,	"ahb-csi0",	"ahb",
		      0x064, BIT(8), 0);
static SUNXI_CCU_GATE(ahb_csi1_clk,	"ahb-csi1",	"ahb",
		      0x064, BIT(9), 0);
/* Not present on A10 */
static SUNXI_CCU_GATE(ahb_hdmi1_clk,	"ahb-hdmi1",	"ahb",
		      0x064, BIT(10), 0);
static SUNXI_CCU_GATE(ahb_hdmi0_clk,	"ahb-hdmi0",	"ahb",
		      0x064, BIT(11), 0);
static SUNXI_CCU_GATE(ahb_de_be0_clk,	"ahb-de-be0",	"ahb",
		      0x064, BIT(12), 0);
static SUNXI_CCU_GATE(ahb_de_be1_clk,	"ahb-de-be1",	"ahb",
		      0x064, BIT(13), 0);
static SUNXI_CCU_GATE(ahb_de_fe0_clk,	"ahb-de-fe0",	"ahb",
		      0x064, BIT(14), 0);
static SUNXI_CCU_GATE(ahb_de_fe1_clk,	"ahb-de-fe1",	"ahb",
		      0x064, BIT(15), 0);
/* Not present on A10 */
static SUNXI_CCU_GATE(ahb_gmac_clk,	"ahb-gmac",	"ahb",
		      0x064, BIT(17), 0);
static SUNXI_CCU_GATE(ahb_mp_clk,	"ahb-mp",	"ahb",
		      0x064, BIT(18), 0);
static SUNXI_CCU_GATE(ahb_gpu_clk,	"ahb-gpu",	"ahb",
		      0x064, BIT(20), 0);

static SUNXI_CCU_GATE(apb0_codec_clk,	"apb0-codec",	"apb0",
		      0x068, BIT(0), 0);
static SUNXI_CCU_GATE(apb0_spdif_clk,	"apb0-spdif",	"apb0",
		      0x068, BIT(1), 0);
static SUNXI_CCU_GATE(apb0_ac97_clk,	"apb0-ac97",	"apb0",
		      0x068, BIT(2), 0);
static SUNXI_CCU_GATE(apb0_i2s0_clk,	"apb0-i2s0",	"apb0",
		      0x068, BIT(3), 0);
/* Not present on A10 */
static SUNXI_CCU_GATE(apb0_i2s1_clk,	"apb0-i2s1",	"apb0",
		      0x068, BIT(4), 0);
static SUNXI_CCU_GATE(apb0_pio_clk,	"apb0-pio",	"apb0",
		      0x068, BIT(5), 0);
static SUNXI_CCU_GATE(apb0_ir0_clk,	"apb0-ir0",	"apb0",
		      0x068, BIT(6), 0);
static SUNXI_CCU_GATE(apb0_ir1_clk,	"apb0-ir1",	"apb0",
		      0x068, BIT(7), 0);
/* Not present on A10 */
static SUNXI_CCU_GATE(apb0_i2s2_clk,	"apb0-i2s2",	"apb0",
		      0x068, BIT(8), 0);
static SUNXI_CCU_GATE(apb0_keypad_clk,	"apb0-keypad",	"apb0",
		      0x068, BIT(10), 0);

static SUNXI_CCU_GATE(apb1_i2c0_clk,	"apb1-i2c0",	"apb1",
		      0x06c, BIT(0), 0);
static SUNXI_CCU_GATE(apb1_i2c1_clk,	"apb1-i2c1",	"apb1",
		      0x06c, BIT(1), 0);
static SUNXI_CCU_GATE(apb1_i2c2_clk,	"apb1-i2c2",	"apb1",
		      0x06c, BIT(2), 0);
/* Not present on A10 */
static SUNXI_CCU_GATE(apb1_i2c3_clk,	"apb1-i2c3",	"apb1",
		      0x06c, BIT(3), 0);
static SUNXI_CCU_GATE(apb1_can_clk,	"apb1-can",	"apb1",
		      0x06c, BIT(4), 0);
static SUNXI_CCU_GATE(apb1_scr_clk,	"apb1-scr",	"apb1",
		      0x06c, BIT(5), 0);
static SUNXI_CCU_GATE(apb1_ps20_clk,	"apb1-ps20",	"apb1",
		      0x06c, BIT(6), 0);
static SUNXI_CCU_GATE(apb1_ps21_clk,	"apb1-ps21",	"apb1",
		      0x06c, BIT(7), 0);
/* Not present on A10 */
static SUNXI_CCU_GATE(apb1_i2c4_clk,	"apb1-i2c4",	"apb1",
		      0x06c, BIT(15), 0);
static SUNXI_CCU_GATE(apb1_uart0_clk,	"apb1-uart0",	"apb1",
		      0x06c, BIT(16), 0);
static SUNXI_CCU_GATE(apb1_uart1_clk,	"apb1-uart1",	"apb1",
		      0x06c, BIT(17), 0);
static SUNXI_CCU_GATE(apb1_uart2_clk,	"apb1-uart2",	"apb1",
		      0x06c, BIT(18), 0);
static SUNXI_CCU_GATE(apb1_uart3_clk,	"apb1-uart3",	"apb1",
		      0x06c, BIT(19), 0);
static SUNXI_CCU_GATE(apb1_uart4_clk,	"apb1-uart4",	"apb1",
		      0x06c, BIT(20), 0);
static SUNXI_CCU_GATE(apb1_uart5_clk,	"apb1-uart5",	"apb1",
		      0x06c, BIT(21), 0);
static SUNXI_CCU_GATE(apb1_uart6_clk,	"apb1-uart6",	"apb1",
		      0x06c, BIT(22), 0);
static SUNXI_CCU_GATE(apb1_uart7_clk,	"apb1-uart7",	"apb1",
		      0x06c, BIT(23), 0);

static const char *const mod0_default_parents[] =;
static SUNXI_CCU_MP_WITH_MUX_GATE(nand_clk, "nand", mod0_default_parents, 0x080,
				  0, 4,		/* M */
				  16, 2,	/* P */
				  24, 2,	/* mux */
				  BIT(31),	/* gate */
				  0);

/* Undocumented on A10 */
static SUNXI_CCU_MP_WITH_MUX_GATE(ms_clk, "ms", mod0_default_parents, 0x084,
				  0, 4,		/* M */
				  16, 2,	/* P */
				  24, 2,	/* mux */
				  BIT(31),	/* gate */
				  0);

static SUNXI_CCU_MP_WITH_MUX_GATE(mmc0_clk, "mmc0", mod0_default_parents, 0x088,
				  0, 4,		/* M */
				  16, 2,	/* P */
				  24, 2,	/* mux */
				  BIT(31),	/* gate */
				  0);

/* MMC output and sample clocks are not present on A10 */
static SUNXI_CCU_PHASE(mmc0_output_clk, "mmc0_output", "mmc0",
		       0x088, 8, 3, 0);
static SUNXI_CCU_PHASE(mmc0_sample_clk, "mmc0_sample", "mmc0",
		       0x088, 20, 3, 0);

static SUNXI_CCU_MP_WITH_MUX_GATE(mmc1_clk, "mmc1", mod0_default_parents, 0x08c,
				  0, 4,		/* M */
				  16, 2,	/* P */
				  24, 2,	/* mux */
				  BIT(31),	/* gate */
				  0);

/* MMC output and sample clocks are not present on A10 */
static SUNXI_CCU_PHASE(mmc1_output_clk, "mmc1_output", "mmc1",
		       0x08c, 8, 3, 0);
static SUNXI_CCU_PHASE(mmc1_sample_clk, "mmc1_sample", "mmc1",
		       0x08c, 20, 3, 0);

static SUNXI_CCU_MP_WITH_MUX_GATE(mmc2_clk, "mmc2", mod0_default_parents, 0x090,
				  0, 4,		/* M */
				  16, 2,	/* P */
				  24, 2,	/* mux */
				  BIT(31),	/* gate */
				  0);

/* MMC output and sample clocks are not present on A10 */
static SUNXI_CCU_PHASE(mmc2_output_clk, "mmc2_output", "mmc2",
		       0x090, 8, 3, 0);
static SUNXI_CCU_PHASE(mmc2_sample_clk, "mmc2_sample", "mmc2",
		       0x090, 20, 3, 0);

static SUNXI_CCU_MP_WITH_MUX_GATE(mmc3_clk, "mmc3", mod0_default_parents, 0x094,
				  0, 4,		/* M */
				  16, 2,	/* P */
				  24, 2,	/* mux */
				  BIT(31),	/* gate */
				  0);

/* MMC output and sample clocks are not present on A10 */
static SUNXI_CCU_PHASE(mmc3_output_clk, "mmc3_output", "mmc3",
		       0x094, 8, 3, 0);
static SUNXI_CCU_PHASE(mmc3_sample_clk, "mmc3_sample", "mmc3",
		       0x094, 20, 3, 0);

static SUNXI_CCU_MP_WITH_MUX_GATE(ts_clk, "ts", mod0_default_parents, 0x098,
				  0, 4,		/* M */
				  16, 2,	/* P */
				  24, 2,	/* mux */
				  BIT(31),	/* gate */
				  0);

static SUNXI_CCU_MP_WITH_MUX_GATE(ss_clk, "ss", mod0_default_parents, 0x09c,
				  0, 4,		/* M */
				  16, 2,	/* P */
				  24, 2,	/* mux */
				  BIT(31),	/* gate */
				  0);

static SUNXI_CCU_MP_WITH_MUX_GATE(spi0_clk, "spi0", mod0_default_parents, 0x0a0,
				  0, 4,		/* M */
				  16, 2,	/* P */
				  24, 2,	/* mux */
				  BIT(31),	/* gate */
				  0);

static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", mod0_default_parents, 0x0a4,
				  0, 4,		/* M */
				  16, 2,	/* P */
				  24, 2,	/* mux */
				  BIT(31),	/* gate */
				  0);

static SUNXI_CCU_MP_WITH_MUX_GATE(spi2_clk, "spi2", mod0_default_parents, 0x0a8,
				  0, 4,		/* M */
				  16, 2,	/* P */
				  24, 2,	/* mux */
				  BIT(31),	/* gate */
				  0);

/* Undocumented on A10 */
static SUNXI_CCU_MP_WITH_MUX_GATE(pata_clk, "pata", mod0_default_parents, 0x0ac,
				  0, 4,		/* M */
				  16, 2,	/* P */
				  24, 2,	/* mux */
				  BIT(31),	/* gate */
				  0);

/* TODO: Check whether A10 actually supports osc32k as 4th parent? */
static const char *const ir_parents_sun4i[] =;
static SUNXI_CCU_MP_WITH_MUX_GATE(ir0_sun4i_clk, "ir0", ir_parents_sun4i, 0x0b0,
				  0, 4,		/* M */
				  16, 2,	/* P */
				  24, 2,	/* mux */
				  BIT(31),	/* gate */
				  0);

static SUNXI_CCU_MP_WITH_MUX_GATE(ir1_sun4i_clk, "ir1", ir_parents_sun4i, 0x0b4,
				  0, 4,		/* M */
				  16, 2,	/* P */
				  24, 2,	/* mux */
				  BIT(31),	/* gate */
				  0);
static const char *const ir_parents_sun7i[] =;
static SUNXI_CCU_MP_WITH_MUX_GATE(ir0_sun7i_clk, "ir0", ir_parents_sun7i, 0x0b0,
				  0, 4,		/* M */
				  16, 2,	/* P */
				  24, 2,	/* mux */
				  BIT(31),	/* gate */
				  0);

static SUNXI_CCU_MP_WITH_MUX_GATE(ir1_sun7i_clk, "ir1", ir_parents_sun7i, 0x0b4,
				  0, 4,		/* M */
				  16, 2,	/* P */
				  24, 2,	/* mux */
				  BIT(31),	/* gate */
				  0);

static const char *const audio_parents[] =;
static SUNXI_CCU_MUX_WITH_GATE(i2s0_clk, "i2s0", audio_parents,
			       0x0b8, 16, 2, BIT(31), CLK_SET_RATE_PARENT);

static SUNXI_CCU_MUX_WITH_GATE(ac97_clk, "ac97", audio_parents,
			       0x0bc, 16, 2, BIT(31), CLK_SET_RATE_PARENT);

/* Undocumented on A10 */
static SUNXI_CCU_MUX_WITH_GATE(spdif_clk, "spdif", audio_parents,
			       0x0c0, 16, 2, BIT(31), CLK_SET_RATE_PARENT);

static const char *const keypad_parents[] =;
static const u8 keypad_table[] =;
static struct ccu_mp keypad_clk =;

/*
 * SATA supports external clock as parent via BIT(24) and is probably an
 * optional crystal or oscillator that can be connected to the
 * SATA-CLKM / SATA-CLKP pins.
 */
static const char *const sata_parents[] =;
static SUNXI_CCU_MUX_WITH_GATE(sata_clk, "sata", sata_parents,
			       0x0c8, 24, 1, BIT(31), CLK_SET_RATE_PARENT);


static SUNXI_CCU_GATE(usb_ohci0_clk,	"usb-ohci0",	"pll-periph",
		      0x0cc, BIT(6), 0);
static SUNXI_CCU_GATE(usb_ohci1_clk,	"usb-ohci1",	"pll-periph",
		      0x0cc, BIT(7), 0);
static SUNXI_CCU_GATE(usb_phy_clk,	"usb-phy",	"pll-periph",
		      0x0cc, BIT(8), 0);

/* TODO: GPS CLK 0x0d0 */

static SUNXI_CCU_MP_WITH_MUX_GATE(spi3_clk, "spi3", mod0_default_parents, 0x0d4,
				  0, 4,		/* M */
				  16, 2,	/* P */
				  24, 2,	/* mux */
				  BIT(31),	/* gate */
				  0);

/* Not present on A10 */
static SUNXI_CCU_MUX_WITH_GATE(i2s1_clk, "i2s1", audio_parents,
			       0x0d8, 16, 2, BIT(31), CLK_SET_RATE_PARENT);

/* Not present on A10 */
static SUNXI_CCU_MUX_WITH_GATE(i2s2_clk, "i2s2", audio_parents,
			       0x0dc, 16, 2, BIT(31), CLK_SET_RATE_PARENT);

static SUNXI_CCU_GATE(dram_ve_clk,	"dram-ve",	"pll-ddr",
		      0x100, BIT(0), 0);
static SUNXI_CCU_GATE(dram_csi0_clk,	"dram-csi0",	"pll-ddr",
		      0x100, BIT(1), 0);
static SUNXI_CCU_GATE(dram_csi1_clk,	"dram-csi1",	"pll-ddr",
		      0x100, BIT(2), 0);
static SUNXI_CCU_GATE(dram_ts_clk,	"dram-ts",	"pll-ddr",
		      0x100, BIT(3), 0);
static SUNXI_CCU_GATE(dram_tvd_clk,	"dram-tvd",	"pll-ddr",
		      0x100, BIT(4), 0);
static SUNXI_CCU_GATE(dram_tve0_clk,	"dram-tve0",	"pll-ddr",
		      0x100, BIT(5), 0);
static SUNXI_CCU_GATE(dram_tve1_clk,	"dram-tve1",	"pll-ddr",
		      0x100, BIT(6), 0);

/* Clock seems to be critical only on sun4i */
static SUNXI_CCU_GATE(dram_out_clk,	"dram-out",	"pll-ddr",
		      0x100, BIT(15), CLK_IS_CRITICAL);
static SUNXI_CCU_GATE(dram_de_fe1_clk,	"dram-de-fe1",	"pll-ddr",
		      0x100, BIT(24), 0);
static SUNXI_CCU_GATE(dram_de_fe0_clk,	"dram-de-fe0",	"pll-ddr",
		      0x100, BIT(25), 0);
static SUNXI_CCU_GATE(dram_de_be0_clk,	"dram-de-be0",	"pll-ddr",
		      0x100, BIT(26), 0);
static SUNXI_CCU_GATE(dram_de_be1_clk,	"dram-de-be1",	"pll-ddr",
		      0x100, BIT(27), 0);
static SUNXI_CCU_GATE(dram_mp_clk,	"dram-mp",	"pll-ddr",
		      0x100, BIT(28), 0);
static SUNXI_CCU_GATE(dram_ace_clk,	"dram-ace",	"pll-ddr",
		      0x100, BIT(29), 0);

static const char *const de_parents[] =;
static SUNXI_CCU_M_WITH_MUX_GATE(de_be0_clk, "de-be0", de_parents,
				 0x104, 0, 4, 24, 2, BIT(31), 0);

static SUNXI_CCU_M_WITH_MUX_GATE(de_be1_clk, "de-be1", de_parents,
				 0x108, 0, 4, 24, 2, BIT(31), 0);

static SUNXI_CCU_M_WITH_MUX_GATE(de_fe0_clk, "de-fe0", de_parents,
				 0x10c, 0, 4, 24, 2, BIT(31), 0);

static SUNXI_CCU_M_WITH_MUX_GATE(de_fe1_clk, "de-fe1", de_parents,
				 0x110, 0, 4, 24, 2, BIT(31), 0);

/* Undocumented on A10 */
static SUNXI_CCU_M_WITH_MUX_GATE(de_mp_clk, "de-mp", de_parents,
				 0x114, 0, 4, 24, 2, BIT(31), 0);

static const char *const disp_parents[] =;
static SUNXI_CCU_MUX_WITH_GATE(tcon0_ch0_clk, "tcon0-ch0-sclk", disp_parents,
			       0x118, 24, 2, BIT(31), CLK_SET_RATE_PARENT);
static SUNXI_CCU_MUX_WITH_GATE(tcon1_ch0_clk, "tcon1-ch0-sclk", disp_parents,
			       0x11c, 24, 2, BIT(31), CLK_SET_RATE_PARENT);

static const char *const csi_sclk_parents[] =;

static SUNXI_CCU_M_WITH_MUX_GATE(csi_sclk_clk, "csi-sclk",
				 csi_sclk_parents,
				 0x120, 0, 4, 24, 2, BIT(31), 0);

/* TVD clock setup for A10 */
static const char *const tvd_parents[] =;
static SUNXI_CCU_MUX_WITH_GATE(tvd_sun4i_clk, "tvd", tvd_parents,
			       0x128, 24, 1, BIT(31), 0);

/* TVD clock setup for A20 */
static SUNXI_CCU_MP_WITH_MUX_GATE(tvd_sclk2_sun7i_clk,
				  "tvd-sclk2", tvd_parents,
				  0x128,
				  0, 4,		/* M */
				  16, 4,	/* P */
				  8, 1,		/* mux */
				  BIT(15),	/* gate */
				  0);

static SUNXI_CCU_M_WITH_GATE(tvd_sclk1_sun7i_clk, "tvd-sclk1", "tvd-sclk2",
			     0x128, 0, 4, BIT(31), 0);

static SUNXI_CCU_M_WITH_MUX_GATE(tcon0_ch1_sclk2_clk, "tcon0-ch1-sclk2",
				 disp_parents,
				 0x12c, 0, 4, 24, 2, BIT(31),
				 CLK_SET_RATE_PARENT);

static SUNXI_CCU_M_WITH_GATE(tcon0_ch1_clk,
			     "tcon0-ch1-sclk1", "tcon0-ch1-sclk2",
			     0x12c, 11, 1, BIT(15),
			     CLK_SET_RATE_PARENT);

static SUNXI_CCU_M_WITH_MUX_GATE(tcon1_ch1_sclk2_clk, "tcon1-ch1-sclk2",
				 disp_parents,
				 0x130, 0, 4, 24, 2, BIT(31),
				 CLK_SET_RATE_PARENT);

static SUNXI_CCU_M_WITH_GATE(tcon1_ch1_clk,
			     "tcon1-ch1-sclk1", "tcon1-ch1-sclk2",
			     0x130, 11, 1, BIT(15),
			     CLK_SET_RATE_PARENT);

static const char *const csi_parents[] =;
static const u8 csi_table[] =;
static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(csi0_clk, "csi0",
				       csi_parents, csi_table,
				       0x134, 0, 5, 24, 3, BIT(31), 0);

static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(csi1_clk, "csi1",
				       csi_parents, csi_table,
				       0x138, 0, 5, 24, 3, BIT(31), 0);

static SUNXI_CCU_M_WITH_GATE(ve_clk, "ve", "pll-ve", 0x13c, 16, 8, BIT(31), 0);

static SUNXI_CCU_GATE(codec_clk, "codec", "pll-audio",
		      0x140, BIT(31), CLK_SET_RATE_PARENT);

static SUNXI_CCU_GATE(avs_clk, "avs", "hosc", 0x144, BIT(31), 0);

static const char *const ace_parents[] =;
static SUNXI_CCU_M_WITH_MUX_GATE(ace_clk, "ace", ace_parents,
				 0x148, 0, 4, 24, 1, BIT(31), 0);

static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", disp_parents,
				 0x150, 0, 4, 24, 2, BIT(31),
				 CLK_SET_RATE_PARENT);

static const char *const gpu_parents_sun4i[] =;
static SUNXI_CCU_M_WITH_MUX_GATE(gpu_sun4i_clk, "gpu", gpu_parents_sun4i,
				 0x154, 0, 4, 24, 2, BIT(31),
				 CLK_SET_RATE_PARENT);

static const char *const gpu_parents_sun7i[] =;
static const u8 gpu_table_sun7i[] =;
static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(gpu_sun7i_clk, "gpu",
				       gpu_parents_sun7i, gpu_table_sun7i,
				       0x154, 0, 4, 24, 3, BIT(31),
				       CLK_SET_RATE_PARENT);

static const char *const mbus_sun4i_parents[] =;
static SUNXI_CCU_MP_WITH_MUX_GATE(mbus_sun4i_clk, "mbus", mbus_sun4i_parents,
				  0x15c, 0, 4, 16, 2, 24, 2, BIT(31),
				  0);
static const char *const mbus_sun7i_parents[] =;
static SUNXI_CCU_MP_WITH_MUX_GATE(mbus_sun7i_clk, "mbus", mbus_sun7i_parents,
				  0x15c, 0, 4, 16, 2, 24, 2, BIT(31),
				  CLK_IS_CRITICAL);

static SUNXI_CCU_GATE(hdmi1_slow_clk, "hdmi1-slow", "hosc", 0x178, BIT(31), 0);

static const char *const hdmi1_parents[] =;
static const u8 hdmi1_table[] =;
static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(hdmi1_clk, "hdmi1",
				       hdmi1_parents, hdmi1_table,
				       0x17c, 0, 4, 24, 2, BIT(31),
				       CLK_SET_RATE_PARENT);

static const char *const out_parents[] =;
static const struct ccu_mux_fixed_prediv clk_out_predivs[] =;

static struct ccu_mp out_a_clk =;
static struct ccu_mp out_b_clk =;

static struct ccu_common *sun4i_sun7i_ccu_clks[] =;

static const struct clk_hw *clk_parent_pll_audio[] =;

/* Post-divider for pll-audio is hardcoded to 1 */
static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio",
			    clk_parent_pll_audio,
			    1, 1, CLK_SET_RATE_PARENT);
static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x",
			    clk_parent_pll_audio,
			    2, 1, CLK_SET_RATE_PARENT);
static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x",
			    clk_parent_pll_audio,
			    1, 1, CLK_SET_RATE_PARENT);
static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x",
			    clk_parent_pll_audio,
			    1, 2, CLK_SET_RATE_PARENT);
static CLK_FIXED_FACTOR_HW(pll_video0_2x_clk, "pll-video0-2x",
			   &pll_video0_clk.common.hw,
			   1, 2, CLK_SET_RATE_PARENT);
static CLK_FIXED_FACTOR_HW(pll_video1_2x_clk, "pll-video1-2x",
			   &pll_video1_clk.common.hw,
			   1, 2, CLK_SET_RATE_PARENT);


static struct clk_hw_onecell_data sun4i_a10_hw_clks =;
static struct clk_hw_onecell_data sun7i_a20_hw_clks =;

static struct ccu_reset_map sunxi_a10_a20_ccu_resets[] =;

static const struct sunxi_ccu_desc sun4i_a10_ccu_desc =;

static const struct sunxi_ccu_desc sun7i_a20_ccu_desc =;

static int sun4i_a10_ccu_probe(struct platform_device *pdev)
{}

static const struct of_device_id sun4i_a10_ccu_ids[] =;
MODULE_DEVICE_TABLE(of, sun4i_a10_ccu_ids);

static struct platform_driver sun4i_a10_ccu_driver =;
module_platform_driver();

MODULE_IMPORT_NS();
MODULE_DESCRIPTION();
MODULE_LICENSE();