Merge branches 'clk-x86', 'clk-stm', 'clk-amlogic' and 'clk-allwinner' into clk-next
authorStephen Boyd <sboyd@kernel.org>
Wed, 12 Jan 2022 02:30:35 +0000 (18:30 -0800)
committerStephen Boyd <sboyd@kernel.org>
Wed, 12 Jan 2022 02:30:35 +0000 (18:30 -0800)
* clk-x86:
  clk: x86: Fix clk_gate_flags for RV_CLK_GATE
  clk: x86: Use dynamic con_id string during clk registration
  ACPI: APD: Add a fmw property clk-name
  drivers: acpi: acpi_apd: Remove unused device property "is-rv"
  x86: clk: clk-fch: Add support for newer family of AMD's SOC
  clk: Introduce clk-tps68470 driver
  platform/x86: int3472: Deal with probe ordering issues
  platform/x86: int3472: Pass tps68470_regulator_platform_data to the tps68470-regulator MFD-cell
  platform/x86: int3472: Pass tps68470_clk_platform_data to the tps68470-regulator MFD-cell
  platform/x86: int3472: Add get_sensor_adev_and_name() helper
  platform/x86: int3472: Split into 2 drivers
  platform_data: Add linux/platform_data/tps68470.h file
  i2c: acpi: Add i2c_acpi_new_device_by_fwnode() function
  i2c: acpi: Use acpi_dev_ready_for_enumeration() helper
  ACPI: delay enumeration of devices with a _DEP pointing to an INT3472 device

* clk-stm:
  clk: stm32: Fix ltdc's clock turn off by clk_disable_unused() after system enter shell

* clk-amlogic:
  clk: meson: gxbb: Fix the SDM_EN bit for MPLL0 on GXBB

* clk-allwinner:
  clk: sunxi-ng: Add support for the D1 SoC clocks
  clk: sunxi-ng: gate: Add macros for gates with fixed dividers
  clk: sunxi-ng: mux: Add macros using clk_parent_data and clk_hw
  clk: sunxi-ng: mp: Add macros using clk_parent_data and clk_hw
  clk: sunxi-ng: div: Add macros using clk_parent_data and clk_hw
  dt-bindings: clk: Add compatibles for D1 CCUs
  clk: sunxi-ng: Allow the CCU core to be built as a module
  clk: sunxi-ng: Convert early providers to platform drivers
  clk: sunxi-ng: Allow drivers to be built as modules
  clk: sunxi-ng: Export symbols used by CCU drivers

78 files changed:
Documentation/devicetree/bindings/clock/allwinner,sun4i-a10-ccu.yaml
drivers/acpi/acpi_apd.c
drivers/acpi/scan.c
drivers/clk/Kconfig
drivers/clk/Makefile
drivers/clk/clk-stm32f4.c
drivers/clk/clk-tps68470.c [new file with mode: 0644]
drivers/clk/meson/gxbb.c
drivers/clk/sunxi-ng/Kconfig
drivers/clk/sunxi-ng/Makefile
drivers/clk/sunxi-ng/ccu-sun20i-d1-r.c [new file with mode: 0644]
drivers/clk/sunxi-ng/ccu-sun20i-d1-r.h [new file with mode: 0644]
drivers/clk/sunxi-ng/ccu-sun20i-d1.c [new file with mode: 0644]
drivers/clk/sunxi-ng/ccu-sun20i-d1.h [new file with mode: 0644]
drivers/clk/sunxi-ng/ccu-sun4i-a10.c
drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c
drivers/clk/sunxi-ng/ccu-sun50i-a100.c
drivers/clk/sunxi-ng/ccu-sun50i-a64.c
drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c
drivers/clk/sunxi-ng/ccu-sun50i-h6.c
drivers/clk/sunxi-ng/ccu-sun50i-h616.c
drivers/clk/sunxi-ng/ccu-sun6i-a31.c
drivers/clk/sunxi-ng/ccu-sun8i-a23.c
drivers/clk/sunxi-ng/ccu-sun8i-a33.c
drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
drivers/clk/sunxi-ng/ccu-sun8i-de2.c
drivers/clk/sunxi-ng/ccu-sun8i-h3.c
drivers/clk/sunxi-ng/ccu-sun8i-r.c
drivers/clk/sunxi-ng/ccu-sun8i-r40.c
drivers/clk/sunxi-ng/ccu-sun8i-v3s.c
drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c
drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c
drivers/clk/sunxi-ng/ccu-sun9i-a80.c
drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c
drivers/clk/sunxi-ng/ccu_common.c
drivers/clk/sunxi-ng/ccu_div.c
drivers/clk/sunxi-ng/ccu_div.h
drivers/clk/sunxi-ng/ccu_frac.c
drivers/clk/sunxi-ng/ccu_gate.c
drivers/clk/sunxi-ng/ccu_gate.h
drivers/clk/sunxi-ng/ccu_mp.c
drivers/clk/sunxi-ng/ccu_mp.h
drivers/clk/sunxi-ng/ccu_mult.c
drivers/clk/sunxi-ng/ccu_mux.c
drivers/clk/sunxi-ng/ccu_mux.h
drivers/clk/sunxi-ng/ccu_nk.c
drivers/clk/sunxi-ng/ccu_nkm.c
drivers/clk/sunxi-ng/ccu_nkmp.c
drivers/clk/sunxi-ng/ccu_nm.c
drivers/clk/sunxi-ng/ccu_phase.c
drivers/clk/sunxi-ng/ccu_reset.c
drivers/clk/sunxi-ng/ccu_sdm.c
drivers/clk/x86/clk-fch.c
drivers/i2c/i2c-core-acpi.c
drivers/mmc/host/Kconfig
drivers/platform/x86/intel/int3472/Makefile
drivers/platform/x86/intel/int3472/clk_and_regulator.c [new file with mode: 0644]
drivers/platform/x86/intel/int3472/common.c [new file with mode: 0644]
drivers/platform/x86/intel/int3472/common.h [new file with mode: 0644]
drivers/platform/x86/intel/int3472/discrete.c [new file with mode: 0644]
drivers/platform/x86/intel/int3472/intel_skl_int3472_clk_and_regulator.c [deleted file]
drivers/platform/x86/intel/int3472/intel_skl_int3472_common.c [deleted file]
drivers/platform/x86/intel/int3472/intel_skl_int3472_common.h [deleted file]
drivers/platform/x86/intel/int3472/intel_skl_int3472_discrete.c [deleted file]
drivers/platform/x86/intel/int3472/intel_skl_int3472_tps68470.c [deleted file]
drivers/platform/x86/intel/int3472/tps68470.c [new file with mode: 0644]
drivers/platform/x86/intel/int3472/tps68470.h [new file with mode: 0644]
drivers/platform/x86/intel/int3472/tps68470_board_data.c [new file with mode: 0644]
include/acpi/acpi_bus.h
include/dt-bindings/clock/sun20i-d1-ccu.h [new file with mode: 0644]
include/dt-bindings/clock/sun20i-d1-r-ccu.h [new file with mode: 0644]
include/dt-bindings/reset/sun20i-d1-ccu.h [new file with mode: 0644]
include/dt-bindings/reset/sun20i-d1-r-ccu.h [new file with mode: 0644]
include/linux/clk/sunxi-ng.h
include/linux/i2c.h
include/linux/mfd/tps68470.h
include/linux/platform_data/clk-fch.h
include/linux/platform_data/tps68470.h [new file with mode: 0644]

index c4b7243..15ed64d 100644 (file)
@@ -34,6 +34,8 @@ properties:
       - allwinner,sun8i-v3-ccu
       - allwinner,sun8i-v3s-ccu
       - allwinner,sun9i-a80-ccu
+      - allwinner,sun20i-d1-ccu
+      - allwinner,sun20i-d1-r-ccu
       - allwinner,sun50i-a64-ccu
       - allwinner,sun50i-a64-r-ccu
       - allwinner,sun50i-a100-ccu
@@ -79,6 +81,7 @@ if:
       enum:
         - allwinner,sun8i-a83t-r-ccu
         - allwinner,sun8i-h3-r-ccu
+        - allwinner,sun20i-d1-r-ccu
         - allwinner,sun50i-a64-r-ccu
         - allwinner,sun50i-a100-r-ccu
         - allwinner,sun50i-h6-r-ccu
@@ -99,6 +102,7 @@ else:
     properties:
       compatible:
         enum:
+          - allwinner,sun20i-d1-ccu
           - allwinner,sun50i-a100-ccu
           - allwinner,sun50i-h6-ccu
           - allwinner,sun50i-h616-ccu
index 6e02448..2b958b4 100644 (file)
@@ -87,8 +87,15 @@ static int fch_misc_setup(struct apd_private_data *pdata)
        if (ret < 0)
                return -ENOENT;
 
-       if (!acpi_dev_get_property(adev, "is-rv", ACPI_TYPE_INTEGER, &obj))
-               clk_data->is_rv = obj->integer.value;
+       if (!acpi_dev_get_property(adev, "clk-name", ACPI_TYPE_STRING, &obj)) {
+               clk_data->name = devm_kzalloc(&adev->dev, obj->string.length,
+                                             GFP_KERNEL);
+
+               strcpy(clk_data->name, obj->string.pointer);
+       } else {
+               /* Set default name to mclk if entry missing in firmware */
+               clk_data->name = "mclk";
+       }
 
        list_for_each_entry(rentry, &resource_list, node) {
                clk_data->base = devm_ioremap(&adev->dev, rentry->res->start,
index a50f196..010ef0b 100644 (file)
@@ -797,6 +797,12 @@ static const char * const acpi_ignore_dep_ids[] = {
        NULL
 };
 
+/* List of HIDs for which we honor deps of matching ACPI devs, when checking _DEP lists. */
+static const char * const acpi_honor_dep_ids[] = {
+       "INT3472", /* Camera sensor PMIC / clk and regulator info */
+       NULL
+};
+
 static struct acpi_device *acpi_bus_get_parent(acpi_handle handle)
 {
        struct acpi_device *device = NULL;
@@ -1762,8 +1768,12 @@ static void acpi_scan_dep_init(struct acpi_device *adev)
        struct acpi_dep_data *dep;
 
        list_for_each_entry(dep, &acpi_dep_list, node) {
-               if (dep->consumer == adev->handle)
+               if (dep->consumer == adev->handle) {
+                       if (dep->honor_dep)
+                               adev->flags.honor_deps = 1;
+
                        adev->dep_unmet++;
+               }
        }
 }
 
@@ -1967,7 +1977,7 @@ static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep)
        for (count = 0, i = 0; i < dep_devices.count; i++) {
                struct acpi_device_info *info;
                struct acpi_dep_data *dep;
-               bool skip;
+               bool skip, honor_dep;
 
                status = acpi_get_object_info(dep_devices.handles[i], &info);
                if (ACPI_FAILURE(status)) {
@@ -1976,6 +1986,7 @@ static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep)
                }
 
                skip = acpi_info_matches_ids(info, acpi_ignore_dep_ids);
+               honor_dep = acpi_info_matches_ids(info, acpi_honor_dep_ids);
                kfree(info);
 
                if (skip)
@@ -1989,6 +2000,7 @@ static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep)
 
                dep->supplier = dep_devices.handles[i];
                dep->consumer = handle;
+               dep->honor_dep = honor_dep;
 
                mutex_lock(&acpi_dep_list_lock);
                list_add_tail(&dep->node , &acpi_dep_list);
@@ -2155,8 +2167,8 @@ static void acpi_bus_attach(struct acpi_device *device, bool first_pass)
                register_dock_dependent_device(device, ejd);
 
        acpi_bus_get_status(device);
