Merge branch 'CR_2440_515_Clocktree_1.5G_Xingyu.Wu' into 'jh7110-5.15.y-devel'
authorandy.hu <andy.hu@starfivetech.com>
Fri, 28 Oct 2022 03:38:26 +0000 (03:38 +0000)
committerandy.hu <andy.hu@starfivetech.com>
Fri, 28 Oct 2022 03:38:26 +0000 (03:38 +0000)
CR_2440_515_Clocktree_1.5G_Xingyu.Wu

See merge request sdk/linux!564

60 files changed:
arch/riscv/boot/dts/starfive/jh7110-common.dtsi
arch/riscv/boot/dts/starfive/jh7110-evb-pinctrl.dtsi
arch/riscv/boot/dts/starfive/jh7110.dtsi
arch/riscv/configs/starfive_jh7110_defconfig
arch/riscv/include/asm/cpu_ops_sbi.h [new file with mode: 0644]
arch/riscv/include/asm/sbi.h
arch/riscv/kernel/asm-offsets.c
arch/riscv/kernel/cpu_ops_sbi.c
arch/riscv/kernel/head.S
arch/riscv/kernel/sbi.c
drivers/char/hw_random/starfive-trng.c [changed mode: 0644->0755]
drivers/clk/starfive/clk-starfive-jh7110-gen.c
drivers/clk/starfive/clk-starfive-jh7110-isp.c [changed mode: 0755->0644]
drivers/clk/starfive/clk-starfive-jh7110-sys.c [changed mode: 0755->0644]
drivers/cpufreq/starfive-cpufreq.c
drivers/cpuidle/cpuidle-riscv-sbi.c
drivers/crypto/starfive/jh7110/jh7110-aes.c
drivers/crypto/starfive/jh7110/jh7110-sec.c
drivers/crypto/starfive/jh7110/jh7110-sha.c
drivers/gpu/drm/img/img-rogue/services/server/common/power.c
drivers/gpu/drm/img/img-rogue/services/server/devices/rogue/rgxinit.c
drivers/gpu/drm/img/img-rogue/services/server/env/linux/module_common.c
drivers/gpu/drm/img/img-rogue/services/server/env/linux/module_common.h
drivers/gpu/drm/img/img-rogue/services/server/env/linux/pvr_drm.c
drivers/gpu/drm/img/img-rogue/services/system/rogue/sf_7110/sysconfig.c
drivers/gpu/drm/img/img-rogue/services/system/rogue/sf_7110/sysconfig.h
drivers/hwmon/sfctemp.c
drivers/i2c/busses/i2c-designware-platdrv.c
drivers/mailbox/starfive_mailbox.c
drivers/media/platform/starfive/v4l2_driver/imx219_mipi.c
drivers/media/platform/starfive/v4l2_driver/ov4689_mipi.c
drivers/media/platform/starfive/v4l2_driver/sc2235.c
drivers/media/platform/starfive/v4l2_driver/stf_isp.c
drivers/media/platform/starfive/v4l2_driver/stf_vin.c
drivers/media/platform/starfive/v4l2_driver/stf_vin.h
drivers/media/platform/starfive/v4l2_driver/stf_vin_hw_ops.c
drivers/media/platform/starfive/v4l2_driver/stfcamss.c
drivers/media/platform/starfive/v4l2_driver/stfcamss.h
drivers/mmc/host/dw_mmc-starfive.c
drivers/net/can/ipms_canfd.c
drivers/pci/controller/pcie-plda.c
drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c
drivers/pwm/pwm-starfive-ptc.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/axp15060-regulator.c [new file with mode: 0644]
drivers/rtc/rtc-starfive.c
drivers/spi/spi-pl022-starfive.c
drivers/usb/cdns3/cdns3-starfive.c
drivers/watchdog/starfive-wdt.c
include/linux/regulator/axp15060.h [new file with mode: 0644]
sound/soc/dwc/dwc-i2s.c [changed mode: 0755->0644]
sound/soc/starfive/starfive_i2s.c
sound/soc/starfive/starfive_pdm.c
sound/soc/starfive/starfive_pwmdac.c
sound/soc/starfive/starfive_spdif.c [changed mode: 0755->0644]
sound/soc/starfive/starfive_spdif.h [changed mode: 0755->0644]
sound/soc/starfive/starfive_spdif_pcm.c [changed mode: 0755->0644]
sound/soc/starfive/starfive_tdm.c
sound/soc/starfive/starfive_tdm.h

index 50d926d..14c35ac 100644 (file)
 };
 
 &pcie0 {
-       pinctrl-names = "perst-default", "perst-active", "power-active";
+       pinctrl-names = "perst-default", "perst-active", "power-default", "power-active";
        pinctrl-0 = <&pcie0_perst_default>;
        pinctrl-1 = <&pcie0_perst_active>;
-       pinctrl-2 = <&pcie0_power_active>;
+       pinctrl-2 = <&pcie0_power_default>;
+       pinctrl-3 = <&pcie0_power_active>;
        status = "disabled";
 };
 
 &pcie1 {
-       pinctrl-names = "perst-default", "perst-active", "power-active";
+       pinctrl-names = "perst-default", "perst-active", "power-default", "power-active";
        pinctrl-0 = <&pcie1_perst_default>;
        pinctrl-1 = <&pcie1_perst_active>;
-       pinctrl-2 = <&pcie1_power_active>;
+       pinctrl-2 = <&pcie1_power_default>;
+       pinctrl-3 = <&pcie1_power_active>;
        status = "disabled";
 };
 
index f5df4f7..507a536 100644 (file)
                };
        };
 
+       pcie0_power_default: pcie0_power_default {
+               power-pins {
+                       starfive,pins = <PAD_GPIO32>;
+                       starfive,pinmux = <PAD_GPIO32_FUNC_SEL 0>;
+                       starfive,pin-ioconfig = <IO(GPIO_IE(1))>;
+                       starfive,pin-gpio-dout = <GPO_LOW>;
+                       starfive,pin-gpio-doen = <OEN_LOW>;
+               };
+       };
+
        pcie0_power_active: pcie0_power_active {
                power-pins {
                        starfive,pins = <PAD_GPIO32>;
                };
        };
 
+       pcie1_power_default: pcie1_power_default {
+               power-pins {
+                       starfive,pins = <PAD_GPIO21>;
+                       starfive,pinmux = <PAD_GPIO21_FUNC_SEL 0>;
+                       starfive,pin-ioconfig = <IO(GPIO_IE(1))>;
+                       starfive,pin-gpio-dout = <GPO_LOW>;
+                       starfive,pin-gpio-doen = <OEN_LOW>;
+               };
+       };
+
        pcie1_power_active: pcie1_power_active {
                power-pins {
                        starfive,pins = <PAD_GPIO21>;
index 99db7b0..6a2b038 100644 (file)
                                        opp-hz = /bits/ 64 <500000000>;
                                        opp-microvolt = <880000>;
                        };
-                       opp-625000000 {
-                                       opp-hz = /bits/ 64 <625000000>;
-                                       opp-microvolt = <880000>;
-                       };
                        opp-750000000 {
                                        opp-hz = /bits/ 64 <750000000>;
                                        opp-microvolt = <880000>;
                        };
-                       opp-875000000 {
-                                       opp-hz = /bits/ 64 <875000000>;
-                                       opp-microvolt = <880000>;
-                       };
-                       opp-1000000000 {
-                                       opp-hz = /bits/ 64 <1000000000>;
-                                       opp-microvolt = <900000>;
-                       };
-                       opp-1250000000 {
-                                       opp-hz = /bits/ 64 <1250000000>;
-                                       opp-microvolt = <950000>;
-                       };
-                       opp-1375000000 {
-                                       opp-hz = /bits/ 64 <1375000000>;
-                                       opp-microvolt = <1000000>;
-                       };
                        opp-1500000000 {
                                        opp-hz = /bits/ 64 <1500000000>;
-                                       opp-microvolt = <1100000>;
-                       };
-                       opp-1625000000 {
-                                       opp-hz = /bits/ 64 <1625000000>;
-                                       opp-microvolt = <1100000>;
-                       };
-                       opp-1750000000 {
-                                       opp-hz = /bits/ 64 <1750000000>;
-                                       opp-microvolt = <1200000>;
+                                       opp-microvolt = <1000000>;
                        };
        };
 
@@ -85,8 +57,7 @@
                        i-tlb-sets = <1>;
                        i-tlb-size = <40>;
                        mmu-type = "riscv,sv39";
-                       cpu-idle-states = <&CPU_RET_0_0 &CPU_NONRET_0_0
-                            &CLUSTER_RET_0 &CLUSTER_NONRET_0>;
+                       cpu-idle-states = <&CPU_NONRET_0_0>;
                        next-level-cache = <&cachectrl>;
                        riscv,isa = "rv64imac";
                        tlb-split;
                        i-tlb-sets = <1>;
                        i-tlb-size = <40>;
                        mmu-type = "riscv,sv39";
-                       cpu-idle-states = <&CPU_RET_0_0 &CPU_NONRET_0_0
-                            &CLUSTER_RET_0 &CLUSTER_NONRET_0>;
+                       cpu-idle-states = <&CPU_NONRET_0_0>;
                        next-level-cache = <&cachectrl>;
                        riscv,isa = "rv64imafdc";
                        tlb-split;
                        i-tlb-sets = <1>;
                        i-tlb-size = <40>;
                        mmu-type = "riscv,sv39";
-                       cpu-idle-states = <&CPU_RET_0_0 &CPU_NONRET_0_0
-                            &CLUSTER_RET_0 &CLUSTER_NONRET_0>;
+                       cpu-idle-states = <&CPU_NONRET_0_0>;
                        next-level-cache = <&cachectrl>;
                        riscv,isa = "rv64imafdc";
                        tlb-split;
                        i-tlb-sets = <1>;
                        i-tlb-size = <40>;
                        mmu-type = "riscv,sv39";
-                       cpu-idle-states = <&CPU_RET_0_0 &CPU_NONRET_0_0
-                            &CLUSTER_RET_0 &CLUSTER_NONRET_0>;
+                       cpu-idle-states = <&CPU_NONRET_0_0>;
                        next-level-cache = <&cachectrl>;
                        riscv,isa = "rv64imafdc";
                        tlb-split;
                        i-tlb-sets = <1>;
                        i-tlb-size = <40>;
                        mmu-type = "riscv,sv39";
-                       cpu-idle-states = <&CPU_RET_0_0 &CPU_NONRET_0_0
-                            &CLUSTER_RET_0 &CLUSTER_NONRET_0>;
+                       cpu-idle-states = <&CPU_NONRET_0_0>;
                        next-level-cache = <&cachectrl>;
                        riscv,isa = "rv64imafdc";
                        tlb-split;
                };
        };
 
-    idle-states {
-        CPU_RET_0_0: cpu-retentive-0-0 {
-            compatible = "starfive,jh7110-idle-state";
-            riscv,sbi-suspend-param = <0x10000000>;
-            entry-latency-us = <20>;
-            exit-latency-us = <40>;
-            min-residency-us = <80>;
-        };
-
-        CPU_NONRET_0_0: cpu-nonretentive-0-0 {
-            compatible = "starfive,jh7110-idle-state";
-            riscv,sbi-suspend-param = <0x90000000>;
-            entry-latency-us = <250>;
-            exit-latency-us = <500>;
-            min-residency-us = <950>;
-        };
-
-        CLUSTER_RET_0: cluster-retentive-0 {
-            compatible = "starfive,jh7110-idle-state";
-            riscv,sbi-suspend-param = <0x11000000>;
-            local-timer-stop;
-            entry-latency-us = <50>;
-            exit-latency-us = <100>;
-            min-residency-us = <250>;
-            wakeup-latency-us = <130>;
-        };
-
-        CLUSTER_NONRET_0: cluster-nonretentive-0 {
-            compatible = "starfive,jh7110-idle-state";
-            riscv,sbi-suspend-param = <0x91000000>;
-            local-timer-stop;
-            entry-latency-us = <600>;
-            exit-latency-us = <1100>;
-            min-residency-us = <2700>;
-            wakeup-latency-us = <1500>;
-        };
+       idle-states {
+               CPU_NONRET_0_0: cpu-nonretentive-0-0 {
+                       compatible = "riscv,idle-state";
+                       riscv,sbi-suspend-param = <0x80000000>;
+                       entry-latency-us = <600>;
+                       exit-latency-us = <1100>;
+                       min-residency-us = <2700>;
+                       wakeup-latency-us = <1500>;
+               };
        };
 
        soc: soc {
                                 <&clkisp JH7110_U0_M31DPHY_REFCLK_IN>,
                                 <&clkisp JH7110_U0_M31DPHY_TXCLKESC_LAN0>,
                                 <&clkgen JH7110_ISP_TOP_CLK_ISPCORE_2X>,
-                                <&clkgen JH7110_ISP_TOP_CLK_ISP_AXI>,
-                                <&clkgen JH7110_NOC_BUS_CLK_ISP_AXI>;
+                                <&clkgen JH7110_ISP_TOP_CLK_ISP_AXI>;
                        clock-names = "clk_apb_func", "clk_pclk", "clk_sys_clk",
                                "clk_wrapper_clk_c", "clk_dvp_inv", "clk_axiwr",
                                "clk_mipi_rx0_pxl", "clk_pixel_clk_if0",
                                "clk_pixel_clk_if1", "clk_pixel_clk_if2",
                                "clk_pixel_clk_if3", "clk_m31dphy_cfgclk_in",
                                "clk_m31dphy_refclk_in", "clk_m31dphy_txclkesc_lan0",
-                               "clk_ispcore_2x", "clk_isp_axi", "clk_noc_bus_clk_isp_axi";
+                               "clk_ispcore_2x", "clk_isp_axi";
                        resets = <&rstgen RSTN_U0_ISPV2_TOP_WRAPPER_P>,
                                 <&rstgen RSTN_U0_ISPV2_TOP_WRAPPER_C>,
                                 <&rstgen RSTN_U0_VIN_N_PCLK>,
                        compatible = "img-gpu";
                        reg = <0x0 0x18000000 0x0 0x100000>,
                                <0x0 0x130C000 0x0 0x10000>;
-                       clocks = <&clkgen JH7110_GPU_CORE>, 
+                       clocks = <&clkgen JH7110_GPU_CORE>,
                                 <&clkgen JH7110_GPU_CLK_APB>,
                                 <&clkgen JH7110_GPU_RTC_TOGGLE>,
                                 <&clkgen JH7110_GPU_CORE_CLK>,
                               0x9 0x40000000 0x0 0x10000000>;
                        reg-names = "reg", "config";
                        device_type = "pci";
-                       starfive,stg-syscon = <&stg_syscon 0xc0 0xc4 0x130>;
+                       starfive,stg-syscon = <&stg_syscon 0xc0 0xc4 0x130 0x1b8>;
                        bus-range = <0x0 0xff>;
                        ranges = <0x82000000  0x0 0x30000000  0x0 0x30000000 0x0 0x08000000>,
                                 <0xc3000000  0x9 0x00000000  0x9 0x00000000 0x0 0x40000000>;
                               0x9 0xc0000000 0x0 0x10000000>;
                        reg-names = "reg", "config";
                        device_type = "pci";
-                       starfive,stg-syscon = <&stg_syscon 0x270 0x274 0x2e0>;
+                       starfive,stg-syscon = <&stg_syscon 0x270 0x274 0x2e0 0x368>;
                        bus-range = <0x0 0xff>;
                        ranges = <0x82000000  0x0 0x38000000  0x0 0x38000000 0x0 0x08000000>,
                                 <0xc3000000  0x9 0x80000000  0x9 0x80000000 0x0 0x40000000>;
 
                starfive_cpufreq: starfive,jh7110-cpufreq {
                        compatible = "starfive,jh7110-cpufreq";
-                       clocks = <&clkgen JH7110_PLL0_OUT>,
-                                        <&clkgen JH7110_CPU_ROOT>,
-                                        <&osc>;
-                       clock-names = "pll0", "cpu_clk", "osc";
+                       clocks = <&clkgen JH7110_CPU_CORE>;
+                       clock-names = "cpu_clk";
                };
        };
 };
index b802534..515647d 100644 (file)
@@ -21,6 +21,8 @@ CONFIG_SOC_STARFIVE_JH7110=y
 CONFIG_SMP=y
 CONFIG_HZ_100=y
 CONFIG_PM=y
+CONFIG_PM_DEBUG=y
+CONFIG_PM_ADVANCED_DEBUG=y
 CONFIG_CPU_IDLE=y
 CONFIG_RISCV_SBI_CPUIDLE=y
 # CONFIG_SECCOMP is not set
@@ -177,6 +179,7 @@ CONFIG_WATCHDOG=y
 CONFIG_WATCHDOG_SYSFS=y
 CONFIG_STARFIVE_WATCHDOG=y
 CONFIG_REGULATOR=y
+CONFIG_REGULATOR_AXP15060=y
 CONFIG_REGULATOR_STARFIVE_JH7110=y
 # CONFIG_MEDIA_CEC_SUPPORT is not set
 CONFIG_MEDIA_SUPPORT=y
@@ -256,6 +259,14 @@ CONFIG_PWM=y
 CONFIG_PWM_STARFIVE_PTC=y
 CONFIG_PHY_M31_DPHY_RX0=y
 CONFIG_RAS=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+CONFIG_CPUFREQ_DT=y
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_AUTOFS4_FS=y
diff --git a/arch/riscv/include/asm/cpu_ops_sbi.h b/arch/riscv/include/asm/cpu_ops_sbi.h
new file mode 100644 (file)
index 0000000..56e4b76
--- /dev/null
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2021 by Rivos Inc.
+ */
+#ifndef __ASM_CPU_OPS_SBI_H
+#define __ASM_CPU_OPS_SBI_H
+
+#ifndef __ASSEMBLY__
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/threads.h>
+
+/**
+ * struct sbi_hart_boot_data - Hart specific boot used during booting and
+ *                            cpu hotplug.
+ * @task_ptr: A pointer to the hart specific tp
+ * @stack_ptr: A pointer to the hart specific sp
+ */
+struct sbi_hart_boot_data {
+       void *task_ptr;
+       void *stack_ptr;
+};
+#endif
+
+#endif /* ifndef __ASM_CPU_OPS_SBI_H */
index f59c9b0..3338ca2 100644 (file)
@@ -27,6 +27,7 @@ enum sbi_ext_id {
        SBI_EXT_IPI = 0x735049,
        SBI_EXT_RFENCE = 0x52464E43,
        SBI_EXT_HSM = 0x48534D,
+       SBI_EXT_SRST = 0x53525354,
 };
 
 enum sbi_ext_base_fid {
@@ -86,6 +87,21 @@ enum sbi_hsm_hart_state {
 #define SBI_HSM_SUSPEND_NON_RET_LAST           (SBI_HSM_SUSP_NON_RET_BIT | \
                                                 SBI_HSM_SUSP_BASE_MASK)
 
+enum sbi_ext_srst_fid {
+       SBI_EXT_SRST_RESET = 0,
+};
+
+enum sbi_srst_reset_type {
+       SBI_SRST_RESET_TYPE_SHUTDOWN = 0,
+       SBI_SRST_RESET_TYPE_COLD_REBOOT,
+       SBI_SRST_RESET_TYPE_WARM_REBOOT,
+};
+
+enum sbi_srst_reset_reason {
+       SBI_SRST_RESET_REASON_NONE = 0,
+       SBI_SRST_RESET_REASON_SYS_FAILURE,
+};
+
 #define SBI_SPEC_VERSION_DEFAULT       0x1
 #define SBI_SPEC_VERSION_MAJOR_SHIFT   24
 #define SBI_SPEC_VERSION_MAJOR_MASK    0x7f
index 5eae199..9ec6731 100644 (file)
@@ -11,6 +11,7 @@
 #include <asm/thread_info.h>
 #include <asm/ptrace.h>
 #include <asm/suspend.h>
+#include <asm/cpu_ops_sbi.h>
 
 void asm_offsets(void);
 
@@ -316,4 +317,6 @@ void asm_offsets(void)
        DEFINE(PT_SIZE_ON_STACK, ALIGN(sizeof(struct pt_regs), STACK_ALIGN));
 
        OFFSET(KERNEL_MAP_VIRT_ADDR, kernel_mapping, virt_addr);
+       OFFSET(SBI_HART_BOOT_TASK_PTR_OFFSET, sbi_hart_boot_data, task_ptr);
+       OFFSET(SBI_HART_BOOT_STACK_PTR_OFFSET, sbi_hart_boot_data, stack_ptr);
 }
index 5fd90f0..2e16f67 100644 (file)
@@ -7,13 +7,22 @@
 
 #include <linux/init.h>
 #include <linux/mm.h>
+#include <linux/sched/task_stack.h>
 #include <asm/cpu_ops.h>
+#include <asm/cpu_ops_sbi.h>
 #include <asm/sbi.h>
 #include <asm/smp.h>
 
 extern char secondary_start_sbi[];
 const struct cpu_operations cpu_ops_sbi;
 
+/*
+ * Ordered booting via HSM brings one cpu at a time. However, cpu hotplug can
+ * be invoked from multiple threads in parallel. Define a per cpu data
+ * to handle that.
+ */
+DEFINE_PER_CPU(struct sbi_hart_boot_data, boot_data);
+
 static int sbi_hsm_hart_start(unsigned long hartid, unsigned long saddr,
                              unsigned long priv)
 {
@@ -55,14 +64,19 @@ static int sbi_hsm_hart_get_status(unsigned long hartid)
 
 static int sbi_cpu_start(unsigned int cpuid, struct task_struct *tidle)
 {
-       int rc;
        unsigned long boot_addr = __pa_symbol(secondary_start_sbi);
        int hartid = cpuid_to_hartid_map(cpuid);
-
-       cpu_update_secondary_bootdata(cpuid, tidle);
-       rc = sbi_hsm_hart_start(hartid, boot_addr, 0);
-
-       return rc;
+       unsigned long hsm_data;
+       struct sbi_hart_boot_data *bdata = &per_cpu(boot_data, cpuid);
+
+       /* Make sure tidle is updated */
+       smp_mb();
+       bdata->task_ptr = tidle;
+       bdata->stack_ptr = task_stack_page(tidle) + THREAD_SIZE;
+       /* Make sure boot data is updated */
+       smp_mb();
+       hsm_data = __pa(bdata);
+       return sbi_hsm_hart_start(hartid, boot_addr, hsm_data);
 }
 
 static int sbi_cpu_prepare(unsigned int cpuid)
index 25baa19..2fc8617 100644 (file)
@@ -11,6 +11,7 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/csr.h>
+#include <asm/cpu_ops_sbi.h>
 #include <asm/hwcap.h>
 #include <asm/image.h>
 #include "efi-header.S"
@@ -147,18 +148,17 @@ secondary_start_sbi:
        la a3, .Lsecondary_park
        csrw CSR_TVEC, a3
 
-       slli a3, a0, LGREG
-       la a4, __cpu_up_stack_pointer
-       XIP_FIXUP_OFFSET a4
-       la a5, __cpu_up_task_pointer
-       XIP_FIXUP_OFFSET a5
-       add a4, a3, a4
-       add a5, a3, a5
-       REG_L sp, (a4)
-       REG_L tp, (a5)
-
-       .global secondary_start_common
-secondary_start_common:
+       /* a0 contains the hartid & a1 contains boot data */
+       li a2, SBI_HART_BOOT_TASK_PTR_OFFSET
+       XIP_FIXUP_OFFSET a2
+       add a2, a2, a1
+       REG_L tp, (a2)
+       li a3, SBI_HART_BOOT_STACK_PTR_OFFSET
+       XIP_FIXUP_OFFSET a3
+       add a3, a3, a1
+       REG_L sp, (a3)
+
+.Lsecondary_start_common:
 
 #ifdef CONFIG_MMU
        /* Enable virtual memory and relocate to virtual address */
@@ -344,7 +344,7 @@ clear_bss_done:
        beqz tp, .Lwait_for_cpu_up
        fence
 
-       tail secondary_start_common
+       tail .Lsecondary_start_common
 #endif
 
 END(_start_kernel)
index 7402a41..9a84f0c 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/init.h>
 #include <linux/pm.h>
+#include <linux/reboot.h>
 #include <asm/sbi.h>
 #include <asm/smp.h>
 
@@ -501,6 +502,32 @@ int sbi_remote_hfence_vvma_asid(const unsigned long *hart_mask,
 }
 EXPORT_SYMBOL(sbi_remote_hfence_vvma_asid);
 
+static void sbi_srst_reset(unsigned long type, unsigned long reason)
+{
+       sbi_ecall(SBI_EXT_SRST, SBI_EXT_SRST_RESET, type, reason,
+                 0, 0, 0, 0);
+       pr_warn("%s: type=0x%lx reason=0x%lx failed\n",
+               __func__, type, reason);
+}
+
+static int sbi_srst_reboot(struct notifier_block *this,
+                          unsigned long mode, void *cmd)
+{
+       sbi_srst_reset((mode == REBOOT_WARM || mode == REBOOT_SOFT) ?
+                      SBI_SRST_RESET_TYPE_WARM_REBOOT :
+                      SBI_SRST_RESET_TYPE_COLD_REBOOT,
+                      SBI_SRST_RESET_REASON_NONE);
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block sbi_srst_reboot_nb;
+
+static void sbi_srst_power_off(void)
+{
+       sbi_srst_reset(SBI_SRST_RESET_TYPE_SHUTDOWN,
+                      SBI_SRST_RESET_REASON_NONE);
+}
+
 /**
  * sbi_probe_extension() - Check if an SBI extension ID is supported or not.
  * @extid: The extension ID to be probed.
@@ -608,6 +635,14 @@ void __init sbi_init(void)
                } else {
                        __sbi_rfence    = __sbi_rfence_v01;
                }
+               if ((sbi_spec_version >= sbi_mk_version(0, 3)) &&
+                   (sbi_probe_extension(SBI_EXT_SRST) > 0)) {
+                       pr_info("SBI SRST extension detected\n");
+                       pm_power_off = sbi_srst_power_off;
+                       sbi_srst_reboot_nb.notifier_call = sbi_srst_reboot;
+                       sbi_srst_reboot_nb.priority = 192;
+                       register_restart_handler(&sbi_srst_reboot_nb);
+               }
        } else {
                __sbi_set_timer = __sbi_set_timer_v01;
                __sbi_send_ipi  = __sbi_send_ipi_v01;
old mode 100644 (file)
new mode 100755 (executable)
index c84aead..b357fe4
@@ -17,7 +17,7 @@
 #include <linux/delay.h>
 #include <linux/clk.h>
 #include <linux/reset.h>
-
+#include <linux/pm_runtime.h>
 #include "starfive-trng.h"
 
 #define to_trng(p)     container_of(p, struct trng, rng)
@@ -231,6 +231,8 @@ static int trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
        struct trng *hrng = to_trng(rng);
        u32 intr = 0;
 
+       pm_runtime_get_sync(hrng->dev);
+
        trng_cmd(hrng, CCORE_CTRL_EXEC_NOP);
 
        if (hrng->mode == PRNG_256BIT)
@@ -261,6 +263,8 @@ static int trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
        trng_wait_till_idle(hrng);
        writel(0, hrng->base + CCORE_IE);
 
+       pm_runtime_put_sync(hrng->dev);
+
        return max;
 }
 
@@ -357,6 +361,13 @@ static int trng_probe(struct platform_device *pdev)
                goto err_disable_miscahb_clk;
        }
 
+       clk_disable_unprepare(rng->hclk);
+       clk_disable_unprepare(rng->miscahb_clk);
+
+       pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_set_autosuspend_delay(&pdev->dev, 100);
+       pm_runtime_enable(&pdev->dev);
+
        return 0;
 
 err_disable_miscahb_clk:
@@ -367,6 +378,46 @@ err_disable_hclk:
 
        return ret;
 }
+#ifdef CONFIG_PM
+
+static int starfive_trng_runtime_suspend(struct device *dev)
+{
+       struct trng *trng = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(trng->hclk);
+       clk_disable_unprepare(trng->miscahb_clk);
+
+       dev_dbg(dev, "starfive hrng runtime suspend");
+
+       return 0;
+}
+
+static int starfive_trng_runtime_resume(struct device *dev)
+{
+       struct trng *trng = dev_get_drvdata(dev);
+
+       clk_prepare_enable(trng->hclk);
+       clk_prepare_enable(trng->miscahb_clk);
+
+       dev_dbg(dev, "starfive hrng runtime resume");
+
+       return 0;
+}
+
+static int starfive_trng_runtime_idle(struct device *dev)
+{
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_autosuspend(dev);
+
+       return 0;
+}
+#endif/*CONFIG_PM*/
+
+static const struct dev_pm_ops starfive_trng_pm_ops = {
+       SET_RUNTIME_PM_OPS(starfive_trng_runtime_suspend, starfive_trng_runtime_resume,
+               starfive_trng_runtime_idle)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+};
 
 static const struct of_device_id trng_dt_ids[] = {
        { .compatible = "starfive,jh7110-trng" },
@@ -377,7 +428,8 @@ MODULE_DEVICE_TABLE(of, trng_dt_ids);
 static struct platform_driver trng_driver = {
        .probe          = trng_probe,
        .driver         = {
-               .name           = "trng",
+               .name   = "trng",
+               .pm     = &starfive_trng_pm_ops,
                .of_match_table = of_match_ptr(trng_dt_ids),
        },
 };
index 877bf04..118154c 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/of_device.h>
+#include <linux/pm_runtime.h>
 
 #include <dt-bindings/clock/starfive-jh7110-clkgen.h>
 #include "clk-starfive-jh7110.h"
@@ -53,6 +54,19 @@ void __iomem *jh7110_clk_reg_addr_get(struct jh7110_clk *clk)
 static u32 jh7110_clk_reg_get(struct jh7110_clk *clk)
 {
        void __iomem *reg = jh7110_clk_reg_addr_get(clk);
+       if (clk->reg_flags == JH7110_CLK_ISP_FLAG) {
+               int ret;
+               struct jh7110_clk_priv *priv = jh7110_priv_from(clk);
+
+               if (pm_runtime_suspended(priv->dev)) {
+                       ret = pm_runtime_get_sync(priv->dev);
+                       if (ret < 0) {
+                               dev_err(priv->dev, "cannot resume device :%d.\n", ret);
+                               return 0;
+                       }
+                       pm_runtime_put(priv->dev);
+               }
+       }
 
        return readl_relaxed(reg);
 }
@@ -69,7 +83,7 @@ static void jh7110_clk_reg_rmw(struct jh7110_clk *clk, u32 mask, u32 value)
                || clk->idx == JH7110_UART5_CLK_CORE)
                && (value != JH7110_CLK_ENABLE))
                value  <<= 8;
-       value |= readl_relaxed(reg) & ~mask;
+       value |= jh7110_clk_reg_get(clk) & ~mask;
        writel_relaxed(value, reg);
        spin_unlock_irqrestore(&priv->rmw_lock, flags);
 }
