summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile3
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/samsung/Makefile8
-rw-r--r--drivers/clk/samsung/clk-exynos4.c1091
-rw-r--r--drivers/clk/samsung/clk-exynos5250.c523
-rw-r--r--drivers/clk/samsung/clk-exynos5440.c139
-rw-r--r--drivers/clk/samsung/clk-pll.c419
-rw-r--r--drivers/clk/samsung/clk-pll.h41
-rw-r--r--drivers/clk/samsung/clk.c320
-rw-r--r--drivers/clk/samsung/clk.h289
-rw-r--r--drivers/clk/tegra/Makefile1
-rw-r--r--drivers/clk/tegra/clk-periph-gate.c11
-rw-r--r--drivers/clk/tegra/clk-periph.c14
-rw-r--r--drivers/clk/tegra/clk-pll.c1144
-rw-r--r--drivers/clk/tegra/clk-tegra114.c2085
-rw-r--r--drivers/clk/tegra/clk-tegra20.c184
-rw-r--r--drivers/clk/tegra/clk-tegra30.c276
-rw-r--r--drivers/clk/tegra/clk.c14
-rw-r--r--drivers/clk/tegra/clk.h98
-rw-r--r--drivers/clocksource/Kconfig8
-rw-r--r--drivers/clocksource/Makefile2
-rw-r--r--drivers/clocksource/cadence_ttc_timer.c436
-rw-r--r--drivers/clocksource/em_sti.c13
-rw-r--r--drivers/clocksource/exynos_mct.c568
-rw-r--r--drivers/clocksource/sh_cmt.c189
-rw-r--r--drivers/clocksource/sh_mtu2.c2
-rw-r--r--drivers/clocksource/sh_tmu.c2
-rw-r--r--drivers/gpio/Kconfig6
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-samsung.c9
-rw-r--r--drivers/gpio/gpio-vt8500.c355
-rw-r--r--drivers/irqchip/Kconfig8
-rw-r--r--drivers/irqchip/Makefile4
-rw-r--r--drivers/irqchip/exynos-combiner.c80
-rw-r--r--drivers/irqchip/irq-renesas-intc-irqpin.c547
-rw-r--r--drivers/irqchip/irq-renesas-irqc.c307
-rw-r--r--drivers/irqchip/irq-s3c24xx.c1356
-rw-r--r--drivers/irqchip/irq-vt8500.c259
-rw-r--r--drivers/of/base.c111
-rw-r--r--drivers/pinctrl/Kconfig1
-rw-r--r--drivers/pinctrl/Makefile1
-rw-r--r--drivers/pinctrl/pinctrl-bcm2835.c19
-rw-r--r--drivers/pinctrl/pinctrl-exynos.c108
-rw-r--r--drivers/pinctrl/pinctrl-samsung.c2
-rw-r--r--drivers/pinctrl/pinctrl-samsung.h1
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh73a0.c6
-rw-r--r--drivers/pinctrl/vt8500/Kconfig52
-rw-r--r--drivers/pinctrl/vt8500/Makefile8
-rw-r--r--drivers/pinctrl/vt8500/pinctrl-vt8500.c501
-rw-r--r--drivers/pinctrl/vt8500/pinctrl-wm8505.c532
-rw-r--r--drivers/pinctrl/vt8500/pinctrl-wm8650.c370
-rw-r--r--drivers/pinctrl/vt8500/pinctrl-wm8750.c409
-rw-r--r--drivers/pinctrl/vt8500/pinctrl-wm8850.c388
-rw-r--r--drivers/pinctrl/vt8500/pinctrl-wmt.c632
-rw-r--r--drivers/pinctrl/vt8500/pinctrl-wmt.h79
-rw-r--r--drivers/reset/Kconfig13
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/reset/core.c297
-rw-r--r--drivers/video/atmel_lcdfb.c120
60 files changed, 13600 insertions, 866 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 8d96238549fa..9953a42809ec 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -164,4 +164,6 @@ source "drivers/irqchip/Kconfig"
source "drivers/ipack/Kconfig"
+source "drivers/reset/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 8e57688ebd95..130abc1dfd65 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -37,6 +37,9 @@ obj-$(CONFIG_XEN) += xen/
# regulators early, since some subsystems rely on them to initialize
obj-$(CONFIG_REGULATOR) += regulator/
+# reset controllers early, since gpu drivers might rely on them to initialize
+obj-$(CONFIG_RESET_CONTROLLER) += reset/
+
# tty/ comes before char/ so that the VT console is the boot-time
# default.
obj-y += tty/
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index e7f7fe9b2f09..137d3e730f86 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_ARCH_U8500) += ux500/
obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
obj-$(CONFIG_ARCH_ZYNQ) += clk-zynq.o
obj-$(CONFIG_ARCH_TEGRA) += tegra/
+obj-$(CONFIG_PLAT_SAMSUNG) += samsung/
obj-$(CONFIG_X86) += x86/
diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile
new file mode 100644
index 000000000000..b7c232e67425
--- /dev/null
+++ b/drivers/clk/samsung/Makefile
@@ -0,0 +1,8 @@
+#
+# Samsung Clock specific Makefile
+#
+
+obj-$(CONFIG_COMMON_CLK) += clk.o clk-pll.o
+obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4.o
+obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o
+obj-$(CONFIG_SOC_EXYNOS5440) += clk-exynos5440.o
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c
new file mode 100644
index 000000000000..71046694d9dd
--- /dev/null
+++ b/drivers/clk/samsung/clk-exynos4.c
@@ -0,0 +1,1091 @@
+/*
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2013 Linaro Ltd.
+ * Author: Thomas Abraham <thomas.ab@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Common Clock Framework support for all Exynos4 SoCs.
+*/
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <plat/cpu.h>
+#include "clk.h"
+#include "clk-pll.h"
+
+/* Exynos4 clock controller register offsets */
+#define SRC_LEFTBUS 0x4200
+#define DIV_LEFTBUS 0x4500
+#define GATE_IP_LEFTBUS 0x4800
+#define E4X12_GATE_IP_IMAGE 0x4930
+#define SRC_RIGHTBUS 0x8200
+#define DIV_RIGHTBUS 0x8500
+#define GATE_IP_RIGHTBUS 0x8800
+#define E4X12_GATE_IP_PERIR 0x8960
+#define EPLL_LOCK 0xc010
+#define VPLL_LOCK 0xc020
+#define EPLL_CON0 0xc110
+#define EPLL_CON1 0xc114
+#define EPLL_CON2 0xc118
+#define VPLL_CON0 0xc120
+#define VPLL_CON1 0xc124
+#define VPLL_CON2 0xc128
+#define SRC_TOP0 0xc210
+#define SRC_TOP1 0xc214
+#define SRC_CAM 0xc220
+#define SRC_TV 0xc224
+#define SRC_MFC 0xcc28
+#define SRC_G3D 0xc22c
+#define E4210_SRC_IMAGE 0xc230
+#define SRC_LCD0 0xc234
+#define E4210_SRC_LCD1 0xc238
+#define E4X12_SRC_ISP 0xc238
+#define SRC_MAUDIO 0xc23c
+#define SRC_FSYS 0xc240
+#define SRC_PERIL0 0xc250
+#define SRC_PERIL1 0xc254
+#define E4X12_SRC_CAM1 0xc258
+#define SRC_MASK_TOP 0xc310
+#define SRC_MASK_CAM 0xc320
+#define SRC_MASK_TV 0xc324
+#define SRC_MASK_LCD0 0xc334
+#define E4210_SRC_MASK_LCD1 0xc338
+#define E4X12_SRC_MASK_ISP 0xc338
+#define SRC_MASK_MAUDIO 0xc33c
+#define SRC_MASK_FSYS 0xc340
+#define SRC_MASK_PERIL0 0xc350
+#define SRC_MASK_PERIL1 0xc354
+#define DIV_TOP 0xc510
+#define DIV_CAM 0xc520
+#define DIV_TV 0xc524
+#define DIV_MFC 0xc528
+#define DIV_G3D 0xc52c
+#define DIV_IMAGE 0xc530
+#define DIV_LCD0 0xc534
+#define E4210_DIV_LCD1 0xc538
+#define E4X12_DIV_ISP 0xc538
+#define DIV_MAUDIO 0xc53c
+#define DIV_FSYS0 0xc540
+#define DIV_FSYS1 0xc544
+#define DIV_FSYS2 0xc548
+#define DIV_FSYS3 0xc54c
+#define DIV_PERIL0 0xc550
+#define DIV_PERIL1 0xc554
+#define DIV_PERIL2 0xc558
+#define DIV_PERIL3 0xc55c
+#define DIV_PERIL4 0xc560
+#define DIV_PERIL5 0xc564
+#define E4X12_DIV_CAM1 0xc568
+#define GATE_SCLK_CAM 0xc820
+#define GATE_IP_CAM 0xc920
+#define GATE_IP_TV 0xc924
+#define GATE_IP_MFC 0xc928
+#define GATE_IP_G3D 0xc92c
+#define E4210_GATE_IP_IMAGE 0xc930
+#define GATE_IP_LCD0 0xc934
+#define E4210_GATE_IP_LCD1 0xc938
+#define E4X12_GATE_IP_ISP 0xc938
+#define E4X12_GATE_IP_MAUDIO 0xc93c
+#define GATE_IP_FSYS 0xc940
+#define GATE_IP_GPS 0xc94c
+#define GATE_IP_PERIL 0xc950
+#define E4210_GATE_IP_PERIR 0xc960
+#define GATE_BLOCK 0xc970
+#define E4X12_MPLL_CON0 0x10108
+#define SRC_DMC 0x10200
+#define SRC_MASK_DMC 0x10300
+#define DIV_DMC0 0x10500
+#define DIV_DMC1 0x10504
+#define GATE_IP_DMC 0x10900
+#define APLL_CON0 0x14100
+#define E4210_MPLL_CON0 0x14108
+#define SRC_CPU 0x14200
+#define DIV_CPU0 0x14500
+#define DIV_CPU1 0x14504
+#define GATE_SCLK_CPU 0x14800
+#define GATE_IP_CPU 0x14900
+#define E4X12_DIV_ISP0 0x18300
+#define E4X12_DIV_ISP1 0x18304
+#define E4X12_GATE_ISP0 0x18800
+#define E4X12_GATE_ISP1 0x18804
+
+/* the exynos4 soc type */
+enum exynos4_soc {
+ EXYNOS4210,
+ EXYNOS4X12,
+};
+
+/*
+ * Let each supported clock get a unique id. This id is used to lookup the clock
+ * for device tree based platforms. The clocks are categorized into three
+ * sections: core, sclk gate and bus interface gate clocks.
+ *
+ * When adding a new clock to this list, it is advised to choose a clock
+ * category and add it to the end of that category. That is because the the
+ * device tree source file is referring to these ids and any change in the
+ * sequence number of existing clocks will require corresponding change in the
+ * device tree files. This limitation would go away when pre-processor support
+ * for dtc would be available.
+ */
+enum exynos4_clks {
+ none,
+
+ /* core clocks */
+ xxti, xusbxti, fin_pll, fout_apll, fout_mpll, fout_epll, fout_vpll,
+ sclk_apll, sclk_mpll, sclk_epll, sclk_vpll, arm_clk, aclk200, aclk100,
+ aclk160, aclk133, mout_mpll_user_t, mout_mpll_user_c, mout_core,
+ mout_apll, /* 20 */
+
+ /* gate for special clocks (sclk) */
+ sclk_fimc0 = 128, sclk_fimc1, sclk_fimc2, sclk_fimc3, sclk_cam0,
+ sclk_cam1, sclk_csis0, sclk_csis1, sclk_hdmi, sclk_mixer, sclk_dac,
+ sclk_pixel, sclk_fimd0, sclk_mdnie0, sclk_mdnie_pwm0, sclk_mipi0,
+ sclk_audio0, sclk_mmc0, sclk_mmc1, sclk_mmc2, sclk_mmc3, sclk_mmc4,
+ sclk_sata, sclk_uart0, sclk_uart1, sclk_uart2, sclk_uart3, sclk_uart4,
+ sclk_audio1, sclk_audio2, sclk_spdif, sclk_spi0, sclk_spi1, sclk_spi2,
+ sclk_slimbus, sclk_fimd1, sclk_mipi1, sclk_pcm1, sclk_pcm2, sclk_i2s1,
+ sclk_i2s2, sclk_mipihsi, sclk_mfc, sclk_pcm0, sclk_g3d, sclk_pwm_isp,
+ sclk_spi0_isp, sclk_spi1_isp, sclk_uart_isp,
+
+ /* gate clocks */
+ fimc0 = 256, fimc1, fimc2, fimc3, csis0, csis1, jpeg, smmu_fimc0,
+ smmu_fimc1, smmu_fimc2, smmu_fimc3, smmu_jpeg, vp, mixer, tvenc, hdmi,
+ smmu_tv, mfc, smmu_mfcl, smmu_mfcr, g3d, g2d, rotator, mdma, smmu_g2d,
+ smmu_rotator, smmu_mdma, fimd0, mie0, mdnie0, dsim0, smmu_fimd0, fimd1,
+ mie1, dsim1, smmu_fimd1, pdma0, pdma1, pcie_phy, sata_phy, tsi, sdmmc0,
+ sdmmc1, sdmmc2, sdmmc3, sdmmc4, sata, sromc, usb_host, usb_device, pcie,
+ onenand, nfcon, smmu_pcie, gps, smmu_gps, uart0, uart1, uart2, uart3,
+ uart4, i2c0, i2c1, i2c2, i2c3, i2c4, i2c5, i2c6, i2c7, i2c_hdmi, tsadc,
+ spi0, spi1, spi2, i2s1, i2s2, pcm0, i2s0, pcm1, pcm2, pwm, slimbus,
+ spdif, ac97, modemif, chipid, sysreg, hdmi_cec, mct, wdt, rtc, keyif,
+ audss, mipi_hsi, mdma2, pixelasyncm0, pixelasyncm1, fimc_lite0,
+ fimc_lite1, ppmuispx, ppmuispmx, fimc_isp, fimc_drc, fimc_fd, mcuisp,
+ gicisp, smmu_isp, smmu_drc, smmu_fd, smmu_lite0, smmu_lite1, mcuctl_isp,
+ mpwm_isp, i2c0_isp, i2c1_isp, mtcadc_isp, pwm_isp, wdt_isp, uart_isp,
+ asyncaxim, smmu_ispcx, spi0_isp, spi1_isp, pwm_isp_sclk, spi0_isp_sclk,
+ spi1_isp_sclk, uart_isp_sclk,
+
+ /* mux clocks */
+ mout_fimc0 = 384, mout_fimc1, mout_fimc2, mout_fimc3, mout_cam0,
+ mout_cam1, mout_csis0, mout_csis1, mout_g3d0, mout_g3d1, mout_g3d,
+ aclk400_mcuisp,
+
+ /* div clocks */
+ div_isp0 = 450, div_isp1, div_mcuisp0, div_mcuisp1, div_aclk200,
+ div_aclk400_mcuisp,
+
+ nr_clks,
+};
+
+/*
+ * list of controller registers to be saved and restored during a
+ * suspend/resume cycle.
+ */
+static __initdata unsigned long exynos4210_clk_save[] = {
+ E4210_SRC_IMAGE,
+ E4210_SRC_LCD1,
+ E4210_SRC_MASK_LCD1,
+ E4210_DIV_LCD1,
+ E4210_GATE_IP_IMAGE,
+ E4210_GATE_IP_LCD1,
+ E4210_GATE_IP_PERIR,
+ E4210_MPLL_CON0,
+};
+
+static __initdata unsigned long exynos4x12_clk_save[] = {
+ E4X12_GATE_IP_IMAGE,
+ E4X12_GATE_IP_PERIR,
+ E4X12_SRC_CAM1,
+ E4X12_DIV_ISP,
+ E4X12_DIV_CAM1,
+ E4X12_MPLL_CON0,
+};
+
+static __initdata unsigned long exynos4_clk_regs[] = {
+ SRC_LEFTBUS,
+ DIV_LEFTBUS,
+ GATE_IP_LEFTBUS,
+ SRC_RIGHTBUS,
+ DIV_RIGHTBUS,
+ GATE_IP_RIGHTBUS,
+ EPLL_CON0,
+ EPLL_CON1,
+ EPLL_CON2,
+ VPLL_CON0,
+ VPLL_CON1,
+ VPLL_CON2,
+ SRC_TOP0,
+ SRC_TOP1,
+ SRC_CAM,
+ SRC_TV,
+ SRC_MFC,
+ SRC_G3D,
+ SRC_LCD0,
+ SRC_MAUDIO,
+ SRC_FSYS,
+ SRC_PERIL0,
+ SRC_PERIL1,
+ SRC_MASK_TOP,
+ SRC_MASK_CAM,
+ SRC_MASK_TV,
+ SRC_MASK_LCD0,
+ SRC_MASK_MAUDIO,
+ SRC_MASK_FSYS,
+ SRC_MASK_PERIL0,
+ SRC_MASK_PERIL1,
+ DIV_TOP,
+ DIV_CAM,
+ DIV_TV,
+ DIV_MFC,
+ DIV_G3D,
+ DIV_IMAGE,
+ DIV_LCD0,
+ DIV_MAUDIO,
+ DIV_FSYS0,
+ DIV_FSYS1,
+ DIV_FSYS2,
+ DIV_FSYS3,
+ DIV_PERIL0,
+ DIV_PERIL1,
+ DIV_PERIL2,
+ DIV_PERIL3,
+ DIV_PERIL4,
+ DIV_PERIL5,
+ GATE_SCLK_CAM,
+ GATE_IP_CAM,
+ GATE_IP_TV,
+ GATE_IP_MFC,
+ GATE_IP_G3D,
+ GATE_IP_LCD0,
+ GATE_IP_FSYS,
+ GATE_IP_GPS,
+ GATE_IP_PERIL,
+ GATE_BLOCK,
+ SRC_MASK_DMC,
+ SRC_DMC,
+ DIV_DMC0,
+ DIV_DMC1,
+ GATE_IP_DMC,
+ APLL_CON0,
+ SRC_CPU,
+ DIV_CPU0,
+ DIV_CPU1,
+ GATE_SCLK_CPU,
+ GATE_IP_CPU,
+};
+
+/* list of all parent clock list */
+PNAME(mout_apll_p) = { "fin_pll", "fout_apll", };
+PNAME(mout_mpll_p) = { "fin_pll", "fout_mpll", };
+PNAME(mout_epll_p) = { "fin_pll", "fout_epll", };
+PNAME(mout_vpllsrc_p) = { "fin_pll", "sclk_hdmi24m", };
+PNAME(mout_vpll_p) = { "fin_pll", "fout_vpll", };
+PNAME(sclk_evpll_p) = { "sclk_epll", "sclk_vpll", };
+PNAME(mout_mfc_p) = { "mout_mfc0", "mout_mfc1", };
+PNAME(mout_g3d_p) = { "mout_g3d0", "mout_g3d1", };
+PNAME(mout_g2d_p) = { "mout_g2d0", "mout_g2d1", };
+PNAME(mout_hdmi_p) = { "sclk_pixel", "sclk_hdmiphy", };
+PNAME(mout_jpeg_p) = { "mout_jpeg0", "mout_jpeg1", };
+PNAME(mout_spdif_p) = { "sclk_audio0", "sclk_audio1", "sclk_audio2",
+ "spdif_extclk", };
+PNAME(mout_onenand_p) = {"aclk133", "aclk160", };
+PNAME(mout_onenand1_p) = {"mout_onenand", "sclk_vpll", };
+
+/* Exynos 4210-specific parent groups */
+PNAME(sclk_vpll_p4210) = { "mout_vpllsrc", "fout_vpll", };
+PNAME(mout_core_p4210) = { "mout_apll", "sclk_mpll", };
+PNAME(sclk_ampll_p4210) = { "sclk_mpll", "sclk_apll", };
+PNAME(group1_p4210) = { "xxti", "xusbxti", "sclk_hdmi24m",
+ "sclk_usbphy0", "none", "sclk_hdmiphy",
+ "sclk_mpll", "sclk_epll", "sclk_vpll", };
+PNAME(mout_audio0_p4210) = { "cdclk0", "none", "sclk_hdmi24m",
+ "sclk_usbphy0", "xxti", "xusbxti", "sclk_mpll",
+ "sclk_epll", "sclk_vpll" };
+PNAME(mout_audio1_p4210) = { "cdclk1", "none", "sclk_hdmi24m",
+ "sclk_usbphy0", "xxti", "xusbxti", "sclk_mpll",
+ "sclk_epll", "sclk_vpll", };
+PNAME(mout_audio2_p4210) = { "cdclk2", "none", "sclk_hdmi24m",
+ "sclk_usbphy0", "xxti", "xusbxti", "sclk_mpll",
+ "sclk_epll", "sclk_vpll", };
+PNAME(mout_mixer_p4210) = { "sclk_dac", "sclk_hdmi", };
+PNAME(mout_dac_p4210) = { "sclk_vpll", "sclk_hdmiphy", };
+
+/* Exynos 4x12-specific parent groups */
+PNAME(mout_mpll_user_p4x12) = { "fin_pll", "sclk_mpll", };
+PNAME(mout_core_p4x12) = { "mout_apll", "mout_mpll_user_c", };
+PNAME(sclk_ampll_p4x12) = { "mout_mpll_user_t", "sclk_apll", };
+PNAME(group1_p4x12) = { "xxti", "xusbxti", "sclk_hdmi24m", "sclk_usbphy0",
+ "none", "sclk_hdmiphy", "mout_mpll_user_t",
+ "sclk_epll", "sclk_vpll", };
+PNAME(mout_audio0_p4x12) = { "cdclk0", "none", "sclk_hdmi24m",
+ "sclk_usbphy0", "xxti", "xusbxti",
+ "mout_mpll_user_t", "sclk_epll", "sclk_vpll" };
+PNAME(mout_audio1_p4x12) = { "cdclk1", "none", "sclk_hdmi24m",
+ "sclk_usbphy0", "xxti", "xusbxti",
+ "mout_mpll_user_t", "sclk_epll", "sclk_vpll", };
+PNAME(mout_audio2_p4x12) = { "cdclk2", "none", "sclk_hdmi24m",
+ "sclk_usbphy0", "xxti", "xusbxti",
+ "mout_mpll_user_t", "sclk_epll", "sclk_vpll", };
+PNAME(aclk_p4412) = { "mout_mpll_user_t", "sclk_apll", };
+PNAME(mout_user_aclk400_mcuisp_p4x12) = {"fin_pll", "div_aclk400_mcuisp", };
+PNAME(mout_user_aclk200_p4x12) = {"fin_pll", "div_aclk200", };
+PNAME(mout_user_aclk266_gps_p4x12) = {"fin_pll", "div_aclk266_gps", };
+
+/* fixed rate clocks generated outside the soc */
+struct samsung_fixed_rate_clock exynos4_fixed_rate_ext_clks[] __initdata = {
+ FRATE(xxti, "xxti", NULL, CLK_IS_ROOT, 0),
+ FRATE(xusbxti, "xusbxti", NULL, CLK_IS_ROOT, 0),
+};
+
+/* fixed rate clocks generated inside the soc */
+struct samsung_fixed_rate_clock exynos4_fixed_rate_clks[] __initdata = {
+ FRATE(none, "sclk_hdmi24m", NULL, CLK_IS_ROOT, 24000000),
+ FRATE(none, "sclk_hdmiphy", NULL, CLK_IS_ROOT, 27000000),
+ FRATE(none, "sclk_usbphy0", NULL, CLK_IS_ROOT, 48000000),
+};
+
+struct samsung_fixed_rate_clock exynos4210_fixed_rate_clks[] __initdata = {
+ FRATE(none, "sclk_usbphy1", NULL, CLK_IS_ROOT, 48000000),
+};
+
+/* list of mux clocks supported in all exynos4 soc's */
+struct samsung_mux_clock exynos4_mux_clks[] __initdata = {
+ MUX_F(mout_apll, "mout_apll", mout_apll_p, SRC_CPU, 0, 1,
+ CLK_SET_RATE_PARENT, 0),
+ MUX(none, "mout_hdmi", mout_hdmi_p, SRC_TV, 0, 1),
+ MUX(none, "mout_mfc1", sclk_evpll_p, SRC_MFC, 4, 1),
+ MUX(none, "mout_mfc", mout_mfc_p, SRC_MFC, 8, 1),
+ MUX_F(mout_g3d1, "mout_g3d1", sclk_evpll_p, SRC_G3D, 4, 1,
+ CLK_SET_RATE_PARENT, 0),
+ MUX_F(mout_g3d, "mout_g3d", mout_g3d_p, SRC_G3D, 8, 1,
+ CLK_SET_RATE_PARENT, 0),
+ MUX(none, "mout_spdif", mout_spdif_p, SRC_PERIL1, 8, 2),
+ MUX(none, "mout_onenand1", mout_onenand1_p, SRC_TOP0, 0, 1),
+ MUX_A(sclk_epll, "sclk_epll", mout_epll_p, SRC_TOP0, 4, 1, "sclk_epll"),
+ MUX(none, "mout_onenand", mout_onenand_p, SRC_TOP0, 28, 1),
+};
+
+/* list of mux clocks supported in exynos4210 soc */
+struct samsung_mux_clock exynos4210_mux_clks[] __initdata = {
+ MUX(none, "mout_aclk200", sclk_ampll_p4210, SRC_TOP0, 12, 1),
+ MUX(none, "mout_aclk100", sclk_ampll_p4210, SRC_TOP0, 16, 1),
+ MUX(none, "mout_aclk160", sclk_ampll_p4210, SRC_TOP0, 20, 1),
+ MUX(none, "mout_aclk133", sclk_ampll_p4210, SRC_TOP0, 24, 1),
+ MUX(none, "mout_vpllsrc", mout_vpllsrc_p, SRC_TOP1, 0, 1),
+ MUX(none, "mout_mixer", mout_mixer_p4210, SRC_TV, 4, 1),
+ MUX(none, "mout_dac", mout_dac_p4210, SRC_TV, 8, 1),
+ MUX(none, "mout_g2d0", sclk_ampll_p4210, E4210_SRC_IMAGE, 0, 1),
+ MUX(none, "mout_g2d1", sclk_evpll_p, E4210_SRC_IMAGE, 4, 1),
+ MUX(none, "mout_g2d", mout_g2d_p, E4210_SRC_IMAGE, 8, 1),
+ MUX(none, "mout_fimd1", group1_p4210, E4210_SRC_LCD1, 0, 4),
+ MUX(none, "mout_mipi1", group1_p4210, E4210_SRC_LCD1, 12, 4),
+ MUX_A(sclk_mpll, "sclk_mpll", mout_mpll_p, SRC_CPU, 8, 1, "sclk_mpll"),
+ MUX_A(mout_core, "mout_core", mout_core_p4210,
+ SRC_CPU, 16, 1, "mout_core"),
+ MUX_A(sclk_vpll, "sclk_vpll", sclk_vpll_p4210,
+ SRC_TOP0, 8, 1, "sclk_vpll"),
+ MUX(mout_fimc0, "mout_fimc0", group1_p4210, SRC_CAM, 0, 4),
+ MUX(mout_fimc1, "mout_fimc1", group1_p4210, SRC_CAM, 4, 4),
+ MUX(mout_fimc2, "mout_fimc2", group1_p4210, SRC_CAM, 8, 4),
+ MUX(mout_fimc3, "mout_fimc3", group1_p4210, SRC_CAM, 12, 4),
+ MUX(mout_cam0, "mout_cam0", group1_p4210, SRC_CAM, 16, 4),
+ MUX(mout_cam1, "mout_cam1", group1_p4210, SRC_CAM, 20, 4),
+ MUX(mout_csis0, "mout_csis0", group1_p4210, SRC_CAM, 24, 4),
+ MUX(mout_csis1, "mout_csis1", group1_p4210, SRC_CAM, 28, 4),
+ MUX(none, "mout_mfc0", sclk_ampll_p4210, SRC_MFC, 0, 1),
+ MUX_F(mout_g3d0, "mout_g3d0", sclk_ampll_p4210, SRC_G3D, 0, 1,
+ CLK_SET_RATE_PARENT, 0),
+ MUX(none, "mout_fimd0", group1_p4210, SRC_LCD0, 0, 4),
+ MUX(none, "mout_mipi0", group1_p4210, SRC_LCD0, 12, 4),
+ MUX(none, "mout_audio0", mout_audio0_p4210, SRC_MAUDIO, 0, 4),
+ MUX(none, "mout_mmc0", group1_p4210, SRC_FSYS, 0, 4),
+ MUX(none, "mout_mmc1", group1_p4210, SRC_FSYS, 4, 4),
+ MUX(none, "mout_mmc2", group1_p4210, SRC_FSYS, 8, 4),
+ MUX(none, "mout_mmc3", group1_p4210, SRC_FSYS, 12, 4),
+ MUX(none, "mout_mmc4", group1_p4210, SRC_FSYS, 16, 4),
+ MUX(none, "mout_sata", sclk_ampll_p4210, SRC_FSYS, 24, 1),
+ MUX(none, "mout_uart0", group1_p4210, SRC_PERIL0, 0, 4),
+ MUX(none, "mout_uart1", group1_p4210, SRC_PERIL0, 4, 4),
+ MUX(none, "mout_uart2", group1_p4210, SRC_PERIL0, 8, 4),
+ MUX(none, "mout_uart3", group1_p4210, SRC_PERIL0, 12, 4),
+ MUX(none, "mout_uart4", group1_p4210, SRC_PERIL0, 16, 4),
+ MUX(none, "mout_audio1", mout_audio1_p4210, SRC_PERIL1, 0, 4),
+ MUX(none, "mout_audio2", mout_audio2_p4210, SRC_PERIL1, 4, 4),
+ MUX(none, "mout_spi0", group1_p4210, SRC_PERIL1, 16, 4),
+ MUX(none, "mout_spi1", group1_p4210, SRC_PERIL1, 20, 4),
+ MUX(none, "mout_spi2", group1_p4210, SRC_PERIL1, 24, 4),
+};
+
+/* list of mux clocks supported in exynos4x12 soc */
+struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = {
+ MUX(mout_mpll_user_c, "mout_mpll_user_c", mout_mpll_user_p4x12,
+ SRC_CPU, 24, 1),
+ MUX(none, "mout_aclk266_gps", aclk_p4412, SRC_TOP1, 4, 1),
+ MUX(none, "mout_aclk400_mcuisp", aclk_p4412, SRC_TOP1, 8, 1),
+ MUX(mout_mpll_user_t, "mout_mpll_user_t", mout_mpll_user_p4x12,
+ SRC_TOP1, 12, 1),
+ MUX(none, "mout_user_aclk266_gps", mout_user_aclk266_gps_p4x12,
+ SRC_TOP1, 16, 1),
+ MUX(aclk200, "aclk200", mout_user_aclk200_p4x12, SRC_TOP1, 20, 1),
+ MUX(aclk400_mcuisp, "aclk400_mcuisp", mout_user_aclk400_mcuisp_p4x12,
+ SRC_TOP1, 24, 1),
+ MUX(none, "mout_aclk200", aclk_p4412, SRC_TOP0, 12, 1),
+ MUX(none, "mout_aclk100", aclk_p4412, SRC_TOP0, 16, 1),
+ MUX(none, "mout_aclk160", aclk_p4412, SRC_TOP0, 20, 1),
+ MUX(none, "mout_aclk133", aclk_p4412, SRC_TOP0, 24, 1),
+ MUX(none, "mout_mdnie0", group1_p4x12, SRC_LCD0, 4, 4),
+ MUX(none, "mout_mdnie_pwm0", group1_p4x12, SRC_LCD0, 8, 4),
+ MUX(none, "mout_sata", sclk_ampll_p4x12, SRC_FSYS, 24, 1),
+ MUX(none, "mout_jpeg0", sclk_ampll_p4x12, E4X12_SRC_CAM1, 0, 1),
+ MUX(none, "mout_jpeg1", sclk_evpll_p, E4X12_SRC_CAM1, 4, 1),
+ MUX(none, "mout_jpeg", mout_jpeg_p, E4X12_SRC_CAM1, 8, 1),
+ MUX_A(sclk_mpll, "sclk_mpll", mout_mpll_p,
+ SRC_DMC, 12, 1, "sclk_mpll"),
+ MUX_A(sclk_vpll, "sclk_vpll", mout_vpll_p,
+ SRC_TOP0, 8, 1, "sclk_vpll"),
+ MUX(mout_core, "mout_core", mout_core_p4x12, SRC_CPU, 16, 1),
+ MUX(mout_fimc0, "mout_fimc0", group1_p4x12, SRC_CAM, 0, 4),
+ MUX(mout_fimc1, "mout_fimc1", group1_p4x12, SRC_CAM, 4, 4),
+ MUX(mout_fimc2, "mout_fimc2", group1_p4x12, SRC_CAM, 8, 4),
+ MUX(mout_fimc3, "mout_fimc3", group1_p4x12, SRC_CAM, 12, 4),
+ MUX(mout_cam0, "mout_cam0", group1_p4x12, SRC_CAM, 16, 4),
+ MUX(mout_cam1, "mout_cam1", group1_p4x12, SRC_CAM, 20, 4),
+ MUX(mout_csis0, "mout_csis0", group1_p4x12, SRC_CAM, 24, 4),
+ MUX(mout_csis1, "mout_csis1", group1_p4x12, SRC_CAM, 28, 4),
+ MUX(none, "mout_mfc0", sclk_ampll_p4x12, SRC_MFC, 0, 1),
+ MUX_F(mout_g3d0, "mout_g3d0", sclk_ampll_p4x12, SRC_G3D, 0, 1,
+ CLK_SET_RATE_PARENT, 0),
+ MUX(none, "mout_fimd0", group1_p4x12, SRC_LCD0, 0, 4),
+ MUX(none, "mout_mipi0", group1_p4x12, SRC_LCD0, 12, 4),
+ MUX(none, "mout_audio0", mout_audio0_p4x12, SRC_MAUDIO, 0, 4),
+ MUX(none, "mout_mmc0", group1_p4x12, SRC_FSYS, 0, 4),
+ MUX(none, "mout_mmc1", group1_p4x12, SRC_FSYS, 4, 4),
+ MUX(none, "mout_mmc2", group1_p4x12, SRC_FSYS, 8, 4),
+ MUX(none, "mout_mmc3", group1_p4x12, SRC_FSYS, 12, 4),
+ MUX(none, "mout_mmc4", group1_p4x12, SRC_FSYS, 16, 4),
+ MUX(none, "mout_mipihsi", aclk_p4412, SRC_FSYS, 24, 1),
+ MUX(none, "mout_uart0", group1_p4x12, SRC_PERIL0, 0, 4),
+ MUX(none, "mout_uart1", group1_p4x12, SRC_PERIL0, 4, 4),
+ MUX(none, "mout_uart2", group1_p4x12, SRC_PERIL0, 8, 4),
+ MUX(none, "mout_uart3", group1_p4x12, SRC_PERIL0, 12, 4),
+ MUX(none, "mout_uart4", group1_p4x12, SRC_PERIL0, 16, 4),
+ MUX(none, "mout_audio1", mout_audio1_p4x12, SRC_PERIL1, 0, 4),
+ MUX(none, "mout_audio2", mout_audio2_p4x12, SRC_PERIL1, 4, 4),
+ MUX(none, "mout_spi0", group1_p4x12, SRC_PERIL1, 16, 4),
+ MUX(none, "mout_spi1", group1_p4x12, SRC_PERIL1, 20, 4),
+ MUX(none, "mout_spi2", group1_p4x12, SRC_PERIL1, 24, 4),
+ MUX(none, "mout_pwm_isp", group1_p4x12, E4X12_SRC_ISP, 0, 4),
+ MUX(none, "mout_spi0_isp", group1_p4x12, E4X12_SRC_ISP, 4, 4),
+ MUX(none, "mout_spi1_isp", group1_p4x12, E4X12_SRC_ISP, 8, 4),
+ MUX(none, "mout_uart_isp", group1_p4x12, E4X12_SRC_ISP, 12, 4),
+};
+
+/* list of divider clocks supported in all exynos4 soc's */
+struct samsung_div_clock exynos4_div_clks[] __initdata = {
+ DIV(none, "div_core", "mout_core", DIV_CPU0, 0, 3),
+ DIV(none, "div_core2", "div_core", DIV_CPU0, 28, 3),
+ DIV(none, "div_fimc0", "mout_fimc0", DIV_CAM, 0, 4),
+ DIV(none, "div_fimc1", "mout_fimc1", DIV_CAM, 4, 4),
+ DIV(none, "div_fimc2", "mout_fimc2", DIV_CAM, 8, 4),
+ DIV(none, "div_fimc3", "mout_fimc3", DIV_CAM, 12, 4),
+ DIV(none, "div_cam0", "mout_cam0", DIV_CAM, 16, 4),
+ DIV(none, "div_cam1", "mout_cam1", DIV_CAM, 20, 4),
+ DIV(none, "div_csis0", "mout_csis0", DIV_CAM, 24, 4),
+ DIV(none, "div_csis1", "mout_csis1", DIV_CAM, 28, 4),
+ DIV(sclk_mfc, "sclk_mfc", "mout_mfc", DIV_MFC, 0, 4),
+ DIV_F(none, "div_g3d", "mout_g3d", DIV_G3D, 0, 4,
+ CLK_SET_RATE_PARENT, 0),
+ DIV(none, "div_fimd0", "mout_fimd0", DIV_LCD0, 0, 4),
+ DIV(none, "div_mipi0", "mout_mipi0", DIV_LCD0, 16, 4),
+ DIV(none, "div_audio0", "mout_audio0", DIV_MAUDIO, 0, 4),
+ DIV(sclk_pcm0, "sclk_pcm0", "sclk_audio0", DIV_MAUDIO, 4, 8),
+ DIV(none, "div_mmc0", "mout_mmc0", DIV_FSYS1, 0, 4),
+ DIV(none, "div_mmc1", "mout_mmc1", DIV_FSYS1, 16, 4),
+ DIV(none, "div_mmc2", "mout_mmc2", DIV_FSYS2, 0, 4),
+ DIV(none, "div_mmc3", "mout_mmc3", DIV_FSYS2, 16, 4),
+ DIV(sclk_pixel, "sclk_pixel", "sclk_vpll", DIV_TV, 0, 4),
+ DIV(aclk100, "aclk100", "mout_aclk100", DIV_TOP, 4, 4),
+ DIV(aclk160, "aclk160", "mout_aclk160", DIV_TOP, 8, 3),
+ DIV(aclk133, "aclk133", "mout_aclk133", DIV_TOP, 12, 3),
+ DIV(none, "div_onenand", "mout_onenand1", DIV_TOP, 16, 3),
+ DIV(sclk_slimbus, "sclk_slimbus", "sclk_epll", DIV_PERIL3, 4, 4),
+ DIV(sclk_pcm1, "sclk_pcm1", "sclk_audio1", DIV_PERIL4, 4, 8),
+ DIV(sclk_pcm2, "sclk_pcm2", "sclk_audio2", DIV_PERIL4, 20, 8),
+ DIV(sclk_i2s1, "sclk_i2s1", "sclk_audio1", DIV_PERIL5, 0, 6),
+ DIV(sclk_i2s2, "sclk_i2s2", "sclk_audio2", DIV_PERIL5, 8, 6),
+ DIV(none, "div_mmc4", "mout_mmc4", DIV_FSYS3, 0, 4),
+ DIV(none, "div_mmc_pre4", "div_mmc4", DIV_FSYS3, 8, 8),
+ DIV(none, "div_uart0", "mout_uart0", DIV_PERIL0, 0, 4),
+ DIV(none, "div_uart1", "mout_uart1", DIV_PERIL0, 4, 4),
+ DIV(none, "div_uart2", "mout_uart2", DIV_PERIL0, 8, 4),
+ DIV(none, "div_uart3", "mout_uart3", DIV_PERIL0, 12, 4),
+ DIV(none, "div_uart4", "mout_uart4", DIV_PERIL0, 16, 4),
+ DIV(none, "div_spi0", "mout_spi0", DIV_PERIL1, 0, 4),
+ DIV(none, "div_spi_pre0", "div_spi0", DIV_PERIL1, 8, 8),
+ DIV(none, "div_spi1", "mout_spi1", DIV_PERIL1, 16, 4),
+ DIV(none, "div_spi_pre1", "div_spi1", DIV_PERIL1, 24, 8),
+ DIV(none, "div_spi2", "mout_spi2", DIV_PERIL2, 0, 4),
+ DIV(none, "div_spi_pre2", "div_spi2", DIV_PERIL2, 8, 8),
+ DIV(none, "div_audio1", "mout_audio1", DIV_PERIL4, 0, 4),
+ DIV(none, "div_audio2", "mout_audio2", DIV_PERIL4, 16, 4),
+ DIV_A(arm_clk, "arm_clk", "div_core2", DIV_CPU0, 28, 3, "arm_clk"),
+ DIV_A(sclk_apll, "sclk_apll", "mout_apll",
+ DIV_CPU0, 24, 3, "sclk_apll"),
+ DIV_F(none, "div_mipi_pre0", "div_mipi0", DIV_LCD0, 20, 4,
+ CLK_SET_RATE_PARENT, 0),
+ DIV_F(none, "div_mmc_pre0", "div_mmc0", DIV_FSYS1, 8, 8,
+ CLK_SET_RATE_PARENT, 0),
+ DIV_F(none, "div_mmc_pre1", "div_mmc1", DIV_FSYS1, 24, 8,
+ CLK_SET_RATE_PARENT, 0),
+ DIV_F(none, "div_mmc_pre2", "div_mmc2", DIV_FSYS2, 8, 8,
+ CLK_SET_RATE_PARENT, 0),
+ DIV_F(none, "div_mmc_pre3", "div_mmc3", DIV_FSYS2, 24, 8,
+ CLK_SET_RATE_PARENT, 0),
+};
+
+/* list of divider clocks supported in exynos4210 soc */
+struct samsung_div_clock exynos4210_div_clks[] __initdata = {
+ DIV(aclk200, "aclk200", "mout_aclk200", DIV_TOP, 0, 3),
+ DIV(none, "div_g2d", "mout_g2d", DIV_IMAGE, 0, 4),
+ DIV(none, "div_fimd1", "mout_fimd1", E4210_DIV_LCD1, 0, 4),
+ DIV(none, "div_mipi1", "mout_mipi1", E4210_DIV_LCD1, 16, 4),
+ DIV(none, "div_sata", "mout_sata", DIV_FSYS0, 20, 4),
+ DIV_F(none, "div_mipi_pre1", "div_mipi1", E4210_DIV_LCD1, 20, 4,
+ CLK_SET_RATE_PARENT, 0),
+};
+
+/* list of divider clocks supported in exynos4x12 soc */
+struct samsung_div_clock exynos4x12_div_clks[] __initdata = {
+ DIV(none, "div_mdnie0", "mout_mdnie0", DIV_LCD0, 4, 4),
+ DIV(none, "div_mdnie_pwm0", "mout_mdnie_pwm0", DIV_LCD0, 8, 4),
+ DIV(none, "div_mdnie_pwm_pre0", "div_mdnie_pwm0", DIV_LCD0, 12, 4),
+ DIV(none, "div_mipihsi", "mout_mipihsi", DIV_FSYS0, 20, 4),
+ DIV(none, "div_jpeg", "mout_jpeg", E4X12_DIV_CAM1, 0, 4),
+ DIV(div_aclk200, "div_aclk200", "mout_aclk200", DIV_TOP, 0, 3),
+ DIV(none, "div_aclk266_gps", "mout_aclk266_gps", DIV_TOP, 20, 3),
+ DIV(div_aclk400_mcuisp, "div_aclk400_mcuisp", "mout_aclk400_mcuisp",
+ DIV_TOP, 24, 3),
+ DIV(none, "div_pwm_isp", "mout_pwm_isp", E4X12_DIV_ISP, 0, 4),
+ DIV(none, "div_spi0_isp", "mout_spi0_isp", E4X12_DIV_ISP, 4, 4),
+ DIV(none, "div_spi0_isp_pre", "div_spi0_isp", E4X12_DIV_ISP, 8, 8),
+ DIV(none, "div_spi1_isp", "mout_spi1_isp", E4X12_DIV_ISP, 16, 4),
+ DIV(none, "div_spi1_isp_pre", "div_spi1_isp", E4X12_DIV_ISP, 20, 8),
+ DIV(none, "div_uart_isp", "mout_uart_isp", E4X12_DIV_ISP, 28, 4),
+ DIV(div_isp0, "div_isp0", "aclk200", E4X12_DIV_ISP0, 0, 3),
+ DIV(div_isp1, "div_isp1", "aclk200", E4X12_DIV_ISP0, 4, 3),
+ DIV(none, "div_mpwm", "div_isp1", E4X12_DIV_ISP1, 0, 3),
+ DIV(div_mcuisp0, "div_mcuisp0", "aclk400_mcuisp", E4X12_DIV_ISP1, 4, 3),
+ DIV(div_mcuisp1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1, 8, 3),
+};
+
+/* list of gate clocks supported in all exynos4 soc's */
+struct samsung_gate_clock exynos4_gate_clks[] __initdata = {
+ /*
+ * After all Exynos4 based platforms are migrated to use device tree,
+ * the device name and clock alias names specified below for some
+ * of the clocks can be removed.
+ */
+ GATE(sclk_hdmi, "sclk_hdmi", "mout_hdmi", SRC_MASK_TV, 0, 0, 0),
+ GATE(sclk_spdif, "sclk_spdif", "mout_spdif", SRC_MASK_PERIL1, 8, 0, 0),
+ GATE(jpeg, "jpeg", "aclk160", GATE_IP_CAM, 6, 0, 0),
+ GATE(mie0, "mie0", "aclk160", GATE_IP_LCD0, 1, 0, 0),
+ GATE(dsim0, "dsim0", "aclk160", GATE_IP_LCD0, 3, 0, 0),
+ GATE(fimd1, "fimd1", "aclk160", E4210_GATE_IP_LCD1, 0, 0, 0),
+ GATE(mie1, "mie1", "aclk160", E4210_GATE_IP_LCD1, 1, 0, 0),
+ GATE(dsim1, "dsim1", "aclk160", E4210_GATE_IP_LCD1, 3, 0, 0),
+ GATE(smmu_fimd1, "smmu_fimd1", "aclk160", E4210_GATE_IP_LCD1, 4, 0, 0),
+ GATE(tsi, "tsi", "aclk133", GATE_IP_FSYS, 4, 0, 0),
+ GATE(sromc, "sromc", "aclk133", GATE_IP_FSYS, 11, 0, 0),
+ GATE(sclk_g3d, "sclk_g3d", "div_g3d", GATE_IP_G3D, 0,
+ CLK_SET_RATE_PARENT, 0),
+ GATE(usb_device, "usb_device", "aclk133", GATE_IP_FSYS, 13, 0, 0),
+ GATE(onenand, "onenand", "aclk133", GATE_IP_FSYS, 15, 0, 0),
+ GATE(nfcon, "nfcon", "aclk133", GATE_IP_FSYS, 16, 0, 0),
+ GATE(gps, "gps", "aclk133", GATE_IP_GPS, 0, 0, 0),
+ GATE(smmu_gps, "smmu_gps", "aclk133", GATE_IP_GPS, 1, 0, 0),
+ GATE(slimbus, "slimbus", "aclk100", GATE_IP_PERIL, 25, 0, 0),
+ GATE(sclk_cam0, "sclk_cam0", "div_cam0", GATE_SCLK_CAM, 4,
+ CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_cam1, "sclk_cam1", "div_cam1", GATE_SCLK_CAM, 5,
+ CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_mipi0, "sclk_mipi0", "div_mipi_pre0",
+ SRC_MASK_LCD0, 12, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_audio0, "sclk_audio0", "div_audio0", SRC_MASK_MAUDIO, 0,
+ CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_audio1, "sclk_audio1", "div_audio1", SRC_MASK_PERIL1, 0,
+ CLK_SET_RATE_PARENT, 0),
+ GATE_D(vp, "s5p-mixer", "vp", "aclk160", GATE_IP_TV, 0, 0, 0),
+ GATE_D(mixer, "s5p-mixer", "mixer", "aclk160", GATE_IP_TV, 1, 0, 0),
+ GATE_D(hdmi, "exynos4-hdmi", "hdmi", "aclk160", GATE_IP_TV, 3, 0, 0),
+ GATE_A(pwm, "pwm", "aclk100", GATE_IP_PERIL, 24, 0, 0, "timers"),
+ GATE_A(sdmmc4, "sdmmc4", "aclk133", GATE_IP_FSYS, 9, 0, 0, "biu"),
+ GATE_A(usb_host, "usb_host", "aclk133",
+ GATE_IP_FSYS, 12, 0, 0, "usbhost"),
+ GATE_DA(sclk_fimc0, "exynos4-fimc.0", "sclk_fimc0", "div_fimc0",
+ SRC_MASK_CAM, 0, CLK_SET_RATE_PARENT, 0, "sclk_fimc"),
+ GATE_DA(sclk_fimc1, "exynos4-fimc.1", "sclk_fimc1", "div_fimc1",
+ SRC_MASK_CAM, 4, CLK_SET_RATE_PARENT, 0, "sclk_fimc"),
+ GATE_DA(sclk_fimc2, "exynos4-fimc.2", "sclk_fimc2", "div_fimc2",
+ SRC_MASK_CAM, 8, CLK_SET_RATE_PARENT, 0, "sclk_fimc"),
+ GATE_DA(sclk_fimc3, "exynos4-fimc.3", "sclk_fimc3", "div_fimc3",
+ SRC_MASK_CAM, 12, CLK_SET_RATE_PARENT, 0, "sclk_fimc"),
+ GATE_DA(sclk_csis0, "s5p-mipi-csis.0", "sclk_csis0", "div_csis0",
+ SRC_MASK_CAM, 24, CLK_SET_RATE_PARENT, 0, "sclk_csis"),
+ GATE_DA(sclk_csis1, "s5p-mipi-csis.1", "sclk_csis1", "div_csis1",
+ SRC_MASK_CAM, 28, CLK_SET_RATE_PARENT, 0, "sclk_csis"),
+ GATE_DA(sclk_fimd0, "exynos4-fb.0", "sclk_fimd0", "div_fimd0",
+ SRC_MASK_LCD0, 0, CLK_SET_RATE_PARENT, 0, "sclk_fimd"),
+ GATE_DA(sclk_mmc0, "exynos4-sdhci.0", "sclk_mmc0", "div_mmc_pre0",
+ SRC_MASK_FSYS, 0, CLK_SET_RATE_PARENT, 0,
+ "mmc_busclk.2"),
+ GATE_DA(sclk_mmc1, "exynos4-sdhci.1", "sclk_mmc1", "div_mmc_pre1",
+ SRC_MASK_FSYS, 4, CLK_SET_RATE_PARENT, 0,
+ "mmc_busclk.2"),
+ GATE_DA(sclk_mmc2, "exynos4-sdhci.2", "sclk_mmc2", "div_mmc_pre2",
+ SRC_MASK_FSYS, 8, CLK_SET_RATE_PARENT, 0,
+ "mmc_busclk.2"),
+ GATE_DA(sclk_mmc3, "exynos4-sdhci.3", "sclk_mmc3", "div_mmc_pre3",
+ SRC_MASK_FSYS, 12, CLK_SET_RATE_PARENT, 0,
+ "mmc_busclk.2"),
+ GATE_DA(sclk_mmc4, NULL, "sclk_mmc4", "div_mmc_pre4",
+ SRC_MASK_FSYS, 16, CLK_SET_RATE_PARENT, 0, "ciu"),
+ GATE_DA(sclk_uart0, "exynos4210-uart.0", "uclk0", "div_uart0",
+ SRC_MASK_PERIL0, 0, CLK_SET_RATE_PARENT,
+ 0, "clk_uart_baud0"),
+ GATE_DA(sclk_uart1, "exynos4210-uart.1", "uclk1", "div_uart1",
+ SRC_MASK_PERIL0, 4, CLK_SET_RATE_PARENT,
+ 0, "clk_uart_baud0"),
+ GATE_DA(sclk_uart2, "exynos4210-uart.2", "uclk2", "div_uart2",
+ SRC_MASK_PERIL0, 8, CLK_SET_RATE_PARENT,
+ 0, "clk_uart_baud0"),
+ GATE_DA(sclk_uart3, "exynos4210-uart.3", "uclk3", "div_uart3",
+ SRC_MASK_PERIL0, 12, CLK_SET_RATE_PARENT,
+ 0, "clk_uart_baud0"),
+ GATE_DA(sclk_uart4, "exynos4210-uart.4", "uclk4", "div_uart4",
+ SRC_MASK_PERIL0, 16, CLK_SET_RATE_PARENT,
+ 0, "clk_uart_baud0"),
+ GATE(sclk_audio2, "sclk_audio2", "div_audio2", SRC_MASK_PERIL1, 4,
+ CLK_SET_RATE_PARENT, 0),
+ GATE_DA(sclk_spi0, "exynos4210-spi.0", "sclk_spi0", "div_spi_pre0",
+ SRC_MASK_PERIL1, 16, CLK_SET_RATE_PARENT,
+ 0, "spi_busclk0"),
+ GATE_DA(sclk_spi1, "exynos4210-spi.1", "sclk_spi1", "div_spi_pre1",
+ SRC_MASK_PERIL1, 20, CLK_SET_RATE_PARENT,
+ 0, "spi_busclk0"),
+ GATE_DA(sclk_spi2, "exynos4210-spi.2", "sclk_spi2", "div_spi_pre2",
+ SRC_MASK_PERIL1, 24, CLK_SET_RATE_PARENT,
+ 0, "spi_busclk0"),
+ GATE_DA(fimc0, "exynos4-fimc.0", "fimc0", "aclk160",
+ GATE_IP_CAM, 0, 0, 0, "fimc"),
+ GATE_DA(fimc1, "exynos4-fimc.1", "fimc1", "aclk160",
+ GATE_IP_CAM, 1, 0, 0, "fimc"),
+ GATE_DA(fimc2, "exynos4-fimc.2", "fimc2", "aclk160",
+ GATE_IP_CAM, 2, 0, 0, "fimc"),
+ GATE_DA(fimc3, "exynos4-fimc.3", "fimc3", "aclk160",
+ GATE_IP_CAM, 3, 0, 0, "fimc"),
+ GATE_DA(csis0, "s5p-mipi-csis.0", "csis0", "aclk160",
+ GATE_IP_CAM, 4, 0, 0, "fimc"),
+ GATE_DA(csis1, "s5p-mipi-csis.1", "csis1", "aclk160",
+ GATE_IP_CAM, 5, 0, 0, "fimc"),
+ GATE_DA(smmu_fimc0, "exynos-sysmmu.5", "smmu_fimc0", "aclk160",
+ GATE_IP_CAM, 7, 0, 0, "sysmmu"),
+ GATE_DA(smmu_fimc1, "exynos-sysmmu.6", "smmu_fimc1", "aclk160",
+ GATE_IP_CAM, 8, 0, 0, "sysmmu"),
+ GATE_DA(smmu_fimc2, "exynos-sysmmu.7", "smmu_fimc2", "aclk160",
+ GATE_IP_CAM, 9, 0, 0, "sysmmu"),
+ GATE_DA(smmu_fimc3, "exynos-sysmmu.8", "smmu_fimc3", "aclk160",
+ GATE_IP_CAM, 10, 0, 0, "sysmmu"),
+ GATE_DA(smmu_jpeg, "exynos-sysmmu.3", "smmu_jpeg", "aclk160",
+ GATE_IP_CAM, 11, 0, 0, "sysmmu"),
+ GATE(pixelasyncm0, "pxl_async0", "aclk160", GATE_IP_CAM, 17, 0, 0),
+ GATE(pixelasyncm1, "pxl_async1", "aclk160", GATE_IP_CAM, 18, 0, 0),
+ GATE_DA(smmu_tv, "exynos-sysmmu.2", "smmu_tv", "aclk160",
+ GATE_IP_TV, 4, 0, 0, "sysmmu"),
+ GATE_DA(mfc, "s5p-mfc", "mfc", "aclk100", GATE_IP_MFC, 0, 0, 0, "mfc"),
+ GATE_DA(smmu_mfcl, "exynos-sysmmu.0", "smmu_mfcl", "aclk100",
+ GATE_IP_MFC, 1, 0, 0, "sysmmu"),
+ GATE_DA(smmu_mfcr, "exynos-sysmmu.1", "smmu_mfcr", "aclk100",
+ GATE_IP_MFC, 2, 0, 0, "sysmmu"),
+ GATE_DA(fimd0, "exynos4-fb.0", "fimd0", "aclk160",
+ GATE_IP_LCD0, 0, 0, 0, "fimd"),
+ GATE_DA(smmu_fimd0, "exynos-sysmmu.10", "smmu_fimd0", "aclk160",
+ GATE_IP_LCD0, 4, 0, 0, "sysmmu"),
+ GATE_DA(pdma0, "dma-pl330.0", "pdma0", "aclk133",
+ GATE_IP_FSYS, 0, 0, 0, "dma"),
+ GATE_DA(pdma1, "dma-pl330.1", "pdma1", "aclk133",
+ GATE_IP_FSYS, 1, 0, 0, "dma"),
+ GATE_DA(sdmmc0, "exynos4-sdhci.0", "sdmmc0", "aclk133",
+ GATE_IP_FSYS, 5, 0, 0, "hsmmc"),
+ GATE_DA(sdmmc1, "exynos4-sdhci.1", "sdmmc1", "aclk133",
+ GATE_IP_FSYS, 6, 0, 0, "hsmmc"),
+ GATE_DA(sdmmc2, "exynos4-sdhci.2", "sdmmc2", "aclk133",
+ GATE_IP_FSYS, 7, 0, 0, "hsmmc"),
+ GATE_DA(sdmmc3, "exynos4-sdhci.3", "sdmmc3", "aclk133",
+ GATE_IP_FSYS, 8, 0, 0, "hsmmc"),
+ GATE_DA(uart0, "exynos4210-uart.0", "uart0", "aclk100",
+ GATE_IP_PERIL, 0, 0, 0, "uart"),
+ GATE_DA(uart1, "exynos4210-uart.1", "uart1", "aclk100",
+ GATE_IP_PERIL, 1, 0, 0, "uart"),
+ GATE_DA(uart2, "exynos4210-uart.2", "uart2", "aclk100",
+ GATE_IP_PERIL, 2, 0, 0, "uart"),
+ GATE_DA(uart3, "exynos4210-uart.3", "uart3", "aclk100",
+ GATE_IP_PERIL, 3, 0, 0, "uart"),
+ GATE_DA(uart4, "exynos4210-uart.4", "uart4", "aclk100",
+ GATE_IP_PERIL, 4, 0, 0, "uart"),
+ GATE_DA(i2c0, "s3c2440-i2c.0", "i2c0", "aclk100",
+ GATE_IP_PERIL, 6, 0, 0, "i2c"),
+ GATE_DA(i2c1, "s3c2440-i2c.1", "i2c1", "aclk100",
+ GATE_IP_PERIL, 7, 0, 0, "i2c"),
+ GATE_DA(i2c2, "s3c2440-i2c.2", "i2c2", "aclk100",
+ GATE_IP_PERIL, 8, 0, 0, "i2c"),
+ GATE_DA(i2c3, "s3c2440-i2c.3", "i2c3", "aclk100",
+ GATE_IP_PERIL, 9, 0, 0, "i2c"),
+ GATE_DA(i2c4, "s3c2440-i2c.4", "i2c4", "aclk100",
+ GATE_IP_PERIL, 10, 0, 0, "i2c"),
+ GATE_DA(i2c5, "s3c2440-i2c.5", "i2c5", "aclk100",
+ GATE_IP_PERIL, 11, 0, 0, "i2c"),
+ GATE_DA(i2c6, "s3c2440-i2c.6", "i2c6", "aclk100",
+ GATE_IP_PERIL, 12, 0, 0, "i2c"),
+ GATE_DA(i2c7, "s3c2440-i2c.7", "i2c7", "aclk100",
+ GATE_IP_PERIL, 13, 0, 0, "i2c"),
+ GATE_DA(i2c_hdmi, "s3c2440-hdmiphy-i2c", "i2c-hdmi", "aclk100",
+ GATE_IP_PERIL, 14, 0, 0, "i2c"),
+ GATE_DA(spi0, "exynos4210-spi.0", "spi0", "aclk100",
+ GATE_IP_PERIL, 16, 0, 0, "spi"),
+ GATE_DA(spi1, "exynos4210-spi.1", "spi1", "aclk100",
+ GATE_IP_PERIL, 17, 0, 0, "spi"),
+ GATE_DA(spi2, "exynos4210-spi.2", "spi2", "aclk100",
+ GATE_IP_PERIL, 18, 0, 0, "spi"),
+ GATE_DA(i2s1, "samsung-i2s.1", "i2s1", "aclk100",
+ GATE_IP_PERIL, 20, 0, 0, "iis"),
+ GATE_DA(i2s2, "samsung-i2s.2", "i2s2", "aclk100",
+ GATE_IP_PERIL, 21, 0, 0, "iis"),
+ GATE_DA(pcm1, "samsung-pcm.1", "pcm1", "aclk100",
+ GATE_IP_PERIL, 22, 0, 0, "pcm"),
+ GATE_DA(pcm2, "samsung-pcm.2", "pcm2", "aclk100",
+ GATE_IP_PERIL, 23, 0, 0, "pcm"),
+ GATE_DA(spdif, "samsung-spdif", "spdif", "aclk100",
+ GATE_IP_PERIL, 26, 0, 0, "spdif"),
+ GATE_DA(ac97, "samsung-ac97", "ac97", "aclk100",
+ GATE_IP_PERIL, 27, 0, 0, "ac97"),
+};
+
+/* list of gate clocks supported in exynos4210 soc */
+struct samsung_gate_clock exynos4210_gate_clks[] __initdata = {
+ GATE(tvenc, "tvenc", "aclk160", GATE_IP_TV, 2, 0, 0),
+ GATE(g2d, "g2d", "aclk200", E4210_GATE_IP_IMAGE, 0, 0, 0),
+ GATE(rotator, "rotator", "aclk200", E4210_GATE_IP_IMAGE, 1, 0, 0),
+ GATE(mdma, "mdma", "aclk200", E4210_GATE_IP_IMAGE, 2, 0, 0),
+ GATE(smmu_g2d, "smmu_g2d", "aclk200", E4210_GATE_IP_IMAGE, 3, 0, 0),
+ GATE(smmu_mdma, "smmu_mdma", "aclk200", E4210_GATE_IP_IMAGE, 5, 0, 0),
+ GATE(pcie_phy, "pcie_phy", "aclk133", GATE_IP_FSYS, 2, 0, 0),
+ GATE(sata_phy, "sata_phy", "aclk133", GATE_IP_FSYS, 3, 0, 0),
+ GATE(sata, "sata", "aclk133", GATE_IP_FSYS, 10, 0, 0),
+ GATE(pcie, "pcie", "aclk133", GATE_IP_FSYS, 14, 0, 0),
+ GATE(smmu_pcie, "smmu_pcie", "aclk133", GATE_IP_FSYS, 18, 0, 0),
+ GATE(modemif, "modemif", "aclk100", GATE_IP_PERIL, 28, 0, 0),
+ GATE(chipid, "chipid", "aclk100", E4210_GATE_IP_PERIR, 0, 0, 0),
+ GATE(sysreg, "sysreg", "aclk100", E4210_GATE_IP_PERIR, 0, 0, 0),
+ GATE(hdmi_cec, "hdmi_cec", "aclk100", E4210_GATE_IP_PERIR, 11, 0, 0),
+ GATE(smmu_rotator, "smmu_rotator", "aclk200",
+ E4210_GATE_IP_IMAGE, 4, 0, 0),
+ GATE(sclk_mipi1, "sclk_mipi1", "div_mipi_pre1",
+ E4210_SRC_MASK_LCD1, 12, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_sata, "sclk_sata", "div_sata",
+ SRC_MASK_FSYS, 24, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_mixer, "sclk_mixer", "mout_mixer", SRC_MASK_TV, 4, 0, 0),
+ GATE(sclk_dac, "sclk_dac", "mout_dac", SRC_MASK_TV, 8, 0, 0),
+ GATE_A(tsadc, "tsadc", "aclk100", GATE_IP_PERIL, 15, 0, 0, "adc"),
+ GATE_A(mct, "mct", "aclk100", E4210_GATE_IP_PERIR, 13, 0, 0, "mct"),
+ GATE_A(wdt, "watchdog", "aclk100", E4210_GATE_IP_PERIR, 14, 0, 0, "watchdog"),
+ GATE_A(rtc, "rtc", "aclk100", E4210_GATE_IP_PERIR, 15, 0, 0, "rtc"),
+ GATE_A(keyif, "keyif", "aclk100", E4210_GATE_IP_PERIR, 16, 0, 0, "keypad"),
+ GATE_DA(sclk_fimd1, "exynos4-fb.1", "sclk_fimd1", "div_fimd1",
+ E4210_SRC_MASK_LCD1, 0, CLK_SET_RATE_PARENT, 0, "sclk_fimd"),
+};
+
+/* list of gate clocks supported in exynos4x12 soc */
+struct samsung_gate_clock exynos4x12_gate_clks[] __initdata = {
+ GATE(audss, "audss", "sclk_epll", E4X12_GATE_IP_MAUDIO, 0, 0, 0),
+ GATE(mdnie0, "mdnie0", "aclk160", GATE_IP_LCD0, 2, 0, 0),
+ GATE(rotator, "rotator", "aclk200", E4X12_GATE_IP_IMAGE, 1, 0, 0),
+ GATE(mdma2, "mdma2", "aclk200", E4X12_GATE_IP_IMAGE, 2, 0, 0),
+ GATE(smmu_mdma, "smmu_mdma", "aclk200", E4X12_GATE_IP_IMAGE, 5, 0, 0),
+ GATE(mipi_hsi, "mipi_hsi", "aclk133", GATE_IP_FSYS, 10, 0, 0),
+ GATE(chipid, "chipid", "aclk100", E4X12_GATE_IP_PERIR, 0, 0, 0),
+ GATE(sysreg, "sysreg", "aclk100", E4X12_GATE_IP_PERIR, 1, 0, 0),
+ GATE(hdmi_cec, "hdmi_cec", "aclk100", E4X12_GATE_IP_PERIR, 11, 0, 0),
+ GATE(sclk_mdnie0, "sclk_mdnie0", "div_mdnie0",
+ SRC_MASK_LCD0, 4, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_mdnie_pwm0, "sclk_mdnie_pwm0", "div_mdnie_pwm_pre0",
+ SRC_MASK_LCD0, 8, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_mipihsi, "sclk_mipihsi", "div_mipihsi",
+ SRC_MASK_FSYS, 24, CLK_SET_RATE_PARENT, 0),
+ GATE(smmu_rotator, "smmu_rotator", "aclk200",
+ E4X12_GATE_IP_IMAGE, 4, 0, 0),
+ GATE_A(mct, "mct", "aclk100", E4X12_GATE_IP_PERIR, 13, 0, 0, "mct"),
+ GATE_A(rtc, "rtc", "aclk100", E4X12_GATE_IP_PERIR, 15, 0, 0, "rtc"),
+ GATE_A(keyif, "keyif", "aclk100",
+ E4X12_GATE_IP_PERIR, 16, 0, 0, "keypad"),
+ GATE(sclk_pwm_isp, "sclk_pwm_isp", "div_pwm_isp",
+ E4X12_SRC_MASK_ISP, 0, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_spi0_isp, "sclk_spi0_isp", "div_spi0_isp_pre",
+ E4X12_SRC_MASK_ISP, 4, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_spi1_isp, "sclk_spi1_isp", "div_spi1_isp_pre",
+ E4X12_SRC_MASK_ISP, 8, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_uart_isp, "sclk_uart_isp", "div_uart_isp",
+ E4X12_SRC_MASK_ISP, 12, CLK_SET_RATE_PARENT, 0),
+ GATE(pwm_isp_sclk, "pwm_isp_sclk", "sclk_pwm_isp",
+ E4X12_GATE_IP_ISP, 0, 0, 0),
+ GATE(spi0_isp_sclk, "spi0_isp_sclk", "sclk_spi0_isp",
+ E4X12_GATE_IP_ISP, 1, 0, 0),
+ GATE(spi1_isp_sclk, "spi1_isp_sclk", "sclk_spi1_isp",
+ E4X12_GATE_IP_ISP, 2, 0, 0),
+ GATE(uart_isp_sclk, "uart_isp_sclk", "sclk_uart_isp",
+ E4X12_GATE_IP_ISP, 3, 0, 0),
+ GATE_A(wdt, "watchdog", "aclk100",
+ E4X12_GATE_IP_PERIR, 14, 0, 0, "watchdog"),
+ GATE_DA(pcm0, "samsung-pcm.0", "pcm0", "aclk100",
+ E4X12_GATE_IP_MAUDIO, 2, 0, 0, "pcm"),
+ GATE_DA(i2s0, "samsung-i2s.0", "i2s0", "aclk100",
+ E4X12_GATE_IP_MAUDIO, 3, 0, 0, "iis"),
+ GATE(fimc_isp, "isp", "aclk200", E4X12_GATE_ISP0, 0,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(fimc_drc, "drc", "aclk200", E4X12_GATE_ISP0, 1,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(fimc_fd, "fd", "aclk200", E4X12_GATE_ISP0, 2,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(fimc_lite0, "lite0", "aclk200", E4X12_GATE_ISP0, 3,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(fimc_lite1, "lite1", "aclk200", E4X12_GATE_ISP0, 4,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(mcuisp, "mcuisp", "aclk200", E4X12_GATE_ISP0, 5,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(gicisp, "gicisp", "aclk200", E4X12_GATE_ISP0, 7,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(smmu_isp, "smmu_isp", "aclk200", E4X12_GATE_ISP0, 8,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(smmu_drc, "smmu_drc", "aclk200", E4X12_GATE_ISP0, 9,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(smmu_fd, "smmu_fd", "aclk200", E4X12_GATE_ISP0, 10,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(smmu_lite0, "smmu_lite0", "aclk200", E4X12_GATE_ISP0, 11,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(smmu_lite1, "smmu_lite1", "aclk200", E4X12_GATE_ISP0, 12,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(ppmuispmx, "ppmuispmx", "aclk200", E4X12_GATE_ISP0, 20,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(ppmuispx, "ppmuispx", "aclk200", E4X12_GATE_ISP0, 21,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(mcuctl_isp, "mcuctl_isp", "aclk200", E4X12_GATE_ISP0, 23,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(mpwm_isp, "mpwm_isp", "aclk200", E4X12_GATE_ISP0, 24,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(i2c0_isp, "i2c0_isp", "aclk200", E4X12_GATE_ISP0, 25,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(i2c1_isp, "i2c1_isp", "aclk200", E4X12_GATE_ISP0, 26,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(mtcadc_isp, "mtcadc_isp", "aclk200", E4X12_GATE_ISP0, 27,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(pwm_isp, "pwm_isp", "aclk200", E4X12_GATE_ISP0, 28,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(wdt_isp, "wdt_isp", "aclk200", E4X12_GATE_ISP0, 30,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(uart_isp, "uart_isp", "aclk200", E4X12_GATE_ISP0, 31,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(asyncaxim, "asyncaxim", "aclk200", E4X12_GATE_ISP1, 0,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(smmu_ispcx, "smmu_ispcx", "aclk200", E4X12_GATE_ISP1, 4,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(spi0_isp, "spi0_isp", "aclk200", E4X12_GATE_ISP1, 12,
+ CLK_IGNORE_UNUSED, 0),
+ GATE(spi1_isp, "spi1_isp", "aclk200", E4X12_GATE_ISP1, 13,
+ CLK_IGNORE_UNUSED, 0),
+};
+
+#ifdef CONFIG_OF
+static struct of_device_id exynos4_clk_ids[] __initdata = {
+ { .compatible = "samsung,exynos4210-clock",
+ .data = (void *)EXYNOS4210, },
+ { .compatible = "samsung,exynos4412-clock",
+ .data = (void *)EXYNOS4X12, },
+ { },
+};
+#endif
+
+/*
+ * The parent of the fin_pll clock is selected by the XOM[0] bit. This bit
+ * resides in chipid register space, outside of the clock controller memory
+ * mapped space. So to determine the parent of fin_pll clock, the chipid
+ * controller is first remapped and the value of XOM[0] bit is read to
+ * determine the parent clock.
+ */
+static void __init exynos4_clk_register_finpll(void)
+{
+ struct samsung_fixed_rate_clock fclk;
+ struct device_node *np;
+ struct clk *clk;
+ void __iomem *chipid_base = S5P_VA_CHIPID;
+ unsigned long xom, finpll_f = 24000000;
+ char *parent_name;
+
+ np = of_find_compatible_node(NULL, NULL, "samsung,exynos4210-chipid");
+ if (np)
+ chipid_base = of_iomap(np, 0);
+
+ if (chipid_base) {
+ xom = readl(chipid_base + 8);
+ parent_name = xom & 1 ? "xusbxti" : "xxti";
+ clk = clk_get(NULL, parent_name);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to lookup parent clock %s, assuming "
+ "fin_pll clock frequency is 24MHz\n", __func__,
+ parent_name);
+ } else {
+ finpll_f = clk_get_rate(clk);
+ }
+ } else {
+ pr_err("%s: failed to map chipid registers, assuming "
+ "fin_pll clock frequency is 24MHz\n", __func__);
+ }
+
+ fclk.id = fin_pll;
+ fclk.name = "fin_pll";
+ fclk.parent_name = NULL;
+ fclk.flags = CLK_IS_ROOT;
+ fclk.fixed_rate = finpll_f;
+ samsung_clk_register_fixed_rate(&fclk, 1);
+
+ if (np)
+ iounmap(chipid_base);
+}
+
+/*
+ * This function allows non-dt platforms to specify the clock speed of the
+ * xxti and xusbxti clocks. These clocks are then registered with the specified
+ * clock speed.
+ */
+void __init exynos4_clk_register_fixed_ext(unsigned long xxti_f,
+ unsigned long xusbxti_f)
+{
+ exynos4_fixed_rate_ext_clks[0].fixed_rate = xxti_f;
+ exynos4_fixed_rate_ext_clks[1].fixed_rate = xusbxti_f;
+ samsung_clk_register_fixed_rate(exynos4_fixed_rate_ext_clks,
+ ARRAY_SIZE(exynos4_fixed_rate_ext_clks));
+}
+
+static __initdata struct of_device_id ext_clk_match[] = {
+ { .compatible = "samsung,clock-xxti", .data = (void *)0, },
+ { .compatible = "samsung,clock-xusbxti", .data = (void *)1, },
+ {},
+};
+
+/* register exynos4 clocks */
+void __init exynos4_clk_init(struct device_node *np)
+{
+ void __iomem *reg_base;
+ struct clk *apll, *mpll, *epll, *vpll;
+ u32 exynos4_soc;
+
+ if (np) {
+ const struct of_device_id *match;
+ match = of_match_node(exynos4_clk_ids, np);
+ exynos4_soc = (u32)match->data;
+
+ reg_base = of_iomap(np, 0);
+ if (!reg_base)
+ panic("%s: failed to map registers\n", __func__);
+ } else {
+ reg_base = S5P_VA_CMU;
+ if (soc_is_exynos4210())
+ exynos4_soc = EXYNOS4210;
+ else if (soc_is_exynos4212() || soc_is_exynos4412())
+ exynos4_soc = EXYNOS4X12;
+ else
+ panic("%s: unable to determine soc\n", __func__);
+ }
+
+ if (exynos4_soc == EXYNOS4210)
+ samsung_clk_init(np, reg_base, nr_clks,
+ exynos4_clk_regs, ARRAY_SIZE(exynos4_clk_regs),
+ exynos4210_clk_save, ARRAY_SIZE(exynos4210_clk_save));
+ else
+ samsung_clk_init(np, reg_base, nr_clks,
+ exynos4_clk_regs, ARRAY_SIZE(exynos4_clk_regs),
+ exynos4x12_clk_save, ARRAY_SIZE(exynos4x12_clk_save));
+
+ if (np)
+ samsung_clk_of_register_fixed_ext(exynos4_fixed_rate_ext_clks,
+ ARRAY_SIZE(exynos4_fixed_rate_ext_clks),
+ ext_clk_match);
+
+ exynos4_clk_register_finpll();
+
+ if (exynos4_soc == EXYNOS4210) {
+ apll = samsung_clk_register_pll45xx("fout_apll", "fin_pll",
+ reg_base + APLL_CON0, pll_4508);
+ mpll = samsung_clk_register_pll45xx("fout_mpll", "fin_pll",
+ reg_base + E4210_MPLL_CON0, pll_4508);
+ epll = samsung_clk_register_pll46xx("fout_epll", "fin_pll",
+ reg_base + EPLL_CON0, pll_4600);
+ vpll = samsung_clk_register_pll46xx("fout_vpll", "mout_vpllsrc",
+ reg_base + VPLL_CON0, pll_4650c);
+ } else {
+ apll = samsung_clk_register_pll35xx("fout_apll", "fin_pll",
+ reg_base + APLL_CON0);
+ mpll = samsung_clk_register_pll35xx("fout_mpll", "fin_pll",
+ reg_base + E4X12_MPLL_CON0);
+ epll = samsung_clk_register_pll36xx("fout_epll", "fin_pll",
+ reg_base + EPLL_CON0);
+ vpll = samsung_clk_register_pll36xx("fout_vpll", "fin_pll",
+ reg_base + VPLL_CON0);
+ }
+
+ samsung_clk_add_lookup(apll, fout_apll);
+ samsung_clk_add_lookup(mpll, fout_mpll);
+ samsung_clk_add_lookup(epll, fout_epll);
+ samsung_clk_add_lookup(vpll, fout_vpll);
+
+ samsung_clk_register_fixed_rate(exynos4_fixed_rate_clks,
+ ARRAY_SIZE(exynos4_fixed_rate_clks));
+ samsung_clk_register_mux(exynos4_mux_clks,
+ ARRAY_SIZE(exynos4_mux_clks));
+ samsung_clk_register_div(exynos4_div_clks,
+ ARRAY_SIZE(exynos4_div_clks));
+ samsung_clk_register_gate(exynos4_gate_clks,
+ ARRAY_SIZE(exynos4_gate_clks));
+
+ if (exynos4_soc == EXYNOS4210) {
+ samsung_clk_register_fixed_rate(exynos4210_fixed_rate_clks,
+ ARRAY_SIZE(exynos4210_fixed_rate_clks));
+ samsung_clk_register_mux(exynos4210_mux_clks,
+ ARRAY_SIZE(exynos4210_mux_clks));
+ samsung_clk_register_div(exynos4210_div_clks,
+ ARRAY_SIZE(exynos4210_div_clks));
+ samsung_clk_register_gate(exynos4210_gate_clks,
+ ARRAY_SIZE(exynos4210_gate_clks));
+ } else {
+ samsung_clk_register_mux(exynos4x12_mux_clks,
+ ARRAY_SIZE(exynos4x12_mux_clks));
+ samsung_clk_register_div(exynos4x12_div_clks,
+ ARRAY_SIZE(exynos4x12_div_clks));
+ samsung_clk_register_gate(exynos4x12_gate_clks,
+ ARRAY_SIZE(exynos4x12_gate_clks));
+ }
+
+ pr_info("%s clocks: sclk_apll = %ld, sclk_mpll = %ld\n"
+ "\tsclk_epll = %ld, sclk_vpll = %ld, arm_clk = %ld\n",
+ exynos4_soc == EXYNOS4210 ? "Exynos4210" : "Exynos4x12",
+ _get_rate("sclk_apll"), _get_rate("sclk_mpll"),
+ _get_rate("sclk_epll"), _get_rate("sclk_vpll"),
+ _get_rate("arm_clk"));
+}
+CLK_OF_DECLARE(exynos4210_clk, "samsung,exynos4210-clock", exynos4_clk_init);
+CLK_OF_DECLARE(exynos4412_clk, "samsung,exynos4412-clock", exynos4_clk_init);
diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c
new file mode 100644
index 000000000000..bb54606ff035
--- /dev/null
+++ b/drivers/clk/samsung/clk-exynos5250.c
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2013 Linaro Ltd.
+ * Author: Thomas Abraham <thomas.ab@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Common Clock Framework support for Exynos5250 SoC.
+*/
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <plat/cpu.h>
+#include "clk.h"
+#include "clk-pll.h"
+
+#define SRC_CPU 0x200
+#define DIV_CPU0 0x500
+#define SRC_CORE1 0x4204
+#define SRC_TOP0 0x10210
+#define SRC_TOP2 0x10218
+#define SRC_GSCL 0x10220
+#define SRC_DISP1_0 0x1022c
+#define SRC_MAU 0x10240
+#define SRC_FSYS 0x10244
+#define SRC_GEN 0x10248
+#define SRC_PERIC0 0x10250
+#define SRC_PERIC1 0x10254
+#define SRC_MASK_GSCL 0x10320
+#define SRC_MASK_DISP1_0 0x1032c
+#define SRC_MASK_MAU 0x10334
+#define SRC_MASK_FSYS 0x10340
+#define SRC_MASK_GEN 0x10344
+#define SRC_MASK_PERIC0 0x10350
+#define SRC_MASK_PERIC1 0x10354
+#define DIV_TOP0 0x10510
+#define DIV_TOP1 0x10514
+#define DIV_GSCL 0x10520
+#define DIV_DISP1_0 0x1052c
+#define DIV_GEN 0x1053c
+#define DIV_MAU 0x10544
+#define DIV_FSYS0 0x10548
+#define DIV_FSYS1 0x1054c
+#define DIV_FSYS2 0x10550
+#define DIV_PERIC0 0x10558
+#define DIV_PERIC1 0x1055c
+#define DIV_PERIC2 0x10560
+#define DIV_PERIC3 0x10564
+#define DIV_PERIC4 0x10568
+#define DIV_PERIC5 0x1056c
+#define GATE_IP_GSCL 0x10920
+#define GATE_IP_MFC 0x1092c
+#define GATE_IP_GEN 0x10934
+#define GATE_IP_FSYS 0x10944
+#define GATE_IP_PERIC 0x10950
+#define GATE_IP_PERIS 0x10960
+#define SRC_CDREX 0x20200
+#define PLL_DIV2_SEL 0x20a24
+#define GATE_IP_DISP1 0x10928
+
+/*
+ * Let each supported clock get a unique id. This id is used to lookup the clock
+ * for device tree based platforms. The clocks are categorized into three
+ * sections: core, sclk gate and bus interface gate clocks.
+ *
+ * When adding a new clock to this list, it is advised to choose a clock
+ * category and add it to the end of that category. That is because the the
+ * device tree source file is referring to these ids and any change in the
+ * sequence number of existing clocks will require corresponding change in the
+ * device tree files. This limitation would go away when pre-processor support
+ * for dtc would be available.
+ */
+enum exynos5250_clks {
+ none,
+
+ /* core clocks */
+ fin_pll,
+
+ /* gate for special clocks (sclk) */
+ sclk_cam_bayer = 128, sclk_cam0, sclk_cam1, sclk_gscl_wa, sclk_gscl_wb,
+ sclk_fimd1, sclk_mipi1, sclk_dp, sclk_hdmi, sclk_pixel, sclk_audio0,
+ sclk_mmc0, sclk_mmc1, sclk_mmc2, sclk_mmc3, sclk_sata, sclk_usb3,
+ sclk_jpeg, sclk_uart0, sclk_uart1, sclk_uart2, sclk_uart3, sclk_pwm,
+ sclk_audio1, sclk_audio2, sclk_spdif, sclk_spi0, sclk_spi1, sclk_spi2,
+
+ /* gate clocks */
+ gscl0 = 256, gscl1, gscl2, gscl3, gscl_wa, gscl_wb, smmu_gscl0,
+ smmu_gscl1, smmu_gscl2, smmu_gscl3, mfc, smmu_mfcl, smmu_mfcr, rotator,
+ jpeg, mdma1, smmu_rotator, smmu_jpeg, smmu_mdma1, pdma0, pdma1, sata,
+ usbotg, mipi_hsi, sdmmc0, sdmmc1, sdmmc2, sdmmc3, sromc, usb2, usb3,
+ sata_phyctrl, sata_phyi2c, uart0, uart1, uart2, uart3, uart4, i2c0,
+ i2c1, i2c2, i2c3, i2c4, i2c5, i2c6, i2c7, i2c_hdmi, adc, spi0, spi1,
+ spi2, i2s1, i2s2, pcm1, pcm2, pwm, spdif, ac97, hsi2c0, hsi2c1, hsi2c2,
+ hsi2c3, chipid, sysreg, pmu, cmu_top, cmu_core, cmu_mem, tzpc0, tzpc1,
+ tzpc2, tzpc3, tzpc4, tzpc5, tzpc6, tzpc7, tzpc8, tzpc9, hdmi_cec, mct,
+ wdt, rtc, tmu, fimd1, mie1, dsim0, dp, mixer, hdmi,
+
+ nr_clks,
+};
+
+/*
+ * list of controller registers to be saved and restored during a
+ * suspend/resume cycle.
+ */
+static __initdata unsigned long exynos5250_clk_regs[] = {
+ SRC_CPU,
+ DIV_CPU0,
+ SRC_CORE1,
+ SRC_TOP0,
+ SRC_TOP2,
+ SRC_GSCL,
+ SRC_DISP1_0,
+ SRC_MAU,
+ SRC_FSYS,
+ SRC_GEN,
+ SRC_PERIC0,
+ SRC_PERIC1,
+ SRC_MASK_GSCL,
+ SRC_MASK_DISP1_0,
+ SRC_MASK_MAU,
+ SRC_MASK_FSYS,
+ SRC_MASK_GEN,
+ SRC_MASK_PERIC0,
+ SRC_MASK_PERIC1,
+ DIV_TOP0,
+ DIV_TOP1,
+ DIV_GSCL,
+ DIV_DISP1_0,
+ DIV_GEN,
+ DIV_MAU,
+ DIV_FSYS0,
+ DIV_FSYS1,
+ DIV_FSYS2,
+ DIV_PERIC0,
+ DIV_PERIC1,
+ DIV_PERIC2,
+ DIV_PERIC3,
+ DIV_PERIC4,
+ DIV_PERIC5,
+ GATE_IP_GSCL,
+ GATE_IP_MFC,
+ GATE_IP_GEN,
+ GATE_IP_FSYS,
+ GATE_IP_PERIC,
+ GATE_IP_PERIS,
+ SRC_CDREX,
+ PLL_DIV2_SEL,
+ GATE_IP_DISP1,
+};
+
+/* list of all parent clock list */
+PNAME(mout_apll_p) = { "fin_pll", "fout_apll", };
+PNAME(mout_cpu_p) = { "mout_apll", "mout_mpll", };
+PNAME(mout_mpll_fout_p) = { "fout_mplldiv2", "fout_mpll" };
+PNAME(mout_mpll_p) = { "fin_pll", "mout_mpll_fout" };
+PNAME(mout_bpll_fout_p) = { "fout_bplldiv2", "fout_bpll" };
+PNAME(mout_bpll_p) = { "fin_pll", "mout_bpll_fout" };
+PNAME(mout_vpllsrc_p) = { "fin_pll", "sclk_hdmi27m" };
+PNAME(mout_vpll_p) = { "mout_vpllsrc", "fout_vpll" };
+PNAME(mout_cpll_p) = { "fin_pll", "fout_cpll" };
+PNAME(mout_epll_p) = { "fin_pll", "fout_epll" };
+PNAME(mout_mpll_user_p) = { "fin_pll", "sclk_mpll" };
+PNAME(mout_bpll_user_p) = { "fin_pll", "sclk_bpll" };
+PNAME(mout_aclk166_p) = { "sclk_cpll", "sclk_mpll_user" };
+PNAME(mout_aclk200_p) = { "sclk_mpll_user", "sclk_bpll_user" };
+PNAME(mout_hdmi_p) = { "div_hdmi_pixel", "sclk_hdmiphy" };
+PNAME(mout_usb3_p) = { "sclk_mpll_user", "sclk_cpll" };
+PNAME(mout_group1_p) = { "fin_pll", "fin_pll", "sclk_hdmi27m",
+ "sclk_dptxphy", "sclk_uhostphy", "sclk_hdmiphy",
+ "sclk_mpll_user", "sclk_epll", "sclk_vpll",
+ "sclk_cpll" };
+PNAME(mout_audio0_p) = { "cdclk0", "fin_pll", "sclk_hdmi27m", "sclk_dptxphy",
+ "sclk_uhostphy", "sclk_hdmiphy",
+ "sclk_mpll_user", "sclk_epll", "sclk_vpll",
+ "sclk_cpll" };
+PNAME(mout_audio1_p) = { "cdclk1", "fin_pll", "sclk_hdmi27m", "sclk_dptxphy",
+ "sclk_uhostphy", "sclk_hdmiphy",
+ "sclk_mpll_user", "sclk_epll", "sclk_vpll",
+ "sclk_cpll" };
+PNAME(mout_audio2_p) = { "cdclk2", "fin_pll", "sclk_hdmi27m", "sclk_dptxphy",
+ "sclk_uhostphy", "sclk_hdmiphy",
+ "sclk_mpll_user", "sclk_epll", "sclk_vpll",
+ "sclk_cpll" };
+PNAME(mout_spdif_p) = { "sclk_audio0", "sclk_audio1", "sclk_audio2",
+ "spdif_extclk" };
+
+/* fixed rate clocks generated outside the soc */
+struct samsung_fixed_rate_clock exynos5250_fixed_rate_ext_clks[] __initdata = {
+ FRATE(fin_pll, "fin_pll", NULL, CLK_IS_ROOT, 0),
+};
+
+/* fixed rate clocks generated inside the soc */
+struct samsung_fixed_rate_clock exynos5250_fixed_rate_clks[] __initdata = {
+ FRATE(none, "sclk_hdmiphy", NULL, CLK_IS_ROOT, 24000000),
+ FRATE(none, "sclk_hdmi27m", NULL, CLK_IS_ROOT, 27000000),
+ FRATE(none, "sclk_dptxphy", NULL, CLK_IS_ROOT, 24000000),
+ FRATE(none, "sclk_uhostphy", NULL, CLK_IS_ROOT, 48000000),
+};
+
+struct samsung_fixed_factor_clock exynos5250_fixed_factor_clks[] __initdata = {
+ FFACTOR(none, "fout_mplldiv2", "fout_mpll", 1, 2, 0),
+ FFACTOR(none, "fout_bplldiv2", "fout_bpll", 1, 2, 0),
+};
+
+struct samsung_mux_clock exynos5250_mux_clks[] __initdata = {
+ MUX(none, "mout_apll", mout_apll_p, SRC_CPU, 0, 1),
+ MUX(none, "mout_cpu", mout_cpu_p, SRC_CPU, 16, 1),
+ MUX(none, "mout_mpll_fout", mout_mpll_fout_p, PLL_DIV2_SEL, 4, 1),
+ MUX(none, "sclk_mpll", mout_mpll_p, SRC_CORE1, 8, 1),
+ MUX(none, "mout_bpll_fout", mout_bpll_fout_p, PLL_DIV2_SEL, 0, 1),
+ MUX(none, "sclk_bpll", mout_bpll_p, SRC_CDREX, 0, 1),
+ MUX(none, "mout_vpllsrc", mout_vpllsrc_p, SRC_TOP2, 0, 1),
+ MUX(none, "sclk_vpll", mout_vpll_p, SRC_TOP2, 16, 1),
+ MUX(none, "sclk_epll", mout_epll_p, SRC_TOP2, 12, 1),
+ MUX(none, "sclk_cpll", mout_cpll_p, SRC_TOP2, 8, 1),
+ MUX(none, "sclk_mpll_user", mout_mpll_user_p, SRC_TOP2, 20, 1),
+ MUX(none, "sclk_bpll_user", mout_bpll_user_p, SRC_TOP2, 24, 1),
+ MUX(none, "mout_aclk166", mout_aclk166_p, SRC_TOP0, 8, 1),
+ MUX(none, "mout_aclk333", mout_aclk166_p, SRC_TOP0, 16, 1),
+ MUX(none, "mout_aclk200", mout_aclk200_p, SRC_TOP0, 12, 1),
+ MUX(none, "mout_cam_bayer", mout_group1_p, SRC_GSCL, 12, 4),
+ MUX(none, "mout_cam0", mout_group1_p, SRC_GSCL, 16, 4),
+ MUX(none, "mout_cam1", mout_group1_p, SRC_GSCL, 20, 4),
+ MUX(none, "mout_gscl_wa", mout_group1_p, SRC_GSCL, 24, 4),
+ MUX(none, "mout_gscl_wb", mout_group1_p, SRC_GSCL, 28, 4),
+ MUX(none, "mout_fimd1", mout_group1_p, SRC_DISP1_0, 0, 4),
+ MUX(none, "mout_mipi1", mout_group1_p, SRC_DISP1_0, 12, 4),
+ MUX(none, "mout_dp", mout_group1_p, SRC_DISP1_0, 16, 4),
+ MUX(none, "mout_hdmi", mout_hdmi_p, SRC_DISP1_0, 20, 1),
+ MUX(none, "mout_audio0", mout_audio0_p, SRC_MAU, 0, 4),
+ MUX(none, "mout_mmc0", mout_group1_p, SRC_FSYS, 0, 4),
+ MUX(none, "mout_mmc1", mout_group1_p, SRC_FSYS, 4, 4),
+ MUX(none, "mout_mmc2", mout_group1_p, SRC_FSYS, 8, 4),
+ MUX(none, "mout_mmc3", mout_group1_p, SRC_FSYS, 12, 4),
+ MUX(none, "mout_sata", mout_aclk200_p, SRC_FSYS, 24, 1),
+ MUX(none, "mout_usb3", mout_usb3_p, SRC_FSYS, 28, 1),
+ MUX(none, "mout_jpeg", mout_group1_p, SRC_GEN, 0, 4),
+ MUX(none, "mout_uart0", mout_group1_p, SRC_PERIC0, 0, 4),
+ MUX(none, "mout_uart1", mout_group1_p, SRC_PERIC0, 4, 4),
+ MUX(none, "mout_uart2", mout_group1_p, SRC_PERIC0, 8, 4),
+ MUX(none, "mout_uart3", mout_group1_p, SRC_PERIC0, 12, 4),
+ MUX(none, "mout_pwm", mout_group1_p, SRC_PERIC0, 24, 4),
+ MUX(none, "mout_audio1", mout_audio1_p, SRC_PERIC1, 0, 4),
+ MUX(none, "mout_audio2", mout_audio2_p, SRC_PERIC1, 4, 4),
+ MUX(none, "mout_spdif", mout_spdif_p, SRC_PERIC1, 8, 2),
+ MUX(none, "mout_spi0", mout_group1_p, SRC_PERIC1, 16, 4),
+ MUX(none, "mout_spi1", mout_group1_p, SRC_PERIC1, 20, 4),
+ MUX(none, "mout_spi2", mout_group1_p, SRC_PERIC1, 24, 4),
+};
+
+struct samsung_div_clock exynos5250_div_clks[] __initdata = {
+ DIV(none, "div_arm", "mout_cpu", DIV_CPU0, 0, 3),
+ DIV(none, "sclk_apll", "mout_apll", DIV_CPU0, 24, 3),
+ DIV(none, "aclk66_pre", "sclk_mpll_user", DIV_TOP1, 24, 3),
+ DIV(none, "aclk66", "aclk66_pre", DIV_TOP0, 0, 3),
+ DIV(none, "aclk266", "sclk_mpll_user", DIV_TOP0, 16, 3),
+ DIV(none, "aclk166", "mout_aclk166", DIV_TOP0, 8, 3),
+ DIV(none, "aclk333", "mout_aclk333", DIV_TOP0, 20, 3),
+ DIV(none, "aclk200", "mout_aclk200", DIV_TOP0, 12, 3),
+ DIV(none, "div_cam_bayer", "mout_cam_bayer", DIV_GSCL, 12, 4),
+ DIV(none, "div_cam0", "mout_cam0", DIV_GSCL, 16, 4),
+ DIV(none, "div_cam1", "mout_cam1", DIV_GSCL, 20, 4),
+ DIV(none, "div_gscl_wa", "mout_gscl_wa", DIV_GSCL, 24, 4),
+ DIV(none, "div_gscl_wb", "mout_gscl_wb", DIV_GSCL, 28, 4),
+ DIV(none, "div_fimd1", "mout_fimd1", DIV_DISP1_0, 0, 4),
+ DIV(none, "div_mipi1", "mout_mipi1", DIV_DISP1_0, 16, 4),
+ DIV(none, "div_dp", "mout_dp", DIV_DISP1_0, 24, 4),
+ DIV(none, "div_jpeg", "mout_jpeg", DIV_GEN, 4, 4),
+ DIV(none, "div_audio0", "mout_audio0", DIV_MAU, 0, 4),
+ DIV(none, "div_pcm0", "sclk_audio0", DIV_MAU, 4, 8),
+ DIV(none, "div_sata", "mout_sata", DIV_FSYS0, 20, 4),
+ DIV(none, "div_usb3", "mout_usb3", DIV_FSYS0, 24, 4),
+ DIV(none, "div_mmc0", "mout_mmc0", DIV_FSYS1, 0, 4),
+ DIV(none, "div_mmc1", "mout_mmc1", DIV_FSYS1, 16, 4),
+ DIV(none, "div_mmc2", "mout_mmc2", DIV_FSYS2, 0, 4),
+ DIV(none, "div_mmc3", "mout_mmc3", DIV_FSYS2, 16, 4),
+ DIV(none, "div_uart0", "mout_uart0", DIV_PERIC0, 0, 4),
+ DIV(none, "div_uart1", "mout_uart1", DIV_PERIC0, 4, 4),
+ DIV(none, "div_uart2", "mout_uart2", DIV_PERIC0, 8, 4),
+ DIV(none, "div_uart3", "mout_uart3", DIV_PERIC0, 12, 4),
+ DIV(none, "div_spi0", "mout_spi0", DIV_PERIC1, 0, 4),
+ DIV(none, "div_spi1", "mout_spi1", DIV_PERIC1, 16, 4),
+ DIV(none, "div_spi2", "mout_spi2", DIV_PERIC2, 0, 4),
+ DIV(none, "div_pwm", "mout_pwm", DIV_PERIC3, 0, 4),
+ DIV(none, "div_audio1", "mout_audio1", DIV_PERIC4, 0, 4),
+ DIV(none, "div_pcm1", "sclk_audio1", DIV_PERIC4, 4, 8),
+ DIV(none, "div_audio2", "mout_audio2", DIV_PERIC4, 16, 4),
+ DIV(none, "div_pcm2", "sclk_audio2", DIV_PERIC4, 20, 8),
+ DIV(none, "div_i2s1", "sclk_audio1", DIV_PERIC5, 0, 6),
+ DIV(none, "div_i2s2", "sclk_audio2", DIV_PERIC5, 8, 6),
+ DIV(sclk_pixel, "div_hdmi_pixel", "sclk_vpll", DIV_DISP1_0, 28, 4),
+ DIV_A(none, "armclk", "div_arm", DIV_CPU0, 28, 3, "armclk"),
+ DIV_F(none, "div_mipi1_pre", "div_mipi1",
+ DIV_DISP1_0, 20, 4, CLK_SET_RATE_PARENT, 0),
+ DIV_F(none, "div_mmc_pre0", "div_mmc0",
+ DIV_FSYS1, 8, 8, CLK_SET_RATE_PARENT, 0),
+ DIV_F(none, "div_mmc_pre1", "div_mmc1",
+ DIV_FSYS1, 24, 8, CLK_SET_RATE_PARENT, 0),
+ DIV_F(none, "div_mmc_pre2", "div_mmc2",
+ DIV_FSYS2, 8, 8, CLK_SET_RATE_PARENT, 0),
+ DIV_F(none, "div_mmc_pre3", "div_mmc3",
+ DIV_FSYS2, 24, 8, CLK_SET_RATE_PARENT, 0),
+ DIV_F(none, "div_spi_pre0", "div_spi0",
+ DIV_PERIC1, 8, 8, CLK_SET_RATE_PARENT, 0),
+ DIV_F(none, "div_spi_pre1", "div_spi1",
+ DIV_PERIC1, 24, 8, CLK_SET_RATE_PARENT, 0),
+ DIV_F(none, "div_spi_pre2", "div_spi2",
+ DIV_PERIC2, 8, 8, CLK_SET_RATE_PARENT, 0),
+};
+
+struct samsung_gate_clock exynos5250_gate_clks[] __initdata = {
+ GATE(gscl0, "gscl0", "none", GATE_IP_GSCL, 0, 0, 0),
+ GATE(gscl1, "gscl1", "none", GATE_IP_GSCL, 1, 0, 0),
+ GATE(gscl2, "gscl2", "aclk266", GATE_IP_GSCL, 2, 0, 0),
+ GATE(gscl3, "gscl3", "aclk266", GATE_IP_GSCL, 3, 0, 0),
+ GATE(gscl_wa, "gscl_wa", "div_gscl_wa", GATE_IP_GSCL, 5, 0, 0),
+ GATE(gscl_wb, "gscl_wb", "div_gscl_wb", GATE_IP_GSCL, 6, 0, 0),
+ GATE(smmu_gscl0, "smmu_gscl0", "aclk266", GATE_IP_GSCL, 7, 0, 0),
+ GATE(smmu_gscl1, "smmu_gscl1", "aclk266", GATE_IP_GSCL, 8, 0, 0),
+ GATE(smmu_gscl2, "smmu_gscl2", "aclk266", GATE_IP_GSCL, 9, 0, 0),
+ GATE(smmu_gscl3, "smmu_gscl3", "aclk266", GATE_IP_GSCL, 10, 0, 0),
+ GATE(mfc, "mfc", "aclk333", GATE_IP_MFC, 0, 0, 0),
+ GATE(smmu_mfcl, "smmu_mfcl", "aclk333", GATE_IP_MFC, 1, 0, 0),
+ GATE(smmu_mfcr, "smmu_mfcr", "aclk333", GATE_IP_MFC, 2, 0, 0),
+ GATE(rotator, "rotator", "aclk266", GATE_IP_GEN, 1, 0, 0),
+ GATE(jpeg, "jpeg", "aclk166", GATE_IP_GEN, 2, 0, 0),
+ GATE(mdma1, "mdma1", "aclk266", GATE_IP_GEN, 4, 0, 0),
+ GATE(smmu_rotator, "smmu_rotator", "aclk266", GATE_IP_GEN, 6, 0, 0),
+ GATE(smmu_jpeg, "smmu_jpeg", "aclk166", GATE_IP_GEN, 7, 0, 0),
+ GATE(smmu_mdma1, "smmu_mdma1", "aclk266", GATE_IP_GEN, 9, 0, 0),
+ GATE(pdma0, "pdma0", "aclk200", GATE_IP_FSYS, 1, 0, 0),
+ GATE(pdma1, "pdma1", "aclk200", GATE_IP_FSYS, 2, 0, 0),
+ GATE(sata, "sata", "aclk200", GATE_IP_FSYS, 6, 0, 0),
+ GATE(usbotg, "usbotg", "aclk200", GATE_IP_FSYS, 7, 0, 0),
+ GATE(mipi_hsi, "mipi_hsi", "aclk200", GATE_IP_FSYS, 8, 0, 0),
+ GATE(sdmmc0, "sdmmc0", "aclk200", GATE_IP_FSYS, 12, 0, 0),
+ GATE(sdmmc1, "sdmmc1", "aclk200", GATE_IP_FSYS, 13, 0, 0),
+ GATE(sdmmc2, "sdmmc2", "aclk200", GATE_IP_FSYS, 14, 0, 0),
+ GATE(sdmmc3, "sdmmc3", "aclk200", GATE_IP_FSYS, 15, 0, 0),
+ GATE(sromc, "sromc", "aclk200", GATE_IP_FSYS, 17, 0, 0),
+ GATE(usb2, "usb2", "aclk200", GATE_IP_FSYS, 18, 0, 0),
+ GATE(usb3, "usb3", "aclk200", GATE_IP_FSYS, 19, 0, 0),
+ GATE(sata_phyctrl, "sata_phyctrl", "aclk200", GATE_IP_FSYS, 24, 0, 0),
+ GATE(sata_phyi2c, "sata_phyi2c", "aclk200", GATE_IP_FSYS, 25, 0, 0),
+ GATE(uart0, "uart0", "aclk66", GATE_IP_PERIC, 0, 0, 0),
+ GATE(uart1, "uart1", "aclk66", GATE_IP_PERIC, 1, 0, 0),
+ GATE(uart2, "uart2", "aclk66", GATE_IP_PERIC, 2, 0, 0),
+ GATE(uart3, "uart3", "aclk66", GATE_IP_PERIC, 3, 0, 0),
+ GATE(uart4, "uart4", "aclk66", GATE_IP_PERIC, 4, 0, 0),
+ GATE(i2c0, "i2c0", "aclk66", GATE_IP_PERIC, 6, 0, 0),
+ GATE(i2c1, "i2c1", "aclk66", GATE_IP_PERIC, 7, 0, 0),
+ GATE(i2c2, "i2c2", "aclk66", GATE_IP_PERIC, 8, 0, 0),
+ GATE(i2c3, "i2c3", "aclk66", GATE_IP_PERIC, 9, 0, 0),
+ GATE(i2c4, "i2c4", "aclk66", GATE_IP_PERIC, 10, 0, 0),
+ GATE(i2c5, "i2c5", "aclk66", GATE_IP_PERIC, 11, 0, 0),
+ GATE(i2c6, "i2c6", "aclk66", GATE_IP_PERIC, 12, 0, 0),
+ GATE(i2c7, "i2c7", "aclk66", GATE_IP_PERIC, 13, 0, 0),
+ GATE(i2c_hdmi, "i2c_hdmi", "aclk66", GATE_IP_PERIC, 14, 0, 0),
+ GATE(adc, "adc", "aclk66", GATE_IP_PERIC, 15, 0, 0),
+ GATE(spi0, "spi0", "aclk66", GATE_IP_PERIC, 16, 0, 0),
+ GATE(spi1, "spi1", "aclk66", GATE_IP_PERIC, 17, 0, 0),
+ GATE(spi2, "spi2", "aclk66", GATE_IP_PERIC, 18, 0, 0),
+ GATE(i2s1, "i2s1", "aclk66", GATE_IP_PERIC, 20, 0, 0),
+ GATE(i2s2, "i2s2", "aclk66", GATE_IP_PERIC, 21, 0, 0),
+ GATE(pcm1, "pcm1", "aclk66", GATE_IP_PERIC, 22, 0, 0),
+ GATE(pcm2, "pcm2", "aclk66", GATE_IP_PERIC, 23, 0, 0),
+ GATE(pwm, "pwm", "aclk66", GATE_IP_PERIC, 24, 0, 0),
+ GATE(spdif, "spdif", "aclk66", GATE_IP_PERIC, 26, 0, 0),
+ GATE(ac97, "ac97", "aclk66", GATE_IP_PERIC, 27, 0, 0),
+ GATE(hsi2c0, "hsi2c0", "aclk66", GATE_IP_PERIC, 28, 0, 0),
+ GATE(hsi2c1, "hsi2c1", "aclk66", GATE_IP_PERIC, 29, 0, 0),
+ GATE(hsi2c2, "hsi2c2", "aclk66", GATE_IP_PERIC, 30, 0, 0),
+ GATE(hsi2c3, "hsi2c3", "aclk66", GATE_IP_PERIC, 31, 0, 0),
+ GATE(chipid, "chipid", "aclk66", GATE_IP_PERIS, 0, 0, 0),
+ GATE(sysreg, "sysreg", "aclk66", GATE_IP_PERIS, 1, 0, 0),
+ GATE(pmu, "pmu", "aclk66", GATE_IP_PERIS, 2, 0, 0),
+ GATE(tzpc0, "tzpc0", "aclk66", GATE_IP_PERIS, 6, 0, 0),
+ GATE(tzpc1, "tzpc1", "aclk66", GATE_IP_PERIS, 7, 0, 0),
+ GATE(tzpc2, "tzpc2", "aclk66", GATE_IP_PERIS, 8, 0, 0),
+ GATE(tzpc3, "tzpc3", "aclk66", GATE_IP_PERIS, 9, 0, 0),
+ GATE(tzpc4, "tzpc4", "aclk66", GATE_IP_PERIS, 10, 0, 0),
+ GATE(tzpc5, "tzpc5", "aclk66", GATE_IP_PERIS, 11, 0, 0),
+ GATE(tzpc6, "tzpc6", "aclk66", GATE_IP_PERIS, 12, 0, 0),
+ GATE(tzpc7, "tzpc7", "aclk66", GATE_IP_PERIS, 13, 0, 0),
+ GATE(tzpc8, "tzpc8", "aclk66", GATE_IP_PERIS, 14, 0, 0),
+ GATE(tzpc9, "tzpc9", "aclk66", GATE_IP_PERIS, 15, 0, 0),
+ GATE(hdmi_cec, "hdmi_cec", "aclk66", GATE_IP_PERIS, 16, 0, 0),
+ GATE(mct, "mct", "aclk66", GATE_IP_PERIS, 18, 0, 0),
+ GATE(wdt, "wdt", "aclk66", GATE_IP_PERIS, 19, 0, 0),
+ GATE(rtc, "rtc", "aclk66", GATE_IP_PERIS, 20, 0, 0),
+ GATE(tmu, "tmu", "aclk66", GATE_IP_PERIS, 21, 0, 0),
+ GATE(cmu_top, "cmu_top", "aclk66",
+ GATE_IP_PERIS, 3, CLK_IGNORE_UNUSED, 0),
+ GATE(cmu_core, "cmu_core", "aclk66",
+ GATE_IP_PERIS, 4, CLK_IGNORE_UNUSED, 0),
+ GATE(cmu_mem, "cmu_mem", "aclk66",
+ GATE_IP_PERIS, 5, CLK_IGNORE_UNUSED, 0),
+ GATE(sclk_cam_bayer, "sclk_cam_bayer", "div_cam_bayer",
+ SRC_MASK_GSCL, 12, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_cam0, "sclk_cam0", "div_cam0",
+ SRC_MASK_GSCL, 16, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_cam1, "sclk_cam1", "div_cam1",
+ SRC_MASK_GSCL, 20, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_gscl_wa, "sclk_gscl_wa", "div_gscl_wa",
+ SRC_MASK_GSCL, 24, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_gscl_wb, "sclk_gscl_wb", "div_gscl_wb",
+ SRC_MASK_GSCL, 28, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_fimd1, "sclk_fimd1", "div_fimd1",
+ SRC_MASK_DISP1_0, 0, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_mipi1, "sclk_mipi1", "div_mipi1",
+ SRC_MASK_DISP1_0, 12, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_dp, "sclk_dp", "div_dp",
+ SRC_MASK_DISP1_0, 16, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_hdmi, "sclk_hdmi", "mout_hdmi",
+ SRC_MASK_DISP1_0, 20, 0, 0),
+ GATE(sclk_audio0, "sclk_audio0", "div_audio0",
+ SRC_MASK_MAU, 0, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_mmc0, "sclk_mmc0", "div_mmc_pre0",
+ SRC_MASK_FSYS, 0, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_mmc1, "sclk_mmc1", "div_mmc_pre1",
+ SRC_MASK_FSYS, 4, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_mmc2, "sclk_mmc2", "div_mmc_pre2",
+ SRC_MASK_FSYS, 8, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_mmc3, "sclk_mmc3", "div_mmc_pre3",
+ SRC_MASK_FSYS, 12, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_sata, "sclk_sata", "div_sata",
+ SRC_MASK_FSYS, 24, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_usb3, "sclk_usb3", "div_usb3",
+ SRC_MASK_FSYS, 28, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_jpeg, "sclk_jpeg", "div_jpeg",
+ SRC_MASK_GEN, 0, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_uart0, "sclk_uart0", "div_uart0",
+ SRC_MASK_PERIC0, 0, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_uart1, "sclk_uart1", "div_uart1",
+ SRC_MASK_PERIC0, 4, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_uart2, "sclk_uart2", "div_uart2",
+ SRC_MASK_PERIC0, 8, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_uart3, "sclk_uart3", "div_uart3",
+ SRC_MASK_PERIC0, 12, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_pwm, "sclk_pwm", "div_pwm",
+ SRC_MASK_PERIC0, 24, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_audio1, "sclk_audio1", "div_audio1",
+ SRC_MASK_PERIC1, 0, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_audio2, "sclk_audio2", "div_audio2",
+ SRC_MASK_PERIC1, 4, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_spdif, "sclk_spdif", "mout_spdif",
+ SRC_MASK_PERIC1, 4, 0, 0),
+ GATE(sclk_spi0, "sclk_spi0", "div_spi_pre0",
+ SRC_MASK_PERIC1, 16, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_spi1, "sclk_spi1", "div_spi_pre1",
+ SRC_MASK_PERIC1, 20, CLK_SET_RATE_PARENT, 0),
+ GATE(sclk_spi2, "sclk_spi2", "div_spi_pre2",
+ SRC_MASK_PERIC1, 24, CLK_SET_RATE_PARENT, 0),
+ GATE(fimd1, "fimd1", "aclk200", GATE_IP_DISP1, 0, 0, 0),
+ GATE(mie1, "mie1", "aclk200", GATE_IP_DISP1, 1, 0, 0),
+ GATE(dsim0, "dsim0", "aclk200", GATE_IP_DISP1, 3, 0, 0),
+ GATE(dp, "dp", "aclk200", GATE_IP_DISP1, 4, 0, 0),
+ GATE(mixer, "mixer", "aclk200", GATE_IP_DISP1, 5, 0, 0),
+ GATE(hdmi, "hdmi", "aclk200", GATE_IP_DISP1, 6, 0, 0),
+};
+
+static __initdata struct of_device_id ext_clk_match[] = {
+ { .compatible = "samsung,clock-xxti", .data = (void *)0, },
+ { },
+};
+
+/* register exynox5250 clocks */
+void __init exynos5250_clk_init(struct device_node *np)
+{
+ void __iomem *reg_base;
+ struct clk *apll, *mpll, *epll, *vpll, *bpll, *gpll, *cpll;
+
+ if (np) {
+ reg_base = of_iomap(np, 0);
+ if (!reg_base)
+ panic("%s: failed to map registers\n", __func__);
+ } else {
+ panic("%s: unable to determine soc\n", __func__);
+ }
+
+ samsung_clk_init(np, reg_base, nr_clks,
+ exynos5250_clk_regs, ARRAY_SIZE(exynos5250_clk_regs),
+ NULL, 0);
+ samsung_clk_of_register_fixed_ext(exynos5250_fixed_rate_ext_clks,
+ ARRAY_SIZE(exynos5250_fixed_rate_ext_clks),
+ ext_clk_match);
+
+ apll = samsung_clk_register_pll35xx("fout_apll", "fin_pll",
+ reg_base + 0x100);
+ mpll = samsung_clk_register_pll35xx("fout_mpll", "fin_pll",
+ reg_base + 0x4100);
+ bpll = samsung_clk_register_pll35xx("fout_bpll", "fin_pll",
+ reg_base + 0x20110);
+ gpll = samsung_clk_register_pll35xx("fout_gpll", "fin_pll",
+ reg_base + 0x10150);
+ cpll = samsung_clk_register_pll35xx("fout_cpll", "fin_pll",
+ reg_base + 0x10120);
+ epll = samsung_clk_register_pll36xx("fout_epll", "fin_pll",
+ reg_base + 0x10130);
+ vpll = samsung_clk_register_pll36xx("fout_vpll", "mout_vpllsrc",
+ reg_base + 0x10140);
+
+ samsung_clk_register_fixed_rate(exynos5250_fixed_rate_clks,
+ ARRAY_SIZE(exynos5250_fixed_rate_clks));
+ samsung_clk_register_fixed_factor(exynos5250_fixed_factor_clks,
+ ARRAY_SIZE(exynos5250_fixed_factor_clks));
+ samsung_clk_register_mux(exynos5250_mux_clks,
+ ARRAY_SIZE(exynos5250_mux_clks));
+ samsung_clk_register_div(exynos5250_div_clks,
+ ARRAY_SIZE(exynos5250_div_clks));
+ samsung_clk_register_gate(exynos5250_gate_clks,
+ ARRAY_SIZE(exynos5250_gate_clks));
+
+ pr_info("Exynos5250: clock setup completed, armclk=%ld\n",
+ _get_rate("armclk"));
+}
+CLK_OF_DECLARE(exynos5250_clk, "samsung,exynos5250-clock", exynos5250_clk_init);
diff --git a/drivers/clk/samsung/clk-exynos5440.c b/drivers/clk/samsung/clk-exynos5440.c
new file mode 100644
index 000000000000..a0a094c06f19
--- /dev/null
+++ b/drivers/clk/samsung/clk-exynos5440.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * Author: Thomas Abraham <thomas.ab@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Common Clock Framework support for Exynos5440 SoC.
+*/
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <plat/cpu.h>
+#include "clk.h"
+#include "clk-pll.h"
+
+#define CLKEN_OV_VAL 0xf8
+#define CPU_CLK_STATUS 0xfc
+#define MISC_DOUT1 0x558
+
+/*
+ * Let each supported clock get a unique id. This id is used to lookup the clock
+ * for device tree based platforms.
+ */
+enum exynos5440_clks {
+ none, xtal, arm_clk,
+
+ spi_baud = 16, pb0_250, pr0_250, pr1_250, b_250, b_125, b_200, sata,
+ usb, gmac0, cs250, pb0_250_o, pr0_250_o, pr1_250_o, b_250_o, b_125_o,
+ b_200_o, sata_o, usb_o, gmac0_o, cs250_o,
+
+ nr_clks,
+};
+
+/* parent clock name list */
+PNAME(mout_armclk_p) = { "cplla", "cpllb" };
+PNAME(mout_spi_p) = { "div125", "div200" };
+
+/* fixed rate clocks generated outside the soc */
+struct samsung_fixed_rate_clock exynos5440_fixed_rate_ext_clks[] __initdata = {
+ FRATE(none, "xtal", NULL, CLK_IS_ROOT, 0),
+};
+
+/* fixed rate clocks */
+struct samsung_fixed_rate_clock exynos5440_fixed_rate_clks[] __initdata = {
+ FRATE(none, "ppll", NULL, CLK_IS_ROOT, 1000000000),
+ FRATE(none, "usb_phy0", NULL, CLK_IS_ROOT, 60000000),
+ FRATE(none, "usb_phy1", NULL, CLK_IS_ROOT, 60000000),
+ FRATE(none, "usb_ohci12", NULL, CLK_IS_ROOT, 12000000),
+ FRATE(none, "usb_ohci48", NULL, CLK_IS_ROOT, 48000000),
+};
+
+/* fixed factor clocks */
+struct samsung_fixed_factor_clock exynos5440_fixed_factor_clks[] __initdata = {
+ FFACTOR(none, "div250", "ppll", 1, 4, 0),
+ FFACTOR(none, "div200", "ppll", 1, 5, 0),
+ FFACTOR(none, "div125", "div250", 1, 2, 0),
+};
+
+/* mux clocks */
+struct samsung_mux_clock exynos5440_mux_clks[] __initdata = {
+ MUX(none, "mout_spi", mout_spi_p, MISC_DOUT1, 5, 1),
+ MUX_A(arm_clk, "arm_clk", mout_armclk_p,
+ CPU_CLK_STATUS, 0, 1, "armclk"),
+};
+
+/* divider clocks */
+struct samsung_div_clock exynos5440_div_clks[] __initdata = {
+ DIV(spi_baud, "div_spi", "mout_spi", MISC_DOUT1, 3, 2),
+};
+
+/* gate clocks */
+struct samsung_gate_clock exynos5440_gate_clks[] __initdata = {
+ GATE(pb0_250, "pb0_250", "div250", CLKEN_OV_VAL, 3, 0, 0),
+ GATE(pr0_250, "pr0_250", "div250", CLKEN_OV_VAL, 4, 0, 0),
+ GATE(pr1_250, "pr1_250", "div250", CLKEN_OV_VAL, 5, 0, 0),
+ GATE(b_250, "b_250", "div250", CLKEN_OV_VAL, 9, 0, 0),
+ GATE(b_125, "b_125", "div125", CLKEN_OV_VAL, 10, 0, 0),
+ GATE(b_200, "b_200", "div200", CLKEN_OV_VAL, 11, 0, 0),
+ GATE(sata, "sata", "div200", CLKEN_OV_VAL, 12, 0, 0),
+ GATE(usb, "usb", "div200", CLKEN_OV_VAL, 13, 0, 0),
+ GATE(gmac0, "gmac0", "div200", CLKEN_OV_VAL, 14, 0, 0),
+ GATE(cs250, "cs250", "div250", CLKEN_OV_VAL, 19, 0, 0),
+ GATE(pb0_250_o, "pb0_250_o", "pb0_250", CLKEN_OV_VAL, 3, 0, 0),
+ GATE(pr0_250_o, "pr0_250_o", "pr0_250", CLKEN_OV_VAL, 4, 0, 0),
+ GATE(pr1_250_o, "pr1_250_o", "pr1_250", CLKEN_OV_VAL, 5, 0, 0),
+ GATE(b_250_o, "b_250_o", "b_250", CLKEN_OV_VAL, 9, 0, 0),
+ GATE(b_125_o, "b_125_o", "b_125", CLKEN_OV_VAL, 10, 0, 0),
+ GATE(b_200_o, "b_200_o", "b_200", CLKEN_OV_VAL, 11, 0, 0),
+ GATE(sata_o, "sata_o", "sata", CLKEN_OV_VAL, 12, 0, 0),
+ GATE(usb_o, "usb_o", "usb", CLKEN_OV_VAL, 13, 0, 0),
+ GATE(gmac0_o, "gmac0_o", "gmac", CLKEN_OV_VAL, 14, 0, 0),
+ GATE(cs250_o, "cs250_o", "cs250", CLKEN_OV_VAL, 19, 0, 0),
+};
+
+static __initdata struct of_device_id ext_clk_match[] = {
+ { .compatible = "samsung,clock-xtal", .data = (void *)0, },
+ {},
+};
+
+/* register exynos5440 clocks */
+void __init exynos5440_clk_init(struct device_node *np)
+{
+ void __iomem *reg_base;
+
+ reg_base = of_iomap(np, 0);
+ if (!reg_base) {
+ pr_err("%s: failed to map clock controller registers,"
+ " aborting clock initialization\n", __func__);
+ return;
+ }
+
+ samsung_clk_init(np, reg_base, nr_clks, NULL, 0, NULL, 0);
+ samsung_clk_of_register_fixed_ext(exynos5440_fixed_rate_ext_clks,
+ ARRAY_SIZE(exynos5440_fixed_rate_ext_clks), ext_clk_match);
+
+ samsung_clk_register_pll2550x("cplla", "xtal", reg_base + 0x1c, 0x10);
+ samsung_clk_register_pll2550x("cpllb", "xtal", reg_base + 0x20, 0x10);
+
+ samsung_clk_register_fixed_rate(exynos5440_fixed_rate_clks,
+ ARRAY_SIZE(exynos5440_fixed_rate_clks));
+ samsung_clk_register_fixed_factor(exynos5440_fixed_factor_clks,
+ ARRAY_SIZE(exynos5440_fixed_factor_clks));
+ samsung_clk_register_mux(exynos5440_mux_clks,
+ ARRAY_SIZE(exynos5440_mux_clks));
+ samsung_clk_register_div(exynos5440_div_clks,
+ ARRAY_SIZE(exynos5440_div_clks));
+ samsung_clk_register_gate(exynos5440_gate_clks,
+ ARRAY_SIZE(exynos5440_gate_clks));
+
+ pr_info("Exynos5440: arm_clk = %ldHz\n", _get_rate("armclk"));
+ pr_info("exynos5440 clock initialization complete\n");
+}
+CLK_OF_DECLARE(exynos5440_clk, "samsung,exynos5440-clock", exynos5440_clk_init);
diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c
new file mode 100644
index 000000000000..89135f6be116
--- /dev/null
+++ b/drivers/clk/samsung/clk-pll.c
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2013 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This file contains the utility functions to register the pll clocks.
+*/
+
+#include <linux/errno.h>
+#include "clk.h"
+#include "clk-pll.h"
+
+/*
+ * PLL35xx Clock Type
+ */
+
+#define PLL35XX_MDIV_MASK (0x3FF)
+#define PLL35XX_PDIV_MASK (0x3F)
+#define PLL35XX_SDIV_MASK (0x7)
+#define PLL35XX_MDIV_SHIFT (16)
+#define PLL35XX_PDIV_SHIFT (8)
+#define PLL35XX_SDIV_SHIFT (0)
+
+struct samsung_clk_pll35xx {
+ struct clk_hw hw;
+ const void __iomem *con_reg;
+};
+
+#define to_clk_pll35xx(_hw) container_of(_hw, struct samsung_clk_pll35xx, hw)
+
+static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct samsung_clk_pll35xx *pll = to_clk_pll35xx(hw);
+ u32 mdiv, pdiv, sdiv, pll_con;
+ u64 fvco = parent_rate;
+
+ pll_con = __raw_readl(pll->con_reg);
+ mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK;
+ pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK;
+ sdiv = (pll_con >> PLL35XX_SDIV_SHIFT) & PLL35XX_SDIV_MASK;
+
+ fvco *= mdiv;
+ do_div(fvco, (pdiv << sdiv));
+
+ return (unsigned long)fvco;
+}
+
+static const struct clk_ops samsung_pll35xx_clk_ops = {
+ .recalc_rate = samsung_pll35xx_recalc_rate,
+};
+
+struct clk * __init samsung_clk_register_pll35xx(const char *name,
+ const char *pname, const void __iomem *con_reg)
+{
+ struct samsung_clk_pll35xx *pll;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll) {
+ pr_err("%s: could not allocate pll clk %s\n", __func__, name);
+ return NULL;
+ }
+
+ init.name = name;
+ init.ops = &samsung_pll35xx_clk_ops;
+ init.flags = CLK_GET_RATE_NOCACHE;
+ init.parent_names = &pname;
+ init.num_parents = 1;
+
+ pll->hw.init = &init;
+ pll->con_reg = con_reg;
+
+ clk = clk_register(NULL, &pll->hw);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to register pll clock %s\n", __func__,
+ name);
+ kfree(pll);
+ }
+
+ if (clk_register_clkdev(clk, name, NULL))
+ pr_err("%s: failed to register lookup for %s", __func__, name);
+
+ return clk;
+}
+
+/*
+ * PLL36xx Clock Type
+ */
+
+#define PLL36XX_KDIV_MASK (0xFFFF)
+#define PLL36XX_MDIV_MASK (0x1FF)
+#define PLL36XX_PDIV_MASK (0x3F)
+#define PLL36XX_SDIV_MASK (0x7)
+#define PLL36XX_MDIV_SHIFT (16)
+#define PLL36XX_PDIV_SHIFT (8)
+#define PLL36XX_SDIV_SHIFT (0)
+
+struct samsung_clk_pll36xx {
+ struct clk_hw hw;
+ const void __iomem *con_reg;
+};
+
+#define to_clk_pll36xx(_hw) container_of(_hw, struct samsung_clk_pll36xx, hw)
+
+static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct samsung_clk_pll36xx *pll = to_clk_pll36xx(hw);
+ u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1;
+ u64 fvco = parent_rate;
+
+ pll_con0 = __raw_readl(pll->con_reg);
+ pll_con1 = __raw_readl(pll->con_reg + 4);
+ mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK;
+ pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK;
+ sdiv = (pll_con0 >> PLL36XX_SDIV_SHIFT) & PLL36XX_SDIV_MASK;
+ kdiv = pll_con1 & PLL36XX_KDIV_MASK;
+
+ fvco *= (mdiv << 16) + kdiv;
+ do_div(fvco, (pdiv << sdiv));
+ fvco >>= 16;
+
+ return (unsigned long)fvco;
+}
+
+static const struct clk_ops samsung_pll36xx_clk_ops = {
+ .recalc_rate = samsung_pll36xx_recalc_rate,
+};
+
+struct clk * __init samsung_clk_register_pll36xx(const char *name,
+ const char *pname, const void __iomem *con_reg)
+{
+ struct samsung_clk_pll36xx *pll;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll) {
+ pr_err("%s: could not allocate pll clk %s\n", __func__, name);
+ return NULL;
+ }
+
+ init.name = name;
+ init.ops = &samsung_pll36xx_clk_ops;
+ init.flags = CLK_GET_RATE_NOCACHE;
+ init.parent_names = &pname;
+ init.num_parents = 1;
+
+ pll->hw.init = &init;
+ pll->con_reg = con_reg;
+
+ clk = clk_register(NULL, &pll->hw);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to register pll clock %s\n", __func__,
+ name);
+ kfree(pll);
+ }
+
+ if (clk_register_clkdev(clk, name, NULL))
+ pr_err("%s: failed to register lookup for %s", __func__, name);
+
+ return clk;
+}
+
+/*
+ * PLL45xx Clock Type
+ */
+
+#define PLL45XX_MDIV_MASK (0x3FF)
+#define PLL45XX_PDIV_MASK (0x3F)
+#define PLL45XX_SDIV_MASK (0x7)
+#define PLL45XX_MDIV_SHIFT (16)
+#define PLL45XX_PDIV_SHIFT (8)
+#define PLL45XX_SDIV_SHIFT (0)
+
+struct samsung_clk_pll45xx {
+ struct clk_hw hw;
+ enum pll45xx_type type;
+ const void __iomem *con_reg;
+};
+
+#define to_clk_pll45xx(_hw) container_of(_hw, struct samsung_clk_pll45xx, hw)
+
+static unsigned long samsung_pll45xx_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct samsung_clk_pll45xx *pll = to_clk_pll45xx(hw);
+ u32 mdiv, pdiv, sdiv, pll_con;
+ u64 fvco = parent_rate;
+
+ pll_con = __raw_readl(pll->con_reg);
+ mdiv = (pll_con >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK;
+ pdiv = (pll_con >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK;
+ sdiv = (pll_con >> PLL45XX_SDIV_SHIFT) & PLL45XX_SDIV_MASK;
+
+ if (pll->type == pll_4508)
+ sdiv = sdiv - 1;
+
+ fvco *= mdiv;
+ do_div(fvco, (pdiv << sdiv));
+
+ return (unsigned long)fvco;
+}
+
+static const struct clk_ops samsung_pll45xx_clk_ops = {
+ .recalc_rate = samsung_pll45xx_recalc_rate,
+};
+
+struct clk * __init samsung_clk_register_pll45xx(const char *name,
+ const char *pname, const void __iomem *con_reg,
+ enum pll45xx_type type)
+{
+ struct samsung_clk_pll45xx *pll;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll) {
+ pr_err("%s: could not allocate pll clk %s\n", __func__, name);
+ return NULL;
+ }
+
+ init.name = name;
+ init.ops = &samsung_pll45xx_clk_ops;
+ init.flags = CLK_GET_RATE_NOCACHE;
+ init.parent_names = &pname;
+ init.num_parents = 1;
+
+ pll->hw.init = &init;
+ pll->con_reg = con_reg;
+ pll->type = type;
+
+ clk = clk_register(NULL, &pll->hw);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to register pll clock %s\n", __func__,
+ name);
+ kfree(pll);
+ }
+
+ if (clk_register_clkdev(clk, name, NULL))
+ pr_err("%s: failed to register lookup for %s", __func__, name);
+
+ return clk;
+}
+
+/*
+ * PLL46xx Clock Type
+ */
+
+#define PLL46XX_MDIV_MASK (0x1FF)
+#define PLL46XX_PDIV_MASK (0x3F)
+#define PLL46XX_SDIV_MASK (0x7)
+#define PLL46XX_MDIV_SHIFT (16)
+#define PLL46XX_PDIV_SHIFT (8)
+#define PLL46XX_SDIV_SHIFT (0)
+
+#define PLL46XX_KDIV_MASK (0xFFFF)
+#define PLL4650C_KDIV_MASK (0xFFF)
+#define PLL46XX_KDIV_SHIFT (0)
+
+struct samsung_clk_pll46xx {
+ struct clk_hw hw;
+ enum pll46xx_type type;
+ const void __iomem *con_reg;
+};
+
+#define to_clk_pll46xx(_hw) container_of(_hw, struct samsung_clk_pll46xx, hw)
+
+static unsigned long samsung_pll46xx_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct samsung_clk_pll46xx *pll = to_clk_pll46xx(hw);
+ u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1, shift;
+ u64 fvco = parent_rate;
+
+ pll_con0 = __raw_readl(pll->con_reg);
+ pll_con1 = __raw_readl(pll->con_reg + 4);
+ mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK;
+ pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
+ sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK;
+ kdiv = pll->type == pll_4650c ? pll_con1 & PLL4650C_KDIV_MASK :
+ pll_con1 & PLL46XX_KDIV_MASK;
+
+ shift = pll->type == pll_4600 ? 16 : 10;
+ fvco *= (mdiv << shift) + kdiv;
+ do_div(fvco, (pdiv << sdiv));
+ fvco >>= shift;
+
+ return (unsigned long)fvco;
+}
+
+static const struct clk_ops samsung_pll46xx_clk_ops = {
+ .recalc_rate = samsung_pll46xx_recalc_rate,
+};
+
+struct clk * __init samsung_clk_register_pll46xx(const char *name,
+ const char *pname, const void __iomem *con_reg,
+ enum pll46xx_type type)
+{
+ struct samsung_clk_pll46xx *pll;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll) {
+ pr_err("%s: could not allocate pll clk %s\n", __func__, name);
+ return NULL;
+ }
+
+ init.name = name;
+ init.ops = &samsung_pll46xx_clk_ops;
+ init.flags = CLK_GET_RATE_NOCACHE;
+ init.parent_names = &pname;
+ init.num_parents = 1;
+
+ pll->hw.init = &init;
+ pll->con_reg = con_reg;
+ pll->type = type;
+
+ clk = clk_register(NULL, &pll->hw);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to register pll clock %s\n", __func__,
+ name);
+ kfree(pll);
+ }
+
+ if (clk_register_clkdev(clk, name, NULL))
+ pr_err("%s: failed to register lookup for %s", __func__, name);
+
+ return clk;
+}
+
+/*
+ * PLL2550x Clock Type
+ */
+
+#define PLL2550X_R_MASK (0x1)
+#define PLL2550X_P_MASK (0x3F)
+#define PLL2550X_M_MASK (0x3FF)
+#define PLL2550X_S_MASK (0x7)
+#define PLL2550X_R_SHIFT (20)
+#define PLL2550X_P_SHIFT (14)
+#define PLL2550X_M_SHIFT (4)
+#define PLL2550X_S_SHIFT (0)
+
+struct samsung_clk_pll2550x {
+ struct clk_hw hw;
+ const void __iomem *reg_base;
+ unsigned long offset;
+};
+
+#define to_clk_pll2550x(_hw) container_of(_hw, struct samsung_clk_pll2550x, hw)
+
+static unsigned long samsung_pll2550x_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct samsung_clk_pll2550x *pll = to_clk_pll2550x(hw);
+ u32 r, p, m, s, pll_stat;
+ u64 fvco = parent_rate;
+
+ pll_stat = __raw_readl(pll->reg_base + pll->offset * 3);
+ r = (pll_stat >> PLL2550X_R_SHIFT) & PLL2550X_R_MASK;
+ if (!r)
+ return 0;
+ p = (pll_stat >> PLL2550X_P_SHIFT) & PLL2550X_P_MASK;
+ m = (pll_stat >> PLL2550X_M_SHIFT) & PLL2550X_M_MASK;
+ s = (pll_stat >> PLL2550X_S_SHIFT) & PLL2550X_S_MASK;
+
+ fvco *= m;
+ do_div(fvco, (p << s));
+
+ return (unsigned long)fvco;
+}
+
+static const struct clk_ops samsung_pll2550x_clk_ops = {
+ .recalc_rate = samsung_pll2550x_recalc_rate,
+};
+
+struct clk * __init samsung_clk_register_pll2550x(const char *name,
+ const char *pname, const void __iomem *reg_base,
+ const unsigned long offset)
+{
+ struct samsung_clk_pll2550x *pll;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll) {
+ pr_err("%s: could not allocate pll clk %s\n", __func__, name);
+ return NULL;
+ }
+
+ init.name = name;
+ init.ops = &samsung_pll2550x_clk_ops;
+ init.flags = CLK_GET_RATE_NOCACHE;
+ init.parent_names = &pname;
+ init.num_parents = 1;
+
+ pll->hw.init = &init;
+ pll->reg_base = reg_base;
+ pll->offset = offset;
+
+ clk = clk_register(NULL, &pll->hw);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to register pll clock %s\n", __func__,
+ name);
+ kfree(pll);
+ }
+
+ if (clk_register_clkdev(clk, name, NULL))
+ pr_err("%s: failed to register lookup for %s", __func__, name);
+
+ return clk;
+}
diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h
new file mode 100644
index 000000000000..f33786e9a78b
--- /dev/null
+++ b/drivers/clk/samsung/clk-pll.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2013 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Common Clock Framework support for all PLL's in Samsung platforms
+*/
+
+#ifndef __SAMSUNG_CLK_PLL_H
+#define __SAMSUNG_CLK_PLL_H
+
+enum pll45xx_type {
+ pll_4500,
+ pll_4502,
+ pll_4508
+};
+
+enum pll46xx_type {
+ pll_4600,
+ pll_4650,
+ pll_4650c,
+};
+
+extern struct clk * __init samsung_clk_register_pll35xx(const char *name,
+ const char *pname, const void __iomem *con_reg);
+extern struct clk * __init samsung_clk_register_pll36xx(const char *name,
+ const char *pname, const void __iomem *con_reg);
+extern struct clk * __init samsung_clk_register_pll45xx(const char *name,
+ const char *pname, const void __iomem *con_reg,
+ enum pll45xx_type type);
+extern struct clk * __init samsung_clk_register_pll46xx(const char *name,
+ const char *pname, const void __iomem *con_reg,
+ enum pll46xx_type type);
+extern struct clk * __init samsung_clk_register_pll2550x(const char *name,
+ const char *pname, const void __iomem *reg_base,
+ const unsigned long offset);
+
+#endif /* __SAMSUNG_CLK_PLL_H */
diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
new file mode 100644
index 000000000000..cd3c40ab50f3
--- /dev/null
+++ b/drivers/clk/samsung/clk.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2013 Linaro Ltd.
+ * Author: Thomas Abraham <thomas.ab@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This file includes utility functions to register clocks to common
+ * clock framework for Samsung platforms.
+*/
+
+#include <linux/syscore_ops.h>
+#include "clk.h"
+
+static DEFINE_SPINLOCK(lock);
+static struct clk **clk_table;
+static void __iomem *reg_base;
+#ifdef CONFIG_OF
+static struct clk_onecell_data clk_data;
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static struct samsung_clk_reg_dump *reg_dump;
+static unsigned long nr_reg_dump;
+
+static int samsung_clk_suspend(void)
+{
+ struct samsung_clk_reg_dump *rd = reg_dump;
+ unsigned long i;
+
+ for (i = 0; i < nr_reg_dump; i++, rd++)
+ rd->value = __raw_readl(reg_base + rd->offset);
+
+ return 0;
+}
+
+static void samsung_clk_resume(void)
+{
+ struct samsung_clk_reg_dump *rd = reg_dump;
+ unsigned long i;
+
+ for (i = 0; i < nr_reg_dump; i++, rd++)
+ __raw_writel(rd->value, reg_base + rd->offset);
+}
+
+static struct syscore_ops samsung_clk_syscore_ops = {
+ .suspend = samsung_clk_suspend,
+ .resume = samsung_clk_resume,
+};
+#endif /* CONFIG_PM_SLEEP */
+
+/* setup the essentials required to support clock lookup using ccf */
+void __init samsung_clk_init(struct device_node *np, void __iomem *base,
+ unsigned long nr_clks, unsigned long *rdump,
+ unsigned long nr_rdump, unsigned long *soc_rdump,
+ unsigned long nr_soc_rdump)
+{
+ reg_base = base;
+
+#ifdef CONFIG_PM_SLEEP
+ if (rdump && nr_rdump) {
+ unsigned int idx;
+ reg_dump = kzalloc(sizeof(struct samsung_clk_reg_dump)
+ * (nr_rdump + nr_soc_rdump), GFP_KERNEL);
+ if (!reg_dump) {
+ pr_err("%s: memory alloc for register dump failed\n",
+ __func__);
+ return;
+ }
+
+ for (idx = 0; idx < nr_rdump; idx++)
+ reg_dump[idx].offset = rdump[idx];
+ for (idx = 0; idx < nr_soc_rdump; idx++)
+ reg_dump[nr_rdump + idx].offset = soc_rdump[idx];
+ nr_reg_dump = nr_rdump + nr_soc_rdump;
+ register_syscore_ops(&samsung_clk_syscore_ops);
+ }
+#endif
+
+ clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
+ if (!clk_table)
+ panic("could not allocate clock lookup table\n");
+
+ if (!np)
+ return;
+
+#ifdef CONFIG_OF
+ clk_data.clks = clk_table;
+ clk_data.clk_num = nr_clks;
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+#endif
+}
+
+/* add a clock instance to the clock lookup table used for dt based lookup */
+void samsung_clk_add_lookup(struct clk *clk, unsigned int id)
+{
+ if (clk_table && id)
+ clk_table[id] = clk;
+}
+
+/* register a list of aliases */
+void __init samsung_clk_register_alias(struct samsung_clock_alias *list,
+ unsigned int nr_clk)
+{
+ struct clk *clk;
+ unsigned int idx, ret;
+
+ if (!clk_table) {
+ pr_err("%s: clock table missing\n", __func__);
+ return;
+ }
+
+ for (idx = 0; idx < nr_clk; idx++, list++) {
+ if (!list->id) {
+ pr_err("%s: clock id missing for index %d\n", __func__,
+ idx);
+ continue;
+ }
+
+ clk = clk_table[list->id];
+ if (!clk) {
+ pr_err("%s: failed to find clock %d\n", __func__,
+ list->id);
+ continue;
+ }
+
+ ret = clk_register_clkdev(clk, list->alias, list->dev_name);
+ if (ret)
+ pr_err("%s: failed to register lookup %s\n",
+ __func__, list->alias);
+ }
+}
+
+/* register a list of fixed clocks */
+void __init samsung_clk_register_fixed_rate(
+ struct samsung_fixed_rate_clock *list, unsigned int nr_clk)
+{
+ struct clk *clk;
+ unsigned int idx, ret;
+
+ for (idx = 0; idx < nr_clk; idx++, list++) {
+ clk = clk_register_fixed_rate(NULL, list->name,
+ list->parent_name, list->flags, list->fixed_rate);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to register clock %s\n", __func__,
+ list->name);
+ continue;
+ }
+
+ samsung_clk_add_lookup(clk, list->id);
+
+ /*
+ * Unconditionally add a clock lookup for the fixed rate clocks.
+ * There are not many of these on any of Samsung platforms.
+ */
+ ret = clk_register_clkdev(clk, list->name, NULL);
+ if (ret)
+ pr_err("%s: failed to register clock lookup for %s",
+ __func__, list->name);
+ }
+}
+
+/* register a list of fixed factor clocks */
+void __init samsung_clk_register_fixed_factor(
+ struct samsung_fixed_factor_clock *list, unsigned int nr_clk)
+{
+ struct clk *clk;
+ unsigned int idx;
+
+ for (idx = 0; idx < nr_clk; idx++, list++) {
+ clk = clk_register_fixed_factor(NULL, list->name,
+ list->parent_name, list->flags, list->mult, list->div);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to register clock %s\n", __func__,
+ list->name);
+ continue;
+ }
+
+ samsung_clk_add_lookup(clk, list->id);
+ }
+}
+
+/* register a list of mux clocks */
+void __init samsung_clk_register_mux(struct samsung_mux_clock *list,
+ unsigned int nr_clk)
+{
+ struct clk *clk;
+ unsigned int idx, ret;
+
+ for (idx = 0; idx < nr_clk; idx++, list++) {
+ clk = clk_register_mux(NULL, list->name, list->parent_names,
+ list->num_parents, list->flags, reg_base + list->offset,
+ list->shift, list->width, list->mux_flags, &lock);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to register clock %s\n", __func__,
+ list->name);
+ continue;
+ }
+
+ samsung_clk_add_lookup(clk, list->id);
+
+ /* register a clock lookup only if a clock alias is specified */
+ if (list->alias) {
+ ret = clk_register_clkdev(clk, list->alias,
+ list->dev_name);
+ if (ret)
+ pr_err("%s: failed to register lookup %s\n",
+ __func__, list->alias);
+ }
+ }
+}
+
+/* register a list of div clocks */
+void __init samsung_clk_register_div(struct samsung_div_clock *list,
+ unsigned int nr_clk)
+{
+ struct clk *clk;
+ unsigned int idx, ret;
+
+ for (idx = 0; idx < nr_clk; idx++, list++) {
+ if (list->table)
+ clk = clk_register_divider_table(NULL, list->name,
+ list->parent_name, list->flags,
+ reg_base + list->offset, list->shift,
+ list->width, list->div_flags,
+ list->table, &lock);
+ else
+ clk = clk_register_divider(NULL, list->name,
+ list->parent_name, list->flags,
+ reg_base + list->offset, list->shift,
+ list->width, list->div_flags, &lock);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to register clock %s\n", __func__,
+ list->name);
+ continue;
+ }
+
+ samsung_clk_add_lookup(clk, list->id);
+
+ /* register a clock lookup only if a clock alias is specified */
+ if (list->alias) {
+ ret = clk_register_clkdev(clk, list->alias,
+ list->dev_name);
+ if (ret)
+ pr_err("%s: failed to register lookup %s\n",
+ __func__, list->alias);
+ }
+ }
+}
+
+/* register a list of gate clocks */
+void __init samsung_clk_register_gate(struct samsung_gate_clock *list,
+ unsigned int nr_clk)
+{
+ struct clk *clk;
+ unsigned int idx, ret;
+
+ for (idx = 0; idx < nr_clk; idx++, list++) {
+ clk = clk_register_gate(NULL, list->name, list->parent_name,
+ list->flags, reg_base + list->offset,
+ list->bit_idx, list->gate_flags, &lock);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to register clock %s\n", __func__,
+ list->name);
+ continue;
+ }
+
+ /* register a clock lookup only if a clock alias is specified */
+ if (list->alias) {
+ ret = clk_register_clkdev(clk, list->alias,
+ list->dev_name);
+ if (ret)
+ pr_err("%s: failed to register lookup %s\n",
+ __func__, list->alias);
+ }
+
+ samsung_clk_add_lookup(clk, list->id);
+ }
+}
+
+/*
+ * obtain the clock speed of all external fixed clock sources from device
+ * tree and register it
+ */
+#ifdef CONFIG_OF
+void __init samsung_clk_of_register_fixed_ext(
+ struct samsung_fixed_rate_clock *fixed_rate_clk,
+ unsigned int nr_fixed_rate_clk,
+ struct of_device_id *clk_matches)
+{
+ const struct of_device_id *match;
+ struct device_node *np;
+ u32 freq;
+
+ for_each_matching_node_and_match(np, clk_matches, &match) {
+ if (of_property_read_u32(np, "clock-frequency", &freq))
+ continue;
+ fixed_rate_clk[(u32)match->data].fixed_rate = freq;
+ }
+ samsung_clk_register_fixed_rate(fixed_rate_clk, nr_fixed_rate_clk);
+}
+#endif
+
+/* utility function to get the rate of a specified clock */
+unsigned long _get_rate(const char *clk_name)
+{
+ struct clk *clk;
+ unsigned long rate;
+
+ clk = clk_get(NULL, clk_name);
+ if (IS_ERR(clk)) {
+ pr_err("%s: could not find clock %s\n", __func__, clk_name);
+ return 0;
+ }
+ rate = clk_get_rate(clk);
+ clk_put(clk);
+ return rate;
+}
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
new file mode 100644
index 000000000000..10b2111f0c0f
--- /dev/null
+++ b/drivers/clk/samsung/clk.h
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2013 Linaro Ltd.
+ * Author: Thomas Abraham <thomas.ab@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Common Clock Framework support for all Samsung platforms
+*/
+
+#ifndef __SAMSUNG_CLK_H
+#define __SAMSUNG_CLK_H
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/io.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <mach/map.h>
+
+/**
+ * struct samsung_clock_alias: information about mux clock
+ * @id: platform specific id of the clock.
+ * @dev_name: name of the device to which this clock belongs.
+ * @alias: optional clock alias name to be assigned to this clock.
+ */
+struct samsung_clock_alias {
+ unsigned int id;
+ const char *dev_name;
+ const char *alias;
+};
+
+#define ALIAS(_id, dname, a) \
+ { \
+ .id = _id, \
+ .dev_name = dname, \
+ .alias = a, \
+ }
+
+/**
+ * struct samsung_fixed_rate_clock: information about fixed-rate clock
+ * @id: platform specific id of the clock.
+ * @name: name of this fixed-rate clock.
+ * @parent_name: optional parent clock name.
+ * @flags: optional fixed-rate clock flags.
+ * @fixed-rate: fixed clock rate of this clock.
+ */
+struct samsung_fixed_rate_clock {
+ unsigned int id;
+ char *name;
+ const char *parent_name;
+ unsigned long flags;
+ unsigned long fixed_rate;
+};
+
+#define FRATE(_id, cname, pname, f, frate) \
+ { \
+ .id = _id, \
+ .name = cname, \
+ .parent_name = pname, \
+ .flags = f, \
+ .fixed_rate = frate, \
+ }
+
+/*
+ * struct samsung_fixed_factor_clock: information about fixed-factor clock
+ * @id: platform specific id of the clock.
+ * @name: name of this fixed-factor clock.
+ * @parent_name: parent clock name.
+ * @mult: fixed multiplication factor.
+ * @div: fixed division factor.
+ * @flags: optional fixed-factor clock flags.
+ */
+struct samsung_fixed_factor_clock {
+ unsigned int id;
+ char *name;
+ const char *parent_name;
+ unsigned long mult;
+ unsigned long div;
+ unsigned long flags;
+};
+
+#define FFACTOR(_id, cname, pname, m, d, f) \
+ { \
+ .id = _id, \
+ .name = cname, \
+ .parent_name = pname, \
+ .mult = m, \
+ .div = d, \
+ .flags = f, \
+ }
+
+/**
+ * struct samsung_mux_clock: information about mux clock
+ * @id: platform specific id of the clock.
+ * @dev_name: name of the device to which this clock belongs.
+ * @name: name of this mux clock.
+ * @parent_names: array of pointer to parent clock names.
+ * @num_parents: number of parents listed in @parent_names.
+ * @flags: optional flags for basic clock.
+ * @offset: offset of the register for configuring the mux.
+ * @shift: starting bit location of the mux control bit-field in @reg.
+ * @width: width of the mux control bit-field in @reg.
+ * @mux_flags: flags for mux-type clock.
+ * @alias: optional clock alias name to be assigned to this clock.
+ */
+struct samsung_mux_clock {
+ unsigned int id;
+ const char *dev_name;
+ const char *name;
+ const char **parent_names;
+ u8 num_parents;
+ unsigned long flags;
+ unsigned long offset;
+ u8 shift;
+ u8 width;
+ u8 mux_flags;
+ const char *alias;
+};
+
+#define __MUX(_id, dname, cname, pnames, o, s, w, f, mf, a) \
+ { \
+ .id = _id, \
+ .dev_name = dname, \
+ .name = cname, \
+ .parent_names = pnames, \
+ .num_parents = ARRAY_SIZE(pnames), \
+ .flags = f, \
+ .offset = o, \
+ .shift = s, \
+ .width = w, \
+ .mux_flags = mf, \
+ .alias = a, \
+ }
+
+#define MUX(_id, cname, pnames, o, s, w) \
+ __MUX(_id, NULL, cname, pnames, o, s, w, 0, 0, NULL)
+
+#define MUX_A(_id, cname, pnames, o, s, w, a) \
+ __MUX(_id, NULL, cname, pnames, o, s, w, 0, 0, a)
+
+#define MUX_F(_id, cname, pnames, o, s, w, f, mf) \
+ __MUX(_id, NULL, cname, pnames, o, s, w, f, mf, NULL)
+
+/**
+ * @id: platform specific id of the clock.
+ * struct samsung_div_clock: information about div clock
+ * @dev_name: name of the device to which this clock belongs.
+ * @name: name of this div clock.
+ * @parent_name: name of the parent clock.
+ * @flags: optional flags for basic clock.
+ * @offset: offset of the register for configuring the div.
+ * @shift: starting bit location of the div control bit-field in @reg.
+ * @div_flags: flags for div-type clock.
+ * @alias: optional clock alias name to be assigned to this clock.
+ */
+struct samsung_div_clock {
+ unsigned int id;
+ const char *dev_name;
+ const char *name;
+ const char *parent_name;
+ unsigned long flags;
+ unsigned long offset;
+ u8 shift;
+ u8 width;
+ u8 div_flags;
+ const char *alias;
+ struct clk_div_table *table;
+};
+
+#define __DIV(_id, dname, cname, pname, o, s, w, f, df, a, t) \
+ { \
+ .id = _id, \
+ .dev_name = dname, \
+ .name = cname, \
+ .parent_name = pname, \
+ .flags = f, \
+ .offset = o, \
+ .shift = s, \
+ .width = w, \
+ .div_flags = df, \
+ .alias = a, \
+ .table = t, \
+ }
+
+#define DIV(_id, cname, pname, o, s, w) \
+ __DIV(_id, NULL, cname, pname, o, s, w, 0, 0, NULL, NULL)
+
+#define DIV_A(_id, cname, pname, o, s, w, a) \
+ __DIV(_id, NULL, cname, pname, o, s, w, 0, 0, a, NULL)
+
+#define DIV_F(_id, cname, pname, o, s, w, f, df) \
+ __DIV(_id, NULL, cname, pname, o, s, w, f, df, NULL, NULL)
+
+#define DIV_T(_id, cname, pname, o, s, w, t) \
+ __DIV(_id, NULL, cname, pname, o, s, w, 0, 0, NULL, t)
+
+/**
+ * struct samsung_gate_clock: information about gate clock
+ * @id: platform specific id of the clock.
+ * @dev_name: name of the device to which this clock belongs.
+ * @name: name of this gate clock.
+ * @parent_name: name of the parent clock.
+ * @flags: optional flags for basic clock.
+ * @offset: offset of the register for configuring the gate.
+ * @bit_idx: bit index of the gate control bit-field in @reg.
+ * @gate_flags: flags for gate-type clock.
+ * @alias: optional clock alias name to be assigned to this clock.
+ */
+struct samsung_gate_clock {
+ unsigned int id;
+ const char *dev_name;
+ const char *name;
+ const char *parent_name;
+ unsigned long flags;
+ unsigned long offset;
+ u8 bit_idx;
+ u8 gate_flags;
+ const char *alias;
+};
+
+#define __GATE(_id, dname, cname, pname, o, b, f, gf, a) \
+ { \
+ .id = _id, \
+ .dev_name = dname, \
+ .name = cname, \
+ .parent_name = pname, \
+ .flags = f, \
+ .offset = o, \
+ .bit_idx = b, \
+ .gate_flags = gf, \
+ .alias = a, \
+ }
+
+#define GATE(_id, cname, pname, o, b, f, gf) \
+ __GATE(_id, NULL, cname, pname, o, b, f, gf, NULL)
+
+#define GATE_A(_id, cname, pname, o, b, f, gf, a) \
+ __GATE(_id, NULL, cname, pname, o, b, f, gf, a)
+
+#define GATE_D(_id, dname, cname, pname, o, b, f, gf) \
+ __GATE(_id, dname, cname, pname, o, b, f, gf, NULL)
+
+#define GATE_DA(_id, dname, cname, pname, o, b, f, gf, a) \
+ __GATE(_id, dname, cname, pname, o, b, f, gf, a)
+
+#define PNAME(x) static const char *x[] __initdata
+
+/**
+ * struct samsung_clk_reg_dump: register dump of clock controller registers.
+ * @offset: clock register offset from the controller base address.
+ * @value: the value to be register at offset.
+ */
+struct samsung_clk_reg_dump {
+ u32 offset;
+ u32 value;
+};
+
+extern void __init samsung_clk_init(struct device_node *np, void __iomem *base,
+ unsigned long nr_clks, unsigned long *rdump,
+ unsigned long nr_rdump, unsigned long *soc_rdump,
+ unsigned long nr_soc_rdump);
+extern void __init samsung_clk_of_register_fixed_ext(
+ struct samsung_fixed_rate_clock *fixed_rate_clk,
+ unsigned int nr_fixed_rate_clk,
+ struct of_device_id *clk_matches);
+
+extern void samsung_clk_add_lookup(struct clk *clk, unsigned int id);
+
+extern void samsung_clk_register_alias(struct samsung_clock_alias *list,
+ unsigned int nr_clk);
+extern void __init samsung_clk_register_fixed_rate(
+ struct samsung_fixed_rate_clock *clk_list, unsigned int nr_clk);
+extern void __init samsung_clk_register_fixed_factor(
+ struct samsung_fixed_factor_clock *list, unsigned int nr_clk);
+extern void __init samsung_clk_register_mux(struct samsung_mux_clock *clk_list,
+ unsigned int nr_clk);
+extern void __init samsung_clk_register_div(struct samsung_div_clock *clk_list,
+ unsigned int nr_clk);
+extern void __init samsung_clk_register_gate(
+ struct samsung_gate_clock *clk_list, unsigned int nr_clk);
+
+extern unsigned long _get_rate(const char *clk_name);
+
+#endif /* __SAMSUNG_CLK_H */
diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile
index 2b41b0f4f731..f49fac2d193a 100644
--- a/drivers/clk/tegra/Makefile
+++ b/drivers/clk/tegra/Makefile
@@ -9,3 +9,4 @@ obj-y += clk-super.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra30.o
+obj-$(CONFIG_ARCH_TEGRA_114_SOC) += clk-tegra114.o
diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c
index 6dd533251e7b..bafee9895a24 100644
--- a/drivers/clk/tegra/clk-periph-gate.c
+++ b/drivers/clk/tegra/clk-periph-gate.c
@@ -41,7 +41,9 @@ static DEFINE_SPINLOCK(periph_ref_lock);
#define write_rst_clr(val, gate) \
writel_relaxed(val, gate->clk_base + (gate->regs->rst_clr_reg))
-#define periph_clk_to_bit(periph) (1 << (gate->clk_num % 32))
+#define periph_clk_to_bit(gate) (1 << (gate->clk_num % 32))
+
+#define LVL2_CLK_GATE_OVRE 0x554
/* Peripheral gate clock ops */
static int clk_periph_is_enabled(struct clk_hw *hw)
@@ -83,6 +85,13 @@ static int clk_periph_enable(struct clk_hw *hw)
}
}
+ if (gate->flags & TEGRA_PERIPH_WAR_1005168) {
+ writel_relaxed(0, gate->clk_base + LVL2_CLK_GATE_OVRE);
+ writel_relaxed(BIT(22), gate->clk_base + LVL2_CLK_GATE_OVRE);
+ udelay(1);
+ writel_relaxed(0, gate->clk_base + LVL2_CLK_GATE_OVRE);
+ }
+
spin_unlock_irqrestore(&periph_ref_lock, flags);
return 0;
diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c
index 788486e6331a..b2309d37a963 100644
--- a/drivers/clk/tegra/clk-periph.c
+++ b/drivers/clk/tegra/clk-periph.c
@@ -16,6 +16,7 @@
#include <linux/clk.h>
#include <linux/clk-provider.h>
+#include <linux/export.h>
#include <linux/slab.h>
#include <linux/err.h>
@@ -128,6 +129,7 @@ void tegra_periph_reset_deassert(struct clk *c)
tegra_periph_reset(gate, 0);
}
+EXPORT_SYMBOL(tegra_periph_reset_deassert);
void tegra_periph_reset_assert(struct clk *c)
{
@@ -147,6 +149,7 @@ void tegra_periph_reset_assert(struct clk *c)
tegra_periph_reset(gate, 1);
}
+EXPORT_SYMBOL(tegra_periph_reset_assert);
const struct clk_ops tegra_clk_periph_ops = {
.get_parent = clk_periph_get_parent,
@@ -170,14 +173,15 @@ const struct clk_ops tegra_clk_periph_nodiv_ops = {
static struct clk *_tegra_clk_register_periph(const char *name,
const char **parent_names, int num_parents,
struct tegra_clk_periph *periph,
- void __iomem *clk_base, u32 offset, bool div)
+ void __iomem *clk_base, u32 offset, bool div,
+ unsigned long flags)
{
struct clk *clk;
struct clk_init_data init;
init.name = name;
init.ops = div ? &tegra_clk_periph_ops : &tegra_clk_periph_nodiv_ops;
- init.flags = div ? 0 : CLK_SET_RATE_PARENT;
+ init.flags = flags;
init.parent_names = parent_names;
init.num_parents = num_parents;
@@ -202,10 +206,10 @@ static struct clk *_tegra_clk_register_periph(const char *name,
struct clk *tegra_clk_register_periph(const char *name,
const char **parent_names, int num_parents,
struct tegra_clk_periph *periph, void __iomem *clk_base,
- u32 offset)
+ u32 offset, unsigned long flags)
{
return _tegra_clk_register_periph(name, parent_names, num_parents,
- periph, clk_base, offset, true);
+ periph, clk_base, offset, true, flags);
}
struct clk *tegra_clk_register_periph_nodiv(const char *name,
@@ -214,5 +218,5 @@ struct clk *tegra_clk_register_periph_nodiv(const char *name,
u32 offset)
{
return _tegra_clk_register_periph(name, parent_names, num_parents,
- periph, clk_base, offset, false);
+ periph, clk_base, offset, false, CLK_SET_RATE_PARENT);
}
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 165f24734c1b..17c2cc086eb4 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2012, 2013, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -79,6 +79,48 @@
#define PLLE_SS_CTRL 0x68
#define PLLE_SS_DISABLE (7 << 10)
+#define PLLE_AUX_PLLP_SEL BIT(2)
+#define PLLE_AUX_ENABLE_SWCTL BIT(4)
+#define PLLE_AUX_SEQ_ENABLE BIT(24)
+#define PLLE_AUX_PLLRE_SEL BIT(28)
+
+#define PLLE_MISC_PLLE_PTS BIT(8)
+#define PLLE_MISC_IDDQ_SW_VALUE BIT(13)
+#define PLLE_MISC_IDDQ_SW_CTRL BIT(14)
+#define PLLE_MISC_VREG_BG_CTRL_SHIFT 4
+#define PLLE_MISC_VREG_BG_CTRL_MASK (3 << PLLE_MISC_VREG_BG_CTRL_SHIFT)
+#define PLLE_MISC_VREG_CTRL_SHIFT 2
+#define PLLE_MISC_VREG_CTRL_MASK (2 << PLLE_MISC_VREG_CTRL_SHIFT)
+
+#define PLLCX_MISC_STROBE BIT(31)
+#define PLLCX_MISC_RESET BIT(30)
+#define PLLCX_MISC_SDM_DIV_SHIFT 28
+#define PLLCX_MISC_SDM_DIV_MASK (0x3 << PLLCX_MISC_SDM_DIV_SHIFT)
+#define PLLCX_MISC_FILT_DIV_SHIFT 26
+#define PLLCX_MISC_FILT_DIV_MASK (0x3 << PLLCX_MISC_FILT_DIV_SHIFT)
+#define PLLCX_MISC_ALPHA_SHIFT 18
+#define PLLCX_MISC_DIV_LOW_RANGE \
+ ((0x1 << PLLCX_MISC_SDM_DIV_SHIFT) | \
+ (0x1 << PLLCX_MISC_FILT_DIV_SHIFT))
+#define PLLCX_MISC_DIV_HIGH_RANGE \
+ ((0x2 << PLLCX_MISC_SDM_DIV_SHIFT) | \
+ (0x2 << PLLCX_MISC_FILT_DIV_SHIFT))
+#define PLLCX_MISC_COEF_LOW_RANGE \
+ ((0x14 << PLLCX_MISC_KA_SHIFT) | (0x38 << PLLCX_MISC_KB_SHIFT))
+#define PLLCX_MISC_KA_SHIFT 2
+#define PLLCX_MISC_KB_SHIFT 9
+#define PLLCX_MISC_DEFAULT (PLLCX_MISC_COEF_LOW_RANGE | \
+ (0x19 << PLLCX_MISC_ALPHA_SHIFT) | \
+ PLLCX_MISC_DIV_LOW_RANGE | \
+ PLLCX_MISC_RESET)
+#define PLLCX_MISC1_DEFAULT 0x000d2308
+#define PLLCX_MISC2_DEFAULT 0x30211200
+#define PLLCX_MISC3_DEFAULT 0x200
+
+#define PMC_PLLM_WB0_OVERRIDE 0x1dc
+#define PMC_PLLM_WB0_OVERRIDE_2 0x2b0
+#define PMC_PLLM_WB0_OVERRIDE_2_DIVP_MASK BIT(27)
+
#define PMC_SATA_PWRGT 0x1ac
#define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE BIT(5)
#define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL BIT(4)
@@ -101,6 +143,24 @@
#define divn_max(p) (divn_mask(p))
#define divp_max(p) (1 << (divp_mask(p)))
+
+#ifdef CONFIG_ARCH_TEGRA_114_SOC
+/* PLLXC has 4-bit PDIV, but entry 15 is not allowed in h/w */
+#define PLLXC_PDIV_MAX 14
+
+/* non-monotonic mapping below is not a typo */
+static u8 pllxc_p[PLLXC_PDIV_MAX + 1] = {
+ /* PDIV: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 */
+ /* p: */ 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 12, 16, 20, 24, 32
+};
+
+#define PLLCX_PDIV_MAX 7
+static u8 pllcx_p[PLLCX_PDIV_MAX + 1] = {
+ /* PDIV: 0, 1, 2, 3, 4, 5, 6, 7 */
+ /* p: */ 1, 2, 3, 4, 6, 8, 12, 16
+};
+#endif
+
static void clk_pll_enable_lock(struct tegra_clk_pll *pll)
{
u32 val;
@@ -108,25 +168,36 @@ static void clk_pll_enable_lock(struct tegra_clk_pll *pll)
if (!(pll->flags & TEGRA_PLL_USE_LOCK))
return;
+ if (!(pll->flags & TEGRA_PLL_HAS_LOCK_ENABLE))
+ return;
+
val = pll_readl_misc(pll);
val |= BIT(pll->params->lock_enable_bit_idx);
pll_writel_misc(val, pll);
}
-static int clk_pll_wait_for_lock(struct tegra_clk_pll *pll,
- void __iomem *lock_addr, u32 lock_bit_idx)
+static int clk_pll_wait_for_lock(struct tegra_clk_pll *pll)
{
int i;
- u32 val;
+ u32 val, lock_mask;
+ void __iomem *lock_addr;
if (!(pll->flags & TEGRA_PLL_USE_LOCK)) {
udelay(pll->params->lock_delay);
return 0;
}
+ lock_addr = pll->clk_base;
+ if (pll->flags & TEGRA_PLL_LOCK_MISC)
+ lock_addr += pll->params->misc_reg;
+ else
+ lock_addr += pll->params->base_reg;
+
+ lock_mask = pll->params->lock_mask;
+
for (i = 0; i < pll->params->lock_delay; i++) {
val = readl_relaxed(lock_addr);
- if (val & BIT(lock_bit_idx)) {
+ if ((val & lock_mask) == lock_mask) {
udelay(PLL_POST_LOCK_DELAY);
return 0;
}
@@ -155,7 +226,7 @@ static int clk_pll_is_enabled(struct clk_hw *hw)
return val & PLL_BASE_ENABLE ? 1 : 0;
}
-static int _clk_pll_enable(struct clk_hw *hw)
+static void _clk_pll_enable(struct clk_hw *hw)
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
u32 val;
@@ -163,7 +234,8 @@ static int _clk_pll_enable(struct clk_hw *hw)
clk_pll_enable_lock(pll);
val = pll_readl_base(pll);
- val &= ~PLL_BASE_BYPASS;
+ if (pll->flags & TEGRA_PLL_BYPASS)
+ val &= ~PLL_BASE_BYPASS;
val |= PLL_BASE_ENABLE;
pll_writel_base(val, pll);
@@ -172,11 +244,6 @@ static int _clk_pll_enable(struct clk_hw *hw)
val |= PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE);
}
-
- clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->base_reg,
- pll->params->lock_bit_idx);
-
- return 0;
}
static void _clk_pll_disable(struct clk_hw *hw)
@@ -185,7 +252,9 @@ static void _clk_pll_disable(struct clk_hw *hw)
u32 val;
val = pll_readl_base(pll);
- val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
+ if (pll->flags & TEGRA_PLL_BYPASS)
+ val &= ~PLL_BASE_BYPASS;
+ val &= ~PLL_BASE_ENABLE;
pll_writel_base(val, pll);
if (pll->flags & TEGRA_PLLM) {
@@ -204,7 +273,9 @@ static int clk_pll_enable(struct clk_hw *hw)
if (pll->lock)
spin_lock_irqsave(pll->lock, flags);
- ret = _clk_pll_enable(hw);
+ _clk_pll_enable(hw);
+
+ ret = clk_pll_wait_for_lock(pll);
if (pll->lock)
spin_unlock_irqrestore(pll->lock, flags);
@@ -241,8 +312,6 @@ static int _get_table_rate(struct clk_hw *hw,
if (sel->input_rate == 0)
return -EINVAL;
- BUG_ON(sel->p < 1);
-
cfg->input_rate = sel->input_rate;
cfg->output_rate = sel->output_rate;
cfg->m = sel->m;
@@ -257,6 +326,7 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
unsigned long rate, unsigned long parent_rate)
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
+ struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
unsigned long cfreq;
u32 p_div = 0;
@@ -290,88 +360,119 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
cfg->output_rate <<= 1)
p_div++;
- cfg->p = 1 << p_div;
cfg->m = parent_rate / cfreq;
cfg->n = cfg->output_rate / cfreq;
cfg->cpcon = OUT_OF_TABLE_CPCON;
if (cfg->m > divm_max(pll) || cfg->n > divn_max(pll) ||
- cfg->p > divp_max(pll) || cfg->output_rate > pll->params->vco_max) {
+ (1 << p_div) > divp_max(pll)
+ || cfg->output_rate > pll->params->vco_max) {
pr_err("%s: Failed to set %s rate %lu\n",
__func__, __clk_get_name(hw->clk), rate);
return -EINVAL;
}
+ if (p_tohw) {
+ p_div = 1 << p_div;
+ while (p_tohw->pdiv) {
+ if (p_div <= p_tohw->pdiv) {
+ cfg->p = p_tohw->hw_val;
+ break;
+ }
+ p_tohw++;
+ }
+ if (!p_tohw->pdiv)
+ return -EINVAL;
+ } else
+ cfg->p = p_div;
+
return 0;
}
-static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
- unsigned long rate)
+static void _update_pll_mnp(struct tegra_clk_pll *pll,
+ struct tegra_clk_pll_freq_table *cfg)
{
- struct tegra_clk_pll *pll = to_clk_pll(hw);
- unsigned long flags = 0;
- u32 divp, val, old_base;
- int state;
-
- divp = __ffs(cfg->p);
-
- if (pll->flags & TEGRA_PLLU)
- divp ^= 1;
+ u32 val;
- if (pll->lock)
- spin_lock_irqsave(pll->lock, flags);
+ val = pll_readl_base(pll);
- old_base = val = pll_readl_base(pll);
val &= ~((divm_mask(pll) << pll->divm_shift) |
(divn_mask(pll) << pll->divn_shift) |
(divp_mask(pll) << pll->divp_shift));
val |= ((cfg->m << pll->divm_shift) |
(cfg->n << pll->divn_shift) |
- (divp << pll->divp_shift));
- if (val == old_base) {
- if (pll->lock)
- spin_unlock_irqrestore(pll->lock, flags);
- return 0;
+ (cfg->p << pll->divp_shift));
+
+ pll_writel_base(val, pll);
+}
+
+static void _get_pll_mnp(struct tegra_clk_pll *pll,
+ struct tegra_clk_pll_freq_table *cfg)
+{
+ u32 val;
+
+ val = pll_readl_base(pll);
+
+ cfg->m = (val >> pll->divm_shift) & (divm_mask(pll));
+ cfg->n = (val >> pll->divn_shift) & (divn_mask(pll));
+ cfg->p = (val >> pll->divp_shift) & (divp_mask(pll));
+}
+
+static void _update_pll_cpcon(struct tegra_clk_pll *pll,
+ struct tegra_clk_pll_freq_table *cfg,
+ unsigned long rate)
+{
+ u32 val;
+
+ val = pll_readl_misc(pll);
+
+ val &= ~(PLL_MISC_CPCON_MASK << PLL_MISC_CPCON_SHIFT);
+ val |= cfg->cpcon << PLL_MISC_CPCON_SHIFT;
+
+ if (pll->flags & TEGRA_PLL_SET_LFCON) {
+ val &= ~(PLL_MISC_LFCON_MASK << PLL_MISC_LFCON_SHIFT);
+ if (cfg->n >= PLLDU_LFCON_SET_DIVN)
+ val |= 1 << PLL_MISC_LFCON_SHIFT;
+ } else if (pll->flags & TEGRA_PLL_SET_DCCON) {
+ val &= ~(1 << PLL_MISC_DCCON_SHIFT);
+ if (rate >= (pll->params->vco_max >> 1))
+ val |= 1 << PLL_MISC_DCCON_SHIFT;
}
+ pll_writel_misc(val, pll);
+}
+
+static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
+ unsigned long rate)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ int state, ret = 0;
+
state = clk_pll_is_enabled(hw);
- if (state) {
+ if (state)
_clk_pll_disable(hw);
- val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
- }
- pll_writel_base(val, pll);
- if (pll->flags & TEGRA_PLL_HAS_CPCON) {
- val = pll_readl_misc(pll);
- val &= ~(PLL_MISC_CPCON_MASK << PLL_MISC_CPCON_SHIFT);
- val |= cfg->cpcon << PLL_MISC_CPCON_SHIFT;
- if (pll->flags & TEGRA_PLL_SET_LFCON) {
- val &= ~(PLL_MISC_LFCON_MASK << PLL_MISC_LFCON_SHIFT);
- if (cfg->n >= PLLDU_LFCON_SET_DIVN)
- val |= 0x1 << PLL_MISC_LFCON_SHIFT;
- } else if (pll->flags & TEGRA_PLL_SET_DCCON) {
- val &= ~(0x1 << PLL_MISC_DCCON_SHIFT);
- if (rate >= (pll->params->vco_max >> 1))
- val |= 0x1 << PLL_MISC_DCCON_SHIFT;
- }
- pll_writel_misc(val, pll);
- }
+ _update_pll_mnp(pll, cfg);
- if (pll->lock)
- spin_unlock_irqrestore(pll->lock, flags);
+ if (pll->flags & TEGRA_PLL_HAS_CPCON)
+ _update_pll_cpcon(pll, cfg, rate);
- if (state)
- clk_pll_enable(hw);
+ if (state) {
+ _clk_pll_enable(hw);
+ ret = clk_pll_wait_for_lock(pll);
+ }
- return 0;
+ return ret;
}
static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
- struct tegra_clk_pll_freq_table cfg;
+ struct tegra_clk_pll_freq_table cfg, old_cfg;
+ unsigned long flags = 0;
+ int ret = 0;
if (pll->flags & TEGRA_PLL_FIXED) {
if (rate != pll->fixed_rate) {
@@ -387,7 +488,18 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
_calc_rate(hw, &cfg, rate, parent_rate))
return -EINVAL;
- return _program_pll(hw, &cfg, rate);
+ if (pll->lock)
+ spin_lock_irqsave(pll->lock, flags);
+
+ _get_pll_mnp(pll, &old_cfg);
+
+ if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_cfg.p != cfg.p)
+ ret = _program_pll(hw, &cfg, rate);
+
+ if (pll->lock)
+ spin_unlock_irqrestore(pll->lock, flags);
+
+ return ret;
}
static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
@@ -409,7 +521,7 @@ static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
return -EINVAL;
output_rate *= cfg.n;
- do_div(output_rate, cfg.m * cfg.p);
+ do_div(output_rate, cfg.m * (1 << cfg.p));
return output_rate;
}
@@ -418,11 +530,15 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
- u32 val = pll_readl_base(pll);
- u32 divn = 0, divm = 0, divp = 0;
+ struct tegra_clk_pll_freq_table cfg;
+ struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
+ u32 val;
u64 rate = parent_rate;
+ int pdiv;
+
+ val = pll_readl_base(pll);
- if (val & PLL_BASE_BYPASS)
+ if ((pll->flags & TEGRA_PLL_BYPASS) && (val & PLL_BASE_BYPASS))
return parent_rate;
if ((pll->flags & TEGRA_PLL_FIXED) && !(val & PLL_BASE_OVERRIDE)) {
@@ -435,16 +551,29 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
return pll->fixed_rate;
}
- divp = (val >> pll->divp_shift) & (divp_mask(pll));
- if (pll->flags & TEGRA_PLLU)
- divp ^= 1;
+ _get_pll_mnp(pll, &cfg);
- divn = (val >> pll->divn_shift) & (divn_mask(pll));
- divm = (val >> pll->divm_shift) & (divm_mask(pll));
- divm *= (1 << divp);
+ if (p_tohw) {
+ while (p_tohw->pdiv) {
+ if (cfg.p == p_tohw->hw_val) {
+ pdiv = p_tohw->pdiv;
+ break;
+ }
+ p_tohw++;
+ }
+
+ if (!p_tohw->pdiv) {
+ WARN_ON(1);
+ pdiv = 1;
+ }
+ } else
+ pdiv = 1 << cfg.p;
+
+ cfg.m *= pdiv;
+
+ rate *= cfg.n;
+ do_div(rate, cfg.m);
- rate *= divn;
- do_div(rate, divm);
return rate;
}
@@ -538,8 +667,8 @@ static int clk_plle_enable(struct clk_hw *hw)
val |= (PLL_BASE_BYPASS | PLL_BASE_ENABLE);
pll_writel_base(val, pll);
- clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->misc_reg,
- pll->params->lock_bit_idx);
+ clk_pll_wait_for_lock(pll);
+
return 0;
}
@@ -577,28 +706,531 @@ const struct clk_ops tegra_clk_plle_ops = {
.enable = clk_plle_enable,
};
-static struct clk *_tegra_clk_register_pll(const char *name,
- const char *parent_name, void __iomem *clk_base,
- void __iomem *pmc, unsigned long flags,
- unsigned long fixed_rate,
- struct tegra_clk_pll_params *pll_params, u8 pll_flags,
- struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock,
- const struct clk_ops *ops)
+#ifdef CONFIG_ARCH_TEGRA_114_SOC
+
+static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params,
+ unsigned long parent_rate)
+{
+ if (parent_rate > pll_params->cf_max)
+ return 2;
+ else
+ return 1;
+}
+
+static int clk_pll_iddq_enable(struct clk_hw *hw)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ unsigned long flags = 0;
+
+ u32 val;
+ int ret;
+
+ if (pll->lock)
+ spin_lock_irqsave(pll->lock, flags);
+
+ val = pll_readl(pll->params->iddq_reg, pll);
+ val &= ~BIT(pll->params->iddq_bit_idx);
+ pll_writel(val, pll->params->iddq_reg, pll);
+ udelay(2);
+
+ _clk_pll_enable(hw);
+
+ ret = clk_pll_wait_for_lock(pll);
+
+ if (pll->lock)
+ spin_unlock_irqrestore(pll->lock, flags);
+
+ return 0;
+}
+
+static void clk_pll_iddq_disable(struct clk_hw *hw)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ unsigned long flags = 0;
+ u32 val;
+
+ if (pll->lock)
+ spin_lock_irqsave(pll->lock, flags);
+
+ _clk_pll_disable(hw);
+
+ val = pll_readl(pll->params->iddq_reg, pll);
+ val |= BIT(pll->params->iddq_bit_idx);
+ pll_writel(val, pll->params->iddq_reg, pll);
+ udelay(2);
+
+ if (pll->lock)
+ spin_unlock_irqrestore(pll->lock, flags);
+}
+
+static int _calc_dynamic_ramp_rate(struct clk_hw *hw,
+ struct tegra_clk_pll_freq_table *cfg,
+ unsigned long rate, unsigned long parent_rate)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ unsigned int p;
+
+ if (!rate)
+ return -EINVAL;
+
+ p = DIV_ROUND_UP(pll->params->vco_min, rate);
+ cfg->m = _pll_fixed_mdiv(pll->params, parent_rate);
+ cfg->p = p;
+ cfg->output_rate = rate * cfg->p;
+ cfg->n = cfg->output_rate * cfg->m / parent_rate;
+
+ if (cfg->n > divn_max(pll) || cfg->output_rate > pll->params->vco_max)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int _pll_ramp_calc_pll(struct clk_hw *hw,
+ struct tegra_clk_pll_freq_table *cfg,
+ unsigned long rate, unsigned long parent_rate)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ int err = 0;
+
+ err = _get_table_rate(hw, cfg, rate, parent_rate);
+ if (err < 0)
+ err = _calc_dynamic_ramp_rate(hw, cfg, rate, parent_rate);
+ else if (cfg->m != _pll_fixed_mdiv(pll->params, parent_rate)) {
+ WARN_ON(1);
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (!cfg->p || (cfg->p > pll->params->max_p))
+ err = -EINVAL;
+
+out:
+ return err;
+}
+
+static int clk_pllxc_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ struct tegra_clk_pll_freq_table cfg, old_cfg;
+ unsigned long flags = 0;
+ int ret = 0;
+ u8 old_p;
+
+ ret = _pll_ramp_calc_pll(hw, &cfg, rate, parent_rate);
+ if (ret < 0)
+ return ret;
+
+ if (pll->lock)
+ spin_lock_irqsave(pll->lock, flags);
+
+ _get_pll_mnp(pll, &old_cfg);
+
+ old_p = pllxc_p[old_cfg.p];
+ if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_p != cfg.p) {
+ cfg.p -= 1;
+ ret = _program_pll(hw, &cfg, rate);
+ }
+
+ if (pll->lock)
+ spin_unlock_irqrestore(pll->lock, flags);
+
+ return ret;
+}
+
+static long clk_pll_ramp_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct tegra_clk_pll_freq_table cfg;
+ int ret = 0;
+ u64 output_rate = *prate;
+
+ ret = _pll_ramp_calc_pll(hw, &cfg, rate, *prate);
+ if (ret < 0)
+ return ret;
+
+ output_rate *= cfg.n;
+ do_div(output_rate, cfg.m * cfg.p);
+
+ return output_rate;
+}
+
+static int clk_pllm_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct tegra_clk_pll_freq_table cfg;
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ unsigned long flags = 0;
+ int state, ret = 0;
+ u32 val;
+
+ if (pll->lock)
+ spin_lock_irqsave(pll->lock, flags);
+
+ state = clk_pll_is_enabled(hw);
+ if (state) {
+ if (rate != clk_get_rate(hw->clk)) {
+ pr_err("%s: Cannot change active PLLM\n", __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+ goto out;
+ }
+
+ ret = _pll_ramp_calc_pll(hw, &cfg, rate, parent_rate);
+ if (ret < 0)
+ goto out;
+
+ cfg.p -= 1;
+
+ val = readl_relaxed(pll->pmc + PMC_PLLM_WB0_OVERRIDE);
+ if (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE) {
+ val = readl_relaxed(pll->pmc + PMC_PLLM_WB0_OVERRIDE_2);
+ val = cfg.p ? (val | PMC_PLLM_WB0_OVERRIDE_2_DIVP_MASK) :
+ (val & ~PMC_PLLM_WB0_OVERRIDE_2_DIVP_MASK);
+ writel_relaxed(val, pll->pmc + PMC_PLLM_WB0_OVERRIDE_2);
+
+ val = readl_relaxed(pll->pmc + PMC_PLLM_WB0_OVERRIDE);
+ val &= ~(divn_mask(pll) | divm_mask(pll));
+ val |= (cfg.m << pll->divm_shift) | (cfg.n << pll->divn_shift);
+ writel_relaxed(val, pll->pmc + PMC_PLLM_WB0_OVERRIDE);
+ } else
+ _update_pll_mnp(pll, &cfg);
+
+
+out:
+ if (pll->lock)
+ spin_unlock_irqrestore(pll->lock, flags);
+
+ return ret;
+}
+
+static void _pllcx_strobe(struct tegra_clk_pll *pll)
+{
+ u32 val;
+
+ val = pll_readl_misc(pll);
+ val |= PLLCX_MISC_STROBE;
+ pll_writel_misc(val, pll);
+ udelay(2);
+
+ val &= ~PLLCX_MISC_STROBE;
+ pll_writel_misc(val, pll);
+}
+
+static int clk_pllc_enable(struct clk_hw *hw)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ u32 val;
+ int ret = 0;
+ unsigned long flags = 0;
+
+ if (pll->lock)
+ spin_lock_irqsave(pll->lock, flags);
+
+ _clk_pll_enable(hw);
+ udelay(2);
+
+ val = pll_readl_misc(pll);
+ val &= ~PLLCX_MISC_RESET;
+ pll_writel_misc(val, pll);
+ udelay(2);
+
+ _pllcx_strobe(pll);
+
+ ret = clk_pll_wait_for_lock(pll);
+
+ if (pll->lock)
+ spin_unlock_irqrestore(pll->lock, flags);
+
+ return ret;
+}
+
+static void _clk_pllc_disable(struct clk_hw *hw)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ u32 val;
+
+ _clk_pll_disable(hw);
+
+ val = pll_readl_misc(pll);
+ val |= PLLCX_MISC_RESET;
+ pll_writel_misc(val, pll);
+ udelay(2);
+}
+
+static void clk_pllc_disable(struct clk_hw *hw)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ unsigned long flags = 0;
+
+ if (pll->lock)
+ spin_lock_irqsave(pll->lock, flags);
+
+ _clk_pllc_disable(hw);
+
+ if (pll->lock)
+ spin_unlock_irqrestore(pll->lock, flags);
+}
+
+static int _pllcx_update_dynamic_coef(struct tegra_clk_pll *pll,
+ unsigned long input_rate, u32 n)
+{
+ u32 val, n_threshold;
+
+ switch (input_rate) {
+ case 12000000:
+ n_threshold = 70;
+ break;
+ case 13000000:
+ case 26000000:
+ n_threshold = 71;
+ break;
+ case 16800000:
+ n_threshold = 55;
+ break;
+ case 19200000:
+ n_threshold = 48;
+ break;
+ default:
+ pr_err("%s: Unexpected reference rate %lu\n",
+ __func__, input_rate);
+ return -EINVAL;
+ }
+
+ val = pll_readl_misc(pll);
+ val &= ~(PLLCX_MISC_SDM_DIV_MASK | PLLCX_MISC_FILT_DIV_MASK);
+ val |= n <= n_threshold ?
+ PLLCX_MISC_DIV_LOW_RANGE : PLLCX_MISC_DIV_HIGH_RANGE;
+ pll_writel_misc(val, pll);
+
+ return 0;
+}
+
+static int clk_pllc_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct tegra_clk_pll_freq_table cfg;
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ unsigned long flags = 0;
+ int state, ret = 0;
+ u32 val;
+ u16 old_m, old_n;
+ u8 old_p;
+
+ if (pll->lock)
+ spin_lock_irqsave(pll->lock, flags);
+
+ ret = _pll_ramp_calc_pll(hw, &cfg, rate, parent_rate);
+ if (ret < 0)
+ goto out;
+
+ val = pll_readl_base(pll);
+ old_m = (val >> pll->divm_shift) & (divm_mask(pll));
+ old_n = (val >> pll->divn_shift) & (divn_mask(pll));
+ old_p = pllcx_p[(val >> pll->divp_shift) & (divp_mask(pll))];
+
+ if (cfg.m != old_m) {
+ WARN_ON(1);
+ goto out;
+ }
+
+ if (old_n == cfg.n && old_p == cfg.p)
+ goto out;
+
+ cfg.p -= 1;
+
+ state = clk_pll_is_enabled(hw);
+ if (state)
+ _clk_pllc_disable(hw);
+
+ ret = _pllcx_update_dynamic_coef(pll, parent_rate, cfg.n);
+ if (ret < 0)
+ goto out;
+
+ _update_pll_mnp(pll, &cfg);
+
+ if (state)
+ ret = clk_pllc_enable(hw);
+
+out:
+ if (pll->lock)
+ spin_unlock_irqrestore(pll->lock, flags);
+
+ return ret;
+}
+
+static long _pllre_calc_rate(struct tegra_clk_pll *pll,
+ struct tegra_clk_pll_freq_table *cfg,
+ unsigned long rate, unsigned long parent_rate)
+{
+ u16 m, n;
+ u64 output_rate = parent_rate;
+
+ m = _pll_fixed_mdiv(pll->params, parent_rate);
+ n = rate * m / parent_rate;
+
+ output_rate *= n;
+ do_div(output_rate, m);
+
+ if (cfg) {
+ cfg->m = m;
+ cfg->n = n;
+ }
+
+ return output_rate;
+}
+static int clk_pllre_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct tegra_clk_pll_freq_table cfg, old_cfg;
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ unsigned long flags = 0;
+ int state, ret = 0;
+
+ if (pll->lock)
+ spin_lock_irqsave(pll->lock, flags);
+
+ _pllre_calc_rate(pll, &cfg, rate, parent_rate);
+ _get_pll_mnp(pll, &old_cfg);
+ cfg.p = old_cfg.p;
+
+ if (cfg.m != old_cfg.m || cfg.n != old_cfg.n) {
+ state = clk_pll_is_enabled(hw);
+ if (state)
+ _clk_pll_disable(hw);
+
+ _update_pll_mnp(pll, &cfg);
+
+ if (state) {
+ _clk_pll_enable(hw);
+ ret = clk_pll_wait_for_lock(pll);
+ }
+ }
+
+ if (pll->lock)
+ spin_unlock_irqrestore(pll->lock, flags);
+
+ return ret;
+}
+
+static unsigned long clk_pllre_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct tegra_clk_pll_freq_table cfg;
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ u64 rate = parent_rate;
+
+ _get_pll_mnp(pll, &cfg);
+
+ rate *= cfg.n;
+ do_div(rate, cfg.m);
+
+ return rate;
+}
+
+static long clk_pllre_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+
+ return _pllre_calc_rate(pll, NULL, rate, *prate);
+}
+
+static int clk_plle_tegra114_enable(struct clk_hw *hw)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ struct tegra_clk_pll_freq_table sel;
+ u32 val;
+ int ret;
+ unsigned long flags = 0;
+ unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk));
+
+ if (_get_table_rate(hw, &sel, pll->fixed_rate, input_rate))
+ return -EINVAL;
+
+ if (pll->lock)
+ spin_lock_irqsave(pll->lock, flags);
+
+ val = pll_readl_base(pll);
+ val &= ~BIT(29); /* Disable lock override */
+ pll_writel_base(val, pll);
+
+ val = pll_readl(pll->params->aux_reg, pll);
+ val |= PLLE_AUX_ENABLE_SWCTL;
+ val &= ~PLLE_AUX_SEQ_ENABLE;
+ pll_writel(val, pll->params->aux_reg, pll);
+ udelay(1);
+
+ val = pll_readl_misc(pll);
+ val |= PLLE_MISC_LOCK_ENABLE;
+ val |= PLLE_MISC_IDDQ_SW_CTRL;
+ val &= ~PLLE_MISC_IDDQ_SW_VALUE;
+ val |= PLLE_MISC_PLLE_PTS;
+ val |= PLLE_MISC_VREG_BG_CTRL_MASK | PLLE_MISC_VREG_CTRL_MASK;
+ pll_writel_misc(val, pll);
+ udelay(5);
+
+ val = pll_readl(PLLE_SS_CTRL, pll);
+ val |= PLLE_SS_DISABLE;
+ pll_writel(val, PLLE_SS_CTRL, pll);
+
+ val = pll_readl_base(pll);
+ val &= ~(divm_mask(pll) | divn_mask(pll) | divp_mask(pll));
+ val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT);
+ val |= sel.m << pll->divm_shift;
+ val |= sel.n << pll->divn_shift;
+ val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT;
+ pll_writel_base(val, pll);
+ udelay(1);
+
+ _clk_pll_enable(hw);
+ ret = clk_pll_wait_for_lock(pll);
+
+ if (ret < 0)
+ goto out;
+
+ /* TODO: enable hw control of xusb brick pll */
+
+out:
+ if (pll->lock)
+ spin_unlock_irqrestore(pll->lock, flags);
+
+ return ret;
+}
+
+static void clk_plle_tegra114_disable(struct clk_hw *hw)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ unsigned long flags = 0;
+ u32 val;
+
+ if (pll->lock)
+ spin_lock_irqsave(pll->lock, flags);
+
+ _clk_pll_disable(hw);
+
+ val = pll_readl_misc(pll);
+ val |= PLLE_MISC_IDDQ_SW_CTRL | PLLE_MISC_IDDQ_SW_VALUE;
+ pll_writel_misc(val, pll);
+ udelay(1);
+
+ if (pll->lock)
+ spin_unlock_irqrestore(pll->lock, flags);
+}
+#endif
+
+static struct tegra_clk_pll *_tegra_init_pll(void __iomem *clk_base,
+ void __iomem *pmc, unsigned long fixed_rate,
+ struct tegra_clk_pll_params *pll_params, u32 pll_flags,
+ struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock)
{
struct tegra_clk_pll *pll;
- struct clk *clk;
- struct clk_init_data init;
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
if (!pll)
return ERR_PTR(-ENOMEM);
- init.name = name;
- init.ops = ops;
- init.flags = flags;
- init.parent_names = (parent_name ? &parent_name : NULL);
- init.num_parents = (parent_name ? 1 : 0);
-
pll->clk_base = clk_base;
pll->pmc = pmc;
@@ -615,34 +1247,336 @@ static struct clk *_tegra_clk_register_pll(const char *name,
pll->divm_shift = PLL_BASE_DIVM_SHIFT;
pll->divm_width = PLL_BASE_DIVM_WIDTH;
+ return pll;
+}
+
+static struct clk *_tegra_clk_register_pll(struct tegra_clk_pll *pll,
+ const char *name, const char *parent_name, unsigned long flags,
+ const struct clk_ops *ops)
+{
+ struct clk_init_data init;
+
+ init.name = name;
+ init.ops = ops;
+ init.flags = flags;
+ init.parent_names = (parent_name ? &parent_name : NULL);
+ init.num_parents = (parent_name ? 1 : 0);
+
/* Data in .init is copied by clk_register(), so stack variable OK */
pll->hw.init = &init;
- clk = clk_register(NULL, &pll->hw);
- if (IS_ERR(clk))
- kfree(pll);
-
- return clk;
+ return clk_register(NULL, &pll->hw);
}
struct clk *tegra_clk_register_pll(const char *name, const char *parent_name,
void __iomem *clk_base, void __iomem *pmc,
unsigned long flags, unsigned long fixed_rate,
- struct tegra_clk_pll_params *pll_params, u8 pll_flags,
+ struct tegra_clk_pll_params *pll_params, u32 pll_flags,
struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock)
{
- return _tegra_clk_register_pll(name, parent_name, clk_base, pmc,
- flags, fixed_rate, pll_params, pll_flags, freq_table,
- lock, &tegra_clk_pll_ops);
+ struct tegra_clk_pll *pll;
+ struct clk *clk;
+
+ pll_flags |= TEGRA_PLL_BYPASS;
+ pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
+ pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags,
+ freq_table, lock);
+ if (IS_ERR(pll))
+ return ERR_CAST(pll);
+
+ clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+ &tegra_clk_pll_ops);
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
}
struct clk *tegra_clk_register_plle(const char *name, const char *parent_name,
void __iomem *clk_base, void __iomem *pmc,
unsigned long flags, unsigned long fixed_rate,
- struct tegra_clk_pll_params *pll_params, u8 pll_flags,
+ struct tegra_clk_pll_params *pll_params, u32 pll_flags,
struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock)
{
- return _tegra_clk_register_pll(name, parent_name, clk_base, pmc,
- flags, fixed_rate, pll_params, pll_flags, freq_table,
- lock, &tegra_clk_plle_ops);
+ struct tegra_clk_pll *pll;
+ struct clk *clk;
+
+ pll_flags |= TEGRA_PLL_LOCK_MISC | TEGRA_PLL_BYPASS;
+ pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
+ pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags,
+ freq_table, lock);
+ if (IS_ERR(pll))
+ return ERR_CAST(pll);
+
+ clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+ &tegra_clk_plle_ops);
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
+}
+
+#ifdef CONFIG_ARCH_TEGRA_114_SOC
+const struct clk_ops tegra_clk_pllxc_ops = {
+ .is_enabled = clk_pll_is_enabled,
+ .enable = clk_pll_iddq_enable,
+ .disable = clk_pll_iddq_disable,
+ .recalc_rate = clk_pll_recalc_rate,
+ .round_rate = clk_pll_ramp_round_rate,
+ .set_rate = clk_pllxc_set_rate,
+};
+
+const struct clk_ops tegra_clk_pllm_ops = {
+ .is_enabled = clk_pll_is_enabled,
+ .enable = clk_pll_iddq_enable,
+ .disable = clk_pll_iddq_disable,
+ .recalc_rate = clk_pll_recalc_rate,
+ .round_rate = clk_pll_ramp_round_rate,
+ .set_rate = clk_pllm_set_rate,
+};
+
+const struct clk_ops tegra_clk_pllc_ops = {
+ .is_enabled = clk_pll_is_enabled,
+ .enable = clk_pllc_enable,
+ .disable = clk_pllc_disable,
+ .recalc_rate = clk_pll_recalc_rate,
+ .round_rate = clk_pll_ramp_round_rate,
+ .set_rate = clk_pllc_set_rate,
+};
+
+const struct clk_ops tegra_clk_pllre_ops = {
+ .is_enabled = clk_pll_is_enabled,
+ .enable = clk_pll_iddq_enable,
+ .disable = clk_pll_iddq_disable,
+ .recalc_rate = clk_pllre_recalc_rate,
+ .round_rate = clk_pllre_round_rate,
+ .set_rate = clk_pllre_set_rate,
+};
+
+const struct clk_ops tegra_clk_plle_tegra114_ops = {
+ .is_enabled = clk_pll_is_enabled,
+ .enable = clk_plle_tegra114_enable,
+ .disable = clk_plle_tegra114_disable,
+ .recalc_rate = clk_pll_recalc_rate,
+};
+
+
+struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name,
+ void __iomem *clk_base, void __iomem *pmc,
+ unsigned long flags, unsigned long fixed_rate,
+ struct tegra_clk_pll_params *pll_params,
+ u32 pll_flags,
+ struct tegra_clk_pll_freq_table *freq_table,
+ spinlock_t *lock)
+{
+ struct tegra_clk_pll *pll;
+ struct clk *clk;
+
+ if (!pll_params->pdiv_tohw)
+ return ERR_PTR(-EINVAL);
+
+ pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
+ pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags,
+ freq_table, lock);
+ if (IS_ERR(pll))
+ return ERR_CAST(pll);
+
+ clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+ &tegra_clk_pllxc_ops);
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
+}
+
+struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name,
+ void __iomem *clk_base, void __iomem *pmc,
+ unsigned long flags, unsigned long fixed_rate,
+ struct tegra_clk_pll_params *pll_params,
+ u32 pll_flags,
+ struct tegra_clk_pll_freq_table *freq_table,
+ spinlock_t *lock, unsigned long parent_rate)
+{
+ u32 val;
+ struct tegra_clk_pll *pll;
+ struct clk *clk;
+
+ pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
+ pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags,
+ freq_table, lock);
+ if (IS_ERR(pll))
+ return ERR_CAST(pll);
+
+ /* program minimum rate by default */
+
+ val = pll_readl_base(pll);
+ if (val & PLL_BASE_ENABLE)
+ WARN_ON(val & pll_params->iddq_bit_idx);
+ else {
+ int m;
+
+ m = _pll_fixed_mdiv(pll_params, parent_rate);
+ val = m << PLL_BASE_DIVM_SHIFT;
+ val |= (pll_params->vco_min / parent_rate)
+ << PLL_BASE_DIVN_SHIFT;
+ pll_writel_base(val, pll);
+ }
+
+ /* disable lock override */
+
+ val = pll_readl_misc(pll);
+ val &= ~BIT(29);
+ pll_writel_misc(val, pll);
+
+ pll_flags |= TEGRA_PLL_LOCK_MISC;
+ clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+ &tegra_clk_pllre_ops);
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
+}
+
+struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name,
+ void __iomem *clk_base, void __iomem *pmc,
+ unsigned long flags, unsigned long fixed_rate,
+ struct tegra_clk_pll_params *pll_params,
+ u32 pll_flags,
+ struct tegra_clk_pll_freq_table *freq_table,
+ spinlock_t *lock)
+{
+ struct tegra_clk_pll *pll;
+ struct clk *clk;
+
+ if (!pll_params->pdiv_tohw)
+ return ERR_PTR(-EINVAL);
+
+ pll_flags |= TEGRA_PLL_BYPASS;
+ pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
+ pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags,
+ freq_table, lock);
+ if (IS_ERR(pll))
+ return ERR_CAST(pll);
+
+ clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+ &tegra_clk_pllm_ops);
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
+}
+
+struct clk *tegra_clk_register_pllc(const char *name, const char *parent_name,
+ void __iomem *clk_base, void __iomem *pmc,
+ unsigned long flags, unsigned long fixed_rate,
+ struct tegra_clk_pll_params *pll_params,
+ u32 pll_flags,
+ struct tegra_clk_pll_freq_table *freq_table,
+ spinlock_t *lock)
+{
+ struct clk *parent, *clk;
+ struct pdiv_map *p_tohw = pll_params->pdiv_tohw;
+ struct tegra_clk_pll *pll;
+ struct tegra_clk_pll_freq_table cfg;
+ unsigned long parent_rate;
+
+ if (!p_tohw)
+ return ERR_PTR(-EINVAL);
+
+ parent = __clk_lookup(parent_name);
+ if (IS_ERR(parent)) {
+ WARN(1, "parent clk %s of %s must be registered first\n",
+ name, parent_name);
+ return ERR_PTR(-EINVAL);
+ }
+
+ pll_flags |= TEGRA_PLL_BYPASS;
+ pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags,
+ freq_table, lock);
+ if (IS_ERR(pll))
+ return ERR_CAST(pll);
+
+ parent_rate = __clk_get_rate(parent);
+
+ /*
+ * Most of PLLC register fields are shadowed, and can not be read
+ * directly from PLL h/w. Hence, actual PLLC boot state is unknown.
+ * Initialize PLL to default state: disabled, reset; shadow registers
+ * loaded with default parameters; dividers are preset for half of
+ * minimum VCO rate (the latter assured that shadowed divider settings
+ * are within supported range).
+ */
+
+ cfg.m = _pll_fixed_mdiv(pll_params, parent_rate);
+ cfg.n = cfg.m * pll_params->vco_min / parent_rate;
+
+ while (p_tohw->pdiv) {
+ if (p_tohw->pdiv == 2) {
+ cfg.p = p_tohw->hw_val;
+ break;
+ }
+ p_tohw++;
+ }
+
+ if (!p_tohw->pdiv) {
+ WARN_ON(1);
+ return ERR_PTR(-EINVAL);
+ }
+
+ pll_writel_base(0, pll);
+ _update_pll_mnp(pll, &cfg);
+
+ pll_writel_misc(PLLCX_MISC_DEFAULT, pll);
+ pll_writel(PLLCX_MISC1_DEFAULT, pll_params->ext_misc_reg[0], pll);
+ pll_writel(PLLCX_MISC2_DEFAULT, pll_params->ext_misc_reg[1], pll);
+ pll_writel(PLLCX_MISC3_DEFAULT, pll_params->ext_misc_reg[2], pll);
+
+ _pllcx_update_dynamic_coef(pll, parent_rate, cfg.n);
+
+ clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+ &tegra_clk_pllc_ops);
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
+}
+
+struct clk *tegra_clk_register_plle_tegra114(const char *name,
+ const char *parent_name,
+ void __iomem *clk_base, unsigned long flags,
+ unsigned long fixed_rate,
+ struct tegra_clk_pll_params *pll_params,
+ struct tegra_clk_pll_freq_table *freq_table,
+ spinlock_t *lock)
+{
+ struct tegra_clk_pll *pll;
+ struct clk *clk;
+ u32 val, val_aux;
+
+ pll = _tegra_init_pll(clk_base, NULL, fixed_rate, pll_params,
+ TEGRA_PLL_HAS_LOCK_ENABLE, freq_table, lock);
+ if (IS_ERR(pll))
+ return ERR_CAST(pll);
+
+ /* ensure parent is set to pll_re_vco */
+
+ val = pll_readl_base(pll);
+ val_aux = pll_readl(pll_params->aux_reg, pll);
+
+ if (val & PLL_BASE_ENABLE) {
+ if (!(val_aux & PLLE_AUX_PLLRE_SEL))
+ WARN(1, "pll_e enabled with unsupported parent %s\n",
+ (val & PLLE_AUX_PLLP_SEL) ? "pllp_out0" : "pll_ref");
+ } else {
+ val_aux |= PLLE_AUX_PLLRE_SEL;
+ pll_writel(val, pll_params->aux_reg, pll);
+ }
+
+ clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
+ &tegra_clk_plle_tegra114_ops);
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
}
+#endif
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
new file mode 100644
index 000000000000..d78e16ee161c
--- /dev/null
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -0,0 +1,2085 @@
+/*
+ * Copyright (c) 2012, 2013, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/delay.h>
+#include <linux/clk/tegra.h>
+
+#include "clk.h"
+
+#define RST_DEVICES_L 0x004
+#define RST_DEVICES_H 0x008
+#define RST_DEVICES_U 0x00C
+#define RST_DEVICES_V 0x358
+#define RST_DEVICES_W 0x35C
+#define RST_DEVICES_X 0x28C
+#define RST_DEVICES_SET_L 0x300
+#define RST_DEVICES_CLR_L 0x304
+#define RST_DEVICES_SET_H 0x308
+#define RST_DEVICES_CLR_H 0x30c
+#define RST_DEVICES_SET_U 0x310
+#define RST_DEVICES_CLR_U 0x314
+#define RST_DEVICES_SET_V 0x430
+#define RST_DEVICES_CLR_V 0x434
+#define RST_DEVICES_SET_W 0x438
+#define RST_DEVICES_CLR_W 0x43c
+#define RST_DEVICES_NUM 5
+
+#define CLK_OUT_ENB_L 0x010
+#define CLK_OUT_ENB_H 0x014
+#define CLK_OUT_ENB_U 0x018
+#define CLK_OUT_ENB_V 0x360
+#define CLK_OUT_ENB_W 0x364
+#define CLK_OUT_ENB_X 0x280
+#define CLK_OUT_ENB_SET_L 0x320
+#define CLK_OUT_ENB_CLR_L 0x324
+#define CLK_OUT_ENB_SET_H 0x328
+#define CLK_OUT_ENB_CLR_H 0x32c
+#define CLK_OUT_ENB_SET_U 0x330
+#define CLK_OUT_ENB_CLR_U 0x334
+#define CLK_OUT_ENB_SET_V 0x440
+#define CLK_OUT_ENB_CLR_V 0x444
+#define CLK_OUT_ENB_SET_W 0x448
+#define CLK_OUT_ENB_CLR_W 0x44c
+#define CLK_OUT_ENB_SET_X 0x284
+#define CLK_OUT_ENB_CLR_X 0x288
+#define CLK_OUT_ENB_NUM 6
+
+#define PLLC_BASE 0x80
+#define PLLC_MISC2 0x88
+#define PLLC_MISC 0x8c
+#define PLLC2_BASE 0x4e8
+#define PLLC2_MISC 0x4ec
+#define PLLC3_BASE 0x4fc
+#define PLLC3_MISC 0x500
+#define PLLM_BASE 0x90
+#define PLLM_MISC 0x9c
+#define PLLP_BASE 0xa0
+#define PLLP_MISC 0xac
+#define PLLX_BASE 0xe0
+#define PLLX_MISC 0xe4
+#define PLLX_MISC2 0x514
+#define PLLX_MISC3 0x518
+#define PLLD_BASE 0xd0
+#define PLLD_MISC 0xdc
+#define PLLD2_BASE 0x4b8
+#define PLLD2_MISC 0x4bc
+#define PLLE_BASE 0xe8
+#define PLLE_MISC 0xec
+#define PLLA_BASE 0xb0
+#define PLLA_MISC 0xbc
+#define PLLU_BASE 0xc0
+#define PLLU_MISC 0xcc
+#define PLLRE_BASE 0x4c4
+#define PLLRE_MISC 0x4c8
+
+#define PLL_MISC_LOCK_ENABLE 18
+#define PLLC_MISC_LOCK_ENABLE 24
+#define PLLDU_MISC_LOCK_ENABLE 22
+#define PLLE_MISC_LOCK_ENABLE 9
+#define PLLRE_MISC_LOCK_ENABLE 30
+
+#define PLLC_IDDQ_BIT 26
+#define PLLX_IDDQ_BIT 3
+#define PLLRE_IDDQ_BIT 16
+
+#define PLL_BASE_LOCK BIT(27)
+#define PLLE_MISC_LOCK BIT(11)
+#define PLLRE_MISC_LOCK BIT(24)
+#define PLLCX_BASE_LOCK (BIT(26)|BIT(27))
+
+#define PLLE_AUX 0x48c
+#define PLLC_OUT 0x84
+#define PLLM_OUT 0x94
+#define PLLP_OUTA 0xa4
+#define PLLP_OUTB 0xa8
+#define PLLA_OUT 0xb4
+
+#define AUDIO_SYNC_CLK_I2S0 0x4a0
+#define AUDIO_SYNC_CLK_I2S1 0x4a4
+#define AUDIO_SYNC_CLK_I2S2 0x4a8
+#define AUDIO_SYNC_CLK_I2S3 0x4ac
+#define AUDIO_SYNC_CLK_I2S4 0x4b0
+#define AUDIO_SYNC_CLK_SPDIF 0x4b4
+
+#define AUDIO_SYNC_DOUBLER 0x49c
+
+#define PMC_CLK_OUT_CNTRL 0x1a8
+#define PMC_DPD_PADS_ORIDE 0x1c
+#define PMC_DPD_PADS_ORIDE_BLINK_ENB 20
+#define PMC_CTRL 0
+#define PMC_CTRL_BLINK_ENB 7
+
+#define OSC_CTRL 0x50
+#define OSC_CTRL_OSC_FREQ_SHIFT 28
+#define OSC_CTRL_PLL_REF_DIV_SHIFT 26
+
+#define PLLXC_SW_MAX_P 6
+
+#define CCLKG_BURST_POLICY 0x368
+#define CCLKLP_BURST_POLICY 0x370
+#define SCLK_BURST_POLICY 0x028
+#define SYSTEM_CLK_RATE 0x030
+
+#define UTMIP_PLL_CFG2 0x488
+#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xffff) << 6)
+#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN BIT(0)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN BIT(2)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN BIT(4)
+
+#define UTMIP_PLL_CFG1 0x484
+#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 6)
+#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
+#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP BIT(17)
+#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN BIT(16)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP BIT(15)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN BIT(14)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN BIT(12)
+
+#define UTMIPLL_HW_PWRDN_CFG0 0x52c
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE BIT(25)
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE BIT(24)
+#define UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET BIT(6)
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_RESET_INPUT_VALUE BIT(5)
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_IN_SWCTL BIT(4)
+#define UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL BIT(2)
+#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE BIT(1)
+#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL BIT(0)
+
+#define CLK_SOURCE_I2S0 0x1d8
+#define CLK_SOURCE_I2S1 0x100
+#define CLK_SOURCE_I2S2 0x104
+#define CLK_SOURCE_NDFLASH 0x160
+#define CLK_SOURCE_I2S3 0x3bc
+#define CLK_SOURCE_I2S4 0x3c0
+#define CLK_SOURCE_SPDIF_OUT 0x108
+#define CLK_SOURCE_SPDIF_IN 0x10c
+#define CLK_SOURCE_PWM 0x110
+#define CLK_SOURCE_ADX 0x638
+#define CLK_SOURCE_AMX 0x63c
+#define CLK_SOURCE_HDA 0x428
+#define CLK_SOURCE_HDA2CODEC_2X 0x3e4
+#define CLK_SOURCE_SBC1 0x134
+#define CLK_SOURCE_SBC2 0x118
+#define CLK_SOURCE_SBC3 0x11c
+#define CLK_SOURCE_SBC4 0x1b4
+#define CLK_SOURCE_SBC5 0x3c8
+#define CLK_SOURCE_SBC6 0x3cc
+#define CLK_SOURCE_SATA_OOB 0x420
+#define CLK_SOURCE_SATA 0x424
+#define CLK_SOURCE_NDSPEED 0x3f8
+#define CLK_SOURCE_VFIR 0x168
+#define CLK_SOURCE_SDMMC1 0x150
+#define CLK_SOURCE_SDMMC2 0x154
+#define CLK_SOURCE_SDMMC3 0x1bc
+#define CLK_SOURCE_SDMMC4 0x164
+#define CLK_SOURCE_VDE 0x1c8
+#define CLK_SOURCE_CSITE 0x1d4
+#define CLK_SOURCE_LA 0x1f8
+#define CLK_SOURCE_TRACE 0x634
+#define CLK_SOURCE_OWR 0x1cc
+#define CLK_SOURCE_NOR 0x1d0
+#define CLK_SOURCE_MIPI 0x174
+#define CLK_SOURCE_I2C1 0x124
+#define CLK_SOURCE_I2C2 0x198
+#define CLK_SOURCE_I2C3 0x1b8
+#define CLK_SOURCE_I2C4 0x3c4
+#define CLK_SOURCE_I2C5 0x128
+#define CLK_SOURCE_UARTA 0x178
+#define CLK_SOURCE_UARTB 0x17c
+#define CLK_SOURCE_UARTC 0x1a0
+#define CLK_SOURCE_UARTD 0x1c0
+#define CLK_SOURCE_UARTE 0x1c4
+#define CLK_SOURCE_UARTA_DBG 0x178
+#define CLK_SOURCE_UARTB_DBG 0x17c
+#define CLK_SOURCE_UARTC_DBG 0x1a0
+#define CLK_SOURCE_UARTD_DBG 0x1c0
+#define CLK_SOURCE_UARTE_DBG 0x1c4
+#define CLK_SOURCE_3D 0x158
+#define CLK_SOURCE_2D 0x15c
+#define CLK_SOURCE_VI_SENSOR 0x1a8
+#define CLK_SOURCE_VI 0x148
+#define CLK_SOURCE_EPP 0x16c
+#define CLK_SOURCE_MSENC 0x1f0
+#define CLK_SOURCE_TSEC 0x1f4
+#define CLK_SOURCE_HOST1X 0x180
+#define CLK_SOURCE_HDMI 0x18c
+#define CLK_SOURCE_DISP1 0x138
+#define CLK_SOURCE_DISP2 0x13c
+#define CLK_SOURCE_CILAB 0x614
+#define CLK_SOURCE_CILCD 0x618
+#define CLK_SOURCE_CILE 0x61c
+#define CLK_SOURCE_DSIALP 0x620
+#define CLK_SOURCE_DSIBLP 0x624
+#define CLK_SOURCE_TSENSOR 0x3b8
+#define CLK_SOURCE_D_AUDIO 0x3d0
+#define CLK_SOURCE_DAM0 0x3d8
+#define CLK_SOURCE_DAM1 0x3dc
+#define CLK_SOURCE_DAM2 0x3e0
+#define CLK_SOURCE_ACTMON 0x3e8
+#define CLK_SOURCE_EXTERN1 0x3ec
+#define CLK_SOURCE_EXTERN2 0x3f0
+#define CLK_SOURCE_EXTERN3 0x3f4
+#define CLK_SOURCE_I2CSLOW 0x3fc
+#define CLK_SOURCE_SE 0x42c
+#define CLK_SOURCE_MSELECT 0x3b4
+#define CLK_SOURCE_SOC_THERM 0x644
+#define CLK_SOURCE_XUSB_HOST_SRC 0x600
+#define CLK_SOURCE_XUSB_FALCON_SRC 0x604
+#define CLK_SOURCE_XUSB_FS_SRC 0x608
+#define CLK_SOURCE_XUSB_SS_SRC 0x610
+#define CLK_SOURCE_XUSB_DEV_SRC 0x60c
+#define CLK_SOURCE_EMC 0x19c
+
+static int periph_clk_enb_refcnt[CLK_OUT_ENB_NUM * 32];
+
+static void __iomem *clk_base;
+static void __iomem *pmc_base;
+
+static DEFINE_SPINLOCK(pll_d_lock);
+static DEFINE_SPINLOCK(pll_d2_lock);
+static DEFINE_SPINLOCK(pll_u_lock);
+static DEFINE_SPINLOCK(pll_div_lock);
+static DEFINE_SPINLOCK(pll_re_lock);
+static DEFINE_SPINLOCK(clk_doubler_lock);
+static DEFINE_SPINLOCK(clk_out_lock);
+static DEFINE_SPINLOCK(sysrate_lock);
+
+static struct pdiv_map pllxc_p[] = {
+ { .pdiv = 1, .hw_val = 0 },
+ { .pdiv = 2, .hw_val = 1 },
+ { .pdiv = 3, .hw_val = 2 },
+ { .pdiv = 4, .hw_val = 3 },
+ { .pdiv = 5, .hw_val = 4 },
+ { .pdiv = 6, .hw_val = 5 },
+ { .pdiv = 8, .hw_val = 6 },
+ { .pdiv = 10, .hw_val = 7 },
+ { .pdiv = 12, .hw_val = 8 },
+ { .pdiv = 16, .hw_val = 9 },
+ { .pdiv = 12, .hw_val = 10 },
+ { .pdiv = 16, .hw_val = 11 },
+ { .pdiv = 20, .hw_val = 12 },
+ { .pdiv = 24, .hw_val = 13 },
+ { .pdiv = 32, .hw_val = 14 },
+ { .pdiv = 0, .hw_val = 0 },
+};
+
+static struct tegra_clk_pll_freq_table pll_c_freq_table[] = {
+ { 12000000, 624000000, 104, 0, 2},
+ { 12000000, 600000000, 100, 0, 2},
+ { 13000000, 600000000, 92, 0, 2}, /* actual: 598.0 MHz */
+ { 16800000, 600000000, 71, 0, 2}, /* actual: 596.4 MHz */
+ { 19200000, 600000000, 62, 0, 2}, /* actual: 595.2 MHz */
+ { 26000000, 600000000, 92, 1, 2}, /* actual: 598.0 MHz */
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct tegra_clk_pll_params pll_c_params = {
+ .input_min = 12000000,
+ .input_max = 800000000,
+ .cf_min = 12000000,
+ .cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */
+ .vco_min = 600000000,
+ .vco_max = 1400000000,
+ .base_reg = PLLC_BASE,
+ .misc_reg = PLLC_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLC_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .iddq_reg = PLLC_MISC,
+ .iddq_bit_idx = PLLC_IDDQ_BIT,
+ .max_p = PLLXC_SW_MAX_P,
+ .dyn_ramp_reg = PLLC_MISC2,
+ .stepa_shift = 17,
+ .stepb_shift = 9,
+ .pdiv_tohw = pllxc_p,
+};
+
+static struct pdiv_map pllc_p[] = {
+ { .pdiv = 1, .hw_val = 0 },
+ { .pdiv = 2, .hw_val = 1 },
+ { .pdiv = 4, .hw_val = 3 },
+ { .pdiv = 8, .hw_val = 5 },
+ { .pdiv = 16, .hw_val = 7 },
+ { .pdiv = 0, .hw_val = 0 },
+};
+
+static struct tegra_clk_pll_freq_table pll_cx_freq_table[] = {
+ {12000000, 600000000, 100, 0, 2},
+ {13000000, 600000000, 92, 0, 2}, /* actual: 598.0 MHz */
+ {16800000, 600000000, 71, 0, 2}, /* actual: 596.4 MHz */
+ {19200000, 600000000, 62, 0, 2}, /* actual: 595.2 MHz */
+ {26000000, 600000000, 92, 1, 2}, /* actual: 598.0 MHz */
+ {0, 0, 0, 0, 0, 0},
+};
+
+static struct tegra_clk_pll_params pll_c2_params = {
+ .input_min = 12000000,
+ .input_max = 48000000,
+ .cf_min = 12000000,
+ .cf_max = 19200000,
+ .vco_min = 600000000,
+ .vco_max = 1200000000,
+ .base_reg = PLLC2_BASE,
+ .misc_reg = PLLC2_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .pdiv_tohw = pllc_p,
+ .ext_misc_reg[0] = 0x4f0,
+ .ext_misc_reg[1] = 0x4f4,
+ .ext_misc_reg[2] = 0x4f8,
+};
+
+static struct tegra_clk_pll_params pll_c3_params = {
+ .input_min = 12000000,
+ .input_max = 48000000,
+ .cf_min = 12000000,
+ .cf_max = 19200000,
+ .vco_min = 600000000,
+ .vco_max = 1200000000,
+ .base_reg = PLLC3_BASE,
+ .misc_reg = PLLC3_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .pdiv_tohw = pllc_p,
+ .ext_misc_reg[0] = 0x504,
+ .ext_misc_reg[1] = 0x508,
+ .ext_misc_reg[2] = 0x50c,
+};
+
+static struct pdiv_map pllm_p[] = {
+ { .pdiv = 1, .hw_val = 0 },
+ { .pdiv = 2, .hw_val = 1 },
+ { .pdiv = 0, .hw_val = 0 },
+};
+
+static struct tegra_clk_pll_freq_table pll_m_freq_table[] = {
+ {12000000, 800000000, 66, 0, 1}, /* actual: 792.0 MHz */
+ {13000000, 800000000, 61, 0, 1}, /* actual: 793.0 MHz */
+ {16800000, 800000000, 47, 0, 1}, /* actual: 789.6 MHz */
+ {19200000, 800000000, 41, 0, 1}, /* actual: 787.2 MHz */
+ {26000000, 800000000, 61, 1, 1}, /* actual: 793.0 MHz */
+ {0, 0, 0, 0, 0, 0},
+};
+
+static struct tegra_clk_pll_params pll_m_params = {
+ .input_min = 12000000,
+ .input_max = 500000000,
+ .cf_min = 12000000,
+ .cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */
+ .vco_min = 400000000,
+ .vco_max = 1066000000,
+ .base_reg = PLLM_BASE,
+ .misc_reg = PLLM_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .max_p = 2,
+ .pdiv_tohw = pllm_p,
+};
+
+static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
+ {12000000, 216000000, 432, 12, 1, 8},
+ {13000000, 216000000, 432, 13, 1, 8},
+ {16800000, 216000000, 360, 14, 1, 8},
+ {19200000, 216000000, 360, 16, 1, 8},
+ {26000000, 216000000, 432, 26, 1, 8},
+ {0, 0, 0, 0, 0, 0},
+};
+
+static struct tegra_clk_pll_params pll_p_params = {
+ .input_min = 2000000,
+ .input_max = 31000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 200000000,
+ .vco_max = 700000000,
+ .base_reg = PLLP_BASE,
+ .misc_reg = PLLP_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+};
+
+static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
+ {9600000, 282240000, 147, 5, 0, 4},
+ {9600000, 368640000, 192, 5, 0, 4},
+ {9600000, 240000000, 200, 8, 0, 8},
+
+ {28800000, 282240000, 245, 25, 0, 8},
+ {28800000, 368640000, 320, 25, 0, 8},
+ {28800000, 240000000, 200, 24, 0, 8},
+ {0, 0, 0, 0, 0, 0},
+};
+
+
+static struct tegra_clk_pll_params pll_a_params = {
+ .input_min = 2000000,
+ .input_max = 31000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 200000000,
+ .vco_max = 700000000,
+ .base_reg = PLLA_BASE,
+ .misc_reg = PLLA_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+};
+
+static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
+ {12000000, 216000000, 864, 12, 2, 12},
+ {13000000, 216000000, 864, 13, 2, 12},
+ {16800000, 216000000, 720, 14, 2, 12},
+ {19200000, 216000000, 720, 16, 2, 12},
+ {26000000, 216000000, 864, 26, 2, 12},
+
+ {12000000, 594000000, 594, 12, 0, 12},
+ {13000000, 594000000, 594, 13, 0, 12},
+ {16800000, 594000000, 495, 14, 0, 12},
+ {19200000, 594000000, 495, 16, 0, 12},
+ {26000000, 594000000, 594, 26, 0, 12},
+
+ {12000000, 1000000000, 1000, 12, 0, 12},
+ {13000000, 1000000000, 1000, 13, 0, 12},
+ {19200000, 1000000000, 625, 12, 0, 12},
+ {26000000, 1000000000, 1000, 26, 0, 12},
+
+ {0, 0, 0, 0, 0, 0},
+};
+
+static struct tegra_clk_pll_params pll_d_params = {
+ .input_min = 2000000,
+ .input_max = 40000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 500000000,
+ .vco_max = 1000000000,
+ .base_reg = PLLD_BASE,
+ .misc_reg = PLLD_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
+ .lock_delay = 1000,
+};
+
+static struct tegra_clk_pll_params pll_d2_params = {
+ .input_min = 2000000,
+ .input_max = 40000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 500000000,
+ .vco_max = 1000000000,
+ .base_reg = PLLD2_BASE,
+ .misc_reg = PLLD2_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
+ .lock_delay = 1000,
+};
+
+static struct pdiv_map pllu_p[] = {
+ { .pdiv = 1, .hw_val = 1 },
+ { .pdiv = 2, .hw_val = 0 },
+ { .pdiv = 0, .hw_val = 0 },
+};
+
+static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
+ {12000000, 480000000, 960, 12, 0, 12},
+ {13000000, 480000000, 960, 13, 0, 12},
+ {16800000, 480000000, 400, 7, 0, 5},
+ {19200000, 480000000, 200, 4, 0, 3},
+ {26000000, 480000000, 960, 26, 0, 12},
+ {0, 0, 0, 0, 0, 0},
+};
+
+static struct tegra_clk_pll_params pll_u_params = {
+ .input_min = 2000000,
+ .input_max = 40000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 480000000,
+ .vco_max = 960000000,
+ .base_reg = PLLU_BASE,
+ .misc_reg = PLLU_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
+ .lock_delay = 1000,
+ .pdiv_tohw = pllu_p,
+};
+
+static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
+ /* 1 GHz */
+ {12000000, 1000000000, 83, 0, 1}, /* actual: 996.0 MHz */
+ {13000000, 1000000000, 76, 0, 1}, /* actual: 988.0 MHz */
+ {16800000, 1000000000, 59, 0, 1}, /* actual: 991.2 MHz */
+ {19200000, 1000000000, 52, 0, 1}, /* actual: 998.4 MHz */
+ {26000000, 1000000000, 76, 1, 1}, /* actual: 988.0 MHz */
+
+ {0, 0, 0, 0, 0, 0},
+};
+
+static struct tegra_clk_pll_params pll_x_params = {
+ .input_min = 12000000,
+ .input_max = 800000000,
+ .cf_min = 12000000,
+ .cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */
+ .vco_min = 700000000,
+ .vco_max = 2400000000U,
+ .base_reg = PLLX_BASE,
+ .misc_reg = PLLX_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .iddq_reg = PLLX_MISC3,
+ .iddq_bit_idx = PLLX_IDDQ_BIT,
+ .max_p = PLLXC_SW_MAX_P,
+ .dyn_ramp_reg = PLLX_MISC2,
+ .stepa_shift = 16,
+ .stepb_shift = 24,
+ .pdiv_tohw = pllxc_p,
+};
+
+static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
+ /* PLLE special case: use cpcon field to store cml divider value */
+ {336000000, 100000000, 100, 21, 16, 11},
+ {312000000, 100000000, 200, 26, 24, 13},
+ {0, 0, 0, 0, 0, 0},
+};
+
+static struct tegra_clk_pll_params pll_e_params = {
+ .input_min = 12000000,
+ .input_max = 1000000000,
+ .cf_min = 12000000,
+ .cf_max = 75000000,
+ .vco_min = 1600000000,
+ .vco_max = 2400000000U,
+ .base_reg = PLLE_BASE,
+ .misc_reg = PLLE_MISC,
+ .aux_reg = PLLE_AUX,
+ .lock_mask = PLLE_MISC_LOCK,
+ .lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+};
+
+static struct tegra_clk_pll_params pll_re_vco_params = {
+ .input_min = 12000000,
+ .input_max = 1000000000,
+ .cf_min = 12000000,
+ .cf_max = 19200000, /* s/w policy, h/w capability 38 MHz */
+ .vco_min = 300000000,
+ .vco_max = 600000000,
+ .base_reg = PLLRE_BASE,
+ .misc_reg = PLLRE_MISC,
+ .lock_mask = PLLRE_MISC_LOCK,
+ .lock_enable_bit_idx = PLLRE_MISC_LOCK_ENABLE,
+ .lock_delay = 300,
+ .iddq_reg = PLLRE_MISC,
+ .iddq_bit_idx = PLLRE_IDDQ_BIT,
+};
+
+/* Peripheral clock registers */
+
+static struct tegra_clk_periph_regs periph_l_regs = {
+ .enb_reg = CLK_OUT_ENB_L,
+ .enb_set_reg = CLK_OUT_ENB_SET_L,
+ .enb_clr_reg = CLK_OUT_ENB_CLR_L,
+ .rst_reg = RST_DEVICES_L,
+ .rst_set_reg = RST_DEVICES_SET_L,
+ .rst_clr_reg = RST_DEVICES_CLR_L,
+};
+
+static struct tegra_clk_periph_regs periph_h_regs = {
+ .enb_reg = CLK_OUT_ENB_H,
+ .enb_set_reg = CLK_OUT_ENB_SET_H,
+ .enb_clr_reg = CLK_OUT_ENB_CLR_H,
+ .rst_reg = RST_DEVICES_H,
+ .rst_set_reg = RST_DEVICES_SET_H,
+ .rst_clr_reg = RST_DEVICES_CLR_H,
+};
+
+static struct tegra_clk_periph_regs periph_u_regs = {
+ .enb_reg = CLK_OUT_ENB_U,
+ .enb_set_reg = CLK_OUT_ENB_SET_U,
+ .enb_clr_reg = CLK_OUT_ENB_CLR_U,
+ .rst_reg = RST_DEVICES_U,
+ .rst_set_reg = RST_DEVICES_SET_U,
+ .rst_clr_reg = RST_DEVICES_CLR_U,
+};
+
+static struct tegra_clk_periph_regs periph_v_regs = {
+ .enb_reg = CLK_OUT_ENB_V,
+ .enb_set_reg = CLK_OUT_ENB_SET_V,
+ .enb_clr_reg = CLK_OUT_ENB_CLR_V,
+ .rst_reg = RST_DEVICES_V,
+ .rst_set_reg = RST_DEVICES_SET_V,
+ .rst_clr_reg = RST_DEVICES_CLR_V,
+};
+
+static struct tegra_clk_periph_regs periph_w_regs = {
+ .enb_reg = CLK_OUT_ENB_W,
+ .enb_set_reg = CLK_OUT_ENB_SET_W,
+ .enb_clr_reg = CLK_OUT_ENB_CLR_W,
+ .rst_reg = RST_DEVICES_W,
+ .rst_set_reg = RST_DEVICES_SET_W,
+ .rst_clr_reg = RST_DEVICES_CLR_W,
+};
+
+/* possible OSC frequencies in Hz */
+static unsigned long tegra114_input_freq[] = {
+ [0] = 13000000,
+ [1] = 16800000,
+ [4] = 19200000,
+ [5] = 38400000,
+ [8] = 12000000,
+ [9] = 48000000,
+ [12] = 260000000,
+};
+
+#define MASK(x) (BIT(x) - 1)
+
+#define TEGRA_INIT_DATA_MUX(_name, _con_id, _dev_id, _parents, _offset, \
+ _clk_num, _regs, _gate_flags, _clk_id) \
+ TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\
+ 30, MASK(2), 0, 0, 8, 1, 0, _regs, _clk_num, \
+ periph_clk_enb_refcnt, _gate_flags, _clk_id, \
+ _parents##_idx, 0)
+
+#define TEGRA_INIT_DATA_MUX_FLAGS(_name, _con_id, _dev_id, _parents, _offset,\
+ _clk_num, _regs, _gate_flags, _clk_id, flags)\
+ TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\
+ 30, MASK(2), 0, 0, 8, 1, 0, _regs, _clk_num, \
+ periph_clk_enb_refcnt, _gate_flags, _clk_id, \
+ _parents##_idx, flags)
+
+#define TEGRA_INIT_DATA_MUX8(_name, _con_id, _dev_id, _parents, _offset, \
+ _clk_num, _regs, _gate_flags, _clk_id) \
+ TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\
+ 29, MASK(3), 0, 0, 8, 1, 0, _regs, _clk_num, \
+ periph_clk_enb_refcnt, _gate_flags, _clk_id, \
+ _parents##_idx, 0)
+
+#define TEGRA_INIT_DATA_INT(_name, _con_id, _dev_id, _parents, _offset, \
+ _clk_num, _regs, _gate_flags, _clk_id) \
+ TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\
+ 30, MASK(2), 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs,\
+ _clk_num, periph_clk_enb_refcnt, _gate_flags, \
+ _clk_id, _parents##_idx, 0)
+
+#define TEGRA_INIT_DATA_INT_FLAGS(_name, _con_id, _dev_id, _parents, _offset,\
+ _clk_num, _regs, _gate_flags, _clk_id, flags)\
+ TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\
+ 30, MASK(2), 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs,\
+ _clk_num, periph_clk_enb_refcnt, _gate_flags, \
+ _clk_id, _parents##_idx, flags)
+
+#define TEGRA_INIT_DATA_INT8(_name, _con_id, _dev_id, _parents, _offset,\
+ _clk_num, _regs, _gate_flags, _clk_id) \
+ TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\
+ 29, MASK(3), 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs,\
+ _clk_num, periph_clk_enb_refcnt, _gate_flags, \
+ _clk_id, _parents##_idx, 0)
+
+#define TEGRA_INIT_DATA_UART(_name, _con_id, _dev_id, _parents, _offset,\
+ _clk_num, _regs, _clk_id) \
+ TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\
+ 30, MASK(2), 0, 0, 16, 1, TEGRA_DIVIDER_UART, _regs,\
+ _clk_num, periph_clk_enb_refcnt, 0, _clk_id, \
+ _parents##_idx, 0)
+
+#define TEGRA_INIT_DATA_I2C(_name, _con_id, _dev_id, _parents, _offset,\
+ _clk_num, _regs, _clk_id) \
+ TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\
+ 30, MASK(2), 0, 0, 16, 0, 0, _regs, _clk_num, \
+ periph_clk_enb_refcnt, 0, _clk_id, _parents##_idx, 0)
+
+#define TEGRA_INIT_DATA_NODIV(_name, _con_id, _dev_id, _parents, _offset, \
+ _mux_shift, _mux_mask, _clk_num, _regs, \
+ _gate_flags, _clk_id) \
+ TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\
+ _mux_shift, _mux_mask, 0, 0, 0, 0, 0, _regs, \
+ _clk_num, periph_clk_enb_refcnt, _gate_flags, \
+ _clk_id, _parents##_idx, 0)
+
+#define TEGRA_INIT_DATA_XUSB(_name, _con_id, _dev_id, _parents, _offset, \
+ _clk_num, _regs, _gate_flags, _clk_id) \
+ TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset, \
+ 29, MASK(3), 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs, \
+ _clk_num, periph_clk_enb_refcnt, _gate_flags, \
+ _clk_id, _parents##_idx, 0)
+
+#define TEGRA_INIT_DATA_AUDIO(_name, _con_id, _dev_id, _offset, _clk_num,\
+ _regs, _gate_flags, _clk_id) \
+ TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, mux_d_audio_clk, \
+ _offset, 16, 0xE01F, 0, 0, 8, 1, 0, _regs, _clk_num, \
+ periph_clk_enb_refcnt, _gate_flags , _clk_id, \
+ mux_d_audio_clk_idx, 0)
+
+enum tegra114_clk {
+ rtc = 4, timer = 5, uarta = 6, sdmmc2 = 9, i2s1 = 11, i2c1 = 12,
+ ndflash = 13, sdmmc1 = 14, sdmmc4 = 15, pwm = 17, i2s2 = 18, epp = 19,
+ gr_2d = 21, usbd = 22, isp = 23, gr_3d = 24, disp2 = 26, disp1 = 27,
+ host1x = 28, vcp = 29, i2s0 = 30, apbdma = 34, kbc = 36, kfuse = 40,
+ sbc1 = 41, nor = 42, sbc2 = 44, sbc3 = 46, i2c5 = 47, dsia = 48,
+ mipi = 50, hdmi = 51, csi = 52, i2c2 = 54, uartc = 55, mipi_cal = 56,
+ emc, usb2, usb3, vde = 61, bsea = 62, bsev = 63, uartd = 65,
+ i2c3 = 67, sbc4 = 68, sdmmc3 = 69, owr = 71, csite = 73,
+ la = 76, trace = 77, soc_therm = 78, dtv = 79, ndspeed = 80,
+ i2cslow = 81, dsib = 82, tsec = 83, xusb_host = 89, msenc = 91,
+ csus = 92, mselect = 99, tsensor = 100, i2s3 = 101, i2s4 = 102,
+ i2c4 = 103, sbc5 = 104, sbc6 = 105, d_audio, apbif = 107, dam0, dam1,
+ dam2, hda2codec_2x = 111, audio0_2x = 113, audio1_2x, audio2_2x,
+ audio3_2x, audio4_2x, spdif_2x, actmon = 119, extern1 = 120,
+ extern2 = 121, extern3 = 122, hda = 125, se = 127, hda2hdmi = 128,
+ cilab = 144, cilcd = 145, cile = 146, dsialp = 147, dsiblp = 148,
+ dds = 150, dp2 = 152, amx = 153, adx = 154, xusb_ss = 156, uartb = 192,
+ vfir, spdif_in, spdif_out, vi, vi_sensor, fuse, fuse_burn, clk_32k,
+ clk_m, clk_m_div2, clk_m_div4, pll_ref, pll_c, pll_c_out1, pll_c2,
+ pll_c3, pll_m, pll_m_out1, pll_p, pll_p_out1, pll_p_out2, pll_p_out3,
+ pll_p_out4, pll_a, pll_a_out0, pll_d, pll_d_out0, pll_d2, pll_d2_out0,
+ pll_u, pll_u_480M, pll_u_60M, pll_u_48M, pll_u_12M, pll_x, pll_x_out0,
+ pll_re_vco, pll_re_out, pll_e_out0, spdif_in_sync, i2s0_sync,
+ i2s1_sync, i2s2_sync, i2s3_sync, i2s4_sync, vimclk_sync, audio0,
+ audio1, audio2, audio3, audio4, spdif, clk_out_1, clk_out_2, clk_out_3,
+ blink, xusb_host_src = 252, xusb_falcon_src, xusb_fs_src, xusb_ss_src,
+ xusb_dev_src, xusb_dev, xusb_hs_src, sclk, hclk, pclk, cclk_g, cclk_lp,
+
+ /* Mux clocks */
+
+ audio0_mux = 300, audio1_mux, audio2_mux, audio3_mux, audio4_mux,
+ spdif_mux, clk_out_1_mux, clk_out_2_mux, clk_out_3_mux, dsia_mux,
+ dsib_mux, clk_max,
+};
+
+struct utmi_clk_param {
+ /* Oscillator Frequency in KHz */
+ u32 osc_frequency;
+ /* UTMIP PLL Enable Delay Count */
+ u8 enable_delay_count;
+ /* UTMIP PLL Stable count */
+ u8 stable_count;
+ /* UTMIP PLL Active delay count */
+ u8 active_delay_count;
+ /* UTMIP PLL Xtal frequency count */
+ u8 xtal_freq_count;
+};
+
+static const struct utmi_clk_param utmi_parameters[] = {
+ {.osc_frequency = 13000000, .enable_delay_count = 0x02,
+ .stable_count = 0x33, .active_delay_count = 0x05,
+ .xtal_freq_count = 0x7F},
+ {.osc_frequency = 19200000, .enable_delay_count = 0x03,
+ .stable_count = 0x4B, .active_delay_count = 0x06,
+ .xtal_freq_count = 0xBB},
+ {.osc_frequency = 12000000, .enable_delay_count = 0x02,
+ .stable_count = 0x2F, .active_delay_count = 0x04,
+ .xtal_freq_count = 0x76},
+ {.osc_frequency = 26000000, .enable_delay_count = 0x04,
+ .stable_count = 0x66, .active_delay_count = 0x09,
+ .xtal_freq_count = 0xFE},
+ {.osc_frequency = 16800000, .enable_delay_count = 0x03,
+ .stable_count = 0x41, .active_delay_count = 0x0A,
+ .xtal_freq_count = 0xA4},
+};
+
+/* peripheral mux definitions */
+
+#define MUX_I2S_SPDIF(_id) \
+static const char *mux_pllaout0_##_id##_2x_pllp_clkm[] = { "pll_a_out0", \
+ #_id, "pll_p",\
+ "clk_m"};
+MUX_I2S_SPDIF(audio0)
+MUX_I2S_SPDIF(audio1)
+MUX_I2S_SPDIF(audio2)
+MUX_I2S_SPDIF(audio3)
+MUX_I2S_SPDIF(audio4)
+MUX_I2S_SPDIF(audio)
+
+#define mux_pllaout0_audio0_2x_pllp_clkm_idx NULL
+#define mux_pllaout0_audio1_2x_pllp_clkm_idx NULL
+#define mux_pllaout0_audio2_2x_pllp_clkm_idx NULL
+#define mux_pllaout0_audio3_2x_pllp_clkm_idx NULL
+#define mux_pllaout0_audio4_2x_pllp_clkm_idx NULL
+#define mux_pllaout0_audio_2x_pllp_clkm_idx NULL
+
+static const char *mux_pllp_pllc_pllm_clkm[] = {
+ "pll_p", "pll_c", "pll_m", "clk_m"
+};
+#define mux_pllp_pllc_pllm_clkm_idx NULL
+
+static const char *mux_pllp_pllc_pllm[] = { "pll_p", "pll_c", "pll_m" };
+#define mux_pllp_pllc_pllm_idx NULL
+
+static const char *mux_pllp_pllc_clk32_clkm[] = {
+ "pll_p", "pll_c", "clk_32k", "clk_m"
+};
+#define mux_pllp_pllc_clk32_clkm_idx NULL
+
+static const char *mux_plla_pllc_pllp_clkm[] = {
+ "pll_a_out0", "pll_c", "pll_p", "clk_m"
+};
+#define mux_plla_pllc_pllp_clkm_idx mux_pllp_pllc_pllm_clkm_idx
+
+static const char *mux_pllp_pllc2_c_c3_pllm_clkm[] = {
+ "pll_p", "pll_c2", "pll_c", "pll_c3", "pll_m", "clk_m"
+};
+static u32 mux_pllp_pllc2_c_c3_pllm_clkm_idx[] = {
+ [0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 6,
+};
+
+static const char *mux_pllp_clkm[] = {
+ "pll_p", "clk_m"
+};
+static u32 mux_pllp_clkm_idx[] = {
+ [0] = 0, [1] = 3,
+};
+
+static const char *mux_pllm_pllc2_c_c3_pllp_plla[] = {
+ "pll_m", "pll_c2", "pll_c", "pll_c3", "pll_p", "pll_a_out0"
+};
+#define mux_pllm_pllc2_c_c3_pllp_plla_idx mux_pllp_pllc2_c_c3_pllm_clkm_idx
+
+static const char *mux_pllp_pllm_plld_plla_pllc_plld2_clkm[] = {
+ "pll_p", "pll_m", "pll_d_out0", "pll_a_out0", "pll_c",
+ "pll_d2_out0", "clk_m"
+};
+#define mux_pllp_pllm_plld_plla_pllc_plld2_clkm_idx NULL
+
+static const char *mux_pllm_pllc_pllp_plla[] = {
+ "pll_m", "pll_c", "pll_p", "pll_a_out0"
+};
+#define mux_pllm_pllc_pllp_plla_idx mux_pllp_pllc_pllm_clkm_idx
+
+static const char *mux_pllp_pllc_clkm[] = {
+ "pll_p", "pll_c", "pll_m"
+};
+static u32 mux_pllp_pllc_clkm_idx[] = {
+ [0] = 0, [1] = 1, [2] = 3,
+};
+
+static const char *mux_pllp_pllc_clkm_clk32[] = {
+ "pll_p", "pll_c", "clk_m", "clk_32k"
+};
+#define mux_pllp_pllc_clkm_clk32_idx NULL
+
+static const char *mux_plla_clk32_pllp_clkm_plle[] = {
+ "pll_a_out0", "clk_32k", "pll_p", "clk_m", "pll_e_out0"
+};
+#define mux_plla_clk32_pllp_clkm_plle_idx NULL
+
+static const char *mux_clkm_pllp_pllc_pllre[] = {
+ "clk_m", "pll_p", "pll_c", "pll_re_out"
+};
+static u32 mux_clkm_pllp_pllc_pllre_idx[] = {
+ [0] = 0, [1] = 1, [2] = 3, [3] = 5,
+};
+
+static const char *mux_clkm_48M_pllp_480M[] = {
+ "clk_m", "pll_u_48M", "pll_p", "pll_u_480M"
+};
+#define mux_clkm_48M_pllp_480M_idx NULL
+
+static const char *mux_clkm_pllre_clk32_480M_pllc_ref[] = {
+ "clk_m", "pll_re_out", "clk_32k", "pll_u_480M", "pll_c", "pll_ref"
+};
+static u32 mux_clkm_pllre_clk32_480M_pllc_ref_idx[] = {
+ [0] = 0, [1] = 1, [2] = 3, [3] = 3, [4] = 4, [5] = 7,
+};
+
+static const char *mux_plld_out0_plld2_out0[] = {
+ "pll_d_out0", "pll_d2_out0",
+};
+#define mux_plld_out0_plld2_out0_idx NULL
+
+static const char *mux_d_audio_clk[] = {
+ "pll_a_out0", "pll_p", "clk_m", "spdif_in_sync", "i2s0_sync",
+ "i2s1_sync", "i2s2_sync", "i2s3_sync", "i2s4_sync", "vimclk_sync",
+};
+static u32 mux_d_audio_clk_idx[] = {
+ [0] = 0, [1] = 0x8000, [2] = 0xc000, [3] = 0xE000, [4] = 0xE001,
+ [5] = 0xE002, [6] = 0xE003, [7] = 0xE004, [8] = 0xE005, [9] = 0xE007,
+};
+
+static const char *mux_pllmcp_clkm[] = {
+ "pll_m_out0", "pll_c_out0", "pll_p_out0", "clk_m", "pll_m_ud",
+};
+
+static const struct clk_div_table pll_re_div_table[] = {
+ { .val = 0, .div = 1 },
+ { .val = 1, .div = 2 },
+ { .val = 2, .div = 3 },
+ { .val = 3, .div = 4 },
+ { .val = 4, .div = 5 },
+ { .val = 5, .div = 6 },
+ { .val = 0, .div = 0 },
+};
+
+static struct clk *clks[clk_max];
+static struct clk_onecell_data clk_data;
+
+static unsigned long osc_freq;
+static unsigned long pll_ref_freq;
+
+static int __init tegra114_osc_clk_init(void __iomem *clk_base)
+{
+ struct clk *clk;
+ u32 val, pll_ref_div;
+
+ val = readl_relaxed(clk_base + OSC_CTRL);
+
+ osc_freq = tegra114_input_freq[val >> OSC_CTRL_OSC_FREQ_SHIFT];
+ if (!osc_freq) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ /* clk_m */
+ clk = clk_register_fixed_rate(NULL, "clk_m", NULL, CLK_IS_ROOT,
+ osc_freq);
+ clk_register_clkdev(clk, "clk_m", NULL);
+ clks[clk_m] = clk;
+
+ /* pll_ref */
+ val = (val >> OSC_CTRL_PLL_REF_DIV_SHIFT) & 3;
+ pll_ref_div = 1 << val;
+ clk = clk_register_fixed_factor(NULL, "pll_ref", "clk_m",
+ CLK_SET_RATE_PARENT, 1, pll_ref_div);
+ clk_register_clkdev(clk, "pll_ref", NULL);
+ clks[pll_ref] = clk;
+
+ pll_ref_freq = osc_freq / pll_ref_div;
+
+ return 0;
+}
+
+static void __init tegra114_fixed_clk_init(void __iomem *clk_base)
+{
+ struct clk *clk;
+
+ /* clk_32k */
+ clk = clk_register_fixed_rate(NULL, "clk_32k", NULL, CLK_IS_ROOT,
+ 32768);
+ clk_register_clkdev(clk, "clk_32k", NULL);
+ clks[clk_32k] = clk;
+
+ /* clk_m_div2 */
+ clk = clk_register_fixed_factor(NULL, "clk_m_div2", "clk_m",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "clk_m_div2", NULL);
+ clks[clk_m_div2] = clk;
+
+ /* clk_m_div4 */
+ clk = clk_register_fixed_factor(NULL, "clk_m_div4", "clk_m",
+ CLK_SET_RATE_PARENT, 1, 4);
+ clk_register_clkdev(clk, "clk_m_div4", NULL);
+ clks[clk_m_div4] = clk;
+
+}
+
+static __init void tegra114_utmi_param_configure(void __iomem *clk_base)
+{
+ u32 reg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
+ if (osc_freq == utmi_parameters[i].osc_frequency)
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(utmi_parameters)) {
+ pr_err("%s: Unexpected oscillator freq %lu\n", __func__,
+ osc_freq);
+ return;
+ }
+
+ reg = readl_relaxed(clk_base + UTMIP_PLL_CFG2);
+
+ /* Program UTMIP PLL stable and active counts */
+ /* [FIXME] arclk_rst.h says WRONG! This should be 1ms -> 0x50 Check! */
+ reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
+ reg |= UTMIP_PLL_CFG2_STABLE_COUNT(utmi_parameters[i].stable_count);
+
+ reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
+
+ reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(utmi_parameters[i].
+ active_delay_count);
+
+ /* Remove power downs from UTMIP PLL control bits */
+ reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN;
+
+ writel_relaxed(reg, clk_base + UTMIP_PLL_CFG2);
+
+ /* Program UTMIP PLL delay and oscillator frequency counts */
+ reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1);
+ reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
+
+ reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(utmi_parameters[i].
+ enable_delay_count);
+
+ reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
+ reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(utmi_parameters[i].
+ xtal_freq_count);
+
+ /* Remove power downs from UTMIP PLL control bits */
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP;
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN;
+ writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1);
+
+ /* Setup HW control of UTMIPLL */
+ reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0);
+ reg |= UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET;
+ reg &= ~UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL;
+ reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE;
+ writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0);
+
+ reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1);
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+ writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1);
+
+ udelay(1);
+
+ /* Setup SW override of UTMIPLL assuming USB2.0
+ ports are assigned to USB2 */
+ reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0);
+ reg |= UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL;
+ reg &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;
+ writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0);
+
+ udelay(1);
+
+ /* Enable HW control UTMIPLL */
+ reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0);
+ reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE;
+ writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0);
+}
+
+static void __init _clip_vco_min(struct tegra_clk_pll_params *pll_params)
+{
+ pll_params->vco_min =
+ DIV_ROUND_UP(pll_params->vco_min, pll_ref_freq) * pll_ref_freq;
+}
+
+static int __init _setup_dynamic_ramp(struct tegra_clk_pll_params *pll_params,
+ void __iomem *clk_base)
+{
+ u32 val;
+ u32 step_a, step_b;
+
+ switch (pll_ref_freq) {
+ case 12000000:
+ case 13000000:
+ case 26000000:
+ step_a = 0x2B;
+ step_b = 0x0B;
+ break;
+ case 16800000:
+ step_a = 0x1A;
+ step_b = 0x09;
+ break;
+ case 19200000:
+ step_a = 0x12;
+ step_b = 0x08;
+ break;
+ default:
+ pr_err("%s: Unexpected reference rate %lu\n",
+ __func__, pll_ref_freq);
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ val = step_a << pll_params->stepa_shift;
+ val |= step_b << pll_params->stepb_shift;
+ writel_relaxed(val, clk_base + pll_params->dyn_ramp_reg);
+
+ return 0;
+}
+
+static void __init _init_iddq(struct tegra_clk_pll_params *pll_params,
+ void __iomem *clk_base)
+{
+ u32 val, val_iddq;
+
+ val = readl_relaxed(clk_base + pll_params->base_reg);
+ val_iddq = readl_relaxed(clk_base + pll_params->iddq_reg);
+
+ if (val & BIT(30))
+ WARN_ON(val_iddq & BIT(pll_params->iddq_bit_idx));
+ else {
+ val_iddq |= BIT(pll_params->iddq_bit_idx);
+ writel_relaxed(val_iddq, clk_base + pll_params->iddq_reg);
+ }
+}
+
+static void __init tegra114_pll_init(void __iomem *clk_base,
+ void __iomem *pmc)
+{
+ u32 val;
+ struct clk *clk;
+
+ /* PLLC */
+ _clip_vco_min(&pll_c_params);
+ if (_setup_dynamic_ramp(&pll_c_params, clk_base) >= 0) {
+ _init_iddq(&pll_c_params, clk_base);
+ clk = tegra_clk_register_pllxc("pll_c", "pll_ref", clk_base,
+ pmc, 0, 0, &pll_c_params, TEGRA_PLL_USE_LOCK,
+ pll_c_freq_table, NULL);
+ clk_register_clkdev(clk, "pll_c", NULL);
+ clks[pll_c] = clk;
+
+ /* PLLC_OUT1 */
+ clk = tegra_clk_register_divider("pll_c_out1_div", "pll_c",
+ clk_base + PLLC_OUT, 0, TEGRA_DIVIDER_ROUND_UP,
+ 8, 8, 1, NULL);
+ clk = tegra_clk_register_pll_out("pll_c_out1", "pll_c_out1_div",
+ clk_base + PLLC_OUT, 1, 0,
+ CLK_SET_RATE_PARENT, 0, NULL);
+ clk_register_clkdev(clk, "pll_c_out1", NULL);
+ clks[pll_c_out1] = clk;
+ }
+
+ /* PLLC2 */
+ _clip_vco_min(&pll_c2_params);
+ clk = tegra_clk_register_pllc("pll_c2", "pll_ref", clk_base, pmc, 0, 0,
+ &pll_c2_params, TEGRA_PLL_USE_LOCK,
+ pll_cx_freq_table, NULL);
+ clk_register_clkdev(clk, "pll_c2", NULL);
+ clks[pll_c2] = clk;
+
+ /* PLLC3 */
+ _clip_vco_min(&pll_c3_params);
+ clk = tegra_clk_register_pllc("pll_c3", "pll_ref", clk_base, pmc, 0, 0,
+ &pll_c3_params, TEGRA_PLL_USE_LOCK,
+ pll_cx_freq_table, NULL);
+ clk_register_clkdev(clk, "pll_c3", NULL);
+ clks[pll_c3] = clk;
+
+ /* PLLP */
+ clk = tegra_clk_register_pll("pll_p", "pll_ref", clk_base, pmc, 0,
+ 408000000, &pll_p_params,
+ TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK,
+ pll_p_freq_table, NULL);
+ clk_register_clkdev(clk, "pll_p", NULL);
+ clks[pll_p] = clk;
+
+ /* PLLP_OUT1 */
+ clk = tegra_clk_register_divider("pll_p_out1_div", "pll_p",
+ clk_base + PLLP_OUTA, 0, TEGRA_DIVIDER_FIXED |
+ TEGRA_DIVIDER_ROUND_UP, 8, 8, 1, &pll_div_lock);
+ clk = tegra_clk_register_pll_out("pll_p_out1", "pll_p_out1_div",
+ clk_base + PLLP_OUTA, 1, 0,
+ CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0,
+ &pll_div_lock);
+ clk_register_clkdev(clk, "pll_p_out1", NULL);
+ clks[pll_p_out1] = clk;
+
+ /* PLLP_OUT2 */
+ clk = tegra_clk_register_divider("pll_p_out2_div", "pll_p",
+ clk_base + PLLP_OUTA, 0, TEGRA_DIVIDER_FIXED |
+ TEGRA_DIVIDER_ROUND_UP, 24, 8, 1,
+ &pll_div_lock);
+ clk = tegra_clk_register_pll_out("pll_p_out2", "pll_p_out2_div",
+ clk_base + PLLP_OUTA, 17, 16,
+ CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0,
+ &pll_div_lock);
+ clk_register_clkdev(clk, "pll_p_out2", NULL);
+ clks[pll_p_out2] = clk;
+
+ /* PLLP_OUT3 */
+ clk = tegra_clk_register_divider("pll_p_out3_div", "pll_p",
+ clk_base + PLLP_OUTB, 0, TEGRA_DIVIDER_FIXED |
+ TEGRA_DIVIDER_ROUND_UP, 8, 8, 1, &pll_div_lock);
+ clk = tegra_clk_register_pll_out("pll_p_out3", "pll_p_out3_div",
+ clk_base + PLLP_OUTB, 1, 0,
+ CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0,
+ &pll_div_lock);
+ clk_register_clkdev(clk, "pll_p_out3", NULL);
+ clks[pll_p_out3] = clk;
+
+ /* PLLP_OUT4 */
+ clk = tegra_clk_register_divider("pll_p_out4_div", "pll_p",
+ clk_base + PLLP_OUTB, 0, TEGRA_DIVIDER_FIXED |
+ TEGRA_DIVIDER_ROUND_UP, 24, 8, 1,
+ &pll_div_lock);
+ clk = tegra_clk_register_pll_out("pll_p_out4", "pll_p_out4_div",
+ clk_base + PLLP_OUTB, 17, 16,
+ CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0,
+ &pll_div_lock);
+ clk_register_clkdev(clk, "pll_p_out4", NULL);
+ clks[pll_p_out4] = clk;
+
+ /* PLLM */
+ _clip_vco_min(&pll_m_params);
+ clk = tegra_clk_register_pllm("pll_m", "pll_ref", clk_base, pmc,
+ CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, 0,
+ &pll_m_params, TEGRA_PLL_USE_LOCK,
+ pll_m_freq_table, NULL);
+ clk_register_clkdev(clk, "pll_m", NULL);
+ clks[pll_m] = clk;
+
+ /* PLLM_OUT1 */
+ clk = tegra_clk_register_divider("pll_m_out1_div", "pll_m",
+ clk_base + PLLM_OUT, 0, TEGRA_DIVIDER_ROUND_UP,
+ 8, 8, 1, NULL);
+ clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div",
+ clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED |
+ CLK_SET_RATE_PARENT, 0, NULL);
+ clk_register_clkdev(clk, "pll_m_out1", NULL);
+ clks[pll_m_out1] = clk;
+
+ /* PLLM_UD */
+ clk = clk_register_fixed_factor(NULL, "pll_m_ud", "pll_m",
+ CLK_SET_RATE_PARENT, 1, 1);
+
+ /* PLLX */
+ _clip_vco_min(&pll_x_params);
+ if (_setup_dynamic_ramp(&pll_x_params, clk_base) >= 0) {
+ _init_iddq(&pll_x_params, clk_base);
+ clk = tegra_clk_register_pllxc("pll_x", "pll_ref", clk_base,
+ pmc, CLK_IGNORE_UNUSED, 0, &pll_x_params,
+ TEGRA_PLL_USE_LOCK, pll_x_freq_table, NULL);
+ clk_register_clkdev(clk, "pll_x", NULL);
+ clks[pll_x] = clk;
+ }
+
+ /* PLLX_OUT0 */
+ clk = clk_register_fixed_factor(NULL, "pll_x_out0", "pll_x",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll_x_out0", NULL);
+ clks[pll_x_out0] = clk;
+
+ /* PLLU */
+ val = readl(clk_base + pll_u_params.base_reg);
+ val &= ~BIT(24); /* disable PLLU_OVERRIDE */
+ writel(val, clk_base + pll_u_params.base_reg);
+
+ clk = tegra_clk_register_pll("pll_u", "pll_ref", clk_base, pmc, 0,
+ 0, &pll_u_params, TEGRA_PLLU |
+ TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
+ TEGRA_PLL_USE_LOCK, pll_u_freq_table, &pll_u_lock);
+ clk_register_clkdev(clk, "pll_u", NULL);
+ clks[pll_u] = clk;
+
+ tegra114_utmi_param_configure(clk_base);
+
+ /* PLLU_480M */
+ clk = clk_register_gate(NULL, "pll_u_480M", "pll_u",
+ CLK_SET_RATE_PARENT, clk_base + PLLU_BASE,
+ 22, 0, &pll_u_lock);
+ clk_register_clkdev(clk, "pll_u_480M", NULL);
+ clks[pll_u_480M] = clk;
+
+ /* PLLU_60M */
+ clk = clk_register_fixed_factor(NULL, "pll_u_60M", "pll_u",
+ CLK_SET_RATE_PARENT, 1, 8);
+ clk_register_clkdev(clk, "pll_u_60M", NULL);
+ clks[pll_u_60M] = clk;
+
+ /* PLLU_48M */
+ clk = clk_register_fixed_factor(NULL, "pll_u_48M", "pll_u",
+ CLK_SET_RATE_PARENT, 1, 10);
+ clk_register_clkdev(clk, "pll_u_48M", NULL);
+ clks[pll_u_48M] = clk;
+
+ /* PLLU_12M */
+ clk = clk_register_fixed_factor(NULL, "pll_u_12M", "pll_u",
+ CLK_SET_RATE_PARENT, 1, 40);
+ clk_register_clkdev(clk, "pll_u_12M", NULL);
+ clks[pll_u_12M] = clk;
+
+ /* PLLD */
+ clk = tegra_clk_register_pll("pll_d", "pll_ref", clk_base, pmc, 0,
+ 0, &pll_d_params,
+ TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
+ TEGRA_PLL_USE_LOCK, pll_d_freq_table, &pll_d_lock);
+ clk_register_clkdev(clk, "pll_d", NULL);
+ clks[pll_d] = clk;
+
+ /* PLLD_OUT0 */
+ clk = clk_register_fixed_factor(NULL, "pll_d_out0", "pll_d",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll_d_out0", NULL);
+ clks[pll_d_out0] = clk;
+
+ /* PLLD2 */
+ clk = tegra_clk_register_pll("pll_d2", "pll_ref", clk_base, pmc, 0,
+ 0, &pll_d2_params,
+ TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
+ TEGRA_PLL_USE_LOCK, pll_d_freq_table, &pll_d2_lock);
+ clk_register_clkdev(clk, "pll_d2", NULL);
+ clks[pll_d2] = clk;
+
+ /* PLLD2_OUT0 */
+ clk = clk_register_fixed_factor(NULL, "pll_d2_out0", "pll_d2",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll_d2_out0", NULL);
+ clks[pll_d2_out0] = clk;
+
+ /* PLLA */
+ clk = tegra_clk_register_pll("pll_a", "pll_p_out1", clk_base, pmc, 0,
+ 0, &pll_a_params, TEGRA_PLL_HAS_CPCON |
+ TEGRA_PLL_USE_LOCK, pll_a_freq_table, NULL);
+ clk_register_clkdev(clk, "pll_a", NULL);
+ clks[pll_a] = clk;
+
+ /* PLLA_OUT0 */
+ clk = tegra_clk_register_divider("pll_a_out0_div", "pll_a",
+ clk_base + PLLA_OUT, 0, TEGRA_DIVIDER_ROUND_UP,
+ 8, 8, 1, NULL);
+ clk = tegra_clk_register_pll_out("pll_a_out0", "pll_a_out0_div",
+ clk_base + PLLA_OUT, 1, 0, CLK_IGNORE_UNUSED |
+ CLK_SET_RATE_PARENT, 0, NULL);
+ clk_register_clkdev(clk, "pll_a_out0", NULL);
+ clks[pll_a_out0] = clk;
+
+ /* PLLRE */
+ _clip_vco_min(&pll_re_vco_params);
+ clk = tegra_clk_register_pllre("pll_re_vco", "pll_ref", clk_base, pmc,
+ 0, 0, &pll_re_vco_params, TEGRA_PLL_USE_LOCK,
+ NULL, &pll_re_lock, pll_ref_freq);
+ clk_register_clkdev(clk, "pll_re_vco", NULL);
+ clks[pll_re_vco] = clk;
+
+ clk = clk_register_divider_table(NULL, "pll_re_out", "pll_re_vco", 0,
+ clk_base + PLLRE_BASE, 16, 4, 0,
+ pll_re_div_table, &pll_re_lock);
+ clk_register_clkdev(clk, "pll_re_out", NULL);
+ clks[pll_re_out] = clk;
+
+ /* PLLE */
+ clk = tegra_clk_register_plle_tegra114("pll_e_out0", "pll_re_vco",
+ clk_base, 0, 100000000, &pll_e_params,
+ pll_e_freq_table, NULL);
+ clk_register_clkdev(clk, "pll_e_out0", NULL);
+ clks[pll_e_out0] = clk;
+}
+
+static const char *mux_audio_sync_clk[] = { "spdif_in_sync", "i2s0_sync",
+ "i2s1_sync", "i2s2_sync", "i2s3_sync", "i2s4_sync", "vimclk_sync",
+};
+
+static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2",
+ "clk_m_div4", "extern1",
+};
+
+static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2",
+ "clk_m_div4", "extern2",
+};
+
+static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2",
+ "clk_m_div4", "extern3",
+};
+
+static void __init tegra114_audio_clk_init(void __iomem *clk_base)
+{
+ struct clk *clk;
+
+ /* spdif_in_sync */
+ clk = tegra_clk_register_sync_source("spdif_in_sync", 24000000,
+ 24000000);
+ clk_register_clkdev(clk, "spdif_in_sync", NULL);
+ clks[spdif_in_sync] = clk;
+
+ /* i2s0_sync */
+ clk = tegra_clk_register_sync_source("i2s0_sync", 24000000, 24000000);
+ clk_register_clkdev(clk, "i2s0_sync", NULL);
+ clks[i2s0_sync] = clk;
+
+ /* i2s1_sync */
+ clk = tegra_clk_register_sync_source("i2s1_sync", 24000000, 24000000);
+ clk_register_clkdev(clk, "i2s1_sync", NULL);
+ clks[i2s1_sync] = clk;
+
+ /* i2s2_sync */
+ clk = tegra_clk_register_sync_source("i2s2_sync", 24000000, 24000000);
+ clk_register_clkdev(clk, "i2s2_sync", NULL);
+ clks[i2s2_sync] = clk;
+
+ /* i2s3_sync */
+ clk = tegra_clk_register_sync_source("i2s3_sync", 24000000, 24000000);
+ clk_register_clkdev(clk, "i2s3_sync", NULL);
+ clks[i2s3_sync] = clk;
+
+ /* i2s4_sync */
+ clk = tegra_clk_register_sync_source("i2s4_sync", 24000000, 24000000);
+ clk_register_clkdev(clk, "i2s4_sync", NULL);
+ clks[i2s4_sync] = clk;
+
+ /* vimclk_sync */
+ clk = tegra_clk_register_sync_source("vimclk_sync", 24000000, 24000000);
+ clk_register_clkdev(clk, "vimclk_sync", NULL);
+ clks[vimclk_sync] = clk;
+
+ /* audio0 */
+ clk = clk_register_mux(NULL, "audio0_mux", mux_audio_sync_clk,
+ ARRAY_SIZE(mux_audio_sync_clk), 0,
+ clk_base + AUDIO_SYNC_CLK_I2S0, 0, 3, 0,
+ NULL);
+ clks[audio0_mux] = clk;
+ clk = clk_register_gate(NULL, "audio0", "audio0_mux", 0,
+ clk_base + AUDIO_SYNC_CLK_I2S0, 4,
+ CLK_GATE_SET_TO_DISABLE, NULL);
+ clk_register_clkdev(clk, "audio0", NULL);
+ clks[audio0] = clk;
+
+ /* audio1 */
+ clk = clk_register_mux(NULL, "audio1_mux", mux_audio_sync_clk,
+ ARRAY_SIZE(mux_audio_sync_clk), 0,
+ clk_base + AUDIO_SYNC_CLK_I2S1, 0, 3, 0,
+ NULL);
+ clks[audio1_mux] = clk;
+ clk = clk_register_gate(NULL, "audio1", "audio1_mux", 0,
+ clk_base + AUDIO_SYNC_CLK_I2S1, 4,
+ CLK_GATE_SET_TO_DISABLE, NULL);
+ clk_register_clkdev(clk, "audio1", NULL);
+ clks[audio1] = clk;
+
+ /* audio2 */
+ clk = clk_register_mux(NULL, "audio2_mux", mux_audio_sync_clk,
+ ARRAY_SIZE(mux_audio_sync_clk), 0,
+ clk_base + AUDIO_SYNC_CLK_I2S2, 0, 3, 0,
+ NULL);
+ clks[audio2_mux] = clk;
+ clk = clk_register_gate(NULL, "audio2", "audio2_mux", 0,
+ clk_base + AUDIO_SYNC_CLK_I2S2, 4,
+ CLK_GATE_SET_TO_DISABLE, NULL);
+ clk_register_clkdev(clk, "audio2", NULL);
+ clks[audio2] = clk;
+
+ /* audio3 */
+ clk = clk_register_mux(NULL, "audio3_mux", mux_audio_sync_clk,
+ ARRAY_SIZE(mux_audio_sync_clk), 0,
+ clk_base + AUDIO_SYNC_CLK_I2S3, 0, 3, 0,
+ NULL);
+ clks[audio3_mux] = clk;
+ clk = clk_register_gate(NULL, "audio3", "audio3_mux", 0,
+ clk_base + AUDIO_SYNC_CLK_I2S3, 4,
+ CLK_GATE_SET_TO_DISABLE, NULL);
+ clk_register_clkdev(clk, "audio3", NULL);
+ clks[audio3] = clk;
+
+ /* audio4 */
+ clk = clk_register_mux(NULL, "audio4_mux", mux_audio_sync_clk,
+ ARRAY_SIZE(mux_audio_sync_clk), 0,
+ clk_base + AUDIO_SYNC_CLK_I2S4, 0, 3, 0,
+ NULL);
+ clks[audio4_mux] = clk;
+ clk = clk_register_gate(NULL, "audio4", "audio4_mux", 0,
+ clk_base + AUDIO_SYNC_CLK_I2S4, 4,
+ CLK_GATE_SET_TO_DISABLE, NULL);
+ clk_register_clkdev(clk, "audio4", NULL);
+ clks[audio4] = clk;
+
+ /* spdif */
+ clk = clk_register_mux(NULL, "spdif_mux", mux_audio_sync_clk,
+ ARRAY_SIZE(mux_audio_sync_clk), 0,
+ clk_base + AUDIO_SYNC_CLK_SPDIF, 0, 3, 0,
+ NULL);
+ clks[spdif_mux] = clk;
+ clk = clk_register_gate(NULL, "spdif", "spdif_mux", 0,
+ clk_base + AUDIO_SYNC_CLK_SPDIF, 4,
+ CLK_GATE_SET_TO_DISABLE, NULL);
+ clk_register_clkdev(clk, "spdif", NULL);
+ clks[spdif] = clk;
+
+ /* audio0_2x */
+ clk = clk_register_fixed_factor(NULL, "audio0_doubler", "audio0",
+ CLK_SET_RATE_PARENT, 2, 1);
+ clk = tegra_clk_register_divider("audio0_div", "audio0_doubler",
+ clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 24, 1,
+ 0, &clk_doubler_lock);
+ clk = tegra_clk_register_periph_gate("audio0_2x", "audio0_div",
+ TEGRA_PERIPH_NO_RESET, clk_base,
+ CLK_SET_RATE_PARENT, 113, &periph_v_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "audio0_2x", NULL);
+ clks[audio0_2x] = clk;
+
+ /* audio1_2x */
+ clk = clk_register_fixed_factor(NULL, "audio1_doubler", "audio1",
+ CLK_SET_RATE_PARENT, 2, 1);
+ clk = tegra_clk_register_divider("audio1_div", "audio1_doubler",
+ clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 25, 1,
+ 0, &clk_doubler_lock);
+ clk = tegra_clk_register_periph_gate("audio1_2x", "audio1_div",
+ TEGRA_PERIPH_NO_RESET, clk_base,
+ CLK_SET_RATE_PARENT, 114, &periph_v_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "audio1_2x", NULL);
+ clks[audio1_2x] = clk;
+
+ /* audio2_2x */
+ clk = clk_register_fixed_factor(NULL, "audio2_doubler", "audio2",
+ CLK_SET_RATE_PARENT, 2, 1);
+ clk = tegra_clk_register_divider("audio2_div", "audio2_doubler",
+ clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 26, 1,
+ 0, &clk_doubler_lock);
+ clk = tegra_clk_register_periph_gate("audio2_2x", "audio2_div",
+ TEGRA_PERIPH_NO_RESET, clk_base,
+ CLK_SET_RATE_PARENT, 115, &periph_v_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "audio2_2x", NULL);
+ clks[audio2_2x] = clk;
+
+ /* audio3_2x */
+ clk = clk_register_fixed_factor(NULL, "audio3_doubler", "audio3",
+ CLK_SET_RATE_PARENT, 2, 1);
+ clk = tegra_clk_register_divider("audio3_div", "audio3_doubler",
+ clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 27, 1,
+ 0, &clk_doubler_lock);
+ clk = tegra_clk_register_periph_gate("audio3_2x", "audio3_div",
+ TEGRA_PERIPH_NO_RESET, clk_base,
+ CLK_SET_RATE_PARENT, 116, &periph_v_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "audio3_2x", NULL);
+ clks[audio3_2x] = clk;
+
+ /* audio4_2x */
+ clk = clk_register_fixed_factor(NULL, "audio4_doubler", "audio4",
+ CLK_SET_RATE_PARENT, 2, 1);
+ clk = tegra_clk_register_divider("audio4_div", "audio4_doubler",
+ clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 28, 1,
+ 0, &clk_doubler_lock);
+ clk = tegra_clk_register_periph_gate("audio4_2x", "audio4_div",
+ TEGRA_PERIPH_NO_RESET, clk_base,
+ CLK_SET_RATE_PARENT, 117, &periph_v_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "audio4_2x", NULL);
+ clks[audio4_2x] = clk;
+
+ /* spdif_2x */
+ clk = clk_register_fixed_factor(NULL, "spdif_doubler", "spdif",
+ CLK_SET_RATE_PARENT, 2, 1);
+ clk = tegra_clk_register_divider("spdif_div", "spdif_doubler",
+ clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 29, 1,
+ 0, &clk_doubler_lock);
+ clk = tegra_clk_register_periph_gate("spdif_2x", "spdif_div",
+ TEGRA_PERIPH_NO_RESET, clk_base,
+ CLK_SET_RATE_PARENT, 118,
+ &periph_v_regs, periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, "spdif_2x", NULL);
+ clks[spdif_2x] = clk;
+}
+
+static void __init tegra114_pmc_clk_init(void __iomem *pmc_base)
+{
+ struct clk *clk;
+
+ /* clk_out_1 */
+ clk = clk_register_mux(NULL, "clk_out_1_mux", clk_out1_parents,
+ ARRAY_SIZE(clk_out1_parents), 0,
+ pmc_base + PMC_CLK_OUT_CNTRL, 6, 3, 0,
+ &clk_out_lock);
+ clks[clk_out_1_mux] = clk;
+ clk = clk_register_gate(NULL, "clk_out_1", "clk_out_1_mux", 0,
+ pmc_base + PMC_CLK_OUT_CNTRL, 2, 0,
+ &clk_out_lock);
+ clk_register_clkdev(clk, "extern1", "clk_out_1");
+ clks[clk_out_1] = clk;
+
+ /* clk_out_2 */
+ clk = clk_register_mux(NULL, "clk_out_2_mux", clk_out2_parents,
+ ARRAY_SIZE(clk_out1_parents), 0,
+ pmc_base + PMC_CLK_OUT_CNTRL, 14, 3, 0,
+ &clk_out_lock);
+ clks[clk_out_2_mux] = clk;
+ clk = clk_register_gate(NULL, "clk_out_2", "clk_out_2_mux", 0,
+ pmc_base + PMC_CLK_OUT_CNTRL, 10, 0,
+ &clk_out_lock);
+ clk_register_clkdev(clk, "extern2", "clk_out_2");
+ clks[clk_out_2] = clk;
+
+ /* clk_out_3 */
+ clk = clk_register_mux(NULL, "clk_out_3_mux", clk_out3_parents,
+ ARRAY_SIZE(clk_out1_parents), 0,
+ pmc_base + PMC_CLK_OUT_CNTRL, 22, 3, 0,
+ &clk_out_lock);
+ clks[clk_out_3_mux] = clk;
+ clk = clk_register_gate(NULL, "clk_out_3", "clk_out_3_mux", 0,
+ pmc_base + PMC_CLK_OUT_CNTRL, 18, 0,
+ &clk_out_lock);
+ clk_register_clkdev(clk, "extern3", "clk_out_3");
+ clks[clk_out_3] = clk;
+
+ /* blink */
+ clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0,
+ pmc_base + PMC_DPD_PADS_ORIDE,
+ PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL);
+ clk = clk_register_gate(NULL, "blink", "blink_override", 0,
+ pmc_base + PMC_CTRL,
+ PMC_CTRL_BLINK_ENB, 0, NULL);
+ clk_register_clkdev(clk, "blink", NULL);
+ clks[blink] = clk;
+
+}
+
+static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4",
+ "pll_p_out3", "pll_p_out2", "unused",
+ "clk_32k", "pll_m_out1" };
+
+static const char *cclk_g_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m",
+ "pll_p", "pll_p_out4", "unused",
+ "unused", "pll_x" };
+
+static const char *cclk_lp_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m",
+ "pll_p", "pll_p_out4", "unused",
+ "unused", "pll_x", "pll_x_out0" };
+
+static void __init tegra114_super_clk_init(void __iomem *clk_base)
+{
+ struct clk *clk;
+
+ /* CCLKG */
+ clk = tegra_clk_register_super_mux("cclk_g", cclk_g_parents,
+ ARRAY_SIZE(cclk_g_parents),
+ CLK_SET_RATE_PARENT,
+ clk_base + CCLKG_BURST_POLICY,
+ 0, 4, 0, 0, NULL);
+ clk_register_clkdev(clk, "cclk_g", NULL);
+ clks[cclk_g] = clk;
+
+ /* CCLKLP */
+ clk = tegra_clk_register_super_mux("cclk_lp", cclk_lp_parents,
+ ARRAY_SIZE(cclk_lp_parents),
+ CLK_SET_RATE_PARENT,
+ clk_base + CCLKLP_BURST_POLICY,
+ 0, 4, 8, 9, NULL);
+ clk_register_clkdev(clk, "cclk_lp", NULL);
+ clks[cclk_lp] = clk;
+
+ /* SCLK */
+ clk = tegra_clk_register_super_mux("sclk", sclk_parents,
+ ARRAY_SIZE(sclk_parents),
+ CLK_SET_RATE_PARENT,
+ clk_base + SCLK_BURST_POLICY,
+ 0, 4, 0, 0, NULL);
+ clk_register_clkdev(clk, "sclk", NULL);
+ clks[sclk] = clk;
+
+ /* HCLK */
+ clk = clk_register_divider(NULL, "hclk_div", "sclk", 0,
+ clk_base + SYSTEM_CLK_RATE, 4, 2, 0,
+ &sysrate_lock);
+ clk = clk_register_gate(NULL, "hclk", "hclk_div", CLK_SET_RATE_PARENT |
+ CLK_IGNORE_UNUSED, clk_base + SYSTEM_CLK_RATE,
+ 7, CLK_GATE_SET_TO_DISABLE, &sysrate_lock);
+ clk_register_clkdev(clk, "hclk", NULL);
+ clks[hclk] = clk;
+
+ /* PCLK */
+ clk = clk_register_divider(NULL, "pclk_div", "hclk", 0,
+ clk_base + SYSTEM_CLK_RATE, 0, 2, 0,
+ &sysrate_lock);
+ clk = clk_register_gate(NULL, "pclk", "pclk_div", CLK_SET_RATE_PARENT |
+ CLK_IGNORE_UNUSED, clk_base + SYSTEM_CLK_RATE,
+ 3, CLK_GATE_SET_TO_DISABLE, &sysrate_lock);
+ clk_register_clkdev(clk, "pclk", NULL);
+ clks[pclk] = clk;
+}
+
+static struct tegra_periph_init_data tegra_periph_clk_list[] = {
+ TEGRA_INIT_DATA_MUX("i2s0", NULL, "tegra30-i2s.0", mux_pllaout0_audio0_2x_pllp_clkm, CLK_SOURCE_I2S0, 30, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s0),
+ TEGRA_INIT_DATA_MUX("i2s1", NULL, "tegra30-i2s.1", mux_pllaout0_audio1_2x_pllp_clkm, CLK_SOURCE_I2S1, 11, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s1),
+ TEGRA_INIT_DATA_MUX("i2s2", NULL, "tegra30-i2s.2", mux_pllaout0_audio2_2x_pllp_clkm, CLK_SOURCE_I2S2, 18, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s2),
+ TEGRA_INIT_DATA_MUX("i2s3", NULL, "tegra30-i2s.3", mux_pllaout0_audio3_2x_pllp_clkm, CLK_SOURCE_I2S3, 101, &periph_v_regs, TEGRA_PERIPH_ON_APB, i2s3),
+ TEGRA_INIT_DATA_MUX("i2s4", NULL, "tegra30-i2s.4", mux_pllaout0_audio4_2x_pllp_clkm, CLK_SOURCE_I2S4, 102, &periph_v_regs, TEGRA_PERIPH_ON_APB, i2s4),
+ TEGRA_INIT_DATA_MUX("spdif_out", "spdif_out", "tegra30-spdif", mux_pllaout0_audio_2x_pllp_clkm, CLK_SOURCE_SPDIF_OUT, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_out),
+ TEGRA_INIT_DATA_MUX("spdif_in", "spdif_in", "tegra30-spdif", mux_pllp_pllc_pllm, CLK_SOURCE_SPDIF_IN, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_in),
+ TEGRA_INIT_DATA_MUX("pwm", NULL, "pwm", mux_pllp_pllc_clk32_clkm, CLK_SOURCE_PWM, 17, &periph_l_regs, TEGRA_PERIPH_ON_APB, pwm),
+ TEGRA_INIT_DATA_MUX("adx", NULL, "adx", mux_plla_pllc_pllp_clkm, CLK_SOURCE_ADX, 154, &periph_w_regs, TEGRA_PERIPH_ON_APB, adx),
+ TEGRA_INIT_DATA_MUX("amx", NULL, "amx", mux_plla_pllc_pllp_clkm, CLK_SOURCE_AMX, 153, &periph_w_regs, TEGRA_PERIPH_ON_APB, amx),
+ TEGRA_INIT_DATA_MUX("hda", "hda", "tegra30-hda", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA, 125, &periph_v_regs, TEGRA_PERIPH_ON_APB, hda),
+ TEGRA_INIT_DATA_MUX("hda2codec_2x", "hda2codec", "tegra30-hda", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA2CODEC_2X, 111, &periph_v_regs, TEGRA_PERIPH_ON_APB, hda2codec_2x),
+ TEGRA_INIT_DATA_MUX("sbc1", NULL, "tegra11-spi.0", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC1, 41, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc1),
+ TEGRA_INIT_DATA_MUX("sbc2", NULL, "tegra11-spi.1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC2, 44, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc2),
+ TEGRA_INIT_DATA_MUX("sbc3", NULL, "tegra11-spi.2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC3, 46, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc3),
+ TEGRA_INIT_DATA_MUX("sbc4", NULL, "tegra11-spi.3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC4, 68, &periph_u_regs, TEGRA_PERIPH_ON_APB, sbc4),
+ TEGRA_INIT_DATA_MUX("sbc5", NULL, "tegra11-spi.4", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC5, 104, &periph_v_regs, TEGRA_PERIPH_ON_APB, sbc5),
+ TEGRA_INIT_DATA_MUX("sbc6", NULL, "tegra11-spi.5", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC6, 105, &periph_v_regs, TEGRA_PERIPH_ON_APB, sbc6),
+ TEGRA_INIT_DATA_MUX8("ndflash", NULL, "tegra_nand", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDFLASH, 13, &periph_u_regs, TEGRA_PERIPH_ON_APB, ndspeed),
+ TEGRA_INIT_DATA_MUX8("ndspeed", NULL, "tegra_nand_speed", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDSPEED, 80, &periph_u_regs, TEGRA_PERIPH_ON_APB, ndspeed),
+ TEGRA_INIT_DATA_MUX("vfir", NULL, "vfir", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_VFIR, 7, &periph_l_regs, TEGRA_PERIPH_ON_APB, vfir),
+ TEGRA_INIT_DATA_MUX("sdmmc1", NULL, "sdhci-tegra.0", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC1, 14, &periph_l_regs, 0, sdmmc1),
+ TEGRA_INIT_DATA_MUX("sdmmc2", NULL, "sdhci-tegra.1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC2, 9, &periph_l_regs, 0, sdmmc2),
+ TEGRA_INIT_DATA_MUX("sdmmc3", NULL, "sdhci-tegra.2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC3, 69, &periph_u_regs, 0, sdmmc3),
+ TEGRA_INIT_DATA_MUX("sdmmc4", NULL, "sdhci-tegra.3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC4, 15, &periph_l_regs, 0, sdmmc4),
+ TEGRA_INIT_DATA_INT("vde", NULL, "vde", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_VDE, 61, &periph_h_regs, 0, vde),
+ TEGRA_INIT_DATA_MUX_FLAGS("csite", NULL, "csite", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_CSITE, 73, &periph_u_regs, TEGRA_PERIPH_ON_APB, csite, CLK_IGNORE_UNUSED),
+ TEGRA_INIT_DATA_MUX("la", NULL, "la", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_LA, 76, &periph_u_regs, TEGRA_PERIPH_ON_APB, la),
+ TEGRA_INIT_DATA_MUX("trace", NULL, "trace", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_TRACE, 77, &periph_u_regs, TEGRA_PERIPH_ON_APB, trace),
+ TEGRA_INIT_DATA_MUX("owr", NULL, "tegra_w1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_OWR, 71, &periph_u_regs, TEGRA_PERIPH_ON_APB, owr),
+ TEGRA_INIT_DATA_MUX("nor", NULL, "tegra-nor", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_NOR, 42, &periph_h_regs, 0, nor),
+ TEGRA_INIT_DATA_MUX("mipi", NULL, "mipi", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_MIPI, 50, &periph_h_regs, TEGRA_PERIPH_ON_APB, mipi),
+ TEGRA_INIT_DATA_I2C("i2c1", "div-clk", "tegra11-i2c.0", mux_pllp_clkm, CLK_SOURCE_I2C1, 12, &periph_l_regs, i2c1),
+ TEGRA_INIT_DATA_I2C("i2c2", "div-clk", "tegra11-i2c.1", mux_pllp_clkm, CLK_SOURCE_I2C2, 54, &periph_h_regs, i2c2),
+ TEGRA_INIT_DATA_I2C("i2c3", "div-clk", "tegra11-i2c.2", mux_pllp_clkm, CLK_SOURCE_I2C3, 67, &periph_u_regs, i2c3),
+ TEGRA_INIT_DATA_I2C("i2c4", "div-clk", "tegra11-i2c.3", mux_pllp_clkm, CLK_SOURCE_I2C4, 103, &periph_v_regs, i2c4),
+ TEGRA_INIT_DATA_I2C("i2c5", "div-clk", "tegra11-i2c.4", mux_pllp_clkm, CLK_SOURCE_I2C5, 47, &periph_h_regs, i2c5),
+ TEGRA_INIT_DATA_UART("uarta", NULL, "tegra_uart.0", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTA, 6, &periph_l_regs, uarta),
+ TEGRA_INIT_DATA_UART("uartb", NULL, "tegra_uart.1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTB, 7, &periph_l_regs, uartb),
+ TEGRA_INIT_DATA_UART("uartc", NULL, "tegra_uart.2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTC, 55, &periph_h_regs, uartc),
+ TEGRA_INIT_DATA_UART("uartd", NULL, "tegra_uart.3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTD, 65, &periph_u_regs, uartd),
+ TEGRA_INIT_DATA_INT("3d", NULL, "3d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_3D, 24, &periph_l_regs, 0, gr_3d),
+ TEGRA_INIT_DATA_INT("2d", NULL, "2d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_2D, 21, &periph_l_regs, 0, gr_2d),
+ TEGRA_INIT_DATA_MUX("vi_sensor", "vi_sensor", "tegra_camera", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR, 20, &periph_l_regs, TEGRA_PERIPH_NO_RESET, vi_sensor),
+ TEGRA_INIT_DATA_INT8("vi", "vi", "tegra_camera", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI, 20, &periph_l_regs, 0, vi),
+ TEGRA_INIT_DATA_INT8("epp", NULL, "epp", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_EPP, 19, &periph_l_regs, 0, epp),
+ TEGRA_INIT_DATA_INT8("msenc", NULL, "msenc", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_MSENC, 91, &periph_h_regs, TEGRA_PERIPH_WAR_1005168, msenc),
+ TEGRA_INIT_DATA_INT8("tsec", NULL, "tsec", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_TSEC, 83, &periph_u_regs, 0, tsec),
+ TEGRA_INIT_DATA_INT8("host1x", NULL, "host1x", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_HOST1X, 28, &periph_l_regs, 0, host1x),
+ TEGRA_INIT_DATA_MUX8("hdmi", NULL, "hdmi", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_HDMI, 51, &periph_h_regs, 0, hdmi),
+ TEGRA_INIT_DATA_MUX("cilab", "cilab", "tegra_camera", mux_pllp_pllc_clkm, CLK_SOURCE_CILAB, 144, &periph_w_regs, 0, cilab),
+ TEGRA_INIT_DATA_MUX("cilcd", "cilcd", "tegra_camera", mux_pllp_pllc_clkm, CLK_SOURCE_CILCD, 145, &periph_w_regs, 0, cilcd),
+ TEGRA_INIT_DATA_MUX("cile", "cile", "tegra_camera", mux_pllp_pllc_clkm, CLK_SOURCE_CILE, 146, &periph_w_regs, 0, cile),
+ TEGRA_INIT_DATA_MUX("dsialp", "dsialp", "tegradc.0", mux_pllp_pllc_clkm, CLK_SOURCE_DSIALP, 147, &periph_w_regs, 0, dsialp),
+ TEGRA_INIT_DATA_MUX("dsiblp", "dsiblp", "tegradc.1", mux_pllp_pllc_clkm, CLK_SOURCE_DSIBLP, 148, &periph_w_regs, 0, dsiblp),
+ TEGRA_INIT_DATA_MUX("tsensor", NULL, "tegra-tsensor", mux_pllp_pllc_clkm_clk32, CLK_SOURCE_TSENSOR, 100, &periph_v_regs, TEGRA_PERIPH_ON_APB, tsensor),
+ TEGRA_INIT_DATA_MUX("actmon", NULL, "actmon", mux_pllp_pllc_clk32_clkm, CLK_SOURCE_ACTMON, 119, &periph_v_regs, 0, actmon),
+ TEGRA_INIT_DATA_MUX8("extern1", NULL, "extern1", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN1, 120, &periph_v_regs, 0, extern1),
+ TEGRA_INIT_DATA_MUX8("extern2", NULL, "extern2", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN2, 121, &periph_v_regs, 0, extern2),
+ TEGRA_INIT_DATA_MUX8("extern3", NULL, "extern3", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN3, 122, &periph_v_regs, 0, extern3),
+ TEGRA_INIT_DATA_MUX("i2cslow", NULL, "i2cslow", mux_pllp_pllc_clk32_clkm, CLK_SOURCE_I2CSLOW, 81, &periph_u_regs, TEGRA_PERIPH_ON_APB, i2cslow),
+ TEGRA_INIT_DATA_INT8("se", NULL, "se", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SE, 127, &periph_v_regs, TEGRA_PERIPH_ON_APB, se),
+ TEGRA_INIT_DATA_INT_FLAGS("mselect", NULL, "mselect", mux_pllp_clkm, CLK_SOURCE_MSELECT, 99, &periph_v_regs, 0, mselect, CLK_IGNORE_UNUSED),
+ TEGRA_INIT_DATA_MUX8("soc_therm", NULL, "soc_therm", mux_pllm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, &periph_u_regs, TEGRA_PERIPH_ON_APB, soc_therm),
+ TEGRA_INIT_DATA_XUSB("xusb_host_src", "host_src", "tegra_xhci", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_HOST_SRC, 143, &periph_w_regs, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, xusb_host_src),
+ TEGRA_INIT_DATA_XUSB("xusb_falcon_src", "falcon_src", "tegra_xhci", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, &periph_w_regs, TEGRA_PERIPH_NO_RESET, xusb_falcon_src),
+ TEGRA_INIT_DATA_XUSB("xusb_fs_src", "fs_src", "tegra_xhci", mux_clkm_48M_pllp_480M, CLK_SOURCE_XUSB_FS_SRC, 143, &periph_w_regs, TEGRA_PERIPH_NO_RESET, xusb_fs_src),
+ TEGRA_INIT_DATA_XUSB("xusb_ss_src", "ss_src", "tegra_xhci", mux_clkm_pllre_clk32_480M_pllc_ref, CLK_SOURCE_XUSB_SS_SRC, 143, &periph_w_regs, TEGRA_PERIPH_NO_RESET, xusb_ss_src),
+ TEGRA_INIT_DATA_XUSB("xusb_dev_src", "dev_src", "tegra_xhci", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, &periph_u_regs, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, xusb_dev_src),
+ TEGRA_INIT_DATA_AUDIO("d_audio", "d_audio", "tegra30-ahub", CLK_SOURCE_D_AUDIO, 106, &periph_v_regs, TEGRA_PERIPH_ON_APB, d_audio),
+ TEGRA_INIT_DATA_AUDIO("dam0", NULL, "tegra30-dam.0", CLK_SOURCE_DAM0, 108, &periph_v_regs, TEGRA_PERIPH_ON_APB, dam0),
+ TEGRA_INIT_DATA_AUDIO("dam1", NULL, "tegra30-dam.1", CLK_SOURCE_DAM1, 109, &periph_v_regs, TEGRA_PERIPH_ON_APB, dam1),
+ TEGRA_INIT_DATA_AUDIO("dam2", NULL, "tegra30-dam.2", CLK_SOURCE_DAM2, 110, &periph_v_regs, TEGRA_PERIPH_ON_APB, dam2),
+};
+
+static struct tegra_periph_init_data tegra_periph_nodiv_clk_list[] = {
+ TEGRA_INIT_DATA_NODIV("disp1", NULL, "tegradc.0", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_DISP1, 29, 7, 27, &periph_l_regs, 0, disp1),
+ TEGRA_INIT_DATA_NODIV("disp2", NULL, "tegradc.1", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_DISP2, 29, 7, 26, &periph_l_regs, 0, disp2),
+};
+
+static __init void tegra114_periph_clk_init(void __iomem *clk_base)
+{
+ struct tegra_periph_init_data *data;
+ struct clk *clk;
+ int i;
+ u32 val;
+
+ /* apbdma */
+ clk = tegra_clk_register_periph_gate("apbdma", "clk_m", 0, clk_base,
+ 0, 34, &periph_h_regs,
+ periph_clk_enb_refcnt);
+ clks[apbdma] = clk;
+
+ /* rtc */
+ clk = tegra_clk_register_periph_gate("rtc", "clk_32k",
+ TEGRA_PERIPH_ON_APB |
+ TEGRA_PERIPH_NO_RESET, clk_base,
+ 0, 4, &periph_l_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, NULL, "rtc-tegra");
+ clks[rtc] = clk;
+
+ /* kbc */
+ clk = tegra_clk_register_periph_gate("kbc", "clk_32k",
+ TEGRA_PERIPH_ON_APB |
+ TEGRA_PERIPH_NO_RESET, clk_base,
+ 0, 36, &periph_h_regs,
+ periph_clk_enb_refcnt);
+ clks[kbc] = clk;
+
+ /* timer */
+ clk = tegra_clk_register_periph_gate("timer", "clk_m", 0, clk_base,
+ 0, 5, &periph_l_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, NULL, "timer");
+ clks[timer] = clk;
+
+ /* kfuse */
+ clk = tegra_clk_register_periph_gate("kfuse", "clk_m",
+ TEGRA_PERIPH_ON_APB, clk_base, 0, 40,
+ &periph_h_regs, periph_clk_enb_refcnt);
+ clks[kfuse] = clk;
+
+ /* fuse */
+ clk = tegra_clk_register_periph_gate("fuse", "clk_m",
+ TEGRA_PERIPH_ON_APB, clk_base, 0, 39,
+ &periph_h_regs, periph_clk_enb_refcnt);
+ clks[fuse] = clk;
+
+ /* fuse_burn */
+ clk = tegra_clk_register_periph_gate("fuse_burn", "clk_m",
+ TEGRA_PERIPH_ON_APB, clk_base, 0, 39,
+ &periph_h_regs, periph_clk_enb_refcnt);
+ clks[fuse_burn] = clk;
+
+ /* apbif */
+ clk = tegra_clk_register_periph_gate("apbif", "clk_m",
+ TEGRA_PERIPH_ON_APB, clk_base, 0, 107,
+ &periph_v_regs, periph_clk_enb_refcnt);
+ clks[apbif] = clk;
+
+ /* hda2hdmi */
+ clk = tegra_clk_register_periph_gate("hda2hdmi", "clk_m",
+ TEGRA_PERIPH_ON_APB, clk_base, 0, 128,
+ &periph_w_regs, periph_clk_enb_refcnt);
+ clks[hda2hdmi] = clk;
+
+ /* vcp */
+ clk = tegra_clk_register_periph_gate("vcp", "clk_m", 0, clk_base, 0,
+ 29, &periph_l_regs,
+ periph_clk_enb_refcnt);
+ clks[vcp] = clk;
+
+ /* bsea */
+ clk = tegra_clk_register_periph_gate("bsea", "clk_m", 0, clk_base,
+ 0, 62, &periph_h_regs,
+ periph_clk_enb_refcnt);
+ clks[bsea] = clk;
+
+ /* bsev */
+ clk = tegra_clk_register_periph_gate("bsev", "clk_m", 0, clk_base,
+ 0, 63, &periph_h_regs,
+ periph_clk_enb_refcnt);
+ clks[bsev] = clk;
+
+ /* mipi-cal */
+ clk = tegra_clk_register_periph_gate("mipi-cal", "clk_m", 0, clk_base,
+ 0, 56, &periph_h_regs,
+ periph_clk_enb_refcnt);
+ clks[mipi_cal] = clk;
+
+ /* usbd */
+ clk = tegra_clk_register_periph_gate("usbd", "clk_m", 0, clk_base,
+ 0, 22, &periph_l_regs,
+ periph_clk_enb_refcnt);
+ clks[usbd] = clk;
+
+ /* usb2 */
+ clk = tegra_clk_register_periph_gate("usb2", "clk_m", 0, clk_base,
+ 0, 58, &periph_h_regs,
+ periph_clk_enb_refcnt);
+ clks[usb2] = clk;
+
+ /* usb3 */
+ clk = tegra_clk_register_periph_gate("usb3", "clk_m", 0, clk_base,
+ 0, 59, &periph_h_regs,
+ periph_clk_enb_refcnt);
+ clks[usb3] = clk;
+
+ /* csi */
+ clk = tegra_clk_register_periph_gate("csi", "pll_p_out3", 0, clk_base,
+ 0, 52, &periph_h_regs,
+ periph_clk_enb_refcnt);
+ clks[csi] = clk;
+
+ /* isp */
+ clk = tegra_clk_register_periph_gate("isp", "clk_m", 0, clk_base, 0,
+ 23, &periph_l_regs,
+ periph_clk_enb_refcnt);
+ clks[isp] = clk;
+
+ /* csus */
+ clk = tegra_clk_register_periph_gate("csus", "clk_m",
+ TEGRA_PERIPH_NO_RESET, clk_base, 0, 92,
+ &periph_u_regs, periph_clk_enb_refcnt);
+ clks[csus] = clk;
+
+ /* dds */
+ clk = tegra_clk_register_periph_gate("dds", "clk_m",
+ TEGRA_PERIPH_ON_APB, clk_base, 0, 150,
+ &periph_w_regs, periph_clk_enb_refcnt);
+ clks[dds] = clk;
+
+ /* dp2 */
+ clk = tegra_clk_register_periph_gate("dp2", "clk_m",
+ TEGRA_PERIPH_ON_APB, clk_base, 0, 152,
+ &periph_w_regs, periph_clk_enb_refcnt);
+ clks[dp2] = clk;
+
+ /* dtv */
+ clk = tegra_clk_register_periph_gate("dtv", "clk_m",
+ TEGRA_PERIPH_ON_APB, clk_base, 0, 79,
+ &periph_u_regs, periph_clk_enb_refcnt);
+ clks[dtv] = clk;
+
+ /* dsia */
+ clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0,
+ ARRAY_SIZE(mux_plld_out0_plld2_out0), 0,
+ clk_base + PLLD_BASE, 25, 1, 0, &pll_d_lock);
+ clks[dsia_mux] = clk;
+ clk = tegra_clk_register_periph_gate("dsia", "dsia_mux", 0, clk_base,
+ 0, 48, &periph_h_regs,
+ periph_clk_enb_refcnt);
+ clks[dsia] = clk;
+
+ /* dsib */
+ clk = clk_register_mux(NULL, "dsib_mux", mux_plld_out0_plld2_out0,
+ ARRAY_SIZE(mux_plld_out0_plld2_out0), 0,
+ clk_base + PLLD2_BASE, 25, 1, 0, &pll_d2_lock);
+ clks[dsib_mux] = clk;
+ clk = tegra_clk_register_periph_gate("dsib", "dsib_mux", 0, clk_base,
+ 0, 82, &periph_u_regs,
+ periph_clk_enb_refcnt);
+ clks[dsib] = clk;
+
+ /* xusb_hs_src */
+ val = readl(clk_base + CLK_SOURCE_XUSB_SS_SRC);
+ val |= BIT(25); /* always select PLLU_60M */
+ writel(val, clk_base + CLK_SOURCE_XUSB_SS_SRC);
+
+ clk = clk_register_fixed_factor(NULL, "xusb_hs_src", "pll_u_60M", 0,
+ 1, 1);
+ clks[xusb_hs_src] = clk;
+
+ /* xusb_host */
+ clk = tegra_clk_register_periph_gate("xusb_host", "xusb_host_src", 0,
+ clk_base, 0, 89, &periph_u_regs,
+ periph_clk_enb_refcnt);
+ clks[xusb_host] = clk;
+
+ /* xusb_ss */
+ clk = tegra_clk_register_periph_gate("xusb_ss", "xusb_ss_src", 0,
+ clk_base, 0, 156, &periph_w_regs,
+ periph_clk_enb_refcnt);
+ clks[xusb_host] = clk;
+
+ /* xusb_dev */
+ clk = tegra_clk_register_periph_gate("xusb_dev", "xusb_dev_src", 0,
+ clk_base, 0, 95, &periph_u_regs,
+ periph_clk_enb_refcnt);
+ clks[xusb_dev] = clk;
+
+ /* emc */
+ clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
+ ARRAY_SIZE(mux_pllmcp_clkm), 0,
+ clk_base + CLK_SOURCE_EMC,
+ 29, 3, 0, NULL);
+ clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base,
+ CLK_IGNORE_UNUSED, 57, &periph_h_regs,
+ periph_clk_enb_refcnt);
+ clks[emc] = clk;
+
+ for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) {
+ data = &tegra_periph_clk_list[i];
+ clk = tegra_clk_register_periph(data->name, data->parent_names,
+ data->num_parents, &data->periph,
+ clk_base, data->offset, data->flags);
+ clks[data->clk_id] = clk;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(tegra_periph_nodiv_clk_list); i++) {
+ data = &tegra_periph_nodiv_clk_list[i];
+ clk = tegra_clk_register_periph_nodiv(data->name,
+ data->parent_names, data->num_parents,
+ &data->periph, clk_base, data->offset);
+ clks[data->clk_id] = clk;
+ }
+}
+
+static struct tegra_cpu_car_ops tegra114_cpu_car_ops;
+
+static const struct of_device_id pmc_match[] __initconst = {
+ { .compatible = "nvidia,tegra114-pmc" },
+ {},
+};
+
+static __initdata struct tegra_clk_init_table init_table[] = {
+ {uarta, pll_p, 408000000, 0},
+ {uartb, pll_p, 408000000, 0},
+ {uartc, pll_p, 408000000, 0},
+ {uartd, pll_p, 408000000, 0},
+ {pll_a, clk_max, 564480000, 1},
+ {pll_a_out0, clk_max, 11289600, 1},
+ {extern1, pll_a_out0, 0, 1},
+ {clk_out_1_mux, extern1, 0, 1},
+ {clk_out_1, clk_max, 0, 1},
+ {i2s0, pll_a_out0, 11289600, 0},
+ {i2s1, pll_a_out0, 11289600, 0},
+ {i2s2, pll_a_out0, 11289600, 0},
+ {i2s3, pll_a_out0, 11289600, 0},
+ {i2s4, pll_a_out0, 11289600, 0},
+ {clk_max, clk_max, 0, 0}, /* This MUST be the last entry. */
+};
+
+static void __init tegra114_clock_apply_init_table(void)
+{
+ tegra_init_from_table(init_table, clks, clk_max);
+}
+
+void __init tegra114_clock_init(struct device_node *np)
+{
+ struct device_node *node;
+ int i;
+
+ clk_base = of_iomap(np, 0);
+ if (!clk_base) {
+ pr_err("ioremap tegra114 CAR failed\n");
+ return;
+ }
+
+ node = of_find_matching_node(NULL, pmc_match);
+ if (!node) {
+ pr_err("Failed to find pmc node\n");
+ WARN_ON(1);
+ return;
+ }
+
+ pmc_base = of_iomap(node, 0);
+ if (!pmc_base) {
+ pr_err("Can't map pmc registers\n");
+ WARN_ON(1);
+ return;
+ }
+
+ if (tegra114_osc_clk_init(clk_base) < 0)
+ return;
+
+ tegra114_fixed_clk_init(clk_base);
+ tegra114_pll_init(clk_base, pmc_base);
+ tegra114_periph_clk_init(clk_base);
+ tegra114_audio_clk_init(clk_base);
+ tegra114_pmc_clk_init(pmc_base);
+ tegra114_super_clk_init(clk_base);
+
+ for (i = 0; i < ARRAY_SIZE(clks); i++) {
+ if (IS_ERR(clks[i])) {
+ pr_err
+ ("Tegra114 clk %d: register failed with %ld\n",
+ i, PTR_ERR(clks[i]));
+ }
+ if (!clks[i])
+ clks[i] = ERR_PTR(-EINVAL);
+ }
+
+ clk_data.clks = clks;
+ clk_data.clk_num = ARRAY_SIZE(clks);
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+
+ tegra_clk_apply_init_table = tegra114_clock_apply_init_table;
+
+ tegra_cpu_car_ops = &tegra114_cpu_car_ops;
+}
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
index bf194009e20f..8292a00c3de9 100644
--- a/drivers/clk/tegra/clk-tegra20.c
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -86,8 +86,8 @@
#define PLLE_BASE 0xe8
#define PLLE_MISC 0xec
-#define PLL_BASE_LOCK 27
-#define PLLE_MISC_LOCK 11
+#define PLL_BASE_LOCK BIT(27)
+#define PLLE_MISC_LOCK BIT(11)
#define PLL_MISC_LOCK_ENABLE 18
#define PLLDU_MISC_LOCK_ENABLE 22
@@ -236,7 +236,7 @@ enum tegra20_clk {
dvc, dsi, mipi = 50, hdmi, csi, tvdac, i2c2, uartc, emc = 57, usb2,
usb3, mpe, vde, bsea, bsev, speedo, uartd, uarte, i2c3, sbc4, sdmmc3,
pex, owr, afi, csite, pcie_xclk, avpucq = 75, la, irama = 84, iramb,
- iramc, iramd, cram2, audio_2x, clk_d, csus = 92, cdev1, cdev2,
+ iramc, iramd, cram2, audio_2x, clk_d, csus = 92, cdev2, cdev1,
uartb = 96, vfir, spdif_in, spdif_out, vi, vi_sensor, tvo, cve,
osc, clk_32k, clk_m, sclk, cclk, hclk, pclk, blink, pll_a, pll_a_out0,
pll_c, pll_c_out1, pll_d, pll_d_out0, pll_e, pll_m, pll_m_out1,
@@ -248,125 +248,125 @@ static struct clk *clks[clk_max];
static struct clk_onecell_data clk_data;
static struct tegra_clk_pll_freq_table pll_c_freq_table[] = {
- { 12000000, 600000000, 600, 12, 1, 8 },
- { 13000000, 600000000, 600, 13, 1, 8 },
- { 19200000, 600000000, 500, 16, 1, 6 },
- { 26000000, 600000000, 600, 26, 1, 8 },
+ { 12000000, 600000000, 600, 12, 0, 8 },
+ { 13000000, 600000000, 600, 13, 0, 8 },
+ { 19200000, 600000000, 500, 16, 0, 6 },
+ { 26000000, 600000000, 600, 26, 0, 8 },
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_m_freq_table[] = {
- { 12000000, 666000000, 666, 12, 1, 8},
- { 13000000, 666000000, 666, 13, 1, 8},
- { 19200000, 666000000, 555, 16, 1, 8},
- { 26000000, 666000000, 666, 26, 1, 8},
- { 12000000, 600000000, 600, 12, 1, 8},
- { 13000000, 600000000, 600, 13, 1, 8},
- { 19200000, 600000000, 375, 12, 1, 6},
- { 26000000, 600000000, 600, 26, 1, 8},
+ { 12000000, 666000000, 666, 12, 0, 8},
+ { 13000000, 666000000, 666, 13, 0, 8},
+ { 19200000, 666000000, 555, 16, 0, 8},
+ { 26000000, 666000000, 666, 26, 0, 8},
+ { 12000000, 600000000, 600, 12, 0, 8},
+ { 13000000, 600000000, 600, 13, 0, 8},
+ { 19200000, 600000000, 375, 12, 0, 6},
+ { 26000000, 600000000, 600, 26, 0, 8},
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
- { 12000000, 216000000, 432, 12, 2, 8},
- { 13000000, 216000000, 432, 13, 2, 8},
- { 19200000, 216000000, 90, 4, 2, 1},
- { 26000000, 216000000, 432, 26, 2, 8},
- { 12000000, 432000000, 432, 12, 1, 8},
- { 13000000, 432000000, 432, 13, 1, 8},
- { 19200000, 432000000, 90, 4, 1, 1},
- { 26000000, 432000000, 432, 26, 1, 8},
+ { 12000000, 216000000, 432, 12, 1, 8},
+ { 13000000, 216000000, 432, 13, 1, 8},
+ { 19200000, 216000000, 90, 4, 1, 1},
+ { 26000000, 216000000, 432, 26, 1, 8},
+ { 12000000, 432000000, 432, 12, 0, 8},
+ { 13000000, 432000000, 432, 13, 0, 8},
+ { 19200000, 432000000, 90, 4, 0, 1},
+ { 26000000, 432000000, 432, 26, 0, 8},
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
- { 28800000, 56448000, 49, 25, 1, 1},
- { 28800000, 73728000, 64, 25, 1, 1},
- { 28800000, 24000000, 5, 6, 1, 1},
+ { 28800000, 56448000, 49, 25, 0, 1},
+ { 28800000, 73728000, 64, 25, 0, 1},
+ { 28800000, 24000000, 5, 6, 0, 1},
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
- { 12000000, 216000000, 216, 12, 1, 4},
- { 13000000, 216000000, 216, 13, 1, 4},
- { 19200000, 216000000, 135, 12, 1, 3},
- { 26000000, 216000000, 216, 26, 1, 4},
+ { 12000000, 216000000, 216, 12, 0, 4},
+ { 13000000, 216000000, 216, 13, 0, 4},
+ { 19200000, 216000000, 135, 12, 0, 3},
+ { 26000000, 216000000, 216, 26, 0, 4},
- { 12000000, 594000000, 594, 12, 1, 8},
- { 13000000, 594000000, 594, 13, 1, 8},
- { 19200000, 594000000, 495, 16, 1, 8},
- { 26000000, 594000000, 594, 26, 1, 8},
+ { 12000000, 594000000, 594, 12, 0, 8},
+ { 13000000, 594000000, 594, 13, 0, 8},
+ { 19200000, 594000000, 495, 16, 0, 8},
+ { 26000000, 594000000, 594, 26, 0, 8},
- { 12000000, 1000000000, 1000, 12, 1, 12},
- { 13000000, 1000000000, 1000, 13, 1, 12},
- { 19200000, 1000000000, 625, 12, 1, 8},
- { 26000000, 1000000000, 1000, 26, 1, 12},
+ { 12000000, 1000000000, 1000, 12, 0, 12},
+ { 13000000, 1000000000, 1000, 13, 0, 12},
+ { 19200000, 1000000000, 625, 12, 0, 8},
+ { 26000000, 1000000000, 1000, 26, 0, 12},
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
- { 12000000, 480000000, 960, 12, 2, 0},
- { 13000000, 480000000, 960, 13, 2, 0},
- { 19200000, 480000000, 200, 4, 2, 0},
- { 26000000, 480000000, 960, 26, 2, 0},
+ { 12000000, 480000000, 960, 12, 0, 0},
+ { 13000000, 480000000, 960, 13, 0, 0},
+ { 19200000, 480000000, 200, 4, 0, 0},
+ { 26000000, 480000000, 960, 26, 0, 0},
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
/* 1 GHz */
- { 12000000, 1000000000, 1000, 12, 1, 12},
- { 13000000, 1000000000, 1000, 13, 1, 12},
- { 19200000, 1000000000, 625, 12, 1, 8},
- { 26000000, 1000000000, 1000, 26, 1, 12},
+ { 12000000, 1000000000, 1000, 12, 0, 12},
+ { 13000000, 1000000000, 1000, 13, 0, 12},
+ { 19200000, 1000000000, 625, 12, 0, 8},
+ { 26000000, 1000000000, 1000, 26, 0, 12},
/* 912 MHz */
- { 12000000, 912000000, 912, 12, 1, 12},
- { 13000000, 912000000, 912, 13, 1, 12},
- { 19200000, 912000000, 760, 16, 1, 8},
- { 26000000, 912000000, 912, 26, 1, 12},
+ { 12000000, 912000000, 912, 12, 0, 12},
+ { 13000000, 912000000, 912, 13, 0, 12},
+ { 19200000, 912000000, 760, 16, 0, 8},
+ { 26000000, 912000000, 912, 26, 0, 12},
/* 816 MHz */
- { 12000000, 816000000, 816, 12, 1, 12},
- { 13000000, 816000000, 816, 13, 1, 12},
- { 19200000, 816000000, 680, 16, 1, 8},
- { 26000000, 816000000, 816, 26, 1, 12},
+ { 12000000, 816000000, 816, 12, 0, 12},
+ { 13000000, 816000000, 816, 13, 0, 12},
+ { 19200000, 816000000, 680, 16, 0, 8},
+ { 26000000, 816000000, 816, 26, 0, 12},
/* 760 MHz */
- { 12000000, 760000000, 760, 12, 1, 12},
- { 13000000, 760000000, 760, 13, 1, 12},
- { 19200000, 760000000, 950, 24, 1, 8},
- { 26000000, 760000000, 760, 26, 1, 12},
+ { 12000000, 760000000, 760, 12, 0, 12},
+ { 13000000, 760000000, 760, 13, 0, 12},
+ { 19200000, 760000000, 950, 24, 0, 8},
+ { 26000000, 760000000, 760, 26, 0, 12},
/* 750 MHz */
- { 12000000, 750000000, 750, 12, 1, 12},
- { 13000000, 750000000, 750, 13, 1, 12},
- { 19200000, 750000000, 625, 16, 1, 8},
- { 26000000, 750000000, 750, 26, 1, 12},
+ { 12000000, 750000000, 750, 12, 0, 12},
+ { 13000000, 750000000, 750, 13, 0, 12},
+ { 19200000, 750000000, 625, 16, 0, 8},
+ { 26000000, 750000000, 750, 26, 0, 12},
/* 608 MHz */
- { 12000000, 608000000, 608, 12, 1, 12},
- { 13000000, 608000000, 608, 13, 1, 12},
- { 19200000, 608000000, 380, 12, 1, 8},
- { 26000000, 608000000, 608, 26, 1, 12},
+ { 12000000, 608000000, 608, 12, 0, 12},
+ { 13000000, 608000000, 608, 13, 0, 12},
+ { 19200000, 608000000, 380, 12, 0, 8},
+ { 26000000, 608000000, 608, 26, 0, 12},
/* 456 MHz */
- { 12000000, 456000000, 456, 12, 1, 12},
- { 13000000, 456000000, 456, 13, 1, 12},
- { 19200000, 456000000, 380, 16, 1, 8},
- { 26000000, 456000000, 456, 26, 1, 12},
+ { 12000000, 456000000, 456, 12, 0, 12},
+ { 13000000, 456000000, 456, 13, 0, 12},
+ { 19200000, 456000000, 380, 16, 0, 8},
+ { 26000000, 456000000, 456, 26, 0, 12},
/* 312 MHz */
- { 12000000, 312000000, 312, 12, 1, 12},
- { 13000000, 312000000, 312, 13, 1, 12},
- { 19200000, 312000000, 260, 16, 1, 8},
- { 26000000, 312000000, 312, 26, 1, 12},
+ { 12000000, 312000000, 312, 12, 0, 12},
+ { 13000000, 312000000, 312, 13, 0, 12},
+ { 19200000, 312000000, 260, 16, 0, 8},
+ { 26000000, 312000000, 312, 26, 0, 12},
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
- { 12000000, 100000000, 200, 24, 1, 0 },
+ { 12000000, 100000000, 200, 24, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
};
@@ -380,7 +380,7 @@ static struct tegra_clk_pll_params pll_c_params = {
.vco_max = 1400000000,
.base_reg = PLLC_BASE,
.misc_reg = PLLC_MISC,
- .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
};
@@ -394,7 +394,7 @@ static struct tegra_clk_pll_params pll_m_params = {
.vco_max = 1200000000,
.base_reg = PLLM_BASE,
.misc_reg = PLLM_MISC,
- .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
};
@@ -408,7 +408,7 @@ static struct tegra_clk_pll_params pll_p_params = {
.vco_max = 1400000000,
.base_reg = PLLP_BASE,
.misc_reg = PLLP_MISC,
- .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
};
@@ -422,7 +422,7 @@ static struct tegra_clk_pll_params pll_a_params = {
.vco_max = 1400000000,
.base_reg = PLLA_BASE,
.misc_reg = PLLA_MISC,
- .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
};
@@ -436,11 +436,17 @@ static struct tegra_clk_pll_params pll_d_params = {
.vco_max = 1000000000,
.base_reg = PLLD_BASE,
.misc_reg = PLLD_MISC,
- .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
.lock_delay = 1000,
};
+static struct pdiv_map pllu_p[] = {
+ { .pdiv = 1, .hw_val = 1 },
+ { .pdiv = 2, .hw_val = 0 },
+ { .pdiv = 0, .hw_val = 0 },
+};
+
static struct tegra_clk_pll_params pll_u_params = {
.input_min = 2000000,
.input_max = 40000000,
@@ -450,9 +456,10 @@ static struct tegra_clk_pll_params pll_u_params = {
.vco_max = 960000000,
.base_reg = PLLU_BASE,
.misc_reg = PLLU_MISC,
- .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
.lock_delay = 1000,
+ .pdiv_tohw = pllu_p,
};
static struct tegra_clk_pll_params pll_x_params = {
@@ -464,7 +471,7 @@ static struct tegra_clk_pll_params pll_x_params = {
.vco_max = 1200000000,
.base_reg = PLLX_BASE,
.misc_reg = PLLX_MISC,
- .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
};
@@ -478,7 +485,7 @@ static struct tegra_clk_pll_params pll_e_params = {
.vco_max = 0,
.base_reg = PLLE_BASE,
.misc_reg = PLLE_MISC,
- .lock_bit_idx = PLLE_MISC_LOCK,
+ .lock_mask = PLLE_MISC_LOCK,
.lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
.lock_delay = 0,
};
@@ -1012,7 +1019,7 @@ static void __init tegra20_periph_clk_init(void)
data = &tegra_periph_clk_list[i];
clk = tegra_clk_register_periph(data->name, data->parent_names,
data->num_parents, &data->periph,
- clk_base, data->offset);
+ clk_base, data->offset, data->flags);
clk_register_clkdev(clk, data->con_id, data->dev_id);
clks[data->clk_id] = clk;
}
@@ -1247,9 +1254,16 @@ static __initdata struct tegra_clk_init_table init_table[] = {
{host1x, pll_c, 150000000, 0},
{disp1, pll_p, 600000000, 0},
{disp2, pll_p, 600000000, 0},
+ {gr2d, pll_c, 300000000, 0},
+ {gr3d, pll_c, 300000000, 0},
{clk_max, clk_max, 0, 0}, /* This MUST be the last entry */
};
+static void __init tegra20_clock_apply_init_table(void)
+{
+ tegra_init_from_table(init_table, clks, clk_max);
+}
+
/*
* Some clocks may be used by different drivers depending on the board
* configuration. List those here to register them twice in the clock lookup
@@ -1316,7 +1330,7 @@ void __init tegra20_clock_init(struct device_node *np)
clk_data.clk_num = ARRAY_SIZE(clks);
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
- tegra_init_from_table(init_table, clks, clk_max);
+ tegra_clk_apply_init_table = tegra20_clock_apply_init_table;
tegra_cpu_car_ops = &tegra20_cpu_car_ops;
}
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index f15f147d473c..c6921f538e28 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -115,8 +115,8 @@
#define PLLDU_MISC_LOCK_ENABLE 22
#define PLLE_MISC_LOCK_ENABLE 9
-#define PLL_BASE_LOCK 27
-#define PLLE_MISC_LOCK 11
+#define PLL_BASE_LOCK BIT(27)
+#define PLLE_MISC_LOCK BIT(11)
#define PLLE_AUX 0x48c
#define PLLC_OUT 0x84
@@ -329,7 +329,7 @@ enum tegra30_clk {
usb3, mpe, vde, bsea, bsev, speedo, uartd, uarte, i2c3, sbc4, sdmmc3,
pcie, owr, afi, csite, pciex, avpucq, la, dtv = 79, ndspeed, i2cslow,
dsib, irama = 84, iramb, iramc, iramd, cram2, audio_2x = 90, csus = 92,
- cdev1, cdev2, cpu_g = 96, cpu_lp, gr3d2, mselect, tsensor, i2s3, i2s4,
+ cdev2, cdev1, cpu_g = 96, cpu_lp, gr3d2, mselect, tsensor, i2s3, i2s4,
i2c4, sbc5, sbc6, d_audio, apbif, dam0, dam1, dam2, hda2codec_2x,
atomics, audio0_2x, audio1_2x, audio2_2x, audio3_2x, audio4_2x,
spdif_2x, actmon, extern1, extern2, extern3, sata_oob, sata, hda,
@@ -373,164 +373,170 @@ static const struct utmi_clk_param utmi_parameters[] = {
};
static struct tegra_clk_pll_freq_table pll_c_freq_table[] = {
- { 12000000, 1040000000, 520, 6, 1, 8},
- { 13000000, 1040000000, 480, 6, 1, 8},
- { 16800000, 1040000000, 495, 8, 1, 8}, /* actual: 1039.5 MHz */
- { 19200000, 1040000000, 325, 6, 1, 6},
- { 26000000, 1040000000, 520, 13, 1, 8},
-
- { 12000000, 832000000, 416, 6, 1, 8},
- { 13000000, 832000000, 832, 13, 1, 8},
- { 16800000, 832000000, 396, 8, 1, 8}, /* actual: 831.6 MHz */
- { 19200000, 832000000, 260, 6, 1, 8},
- { 26000000, 832000000, 416, 13, 1, 8},
-
- { 12000000, 624000000, 624, 12, 1, 8},
- { 13000000, 624000000, 624, 13, 1, 8},
- { 16800000, 600000000, 520, 14, 1, 8},
- { 19200000, 624000000, 520, 16, 1, 8},
- { 26000000, 624000000, 624, 26, 1, 8},
-
- { 12000000, 600000000, 600, 12, 1, 8},
- { 13000000, 600000000, 600, 13, 1, 8},
- { 16800000, 600000000, 500, 14, 1, 8},
- { 19200000, 600000000, 375, 12, 1, 6},
- { 26000000, 600000000, 600, 26, 1, 8},
-
- { 12000000, 520000000, 520, 12, 1, 8},
- { 13000000, 520000000, 520, 13, 1, 8},
- { 16800000, 520000000, 495, 16, 1, 8}, /* actual: 519.75 MHz */
- { 19200000, 520000000, 325, 12, 1, 6},
- { 26000000, 520000000, 520, 26, 1, 8},
-
- { 12000000, 416000000, 416, 12, 1, 8},
- { 13000000, 416000000, 416, 13, 1, 8},
- { 16800000, 416000000, 396, 16, 1, 8}, /* actual: 415.8 MHz */
- { 19200000, 416000000, 260, 12, 1, 6},
- { 26000000, 416000000, 416, 26, 1, 8},
+ { 12000000, 1040000000, 520, 6, 0, 8},
+ { 13000000, 1040000000, 480, 6, 0, 8},
+ { 16800000, 1040000000, 495, 8, 0, 8}, /* actual: 1039.5 MHz */
+ { 19200000, 1040000000, 325, 6, 0, 6},
+ { 26000000, 1040000000, 520, 13, 0, 8},
+
+ { 12000000, 832000000, 416, 6, 0, 8},
+ { 13000000, 832000000, 832, 13, 0, 8},
+ { 16800000, 832000000, 396, 8, 0, 8}, /* actual: 831.6 MHz */
+ { 19200000, 832000000, 260, 6, 0, 8},
+ { 26000000, 832000000, 416, 13, 0, 8},
+
+ { 12000000, 624000000, 624, 12, 0, 8},
+ { 13000000, 624000000, 624, 13, 0, 8},
+ { 16800000, 600000000, 520, 14, 0, 8},
+ { 19200000, 624000000, 520, 16, 0, 8},
+ { 26000000, 624000000, 624, 26, 0, 8},
+
+ { 12000000, 600000000, 600, 12, 0, 8},
+ { 13000000, 600000000, 600, 13, 0, 8},
+ { 16800000, 600000000, 500, 14, 0, 8},
+ { 19200000, 600000000, 375, 12, 0, 6},
+ { 26000000, 600000000, 600, 26, 0, 8},
+
+ { 12000000, 520000000, 520, 12, 0, 8},
+ { 13000000, 520000000, 520, 13, 0, 8},
+ { 16800000, 520000000, 495, 16, 0, 8}, /* actual: 519.75 MHz */
+ { 19200000, 520000000, 325, 12, 0, 6},
+ { 26000000, 520000000, 520, 26, 0, 8},
+
+ { 12000000, 416000000, 416, 12, 0, 8},
+ { 13000000, 416000000, 416, 13, 0, 8},
+ { 16800000, 416000000, 396, 16, 0, 8}, /* actual: 415.8 MHz */
+ { 19200000, 416000000, 260, 12, 0, 6},
+ { 26000000, 416000000, 416, 26, 0, 8},
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_m_freq_table[] = {
- { 12000000, 666000000, 666, 12, 1, 8},
- { 13000000, 666000000, 666, 13, 1, 8},
- { 16800000, 666000000, 555, 14, 1, 8},
- { 19200000, 666000000, 555, 16, 1, 8},
- { 26000000, 666000000, 666, 26, 1, 8},
- { 12000000, 600000000, 600, 12, 1, 8},
- { 13000000, 600000000, 600, 13, 1, 8},
- { 16800000, 600000000, 500, 14, 1, 8},
- { 19200000, 600000000, 375, 12, 1, 6},
- { 26000000, 600000000, 600, 26, 1, 8},
+ { 12000000, 666000000, 666, 12, 0, 8},
+ { 13000000, 666000000, 666, 13, 0, 8},
+ { 16800000, 666000000, 555, 14, 0, 8},
+ { 19200000, 666000000, 555, 16, 0, 8},
+ { 26000000, 666000000, 666, 26, 0, 8},
+ { 12000000, 600000000, 600, 12, 0, 8},
+ { 13000000, 600000000, 600, 13, 0, 8},
+ { 16800000, 600000000, 500, 14, 0, 8},
+ { 19200000, 600000000, 375, 12, 0, 6},
+ { 26000000, 600000000, 600, 26, 0, 8},
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
- { 12000000, 216000000, 432, 12, 2, 8},
- { 13000000, 216000000, 432, 13, 2, 8},
- { 16800000, 216000000, 360, 14, 2, 8},
- { 19200000, 216000000, 360, 16, 2, 8},
- { 26000000, 216000000, 432, 26, 2, 8},
+ { 12000000, 216000000, 432, 12, 1, 8},
+ { 13000000, 216000000, 432, 13, 1, 8},
+ { 16800000, 216000000, 360, 14, 1, 8},
+ { 19200000, 216000000, 360, 16, 1, 8},
+ { 26000000, 216000000, 432, 26, 1, 8},
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
- { 9600000, 564480000, 294, 5, 1, 4},
- { 9600000, 552960000, 288, 5, 1, 4},
- { 9600000, 24000000, 5, 2, 1, 1},
+ { 9600000, 564480000, 294, 5, 0, 4},
+ { 9600000, 552960000, 288, 5, 0, 4},
+ { 9600000, 24000000, 5, 2, 0, 1},
- { 28800000, 56448000, 49, 25, 1, 1},
- { 28800000, 73728000, 64, 25, 1, 1},
- { 28800000, 24000000, 5, 6, 1, 1},
+ { 28800000, 56448000, 49, 25, 0, 1},
+ { 28800000, 73728000, 64, 25, 0, 1},
+ { 28800000, 24000000, 5, 6, 0, 1},
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
- { 12000000, 216000000, 216, 12, 1, 4},
- { 13000000, 216000000, 216, 13, 1, 4},
- { 16800000, 216000000, 180, 14, 1, 4},
- { 19200000, 216000000, 180, 16, 1, 4},
- { 26000000, 216000000, 216, 26, 1, 4},
-
- { 12000000, 594000000, 594, 12, 1, 8},
- { 13000000, 594000000, 594, 13, 1, 8},
- { 16800000, 594000000, 495, 14, 1, 8},
- { 19200000, 594000000, 495, 16, 1, 8},
- { 26000000, 594000000, 594, 26, 1, 8},
-
- { 12000000, 1000000000, 1000, 12, 1, 12},
- { 13000000, 1000000000, 1000, 13, 1, 12},
- { 19200000, 1000000000, 625, 12, 1, 8},
- { 26000000, 1000000000, 1000, 26, 1, 12},
+ { 12000000, 216000000, 216, 12, 0, 4},
+ { 13000000, 216000000, 216, 13, 0, 4},
+ { 16800000, 216000000, 180, 14, 0, 4},
+ { 19200000, 216000000, 180, 16, 0, 4},
+ { 26000000, 216000000, 216, 26, 0, 4},
+
+ { 12000000, 594000000, 594, 12, 0, 8},
+ { 13000000, 594000000, 594, 13, 0, 8},
+ { 16800000, 594000000, 495, 14, 0, 8},
+ { 19200000, 594000000, 495, 16, 0, 8},
+ { 26000000, 594000000, 594, 26, 0, 8},
+
+ { 12000000, 1000000000, 1000, 12, 0, 12},
+ { 13000000, 1000000000, 1000, 13, 0, 12},
+ { 19200000, 1000000000, 625, 12, 0, 8},
+ { 26000000, 1000000000, 1000, 26, 0, 12},
{ 0, 0, 0, 0, 0, 0 },
};
+static struct pdiv_map pllu_p[] = {
+ { .pdiv = 1, .hw_val = 1 },
+ { .pdiv = 2, .hw_val = 0 },
+ { .pdiv = 0, .hw_val = 0 },
+};
+
static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
- { 12000000, 480000000, 960, 12, 2, 12},
- { 13000000, 480000000, 960, 13, 2, 12},
- { 16800000, 480000000, 400, 7, 2, 5},
- { 19200000, 480000000, 200, 4, 2, 3},
- { 26000000, 480000000, 960, 26, 2, 12},
+ { 12000000, 480000000, 960, 12, 0, 12},
+ { 13000000, 480000000, 960, 13, 0, 12},
+ { 16800000, 480000000, 400, 7, 0, 5},
+ { 19200000, 480000000, 200, 4, 0, 3},
+ { 26000000, 480000000, 960, 26, 0, 12},
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
/* 1.7 GHz */
- { 12000000, 1700000000, 850, 6, 1, 8},
- { 13000000, 1700000000, 915, 7, 1, 8}, /* actual: 1699.2 MHz */
- { 16800000, 1700000000, 708, 7, 1, 8}, /* actual: 1699.2 MHz */
- { 19200000, 1700000000, 885, 10, 1, 8}, /* actual: 1699.2 MHz */
- { 26000000, 1700000000, 850, 13, 1, 8},
+ { 12000000, 1700000000, 850, 6, 0, 8},
+ { 13000000, 1700000000, 915, 7, 0, 8}, /* actual: 1699.2 MHz */
+ { 16800000, 1700000000, 708, 7, 0, 8}, /* actual: 1699.2 MHz */
+ { 19200000, 1700000000, 885, 10, 0, 8}, /* actual: 1699.2 MHz */
+ { 26000000, 1700000000, 850, 13, 0, 8},
/* 1.6 GHz */
- { 12000000, 1600000000, 800, 6, 1, 8},
- { 13000000, 1600000000, 738, 6, 1, 8}, /* actual: 1599.0 MHz */
- { 16800000, 1600000000, 857, 9, 1, 8}, /* actual: 1599.7 MHz */
- { 19200000, 1600000000, 500, 6, 1, 8},
- { 26000000, 1600000000, 800, 13, 1, 8},
+ { 12000000, 1600000000, 800, 6, 0, 8},
+ { 13000000, 1600000000, 738, 6, 0, 8}, /* actual: 1599.0 MHz */
+ { 16800000, 1600000000, 857, 9, 0, 8}, /* actual: 1599.7 MHz */
+ { 19200000, 1600000000, 500, 6, 0, 8},
+ { 26000000, 1600000000, 800, 13, 0, 8},
/* 1.5 GHz */
- { 12000000, 1500000000, 750, 6, 1, 8},
- { 13000000, 1500000000, 923, 8, 1, 8}, /* actual: 1499.8 MHz */
- { 16800000, 1500000000, 625, 7, 1, 8},
- { 19200000, 1500000000, 625, 8, 1, 8},
- { 26000000, 1500000000, 750, 13, 1, 8},
+ { 12000000, 1500000000, 750, 6, 0, 8},
+ { 13000000, 1500000000, 923, 8, 0, 8}, /* actual: 1499.8 MHz */
+ { 16800000, 1500000000, 625, 7, 0, 8},
+ { 19200000, 1500000000, 625, 8, 0, 8},
+ { 26000000, 1500000000, 750, 13, 0, 8},
/* 1.4 GHz */
- { 12000000, 1400000000, 700, 6, 1, 8},
- { 13000000, 1400000000, 969, 9, 1, 8}, /* actual: 1399.7 MHz */
- { 16800000, 1400000000, 1000, 12, 1, 8},
- { 19200000, 1400000000, 875, 12, 1, 8},
- { 26000000, 1400000000, 700, 13, 1, 8},
+ { 12000000, 1400000000, 700, 6, 0, 8},
+ { 13000000, 1400000000, 969, 9, 0, 8}, /* actual: 1399.7 MHz */
+ { 16800000, 1400000000, 1000, 12, 0, 8},
+ { 19200000, 1400000000, 875, 12, 0, 8},
+ { 26000000, 1400000000, 700, 13, 0, 8},
/* 1.3 GHz */
- { 12000000, 1300000000, 975, 9, 1, 8},
- { 13000000, 1300000000, 1000, 10, 1, 8},
- { 16800000, 1300000000, 928, 12, 1, 8}, /* actual: 1299.2 MHz */
- { 19200000, 1300000000, 812, 12, 1, 8}, /* actual: 1299.2 MHz */
- { 26000000, 1300000000, 650, 13, 1, 8},
+ { 12000000, 1300000000, 975, 9, 0, 8},
+ { 13000000, 1300000000, 1000, 10, 0, 8},
+ { 16800000, 1300000000, 928, 12, 0, 8}, /* actual: 1299.2 MHz */
+ { 19200000, 1300000000, 812, 12, 0, 8}, /* actual: 1299.2 MHz */
+ { 26000000, 1300000000, 650, 13, 0, 8},
/* 1.2 GHz */
- { 12000000, 1200000000, 1000, 10, 1, 8},
- { 13000000, 1200000000, 923, 10, 1, 8}, /* actual: 1199.9 MHz */
- { 16800000, 1200000000, 1000, 14, 1, 8},
- { 19200000, 1200000000, 1000, 16, 1, 8},
- { 26000000, 1200000000, 600, 13, 1, 8},
+ { 12000000, 1200000000, 1000, 10, 0, 8},
+ { 13000000, 1200000000, 923, 10, 0, 8}, /* actual: 1199.9 MHz */
+ { 16800000, 1200000000, 1000, 14, 0, 8},
+ { 19200000, 1200000000, 1000, 16, 0, 8},
+ { 26000000, 1200000000, 600, 13, 0, 8},
/* 1.1 GHz */
- { 12000000, 1100000000, 825, 9, 1, 8},
- { 13000000, 1100000000, 846, 10, 1, 8}, /* actual: 1099.8 MHz */
- { 16800000, 1100000000, 982, 15, 1, 8}, /* actual: 1099.8 MHz */
- { 19200000, 1100000000, 859, 15, 1, 8}, /* actual: 1099.5 MHz */
- { 26000000, 1100000000, 550, 13, 1, 8},
+ { 12000000, 1100000000, 825, 9, 0, 8},
+ { 13000000, 1100000000, 846, 10, 0, 8}, /* actual: 1099.8 MHz */
+ { 16800000, 1100000000, 982, 15, 0, 8}, /* actual: 1099.8 MHz */
+ { 19200000, 1100000000, 859, 15, 0, 8}, /* actual: 1099.5 MHz */
+ { 26000000, 1100000000, 550, 13, 0, 8},
/* 1 GHz */
- { 12000000, 1000000000, 1000, 12, 1, 8},
- { 13000000, 1000000000, 1000, 13, 1, 8},
- { 16800000, 1000000000, 833, 14, 1, 8}, /* actual: 999.6 MHz */
- { 19200000, 1000000000, 625, 12, 1, 8},
- { 26000000, 1000000000, 1000, 26, 1, 8},
+ { 12000000, 1000000000, 1000, 12, 0, 8},
+ { 13000000, 1000000000, 1000, 13, 0, 8},
+ { 16800000, 1000000000, 833, 14, 0, 8}, /* actual: 999.6 MHz */
+ { 19200000, 1000000000, 625, 12, 0, 8},
+ { 26000000, 1000000000, 1000, 26, 0, 8},
{ 0, 0, 0, 0, 0, 0 },
};
@@ -552,7 +558,7 @@ static struct tegra_clk_pll_params pll_c_params = {
.vco_max = 1400000000,
.base_reg = PLLC_BASE,
.misc_reg = PLLC_MISC,
- .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
};
@@ -566,7 +572,7 @@ static struct tegra_clk_pll_params pll_m_params = {
.vco_max = 1200000000,
.base_reg = PLLM_BASE,
.misc_reg = PLLM_MISC,
- .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
};
@@ -580,7 +586,7 @@ static struct tegra_clk_pll_params pll_p_params = {
.vco_max = 1400000000,
.base_reg = PLLP_BASE,
.misc_reg = PLLP_MISC,
- .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
};
@@ -594,7 +600,7 @@ static struct tegra_clk_pll_params pll_a_params = {
.vco_max = 1400000000,
.base_reg = PLLA_BASE,
.misc_reg = PLLA_MISC,
- .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
};
@@ -608,7 +614,7 @@ static struct tegra_clk_pll_params pll_d_params = {
.vco_max = 1000000000,
.base_reg = PLLD_BASE,
.misc_reg = PLLD_MISC,
- .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
.lock_delay = 1000,
};
@@ -622,7 +628,7 @@ static struct tegra_clk_pll_params pll_d2_params = {
.vco_max = 1000000000,
.base_reg = PLLD2_BASE,
.misc_reg = PLLD2_MISC,
- .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
.lock_delay = 1000,
};
@@ -636,9 +642,10 @@ static struct tegra_clk_pll_params pll_u_params = {
.vco_max = 960000000,
.base_reg = PLLU_BASE,
.misc_reg = PLLU_MISC,
- .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
.lock_delay = 1000,
+ .pdiv_tohw = pllu_p,
};
static struct tegra_clk_pll_params pll_x_params = {
@@ -650,7 +657,7 @@ static struct tegra_clk_pll_params pll_x_params = {
.vco_max = 1700000000,
.base_reg = PLLX_BASE,
.misc_reg = PLLX_MISC,
- .lock_bit_idx = PLL_BASE_LOCK,
+ .lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
};
@@ -664,7 +671,7 @@ static struct tegra_clk_pll_params pll_e_params = {
.vco_max = 2400000000U,
.base_reg = PLLE_BASE,
.misc_reg = PLLE_MISC,
- .lock_bit_idx = PLLE_MISC_LOCK,
+ .lock_mask = PLLE_MISC_LOCK,
.lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
.lock_delay = 300,
};
@@ -1660,7 +1667,7 @@ static void __init tegra30_periph_clk_init(void)
data = &tegra_periph_clk_list[i];
clk = tegra_clk_register_periph(data->name, data->parent_names,
data->num_parents, &data->periph,
- clk_base, data->offset);
+ clk_base, data->offset, data->flags);
clk_register_clkdev(clk, data->con_id, data->dev_id);
clks[data->clk_id] = clk;
}
@@ -1910,9 +1917,16 @@ static __initdata struct tegra_clk_init_table init_table[] = {
{disp1, pll_p, 600000000, 0},
{disp2, pll_p, 600000000, 0},
{twd, clk_max, 0, 1},
+ {gr2d, pll_c, 300000000, 0},
+ {gr3d, pll_c, 300000000, 0},
{clk_max, clk_max, 0, 0}, /* This MUST be the last entry. */
};
+static void __init tegra30_clock_apply_init_table(void)
+{
+ tegra_init_from_table(init_table, clks, clk_max);
+}
+
/*
* Some clocks may be used by different drivers depending on the board
* configuration. List those here to register them twice in the clock lookup
@@ -1986,7 +2000,7 @@ void __init tegra30_clock_init(struct device_node *np)
clk_data.clk_num = ARRAY_SIZE(clks);
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
- tegra_init_from_table(init_table, clks, clk_max);
+ tegra_clk_apply_init_table = tegra30_clock_apply_init_table;
tegra_cpu_car_ops = &tegra30_cpu_car_ops;
}
diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c
index a603b9af0ad3..923ca7ee4694 100644
--- a/drivers/clk/tegra/clk.c
+++ b/drivers/clk/tegra/clk.c
@@ -22,7 +22,8 @@
#include "clk.h"
/* Global data of Tegra CPU CAR ops */
-struct tegra_cpu_car_ops *tegra_cpu_car_ops;
+static struct tegra_cpu_car_ops dummy_car_ops;
+struct tegra_cpu_car_ops *tegra_cpu_car_ops = &dummy_car_ops;
void __init tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list,
struct clk *clks[], int clk_max)
@@ -76,6 +77,7 @@ void __init tegra_init_from_table(struct tegra_clk_init_table *tbl,
static const struct of_device_id tegra_dt_clk_match[] = {
{ .compatible = "nvidia,tegra20-car", .data = tegra20_clock_init },
{ .compatible = "nvidia,tegra30-car", .data = tegra30_clock_init },
+ { .compatible = "nvidia,tegra114-car", .data = tegra114_clock_init },
{ }
};
@@ -83,3 +85,13 @@ void __init tegra_clocks_init(void)
{
of_clk_init(tegra_dt_clk_match);
}
+
+tegra_clk_apply_init_table_func tegra_clk_apply_init_table;
+
+void __init tegra_clocks_apply_init_table(void)
+{
+ if (!tegra_clk_apply_init_table)
+ return;
+
+ tegra_clk_apply_init_table();
+}
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index a09d7dcaf183..e0565620d68e 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -1,4 +1,4 @@
-/*
+ /*
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
@@ -117,6 +117,17 @@ struct tegra_clk_pll_freq_table {
};
/**
+ * struct pdiv_map - map post divider to hw value
+ *
+ * @pdiv: post divider
+ * @hw_val: value to be written to the PLL hw
+ */
+struct pdiv_map {
+ u8 pdiv;
+ u8 hw_val;
+};
+
+/**
* struct clk_pll_params - PLL parameters
*
* @input_min: Minimum input frequency
@@ -143,9 +154,18 @@ struct tegra_clk_pll_params {
u32 base_reg;
u32 misc_reg;
u32 lock_reg;
- u32 lock_bit_idx;
+ u32 lock_mask;
u32 lock_enable_bit_idx;
+ u32 iddq_reg;
+ u32 iddq_bit_idx;
+ u32 aux_reg;
+ u32 dyn_ramp_reg;
+ u32 ext_misc_reg[3];
+ int stepa_shift;
+ int stepb_shift;
int lock_delay;
+ int max_p;
+ struct pdiv_map *pdiv_tohw;
};
/**
@@ -182,12 +202,16 @@ struct tegra_clk_pll_params {
* TEGRA_PLL_FIXED - We are not supposed to change output frequency
* of some plls.
* TEGRA_PLLE_CONFIGURE - Configure PLLE when enabling.
+ * TEGRA_PLL_LOCK_MISC - Lock bit is in the misc register instead of the
+ * base register.
+ * TEGRA_PLL_BYPASS - PLL has bypass bit
+ * TEGRA_PLL_HAS_LOCK_ENABLE - PLL has bit to enable lock monitoring
*/
struct tegra_clk_pll {
struct clk_hw hw;
void __iomem *clk_base;
void __iomem *pmc;
- u8 flags;
+ u32 flags;
unsigned long fixed_rate;
spinlock_t *lock;
u8 divn_shift;
@@ -210,20 +234,64 @@ struct tegra_clk_pll {
#define TEGRA_PLLM BIT(5)
#define TEGRA_PLL_FIXED BIT(6)
#define TEGRA_PLLE_CONFIGURE BIT(7)
+#define TEGRA_PLL_LOCK_MISC BIT(8)
+#define TEGRA_PLL_BYPASS BIT(9)
+#define TEGRA_PLL_HAS_LOCK_ENABLE BIT(10)
extern const struct clk_ops tegra_clk_pll_ops;
extern const struct clk_ops tegra_clk_plle_ops;
struct clk *tegra_clk_register_pll(const char *name, const char *parent_name,
void __iomem *clk_base, void __iomem *pmc,
unsigned long flags, unsigned long fixed_rate,
- struct tegra_clk_pll_params *pll_params, u8 pll_flags,
+ struct tegra_clk_pll_params *pll_params, u32 pll_flags,
struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock);
+
struct clk *tegra_clk_register_plle(const char *name, const char *parent_name,
void __iomem *clk_base, void __iomem *pmc,
unsigned long flags, unsigned long fixed_rate,
- struct tegra_clk_pll_params *pll_params, u8 pll_flags,
+ struct tegra_clk_pll_params *pll_params, u32 pll_flags,
struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock);
+struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name,
+ void __iomem *clk_base, void __iomem *pmc,
+ unsigned long flags, unsigned long fixed_rate,
+ struct tegra_clk_pll_params *pll_params,
+ u32 pll_flags,
+ struct tegra_clk_pll_freq_table *freq_table,
+ spinlock_t *lock);
+
+struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name,
+ void __iomem *clk_base, void __iomem *pmc,
+ unsigned long flags, unsigned long fixed_rate,
+ struct tegra_clk_pll_params *pll_params,
+ u32 pll_flags,
+ struct tegra_clk_pll_freq_table *freq_table,
+ spinlock_t *lock);
+
+struct clk *tegra_clk_register_pllc(const char *name, const char *parent_name,
+ void __iomem *clk_base, void __iomem *pmc,
+ unsigned long flags, unsigned long fixed_rate,
+ struct tegra_clk_pll_params *pll_params,
+ u32 pll_flags,
+ struct tegra_clk_pll_freq_table *freq_table,
+ spinlock_t *lock);
+
+struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name,
+ void __iomem *clk_base, void __iomem *pmc,
+ unsigned long flags, unsigned long fixed_rate,
+ struct tegra_clk_pll_params *pll_params,
+ u32 pll_flags,
+ struct tegra_clk_pll_freq_table *freq_table,
+ spinlock_t *lock, unsigned long parent_rate);
+
+struct clk *tegra_clk_register_plle_tegra114(const char *name,
+ const char *parent_name,
+ void __iomem *clk_base, unsigned long flags,
+ unsigned long fixed_rate,
+ struct tegra_clk_pll_params *pll_params,
+ struct tegra_clk_pll_freq_table *freq_table,
+ spinlock_t *lock);
+
/**
* struct tegra_clk_pll_out - PLL divider down clock
*
@@ -290,6 +358,7 @@ struct tegra_clk_periph_regs {
* TEGRA_PERIPH_ON_APB - If peripheral is in the APB bus then read the
* bus to flush the write operation in apb bus. This flag indicates
* that this peripheral is in apb bus.
+ * TEGRA_PERIPH_WAR_1005168 - Apply workaround for Tegra114 MSENC bug
*/
struct tegra_clk_periph_gate {
u32 magic;
@@ -309,6 +378,7 @@ struct tegra_clk_periph_gate {
#define TEGRA_PERIPH_NO_RESET BIT(0)
#define TEGRA_PERIPH_MANUAL_RESET BIT(1)
#define TEGRA_PERIPH_ON_APB BIT(2)
+#define TEGRA_PERIPH_WAR_1005168 BIT(3)
void tegra_periph_reset(struct tegra_clk_periph_gate *gate, bool assert);
extern const struct clk_ops tegra_clk_periph_gate_ops;
@@ -349,7 +419,7 @@ extern const struct clk_ops tegra_clk_periph_ops;
struct clk *tegra_clk_register_periph(const char *name,
const char **parent_names, int num_parents,
struct tegra_clk_periph *periph, void __iomem *clk_base,
- u32 offset);
+ u32 offset, unsigned long flags);
struct clk *tegra_clk_register_periph_nodiv(const char *name,
const char **parent_names, int num_parents,
struct tegra_clk_periph *periph, void __iomem *clk_base,
@@ -392,12 +462,14 @@ struct tegra_periph_init_data {
u32 offset;
const char *con_id;
const char *dev_id;
+ unsigned long flags;
};
#define TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parent_names, _offset,\
_mux_shift, _mux_mask, _mux_flags, _div_shift, \
_div_width, _div_frac_width, _div_flags, _regs, \
- _clk_num, _enb_refcnt, _gate_flags, _clk_id, _table) \
+ _clk_num, _enb_refcnt, _gate_flags, _clk_id, _table,\
+ _flags) \
{ \
.name = _name, \
.clk_id = _clk_id, \
@@ -412,6 +484,7 @@ struct tegra_periph_init_data {
.offset = _offset, \
.con_id = _con_id, \
.dev_id = _dev_id, \
+ .flags = _flags \
}
#define TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parent_names, _offset,\
@@ -422,7 +495,7 @@ struct tegra_periph_init_data {
_mux_shift, BIT(_mux_width) - 1, _mux_flags, \
_div_shift, _div_width, _div_frac_width, _div_flags, \
_regs, _clk_num, _enb_refcnt, _gate_flags, _clk_id,\
- NULL)
+ NULL, 0)
/**
* struct clk_super_mux - super clock
@@ -510,4 +583,13 @@ void tegra30_clock_init(struct device_node *np);
static inline void tegra30_clock_init(struct device_node *np) {}
#endif /* CONFIG_ARCH_TEGRA_3x_SOC */
+#ifdef CONFIG_ARCH_TEGRA_114_SOC
+void tegra114_clock_init(struct device_node *np);
+#else
+static inline void tegra114_clock_init(struct device_node *np) {}
+#endif /* CONFIG_ARCH_TEGRA114_SOC */
+
+typedef void (*tegra_clk_apply_init_table_func)(void);
+extern tegra_clk_apply_init_table_func tegra_clk_apply_init_table;
+
#endif /* TEGRA_CLK_H */
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 9002185a0a1a..7bc6e51757ee 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -31,6 +31,9 @@ config SUN4I_TIMER
config VT8500_TIMER
bool
+config CADENCE_TTC_TIMER
+ bool
+
config CLKSRC_NOMADIK_MTU
bool
depends on (ARCH_NOMADIK || ARCH_U8500)
@@ -67,3 +70,8 @@ config CLKSRC_METAG_GENERIC
def_bool y if METAG
help
This option enables support for the Meta per-thread timers.
+
+config CLKSRC_EXYNOS_MCT
+ def_bool y if ARCH_EXYNOS
+ help
+ Support for Multi Core Timer controller on Exynos SoCs.
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 682d48d08164..caacdb63aff9 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -23,6 +23,8 @@ obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o
obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o
obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o
obj-$(CONFIG_ARCH_BCM) += bcm_kona_timer.o
+obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o
+obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o
obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o
diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/cadence_ttc_timer.c
new file mode 100644
index 000000000000..685bc60e210a
--- /dev/null
+++ b/drivers/clocksource/cadence_ttc_timer.c
@@ -0,0 +1,436 @@
+/*
+ * This file contains driver for the Cadence Triple Timer Counter Rev 06
+ *
+ * Copyright (C) 2011-2013 Xilinx
+ *
+ * based on arch/mips/kernel/time.c timer driver
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/clockchips.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/clk-provider.h>
+
+/*
+ * This driver configures the 2 16-bit count-up timers as follows:
+ *
+ * T1: Timer 1, clocksource for generic timekeeping
+ * T2: Timer 2, clockevent source for hrtimers
+ * T3: Timer 3, <unused>
+ *
+ * The input frequency to the timer module for emulation is 2.5MHz which is
+ * common to all the timer channels (T1, T2, and T3). With a pre-scaler of 32,
+ * the timers are clocked at 78.125KHz (12.8 us resolution).
+
+ * The input frequency to the timer module in silicon is configurable and
+ * obtained from device tree. The pre-scaler of 32 is used.
+ */
+
+/*
+ * Timer Register Offset Definitions of Timer 1, Increment base address by 4
+ * and use same offsets for Timer 2
+ */
+#define TTC_CLK_CNTRL_OFFSET 0x00 /* Clock Control Reg, RW */
+#define TTC_CNT_CNTRL_OFFSET 0x0C /* Counter Control Reg, RW */
+#define TTC_COUNT_VAL_OFFSET 0x18 /* Counter Value Reg, RO */
+#define TTC_INTR_VAL_OFFSET 0x24 /* Interval Count Reg, RW */
+#define TTC_ISR_OFFSET 0x54 /* Interrupt Status Reg, RO */
+#define TTC_IER_OFFSET 0x60 /* Interrupt Enable Reg, RW */
+
+#define TTC_CNT_CNTRL_DISABLE_MASK 0x1
+
+/*
+ * Setup the timers to use pre-scaling, using a fixed value for now that will
+ * work across most input frequency, but it may need to be more dynamic
+ */
+#define PRESCALE_EXPONENT 11 /* 2 ^ PRESCALE_EXPONENT = PRESCALE */
+#define PRESCALE 2048 /* The exponent must match this */
+#define CLK_CNTRL_PRESCALE ((PRESCALE_EXPONENT - 1) << 1)
+#define CLK_CNTRL_PRESCALE_EN 1
+#define CNT_CNTRL_RESET (1 << 4)
+
+/**
+ * struct ttc_timer - This definition defines local timer structure
+ *
+ * @base_addr: Base address of timer
+ * @clk: Associated clock source
+ * @clk_rate_change_nb Notifier block for clock rate changes
+ */
+struct ttc_timer {
+ void __iomem *base_addr;
+ struct clk *clk;
+ struct notifier_block clk_rate_change_nb;
+};
+
+#define to_ttc_timer(x) \
+ container_of(x, struct ttc_timer, clk_rate_change_nb)
+
+struct ttc_timer_clocksource {
+ struct ttc_timer ttc;
+ struct clocksource cs;
+};
+
+#define to_ttc_timer_clksrc(x) \
+ container_of(x, struct ttc_timer_clocksource, cs)
+
+struct ttc_timer_clockevent {
+ struct ttc_timer ttc;
+ struct clock_event_device ce;
+};
+
+#define to_ttc_timer_clkevent(x) \
+ container_of(x, struct ttc_timer_clockevent, ce)
+
+/**
+ * ttc_set_interval - Set the timer interval value
+ *
+ * @timer: Pointer to the timer instance
+ * @cycles: Timer interval ticks
+ **/
+static void ttc_set_interval(struct ttc_timer *timer,
+ unsigned long cycles)
+{
+ u32 ctrl_reg;
+
+ /* Disable the counter, set the counter value and re-enable counter */
+ ctrl_reg = __raw_readl(timer->base_addr + TTC_CNT_CNTRL_OFFSET);
+ ctrl_reg |= TTC_CNT_CNTRL_DISABLE_MASK;
+ __raw_writel(ctrl_reg, timer->base_addr + TTC_CNT_CNTRL_OFFSET);
+
+ __raw_writel(cycles, timer->base_addr + TTC_INTR_VAL_OFFSET);
+
+ /*
+ * Reset the counter (0x10) so that it starts from 0, one-shot
+ * mode makes this needed for timing to be right.
+ */
+ ctrl_reg |= CNT_CNTRL_RESET;
+ ctrl_reg &= ~TTC_CNT_CNTRL_DISABLE_MASK;
+ __raw_writel(ctrl_reg, timer->base_addr + TTC_CNT_CNTRL_OFFSET);
+}
+
+/**
+ * ttc_clock_event_interrupt - Clock event timer interrupt handler
+ *
+ * @irq: IRQ number of the Timer
+ * @dev_id: void pointer to the ttc_timer instance
+ *
+ * returns: Always IRQ_HANDLED - success
+ **/
+static irqreturn_t ttc_clock_event_interrupt(int irq, void *dev_id)
+{
+ struct ttc_timer_clockevent *ttce = dev_id;
+ struct ttc_timer *timer = &ttce->ttc;
+
+ /* Acknowledge the interrupt and call event handler */
+ __raw_readl(timer->base_addr + TTC_ISR_OFFSET);
+
+ ttce->ce.event_handler(&ttce->ce);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * __ttc_clocksource_read - Reads the timer counter register
+ *
+ * returns: Current timer counter register value
+ **/
+static cycle_t __ttc_clocksource_read(struct clocksource *cs)
+{
+ struct ttc_timer *timer = &to_ttc_timer_clksrc(cs)->ttc;
+
+ return (cycle_t)__raw_readl(timer->base_addr +
+ TTC_COUNT_VAL_OFFSET);
+}
+
+/**
+ * ttc_set_next_event - Sets the time interval for next event
+ *
+ * @cycles: Timer interval ticks
+ * @evt: Address of clock event instance
+ *
+ * returns: Always 0 - success
+ **/
+static int ttc_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt);
+ struct ttc_timer *timer = &ttce->ttc;
+
+ ttc_set_interval(timer, cycles);
+ return 0;
+}
+
+/**
+ * ttc_set_mode - Sets the mode of timer
+ *
+ * @mode: Mode to be set
+ * @evt: Address of clock event instance
+ **/
+static void ttc_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt);
+ struct ttc_timer *timer = &ttce->ttc;
+ u32 ctrl_reg;
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ ttc_set_interval(timer,
+ DIV_ROUND_CLOSEST(clk_get_rate(ttce->ttc.clk),
+ PRESCALE * HZ));
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ ctrl_reg = __raw_readl(timer->base_addr +
+ TTC_CNT_CNTRL_OFFSET);
+ ctrl_reg |= TTC_CNT_CNTRL_DISABLE_MASK;
+ __raw_writel(ctrl_reg,
+ timer->base_addr + TTC_CNT_CNTRL_OFFSET);
+ break;
+ case CLOCK_EVT_MODE_RESUME:
+ ctrl_reg = __raw_readl(timer->base_addr +
+ TTC_CNT_CNTRL_OFFSET);
+ ctrl_reg &= ~TTC_CNT_CNTRL_DISABLE_MASK;
+ __raw_writel(ctrl_reg,
+ timer->base_addr + TTC_CNT_CNTRL_OFFSET);
+ break;
+ }
+}
+
+static int ttc_rate_change_clocksource_cb(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct clk_notifier_data *ndata = data;
+ struct ttc_timer *ttc = to_ttc_timer(nb);
+ struct ttc_timer_clocksource *ttccs = container_of(ttc,
+ struct ttc_timer_clocksource, ttc);
+
+ switch (event) {
+ case POST_RATE_CHANGE:
+ /*
+ * Do whatever is necessary to maintain a proper time base
+ *
+ * I cannot find a way to adjust the currently used clocksource
+ * to the new frequency. __clocksource_updatefreq_hz() sounds
+ * good, but does not work. Not sure what's that missing.
+ *
+ * This approach works, but triggers two clocksource switches.
+ * The first after unregister to clocksource jiffies. And
+ * another one after the register to the newly registered timer.
+ *
+ * Alternatively we could 'waste' another HW timer to ping pong
+ * between clock sources. That would also use one register and
+ * one unregister call, but only trigger one clocksource switch
+ * for the cost of another HW timer used by the OS.
+ */
+ clocksource_unregister(&ttccs->cs);
+ clocksource_register_hz(&ttccs->cs,
+ ndata->new_rate / PRESCALE);
+ /* fall through */
+ case PRE_RATE_CHANGE:
+ case ABORT_RATE_CHANGE:
+ default:
+ return NOTIFY_DONE;
+ }
+}
+
+static void __init ttc_setup_clocksource(struct clk *clk, void __iomem *base)
+{
+ struct ttc_timer_clocksource *ttccs;
+ int err;
+
+ ttccs = kzalloc(sizeof(*ttccs), GFP_KERNEL);
+ if (WARN_ON(!ttccs))
+ return;
+
+ ttccs->ttc.clk = clk;
+
+ err = clk_prepare_enable(ttccs->ttc.clk);
+ if (WARN_ON(err)) {
+ kfree(ttccs);
+ return;
+ }
+
+ ttccs->ttc.clk_rate_change_nb.notifier_call =
+ ttc_rate_change_clocksource_cb;
+ ttccs->ttc.clk_rate_change_nb.next = NULL;
+ if (clk_notifier_register(ttccs->ttc.clk,
+ &ttccs->ttc.clk_rate_change_nb))
+ pr_warn("Unable to register clock notifier.\n");
+
+ ttccs->ttc.base_addr = base;
+ ttccs->cs.name = "ttc_clocksource";
+ ttccs->cs.rating = 200;
+ ttccs->cs.read = __ttc_clocksource_read;
+ ttccs->cs.mask = CLOCKSOURCE_MASK(16);
+ ttccs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
+
+ /*
+ * Setup the clock source counter to be an incrementing counter
+ * with no interrupt and it rolls over at 0xFFFF. Pre-scale
+ * it by 32 also. Let it start running now.
+ */
+ __raw_writel(0x0, ttccs->ttc.base_addr + TTC_IER_OFFSET);
+ __raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN,
+ ttccs->ttc.base_addr + TTC_CLK_CNTRL_OFFSET);
+ __raw_writel(CNT_CNTRL_RESET,
+ ttccs->ttc.base_addr + TTC_CNT_CNTRL_OFFSET);
+
+ err = clocksource_register_hz(&ttccs->cs,
+ clk_get_rate(ttccs->ttc.clk) / PRESCALE);
+ if (WARN_ON(err)) {
+ kfree(ttccs);
+ return;
+ }
+}
+
+static int ttc_rate_change_clockevent_cb(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct clk_notifier_data *ndata = data;
+ struct ttc_timer *ttc = to_ttc_timer(nb);
+ struct ttc_timer_clockevent *ttcce = container_of(ttc,
+ struct ttc_timer_clockevent, ttc);
+
+ switch (event) {
+ case POST_RATE_CHANGE:
+ {
+ unsigned long flags;
+
+ /*
+ * clockevents_update_freq should be called with IRQ disabled on
+ * the CPU the timer provides events for. The timer we use is
+ * common to both CPUs, not sure if we need to run on both
+ * cores.
+ */
+ local_irq_save(flags);
+ clockevents_update_freq(&ttcce->ce,
+ ndata->new_rate / PRESCALE);
+ local_irq_restore(flags);
+
+ /* fall through */
+ }
+ case PRE_RATE_CHANGE:
+ case ABORT_RATE_CHANGE:
+ default:
+ return NOTIFY_DONE;
+ }
+}
+
+static void __init ttc_setup_clockevent(struct clk *clk,
+ void __iomem *base, u32 irq)
+{
+ struct ttc_timer_clockevent *ttcce;
+ int err;
+
+ ttcce = kzalloc(sizeof(*ttcce), GFP_KERNEL);
+ if (WARN_ON(!ttcce))
+ return;
+
+ ttcce->ttc.clk = clk;
+
+ err = clk_prepare_enable(ttcce->ttc.clk);
+ if (WARN_ON(err)) {
+ kfree(ttcce);
+ return;
+ }
+
+ ttcce->ttc.clk_rate_change_nb.notifier_call =
+ ttc_rate_change_clockevent_cb;
+ ttcce->ttc.clk_rate_change_nb.next = NULL;
+ if (clk_notifier_register(ttcce->ttc.clk,
+ &ttcce->ttc.clk_rate_change_nb))
+ pr_warn("Unable to register clock notifier.\n");
+
+ ttcce->ttc.base_addr = base;
+ ttcce->ce.name = "ttc_clockevent";
+ ttcce->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+ ttcce->ce.set_next_event = ttc_set_next_event;
+ ttcce->ce.set_mode = ttc_set_mode;
+ ttcce->ce.rating = 200;
+ ttcce->ce.irq = irq;
+ ttcce->ce.cpumask = cpu_possible_mask;
+
+ /*
+ * Setup the clock event timer to be an interval timer which
+ * is prescaled by 32 using the interval interrupt. Leave it
+ * disabled for now.
+ */
+ __raw_writel(0x23, ttcce->ttc.base_addr + TTC_CNT_CNTRL_OFFSET);
+ __raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN,
+ ttcce->ttc.base_addr + TTC_CLK_CNTRL_OFFSET);
+ __raw_writel(0x1, ttcce->ttc.base_addr + TTC_IER_OFFSET);
+
+ err = request_irq(irq, ttc_clock_event_interrupt,
+ IRQF_DISABLED | IRQF_TIMER,
+ ttcce->ce.name, ttcce);
+ if (WARN_ON(err)) {
+ kfree(ttcce);
+ return;
+ }
+
+ clockevents_config_and_register(&ttcce->ce,
+ clk_get_rate(ttcce->ttc.clk) / PRESCALE, 1, 0xfffe);
+}
+
+/**
+ * ttc_timer_init - Initialize the timer
+ *
+ * Initializes the timer hardware and register the clock source and clock event
+ * timers with Linux kernal timer framework
+ */
+static void __init ttc_timer_init(struct device_node *timer)
+{
+ unsigned int irq;
+ void __iomem *timer_baseaddr;
+ struct clk *clk;
+ static int initialized;
+
+ if (initialized)
+ return;
+
+ initialized = 1;
+
+ /*
+ * Get the 1st Triple Timer Counter (TTC) block from the device tree
+ * and use it. Note that the event timer uses the interrupt and it's the
+ * 2nd TTC hence the irq_of_parse_and_map(,1)
+ */
+ timer_baseaddr = of_iomap(timer, 0);
+ if (!timer_baseaddr) {
+ pr_err("ERROR: invalid timer base address\n");
+ BUG();
+ }
+
+ irq = irq_of_parse_and_map(timer, 1);
+ if (irq <= 0) {
+ pr_err("ERROR: invalid interrupt number\n");
+ BUG();
+ }
+
+ clk = of_clk_get_by_name(timer, "cpu_1x");
+ if (IS_ERR(clk)) {
+ pr_err("ERROR: timer input clock not found\n");
+ BUG();
+ }
+
+ ttc_setup_clocksource(clk, timer_baseaddr);
+ ttc_setup_clockevent(clk, timer_baseaddr + 4, irq);
+
+ pr_info("%s #0 at %p, irq=%d\n", timer->name, timer_baseaddr, irq);
+}
+
+CLOCKSOURCE_OF_DECLARE(ttc, "cdns,ttc", ttc_timer_init);
diff --git a/drivers/clocksource/em_sti.c b/drivers/clocksource/em_sti.c
index e6a553cb73e8..4329a29a5310 100644
--- a/drivers/clocksource/em_sti.c
+++ b/drivers/clocksource/em_sti.c
@@ -399,7 +399,18 @@ static struct platform_driver em_sti_device_driver = {
}
};
-module_platform_driver(em_sti_device_driver);
+static int __init em_sti_init(void)
+{
+ return platform_driver_register(&em_sti_device_driver);
+}
+
+static void __exit em_sti_exit(void)
+{
+ platform_driver_unregister(&em_sti_device_driver);
+}
+
+subsys_initcall(em_sti_init);
+module_exit(em_sti_exit);
MODULE_AUTHOR("Magnus Damm");
MODULE_DESCRIPTION("Renesas Emma Mobile STI Timer Driver");
diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c
new file mode 100644
index 000000000000..661026834b23
--- /dev/null
+++ b/drivers/clocksource/exynos_mct.c
@@ -0,0 +1,568 @@
+/* linux/arch/arm/mach-exynos4/mct.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * EXYNOS4 MCT(Multi-Core Timer) support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/percpu.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/clocksource.h>
+
+#include <asm/arch_timer.h>
+#include <asm/localtimer.h>
+
+#include <plat/cpu.h>
+
+#include <mach/map.h>
+#include <mach/irqs.h>
+#include <asm/mach/time.h>
+
+#define EXYNOS4_MCTREG(x) (x)
+#define EXYNOS4_MCT_G_CNT_L EXYNOS4_MCTREG(0x100)
+#define EXYNOS4_MCT_G_CNT_U EXYNOS4_MCTREG(0x104)
+#define EXYNOS4_MCT_G_CNT_WSTAT EXYNOS4_MCTREG(0x110)
+#define EXYNOS4_MCT_G_COMP0_L EXYNOS4_MCTREG(0x200)
+#define EXYNOS4_MCT_G_COMP0_U EXYNOS4_MCTREG(0x204)
+#define EXYNOS4_MCT_G_COMP0_ADD_INCR EXYNOS4_MCTREG(0x208)
+#define EXYNOS4_MCT_G_TCON EXYNOS4_MCTREG(0x240)
+#define EXYNOS4_MCT_G_INT_CSTAT EXYNOS4_MCTREG(0x244)
+#define EXYNOS4_MCT_G_INT_ENB EXYNOS4_MCTREG(0x248)
+#define EXYNOS4_MCT_G_WSTAT EXYNOS4_MCTREG(0x24C)
+#define _EXYNOS4_MCT_L_BASE EXYNOS4_MCTREG(0x300)
+#define EXYNOS4_MCT_L_BASE(x) (_EXYNOS4_MCT_L_BASE + (0x100 * x))
+#define EXYNOS4_MCT_L_MASK (0xffffff00)
+
+#define MCT_L_TCNTB_OFFSET (0x00)
+#define MCT_L_ICNTB_OFFSET (0x08)
+#define MCT_L_TCON_OFFSET (0x20)
+#define MCT_L_INT_CSTAT_OFFSET (0x30)
+#define MCT_L_INT_ENB_OFFSET (0x34)
+#define MCT_L_WSTAT_OFFSET (0x40)
+#define MCT_G_TCON_START (1 << 8)
+#define MCT_G_TCON_COMP0_AUTO_INC (1 << 1)
+#define MCT_G_TCON_COMP0_ENABLE (1 << 0)
+#define MCT_L_TCON_INTERVAL_MODE (1 << 2)
+#define MCT_L_TCON_INT_START (1 << 1)
+#define MCT_L_TCON_TIMER_START (1 << 0)
+
+#define TICK_BASE_CNT 1
+
+enum {
+ MCT_INT_SPI,
+ MCT_INT_PPI
+};
+
+enum {
+ MCT_G0_IRQ,
+ MCT_G1_IRQ,
+ MCT_G2_IRQ,
+ MCT_G3_IRQ,
+ MCT_L0_IRQ,
+ MCT_L1_IRQ,
+ MCT_L2_IRQ,
+ MCT_L3_IRQ,
+ MCT_NR_IRQS,
+};
+
+static void __iomem *reg_base;
+static unsigned long clk_rate;
+static unsigned int mct_int_type;
+static int mct_irqs[MCT_NR_IRQS];
+
+struct mct_clock_event_device {
+ struct clock_event_device *evt;
+ unsigned long base;
+ char name[10];
+};
+
+static void exynos4_mct_write(unsigned int value, unsigned long offset)
+{
+ unsigned long stat_addr;
+ u32 mask;
+ u32 i;
+
+ __raw_writel(value, reg_base + offset);
+
+ if (likely(offset >= EXYNOS4_MCT_L_BASE(0))) {
+ stat_addr = (offset & ~EXYNOS4_MCT_L_MASK) + MCT_L_WSTAT_OFFSET;
+ switch (offset & EXYNOS4_MCT_L_MASK) {
+ case MCT_L_TCON_OFFSET:
+ mask = 1 << 3; /* L_TCON write status */
+ break;
+ case MCT_L_ICNTB_OFFSET:
+ mask = 1 << 1; /* L_ICNTB write status */
+ break;
+ case MCT_L_TCNTB_OFFSET:
+ mask = 1 << 0; /* L_TCNTB write status */
+ break;
+ default:
+ return;
+ }
+ } else {
+ switch (offset) {
+ case EXYNOS4_MCT_G_TCON:
+ stat_addr = EXYNOS4_MCT_G_WSTAT;
+ mask = 1 << 16; /* G_TCON write status */
+ break;
+ case EXYNOS4_MCT_G_COMP0_L:
+ stat_addr = EXYNOS4_MCT_G_WSTAT;
+ mask = 1 << 0; /* G_COMP0_L write status */
+ break;
+ case EXYNOS4_MCT_G_COMP0_U:
+ stat_addr = EXYNOS4_MCT_G_WSTAT;
+ mask = 1 << 1; /* G_COMP0_U write status */
+ break;
+ case EXYNOS4_MCT_G_COMP0_ADD_INCR:
+ stat_addr = EXYNOS4_MCT_G_WSTAT;
+ mask = 1 << 2; /* G_COMP0_ADD_INCR w status */
+ break;
+ case EXYNOS4_MCT_G_CNT_L:
+ stat_addr = EXYNOS4_MCT_G_CNT_WSTAT;
+ mask = 1 << 0; /* G_CNT_L write status */
+ break;
+ case EXYNOS4_MCT_G_CNT_U:
+ stat_addr = EXYNOS4_MCT_G_CNT_WSTAT;
+ mask = 1 << 1; /* G_CNT_U write status */
+ break;
+ default:
+ return;
+ }
+ }
+
+ /* Wait maximum 1 ms until written values are applied */
+ for (i = 0; i < loops_per_jiffy / 1000 * HZ; i++)
+ if (__raw_readl(reg_base + stat_addr) & mask) {
+ __raw_writel(mask, reg_base + stat_addr);
+ return;
+ }
+
+ panic("MCT hangs after writing %d (offset:0x%lx)\n", value, offset);
+}
+
+/* Clocksource handling */
+static void exynos4_mct_frc_start(u32 hi, u32 lo)
+{
+ u32 reg;
+
+ exynos4_mct_write(lo, EXYNOS4_MCT_G_CNT_L);
+ exynos4_mct_write(hi, EXYNOS4_MCT_G_CNT_U);
+
+ reg = __raw_readl(reg_base + EXYNOS4_MCT_G_TCON);
+ reg |= MCT_G_TCON_START;
+ exynos4_mct_write(reg, EXYNOS4_MCT_G_TCON);
+}
+
+static cycle_t exynos4_frc_read(struct clocksource *cs)
+{
+ unsigned int lo, hi;
+ u32 hi2 = __raw_readl(reg_base + EXYNOS4_MCT_G_CNT_U);
+
+ do {
+ hi = hi2;
+ lo = __raw_readl(reg_base + EXYNOS4_MCT_G_CNT_L);
+ hi2 = __raw_readl(reg_base + EXYNOS4_MCT_G_CNT_U);
+ } while (hi != hi2);
+
+ return ((cycle_t)hi << 32) | lo;
+}
+
+static void exynos4_frc_resume(struct clocksource *cs)
+{
+ exynos4_mct_frc_start(0, 0);
+}
+
+struct clocksource mct_frc = {
+ .name = "mct-frc",
+ .rating = 400,
+ .read = exynos4_frc_read,
+ .mask = CLOCKSOURCE_MASK(64),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .resume = exynos4_frc_resume,
+};
+
+static void __init exynos4_clocksource_init(void)
+{
+ exynos4_mct_frc_start(0, 0);
+
+ if (clocksource_register_hz(&mct_frc, clk_rate))
+ panic("%s: can't register clocksource\n", mct_frc.name);
+}
+
+static void exynos4_mct_comp0_stop(void)
+{
+ unsigned int tcon;
+
+ tcon = __raw_readl(reg_base + EXYNOS4_MCT_G_TCON);
+ tcon &= ~(MCT_G_TCON_COMP0_ENABLE | MCT_G_TCON_COMP0_AUTO_INC);
+
+ exynos4_mct_write(tcon, EXYNOS4_MCT_G_TCON);
+ exynos4_mct_write(0, EXYNOS4_MCT_G_INT_ENB);
+}
+
+static void exynos4_mct_comp0_start(enum clock_event_mode mode,
+ unsigned long cycles)
+{
+ unsigned int tcon;
+ cycle_t comp_cycle;
+
+ tcon = __raw_readl(reg_base + EXYNOS4_MCT_G_TCON);
+
+ if (mode == CLOCK_EVT_MODE_PERIODIC) {
+ tcon |= MCT_G_TCON_COMP0_AUTO_INC;
+ exynos4_mct_write(cycles, EXYNOS4_MCT_G_COMP0_ADD_INCR);
+ }
+
+ comp_cycle = exynos4_frc_read(&mct_frc) + cycles;
+ exynos4_mct_write((u32)comp_cycle, EXYNOS4_MCT_G_COMP0_L);
+ exynos4_mct_write((u32)(comp_cycle >> 32), EXYNOS4_MCT_G_COMP0_U);
+
+ exynos4_mct_write(0x1, EXYNOS4_MCT_G_INT_ENB);
+
+ tcon |= MCT_G_TCON_COMP0_ENABLE;
+ exynos4_mct_write(tcon , EXYNOS4_MCT_G_TCON);
+}
+
+static int exynos4_comp_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ exynos4_mct_comp0_start(evt->mode, cycles);
+
+ return 0;
+}
+
+static void exynos4_comp_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ unsigned long cycles_per_jiffy;
+ exynos4_mct_comp0_stop();
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ cycles_per_jiffy =
+ (((unsigned long long) NSEC_PER_SEC / HZ * evt->mult) >> evt->shift);
+ exynos4_mct_comp0_start(mode, cycles_per_jiffy);
+ break;
+
+ case CLOCK_EVT_MODE_ONESHOT:
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_RESUME:
+ break;
+ }
+}
+
+static struct clock_event_device mct_comp_device = {
+ .name = "mct-comp",
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .rating = 250,
+ .set_next_event = exynos4_comp_set_next_event,
+ .set_mode = exynos4_comp_set_mode,
+};
+
+static irqreturn_t exynos4_mct_comp_isr(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+
+ exynos4_mct_write(0x1, EXYNOS4_MCT_G_INT_CSTAT);
+
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction mct_comp_event_irq = {
+ .name = "mct_comp_irq",
+ .flags = IRQF_TIMER | IRQF_IRQPOLL,
+ .handler = exynos4_mct_comp_isr,
+ .dev_id = &mct_comp_device,
+};
+
+static void exynos4_clockevent_init(void)
+{
+ mct_comp_device.cpumask = cpumask_of(0);
+ clockevents_config_and_register(&mct_comp_device, clk_rate,
+ 0xf, 0xffffffff);
+ setup_irq(mct_irqs[MCT_G0_IRQ], &mct_comp_event_irq);
+}
+
+#ifdef CONFIG_LOCAL_TIMERS
+
+static DEFINE_PER_CPU(struct mct_clock_event_device, percpu_mct_tick);
+
+/* Clock event handling */
+static void exynos4_mct_tick_stop(struct mct_clock_event_device *mevt)
+{
+ unsigned long tmp;
+ unsigned long mask = MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START;
+ unsigned long offset = mevt->base + MCT_L_TCON_OFFSET;
+
+ tmp = __raw_readl(reg_base + offset);
+ if (tmp & mask) {
+ tmp &= ~mask;
+ exynos4_mct_write(tmp, offset);
+ }
+}
+
+static void exynos4_mct_tick_start(unsigned long cycles,
+ struct mct_clock_event_device *mevt)
+{
+ unsigned long tmp;
+
+ exynos4_mct_tick_stop(mevt);
+
+ tmp = (1 << 31) | cycles; /* MCT_L_UPDATE_ICNTB */
+
+ /* update interrupt count buffer */
+ exynos4_mct_write(tmp, mevt->base + MCT_L_ICNTB_OFFSET);
+
+ /* enable MCT tick interrupt */
+ exynos4_mct_write(0x1, mevt->base + MCT_L_INT_ENB_OFFSET);
+
+ tmp = __raw_readl(reg_base + mevt->base + MCT_L_TCON_OFFSET);
+ tmp |= MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START |
+ MCT_L_TCON_INTERVAL_MODE;
+ exynos4_mct_write(tmp, mevt->base + MCT_L_TCON_OFFSET);
+}
+
+static int exynos4_tick_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick);
+
+ exynos4_mct_tick_start(cycles, mevt);
+
+ return 0;
+}
+
+static inline void exynos4_tick_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick);
+ unsigned long cycles_per_jiffy;
+
+ exynos4_mct_tick_stop(mevt);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ cycles_per_jiffy =
+ (((unsigned long long) NSEC_PER_SEC / HZ * evt->mult) >> evt->shift);
+ exynos4_mct_tick_start(cycles_per_jiffy, mevt);
+ break;
+
+ case CLOCK_EVT_MODE_ONESHOT:
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_RESUME:
+ break;
+ }
+}
+
+static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
+{
+ struct clock_event_device *evt = mevt->evt;
+
+ /*
+ * This is for supporting oneshot mode.
+ * Mct would generate interrupt periodically
+ * without explicit stopping.
+ */
+ if (evt->mode != CLOCK_EVT_MODE_PERIODIC)
+ exynos4_mct_tick_stop(mevt);
+
+ /* Clear the MCT tick interrupt */
+ if (__raw_readl(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) {
+ exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id)
+{
+ struct mct_clock_event_device *mevt = dev_id;
+ struct clock_event_device *evt = mevt->evt;
+
+ exynos4_mct_tick_clear(mevt);
+
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction mct_tick0_event_irq = {
+ .name = "mct_tick0_irq",
+ .flags = IRQF_TIMER | IRQF_NOBALANCING,
+ .handler = exynos4_mct_tick_isr,
+};
+
+static struct irqaction mct_tick1_event_irq = {
+ .name = "mct_tick1_irq",
+ .flags = IRQF_TIMER | IRQF_NOBALANCING,
+ .handler = exynos4_mct_tick_isr,
+};
+
+static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt)
+{
+ struct mct_clock_event_device *mevt;
+ unsigned int cpu = smp_processor_id();
+
+ mevt = this_cpu_ptr(&percpu_mct_tick);
+ mevt->evt = evt;
+
+ mevt->base = EXYNOS4_MCT_L_BASE(cpu);
+ sprintf(mevt->name, "mct_tick%d", cpu);
+
+ evt->name = mevt->name;
+ evt->cpumask = cpumask_of(cpu);
+ evt->set_next_event = exynos4_tick_set_next_event;
+ evt->set_mode = exynos4_tick_set_mode;
+ evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+ evt->rating = 450;
+ clockevents_config_and_register(evt, clk_rate / (TICK_BASE_CNT + 1),
+ 0xf, 0x7fffffff);
+
+ exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET);
+
+ if (mct_int_type == MCT_INT_SPI) {
+ if (cpu == 0) {
+ mct_tick0_event_irq.dev_id = mevt;
+ evt->irq = mct_irqs[MCT_L0_IRQ];
+ setup_irq(evt->irq, &mct_tick0_event_irq);
+ } else {
+ mct_tick1_event_irq.dev_id = mevt;
+ evt->irq = mct_irqs[MCT_L1_IRQ];
+ setup_irq(evt->irq, &mct_tick1_event_irq);
+ irq_set_affinity(evt->irq, cpumask_of(1));
+ }
+ } else {
+ enable_percpu_irq(mct_irqs[MCT_L0_IRQ], 0);
+ }
+
+ return 0;
+}
+
+static void exynos4_local_timer_stop(struct clock_event_device *evt)
+{
+ unsigned int cpu = smp_processor_id();
+ evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
+ if (mct_int_type == MCT_INT_SPI)
+ if (cpu == 0)
+ remove_irq(evt->irq, &mct_tick0_event_irq);
+ else
+ remove_irq(evt->irq, &mct_tick1_event_irq);
+ else
+ disable_percpu_irq(mct_irqs[MCT_L0_IRQ]);
+}
+
+static struct local_timer_ops exynos4_mct_tick_ops __cpuinitdata = {
+ .setup = exynos4_local_timer_setup,
+ .stop = exynos4_local_timer_stop,
+};
+#endif /* CONFIG_LOCAL_TIMERS */
+
+static void __init exynos4_timer_resources(struct device_node *np, void __iomem *base)
+{
+ struct clk *mct_clk, *tick_clk;
+
+ tick_clk = np ? of_clk_get_by_name(np, "fin_pll") :
+ clk_get(NULL, "fin_pll");
+ if (IS_ERR(tick_clk))
+ panic("%s: unable to determine tick clock rate\n", __func__);
+ clk_rate = clk_get_rate(tick_clk);
+
+ mct_clk = np ? of_clk_get_by_name(np, "mct") : clk_get(NULL, "mct");
+ if (IS_ERR(mct_clk))
+ panic("%s: unable to retrieve mct clock instance\n", __func__);
+ clk_prepare_enable(mct_clk);
+
+ reg_base = base;
+ if (!reg_base)
+ panic("%s: unable to ioremap mct address space\n", __func__);
+
+#ifdef CONFIG_LOCAL_TIMERS
+ if (mct_int_type == MCT_INT_PPI) {
+ int err;
+
+ err = request_percpu_irq(mct_irqs[MCT_L0_IRQ],
+ exynos4_mct_tick_isr, "MCT",
+ &percpu_mct_tick);
+ WARN(err, "MCT: can't request IRQ %d (%d)\n",
+ mct_irqs[MCT_L0_IRQ], err);
+ }
+
+ local_timer_register(&exynos4_mct_tick_ops);
+#endif /* CONFIG_LOCAL_TIMERS */
+}
+
+void __init mct_init(void)
+{
+ if (soc_is_exynos4210()) {
+ mct_irqs[MCT_G0_IRQ] = EXYNOS4_IRQ_MCT_G0;
+ mct_irqs[MCT_L0_IRQ] = EXYNOS4_IRQ_MCT_L0;
+ mct_irqs[MCT_L1_IRQ] = EXYNOS4_IRQ_MCT_L1;
+ mct_int_type = MCT_INT_SPI;
+ } else {
+ panic("unable to determine mct controller type\n");
+ }
+
+ exynos4_timer_resources(NULL, S5P_VA_SYSTIMER);
+ exynos4_clocksource_init();
+ exynos4_clockevent_init();
+}
+
+static void __init mct_init_dt(struct device_node *np, unsigned int int_type)
+{
+ u32 nr_irqs, i;
+
+ mct_int_type = int_type;
+
+ /* This driver uses only one global timer interrupt */
+ mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ);
+
+ /*
+ * Find out the number of local irqs specified. The local
+ * timer irqs are specified after the four global timer
+ * irqs are specified.
+ */
+#ifdef CONFIG_OF
+ nr_irqs = of_irq_count(np);
+#else
+ nr_irqs = 0;
+#endif
+ for (i = MCT_L0_IRQ; i < nr_irqs; i++)
+ mct_irqs[i] = irq_of_parse_and_map(np, i);
+
+ exynos4_timer_resources(np, of_iomap(np, 0));
+ exynos4_clocksource_init();
+ exynos4_clockevent_init();
+}
+
+
+static void __init mct_init_spi(struct device_node *np)
+{
+ return mct_init_dt(np, MCT_INT_SPI);
+}
+
+static void __init mct_init_ppi(struct device_node *np)
+{
+ return mct_init_dt(np, MCT_INT_PPI);
+}
+CLOCKSOURCE_OF_DECLARE(exynos4210, "samsung,exynos4210-mct", mct_init_spi);
+CLOCKSOURCE_OF_DECLARE(exynos4412, "samsung,exynos4412-mct", mct_init_ppi);
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index 488c14cc8dbf..08d0c418c94a 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -54,62 +54,100 @@ struct sh_cmt_priv {
struct clocksource cs;
unsigned long total_cycles;
bool cs_enabled;
+
+ /* callbacks for CMSTR and CMCSR access */
+ unsigned long (*read_control)(void __iomem *base, unsigned long offs);
+ void (*write_control)(void __iomem *base, unsigned long offs,
+ unsigned long value);
+
+ /* callbacks for CMCNT and CMCOR access */
+ unsigned long (*read_count)(void __iomem *base, unsigned long offs);
+ void (*write_count)(void __iomem *base, unsigned long offs,
+ unsigned long value);
};
-static DEFINE_RAW_SPINLOCK(sh_cmt_lock);
+/* Examples of supported CMT timer register layouts and I/O access widths:
+ *
+ * "16-bit counter and 16-bit control" as found on sh7263:
+ * CMSTR 0xfffec000 16-bit
+ * CMCSR 0xfffec002 16-bit
+ * CMCNT 0xfffec004 16-bit
+ * CMCOR 0xfffec006 16-bit
+ *
+ * "32-bit counter and 16-bit control" as found on sh7372, sh73a0, r8a7740:
+ * CMSTR 0xffca0000 16-bit
+ * CMCSR 0xffca0060 16-bit
+ * CMCNT 0xffca0064 32-bit
+ * CMCOR 0xffca0068 32-bit
+ */
+
+static unsigned long sh_cmt_read16(void __iomem *base, unsigned long offs)
+{
+ return ioread16(base + (offs << 1));
+}
+
+static unsigned long sh_cmt_read32(void __iomem *base, unsigned long offs)
+{
+ return ioread32(base + (offs << 2));
+}
+
+static void sh_cmt_write16(void __iomem *base, unsigned long offs,
+ unsigned long value)
+{
+ iowrite16(value, base + (offs << 1));
+}
+
+static void sh_cmt_write32(void __iomem *base, unsigned long offs,
+ unsigned long value)
+{
+ iowrite32(value, base + (offs << 2));
+}
-#define CMSTR -1 /* shared register */
#define CMCSR 0 /* channel register */
#define CMCNT 1 /* channel register */
#define CMCOR 2 /* channel register */
-static inline unsigned long sh_cmt_read(struct sh_cmt_priv *p, int reg_nr)
+static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_priv *p)
{
struct sh_timer_config *cfg = p->pdev->dev.platform_data;
- void __iomem *base = p->mapbase;
- unsigned long offs;
-
- if (reg_nr == CMSTR) {
- offs = 0;
- base -= cfg->channel_offset;
- } else
- offs = reg_nr;
-
- if (p->width == 16)
- offs <<= 1;
- else {
- offs <<= 2;
- if ((reg_nr == CMCNT) || (reg_nr == CMCOR))
- return ioread32(base + offs);
- }
- return ioread16(base + offs);
+ return p->read_control(p->mapbase - cfg->channel_offset, 0);
}
-static inline void sh_cmt_write(struct sh_cmt_priv *p, int reg_nr,
- unsigned long value)
+static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_priv *p)
+{
+ return p->read_control(p->mapbase, CMCSR);
+}
+
+static inline unsigned long sh_cmt_read_cmcnt(struct sh_cmt_priv *p)
+{
+ return p->read_count(p->mapbase, CMCNT);
+}
+
+static inline void sh_cmt_write_cmstr(struct sh_cmt_priv *p,
+ unsigned long value)
{
struct sh_timer_config *cfg = p->pdev->dev.platform_data;
- void __iomem *base = p->mapbase;
- unsigned long offs;
-
- if (reg_nr == CMSTR) {
- offs = 0;
- base -= cfg->channel_offset;
- } else
- offs = reg_nr;
-
- if (p->width == 16)
- offs <<= 1;
- else {
- offs <<= 2;
- if ((reg_nr == CMCNT) || (reg_nr == CMCOR)) {
- iowrite32(value, base + offs);
- return;
- }
- }
- iowrite16(value, base + offs);
+ p->write_control(p->mapbase - cfg->channel_offset, 0, value);
+}
+
+static inline void sh_cmt_write_cmcsr(struct sh_cmt_priv *p,
+ unsigned long value)
+{
+ p->write_control(p->mapbase, CMCSR, value);
+}
+
+static inline void sh_cmt_write_cmcnt(struct sh_cmt_priv *p,
+ unsigned long value)
+{
+ p->write_count(p->mapbase, CMCNT, value);
+}
+
+static inline void sh_cmt_write_cmcor(struct sh_cmt_priv *p,
+ unsigned long value)
+{
+ p->write_count(p->mapbase, CMCOR, value);
}
static unsigned long sh_cmt_get_counter(struct sh_cmt_priv *p,
@@ -118,15 +156,15 @@ static unsigned long sh_cmt_get_counter(struct sh_cmt_priv *p,
unsigned long v1, v2, v3;
int o1, o2;
- o1 = sh_cmt_read(p, CMCSR) & p->overflow_bit;
+ o1 = sh_cmt_read_cmcsr(p) & p->overflow_bit;
/* Make sure the timer value is stable. Stolen from acpi_pm.c */
do {
o2 = o1;
- v1 = sh_cmt_read(p, CMCNT);
- v2 = sh_cmt_read(p, CMCNT);
- v3 = sh_cmt_read(p, CMCNT);
- o1 = sh_cmt_read(p, CMCSR) & p->overflow_bit;
+ v1 = sh_cmt_read_cmcnt(p);
+ v2 = sh_cmt_read_cmcnt(p);
+ v3 = sh_cmt_read_cmcnt(p);
+ o1 = sh_cmt_read_cmcsr(p) & p->overflow_bit;
} while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
|| (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
@@ -134,6 +172,7 @@ static unsigned long sh_cmt_get_counter(struct sh_cmt_priv *p,
return v2;
}
+static DEFINE_RAW_SPINLOCK(sh_cmt_lock);
static void sh_cmt_start_stop_ch(struct sh_cmt_priv *p, int start)
{
@@ -142,14 +181,14 @@ static void sh_cmt_start_stop_ch(struct sh_cmt_priv *p, int start)
/* start stop register shared by multiple timer channels */
raw_spin_lock_irqsave(&sh_cmt_lock, flags);
- value = sh_cmt_read(p, CMSTR);
+ value = sh_cmt_read_cmstr(p);
if (start)
value |= 1 << cfg->timer_bit;
else
value &= ~(1 << cfg->timer_bit);
- sh_cmt_write(p, CMSTR, value);
+ sh_cmt_write_cmstr(p, value);
raw_spin_unlock_irqrestore(&sh_cmt_lock, flags);
}
@@ -173,14 +212,14 @@ static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate)
/* configure channel, periodic mode and maximum timeout */
if (p->width == 16) {
*rate = clk_get_rate(p->clk) / 512;
- sh_cmt_write(p, CMCSR, 0x43);
+ sh_cmt_write_cmcsr(p, 0x43);
} else {
*rate = clk_get_rate(p->clk) / 8;
- sh_cmt_write(p, CMCSR, 0x01a4);
+ sh_cmt_write_cmcsr(p, 0x01a4);
}
- sh_cmt_write(p, CMCOR, 0xffffffff);
- sh_cmt_write(p, CMCNT, 0);
+ sh_cmt_write_cmcor(p, 0xffffffff);
+ sh_cmt_write_cmcnt(p, 0);
/*
* According to the sh73a0 user's manual, as CMCNT can be operated
@@ -194,12 +233,12 @@ static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate)
* take RCLKx2 at maximum.
*/
for (k = 0; k < 100; k++) {
- if (!sh_cmt_read(p, CMCNT))
+ if (!sh_cmt_read_cmcnt(p))
break;
udelay(1);
}
- if (sh_cmt_read(p, CMCNT)) {
+ if (sh_cmt_read_cmcnt(p)) {
dev_err(&p->pdev->dev, "cannot clear CMCNT\n");
ret = -ETIMEDOUT;
goto err1;
@@ -222,7 +261,7 @@ static void sh_cmt_disable(struct sh_cmt_priv *p)
sh_cmt_start_stop_ch(p, 0);
/* disable interrupts in CMT block */
- sh_cmt_write(p, CMCSR, 0);
+ sh_cmt_write_cmcsr(p, 0);
/* stop clock */
clk_disable(p->clk);
@@ -270,7 +309,7 @@ static void sh_cmt_clock_event_program_verify(struct sh_cmt_priv *p,
if (new_match > p->max_match_value)
new_match = p->max_match_value;
- sh_cmt_write(p, CMCOR, new_match);
+ sh_cmt_write_cmcor(p, new_match);
now = sh_cmt_get_counter(p, &has_wrapped);
if (has_wrapped && (new_match > p->match_value)) {
@@ -346,7 +385,7 @@ static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id)
struct sh_cmt_priv *p = dev_id;
/* clear flags */
- sh_cmt_write(p, CMCSR, sh_cmt_read(p, CMCSR) & p->clear_bits);
+ sh_cmt_write_cmcsr(p, sh_cmt_read_cmcsr(p) & p->clear_bits);
/* update clock source counter to begin with if enabled
* the wrap flag should be cleared by the timer specific
@@ -625,14 +664,6 @@ static int sh_cmt_register(struct sh_cmt_priv *p, char *name,
unsigned long clockevent_rating,
unsigned long clocksource_rating)
{
- if (p->width == (sizeof(p->max_match_value) * 8))
- p->max_match_value = ~0;
- else
- p->max_match_value = (1 << p->width) - 1;
-
- p->match_value = p->max_match_value;
- raw_spin_lock_init(&p->lock);
-
if (clockevent_rating)
sh_cmt_register_clockevent(p, name, clockevent_rating);
@@ -657,8 +688,6 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
goto err0;
}
- platform_set_drvdata(pdev, p);
-
res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&p->pdev->dev, "failed to get I/O memory\n");
@@ -693,32 +722,51 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
goto err1;
}
+ p->read_control = sh_cmt_read16;
+ p->write_control = sh_cmt_write16;
+
if (resource_size(res) == 6) {
p->width = 16;
+ p->read_count = sh_cmt_read16;
+ p->write_count = sh_cmt_write16;
p->overflow_bit = 0x80;
p->clear_bits = ~0x80;
} else {
p->width = 32;
+ p->read_count = sh_cmt_read32;
+ p->write_count = sh_cmt_write32;
p->overflow_bit = 0x8000;
p->clear_bits = ~0xc000;
}
+ if (p->width == (sizeof(p->max_match_value) * 8))
+ p->max_match_value = ~0;
+ else
+ p->max_match_value = (1 << p->width) - 1;
+
+ p->match_value = p->max_match_value;
+ raw_spin_lock_init(&p->lock);
+
ret = sh_cmt_register(p, (char *)dev_name(&p->pdev->dev),
cfg->clockevent_rating,
cfg->clocksource_rating);
if (ret) {
dev_err(&p->pdev->dev, "registration failed\n");
- goto err1;
+ goto err2;
}
p->cs_enabled = false;
ret = setup_irq(irq, &p->irqaction);
if (ret) {
dev_err(&p->pdev->dev, "failed to request irq %d\n", irq);
- goto err1;
+ goto err2;
}
+ platform_set_drvdata(pdev, p);
+
return 0;
+err2:
+ clk_put(p->clk);
err1:
iounmap(p->mapbase);
@@ -751,7 +799,6 @@ static int sh_cmt_probe(struct platform_device *pdev)
ret = sh_cmt_setup(p, pdev);
if (ret) {
kfree(p);
- platform_set_drvdata(pdev, NULL);
pm_runtime_idle(&pdev->dev);
return ret;
}
@@ -791,7 +838,7 @@ static void __exit sh_cmt_exit(void)
}
early_platform_init("earlytimer", &sh_cmt_device_driver);
-module_init(sh_cmt_init);
+subsys_initcall(sh_cmt_init);
module_exit(sh_cmt_exit);
MODULE_AUTHOR("Magnus Damm");
diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c
index 83943e27cfac..4aac9ee0d0c0 100644
--- a/drivers/clocksource/sh_mtu2.c
+++ b/drivers/clocksource/sh_mtu2.c
@@ -386,7 +386,7 @@ static void __exit sh_mtu2_exit(void)
}
early_platform_init("earlytimer", &sh_mtu2_device_driver);
-module_init(sh_mtu2_init);
+subsys_initcall(sh_mtu2_init);
module_exit(sh_mtu2_exit);
MODULE_AUTHOR("Magnus Damm");
diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c
index b4502edce2a1..78b8dae49628 100644
--- a/drivers/clocksource/sh_tmu.c
+++ b/drivers/clocksource/sh_tmu.c
@@ -549,7 +549,7 @@ static void __exit sh_tmu_exit(void)
}
early_platform_init("earlytimer", &sh_tmu_device_driver);
-module_init(sh_tmu_init);
+subsys_initcall(sh_tmu_init);
module_exit(sh_tmu_exit);
MODULE_AUTHOR("Magnus Damm");
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 93aaadf99f28..b166e30b3bc4 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -227,12 +227,6 @@ config GPIO_TS5500
blocks of the TS-5500: DIO1, DIO2 and the LCD port, and the TS-5600
LCD port.
-config GPIO_VT8500
- bool "VIA/Wondermedia SoC GPIO Support"
- depends on ARCH_VT8500
- help
- Say yes here to support the VT8500/WM8505/WM8650 GPIO controller.
-
config GPIO_XILINX
bool "Xilinx GPIO support"
depends on PPC_OF || MICROBLAZE
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 22e07bc9fcb5..a274d7df3c8c 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -80,7 +80,6 @@ obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o
obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o
obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o
obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o
-obj-$(CONFIG_GPIO_VT8500) += gpio-vt8500.o
obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o
obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o
diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c
index b3643ff007e4..99e0fa49fcbd 100644
--- a/drivers/gpio/gpio-samsung.c
+++ b/drivers/gpio/gpio-samsung.c
@@ -1122,8 +1122,12 @@ int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset)
#ifdef CONFIG_PLAT_S3C24XX
static int s3c24xx_gpiolib_fbank_to_irq(struct gpio_chip *chip, unsigned offset)
{
- if (offset < 4)
- return IRQ_EINT0 + offset;
+ if (offset < 4) {
+ if (soc_is_s3c2412())
+ return IRQ_EINT0_2412 + offset;
+ else
+ return IRQ_EINT0 + offset;
+ }
if (offset < 8)
return IRQ_EINT4 + offset - 4;
@@ -3024,6 +3028,7 @@ static __init int samsung_gpiolib_init(void)
static const struct of_device_id exynos_pinctrl_ids[] = {
{ .compatible = "samsung,exynos4210-pinctrl", },
{ .compatible = "samsung,exynos4x12-pinctrl", },
+ { .compatible = "samsung,exynos5250-pinctrl", },
{ .compatible = "samsung,exynos5440-pinctrl", },
};
for_each_matching_node(pctrl_np, exynos_pinctrl_ids)
diff --git a/drivers/gpio/gpio-vt8500.c b/drivers/gpio/gpio-vt8500.c
deleted file mode 100644
index 81683ca35ac1..000000000000
--- a/drivers/gpio/gpio-vt8500.c
+++ /dev/null
@@ -1,355 +0,0 @@
-/* drivers/gpio/gpio-vt8500.c
- *
- * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
- * Based on arch/arm/mach-vt8500/gpio.c:
- * - Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/bitops.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_device.h>
-
-/*
- We handle GPIOs by bank, each bank containing up to 32 GPIOs covered
- by one set of registers (although not all may be valid).
-
- Because different SoC's have different register offsets, we pass the
- register offsets as data in vt8500_gpio_dt_ids[].
-
- A value of NO_REG is used to indicate that this register is not
- supported. Only used for ->en at the moment.
-*/
-
-#define NO_REG 0xFFFF
-
-/*
- * struct vt8500_gpio_bank_regoffsets
- * @en: offset to enable register of the bank
- * @dir: offset to direction register of the bank
- * @data_out: offset to the data out register of the bank
- * @data_in: offset to the data in register of the bank
- * @ngpio: highest valid pin in this bank
- */
-
-struct vt8500_gpio_bank_regoffsets {
- unsigned int en;
- unsigned int dir;
- unsigned int data_out;
- unsigned int data_in;
- unsigned char ngpio;
-};
-
-struct vt8500_gpio_data {
- unsigned int num_banks;
- struct vt8500_gpio_bank_regoffsets banks[];
-};
-
-#define VT8500_BANK(__en, __dir, __out, __in, __ngpio) \
-{ \
- .en = __en, \
- .dir = __dir, \
- .data_out = __out, \
- .data_in = __in, \
- .ngpio = __ngpio, \
-}
-
-static struct vt8500_gpio_data vt8500_data = {
- .num_banks = 7,
- .banks = {
- VT8500_BANK(NO_REG, 0x3C, 0x5C, 0x7C, 9),
- VT8500_BANK(0x00, 0x20, 0x40, 0x60, 26),
- VT8500_BANK(0x04, 0x24, 0x44, 0x64, 28),
- VT8500_BANK(0x08, 0x28, 0x48, 0x68, 31),
- VT8500_BANK(0x0C, 0x2C, 0x4C, 0x6C, 19),
- VT8500_BANK(0x10, 0x30, 0x50, 0x70, 19),
- VT8500_BANK(0x14, 0x34, 0x54, 0x74, 23),
- },
-};
-
-static struct vt8500_gpio_data wm8505_data = {
- .num_banks = 10,
- .banks = {
- VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22),
- VT8500_BANK(0x40, 0x68, 0x90, 0xB8, 8),
- VT8500_BANK(0x44, 0x6C, 0x94, 0xBC, 32),
- VT8500_BANK(0x48, 0x70, 0x98, 0xC0, 6),
- VT8500_BANK(0x4C, 0x74, 0x9C, 0xC4, 16),
- VT8500_BANK(0x50, 0x78, 0xA0, 0xC8, 25),
- VT8500_BANK(0x54, 0x7C, 0xA4, 0xCC, 5),
- VT8500_BANK(0x58, 0x80, 0xA8, 0xD0, 5),
- VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12),
- VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16),
- VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6),
- },
-};
-
-/*
- * No information about which bits are valid so we just make
- * them all available until its figured out.
- */
-static struct vt8500_gpio_data wm8650_data = {
- .num_banks = 9,
- .banks = {
- VT8500_BANK(0x40, 0x80, 0xC0, 0x00, 32),
- VT8500_BANK(0x44, 0x84, 0xC4, 0x04, 32),
- VT8500_BANK(0x48, 0x88, 0xC8, 0x08, 32),
- VT8500_BANK(0x4C, 0x8C, 0xCC, 0x0C, 32),
- VT8500_BANK(0x50, 0x90, 0xD0, 0x10, 32),
- VT8500_BANK(0x54, 0x94, 0xD4, 0x14, 32),
- VT8500_BANK(0x58, 0x98, 0xD8, 0x18, 32),
- VT8500_BANK(0x5C, 0x9C, 0xDC, 0x1C, 32),
- VT8500_BANK(0x7C, 0xBC, 0xFC, 0x3C, 32),
- VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6),
- },
-};
-
-struct vt8500_gpio_chip {
- struct gpio_chip chip;
-
- const struct vt8500_gpio_bank_regoffsets *regs;
- void __iomem *base;
-};
-
-struct vt8500_data {
- struct vt8500_gpio_chip *chip;
- void __iomem *iobase;
- int num_banks;
-};
-
-
-#define to_vt8500(__chip) container_of(__chip, struct vt8500_gpio_chip, chip)
-
-static int vt8500_gpio_request(struct gpio_chip *chip, unsigned offset)
-{
- u32 val;
- struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
-
- if (vt8500_chip->regs->en == NO_REG)
- return 0;
-
- val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->en);
- val |= BIT(offset);
- writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->en);
-
- return 0;
-}
-
-static void vt8500_gpio_free(struct gpio_chip *chip, unsigned offset)
-{
- struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
- u32 val;
-
- if (vt8500_chip->regs->en == NO_REG)
- return;
-
- val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->en);
- val &= ~BIT(offset);
- writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->en);
-}
-
-static int vt8500_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
-{
- struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
-
- u32 val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->dir);
- val &= ~BIT(offset);
- writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->dir);
-
- return 0;
-}
-
-static int vt8500_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
- int value)
-{
- struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
-
- u32 val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->dir);
- val |= BIT(offset);
- writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->dir);
-
- if (value) {
- val = readl_relaxed(vt8500_chip->base +
- vt8500_chip->regs->data_out);
- val |= BIT(offset);
- writel_relaxed(val, vt8500_chip->base +
- vt8500_chip->regs->data_out);
- }
- return 0;
-}
-
-static int vt8500_gpio_get_value(struct gpio_chip *chip, unsigned offset)
-{
- struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
-
- return (readl_relaxed(vt8500_chip->base + vt8500_chip->regs->data_in) >>
- offset) & 1;
-}
-
-static void vt8500_gpio_set_value(struct gpio_chip *chip, unsigned offset,
- int value)
-{
- struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
-
- u32 val = readl_relaxed(vt8500_chip->base +
- vt8500_chip->regs->data_out);
- if (value)
- val |= BIT(offset);
- else
- val &= ~BIT(offset);
-
- writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->data_out);
-}
-
-static int vt8500_of_xlate(struct gpio_chip *gc,
- const struct of_phandle_args *gpiospec, u32 *flags)
-{
- /* bank if specificed in gpiospec->args[0] */
- if (flags)
- *flags = gpiospec->args[2];
-
- return gpiospec->args[1];
-}
-
-static int vt8500_add_chips(struct platform_device *pdev, void __iomem *base,
- const struct vt8500_gpio_data *data)
-{
- struct vt8500_data *priv;
- struct vt8500_gpio_chip *vtchip;
- struct gpio_chip *chip;
- int i;
- int pin_cnt = 0;
-
- priv = devm_kzalloc(&pdev->dev, sizeof(struct vt8500_data), GFP_KERNEL);
- if (!priv) {
- dev_err(&pdev->dev, "failed to allocate memory\n");
- return -ENOMEM;
- }
-
- priv->chip = devm_kzalloc(&pdev->dev,
- sizeof(struct vt8500_gpio_chip) * data->num_banks,
- GFP_KERNEL);
- if (!priv->chip) {
- dev_err(&pdev->dev, "failed to allocate chip memory\n");
- return -ENOMEM;
- }
-
- priv->iobase = base;
- priv->num_banks = data->num_banks;
- platform_set_drvdata(pdev, priv);
-
- vtchip = priv->chip;
-
- for (i = 0; i < data->num_banks; i++) {
- vtchip[i].base = base;
- vtchip[i].regs = &data->banks[i];
-
- chip = &vtchip[i].chip;
-
- chip->of_xlate = vt8500_of_xlate;
- chip->of_gpio_n_cells = 3;
- chip->of_node = pdev->dev.of_node;
-
- chip->request = vt8500_gpio_request;
- chip->free = vt8500_gpio_free;
- chip->direction_input = vt8500_gpio_direction_input;
- chip->direction_output = vt8500_gpio_direction_output;
- chip->get = vt8500_gpio_get_value;
- chip->set = vt8500_gpio_set_value;
- chip->can_sleep = 0;
- chip->base = pin_cnt;
- chip->ngpio = data->banks[i].ngpio;
-
- pin_cnt += data->banks[i].ngpio;
-
- gpiochip_add(chip);
- }
- return 0;
-}
-
-static struct of_device_id vt8500_gpio_dt_ids[] = {
- { .compatible = "via,vt8500-gpio", .data = &vt8500_data, },
- { .compatible = "wm,wm8505-gpio", .data = &wm8505_data, },
- { .compatible = "wm,wm8650-gpio", .data = &wm8650_data, },
- { /* Sentinel */ },
-};
-
-static int vt8500_gpio_probe(struct platform_device *pdev)
-{
- int ret;
- void __iomem *gpio_base;
- struct resource *res;
- const struct of_device_id *of_id =
- of_match_device(vt8500_gpio_dt_ids, &pdev->dev);
-
- if (!of_id) {
- dev_err(&pdev->dev, "No matching driver data\n");
- return -ENODEV;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Unable to get IO resource\n");
- return -ENODEV;
- }
-
- gpio_base = devm_request_and_ioremap(&pdev->dev, res);
- if (!gpio_base) {
- dev_err(&pdev->dev, "Unable to map GPIO registers\n");
- return -ENOMEM;
- }
-
- ret = vt8500_add_chips(pdev, gpio_base, of_id->data);
-
- return ret;
-}
-
-static int vt8500_gpio_remove(struct platform_device *pdev)
-{
- int i;
- int ret;
- struct vt8500_data *priv = platform_get_drvdata(pdev);
- struct vt8500_gpio_chip *vtchip = priv->chip;
-
- for (i = 0; i < priv->num_banks; i++) {
- ret = gpiochip_remove(&vtchip[i].chip);
- if (ret)
- dev_warn(&pdev->dev, "gpiochip_remove returned %d\n",
- ret);
- }
-
- return 0;
-}
-
-static struct platform_driver vt8500_gpio_driver = {
- .probe = vt8500_gpio_probe,
- .remove = vt8500_gpio_remove,
- .driver = {
- .name = "vt8500-gpio",
- .owner = THIS_MODULE,
- .of_match_table = vt8500_gpio_dt_ids,
- },
-};
-
-module_platform_driver(vt8500_gpio_driver);
-
-MODULE_DESCRIPTION("VT8500 GPIO Driver");
-MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
-MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, vt8500_gpio_dt_ids);
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index a350969e5efe..4a33351c25dc 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -25,6 +25,14 @@ config ARM_VIC_NR
The maximum number of VICs available in the system, for
power management.
+config RENESAS_INTC_IRQPIN
+ bool
+ select IRQ_DOMAIN
+
+config RENESAS_IRQC
+ bool
+ select IRQ_DOMAIN
+
config VERSATILE_FPGA_IRQ
bool
select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 10ef57f35a6e..c28fcccf4a0d 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_IRQCHIP) += irqchip.o
obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o
obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o
obj-$(CONFIG_ARCH_MXS) += irq-mxs.o
+obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o
obj-$(CONFIG_METAG) += irq-metag-ext.o
obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o
obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o
@@ -10,4 +11,7 @@ obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
obj-$(CONFIG_ARM_GIC) += irq-gic.o
obj-$(CONFIG_ARM_VIC) += irq-vic.o
obj-$(CONFIG_SIRF_IRQ) += irq-sirfsoc.o
+obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o
+obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o
obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o
+obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o
diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c
index 6a5201351507..02492ab20d22 100644
--- a/drivers/irqchip/exynos-combiner.c
+++ b/drivers/irqchip/exynos-combiner.c
@@ -32,6 +32,7 @@ struct combiner_chip_data {
unsigned int irq_offset;
unsigned int irq_mask;
void __iomem *base;
+ unsigned int parent_irq;
};
static struct irq_domain *combiner_irq_domain;
@@ -88,22 +89,46 @@ static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
+#ifdef CONFIG_SMP
+static int combiner_set_affinity(struct irq_data *d,
+ const struct cpumask *mask_val, bool force)
+{
+ struct combiner_chip_data *chip_data = irq_data_get_irq_chip_data(d);
+ struct irq_chip *chip = irq_get_chip(chip_data->parent_irq);
+ struct irq_data *data = irq_get_irq_data(chip_data->parent_irq);
+
+ if (chip && chip->irq_set_affinity)
+ return chip->irq_set_affinity(data, mask_val, force);
+ else
+ return -EINVAL;
+}
+#endif
+
static struct irq_chip combiner_chip = {
- .name = "COMBINER",
- .irq_mask = combiner_mask_irq,
- .irq_unmask = combiner_unmask_irq,
+ .name = "COMBINER",
+ .irq_mask = combiner_mask_irq,
+ .irq_unmask = combiner_unmask_irq,
+#ifdef CONFIG_SMP
+ .irq_set_affinity = combiner_set_affinity,
+#endif
};
-static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq)
+static unsigned int max_combiner_nr(void)
{
- unsigned int max_nr;
-
if (soc_is_exynos5250())
- max_nr = EXYNOS5_MAX_COMBINER_NR;
+ return EXYNOS5_MAX_COMBINER_NR;
+ else if (soc_is_exynos4412())
+ return EXYNOS4412_MAX_COMBINER_NR;
+ else if (soc_is_exynos4212())
+ return EXYNOS4212_MAX_COMBINER_NR;
else
- max_nr = EXYNOS4_MAX_COMBINER_NR;
+ return EXYNOS4210_MAX_COMBINER_NR;
+}
- if (combiner_nr >= max_nr)
+static void __init combiner_cascade_irq(unsigned int combiner_nr,
+ unsigned int irq)
+{
+ if (combiner_nr >= max_combiner_nr())
BUG();
if (irq_set_handler_data(irq, &combiner_data[combiner_nr]) != 0)
BUG();
@@ -111,12 +136,13 @@ static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int i
}
static void __init combiner_init_one(unsigned int combiner_nr,
- void __iomem *base)
+ void __iomem *base, unsigned int irq)
{
combiner_data[combiner_nr].base = base;
combiner_data[combiner_nr].irq_offset = irq_find_mapping(
combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER);
combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3);
+ combiner_data[combiner_nr].parent_irq = irq;
/* Disable all interrupts */
__raw_writel(combiner_data[combiner_nr].irq_mask,
@@ -167,23 +193,38 @@ static struct irq_domain_ops combiner_irq_domain_ops = {
.map = combiner_irq_domain_map,
};
+static unsigned int exynos4x12_combiner_extra_irq(int group)
+{
+ switch (group) {
+ case 16:
+ return IRQ_SPI(107);
+ case 17:
+ return IRQ_SPI(108);
+ case 18:
+ return IRQ_SPI(48);
+ case 19:
+ return IRQ_SPI(42);
+ default:
+ return 0;
+ }
+}
+
void __init combiner_init(void __iomem *combiner_base,
struct device_node *np)
{
int i, irq, irq_base;
unsigned int max_nr, nr_irq;
+ max_nr = max_combiner_nr();
+
if (np) {
if (of_property_read_u32(np, "samsung,combiner-nr", &max_nr)) {
- pr_warning("%s: number of combiners not specified, "
+ pr_info("%s: number of combiners not specified, "
"setting default as %d.\n",
- __func__, EXYNOS4_MAX_COMBINER_NR);
- max_nr = EXYNOS4_MAX_COMBINER_NR;
+ __func__, max_nr);
}
- } else {
- max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR :
- EXYNOS4_MAX_COMBINER_NR;
}
+
nr_irq = max_nr * MAX_IRQ_IN_COMBINER;
irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0);
@@ -200,12 +241,15 @@ void __init combiner_init(void __iomem *combiner_base,
}
for (i = 0; i < max_nr; i++) {
- combiner_init_one(i, combiner_base + (i >> 2) * 0x10);
- irq = IRQ_SPI(i);
+ if (i < EXYNOS4210_MAX_COMBINER_NR || soc_is_exynos5250())
+ irq = IRQ_SPI(i);
+ else
+ irq = exynos4x12_combiner_extra_irq(i);
#ifdef CONFIG_OF
if (np)
irq = irq_of_parse_and_map(np, i);
#endif
+ combiner_init_one(i, combiner_base + (i >> 2) * 0x10, irq);
combiner_cascade_irq(i, irq);
}
}
diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c
new file mode 100644
index 000000000000..5a68e5accec1
--- /dev/null
+++ b/drivers/irqchip/irq-renesas-intc-irqpin.c
@@ -0,0 +1,547 @@
+/*
+ * Renesas INTC External IRQ Pin Driver
+ *
+ * Copyright (C) 2013 Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_data/irq-renesas-intc-irqpin.h>
+
+#define INTC_IRQPIN_MAX 8 /* maximum 8 interrupts per driver instance */
+
+#define INTC_IRQPIN_REG_SENSE 0 /* ICRn */
+#define INTC_IRQPIN_REG_PRIO 1 /* INTPRInn */
+#define INTC_IRQPIN_REG_SOURCE 2 /* INTREQnn */
+#define INTC_IRQPIN_REG_MASK 3 /* INTMSKnn */
+#define INTC_IRQPIN_REG_CLEAR 4 /* INTMSKCLRnn */
+#define INTC_IRQPIN_REG_NR 5
+
+/* INTC external IRQ PIN hardware register access:
+ *
+ * SENSE is read-write 32-bit with 2-bits or 4-bits per IRQ (*)
+ * PRIO is read-write 32-bit with 4-bits per IRQ (**)
+ * SOURCE is read-only 32-bit or 8-bit with 1-bit per IRQ (***)
+ * MASK is write-only 32-bit or 8-bit with 1-bit per IRQ (***)
+ * CLEAR is write-only 32-bit or 8-bit with 1-bit per IRQ (***)
+ *
+ * (*) May be accessed by more than one driver instance - lock needed
+ * (**) Read-modify-write access by one driver instance - lock needed
+ * (***) Accessed by one driver instance only - no locking needed
+ */
+
+struct intc_irqpin_iomem {
+ void __iomem *iomem;
+ unsigned long (*read)(void __iomem *iomem);
+ void (*write)(void __iomem *iomem, unsigned long data);
+ int width;
+};
+
+struct intc_irqpin_irq {
+ int hw_irq;
+ int requested_irq;
+ int domain_irq;
+ struct intc_irqpin_priv *p;
+};
+
+struct intc_irqpin_priv {
+ struct intc_irqpin_iomem iomem[INTC_IRQPIN_REG_NR];
+ struct intc_irqpin_irq irq[INTC_IRQPIN_MAX];
+ struct renesas_intc_irqpin_config config;
+ unsigned int number_of_irqs;
+ struct platform_device *pdev;
+ struct irq_chip irq_chip;
+ struct irq_domain *irq_domain;
+ bool shared_irqs;
+ u8 shared_irq_mask;
+};
+
+static unsigned long intc_irqpin_read32(void __iomem *iomem)
+{
+ return ioread32(iomem);
+}
+
+static unsigned long intc_irqpin_read8(void __iomem *iomem)
+{
+ return ioread8(iomem);
+}
+
+static void intc_irqpin_write32(void __iomem *iomem, unsigned long data)
+{
+ iowrite32(data, iomem);
+}
+
+static void intc_irqpin_write8(void __iomem *iomem, unsigned long data)
+{
+ iowrite8(data, iomem);
+}
+
+static inline unsigned long intc_irqpin_read(struct intc_irqpin_priv *p,
+ int reg)
+{
+ struct intc_irqpin_iomem *i = &p->iomem[reg];
+
+ return i->read(i->iomem);
+}
+
+static inline void intc_irqpin_write(struct intc_irqpin_priv *p,
+ int reg, unsigned long data)
+{
+ struct intc_irqpin_iomem *i = &p->iomem[reg];
+
+ i->write(i->iomem, data);
+}
+
+static inline unsigned long intc_irqpin_hwirq_mask(struct intc_irqpin_priv *p,
+ int reg, int hw_irq)
+{
+ return BIT((p->iomem[reg].width - 1) - hw_irq);
+}
+
+static inline void intc_irqpin_irq_write_hwirq(struct intc_irqpin_priv *p,
+ int reg, int hw_irq)
+{
+ intc_irqpin_write(p, reg, intc_irqpin_hwirq_mask(p, reg, hw_irq));
+}
+
+static DEFINE_RAW_SPINLOCK(intc_irqpin_lock); /* only used by slow path */
+
+static void intc_irqpin_read_modify_write(struct intc_irqpin_priv *p,
+ int reg, int shift,
+ int width, int value)
+{
+ unsigned long flags;
+ unsigned long tmp;
+
+ raw_spin_lock_irqsave(&intc_irqpin_lock, flags);
+
+ tmp = intc_irqpin_read(p, reg);
+ tmp &= ~(((1 << width) - 1) << shift);
+ tmp |= value << shift;
+ intc_irqpin_write(p, reg, tmp);
+
+ raw_spin_unlock_irqrestore(&intc_irqpin_lock, flags);
+}
+
+static void intc_irqpin_mask_unmask_prio(struct intc_irqpin_priv *p,
+ int irq, int do_mask)
+{
+ int bitfield_width = 4; /* PRIO assumed to have fixed bitfield width */
+ int shift = (7 - irq) * bitfield_width; /* PRIO assumed to be 32-bit */
+
+ intc_irqpin_read_modify_write(p, INTC_IRQPIN_REG_PRIO,
+ shift, bitfield_width,
+ do_mask ? 0 : (1 << bitfield_width) - 1);
+}
+
+static int intc_irqpin_set_sense(struct intc_irqpin_priv *p, int irq, int value)
+{
+ int bitfield_width = p->config.sense_bitfield_width;
+ int shift = (7 - irq) * bitfield_width; /* SENSE assumed to be 32-bit */
+
+ dev_dbg(&p->pdev->dev, "sense irq = %d, mode = %d\n", irq, value);
+
+ if (value >= (1 << bitfield_width))
+ return -EINVAL;
+
+ intc_irqpin_read_modify_write(p, INTC_IRQPIN_REG_SENSE, shift,
+ bitfield_width, value);
+ return 0;
+}
+
+static void intc_irqpin_dbg(struct intc_irqpin_irq *i, char *str)
+{
+ dev_dbg(&i->p->pdev->dev, "%s (%d:%d:%d)\n",
+ str, i->requested_irq, i->hw_irq, i->domain_irq);
+}
+
+static void intc_irqpin_irq_enable(struct irq_data *d)
+{
+ struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
+ int hw_irq = irqd_to_hwirq(d);
+
+ intc_irqpin_dbg(&p->irq[hw_irq], "enable");
+ intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_CLEAR, hw_irq);
+}
+
+static void intc_irqpin_irq_disable(struct irq_data *d)
+{
+ struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
+ int hw_irq = irqd_to_hwirq(d);
+
+ intc_irqpin_dbg(&p->irq[hw_irq], "disable");
+ intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_MASK, hw_irq);
+}
+
+static void intc_irqpin_shared_irq_enable(struct irq_data *d)
+{
+ struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
+ int hw_irq = irqd_to_hwirq(d);
+
+ intc_irqpin_dbg(&p->irq[hw_irq], "shared enable");
+ intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_CLEAR, hw_irq);
+
+ p->shared_irq_mask &= ~BIT(hw_irq);
+}
+
+static void intc_irqpin_shared_irq_disable(struct irq_data *d)
+{
+ struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
+ int hw_irq = irqd_to_hwirq(d);
+
+ intc_irqpin_dbg(&p->irq[hw_irq], "shared disable");
+ intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_MASK, hw_irq);
+
+ p->shared_irq_mask |= BIT(hw_irq);
+}
+
+static void intc_irqpin_irq_enable_force(struct irq_data *d)
+{
+ struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
+ int irq = p->irq[irqd_to_hwirq(d)].requested_irq;
+
+ intc_irqpin_irq_enable(d);
+
+ /* enable interrupt through parent interrupt controller,
+ * assumes non-shared interrupt with 1:1 mapping
+ * needed for busted IRQs on some SoCs like sh73a0
+ */
+ irq_get_chip(irq)->irq_unmask(irq_get_irq_data(irq));
+}
+
+static void intc_irqpin_irq_disable_force(struct irq_data *d)
+{
+ struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
+ int irq = p->irq[irqd_to_hwirq(d)].requested_irq;
+
+ /* disable interrupt through parent interrupt controller,
+ * assumes non-shared interrupt with 1:1 mapping
+ * needed for busted IRQs on some SoCs like sh73a0
+ */
+ irq_get_chip(irq)->irq_mask(irq_get_irq_data(irq));
+ intc_irqpin_irq_disable(d);
+}
+
+#define INTC_IRQ_SENSE_VALID 0x10
+#define INTC_IRQ_SENSE(x) (x + INTC_IRQ_SENSE_VALID)
+
+static unsigned char intc_irqpin_sense[IRQ_TYPE_SENSE_MASK + 1] = {
+ [IRQ_TYPE_EDGE_FALLING] = INTC_IRQ_SENSE(0x00),
+ [IRQ_TYPE_EDGE_RISING] = INTC_IRQ_SENSE(0x01),
+ [IRQ_TYPE_LEVEL_LOW] = INTC_IRQ_SENSE(0x02),
+ [IRQ_TYPE_LEVEL_HIGH] = INTC_IRQ_SENSE(0x03),
+ [IRQ_TYPE_EDGE_BOTH] = INTC_IRQ_SENSE(0x04),
+};
+
+static int intc_irqpin_irq_set_type(struct irq_data *d, unsigned int type)
+{
+ unsigned char value = intc_irqpin_sense[type & IRQ_TYPE_SENSE_MASK];
+ struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
+
+ if (!(value & INTC_IRQ_SENSE_VALID))
+ return -EINVAL;
+
+ return intc_irqpin_set_sense(p, irqd_to_hwirq(d),
+ value ^ INTC_IRQ_SENSE_VALID);
+}
+
+static irqreturn_t intc_irqpin_irq_handler(int irq, void *dev_id)
+{
+ struct intc_irqpin_irq *i = dev_id;
+ struct intc_irqpin_priv *p = i->p;
+ unsigned long bit;
+
+ intc_irqpin_dbg(i, "demux1");
+ bit = intc_irqpin_hwirq_mask(p, INTC_IRQPIN_REG_SOURCE, i->hw_irq);
+
+ if (intc_irqpin_read(p, INTC_IRQPIN_REG_SOURCE) & bit) {
+ intc_irqpin_write(p, INTC_IRQPIN_REG_SOURCE, ~bit);
+ intc_irqpin_dbg(i, "demux2");
+ generic_handle_irq(i->domain_irq);
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
+}
+
+static irqreturn_t intc_irqpin_shared_irq_handler(int irq, void *dev_id)
+{
+ struct intc_irqpin_priv *p = dev_id;
+ unsigned int reg_source = intc_irqpin_read(p, INTC_IRQPIN_REG_SOURCE);
+ irqreturn_t status = IRQ_NONE;
+ int k;
+
+ for (k = 0; k < 8; k++) {
+ if (reg_source & BIT(7 - k)) {
+ if (BIT(k) & p->shared_irq_mask)
+ continue;
+
+ status |= intc_irqpin_irq_handler(irq, &p->irq[k]);
+ }
+ }
+
+ return status;
+}
+
+static int intc_irqpin_irq_domain_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct intc_irqpin_priv *p = h->host_data;
+
+ p->irq[hw].domain_irq = virq;
+ p->irq[hw].hw_irq = hw;
+
+ intc_irqpin_dbg(&p->irq[hw], "map");
+ irq_set_chip_data(virq, h->host_data);
+ irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq);
+ set_irq_flags(virq, IRQF_VALID); /* kill me now */
+ return 0;
+}
+
+static struct irq_domain_ops intc_irqpin_irq_domain_ops = {
+ .map = intc_irqpin_irq_domain_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+static int intc_irqpin_probe(struct platform_device *pdev)
+{
+ struct renesas_intc_irqpin_config *pdata = pdev->dev.platform_data;
+ struct intc_irqpin_priv *p;
+ struct intc_irqpin_iomem *i;
+ struct resource *io[INTC_IRQPIN_REG_NR];
+ struct resource *irq;
+ struct irq_chip *irq_chip;
+ void (*enable_fn)(struct irq_data *d);
+ void (*disable_fn)(struct irq_data *d);
+ const char *name = dev_name(&pdev->dev);
+ int ref_irq;
+ int ret;
+ int k;
+
+ p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
+ if (!p) {
+ dev_err(&pdev->dev, "failed to allocate driver data\n");
+ ret = -ENOMEM;
+ goto err0;
+ }
+
+ /* deal with driver instance configuration */
+ if (pdata)
+ memcpy(&p->config, pdata, sizeof(*pdata));
+ if (!p->config.sense_bitfield_width)
+ p->config.sense_bitfield_width = 4; /* default to 4 bits */
+
+ p->pdev = pdev;
+ platform_set_drvdata(pdev, p);
+
+ /* get hold of manadatory IOMEM */
+ for (k = 0; k < INTC_IRQPIN_REG_NR; k++) {
+ io[k] = platform_get_resource(pdev, IORESOURCE_MEM, k);
+ if (!io[k]) {
+ dev_err(&pdev->dev, "not enough IOMEM resources\n");
+ ret = -EINVAL;
+ goto err0;
+ }
+ }
+
+ /* allow any number of IRQs between 1 and INTC_IRQPIN_MAX */
+ for (k = 0; k < INTC_IRQPIN_MAX; k++) {
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, k);
+ if (!irq)
+ break;
+
+ p->irq[k].p = p;
+ p->irq[k].requested_irq = irq->start;
+ }
+
+ p->number_of_irqs = k;
+ if (p->number_of_irqs < 1) {
+ dev_err(&pdev->dev, "not enough IRQ resources\n");
+ ret = -EINVAL;
+ goto err0;
+ }
+
+ /* ioremap IOMEM and setup read/write callbacks */
+ for (k = 0; k < INTC_IRQPIN_REG_NR; k++) {
+ i = &p->iomem[k];
+
+ switch (resource_size(io[k])) {
+ case 1:
+ i->width = 8;
+ i->read = intc_irqpin_read8;
+ i->write = intc_irqpin_write8;
+ break;
+ case 4:
+ i->width = 32;
+ i->read = intc_irqpin_read32;
+ i->write = intc_irqpin_write32;
+ break;
+ default:
+ dev_err(&pdev->dev, "IOMEM size mismatch\n");
+ ret = -EINVAL;
+ goto err0;
+ }
+
+ i->iomem = devm_ioremap_nocache(&pdev->dev, io[k]->start,
+ resource_size(io[k]));
+ if (!i->iomem) {
+ dev_err(&pdev->dev, "failed to remap IOMEM\n");
+ ret = -ENXIO;
+ goto err0;
+ }
+ }
+
+ /* mask all interrupts using priority */
+ for (k = 0; k < p->number_of_irqs; k++)
+ intc_irqpin_mask_unmask_prio(p, k, 1);
+
+ /* clear all pending interrupts */
+ intc_irqpin_write(p, INTC_IRQPIN_REG_SOURCE, 0x0);
+
+ /* scan for shared interrupt lines */
+ ref_irq = p->irq[0].requested_irq;
+ p->shared_irqs = true;
+ for (k = 1; k < p->number_of_irqs; k++) {
+ if (ref_irq != p->irq[k].requested_irq) {
+ p->shared_irqs = false;
+ break;
+ }
+ }
+
+ /* use more severe masking method if requested */
+ if (p->config.control_parent) {
+ enable_fn = intc_irqpin_irq_enable_force;
+ disable_fn = intc_irqpin_irq_disable_force;
+ } else if (!p->shared_irqs) {
+ enable_fn = intc_irqpin_irq_enable;
+ disable_fn = intc_irqpin_irq_disable;
+ } else {
+ enable_fn = intc_irqpin_shared_irq_enable;
+ disable_fn = intc_irqpin_shared_irq_disable;
+ }
+
+ irq_chip = &p->irq_chip;
+ irq_chip->name = name;
+ irq_chip->irq_mask = disable_fn;
+ irq_chip->irq_unmask = enable_fn;
+ irq_chip->irq_enable = enable_fn;
+ irq_chip->irq_disable = disable_fn;
+ irq_chip->irq_set_type = intc_irqpin_irq_set_type;
+ irq_chip->flags = IRQCHIP_SKIP_SET_WAKE;
+
+ p->irq_domain = irq_domain_add_simple(pdev->dev.of_node,
+ p->number_of_irqs,
+ p->config.irq_base,
+ &intc_irqpin_irq_domain_ops, p);
+ if (!p->irq_domain) {
+ ret = -ENXIO;
+ dev_err(&pdev->dev, "cannot initialize irq domain\n");
+ goto err0;
+ }
+
+ if (p->shared_irqs) {
+ /* request one shared interrupt */
+ if (devm_request_irq(&pdev->dev, p->irq[0].requested_irq,
+ intc_irqpin_shared_irq_handler,
+ IRQF_SHARED, name, p)) {
+ dev_err(&pdev->dev, "failed to request low IRQ\n");
+ ret = -ENOENT;
+ goto err1;
+ }
+ } else {
+ /* request interrupts one by one */
+ for (k = 0; k < p->number_of_irqs; k++) {
+ if (devm_request_irq(&pdev->dev,
+ p->irq[k].requested_irq,
+ intc_irqpin_irq_handler,
+ 0, name, &p->irq[k])) {
+ dev_err(&pdev->dev,
+ "failed to request low IRQ\n");
+ ret = -ENOENT;
+ goto err1;
+ }
+ }
+ }
+
+ /* unmask all interrupts on prio level */
+ for (k = 0; k < p->number_of_irqs; k++)
+ intc_irqpin_mask_unmask_prio(p, k, 0);
+
+ dev_info(&pdev->dev, "driving %d irqs\n", p->number_of_irqs);
+
+ /* warn in case of mismatch if irq base is specified */
+ if (p->config.irq_base) {
+ if (p->config.irq_base != p->irq[0].domain_irq)
+ dev_warn(&pdev->dev, "irq base mismatch (%d/%d)\n",
+ p->config.irq_base, p->irq[0].domain_irq);
+ }
+
+ return 0;
+
+err1:
+ irq_domain_remove(p->irq_domain);
+err0:
+ return ret;
+}
+
+static int intc_irqpin_remove(struct platform_device *pdev)
+{
+ struct intc_irqpin_priv *p = platform_get_drvdata(pdev);
+
+ irq_domain_remove(p->irq_domain);
+
+ return 0;
+}
+
+static const struct of_device_id intc_irqpin_dt_ids[] = {
+ { .compatible = "renesas,intc-irqpin", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, intc_irqpin_dt_ids);
+
+static struct platform_driver intc_irqpin_device_driver = {
+ .probe = intc_irqpin_probe,
+ .remove = intc_irqpin_remove,
+ .driver = {
+ .name = "renesas_intc_irqpin",
+ .of_match_table = intc_irqpin_dt_ids,
+ .owner = THIS_MODULE,
+ }
+};
+
+static int __init intc_irqpin_init(void)
+{
+ return platform_driver_register(&intc_irqpin_device_driver);
+}
+postcore_initcall(intc_irqpin_init);
+
+static void __exit intc_irqpin_exit(void)
+{
+ platform_driver_unregister(&intc_irqpin_device_driver);
+}
+module_exit(intc_irqpin_exit);
+
+MODULE_AUTHOR("Magnus Damm");
+MODULE_DESCRIPTION("Renesas INTC External IRQ Pin Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c
new file mode 100644
index 000000000000..927bff373aac
--- /dev/null
+++ b/drivers/irqchip/irq-renesas-irqc.c
@@ -0,0 +1,307 @@
+/*
+ * Renesas IRQC Driver
+ *
+ * Copyright (C) 2013 Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_data/irq-renesas-irqc.h>
+
+#define IRQC_IRQ_MAX 32 /* maximum 32 interrupts per driver instance */
+
+#define IRQC_REQ_STS 0x00
+#define IRQC_EN_STS 0x04
+#define IRQC_EN_SET 0x08
+#define IRQC_INT_CPU_BASE(n) (0x000 + ((n) * 0x10))
+#define DETECT_STATUS 0x100
+#define IRQC_CONFIG(n) (0x180 + ((n) * 0x04))
+
+struct irqc_irq {
+ int hw_irq;
+ int requested_irq;
+ int domain_irq;
+ struct irqc_priv *p;
+};
+
+struct irqc_priv {
+ void __iomem *iomem;
+ void __iomem *cpu_int_base;
+ struct irqc_irq irq[IRQC_IRQ_MAX];
+ struct renesas_irqc_config config;
+ unsigned int number_of_irqs;
+ struct platform_device *pdev;
+ struct irq_chip irq_chip;
+ struct irq_domain *irq_domain;
+};
+
+static void irqc_dbg(struct irqc_irq *i, char *str)
+{
+ dev_dbg(&i->p->pdev->dev, "%s (%d:%d:%d)\n",
+ str, i->requested_irq, i->hw_irq, i->domain_irq);
+}
+
+static void irqc_irq_enable(struct irq_data *d)
+{
+ struct irqc_priv *p = irq_data_get_irq_chip_data(d);
+ int hw_irq = irqd_to_hwirq(d);
+
+ irqc_dbg(&p->irq[hw_irq], "enable");
+ iowrite32(BIT(hw_irq), p->cpu_int_base + IRQC_EN_SET);
+}
+
+static void irqc_irq_disable(struct irq_data *d)
+{
+ struct irqc_priv *p = irq_data_get_irq_chip_data(d);
+ int hw_irq = irqd_to_hwirq(d);
+
+ irqc_dbg(&p->irq[hw_irq], "disable");
+ iowrite32(BIT(hw_irq), p->cpu_int_base + IRQC_EN_STS);
+}
+
+#define INTC_IRQ_SENSE_VALID 0x10
+#define INTC_IRQ_SENSE(x) (x + INTC_IRQ_SENSE_VALID)
+
+static unsigned char irqc_sense[IRQ_TYPE_SENSE_MASK + 1] = {
+ [IRQ_TYPE_LEVEL_LOW] = INTC_IRQ_SENSE(0x01),
+ [IRQ_TYPE_LEVEL_HIGH] = INTC_IRQ_SENSE(0x02),
+ [IRQ_TYPE_EDGE_FALLING] = INTC_IRQ_SENSE(0x04), /* Synchronous */
+ [IRQ_TYPE_EDGE_RISING] = INTC_IRQ_SENSE(0x08), /* Synchronous */
+ [IRQ_TYPE_EDGE_BOTH] = INTC_IRQ_SENSE(0x0c), /* Synchronous */
+};
+
+static int irqc_irq_set_type(struct irq_data *d, unsigned int type)
+{
+ struct irqc_priv *p = irq_data_get_irq_chip_data(d);
+ int hw_irq = irqd_to_hwirq(d);
+ unsigned char value = irqc_sense[type & IRQ_TYPE_SENSE_MASK];
+ unsigned long tmp;
+
+ irqc_dbg(&p->irq[hw_irq], "sense");
+
+ if (!(value & INTC_IRQ_SENSE_VALID))
+ return -EINVAL;
+
+ tmp = ioread32(p->iomem + IRQC_CONFIG(hw_irq));
+ tmp &= ~0x3f;
+ tmp |= value ^ INTC_IRQ_SENSE_VALID;
+ iowrite32(tmp, p->iomem + IRQC_CONFIG(hw_irq));
+ return 0;
+}
+
+static irqreturn_t irqc_irq_handler(int irq, void *dev_id)
+{
+ struct irqc_irq *i = dev_id;
+ struct irqc_priv *p = i->p;
+ unsigned long bit = BIT(i->hw_irq);
+
+ irqc_dbg(i, "demux1");
+
+ if (ioread32(p->iomem + DETECT_STATUS) & bit) {
+ iowrite32(bit, p->iomem + DETECT_STATUS);
+ irqc_dbg(i, "demux2");
+ generic_handle_irq(i->domain_irq);
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
+}
+
+static int irqc_irq_domain_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct irqc_priv *p = h->host_data;
+
+ p->irq[hw].domain_irq = virq;
+ p->irq[hw].hw_irq = hw;
+
+ irqc_dbg(&p->irq[hw], "map");
+ irq_set_chip_data(virq, h->host_data);
+ irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq);
+ set_irq_flags(virq, IRQF_VALID); /* kill me now */
+ return 0;
+}
+
+static struct irq_domain_ops irqc_irq_domain_ops = {
+ .map = irqc_irq_domain_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+static int irqc_probe(struct platform_device *pdev)
+{
+ struct renesas_irqc_config *pdata = pdev->dev.platform_data;
+ struct irqc_priv *p;
+ struct resource *io;
+ struct resource *irq;
+ struct irq_chip *irq_chip;
+ const char *name = dev_name(&pdev->dev);
+ int ret;
+ int k;
+
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p) {
+ dev_err(&pdev->dev, "failed to allocate driver data\n");
+ ret = -ENOMEM;
+ goto err0;
+ }
+
+ /* deal with driver instance configuration */
+ if (pdata)
+ memcpy(&p->config, pdata, sizeof(*pdata));
+
+ p->pdev = pdev;
+ platform_set_drvdata(pdev, p);
+
+ /* get hold of manadatory IOMEM */
+ io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!io) {
+ dev_err(&pdev->dev, "not enough IOMEM resources\n");
+ ret = -EINVAL;
+ goto err1;
+ }
+
+ /* allow any number of IRQs between 1 and IRQC_IRQ_MAX */
+ for (k = 0; k < IRQC_IRQ_MAX; k++) {
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, k);
+ if (!irq)
+ break;
+
+ p->irq[k].p = p;
+ p->irq[k].requested_irq = irq->start;
+ }
+
+ p->number_of_irqs = k;
+ if (p->number_of_irqs < 1) {
+ dev_err(&pdev->dev, "not enough IRQ resources\n");
+ ret = -EINVAL;
+ goto err1;
+ }
+
+ /* ioremap IOMEM and setup read/write callbacks */
+ p->iomem = ioremap_nocache(io->start, resource_size(io));
+ if (!p->iomem) {
+ dev_err(&pdev->dev, "failed to remap IOMEM\n");
+ ret = -ENXIO;
+ goto err2;
+ }
+
+ p->cpu_int_base = p->iomem + IRQC_INT_CPU_BASE(0); /* SYS-SPI */
+
+ irq_chip = &p->irq_chip;
+ irq_chip->name = name;
+ irq_chip->irq_mask = irqc_irq_disable;
+ irq_chip->irq_unmask = irqc_irq_enable;
+ irq_chip->irq_enable = irqc_irq_enable;
+ irq_chip->irq_disable = irqc_irq_disable;
+ irq_chip->irq_set_type = irqc_irq_set_type;
+ irq_chip->flags = IRQCHIP_SKIP_SET_WAKE;
+
+ p->irq_domain = irq_domain_add_simple(pdev->dev.of_node,
+ p->number_of_irqs,
+ p->config.irq_base,
+ &irqc_irq_domain_ops, p);
+ if (!p->irq_domain) {
+ ret = -ENXIO;
+ dev_err(&pdev->dev, "cannot initialize irq domain\n");
+ goto err2;
+ }
+
+ /* request interrupts one by one */
+ for (k = 0; k < p->number_of_irqs; k++) {
+ if (request_irq(p->irq[k].requested_irq, irqc_irq_handler,
+ 0, name, &p->irq[k])) {
+ dev_err(&pdev->dev, "failed to request IRQ\n");
+ ret = -ENOENT;
+ goto err3;
+ }
+ }
+
+ dev_info(&pdev->dev, "driving %d irqs\n", p->number_of_irqs);
+
+ /* warn in case of mismatch if irq base is specified */
+ if (p->config.irq_base) {
+ if (p->config.irq_base != p->irq[0].domain_irq)
+ dev_warn(&pdev->dev, "irq base mismatch (%d/%d)\n",
+ p->config.irq_base, p->irq[0].domain_irq);
+ }
+
+ return 0;
+err3:
+ for (; k >= 0; k--)
+ free_irq(p->irq[k - 1].requested_irq, &p->irq[k - 1]);
+
+ irq_domain_remove(p->irq_domain);
+err2:
+ iounmap(p->iomem);
+err1:
+ kfree(p);
+err0:
+ return ret;
+}
+
+static int irqc_remove(struct platform_device *pdev)
+{
+ struct irqc_priv *p = platform_get_drvdata(pdev);
+ int k;
+
+ for (k = 0; k < p->number_of_irqs; k++)
+ free_irq(p->irq[k].requested_irq, &p->irq[k]);
+
+ irq_domain_remove(p->irq_domain);
+ iounmap(p->iomem);
+ kfree(p);
+ return 0;
+}
+
+static const struct of_device_id irqc_dt_ids[] = {
+ { .compatible = "renesas,irqc", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, irqc_dt_ids);
+
+static struct platform_driver irqc_device_driver = {
+ .probe = irqc_probe,
+ .remove = irqc_remove,
+ .driver = {
+ .name = "renesas_irqc",
+ .of_match_table = irqc_dt_ids,
+ .owner = THIS_MODULE,
+ }
+};
+
+static int __init irqc_init(void)
+{
+ return platform_driver_register(&irqc_device_driver);
+}
+postcore_initcall(irqc_init);
+
+static void __exit irqc_exit(void)
+{
+ platform_driver_unregister(&irqc_device_driver);
+}
+module_exit(irqc_exit);
+
+MODULE_AUTHOR("Magnus Damm");
+MODULE_DESCRIPTION("Renesas IRQC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/irqchip/irq-s3c24xx.c b/drivers/irqchip/irq-s3c24xx.c
new file mode 100644
index 000000000000..bbcc944ed94f
--- /dev/null
+++ b/drivers/irqchip/irq-s3c24xx.c
@@ -0,0 +1,1356 @@
+/*
+ * S3C24XX IRQ handling
+ *
+ * Copyright (c) 2003-2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ * Copyright (c) 2012 Heiko Stuebner <heiko@sntech.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+*/
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+
+#include <asm/exception.h>
+#include <asm/mach/irq.h>
+
+#include <mach/regs-irq.h>
+#include <mach/regs-gpio.h>
+
+#include <plat/cpu.h>
+#include <plat/regs-irqtype.h>
+#include <plat/pm.h>
+
+#include "irqchip.h"
+
+#define S3C_IRQTYPE_NONE 0
+#define S3C_IRQTYPE_EINT 1
+#define S3C_IRQTYPE_EDGE 2
+#define S3C_IRQTYPE_LEVEL 3
+
+struct s3c_irq_data {
+ unsigned int type;
+ unsigned long offset;
+ unsigned long parent_irq;
+
+ /* data gets filled during init */
+ struct s3c_irq_intc *intc;
+ unsigned long sub_bits;
+ struct s3c_irq_intc *sub_intc;
+};
+
+/*
+ * Sructure holding the controller data
+ * @reg_pending register holding pending irqs
+ * @reg_intpnd special register intpnd in main intc
+ * @reg_mask mask register
+ * @domain irq_domain of the controller
+ * @parent parent controller for ext and sub irqs
+ * @irqs irq-data, always s3c_irq_data[32]
+ */
+struct s3c_irq_intc {
+ void __iomem *reg_pending;
+ void __iomem *reg_intpnd;
+ void __iomem *reg_mask;
+ struct irq_domain *domain;
+ struct s3c_irq_intc *parent;
+ struct s3c_irq_data *irqs;
+};
+
+/*
+ * Array holding pointers to the global controller structs
+ * [0] ... main_intc
+ * [1] ... sub_intc
+ * [2] ... main_intc2 on s3c2416
+ */
+static struct s3c_irq_intc *s3c_intc[3];
+
+static void s3c_irq_mask(struct irq_data *data)
+{
+ struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data);
+ struct s3c_irq_intc *intc = irq_data->intc;
+ struct s3c_irq_intc *parent_intc = intc->parent;
+ struct s3c_irq_data *parent_data;
+ unsigned long mask;
+ unsigned int irqno;
+
+ mask = __raw_readl(intc->reg_mask);
+ mask |= (1UL << irq_data->offset);
+ __raw_writel(mask, intc->reg_mask);
+
+ if (parent_intc) {
+ parent_data = &parent_intc->irqs[irq_data->parent_irq];
+
+ /* check to see if we need to mask the parent IRQ
+ * The parent_irq is always in main_intc, so the hwirq
+ * for find_mapping does not need an offset in any case.
+ */
+ if ((mask & parent_data->sub_bits) == parent_data->sub_bits) {
+ irqno = irq_find_mapping(parent_intc->domain,
+ irq_data->parent_irq);
+ s3c_irq_mask(irq_get_irq_data(irqno));
+ }
+ }
+}
+
+static void s3c_irq_unmask(struct irq_data *data)
+{
+ struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data);
+ struct s3c_irq_intc *intc = irq_data->intc;
+ struct s3c_irq_intc *parent_intc = intc->parent;
+ unsigned long mask;
+ unsigned int irqno;
+
+ mask = __raw_readl(intc->reg_mask);
+ mask &= ~(1UL << irq_data->offset);
+ __raw_writel(mask, intc->reg_mask);
+
+ if (parent_intc) {
+ irqno = irq_find_mapping(parent_intc->domain,
+ irq_data->parent_irq);
+ s3c_irq_unmask(irq_get_irq_data(irqno));
+ }
+}
+
+static inline void s3c_irq_ack(struct irq_data *data)
+{
+ struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data);
+ struct s3c_irq_intc *intc = irq_data->intc;
+ unsigned long bitval = 1UL << irq_data->offset;
+
+ __raw_writel(bitval, intc->reg_pending);
+ if (intc->reg_intpnd)
+ __raw_writel(bitval, intc->reg_intpnd);
+}
+
+static int s3c_irq_type(struct irq_data *data, unsigned int type)
+{
+ switch (type) {
+ case IRQ_TYPE_NONE:
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ case IRQ_TYPE_EDGE_FALLING:
+ case IRQ_TYPE_EDGE_BOTH:
+ irq_set_handler(data->irq, handle_edge_irq);
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ case IRQ_TYPE_LEVEL_HIGH:
+ irq_set_handler(data->irq, handle_level_irq);
+ break;
+ default:
+ pr_err("No such irq type %d", type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int s3c_irqext_type_set(void __iomem *gpcon_reg,
+ void __iomem *extint_reg,
+ unsigned long gpcon_offset,
+ unsigned long extint_offset,
+ unsigned int type)
+{
+ unsigned long newvalue = 0, value;
+
+ /* Set the GPIO to external interrupt mode */
+ value = __raw_readl(gpcon_reg);
+ value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset);
+ __raw_writel(value, gpcon_reg);
+
+ /* Set the external interrupt to pointed trigger type */
+ switch (type)
+ {
+ case IRQ_TYPE_NONE:
+ pr_warn("No edge setting!\n");
+ break;
+
+ case IRQ_TYPE_EDGE_RISING:
+ newvalue = S3C2410_EXTINT_RISEEDGE;
+ break;
+
+ case IRQ_TYPE_EDGE_FALLING:
+ newvalue = S3C2410_EXTINT_FALLEDGE;
+ break;
+
+ case IRQ_TYPE_EDGE_BOTH:
+ newvalue = S3C2410_EXTINT_BOTHEDGE;
+ break;
+
+ case IRQ_TYPE_LEVEL_LOW:
+ newvalue = S3C2410_EXTINT_LOWLEV;
+ break;
+
+ case IRQ_TYPE_LEVEL_HIGH:
+ newvalue = S3C2410_EXTINT_HILEV;
+ break;
+
+ default:
+ pr_err("No such irq type %d", type);
+ return -EINVAL;
+ }
+
+ value = __raw_readl(extint_reg);
+ value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset);
+ __raw_writel(value, extint_reg);
+
+ return 0;
+}
+
+static int s3c_irqext_type(struct irq_data *data, unsigned int type)
+{
+ void __iomem *extint_reg;
+ void __iomem *gpcon_reg;
+ unsigned long gpcon_offset, extint_offset;
+
+ if ((data->hwirq >= 4) && (data->hwirq <= 7)) {
+ gpcon_reg = S3C2410_GPFCON;
+ extint_reg = S3C24XX_EXTINT0;
+ gpcon_offset = (data->hwirq) * 2;
+ extint_offset = (data->hwirq) * 4;
+ } else if ((data->hwirq >= 8) && (data->hwirq <= 15)) {
+ gpcon_reg = S3C2410_GPGCON;
+ extint_reg = S3C24XX_EXTINT1;
+ gpcon_offset = (data->hwirq - 8) * 2;
+ extint_offset = (data->hwirq - 8) * 4;
+ } else if ((data->hwirq >= 16) && (data->hwirq <= 23)) {
+ gpcon_reg = S3C2410_GPGCON;
+ extint_reg = S3C24XX_EXTINT2;
+ gpcon_offset = (data->hwirq - 8) * 2;
+ extint_offset = (data->hwirq - 16) * 4;
+ } else {
+ return -EINVAL;
+ }
+
+ return s3c_irqext_type_set(gpcon_reg, extint_reg, gpcon_offset,
+ extint_offset, type);
+}
+
+static int s3c_irqext0_type(struct irq_data *data, unsigned int type)
+{
+ void __iomem *extint_reg;
+ void __iomem *gpcon_reg;
+ unsigned long gpcon_offset, extint_offset;
+
+ if ((data->hwirq >= 0) && (data->hwirq <= 3)) {
+ gpcon_reg = S3C2410_GPFCON;
+ extint_reg = S3C24XX_EXTINT0;
+ gpcon_offset = (data->hwirq) * 2;
+ extint_offset = (data->hwirq) * 4;
+ } else {
+ return -EINVAL;
+ }
+
+ return s3c_irqext_type_set(gpcon_reg, extint_reg, gpcon_offset,
+ extint_offset, type);
+}
+
+static struct irq_chip s3c_irq_chip = {
+ .name = "s3c",
+ .irq_ack = s3c_irq_ack,
+ .irq_mask = s3c_irq_mask,
+ .irq_unmask = s3c_irq_unmask,
+ .irq_set_type = s3c_irq_type,
+ .irq_set_wake = s3c_irq_wake
+};
+
+static struct irq_chip s3c_irq_level_chip = {
+ .name = "s3c-level",
+ .irq_mask = s3c_irq_mask,
+ .irq_unmask = s3c_irq_unmask,
+ .irq_ack = s3c_irq_ack,
+ .irq_set_type = s3c_irq_type,
+};
+
+static struct irq_chip s3c_irqext_chip = {
+ .name = "s3c-ext",
+ .irq_mask = s3c_irq_mask,
+ .irq_unmask = s3c_irq_unmask,
+ .irq_ack = s3c_irq_ack,
+ .irq_set_type = s3c_irqext_type,
+ .irq_set_wake = s3c_irqext_wake
+};
+
+static struct irq_chip s3c_irq_eint0t4 = {
+ .name = "s3c-ext0",
+ .irq_ack = s3c_irq_ack,
+ .irq_mask = s3c_irq_mask,
+ .irq_unmask = s3c_irq_unmask,
+ .irq_set_wake = s3c_irq_wake,
+ .irq_set_type = s3c_irqext0_type,
+};
+
+static void s3c_irq_demux(unsigned int irq, struct irq_desc *desc)
+{
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct s3c_irq_data *irq_data = irq_desc_get_chip_data(desc);
+ struct s3c_irq_intc *intc = irq_data->intc;
+ struct s3c_irq_intc *sub_intc = irq_data->sub_intc;
+ unsigned long src;
+ unsigned long msk;
+ unsigned int n;
+ unsigned int offset;
+
+ /* we're using individual domains for the non-dt case
+ * and one big domain for the dt case where the subintc
+ * starts at hwirq number 32.
+ */
+ offset = (intc->domain->of_node) ? 32 : 0;
+
+ chained_irq_enter(chip, desc);
+
+ src = __raw_readl(sub_intc->reg_pending);
+ msk = __raw_readl(sub_intc->reg_mask);
+
+ src &= ~msk;
+ src &= irq_data->sub_bits;
+
+ while (src) {
+ n = __ffs(src);
+ src &= ~(1 << n);
+ irq = irq_find_mapping(sub_intc->domain, offset + n);
+ generic_handle_irq(irq);
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static inline int s3c24xx_handle_intc(struct s3c_irq_intc *intc,
+ struct pt_regs *regs, int intc_offset)
+{
+ int pnd;
+ int offset;
+ int irq;
+
+ pnd = __raw_readl(intc->reg_intpnd);
+ if (!pnd)
+ return false;
+
+ /* non-dt machines use individual domains */
+ if (!intc->domain->of_node)
+ intc_offset = 0;
+
+ /* We have a problem that the INTOFFSET register does not always
+ * show one interrupt. Occasionally we get two interrupts through
+ * the prioritiser, and this causes the INTOFFSET register to show
+ * what looks like the logical-or of the two interrupt numbers.
+ *
+ * Thanks to Klaus, Shannon, et al for helping to debug this problem
+ */
+ offset = __raw_readl(intc->reg_intpnd + 4);
+
+ /* Find the bit manually, when the offset is wrong.
+ * The pending register only ever contains the one bit of the next
+ * interrupt to handle.
+ */
+ if (!(pnd & (1 << offset)))
+ offset = __ffs(pnd);
+
+ irq = irq_find_mapping(intc->domain, intc_offset + offset);
+ handle_IRQ(irq, regs);
+ return true;
+}
+
+asmlinkage void __exception_irq_entry s3c24xx_handle_irq(struct pt_regs *regs)
+{
+ do {
+ if (likely(s3c_intc[0]))
+ if (s3c24xx_handle_intc(s3c_intc[0], regs, 0))
+ continue;
+
+ if (s3c_intc[2])
+ if (s3c24xx_handle_intc(s3c_intc[2], regs, 64))
+ continue;
+
+ break;
+ } while (1);
+}
+
+#ifdef CONFIG_FIQ
+/**
+ * s3c24xx_set_fiq - set the FIQ routing
+ * @irq: IRQ number to route to FIQ on processor.
+ * @on: Whether to route @irq to the FIQ, or to remove the FIQ routing.
+ *
+ * Change the state of the IRQ to FIQ routing depending on @irq and @on. If
+ * @on is true, the @irq is checked to see if it can be routed and the
+ * interrupt controller updated to route the IRQ. If @on is false, the FIQ
+ * routing is cleared, regardless of which @irq is specified.
+ */
+int s3c24xx_set_fiq(unsigned int irq, bool on)
+{
+ u32 intmod;
+ unsigned offs;
+
+ if (on) {
+ offs = irq - FIQ_START;
+ if (offs > 31)
+ return -EINVAL;
+
+ intmod = 1 << offs;
+ } else {
+ intmod = 0;
+ }
+
+ __raw_writel(intmod, S3C2410_INTMOD);
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(s3c24xx_set_fiq);
+#endif
+
+static int s3c24xx_irq_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct s3c_irq_intc *intc = h->host_data;
+ struct s3c_irq_data *irq_data = &intc->irqs[hw];
+ struct s3c_irq_intc *parent_intc;
+ struct s3c_irq_data *parent_irq_data;
+ unsigned int irqno;
+
+ /* attach controller pointer to irq_data */
+ irq_data->intc = intc;
+ irq_data->offset = hw;
+
+ parent_intc = intc->parent;
+
+ /* set handler and flags */
+ switch (irq_data->type) {
+ case S3C_IRQTYPE_NONE:
+ return 0;
+ case S3C_IRQTYPE_EINT:
+ /* On the S3C2412, the EINT0to3 have a parent irq
+ * but need the s3c_irq_eint0t4 chip
+ */
+ if (parent_intc && (!soc_is_s3c2412() || hw >= 4))
+ irq_set_chip_and_handler(virq, &s3c_irqext_chip,
+ handle_edge_irq);
+ else
+ irq_set_chip_and_handler(virq, &s3c_irq_eint0t4,
+ handle_edge_irq);
+ break;
+ case S3C_IRQTYPE_EDGE:
+ if (parent_intc || intc->reg_pending == S3C2416_SRCPND2)
+ irq_set_chip_and_handler(virq, &s3c_irq_level_chip,
+ handle_edge_irq);
+ else
+ irq_set_chip_and_handler(virq, &s3c_irq_chip,
+ handle_edge_irq);
+ break;
+ case S3C_IRQTYPE_LEVEL:
+ if (parent_intc)
+ irq_set_chip_and_handler(virq, &s3c_irq_level_chip,
+ handle_level_irq);
+ else
+ irq_set_chip_and_handler(virq, &s3c_irq_chip,
+ handle_level_irq);
+ break;
+ default:
+ pr_err("irq-s3c24xx: unsupported irqtype %d\n", irq_data->type);
+ return -EINVAL;
+ }
+
+ irq_set_chip_data(virq, irq_data);
+
+ set_irq_flags(virq, IRQF_VALID);
+
+ if (parent_intc && irq_data->type != S3C_IRQTYPE_NONE) {
+ if (irq_data->parent_irq > 31) {
+ pr_err("irq-s3c24xx: parent irq %lu is out of range\n",
+ irq_data->parent_irq);
+ goto err;
+ }
+
+ parent_irq_data = &parent_intc->irqs[irq_data->parent_irq];
+ parent_irq_data->sub_intc = intc;
+ parent_irq_data->sub_bits |= (1UL << hw);
+
+ /* attach the demuxer to the parent irq */
+ irqno = irq_find_mapping(parent_intc->domain,
+ irq_data->parent_irq);
+ if (!irqno) {
+ pr_err("irq-s3c24xx: could not find mapping for parent irq %lu\n",
+ irq_data->parent_irq);
+ goto err;
+ }
+ irq_set_chained_handler(irqno, s3c_irq_demux);
+ }
+
+ return 0;
+
+err:
+ set_irq_flags(virq, 0);
+
+ /* the only error can result from bad mapping data*/
+ return -EINVAL;
+}
+
+static struct irq_domain_ops s3c24xx_irq_ops = {
+ .map = s3c24xx_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+static void s3c24xx_clear_intc(struct s3c_irq_intc *intc)
+{
+ void __iomem *reg_source;
+ unsigned long pend;
+ unsigned long last;
+ int i;
+
+ /* if intpnd is set, read the next pending irq from there */
+ reg_source = intc->reg_intpnd ? intc->reg_intpnd : intc->reg_pending;
+
+ last = 0;
+ for (i = 0; i < 4; i++) {
+ pend = __raw_readl(reg_source);
+
+ if (pend == 0 || pend == last)
+ break;
+
+ __raw_writel(pend, intc->reg_pending);
+ if (intc->reg_intpnd)
+ __raw_writel(pend, intc->reg_intpnd);
+
+ pr_info("irq: clearing pending status %08x\n", (int)pend);
+ last = pend;
+ }
+}
+
+static struct s3c_irq_intc * __init s3c24xx_init_intc(struct device_node *np,
+ struct s3c_irq_data *irq_data,
+ struct s3c_irq_intc *parent,
+ unsigned long address)
+{
+ struct s3c_irq_intc *intc;
+ void __iomem *base = (void *)0xf6000000; /* static mapping */
+ int irq_num;
+ int irq_start;
+ int ret;
+
+ intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL);
+ if (!intc)
+ return ERR_PTR(-ENOMEM);
+
+ intc->irqs = irq_data;
+
+ if (parent)
+ intc->parent = parent;
+
+ /* select the correct data for the controller.
+ * Need to hard code the irq num start and offset
+ * to preserve the static mapping for now
+ */
+ switch (address) {
+ case 0x4a000000:
+ pr_debug("irq: found main intc\n");
+ intc->reg_pending = base;
+ intc->reg_mask = base + 0x08;
+ intc->reg_intpnd = base + 0x10;
+ irq_num = 32;
+ irq_start = S3C2410_IRQ(0);
+ break;
+ case 0x4a000018:
+ pr_debug("irq: found subintc\n");
+ intc->reg_pending = base + 0x18;
+ intc->reg_mask = base + 0x1c;
+ irq_num = 29;
+ irq_start = S3C2410_IRQSUB(0);
+ break;
+ case 0x4a000040:
+ pr_debug("irq: found intc2\n");
+ intc->reg_pending = base + 0x40;
+ intc->reg_mask = base + 0x48;
+ intc->reg_intpnd = base + 0x50;
+ irq_num = 8;
+ irq_start = S3C2416_IRQ(0);
+ break;
+ case 0x560000a4:
+ pr_debug("irq: found eintc\n");
+ base = (void *)0xfd000000;
+
+ intc->reg_mask = base + 0xa4;
+ intc->reg_pending = base + 0xa8;
+ irq_num = 24;
+ irq_start = S3C2410_IRQ(32);
+ break;
+ default:
+ pr_err("irq: unsupported controller address\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* now that all the data is complete, init the irq-domain */
+ s3c24xx_clear_intc(intc);
+ intc->domain = irq_domain_add_legacy(np, irq_num, irq_start,
+ 0, &s3c24xx_irq_ops,
+ intc);
+ if (!intc->domain) {
+ pr_err("irq: could not create irq-domain\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ set_handle_irq(s3c24xx_handle_irq);
+
+ return intc;
+
+err:
+ kfree(intc);
+ return ERR_PTR(ret);
+}
+
+static struct s3c_irq_data init_eint[32] = {
+ { .type = S3C_IRQTYPE_NONE, }, /* reserved */
+ { .type = S3C_IRQTYPE_NONE, }, /* reserved */
+ { .type = S3C_IRQTYPE_NONE, }, /* reserved */
+ { .type = S3C_IRQTYPE_NONE, }, /* reserved */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT4 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT5 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT6 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT7 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT8 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT9 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT10 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT11 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT12 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT13 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT14 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT15 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT16 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT17 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT18 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT19 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT20 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT21 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT22 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT23 */
+};
+
+#ifdef CONFIG_CPU_S3C2410
+static struct s3c_irq_data init_s3c2410base[32] = {
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
+ { .type = S3C_IRQTYPE_NONE, }, /* reserved */
+ { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
+ { .type = S3C_IRQTYPE_EDGE, }, /* WDT */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* LCD */
+ { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SDI */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
+ { .type = S3C_IRQTYPE_NONE, }, /* reserved */
+ { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
+ { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
+ { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
+};
+
+static struct s3c_irq_data init_s3c2410subint[32] = {
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
+ { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
+ { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
+};
+
+void __init s3c2410_init_irq(void)
+{
+#ifdef CONFIG_FIQ
+ init_FIQ(FIQ_START);
+#endif
+
+ s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2410base[0], NULL,
+ 0x4a000000);
+ if (IS_ERR(s3c_intc[0])) {
+ pr_err("irq: could not create main interrupt controller\n");
+ return;
+ }
+
+ s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2410subint[0],
+ s3c_intc[0], 0x4a000018);
+ s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4);
+}
+#endif
+
+#ifdef CONFIG_CPU_S3C2412
+static struct s3c_irq_data init_s3c2412base[32] = {
+ { .type = S3C_IRQTYPE_LEVEL, }, /* EINT0 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* EINT1 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* EINT2 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* EINT3 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
+ { .type = S3C_IRQTYPE_NONE, }, /* reserved */
+ { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
+ { .type = S3C_IRQTYPE_EDGE, }, /* WDT */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* LCD */
+ { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* SDI/CF */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
+ { .type = S3C_IRQTYPE_NONE, }, /* reserved */
+ { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
+ { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
+ { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
+};
+
+static struct s3c_irq_data init_s3c2412eint[32] = {
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 0 }, /* EINT0 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 1 }, /* EINT1 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 2 }, /* EINT2 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 3 }, /* EINT3 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT4 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT5 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT6 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT7 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT8 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT9 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT10 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT11 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT12 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT13 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT14 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT15 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT16 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT17 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT18 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT19 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT20 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT21 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT22 */
+ { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT23 */
+};
+
+static struct s3c_irq_data init_s3c2412subint[32] = {
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
+ { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
+ { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
+ { .type = S3C_IRQTYPE_NONE, },
+ { .type = S3C_IRQTYPE_NONE, },
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 21 }, /* SDI */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 21 }, /* CF */
+};
+
+void __init s3c2412_init_irq(void)
+{
+ pr_info("S3C2412: IRQ Support\n");
+
+#ifdef CONFIG_FIQ
+ init_FIQ(FIQ_START);
+#endif
+
+ s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2412base[0], NULL,
+ 0x4a000000);
+ if (IS_ERR(s3c_intc[0])) {
+ pr_err("irq: could not create main interrupt controller\n");
+ return;
+ }
+
+ s3c24xx_init_intc(NULL, &init_s3c2412eint[0], s3c_intc[0], 0x560000a4);
+ s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2412subint[0],
+ s3c_intc[0], 0x4a000018);
+}
+#endif
+
+#ifdef CONFIG_CPU_S3C2416
+static struct s3c_irq_data init_s3c2416base[32] = {
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
+ { .type = S3C_IRQTYPE_NONE, }, /* reserved */
+ { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* LCD */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* DMA */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART3 */
+ { .type = S3C_IRQTYPE_NONE, }, /* reserved */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SDI1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SDI0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* NAND */
+ { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
+ { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
+ { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
+ { .type = S3C_IRQTYPE_NONE, },
+ { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
+};
+
+static struct s3c_irq_data init_s3c2416subint[32] = {
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
+ { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
+ { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
+ { .type = S3C_IRQTYPE_NONE }, /* reserved */
+ { .type = S3C_IRQTYPE_NONE }, /* reserved */
+ { .type = S3C_IRQTYPE_NONE }, /* reserved */
+ { .type = S3C_IRQTYPE_NONE }, /* reserved */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD2 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD3 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD4 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA0 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA1 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA2 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA3 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA4 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA5 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-ERR */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */
+};
+
+static struct s3c_irq_data init_s3c2416_second[32] = {
+ { .type = S3C_IRQTYPE_EDGE }, /* 2D */
+ { .type = S3C_IRQTYPE_NONE }, /* reserved */
+ { .type = S3C_IRQTYPE_NONE }, /* reserved */
+ { .type = S3C_IRQTYPE_NONE }, /* reserved */
+ { .type = S3C_IRQTYPE_EDGE }, /* PCM0 */
+ { .type = S3C_IRQTYPE_NONE }, /* reserved */
+ { .type = S3C_IRQTYPE_EDGE }, /* I2S0 */
+};
+
+void __init s3c2416_init_irq(void)
+{
+ pr_info("S3C2416: IRQ Support\n");
+
+#ifdef CONFIG_FIQ
+ init_FIQ(FIQ_START);
+#endif
+
+ s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2416base[0], NULL,
+ 0x4a000000);
+ if (IS_ERR(s3c_intc[0])) {
+ pr_err("irq: could not create main interrupt controller\n");
+ return;
+ }
+
+ s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4);
+ s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2416subint[0],
+ s3c_intc[0], 0x4a000018);
+
+ s3c_intc[2] = s3c24xx_init_intc(NULL, &init_s3c2416_second[0],
+ NULL, 0x4a000040);
+}
+
+#endif
+
+#ifdef CONFIG_CPU_S3C2440
+static struct s3c_irq_data init_s3c2440base[32] = {
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* CAM */
+ { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* LCD */
+ { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SDI */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* NFCON */
+ { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
+ { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
+ { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
+};
+
+static struct s3c_irq_data init_s3c2440subint[32] = {
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
+ { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
+ { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */
+};
+
+void __init s3c2440_init_irq(void)
+{
+ pr_info("S3C2440: IRQ Support\n");
+
+#ifdef CONFIG_FIQ
+ init_FIQ(FIQ_START);
+#endif
+
+ s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2440base[0], NULL,
+ 0x4a000000);
+ if (IS_ERR(s3c_intc[0])) {
+ pr_err("irq: could not create main interrupt controller\n");
+ return;
+ }
+
+ s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4);
+ s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2440subint[0],
+ s3c_intc[0], 0x4a000018);
+}
+#endif
+
+#ifdef CONFIG_CPU_S3C2442
+static struct s3c_irq_data init_s3c2442base[32] = {
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* CAM */
+ { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
+ { .type = S3C_IRQTYPE_EDGE, }, /* WDT */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* LCD */
+ { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SDI */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* NFCON */
+ { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
+ { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
+ { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
+};
+
+static struct s3c_irq_data init_s3c2442subint[32] = {
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
+ { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
+ { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */
+};
+
+void __init s3c2442_init_irq(void)
+{
+ pr_info("S3C2442: IRQ Support\n");
+
+#ifdef CONFIG_FIQ
+ init_FIQ(FIQ_START);
+#endif
+
+ s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2442base[0], NULL,
+ 0x4a000000);
+ if (IS_ERR(s3c_intc[0])) {
+ pr_err("irq: could not create main interrupt controller\n");
+ return;
+ }
+
+ s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4);
+ s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2442subint[0],
+ s3c_intc[0], 0x4a000018);
+}
+#endif
+
+#ifdef CONFIG_CPU_S3C2443
+static struct s3c_irq_data init_s3c2443base[32] = {
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
+ { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* CAM */
+ { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* LCD */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* DMA */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART3 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* CFON */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SDI1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SDI0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* NAND */
+ { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
+ { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
+ { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */
+ { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
+ { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
+};
+
+
+static struct s3c_irq_data init_s3c2443subint[32] = {
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
+ { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
+ { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */
+ { .type = S3C_IRQTYPE_NONE }, /* reserved */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD1 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD2 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD3 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD4 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA0 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA1 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA2 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA3 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA4 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA5 */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-RX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-TX */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-ERR */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */
+ { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */
+};
+
+void __init s3c2443_init_irq(void)
+{
+ pr_info("S3C2443: IRQ Support\n");
+
+#ifdef CONFIG_FIQ
+ init_FIQ(FIQ_START);
+#endif
+
+ s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2443base[0], NULL,
+ 0x4a000000);
+ if (IS_ERR(s3c_intc[0])) {
+ pr_err("irq: could not create main interrupt controller\n");
+ return;
+ }
+
+ s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4);
+ s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2443subint[0],
+ s3c_intc[0], 0x4a000018);
+}
+#endif
+
+#ifdef CONFIG_OF
+static int s3c24xx_irq_map_of(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ unsigned int ctrl_num = hw / 32;
+ unsigned int intc_hw = hw % 32;
+ struct s3c_irq_intc *intc = s3c_intc[ctrl_num];
+ struct s3c_irq_intc *parent_intc = intc->parent;
+ struct s3c_irq_data *irq_data = &intc->irqs[intc_hw];
+
+ /* attach controller pointer to irq_data */
+ irq_data->intc = intc;
+ irq_data->offset = intc_hw;
+
+ if (!parent_intc)
+ irq_set_chip_and_handler(virq, &s3c_irq_chip, handle_edge_irq);
+ else
+ irq_set_chip_and_handler(virq, &s3c_irq_level_chip,
+ handle_edge_irq);
+
+ irq_set_chip_data(virq, irq_data);
+
+ set_irq_flags(virq, IRQF_VALID);
+
+ return 0;
+}
+
+/* Translate our of irq notation
+ * format: <ctrl_num ctrl_irq parent_irq type>
+ */
+static int s3c24xx_irq_xlate_of(struct irq_domain *d, struct device_node *n,
+ const u32 *intspec, unsigned int intsize,
+ irq_hw_number_t *out_hwirq, unsigned int *out_type)
+{
+ struct s3c_irq_intc *intc;
+ struct s3c_irq_intc *parent_intc;
+ struct s3c_irq_data *irq_data;
+ struct s3c_irq_data *parent_irq_data;
+ int irqno;
+
+ if (WARN_ON(intsize < 4))
+ return -EINVAL;
+
+ if (intspec[0] > 2 || !s3c_intc[intspec[0]]) {
+ pr_err("controller number %d invalid\n", intspec[0]);
+ return -EINVAL;
+ }
+ intc = s3c_intc[intspec[0]];
+
+ *out_hwirq = intspec[0] * 32 + intspec[2];
+ *out_type = intspec[3] & IRQ_TYPE_SENSE_MASK;
+
+ parent_intc = intc->parent;
+ if (parent_intc) {
+ irq_data = &intc->irqs[intspec[2]];
+ irq_data->parent_irq = intspec[1];
+ parent_irq_data = &parent_intc->irqs[irq_data->parent_irq];
+ parent_irq_data->sub_intc = intc;
+ parent_irq_data->sub_bits |= (1UL << intspec[2]);
+
+ /* parent_intc is always s3c_intc[0], so no offset */
+ irqno = irq_create_mapping(parent_intc->domain, intspec[1]);
+ if (irqno < 0) {
+ pr_err("irq: could not map parent interrupt\n");
+ return irqno;
+ }
+
+ irq_set_chained_handler(irqno, s3c_irq_demux);
+ }
+
+ return 0;
+}
+
+static struct irq_domain_ops s3c24xx_irq_ops_of = {
+ .map = s3c24xx_irq_map_of,
+ .xlate = s3c24xx_irq_xlate_of,
+};
+
+struct s3c24xx_irq_of_ctrl {
+ char *name;
+ unsigned long offset;
+ struct s3c_irq_intc **handle;
+ struct s3c_irq_intc **parent;
+ struct irq_domain_ops *ops;
+};
+
+static int __init s3c_init_intc_of(struct device_node *np,
+ struct device_node *interrupt_parent,
+ struct s3c24xx_irq_of_ctrl *s3c_ctrl, int num_ctrl)
+{
+ struct s3c_irq_intc *intc;
+ struct s3c24xx_irq_of_ctrl *ctrl;
+ struct irq_domain *domain;
+ void __iomem *reg_base;
+ int i;
+
+ reg_base = of_iomap(np, 0);
+ if (!reg_base) {
+ pr_err("irq-s3c24xx: could not map irq registers\n");
+ return -EINVAL;
+ }
+
+ domain = irq_domain_add_linear(np, num_ctrl * 32,
+ &s3c24xx_irq_ops_of, NULL);
+ if (!domain) {
+ pr_err("irq: could not create irq-domain\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num_ctrl; i++) {
+ ctrl = &s3c_ctrl[i];
+
+ pr_debug("irq: found controller %s\n", ctrl->name);
+
+ intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL);
+ if (!intc)
+ return -ENOMEM;
+
+ intc->domain = domain;
+ intc->irqs = kzalloc(sizeof(struct s3c_irq_data) * 32,
+ GFP_KERNEL);
+ if (!intc->irqs) {
+ kfree(intc);
+ return -ENOMEM;
+ }
+
+ if (ctrl->parent) {
+ intc->reg_pending = reg_base + ctrl->offset;
+ intc->reg_mask = reg_base + ctrl->offset + 0x4;
+
+ if (*(ctrl->parent)) {
+ intc->parent = *(ctrl->parent);
+ } else {
+ pr_warn("irq: parent of %s missing\n",
+ ctrl->name);
+ kfree(intc->irqs);
+ kfree(intc);
+ continue;
+ }
+ } else {
+ intc->reg_pending = reg_base + ctrl->offset;
+ intc->reg_mask = reg_base + ctrl->offset + 0x08;
+ intc->reg_intpnd = reg_base + ctrl->offset + 0x10;
+ }
+
+ s3c24xx_clear_intc(intc);
+ s3c_intc[i] = intc;
+ }
+
+ set_handle_irq(s3c24xx_handle_irq);
+
+ return 0;
+}
+
+static struct s3c24xx_irq_of_ctrl s3c2410_ctrl[] = {
+ {
+ .name = "intc",
+ .offset = 0,
+ }, {
+ .name = "subintc",
+ .offset = 0x18,
+ .parent = &s3c_intc[0],
+ }
+};
+
+int __init s3c2410_init_intc_of(struct device_node *np,
+ struct device_node *interrupt_parent,
+ struct s3c24xx_irq_of_ctrl *ctrl, int num_ctrl)
+{
+ return s3c_init_intc_of(np, interrupt_parent,
+ s3c2410_ctrl, ARRAY_SIZE(s3c2410_ctrl));
+}
+IRQCHIP_DECLARE(s3c2410_irq, "samsung,s3c2410-irq", s3c2410_init_intc_of);
+
+static struct s3c24xx_irq_of_ctrl s3c2416_ctrl[] = {
+ {
+ .name = "intc",
+ .offset = 0,
+ }, {
+ .name = "subintc",
+ .offset = 0x18,
+ .parent = &s3c_intc[0],
+ }, {
+ .name = "intc2",
+ .offset = 0x40,
+ }
+};
+
+int __init s3c2416_init_intc_of(struct device_node *np,
+ struct device_node *interrupt_parent,
+ struct s3c24xx_irq_of_ctrl *ctrl, int num_ctrl)
+{
+ return s3c_init_intc_of(np, interrupt_parent,
+ s3c2416_ctrl, ARRAY_SIZE(s3c2416_ctrl));
+}
+IRQCHIP_DECLARE(s3c2416_irq, "samsung,s3c2416-irq", s3c2416_init_intc_of);
+#endif
diff --git a/drivers/irqchip/irq-vt8500.c b/drivers/irqchip/irq-vt8500.c
new file mode 100644
index 000000000000..d97059550a2c
--- /dev/null
+++ b/drivers/irqchip/irq-vt8500.c
@@ -0,0 +1,259 @@
+/*
+ * arch/arm/mach-vt8500/irq.c
+ *
+ * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * This file is copied and modified from the original irq.c provided by
+ * Alexey Charkov. Minor changes have been made for Device Tree Support.
+ */
+
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+
+#include <asm/irq.h>
+#include <asm/exception.h>
+#include <asm/mach/irq.h>
+
+#include "irqchip.h"
+
+#define VT8500_ICPC_IRQ 0x20
+#define VT8500_ICPC_FIQ 0x24
+#define VT8500_ICDC 0x40 /* Destination Control 64*u32 */
+#define VT8500_ICIS 0x80 /* Interrupt status, 16*u32 */
+
+/* ICPC */
+#define ICPC_MASK 0x3F
+#define ICPC_ROTATE BIT(6)
+
+/* IC_DCTR */
+#define ICDC_IRQ 0x00
+#define ICDC_FIQ 0x01
+#define ICDC_DSS0 0x02
+#define ICDC_DSS1 0x03
+#define ICDC_DSS2 0x04
+#define ICDC_DSS3 0x05
+#define ICDC_DSS4 0x06
+#define ICDC_DSS5 0x07
+
+#define VT8500_INT_DISABLE 0
+#define VT8500_INT_ENABLE BIT(3)
+
+#define VT8500_TRIGGER_HIGH 0
+#define VT8500_TRIGGER_RISING BIT(5)
+#define VT8500_TRIGGER_FALLING BIT(6)
+#define VT8500_EDGE ( VT8500_TRIGGER_RISING \
+ | VT8500_TRIGGER_FALLING)
+
+/* vt8500 has 1 intc, wm8505 and wm8650 have 2 */
+#define VT8500_INTC_MAX 2
+
+struct vt8500_irq_data {
+ void __iomem *base; /* IO Memory base address */
+ struct irq_domain *domain; /* Domain for this controller */
+};
+
+/* Global variable for accessing io-mem addresses */
+static struct vt8500_irq_data intc[VT8500_INTC_MAX];
+static u32 active_cnt = 0;
+
+static void vt8500_irq_mask(struct irq_data *d)
+{
+ struct vt8500_irq_data *priv = d->domain->host_data;
+ void __iomem *base = priv->base;
+ void __iomem *stat_reg = base + VT8500_ICIS + (d->hwirq < 32 ? 0 : 4);
+ u8 edge, dctr;
+ u32 status;
+
+ edge = readb(base + VT8500_ICDC + d->hwirq) & VT8500_EDGE;
+ if (edge) {
+ status = readl(stat_reg);
+
+ status |= (1 << (d->hwirq & 0x1f));
+ writel(status, stat_reg);
+ } else {
+ dctr = readb(base + VT8500_ICDC + d->hwirq);
+ dctr &= ~VT8500_INT_ENABLE;
+ writeb(dctr, base + VT8500_ICDC + d->hwirq);
+ }
+}
+
+static void vt8500_irq_unmask(struct irq_data *d)
+{
+ struct vt8500_irq_data *priv = d->domain->host_data;
+ void __iomem *base = priv->base;
+ u8 dctr;
+
+ dctr = readb(base + VT8500_ICDC + d->hwirq);
+ dctr |= VT8500_INT_ENABLE;
+ writeb(dctr, base + VT8500_ICDC + d->hwirq);
+}
+
+static int vt8500_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+ struct vt8500_irq_data *priv = d->domain->host_data;
+ void __iomem *base = priv->base;
+ u8 dctr;
+
+ dctr = readb(base + VT8500_ICDC + d->hwirq);
+ dctr &= ~VT8500_EDGE;
+
+ switch (flow_type) {
+ case IRQF_TRIGGER_LOW:
+ return -EINVAL;
+ case IRQF_TRIGGER_HIGH:
+ dctr |= VT8500_TRIGGER_HIGH;
+ __irq_set_handler_locked(d->irq, handle_level_irq);
+ break;
+ case IRQF_TRIGGER_FALLING:
+ dctr |= VT8500_TRIGGER_FALLING;
+ __irq_set_handler_locked(d->irq, handle_edge_irq);
+ break;
+ case IRQF_TRIGGER_RISING:
+ dctr |= VT8500_TRIGGER_RISING;
+ __irq_set_handler_locked(d->irq, handle_edge_irq);
+ break;
+ }
+ writeb(dctr, base + VT8500_ICDC + d->hwirq);
+
+ return 0;
+}
+
+static struct irq_chip vt8500_irq_chip = {
+ .name = "vt8500",
+ .irq_ack = vt8500_irq_mask,
+ .irq_mask = vt8500_irq_mask,
+ .irq_unmask = vt8500_irq_unmask,
+ .irq_set_type = vt8500_irq_set_type,
+};
+
+static void __init vt8500_init_irq_hw(void __iomem *base)
+{
+ u32 i;
+
+ /* Enable rotating priority for IRQ */
+ writel(ICPC_ROTATE, base + VT8500_ICPC_IRQ);
+ writel(0x00, base + VT8500_ICPC_FIQ);
+
+ /* Disable all interrupts and route them to IRQ */
+ for (i = 0; i < 64; i++)
+ writeb(VT8500_INT_DISABLE | ICDC_IRQ, base + VT8500_ICDC + i);
+}
+
+static int vt8500_irq_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ irq_set_chip_and_handler(virq, &vt8500_irq_chip, handle_level_irq);
+ set_irq_flags(virq, IRQF_VALID);
+
+ return 0;
+}
+
+static struct irq_domain_ops vt8500_irq_domain_ops = {
+ .map = vt8500_irq_map,
+ .xlate = irq_domain_xlate_onecell,
+};
+
+asmlinkage void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
+{
+ u32 stat, i;
+ int irqnr, virq;
+ void __iomem *base;
+
+ /* Loop through each active controller */
+ for (i=0; i<active_cnt; i++) {
+ base = intc[i].base;
+ irqnr = readl_relaxed(base) & 0x3F;
+ /*
+ Highest Priority register default = 63, so check that this
+ is a real interrupt by checking the status register
+ */
+ if (irqnr == 63) {
+ stat = readl_relaxed(base + VT8500_ICIS + 4);
+ if (!(stat & BIT(31)))
+ continue;
+ }
+
+ virq = irq_find_mapping(intc[i].domain, irqnr);
+ handle_IRQ(virq, regs);
+ }
+}
+
+int __init vt8500_irq_init(struct device_node *node, struct device_node *parent)
+{
+ int irq, i;
+ struct device_node *np = node;
+
+ if (active_cnt == VT8500_INTC_MAX) {
+ pr_err("%s: Interrupt controllers > VT8500_INTC_MAX\n",
+ __func__);
+ goto out;
+ }
+
+ intc[active_cnt].base = of_iomap(np, 0);
+ intc[active_cnt].domain = irq_domain_add_linear(node, 64,
+ &vt8500_irq_domain_ops, &intc[active_cnt]);
+
+ if (!intc[active_cnt].base) {
+ pr_err("%s: Unable to map IO memory\n", __func__);
+ goto out;
+ }
+
+ if (!intc[active_cnt].domain) {
+ pr_err("%s: Unable to add irq domain!\n", __func__);
+ goto out;
+ }
+
+ set_handle_irq(vt8500_handle_irq);
+
+ vt8500_init_irq_hw(intc[active_cnt].base);
+
+ pr_info("vt8500-irq: Added interrupt controller\n");
+
+ active_cnt++;
+
+ /* check if this is a slaved controller */
+ if (of_irq_count(np) != 0) {
+ /* check that we have the correct number of interrupts */
+ if (of_irq_count(np) != 8) {
+ pr_err("%s: Incorrect IRQ map for slaved controller\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < 8; i++) {
+ irq = irq_of_parse_and_map(np, i);
+ enable_irq(irq);
+ }
+
+ pr_info("vt8500-irq: Enabled slave->parent interrupts\n");
+ }
+out:
+ return 0;
+}
+
+IRQCHIP_DECLARE(vt8500_irq, "via,vt8500-intc", vt8500_irq_init);
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 0a2bdd106b23..c76d16c972cc 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -747,6 +747,64 @@ struct device_node *of_find_node_by_phandle(phandle handle)
EXPORT_SYMBOL(of_find_node_by_phandle);
/**
+ * of_find_property_value_of_size
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @len: requested length of property value
+ *
+ * Search for a property in a device node and valid the requested size.
+ * Returns the property value on success, -EINVAL if the property does not
+ * exist, -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ *
+ */
+static void *of_find_property_value_of_size(const struct device_node *np,
+ const char *propname, u32 len)
+{
+ struct property *prop = of_find_property(np, propname, NULL);
+
+ if (!prop)
+ return ERR_PTR(-EINVAL);
+ if (!prop->value)
+ return ERR_PTR(-ENODATA);
+ if (len > prop->length)
+ return ERR_PTR(-EOVERFLOW);
+
+ return prop->value;
+}
+
+/**
+ * of_property_read_u32_index - Find and read a u32 from a multi-value property.
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @index: index of the u32 in the list of values
+ * @out_value: pointer to return value, modified only if no error.
+ *
+ * Search for a property in a device node and read nth 32-bit value from
+ * it. Returns 0 on success, -EINVAL if the property does not exist,
+ * -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ *
+ * The out_value is modified only if a valid u32 value can be decoded.
+ */
+int of_property_read_u32_index(const struct device_node *np,
+ const char *propname,
+ u32 index, u32 *out_value)
+{
+ const u32 *val = of_find_property_value_of_size(np, propname,
+ ((index + 1) * sizeof(*out_value)));
+
+ if (IS_ERR(val))
+ return PTR_ERR(val);
+
+ *out_value = be32_to_cpup(((__be32 *)val) + index);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_property_read_u32_index);
+
+/**
* of_property_read_u8_array - Find and read an array of u8 from a property.
*
* @np: device node from which the property value is to be read.
@@ -767,17 +825,12 @@ EXPORT_SYMBOL(of_find_node_by_phandle);
int of_property_read_u8_array(const struct device_node *np,
const char *propname, u8 *out_values, size_t sz)
{
- struct property *prop = of_find_property(np, propname, NULL);
- const u8 *val;
+ const u8 *val = of_find_property_value_of_size(np, propname,
+ (sz * sizeof(*out_values)));
- if (!prop)
- return -EINVAL;
- if (!prop->value)
- return -ENODATA;
- if ((sz * sizeof(*out_values)) > prop->length)
- return -EOVERFLOW;
+ if (IS_ERR(val))
+ return PTR_ERR(val);
- val = prop->value;
while (sz--)
*out_values++ = *val++;
return 0;
@@ -805,17 +858,12 @@ EXPORT_SYMBOL_GPL(of_property_read_u8_array);
int of_property_read_u16_array(const struct device_node *np,
const char *propname, u16 *out_values, size_t sz)
{
- struct property *prop = of_find_property(np, propname, NULL);
- const __be16 *val;
+ const __be16 *val = of_find_property_value_of_size(np, propname,
+ (sz * sizeof(*out_values)));
- if (!prop)
- return -EINVAL;
- if (!prop->value)
- return -ENODATA;
- if ((sz * sizeof(*out_values)) > prop->length)
- return -EOVERFLOW;
+ if (IS_ERR(val))
+ return PTR_ERR(val);
- val = prop->value;
while (sz--)
*out_values++ = be16_to_cpup(val++);
return 0;
@@ -842,17 +890,12 @@ int of_property_read_u32_array(const struct device_node *np,
const char *propname, u32 *out_values,
size_t sz)
{
- struct property *prop = of_find_property(np, propname, NULL);
- const __be32 *val;
+ const __be32 *val = of_find_property_value_of_size(np, propname,
+ (sz * sizeof(*out_values)));
- if (!prop)
- return -EINVAL;
- if (!prop->value)
- return -ENODATA;
- if ((sz * sizeof(*out_values)) > prop->length)
- return -EOVERFLOW;
+ if (IS_ERR(val))
+ return PTR_ERR(val);
- val = prop->value;
while (sz--)
*out_values++ = be32_to_cpup(val++);
return 0;
@@ -875,15 +918,13 @@ EXPORT_SYMBOL_GPL(of_property_read_u32_array);
int of_property_read_u64(const struct device_node *np, const char *propname,
u64 *out_value)
{
- struct property *prop = of_find_property(np, propname, NULL);
+ const __be32 *val = of_find_property_value_of_size(np, propname,
+ sizeof(*out_value));
- if (!prop)
- return -EINVAL;
- if (!prop->value)
- return -ENODATA;
- if (sizeof(*out_value) > prop->length)
- return -EOVERFLOW;
- *out_value = of_read_number(prop->value, 2);
+ if (IS_ERR(val))
+ return PTR_ERR(val);
+
+ *out_value = of_read_number(val, 2);
return 0;
}
EXPORT_SYMBOL_GPL(of_property_read_u64);
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 51336b2aedc9..8f6692438149 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -224,6 +224,7 @@ config PINCTRL_S3C64XX
source "drivers/pinctrl/mvebu/Kconfig"
source "drivers/pinctrl/sh-pfc/Kconfig"
source "drivers/pinctrl/spear/Kconfig"
+source "drivers/pinctrl/vt8500/Kconfig"
config PINCTRL_XWAY
bool
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index b9aaa61facd1..9bdaeb8785ce 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -50,3 +50,4 @@ obj-$(CONFIG_PLAT_ORION) += mvebu/
obj-$(CONFIG_ARCH_SHMOBILE) += sh-pfc/
obj-$(CONFIG_SUPERH) += sh-pfc/
obj-$(CONFIG_PLAT_SPEAR) += spear/
+obj-$(CONFIG_ARCH_VT8500) += vt8500/
diff --git a/drivers/pinctrl/pinctrl-bcm2835.c b/drivers/pinctrl/pinctrl-bcm2835.c
index f28d4b08771a..c8f20a3d8f88 100644
--- a/drivers/pinctrl/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/pinctrl-bcm2835.c
@@ -699,11 +699,6 @@ static int bcm2835_pctl_dt_node_to_map_pull(struct bcm2835_pinctrl *pc,
return 0;
}
-static inline u32 prop_u32(struct property *p, int i)
-{
- return be32_to_cpup(((__be32 *)p->value) + i);
-}
-
static int bcm2835_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
struct device_node *np,
struct pinctrl_map **map, unsigned *num_maps)
@@ -761,7 +756,9 @@ static int bcm2835_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
return -ENOMEM;
for (i = 0; i < num_pins; i++) {
- pin = prop_u32(pins, i);
+ err = of_property_read_u32_index(np, "brcm,pins", i, &pin);
+ if (err)
+ goto out;
if (pin >= ARRAY_SIZE(bcm2835_gpio_pins)) {
dev_err(pc->dev, "%s: invalid brcm,pins value %d\n",
of_node_full_name(np), pin);
@@ -770,14 +767,20 @@ static int bcm2835_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
}
if (num_funcs) {
- func = prop_u32(funcs, (num_funcs > 1) ? i : 0);
+ err = of_property_read_u32_index(np, "brcm,function",
+ (num_funcs > 1) ? i : 0, &func);
+ if (err)
+ goto out;
err = bcm2835_pctl_dt_node_to_map_func(pc, np, pin,
func, &cur_map);
if (err)
goto out;
}
if (num_pulls) {
- pull = prop_u32(pulls, (num_pulls > 1) ? i : 0);
+ err = of_property_read_u32_index(np, "brcm,pull",
+ (num_funcs > 1) ? i : 0, &pull);
+ if (err)
+ goto out;
err = bcm2835_pctl_dt_node_to_map_pull(pc, np, pin,
pull, &cur_map);
if (err)
diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c
index ec1567842a7e..ac742817ebce 100644
--- a/drivers/pinctrl/pinctrl-exynos.c
+++ b/drivers/pinctrl/pinctrl-exynos.c
@@ -700,3 +700,111 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = {
.label = "exynos4x12-gpio-ctrl3",
},
};
+
+/* pin banks of exynos5250 pin-controller 0 */
+static struct samsung_pin_bank exynos5250_pin_banks0[] = {
+ EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
+ EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
+ EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpa2", 0x08),
+ EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpb0", 0x0c),
+ EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpb1", 0x10),
+ EXYNOS_PIN_BANK_EINTG(4, 0x0A0, "gpb2", 0x14),
+ EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpb3", 0x18),
+ EXYNOS_PIN_BANK_EINTG(7, 0x0E0, "gpc0", 0x1c),
+ EXYNOS_PIN_BANK_EINTG(4, 0x100, "gpc1", 0x20),
+ EXYNOS_PIN_BANK_EINTG(7, 0x120, "gpc2", 0x24),
+ EXYNOS_PIN_BANK_EINTG(7, 0x140, "gpc3", 0x28),
+ EXYNOS_PIN_BANK_EINTG(4, 0x160, "gpd0", 0x2c),
+ EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpd1", 0x30),
+ EXYNOS_PIN_BANK_EINTG(7, 0x2E0, "gpc4", 0x34),
+ EXYNOS_PIN_BANK_EINTN(6, 0x1A0, "gpy0"),
+ EXYNOS_PIN_BANK_EINTN(4, 0x1C0, "gpy1"),
+ EXYNOS_PIN_BANK_EINTN(6, 0x1E0, "gpy2"),
+ EXYNOS_PIN_BANK_EINTN(8, 0x200, "gpy3"),
+ EXYNOS_PIN_BANK_EINTN(8, 0x220, "gpy4"),
+ EXYNOS_PIN_BANK_EINTN(8, 0x240, "gpy5"),
+ EXYNOS_PIN_BANK_EINTN(8, 0x260, "gpy6"),
+ EXYNOS_PIN_BANK_EINTW(8, 0xC00, "gpx0", 0x00),
+ EXYNOS_PIN_BANK_EINTW(8, 0xC20, "gpx1", 0x04),
+ EXYNOS_PIN_BANK_EINTW(8, 0xC40, "gpx2", 0x08),
+ EXYNOS_PIN_BANK_EINTW(8, 0xC60, "gpx3", 0x0c),
+};
+
+/* pin banks of exynos5250 pin-controller 1 */
+static struct samsung_pin_bank exynos5250_pin_banks1[] = {
+ EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpe0", 0x00),
+ EXYNOS_PIN_BANK_EINTG(2, 0x020, "gpe1", 0x04),
+ EXYNOS_PIN_BANK_EINTG(4, 0x040, "gpf0", 0x08),
+ EXYNOS_PIN_BANK_EINTG(4, 0x060, "gpf1", 0x0c),
+ EXYNOS_PIN_BANK_EINTG(8, 0x080, "gpg0", 0x10),
+ EXYNOS_PIN_BANK_EINTG(8, 0x0A0, "gpg1", 0x14),
+ EXYNOS_PIN_BANK_EINTG(2, 0x0C0, "gpg2", 0x18),
+ EXYNOS_PIN_BANK_EINTG(4, 0x0E0, "gph0", 0x1c),
+ EXYNOS_PIN_BANK_EINTG(8, 0x100, "gph1", 0x20),
+};
+
+/* pin banks of exynos5250 pin-controller 2 */
+static struct samsung_pin_bank exynos5250_pin_banks2[] = {
+ EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpv0", 0x00),
+ EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpv1", 0x04),
+ EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpv2", 0x08),
+ EXYNOS_PIN_BANK_EINTG(8, 0x080, "gpv3", 0x0c),
+ EXYNOS_PIN_BANK_EINTG(2, 0x0C0, "gpv4", 0x10),
+};
+
+/* pin banks of exynos5250 pin-controller 3 */
+static struct samsung_pin_bank exynos5250_pin_banks3[] = {
+ EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00),
+};
+
+/*
+ * Samsung pinctrl driver data for Exynos5250 SoC. Exynos5250 SoC includes
+ * four gpio/pin-mux/pinconfig controllers.
+ */
+struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
+ {
+ /* pin-controller instance 0 data */
+ .pin_banks = exynos5250_pin_banks0,
+ .nr_banks = ARRAY_SIZE(exynos5250_pin_banks0),
+ .geint_con = EXYNOS_GPIO_ECON_OFFSET,
+ .geint_mask = EXYNOS_GPIO_EMASK_OFFSET,
+ .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
+ .weint_con = EXYNOS_WKUP_ECON_OFFSET,
+ .weint_mask = EXYNOS_WKUP_EMASK_OFFSET,
+ .weint_pend = EXYNOS_WKUP_EPEND_OFFSET,
+ .svc = EXYNOS_SVC_OFFSET,
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .eint_wkup_init = exynos_eint_wkup_init,
+ .label = "exynos5250-gpio-ctrl0",
+ }, {
+ /* pin-controller instance 1 data */
+ .pin_banks = exynos5250_pin_banks1,
+ .nr_banks = ARRAY_SIZE(exynos5250_pin_banks1),
+ .geint_con = EXYNOS_GPIO_ECON_OFFSET,
+ .geint_mask = EXYNOS_GPIO_EMASK_OFFSET,
+ .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
+ .svc = EXYNOS_SVC_OFFSET,
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .label = "exynos5250-gpio-ctrl1",
+ }, {
+ /* pin-controller instance 2 data */
+ .pin_banks = exynos5250_pin_banks2,
+ .nr_banks = ARRAY_SIZE(exynos5250_pin_banks2),
+ .geint_con = EXYNOS_GPIO_ECON_OFFSET,
+ .geint_mask = EXYNOS_GPIO_EMASK_OFFSET,
+ .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
+ .svc = EXYNOS_SVC_OFFSET,
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .label = "exynos5250-gpio-ctrl2",
+ }, {
+ /* pin-controller instance 3 data */
+ .pin_banks = exynos5250_pin_banks3,
+ .nr_banks = ARRAY_SIZE(exynos5250_pin_banks3),
+ .geint_con = EXYNOS_GPIO_ECON_OFFSET,
+ .geint_mask = EXYNOS_GPIO_EMASK_OFFSET,
+ .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
+ .svc = EXYNOS_SVC_OFFSET,
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .label = "exynos5250-gpio-ctrl3",
+ },
+};
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c
index 4f54faf2971f..976366899f68 100644
--- a/drivers/pinctrl/pinctrl-samsung.c
+++ b/drivers/pinctrl/pinctrl-samsung.c
@@ -970,6 +970,8 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = {
.data = (void *)exynos4210_pin_ctrl },
{ .compatible = "samsung,exynos4x12-pinctrl",
.data = (void *)exynos4x12_pin_ctrl },
+ { .compatible = "samsung,exynos5250-pinctrl",
+ .data = (void *)exynos5250_pin_ctrl },
#endif
#ifdef CONFIG_PINCTRL_S3C64XX
{ .compatible = "samsung,s3c64xx-pinctrl",
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h
index 45f27b41e30c..7c7f9ebcd05b 100644
--- a/drivers/pinctrl/pinctrl-samsung.h
+++ b/drivers/pinctrl/pinctrl-samsung.h
@@ -244,6 +244,7 @@ struct samsung_pmx_func {
/* list of all exported SoC specific data */
extern struct samsung_pin_ctrl exynos4210_pin_ctrl[];
extern struct samsung_pin_ctrl exynos4x12_pin_ctrl[];
+extern struct samsung_pin_ctrl exynos5250_pin_ctrl[];
extern struct samsung_pin_ctrl s3c64xx_pin_ctrl[];
#endif /* __PINCTRL_SAMSUNG_H */
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
index 709008e94124..6f15c03077a0 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
@@ -2733,9 +2733,9 @@ static struct pinmux_data_reg pinmux_data_regs[] = {
{ },
};
-/* IRQ pins through INTCS with IRQ0->15 from 0x200 and IRQ16-31 from 0x3200 */
-#define EXT_IRQ16L(n) intcs_evt2irq(0x200 + ((n) << 5))
-#define EXT_IRQ16H(n) intcs_evt2irq(0x3200 + ((n - 16) << 5))
+/* External IRQ pins mapped at IRQPIN_BASE */
+#define EXT_IRQ16L(n) irq_pin(n)
+#define EXT_IRQ16H(n) irq_pin(n)
static struct pinmux_irq pinmux_irqs[] = {
PINMUX_IRQ(EXT_IRQ16H(19), PORT9_FN0),
diff --git a/drivers/pinctrl/vt8500/Kconfig b/drivers/pinctrl/vt8500/Kconfig
new file mode 100644
index 000000000000..55724a73d94a
--- /dev/null
+++ b/drivers/pinctrl/vt8500/Kconfig
@@ -0,0 +1,52 @@
+#
+# VIA/Wondermedia PINCTRL drivers
+#
+
+if ARCH_VT8500
+
+config PINCTRL_WMT
+ bool
+ select PINMUX
+ select GENERIC_PINCONF
+
+config PINCTRL_VT8500
+ bool "VIA VT8500 pin controller driver"
+ depends on ARCH_WM8505
+ select PINCTRL_WMT
+ help
+ Say yes here to support the gpio/pin control module on
+ VIA VT8500 SoCs.
+
+config PINCTRL_WM8505
+ bool "Wondermedia WM8505 pin controller driver"
+ depends on ARCH_WM8505
+ select PINCTRL_WMT
+ help
+ Say yes here to support the gpio/pin control module on
+ Wondermedia WM8505 SoCs.
+
+config PINCTRL_WM8650
+ bool "Wondermedia WM8650 pin controller driver"
+ depends on ARCH_WM8505
+ select PINCTRL_WMT
+ help
+ Say yes here to support the gpio/pin control module on
+ Wondermedia WM8650 SoCs.
+
+config PINCTRL_WM8750
+ bool "Wondermedia WM8750 pin controller driver"
+ depends on ARCH_WM8750
+ select PINCTRL_WMT
+ help
+ Say yes here to support the gpio/pin control module on
+ Wondermedia WM8750 SoCs.
+
+config PINCTRL_WM8850
+ bool "Wondermedia WM8850 pin controller driver"
+ depends on ARCH_WM8850
+ select PINCTRL_WMT
+ help
+ Say yes here to support the gpio/pin control module on
+ Wondermedia WM8850 SoCs.
+
+endif
diff --git a/drivers/pinctrl/vt8500/Makefile b/drivers/pinctrl/vt8500/Makefile
new file mode 100644
index 000000000000..24ec45dd0d80
--- /dev/null
+++ b/drivers/pinctrl/vt8500/Makefile
@@ -0,0 +1,8 @@
+# VIA/Wondermedia pinctrl support
+
+obj-$(CONFIG_PINCTRL_WMT) += pinctrl-wmt.o
+obj-$(CONFIG_PINCTRL_VT8500) += pinctrl-vt8500.o
+obj-$(CONFIG_PINCTRL_WM8505) += pinctrl-wm8505.o
+obj-$(CONFIG_PINCTRL_WM8650) += pinctrl-wm8650.o
+obj-$(CONFIG_PINCTRL_WM8750) += pinctrl-wm8750.o
+obj-$(CONFIG_PINCTRL_WM8850) += pinctrl-wm8850.o
diff --git a/drivers/pinctrl/vt8500/pinctrl-vt8500.c b/drivers/pinctrl/vt8500/pinctrl-vt8500.c
new file mode 100644
index 000000000000..f2fe9f85cfa6
--- /dev/null
+++ b/drivers/pinctrl/vt8500/pinctrl-vt8500.c
@@ -0,0 +1,501 @@
+/*
+ * Pinctrl data for VIA VT8500 SoC
+ *
+ * Copyright (c) 2013 Tony Prisk <linux@prisktech.co.nz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "pinctrl-wmt.h"
+
+/*
+ * Describe the register offsets within the GPIO memory space
+ * The dedicated external GPIO's should always be listed in bank 0
+ * so they are exported in the 0..31 range which is what users
+ * expect.
+ *
+ * Do not reorder these banks as it will change the pin numbering
+ */
+static const struct wmt_pinctrl_bank_registers vt8500_banks[] = {
+ WMT_PINCTRL_BANK(NO_REG, 0x3C, 0x5C, 0x7C, NO_REG, NO_REG), /* 0 */
+ WMT_PINCTRL_BANK(0x00, 0x20, 0x40, 0x60, NO_REG, NO_REG), /* 1 */
+ WMT_PINCTRL_BANK(0x04, 0x24, 0x44, 0x64, NO_REG, NO_REG), /* 2 */
+ WMT_PINCTRL_BANK(0x08, 0x28, 0x48, 0x68, NO_REG, NO_REG), /* 3 */
+ WMT_PINCTRL_BANK(0x0C, 0x2C, 0x4C, 0x6C, NO_REG, NO_REG), /* 4 */
+ WMT_PINCTRL_BANK(0x10, 0x30, 0x50, 0x70, NO_REG, NO_REG), /* 5 */
+ WMT_PINCTRL_BANK(0x14, 0x34, 0x54, 0x74, NO_REG, NO_REG), /* 6 */
+};
+
+/* Please keep sorted by bank/bit */
+#define WMT_PIN_EXTGPIO0 WMT_PIN(0, 0)
+#define WMT_PIN_EXTGPIO1 WMT_PIN(0, 1)
+#define WMT_PIN_EXTGPIO2 WMT_PIN(0, 2)
+#define WMT_PIN_EXTGPIO3 WMT_PIN(0, 3)
+#define WMT_PIN_EXTGPIO4 WMT_PIN(0, 4)
+#define WMT_PIN_EXTGPIO5 WMT_PIN(0, 5)
+#define WMT_PIN_EXTGPIO6 WMT_PIN(0, 6)
+#define WMT_PIN_EXTGPIO7 WMT_PIN(0, 7)
+#define WMT_PIN_EXTGPIO8 WMT_PIN(0, 8)
+#define WMT_PIN_UART0RTS WMT_PIN(1, 0)
+#define WMT_PIN_UART0TXD WMT_PIN(1, 1)
+#define WMT_PIN_UART0CTS WMT_PIN(1, 2)
+#define WMT_PIN_UART0RXD WMT_PIN(1, 3)
+#define WMT_PIN_UART1RTS WMT_PIN(1, 4)
+#define WMT_PIN_UART1TXD WMT_PIN(1, 5)
+#define WMT_PIN_UART1CTS WMT_PIN(1, 6)
+#define WMT_PIN_UART1RXD WMT_PIN(1, 7)
+#define WMT_PIN_SPI0CLK WMT_PIN(1, 8)
+#define WMT_PIN_SPI0SS WMT_PIN(1, 9)
+#define WMT_PIN_SPI0MISO WMT_PIN(1, 10)
+#define WMT_PIN_SPI0MOSI WMT_PIN(1, 11)
+#define WMT_PIN_SPI1CLK WMT_PIN(1, 12)
+#define WMT_PIN_SPI1SS WMT_PIN(1, 13)
+#define WMT_PIN_SPI1MISO WMT_PIN(1, 14)
+#define WMT_PIN_SPI1MOSI WMT_PIN(1, 15)
+#define WMT_PIN_SPI2CLK WMT_PIN(1, 16)
+#define WMT_PIN_SPI2SS WMT_PIN(1, 17)
+#define WMT_PIN_SPI2MISO WMT_PIN(1, 18)
+#define WMT_PIN_SPI2MOSI WMT_PIN(1, 19)
+#define WMT_PIN_SDDATA0 WMT_PIN(2, 0)
+#define WMT_PIN_SDDATA1 WMT_PIN(2, 1)
+#define WMT_PIN_SDDATA2 WMT_PIN(2, 2)
+#define WMT_PIN_SDDATA3 WMT_PIN(2, 3)
+#define WMT_PIN_MMCDATA0 WMT_PIN(2, 4)
+#define WMT_PIN_MMCDATA1 WMT_PIN(2, 5)
+#define WMT_PIN_MMCDATA2 WMT_PIN(2, 6)
+#define WMT_PIN_MMCDATA3 WMT_PIN(2, 7)
+#define WMT_PIN_SDCLK WMT_PIN(2, 8)
+#define WMT_PIN_SDWP WMT_PIN(2, 9)
+#define WMT_PIN_SDCMD WMT_PIN(2, 10)
+#define WMT_PIN_MSDATA0 WMT_PIN(2, 16)
+#define WMT_PIN_MSDATA1 WMT_PIN(2, 17)
+#define WMT_PIN_MSDATA2 WMT_PIN(2, 18)
+#define WMT_PIN_MSDATA3 WMT_PIN(2, 19)
+#define WMT_PIN_MSCLK WMT_PIN(2, 20)
+#define WMT_PIN_MSBS WMT_PIN(2, 21)
+#define WMT_PIN_MSINS WMT_PIN(2, 22)
+#define WMT_PIN_I2C0SCL WMT_PIN(2, 24)
+#define WMT_PIN_I2C0SDA WMT_PIN(2, 25)
+#define WMT_PIN_I2C1SCL WMT_PIN(2, 26)
+#define WMT_PIN_I2C1SDA WMT_PIN(2, 27)
+#define WMT_PIN_MII0RXD0 WMT_PIN(3, 0)
+#define WMT_PIN_MII0RXD1 WMT_PIN(3, 1)
+#define WMT_PIN_MII0RXD2 WMT_PIN(3, 2)
+#define WMT_PIN_MII0RXD3 WMT_PIN(3, 3)
+#define WMT_PIN_MII0RXCLK WMT_PIN(3, 4)
+#define WMT_PIN_MII0RXDV WMT_PIN(3, 5)
+#define WMT_PIN_MII0RXERR WMT_PIN(3, 6)
+#define WMT_PIN_MII0PHYRST WMT_PIN(3, 7)
+#define WMT_PIN_MII0TXD0 WMT_PIN(3, 8)
+#define WMT_PIN_MII0TXD1 WMT_PIN(3, 9)
+#define WMT_PIN_MII0TXD2 WMT_PIN(3, 10)
+#define WMT_PIN_MII0TXD3 WMT_PIN(3, 11)
+#define WMT_PIN_MII0TXCLK WMT_PIN(3, 12)
+#define WMT_PIN_MII0TXEN WMT_PIN(3, 13)
+#define WMT_PIN_MII0TXERR WMT_PIN(3, 14)
+#define WMT_PIN_MII0PHYPD WMT_PIN(3, 15)
+#define WMT_PIN_MII0COL WMT_PIN(3, 16)
+#define WMT_PIN_MII0CRS WMT_PIN(3, 17)
+#define WMT_PIN_MII0MDIO WMT_PIN(3, 18)
+#define WMT_PIN_MII0MDC WMT_PIN(3, 19)
+#define WMT_PIN_SEECS WMT_PIN(3, 20)
+#define WMT_PIN_SEECK WMT_PIN(3, 21)
+#define WMT_PIN_SEEDI WMT_PIN(3, 22)
+#define WMT_PIN_SEEDO WMT_PIN(3, 23)
+#define WMT_PIN_IDEDREQ0 WMT_PIN(3, 24)
+#define WMT_PIN_IDEDREQ1 WMT_PIN(3, 25)
+#define WMT_PIN_IDEIOW WMT_PIN(3, 26)
+#define WMT_PIN_IDEIOR WMT_PIN(3, 27)
+#define WMT_PIN_IDEDACK WMT_PIN(3, 28)
+#define WMT_PIN_IDEIORDY WMT_PIN(3, 29)
+#define WMT_PIN_IDEINTRQ WMT_PIN(3, 30)
+#define WMT_PIN_VDIN0 WMT_PIN(4, 0)
+#define WMT_PIN_VDIN1 WMT_PIN(4, 1)
+#define WMT_PIN_VDIN2 WMT_PIN(4, 2)
+#define WMT_PIN_VDIN3 WMT_PIN(4, 3)
+#define WMT_PIN_VDIN4 WMT_PIN(4, 4)
+#define WMT_PIN_VDIN5 WMT_PIN(4, 5)
+#define WMT_PIN_VDIN6 WMT_PIN(4, 6)
+#define WMT_PIN_VDIN7 WMT_PIN(4, 7)
+#define WMT_PIN_VDOUT0 WMT_PIN(4, 8)
+#define WMT_PIN_VDOUT1 WMT_PIN(4, 9)
+#define WMT_PIN_VDOUT2 WMT_PIN(4, 10)
+#define WMT_PIN_VDOUT3 WMT_PIN(4, 11)
+#define WMT_PIN_VDOUT4 WMT_PIN(4, 12)
+#define WMT_PIN_VDOUT5 WMT_PIN(4, 13)
+#define WMT_PIN_NANDCLE0 WMT_PIN(4, 14)
+#define WMT_PIN_NANDCLE1 WMT_PIN(4, 15)
+#define WMT_PIN_VDOUT6_7 WMT_PIN(4, 16)
+#define WMT_PIN_VHSYNC WMT_PIN(4, 17)
+#define WMT_PIN_VVSYNC WMT_PIN(4, 18)
+#define WMT_PIN_TSDIN0 WMT_PIN(5, 8)
+#define WMT_PIN_TSDIN1 WMT_PIN(5, 9)
+#define WMT_PIN_TSDIN2 WMT_PIN(5, 10)
+#define WMT_PIN_TSDIN3 WMT_PIN(5, 11)
+#define WMT_PIN_TSDIN4 WMT_PIN(5, 12)
+#define WMT_PIN_TSDIN5 WMT_PIN(5, 13)
+#define WMT_PIN_TSDIN6 WMT_PIN(5, 14)
+#define WMT_PIN_TSDIN7 WMT_PIN(5, 15)
+#define WMT_PIN_TSSYNC WMT_PIN(5, 16)
+#define WMT_PIN_TSVALID WMT_PIN(5, 17)
+#define WMT_PIN_TSCLK WMT_PIN(5, 18)
+#define WMT_PIN_LCDD0 WMT_PIN(6, 0)
+#define WMT_PIN_LCDD1 WMT_PIN(6, 1)
+#define WMT_PIN_LCDD2 WMT_PIN(6, 2)
+#define WMT_PIN_LCDD3 WMT_PIN(6, 3)
+#define WMT_PIN_LCDD4 WMT_PIN(6, 4)
+#define WMT_PIN_LCDD5 WMT_PIN(6, 5)
+#define WMT_PIN_LCDD6 WMT_PIN(6, 6)
+#define WMT_PIN_LCDD7 WMT_PIN(6, 7)
+#define WMT_PIN_LCDD8 WMT_PIN(6, 8)
+#define WMT_PIN_LCDD9 WMT_PIN(6, 9)
+#define WMT_PIN_LCDD10 WMT_PIN(6, 10)
+#define WMT_PIN_LCDD11 WMT_PIN(6, 11)
+#define WMT_PIN_LCDD12 WMT_PIN(6, 12)
+#define WMT_PIN_LCDD13 WMT_PIN(6, 13)
+#define WMT_PIN_LCDD14 WMT_PIN(6, 14)
+#define WMT_PIN_LCDD15 WMT_PIN(6, 15)
+#define WMT_PIN_LCDD16 WMT_PIN(6, 16)
+#define WMT_PIN_LCDD17 WMT_PIN(6, 17)
+#define WMT_PIN_LCDCLK WMT_PIN(6, 18)
+#define WMT_PIN_LCDDEN WMT_PIN(6, 19)
+#define WMT_PIN_LCDLINE WMT_PIN(6, 20)
+#define WMT_PIN_LCDFRM WMT_PIN(6, 21)
+#define WMT_PIN_LCDBIAS WMT_PIN(6, 22)
+
+static const struct pinctrl_pin_desc vt8500_pins[] = {
+ PINCTRL_PIN(WMT_PIN_EXTGPIO0, "extgpio0"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO1, "extgpio1"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO2, "extgpio2"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO3, "extgpio3"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO4, "extgpio4"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO5, "extgpio5"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO6, "extgpio6"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO7, "extgpio7"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO8, "extgpio8"),
+ PINCTRL_PIN(WMT_PIN_UART0RTS, "uart0_rts"),
+ PINCTRL_PIN(WMT_PIN_UART0TXD, "uart0_txd"),
+ PINCTRL_PIN(WMT_PIN_UART0CTS, "uart0_cts"),
+ PINCTRL_PIN(WMT_PIN_UART0RXD, "uart0_rxd"),
+ PINCTRL_PIN(WMT_PIN_UART1RTS, "uart1_rts"),
+ PINCTRL_PIN(WMT_PIN_UART1TXD, "uart1_txd"),
+ PINCTRL_PIN(WMT_PIN_UART1CTS, "uart1_cts"),
+ PINCTRL_PIN(WMT_PIN_UART1RXD, "uart1_rxd"),
+ PINCTRL_PIN(WMT_PIN_SPI0CLK, "spi0_clk"),
+ PINCTRL_PIN(WMT_PIN_SPI0SS, "spi0_ss"),
+ PINCTRL_PIN(WMT_PIN_SPI0MISO, "spi0_miso"),
+ PINCTRL_PIN(WMT_PIN_SPI0MOSI, "spi0_mosi"),
+ PINCTRL_PIN(WMT_PIN_SPI1CLK, "spi1_clk"),
+ PINCTRL_PIN(WMT_PIN_SPI1SS, "spi1_ss"),
+ PINCTRL_PIN(WMT_PIN_SPI1MISO, "spi1_miso"),
+ PINCTRL_PIN(WMT_PIN_SPI1MOSI, "spi1_mosi"),
+ PINCTRL_PIN(WMT_PIN_SPI2CLK, "spi2_clk"),
+ PINCTRL_PIN(WMT_PIN_SPI2SS, "spi2_ss"),
+ PINCTRL_PIN(WMT_PIN_SPI2MISO, "spi2_miso"),
+ PINCTRL_PIN(WMT_PIN_SPI2MOSI, "spi2_mosi"),
+ PINCTRL_PIN(WMT_PIN_SDDATA0, "sd_data0"),
+ PINCTRL_PIN(WMT_PIN_SDDATA1, "sd_data1"),
+ PINCTRL_PIN(WMT_PIN_SDDATA2, "sd_data2"),
+ PINCTRL_PIN(WMT_PIN_SDDATA3, "sd_data3"),
+ PINCTRL_PIN(WMT_PIN_MMCDATA0, "mmc_data0"),
+ PINCTRL_PIN(WMT_PIN_MMCDATA1, "mmc_data1"),
+ PINCTRL_PIN(WMT_PIN_MMCDATA2, "mmc_data2"),
+ PINCTRL_PIN(WMT_PIN_MMCDATA3, "mmc_data3"),
+ PINCTRL_PIN(WMT_PIN_SDCLK, "sd_clk"),
+ PINCTRL_PIN(WMT_PIN_SDWP, "sd_wp"),
+ PINCTRL_PIN(WMT_PIN_SDCMD, "sd_cmd"),
+ PINCTRL_PIN(WMT_PIN_MSDATA0, "ms_data0"),
+ PINCTRL_PIN(WMT_PIN_MSDATA1, "ms_data1"),
+ PINCTRL_PIN(WMT_PIN_MSDATA2, "ms_data2"),
+ PINCTRL_PIN(WMT_PIN_MSDATA3, "ms_data3"),
+ PINCTRL_PIN(WMT_PIN_MSCLK, "ms_clk"),
+ PINCTRL_PIN(WMT_PIN_MSBS, "ms_bs"),
+ PINCTRL_PIN(WMT_PIN_MSINS, "ms_ins"),
+ PINCTRL_PIN(WMT_PIN_I2C0SCL, "i2c0_scl"),
+ PINCTRL_PIN(WMT_PIN_I2C0SDA, "i2c0_sda"),
+ PINCTRL_PIN(WMT_PIN_I2C1SCL, "i2c1_scl"),
+ PINCTRL_PIN(WMT_PIN_I2C1SDA, "i2c1_sda"),
+ PINCTRL_PIN(WMT_PIN_MII0RXD0, "mii0_rxd0"),
+ PINCTRL_PIN(WMT_PIN_MII0RXD1, "mii0_rxd1"),
+ PINCTRL_PIN(WMT_PIN_MII0RXD2, "mii0_rxd2"),
+ PINCTRL_PIN(WMT_PIN_MII0RXD3, "mii0_rxd3"),
+ PINCTRL_PIN(WMT_PIN_MII0RXCLK, "mii0_rxclk"),
+ PINCTRL_PIN(WMT_PIN_MII0RXDV, "mii0_rxdv"),
+ PINCTRL_PIN(WMT_PIN_MII0RXERR, "mii0_rxerr"),
+ PINCTRL_PIN(WMT_PIN_MII0PHYRST, "mii0_phyrst"),
+ PINCTRL_PIN(WMT_PIN_MII0TXD0, "mii0_txd0"),
+ PINCTRL_PIN(WMT_PIN_MII0TXD1, "mii0_txd1"),
+ PINCTRL_PIN(WMT_PIN_MII0TXD2, "mii0_txd2"),
+ PINCTRL_PIN(WMT_PIN_MII0TXD3, "mii0_txd3"),
+ PINCTRL_PIN(WMT_PIN_MII0TXCLK, "mii0_txclk"),
+ PINCTRL_PIN(WMT_PIN_MII0TXEN, "mii0_txen"),
+ PINCTRL_PIN(WMT_PIN_MII0TXERR, "mii0_txerr"),
+ PINCTRL_PIN(WMT_PIN_MII0PHYPD, "mii0_phypd"),
+ PINCTRL_PIN(WMT_PIN_MII0COL, "mii0_col"),
+ PINCTRL_PIN(WMT_PIN_MII0CRS, "mii0_crs"),
+ PINCTRL_PIN(WMT_PIN_MII0MDIO, "mii0_mdio"),
+ PINCTRL_PIN(WMT_PIN_MII0MDC, "mii0_mdc"),
+ PINCTRL_PIN(WMT_PIN_SEECS, "see_cs"),
+ PINCTRL_PIN(WMT_PIN_SEECK, "see_ck"),
+ PINCTRL_PIN(WMT_PIN_SEEDI, "see_di"),
+ PINCTRL_PIN(WMT_PIN_SEEDO, "see_do"),
+ PINCTRL_PIN(WMT_PIN_IDEDREQ0, "ide_dreq0"),
+ PINCTRL_PIN(WMT_PIN_IDEDREQ1, "ide_dreq1"),
+ PINCTRL_PIN(WMT_PIN_IDEIOW, "ide_iow"),
+ PINCTRL_PIN(WMT_PIN_IDEIOR, "ide_ior"),
+ PINCTRL_PIN(WMT_PIN_IDEDACK, "ide_dack"),
+ PINCTRL_PIN(WMT_PIN_IDEIORDY, "ide_iordy"),
+ PINCTRL_PIN(WMT_PIN_IDEINTRQ, "ide_intrq"),
+ PINCTRL_PIN(WMT_PIN_VDIN0, "vdin0"),
+ PINCTRL_PIN(WMT_PIN_VDIN1, "vdin1"),
+ PINCTRL_PIN(WMT_PIN_VDIN2, "vdin2"),
+ PINCTRL_PIN(WMT_PIN_VDIN3, "vdin3"),
+ PINCTRL_PIN(WMT_PIN_VDIN4, "vdin4"),
+ PINCTRL_PIN(WMT_PIN_VDIN5, "vdin5"),
+ PINCTRL_PIN(WMT_PIN_VDIN6, "vdin6"),
+ PINCTRL_PIN(WMT_PIN_VDIN7, "vdin7"),
+ PINCTRL_PIN(WMT_PIN_VDOUT0, "vdout0"),
+ PINCTRL_PIN(WMT_PIN_VDOUT1, "vdout1"),
+ PINCTRL_PIN(WMT_PIN_VDOUT2, "vdout2"),
+ PINCTRL_PIN(WMT_PIN_VDOUT3, "vdout3"),
+ PINCTRL_PIN(WMT_PIN_VDOUT4, "vdout4"),
+ PINCTRL_PIN(WMT_PIN_VDOUT5, "vdout5"),
+ PINCTRL_PIN(WMT_PIN_NANDCLE0, "nand_cle0"),
+ PINCTRL_PIN(WMT_PIN_NANDCLE1, "nand_cle1"),
+ PINCTRL_PIN(WMT_PIN_VDOUT6_7, "vdout6_7"),
+ PINCTRL_PIN(WMT_PIN_VHSYNC, "vhsync"),
+ PINCTRL_PIN(WMT_PIN_VVSYNC, "vvsync"),
+ PINCTRL_PIN(WMT_PIN_TSDIN0, "tsdin0"),
+ PINCTRL_PIN(WMT_PIN_TSDIN1, "tsdin1"),
+ PINCTRL_PIN(WMT_PIN_TSDIN2, "tsdin2"),
+ PINCTRL_PIN(WMT_PIN_TSDIN3, "tsdin3"),
+ PINCTRL_PIN(WMT_PIN_TSDIN4, "tsdin4"),
+ PINCTRL_PIN(WMT_PIN_TSDIN5, "tsdin5"),
+ PINCTRL_PIN(WMT_PIN_TSDIN6, "tsdin6"),
+ PINCTRL_PIN(WMT_PIN_TSDIN7, "tsdin7"),
+ PINCTRL_PIN(WMT_PIN_TSSYNC, "tssync"),
+ PINCTRL_PIN(WMT_PIN_TSVALID, "tsvalid"),
+ PINCTRL_PIN(WMT_PIN_TSCLK, "tsclk"),
+ PINCTRL_PIN(WMT_PIN_LCDD0, "lcd_d0"),
+ PINCTRL_PIN(WMT_PIN_LCDD1, "lcd_d1"),
+ PINCTRL_PIN(WMT_PIN_LCDD2, "lcd_d2"),
+ PINCTRL_PIN(WMT_PIN_LCDD3, "lcd_d3"),
+ PINCTRL_PIN(WMT_PIN_LCDD4, "lcd_d4"),
+ PINCTRL_PIN(WMT_PIN_LCDD5, "lcd_d5"),
+ PINCTRL_PIN(WMT_PIN_LCDD6, "lcd_d6"),
+ PINCTRL_PIN(WMT_PIN_LCDD7, "lcd_d7"),
+ PINCTRL_PIN(WMT_PIN_LCDD8, "lcd_d8"),
+ PINCTRL_PIN(WMT_PIN_LCDD9, "lcd_d9"),
+ PINCTRL_PIN(WMT_PIN_LCDD10, "lcd_d10"),
+ PINCTRL_PIN(WMT_PIN_LCDD11, "lcd_d11"),
+ PINCTRL_PIN(WMT_PIN_LCDD12, "lcd_d12"),
+ PINCTRL_PIN(WMT_PIN_LCDD13, "lcd_d13"),
+ PINCTRL_PIN(WMT_PIN_LCDD14, "lcd_d14"),
+ PINCTRL_PIN(WMT_PIN_LCDD15, "lcd_d15"),
+ PINCTRL_PIN(WMT_PIN_LCDD16, "lcd_d16"),
+ PINCTRL_PIN(WMT_PIN_LCDD17, "lcd_d17"),
+ PINCTRL_PIN(WMT_PIN_LCDCLK, "lcd_clk"),
+ PINCTRL_PIN(WMT_PIN_LCDDEN, "lcd_den"),
+ PINCTRL_PIN(WMT_PIN_LCDLINE, "lcd_line"),
+ PINCTRL_PIN(WMT_PIN_LCDFRM, "lcd_frm"),
+ PINCTRL_PIN(WMT_PIN_LCDBIAS, "lcd_bias"),
+};
+
+/* Order of these names must match the above list */
+static const char * const vt8500_groups[] = {
+ "extgpio0",
+ "extgpio1",
+ "extgpio2",
+ "extgpio3",
+ "extgpio4",
+ "extgpio5",
+ "extgpio6",
+ "extgpio7",
+ "extgpio8",
+ "uart0_rts",
+ "uart0_txd",
+ "uart0_cts",
+ "uart0_rxd",
+ "uart1_rts",
+ "uart1_txd",
+ "uart1_cts",
+ "uart1_rxd",
+ "spi0_clk",
+ "spi0_ss",
+ "spi0_miso",
+ "spi0_mosi",
+ "spi1_clk",
+ "spi1_ss",
+ "spi1_miso",
+ "spi1_mosi",
+ "spi2_clk",
+ "spi2_ss",
+ "spi2_miso",
+ "spi2_mosi",
+ "sd_data0",
+ "sd_data1",
+ "sd_data2",
+ "sd_data3",
+ "mmc_data0",
+ "mmc_data1",
+ "mmc_data2",
+ "mmc_data3",
+ "sd_clk",
+ "sd_wp",
+ "sd_cmd",
+ "ms_data0",
+ "ms_data1",
+ "ms_data2",
+ "ms_data3",
+ "ms_clk",
+ "ms_bs",
+ "ms_ins",
+ "i2c0_scl",
+ "i2c0_sda",
+ "i2c1_scl",
+ "i2c1_sda",
+ "mii0_rxd0",
+ "mii0_rxd1",
+ "mii0_rxd2",
+ "mii0_rxd3",
+ "mii0_rxclk",
+ "mii0_rxdv",
+ "mii0_rxerr",
+ "mii0_phyrst",
+ "mii0_txd0",
+ "mii0_txd1",
+ "mii0_txd2",
+ "mii0_txd3",
+ "mii0_txclk",
+ "mii0_txen",
+ "mii0_txerr",
+ "mii0_phypd",
+ "mii0_col",
+ "mii0_crs",
+ "mii0_mdio",
+ "mii0_mdc",
+ "see_cs",
+ "see_ck",
+ "see_di",
+ "see_do",
+ "ide_dreq0",
+ "ide_dreq1",
+ "ide_iow",
+ "ide_ior",
+ "ide_dack",
+ "ide_iordy",
+ "ide_intrq",
+ "vdin0",
+ "vdin1",
+ "vdin2",
+ "vdin3",
+ "vdin4",
+ "vdin5",
+ "vdin6",
+ "vdin7",
+ "vdout0",
+ "vdout1",
+ "vdout2",
+ "vdout3",
+ "vdout4",
+ "vdout5",
+ "nand_cle0",
+ "nand_cle1",
+ "vdout6_7",
+ "vhsync",
+ "vvsync",
+ "tsdin0",
+ "tsdin1",
+ "tsdin2",
+ "tsdin3",
+ "tsdin4",
+ "tsdin5",
+ "tsdin6",
+ "tsdin7",
+ "tssync",
+ "tsvalid",
+ "tsclk",
+ "lcd_d0",
+ "lcd_d1",
+ "lcd_d2",
+ "lcd_d3",
+ "lcd_d4",
+ "lcd_d5",
+ "lcd_d6",
+ "lcd_d7",
+ "lcd_d8",
+ "lcd_d9",
+ "lcd_d10",
+ "lcd_d11",
+ "lcd_d12",
+ "lcd_d13",
+ "lcd_d14",
+ "lcd_d15",
+ "lcd_d16",
+ "lcd_d17",
+ "lcd_clk",
+ "lcd_den",
+ "lcd_line",
+ "lcd_frm",
+ "lcd_bias",
+};
+
+static int vt8500_pinctrl_probe(struct platform_device *pdev)
+{
+ struct wmt_pinctrl_data *data;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ dev_err(&pdev->dev, "failed to allocate data\n");
+ return -ENOMEM;
+ }
+
+ data->banks = vt8500_banks;
+ data->nbanks = ARRAY_SIZE(vt8500_banks);
+ data->pins = vt8500_pins;
+ data->npins = ARRAY_SIZE(vt8500_pins);
+ data->groups = vt8500_groups;
+ data->ngroups = ARRAY_SIZE(vt8500_groups);
+
+ return wmt_pinctrl_probe(pdev, data);
+}
+
+static int vt8500_pinctrl_remove(struct platform_device *pdev)
+{
+ return wmt_pinctrl_remove(pdev);
+}
+
+static struct of_device_id wmt_pinctrl_of_match[] = {
+ { .compatible = "via,vt8500-pinctrl" },
+ { /* sentinel */ },
+};
+
+static struct platform_driver wmt_pinctrl_driver = {
+ .probe = vt8500_pinctrl_probe,
+ .remove = vt8500_pinctrl_remove,
+ .driver = {
+ .name = "pinctrl-vt8500",
+ .owner = THIS_MODULE,
+ .of_match_table = wmt_pinctrl_of_match,
+ },
+};
+
+module_platform_driver(wmt_pinctrl_driver);
+
+MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
+MODULE_DESCRIPTION("VIA VT8500 Pincontrol driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, wmt_pinctrl_of_match);
diff --git a/drivers/pinctrl/vt8500/pinctrl-wm8505.c b/drivers/pinctrl/vt8500/pinctrl-wm8505.c
new file mode 100644
index 000000000000..483ba732694e
--- /dev/null
+++ b/drivers/pinctrl/vt8500/pinctrl-wm8505.c
@@ -0,0 +1,532 @@
+/*
+ * Pinctrl data for Wondermedia WM8505 SoC
+ *
+ * Copyright (c) 2013 Tony Prisk <linux@prisktech.co.nz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "pinctrl-wmt.h"
+
+/*
+ * Describe the register offsets within the GPIO memory space
+ * The dedicated external GPIO's should always be listed in bank 0
+ * so they are exported in the 0..31 range which is what users
+ * expect.
+ *
+ * Do not reorder these banks as it will change the pin numbering
+ */
+static const struct wmt_pinctrl_bank_registers wm8505_banks[] = {
+ WMT_PINCTRL_BANK(0x64, 0x8C, 0xB4, 0xDC, NO_REG, NO_REG), /* 0 */
+ WMT_PINCTRL_BANK(0x40, 0x68, 0x90, 0xB8, NO_REG, NO_REG), /* 1 */
+ WMT_PINCTRL_BANK(0x44, 0x6C, 0x94, 0xBC, NO_REG, NO_REG), /* 2 */
+ WMT_PINCTRL_BANK(0x48, 0x70, 0x98, 0xC0, NO_REG, NO_REG), /* 3 */
+ WMT_PINCTRL_BANK(0x4C, 0x74, 0x9C, 0xC4, NO_REG, NO_REG), /* 4 */
+ WMT_PINCTRL_BANK(0x50, 0x78, 0xA0, 0xC8, NO_REG, NO_REG), /* 5 */
+ WMT_PINCTRL_BANK(0x54, 0x7C, 0xA4, 0xD0, NO_REG, NO_REG), /* 6 */
+ WMT_PINCTRL_BANK(0x58, 0x80, 0xA8, 0xD4, NO_REG, NO_REG), /* 7 */
+ WMT_PINCTRL_BANK(0x5C, 0x84, 0xAC, 0xD8, NO_REG, NO_REG), /* 8 */
+ WMT_PINCTRL_BANK(0x60, 0x88, 0xB0, 0xDC, NO_REG, NO_REG), /* 9 */
+ WMT_PINCTRL_BANK(0x500, 0x504, 0x508, 0x50C, NO_REG, NO_REG), /* 10 */
+};
+
+/* Please keep sorted by bank/bit */
+#define WMT_PIN_EXTGPIO0 WMT_PIN(0, 0)
+#define WMT_PIN_EXTGPIO1 WMT_PIN(0, 1)
+#define WMT_PIN_EXTGPIO2 WMT_PIN(0, 2)
+#define WMT_PIN_EXTGPIO3 WMT_PIN(0, 3)
+#define WMT_PIN_EXTGPIO4 WMT_PIN(0, 4)
+#define WMT_PIN_EXTGPIO5 WMT_PIN(0, 5)
+#define WMT_PIN_EXTGPIO6 WMT_PIN(0, 6)
+#define WMT_PIN_EXTGPIO7 WMT_PIN(0, 7)
+#define WMT_PIN_WAKEUP0 WMT_PIN(0, 16)
+#define WMT_PIN_WAKEUP1 WMT_PIN(0, 17)
+#define WMT_PIN_WAKEUP2 WMT_PIN(0, 18)
+#define WMT_PIN_WAKEUP3 WMT_PIN(0, 19)
+#define WMT_PIN_SUSGPIO0 WMT_PIN(0, 21)
+#define WMT_PIN_SDDATA0 WMT_PIN(1, 0)
+#define WMT_PIN_SDDATA1 WMT_PIN(1, 1)
+#define WMT_PIN_SDDATA2 WMT_PIN(1, 2)
+#define WMT_PIN_SDDATA3 WMT_PIN(1, 3)
+#define WMT_PIN_MMCDATA0 WMT_PIN(1, 4)
+#define WMT_PIN_MMCDATA1 WMT_PIN(1, 5)
+#define WMT_PIN_MMCDATA2 WMT_PIN(1, 6)
+#define WMT_PIN_MMCDATA3 WMT_PIN(1, 7)
+#define WMT_PIN_VDIN0 WMT_PIN(2, 0)
+#define WMT_PIN_VDIN1 WMT_PIN(2, 1)
+#define WMT_PIN_VDIN2 WMT_PIN(2, 2)
+#define WMT_PIN_VDIN3 WMT_PIN(2, 3)
+#define WMT_PIN_VDIN4 WMT_PIN(2, 4)
+#define WMT_PIN_VDIN5 WMT_PIN(2, 5)
+#define WMT_PIN_VDIN6 WMT_PIN(2, 6)
+#define WMT_PIN_VDIN7 WMT_PIN(2, 7)
+#define WMT_PIN_VDOUT0 WMT_PIN(2, 8)
+#define WMT_PIN_VDOUT1 WMT_PIN(2, 9)
+#define WMT_PIN_VDOUT2 WMT_PIN(2, 10)
+#define WMT_PIN_VDOUT3 WMT_PIN(2, 11)
+#define WMT_PIN_VDOUT4 WMT_PIN(2, 12)
+#define WMT_PIN_VDOUT5 WMT_PIN(2, 13)
+#define WMT_PIN_VDOUT6 WMT_PIN(2, 14)
+#define WMT_PIN_VDOUT7 WMT_PIN(2, 15)
+#define WMT_PIN_VDOUT8 WMT_PIN(2, 16)
+#define WMT_PIN_VDOUT9 WMT_PIN(2, 17)
+#define WMT_PIN_VDOUT10 WMT_PIN(2, 18)
+#define WMT_PIN_VDOUT11 WMT_PIN(2, 19)
+#define WMT_PIN_VDOUT12 WMT_PIN(2, 20)
+#define WMT_PIN_VDOUT13 WMT_PIN(2, 21)
+#define WMT_PIN_VDOUT14 WMT_PIN(2, 22)
+#define WMT_PIN_VDOUT15 WMT_PIN(2, 23)
+#define WMT_PIN_VDOUT16 WMT_PIN(2, 24)
+#define WMT_PIN_VDOUT17 WMT_PIN(2, 25)
+#define WMT_PIN_VDOUT18 WMT_PIN(2, 26)
+#define WMT_PIN_VDOUT19 WMT_PIN(2, 27)
+#define WMT_PIN_VDOUT20 WMT_PIN(2, 28)
+#define WMT_PIN_VDOUT21 WMT_PIN(2, 29)
+#define WMT_PIN_VDOUT22 WMT_PIN(2, 30)
+#define WMT_PIN_VDOUT23 WMT_PIN(2, 31)
+#define WMT_PIN_VHSYNC WMT_PIN(3, 0)
+#define WMT_PIN_VVSYNC WMT_PIN(3, 1)
+#define WMT_PIN_VGAHSYNC WMT_PIN(3, 2)
+#define WMT_PIN_VGAVSYNC WMT_PIN(3, 3)
+#define WMT_PIN_VDHSYNC WMT_PIN(3, 4)
+#define WMT_PIN_VDVSYNC WMT_PIN(3, 5)
+#define WMT_PIN_NORD0 WMT_PIN(4, 0)
+#define WMT_PIN_NORD1 WMT_PIN(4, 1)
+#define WMT_PIN_NORD2 WMT_PIN(4, 2)
+#define WMT_PIN_NORD3 WMT_PIN(4, 3)
+#define WMT_PIN_NORD4 WMT_PIN(4, 4)
+#define WMT_PIN_NORD5 WMT_PIN(4, 5)
+#define WMT_PIN_NORD6 WMT_PIN(4, 6)
+#define WMT_PIN_NORD7 WMT_PIN(4, 7)
+#define WMT_PIN_NORD8 WMT_PIN(4, 8)
+#define WMT_PIN_NORD9 WMT_PIN(4, 9)
+#define WMT_PIN_NORD10 WMT_PIN(4, 10)
+#define WMT_PIN_NORD11 WMT_PIN(4, 11)
+#define WMT_PIN_NORD12 WMT_PIN(4, 12)
+#define WMT_PIN_NORD13 WMT_PIN(4, 13)
+#define WMT_PIN_NORD14 WMT_PIN(4, 14)
+#define WMT_PIN_NORD15 WMT_PIN(4, 15)
+#define WMT_PIN_NORA0 WMT_PIN(5, 0)
+#define WMT_PIN_NORA1 WMT_PIN(5, 1)
+#define WMT_PIN_NORA2 WMT_PIN(5, 2)
+#define WMT_PIN_NORA3 WMT_PIN(5, 3)
+#define WMT_PIN_NORA4 WMT_PIN(5, 4)
+#define WMT_PIN_NORA5 WMT_PIN(5, 5)
+#define WMT_PIN_NORA6 WMT_PIN(5, 6)
+#define WMT_PIN_NORA7 WMT_PIN(5, 7)
+#define WMT_PIN_NORA8 WMT_PIN(5, 8)
+#define WMT_PIN_NORA9 WMT_PIN(5, 9)
+#define WMT_PIN_NORA10 WMT_PIN(5, 10)
+#define WMT_PIN_NORA11 WMT_PIN(5, 11)
+#define WMT_PIN_NORA12 WMT_PIN(5, 12)
+#define WMT_PIN_NORA13 WMT_PIN(5, 13)
+#define WMT_PIN_NORA14 WMT_PIN(5, 14)
+#define WMT_PIN_NORA15 WMT_PIN(5, 15)
+#define WMT_PIN_NORA16 WMT_PIN(5, 16)
+#define WMT_PIN_NORA17 WMT_PIN(5, 17)
+#define WMT_PIN_NORA18 WMT_PIN(5, 18)
+#define WMT_PIN_NORA19 WMT_PIN(5, 19)
+#define WMT_PIN_NORA20 WMT_PIN(5, 20)
+#define WMT_PIN_NORA21 WMT_PIN(5, 21)
+#define WMT_PIN_NORA22 WMT_PIN(5, 22)
+#define WMT_PIN_NORA23 WMT_PIN(5, 23)
+#define WMT_PIN_NORA24 WMT_PIN(5, 24)
+#define WMT_PIN_AC97SDI WMT_PIN(6, 0)
+#define WMT_PIN_AC97SYNC WMT_PIN(6, 1)
+#define WMT_PIN_AC97SDO WMT_PIN(6, 2)
+#define WMT_PIN_AC97BCLK WMT_PIN(6, 3)
+#define WMT_PIN_AC97RST WMT_PIN(6, 4)
+#define WMT_PIN_SFDO WMT_PIN(7, 0)
+#define WMT_PIN_SFCS0 WMT_PIN(7, 1)
+#define WMT_PIN_SFCS1 WMT_PIN(7, 2)
+#define WMT_PIN_SFCLK WMT_PIN(7, 3)
+#define WMT_PIN_SFDI WMT_PIN(7, 4)
+#define WMT_PIN_SPI0CLK WMT_PIN(8, 0)
+#define WMT_PIN_SPI0MISO WMT_PIN(8, 1)
+#define WMT_PIN_SPI0MOSI WMT_PIN(8, 2)
+#define WMT_PIN_SPI0SS WMT_PIN(8, 3)
+#define WMT_PIN_SPI1CLK WMT_PIN(8, 4)
+#define WMT_PIN_SPI1MISO WMT_PIN(8, 5)
+#define WMT_PIN_SPI1MOSI WMT_PIN(8, 6)
+#define WMT_PIN_SPI1SS WMT_PIN(8, 7)
+#define WMT_PIN_SPI2CLK WMT_PIN(8, 8)
+#define WMT_PIN_SPI2MISO WMT_PIN(8, 9)
+#define WMT_PIN_SPI2MOSI WMT_PIN(8, 10)
+#define WMT_PIN_SPI2SS WMT_PIN(8, 11)
+#define WMT_PIN_UART0_RTS WMT_PIN(9, 0)
+#define WMT_PIN_UART0_TXD WMT_PIN(9, 1)
+#define WMT_PIN_UART0_CTS WMT_PIN(9, 2)
+#define WMT_PIN_UART0_RXD WMT_PIN(9, 3)
+#define WMT_PIN_UART1_RTS WMT_PIN(9, 4)
+#define WMT_PIN_UART1_TXD WMT_PIN(9, 5)
+#define WMT_PIN_UART1_CTS WMT_PIN(9, 6)
+#define WMT_PIN_UART1_RXD WMT_PIN(9, 7)
+#define WMT_PIN_UART2_RTS WMT_PIN(9, 8)
+#define WMT_PIN_UART2_TXD WMT_PIN(9, 9)
+#define WMT_PIN_UART2_CTS WMT_PIN(9, 10)
+#define WMT_PIN_UART2_RXD WMT_PIN(9, 11)
+#define WMT_PIN_UART3_RTS WMT_PIN(9, 12)
+#define WMT_PIN_UART3_TXD WMT_PIN(9, 13)
+#define WMT_PIN_UART3_CTS WMT_PIN(9, 14)
+#define WMT_PIN_UART3_RXD WMT_PIN(9, 15)
+#define WMT_PIN_I2C0SCL WMT_PIN(10, 0)
+#define WMT_PIN_I2C0SDA WMT_PIN(10, 1)
+#define WMT_PIN_I2C1SCL WMT_PIN(10, 2)
+#define WMT_PIN_I2C1SDA WMT_PIN(10, 3)
+#define WMT_PIN_I2C2SCL WMT_PIN(10, 4)
+#define WMT_PIN_I2C2SDA WMT_PIN(10, 5)
+
+static const struct pinctrl_pin_desc wm8505_pins[] = {
+ PINCTRL_PIN(WMT_PIN_EXTGPIO0, "extgpio0"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO1, "extgpio1"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO2, "extgpio2"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO3, "extgpio3"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO4, "extgpio4"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO5, "extgpio5"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO6, "extgpio6"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO7, "extgpio7"),
+ PINCTRL_PIN(WMT_PIN_WAKEUP0, "wakeup0"),
+ PINCTRL_PIN(WMT_PIN_WAKEUP1, "wakeup1"),
+ PINCTRL_PIN(WMT_PIN_WAKEUP2, "wakeup2"),
+ PINCTRL_PIN(WMT_PIN_WAKEUP3, "wakeup3"),
+ PINCTRL_PIN(WMT_PIN_SUSGPIO0, "susgpio0"),
+ PINCTRL_PIN(WMT_PIN_SDDATA0, "sd_data0"),
+ PINCTRL_PIN(WMT_PIN_SDDATA1, "sd_data1"),
+ PINCTRL_PIN(WMT_PIN_SDDATA2, "sd_data2"),
+ PINCTRL_PIN(WMT_PIN_SDDATA3, "sd_data3"),
+ PINCTRL_PIN(WMT_PIN_MMCDATA0, "mmc_data0"),
+ PINCTRL_PIN(WMT_PIN_MMCDATA1, "mmc_data1"),
+ PINCTRL_PIN(WMT_PIN_MMCDATA2, "mmc_data2"),
+ PINCTRL_PIN(WMT_PIN_MMCDATA3, "mmc_data3"),
+ PINCTRL_PIN(WMT_PIN_VDIN0, "vdin0"),
+ PINCTRL_PIN(WMT_PIN_VDIN1, "vdin1"),
+ PINCTRL_PIN(WMT_PIN_VDIN2, "vdin2"),
+ PINCTRL_PIN(WMT_PIN_VDIN3, "vdin3"),
+ PINCTRL_PIN(WMT_PIN_VDIN4, "vdin4"),
+ PINCTRL_PIN(WMT_PIN_VDIN5, "vdin5"),
+ PINCTRL_PIN(WMT_PIN_VDIN6, "vdin6"),
+ PINCTRL_PIN(WMT_PIN_VDIN7, "vdin7"),
+ PINCTRL_PIN(WMT_PIN_VDOUT0, "vdout0"),
+ PINCTRL_PIN(WMT_PIN_VDOUT1, "vdout1"),
+ PINCTRL_PIN(WMT_PIN_VDOUT2, "vdout2"),
+ PINCTRL_PIN(WMT_PIN_VDOUT3, "vdout3"),
+ PINCTRL_PIN(WMT_PIN_VDOUT4, "vdout4"),
+ PINCTRL_PIN(WMT_PIN_VDOUT5, "vdout5"),
+ PINCTRL_PIN(WMT_PIN_VDOUT6, "vdout6"),
+ PINCTRL_PIN(WMT_PIN_VDOUT7, "vdout7"),
+ PINCTRL_PIN(WMT_PIN_VDOUT8, "vdout8"),
+ PINCTRL_PIN(WMT_PIN_VDOUT9, "vdout9"),
+ PINCTRL_PIN(WMT_PIN_VDOUT10, "vdout10"),
+ PINCTRL_PIN(WMT_PIN_VDOUT11, "vdout11"),
+ PINCTRL_PIN(WMT_PIN_VDOUT12, "vdout12"),
+ PINCTRL_PIN(WMT_PIN_VDOUT13, "vdout13"),
+ PINCTRL_PIN(WMT_PIN_VDOUT14, "vdout14"),
+ PINCTRL_PIN(WMT_PIN_VDOUT15, "vdout15"),
+ PINCTRL_PIN(WMT_PIN_VDOUT16, "vdout16"),
+ PINCTRL_PIN(WMT_PIN_VDOUT17, "vdout17"),
+ PINCTRL_PIN(WMT_PIN_VDOUT18, "vdout18"),
+ PINCTRL_PIN(WMT_PIN_VDOUT19, "vdout19"),
+ PINCTRL_PIN(WMT_PIN_VDOUT20, "vdout20"),
+ PINCTRL_PIN(WMT_PIN_VDOUT21, "vdout21"),
+ PINCTRL_PIN(WMT_PIN_VDOUT22, "vdout22"),
+ PINCTRL_PIN(WMT_PIN_VDOUT23, "vdout23"),
+ PINCTRL_PIN(WMT_PIN_VHSYNC, "v_hsync"),
+ PINCTRL_PIN(WMT_PIN_VVSYNC, "v_vsync"),
+ PINCTRL_PIN(WMT_PIN_VGAHSYNC, "vga_hsync"),
+ PINCTRL_PIN(WMT_PIN_VGAVSYNC, "vga_vsync"),
+ PINCTRL_PIN(WMT_PIN_VDHSYNC, "vd_hsync"),
+ PINCTRL_PIN(WMT_PIN_VDVSYNC, "vd_vsync"),
+ PINCTRL_PIN(WMT_PIN_NORD0, "nor_d0"),
+ PINCTRL_PIN(WMT_PIN_NORD1, "nor_d1"),
+ PINCTRL_PIN(WMT_PIN_NORD2, "nor_d2"),
+ PINCTRL_PIN(WMT_PIN_NORD3, "nor_d3"),
+ PINCTRL_PIN(WMT_PIN_NORD4, "nor_d4"),
+ PINCTRL_PIN(WMT_PIN_NORD5, "nor_d5"),
+ PINCTRL_PIN(WMT_PIN_NORD6, "nor_d6"),
+ PINCTRL_PIN(WMT_PIN_NORD7, "nor_d7"),
+ PINCTRL_PIN(WMT_PIN_NORD8, "nor_d8"),
+ PINCTRL_PIN(WMT_PIN_NORD9, "nor_d9"),
+ PINCTRL_PIN(WMT_PIN_NORD10, "nor_d10"),
+ PINCTRL_PIN(WMT_PIN_NORD11, "nor_d11"),
+ PINCTRL_PIN(WMT_PIN_NORD12, "nor_d12"),
+ PINCTRL_PIN(WMT_PIN_NORD13, "nor_d13"),
+ PINCTRL_PIN(WMT_PIN_NORD14, "nor_d14"),
+ PINCTRL_PIN(WMT_PIN_NORD15, "nor_d15"),
+ PINCTRL_PIN(WMT_PIN_NORA0, "nor_a0"),
+ PINCTRL_PIN(WMT_PIN_NORA1, "nor_a1"),
+ PINCTRL_PIN(WMT_PIN_NORA2, "nor_a2"),
+ PINCTRL_PIN(WMT_PIN_NORA3, "nor_a3"),
+ PINCTRL_PIN(WMT_PIN_NORA4, "nor_a4"),
+ PINCTRL_PIN(WMT_PIN_NORA5, "nor_a5"),
+ PINCTRL_PIN(WMT_PIN_NORA6, "nor_a6"),
+ PINCTRL_PIN(WMT_PIN_NORA7, "nor_a7"),
+ PINCTRL_PIN(WMT_PIN_NORA8, "nor_a8"),
+ PINCTRL_PIN(WMT_PIN_NORA9, "nor_a9"),
+ PINCTRL_PIN(WMT_PIN_NORA10, "nor_a10"),
+ PINCTRL_PIN(WMT_PIN_NORA11, "nor_a11"),
+ PINCTRL_PIN(WMT_PIN_NORA12, "nor_a12"),
+ PINCTRL_PIN(WMT_PIN_NORA13, "nor_a13"),
+ PINCTRL_PIN(WMT_PIN_NORA14, "nor_a14"),
+ PINCTRL_PIN(WMT_PIN_NORA15, "nor_a15"),
+ PINCTRL_PIN(WMT_PIN_NORA16, "nor_a16"),
+ PINCTRL_PIN(WMT_PIN_NORA17, "nor_a17"),
+ PINCTRL_PIN(WMT_PIN_NORA18, "nor_a18"),
+ PINCTRL_PIN(WMT_PIN_NORA19, "nor_a19"),
+ PINCTRL_PIN(WMT_PIN_NORA20, "nor_a20"),
+ PINCTRL_PIN(WMT_PIN_NORA21, "nor_a21"),
+ PINCTRL_PIN(WMT_PIN_NORA22, "nor_a22"),
+ PINCTRL_PIN(WMT_PIN_NORA23, "nor_a23"),
+ PINCTRL_PIN(WMT_PIN_NORA24, "nor_a24"),
+ PINCTRL_PIN(WMT_PIN_AC97SDI, "ac97_sdi"),
+ PINCTRL_PIN(WMT_PIN_AC97SYNC, "ac97_sync"),
+ PINCTRL_PIN(WMT_PIN_AC97SDO, "ac97_sdo"),
+ PINCTRL_PIN(WMT_PIN_AC97BCLK, "ac97_bclk"),
+ PINCTRL_PIN(WMT_PIN_AC97RST, "ac97_rst"),
+ PINCTRL_PIN(WMT_PIN_SFDO, "sf_do"),
+ PINCTRL_PIN(WMT_PIN_SFCS0, "sf_cs0"),
+ PINCTRL_PIN(WMT_PIN_SFCS1, "sf_cs1"),
+ PINCTRL_PIN(WMT_PIN_SFCLK, "sf_clk"),
+ PINCTRL_PIN(WMT_PIN_SFDI, "sf_di"),
+ PINCTRL_PIN(WMT_PIN_SPI0CLK, "spi0_clk"),
+ PINCTRL_PIN(WMT_PIN_SPI0MISO, "spi0_miso"),
+ PINCTRL_PIN(WMT_PIN_SPI0MOSI, "spi0_mosi"),
+ PINCTRL_PIN(WMT_PIN_SPI0SS, "spi0_ss"),
+ PINCTRL_PIN(WMT_PIN_SPI1CLK, "spi1_clk"),
+ PINCTRL_PIN(WMT_PIN_SPI1MISO, "spi1_miso"),
+ PINCTRL_PIN(WMT_PIN_SPI1MOSI, "spi1_mosi"),
+ PINCTRL_PIN(WMT_PIN_SPI1SS, "spi1_ss"),
+ PINCTRL_PIN(WMT_PIN_SPI2CLK, "spi2_clk"),
+ PINCTRL_PIN(WMT_PIN_SPI2MISO, "spi2_miso"),
+ PINCTRL_PIN(WMT_PIN_SPI2MOSI, "spi2_mosi"),
+ PINCTRL_PIN(WMT_PIN_SPI2SS, "spi2_ss"),
+ PINCTRL_PIN(WMT_PIN_UART0_RTS, "uart0_rts"),
+ PINCTRL_PIN(WMT_PIN_UART0_TXD, "uart0_txd"),
+ PINCTRL_PIN(WMT_PIN_UART0_CTS, "uart0_cts"),
+ PINCTRL_PIN(WMT_PIN_UART0_RXD, "uart0_rxd"),
+ PINCTRL_PIN(WMT_PIN_UART1_RTS, "uart1_rts"),
+ PINCTRL_PIN(WMT_PIN_UART1_TXD, "uart1_txd"),
+ PINCTRL_PIN(WMT_PIN_UART1_CTS, "uart1_cts"),
+ PINCTRL_PIN(WMT_PIN_UART1_RXD, "uart1_rxd"),
+ PINCTRL_PIN(WMT_PIN_UART2_RTS, "uart2_rts"),
+ PINCTRL_PIN(WMT_PIN_UART2_TXD, "uart2_txd"),
+ PINCTRL_PIN(WMT_PIN_UART2_CTS, "uart2_cts"),
+ PINCTRL_PIN(WMT_PIN_UART2_RXD, "uart2_rxd"),
+ PINCTRL_PIN(WMT_PIN_UART3_RTS, "uart3_rts"),
+ PINCTRL_PIN(WMT_PIN_UART3_TXD, "uart3_txd"),
+ PINCTRL_PIN(WMT_PIN_UART3_CTS, "uart3_cts"),
+ PINCTRL_PIN(WMT_PIN_UART3_RXD, "uart3_rxd"),
+ PINCTRL_PIN(WMT_PIN_I2C0SCL, "i2c0_scl"),
+ PINCTRL_PIN(WMT_PIN_I2C0SDA, "i2c0_sda"),
+ PINCTRL_PIN(WMT_PIN_I2C1SCL, "i2c1_scl"),
+ PINCTRL_PIN(WMT_PIN_I2C1SDA, "i2c1_sda"),
+ PINCTRL_PIN(WMT_PIN_I2C2SCL, "i2c2_scl"),
+ PINCTRL_PIN(WMT_PIN_I2C2SDA, "i2c2_sda"),
+};
+
+/* Order of these names must match the above list */
+static const char * const wm8505_groups[] = {
+ "extgpio0",
+ "extgpio1",
+ "extgpio2",
+ "extgpio3",
+ "extgpio4",
+ "extgpio5",
+ "extgpio6",
+ "extgpio7",
+ "wakeup0",
+ "wakeup1",
+ "wakeup2",
+ "wakeup3",
+ "susgpio0",
+ "sd_data0",
+ "sd_data1",
+ "sd_data2",
+ "sd_data3",
+ "mmc_data0",
+ "mmc_data1",
+ "mmc_data2",
+ "mmc_data3",
+ "vdin0",
+ "vdin1",
+ "vdin2",
+ "vdin3",
+ "vdin4",
+ "vdin5",
+ "vdin6",
+ "vdin7",
+ "vdout0",
+ "vdout1",
+ "vdout2",
+ "vdout3",
+ "vdout4",
+ "vdout5",
+ "vdout6",
+ "vdout7",
+ "vdout8",
+ "vdout9",
+ "vdout10",
+ "vdout11",
+ "vdout12",
+ "vdout13",
+ "vdout14",
+ "vdout15",
+ "vdout16",
+ "vdout17",
+ "vdout18",
+ "vdout19",
+ "vdout20",
+ "vdout21",
+ "vdout22",
+ "vdout23",
+ "v_hsync",
+ "v_vsync",
+ "vga_hsync",
+ "vga_vsync",
+ "vd_hsync",
+ "vd_vsync",
+ "nor_d0",
+ "nor_d1",
+ "nor_d2",
+ "nor_d3",
+ "nor_d4",
+ "nor_d5",
+ "nor_d6",
+ "nor_d7",
+ "nor_d8",
+ "nor_d9",
+ "nor_d10",
+ "nor_d11",
+ "nor_d12",
+ "nor_d13",
+ "nor_d14",
+ "nor_d15",
+ "nor_a0",
+ "nor_a1",
+ "nor_a2",
+ "nor_a3",
+ "nor_a4",
+ "nor_a5",
+ "nor_a6",
+ "nor_a7",
+ "nor_a8",
+ "nor_a9",
+ "nor_a10",
+ "nor_a11",
+ "nor_a12",
+ "nor_a13",
+ "nor_a14",
+ "nor_a15",
+ "nor_a16",
+ "nor_a17",
+ "nor_a18",
+ "nor_a19",
+ "nor_a20",
+ "nor_a21",
+ "nor_a22",
+ "nor_a23",
+ "nor_a24",
+ "ac97_sdi",
+ "ac97_sync",
+ "ac97_sdo",
+ "ac97_bclk",
+ "ac97_rst",
+ "sf_do",
+ "sf_cs0",
+ "sf_cs1",
+ "sf_clk",
+ "sf_di",
+ "spi0_clk",
+ "spi0_miso",
+ "spi0_mosi",
+ "spi0_ss",
+ "spi1_clk",
+ "spi1_miso",
+ "spi1_mosi",
+ "spi1_ss",
+ "spi2_clk",
+ "spi2_miso",
+ "spi2_mosi",
+ "spi2_ss",
+ "uart0_rts",
+ "uart0_txd",
+ "uart0_cts",
+ "uart0_rxd",
+ "uart1_rts",
+ "uart1_txd",
+ "uart1_cts",
+ "uart1_rxd",
+ "uart2_rts",
+ "uart2_txd",
+ "uart2_cts",
+ "uart2_rxd",
+ "uart3_rts",
+ "uart3_txd",
+ "uart3_cts",
+ "uart3_rxd",
+ "i2c0_scl",
+ "i2c0_sda",
+ "i2c1_scl",
+ "i2c1_sda",
+ "i2c2_scl",
+ "i2c2_sda",
+};
+
+static int wm8505_pinctrl_probe(struct platform_device *pdev)
+{
+ struct wmt_pinctrl_data *data;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ dev_err(&pdev->dev, "failed to allocate data\n");
+ return -ENOMEM;
+ }
+
+ data->banks = wm8505_banks;
+ data->nbanks = ARRAY_SIZE(wm8505_banks);
+ data->pins = wm8505_pins;
+ data->npins = ARRAY_SIZE(wm8505_pins);
+ data->groups = wm8505_groups;
+ data->ngroups = ARRAY_SIZE(wm8505_groups);
+
+ return wmt_pinctrl_probe(pdev, data);
+}
+
+static int wm8505_pinctrl_remove(struct platform_device *pdev)
+{
+ return wmt_pinctrl_remove(pdev);
+}
+
+static struct of_device_id wmt_pinctrl_of_match[] = {
+ { .compatible = "wm,wm8505-pinctrl" },
+ { /* sentinel */ },
+};
+
+static struct platform_driver wmt_pinctrl_driver = {
+ .probe = wm8505_pinctrl_probe,
+ .remove = wm8505_pinctrl_remove,
+ .driver = {
+ .name = "pinctrl-wm8505",
+ .owner = THIS_MODULE,
+ .of_match_table = wmt_pinctrl_of_match,
+ },
+};
+
+module_platform_driver(wmt_pinctrl_driver);
+
+MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
+MODULE_DESCRIPTION("Wondermedia WM8505 Pincontrol driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, wmt_pinctrl_of_match);
diff --git a/drivers/pinctrl/vt8500/pinctrl-wm8650.c b/drivers/pinctrl/vt8500/pinctrl-wm8650.c
new file mode 100644
index 000000000000..7de57f063153
--- /dev/null
+++ b/drivers/pinctrl/vt8500/pinctrl-wm8650.c
@@ -0,0 +1,370 @@
+/*
+ * Pinctrl data for Wondermedia WM8650 SoC
+ *
+ * Copyright (c) 2013 Tony Prisk <linux@prisktech.co.nz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "pinctrl-wmt.h"
+
+/*
+ * Describe the register offsets within the GPIO memory space
+ * The dedicated external GPIO's should always be listed in bank 0
+ * so they are exported in the 0..31 range which is what users
+ * expect.
+ *
+ * Do not reorder these banks as it will change the pin numbering
+ */
+static const struct wmt_pinctrl_bank_registers wm8650_banks[] = {
+ WMT_PINCTRL_BANK(0x40, 0x80, 0xC0, 0x00, 0x480, 0x4C0), /* 0 */
+ WMT_PINCTRL_BANK(0x44, 0x84, 0xC4, 0x04, 0x484, 0x4C4), /* 1 */
+ WMT_PINCTRL_BANK(0x48, 0x88, 0xC8, 0x08, 0x488, 0x4C8), /* 2 */
+ WMT_PINCTRL_BANK(0x4C, 0x8C, 0xCC, 0x0C, 0x48C, 0x4CC), /* 3 */
+ WMT_PINCTRL_BANK(0x50, 0x90, 0xD0, 0x10, 0x490, 0x4D0), /* 4 */
+ WMT_PINCTRL_BANK(0x54, 0x94, 0xD4, 0x14, 0x494, 0x4D4), /* 5 */
+ WMT_PINCTRL_BANK(0x58, 0x98, 0xD8, 0x18, 0x498, 0x4D8), /* 6 */
+ WMT_PINCTRL_BANK(0x5C, 0x9C, 0xDC, 0x1C, 0x49C, 0x4DC), /* 7 */
+};
+
+/* Please keep sorted by bank/bit */
+#define WMT_PIN_EXTGPIO0 WMT_PIN(0, 0)
+#define WMT_PIN_EXTGPIO1 WMT_PIN(0, 1)
+#define WMT_PIN_EXTGPIO2 WMT_PIN(0, 2)
+#define WMT_PIN_EXTGPIO3 WMT_PIN(0, 3)
+#define WMT_PIN_EXTGPIO4 WMT_PIN(0, 4)
+#define WMT_PIN_EXTGPIO5 WMT_PIN(0, 5)
+#define WMT_PIN_EXTGPIO6 WMT_PIN(0, 6)
+#define WMT_PIN_EXTGPIO7 WMT_PIN(0, 7)
+#define WMT_PIN_WAKEUP0 WMT_PIN(0, 16)
+#define WMT_PIN_WAKEUP1 WMT_PIN(0, 17)
+#define WMT_PIN_SUSGPIO0 WMT_PIN(0, 21)
+#define WMT_PIN_SD0CD WMT_PIN(0, 28)
+#define WMT_PIN_SD1CD WMT_PIN(0, 29)
+#define WMT_PIN_VDOUT0 WMT_PIN(1, 0)
+#define WMT_PIN_VDOUT1 WMT_PIN(1, 1)
+#define WMT_PIN_VDOUT2 WMT_PIN(1, 2)
+#define WMT_PIN_VDOUT3 WMT_PIN(1, 3)
+#define WMT_PIN_VDOUT4 WMT_PIN(1, 4)
+#define WMT_PIN_VDOUT5 WMT_PIN(1, 5)
+#define WMT_PIN_VDOUT6 WMT_PIN(1, 6)
+#define WMT_PIN_VDOUT7 WMT_PIN(1, 7)
+#define WMT_PIN_VDOUT8 WMT_PIN(1, 8)
+#define WMT_PIN_VDOUT9 WMT_PIN(1, 9)
+#define WMT_PIN_VDOUT10 WMT_PIN(1, 10)
+#define WMT_PIN_VDOUT11 WMT_PIN(1, 11)
+#define WMT_PIN_VDOUT12 WMT_PIN(1, 12)
+#define WMT_PIN_VDOUT13 WMT_PIN(1, 13)
+#define WMT_PIN_VDOUT14 WMT_PIN(1, 14)
+#define WMT_PIN_VDOUT15 WMT_PIN(1, 15)
+#define WMT_PIN_VDOUT16 WMT_PIN(1, 16)
+#define WMT_PIN_VDOUT17 WMT_PIN(1, 17)
+#define WMT_PIN_VDOUT18 WMT_PIN(1, 18)
+#define WMT_PIN_VDOUT19 WMT_PIN(1, 19)
+#define WMT_PIN_VDOUT20 WMT_PIN(1, 20)
+#define WMT_PIN_VDOUT21 WMT_PIN(1, 21)
+#define WMT_PIN_VDOUT22 WMT_PIN(1, 22)
+#define WMT_PIN_VDOUT23 WMT_PIN(1, 23)
+#define WMT_PIN_VDIN0 WMT_PIN(2, 0)
+#define WMT_PIN_VDIN1 WMT_PIN(2, 1)
+#define WMT_PIN_VDIN2 WMT_PIN(2, 2)
+#define WMT_PIN_VDIN3 WMT_PIN(2, 3)
+#define WMT_PIN_VDIN4 WMT_PIN(2, 4)
+#define WMT_PIN_VDIN5 WMT_PIN(2, 5)
+#define WMT_PIN_VDIN6 WMT_PIN(2, 6)
+#define WMT_PIN_VDIN7 WMT_PIN(2, 7)
+#define WMT_PIN_I2C1SCL WMT_PIN(2, 12)
+#define WMT_PIN_I2C1SDA WMT_PIN(2, 13)
+#define WMT_PIN_SPI0MOSI WMT_PIN(2, 24)
+#define WMT_PIN_SPI0MISO WMT_PIN(2, 25)
+#define WMT_PIN_SPI0SS0 WMT_PIN(2, 26)
+#define WMT_PIN_SPI0CLK WMT_PIN(2, 27)
+#define WMT_PIN_SD0DATA0 WMT_PIN(3, 8)
+#define WMT_PIN_SD0DATA1 WMT_PIN(3, 9)
+#define WMT_PIN_SD0DATA2 WMT_PIN(3, 10)
+#define WMT_PIN_SD0DATA3 WMT_PIN(3, 11)
+#define WMT_PIN_SD0CLK WMT_PIN(3, 12)
+#define WMT_PIN_SD0WP WMT_PIN(3, 13)
+#define WMT_PIN_SD0CMD WMT_PIN(3, 14)
+#define WMT_PIN_SD1DATA0 WMT_PIN(3, 24)
+#define WMT_PIN_SD1DATA1 WMT_PIN(3, 25)
+#define WMT_PIN_SD1DATA2 WMT_PIN(3, 26)
+#define WMT_PIN_SD1DATA3 WMT_PIN(3, 27)
+#define WMT_PIN_SD1DATA4 WMT_PIN(3, 28)
+#define WMT_PIN_SD1DATA5 WMT_PIN(3, 29)
+#define WMT_PIN_SD1DATA6 WMT_PIN(3, 30)
+#define WMT_PIN_SD1DATA7 WMT_PIN(3, 31)
+#define WMT_PIN_I2C0SCL WMT_PIN(5, 8)
+#define WMT_PIN_I2C0SDA WMT_PIN(5, 9)
+#define WMT_PIN_UART0RTS WMT_PIN(5, 16)
+#define WMT_PIN_UART0TXD WMT_PIN(5, 17)
+#define WMT_PIN_UART0CTS WMT_PIN(5, 18)
+#define WMT_PIN_UART0RXD WMT_PIN(5, 19)
+#define WMT_PIN_UART1RTS WMT_PIN(5, 20)
+#define WMT_PIN_UART1TXD WMT_PIN(5, 21)
+#define WMT_PIN_UART1CTS WMT_PIN(5, 22)
+#define WMT_PIN_UART1RXD WMT_PIN(5, 23)
+#define WMT_PIN_UART2RTS WMT_PIN(5, 24)
+#define WMT_PIN_UART2TXD WMT_PIN(5, 25)
+#define WMT_PIN_UART2CTS WMT_PIN(5, 26)
+#define WMT_PIN_UART2RXD WMT_PIN(5, 27)
+#define WMT_PIN_UART3RTS WMT_PIN(5, 28)
+#define WMT_PIN_UART3TXD WMT_PIN(5, 29)
+#define WMT_PIN_UART3CTS WMT_PIN(5, 30)
+#define WMT_PIN_UART3RXD WMT_PIN(5, 31)
+#define WMT_PIN_KPADROW0 WMT_PIN(6, 16)
+#define WMT_PIN_KPADROW1 WMT_PIN(6, 17)
+#define WMT_PIN_KPADCOL0 WMT_PIN(6, 18)
+#define WMT_PIN_KPADCOL1 WMT_PIN(6, 19)
+#define WMT_PIN_SD1CLK WMT_PIN(7, 0)
+#define WMT_PIN_SD1CMD WMT_PIN(7, 1)
+#define WMT_PIN_SD1WP WMT_PIN(7, 13)
+
+static const struct pinctrl_pin_desc wm8650_pins[] = {
+ PINCTRL_PIN(WMT_PIN_EXTGPIO0, "extgpio0"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO1, "extgpio1"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO2, "extgpio2"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO3, "extgpio3"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO4, "extgpio4"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO5, "extgpio5"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO6, "extgpio6"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO7, "extgpio7"),
+ PINCTRL_PIN(WMT_PIN_WAKEUP0, "wakeup0"),
+ PINCTRL_PIN(WMT_PIN_WAKEUP1, "wakeup1"),
+ PINCTRL_PIN(WMT_PIN_SUSGPIO0, "susgpio0"),
+ PINCTRL_PIN(WMT_PIN_SD0CD, "sd0_cd"),
+ PINCTRL_PIN(WMT_PIN_SD1CD, "sd1_cd"),
+ PINCTRL_PIN(WMT_PIN_VDOUT0, "vdout0"),
+ PINCTRL_PIN(WMT_PIN_VDOUT1, "vdout1"),
+ PINCTRL_PIN(WMT_PIN_VDOUT2, "vdout2"),
+ PINCTRL_PIN(WMT_PIN_VDOUT3, "vdout3"),
+ PINCTRL_PIN(WMT_PIN_VDOUT4, "vdout4"),
+ PINCTRL_PIN(WMT_PIN_VDOUT5, "vdout5"),
+ PINCTRL_PIN(WMT_PIN_VDOUT6, "vdout6"),
+ PINCTRL_PIN(WMT_PIN_VDOUT7, "vdout7"),
+ PINCTRL_PIN(WMT_PIN_VDOUT8, "vdout8"),
+ PINCTRL_PIN(WMT_PIN_VDOUT9, "vdout9"),
+ PINCTRL_PIN(WMT_PIN_VDOUT10, "vdout10"),
+ PINCTRL_PIN(WMT_PIN_VDOUT11, "vdout11"),
+ PINCTRL_PIN(WMT_PIN_VDOUT12, "vdout12"),
+ PINCTRL_PIN(WMT_PIN_VDOUT13, "vdout13"),
+ PINCTRL_PIN(WMT_PIN_VDOUT14, "vdout14"),
+ PINCTRL_PIN(WMT_PIN_VDOUT15, "vdout15"),
+ PINCTRL_PIN(WMT_PIN_VDOUT16, "vdout16"),
+ PINCTRL_PIN(WMT_PIN_VDOUT17, "vdout17"),
+ PINCTRL_PIN(WMT_PIN_VDOUT18, "vdout18"),
+ PINCTRL_PIN(WMT_PIN_VDOUT19, "vdout19"),
+ PINCTRL_PIN(WMT_PIN_VDOUT20, "vdout20"),
+ PINCTRL_PIN(WMT_PIN_VDOUT21, "vdout21"),
+ PINCTRL_PIN(WMT_PIN_VDOUT22, "vdout22"),
+ PINCTRL_PIN(WMT_PIN_VDOUT23, "vdout23"),
+ PINCTRL_PIN(WMT_PIN_VDIN0, "vdin0"),
+ PINCTRL_PIN(WMT_PIN_VDIN1, "vdin1"),
+ PINCTRL_PIN(WMT_PIN_VDIN2, "vdin2"),
+ PINCTRL_PIN(WMT_PIN_VDIN3, "vdin3"),
+ PINCTRL_PIN(WMT_PIN_VDIN4, "vdin4"),
+ PINCTRL_PIN(WMT_PIN_VDIN5, "vdin5"),
+ PINCTRL_PIN(WMT_PIN_VDIN6, "vdin6"),
+ PINCTRL_PIN(WMT_PIN_VDIN7, "vdin7"),
+ PINCTRL_PIN(WMT_PIN_I2C1SCL, "i2c1_scl"),
+ PINCTRL_PIN(WMT_PIN_I2C1SDA, "i2c1_sda"),
+ PINCTRL_PIN(WMT_PIN_SPI0MOSI, "spi0_mosi"),
+ PINCTRL_PIN(WMT_PIN_SPI0MISO, "spi0_miso"),
+ PINCTRL_PIN(WMT_PIN_SPI0SS0, "spi0_ss0"),
+ PINCTRL_PIN(WMT_PIN_SPI0CLK, "spi0_clk"),
+ PINCTRL_PIN(WMT_PIN_SD0DATA0, "sd0_data0"),
+ PINCTRL_PIN(WMT_PIN_SD0DATA1, "sd0_data1"),
+ PINCTRL_PIN(WMT_PIN_SD0DATA2, "sd0_data2"),
+ PINCTRL_PIN(WMT_PIN_SD0DATA3, "sd0_data3"),
+ PINCTRL_PIN(WMT_PIN_SD0CLK, "sd0_clk"),
+ PINCTRL_PIN(WMT_PIN_SD0WP, "sd0_wp"),
+ PINCTRL_PIN(WMT_PIN_SD0CMD, "sd0_cmd"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA0, "sd1_data0"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA1, "sd1_data1"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA2, "sd1_data2"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA3, "sd1_data3"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA4, "sd1_data4"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA5, "sd1_data5"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA6, "sd1_data6"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA7, "sd1_data7"),
+ PINCTRL_PIN(WMT_PIN_I2C0SCL, "i2c0_scl"),
+ PINCTRL_PIN(WMT_PIN_I2C0SDA, "i2c0_sda"),
+ PINCTRL_PIN(WMT_PIN_UART0RTS, "uart0_rts"),
+ PINCTRL_PIN(WMT_PIN_UART0TXD, "uart0_txd"),
+ PINCTRL_PIN(WMT_PIN_UART0CTS, "uart0_cts"),
+ PINCTRL_PIN(WMT_PIN_UART0RXD, "uart0_rxd"),
+ PINCTRL_PIN(WMT_PIN_UART1RTS, "uart1_rts"),
+ PINCTRL_PIN(WMT_PIN_UART1TXD, "uart1_txd"),
+ PINCTRL_PIN(WMT_PIN_UART1CTS, "uart1_cts"),
+ PINCTRL_PIN(WMT_PIN_UART1RXD, "uart1_rxd"),
+ PINCTRL_PIN(WMT_PIN_UART2RTS, "uart2_rts"),
+ PINCTRL_PIN(WMT_PIN_UART2TXD, "uart2_txd"),
+ PINCTRL_PIN(WMT_PIN_UART2CTS, "uart2_cts"),
+ PINCTRL_PIN(WMT_PIN_UART2RXD, "uart2_rxd"),
+ PINCTRL_PIN(WMT_PIN_UART3RTS, "uart3_rts"),
+ PINCTRL_PIN(WMT_PIN_UART3TXD, "uart3_txd"),
+ PINCTRL_PIN(WMT_PIN_UART3CTS, "uart3_cts"),
+ PINCTRL_PIN(WMT_PIN_UART3RXD, "uart3_rxd"),
+ PINCTRL_PIN(WMT_PIN_KPADROW0, "kpadrow0"),
+ PINCTRL_PIN(WMT_PIN_KPADROW1, "kpadrow1"),
+ PINCTRL_PIN(WMT_PIN_KPADCOL0, "kpadcol0"),
+ PINCTRL_PIN(WMT_PIN_KPADCOL1, "kpadcol1"),
+ PINCTRL_PIN(WMT_PIN_SD1CLK, "sd1_clk"),
+ PINCTRL_PIN(WMT_PIN_SD1CMD, "sd1_cmd"),
+ PINCTRL_PIN(WMT_PIN_SD1WP, "sd1_wp"),
+};
+
+/* Order of these names must match the above list */
+static const char * const wm8650_groups[] = {
+ "extgpio0",
+ "extgpio1",
+ "extgpio2",
+ "extgpio3",
+ "extgpio4",
+ "extgpio5",
+ "extgpio6",
+ "extgpio7",
+ "wakeup0",
+ "wakeup1",
+ "susgpio0",
+ "sd0_cd",
+ "sd1_cd",
+ "vdout0",
+ "vdout1",
+ "vdout2",
+ "vdout3",
+ "vdout4",
+ "vdout5",
+ "vdout6",
+ "vdout7",
+ "vdout8",
+ "vdout9",
+ "vdout10",
+ "vdout11",
+ "vdout12",
+ "vdout13",
+ "vdout14",
+ "vdout15",
+ "vdout16",
+ "vdout17",
+ "vdout18",
+ "vdout19",
+ "vdout20",
+ "vdout21",
+ "vdout22",
+ "vdout23",
+ "vdin0",
+ "vdin1",
+ "vdin2",
+ "vdin3",
+ "vdin4",
+ "vdin5",
+ "vdin6",
+ "vdin7",
+ "i2c1_scl",
+ "i2c1_sda",
+ "spi0_mosi",
+ "spi0_miso",
+ "spi0_ss0",
+ "spi0_clk",
+ "sd0_data0",
+ "sd0_data1",
+ "sd0_data2",
+ "sd0_data3",
+ "sd0_clk",
+ "sd0_wp",
+ "sd0_cmd",
+ "sd1_data0",
+ "sd1_data1",
+ "sd1_data2",
+ "sd1_data3",
+ "sd1_data4",
+ "sd1_data5",
+ "sd1_data6",
+ "sd1_data7",
+ "i2c0_scl",
+ "i2c0_sda",
+ "uart0_rts",
+ "uart0_txd",
+ "uart0_cts",
+ "uart0_rxd",
+ "uart1_rts",
+ "uart1_txd",
+ "uart1_cts",
+ "uart1_rxd",
+ "uart2_rts",
+ "uart2_txd",
+ "uart2_cts",
+ "uart2_rxd",
+ "uart3_rts",
+ "uart3_txd",
+ "uart3_cts",
+ "uart3_rxd",
+ "kpadrow0",
+ "kpadrow1",
+ "kpadcol0",
+ "kpadcol1",
+ "sd1_clk",
+ "sd1_cmd",
+ "sd1_wp",
+};
+
+static int wm8650_pinctrl_probe(struct platform_device *pdev)
+{
+ struct wmt_pinctrl_data *data;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ dev_err(&pdev->dev, "failed to allocate data\n");
+ return -ENOMEM;
+ }
+
+ data->banks = wm8650_banks;
+ data->nbanks = ARRAY_SIZE(wm8650_banks);
+ data->pins = wm8650_pins;
+ data->npins = ARRAY_SIZE(wm8650_pins);
+ data->groups = wm8650_groups;
+ data->ngroups = ARRAY_SIZE(wm8650_groups);
+
+ return wmt_pinctrl_probe(pdev, data);
+}
+
+static int wm8650_pinctrl_remove(struct platform_device *pdev)
+{
+ return wmt_pinctrl_remove(pdev);
+}
+
+static struct of_device_id wmt_pinctrl_of_match[] = {
+ { .compatible = "wm,wm8650-pinctrl" },
+ { /* sentinel */ },
+};
+
+static struct platform_driver wmt_pinctrl_driver = {
+ .probe = wm8650_pinctrl_probe,
+ .remove = wm8650_pinctrl_remove,
+ .driver = {
+ .name = "pinctrl-wm8650",
+ .owner = THIS_MODULE,
+ .of_match_table = wmt_pinctrl_of_match,
+ },
+};
+
+module_platform_driver(wmt_pinctrl_driver);
+
+MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
+MODULE_DESCRIPTION("Wondermedia WM8650 Pincontrol driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, wmt_pinctrl_of_match);
diff --git a/drivers/pinctrl/vt8500/pinctrl-wm8750.c b/drivers/pinctrl/vt8500/pinctrl-wm8750.c
new file mode 100644
index 000000000000..b964cc550568
--- /dev/null
+++ b/drivers/pinctrl/vt8500/pinctrl-wm8750.c
@@ -0,0 +1,409 @@
+/*
+ * Pinctrl data for Wondermedia WM8750 SoC
+ *
+ * Copyright (c) 2013 Tony Prisk <linux@prisktech.co.nz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "pinctrl-wmt.h"
+
+/*
+ * Describe the register offsets within the GPIO memory space
+ * The dedicated external GPIO's should always be listed in bank 0
+ * so they are exported in the 0..31 range which is what users
+ * expect.
+ *
+ * Do not reorder these banks as it will change the pin numbering
+ */
+static const struct wmt_pinctrl_bank_registers wm8750_banks[] = {
+ WMT_PINCTRL_BANK(0x40, 0x80, 0xC0, 0x00, 0x480, 0x4C0), /* 0 */
+ WMT_PINCTRL_BANK(0x44, 0x84, 0xC4, 0x04, 0x484, 0x4C4), /* 1 */
+ WMT_PINCTRL_BANK(0x48, 0x88, 0xC8, 0x08, 0x488, 0x4C8), /* 2 */
+ WMT_PINCTRL_BANK(0x4C, 0x8C, 0xCC, 0x0C, 0x48C, 0x4CC), /* 3 */
+ WMT_PINCTRL_BANK(0x50, 0x90, 0xD0, 0x10, 0x490, 0x4D0), /* 4 */
+ WMT_PINCTRL_BANK(0x54, 0x94, 0xD4, 0x14, 0x494, 0x4D4), /* 5 */
+ WMT_PINCTRL_BANK(0x58, 0x98, 0xD8, 0x18, 0x498, 0x4D8), /* 6 */
+ WMT_PINCTRL_BANK(0x5C, 0x9C, 0xDC, 0x1C, 0x49C, 0x4DC), /* 7 */
+ WMT_PINCTRL_BANK(0x60, 0xA0, 0xE0, 0x20, 0x4A0, 0x4E0), /* 8 */
+ WMT_PINCTRL_BANK(0x70, 0xB0, 0xF0, 0x30, 0x4B0, 0x4F0), /* 9 */
+ WMT_PINCTRL_BANK(0x7C, 0xBC, 0xDC, 0x3C, 0x4BC, 0x4FC), /* 10 */
+};
+
+/* Please keep sorted by bank/bit */
+#define WMT_PIN_EXTGPIO0 WMT_PIN(0, 0)
+#define WMT_PIN_EXTGPIO1 WMT_PIN(0, 1)
+#define WMT_PIN_EXTGPIO2 WMT_PIN(0, 2)
+#define WMT_PIN_EXTGPIO3 WMT_PIN(0, 3)
+#define WMT_PIN_EXTGPIO4 WMT_PIN(0, 4)
+#define WMT_PIN_EXTGPIO5 WMT_PIN(0, 5)
+#define WMT_PIN_EXTGPIO6 WMT_PIN(0, 6)
+#define WMT_PIN_EXTGPIO7 WMT_PIN(0, 7)
+#define WMT_PIN_WAKEUP0 WMT_PIN(0, 16)
+#define WMT_PIN_WAKEUP1 WMT_PIN(0, 16)
+#define WMT_PIN_SD0CD WMT_PIN(0, 28)
+#define WMT_PIN_VDOUT0 WMT_PIN(1, 0)
+#define WMT_PIN_VDOUT1 WMT_PIN(1, 1)
+#define WMT_PIN_VDOUT2 WMT_PIN(1, 2)
+#define WMT_PIN_VDOUT3 WMT_PIN(1, 3)
+#define WMT_PIN_VDOUT4 WMT_PIN(1, 4)
+#define WMT_PIN_VDOUT5 WMT_PIN(1, 5)
+#define WMT_PIN_VDOUT6 WMT_PIN(1, 6)
+#define WMT_PIN_VDOUT7 WMT_PIN(1, 7)
+#define WMT_PIN_VDOUT8 WMT_PIN(1, 8)
+#define WMT_PIN_VDOUT9 WMT_PIN(1, 9)
+#define WMT_PIN_VDOUT10 WMT_PIN(1, 10)
+#define WMT_PIN_VDOUT11 WMT_PIN(1, 11)
+#define WMT_PIN_VDOUT12 WMT_PIN(1, 12)
+#define WMT_PIN_VDOUT13 WMT_PIN(1, 13)
+#define WMT_PIN_VDOUT14 WMT_PIN(1, 14)
+#define WMT_PIN_VDOUT15 WMT_PIN(1, 15)
+#define WMT_PIN_VDOUT16 WMT_PIN(1, 16)
+#define WMT_PIN_VDOUT17 WMT_PIN(1, 17)
+#define WMT_PIN_VDOUT18 WMT_PIN(1, 18)
+#define WMT_PIN_VDOUT19 WMT_PIN(1, 19)
+#define WMT_PIN_VDOUT20 WMT_PIN(1, 20)
+#define WMT_PIN_VDOUT21 WMT_PIN(1, 21)
+#define WMT_PIN_VDOUT22 WMT_PIN(1, 22)
+#define WMT_PIN_VDOUT23 WMT_PIN(1, 23)
+#define WMT_PIN_VDIN0 WMT_PIN(2, 0)
+#define WMT_PIN_VDIN1 WMT_PIN(2, 1)
+#define WMT_PIN_VDIN2 WMT_PIN(2, 2)
+#define WMT_PIN_VDIN3 WMT_PIN(2, 3)
+#define WMT_PIN_VDIN4 WMT_PIN(2, 4)
+#define WMT_PIN_VDIN5 WMT_PIN(2, 5)
+#define WMT_PIN_VDIN6 WMT_PIN(2, 6)
+#define WMT_PIN_VDIN7 WMT_PIN(2, 7)
+#define WMT_PIN_SPI0_MOSI WMT_PIN(2, 24)
+#define WMT_PIN_SPI0_MISO WMT_PIN(2, 25)
+#define WMT_PIN_SPI0_SS WMT_PIN(2, 26)
+#define WMT_PIN_SPI0_CLK WMT_PIN(2, 27)
+#define WMT_PIN_SPI0_SSB WMT_PIN(2, 28)
+#define WMT_PIN_SD0CLK WMT_PIN(3, 17)
+#define WMT_PIN_SD0CMD WMT_PIN(3, 18)
+#define WMT_PIN_SD0WP WMT_PIN(3, 19)
+#define WMT_PIN_SD0DATA0 WMT_PIN(3, 20)
+#define WMT_PIN_SD0DATA1 WMT_PIN(3, 21)
+#define WMT_PIN_SD0DATA2 WMT_PIN(3, 22)
+#define WMT_PIN_SD0DATA3 WMT_PIN(3, 23)
+#define WMT_PIN_SD1DATA0 WMT_PIN(3, 24)
+#define WMT_PIN_SD1DATA1 WMT_PIN(3, 25)
+#define WMT_PIN_SD1DATA2 WMT_PIN(3, 26)
+#define WMT_PIN_SD1DATA3 WMT_PIN(3, 27)
+#define WMT_PIN_SD1DATA4 WMT_PIN(3, 28)
+#define WMT_PIN_SD1DATA5 WMT_PIN(3, 29)
+#define WMT_PIN_SD1DATA6 WMT_PIN(3, 30)
+#define WMT_PIN_SD1DATA7 WMT_PIN(3, 31)
+#define WMT_PIN_I2C0_SCL WMT_PIN(5, 8)
+#define WMT_PIN_I2C0_SDA WMT_PIN(5, 9)
+#define WMT_PIN_I2C1_SCL WMT_PIN(5, 10)
+#define WMT_PIN_I2C1_SDA WMT_PIN(5, 11)
+#define WMT_PIN_I2C2_SCL WMT_PIN(5, 12)
+#define WMT_PIN_I2C2_SDA WMT_PIN(5, 13)
+#define WMT_PIN_UART0_RTS WMT_PIN(5, 16)
+#define WMT_PIN_UART0_TXD WMT_PIN(5, 17)
+#define WMT_PIN_UART0_CTS WMT_PIN(5, 18)
+#define WMT_PIN_UART0_RXD WMT_PIN(5, 19)
+#define WMT_PIN_UART1_RTS WMT_PIN(5, 20)
+#define WMT_PIN_UART1_TXD WMT_PIN(5, 21)
+#define WMT_PIN_UART1_CTS WMT_PIN(5, 22)
+#define WMT_PIN_UART1_RXD WMT_PIN(5, 23)
+#define WMT_PIN_UART2_RTS WMT_PIN(5, 24)
+#define WMT_PIN_UART2_TXD WMT_PIN(5, 25)
+#define WMT_PIN_UART2_CTS WMT_PIN(5, 26)
+#define WMT_PIN_UART2_RXD WMT_PIN(5, 27)
+#define WMT_PIN_UART3_RTS WMT_PIN(5, 28)
+#define WMT_PIN_UART3_TXD WMT_PIN(5, 29)
+#define WMT_PIN_UART3_CTS WMT_PIN(5, 30)
+#define WMT_PIN_UART3_RXD WMT_PIN(5, 31)
+#define WMT_PIN_SD2CD WMT_PIN(6, 0)
+#define WMT_PIN_SD2DATA3 WMT_PIN(6, 1)
+#define WMT_PIN_SD2DATA0 WMT_PIN(6, 2)
+#define WMT_PIN_SD2WP WMT_PIN(6, 3)
+#define WMT_PIN_SD2DATA1 WMT_PIN(6, 4)
+#define WMT_PIN_SD2DATA2 WMT_PIN(6, 5)
+#define WMT_PIN_SD2CMD WMT_PIN(6, 6)
+#define WMT_PIN_SD2CLK WMT_PIN(6, 7)
+#define WMT_PIN_SD2PWR WMT_PIN(6, 9)
+#define WMT_PIN_SD1CLK WMT_PIN(7, 0)
+#define WMT_PIN_SD1CMD WMT_PIN(7, 1)
+#define WMT_PIN_SD1PWR WMT_PIN(7, 10)
+#define WMT_PIN_SD1WP WMT_PIN(7, 11)
+#define WMT_PIN_SD1CD WMT_PIN(7, 12)
+#define WMT_PIN_SPI0SS3 WMT_PIN(7, 24)
+#define WMT_PIN_SPI0SS2 WMT_PIN(7, 25)
+#define WMT_PIN_PWMOUT1 WMT_PIN(7, 26)
+#define WMT_PIN_PWMOUT0 WMT_PIN(7, 27)
+
+static const struct pinctrl_pin_desc wm8750_pins[] = {
+ PINCTRL_PIN(WMT_PIN_EXTGPIO0, "extgpio0"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO1, "extgpio1"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO2, "extgpio2"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO3, "extgpio3"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO4, "extgpio4"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO5, "extgpio5"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO6, "extgpio6"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO7, "extgpio7"),
+ PINCTRL_PIN(WMT_PIN_WAKEUP0, "wakeup0"),
+ PINCTRL_PIN(WMT_PIN_WAKEUP1, "wakeup1"),
+ PINCTRL_PIN(WMT_PIN_SD0CD, "sd0_cd"),
+ PINCTRL_PIN(WMT_PIN_VDOUT0, "vdout0"),
+ PINCTRL_PIN(WMT_PIN_VDOUT1, "vdout1"),
+ PINCTRL_PIN(WMT_PIN_VDOUT2, "vdout2"),
+ PINCTRL_PIN(WMT_PIN_VDOUT3, "vdout3"),
+ PINCTRL_PIN(WMT_PIN_VDOUT4, "vdout4"),
+ PINCTRL_PIN(WMT_PIN_VDOUT5, "vdout5"),
+ PINCTRL_PIN(WMT_PIN_VDOUT6, "vdout6"),
+ PINCTRL_PIN(WMT_PIN_VDOUT7, "vdout7"),
+ PINCTRL_PIN(WMT_PIN_VDOUT8, "vdout8"),
+ PINCTRL_PIN(WMT_PIN_VDOUT9, "vdout9"),
+ PINCTRL_PIN(WMT_PIN_VDOUT10, "vdout10"),
+ PINCTRL_PIN(WMT_PIN_VDOUT11, "vdout11"),
+ PINCTRL_PIN(WMT_PIN_VDOUT12, "vdout12"),
+ PINCTRL_PIN(WMT_PIN_VDOUT13, "vdout13"),
+ PINCTRL_PIN(WMT_PIN_VDOUT14, "vdout14"),
+ PINCTRL_PIN(WMT_PIN_VDOUT15, "vdout15"),
+ PINCTRL_PIN(WMT_PIN_VDOUT16, "vdout16"),
+ PINCTRL_PIN(WMT_PIN_VDOUT17, "vdout17"),
+ PINCTRL_PIN(WMT_PIN_VDOUT18, "vdout18"),
+ PINCTRL_PIN(WMT_PIN_VDOUT19, "vdout19"),
+ PINCTRL_PIN(WMT_PIN_VDOUT20, "vdout20"),
+ PINCTRL_PIN(WMT_PIN_VDOUT21, "vdout21"),
+ PINCTRL_PIN(WMT_PIN_VDOUT22, "vdout22"),
+ PINCTRL_PIN(WMT_PIN_VDOUT23, "vdout23"),
+ PINCTRL_PIN(WMT_PIN_VDIN0, "vdin0"),
+ PINCTRL_PIN(WMT_PIN_VDIN1, "vdin1"),
+ PINCTRL_PIN(WMT_PIN_VDIN2, "vdin2"),
+ PINCTRL_PIN(WMT_PIN_VDIN3, "vdin3"),
+ PINCTRL_PIN(WMT_PIN_VDIN4, "vdin4"),
+ PINCTRL_PIN(WMT_PIN_VDIN5, "vdin5"),
+ PINCTRL_PIN(WMT_PIN_VDIN6, "vdin6"),
+ PINCTRL_PIN(WMT_PIN_VDIN7, "vdin7"),
+ PINCTRL_PIN(WMT_PIN_SPI0_MOSI, "spi0_mosi"),
+ PINCTRL_PIN(WMT_PIN_SPI0_MISO, "spi0_miso"),
+ PINCTRL_PIN(WMT_PIN_SPI0_SS, "spi0_ss"),
+ PINCTRL_PIN(WMT_PIN_SPI0_CLK, "spi0_clk"),
+ PINCTRL_PIN(WMT_PIN_SPI0_SSB, "spi0_ssb"),
+ PINCTRL_PIN(WMT_PIN_SD0CLK, "sd0_clk"),
+ PINCTRL_PIN(WMT_PIN_SD0CMD, "sd0_cmd"),
+ PINCTRL_PIN(WMT_PIN_SD0WP, "sd0_wp"),
+ PINCTRL_PIN(WMT_PIN_SD0DATA0, "sd0_data0"),
+ PINCTRL_PIN(WMT_PIN_SD0DATA1, "sd0_data1"),
+ PINCTRL_PIN(WMT_PIN_SD0DATA2, "sd0_data2"),
+ PINCTRL_PIN(WMT_PIN_SD0DATA3, "sd0_data3"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA0, "sd1_data0"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA1, "sd1_data1"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA2, "sd1_data2"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA3, "sd1_data3"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA4, "sd1_data4"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA5, "sd1_data5"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA6, "sd1_data6"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA7, "sd1_data7"),
+ PINCTRL_PIN(WMT_PIN_I2C0_SCL, "i2c0_scl"),
+ PINCTRL_PIN(WMT_PIN_I2C0_SDA, "i2c0_sda"),
+ PINCTRL_PIN(WMT_PIN_I2C1_SCL, "i2c1_scl"),
+ PINCTRL_PIN(WMT_PIN_I2C1_SDA, "i2c1_sda"),
+ PINCTRL_PIN(WMT_PIN_I2C2_SCL, "i2c2_scl"),
+ PINCTRL_PIN(WMT_PIN_I2C2_SDA, "i2c2_sda"),
+ PINCTRL_PIN(WMT_PIN_UART0_RTS, "uart0_rts"),
+ PINCTRL_PIN(WMT_PIN_UART0_TXD, "uart0_txd"),
+ PINCTRL_PIN(WMT_PIN_UART0_CTS, "uart0_cts"),
+ PINCTRL_PIN(WMT_PIN_UART0_RXD, "uart0_rxd"),
+ PINCTRL_PIN(WMT_PIN_UART1_RTS, "uart1_rts"),
+ PINCTRL_PIN(WMT_PIN_UART1_TXD, "uart1_txd"),
+ PINCTRL_PIN(WMT_PIN_UART1_CTS, "uart1_cts"),
+ PINCTRL_PIN(WMT_PIN_UART1_RXD, "uart1_rxd"),
+ PINCTRL_PIN(WMT_PIN_UART2_RTS, "uart2_rts"),
+ PINCTRL_PIN(WMT_PIN_UART2_TXD, "uart2_txd"),
+ PINCTRL_PIN(WMT_PIN_UART2_CTS, "uart2_cts"),
+ PINCTRL_PIN(WMT_PIN_UART2_RXD, "uart2_rxd"),
+ PINCTRL_PIN(WMT_PIN_UART3_RTS, "uart3_rts"),
+ PINCTRL_PIN(WMT_PIN_UART3_TXD, "uart3_txd"),
+ PINCTRL_PIN(WMT_PIN_UART3_CTS, "uart3_cts"),
+ PINCTRL_PIN(WMT_PIN_UART3_RXD, "uart3_rxd"),
+ PINCTRL_PIN(WMT_PIN_SD2CD, "sd2_cd"),
+ PINCTRL_PIN(WMT_PIN_SD2DATA3, "sd2_data3"),
+ PINCTRL_PIN(WMT_PIN_SD2DATA0, "sd2_data0"),
+ PINCTRL_PIN(WMT_PIN_SD2WP, "sd2_wp"),
+ PINCTRL_PIN(WMT_PIN_SD2DATA1, "sd2_data1"),
+ PINCTRL_PIN(WMT_PIN_SD2DATA2, "sd2_data2"),
+ PINCTRL_PIN(WMT_PIN_SD2CMD, "sd2_cmd"),
+ PINCTRL_PIN(WMT_PIN_SD2CLK, "sd2_clk"),
+ PINCTRL_PIN(WMT_PIN_SD2PWR, "sd2_pwr"),
+ PINCTRL_PIN(WMT_PIN_SD1CLK, "sd1_clk"),
+ PINCTRL_PIN(WMT_PIN_SD1CMD, "sd1_cmd"),
+ PINCTRL_PIN(WMT_PIN_SD1PWR, "sd1_pwr"),
+ PINCTRL_PIN(WMT_PIN_SD1WP, "sd1_wp"),
+ PINCTRL_PIN(WMT_PIN_SD1CD, "sd1_cd"),
+ PINCTRL_PIN(WMT_PIN_SPI0SS3, "spi0_ss3"),
+ PINCTRL_PIN(WMT_PIN_SPI0SS2, "spi0_ss2"),
+ PINCTRL_PIN(WMT_PIN_PWMOUT1, "pwmout1"),
+ PINCTRL_PIN(WMT_PIN_PWMOUT0, "pwmout0"),
+};
+
+/* Order of these names must match the above list */
+static const char * const wm8750_groups[] = {
+ "extgpio0",
+ "extgpio1",
+ "extgpio2",
+ "extgpio3",
+ "extgpio4",
+ "extgpio5",
+ "extgpio6",
+ "extgpio7",
+ "wakeup0",
+ "wakeup1",
+ "sd0_cd",
+ "vdout0",
+ "vdout1",
+ "vdout2",
+ "vdout3",
+ "vdout4",
+ "vdout5",
+ "vdout6",
+ "vdout7",
+ "vdout8",
+ "vdout9",
+ "vdout10",
+ "vdout11",
+ "vdout12",
+ "vdout13",
+ "vdout14",
+ "vdout15",
+ "vdout16",
+ "vdout17",
+ "vdout18",
+ "vdout19",
+ "vdout20",
+ "vdout21",
+ "vdout22",
+ "vdout23",
+ "vdin0",
+ "vdin1",
+ "vdin2",
+ "vdin3",
+ "vdin4",
+ "vdin5",
+ "vdin6",
+ "vdin7",
+ "spi0_mosi",
+ "spi0_miso",
+ "spi0_ss",
+ "spi0_clk",
+ "spi0_ssb",
+ "sd0_clk",
+ "sd0_cmd",
+ "sd0_wp",
+ "sd0_data0",
+ "sd0_data1",
+ "sd0_data2",
+ "sd0_data3",
+ "sd1_data0",
+ "sd1_data1",
+ "sd1_data2",
+ "sd1_data3",
+ "sd1_data4",
+ "sd1_data5",
+ "sd1_data6",
+ "sd1_data7",
+ "i2c0_scl",
+ "i2c0_sda",
+ "i2c1_scl",
+ "i2c1_sda",
+ "i2c2_scl",
+ "i2c2_sda",
+ "uart0_rts",
+ "uart0_txd",
+ "uart0_cts",
+ "uart0_rxd",
+ "uart1_rts",
+ "uart1_txd",
+ "uart1_cts",
+ "uart1_rxd",
+ "uart2_rts",
+ "uart2_txd",
+ "uart2_cts",
+ "uart2_rxd",
+ "uart3_rts",
+ "uart3_txd",
+ "uart3_cts",
+ "uart3_rxd",
+ "sd2_cd",
+ "sd2_data3",
+ "sd2_data0",
+ "sd2_wp",
+ "sd2_data1",
+ "sd2_data2",
+ "sd2_cmd",
+ "sd2_clk",
+ "sd2_pwr",
+ "sd1_clk",
+ "sd1_cmd",
+ "sd1_pwr",
+ "sd1_wp",
+ "sd1_cd",
+ "spi0_ss3",
+ "spi0_ss2",
+ "pwmout1",
+ "pwmout0",
+};
+
+static int wm8750_pinctrl_probe(struct platform_device *pdev)
+{
+ struct wmt_pinctrl_data *data;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ dev_err(&pdev->dev, "failed to allocate data\n");
+ return -ENOMEM;
+ }
+
+ data->banks = wm8750_banks;
+ data->nbanks = ARRAY_SIZE(wm8750_banks);
+ data->pins = wm8750_pins;
+ data->npins = ARRAY_SIZE(wm8750_pins);
+ data->groups = wm8750_groups;
+ data->ngroups = ARRAY_SIZE(wm8750_groups);
+
+ return wmt_pinctrl_probe(pdev, data);
+}
+
+static int wm8750_pinctrl_remove(struct platform_device *pdev)
+{
+ return wmt_pinctrl_remove(pdev);
+}
+
+static struct of_device_id wmt_pinctrl_of_match[] = {
+ { .compatible = "wm,wm8750-pinctrl" },
+ { /* sentinel */ },
+};
+
+static struct platform_driver wmt_pinctrl_driver = {
+ .probe = wm8750_pinctrl_probe,
+ .remove = wm8750_pinctrl_remove,
+ .driver = {
+ .name = "pinctrl-wm8750",
+ .owner = THIS_MODULE,
+ .of_match_table = wmt_pinctrl_of_match,
+ },
+};
+
+module_platform_driver(wmt_pinctrl_driver);
+
+MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
+MODULE_DESCRIPTION("Wondermedia WM8750 Pincontrol driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, wmt_pinctrl_of_match);
diff --git a/drivers/pinctrl/vt8500/pinctrl-wm8850.c b/drivers/pinctrl/vt8500/pinctrl-wm8850.c
new file mode 100644
index 000000000000..ecadce9c91d5
--- /dev/null
+++ b/drivers/pinctrl/vt8500/pinctrl-wm8850.c
@@ -0,0 +1,388 @@
+/*
+ * Pinctrl data for Wondermedia WM8850 SoC
+ *
+ * Copyright (c) 2013 Tony Prisk <linux@prisktech.co.nz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "pinctrl-wmt.h"
+
+/*
+ * Describe the register offsets within the GPIO memory space
+ * The dedicated external GPIO's should always be listed in bank 0
+ * so they are exported in the 0..31 range which is what users
+ * expect.
+ *
+ * Do not reorder these banks as it will change the pin numbering
+ */
+static const struct wmt_pinctrl_bank_registers wm8850_banks[] = {
+ WMT_PINCTRL_BANK(0x40, 0x80, 0xC0, 0x00, 0x480, 0x4C0), /* 0 */
+ WMT_PINCTRL_BANK(0x44, 0x84, 0xC4, 0x04, 0x484, 0x4C4), /* 1 */
+ WMT_PINCTRL_BANK(0x48, 0x88, 0xC8, 0x08, 0x488, 0x4C8), /* 2 */
+ WMT_PINCTRL_BANK(0x4C, 0x8C, 0xCC, 0x0C, 0x48C, 0x4CC), /* 3 */
+ WMT_PINCTRL_BANK(0x50, 0x90, 0xD0, 0x10, 0x490, 0x4D0), /* 4 */
+ WMT_PINCTRL_BANK(0x54, 0x94, 0xD4, 0x14, 0x494, 0x4D4), /* 5 */
+ WMT_PINCTRL_BANK(0x58, 0x98, 0xD8, 0x18, 0x498, 0x4D8), /* 6 */
+ WMT_PINCTRL_BANK(0x5C, 0x9C, 0xDC, 0x1C, 0x49C, 0x4DC), /* 7 */
+ WMT_PINCTRL_BANK(0x60, 0xA0, 0xE0, 0x20, 0x4A0, 0x4E0), /* 8 */
+ WMT_PINCTRL_BANK(0x70, 0xB0, 0xF0, 0x30, 0x4B0, 0x4F0), /* 9 */
+ WMT_PINCTRL_BANK(0x7C, 0xBC, 0xDC, 0x3C, 0x4BC, 0x4FC), /* 10 */
+};
+
+/* Please keep sorted by bank/bit */
+#define WMT_PIN_EXTGPIO0 WMT_PIN(0, 0)
+#define WMT_PIN_EXTGPIO1 WMT_PIN(0, 1)
+#define WMT_PIN_EXTGPIO2 WMT_PIN(0, 2)
+#define WMT_PIN_EXTGPIO3 WMT_PIN(0, 3)
+#define WMT_PIN_EXTGPIO4 WMT_PIN(0, 4)
+#define WMT_PIN_EXTGPIO5 WMT_PIN(0, 5)
+#define WMT_PIN_EXTGPIO6 WMT_PIN(0, 6)
+#define WMT_PIN_EXTGPIO7 WMT_PIN(0, 7)
+#define WMT_PIN_WAKEUP0 WMT_PIN(0, 16)
+#define WMT_PIN_WAKEUP1 WMT_PIN(0, 17)
+#define WMT_PIN_WAKEUP2 WMT_PIN(0, 18)
+#define WMT_PIN_WAKEUP3 WMT_PIN(0, 19)
+#define WMT_PIN_SUSGPIO0 WMT_PIN(0, 21)
+#define WMT_PIN_SUSGPIO1 WMT_PIN(0, 22)
+#define WMT_PIN_SD0CD WMT_PIN(0, 28)
+#define WMT_PIN_VDOUT0 WMT_PIN(1, 0)
+#define WMT_PIN_VDOUT1 WMT_PIN(1, 1)
+#define WMT_PIN_VDOUT2 WMT_PIN(1, 2)
+#define WMT_PIN_VDOUT3 WMT_PIN(1, 3)
+#define WMT_PIN_VDOUT4 WMT_PIN(1, 4)
+#define WMT_PIN_VDOUT5 WMT_PIN(1, 5)
+#define WMT_PIN_VDOUT6 WMT_PIN(1, 6)
+#define WMT_PIN_VDOUT7 WMT_PIN(1, 7)
+#define WMT_PIN_VDOUT8 WMT_PIN(1, 8)
+#define WMT_PIN_VDOUT9 WMT_PIN(1, 9)
+#define WMT_PIN_VDOUT10 WMT_PIN(1, 10)
+#define WMT_PIN_VDOUT11 WMT_PIN(1, 11)
+#define WMT_PIN_VDOUT12 WMT_PIN(1, 12)
+#define WMT_PIN_VDOUT13 WMT_PIN(1, 13)
+#define WMT_PIN_VDOUT14 WMT_PIN(1, 14)
+#define WMT_PIN_VDOUT15 WMT_PIN(1, 15)
+#define WMT_PIN_VDOUT16 WMT_PIN(1, 16)
+#define WMT_PIN_VDOUT17 WMT_PIN(1, 17)
+#define WMT_PIN_VDOUT18 WMT_PIN(1, 18)
+#define WMT_PIN_VDOUT19 WMT_PIN(1, 19)
+#define WMT_PIN_VDOUT20 WMT_PIN(1, 20)
+#define WMT_PIN_VDOUT21 WMT_PIN(1, 21)
+#define WMT_PIN_VDOUT22 WMT_PIN(1, 22)
+#define WMT_PIN_VDOUT23 WMT_PIN(1, 23)
+#define WMT_PIN_VDIN0 WMT_PIN(2, 0)
+#define WMT_PIN_VDIN1 WMT_PIN(2, 1)
+#define WMT_PIN_VDIN2 WMT_PIN(2, 2)
+#define WMT_PIN_VDIN3 WMT_PIN(2, 3)
+#define WMT_PIN_VDIN4 WMT_PIN(2, 4)
+#define WMT_PIN_VDIN5 WMT_PIN(2, 5)
+#define WMT_PIN_VDIN6 WMT_PIN(2, 6)
+#define WMT_PIN_VDIN7 WMT_PIN(2, 7)
+#define WMT_PIN_SPI0_MOSI WMT_PIN(2, 24)
+#define WMT_PIN_SPI0_MISO WMT_PIN(2, 25)
+#define WMT_PIN_SPI0_SS WMT_PIN(2, 26)
+#define WMT_PIN_SPI0_CLK WMT_PIN(2, 27)
+#define WMT_PIN_SPI0_SSB WMT_PIN(2, 28)
+#define WMT_PIN_SD0CLK WMT_PIN(3, 17)
+#define WMT_PIN_SD0CMD WMT_PIN(3, 18)
+#define WMT_PIN_SD0WP WMT_PIN(3, 19)
+#define WMT_PIN_SD0DATA0 WMT_PIN(3, 20)
+#define WMT_PIN_SD0DATA1 WMT_PIN(3, 21)
+#define WMT_PIN_SD0DATA2 WMT_PIN(3, 22)
+#define WMT_PIN_SD0DATA3 WMT_PIN(3, 23)
+#define WMT_PIN_SD1DATA0 WMT_PIN(3, 24)
+#define WMT_PIN_SD1DATA1 WMT_PIN(3, 25)
+#define WMT_PIN_SD1DATA2 WMT_PIN(3, 26)
+#define WMT_PIN_SD1DATA3 WMT_PIN(3, 27)
+#define WMT_PIN_SD1DATA4 WMT_PIN(3, 28)
+#define WMT_PIN_SD1DATA5 WMT_PIN(3, 29)
+#define WMT_PIN_SD1DATA6 WMT_PIN(3, 30)
+#define WMT_PIN_SD1DATA7 WMT_PIN(3, 31)
+#define WMT_PIN_I2C0_SCL WMT_PIN(5, 8)
+#define WMT_PIN_I2C0_SDA WMT_PIN(5, 9)
+#define WMT_PIN_I2C1_SCL WMT_PIN(5, 10)
+#define WMT_PIN_I2C1_SDA WMT_PIN(5, 11)
+#define WMT_PIN_I2C2_SCL WMT_PIN(5, 12)
+#define WMT_PIN_I2C2_SDA WMT_PIN(5, 13)
+#define WMT_PIN_UART0_RTS WMT_PIN(5, 16)
+#define WMT_PIN_UART0_TXD WMT_PIN(5, 17)
+#define WMT_PIN_UART0_CTS WMT_PIN(5, 18)
+#define WMT_PIN_UART0_RXD WMT_PIN(5, 19)
+#define WMT_PIN_UART1_RTS WMT_PIN(5, 20)
+#define WMT_PIN_UART1_TXD WMT_PIN(5, 21)
+#define WMT_PIN_UART1_CTS WMT_PIN(5, 22)
+#define WMT_PIN_UART1_RXD WMT_PIN(5, 23)
+#define WMT_PIN_UART2_RTS WMT_PIN(5, 24)
+#define WMT_PIN_UART2_TXD WMT_PIN(5, 25)
+#define WMT_PIN_UART2_CTS WMT_PIN(5, 26)
+#define WMT_PIN_UART2_RXD WMT_PIN(5, 27)
+#define WMT_PIN_SD2WP WMT_PIN(6, 3)
+#define WMT_PIN_SD2CMD WMT_PIN(6, 6)
+#define WMT_PIN_SD2CLK WMT_PIN(6, 7)
+#define WMT_PIN_SD2PWR WMT_PIN(6, 9)
+#define WMT_PIN_SD1CLK WMT_PIN(7, 0)
+#define WMT_PIN_SD1CMD WMT_PIN(7, 1)
+#define WMT_PIN_SD1PWR WMT_PIN(7, 10)
+#define WMT_PIN_SD1WP WMT_PIN(7, 11)
+#define WMT_PIN_SD1CD WMT_PIN(7, 12)
+#define WMT_PIN_PWMOUT1 WMT_PIN(7, 26)
+#define WMT_PIN_PWMOUT0 WMT_PIN(7, 27)
+
+static const struct pinctrl_pin_desc wm8850_pins[] = {
+ PINCTRL_PIN(WMT_PIN_EXTGPIO0, "extgpio0"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO1, "extgpio1"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO2, "extgpio2"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO3, "extgpio3"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO4, "extgpio4"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO5, "extgpio5"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO6, "extgpio6"),
+ PINCTRL_PIN(WMT_PIN_EXTGPIO7, "extgpio7"),
+ PINCTRL_PIN(WMT_PIN_WAKEUP0, "wakeup0"),
+ PINCTRL_PIN(WMT_PIN_WAKEUP1, "wakeup1"),
+ PINCTRL_PIN(WMT_PIN_WAKEUP2, "wakeup2"),
+ PINCTRL_PIN(WMT_PIN_WAKEUP3, "wakeup3"),
+ PINCTRL_PIN(WMT_PIN_SUSGPIO0, "susgpio0"),
+ PINCTRL_PIN(WMT_PIN_SUSGPIO1, "susgpio1"),
+ PINCTRL_PIN(WMT_PIN_SD0CD, "sd0_cd"),
+ PINCTRL_PIN(WMT_PIN_VDOUT0, "vdout0"),
+ PINCTRL_PIN(WMT_PIN_VDOUT1, "vdout1"),
+ PINCTRL_PIN(WMT_PIN_VDOUT2, "vdout2"),
+ PINCTRL_PIN(WMT_PIN_VDOUT3, "vdout3"),
+ PINCTRL_PIN(WMT_PIN_VDOUT4, "vdout4"),
+ PINCTRL_PIN(WMT_PIN_VDOUT5, "vdout5"),
+ PINCTRL_PIN(WMT_PIN_VDOUT6, "vdout6"),
+ PINCTRL_PIN(WMT_PIN_VDOUT7, "vdout7"),
+ PINCTRL_PIN(WMT_PIN_VDOUT8, "vdout8"),
+ PINCTRL_PIN(WMT_PIN_VDOUT9, "vdout9"),
+ PINCTRL_PIN(WMT_PIN_VDOUT10, "vdout10"),
+ PINCTRL_PIN(WMT_PIN_VDOUT11, "vdout11"),
+ PINCTRL_PIN(WMT_PIN_VDOUT12, "vdout12"),
+ PINCTRL_PIN(WMT_PIN_VDOUT13, "vdout13"),
+ PINCTRL_PIN(WMT_PIN_VDOUT14, "vdout14"),
+ PINCTRL_PIN(WMT_PIN_VDOUT15, "vdout15"),
+ PINCTRL_PIN(WMT_PIN_VDOUT16, "vdout16"),
+ PINCTRL_PIN(WMT_PIN_VDOUT17, "vdout17"),
+ PINCTRL_PIN(WMT_PIN_VDOUT18, "vdout18"),
+ PINCTRL_PIN(WMT_PIN_VDOUT19, "vdout19"),
+ PINCTRL_PIN(WMT_PIN_VDOUT20, "vdout20"),
+ PINCTRL_PIN(WMT_PIN_VDOUT21, "vdout21"),
+ PINCTRL_PIN(WMT_PIN_VDOUT22, "vdout22"),
+ PINCTRL_PIN(WMT_PIN_VDOUT23, "vdout23"),
+ PINCTRL_PIN(WMT_PIN_VDIN0, "vdin0"),
+ PINCTRL_PIN(WMT_PIN_VDIN1, "vdin1"),
+ PINCTRL_PIN(WMT_PIN_VDIN2, "vdin2"),
+ PINCTRL_PIN(WMT_PIN_VDIN3, "vdin3"),
+ PINCTRL_PIN(WMT_PIN_VDIN4, "vdin4"),
+ PINCTRL_PIN(WMT_PIN_VDIN5, "vdin5"),
+ PINCTRL_PIN(WMT_PIN_VDIN6, "vdin6"),
+ PINCTRL_PIN(WMT_PIN_VDIN7, "vdin7"),
+ PINCTRL_PIN(WMT_PIN_SPI0_MOSI, "spi0_mosi"),
+ PINCTRL_PIN(WMT_PIN_SPI0_MISO, "spi0_miso"),
+ PINCTRL_PIN(WMT_PIN_SPI0_SS, "spi0_ss"),
+ PINCTRL_PIN(WMT_PIN_SPI0_CLK, "spi0_clk"),
+ PINCTRL_PIN(WMT_PIN_SPI0_SSB, "spi0_ssb"),
+ PINCTRL_PIN(WMT_PIN_SD0CLK, "sd0_clk"),
+ PINCTRL_PIN(WMT_PIN_SD0CMD, "sd0_cmd"),
+ PINCTRL_PIN(WMT_PIN_SD0WP, "sd0_wp"),
+ PINCTRL_PIN(WMT_PIN_SD0DATA0, "sd0_data0"),
+ PINCTRL_PIN(WMT_PIN_SD0DATA1, "sd0_data1"),
+ PINCTRL_PIN(WMT_PIN_SD0DATA2, "sd0_data2"),
+ PINCTRL_PIN(WMT_PIN_SD0DATA3, "sd0_data3"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA0, "sd1_data0"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA1, "sd1_data1"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA2, "sd1_data2"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA3, "sd1_data3"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA4, "sd1_data4"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA5, "sd1_data5"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA6, "sd1_data6"),
+ PINCTRL_PIN(WMT_PIN_SD1DATA7, "sd1_data7"),
+ PINCTRL_PIN(WMT_PIN_I2C0_SCL, "i2c0_scl"),
+ PINCTRL_PIN(WMT_PIN_I2C0_SDA, "i2c0_sda"),
+ PINCTRL_PIN(WMT_PIN_I2C1_SCL, "i2c1_scl"),
+ PINCTRL_PIN(WMT_PIN_I2C1_SDA, "i2c1_sda"),
+ PINCTRL_PIN(WMT_PIN_I2C2_SCL, "i2c2_scl"),
+ PINCTRL_PIN(WMT_PIN_I2C2_SDA, "i2c2_sda"),
+ PINCTRL_PIN(WMT_PIN_UART0_RTS, "uart0_rts"),
+ PINCTRL_PIN(WMT_PIN_UART0_TXD, "uart0_txd"),
+ PINCTRL_PIN(WMT_PIN_UART0_CTS, "uart0_cts"),
+ PINCTRL_PIN(WMT_PIN_UART0_RXD, "uart0_rxd"),
+ PINCTRL_PIN(WMT_PIN_UART1_RTS, "uart1_rts"),
+ PINCTRL_PIN(WMT_PIN_UART1_TXD, "uart1_txd"),
+ PINCTRL_PIN(WMT_PIN_UART1_CTS, "uart1_cts"),
+ PINCTRL_PIN(WMT_PIN_UART1_RXD, "uart1_rxd"),
+ PINCTRL_PIN(WMT_PIN_UART2_RTS, "uart2_rts"),
+ PINCTRL_PIN(WMT_PIN_UART2_TXD, "uart2_txd"),
+ PINCTRL_PIN(WMT_PIN_UART2_CTS, "uart2_cts"),
+ PINCTRL_PIN(WMT_PIN_UART2_RXD, "uart2_rxd"),
+ PINCTRL_PIN(WMT_PIN_SD2WP, "sd2_wp"),
+ PINCTRL_PIN(WMT_PIN_SD2CMD, "sd2_cmd"),
+ PINCTRL_PIN(WMT_PIN_SD2CLK, "sd2_clk"),
+ PINCTRL_PIN(WMT_PIN_SD2PWR, "sd2_pwr"),
+ PINCTRL_PIN(WMT_PIN_SD1CLK, "sd1_clk"),
+ PINCTRL_PIN(WMT_PIN_SD1CMD, "sd1_cmd"),
+ PINCTRL_PIN(WMT_PIN_SD1PWR, "sd1_pwr"),
+ PINCTRL_PIN(WMT_PIN_SD1WP, "sd1_wp"),
+ PINCTRL_PIN(WMT_PIN_SD1CD, "sd1_cd"),
+ PINCTRL_PIN(WMT_PIN_PWMOUT1, "pwmout1"),
+ PINCTRL_PIN(WMT_PIN_PWMOUT0, "pwmout0"),
+};
+
+/* Order of these names must match the above list */
+static const char * const wm8850_groups[] = {
+ "extgpio0",
+ "extgpio1",
+ "extgpio2",
+ "extgpio3",
+ "extgpio4",
+ "extgpio5",
+ "extgpio6",
+ "extgpio7",
+ "wakeup0",
+ "wakeup1",
+ "wakeup2",
+ "wakeup3",
+ "susgpio0",
+ "susgpio1",
+ "sd0_cd",
+ "vdout0",
+ "vdout1",
+ "vdout2",
+ "vdout3",
+ "vdout4",
+ "vdout5",
+ "vdout6",
+ "vdout7",
+ "vdout8",
+ "vdout9",
+ "vdout10",
+ "vdout11",
+ "vdout12",
+ "vdout13",
+ "vdout14",
+ "vdout15",
+ "vdout16",
+ "vdout17",
+ "vdout18",
+ "vdout19",
+ "vdout20",
+ "vdout21",
+ "vdout22",
+ "vdout23",
+ "vdin0",
+ "vdin1",
+ "vdin2",
+ "vdin3",
+ "vdin4",
+ "vdin5",
+ "vdin6",
+ "vdin7",
+ "spi0_mosi",
+ "spi0_miso",
+ "spi0_ss",
+ "spi0_clk",
+ "spi0_ssb",
+ "sd0_clk",
+ "sd0_cmd",
+ "sd0_wp",
+ "sd0_data0",
+ "sd0_data1",
+ "sd0_data2",
+ "sd0_data3",
+ "sd1_data0",
+ "sd1_data1",
+ "sd1_data2",
+ "sd1_data3",
+ "sd1_data4",
+ "sd1_data5",
+ "sd1_data6",
+ "sd1_data7",
+ "i2c0_scl",
+ "i2c0_sda",
+ "i2c1_scl",
+ "i2c1_sda",
+ "i2c2_scl",
+ "i2c2_sda",
+ "uart0_rts",
+ "uart0_txd",
+ "uart0_cts",
+ "uart0_rxd",
+ "uart1_rts",
+ "uart1_txd",
+ "uart1_cts",
+ "uart1_rxd",
+ "uart2_rts",
+ "uart2_txd",
+ "uart2_cts",
+ "uart2_rxd",
+ "sd2_wp",
+ "sd2_cmd",
+ "sd2_clk",
+ "sd2_pwr",
+ "sd1_clk",
+ "sd1_cmd",
+ "sd1_pwr",
+ "sd1_wp",
+ "sd1_cd",
+ "pwmout1",
+ "pwmout0",
+};
+
+static int wm8850_pinctrl_probe(struct platform_device *pdev)
+{
+ struct wmt_pinctrl_data *data;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ dev_err(&pdev->dev, "failed to allocate data\n");
+ return -ENOMEM;
+ }
+
+ data->banks = wm8850_banks;
+ data->nbanks = ARRAY_SIZE(wm8850_banks);
+ data->pins = wm8850_pins;
+ data->npins = ARRAY_SIZE(wm8850_pins);
+ data->groups = wm8850_groups;
+ data->ngroups = ARRAY_SIZE(wm8850_groups);
+
+ return wmt_pinctrl_probe(pdev, data);
+}
+
+static int wm8850_pinctrl_remove(struct platform_device *pdev)
+{
+ return wmt_pinctrl_remove(pdev);
+}
+
+static struct of_device_id wmt_pinctrl_of_match[] = {
+ { .compatible = "wm,wm8850-pinctrl" },
+ { /* sentinel */ },
+};
+
+static struct platform_driver wmt_pinctrl_driver = {
+ .probe = wm8850_pinctrl_probe,
+ .remove = wm8850_pinctrl_remove,
+ .driver = {
+ .name = "pinctrl-wm8850",
+ .owner = THIS_MODULE,
+ .of_match_table = wmt_pinctrl_of_match,
+ },
+};
+
+module_platform_driver(wmt_pinctrl_driver);
+
+MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
+MODULE_DESCRIPTION("Wondermedia WM8850 Pincontrol driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, wmt_pinctrl_of_match);
diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.c b/drivers/pinctrl/vt8500/pinctrl-wmt.c
new file mode 100644
index 000000000000..ab63104e8dc9
--- /dev/null
+++ b/drivers/pinctrl/vt8500/pinctrl-wmt.c
@@ -0,0 +1,632 @@
+/*
+ * Pinctrl driver for the Wondermedia SoC's
+ *
+ * Copyright (c) 2013 Tony Prisk <linux@prisktech.co.nz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "pinctrl-wmt.h"
+
+static inline void wmt_setbits(struct wmt_pinctrl_data *data, u32 reg,
+ u32 mask)
+{
+ u32 val;
+
+ val = readl_relaxed(data->base + reg);
+ val |= mask;
+ writel_relaxed(val, data->base + reg);
+}
+
+static inline void wmt_clearbits(struct wmt_pinctrl_data *data, u32 reg,
+ u32 mask)
+{
+ u32 val;
+
+ val = readl_relaxed(data->base + reg);
+ val &= ~mask;
+ writel_relaxed(val, data->base + reg);
+}
+
+enum wmt_func_sel {
+ WMT_FSEL_GPIO_IN = 0,
+ WMT_FSEL_GPIO_OUT = 1,
+ WMT_FSEL_ALT = 2,
+ WMT_FSEL_COUNT = 3,
+};
+
+static const char * const wmt_functions[WMT_FSEL_COUNT] = {
+ [WMT_FSEL_GPIO_IN] = "gpio_in",
+ [WMT_FSEL_GPIO_OUT] = "gpio_out",
+ [WMT_FSEL_ALT] = "alt",
+};
+
+static int wmt_pmx_get_functions_count(struct pinctrl_dev *pctldev)
+{
+ return WMT_FSEL_COUNT;
+}
+
+static const char *wmt_pmx_get_function_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ return wmt_functions[selector];
+}
+
+static int wmt_pmx_get_function_groups(struct pinctrl_dev *pctldev,
+ unsigned selector,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev);
+
+ /* every pin does every function */
+ *groups = data->groups;
+ *num_groups = data->ngroups;
+
+ return 0;
+}
+
+static int wmt_set_pinmux(struct wmt_pinctrl_data *data, unsigned func,
+ unsigned pin)
+{
+ u32 bank = WMT_BANK_FROM_PIN(pin);
+ u32 bit = WMT_BIT_FROM_PIN(pin);
+ u32 reg_en = data->banks[bank].reg_en;
+ u32 reg_dir = data->banks[bank].reg_dir;
+
+ if (reg_dir == NO_REG) {
+ dev_err(data->dev, "pin:%d no direction register defined\n",
+ pin);
+ return -EINVAL;
+ }
+
+ /*
+ * If reg_en == NO_REG, we assume it is a dedicated GPIO and cannot be
+ * disabled (as on VT8500) and that no alternate function is available.
+ */
+ switch (func) {
+ case WMT_FSEL_GPIO_IN:
+ if (reg_en != NO_REG)
+ wmt_setbits(data, reg_en, BIT(bit));
+ wmt_clearbits(data, reg_dir, BIT(bit));
+ break;
+ case WMT_FSEL_GPIO_OUT:
+ if (reg_en != NO_REG)
+ wmt_setbits(data, reg_en, BIT(bit));
+ wmt_setbits(data, reg_dir, BIT(bit));
+ break;
+ case WMT_FSEL_ALT:
+ if (reg_en == NO_REG) {
+ dev_err(data->dev, "pin:%d no alt function available\n",
+ pin);
+ return -EINVAL;
+ }
+ wmt_clearbits(data, reg_en, BIT(bit));
+ }
+
+ return 0;
+}
+
+static int wmt_pmx_enable(struct pinctrl_dev *pctldev,
+ unsigned func_selector,
+ unsigned group_selector)
+{
+ struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev);
+ u32 pinnum = data->pins[group_selector].number;
+
+ return wmt_set_pinmux(data, func_selector, pinnum);
+}
+
+static void wmt_pmx_disable(struct pinctrl_dev *pctldev,
+ unsigned func_selector,
+ unsigned group_selector)
+{
+ struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev);
+ u32 pinnum = data->pins[group_selector].number;
+
+ /* disable by setting GPIO_IN */
+ wmt_set_pinmux(data, WMT_FSEL_GPIO_IN, pinnum);
+}
+
+static void wmt_pmx_gpio_disable_free(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
+{
+ struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev);
+
+ /* disable by setting GPIO_IN */
+ wmt_set_pinmux(data, WMT_FSEL_GPIO_IN, offset);
+}
+
+static int wmt_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset,
+ bool input)
+{
+ struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev);
+
+ wmt_set_pinmux(data, (input ? WMT_FSEL_GPIO_IN : WMT_FSEL_GPIO_OUT),
+ offset);
+
+ return 0;
+}
+
+static struct pinmux_ops wmt_pinmux_ops = {
+ .get_functions_count = wmt_pmx_get_functions_count,
+ .get_function_name = wmt_pmx_get_function_name,
+ .get_function_groups = wmt_pmx_get_function_groups,
+ .enable = wmt_pmx_enable,
+ .disable = wmt_pmx_disable,
+ .gpio_disable_free = wmt_pmx_gpio_disable_free,
+ .gpio_set_direction = wmt_pmx_gpio_set_direction,
+};
+
+static int wmt_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev);
+
+ return data->ngroups;
+}
+
+static const char *wmt_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev);
+
+ return data->groups[selector];
+}
+
+static int wmt_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned selector,
+ const unsigned **pins,
+ unsigned *num_pins)
+{
+ struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev);
+
+ *pins = &data->pins[selector].number;
+ *num_pins = 1;
+
+ return 0;
+}
+
+static int wmt_pctl_find_group_by_pin(struct wmt_pinctrl_data *data, u32 pin)
+{
+ int i;
+
+ for (i = 0; i < data->npins; i++) {
+ if (data->pins[i].number == pin)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static int wmt_pctl_dt_node_to_map_func(struct wmt_pinctrl_data *data,
+ struct device_node *np,
+ u32 pin, u32 fnum,
+ struct pinctrl_map **maps)
+{
+ int group;
+ struct pinctrl_map *map = *maps;
+
+ if (fnum >= ARRAY_SIZE(wmt_functions)) {
+ dev_err(data->dev, "invalid wm,function %d\n", fnum);
+ return -EINVAL;
+ }
+
+ group = wmt_pctl_find_group_by_pin(data, pin);
+ if (group < 0) {
+ dev_err(data->dev, "unable to match pin %d to group\n", pin);
+ return group;
+ }
+
+ map->type = PIN_MAP_TYPE_MUX_GROUP;
+ map->data.mux.group = data->groups[group];
+ map->data.mux.function = wmt_functions[fnum];
+ (*maps)++;
+
+ return 0;
+}
+
+static int wmt_pctl_dt_node_to_map_pull(struct wmt_pinctrl_data *data,
+ struct device_node *np,
+ u32 pin, u32 pull,
+ struct pinctrl_map **maps)
+{
+ int group;
+ unsigned long *configs;
+ struct pinctrl_map *map = *maps;
+
+ if (pull > 2) {
+ dev_err(data->dev, "invalid wm,pull %d\n", pull);
+ return -EINVAL;
+ }
+
+ group = wmt_pctl_find_group_by_pin(data, pin);
+ if (group < 0) {
+ dev_err(data->dev, "unable to match pin %d to group\n", pin);
+ return group;
+ }
+
+ configs = kzalloc(sizeof(*configs), GFP_KERNEL);
+ if (!configs)
+ return -ENOMEM;
+
+ configs[0] = pull;
+
+ map->type = PIN_MAP_TYPE_CONFIGS_PIN;
+ map->data.configs.group_or_pin = data->groups[group];
+ map->data.configs.configs = configs;
+ map->data.configs.num_configs = 1;
+ (*maps)++;
+
+ return 0;
+}
+
+static void wmt_pctl_dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *maps,
+ unsigned num_maps)
+{
+ int i;
+
+ for (i = 0; i < num_maps; i++)
+ if (maps[i].type == PIN_MAP_TYPE_CONFIGS_PIN)
+ kfree(maps[i].data.configs.configs);
+
+ kfree(maps);
+}
+
+static int wmt_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np,
+ struct pinctrl_map **map,
+ unsigned *num_maps)
+{
+ struct pinctrl_map *maps, *cur_map;
+ struct property *pins, *funcs, *pulls;
+ u32 pin, func, pull;
+ int num_pins, num_funcs, num_pulls, maps_per_pin;
+ int i, err;
+ struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev);
+
+ pins = of_find_property(np, "wm,pins", NULL);
+ if (!pins) {
+ dev_err(data->dev, "missing wmt,pins property\n");
+ return -EINVAL;
+ }
+
+ funcs = of_find_property(np, "wm,function", NULL);
+ pulls = of_find_property(np, "wm,pull", NULL);
+
+ if (!funcs && !pulls) {
+ dev_err(data->dev, "neither wm,function nor wm,pull specified\n");
+ return -EINVAL;
+ }
+
+ /*
+ * The following lines calculate how many values are defined for each
+ * of the properties.
+ */
+ num_pins = pins->length / sizeof(u32);
+ num_funcs = funcs ? (funcs->length / sizeof(u32)) : 0;
+ num_pulls = pulls ? (pulls->length / sizeof(u32)) : 0;
+
+ if (num_funcs > 1 && num_funcs != num_pins) {
+ dev_err(data->dev, "wm,function must have 1 or %d entries\n",
+ num_pins);
+ return -EINVAL;
+ }
+
+ if (num_pulls > 1 && num_pulls != num_pins) {
+ dev_err(data->dev, "wm,pull must have 1 or %d entries\n",
+ num_pins);
+ return -EINVAL;
+ }
+
+ maps_per_pin = 0;
+ if (num_funcs)
+ maps_per_pin++;
+ if (num_pulls)
+ maps_per_pin++;
+
+ cur_map = maps = kzalloc(num_pins * maps_per_pin * sizeof(*maps),
+ GFP_KERNEL);
+ if (!maps)
+ return -ENOMEM;
+
+ for (i = 0; i < num_pins; i++) {
+ err = of_property_read_u32_index(np, "wm,pins", i, &pin);
+ if (err)
+ goto fail;
+
+ if (pin >= (data->nbanks * 32)) {
+ dev_err(data->dev, "invalid wm,pins value\n");
+ err = -EINVAL;
+ goto fail;
+ }
+
+ if (num_funcs) {
+ err = of_property_read_u32_index(np, "wm,function",
+ (num_funcs > 1 ? i : 0), &func);
+ if (err)
+ goto fail;
+
+ err = wmt_pctl_dt_node_to_map_func(data, np, pin, func,
+ &cur_map);
+ if (err)
+ goto fail;
+ }
+
+ if (num_pulls) {
+ err = of_property_read_u32_index(np, "wm,pull",
+ (num_pulls > 1 ? i : 0), &pull);
+ if (err)
+ goto fail;
+
+ err = wmt_pctl_dt_node_to_map_pull(data, np, pin, pull,
+ &cur_map);
+ if (err)
+ goto fail;
+ }
+ }
+ *map = maps;
+ *num_maps = num_pins * maps_per_pin;
+ return 0;
+
+/*
+ * The fail path removes any maps that have been allocated. The fail path is
+ * only called from code after maps has been kzalloc'd. It is also safe to
+ * pass 'num_pins * maps_per_pin' as the map count even though we probably
+ * failed before all the mappings were read as all maps are allocated at once,
+ * and configs are only allocated for .type = PIN_MAP_TYPE_CONFIGS_PIN - there
+ * is no failpath where a config can be allocated without .type being set.
+ */
+fail:
+ wmt_pctl_dt_free_map(pctldev, maps, num_pins * maps_per_pin);
+ return err;
+}
+
+static struct pinctrl_ops wmt_pctl_ops = {
+ .get_groups_count = wmt_get_groups_count,
+ .get_group_name = wmt_get_group_name,
+ .get_group_pins = wmt_get_group_pins,
+ .dt_node_to_map = wmt_pctl_dt_node_to_map,
+ .dt_free_map = wmt_pctl_dt_free_map,
+};
+
+static int wmt_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long *config)
+{
+ return -ENOTSUPP;
+}
+
+static int wmt_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long config)
+{
+ struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev);
+ enum pin_config_param param = pinconf_to_config_param(config);
+ u16 arg = pinconf_to_config_argument(config);
+ u32 bank = WMT_BANK_FROM_PIN(pin);
+ u32 bit = WMT_BIT_FROM_PIN(pin);
+ u32 reg_pull_en = data->banks[bank].reg_pull_en;
+ u32 reg_pull_cfg = data->banks[bank].reg_pull_cfg;
+
+ if ((reg_pull_en == NO_REG) || (reg_pull_cfg == NO_REG)) {
+ dev_err(data->dev, "bias functions not supported on pin %d\n",
+ pin);
+ return -EINVAL;
+ }
+
+ if ((param == PIN_CONFIG_BIAS_PULL_DOWN) ||
+ (param == PIN_CONFIG_BIAS_PULL_UP)) {
+ if (arg == 0)
+ param = PIN_CONFIG_BIAS_DISABLE;
+ }
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ wmt_clearbits(data, reg_pull_en, BIT(bit));
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ wmt_clearbits(data, reg_pull_cfg, BIT(bit));
+ wmt_setbits(data, reg_pull_en, BIT(bit));
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ wmt_setbits(data, reg_pull_cfg, BIT(bit));
+ wmt_setbits(data, reg_pull_en, BIT(bit));
+ break;
+ default:
+ dev_err(data->dev, "unknown pinconf param\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct pinconf_ops wmt_pinconf_ops = {
+ .pin_config_get = wmt_pinconf_get,
+ .pin_config_set = wmt_pinconf_set,
+};
+
+static struct pinctrl_desc wmt_desc = {
+ .owner = THIS_MODULE,
+ .name = "pinctrl-wmt",
+ .pctlops = &wmt_pctl_ops,
+ .pmxops = &wmt_pinmux_ops,
+ .confops = &wmt_pinconf_ops,
+};
+
+static int wmt_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ return pinctrl_request_gpio(chip->base + offset);
+}
+
+static void wmt_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ pinctrl_free_gpio(chip->base + offset);
+}
+
+static int wmt_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+ struct wmt_pinctrl_data *data = dev_get_drvdata(chip->dev);
+ u32 bank = WMT_BANK_FROM_PIN(offset);
+ u32 bit = WMT_BIT_FROM_PIN(offset);
+ u32 reg_dir = data->banks[bank].reg_dir;
+ u32 val;
+
+ val = readl_relaxed(data->base + reg_dir);
+ if (val & BIT(bit))
+ return GPIOF_DIR_OUT;
+ else
+ return GPIOF_DIR_IN;
+}
+
+static int wmt_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ return pinctrl_gpio_direction_input(chip->base + offset);
+}
+
+static int wmt_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ return pinctrl_gpio_direction_output(chip->base + offset);
+}
+
+static int wmt_gpio_get_value(struct gpio_chip *chip, unsigned offset)
+{
+ struct wmt_pinctrl_data *data = dev_get_drvdata(chip->dev);
+ u32 bank = WMT_BANK_FROM_PIN(offset);
+ u32 bit = WMT_BIT_FROM_PIN(offset);
+ u32 reg_data_in = data->banks[bank].reg_data_in;
+
+ if (reg_data_in == NO_REG) {
+ dev_err(data->dev, "no data in register defined\n");
+ return -EINVAL;
+ }
+
+ return !!(readl_relaxed(data->base + reg_data_in) & BIT(bit));
+}
+
+static void wmt_gpio_set_value(struct gpio_chip *chip, unsigned offset,
+ int val)
+{
+ struct wmt_pinctrl_data *data = dev_get_drvdata(chip->dev);
+ u32 bank = WMT_BANK_FROM_PIN(offset);
+ u32 bit = WMT_BIT_FROM_PIN(offset);
+ u32 reg_data_out = data->banks[bank].reg_data_out;
+
+ if (reg_data_out == NO_REG) {
+ dev_err(data->dev, "no data out register defined\n");
+ return;
+ }
+
+ if (val)
+ wmt_setbits(data, reg_data_out, BIT(bit));
+ else
+ wmt_clearbits(data, reg_data_out, BIT(bit));
+}
+
+static struct gpio_chip wmt_gpio_chip = {
+ .label = "gpio-wmt",
+ .owner = THIS_MODULE,
+ .request = wmt_gpio_request,
+ .free = wmt_gpio_free,
+ .get_direction = wmt_gpio_get_direction,
+ .direction_input = wmt_gpio_direction_input,
+ .direction_output = wmt_gpio_direction_output,
+ .get = wmt_gpio_get_value,
+ .set = wmt_gpio_set_value,
+ .can_sleep = 0,
+};
+
+int wmt_pinctrl_probe(struct platform_device *pdev,
+ struct wmt_pinctrl_data *data)
+{
+ int err;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ data->base = devm_request_and_ioremap(&pdev->dev, res);
+ if (!data->base) {
+ dev_err(&pdev->dev, "failed to map memory resource\n");
+ return -EBUSY;
+ }
+
+ wmt_desc.pins = data->pins;
+ wmt_desc.npins = data->npins;
+
+ data->gpio_chip = wmt_gpio_chip;
+ data->gpio_chip.dev = &pdev->dev;
+ data->gpio_chip.of_node = pdev->dev.of_node;
+ data->gpio_chip.ngpio = data->nbanks * 32;
+
+ platform_set_drvdata(pdev, data);
+
+ data->dev = &pdev->dev;
+
+ data->pctl_dev = pinctrl_register(&wmt_desc, &pdev->dev, data);
+ if (!data->pctl_dev) {
+ dev_err(&pdev->dev, "Failed to register pinctrl\n");
+ return -EINVAL;
+ }
+
+ err = gpiochip_add(&data->gpio_chip);
+ if (err) {
+ dev_err(&pdev->dev, "could not add GPIO chip\n");
+ goto fail_gpio;
+ }
+
+ err = gpiochip_add_pin_range(&data->gpio_chip, dev_name(data->dev),
+ 0, 0, data->nbanks * 32);
+ if (err)
+ goto fail_range;
+
+ dev_info(&pdev->dev, "Pin controller initialized\n");
+
+ return 0;
+
+fail_range:
+ err = gpiochip_remove(&data->gpio_chip);
+ if (err)
+ dev_err(&pdev->dev, "failed to remove gpio chip\n");
+fail_gpio:
+ pinctrl_unregister(data->pctl_dev);
+ return err;
+}
+
+int wmt_pinctrl_remove(struct platform_device *pdev)
+{
+ struct wmt_pinctrl_data *data = platform_get_drvdata(pdev);
+ int err;
+
+ err = gpiochip_remove(&data->gpio_chip);
+ if (err)
+ dev_err(&pdev->dev, "failed to remove gpio chip\n");
+
+ pinctrl_unregister(data->pctl_dev);
+
+ return 0;
+}
diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.h b/drivers/pinctrl/vt8500/pinctrl-wmt.h
new file mode 100644
index 000000000000..41f5f2deb5d6
--- /dev/null
+++ b/drivers/pinctrl/vt8500/pinctrl-wmt.h
@@ -0,0 +1,79 @@
+/*
+ * Pinctrl driver for the Wondermedia SoC's
+ *
+ * Copyright (c) 2013 Tony Prisk <linux@prisktech.co.nz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/gpio.h>
+
+/* VT8500 has no enable register in the extgpio bank. */
+#define NO_REG 0xFFFF
+
+#define WMT_PINCTRL_BANK(__en, __dir, __dout, __din, __pen, __pcfg) \
+{ \
+ .reg_en = __en, \
+ .reg_dir = __dir, \
+ .reg_data_out = __dout, \
+ .reg_data_in = __din, \
+ .reg_pull_en = __pen, \
+ .reg_pull_cfg = __pcfg, \
+}
+
+/* Encode/decode the bank/bit pairs into a pin value */
+#define WMT_PIN(__bank, __offset) ((__bank << 5) | __offset)
+#define WMT_BANK_FROM_PIN(__pin) (__pin >> 5)
+#define WMT_BIT_FROM_PIN(__pin) (__pin & 0x1f)
+
+#define WMT_GROUP(__name, __data) \
+{ \
+ .name = __name, \
+ .pins = __data, \
+ .npins = ARRAY_SIZE(__data), \
+}
+
+struct wmt_pinctrl_bank_registers {
+ u32 reg_en;
+ u32 reg_dir;
+ u32 reg_data_out;
+ u32 reg_data_in;
+
+ u32 reg_pull_en;
+ u32 reg_pull_cfg;
+};
+
+struct wmt_pinctrl_group {
+ const char *name;
+ const unsigned int *pins;
+ const unsigned npins;
+};
+
+struct wmt_pinctrl_data {
+ struct device *dev;
+ struct pinctrl_dev *pctl_dev;
+
+ /* must be initialized before calling wmt_pinctrl_probe */
+ void __iomem *base;
+ const struct wmt_pinctrl_bank_registers *banks;
+ const struct pinctrl_pin_desc *pins;
+ const char * const *groups;
+
+ u32 nbanks;
+ u32 npins;
+ u32 ngroups;
+
+ struct gpio_chip gpio_chip;
+ struct pinctrl_gpio_range gpio_range;
+};
+
+int wmt_pinctrl_probe(struct platform_device *pdev,
+ struct wmt_pinctrl_data *data);
+int wmt_pinctrl_remove(struct platform_device *pdev);
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
new file mode 100644
index 000000000000..c9d04f797862
--- /dev/null
+++ b/drivers/reset/Kconfig
@@ -0,0 +1,13 @@
+config ARCH_HAS_RESET_CONTROLLER
+ bool
+
+menuconfig RESET_CONTROLLER
+ bool "Reset Controller Support"
+ default y if ARCH_HAS_RESET_CONTROLLER
+ help
+ Generic Reset Controller support.
+
+ This framework is designed to abstract reset handling of devices
+ via GPIOs or SoC-internal reset controller modules.
+
+ If unsure, say no.
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
new file mode 100644
index 000000000000..1e2d83f2b995
--- /dev/null
+++ b/drivers/reset/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_RESET_CONTROLLER) += core.o
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
new file mode 100644
index 000000000000..d1b6089a0ef8
--- /dev/null
+++ b/drivers/reset/core.c
@@ -0,0 +1,297 @@
+/*
+ * Reset Controller framework
+ *
+ * Copyright 2013 Philipp Zabel, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/reset.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+
+static DEFINE_MUTEX(reset_controller_list_mutex);
+static LIST_HEAD(reset_controller_list);
+
+/**
+ * struct reset_control - a reset control
+ * @rcdev: a pointer to the reset controller device
+ * this reset control belongs to
+ * @id: ID of the reset controller in the reset
+ * controller device
+ */
+struct reset_control {
+ struct reset_controller_dev *rcdev;
+ struct device *dev;
+ unsigned int id;
+};
+
+/**
+ * of_reset_simple_xlate - translate reset_spec to the reset line number
+ * @rcdev: a pointer to the reset controller device
+ * @reset_spec: reset line specifier as found in the device tree
+ * @flags: a flags pointer to fill in (optional)
+ *
+ * This simple translation function should be used for reset controllers
+ * with 1:1 mapping, where reset lines can be indexed by number without gaps.
+ */
+int of_reset_simple_xlate(struct reset_controller_dev *rcdev,
+ const struct of_phandle_args *reset_spec)
+{
+ if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells))
+ return -EINVAL;
+
+ if (reset_spec->args[0] >= rcdev->nr_resets)
+ return -EINVAL;
+
+ return reset_spec->args[0];
+}
+EXPORT_SYMBOL_GPL(of_reset_simple_xlate);
+
+/**
+ * reset_controller_register - register a reset controller device
+ * @rcdev: a pointer to the initialized reset controller device
+ */
+int reset_controller_register(struct reset_controller_dev *rcdev)
+{
+ if (!rcdev->of_xlate) {
+ rcdev->of_reset_n_cells = 1;
+ rcdev->of_xlate = of_reset_simple_xlate;
+ }
+
+ mutex_lock(&reset_controller_list_mutex);
+ list_add(&rcdev->list, &reset_controller_list);
+ mutex_unlock(&reset_controller_list_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(reset_controller_register);
+
+/**
+ * reset_controller_unregister - unregister a reset controller device
+ * @rcdev: a pointer to the reset controller device
+ */
+void reset_controller_unregister(struct reset_controller_dev *rcdev)
+{
+ mutex_lock(&reset_controller_list_mutex);
+ list_del(&rcdev->list);
+ mutex_unlock(&reset_controller_list_mutex);
+}
+EXPORT_SYMBOL_GPL(reset_controller_unregister);
+
+/**
+ * reset_control_reset - reset the controlled device
+ * @rstc: reset controller
+ */
+int reset_control_reset(struct reset_control *rstc)
+{
+ if (rstc->rcdev->ops->reset)
+ return rstc->rcdev->ops->reset(rstc->rcdev, rstc->id);
+
+ return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(reset_control_reset);
+
+/**
+ * reset_control_assert - asserts the reset line
+ * @rstc: reset controller
+ */
+int reset_control_assert(struct reset_control *rstc)
+{
+ if (rstc->rcdev->ops->assert)
+ return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id);
+
+ return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(reset_control_assert);
+
+/**
+ * reset_control_deassert - deasserts the reset line
+ * @rstc: reset controller
+ */
+int reset_control_deassert(struct reset_control *rstc)
+{
+ if (rstc->rcdev->ops->deassert)
+ return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
+
+ return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(reset_control_deassert);
+
+/**
+ * reset_control_get - Lookup and obtain a reference to a reset controller.
+ * @dev: device to be reset by the controller
+ * @id: reset line name
+ *
+ * Returns a struct reset_control or IS_ERR() condition containing errno.
+ *
+ * Use of id names is optional.
+ */
+struct reset_control *reset_control_get(struct device *dev, const char *id)
+{
+ struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
+ struct reset_controller_dev *r, *rcdev;
+ struct of_phandle_args args;
+ int index = 0;
+ int rstc_id;
+ int ret;
+
+ if (!dev)
+ return ERR_PTR(-EINVAL);
+
+ if (id)
+ index = of_property_match_string(dev->of_node,
+ "reset-names", id);
+ ret = of_parse_phandle_with_args(dev->of_node, "resets", "#reset-cells",
+ index, &args);
+ if (ret)
+ return ERR_PTR(ret);
+
+ mutex_lock(&reset_controller_list_mutex);
+ rcdev = NULL;
+ list_for_each_entry(r, &reset_controller_list, list) {
+ if (args.np == r->of_node) {
+ rcdev = r;
+ break;
+ }
+ }
+ of_node_put(args.np);
+
+ if (!rcdev) {
+ mutex_unlock(&reset_controller_list_mutex);
+ return ERR_PTR(-ENODEV);
+ }
+
+ rstc_id = rcdev->of_xlate(rcdev, &args);
+ if (rstc_id < 0) {
+ mutex_unlock(&reset_controller_list_mutex);
+ return ERR_PTR(rstc_id);
+ }
+
+ try_module_get(rcdev->owner);
+ mutex_unlock(&reset_controller_list_mutex);
+
+ rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
+ if (!rstc) {
+ module_put(rcdev->owner);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ rstc->dev = dev;
+ rstc->rcdev = rcdev;
+ rstc->id = rstc_id;
+
+ return rstc;
+}
+EXPORT_SYMBOL_GPL(reset_control_get);
+
+/**
+ * reset_control_put - free the reset controller
+ * @rstc: reset controller
+ */
+
+void reset_control_put(struct reset_control *rstc)
+{
+ if (IS_ERR(rstc))
+ return;
+
+ module_put(rstc->rcdev->owner);
+ kfree(rstc);
+}
+EXPORT_SYMBOL_GPL(reset_control_put);
+
+static void devm_reset_control_release(struct device *dev, void *res)
+{
+ reset_control_put(*(struct reset_control **)res);
+}
+
+/**
+ * devm_reset_control_get - resource managed reset_control_get()
+ * @dev: device to be reset by the controller
+ * @id: reset line name
+ *
+ * Managed reset_control_get(). For reset controllers returned from this
+ * function, reset_control_put() is called automatically on driver detach.
+ * See reset_control_get() for more information.
+ */
+struct reset_control *devm_reset_control_get(struct device *dev, const char *id)
+{
+ struct reset_control **ptr, *rstc;
+
+ ptr = devres_alloc(devm_reset_control_release, sizeof(*ptr),
+ GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ rstc = reset_control_get(dev, id);
+ if (!IS_ERR(rstc)) {
+ *ptr = rstc;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return rstc;
+}
+EXPORT_SYMBOL_GPL(devm_reset_control_get);
+
+static int devm_reset_control_match(struct device *dev, void *res, void *data)
+{
+ struct reset_control **rstc = res;
+ if (WARN_ON(!rstc || !*rstc))
+ return 0;
+ return *rstc == data;
+}
+
+/**
+ * devm_reset_control_put - resource managed reset_control_put()
+ * @rstc: reset controller to free
+ *
+ * Deallocate a reset control allocated withd devm_reset_control_get().
+ * This function will not need to be called normally, as devres will take
+ * care of freeing the resource.
+ */
+void devm_reset_control_put(struct reset_control *rstc)
+{
+ int ret;
+
+ ret = devres_release(rstc->dev, devm_reset_control_release,
+ devm_reset_control_match, rstc);
+ if (ret)
+ WARN_ON(ret);
+}
+EXPORT_SYMBOL_GPL(devm_reset_control_put);
+
+/**
+ * device_reset - find reset controller associated with the device
+ * and perform reset
+ * @dev: device to be reset by the controller
+ *
+ * Convenience wrapper for reset_control_get() and reset_control_reset().
+ * This is useful for the common case of devices with single, dedicated reset
+ * lines.
+ */
+int device_reset(struct device *dev)
+{
+ struct reset_control *rstc;
+ int ret;
+
+ rstc = reset_control_get(dev, NULL);
+ if (IS_ERR(rstc))
+ return PTR_ERR(rstc);
+
+ ret = reset_control_reset(rstc);
+
+ reset_control_put(rstc);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(device_reset);
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 98348ec0b3ce..540909de6247 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -34,6 +34,77 @@
#define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */
#define ATMEL_LCDC_FIFO_SIZE 512 /* words */
+struct atmel_lcdfb_config {
+ bool have_alt_pixclock;
+ bool have_hozval;
+ bool have_intensity_bit;
+};
+
+static struct atmel_lcdfb_config at91sam9261_config = {
+ .have_hozval = true,
+ .have_intensity_bit = true,
+};
+
+static struct atmel_lcdfb_config at91sam9263_config = {
+ .have_intensity_bit = true,
+};
+
+static struct atmel_lcdfb_config at91sam9g10_config = {
+ .have_hozval = true,
+};
+
+static struct atmel_lcdfb_config at91sam9g45_config = {
+ .have_alt_pixclock = true,
+};
+
+static struct atmel_lcdfb_config at91sam9g45es_config = {
+};
+
+static struct atmel_lcdfb_config at91sam9rl_config = {
+ .have_intensity_bit = true,
+};
+
+static struct atmel_lcdfb_config at32ap_config = {
+ .have_hozval = true,
+};
+
+static const struct platform_device_id atmel_lcdfb_devtypes[] = {
+ {
+ .name = "at91sam9261-lcdfb",
+ .driver_data = (unsigned long)&at91sam9261_config,
+ }, {
+ .name = "at91sam9263-lcdfb",
+ .driver_data = (unsigned long)&at91sam9263_config,
+ }, {
+ .name = "at91sam9g10-lcdfb",
+ .driver_data = (unsigned long)&at91sam9g10_config,
+ }, {
+ .name = "at91sam9g45-lcdfb",
+ .driver_data = (unsigned long)&at91sam9g45_config,
+ }, {
+ .name = "at91sam9g45es-lcdfb",
+ .driver_data = (unsigned long)&at91sam9g45es_config,
+ }, {
+ .name = "at91sam9rl-lcdfb",
+ .driver_data = (unsigned long)&at91sam9rl_config,
+ }, {
+ .name = "at32ap-lcdfb",
+ .driver_data = (unsigned long)&at32ap_config,
+ }, {
+ /* terminator */
+ }
+};
+
+static struct atmel_lcdfb_config *
+atmel_lcdfb_get_config(struct platform_device *pdev)
+{
+ unsigned long data;
+
+ data = platform_get_device_id(pdev)->driver_data;
+
+ return (struct atmel_lcdfb_config *)data;
+}
+
#if defined(CONFIG_ARCH_AT91)
#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
| FBINFO_PARTIAL_PAN_OK \
@@ -193,14 +264,16 @@ static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
.accel = FB_ACCEL_NONE,
};
-static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
+static unsigned long compute_hozval(struct atmel_lcdfb_info *sinfo,
+ unsigned long xres)
{
+ unsigned long lcdcon2;
unsigned long value;
- if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10()
- || cpu_is_at32ap7000()))
+ if (!sinfo->config->have_hozval)
return xres;
+ lcdcon2 = lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2);
value = xres;
if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) {
/* STN display */
@@ -423,7 +496,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
break;
case 16:
/* Older SOCs use IBGR:555 rather than BGR:565. */
- if (sinfo->have_intensity_bit)
+ if (sinfo->config->have_intensity_bit)
var->green.length = 5;
else
var->green.length = 6;
@@ -531,7 +604,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
/* Now, the LCDC core... */
/* Set pixel clock */
- if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
+ if (sinfo->config->have_alt_pixclock)
pix_factor = 1;
clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
@@ -591,8 +664,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
/* Horizontal value (aka line size) */
- hozval_linesz = compute_hozval(info->var.xres,
- lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
+ hozval_linesz = compute_hozval(sinfo, info->var.xres);
/* Display size */
value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
@@ -684,7 +756,7 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
case FB_VISUAL_PSEUDOCOLOR:
if (regno < 256) {
- if (sinfo->have_intensity_bit) {
+ if (sinfo->config->have_intensity_bit) {
/* old style I+BGR:555 */
val = ((red >> 11) & 0x001f);
val |= ((green >> 6) & 0x03e0);
@@ -821,15 +893,13 @@ static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo)
static void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo)
{
- if (sinfo->bus_clk)
- clk_enable(sinfo->bus_clk);
+ clk_enable(sinfo->bus_clk);
clk_enable(sinfo->lcdc_clk);
}
static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo)
{
- if (sinfo->bus_clk)
- clk_disable(sinfo->bus_clk);
+ clk_disable(sinfo->bus_clk);
clk_disable(sinfo->lcdc_clk);
}
@@ -874,10 +944,9 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
}
sinfo->info = info;
sinfo->pdev = pdev;
- if (cpu_is_at91sam9261() || cpu_is_at91sam9263() ||
- cpu_is_at91sam9rl()) {
- sinfo->have_intensity_bit = true;
- }
+ sinfo->config = atmel_lcdfb_get_config(pdev);
+ if (!sinfo->config)
+ goto free_info;
strcpy(info->fix.id, sinfo->pdev->name);
info->flags = ATMEL_LCDFB_FBINFO_DEFAULT;
@@ -888,13 +957,10 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
info->fix = atmel_lcdfb_fix;
/* Enable LCDC Clocks */
- if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()
- || cpu_is_at32ap7000()) {
- sinfo->bus_clk = clk_get(dev, "hck1");
- if (IS_ERR(sinfo->bus_clk)) {
- ret = PTR_ERR(sinfo->bus_clk);
- goto free_info;
- }
+ sinfo->bus_clk = clk_get(dev, "hclk");
+ if (IS_ERR(sinfo->bus_clk)) {
+ ret = PTR_ERR(sinfo->bus_clk);
+ goto free_info;
}
sinfo->lcdc_clk = clk_get(dev, "lcdc_clk");
if (IS_ERR(sinfo->lcdc_clk)) {
@@ -1055,8 +1121,7 @@ stop_clk:
atmel_lcdfb_stop_clock(sinfo);
clk_put(sinfo->lcdc_clk);
put_bus_clk:
- if (sinfo->bus_clk)
- clk_put(sinfo->bus_clk);
+ clk_put(sinfo->bus_clk);
free_info:
framebuffer_release(info);
out:
@@ -1081,8 +1146,7 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
unregister_framebuffer(info);
atmel_lcdfb_stop_clock(sinfo);
clk_put(sinfo->lcdc_clk);
- if (sinfo->bus_clk)
- clk_put(sinfo->bus_clk);
+ clk_put(sinfo->bus_clk);
fb_dealloc_cmap(&info->cmap);
free_irq(sinfo->irq_base, info);
iounmap(sinfo->mmio);
@@ -1151,7 +1215,7 @@ static struct platform_driver atmel_lcdfb_driver = {
.remove = __exit_p(atmel_lcdfb_remove),
.suspend = atmel_lcdfb_suspend,
.resume = atmel_lcdfb_resume,
-
+ .id_table = atmel_lcdfb_devtypes,
.driver = {
.name = "atmel_lcdfb",
.owner = THIS_MODULE,