-       /* Skip devices that are not present. */
-       if (!acpi_device_is_present(device)) {
+       /* Skip devices that are not ready for enumeration (e.g. not present) */
+       if (!acpi_dev_ready_for_enumeration(device)) {
                device->flags.initialized = false;
                acpi_device_clear_enumerated(device);
                device->flags.power_manageable = 0;
@@ -2318,6 +2330,23 @@ void acpi_dev_clear_dependencies(struct acpi_device *supplier)
 }
 EXPORT_SYMBOL_GPL(acpi_dev_clear_dependencies);
 
+/**
+ * acpi_dev_ready_for_enumeration - Check if the ACPI device is ready for enumeration
+ * @device: Pointer to the &struct acpi_device to check
+ *
+ * Check if the device is present and has no unmet dependencies.
+ *
+ * Return true if the device is ready for enumeratino. Otherwise, return false.
+ */
+bool acpi_dev_ready_for_enumeration(const struct acpi_device *device)
+{
+       if (device->flags.honor_deps && device->dep_unmet)
+               return false;
+
+       return acpi_device_is_present(device);
+}
+EXPORT_SYMBOL_GPL(acpi_dev_ready_for_enumeration);
+
 /**
  * acpi_dev_get_first_consumer_dev - Return ACPI device dependent on @supplier
  * @supplier: Pointer to the dependee device
index 1b992a5..73243ce 100644 (file)
@@ -169,6 +169,14 @@ config COMMON_CLK_CDCE706
        help
          This driver supports TI CDCE706 programmable 3-PLL clock synthesizer.
 
+config COMMON_CLK_TPS68470
+       tristate "Clock Driver for TI TPS68470 PMIC"
+       depends on I2C
+       depends on INTEL_SKL_INT3472 || COMPILE_TEST
+       select REGMAP_I2C
+       help
+         This driver supports the clocks provided by the TPS68470 PMIC.
+
 config COMMON_CLK_CDCE925
        tristate "Clock driver for TI CDCE913/925/937/949 devices"
        depends on I2C
index d8565ef..154bf3c 100644 (file)
@@ -64,6 +64,7 @@ obj-$(CONFIG_COMMON_CLK_SI570)                += clk-si570.o
 obj-$(CONFIG_COMMON_CLK_STM32F)                += clk-stm32f4.o
 obj-$(CONFIG_COMMON_CLK_STM32H7)       += clk-stm32h7.o
 obj-$(CONFIG_COMMON_CLK_STM32MP157)    += clk-stm32mp1.o
+obj-$(CONFIG_COMMON_CLK_TPS68470)      += clk-tps68470.o
 obj-$(CONFIG_CLK_TWL6040)              += clk-twl6040.o
 obj-$(CONFIG_ARCH_VT8500)              += clk-vt8500.o
 obj-$(CONFIG_COMMON_CLK_VC5)           += clk-versaclock5.o
@@ -111,7 +112,7 @@ obj-$(CONFIG_PLAT_SPEAR)            += spear/
 obj-y                                  += sprd/
 obj-$(CONFIG_ARCH_STI)                 += st/
 obj-$(CONFIG_ARCH_SUNXI)               += sunxi/
-obj-$(CONFIG_SUNXI_CCU)                        += sunxi-ng/
+obj-y                                  += sunxi-ng/
 obj-$(CONFIG_ARCH_TEGRA)               += tegra/
 obj-y                                  += ti/
 obj-$(CONFIG_CLK_UNIPHIER)             += uniphier/
index af46176..473dfe6 100644 (file)
@@ -129,7 +129,6 @@ static const struct stm32f4_gate_data stm32f429_gates[] __initconst = {
        { STM32F4_RCC_APB2ENR, 20,      "spi5",         "apb2_div" },
        { STM32F4_RCC_APB2ENR, 21,      "spi6",         "apb2_div" },
        { STM32F4_RCC_APB2ENR, 22,      "sai1",         "apb2_div" },
-       { STM32F4_RCC_APB2ENR, 26,      "ltdc",         "apb2_div" },
 };
 
 static const struct stm32f4_gate_data stm32f469_gates[] __initconst = {
@@ -211,7 +210,6 @@ static const struct stm32f4_gate_data stm32f469_gates[] __initconst = {
        { STM32F4_RCC_APB2ENR, 20,      "spi5",         "apb2_div" },
        { STM32F4_RCC_APB2ENR, 21,      "spi6",         "apb2_div" },
        { STM32F4_RCC_APB2ENR, 22,      "sai1",         "apb2_div" },
-       { STM32F4_RCC_APB2ENR, 26,      "ltdc",         "apb2_div" },
 };
 
 static const struct stm32f4_gate_data stm32f746_gates[] __initconst = {
@@ -286,7 +284,6 @@ static const struct stm32f4_gate_data stm32f746_gates[] __initconst = {
        { STM32F4_RCC_APB2ENR, 21,      "spi6",         "apb2_div" },
        { STM32F4_RCC_APB2ENR, 22,      "sai1",         "apb2_div" },
        { STM32F4_RCC_APB2ENR, 23,      "sai2",         "apb2_div" },
-       { STM32F4_RCC_APB2ENR, 26,      "ltdc",         "apb2_div" },
 };
 
 static const struct stm32f4_gate_data stm32f769_gates[] __initconst = {
@@ -364,7 +361,6 @@ static const struct stm32f4_gate_data stm32f769_gates[] __initconst = {
        { STM32F4_RCC_APB2ENR, 21,      "spi6",         "apb2_div" },
        { STM32F4_RCC_APB2ENR, 22,      "sai1",         "apb2_div" },
        { STM32F4_RCC_APB2ENR, 23,      "sai2",         "apb2_div" },
-       { STM32F4_RCC_APB2ENR, 26,      "ltdc",         "apb2_div" },
        { STM32F4_RCC_APB2ENR, 30,      "mdio",         "apb2_div" },
 };
 
diff --git a/drivers/clk/clk-tps68470.c b/drivers/clk/clk-tps68470.c
new file mode 100644 (file)
index 0000000..e5fbefd
--- /dev/null
@@ -0,0 +1,261 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Clock driver for TPS68470 PMIC
+ *
+ * Copyright (c) 2021 Red Hat Inc.
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * Authors:
+ *     Hans de Goede <hdegoede@redhat.com>
+ *     Zaikuo Wang <zaikuo.wang@intel.com>
+ *     Tianshu Qiu <tian.shu.qiu@intel.com>
+ *     Jian Xu Zheng <jian.xu.zheng@intel.com>
+ *     Yuning Pu <yuning.pu@intel.com>
+ *     Antti Laakso <antti.laakso@intel.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/kernel.h>
+#include <linux/mfd/tps68470.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/tps68470.h>
+#include <linux/regmap.h>
+
+#define TPS68470_CLK_NAME "tps68470-clk"
+
+#define to_tps68470_clkdata(clkd) \
+       container_of(clkd, struct tps68470_clkdata, clkout_hw)
+
+static struct tps68470_clkout_freqs {
+       unsigned long freq;
+       unsigned int xtaldiv;
+       unsigned int plldiv;
+       unsigned int postdiv;
+       unsigned int buckdiv;
+       unsigned int boostdiv;
+} clk_freqs[] = {
+/*
+ *  The PLL is used to multiply the crystal oscillator
+ *  frequency range of 3 MHz to 27 MHz by a programmable
+ *  factor of F = (M/N)*(1/P) such that the output
+ *  available at the HCLK_A or HCLK_B pins are in the range
+ *  of 4 MHz to 64 MHz in increments of 0.1 MHz.
+ *
+ * hclk_# = osc_in * (((plldiv*2)+320) / (xtaldiv+30)) * (1 / 2^postdiv)
+ *
+ * PLL_REF_CLK should be as close as possible to 100kHz
+ * PLL_REF_CLK = input clk / XTALDIV[7:0] + 30)
+ *
+ * PLL_VCO_CLK = (PLL_REF_CLK * (plldiv*2 + 320))
+ *
+ * BOOST should be as close as possible to 2Mhz
+ * BOOST = PLL_VCO_CLK / (BOOSTDIV[4:0] + 16) *
+ *
+ * BUCK should be as close as possible to 5.2Mhz
+ * BUCK = PLL_VCO_CLK / (BUCKDIV[3:0] + 5)
+ *
+ * osc_in   xtaldiv  plldiv   postdiv   hclk_#
+ * 20Mhz    170      32       1         19.2Mhz
+ * 20Mhz    170      40       1         20Mhz
+ * 20Mhz    170      80       1         24Mhz
+ */
+       { 19200000, 170, 32, 1, 2, 3 },
+       { 20000000, 170, 40, 1, 3, 4 },
+       { 24000000, 170, 80, 1, 4, 8 },
+};
+
+struct tps68470_clkdata {
+       struct clk_hw clkout_hw;
+       struct regmap *regmap;
+       unsigned long rate;
+};
+
+static int tps68470_clk_is_prepared(struct clk_hw *hw)
+{
+       struct tps68470_clkdata *clkdata = to_tps68470_clkdata(hw);
+       int val;
+
+       if (regmap_read(clkdata->regmap, TPS68470_REG_PLLCTL, &val))
+               return 0;
+
+       return val & TPS68470_PLL_EN_MASK;
+}
+
+static int tps68470_clk_prepare(struct clk_hw *hw)
+{
+       struct tps68470_clkdata *clkdata = to_tps68470_clkdata(hw);
+
+       regmap_write(clkdata->regmap, TPS68470_REG_CLKCFG1,
+                          (TPS68470_PLL_OUTPUT_ENABLE << TPS68470_OUTPUT_A_SHIFT) |
+                          (TPS68470_PLL_OUTPUT_ENABLE << TPS68470_OUTPUT_B_SHIFT));
+
+       regmap_update_bits(clkdata->regmap, TPS68470_REG_PLLCTL,
+                          TPS68470_PLL_EN_MASK, TPS68470_PLL_EN_MASK);
+
+       /*
+        * The PLLCTL reg lock bit is set by the PMIC after approx. 4ms and
+        * does not indicate a true lock, so just wait 4 ms.
+        */
+       usleep_range(4000, 5000);
+
+       return 0;
+}
+
+static void tps68470_clk_unprepare(struct clk_hw *hw)
+{
+       struct tps68470_clkdata *clkdata = to_tps68470_clkdata(hw);
+
+       /* Disable clock first ... */
+       regmap_update_bits(clkdata->regmap, TPS68470_REG_PLLCTL, TPS68470_PLL_EN_MASK, 0);
+
+       /* ... and then tri-state the clock outputs. */
+       regmap_write(clkdata->regmap, TPS68470_REG_CLKCFG1, 0);
+}
+
+static unsigned long tps68470_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+       struct tps68470_clkdata *clkdata = to_tps68470_clkdata(hw);
+
+       return clkdata->rate;
+}
+
+/*
+ * This returns the index of the clk_freqs[] cfg with the closest rate for
+ * use in tps68470_clk_round_rate(). tps68470_clk_set_rate() checks that
+ * the rate of the returned cfg is an exact match.
+ */
+static unsigned int tps68470_clk_cfg_lookup(unsigned long rate)
+{
+       long diff, best_diff = LONG_MAX;
+       unsigned int i, best_idx = 0;
+
+       for (i = 0; i < ARRAY_SIZE(clk_freqs); i++) {
+               diff = clk_freqs[i].freq - rate;
+               if (diff == 0)
+                       return i;
+
+               diff = abs(diff);
+               if (diff < best_diff) {
+                       best_diff = diff;
+                       best_idx = i;
+               }
+       }
+
+       return best_idx;
+}
+
+static long tps68470_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+                                   unsigned long *parent_rate)
+{
+       unsigned int idx = tps68470_clk_cfg_lookup(rate);
+
+       return clk_freqs[idx].freq;
+}
+
+static int tps68470_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+                                unsigned long parent_rate)
+{
+       struct tps68470_clkdata *clkdata = to_tps68470_clkdata(hw);
+       unsigned int idx = tps68470_clk_cfg_lookup(rate);
+
+       if (rate != clk_freqs[idx].freq)
+               return -EINVAL;
+
+       regmap_write(clkdata->regmap, TPS68470_REG_BOOSTDIV, clk_freqs[idx].boostdiv);
+       regmap_write(clkdata->regmap, TPS68470_REG_BUCKDIV, clk_freqs[idx].buckdiv);
+       regmap_write(clkdata->regmap, TPS68470_REG_PLLSWR, TPS68470_PLLSWR_DEFAULT);
+       regmap_write(clkdata->regmap, TPS68470_REG_XTALDIV, clk_freqs[idx].xtaldiv);
+       regmap_write(clkdata->regmap, TPS68470_REG_PLLDIV, clk_freqs[idx].plldiv);
+       regmap_write(clkdata->regmap, TPS68470_REG_POSTDIV, clk_freqs[idx].postdiv);
+       regmap_write(clkdata->regmap, TPS68470_REG_POSTDIV2, clk_freqs[idx].postdiv);
+       regmap_write(clkdata->regmap, TPS68470_REG_CLKCFG2, TPS68470_CLKCFG2_DRV_STR_2MA);
+
+       regmap_write(clkdata->regmap, TPS68470_REG_PLLCTL,
+                    TPS68470_OSC_EXT_CAP_DEFAULT << TPS68470_OSC_EXT_CAP_SHIFT |
+                    TPS68470_CLK_SRC_XTAL << TPS68470_CLK_SRC_SHIFT);
+
+       clkdata->rate = rate;
+
+       return 0;
+}
+
+static const struct clk_ops tps68470_clk_ops = {
+       .is_prepared = tps68470_clk_is_prepared,
+       .prepare = tps68470_clk_prepare,
+       .unprepare = tps68470_clk_unprepare,
+       .recalc_rate = tps68470_clk_recalc_rate,
+       .round_rate = tps68470_clk_round_rate,
+       .set_rate = tps68470_clk_set_rate,
+};
+
+static int tps68470_clk_probe(struct platform_device *pdev)
+{
+       struct tps68470_clk_platform_data *pdata = pdev->dev.platform_data;
+       struct clk_init_data tps68470_clk_initdata = {
+               .name = TPS68470_CLK_NAME,
+               .ops = &tps68470_clk_ops,
+               /* Changing the dividers when the PLL is on is not allowed */
+               .flags = CLK_SET_RATE_GATE,
+       };
+       struct tps68470_clkdata *tps68470_clkdata;
+       int ret;
+
+       tps68470_clkdata = devm_kzalloc(&pdev->dev, sizeof(*tps68470_clkdata),
+                                       GFP_KERNEL);
+       if (!tps68470_clkdata)
+               return -ENOMEM;
+
+       tps68470_clkdata->regmap = dev_get_drvdata(pdev->dev.parent);
+       tps68470_clkdata->clkout_hw.init = &tps68470_clk_initdata;
+
+       /* Set initial rate */
+       tps68470_clk_set_rate(&tps68470_clkdata->clkout_hw, clk_freqs[0].freq, 0);
+
+       ret = devm_clk_hw_register(&pdev->dev, &tps68470_clkdata->clkout_hw);
+       if (ret)
+               return ret;
+
+       ret = devm_clk_hw_register_clkdev(&pdev->dev, &tps68470_clkdata->clkout_hw,
+                                         TPS68470_CLK_NAME, NULL);
+       if (ret)
+               return ret;
+
+       if (pdata) {
+               ret = devm_clk_hw_register_clkdev(&pdev->dev,
+                                                 &tps68470_clkdata->clkout_hw,
+                                                 pdata->consumer_con_id,
+                                                 pdata->consumer_dev_name);
+       }
+
+       return ret;
+}
+
+static struct platform_driver tps68470_clk_driver = {
+       .driver = {
+               .name = TPS68470_CLK_NAME,
+       },
+       .probe = tps68470_clk_probe,
+};
+
+/*
+ * The ACPI tps68470 probe-ordering depends on the clk/gpio/regulator drivers
+ * registering before the drivers for the camera-sensors which use them bind.
+ * subsys_initcall() ensures this when the drivers are builtin.
+ */
+static int __init tps68470_clk_init(void)
+{
+       return platform_driver_register(&tps68470_clk_driver);
+}
+subsys_initcall(tps68470_clk_init);
+
+static void __exit tps68470_clk_exit(void)
+{
+       platform_driver_unregister(&tps68470_clk_driver);
+}
+module_exit(tps68470_clk_exit);
+
+MODULE_ALIAS("platform:tps68470-clk");
+MODULE_DESCRIPTION("clock driver for TPS68470 pmic");
+MODULE_LICENSE("GPL");
index d6eed76..608e0e8 100644 (file)
@@ -713,6 +713,35 @@ static struct clk_regmap gxbb_mpll_prediv = {
 };
 
 static struct clk_regmap gxbb_mpll0_div = {
+       .data = &(struct meson_clk_mpll_data){
+               .sdm = {
+                       .reg_off = HHI_MPLL_CNTL7,
+                       .shift   = 0,
+                       .width   = 14,
+               },
+               .sdm_en = {
+                       .reg_off = HHI_MPLL_CNTL,
+                       .shift   = 25,
+                       .width   = 1,
+               },
+               .n2 = {
+                       .reg_off = HHI_MPLL_CNTL7,
+                       .shift   = 16,
+                       .width   = 9,
+               },
+               .lock = &meson_clk_lock,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mpll0_div",
+               .ops = &meson_clk_mpll_ops,
+               .parent_hws = (const struct clk_hw *[]) {
+                       &gxbb_mpll_prediv.hw
+               },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap gxl_mpll0_div = {
        .data = &(struct meson_clk_mpll_data){
                .sdm = {
                        .reg_off = HHI_MPLL_CNTL7,
@@ -749,7 +778,16 @@ static struct clk_regmap gxbb_mpll0 = {
        .hw.init = &(struct clk_init_data){
                .name = "mpll0",
                .ops = &clk_regmap_gate_ops,
-               .parent_hws = (const struct clk_hw *[]) { &gxbb_mpll0_div.hw },
+               .parent_data = &(const struct clk_parent_data) {
+                       /*
+                        * Note:
+                        * GXL and GXBB have different SDM_EN registers. We
+                        * fallback to the global naming string mechanism so
+                        * mpll0_div picks up the appropriate one.
+                        */
+                       .name = "mpll0_div",
+                       .index = -1,
+               },
                .num_parents = 1,
                .flags = CLK_SET_RATE_PARENT,
        },
@@ -3044,7 +3082,7 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = {
                [CLKID_VAPB_1]              = &gxbb_vapb_1.hw,
                [CLKID_VAPB_SEL]            = &gxbb_vapb_sel.hw,
                [CLKID_VAPB]                = &gxbb_vapb.hw,
-               [CLKID_MPLL0_DIV]           = &gxbb_mpll0_div.hw,
+               [CLKID_MPLL0_DIV]           = &gxl_mpll0_div.hw,
                [CLKID_MPLL1_DIV]           = &gxbb_mpll1_div.hw,
                [CLKID_MPLL2_DIV]           = &gxbb_mpll2_div.hw,
                [CLKID_MPLL_PREDIV]         = &gxbb_mpll_prediv.hw,
@@ -3439,7 +3477,7 @@ static struct clk_regmap *const gxl_clk_regmaps[] = {
        &gxbb_mpll0,
        &gxbb_mpll1,
        &gxbb_mpll2,
-       &gxbb_mpll0_div,
+       &gxl_mpll0_div,
        &gxbb_mpll1_div,
        &gxbb_mpll2_div,
        &gxbb_cts_amclk_div,
index e76e167..68a94e5 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 config SUNXI_CCU
-       bool "Clock support for Allwinner SoCs"
+       tristate "Clock support for Allwinner SoCs"
        depends on ARCH_SUNXI || COMPILE_TEST
        select RESET_CONTROLLER
        default ARCH_SUNXI
@@ -8,42 +8,52 @@ config SUNXI_CCU
 if SUNXI_CCU
 
 config SUNIV_F1C100S_CCU
-       bool "Support for the Allwinner newer F1C100s CCU"
+       tristate "Support for the Allwinner newer F1C100s CCU"
        default MACH_SUNIV
        depends on MACH_SUNIV || COMPILE_TEST
 
+config SUN20I_D1_CCU
+       tristate "Support for the Allwinner D1 CCU"
+       default RISCV && ARCH_SUNXI
+       depends on (RISCV && ARCH_SUNXI) || COMPILE_TEST
+
+config SUN20I_D1_R_CCU
+       tristate "Support for the Allwinner D1 PRCM CCU"
+       default RISCV && ARCH_SUNXI
+       depends on (RISCV && ARCH_SUNXI) || COMPILE_TEST
+
 config SUN50I_A64_CCU
-       bool "Support for the Allwinner A64 CCU"
+       tristate "Support for the Allwinner A64 CCU"
        default ARM64 && ARCH_SUNXI
        depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
 
 config SUN50I_A100_CCU
-       bool "Support for the Allwinner A100 CCU"
+       tristate "Support for the Allwinner A100 CCU"
        default ARM64 && ARCH_SUNXI
        depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
 
 config SUN50I_A100_R_CCU
-       bool "Support for the Allwinner A100 PRCM CCU"
+       tristate "Support for the Allwinner A100 PRCM CCU"
        default ARM64 && ARCH_SUNXI
        depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
 
 config SUN50I_H6_CCU
-       bool "Support for the Allwinner H6 CCU"
+       tristate "Support for the Allwinner H6 CCU"
        default ARM64 && ARCH_SUNXI
        depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
 
 config SUN50I_H616_CCU
-       bool "Support for the Allwinner H616 CCU"
+       tristate "Support for the Allwinner H616 CCU"
        default ARM64 && ARCH_SUNXI
        depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
 
 config SUN50I_H6_R_CCU
-       bool "Support for the Allwinner H6 and H616 PRCM CCU"
+       tristate "Support for the Allwinner H6 and H616 PRCM CCU"
        default ARM64 && ARCH_SUNXI
        depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
 
 config SUN4I_A10_CCU
-       bool "Support for the Allwinner A10/A20 CCU"
+       tristate "Support for the Allwinner A10/A20 CCU"
        default MACH_SUN4I
        default MACH_SUN7I
        depends on MACH_SUN4I || MACH_SUN7I || COMPILE_TEST
@@ -52,53 +62,54 @@ config SUN5I_CCU
        bool "Support for the Allwinner sun5i family CCM"
        default MACH_SUN5I
        depends on MACH_SUN5I || COMPILE_TEST
+       depends on SUNXI_CCU=y
 
 config SUN6I_A31_CCU
-       bool "Support for the Allwinner A31/A31s CCU"
+       tristate "Support for the Allwinner A31/A31s CCU"
        default MACH_SUN6I
        depends on MACH_SUN6I || COMPILE_TEST
 
 config SUN8I_A23_CCU
-       bool "Support for the Allwinner A23 CCU"
+       tristate "Support for the Allwinner A23 CCU"
        default MACH_SUN8I
        depends on MACH_SUN8I || COMPILE_TEST
 
 config SUN8I_A33_CCU
-       bool "Support for the Allwinner A33 CCU"
+       tristate "Support for the Allwinner A33 CCU"
        default MACH_SUN8I
        depends on MACH_SUN8I || COMPILE_TEST
 
 config SUN8I_A83T_CCU
-       bool "Support for the Allwinner A83T CCU"
+       tristate "Support for the Allwinner A83T CCU"
        default MACH_SUN8I
        depends on MACH_SUN8I || COMPILE_TEST
 
 config SUN8I_H3_CCU
-       bool "Support for the Allwinner H3 CCU"
+       tristate "Support for the Allwinner H3 CCU"
        default MACH_SUN8I || (ARM64 && ARCH_SUNXI)
        depends on MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST
 
 config SUN8I_V3S_CCU
-       bool "Support for the Allwinner V3s CCU"
+       tristate "Support for the Allwinner V3s CCU"
        default MACH_SUN8I
        depends on MACH_SUN8I || COMPILE_TEST
 
 config SUN8I_DE2_CCU
-       bool "Support for the Allwinner SoCs DE2 CCU"
+       tristate "Support for the Allwinner SoCs DE2 CCU"
        default MACH_SUN8I || (ARM64 && ARCH_SUNXI)
 
 config SUN8I_R40_CCU
-       bool "Support for the Allwinner R40 CCU"
+       tristate "Support for the Allwinner R40 CCU"
        default MACH_SUN8I
        depends on MACH_SUN8I || COMPILE_TEST
 
 config SUN9I_A80_CCU
-       bool "Support for the Allwinner A80 CCU"
+       tristate "Support for the Allwinner A80 CCU"
        default MACH_SUN9I
        depends on MACH_SUN9I || COMPILE_TEST
 
 config SUN8I_R_CCU
-       bool "Support for Allwinner SoCs' PRCM CCUs"
+       tristate "Support for Allwinner SoCs' PRCM CCUs"
        default MACH_SUN8I || (ARCH_SUNXI && ARM64)
 
 endif
index 96c3243..ec931cb 100644 (file)
@@ -1,44 +1,73 @@
 # SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_SUNXI_CCU)                += sunxi-ccu.o
+
 # Common objects
-obj-y                          += ccu_common.o
-obj-y                          += ccu_mmc_timing.o
-obj-y                          += ccu_reset.o
+sunxi-ccu-y                    += ccu_common.o
+sunxi-ccu-y                    += ccu_mmc_timing.o
+sunxi-ccu-y                    += ccu_reset.o
 
 # Base clock types
-obj-y                          += ccu_div.o
-obj-y                          += ccu_frac.o
-obj-y                          += ccu_gate.o
-obj-y                          += ccu_mux.o
-obj-y                          += ccu_mult.o
-obj-y                          += ccu_phase.o
-obj-y                          += ccu_sdm.o
+sunxi-ccu-y                    += ccu_div.o
+sunxi-ccu-y                    += ccu_frac.o
+sunxi-ccu-y                    += ccu_gate.o
+sunxi-ccu-y                    += ccu_mux.o
+sunxi-ccu-y                    += ccu_mult.o
+sunxi-ccu-y                    += ccu_phase.o
+sunxi-ccu-y                    += ccu_sdm.o
 
 # Multi-factor clocks
-obj-y                          += ccu_nk.o
-obj-y                          += ccu_nkm.o
-obj-y                          += ccu_nkmp.o
-obj-y                          += ccu_nm.o
-obj-y                          += ccu_mp.o
+sunxi-ccu-y                    += ccu_nk.o
+sunxi-ccu-y                    += ccu_nkm.o
+sunxi-ccu-y                    += ccu_nkmp.o
+sunxi-ccu-y                    += ccu_nm.o
+sunxi-ccu-y                    += ccu_mp.o
 
 # SoC support
-obj-$(CONFIG_SUNIV_F1C100S_CCU)        += ccu-suniv-f1c100s.o
-obj-$(CONFIG_SUN50I_A64_CCU)   += ccu-sun50i-a64.o
-obj-$(CONFIG_SUN50I_A100_CCU)  += ccu-sun50i-a100.o
-obj-$(CONFIG_SUN50I_A100_R_CCU)        += ccu-sun50i-a100-r.o
-obj-$(CONFIG_SUN50I_H6_CCU)    += ccu-sun50i-h6.o
-obj-$(CONFIG_SUN50I_H616_CCU)  += ccu-sun50i-h616.o
-obj-$(CONFIG_SUN50I_H6_R_CCU)  += ccu-sun50i-h6-r.o
-obj-$(CONFIG_SUN4I_A10_CCU)    += ccu-sun4i-a10.o
-obj-$(CONFIG_SUN5I_CCU)                += ccu-sun5i.o
-obj-$(CONFIG_SUN6I_A31_CCU)    += ccu-sun6i-a31.o
-obj-$(CONFIG_SUN8I_A23_CCU)    += ccu-sun8i-a23.o
-obj-$(CONFIG_SUN8I_A33_CCU)    += ccu-sun8i-a33.o
-obj-$(CONFIG_SUN8I_A83T_CCU)   += ccu-sun8i-a83t.o
-obj-$(CONFIG_SUN8I_H3_CCU)     += ccu-sun8i-h3.o
-obj-$(CONFIG_SUN8I_V3S_CCU)    += ccu-sun8i-v3s.o
-obj-$(CONFIG_SUN8I_DE2_CCU)    += ccu-sun8i-de2.o
-obj-$(CONFIG_SUN8I_R_CCU)      += ccu-sun8i-r.o
-obj-$(CONFIG_SUN8I_R40_CCU)    += ccu-sun8i-r40.o
-obj-$(CONFIG_SUN9I_A80_CCU)    += ccu-sun9i-a80.o
-obj-$(CONFIG_SUN9I_A80_CCU)    += ccu-sun9i-a80-de.o
-obj-$(CONFIG_SUN9I_A80_CCU)    += ccu-sun9i-a80-usb.o
+obj-$(CONFIG_SUNIV_F1C100S_CCU)        += suniv-f1c100s-ccu.o
+obj-$(CONFIG_SUN20I_D1_CCU)    += sun20i-d1-ccu.o
+obj-$(CONFIG_SUN20I_D1_R_CCU)  += sun20i-d1-r-ccu.o
+obj-$(CONFIG_SUN50I_A64_CCU)   += sun50i-a64-ccu.o
+obj-$(CONFIG_SUN50I_A100_CCU)  += sun50i-a100-ccu.o
+obj-$(CONFIG_SUN50I_A100_R_CCU)        += sun50i-a100-r-ccu.o
+obj-$(CONFIG_SUN50I_H6_CCU)    += sun50i-h6-ccu.o
+obj-$(CONFIG_SUN50I_H6_R_CCU)  += sun50i-h6-r-ccu.o
+obj-$(CONFIG_SUN50I_H616_CCU)  += sun50i-h616-ccu.o
+obj-$(CONFIG_SUN4I_A10_CCU)    += sun4i-a10-ccu.o
+obj-$(CONFIG_SUN5I_CCU)                += sun5i-ccu.o
+obj-$(CONFIG_SUN6I_A31_CCU)    += sun6i-a31-ccu.o
+obj-$(CONFIG_SUN8I_A23_CCU)    += sun8i-a23-ccu.o
+obj-$(CONFIG_SUN8I_A33_CCU)    += sun8i-a33-ccu.o
+obj-$(CONFIG_SUN8I_A83T_CCU)   += sun8i-a83t-ccu.o
+obj-$(CONFIG_SUN8I_H3_CCU)     += sun8i-h3-ccu.o
+obj-$(CONFIG_SUN8I_R40_CCU)    += sun8i-r40-ccu.o
+obj-$(CONFIG_SUN8I_V3S_CCU)    += sun8i-v3s-ccu.o
+obj-$(CONFIG_SUN8I_DE2_CCU)    += sun8i-de2-ccu.o
+obj-$(CONFIG_SUN8I_R_CCU)      += sun8i-r-ccu.o
+obj-$(CONFIG_SUN9I_A80_CCU)    += sun9i-a80-ccu.o
+obj-$(CONFIG_SUN9I_A80_CCU)    += sun9i-a80-de-ccu.o
+obj-$(CONFIG_SUN9I_A80_CCU)    += sun9i-a80-usb-ccu.o
+
+suniv-f1c100s-ccu-y            += ccu-suniv-f1c100s.o
+sun20i-d1-ccu-y                        += ccu-sun20i-d1.o
+sun20i-d1-r-ccu-y              += ccu-sun20i-d1-r.o
+sun50i-a64-ccu-y               += ccu-sun50i-a64.o
+sun50i-a100-ccu-y              += ccu-sun50i-a100.o
+sun50i-a100-r-ccu-y            += ccu-sun50i-a100-r.o
+sun50i-h6-ccu-y                        += ccu-sun50i-h6.o
+sun50i-h6-r-ccu-y              += ccu-sun50i-h6-r.o
+sun50i-h616-ccu-y              += ccu-sun50i-h616.o
+sun4i-a10-ccu-y                        += ccu-sun4i-a10.o
+sun5i-ccu-y                    += ccu-sun5i.o
+sun6i-a31-ccu-y                        += ccu-sun6i-a31.o
+sun8i-a23-ccu-y                        += ccu-sun8i-a23.o
+sun8i-a33-ccu-y                        += ccu-sun8i-a33.o
+sun8i-a83t-ccu-y               += ccu-sun8i-a83t.o
+sun8i-h3-ccu-y                 += ccu-sun8i-h3.o
+sun8i-r40-ccu-y                        += ccu-sun8i-r40.o
+sun8i-v3s-ccu-y                        += ccu-sun8i-v3s.o
+sun8i-de2-ccu-y                        += ccu-sun8i-de2.o
+sun8i-r-ccu-y                  += ccu-sun8i-r.o
+sun9i-a80-ccu-y                        += ccu-sun9i-a80.o
+sun9i-a80-de-ccu-y             += ccu-sun9i-a80-de.o
+sun9i-a80-usb-ccu-y            += ccu-sun9i-a80-usb.o
diff --git a/drivers/clk/sunxi-ng/ccu-sun20i-d1-r.c b/drivers/clk/sunxi-ng/ccu-sun20i-d1-r.c
new file mode 100644 (file)
index 0000000..9d3ffd3
--- /dev/null
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020 huangzhenwei@allwinnertech.com
+ * Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "ccu_common.h"
+#include "ccu_reset.h"
+
+#include "ccu_gate.h"
+#include "ccu_mp.h"
+
+#include "ccu-sun20i-d1-r.h"
+
+static const struct clk_parent_data r_ahb_apb0_parents[] = {
+       { .fw_name = "hosc" },
+       { .fw_name = "losc" },
+       { .fw_name = "iosc" },
+       { .fw_name = "pll-periph" },
+};
+static SUNXI_CCU_MP_DATA_WITH_MUX(r_ahb_clk, "r-ahb",
+                                 r_ahb_apb0_parents, 0x000,
+                                 0, 5,         /* M */
+                                 8, 2,         /* P */
+                                 24, 3,        /* mux */
+                                 0);
+static const struct clk_hw *r_ahb_hw = &r_ahb_clk.common.hw;
+
+static SUNXI_CCU_MP_DATA_WITH_MUX(r_apb0_clk, "r-apb0",
+                                 r_ahb_apb0_parents, 0x00c,
+                                 0, 5,         /* M */
+                                 8, 2,         /* P */
+                                 24, 3,        /* mux */
+                                 0);
+static const struct clk_hw *r_apb0_hw = &r_apb0_clk.common.hw;
+
+static SUNXI_CCU_GATE_HWS(bus_r_timer_clk,     "bus-r-timer",  &r_apb0_hw,
+                         0x11c, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_r_twd_clk,       "bus-r-twd",    &r_apb0_hw,
+                         0x12c, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_r_ppu_clk,       "bus-r-ppu",    &r_apb0_hw,
+                         0x1ac, BIT(0), 0);
+
+static const struct clk_parent_data r_ir_rx_parents[] = {
+       { .fw_name = "losc" },
+       { .fw_name = "hosc" },
+};
+static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(r_ir_rx_clk, "r-ir-rx",
+                                      r_ir_rx_parents, 0x1c0,
+                                      0, 5,    /* M */
+                                      8, 2,    /* P */
+                                      24, 2,   /* mux */
+                                      BIT(31), /* gate */
+                                      0);
+
+static SUNXI_CCU_GATE_HWS(bus_r_ir_rx_clk,     "bus-r-ir-rx",  &r_apb0_hw,
+                         0x1cc, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_r_rtc_clk,       "bus-r-rtc",    &r_ahb_hw,
+                         0x20c, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_r_cpucfg_clk,    "bus-r-cpucfg", &r_apb0_hw,
+                         0x22c, BIT(0), 0);
+
+static struct ccu_common *sun20i_d1_r_ccu_clks[] = {
+       &r_ahb_clk.common,
+       &r_apb0_clk.common,
+       &bus_r_timer_clk.common,
+       &bus_r_twd_clk.common,
+       &bus_r_ppu_clk.common,
+       &r_ir_rx_clk.common,
+       &bus_r_ir_rx_clk.common,
+       &bus_r_rtc_clk.common,
+       &bus_r_cpucfg_clk.common,
+};
+
+static struct clk_hw_onecell_data sun20i_d1_r_hw_clks = {
+       .num    = CLK_NUMBER,
+       .hws    = {
+               [CLK_R_AHB]             = &r_ahb_clk.common.hw,
+               [CLK_R_APB0]            = &r_apb0_clk.common.hw,
+               [CLK_BUS_R_TIMER]       = &bus_r_timer_clk.common.hw,
+               [CLK_BUS_R_TWD]         = &bus_r_twd_clk.common.hw,
+               [CLK_BUS_R_PPU]         = &bus_r_ppu_clk.common.hw,
+               [CLK_R_IR_RX]           = &r_ir_rx_clk.common.hw,
+               [CLK_BUS_R_IR_RX]       = &bus_r_ir_rx_clk.common.hw,
+               [CLK_BUS_R_RTC]         = &bus_r_rtc_clk.common.hw,
+               [CLK_BUS_R_CPUCFG]      = &bus_r_cpucfg_clk.common.hw,
+       },
+};
+
+static struct ccu_reset_map sun20i_d1_r_ccu_resets[] = {
+       [RST_BUS_R_TIMER]       = { 0x11c, BIT(16) },
+       [RST_BUS_R_TWD]         = { 0x12c, BIT(16) },
+       [RST_BUS_R_PPU]         = { 0x1ac, BIT(16) },
+       [RST_BUS_R_IR_RX]       = { 0x1cc, BIT(16) },
+       [RST_BUS_R_RTC]         = { 0x20c, BIT(16) },
+       [RST_BUS_R_CPUCFG]      = { 0x22c, BIT(16) },
+};
+
+static const struct sunxi_ccu_desc sun20i_d1_r_ccu_desc = {
+       .ccu_clks       = sun20i_d1_r_ccu_clks,
+       .num_ccu_clks   = ARRAY_SIZE(sun20i_d1_r_ccu_clks),
+
+       .hw_clks        = &sun20i_d1_r_hw_clks,
+
+       .resets         = sun20i_d1_r_ccu_resets,
+       .num_resets     = ARRAY_SIZE(sun20i_d1_r_ccu_resets),
+};
+
+static int sun20i_d1_r_ccu_probe(struct platform_device *pdev)
+{
+       void __iomem *reg;
+
+       reg = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(reg))
+               return PTR_ERR(reg);
+
+       return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun20i_d1_r_ccu_desc);
+}
+
+static const struct of_device_id sun20i_d1_r_ccu_ids[] = {
+       { .compatible = "allwinner,sun20i-d1-r-ccu" },
+       { }
+};
+
+static struct platform_driver sun20i_d1_r_ccu_driver = {
+       .probe  = sun20i_d1_r_ccu_probe,
+       .driver = {
+               .name                   = "sun20i-d1-r-ccu",
+               .suppress_bind_attrs    = true,
+               .of_match_table         = sun20i_d1_r_ccu_ids,
+       },
+};
+module_platform_driver(sun20i_d1_r_ccu_driver);
+
+MODULE_IMPORT_NS(SUNXI_CCU);
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/sunxi-ng/ccu-sun20i-d1-r.h b/drivers/clk/sunxi-ng/ccu-sun20i-d1-r.h
new file mode 100644 (file)
index 0000000..afd4342
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2020 frank@allwinnertech.com
+ * Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
+ */
+
+#ifndef _CCU_SUN20I_D1_R_H
+#define _CCU_SUN20I_D1_R_H
+
+#include <dt-bindings/clock/sun20i-d1-r-ccu.h>
+#include <dt-bindings/reset/sun20i-d1-r-ccu.h>
+
+#define CLK_R_APB0             1
+
+#define CLK_NUMBER             (CLK_BUS_R_CPUCFG + 1)
+
+#endif /* _CCU_SUN20I_D1_R_H */
diff --git a/drivers/clk/sunxi-ng/ccu-sun20i-d1.c b/drivers/clk/sunxi-ng/ccu-sun20i-d1.c
new file mode 100644 (file)
index 0000000..51058ba
--- /dev/null
@@ -0,0 +1,1390 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020 huangzhenwei@allwinnertech.com
+ * Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "../clk.h"
+
+#include "ccu_common.h"
+#include "ccu_reset.h"
+
+#include "ccu_div.h"
+#include "ccu_gate.h"
+#include "ccu_mp.h"
+#include "ccu_mult.h"
+#include "ccu_nk.h"
+#include "ccu_nkm.h"
+#include "ccu_nkmp.h"
+#include "ccu_nm.h"
+
+#include "ccu-sun20i-d1.h"
+
+static const struct clk_parent_data osc24M[] = {
+       { .fw_name = "hosc" }
+};
+
+/*
+ * For the CPU PLL, the output divider is described as "only for testing"
+ * in the user manual. So it's not modelled and forced to 0.
+ */
+#define SUN20I_D1_PLL_CPUX_REG         0x000
+static struct ccu_mult pll_cpux_clk = {
+       .enable         = BIT(27),
+       .lock           = BIT(28),
+       .mult           = _SUNXI_CCU_MULT_MIN(8, 8, 12),
+       .common         = {
+               .reg            = 0x000,
+               .hw.init        = CLK_HW_INIT_PARENTS_DATA("pll-cpux", osc24M,
+                                                          &ccu_mult_ops,
+                                                          CLK_SET_RATE_UNGATE),
+       },
+};
+
+/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */
+#define SUN20I_D1_PLL_DDR0_REG         0x010
+static struct ccu_nkmp pll_ddr0_clk = {
+       .enable         = BIT(27),
+       .lock           = BIT(28),
+       .n              = _SUNXI_CCU_MULT_MIN(8, 8, 12),
+       .m              = _SUNXI_CCU_DIV(1, 1), /* input divider */
+       .p              = _SUNXI_CCU_DIV(0, 1), /* output divider */
+       .common         = {
+               .reg            = 0x010,
+               .hw.init        = CLK_HW_INIT_PARENTS_DATA("pll-ddr0", osc24M,
+                                                          &ccu_nkmp_ops,
+                                                          CLK_SET_RATE_UNGATE),
+       },
+};
+
+#define SUN20I_D1_PLL_PERIPH0_REG      0x020
+static struct ccu_nm pll_periph0_4x_clk = {
+       .enable         = BIT(27),
+       .lock           = BIT(28),
+       .n              = _SUNXI_CCU_MULT_MIN(8, 8, 12),
+       .m              = _SUNXI_CCU_DIV(1, 1), /* input divider */
+       .common         = {
+               .reg            = 0x020,
+               .hw.init        = CLK_HW_INIT_PARENTS_DATA("pll-periph0-4x", osc24M,
+                                                          &ccu_nm_ops,
+                                                          CLK_SET_RATE_UNGATE),
+       },
+};
+
+static const struct clk_hw *pll_periph0_4x_hws[] = {
+       &pll_periph0_4x_clk.common.hw
+};
+static SUNXI_CCU_M_HWS(pll_periph0_2x_clk, "pll-periph0-2x",
+                      pll_periph0_4x_hws, 0x020, 16, 3, 0);
+static SUNXI_CCU_M_HWS(pll_periph0_800M_clk, "pll-periph0-800M",
+                      pll_periph0_4x_hws, 0x020, 20, 3, 0);
+
+static const struct clk_hw *pll_periph0_2x_hws[] = {
+       &pll_periph0_2x_clk.common.hw
+};
+static CLK_FIXED_FACTOR_HWS(pll_periph0_clk, "pll-periph0",
+                           pll_periph0_2x_hws, 2, 1, 0);
+
+static const struct clk_hw *pll_periph0_hws[] = { &pll_periph0_clk.hw };
+static CLK_FIXED_FACTOR_HWS(pll_periph0_div3_clk, "pll-periph0-div3",
+                           pll_periph0_2x_hws, 6, 1, 0);
+
+/*
+ * For Video PLLs, the output divider is described as "only for testing"
+ * in the user manual. So it's not modelled and forced to 0.
+ */
+#define SUN20I_D1_PLL_VIDEO0_REG       0x040
+static struct ccu_nm pll_video0_4x_clk = {
+       .enable         = BIT(27),
+       .lock           = BIT(28),
+       .n              = _SUNXI_CCU_MULT_MIN(8, 8, 12),
+       .m              = _SUNXI_CCU_DIV(1, 1), /* input divider */
+       .common         = {
+               .reg            = 0x040,
+               .hw.init        = CLK_HW_INIT_PARENTS_DATA("pll-video0-4x", osc24M,
+                                                          &ccu_nm_ops,
+                                                          CLK_SET_RATE_UNGATE),
+       },
+};
+
+static const struct clk_hw *pll_video0_4x_hws[] = {
+       &pll_video0_4x_clk.common.hw
+};
+static CLK_FIXED_FACTOR_HWS(pll_video0_2x_clk, "pll-video0-2x",
+                           pll_video0_4x_hws, 2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_video0_clk, "pll-video0",
+                           pll_video0_4x_hws, 4, 1, CLK_SET_RATE_PARENT);
+
+#define SUN20I_D1_PLL_VIDEO1_REG       0x048
+static struct ccu_nm pll_video1_4x_clk = {
+       .enable         = BIT(27),
+       .lock           = BIT(28),
+       .n              = _SUNXI_CCU_MULT_MIN(8, 8, 12),
+       .m              = _SUNXI_CCU_DIV(1, 1), /* input divider */
+       .common         = {
+               .reg            = 0x048,
+               .hw.init        = CLK_HW_INIT_PARENTS_DATA("pll-video1-4x", osc24M,
+                                                          &ccu_nm_ops,
+                                                          CLK_SET_RATE_UNGATE),
+       },
+};
+
+static const struct clk_hw *pll_video1_4x_hws[] = {
+       &pll_video1_4x_clk.common.hw
+};
+static CLK_FIXED_FACTOR_HWS(pll_video1_2x_clk, "pll-video1-2x",
+                           pll_video1_4x_hws, 2, 1, CLK_SET_RATE_PARENT);
+static CLK_FIXED_FACTOR_HWS(pll_video1_clk, "pll-video1",
+                           pll_video1_4x_hws, 4, 1, CLK_SET_RATE_PARENT);
+
+#define SUN20I_D1_PLL_VE_REG           0x058
+static struct ccu_nkmp pll_ve_clk = {
+       .enable         = BIT(27),
+       .lock           = BIT(28),
+       .n              = _SUNXI_CCU_MULT_MIN(8, 8, 12),
+       .m              = _SUNXI_CCU_DIV(1, 1), /* input divider */
+       .p              = _SUNXI_CCU_DIV(0, 1), /* output divider */
+       .common         = {
+               .reg            = 0x058,
+               .hw.init        = CLK_HW_INIT_PARENTS_DATA("pll-ve", osc24M,
+                                                          &ccu_nkmp_ops,
+                                                          CLK_SET_RATE_UNGATE),
+       },
+};
+
+/*
+ * PLL_AUDIO0 has m0, m1 dividers in addition to the usual N, M factors.
+ * Since we only need one frequency from this PLL (22.5792 x 4 == 90.3168 MHz),
+ * ignore them for now. Enforce the default for them, which is m1 = 0, m0 = 0.
+ * The M factor must be an even number to produce a 50% duty cycle output.
+ */
+#define SUN20I_D1_PLL_AUDIO0_REG               0x078
+static struct ccu_sdm_setting pll_audio0_sdm_table[] = {
+       { .rate = 90316800, .pattern = 0xc001288d, .m = 6, .n = 22 },
+};
+
+static struct ccu_nm pll_audio0_4x_clk = {
+       .enable         = BIT(27),
+       .lock           = BIT(28),
+       .n              = _SUNXI_CCU_MULT_MIN(8, 8, 12),
+       .m              = _SUNXI_CCU_DIV(16, 6),
+       .sdm            = _SUNXI_CCU_SDM(pll_audio0_sdm_table, BIT(24),
+                                        0x178, BIT(31)),
+       .common         = {
+               .reg            = 0x078,
+               .features       = CCU_FEATURE_SIGMA_DELTA_MOD,
+               .hw.init        = CLK_HW_INIT_PARENTS_DATA("pll-audio0-4x", osc24M,
+                                                          &ccu_nm_ops,
+                                                          CLK_SET_RATE_UNGATE),
+       },
+};
+
+static const struct clk_hw *pll_audio0_4x_hws[] = {
+       &pll_audio0_4x_clk.common.hw
+};
+static CLK_FIXED_FACTOR_HWS(pll_audio0_2x_clk, "pll-audio0-2x",
+                           pll_audio0_4x_hws, 2, 1, 0);
+static CLK_FIXED_FACTOR_HWS(pll_audio0_clk, "pll-audio0",
+                           pll_audio0_4x_hws, 4, 1, 0);
+
+/*
+ * PLL_AUDIO1 doesn't need Fractional-N. The output is usually 614.4 MHz for
+ * audio. The ADC or DAC should divide the PLL output further to 24.576 MHz.
+ */
+#define SUN20I_D1_PLL_AUDIO1_REG               0x080
+static struct ccu_nm pll_audio1_clk = {
+       .enable         = BIT(27),
+       .lock           = BIT(28),
+       .n              = _SUNXI_CCU_MULT_MIN(8, 8, 12),
+       .m              = _SUNXI_CCU_DIV(1, 1),
+       .common         = {
+               .reg            = 0x080,
+               .hw.init        = CLK_HW_INIT_PARENTS_DATA("pll-audio1", osc24M,
+                                                          &ccu_nm_ops,
+                                                          CLK_SET_RATE_UNGATE),
+       },
+};
+
+static const struct clk_hw *pll_audio1_hws[] = {
+       &pll_audio1_clk.common.hw
+};
+static SUNXI_CCU_M_HWS(pll_audio1_div2_clk, "pll-audio1-div2",
+                      pll_audio1_hws, 0x080, 16, 3, 0);
+static SUNXI_CCU_M_HWS(pll_audio1_div5_clk, "pll-audio1-div5",
+                      pll_audio1_hws, 0x080, 20, 3, 0);
+
+/*
+ * The CPUX gate is not modelled - it is in a separate register (0x504)
+ * and has a special key field. The clock does not need to be ungated anyway.
+ */
+static const struct clk_parent_data cpux_parents[] = {
+       { .fw_name = "hosc" },
+       { .fw_name = "losc" },
+       { .fw_name = "iosc" },
+       { .hw = &pll_cpux_clk.common.hw },
+       { .hw = &pll_periph0_clk.hw },
+       { .hw = &pll_periph0_2x_clk.common.hw },
+       { .hw = &pll_periph0_800M_clk.common.hw },
+};
+static SUNXI_CCU_MUX_DATA(cpux_clk, "cpux", cpux_parents,
+                         0x500, 24, 3, CLK_SET_RATE_PARENT);
+
+static const struct clk_hw *cpux_hws[] = { &cpux_clk.common.hw };
+static SUNXI_CCU_M_HWS(cpux_axi_clk, "cpux-axi",
+                      cpux_hws, 0x500, 0, 2, 0);
+static SUNXI_CCU_M_HWS(cpux_apb_clk, "cpux-apb",
+                      cpux_hws, 0x500, 8, 2, 0);
+
+static const struct clk_parent_data psi_ahb_parents[] = {
+       { .fw_name = "hosc" },
+       { .fw_name = "losc" },
+       { .fw_name = "iosc" },
+       { .hw = &pll_periph0_clk.hw },
+};
+static SUNXI_CCU_MP_DATA_WITH_MUX(psi_ahb_clk, "psi-ahb", psi_ahb_parents, 0x510,
+                                 0, 2,         /* M */
+                                 8, 2,         /* P */
+                                 24, 2,        /* mux */
+                                 0);
+
+static const struct clk_parent_data apb0_apb1_parents[] = {
+       { .fw_name = "hosc" },
+       { .fw_name = "losc" },
+       { .hw = &psi_ahb_clk.common.hw },
+       { .hw = &pll_periph0_clk.hw },
+};
+static SUNXI_CCU_MP_DATA_WITH_MUX(apb0_clk, "apb0", apb0_apb1_parents, 0x520,
+                                 0, 5,         /* M */
+                                 8, 2,         /* P */
+                                 24, 2,        /* mux */
+                                 0);
+
+static SUNXI_CCU_MP_DATA_WITH_MUX(apb1_clk, "apb1", apb0_apb1_parents, 0x524,
+                                 0, 5,         /* M */
+                                 8, 2,         /* P */
+                                 24, 2,        /* mux */
+                                 0);
+
+static const struct clk_hw *psi_ahb_hws[] = { &psi_ahb_clk.common.hw };
+static const struct clk_hw *apb0_hws[] = { &apb0_clk.common.hw };
+static const struct clk_hw *apb1_hws[] = { &apb1_clk.common.hw };
+
+static const struct clk_hw *de_di_g2d_parents[] = {
+       &pll_periph0_2x_clk.common.hw,
+       &pll_video0_4x_clk.common.hw,
+       &pll_video1_4x_clk.common.hw,
+       &pll_audio1_div2_clk.common.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(de_clk, "de", de_di_g2d_parents, 0x600,
+                                   0, 5,       /* M */
+                                   24, 3,      /* mux */
+                                   BIT(31),    /* gate */
+                                   CLK_SET_RATE_PARENT);
+
+static SUNXI_CCU_GATE_HWS(bus_de_clk, "bus-de", psi_ahb_hws,
+                         0x60c, BIT(0), 0);
+
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(di_clk, "di", de_di_g2d_parents, 0x620,
+                                   0, 5,       /* M */
+                                   24, 3,      /* mux */
+                                   BIT(31),    /* gate */
+                                   CLK_SET_RATE_PARENT);
+
+static SUNXI_CCU_GATE_HWS(bus_di_clk, "bus-di", psi_ahb_hws,
+                         0x62c, BIT(0), 0);
+
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(g2d_clk, "g2d", de_di_g2d_parents, 0x630,
+                                   0, 5,       /* M */
+                                   24, 3,      /* mux */
+                                   BIT(31),    /* gate */
+                                   0);
+
+static SUNXI_CCU_GATE_HWS(bus_g2d_clk, "bus-g2d", psi_ahb_hws,
+                         0x63c, BIT(0), 0);
+
+static const struct clk_parent_data ce_parents[] = {
+       { .fw_name = "hosc" },
+       { .hw = &pll_periph0_2x_clk.common.hw },
+       { .hw = &pll_periph0_clk.hw },
+};
+static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(ce_clk, "ce", ce_parents, 0x680,
+                                      0, 4,    /* M */
+                                      8, 2,    /* P */
+                                      24, 3,   /* mux */
+                                      BIT(31), /* gate */
+                                      0);
+
+static SUNXI_CCU_GATE_HWS(bus_ce_clk, "bus-ce", psi_ahb_hws,
+                         0x68c, BIT(0), 0);
+
+static const struct clk_hw *ve_parents[] = {
+       &pll_ve_clk.common.hw,
+       &pll_periph0_2x_clk.common.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(ve_clk, "ve", ve_parents, 0x690,
+                                   0, 5,       /* M */
+                                   24, 1,      /* mux */
+                                   BIT(31),    /* gate */
+                                   CLK_SET_RATE_PARENT);
+
+static SUNXI_CCU_GATE_HWS(bus_ve_clk, "bus-ve", psi_ahb_hws,
+                         0x69c, BIT(0), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_dma_clk, "bus-dma", psi_ahb_hws,
+                         0x70c, BIT(0), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_msgbox0_clk, "bus-msgbox0", psi_ahb_hws,
+                         0x71c, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_msgbox1_clk, "bus-msgbox1", psi_ahb_hws,
+                         0x71c, BIT(1), 0);
+static SUNXI_CCU_GATE_HWS(bus_msgbox2_clk, "bus-msgbox2", psi_ahb_hws,
+                         0x71c, BIT(2), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_spinlock_clk, "bus-spinlock", psi_ahb_hws,
+                         0x72c, BIT(0), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_hstimer_clk, "bus-hstimer", psi_ahb_hws,
+                         0x73c, BIT(0), 0);
+
+static SUNXI_CCU_GATE_DATA(avs_clk, "avs", osc24M,
+                          0x740, BIT(31), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_dbg_clk, "bus-dbg", psi_ahb_hws,
+                         0x78c, BIT(0), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_pwm_clk, "bus-pwm", apb0_hws,
+                         0x7ac, BIT(0), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_iommu_clk, "bus-iommu", apb0_hws,
+                         0x7bc, BIT(0), 0);
+
+static const struct clk_hw *dram_parents[] = {
+       &pll_ddr0_clk.common.hw,
+       &pll_audio1_div2_clk.common.hw,
+       &pll_periph0_2x_clk.common.hw,
+       &pll_periph0_800M_clk.common.hw,
+};
+static SUNXI_CCU_MP_HW_WITH_MUX_GATE(dram_clk, "dram", dram_parents, 0x800,
+                                    0, 2,      /* M */
+                                    8, 2,      /* P */
+                                    24, 2,     /* mux */
+                                    BIT(31), CLK_IS_CRITICAL);
+
+static CLK_FIXED_FACTOR_HW(mbus_clk, "mbus",
+                          &dram_clk.common.hw, 4, 1, 0);
+
+static const struct clk_hw *mbus_hws[] = { &mbus_clk.hw };
+
+static SUNXI_CCU_GATE_HWS(mbus_dma_clk, "mbus-dma", mbus_hws,
+                         0x804, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(mbus_ve_clk, "mbus-ve", mbus_hws,
+                         0x804, BIT(1), 0);
+static SUNXI_CCU_GATE_HWS(mbus_ce_clk, "mbus-ce", mbus_hws,
+                         0x804, BIT(2), 0);
+static SUNXI_CCU_GATE_HWS(mbus_tvin_clk, "mbus-tvin", mbus_hws,
+                         0x804, BIT(7), 0);
+static SUNXI_CCU_GATE_HWS(mbus_csi_clk, "mbus-csi", mbus_hws,
+                         0x804, BIT(8), 0);
+static SUNXI_CCU_GATE_HWS(mbus_g2d_clk, "mbus-g2d", mbus_hws,
+                         0x804, BIT(10), 0);
+static SUNXI_CCU_GATE_HWS(mbus_riscv_clk, "mbus-riscv", mbus_hws,
+                         0x804, BIT(11), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_dram_clk, "bus-dram", psi_ahb_hws,
+                         0x80c, BIT(0), CLK_IS_CRITICAL);
+
+static const struct clk_parent_data mmc0_mmc1_parents[] = {
+       { .fw_name = "hosc" },
+       { .hw = &pll_periph0_clk.hw },
+       { .hw = &pll_periph0_2x_clk.common.hw },
+       { .hw = &pll_audio1_div2_clk.common.hw },
+};
+static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(mmc0_clk, "mmc0", mmc0_mmc1_parents, 0x830,
+                                      0, 4,    /* M */
+                                      8, 2,    /* P */
+                                      24, 3,   /* mux */
+                                      BIT(31), /* gate */
+                                      0);
+
+static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(mmc1_clk, "mmc1", mmc0_mmc1_parents, 0x834,
+                                      0, 4,    /* M */
+                                      8, 2,    /* P */
+                                      24, 3,   /* mux */
+                                      BIT(31), /* gate */
+                                      0);
+
+static const struct clk_parent_data mmc2_parents[] = {
+       { .fw_name = "hosc" },
+       { .hw = &pll_periph0_clk.hw },
+       { .hw = &pll_periph0_2x_clk.common.hw },
+       { .hw = &pll_periph0_800M_clk.common.hw },
+       { .hw = &pll_audio1_div2_clk.common.hw },
+};
+static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(mmc2_clk, "mmc2", mmc2_parents, 0x838,
+                                      0, 4,    /* M */
+                                      8, 2,    /* P */
+                                      24, 3,   /* mux */
+                                      BIT(31), /* gate */
+                                      0);
+
+static SUNXI_CCU_GATE_HWS(bus_mmc0_clk, "bus-mmc0", psi_ahb_hws,
+                         0x84c, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_mmc1_clk, "bus-mmc1", psi_ahb_hws,
+                         0x84c, BIT(1), 0);
+static SUNXI_CCU_GATE_HWS(bus_mmc2_clk, "bus-mmc2", psi_ahb_hws,
+                         0x84c, BIT(2), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_uart0_clk, "bus-uart0", apb1_hws,
+                         0x90c, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_uart1_clk, "bus-uart1", apb1_hws,
+                         0x90c, BIT(1), 0);
+static SUNXI_CCU_GATE_HWS(bus_uart2_clk, "bus-uart2", apb1_hws,
+                         0x90c, BIT(2), 0);
+static SUNXI_CCU_GATE_HWS(bus_uart3_clk, "bus-uart3", apb1_hws,
+                         0x90c, BIT(3), 0);
+static SUNXI_CCU_GATE_HWS(bus_uart4_clk, "bus-uart4", apb1_hws,
+                         0x90c, BIT(4), 0);
+static SUNXI_CCU_GATE_HWS(bus_uart5_clk, "bus-uart5", apb1_hws,
+                         0x90c, BIT(5), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_i2c0_clk, "bus-i2c0", apb1_hws,
+                         0x91c, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_i2c1_clk, "bus-i2c1", apb1_hws,
+                         0x91c, BIT(1), 0);
+static SUNXI_CCU_GATE_HWS(bus_i2c2_clk, "bus-i2c2", apb1_hws,
+                         0x91c, BIT(2), 0);
+static SUNXI_CCU_GATE_HWS(bus_i2c3_clk, "bus-i2c3", apb1_hws,
+                         0x91c, BIT(3), 0);
+
+static const struct clk_parent_data spi_parents[] = {
+       { .fw_name = "hosc" },
+       { .hw = &pll_periph0_clk.hw },
+       { .hw = &pll_periph0_2x_clk.common.hw },
+       { .hw = &pll_audio1_div2_clk.common.hw },
+       { .hw = &pll_audio1_div5_clk.common.hw },
+};
+static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(spi0_clk, "spi0", spi_parents, 0x940,
+                                      0, 4,    /* M */
+                                      8, 2,    /* P */
+                                      24, 3,   /* mux */
+                                      BIT(31), /* gate */
+                                      0);
+
+static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(spi1_clk, "spi1", spi_parents, 0x944,
+                                      0, 4,    /* M */
+                                      8, 2,    /* P */
+                                      24, 3,   /* mux */
+                                      BIT(31), /* gate */
+                                      0);
+
+static SUNXI_CCU_GATE_HWS(bus_spi0_clk, "bus-spi0", psi_ahb_hws,
+                         0x96c, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_spi1_clk, "bus-spi1", psi_ahb_hws,
+                         0x96c, BIT(1), 0);
+
+static SUNXI_CCU_GATE_HWS_WITH_PREDIV(emac_25M_clk, "emac-25M", pll_periph0_hws,
+                                     0x970, BIT(31) | BIT(30), 24, 0);
+
+static SUNXI_CCU_GATE_HWS(bus_emac_clk, "bus-emac", psi_ahb_hws,
+                         0x97c, BIT(0), 0);
+
+static const struct clk_parent_data ir_tx_ledc_parents[] = {
+       { .fw_name = "hosc" },
+       { .hw = &pll_periph0_clk.hw },
+};
+static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(ir_tx_clk, "ir-tx", ir_tx_ledc_parents, 0x9c0,
+                                      0, 4,    /* M */
+                                      8, 2,    /* P */
+                                      24, 3,   /* mux */
+                                      BIT(31), /* gate */
+                                      0);
+
+static SUNXI_CCU_GATE_HWS(bus_ir_tx_clk, "bus-ir-tx", apb0_hws,
+                         0x9cc, BIT(0), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_gpadc_clk, "bus-gpadc", apb0_hws,
+                         0x9ec, BIT(0), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_ths_clk, "bus-ths", apb0_hws,
+                         0x9fc, BIT(0), 0);
+
+static const struct clk_hw *i2s_spdif_tx_parents[] = {
+       &pll_audio0_clk.hw,
+       &pll_audio0_4x_clk.common.hw,
+       &pll_audio1_div2_clk.common.hw,
+       &pll_audio1_div5_clk.common.hw,
+};
+static SUNXI_CCU_MP_HW_WITH_MUX_GATE(i2s0_clk, "i2s0", i2s_spdif_tx_parents, 0xa10,
+                                    0, 5,      /* M */
+                                    8, 2,      /* P */
+                                    24, 3,     /* mux */
+                                    BIT(31),   /* gate */
+                                    0);
+
+static SUNXI_CCU_MP_HW_WITH_MUX_GATE(i2s1_clk, "i2s1", i2s_spdif_tx_parents, 0xa14,
+                                    0, 5,      /* M */
+                                    8, 2,      /* P */
+                                    24, 3,     /* mux */
+                                    BIT(31),   /* gate */
+                                    0);
+
+static SUNXI_CCU_MP_HW_WITH_MUX_GATE(i2s2_clk, "i2s2", i2s_spdif_tx_parents, 0xa18,
+                                    0, 5,      /* M */
+                                    8, 2,      /* P */
+                                    24, 3,     /* mux */
+                                    BIT(31),   /* gate */
+                                    0);
+
+static const struct clk_hw *i2s2_asrc_parents[] = {
+       &pll_audio0_4x_clk.common.hw,
+       &pll_periph0_clk.hw,
+       &pll_audio1_div2_clk.common.hw,
+       &pll_audio1_div5_clk.common.hw,
+};
+static SUNXI_CCU_MP_HW_WITH_MUX_GATE(i2s2_asrc_clk, "i2s2-asrc", i2s2_asrc_parents, 0xa1c,
+                                    0, 5,      /* M */
+                                    8, 2,      /* P */
+                                    24, 3,     /* mux */
+                                    BIT(31),   /* gate */
+                                    0);
+
+static SUNXI_CCU_GATE_HWS(bus_i2s0_clk, "bus-i2s0", apb0_hws,
+                         0xa20, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_i2s1_clk, "bus-i2s1", apb0_hws,
+                         0xa20, BIT(1), 0);
+static SUNXI_CCU_GATE_HWS(bus_i2s2_clk, "bus-i2s2", apb0_hws,
+                         0xa20, BIT(2), 0);
+
+static SUNXI_CCU_MP_HW_WITH_MUX_GATE(spdif_tx_clk, "spdif-tx", i2s_spdif_tx_parents, 0xa24,
+                                    0, 5,      /* M */
+                                    8, 2,      /* P */
+                                    24, 3,     /* mux */
+                                    BIT(31),   /* gate */
+                                    0);
+
+static const struct clk_hw *spdif_rx_parents[] = {
+       &pll_periph0_clk.hw,
+       &pll_audio1_div2_clk.common.hw,
+       &pll_audio1_div5_clk.common.hw,
+};
+static SUNXI_CCU_MP_HW_WITH_MUX_GATE(spdif_rx_clk, "spdif-rx", spdif_rx_parents, 0xa28,
+                                    0, 5,      /* M */
+                                    8, 2,      /* P */
+                                    24, 3,     /* mux */
+                                    BIT(31),   /* gate */
+                                    0);
+
+static SUNXI_CCU_GATE_HWS(bus_spdif_clk, "bus-spdif", apb0_hws,
+                         0xa2c, BIT(0), 0);
+
+static const struct clk_hw *dmic_codec_parents[] = {
+       &pll_audio0_clk.hw,
+       &pll_audio1_div2_clk.common.hw,
+       &pll_audio1_div5_clk.common.hw,
+};
+static SUNXI_CCU_MP_HW_WITH_MUX_GATE(dmic_clk, "dmic", dmic_codec_parents, 0xa40,
+                                    0, 5,      /* M */
+                                    8, 2,      /* P */
+                                    24, 3,     /* mux */
+                                    BIT(31),   /* gate */
+                                    0);
+
+static SUNXI_CCU_GATE_HWS(bus_dmic_clk, "bus-dmic", apb0_hws,
+                         0xa4c, BIT(0), 0);
+
+static SUNXI_CCU_MP_HW_WITH_MUX_GATE(audio_dac_clk, "audio-dac", dmic_codec_parents, 0xa50,
+                                    0, 5,      /* M */
+                                    8, 2,      /* P */
+                                    24, 3,     /* mux */
+                                    BIT(31),   /* gate */
+                                    0);
+
+static SUNXI_CCU_MP_HW_WITH_MUX_GATE(audio_adc_clk, "audio-adc", dmic_codec_parents, 0xa54,
+                                    0, 5,      /* M */
+                                    8, 2,      /* P */
+                                    24, 3,     /* mux */
+                                    BIT(31),   /* gate */
+                                    0);
+
+static SUNXI_CCU_GATE_HWS(bus_audio_clk, "bus-audio", apb0_hws,
+                         0xa5c, BIT(0), 0);
+
+
+/*
+ * The first parent is a 48 MHz input clock divided by 4. That 48 MHz clock is
+ * a 2x multiplier from osc24M synchronized by pll-periph0, and is also used by
+ * the OHCI module.
+ */
+static const struct clk_parent_data usb_ohci_parents[] = {
+       { .hw = &pll_periph0_clk.hw },
+       { .fw_name = "hosc" },
+       { .fw_name = "losc" },
+};
+static const struct ccu_mux_fixed_prediv usb_ohci_predivs[] = {
+       { .index = 0, .div = 50 },
+       { .index = 1, .div = 2 },
+};
+
+static struct ccu_mux usb_ohci0_clk = {
+       .enable         = BIT(31),
+       .mux            = {
+               .shift          = 24,
+               .width          = 2,
+               .fixed_predivs  = usb_ohci_predivs,
+               .n_predivs      = ARRAY_SIZE(usb_ohci_predivs),
+       },
+       .common         = {
+               .reg            = 0xa70,
+               .features       = CCU_FEATURE_FIXED_PREDIV,
+               .hw.init        = CLK_HW_INIT_PARENTS_DATA("usb-ohci0",
+                                                          usb_ohci_parents,
+                                                          &ccu_mux_ops,
+                                                          0),
+       },
+};
+
+static struct ccu_mux usb_ohci1_clk = {
+       .enable         = BIT(31),
+       .mux            = {
+               .shift          = 24,
+               .width          = 2,
+               .fixed_predivs  = usb_ohci_predivs,
+               .n_predivs      = ARRAY_SIZE(usb_ohci_predivs),
+       },
+       .common         = {
+               .reg            = 0xa74,
+               .features       = CCU_FEATURE_FIXED_PREDIV,
+               .hw.init        = CLK_HW_INIT_PARENTS_DATA("usb-ohci1",
+                                                          usb_ohci_parents,
+                                                          &ccu_mux_ops,
+                                                          0),
+       },
+};
+
+static SUNXI_CCU_GATE_HWS(bus_ohci0_clk, "bus-ohci0", psi_ahb_hws,
+                         0xa8c, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_ohci1_clk, "bus-ohci1", psi_ahb_hws,
+                         0xa8c, BIT(1), 0);
+static SUNXI_CCU_GATE_HWS(bus_ehci0_clk, "bus-ehci0", psi_ahb_hws,
+                         0xa8c, BIT(4), 0);
+static SUNXI_CCU_GATE_HWS(bus_ehci1_clk, "bus-ehci1", psi_ahb_hws,
+                         0xa8c, BIT(5), 0);
+static SUNXI_CCU_GATE_HWS(bus_otg_clk, "bus-otg", psi_ahb_hws,
+                         0xa8c, BIT(8), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_lradc_clk, "bus-lradc", apb0_hws,
+                         0xa9c, BIT(0), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_dpss_top_clk, "bus-dpss-top", psi_ahb_hws,
+                         0xabc, BIT(0), 0);
+
+static SUNXI_CCU_GATE_DATA(hdmi_24M_clk, "hdmi-24M", osc24M,
+                          0xb04, BIT(31), 0);
+
+static SUNXI_CCU_GATE_HWS_WITH_PREDIV(hdmi_cec_32k_clk, "hdmi-cec-32k",
+                                     pll_periph0_2x_hws,
+                                     0xb10, BIT(30), 36621, 0);
+
+static const struct clk_parent_data hdmi_cec_parents[] = {
+       { .fw_name = "losc" },
+       { .hw = &hdmi_cec_32k_clk.common.hw },
+};
+static SUNXI_CCU_MUX_DATA_WITH_GATE(hdmi_cec_clk, "hdmi-cec", hdmi_cec_parents, 0xb10,
+                                   24, 1,      /* mux */
+                                   BIT(31),    /* gate */
+                                   0);
+
+static SUNXI_CCU_GATE_HWS(bus_hdmi_clk, "bus-hdmi", psi_ahb_hws,
+                         0xb1c, BIT(0), 0);
+
+static const struct clk_parent_data mipi_dsi_parents[] = {
+       { .fw_name = "hosc" },
+       { .hw = &pll_periph0_clk.hw },
+       { .hw = &pll_video0_2x_clk.hw },
+       { .hw = &pll_video1_2x_clk.hw },
+       { .hw = &pll_audio1_div2_clk.common.hw },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(mipi_dsi_clk, "mipi-dsi", mipi_dsi_parents, 0xb24,
+                                     0, 4,     /* M */
+                                     24, 3,    /* mux */
+                                     BIT(31),  /* gate */
+                                     CLK_SET_RATE_PARENT);
+
+static SUNXI_CCU_GATE_HWS(bus_mipi_dsi_clk, "bus-mipi-dsi", psi_ahb_hws,
+                         0xb4c, BIT(0), 0);
+
+static const struct clk_hw *tcon_tve_parents[] = {
+       &pll_video0_clk.hw,
+       &pll_video0_4x_clk.common.hw,
+       &pll_video1_clk.hw,
+       &pll_video1_4x_clk.common.hw,
+       &pll_periph0_2x_clk.common.hw,
+       &pll_audio1_div2_clk.common.hw,
+};
+static SUNXI_CCU_MP_HW_WITH_MUX_GATE(tcon_lcd0_clk, "tcon-lcd0", tcon_tve_parents, 0xb60,
+                                    0, 4,      /* M */
+                                    8, 2,      /* P */
+                                    24, 3,     /* mux */
+                                    BIT(31),   /* gate */
+                                    CLK_SET_RATE_PARENT);
+
+static SUNXI_CCU_GATE_HWS(bus_tcon_lcd0_clk, "bus-tcon-lcd0", psi_ahb_hws,
+                         0xb7c, BIT(0), 0);
+
+static SUNXI_CCU_MP_HW_WITH_MUX_GATE(tcon_tv_clk, "tcon-tv", tcon_tve_parents, 0xb80,
+                                    0, 4,      /* M */
+                                    8, 2,      /* P */
+                                    24, 3,     /* mux */
+                                    BIT(31),   /* gate */
+                                    CLK_SET_RATE_PARENT);
+
+static SUNXI_CCU_GATE_HWS(bus_tcon_tv_clk, "bus-tcon-tv", psi_ahb_hws,
+                         0xb9c, BIT(0), 0);
+
+static SUNXI_CCU_MP_HW_WITH_MUX_GATE(tve_clk, "tve", tcon_tve_parents, 0xbb0,
+                                    0, 4,      /* M */
+                                    8, 2,      /* P */
+                                    24, 3,     /* mux */
+                                    BIT(31),   /* gate */
+                                    0);
+
+static SUNXI_CCU_GATE_HWS(bus_tve_top_clk, "bus-tve-top", psi_ahb_hws,
+                         0xbbc, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_tve_clk, "bus-tve", psi_ahb_hws,
+                         0xbbc, BIT(1), 0);
+
+static const struct clk_parent_data tvd_parents[] = {
+       { .fw_name = "hosc" },
+       { .hw = &pll_video0_clk.hw },
+       { .hw = &pll_video1_clk.hw },
+       { .hw = &pll_periph0_clk.hw },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(tvd_clk, "tvd", tvd_parents, 0xbc0,
+                                     0, 5,     /* M */
+                                     24, 3,    /* mux */
+                                     BIT(31),  /* gate */
+                                     0);
+
+static SUNXI_CCU_GATE_HWS(bus_tvd_top_clk, "bus-tvd-top", psi_ahb_hws,
+                         0xbdc, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_tvd_clk, "bus-tvd", psi_ahb_hws,
+                         0xbdc, BIT(1), 0);
+
+static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(ledc_clk, "ledc", ir_tx_ledc_parents, 0xbf0,
+                                      0, 4,    /* M */
+                                      8, 2,    /* P */
+                                      24, 1,   /* mux */
+                                      BIT(31), /* gate */
+                                      0);
+
+static SUNXI_CCU_GATE_HWS(bus_ledc_clk, "bus-ledc", psi_ahb_hws,
+                         0xbfc, BIT(0), 0);
+
+static const struct clk_hw *csi_top_parents[] = {
+       &pll_periph0_2x_clk.common.hw,
+       &pll_video0_2x_clk.hw,
+       &pll_video1_2x_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(csi_top_clk, "csi-top", csi_top_parents, 0xc04,
+                                   0, 4,       /* M */
+                                   24, 3,      /* mux */
+                                   BIT(31),    /* gate */
+                                   0);
+
+static const struct clk_parent_data csi_mclk_parents[] = {
+       { .fw_name = "hosc" },
+       { .hw = &pll_periph0_clk.hw },
+       { .hw = &pll_video0_clk.hw },
+       { .hw = &pll_video1_clk.hw },
+       { .hw = &pll_audio1_div2_clk.common.hw },
+       { .hw = &pll_audio1_div5_clk.common.hw },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(csi_mclk_clk, "csi-mclk", csi_mclk_parents, 0xc08,
+                                     0, 5,     /* M */
+                                     24, 3,    /* mux */
+                                     BIT(31),  /* gate */
+                                     0);
+
+static SUNXI_CCU_GATE_HWS(bus_csi_clk, "bus-csi", psi_ahb_hws,
+                         0xc1c, BIT(0), 0);
+
+static const struct clk_parent_data tpadc_parents[] = {
+       { .fw_name = "hosc" },
+       { .hw = &pll_audio0_clk.hw },
+};
+static SUNXI_CCU_MUX_DATA_WITH_GATE(tpadc_clk, "tpadc", tpadc_parents, 0xc50,
+                                   24, 3,      /* mux */
+                                   BIT(31),    /* gate */
+                                   0);
+
+static SUNXI_CCU_GATE_HWS(bus_tpadc_clk, "bus-tpadc", apb0_hws,
+                         0xc5c, BIT(0), 0);
+
+static SUNXI_CCU_GATE_HWS(bus_tzma_clk, "bus-tzma", apb0_hws,
+                         0xc6c, BIT(0), 0);
+
+static const struct clk_parent_data dsp_parents[] = {
+       { .fw_name = "hosc" },
+       { .fw_name = "losc" },
+       { .fw_name = "iosc" },
+       { .hw = &pll_periph0_2x_clk.common.hw },
+       { .hw = &pll_audio1_div2_clk.common.hw },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(dsp_clk, "dsp", dsp_parents, 0xc70,
+                                     0, 5,     /* M */
+                                     24, 3,    /* mux */
+                                     BIT(31),  /* gate */
+                                     0);
+
+static SUNXI_CCU_GATE_HWS(bus_dsp_cfg_clk, "bus-dsp-cfg", psi_ahb_hws,
+                         0xc7c, BIT(1), 0);
+
+/*
+ * The RISC-V gate is not modelled - it is in a separate register (0xd04)
+ * and has a special key field. The clock is critical anyway.
+ */
+static const struct clk_parent_data riscv_parents[] = {
+       { .fw_name = "hosc" },
+       { .fw_name = "losc" },
+       { .fw_name = "iosc" },
+       { .hw = &pll_periph0_800M_clk.common.hw },
+       { .hw = &pll_periph0_clk.hw },
+       { .hw = &pll_cpux_clk.common.hw },
+       { .hw = &pll_audio1_div2_clk.common.hw },
+};
+static SUNXI_CCU_M_DATA_WITH_MUX(riscv_clk, "riscv", riscv_parents, 0xd00,
+                                0, 5,  /* M */
+                                24, 3, /* mux */
+                                CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
+
+/* The riscv-axi clk must be divided by at least 2. */
+static struct clk_div_table riscv_axi_table[] = {
+       { .val = 1, .div = 2 },
+       { .val = 2, .div = 3 },
+       { .val = 3, .div = 4 },
+       { /* Sentinel */ }
+};
+static SUNXI_CCU_DIV_TABLE_HW(riscv_axi_clk, "riscv-axi", &riscv_clk.common.hw,
+                             0xd00, 8, 2, riscv_axi_table, 0);
+
+static SUNXI_CCU_GATE_HWS(bus_riscv_cfg_clk, "bus-riscv-cfg", psi_ahb_hws,
+                         0xd0c, BIT(0), CLK_IS_CRITICAL);
+
+static SUNXI_CCU_GATE_DATA(fanout_24M_clk, "fanout-24M", osc24M,
+                          0xf30, BIT(0), 0);
+static SUNXI_CCU_GATE_DATA_WITH_PREDIV(fanout_12M_clk, "fanout-12M", osc24M,
+                                      0xf30, BIT(1), 2, 0);
+static SUNXI_CCU_GATE_HWS_WITH_PREDIV(fanout_16M_clk, "fanout-16M", pll_periph0_2x_hws,
+                                     0xf30, BIT(2), 75, 0);
+static SUNXI_CCU_GATE_HWS_WITH_PREDIV(fanout_25M_clk, "fanout-25M", pll_periph0_hws,
+                                     0xf30, BIT(3), 24, 0);
+static SUNXI_CCU_GATE_HWS_WITH_PREDIV(fanout_32k_clk, "fanout-32k", pll_periph0_2x_hws,
+                                     0xf30, BIT(4), 36621, 0);
+
+/* This clock has a second divider that is not modelled and forced to 0. */
+#define SUN20I_D1_FANOUT_27M_REG       0xf34
+static const struct clk_hw *fanout_27M_parents[] = {
+       &pll_video0_clk.hw,
+       &pll_video1_clk.hw,
+};
+static SUNXI_CCU_M_HW_WITH_MUX_GATE(fanout_27M_clk, "fanout-27M", fanout_27M_parents, 0xf34,
+                                   0, 5,       /* M */
+                                   24, 2,      /* mux */
+                                   BIT(31),    /* gate */
+                                   0);
+
+static SUNXI_CCU_M_HWS_WITH_GATE(fanout_pclk_clk, "fanout-pclk", apb0_hws, 0xf38,
+                                0, 5,          /* M */
+                                BIT(31),       /* gate */
+                                0);
+
+static const struct clk_hw *fanout_parents[] = {
+       &fanout_32k_clk.common.hw,
+       &fanout_12M_clk.common.hw,
+       &fanout_16M_clk.common.hw,
+       &fanout_24M_clk.common.hw,
+       &fanout_25M_clk.common.hw,
+       &fanout_27M_clk.common.hw,
+       &fanout_pclk_clk.common.hw,
+};
+static SUNXI_CCU_MUX_HW_WITH_GATE(fanout0_clk, "fanout0", fanout_parents, 0xf3c,
+                                 0, 3,         /* mux */
+                                 BIT(21),      /* gate */
+                                 0);
+static SUNXI_CCU_MUX_HW_WITH_GATE(fanout1_clk, "fanout1", fanout_parents, 0xf3c,
+                                 3, 3,         /* mux */
+                                 BIT(22),      /* gate */
+                                 0);
+static SUNXI_CCU_MUX_HW_WITH_GATE(fanout2_clk, "fanout2", fanout_parents, 0xf3c,
+                                 6, 3,         /* mux */
+                                 BIT(23),      /* gate */
+                                 0);
+
+static struct ccu_common *sun20i_d1_ccu_clks[] = {
+       &pll_cpux_clk.common,
+       &pll_ddr0_clk.common,
+       &pll_periph0_4x_clk.common,
+       &pll_periph0_2x_clk.common,
+       &pll_periph0_800M_clk.common,
+       &pll_video0_4x_clk.common,
+       &pll_video1_4x_clk.common,
+       &pll_ve_clk.common,
+       &pll_audio0_4x_clk.common,
+       &pll_audio1_clk.common,
+       &pll_audio1_div2_clk.common,
+       &pll_audio1_div5_clk.common,
+       &cpux_clk.common,
+       &cpux_axi_clk.common,
+       &cpux_apb_clk.common,
+       &psi_ahb_clk.common,
+       &apb0_clk.common,
+       &apb1_clk.common,
+       &de_clk.common,
+       &bus_de_clk.common,
+       &di_clk.common,
+       &bus_di_clk.common,
+       &g2d_clk.common,
+       &bus_g2d_clk.common,
+       &ce_clk.common,
+       &bus_ce_clk.common,
+       &ve_clk.common,
+       &bus_ve_clk.common,
+       &bus_dma_clk.common,
+       &bus_msgbox0_clk.common,
+       &bus_msgbox1_clk.common,
+       &bus_msgbox2_clk.common,
+       &bus_spinlock_clk.common,
+       &bus_hstimer_clk.common,
+       &avs_clk.common,
+       &bus_dbg_clk.common,
+       &bus_pwm_clk.common,
+       &bus_iommu_clk.common,
+       &dram_clk.common,
+       &mbus_dma_clk.common,
+       &mbus_ve_clk.common,
+       &mbus_ce_clk.common,
+       &mbus_tvin_clk.common,
+       &mbus_csi_clk.common,
+       &mbus_g2d_clk.common,
+       &mbus_riscv_clk.common,
+       &bus_dram_clk.common,
+       &mmc0_clk.common,
+       &mmc1_clk.common,
+       &mmc2_clk.common,
+       &bus_mmc0_clk.common,
+       &bus_mmc1_clk.common,
+       &bus_mmc2_clk.common,
+       &bus_uart0_clk.common,
+       &bus_uart1_clk.common,
+       &bus_uart2_clk.common,
+       &bus_uart3_clk.common,
+       &bus_uart4_clk.common,
+       &bus_uart5_clk.common,
+       &bus_i2c0_clk.common,
+       &bus_i2c1_clk.common,
+       &bus_i2c2_clk.common,
+       &bus_i2c3_clk.common,
+       &spi0_clk.common,
+       &spi1_clk.common,
+       &bus_spi0_clk.common,
+       &bus_spi1_clk.common,
+       &emac_25M_clk.common,
+       &bus_emac_clk.common,
+       &ir_tx_clk.common,
+       &bus_ir_tx_clk.common,
+       &bus_gpadc_clk.common,
+       &bus_ths_clk.common,
+       &i2s0_clk.common,
+       &i2s1_clk.common,
+       &i2s2_clk.common,
+       &i2s2_asrc_clk.common,
+       &bus_i2s0_clk.common,
+       &bus_i2s1_clk.common,
+       &bus_i2s2_clk.common,
+       &spdif_tx_clk.common,
+       &spdif_rx_clk.common,
+       &bus_spdif_clk.common,
+       &dmic_clk.common,
+       &bus_dmic_clk.common,
+       &audio_dac_clk.common,
+       &audio_adc_clk.common,
+       &bus_audio_clk.common,
+       &usb_ohci0_clk.common,
+       &usb_ohci1_clk.common,
+       &bus_ohci0_clk.common,
+       &bus_ohci1_clk.common,
+       &bus_ehci0_clk.common,
+       &bus_ehci1_clk.common,
+       &bus_otg_clk.common,
+       &bus_lradc_clk.common,
+       &bus_dpss_top_clk.common,
+       &hdmi_24M_clk.common,
+       &hdmi_cec_32k_clk.common,
+       &hdmi_cec_clk.common,
+       &bus_hdmi_clk.common,
+       &mipi_dsi_clk.common,
+       &bus_mipi_dsi_clk.common,
+       &tcon_lcd0_clk.common,
+       &bus_tcon_lcd0_clk.common,
+       &tcon_tv_clk.common,
+       &bus_tcon_tv_clk.common,
+       &tve_clk.common,
+       &bus_tve_top_clk.common,
+       &bus_tve_clk.common,
+       &tvd_clk.common,
+       &bus_tvd_top_clk.common,
+       &bus_tvd_clk.common,
+       &ledc_clk.common,
+       &bus_ledc_clk.common,
+       &csi_top_clk.common,
+       &csi_mclk_clk.common,
+       &bus_csi_clk.common,
+       &tpadc_clk.common,
+       &bus_tpadc_clk.common,
+       &bus_tzma_clk.common,
+       &dsp_clk.common,
+       &bus_dsp_cfg_clk.common,
+       &riscv_clk.common,
+       &riscv_axi_clk.common,
+       &bus_riscv_cfg_clk.common,
+       &fanout_24M_clk.common,
+       &fanout_12M_clk.common,
+       &fanout_16M_clk.common,
+       &fanout_25M_clk.common,
+       &fanout_32k_clk.common,
+       &fanout_27M_clk.common,
+       &fanout_pclk_clk.common,
+       &fanout0_clk.common,
+       &fanout1_clk.common,
+       &fanout2_clk.common,
+};
+
+static struct clk_hw_onecell_data sun20i_d1_hw_clks = {
+       .num    = CLK_NUMBER,
+       .hws    = {
+               [CLK_PLL_CPUX]          = &pll_cpux_clk.common.hw,
+               [CLK_PLL_DDR0]          = &pll_ddr0_clk.common.hw,
+               [CLK_PLL_PERIPH0_4X]    = &pll_periph0_4x_clk.common.hw,
+               [CLK_PLL_PERIPH0_2X]    = &pll_periph0_2x_clk.common.hw,
+               [CLK_PLL_PERIPH0_800M]  = &pll_periph0_800M_clk.common.hw,
+               [CLK_PLL_PERIPH0]       = &pll_periph0_clk.hw,
+               [CLK_PLL_PERIPH0_DIV3]  = &pll_periph0_div3_clk.hw,
+               [CLK_PLL_VIDEO0_4X]     = &pll_video0_4x_clk.common.hw,
+               [CLK_PLL_VIDEO0_2X]     = &pll_video0_2x_clk.hw,
+               [CLK_PLL_VIDEO0]        = &pll_video0_clk.hw,
+               [CLK_PLL_VIDEO1_4X]     = &pll_video1_4x_clk.common.hw,
+               [CLK_PLL_VIDEO1_2X]     = &pll_video1_2x_clk.hw,
+               [CLK_PLL_VIDEO1]        = &pll_video1_clk.hw,
+               [CLK_PLL_VE]            = &pll_ve_clk.common.hw,
+               [CLK_PLL_AUDIO0_4X]     = &pll_audio0_4x_clk.common.hw,
+               [CLK_PLL_AUDIO0_2X]     = &pll_audio0_2x_clk.hw,
+               [CLK_PLL_AUDIO0]        = &pll_audio0_clk.hw,
+               [CLK_PLL_AUDIO1]        = &pll_audio1_clk.common.hw,
+               [CLK_PLL_AUDIO1_DIV2]   = &pll_audio1_div2_clk.common.hw,
+               [CLK_PLL_AUDIO1_DIV5]   = &pll_audio1_div5_clk.common.hw,
+               [CLK_CPUX]              = &cpux_clk.common.hw,
+               [CLK_CPUX_AXI]          = &cpux_axi_clk.common.hw,
+               [CLK_CPUX_APB]          = &cpux_apb_clk.common.hw,
+               [CLK_PSI_AHB]           = &psi_ahb_clk.common.hw,
+               [CLK_APB0]              = &apb0_clk.common.hw,
+               [CLK_APB1]              = &apb1_clk.common.hw,
+               [CLK_MBUS]              = &mbus_clk.hw,
+               [CLK_DE]                = &de_clk.common.hw,
+               [CLK_BUS_DE]            = &bus_de_clk.common.hw,
+               [CLK_DI]                = &di_clk.common.hw,
+               [CLK_BUS_DI]            = &bus_di_clk.common.hw,
+               [CLK_G2D]               = &g2d_clk.common.hw,
+               [CLK_BUS_G2D]           = &bus_g2d_clk.common.hw,
+               [CLK_CE]                = &ce_clk.common.hw,
+               [CLK_BUS_CE]            = &bus_ce_clk.common.hw,
+               [CLK_VE]                = &ve_clk.common.hw,
+               [CLK_BUS_VE]            = &bus_ve_clk.common.hw,
+               [CLK_BUS_DMA]           = &bus_dma_clk.common.hw,
+               [CLK_BUS_MSGBOX0]       = &bus_msgbox0_clk.common.hw,
+               [CLK_BUS_MSGBOX1]       = &bus_msgbox1_clk.common.hw,
+               [CLK_BUS_MSGBOX2]       = &bus_msgbox2_clk.common.hw,
+               [CLK_BUS_SPINLOCK]      = &bus_spinlock_clk.common.hw,
+               [CLK_BUS_HSTIMER]       = &bus_hstimer_clk.common.hw,
+               [CLK_AVS]               = &avs_clk.common.hw,
+               [CLK_BUS_DBG]           = &bus_dbg_clk.common.hw,
+               [CLK_BUS_PWM]           = &bus_pwm_clk.common.hw,
+               [CLK_BUS_IOMMU]         = &bus_iommu_clk.common.hw,
+               [CLK_DRAM]              = &dram_clk.common.hw,
+               [CLK_MBUS_DMA]          = &mbus_dma_clk.common.hw,
+               [CLK_MBUS_VE]           = &mbus_ve_clk.common.hw,
+               [CLK_MBUS_CE]           = &mbus_ce_clk.common.hw,
+               [CLK_MBUS_TVIN]         = &mbus_tvin_clk.common.hw,
+               [CLK_MBUS_CSI]          = &mbus_csi_clk.common.hw,
+               [CLK_MBUS_G2D]          = &mbus_g2d_clk.common.hw,
+               [CLK_MBUS_RISCV]        = &mbus_riscv_clk.common.hw,
+               [CLK_BUS_DRAM]          = &bus_dram_clk.common.hw,
+               [CLK_MMC0]              = &mmc0_clk.common.hw,
+               [CLK_MMC1]              = &mmc1_clk.common.hw,
+               [CLK_MMC2]              = &mmc2_clk.common.hw,
+               [CLK_BUS_MMC0]          = &bus_mmc0_clk.common.hw,
+               [CLK_BUS_MMC1]          = &bus_mmc1_clk.common.hw,
+               [CLK_BUS_MMC2]          = &bus_mmc2_clk.common.hw,
+               [CLK_BUS_UART0]         = &bus_uart0_clk.common.hw,
+               [CLK_BUS_UART1]         = &bus_uart1_clk.common.hw,
+               [CLK_BUS_UART2]         = &bus_uart2_clk.common.hw,
+               [CLK_BUS_UART3]         = &bus_uart3_clk.common.hw,
+               [CLK_BUS_UART4]         = &bus_uart4_clk.common.hw,
+               [CLK_BUS_UART5]         = &bus_uart5_clk.common.hw,
+               [CLK_BUS_I2C0]          = &bus_i2c0_clk.common.hw,
+               [CLK_BUS_I2C1]          = &bus_i2c1_clk.common.hw,
+               [CLK_BUS_I2C2]          = &bus_i2c2_clk.common.hw,
+               [CLK_BUS_I2C3]          = &bus_i2c3_clk.common.hw,
+               [CLK_SPI0]              = &spi0_clk.common.hw,
+               [CLK_SPI1]              = &spi1_clk.common.hw,
+               [CLK_BUS_SPI0]          = &bus_spi0_clk.common.hw,
+               [CLK_BUS_SPI1]          = &bus_spi1_clk.common.hw,
+               [CLK_EMAC_25M]          = &emac_25M_clk.common.hw,
+               [CLK_BUS_EMAC]          = &bus_emac_clk.common.hw,
+               [CLK_IR_TX]             = &ir_tx_clk.common.hw,
+               [CLK_BUS_IR_TX]         = &bus_ir_tx_clk.common.hw,
+               [CLK_BUS_GPADC]         = &bus_gpadc_clk.common.hw,
+               [CLK_BUS_THS]           = &bus_ths_clk.common.hw,
+               [CLK_I2S0]              = &i2s0_clk.common.hw,
+               [CLK_I2S1]              = &i2s1_clk.common.hw,
+               [CLK_I2S2]              = &i2s2_clk.common.hw,
+               [CLK_I2S2_ASRC]         = &i2s2_asrc_clk.common.hw,
+               [CLK_BUS_I2S0]          = &bus_i2s0_clk.common.hw,
+               [CLK_BUS_I2S1]          = &bus_i2s1_clk.common.hw,
+               [CLK_BUS_I2S2]          = &bus_i2s2_clk.common.hw,
+               [CLK_SPDIF_TX]          = &spdif_tx_clk.common.hw,
+               [CLK_SPDIF_RX]          = &spdif_rx_clk.common.hw,
+               [CLK_BUS_SPDIF]         = &bus_spdif_clk.common.hw,
+               [CLK_DMIC]              = &dmic_clk.common.hw,
+               [CLK_BUS_DMIC]          = &bus_dmic_clk.common.hw,
+               [CLK_AUDIO_DAC]         = &audio_dac_clk.common.hw,
+               [CLK_AUDIO_ADC]         = &audio_adc_clk.common.hw,
+               [CLK_BUS_AUDIO]         = &bus_audio_clk.common.hw,
+               [CLK_USB_OHCI0]         = &usb_ohci0_clk.common.hw,
+               [CLK_USB_OHCI1]         = &usb_ohci1_clk.common.hw,
+               [CLK_BUS_OHCI0]         = &bus_ohci0_clk.common.hw,
+               [CLK_BUS_OHCI1]         = &bus_ohci1_clk.common.hw,
+               [CLK_BUS_EHCI0]         = &bus_ehci0_clk.common.hw,
+               [CLK_BUS_EHCI1]         = &bus_ehci1_clk.common.hw,
+               [CLK_BUS_OTG]           = &bus_otg_clk.common.hw,
+               [CLK_BUS_LRADC]         = &bus_lradc_clk.common.hw,
+               [CLK_BUS_DPSS_TOP]      = &bus_dpss_top_clk.common.hw,
+               [CLK_HDMI_24M]          = &hdmi_24M_clk.common.hw,
+               [CLK_HDMI_CEC_32K]      = &hdmi_cec_32k_clk.common.hw,
+               [CLK_HDMI_CEC]          = &hdmi_cec_clk.common.hw,
+               [CLK_BUS_HDMI]          = &bus_hdmi_clk.common.hw,
+               [CLK_MIPI_DSI]          = &mipi_dsi_clk.common.hw,
+               [CLK_BUS_MIPI_DSI]      = &bus_mipi_dsi_clk.common.hw,
+               [CLK_TCON_LCD0]         = &tcon_lcd0_clk.common.hw,
+               [CLK_BUS_TCON_LCD0]     = &bus_tcon_lcd0_clk.common.hw,
+               [CLK_TCON_TV]           = &tcon_tv_clk.common.hw,
+               [CLK_BUS_TCON_TV]       = &bus_tcon_tv_clk.common.hw,
+               [CLK_TVE]               = &tve_clk.common.hw,
+               [CLK_BUS_TVE_TOP]       = &bus_tve_top_clk.common.hw,
+               [CLK_BUS_TVE]           = &bus_tve_clk.common.hw,
+               [CLK_TVD]               = &tvd_clk.common.hw,
+               [CLK_BUS_TVD_TOP]       = &bus_tvd_top_clk.common.hw,
+               [CLK_BUS_TVD]           = &bus_tvd_clk.common.hw,
+               [CLK_LEDC]              = &ledc_clk.common.hw,
+               [CLK_BUS_LEDC]          = &bus_ledc_clk.common.hw,
+               [CLK_CSI_TOP]           = &csi_top_clk.common.hw,
+               [CLK_CSI_MCLK]          = &csi_mclk_clk.common.hw,
+               [CLK_BUS_CSI]           = &bus_csi_clk.common.hw,
+               [CLK_TPADC]             = &tpadc_clk.common.hw,
+               [CLK_BUS_TPADC]         = &bus_tpadc_clk.common.hw,
+               [CLK_BUS_TZMA]          = &bus_tzma_clk.common.hw,
+               [CLK_DSP]               = &dsp_clk.common.hw,
+               [CLK_BUS_DSP_CFG]       = &bus_dsp_cfg_clk.common.hw,
+               [CLK_RISCV]             = &riscv_clk.common.hw,
+               [CLK_RISCV_AXI]         = &riscv_axi_clk.common.hw,
+               [CLK_BUS_RISCV_CFG]     = &bus_riscv_cfg_clk.common.hw,
+               [CLK_FANOUT_24M]        = &fanout_24M_clk.common.hw,
+               [CLK_FANOUT_12M]        = &fanout_12M_clk.common.hw,
+               [CLK_FANOUT_16M]        = &fanout_16M_clk.common.hw,
+               [CLK_FANOUT_25M]        = &fanout_25M_clk.common.hw,
+               [CLK_FANOUT_32K]        = &fanout_32k_clk.common.hw,
+               [CLK_FANOUT_27M]        = &fanout_27M_clk.common.hw,
+               [CLK_FANOUT_PCLK]       = &fanout_pclk_clk.common.hw,
+               [CLK_FANOUT0]           = &fanout0_clk.common.hw,
+               [CLK_FANOUT1]           = &fanout1_clk.common.hw,
+               [CLK_FANOUT2]           = &fanout2_clk.common.hw,
+       },
+};
+
+static struct ccu_reset_map sun20i_d1_ccu_resets[] = {
+       [RST_MBUS]              = { 0x540, BIT(30) },
+       [RST_BUS_DE]            = { 0x60c, BIT(16) },
+       [RST_BUS_DI]            = { 0x62c, BIT(16) },
+       [RST_BUS_G2D]           = { 0x63c, BIT(16) },
+       [RST_BUS_CE]            = { 0x68c, BIT(16) },
+       [RST_BUS_VE]            = { 0x69c, BIT(16) },
+       [RST_BUS_DMA]           = { 0x70c, BIT(16) },
+       [RST_BUS_MSGBOX0]       = { 0x71c, BIT(16) },
+       [RST_BUS_MSGBOX1]       = { 0x71c, BIT(17) },
+       [RST_BUS_MSGBOX2]       = { 0x71c, BIT(18) },
+       [RST_BUS_SPINLOCK]      = { 0x72c, BIT(16) },
+       [RST_BUS_HSTIMER]       = { 0x73c, BIT(16) },
+       [RST_BUS_DBG]           = { 0x78c, BIT(16) },
+       [RST_BUS_PWM]           = { 0x7ac, BIT(16) },
+       [RST_BUS_DRAM]          = { 0x80c, BIT(16) },
+       [RST_BUS_MMC0]          = { 0x84c, BIT(16) },
+       [RST_BUS_MMC1]          = { 0x84c, BIT(17) },
+       [RST_BUS_MMC2]          = { 0x84c, BIT(18) },
+       [RST_BUS_UART0]         = { 0x90c, BIT(16) },
+       [RST_BUS_UART1]         = { 0x90c, BIT(17) },
+       [RST_BUS_UART2]         = { 0x90c, BIT(18) },
+       [RST_BUS_UART3]         = { 0x90c, BIT(19) },
+       [RST_BUS_UART4]         = { 0x90c, BIT(20) },
+       [RST_BUS_UART5]         = { 0x90c, BIT(21) },
+       [RST_BUS_I2C0]          = { 0x91c, BIT(16) },
+       [RST_BUS_I2C1]          = { 0x91c, BIT(17) },
+       [RST_BUS_I2C2]          = { 0x91c, BIT(18) },
+       [RST_BUS_I2C3]          = { 0x91c, BIT(19) },
+       [RST_BUS_SPI0]          = { 0x96c, BIT(16) },
+       [RST_BUS_SPI1]          = { 0x96c, BIT(17) },
+       [RST_BUS_EMAC]          = { 0x97c, BIT(16) },
+       [RST_BUS_IR_TX]         = { 0x9cc, BIT(16) },
+       [RST_BUS_GPADC]         = { 0x9ec, BIT(16) },
+       [RST_BUS_THS]           = { 0x9fc, BIT(16) },
+       [RST_BUS_I2S0]          = { 0xa20, BIT(16) },
+       [RST_BUS_I2S1]          = { 0xa20, BIT(17) },
+       [RST_BUS_I2S2]          = { 0xa20, BIT(18) },
+       [RST_BUS_SPDIF]         = { 0xa2c, BIT(16) },
+       [RST_BUS_DMIC]          = { 0xa4c, BIT(16) },
+       [RST_BUS_AUDIO]         = { 0xa5c, BIT(16) },
+       [RST_USB_PHY0]          = { 0xa70, BIT(30) },
+       [RST_USB_PHY1]          = { 0xa74, BIT(30) },
+       [RST_BUS_OHCI0]         = { 0xa8c, BIT(16) },
+       [RST_BUS_OHCI1]         = { 0xa8c, BIT(17) },
+       [RST_BUS_EHCI0]         = { 0xa8c, BIT(20) },
+       [RST_BUS_EHCI1]         = { 0xa8c, BIT(21) },
+       [RST_BUS_OTG]           = { 0xa8c, BIT(24) },
+       [RST_BUS_LRADC]         = { 0xa9c, BIT(16) },
+       [RST_BUS_DPSS_TOP]      = { 0xabc, BIT(16) },
+       [RST_BUS_HDMI_MAIN]     = { 0xb1c, BIT(16) },
+       [RST_BUS_HDMI_SUB]      = { 0xb1c, BIT(17) },
+       [RST_BUS_MIPI_DSI]      = { 0xb4c, BIT(16) },
+       [RST_BUS_TCON_LCD0]     = { 0xb7c, BIT(16) },
+       [RST_BUS_TCON_TV]       = { 0xb9c, BIT(16) },
+       [RST_BUS_LVDS0]         = { 0xbac, BIT(16) },
+       [RST_BUS_TVE_TOP]       = { 0xbbc, BIT(16) },
+       [RST_BUS_TVE]           = { 0xbbc, BIT(17) },
+       [RST_BUS_TVD_TOP]       = { 0xbdc, BIT(16) },
+       [RST_BUS_TVD]           = { 0xbdc, BIT(17) },
+       [RST_BUS_LEDC]          = { 0xbfc, BIT(16) },
+       [RST_BUS_CSI]           = { 0xc1c, BIT(16) },
+       [RST_BUS_TPADC]         = { 0xc5c, BIT(16) },
+       [RST_DSP]               = { 0xc7c, BIT(16) },
+       [RST_BUS_DSP_CFG]       = { 0xc7c, BIT(17) },
+       [RST_BUS_DSP_DBG]       = { 0xc7c, BIT(18) },
+       [RST_BUS_RISCV_CFG]     = { 0xd0c, BIT(16) },
+};
+
+static const struct sunxi_ccu_desc sun20i_d1_ccu_desc = {
+       .ccu_clks       = sun20i_d1_ccu_clks,
+       .num_ccu_clks   = ARRAY_SIZE(sun20i_d1_ccu_clks),
+
+       .hw_clks        = &sun20i_d1_hw_clks,
+
+       .resets         = sun20i_d1_ccu_resets,
+       .num_resets     = ARRAY_SIZE(sun20i_d1_ccu_resets),
+};
+
+static const u32 pll_regs[] = {
+       SUN20I_D1_PLL_CPUX_REG,
+       SUN20I_D1_PLL_DDR0_REG,
+       SUN20I_D1_PLL_PERIPH0_REG,
+       SUN20I_D1_PLL_VIDEO0_REG,
+       SUN20I_D1_PLL_VIDEO1_REG,
+       SUN20I_D1_PLL_VE_REG,
+       SUN20I_D1_PLL_AUDIO0_REG,
+       SUN20I_D1_PLL_AUDIO1_REG,
+};
+
+static const u32 pll_video_regs[] = {
+       SUN20I_D1_PLL_VIDEO0_REG,
+       SUN20I_D1_PLL_VIDEO1_REG,
+};
+
+static struct ccu_mux_nb sun20i_d1_riscv_nb = {
+       .common         = &riscv_clk.common,
+       .cm             = &riscv_clk.mux,
+       .delay_us       = 1,
+       .bypass_index   = 4, /* index of pll-periph0 */
+};
+
+static int sun20i_d1_ccu_probe(struct platform_device *pdev)
+{
+       void __iomem *reg;
+       u32 val;
+       int i, ret;
+
+       reg = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(reg))
+               return PTR_ERR(reg);
+
+       /* Enable the enable, LDO, and lock bits on all PLLs. */
+       for (i = 0; i < ARRAY_SIZE(pll_regs); i++) {
+               val = readl(reg + pll_regs[i]);
+               val |= BIT(31) | BIT(30) | BIT(29);
+               writel(val, reg + pll_regs[i]);
+       }
+
+       /* Force PLL_CPUX factor M to 0. */
+       val = readl(reg + SUN20I_D1_PLL_CPUX_REG);
+       val &= ~GENMASK(1, 0);
+       writel(val, reg + SUN20I_D1_PLL_CPUX_REG);
+
+       /*
+        * Force the output divider of video PLLs to 0.
+        *
+        * See the comment before pll-video0 definition for the reason.
+        */
+       for (i = 0; i < ARRAY_SIZE(pll_video_regs); i++) {
+               val = readl(reg + pll_video_regs[i]);
+               val &= ~BIT(0);
+               writel(val, reg + pll_video_regs[i]);
+       }
+
+       /* Enforce m1 = 0, m0 = 0 for PLL_AUDIO0 */
+       val = readl(reg + SUN20I_D1_PLL_AUDIO0_REG);
+       val &= ~BIT(1) | BIT(0);
+       writel(val, reg + SUN20I_D1_PLL_AUDIO0_REG);
+
+       /* Force fanout-27M factor N to 0. */
+       val = readl(reg + SUN20I_D1_FANOUT_27M_REG);
+       val &= ~GENMASK(9, 8);
+       writel(val, reg + SUN20I_D1_FANOUT_27M_REG);
+
+       ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun20i_d1_ccu_desc);
+       if (ret)
+               return ret;
+
+       /* Reparent CPU during PLL CPUX rate changes */
+       ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk,
+                                 &sun20i_d1_riscv_nb);
+
+       return 0;
+}
+
+static const struct of_device_id sun20i_d1_ccu_ids[] = {
+       { .compatible = "allwinner,sun20i-d1-ccu" },
+       { }
+};
+
+static struct platform_driver sun20i_d1_ccu_driver = {
+       .probe  = sun20i_d1_ccu_probe,
+       .driver = {
+               .name                   = "sun20i-d1-ccu",
+               .suppress_bind_attrs    = true,
+               .of_match_table         = sun20i_d1_ccu_ids,
+       },
+};
+module_platform_driver(sun20i_d1_ccu_driver);
+
+MODULE_IMPORT_NS(SUNXI_CCU);
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/sunxi-ng/ccu-sun20i-d1.h b/drivers/clk/sunxi-ng/ccu-sun20i-d1.h
new file mode 100644 (file)
index 0000000..e303176
--- /dev/null
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2020 frank@allwinnertech.com
+ * Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
+ */
+
+#ifndef _CCU_SUN20I_D1_H_
+#define _CCU_SUN20I_D1_H_
+
+#include <dt-bindings/clock/sun20i-d1-ccu.h>
+#include <dt-bindings/reset/sun20i-d1-ccu.h>
+
+#define CLK_NUMBER             (CLK_FANOUT2 + 1)
+
+#endif /* _CCU_SUN20I_D1_H_ */
index bd9a878..c19828f 100644 (file)
@@ -7,7 +7,9 @@
 
 #include <linux/clk-provider.h>
 #include <linux/io.h>
-#include <linux/of_address.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
 
 #include "ccu_common.h"
 #include "ccu_reset.h"
@@ -1425,18 +1427,19 @@ static const struct sunxi_ccu_desc sun7i_a20_ccu_desc = {
        .num_resets     = ARRAY_SIZE(sunxi_a10_a20_ccu_resets),
 };
 
-static void __init sun4i_ccu_init(struct device_node *node,
-                                 const struct sunxi_ccu_desc *desc)
+static int sun4i_a10_ccu_probe(struct platform_device *pdev)
 {
+       const struct sunxi_ccu_desc *desc;
        void __iomem *reg;
        u32 val;
 
-       reg = of_io_request_and_map(node, 0, of_node_full_name(node));
-       if (IS_ERR(reg)) {
-               pr_err("%s: Could not map the clock registers\n",
-                      of_node_full_name(node));
-               return;
-       }
+       desc = of_device_get_match_data(&pdev->dev);
+       if (!desc)
+               return -EINVAL;
+
+       reg = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(reg))
+               return PTR_ERR(reg);
 
        val = readl(reg + SUN4I_PLL_AUDIO_REG);
 
@@ -1464,19 +1467,30 @@ static void __init sun4i_ccu_init(struct device_node *node,
        val &= ~GENMASK(7, 6);
        writel(val | (2 << 6), reg + SUN4I_AHB_REG);
 
-       of_sunxi_ccu_probe(node, reg, desc);
+       return devm_sunxi_ccu_probe(&pdev->dev, reg, desc);
 }
 
-static void __init sun4i_a10_ccu_setup(struct device_node *node)
-{
-       sun4i_ccu_init(node, &sun4i_a10_ccu_desc);
-}
-CLK_OF_DECLARE(sun4i_a10_ccu, "allwinner,sun4i-a10-ccu",
-              sun4i_a10_ccu_setup);
+static const struct of_device_id sun4i_a10_ccu_ids[] = {
+       {
+               .compatible = "allwinner,sun4i-a10-ccu",
+               .data = &sun4i_a10_ccu_desc,
+       },
+       {
+               .compatible = "allwinner,sun7i-a20-ccu",
+               .data = &sun7i_a20_ccu_desc,
+       },
+       { }
+};
 
-static void __init sun7i_a20_ccu_setup(struct device_node *node)
-{
-       sun4i_ccu_init(node, &sun7i_a20_ccu_desc);
-}
-CLK_OF_DECLARE(sun7i_a20_ccu, "allwinner,sun7i-a20-ccu",
-              sun7i_a20_ccu_setup);
+static struct platform_driver sun4i_a10_ccu_driver = {
+       .probe  = sun4i_a10_ccu_probe,
+       .driver = {
+               .name                   = "sun4i-a10-ccu",
+               .suppress_bind_attrs    = true,
+               .of_match_table         = sun4i_a10_ccu_ids,
+       },
+};
+module_platform_driver(sun4i_a10_ccu_driver);
+
+MODULE_IMPORT_NS(SUNXI_CCU);
+MODULE_LICENSE("GPL");
index 804729e..fddd6c8 100644 (file)
@@ -5,7 +5,6 @@
 
 #include <linux/clk-provider.h>
 #include <linux/module.h>
-#include <linux/of_address.h>
 #include <linux/platform_device.h>
 
 #include "ccu_common.h"
@@ -213,3 +212,6 @@ static struct platform_driver sun50i_a100_r_ccu_driver = {
        },
 };
 module_platform_driver(sun50i_a100_r_ccu_driver);
+
+MODULE_IMPORT_NS(SUNXI_CCU);
+MODULE_LICENSE("GPL");
index 1d475d5..5f93b55 100644 (file)
@@ -6,7 +6,6 @@
 #include <linux/clk-provider.h>
 #include <linux/io.h>
 #include <linux/module.h>
-#include <linux/of_address.h>
 #include <linux/platform_device.h>
 
 #include "ccu_common.h"
@@ -1275,3 +1274,6 @@ static struct platform_driver sun50i_a100_ccu_driver = {
        },
 };
 module_platform_driver(sun50i_a100_ccu_driver);
+
+MODULE_IMPORT_NS(SUNXI_CCU);
+MODULE_LICENSE("GPL");
index a8c5a92..4151918 100644 (file)
@@ -5,7 +5,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/io.h>
-#include <linux/of_address.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
 
 #include "ccu_common.h"
@@ -980,4 +980,7 @@ static struct platform_driver sun50i_a64_ccu_driver = {
                .of_match_table = sun50i_a64_ccu_ids,
        },
 };
-builtin_platform_driver(sun50i_a64_ccu_driver);
+module_platform_driver(sun50i_a64_ccu_driver);
+
+MODULE_IMPORT_NS(SUNXI_CCU);
+MODULE_LICENSE("GPL");
index f30d7eb..712e103 100644 (file)
@@ -4,7 +4,8 @@
  */
 
 #include <linux/clk-provider.h>
-#include <linux/of_address.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 
 #include "ccu_common.h"
@@ -221,30 +222,43 @@ static const struct sunxi_ccu_desc sun50i_h616_r_ccu_desc = {
        .num_resets     = ARRAY_SIZE(sun50i_h616_r_ccu_resets),
 };
 
-static void __init sunxi_r_ccu_init(struct device_node *node,
-                                   const struct sunxi_ccu_desc *desc)
+static int sun50i_h6_r_ccu_probe(struct platform_device *pdev)
 {
+       const struct sunxi_ccu_desc *desc;
        void __iomem *reg;
 
-       reg = of_io_request_and_map(node, 0, of_node_full_name(node));
-       if (IS_ERR(reg)) {
-               pr_err("%pOF: Could not map the clock registers\n", node);
-               return;
-       }
+       desc = of_device_get_match_data(&pdev->dev);
+       if (!desc)
+               return -EINVAL;
 
-       of_sunxi_ccu_probe(node, reg, desc);
-}
+       reg = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(reg))
+               return PTR_ERR(reg);
 
-static void __init sun50i_h6_r_ccu_setup(struct device_node *node)
-{
-       sunxi_r_ccu_init(node, &sun50i_h6_r_ccu_desc);
+       return devm_sunxi_ccu_probe(&pdev->dev, reg, desc);
 }
-CLK_OF_DECLARE(sun50i_h6_r_ccu, "allwinner,sun50i-h6-r-ccu",
-              sun50i_h6_r_ccu_setup);
 
-static void __init sun50i_h616_r_ccu_setup(struct device_node *node)
-{
-       sunxi_r_ccu_init(node, &sun50i_h616_r_ccu_desc);
-}
-CLK_OF_DECLARE(sun50i_h616_r_ccu, "allwinner,sun50i-h616-r-ccu",
-              sun50i_h616_r_ccu_setup);
+static const struct of_device_id sun50i_h6_r_ccu_ids[] = {
+       {
+               .compatible = "allwinner,sun50i-h6-r-ccu",
+               .data = &sun50i_h6_r_ccu_desc,
+       },
+       {
+               .compatible = "allwinner,sun50i-h616-r-ccu",
+               .data = &sun50i_h616_r_ccu_desc,
+       },
+       { }
+};
+
+static struct platform_driver sun50i_h6_r_ccu_driver = {
+       .probe  = sun50i_h6_r_ccu_probe,
+       .driver = {
+               .name                   = "sun50i-h6-r-ccu",
+               .suppress_bind_attrs    = true,
+               .of_match_table         = sun50i_h6_r_ccu_ids,
+       },
+};
+module_platform_driver(sun50i_h6_r_ccu_driver);
+
+MODULE_IMPORT_NS(SUNXI_CCU);
+MODULE_LICENSE("GPL");
index e5672c1..1a5e418 100644 (file)
@@ -5,7 +5,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/io.h>
-#include <linux/of_address.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
 
 #include "ccu_common.h"
@@ -1254,4 +1254,7 @@ static struct platform_driver sun50i_h6_ccu_driver = {
                .of_match_table = sun50i_h6_ccu_ids,
        },
 };
-builtin_platform_driver(sun50i_h6_ccu_driver);
+module_platform_driver(sun50i_h6_ccu_driver);
+
+MODULE_IMPORT_NS(SUNXI_CCU);
+MODULE_LICENSE("GPL");
index 22eb180..49a2474 100644 (file)
@@ -7,7 +7,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/io.h>
-#include <linux/of_address.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
 
 #include "ccu_common.h"
@@ -1082,17 +1082,15 @@ static const u32 usb2_clk_regs[] = {
        SUN50I_H616_USB3_CLK_REG,
 };
 
-static void __init sun50i_h616_ccu_setup(struct device_node *node)
+static int sun50i_h616_ccu_probe(struct platform_device *pdev)
 {
        void __iomem *reg;
        u32 val;
        int i;
 
-       reg = of_io_request_and_map(node, 0, of_node_full_name(node));
-       if (IS_ERR(reg)) {
-               pr_err("%pOF: Could not map clock registers\n", node);
-               return;
-       }
+       reg = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(reg))
+               return PTR_ERR(reg);
 
        /* Enable the lock bits and the output enable bits on all PLLs */
        for (i = 0; i < ARRAY_SIZE(pll_regs); i++) {
@@ -1141,8 +1139,23 @@ static void __init sun50i_h616_ccu_setup(struct device_node *node)
        val |= BIT(24);
        writel(val, reg + SUN50I_H616_HDMI_CEC_CLK_REG);
 
-       of_sunxi_ccu_probe(node, reg, &sun50i_h616_ccu_desc);
+       return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun50i_h616_ccu_desc);
 }
 
-CLK_OF_DECLARE(sun50i_h616_ccu, "allwinner,sun50i-h616-ccu",
-              sun50i_h616_ccu_setup);
+static const struct of_device_id sun50i_h616_ccu_ids[] = {
+       { .compatible = "allwinner,sun50i-h616-ccu" },
+       { }
+};
+
+static struct platform_driver sun50i_h616_ccu_driver = {
+       .probe  = sun50i_h616_ccu_probe,
+       .driver = {
+               .name                   = "sun50i-h616-ccu",
+               .suppress_bind_attrs    = true,
+               .of_match_table         = sun50i_h616_ccu_ids,
+       },
+};
+module_platform_driver(sun50i_h616_ccu_driver);
+
+MODULE_IMPORT_NS(SUNXI_CCU);
+MODULE_LICENSE("GPL");
index 3df5c0b..0762def 100644 (file)
@@ -9,7 +9,8 @@
 
 #include <linux/clk-provider.h>
 #include <linux/io.h>
-#include <linux/of_address.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
 
 #include "ccu_common.h"
 #include "ccu_reset.h"
@@ -1226,16 +1227,15 @@ static struct ccu_mux_nb sun6i_a31_cpu_nb = {
        .bypass_index   = 1, /* index of 24 MHz oscillator */
 };
 
-static void __init sun6i_a31_ccu_setup(struct device_node *node)
+static int sun6i_a31_ccu_probe(struct platform_device *pdev)
 {
        void __iomem *reg;
+       int ret;
        u32 val;
 
-       reg = of_io_request_and_map(node, 0, of_node_full_name(node));
-       if (IS_ERR(reg)) {
-               pr_err("%pOF: Could not map the clock registers\n", node);
-               return;
-       }
+       reg = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(reg))
+               return PTR_ERR(reg);
 
        /* Force the PLL-Audio-1x divider to 1 */
        val = readl(reg + SUN6I_A31_PLL_AUDIO_REG);
@@ -1257,10 +1257,30 @@ static void __init sun6i_a31_ccu_setup(struct device_node *node)
        val |= 0x3 << 12;
        writel(val, reg + SUN6I_A31_AHB1_REG);
 
-       of_sunxi_ccu_probe(node, reg, &sun6i_a31_ccu_desc);
+       ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun6i_a31_ccu_desc);
+       if (ret)
+               return ret;
 
        ccu_mux_notifier_register(pll_cpu_clk.common.hw.clk,
                                  &sun6i_a31_cpu_nb);
+
+       return 0;
 }
-CLK_OF_DECLARE(sun6i_a31_ccu, "allwinner,sun6i-a31-ccu",
-              sun6i_a31_ccu_setup);
+
+static const struct of_device_id sun6i_a31_ccu_ids[] = {
+       { .compatible = "allwinner,sun6i-a31-ccu" },
+       { }
+};
+
+static struct platform_driver sun6i_a31_ccu_driver = {
+       .probe  = sun6i_a31_ccu_probe,
+       .driver = {
+               .name                   = "sun6i-a31-ccu",
+               .suppress_bind_attrs    = true,
+               .of_match_table         = sun6i_a31_ccu_ids,
+       },
+};
+module_platform_driver(sun6i_a31_ccu_driver);
+
+MODULE_IMPORT_NS(SUNXI_CCU);
+MODULE_LICENSE("GPL");
index 577bb23..e80cc38 100644 (file)
@@ -5,7 +5,8 @@
 
 #include <linux/clk-provider.h>
 #include <linux/io.h>
-#include <linux/of_address.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
 
 #include "ccu_common.h"
 #include "ccu_reset.h"
@@ -724,16 +725,14 @@ static const struct sunxi_ccu_desc sun8i_a23_ccu_desc = {
        .num_resets     = ARRAY_SIZE(sun8i_a23_ccu_resets),
 };
 
-static void __init sun8i_a23_ccu_setup(struct device_node *node)
+static int sun8i_a23_ccu_probe(struct platform_device *pdev)
 {
        void __iomem *reg;
        u32 val;
 
-       reg = of_io_request_and_map(node, 0, of_node_full_name(node));
-       if (IS_ERR(reg)) {
-               pr_err("%pOF: Could not map the clock registers\n", node);
-               return;
-       }
+       reg = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(reg))
+               return PTR_ERR(reg);
 
        /* Force the PLL-Audio-1x divider to 1 */
        val = readl(reg + SUN8I_A23_PLL_AUDIO_REG);
@@ -745,7 +744,23 @@ static void __init sun8i_a23_ccu_setup(struct device_node *node)
        val &= ~BIT(16);
        writel(val, reg + SUN8I_A23_PLL_MIPI_REG);
 
-       of_sunxi_ccu_probe(node, reg, &sun8i_a23_ccu_desc);
+       return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun8i_a23_ccu_desc);
 }
-CLK_OF_DECLARE(sun8i_a23_ccu, "allwinner,sun8i-a23-ccu",
-              sun8i_a23_ccu_setup);
+
+static const struct of_device_id sun8i_a23_ccu_ids[] = {
+       { .compatible = "allwinner,sun8i-a23-ccu" },
+       { }
+};
+
+static struct platform_driver sun8i_a23_ccu_driver = {
+       .probe  = sun8i_a23_ccu_probe,
+       .driver = {
+               .name                   = "sun8i-a23-ccu",
+               .suppress_bind_attrs    = true,
+               .of_match_table         = sun8i_a23_ccu_ids,
+       },
+};
+module_platform_driver(sun8i_a23_ccu_driver);
+
+MODULE_IMPORT_NS(SUNXI_CCU);
+MODULE_LICENSE("GPL");
index 8f65cd0..d12878a 100644 (file)
@@ -5,7 +5,8 @@
 
 #include <linux/clk-provider.h>
 #include <linux/io.h>
-#include <linux/of_address.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
 
 #include "ccu_common.h"
 #include "ccu_reset.h"
@@ -784,16 +785,15 @@ static struct ccu_mux_nb sun8i_a33_cpu_nb = {
        .bypass_index   = 1, /* index of 24 MHz oscillator */
 };
 
-static void __init sun8i_a33_ccu_setup(struct device_node *node)
+static int sun8i_a33_ccu_probe(struct platform_device *pdev)
 {
        void __iomem *reg;
+       int ret;
        u32 val;
 
-       reg = of_io_request_and_map(node, 0, of_node_full_name(node));
-       if (IS_ERR(reg)) {
-               pr_err("%pOF: Could not map the clock registers\n", node);
-               return;
-       }
+       reg = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(reg))
+               return PTR_ERR(reg);
 
        /* Force the PLL-Audio-1x divider to 1 */
        val = readl(reg + SUN8I_A33_PLL_AUDIO_REG);
@@ -805,7 +805,9 @@ static void __init sun8i_a33_ccu_setup(struct device_node *node)
        val &= ~BIT(16);
        writel(val, reg + SUN8I_A33_PLL_MIPI_REG);
 
-       of_sunxi_ccu_probe(node, reg, &sun8i_a33_ccu_desc);
+       ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun8i_a33_ccu_desc);
+       if (ret)
+               return ret;
 
        /* Gate then ungate PLL CPU after any rate changes */
        ccu_pll_notifier_register(&sun8i_a33_pll_cpu_nb);
@@ -813,6 +815,24 @@ static void __init sun8i_a33_ccu_setup(struct device_node *node)
        /* Reparent CPU during PLL CPU rate changes */
        ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk,
                                  &sun8i_a33_cpu_nb);