old mode 100755 (executable)
new mode 100644 (file)
index a8fc3c5..b30cc76
 #define JH7110_ISP_TOP_CLK_BIST_APB_CLKGEN     (JH7110_CLK_ISP_END + 2)
 #define JH7110_ISP_TOP_CLK_DVP_CLKGEN          (JH7110_CLK_ISP_END + 3)
 
+struct isp_init_crg {
+       int num_clks;
+       struct clk_bulk_data *clks;
+       struct reset_control *rsts;
+};
+
 static const struct jh7110_clk_data jh7110_clk_isp_data[] __initconst = {
        //syscon
        JH7110__DIV(JH7110_DOM4_APB_FUNC, "dom4_apb_func",
@@ -72,7 +78,92 @@ static const struct jh7110_clk_data jh7110_clk_isp_data[] __initconst = {
 static struct clk_bulk_data isp_top_clks[] = {
        { .id = "u0_dom_isp_top_clk_dom_isp_top_clk_ispcore_2x" },
        { .id = "u0_dom_isp_top_clk_dom_isp_top_clk_isp_axi" },
-       { .id = "u0_sft7110_noc_bus_clk_isp_axi" },
+};
+
+static int jh7110_isp_crg_get(struct device *dev, struct isp_init_crg *crg)
+{
+       int ret;
+
+       crg->rsts = devm_reset_control_array_get_shared(dev);
+       if (IS_ERR(crg->rsts)) {
+               dev_err(dev, "rst get failed\n");
+               return PTR_ERR(crg->rsts);
+       }
+
+       crg->clks = isp_top_clks;
+       crg->num_clks = ARRAY_SIZE(isp_top_clks);
+       ret = clk_bulk_get(dev, crg->num_clks, crg->clks);
+       if (ret) {
+               dev_err(dev, "clks get failed: %d\n", ret);
+               goto clks_get_failed;
+       }
+
+       return 0;
+
+clks_get_failed:
+       reset_control_assert(crg->rsts);
+       reset_control_put(crg->rsts);
+
+       return ret;
+}
+
+static int jh7110_isp_crg_enable(struct device *dev, struct isp_init_crg *crg, bool enable)
+{
+       int ret;
+
+       dev_dbg(dev, "starfive jh7110 isp clk&rst %sable\n", enable ? "en":"dis");
+       if (enable) {
+               ret = reset_control_deassert(crg->rsts);
+               if (ret) {
+                       dev_err(dev, "rst deassert failed: %d\n", ret);
+                       goto crg_failed;
+               }
+
+               ret = clk_bulk_prepare_enable(crg->num_clks, crg->clks);
+               if (ret) {
+                       dev_err(dev, "clks enable failed: %d\n", ret);
+                       goto crg_failed;
+               }
+       } else {
+               clk_bulk_disable_unprepare(crg->num_clks, crg->clks);
+       }
+
+       return 0;
+crg_failed:
+       return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int clk_isp_system_suspend(struct device *dev)
+{
+       return pm_runtime_force_suspend(dev);
+}
+
+static int clk_isp_system_resume(struct device *dev)
+{
+       return pm_runtime_force_resume(dev);
+}
+#endif
+
+#ifdef CONFIG_PM
+static int clk_isp_runtime_suspend(struct device *dev)
+{
+       struct isp_init_crg *crg = dev_get_drvdata(dev);
+
+       return jh7110_isp_crg_enable(dev, crg, false);
+}
+
+static int clk_isp_runtime_resume(struct device *dev)
+{
+       struct isp_init_crg *crg = dev_get_drvdata(dev);
+
+       return jh7110_isp_crg_enable(dev, crg, true);
+}
+#endif
+
+static const struct dev_pm_ops clk_isp_pm_ops = {
+       SET_RUNTIME_PM_OPS(clk_isp_runtime_suspend, clk_isp_runtime_resume, NULL)
+       SET_LATE_SYSTEM_SLEEP_PM_OPS(clk_isp_system_suspend, clk_isp_system_resume)
 };
 
 static struct clk_hw *jh7110_isp_clk_get(struct of_phandle_args *clkspec,
@@ -93,9 +184,8 @@ static struct clk_hw *jh7110_isp_clk_get(struct of_phandle_args *clkspec,
 static int __init clk_starfive_jh7110_isp_probe(struct platform_device *pdev)
 {
        struct jh7110_clk_priv *priv;
+       struct isp_init_crg *crg;
        unsigned int idx;
-       struct reset_control *rsts;
-       int num_clks;
        int ret = 0;
 
        priv = devm_kzalloc(&pdev->dev, struct_size(priv, reg,
@@ -109,36 +199,22 @@ static int __init clk_starfive_jh7110_isp_probe(struct platform_device *pdev)
        if (IS_ERR(priv->isp_base))
                return PTR_ERR(priv->isp_base);
 
+       crg = devm_kzalloc(&pdev->dev, sizeof(*crg), GFP_KERNEL);
+       if (!crg)
+               return -ENOMEM;
+       dev_set_drvdata(&pdev->dev, crg);
+
+       ret = jh7110_isp_crg_get(&pdev->dev, crg);
+       if (ret)
+               goto init_failed;
+
+       pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
        pm_runtime_enable(&pdev->dev);
        ret = pm_runtime_get_sync(&pdev->dev);
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to get pm runtime: %d\n", ret);
-               return ret;
-       }
-
-       rsts = devm_reset_control_array_get_shared(priv->dev);
-       if (!IS_ERR(rsts)) {
-               ret = reset_control_deassert(rsts);
-               if (ret) {
-                       dev_err(priv->dev, "rst deassert failed: %d\n", ret);
-                       goto rsts_deassert_failed;
-               }
-       } else {
-               dev_err(priv->dev, "rst get failed\n");
-               return PTR_ERR(rsts);
-       }
-
-       num_clks = ARRAY_SIZE(isp_top_clks);
-       ret = clk_bulk_get(priv->dev, num_clks, isp_top_clks);
-       if (!ret) {
-               ret = clk_bulk_prepare_enable(num_clks, isp_top_clks);
-               if (ret) {
-                       dev_err(priv->dev, "clks enable failed: %d\n", ret);
-                       goto clks_enable_failed;
-               }
-       } else {
-               dev_err(priv->dev, "clks get failed: %d\n", ret);
-               goto clks_get_failed;
+               goto init_failed;
        }
 
        priv->pll[PLL_OFI(JH7110_U3_PCLK_MUX_FUNC_PCLK)] =
@@ -247,28 +323,20 @@ static int __init clk_starfive_jh7110_isp_probe(struct platform_device *pdev)
 
                ret = devm_clk_hw_register(priv->dev, &clk->hw);
                if (ret)
-                       return ret;
+                       goto init_failed;
        }
 
        ret = devm_of_clk_add_hw_provider(priv->dev, jh7110_isp_clk_get, priv);
        if (ret)
-               return ret;
+               goto init_failed;
 
-       clk_bulk_put(num_clks, isp_top_clks);
-       reset_control_put(rsts);
+       pm_runtime_put_sync(&pdev->dev);
 
        dev_info(&pdev->dev, "starfive JH7110 clk_isp init successfully.");
        return 0;
 
-clks_enable_failed:
-       clk_bulk_put(num_clks, isp_top_clks);
-clks_get_failed:
-       reset_control_assert(rsts);
-rsts_deassert_failed:
-       reset_control_put(rsts);
-
+init_failed:
        return ret;
-
 }
 
 static const struct of_device_id clk_starfive_jh7110_isp_match[] = {
@@ -281,6 +349,7 @@ static struct platform_driver clk_starfive_jh7110_isp_driver = {
                .driver = {
                .name = "clk-starfive-jh7110-isp",
                .of_match_table = clk_starfive_jh7110_isp_match,
+               .pm     = &clk_isp_pm_ops,
        },
 };
 module_platform_driver(clk_starfive_jh7110_isp_driver);
old mode 100755 (executable)
new mode 100644 (file)
index 73051bb..cc19ec6
@@ -138,7 +138,7 @@ static const struct jh7110_clk_data jh7110_clk_sys_data[] __initconst = {
                        GATE_FLAG_NORMAL, JH7110_ISP_AXI),
        JH7110_GATE(JH7110_NOC_BUS_CLK_ISP_AXI,
                        "u0_sft7110_noc_bus_clk_isp_axi",
-                       CLK_IGNORE_UNUSED, JH7110_ISP_AXI),
+                       CLK_IS_CRITICAL, JH7110_ISP_AXI),
        //HIFI4
        JH7110__DIV(JH7110_HIFI4_CORE, "hifi4_core", 15, JH7110_BUS_ROOT),
        JH7110__DIV(JH7110_HIFI4_AXI, "hifi4_axi", 2, JH7110_HIFI4_CORE),
index b7bf203..54c2539 100644 (file)
@@ -19,8 +19,6 @@
 struct starfive_cpu_dvfs_info {
        struct regulator *vddcpu;
        struct clk *cpu_clk;
-       struct clk *pll0_clk;
-       struct clk *osc_clk;
        unsigned long regulator_latency;
        struct device *cpu_dev;
        struct cpumask cpus;
@@ -62,16 +60,11 @@ static int starfive_cpufreq_set_target_index(struct cpufreq_policy *policy,
                }
        }
 
-       if (clk_set_parent(policy->clk, info->osc_clk))
-               pr_err("cpu set parent osc failed\n");
-
-       ret = clk_set_rate(info->pll0_clk, new_freq);
+       ret = clk_set_rate(info->cpu_clk, new_freq);
        if (ret < 0) {
                pr_err("Failed to set rate %ldkHz: %d\n",
                       new_freq, ret);
        }
-       if (clk_set_parent(policy->clk, info->pll0_clk))
-               pr_err("cpu set parent pll0 failed\n");
 
        if (info->vddcpu && new_freq < old_freq) {
                ret = regulator_set_voltage(info->vddcpu,
@@ -120,12 +113,12 @@ static int starfive_cpu_dvfs_info_init(struct platform_device *pdev,
        int ret;
        static int retry = 3;
 
-       info->vddcpu = regulator_get_optional(&pdev->dev, "cpu_vdd_0p9");
+       info->vddcpu = regulator_get_optional(&pdev->dev, "cpu_vdd");
        if (IS_ERR(info->vddcpu)) {
                if (PTR_ERR(info->vddcpu) == -EPROBE_DEFER)
                        dev_warn(&pdev->dev, "The cpu regulator is not ready, retry.\n");
                else
-                       dev_err(&pdev->dev, "Failed to get regulator for cpu\n");
+                       dev_err(&pdev->dev, "Failed to get regulator for cpu!\n");
                if (retry-- > 0)
                        return -EPROBE_DEFER;
                else
@@ -138,19 +131,6 @@ static int starfive_cpu_dvfs_info_init(struct platform_device *pdev,
                           PTR_ERR(info->cpu_clk));
                return PTR_ERR(info->cpu_clk);
        }
-       info->pll0_clk = devm_clk_get(dev, "pll0");
-       if (IS_ERR(info->pll0_clk)) {
-               dev_err(&pdev->dev, "Unable to obtain cpu_clk: %ld\n",
-                          PTR_ERR(info->pll0_clk));
-               return PTR_ERR(info->pll0_clk);
-       }
-
-       info->osc_clk = devm_clk_get(dev, "osc");
-       if (IS_ERR(info->osc_clk)) {
-               dev_err(&pdev->dev, "Unable to obtain osc_clk: %ld\n",
-                          PTR_ERR(info->osc_clk));
-               return PTR_ERR(info->osc_clk);
-       }
 
        info->cpu_dev = get_cpu_device(1);
        if (!info->cpu_dev) {
@@ -224,7 +204,7 @@ static int __init starfive_cpufreq_init(void)
 {
        return platform_driver_register(&starfive_cpufreq_plat_driver);
 }
-postcore_initcall(starfive_cpufreq_init);
+device_initcall(starfive_cpufreq_init);
 
 MODULE_DESCRIPTION("STARFIVE CPUFREQ Driver");
 MODULE_AUTHOR("Mason Huuo <mason.huo@starfivetech.com>");
index 936152b..478970f 100644 (file)
@@ -195,7 +195,7 @@ static void sbi_idle_init_cpuhp(void)
 }
 
 static const struct of_device_id sbi_cpuidle_state_match[] = {
-       { .compatible = "starfive,jh7110-idle-state",
+       { .compatible = "riscv,idle-state",
          .data = sbi_cpuidle_enter_state },
        { },
 };
@@ -413,7 +413,7 @@ static int sbi_pd_init(struct device_node *np)
        struct generic_pm_domain *pd;
        struct sbi_pd_provider *pd_provider;
        struct dev_power_governor *pd_gov;
-       int ret = -ENOMEM, state_count = 0;
+       int ret = -ENOMEM;
 
        pd = dt_idle_pd_alloc(np, sbi_dt_parse_state_node);
        if (!pd)
@@ -432,7 +432,7 @@ static int sbi_pd_init(struct device_node *np)
                pd->flags |= GENPD_FLAG_ALWAYS_ON;
 
        /* Use governor for CPU PM domains if it has some states to manage. */
-       pd_gov = state_count > 0 ? &pm_domain_cpu_gov : NULL;
+       pd_gov = pd->states ? &pm_domain_cpu_gov : NULL;
 
        ret = pm_genpd_init(pd, pd_gov, false);
        if (ret)
index b609174..84174ec 100755 (executable)
@@ -480,6 +480,8 @@ static int jh7110_cryp_hw_init(struct jh7110_sec_ctx *ctx)
        int ret;
        u32 hw_mode;
 
+       pm_runtime_resume_and_get(ctx->sdev->dev);
+
        jh7110_aes_reset(ctx);
 
        hw_mode = get_aes_mode(ctx->rctx);
@@ -642,6 +644,9 @@ static void jh7110_cryp_finish_req(struct jh7110_sec_ctx *ctx, int err)
                free_pages((unsigned long)buf_out, pages);
        }
 
+       pm_runtime_mark_last_busy(ctx->sdev->dev);
+       pm_runtime_put_autosuspend(ctx->sdev->dev);
+
        if (is_gcm(rctx) || is_ccm(rctx))
                crypto_finalize_aead_request(ctx->sdev->engine, rctx->req.areq, err);
        else
index afefd27..aa6e54f 100755 (executable)
@@ -223,6 +223,13 @@ static int jh7110_cryp_probe(struct platform_device *pdev)
                return PTR_ERR(sdev->sec_ahb);
        }
 
+       pm_runtime_set_autosuspend_delay(dev, 50);
+       pm_runtime_use_autosuspend(dev);
+
+       pm_runtime_get_noresume(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+
        sdev->rst_hresetn = devm_reset_control_get_shared(sdev->dev, "sec_hre");
        if (IS_ERR(sdev->rst_hresetn)) {
                dev_err(sdev->dev, "failed to get sec reset\n");
@@ -295,6 +302,8 @@ static int jh7110_cryp_probe(struct platform_device *pdev)
 
        dev_info(dev, "Initialized\n");
 
+       pm_runtime_put_sync(dev);
+
        return 0;
  err_algs_pka:
        jh7110_aes_unregister_algs();
@@ -323,10 +332,15 @@ static int jh7110_cryp_probe(struct platform_device *pdev)
 static int jh7110_cryp_remove(struct platform_device *pdev)
 {
        struct jh7110_sec_dev *sdev = platform_get_drvdata(pdev);
+       int ret;
 
        if (!sdev)
                return -ENODEV;
 
+       ret = pm_runtime_resume_and_get(sdev->dev);
+       if (ret < 0)
+               return ret;
+
        jh7110_pka_unregister_algs();
        jh7110_aes_unregister_algs();
        jh7110_hash_unregister_algs();
@@ -347,8 +361,12 @@ static int jh7110_cryp_remove(struct platform_device *pdev)
        list_del(&sdev->list);
        spin_unlock(&dev_list.lock);
 
+       pm_runtime_disable(sdev->dev);
+       pm_runtime_put_noidle(sdev->dev);
+
        clk_disable_unprepare(sdev->sec_hclk);
        clk_disable_unprepare(sdev->sec_ahb);
+       reset_control_assert(sdev->rst_hresetn);
 
        return 0;
 }
@@ -392,6 +410,8 @@ static const struct dev_pm_ops jh7110_cryp_pm_ops = {
                           jh7110_cryp_runtime_resume, NULL)
 };
 
+
+
 static struct platform_driver jh7110_cryp_driver = {
        .probe  = jh7110_cryp_probe,
        .remove = jh7110_cryp_remove,
index dc4422c..6f678fe 100644 (file)
@@ -659,6 +659,8 @@ static int jh7110_hash_cra_init_algs(struct crypto_tfm *tfm,
        if (algs_hmac_name)
                ctx->sha_mode |= JH7110_SHA_HMAC_FLAGS;
 
+       pm_runtime_resume_and_get(ctx->sdev->dev);
+
        ctx->enginectx.op.do_one_request = jh7110_hash_one_request;
        ctx->enginectx.op.prepare_request = jh7110_hash_prepare_req;
        ctx->enginectx.op.unprepare_request = NULL;
@@ -672,6 +674,8 @@ static void jh7110_hash_cra_exit(struct crypto_tfm *tfm)
 
        crypto_free_shash(ctx->fallback.shash);
 
+       pm_runtime_put_sync_suspend(ctx->sdev->dev);
+
        ctx->fallback.shash = NULL;
        ctx->enginectx.op.do_one_request = NULL;
        ctx->enginectx.op.prepare_request = NULL;
index 5ad6695..e1c3a3a 100644 (file)
@@ -277,6 +277,7 @@ static PVRSRV_ERROR _PVRSRVDeviceIdleRequestKM(PPVRSRV_DEVICE_NODE psDeviceNode,
        }
        else
        {
+               PVRSRVSetSystemPowerState(psDeviceNode->psDevConfig, PVRSRV_SYS_POWER_STATE_ON);
                return PVRSRV_OK;
        }
 
index ca92eff..dd572a5 100644 (file)
@@ -4863,7 +4863,6 @@ PVRSRV_ERROR RGXRegisterDevice(PVRSRV_DEVICE_NODE *psDeviceNode)
                psDeviceNode->pfnFwMMUInit = RGXMipsMMUInit_Register;
        }
 
-       PVRSRVSetSystemPowerState(psDeviceNode->psDevConfig, PVRSRV_SYS_POWER_STATE_ON);
        /* The device shared-virtual-memory heap address-space size is stored here for faster
           look-up without having to walk the device heap configuration structures during
           client device connection  (i.e. this size is relative to a zero-based offset) */
index 62aa58e..f7a956d 100644 (file)
@@ -79,6 +79,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include "srvinit.h"
 
 #include "pvr_ion_stats.h"
+#include "sysconfig.h"
 
 #if defined(SUPPORT_DISPLAY_CLASS)
 /* Display class interface */
@@ -445,6 +446,26 @@ int PVRSRVDeviceResume(PVRSRV_DEVICE_NODE *psDeviceNode)
        return 0;
 }
 
+int sPVRSRVDeviceSuspend(PVRSRV_DEVICE_NODE *psDeviceNode)
+{
+       struct sf7110_cfg *sft = sys_get_privdata();
+
+       if (sft->runtime_suspend != NULL)
+               sft->runtime_suspend(NULL);
+
+       return 0;
+}
+
+int sPVRSRVDeviceResume(PVRSRV_DEVICE_NODE *psDeviceNode)
+{
+       struct sf7110_cfg *sft = sys_get_privdata();
+
+       if (sft->runtime_resume != NULL)
+               sft->runtime_resume(NULL);
+
+       return 0;
+}
+
 /**************************************************************************/ /*!
 @Function     PVRSRVDeviceServicesOpen
 @Description  Services device open.
@@ -504,6 +525,7 @@ int PVRSRVDeviceServicesOpen(PVRSRV_DEVICE_NODE *psDeviceNode,
 
        if (psDeviceNode->eDevState == PVRSRV_DEVICE_STATE_INIT)
        {
+               PVRSRVSetSystemPowerState(psDeviceNode->psDevConfig, PVRSRV_SYS_POWER_STATE_ON);
                eError = PVRSRVCommonDeviceInitialise(psDeviceNode);
                if (eError != PVRSRV_OK)
                {
index 7317a0a..c7d1ebd 100644 (file)
@@ -98,4 +98,7 @@ void PVRSRVDeviceRelease(struct _PVRSRV_DEVICE_NODE_ *psDeviceNode,
 int drm_pvr_srvkm_init(struct drm_device *dev,
                        void *arg, struct drm_file *psDRMFile);
 
+int sPVRSRVDeviceSuspend(struct _PVRSRV_DEVICE_NODE_ *psDeviceNode);
+
+int sPVRSRVDeviceResume(struct _PVRSRV_DEVICE_NODE_ *psDeviceNode);
 #endif /* MODULE_COMMON_H */
index 65a8e51..2b3cd5c 100644 (file)
@@ -61,6 +61,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 #include <linux/mutex.h>
+#include <linux/pm_runtime.h>
 
 #include "module_common.h"
 #include "pvr_drm.h"
@@ -102,9 +103,29 @@ static int pvr_pm_resume(struct device *dev)
        return PVRSRVDeviceResume(priv->dev_node);
 }
 
+static int pvr_pm_runtime_suspend(struct device *dev)
+{
+       struct drm_device *ddev = dev_get_drvdata(dev);
+       struct pvr_drm_private *priv = ddev->dev_private;
+
+       sPVRSRVDeviceSuspend(priv->dev_node);
+       return 0;
+}
+
+static int pvr_pm_runtime_resume(struct device *dev)
+{
+       struct drm_device *ddev = dev_get_drvdata(dev);
+       struct pvr_drm_private *priv = ddev->dev_private;
+
+       sPVRSRVDeviceResume(priv->dev_node);
+       return 0;
+}
+
 const struct dev_pm_ops pvr_pm_ops = {
        .suspend = pvr_pm_suspend,
        .resume = pvr_pm_resume,
+       .runtime_suspend = pvr_pm_runtime_suspend,
+       .runtime_resume = pvr_pm_runtime_resume,
 };
 
 
@@ -214,6 +235,7 @@ void pvr_drm_unload(struct drm_device *ddev)
 
        PVRSRVDeviceDeinit(priv->dev_node);
 
+       pm_runtime_disable(ddev->dev);
        mutex_lock(&g_device_mutex);
        PVRSRVCommonDeviceDestroy(priv->dev_node);
        mutex_unlock(&g_device_mutex);
index af93caa..ada8ff7 100644 (file)
@@ -222,6 +222,23 @@ void SysDevHost_Cache_Maintenance(IMG_HANDLE hSysData,
 }
 #endif
 
+static IMG_UINT32 sys_gpu_runtime_resume(IMG_HANDLE hd)
+{
+       starfive_pmu_hw_event_turn_off_mask(0);
+       clk_prepare_enable(sf_cfg_t.clk_axi);
+       u0_img_gpu_enable();
+
+       return 0;
+}
+
+static IMG_UINT32 sys_gpu_runtime_suspend(IMG_HANDLE hd)
+{
+       u0_img_gpu_disable();
+       starfive_pmu_hw_event_turn_off_mask((uint32_t)-1);
+
+       return 0;
+}
+
 static int create_sf7110_cfg(struct device *dev)
 {
        struct sf7110_cfg *psf = &sf_cfg_t;
@@ -282,6 +299,9 @@ static int create_sf7110_cfg(struct device *dev)
                goto err_gpu_unmap;
        }
 
+       psf->runtime_resume = sys_gpu_runtime_resume;
+       psf->runtime_suspend = sys_gpu_runtime_suspend;
+
        return 0;
 err_gpu_unmap:
        iounmap(psf->gpu_reg_base);
@@ -312,44 +332,37 @@ void u0_img_gpu_disable(void)
        clk_disable_unprepare(sf_cfg_t.clk_sys);
 }
 
-
-
 static int sys_gpu_enable(void)
 {
        int ret;
-       
-       pm_runtime_enable(sf_cfg_t.dev);
+
        ret = pm_runtime_get_sync(sf_cfg_t.dev);
        if (ret < 0) {
                dev_err(sf_cfg_t.dev, "gpu: failed to get pm runtime: %d\n", ret);
                return ret;
        }
-       starfive_pmu_hw_event_turn_off_mask(0);
-       clk_prepare_enable(sf_cfg_t.clk_axi);
-       u0_img_gpu_enable();
+
        return 0;
 }
 
 static int sys_gpu_disable(void)
 {
-       u0_img_gpu_disable();
-       starfive_pmu_hw_event_turn_off_mask((uint32_t)-1);
        pm_runtime_put_sync(sf_cfg_t.dev);
        //pm_runtime_disable(sf_cfg_t.dev);
        return 0;
 }
 
-
-
-
 static PVRSRV_ERROR sfSysDevPrePowerState(
                IMG_HANDLE hSysData,
                PVRSRV_SYS_POWER_STATE eNewPowerState,
                PVRSRV_SYS_POWER_STATE eCurrentPowerState,
-               IMG_BOOL bForced)
+               PVRSRV_POWER_FLAGS ePwrFlags)
 {
        struct sf7110_cfg *psf = hSysData;
 
+       pr_debug("(%s()) state: current=%d, new=%d; flags: 0x%08x", __func__,
+            eCurrentPowerState, eNewPowerState, ePwrFlags);
+
        mutex_lock(&psf->set_power_state);
 
        if ((PVRSRV_SYS_POWER_STATE_OFF == eNewPowerState) &&
@@ -364,11 +377,13 @@ static PVRSRV_ERROR sfSysDevPostPowerState(
                IMG_HANDLE hSysData,
                PVRSRV_SYS_POWER_STATE eNewPowerState,
                PVRSRV_SYS_POWER_STATE eCurrentPowerState,
-               IMG_BOOL bForced)
+               PVRSRV_POWER_FLAGS ePwrFlags)
 {
        struct sf7110_cfg *psf = hSysData;
        PVRSRV_ERROR ret;
 
+       pr_debug("(%s()) state: current=%d, new=%d; flags: 0x%08x", __func__,
+            eCurrentPowerState, eNewPowerState, ePwrFlags);
 
        mutex_lock(&psf->set_power_state);
 
@@ -423,7 +438,7 @@ PVRSRV_ERROR SysDevInit(void *pvOSDevice, PVRSRV_DEVICE_CONFIG **ppsDevConfig)
         * Setup RGX specific timing data
         */
        gsRGXTimingInfo.ui32CoreClockSpeed      = RGX_STARFIVE_7100_CORE_CLOCK_SPEED;
-       gsRGXTimingInfo.bEnableActivePM         = IMG_FALSE;
+       gsRGXTimingInfo.bEnableActivePM         = IMG_TRUE;
        gsRGXTimingInfo.bEnableRDPowIsland      = IMG_TRUE;
        gsRGXTimingInfo.ui32ActivePMLatencyms   = SYS_RGX_ACTIVE_POWER_LATENCY_MS;
 
@@ -483,6 +498,7 @@ PVRSRV_ERROR SysDevInit(void *pvOSDevice, PVRSRV_DEVICE_CONFIG **ppsDevConfig)
        }
        gsDevices[0].hSysData = &sf_cfg_t;
 
+       pm_runtime_enable(sf_cfg_t.dev);
        /* power management on HW system */
        gsDevices[0].pfnPrePowerState = sfSysDevPrePowerState;
        gsDevices[0].pfnPostPowerState = sfSysDevPostPowerState;
@@ -617,6 +633,11 @@ PVRSRV_ERROR SysDebugInfo(PVRSRV_DEVICE_CONFIG *psDevConfig,
        return PVRSRV_OK;
 }
 
+struct sf7110_cfg *sys_get_privdata(void)
+{
+       return &sf_cfg_t;
+}
+
 /******************************************************************************
  End of file (sysconfig.c)
 ******************************************************************************/
index f44edb3..435f637 100644 (file)
@@ -52,6 +52,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #define STARFIVE_7110_GPU_SIZE 0x00100000
 #define STARFIVE_7110_GPU_PBASE 0x18000000
 
+typedef IMG_UINT32 (*SYS_DEV_CLK_GET)(IMG_HANDLE hData);
+
 struct sf7110_cfg {
        void __iomem *gpu_reg_base;
        resource_size_t gpu_reg_start;
@@ -72,6 +74,8 @@ struct sf7110_cfg {
        /* for gpu device freq/volt update, to be fill later */
        //struct clk **top_clk;
        struct device *dev;
+       SYS_DEV_CLK_GET runtime_resume;
+       SYS_DEV_CLK_GET runtime_suspend;
 };
 
 #define mk_crg_offset(x)  ((x) - (U0_SYS_CRG__SAIF_BD_APBS__BASE_ADDR))
@@ -86,6 +90,9 @@ struct sf7110_cfg {
 
 extern void do_sifive_l2_flush64_range(unsigned long start, unsigned long len);
 
+void u0_img_gpu_enable(void);
+void u0_img_gpu_disable(void);
+struct sf7110_cfg *sys_get_privdata(void);
 /*****************************************************************************
  * system specific data structures
  *****************************************************************************/
index acbc4ba..a5d0ac1 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/reset.h>
+#include <linux/pm_runtime.h>
 
 /*
  * TempSensor reset. The RSTN can be de-asserted once the analog core has
@@ -207,18 +208,26 @@ static int sfctemp_read(struct device *dev, enum hwmon_sensor_types type,
                        u32 attr, int channel, long *val)
 {
        struct sfctemp *sfctemp = dev_get_drvdata(dev);
+       int ret;
+
+       ret = pm_runtime_get_sync(dev);
 
        switch (type) {
        case hwmon_temp:
                switch (attr) {
                case hwmon_temp_enable:
                        *val = sfctemp->enabled;
+                       pm_runtime_put(dev);
                        return 0;
                case hwmon_temp_input:
-                       return sfctemp_convert(sfctemp, val);
+                       ret = sfctemp_convert(sfctemp, val);
+                       pm_runtime_put(dev);
+                       return ret;
                }
+               pm_runtime_put(dev);
                return -EINVAL;
        default:
+               pm_runtime_put(dev);
                return -EINVAL;
        }
 }
@@ -326,9 +335,41 @@ static int sfctemp_probe(struct platform_device *pdev)
 
        hwmon_dev = devm_hwmon_device_register_with_info(dev, pdev->name, sfctemp,
                                                         &sfctemp_chip_info, NULL);
+
+       pm_runtime_enable(hwmon_dev);
+       pm_runtime_enable(dev);
+
+       sfctemp_disable(sfctemp);
+
        return PTR_ERR_OR_ZERO(hwmon_dev);
 }
 
+#ifdef CONFIG_PM
+
+static int starfive_temp_suspend(struct device *dev)
+{
+       struct sfctemp *sfctemp = dev_get_drvdata(dev);
+
+       dev_dbg(dev, "starfive temp runtime suspend");
+
+       return sfctemp_disable(sfctemp);
+}
+
+static int starfive_temp_resume(struct device *dev)
+{
+       struct sfctemp *sfctemp = dev_get_drvdata(dev);
+
+       dev_dbg(dev, "starfive temp runtime resume");
+
+       return sfctemp_enable(sfctemp);
+}
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops sfctemp_dev_pm_ops = {
+       SET_RUNTIME_PM_OPS(starfive_temp_suspend, starfive_temp_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+};
+
 static const struct of_device_id sfctemp_of_match[] = {
        { .compatible = "starfive,jh7100-temp" },
        { .compatible = "starfive,jh7110-temp" },
@@ -341,6 +382,7 @@ static struct platform_driver sfctemp_driver = {
        .driver = {
                .name = "sfctemp",
                .of_match_table = sfctemp_of_match,
+               .pm   = &sfctemp_dev_pm_ops,
        },
 };
 module_platform_driver(sfctemp_driver);
index 50de0bd..aa53d32 100755 (executable)
@@ -366,7 +366,6 @@ static void dw_i2c_plat_complete(struct device *dev)
 #endif
 
 #ifdef CONFIG_PM
-/*
 static int dw_i2c_plat_suspend(struct device *dev)
 {
        struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
@@ -401,10 +400,8 @@ static const struct dev_pm_ops dw_i2c_dev_pm_ops = {
        SET_LATE_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume)
        SET_RUNTIME_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume, NULL)
 };
-*/
 
-//#define DW_I2C_DEV_PMOPS (&dw_i2c_dev_pm_ops)
-#define DW_I2C_DEV_PMOPS NULL
+#define DW_I2C_DEV_PMOPS (&dw_i2c_dev_pm_ops)
 #else
 #define DW_I2C_DEV_PMOPS NULL
 #endif
@@ -427,7 +424,7 @@ static int __init dw_i2c_init_driver(void)
 {
        return platform_driver_register(&dw_i2c_driver);
 }
-subsys_initcall(dw_i2c_init_driver);
+device_initcall(dw_i2c_init_driver);
 
 static void __exit dw_i2c_exit_driver(void)
 {
index d8081c4..c73ed9c 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/reset.h>
+#include <linux/pm_runtime.h>
 
 #include "mailbox.h"
 
@@ -144,8 +145,14 @@ static int starfive_mbox_check_state(struct mbox_chan *chan)
 {
        unsigned long ch = (unsigned long)chan->con_priv;
        struct starfive_mbox *mbox = to_starfive_mbox(chan->mbox);
+       unsigned long irq_flag = IRQF_SHARED;
        long ret = 0;
 
+       pm_runtime_get_sync(mbox->dev);
+       /* MAILBOX should be with IRQF_NO_SUSPEND set */
+       if (!mbox->dev->pm_domain)
+               irq_flag |= IRQF_NO_SUSPEND;
+
        /* Mailbox is idle so directly bail out */
        if (readl(mbox->base + MBC_PEND_SMRY) & BIT(ch))
                return -EBUSY;
@@ -153,7 +160,7 @@ static int starfive_mbox_check_state(struct mbox_chan *chan)
        if (mbox->mchan[ch].dst_irq > 0) {
                dev_dbg(mbox->dev, "%s: host IRQ = %d, ch:%ld", __func__, mbox->mchan[ch].dst_irq, ch);
                ret = devm_request_irq(mbox->dev, mbox->mchan[ch].dst_irq, starfive_rx_irq_handler,
-                       IRQF_SHARED, irq_peer_name[ch].name, chan);
+                       irq_flag, irq_peer_name[ch].name, chan);
                if (ret < 0)
                        dev_err(mbox->dev, "request_irq %d failed\n", mbox->mchan[ch].dst_irq);
        }
@@ -177,6 +184,7 @@ static void starfive_mbox_shutdown(struct mbox_chan *chan)
 
        if (mbox->mchan[ch].dst_irq > 0)
                devm_free_irq(mbox->dev, mbox->mchan[ch].dst_irq, chan);
+       pm_runtime_put_sync(mbox->dev);
 }
 
 static int starfive_mbox_send_data(struct mbox_chan *chan, void *msg)
@@ -280,6 +288,9 @@ static int starfive_mbox_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, mbox);
        dev_info(dev, "Mailbox enabled\n");
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+
        return 0;
 }
 
@@ -289,16 +300,44 @@ static int starfive_mbox_remove(struct platform_device *pdev)
 
        mbox_controller_unregister(&mbox->controller);
        devm_clk_put(mbox->dev, mbox->clk);
+       pm_runtime_disable(mbox->dev);
+
+       return 0;
+}
+
+static int __maybe_unused starfive_mbox_suspend(struct device *dev)
+{
+       struct starfive_mbox *mbox = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(mbox->clk);
 
        return 0;
 }
 
+static int __maybe_unused starfive_mbox_resume(struct device *dev)
+{
+       struct starfive_mbox *mbox = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(mbox->clk);
+       if (ret)
+               dev_err(dev, "failed to enable clock\n");
+
+       return ret;
+}
+
+static const struct dev_pm_ops starfive_mbox_pm_ops = {
+       .suspend = starfive_mbox_suspend,
+       .resume = starfive_mbox_resume,
+       SET_RUNTIME_PM_OPS(starfive_mbox_suspend, starfive_mbox_resume, NULL)
+};
 static struct platform_driver starfive_mbox_driver = {
        .probe  = starfive_mbox_probe,
        .remove = starfive_mbox_remove,
        .driver = {
        .name = "mailbox",
                .of_match_table = starfive_mbox_of_match,
+               .pm = &starfive_mbox_pm_ops,
        },
 };
 
index 5ce43f9..9bc20d1 100644 (file)
@@ -1086,37 +1086,31 @@ static int imx219_start_streaming(struct imx219 *imx219)
        const struct imx219_reg_list *reg_list;
        int ret;
 
-       ret = pm_runtime_get_sync(&client->dev);
-       if (ret < 0) {
-               pm_runtime_put_noidle(&client->dev);
-               return ret;
-       }
-
        /* Apply default values of current mode */
        reg_list = &imx219->mode->reg_list;
        ret = imx219_write_regs(imx219, reg_list->regs, reg_list->num_of_regs);
        if (ret) {
                dev_err(&client->dev, "%s failed to set mode\n", __func__);
-               goto err_rpm_put;
+               goto err;
        }
 
        ret = imx219_set_framefmt(imx219);
        if (ret) {
                dev_err(&client->dev, "%s failed to set frame format: %d\n",
                        __func__, ret);
-               goto err_rpm_put;
+               goto err;
        }
 
        /* Apply customized values from user */
        ret =  __v4l2_ctrl_handler_setup(imx219->sd.ctrl_handler);
        if (ret)
-               goto err_rpm_put;
+               goto err;
 
        /* set stream on register */
        ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
                               IMX219_REG_VALUE_08BIT, IMX219_MODE_STREAMING);
        if (ret)
-               goto err_rpm_put;
+               goto err;
 
        /* vflip and hflip cannot change during streaming */
        __v4l2_ctrl_grab(imx219->vflip, true);
@@ -1124,8 +1118,7 @@ static int imx219_start_streaming(struct imx219 *imx219)
 
        return 0;
 
-err_rpm_put:
-       pm_runtime_put(&client->dev);
+err:
        return ret;
 }
 
@@ -1142,13 +1135,12 @@ static void imx219_stop_streaming(struct imx219 *imx219)
 
        __v4l2_ctrl_grab(imx219->vflip, false);
        __v4l2_ctrl_grab(imx219->hflip, false);
-
-       pm_runtime_put(&client->dev);
 }
 
 static int imx219_set_stream(struct v4l2_subdev *sd, int enable)
 {
        struct imx219 *imx219 = to_imx219(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        int ret = 0;
 
        mutex_lock(&imx219->mutex);
@@ -1156,6 +1148,12 @@ static int imx219_set_stream(struct v4l2_subdev *sd, int enable)
                goto unlock;
 
        if (enable) {
+               ret = pm_runtime_get_sync(&client->dev);
+               if (ret < 0) {
+                       pm_runtime_put_noidle(&client->dev);
+                       return ret;
+               }
+
                /*
                 * Apply default & customized values
                 * and then start streaming.
@@ -1165,6 +1163,7 @@ static int imx219_set_stream(struct v4l2_subdev *sd, int enable)
                        goto err_unlock;
        } else {
                imx219_stop_streaming(imx219);
+               pm_runtime_put(&client->dev);
        }
 
 unlock:
@@ -1176,6 +1175,7 @@ unlock:
        return ret;
 
 err_unlock:
+       pm_runtime_put(&client->dev);
        mutex_unlock(&imx219->mutex);
 
        return ret;
@@ -1244,38 +1244,6 @@ static int imx219_power_off(struct device *dev)
        return 0;
 }
 
-static int __maybe_unused imx219_suspend(struct device *dev)
-{
-       struct v4l2_subdev *sd = dev_get_drvdata(dev);
-       struct imx219 *imx219 = to_imx219(sd);
-
-       if (imx219->streaming)
-               imx219_stop_streaming(imx219);
-
-       return 0;
-}
-
-static int __maybe_unused imx219_resume(struct device *dev)
-{
-       struct v4l2_subdev *sd = dev_get_drvdata(dev);
-       struct imx219 *imx219 = to_imx219(sd);
-       int ret;
-
-       if (imx219->streaming) {
-               ret = imx219_start_streaming(imx219);
-               if (ret)
-                       goto error;
-       }
-
-       return 0;
-
-error:
-       imx219_stop_streaming(imx219);
-       imx219->streaming = false;
-
-       return ret;
-}
-
 static int imx219_get_regulators(struct imx219 *imx219)
 {
        struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
@@ -1655,7 +1623,6 @@ static const struct of_device_id imx219_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, imx219_dt_ids);
 
 static const struct dev_pm_ops imx219_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(imx219_suspend, imx219_resume)
        SET_RUNTIME_PM_OPS(imx219_power_off, imx219_power_on, NULL)
 };
 
index 211c24c..aaaff98 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 #include <linux/of_device.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include "stfcamss.h"
 
 
-#define OV4689_LANES    2
+#define OV4689_LANES    4
 
 #define OV4689_LINK_FREQ_500MHZ         500000000LL
 
 /* min/typical/max system clock (xclk) frequencies */
 #define OV4689_XCLK_MIN  6000000
-#define OV4689_XCLK_MAX 54000000
+#define OV4689_XCLK_MAX 64000000
 
 #define OV4689_CHIP_ID (0x4688)
 
@@ -59,7 +60,7 @@
 
 #define OV4689_REG_AWB_R_GAIN           0x500C
 #define OV4689_REG_AWB_B_GAIN           0x5010
-
+#define OV4689_REG_STREAM_ON            0x0100
 
 enum ov4689_mode_id {
        //OV4689_MODE_720P_1280_720 = 0,
@@ -175,8 +176,6 @@ struct ov4689_dev {
        /* lock to protect all members below */
        struct mutex lock;
 
-       int power_count;
-
        struct v4l2_mbus_framefmt fmt;
 
        const struct ov4689_mode_info *current_mode;
@@ -186,9 +185,6 @@ struct ov4689_dev {
 
        struct ov4689_ctrls ctrls;
 
-       u32 prev_sysclk, prev_hts;
-       u32 ae_low, ae_high, ae_target;
-
        bool pending_mode_change;
        int streaming;
 };
@@ -1770,11 +1766,6 @@ static int ov4689_set_gain(struct ov4689_dev *sensor, int gain)
        return 0;
 }
 
-static int ov4689_set_stream_mipi(struct ov4689_dev *sensor, bool on)
-{
-       return 0;
-}
-
 #ifdef UNUSED_CODE
 static int ov4689_get_sysclk(struct ov4689_dev *sensor)
 {
@@ -1970,8 +1961,6 @@ static u64 ov4689_calc_pixel_rate(struct ov4689_dev *sensor)
 #define OV4689_PLL2_DIVS            0x030e  // bits[2:0]
 #define OV4689_PLL2_DIVDAC          0x0312  // bits[3:0]
 
-#define OV4689_TIMING_HTS           0x380c
-
 static int ov4689_set_mipi_pclk(struct ov4689_dev *sensor,
                                unsigned long rate)
 {
@@ -1984,17 +1973,17 @@ static int ov4689_set_mipi_pclk(struct ov4689_dev *sensor,
 
        htot = mode->htot * ov4689_framerates[mode->max_fps] / fps;
 
-       ret = ov4689_write_reg16(sensor, OV4689_TIMING_HTS, htot);
+       ret = ov4689_write_reg16(sensor, OV4689_REG_TIMING_HTS, htot);
 
-       ret = ov4689_read_reg(sensor, OV4689_TIMING_HTS, &val);
+       ret = ov4689_read_reg(sensor, OV4689_REG_TIMING_HTS, &val);
        val16 = val << 8;
-       ret = ov4689_read_reg(sensor, OV4689_TIMING_HTS + 1, &val);
+       ret = ov4689_read_reg(sensor, OV4689_REG_TIMING_HTS + 1, &val);
        val16 |= val;
 
        st_info(ST_SENSOR, "fps = %d, max_fps = %d\n", fps, mode->max_fps);
        st_info(ST_SENSOR, "mode->htot = 0x%x, htot = 0x%x\n", mode->htot,
                        htot);
-       st_info(ST_SENSOR, "reg: 0x%x = 0x%x\n", OV4689_TIMING_HTS, val16);
+       st_info(ST_SENSOR, "reg: 0x%x = 0x%x\n", OV4689_REG_TIMING_HTS, val16);
 
        return 0;
 }
@@ -2016,7 +2005,6 @@ static int ov4689_set_mode_direct(struct ov4689_dev *sensor,
 static int ov4689_set_mode(struct ov4689_dev *sensor)
 {
        const struct ov4689_mode_info *mode = sensor->current_mode;
-       //const struct ov4689_mode_info *orig_mode = sensor->last_mode;
 
        int ret = 0;
 
@@ -2024,12 +2012,7 @@ static int ov4689_set_mode(struct ov4689_dev *sensor)
        if (ret < 0)
                return ret;
 
-       /*
-        * we support have 10 bits raw RGB(mipi)
-        */
-       if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
-               ret = ov4689_set_mipi_pclk(sensor, 0);
-
+       ret = ov4689_set_mipi_pclk(sensor, 0);
        if (ret < 0)
                return 0;
 
@@ -2077,9 +2060,11 @@ static void ov4689_reset(struct ov4689_dev *sensor)
        usleep_range(1000, 2000);
 }
 
-static int ov4689_set_power_on(struct ov4689_dev *sensor)
+static int ov4689_set_power_on(struct device *dev)
 {
-       struct i2c_client *client = sensor->i2c_client;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct ov4689_dev *sensor = to_ov4689_dev(sd);
        int ret;
 
        ret = clk_prepare_enable(sensor->xclk);
@@ -2107,95 +2092,17 @@ xclk_off:
        return ret;
 }
 
-static void ov4689_set_power_off(struct ov4689_dev *sensor)
+static int ov4689_set_power_off(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct ov4689_dev *sensor = to_ov4689_dev(sd);
+
        ov4689_power(sensor, false);
        regulator_bulk_disable(OV4689_NUM_SUPPLIES, sensor->supplies);
        clk_disable_unprepare(sensor->xclk);
-}
-
-static int ov4689_set_power_mipi(struct ov4689_dev *sensor, bool on)
-{
-       return 0;
-}
-
-static int ov4689_set_power(struct ov4689_dev *sensor, bool on)
-{
-       int ret = 0;
-       u16 chip_id;
-
-       if (on) {
-               ret = ov4689_set_power_on(sensor);
-               if (ret)
-                       return ret;
-
-               ret = ov4689_read_reg16(sensor, OV4689_REG_CHIP_ID, &chip_id);
-               if (ret) {
-                       dev_err(&sensor->i2c_client->dev, "%s: failed to read chip identifier\n",
-                               __func__);
-                       ret = -ENODEV;
-                       goto power_off;
-               }
-
-               if (chip_id != OV4689_CHIP_ID) {
-                       dev_err(&sensor->i2c_client->dev,
-                                       "%s: wrong chip identifier, expected 0x%x, got 0x%x\n",
-                                       __func__, OV4689_CHIP_ID, chip_id);
-                       ret = -ENXIO;
-                       goto power_off;
-               }
-               dev_err(&sensor->i2c_client->dev, "%s: chip identifier, got 0x%x\n",
-                       __func__, chip_id);
-
-               ret = ov4689_restore_mode(sensor);
-               if (ret)
-                       goto power_off;
-       }
-
-       if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
-               ret = ov4689_set_power_mipi(sensor, on);
-       if (ret)
-               goto power_off;
-
-       if (!on)
-               ov4689_set_power_off(sensor);
 
        return 0;
-
-power_off:
-       ov4689_set_power_off(sensor);
-       return ret;
-}
-
-static int ov4689_s_power(struct v4l2_subdev *sd, int on)
-{
-       struct ov4689_dev *sensor = to_ov4689_dev(sd);
-       int ret = 0;
-
-       mutex_lock(&sensor->lock);
-
-       /*
-        * If the power count is modified from 0 to != 0 or from != 0 to 0,
-        * update the power state.
-        */
-       if (sensor->power_count == !on) {
-               ret = ov4689_set_power(sensor, !!on);
-               if (ret)
-                       goto out;
-       }
-
-       /* Update the power count. */
-       sensor->power_count += on ? 1 : -1;
-       WARN_ON(sensor->power_count < 0);
-out:
-       mutex_unlock(&sensor->lock);
-
-       if (on && !ret && sensor->power_count == 1) {
-               /* restore controls */
-               ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
-       }
-
-       return ret;
 }
 
 static int ov4689_try_frame_interval(struct ov4689_dev *sensor,
@@ -2502,12 +2409,17 @@ static int ov4689_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 
        /* v4l2_ctrl_lock() locks our own mutex */
 
+       if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev))
+               return 0;
+
        switch (ctrl->id) {
        case V4L2_CID_ANALOGUE_GAIN:
                val = ov4689_get_gain(sensor);
                break;
        }
 
+       pm_runtime_put(&sensor->i2c_client->dev);
+
        return 0;
 }
 
@@ -2522,9 +2434,9 @@ static int ov4689_s_ctrl(struct v4l2_ctrl *ctrl)
        /*
         * If the device is not powered up by the host driver do
         * not apply any controls to H/W at this time. Instead
-        * the controls will be restored right after power-up.
+        * the controls will be restored at start streaming time.
         */
-       if (sensor->power_count == 0)
+       if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev))
                return 0;
 
        switch (ctrl->id) {
@@ -2563,6 +2475,8 @@ static int ov4689_s_ctrl(struct v4l2_ctrl *ctrl)
                break;
        }
 
+       pm_runtime_put(&sensor->i2c_client->dev);
+
        return ret;
 }
 
@@ -2756,7 +2670,7 @@ out:
 
 static int ov4689_stream_start(struct ov4689_dev *sensor, int enable)
 {
-       return ov4689_write_reg(sensor, 0x100, enable);
+       return ov4689_write_reg(sensor, OV4689_REG_STREAM_ON, enable);
 }
 
 static int ov4689_s_stream(struct v4l2_subdev *sd, int enable)
@@ -2764,20 +2678,32 @@ static int ov4689_s_stream(struct v4l2_subdev *sd, int enable)
        struct ov4689_dev *sensor = to_ov4689_dev(sd);
        int ret = 0;
 
+       if (enable) {
+               pm_runtime_get_sync(&sensor->i2c_client->dev);
+
+               ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
+               if (ret) {
+                       pm_runtime_put_sync(&sensor->i2c_client->dev);
+                       return ret;
+               }
+       }
+
        mutex_lock(&sensor->lock);
 
        if (sensor->streaming == !enable) {
+               if (enable) {
+                       ret = ov4689_restore_mode(sensor);
+                       if (ret)
+                               goto out;
+               }
+
                if (enable && sensor->pending_mode_change) {
                        ret = ov4689_set_mode(sensor);
                        if (ret)
                                goto out;
                }
 
-               if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
-                       ret = ov4689_set_stream_mipi(sensor, enable);
-
                ret = ov4689_stream_start(sensor, enable);
-
                if (ret)
                        goto out;
        }
@@ -2785,11 +2711,14 @@ static int ov4689_s_stream(struct v4l2_subdev *sd, int enable)
        WARN_ON(sensor->streaming < 0);
 out:
        mutex_unlock(&sensor->lock);
+
+       if (!enable || ret)
+               pm_runtime_put_sync(&sensor->i2c_client->dev);
+
        return ret;
 }
 
 static const struct v4l2_subdev_core_ops ov4689_core_ops = {
-       .s_power = ov4689_s_power,
        .log_status = v4l2_ctrl_subdev_log_status,
        .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
        .unsubscribe_event = v4l2_event_subdev_unsubscribe,
@@ -2833,28 +2762,22 @@ static int ov4689_check_chip_id(struct ov4689_dev *sensor)
        int ret = 0;
        u16 chip_id;
 
-       ret = ov4689_set_power_on(sensor);
-       if (ret)
-               return ret;
-
        ret = ov4689_read_reg16(sensor, OV4689_REG_CHIP_ID, &chip_id);
        if (ret) {
                dev_err(&client->dev, "%s: failed to read chip identifier\n",
                        __func__);
-               goto power_off;
+               return ret;
        }
 
        if (chip_id != OV4689_CHIP_ID) {
                dev_err(&client->dev, "%s: wrong chip identifier, expected 0x%x,  got 0x%x\n",
                        __func__, OV4689_CHIP_ID, chip_id);
-               ret = -ENXIO;
+               return -ENXIO;
        }
        dev_err(&client->dev, "%s: chip identifier, got 0x%x\n",
                __func__, chip_id);
 
-power_off:
-       ov4689_set_power_off(sensor);
-       return ret;
+       return 0;
 }
 
 static int ov4689_probe(struct i2c_client *client)
@@ -2888,7 +2811,6 @@ static int ov4689_probe(struct i2c_client *client)
                &ov4689_mode_data[OV4689_MODE_1080P_1920_1080];
        sensor->last_mode = sensor->current_mode;
 
-       sensor->ae_target = 52;
 
        /* optional indication of physical rotation of sensor */
        ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation",
@@ -2920,9 +2842,7 @@ static int ov4689_probe(struct i2c_client *client)
                return ret;
        }
 
-       if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL &&
-               sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY &&
-               sensor->ep.bus_type != V4L2_MBUS_BT656) {
+       if (sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY) {
                dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type);
                return -EINVAL;
        }
@@ -2970,22 +2890,33 @@ static int ov4689_probe(struct i2c_client *client)
 
        mutex_init(&sensor->lock);
 
+       ret = ov4689_set_power_on(dev);
+       if (ret) {
+               dev_err(dev, "failed to power on\n");
+               goto entity_cleanup;
+       }
+
        ret = ov4689_check_chip_id(sensor);
        if (ret)
-               goto entity_cleanup;
+               goto error_power_off;
 
        ret = ov4689_init_controls(sensor);
        if (ret)
-               goto entity_cleanup;
+               goto error_power_off;
 
        ret = v4l2_async_register_subdev_sensor(&sensor->sd);
        if (ret)
                goto free_ctrls;
 
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+
        return 0;
 
 free_ctrls:
        v4l2_ctrl_handler_free(&sensor->ctrls.handler);
+error_power_off:
+       ov4689_set_power_off(dev);
 entity_cleanup:
        media_entity_cleanup(&sensor->sd.entity);
        mutex_destroy(&sensor->lock);
@@ -3002,6 +2933,11 @@ static int ov4689_remove(struct i2c_client *client)
        v4l2_ctrl_handler_free(&sensor->ctrls.handler);
        mutex_destroy(&sensor->lock);
 
+       pm_runtime_disable(&client->dev);
+       if (!pm_runtime_status_suspended(&client->dev))
+               ov4689_set_power_off(&client->dev);
+       pm_runtime_set_suspended(&client->dev);
+
        return 0;
 }
 
@@ -3017,10 +2953,15 @@ static const struct of_device_id ov4689_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, ov4689_dt_ids);
 
