rk322x: add IR driver for remote controller wakeup
This commit is contained in:
parent
595e1fdf62
commit
c2b148add7
@ -1,18 +1,20 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Linux/arm 6.1.4 Kernel Configuration
|
||||
# Linux/arm 6.1.57 Kernel Configuration
|
||||
#
|
||||
CONFIG_CC_VERSION_TEXT="arm-linux-gnueabihf-gcc (GNU Toolchain for the A-profile Architecture 8.3-2019.03 (arm-rel-8.36)) 8.3.0"
|
||||
CONFIG_CC_VERSION_TEXT="arm-linux-gnueabihf-gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0"
|
||||
CONFIG_CC_IS_GCC=y
|
||||
CONFIG_GCC_VERSION=80300
|
||||
CONFIG_GCC_VERSION=110300
|
||||
CONFIG_CLANG_VERSION=0
|
||||
CONFIG_AS_IS_GNU=y
|
||||
CONFIG_AS_VERSION=23200
|
||||
CONFIG_AS_VERSION=23800
|
||||
CONFIG_LD_IS_BFD=y
|
||||
CONFIG_LD_VERSION=23200
|
||||
CONFIG_LD_VERSION=23800
|
||||
CONFIG_LLD_VERSION=0
|
||||
CONFIG_CC_CAN_LINK=y
|
||||
CONFIG_CC_CAN_LINK_STATIC=y
|
||||
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
|
||||
CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y
|
||||
CONFIG_CC_HAS_ASM_INLINE=y
|
||||
CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y
|
||||
CONFIG_PAHOLE_VERSION=122
|
||||
@ -158,7 +160,8 @@ CONFIG_GENERIC_SCHED_CLOCK=y
|
||||
# end of Scheduler features
|
||||
|
||||
CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5"
|
||||
CONFIG_GCC12_NO_ARRAY_BOUNDS=y
|
||||
CONFIG_GCC11_NO_ARRAY_BOUNDS=y
|
||||
CONFIG_CC_NO_ARRAY_BOUNDS=y
|
||||
CONFIG_CGROUPS=y
|
||||
CONFIG_PAGE_COUNTER=y
|
||||
# CONFIG_CGROUP_FAVOR_DYNMODS is not set
|
||||
@ -608,6 +611,7 @@ CONFIG_GENERIC_IDLE_POLL_SETUP=y
|
||||
CONFIG_ARCH_HAS_FORTIFY_SOURCE=y
|
||||
CONFIG_ARCH_HAS_KEEPINITRD=y
|
||||
CONFIG_ARCH_HAS_SET_MEMORY=y
|
||||
CONFIG_ARCH_HAS_CPU_FINALIZE_INIT=y
|
||||
CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y
|
||||
CONFIG_ARCH_32BIT_OFF_T=y
|
||||
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
|
||||
@ -666,7 +670,6 @@ CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
|
||||
# end of GCOV-based kernel profiling
|
||||
|
||||
CONFIG_HAVE_GCC_PLUGINS=y
|
||||
# CONFIG_GCC_PLUGINS is not set
|
||||
# end of General architecture-dependent options
|
||||
|
||||
CONFIG_RT_MUTEXES=y
|
||||
@ -847,6 +850,7 @@ CONFIG_KMAP_LOCAL_NON_LINEAR_PTE_ARRAY=y
|
||||
CONFIG_LRU_GEN=y
|
||||
CONFIG_LRU_GEN_ENABLED=y
|
||||
# CONFIG_LRU_GEN_STATS is not set
|
||||
CONFIG_LOCK_MM_AND_FIND_VMA=y
|
||||
|
||||
#
|
||||
# Data Access Monitoring
|
||||
@ -1493,14 +1497,11 @@ CONFIG_DEFAULT_NET_SCH="pfifo_fast"
|
||||
#
|
||||
CONFIG_NET_CLS=y
|
||||
CONFIG_NET_CLS_BASIC=m
|
||||
CONFIG_NET_CLS_TCINDEX=m
|
||||
CONFIG_NET_CLS_ROUTE4=m
|
||||
CONFIG_NET_CLS_FW=m
|
||||
CONFIG_NET_CLS_U32=m
|
||||
CONFIG_CLS_U32_PERF=y
|
||||
CONFIG_CLS_U32_MARK=y
|
||||
CONFIG_NET_CLS_RSVP=m
|
||||
CONFIG_NET_CLS_RSVP6=m
|
||||
CONFIG_NET_CLS_FLOW=m
|
||||
CONFIG_NET_CLS_CGROUP=m
|
||||
CONFIG_NET_CLS_BPF=m
|
||||
@ -2432,6 +2433,7 @@ CONFIG_MT7615_COMMON=m
|
||||
CONFIG_MT7663_USB_SDIO_COMMON=m
|
||||
CONFIG_MT7663U=m
|
||||
# CONFIG_MT7663S is not set
|
||||
CONFIG_MT7921_COMMON=m
|
||||
# CONFIG_MT7921S is not set
|
||||
CONFIG_MT7921U=m
|
||||
# CONFIG_WLAN_VENDOR_MICROCHIP is not set
|
||||
@ -2468,6 +2470,14 @@ CONFIG_RTL8192C_COMMON=m
|
||||
CONFIG_RTL8XXXU=m
|
||||
# CONFIG_RTL8XXXU_UNTESTED is not set
|
||||
CONFIG_RTW88=m
|
||||
# CONFIG_RTW88_8822BS is not set
|
||||
# CONFIG_RTW88_8822BU is not set
|
||||
# CONFIG_RTW88_8822CS is not set
|
||||
# CONFIG_RTW88_8822CU is not set
|
||||
# CONFIG_RTW88_8723DS is not set
|
||||
# CONFIG_RTW88_8723DU is not set
|
||||
# CONFIG_RTW88_8821CS is not set
|
||||
# CONFIG_RTW88_8821CU is not set
|
||||
# CONFIG_RTW89 is not set
|
||||
CONFIG_WLAN_VENDOR_RSI=y
|
||||
# CONFIG_RSI_91X is not set
|
||||
@ -2482,7 +2492,6 @@ CONFIG_WLAN_VENDOR_TI=y
|
||||
# CONFIG_WLCORE is not set
|
||||
CONFIG_RTL8723DU=m
|
||||
# CONFIG_RTL8723DS is not set
|
||||
# CONFIG_RTL8822CS is not set
|
||||
CONFIG_RTL8822BU=m
|
||||
CONFIG_RTL8821CU=m
|
||||
CONFIG_88XXAU=m
|
||||
@ -3318,7 +3327,6 @@ CONFIG_SENSORS_GPIO_FAN=y
|
||||
# CONFIG_SENSORS_PC87427 is not set
|
||||
# CONFIG_SENSORS_NTC_THERMISTOR is not set
|
||||
# CONFIG_SENSORS_NCT6683 is not set
|
||||
# CONFIG_SENSORS_NCT6775 is not set
|
||||
# CONFIG_SENSORS_NCT6775_I2C is not set
|
||||
# CONFIG_SENSORS_NCT7802 is not set
|
||||
# CONFIG_SENSORS_NCT7904 is not set
|
||||
@ -3662,6 +3670,7 @@ CONFIG_IR_GPIO_CIR=m
|
||||
# CONFIG_IR_MCEUSB is not set
|
||||
# CONFIG_IR_PWM_TX is not set
|
||||
# CONFIG_IR_REDRAT3 is not set
|
||||
CONFIG_IR_ROCKCHIP_CIR=m
|
||||
# CONFIG_IR_SERIAL is not set
|
||||
CONFIG_IR_SPI=m
|
||||
# CONFIG_IR_STREAMZAP is not set
|
||||
@ -3711,8 +3720,8 @@ CONFIG_VIDEO_TUNER=m
|
||||
CONFIG_V4L2_H264=m
|
||||
CONFIG_V4L2_VP9=m
|
||||
CONFIG_V4L2_MEM2MEM_DEV=m
|
||||
CONFIG_V4L2_FWNODE=m
|
||||
CONFIG_V4L2_ASYNC=m
|
||||
CONFIG_V4L2_FWNODE=y
|
||||
CONFIG_V4L2_ASYNC=y
|
||||
# end of Video4Linux options
|
||||
|
||||
#
|
||||
@ -4034,10 +4043,7 @@ CONFIG_VIDEOBUF2_DMA_SG=y
|
||||
#
|
||||
CONFIG_MEDIA_ATTACH=y
|
||||
CONFIG_VIDEO_IR_I2C=m
|
||||
|
||||
#
|
||||
# Camera sensor devices
|
||||
#
|
||||
CONFIG_VIDEO_CAMERA_SENSOR=y
|
||||
# CONFIG_VIDEO_AR0521 is not set
|
||||
# CONFIG_VIDEO_HI556 is not set
|
||||
# CONFIG_VIDEO_HI846 is not set
|
||||
@ -4104,7 +4110,6 @@ CONFIG_VIDEO_IR_I2C=m
|
||||
# CONFIG_VIDEO_CCS is not set
|
||||
# CONFIG_VIDEO_ET8EK8 is not set
|
||||
# CONFIG_VIDEO_M5MOLS is not set
|
||||
# end of Camera sensor devices
|
||||
|
||||
#
|
||||
# Lens drivers
|
||||
@ -4593,8 +4598,6 @@ CONFIG_DRM_DW_HDMI_CEC=y
|
||||
# CONFIG_DRM_STI is not set
|
||||
# CONFIG_DRM_ETNAVIV is not set
|
||||
# CONFIG_DRM_LOGICVC is not set
|
||||
# CONFIG_DRM_MXSFB is not set
|
||||
# CONFIG_DRM_IMX_LCDIF is not set
|
||||
# CONFIG_DRM_ARCPGU is not set
|
||||
# CONFIG_DRM_GM12U320 is not set
|
||||
# CONFIG_DRM_PANEL_MIPI_DBI is not set
|
||||
@ -5769,7 +5772,6 @@ CONFIG_STAGING=y
|
||||
# CONFIG_PRISM2_USB is not set
|
||||
# CONFIG_RTLLIB is not set
|
||||
CONFIG_RTL8723BS=m
|
||||
CONFIG_RTL8723CS=m
|
||||
CONFIG_R8712U=m
|
||||
CONFIG_R8188EU=m
|
||||
# CONFIG_VT6656 is not set
|
||||
@ -5869,6 +5871,7 @@ CONFIG_FIELDBUS_DEV=m
|
||||
CONFIG_HMS_ANYBUSS_BUS=m
|
||||
CONFIG_ARCX_ANYBUS_CONTROLLER=m
|
||||
CONFIG_HMS_PROFINET=m
|
||||
CONFIG_RTL8723CS=m
|
||||
# CONFIG_GOLDFISH is not set
|
||||
# CONFIG_CHROME_PLATFORMS is not set
|
||||
# CONFIG_MELLANOX_PLATFORM is not set
|
||||
@ -6041,7 +6044,6 @@ CONFIG_DEVFREQ_GOV_USERSPACE=y
|
||||
#
|
||||
# DEVFREQ Drivers
|
||||
#
|
||||
# CONFIG_ARM_RK3328_DMC_DEVFREQ is not set
|
||||
CONFIG_ARM_RK3228_DMC_DEVFREQ=y
|
||||
# CONFIG_ARM_RK3399_DMC_DEVFREQ is not set
|
||||
CONFIG_PM_DEVFREQ_EVENT=y
|
||||
@ -6928,24 +6930,6 @@ CONFIG_PSTORE_RAM=y
|
||||
# CONFIG_SYSV_FS is not set
|
||||
# CONFIG_UFS_FS is not set
|
||||
# CONFIG_EROFS_FS is not set
|
||||
CONFIG_AUFS_FS=m
|
||||
CONFIG_AUFS_BRANCH_MAX_127=y
|
||||
# CONFIG_AUFS_BRANCH_MAX_511 is not set
|
||||
# CONFIG_AUFS_BRANCH_MAX_1023 is not set
|
||||
# CONFIG_AUFS_BRANCH_MAX_32767 is not set
|
||||
CONFIG_AUFS_SBILIST=y
|
||||
# CONFIG_AUFS_HNOTIFY is not set
|
||||
# CONFIG_AUFS_EXPORT is not set
|
||||
# CONFIG_AUFS_XATTR is not set
|
||||
# CONFIG_AUFS_FHSM is not set
|
||||
# CONFIG_AUFS_RDU is not set
|
||||
# CONFIG_AUFS_DIRREN is not set
|
||||
# CONFIG_AUFS_SHWH is not set
|
||||
# CONFIG_AUFS_BR_RAMFS is not set
|
||||
# CONFIG_AUFS_BR_FUSE is not set
|
||||
CONFIG_AUFS_BR_HFSPLUS=y
|
||||
CONFIG_AUFS_BDEV_LOOP=y
|
||||
# CONFIG_AUFS_DEBUG is not set
|
||||
CONFIG_NETWORK_FILESYSTEMS=y
|
||||
CONFIG_NFS_FS=m
|
||||
CONFIG_NFS_V2=m
|
||||
@ -7006,7 +6990,7 @@ CONFIG_CIFS_FSCACHE=y
|
||||
CONFIG_SMB_SERVER=m
|
||||
CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN=y
|
||||
# CONFIG_SMB_SERVER_KERBEROS5 is not set
|
||||
CONFIG_SMBFS_COMMON=m
|
||||
CONFIG_SMBFS=m
|
||||
# CONFIG_CODA_FS is not set
|
||||
# CONFIG_AFS_FS is not set
|
||||
CONFIG_NLS=y
|
||||
@ -7118,6 +7102,8 @@ CONFIG_LSM="yama,loadpin,safesetid,integrity"
|
||||
CONFIG_INIT_STACK_NONE=y
|
||||
# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set
|
||||
# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set
|
||||
CONFIG_CC_HAS_ZERO_CALL_USED_REGS=y
|
||||
# CONFIG_ZERO_CALL_USED_REGS is not set
|
||||
# end of Memory initialization
|
||||
|
||||
CONFIG_RANDSTRUCT_NONE=y
|
||||
@ -7570,6 +7556,7 @@ CONFIG_DEBUG_FS_ALLOW_ALL=y
|
||||
CONFIG_HAVE_ARCH_KGDB=y
|
||||
# CONFIG_KGDB is not set
|
||||
# CONFIG_UBSAN is not set
|
||||
CONFIG_HAVE_KCSAN_COMPILER=y
|
||||
# end of Generic Kernel Debugging Instruments
|
||||
|
||||
#
|
||||
|
||||
@ -1,21 +1,23 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Linux/arm 6.5.5 Kernel Configuration
|
||||
# Linux/arm 6.5.7 Kernel Configuration
|
||||
#
|
||||
CONFIG_CC_VERSION_TEXT="arm-linux-gnueabihf-gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0"
|
||||
CONFIG_CC_VERSION_TEXT="arm-linux-gnueabihf-gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0"
|
||||
CONFIG_CC_IS_GCC=y
|
||||
CONFIG_GCC_VERSION=110400
|
||||
CONFIG_GCC_VERSION=110300
|
||||
CONFIG_CLANG_VERSION=0
|
||||
CONFIG_AS_IS_GNU=y
|
||||
CONFIG_AS_VERSION=23800
|
||||
CONFIG_LD_IS_BFD=y
|
||||
CONFIG_LD_VERSION=23800
|
||||
CONFIG_LLD_VERSION=0
|
||||
CONFIG_CC_CAN_LINK=y
|
||||
CONFIG_CC_CAN_LINK_STATIC=y
|
||||
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
|
||||
CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y
|
||||
CONFIG_CC_HAS_ASM_INLINE=y
|
||||
CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y
|
||||
CONFIG_PAHOLE_VERSION=125
|
||||
CONFIG_PAHOLE_VERSION=122
|
||||
CONFIG_IRQ_WORK=y
|
||||
CONFIG_BUILDTIME_TABLE_SORT=y
|
||||
CONFIG_THREAD_INFO_IN_TASK=y
|
||||
@ -1354,6 +1356,7 @@ CONFIG_BRIDGE_EBT_SNAT=m
|
||||
CONFIG_BRIDGE_EBT_LOG=m
|
||||
CONFIG_BRIDGE_EBT_NFLOG=m
|
||||
CONFIG_BPFILTER=y
|
||||
CONFIG_BPFILTER_UMH=m
|
||||
CONFIG_IP_DCCP=m
|
||||
CONFIG_INET_DCCP_DIAG=m
|
||||
|
||||
@ -3711,6 +3714,7 @@ CONFIG_IR_GPIO_CIR=m
|
||||
# CONFIG_IR_MCEUSB is not set
|
||||
# CONFIG_IR_PWM_TX is not set
|
||||
# CONFIG_IR_REDRAT3 is not set
|
||||
CONFIG_IR_ROCKCHIP_CIR=m
|
||||
# CONFIG_IR_SERIAL is not set
|
||||
CONFIG_IR_SPI=m
|
||||
# CONFIG_IR_STREAMZAP is not set
|
||||
|
||||
@ -119,6 +119,22 @@
|
||||
linux,rc-map-name = "rc-rk322x-tvbox";
|
||||
};
|
||||
|
||||
rockchip_ir_receiver: rockchip-ir-receiver {
|
||||
compatible = "rockchip-ir-receiver";
|
||||
reg = <0x110b0030 0x10>;
|
||||
gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_LOW>;
|
||||
clocks = <&cru PCLK_PWM>;
|
||||
interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
|
||||
linux,rc-map-name = "rc-rk322x-tvbox";
|
||||
pinctrl-names = "default", "suspend";
|
||||
pinctrl-0 = <&ir_int>;
|
||||
pinctrl-1 = <&pwm3_pin>;
|
||||
pwm-id = <3>;
|
||||
shutdown-is-virtual-poweroff;
|
||||
wakeup-source;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
sdio_pwrseq: sdio-pwrseq {
|
||||
compatible = "mmc-pwrseq-simple";
|
||||
pinctrl-names = "default";
|
||||
|
||||
@ -0,0 +1,778 @@
|
||||
From 13498feb91614d59ebece61d0c278e31529bb8c8 Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Sabatino <paolo.sabatino@gmail.com>
|
||||
Date: Tue, 10 Oct 2023 21:54:51 +0200
|
||||
Subject: [PATCH] rockchip gpio IR driver
|
||||
|
||||
---
|
||||
drivers/media/rc/Kconfig | 11 +
|
||||
drivers/media/rc/Makefile | 1 +
|
||||
drivers/media/rc/rockchip-ir.c | 723 +++++++++++++++++++++++++++++++++
|
||||
3 files changed, 735 insertions(+)
|
||||
create mode 100644 drivers/media/rc/rockchip-ir.c
|
||||
|
||||
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
|
||||
index f560fc38895f..b77fa83e90e8 100644
|
||||
--- a/drivers/media/rc/Kconfig
|
||||
+++ b/drivers/media/rc/Kconfig
|
||||
@@ -333,6 +333,17 @@ config IR_REDRAT3
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called redrat3.
|
||||
|
||||
+config IR_ROCKCHIP_CIR
|
||||
+ tristate "Rockchip GPIO IR receiver"
|
||||
+ depends on (OF && GPIOLIB) || COMPILE_TEST
|
||||
+ help
|
||||
+ Say Y here if you want to use the Rockchip IR receiver with
|
||||
+ virtual poweroff features provided by rockchip Trust OS
|
||||
+
|
||||
+ To compile this driver as a module, choose M here: the
|
||||
+ module will be called rockchip-ir
|
||||
+
|
||||
+
|
||||
config IR_RX51
|
||||
tristate "Nokia N900 IR transmitter diode"
|
||||
depends on (OMAP_DM_TIMER && PWM_OMAP_DMTIMER && ARCH_OMAP2PLUS || COMPILE_TEST) && RC_CORE
|
||||
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
|
||||
index a9285266e944..057d5b64c121 100644
|
||||
--- a/drivers/media/rc/Makefile
|
||||
+++ b/drivers/media/rc/Makefile
|
||||
@@ -43,6 +43,7 @@ obj-$(CONFIG_IR_MTK) += mtk-cir.o
|
||||
obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o
|
||||
obj-$(CONFIG_IR_PWM_TX) += pwm-ir-tx.o
|
||||
obj-$(CONFIG_IR_REDRAT3) += redrat3.o
|
||||
+obj-$(CONFIG_IR_ROCKCHIP_CIR) += rockchip-ir.o
|
||||
obj-$(CONFIG_IR_RX51) += ir-rx51.o
|
||||
obj-$(CONFIG_IR_SERIAL) += serial_ir.o
|
||||
obj-$(CONFIG_IR_SPI) += ir-spi.o
|
||||
diff --git a/drivers/media/rc/rockchip-ir.c b/drivers/media/rc/rockchip-ir.c
|
||||
new file mode 100644
|
||||
index 000000000000..06c483cd8d5b
|
||||
--- /dev/null
|
||||
+++ b/drivers/media/rc/rockchip-ir.c
|
||||
@@ -0,0 +1,723 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-only
|
||||
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
|
||||
+*/
|
||||
+
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/gpio/consumer.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/of_gpio.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/pm_runtime.h>
|
||||
+#include <linux/pm_qos.h>
|
||||
+#include <linux/irq.h>
|
||||
+#include <linux/arm-smccc.h>
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/reboot.h>
|
||||
+#include <uapi/linux/psci.h>
|
||||
+#include <media/rc-core.h>
|
||||
+#include <soc/rockchip/rockchip_sip.h>
|
||||
+
|
||||
+#define ROCKCHIP_IR_DEVICE_NAME "rockchip_ir_recv"
|
||||
+
|
||||
+#ifdef CONFIG_64BIT
|
||||
+#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN64_##name
|
||||
+#else
|
||||
+#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN_##name
|
||||
+#endif
|
||||
+
|
||||
+/*
|
||||
+* SIP/TEE constants for remote calls
|
||||
+*/
|
||||
+#define SIP_REMOTECTL_CFG 0x8200000b
|
||||
+#define SIP_SUSPEND_MODE 0x82000003
|
||||
+#define SIP_REMOTECTL_CFG 0x8200000b
|
||||
+#define SUSPEND_MODE_CONFIG 0x01
|
||||
+#define WKUP_SOURCE_CONFIG 0x02
|
||||
+#define PWM_REGULATOR_CONFIG 0x03
|
||||
+#define GPIO_POWER_CONFIG 0x04
|
||||
+#define SUSPEND_DEBUG_ENABLE 0x05
|
||||
+#define APIOS_SUSPEND_CONFIG 0x06
|
||||
+#define VIRTUAL_POWEROFF 0x07
|
||||
+
|
||||
+#define REMOTECTL_SET_IRQ 0xf0
|
||||
+#define REMOTECTL_SET_PWM_CH 0xf1
|
||||
+#define REMOTECTL_SET_PWRKEY 0xf2
|
||||
+#define REMOTECTL_GET_WAKEUP_STATE 0xf3
|
||||
+#define REMOTECTL_ENABLE 0xf4
|
||||
+#define REMOTECTL_PWRKEY_WAKEUP 0xdeadbeaf /* wakeup state */
|
||||
+
|
||||
+/*
|
||||
+* PWM Registers
|
||||
+* Each PWM has its own control registers
|
||||
+*/
|
||||
+#define PWM_REG_CNTR 0x00 /* Counter Register */
|
||||
+#define PWM_REG_HPR 0x04 /* Period Register */
|
||||
+#define PWM_REG_LPR 0x08 /* Duty Cycle Register */
|
||||
+#define PWM_REG_CTRL 0x0c /* Control Register */
|
||||
+
|
||||
+/*
|
||||
+* PWM General registers
|
||||
+* Registers shared among PWMs
|
||||
+*/
|
||||
+#define PWM_REG_INT_EN 0x44
|
||||
+
|
||||
+/*REG_CTRL bits definitions*/
|
||||
+#define PWM_ENABLE (1 << 0)
|
||||
+#define PWM_DISABLE (0 << 0)
|
||||
+
|
||||
+/*operation mode*/
|
||||
+#define PWM_MODE_ONESHOT (0x00 << 1)
|
||||
+#define PWM_MODE_CONTINUMOUS (0x01 << 1)
|
||||
+#define PWM_MODE_CAPTURE (0x02 << 1)
|
||||
+
|
||||
+/* Channel interrupt enable bit */
|
||||
+#define PWM_CH_INT_ENABLE(n) BIT(n)
|
||||
+
|
||||
+enum pwm_div {
|
||||
+ PWM_DIV1 = (0x0 << 12),
|
||||
+ PWM_DIV2 = (0x1 << 12),
|
||||
+ PWM_DIV4 = (0x2 << 12),
|
||||
+ PWM_DIV8 = (0x3 << 12),
|
||||
+ PWM_DIV16 = (0x4 << 12),
|
||||
+ PWM_DIV32 = (0x5 << 12),
|
||||
+ PWM_DIV64 = (0x6 << 12),
|
||||
+ PWM_DIV128 = (0x7 << 12),
|
||||
+};
|
||||
+
|
||||
+#define PWM_INT_ENABLE 1
|
||||
+#define PWM_INT_DISABLE 0
|
||||
+
|
||||
+struct rockchip_rc_dev {
|
||||
+ struct rc_dev *rcdev;
|
||||
+ struct gpio_desc *gpiod;
|
||||
+ int irq;
|
||||
+ struct device *pmdev;
|
||||
+ struct pm_qos_request qos;
|
||||
+ void __iomem *pwm_base;
|
||||
+ int pwm_wake_irq;
|
||||
+ int pwm_id;
|
||||
+ bool use_shutdown_handler; // if true, installs a shutdown handler and triggers virtual poweroff
|
||||
+ bool use_suspend_handler; // if true, virtual poweroff is used as suspend mode otherwise use as regular suspend
|
||||
+ struct pinctrl *pinctrl;
|
||||
+ struct pinctrl_state *pinctrl_state_default;
|
||||
+ struct pinctrl_state *pinctrl_state_suspend;
|
||||
+};
|
||||
+
|
||||
+static struct arm_smccc_res __invoke_sip_fn_smc(unsigned long function_id,
|
||||
+ unsigned long arg0,
|
||||
+ unsigned long arg1,
|
||||
+ unsigned long arg2)
|
||||
+{
|
||||
+ struct arm_smccc_res res;
|
||||
+
|
||||
+ arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
|
||||
+
|
||||
+ return res;
|
||||
+}
|
||||
+
|
||||
+int sip_smc_remotectl_config(u32 func, u32 data)
|
||||
+{
|
||||
+ struct arm_smccc_res res;
|
||||
+
|
||||
+ res = __invoke_sip_fn_smc(SIP_REMOTECTL_CFG, func, data, 0);
|
||||
+
|
||||
+ return res.a0;
|
||||
+}
|
||||
+
|
||||
+int sip_smc_set_suspend_mode(u32 ctrl, u32 config1, u32 config2)
|
||||
+{
|
||||
+ struct arm_smccc_res res;
|
||||
+
|
||||
+ res = __invoke_sip_fn_smc(SIP_SUSPEND_MODE, ctrl, config1, config2);
|
||||
+ return res.a0;
|
||||
+}
|
||||
+
|
||||
+int sip_smc_virtual_poweroff(void)
|
||||
+{
|
||||
+ struct arm_smccc_res res;
|
||||
+
|
||||
+ res = __invoke_sip_fn_smc(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND), 0, 0, 0);
|
||||
+ return res.a0;
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t rockchip_ir_recv_irq(int irq, void *dev_id)
|
||||
+{
|
||||
+ int val;
|
||||
+ struct rockchip_rc_dev *gpio_dev = dev_id;
|
||||
+ struct device *pmdev = gpio_dev->pmdev;
|
||||
+
|
||||
+ /*
|
||||
+ * For some cpuidle systems, not all:
|
||||
+ * Respond to interrupt taking more latency when cpu in idle.
|
||||
+ * Invoke asynchronous pm runtime get from interrupt context,
|
||||
+ * this may introduce a millisecond delay to call resume callback,
|
||||
+ * where to disable cpuilde.
|
||||
+ *
|
||||
+ * Two issues lead to fail to decode first frame, one is latency to
|
||||
+ * respond to interrupt, another is delay introduced by async api.
|
||||
+ */
|
||||
+ if (pmdev)
|
||||
+ pm_runtime_get(pmdev);
|
||||
+
|
||||
+ val = gpiod_get_value(gpio_dev->gpiod);
|
||||
+ if (val >= 0)
|
||||
+ ir_raw_event_store_edge(gpio_dev->rcdev, val == 1);
|
||||
+
|
||||
+ if (pmdev) {
|
||||
+ pm_runtime_mark_last_busy(pmdev);
|
||||
+ pm_runtime_put_autosuspend(pmdev);
|
||||
+ }
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+static void rockchip_pwm_int_ctrl(struct rockchip_rc_dev *gpio_dev, bool enable)
|
||||
+{
|
||||
+
|
||||
+ void __iomem *pwm_base = gpio_dev->pwm_base;
|
||||
+ struct device *dev = &gpio_dev->rcdev->dev;
|
||||
+ int pwm_id = gpio_dev->pwm_id;
|
||||
+
|
||||
+ void __iomem *reg_int_ctrl;
|
||||
+ int val;
|
||||
+
|
||||
+ reg_int_ctrl= pwm_base - (0x10 * pwm_id) + PWM_REG_INT_EN;
|
||||
+
|
||||
+ val = readl_relaxed(reg_int_ctrl);
|
||||
+
|
||||
+ if (enable) {
|
||||
+ val |= PWM_CH_INT_ENABLE(pwm_id);
|
||||
+ dev_info(dev, "PWM interrupt enabled, register value %x\n", val);
|
||||
+ } else {
|
||||
+ val &= ~PWM_CH_INT_ENABLE(pwm_id);
|
||||
+ dev_info(dev, "PWM interrupt disabled, register value %x\n", val);
|
||||
+ }
|
||||
+
|
||||
+ writel_relaxed(val, reg_int_ctrl);
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static int rockchip_pwm_hw_init(struct rockchip_rc_dev *gpio_dev)
|
||||
+{
|
||||
+
|
||||
+ void __iomem *pwm_base = gpio_dev->pwm_base;
|
||||
+ int val;
|
||||
+
|
||||
+ //1. disabled pwm
|
||||
+ val = readl_relaxed(pwm_base + PWM_REG_CTRL);
|
||||
+ val = (val & 0xFFFFFFFE) | PWM_DISABLE;
|
||||
+ writel_relaxed(val, pwm_base + PWM_REG_CTRL);
|
||||
+
|
||||
+ //2. capture mode
|
||||
+ val = readl_relaxed(pwm_base + PWM_REG_CTRL);
|
||||
+ val = (val & 0xFFFFFFF9) | PWM_MODE_CAPTURE;
|
||||
+ writel_relaxed(val, pwm_base + PWM_REG_CTRL);
|
||||
+
|
||||
+ //set clk div, clk div to 64
|
||||
+ val = readl_relaxed(pwm_base + PWM_REG_CTRL);
|
||||
+ val = (val & 0xFF0001FF) | PWM_DIV64;
|
||||
+ writel_relaxed(val, pwm_base + PWM_REG_CTRL);
|
||||
+
|
||||
+ //4. enabled pwm int
|
||||
+ rockchip_pwm_int_ctrl(gpio_dev, true);
|
||||
+
|
||||
+ //5. enabled pwm
|
||||
+ val = readl_relaxed(pwm_base + PWM_REG_CTRL);
|
||||
+ val = (val & 0xFFFFFFFE) | PWM_ENABLE;
|
||||
+ writel_relaxed(val, pwm_base + PWM_REG_CTRL);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static int rockchip_pwm_hw_stop(struct rockchip_rc_dev *gpio_dev)
|
||||
+{
|
||||
+
|
||||
+ void __iomem *pwm_base = gpio_dev->pwm_base;
|
||||
+ int val;
|
||||
+
|
||||
+ //disable pwm interrupt
|
||||
+ rockchip_pwm_int_ctrl(gpio_dev, false);
|
||||
+
|
||||
+ //disable pwm
|
||||
+ val = readl_relaxed(pwm_base + PWM_REG_CTRL);
|
||||
+ val = (val & 0xFFFFFFFE) | PWM_DISABLE;
|
||||
+ writel_relaxed(val, pwm_base + PWM_REG_CTRL);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static int rockchip_pwm_sip_wakeup_init(struct rockchip_rc_dev *gpio_dev)
|
||||
+{
|
||||
+
|
||||
+ struct device *dev = &gpio_dev->rcdev->dev;
|
||||
+
|
||||
+ struct irq_data *irq_data;
|
||||
+ long hwirq;
|
||||
+ int ret;
|
||||
+
|
||||
+ irq_data = irq_get_irq_data(gpio_dev->pwm_wake_irq);
|
||||
+ if (!irq_data) {
|
||||
+ dev_err(dev, "could not get irq data\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ hwirq = irq_data->hwirq;
|
||||
+ dev_info(dev, "use hwirq %ld, pwm chip id %d for PWM SIP wakeup\n", hwirq, gpio_dev->pwm_id);
|
||||
+
|
||||
+ ret = 0;
|
||||
+
|
||||
+ ret |= sip_smc_remotectl_config(REMOTECTL_SET_IRQ, (int)hwirq);
|
||||
+ ret |= sip_smc_remotectl_config(REMOTECTL_SET_PWM_CH, gpio_dev->pwm_id);
|
||||
+ ret |= sip_smc_remotectl_config(REMOTECTL_ENABLE, 1);
|
||||
+
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "SIP remote controller mode, TEE does not support feature\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ sip_smc_set_suspend_mode(SUSPEND_MODE_CONFIG, 0x10042, 0);
|
||||
+ sip_smc_set_suspend_mode(WKUP_SOURCE_CONFIG, 0x0, 0);
|
||||
+ sip_smc_set_suspend_mode(PWM_REGULATOR_CONFIG, 0x0, 0);
|
||||
+ //sip_smc_set_suspend_mode(GPIO_POWER_CONFIG, i, gpio_temp[i]);
|
||||
+ sip_smc_set_suspend_mode(SUSPEND_DEBUG_ENABLE, 0x1, 0);
|
||||
+ sip_smc_set_suspend_mode(APIOS_SUSPEND_CONFIG, 0x0, 0);
|
||||
+ sip_smc_set_suspend_mode(VIRTUAL_POWEROFF, 0, 1);
|
||||
+
|
||||
+ dev_info(dev, "TEE remote controller wakeup installed\n");
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static int rockchip_ir_recv_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct rockchip_rc_dev *gpio_dev = platform_get_drvdata(pdev);
|
||||
+ struct device *pmdev = gpio_dev->pmdev;
|
||||
+
|
||||
+ if (pmdev) {
|
||||
+ pm_runtime_get_sync(pmdev);
|
||||
+ cpu_latency_qos_remove_request(&gpio_dev->qos);
|
||||
+
|
||||
+ pm_runtime_disable(pmdev);
|
||||
+ pm_runtime_put_noidle(pmdev);
|
||||
+ pm_runtime_set_suspended(pmdev);
|
||||
+ }
|
||||
+
|
||||
+ // Disable the remote controller handling of the Trust OS
|
||||
+ sip_smc_remotectl_config(REMOTECTL_ENABLE, 0);
|
||||
+
|
||||
+ // Disable the virtual poweroff of the Trust OS
|
||||
+ sip_smc_set_suspend_mode(VIRTUAL_POWEROFF, 0, 0);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int rockchip_ir_register_power_key(struct device *dev)
|
||||
+{
|
||||
+
|
||||
+ struct rockchip_rc_dev *gpio_dev = dev_get_drvdata(dev);
|
||||
+
|
||||
+ struct rc_map *key_map;
|
||||
+ struct rc_map_table *key;
|
||||
+ int idx, scancode;
|
||||
+
|
||||
+ key_map = &gpio_dev->rcdev->rc_map;
|
||||
+
|
||||
+ dev_info(dev, "remote key table %s, key map of %d items\n", key_map->name, key_map->len);
|
||||
+
|
||||
+ for (idx = 0; idx < key_map->len; idx++) {
|
||||
+
|
||||
+ key = &key_map->scan[idx];
|
||||
+
|
||||
+ if (key->keycode != KEY_POWER)
|
||||
+ continue;
|
||||
+
|
||||
+ scancode = ((key->scancode & 0xff0000) >> 8) | ((key->scancode & 0xff00) << 8);
|
||||
+ scancode |= (~key->scancode) & 0xff;
|
||||
+ scancode <<= 8;
|
||||
+
|
||||
+ sip_smc_remotectl_config(REMOTECTL_SET_PWRKEY, scancode);
|
||||
+
|
||||
+ dev_info(dev, "registered scancode %08llx (SIP: %8x)\n", key->scancode, scancode);
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static int rockchip_ir_recv_suspend_prepare(struct device *dev)
|
||||
+{
|
||||
+ struct rockchip_rc_dev *gpio_dev = dev_get_drvdata(dev);
|
||||
+ int ret;
|
||||
+
|
||||
+ dev_info(dev, "initialize rockchip SIP virtual poweroff\n");
|
||||
+ ret = rockchip_pwm_sip_wakeup_init(gpio_dev);
|
||||
+
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ rockchip_ir_register_power_key(dev);
|
||||
+
|
||||
+ disable_irq(gpio_dev->irq);
|
||||
+ dev_info(dev, "GPIO IRQ disabled\n");
|
||||
+
|
||||
+ ret = pinctrl_select_state(gpio_dev->pinctrl, gpio_dev->pinctrl_state_suspend);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "unable to set pin in PWM mode\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ dev_info(dev, "set pin configuration to PWM mode\n");
|
||||
+
|
||||
+ rockchip_pwm_hw_init(gpio_dev);
|
||||
+ dev_info(dev, "started pin PWM mode\n");
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+#ifdef CONFIG_PM
|
||||
+static int rockchip_ir_recv_suspend(struct device *dev)
|
||||
+{
|
||||
+ struct rockchip_rc_dev *gpio_dev = dev_get_drvdata(dev);
|
||||
+
|
||||
+ /*
|
||||
+ * if property suspend-is-virtual-poweroff is set, we can disable
|
||||
+ * the regular gpio wakeup and enable the PWM mode for the Trust OS
|
||||
+ * to take control and react to remote control.
|
||||
+ * If the property is not set, we instead enable the wake up for the
|
||||
+ * regular gpio.
|
||||
+ */
|
||||
+ if (gpio_dev->use_suspend_handler) {
|
||||
+
|
||||
+ rockchip_ir_recv_suspend_prepare(dev);
|
||||
+
|
||||
+ } else {
|
||||
+
|
||||
+ if (device_may_wakeup(dev))
|
||||
+ enable_irq_wake(gpio_dev->irq);
|
||||
+ else
|
||||
+ disable_irq(gpio_dev->irq);
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int rockchip_ir_recv_resume(struct device *dev)
|
||||
+{
|
||||
+ struct rockchip_rc_dev *gpio_dev = dev_get_drvdata(dev);
|
||||
+ int ret;
|
||||
+
|
||||
+ /*
|
||||
+ * In case suspend-is-virtual-poweroff property is set,
|
||||
+ * restore the pin from PWM mode to regular GPIO configuration
|
||||
+ * and stop the PWM function.
|
||||
+ * Otherwise, just enable the regular GPIO irq
|
||||
+ */
|
||||
+ if (gpio_dev->use_suspend_handler) {
|
||||
+
|
||||
+ rockchip_pwm_hw_stop(gpio_dev);
|
||||
+ dev_info(dev, "stopped pin PWM mode\n");
|
||||
+
|
||||
+ ret = pinctrl_select_state(gpio_dev->pinctrl, gpio_dev->pinctrl_state_default);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "unable to restore pin in GPIO mode\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+ dev_info(dev, "restored pin configuration di GPIO\n");
|
||||
+
|
||||
+ enable_irq(gpio_dev->irq);
|
||||
+ dev_info(dev, "restored GPIO IRQ\n");
|
||||
+
|
||||
+ } else {
|
||||
+
|
||||
+ if (device_may_wakeup(dev))
|
||||
+ disable_irq_wake(gpio_dev->irq);
|
||||
+ else
|
||||
+ enable_irq(gpio_dev->irq);
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void rockchip_ir_recv_shutdown(struct platform_device *pdev)
|
||||
+{
|
||||
+
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct rockchip_rc_dev *gpio_dev = dev_get_drvdata(dev);
|
||||
+
|
||||
+ if (gpio_dev->use_shutdown_handler)
|
||||
+ rockchip_ir_recv_suspend_prepare(dev);
|
||||
+
|
||||
+ return;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static int rockchip_ir_recv_sys_off(struct sys_off_data *data)
|
||||
+{
|
||||
+
|
||||
+ sip_smc_virtual_poweroff();
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static int rockchip_ir_recv_init_sip(void)
|
||||
+{
|
||||
+ struct arm_smccc_res res;
|
||||
+
|
||||
+ arm_smccc_smc(ROCKCHIP_SIP_SIP_VERSION, ROCKCHIP_SIP_IMPLEMENT_V2, SECURE_REG_WR, 0, 0, 0, 0, 0, &res);
|
||||
+
|
||||
+ if (res.a0)
|
||||
+ return 0;
|
||||
+
|
||||
+ return res.a1;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static int rockchip_ir_recv_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct device_node *np = dev->of_node;
|
||||
+ struct rockchip_rc_dev *gpio_dev;
|
||||
+ struct rc_dev *rcdev;
|
||||
+ struct clk *clk;
|
||||
+ struct clk *p_clk;
|
||||
+ struct resource *res;
|
||||
+ u32 period = 0;
|
||||
+ int rc;
|
||||
+ int ret;
|
||||
+ int pwm_wake_irq;
|
||||
+ int clocks;
|
||||
+
|
||||
+ if (!np)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ gpio_dev = devm_kzalloc(dev, sizeof(*gpio_dev), GFP_KERNEL);
|
||||
+ if (!gpio_dev)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ gpio_dev->gpiod = devm_gpiod_get(dev, NULL, GPIOD_IN);
|
||||
+ if (IS_ERR(gpio_dev->gpiod)) {
|
||||
+ rc = PTR_ERR(gpio_dev->gpiod);
|
||||
+ /* Just try again if this happens */
|
||||
+ if (rc != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "error getting gpio (%d)\n", rc);
|
||||
+ return rc;
|
||||
+ }
|
||||
+ gpio_dev->irq = gpiod_to_irq(gpio_dev->gpiod);
|
||||
+ if (gpio_dev->irq < 0)
|
||||
+ return gpio_dev->irq;
|
||||
+
|
||||
+ rcdev = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW);
|
||||
+ if (!rcdev)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ rcdev->priv = gpio_dev;
|
||||
+ rcdev->device_name = ROCKCHIP_IR_DEVICE_NAME;
|
||||
+ rcdev->input_phys = ROCKCHIP_IR_DEVICE_NAME "/input0";
|
||||
+ rcdev->input_id.bustype = BUS_HOST;
|
||||
+ rcdev->input_id.vendor = 0x0001;
|
||||
+ rcdev->input_id.product = 0x0001;
|
||||
+ rcdev->input_id.version = 0x0100;
|
||||
+ rcdev->dev.parent = dev;
|
||||
+ rcdev->driver_name = KBUILD_MODNAME;
|
||||
+ rcdev->min_timeout = 1;
|
||||
+ rcdev->timeout = IR_DEFAULT_TIMEOUT;
|
||||
+ rcdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
|
||||
+ rcdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
|
||||
+ rcdev->map_name = of_get_property(np, "linux,rc-map-name", NULL);
|
||||
+ if (!rcdev->map_name)
|
||||
+ rcdev->map_name = RC_MAP_EMPTY;
|
||||
+
|
||||
+ gpio_dev->rcdev = rcdev;
|
||||
+ if (of_property_read_bool(np, "wakeup-source")) {
|
||||
+
|
||||
+ ret = device_init_wakeup(dev, true);
|
||||
+
|
||||
+ if (ret)
|
||||
+ dev_err(dev, "could not init wakeup device\n");
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ rc = devm_rc_register_device(dev, rcdev);
|
||||
+ if (rc < 0) {
|
||||
+ dev_err(dev, "failed to register rc device (%d)\n", rc);
|
||||
+ return rc;
|
||||
+ }
|
||||
+
|
||||
+ of_property_read_u32(np, "linux,autosuspend-period", &period);
|
||||
+ if (period) {
|
||||
+ gpio_dev->pmdev = dev;
|
||||
+ pm_runtime_set_autosuspend_delay(dev, period);
|
||||
+ pm_runtime_use_autosuspend(dev);
|
||||
+ pm_runtime_set_suspended(dev);
|
||||
+ pm_runtime_enable(dev);
|
||||
+ }
|
||||
+
|
||||
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+ if (!res) {
|
||||
+ dev_err(dev, "no memory resources defined\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ gpio_dev->pwm_base = devm_ioremap_resource(dev, res);
|
||||
+ if (IS_ERR(gpio_dev->pwm_base))
|
||||
+ return PTR_ERR(gpio_dev->pwm_base);
|
||||
+
|
||||
+ clocks = of_property_count_strings(np, "clock-names");
|
||||
+ if (clocks == 2) {
|
||||
+ clk = devm_clk_get(dev, "pwm");
|
||||
+ p_clk = devm_clk_get(dev, "pclk");
|
||||
+ } else {
|
||||
+ clk = devm_clk_get(dev, NULL);
|
||||
+ p_clk = clk;
|
||||
+ }
|
||||
+
|
||||
+ if (IS_ERR(clk)) {
|
||||
+ ret = PTR_ERR(clk);
|
||||
+ if (ret != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Can't get bus clock: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if (IS_ERR(p_clk)) {
|
||||
+ ret = PTR_ERR(p_clk);
|
||||
+ if (ret != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Can't get peripheral clock: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = clk_prepare_enable(clk);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "Can't enable bus clk: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = clk_prepare_enable(p_clk);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "Can't enable peripheral clk: %d\n", ret);
|
||||
+ goto error_clk;
|
||||
+ }
|
||||
+
|
||||
+ pwm_wake_irq = platform_get_irq(pdev, 0);
|
||||
+ if (pwm_wake_irq < 0) {
|
||||
+ dev_err(&pdev->dev, "cannot find PWM wake interrupt\n");
|
||||
+ goto error_pclk;
|
||||
+ }
|
||||
+
|
||||
+ gpio_dev->pwm_wake_irq = pwm_wake_irq;
|
||||
+ ret = enable_irq_wake(pwm_wake_irq);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "could not enable IRQ wakeup\n");
|
||||
+ }
|
||||
+
|
||||
+ ret = of_property_read_u32(np, "pwm-id", &gpio_dev->pwm_id);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "missing pwm-id property\n");
|
||||
+ goto error_pclk;
|
||||
+ }
|
||||
+
|
||||
+ if (gpio_dev->pwm_id > 3) {
|
||||
+ dev_err(dev, "invalid pwm-id property\n");
|
||||
+ goto error_pclk;
|
||||
+ }
|
||||
+
|
||||
+ gpio_dev->use_shutdown_handler = of_property_read_bool(np, "shutdown-is-virtual-poweroff");
|
||||
+ gpio_dev->use_suspend_handler = of_property_read_bool(np, "suspend-is-virtual-poweroff");
|
||||
+
|
||||
+ gpio_dev->pinctrl = devm_pinctrl_get(dev);
|
||||
+ if (IS_ERR(gpio_dev->pinctrl)) {
|
||||
+ dev_err(dev, "Unable to get pinctrl\n");
|
||||
+ goto error_pclk;
|
||||
+ }
|
||||
+
|
||||
+ gpio_dev->pinctrl_state_default = pinctrl_lookup_state(gpio_dev->pinctrl, "default");
|
||||
+ if (IS_ERR(gpio_dev->pinctrl_state_default)) {
|
||||
+ dev_err(dev, "Unable to get default pinctrl state\n");
|
||||
+ goto error_pclk;
|
||||
+ }
|
||||
+
|
||||
+ gpio_dev->pinctrl_state_suspend = pinctrl_lookup_state(gpio_dev->pinctrl, "suspend");
|
||||
+ if (IS_ERR(gpio_dev->pinctrl_state_suspend)) {
|
||||
+ dev_err(dev, "Unable to get suspend pinctrl state\n");
|
||||
+ goto error_pclk;
|
||||
+ }
|
||||
+
|
||||
+ platform_set_drvdata(pdev, gpio_dev);
|
||||
+
|
||||
+ ret = devm_request_irq(dev, gpio_dev->irq, rockchip_ir_recv_irq,
|
||||
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
|
||||
+ "gpio-ir-recv-irq", gpio_dev);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "Can't request GPIO interrupt\n");
|
||||
+ goto error_pclk;
|
||||
+ }
|
||||
+
|
||||
+ if (gpio_dev->use_shutdown_handler) {
|
||||
+
|
||||
+ ret = devm_register_sys_off_handler(dev, SYS_OFF_MODE_POWER_OFF,
|
||||
+ SYS_OFF_PRIO_FIRMWARE, rockchip_ir_recv_sys_off, NULL);
|
||||
+
|
||||
+ if (ret)
|
||||
+ dev_err(dev, "could not register sys_off handler\n");
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ ret = rockchip_ir_recv_init_sip();
|
||||
+ if (!ret) {
|
||||
+ dev_err(dev, "Unable to initialize Rockchip SIP v2, virtual poweroff unavailable\n");
|
||||
+ gpio_dev->use_shutdown_handler = false;
|
||||
+ gpio_dev->use_suspend_handler = false;
|
||||
+ } else {
|
||||
+ dev_info(dev, "rockchip SIP initialized, version 0x%x\n", ret);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+error_pclk:
|
||||
+ clk_unprepare(p_clk);
|
||||
+error_clk:
|
||||
+ clk_unprepare(clk);
|
||||
+
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static const struct dev_pm_ops rockchip_ir_recv_pm_ops = {
|
||||
+ .suspend = rockchip_ir_recv_suspend,
|
||||
+ .resume = rockchip_ir_recv_resume,
|
||||
+};
|
||||
+#endif
|
||||
+
|
||||
+static const struct of_device_id rockchip_ir_recv_of_match[] = {
|
||||
+ { .compatible = "rockchip-ir", },
|
||||
+ { },
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, rockchip_ir_recv_of_match);
|
||||
+
|
||||
+static struct platform_driver rockchip_ir_recv_driver = {
|
||||
+ .probe = rockchip_ir_recv_probe,
|
||||
+ .remove = rockchip_ir_recv_remove,
|
||||
+ .shutdown = rockchip_ir_recv_shutdown,
|
||||
+ .driver = {
|
||||
+ .name = KBUILD_MODNAME,
|
||||
+ .of_match_table = of_match_ptr(rockchip_ir_recv_of_match),
|
||||
+#ifdef CONFIG_PM
|
||||
+ .pm = &rockchip_ir_recv_pm_ops,
|
||||
+#endif
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(rockchip_ir_recv_driver);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Rockchip IR Receiver driver");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@ -14,11 +14,12 @@ dtbo-$(CONFIG_ARCH_ROCKCHIP) += \
|
||||
rk322x-led-conf5.dtbo \
|
||||
rk322x-led-conf6.dtbo \
|
||||
rk322x-led-conf7.dtbo \
|
||||
rk322x-led-conf8.dtbo \
|
||||
rk322x-led-conf8.dtbo \
|
||||
rk322x-cpu-hs.dtbo \
|
||||
rk322x-cpu-hs-lv.dtbo \
|
||||
rk322x-wlan-alt-wiring.dtbo \
|
||||
rk322x-cpu-stability.dtbo \
|
||||
rk322x-ir-wakeup.dtbo \
|
||||
rk322x-ddr3-330.dtbo \
|
||||
rk322x-ddr3-528.dtbo \
|
||||
rk322x-ddr3-660.dtbo \
|
||||
|
||||
@ -18,6 +18,7 @@ rk322x (Rockchip)
|
||||
- rk322x-ddr3-*
|
||||
- rk322x-bt-*
|
||||
- rk322x-usb-otg-peripheral
|
||||
- rk322x-ir-wakeup
|
||||
|
||||
### Overlay details:
|
||||
|
||||
@ -89,3 +90,10 @@ rk322x-bt-8723cs: enable this overlay for 8723cs and 8703bs wifi/bluetooth
|
||||
|
||||
Set the OTG USB port to peripheral mode to be used as USB slave instead
|
||||
of USB host
|
||||
|
||||
### rk322x-ir-wakeup
|
||||
|
||||
Enable the rockchip-ir-driver in place of the standard gpio-ir-receiver.
|
||||
The rockchip-specific driver exploits the Trust OS and Virtual Poweroff mode
|
||||
to allow power up via remote controller power button.
|
||||
|
||||
|
||||
16
patch/kernel/archive/rk322x-6.1/overlay/rk322x-ir-wakeup.dts
Normal file
16
patch/kernel/archive/rk322x-6.1/overlay/rk322x-ir-wakeup.dts
Normal file
@ -0,0 +1,16 @@
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
/*
|
||||
* Disable regular gpio-ir-receiver and enable
|
||||
* rockchip-ir-receiver driver; also enables virtual
|
||||
* poweroff on shutdown to allow restart with power key
|
||||
* on remote controller
|
||||
*/
|
||||
&ir_receiver {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&rockchip_ir_receiver {
|
||||
status = "okay";
|
||||
};
|
||||
@ -119,6 +119,22 @@
|
||||
linux,rc-map-name = "rc-rk322x-tvbox";
|
||||
};
|
||||
|
||||
rockchip_ir_receiver: rockchip-ir-receiver {
|
||||
compatible = "rockchip-ir-receiver";
|
||||
reg = <0x110b0030 0x10>;
|
||||
gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_LOW>;
|
||||
clocks = <&cru PCLK_PWM>;
|
||||
interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
|
||||
linux,rc-map-name = "rc-rk322x-tvbox";
|
||||
pinctrl-names = "default", "suspend";
|
||||
pinctrl-0 = <&ir_int>;
|
||||
pinctrl-1 = <&pwm3_pin>;
|
||||
pwm-id = <3>;
|
||||
shutdown-is-virtual-poweroff;
|
||||
wakeup-source;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
sdio_pwrseq: sdio-pwrseq {
|
||||
compatible = "mmc-pwrseq-simple";
|
||||
pinctrl-names = "default";
|
||||
@ -735,14 +751,14 @@
|
||||
rockchip,hw-tshut-mode = <0>;
|
||||
rockchip,hw-tshut-polarity = <1>;
|
||||
rockchip,hw-tshut-temp = <110000>;
|
||||
|
||||
|
||||
/* delete the pinctrl-* properties because, on mainline kernel, they (in particular "default")
|
||||
change the GPIO configuration of the associated PIN. On most boards that pin is not connected
|
||||
so it does not do anything, but some other boards (X96-Mini) have that pin connected to
|
||||
a reset pin of the soc or whatever, thus changing the configuration of the pin at boot
|
||||
a reset pin of the soc or whatever, thus changing the configuration of the pin at boot
|
||||
causes them to bootloop.
|
||||
We don't really need these ones though, because since hw-tshut-mode is set to 0, the CRU
|
||||
unit of the SoC does the reboot*/
|
||||
unit of the SoC does the reboot*/
|
||||
/delete-property/ pinctrl-names;
|
||||
/delete-property/ pinctrl-0;
|
||||
/delete-property/ pinctrl-1;
|
||||
|
||||
@ -0,0 +1,778 @@
|
||||
From 13498feb91614d59ebece61d0c278e31529bb8c8 Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Sabatino <paolo.sabatino@gmail.com>
|
||||
Date: Tue, 10 Oct 2023 21:54:51 +0200
|
||||
Subject: [PATCH] rockchip gpio IR driver
|
||||
|
||||
---
|
||||
drivers/media/rc/Kconfig | 11 +
|
||||
drivers/media/rc/Makefile | 1 +
|
||||
drivers/media/rc/rockchip-ir.c | 723 +++++++++++++++++++++++++++++++++
|
||||
3 files changed, 735 insertions(+)
|
||||
create mode 100644 drivers/media/rc/rockchip-ir.c
|
||||
|
||||
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
|
||||
index f560fc38895f..b77fa83e90e8 100644
|
||||
--- a/drivers/media/rc/Kconfig
|
||||
+++ b/drivers/media/rc/Kconfig
|
||||
@@ -333,6 +333,17 @@ config IR_REDRAT3
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called redrat3.
|
||||
|
||||
+config IR_ROCKCHIP_CIR
|
||||
+ tristate "Rockchip GPIO IR receiver"
|
||||
+ depends on (OF && GPIOLIB) || COMPILE_TEST
|
||||
+ help
|
||||
+ Say Y here if you want to use the Rockchip IR receiver with
|
||||
+ virtual poweroff features provided by rockchip Trust OS
|
||||
+
|
||||
+ To compile this driver as a module, choose M here: the
|
||||
+ module will be called rockchip-ir
|
||||
+
|
||||
+
|
||||
config IR_RX51
|
||||
tristate "Nokia N900 IR transmitter diode"
|
||||
depends on (OMAP_DM_TIMER && PWM_OMAP_DMTIMER && ARCH_OMAP2PLUS || COMPILE_TEST) && RC_CORE
|
||||
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
|
||||
index a9285266e944..057d5b64c121 100644
|
||||
--- a/drivers/media/rc/Makefile
|
||||
+++ b/drivers/media/rc/Makefile
|
||||
@@ -43,6 +43,7 @@ obj-$(CONFIG_IR_MTK) += mtk-cir.o
|
||||
obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o
|
||||
obj-$(CONFIG_IR_PWM_TX) += pwm-ir-tx.o
|
||||
obj-$(CONFIG_IR_REDRAT3) += redrat3.o
|
||||
+obj-$(CONFIG_IR_ROCKCHIP_CIR) += rockchip-ir.o
|
||||
obj-$(CONFIG_IR_RX51) += ir-rx51.o
|
||||
obj-$(CONFIG_IR_SERIAL) += serial_ir.o
|
||||
obj-$(CONFIG_IR_SPI) += ir-spi.o
|
||||
diff --git a/drivers/media/rc/rockchip-ir.c b/drivers/media/rc/rockchip-ir.c
|
||||
new file mode 100644
|
||||
index 000000000000..06c483cd8d5b
|
||||
--- /dev/null
|
||||
+++ b/drivers/media/rc/rockchip-ir.c
|
||||
@@ -0,0 +1,723 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-only
|
||||
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
|
||||
+*/
|
||||
+
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/gpio/consumer.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/of_gpio.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/pm_runtime.h>
|
||||
+#include <linux/pm_qos.h>
|
||||
+#include <linux/irq.h>
|
||||
+#include <linux/arm-smccc.h>
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/reboot.h>
|
||||
+#include <uapi/linux/psci.h>
|
||||
+#include <media/rc-core.h>
|
||||
+#include <soc/rockchip/rockchip_sip.h>
|
||||
+
|
||||
+#define ROCKCHIP_IR_DEVICE_NAME "rockchip_ir_recv"
|
||||
+
|
||||
+#ifdef CONFIG_64BIT
|
||||
+#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN64_##name
|
||||
+#else
|
||||
+#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN_##name
|
||||
+#endif
|
||||
+
|
||||
+/*
|
||||
+* SIP/TEE constants for remote calls
|
||||
+*/
|
||||
+#define SIP_REMOTECTL_CFG 0x8200000b
|
||||
+#define SIP_SUSPEND_MODE 0x82000003
|
||||
+#define SIP_REMOTECTL_CFG 0x8200000b
|
||||
+#define SUSPEND_MODE_CONFIG 0x01
|
||||
+#define WKUP_SOURCE_CONFIG 0x02
|
||||
+#define PWM_REGULATOR_CONFIG 0x03
|
||||
+#define GPIO_POWER_CONFIG 0x04
|
||||
+#define SUSPEND_DEBUG_ENABLE 0x05
|
||||
+#define APIOS_SUSPEND_CONFIG 0x06
|
||||
+#define VIRTUAL_POWEROFF 0x07
|
||||
+
|
||||
+#define REMOTECTL_SET_IRQ 0xf0
|
||||
+#define REMOTECTL_SET_PWM_CH 0xf1
|
||||
+#define REMOTECTL_SET_PWRKEY 0xf2
|
||||
+#define REMOTECTL_GET_WAKEUP_STATE 0xf3
|
||||
+#define REMOTECTL_ENABLE 0xf4
|
||||
+#define REMOTECTL_PWRKEY_WAKEUP 0xdeadbeaf /* wakeup state */
|
||||
+
|
||||
+/*
|
||||
+* PWM Registers
|
||||
+* Each PWM has its own control registers
|
||||
+*/
|
||||
+#define PWM_REG_CNTR 0x00 /* Counter Register */
|
||||
+#define PWM_REG_HPR 0x04 /* Period Register */
|
||||
+#define PWM_REG_LPR 0x08 /* Duty Cycle Register */
|
||||
+#define PWM_REG_CTRL 0x0c /* Control Register */
|
||||
+
|
||||
+/*
|
||||
+* PWM General registers
|
||||
+* Registers shared among PWMs
|
||||
+*/
|
||||
+#define PWM_REG_INT_EN 0x44
|
||||
+
|
||||
+/*REG_CTRL bits definitions*/
|
||||
+#define PWM_ENABLE (1 << 0)
|
||||
+#define PWM_DISABLE (0 << 0)
|
||||
+
|
||||
+/*operation mode*/
|
||||
+#define PWM_MODE_ONESHOT (0x00 << 1)
|
||||
+#define PWM_MODE_CONTINUMOUS (0x01 << 1)
|
||||
+#define PWM_MODE_CAPTURE (0x02 << 1)
|
||||
+
|
||||
+/* Channel interrupt enable bit */
|
||||
+#define PWM_CH_INT_ENABLE(n) BIT(n)
|
||||
+
|
||||
+enum pwm_div {
|
||||
+ PWM_DIV1 = (0x0 << 12),
|
||||
+ PWM_DIV2 = (0x1 << 12),
|
||||
+ PWM_DIV4 = (0x2 << 12),
|
||||
+ PWM_DIV8 = (0x3 << 12),
|
||||
+ PWM_DIV16 = (0x4 << 12),
|
||||
+ PWM_DIV32 = (0x5 << 12),
|
||||
+ PWM_DIV64 = (0x6 << 12),
|
||||
+ PWM_DIV128 = (0x7 << 12),
|
||||
+};
|
||||
+
|
||||
+#define PWM_INT_ENABLE 1
|
||||
+#define PWM_INT_DISABLE 0
|
||||
+
|
||||
+struct rockchip_rc_dev {
|
||||
+ struct rc_dev *rcdev;
|
||||
+ struct gpio_desc *gpiod;
|
||||
+ int irq;
|
||||
+ struct device *pmdev;
|
||||
+ struct pm_qos_request qos;
|
||||
+ void __iomem *pwm_base;
|
||||
+ int pwm_wake_irq;
|
||||
+ int pwm_id;
|
||||
+ bool use_shutdown_handler; // if true, installs a shutdown handler and triggers virtual poweroff
|
||||
+ bool use_suspend_handler; // if true, virtual poweroff is used as suspend mode otherwise use as regular suspend
|
||||
+ struct pinctrl *pinctrl;
|
||||
+ struct pinctrl_state *pinctrl_state_default;
|
||||
+ struct pinctrl_state *pinctrl_state_suspend;
|
||||
+};
|
||||
+
|
||||
+static struct arm_smccc_res __invoke_sip_fn_smc(unsigned long function_id,
|
||||
+ unsigned long arg0,
|
||||
+ unsigned long arg1,
|
||||
+ unsigned long arg2)
|
||||
+{
|
||||
+ struct arm_smccc_res res;
|
||||
+
|
||||
+ arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
|
||||
+
|
||||
+ return res;
|
||||
+}
|
||||
+
|
||||
+int sip_smc_remotectl_config(u32 func, u32 data)
|
||||
+{
|
||||
+ struct arm_smccc_res res;
|
||||
+
|
||||
+ res = __invoke_sip_fn_smc(SIP_REMOTECTL_CFG, func, data, 0);
|
||||
+
|
||||
+ return res.a0;
|
||||
+}
|
||||
+
|
||||
+int sip_smc_set_suspend_mode(u32 ctrl, u32 config1, u32 config2)
|
||||
+{
|
||||
+ struct arm_smccc_res res;
|
||||
+
|
||||
+ res = __invoke_sip_fn_smc(SIP_SUSPEND_MODE, ctrl, config1, config2);
|
||||
+ return res.a0;
|
||||
+}
|
||||
+
|
||||
+int sip_smc_virtual_poweroff(void)
|
||||
+{
|
||||
+ struct arm_smccc_res res;
|
||||
+
|
||||
+ res = __invoke_sip_fn_smc(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND), 0, 0, 0);
|
||||
+ return res.a0;
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t rockchip_ir_recv_irq(int irq, void *dev_id)
|
||||
+{
|
||||
+ int val;
|
||||
+ struct rockchip_rc_dev *gpio_dev = dev_id;
|
||||
+ struct device *pmdev = gpio_dev->pmdev;
|
||||
+
|
||||
+ /*
|
||||
+ * For some cpuidle systems, not all:
|
||||
+ * Respond to interrupt taking more latency when cpu in idle.
|
||||
+ * Invoke asynchronous pm runtime get from interrupt context,
|
||||
+ * this may introduce a millisecond delay to call resume callback,
|
||||
+ * where to disable cpuilde.
|
||||
+ *
|
||||
+ * Two issues lead to fail to decode first frame, one is latency to
|
||||
+ * respond to interrupt, another is delay introduced by async api.
|
||||
+ */
|
||||
+ if (pmdev)
|
||||
+ pm_runtime_get(pmdev);
|
||||
+
|
||||
+ val = gpiod_get_value(gpio_dev->gpiod);
|
||||
+ if (val >= 0)
|
||||
+ ir_raw_event_store_edge(gpio_dev->rcdev, val == 1);
|
||||
+
|
||||
+ if (pmdev) {
|
||||
+ pm_runtime_mark_last_busy(pmdev);
|
||||
+ pm_runtime_put_autosuspend(pmdev);
|
||||
+ }
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+static void rockchip_pwm_int_ctrl(struct rockchip_rc_dev *gpio_dev, bool enable)
|
||||
+{
|
||||
+
|
||||
+ void __iomem *pwm_base = gpio_dev->pwm_base;
|
||||
+ struct device *dev = &gpio_dev->rcdev->dev;
|
||||
+ int pwm_id = gpio_dev->pwm_id;
|
||||
+
|
||||
+ void __iomem *reg_int_ctrl;
|
||||
+ int val;
|
||||
+
|
||||
+ reg_int_ctrl= pwm_base - (0x10 * pwm_id) + PWM_REG_INT_EN;
|
||||
+
|
||||
+ val = readl_relaxed(reg_int_ctrl);
|
||||
+
|
||||
+ if (enable) {
|
||||
+ val |= PWM_CH_INT_ENABLE(pwm_id);
|
||||
+ dev_info(dev, "PWM interrupt enabled, register value %x\n", val);
|
||||
+ } else {
|
||||
+ val &= ~PWM_CH_INT_ENABLE(pwm_id);
|
||||
+ dev_info(dev, "PWM interrupt disabled, register value %x\n", val);
|
||||
+ }
|
||||
+
|
||||
+ writel_relaxed(val, reg_int_ctrl);
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static int rockchip_pwm_hw_init(struct rockchip_rc_dev *gpio_dev)
|
||||
+{
|
||||
+
|
||||
+ void __iomem *pwm_base = gpio_dev->pwm_base;
|
||||
+ int val;
|
||||
+
|
||||
+ //1. disabled pwm
|
||||
+ val = readl_relaxed(pwm_base + PWM_REG_CTRL);
|
||||
+ val = (val & 0xFFFFFFFE) | PWM_DISABLE;
|
||||
+ writel_relaxed(val, pwm_base + PWM_REG_CTRL);
|
||||
+
|
||||
+ //2. capture mode
|
||||
+ val = readl_relaxed(pwm_base + PWM_REG_CTRL);
|
||||
+ val = (val & 0xFFFFFFF9) | PWM_MODE_CAPTURE;
|
||||
+ writel_relaxed(val, pwm_base + PWM_REG_CTRL);
|
||||
+
|
||||
+ //set clk div, clk div to 64
|
||||
+ val = readl_relaxed(pwm_base + PWM_REG_CTRL);
|
||||
+ val = (val & 0xFF0001FF) | PWM_DIV64;
|
||||
+ writel_relaxed(val, pwm_base + PWM_REG_CTRL);
|
||||
+
|
||||
+ //4. enabled pwm int
|
||||
+ rockchip_pwm_int_ctrl(gpio_dev, true);
|
||||
+
|
||||
+ //5. enabled pwm
|
||||
+ val = readl_relaxed(pwm_base + PWM_REG_CTRL);
|
||||
+ val = (val & 0xFFFFFFFE) | PWM_ENABLE;
|
||||
+ writel_relaxed(val, pwm_base + PWM_REG_CTRL);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static int rockchip_pwm_hw_stop(struct rockchip_rc_dev *gpio_dev)
|
||||
+{
|
||||
+
|
||||
+ void __iomem *pwm_base = gpio_dev->pwm_base;
|
||||
+ int val;
|
||||
+
|
||||
+ //disable pwm interrupt
|
||||
+ rockchip_pwm_int_ctrl(gpio_dev, false);
|
||||
+
|
||||
+ //disable pwm
|
||||
+ val = readl_relaxed(pwm_base + PWM_REG_CTRL);
|
||||
+ val = (val & 0xFFFFFFFE) | PWM_DISABLE;
|
||||
+ writel_relaxed(val, pwm_base + PWM_REG_CTRL);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static int rockchip_pwm_sip_wakeup_init(struct rockchip_rc_dev *gpio_dev)
|
||||
+{
|
||||
+
|
||||
+ struct device *dev = &gpio_dev->rcdev->dev;
|
||||
+
|
||||
+ struct irq_data *irq_data;
|
||||
+ long hwirq;
|
||||
+ int ret;
|
||||
+
|
||||
+ irq_data = irq_get_irq_data(gpio_dev->pwm_wake_irq);
|
||||
+ if (!irq_data) {
|
||||
+ dev_err(dev, "could not get irq data\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ hwirq = irq_data->hwirq;
|
||||
+ dev_info(dev, "use hwirq %ld, pwm chip id %d for PWM SIP wakeup\n", hwirq, gpio_dev->pwm_id);
|
||||
+
|
||||
+ ret = 0;
|
||||
+
|
||||
+ ret |= sip_smc_remotectl_config(REMOTECTL_SET_IRQ, (int)hwirq);
|
||||
+ ret |= sip_smc_remotectl_config(REMOTECTL_SET_PWM_CH, gpio_dev->pwm_id);
|
||||
+ ret |= sip_smc_remotectl_config(REMOTECTL_ENABLE, 1);
|
||||
+
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "SIP remote controller mode, TEE does not support feature\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ sip_smc_set_suspend_mode(SUSPEND_MODE_CONFIG, 0x10042, 0);
|
||||
+ sip_smc_set_suspend_mode(WKUP_SOURCE_CONFIG, 0x0, 0);
|
||||
+ sip_smc_set_suspend_mode(PWM_REGULATOR_CONFIG, 0x0, 0);
|
||||
+ //sip_smc_set_suspend_mode(GPIO_POWER_CONFIG, i, gpio_temp[i]);
|
||||
+ sip_smc_set_suspend_mode(SUSPEND_DEBUG_ENABLE, 0x1, 0);
|
||||
+ sip_smc_set_suspend_mode(APIOS_SUSPEND_CONFIG, 0x0, 0);
|
||||
+ sip_smc_set_suspend_mode(VIRTUAL_POWEROFF, 0, 1);
|
||||
+
|
||||
+ dev_info(dev, "TEE remote controller wakeup installed\n");
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static int rockchip_ir_recv_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct rockchip_rc_dev *gpio_dev = platform_get_drvdata(pdev);
|
||||
+ struct device *pmdev = gpio_dev->pmdev;
|
||||
+
|
||||
+ if (pmdev) {
|
||||
+ pm_runtime_get_sync(pmdev);
|
||||
+ cpu_latency_qos_remove_request(&gpio_dev->qos);
|
||||
+
|
||||
+ pm_runtime_disable(pmdev);
|
||||
+ pm_runtime_put_noidle(pmdev);
|
||||
+ pm_runtime_set_suspended(pmdev);
|
||||
+ }
|
||||
+
|
||||
+ // Disable the remote controller handling of the Trust OS
|
||||
+ sip_smc_remotectl_config(REMOTECTL_ENABLE, 0);
|
||||
+
|
||||
+ // Disable the virtual poweroff of the Trust OS
|
||||
+ sip_smc_set_suspend_mode(VIRTUAL_POWEROFF, 0, 0);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int rockchip_ir_register_power_key(struct device *dev)
|
||||
+{
|
||||
+
|
||||
+ struct rockchip_rc_dev *gpio_dev = dev_get_drvdata(dev);
|
||||
+
|
||||
+ struct rc_map *key_map;
|
||||
+ struct rc_map_table *key;
|
||||
+ int idx, scancode;
|
||||
+
|
||||
+ key_map = &gpio_dev->rcdev->rc_map;
|
||||
+
|
||||
+ dev_info(dev, "remote key table %s, key map of %d items\n", key_map->name, key_map->len);
|
||||
+
|
||||
+ for (idx = 0; idx < key_map->len; idx++) {
|
||||
+
|
||||
+ key = &key_map->scan[idx];
|
||||
+
|
||||
+ if (key->keycode != KEY_POWER)
|
||||
+ continue;
|
||||
+
|
||||
+ scancode = ((key->scancode & 0xff0000) >> 8) | ((key->scancode & 0xff00) << 8);
|
||||
+ scancode |= (~key->scancode) & 0xff;
|
||||
+ scancode <<= 8;
|
||||
+
|
||||
+ sip_smc_remotectl_config(REMOTECTL_SET_PWRKEY, scancode);
|
||||
+
|
||||
+ dev_info(dev, "registered scancode %08llx (SIP: %8x)\n", key->scancode, scancode);
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static int rockchip_ir_recv_suspend_prepare(struct device *dev)
|
||||
+{
|
||||
+ struct rockchip_rc_dev *gpio_dev = dev_get_drvdata(dev);
|
||||
+ int ret;
|
||||
+
|
||||
+ dev_info(dev, "initialize rockchip SIP virtual poweroff\n");
|
||||
+ ret = rockchip_pwm_sip_wakeup_init(gpio_dev);
|
||||
+
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ rockchip_ir_register_power_key(dev);
|
||||
+
|
||||
+ disable_irq(gpio_dev->irq);
|
||||
+ dev_info(dev, "GPIO IRQ disabled\n");
|
||||
+
|
||||
+ ret = pinctrl_select_state(gpio_dev->pinctrl, gpio_dev->pinctrl_state_suspend);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "unable to set pin in PWM mode\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ dev_info(dev, "set pin configuration to PWM mode\n");
|
||||
+
|
||||
+ rockchip_pwm_hw_init(gpio_dev);
|
||||
+ dev_info(dev, "started pin PWM mode\n");
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+#ifdef CONFIG_PM
|
||||
+static int rockchip_ir_recv_suspend(struct device *dev)
|
||||
+{
|
||||
+ struct rockchip_rc_dev *gpio_dev = dev_get_drvdata(dev);
|
||||
+
|
||||
+ /*
|
||||
+ * if property suspend-is-virtual-poweroff is set, we can disable
|
||||
+ * the regular gpio wakeup and enable the PWM mode for the Trust OS
|
||||
+ * to take control and react to remote control.
|
||||
+ * If the property is not set, we instead enable the wake up for the
|
||||
+ * regular gpio.
|
||||
+ */
|
||||
+ if (gpio_dev->use_suspend_handler) {
|
||||
+
|
||||
+ rockchip_ir_recv_suspend_prepare(dev);
|
||||
+
|
||||
+ } else {
|
||||
+
|
||||
+ if (device_may_wakeup(dev))
|
||||
+ enable_irq_wake(gpio_dev->irq);
|
||||
+ else
|
||||
+ disable_irq(gpio_dev->irq);
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int rockchip_ir_recv_resume(struct device *dev)
|
||||
+{
|
||||
+ struct rockchip_rc_dev *gpio_dev = dev_get_drvdata(dev);
|
||||
+ int ret;
|
||||
+
|
||||
+ /*
|
||||
+ * In case suspend-is-virtual-poweroff property is set,
|
||||
+ * restore the pin from PWM mode to regular GPIO configuration
|
||||
+ * and stop the PWM function.
|
||||
+ * Otherwise, just enable the regular GPIO irq
|
||||
+ */
|
||||
+ if (gpio_dev->use_suspend_handler) {
|
||||
+
|
||||
+ rockchip_pwm_hw_stop(gpio_dev);
|
||||
+ dev_info(dev, "stopped pin PWM mode\n");
|
||||
+
|
||||
+ ret = pinctrl_select_state(gpio_dev->pinctrl, gpio_dev->pinctrl_state_default);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "unable to restore pin in GPIO mode\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+ dev_info(dev, "restored pin configuration di GPIO\n");
|
||||
+
|
||||
+ enable_irq(gpio_dev->irq);
|
||||
+ dev_info(dev, "restored GPIO IRQ\n");
|
||||
+
|
||||
+ } else {
|
||||
+
|
||||
+ if (device_may_wakeup(dev))
|
||||
+ disable_irq_wake(gpio_dev->irq);
|
||||
+ else
|
||||
+ enable_irq(gpio_dev->irq);
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void rockchip_ir_recv_shutdown(struct platform_device *pdev)
|
||||
+{
|
||||
+
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct rockchip_rc_dev *gpio_dev = dev_get_drvdata(dev);
|
||||
+
|
||||
+ if (gpio_dev->use_shutdown_handler)
|
||||
+ rockchip_ir_recv_suspend_prepare(dev);
|
||||
+
|
||||
+ return;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static int rockchip_ir_recv_sys_off(struct sys_off_data *data)
|
||||
+{
|
||||
+
|
||||
+ sip_smc_virtual_poweroff();
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static int rockchip_ir_recv_init_sip(void)
|
||||
+{
|
||||
+ struct arm_smccc_res res;
|
||||
+
|
||||
+ arm_smccc_smc(ROCKCHIP_SIP_SIP_VERSION, ROCKCHIP_SIP_IMPLEMENT_V2, SECURE_REG_WR, 0, 0, 0, 0, 0, &res);
|
||||
+
|
||||
+ if (res.a0)
|
||||
+ return 0;
|
||||
+
|
||||
+ return res.a1;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static int rockchip_ir_recv_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct device_node *np = dev->of_node;
|
||||
+ struct rockchip_rc_dev *gpio_dev;
|
||||
+ struct rc_dev *rcdev;
|
||||
+ struct clk *clk;
|
||||
+ struct clk *p_clk;
|
||||
+ struct resource *res;
|
||||
+ u32 period = 0;
|
||||
+ int rc;
|
||||
+ int ret;
|
||||
+ int pwm_wake_irq;
|
||||
+ int clocks;
|
||||
+
|
||||
+ if (!np)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ gpio_dev = devm_kzalloc(dev, sizeof(*gpio_dev), GFP_KERNEL);
|
||||
+ if (!gpio_dev)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ gpio_dev->gpiod = devm_gpiod_get(dev, NULL, GPIOD_IN);
|
||||
+ if (IS_ERR(gpio_dev->gpiod)) {
|
||||
+ rc = PTR_ERR(gpio_dev->gpiod);
|
||||
+ /* Just try again if this happens */
|
||||
+ if (rc != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "error getting gpio (%d)\n", rc);
|
||||
+ return rc;
|
||||
+ }
|
||||
+ gpio_dev->irq = gpiod_to_irq(gpio_dev->gpiod);
|
||||
+ if (gpio_dev->irq < 0)
|
||||
+ return gpio_dev->irq;
|
||||
+
|
||||
+ rcdev = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW);
|
||||
+ if (!rcdev)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ rcdev->priv = gpio_dev;
|
||||
+ rcdev->device_name = ROCKCHIP_IR_DEVICE_NAME;
|
||||
+ rcdev->input_phys = ROCKCHIP_IR_DEVICE_NAME "/input0";
|
||||
+ rcdev->input_id.bustype = BUS_HOST;
|
||||
+ rcdev->input_id.vendor = 0x0001;
|
||||
+ rcdev->input_id.product = 0x0001;
|
||||
+ rcdev->input_id.version = 0x0100;
|
||||
+ rcdev->dev.parent = dev;
|
||||
+ rcdev->driver_name = KBUILD_MODNAME;
|
||||
+ rcdev->min_timeout = 1;
|
||||
+ rcdev->timeout = IR_DEFAULT_TIMEOUT;
|
||||
+ rcdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
|
||||
+ rcdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
|
||||
+ rcdev->map_name = of_get_property(np, "linux,rc-map-name", NULL);
|
||||
+ if (!rcdev->map_name)
|
||||
+ rcdev->map_name = RC_MAP_EMPTY;
|
||||
+
|
||||
+ gpio_dev->rcdev = rcdev;
|
||||
+ if (of_property_read_bool(np, "wakeup-source")) {
|
||||
+
|
||||
+ ret = device_init_wakeup(dev, true);
|
||||
+
|
||||
+ if (ret)
|
||||
+ dev_err(dev, "could not init wakeup device\n");
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ rc = devm_rc_register_device(dev, rcdev);
|
||||
+ if (rc < 0) {
|
||||
+ dev_err(dev, "failed to register rc device (%d)\n", rc);
|
||||
+ return rc;
|
||||
+ }
|
||||
+
|
||||
+ of_property_read_u32(np, "linux,autosuspend-period", &period);
|
||||
+ if (period) {
|
||||
+ gpio_dev->pmdev = dev;
|
||||
+ pm_runtime_set_autosuspend_delay(dev, period);
|
||||
+ pm_runtime_use_autosuspend(dev);
|
||||
+ pm_runtime_set_suspended(dev);
|
||||
+ pm_runtime_enable(dev);
|
||||
+ }
|
||||
+
|
||||
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+ if (!res) {
|
||||
+ dev_err(dev, "no memory resources defined\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ gpio_dev->pwm_base = devm_ioremap_resource(dev, res);
|
||||
+ if (IS_ERR(gpio_dev->pwm_base))
|
||||
+ return PTR_ERR(gpio_dev->pwm_base);
|
||||
+
|
||||
+ clocks = of_property_count_strings(np, "clock-names");
|
||||
+ if (clocks == 2) {
|
||||
+ clk = devm_clk_get(dev, "pwm");
|
||||
+ p_clk = devm_clk_get(dev, "pclk");
|
||||
+ } else {
|
||||
+ clk = devm_clk_get(dev, NULL);
|
||||
+ p_clk = clk;
|
||||
+ }
|
||||
+
|
||||
+ if (IS_ERR(clk)) {
|
||||
+ ret = PTR_ERR(clk);
|
||||
+ if (ret != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Can't get bus clock: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if (IS_ERR(p_clk)) {
|
||||
+ ret = PTR_ERR(p_clk);
|
||||
+ if (ret != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Can't get peripheral clock: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = clk_prepare_enable(clk);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "Can't enable bus clk: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = clk_prepare_enable(p_clk);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "Can't enable peripheral clk: %d\n", ret);
|
||||
+ goto error_clk;
|
||||
+ }
|
||||
+
|
||||
+ pwm_wake_irq = platform_get_irq(pdev, 0);
|
||||
+ if (pwm_wake_irq < 0) {
|
||||
+ dev_err(&pdev->dev, "cannot find PWM wake interrupt\n");
|
||||
+ goto error_pclk;
|
||||
+ }
|
||||
+
|
||||
+ gpio_dev->pwm_wake_irq = pwm_wake_irq;
|
||||
+ ret = enable_irq_wake(pwm_wake_irq);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "could not enable IRQ wakeup\n");
|
||||
+ }
|
||||
+
|
||||
+ ret = of_property_read_u32(np, "pwm-id", &gpio_dev->pwm_id);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "missing pwm-id property\n");
|
||||
+ goto error_pclk;
|
||||
+ }
|
||||
+
|
||||
+ if (gpio_dev->pwm_id > 3) {
|
||||
+ dev_err(dev, "invalid pwm-id property\n");
|
||||
+ goto error_pclk;
|
||||
+ }
|
||||
+
|
||||
+ gpio_dev->use_shutdown_handler = of_property_read_bool(np, "shutdown-is-virtual-poweroff");
|
||||
+ gpio_dev->use_suspend_handler = of_property_read_bool(np, "suspend-is-virtual-poweroff");
|
||||
+
|
||||
+ gpio_dev->pinctrl = devm_pinctrl_get(dev);
|
||||
+ if (IS_ERR(gpio_dev->pinctrl)) {
|
||||
+ dev_err(dev, "Unable to get pinctrl\n");
|
||||
+ goto error_pclk;
|
||||
+ }
|
||||
+
|
||||
+ gpio_dev->pinctrl_state_default = pinctrl_lookup_state(gpio_dev->pinctrl, "default");
|
||||
+ if (IS_ERR(gpio_dev->pinctrl_state_default)) {
|
||||
+ dev_err(dev, "Unable to get default pinctrl state\n");
|
||||
+ goto error_pclk;
|
||||
+ }
|
||||
+
|
||||
+ gpio_dev->pinctrl_state_suspend = pinctrl_lookup_state(gpio_dev->pinctrl, "suspend");
|
||||
+ if (IS_ERR(gpio_dev->pinctrl_state_suspend)) {
|
||||
+ dev_err(dev, "Unable to get suspend pinctrl state\n");
|
||||
+ goto error_pclk;
|
||||
+ }
|
||||
+
|
||||
+ platform_set_drvdata(pdev, gpio_dev);
|
||||
+
|
||||
+ ret = devm_request_irq(dev, gpio_dev->irq, rockchip_ir_recv_irq,
|
||||
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
|
||||
+ "gpio-ir-recv-irq", gpio_dev);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "Can't request GPIO interrupt\n");
|
||||
+ goto error_pclk;
|
||||
+ }
|
||||
+
|
||||
+ if (gpio_dev->use_shutdown_handler) {
|
||||
+
|
||||
+ ret = devm_register_sys_off_handler(dev, SYS_OFF_MODE_POWER_OFF,
|
||||
+ SYS_OFF_PRIO_FIRMWARE, rockchip_ir_recv_sys_off, NULL);
|
||||
+
|
||||
+ if (ret)
|
||||
+ dev_err(dev, "could not register sys_off handler\n");
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ ret = rockchip_ir_recv_init_sip();
|
||||
+ if (!ret) {
|
||||
+ dev_err(dev, "Unable to initialize Rockchip SIP v2, virtual poweroff unavailable\n");
|
||||
+ gpio_dev->use_shutdown_handler = false;
|
||||
+ gpio_dev->use_suspend_handler = false;
|
||||
+ } else {
|
||||
+ dev_info(dev, "rockchip SIP initialized, version 0x%x\n", ret);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+error_pclk:
|
||||
+ clk_unprepare(p_clk);
|
||||
+error_clk:
|
||||
+ clk_unprepare(clk);
|
||||
+
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static const struct dev_pm_ops rockchip_ir_recv_pm_ops = {
|
||||
+ .suspend = rockchip_ir_recv_suspend,
|
||||
+ .resume = rockchip_ir_recv_resume,
|
||||
+};
|
||||
+#endif
|
||||
+
|
||||
+static const struct of_device_id rockchip_ir_recv_of_match[] = {
|
||||
+ { .compatible = "rockchip-ir", },
|
||||
+ { },
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, rockchip_ir_recv_of_match);
|
||||
+
|
||||
+static struct platform_driver rockchip_ir_recv_driver = {
|
||||
+ .probe = rockchip_ir_recv_probe,
|
||||
+ .remove = rockchip_ir_recv_remove,
|
||||
+ .shutdown = rockchip_ir_recv_shutdown,
|
||||
+ .driver = {
|
||||
+ .name = KBUILD_MODNAME,
|
||||
+ .of_match_table = of_match_ptr(rockchip_ir_recv_of_match),
|
||||
+#ifdef CONFIG_PM
|
||||
+ .pm = &rockchip_ir_recv_pm_ops,
|
||||
+#endif
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(rockchip_ir_recv_driver);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Rockchip IR Receiver driver");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@ -19,6 +19,7 @@ dtbo-$(CONFIG_ARCH_ROCKCHIP) += \
|
||||
rk322x-cpu-hs-lv.dtbo \
|
||||
rk322x-wlan-alt-wiring.dtbo \
|
||||
rk322x-cpu-stability.dtbo \
|
||||
rk322x-ir-wakeup.dtbo \
|
||||
rk322x-ddr3-330.dtbo \
|
||||
rk322x-ddr3-528.dtbo \
|
||||
rk322x-ddr3-660.dtbo \
|
||||
|
||||
@ -18,6 +18,7 @@ rk322x (Rockchip)
|
||||
- rk322x-ddr3-*
|
||||
- rk322x-bt-*
|
||||
- rk322x-usb-otg-peripheral
|
||||
- rk322x-ir-wakeup
|
||||
|
||||
### Overlay details:
|
||||
|
||||
@ -89,3 +90,9 @@ rk322x-bt-8723cs: enable this overlay for 8723cs and 8703bs wifi/bluetooth
|
||||
|
||||
Set the OTG USB port to peripheral mode to be used as USB slave instead
|
||||
of USB host
|
||||
|
||||
### rk322x-ir-wakeup
|
||||
|
||||
Enable the rockchip-ir-driver in place of the standard gpio-ir-receiver.
|
||||
The rockchip-specific driver exploits the Trust OS and Virtual Poweroff mode
|
||||
to allow power up via remote controller power button.
|
||||
|
||||
16
patch/kernel/archive/rk322x-6.5/overlay/rk322x-ir-wakeup.dts
Normal file
16
patch/kernel/archive/rk322x-6.5/overlay/rk322x-ir-wakeup.dts
Normal file
@ -0,0 +1,16 @@
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
/*
|
||||
* Disable regular gpio-ir-receiver and enable
|
||||
* rockchip-ir-receiver driver; also enables virtual
|
||||
* poweroff on shutdown to allow restart with power key
|
||||
* on remote controller
|
||||
*/
|
||||
&ir_receiver {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&rockchip_ir_receiver {
|
||||
status = "okay";
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user