+
+       return 0;
 }
-CLK_OF_DECLARE(sun8i_a33_ccu, "allwinner,sun8i-a33-ccu",
-              sun8i_a33_ccu_setup);
+
+static const struct of_device_id sun8i_a33_ccu_ids[] = {
+       { .compatible = "allwinner,sun8i-a33-ccu" },
+       { }
+};
+
+static struct platform_driver sun8i_a33_ccu_driver = {
+       .probe  = sun8i_a33_ccu_probe,
+       .driver = {
+               .name                   = "sun8i-a33-ccu",
+               .suppress_bind_attrs    = true,
+               .of_match_table         = sun8i_a33_ccu_ids,
+       },
+};
+module_platform_driver(sun8i_a33_ccu_driver);
+
+MODULE_IMPORT_NS(SUNXI_CCU);
+MODULE_LICENSE("GPL");
index 3c310ae..76cbd9e 100644 (file)
@@ -5,7 +5,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/io.h>
-#include <linux/of_address.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
 
 #include "ccu_common.h"
@@ -920,4 +920,7 @@ static struct platform_driver sun8i_a83t_ccu_driver = {
                .of_match_table = sun8i_a83t_ccu_ids,
        },
 };
-builtin_platform_driver(sun8i_a83t_ccu_driver);
+module_platform_driver(sun8i_a83t_ccu_driver);
+
+MODULE_IMPORT_NS(SUNXI_CCU);
+MODULE_LICENSE("GPL");
index 573b505..e7e3ddf 100644 (file)
@@ -5,8 +5,8 @@
 
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/reset.h>
 