+static const struct dev_pm_ops ov4689_pm_ops = {
+       SET_RUNTIME_PM_OPS(ov4689_set_power_off, ov4689_set_power_on, NULL)
+};
+
 static struct i2c_driver ov4689_i2c_driver = {
        .driver = {
                .name  = "ov4689",
                .of_match_table = ov4689_dt_ids,
+               .pm = &ov4689_pm_ops,
        },
        .id_table = ov4689_id,
        .probe_new = ov4689_probe,
index e50de3a..cccb679 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 #include <linux/of_device.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <media/v4l2-event.h>
 #include <media/v4l2-fwnode.h>
 #include <media/v4l2-subdev.h>
-#include <linux/pinctrl/pinctrl.h>
 #include "stfcamss.h"
 
 /* min/typical/max system clock (xclk) frequencies */
 #define SC2235_XCLK_MIN                        6000000
-#define SC2235_XCLK_MAX                        54000000
+#define SC2235_XCLK_MAX                        27000000
 
 #define SC2235_CHIP_ID         (0x2235)
 
@@ -56,7 +56,6 @@ enum sc2235_mode_id {
 enum sc2235_frame_rate {
        SC2235_15_FPS = 0,
        SC2235_30_FPS,
-       SC2235_60_FPS,
        SC2235_NUM_FRAMERATES,
 };
 
@@ -66,14 +65,12 @@ struct sc2235_pixfmt {
 };
 
 static const struct sc2235_pixfmt sc2235_formats[] = {
-       //{ MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_COLORSPACE_SRGB, },
        { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB, },
 };
 
 static const int sc2235_framerates[] = {
        [SC2235_15_FPS] = 15,
        [SC2235_30_FPS] = 30,
-       [SC2235_60_FPS] = 60,
 };
 
 /* regulator supplies */
@@ -145,8 +142,6 @@ struct sc2235_dev {
        /* lock to protect all members below */
        struct mutex lock;
 
-       int power_count;
-
        struct v4l2_mbus_framefmt fmt;
        bool pending_fmt_change;
 
@@ -157,9 +152,6 @@ struct sc2235_dev {
 
        struct sc2235_ctrls ctrls;
 
-       u32 prev_sysclk, prev_hts;
-       u32 ae_low, ae_high, ae_target;
-
        bool pending_mode_change;
        int streaming;
 };
@@ -408,7 +400,7 @@ static const struct sc2235_mode_info sc2235_mode_init_data = {
        1920, 0x8ca, 1080, 0x4b0,
        sc2235_init_regs_tbl_1080,
        ARRAY_SIZE(sc2235_init_regs_tbl_1080),
-       SC2235_60_FPS,
+       SC2235_30_FPS,
 };
 
 static const struct sc2235_mode_info
@@ -417,7 +409,7 @@ sc2235_mode_data[SC2235_NUM_MODES] = {
         1920, 0x8ca, 1080, 0x4b0,
         sc2235_setting_1080P_1920_1080,
         ARRAY_SIZE(sc2235_setting_1080P_1920_1080),
-        SC2235_60_FPS},
+        SC2235_30_FPS},
 };
 
 static int sc2235_write_reg(struct sc2235_dev *sensor, u16 reg, u8 val)
@@ -700,12 +692,6 @@ static int sc2235_set_autogain(struct sc2235_dev *sensor, bool on)
                                BIT(1), on ? 0 : BIT(1));
 }
 