@@ -394,4 +394,7 @@ static struct platform_driver sunxi_de2_clk_driver = {
                .of_match_table = sunxi_de2_clk_ids,
        },
 };
-builtin_platform_driver(sunxi_de2_clk_driver);
+module_platform_driver(sunxi_de2_clk_driver);
+
+MODULE_IMPORT_NS(SUNXI_CCU);
+MODULE_LICENSE("GPL");
index d2fc290..e058cf6 100644 (file)
@@ -5,7 +5,9 @@
 
 #include <linux/clk-provider.h>
 #include <linux/io.h>
-#include <linux/of_address.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
 
 #include "ccu_common.h"
 #include "ccu_reset.h"
@@ -1137,24 +1139,29 @@ static struct ccu_mux_nb sun8i_h3_cpu_nb = {
        .bypass_index   = 1, /* index of 24 MHz oscillator */
 };
 
-static void __init sunxi_h3_h5_ccu_init(struct device_node *node,
-                                       const struct sunxi_ccu_desc *desc)
+static int sun8i_h3_ccu_probe(struct platform_device *pdev)
 {
+       const struct sunxi_ccu_desc *desc;
        void __iomem *reg;
+       int ret;
        u32 val;
 
-       reg = of_io_request_and_map(node, 0, of_node_full_name(node));
-       if (IS_ERR(reg)) {
-               pr_err("%pOF: Could not map the clock registers\n", node);
-               return;
-       }
+       desc = of_device_get_match_data(&pdev->dev);
+       if (!desc)
+               return -EINVAL;
+
+       reg = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(reg))
+               return PTR_ERR(reg);
 
        /* Force the PLL-Audio-1x divider to 1 */
        val = readl(reg + SUN8I_H3_PLL_AUDIO_REG);
        val &= ~GENMASK(19, 16);
        writel(val | (0 << 16), reg + SUN8I_H3_PLL_AUDIO_REG);
 