-static int sc2235_set_stream_dvp(struct sc2235_dev *sensor, bool on)
-{
-       return sc2235_mod_reg(sensor, SC2235_REG_STREAM_ON,
-                               BIT(0), on);
-}
-
 #ifdef UNUSED_CODE
 static int sc2235_get_sysclk(struct sc2235_dev *sensor)
 {
@@ -875,10 +861,8 @@ static int sc2235_set_mode(struct sc2235_dev *sensor)
        }
 
        rate = sc2235_calc_pixel_rate(sensor);
-       if (sensor->ep.bus_type == V4L2_MBUS_PARALLEL)
-               ret = sc2235_set_dvp_pclk(sensor, rate);
-
 
+       ret = sc2235_set_dvp_pclk(sensor, rate);
        if (ret < 0)
                return 0;
 
@@ -886,7 +870,6 @@ static int sc2235_set_mode(struct sc2235_dev *sensor)
        if (ret < 0)
                goto restore_auto_exp_gain;
 
-
        /* restore auto gain and exposure */
        if (auto_gain)
                sc2235_set_autogain(sensor, true);
@@ -956,9 +939,11 @@ static void sc2235_reset(struct sc2235_dev *sensor)
        usleep_range(20000, 25000);
 }
 
-static int sc2235_set_power_on(struct sc2235_dev *sensor)
+static int sc2235_set_power_on(struct device *dev)
 {
-       struct i2c_client *client = sensor->i2c_client;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct sc2235_dev *sensor = to_sc2235_dev(sd);
        int ret;
 
        ret = clk_prepare_enable(sensor->xclk);
@@ -986,41 +971,15 @@ xclk_off:
        return ret;
 }
 
-static void sc2235_set_power_off(struct sc2235_dev *sensor)
+static int sc2235_set_power_off(struct device *dev)
 {
-       sc2235_power(sensor, false);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct sc2235_dev *sensor = to_sc2235_dev(sd);
 
+       sc2235_power(sensor, false);
        regulator_bulk_disable(SC2235_NUM_SUPPLIES, sensor->supplies);
        clk_disable_unprepare(sensor->xclk);
-}
-
-static int sc2235_set_power_dvp(struct sc2235_dev *sensor, bool on)
-{
-       unsigned int flags = sensor->ep.bus.parallel.flags;
-       u8 polarities = 0;
-
-       /*
-        * configure parallel port control lines polarity
-        *
-        * POLARITY CTRL0
-        * - [5]:       PCLK polarity (0: active low, 1: active high)
-        * - [1]:       HREF polarity (0: active low, 1: active high)
-        * - [0]:       VSYNC polarity (mismatch here between
-        *              datasheet and hardware, 0 is active high
-        *              and 1 is active low...)
-        */
-       if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
-               polarities |= BIT(1);
-       if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
-               polarities |= BIT(0);
-       if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
-               polarities |= BIT(5);
-
-       // ret = sc2235_write_reg(sensor,
-       //              SC2235_REG_POLARITY_CTRL00,
-       //              polarities);
-       // if (ret)
-       //      return ret;
 
        return 0;
 }
@@ -1030,27 +989,20 @@ static int sc2235_set_power(struct sc2235_dev *sensor, bool on)
        int ret = 0;
 
        if (on) {
-               ret = sc2235_set_power_on(sensor);
-               if (ret)
-                       return ret;
+               pm_runtime_get_sync(&sensor->i2c_client->dev);
 
                ret = sc2235_restore_mode(sensor);
                if (ret)
                        goto power_off;
        }
 
-       if (sensor->ep.bus_type == V4L2_MBUS_PARALLEL)
-               ret = sc2235_set_power_dvp(sensor, on);
-       if (ret)
-               goto power_off;
-
        if (!on)
-               sc2235_set_power_off(sensor);
+               pm_runtime_put_sync(&sensor->i2c_client->dev);
 
        return 0;
 
 power_off:
-       sc2235_set_power_off(sensor);
+       pm_runtime_put_sync(&sensor->i2c_client->dev);
 
        return ret;
 }
@@ -1062,27 +1014,15 @@ static int sc2235_s_power(struct v4l2_subdev *sd, int on)
 
        mutex_lock(&sensor->lock);
 
-       /*
-        * If the power count is modified from 0 to != 0 or from != 0 to 0,
-        * update the power state.
-        */
-       if (sensor->power_count == !on) {
-               ret = sc2235_set_power(sensor, !!on);
-               if (ret)
-                       goto out;
-       }
+       ret = sc2235_set_power(sensor, !!on);
+       if (ret)
+               goto out;
 
-       /* Update the power count. */
-       sensor->power_count += on ? 1 : -1;
-       WARN_ON(sensor->power_count < 0);
-out:
        mutex_unlock(&sensor->lock);
+       return 0;
 
-       if (on && !ret && sensor->power_count == 1) {
-               /* restore controls */
-               ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
-       }
-
+out:
+       mutex_unlock(&sensor->lock);
        return ret;
 }
 
@@ -1096,12 +1036,12 @@ static int sc2235_try_frame_interval(struct sc2235_dev *sensor,
        int i;
 
        minfps = sc2235_framerates[SC2235_15_FPS];
-       maxfps = sc2235_framerates[SC2235_60_FPS];
+       maxfps = sc2235_framerates[SC2235_30_FPS];
 
        if (fi->numerator == 0) {
                fi->denominator = maxfps;
                fi->numerator = 1;
-               rate = SC2235_60_FPS;
+               rate = SC2235_30_FPS;
                goto find_mode;
        }
 
@@ -1377,6 +1317,9 @@ static int sc2235_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 
        /* v4l2_ctrl_lock() locks our own mutex */
 
+       if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev))
+               return 0;
+
        switch (ctrl->id) {
        case V4L2_CID_AUTOGAIN:
                val = sc2235_get_gain(sensor);
@@ -1392,6 +1335,8 @@ static int sc2235_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
                break;
        }
 
+       pm_runtime_put(&sensor->i2c_client->dev);
+
        return 0;
 }
 
@@ -1406,9 +1351,9 @@ static int sc2235_s_ctrl(struct v4l2_ctrl *ctrl)
        /*
         * If the device is not powered up by the host driver do
         * not apply any controls to H/W at this time. Instead
-        * the controls will be restored right after power-up.
+        * the controls will be restored at start streaming time.
         */
-       if (sensor->power_count == 0)
+       if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev))
                return 0;
 
        switch (ctrl->id) {
@@ -1447,6 +1392,8 @@ static int sc2235_s_ctrl(struct v4l2_ctrl *ctrl)
                break;
        }
 
+       pm_runtime_put(&sensor->i2c_client->dev);
+
        return ret;
 }
 
@@ -1502,7 +1449,7 @@ static int sc2235_init_controls(struct sc2235_dev *sensor)
                                                V4L2_EXPOSURE_MANUAL, 0,
                                                1);
        ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
-                                       0, 65535, 1, 0x4600);
+                                       0, 65535, 1, 720);
        /* Auto/manual gain */
        ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
                                                0, 1, 1, 0);
@@ -1673,11 +1620,22 @@ static int sc2235_enum_mbus_code(struct v4l2_subdev *sd,
        return 0;
 }
 
+static int sc2235_stream_start(struct sc2235_dev *sensor, int enable)
+{
+       return sc2235_mod_reg(sensor, SC2235_REG_STREAM_ON, BIT(0), !!enable);
+}
+
 static int sc2235_s_stream(struct v4l2_subdev *sd, int enable)
 {
        struct sc2235_dev *sensor = to_sc2235_dev(sd);
        int ret = 0;
 
+       if (enable) {
+               ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
+               if (ret)
+                       return ret;
+       }
+
        mutex_lock(&sensor->lock);
 
        if (sensor->streaming == !enable) {
@@ -1694,12 +1652,7 @@ static int sc2235_s_stream(struct v4l2_subdev *sd, int enable)
                        sensor->pending_fmt_change = false;
                }
 
-               if (sensor->ep.bus_type == V4L2_MBUS_PARALLEL) {
-                       ret = sc2235_set_gain(sensor, 0x10);
-                       ret = sc2235_set_exposure(sensor, (360 * 2));
-                       ret = sc2235_set_stream_dvp(sensor, enable);
-               }
-
+               ret = sc2235_stream_start(sensor, enable);
                if (ret)
                        goto out;
        }
@@ -1756,28 +1709,22 @@ static int sc2235_check_chip_id(struct sc2235_dev *sensor)
        int ret = 0;
        u16 chip_id;
 
-       ret = sc2235_set_power_on(sensor);
-       if (ret)
-               return ret;
-
        ret = sc2235_read_reg16(sensor, SC2235_REG_CHIP_ID, &chip_id);
        if (ret) {
                dev_err(&client->dev, "%s: failed to read chip identifier\n",
                        __func__);
-               goto power_off;
+               return ret;
        }
 
        if (chip_id != SC2235_CHIP_ID) {
                dev_err(&client->dev, "%s: wrong chip identifier, expected 0x%x, got 0x%x\n",
                        __func__, SC2235_CHIP_ID, chip_id);
-               ret = -ENXIO;
+               return -ENXIO;
        }
        dev_err(&client->dev, "%s: chip identifier, got 0x%x\n",
                __func__, chip_id);
 
-power_off:
-       sc2235_set_power_off(sensor);
-       return ret;
+       return 0;
 }
 
 static int sc2235_probe(struct i2c_client *client)
@@ -1811,8 +1758,6 @@ static int sc2235_probe(struct i2c_client *client)
                &sc2235_mode_data[SC2235_MODE_1080P_1920_1080];
        sensor->last_mode = sensor->current_mode;
 
-       sensor->ae_target = 52;
-
        /* optional indication of physical rotation of sensor */
        ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation",
                                        &rotation);
@@ -1843,9 +1788,7 @@ static int sc2235_probe(struct i2c_client *client)
                return ret;
        }
 
-       if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL &&
-           sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY &&
-           sensor->ep.bus_type != V4L2_MBUS_BT656) {
+       if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL) {
                dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type);
                return -EINVAL;
        }
@@ -1890,22 +1833,33 @@ static int sc2235_probe(struct i2c_client *client)
                return ret;
        mutex_init(&sensor->lock);
 
+       ret = sc2235_set_power_on(dev);
+       if (ret) {
+               dev_err(dev, "failed to power on\n");
+               goto entity_cleanup;
+       }
+
        ret = sc2235_check_chip_id(sensor);
        if (ret)
-               goto entity_cleanup;
+               goto entity_power_off;
 
        ret = sc2235_init_controls(sensor);
        if (ret)
-               goto entity_cleanup;
+               goto entity_power_off;
 
        ret = v4l2_async_register_subdev_sensor(&sensor->sd);
        if (ret)
                goto free_ctrls;
 
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+
        return 0;
 
 free_ctrls:
        v4l2_ctrl_handler_free(&sensor->ctrls.handler);
+entity_power_off:
+       sc2235_set_power_off(dev);
 entity_cleanup:
        media_entity_cleanup(&sensor->sd.entity);
        mutex_destroy(&sensor->lock);
@@ -1922,6 +1876,11 @@ static int sc2235_remove(struct i2c_client *client)
        v4l2_ctrl_handler_free(&sensor->ctrls.handler);
        mutex_destroy(&sensor->lock);
 
+       pm_runtime_disable(&client->dev);
+       if (!pm_runtime_status_suspended(&client->dev))
+               sc2235_set_power_off(&client->dev);
+       pm_runtime_set_suspended(&client->dev);
+
        return 0;
 }
 
@@ -1937,10 +1896,15 @@ static const struct of_device_id sc2235_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, sc2235_dt_ids);
 
+static const struct dev_pm_ops sc2235_pm_ops = {
+       SET_RUNTIME_PM_OPS(sc2235_set_power_off, sc2235_set_power_on, NULL)
+};
+
 static struct i2c_driver sc2235_i2c_driver = {
        .driver = {
                .name  = "sc2235",
                .of_match_table = sc2235_dt_ids,
+               .pm = &sc2235_pm_ops,
        },
        .id_table = sc2235_id,
        .probe_new = sc2235_probe,
@@ -1949,5 +1913,5 @@ static struct i2c_driver sc2235_i2c_driver = {
 
 module_i2c_driver(sc2235_i2c_driver);
 
-MODULE_DESCRIPTION("SC2235 MIPI Camera Subdev Driver");
+MODULE_DESCRIPTION("SC2235 Camera Subdev Driver");
 MODULE_LICENSE("GPL");
index 6fb75d4..52c0833 100644 (file)
@@ -400,25 +400,16 @@ free_ctrls:
 static int isp_set_power(struct v4l2_subdev *sd, int on)
 {
        struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
-       struct stf_vin2_dev *vin_dev = isp_dev->stfcamss->vin_dev;
 
        st_debug(ST_ISP, "%s, %d\n", __func__, __LINE__);
        mutex_lock(&isp_dev->power_lock);
        if (on) {
-               if (isp_dev->power_count == 0) {
-                       /* Needs to enable vin clock before access ISP. */
-                       vin_dev->hw_ops->vin_top_clk_init(vin_dev);
-                       vin_dev->hw_ops->vin_clk_enable(vin_dev);
-                       isp_dev->hw_ops->isp_clk_enable(isp_dev);
-                       if (!user_config_isp)
-                               isp_dev->hw_ops->isp_config_set(isp_dev);
-               }
+               if (isp_dev->power_count == 0)
+                       st_debug(ST_ISP, "turn on isp\n");
                isp_dev->power_count++;
        } else {
                if (isp_dev->power_count == 0)
                        goto exit;
-               if (isp_dev->power_count == 1)
-                       isp_dev->hw_ops->isp_clk_disable(isp_dev);
                isp_dev->power_count--;
        }
 exit:
@@ -473,6 +464,9 @@ static int isp_set_stream(struct v4l2_subdev *sd, int enable)
        mutex_lock(&isp_dev->stream_lock);
        if (enable) {
                if (isp_dev->stream_count == 0) {
+                       isp_dev->hw_ops->isp_clk_enable(isp_dev);
+                       if (!user_config_isp)
+                               isp_dev->hw_ops->isp_config_set(isp_dev);
                        interface_type = isp_get_interface_type(&sd->entity);
                        if (interface_type < 0) {
                                st_err(ST_ISP, "%s, pipeline not config\n", __func__);
@@ -488,8 +482,10 @@ static int isp_set_stream(struct v4l2_subdev *sd, int enable)
        } else {
                if (isp_dev->stream_count == 0)
                        goto exit;
-               if (isp_dev->stream_count == 1)
+               if (isp_dev->stream_count == 1) {
                        isp_dev->hw_ops->isp_stream_set(isp_dev, enable);
+                       isp_dev->hw_ops->isp_clk_disable(isp_dev);
+               }
                isp_dev->stream_count--;
        }
        src_ch.type = V4L2_EVENT_SOURCE_CHANGE,
index 7625aad..f333371 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
 
 #include "stfcamss.h"
 
@@ -215,26 +216,6 @@ int stf_vin_subdev_init(struct stfcamss *stfcamss)
                goto out;
        }
 
-       vin_dev->hw_ops->vin_wr_irq_enable(vin_dev, 1);
-       vin_dev->hw_ops->vin_wr_irq_enable(vin_dev, 0);
-
-       /* Reset device */
-       /*Do not configure the CLK before powering on the device,
-        *add vin_power_on() to vin_set_power() 2021 1111
-        */
-       ret = vin_dev->hw_ops->vin_top_clk_init(vin_dev);
-       if (ret) {
-               st_err(ST_VIN, "Failed to reset device\n");
-               goto out;
-       }
-
-       // /* set the sysctl config */
-       // ret = vin_dev->hw_ops->vin_config_set(vin_dev);
-       // if (ret) {
-       //      st_err(ST_VIN, "Failed to config device\n");
-       //      goto out;
-       // }
-
        mutex_init(&vin_dev->power_lock);
        vin_dev->power_count = 0;
 
@@ -283,6 +264,7 @@ static int vin_set_power(struct v4l2_subdev *sd, int on)
 {
        struct vin_line *line = v4l2_get_subdevdata(sd);
        struct stf_vin2_dev *vin_dev = line_to_vin2_dev(line);
+       struct stfcamss *stfcamss = vin_dev->stfcamss;
 
        mutex_lock(&line->power_lock);
        if (on) {
@@ -303,7 +285,7 @@ exit_line:
        mutex_lock(&vin_dev->power_lock);
        if (on) {
                if (vin_dev->power_count == 0) {
-                       //vin_dev->hw_ops->vin_top_clk_init(vin_dev);
+                       pm_runtime_get_sync(stfcamss->dev);
                        vin_dev->hw_ops->vin_clk_enable(vin_dev);
                        vin_dev->hw_ops->vin_config_set(vin_dev);
                }
@@ -316,7 +298,7 @@ exit_line:
                }
                if (vin_dev->power_count == 1) {
                        vin_dev->hw_ops->vin_clk_disable(vin_dev);
-                       //vin_dev->hw_ops->vin_top_clk_deinit(vin_dev);
+                       pm_runtime_put_sync(stfcamss->dev);
                }
                vin_dev->power_count--;
        }
@@ -638,23 +620,25 @@ static int vin_set_stream(struct v4l2_subdev *sd, int enable)
        }
        mutex_unlock(&dummy_buffer->stream_lock);
 
-       if (line->id == VIN_LINE_WR) {
-               mutex_lock(&line->stream_lock);
-               if (enable) {
-                       if (line->stream_count == 0) {
+       mutex_lock(&line->stream_lock);
+       if (enable) {
+               if (line->stream_count == 0) {
+                       if (line->id == VIN_LINE_WR) {
                                vin_dev->hw_ops->vin_wr_irq_enable(vin_dev, 1);
                                vin_dev->hw_ops->vin_wr_stream_set(vin_dev, 1);
                        }
-                       line->stream_count++;
-               } else {
-                       if (line->stream_count == 1) {
+               }
+               line->stream_count++;
+       } else {
+               if (line->stream_count == 1) {
+                       if (line->id == VIN_LINE_WR) {
                                vin_dev->hw_ops->vin_wr_irq_enable(vin_dev, 0);
                                vin_dev->hw_ops->vin_wr_stream_set(vin_dev, 0);
                        }
-                       line->stream_count--;
                }
-               mutex_unlock(&line->stream_lock);
+               line->stream_count--;
        }
+       mutex_unlock(&line->stream_lock);
 
        if (enable)
                vin_enable_output(line);
index b751afc..5625621 100644 (file)
@@ -87,8 +87,6 @@ struct vin_line {
 struct stf_vin2_dev;
 
 struct vin_hw_ops {
-       int (*vin_top_clk_init)(struct stf_vin2_dev *vin_dev);
-       int (*vin_top_clk_deinit)(struct stf_vin2_dev *vin_dev);
        int (*vin_clk_enable)(struct stf_vin2_dev *vin_dev);
        int (*vin_clk_disable)(struct stf_vin2_dev *vin_dev);
        int (*vin_config_set)(struct stf_vin2_dev *vin_dev);
index 9b06550..aaec27c 100644 (file)
@@ -7,8 +7,6 @@
 #include <media/v4l2-async.h>
 #include <media/v4l2-fwnode.h>
 #include <media/v4l2-subdev.h>
-#include <linux/clk-provider.h>
-#include <linux/pm_runtime.h>
 
 static void vin_intr_clear(void __iomem *sysctrl_base)
 {
@@ -213,47 +211,6 @@ static irqreturn_t stf_vin_isp_irq_csiline_handler(int irq, void *priv)
        return IRQ_HANDLED;
 }
 
-static int stf_vin_top_clk_init(struct stf_vin2_dev *vin_dev)
-{
-       struct stfcamss *stfcamss = vin_dev->stfcamss;
-       int ret;
-
-       pm_runtime_enable(stfcamss->dev);
-       ret = pm_runtime_get_sync(stfcamss->dev);
-       if (ret < 0) {
-               dev_err(stfcamss->dev,
-                       "vin_clk_init: failed to get pm runtime: %d\n", ret);
-               return ret;
-       }
-
-       if (!__clk_is_enabled(stfcamss->sys_clk[STFCLK_NOC_BUS_CLK_ISP_AXI].clk))
-               clk_prepare_enable(stfcamss->sys_clk[STFCLK_NOC_BUS_CLK_ISP_AXI].clk);
-       else
-               st_warn(ST_VIN, "noc_bus_clk_isp_axi already enable\n");
-
-       clk_prepare_enable(stfcamss->sys_clk[STFCLK_ISPCORE_2X].clk);
-       clk_prepare_enable(stfcamss->sys_clk[STFCLK_ISP_AXI].clk);
-       reset_control_deassert(stfcamss->sys_rst[STFRST_ISP_TOP_N].rstc);
-       reset_control_deassert(stfcamss->sys_rst[STFRST_ISP_TOP_AXI].rstc);
-
-       return 0;
-}
-
-static int stf_vin_top_clk_deinit(struct stf_vin2_dev *vin_dev)
-{
-       struct stfcamss *stfcamss = vin_dev->stfcamss;
-
-       reset_control_assert(stfcamss->sys_rst[STFRST_ISP_TOP_AXI].rstc);
-       reset_control_assert(stfcamss->sys_rst[STFRST_ISP_TOP_N].rstc);
-       clk_disable_unprepare(stfcamss->sys_clk[STFCLK_ISP_AXI].clk);
-       clk_disable_unprepare(stfcamss->sys_clk[STFCLK_ISPCORE_2X].clk);
-
-       pm_runtime_put_sync(stfcamss->dev);
-       pm_runtime_disable(stfcamss->dev);
-
-       return 0;
-}
-
 static int stf_vin_clk_enable(struct stf_vin2_dev *vin_dev)
 {
        struct stfcamss *stfcamss = vin_dev->stfcamss;
@@ -451,8 +408,6 @@ void dump_vin_reg(void *__iomem regbase)
 }
 
 struct vin_hw_ops vin_ops = {
-       .vin_top_clk_init      = stf_vin_top_clk_init,
-       .vin_top_clk_deinit    = stf_vin_top_clk_deinit,
        .vin_clk_enable        = stf_vin_clk_enable,
        .vin_clk_disable       = stf_vin_clk_disable,
        .vin_config_set        = stf_vin_config_set,
index f699766..11dbb85 100644 (file)
@@ -71,7 +71,6 @@ static struct clk_bulk_data stfcamss_clocks[] = {
        { .id = "clk_m31dphy_txclkesc_lan0" },
        { .id = "clk_ispcore_2x" },
        { .id = "clk_isp_axi" },
-       { .id = "clk_noc_bus_clk_isp_axi" },
 };
 
 static struct reset_control_bulk_data stfcamss_resets[] = {
@@ -1011,6 +1010,8 @@ static int stfcamss_probe(struct platform_device *pdev)
                goto err_cam;
        }
 
+       pm_runtime_enable(dev);
+
        stfcamss->nclks = ARRAY_SIZE(stfcamss_clocks);
        stfcamss->sys_clk = stfcamss_clocks;
 
@@ -1023,7 +1024,7 @@ static int stfcamss_probe(struct platform_device *pdev)
        stfcamss->nrsts = ARRAY_SIZE(stfcamss_resets);
        stfcamss->sys_rst = stfcamss_resets;
 
-       ret = devm_reset_control_bulk_get_exclusive(dev, stfcamss->nrsts,
+       ret = devm_reset_control_bulk_get_shared(dev, stfcamss->nrsts,
                stfcamss->sys_rst);
        if (ret) {
                st_err(ST_CAMSS, "Failed to get reset controls\n");
@@ -1175,6 +1176,7 @@ static int stfcamss_remove(struct platform_device *pdev)
        stfcamss_unregister_subdevices(stfcamss);
        v4l2_device_unregister(&stfcamss->v4l2_dev);
        media_device_cleanup(&stfcamss->media_dev);
+       pm_runtime_disable(&pdev->dev);
 
        kfree(stfcamss);
 
@@ -1188,11 +1190,143 @@ static const struct of_device_id stfcamss_of_match[] = {
 
 MODULE_DEVICE_TABLE(of, stfcamss_of_match);
 
+#ifdef CONFIG_PM_SLEEP
+static int stfcamss_suspend(struct device *dev)
+{
+       struct stfcamss *stfcamss = dev_get_drvdata(dev);
+       struct stf_vin2_dev *vin_dev = stfcamss->vin_dev;
+       struct media_entity *entity;
+       struct media_pad *pad;
+       struct v4l2_subdev *subdev;
+       struct stfcamss_video *video;
+       struct video_device *vdev;
+       int i = 0;
+
+       for (i = 0; i < VIN_LINE_MAX; i++) {
+               if (vin_dev->line[i].stream_count) {
+                       vin_dev->line[i].stream_count ++;
+                       video = &vin_dev->line[i].video_out;
+                       vdev = &vin_dev->line[i].video_out.vdev;
+                       entity = &vdev->entity;
+                       while (1) {
+                               pad = &entity->pads[0];
+                               if (!(pad->flags & MEDIA_PAD_FL_SINK))
+                                       break;
+
+                               pad = media_entity_remote_pad(pad);
+                               if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
+                                       break;
+
+                               entity = pad->entity;
+                               subdev = media_entity_to_v4l2_subdev(entity);
+
+                               v4l2_subdev_call(subdev, video, s_stream, 0);
+                       }
+                       media_pipeline_stop(&vdev->entity);
+                       video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR);
+                       v4l2_pipeline_pm_put(&vdev->entity);
+               }
+       }
+
+       return pm_runtime_force_suspend(dev);
+}
+
+static int stfcamss_resume(struct device *dev)
+{
+       struct stfcamss *stfcamss = dev_get_drvdata(dev);
+       struct stf_vin2_dev *vin_dev = stfcamss->vin_dev;
+       struct media_entity *entity;
+       struct media_pad *pad;
+       struct v4l2_subdev *subdev;
+       struct stfcamss_video *video;
+       struct video_device *vdev;
+       int i = 0;
+       int ret = 0;
+
+       pm_runtime_force_resume(dev);
+
+       for (i = 0; i < VIN_LINE_MAX; i++) {
+               if (vin_dev->line[i].stream_count) {
+                       vin_dev->line[i].stream_count--;
+                       video = &vin_dev->line[i].video_out;
+                       vdev = &vin_dev->line[i].video_out.vdev;
+
+                       ret = v4l2_pipeline_pm_get(&vdev->entity);
+                       if (ret < 0)
+                               goto err;
+
+                       ret = media_pipeline_start(&vdev->entity, &video->stfcamss->pipe);
+                       if (ret < 0)
+                               goto err_pm_put;
+
+                       entity = &vdev->entity;
+                       while (1) {
+                               pad = &entity->pads[0];
+                               if (!(pad->flags & MEDIA_PAD_FL_SINK))
+                                       break;
+
+                               pad = media_entity_remote_pad(pad);
+                               if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
+                                       break;
+
+                               entity = pad->entity;
+                               subdev = media_entity_to_v4l2_subdev(entity);
+
+                               ret = v4l2_subdev_call(subdev, video, s_stream, 1);
+                               if (ret < 0 && ret != -ENOIOCTLCMD)
+                                       goto err_pipeline_stop;
+                       }
+               }
+       }
+
+       return 0;
+
+err_pipeline_stop:
+       media_pipeline_stop(&vdev->entity);
+err_pm_put:
+       v4l2_pipeline_pm_put(&vdev->entity);
+err:
+       return ret;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM
+static int stfcamss_runtime_suspend(struct device *dev)
+{
+       struct stfcamss *stfcamss = dev_get_drvdata(dev);
+
+       reset_control_assert(stfcamss->sys_rst[STFRST_ISP_TOP_AXI].rstc);
+       reset_control_assert(stfcamss->sys_rst[STFRST_ISP_TOP_N].rstc);
+       clk_disable_unprepare(stfcamss->sys_clk[STFCLK_ISP_AXI].clk);
+       clk_disable_unprepare(stfcamss->sys_clk[STFCLK_ISPCORE_2X].clk);
+
+       return 0;
+}
+
+static int stfcamss_runtime_resume(struct device *dev)
+{
+       struct stfcamss *stfcamss = dev_get_drvdata(dev);
+
+       clk_prepare_enable(stfcamss->sys_clk[STFCLK_ISPCORE_2X].clk);
+       clk_prepare_enable(stfcamss->sys_clk[STFCLK_ISP_AXI].clk);
+       reset_control_deassert(stfcamss->sys_rst[STFRST_ISP_TOP_N].rstc);
+       reset_control_deassert(stfcamss->sys_rst[STFRST_ISP_TOP_AXI].rstc);
+
+       return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops stfcamss_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(stfcamss_suspend, stfcamss_resume)
+       SET_RUNTIME_PM_OPS(stfcamss_runtime_suspend, stfcamss_runtime_resume, NULL)
+};
+
 static struct platform_driver stfcamss_driver = {
        .probe = stfcamss_probe,
        .remove = stfcamss_remove,
        .driver = {
                .name = DRV_NAME,
+               .pm = &stfcamss_pm_ops,
                .of_match_table = of_match_ptr(stfcamss_of_match),
        },
 };
index 186c03b..41cac3b 100644 (file)
@@ -56,7 +56,6 @@ enum stf_clk_num {
        STFCLK_M31DPHY_TXCLKESC_LAN0,
        STFCLK_ISPCORE_2X,
        STFCLK_ISP_AXI,
-       STFCLK_NOC_BUS_CLK_ISP_AXI,
        STFCLK_NUM
 };
 
index b328e23..0cb0bab 100644 (file)
@@ -193,27 +193,92 @@ static const struct dw_mci_drv_data starfive_data = {
        .switch_voltage  = dw_mci_starfive_switch_voltage,
 };
 
+static const struct of_device_id dw_mci_starfive_match[] = {
+       { .compatible = "starfive,jh7110-sdio",
+               .data = &starfive_data },
+       {},
+};
+MODULE_DEVICE_TABLE(of, dw_mci_starfive_match);
+
 static int dw_mci_starfive_probe(struct platform_device *pdev)
 {
-       return dw_mci_pltfm_register(pdev, &starfive_data);
+       const struct dw_mci_drv_data *drv_data;
+       const struct of_device_id *match;
+       int ret;
+
+       match = of_match_node(dw_mci_starfive_match, pdev->dev.of_node);
+       drv_data = match->data;
+
+       pm_runtime_get_noresume(&pdev->dev);
+       pm_runtime_set_active(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+
+       ret = dw_mci_pltfm_register(pdev, drv_data);
+       if (ret) {
+               pm_runtime_disable(&pdev->dev);
+               pm_runtime_set_suspended(&pdev->dev);
+               pm_runtime_put_noidle(&pdev->dev);
+
+               return ret;
+       }
+
+       return 0;
 }
 
 static int dw_mci_starfive_remove(struct platform_device *pdev)
 {
+       pm_runtime_disable(&pdev->dev);
+       pm_runtime_set_suspended(&pdev->dev);
+       pm_runtime_put_noidle(&pdev->dev);
+
        return dw_mci_pltfm_remove(pdev);
 }
 
-static const struct of_device_id dw_mci_starfive_match[] = {
-       { .compatible = "starfive,jh7110-sdio", },
-       {},
+#ifdef CONFIG_PM
+static int dw_mci_starfive_runtime_suspend(struct device *dev)
+{
+       struct dw_mci *host = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(host->biu_clk);
+       clk_disable_unprepare(host->ciu_clk);
+
+       return 0;
+}
+
+static int dw_mci_starfive_runtime_resume(struct device *dev)
+{
+       struct dw_mci *host = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(host->biu_clk);
+       if (ret) {
+               dev_err(host->dev, "Failed to prepare_enable biu_clk clock\n");
+               return ret;
+       }
+
+       ret = clk_prepare_enable(host->ciu_clk);
+       if (ret) {
+               dev_err(host->dev, "Failed to prepare_enable ciu_clk clock\n");
+               return ret;
+       }
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops dw_mci_starfive_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
+       SET_RUNTIME_PM_OPS(dw_mci_starfive_runtime_suspend,
+                          dw_mci_starfive_runtime_resume, NULL)
 };
 
-MODULE_DEVICE_TABLE(of, dw_mci_starfive_match);
 static struct platform_driver dw_mci_starfive_driver = {
        .probe = dw_mci_starfive_probe,
        .remove = dw_mci_starfive_remove,
        .driver = {
                .name = "dwmmc_starfive",
+               .pm   = &dw_mci_starfive_pm_ops,
                .probe_type = PROBE_PREFER_ASYNCHRONOUS,
                .of_match_table = dw_mci_starfive_match,
        },
index 6e0a816..0212b43 100644 (file)
@@ -697,6 +697,8 @@ static int canfd_driver_close(struct net_device *ndev)
        free_irq(ndev->irq, ndev);
        close_candev(ndev);
 
+       pm_runtime_put(priv->dev);
+
        return 0;
 }
 
@@ -955,6 +957,12 @@ static int canfd_driver_open(struct net_device *ndev)
        struct ipms_canfd_priv *priv = netdev_priv(ndev);
        int ret;
 
+       ret = pm_runtime_get_sync(priv->dev);
+       if (ret < 0) {
+               dev_err(priv->dev, " %s: pm_runtime_get failed\n", __func__);
+               goto err;
+       }
+
        /* Set chip into reset mode */
        ret = set_reset_mode(ndev);
        if (ret) {
@@ -987,6 +995,8 @@ static int canfd_driver_open(struct net_device *ndev)
 
 exit_can_start:
        free_irq(ndev->irq, ndev);
+err:
+       pm_runtime_put(priv->dev);
 exit_irq:
        close_candev(ndev);
        return ret;
@@ -1101,6 +1111,9 @@ static int canfd_driver_probe(struct platform_device *pdev)
        priv->reg_base = addr;
        priv->write_reg = canfd_write_reg_le;
        priv->read_reg = canfd_read_reg_le;
+
+       pm_runtime_enable(&pdev->dev);
+
        priv->can_clk = devm_clk_get(&pdev->dev, "core_clk");
        if (IS_ERR(priv->can_clk)) {
                dev_err(&pdev->dev, "Device clock not found.\n");
@@ -1150,6 +1163,7 @@ static int canfd_driver_remove(struct platform_device *pdev)
 
        reset_control_assert(priv->resets);
        clk_bulk_disable_unprepare(priv->nr_clks, priv->clks);
+       pm_runtime_disable(&pdev->dev);
 
        unregister_candev(ndev);
        netif_napi_del(&priv->napi);
@@ -1158,6 +1172,45 @@ static int canfd_driver_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int canfd_runtime_suspend(struct device *dev)
+{
+       struct ipms_canfd_priv *priv = dev_get_drvdata(dev);
+
+       reset_control_assert(priv->resets);
+       clk_bulk_disable_unprepare(priv->nr_clks, priv->clks);
+
+       return 0;
+}
+
+static int canfd_runtime_resume(struct device *dev)
+{
+       struct ipms_canfd_priv *priv = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_bulk_prepare_enable(priv->nr_clks, priv->clks);
+       if (ret) {
+               dev_err(dev, "Failed to  prepare_enable clk\n");
+               return ret;
+       }
+
+       ret = reset_control_deassert(priv->resets);
+       if (ret) {
+               dev_err(dev, "Failed to deassert reset\n");
+               return ret;
+       }
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops canfd_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
+       SET_RUNTIME_PM_OPS(canfd_runtime_suspend,
+                          canfd_runtime_resume, NULL)
+};
+
 static const struct of_device_id canfd_of_match[] = {
        { .compatible = "ipms,can" },
        { }
@@ -1169,6 +1222,7 @@ static struct platform_driver can_driver = {
        .remove         = canfd_driver_remove,
        .driver = {
                .name  = DRIVER_NAME,
+               .pm    = &canfd_pm_ops,
                .of_match_table = canfd_of_match,
        },
 };
index 92794b8..cde8f7b 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/pci.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/reset.h>
 #include <linux/slab.h>
 #define PLDA_EP_ENABLE                 0
 #define PLDA_RP_ENABLE                 1
 
+#define PLDA_LINK_UP                   1
+#define PLDA_LINK_DOWN                 0
+
+#define PLDA_DATA_LINK_ACTIVE          BIT(5)
 #define PREF_MEM_WIN_64_SUPPORT                BIT(3)
 #define PMSG_LTR_SUPPORT               BIT(2)
 #define PDLA_LINK_SPEED_GEN2           BIT(12)
@@ -139,6 +144,7 @@ struct plda_pcie {
        u32 stg_arfun;
        u32 stg_awfun;
        u32 stg_rp_nep;
+       u32 stg_lnksta;
        int                     irq;
        struct irq_domain       *legacy_irq_domain;
        struct pci_host_bridge  *bridge;
@@ -150,6 +156,7 @@ struct plda_pcie {
        struct pinctrl *pinctrl;
        struct pinctrl_state *perst_state_def;
        struct pinctrl_state *perst_state_active;
+       struct pinctrl_state *power_state_def;
        struct pinctrl_state *power_state_active;
 };
 
@@ -593,7 +600,7 @@ static int plda_pcie_parse_dt(struct plda_pcie *pcie)
        }
 
        ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
-                                                       "starfive,stg-syscon", 3, 0, &args);
+                                                       "starfive,stg-syscon", 4, 0, &args);
        if (ret < 0) {
                dev_err(&pdev->dev, "Failed to parse starfive,stg-syscon\n");
                return -EINVAL;
@@ -607,6 +614,7 @@ static int plda_pcie_parse_dt(struct plda_pcie *pcie)
        pcie->stg_arfun = args.args[0];
        pcie->stg_awfun = args.args[1];
        pcie->stg_rp_nep = args.args[2];
+       pcie->stg_lnksta = args.args[3];
 
        /* Clear all interrupts */
        plda_writel(pcie, 0xffffffff, ISTATUS_LOCAL);
@@ -734,10 +742,17 @@ int plda_pinctrl_init(struct plda_pcie *pcie)
                return -EINVAL;
        }
 
+       pcie->power_state_def
+               = pinctrl_lookup_state(pcie->pinctrl, "power-default");
+       if (IS_ERR_OR_NULL(pcie->power_state_def)) {
+               dev_err(dev, "Failed to get the power-default pinctrl handle\n");
+               return -EINVAL;
+       }
+
        pcie->power_state_active
                = pinctrl_lookup_state(pcie->pinctrl, "power-active");
        if (IS_ERR_OR_NULL(pcie->power_state_active)) {
-               dev_err(dev, "Failed to get the power-default pinctrl handle\n");
+               dev_err(dev, "Failed to get the power-active pinctrl handle\n");
                return -EINVAL;
        }
 
@@ -828,7 +843,32 @@ static void plda_pcie_hw_init(struct plda_pcie *pcie)
                if (ret)
                        dev_err(dev, "Cannot set reset pin to high\n");
        }
+}
+
+static int plda_pcie_is_link_up(struct plda_pcie *pcie)
+{
+       struct device *dev = &pcie->pdev->dev;
+       int ret;
+       u32 stg_reg_val;
+
+       /* 100ms timeout value should be enough for Gen1/2 training */
+       ret = regmap_read_poll_timeout(pcie->reg_syscon,
+                                       pcie->stg_lnksta,
+                                       stg_reg_val,
+                                       stg_reg_val & PLDA_DATA_LINK_ACTIVE,
+                                       10 * 1000, 100 * 1000);
+
+       /* If the link is down (no device in slot), then exit. */
+       if (ret == -ETIMEDOUT) {
+               dev_info(dev, "Port link down, exit.\n");
+               return PLDA_LINK_DOWN;
+       } else if (ret == 0) {
+               dev_info(dev, "Port link up.\n");
+               return PLDA_LINK_UP;
+       }
 
+       dev_warn(dev, "Read stg_linksta failed.\n");
+       return ret;
 }
 
 static int plda_pcie_probe(struct platform_device *pdev)
@@ -893,6 +933,9 @@ static int plda_pcie_probe(struct platform_device *pdev)
                goto exit;
        }
 
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
+
        /* Set default bus ops */
        bridge->ops = &plda_pcie_ops;
        bridge->sysdata = pcie;
@@ -900,20 +943,40 @@ static int plda_pcie_probe(struct platform_device *pdev)
 
        plda_pcie_hw_init(pcie);
 
+       if (plda_pcie_is_link_up(pcie) == PLDA_LINK_DOWN)
+               goto release;
+
        ret = pci_host_probe(bridge);
        if (ret < 0) {
                dev_err(&pdev->dev, "Failed to pci host probe: %d\n", ret);
-               goto exit;
+               goto release;
        }
 
        if (IS_ENABLED(CONFIG_PCI_MSI)) {
                ret = plda_pcie_enable_msi(pcie, bus);
-               if (ret < 0)
+               if (ret < 0) {
                        dev_err(&pdev->dev,     "Failed to enable MSI support: %d\n", ret);
+                       goto release;
+               }
        }
 
 exit:
        return ret;
+
+release:
+       if (pcie->power_state_def &&
+           pinctrl_select_state(pcie->pinctrl, pcie->power_state_def))
+               dev_err(dev, "Cannot set power pin to low\n");
+       plda_clk_rst_deinit(pcie);
+
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+
+       pci_free_host_bridge(pcie->bridge);
+       devm_kfree(&pdev->dev, pcie);
+       platform_set_drvdata(pdev, NULL);
+
+       return ret;
 }
 
 static int plda_pcie_remove(struct platform_device *pdev)
@@ -927,6 +990,39 @@ static int plda_pcie_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int __maybe_unused plda_pcie_suspend_noirq(struct device *dev)
+{
+       struct plda_pcie *pcie = dev_get_drvdata(dev);
+
+       if (!pcie)
+               return 0;
+
+       clk_bulk_disable_unprepare(pcie->num_clks, pcie->clks);
+
+       return 0;
+}
+
+static int __maybe_unused plda_pcie_resume_noirq(struct device *dev)
+{
+       struct plda_pcie *pcie = dev_get_drvdata(dev);
+       int ret;
+
+       if (!pcie)
+               return 0;
+
+       ret = clk_bulk_prepare_enable(pcie->num_clks, pcie->clks);
+       if (ret)
+               dev_err(dev, "Failed to enable clocks\n");
+
+       return ret;
+}
+
+static const struct dev_pm_ops plda_pcie_pm_ops = {
+       SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(plda_pcie_suspend_noirq,
+                                     plda_pcie_resume_noirq)
+};
+#endif
 
 static const struct of_device_id plda_pcie_of_match[] = {
        { .compatible = "plda,pci-xpressrich3-axi"},
@@ -939,6 +1035,9 @@ static struct platform_driver plda_pcie_driver = {
        .driver = {
                .name = KBUILD_MODNAME,
                .of_match_table = of_match_ptr(plda_pcie_of_match),
+#ifdef CONFIG_PM_SLEEP
+               .pm = &plda_pcie_pm_ops,
+#endif
        },
        .probe = plda_pcie_probe,
        .remove = plda_pcie_remove,
index 1e7a20b..d7adf8b 100755 (executable)
@@ -1666,6 +1666,7 @@ static int starfive_jh7110_pinctrl_probe(struct platform_device *pdev)
 static struct platform_driver starfive_jh7110_pinctrl_driver = {
        .driver = {
                .name = "starfive_jh7110-pinctrl",
+               .pm = &starfive_pinctrl_pm_ops,
                .of_match_table = of_match_ptr(starfive_jh7110_pinctrl_of_match),
        },
        .probe = starfive_jh7110_pinctrl_probe,
index 85cfaf0..746e6ce 100644 (file)
@@ -8,6 +8,7 @@
 #include <dt-bindings/pwm/pwm.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/pwm.h>
 #include <linux/slab.h>
 #include <linux/clk.h>
@@ -78,19 +79,23 @@ static void starfive_pwm_ptc_get_state(struct pwm_chip *chip,
                                       struct pwm_state *state)
 {
        struct starfive_pwm_ptc_device *pwm = chip_to_starfive_ptc(chip);
-       u32 data_lrc;
-       u32 data_hrc;
+       u32 data_lrc, data_hrc, data_ctrl;
        u32 pwm_clk_ns = 0;
 
+       pm_runtime_get_sync(chip->dev);
+
        data_lrc = ioread32(REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm));
        data_hrc = ioread32(REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm));
+       data_ctrl = ioread32(REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm));
 
        pwm_clk_ns = NS_PER_SECOND / pwm->approx_freq;
 
        state->period = data_lrc * pwm_clk_ns;
        state->duty_cycle = data_hrc * pwm_clk_ns;
        state->polarity = PWM_POLARITY_NORMAL;
-       state->enabled = 1;
+       state->enabled = (data_ctrl & PTC_EN) ? true : false;
+
+       pm_runtime_put(chip->dev);
 }
 
 static int starfive_pwm_ptc_apply(struct pwm_chip *chip,
@@ -105,6 +110,24 @@ static int starfive_pwm_ptc_apply(struct pwm_chip *chip,
        s64 multi = pwm->approx_freq;
        s64 div = NS_PER_SECOND;
        void __iomem *reg_addr;
+       u32 val;
+
+       if (state->enabled) {
+               if (!pwm_is_enabled(dev)) {
+                       pm_runtime_get_sync(chip->dev);
+                       reg_addr = REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm);
+                       val = ioread32(reg_addr);
+                       iowrite32(val | PTC_EN | PTC_OE, reg_addr);
+               }
+       } else if (pwm_is_enabled(dev)) {
+               reg_addr = REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm);
+               val = ioread32(reg_addr);
+               iowrite32(val & ~(PTC_EN | PTC_OE), reg_addr);
+               pm_runtime_put(chip->dev);
+               return 0;
+       } else {
+               return 0;
+       }
 
        if (state->duty_cycle > state->period)
                state->duty_cycle = state->period;
@@ -120,15 +143,11 @@ static int starfive_pwm_ptc_apply(struct pwm_chip *chip,
            (state->period > 0 && period_data == 0))
                period_data += 1;
 
-       if (state->enabled) {
-               duty_data = (u32)(state->duty_cycle * multi / div);
-               if (abs(duty_data * div / multi - state->duty_cycle)
-                   > abs((duty_data + 1) * div / multi - state->duty_cycle) ||
-                   (state->duty_cycle > 0 && duty_data == 0))
-                       duty_data += 1;
-       } else {
-               duty_data = 0;
-       }
+       duty_data = (u32)(state->duty_cycle * multi / div);
+       if (abs(duty_data * div / multi - state->duty_cycle)
+           > abs((duty_data + 1) * div / multi - state->duty_cycle) ||
+           (state->duty_cycle > 0 && duty_data == 0))
+               duty_data += 1;
 
        if (state->polarity == PWM_POLARITY_NORMAL)
                data_hrc = period_data - duty_data;
@@ -146,9 +165,6 @@ static int starfive_pwm_ptc_apply(struct pwm_chip *chip,
        reg_addr = REG_PTC_RPTC_CNTR(pwm->regs, dev->hwpwm);
        iowrite32(0, reg_addr);
 
-       reg_addr = REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm);
-       iowrite32(PTC_EN | PTC_OE, reg_addr);
-
        return 0;
 }
 
@@ -201,14 +217,6 @@ static int starfive_pwm_ptc_probe(struct platform_device *pdev)
                return PTR_ERR(pwm->rst);
        }
 
-       ret = clk_prepare_enable(pwm->clk);
-       if (ret) {
-               dev_err(dev,
-                       "Failed to enable pwm clock, %d\n", ret);
-               return ret;
-       }
-       reset_control_deassert(pwm->rst);
-
        ret = of_property_read_u32(node, "starfive,approx-freq",
                                   &clk_apb_freq);
        if (!ret)
@@ -232,6 +240,8 @@ static int starfive_pwm_ptc_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, pwm);
 
+       pm_runtime_enable(dev);
+
        return 0;
 }
 
@@ -243,9 +253,45 @@ static int starfive_pwm_ptc_remove(struct platform_device *dev)
        clk_disable_unprepare(pwm->clk);
        pwmchip_remove(chip);
 
+       pm_runtime_disable(&dev->dev);
+
        return 0;
 }
 
+#if defined(CONFIG_PM) || defined(CONFIG_PM_SLEEP)
+static int __maybe_unused starfive_pwm_runtime_suspend(struct device *dev)
+{
+       struct starfive_pwm_ptc_device *pwm = dev_get_drvdata(dev);
+
+       dev_dbg(dev, "starfive pwm runtime suspending..");
+       reset_control_assert(pwm->rst);
+       clk_disable_unprepare(pwm->clk);
+
+       return 0;
+}
+
+static int __maybe_unused starfive_pwm_runtime_resume(struct device *dev)
+{
+       struct starfive_pwm_ptc_device *pwm = dev_get_drvdata(dev);
+       int ret;
+
+       dev_dbg(dev, "starfive pwm runtime resuming..");
+       ret = clk_prepare_enable(pwm->clk);
+       if (ret)
+               dev_err(dev,
+                       "Failed to resume pwm clock, %d\n", ret);
+       reset_control_deassert(pwm->rst);
+       return ret;
+}
+#endif
+
+static const struct dev_pm_ops starfive_pwm_pm_ops = {
+       SET_RUNTIME_PM_OPS(starfive_pwm_runtime_suspend,
+                          starfive_pwm_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
+};
+
 static const struct of_device_id starfive_pwm_ptc_of_match[] = {
        { .compatible = "starfive,jh7110-pwm" },
        {},
@@ -258,6 +304,7 @@ static struct platform_driver starfive_pwm_ptc_driver = {
        .driver = {
                .name = "pwm-starfive-ptc",
                .of_match_table = of_match_ptr(starfive_pwm_ptc_of_match),
+               .pm = &starfive_pwm_pm_ops,
        },
 };
 module_platform_driver(starfive_pwm_ptc_driver);
index b650eee..0bc8df0 100644 (file)
@@ -178,6 +178,14 @@ config REGULATOR_ATC260X
          ATC260x PMICs. This will enable support for all the software
          controllable DCDC/LDO regulators.
 
+config REGULATOR_AXP15060
+       tristate "X-POWERS AXP15060 PMIC Regulators"
+       depends on I2C
+       select REGMAP_I2C
+       help
+         This driver provides support for the voltage regulators on the
+         AXP15060 PMIC.
+
 config REGULATOR_AXP20X
        tristate "X-POWERS AXP20X PMIC Regulators"
        depends on MFD_AXP20X
index 3220029..927a16d 100644 (file)
@@ -27,6 +27,7 @@ obj-$(CONFIG_REGULATOR_ARM_SCMI) += scmi-regulator.o
 obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o
 obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o
 obj-$(CONFIG_REGULATOR_ATC260X) += atc260x-regulator.o
+obj-$(CONFIG_REGULATOR_AXP15060) += axp15060-regulator.o
 obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o
 obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o
 obj-$(CONFIG_REGULATOR_BD71815)        += bd71815-regulator.o
diff --git a/drivers/regulator/axp15060-regulator.c b/drivers/regulator/axp15060-regulator.c
new file mode 100644 (file)
index 0000000..fa3abee
--- /dev/null
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 Starfive Technology Co., Ltd.
+ * Author: Kevin Xie <kevin.xie@starfivetech.com>
+ */
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/axp15060.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+
+#define AXP15060_ON_OFF_CTRL_1         0x10
+#define AXP15060_ON_OFF_CTRL_2         0x11
+#define AXP15060_ON_OFF_CTRL_3         0x12
+#define AXP15060_VOL_CTRL_DCDC_1       0x13
+#define AXP15060_VOL_CTRL_DCDC_2       0x14
+#define AXP15060_VOL_CTRL_DCDC_3       0x15
+#define AXP15060_VOL_CTRL_DCDC_4       0x16
+#define AXP15060_VOL_CTRL_DCDC_5       0x17
+#define AXP15060_VOL_CTRL_DCDC_6       0x18
+#define AXP15060_VOL_CTRL_ALDO_1       0x19
+#define AXP15060_DCDC_MODE_CTRL_1      0x1A
+#define AXP15060_DCDC_MODE_CTRL_2      0x1B
+
+#define AXP15060_OUTPUT_MONITOR_OFF_DISCHARGE  0x1E
+#define AXP15060_IRQ_PWROK_VOFF_SETTING                0x1F
+#define AXP15060_VOL_CTRL_ALDO_2       0x20
+#define AXP15060_VOL_CTRL_ALDO_3       0x21
+#define AXP15060_VOL_CTRL_ALDO_4       0x22
+#define AXP15060_VOL_CTRL_ALDO_5       0x23
+#define AXP15060_VOL_CTRL_BLDO_1       0x24
+#define AXP15060_VOL_CTRL_BLDO_2       0x25
+#define AXP15060_VOL_CTRL_BLDO_3       0x26
+#define AXP15060_VOL_CTRL_BLDO_4       0x27
+#define AXP15060_VOL_CTRL_BLDO_5       0x28
+#define AXP15060_VOL_CTRL_CLDO_1       0x29
+#define AXP15060_VOL_CTRL_CLDO_2       0x2A
+/* CLDO3 voltage ctrl and CLDO3/GPIO1/Wakeup ctrl */
+#define AXP15060_VOL_CTRL_CLDO_3       0x2B
+#define AXP15060_CLDO_4_GPIO_2_CTRL    0x2C
+#define AXP15060_VOL_CTRL_CLDO_4       0x2D
+#define AXP15060_VOL_CTRL_CPUSLDO      0x2E
+
+#define AXP15060_PWR_WAKEUP_CTRL       0x31
+/* Power disable and power down sequence */
+#define AXP15060_PWR_DISABLE           0x32
+
+#define AXP15060_POK_SETTING           0x36
+
+#define AXP15060_INTERFACE_MODE_SEL    0x3E
+
+#define AXP15060_IRQ_ENABLE_1          0x40
+#define AXP15060_IRQ_ENABLE_2          0x41
+
+#define AXP15060_IRQ_STATUS_1          0x48
+#define AXP15060_IRQ_STATUS_2          0x49
+
+/* AXP15060_ON_OFF_CTRL_1 */
+#define AXP15060_PWR_OUT_DCDC1_MASK            BIT(0)
+#define AXP15060_PWR_OUT_DCDC2_MASK            BIT(1)
+#define AXP15060_PWR_OUT_DCDC3_MASK            BIT(2)
+#define AXP15060_PWR_OUT_DCDC4_MASK            BIT(3)
+#define AXP15060_PWR_OUT_DCDC5_MASK            BIT(4)
+#define AXP15060_PWR_OUT_DCDC6_MASK            BIT(5)
+
+/* AXP15060_ON_OFF_CTRL_2 */
+#define AXP15060_PWR_OUT_ALDO1_MASK            BIT(0)
+#define AXP15060_PWR_OUT_ALDO2_MASK            BIT(1)
+#define AXP15060_PWR_OUT_ALDO3_MASK            BIT(2)
+#define AXP15060_PWR_OUT_ALDO4_MASK            BIT(3)
+#define AXP15060_PWR_OUT_ALDO5_MASK            BIT(4)
+#define AXP15060_PWR_OUT_BLDO1_MASK            BIT(5)
+#define AXP15060_PWR_OUT_BLDO2_MASK            BIT(6)
+#define AXP15060_PWR_OUT_BLDO3_MASK            BIT(7)
+
+/* AXP15060_ON_OFF_CTRL_3 */
+#define AXP15060_PWR_OUT_BLDO4_MASK            BIT(0)
+#define AXP15060_PWR_OUT_BLDO5_MASK            BIT(1)
+#define AXP15060_PWR_OUT_CLDO1_MASK            BIT(2)
+#define AXP15060_PWR_OUT_CLDO2_MASK            BIT(3)
+#define AXP15060_PWR_OUT_CLDO3_MASK            BIT(4)
+#define AXP15060_PWR_OUT_CLDO4_MASK            BIT(5)
+#define AXP15060_PWR_OUT_CPULDO_MASK           BIT(6)
+#define AXP15060_PWR_OUT_SWITCH_MASK           BIT(7)
+
+#define AXP15060_ALDO1_V_OUT_MASK              GENMASK(4, 0)
+#define AXP15060_ALDO2_V_OUT_MASK              GENMASK(4, 0)
+#define AXP15060_ALDO3_V_OUT_MASK              GENMASK(4, 0)
+#define AXP15060_ALDO4_V_OUT_MASK              GENMASK(4, 0)
+#define AXP15060_ALDO5_V_OUT_MASK              GENMASK(4, 0)
+
+#define AXP15060_BLDO1_V_OUT_MASK              GENMASK(4, 0)
+#define AXP15060_BLDO2_V_OUT_MASK              GENMASK(4, 0)
+#define AXP15060_BLDO3_V_OUT_MASK              GENMASK(4, 0)
+#define AXP15060_BLDO4_V_OUT_MASK              GENMASK(4, 0)
+#define AXP15060_BLDO5_V_OUT_MASK              GENMASK(4, 0)
+
+#define AXP15060_CLDO1_V_OUT_MASK              GENMASK(4, 0)
+#define AXP15060_CLDO2_V_OUT_MASK              GENMASK(4, 0)
+#define AXP15060_CLDO3_V_OUT_MASK              GENMASK(4, 0)
+#define AXP15060_CLDO4_V_OUT_MASK              GENMASK(5, 0)
+#define AXP15060_CPUSLDO_V_OUT_MASK            GENMASK(3, 0)
+
+#define AXP15060_DCDC1_V_OUT_MASK              GENMASK(4, 0)
+/* DCDC2 bit7 is set by fw, which is different from datasheet desc. */
+#define AXP15060_DCDC2_V_OUT_MASK              GENMASK(7, 0)
+#define AXP15060_DCDC3_V_OUT_MASK              GENMASK(6, 0)
+#define AXP15060_DCDC4_V_OUT_MASK              GENMASK(6, 0)
+#define AXP15060_DCDC5_V_OUT_MASK              GENMASK(6, 0)
+#define AXP15060_DCDC6_V_OUT_MASK              GENMASK(4, 0)
+
+#define AXP15060_DCDC2_V_OUT_RANGE1_7bit_500mV_START           0x00
+#define AXP15060_DCDC2_V_OUT_RANGE1_7bit_1200mV_END            0x46
+#define AXP15060_DCDC2_V_OUT_RANGE2_7bit_1220mV_START          0x47
+#define AXP15060_DCDC2_V_OUT_RANGE2_7bit_1540mV_END            0x57
+#define AXP15060_DCDC2_V_OUT_RANGE1_500mV_START                        0x80
+#define AXP15060_DCDC2_V_OUT_RANGE1_1200mV_END                 0xC6
+#define AXP15060_DCDC2_V_OUT_RANGE2_1220mV_START               0xC7
+#define AXP15060_DCDC2_V_OUT_RANGE2_1540mV_END                 0xD7
+#define AXP15060_DCDC2_NUM_VOLTAGES                                    \
+                               (AXP15060_DCDC2_V_OUT_RANGE2_1540mV_END + 1)
+
+static const struct linear_range axp15060_dcdc2_ranges[] = {
+       REGULATOR_LINEAR_RANGE(500000,
+                               AXP15060_DCDC2_V_OUT_RANGE1_7bit_500mV_START,
+                               AXP15060_DCDC2_V_OUT_RANGE1_7bit_1200mV_END,
+                               10000),
+       REGULATOR_LINEAR_RANGE(1220000,
+                               AXP15060_DCDC2_V_OUT_RANGE2_7bit_1220mV_START,
+                               AXP15060_DCDC2_V_OUT_RANGE2_7bit_1540mV_END,
+                               20000),
+       REGULATOR_LINEAR_RANGE(500000,
+                               AXP15060_DCDC2_V_OUT_RANGE1_500mV_START,
+                               AXP15060_DCDC2_V_OUT_RANGE1_1200mV_END,
+                               10000),
+       REGULATOR_LINEAR_RANGE(1220000,
+                               AXP15060_DCDC2_V_OUT_RANGE2_1220mV_START,
+                               AXP15060_DCDC2_V_OUT_RANGE2_1540mV_END,
+                               20000),
+};
+
+static const struct regmap_range axp15060_writeable_ranges[] = {
+       regmap_reg_range(AXP15060_ON_OFF_CTRL_1, AXP15060_DCDC_MODE_CTRL_2),
+       regmap_reg_range(AXP15060_OUTPUT_MONITOR_OFF_DISCHARGE,
+                                       AXP15060_VOL_CTRL_CPUSLDO),
+       regmap_reg_range(AXP15060_PWR_WAKEUP_CTRL, AXP15060_PWR_DISABLE),
+       regmap_reg_range(AXP15060_POK_SETTING, AXP15060_POK_SETTING),
+       regmap_reg_range(AXP15060_INTERFACE_MODE_SEL, AXP15060_INTERFACE_MODE_SEL),
+       regmap_reg_range(AXP15060_IRQ_ENABLE_1, AXP15060_IRQ_ENABLE_2),
+       regmap_reg_range(AXP15060_IRQ_STATUS_1, AXP15060_IRQ_STATUS_2),
+};
+
+static const struct regmap_access_table axp15060_writeable_table = {
+       .yes_ranges     = axp15060_writeable_ranges,
+       .n_yes_ranges   = ARRAY_SIZE(axp15060_writeable_ranges),
+};
+
+static const struct regmap_config axp15060_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .wr_table       = &axp15060_writeable_table,
+       .max_register = AXP15060_IRQ_STATUS_2,
+       .cache_type = REGCACHE_NONE,
+};
+
+static const struct regulator_ops axp15060_fixed_ops = {
+       .list_voltage           = regulator_list_voltage_linear,
+};
+
+static const struct regulator_ops axp15060_sw_ops = {
+       .enable                 = regulator_enable_regmap,
+       .disable                = regulator_disable_regmap,
+       .is_enabled             = regulator_is_enabled_regmap,
+};
+
+static const struct regulator_ops axp15060_ops = {
+       .set_voltage_sel        = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel        = regulator_get_voltage_sel_regmap,
+       .list_voltage           = regulator_list_voltage_linear,
+       .enable                 = regulator_enable_regmap,
+       .disable                = regulator_disable_regmap,
+       .is_enabled             = regulator_is_enabled_regmap,
+};
+
+static const struct regulator_ops axp15060_range_ops = {
+       .set_voltage_sel                = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel                = regulator_get_voltage_sel_regmap,
+       .set_voltage_time_sel           = regulator_set_voltage_time_sel,
+       .list_voltage                   = regulator_list_voltage_linear_range,
+       .enable                         = regulator_enable_regmap,
+       .disable                        = regulator_disable_regmap,
+       .is_enabled                     = regulator_is_enabled_regmap,
+};
+
+#define AXP15060_DESC_FIXED(_id, _match, _volt)                                        \
+       {                                                                       \
+               .name           = (_match),                                     \
+               .of_match       = of_match_ptr(_match),                         \
+               .regulators_node = of_match_ptr("regulators"),                  \
+               .type           = REGULATOR_VOLTAGE,                            \
+               .id             = AXP15060_ID_##_id,                            \
+               .n_voltages     = 1,                                            \
+               .owner          = THIS_MODULE,                                  \
+               .min_uV         = (_volt) * 1000,                               \
+               .ops            = &axp15060_fixed_ops,                          \
+       }
+
+#define AXP_DESC_SW(_id, _match, _ereg, _emask)                                        \
+       {                                                                       \
+               .name           = (_match),                                     \
+               .of_match       = of_match_ptr(_match),                         \
+               .regulators_node = of_match_ptr("regulators"),                  \
+               .type           = REGULATOR_VOLTAGE,                            \
+               .id             = AXP15060_ID_##_id,                            \
+               .owner          = THIS_MODULE,                                  \
+               .enable_reg     = (_ereg),                                      \
+               .enable_mask    = (_emask),                                     \
+               .ops            = &axp15060_sw_ops,                             \
+       }
+
+#define AXP15060_DESC(_id, _match, _min, _max, _step, _vreg,                   \
+               _vmask, _ereg, _emask)                                          \
+       {                                                                       \
+               .name           = (_match),                                     \
+               .of_match       = of_match_ptr(_match),                         \
+               .regulators_node = of_match_ptr("regulators"),                  \
+               .type           = REGULATOR_VOLTAGE,                            \
+               .id             = AXP15060_ID_##_id,                            \
+               .n_voltages     = (((_max) - (_min)) / (_step) + 1),            \
+               .owner          = THIS_MODULE,                                  \
+               .min_uV         = (_min) * 1000,                                \
+               .uV_step        = (_step) * 1000,                               \
+               .vsel_reg       = (_vreg),                                      \
+               .vsel_mask      = (_vmask),                                     \
+               .enable_reg     = (_ereg),                                      \
+               .enable_mask    = (_emask),                                     \
+               .ops            = &axp15060_ops,                                \
+       }
+
+#define AXP15060_DESC_RANGES(_id, _match, _ranges, _n_voltages,\
+                                        _vreg, _vmask, _ereg, _emask)          \
+       {                                                                       \
+               .name                   = (_match),                             \
+               .of_match               = of_match_ptr(_match),                 \
+               .regulators_node        = of_match_ptr("regulators"),           \
+               .type                   = REGULATOR_VOLTAGE,                    \
+               .id                     = AXP15060_ID_##_id,                    \
+               .n_voltages             = (_n_voltages),                        \
+               .owner                  = THIS_MODULE,                          \
+               .vsel_reg               = (_vreg),                              \
+               .vsel_mask              = (_vmask),                             \
+               .enable_reg             = (_ereg),                              \
+               .enable_mask            = (_emask),                             \
+               .linear_ranges          = (_ranges),                            \
+               .n_linear_ranges        = ARRAY_SIZE(_ranges),                  \
+               .ops                    = &axp15060_range_ops,                  \
+       }
+/* Only register the regulators that needed to be controlled(onoff/vol) */
+static const struct regulator_desc axp15060_regulators[] = {
+       AXP15060_DESC(ALDO1, "mipi_0p9", 700, 3300, 100,
+                       AXP15060_VOL_CTRL_ALDO_1, AXP15060_ALDO1_V_OUT_MASK,
+                       AXP15060_ON_OFF_CTRL_2, AXP15060_PWR_OUT_ALDO1_MASK),
+
+       AXP15060_DESC(ALDO3, "hdmi_1p8", 700, 3300, 100,
+                       AXP15060_VOL_CTRL_ALDO_3, AXP15060_ALDO3_V_OUT_MASK,
+                       AXP15060_ON_OFF_CTRL_2, AXP15060_PWR_OUT_ALDO3_MASK),
+
+       AXP15060_DESC(ALDO4, "sdio_vdd", 700, 3300, 100,
+                       AXP15060_VOL_CTRL_ALDO_4, AXP15060_ALDO4_V_OUT_MASK,
+                       AXP15060_ON_OFF_CTRL_2, AXP15060_PWR_OUT_ALDO4_MASK),
+
+       AXP15060_DESC(ALDO5, "hdmi_0p9", 700, 3300, 100,
+                       AXP15060_VOL_CTRL_ALDO_5, AXP15060_ALDO5_V_OUT_MASK,
+                       AXP15060_ON_OFF_CTRL_2, AXP15060_PWR_OUT_ALDO5_MASK),
+
+       AXP15060_DESC_RANGES(DCDC2, "cpu_vdd",
+                               axp15060_dcdc2_ranges, AXP15060_DCDC2_NUM_VOLTAGES,
+                               AXP15060_VOL_CTRL_DCDC_2, AXP15060_DCDC2_V_OUT_MASK,
+                               AXP15060_ON_OFF_CTRL_1, AXP15060_PWR_OUT_DCDC2_MASK),
+};
+
+static struct of_regulator_match axp15060_matches[] = {
+       { .name = "mipi_0p9", },
+       { .name = "hdmi_1p8", },
+       { .name = "sdio_vdd", },
+       { .name = "hdmi_0p9", },
+       { .name = "cpu_vdd", },
+};
+
+static int axp15060_i2c_probe(struct i2c_client *i2c)
+{
+       struct regulator_config config = { };
+       struct regulator_dev *rdev;
+       struct device_node *np, *regulators;
+       struct regmap *regmap;
+       int i, ret;
+
+       np = of_node_get(i2c->dev.of_node);
+       if (!np)
+               return -EINVAL;
+
+       regulators = of_get_child_by_name(np, "regulators");
+       if (!regulators) {
+               dev_err(&i2c->dev, "Regulators node not found\n");
+               return -EINVAL;
+       }
+
+       i = of_regulator_match(&i2c->dev, regulators, axp15060_matches,
+                                ARRAY_SIZE(axp15060_matches));
+       of_node_put(i2c->dev.of_node);
+       if (i < 0) {
+               dev_err(&i2c->dev, "Failed to match regulators\n");
+               return -EINVAL;
+       }
+
+       regmap = devm_regmap_init_i2c(i2c, &axp15060_regmap_config);
+       if (IS_ERR(regmap)) {
+               ret = PTR_ERR(regmap);
+               dev_err(&i2c->dev, "Failed to allocate register map: %d\n", ret);
+               return ret;
+       }
+
+       for (i = 0; i < AXP15060_MAX_REGULATORS; i++) {
+               config.dev = &i2c->dev;
+               config.regmap = regmap;
+               config.init_data = axp15060_matches[i].init_data;
+
+               rdev = devm_regulator_register(&i2c->dev,
+                       &axp15060_regulators[i], &config);
+               if (IS_ERR(rdev)) {
+                       dev_err(&i2c->dev,
+                               "Failed to register AXP15060 regulator\n");
+                       return PTR_ERR(rdev);
+               }
+               dev_info(&i2c->dev, "Register %s done! vol range:%d ~ %d mV\n",
+                               rdev->desc->name,
+                               (rdev->constraints->min_uV) / 1000,
+                               (rdev->constraints->max_uV) / 1000);
+       }
+
+       return 0;
+}
+
+static const struct i2c_device_id axp15060_i2c_id[] = {
+       {"axp15060_reg", 0},
+       {},
+};
+MODULE_DEVICE_TABLE(i2c, axp15060_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id axp15060_dt_ids[] = {
+       { .compatible = "stf,axp15060-regulator",
+         .data = &axp15060_i2c_id[0] },
+       {},
+};
+MODULE_DEVICE_TABLE(of, axp15060_dt_ids);
+#endif
+
+static struct i2c_driver axp15060_regulator_driver = {
+       .driver = {
+               .name = "axp15060-regulator",
+               .of_match_table = of_match_ptr(axp15060_dt_ids),
+       },
+       .probe_new = axp15060_i2c_probe,
+       .id_table = axp15060_i2c_id,
+};
+
+module_i2c_driver(axp15060_regulator_driver);
+
+MODULE_AUTHOR("Kevin Xie <kevin.xie@starfivetech.com>");
+MODULE_DESCRIPTION("Regulator device driver for X-Powers AXP15060");
+MODULE_LICENSE("GPL v2");
index 15872c6..895960f 100644 (file)
@@ -575,6 +575,7 @@ static int sft_rtc_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct sft_rtc *srtc;
        struct rtc_time tm;
+       struct irq_desc *desc;
        int ret;
 
        srtc = devm_kzalloc(dev, sizeof(*srtc), GFP_KERNEL);
@@ -639,6 +640,9 @@ static int sft_rtc_probe(struct platform_device *pdev)
        srtc->rtc_dev->ops = &starfive_rtc_ops;
        device_init_wakeup(dev, true);
 
+       desc = irq_to_desc(srtc->rtc_irq);
+       irq_desc_get_chip(desc)->flags = IRQCHIP_SKIP_SET_WAKE;
+
        /* Always use 24-hour mode and keep the RTC values */
        sft_rtc_set_mode(srtc, RTC_HOUR_MODE_24H);
 
@@ -725,7 +729,7 @@ static struct platform_driver starfive_rtc_driver = {
        .driver = {
                .name = "starfive-rtc",
                .of_match_table = sft_rtc_of_match,
-               .pm = &sft_rtc_pm_ops,
+               .pm   = &sft_rtc_pm_ops,
        },
        .probe = sft_rtc_probe,
        .remove = sft_rtc_remove,
index c783cc9..1e08aae 100755 (executable)
@@ -669,7 +669,6 @@ static void load_ssp_default_config(struct pl022 *pl022)
  */
 static void readwriter(struct pl022 *pl022)
 {
-
        /*
         * The FIFO depth is different between primecell variants.
         * I believe filling in too much in the FIFO might cause
@@ -2156,10 +2155,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
        master->cleanup = pl022_cleanup;
        master->setup = pl022_setup;
        /* If open CONFIG_PM, auto_runtime_pm should be false when of-platform.*/
-       if (platform_flag)
-               master->auto_runtime_pm = false;
-       else
-               master->auto_runtime_pm = true;
+       master->auto_runtime_pm = true;
        master->transfer_one_message = pl022_transfer_one_message;
        master->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware;
        master->rt = platform_info->rt;
@@ -2267,6 +2263,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
 
        /* Register with the SPI framework */
        amba_set_drvdata(adev, pl022);
+
        if (platform_flag)
                status = spi_register_master(master);
        else
@@ -2277,7 +2274,8 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
                goto err_spi_register;
        }
        dev_dbg(dev, "probe succeeded\n");
-
+       if (!platform_flag)
+               platform_info->autosuspend_delay = 100;
        /* let runtime pm put suspend */
        if (platform_info->autosuspend_delay > 0) {
                dev_info(&adev->dev,
@@ -2287,7 +2285,10 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
                        platform_info->autosuspend_delay);
                pm_runtime_use_autosuspend(dev);
        }
-       pm_runtime_put(dev);
+       if (platform_flag)
+               clk_disable_unprepare(pl022->clk);
+       else
+               pm_runtime_put(dev);
 
        return 0;
 
@@ -2359,7 +2360,8 @@ static int pl022_suspend(struct device *dev)
 
        pinctrl_pm_select_sleep_state(dev);
 
-       dev_dbg(dev, "suspended\n");
+       dev_dbg(dev, "starfive spi suspended\n");
+
        return 0;
 }
 
@@ -2375,7 +2377,7 @@ static int pl022_resume(struct device *dev)
        /* Start the queue running */
        ret = spi_master_resume(pl022->master);
        if (!ret)
-               dev_dbg(dev, "resumed\n");
+               dev_dbg(dev, "starfive spi resumed\n");
 
        return ret;
 }
@@ -2389,6 +2391,8 @@ static int pl022_runtime_suspend(struct device *dev)
        clk_disable_unprepare(pl022->clk);
        pinctrl_pm_select_idle_state(dev);
 
+       dev_dbg(dev, "starfive spi runtime suspend");
+
        return 0;
 }
 
@@ -2399,6 +2403,7 @@ static int pl022_runtime_resume(struct device *dev)
        pinctrl_pm_select_default_state(dev);
        clk_prepare_enable(pl022->clk);
 
+       dev_dbg(dev, "stafive spi runtime resume");
        return 0;
 }
 #endif
@@ -2553,12 +2558,17 @@ static int starfive_of_pl022_probe(struct platform_device *pdev)
        if (ret)
                goto err_probe;
 
-       pm_runtime_get_noresume(dev);
-       pm_runtime_set_active(dev);
-       pm_runtime_enable(dev);
-
        ret = pl022_probe(pcdev, &id);
 
+       struct pl022 *pl022 = amba_get_drvdata(pcdev);
+
+       pl022->master->dev.parent = &pdev->dev;
+       platform_set_drvdata(pdev, pl022);
+
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_set_autosuspend_delay(&pdev->dev, 100);
+       pm_runtime_use_autosuspend(&pdev->dev);
+
        if (ret) {
                pm_runtime_disable(dev);
                pm_runtime_set_suspended(dev);
@@ -2597,6 +2607,8 @@ static int starfive_of_pl022_remove(struct platform_device *pdev)
        size = resource_size(pdev->resource);
        release_mem_region(pdev->resource->start, size);
        tasklet_disable(&pl022->pump_transfers);
+       pm_runtime_disable(&pdev->dev);
+
        return 0;
 }
 
index 7d0545a..9d1147b 100644 (file)
@@ -298,6 +298,10 @@ static int cdns_starfive_probe(struct platform_device *pdev)
                goto exit;
        }
 
+       device_set_wakeup_capable(dev, true);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+
        dev_info(dev, "usb mode %d %s probe success\n",
                data->mode, data->usb2_only ? "2.0" : "3.0");
 
@@ -318,14 +322,55 @@ static int cdns_starfive_remove_core(struct device *dev, void *c)
 static int cdns_starfive_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
+       struct cdns_starfive *data = dev_get_drvdata(dev);
 
+       pm_runtime_get_sync(dev);
        device_for_each_child(dev, NULL, cdns_starfive_remove_core);
 
+       reset_control_assert(data->resets);
+       clk_bulk_disable_unprepare(data->num_clks, data->clks);
+       pm_runtime_disable(dev);
+       pm_runtime_put_noidle(dev);
        platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int cdns_starfive_resume(struct device *dev)
+{
+       struct cdns_starfive *data = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_set_rate(data->usb_125m_clk, USB_125M_CLK_RATE);
+       if (ret)
+               goto err;
+
+       ret = clk_bulk_prepare_enable(data->num_clks, data->clks);
+       if (ret)
+               goto err;
+
+       ret = reset_control_deassert(data->resets);
+err:
+       return ret;
+}
+
+static int cdns_starfive_suspend(struct device *dev)
+{
+       struct cdns_starfive *data = dev_get_drvdata(dev);
+
+       clk_bulk_disable_unprepare(data->num_clks, data->clks);
+       reset_control_assert(data->resets);
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops cdns_starfive_pm_ops = {
+       SET_RUNTIME_PM_OPS(cdns_starfive_suspend, cdns_starfive_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(cdns_starfive_suspend, cdns_starfive_resume)
+};
+
 static const struct of_device_id cdns_starfive_of_match[] = {
        { .compatible = "starfive,jh7110-cdns3", },
        {},
@@ -338,6 +383,7 @@ static struct platform_driver cdns_starfive_driver = {
        .driver         = {
                .name   = "cdns3-starfive",
                .of_match_table = cdns_starfive_of_match,
+               .pm     = &cdns_starfive_pm_ops,
        },
 };
 
index 70588a5..4eb16c4 100755 (executable)
@@ -31,6 +31,7 @@
 #include <linux/watchdog.h>
 #include <linux/reset.h>
 #include <linux/reset-controller.h>
+#include <linux/pm_runtime.h>
 
 #define WDT_INT_DIS    BIT(0)
 #define DELAY_US       0
@@ -106,7 +107,8 @@ MODULE_PARM_DESC(tmr_atboot,
                        __MODULE_STRING(STARFIVE_WATCHDOG_ATBOOT));
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
                        __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
-MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, 0 to reboot (default 0)");
+MODULE_PARM_DESC(soft_noboot,
+       "Watchdog action, set to 1 to ignore reboots, 0 to reboot (default 0)");
 
 struct starfive_wdt_variant_t {
        u32 unlock_key;
@@ -183,10 +185,8 @@ static const struct starfive_wdt_variant drv_data_jh7110 = {
 };
 
 static const struct of_device_id starfive_wdt_match[] = {
-       { .compatible = "starfive,jh7100-wdt",
-               .data = &drv_data_jh7100 },
-       { .compatible = "starfive,jh7110-wdt",
-               .data = &drv_data_jh7110 },
+       { .compatible = "starfive,jh7100-wdt", .data = &drv_data_jh7100 },
+       { .compatible = "starfive,jh7110-wdt", .data = &drv_data_jh7110 },
        {},
 };
 MODULE_DEVICE_TABLE(of, starfive_wdt_match);
@@ -503,10 +503,22 @@ static int starfive_wdt_stop(struct watchdog_device *wdd)
        return 0;
 }
 
+static int starfive_wdt_pm_stop(struct watchdog_device *wdd)
+{
+       struct starfive_wdt *wdt = watchdog_get_drvdata(wdd);
+
+       starfive_wdt_stop(wdd);
+       pm_runtime_put(wdt->dev);
+
+       return 0;
+}
+
 static int starfive_wdt_start(struct watchdog_device *wdd)
 {
        struct starfive_wdt *wdt = watchdog_get_drvdata(wdd);
 
+       pm_runtime_get_sync(wdt->dev);
+
        spin_lock(&wdt->lock);
 
        starfive_wdt_unlock(wdt);
@@ -606,7 +618,7 @@ static const struct watchdog_info starfive_wdt_ident = {
 static const struct watchdog_ops starfive_wdt_ops = {
        .owner = THIS_MODULE,
        .start = starfive_wdt_start,
-       .stop = starfive_wdt_stop,
+       .stop = starfive_wdt_pm_stop,
        .ping = starfive_wdt_keepalive,
        .set_timeout = starfive_wdt_set_timeout,
        .restart = starfive_wdt_restart,
@@ -642,6 +654,8 @@ static int starfive_wdt_probe(struct platform_device *pdev)
        int started = 0;
        int ret;
 
+       pm_runtime_enable(dev);
+
        wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
@@ -730,15 +744,16 @@ static int starfive_wdt_probe(struct platform_device *pdev)
                 */
                starfive_wdt_stop(&wdt->wdt_device);
        }
+       clk_disable_unprepare(wdt->core_clk);
+       clk_disable_unprepare(wdt->apb_clk);
 
        platform_set_drvdata(pdev, wdt);
 
        return 0;
 
- err_unregister:
+err_unregister:
        watchdog_unregister_device(&wdt->wdt_device);
-
- err:
+err:
        return ret;
 }
 
@@ -754,6 +769,8 @@ static int starfive_wdt_remove(struct platform_device *dev)
        watchdog_unregister_device(&wdt->wdt_device);
 
        clk_disable_unprepare(wdt->core_clk);
+       clk_disable_unprepare(wdt->apb_clk);
+       pm_runtime_disable(wdt->dev);
 
        return 0;
 }
@@ -764,8 +781,7 @@ static void starfive_wdt_shutdown(struct platform_device *dev)
 
        starfive_wdt_mask_and_disable_reset(wdt, true);
 
-       starfive_wdt_stop(&wdt->wdt_device);
-
+       starfive_wdt_pm_stop(&wdt->wdt_device);
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -786,6 +802,7 @@ static int starfive_wdt_suspend(struct device *dev)
 
        /* Note that WTCNT doesn't need to be saved. */
        starfive_wdt_stop(&wdt->wdt_device);
+       pm_runtime_force_suspend(dev);
 
        starfive_wdt_lock(wdt);
 
@@ -803,20 +820,48 @@ static int starfive_wdt_resume(struct device *dev)
        /* Restore watchdog state. */
        starfive_wdt_set_relod_count(wdt, wdt->reload);
 
+       pm_runtime_force_resume(dev);
+
+       starfive_wdt_restart(&wdt->wdt_device, 0, NULL);
+
        ret = starfive_wdt_mask_and_disable_reset(wdt, false);
        if (ret < 0)
                return ret;
 
        starfive_wdt_lock(wdt);
 
-       dev_info(dev, "watchdog resume\n")
-
        return 0;
 }
 #endif /* CONFIG_PM_SLEEP */
 
-static SIMPLE_DEV_PM_OPS(starfive_wdt_pm_ops, starfive_wdt_suspend,
-                       starfive_wdt_resume);
+#ifdef CONFIG_PM
+
+static int starfive_wdt_runtime_suspend(struct device *dev)
+{
+       struct starfive_wdt *wdt = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(wdt->apb_clk);
+       clk_disable_unprepare(wdt->core_clk);
+
+       return 0;
+}
+
+static int starfive_wdt_runtime_resume(struct device *dev)
+{
+       struct starfive_wdt *wdt = dev_get_drvdata(dev);
+
+       clk_prepare_enable(wdt->apb_clk);
+       clk_prepare_enable(wdt->core_clk);
+
+       return 0;
+}
+
+#endif /*CONFIG_PM*/
+
+static const struct dev_pm_ops starfive_wdt_pm_ops = {
+       SET_RUNTIME_PM_OPS(starfive_wdt_runtime_suspend, starfive_wdt_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(starfive_wdt_suspend, starfive_wdt_resume)
+};
 
 static struct platform_driver starfive_starfive_wdt_driver = {
        .probe          = starfive_wdt_probe,
diff --git a/include/linux/regulator/axp15060.h b/include/linux/regulator/axp15060.h
new file mode 100644 (file)
index 0000000..8456a1a
--- /dev/null
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022 Starfive Technology Co., Ltd.
+ * Author: Mason Huo <mason.huo@starfivetech.com>
+ */
+
+#ifndef __LINUX_REGULATOR_AXP15060_H
+#define __LINUX_REGULATOR_AXP15060_H
+
+/* Hide useless or always-on regulators */
+/*
+enum axp15060_reg_id {
+       AXP15060_ID_ALDO1 = 0,
+       AXP15060_ID_ALDO2,
+       AXP15060_ID_ALDO3,
+       AXP15060_ID_ALDO4,
+       AXP15060_ID_ALDO5,
+       AXP15060_ID_BLDO1,
+       AXP15060_ID_BLDO2,
+       AXP15060_ID_BLDO3,
+       AXP15060_ID_BLDO4,
+       AXP15060_ID_BLDO5,
+       AXP15060_ID_CLDO1,
+       AXP15060_ID_CLDO2,
+       AXP15060_ID_CLDO3,
+       AXP15060_ID_CLDO4,
+       AXP15060_ID_CPUSLDO,
+       AXP15060_ID_DCDC1,
+       AXP15060_ID_DCDC2,
+       AXP15060_ID_DCDC3,
+       AXP15060_ID_DCDC4,
+       AXP15060_ID_DCDC5,
+       AXP15060_ID_DCDC6,
+       AXP15060_MAX_REGULATORS,
+};
+*/
+
+enum axp15060_reg_id {
+       AXP15060_ID_ALDO1 = 0,
+       AXP15060_ID_ALDO3,
+       AXP15060_ID_ALDO4,
+       AXP15060_ID_ALDO5,
+       AXP15060_ID_DCDC2,
+       AXP15060_MAX_REGULATORS,
+};
+
+#endif /* __LINUX_REGULATOR_AXP15060_H */
old mode 100755 (executable)
new mode 100644 (file)
index b45e721..2fd8320
@@ -311,48 +311,24 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
        }
 
        if (txrx == SNDRV_PCM_STREAM_PLAYBACK) {
-               ret = clk_prepare_enable(dev->clks_dac_bclk);
-               if (ret) {
-                       dev_err(dev->dev, "%s: failed to enable clks_dac_bclk\n", __func__);
-                       return ret;
-               }
-
                ret = clk_set_parent(dev->clks_bclk, dev->clks_dac_bclk);
                if (ret) {
                        dev_err(dev->dev, "Can't set clock source for clks_bclk: %d\n", ret);
                        return ret;
                }
 
-               ret = clk_prepare_enable(dev->clks_dac_lrck);
-               if (ret) {
-                       dev_err(dev->dev, "%s: failed to enable clks_dac_lrck\n", __func__);
-                       return ret;
-               }
-
                ret = clk_set_parent(dev->clks_lrclk, dev->clks_dac_lrck);
                if (ret) {
                        dev_err(dev->dev, "Can't set clock source for clks_lrclk: %d\n", ret);
                        return ret;
                }
        } else if (txrx == SNDRV_PCM_STREAM_CAPTURE) {
-               ret = clk_prepare_enable(dev->clks[CLK_ADC_BCLK_EXT]);
-               if (ret) {
-                       dev_err(dev->dev, "%s: failed to enable CLK_ADC_BCLK_EXT\n", __func__);
-                       return ret;
-               }
-
                ret = clk_set_parent(dev->clks[CLK_ADC_RX_BCLK], dev->clks[CLK_ADC_BCLK_EXT]);
                if (ret) {
                        dev_err(dev->dev, "Can't set clock source for CLK_ADC_RX_BCLK: %d\n", ret);
                        return ret;
                }
 
-               ret = clk_prepare_enable(dev->clks[CLK_ADC_LRCK_EXT]);
-               if (ret) {
-                       dev_err(dev->dev, "%s: failed to enable CLK_ADC_LRCK_EXT\n", __func__);
-                       return ret;
-               }
-
                ret = clk_set_parent(dev->clks[CLK_ADC_RX_LRCK], dev->clks[CLK_ADC_LRCK_EXT]);
                if (ret) {
                        dev_err(dev->dev, "Can't set clock source for CLK_ADC_RX_LRCK: %d\n", ret);
@@ -480,24 +456,74 @@ static int dw_i2s_runtime_suspend(struct device *dev)
 
        if (dw_dev->capability & DW_I2S_MASTER)
                clk_disable(dw_dev->clk);
+       else {
+               if (dw_dev->capability & DWC_I2S_PLAY) {
+                       clk_disable_unprepare(dw_dev->clks_mclk_out);
+                       clk_disable_unprepare(dw_dev->clks_bclk_mst);
+                       clk_disable_unprepare(dw_dev->clks_4ch_apb);
+               } else {
+                       clk_disable_unprepare(dw_dev->clks[CLK_ADC_BCLK]);
+                       clk_disable_unprepare(dw_dev->clks[CLK_ADC_APB]);
+               }
+       }
        return 0;
 }
 
 static int dw_i2s_runtime_resume(struct device *dev)
 {
        struct dw_i2s_dev *dw_dev = dev_get_drvdata(dev);
+       int ret;
 
        if (dw_dev->capability & DW_I2S_MASTER)
                clk_enable(dw_dev->clk);
+       else {
+               if (dw_dev->capability & DWC_I2S_PLAY) {
+                       ret = clk_prepare_enable(dw_dev->clks_4ch_apb);
+                       if (ret) {
+                               dev_err(dev, "failed to enable clks_4ch_apb\n");
+                               goto failed_enable;
+                       }
+                       ret = clk_prepare_enable(dw_dev->clks_bclk_mst);
+                       if (ret) {
+                               dev_err(dev, "failed to enable clks_bclk_mst\n");
+                               goto failed_enable;
+                       }
+                       ret = clk_prepare_enable(dw_dev->clks_mclk_out);
+                       if (ret) {
+                               dev_err(dev, "failed to enable clks_mclk_out\n");
+                               goto failed_enable;
+                       }
+               } else {
+                       ret = clk_prepare_enable(dw_dev->clks[CLK_ADC_BCLK]);
+                       if (ret) {
+                               dev_err(dev, "failed to enable CLK_ADC_BCLK\n");
+                               goto failed_enable;
+                       }
+                       ret = clk_prepare_enable(dw_dev->clks[CLK_ADC_APB]);
+                       if (ret) {
+                               dev_err(dev, "failed to enable CLK_ADC_APB\n");
+                               goto failed_enable;
+                       }
+               }
+       }
        return 0;
+
+failed_enable:
+       return ret;
 }
 
 static int dw_i2s_suspend(struct snd_soc_component *component)
 {
        struct dw_i2s_dev *dev = snd_soc_component_get_drvdata(component);
+       int ret;
 
        if (dev->capability & DW_I2S_MASTER)
                clk_disable(dev->clk);
+
+       ret = pm_runtime_force_suspend(component->dev);
+       if (ret)
+               return ret;
+
        return 0;
 }
 
@@ -506,10 +532,15 @@ static int dw_i2s_resume(struct snd_soc_component *component)
        struct dw_i2s_dev *dev = snd_soc_component_get_drvdata(component);
        struct snd_soc_dai *dai;
        int stream;
+       int ret;
 
        if (dev->capability & DW_I2S_MASTER)
                clk_enable(dev->clk);
 
+       ret = pm_runtime_force_resume(component->dev);
+       if (ret)
+               return ret;
+
        for_each_component_dais(component, dai) {
                for_each_pcm_streams(stream)
                        if (snd_soc_dai_stream_active(dai, stream))
@@ -565,65 +596,30 @@ static int dw_i2srx_clk_init(struct platform_device *pdev, struct dw_i2s_dev *de
        dev->clks[CLK_ADC_BCLK_EXT] = clks[9].clk;
        dev->clks[CLK_ADC_LRCK_EXT] = clks[10].clk;
 
-       ret = clk_prepare_enable(dev->clks[CLK_ADC_APB0]);
-       if (ret) {
-               dev_err(&pdev->dev, "%s: failed to enable CLK_ADC_APB0\n", __func__);
-               goto disable_APB0_clk;
-       }
-
        ret = clk_prepare_enable(dev->clks[CLK_ADC_APB]);
        if (ret) {
                dev_err(&pdev->dev, "%s: failed to enable CLK_ADC_APB\n", __func__);
                goto disable_APB_clk;
        }
 
-       ret = clk_prepare_enable(dev->clks[CLK_ADC_AUDROOT]);
-       if (ret) {
-               dev_err(&pdev->dev, "%s: failed to enable CLK_ADC_AUDROOT\n", __func__);
-               goto disable_audroot_clk;
-       }
-
        ret = clk_set_rate(dev->clks[CLK_ADC_AUDROOT], 204800000);
        if (ret) {
                dev_err(&pdev->dev, "failed to set rate for CLK_ADC_MCLK \n");
                goto disable_audroot_clk;
        }
 
-       ret = clk_prepare_enable(dev->clks[CLK_ADC_MCLK_INNER]);
-       if (ret) {
-               dev_err(&pdev->dev, "%s: failed to enable CLK_ADC_MCLK_INNER\n", __func__);
-               goto disable_inner_clk;
-       }
-
        ret = clk_set_rate(dev->clks[CLK_ADC_MCLK_INNER], 4096000);
        if (ret) {
                dev_err(&pdev->dev, "failed to set rate for CLK_ADC_MCLK \n");
-               goto disable_inner_clk;
+               goto disable_audroot_clk;
        }
 
        ret = clk_prepare_enable(dev->clks[CLK_ADC_BCLK]);
        if (ret) {
                dev_err(&pdev->dev, "%s: failed to enable CLK_ADC_BCLK\n", __func__);
-               goto disable_bclk;
-       }
-
-       ret = clk_prepare_enable(dev->clks[CLK_ADC_LRCLK]);
-       if (ret) {
-               dev_err(&pdev->dev, "%s: failed to enable CLK_ADC_LRCLK\n", __func__);
-               goto disable_lrclk;
-       }
-
-       ret = clk_prepare_enable(dev->clks[CLK_ADC_RX_BCLK]);
-       if (ret) {
-               dev_err(&pdev->dev, "%s: failed to enable CLK_ADC_RX_BCLK\n", __func__);
-               goto disable_rx_bclk;
+               goto disable_audroot_clk;
        }
 
-       ret = clk_prepare_enable(dev->clks[CLK_ADC_RX_LRCK]);
-       if (ret) {
-               dev_err(&pdev->dev, "%s: failed to enable CLK_ADC_RX_LRCK\n", __func__);
-               goto disable_rx_lrclk;
-       }
        dev_dbg(&pdev->dev, "dev->clks[CLK_ADC_APB0] = %lu \n", clk_get_rate(dev->clks[CLK_ADC_APB0]));
        dev_dbg(&pdev->dev, "dev->clks[CLK_ADC_APB] = %lu \n", clk_get_rate(dev->clks[CLK_ADC_APB]));
        dev_dbg(&pdev->dev, "dev->clks[CLK_ADC_BCLK] = %lu \n", clk_get_rate(dev->clks[CLK_ADC_BCLK]));
@@ -634,19 +630,19 @@ static int dw_i2srx_clk_init(struct platform_device *pdev, struct dw_i2s_dev *de
        dev->rstc_rx = devm_reset_control_array_get_exclusive(&pdev->dev);
        if (IS_ERR(dev->rstc_rx)) {
                dev_err(&pdev->dev, "%s: failed to get rstc_rx reset control\n", __func__);
-               goto disable_rx_lrclk;
+               goto disable_rst;
        }
 
        ret = reset_control_assert(dev->rstc_rx);
        if (ret) {
                dev_err(&pdev->dev, "%s: failed to reset control assert rstc_rx\n", __func__);
-               goto disable_rx_lrclk;
+               goto disable_rst;
        }
        udelay(5);
        ret = reset_control_deassert(dev->rstc_rx);
        if (ret) {
                dev_err(&pdev->dev, "%s: failed to reset control deassert rstc_rx\n", __func__);
-               goto disable_rx_lrclk;
+               goto disable_rst;
        }
 
        /*i2srx_3ch_adc_enable*/
@@ -659,22 +655,11 @@ static int dw_i2srx_clk_init(struct platform_device *pdev, struct dw_i2s_dev *de
 
        return 0;
 
-disable_rx_lrclk:
-       clk_disable_unprepare(dev->clks[CLK_ADC_RX_LRCK]);
-disable_rx_bclk:
-       clk_disable_unprepare(dev->clks[CLK_ADC_RX_BCLK]);
-disable_lrclk:
-       clk_disable_unprepare(dev->clks[CLK_ADC_LRCLK]);
-disable_bclk:
+disable_rst:
        clk_disable_unprepare(dev->clks[CLK_ADC_BCLK]);
-disable_inner_clk:
-       clk_disable_unprepare(dev->clks[CLK_ADC_MCLK_INNER]);
 disable_audroot_clk:
-       clk_disable_unprepare(dev->clks[CLK_ADC_AUDROOT]);
-disable_APB_clk:
        clk_disable_unprepare(dev->clks[CLK_ADC_APB]);
-disable_APB0_clk:
-       clk_disable_unprepare(dev->clks[CLK_ADC_APB0]);
+disable_APB_clk:
 
        return ret;
 }
@@ -823,33 +808,22 @@ static int dw_i2stx_4ch1_clk_init(struct platform_device *pdev, struct dw_i2s_de
        if (IS_ERR(dev->clks_dac_lrck))
                return PTR_ERR(dev->clks_dac_lrck);
 
-       ret = clk_prepare_enable(dev->clks_audroot);
-       if (ret) {
-               dev_err(&pdev->dev, "%s: failed to enable clks_audroot\n", __func__);
-               goto disable_audioroot_clk;
-       }
        ret = clk_set_rate(dev->clks_audroot, 204800000);
        if (ret) {
                dev_err(&pdev->dev, "failed to set rate for clks_audroot ret=%d\n", ret);
                goto disable_audioroot_clk;
        }
 
-       ret = clk_prepare_enable(dev->clks_inner);
-       if (ret) {
-               dev_err(&pdev->dev, "%s: failed to enable clks_inner\n", __func__);
-               goto disable_audinner_clk;
-       }
-
        ret = clk_set_rate(dev->clks_inner, 4096000);
        if (ret) {
                dev_err(&pdev->dev, "failed to set rate for clks_inner ret=%d\n", ret);
-               goto disable_audinner_clk;
+               goto disable_audioroot_clk;
        }
 
        ret = clk_prepare_enable(dev->clks_bclk_mst);
        if (ret) {
                dev_err(&pdev->dev, "%s: failed to enable clks_bclk_mst\n", __func__);
-               goto disable_mst_bclk;
+               goto disable_audioroot_clk;
        }
 
        ret = clk_set_rate(dev->clks_bclk_mst, 1024000);
@@ -858,40 +832,10 @@ static int dw_i2stx_4ch1_clk_init(struct platform_device *pdev, struct dw_i2s_de
                goto disable_mst_bclk;
        }
 
-       ret = clk_prepare_enable(dev->clks_lrclk_mst);
-       if (ret) {
-               dev_err(&pdev->dev, "%s: failed to enable clks_lrclk_mst\n", __func__);
-               goto disable_mst_lrclk;
-       }
-
-       ret = clk_prepare_enable(dev->clks_mclk);
-       if (ret) {
-               dev_err(&pdev->dev, "%s: failed to enable clks_mclk\n", __func__);
-               goto disable_mclk;
-       }
-
-       ret = clk_prepare_enable(dev->clks_bclk);
-       if (ret) {
-               dev_err(&pdev->dev, "%s: failed to enable clks_bclk\n", __func__);
-               goto disable_bclk;
-       }
-
-       ret = clk_prepare_enable(dev->clks_lrclk);
-       if (ret) {
-               dev_err(&pdev->dev, "%s: failed to enable clks_lrclk\n", __func__);
-               goto disable_lrclk;
-       }
-
        ret = clk_prepare_enable(dev->clks_mclk_out);
        if (ret) {
                dev_err(&pdev->dev, "%s: failed to enable clks_mclk_out\n", __func__);
-               goto disable_mclk_out;
-       }
-
-       ret = clk_prepare_enable(dev->clks_apb0);
-       if (ret) {
-               dev_err(&pdev->dev, "%s: failed to enable clks_apb0\n", __func__);
-               goto disable_apb0;
+               goto disable_mst_bclk;
        }
 
        ret = clk_prepare_enable(dev->clks_4ch_apb);
@@ -900,7 +844,6 @@ static int dw_i2stx_4ch1_clk_init(struct platform_device *pdev, struct dw_i2s_de
                goto disable_4ch_apb;
        }
 
-
        dev_dbg(&pdev->dev, "dev->clks_inner = %lu \n", clk_get_rate(dev->clks_inner));
        dev_dbg(&pdev->dev, "dev->clks_bclk_mst = %lu \n", clk_get_rate(dev->clks_bclk_mst));
        dev_dbg(&pdev->dev, "dev->clks_lrclk_mst = %lu \n", clk_get_rate(dev->clks_lrclk_mst));
@@ -914,43 +857,30 @@ static int dw_i2stx_4ch1_clk_init(struct platform_device *pdev, struct dw_i2s_de
        dev->rstc_ch1 = devm_reset_control_array_get_exclusive(&pdev->dev);
        if (IS_ERR(dev->rstc_ch1)) {
                dev_err(&pdev->dev, "%s: failed to get rstc_ch1 reset control\n", __func__);
-               goto disable_4ch_apb;
+               goto disable_rst;
        }
 
        ret = reset_control_assert(dev->rstc_ch1);
        if (ret) {
                dev_err(&pdev->dev, "%s: failed to reset control assert rstc_ch1\n", __func__);
-               goto disable_4ch_apb;
+               goto disable_rst;
        }
 
        ret = reset_control_deassert(dev->rstc_ch1);
        if (ret) {
                dev_err(&pdev->dev, "%s: failed to reset control deassert rstc_ch1\n", __func__);
-               goto disable_4ch_apb;
+               goto disable_rst;
        }
 
        return 0;
 
-disable_4ch_apb:
+disable_rst:
        clk_disable_unprepare(dev->clks_4ch_apb);
-disable_apb0:
-       clk_disable_unprepare(dev->clks_apb0);
-disable_mclk_out:
+disable_4ch_apb:
        clk_disable_unprepare(dev->clks_mclk_out);
-disable_lrclk:
-       clk_disable_unprepare(dev->clks_lrclk);
-disable_bclk:
-       clk_disable_unprepare(dev->clks_bclk);
-disable_mclk:
-       clk_disable_unprepare(dev->clks_mclk);
-disable_mst_lrclk:
-       clk_disable_unprepare(dev->clks_lrclk_mst);
 disable_mst_bclk:
        clk_disable_unprepare(dev->clks_bclk_mst);
-disable_audinner_clk:
-       clk_disable_unprepare(dev->clks_inner);
 disable_audioroot_clk:
-       clk_disable_unprepare(dev->clks_audroot);
 
        return ret;
 }
@@ -1276,14 +1206,34 @@ static int dw_i2s_probe(struct platform_device *pdev)
        }
 
        pm_runtime_enable(&pdev->dev);
-       clk_disable_unprepare(dev->clks_mclk_out);
-       clk_disable_unprepare(dev->clks_bclk_mst);
-       clk_disable_unprepare(dev->clks_lrclk_mst);
+
+#ifdef CONFIG_PM
+       if (dev->capability & DWC_I2S_PLAY) {
+               clk_disable_unprepare(dev->clks_mclk_out);
+               clk_disable_unprepare(dev->clks_bclk_mst);
+               clk_disable_unprepare(dev->clks_4ch_apb);
+       } else {
+               clk_disable_unprepare(dev->clks[CLK_ADC_BCLK]);
+               clk_disable_unprepare(dev->clks[CLK_ADC_APB]);
+       }
+#endif
+
        return 0;
 
 err_clk_disable:
        if (dev->capability & DW_I2S_MASTER)
                clk_disable_unprepare(dev->clk);
+       else{
+               if (dev->capability & DWC_I2S_PLAY) {
+                       clk_disable_unprepare(dev->clks_mclk_out);
+                       clk_disable_unprepare(dev->clks_bclk_mst);
+                       clk_disable_unprepare(dev->clks_4ch_apb);
+               } else {
+                       clk_disable_unprepare(dev->clks[CLK_ADC_BCLK]);
+                       clk_disable_unprepare(dev->clks[CLK_ADC_APB]);
+               }
+       }
+
        return ret;
 }
 
index 9b2ef6e..00dbdae 100644 (file)
@@ -434,8 +434,8 @@ static int dw_i2s_runtime_suspend(struct device *dev)
        struct dw_i2s_dev *dw_dev = dev_get_drvdata(dev);
 
        if (dw_dev->capability & DW_I2S_MASTER) {
-               clk_disable_unprepare(dw_dev->clk_i2s_lrck);
-               clk_disable_unprepare(dw_dev->clk_i2s_bclk);
+               clk_disable_unprepare(dw_dev->clk_i2s_bclk_mst);
+               clk_disable_unprepare(dw_dev->clk_i2s_apb);
        }
 
        return 0;
@@ -447,13 +447,13 @@ static int dw_i2s_runtime_resume(struct device *dev)
        int ret;
 
        if (dw_dev->capability & DW_I2S_MASTER) {
-               ret = clk_prepare_enable(dw_dev->clk_i2s_bclk);
+               ret = clk_prepare_enable(dw_dev->clk_i2s_apb);
                if (ret) {
-                       dev_err(dw_dev->dev, "Failed to enable clk_i2s_bclk\n");
+                       dev_err(dw_dev->dev, "Failed to enable clk_i2s_apb\n");
                        return ret;
                }
 
-               ret = clk_prepare_enable(dw_dev->clk_i2s_lrck);
+               ret = clk_prepare_enable(dw_dev->clk_i2s_bclk_mst);
                if (ret) {
                        dev_err(dw_dev->dev, "Failed to enable clk_i2s_lrck\n");
                        return ret;
@@ -465,14 +465,7 @@ static int dw_i2s_runtime_resume(struct device *dev)
 
 static int dw_i2s_suspend(struct snd_soc_component *component)
 {
-       struct dw_i2s_dev *dev = snd_soc_component_get_drvdata(component);
-
-       if (dev->capability & DW_I2S_MASTER) {
-               clk_disable_unprepare(dev->clk_i2s_lrck);
-               clk_disable_unprepare(dev->clk_i2s_bclk);
-       }
-
-       return 0;
+       return pm_runtime_force_suspend(component->dev);
 }
 
 static int dw_i2s_resume(struct snd_soc_component *component)
@@ -482,19 +475,9 @@ static int dw_i2s_resume(struct snd_soc_component *component)
        int stream;
        int ret;
 
-       if (dev->capability & DW_I2S_MASTER) {
-               ret = clk_prepare_enable(dev->clk_i2s_bclk);
-               if (ret) {
-                       dev_err(dev->dev, "Failed to enable clk_i2s_bclk\n");
-                       return ret;
-               }
-
-               ret = clk_prepare_enable(dev->clk_i2s_lrck);
-               if (ret) {
-                       dev_err(dev->dev, "Failed to enable clk_i2s_lrck\n");
-                       return ret;
-               }
-       }
+       ret = pm_runtime_force_resume(component->dev);
+       if (ret)
+               return ret;
 
        for_each_component_dais(component, dai) {
                for_each_pcm_streams(stream)
@@ -521,7 +504,6 @@ static int dw_i2srx_clk_init(struct platform_device *pdev, struct dw_i2s_dev *de
        int ret = 0;
 
        static struct clk_bulk_data clks[] = {
-               { .id = "apb0" },
                { .id = "i2srx_apb" },
                { .id = "i2srx_bclk_mst" },
                { .id = "i2srx_lrck_mst" },
@@ -535,12 +517,11 @@ static int dw_i2srx_clk_init(struct platform_device *pdev, struct dw_i2s_dev *de
                goto exit;
        }
 
-       dev->clk_apb0 = clks[0].clk;
-       dev->clk_i2s_apb = clks[1].clk;
-       dev->clk_i2s_bclk_mst = clks[2].clk;
-       dev->clk_i2s_lrck_mst = clks[3].clk;
-       dev->clk_i2s_bclk = clks[4].clk;
-       dev->clk_i2s_lrck = clks[5].clk;
+       dev->clk_i2s_apb = clks[0].clk;
+       dev->clk_i2s_bclk_mst = clks[1].clk;
+       dev->clk_i2s_lrck_mst = clks[2].clk;
+       dev->clk_i2s_bclk = clks[3].clk;
+       dev->clk_i2s_lrck = clks[4].clk;
 
        dev->rst_i2s_apb = devm_reset_control_get_exclusive(&pdev->dev, "rst_apb_rx");
        if (IS_ERR(dev->rst_i2s_apb)) {
@@ -559,16 +540,10 @@ static int dw_i2srx_clk_init(struct platform_device *pdev, struct dw_i2s_dev *de
        reset_control_assert(dev->rst_i2s_apb);
        reset_control_assert(dev->rst_i2s_bclk);
 
-       ret = clk_prepare_enable(dev->clk_apb0);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to prepare enable clk_apb0\n");
-               goto exit;
-       }
-
        ret = clk_prepare_enable(dev->clk_i2s_apb);
        if (ret) {
                dev_err(&pdev->dev, "failed to prepare enable clk_i2srx_apb\n");
-               goto err_dis_i2srx_apb;
+               goto exit;
        }
 
        ret = clk_prepare_enable(dev->clk_i2s_bclk_mst);
@@ -577,24 +552,6 @@ static int dw_i2srx_clk_init(struct platform_device *pdev, struct dw_i2s_dev *de
                goto err_dis_bclk_mst;
        }
 
-       ret = clk_prepare_enable(dev->clk_i2s_lrck_mst);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to prepare enable clk_i2srx_3ch_lrck_mst\n");
-               goto err_dis_lrck_mst;
-       }
-
-       ret = clk_prepare_enable(dev->clk_i2s_bclk);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to prepare enable clk_i2srx_3ch_bclk\n");
-               goto err_dis_bclk;
-       }
-
-       ret = clk_prepare_enable(dev->clk_i2s_lrck);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to prepare enable clk_i2srx_3ch_lrck\n");
-               goto err_dis_lrck;
-       }
-
        reset_control_deassert(dev->rst_i2s_apb);
        reset_control_deassert(dev->rst_i2s_bclk);
 
@@ -602,16 +559,8 @@ static int dw_i2srx_clk_init(struct platform_device *pdev, struct dw_i2s_dev *de
                                I2SRX_3CH_ADC_MASK, I2SRX_3CH_ADC_EN);
        return 0;
 
-err_dis_i2srx_apb:
-       clk_disable_unprepare(dev->clk_apb0);
 err_dis_bclk_mst:
        clk_disable_unprepare(dev->clk_i2s_apb);
-err_dis_lrck_mst:
-       clk_disable_unprepare(dev->clk_i2s_bclk_mst);
-err_dis_bclk:
-       clk_disable_unprepare(dev->clk_i2s_lrck_mst);
-err_dis_lrck:
-       clk_disable_unprepare(dev->clk_i2s_bclk);
 exit:
        return ret;
 }
@@ -1022,11 +971,21 @@ static int dw_i2s_probe(struct platform_device *pdev)
        }
 
        pm_runtime_enable(&pdev->dev);
+
+#ifdef CONFIG_PM
+       if (dev->capability & DW_I2S_MASTER) {
+               clk_disable_unprepare(dev->clk_i2s_bclk_mst);
+               clk_disable_unprepare(dev->clk_i2s_apb);
+       }
+#endif
+
        return 0;
 
 err_clk_disable:
-       if (dev->capability & DW_I2S_MASTER)
+       if (dev->capability & DW_I2S_MASTER) {
                clk_disable_unprepare(dev->clk_i2s_bclk_mst);
+               clk_disable_unprepare(dev->clk_i2s_apb);
+       }
        return ret;
 }
 
@@ -1034,8 +993,10 @@ static int dw_i2s_remove(struct platform_device *pdev)
 {
        struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev);
 
-       if (dev->capability & DW_I2S_MASTER)
+       if (dev->capability & DW_I2S_MASTER) {
                clk_disable_unprepare(dev->clk_i2s_bclk_mst);
+               clk_disable_unprepare(dev->clk_i2s_apb);
+       }
 
        pm_runtime_disable(&pdev->dev);
        return 0;
index d6c10d6..6eb9b92 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/regmap.h>
+#include <linux/pm_runtime.h>
 #include <sound/soc.h>
 #include <sound/soc-dai.h>
 #include <sound/pcm_params.h>
@@ -239,9 +240,73 @@ static int pdm_probe(struct snd_soc_component *component)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int sf_pdm_runtime_suspend(struct device *dev)
+{
+       struct sf_pdm *priv = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(priv->clk_pdm_apb);
+       clk_disable_unprepare(priv->clk_pdm_mclk);
+       clk_disable_unprepare(priv->clk_mclk);
+
+       return 0;
+}
+
+static int sf_pdm_runtime_resume(struct device *dev)
+{
+       struct sf_pdm *priv = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(priv->clk_mclk);
+       if (ret) {
+               dev_err(dev, "failed to prepare enable clk_mclk\n");
+               return ret;
+       }
+
+       ret = clk_prepare_enable(priv->clk_pdm_mclk);
+       if (ret) {
+               dev_err(dev, "failed to prepare enable clk_pdm_mclk\n");
+               goto disable_mclk;
+       }
+
+       ret = clk_prepare_enable(priv->clk_pdm_apb);
+       if (ret) {
+               dev_err(dev, "failed to prepare enable clk_pdm_apb\n");
+               goto disable_pdm_mclk;
+       }
+
+       return 0;
+
+disable_pdm_mclk:
+       clk_disable_unprepare(priv->clk_pdm_mclk);
+disable_mclk:
+       clk_disable_unprepare(priv->clk_mclk);
+
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int sf_pdm_suspend(struct snd_soc_component *component)
+{
+       return pm_runtime_force_suspend(component->dev);
+}
+
+static int sf_pdm_resume(struct snd_soc_component *component)
+{
+       return pm_runtime_force_resume(component->dev);
+}
+
+#else
+#define sf_pdm_suspend NULL
+#define sf_pdm_resume  NULL
+#endif
+
 static const struct snd_soc_component_driver sf_pdm_component_drv = {
        .name = "jh7110-pdm",
        .probe = pdm_probe,
+       .suspend = sf_pdm_suspend,
+       .resume = sf_pdm_resume,
 };
 
 static const struct regmap_config sf_pdm_regmap_cfg = {
@@ -386,12 +451,28 @@ static int sf_pdm_probe(struct platform_device *pdev)
                return ret;
        }
 
-       return devm_snd_soc_register_component(&pdev->dev, &sf_pdm_component_drv,
+       dev_set_drvdata(&pdev->dev, priv);
+
+       ret = devm_snd_soc_register_component(&pdev->dev, &sf_pdm_component_drv,
                                               &sf_pdm_dai_drv, 1);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register pdm dai\n");
+               return ret;
+       }
+
+       pm_runtime_enable(&pdev->dev);
+#ifdef CONFIG_PM
+       clk_disable_unprepare(priv->clk_pdm_apb);
+       clk_disable_unprepare(priv->clk_pdm_mclk);
+       clk_disable_unprepare(priv->clk_mclk);
+#endif
+
+       return 0;
 }
 
 static int sf_pdm_dev_remove(struct platform_device *pdev)
 {
+       pm_runtime_disable(&pdev->dev);
        return 0;
 }
 
@@ -401,10 +482,16 @@ static const struct of_device_id sf_pdm_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, sf_pdm_of_match);
 
+static const struct dev_pm_ops sf_pdm_pm_ops = {
+       SET_RUNTIME_PM_OPS(sf_pdm_runtime_suspend,
+                       sf_pdm_runtime_resume, NULL)
+};
+
 static struct platform_driver sf_pdm_driver = {
        .driver = {
                .name = "jh7110-pdm",
                .of_match_table = sf_pdm_of_match,
+               .pm = &sf_pdm_pm_ops,
        },
        .probe = sf_pdm_probe,
        .remove = sf_pdm_dev_remove,
index 2287cf4..1e7a438 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * PWMDAC driver for the StarFive JH7110 SoC
  *
@@ -623,12 +624,6 @@ static int sf_pwmdac_hw_params(struct snd_pcm_substream *substream,
        mclk_dac_value = mclk_dac_value + 64;
        pwmdac_set(dev);
 
-       ret = clk_prepare_enable(dev->clk_pwmdac_core);
-       if (ret) {
-               dev_err(dai->dev, "failed to prepare enable clk_pwmdac_core\n");
-               goto err_clk_pwmdac;
-       }
-
        ret = clk_set_rate(dev->clk_pwmdac_core, mclk_dac_value);
        if (ret) {
                dev_err(dai->dev, "failed to set rate for clk_pwmdac_core %lu\n", mclk_dac_value);
@@ -678,28 +673,61 @@ static int sf_pwmdac_resets_get(struct platform_device *pdev,
        return 0;
 }
 
-static int sf_pwmdac_clk_init(struct platform_device *pdev,
-                               struct sf_pwmdac_dev *dev)
+static int starfive_pwmdac_crg_enable(struct sf_pwmdac_dev *dev, bool enable)
 {
        int ret = 0;
 
-       ret = clk_prepare_enable(dev->clk_apb0);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to prepare enable clk_apb0\n");
-               goto err_clk_pwmdac;
-       }
+       dev_dbg(dev->dev, "starfive_pwmdac clk&rst %sable.\n", enable ? "en":"dis");
+       if (enable) {
+               ret = clk_prepare_enable(dev->clk_apb0);
+               if (ret) {
+                       dev_err(dev->dev, "failed to prepare enable clk_apb0\n");
+                       goto err_clk_apb0;
+               }
 
-       ret = clk_prepare_enable(dev->clk_pwmdac_apb);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to prepare enable clk_pwmdac_apb\n");
-               goto err_clk_pwmdac;
+               ret = clk_prepare_enable(dev->clk_pwmdac_apb);
+               if (ret) {
+                       dev_err(dev->dev, "failed to prepare enable clk_pwmdac_apb\n");
+                       goto err_clk_apb;
+               }
+
+               ret = clk_prepare_enable(dev->clk_pwmdac_core);
+               if (ret) {
+                       dev_err(dev->dev, "failed to prepare enable clk_pwmdac_core\n");
+                       goto err_clk_core;
+               }
+
+               ret = reset_control_deassert(dev->rst_apb);
+               if (ret) {
+                       dev_err(dev->dev, "failed to deassert apb\n");
+                       goto err_rst_apb;
+               }
+       } else {
+               clk_disable_unprepare(dev->clk_pwmdac_core);
+               clk_disable_unprepare(dev->clk_pwmdac_apb);
+               clk_disable_unprepare(dev->clk_apb0);
        }
 
-       ret = clk_prepare_enable(dev->clk_pwmdac_core);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to prepare enable clk_pwmdac_core\n");
+       return 0;
+
+err_rst_apb:
+       clk_disable_unprepare(dev->clk_pwmdac_core);
+err_clk_core:
+       clk_disable_unprepare(dev->clk_pwmdac_apb);
+err_clk_apb:
+       clk_disable_unprepare(dev->clk_apb0);
+err_clk_apb0:
+       return ret;
+}
+
+static int sf_pwmdac_clk_init(struct platform_device *pdev,
+                               struct sf_pwmdac_dev *dev)
+{
+       int ret = 0;
+
+       ret = starfive_pwmdac_crg_enable(dev, true);
+       if (ret)
                goto err_clk_pwmdac;
-       }
 
        ret = clk_set_rate(dev->clk_pwmdac_core, 4096000);
        if (ret) {
@@ -711,12 +739,6 @@ static int sf_pwmdac_clk_init(struct platform_device *pdev,
                clk_get_rate(dev->clk_apb0), clk_get_rate(dev->clk_pwmdac_apb),
                clk_get_rate(dev->clk_pwmdac_core));
 
-       ret = reset_control_deassert(dev->rst_apb);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to deassert apb\n");
-               goto err_clk_pwmdac;
-       }
-
 err_clk_pwmdac:
        return ret;
 }
@@ -736,6 +758,39 @@ static int sf_pwmdac_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int starfive_pwmdac_system_suspend(struct device *dev)
+{
+       return pm_runtime_force_suspend(dev);
+}
+
+static int starfive_pwmdac_system_resume(struct device *dev)
+{
+       return pm_runtime_force_resume(dev);
+}
+#endif
+
+#ifdef CONFIG_PM
+static int starfive_pwmdac_runtime_suspend(struct device *dev)
+{
+       struct sf_pwmdac_dev *pwmdac = dev_get_drvdata(dev);
+
+       return starfive_pwmdac_crg_enable(pwmdac, false);
+}
+
+static int starfive_pwmdac_runtime_resume(struct device *dev)
+{
+       struct sf_pwmdac_dev *pwmdac = dev_get_drvdata(dev);
+
+       return starfive_pwmdac_crg_enable(pwmdac, true);
+}
+#endif
+
+static const struct dev_pm_ops starfive_pwmdac_pm_ops = {
+       SET_RUNTIME_PM_OPS(starfive_pwmdac_runtime_suspend, starfive_pwmdac_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(starfive_pwmdac_system_suspend, starfive_pwmdac_system_resume)
+};
+
 #define SOC_PWMDAC_ENUM_DECL(xname, xinfo, xget, xput) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .info = xinfo, .get = xget, .put = xput,}
@@ -825,6 +880,7 @@ static int sf_pwmdac_probe(struct platform_device *pdev)
                return PTR_ERR(dev->pwmdac_base);
 
        dev->mapbase = res->start;
+       dev->dev = &pdev->dev;
 
        ret = sf_pwmdac_clks_get(pdev, dev);
        if (ret) {
@@ -844,7 +900,6 @@ static int sf_pwmdac_probe(struct platform_device *pdev)
                return ret;
        }
 
-       dev->dev = &pdev->dev;
        dev->mode = shift_8Bit_inverter;
        dev->fifo_th = 1;//8byte
        pwmdac_config(dev);
@@ -865,6 +920,12 @@ static int sf_pwmdac_probe(struct platform_device *pdev)
                                0);
        }
 
+#ifdef CONFIG_PM
+       starfive_pwmdac_crg_enable(dev, false);
+#endif
+
+       pm_runtime_enable(dev->dev);
+
        return 0;
 }
 
@@ -890,6 +951,7 @@ static struct platform_driver sf_pwmdac_driver = {
        .driver         = {
                .name   = "starfive-pwmdac",
                .of_match_table = of_match_ptr(sf_pwmdac_of_match),
+               .pm = &starfive_pwmdac_pm_ops,
        },
 };
 
@@ -908,6 +970,7 @@ late_initcall(pwmdac_driver_init);
 module_exit(pwmdac_driver_exit);
 
 MODULE_AUTHOR("curry.zhang <curry.zhang@starfivetech.com>");
+MODULE_AUTHOR("Xingyu Wu <xingyu.wu@starfivetech.com>");
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("starfive pwmdac SoC Interface");
 MODULE_ALIAS("platform:starfive-pwmdac");
old mode 100755 (executable)
new mode 100644 (file)
index 9608495..ee97627
@@ -21,6 +21,7 @@
 #include <sound/soc.h>
 #include <sound/initval.h>
 #include <sound/dmaengine_pcm.h>
+#include <linux/pm_runtime.h>
 #include "starfive_spdif.h"
 
 static irqreturn_t spdif_irq_handler(int irq, void *dev_id)
@@ -284,22 +285,52 @@ static int sf_spdif_resets_get(struct platform_device *pdev,
        return 0;
 }
 
+static int starfive_spdif_crg_enable(struct sf_spdif_dev *spdif, bool enable)
+{
+       int ret;
+
+       dev_dbg(spdif->dev, "starfive_spdif clk&rst %sable.\n", enable ? "en":"dis");
+       if (enable) {
+               ret = clk_prepare_enable(spdif->spdif_apb);
+               if (ret) {
+                       dev_err(spdif->dev, "failed to prepare enable spdif_apb\n");
+                       goto failed_apb_clk;
+               }
+
+               ret = clk_prepare_enable(spdif->spdif_core);
+               if (ret) {
+                       dev_err(spdif->dev, "failed to prepare enable spdif_core\n");
+                       goto failed_core_clk;
+               }
+
+               ret = reset_control_deassert(spdif->rst_apb);
+               if (ret) {
+                       dev_err(spdif->dev, "failed to deassert apb\n");
+                       goto failed_rst;
+               }
+       } else {
+               clk_disable_unprepare(spdif->spdif_core);
+               clk_disable_unprepare(spdif->spdif_apb);
+       }
+
+       return 0;
+
+failed_rst:
+       clk_disable_unprepare(spdif->spdif_core);
+failed_core_clk:
+       clk_disable_unprepare(spdif->spdif_apb);
+failed_apb_clk:
+       return ret;
+}
+
 static int sf_spdif_clk_init(struct platform_device *pdev,
                                struct sf_spdif_dev *spdif)
 {
        int ret = 0;
 
-       ret = clk_prepare_enable(spdif->spdif_apb);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to prepare enable spdif_apb\n");
-               goto disable_apb_clk;
-       }
-
-       ret = clk_prepare_enable(spdif->spdif_core);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to prepare enable spdif_core\n");
-               goto disable_core_clk;
-       }
+       ret = starfive_spdif_crg_enable(spdif, true);
+       if (ret)
+               return ret;
 
        ret = clk_set_rate(spdif->audio_root, 204800000);
        if (ret) {
@@ -322,17 +353,10 @@ static int sf_spdif_clk_init(struct platform_device *pdev,
                goto disable_core_clk;
        }
 
-       ret = reset_control_deassert(spdif->rst_apb);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to deassert apb\n");
-               goto disable_core_clk;
-       }
-
        return 0;
 
 disable_core_clk:
        clk_disable_unprepare(spdif->spdif_core);
-disable_apb_clk:
        clk_disable_unprepare(spdif->spdif_apb);
 
        return ret;
@@ -342,6 +366,8 @@ static int sf_spdif_dai_probe(struct snd_soc_dai *dai)
 {
        struct sf_spdif_dev *spdif = snd_soc_dai_get_drvdata(dai);
 
+       pm_runtime_get_sync(spdif->dev);
+
        /* reset */
        regmap_update_bits(spdif->regmap, SPDIF_CTRL,
                SPDIF_ENABLE | SPDIF_SFR_ENABLE | SPDIF_FIFO_ENABLE, 0);
@@ -385,6 +411,7 @@ static int sf_spdif_dai_probe(struct snd_soc_dai *dai)
        regmap_update_bits(spdif->regmap, SPDIF_CTRL,
                SPDIF_CHANNEL_MODE, 0);
 
+       pm_runtime_put_sync(spdif->dev);
        return 0;
 }
 
@@ -393,6 +420,40 @@ static const struct snd_soc_dai_ops sf_spdif_dai_ops = {
        .hw_params = sf_spdif_hw_params,
 };
 
+#ifdef CONFIG_PM_SLEEP
+static int spdif_system_suspend(struct device *dev)
+{
+       return pm_runtime_force_suspend(dev);
+}
+
+static int spdif_system_resume(struct device *dev)
+{
+       return pm_runtime_force_resume(dev);
+}
+#endif
+
+#ifdef CONFIG_PM
+static int spdif_runtime_suspend(struct device *dev)
+{
+       struct sf_spdif_dev *spdif = dev_get_drvdata(dev);
+
+       return starfive_spdif_crg_enable(spdif, false);
+}
+
+static int spdif_runtime_resume(struct device *dev)
+{
+       struct sf_spdif_dev *spdif = dev_get_drvdata(dev);
+
+       return starfive_spdif_crg_enable(spdif, true);
+}
+#endif
+
+static const struct dev_pm_ops spdif_pm_ops = {
+       SET_RUNTIME_PM_OPS(spdif_runtime_suspend, spdif_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(spdif_system_suspend, spdif_system_resume)
+};
+
+
 #define SF_PCM_RATE_44100_192000  (SNDRV_PCM_RATE_44100 | \
                                   SNDRV_PCM_RATE_48000 | \
                                   SNDRV_PCM_RATE_96000 | \
@@ -457,6 +518,8 @@ static int sf_spdif_probe(struct platform_device *pdev)
        if (IS_ERR(spdif->regmap))
                return PTR_ERR(spdif->regmap);
 
+       spdif->dev = &pdev->dev;
+
        ret = sf_spdif_clks_get(pdev, spdif);
        if (ret) {
                dev_err(&pdev->dev, "failed to get audio clock\n");
@@ -475,7 +538,6 @@ static int sf_spdif_probe(struct platform_device *pdev)
                return ret;
        }
 
-       spdif->dev = &pdev->dev;
        spdif->fifo_th = 16;
 
        irq = platform_get_irq(pdev, 0);
@@ -505,6 +567,10 @@ static int sf_spdif_probe(struct platform_device *pdev)
        if (ret)
                goto err_clk_disable;
 
+       starfive_spdif_crg_enable(spdif, false);
+       pm_runtime_enable(&pdev->dev);
+       dev_info(&pdev->dev, "spdif register done.\n");
+
        return 0;
 
 err_clk_disable:
@@ -521,6 +587,7 @@ static struct platform_driver sf_spdif_driver = {
        .driver = {
                .name = "starfive-spdif",
                .of_match_table = sf_spdif_of_match,
+               .pm = &spdif_pm_ops,
        },
        .probe = sf_spdif_probe,
 };
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index 9d5a8ec..bd7372e 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/regmap.h>
+#include <linux/pm_runtime.h>
 #include <linux/dma/starfive-dma.h>
 #include <sound/soc.h>
 #include <sound/soc-dai.h>
@@ -90,7 +91,10 @@ static void sf_tdm_contrl(struct sf_tdm_dev *dev)
 {
        u32 data;
 
-       data = (dev->clkpolity << 5) | (dev->elm << 3) | (dev->syncm << 2) | (dev->ms_mode << 1);
+       data = (dev->clkpolity << CLKPOL_BIT) |
+               (dev->elm << ELM_BIT) |
+               (dev->syncm << SYNCM_BIT) |
+               (dev->ms_mode << MS_BIT);
        sf_tdm_writel(dev, TDM_PCMGBCR, data);
 }
 
@@ -101,11 +105,17 @@ static void sf_tdm_config(struct sf_tdm_dev *dev, struct snd_pcm_substream *subs
        sf_tdm_contrl(dev);
        sf_tdm_syncdiv(dev);
 
-       datarx = (dev->rx.ifl << 11) | (dev->rx.wl << 8) | (dev->rx.sscale << 4) |
-               (dev->rx.sl << 2) | (dev->rx.lrj << 1);
+       datarx = (dev->rx.ifl << IFL_BIT) |
+               (dev->rx.wl << WL_BIT) |
+               (dev->rx.sscale << SSCALE_BIT) |
+               (dev->rx.sl << SL_BIT) |
+               (dev->rx.lrj << LRJ_BIT);
 
-       datatx = (dev->tx.ifl << 11) | (dev->tx.wl << 8) | (dev->tx.sscale << 4) |
-               (dev->tx.sl << 2) | (dev->tx.lrj << 1);
+       datatx = (dev->tx.ifl << IFL_BIT) |
+               (dev->tx.wl << WL_BIT) |
+               (dev->tx.sscale << SSCALE_BIT) |
+               (dev->tx.sl << SL_BIT) |
+               (dev->tx.lrj << LRJ_BIT);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                sf_tdm_writel(dev, TDM_PCMTXCR, datatx);
@@ -113,13 +123,102 @@ static void sf_tdm_config(struct sf_tdm_dev *dev, struct snd_pcm_substream *subs
                sf_tdm_writel(dev, TDM_PCMRXCR, datarx);
 }
 
+static void sf_tdm_clk_disable(struct sf_tdm_dev *priv)
+{
+       clk_disable_unprepare(priv->clk_tdm);
+       clk_disable_unprepare(priv->clk_tdm_ext);
+       clk_disable_unprepare(priv->clk_tdm_internal);
+       clk_disable_unprepare(priv->clk_tdm_apb);
+       clk_disable_unprepare(priv->clk_tdm_ahb);
+       clk_disable_unprepare(priv->clk_mclk_inner);
+}
+
+#ifdef CONFIG_PM
+static int sf_tdm_runtime_suspend(struct device *dev)
+{
+       struct sf_tdm_dev *priv = dev_get_drvdata(dev);
+
+       sf_tdm_clk_disable(priv);
+       return 0;
+}
+
+static int sf_tdm_runtime_resume(struct device *dev)
+{
+       struct sf_tdm_dev *priv = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(priv->clk_mclk_inner);
+       if (ret) {
+               dev_err(dev, "failed to prepare enable clk_mclk_inner\n");
+               return ret;
+       }
+
+       ret = clk_prepare_enable(priv->clk_tdm_ahb);
+       if (ret) {
+               dev_err(dev, "Failed to prepare enable clk_tdm_ahb\n");
+               goto dis_mclk_inner;
+       }
+
+       ret = clk_prepare_enable(priv->clk_tdm_apb);
+       if (ret) {
+               dev_err(dev, "Failed to prepare enable clk_tdm_apb\n");
+               goto dis_tdm_ahb;
+       }
+
+       ret = clk_prepare_enable(priv->clk_tdm_internal);
+       if (ret) {
+               dev_err(dev, "Failed to prepare enable clk_tdm_intl\n");
+               goto dis_tdm_apb;
+       }
+
+       ret = clk_prepare_enable(priv->clk_tdm_ext);
+       if (ret) {
+               dev_err(dev, "Failed to prepare enable clk_tdm_ext\n");
+               goto dis_tdm_internal;
+       }
 
+       ret = clk_prepare_enable(priv->clk_tdm);
+       if (ret) {
+               dev_err(dev, "Failed to prepare enable clk_tdm\n");
+               goto dis_tdm_ext;
+       }
+
+       return 0;
+
+dis_tdm_ext:
+       clk_disable_unprepare(priv->clk_tdm_ext);
+dis_tdm_internal:
+       clk_disable_unprepare(priv->clk_tdm_internal);
+dis_tdm_apb:
+       clk_disable_unprepare(priv->clk_tdm_apb);
+dis_tdm_ahb:
+       clk_disable_unprepare(priv->clk_tdm_ahb);
+dis_mclk_inner:
+       clk_disable_unprepare(priv->clk_mclk_inner);
+
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int sf_tdm_suspend(struct snd_soc_component *component)
+{
+       return pm_runtime_force_suspend(component->dev);
+}
+
+static int sf_tdm_resume(struct snd_soc_component *component)
+{
+       return pm_runtime_force_resume(component->dev);
+}
+
+#else
 #define sf_tdm_suspend NULL
 #define sf_tdm_resume  NULL
+#endif
 
-/* 
+/*
  * To stop dma first, we must implement this function, because it is
- * called before stopping the stream. 
+ * called before stopping the stream.
  */
 static int sf_pcm_trigger(struct snd_soc_component *component,
                              struct snd_pcm_substream *substream, int cmd)
@@ -177,35 +276,29 @@ static int sf_tdm_hw_params(struct snd_pcm_substream *substream,
        /*  There are some limitation when using 8k sample rate  */
        case 8000:
                mclk_rate = 12288000;
-               dev->pcmclk = 512000;
                if ((data_width == 16) || (channels == 1)) {
                        pr_err("TDM: not support 16bit or 1-channel when using 8k sample rate\n");
                        return -EINVAL;
                }
                break;
        case 11025:
-               mclk_rate = 11289600; //sysclk
-               dev->pcmclk = 352800; //bit clock, for 16-bit
+               /* sysclk */
+               mclk_rate = 11289600;
                break;
        case 16000:
-               mclk_rate = 12288000; //sysclk
-               dev->pcmclk = 512000; //bit clock
+               mclk_rate = 12288000;
                break;
        case 22050:
                mclk_rate = 11289600;
-               dev->pcmclk = 705600;
                break;
        case 32000:
                mclk_rate = 12288000;
-               dev->pcmclk = 1024000;
                break;
        case 44100:
                mclk_rate = 11289600;
-               dev->pcmclk = 1411200;
                break;
        case 48000:
                mclk_rate = 12288000;
-               dev->pcmclk = 1536000;
                break;
        default:
                pr_err("TDM: not support sample rate:%d\n", dev->samplerate);
@@ -491,60 +584,68 @@ static int sf_tdm_clk_reset_init(struct platform_device *pdev, struct sf_tdm_dev
        ret = clk_prepare_enable(dev->clk_ahb0);
        if (ret) {
                dev_err(&pdev->dev, "Failed to prepare enable clk_ahb0\n");
-               goto err_dis_ahb0;
+               goto dis_mclk_inner;
        }
 
        ret = clk_prepare_enable(dev->clk_tdm_ahb);
        if (ret) {
                dev_err(&pdev->dev, "Failed to prepare enable clk_tdm_ahb\n");
-               goto err_dis_tdm_ahb;
+               goto dis_ahb0;
        }
 
        ret = clk_prepare_enable(dev->clk_apb0);
        if (ret) {
                dev_err(&pdev->dev, "Failed to prepare enable clk_apb0\n");
-               goto err_dis_apb0;
+               goto dis_tdm_ahb;
        }
 
        ret = clk_prepare_enable(dev->clk_tdm_apb);
        if (ret) {
                dev_err(&pdev->dev, "Failed to prepare enable clk_tdm_apb\n");
-               goto err_dis_tdm_apb;
+               goto dis_apb0;
        }
 
        ret = clk_prepare_enable(dev->clk_tdm_internal);
        if (ret) {
                dev_err(&pdev->dev, "Failed to prepare enable clk_tdm_intl\n");
-               goto err_dis_tdm_internal;
+               goto dis_tdm_apb;
        }
 
        ret = clk_prepare_enable(dev->clk_tdm_ext);
        if (ret) {
                dev_err(&pdev->dev, "failed to prepare enable clk_tdm_ext\n");
-               goto err_dis_tdm_ext;
+               goto dis_tdm_internal;
+       }
+
+       ret = clk_prepare_enable(dev->clk_tdm);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to prepare enable clk_tdm\n");
+               goto dis_tdm_ext;
        }
 
        ret = reset_control_deassert(dev->resets);
        if (ret) {
                dev_err(&pdev->dev, "Failed to deassert tdm resets\n");
-               goto err_clk_disable;
+               goto dis_tdm_clk;
        }
 
        return 0;
 
-err_clk_disable:
+dis_tdm_clk:
+       clk_disable_unprepare(dev->clk_tdm);
+dis_tdm_ext:
        clk_disable_unprepare(dev->clk_tdm_ext);
-err_dis_tdm_ext:
+dis_tdm_internal:
        clk_disable_unprepare(dev->clk_tdm_internal);
-err_dis_tdm_internal:
+dis_tdm_apb:
        clk_disable_unprepare(dev->clk_tdm_apb);
-err_dis_tdm_apb:
+dis_apb0:
        clk_disable_unprepare(dev->clk_apb0);
-err_dis_apb0:
+dis_tdm_ahb:
        clk_disable_unprepare(dev->clk_tdm_ahb);
-err_dis_tdm_ahb:
+dis_ahb0:
        clk_disable_unprepare(dev->clk_ahb0);
-err_dis_ahb0:
+dis_mclk_inner:
        clk_disable_unprepare(dev->clk_mclk_inner);
 exit:
        return ret;
@@ -575,8 +676,8 @@ static int sf_tdm_probe(struct platform_device *pdev)
 
        dev->frame_mode = SHORT_LATER;
        tdm_init_params(dev);
-
        dev_set_drvdata(&pdev->dev, dev);
+
        ret = devm_snd_soc_register_component(&pdev->dev, &sf_tdm_component,
                                         &sf_tdm_dai, 1);
        if (ret != 0) {
@@ -592,11 +693,17 @@ static int sf_tdm_probe(struct platform_device *pdev)
                return ret;
        }
 
+       pm_runtime_enable(&pdev->dev);
+#ifdef CONFIG_PM
+       sf_tdm_clk_disable(dev);
+#endif
+
        return 0;
 }
 
 static int sf_tdm_dev_remove(struct platform_device *pdev)
 {
+       pm_runtime_disable(&pdev->dev);
        return 0;
 }
 static const struct of_device_id sf_tdm_of_match[] = {
@@ -605,10 +712,16 @@ static const struct of_device_id sf_tdm_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, sf_tdm_of_match);
 
+static const struct dev_pm_ops sf_tdm_pm_ops = {
+       SET_RUNTIME_PM_OPS(sf_tdm_runtime_suspend,
+                       sf_tdm_runtime_resume, NULL)
+};
+
 static struct platform_driver sf_tdm_driver = {
        .driver = {
                .name = "jh7110-tdm",
                .of_match_table = sf_tdm_of_match,
+               .pm = &sf_tdm_pm_ops,
        },
        .probe = sf_tdm_probe,
        .remove = sf_tdm_dev_remove,
index 1f580ee..dfba82f 100644 (file)
        #define MS_BIT                  1
 #define TDM_PCMTXCR                    0x04
        #define PCMTXCR_TXEN            BIT(0)
+       #define IFL_BIT                 11
+       #define WL_BIT                  8
+       #define SSCALE_BIT              4
+       #define SL_BIT                  2
+       #define LRJ_BIT                 1
 #define TDM_PCMRXCR                    0x08
        #define PCMRXCR_RXEN            BIT(0)
        #define PCMRXCR_RXSL_MASK       0xc
@@ -36,8 +41,7 @@
 #define TDM_PCMDIV                     0x0c
 
 /*  DMA registers */
-#define TDM_FIFO               0x170c0000
-//#define TDM_FIFO_DEPTH                       16
+#define TDM_FIFO                       0x170c0000
 #define TDM_FIFO_DEPTH                 32
 
 #define ONE_CHANNEL_SUPPORT            1