-       of_sunxi_ccu_probe(node, reg, desc);
+       ret = devm_sunxi_ccu_probe(&pdev->dev, reg, desc);
+       if (ret)
+               return ret;
 
        /* Gate then ungate PLL CPU after any rate changes */
        ccu_pll_notifier_register(&sun8i_h3_pll_cpu_nb);
@@ -1162,18 +1169,31 @@ static void __init sunxi_h3_h5_ccu_init(struct device_node *node,
        /* Reparent CPU during PLL CPU rate changes */
        ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk,
                                  &sun8i_h3_cpu_nb);
-}
 
-static void __init sun8i_h3_ccu_setup(struct device_node *node)
-{
-       sunxi_h3_h5_ccu_init(node, &sun8i_h3_ccu_desc);
+       return 0;
 }
-CLK_OF_DECLARE(sun8i_h3_ccu, "allwinner,sun8i-h3-ccu",
-              sun8i_h3_ccu_setup);
 
-static void __init sun50i_h5_ccu_setup(struct device_node *node)
-{
-       sunxi_h3_h5_ccu_init(node, &sun50i_h5_ccu_desc);
-}
-CLK_OF_DECLARE(sun50i_h5_ccu, "allwinner,sun50i-h5-ccu",
-              sun50i_h5_ccu_setup);
+static const struct of_device_id sun8i_h3_ccu_ids[] = {
+       {
+               .compatible = "allwinner,sun8i-h3-ccu",
+               .data = &sun8i_h3_ccu_desc,
+       },
+       {
+               .compatible = "allwinner,sun50i-h5-ccu",
+               .data = &sun50i_h5_ccu_desc,
+       },
+       { }
+};
+
+static struct platform_driver sun8i_h3_ccu_driver = {
+       .probe  = sun8i_h3_ccu_probe,
+       .driver = {
+               .name                   = "sun8i-h3-ccu",
+               .suppress_bind_attrs    = true,
+               .of_match_table         = sun8i_h3_ccu_ids,
+       },
+};
+module_platform_driver(sun8i_h3_ccu_driver);
+
+MODULE_IMPORT_NS(SUNXI_CCU);
+MODULE_LICENSE("GPL");
index 9e754d1..5b7fab8 100644 (file)
@@ -4,7 +4,8 @@
  */
 
 #include <linux/clk-provider.h>
-#include <linux/of_address.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 
 #include "ccu_common.h"
@@ -254,37 +255,47 @@ static const struct sunxi_ccu_desc sun50i_a64_r_ccu_desc = {
        .num_resets     = ARRAY_SIZE(sun50i_a64_r_ccu_resets),
 };
 
-static void __init sunxi_r_ccu_init(struct device_node *node,
-                                   const struct sunxi_ccu_desc *desc)
+static int sun8i_r_ccu_probe(struct platform_device *pdev)
 {
+       const struct sunxi_ccu_desc *desc;
        void __iomem *reg;
 
-       reg = of_io_request_and_map(node, 0, of_node_full_name(node));
-       if (IS_ERR(reg)) {
-               pr_err("%pOF: Could not map the clock registers\n", node);
-               return;
-       }
+       desc = of_device_get_match_data(&pdev->dev);
+       if (!desc)
+               return -EINVAL;
 
-       of_sunxi_ccu_probe(node, reg, desc);
-}
+       reg = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(reg))
+               return PTR_ERR(reg);
 
-static void __init sun8i_a83t_r_ccu_setup(struct device_node *node)
-{
-       sunxi_r_ccu_init(node, &sun8i_a83t_r_ccu_desc);
+       return devm_sunxi_ccu_probe(&pdev->dev, reg, desc);
 }
-CLK_OF_DECLARE(sun8i_a83t_r_ccu, "allwinner,sun8i-a83t-r-ccu",
-              sun8i_a83t_r_ccu_setup);
 
-static void __init sun8i_h3_r_ccu_setup(struct device_node *node)
-{
-       sunxi_r_ccu_init(node, &sun8i_h3_r_ccu_desc);
-}
-CLK_OF_DECLARE(sun8i_h3_r_ccu, "allwinner,sun8i-h3-r-ccu",
-              sun8i_h3_r_ccu_setup);
+static const struct of_device_id sun8i_r_ccu_ids[] = {
+       {
+               .compatible = "allwinner,sun8i-a83t-r-ccu",
+               .data = &sun8i_a83t_r_ccu_desc,
+       },
+       {
+               .compatible = "allwinner,sun8i-h3-r-ccu",
+               .data = &sun8i_h3_r_ccu_desc,
+       },
+       {
+               .compatible = "allwinner,sun50i-a64-r-ccu",
+               .data = &sun50i_a64_r_ccu_desc,
+       },
+       { }
+};
 
-static void __init sun50i_a64_r_ccu_setup(struct device_node *node)
-{
-       sunxi_r_ccu_init(node, &sun50i_a64_r_ccu_desc);
-}
-CLK_OF_DECLARE(sun50i_a64_r_ccu, "allwinner,sun50i-a64-r-ccu",
-              sun50i_a64_r_ccu_setup);
+static struct platform_driver sun8i_r_ccu_driver = {
+       .probe  = sun8i_r_ccu_probe,
+       .driver = {
+               .name                   = "sun8i-r-ccu",
+               .suppress_bind_attrs    = true,
+               .of_match_table         = sun8i_r_ccu_ids,
+       },
+};
+module_platform_driver(sun8i_r_ccu_driver);
+
+MODULE_IMPORT_NS(SUNXI_CCU);
+MODULE_LICENSE("GPL");
index 8bb18d9..31eca0d 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/io.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 
@@ -1371,4 +1372,7 @@ static struct platform_driver sun8i_r40_ccu_driver = {
                .of_match_table = sun8i_r40_ccu_ids,
        },
 };
-builtin_platform_driver(sun8i_r40_ccu_driver);
+module_platform_driver(sun8i_r40_ccu_driver);
+
+MODULE_IMPORT_NS(SUNXI_CCU);
+MODULE_LICENSE("GPL");
index ce150f8..87f87d6 100644 (file)
@@ -8,7 +8,9 @@
 
 #include <linux/clk-provider.h>
 #include <linux/io.h>
-#include <linux/of_address.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
 
 #include "ccu_common.h"
 #include "ccu_reset.h"
@@ -805,38 +807,49 @@ static const struct sunxi_ccu_desc sun8i_v3_ccu_desc = {
        .num_resets     = ARRAY_SIZE(sun8i_v3_ccu_resets),
 };
 
-static void __init sun8i_v3_v3s_ccu_init(struct device_node *node,
-                                        const struct sunxi_ccu_desc *ccu_desc)
+static int sun8i_v3s_ccu_probe(struct platform_device *pdev)
 {
+       const struct sunxi_ccu_desc *desc;
        void __iomem *reg;
        u32 val;
 
-       reg = of_io_request_and_map(node, 0, of_node_full_name(node));
-       if (IS_ERR(reg)) {
-               pr_err("%pOF: Could not map the clock registers\n", node);
-               return;
-       }
+       desc = of_device_get_match_data(&pdev->dev);
+       if (!desc)
+               return -EINVAL;
+
+       reg = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(reg))
+               return PTR_ERR(reg);
 
        /* Force the PLL-Audio-1x divider to 1 */
        val = readl(reg + SUN8I_V3S_PLL_AUDIO_REG);
        val &= ~GENMASK(19, 16);
        writel(val, reg + SUN8I_V3S_PLL_AUDIO_REG);
 
-       of_sunxi_ccu_probe(node, reg, ccu_desc);
-}
-
-static void __init sun8i_v3s_ccu_setup(struct device_node *node)
-{
-       sun8i_v3_v3s_ccu_init(node, &sun8i_v3s_ccu_desc);
+       return devm_sunxi_ccu_probe(&pdev->dev, reg, desc);
 }
 
-static void __init sun8i_v3_ccu_setup(struct device_node *node)
-{
-       sun8i_v3_v3s_ccu_init(node, &sun8i_v3_ccu_desc);
-}
+static const struct of_device_id sun8i_v3s_ccu_ids[] = {
+       {
+               .compatible = "allwinner,sun8i-v3-ccu",
+               .data = &sun8i_v3_ccu_desc,
+       },
+       {
+               .compatible = "allwinner,sun8i-v3s-ccu",
+               .data = &sun8i_v3s_ccu_desc,
+       },
+       { }
+};
 
-CLK_OF_DECLARE(sun8i_v3s_ccu, "allwinner,sun8i-v3s-ccu",
-              sun8i_v3s_ccu_setup);
+static struct platform_driver sun8i_v3s_ccu_driver = {
+       .probe  = sun8i_v3s_ccu_probe,
+       .driver = {
+               .name                   = "sun8i-v3s-ccu",
+               .suppress_bind_attrs    = true,
+               .of_match_table         = sun8i_v3s_ccu_ids,
+       },
+};
+module_platform_driver(sun8i_v3s_ccu_driver);
 
-CLK_OF_DECLARE(sun8i_v3_ccu, "allwinner,sun8i-v3-ccu",
-              sun8i_v3_ccu_setup);
+MODULE_IMPORT_NS(SUNXI_CCU);
+MODULE_LICENSE("GPL");
index 3cde261..f2fe0e1 100644 (file)
@@ -5,7 +5,7 @@
 
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
-#include <linux/of_address.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/reset.h>
 
@@ -270,4 +270,7 @@ static struct platform_driver sun9i_a80_de_clk_driver = {
                .of_match_table = sun9i_a80_de_clk_ids,
        },
 };
-builtin_platform_driver(sun9i_a80_de_clk_driver);
+module_platform_driver(sun9i_a80_de_clk_driver);
+
+MODULE_IMPORT_NS(SUNXI_CCU);
+MODULE_LICENSE("GPL");
index 0740e89..575ae4c 100644 (file)
@@ -5,7 +5,7 @@
 
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
-#include <linux/of_address.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
 
 #include "ccu_common.h"
@@ -138,4 +138,7 @@ static struct platform_driver sun9i_a80_usb_clk_driver = {
                .of_match_table = sun9i_a80_usb_clk_ids,
        },
 };
-builtin_platform_driver(sun9i_a80_usb_clk_driver);
+module_platform_driver(sun9i_a80_usb_clk_driver);
+
+MODULE_IMPORT_NS(SUNXI_CCU);
+MODULE_LICENSE("GPL");
index d416af2..730fd8e 100644 (file)
@@ -5,7 +5,7 @@
 
 #include <linux/clk-provider.h>
 #include <linux/io.h>
-#include <linux/of_address.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
 
 #include "ccu_common.h"
@@ -1245,4 +1245,7 @@ static struct platform_driver sun9i_a80_ccu_driver = {
                .of_match_table = sun9i_a80_ccu_ids,
        },
 };
-builtin_platform_driver(sun9i_a80_ccu_driver);
+module_platform_driver(sun9i_a80_ccu_driver);
+
+MODULE_IMPORT_NS(SUNXI_CCU);
+MODULE_LICENSE("GPL");
index 61ad7ee..ed097c4 100644 (file)
@@ -6,7 +6,8 @@
 
 #include <linux/clk-provider.h>
 #include <linux/io.h>
-#include <linux/of_address.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
 
 #include "ccu_common.h"
 #include "ccu_reset.h"
@@ -522,23 +523,24 @@ static struct ccu_mux_nb suniv_cpu_nb = {
        .bypass_index   = 1, /* index of 24 MHz oscillator */
 };
 
-static void __init suniv_f1c100s_ccu_setup(struct device_node *node)
+static int suniv_f1c100s_ccu_probe(struct platform_device *pdev)
 {
        void __iomem *reg;
+       int ret;
        u32 val;
 
-       reg = of_io_request_and_map(node, 0, of_node_full_name(node));
-       if (IS_ERR(reg)) {
-               pr_err("%pOF: Could not map the clock registers\n", node);
-               return;
-       }
+       reg = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(reg))
+               return PTR_ERR(reg);
 
        /* Force the PLL-Audio-1x divider to 4 */
        val = readl(reg + SUNIV_PLL_AUDIO_REG);
        val &= ~GENMASK(19, 16);
        writel(val | (3 << 16), reg + SUNIV_PLL_AUDIO_REG);
 
-       of_sunxi_ccu_probe(node, reg, &suniv_ccu_desc);
+       ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &suniv_ccu_desc);
+       if (ret)
+               return ret;
 
        /* Gate then ungate PLL CPU after any rate changes */
        ccu_pll_notifier_register(&suniv_pll_cpu_nb);
@@ -546,6 +548,24 @@ static void __init suniv_f1c100s_ccu_setup(struct device_node *node)
        /* Reparent CPU during PLL CPU rate changes */
        ccu_mux_notifier_register(pll_cpu_clk.common.hw.clk,
                                  &suniv_cpu_nb);
+
+       return 0;
 }
-CLK_OF_DECLARE(suniv_f1c100s_ccu, "allwinner,suniv-f1c100s-ccu",
-              suniv_f1c100s_ccu_setup);
+
+static const struct of_device_id suniv_f1c100s_ccu_ids[] = {
+       { .compatible = "allwinner,suniv-f1c100s-ccu" },
+       { }
+};
+
+static struct platform_driver suniv_f1c100s_ccu_driver = {
+       .probe  = suniv_f1c100s_ccu_probe,
+       .driver = {
+               .name                   = "suniv-f1c100s-ccu",
+               .suppress_bind_attrs    = true,
+               .of_match_table         = suniv_f1c100s_ccu_ids,
+       },
+};
+module_platform_driver(suniv_f1c100s_ccu_driver);
+
+MODULE_IMPORT_NS(SUNXI_CCU);
+MODULE_LICENSE("GPL");
index 31af8b6..8d28a7a 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/clk-provider.h>
 #include <linux/device.h>
 #include <linux/iopoll.h>
+#include <linux/module.h>
 #include <linux/slab.h>
 
 #include "ccu_common.h"
@@ -36,6 +37,7 @@ void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock)
 
        WARN_ON(readl_relaxed_poll_timeout(addr, reg, reg & lock, 100, 70000));
 }
+EXPORT_SYMBOL_NS_GPL(ccu_helper_wait_for_lock, SUNXI_CCU);
 
 /*
  * This clock notifier is called when the frequency of a PLL clock is
@@ -83,6 +85,7 @@ int ccu_pll_notifier_register(struct ccu_pll_nb *pll_nb)
        return clk_notifier_register(pll_nb->common->hw.clk,
                                     &pll_nb->clk_nb);
 }
+EXPORT_SYMBOL_NS_GPL(ccu_pll_notifier_register, SUNXI_CCU);
 
 static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev,
                           struct device_node *node, void __iomem *reg,
@@ -194,6 +197,7 @@ int devm_sunxi_ccu_probe(struct device *dev, void __iomem *reg,
 
        return 0;
 }
+EXPORT_SYMBOL_NS_GPL(devm_sunxi_ccu_probe, SUNXI_CCU);
 
 void of_sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
                        const struct sunxi_ccu_desc *desc)
@@ -211,3 +215,5 @@ void of_sunxi_ccu_probe(struct device_node *node, void __iomem *reg,
                kfree(ccu);
        }
 }
+
+MODULE_LICENSE("GPL");
index 4c29708..cb10a3e 100644 (file)
@@ -141,3 +141,4 @@ const struct clk_ops ccu_div_ops = {
        .recalc_rate    = ccu_div_recalc_rate,
        .set_rate       = ccu_div_set_rate,
 };
+EXPORT_SYMBOL_NS_GPL(ccu_div_ops, SUNXI_CCU);
index 6682fde..948e2b0 100644 (file)
@@ -108,6 +108,22 @@ struct ccu_div {
                                      _shift, _width, _table, 0,        \
                                      _flags)
 
+#define SUNXI_CCU_DIV_TABLE_HW(_struct, _name, _parent, _reg,          \
+                              _shift, _width,                          \
+                              _table, _flags)                          \
+       struct ccu_div _struct = {                                      \
+               .div            = _SUNXI_CCU_DIV_TABLE(_shift, _width,  \
+                                                      _table),         \
+               .common = {                                             \
+                       .reg            = _reg,                         \
+                       .hw.init        = CLK_HW_INIT_HW(_name,         \
+                                                        _parent,       \
+                                                        &ccu_div_ops,  \
+                                                        _flags),       \
+               }                                                       \
+       }
+
+
 #define SUNXI_CCU_M_WITH_MUX_TABLE_GATE(_struct, _name,                        \
                                        _parents, _table,               \
                                        _reg,                           \
@@ -166,6 +182,68 @@ struct ccu_div {
        SUNXI_CCU_M_WITH_GATE(_struct, _name, _parent, _reg,            \
                              _mshift, _mwidth, 0, _flags)
 
+#define SUNXI_CCU_M_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
+                                      _mshift, _mwidth,                \
+                                      _muxshift, _muxwidth,            \
+                                      _gate, _flags)                   \
+       struct ccu_div _struct = {                                      \
+               .enable = _gate,                                        \
+               .div    = _SUNXI_CCU_DIV(_mshift, _mwidth),             \
+               .mux    = _SUNXI_CCU_MUX(_muxshift, _muxwidth),         \
+               .common = {                                             \
+                       .reg            = _reg,                         \
+                       .hw.init        = CLK_HW_INIT_PARENTS_DATA(_name, \
+                                                                  _parents, \
+                                                                  &ccu_div_ops, \
+                                                                  _flags), \
+               },                                                      \
+       }
+
+#define SUNXI_CCU_M_DATA_WITH_MUX(_struct, _name, _parents, _reg,      \
+                                 _mshift, _mwidth,                     \
+                                 _muxshift, _muxwidth,                 \
+                                 _flags)                               \
+       SUNXI_CCU_M_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg,  \
+                                      _mshift, _mwidth,                \
+                                      _muxshift, _muxwidth,            \
+                                      0, _flags)
+
+#define SUNXI_CCU_M_HW_WITH_MUX_GATE(_struct, _name, _parents, _reg,   \
+                                    _mshift, _mwidth, _muxshift, _muxwidth, \
+                                    _gate, _flags)                     \
+       struct ccu_div _struct = {                                      \
+               .enable = _gate,                                        \
+               .div    = _SUNXI_CCU_DIV(_mshift, _mwidth),             \
+               .mux    = _SUNXI_CCU_MUX(_muxshift, _muxwidth),         \
+               .common = {                                             \
+                       .reg            = _reg,                         \
+                       .hw.init        = CLK_HW_INIT_PARENTS_HW(_name, \
+                                                                _parents, \
+                                                                &ccu_div_ops, \
+                                                                _flags), \
+               },                                                      \
+       }
+
+#define SUNXI_CCU_M_HWS_WITH_GATE(_struct, _name, _parent, _reg,       \
+                                 _mshift, _mwidth, _gate,              \
+                                 _flags)                               \
+       struct ccu_div _struct = {                                      \
+               .enable = _gate,                                        \
+               .div    = _SUNXI_CCU_DIV(_mshift, _mwidth),             \
+               .common = {                                             \
+                       .reg            = _reg,                         \
+                       .hw.init        = CLK_HW_INIT_HWS(_name,        \
+                                                         _parent,      \
+                                                         &ccu_div_ops, \
+                                                         _flags),      \
+               },                                                      \
+       }
+
+#define SUNXI_CCU_M_HWS(_struct, _name, _parent, _reg, _mshift,                \
+                       _mwidth, _flags)                                \
+       SUNXI_CCU_M_HWS_WITH_GATE(_struct, _name, _parent, _reg,        \
+                                 _mshift, _mwidth, 0, _flags)
+
 static inline struct ccu_div *hw_to_ccu_div(struct clk_hw *hw)
 {
        struct ccu_common *common = hw_to_ccu_common(hw);
index 44fcded..b31f3ad 100644 (file)
@@ -18,6 +18,7 @@ bool ccu_frac_helper_is_enabled(struct ccu_common *common,
 
        return !(readl(common->base + common->reg) & cf->enable);
 }
+EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_is_enabled, SUNXI_CCU);
 
 void ccu_frac_helper_enable(struct ccu_common *common,
                            struct ccu_frac_internal *cf)
@@ -33,6 +34,7 @@ void ccu_frac_helper_enable(struct ccu_common *common,
        writel(reg & ~cf->enable, common->base + common->reg);
        spin_unlock_irqrestore(common->lock, flags);
 }
+EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_enable, SUNXI_CCU);
 
 void ccu_frac_helper_disable(struct ccu_common *common,
                             struct ccu_frac_internal *cf)
@@ -48,6 +50,7 @@ void ccu_frac_helper_disable(struct ccu_common *common,
        writel(reg | cf->enable, common->base + common->reg);
        spin_unlock_irqrestore(common->lock, flags);
 }
+EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_disable, SUNXI_CCU);
 
 bool ccu_frac_helper_has_rate(struct ccu_common *common,
                              struct ccu_frac_internal *cf,
@@ -58,6 +61,7 @@ bool ccu_frac_helper_has_rate(struct ccu_common *common,
 
        return (cf->rates[0] == rate) || (cf->rates[1] == rate);
 }
+EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_has_rate, SUNXI_CCU);
 
 unsigned long ccu_frac_helper_read_rate(struct ccu_common *common,
                                        struct ccu_frac_internal *cf)
@@ -79,6 +83,7 @@ unsigned long ccu_frac_helper_read_rate(struct ccu_common *common,
 
        return (reg & cf->select) ? cf->rates[1] : cf->rates[0];
 }
+EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_read_rate, SUNXI_CCU);
 
 int ccu_frac_helper_set_rate(struct ccu_common *common,
                             struct ccu_frac_internal *cf,
@@ -107,3 +112,4 @@ int ccu_frac_helper_set_rate(struct ccu_common *common,
 
        return 0;
 }
+EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_set_rate, SUNXI_CCU);
index 3d5ca09..a2115a2 100644 (file)
@@ -24,6 +24,7 @@ void ccu_gate_helper_disable(struct ccu_common *common, u32 gate)
 
        spin_unlock_irqrestore(common->lock, flags);
 }
+EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_disable, SUNXI_CCU);
 
 static void ccu_gate_disable(struct clk_hw *hw)
 {
@@ -49,6 +50,7 @@ int ccu_gate_helper_enable(struct ccu_common *common, u32 gate)
 
        return 0;
 }
+EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_enable, SUNXI_CCU);
 
 static int ccu_gate_enable(struct clk_hw *hw)
 {
@@ -64,6 +66,7 @@ int ccu_gate_helper_is_enabled(struct ccu_common *common, u32 gate)
 
        return readl(common->base + common->reg) & gate;
 }
+EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_is_enabled, SUNXI_CCU);
 
 static int ccu_gate_is_enabled(struct clk_hw *hw)
 {
@@ -124,3 +127,4 @@ const struct clk_ops ccu_gate_ops = {
        .set_rate       = ccu_gate_set_rate,
        .recalc_rate    = ccu_gate_recalc_rate,
 };
+EXPORT_SYMBOL_NS_GPL(ccu_gate_ops, SUNXI_CCU);
index c386689..dc05ce0 100644 (file)
@@ -53,7 +53,7 @@ struct ccu_gate {
        }
 
 /*
- * The following two macros allow the re-use of the data structure
+ * The following macros allow the re-use of the data structure
  * holding the parent info.
  */
 #define SUNXI_CCU_GATE_HWS(_struct, _name, _parent, _reg, _gate, _flags) \
@@ -68,6 +68,21 @@ struct ccu_gate {
                }                                                       \
        }
 
+#define SUNXI_CCU_GATE_HWS_WITH_PREDIV(_struct, _name, _parent, _reg,  \
+                                      _gate, _prediv, _flags)          \
+       struct ccu_gate _struct = {                                     \
+               .enable = _gate,                                        \
+               .common = {                                             \
+                       .reg            = _reg,                         \
+                       .prediv         = _prediv,                      \
+                       .features       = CCU_FEATURE_ALL_PREDIV,       \
+                       .hw.init        = CLK_HW_INIT_HWS(_name,        \
+                                                         _parent,      \
+                                                         &ccu_gate_ops, \
+                                                         _flags),      \
+               }                                                       \
+       }
+
 #define SUNXI_CCU_GATE_DATA(_struct, _name, _data, _reg, _gate, _flags)        \
        struct ccu_gate _struct = {                                     \
                .enable = _gate,                                        \
@@ -81,6 +96,21 @@ struct ccu_gate {
                }                                                       \
        }
 
+#define SUNXI_CCU_GATE_DATA_WITH_PREDIV(_struct, _name, _parent, _reg, \
+                                       _gate, _prediv, _flags)         \
+       struct ccu_gate _struct = {                                     \
+               .enable = _gate,                                        \
+               .common = {                                             \
+                       .reg            = _reg,                         \
+                       .prediv         = _prediv,                      \
+                       .features       = CCU_FEATURE_ALL_PREDIV,       \
+                       .hw.init        = CLK_HW_INIT_PARENTS_DATA(_name, \
+                                                                  _parent, \
+                                                                  &ccu_gate_ops, \
+                                                                  _flags), \
+               }                                                       \
+       }
+
 static inline struct ccu_gate *hw_to_ccu_gate(struct clk_hw *hw)
 {
        struct ccu_common *common = hw_to_ccu_common(hw);
index 9d3a766..57cf2d6 100644 (file)
@@ -245,6 +245,7 @@ const struct clk_ops ccu_mp_ops = {
        .recalc_rate    = ccu_mp_recalc_rate,
        .set_rate       = ccu_mp_set_rate,
 };
+EXPORT_SYMBOL_NS_GPL(ccu_mp_ops, SUNXI_CCU);
 
 /*
  * Support for MMC timing mode switching
@@ -325,3 +326,4 @@ const struct clk_ops ccu_mp_mmc_ops = {
        .recalc_rate    = ccu_mp_mmc_recalc_rate,
        .set_rate       = ccu_mp_mmc_set_rate,
 };
+EXPORT_SYMBOL_NS_GPL(ccu_mp_mmc_ops, SUNXI_CCU);
index b392e0d..6e50f37 100644 (file)
@@ -82,6 +82,55 @@ struct ccu_mp {
                                   _muxshift, _muxwidth,                \
                                   0, _flags)
 
+#define SUNXI_CCU_MP_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg,        \
+                                       _mshift, _mwidth,               \
+                                       _pshift, _pwidth,               \
+                                       _muxshift, _muxwidth,           \
+                                       _gate, _flags)                  \
+       struct ccu_mp _struct = {                                       \
+               .enable = _gate,                                        \
+               .m      = _SUNXI_CCU_DIV(_mshift, _mwidth),             \
+               .p      = _SUNXI_CCU_DIV(_pshift, _pwidth),             \
+               .mux    = _SUNXI_CCU_MUX(_muxshift, _muxwidth),         \
+               .common = {                                             \
+                       .reg            = _reg,                         \
+                       .hw.init        = CLK_HW_INIT_PARENTS_DATA(_name, \
+                                                                  _parents, \
+                                                                  &ccu_mp_ops, \
+                                                                  _flags), \
+               }                                                       \
+       }
+
+#define SUNXI_CCU_MP_DATA_WITH_MUX(_struct, _name, _parents, _reg,     \
+                                  _mshift, _mwidth,                    \
+                                  _pshift, _pwidth,                    \
+                                  _muxshift, _muxwidth,                \
+                                  _flags)                              \
+       SUNXI_CCU_MP_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
+                                       _mshift, _mwidth,               \
+                                       _pshift, _pwidth,               \
+                                       _muxshift, _muxwidth,           \
+                                       0, _flags)
+
+#define SUNXI_CCU_MP_HW_WITH_MUX_GATE(_struct, _name, _parents, _reg,  \
+                                     _mshift, _mwidth,                 \
+                                     _pshift, _pwidth,                 \
+                                     _muxshift, _muxwidth,             \
+                                     _gate, _flags)                    \
+       struct ccu_mp _struct = {                                       \
+               .enable = _gate,                                        \
+               .m      = _SUNXI_CCU_DIV(_mshift, _mwidth),             \
+               .p      = _SUNXI_CCU_DIV(_pshift, _pwidth),             \
+               .mux    = _SUNXI_CCU_MUX(_muxshift, _muxwidth),         \
+               .common = {                                             \
+                       .reg            = _reg,                         \
+                       .hw.init        = CLK_HW_INIT_PARENTS_HW(_name, \
+                                                                _parents, \
+                                                                &ccu_mp_ops, \
+                                                                _flags), \
+               }                                                       \
+       }
+
 static inline struct ccu_mp *hw_to_ccu_mp(struct clk_hw *hw)
 {
        struct ccu_common *common = hw_to_ccu_common(hw);
index 7c8cf2e..7bee217 100644 (file)
@@ -170,3 +170,4 @@ const struct clk_ops ccu_mult_ops = {
        .recalc_rate    = ccu_mult_recalc_rate,
        .set_rate       = ccu_mult_set_rate,
 };
+EXPORT_SYMBOL_NS_GPL(ccu_mult_ops, SUNXI_CCU);
index 7d75da9..2306a1c 100644 (file)
@@ -64,6 +64,7 @@ unsigned long ccu_mux_helper_apply_prediv(struct ccu_common *common,
 {
        return parent_rate / ccu_mux_get_prediv(common, cm, parent_index);
 }
+EXPORT_SYMBOL_NS_GPL(ccu_mux_helper_apply_prediv, SUNXI_CCU);
 
 static unsigned long ccu_mux_helper_unapply_prediv(struct ccu_common *common,
                                            struct ccu_mux_internal *cm,
@@ -152,6 +153,7 @@ out:
        req->rate = best_rate;
        return 0;
 }
+EXPORT_SYMBOL_NS_GPL(ccu_mux_helper_determine_rate, SUNXI_CCU);
 
 u8 ccu_mux_helper_get_parent(struct ccu_common *common,
                             struct ccu_mux_internal *cm)
@@ -174,6 +176,7 @@ u8 ccu_mux_helper_get_parent(struct ccu_common *common,
 
        return parent;
 }
+EXPORT_SYMBOL_NS_GPL(ccu_mux_helper_get_parent, SUNXI_CCU);
 
 int ccu_mux_helper_set_parent(struct ccu_common *common,
                              struct ccu_mux_internal *cm,
@@ -195,6 +198,7 @@ int ccu_mux_helper_set_parent(struct ccu_common *common,
 
        return 0;
 }
+EXPORT_SYMBOL_NS_GPL(ccu_mux_helper_set_parent, SUNXI_CCU);
 
 static void ccu_mux_disable(struct clk_hw *hw)
 {
@@ -251,6 +255,7 @@ const struct clk_ops ccu_mux_ops = {
        .determine_rate = __clk_mux_determine_rate,
        .recalc_rate    = ccu_mux_recalc_rate,
 };
+EXPORT_SYMBOL_NS_GPL(ccu_mux_ops, SUNXI_CCU);
 
 /*
  * This clock notifier is called when the frequency of the of the parent
@@ -285,3 +290,4 @@ int ccu_mux_notifier_register(struct clk *clk, struct ccu_mux_nb *mux_nb)
 
        return clk_notifier_register(clk, &mux_nb->clk_nb);
 }
+EXPORT_SYMBOL_NS_GPL(ccu_mux_notifier_register, SUNXI_CCU);
index e31efc5..2c1811a 100644 (file)
@@ -72,6 +72,39 @@ struct ccu_mux {
        SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, NULL,   \
                                      _reg, _shift, _width, 0, _flags)
 
+#define SUNXI_CCU_MUX_DATA_WITH_GATE(_struct, _name, _parents, _reg,   \
+                                    _shift, _width, _gate, _flags)     \
+       struct ccu_mux _struct = {                                      \
+               .enable = _gate,                                        \
+               .mux    = _SUNXI_CCU_MUX(_shift, _width),               \
+               .common = {                                             \
+                       .reg            = _reg,                         \
+                       .hw.init        = CLK_HW_INIT_PARENTS_DATA(_name, \
+                                                                  _parents, \
+                                                                  &ccu_mux_ops, \
+                                                                  _flags), \
+               }                                                       \
+       }
+
+#define SUNXI_CCU_MUX_DATA(_struct, _name, _parents, _reg,             \
+                     _shift, _width, _flags)                           \
+       SUNXI_CCU_MUX_DATA_WITH_GATE(_struct, _name, _parents, _reg,    \
+                                    _shift, _width, 0, _flags)
+
+#define SUNXI_CCU_MUX_HW_WITH_GATE(_struct, _name, _parents, _reg,     \
+                                  _shift, _width, _gate, _flags)       \
+       struct ccu_mux _struct = {                                      \
+               .enable = _gate,                                        \
+               .mux    = _SUNXI_CCU_MUX(_shift, _width),               \
+               .common = {                                             \
+                       .reg            = _reg,                         \
+                       .hw.init        = CLK_HW_INIT_PARENTS_HW(_name, \
+                                                                _parents, \
+                                                                &ccu_mux_ops, \
+                                                                _flags), \
+               }                                                       \
+       }
+
 static inline struct ccu_mux *hw_to_ccu_mux(struct clk_hw *hw)
 {
        struct ccu_common *common = hw_to_ccu_common(hw);
index aee68b0..c4fb82a 100644 (file)
@@ -157,3 +157,4 @@ const struct clk_ops ccu_nk_ops = {
        .round_rate     = ccu_nk_round_rate,
        .set_rate       = ccu_nk_set_rate,
 };
+EXPORT_SYMBOL_NS_GPL(ccu_nk_ops, SUNXI_CCU);
index b9cfee0..67da2c1 100644 (file)
@@ -206,3 +206,4 @@ const struct clk_ops ccu_nkm_ops = {
        .recalc_rate    = ccu_nkm_recalc_rate,
        .set_rate       = ccu_nkm_set_rate,
 };
+EXPORT_SYMBOL_NS_GPL(ccu_nkm_ops, SUNXI_CCU);
index bda87b3..39413cb 100644 (file)
@@ -230,3 +230,4 @@ const struct clk_ops ccu_nkmp_ops = {
        .round_rate     = ccu_nkmp_round_rate,
        .set_rate       = ccu_nkmp_set_rate,
 };
+EXPORT_SYMBOL_NS_GPL(ccu_nkmp_ops, SUNXI_CCU);
index e6bcc0a..9ca9257 100644 (file)
@@ -238,3 +238,4 @@ const struct clk_ops ccu_nm_ops = {
        .round_rate     = ccu_nm_round_rate,
        .set_rate       = ccu_nm_set_rate,
 };
+EXPORT_SYMBOL_NS_GPL(ccu_nm_ops, SUNXI_CCU);
index 92ab8bd..e4cae2a 100644 (file)
@@ -121,3 +121,4 @@ const struct clk_ops ccu_phase_ops = {
        .get_phase      = ccu_phase_get_phase,
        .set_phase      = ccu_phase_set_phase,
 };
+EXPORT_SYMBOL_NS_GPL(ccu_phase_ops, SUNXI_CCU);
index 483100e..6577aa1 100644 (file)
@@ -75,3 +75,4 @@ const struct reset_control_ops ccu_reset_ops = {
        .reset          = ccu_reset_reset,
        .status         = ccu_reset_status,
 };
+EXPORT_SYMBOL_NS_GPL(ccu_reset_ops, SUNXI_CCU);
index 79581a1..41937ed 100644 (file)
@@ -20,6 +20,7 @@ bool ccu_sdm_helper_is_enabled(struct ccu_common *common,
 
        return !!(readl(common->base + sdm->tuning_reg) & sdm->tuning_enable);
 }
+EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_is_enabled, SUNXI_CCU);
 
 void ccu_sdm_helper_enable(struct ccu_common *common,
                           struct ccu_sdm_internal *sdm,
@@ -49,6 +50,7 @@ void ccu_sdm_helper_enable(struct ccu_common *common,
        writel(reg | sdm->enable, common->base + common->reg);
        spin_unlock_irqrestore(common->lock, flags);
 }
+EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_enable, SUNXI_CCU);
 
 void ccu_sdm_helper_disable(struct ccu_common *common,
                            struct ccu_sdm_internal *sdm)
@@ -69,6 +71,7 @@ void ccu_sdm_helper_disable(struct ccu_common *common,
        writel(reg & ~sdm->tuning_enable, common->base + sdm->tuning_reg);
        spin_unlock_irqrestore(common->lock, flags);
 }
+EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_disable, SUNXI_CCU);
 
 /*
  * Sigma delta modulation provides a way to do fractional-N frequency
@@ -102,6 +105,7 @@ bool ccu_sdm_helper_has_rate(struct ccu_common *common,
 
        return false;
 }
+EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_has_rate, SUNXI_CCU);
 
 unsigned long ccu_sdm_helper_read_rate(struct ccu_common *common,
                                       struct ccu_sdm_internal *sdm,
@@ -132,6 +136,7 @@ unsigned long ccu_sdm_helper_read_rate(struct ccu_common *common,
        /* We can't calculate the effective clock rate, so just fail. */
        return 0;
 }
+EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_read_rate, SUNXI_CCU);
 
 int ccu_sdm_helper_get_factors(struct ccu_common *common,
                               struct ccu_sdm_internal *sdm,
@@ -153,3 +158,4 @@ int ccu_sdm_helper_get_factors(struct ccu_common *common,
        /* nothing found */
        return -EINVAL;
 }
+EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_get_factors, SUNXI_CCU);
index 8f7c514..fdc060e 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: MIT
 /*
- * clock framework for AMD Stoney based clocks
+ * clock framework for AMD FCH controller block
  *
  * Copyright 2018 Advanced Micro Devices, Inc.
  */
@@ -8,6 +8,7 @@
 #include <linux/clk.h>
 #include <linux/clkdev.h>
 #include <linux/clk-provider.h>
+#include <linux/pci.h>
 #include <linux/platform_data/clk-fch.h>
 #include <linux/platform_device.h>
 
 #define ST_CLK_GATE    3
 #define ST_MAX_CLKS    4
 
-#define RV_CLK_48M     0
-#define RV_CLK_GATE    1
-#define RV_MAX_CLKS    2
+#define CLK_48M_FIXED  0
+#define CLK_GATE_FIXED 1
+#define CLK_MAX_FIXED  2
+
+/* List of supported CPU ids for clk mux with 25Mhz clk support */
+#define AMD_CPU_ID_ST                  0x1576
 
 static const char * const clk_oscout1_parents[] = { "clk48MHz", "clk25MHz" };
 static struct clk_hw *hws[ST_MAX_CLKS];
 
+static const struct pci_device_id fch_pci_ids[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_ST) },
+       { }
+};
+
 static int fch_clk_probe(struct platform_device *pdev)
 {
        struct fch_clk_data *fch_data;
+       struct pci_dev *rdev;
 
        fch_data = dev_get_platdata(&pdev->dev);
        if (!fch_data || !fch_data->base)
                return -EINVAL;
 
-       if (!fch_data->is_rv) {
+       rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0));
+       if (!rdev) {
+               dev_err(&pdev->dev, "FCH device not found\n");
+               return -ENODEV;
+       }
+
+       if (pci_match_id(fch_pci_ids, rdev)) {
                hws[ST_CLK_48M] = clk_hw_register_fixed_rate(NULL, "clk48MHz",
                        NULL, 0, 48000000);
                hws[ST_CLK_25M] = clk_hw_register_fixed_rate(NULL, "clk25MHz",
@@ -59,34 +75,38 @@ static int fch_clk_probe(struct platform_device *pdev)
                        OSCCLKENB, CLK_GATE_SET_TO_DISABLE, NULL);
 
                devm_clk_hw_register_clkdev(&pdev->dev, hws[ST_CLK_GATE],
-                       "oscout1", NULL);
+                                           fch_data->name, NULL);
        } else {
-               hws[RV_CLK_48M] = clk_hw_register_fixed_rate(NULL, "clk48MHz",
+               hws[CLK_48M_FIXED] = clk_hw_register_fixed_rate(NULL, "clk48MHz",
                        NULL, 0, 48000000);
 
-               hws[RV_CLK_GATE] = clk_hw_register_gate(NULL, "oscout1",
+               hws[CLK_GATE_FIXED] = clk_hw_register_gate(NULL, "oscout1",
                        "clk48MHz", 0, fch_data->base + MISCCLKCNTL1,
-                       OSCCLKENB, CLK_GATE_SET_TO_DISABLE, NULL);
+                       OSCCLKENB, 0, NULL);
 
-               devm_clk_hw_register_clkdev(&pdev->dev, hws[RV_CLK_GATE],
-                       "oscout1", NULL);
+               devm_clk_hw_register_clkdev(&pdev->dev, hws[CLK_GATE_FIXED],
+                                           fch_data->name, NULL);
        }
 
+       pci_dev_put(rdev);
        return 0;
 }
 
 static int fch_clk_remove(struct platform_device *pdev)
 {
        int i, clks;
-       struct fch_clk_data *fch_data;
+       struct pci_dev *rdev;
 
-       fch_data = dev_get_platdata(&pdev->dev);
+       rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0));
+       if (!rdev)
+               return -ENODEV;
 
-       clks = fch_data->is_rv ? RV_MAX_CLKS : ST_MAX_CLKS;
+       clks = pci_match_id(fch_pci_ids, rdev) ? CLK_MAX_FIXED : ST_MAX_CLKS;
 
        for (i = 0; i < clks; i++)
                clk_hw_unregister(hws[i]);
 
+       pci_dev_put(rdev);
        return 0;
 }
 
index 92c1cc0..c87ce22 100644 (file)
@@ -144,9 +144,12 @@ static int i2c_acpi_do_lookup(struct acpi_device *adev,
        struct list_head resource_list;
        int ret;
 
-       if (acpi_bus_get_status(adev) || !adev->status.present)
+       if (acpi_bus_get_status(adev))
                return -EINVAL;
 
+       if (!acpi_dev_ready_for_enumeration(adev))
+               return -ENODEV;
+
        if (acpi_match_device_ids(adev, i2c_acpi_ignored_device_ids) == 0)
                return -ENODEV;
 
@@ -473,8 +476,8 @@ struct notifier_block i2c_acpi_notifier = {
 };
 
 /**
- * i2c_acpi_new_device - Create i2c-client for the Nth I2cSerialBus resource
- * @dev:     Device owning the ACPI resources to get the client from
+ * i2c_acpi_new_device_by_fwnode - Create i2c-client for the Nth I2cSerialBus resource
+ * @fwnode:  fwnode with the ACPI resources to get the client from
  * @index:   Index of ACPI resource to get
  * @info:    describes the I2C device; note this is modified (addr gets set)
  * Context: can sleep
@@ -490,15 +493,20 @@ struct notifier_block i2c_acpi_notifier = {
  * Returns a pointer to the new i2c-client, or error pointer in case of failure.
  * Specifically, -EPROBE_DEFER is returned if the adapter is not found.
  */
-struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
-                                      struct i2c_board_info *info)
+struct i2c_client *i2c_acpi_new_device_by_fwnode(struct fwnode_handle *fwnode,
+                                                int index,
+                                                struct i2c_board_info *info)
 {
-       struct acpi_device *adev = ACPI_COMPANION(dev);
        struct i2c_acpi_lookup lookup;
        struct i2c_adapter *adapter;
+       struct acpi_device *adev;
        LIST_HEAD(resource_list);
        int ret;
 
+       adev = to_acpi_device_node(fwnode);
+       if (!adev)
+               return ERR_PTR(-ENODEV);
+
        memset(&lookup, 0, sizeof(lookup));
        lookup.info = info;
        lookup.device_handle = acpi_device_handle(adev);
@@ -520,7 +528,7 @@ struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
 
        return i2c_new_client_device(adapter, info);
 }
-EXPORT_SYMBOL_GPL(i2c_acpi_new_device);
+EXPORT_SYMBOL_GPL(i2c_acpi_new_device_by_fwnode);
 
 bool i2c_acpi_waive_d0_probe(struct device *dev)
 {
index 5af8494..52b0b27 100644 (file)
@@ -966,6 +966,7 @@ config MMC_REALTEK_USB
 config MMC_SUNXI
        tristate "Allwinner sunxi SD/MMC Host Controller support"
        depends on ARCH_SUNXI || COMPILE_TEST
+       depends on SUNXI_CCU
        help
          This selects support for the SD/MMC Host Controller on
          Allwinner sunxi SoCs.
index 2362e04..cfec778 100644 (file)
@@ -1,5 +1,4 @@
-obj-$(CONFIG_INTEL_SKL_INT3472)                += intel_skl_int3472.o
-intel_skl_int3472-y                    := intel_skl_int3472_common.o \
-                                          intel_skl_int3472_discrete.o \
-                                          intel_skl_int3472_tps68470.o \
-                                          intel_skl_int3472_clk_and_regulator.o
+obj-$(CONFIG_INTEL_SKL_INT3472)                += intel_skl_int3472_discrete.o \
+                                          intel_skl_int3472_tps68470.o
+intel_skl_int3472_discrete-y           := discrete.o clk_and_regulator.o common.o
+intel_skl_int3472_tps68470-y           := tps68470.o tps68470_board_data.o common.o
diff --git a/drivers/platform/x86/intel/int3472/clk_and_regulator.c b/drivers/platform/x86/intel/int3472/clk_and_regulator.c
new file mode 100644 (file)
index 0000000..1cf9589
--- /dev/null
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Dan Scally <djrscally@gmail.com> */
+
+#include <linux/acpi.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/driver.h>
+#include <linux/slab.h>
+
+#include "common.h"
+
+/*
+ * The regulators have to have .ops to be valid, but the only ops we actually
+ * support are .enable and .disable which are handled via .ena_gpiod. Pass an
+ * empty struct to clear the check without lying about capabilities.
+ */
+static const struct regulator_ops int3472_gpio_regulator_ops;
+
+static int skl_int3472_clk_prepare(struct clk_hw *hw)
+{
+       struct int3472_gpio_clock *clk = to_int3472_clk(hw);
+
+       gpiod_set_value_cansleep(clk->ena_gpio, 1);
+       gpiod_set_value_cansleep(clk->led_gpio, 1);
+
+       return 0;
+}
+
+static void skl_int3472_clk_unprepare(struct clk_hw *hw)
+{
+       struct int3472_gpio_clock *clk = to_int3472_clk(hw);
+
+       gpiod_set_value_cansleep(clk->ena_gpio, 0);
+       gpiod_set_value_cansleep(clk->led_gpio, 0);
+}
+
+static int skl_int3472_clk_enable(struct clk_hw *hw)
+{
+       /*
+        * We're just turning a GPIO on to enable the clock, which operation
+        * has the potential to sleep. Given .enable() cannot sleep, but
+        * .prepare() can, we toggle the GPIO in .prepare() instead. Thus,
+        * nothing to do here.
+        */
+       return 0;
+}
+
+static void skl_int3472_clk_disable(struct clk_hw *hw)
+{
+       /* Likewise, nothing to do here... */
+}
+
+static unsigned int skl_int3472_get_clk_frequency(struct int3472_discrete_device *int3472)
+{
+       union acpi_object *obj;
+       unsigned int freq;
+
+       obj = skl_int3472_get_acpi_buffer(int3472->sensor, "SSDB");
+       if (IS_ERR(obj))
+               return 0; /* report rate as 0 on error */
+
+       if (obj->buffer.length < CIO2_SENSOR_SSDB_MCLKSPEED_OFFSET + sizeof(u32)) {
+               dev_err(int3472->dev, "The buffer is too small\n");
+               kfree(obj);
+               return 0;
+       }
+
+       freq = *(u32 *)(obj->buffer.pointer + CIO2_SENSOR_SSDB_MCLKSPEED_OFFSET);
+
+       kfree(obj);
+       return freq;
+}
+
+static unsigned long skl_int3472_clk_recalc_rate(struct clk_hw *hw,
+                                                unsigned long parent_rate)
+{
+       struct int3472_gpio_clock *clk = to_int3472_clk(hw);
+
+       return clk->frequency;
+}
+
+static const struct clk_ops skl_int3472_clock_ops = {
+       .prepare = skl_int3472_clk_prepare,
+       .unprepare = skl_int3472_clk_unprepare,
+       .enable = skl_int3472_clk_enable,
+       .disable = skl_int3472_clk_disable,
+       .recalc_rate = skl_int3472_clk_recalc_rate,
+};
+
+int skl_int3472_register_clock(struct int3472_discrete_device *int3472)
+{
+       struct clk_init_data init = {
+               .ops = &skl_int3472_clock_ops,
+               .flags = CLK_GET_RATE_NOCACHE,
+       };
+       int ret;
+
+       init.name = kasprintf(GFP_KERNEL, "%s-clk",
+                             acpi_dev_name(int3472->adev));
+       if (!init.name)
+               return -ENOMEM;
+
+       int3472->clock.frequency = skl_int3472_get_clk_frequency(int3472);
+
+       int3472->clock.clk_hw.init = &init;
+       int3472->clock.clk = clk_register(&int3472->adev->dev,
+                                         &int3472->clock.clk_hw);
+       if (IS_ERR(int3472->clock.clk)) {
+               ret = PTR_ERR(int3472->clock.clk);
+               goto out_free_init_name;
+       }
+
+       int3472->clock.cl = clkdev_create(int3472->clock.clk, NULL,
+                                         int3472->sensor_name);
+       if (!int3472->clock.cl) {
+               ret = -ENOMEM;
+               goto err_unregister_clk;
+       }
+
+       kfree(init.name);
+       return 0;
+
+err_unregister_clk:
+       clk_unregister(int3472->clock.clk);
+out_free_init_name:
+       kfree(init.name);
+
+       return ret;
+}
+
+void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472)
+{
+       clkdev_drop(int3472->clock.cl);
+       clk_unregister(int3472->clock.clk);
+}
+
+int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
+                                  struct acpi_resource_gpio *agpio)
+{
+       const struct int3472_sensor_config *sensor_config;
+       char *path = agpio->resource_source.string_ptr;
+       struct regulator_consumer_supply supply_map;
+       struct regulator_init_data init_data = { };
+       struct regulator_config cfg = { };
+       int ret;
+
+       sensor_config = int3472->sensor_config;
+       if (IS_ERR(sensor_config)) {
+               dev_err(int3472->dev, "No sensor module config\n");
+               return PTR_ERR(sensor_config);
+       }
+
+       if (!sensor_config->supply_map.supply) {
+               dev_err(int3472->dev, "No supply name defined\n");
+               return -ENODEV;
+       }
+
+       init_data.constraints.valid_ops_mask = REGULATOR_CHANGE_STATUS;
+       init_data.num_consumer_supplies = 1;
+       supply_map = sensor_config->supply_map;
+       supply_map.dev_name = int3472->sensor_name;
+       init_data.consumer_supplies = &supply_map;
+
+       snprintf(int3472->regulator.regulator_name,
+                sizeof(int3472->regulator.regulator_name), "%s-regulator",
+                acpi_dev_name(int3472->adev));
+       snprintf(int3472->regulator.supply_name,
+                GPIO_REGULATOR_SUPPLY_NAME_LENGTH, "supply-0");
+
+       int3472->regulator.rdesc = INT3472_REGULATOR(
+                                               int3472->regulator.regulator_name,
+                                               int3472->regulator.supply_name,
+                                               &int3472_gpio_regulator_ops);
+
+       int3472->regulator.gpio = acpi_get_and_request_gpiod(path, agpio->pin_table[0],
+                                                            "int3472,regulator");
+       if (IS_ERR(int3472->regulator.gpio)) {
+               dev_err(int3472->dev, "Failed to get regulator GPIO line\n");
+               return PTR_ERR(int3472->regulator.gpio);
+       }
+
+       cfg.dev = &int3472->adev->dev;
+       cfg.init_data = &init_data;
+       cfg.ena_gpiod = int3472->regulator.gpio;
+
+       int3472->regulator.rdev = regulator_register(&int3472->regulator.rdesc,
+                                                    &cfg);
+       if (IS_ERR(int3472->regulator.rdev)) {
+               ret = PTR_ERR(int3472->regulator.rdev);
+               goto err_free_gpio;
+       }
+
+       return 0;
+
+err_free_gpio:
+       gpiod_put(int3472->regulator.gpio);
+
+       return ret;
+}
+
+void skl_int3472_unregister_regulator(struct int3472_discrete_device *int3472)
+{
+       regulator_unregister(int3472->regulator.rdev);
+       gpiod_put(int3472->regulator.gpio);
+}
diff --git a/drivers/platform/x86/intel/int3472/common.c b/drivers/platform/x86/intel/int3472/common.c
new file mode 100644 (file)
index 0000000..77cf058
--- /dev/null
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Dan Scally <djrscally@gmail.com> */
+
+#include <linux/acpi.h>
+#include <linux/slab.h>
+
+#include "common.h"
+
+union acpi_object *skl_int3472_get_acpi_buffer(struct acpi_device *adev, char *id)
+{
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       acpi_handle handle = adev->handle;
+       union acpi_object *obj;
+       acpi_status status;
+
+       status = acpi_evaluate_object(handle, id, NULL, &buffer);
+       if (ACPI_FAILURE(status))
+               return ERR_PTR(-ENODEV);
+
+       obj = buffer.pointer;
+       if (!obj)
+               return ERR_PTR(-ENODEV);
+
+       if (obj->type != ACPI_TYPE_BUFFER) {
+               acpi_handle_err(handle, "%s object is not an ACPI buffer\n", id);
+               kfree(obj);
+               return ERR_PTR(-EINVAL);
+       }
+
+       return obj;
+}
+
+int skl_int3472_fill_cldb(struct acpi_device *adev, struct int3472_cldb *cldb)
+{
+       union acpi_object *obj;
+       int ret;
+
+       obj = skl_int3472_get_acpi_buffer(adev, "CLDB");
+       if (IS_ERR(obj))
+               return PTR_ERR(obj);
+
+       if (obj->buffer.length > sizeof(*cldb)) {
+               acpi_handle_err(adev->handle, "The CLDB buffer is too large\n");
+               ret = -EINVAL;
+               goto out_free_obj;
+       }
+
+       memcpy(cldb, obj->buffer.pointer, obj->buffer.length);
+       ret = 0;
+
+out_free_obj:
+       kfree(obj);
+       return ret;
+}
+
+/* sensor_adev_ret may be NULL, name_ret must not be NULL */
+int skl_int3472_get_sensor_adev_and_name(struct device *dev,
+                                        struct acpi_device **sensor_adev_ret,
+                                        const char **name_ret)
+{
+       struct acpi_device *adev = ACPI_COMPANION(dev);
+       struct acpi_device *sensor;
+       int ret = 0;
+
+       sensor = acpi_dev_get_first_consumer_dev(adev);
+       if (!sensor) {
+               dev_err(dev, "INT3472 seems to have no dependents.\n");
+               return -ENODEV;
+       }
+
+       *name_ret = devm_kasprintf(dev, GFP_KERNEL, I2C_DEV_NAME_FORMAT,
+                                  acpi_dev_name(sensor));
+       if (!*name_ret)
+               ret = -ENOMEM;
+
+       if (ret == 0 && sensor_adev_ret)
+               *sensor_adev_ret = sensor;
+       else
+               acpi_dev_put(sensor);
+
+       return ret;
+}
diff --git a/drivers/platform/x86/intel/int3472/common.h b/drivers/platform/x86/intel/int3472/common.h
new file mode 100644 (file)
index 0000000..53270d1
--- /dev/null
@@ -0,0 +1,122 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Author: Dan Scally <djrscally@gmail.com> */
+
+#ifndef _INTEL_SKL_INT3472_H
+#define _INTEL_SKL_INT3472_H
+
+#include <linux/clk-provider.h>
+#include <linux/gpio/machine.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/types.h>
+
+/* FIXME drop this once the I2C_DEV_NAME_FORMAT macro has been added to include/linux/i2c.h */
+#ifndef I2C_DEV_NAME_FORMAT
+#define I2C_DEV_NAME_FORMAT                                    "i2c-%s"
+#endif
+
+/* PMIC GPIO Types */
+#define INT3472_GPIO_TYPE_RESET                                        0x00
+#define INT3472_GPIO_TYPE_POWERDOWN                            0x01
+#define INT3472_GPIO_TYPE_POWER_ENABLE                         0x0b
+#define INT3472_GPIO_TYPE_CLK_ENABLE                           0x0c
+#define INT3472_GPIO_TYPE_PRIVACY_LED                          0x0d
+
+#define INT3472_PDEV_MAX_NAME_LEN                              23
+#define INT3472_MAX_SENSOR_GPIOS                               3
+
+#define GPIO_REGULATOR_NAME_LENGTH                             21
+#define GPIO_REGULATOR_SUPPLY_NAME_LENGTH                      9
+
+#define CIO2_SENSOR_SSDB_MCLKSPEED_OFFSET                      86
+
+#define INT3472_REGULATOR(_name, _supply, _ops)                        \
+       (const struct regulator_desc) {                         \
+               .name = _name,                                  \
+               .supply_name = _supply,                         \
+               .type = REGULATOR_VOLTAGE,                      \
+               .ops = _ops,                                    \
+               .owner = THIS_MODULE,                           \
+       }
+
+#define to_int3472_clk(hw)                                     \
+       container_of(hw, struct int3472_gpio_clock, clk_hw)
+
+#define to_int3472_device(clk)                                 \
+       container_of(clk, struct int3472_discrete_device, clock)
+
+struct acpi_device;
+struct i2c_client;
+struct platform_device;
+
+struct int3472_cldb {
+       u8 version;
+       /*
+        * control logic type
+        * 0: UNKNOWN
+        * 1: DISCRETE(CRD-D)
+        * 2: PMIC TPS68470
+        * 3: PMIC uP6641
+        */
+       u8 control_logic_type;
+       u8 control_logic_id;
+       u8 sensor_card_sku;
+       u8 reserved[28];
+};
+
+struct int3472_gpio_function_remap {
+       const char *documented;
+       const char *actual;
+};
+
+struct int3472_sensor_config {
+       const char *sensor_module_name;
+       struct regulator_consumer_supply supply_map;
+       const struct int3472_gpio_function_remap *function_maps;
+};
+
+struct int3472_discrete_device {
+       struct acpi_device *adev;
+       struct device *dev;
+       struct acpi_device *sensor;
+       const char *sensor_name;
+
+       const struct int3472_sensor_config *sensor_config;
+
+       struct int3472_gpio_regulator {
+               char regulator_name[GPIO_REGULATOR_NAME_LENGTH];
+               char supply_name[GPIO_REGULATOR_SUPPLY_NAME_LENGTH];
+               struct gpio_desc *gpio;
+               struct regulator_dev *rdev;
+               struct regulator_desc rdesc;
+       } regulator;
+
+       struct int3472_gpio_clock {
+               struct clk *clk;
+               struct clk_hw clk_hw;
+               struct clk_lookup *cl;
+               struct gpio_desc *ena_gpio;
+               struct gpio_desc *led_gpio;
+               u32 frequency;
+       } clock;
+
+       unsigned int ngpios; /* how many GPIOs have we seen */
+       unsigned int n_sensor_gpios; /* how many have we mapped to sensor */
+       struct gpiod_lookup_table gpios;
+};
+
+union acpi_object *skl_int3472_get_acpi_buffer(struct acpi_device *adev,
+                                              char *id);
+int skl_int3472_fill_cldb(struct acpi_device *adev, struct int3472_cldb *cldb);
+int skl_int3472_get_sensor_adev_and_name(struct device *dev,
+                                        struct acpi_device **sensor_adev_ret,
+                                        const char **name_ret);
+
+int skl_int3472_register_clock(struct int3472_discrete_device *int3472);
+void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472);
+
+int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
+                                  struct acpi_resource_gpio *agpio);
+void skl_int3472_unregister_regulator(struct int3472_discrete_device *int3472);
+
+#endif
diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c
new file mode 100644 (file)
index 0000000..5b514fa
--- /dev/null
@@ -0,0 +1,422 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Dan Scally <djrscally@gmail.com> */
+
+#include <linux/acpi.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/overflow.h>
+#include <linux/platform_device.h>
+#include <linux/uuid.h>
+
+#include "common.h"
+
+/*
+ * 79234640-9e10-4fea-a5c1-b5aa8b19756f
+ * This _DSM GUID returns information about the GPIO lines mapped to a
+ * discrete INT3472 device. Function number 1 returns a count of the GPIO
+ * lines that are mapped. Subsequent functions return 32 bit ints encoding
+ * information about the GPIO line, including its purpose.
+ */
+static const guid_t int3472_gpio_guid =
+       GUID_INIT(0x79234640, 0x9e10, 0x4fea,
+                 0xa5, 0xc1, 0xb5, 0xaa, 0x8b, 0x19, 0x75, 0x6f);
+
+/*
+ * 822ace8f-2814-4174-a56b-5f029fe079ee
+ * This _DSM GUID returns a string from the sensor device, which acts as a
+ * module identifier.
+ */
+static const guid_t cio2_sensor_module_guid =
+       GUID_INIT(0x822ace8f, 0x2814, 0x4174,
+                 0xa5, 0x6b, 0x5f, 0x02, 0x9f, 0xe0, 0x79, 0xee);
+
+/*
+ * Here follows platform specific mapping information that we can pass to
+ * the functions mapping resources to the sensors. Where the sensors have
+ * a power enable pin defined in DSDT we need to provide a supply name so
+ * the sensor drivers can find the regulator. The device name will be derived
+ * from the sensor's ACPI device within the code. Optionally, we can provide a
+ * NULL terminated array of function name mappings to deal with any platform
+ * specific deviations from the documented behaviour of GPIOs.
+ *
+ * Map a GPIO function name to NULL to prevent the driver from mapping that
+ * GPIO at all.
+ */
+
+static const struct int3472_gpio_function_remap ov2680_gpio_function_remaps[] = {
+       { "reset", NULL },
+       { "powerdown", "reset" },
+       { }
+};
+
+static const struct int3472_sensor_config int3472_sensor_configs[] = {
+       /* Lenovo Miix 510-12ISK - OV2680, Front */
+       { "GNDF140809R", { 0 }, ov2680_gpio_function_remaps },
+       /* Lenovo Miix 510-12ISK - OV5648, Rear */
+       { "GEFF150023R", REGULATOR_SUPPLY("avdd", NULL), NULL },
+       /* Surface Go 1&2 - OV5693, Front */
+       { "YHCU", REGULATOR_SUPPLY("avdd", NULL), NULL },
+};
+
+static const struct int3472_sensor_config *
+skl_int3472_get_sensor_module_config(struct int3472_discrete_device *int3472)
+{
+       union acpi_object *obj;
+       unsigned int i;
+
+       obj = acpi_evaluate_dsm_typed(int3472->sensor->handle,
+                                     &cio2_sensor_module_guid, 0x00,
+                                     0x01, NULL, ACPI_TYPE_STRING);
+
+       if (!obj) {
+               dev_err(int3472->dev,
+                       "Failed to get sensor module string from _DSM\n");
+               return ERR_PTR(-ENODEV);
+       }
+
+       if (obj->string.type != ACPI_TYPE_STRING) {
+               dev_err(int3472->dev,
+                       "Sensor _DSM returned a non-string value\n");
+
+               ACPI_FREE(obj);
+               return ERR_PTR(-EINVAL);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(int3472_sensor_configs); i++) {
+               if (!strcmp(int3472_sensor_configs[i].sensor_module_name,
+                           obj->string.pointer))
+                       break;
+       }
+
+       ACPI_FREE(obj);
+
+       if (i >= ARRAY_SIZE(int3472_sensor_configs))
+               return ERR_PTR(-EINVAL);
+
+       return &int3472_sensor_configs[i];
+}
+
+static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int3472,
+                                         struct acpi_resource_gpio *agpio,
+                                         const char *func, u32 polarity)
+{
+       const struct int3472_sensor_config *sensor_config;
+       char *path = agpio->resource_source.string_ptr;
+       struct gpiod_lookup *table_entry;
+       struct acpi_device *adev;
+       acpi_handle handle;
+       acpi_status status;
+       int ret;
+
+       if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) {
+               dev_warn(int3472->dev, "Too many GPIOs mapped\n");
+               return -EINVAL;
+       }
+
+       sensor_config = int3472->sensor_config;
+       if (!IS_ERR(sensor_config) && sensor_config->function_maps) {
+               const struct int3472_gpio_function_remap *remap;
+
+               for (remap = sensor_config->function_maps; remap->documented; remap++) {
+                       if (!strcmp(func, remap->documented)) {
+                               func = remap->actual;
+                               break;
+                       }
+               }
+       }
+
+       /* Functions mapped to NULL should not be mapped to the sensor */
+       if (!func)
+               return 0;
+
+       status = acpi_get_handle(NULL, path, &handle);
+       if (ACPI_FAILURE(status))
+               return -EINVAL;
+
+       ret = acpi_bus_get_device(handle, &adev);
+       if (ret)
+               return -ENODEV;
+
+       table_entry = &int3472->gpios.table[int3472->n_sensor_gpios];
+       table_entry->key = acpi_dev_name(adev);
+       table_entry->chip_hwnum = agpio->pin_table[0];
+       table_entry->con_id = func;
+       table_entry->idx = 0;
+       table_entry->flags = polarity;
+
+       int3472->n_sensor_gpios++;
+
+       return 0;
+}
+
+static int skl_int3472_map_gpio_to_clk(struct int3472_discrete_device *int3472,
+                                      struct acpi_resource_gpio *agpio, u8 type)
+{
+       char *path = agpio->resource_source.string_ptr;
+       u16 pin = agpio->pin_table[0];
+       struct gpio_desc *gpio;
+
+       switch (type) {
+       case INT3472_GPIO_TYPE_CLK_ENABLE:
+               gpio = acpi_get_and_request_gpiod(path, pin, "int3472,clk-enable");
+               if (IS_ERR(gpio))
+                       return (PTR_ERR(gpio));
+
+               int3472->clock.ena_gpio = gpio;
+               break;
+       case INT3472_GPIO_TYPE_PRIVACY_LED:
+               gpio = acpi_get_and_request_gpiod(path, pin, "int3472,privacy-led");
+               if (IS_ERR(gpio))
+                       return (PTR_ERR(gpio));
+
+               int3472->clock.led_gpio = gpio;
+               break;
+       default:
+               dev_err(int3472->dev, "Invalid GPIO type 0x%02x for clock\n", type);
+               break;
+       }
+
+       return 0;
+}
+
+/**
+ * skl_int3472_handle_gpio_resources: Map PMIC resources to consuming sensor
+ * @ares: A pointer to a &struct acpi_resource
+ * @data: A pointer to a &struct int3472_discrete_device
+ *
+ * This function handles GPIO resources that are against an INT3472
+ * ACPI device, by checking the value of the corresponding _DSM entry.
+ * This will return a 32bit int, where the lowest byte represents the
+ * function of the GPIO pin:
+ *
+ * 0x00 Reset
+ * 0x01 Power down
+ * 0x0b Power enable
+ * 0x0c Clock enable
+ * 0x0d Privacy LED
+ *
+ * There are some known platform specific quirks where that does not quite
+ * hold up; for example where a pin with type 0x01 (Power down) is mapped to
+ * a sensor pin that performs a reset function or entries in _CRS and _DSM that
+ * do not actually correspond to a physical connection. These will be handled
+ * by the mapping sub-functions.
+ *
+ * GPIOs will either be mapped directly to the sensor device or else used
+ * to create clocks and regulators via the usual frameworks.
+ *
+ * Return:
+ * * 1         - To continue the loop
+ * * 0         - When all resources found are handled properly.
+ * * -EINVAL   - If the resource is not a GPIO IO resource
+ * * -ENODEV   - If the resource has no corresponding _DSM entry
+ * * -Other    - Errors propagated from one of the sub-functions.
+ */
+static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
+                                            void *data)
+{
+       struct int3472_discrete_device *int3472 = data;
+       struct acpi_resource_gpio *agpio;
+       union acpi_object *obj;
+       const char *err_msg;
+       int ret;
+       u8 type;
+
+       if (!acpi_gpio_get_io_resource(ares, &agpio))
+               return 1;
+
+       /*
+        * ngpios + 2 because the index of this _DSM function is 1-based and
+        * the first function is just a count.
+        */
+       obj = acpi_evaluate_dsm_typed(int3472->adev->handle,
+                                     &int3472_gpio_guid, 0x00,
+                                     int3472->ngpios + 2,
+                                     NULL, ACPI_TYPE_INTEGER);
+
+       if (!obj) {
+               dev_warn(int3472->dev, "No _DSM entry for GPIO pin %u\n",
+                        agpio->pin_table[0]);
+               return 1;
+       }
+
+       type = obj->integer.value & 0xff;
+
+       switch (type) {
+       case INT3472_GPIO_TYPE_RESET:
+               ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, "reset",
+                                                    GPIO_ACTIVE_LOW);
+               if (ret)
+                       err_msg = "Failed to map reset pin to sensor\n";
+
+               break;
+       case INT3472_GPIO_TYPE_POWERDOWN:
+               ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, "powerdown",
+                                                    GPIO_ACTIVE_LOW);
+               if (ret)
+                       err_msg = "Failed to map powerdown pin to sensor\n";
+
+               break;
+       case INT3472_GPIO_TYPE_CLK_ENABLE:
+       case INT3472_GPIO_TYPE_PRIVACY_LED:
+               ret = skl_int3472_map_gpio_to_clk(int3472, agpio, type);
+               if (ret)
+                       err_msg = "Failed to map GPIO to clock\n";
+
+               break;
+       case INT3472_GPIO_TYPE_POWER_ENABLE:
+               ret = skl_int3472_register_regulator(int3472, agpio);
+               if (ret)
+                       err_msg = "Failed to map regulator to sensor\n";
+
+               break;
+       default:
+               dev_warn(int3472->dev,
+                        "GPIO type 0x%02x unknown; the sensor may not work\n",
+                        type);
+               ret = 1;
+               break;
+       }
+
+       int3472->ngpios++;
+       ACPI_FREE(obj);
+
+       if (ret < 0)
+               return dev_err_probe(int3472->dev, ret, err_msg);
+
+       return ret;
+}
+
+static int skl_int3472_parse_crs(struct int3472_discrete_device *int3472)
+{
+       LIST_HEAD(resource_list);
+       int ret;
+
+       /*
+        * No error check, because not having a sensor config is not necessarily
+        * a failure mode.
+        */
+       int3472->sensor_config = skl_int3472_get_sensor_module_config(int3472);
+
+       ret = acpi_dev_get_resources(int3472->adev, &resource_list,
+                                    skl_int3472_handle_gpio_resources,
+                                    int3472);
+       if (ret < 0)
+               return ret;
+
+       acpi_dev_free_resource_list(&resource_list);
+
+       /*
+        * If we find no clock enable GPIO pin then the privacy LED won't work.
+        * We've never seen that situation, but it's possible. Warn the user so
+        * it's clear what's happened.
+        */
+       if (int3472->clock.ena_gpio) {
+               ret = skl_int3472_register_clock(int3472);
+               if (ret)
+                       return ret;
+       } else {
+               if (int3472->clock.led_gpio)
+                       dev_warn(int3472->dev,
+                                "No clk GPIO. The privacy LED won't work\n");
+       }
+
+       int3472->gpios.dev_id = int3472->sensor_name;
+       gpiod_add_lookup_table(&int3472->gpios);
+
+       return 0;
+}
+
+static int skl_int3472_discrete_remove(struct platform_device *pdev);
+
+static int skl_int3472_discrete_probe(struct platform_device *pdev)
+{
+       struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
+       struct int3472_discrete_device *int3472;
+       struct int3472_cldb cldb;
+       int ret;
+
+       ret = skl_int3472_fill_cldb(adev, &cldb);
+       if (ret) {
+               dev_err(&pdev->dev, "Couldn't fill CLDB structure\n");
+               return ret;
+       }
+
+       if (cldb.control_logic_type != 1) {
+               dev_err(&pdev->dev, "Unsupported control logic type %u\n",
+                       cldb.control_logic_type);
+               return -EINVAL;
+       }
+
+       /* Max num GPIOs we've seen plus a terminator */
+       int3472 = devm_kzalloc(&pdev->dev, struct_size(int3472, gpios.table,
+                              INT3472_MAX_SENSOR_GPIOS + 1), GFP_KERNEL);
+       if (!int3472)
+               return -ENOMEM;
+
+       int3472->adev = adev;
+       int3472->dev = &pdev->dev;
+       platform_set_drvdata(pdev, int3472);
+
+       ret = skl_int3472_get_sensor_adev_and_name(&pdev->dev, &int3472->sensor,
+                                                  &int3472->sensor_name);
+       if (ret)
+               return ret;
+
+       /*
+        * Initialising this list means we can call gpiod_remove_lookup_table()
+        * in failure paths without issue.
+        */
+       INIT_LIST_HEAD(&int3472->gpios.list);
+
+       ret = skl_int3472_parse_crs(int3472);
+       if (ret) {
+               skl_int3472_discrete_remove(pdev);
+               return ret;
+       }
+
+       acpi_dev_clear_dependencies(adev);
+       return 0;
+}
+
+static int skl_int3472_discrete_remove(struct platform_device *pdev)
+{
+       struct int3472_discrete_device *int3472 = platform_get_drvdata(pdev);
+
+       gpiod_remove_lookup_table(&int3472->gpios);
+
+       if (int3472->clock.cl)
+               skl_int3472_unregister_clock(int3472);
+
+       gpiod_put(int3472->clock.ena_gpio);
+       gpiod_put(int3472->clock.led_gpio);
+
+       skl_int3472_unregister_regulator(int3472);
+
+       return 0;
+}
+
+static const struct acpi_device_id int3472_device_id[] = {
+       { "INT3472", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, int3472_device_id);
+
+static struct platform_driver int3472_discrete = {
+       .driver = {
+               .name = "int3472-discrete",
+               .acpi_match_table = int3472_device_id,
+       },
+       .probe = skl_int3472_discrete_probe,
+       .remove = skl_int3472_discrete_remove,
+};
+module_platform_driver(int3472_discrete);
+
+MODULE_DESCRIPTION("Intel SkyLake INT3472 ACPI Discrete Device Driver");
+MODULE_AUTHOR("Daniel Scally <djrscally@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/intel/int3472/intel_skl_int3472_clk_and_regulator.c b/drivers/platform/x86/intel/int3472/intel_skl_int3472_clk_and_regulator.c
deleted file mode 100644 (file)
index 1700e75..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Author: Dan Scally <djrscally@gmail.com> */
-
-#include <linux/acpi.h>
-#include <linux/clkdev.h>
-#include <linux/clk-provider.h>
-#include <linux/device.h>
-#include <linux/gpio/consumer.h>
-#include <linux/regulator/driver.h>
-#include <linux/slab.h>
-
-#include "intel_skl_int3472_common.h"
-
-/*
- * The regulators have to have .ops to be valid, but the only ops we actually
- * support are .enable and .disable which are handled via .ena_gpiod. Pass an
- * empty struct to clear the check without lying about capabilities.
- */
-static const struct regulator_ops int3472_gpio_regulator_ops;
-
-static int skl_int3472_clk_prepare(struct clk_hw *hw)
-{
-       struct int3472_gpio_clock *clk = to_int3472_clk(hw);
-
-       gpiod_set_value_cansleep(clk->ena_gpio, 1);
-       gpiod_set_value_cansleep(clk->led_gpio, 1);
-
-       return 0;
-}
-
-static void skl_int3472_clk_unprepare(struct clk_hw *hw)
-{
-       struct int3472_gpio_clock *clk = to_int3472_clk(hw);
-
-       gpiod_set_value_cansleep(clk->ena_gpio, 0);
-       gpiod_set_value_cansleep(clk->led_gpio, 0);
-}
-
-static int skl_int3472_clk_enable(struct clk_hw *hw)
-{
-       /*
-        * We're just turning a GPIO on to enable the clock, which operation
-        * has the potential to sleep. Given .enable() cannot sleep, but
-        * .prepare() can, we toggle the GPIO in .prepare() instead. Thus,
-        * nothing to do here.
-        */
-       return 0;
-}
-
-static void skl_int3472_clk_disable(struct clk_hw *hw)
-{
-       /* Likewise, nothing to do here... */
-}
-
-static unsigned int skl_int3472_get_clk_frequency(struct int3472_discrete_device *int3472)
-{
-       union acpi_object *obj;
-       unsigned int freq;
-
-       obj = skl_int3472_get_acpi_buffer(int3472->sensor, "SSDB");
-       if (IS_ERR(obj))
-               return 0; /* report rate as 0 on error */
-
-       if (obj->buffer.length < CIO2_SENSOR_SSDB_MCLKSPEED_OFFSET + sizeof(u32)) {
-               dev_err(int3472->dev, "The buffer is too small\n");
-               kfree(obj);
-               return 0;
-       }
-
-       freq = *(u32 *)(obj->buffer.pointer + CIO2_SENSOR_SSDB_MCLKSPEED_OFFSET);
-
-       kfree(obj);
-       return freq;
-}
-
-static unsigned long skl_int3472_clk_recalc_rate(struct clk_hw *hw,
-                                                unsigned long parent_rate)
-{
-       struct int3472_gpio_clock *clk = to_int3472_clk(hw);
-
-       return clk->frequency;
-}
-
-static const struct clk_ops skl_int3472_clock_ops = {
-       .prepare = skl_int3472_clk_prepare,
-       .unprepare = skl_int3472_clk_unprepare,
-       .enable = skl_int3472_clk_enable,
-       .disable = skl_int3472_clk_disable,
-       .recalc_rate = skl_int3472_clk_recalc_rate,
-};
-
-int skl_int3472_register_clock(struct int3472_discrete_device *int3472)
-{
-       struct clk_init_data init = {
-               .ops = &skl_int3472_clock_ops,
-               .flags = CLK_GET_RATE_NOCACHE,
-       };
-       int ret;
-
-       init.name = kasprintf(GFP_KERNEL, "%s-clk",
-                             acpi_dev_name(int3472->adev));
-       if (!init.name)
-               return -ENOMEM;
-
-       int3472->clock.frequency = skl_int3472_get_clk_frequency(int3472);
-
-       int3472->clock.clk_hw.init = &init;
-       int3472->clock.clk = clk_register(&int3472->adev->dev,
-                                         &int3472->clock.clk_hw);
-       if (IS_ERR(int3472->clock.clk)) {
-               ret = PTR_ERR(int3472->clock.clk);
-               goto out_free_init_name;
-       }
-
-       int3472->clock.cl = clkdev_create(int3472->clock.clk, NULL,
-                                         int3472->sensor_name);
-       if (!int3472->clock.cl) {
-               ret = -ENOMEM;
-               goto err_unregister_clk;
-       }
-
-       kfree(init.name);
-       return 0;
-
-err_unregister_clk:
-       clk_unregister(int3472->clock.clk);
-out_free_init_name:
-       kfree(init.name);
-
-       return ret;
-}
-
-void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472)
-{
-       clkdev_drop(int3472->clock.cl);
-       clk_unregister(int3472->clock.clk);
-}
-
-int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
-                                  struct acpi_resource_gpio *agpio)
-{
-       const struct int3472_sensor_config *sensor_config;
-       char *path = agpio->resource_source.string_ptr;
-       struct regulator_consumer_supply supply_map;
-       struct regulator_init_data init_data = { };
-       struct regulator_config cfg = { };
-       int ret;
-
-       sensor_config = int3472->sensor_config;
-       if (IS_ERR(sensor_config)) {
-               dev_err(int3472->dev, "No sensor module config\n");
-               return PTR_ERR(sensor_config);
-       }
-
-       if (!sensor_config->supply_map.supply) {
-               dev_err(int3472->dev, "No supply name defined\n");
-               return -ENODEV;
-       }
-
-       init_data.constraints.valid_ops_mask = REGULATOR_CHANGE_STATUS;
-       init_data.num_consumer_supplies = 1;
-       supply_map = sensor_config->supply_map;
-       supply_map.dev_name = int3472->sensor_name;
-       init_data.consumer_supplies = &supply_map;
-
-       snprintf(int3472->regulator.regulator_name,
-                sizeof(int3472->regulator.regulator_name), "%s-regulator",
-                acpi_dev_name(int3472->adev));
-       snprintf(int3472->regulator.supply_name,
-                GPIO_REGULATOR_SUPPLY_NAME_LENGTH, "supply-0");
-
-       int3472->regulator.rdesc = INT3472_REGULATOR(
-                                               int3472->regulator.regulator_name,
-                                               int3472->regulator.supply_name,
-                                               &int3472_gpio_regulator_ops);
-
-       int3472->regulator.gpio = acpi_get_and_request_gpiod(path, agpio->pin_table[0],
-                                                            "int3472,regulator");
-       if (IS_ERR(int3472->regulator.gpio)) {
-               dev_err(int3472->dev, "Failed to get regulator GPIO line\n");
-               return PTR_ERR(int3472->regulator.gpio);
-       }
-
-       cfg.dev = &int3472->adev->dev;
-       cfg.init_data = &init_data;
-       cfg.ena_gpiod = int3472->regulator.gpio;
-
-       int3472->regulator.rdev = regulator_register(&int3472->regulator.rdesc,
-                                                    &cfg);
-       if (IS_ERR(int3472->regulator.rdev)) {
-               ret = PTR_ERR(int3472->regulator.rdev);
-               goto err_free_gpio;
-       }
-
-       return 0;
-
-err_free_gpio:
-       gpiod_put(int3472->regulator.gpio);
-
-       return ret;
-}
-
-void skl_int3472_unregister_regulator(struct int3472_discrete_device *int3472)
-{
-       regulator_unregister(int3472->regulator.rdev);
-       gpiod_put(int3472->regulator.gpio);
-}
diff --git a/drivers/platform/x86/intel/int3472/intel_skl_int3472_common.c b/drivers/platform/x86/intel/int3472/intel_skl_int3472_common.c
deleted file mode 100644 (file)
index 497e74f..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Author: Dan Scally <djrscally@gmail.com> */
-
-#include <linux/acpi.h>
-#include <linux/i2c.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-#include "intel_skl_int3472_common.h"
-
-union acpi_object *skl_int3472_get_acpi_buffer(struct acpi_device *adev, char *id)
-{
-       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-       acpi_handle handle = adev->handle;
-       union acpi_object *obj;
-       acpi_status status;
-
-       status = acpi_evaluate_object(handle, id, NULL, &buffer);
-       if (ACPI_FAILURE(status))
-               return ERR_PTR(-ENODEV);
-
-       obj = buffer.pointer;
-       if (!obj)
-               return ERR_PTR(-ENODEV);
-
-       if (obj->type != ACPI_TYPE_BUFFER) {
-               acpi_handle_err(handle, "%s object is not an ACPI buffer\n", id);
-               kfree(obj);
-               return ERR_PTR(-EINVAL);
-       }
-
-       return obj;
-}
-
-int skl_int3472_fill_cldb(struct acpi_device *adev, struct int3472_cldb *cldb)
-{
-       union acpi_object *obj;
-       int ret;
-
-       obj = skl_int3472_get_acpi_buffer(adev, "CLDB");
-       if (IS_ERR(obj))
-               return PTR_ERR(obj);
-
-       if (obj->buffer.length > sizeof(*cldb)) {
-               acpi_handle_err(adev->handle, "The CLDB buffer is too large\n");
-               ret = -EINVAL;
-               goto out_free_obj;
-       }
-
-       memcpy(cldb, obj->buffer.pointer, obj->buffer.length);
-       ret = 0;
-
-out_free_obj:
-       kfree(obj);
-       return ret;
-}
-
-static const struct acpi_device_id int3472_device_id[] = {
-       { "INT3472", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(acpi, int3472_device_id);
-
-static struct platform_driver int3472_discrete = {
-       .driver = {
-               .name = "int3472-discrete",
-               .acpi_match_table = int3472_device_id,
-       },
-       .probe = skl_int3472_discrete_probe,
-       .remove = skl_int3472_discrete_remove,
-};
-
-static struct i2c_driver int3472_tps68470 = {
-       .driver = {
-               .name = "int3472-tps68470",
-               .acpi_match_table = int3472_device_id,
-       },
-       .probe_new = skl_int3472_tps68470_probe,
-};
-
-static int skl_int3472_init(void)
-{
-       int ret;
-
-       ret = platform_driver_register(&int3472_discrete);
-       if (ret)
-               return ret;
-
-       ret = i2c_register_driver(THIS_MODULE, &int3472_tps68470);
-       if (ret)
-               platform_driver_unregister(&int3472_discrete);
-
-       return ret;
-}
-module_init(skl_int3472_init);
-
-static void skl_int3472_exit(void)
-{
-       platform_driver_unregister(&int3472_discrete);
-       i2c_del_driver(&int3472_tps68470);
-}
-module_exit(skl_int3472_exit);
-
-MODULE_DESCRIPTION("Intel SkyLake INT3472 ACPI Device Driver");
-MODULE_AUTHOR("Daniel Scally <djrscally@gmail.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/intel/int3472/intel_skl_int3472_common.h b/drivers/platform/x86/intel/int3472/intel_skl_int3472_common.h
deleted file mode 100644 (file)
index 714fde7..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* Author: Dan Scally <djrscally@gmail.com> */
-
-#ifndef _INTEL_SKL_INT3472_H
-#define _INTEL_SKL_INT3472_H
-
-#include <linux/clk-provider.h>
-#include <linux/gpio/machine.h>
-#include <linux/regulator/driver.h>
-#include <linux/regulator/machine.h>
-#include <linux/types.h>
-
-/* FIXME drop this once the I2C_DEV_NAME_FORMAT macro has been added to include/linux/i2c.h */
-#ifndef I2C_DEV_NAME_FORMAT
-#define I2C_DEV_NAME_FORMAT                                    "i2c-%s"
-#endif
-
-/* PMIC GPIO Types */
-#define INT3472_GPIO_TYPE_RESET                                        0x00
-#define INT3472_GPIO_TYPE_POWERDOWN                            0x01
-#define INT3472_GPIO_TYPE_POWER_ENABLE                         0x0b
-#define INT3472_GPIO_TYPE_CLK_ENABLE                           0x0c
-#define INT3472_GPIO_TYPE_PRIVACY_LED                          0x0d
-
-#define INT3472_PDEV_MAX_NAME_LEN                              23
-#define INT3472_MAX_SENSOR_GPIOS                               3
-
-#define GPIO_REGULATOR_NAME_LENGTH                             21
-#define GPIO_REGULATOR_SUPPLY_NAME_LENGTH                      9
-
-#define CIO2_SENSOR_SSDB_MCLKSPEED_OFFSET                      86
-
-#define INT3472_REGULATOR(_name, _supply, _ops)                        \
-       (const struct regulator_desc) {                         \
-               .name = _name,                                  \
-               .supply_name = _supply,                         \
-               .type = REGULATOR_VOLTAGE,                      \
-               .ops = _ops,                                    \
-               .owner = THIS_MODULE,                           \
-       }
-
-#define to_int3472_clk(hw)                                     \
-       container_of(hw, struct int3472_gpio_clock, clk_hw)
-
-#define to_int3472_device(clk)                                 \
-       container_of(clk, struct int3472_discrete_device, clock)
-
-struct acpi_device;
-struct i2c_client;
-struct platform_device;
-
-struct int3472_cldb {
-       u8 version;
-       /*
-        * control logic type
-        * 0: UNKNOWN
-        * 1: DISCRETE(CRD-D)
-        * 2: PMIC TPS68470
-        * 3: PMIC uP6641
-        */
-       u8 control_logic_type;
-       u8 control_logic_id;
-       u8 sensor_card_sku;
-       u8 reserved[28];
-};
-
-struct int3472_gpio_function_remap {
-       const char *documented;
-       const char *actual;
-};
-
-struct int3472_sensor_config {
-       const char *sensor_module_name;
-       struct regulator_consumer_supply supply_map;
-       const struct int3472_gpio_function_remap *function_maps;
-};
-
-struct int3472_discrete_device {
-       struct acpi_device *adev;
-       struct device *dev;
-       struct acpi_device *sensor;
-       const char *sensor_name;
-
-       const struct int3472_sensor_config *sensor_config;
-
-       struct int3472_gpio_regulator {
-               char regulator_name[GPIO_REGULATOR_NAME_LENGTH];
-               char supply_name[GPIO_REGULATOR_SUPPLY_NAME_LENGTH];
-               struct gpio_desc *gpio;
-               struct regulator_dev *rdev;
-               struct regulator_desc rdesc;
-       } regulator;
-
-       struct int3472_gpio_clock {
-               struct clk *clk;
-               struct clk_hw clk_hw;
-               struct clk_lookup *cl;
-               struct gpio_desc *ena_gpio;
-               struct gpio_desc *led_gpio;
-               u32 frequency;
-       } clock;
-
-       unsigned int ngpios; /* how many GPIOs have we seen */
-       unsigned int n_sensor_gpios; /* how many have we mapped to sensor */
-       struct gpiod_lookup_table gpios;
-};
-
-int skl_int3472_discrete_probe(struct platform_device *pdev);
-int skl_int3472_discrete_remove(struct platform_device *pdev);
-int skl_int3472_tps68470_probe(struct i2c_client *client);
-union acpi_object *skl_int3472_get_acpi_buffer(struct acpi_device *adev,
-                                              char *id);
-int skl_int3472_fill_cldb(struct acpi_device *adev, struct int3472_cldb *cldb);
-
-int skl_int3472_register_clock(struct int3472_discrete_device *int3472);
-void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472);
-
-int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
-                                  struct acpi_resource_gpio *agpio);
-void skl_int3472_unregister_regulator(struct int3472_discrete_device *int3472);
-
-#endif
diff --git a/drivers/platform/x86/intel/int3472/intel_skl_int3472_discrete.c b/drivers/platform/x86/intel/int3472/intel_skl_int3472_discrete.c
deleted file mode 100644 (file)
index e59d79c..0000000
+++ /dev/null
@@ -1,413 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Author: Dan Scally <djrscally@gmail.com> */
-
-#include <linux/acpi.h>
-#include <linux/clkdev.h>
-#include <linux/clk-provider.h>
-#include <linux/device.h>
-#include <linux/gpio/consumer.h>
-#include <linux/gpio/machine.h>
-#include <linux/i2c.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/overflow.h>
-#include <linux/platform_device.h>
-#include <linux/uuid.h>
-
-#include "intel_skl_int3472_common.h"
-
-/*
- * 79234640-9e10-4fea-a5c1-b5aa8b19756f
- * This _DSM GUID returns information about the GPIO lines mapped to a
- * discrete INT3472 device. Function number 1 returns a count of the GPIO
- * lines that are mapped. Subsequent functions return 32 bit ints encoding
- * information about the GPIO line, including its purpose.
- */
-static const guid_t int3472_gpio_guid =
-       GUID_INIT(0x79234640, 0x9e10, 0x4fea,
-                 0xa5, 0xc1, 0xb5, 0xaa, 0x8b, 0x19, 0x75, 0x6f);
-
-/*
- * 822ace8f-2814-4174-a56b-5f029fe079ee
- * This _DSM GUID returns a string from the sensor device, which acts as a
- * module identifier.
- */
-static const guid_t cio2_sensor_module_guid =
-       GUID_INIT(0x822ace8f, 0x2814, 0x4174,
-                 0xa5, 0x6b, 0x5f, 0x02, 0x9f, 0xe0, 0x79, 0xee);
-
-/*
- * Here follows platform specific mapping information that we can pass to
- * the functions mapping resources to the sensors. Where the sensors have
- * a power enable pin defined in DSDT we need to provide a supply name so
- * the sensor drivers can find the regulator. The device name will be derived
- * from the sensor's ACPI device within the code. Optionally, we can provide a
- * NULL terminated array of function name mappings to deal with any platform
- * specific deviations from the documented behaviour of GPIOs.
- *
- * Map a GPIO function name to NULL to prevent the driver from mapping that
- * GPIO at all.
- */
-
-static const struct int3472_gpio_function_remap ov2680_gpio_function_remaps[] = {
-       { "reset", NULL },
-       { "powerdown", "reset" },
-       { }
-};
-
-static const struct int3472_sensor_config int3472_sensor_configs[] = {
-       /* Lenovo Miix 510-12ISK - OV2680, Front */
-       { "GNDF140809R", { 0 }, ov2680_gpio_function_remaps },
-       /* Lenovo Miix 510-12ISK - OV5648, Rear */
-       { "GEFF150023R", REGULATOR_SUPPLY("avdd", NULL), NULL },
-       /* Surface Go 1&2 - OV5693, Front */
-       { "YHCU", REGULATOR_SUPPLY("avdd", NULL), NULL },
-};
-
-static const struct int3472_sensor_config *
-skl_int3472_get_sensor_module_config(struct int3472_discrete_device *int3472)
-{
-       union acpi_object *obj;
-       unsigned int i;
-
-       obj = acpi_evaluate_dsm_typed(int3472->sensor->handle,
-                                     &cio2_sensor_module_guid, 0x00,
-                                     0x01, NULL, ACPI_TYPE_STRING);
-
-       if (!obj) {
-               dev_err(int3472->dev,
-                       "Failed to get sensor module string from _DSM\n");
-               return ERR_PTR(-ENODEV);
-       }
-
-       if (obj->string.type != ACPI_TYPE_STRING) {
-               dev_err(int3472->dev,
-                       "Sensor _DSM returned a non-string value\n");
-
-               ACPI_FREE(obj);
-               return ERR_PTR(-EINVAL);
-       }
-
-       for (i = 0; i < ARRAY_SIZE(int3472_sensor_configs); i++) {
-               if (!strcmp(int3472_sensor_configs[i].sensor_module_name,
-                           obj->string.pointer))
-                       break;
-       }
-
-       ACPI_FREE(obj);
-
-       if (i >= ARRAY_SIZE(int3472_sensor_configs))
-               return ERR_PTR(-EINVAL);
-
-       return &int3472_sensor_configs[i];
-}
-
-static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int3472,
-                                         struct acpi_resource_gpio *agpio,
-                                         const char *func, u32 polarity)
-{
-       const struct int3472_sensor_config *sensor_config;
-       char *path = agpio->resource_source.string_ptr;
-       struct gpiod_lookup *table_entry;
-       struct acpi_device *adev;
-       acpi_handle handle;
-       acpi_status status;
-       int ret;
-
-       if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) {
-               dev_warn(int3472->dev, "Too many GPIOs mapped\n");
-               return -EINVAL;
-       }
-
-       sensor_config = int3472->sensor_config;
-       if (!IS_ERR(sensor_config) && sensor_config->function_maps) {
-               const struct int3472_gpio_function_remap *remap;
-
-               for (remap = sensor_config->function_maps; remap->documented; remap++) {
-                       if (!strcmp(func, remap->documented)) {
-                               func = remap->actual;
-                               break;
-                       }
-               }
-       }
-
-       /* Functions mapped to NULL should not be mapped to the sensor */
-       if (!func)
-               return 0;
-
-       status = acpi_get_handle(NULL, path, &handle);
-       if (ACPI_FAILURE(status))
-               return -EINVAL;
-
-       ret = acpi_bus_get_device(handle, &adev);
-       if (ret)
-               return -ENODEV;
-
-       table_entry = &int3472->gpios.table[int3472->n_sensor_gpios];
-       table_entry->key = acpi_dev_name(adev);
-       table_entry->chip_hwnum = agpio->pin_table[0];
-       table_entry->con_id = func;
-       table_entry->idx = 0;
-       table_entry->flags = polarity;
-
-       int3472->n_sensor_gpios++;
-
-       return 0;
-}
-
-static int skl_int3472_map_gpio_to_clk(struct int3472_discrete_device *int3472,
-                                      struct acpi_resource_gpio *agpio, u8 type)
-{
-       char *path = agpio->resource_source.string_ptr;
-       u16 pin = agpio->pin_table[0];
-       struct gpio_desc *gpio;
-
-       switch (type) {
-       case INT3472_GPIO_TYPE_CLK_ENABLE:
-               gpio = acpi_get_and_request_gpiod(path, pin, "int3472,clk-enable");
-               if (IS_ERR(gpio))
-                       return (PTR_ERR(gpio));
-
-               int3472->clock.ena_gpio = gpio;
-               break;
-       case INT3472_GPIO_TYPE_PRIVACY_LED:
-               gpio = acpi_get_and_request_gpiod(path, pin, "int3472,privacy-led");
-               if (IS_ERR(gpio))
-                       return (PTR_ERR(gpio));
-
-               int3472->clock.led_gpio = gpio;
-               break;
-       default:
-               dev_err(int3472->dev, "Invalid GPIO type 0x%02x for clock\n", type);
-               break;
-       }
-
-       return 0;
-}
-
-/**
- * skl_int3472_handle_gpio_resources: Map PMIC resources to consuming sensor
- * @ares: A pointer to a &struct acpi_resource
- * @data: A pointer to a &struct int3472_discrete_device
- *
- * This function handles GPIO resources that are against an INT3472
- * ACPI device, by checking the value of the corresponding _DSM entry.
- * This will return a 32bit int, where the lowest byte represents the
- * function of the GPIO pin:
- *
- * 0x00 Reset
- * 0x01 Power down
- * 0x0b Power enable
- * 0x0c Clock enable
- * 0x0d Privacy LED
- *
- * There are some known platform specific quirks where that does not quite
- * hold up; for example where a pin with type 0x01 (Power down) is mapped to
- * a sensor pin that performs a reset function or entries in _CRS and _DSM that
- * do not actually correspond to a physical connection. These will be handled
- * by the mapping sub-functions.
- *
- * GPIOs will either be mapped directly to the sensor device or else used
- * to create clocks and regulators via the usual frameworks.
- *
- * Return:
- * * 1         - To continue the loop
- * * 0         - When all resources found are handled properly.
- * * -EINVAL   - If the resource is not a GPIO IO resource
- * * -ENODEV   - If the resource has no corresponding _DSM entry
- * * -Other    - Errors propagated from one of the sub-functions.
- */
-static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
-                                            void *data)
-{
-       struct int3472_discrete_device *int3472 = data;
-       struct acpi_resource_gpio *agpio;
-       union acpi_object *obj;
-       const char *err_msg;
-       int ret;
-       u8 type;
-
-       if (!acpi_gpio_get_io_resource(ares, &agpio))
-               return 1;
-
-       /*
-        * ngpios + 2 because the index of this _DSM function is 1-based and
-        * the first function is just a count.
-        */
-       obj = acpi_evaluate_dsm_typed(int3472->adev->handle,
-                                     &int3472_gpio_guid, 0x00,
-                                     int3472->ngpios + 2,
-                                     NULL, ACPI_TYPE_INTEGER);
-
-       if (!obj) {
-               dev_warn(int3472->dev, "No _DSM entry for GPIO pin %u\n",
-                        agpio->pin_table[0]);
-               return 1;
-       }
-
-       type = obj->integer.value & 0xff;
-
-       switch (type) {
-       case INT3472_GPIO_TYPE_RESET:
-               ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, "reset",
-                                                    GPIO_ACTIVE_LOW);
-               if (ret)
-                       err_msg = "Failed to map reset pin to sensor\n";
-
-               break;
-       case INT3472_GPIO_TYPE_POWERDOWN:
-               ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, "powerdown",
-                                                    GPIO_ACTIVE_LOW);
-               if (ret)
-                       err_msg = "Failed to map powerdown pin to sensor\n";
-
-               break;
-       case INT3472_GPIO_TYPE_CLK_ENABLE:
-       case INT3472_GPIO_TYPE_PRIVACY_LED:
-               ret = skl_int3472_map_gpio_to_clk(int3472, agpio, type);
-               if (ret)
-                       err_msg = "Failed to map GPIO to clock\n";
-
-               break;
-       case INT3472_GPIO_TYPE_POWER_ENABLE:
-               ret = skl_int3472_register_regulator(int3472, agpio);
-               if (ret)
-                       err_msg = "Failed to map regulator to sensor\n";
-
-               break;
-       default:
-               dev_warn(int3472->dev,
-                        "GPIO type 0x%02x unknown; the sensor may not work\n",
-                        type);
-               ret = 1;
-               break;
-       }
-
-       int3472->ngpios++;
-       ACPI_FREE(obj);
-
-       if (ret < 0)
-               return dev_err_probe(int3472->dev, ret, err_msg);
-
-       return ret;
-}
-
-static int skl_int3472_parse_crs(struct int3472_discrete_device *int3472)
-{
-       LIST_HEAD(resource_list);
-       int ret;
-
-       /*
-        * No error check, because not having a sensor config is not necessarily
-        * a failure mode.
-        */
-       int3472->sensor_config = skl_int3472_get_sensor_module_config(int3472);
-
-       ret = acpi_dev_get_resources(int3472->adev, &resource_list,
-                                    skl_int3472_handle_gpio_resources,
-                                    int3472);
-       if (ret < 0)
-               return ret;
-
-       acpi_dev_free_resource_list(&resource_list);
-
-       /*
-        * If we find no clock enable GPIO pin then the privacy LED won't work.
-        * We've never seen that situation, but it's possible. Warn the user so
-        * it's clear what's happened.
-        */
-       if (int3472->clock.ena_gpio) {
-               ret = skl_int3472_register_clock(int3472);
-               if (ret)
-                       return ret;
-       } else {
-               if (int3472->clock.led_gpio)
-                       dev_warn(int3472->dev,
-                                "No clk GPIO. The privacy LED won't work\n");
-       }
-
-       int3472->gpios.dev_id = int3472->sensor_name;
-       gpiod_add_lookup_table(&int3472->gpios);
-
-       return 0;
-}
-
-int skl_int3472_discrete_probe(struct platform_device *pdev)
-{
-       struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
-       struct int3472_discrete_device *int3472;
-       struct int3472_cldb cldb;
-       int ret;
-
-       ret = skl_int3472_fill_cldb(adev, &cldb);
-       if (ret) {
-               dev_err(&pdev->dev, "Couldn't fill CLDB structure\n");
-               return ret;
-       }
-
-       if (cldb.control_logic_type != 1) {
-               dev_err(&pdev->dev, "Unsupported control logic type %u\n",
-                       cldb.control_logic_type);
-               return -EINVAL;
-       }
-
-       /* Max num GPIOs we've seen plus a terminator */
-       int3472 = devm_kzalloc(&pdev->dev, struct_size(int3472, gpios.table,
-                              INT3472_MAX_SENSOR_GPIOS + 1), GFP_KERNEL);
-       if (!int3472)
-               return -ENOMEM;
-
-       int3472->adev = adev;
-       int3472->dev = &pdev->dev;
-       platform_set_drvdata(pdev, int3472);
-
-       int3472->sensor = acpi_dev_get_first_consumer_dev(adev);
-       if (!int3472->sensor) {
-               dev_err(&pdev->dev, "INT3472 seems to have no dependents.\n");
-               return -ENODEV;
-       }
-
-       int3472->sensor_name = devm_kasprintf(int3472->dev, GFP_KERNEL,
-                                             I2C_DEV_NAME_FORMAT,
-                                             acpi_dev_name(int3472->sensor));
-       if (!int3472->sensor_name) {
-               ret = -ENOMEM;
-               goto err_put_sensor;
-       }
-
-       /*
-        * Initialising this list means we can call gpiod_remove_lookup_table()
-        * in failure paths without issue.
-        */
-       INIT_LIST_HEAD(&int3472->gpios.list);
-
-       ret = skl_int3472_parse_crs(int3472);
-       if (ret) {
-               skl_int3472_discrete_remove(pdev);
-               return ret;
-       }
-
-       return 0;
-
-err_put_sensor:
-       acpi_dev_put(int3472->sensor);
-
-       return ret;
-}
-
-int skl_int3472_discrete_remove(struct platform_device *pdev)
-{
-       struct int3472_discrete_device *int3472 = platform_get_drvdata(pdev);
-
-       gpiod_remove_lookup_table(&int3472->gpios);
-
-       if (int3472->clock.cl)
-               skl_int3472_unregister_clock(int3472);
-
-       gpiod_put(int3472->clock.ena_gpio);
-       gpiod_put(int3472->clock.led_gpio);
-
-       skl_int3472_unregister_regulator(int3472);
-
-       return 0;
-}
diff --git a/drivers/platform/x86/intel/int3472/intel_skl_int3472_tps68470.c b/drivers/platform/x86/intel/int3472/intel_skl_int3472_tps68470.c
deleted file mode 100644 (file)
index c05b4cf..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Author: Dan Scally <djrscally@gmail.com> */
-
-#include <linux/i2c.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/tps68470.h>
-#include <linux/platform_device.h>
-#include <linux/regmap.h>
-
-#include "intel_skl_int3472_common.h"
-
-#define DESIGNED_FOR_CHROMEOS          1
-#define DESIGNED_FOR_WINDOWS           2
-
-static const struct mfd_cell tps68470_cros[] = {
-       { .name = "tps68470-gpio" },
-       { .name = "tps68470_pmic_opregion" },
-};
-
-static const struct mfd_cell tps68470_win[] = {
-       { .name = "tps68470-gpio" },
-       { .name = "tps68470-clk" },
-       { .name = "tps68470-regulator" },
-};
-
-static const struct regmap_config tps68470_regmap_config = {
-       .reg_bits = 8,
-       .val_bits = 8,
-       .max_register = TPS68470_REG_MAX,
-};
-
-static int tps68470_chip_init(struct device *dev, struct regmap *regmap)
-{
-       unsigned int version;
-       int ret;
-
-       /* Force software reset */
-       ret = regmap_write(regmap, TPS68470_REG_RESET, TPS68470_REG_RESET_MASK);
-       if (ret)
-               return ret;
-
-       ret = regmap_read(regmap, TPS68470_REG_REVID, &version);
-       if (ret) {
-               dev_err(dev, "Failed to read revision register: %d\n", ret);
-               return ret;
-       }
-
-       dev_info(dev, "TPS68470 REVID: 0x%02x\n", version);
-
-       return 0;
-}
-
-/** skl_int3472_tps68470_calc_type: Check what platform a device is designed for
- * @adev: A pointer to a &struct acpi_device
- *
- * Check CLDB buffer against the PMIC's adev. If present, then we check
- * the value of control_logic_type field and follow one of the
- * following scenarios:
- *
- *     1. No CLDB - likely ACPI tables designed for ChromeOS. We
- *     create platform devices for the GPIOs and OpRegion drivers.
- *
- *     2. CLDB, with control_logic_type = 2 - probably ACPI tables
- *     made for Windows 2-in-1 platforms. Register pdevs for GPIO,
- *     Clock and Regulator drivers to bind to.
- *
- *     3. Any other value in control_logic_type, we should never have
- *     gotten to this point; fail probe and return.
- *
- * Return:
- * * 1         Device intended for ChromeOS
- * * 2         Device intended for Windows
- * * -EINVAL   Where @adev has an object named CLDB but it does not conform to
- *             our expectations
- */
-static int skl_int3472_tps68470_calc_type(struct acpi_device *adev)
-{
-       struct int3472_cldb cldb = { 0 };
-       int ret;
-
-       /*
-        * A CLDB buffer that exists, but which does not match our expectations
-        * should trigger an error so we don't blindly continue.
-        */
-       ret = skl_int3472_fill_cldb(adev, &cldb);
-       if (ret && ret != -ENODEV)
-               return ret;
-
-       if (ret)
-               return DESIGNED_FOR_CHROMEOS;
-
-       if (cldb.control_logic_type != 2)
-               return -EINVAL;
-
-       return DESIGNED_FOR_WINDOWS;
-}
-
-int skl_int3472_tps68470_probe(struct i2c_client *client)
-{
-       struct acpi_device *adev = ACPI_COMPANION(&client->dev);
-       struct regmap *regmap;
-       int device_type;
-       int ret;
-
-       regmap = devm_regmap_init_i2c(client, &tps68470_regmap_config);
-       if (IS_ERR(regmap)) {
-               dev_err(&client->dev, "Failed to create regmap: %ld\n", PTR_ERR(regmap));
-               return PTR_ERR(regmap);
-       }
-
-       i2c_set_clientdata(client, regmap);
-
-       ret = tps68470_chip_init(&client->dev, regmap);
-       if (ret < 0) {
-               dev_err(&client->dev, "TPS68470 init error %d\n", ret);
-               return ret;
-       }
-
-       device_type = skl_int3472_tps68470_calc_type(adev);
-       switch (device_type) {
-       case DESIGNED_FOR_WINDOWS:
-               ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
-                                          tps68470_win, ARRAY_SIZE(tps68470_win),
-                                          NULL, 0, NULL);
-               break;
-       case DESIGNED_FOR_CHROMEOS:
-               ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
-                                          tps68470_cros, ARRAY_SIZE(tps68470_cros),
-                                          NULL, 0, NULL);
-               break;
-       default:
-               dev_err(&client->dev, "Failed to add MFD devices\n");
-               return device_type;
-       }
-
-       return ret;
-}
diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c
new file mode 100644 (file)
index 0000000..22f61b4
--- /dev/null
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Dan Scally <djrscally@gmail.com> */
+
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps68470.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/tps68470.h>
+#include <linux/regmap.h>
+#include <linux/string.h>
+
+#include "common.h"
+#include "tps68470.h"
+
+#define DESIGNED_FOR_CHROMEOS          1
+#define DESIGNED_FOR_WINDOWS           2
+
+#define TPS68470_WIN_MFD_CELL_COUNT    3
+
+static const struct mfd_cell tps68470_cros[] = {
+       { .name = "tps68470-gpio" },
+       { .name = "tps68470_pmic_opregion" },
+};
+
+static const struct regmap_config tps68470_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = TPS68470_REG_MAX,
+};
+
+static int tps68470_chip_init(struct device *dev, struct regmap *regmap)
+{
+       unsigned int version;
+       int ret;
+
+       /* Force software reset */
+       ret = regmap_write(regmap, TPS68470_REG_RESET, TPS68470_REG_RESET_MASK);
+       if (ret)
+               return ret;
+
+       ret = regmap_read(regmap, TPS68470_REG_REVID, &version);
+       if (ret) {
+               dev_err(dev, "Failed to read revision register: %d\n", ret);
+               return ret;
+       }
+
+       dev_info(dev, "TPS68470 REVID: 0x%02x\n", version);
+
+       return 0;
+}
+
+/** skl_int3472_tps68470_calc_type: Check what platform a device is designed for
+ * @adev: A pointer to a &struct acpi_device
+ *
+ * Check CLDB buffer against the PMIC's adev. If present, then we check
+ * the value of control_logic_type field and follow one of the
+ * following scenarios:
+ *
+ *     1. No CLDB - likely ACPI tables designed for ChromeOS. We
+ *     create platform devices for the GPIOs and OpRegion drivers.
+ *
+ *     2. CLDB, with control_logic_type = 2 - probably ACPI tables
+ *     made for Windows 2-in-1 platforms. Register pdevs for GPIO,
+ *     Clock and Regulator drivers to bind to.
+ *
+ *     3. Any other value in control_logic_type, we should never have
+ *     gotten to this point; fail probe and return.
+ *
+ * Return:
+ * * 1         Device intended for ChromeOS
+ * * 2         Device intended for Windows
+ * * -EINVAL   Where @adev has an object named CLDB but it does not conform to
+ *             our expectations
+ */
+static int skl_int3472_tps68470_calc_type(struct acpi_device *adev)
+{
+       struct int3472_cldb cldb = { 0 };
+       int ret;
+
+       /*
+        * A CLDB buffer that exists, but which does not match our expectations
+        * should trigger an error so we don't blindly continue.
+        */
+       ret = skl_int3472_fill_cldb(adev, &cldb);
+       if (ret && ret != -ENODEV)
+               return ret;
+
+       if (ret)
+               return DESIGNED_FOR_CHROMEOS;
+
+       if (cldb.control_logic_type != 2)
+               return -EINVAL;
+
+       return DESIGNED_FOR_WINDOWS;
+}
+
+static int skl_int3472_tps68470_probe(struct i2c_client *client)
+{
+       struct acpi_device *adev = ACPI_COMPANION(&client->dev);
+       const struct int3472_tps68470_board_data *board_data;
+       struct tps68470_clk_platform_data clk_pdata = {};
+       struct mfd_cell *cells;
+       struct regmap *regmap;
+       int device_type;
+       int ret;
+
+       ret = skl_int3472_get_sensor_adev_and_name(&client->dev, NULL,
+                                                  &clk_pdata.consumer_dev_name);
+       if (ret)
+               return ret;
+
+       regmap = devm_regmap_init_i2c(client, &tps68470_regmap_config);
+       if (IS_ERR(regmap)) {
+               dev_err(&client->dev, "Failed to create regmap: %ld\n", PTR_ERR(regmap));
+               return PTR_ERR(regmap);
+       }
+
+       i2c_set_clientdata(client, regmap);
+
+       ret = tps68470_chip_init(&client->dev, regmap);
+       if (ret < 0) {
+               dev_err(&client->dev, "TPS68470 init error %d\n", ret);
+               return ret;
+       }
+
+       device_type = skl_int3472_tps68470_calc_type(adev);
+       switch (device_type) {
+       case DESIGNED_FOR_WINDOWS:
+               board_data = int3472_tps68470_get_board_data(dev_name(&client->dev));
+               if (!board_data)
+                       return dev_err_probe(&client->dev, -ENODEV, "No board-data found for this model\n");
+
+               cells = kcalloc(TPS68470_WIN_MFD_CELL_COUNT, sizeof(*cells), GFP_KERNEL);
+               if (!cells)
+                       return -ENOMEM;
+
+               /*
+                * The order of the cells matters here! The clk must be first
+                * because the regulator depends on it. The gpios must be last,
+                * acpi_gpiochip_add() calls acpi_dev_clear_dependencies() and
+                * the clk + regulators must be ready when this happens.
+                */
+               cells[0].name = "tps68470-clk";
+               cells[0].platform_data = &clk_pdata;
+               cells[0].pdata_size = sizeof(clk_pdata);
+               cells[1].name = "tps68470-regulator";
+               cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata;
+               cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data);
+               cells[2].name = "tps68470-gpio";
+
+               gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_table);
+
+               ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
+                                          cells, TPS68470_WIN_MFD_CELL_COUNT,
+                                          NULL, 0, NULL);
+               kfree(cells);
+
+               if (ret)
+                       gpiod_remove_lookup_table(board_data->tps68470_gpio_lookup_table);
+
+               break;
+       case DESIGNED_FOR_CHROMEOS:
+               ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
+                                          tps68470_cros, ARRAY_SIZE(tps68470_cros),
+                                          NULL, 0, NULL);
+               break;
+       default:
+               dev_err(&client->dev, "Failed to add MFD devices\n");
+               return device_type;
+       }
+
+       /*
+        * No acpi_dev_clear_dependencies() here, since the acpi_gpiochip_add()
+        * for the GPIO cell already does this.
+        */
+
+       return ret;
+}
+
+static int skl_int3472_tps68470_remove(struct i2c_client *client)
+{
+       const struct int3472_tps68470_board_data *board_data;
+
+       board_data = int3472_tps68470_get_board_data(dev_name(&client->dev));
+       if (board_data)
+               gpiod_remove_lookup_table(board_data->tps68470_gpio_lookup_table);
+
+       return 0;
+}
+
+static const struct acpi_device_id int3472_device_id[] = {
+       { "INT3472", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, int3472_device_id);
+
+static struct i2c_driver int3472_tps68470 = {
+       .driver = {
+               .name = "int3472-tps68470",
+               .acpi_match_table = int3472_device_id,
+       },
+       .probe_new = skl_int3472_tps68470_probe,
+       .remove = skl_int3472_tps68470_remove,
+};
+module_i2c_driver(int3472_tps68470);
+
+MODULE_DESCRIPTION("Intel SkyLake INT3472 ACPI TPS68470 Device Driver");
+MODULE_AUTHOR("Daniel Scally <djrscally@gmail.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_SOFTDEP("pre: clk-tps68470 tps68470-regulator");
diff --git a/drivers/platform/x86/intel/int3472/tps68470.h b/drivers/platform/x86/intel/int3472/tps68470.h
new file mode 100644 (file)
index 0000000..cfd33eb
--- /dev/null
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * TI TPS68470 PMIC platform data definition.
+ *
+ * Copyright (c) 2021 Red Hat Inc.
+ *
+ * Red Hat authors:
+ * Hans de Goede <hdegoede@redhat.com>
+ */
+
+#ifndef _INTEL_SKL_INT3472_TPS68470_H
+#define _INTEL_SKL_INT3472_TPS68470_H
+
+struct gpiod_lookup_table;
+struct tps68470_regulator_platform_data;
+
+struct int3472_tps68470_board_data {
+       const char *dev_name;
+       struct gpiod_lookup_table *tps68470_gpio_lookup_table;
+       const struct tps68470_regulator_platform_data *tps68470_regulator_pdata;
+};
+
+const struct int3472_tps68470_board_data *int3472_tps68470_get_board_data(const char *dev_name);
+
+#endif
diff --git a/drivers/platform/x86/intel/int3472/tps68470_board_data.c b/drivers/platform/x86/intel/int3472/tps68470_board_data.c
new file mode 100644 (file)
index 0000000..faa5570
--- /dev/null
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * TI TPS68470 PMIC platform data definition.
+ *
+ * Copyright (c) 2021 Dan Scally <djrscally@gmail.com>
+ * Copyright (c) 2021 Red Hat Inc.
+ *
+ * Red Hat authors:
+ * Hans de Goede <hdegoede@redhat.com>
+ */
+
+#include <linux/dmi.h>
+#include <linux/gpio/machine.h>
+#include <linux/platform_data/tps68470.h>
+#include <linux/regulator/machine.h>
+#include "tps68470.h"
+
+static struct regulator_consumer_supply int347a_core_consumer_supplies[] = {
+       REGULATOR_SUPPLY("dvdd", "i2c-INT347A:00"),
+};
+
+static struct regulator_consumer_supply int347a_ana_consumer_supplies[] = {
+       REGULATOR_SUPPLY("avdd", "i2c-INT347A:00"),
+};
+
+static struct regulator_consumer_supply int347a_vcm_consumer_supplies[] = {
+       REGULATOR_SUPPLY("vdd", "i2c-INT347A:00-VCM"),
+};
+
+static struct regulator_consumer_supply int347a_vsio_consumer_supplies[] = {
+       REGULATOR_SUPPLY("dovdd", "i2c-INT347A:00"),
+       REGULATOR_SUPPLY("vsio", "i2c-INT347A:00-VCM"),
+};
+
+static const struct regulator_init_data surface_go_tps68470_core_reg_init_data = {
+       .constraints = {
+               .min_uV = 1200000,
+               .max_uV = 1200000,
+               .apply_uV = true,
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies = ARRAY_SIZE(int347a_core_consumer_supplies),
+       .consumer_supplies = int347a_core_consumer_supplies,
+};
+
+static const struct regulator_init_data surface_go_tps68470_ana_reg_init_data = {
+       .constraints = {
+               .min_uV = 2815200,
+               .max_uV = 2815200,
+               .apply_uV = true,
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies = ARRAY_SIZE(int347a_ana_consumer_supplies),
+       .consumer_supplies = int347a_ana_consumer_supplies,
+};
+
+static const struct regulator_init_data surface_go_tps68470_vcm_reg_init_data = {
+       .constraints = {
+               .min_uV = 2815200,
+               .max_uV = 2815200,
+               .apply_uV = true,
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies = ARRAY_SIZE(int347a_vcm_consumer_supplies),
+       .consumer_supplies = int347a_vcm_consumer_supplies,
+};
+
+/* Ensure the always-on VIO regulator has the same voltage as VSIO */
+static const struct regulator_init_data surface_go_tps68470_vio_reg_init_data = {
+       .constraints = {
+               .min_uV = 1800600,
+               .max_uV = 1800600,
+               .apply_uV = true,
+               .always_on = true,
+       },
+};
+
+static const struct regulator_init_data surface_go_tps68470_vsio_reg_init_data = {
+       .constraints = {
+               .min_uV = 1800600,
+               .max_uV = 1800600,
+               .apply_uV = true,
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies = ARRAY_SIZE(int347a_vsio_consumer_supplies),
+       .consumer_supplies = int347a_vsio_consumer_supplies,
+};
+
+static const struct tps68470_regulator_platform_data surface_go_tps68470_pdata = {
+       .reg_init_data = {
+               [TPS68470_CORE] = &surface_go_tps68470_core_reg_init_data,
+               [TPS68470_ANA]  = &surface_go_tps68470_ana_reg_init_data,
+               [TPS68470_VCM]  = &surface_go_tps68470_vcm_reg_init_data,
+               [TPS68470_VIO] = &surface_go_tps68470_vio_reg_init_data,
+               [TPS68470_VSIO] = &surface_go_tps68470_vsio_reg_init_data,
+       },
+};
+
+static struct gpiod_lookup_table surface_go_tps68470_gpios = {
+       .dev_id = "i2c-INT347A:00",
+       .table = {
+               GPIO_LOOKUP("tps68470-gpio", 9, "reset", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("tps68470-gpio", 7, "powerdown", GPIO_ACTIVE_LOW)
+       }
+};
+
+static const struct int3472_tps68470_board_data surface_go_tps68470_board_data = {
+       .dev_name = "i2c-INT3472:05",
+       .tps68470_gpio_lookup_table = &surface_go_tps68470_gpios,
+       .tps68470_regulator_pdata = &surface_go_tps68470_pdata,
+};
+
+static const struct dmi_system_id int3472_tps68470_board_data_table[] = {
+       {
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Go"),
+               },
+               .driver_data = (void *)&surface_go_tps68470_board_data,
+       },
+       {
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Go 2"),
+               },
+               .driver_data = (void *)&surface_go_tps68470_board_data,
+       },
+       { }
+};
+
+const struct int3472_tps68470_board_data *int3472_tps68470_get_board_data(const char *dev_name)
+{
+       const struct int3472_tps68470_board_data *board_data;
+       const struct dmi_system_id *match;
+
+       for (match = dmi_first_match(int3472_tps68470_board_data_table);
+            match;
+            match = dmi_first_match(match + 1)) {
+               board_data = match->driver_data;
+               if (strcmp(board_data->dev_name, dev_name) == 0)
+                       return board_data;
+       }
+
+       return NULL;
+}
index 480f920..2f93ecf 100644 (file)
@@ -202,7 +202,8 @@ struct acpi_device_flags {
        u32 coherent_dma:1;
        u32 cca_seen:1;
        u32 enumeration_by_parent:1;
-       u32 reserved:19;
+       u32 honor_deps:1;
+       u32 reserved:18;
 };
 
 /* File System */
@@ -285,6 +286,7 @@ struct acpi_dep_data {
        struct list_head node;
        acpi_handle supplier;
        acpi_handle consumer;
+       bool honor_dep;
 };
 
 /* Performance Management */
@@ -693,6 +695,7 @@ static inline bool acpi_device_can_poweroff(struct acpi_device *adev)
 bool acpi_dev_hid_uid_match(struct acpi_device *adev, const char *hid2, const char *uid2);
 
 void acpi_dev_clear_dependencies(struct acpi_device *supplier);
+bool acpi_dev_ready_for_enumeration(const struct acpi_device *device);
 struct acpi_device *acpi_dev_get_first_consumer_dev(struct acpi_device *supplier);
 struct acpi_device *
 acpi_dev_get_next_match_dev(struct acpi_device *adev, const char *hid, const char *uid, s64 hrv);
diff --git a/include/dt-bindings/clock/sun20i-d1-ccu.h b/include/dt-bindings/clock/sun20i-d1-ccu.h
new file mode 100644 (file)
index 0000000..e3ac533
--- /dev/null
@@ -0,0 +1,156 @@
+/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */
+/*
+ * Copyright (C) 2020 huangzhenwei@allwinnertech.com
+ * Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
+ */
+
+#ifndef _DT_BINDINGS_CLK_SUN20I_D1_CCU_H_
+#define _DT_BINDINGS_CLK_SUN20I_D1_CCU_H_
+
+#define CLK_PLL_CPUX           0
+#define CLK_PLL_DDR0           1
+#define CLK_PLL_PERIPH0_4X     2
+#define CLK_PLL_PERIPH0_2X     3
+#define CLK_PLL_PERIPH0_800M   4
+#define CLK_PLL_PERIPH0                5
+#define CLK_PLL_PERIPH0_DIV3   6
+#define CLK_PLL_VIDEO0_4X      7
+#define CLK_PLL_VIDEO0_2X      8
+#define CLK_PLL_VIDEO0         9
+#define CLK_PLL_VIDEO1_4X      10
+#define CLK_PLL_VIDEO1_2X      11
+#define CLK_PLL_VIDEO1         12
+#define CLK_PLL_VE             13
+#define CLK_PLL_AUDIO0_4X      14
+#define CLK_PLL_AUDIO0_2X      15
+#define CLK_PLL_AUDIO0         16
+#define CLK_PLL_AUDIO1         17
+#define CLK_PLL_AUDIO1_DIV2    18
+#define CLK_PLL_AUDIO1_DIV5    19
+#define CLK_CPUX               20
+#define CLK_CPUX_AXI           21
+#define CLK_CPUX_APB           22
+#define CLK_PSI_AHB            23
+#define CLK_APB0               24
+#define CLK_APB1               25
+#define CLK_MBUS               26
+#define CLK_DE                 27
+#define CLK_BUS_DE             28
+#define CLK_DI                 29
+#define CLK_BUS_DI             30
+#define CLK_G2D                        31
+#define CLK_BUS_G2D            32
+#define CLK_CE                 33
+#define CLK_BUS_CE             34
+#define CLK_VE                 35
+#define CLK_BUS_VE             36
+#define CLK_BUS_DMA            37
+#define CLK_BUS_MSGBOX0                38
+#define CLK_BUS_MSGBOX1                39
+#define CLK_BUS_MSGBOX2                40
+#define CLK_BUS_SPINLOCK       41
+#define CLK_BUS_HSTIMER                42
+#define CLK_AVS                        43
+#define CLK_BUS_DBG            44
+#define CLK_BUS_PWM            45
+#define CLK_BUS_IOMMU          46
+#define CLK_DRAM               47
+#define CLK_MBUS_DMA           48
+#define CLK_MBUS_VE            49
+#define CLK_MBUS_CE            50
+#define CLK_MBUS_TVIN          51
+#define CLK_MBUS_CSI           52
+#define CLK_MBUS_G2D           53
+#define CLK_MBUS_RISCV         54
+#define CLK_BUS_DRAM           55
+#define CLK_MMC0               56
+#define CLK_MMC1               57
+#define CLK_MMC2               58
+#define CLK_BUS_MMC0           59
+#define CLK_BUS_MMC1           60
+#define CLK_BUS_MMC2           61
+#define CLK_BUS_UART0          62
+#define CLK_BUS_UART1          63
+#define CLK_BUS_UART2          64
+#define CLK_BUS_UART3          65
+#define CLK_BUS_UART4          66
+#define CLK_BUS_UART5          67
+#define CLK_BUS_I2C0           68
+#define CLK_BUS_I2C1           69
+#define CLK_BUS_I2C2           70
+#define CLK_BUS_I2C3           71
+#define CLK_SPI0               72
+#define CLK_SPI1               73
+#define CLK_BUS_SPI0           74
+#define CLK_BUS_SPI1           75
+#define CLK_EMAC_25M           76
+#define CLK_BUS_EMAC           77
+#define CLK_IR_TX              78
+#define CLK_BUS_IR_TX          79
+#define CLK_BUS_GPADC          80
+#define CLK_BUS_THS            81
+#define CLK_I2S0               82
+#define CLK_I2S1               83
+#define CLK_I2S2               84
+#define CLK_I2S2_ASRC          85
+#define CLK_BUS_I2S0           86
+#define CLK_BUS_I2S1           87
+#define CLK_BUS_I2S2           88
+#define CLK_SPDIF_TX           89
+#define CLK_SPDIF_RX           90
+#define CLK_BUS_SPDIF          91
+#define CLK_DMIC               92
+#define CLK_BUS_DMIC           93
+#define CLK_AUDIO_DAC          94
+#define CLK_AUDIO_ADC          95
+#define CLK_BUS_AUDIO          96
+#define CLK_USB_OHCI0          97
+#define CLK_USB_OHCI1          98
+#define CLK_BUS_OHCI0          99
+#define CLK_BUS_OHCI1          100
+#define CLK_BUS_EHCI0          101
+#define CLK_BUS_EHCI1          102
+#define CLK_BUS_OTG            103
+#define CLK_BUS_LRADC          104
+#define CLK_BUS_DPSS_TOP       105
+#define CLK_HDMI_24M           106
+#define CLK_HDMI_CEC_32K       107
+#define CLK_HDMI_CEC           108
+#define CLK_BUS_HDMI           109
+#define CLK_MIPI_DSI           110
+#define CLK_BUS_MIPI_DSI       111
+#define CLK_TCON_LCD0          112
+#define CLK_BUS_TCON_LCD0      113
+#define CLK_TCON_TV            114
+#define CLK_BUS_TCON_TV                115
+#define CLK_TVE                        116
+#define CLK_BUS_TVE_TOP                117
+#define CLK_BUS_TVE            118
+#define CLK_TVD                        119
+#define CLK_BUS_TVD_TOP                120
+#define CLK_BUS_TVD            121
+#define CLK_LEDC               122
+#define CLK_BUS_LEDC           123
+#define CLK_CSI_TOP            124
+#define CLK_CSI_MCLK           125
+#define CLK_BUS_CSI            126
+#define CLK_TPADC              127
+#define CLK_BUS_TPADC          128
+#define CLK_BUS_TZMA           129
+#define CLK_DSP                        130
+#define CLK_BUS_DSP_CFG                131
+#define CLK_RISCV              132
+#define CLK_RISCV_AXI          133
+#define CLK_BUS_RISCV_CFG      134
+#define CLK_FANOUT_24M         135
+#define CLK_FANOUT_12M         136
+#define CLK_FANOUT_16M         137
+#define CLK_FANOUT_25M         138
+#define CLK_FANOUT_32K         139
+#define CLK_FANOUT_27M         140
+#define CLK_FANOUT_PCLK                141
+#define CLK_FANOUT0            142
+#define CLK_FANOUT1            143
+#define CLK_FANOUT2            144
+
+#endif /* _DT_BINDINGS_CLK_SUN20I_D1_CCU_H_ */
diff --git a/include/dt-bindings/clock/sun20i-d1-r-ccu.h b/include/dt-bindings/clock/sun20i-d1-r-ccu.h
new file mode 100644 (file)
index 0000000..4c2697f
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */
+/*
+ * Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
+ */
+
+#ifndef _DT_BINDINGS_CLK_SUN20I_D1_R_CCU_H_
+#define _DT_BINDINGS_CLK_SUN20I_D1_R_CCU_H_
+
+#define CLK_R_AHB              0
+
+#define CLK_BUS_R_TIMER                2
+#define CLK_BUS_R_TWD          3
+#define CLK_BUS_R_PPU          4
+#define CLK_R_IR_RX            5
+#define CLK_BUS_R_IR_RX                6
+#define CLK_BUS_R_RTC          7
+#define CLK_BUS_R_CPUCFG       8
+
+#endif /* _DT_BINDINGS_CLK_SUN20I_D1_R_CCU_H_ */
diff --git a/include/dt-bindings/reset/sun20i-d1-ccu.h b/include/dt-bindings/reset/sun20i-d1-ccu.h
new file mode 100644 (file)
index 0000000..de9ff52
--- /dev/null
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */
+/*
+ * Copyright (c) 2020 huangzhenwei@allwinnertech.com
+ * Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
+ */
+
+#ifndef _DT_BINDINGS_RST_SUN20I_D1_CCU_H_
+#define _DT_BINDINGS_RST_SUN20I_D1_CCU_H_
+
+#define RST_MBUS               0
+#define RST_BUS_DE             1
+#define RST_BUS_DI             2
+#define RST_BUS_G2D            3
+#define RST_BUS_CE             4
+#define RST_BUS_VE             5
+#define RST_BUS_DMA            6
+#define RST_BUS_MSGBOX0                7
+#define RST_BUS_MSGBOX1                8
+#define RST_BUS_MSGBOX2                9
+#define RST_BUS_SPINLOCK       10
+#define RST_BUS_HSTIMER                11
+#define RST_BUS_DBG            12
+#define RST_BUS_PWM            13
+#define RST_BUS_DRAM           14
+#define RST_BUS_MMC0           15
+#define RST_BUS_MMC1           16
+#define RST_BUS_MMC2           17
+#define RST_BUS_UART0          18
+#define RST_BUS_UART1          19
+#define RST_BUS_UART2          20
+#define RST_BUS_UART3          21
+#define RST_BUS_UART4          22
+#define RST_BUS_UART5          23
+#define RST_BUS_I2C0           24
+#define RST_BUS_I2C1           25
+#define RST_BUS_I2C2           26
+#define RST_BUS_I2C3           27
+#define RST_BUS_SPI0           28
+#define RST_BUS_SPI1           29
+#define RST_BUS_EMAC           30
+#define RST_BUS_IR_TX          31
+#define RST_BUS_GPADC          32
+#define RST_BUS_THS            33
+#define RST_BUS_I2S0           34
+#define RST_BUS_I2S1           35
+#define RST_BUS_I2S2           36
+#define RST_BUS_SPDIF          37
+#define RST_BUS_DMIC           38
+#define RST_BUS_AUDIO          39
+#define RST_USB_PHY0           40
+#define RST_USB_PHY1           41
+#define RST_BUS_OHCI0          42
+#define RST_BUS_OHCI1          43
+#define RST_BUS_EHCI0          44
+#define RST_BUS_EHCI1          45
+#define RST_BUS_OTG            46
+#define RST_BUS_LRADC          47
+#define RST_BUS_DPSS_TOP       48
+#define RST_BUS_HDMI_SUB       49
+#define RST_BUS_HDMI_MAIN      50
+#define RST_BUS_MIPI_DSI       51
+#define RST_BUS_TCON_LCD0      52
+#define RST_BUS_TCON_TV                53
+#define RST_BUS_LVDS0          54
+#define RST_BUS_TVE            55
+#define RST_BUS_TVE_TOP                56
+#define RST_BUS_TVD            57
+#define RST_BUS_TVD_TOP                58
+#define RST_BUS_LEDC           59
+#define RST_BUS_CSI            60
+#define RST_BUS_TPADC          61
+#define RST_DSP                        62
+#define RST_BUS_DSP_CFG                63
+#define RST_BUS_DSP_DBG                64
+#define RST_BUS_RISCV_CFG      65
+
+#endif /* _DT_BINDINGS_RST_SUN20I_D1_CCU_H_ */
diff --git a/include/dt-bindings/reset/sun20i-d1-r-ccu.h b/include/dt-bindings/reset/sun20i-d1-r-ccu.h
new file mode 100644 (file)
index 0000000..d93d642
--- /dev/null
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */
+/*
+ * Copyright (C) 2021 Samuel Holland <samuel@sholland.org>
+ */
+
+#ifndef _DT_BINDINGS_RST_SUN20I_D1_R_CCU_H_
+#define _DT_BINDINGS_RST_SUN20I_D1_R_CCU_H_
+
+#define RST_BUS_R_TIMER                0
+#define RST_BUS_R_TWD          1
+#define RST_BUS_R_PPU          2
+#define RST_BUS_R_IR_RX                3
+#define RST_BUS_R_RTC          4
+#define RST_BUS_R_CPUCFG       5
+
+#endif /* _DT_BINDINGS_RST_SUN20I_D1_R_CCU_H_ */
index 3cd14ac..cf32123 100644 (file)
@@ -6,22 +6,7 @@
 #ifndef _LINUX_CLK_SUNXI_NG_H_
 #define _LINUX_CLK_SUNXI_NG_H_
 
-#include <linux/errno.h>
-
-#ifdef CONFIG_SUNXI_CCU
 int sunxi_ccu_set_mmc_timing_mode(struct clk *clk, bool new_mode);
 int sunxi_ccu_get_mmc_timing_mode(struct clk *clk);
-#else
-static inline int sunxi_ccu_set_mmc_timing_mode(struct clk *clk,
-                                               bool new_mode)
-{
-       return -ENOTSUPP;
-}
-
-static inline int sunxi_ccu_get_mmc_timing_mode(struct clk *clk)
-{
-       return -ENOTSUPP;
-}
-#endif
 
 #endif
index 16119ac..7d4f52c 100644 (file)
@@ -1025,8 +1025,9 @@ bool i2c_acpi_get_i2c_resource(struct acpi_resource *ares,
                               struct acpi_resource_i2c_serialbus **i2c);
 int i2c_acpi_client_count(struct acpi_device *adev);
 u32 i2c_acpi_find_bus_speed(struct device *dev);
-struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
-                                      struct i2c_board_info *info);
+struct i2c_client *i2c_acpi_new_device_by_fwnode(struct fwnode_handle *fwnode,
+                                                int index,
+                                                struct i2c_board_info *info);
 struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle);
 bool i2c_acpi_waive_d0_probe(struct device *dev);
 #else
@@ -1043,8 +1044,9 @@ static inline u32 i2c_acpi_find_bus_speed(struct device *dev)
 {
        return 0;
 }
-static inline struct i2c_client *i2c_acpi_new_device(struct device *dev,
-                                       int index, struct i2c_board_info *info)
+static inline struct i2c_client *i2c_acpi_new_device_by_fwnode(
+                                       struct fwnode_handle *fwnode, int index,
+                                       struct i2c_board_info *info)
 {
        return ERR_PTR(-ENODEV);
 }
@@ -1058,4 +1060,11 @@ static inline bool i2c_acpi_waive_d0_probe(struct device *dev)
 }
 #endif /* CONFIG_ACPI */
 
+static inline struct i2c_client *i2c_acpi_new_device(struct device *dev,
+                                                    int index,
+                                                    struct i2c_board_info *info)
+{
+       return i2c_acpi_new_device_by_fwnode(dev_fwnode(dev), index, info);
+}
+
 #endif /* _LINUX_I2C_H */
index ffe8112..7807fa3 100644 (file)
 #define TPS68470_CLKCFG1_MODE_A_MASK   GENMASK(1, 0)
 #define TPS68470_CLKCFG1_MODE_B_MASK   GENMASK(3, 2)
 
+#define TPS68470_CLKCFG2_DRV_STR_2MA   0x05
+#define TPS68470_PLL_OUTPUT_ENABLE     0x02
+#define TPS68470_CLK_SRC_XTAL          BIT(0)
+#define TPS68470_PLLSWR_DEFAULT                GENMASK(1, 0)
+#define TPS68470_OSC_EXT_CAP_DEFAULT   0x05
+
+#define TPS68470_OUTPUT_A_SHIFT                0x00
+#define TPS68470_OUTPUT_B_SHIFT                0x02
+#define TPS68470_CLK_SRC_SHIFT         GENMASK(2, 0)
+#define TPS68470_OSC_EXT_CAP_SHIFT     BIT(2)
+
 #define TPS68470_GPIO_CTL_REG_A(x)     (TPS68470_REG_GPCTL0A + (x) * 2)
 #define TPS68470_GPIO_CTL_REG_B(x)     (TPS68470_REG_GPCTL0B + (x) * 2)
 #define TPS68470_GPIO_MODE_MASK                GENMASK(1, 0)
index b9f6824..11a2a23 100644 (file)
@@ -12,7 +12,7 @@
 
 struct fch_clk_data {
        void __iomem *base;
-       u32 is_rv;
+       char *name;
 };
 
 #endif /* __CLK_FCH_H */
diff --git a/include/linux/platform_data/tps68470.h b/include/linux/platform_data/tps68470.h
new file mode 100644 (file)
index 0000000..126d082
--- /dev/null
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * TI TPS68470 PMIC platform data definition.
+ *
+ * Copyright (c) 2021 Red Hat Inc.
+ *
+ * Red Hat authors:
+ * Hans de Goede <hdegoede@redhat.com>
+ */
+#ifndef __PDATA_TPS68470_H
+#define __PDATA_TPS68470_H
+
+enum tps68470_regulators {
+       TPS68470_CORE,
+       TPS68470_ANA,
+       TPS68470_VCM,
+       TPS68470_VIO,
+       TPS68470_VSIO,
+       TPS68470_AUX1,
+       TPS68470_AUX2,
+       TPS68470_NUM_REGULATORS
+};
+
+struct regulator_init_data;
+
+struct tps68470_regulator_platform_data {
+       const struct regulator_init_data *reg_init_data[TPS68470_NUM_REGULATORS];
+};
+
+struct tps68470_clk_platform_data {
+       const char *consumer_dev_name;
+       const char *consumer_con_id;
+};
+
+#endif