mirror of
https://github.com/armbian/build.git
synced 2025-08-09 20:56:57 +02:00
Switch meson64, bcm2711, sunxi, imx6, mvebu current to 6.6, edge to 6.7 and leave 6.1 for legecy
- detach sunxi from fixed vesions - imx6 remove symlinks - move to archive & cleanup
This commit is contained in:
parent
56c406d2f6
commit
f852beca0a
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Linux/arm64 6.6.3 Kernel Configuration
|
||||
# Linux/arm64 6.7.0-rc6 Kernel Configuration
|
||||
#
|
||||
CONFIG_CC_VERSION_TEXT="aarch64-linux-gnu-gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0"
|
||||
CONFIG_CC_IS_GCC=y
|
||||
@ -266,6 +266,7 @@ CONFIG_TRACEPOINTS=y
|
||||
#
|
||||
CONFIG_CRASH_CORE=y
|
||||
# CONFIG_KEXEC_FILE is not set
|
||||
# CONFIG_CRASH_DUMP is not set
|
||||
# end of Kexec and crash features
|
||||
# end of General setup
|
||||
|
||||
@ -322,6 +323,7 @@ CONFIG_ARCH_BRCMSTB=y
|
||||
# CONFIG_ARCH_NXP is not set
|
||||
# CONFIG_ARCH_MA35 is not set
|
||||
# CONFIG_ARCH_NPCM is not set
|
||||
# CONFIG_ARCH_PENSANDO is not set
|
||||
# CONFIG_ARCH_QCOM is not set
|
||||
# CONFIG_ARCH_REALTEK is not set
|
||||
# CONFIG_ARCH_RENESAS is not set
|
||||
@ -429,6 +431,7 @@ CONFIG_ARCH_SUPPORTS_KEXEC_SIG=y
|
||||
CONFIG_ARCH_SUPPORTS_KEXEC_IMAGE_VERIFY_SIG=y
|
||||
CONFIG_ARCH_DEFAULT_KEXEC_IMAGE_VERIFY_SIG=y
|
||||
CONFIG_ARCH_SUPPORTS_CRASH_DUMP=y
|
||||
CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION=y
|
||||
# CONFIG_XEN is not set
|
||||
CONFIG_ARCH_FORCE_MAX_ORDER=10
|
||||
CONFIG_UNMAP_KERNEL_AT_EL0=y
|
||||
@ -566,7 +569,7 @@ CONFIG_CPU_FREQ_GOV_ATTR_SET=y
|
||||
CONFIG_CPU_FREQ_GOV_COMMON=y
|
||||
CONFIG_CPU_FREQ_STAT=y
|
||||
# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
|
||||
CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE=y
|
||||
# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
|
||||
# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
|
||||
# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
|
||||
# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
|
||||
@ -903,6 +906,7 @@ CONFIG_MIGRATION=y
|
||||
CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION=y
|
||||
CONFIG_ARCH_ENABLE_THP_MIGRATION=y
|
||||
CONFIG_CONTIG_ALLOC=y
|
||||
CONFIG_PCP_BATCH_SCALE_MAX=5
|
||||
CONFIG_PHYS_ADDR_T_64BIT=y
|
||||
CONFIG_MMU_NOTIFIER=y
|
||||
# CONFIG_KSM is not set
|
||||
@ -1473,7 +1477,6 @@ CONFIG_VLAN_8021Q_GVRP=y
|
||||
CONFIG_LLC=m
|
||||
# CONFIG_LLC2 is not set
|
||||
CONFIG_ATALK=m
|
||||
# CONFIG_DEV_APPLETALK is not set
|
||||
# CONFIG_X25 is not set
|
||||
# CONFIG_LAPB is not set
|
||||
# CONFIG_PHONET is not set
|
||||
@ -1762,7 +1765,6 @@ CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
|
||||
CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
|
||||
CONFIG_MAC80211_MESH=y
|
||||
CONFIG_MAC80211_LEDS=y
|
||||
# CONFIG_MAC80211_DEBUGFS is not set
|
||||
# CONFIG_MAC80211_MESSAGE_TRACING is not set
|
||||
# CONFIG_MAC80211_DEBUG_MENU is not set
|
||||
CONFIG_MAC80211_STA_HASH_MAX_SIZE=0
|
||||
@ -1817,6 +1819,7 @@ CONFIG_PCI_SYSCALL=y
|
||||
CONFIG_PCIEPORTBUS=y
|
||||
CONFIG_PCIEAER=y
|
||||
# CONFIG_PCIEAER_INJECT is not set
|
||||
CONFIG_PCIEAER_CXL=y
|
||||
# CONFIG_PCIE_ECRC is not set
|
||||
CONFIG_PCIEASPM=y
|
||||
# CONFIG_PCIEASPM_DEFAULT is not set
|
||||
@ -2010,6 +2013,12 @@ CONFIG_EFI_EARLYCON=y
|
||||
# end of EFI (Extensible Firmware Interface) Support
|
||||
|
||||
CONFIG_ARM_PSCI_FW=y
|
||||
|
||||
#
|
||||
# Qualcomm firmware drivers
|
||||
#
|
||||
# end of Qualcomm firmware drivers
|
||||
|
||||
CONFIG_HAVE_ARM_SMCCC=y
|
||||
CONFIG_HAVE_ARM_SMCCC_DISCOVERY=y
|
||||
CONFIG_ARM_SMCCC_SOC_ID=y
|
||||
@ -2027,7 +2036,6 @@ CONFIG_MTD=m
|
||||
#
|
||||
# Partition parsers
|
||||
#
|
||||
# CONFIG_MTD_AR7_PARTS is not set
|
||||
# CONFIG_MTD_CMDLINE_PARTS is not set
|
||||
CONFIG_MTD_OF_PARTS=m
|
||||
# CONFIG_MTD_AFS_PARTS is not set
|
||||
@ -2187,7 +2195,7 @@ CONFIG_BLK_DEV_NVME=y
|
||||
# CONFIG_NVME_HWMON is not set
|
||||
# CONFIG_NVME_FC is not set
|
||||
# CONFIG_NVME_TCP is not set
|
||||
# CONFIG_NVME_AUTH is not set
|
||||
# CONFIG_NVME_HOST_AUTH is not set
|
||||
# CONFIG_NVME_TARGET is not set
|
||||
# end of NVME Support
|
||||
|
||||
@ -2225,7 +2233,6 @@ CONFIG_VCPU_STALL_DETECTOR=m
|
||||
#
|
||||
CONFIG_EEPROM_AT24=m
|
||||
CONFIG_EEPROM_AT25=m
|
||||
CONFIG_EEPROM_LEGACY=m
|
||||
# CONFIG_EEPROM_MAX6875 is not set
|
||||
CONFIG_EEPROM_93CX6=m
|
||||
# CONFIG_EEPROM_93XX46 is not set
|
||||
@ -2536,6 +2543,7 @@ CONFIG_TAP=m
|
||||
CONFIG_VETH=m
|
||||
CONFIG_VIRTIO_NET=m
|
||||
# CONFIG_NLMON is not set
|
||||
# CONFIG_NETKIT is not set
|
||||
CONFIG_NET_VRF=m
|
||||
CONFIG_VSOCKMON=m
|
||||
# CONFIG_ARCNET is not set
|
||||
@ -2656,6 +2664,7 @@ CONFIG_NET_VENDOR_INTEL=y
|
||||
# CONFIG_ICE is not set
|
||||
# CONFIG_FM10K is not set
|
||||
# CONFIG_IGC is not set
|
||||
# CONFIG_IDPF is not set
|
||||
# CONFIG_JME is not set
|
||||
CONFIG_NET_VENDOR_ADI=y
|
||||
CONFIG_NET_VENDOR_LITEX=y
|
||||
@ -3006,7 +3015,6 @@ CONFIG_ATH9K_BTCOEX_SUPPORT=y
|
||||
CONFIG_ATH9K=m
|
||||
CONFIG_ATH9K_PCI=y
|
||||
# CONFIG_ATH9K_AHB is not set
|
||||
# CONFIG_ATH9K_DEBUGFS is not set
|
||||
# CONFIG_ATH9K_DYNACK is not set
|
||||
# CONFIG_ATH9K_WOW is not set
|
||||
CONFIG_ATH9K_RFKILL=y
|
||||
@ -3134,6 +3142,8 @@ CONFIG_MT7921E=m
|
||||
CONFIG_MT7921S=m
|
||||
CONFIG_MT7921U=m
|
||||
# CONFIG_MT7996E is not set
|
||||
# CONFIG_MT7925E is not set
|
||||
# CONFIG_MT7925U is not set
|
||||
CONFIG_WLAN_VENDOR_MICROCHIP=y
|
||||
# CONFIG_WILC1000_SDIO is not set
|
||||
# CONFIG_WILC1000_SPI is not set
|
||||
@ -3194,14 +3204,6 @@ CONFIG_WLAN_VENDOR_TI=y
|
||||
# CONFIG_WL12XX is not set
|
||||
# CONFIG_WL18XX is not set
|
||||
# CONFIG_WLCORE is not set
|
||||
# CONFIG_RTL8723DU is not set
|
||||
# CONFIG_RTL8723DS is not set
|
||||
# CONFIG_RTL8822BU is not set
|
||||
CONFIG_RTL8821CU=m
|
||||
CONFIG_88XXAU=m
|
||||
CONFIG_RTL8192EU=m
|
||||
# CONFIG_RTL8189FS is not set
|
||||
# CONFIG_RTL8189ES is not set
|
||||
CONFIG_WLAN_VENDOR_ZYDAS=y
|
||||
CONFIG_USB_ZD1201=m
|
||||
CONFIG_ZD1211RW=m
|
||||
@ -4025,6 +4027,7 @@ CONFIG_BATTERY_GOLDFISH=m
|
||||
# CONFIG_CHARGER_UCS1002 is not set
|
||||
# CONFIG_CHARGER_BD99954 is not set
|
||||
CONFIG_BATTERY_UG3105=m
|
||||
# CONFIG_FUEL_GAUGE_MM8013 is not set
|
||||
CONFIG_HWMON=y
|
||||
CONFIG_HWMON_VID=m
|
||||
# CONFIG_HWMON_DEBUG_CHIP is not set
|
||||
@ -4074,6 +4077,7 @@ CONFIG_SENSORS_HIH6130=m
|
||||
CONFIG_SENSORS_IIO_HWMON=m
|
||||
CONFIG_SENSORS_IT87=m
|
||||
CONFIG_SENSORS_JC42=m
|
||||
# CONFIG_SENSORS_POWERZ is not set
|
||||
CONFIG_SENSORS_POWR1220=m
|
||||
CONFIG_SENSORS_LINEAGE=m
|
||||
CONFIG_SENSORS_LTC2945=m
|
||||
@ -4081,6 +4085,7 @@ CONFIG_SENSORS_LTC2947=m
|
||||
CONFIG_SENSORS_LTC2947_I2C=m
|
||||
# CONFIG_SENSORS_LTC2947_SPI is not set
|
||||
CONFIG_SENSORS_LTC2990=m
|
||||
# CONFIG_SENSORS_LTC2991 is not set
|
||||
CONFIG_SENSORS_LTC2992=m
|
||||
CONFIG_SENSORS_LTC4151=m
|
||||
CONFIG_SENSORS_LTC4215=m
|
||||
@ -4466,6 +4471,7 @@ CONFIG_REGULATOR_GPIO=y
|
||||
# CONFIG_REGULATOR_LTC3589 is not set
|
||||
# CONFIG_REGULATOR_LTC3676 is not set
|
||||
# CONFIG_REGULATOR_MAX1586 is not set
|
||||
# CONFIG_REGULATOR_MAX77503 is not set
|
||||
# CONFIG_REGULATOR_MAX77857 is not set
|
||||
# CONFIG_REGULATOR_MAX8649 is not set
|
||||
# CONFIG_REGULATOR_MAX8660 is not set
|
||||
@ -4861,6 +4867,10 @@ CONFIG_VIDEO_BCM2835_UNICAM=m
|
||||
# Microchip Technology, Inc. media platform drivers
|
||||
#
|
||||
|
||||
#
|
||||
# Nuvoton media platform drivers
|
||||
#
|
||||
|
||||
#
|
||||
# NVidia media platform drivers
|
||||
#
|
||||
@ -4983,6 +4993,7 @@ CONFIG_VIDEO_IMX708=m
|
||||
CONFIG_VIDEO_MAX9271_LIB=m
|
||||
# CONFIG_VIDEO_MT9M001 is not set
|
||||
# CONFIG_VIDEO_MT9M111 is not set
|
||||
# CONFIG_VIDEO_MT9M114 is not set
|
||||
# CONFIG_VIDEO_MT9P031 is not set
|
||||
# CONFIG_VIDEO_MT9T112 is not set
|
||||
CONFIG_VIDEO_MT9V011=m
|
||||
@ -5009,6 +5020,7 @@ CONFIG_VIDEO_OV5670=m
|
||||
CONFIG_VIDEO_OV5675=m
|
||||
CONFIG_VIDEO_OV5693=m
|
||||
CONFIG_VIDEO_OV5695=m
|
||||
# CONFIG_VIDEO_OV64A40 is not set
|
||||
CONFIG_VIDEO_OV6650=m
|
||||
CONFIG_VIDEO_OV7251=m
|
||||
CONFIG_VIDEO_OV7640=m
|
||||
@ -5037,6 +5049,7 @@ CONFIG_VIDEO_ET8EK8=m
|
||||
CONFIG_VIDEO_AD5398=m
|
||||
# CONFIG_VIDEO_AD5820 is not set
|
||||
CONFIG_VIDEO_AK7375=m
|
||||
# CONFIG_VIDEO_BU64754 is not set
|
||||
# CONFIG_VIDEO_DW9714 is not set
|
||||
# CONFIG_VIDEO_DW9719 is not set
|
||||
# CONFIG_VIDEO_DW9768 is not set
|
||||
@ -5481,10 +5494,12 @@ CONFIG_DRM_PANEL_EBBG_FT8719=m
|
||||
CONFIG_DRM_PANEL_ILITEK_ILI9341=m
|
||||
CONFIG_DRM_PANEL_ILITEK_ILI9806E=m
|
||||
CONFIG_DRM_PANEL_ILITEK_ILI9881C=m
|
||||
# CONFIG_DRM_PANEL_ILITEK_ILI9882T is not set
|
||||
CONFIG_DRM_PANEL_INNOLUX_EJ030NA=m
|
||||
# CONFIG_DRM_PANEL_INNOLUX_P079ZCA is not set
|
||||
# CONFIG_DRM_PANEL_JADARD_JD9365DA_H3 is not set
|
||||
CONFIG_DRM_PANEL_JDI_LT070ME05000=m
|
||||
# CONFIG_DRM_PANEL_JDI_LPM102A188A is not set
|
||||
CONFIG_DRM_PANEL_JDI_R63452=m
|
||||
CONFIG_DRM_PANEL_KHADAS_TS050=m
|
||||
# CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04 is not set
|
||||
@ -5512,6 +5527,7 @@ CONFIG_DRM_PANEL_NOVATEK_NT36672A=m
|
||||
CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m
|
||||
# CONFIG_DRM_PANEL_RAYDIUM_RM67191 is not set
|
||||
# CONFIG_DRM_PANEL_RAYDIUM_RM68200 is not set
|
||||
# CONFIG_DRM_PANEL_RAYDIUM_RM692E5 is not set
|
||||
# CONFIG_DRM_PANEL_RONBO_RB070D30 is not set
|
||||
CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20=m
|
||||
CONFIG_DRM_PANEL_SAMSUNG_DB7430=m
|
||||
@ -5688,6 +5704,7 @@ CONFIG_FB_SYS_IMAGEBLIT=y
|
||||
CONFIG_FB_SYS_FOPS=y
|
||||
CONFIG_FB_DEFERRED_IO=y
|
||||
CONFIG_FB_DMAMEM_HELPERS=y
|
||||
CONFIG_FB_IOMEM_FOPS=y
|
||||
CONFIG_FB_IOMEM_HELPERS=y
|
||||
CONFIG_FB_SYSMEM_HELPERS=y
|
||||
CONFIG_FB_SYSMEM_HELPERS_DEFERRED=y
|
||||
@ -6026,6 +6043,8 @@ CONFIG_SND_SOC_AK4554=m
|
||||
CONFIG_SND_SOC_AW8738=m
|
||||
# CONFIG_SND_SOC_AW88395 is not set
|
||||
# CONFIG_SND_SOC_AW88261 is not set
|
||||
# CONFIG_SND_SOC_AW87390 is not set
|
||||
# CONFIG_SND_SOC_AW88399 is not set
|
||||
# CONFIG_SND_SOC_BD28623 is not set
|
||||
# CONFIG_SND_SOC_BT_SCO is not set
|
||||
# CONFIG_SND_SOC_CHV3_CODEC is not set
|
||||
@ -6115,6 +6134,7 @@ CONFIG_SND_SOC_PCM1794A=m
|
||||
CONFIG_SND_SOC_RT5640=m
|
||||
CONFIG_SND_SOC_RT5659=m
|
||||
CONFIG_SND_SOC_RT9120=m
|
||||
# CONFIG_SND_SOC_RTQ9128 is not set
|
||||
CONFIG_SND_SOC_SGTL5000=m
|
||||
CONFIG_SND_SOC_SIGMADSP=m
|
||||
CONFIG_SND_SOC_SIGMADSP_I2C=m
|
||||
@ -6385,6 +6405,7 @@ CONFIG_USB_COMMON=y
|
||||
CONFIG_USB_ARCH_HAS_HCD=y
|
||||
CONFIG_USB=y
|
||||
CONFIG_USB_PCI=y
|
||||
# CONFIG_USB_PCI_AMD is not set
|
||||
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
|
||||
|
||||
#
|
||||
@ -6813,6 +6834,7 @@ CONFIG_LEDS_IS31FL32XX=m
|
||||
# RGB LED drivers
|
||||
#
|
||||
# CONFIG_LEDS_GROUP_MULTICOLOR is not set
|
||||
# CONFIG_LEDS_KTD202X is not set
|
||||
# CONFIG_LEDS_PWM_MULTICOLOR is not set
|
||||
|
||||
#
|
||||
@ -6827,6 +6849,7 @@ CONFIG_LEDS_TRIGGER_HEARTBEAT=y
|
||||
CONFIG_LEDS_TRIGGER_BACKLIGHT=y
|
||||
CONFIG_LEDS_TRIGGER_CPU=y
|
||||
# CONFIG_LEDS_TRIGGER_ACTIVITY is not set
|
||||
# CONFIG_LEDS_TRIGGER_GPIO is not set
|
||||
CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
|
||||
|
||||
#
|
||||
@ -7079,7 +7102,6 @@ CONFIG_VHOST_CROSS_ENDIAN_LEGACY=y
|
||||
# CONFIG_COMEDI is not set
|
||||
CONFIG_STAGING=y
|
||||
CONFIG_PRISM2_USB=m
|
||||
# CONFIG_RTL8192U is not set
|
||||
# CONFIG_RTLLIB is not set
|
||||
# CONFIG_RTL8723BS is not set
|
||||
CONFIG_R8712U=m
|
||||
@ -7122,12 +7144,6 @@ CONFIG_AD9834=m
|
||||
#
|
||||
# CONFIG_AD5933 is not set
|
||||
# end of Network Analyzer, Impedance Converters
|
||||
|
||||
#
|
||||
# Resolver to digital converters
|
||||
#
|
||||
# CONFIG_AD2S1210 is not set
|
||||
# end of Resolver to digital converters
|
||||
# end of IIO staging drivers
|
||||
|
||||
# CONFIG_FB_SM750 is not set
|
||||
@ -7192,7 +7208,6 @@ CONFIG_BCM2835_VCHIQ_MMAL=m
|
||||
# CONFIG_PI433 is not set
|
||||
# CONFIG_XIL_AXIS_FIFO is not set
|
||||
# CONFIG_FIELDBUS_DEV is not set
|
||||
# CONFIG_QLGE is not set
|
||||
# CONFIG_VME_BUS is not set
|
||||
# CONFIG_GOLDFISH is not set
|
||||
# CONFIG_CHROME_PLATFORMS is not set
|
||||
@ -7284,7 +7299,6 @@ CONFIG_IOMMU_DMA=y
|
||||
# CONFIG_ARM_SMMU is not set
|
||||
# CONFIG_ARM_SMMU_V3 is not set
|
||||
# CONFIG_VIRTIO_IOMMU is not set
|
||||
CONFIG_BCM2712_IOMMU=y
|
||||
|
||||
#
|
||||
# Remoteproc drivers
|
||||
@ -7313,8 +7327,6 @@ CONFIG_BCM2712_IOMMU=y
|
||||
#
|
||||
# Broadcom SoC drivers
|
||||
#
|
||||
CONFIG_BCM2835_POWER=y
|
||||
CONFIG_RASPBERRYPI_POWER=y
|
||||
CONFIG_SOC_BRCMSTB=y
|
||||
# end of Broadcom SoC drivers
|
||||
|
||||
@ -7356,6 +7368,33 @@ CONFIG_LITEX_SOC_CONTROLLER=m
|
||||
# end of Xilinx SoC drivers
|
||||
# end of SOC (System On Chip) specific Drivers
|
||||
|
||||
#
|
||||
# PM Domains
|
||||
#
|
||||
|
||||
#
|
||||
# Amlogic PM Domains
|
||||
#
|
||||
# end of Amlogic PM Domains
|
||||
|
||||
#
|
||||
# Broadcom PM Domains
|
||||
#
|
||||
CONFIG_BCM2835_POWER=y
|
||||
CONFIG_RASPBERRYPI_POWER=y
|
||||
# end of Broadcom PM Domains
|
||||
|
||||
#
|
||||
# i.MX PM Domains
|
||||
#
|
||||
# end of i.MX PM Domains
|
||||
|
||||
#
|
||||
# Qualcomm PM Domains
|
||||
#
|
||||
# end of Qualcomm PM Domains
|
||||
# end of PM Domains
|
||||
|
||||
# CONFIG_PM_DEVFREQ is not set
|
||||
CONFIG_EXTCON=y
|
||||
|
||||
@ -7479,6 +7518,7 @@ CONFIG_AD799X=m
|
||||
# CONFIG_HI8435 is not set
|
||||
# CONFIG_HX711 is not set
|
||||
CONFIG_INA2XX_ADC=m
|
||||
# CONFIG_LTC2309 is not set
|
||||
CONFIG_LTC2471=m
|
||||
CONFIG_LTC2485=m
|
||||
CONFIG_LTC2496=m
|
||||
@ -7493,6 +7533,7 @@ CONFIG_MAX1363=m
|
||||
CONFIG_MAX9611=m
|
||||
CONFIG_MCP320X=m
|
||||
CONFIG_MCP3422=m
|
||||
# CONFIG_MCP3564 is not set
|
||||
CONFIG_MCP3911=m
|
||||
# CONFIG_NAU7802 is not set
|
||||
# CONFIG_RICHTEK_RTQ6056 is not set
|
||||
@ -7896,6 +7937,7 @@ CONFIG_MCP41010=m
|
||||
# Pressure sensors
|
||||
#
|
||||
# CONFIG_ABP060MG is not set
|
||||
# CONFIG_ROHM_BM1390 is not set
|
||||
CONFIG_BMP280=m
|
||||
CONFIG_BMP280_I2C=m
|
||||
CONFIG_BMP280_SPI=m
|
||||
@ -7947,6 +7989,7 @@ CONFIG_VL53L0X_I2C=m
|
||||
#
|
||||
# CONFIG_AD2S90 is not set
|
||||
# CONFIG_AD2S1200 is not set
|
||||
# CONFIG_AD2S1210 is not set
|
||||
# end of Resolver to digital converters
|
||||
|
||||
#
|
||||
@ -7975,6 +8018,7 @@ CONFIG_PWM_ATMEL_TCB=m
|
||||
CONFIG_PWM_BCM2835=m
|
||||
CONFIG_PWM_BRCMSTB=m
|
||||
CONFIG_PWM_CLK=m
|
||||
CONFIG_PWM_DWC_CORE=m
|
||||
CONFIG_PWM_DWC=m
|
||||
# CONFIG_PWM_FSL_FTM is not set
|
||||
CONFIG_PWM_NTXEC=m
|
||||
@ -8179,7 +8223,6 @@ CONFIG_OCFS2_DEBUG_MASKLOG=y
|
||||
# CONFIG_OCFS2_DEBUG_FS is not set
|
||||
CONFIG_BTRFS_FS=m
|
||||
CONFIG_BTRFS_FS_POSIX_ACL=y
|
||||
# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set
|
||||
# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set
|
||||
# CONFIG_BTRFS_DEBUG is not set
|
||||
# CONFIG_BTRFS_ASSERT is not set
|
||||
@ -8200,6 +8243,7 @@ CONFIG_F2FS_FS_LZ4HC=y
|
||||
CONFIG_F2FS_FS_ZSTD=y
|
||||
CONFIG_F2FS_IOSTAT=y
|
||||
# CONFIG_F2FS_UNFAIR_RWSEM is not set
|
||||
# CONFIG_BCACHEFS_FS is not set
|
||||
CONFIG_FS_POSIX_ACL=y
|
||||
CONFIG_EXPORTFS=y
|
||||
CONFIG_EXPORTFS_BLOCK_OPS=y
|
||||
@ -8755,7 +8799,9 @@ CONFIG_CRYPTO_DRBG_HMAC=y
|
||||
# CONFIG_CRYPTO_DRBG_CTR is not set
|
||||
CONFIG_CRYPTO_DRBG=m
|
||||
CONFIG_CRYPTO_JITTERENTROPY=m
|
||||
# CONFIG_CRYPTO_JITTERENTROPY_TESTINTERFACE is not set
|
||||
CONFIG_CRYPTO_JITTERENTROPY_MEMORY_BLOCKS=64
|
||||
CONFIG_CRYPTO_JITTERENTROPY_MEMORY_BLOCKSIZE=32
|
||||
CONFIG_CRYPTO_JITTERENTROPY_OSR=1
|
||||
CONFIG_CRYPTO_KDF800108_CTR=y
|
||||
# end of Random number generation
|
||||
|
||||
@ -8905,7 +8951,6 @@ CONFIG_ZSTD_DECOMPRESS=y
|
||||
CONFIG_XZ_DEC=y
|
||||
CONFIG_XZ_DEC_X86=y
|
||||
CONFIG_XZ_DEC_POWERPC=y
|
||||
CONFIG_XZ_DEC_IA64=y
|
||||
CONFIG_XZ_DEC_ARM=y
|
||||
CONFIG_XZ_DEC_ARMTHUMB=y
|
||||
CONFIG_XZ_DEC_SPARC=y
|
||||
@ -9005,6 +9050,7 @@ CONFIG_ARCH_STACKWALK=y
|
||||
CONFIG_STACKDEPOT=y
|
||||
CONFIG_REF_TRACKER=y
|
||||
CONFIG_SBITMAP=y
|
||||
# CONFIG_LWQ_TEST is not set
|
||||
# end of Library routines
|
||||
|
||||
CONFIG_GENERIC_IOREMAP=y
|
||||
@ -9200,8 +9246,6 @@ CONFIG_STACKTRACE=y
|
||||
# CONFIG_DEBUG_MAPLE_TREE is not set
|
||||
# end of Debug kernel data structures
|
||||
|
||||
# CONFIG_DEBUG_CREDENTIALS is not set
|
||||
|
||||
#
|
||||
# RCU Debugging
|
||||
#
|
||||
@ -9349,6 +9393,7 @@ CONFIG_TEST_BLACKHOLE_DEV=m
|
||||
CONFIG_TEST_MEMCAT_P=m
|
||||
# CONFIG_TEST_MEMINIT is not set
|
||||
# CONFIG_TEST_FREE_PAGES is not set
|
||||
# CONFIG_TEST_OBJPOOL is not set
|
||||
CONFIG_ARCH_USE_MEMTEST=y
|
||||
# CONFIG_MEMTEST is not set
|
||||
# end of Kernel Testing and Coverage
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Linux/arm64 6.1.65 Kernel Configuration
|
||||
# Linux/arm64 6.1.71 Kernel Configuration
|
||||
#
|
||||
CONFIG_CC_VERSION_TEXT="aarch64-linux-gnu-gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0"
|
||||
CONFIG_CC_IS_GCC=y
|
||||
@ -2967,7 +2967,6 @@ CONFIG_STMMAC_PLATFORM=m
|
||||
CONFIG_DWMAC_GENERIC=m
|
||||
CONFIG_DWMAC_ROCKCHIP=m
|
||||
# CONFIG_DWMAC_INTEL_PLAT is not set
|
||||
CONFIG_DWMAC_LOONGSON=m
|
||||
# CONFIG_STMMAC_PCI is not set
|
||||
CONFIG_NET_VENDOR_SUN=y
|
||||
# CONFIG_HAPPYMEAL is not set
|
||||
|
@ -18,23 +18,20 @@ declare -g UEFISIZE=256 # in MiB. Not really UEFI, but part
|
||||
declare -g BOOTSIZE=0 # No separate /boot; instead we have /boot/firmware fat32 partition
|
||||
declare -g BOOTCONFIG=none # We are currently not using U-boot for Raspberry Pi boards
|
||||
declare -g UEFI_MOUNT_POINT="/boot/firmware" # mount uefi partition at /boot/firmware
|
||||
declare -g LINUXCONFIG="linux-${LINUXFAMILY}-${BRANCH}"
|
||||
|
||||
case "${BRANCH}" in
|
||||
|
||||
legacy)
|
||||
declare -g KERNELSOURCE='https://github.com/raspberrypi/linux'
|
||||
declare -g KERNEL_MAJOR_MINOR="5.15" # Major and minor versions of this kernel. For mainline caching.
|
||||
declare -g KERNELBRANCH="branch:rpi-5.15.y"
|
||||
declare -g KERNELPATCHDIR="${LINUXFAMILY}-${BRANCH}"
|
||||
declare -g LINUXCONFIG="linux-${LINUXFAMILY}-${BRANCH}"
|
||||
declare -g KERNEL_MAJOR_MINOR="6.1" # Major and minor versions of this kernel. For mainline caching.
|
||||
declare -g KERNELBRANCH="branch:rpi-6.1.y"
|
||||
;;
|
||||
|
||||
current)
|
||||
declare -g KERNELSOURCE='https://github.com/raspberrypi/linux'
|
||||
declare -g KERNEL_MAJOR_MINOR="6.1" # Major and minor versions of this kernel. For mainline caching.
|
||||
declare -g KERNELBRANCH="branch:rpi-6.1.y"
|
||||
declare -g KERNELPATCHDIR="${LINUXFAMILY}-${BRANCH}"
|
||||
declare -g LINUXCONFIG="linux-${LINUXFAMILY}-${BRANCH}"
|
||||
declare -g KERNEL_MAJOR_MINOR="6.6" # Major and minor versions of this kernel. For mainline caching.
|
||||
declare -g KERNELBRANCH="branch:rpi-6.6.y"
|
||||
;;
|
||||
|
||||
edge)
|
||||
@ -42,8 +39,6 @@ case "${BRANCH}" in
|
||||
declare -g KERNELSOURCE='https://github.com/raspberrypi/linux'
|
||||
declare -g KERNEL_MAJOR_MINOR="6.7" # Major and minor versions of this kernel. For mainline caching.
|
||||
declare -g KERNELBRANCH="branch:rpi-6.7.y"
|
||||
declare -g KERNELPATCHDIR="${LINUXFAMILY}-${BRANCH}"
|
||||
declare -g LINUXCONFIG="linux-${LINUXFAMILY}-${BRANCH}"
|
||||
;;
|
||||
esac
|
||||
|
||||
|
@ -18,23 +18,17 @@ case $BRANCH in
|
||||
|
||||
legacy)
|
||||
|
||||
declare -g KERNEL_MAJOR_MINOR="5.15" # Major and minor versions of this kernel.
|
||||
KERNELBRANCH='branch:linux-5.15.y'
|
||||
|
||||
declare -g KERNEL_MAJOR_MINOR="6.1" # Major and minor versions of this kernel.
|
||||
;;
|
||||
|
||||
current)
|
||||
|
||||
declare -g KERNEL_MAJOR_MINOR="6.1" # Major and minor versions of this kernel.
|
||||
KERNELBRANCH='branch:linux-6.1.y'
|
||||
|
||||
declare -g KERNEL_MAJOR_MINOR="6.6" # Major and minor versions of this kernel.
|
||||
;;
|
||||
|
||||
edge)
|
||||
|
||||
declare -g KERNEL_MAJOR_MINOR="6.2" # Major and minor versions of this kernel.
|
||||
KERNELBRANCH='branch:linux-6.2.y'
|
||||
|
||||
declare -g KERNEL_MAJOR_MINOR="6.7" # Major and minor versions of this kernel.
|
||||
;;
|
||||
|
||||
esac
|
||||
|
@ -38,13 +38,15 @@ GOVERNOR=${GOVERNOR:-ondemand}
|
||||
|
||||
case $BRANCH in
|
||||
|
||||
current)
|
||||
legacy)
|
||||
declare -g KERNEL_MAJOR_MINOR="6.1"
|
||||
;;
|
||||
|
||||
edge)
|
||||
current)
|
||||
declare -g KERNEL_MAJOR_MINOR="6.6"
|
||||
;;
|
||||
edge)
|
||||
declare -g KERNEL_MAJOR_MINOR="6.7"
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
|
@ -45,12 +45,16 @@ esac
|
||||
|
||||
case $BRANCH in
|
||||
|
||||
legacy)
|
||||
declare -g KERNEL_MAJOR_MINOR="6.1"
|
||||
;;
|
||||
|
||||
current)
|
||||
declare -g KERNEL_MAJOR_MINOR="6.1"
|
||||
declare -g KERNEL_MAJOR_MINOR="6.6"
|
||||
;;
|
||||
|
||||
edge)
|
||||
declare -g KERNEL_MAJOR_MINOR="6.6"
|
||||
declare -g KERNEL_MAJOR_MINOR="6.7"
|
||||
;;
|
||||
esac
|
||||
|
||||
|
@ -27,14 +27,10 @@ case $BRANCH in
|
||||
|
||||
current)
|
||||
declare -g KERNEL_MAJOR_MINOR="6.1"
|
||||
declare -g LINUXFAMILY=rockchip64
|
||||
declare -g LINUXCONFIG='linux-rockchip64-'$BRANCH
|
||||
;;
|
||||
|
||||
edge)
|
||||
declare -g KERNEL_MAJOR_MINOR="6.6"
|
||||
declare -g LINUXFAMILY=rockchip64
|
||||
declare -g LINUXCONFIG='linux-rockchip64-'$BRANCH
|
||||
;;
|
||||
esac
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
ž#
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Copyright (c) 2013-2023 Igor Pecovnik, igor@armbian.com
|
||||
@ -24,17 +24,14 @@ case $BRANCH in
|
||||
|
||||
legacy)
|
||||
declare -g KERNEL_MAJOR_MINOR="6.1" # Major and minor versions of this kernel.
|
||||
declare -g KERNELBRANCH="tag:v6.1.69"
|
||||
;;
|
||||
|
||||
current)
|
||||
declare -g KERNEL_MAJOR_MINOR="6.6" # Major and minor versions of this kernel.
|
||||
declare -g KERNELBRANCH="tag:v6.6.8"
|
||||
;;
|
||||
|
||||
edge)
|
||||
declare -g KERNEL_MAJOR_MINOR="6.7" # Major and minor versions of this kernel.
|
||||
declare -g KERNELBRANCH="tag:v6.7-rc6"
|
||||
;;
|
||||
esac
|
||||
|
||||
|
@ -25,17 +25,14 @@ case $BRANCH in
|
||||
|
||||
legacy)
|
||||
declare -g KERNEL_MAJOR_MINOR="6.1" # Major and minor versions of this kernel.
|
||||
declare -g KERNELBRANCH="tag:v6.1.69"
|
||||
;;
|
||||
|
||||
current)
|
||||
declare -g KERNEL_MAJOR_MINOR="6.6" # Major and minor versions of this kernel.
|
||||
declare -g KERNELBRANCH="tag:v6.6.8"
|
||||
;;
|
||||
|
||||
edge)
|
||||
declare -g KERNEL_MAJOR_MINOR="6.7" # Major and minor versions of this kernel.
|
||||
declare -g KERNELBRANCH="tag:v6.7-rc6"
|
||||
;;
|
||||
esac
|
||||
|
||||
|
@ -18,29 +18,18 @@ fi
|
||||
|
||||
case $BRANCH in
|
||||
|
||||
legacy)
|
||||
declare -g KERNEL_MAJOR_MINOR="6.1" # Major and minor versions of this kernel.
|
||||
;;
|
||||
|
||||
current)
|
||||
|
||||
declare -g KERNEL_MAJOR_MINOR="6.1" # Major and minor versions of this kernel.
|
||||
KERNELBRANCH='branch:linux-6.1.y'
|
||||
|
||||
declare -g KERNEL_MAJOR_MINOR="6.6" # Major and minor versions of this kernel.
|
||||
;;
|
||||
|
||||
edge)
|
||||
|
||||
declare -g KERNEL_MAJOR_MINOR="6.6" # Major and minor versions of this kernel.
|
||||
KERNELBRANCH='branch:linux-6.6.y'
|
||||
|
||||
LINUXCONFIG='linux-mvebu-edge'
|
||||
KERNELPATCHDIR="mvebu-edge"
|
||||
|
||||
#BOOTBRANCH='tag:v2019.04'
|
||||
#BOOTPATCHDIR='u-boot-mvebu-dev'
|
||||
#BOOTSCRIPT='boot-mvebu.cmd:boot.cmd'
|
||||
|
||||
#UBOOT_TARGET_MAP=";sdhc;u-boot-spl.kwb:u-boot.mmc
|
||||
# ;spi;u-boot-spl.kwb:u-boot.flash
|
||||
# ;uart;u-boot-spl.kwb:u-boot.uart"
|
||||
|
||||
declare -g KERNEL_MAJOR_MINOR="6.7" # Major and minor versions of this kernel.
|
||||
;;
|
||||
|
||||
esac
|
||||
|
@ -34,7 +34,6 @@ case $BRANCH in
|
||||
LINUXFAMILY=rockchip-rk3588
|
||||
LINUXCONFIG='linux-rockchip-rk3588-'$BRANCH
|
||||
KERNEL_MAJOR_MINOR="6.7" # Major and minor versions of this kernel.
|
||||
KERNELBRANCH='tag:v6.7-rc7'
|
||||
KERNELPATCHDIR='rockchip-rk3588-edge'
|
||||
;;
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
function mainline_kernel_decide_version__upstream_release_candidate_number() {
|
||||
[[ -n "${KERNELBRANCH}" ]] && return 0 # if already set, don't touch it; that way other hooks can run in any order
|
||||
if [[ "${KERNEL_MAJOR_MINOR}" == "6.7" ]]; then # @TODO: roll over to 6.8 and v6.8-rc1 when it is released, which should be around Sunday, 2024-01-21 - see https://deb.tandrin.de/phb-crystal-ball.htm
|
||||
declare -g KERNELBRANCH="tag:v6.7-rc7"
|
||||
declare -g KERNELBRANCH="tag:v6.7-rc8"
|
||||
display_alert "mainline-kernel: upstream release candidate" "Using KERNELBRANCH='${KERNELBRANCH}' for KERNEL_MAJOR_MINOR='${KERNEL_MAJOR_MINOR}'" "info"
|
||||
fi
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
diff -Naur a/arch/arm/Kconfig b/arch/arm/Kconfig
|
||||
--- a/arch/arm/Kconfig 2022-12-11 17:15:18.000000000 -0500
|
||||
+++ b/arch/arm/Kconfig 2022-12-13 10:24:24.085749880 -0500
|
||||
@@ -2,6 +2,7 @@
|
||||
config ARM
|
||||
bool
|
||||
default y
|
||||
+ select ARCH_BCM
|
||||
select ARCH_32BIT_OFF_T
|
||||
select ARCH_CORRECT_STACKTRACE_ON_KRETPROBE if HAVE_KRETPROBES && FRAME_POINTER && !ARM_UNWIND
|
||||
select ARCH_HAS_BINFMT_FLAT
|
||||
diff -Naur a/arch/arm64/Kconfig b/arch/arm64/Kconfig
|
||||
--- a/arch/arm64/Kconfig 2022-12-11 17:15:18.000000000 -0500
|
||||
+++ b/arch/arm64/Kconfig 2022-12-13 10:28:40.045233987 -0500
|
||||
@@ -1,6 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config ARM64
|
||||
def_bool y
|
||||
+ select ARCH_BCM
|
||||
select ACPI_CCA_REQUIRED if ACPI
|
||||
select ACPI_GENERIC_GSI if ACPI
|
||||
select ACPI_GTDT if ACPI
|
@ -1,46 +0,0 @@
|
||||
From 65bfdb21c26a922b2ada21140782251465159ae3 Mon Sep 17 00:00:00 2001
|
||||
From: Peter Chen <peter.chen@nxp.com>
|
||||
Date: Thu, 18 May 2017 08:48:59 +0800
|
||||
Subject: [PATCH 3/9] binding-doc: usb: usb-device: add optional properties for
|
||||
power sequence
|
||||
|
||||
Add optional properties for power sequence.
|
||||
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
Acked-by: Rob Herring <robh@kernel.org>
|
||||
---
|
||||
Documentation/devicetree/bindings/usb/usb-device.txt | 9 ++++++++-
|
||||
1 file changed, 8 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/usb/usb-device.txt b/Documentation/devicetree/bindings/usb/usb-device.txt
|
||||
index 036be172b1ae..cb85f82a12bb 100644
|
||||
--- a/Documentation/devicetree/bindings/usb/usb-device.txt
|
||||
+++ b/Documentation/devicetree/bindings/usb/usb-device.txt
|
||||
@@ -65,6 +65,9 @@ Required properties for host-controller nodes with device nodes:
|
||||
- #address-cells: shall be 1
|
||||
- #size-cells: shall be 0
|
||||
|
||||
+Optional properties:
|
||||
+power sequence properties, see
|
||||
+Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt for detail
|
||||
|
||||
Example:
|
||||
|
||||
@@ -72,9 +75,13 @@ Example:
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
- hub@1 { /* hub connected to port 1 */
|
||||
+ genesys: hub@1 { /* hub connected to port 1 */
|
||||
compatible = "usb5e3,608";
|
||||
reg = <1>;
|
||||
+
|
||||
+ clocks = <&clks IMX6SX_CLK_CKO>;
|
||||
+ reset-gpios = <&gpio4 5 GPIO_ACTIVE_LOW>; /* hub reset pin */
|
||||
+ reset-duration-us = <10>;
|
||||
};
|
||||
|
||||
device@2 { /* device connected to port 2 */
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,165 +0,0 @@
|
||||
From a42362841fe263a6c97a1793ccd4b9246ac2b108 Mon Sep 17 00:00:00 2001
|
||||
From: Peter Chen <peter.chen@nxp.com>
|
||||
Date: Thu, 18 May 2017 08:49:00 +0800
|
||||
Subject: [PATCH 4/9] usb: core: add power sequence handling for USB devices
|
||||
|
||||
Some hard-wired USB devices need to do power sequence to let the
|
||||
device work normally, the typical power sequence like: enable USB
|
||||
PHY clock, toggle reset pin, etc. But current Linux USB driver
|
||||
lacks of such code to do it, it may cause some hard-wired USB devices
|
||||
works abnormal or can't be recognized by controller at all.
|
||||
|
||||
In this patch, it calls power sequence library APIs to finish
|
||||
the power sequence events. It will do power on sequence at hub's
|
||||
probe for all devices under this hub (includes root hub).
|
||||
At hub_disconnect, it will do power off sequence which is at powered
|
||||
on list.
|
||||
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
Tested-by Joshua Clayton <stillcompiling@gmail.com>
|
||||
Tested-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
|
||||
Reviewed-by: Vaibhav Hiremath <hvaibhav.linux@gmail.com>
|
||||
---
|
||||
drivers/usb/Kconfig | 1 +
|
||||
drivers/usb/core/hub.c | 49 ++++++++++++++++++++++++++++++++++++++----
|
||||
drivers/usb/core/hub.h | 1 +
|
||||
3 files changed, 47 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
|
||||
index 6e59d370ef81..2162fd85b32d 100644
|
||||
--- a/drivers/usb/Kconfig
|
||||
+++ b/drivers/usb/Kconfig
|
||||
@@ -47,6 +47,7 @@ config USB
|
||||
depends on USB_ARCH_HAS_HCD
|
||||
select GENERIC_ALLOCATOR
|
||||
select USB_COMMON
|
||||
+ select POWER_SEQUENCE
|
||||
select NLS # for UTF-8 strings
|
||||
---help---
|
||||
Universal Serial Bus (USB) is a specification for a serial bus
|
||||
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
|
||||
index 236313f41f4a..3db75b0d2426 100644
|
||||
--- a/drivers/usb/core/hub.c
|
||||
+++ b/drivers/usb/core/hub.c
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <linux/random.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/kobject.h>
|
||||
+#include <linux/power/pwrseq.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/byteorder.h>
|
||||
@@ -1705,6 +1706,7 @@ static void hub_disconnect(struct usb_interface *intf)
|
||||
hub->error = 0;
|
||||
hub_quiesce(hub, HUB_DISCONNECT);
|
||||
|
||||
+ of_pwrseq_off_list(&hub->pwrseq_on_list);
|
||||
mutex_lock(&usb_port_peer_mutex);
|
||||
|
||||
/* Avoid races with recursively_mark_NOTATTACHED() */
|
||||
@@ -1751,11 +1753,41 @@ static bool hub_descriptor_is_sane(struct usb_host_interface *desc)
|
||||
return true;
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_OF
|
||||
+static int hub_of_pwrseq_on(struct usb_hub *hub)
|
||||
+{
|
||||
+ struct device *parent;
|
||||
+ struct usb_device *hdev = hub->hdev;
|
||||
+ struct device_node *np;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (hdev->parent)
|
||||
+ parent = &hdev->dev;
|
||||
+ else
|
||||
+ parent = bus_to_hcd(hdev->bus)->self.sysdev;
|
||||
+
|
||||
+ for_each_child_of_node(parent->of_node, np) {
|
||||
+ ret = of_pwrseq_on_list(np, &hub->pwrseq_on_list);
|
||||
+ /* Maybe no power sequence library is chosen */
|
||||
+ if (ret && ret != -ENOENT)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+#else
|
||||
+static int hub_of_pwrseq_on(struct usb_hub *hub)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_host_interface *desc;
|
||||
struct usb_device *hdev;
|
||||
struct usb_hub *hub;
|
||||
+ int ret = -ENODEV;
|
||||
|
||||
desc = intf->cur_altsetting;
|
||||
hdev = interface_to_usbdev(intf);
|
||||
@@ -1846,6 +1878,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
INIT_DELAYED_WORK(&hub->leds, led_work);
|
||||
INIT_DELAYED_WORK(&hub->init_work, NULL);
|
||||
INIT_WORK(&hub->events, hub_event);
|
||||
+ INIT_LIST_HEAD(&hub->pwrseq_on_list);
|
||||
spin_lock_init(&hub->irq_urb_lock);
|
||||
timer_setup(&hub->irq_urb_retry, hub_retry_irq_urb, 0);
|
||||
usb_get_intf(intf);
|
||||
@@ -1861,11 +1894,14 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
if (id->driver_info & HUB_QUIRK_CHECK_PORT_AUTOSUSPEND)
|
||||
hub->quirk_check_port_auto_suspend = 1;
|
||||
|
||||
- if (hub_configure(hub, &desc->endpoint[0].desc) >= 0)
|
||||
- return 0;
|
||||
+ if (hub_configure(hub, &desc->endpoint[0].desc) >= 0) {
|
||||
+ ret = hub_of_pwrseq_on(hub);
|
||||
+ if (!ret)
|
||||
+ return 0;
|
||||
+ }
|
||||
|
||||
hub_disconnect(intf);
|
||||
- return -ENODEV;
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -3720,7 +3756,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
|
||||
|
||||
/* stop hub_wq and related activity */
|
||||
hub_quiesce(hub, HUB_SUSPEND);
|
||||
- return 0;
|
||||
+ return pwrseq_suspend_list(&hub->pwrseq_on_list);
|
||||
}
|
||||
|
||||
/* Report wakeup requests from the ports of a resuming root hub */
|
||||
@@ -3760,8 +3796,13 @@ static void report_wakeup_requests(struct usb_hub *hub)
|
||||
static int hub_resume(struct usb_interface *intf)
|
||||
{
|
||||
struct usb_hub *hub = usb_get_intfdata(intf);
|
||||
+ int ret;
|
||||
|
||||
dev_dbg(&intf->dev, "%s\n", __func__);
|
||||
+ ret = pwrseq_resume_list(&hub->pwrseq_on_list);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
hub_activate(hub, HUB_RESUME);
|
||||
|
||||
/*
|
||||
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
|
||||
index a9e24e4b8df1..feab956a1414 100644
|
||||
--- a/drivers/usb/core/hub.h
|
||||
+++ b/drivers/usb/core/hub.h
|
||||
@@ -72,6 +72,7 @@ struct usb_hub {
|
||||
spinlock_t irq_urb_lock;
|
||||
struct timer_list irq_urb_retry;
|
||||
struct usb_port **ports;
|
||||
+ struct list_head pwrseq_on_list; /* powered pwrseq node list */
|
||||
};
|
||||
|
||||
/**
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,79 +0,0 @@
|
||||
From c46707dde637ec75182c2f42f61aab96486bbcee Mon Sep 17 00:00:00 2001
|
||||
From: Peter Chen <peter.chen@nxp.com>
|
||||
Date: Thu, 18 May 2017 08:49:02 +0800
|
||||
Subject: [PATCH 6/9] ARM: dts: imx6qdl-udoo.dtsi: fix onboard USB HUB property
|
||||
|
||||
The current dts describes USB HUB's property at USB controller's
|
||||
entry, it is improper. The USB HUB should be the child node
|
||||
under USB controller, and power sequence properties are under
|
||||
it. Besides, using gpio pinctrl setting for USB2415's reset pin.
|
||||
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
Signed-off-by: Joshua Clayton <stillcompiling@gmail.com>
|
||||
Tested-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
|
||||
---
|
||||
arch/arm/boot/dts/imx6qdl-udoo.dtsi | 26 ++++++++++++--------------
|
||||
1 file changed, 12 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/arch/arm/boot/dts/imx6qdl-udoo.dtsi b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
|
||||
index 776bfc77f89d..4781a9e04338 100644
|
||||
--- a/arch/arm/boot/dts/imx6qdl-udoo.dtsi
|
||||
+++ b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
|
||||
@@ -5,6 +5,8 @@
|
||||
* Author: Fabio Estevam <fabio.estevam@freescale.com>
|
||||
*/
|
||||
|
||||
+#include <dt-bindings/gpio/gpio.h>
|
||||
+
|
||||
/ {
|
||||
aliases {
|
||||
backlight = &backlight;
|
||||
@@ -62,17 +64,6 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
- reg_usb_h1_vbus: regulator@0 {
|
||||
- compatible = "regulator-fixed";
|
||||
- reg = <0>;
|
||||
- regulator-name = "usb_h1_vbus";
|
||||
- regulator-min-microvolt = <5000000>;
|
||||
- regulator-max-microvolt = <5000000>;
|
||||
- enable-active-high;
|
||||
- startup-delay-us = <2>; /* USB2415 requires a POR of 1 us minimum */
|
||||
- gpio = <&gpio7 12 0>;
|
||||
- };
|
||||
-
|
||||
reg_panel: regulator@1 {
|
||||
compatible = "regulator-fixed";
|
||||
reg = <1>;
|
||||
@@ -205,7 +196,7 @@
|
||||
|
||||
pinctrl_usbh: usbhgrp {
|
||||
fsl,pins = <
|
||||
- MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x80000000
|
||||
+ MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x1b0b0
|
||||
MX6QDL_PAD_NANDF_CS2__CCM_CLKO2 0x130b0
|
||||
>;
|
||||
};
|
||||
@@ -282,9 +273,16 @@
|
||||
&usbh1 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_usbh>;
|
||||
- vbus-supply = <®_usb_h1_vbus>;
|
||||
- clocks = <&clks IMX6QDL_CLK_CKO>;
|
||||
status = "okay";
|
||||
+
|
||||
+ usb2415: hub@1 {
|
||||
+ compatible = "usb424,2514";
|
||||
+ reg = <1>;
|
||||
+
|
||||
+ clocks = <&clks IMX6QDL_CLK_CKO>;
|
||||
+ reset-gpios = <&gpio7 12 GPIO_ACTIVE_LOW>;
|
||||
+ reset-duration-us = <3000>;
|
||||
+ };
|
||||
};
|
||||
|
||||
&usdhc3 {
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,511 +0,0 @@
|
||||
From 9a4d8e886600c7c330590a2435dd74eb16d480ce Mon Sep 17 00:00:00 2001
|
||||
From: Steve Arnold <nerdboy@gentoo.org>
|
||||
Date: Fri, 15 Dec 2017 16:43:22 -0800
|
||||
Subject: [PATCH 8/9] ARM: dts,driver: imx6,udooqdl: add arduino manager driver
|
||||
and update dts
|
||||
|
||||
* note this is required to upload sketches to sam3 from arduino IDE
|
||||
|
||||
Signed-off-by: Steve Arnold <nerdboy@gentoo.org>
|
||||
---
|
||||
arch/arm/boot/dts/imx6qdl-udoo.dtsi | 20 ++
|
||||
drivers/misc/Kconfig | 7 +
|
||||
drivers/misc/Makefile | 1 +
|
||||
drivers/misc/udoo_ard.c | 417 ++++++++++++++++++++++++++++
|
||||
4 files changed, 445 insertions(+)
|
||||
create mode 100755 drivers/misc/udoo_ard.c
|
||||
|
||||
diff --git a/arch/arm/boot/dts/imx6qdl-udoo.dtsi b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
|
||||
index 4781a9e04338..554f601eb72a 100644
|
||||
--- a/arch/arm/boot/dts/imx6qdl-udoo.dtsi
|
||||
+++ b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
|
||||
@@ -84,6 +84,17 @@
|
||||
mux-int-port = <1>;
|
||||
mux-ext-port = <6>;
|
||||
};
|
||||
+
|
||||
+ udoo_ard: udoo_ard_manager {
|
||||
+ compatible = "udoo,imx6q-udoo-ard";
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&pinctrl_udooard>;
|
||||
+ bossac-clk-gpio = <&gpio6 3 0>;
|
||||
+ bossac-dat-gpio = <&gpio5 18 0>;
|
||||
+ bossac-erase-gpio = <&gpio4 21 0>;
|
||||
+ bossac-reset-gpio = <&gpio1 0 0>;
|
||||
+ status = "okay";
|
||||
+ };
|
||||
};
|
||||
|
||||
&fec {
|
||||
@@ -201,6 +212,15 @@
|
||||
>;
|
||||
};
|
||||
|
||||
+ pinctrl_udooard: udooardgrp {
|
||||
+ fsl,pins = <
|
||||
+ MX6QDL_PAD_DISP0_DAT0__GPIO4_IO21 0x80000000
|
||||
+ MX6QDL_PAD_CSI0_DAT17__GPIO6_IO03 0x80000000
|
||||
+ MX6QDL_PAD_CSI0_PIXCLK__GPIO5_IO18 0x80000000
|
||||
+ MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x80000000
|
||||
+ >;
|
||||
+ };
|
||||
+
|
||||
pinctrl_usdhc3: usdhc3grp {
|
||||
fsl,pins = <
|
||||
MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059
|
||||
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
|
||||
index 2cf9db44e4b2..f4616fc61808 100644
|
||||
--- a/drivers/misc/Kconfig
|
||||
+++ b/drivers/misc/Kconfig
|
||||
@@ -487,6 +487,13 @@ config PVPANIC
|
||||
a paravirtualized device provided by QEMU; it lets a virtual machine
|
||||
(guest) communicate panic events to the host.
|
||||
|
||||
+config UDOO_ARD
|
||||
+ tristate "UDOO-Arduino erase/reset Driver"
|
||||
+ default y
|
||||
+ help
|
||||
+ This driver is used to erase and reset arduino board via command sent
|
||||
+ over USB-to-SERIAL connection.
|
||||
+
|
||||
source "drivers/misc/c2port/Kconfig"
|
||||
source "drivers/misc/eeprom/Kconfig"
|
||||
source "drivers/misc/cb710/Kconfig"
|
||||
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
|
||||
index dcc801e8834e..13e132dd62c9 100644
|
||||
--- a/drivers/misc/Makefile
|
||||
+++ b/drivers/misc/Makefile
|
||||
@@ -54,6 +54,7 @@ obj-y += cape/
|
||||
obj-$(CONFIG_ECHO) += echo/
|
||||
obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
|
||||
obj-$(CONFIG_CXL_BASE) += cxl/
|
||||
+obj-$(CONFIG_UDOO_ARD) += udoo_ard.o
|
||||
obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o
|
||||
obj-$(CONFIG_OCXL) += ocxl/
|
||||
obj-y += cardreader/
|
||||
diff --git a/drivers/misc/udoo_ard.c b/drivers/misc/udoo_ard.c
|
||||
new file mode 100755
|
||||
index 000000000000..2210738e09c0
|
||||
--- /dev/null
|
||||
+++ b/drivers/misc/udoo_ard.c
|
||||
@@ -0,0 +1,417 @@
|
||||
+/*
|
||||
+ * udoo_ard.c
|
||||
+ * UDOO quad/dual Arduino flash erase / CPU resetter
|
||||
+ *
|
||||
+ * Copyright (C) 2013-2015 Aidilab srl
|
||||
+ * Author: UDOO Team <social@udoo.org>
|
||||
+ * Author: Giuseppe Pagano <giuseppe.pagano@seco.com>
|
||||
+ * Author: Francesco Montefoschi <francesco.monte@gmail.com>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it
|
||||
+ * under the terms of the GNU General Public License version 2 as published by
|
||||
+ * the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
+ * more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License along with
|
||||
+ * this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/errno.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/gpio.h>
|
||||
+#include <linux/sched.h>
|
||||
+#include <linux/sched/clock.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/workqueue.h>
|
||||
+#include <linux/fs.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/of_address.h>
|
||||
+#include <linux/of_gpio.h>
|
||||
+#include <linux/of_irq.h>
|
||||
+#include <linux/of_platform.h>
|
||||
+#include <linux/uaccess.h>
|
||||
+
|
||||
+#define DRIVER_NAME "udoo_ard"
|
||||
+#define PINCTRL_DEFAULT "default"
|
||||
+#define AUTH_TOKEN 0x5A5A
|
||||
+#define MAX_MSEC_SINCE_LAST_IRQ 400
|
||||
+#define GRAY_TIME_BETWEEN_RESET 10000 // In this time we can't accept new erase/reset code
|
||||
+
|
||||
+static struct workqueue_struct *erase_reset_wq;
|
||||
+typedef struct {
|
||||
+ struct work_struct erase_reset_work;
|
||||
+ struct pinctrl *pinctrl;
|
||||
+ struct pinctrl_state *pins_default;
|
||||
+ int step;
|
||||
+ int cmdcode;
|
||||
+ int erase_reset_lock;
|
||||
+ int gpio_bossac_clk;
|
||||
+ int gpio_bossac_dat;
|
||||
+ int gpio_ard_erase;
|
||||
+ int gpio_ard_reset;
|
||||
+ unsigned long last_int_time_in_ns;
|
||||
+ unsigned long last_int_time_in_sec;
|
||||
+} erase_reset_work_t;
|
||||
+
|
||||
+erase_reset_work_t *work;
|
||||
+static u32 origTX, origRX; // original UART4 TX/RX pad control registers
|
||||
+static int major; // for /dev/udoo_ard
|
||||
+static struct class *udoo_class;
|
||||
+
|
||||
+static struct platform_device_id udoo_ard_devtype[] = {
|
||||
+ {
|
||||
+ /* keep it for coldfire */
|
||||
+ .name = DRIVER_NAME,
|
||||
+ .driver_data = 0,
|
||||
+ }, {
|
||||
+ /* sentinel */
|
||||
+ }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(platform, udoo_ard_devtype);
|
||||
+
|
||||
+static const struct of_device_id udoo_ard_dt_ids[] = {
|
||||
+ { .compatible = "udoo,imx6q-udoo-ard", .data = &udoo_ard_devtype[0], },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, udoo_ard_dt_ids);
|
||||
+
|
||||
+static void disable_serial(void)
|
||||
+{
|
||||
+ u32 addrTX;
|
||||
+ void __iomem *_addrTX;
|
||||
+
|
||||
+ printk("[bossac] Disable UART4 serial port.\n");
|
||||
+
|
||||
+ addrTX = 0x20E01F8;
|
||||
+ _addrTX = ioremap(addrTX, 8);
|
||||
+
|
||||
+ origTX = __raw_readl(_addrTX);
|
||||
+ origRX = __raw_readl(_addrTX + 0x4);
|
||||
+
|
||||
+ __raw_writel(0x15, _addrTX);
|
||||
+ __raw_writel(0x15, _addrTX + 0x4);
|
||||
+
|
||||
+ iounmap(_addrTX);
|
||||
+}
|
||||
+
|
||||
+static void enable_serial(void)
|
||||
+{
|
||||
+ u32 addrTX;
|
||||
+ void __iomem *_addrTX;
|
||||
+
|
||||
+ printk("[bossac] Enable UART4 serial port.\n");
|
||||
+
|
||||
+ addrTX = 0x20E01F8;
|
||||
+ _addrTX = ioremap(addrTX, 8);
|
||||
+
|
||||
+ __raw_writel(origTX, _addrTX);
|
||||
+ __raw_writel(origRX, _addrTX + 0x4);
|
||||
+
|
||||
+ iounmap(_addrTX);
|
||||
+}
|
||||
+
|
||||
+static void erase_reset(void)
|
||||
+{
|
||||
+ printk("[bossac] UDOO ERASE and RESET on Sam3x started.\n");
|
||||
+
|
||||
+ gpio_direction_input(work->gpio_ard_erase);
|
||||
+ gpio_set_value(work->gpio_ard_reset, 1);
|
||||
+ msleep(1);
|
||||
+
|
||||
+ gpio_direction_output(work->gpio_ard_erase, 1);
|
||||
+ msleep(300);
|
||||
+ gpio_direction_input(work->gpio_ard_erase);
|
||||
+
|
||||
+ msleep(10);
|
||||
+ gpio_set_value(work->gpio_ard_reset, 0);
|
||||
+
|
||||
+ msleep(80);
|
||||
+ gpio_set_value(work->gpio_ard_reset, 1);
|
||||
+
|
||||
+ printk("[bossac] UDOO ERASE and RESET on Sam3x EXECUTED.\n");
|
||||
+}
|
||||
+
|
||||
+static void shutdown_sam3x(void)
|
||||
+{
|
||||
+ printk("[bossac] RESET on Sam3x.\n");
|
||||
+
|
||||
+ gpio_set_value(work->gpio_ard_reset, 0);
|
||||
+}
|
||||
+
|
||||
+static void erase_reset_wq_function( struct work_struct *work2)
|
||||
+{
|
||||
+ disable_serial();
|
||||
+ erase_reset();
|
||||
+ msleep(GRAY_TIME_BETWEEN_RESET);
|
||||
+
|
||||
+ work->erase_reset_lock = 0;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Called everytime the gpio_bossac_clk signal toggles.
|
||||
+ * If the auth token (16 bit) is found, we look for the command code (4 bit).
|
||||
+ * The code 0x0F is sent by Bossac to trigger an erase/reset (to achieve this,
|
||||
+ * erase_reset_wq is scheduled). Before starting to program the flash, we disable
|
||||
+ * the UART4 serial port, otherwise there is too noise on the serial lines (the
|
||||
+ * programming port and UART4 port are connected together, see hw schematics).
|
||||
+ * When Bossac finishes to flash/verify, the code 0x00 is sent which re-enables
|
||||
+ * the UART4 port.
|
||||
+ */
|
||||
+static irqreturn_t udoo_bossac_req(int irq, void *dev_id)
|
||||
+{
|
||||
+ int retval, auth_bit, expected_bit, msec_since_last_irq;
|
||||
+ u64 nowsec;
|
||||
+ unsigned long rem_nsec;
|
||||
+ erase_reset_work_t *erase_reset_work;
|
||||
+
|
||||
+ auth_bit = 0;
|
||||
+ if (gpio_get_value(work->gpio_bossac_dat) != 0x0) {
|
||||
+ auth_bit = 1;
|
||||
+ }
|
||||
+
|
||||
+ erase_reset_work = (erase_reset_work_t *)work;
|
||||
+
|
||||
+ nowsec = local_clock();
|
||||
+ rem_nsec = do_div(nowsec, 1000000000) ;
|
||||
+ msec_since_last_irq = (((unsigned long)nowsec * 1000) + rem_nsec/1000000 ) - (((unsigned long)erase_reset_work->last_int_time_in_sec * 1000) + erase_reset_work->last_int_time_in_ns/1000000);
|
||||
+
|
||||
+ if (msec_since_last_irq > MAX_MSEC_SINCE_LAST_IRQ) {
|
||||
+ erase_reset_work->step = 0;
|
||||
+#ifdef DEBUG
|
||||
+ printk("[bossac] Reset authentication timeout!\n");
|
||||
+#endif
|
||||
+ }
|
||||
+
|
||||
+#ifdef DEBUG
|
||||
+ printk("[bossac] STEP %d -> 0x%d \n", erase_reset_work->step, auth_bit);
|
||||
+#endif
|
||||
+ erase_reset_work->last_int_time_in_ns = rem_nsec;
|
||||
+ erase_reset_work->last_int_time_in_sec = nowsec;
|
||||
+
|
||||
+ if ( erase_reset_work->step < 16 ) { // Authenticating received token bit.
|
||||
+ expected_bit = (( AUTH_TOKEN >> erase_reset_work->step ) & 0x01 );
|
||||
+ if ( auth_bit == expected_bit ) {
|
||||
+ erase_reset_work->step = erase_reset_work->step + 1;
|
||||
+ } else {
|
||||
+ erase_reset_work->step = 0;
|
||||
+ }
|
||||
+ } else { // Passed all authentication step. Receiving command code.
|
||||
+ erase_reset_work->cmdcode = erase_reset_work->cmdcode | (auth_bit << (erase_reset_work->step - 16));
|
||||
+ erase_reset_work->step = erase_reset_work->step + 1;
|
||||
+ }
|
||||
+
|
||||
+#ifdef DEBUG
|
||||
+ printk("erase_reset_work->erase_reset_lock = %d \n", erase_reset_work->erase_reset_lock);
|
||||
+#endif
|
||||
+ if ( erase_reset_work->step == 20 ) { // Passed authentication and code acquiring step.
|
||||
+#ifdef DEBUG
|
||||
+ printk("[bossac] Received code = 0x%04x \n", erase_reset_work->cmdcode);
|
||||
+#endif
|
||||
+ if (erase_reset_work->cmdcode == 0xF) {
|
||||
+ if (erase_reset_work->erase_reset_lock == 0) {
|
||||
+ erase_reset_work->erase_reset_lock = 1;
|
||||
+ retval = queue_work( erase_reset_wq, (struct work_struct *)work );
|
||||
+ } else {
|
||||
+#ifdef DEBUG
|
||||
+ printk("Erase and reset operation already in progress. Do nothing.\n");
|
||||
+#endif
|
||||
+ }
|
||||
+ } else {
|
||||
+ enable_serial();
|
||||
+ }
|
||||
+ erase_reset_work->step = 0;
|
||||
+ erase_reset_work->cmdcode = 0;
|
||||
+ }
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Takes control of clock, data, erase, reset GPIOs.
|
||||
+ */
|
||||
+static int gpio_setup(void)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = gpio_request(work->gpio_bossac_clk, "BOSSA_CLK");
|
||||
+ if (ret) {
|
||||
+ printk(KERN_ERR "request BOSSA_CLK IRQ\n");
|
||||
+ return -1;
|
||||
+ } else {
|
||||
+ gpio_direction_input(work->gpio_bossac_clk);
|
||||
+ }
|
||||
+
|
||||
+ ret = gpio_request(work->gpio_bossac_dat, "BOSSA_DAT");
|
||||
+ if (ret) {
|
||||
+ printk(KERN_ERR "request BOSSA_DAT IRQ\n");
|
||||
+ return -1;
|
||||
+ } else {
|
||||
+ gpio_direction_input(work->gpio_bossac_dat);
|
||||
+ }
|
||||
+
|
||||
+ ret = gpio_request(work->gpio_ard_erase, "BOSSAC");
|
||||
+ if (ret) {
|
||||
+ printk(KERN_ERR "request GPIO FOR ARDUINO ERASE\n");
|
||||
+ return -1;
|
||||
+ } else {
|
||||
+ gpio_direction_input(work->gpio_ard_erase);
|
||||
+ }
|
||||
+
|
||||
+ ret = gpio_request(work->gpio_ard_reset, "BOSSAC");
|
||||
+ if (ret) {
|
||||
+ printk(KERN_ERR "request GPIO FOR ARDUINO RESET\n");
|
||||
+ return -1;
|
||||
+ } else {
|
||||
+ gpio_direction_output(work->gpio_ard_reset, 1);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static ssize_t device_write(struct file *filp, const char *buff, size_t len, loff_t *off)
|
||||
+{
|
||||
+ char msg[10];
|
||||
+ long res;
|
||||
+
|
||||
+ if (len > 10)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+
|
||||
+ res = copy_from_user(msg, buff, len);
|
||||
+ if (res) {
|
||||
+ return -EFAULT;
|
||||
+ }
|
||||
+ msg[len] = '\0';
|
||||
+
|
||||
+ if (strcmp(msg, "erase")==0) {
|
||||
+ erase_reset();
|
||||
+ } else if (strcmp(msg, "shutdown")==0) {
|
||||
+ shutdown_sam3x();
|
||||
+ } else if (strcmp(msg, "uartoff")==0) {
|
||||
+ disable_serial();
|
||||
+ } else if (strcmp(msg, "uarton")==0) {
|
||||
+ enable_serial();
|
||||
+ } else {
|
||||
+ printk("[bossac] udoo_ard invalid operation! %s", msg);
|
||||
+ }
|
||||
+
|
||||
+ return len;
|
||||
+}
|
||||
+
|
||||
+static struct file_operations fops = {
|
||||
+ .write = device_write,
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * If a fdt udoo_ard entry is found, we register an IRQ on bossac clock line
|
||||
+ * and we create /dev/udoo_ard
|
||||
+ */
|
||||
+static int udoo_ard_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int retval;
|
||||
+ struct device *temp_class;
|
||||
+ struct platform_device *bdev;
|
||||
+ struct device_node *np;
|
||||
+
|
||||
+ bdev = kzalloc(sizeof(*bdev), GFP_KERNEL);
|
||||
+ np = pdev->dev.of_node;
|
||||
+
|
||||
+ if (!np)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ work = (erase_reset_work_t *)kmalloc(sizeof(erase_reset_work_t), GFP_KERNEL);
|
||||
+ if (work) {
|
||||
+ work->gpio_ard_reset = of_get_named_gpio(np, "bossac-reset-gpio", 0);
|
||||
+ work->gpio_ard_erase = of_get_named_gpio(np, "bossac-erase-gpio", 0);
|
||||
+ work->gpio_bossac_clk = of_get_named_gpio(np, "bossac-clk-gpio", 0);
|
||||
+ work->gpio_bossac_dat = of_get_named_gpio(np, "bossac-dat-gpio", 0);
|
||||
+ work->pinctrl = devm_pinctrl_get(&pdev->dev);
|
||||
+ work->pins_default = pinctrl_lookup_state(work->pinctrl, PINCTRL_DEFAULT);
|
||||
+ } else {
|
||||
+ printk("[bossac] Failed to allocate data structure.");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ pinctrl_select_state(work->pinctrl, work->pins_default);
|
||||
+ gpio_setup();
|
||||
+
|
||||
+ printk("[bossac] Registering IRQ %d for BOSSAC Arduino erase/reset operation\n", gpio_to_irq(work->gpio_bossac_clk));
|
||||
+ retval = request_irq(gpio_to_irq(work->gpio_bossac_clk), udoo_bossac_req, IRQF_TRIGGER_FALLING, "UDOO", bdev);
|
||||
+
|
||||
+ major = register_chrdev(major, "udoo_ard", &fops);
|
||||
+ if (major < 0) {
|
||||
+ printk(KERN_ERR "[bossac] Cannot get major for UDOO Ard\n");
|
||||
+ return -EBUSY;
|
||||
+ }
|
||||
+
|
||||
+ udoo_class = class_create(THIS_MODULE, "udoo_ard");
|
||||
+ if (IS_ERR(udoo_class)) {
|
||||
+ return PTR_ERR(udoo_class);
|
||||
+ }
|
||||
+
|
||||
+ temp_class = device_create(udoo_class, NULL, MKDEV(major, 0), NULL, "udoo_ard");
|
||||
+ if (IS_ERR(temp_class)) {
|
||||
+ return PTR_ERR(temp_class);
|
||||
+ }
|
||||
+
|
||||
+ printk("[bossac] Created device file /dev/udoo_ard\n");
|
||||
+
|
||||
+ erase_reset_wq = create_workqueue("erase_reset_queue");
|
||||
+ if (erase_reset_wq) {
|
||||
+
|
||||
+ /* Queue some work (item 1) */
|
||||
+ if (work) {
|
||||
+ INIT_WORK( (struct work_struct *)work, erase_reset_wq_function );
|
||||
+ work->step = 1;
|
||||
+ work->cmdcode = 0;
|
||||
+ work->last_int_time_in_ns = 0;
|
||||
+ work->last_int_time_in_sec = 0;
|
||||
+ work->erase_reset_lock = 0;
|
||||
+ // retval = queue_work( erase_reset_wq, (struct work_struct *)work );
|
||||
+ }
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int udoo_ard_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ printk("[bossac] Unloading UDOO ard driver.\n");
|
||||
+ free_irq(gpio_to_irq(work->gpio_bossac_clk), NULL);
|
||||
+
|
||||
+ gpio_free(work->gpio_ard_reset);
|
||||
+ gpio_free(work->gpio_ard_erase);
|
||||
+ gpio_free(work->gpio_bossac_clk);
|
||||
+ gpio_free(work->gpio_bossac_dat);
|
||||
+
|
||||
+ device_destroy(udoo_class, MKDEV(major, 0));
|
||||
+ class_destroy(udoo_class);
|
||||
+ unregister_chrdev(major, "udoo_ard");
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver udoo_ard_driver = {
|
||||
+ .driver = {
|
||||
+ .name = DRIVER_NAME,
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = udoo_ard_dt_ids,
|
||||
+ },
|
||||
+ .id_table = udoo_ard_devtype,
|
||||
+ .probe = udoo_ard_probe,
|
||||
+ .remove = udoo_ard_remove,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(udoo_ard_driver);
|
||||
+
|
||||
+MODULE_ALIAS("platform:"DRIVER_NAME);
|
||||
+MODULE_LICENSE("GPL");
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,73 +0,0 @@
|
||||
From f5528e96b7dd2b30e1accc518df85d14baad6bae Mon Sep 17 00:00:00 2001
|
||||
From: Peter Chen <peter.chen@nxp.com>
|
||||
Date: Thu, 18 May 2017 08:48:57 +0800
|
||||
Subject: [PATCH 1/9] binding-doc: power: pwrseq-generic: add binding doc for
|
||||
generic power sequence library
|
||||
|
||||
Add binding doc for generic power sequence library.
|
||||
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
|
||||
Acked-by: Rob Herring <robh@kernel.org>
|
||||
---
|
||||
.../bindings/power/pwrseq/pwrseq-generic.txt | 48 +++++++++++++++++++
|
||||
1 file changed, 48 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt b/Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt
|
||||
new file mode 100644
|
||||
index 000000000000..ebf0d477b688
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt
|
||||
@@ -0,0 +1,48 @@
|
||||
+The generic power sequence library
|
||||
+
|
||||
+Some hard-wired devices (eg USB/MMC) need to do power sequence before
|
||||
+the device can be enumerated on the bus, the typical power sequence
|
||||
+like: enable USB PHY clock, toggle reset pin, etc. But current
|
||||
+Linux device driver lacks of such code to do it, it may cause some
|
||||
+hard-wired devices works abnormal or can't be recognized by
|
||||
+controller at all. The power sequence will be done before this device
|
||||
+can be found at the bus.
|
||||
+
|
||||
+The power sequence properties is under the device node.
|
||||
+
|
||||
+Optional properties:
|
||||
+- clocks: the input clocks for device.
|
||||
+- reset-gpios: Should specify the GPIO for reset.
|
||||
+- reset-duration-us: the duration in microsecond for assert reset signal.
|
||||
+
|
||||
+Below is the example of USB power sequence properties on USB device
|
||||
+nodes which have two level USB hubs.
|
||||
+
|
||||
+&usbotg1 {
|
||||
+ vbus-supply = <®_usb_otg1_vbus>;
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&pinctrl_usb_otg1_id>;
|
||||
+ status = "okay";
|
||||
+
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+ genesys: hub@1 {
|
||||
+ compatible = "usb5e3,608";
|
||||
+ reg = <1>;
|
||||
+
|
||||
+ clocks = <&clks IMX6SX_CLK_CKO>;
|
||||
+ reset-gpios = <&gpio4 5 GPIO_ACTIVE_LOW>; /* hub reset pin */
|
||||
+ reset-duration-us = <10>;
|
||||
+
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+ asix: ethernet@1 {
|
||||
+ compatible = "usbb95,1708";
|
||||
+ reg = <1>;
|
||||
+
|
||||
+ clocks = <&clks IMX6SX_CLK_IPG>;
|
||||
+ reset-gpios = <&gpio4 6 GPIO_ACTIVE_LOW>; /* ethernet_rst */
|
||||
+ reset-duration-us = <15>;
|
||||
+ };
|
||||
+ };
|
||||
+};
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,853 +0,0 @@
|
||||
From e42fbf22376c41b275d47b9cfac360c66ee718dc Mon Sep 17 00:00:00 2001
|
||||
From: Peter Chen <peter.chen@nxp.com>
|
||||
Date: Thu, 18 May 2017 08:48:58 +0800
|
||||
Subject: [PATCH 2/9] power: add power sequence library
|
||||
|
||||
We have an well-known problem that the device needs to do some power
|
||||
sequence before it can be recognized by related host, the typical
|
||||
example like hard-wired mmc devices and usb devices.
|
||||
|
||||
This power sequence is hard to be described at device tree and handled by
|
||||
related host driver, so we have created a common power sequence
|
||||
library to cover this requirement. The core code has supplied
|
||||
some common helpers for host driver, and individual power sequence
|
||||
libraries handle kinds of power sequence for devices. The pwrseq
|
||||
librares always need to allocate extra instance for compatible
|
||||
string match.
|
||||
|
||||
pwrseq_generic is intended for general purpose of power sequence, which
|
||||
handles gpios and clocks currently, and can cover other controls in
|
||||
future. The host driver just needs to call of_pwrseq_on/of_pwrseq_off
|
||||
if only one power sequence is needed, else call of_pwrseq_on_list
|
||||
/of_pwrseq_off_list instead (eg, USB hub driver).
|
||||
|
||||
For new power sequence library, it can add its compatible string
|
||||
to pwrseq_of_match_table, then the pwrseq core will match it with
|
||||
DT's, and choose this library at runtime.
|
||||
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
Tested-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
|
||||
Tested-by Joshua Clayton <stillcompiling@gmail.com>
|
||||
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
|
||||
Tested-by: Matthias Kaehlcke <mka@chromium.org>
|
||||
---
|
||||
Documentation/power/power-sequence/design.rst | 54 +++
|
||||
MAINTAINERS | 9 +
|
||||
drivers/power/Kconfig | 1 +
|
||||
drivers/power/Makefile | 1 +
|
||||
drivers/power/pwrseq/Kconfig | 20 ++
|
||||
drivers/power/pwrseq/Makefile | 2 +
|
||||
drivers/power/pwrseq/core.c | 335 ++++++++++++++++++
|
||||
drivers/power/pwrseq/pwrseq_generic.c | 234 ++++++++++++
|
||||
include/linux/power/pwrseq.h | 81 +++++
|
||||
9 files changed, 737 insertions(+)
|
||||
create mode 100644 Documentation/power/power-sequence/design.rst
|
||||
create mode 100644 drivers/power/pwrseq/Kconfig
|
||||
create mode 100644 drivers/power/pwrseq/Makefile
|
||||
create mode 100644 drivers/power/pwrseq/core.c
|
||||
create mode 100644 drivers/power/pwrseq/pwrseq_generic.c
|
||||
create mode 100644 include/linux/power/pwrseq.h
|
||||
|
||||
diff --git a/Documentation/power/power-sequence/design.rst b/Documentation/power/power-sequence/design.rst
|
||||
new file mode 100644
|
||||
index 000000000000..554608e5f3b6
|
||||
--- /dev/null
|
||||
+++ b/Documentation/power/power-sequence/design.rst
|
||||
@@ -0,0 +1,54 @@
|
||||
+====================================
|
||||
+Power Sequence Library
|
||||
+====================================
|
||||
+
|
||||
+:Date: Feb, 2017
|
||||
+:Author: Peter Chen <peter.chen@nxp.com>
|
||||
+
|
||||
+
|
||||
+Introduction
|
||||
+============
|
||||
+
|
||||
+We have an well-known problem that the device needs to do a power
|
||||
+sequence before it can be recognized by related host, the typical
|
||||
+examples are hard-wired mmc devices and usb devices. The host controller
|
||||
+can't know what kinds of this device is in its bus if the power
|
||||
+sequence has not done, since the related devices driver's probe calling
|
||||
+is determined by runtime according to eunumeration results. Besides,
|
||||
+the devices may have custom power sequence, so the power sequence library
|
||||
+which is independent with the devices is needed.
|
||||
+
|
||||
+Design
|
||||
+============
|
||||
+
|
||||
+The power sequence library includes the core file and customer power
|
||||
+sequence library. The core file exports interfaces are called by
|
||||
+host controller driver for power sequence and customer power sequence
|
||||
+library files to register its power sequence instance to global
|
||||
+power sequence list. The custom power sequence library creates power
|
||||
+sequence instance and implement custom power sequence.
|
||||
+
|
||||
+Since the power sequence describes hardware design, the description is
|
||||
+located at board description file, eg, device tree dts file. And
|
||||
+a specific power sequence belongs to device, so its description
|
||||
+is under the device node, please refer to:
|
||||
+Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt
|
||||
+
|
||||
+Custom power sequence library allocates one power sequence instance at
|
||||
+bootup periods using postcore_initcall, this static allocated instance is
|
||||
+used to compare with device-tree (DT) node to see if this library can be
|
||||
+used for the node or not. When the result is matched, the core API will
|
||||
+try to get resourses (->get, implemented at each library) for power
|
||||
+sequence, if all resources are got, it will try to allocate another
|
||||
+instance for next possible request from host driver.
|
||||
+
|
||||
+Then, the host controller driver can carry out power sequence on for this
|
||||
+DT node, the library will do corresponding operations, like open clocks,
|
||||
+toggle gpio, etc. The power sequence off routine will close and free the
|
||||
+resources, and is called when the parent is removed. And the power
|
||||
+sequence suspend and resume routine can be called at host driver's
|
||||
+suspend and resume routine if needed.
|
||||
+
|
||||
+The exported interfaces
|
||||
+.. kernel-doc:: drivers/power/pwrseq/core.c
|
||||
+ :export:
|
||||
diff --git a/MAINTAINERS b/MAINTAINERS
|
||||
index 429c6c624861..88fd31d1870f 100644
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -12599,6 +12599,15 @@ F: drivers/firmware/psci/
|
||||
F: include/linux/psci.h
|
||||
F: include/uapi/linux/psci.h
|
||||
|
||||
+POWER SEQUENCE LIBRARY
|
||||
+M: Peter Chen <Peter.Chen@nxp.com>
|
||||
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git
|
||||
+L: linux-pm@vger.kernel.org
|
||||
+S: Maintained
|
||||
+F: Documentation/devicetree/bindings/power/pwrseq/
|
||||
+F: drivers/power/pwrseq/
|
||||
+F: include/linux/power/pwrseq.h
|
||||
+
|
||||
POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS
|
||||
M: Sebastian Reichel <sre@kernel.org>
|
||||
L: linux-pm@vger.kernel.org
|
||||
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
|
||||
index ff0350ca3b74..78b6fa270cf9 100644
|
||||
--- a/drivers/power/Kconfig
|
||||
+++ b/drivers/power/Kconfig
|
||||
@@ -2,3 +2,4 @@
|
||||
source "drivers/power/avs/Kconfig"
|
||||
source "drivers/power/reset/Kconfig"
|
||||
source "drivers/power/supply/Kconfig"
|
||||
+source "drivers/power/pwrseq/Kconfig"
|
||||
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
|
||||
index b7c2e372186b..13046c7fb499 100644
|
||||
--- a/drivers/power/Makefile
|
||||
+++ b/drivers/power/Makefile
|
||||
@@ -2,3 +2,4 @@
|
||||
obj-$(CONFIG_POWER_AVS) += avs/
|
||||
obj-$(CONFIG_POWER_RESET) += reset/
|
||||
obj-$(CONFIG_POWER_SUPPLY) += supply/
|
||||
+obj-$(CONFIG_POWER_SEQUENCE) += pwrseq/
|
||||
diff --git a/drivers/power/pwrseq/Kconfig b/drivers/power/pwrseq/Kconfig
|
||||
new file mode 100644
|
||||
index 000000000000..c6b356926cca
|
||||
--- /dev/null
|
||||
+++ b/drivers/power/pwrseq/Kconfig
|
||||
@@ -0,0 +1,20 @@
|
||||
+#
|
||||
+# Power Sequence library
|
||||
+#
|
||||
+
|
||||
+menuconfig POWER_SEQUENCE
|
||||
+ bool "Power sequence control"
|
||||
+ help
|
||||
+ It is used for drivers which needs to do power sequence
|
||||
+ (eg, turn on clock, toggle reset gpio) before the related
|
||||
+ devices can be found by hardware, eg, USB bus.
|
||||
+
|
||||
+if POWER_SEQUENCE
|
||||
+
|
||||
+config PWRSEQ_GENERIC
|
||||
+ bool "Generic power sequence control"
|
||||
+ depends on OF
|
||||
+ help
|
||||
+ This is the generic power sequence control library, and is
|
||||
+ supposed to support common power sequence usage.
|
||||
+endif
|
||||
diff --git a/drivers/power/pwrseq/Makefile b/drivers/power/pwrseq/Makefile
|
||||
new file mode 100644
|
||||
index 000000000000..ad82389028c2
|
||||
--- /dev/null
|
||||
+++ b/drivers/power/pwrseq/Makefile
|
||||
@@ -0,0 +1,2 @@
|
||||
+obj-$(CONFIG_POWER_SEQUENCE) += core.o
|
||||
+obj-$(CONFIG_PWRSEQ_GENERIC) += pwrseq_generic.o
|
||||
diff --git a/drivers/power/pwrseq/core.c b/drivers/power/pwrseq/core.c
|
||||
new file mode 100644
|
||||
index 000000000000..3d19e62a2e76
|
||||
--- /dev/null
|
||||
+++ b/drivers/power/pwrseq/core.c
|
||||
@@ -0,0 +1,335 @@
|
||||
+/*
|
||||
+ * core.c power sequence core file
|
||||
+ *
|
||||
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
|
||||
+ * Author: Peter Chen <peter.chen@nxp.com>
|
||||
+ *
|
||||
+ * This program is free software: you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 of
|
||||
+ * the License as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/list.h>
|
||||
+#include <linux/mutex.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/power/pwrseq.h>
|
||||
+
|
||||
+static DEFINE_MUTEX(pwrseq_list_mutex);
|
||||
+static LIST_HEAD(pwrseq_list);
|
||||
+
|
||||
+static int pwrseq_get(struct device_node *np, struct pwrseq *p)
|
||||
+{
|
||||
+ if (p && p->get)
|
||||
+ return p->get(np, p);
|
||||
+
|
||||
+ return -ENOTSUPP;
|
||||
+}
|
||||
+
|
||||
+static int pwrseq_on(struct pwrseq *p)
|
||||
+{
|
||||
+ if (p && p->on)
|
||||
+ return p->on(p);
|
||||
+
|
||||
+ return -ENOTSUPP;
|
||||
+}
|
||||
+
|
||||
+static void pwrseq_off(struct pwrseq *p)
|
||||
+{
|
||||
+ if (p && p->off)
|
||||
+ p->off(p);
|
||||
+}
|
||||
+
|
||||
+static void pwrseq_put(struct pwrseq *p)
|
||||
+{
|
||||
+ if (p && p->put)
|
||||
+ p->put(p);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_register - Add pwrseq instance to global pwrseq list
|
||||
+ *
|
||||
+ * @pwrseq: the pwrseq instance
|
||||
+ */
|
||||
+void pwrseq_register(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ mutex_lock(&pwrseq_list_mutex);
|
||||
+ list_add(&pwrseq->node, &pwrseq_list);
|
||||
+ mutex_unlock(&pwrseq_list_mutex);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_register);
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_unregister - Remove pwrseq instance from global pwrseq list
|
||||
+ *
|
||||
+ * @pwrseq: the pwrseq instance
|
||||
+ */
|
||||
+void pwrseq_unregister(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ mutex_lock(&pwrseq_list_mutex);
|
||||
+ list_del(&pwrseq->node);
|
||||
+ mutex_unlock(&pwrseq_list_mutex);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_unregister);
|
||||
+
|
||||
+static struct pwrseq *pwrseq_find_available_instance(struct device_node *np)
|
||||
+{
|
||||
+ struct pwrseq *pwrseq;
|
||||
+
|
||||
+ mutex_lock(&pwrseq_list_mutex);
|
||||
+ list_for_each_entry(pwrseq, &pwrseq_list, node) {
|
||||
+ if (pwrseq->used)
|
||||
+ continue;
|
||||
+
|
||||
+ /* compare compatible string for pwrseq node */
|
||||
+ if (of_match_node(pwrseq->pwrseq_of_match_table, np)) {
|
||||
+ pwrseq->used = true;
|
||||
+ mutex_unlock(&pwrseq_list_mutex);
|
||||
+ return pwrseq;
|
||||
+ }
|
||||
+
|
||||
+ /* return generic pwrseq instance */
|
||||
+ if (!strcmp(pwrseq->pwrseq_of_match_table->compatible,
|
||||
+ "generic")) {
|
||||
+ pr_debug("using generic pwrseq instance for %s\n",
|
||||
+ np->full_name);
|
||||
+ pwrseq->used = true;
|
||||
+ mutex_unlock(&pwrseq_list_mutex);
|
||||
+ return pwrseq;
|
||||
+ }
|
||||
+ }
|
||||
+ mutex_unlock(&pwrseq_list_mutex);
|
||||
+ pr_debug("Can't find any pwrseq instances for %s\n", np->full_name);
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * of_pwrseq_on - Carry out power sequence on for device node
|
||||
+ *
|
||||
+ * @np: the device node would like to power on
|
||||
+ *
|
||||
+ * Carry out a single device power on. If multiple devices
|
||||
+ * need to be handled, use of_pwrseq_on_list() instead.
|
||||
+ *
|
||||
+ * Return a pointer to the power sequence instance on success,
|
||||
+ * or an error code otherwise.
|
||||
+ */
|
||||
+struct pwrseq *of_pwrseq_on(struct device_node *np)
|
||||
+{
|
||||
+ struct pwrseq *pwrseq;
|
||||
+ int ret;
|
||||
+
|
||||
+ pwrseq = pwrseq_find_available_instance(np);
|
||||
+ if (!pwrseq)
|
||||
+ return ERR_PTR(-ENOENT);
|
||||
+
|
||||
+ ret = pwrseq_get(np, pwrseq);
|
||||
+ if (ret) {
|
||||
+ /* Mark current pwrseq as unused */
|
||||
+ pwrseq->used = false;
|
||||
+ return ERR_PTR(ret);
|
||||
+ }
|
||||
+
|
||||
+ ret = pwrseq_on(pwrseq);
|
||||
+ if (ret)
|
||||
+ goto pwr_put;
|
||||
+
|
||||
+ return pwrseq;
|
||||
+
|
||||
+pwr_put:
|
||||
+ pwrseq_put(pwrseq);
|
||||
+ return ERR_PTR(ret);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(of_pwrseq_on);
|
||||
+
|
||||
+/**
|
||||
+ * of_pwrseq_off - Carry out power sequence off for this pwrseq instance
|
||||
+ *
|
||||
+ * @pwrseq: the pwrseq instance which related device would like to be off
|
||||
+ *
|
||||
+ * This API is used to power off single device, it is the opposite
|
||||
+ * operation for of_pwrseq_on.
|
||||
+ */
|
||||
+void of_pwrseq_off(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ pwrseq_off(pwrseq);
|
||||
+ pwrseq_put(pwrseq);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(of_pwrseq_off);
|
||||
+
|
||||
+/**
|
||||
+ * of_pwrseq_on_list - Carry out power sequence on for list
|
||||
+ *
|
||||
+ * @np: the device node would like to power on
|
||||
+ * @head: the list head for pwrseq list on this bus
|
||||
+ *
|
||||
+ * This API is used to power on multiple devices at single bus.
|
||||
+ * If there are several devices on bus (eg, USB bus), uses this
|
||||
+ * this API. Otherwise, use of_pwrseq_on instead. After the device
|
||||
+ * is powered on successfully, it will be added to pwrseq list for
|
||||
+ * this bus. The caller needs to use mutex_lock for concurrent.
|
||||
+ *
|
||||
+ * Return 0 on success, or an error value otherwise.
|
||||
+ */
|
||||
+int of_pwrseq_on_list(struct device_node *np, struct list_head *head)
|
||||
+{
|
||||
+ struct pwrseq *pwrseq;
|
||||
+ struct pwrseq_list_per_dev *pwrseq_list_node;
|
||||
+
|
||||
+ pwrseq_list_node = kzalloc(sizeof(*pwrseq_list_node), GFP_KERNEL);
|
||||
+ if (!pwrseq_list_node)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ pwrseq = of_pwrseq_on(np);
|
||||
+ if (IS_ERR(pwrseq)) {
|
||||
+ kfree(pwrseq_list_node);
|
||||
+ return PTR_ERR(pwrseq);
|
||||
+ }
|
||||
+
|
||||
+ pwrseq_list_node->pwrseq = pwrseq;
|
||||
+ list_add(&pwrseq_list_node->list, head);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(of_pwrseq_on_list);
|
||||
+
|
||||
+/**
|
||||
+ * of_pwrseq_off_list - Carry out power sequence off for the list
|
||||
+ *
|
||||
+ * @head: the list head for pwrseq instance list on this bus
|
||||
+ *
|
||||
+ * This API is used to power off all devices on this bus, it is
|
||||
+ * the opposite operation for of_pwrseq_on_list.
|
||||
+ * The caller needs to use mutex_lock for concurrent.
|
||||
+ */
|
||||
+void of_pwrseq_off_list(struct list_head *head)
|
||||
+{
|
||||
+ struct pwrseq *pwrseq;
|
||||
+ struct pwrseq_list_per_dev *pwrseq_list_node, *tmp_node;
|
||||
+
|
||||
+ list_for_each_entry_safe(pwrseq_list_node, tmp_node, head, list) {
|
||||
+ pwrseq = pwrseq_list_node->pwrseq;
|
||||
+ of_pwrseq_off(pwrseq);
|
||||
+ list_del(&pwrseq_list_node->list);
|
||||
+ kfree(pwrseq_list_node);
|
||||
+ }
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(of_pwrseq_off_list);
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_suspend - Carry out power sequence suspend for this pwrseq instance
|
||||
+ *
|
||||
+ * @pwrseq: the pwrseq instance
|
||||
+ *
|
||||
+ * This API is used to do suspend operation on pwrseq instance.
|
||||
+ *
|
||||
+ * Return 0 on success, or an error value otherwise.
|
||||
+ */
|
||||
+int pwrseq_suspend(struct pwrseq *p)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ if (p && p->suspend)
|
||||
+ ret = p->suspend(p);
|
||||
+ else
|
||||
+ return ret;
|
||||
+
|
||||
+ if (!ret)
|
||||
+ p->suspended = true;
|
||||
+ else
|
||||
+ pr_err("%s failed\n", __func__);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_suspend);
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_resume - Carry out power sequence resume for this pwrseq instance
|
||||
+ *
|
||||
+ * @pwrseq: the pwrseq instance
|
||||
+ *
|
||||
+ * This API is used to do resume operation on pwrseq instance.
|
||||
+ *
|
||||
+ * Return 0 on success, or an error value otherwise.
|
||||
+ */
|
||||
+int pwrseq_resume(struct pwrseq *p)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ if (p && p->resume)
|
||||
+ ret = p->resume(p);
|
||||
+ else
|
||||
+ return ret;
|
||||
+
|
||||
+ if (!ret)
|
||||
+ p->suspended = false;
|
||||
+ else
|
||||
+ pr_err("%s failed\n", __func__);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_resume);
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_suspend_list - Carry out power sequence suspend for list
|
||||
+ *
|
||||
+ * @head: the list head for pwrseq instance list on this bus
|
||||
+ *
|
||||
+ * This API is used to do suspend on all power sequence instances on this bus.
|
||||
+ * The caller needs to use mutex_lock for concurrent.
|
||||
+ */
|
||||
+int pwrseq_suspend_list(struct list_head *head)
|
||||
+{
|
||||
+ struct pwrseq *pwrseq;
|
||||
+ struct pwrseq_list_per_dev *pwrseq_list_node;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ list_for_each_entry(pwrseq_list_node, head, list) {
|
||||
+ ret = pwrseq_suspend(pwrseq_list_node->pwrseq);
|
||||
+ if (ret)
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (ret) {
|
||||
+ list_for_each_entry(pwrseq_list_node, head, list) {
|
||||
+ pwrseq = pwrseq_list_node->pwrseq;
|
||||
+ if (pwrseq->suspended)
|
||||
+ pwrseq_resume(pwrseq);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_suspend_list);
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_resume_list - Carry out power sequence resume for the list
|
||||
+ *
|
||||
+ * @head: the list head for pwrseq instance list on this bus
|
||||
+ *
|
||||
+ * This API is used to do resume on all power sequence instances on this bus.
|
||||
+ * The caller needs to use mutex_lock for concurrent.
|
||||
+ */
|
||||
+int pwrseq_resume_list(struct list_head *head)
|
||||
+{
|
||||
+ struct pwrseq_list_per_dev *pwrseq_list_node;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ list_for_each_entry(pwrseq_list_node, head, list) {
|
||||
+ ret = pwrseq_resume(pwrseq_list_node->pwrseq);
|
||||
+ if (ret)
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_resume_list);
|
||||
diff --git a/drivers/power/pwrseq/pwrseq_generic.c b/drivers/power/pwrseq/pwrseq_generic.c
|
||||
new file mode 100644
|
||||
index 000000000000..4e7c09086cfb
|
||||
--- /dev/null
|
||||
+++ b/drivers/power/pwrseq/pwrseq_generic.c
|
||||
@@ -0,0 +1,234 @@
|
||||
+/*
|
||||
+ * pwrseq_generic.c Generic power sequence handling
|
||||
+ *
|
||||
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
|
||||
+ * Author: Peter Chen <peter.chen@nxp.com>
|
||||
+ *
|
||||
+ * This program is free software: you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 of
|
||||
+ * the License as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/gpio.h>
|
||||
+#include <linux/gpio/consumer.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/of_gpio.h>
|
||||
+#include <linux/slab.h>
|
||||
+
|
||||
+#include <linux/power/pwrseq.h>
|
||||
+
|
||||
+struct pwrseq_generic {
|
||||
+ struct pwrseq pwrseq;
|
||||
+ struct gpio_desc *gpiod_reset;
|
||||
+ struct clk *clks[PWRSEQ_MAX_CLKS];
|
||||
+ u32 duration_us;
|
||||
+ bool suspended;
|
||||
+};
|
||||
+
|
||||
+#define to_generic_pwrseq(p) container_of(p, struct pwrseq_generic, pwrseq)
|
||||
+
|
||||
+static int pwrseq_generic_alloc_instance(void);
|
||||
+static const struct of_device_id generic_id_table[] = {
|
||||
+ { .compatible = "generic",},
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+
|
||||
+static int pwrseq_generic_suspend(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ int clk;
|
||||
+
|
||||
+ for (clk = PWRSEQ_MAX_CLKS - 1; clk >= 0; clk--)
|
||||
+ clk_disable_unprepare(pwrseq_gen->clks[clk]);
|
||||
+
|
||||
+ pwrseq_gen->suspended = true;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int pwrseq_generic_resume(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ int clk, ret = 0;
|
||||
+
|
||||
+ for (clk = 0; clk < PWRSEQ_MAX_CLKS && pwrseq_gen->clks[clk]; clk++) {
|
||||
+ ret = clk_prepare_enable(pwrseq_gen->clks[clk]);
|
||||
+ if (ret) {
|
||||
+ pr_err("Can't enable clock, ret=%d\n", ret);
|
||||
+ goto err_disable_clks;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ pwrseq_gen->suspended = false;
|
||||
+ return ret;
|
||||
+
|
||||
+err_disable_clks:
|
||||
+ while (--clk >= 0)
|
||||
+ clk_disable_unprepare(pwrseq_gen->clks[clk]);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void pwrseq_generic_put(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ int clk;
|
||||
+
|
||||
+ if (pwrseq_gen->gpiod_reset)
|
||||
+ gpiod_put(pwrseq_gen->gpiod_reset);
|
||||
+
|
||||
+ for (clk = 0; clk < PWRSEQ_MAX_CLKS; clk++)
|
||||
+ clk_put(pwrseq_gen->clks[clk]);
|
||||
+
|
||||
+ pwrseq_unregister(&pwrseq_gen->pwrseq);
|
||||
+ kfree(pwrseq_gen);
|
||||
+}
|
||||
+
|
||||
+static void pwrseq_generic_off(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ int clk;
|
||||
+
|
||||
+ if (pwrseq_gen->suspended)
|
||||
+ return;
|
||||
+
|
||||
+ for (clk = PWRSEQ_MAX_CLKS - 1; clk >= 0; clk--)
|
||||
+ clk_disable_unprepare(pwrseq_gen->clks[clk]);
|
||||
+}
|
||||
+
|
||||
+static int pwrseq_generic_on(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ int clk, ret = 0;
|
||||
+ struct gpio_desc *gpiod_reset = pwrseq_gen->gpiod_reset;
|
||||
+
|
||||
+ for (clk = 0; clk < PWRSEQ_MAX_CLKS && pwrseq_gen->clks[clk]; clk++) {
|
||||
+ ret = clk_prepare_enable(pwrseq_gen->clks[clk]);
|
||||
+ if (ret) {
|
||||
+ pr_err("Can't enable clock, ret=%d\n", ret);
|
||||
+ goto err_disable_clks;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (gpiod_reset) {
|
||||
+ u32 duration_us = pwrseq_gen->duration_us;
|
||||
+
|
||||
+ if (duration_us <= 10)
|
||||
+ udelay(10);
|
||||
+ else
|
||||
+ usleep_range(duration_us, duration_us + 100);
|
||||
+ gpiod_set_value(gpiod_reset, 0);
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+
|
||||
+err_disable_clks:
|
||||
+ while (--clk >= 0)
|
||||
+ clk_disable_unprepare(pwrseq_gen->clks[clk]);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int pwrseq_generic_get(struct device_node *np, struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ enum of_gpio_flags flags;
|
||||
+ int reset_gpio, clk, ret = 0;
|
||||
+
|
||||
+ for (clk = 0; clk < PWRSEQ_MAX_CLKS; clk++) {
|
||||
+ pwrseq_gen->clks[clk] = of_clk_get(np, clk);
|
||||
+ if (IS_ERR(pwrseq_gen->clks[clk])) {
|
||||
+ ret = PTR_ERR(pwrseq_gen->clks[clk]);
|
||||
+ if (ret != -ENOENT)
|
||||
+ goto err_put_clks;
|
||||
+ pwrseq_gen->clks[clk] = NULL;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ reset_gpio = of_get_named_gpio_flags(np, "reset-gpios", 0, &flags);
|
||||
+ if (gpio_is_valid(reset_gpio)) {
|
||||
+ unsigned long gpio_flags;
|
||||
+
|
||||
+ if (flags & OF_GPIO_ACTIVE_LOW)
|
||||
+ gpio_flags = GPIOF_ACTIVE_LOW | GPIOF_OUT_INIT_LOW;
|
||||
+ else
|
||||
+ gpio_flags = GPIOF_OUT_INIT_HIGH;
|
||||
+
|
||||
+ ret = gpio_request_one(reset_gpio, gpio_flags,
|
||||
+ "pwrseq-reset-gpios");
|
||||
+ if (ret)
|
||||
+ goto err_put_clks;
|
||||
+
|
||||
+ pwrseq_gen->gpiod_reset = gpio_to_desc(reset_gpio);
|
||||
+ of_property_read_u32(np, "reset-duration-us",
|
||||
+ &pwrseq_gen->duration_us);
|
||||
+ } else if (reset_gpio == -ENOENT) {
|
||||
+ ; /* no such gpio */
|
||||
+ } else {
|
||||
+ ret = reset_gpio;
|
||||
+ pr_err("Failed to get reset gpio on %s, err = %d\n",
|
||||
+ np->full_name, reset_gpio);
|
||||
+ goto err_put_clks;
|
||||
+ }
|
||||
+
|
||||
+ /* allocate new one for later pwrseq instance request */
|
||||
+ ret = pwrseq_generic_alloc_instance();
|
||||
+ if (ret)
|
||||
+ goto err_put_gpio;
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_put_gpio:
|
||||
+ if (pwrseq_gen->gpiod_reset)
|
||||
+ gpiod_put(pwrseq_gen->gpiod_reset);
|
||||
+err_put_clks:
|
||||
+ while (--clk >= 0)
|
||||
+ clk_put(pwrseq_gen->clks[clk]);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_generic_alloc_instance - power sequence instance allocation
|
||||
+ *
|
||||
+ * This function is used to allocate one generic power sequence instance,
|
||||
+ * it is called when the system boots up and after one power sequence
|
||||
+ * instance is got successfully.
|
||||
+ *
|
||||
+ * Return zero on success or an error code otherwise.
|
||||
+ */
|
||||
+static int pwrseq_generic_alloc_instance(void)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen;
|
||||
+
|
||||
+ pwrseq_gen = kzalloc(sizeof(*pwrseq_gen), GFP_KERNEL);
|
||||
+ if (!pwrseq_gen)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ pwrseq_gen->pwrseq.pwrseq_of_match_table = generic_id_table;
|
||||
+ pwrseq_gen->pwrseq.get = pwrseq_generic_get;
|
||||
+ pwrseq_gen->pwrseq.on = pwrseq_generic_on;
|
||||
+ pwrseq_gen->pwrseq.off = pwrseq_generic_off;
|
||||
+ pwrseq_gen->pwrseq.put = pwrseq_generic_put;
|
||||
+ pwrseq_gen->pwrseq.suspend = pwrseq_generic_suspend;
|
||||
+ pwrseq_gen->pwrseq.resume = pwrseq_generic_resume;
|
||||
+
|
||||
+ pwrseq_register(&pwrseq_gen->pwrseq);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Allocate one pwrseq instance during boots up */
|
||||
+static int __init pwrseq_generic_register(void)
|
||||
+{
|
||||
+ return pwrseq_generic_alloc_instance();
|
||||
+}
|
||||
+postcore_initcall(pwrseq_generic_register)
|
||||
diff --git a/include/linux/power/pwrseq.h b/include/linux/power/pwrseq.h
|
||||
new file mode 100644
|
||||
index 000000000000..cbc344cdf9d2
|
||||
--- /dev/null
|
||||
+++ b/include/linux/power/pwrseq.h
|
||||
@@ -0,0 +1,81 @@
|
||||
+#ifndef __LINUX_PWRSEQ_H
|
||||
+#define __LINUX_PWRSEQ_H
|
||||
+
|
||||
+#include <linux/of.h>
|
||||
+
|
||||
+#define PWRSEQ_MAX_CLKS 3
|
||||
+
|
||||
+/**
|
||||
+ * struct pwrseq - the power sequence structure
|
||||
+ * @pwrseq_of_match_table: the OF device id table this pwrseq library supports
|
||||
+ * @node: the list pointer to be added to pwrseq list
|
||||
+ * @get: the API is used to get pwrseq instance from the device node
|
||||
+ * @on: do power on for this pwrseq instance
|
||||
+ * @off: do power off for this pwrseq instance
|
||||
+ * @put: release the resources on this pwrseq instance
|
||||
+ * @suspend: do suspend operation on this pwrseq instance
|
||||
+ * @resume: do resume operation on this pwrseq instance
|
||||
+ * @used: this pwrseq instance is used by device
|
||||
+ */
|
||||
+struct pwrseq {
|
||||
+ const struct of_device_id *pwrseq_of_match_table;
|
||||
+ struct list_head node;
|
||||
+ int (*get)(struct device_node *np, struct pwrseq *p);
|
||||
+ int (*on)(struct pwrseq *p);
|
||||
+ void (*off)(struct pwrseq *p);
|
||||
+ void (*put)(struct pwrseq *p);
|
||||
+ int (*suspend)(struct pwrseq *p);
|
||||
+ int (*resume)(struct pwrseq *p);
|
||||
+ bool used;
|
||||
+ bool suspended;
|
||||
+};
|
||||
+
|
||||
+/* used for power sequence instance list in one driver */
|
||||
+struct pwrseq_list_per_dev {
|
||||
+ struct pwrseq *pwrseq;
|
||||
+ struct list_head list;
|
||||
+};
|
||||
+
|
||||
+#if IS_ENABLED(CONFIG_POWER_SEQUENCE)
|
||||
+void pwrseq_register(struct pwrseq *pwrseq);
|
||||
+void pwrseq_unregister(struct pwrseq *pwrseq);
|
||||
+struct pwrseq *of_pwrseq_on(struct device_node *np);
|
||||
+void of_pwrseq_off(struct pwrseq *pwrseq);
|
||||
+int of_pwrseq_on_list(struct device_node *np, struct list_head *head);
|
||||
+void of_pwrseq_off_list(struct list_head *head);
|
||||
+int pwrseq_suspend(struct pwrseq *p);
|
||||
+int pwrseq_resume(struct pwrseq *p);
|
||||
+int pwrseq_suspend_list(struct list_head *head);
|
||||
+int pwrseq_resume_list(struct list_head *head);
|
||||
+#else
|
||||
+static inline void pwrseq_register(struct pwrseq *pwrseq) {}
|
||||
+static inline void pwrseq_unregister(struct pwrseq *pwrseq) {}
|
||||
+static inline struct pwrseq *of_pwrseq_on(struct device_node *np)
|
||||
+{
|
||||
+ return NULL;
|
||||
+}
|
||||
+static void of_pwrseq_off(struct pwrseq *pwrseq) {}
|
||||
+static int of_pwrseq_on_list(struct device_node *np, struct list_head *head)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+static void of_pwrseq_off_list(struct list_head *head) {}
|
||||
+static int pwrseq_suspend(struct pwrseq *p)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+static int pwrseq_resume(struct pwrseq *p)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+static int pwrseq_suspend_list(struct list_head *head)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+static int pwrseq_resume_list(struct list_head *head)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif /* CONFIG_POWER_SEQUENCE */
|
||||
+
|
||||
+#endif /* __LINUX_PWRSEQ_H */
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,165 +0,0 @@
|
||||
From a42362841fe263a6c97a1793ccd4b9246ac2b108 Mon Sep 17 00:00:00 2001
|
||||
From: Peter Chen <peter.chen@nxp.com>
|
||||
Date: Thu, 18 May 2017 08:49:00 +0800
|
||||
Subject: [PATCH 4/9] usb: core: add power sequence handling for USB devices
|
||||
|
||||
Some hard-wired USB devices need to do power sequence to let the
|
||||
device work normally, the typical power sequence like: enable USB
|
||||
PHY clock, toggle reset pin, etc. But current Linux USB driver
|
||||
lacks of such code to do it, it may cause some hard-wired USB devices
|
||||
works abnormal or can't be recognized by controller at all.
|
||||
|
||||
In this patch, it calls power sequence library APIs to finish
|
||||
the power sequence events. It will do power on sequence at hub's
|
||||
probe for all devices under this hub (includes root hub).
|
||||
At hub_disconnect, it will do power off sequence which is at powered
|
||||
on list.
|
||||
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
Tested-by Joshua Clayton <stillcompiling@gmail.com>
|
||||
Tested-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
|
||||
Reviewed-by: Vaibhav Hiremath <hvaibhav.linux@gmail.com>
|
||||
---
|
||||
drivers/usb/Kconfig | 1 +
|
||||
drivers/usb/core/hub.c | 49 ++++++++++++++++++++++++++++++++++++++----
|
||||
drivers/usb/core/hub.h | 1 +
|
||||
3 files changed, 47 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
|
||||
index 6e59d370ef81..2162fd85b32d 100644
|
||||
--- a/drivers/usb/Kconfig
|
||||
+++ b/drivers/usb/Kconfig
|
||||
@@ -47,6 +47,7 @@ config USB
|
||||
depends on USB_ARCH_HAS_HCD
|
||||
select GENERIC_ALLOCATOR
|
||||
select USB_COMMON
|
||||
+ select POWER_SEQUENCE
|
||||
select NLS # for UTF-8 strings
|
||||
---help---
|
||||
Universal Serial Bus (USB) is a specification for a serial bus
|
||||
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
|
||||
index 236313f41f4a..3db75b0d2426 100644
|
||||
--- a/drivers/usb/core/hub.c
|
||||
+++ b/drivers/usb/core/hub.c
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <linux/random.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/kobject.h>
|
||||
+#include <linux/power/pwrseq.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/byteorder.h>
|
||||
@@ -1705,6 +1706,7 @@ static void hub_disconnect(struct usb_interface *intf)
|
||||
hub->error = 0;
|
||||
hub_quiesce(hub, HUB_DISCONNECT);
|
||||
|
||||
+ of_pwrseq_off_list(&hub->pwrseq_on_list);
|
||||
mutex_lock(&usb_port_peer_mutex);
|
||||
|
||||
/* Avoid races with recursively_mark_NOTATTACHED() */
|
||||
@@ -1751,11 +1753,41 @@ static bool hub_descriptor_is_sane(struct usb_host_interface *desc)
|
||||
return true;
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_OF
|
||||
+static int hub_of_pwrseq_on(struct usb_hub *hub)
|
||||
+{
|
||||
+ struct device *parent;
|
||||
+ struct usb_device *hdev = hub->hdev;
|
||||
+ struct device_node *np;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (hdev->parent)
|
||||
+ parent = &hdev->dev;
|
||||
+ else
|
||||
+ parent = bus_to_hcd(hdev->bus)->self.sysdev;
|
||||
+
|
||||
+ for_each_child_of_node(parent->of_node, np) {
|
||||
+ ret = of_pwrseq_on_list(np, &hub->pwrseq_on_list);
|
||||
+ /* Maybe no power sequence library is chosen */
|
||||
+ if (ret && ret != -ENOENT)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+#else
|
||||
+static int hub_of_pwrseq_on(struct usb_hub *hub)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_host_interface *desc;
|
||||
struct usb_device *hdev;
|
||||
struct usb_hub *hub;
|
||||
+ int ret = -ENODEV;
|
||||
|
||||
desc = intf->cur_altsetting;
|
||||
hdev = interface_to_usbdev(intf);
|
||||
@@ -1846,6 +1878,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
INIT_DELAYED_WORK(&hub->leds, led_work);
|
||||
INIT_DELAYED_WORK(&hub->init_work, NULL);
|
||||
INIT_WORK(&hub->events, hub_event);
|
||||
+ INIT_LIST_HEAD(&hub->pwrseq_on_list);
|
||||
spin_lock_init(&hub->irq_urb_lock);
|
||||
timer_setup(&hub->irq_urb_retry, hub_retry_irq_urb, 0);
|
||||
usb_get_intf(intf);
|
||||
@@ -1861,11 +1894,14 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
if (id->driver_info & HUB_QUIRK_CHECK_PORT_AUTOSUSPEND)
|
||||
hub->quirk_check_port_auto_suspend = 1;
|
||||
|
||||
- if (hub_configure(hub, &desc->endpoint[0].desc) >= 0)
|
||||
- return 0;
|
||||
+ if (hub_configure(hub, &desc->endpoint[0].desc) >= 0) {
|
||||
+ ret = hub_of_pwrseq_on(hub);
|
||||
+ if (!ret)
|
||||
+ return 0;
|
||||
+ }
|
||||
|
||||
hub_disconnect(intf);
|
||||
- return -ENODEV;
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -3720,7 +3756,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
|
||||
|
||||
/* stop hub_wq and related activity */
|
||||
hub_quiesce(hub, HUB_SUSPEND);
|
||||
- return 0;
|
||||
+ return pwrseq_suspend_list(&hub->pwrseq_on_list);
|
||||
}
|
||||
|
||||
/* Report wakeup requests from the ports of a resuming root hub */
|
||||
@@ -3760,8 +3796,13 @@ static void report_wakeup_requests(struct usb_hub *hub)
|
||||
static int hub_resume(struct usb_interface *intf)
|
||||
{
|
||||
struct usb_hub *hub = usb_get_intfdata(intf);
|
||||
+ int ret;
|
||||
|
||||
dev_dbg(&intf->dev, "%s\n", __func__);
|
||||
+ ret = pwrseq_resume_list(&hub->pwrseq_on_list);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
hub_activate(hub, HUB_RESUME);
|
||||
|
||||
/*
|
||||
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
|
||||
index a9e24e4b8df1..feab956a1414 100644
|
||||
--- a/drivers/usb/core/hub.h
|
||||
+++ b/drivers/usb/core/hub.h
|
||||
@@ -72,6 +72,7 @@ struct usb_hub {
|
||||
spinlock_t irq_urb_lock;
|
||||
struct timer_list irq_urb_retry;
|
||||
struct usb_port **ports;
|
||||
+ struct list_head pwrseq_on_list; /* powered pwrseq node list */
|
||||
};
|
||||
|
||||
/**
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,49 +0,0 @@
|
||||
From bf1b3a63aa2f3438750f5acdf372705f8a1beb41 Mon Sep 17 00:00:00 2001
|
||||
From: Joshua Clayton <stillcompiling@gmail.com>
|
||||
Date: Thu, 18 May 2017 08:49:01 +0800
|
||||
Subject: [PATCH 5/9] ARM: dts: imx6qdl: Enable usb node children with <reg>
|
||||
|
||||
Give usb nodes #address and #size attributes, so that a child node
|
||||
representing a permanently connected device such as an onboard hub may
|
||||
be addressed with a <reg> attribute
|
||||
|
||||
Signed-off-by: Joshua Clayton <stillcompiling@gmail.com>
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
---
|
||||
arch/arm/boot/dts/imx6qdl.dtsi | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
|
||||
index fe17a3405edc..a5f2f981255f 100644
|
||||
--- a/arch/arm/boot/dts/imx6qdl.dtsi
|
||||
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
|
||||
@@ -977,6 +977,8 @@
|
||||
|
||||
usbh1: usb@2184200 {
|
||||
compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
reg = <0x02184200 0x200>;
|
||||
interrupts = <0 40 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX6QDL_CLK_USBOH3>;
|
||||
@@ -991,6 +993,8 @@
|
||||
|
||||
usbh2: usb@2184400 {
|
||||
compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
reg = <0x02184400 0x200>;
|
||||
interrupts = <0 41 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX6QDL_CLK_USBOH3>;
|
||||
@@ -1006,6 +1010,8 @@
|
||||
|
||||
usbh3: usb@2184600 {
|
||||
compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
reg = <0x02184600 0x200>;
|
||||
interrupts = <0 42 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX6QDL_CLK_USBOH3>;
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,79 +0,0 @@
|
||||
From c46707dde637ec75182c2f42f61aab96486bbcee Mon Sep 17 00:00:00 2001
|
||||
From: Peter Chen <peter.chen@nxp.com>
|
||||
Date: Thu, 18 May 2017 08:49:02 +0800
|
||||
Subject: [PATCH 6/9] ARM: dts: imx6qdl-udoo.dtsi: fix onboard USB HUB property
|
||||
|
||||
The current dts describes USB HUB's property at USB controller's
|
||||
entry, it is improper. The USB HUB should be the child node
|
||||
under USB controller, and power sequence properties are under
|
||||
it. Besides, using gpio pinctrl setting for USB2415's reset pin.
|
||||
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
Signed-off-by: Joshua Clayton <stillcompiling@gmail.com>
|
||||
Tested-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
|
||||
---
|
||||
arch/arm/boot/dts/imx6qdl-udoo.dtsi | 26 ++++++++++++--------------
|
||||
1 file changed, 12 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/arch/arm/boot/dts/imx6qdl-udoo.dtsi b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
|
||||
index 776bfc77f89d..4781a9e04338 100644
|
||||
--- a/arch/arm/boot/dts/imx6qdl-udoo.dtsi
|
||||
+++ b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
|
||||
@@ -5,6 +5,8 @@
|
||||
* Author: Fabio Estevam <fabio.estevam@freescale.com>
|
||||
*/
|
||||
|
||||
+#include <dt-bindings/gpio/gpio.h>
|
||||
+
|
||||
/ {
|
||||
aliases {
|
||||
backlight = &backlight;
|
||||
@@ -62,17 +64,6 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
- reg_usb_h1_vbus: regulator@0 {
|
||||
- compatible = "regulator-fixed";
|
||||
- reg = <0>;
|
||||
- regulator-name = "usb_h1_vbus";
|
||||
- regulator-min-microvolt = <5000000>;
|
||||
- regulator-max-microvolt = <5000000>;
|
||||
- enable-active-high;
|
||||
- startup-delay-us = <2>; /* USB2415 requires a POR of 1 us minimum */
|
||||
- gpio = <&gpio7 12 0>;
|
||||
- };
|
||||
-
|
||||
reg_panel: regulator@1 {
|
||||
compatible = "regulator-fixed";
|
||||
reg = <1>;
|
||||
@@ -205,7 +196,7 @@
|
||||
|
||||
pinctrl_usbh: usbhgrp {
|
||||
fsl,pins = <
|
||||
- MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x80000000
|
||||
+ MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x1b0b0
|
||||
MX6QDL_PAD_NANDF_CS2__CCM_CLKO2 0x130b0
|
||||
>;
|
||||
};
|
||||
@@ -282,9 +273,16 @@
|
||||
&usbh1 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_usbh>;
|
||||
- vbus-supply = <®_usb_h1_vbus>;
|
||||
- clocks = <&clks IMX6QDL_CLK_CKO>;
|
||||
status = "okay";
|
||||
+
|
||||
+ usb2415: hub@1 {
|
||||
+ compatible = "usb424,2514";
|
||||
+ reg = <1>;
|
||||
+
|
||||
+ clocks = <&clks IMX6QDL_CLK_CKO>;
|
||||
+ reset-gpios = <&gpio7 12 GPIO_ACTIVE_LOW>;
|
||||
+ reset-duration-us = <3000>;
|
||||
+ };
|
||||
};
|
||||
|
||||
&usdhc3 {
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,74 +0,0 @@
|
||||
From 0ae59d1767a9cf9875b35a026b5df13eeb3694db Mon Sep 17 00:00:00 2001
|
||||
From: Joshua Clayton <stillcompiling@gmail.com>
|
||||
Date: Thu, 18 May 2017 08:49:03 +0800
|
||||
Subject: [PATCH 7/9] ARM: dts: imx6q-evi: Fix onboard hub reset line
|
||||
|
||||
Previously the onboard hub was made to work by treating its
|
||||
reset gpio as a regulator enable.
|
||||
Get rid of that kludge now that pwseq has added reset gpio support
|
||||
Move pin muxing the hub reset pin into the usbh1 group
|
||||
|
||||
Signed-off-by: Joshua Clayton <stillcompiling@gmail.com>
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
---
|
||||
arch/arm/boot/dts/imx6q-evi.dts | 25 +++++++------------------
|
||||
1 file changed, 7 insertions(+), 18 deletions(-)
|
||||
|
||||
diff --git a/arch/arm/boot/dts/imx6q-evi.dts b/arch/arm/boot/dts/imx6q-evi.dts
|
||||
index c63f371ede8b..546d9d4e8ca1 100644
|
||||
--- a/arch/arm/boot/dts/imx6q-evi.dts
|
||||
+++ b/arch/arm/boot/dts/imx6q-evi.dts
|
||||
@@ -55,18 +55,6 @@
|
||||
reg = <0x10000000 0x40000000>;
|
||||
};
|
||||
|
||||
- reg_usbh1_vbus: regulator-usbhubreset {
|
||||
- compatible = "regulator-fixed";
|
||||
- regulator-name = "usbh1_vbus";
|
||||
- regulator-min-microvolt = <5000000>;
|
||||
- regulator-max-microvolt = <5000000>;
|
||||
- enable-active-high;
|
||||
- startup-delay-us = <2>;
|
||||
- pinctrl-names = "default";
|
||||
- pinctrl-0 = <&pinctrl_usbh1_hubreset>;
|
||||
- gpio = <&gpio7 12 GPIO_ACTIVE_HIGH>;
|
||||
- };
|
||||
-
|
||||
reg_usb_otg_vbus: regulator-usbotgvbus {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "usb_otg_vbus";
|
||||
@@ -214,12 +202,18 @@
|
||||
};
|
||||
|
||||
&usbh1 {
|
||||
- vbus-supply = <®_usbh1_vbus>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_usbh1>;
|
||||
dr_mode = "host";
|
||||
disable-over-current;
|
||||
status = "okay";
|
||||
+
|
||||
+ usb2415host: hub@1 {
|
||||
+ compatible = "usb424,2513";
|
||||
+ reg = <1>;
|
||||
+ reset-gpios = <&gpio7 12 GPIO_ACTIVE_LOW>;
|
||||
+ reset-duration-us = <3000>;
|
||||
+ };
|
||||
};
|
||||
|
||||
&usbotg {
|
||||
@@ -482,11 +476,6 @@
|
||||
MX6QDL_PAD_GPIO_3__USB_H1_OC 0x1b0b0
|
||||
/* usbh1_b OC */
|
||||
MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x1b0b0
|
||||
- >;
|
||||
- };
|
||||
-
|
||||
- pinctrl_usbh1_hubreset: usbh1hubresetgrp {
|
||||
- fsl,pins = <
|
||||
MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x1b0b0
|
||||
>;
|
||||
};
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,511 +0,0 @@
|
||||
From 9a4d8e886600c7c330590a2435dd74eb16d480ce Mon Sep 17 00:00:00 2001
|
||||
From: Steve Arnold <nerdboy@gentoo.org>
|
||||
Date: Fri, 15 Dec 2017 16:43:22 -0800
|
||||
Subject: [PATCH 8/9] ARM: dts,driver: imx6,udooqdl: add arduino manager driver
|
||||
and update dts
|
||||
|
||||
* note this is required to upload sketches to sam3 from arduino IDE
|
||||
|
||||
Signed-off-by: Steve Arnold <nerdboy@gentoo.org>
|
||||
---
|
||||
arch/arm/boot/dts/imx6qdl-udoo.dtsi | 20 ++
|
||||
drivers/misc/Kconfig | 7 +
|
||||
drivers/misc/Makefile | 1 +
|
||||
drivers/misc/udoo_ard.c | 417 ++++++++++++++++++++++++++++
|
||||
4 files changed, 445 insertions(+)
|
||||
create mode 100755 drivers/misc/udoo_ard.c
|
||||
|
||||
diff --git a/arch/arm/boot/dts/imx6qdl-udoo.dtsi b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
|
||||
index 4781a9e04338..554f601eb72a 100644
|
||||
--- a/arch/arm/boot/dts/imx6qdl-udoo.dtsi
|
||||
+++ b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
|
||||
@@ -84,6 +84,17 @@
|
||||
mux-int-port = <1>;
|
||||
mux-ext-port = <6>;
|
||||
};
|
||||
+
|
||||
+ udoo_ard: udoo_ard_manager {
|
||||
+ compatible = "udoo,imx6q-udoo-ard";
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&pinctrl_udooard>;
|
||||
+ bossac-clk-gpio = <&gpio6 3 0>;
|
||||
+ bossac-dat-gpio = <&gpio5 18 0>;
|
||||
+ bossac-erase-gpio = <&gpio4 21 0>;
|
||||
+ bossac-reset-gpio = <&gpio1 0 0>;
|
||||
+ status = "okay";
|
||||
+ };
|
||||
};
|
||||
|
||||
&fec {
|
||||
@@ -201,6 +212,15 @@
|
||||
>;
|
||||
};
|
||||
|
||||
+ pinctrl_udooard: udooardgrp {
|
||||
+ fsl,pins = <
|
||||
+ MX6QDL_PAD_DISP0_DAT0__GPIO4_IO21 0x80000000
|
||||
+ MX6QDL_PAD_CSI0_DAT17__GPIO6_IO03 0x80000000
|
||||
+ MX6QDL_PAD_CSI0_PIXCLK__GPIO5_IO18 0x80000000
|
||||
+ MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x80000000
|
||||
+ >;
|
||||
+ };
|
||||
+
|
||||
pinctrl_usdhc3: usdhc3grp {
|
||||
fsl,pins = <
|
||||
MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059
|
||||
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
|
||||
index 2cf9db44e4b2..f4616fc61808 100644
|
||||
--- a/drivers/misc/Kconfig
|
||||
+++ b/drivers/misc/Kconfig
|
||||
@@ -487,6 +487,13 @@ config PVPANIC
|
||||
a paravirtualized device provided by QEMU; it lets a virtual machine
|
||||
(guest) communicate panic events to the host.
|
||||
|
||||
+config UDOO_ARD
|
||||
+ tristate "UDOO-Arduino erase/reset Driver"
|
||||
+ default y
|
||||
+ help
|
||||
+ This driver is used to erase and reset arduino board via command sent
|
||||
+ over USB-to-SERIAL connection.
|
||||
+
|
||||
source "drivers/misc/c2port/Kconfig"
|
||||
source "drivers/misc/eeprom/Kconfig"
|
||||
source "drivers/misc/cb710/Kconfig"
|
||||
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
|
||||
index dcc801e8834e..13e132dd62c9 100644
|
||||
--- a/drivers/misc/Makefile
|
||||
+++ b/drivers/misc/Makefile
|
||||
@@ -54,6 +54,7 @@ obj-y += cape/
|
||||
obj-$(CONFIG_ECHO) += echo/
|
||||
obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
|
||||
obj-$(CONFIG_CXL_BASE) += cxl/
|
||||
+obj-$(CONFIG_UDOO_ARD) += udoo_ard.o
|
||||
obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o
|
||||
obj-$(CONFIG_OCXL) += ocxl/
|
||||
obj-y += cardreader/
|
||||
diff --git a/drivers/misc/udoo_ard.c b/drivers/misc/udoo_ard.c
|
||||
new file mode 100755
|
||||
index 000000000000..2210738e09c0
|
||||
--- /dev/null
|
||||
+++ b/drivers/misc/udoo_ard.c
|
||||
@@ -0,0 +1,417 @@
|
||||
+/*
|
||||
+ * udoo_ard.c
|
||||
+ * UDOO quad/dual Arduino flash erase / CPU resetter
|
||||
+ *
|
||||
+ * Copyright (C) 2013-2015 Aidilab srl
|
||||
+ * Author: UDOO Team <social@udoo.org>
|
||||
+ * Author: Giuseppe Pagano <giuseppe.pagano@seco.com>
|
||||
+ * Author: Francesco Montefoschi <francesco.monte@gmail.com>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it
|
||||
+ * under the terms of the GNU General Public License version 2 as published by
|
||||
+ * the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
+ * more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License along with
|
||||
+ * this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/errno.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/gpio.h>
|
||||
+#include <linux/sched.h>
|
||||
+#include <linux/sched/clock.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/workqueue.h>
|
||||
+#include <linux/fs.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/of_address.h>
|
||||
+#include <linux/of_gpio.h>
|
||||
+#include <linux/of_irq.h>
|
||||
+#include <linux/of_platform.h>
|
||||
+#include <linux/uaccess.h>
|
||||
+
|
||||
+#define DRIVER_NAME "udoo_ard"
|
||||
+#define PINCTRL_DEFAULT "default"
|
||||
+#define AUTH_TOKEN 0x5A5A
|
||||
+#define MAX_MSEC_SINCE_LAST_IRQ 400
|
||||
+#define GRAY_TIME_BETWEEN_RESET 10000 // In this time we can't accept new erase/reset code
|
||||
+
|
||||
+static struct workqueue_struct *erase_reset_wq;
|
||||
+typedef struct {
|
||||
+ struct work_struct erase_reset_work;
|
||||
+ struct pinctrl *pinctrl;
|
||||
+ struct pinctrl_state *pins_default;
|
||||
+ int step;
|
||||
+ int cmdcode;
|
||||
+ int erase_reset_lock;
|
||||
+ int gpio_bossac_clk;
|
||||
+ int gpio_bossac_dat;
|
||||
+ int gpio_ard_erase;
|
||||
+ int gpio_ard_reset;
|
||||
+ unsigned long last_int_time_in_ns;
|
||||
+ unsigned long last_int_time_in_sec;
|
||||
+} erase_reset_work_t;
|
||||
+
|
||||
+erase_reset_work_t *work;
|
||||
+static u32 origTX, origRX; // original UART4 TX/RX pad control registers
|
||||
+static int major; // for /dev/udoo_ard
|
||||
+static struct class *udoo_class;
|
||||
+
|
||||
+static struct platform_device_id udoo_ard_devtype[] = {
|
||||
+ {
|
||||
+ /* keep it for coldfire */
|
||||
+ .name = DRIVER_NAME,
|
||||
+ .driver_data = 0,
|
||||
+ }, {
|
||||
+ /* sentinel */
|
||||
+ }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(platform, udoo_ard_devtype);
|
||||
+
|
||||
+static const struct of_device_id udoo_ard_dt_ids[] = {
|
||||
+ { .compatible = "udoo,imx6q-udoo-ard", .data = &udoo_ard_devtype[0], },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, udoo_ard_dt_ids);
|
||||
+
|
||||
+static void disable_serial(void)
|
||||
+{
|
||||
+ u32 addrTX;
|
||||
+ void __iomem *_addrTX;
|
||||
+
|
||||
+ printk("[bossac] Disable UART4 serial port.\n");
|
||||
+
|
||||
+ addrTX = 0x20E01F8;
|
||||
+ _addrTX = ioremap(addrTX, 8);
|
||||
+
|
||||
+ origTX = __raw_readl(_addrTX);
|
||||
+ origRX = __raw_readl(_addrTX + 0x4);
|
||||
+
|
||||
+ __raw_writel(0x15, _addrTX);
|
||||
+ __raw_writel(0x15, _addrTX + 0x4);
|
||||
+
|
||||
+ iounmap(_addrTX);
|
||||
+}
|
||||
+
|
||||
+static void enable_serial(void)
|
||||
+{
|
||||
+ u32 addrTX;
|
||||
+ void __iomem *_addrTX;
|
||||
+
|
||||
+ printk("[bossac] Enable UART4 serial port.\n");
|
||||
+
|
||||
+ addrTX = 0x20E01F8;
|
||||
+ _addrTX = ioremap(addrTX, 8);
|
||||
+
|
||||
+ __raw_writel(origTX, _addrTX);
|
||||
+ __raw_writel(origRX, _addrTX + 0x4);
|
||||
+
|
||||
+ iounmap(_addrTX);
|
||||
+}
|
||||
+
|
||||
+static void erase_reset(void)
|
||||
+{
|
||||
+ printk("[bossac] UDOO ERASE and RESET on Sam3x started.\n");
|
||||
+
|
||||
+ gpio_direction_input(work->gpio_ard_erase);
|
||||
+ gpio_set_value(work->gpio_ard_reset, 1);
|
||||
+ msleep(1);
|
||||
+
|
||||
+ gpio_direction_output(work->gpio_ard_erase, 1);
|
||||
+ msleep(300);
|
||||
+ gpio_direction_input(work->gpio_ard_erase);
|
||||
+
|
||||
+ msleep(10);
|
||||
+ gpio_set_value(work->gpio_ard_reset, 0);
|
||||
+
|
||||
+ msleep(80);
|
||||
+ gpio_set_value(work->gpio_ard_reset, 1);
|
||||
+
|
||||
+ printk("[bossac] UDOO ERASE and RESET on Sam3x EXECUTED.\n");
|
||||
+}
|
||||
+
|
||||
+static void shutdown_sam3x(void)
|
||||
+{
|
||||
+ printk("[bossac] RESET on Sam3x.\n");
|
||||
+
|
||||
+ gpio_set_value(work->gpio_ard_reset, 0);
|
||||
+}
|
||||
+
|
||||
+static void erase_reset_wq_function( struct work_struct *work2)
|
||||
+{
|
||||
+ disable_serial();
|
||||
+ erase_reset();
|
||||
+ msleep(GRAY_TIME_BETWEEN_RESET);
|
||||
+
|
||||
+ work->erase_reset_lock = 0;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Called everytime the gpio_bossac_clk signal toggles.
|
||||
+ * If the auth token (16 bit) is found, we look for the command code (4 bit).
|
||||
+ * The code 0x0F is sent by Bossac to trigger an erase/reset (to achieve this,
|
||||
+ * erase_reset_wq is scheduled). Before starting to program the flash, we disable
|
||||
+ * the UART4 serial port, otherwise there is too noise on the serial lines (the
|
||||
+ * programming port and UART4 port are connected together, see hw schematics).
|
||||
+ * When Bossac finishes to flash/verify, the code 0x00 is sent which re-enables
|
||||
+ * the UART4 port.
|
||||
+ */
|
||||
+static irqreturn_t udoo_bossac_req(int irq, void *dev_id)
|
||||
+{
|
||||
+ int retval, auth_bit, expected_bit, msec_since_last_irq;
|
||||
+ u64 nowsec;
|
||||
+ unsigned long rem_nsec;
|
||||
+ erase_reset_work_t *erase_reset_work;
|
||||
+
|
||||
+ auth_bit = 0;
|
||||
+ if (gpio_get_value(work->gpio_bossac_dat) != 0x0) {
|
||||
+ auth_bit = 1;
|
||||
+ }
|
||||
+
|
||||
+ erase_reset_work = (erase_reset_work_t *)work;
|
||||
+
|
||||
+ nowsec = local_clock();
|
||||
+ rem_nsec = do_div(nowsec, 1000000000) ;
|
||||
+ msec_since_last_irq = (((unsigned long)nowsec * 1000) + rem_nsec/1000000 ) - (((unsigned long)erase_reset_work->last_int_time_in_sec * 1000) + erase_reset_work->last_int_time_in_ns/1000000);
|
||||
+
|
||||
+ if (msec_since_last_irq > MAX_MSEC_SINCE_LAST_IRQ) {
|
||||
+ erase_reset_work->step = 0;
|
||||
+#ifdef DEBUG
|
||||
+ printk("[bossac] Reset authentication timeout!\n");
|
||||
+#endif
|
||||
+ }
|
||||
+
|
||||
+#ifdef DEBUG
|
||||
+ printk("[bossac] STEP %d -> 0x%d \n", erase_reset_work->step, auth_bit);
|
||||
+#endif
|
||||
+ erase_reset_work->last_int_time_in_ns = rem_nsec;
|
||||
+ erase_reset_work->last_int_time_in_sec = nowsec;
|
||||
+
|
||||
+ if ( erase_reset_work->step < 16 ) { // Authenticating received token bit.
|
||||
+ expected_bit = (( AUTH_TOKEN >> erase_reset_work->step ) & 0x01 );
|
||||
+ if ( auth_bit == expected_bit ) {
|
||||
+ erase_reset_work->step = erase_reset_work->step + 1;
|
||||
+ } else {
|
||||
+ erase_reset_work->step = 0;
|
||||
+ }
|
||||
+ } else { // Passed all authentication step. Receiving command code.
|
||||
+ erase_reset_work->cmdcode = erase_reset_work->cmdcode | (auth_bit << (erase_reset_work->step - 16));
|
||||
+ erase_reset_work->step = erase_reset_work->step + 1;
|
||||
+ }
|
||||
+
|
||||
+#ifdef DEBUG
|
||||
+ printk("erase_reset_work->erase_reset_lock = %d \n", erase_reset_work->erase_reset_lock);
|
||||
+#endif
|
||||
+ if ( erase_reset_work->step == 20 ) { // Passed authentication and code acquiring step.
|
||||
+#ifdef DEBUG
|
||||
+ printk("[bossac] Received code = 0x%04x \n", erase_reset_work->cmdcode);
|
||||
+#endif
|
||||
+ if (erase_reset_work->cmdcode == 0xF) {
|
||||
+ if (erase_reset_work->erase_reset_lock == 0) {
|
||||
+ erase_reset_work->erase_reset_lock = 1;
|
||||
+ retval = queue_work( erase_reset_wq, (struct work_struct *)work );
|
||||
+ } else {
|
||||
+#ifdef DEBUG
|
||||
+ printk("Erase and reset operation already in progress. Do nothing.\n");
|
||||
+#endif
|
||||
+ }
|
||||
+ } else {
|
||||
+ enable_serial();
|
||||
+ }
|
||||
+ erase_reset_work->step = 0;
|
||||
+ erase_reset_work->cmdcode = 0;
|
||||
+ }
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Takes control of clock, data, erase, reset GPIOs.
|
||||
+ */
|
||||
+static int gpio_setup(void)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = gpio_request(work->gpio_bossac_clk, "BOSSA_CLK");
|
||||
+ if (ret) {
|
||||
+ printk(KERN_ERR "request BOSSA_CLK IRQ\n");
|
||||
+ return -1;
|
||||
+ } else {
|
||||
+ gpio_direction_input(work->gpio_bossac_clk);
|
||||
+ }
|
||||
+
|
||||
+ ret = gpio_request(work->gpio_bossac_dat, "BOSSA_DAT");
|
||||
+ if (ret) {
|
||||
+ printk(KERN_ERR "request BOSSA_DAT IRQ\n");
|
||||
+ return -1;
|
||||
+ } else {
|
||||
+ gpio_direction_input(work->gpio_bossac_dat);
|
||||
+ }
|
||||
+
|
||||
+ ret = gpio_request(work->gpio_ard_erase, "BOSSAC");
|
||||
+ if (ret) {
|
||||
+ printk(KERN_ERR "request GPIO FOR ARDUINO ERASE\n");
|
||||
+ return -1;
|
||||
+ } else {
|
||||
+ gpio_direction_input(work->gpio_ard_erase);
|
||||
+ }
|
||||
+
|
||||
+ ret = gpio_request(work->gpio_ard_reset, "BOSSAC");
|
||||
+ if (ret) {
|
||||
+ printk(KERN_ERR "request GPIO FOR ARDUINO RESET\n");
|
||||
+ return -1;
|
||||
+ } else {
|
||||
+ gpio_direction_output(work->gpio_ard_reset, 1);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static ssize_t device_write(struct file *filp, const char *buff, size_t len, loff_t *off)
|
||||
+{
|
||||
+ char msg[10];
|
||||
+ long res;
|
||||
+
|
||||
+ if (len > 10)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+
|
||||
+ res = copy_from_user(msg, buff, len);
|
||||
+ if (res) {
|
||||
+ return -EFAULT;
|
||||
+ }
|
||||
+ msg[len] = '\0';
|
||||
+
|
||||
+ if (strcmp(msg, "erase")==0) {
|
||||
+ erase_reset();
|
||||
+ } else if (strcmp(msg, "shutdown")==0) {
|
||||
+ shutdown_sam3x();
|
||||
+ } else if (strcmp(msg, "uartoff")==0) {
|
||||
+ disable_serial();
|
||||
+ } else if (strcmp(msg, "uarton")==0) {
|
||||
+ enable_serial();
|
||||
+ } else {
|
||||
+ printk("[bossac] udoo_ard invalid operation! %s", msg);
|
||||
+ }
|
||||
+
|
||||
+ return len;
|
||||
+}
|
||||
+
|
||||
+static struct file_operations fops = {
|
||||
+ .write = device_write,
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * If a fdt udoo_ard entry is found, we register an IRQ on bossac clock line
|
||||
+ * and we create /dev/udoo_ard
|
||||
+ */
|
||||
+static int udoo_ard_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int retval;
|
||||
+ struct device *temp_class;
|
||||
+ struct platform_device *bdev;
|
||||
+ struct device_node *np;
|
||||
+
|
||||
+ bdev = kzalloc(sizeof(*bdev), GFP_KERNEL);
|
||||
+ np = pdev->dev.of_node;
|
||||
+
|
||||
+ if (!np)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ work = (erase_reset_work_t *)kmalloc(sizeof(erase_reset_work_t), GFP_KERNEL);
|
||||
+ if (work) {
|
||||
+ work->gpio_ard_reset = of_get_named_gpio(np, "bossac-reset-gpio", 0);
|
||||
+ work->gpio_ard_erase = of_get_named_gpio(np, "bossac-erase-gpio", 0);
|
||||
+ work->gpio_bossac_clk = of_get_named_gpio(np, "bossac-clk-gpio", 0);
|
||||
+ work->gpio_bossac_dat = of_get_named_gpio(np, "bossac-dat-gpio", 0);
|
||||
+ work->pinctrl = devm_pinctrl_get(&pdev->dev);
|
||||
+ work->pins_default = pinctrl_lookup_state(work->pinctrl, PINCTRL_DEFAULT);
|
||||
+ } else {
|
||||
+ printk("[bossac] Failed to allocate data structure.");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ pinctrl_select_state(work->pinctrl, work->pins_default);
|
||||
+ gpio_setup();
|
||||
+
|
||||
+ printk("[bossac] Registering IRQ %d for BOSSAC Arduino erase/reset operation\n", gpio_to_irq(work->gpio_bossac_clk));
|
||||
+ retval = request_irq(gpio_to_irq(work->gpio_bossac_clk), udoo_bossac_req, IRQF_TRIGGER_FALLING, "UDOO", bdev);
|
||||
+
|
||||
+ major = register_chrdev(major, "udoo_ard", &fops);
|
||||
+ if (major < 0) {
|
||||
+ printk(KERN_ERR "[bossac] Cannot get major for UDOO Ard\n");
|
||||
+ return -EBUSY;
|
||||
+ }
|
||||
+
|
||||
+ udoo_class = class_create(THIS_MODULE, "udoo_ard");
|
||||
+ if (IS_ERR(udoo_class)) {
|
||||
+ return PTR_ERR(udoo_class);
|
||||
+ }
|
||||
+
|
||||
+ temp_class = device_create(udoo_class, NULL, MKDEV(major, 0), NULL, "udoo_ard");
|
||||
+ if (IS_ERR(temp_class)) {
|
||||
+ return PTR_ERR(temp_class);
|
||||
+ }
|
||||
+
|
||||
+ printk("[bossac] Created device file /dev/udoo_ard\n");
|
||||
+
|
||||
+ erase_reset_wq = create_workqueue("erase_reset_queue");
|
||||
+ if (erase_reset_wq) {
|
||||
+
|
||||
+ /* Queue some work (item 1) */
|
||||
+ if (work) {
|
||||
+ INIT_WORK( (struct work_struct *)work, erase_reset_wq_function );
|
||||
+ work->step = 1;
|
||||
+ work->cmdcode = 0;
|
||||
+ work->last_int_time_in_ns = 0;
|
||||
+ work->last_int_time_in_sec = 0;
|
||||
+ work->erase_reset_lock = 0;
|
||||
+ // retval = queue_work( erase_reset_wq, (struct work_struct *)work );
|
||||
+ }
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int udoo_ard_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ printk("[bossac] Unloading UDOO ard driver.\n");
|
||||
+ free_irq(gpio_to_irq(work->gpio_bossac_clk), NULL);
|
||||
+
|
||||
+ gpio_free(work->gpio_ard_reset);
|
||||
+ gpio_free(work->gpio_ard_erase);
|
||||
+ gpio_free(work->gpio_bossac_clk);
|
||||
+ gpio_free(work->gpio_bossac_dat);
|
||||
+
|
||||
+ device_destroy(udoo_class, MKDEV(major, 0));
|
||||
+ class_destroy(udoo_class);
|
||||
+ unregister_chrdev(major, "udoo_ard");
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver udoo_ard_driver = {
|
||||
+ .driver = {
|
||||
+ .name = DRIVER_NAME,
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = udoo_ard_dt_ids,
|
||||
+ },
|
||||
+ .id_table = udoo_ard_devtype,
|
||||
+ .probe = udoo_ard_probe,
|
||||
+ .remove = udoo_ard_remove,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(udoo_ard_driver);
|
||||
+
|
||||
+MODULE_ALIAS("platform:"DRIVER_NAME);
|
||||
+MODULE_LICENSE("GPL");
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,11 +0,0 @@
|
||||
--- ./arch/arm/mm/cache-feroceon-l2.c.orig 2013-04-26 13:18:32.000000000 -0600
|
||||
+++ ./arch/arm/mm/cache-feroceon-l2.c 2013-04-28 04:01:09.815592333 -0600
|
||||
@@ -117,7 +117,7 @@ static inline void l2_inv_pa_range(unsig
|
||||
l2_put_va(va_start);
|
||||
}
|
||||
|
||||
-static inline void l2_inv_all(void)
|
||||
+static void l2_inv_all(void)
|
||||
{
|
||||
__asm__("mcr p15, 1, %0, c15, c11, 0" : : "r" (0));
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
--- ./arch/arm/boot/dts/imx6qdl-hummingboard.dtsi.orig 2015-01-08 11:30:41.000000000 -0700
|
||||
+++ ./arch/arm/boot/dts/imx6qdl-hummingboard.dtsi 2015-01-13 14:19:29.696485445 -0700
|
||||
@@ -94,6 +94,31 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
+&i2c3 {
|
||||
+ clock-frequency = <100000>;
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&pinctrl_hummingboard_i2c3>;
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&ecspi2 {
|
||||
+ fsl,spi-num-chipselects = <2>;
|
||||
+ cs-gpios = <&gpio2 26 1>, <&gpio2 27 1>;
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&pinctrl_hummingboard_spi>;
|
||||
+ status = "okay";
|
||||
+ spidev@0x00 {
|
||||
+ compatible = "spidev";
|
||||
+ spi-max-frequency = <5000000>;
|
||||
+ reg = <0>;
|
||||
+ };
|
||||
+ spidev@0x01 {
|
||||
+ compatible = "spidev";
|
||||
+ spi-max-frequency = <5000000>;
|
||||
+ reg = <1>;
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
&iomuxc {
|
||||
hummingboard {
|
||||
pinctrl_hummingboard_flexcan1: hummingboard-flexcan1 {
|
||||
@@ -103,6 +128,17 @@
|
||||
>;
|
||||
};
|
||||
|
||||
+ pinctrl_hummingboard_spi: hummingboard_spi {
|
||||
+ fsl,pins = <
|
||||
+ MX6QDL_PAD_EIM_OE__ECSPI2_MISO 0x100b1
|
||||
+ MX6QDL_PAD_EIM_CS1__ECSPI2_MOSI 0x100b1
|
||||
+ MX6QDL_PAD_EIM_CS0__ECSPI2_SCLK 0x100b1
|
||||
+ /* MX6QDL_PAD_EIM_RW__ECSPI2_SS0 0x100b1 */
|
||||
+ MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x100b1
|
||||
+ MX6QDL_PAD_EIM_LBA__ECSPI2_SS1 0x100b1
|
||||
+ >;
|
||||
+ };
|
||||
+
|
||||
pinctrl_hummingboard_gpio3_5: hummingboard-gpio3_5 {
|
||||
fsl,pins = <
|
||||
MX6QDL_PAD_EIM_DA5__GPIO3_IO05 0x1b0b1
|
||||
@@ -129,6 +165,13 @@
|
||||
>;
|
||||
};
|
||||
|
||||
+ pinctrl_hummingboard_i2c3: hummingboard-i2c3 {
|
||||
+ fsl,pins = <
|
||||
+ MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1
|
||||
+ MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1
|
||||
+ >;
|
||||
+ };
|
||||
+
|
||||
pinctrl_hummingboard_spdif: hummingboard-spdif {
|
||||
fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x13091>;
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
--- ./fs/timerfd.c.orig 2015-11-09 15:37:56.000000000 -0700
|
||||
+++ ./fs/timerfd.c 2015-11-14 08:20:51.720068530 -0700
|
||||
@@ -134,7 +134,7 @@ static void timerfd_setup_cancel(struct
|
||||
{
|
||||
if ((ctx->clockid == CLOCK_REALTIME ||
|
||||
ctx->clockid == CLOCK_REALTIME_ALARM) &&
|
||||
- (flags & TFD_TIMER_ABSTIME) && (flags & TFD_TIMER_CANCEL_ON_SET)) {
|
||||
+ (flags & TFD_TIMER_CANCEL_ON_SET)) {
|
||||
if (!ctx->might_cancel) {
|
||||
ctx->might_cancel = true;
|
||||
spin_lock(&cancel_lock);
|
@ -1,73 +0,0 @@
|
||||
From f5528e96b7dd2b30e1accc518df85d14baad6bae Mon Sep 17 00:00:00 2001
|
||||
From: Peter Chen <peter.chen@nxp.com>
|
||||
Date: Thu, 18 May 2017 08:48:57 +0800
|
||||
Subject: [PATCH 1/9] binding-doc: power: pwrseq-generic: add binding doc for
|
||||
generic power sequence library
|
||||
|
||||
Add binding doc for generic power sequence library.
|
||||
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
|
||||
Acked-by: Rob Herring <robh@kernel.org>
|
||||
---
|
||||
.../bindings/power/pwrseq/pwrseq-generic.txt | 48 +++++++++++++++++++
|
||||
1 file changed, 48 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt b/Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt
|
||||
new file mode 100644
|
||||
index 000000000000..ebf0d477b688
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt
|
||||
@@ -0,0 +1,48 @@
|
||||
+The generic power sequence library
|
||||
+
|
||||
+Some hard-wired devices (eg USB/MMC) need to do power sequence before
|
||||
+the device can be enumerated on the bus, the typical power sequence
|
||||
+like: enable USB PHY clock, toggle reset pin, etc. But current
|
||||
+Linux device driver lacks of such code to do it, it may cause some
|
||||
+hard-wired devices works abnormal or can't be recognized by
|
||||
+controller at all. The power sequence will be done before this device
|
||||
+can be found at the bus.
|
||||
+
|
||||
+The power sequence properties is under the device node.
|
||||
+
|
||||
+Optional properties:
|
||||
+- clocks: the input clocks for device.
|
||||
+- reset-gpios: Should specify the GPIO for reset.
|
||||
+- reset-duration-us: the duration in microsecond for assert reset signal.
|
||||
+
|
||||
+Below is the example of USB power sequence properties on USB device
|
||||
+nodes which have two level USB hubs.
|
||||
+
|
||||
+&usbotg1 {
|
||||
+ vbus-supply = <®_usb_otg1_vbus>;
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&pinctrl_usb_otg1_id>;
|
||||
+ status = "okay";
|
||||
+
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+ genesys: hub@1 {
|
||||
+ compatible = "usb5e3,608";
|
||||
+ reg = <1>;
|
||||
+
|
||||
+ clocks = <&clks IMX6SX_CLK_CKO>;
|
||||
+ reset-gpios = <&gpio4 5 GPIO_ACTIVE_LOW>; /* hub reset pin */
|
||||
+ reset-duration-us = <10>;
|
||||
+
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+ asix: ethernet@1 {
|
||||
+ compatible = "usbb95,1708";
|
||||
+ reg = <1>;
|
||||
+
|
||||
+ clocks = <&clks IMX6SX_CLK_IPG>;
|
||||
+ reset-gpios = <&gpio4 6 GPIO_ACTIVE_LOW>; /* ethernet_rst */
|
||||
+ reset-duration-us = <15>;
|
||||
+ };
|
||||
+ };
|
||||
+};
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,853 +0,0 @@
|
||||
From e42fbf22376c41b275d47b9cfac360c66ee718dc Mon Sep 17 00:00:00 2001
|
||||
From: Peter Chen <peter.chen@nxp.com>
|
||||
Date: Thu, 18 May 2017 08:48:58 +0800
|
||||
Subject: [PATCH 2/9] power: add power sequence library
|
||||
|
||||
We have an well-known problem that the device needs to do some power
|
||||
sequence before it can be recognized by related host, the typical
|
||||
example like hard-wired mmc devices and usb devices.
|
||||
|
||||
This power sequence is hard to be described at device tree and handled by
|
||||
related host driver, so we have created a common power sequence
|
||||
library to cover this requirement. The core code has supplied
|
||||
some common helpers for host driver, and individual power sequence
|
||||
libraries handle kinds of power sequence for devices. The pwrseq
|
||||
librares always need to allocate extra instance for compatible
|
||||
string match.
|
||||
|
||||
pwrseq_generic is intended for general purpose of power sequence, which
|
||||
handles gpios and clocks currently, and can cover other controls in
|
||||
future. The host driver just needs to call of_pwrseq_on/of_pwrseq_off
|
||||
if only one power sequence is needed, else call of_pwrseq_on_list
|
||||
/of_pwrseq_off_list instead (eg, USB hub driver).
|
||||
|
||||
For new power sequence library, it can add its compatible string
|
||||
to pwrseq_of_match_table, then the pwrseq core will match it with
|
||||
DT's, and choose this library at runtime.
|
||||
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
Tested-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
|
||||
Tested-by Joshua Clayton <stillcompiling@gmail.com>
|
||||
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
|
||||
Tested-by: Matthias Kaehlcke <mka@chromium.org>
|
||||
---
|
||||
Documentation/power/power-sequence/design.rst | 54 +++
|
||||
MAINTAINERS | 9 +
|
||||
drivers/power/Kconfig | 1 +
|
||||
drivers/power/Makefile | 1 +
|
||||
drivers/power/pwrseq/Kconfig | 20 ++
|
||||
drivers/power/pwrseq/Makefile | 2 +
|
||||
drivers/power/pwrseq/core.c | 335 ++++++++++++++++++
|
||||
drivers/power/pwrseq/pwrseq_generic.c | 234 ++++++++++++
|
||||
include/linux/power/pwrseq.h | 81 +++++
|
||||
9 files changed, 737 insertions(+)
|
||||
create mode 100644 Documentation/power/power-sequence/design.rst
|
||||
create mode 100644 drivers/power/pwrseq/Kconfig
|
||||
create mode 100644 drivers/power/pwrseq/Makefile
|
||||
create mode 100644 drivers/power/pwrseq/core.c
|
||||
create mode 100644 drivers/power/pwrseq/pwrseq_generic.c
|
||||
create mode 100644 include/linux/power/pwrseq.h
|
||||
|
||||
diff --git a/Documentation/power/power-sequence/design.rst b/Documentation/power/power-sequence/design.rst
|
||||
new file mode 100644
|
||||
index 000000000000..554608e5f3b6
|
||||
--- /dev/null
|
||||
+++ b/Documentation/power/power-sequence/design.rst
|
||||
@@ -0,0 +1,54 @@
|
||||
+====================================
|
||||
+Power Sequence Library
|
||||
+====================================
|
||||
+
|
||||
+:Date: Feb, 2017
|
||||
+:Author: Peter Chen <peter.chen@nxp.com>
|
||||
+
|
||||
+
|
||||
+Introduction
|
||||
+============
|
||||
+
|
||||
+We have an well-known problem that the device needs to do a power
|
||||
+sequence before it can be recognized by related host, the typical
|
||||
+examples are hard-wired mmc devices and usb devices. The host controller
|
||||
+can't know what kinds of this device is in its bus if the power
|
||||
+sequence has not done, since the related devices driver's probe calling
|
||||
+is determined by runtime according to eunumeration results. Besides,
|
||||
+the devices may have custom power sequence, so the power sequence library
|
||||
+which is independent with the devices is needed.
|
||||
+
|
||||
+Design
|
||||
+============
|
||||
+
|
||||
+The power sequence library includes the core file and customer power
|
||||
+sequence library. The core file exports interfaces are called by
|
||||
+host controller driver for power sequence and customer power sequence
|
||||
+library files to register its power sequence instance to global
|
||||
+power sequence list. The custom power sequence library creates power
|
||||
+sequence instance and implement custom power sequence.
|
||||
+
|
||||
+Since the power sequence describes hardware design, the description is
|
||||
+located at board description file, eg, device tree dts file. And
|
||||
+a specific power sequence belongs to device, so its description
|
||||
+is under the device node, please refer to:
|
||||
+Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt
|
||||
+
|
||||
+Custom power sequence library allocates one power sequence instance at
|
||||
+bootup periods using postcore_initcall, this static allocated instance is
|
||||
+used to compare with device-tree (DT) node to see if this library can be
|
||||
+used for the node or not. When the result is matched, the core API will
|
||||
+try to get resourses (->get, implemented at each library) for power
|
||||
+sequence, if all resources are got, it will try to allocate another
|
||||
+instance for next possible request from host driver.
|
||||
+
|
||||
+Then, the host controller driver can carry out power sequence on for this
|
||||
+DT node, the library will do corresponding operations, like open clocks,
|
||||
+toggle gpio, etc. The power sequence off routine will close and free the
|
||||
+resources, and is called when the parent is removed. And the power
|
||||
+sequence suspend and resume routine can be called at host driver's
|
||||
+suspend and resume routine if needed.
|
||||
+
|
||||
+The exported interfaces
|
||||
+.. kernel-doc:: drivers/power/pwrseq/core.c
|
||||
+ :export:
|
||||
diff --git a/MAINTAINERS b/MAINTAINERS
|
||||
index 429c6c624861..88fd31d1870f 100644
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -12599,6 +12599,15 @@ F: drivers/firmware/psci/
|
||||
F: include/linux/psci.h
|
||||
F: include/uapi/linux/psci.h
|
||||
|
||||
+POWER SEQUENCE LIBRARY
|
||||
+M: Peter Chen <Peter.Chen@nxp.com>
|
||||
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git
|
||||
+L: linux-pm@vger.kernel.org
|
||||
+S: Maintained
|
||||
+F: Documentation/devicetree/bindings/power/pwrseq/
|
||||
+F: drivers/power/pwrseq/
|
||||
+F: include/linux/power/pwrseq.h
|
||||
+
|
||||
POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS
|
||||
M: Sebastian Reichel <sre@kernel.org>
|
||||
L: linux-pm@vger.kernel.org
|
||||
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
|
||||
index ff0350ca3b74..78b6fa270cf9 100644
|
||||
--- a/drivers/power/Kconfig
|
||||
+++ b/drivers/power/Kconfig
|
||||
@@ -2,3 +2,4 @@
|
||||
source "drivers/power/avs/Kconfig"
|
||||
source "drivers/power/reset/Kconfig"
|
||||
source "drivers/power/supply/Kconfig"
|
||||
+source "drivers/power/pwrseq/Kconfig"
|
||||
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
|
||||
index b7c2e372186b..13046c7fb499 100644
|
||||
--- a/drivers/power/Makefile
|
||||
+++ b/drivers/power/Makefile
|
||||
@@ -2,3 +2,4 @@
|
||||
obj-$(CONFIG_POWER_AVS) += avs/
|
||||
obj-$(CONFIG_POWER_RESET) += reset/
|
||||
obj-$(CONFIG_POWER_SUPPLY) += supply/
|
||||
+obj-$(CONFIG_POWER_SEQUENCE) += pwrseq/
|
||||
diff --git a/drivers/power/pwrseq/Kconfig b/drivers/power/pwrseq/Kconfig
|
||||
new file mode 100644
|
||||
index 000000000000..c6b356926cca
|
||||
--- /dev/null
|
||||
+++ b/drivers/power/pwrseq/Kconfig
|
||||
@@ -0,0 +1,20 @@
|
||||
+#
|
||||
+# Power Sequence library
|
||||
+#
|
||||
+
|
||||
+menuconfig POWER_SEQUENCE
|
||||
+ bool "Power sequence control"
|
||||
+ help
|
||||
+ It is used for drivers which needs to do power sequence
|
||||
+ (eg, turn on clock, toggle reset gpio) before the related
|
||||
+ devices can be found by hardware, eg, USB bus.
|
||||
+
|
||||
+if POWER_SEQUENCE
|
||||
+
|
||||
+config PWRSEQ_GENERIC
|
||||
+ bool "Generic power sequence control"
|
||||
+ depends on OF
|
||||
+ help
|
||||
+ This is the generic power sequence control library, and is
|
||||
+ supposed to support common power sequence usage.
|
||||
+endif
|
||||
diff --git a/drivers/power/pwrseq/Makefile b/drivers/power/pwrseq/Makefile
|
||||
new file mode 100644
|
||||
index 000000000000..ad82389028c2
|
||||
--- /dev/null
|
||||
+++ b/drivers/power/pwrseq/Makefile
|
||||
@@ -0,0 +1,2 @@
|
||||
+obj-$(CONFIG_POWER_SEQUENCE) += core.o
|
||||
+obj-$(CONFIG_PWRSEQ_GENERIC) += pwrseq_generic.o
|
||||
diff --git a/drivers/power/pwrseq/core.c b/drivers/power/pwrseq/core.c
|
||||
new file mode 100644
|
||||
index 000000000000..3d19e62a2e76
|
||||
--- /dev/null
|
||||
+++ b/drivers/power/pwrseq/core.c
|
||||
@@ -0,0 +1,335 @@
|
||||
+/*
|
||||
+ * core.c power sequence core file
|
||||
+ *
|
||||
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
|
||||
+ * Author: Peter Chen <peter.chen@nxp.com>
|
||||
+ *
|
||||
+ * This program is free software: you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 of
|
||||
+ * the License as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/list.h>
|
||||
+#include <linux/mutex.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/power/pwrseq.h>
|
||||
+
|
||||
+static DEFINE_MUTEX(pwrseq_list_mutex);
|
||||
+static LIST_HEAD(pwrseq_list);
|
||||
+
|
||||
+static int pwrseq_get(struct device_node *np, struct pwrseq *p)
|
||||
+{
|
||||
+ if (p && p->get)
|
||||
+ return p->get(np, p);
|
||||
+
|
||||
+ return -ENOTSUPP;
|
||||
+}
|
||||
+
|
||||
+static int pwrseq_on(struct pwrseq *p)
|
||||
+{
|
||||
+ if (p && p->on)
|
||||
+ return p->on(p);
|
||||
+
|
||||
+ return -ENOTSUPP;
|
||||
+}
|
||||
+
|
||||
+static void pwrseq_off(struct pwrseq *p)
|
||||
+{
|
||||
+ if (p && p->off)
|
||||
+ p->off(p);
|
||||
+}
|
||||
+
|
||||
+static void pwrseq_put(struct pwrseq *p)
|
||||
+{
|
||||
+ if (p && p->put)
|
||||
+ p->put(p);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_register - Add pwrseq instance to global pwrseq list
|
||||
+ *
|
||||
+ * @pwrseq: the pwrseq instance
|
||||
+ */
|
||||
+void pwrseq_register(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ mutex_lock(&pwrseq_list_mutex);
|
||||
+ list_add(&pwrseq->node, &pwrseq_list);
|
||||
+ mutex_unlock(&pwrseq_list_mutex);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_register);
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_unregister - Remove pwrseq instance from global pwrseq list
|
||||
+ *
|
||||
+ * @pwrseq: the pwrseq instance
|
||||
+ */
|
||||
+void pwrseq_unregister(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ mutex_lock(&pwrseq_list_mutex);
|
||||
+ list_del(&pwrseq->node);
|
||||
+ mutex_unlock(&pwrseq_list_mutex);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_unregister);
|
||||
+
|
||||
+static struct pwrseq *pwrseq_find_available_instance(struct device_node *np)
|
||||
+{
|
||||
+ struct pwrseq *pwrseq;
|
||||
+
|
||||
+ mutex_lock(&pwrseq_list_mutex);
|
||||
+ list_for_each_entry(pwrseq, &pwrseq_list, node) {
|
||||
+ if (pwrseq->used)
|
||||
+ continue;
|
||||
+
|
||||
+ /* compare compatible string for pwrseq node */
|
||||
+ if (of_match_node(pwrseq->pwrseq_of_match_table, np)) {
|
||||
+ pwrseq->used = true;
|
||||
+ mutex_unlock(&pwrseq_list_mutex);
|
||||
+ return pwrseq;
|
||||
+ }
|
||||
+
|
||||
+ /* return generic pwrseq instance */
|
||||
+ if (!strcmp(pwrseq->pwrseq_of_match_table->compatible,
|
||||
+ "generic")) {
|
||||
+ pr_debug("using generic pwrseq instance for %s\n",
|
||||
+ np->full_name);
|
||||
+ pwrseq->used = true;
|
||||
+ mutex_unlock(&pwrseq_list_mutex);
|
||||
+ return pwrseq;
|
||||
+ }
|
||||
+ }
|
||||
+ mutex_unlock(&pwrseq_list_mutex);
|
||||
+ pr_debug("Can't find any pwrseq instances for %s\n", np->full_name);
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * of_pwrseq_on - Carry out power sequence on for device node
|
||||
+ *
|
||||
+ * @np: the device node would like to power on
|
||||
+ *
|
||||
+ * Carry out a single device power on. If multiple devices
|
||||
+ * need to be handled, use of_pwrseq_on_list() instead.
|
||||
+ *
|
||||
+ * Return a pointer to the power sequence instance on success,
|
||||
+ * or an error code otherwise.
|
||||
+ */
|
||||
+struct pwrseq *of_pwrseq_on(struct device_node *np)
|
||||
+{
|
||||
+ struct pwrseq *pwrseq;
|
||||
+ int ret;
|
||||
+
|
||||
+ pwrseq = pwrseq_find_available_instance(np);
|
||||
+ if (!pwrseq)
|
||||
+ return ERR_PTR(-ENOENT);
|
||||
+
|
||||
+ ret = pwrseq_get(np, pwrseq);
|
||||
+ if (ret) {
|
||||
+ /* Mark current pwrseq as unused */
|
||||
+ pwrseq->used = false;
|
||||
+ return ERR_PTR(ret);
|
||||
+ }
|
||||
+
|
||||
+ ret = pwrseq_on(pwrseq);
|
||||
+ if (ret)
|
||||
+ goto pwr_put;
|
||||
+
|
||||
+ return pwrseq;
|
||||
+
|
||||
+pwr_put:
|
||||
+ pwrseq_put(pwrseq);
|
||||
+ return ERR_PTR(ret);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(of_pwrseq_on);
|
||||
+
|
||||
+/**
|
||||
+ * of_pwrseq_off - Carry out power sequence off for this pwrseq instance
|
||||
+ *
|
||||
+ * @pwrseq: the pwrseq instance which related device would like to be off
|
||||
+ *
|
||||
+ * This API is used to power off single device, it is the opposite
|
||||
+ * operation for of_pwrseq_on.
|
||||
+ */
|
||||
+void of_pwrseq_off(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ pwrseq_off(pwrseq);
|
||||
+ pwrseq_put(pwrseq);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(of_pwrseq_off);
|
||||
+
|
||||
+/**
|
||||
+ * of_pwrseq_on_list - Carry out power sequence on for list
|
||||
+ *
|
||||
+ * @np: the device node would like to power on
|
||||
+ * @head: the list head for pwrseq list on this bus
|
||||
+ *
|
||||
+ * This API is used to power on multiple devices at single bus.
|
||||
+ * If there are several devices on bus (eg, USB bus), uses this
|
||||
+ * this API. Otherwise, use of_pwrseq_on instead. After the device
|
||||
+ * is powered on successfully, it will be added to pwrseq list for
|
||||
+ * this bus. The caller needs to use mutex_lock for concurrent.
|
||||
+ *
|
||||
+ * Return 0 on success, or an error value otherwise.
|
||||
+ */
|
||||
+int of_pwrseq_on_list(struct device_node *np, struct list_head *head)
|
||||
+{
|
||||
+ struct pwrseq *pwrseq;
|
||||
+ struct pwrseq_list_per_dev *pwrseq_list_node;
|
||||
+
|
||||
+ pwrseq_list_node = kzalloc(sizeof(*pwrseq_list_node), GFP_KERNEL);
|
||||
+ if (!pwrseq_list_node)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ pwrseq = of_pwrseq_on(np);
|
||||
+ if (IS_ERR(pwrseq)) {
|
||||
+ kfree(pwrseq_list_node);
|
||||
+ return PTR_ERR(pwrseq);
|
||||
+ }
|
||||
+
|
||||
+ pwrseq_list_node->pwrseq = pwrseq;
|
||||
+ list_add(&pwrseq_list_node->list, head);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(of_pwrseq_on_list);
|
||||
+
|
||||
+/**
|
||||
+ * of_pwrseq_off_list - Carry out power sequence off for the list
|
||||
+ *
|
||||
+ * @head: the list head for pwrseq instance list on this bus
|
||||
+ *
|
||||
+ * This API is used to power off all devices on this bus, it is
|
||||
+ * the opposite operation for of_pwrseq_on_list.
|
||||
+ * The caller needs to use mutex_lock for concurrent.
|
||||
+ */
|
||||
+void of_pwrseq_off_list(struct list_head *head)
|
||||
+{
|
||||
+ struct pwrseq *pwrseq;
|
||||
+ struct pwrseq_list_per_dev *pwrseq_list_node, *tmp_node;
|
||||
+
|
||||
+ list_for_each_entry_safe(pwrseq_list_node, tmp_node, head, list) {
|
||||
+ pwrseq = pwrseq_list_node->pwrseq;
|
||||
+ of_pwrseq_off(pwrseq);
|
||||
+ list_del(&pwrseq_list_node->list);
|
||||
+ kfree(pwrseq_list_node);
|
||||
+ }
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(of_pwrseq_off_list);
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_suspend - Carry out power sequence suspend for this pwrseq instance
|
||||
+ *
|
||||
+ * @pwrseq: the pwrseq instance
|
||||
+ *
|
||||
+ * This API is used to do suspend operation on pwrseq instance.
|
||||
+ *
|
||||
+ * Return 0 on success, or an error value otherwise.
|
||||
+ */
|
||||
+int pwrseq_suspend(struct pwrseq *p)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ if (p && p->suspend)
|
||||
+ ret = p->suspend(p);
|
||||
+ else
|
||||
+ return ret;
|
||||
+
|
||||
+ if (!ret)
|
||||
+ p->suspended = true;
|
||||
+ else
|
||||
+ pr_err("%s failed\n", __func__);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_suspend);
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_resume - Carry out power sequence resume for this pwrseq instance
|
||||
+ *
|
||||
+ * @pwrseq: the pwrseq instance
|
||||
+ *
|
||||
+ * This API is used to do resume operation on pwrseq instance.
|
||||
+ *
|
||||
+ * Return 0 on success, or an error value otherwise.
|
||||
+ */
|
||||
+int pwrseq_resume(struct pwrseq *p)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ if (p && p->resume)
|
||||
+ ret = p->resume(p);
|
||||
+ else
|
||||
+ return ret;
|
||||
+
|
||||
+ if (!ret)
|
||||
+ p->suspended = false;
|
||||
+ else
|
||||
+ pr_err("%s failed\n", __func__);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_resume);
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_suspend_list - Carry out power sequence suspend for list
|
||||
+ *
|
||||
+ * @head: the list head for pwrseq instance list on this bus
|
||||
+ *
|
||||
+ * This API is used to do suspend on all power sequence instances on this bus.
|
||||
+ * The caller needs to use mutex_lock for concurrent.
|
||||
+ */
|
||||
+int pwrseq_suspend_list(struct list_head *head)
|
||||
+{
|
||||
+ struct pwrseq *pwrseq;
|
||||
+ struct pwrseq_list_per_dev *pwrseq_list_node;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ list_for_each_entry(pwrseq_list_node, head, list) {
|
||||
+ ret = pwrseq_suspend(pwrseq_list_node->pwrseq);
|
||||
+ if (ret)
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (ret) {
|
||||
+ list_for_each_entry(pwrseq_list_node, head, list) {
|
||||
+ pwrseq = pwrseq_list_node->pwrseq;
|
||||
+ if (pwrseq->suspended)
|
||||
+ pwrseq_resume(pwrseq);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_suspend_list);
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_resume_list - Carry out power sequence resume for the list
|
||||
+ *
|
||||
+ * @head: the list head for pwrseq instance list on this bus
|
||||
+ *
|
||||
+ * This API is used to do resume on all power sequence instances on this bus.
|
||||
+ * The caller needs to use mutex_lock for concurrent.
|
||||
+ */
|
||||
+int pwrseq_resume_list(struct list_head *head)
|
||||
+{
|
||||
+ struct pwrseq_list_per_dev *pwrseq_list_node;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ list_for_each_entry(pwrseq_list_node, head, list) {
|
||||
+ ret = pwrseq_resume(pwrseq_list_node->pwrseq);
|
||||
+ if (ret)
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_resume_list);
|
||||
diff --git a/drivers/power/pwrseq/pwrseq_generic.c b/drivers/power/pwrseq/pwrseq_generic.c
|
||||
new file mode 100644
|
||||
index 000000000000..4e7c09086cfb
|
||||
--- /dev/null
|
||||
+++ b/drivers/power/pwrseq/pwrseq_generic.c
|
||||
@@ -0,0 +1,234 @@
|
||||
+/*
|
||||
+ * pwrseq_generic.c Generic power sequence handling
|
||||
+ *
|
||||
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
|
||||
+ * Author: Peter Chen <peter.chen@nxp.com>
|
||||
+ *
|
||||
+ * This program is free software: you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 of
|
||||
+ * the License as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/gpio.h>
|
||||
+#include <linux/gpio/consumer.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/of_gpio.h>
|
||||
+#include <linux/slab.h>
|
||||
+
|
||||
+#include <linux/power/pwrseq.h>
|
||||
+
|
||||
+struct pwrseq_generic {
|
||||
+ struct pwrseq pwrseq;
|
||||
+ struct gpio_desc *gpiod_reset;
|
||||
+ struct clk *clks[PWRSEQ_MAX_CLKS];
|
||||
+ u32 duration_us;
|
||||
+ bool suspended;
|
||||
+};
|
||||
+
|
||||
+#define to_generic_pwrseq(p) container_of(p, struct pwrseq_generic, pwrseq)
|
||||
+
|
||||
+static int pwrseq_generic_alloc_instance(void);
|
||||
+static const struct of_device_id generic_id_table[] = {
|
||||
+ { .compatible = "generic",},
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+
|
||||
+static int pwrseq_generic_suspend(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ int clk;
|
||||
+
|
||||
+ for (clk = PWRSEQ_MAX_CLKS - 1; clk >= 0; clk--)
|
||||
+ clk_disable_unprepare(pwrseq_gen->clks[clk]);
|
||||
+
|
||||
+ pwrseq_gen->suspended = true;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int pwrseq_generic_resume(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ int clk, ret = 0;
|
||||
+
|
||||
+ for (clk = 0; clk < PWRSEQ_MAX_CLKS && pwrseq_gen->clks[clk]; clk++) {
|
||||
+ ret = clk_prepare_enable(pwrseq_gen->clks[clk]);
|
||||
+ if (ret) {
|
||||
+ pr_err("Can't enable clock, ret=%d\n", ret);
|
||||
+ goto err_disable_clks;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ pwrseq_gen->suspended = false;
|
||||
+ return ret;
|
||||
+
|
||||
+err_disable_clks:
|
||||
+ while (--clk >= 0)
|
||||
+ clk_disable_unprepare(pwrseq_gen->clks[clk]);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void pwrseq_generic_put(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ int clk;
|
||||
+
|
||||
+ if (pwrseq_gen->gpiod_reset)
|
||||
+ gpiod_put(pwrseq_gen->gpiod_reset);
|
||||
+
|
||||
+ for (clk = 0; clk < PWRSEQ_MAX_CLKS; clk++)
|
||||
+ clk_put(pwrseq_gen->clks[clk]);
|
||||
+
|
||||
+ pwrseq_unregister(&pwrseq_gen->pwrseq);
|
||||
+ kfree(pwrseq_gen);
|
||||
+}
|
||||
+
|
||||
+static void pwrseq_generic_off(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ int clk;
|
||||
+
|
||||
+ if (pwrseq_gen->suspended)
|
||||
+ return;
|
||||
+
|
||||
+ for (clk = PWRSEQ_MAX_CLKS - 1; clk >= 0; clk--)
|
||||
+ clk_disable_unprepare(pwrseq_gen->clks[clk]);
|
||||
+}
|
||||
+
|
||||
+static int pwrseq_generic_on(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ int clk, ret = 0;
|
||||
+ struct gpio_desc *gpiod_reset = pwrseq_gen->gpiod_reset;
|
||||
+
|
||||
+ for (clk = 0; clk < PWRSEQ_MAX_CLKS && pwrseq_gen->clks[clk]; clk++) {
|
||||
+ ret = clk_prepare_enable(pwrseq_gen->clks[clk]);
|
||||
+ if (ret) {
|
||||
+ pr_err("Can't enable clock, ret=%d\n", ret);
|
||||
+ goto err_disable_clks;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (gpiod_reset) {
|
||||
+ u32 duration_us = pwrseq_gen->duration_us;
|
||||
+
|
||||
+ if (duration_us <= 10)
|
||||
+ udelay(10);
|
||||
+ else
|
||||
+ usleep_range(duration_us, duration_us + 100);
|
||||
+ gpiod_set_value(gpiod_reset, 0);
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+
|
||||
+err_disable_clks:
|
||||
+ while (--clk >= 0)
|
||||
+ clk_disable_unprepare(pwrseq_gen->clks[clk]);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int pwrseq_generic_get(struct device_node *np, struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ enum of_gpio_flags flags;
|
||||
+ int reset_gpio, clk, ret = 0;
|
||||
+
|
||||
+ for (clk = 0; clk < PWRSEQ_MAX_CLKS; clk++) {
|
||||
+ pwrseq_gen->clks[clk] = of_clk_get(np, clk);
|
||||
+ if (IS_ERR(pwrseq_gen->clks[clk])) {
|
||||
+ ret = PTR_ERR(pwrseq_gen->clks[clk]);
|
||||
+ if (ret != -ENOENT)
|
||||
+ goto err_put_clks;
|
||||
+ pwrseq_gen->clks[clk] = NULL;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ reset_gpio = of_get_named_gpio_flags(np, "reset-gpios", 0, &flags);
|
||||
+ if (gpio_is_valid(reset_gpio)) {
|
||||
+ unsigned long gpio_flags;
|
||||
+
|
||||
+ if (flags & OF_GPIO_ACTIVE_LOW)
|
||||
+ gpio_flags = GPIOF_ACTIVE_LOW | GPIOF_OUT_INIT_LOW;
|
||||
+ else
|
||||
+ gpio_flags = GPIOF_OUT_INIT_HIGH;
|
||||
+
|
||||
+ ret = gpio_request_one(reset_gpio, gpio_flags,
|
||||
+ "pwrseq-reset-gpios");
|
||||
+ if (ret)
|
||||
+ goto err_put_clks;
|
||||
+
|
||||
+ pwrseq_gen->gpiod_reset = gpio_to_desc(reset_gpio);
|
||||
+ of_property_read_u32(np, "reset-duration-us",
|
||||
+ &pwrseq_gen->duration_us);
|
||||
+ } else if (reset_gpio == -ENOENT) {
|
||||
+ ; /* no such gpio */
|
||||
+ } else {
|
||||
+ ret = reset_gpio;
|
||||
+ pr_err("Failed to get reset gpio on %s, err = %d\n",
|
||||
+ np->full_name, reset_gpio);
|
||||
+ goto err_put_clks;
|
||||
+ }
|
||||
+
|
||||
+ /* allocate new one for later pwrseq instance request */
|
||||
+ ret = pwrseq_generic_alloc_instance();
|
||||
+ if (ret)
|
||||
+ goto err_put_gpio;
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_put_gpio:
|
||||
+ if (pwrseq_gen->gpiod_reset)
|
||||
+ gpiod_put(pwrseq_gen->gpiod_reset);
|
||||
+err_put_clks:
|
||||
+ while (--clk >= 0)
|
||||
+ clk_put(pwrseq_gen->clks[clk]);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_generic_alloc_instance - power sequence instance allocation
|
||||
+ *
|
||||
+ * This function is used to allocate one generic power sequence instance,
|
||||
+ * it is called when the system boots up and after one power sequence
|
||||
+ * instance is got successfully.
|
||||
+ *
|
||||
+ * Return zero on success or an error code otherwise.
|
||||
+ */
|
||||
+static int pwrseq_generic_alloc_instance(void)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen;
|
||||
+
|
||||
+ pwrseq_gen = kzalloc(sizeof(*pwrseq_gen), GFP_KERNEL);
|
||||
+ if (!pwrseq_gen)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ pwrseq_gen->pwrseq.pwrseq_of_match_table = generic_id_table;
|
||||
+ pwrseq_gen->pwrseq.get = pwrseq_generic_get;
|
||||
+ pwrseq_gen->pwrseq.on = pwrseq_generic_on;
|
||||
+ pwrseq_gen->pwrseq.off = pwrseq_generic_off;
|
||||
+ pwrseq_gen->pwrseq.put = pwrseq_generic_put;
|
||||
+ pwrseq_gen->pwrseq.suspend = pwrseq_generic_suspend;
|
||||
+ pwrseq_gen->pwrseq.resume = pwrseq_generic_resume;
|
||||
+
|
||||
+ pwrseq_register(&pwrseq_gen->pwrseq);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Allocate one pwrseq instance during boots up */
|
||||
+static int __init pwrseq_generic_register(void)
|
||||
+{
|
||||
+ return pwrseq_generic_alloc_instance();
|
||||
+}
|
||||
+postcore_initcall(pwrseq_generic_register)
|
||||
diff --git a/include/linux/power/pwrseq.h b/include/linux/power/pwrseq.h
|
||||
new file mode 100644
|
||||
index 000000000000..cbc344cdf9d2
|
||||
--- /dev/null
|
||||
+++ b/include/linux/power/pwrseq.h
|
||||
@@ -0,0 +1,81 @@
|
||||
+#ifndef __LINUX_PWRSEQ_H
|
||||
+#define __LINUX_PWRSEQ_H
|
||||
+
|
||||
+#include <linux/of.h>
|
||||
+
|
||||
+#define PWRSEQ_MAX_CLKS 3
|
||||
+
|
||||
+/**
|
||||
+ * struct pwrseq - the power sequence structure
|
||||
+ * @pwrseq_of_match_table: the OF device id table this pwrseq library supports
|
||||
+ * @node: the list pointer to be added to pwrseq list
|
||||
+ * @get: the API is used to get pwrseq instance from the device node
|
||||
+ * @on: do power on for this pwrseq instance
|
||||
+ * @off: do power off for this pwrseq instance
|
||||
+ * @put: release the resources on this pwrseq instance
|
||||
+ * @suspend: do suspend operation on this pwrseq instance
|
||||
+ * @resume: do resume operation on this pwrseq instance
|
||||
+ * @used: this pwrseq instance is used by device
|
||||
+ */
|
||||
+struct pwrseq {
|
||||
+ const struct of_device_id *pwrseq_of_match_table;
|
||||
+ struct list_head node;
|
||||
+ int (*get)(struct device_node *np, struct pwrseq *p);
|
||||
+ int (*on)(struct pwrseq *p);
|
||||
+ void (*off)(struct pwrseq *p);
|
||||
+ void (*put)(struct pwrseq *p);
|
||||
+ int (*suspend)(struct pwrseq *p);
|
||||
+ int (*resume)(struct pwrseq *p);
|
||||
+ bool used;
|
||||
+ bool suspended;
|
||||
+};
|
||||
+
|
||||
+/* used for power sequence instance list in one driver */
|
||||
+struct pwrseq_list_per_dev {
|
||||
+ struct pwrseq *pwrseq;
|
||||
+ struct list_head list;
|
||||
+};
|
||||
+
|
||||
+#if IS_ENABLED(CONFIG_POWER_SEQUENCE)
|
||||
+void pwrseq_register(struct pwrseq *pwrseq);
|
||||
+void pwrseq_unregister(struct pwrseq *pwrseq);
|
||||
+struct pwrseq *of_pwrseq_on(struct device_node *np);
|
||||
+void of_pwrseq_off(struct pwrseq *pwrseq);
|
||||
+int of_pwrseq_on_list(struct device_node *np, struct list_head *head);
|
||||
+void of_pwrseq_off_list(struct list_head *head);
|
||||
+int pwrseq_suspend(struct pwrseq *p);
|
||||
+int pwrseq_resume(struct pwrseq *p);
|
||||
+int pwrseq_suspend_list(struct list_head *head);
|
||||
+int pwrseq_resume_list(struct list_head *head);
|
||||
+#else
|
||||
+static inline void pwrseq_register(struct pwrseq *pwrseq) {}
|
||||
+static inline void pwrseq_unregister(struct pwrseq *pwrseq) {}
|
||||
+static inline struct pwrseq *of_pwrseq_on(struct device_node *np)
|
||||
+{
|
||||
+ return NULL;
|
||||
+}
|
||||
+static void of_pwrseq_off(struct pwrseq *pwrseq) {}
|
||||
+static int of_pwrseq_on_list(struct device_node *np, struct list_head *head)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+static void of_pwrseq_off_list(struct list_head *head) {}
|
||||
+static int pwrseq_suspend(struct pwrseq *p)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+static int pwrseq_resume(struct pwrseq *p)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+static int pwrseq_suspend_list(struct list_head *head)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+static int pwrseq_resume_list(struct list_head *head)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif /* CONFIG_POWER_SEQUENCE */
|
||||
+
|
||||
+#endif /* __LINUX_PWRSEQ_H */
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,165 +0,0 @@
|
||||
From a42362841fe263a6c97a1793ccd4b9246ac2b108 Mon Sep 17 00:00:00 2001
|
||||
From: Peter Chen <peter.chen@nxp.com>
|
||||
Date: Thu, 18 May 2017 08:49:00 +0800
|
||||
Subject: [PATCH 4/9] usb: core: add power sequence handling for USB devices
|
||||
|
||||
Some hard-wired USB devices need to do power sequence to let the
|
||||
device work normally, the typical power sequence like: enable USB
|
||||
PHY clock, toggle reset pin, etc. But current Linux USB driver
|
||||
lacks of such code to do it, it may cause some hard-wired USB devices
|
||||
works abnormal or can't be recognized by controller at all.
|
||||
|
||||
In this patch, it calls power sequence library APIs to finish
|
||||
the power sequence events. It will do power on sequence at hub's
|
||||
probe for all devices under this hub (includes root hub).
|
||||
At hub_disconnect, it will do power off sequence which is at powered
|
||||
on list.
|
||||
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
Tested-by Joshua Clayton <stillcompiling@gmail.com>
|
||||
Tested-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
|
||||
Reviewed-by: Vaibhav Hiremath <hvaibhav.linux@gmail.com>
|
||||
---
|
||||
drivers/usb/Kconfig | 1 +
|
||||
drivers/usb/core/hub.c | 49 ++++++++++++++++++++++++++++++++++++++----
|
||||
drivers/usb/core/hub.h | 1 +
|
||||
3 files changed, 47 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
|
||||
index 6e59d370ef81..2162fd85b32d 100644
|
||||
--- a/drivers/usb/Kconfig
|
||||
+++ b/drivers/usb/Kconfig
|
||||
@@ -47,6 +47,7 @@ config USB
|
||||
depends on USB_ARCH_HAS_HCD
|
||||
select GENERIC_ALLOCATOR
|
||||
select USB_COMMON
|
||||
+ select POWER_SEQUENCE
|
||||
select NLS # for UTF-8 strings
|
||||
---help---
|
||||
Universal Serial Bus (USB) is a specification for a serial bus
|
||||
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
|
||||
index 236313f41f4a..3db75b0d2426 100644
|
||||
--- a/drivers/usb/core/hub.c
|
||||
+++ b/drivers/usb/core/hub.c
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <linux/random.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/kobject.h>
|
||||
+#include <linux/power/pwrseq.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/byteorder.h>
|
||||
@@ -1705,6 +1706,7 @@ static void hub_disconnect(struct usb_interface *intf)
|
||||
hub->error = 0;
|
||||
hub_quiesce(hub, HUB_DISCONNECT);
|
||||
|
||||
+ of_pwrseq_off_list(&hub->pwrseq_on_list);
|
||||
mutex_lock(&usb_port_peer_mutex);
|
||||
|
||||
/* Avoid races with recursively_mark_NOTATTACHED() */
|
||||
@@ -1751,11 +1753,41 @@ static bool hub_descriptor_is_sane(struct usb_host_interface *desc)
|
||||
return true;
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_OF
|
||||
+static int hub_of_pwrseq_on(struct usb_hub *hub)
|
||||
+{
|
||||
+ struct device *parent;
|
||||
+ struct usb_device *hdev = hub->hdev;
|
||||
+ struct device_node *np;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (hdev->parent)
|
||||
+ parent = &hdev->dev;
|
||||
+ else
|
||||
+ parent = bus_to_hcd(hdev->bus)->self.sysdev;
|
||||
+
|
||||
+ for_each_child_of_node(parent->of_node, np) {
|
||||
+ ret = of_pwrseq_on_list(np, &hub->pwrseq_on_list);
|
||||
+ /* Maybe no power sequence library is chosen */
|
||||
+ if (ret && ret != -ENOENT)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+#else
|
||||
+static int hub_of_pwrseq_on(struct usb_hub *hub)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_host_interface *desc;
|
||||
struct usb_device *hdev;
|
||||
struct usb_hub *hub;
|
||||
+ int ret = -ENODEV;
|
||||
|
||||
desc = intf->cur_altsetting;
|
||||
hdev = interface_to_usbdev(intf);
|
||||
@@ -1846,6 +1878,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
INIT_DELAYED_WORK(&hub->leds, led_work);
|
||||
INIT_DELAYED_WORK(&hub->init_work, NULL);
|
||||
INIT_WORK(&hub->events, hub_event);
|
||||
+ INIT_LIST_HEAD(&hub->pwrseq_on_list);
|
||||
spin_lock_init(&hub->irq_urb_lock);
|
||||
timer_setup(&hub->irq_urb_retry, hub_retry_irq_urb, 0);
|
||||
usb_get_intf(intf);
|
||||
@@ -1861,11 +1894,14 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
if (id->driver_info & HUB_QUIRK_CHECK_PORT_AUTOSUSPEND)
|
||||
hub->quirk_check_port_auto_suspend = 1;
|
||||
|
||||
- if (hub_configure(hub, &desc->endpoint[0].desc) >= 0)
|
||||
- return 0;
|
||||
+ if (hub_configure(hub, &desc->endpoint[0].desc) >= 0) {
|
||||
+ ret = hub_of_pwrseq_on(hub);
|
||||
+ if (!ret)
|
||||
+ return 0;
|
||||
+ }
|
||||
|
||||
hub_disconnect(intf);
|
||||
- return -ENODEV;
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -3720,7 +3756,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
|
||||
|
||||
/* stop hub_wq and related activity */
|
||||
hub_quiesce(hub, HUB_SUSPEND);
|
||||
- return 0;
|
||||
+ return pwrseq_suspend_list(&hub->pwrseq_on_list);
|
||||
}
|
||||
|
||||
/* Report wakeup requests from the ports of a resuming root hub */
|
||||
@@ -3760,8 +3796,13 @@ static void report_wakeup_requests(struct usb_hub *hub)
|
||||
static int hub_resume(struct usb_interface *intf)
|
||||
{
|
||||
struct usb_hub *hub = usb_get_intfdata(intf);
|
||||
+ int ret;
|
||||
|
||||
dev_dbg(&intf->dev, "%s\n", __func__);
|
||||
+ ret = pwrseq_resume_list(&hub->pwrseq_on_list);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
hub_activate(hub, HUB_RESUME);
|
||||
|
||||
/*
|
||||
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
|
||||
index a9e24e4b8df1..feab956a1414 100644
|
||||
--- a/drivers/usb/core/hub.h
|
||||
+++ b/drivers/usb/core/hub.h
|
||||
@@ -72,6 +72,7 @@ struct usb_hub {
|
||||
spinlock_t irq_urb_lock;
|
||||
struct timer_list irq_urb_retry;
|
||||
struct usb_port **ports;
|
||||
+ struct list_head pwrseq_on_list; /* powered pwrseq node list */
|
||||
};
|
||||
|
||||
/**
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,49 +0,0 @@
|
||||
From bf1b3a63aa2f3438750f5acdf372705f8a1beb41 Mon Sep 17 00:00:00 2001
|
||||
From: Joshua Clayton <stillcompiling@gmail.com>
|
||||
Date: Thu, 18 May 2017 08:49:01 +0800
|
||||
Subject: [PATCH 5/9] ARM: dts: imx6qdl: Enable usb node children with <reg>
|
||||
|
||||
Give usb nodes #address and #size attributes, so that a child node
|
||||
representing a permanently connected device such as an onboard hub may
|
||||
be addressed with a <reg> attribute
|
||||
|
||||
Signed-off-by: Joshua Clayton <stillcompiling@gmail.com>
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
---
|
||||
arch/arm/boot/dts/imx6qdl.dtsi | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
|
||||
index fe17a3405edc..a5f2f981255f 100644
|
||||
--- a/arch/arm/boot/dts/imx6qdl.dtsi
|
||||
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
|
||||
@@ -977,6 +977,8 @@
|
||||
|
||||
usbh1: usb@2184200 {
|
||||
compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
reg = <0x02184200 0x200>;
|
||||
interrupts = <0 40 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX6QDL_CLK_USBOH3>;
|
||||
@@ -991,6 +993,8 @@
|
||||
|
||||
usbh2: usb@2184400 {
|
||||
compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
reg = <0x02184400 0x200>;
|
||||
interrupts = <0 41 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX6QDL_CLK_USBOH3>;
|
||||
@@ -1006,6 +1010,8 @@
|
||||
|
||||
usbh3: usb@2184600 {
|
||||
compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
reg = <0x02184600 0x200>;
|
||||
interrupts = <0 42 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX6QDL_CLK_USBOH3>;
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,79 +0,0 @@
|
||||
From c46707dde637ec75182c2f42f61aab96486bbcee Mon Sep 17 00:00:00 2001
|
||||
From: Peter Chen <peter.chen@nxp.com>
|
||||
Date: Thu, 18 May 2017 08:49:02 +0800
|
||||
Subject: [PATCH 6/9] ARM: dts: imx6qdl-udoo.dtsi: fix onboard USB HUB property
|
||||
|
||||
The current dts describes USB HUB's property at USB controller's
|
||||
entry, it is improper. The USB HUB should be the child node
|
||||
under USB controller, and power sequence properties are under
|
||||
it. Besides, using gpio pinctrl setting for USB2415's reset pin.
|
||||
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
Signed-off-by: Joshua Clayton <stillcompiling@gmail.com>
|
||||
Tested-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
|
||||
---
|
||||
arch/arm/boot/dts/imx6qdl-udoo.dtsi | 26 ++++++++++++--------------
|
||||
1 file changed, 12 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/arch/arm/boot/dts/imx6qdl-udoo.dtsi b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
|
||||
index 776bfc77f89d..4781a9e04338 100644
|
||||
--- a/arch/arm/boot/dts/imx6qdl-udoo.dtsi
|
||||
+++ b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
|
||||
@@ -5,6 +5,8 @@
|
||||
* Author: Fabio Estevam <fabio.estevam@freescale.com>
|
||||
*/
|
||||
|
||||
+#include <dt-bindings/gpio/gpio.h>
|
||||
+
|
||||
/ {
|
||||
aliases {
|
||||
backlight = &backlight;
|
||||
@@ -62,17 +64,6 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
- reg_usb_h1_vbus: regulator@0 {
|
||||
- compatible = "regulator-fixed";
|
||||
- reg = <0>;
|
||||
- regulator-name = "usb_h1_vbus";
|
||||
- regulator-min-microvolt = <5000000>;
|
||||
- regulator-max-microvolt = <5000000>;
|
||||
- enable-active-high;
|
||||
- startup-delay-us = <2>; /* USB2415 requires a POR of 1 us minimum */
|
||||
- gpio = <&gpio7 12 0>;
|
||||
- };
|
||||
-
|
||||
reg_panel: regulator@1 {
|
||||
compatible = "regulator-fixed";
|
||||
reg = <1>;
|
||||
@@ -205,7 +196,7 @@
|
||||
|
||||
pinctrl_usbh: usbhgrp {
|
||||
fsl,pins = <
|
||||
- MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x80000000
|
||||
+ MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x1b0b0
|
||||
MX6QDL_PAD_NANDF_CS2__CCM_CLKO2 0x130b0
|
||||
>;
|
||||
};
|
||||
@@ -282,9 +273,16 @@
|
||||
&usbh1 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_usbh>;
|
||||
- vbus-supply = <®_usb_h1_vbus>;
|
||||
- clocks = <&clks IMX6QDL_CLK_CKO>;
|
||||
status = "okay";
|
||||
+
|
||||
+ usb2415: hub@1 {
|
||||
+ compatible = "usb424,2514";
|
||||
+ reg = <1>;
|
||||
+
|
||||
+ clocks = <&clks IMX6QDL_CLK_CKO>;
|
||||
+ reset-gpios = <&gpio7 12 GPIO_ACTIVE_LOW>;
|
||||
+ reset-duration-us = <3000>;
|
||||
+ };
|
||||
};
|
||||
|
||||
&usdhc3 {
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,74 +0,0 @@
|
||||
From 0ae59d1767a9cf9875b35a026b5df13eeb3694db Mon Sep 17 00:00:00 2001
|
||||
From: Joshua Clayton <stillcompiling@gmail.com>
|
||||
Date: Thu, 18 May 2017 08:49:03 +0800
|
||||
Subject: [PATCH 7/9] ARM: dts: imx6q-evi: Fix onboard hub reset line
|
||||
|
||||
Previously the onboard hub was made to work by treating its
|
||||
reset gpio as a regulator enable.
|
||||
Get rid of that kludge now that pwseq has added reset gpio support
|
||||
Move pin muxing the hub reset pin into the usbh1 group
|
||||
|
||||
Signed-off-by: Joshua Clayton <stillcompiling@gmail.com>
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
---
|
||||
arch/arm/boot/dts/imx6q-evi.dts | 25 +++++++------------------
|
||||
1 file changed, 7 insertions(+), 18 deletions(-)
|
||||
|
||||
diff --git a/arch/arm/boot/dts/imx6q-evi.dts b/arch/arm/boot/dts/imx6q-evi.dts
|
||||
index c63f371ede8b..546d9d4e8ca1 100644
|
||||
--- a/arch/arm/boot/dts/imx6q-evi.dts
|
||||
+++ b/arch/arm/boot/dts/imx6q-evi.dts
|
||||
@@ -55,18 +55,6 @@
|
||||
reg = <0x10000000 0x40000000>;
|
||||
};
|
||||
|
||||
- reg_usbh1_vbus: regulator-usbhubreset {
|
||||
- compatible = "regulator-fixed";
|
||||
- regulator-name = "usbh1_vbus";
|
||||
- regulator-min-microvolt = <5000000>;
|
||||
- regulator-max-microvolt = <5000000>;
|
||||
- enable-active-high;
|
||||
- startup-delay-us = <2>;
|
||||
- pinctrl-names = "default";
|
||||
- pinctrl-0 = <&pinctrl_usbh1_hubreset>;
|
||||
- gpio = <&gpio7 12 GPIO_ACTIVE_HIGH>;
|
||||
- };
|
||||
-
|
||||
reg_usb_otg_vbus: regulator-usbotgvbus {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "usb_otg_vbus";
|
||||
@@ -214,12 +202,18 @@
|
||||
};
|
||||
|
||||
&usbh1 {
|
||||
- vbus-supply = <®_usbh1_vbus>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_usbh1>;
|
||||
dr_mode = "host";
|
||||
disable-over-current;
|
||||
status = "okay";
|
||||
+
|
||||
+ usb2415host: hub@1 {
|
||||
+ compatible = "usb424,2513";
|
||||
+ reg = <1>;
|
||||
+ reset-gpios = <&gpio7 12 GPIO_ACTIVE_LOW>;
|
||||
+ reset-duration-us = <3000>;
|
||||
+ };
|
||||
};
|
||||
|
||||
&usbotg {
|
||||
@@ -482,11 +476,6 @@
|
||||
MX6QDL_PAD_GPIO_3__USB_H1_OC 0x1b0b0
|
||||
/* usbh1_b OC */
|
||||
MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x1b0b0
|
||||
- >;
|
||||
- };
|
||||
-
|
||||
- pinctrl_usbh1_hubreset: usbh1hubresetgrp {
|
||||
- fsl,pins = <
|
||||
MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x1b0b0
|
||||
>;
|
||||
};
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,511 +0,0 @@
|
||||
From 9a4d8e886600c7c330590a2435dd74eb16d480ce Mon Sep 17 00:00:00 2001
|
||||
From: Steve Arnold <nerdboy@gentoo.org>
|
||||
Date: Fri, 15 Dec 2017 16:43:22 -0800
|
||||
Subject: [PATCH 8/9] ARM: dts,driver: imx6,udooqdl: add arduino manager driver
|
||||
and update dts
|
||||
|
||||
* note this is required to upload sketches to sam3 from arduino IDE
|
||||
|
||||
Signed-off-by: Steve Arnold <nerdboy@gentoo.org>
|
||||
---
|
||||
arch/arm/boot/dts/imx6qdl-udoo.dtsi | 20 ++
|
||||
drivers/misc/Kconfig | 7 +
|
||||
drivers/misc/Makefile | 1 +
|
||||
drivers/misc/udoo_ard.c | 417 ++++++++++++++++++++++++++++
|
||||
4 files changed, 445 insertions(+)
|
||||
create mode 100755 drivers/misc/udoo_ard.c
|
||||
|
||||
diff --git a/arch/arm/boot/dts/imx6qdl-udoo.dtsi b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
|
||||
index 4781a9e04338..554f601eb72a 100644
|
||||
--- a/arch/arm/boot/dts/imx6qdl-udoo.dtsi
|
||||
+++ b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
|
||||
@@ -84,6 +84,17 @@
|
||||
mux-int-port = <1>;
|
||||
mux-ext-port = <6>;
|
||||
};
|
||||
+
|
||||
+ udoo_ard: udoo_ard_manager {
|
||||
+ compatible = "udoo,imx6q-udoo-ard";
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&pinctrl_udooard>;
|
||||
+ bossac-clk-gpio = <&gpio6 3 0>;
|
||||
+ bossac-dat-gpio = <&gpio5 18 0>;
|
||||
+ bossac-erase-gpio = <&gpio4 21 0>;
|
||||
+ bossac-reset-gpio = <&gpio1 0 0>;
|
||||
+ status = "okay";
|
||||
+ };
|
||||
};
|
||||
|
||||
&fec {
|
||||
@@ -201,6 +212,15 @@
|
||||
>;
|
||||
};
|
||||
|
||||
+ pinctrl_udooard: udooardgrp {
|
||||
+ fsl,pins = <
|
||||
+ MX6QDL_PAD_DISP0_DAT0__GPIO4_IO21 0x80000000
|
||||
+ MX6QDL_PAD_CSI0_DAT17__GPIO6_IO03 0x80000000
|
||||
+ MX6QDL_PAD_CSI0_PIXCLK__GPIO5_IO18 0x80000000
|
||||
+ MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x80000000
|
||||
+ >;
|
||||
+ };
|
||||
+
|
||||
pinctrl_usdhc3: usdhc3grp {
|
||||
fsl,pins = <
|
||||
MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059
|
||||
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
|
||||
index 2cf9db44e4b2..f4616fc61808 100644
|
||||
--- a/drivers/misc/Kconfig
|
||||
+++ b/drivers/misc/Kconfig
|
||||
@@ -487,6 +487,13 @@ config PVPANIC
|
||||
a paravirtualized device provided by QEMU; it lets a virtual machine
|
||||
(guest) communicate panic events to the host.
|
||||
|
||||
+config UDOO_ARD
|
||||
+ tristate "UDOO-Arduino erase/reset Driver"
|
||||
+ default y
|
||||
+ help
|
||||
+ This driver is used to erase and reset arduino board via command sent
|
||||
+ over USB-to-SERIAL connection.
|
||||
+
|
||||
source "drivers/misc/c2port/Kconfig"
|
||||
source "drivers/misc/eeprom/Kconfig"
|
||||
source "drivers/misc/cb710/Kconfig"
|
||||
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
|
||||
index dcc801e8834e..13e132dd62c9 100644
|
||||
--- a/drivers/misc/Makefile
|
||||
+++ b/drivers/misc/Makefile
|
||||
@@ -11,6 +11,7 @@ obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o
|
||||
obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
|
||||
obj-$(CONFIG_DUMMY_IRQ) += dummy-irq.o
|
||||
obj-$(CONFIG_ICS932S401) += ics932s401.o
|
||||
+obj-$(CONFIG_UDOO_ARD) += udoo_ard.o
|
||||
obj-$(CONFIG_LKDTM) += lkdtm/
|
||||
obj-$(CONFIG_TIFM_CORE) += tifm_core.o
|
||||
obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
|
||||
diff --git a/drivers/misc/udoo_ard.c b/drivers/misc/udoo_ard.c
|
||||
new file mode 100755
|
||||
index 000000000000..2210738e09c0
|
||||
--- /dev/null
|
||||
+++ b/drivers/misc/udoo_ard.c
|
||||
@@ -0,0 +1,417 @@
|
||||
+/*
|
||||
+ * udoo_ard.c
|
||||
+ * UDOO quad/dual Arduino flash erase / CPU resetter
|
||||
+ *
|
||||
+ * Copyright (C) 2013-2015 Aidilab srl
|
||||
+ * Author: UDOO Team <social@udoo.org>
|
||||
+ * Author: Giuseppe Pagano <giuseppe.pagano@seco.com>
|
||||
+ * Author: Francesco Montefoschi <francesco.monte@gmail.com>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it
|
||||
+ * under the terms of the GNU General Public License version 2 as published by
|
||||
+ * the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
+ * more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License along with
|
||||
+ * this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/errno.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/gpio.h>
|
||||
+#include <linux/sched.h>
|
||||
+#include <linux/sched/clock.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/workqueue.h>
|
||||
+#include <linux/fs.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/of_address.h>
|
||||
+#include <linux/of_gpio.h>
|
||||
+#include <linux/of_irq.h>
|
||||
+#include <linux/of_platform.h>
|
||||
+#include <linux/uaccess.h>
|
||||
+
|
||||
+#define DRIVER_NAME "udoo_ard"
|
||||
+#define PINCTRL_DEFAULT "default"
|
||||
+#define AUTH_TOKEN 0x5A5A
|
||||
+#define MAX_MSEC_SINCE_LAST_IRQ 400
|
||||
+#define GRAY_TIME_BETWEEN_RESET 10000 // In this time we can't accept new erase/reset code
|
||||
+
|
||||
+static struct workqueue_struct *erase_reset_wq;
|
||||
+typedef struct {
|
||||
+ struct work_struct erase_reset_work;
|
||||
+ struct pinctrl *pinctrl;
|
||||
+ struct pinctrl_state *pins_default;
|
||||
+ int step;
|
||||
+ int cmdcode;
|
||||
+ int erase_reset_lock;
|
||||
+ int gpio_bossac_clk;
|
||||
+ int gpio_bossac_dat;
|
||||
+ int gpio_ard_erase;
|
||||
+ int gpio_ard_reset;
|
||||
+ unsigned long last_int_time_in_ns;
|
||||
+ unsigned long last_int_time_in_sec;
|
||||
+} erase_reset_work_t;
|
||||
+
|
||||
+erase_reset_work_t *work;
|
||||
+static u32 origTX, origRX; // original UART4 TX/RX pad control registers
|
||||
+static int major; // for /dev/udoo_ard
|
||||
+static struct class *udoo_class;
|
||||
+
|
||||
+static struct platform_device_id udoo_ard_devtype[] = {
|
||||
+ {
|
||||
+ /* keep it for coldfire */
|
||||
+ .name = DRIVER_NAME,
|
||||
+ .driver_data = 0,
|
||||
+ }, {
|
||||
+ /* sentinel */
|
||||
+ }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(platform, udoo_ard_devtype);
|
||||
+
|
||||
+static const struct of_device_id udoo_ard_dt_ids[] = {
|
||||
+ { .compatible = "udoo,imx6q-udoo-ard", .data = &udoo_ard_devtype[0], },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, udoo_ard_dt_ids);
|
||||
+
|
||||
+static void disable_serial(void)
|
||||
+{
|
||||
+ u32 addrTX;
|
||||
+ void __iomem *_addrTX;
|
||||
+
|
||||
+ printk("[bossac] Disable UART4 serial port.\n");
|
||||
+
|
||||
+ addrTX = 0x20E01F8;
|
||||
+ _addrTX = ioremap(addrTX, 8);
|
||||
+
|
||||
+ origTX = __raw_readl(_addrTX);
|
||||
+ origRX = __raw_readl(_addrTX + 0x4);
|
||||
+
|
||||
+ __raw_writel(0x15, _addrTX);
|
||||
+ __raw_writel(0x15, _addrTX + 0x4);
|
||||
+
|
||||
+ iounmap(_addrTX);
|
||||
+}
|
||||
+
|
||||
+static void enable_serial(void)
|
||||
+{
|
||||
+ u32 addrTX;
|
||||
+ void __iomem *_addrTX;
|
||||
+
|
||||
+ printk("[bossac] Enable UART4 serial port.\n");
|
||||
+
|
||||
+ addrTX = 0x20E01F8;
|
||||
+ _addrTX = ioremap(addrTX, 8);
|
||||
+
|
||||
+ __raw_writel(origTX, _addrTX);
|
||||
+ __raw_writel(origRX, _addrTX + 0x4);
|
||||
+
|
||||
+ iounmap(_addrTX);
|
||||
+}
|
||||
+
|
||||
+static void erase_reset(void)
|
||||
+{
|
||||
+ printk("[bossac] UDOO ERASE and RESET on Sam3x started.\n");
|
||||
+
|
||||
+ gpio_direction_input(work->gpio_ard_erase);
|
||||
+ gpio_set_value(work->gpio_ard_reset, 1);
|
||||
+ msleep(1);
|
||||
+
|
||||
+ gpio_direction_output(work->gpio_ard_erase, 1);
|
||||
+ msleep(300);
|
||||
+ gpio_direction_input(work->gpio_ard_erase);
|
||||
+
|
||||
+ msleep(10);
|
||||
+ gpio_set_value(work->gpio_ard_reset, 0);
|
||||
+
|
||||
+ msleep(80);
|
||||
+ gpio_set_value(work->gpio_ard_reset, 1);
|
||||
+
|
||||
+ printk("[bossac] UDOO ERASE and RESET on Sam3x EXECUTED.\n");
|
||||
+}
|
||||
+
|
||||
+static void shutdown_sam3x(void)
|
||||
+{
|
||||
+ printk("[bossac] RESET on Sam3x.\n");
|
||||
+
|
||||
+ gpio_set_value(work->gpio_ard_reset, 0);
|
||||
+}
|
||||
+
|
||||
+static void erase_reset_wq_function( struct work_struct *work2)
|
||||
+{
|
||||
+ disable_serial();
|
||||
+ erase_reset();
|
||||
+ msleep(GRAY_TIME_BETWEEN_RESET);
|
||||
+
|
||||
+ work->erase_reset_lock = 0;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Called everytime the gpio_bossac_clk signal toggles.
|
||||
+ * If the auth token (16 bit) is found, we look for the command code (4 bit).
|
||||
+ * The code 0x0F is sent by Bossac to trigger an erase/reset (to achieve this,
|
||||
+ * erase_reset_wq is scheduled). Before starting to program the flash, we disable
|
||||
+ * the UART4 serial port, otherwise there is too noise on the serial lines (the
|
||||
+ * programming port and UART4 port are connected together, see hw schematics).
|
||||
+ * When Bossac finishes to flash/verify, the code 0x00 is sent which re-enables
|
||||
+ * the UART4 port.
|
||||
+ */
|
||||
+static irqreturn_t udoo_bossac_req(int irq, void *dev_id)
|
||||
+{
|
||||
+ int retval, auth_bit, expected_bit, msec_since_last_irq;
|
||||
+ u64 nowsec;
|
||||
+ unsigned long rem_nsec;
|
||||
+ erase_reset_work_t *erase_reset_work;
|
||||
+
|
||||
+ auth_bit = 0;
|
||||
+ if (gpio_get_value(work->gpio_bossac_dat) != 0x0) {
|
||||
+ auth_bit = 1;
|
||||
+ }
|
||||
+
|
||||
+ erase_reset_work = (erase_reset_work_t *)work;
|
||||
+
|
||||
+ nowsec = local_clock();
|
||||
+ rem_nsec = do_div(nowsec, 1000000000) ;
|
||||
+ msec_since_last_irq = (((unsigned long)nowsec * 1000) + rem_nsec/1000000 ) - (((unsigned long)erase_reset_work->last_int_time_in_sec * 1000) + erase_reset_work->last_int_time_in_ns/1000000);
|
||||
+
|
||||
+ if (msec_since_last_irq > MAX_MSEC_SINCE_LAST_IRQ) {
|
||||
+ erase_reset_work->step = 0;
|
||||
+#ifdef DEBUG
|
||||
+ printk("[bossac] Reset authentication timeout!\n");
|
||||
+#endif
|
||||
+ }
|
||||
+
|
||||
+#ifdef DEBUG
|
||||
+ printk("[bossac] STEP %d -> 0x%d \n", erase_reset_work->step, auth_bit);
|
||||
+#endif
|
||||
+ erase_reset_work->last_int_time_in_ns = rem_nsec;
|
||||
+ erase_reset_work->last_int_time_in_sec = nowsec;
|
||||
+
|
||||
+ if ( erase_reset_work->step < 16 ) { // Authenticating received token bit.
|
||||
+ expected_bit = (( AUTH_TOKEN >> erase_reset_work->step ) & 0x01 );
|
||||
+ if ( auth_bit == expected_bit ) {
|
||||
+ erase_reset_work->step = erase_reset_work->step + 1;
|
||||
+ } else {
|
||||
+ erase_reset_work->step = 0;
|
||||
+ }
|
||||
+ } else { // Passed all authentication step. Receiving command code.
|
||||
+ erase_reset_work->cmdcode = erase_reset_work->cmdcode | (auth_bit << (erase_reset_work->step - 16));
|
||||
+ erase_reset_work->step = erase_reset_work->step + 1;
|
||||
+ }
|
||||
+
|
||||
+#ifdef DEBUG
|
||||
+ printk("erase_reset_work->erase_reset_lock = %d \n", erase_reset_work->erase_reset_lock);
|
||||
+#endif
|
||||
+ if ( erase_reset_work->step == 20 ) { // Passed authentication and code acquiring step.
|
||||
+#ifdef DEBUG
|
||||
+ printk("[bossac] Received code = 0x%04x \n", erase_reset_work->cmdcode);
|
||||
+#endif
|
||||
+ if (erase_reset_work->cmdcode == 0xF) {
|
||||
+ if (erase_reset_work->erase_reset_lock == 0) {
|
||||
+ erase_reset_work->erase_reset_lock = 1;
|
||||
+ retval = queue_work( erase_reset_wq, (struct work_struct *)work );
|
||||
+ } else {
|
||||
+#ifdef DEBUG
|
||||
+ printk("Erase and reset operation already in progress. Do nothing.\n");
|
||||
+#endif
|
||||
+ }
|
||||
+ } else {
|
||||
+ enable_serial();
|
||||
+ }
|
||||
+ erase_reset_work->step = 0;
|
||||
+ erase_reset_work->cmdcode = 0;
|
||||
+ }
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Takes control of clock, data, erase, reset GPIOs.
|
||||
+ */
|
||||
+static int gpio_setup(void)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = gpio_request(work->gpio_bossac_clk, "BOSSA_CLK");
|
||||
+ if (ret) {
|
||||
+ printk(KERN_ERR "request BOSSA_CLK IRQ\n");
|
||||
+ return -1;
|
||||
+ } else {
|
||||
+ gpio_direction_input(work->gpio_bossac_clk);
|
||||
+ }
|
||||
+
|
||||
+ ret = gpio_request(work->gpio_bossac_dat, "BOSSA_DAT");
|
||||
+ if (ret) {
|
||||
+ printk(KERN_ERR "request BOSSA_DAT IRQ\n");
|
||||
+ return -1;
|
||||
+ } else {
|
||||
+ gpio_direction_input(work->gpio_bossac_dat);
|
||||
+ }
|
||||
+
|
||||
+ ret = gpio_request(work->gpio_ard_erase, "BOSSAC");
|
||||
+ if (ret) {
|
||||
+ printk(KERN_ERR "request GPIO FOR ARDUINO ERASE\n");
|
||||
+ return -1;
|
||||
+ } else {
|
||||
+ gpio_direction_input(work->gpio_ard_erase);
|
||||
+ }
|
||||
+
|
||||
+ ret = gpio_request(work->gpio_ard_reset, "BOSSAC");
|
||||
+ if (ret) {
|
||||
+ printk(KERN_ERR "request GPIO FOR ARDUINO RESET\n");
|
||||
+ return -1;
|
||||
+ } else {
|
||||
+ gpio_direction_output(work->gpio_ard_reset, 1);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static ssize_t device_write(struct file *filp, const char *buff, size_t len, loff_t *off)
|
||||
+{
|
||||
+ char msg[10];
|
||||
+ long res;
|
||||
+
|
||||
+ if (len > 10)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+
|
||||
+ res = copy_from_user(msg, buff, len);
|
||||
+ if (res) {
|
||||
+ return -EFAULT;
|
||||
+ }
|
||||
+ msg[len] = '\0';
|
||||
+
|
||||
+ if (strcmp(msg, "erase")==0) {
|
||||
+ erase_reset();
|
||||
+ } else if (strcmp(msg, "shutdown")==0) {
|
||||
+ shutdown_sam3x();
|
||||
+ } else if (strcmp(msg, "uartoff")==0) {
|
||||
+ disable_serial();
|
||||
+ } else if (strcmp(msg, "uarton")==0) {
|
||||
+ enable_serial();
|
||||
+ } else {
|
||||
+ printk("[bossac] udoo_ard invalid operation! %s", msg);
|
||||
+ }
|
||||
+
|
||||
+ return len;
|
||||
+}
|
||||
+
|
||||
+static struct file_operations fops = {
|
||||
+ .write = device_write,
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * If a fdt udoo_ard entry is found, we register an IRQ on bossac clock line
|
||||
+ * and we create /dev/udoo_ard
|
||||
+ */
|
||||
+static int udoo_ard_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int retval;
|
||||
+ struct device *temp_class;
|
||||
+ struct platform_device *bdev;
|
||||
+ struct device_node *np;
|
||||
+
|
||||
+ bdev = kzalloc(sizeof(*bdev), GFP_KERNEL);
|
||||
+ np = pdev->dev.of_node;
|
||||
+
|
||||
+ if (!np)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ work = (erase_reset_work_t *)kmalloc(sizeof(erase_reset_work_t), GFP_KERNEL);
|
||||
+ if (work) {
|
||||
+ work->gpio_ard_reset = of_get_named_gpio(np, "bossac-reset-gpio", 0);
|
||||
+ work->gpio_ard_erase = of_get_named_gpio(np, "bossac-erase-gpio", 0);
|
||||
+ work->gpio_bossac_clk = of_get_named_gpio(np, "bossac-clk-gpio", 0);
|
||||
+ work->gpio_bossac_dat = of_get_named_gpio(np, "bossac-dat-gpio", 0);
|
||||
+ work->pinctrl = devm_pinctrl_get(&pdev->dev);
|
||||
+ work->pins_default = pinctrl_lookup_state(work->pinctrl, PINCTRL_DEFAULT);
|
||||
+ } else {
|
||||
+ printk("[bossac] Failed to allocate data structure.");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ pinctrl_select_state(work->pinctrl, work->pins_default);
|
||||
+ gpio_setup();
|
||||
+
|
||||
+ printk("[bossac] Registering IRQ %d for BOSSAC Arduino erase/reset operation\n", gpio_to_irq(work->gpio_bossac_clk));
|
||||
+ retval = request_irq(gpio_to_irq(work->gpio_bossac_clk), udoo_bossac_req, IRQF_TRIGGER_FALLING, "UDOO", bdev);
|
||||
+
|
||||
+ major = register_chrdev(major, "udoo_ard", &fops);
|
||||
+ if (major < 0) {
|
||||
+ printk(KERN_ERR "[bossac] Cannot get major for UDOO Ard\n");
|
||||
+ return -EBUSY;
|
||||
+ }
|
||||
+
|
||||
+ udoo_class = class_create(THIS_MODULE, "udoo_ard");
|
||||
+ if (IS_ERR(udoo_class)) {
|
||||
+ return PTR_ERR(udoo_class);
|
||||
+ }
|
||||
+
|
||||
+ temp_class = device_create(udoo_class, NULL, MKDEV(major, 0), NULL, "udoo_ard");
|
||||
+ if (IS_ERR(temp_class)) {
|
||||
+ return PTR_ERR(temp_class);
|
||||
+ }
|
||||
+
|
||||
+ printk("[bossac] Created device file /dev/udoo_ard\n");
|
||||
+
|
||||
+ erase_reset_wq = create_workqueue("erase_reset_queue");
|
||||
+ if (erase_reset_wq) {
|
||||
+
|
||||
+ /* Queue some work (item 1) */
|
||||
+ if (work) {
|
||||
+ INIT_WORK( (struct work_struct *)work, erase_reset_wq_function );
|
||||
+ work->step = 1;
|
||||
+ work->cmdcode = 0;
|
||||
+ work->last_int_time_in_ns = 0;
|
||||
+ work->last_int_time_in_sec = 0;
|
||||
+ work->erase_reset_lock = 0;
|
||||
+ // retval = queue_work( erase_reset_wq, (struct work_struct *)work );
|
||||
+ }
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int udoo_ard_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ printk("[bossac] Unloading UDOO ard driver.\n");
|
||||
+ free_irq(gpio_to_irq(work->gpio_bossac_clk), NULL);
|
||||
+
|
||||
+ gpio_free(work->gpio_ard_reset);
|
||||
+ gpio_free(work->gpio_ard_erase);
|
||||
+ gpio_free(work->gpio_bossac_clk);
|
||||
+ gpio_free(work->gpio_bossac_dat);
|
||||
+
|
||||
+ device_destroy(udoo_class, MKDEV(major, 0));
|
||||
+ class_destroy(udoo_class);
|
||||
+ unregister_chrdev(major, "udoo_ard");
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver udoo_ard_driver = {
|
||||
+ .driver = {
|
||||
+ .name = DRIVER_NAME,
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = udoo_ard_dt_ids,
|
||||
+ },
|
||||
+ .id_table = udoo_ard_devtype,
|
||||
+ .probe = udoo_ard_probe,
|
||||
+ .remove = udoo_ard_remove,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(udoo_ard_driver);
|
||||
+
|
||||
+MODULE_ALIAS("platform:"DRIVER_NAME);
|
||||
+MODULE_LICENSE("GPL");
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,11 +0,0 @@
|
||||
--- ./arch/arm/mm/cache-feroceon-l2.c.orig 2013-04-26 13:18:32.000000000 -0600
|
||||
+++ ./arch/arm/mm/cache-feroceon-l2.c 2013-04-28 04:01:09.815592333 -0600
|
||||
@@ -117,7 +117,7 @@ static inline void l2_inv_pa_range(unsig
|
||||
l2_put_va(va_start);
|
||||
}
|
||||
|
||||
-static inline void l2_inv_all(void)
|
||||
+static void l2_inv_all(void)
|
||||
{
|
||||
__asm__("mcr p15, 1, %0, c15, c11, 0" : : "r" (0));
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
--- ./arch/arm/boot/dts/imx6qdl-hummingboard.dtsi.orig 2015-01-08 11:30:41.000000000 -0700
|
||||
+++ ./arch/arm/boot/dts/imx6qdl-hummingboard.dtsi 2015-01-13 14:19:29.696485445 -0700
|
||||
@@ -94,6 +94,31 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
+&i2c3 {
|
||||
+ clock-frequency = <100000>;
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&pinctrl_hummingboard_i2c3>;
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&ecspi2 {
|
||||
+ fsl,spi-num-chipselects = <2>;
|
||||
+ cs-gpios = <&gpio2 26 1>, <&gpio2 27 1>;
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&pinctrl_hummingboard_spi>;
|
||||
+ status = "okay";
|
||||
+ spidev@0x00 {
|
||||
+ compatible = "spidev";
|
||||
+ spi-max-frequency = <5000000>;
|
||||
+ reg = <0>;
|
||||
+ };
|
||||
+ spidev@0x01 {
|
||||
+ compatible = "spidev";
|
||||
+ spi-max-frequency = <5000000>;
|
||||
+ reg = <1>;
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
&iomuxc {
|
||||
hummingboard {
|
||||
pinctrl_hummingboard_flexcan1: hummingboard-flexcan1 {
|
||||
@@ -103,6 +128,17 @@
|
||||
>;
|
||||
};
|
||||
|
||||
+ pinctrl_hummingboard_spi: hummingboard_spi {
|
||||
+ fsl,pins = <
|
||||
+ MX6QDL_PAD_EIM_OE__ECSPI2_MISO 0x100b1
|
||||
+ MX6QDL_PAD_EIM_CS1__ECSPI2_MOSI 0x100b1
|
||||
+ MX6QDL_PAD_EIM_CS0__ECSPI2_SCLK 0x100b1
|
||||
+ /* MX6QDL_PAD_EIM_RW__ECSPI2_SS0 0x100b1 */
|
||||
+ MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x100b1
|
||||
+ MX6QDL_PAD_EIM_LBA__ECSPI2_SS1 0x100b1
|
||||
+ >;
|
||||
+ };
|
||||
+
|
||||
pinctrl_hummingboard_gpio3_5: hummingboard-gpio3_5 {
|
||||
fsl,pins = <
|
||||
MX6QDL_PAD_EIM_DA5__GPIO3_IO05 0x1b0b1
|
||||
@@ -129,6 +165,13 @@
|
||||
>;
|
||||
};
|
||||
|
||||
+ pinctrl_hummingboard_i2c3: hummingboard-i2c3 {
|
||||
+ fsl,pins = <
|
||||
+ MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1
|
||||
+ MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1
|
||||
+ >;
|
||||
+ };
|
||||
+
|
||||
pinctrl_hummingboard_spdif: hummingboard-spdif {
|
||||
fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x13091>;
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
--- ./fs/timerfd.c.orig 2015-11-09 15:37:56.000000000 -0700
|
||||
+++ ./fs/timerfd.c 2015-11-14 08:20:51.720068530 -0700
|
||||
@@ -134,7 +134,7 @@ static void timerfd_setup_cancel(struct
|
||||
{
|
||||
if ((ctx->clockid == CLOCK_REALTIME ||
|
||||
ctx->clockid == CLOCK_REALTIME_ALARM) &&
|
||||
- (flags & TFD_TIMER_ABSTIME) && (flags & TFD_TIMER_CANCEL_ON_SET)) {
|
||||
+ (flags & TFD_TIMER_CANCEL_ON_SET)) {
|
||||
if (!ctx->might_cancel) {
|
||||
ctx->might_cancel = true;
|
||||
spin_lock(&cancel_lock);
|
@ -1,73 +0,0 @@
|
||||
From f5528e96b7dd2b30e1accc518df85d14baad6bae Mon Sep 17 00:00:00 2001
|
||||
From: Peter Chen <peter.chen@nxp.com>
|
||||
Date: Thu, 18 May 2017 08:48:57 +0800
|
||||
Subject: [PATCH 1/9] binding-doc: power: pwrseq-generic: add binding doc for
|
||||
generic power sequence library
|
||||
|
||||
Add binding doc for generic power sequence library.
|
||||
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
|
||||
Acked-by: Rob Herring <robh@kernel.org>
|
||||
---
|
||||
.../bindings/power/pwrseq/pwrseq-generic.txt | 48 +++++++++++++++++++
|
||||
1 file changed, 48 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt b/Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt
|
||||
new file mode 100644
|
||||
index 000000000000..ebf0d477b688
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt
|
||||
@@ -0,0 +1,48 @@
|
||||
+The generic power sequence library
|
||||
+
|
||||
+Some hard-wired devices (eg USB/MMC) need to do power sequence before
|
||||
+the device can be enumerated on the bus, the typical power sequence
|
||||
+like: enable USB PHY clock, toggle reset pin, etc. But current
|
||||
+Linux device driver lacks of such code to do it, it may cause some
|
||||
+hard-wired devices works abnormal or can't be recognized by
|
||||
+controller at all. The power sequence will be done before this device
|
||||
+can be found at the bus.
|
||||
+
|
||||
+The power sequence properties is under the device node.
|
||||
+
|
||||
+Optional properties:
|
||||
+- clocks: the input clocks for device.
|
||||
+- reset-gpios: Should specify the GPIO for reset.
|
||||
+- reset-duration-us: the duration in microsecond for assert reset signal.
|
||||
+
|
||||
+Below is the example of USB power sequence properties on USB device
|
||||
+nodes which have two level USB hubs.
|
||||
+
|
||||
+&usbotg1 {
|
||||
+ vbus-supply = <®_usb_otg1_vbus>;
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&pinctrl_usb_otg1_id>;
|
||||
+ status = "okay";
|
||||
+
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+ genesys: hub@1 {
|
||||
+ compatible = "usb5e3,608";
|
||||
+ reg = <1>;
|
||||
+
|
||||
+ clocks = <&clks IMX6SX_CLK_CKO>;
|
||||
+ reset-gpios = <&gpio4 5 GPIO_ACTIVE_LOW>; /* hub reset pin */
|
||||
+ reset-duration-us = <10>;
|
||||
+
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+ asix: ethernet@1 {
|
||||
+ compatible = "usbb95,1708";
|
||||
+ reg = <1>;
|
||||
+
|
||||
+ clocks = <&clks IMX6SX_CLK_IPG>;
|
||||
+ reset-gpios = <&gpio4 6 GPIO_ACTIVE_LOW>; /* ethernet_rst */
|
||||
+ reset-duration-us = <15>;
|
||||
+ };
|
||||
+ };
|
||||
+};
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,853 +0,0 @@
|
||||
From e42fbf22376c41b275d47b9cfac360c66ee718dc Mon Sep 17 00:00:00 2001
|
||||
From: Peter Chen <peter.chen@nxp.com>
|
||||
Date: Thu, 18 May 2017 08:48:58 +0800
|
||||
Subject: [PATCH 2/9] power: add power sequence library
|
||||
|
||||
We have an well-known problem that the device needs to do some power
|
||||
sequence before it can be recognized by related host, the typical
|
||||
example like hard-wired mmc devices and usb devices.
|
||||
|
||||
This power sequence is hard to be described at device tree and handled by
|
||||
related host driver, so we have created a common power sequence
|
||||
library to cover this requirement. The core code has supplied
|
||||
some common helpers for host driver, and individual power sequence
|
||||
libraries handle kinds of power sequence for devices. The pwrseq
|
||||
librares always need to allocate extra instance for compatible
|
||||
string match.
|
||||
|
||||
pwrseq_generic is intended for general purpose of power sequence, which
|
||||
handles gpios and clocks currently, and can cover other controls in
|
||||
future. The host driver just needs to call of_pwrseq_on/of_pwrseq_off
|
||||
if only one power sequence is needed, else call of_pwrseq_on_list
|
||||
/of_pwrseq_off_list instead (eg, USB hub driver).
|
||||
|
||||
For new power sequence library, it can add its compatible string
|
||||
to pwrseq_of_match_table, then the pwrseq core will match it with
|
||||
DT's, and choose this library at runtime.
|
||||
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
Tested-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
|
||||
Tested-by Joshua Clayton <stillcompiling@gmail.com>
|
||||
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
|
||||
Tested-by: Matthias Kaehlcke <mka@chromium.org>
|
||||
---
|
||||
Documentation/power/power-sequence/design.rst | 54 +++
|
||||
MAINTAINERS | 9 +
|
||||
drivers/power/Kconfig | 1 +
|
||||
drivers/power/Makefile | 1 +
|
||||
drivers/power/pwrseq/Kconfig | 20 ++
|
||||
drivers/power/pwrseq/Makefile | 2 +
|
||||
drivers/power/pwrseq/core.c | 335 ++++++++++++++++++
|
||||
drivers/power/pwrseq/pwrseq_generic.c | 234 ++++++++++++
|
||||
include/linux/power/pwrseq.h | 81 +++++
|
||||
9 files changed, 737 insertions(+)
|
||||
create mode 100644 Documentation/power/power-sequence/design.rst
|
||||
create mode 100644 drivers/power/pwrseq/Kconfig
|
||||
create mode 100644 drivers/power/pwrseq/Makefile
|
||||
create mode 100644 drivers/power/pwrseq/core.c
|
||||
create mode 100644 drivers/power/pwrseq/pwrseq_generic.c
|
||||
create mode 100644 include/linux/power/pwrseq.h
|
||||
|
||||
diff --git a/Documentation/power/power-sequence/design.rst b/Documentation/power/power-sequence/design.rst
|
||||
new file mode 100644
|
||||
index 000000000000..554608e5f3b6
|
||||
--- /dev/null
|
||||
+++ b/Documentation/power/power-sequence/design.rst
|
||||
@@ -0,0 +1,54 @@
|
||||
+====================================
|
||||
+Power Sequence Library
|
||||
+====================================
|
||||
+
|
||||
+:Date: Feb, 2017
|
||||
+:Author: Peter Chen <peter.chen@nxp.com>
|
||||
+
|
||||
+
|
||||
+Introduction
|
||||
+============
|
||||
+
|
||||
+We have an well-known problem that the device needs to do a power
|
||||
+sequence before it can be recognized by related host, the typical
|
||||
+examples are hard-wired mmc devices and usb devices. The host controller
|
||||
+can't know what kinds of this device is in its bus if the power
|
||||
+sequence has not done, since the related devices driver's probe calling
|
||||
+is determined by runtime according to eunumeration results. Besides,
|
||||
+the devices may have custom power sequence, so the power sequence library
|
||||
+which is independent with the devices is needed.
|
||||
+
|
||||
+Design
|
||||
+============
|
||||
+
|
||||
+The power sequence library includes the core file and customer power
|
||||
+sequence library. The core file exports interfaces are called by
|
||||
+host controller driver for power sequence and customer power sequence
|
||||
+library files to register its power sequence instance to global
|
||||
+power sequence list. The custom power sequence library creates power
|
||||
+sequence instance and implement custom power sequence.
|
||||
+
|
||||
+Since the power sequence describes hardware design, the description is
|
||||
+located at board description file, eg, device tree dts file. And
|
||||
+a specific power sequence belongs to device, so its description
|
||||
+is under the device node, please refer to:
|
||||
+Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt
|
||||
+
|
||||
+Custom power sequence library allocates one power sequence instance at
|
||||
+bootup periods using postcore_initcall, this static allocated instance is
|
||||
+used to compare with device-tree (DT) node to see if this library can be
|
||||
+used for the node or not. When the result is matched, the core API will
|
||||
+try to get resourses (->get, implemented at each library) for power
|
||||
+sequence, if all resources are got, it will try to allocate another
|
||||
+instance for next possible request from host driver.
|
||||
+
|
||||
+Then, the host controller driver can carry out power sequence on for this
|
||||
+DT node, the library will do corresponding operations, like open clocks,
|
||||
+toggle gpio, etc. The power sequence off routine will close and free the
|
||||
+resources, and is called when the parent is removed. And the power
|
||||
+sequence suspend and resume routine can be called at host driver's
|
||||
+suspend and resume routine if needed.
|
||||
+
|
||||
+The exported interfaces
|
||||
+.. kernel-doc:: drivers/power/pwrseq/core.c
|
||||
+ :export:
|
||||
diff --git a/MAINTAINERS b/MAINTAINERS
|
||||
index 429c6c624861..88fd31d1870f 100644
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -12599,6 +12599,15 @@ F: drivers/firmware/psci/
|
||||
F: include/linux/psci.h
|
||||
F: include/uapi/linux/psci.h
|
||||
|
||||
+POWER SEQUENCE LIBRARY
|
||||
+M: Peter Chen <Peter.Chen@nxp.com>
|
||||
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git
|
||||
+L: linux-pm@vger.kernel.org
|
||||
+S: Maintained
|
||||
+F: Documentation/devicetree/bindings/power/pwrseq/
|
||||
+F: drivers/power/pwrseq/
|
||||
+F: include/linux/power/pwrseq.h
|
||||
+
|
||||
POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS
|
||||
M: Sebastian Reichel <sre@kernel.org>
|
||||
L: linux-pm@vger.kernel.org
|
||||
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
|
||||
index ff0350ca3b74..78b6fa270cf9 100644
|
||||
--- a/drivers/power/Kconfig
|
||||
+++ b/drivers/power/Kconfig
|
||||
@@ -2,3 +2,4 @@
|
||||
source "drivers/power/avs/Kconfig"
|
||||
source "drivers/power/reset/Kconfig"
|
||||
source "drivers/power/supply/Kconfig"
|
||||
+source "drivers/power/pwrseq/Kconfig"
|
||||
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
|
||||
index b7c2e372186b..13046c7fb499 100644
|
||||
--- a/drivers/power/Makefile
|
||||
+++ b/drivers/power/Makefile
|
||||
@@ -2,3 +2,4 @@
|
||||
obj-$(CONFIG_POWER_AVS) += avs/
|
||||
obj-$(CONFIG_POWER_RESET) += reset/
|
||||
obj-$(CONFIG_POWER_SUPPLY) += supply/
|
||||
+obj-$(CONFIG_POWER_SEQUENCE) += pwrseq/
|
||||
diff --git a/drivers/power/pwrseq/Kconfig b/drivers/power/pwrseq/Kconfig
|
||||
new file mode 100644
|
||||
index 000000000000..c6b356926cca
|
||||
--- /dev/null
|
||||
+++ b/drivers/power/pwrseq/Kconfig
|
||||
@@ -0,0 +1,20 @@
|
||||
+#
|
||||
+# Power Sequence library
|
||||
+#
|
||||
+
|
||||
+menuconfig POWER_SEQUENCE
|
||||
+ bool "Power sequence control"
|
||||
+ help
|
||||
+ It is used for drivers which needs to do power sequence
|
||||
+ (eg, turn on clock, toggle reset gpio) before the related
|
||||
+ devices can be found by hardware, eg, USB bus.
|
||||
+
|
||||
+if POWER_SEQUENCE
|
||||
+
|
||||
+config PWRSEQ_GENERIC
|
||||
+ bool "Generic power sequence control"
|
||||
+ depends on OF
|
||||
+ help
|
||||
+ This is the generic power sequence control library, and is
|
||||
+ supposed to support common power sequence usage.
|
||||
+endif
|
||||
diff --git a/drivers/power/pwrseq/Makefile b/drivers/power/pwrseq/Makefile
|
||||
new file mode 100644
|
||||
index 000000000000..ad82389028c2
|
||||
--- /dev/null
|
||||
+++ b/drivers/power/pwrseq/Makefile
|
||||
@@ -0,0 +1,2 @@
|
||||
+obj-$(CONFIG_POWER_SEQUENCE) += core.o
|
||||
+obj-$(CONFIG_PWRSEQ_GENERIC) += pwrseq_generic.o
|
||||
diff --git a/drivers/power/pwrseq/core.c b/drivers/power/pwrseq/core.c
|
||||
new file mode 100644
|
||||
index 000000000000..3d19e62a2e76
|
||||
--- /dev/null
|
||||
+++ b/drivers/power/pwrseq/core.c
|
||||
@@ -0,0 +1,335 @@
|
||||
+/*
|
||||
+ * core.c power sequence core file
|
||||
+ *
|
||||
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
|
||||
+ * Author: Peter Chen <peter.chen@nxp.com>
|
||||
+ *
|
||||
+ * This program is free software: you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 of
|
||||
+ * the License as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/list.h>
|
||||
+#include <linux/mutex.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/power/pwrseq.h>
|
||||
+
|
||||
+static DEFINE_MUTEX(pwrseq_list_mutex);
|
||||
+static LIST_HEAD(pwrseq_list);
|
||||
+
|
||||
+static int pwrseq_get(struct device_node *np, struct pwrseq *p)
|
||||
+{
|
||||
+ if (p && p->get)
|
||||
+ return p->get(np, p);
|
||||
+
|
||||
+ return -ENOTSUPP;
|
||||
+}
|
||||
+
|
||||
+static int pwrseq_on(struct pwrseq *p)
|
||||
+{
|
||||
+ if (p && p->on)
|
||||
+ return p->on(p);
|
||||
+
|
||||
+ return -ENOTSUPP;
|
||||
+}
|
||||
+
|
||||
+static void pwrseq_off(struct pwrseq *p)
|
||||
+{
|
||||
+ if (p && p->off)
|
||||
+ p->off(p);
|
||||
+}
|
||||
+
|
||||
+static void pwrseq_put(struct pwrseq *p)
|
||||
+{
|
||||
+ if (p && p->put)
|
||||
+ p->put(p);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_register - Add pwrseq instance to global pwrseq list
|
||||
+ *
|
||||
+ * @pwrseq: the pwrseq instance
|
||||
+ */
|
||||
+void pwrseq_register(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ mutex_lock(&pwrseq_list_mutex);
|
||||
+ list_add(&pwrseq->node, &pwrseq_list);
|
||||
+ mutex_unlock(&pwrseq_list_mutex);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_register);
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_unregister - Remove pwrseq instance from global pwrseq list
|
||||
+ *
|
||||
+ * @pwrseq: the pwrseq instance
|
||||
+ */
|
||||
+void pwrseq_unregister(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ mutex_lock(&pwrseq_list_mutex);
|
||||
+ list_del(&pwrseq->node);
|
||||
+ mutex_unlock(&pwrseq_list_mutex);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_unregister);
|
||||
+
|
||||
+static struct pwrseq *pwrseq_find_available_instance(struct device_node *np)
|
||||
+{
|
||||
+ struct pwrseq *pwrseq;
|
||||
+
|
||||
+ mutex_lock(&pwrseq_list_mutex);
|
||||
+ list_for_each_entry(pwrseq, &pwrseq_list, node) {
|
||||
+ if (pwrseq->used)
|
||||
+ continue;
|
||||
+
|
||||
+ /* compare compatible string for pwrseq node */
|
||||
+ if (of_match_node(pwrseq->pwrseq_of_match_table, np)) {
|
||||
+ pwrseq->used = true;
|
||||
+ mutex_unlock(&pwrseq_list_mutex);
|
||||
+ return pwrseq;
|
||||
+ }
|
||||
+
|
||||
+ /* return generic pwrseq instance */
|
||||
+ if (!strcmp(pwrseq->pwrseq_of_match_table->compatible,
|
||||
+ "generic")) {
|
||||
+ pr_debug("using generic pwrseq instance for %s\n",
|
||||
+ np->full_name);
|
||||
+ pwrseq->used = true;
|
||||
+ mutex_unlock(&pwrseq_list_mutex);
|
||||
+ return pwrseq;
|
||||
+ }
|
||||
+ }
|
||||
+ mutex_unlock(&pwrseq_list_mutex);
|
||||
+ pr_debug("Can't find any pwrseq instances for %s\n", np->full_name);
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * of_pwrseq_on - Carry out power sequence on for device node
|
||||
+ *
|
||||
+ * @np: the device node would like to power on
|
||||
+ *
|
||||
+ * Carry out a single device power on. If multiple devices
|
||||
+ * need to be handled, use of_pwrseq_on_list() instead.
|
||||
+ *
|
||||
+ * Return a pointer to the power sequence instance on success,
|
||||
+ * or an error code otherwise.
|
||||
+ */
|
||||
+struct pwrseq *of_pwrseq_on(struct device_node *np)
|
||||
+{
|
||||
+ struct pwrseq *pwrseq;
|
||||
+ int ret;
|
||||
+
|
||||
+ pwrseq = pwrseq_find_available_instance(np);
|
||||
+ if (!pwrseq)
|
||||
+ return ERR_PTR(-ENOENT);
|
||||
+
|
||||
+ ret = pwrseq_get(np, pwrseq);
|
||||
+ if (ret) {
|
||||
+ /* Mark current pwrseq as unused */
|
||||
+ pwrseq->used = false;
|
||||
+ return ERR_PTR(ret);
|
||||
+ }
|
||||
+
|
||||
+ ret = pwrseq_on(pwrseq);
|
||||
+ if (ret)
|
||||
+ goto pwr_put;
|
||||
+
|
||||
+ return pwrseq;
|
||||
+
|
||||
+pwr_put:
|
||||
+ pwrseq_put(pwrseq);
|
||||
+ return ERR_PTR(ret);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(of_pwrseq_on);
|
||||
+
|
||||
+/**
|
||||
+ * of_pwrseq_off - Carry out power sequence off for this pwrseq instance
|
||||
+ *
|
||||
+ * @pwrseq: the pwrseq instance which related device would like to be off
|
||||
+ *
|
||||
+ * This API is used to power off single device, it is the opposite
|
||||
+ * operation for of_pwrseq_on.
|
||||
+ */
|
||||
+void of_pwrseq_off(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ pwrseq_off(pwrseq);
|
||||
+ pwrseq_put(pwrseq);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(of_pwrseq_off);
|
||||
+
|
||||
+/**
|
||||
+ * of_pwrseq_on_list - Carry out power sequence on for list
|
||||
+ *
|
||||
+ * @np: the device node would like to power on
|
||||
+ * @head: the list head for pwrseq list on this bus
|
||||
+ *
|
||||
+ * This API is used to power on multiple devices at single bus.
|
||||
+ * If there are several devices on bus (eg, USB bus), uses this
|
||||
+ * this API. Otherwise, use of_pwrseq_on instead. After the device
|
||||
+ * is powered on successfully, it will be added to pwrseq list for
|
||||
+ * this bus. The caller needs to use mutex_lock for concurrent.
|
||||
+ *
|
||||
+ * Return 0 on success, or an error value otherwise.
|
||||
+ */
|
||||
+int of_pwrseq_on_list(struct device_node *np, struct list_head *head)
|
||||
+{
|
||||
+ struct pwrseq *pwrseq;
|
||||
+ struct pwrseq_list_per_dev *pwrseq_list_node;
|
||||
+
|
||||
+ pwrseq_list_node = kzalloc(sizeof(*pwrseq_list_node), GFP_KERNEL);
|
||||
+ if (!pwrseq_list_node)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ pwrseq = of_pwrseq_on(np);
|
||||
+ if (IS_ERR(pwrseq)) {
|
||||
+ kfree(pwrseq_list_node);
|
||||
+ return PTR_ERR(pwrseq);
|
||||
+ }
|
||||
+
|
||||
+ pwrseq_list_node->pwrseq = pwrseq;
|
||||
+ list_add(&pwrseq_list_node->list, head);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(of_pwrseq_on_list);
|
||||
+
|
||||
+/**
|
||||
+ * of_pwrseq_off_list - Carry out power sequence off for the list
|
||||
+ *
|
||||
+ * @head: the list head for pwrseq instance list on this bus
|
||||
+ *
|
||||
+ * This API is used to power off all devices on this bus, it is
|
||||
+ * the opposite operation for of_pwrseq_on_list.
|
||||
+ * The caller needs to use mutex_lock for concurrent.
|
||||
+ */
|
||||
+void of_pwrseq_off_list(struct list_head *head)
|
||||
+{
|
||||
+ struct pwrseq *pwrseq;
|
||||
+ struct pwrseq_list_per_dev *pwrseq_list_node, *tmp_node;
|
||||
+
|
||||
+ list_for_each_entry_safe(pwrseq_list_node, tmp_node, head, list) {
|
||||
+ pwrseq = pwrseq_list_node->pwrseq;
|
||||
+ of_pwrseq_off(pwrseq);
|
||||
+ list_del(&pwrseq_list_node->list);
|
||||
+ kfree(pwrseq_list_node);
|
||||
+ }
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(of_pwrseq_off_list);
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_suspend - Carry out power sequence suspend for this pwrseq instance
|
||||
+ *
|
||||
+ * @pwrseq: the pwrseq instance
|
||||
+ *
|
||||
+ * This API is used to do suspend operation on pwrseq instance.
|
||||
+ *
|
||||
+ * Return 0 on success, or an error value otherwise.
|
||||
+ */
|
||||
+int pwrseq_suspend(struct pwrseq *p)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ if (p && p->suspend)
|
||||
+ ret = p->suspend(p);
|
||||
+ else
|
||||
+ return ret;
|
||||
+
|
||||
+ if (!ret)
|
||||
+ p->suspended = true;
|
||||
+ else
|
||||
+ pr_err("%s failed\n", __func__);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_suspend);
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_resume - Carry out power sequence resume for this pwrseq instance
|
||||
+ *
|
||||
+ * @pwrseq: the pwrseq instance
|
||||
+ *
|
||||
+ * This API is used to do resume operation on pwrseq instance.
|
||||
+ *
|
||||
+ * Return 0 on success, or an error value otherwise.
|
||||
+ */
|
||||
+int pwrseq_resume(struct pwrseq *p)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ if (p && p->resume)
|
||||
+ ret = p->resume(p);
|
||||
+ else
|
||||
+ return ret;
|
||||
+
|
||||
+ if (!ret)
|
||||
+ p->suspended = false;
|
||||
+ else
|
||||
+ pr_err("%s failed\n", __func__);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_resume);
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_suspend_list - Carry out power sequence suspend for list
|
||||
+ *
|
||||
+ * @head: the list head for pwrseq instance list on this bus
|
||||
+ *
|
||||
+ * This API is used to do suspend on all power sequence instances on this bus.
|
||||
+ * The caller needs to use mutex_lock for concurrent.
|
||||
+ */
|
||||
+int pwrseq_suspend_list(struct list_head *head)
|
||||
+{
|
||||
+ struct pwrseq *pwrseq;
|
||||
+ struct pwrseq_list_per_dev *pwrseq_list_node;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ list_for_each_entry(pwrseq_list_node, head, list) {
|
||||
+ ret = pwrseq_suspend(pwrseq_list_node->pwrseq);
|
||||
+ if (ret)
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (ret) {
|
||||
+ list_for_each_entry(pwrseq_list_node, head, list) {
|
||||
+ pwrseq = pwrseq_list_node->pwrseq;
|
||||
+ if (pwrseq->suspended)
|
||||
+ pwrseq_resume(pwrseq);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_suspend_list);
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_resume_list - Carry out power sequence resume for the list
|
||||
+ *
|
||||
+ * @head: the list head for pwrseq instance list on this bus
|
||||
+ *
|
||||
+ * This API is used to do resume on all power sequence instances on this bus.
|
||||
+ * The caller needs to use mutex_lock for concurrent.
|
||||
+ */
|
||||
+int pwrseq_resume_list(struct list_head *head)
|
||||
+{
|
||||
+ struct pwrseq_list_per_dev *pwrseq_list_node;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ list_for_each_entry(pwrseq_list_node, head, list) {
|
||||
+ ret = pwrseq_resume(pwrseq_list_node->pwrseq);
|
||||
+ if (ret)
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_resume_list);
|
||||
diff --git a/drivers/power/pwrseq/pwrseq_generic.c b/drivers/power/pwrseq/pwrseq_generic.c
|
||||
new file mode 100644
|
||||
index 000000000000..4e7c09086cfb
|
||||
--- /dev/null
|
||||
+++ b/drivers/power/pwrseq/pwrseq_generic.c
|
||||
@@ -0,0 +1,234 @@
|
||||
+/*
|
||||
+ * pwrseq_generic.c Generic power sequence handling
|
||||
+ *
|
||||
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
|
||||
+ * Author: Peter Chen <peter.chen@nxp.com>
|
||||
+ *
|
||||
+ * This program is free software: you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 of
|
||||
+ * the License as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/gpio.h>
|
||||
+#include <linux/gpio/consumer.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/of_gpio.h>
|
||||
+#include <linux/slab.h>
|
||||
+
|
||||
+#include <linux/power/pwrseq.h>
|
||||
+
|
||||
+struct pwrseq_generic {
|
||||
+ struct pwrseq pwrseq;
|
||||
+ struct gpio_desc *gpiod_reset;
|
||||
+ struct clk *clks[PWRSEQ_MAX_CLKS];
|
||||
+ u32 duration_us;
|
||||
+ bool suspended;
|
||||
+};
|
||||
+
|
||||
+#define to_generic_pwrseq(p) container_of(p, struct pwrseq_generic, pwrseq)
|
||||
+
|
||||
+static int pwrseq_generic_alloc_instance(void);
|
||||
+static const struct of_device_id generic_id_table[] = {
|
||||
+ { .compatible = "generic",},
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+
|
||||
+static int pwrseq_generic_suspend(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ int clk;
|
||||
+
|
||||
+ for (clk = PWRSEQ_MAX_CLKS - 1; clk >= 0; clk--)
|
||||
+ clk_disable_unprepare(pwrseq_gen->clks[clk]);
|
||||
+
|
||||
+ pwrseq_gen->suspended = true;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int pwrseq_generic_resume(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ int clk, ret = 0;
|
||||
+
|
||||
+ for (clk = 0; clk < PWRSEQ_MAX_CLKS && pwrseq_gen->clks[clk]; clk++) {
|
||||
+ ret = clk_prepare_enable(pwrseq_gen->clks[clk]);
|
||||
+ if (ret) {
|
||||
+ pr_err("Can't enable clock, ret=%d\n", ret);
|
||||
+ goto err_disable_clks;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ pwrseq_gen->suspended = false;
|
||||
+ return ret;
|
||||
+
|
||||
+err_disable_clks:
|
||||
+ while (--clk >= 0)
|
||||
+ clk_disable_unprepare(pwrseq_gen->clks[clk]);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void pwrseq_generic_put(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ int clk;
|
||||
+
|
||||
+ if (pwrseq_gen->gpiod_reset)
|
||||
+ gpiod_put(pwrseq_gen->gpiod_reset);
|
||||
+
|
||||
+ for (clk = 0; clk < PWRSEQ_MAX_CLKS; clk++)
|
||||
+ clk_put(pwrseq_gen->clks[clk]);
|
||||
+
|
||||
+ pwrseq_unregister(&pwrseq_gen->pwrseq);
|
||||
+ kfree(pwrseq_gen);
|
||||
+}
|
||||
+
|
||||
+static void pwrseq_generic_off(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ int clk;
|
||||
+
|
||||
+ if (pwrseq_gen->suspended)
|
||||
+ return;
|
||||
+
|
||||
+ for (clk = PWRSEQ_MAX_CLKS - 1; clk >= 0; clk--)
|
||||
+ clk_disable_unprepare(pwrseq_gen->clks[clk]);
|
||||
+}
|
||||
+
|
||||
+static int pwrseq_generic_on(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ int clk, ret = 0;
|
||||
+ struct gpio_desc *gpiod_reset = pwrseq_gen->gpiod_reset;
|
||||
+
|
||||
+ for (clk = 0; clk < PWRSEQ_MAX_CLKS && pwrseq_gen->clks[clk]; clk++) {
|
||||
+ ret = clk_prepare_enable(pwrseq_gen->clks[clk]);
|
||||
+ if (ret) {
|
||||
+ pr_err("Can't enable clock, ret=%d\n", ret);
|
||||
+ goto err_disable_clks;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (gpiod_reset) {
|
||||
+ u32 duration_us = pwrseq_gen->duration_us;
|
||||
+
|
||||
+ if (duration_us <= 10)
|
||||
+ udelay(10);
|
||||
+ else
|
||||
+ usleep_range(duration_us, duration_us + 100);
|
||||
+ gpiod_set_value(gpiod_reset, 0);
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+
|
||||
+err_disable_clks:
|
||||
+ while (--clk >= 0)
|
||||
+ clk_disable_unprepare(pwrseq_gen->clks[clk]);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int pwrseq_generic_get(struct device_node *np, struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ enum of_gpio_flags flags;
|
||||
+ int reset_gpio, clk, ret = 0;
|
||||
+
|
||||
+ for (clk = 0; clk < PWRSEQ_MAX_CLKS; clk++) {
|
||||
+ pwrseq_gen->clks[clk] = of_clk_get(np, clk);
|
||||
+ if (IS_ERR(pwrseq_gen->clks[clk])) {
|
||||
+ ret = PTR_ERR(pwrseq_gen->clks[clk]);
|
||||
+ if (ret != -ENOENT)
|
||||
+ goto err_put_clks;
|
||||
+ pwrseq_gen->clks[clk] = NULL;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ reset_gpio = of_get_named_gpio_flags(np, "reset-gpios", 0, &flags);
|
||||
+ if (gpio_is_valid(reset_gpio)) {
|
||||
+ unsigned long gpio_flags;
|
||||
+
|
||||
+ if (flags & OF_GPIO_ACTIVE_LOW)
|
||||
+ gpio_flags = GPIOF_ACTIVE_LOW | GPIOF_OUT_INIT_LOW;
|
||||
+ else
|
||||
+ gpio_flags = GPIOF_OUT_INIT_HIGH;
|
||||
+
|
||||
+ ret = gpio_request_one(reset_gpio, gpio_flags,
|
||||
+ "pwrseq-reset-gpios");
|
||||
+ if (ret)
|
||||
+ goto err_put_clks;
|
||||
+
|
||||
+ pwrseq_gen->gpiod_reset = gpio_to_desc(reset_gpio);
|
||||
+ of_property_read_u32(np, "reset-duration-us",
|
||||
+ &pwrseq_gen->duration_us);
|
||||
+ } else if (reset_gpio == -ENOENT) {
|
||||
+ ; /* no such gpio */
|
||||
+ } else {
|
||||
+ ret = reset_gpio;
|
||||
+ pr_err("Failed to get reset gpio on %s, err = %d\n",
|
||||
+ np->full_name, reset_gpio);
|
||||
+ goto err_put_clks;
|
||||
+ }
|
||||
+
|
||||
+ /* allocate new one for later pwrseq instance request */
|
||||
+ ret = pwrseq_generic_alloc_instance();
|
||||
+ if (ret)
|
||||
+ goto err_put_gpio;
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_put_gpio:
|
||||
+ if (pwrseq_gen->gpiod_reset)
|
||||
+ gpiod_put(pwrseq_gen->gpiod_reset);
|
||||
+err_put_clks:
|
||||
+ while (--clk >= 0)
|
||||
+ clk_put(pwrseq_gen->clks[clk]);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_generic_alloc_instance - power sequence instance allocation
|
||||
+ *
|
||||
+ * This function is used to allocate one generic power sequence instance,
|
||||
+ * it is called when the system boots up and after one power sequence
|
||||
+ * instance is got successfully.
|
||||
+ *
|
||||
+ * Return zero on success or an error code otherwise.
|
||||
+ */
|
||||
+static int pwrseq_generic_alloc_instance(void)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen;
|
||||
+
|
||||
+ pwrseq_gen = kzalloc(sizeof(*pwrseq_gen), GFP_KERNEL);
|
||||
+ if (!pwrseq_gen)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ pwrseq_gen->pwrseq.pwrseq_of_match_table = generic_id_table;
|
||||
+ pwrseq_gen->pwrseq.get = pwrseq_generic_get;
|
||||
+ pwrseq_gen->pwrseq.on = pwrseq_generic_on;
|
||||
+ pwrseq_gen->pwrseq.off = pwrseq_generic_off;
|
||||
+ pwrseq_gen->pwrseq.put = pwrseq_generic_put;
|
||||
+ pwrseq_gen->pwrseq.suspend = pwrseq_generic_suspend;
|
||||
+ pwrseq_gen->pwrseq.resume = pwrseq_generic_resume;
|
||||
+
|
||||
+ pwrseq_register(&pwrseq_gen->pwrseq);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Allocate one pwrseq instance during boots up */
|
||||
+static int __init pwrseq_generic_register(void)
|
||||
+{
|
||||
+ return pwrseq_generic_alloc_instance();
|
||||
+}
|
||||
+postcore_initcall(pwrseq_generic_register)
|
||||
diff --git a/include/linux/power/pwrseq.h b/include/linux/power/pwrseq.h
|
||||
new file mode 100644
|
||||
index 000000000000..cbc344cdf9d2
|
||||
--- /dev/null
|
||||
+++ b/include/linux/power/pwrseq.h
|
||||
@@ -0,0 +1,81 @@
|
||||
+#ifndef __LINUX_PWRSEQ_H
|
||||
+#define __LINUX_PWRSEQ_H
|
||||
+
|
||||
+#include <linux/of.h>
|
||||
+
|
||||
+#define PWRSEQ_MAX_CLKS 3
|
||||
+
|
||||
+/**
|
||||
+ * struct pwrseq - the power sequence structure
|
||||
+ * @pwrseq_of_match_table: the OF device id table this pwrseq library supports
|
||||
+ * @node: the list pointer to be added to pwrseq list
|
||||
+ * @get: the API is used to get pwrseq instance from the device node
|
||||
+ * @on: do power on for this pwrseq instance
|
||||
+ * @off: do power off for this pwrseq instance
|
||||
+ * @put: release the resources on this pwrseq instance
|
||||
+ * @suspend: do suspend operation on this pwrseq instance
|
||||
+ * @resume: do resume operation on this pwrseq instance
|
||||
+ * @used: this pwrseq instance is used by device
|
||||
+ */
|
||||
+struct pwrseq {
|
||||
+ const struct of_device_id *pwrseq_of_match_table;
|
||||
+ struct list_head node;
|
||||
+ int (*get)(struct device_node *np, struct pwrseq *p);
|
||||
+ int (*on)(struct pwrseq *p);
|
||||
+ void (*off)(struct pwrseq *p);
|
||||
+ void (*put)(struct pwrseq *p);
|
||||
+ int (*suspend)(struct pwrseq *p);
|
||||
+ int (*resume)(struct pwrseq *p);
|
||||
+ bool used;
|
||||
+ bool suspended;
|
||||
+};
|
||||
+
|
||||
+/* used for power sequence instance list in one driver */
|
||||
+struct pwrseq_list_per_dev {
|
||||
+ struct pwrseq *pwrseq;
|
||||
+ struct list_head list;
|
||||
+};
|
||||
+
|
||||
+#if IS_ENABLED(CONFIG_POWER_SEQUENCE)
|
||||
+void pwrseq_register(struct pwrseq *pwrseq);
|
||||
+void pwrseq_unregister(struct pwrseq *pwrseq);
|
||||
+struct pwrseq *of_pwrseq_on(struct device_node *np);
|
||||
+void of_pwrseq_off(struct pwrseq *pwrseq);
|
||||
+int of_pwrseq_on_list(struct device_node *np, struct list_head *head);
|
||||
+void of_pwrseq_off_list(struct list_head *head);
|
||||
+int pwrseq_suspend(struct pwrseq *p);
|
||||
+int pwrseq_resume(struct pwrseq *p);
|
||||
+int pwrseq_suspend_list(struct list_head *head);
|
||||
+int pwrseq_resume_list(struct list_head *head);
|
||||
+#else
|
||||
+static inline void pwrseq_register(struct pwrseq *pwrseq) {}
|
||||
+static inline void pwrseq_unregister(struct pwrseq *pwrseq) {}
|
||||
+static inline struct pwrseq *of_pwrseq_on(struct device_node *np)
|
||||
+{
|
||||
+ return NULL;
|
||||
+}
|
||||
+static void of_pwrseq_off(struct pwrseq *pwrseq) {}
|
||||
+static int of_pwrseq_on_list(struct device_node *np, struct list_head *head)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+static void of_pwrseq_off_list(struct list_head *head) {}
|
||||
+static int pwrseq_suspend(struct pwrseq *p)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+static int pwrseq_resume(struct pwrseq *p)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+static int pwrseq_suspend_list(struct list_head *head)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+static int pwrseq_resume_list(struct list_head *head)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif /* CONFIG_POWER_SEQUENCE */
|
||||
+
|
||||
+#endif /* __LINUX_PWRSEQ_H */
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,165 +0,0 @@
|
||||
From a42362841fe263a6c97a1793ccd4b9246ac2b108 Mon Sep 17 00:00:00 2001
|
||||
From: Peter Chen <peter.chen@nxp.com>
|
||||
Date: Thu, 18 May 2017 08:49:00 +0800
|
||||
Subject: [PATCH 4/9] usb: core: add power sequence handling for USB devices
|
||||
|
||||
Some hard-wired USB devices need to do power sequence to let the
|
||||
device work normally, the typical power sequence like: enable USB
|
||||
PHY clock, toggle reset pin, etc. But current Linux USB driver
|
||||
lacks of such code to do it, it may cause some hard-wired USB devices
|
||||
works abnormal or can't be recognized by controller at all.
|
||||
|
||||
In this patch, it calls power sequence library APIs to finish
|
||||
the power sequence events. It will do power on sequence at hub's
|
||||
probe for all devices under this hub (includes root hub).
|
||||
At hub_disconnect, it will do power off sequence which is at powered
|
||||
on list.
|
||||
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
Tested-by Joshua Clayton <stillcompiling@gmail.com>
|
||||
Tested-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
|
||||
Reviewed-by: Vaibhav Hiremath <hvaibhav.linux@gmail.com>
|
||||
---
|
||||
drivers/usb/Kconfig | 1 +
|
||||
drivers/usb/core/hub.c | 49 ++++++++++++++++++++++++++++++++++++++----
|
||||
drivers/usb/core/hub.h | 1 +
|
||||
3 files changed, 47 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
|
||||
index 6e59d370ef81..2162fd85b32d 100644
|
||||
--- a/drivers/usb/Kconfig
|
||||
+++ b/drivers/usb/Kconfig
|
||||
@@ -47,6 +47,7 @@ config USB
|
||||
depends on USB_ARCH_HAS_HCD
|
||||
select GENERIC_ALLOCATOR
|
||||
select USB_COMMON
|
||||
+ select POWER_SEQUENCE
|
||||
select NLS # for UTF-8 strings
|
||||
---help---
|
||||
Universal Serial Bus (USB) is a specification for a serial bus
|
||||
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
|
||||
index 236313f41f4a..3db75b0d2426 100644
|
||||
--- a/drivers/usb/core/hub.c
|
||||
+++ b/drivers/usb/core/hub.c
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <linux/random.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/kobject.h>
|
||||
+#include <linux/power/pwrseq.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/byteorder.h>
|
||||
@@ -1705,6 +1706,7 @@ static void hub_disconnect(struct usb_interface *intf)
|
||||
hub->error = 0;
|
||||
hub_quiesce(hub, HUB_DISCONNECT);
|
||||
|
||||
+ of_pwrseq_off_list(&hub->pwrseq_on_list);
|
||||
mutex_lock(&usb_port_peer_mutex);
|
||||
|
||||
/* Avoid races with recursively_mark_NOTATTACHED() */
|
||||
@@ -1751,11 +1753,41 @@ static bool hub_descriptor_is_sane(struct usb_host_interface *desc)
|
||||
return true;
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_OF
|
||||
+static int hub_of_pwrseq_on(struct usb_hub *hub)
|
||||
+{
|
||||
+ struct device *parent;
|
||||
+ struct usb_device *hdev = hub->hdev;
|
||||
+ struct device_node *np;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (hdev->parent)
|
||||
+ parent = &hdev->dev;
|
||||
+ else
|
||||
+ parent = bus_to_hcd(hdev->bus)->self.sysdev;
|
||||
+
|
||||
+ for_each_child_of_node(parent->of_node, np) {
|
||||
+ ret = of_pwrseq_on_list(np, &hub->pwrseq_on_list);
|
||||
+ /* Maybe no power sequence library is chosen */
|
||||
+ if (ret && ret != -ENOENT)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+#else
|
||||
+static int hub_of_pwrseq_on(struct usb_hub *hub)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_host_interface *desc;
|
||||
struct usb_device *hdev;
|
||||
struct usb_hub *hub;
|
||||
+ int ret = -ENODEV;
|
||||
|
||||
desc = intf->cur_altsetting;
|
||||
hdev = interface_to_usbdev(intf);
|
||||
@@ -1846,6 +1878,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
INIT_DELAYED_WORK(&hub->leds, led_work);
|
||||
INIT_DELAYED_WORK(&hub->init_work, NULL);
|
||||
INIT_WORK(&hub->events, hub_event);
|
||||
+ INIT_LIST_HEAD(&hub->pwrseq_on_list);
|
||||
spin_lock_init(&hub->irq_urb_lock);
|
||||
timer_setup(&hub->irq_urb_retry, hub_retry_irq_urb, 0);
|
||||
usb_get_intf(intf);
|
||||
@@ -1861,11 +1894,14 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
if (id->driver_info & HUB_QUIRK_CHECK_PORT_AUTOSUSPEND)
|
||||
hub->quirk_check_port_auto_suspend = 1;
|
||||
|
||||
- if (hub_configure(hub, &desc->endpoint[0].desc) >= 0)
|
||||
- return 0;
|
||||
+ if (hub_configure(hub, &desc->endpoint[0].desc) >= 0) {
|
||||
+ ret = hub_of_pwrseq_on(hub);
|
||||
+ if (!ret)
|
||||
+ return 0;
|
||||
+ }
|
||||
|
||||
hub_disconnect(intf);
|
||||
- return -ENODEV;
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -3720,7 +3756,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
|
||||
|
||||
/* stop hub_wq and related activity */
|
||||
hub_quiesce(hub, HUB_SUSPEND);
|
||||
- return 0;
|
||||
+ return pwrseq_suspend_list(&hub->pwrseq_on_list);
|
||||
}
|
||||
|
||||
/* Report wakeup requests from the ports of a resuming root hub */
|
||||
@@ -3760,8 +3796,13 @@ static void report_wakeup_requests(struct usb_hub *hub)
|
||||
static int hub_resume(struct usb_interface *intf)
|
||||
{
|
||||
struct usb_hub *hub = usb_get_intfdata(intf);
|
||||
+ int ret;
|
||||
|
||||
dev_dbg(&intf->dev, "%s\n", __func__);
|
||||
+ ret = pwrseq_resume_list(&hub->pwrseq_on_list);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
hub_activate(hub, HUB_RESUME);
|
||||
|
||||
/*
|
||||
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
|
||||
index a9e24e4b8df1..feab956a1414 100644
|
||||
--- a/drivers/usb/core/hub.h
|
||||
+++ b/drivers/usb/core/hub.h
|
||||
@@ -72,6 +72,7 @@ struct usb_hub {
|
||||
spinlock_t irq_urb_lock;
|
||||
struct timer_list irq_urb_retry;
|
||||
struct usb_port **ports;
|
||||
+ struct list_head pwrseq_on_list; /* powered pwrseq node list */
|
||||
};
|
||||
|
||||
/**
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,49 +0,0 @@
|
||||
From bf1b3a63aa2f3438750f5acdf372705f8a1beb41 Mon Sep 17 00:00:00 2001
|
||||
From: Joshua Clayton <stillcompiling@gmail.com>
|
||||
Date: Thu, 18 May 2017 08:49:01 +0800
|
||||
Subject: [PATCH 5/9] ARM: dts: imx6qdl: Enable usb node children with <reg>
|
||||
|
||||
Give usb nodes #address and #size attributes, so that a child node
|
||||
representing a permanently connected device such as an onboard hub may
|
||||
be addressed with a <reg> attribute
|
||||
|
||||
Signed-off-by: Joshua Clayton <stillcompiling@gmail.com>
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
---
|
||||
arch/arm/boot/dts/imx6qdl.dtsi | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
|
||||
index fe17a3405edc..a5f2f981255f 100644
|
||||
--- a/arch/arm/boot/dts/imx6qdl.dtsi
|
||||
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
|
||||
@@ -977,6 +977,8 @@
|
||||
|
||||
usbh1: usb@2184200 {
|
||||
compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
reg = <0x02184200 0x200>;
|
||||
interrupts = <0 40 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX6QDL_CLK_USBOH3>;
|
||||
@@ -991,6 +993,8 @@
|
||||
|
||||
usbh2: usb@2184400 {
|
||||
compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
reg = <0x02184400 0x200>;
|
||||
interrupts = <0 41 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX6QDL_CLK_USBOH3>;
|
||||
@@ -1006,6 +1010,8 @@
|
||||
|
||||
usbh3: usb@2184600 {
|
||||
compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
reg = <0x02184600 0x200>;
|
||||
interrupts = <0 42 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX6QDL_CLK_USBOH3>;
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,74 +0,0 @@
|
||||
From 0ae59d1767a9cf9875b35a026b5df13eeb3694db Mon Sep 17 00:00:00 2001
|
||||
From: Joshua Clayton <stillcompiling@gmail.com>
|
||||
Date: Thu, 18 May 2017 08:49:03 +0800
|
||||
Subject: [PATCH 7/9] ARM: dts: imx6q-evi: Fix onboard hub reset line
|
||||
|
||||
Previously the onboard hub was made to work by treating its
|
||||
reset gpio as a regulator enable.
|
||||
Get rid of that kludge now that pwseq has added reset gpio support
|
||||
Move pin muxing the hub reset pin into the usbh1 group
|
||||
|
||||
Signed-off-by: Joshua Clayton <stillcompiling@gmail.com>
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
---
|
||||
arch/arm/boot/dts/imx6q-evi.dts | 25 +++++++------------------
|
||||
1 file changed, 7 insertions(+), 18 deletions(-)
|
||||
|
||||
diff --git a/arch/arm/boot/dts/imx6q-evi.dts b/arch/arm/boot/dts/imx6q-evi.dts
|
||||
index c63f371ede8b..546d9d4e8ca1 100644
|
||||
--- a/arch/arm/boot/dts/imx6q-evi.dts
|
||||
+++ b/arch/arm/boot/dts/imx6q-evi.dts
|
||||
@@ -55,18 +55,6 @@
|
||||
reg = <0x10000000 0x40000000>;
|
||||
};
|
||||
|
||||
- reg_usbh1_vbus: regulator-usbhubreset {
|
||||
- compatible = "regulator-fixed";
|
||||
- regulator-name = "usbh1_vbus";
|
||||
- regulator-min-microvolt = <5000000>;
|
||||
- regulator-max-microvolt = <5000000>;
|
||||
- enable-active-high;
|
||||
- startup-delay-us = <2>;
|
||||
- pinctrl-names = "default";
|
||||
- pinctrl-0 = <&pinctrl_usbh1_hubreset>;
|
||||
- gpio = <&gpio7 12 GPIO_ACTIVE_HIGH>;
|
||||
- };
|
||||
-
|
||||
reg_usb_otg_vbus: regulator-usbotgvbus {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "usb_otg_vbus";
|
||||
@@ -214,12 +202,18 @@
|
||||
};
|
||||
|
||||
&usbh1 {
|
||||
- vbus-supply = <®_usbh1_vbus>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_usbh1>;
|
||||
dr_mode = "host";
|
||||
disable-over-current;
|
||||
status = "okay";
|
||||
+
|
||||
+ usb2415host: hub@1 {
|
||||
+ compatible = "usb424,2513";
|
||||
+ reg = <1>;
|
||||
+ reset-gpios = <&gpio7 12 GPIO_ACTIVE_LOW>;
|
||||
+ reset-duration-us = <3000>;
|
||||
+ };
|
||||
};
|
||||
|
||||
&usbotg {
|
||||
@@ -482,11 +476,6 @@
|
||||
MX6QDL_PAD_GPIO_3__USB_H1_OC 0x1b0b0
|
||||
/* usbh1_b OC */
|
||||
MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x1b0b0
|
||||
- >;
|
||||
- };
|
||||
-
|
||||
- pinctrl_usbh1_hubreset: usbh1hubresetgrp {
|
||||
- fsl,pins = <
|
||||
MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x1b0b0
|
||||
>;
|
||||
};
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,511 +0,0 @@
|
||||
From 9a4d8e886600c7c330590a2435dd74eb16d480ce Mon Sep 17 00:00:00 2001
|
||||
From: Steve Arnold <nerdboy@gentoo.org>
|
||||
Date: Fri, 15 Dec 2017 16:43:22 -0800
|
||||
Subject: [PATCH 8/9] ARM: dts,driver: imx6,udooqdl: add arduino manager driver
|
||||
and update dts
|
||||
|
||||
* note this is required to upload sketches to sam3 from arduino IDE
|
||||
|
||||
Signed-off-by: Steve Arnold <nerdboy@gentoo.org>
|
||||
---
|
||||
arch/arm/boot/dts/imx6qdl-udoo.dtsi | 20 ++
|
||||
drivers/misc/Kconfig | 7 +
|
||||
drivers/misc/Makefile | 1 +
|
||||
drivers/misc/udoo_ard.c | 417 ++++++++++++++++++++++++++++
|
||||
4 files changed, 445 insertions(+)
|
||||
create mode 100755 drivers/misc/udoo_ard.c
|
||||
|
||||
diff --git a/arch/arm/boot/dts/imx6qdl-udoo.dtsi b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
|
||||
index 4781a9e04338..554f601eb72a 100644
|
||||
--- a/arch/arm/boot/dts/imx6qdl-udoo.dtsi
|
||||
+++ b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
|
||||
@@ -84,6 +84,17 @@
|
||||
mux-int-port = <1>;
|
||||
mux-ext-port = <6>;
|
||||
};
|
||||
+
|
||||
+ udoo_ard: udoo_ard_manager {
|
||||
+ compatible = "udoo,imx6q-udoo-ard";
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&pinctrl_udooard>;
|
||||
+ bossac-clk-gpio = <&gpio6 3 0>;
|
||||
+ bossac-dat-gpio = <&gpio5 18 0>;
|
||||
+ bossac-erase-gpio = <&gpio4 21 0>;
|
||||
+ bossac-reset-gpio = <&gpio1 0 0>;
|
||||
+ status = "okay";
|
||||
+ };
|
||||
};
|
||||
|
||||
&fec {
|
||||
@@ -201,6 +212,15 @@
|
||||
>;
|
||||
};
|
||||
|
||||
+ pinctrl_udooard: udooardgrp {
|
||||
+ fsl,pins = <
|
||||
+ MX6QDL_PAD_DISP0_DAT0__GPIO4_IO21 0x80000000
|
||||
+ MX6QDL_PAD_CSI0_DAT17__GPIO6_IO03 0x80000000
|
||||
+ MX6QDL_PAD_CSI0_PIXCLK__GPIO5_IO18 0x80000000
|
||||
+ MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x80000000
|
||||
+ >;
|
||||
+ };
|
||||
+
|
||||
pinctrl_usdhc3: usdhc3grp {
|
||||
fsl,pins = <
|
||||
MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059
|
||||
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
|
||||
index 2cf9db44e4b2..f4616fc61808 100644
|
||||
--- a/drivers/misc/Kconfig
|
||||
+++ b/drivers/misc/Kconfig
|
||||
@@ -487,6 +487,13 @@ config PVPANIC
|
||||
a paravirtualized device provided by QEMU; it lets a virtual machine
|
||||
(guest) communicate panic events to the host.
|
||||
|
||||
+config UDOO_ARD
|
||||
+ tristate "UDOO-Arduino erase/reset Driver"
|
||||
+ default y
|
||||
+ help
|
||||
+ This driver is used to erase and reset arduino board via command sent
|
||||
+ over USB-to-SERIAL connection.
|
||||
+
|
||||
source "drivers/misc/c2port/Kconfig"
|
||||
source "drivers/misc/eeprom/Kconfig"
|
||||
source "drivers/misc/cb710/Kconfig"
|
||||
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
|
||||
index dcc801e8834e..13e132dd62c9 100644
|
||||
--- a/drivers/misc/Makefile
|
||||
+++ b/drivers/misc/Makefile
|
||||
@@ -11,6 +11,7 @@ obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o
|
||||
obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
|
||||
obj-$(CONFIG_DUMMY_IRQ) += dummy-irq.o
|
||||
obj-$(CONFIG_ICS932S401) += ics932s401.o
|
||||
+obj-$(CONFIG_UDOO_ARD) += udoo_ard.o
|
||||
obj-$(CONFIG_LKDTM) += lkdtm/
|
||||
obj-$(CONFIG_TIFM_CORE) += tifm_core.o
|
||||
obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
|
||||
diff --git a/drivers/misc/udoo_ard.c b/drivers/misc/udoo_ard.c
|
||||
new file mode 100755
|
||||
index 000000000000..2210738e09c0
|
||||
--- /dev/null
|
||||
+++ b/drivers/misc/udoo_ard.c
|
||||
@@ -0,0 +1,417 @@
|
||||
+/*
|
||||
+ * udoo_ard.c
|
||||
+ * UDOO quad/dual Arduino flash erase / CPU resetter
|
||||
+ *
|
||||
+ * Copyright (C) 2013-2015 Aidilab srl
|
||||
+ * Author: UDOO Team <social@udoo.org>
|
||||
+ * Author: Giuseppe Pagano <giuseppe.pagano@seco.com>
|
||||
+ * Author: Francesco Montefoschi <francesco.monte@gmail.com>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it
|
||||
+ * under the terms of the GNU General Public License version 2 as published by
|
||||
+ * the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
+ * more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License along with
|
||||
+ * this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/errno.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/gpio.h>
|
||||
+#include <linux/sched.h>
|
||||
+#include <linux/sched/clock.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/workqueue.h>
|
||||
+#include <linux/fs.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/of_address.h>
|
||||
+#include <linux/of_gpio.h>
|
||||
+#include <linux/of_irq.h>
|
||||
+#include <linux/of_platform.h>
|
||||
+#include <linux/uaccess.h>
|
||||
+
|
||||
+#define DRIVER_NAME "udoo_ard"
|
||||
+#define PINCTRL_DEFAULT "default"
|
||||
+#define AUTH_TOKEN 0x5A5A
|
||||
+#define MAX_MSEC_SINCE_LAST_IRQ 400
|
||||
+#define GRAY_TIME_BETWEEN_RESET 10000 // In this time we can't accept new erase/reset code
|
||||
+
|
||||
+static struct workqueue_struct *erase_reset_wq;
|
||||
+typedef struct {
|
||||
+ struct work_struct erase_reset_work;
|
||||
+ struct pinctrl *pinctrl;
|
||||
+ struct pinctrl_state *pins_default;
|
||||
+ int step;
|
||||
+ int cmdcode;
|
||||
+ int erase_reset_lock;
|
||||
+ int gpio_bossac_clk;
|
||||
+ int gpio_bossac_dat;
|
||||
+ int gpio_ard_erase;
|
||||
+ int gpio_ard_reset;
|
||||
+ unsigned long last_int_time_in_ns;
|
||||
+ unsigned long last_int_time_in_sec;
|
||||
+} erase_reset_work_t;
|
||||
+
|
||||
+erase_reset_work_t *work;
|
||||
+static u32 origTX, origRX; // original UART4 TX/RX pad control registers
|
||||
+static int major; // for /dev/udoo_ard
|
||||
+static struct class *udoo_class;
|
||||
+
|
||||
+static struct platform_device_id udoo_ard_devtype[] = {
|
||||
+ {
|
||||
+ /* keep it for coldfire */
|
||||
+ .name = DRIVER_NAME,
|
||||
+ .driver_data = 0,
|
||||
+ }, {
|
||||
+ /* sentinel */
|
||||
+ }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(platform, udoo_ard_devtype);
|
||||
+
|
||||
+static const struct of_device_id udoo_ard_dt_ids[] = {
|
||||
+ { .compatible = "udoo,imx6q-udoo-ard", .data = &udoo_ard_devtype[0], },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, udoo_ard_dt_ids);
|
||||
+
|
||||
+static void disable_serial(void)
|
||||
+{
|
||||
+ u32 addrTX;
|
||||
+ void __iomem *_addrTX;
|
||||
+
|
||||
+ printk("[bossac] Disable UART4 serial port.\n");
|
||||
+
|
||||
+ addrTX = 0x20E01F8;
|
||||
+ _addrTX = ioremap(addrTX, 8);
|
||||
+
|
||||
+ origTX = __raw_readl(_addrTX);
|
||||
+ origRX = __raw_readl(_addrTX + 0x4);
|
||||
+
|
||||
+ __raw_writel(0x15, _addrTX);
|
||||
+ __raw_writel(0x15, _addrTX + 0x4);
|
||||
+
|
||||
+ iounmap(_addrTX);
|
||||
+}
|
||||
+
|
||||
+static void enable_serial(void)
|
||||
+{
|
||||
+ u32 addrTX;
|
||||
+ void __iomem *_addrTX;
|
||||
+
|
||||
+ printk("[bossac] Enable UART4 serial port.\n");
|
||||
+
|
||||
+ addrTX = 0x20E01F8;
|
||||
+ _addrTX = ioremap(addrTX, 8);
|
||||
+
|
||||
+ __raw_writel(origTX, _addrTX);
|
||||
+ __raw_writel(origRX, _addrTX + 0x4);
|
||||
+
|
||||
+ iounmap(_addrTX);
|
||||
+}
|
||||
+
|
||||
+static void erase_reset(void)
|
||||
+{
|
||||
+ printk("[bossac] UDOO ERASE and RESET on Sam3x started.\n");
|
||||
+
|
||||
+ gpio_direction_input(work->gpio_ard_erase);
|
||||
+ gpio_set_value(work->gpio_ard_reset, 1);
|
||||
+ msleep(1);
|
||||
+
|
||||
+ gpio_direction_output(work->gpio_ard_erase, 1);
|
||||
+ msleep(300);
|
||||
+ gpio_direction_input(work->gpio_ard_erase);
|
||||
+
|
||||
+ msleep(10);
|
||||
+ gpio_set_value(work->gpio_ard_reset, 0);
|
||||
+
|
||||
+ msleep(80);
|
||||
+ gpio_set_value(work->gpio_ard_reset, 1);
|
||||
+
|
||||
+ printk("[bossac] UDOO ERASE and RESET on Sam3x EXECUTED.\n");
|
||||
+}
|
||||
+
|
||||
+static void shutdown_sam3x(void)
|
||||
+{
|
||||
+ printk("[bossac] RESET on Sam3x.\n");
|
||||
+
|
||||
+ gpio_set_value(work->gpio_ard_reset, 0);
|
||||
+}
|
||||
+
|
||||
+static void erase_reset_wq_function( struct work_struct *work2)
|
||||
+{
|
||||
+ disable_serial();
|
||||
+ erase_reset();
|
||||
+ msleep(GRAY_TIME_BETWEEN_RESET);
|
||||
+
|
||||
+ work->erase_reset_lock = 0;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Called everytime the gpio_bossac_clk signal toggles.
|
||||
+ * If the auth token (16 bit) is found, we look for the command code (4 bit).
|
||||
+ * The code 0x0F is sent by Bossac to trigger an erase/reset (to achieve this,
|
||||
+ * erase_reset_wq is scheduled). Before starting to program the flash, we disable
|
||||
+ * the UART4 serial port, otherwise there is too noise on the serial lines (the
|
||||
+ * programming port and UART4 port are connected together, see hw schematics).
|
||||
+ * When Bossac finishes to flash/verify, the code 0x00 is sent which re-enables
|
||||
+ * the UART4 port.
|
||||
+ */
|
||||
+static irqreturn_t udoo_bossac_req(int irq, void *dev_id)
|
||||
+{
|
||||
+ int retval, auth_bit, expected_bit, msec_since_last_irq;
|
||||
+ u64 nowsec;
|
||||
+ unsigned long rem_nsec;
|
||||
+ erase_reset_work_t *erase_reset_work;
|
||||
+
|
||||
+ auth_bit = 0;
|
||||
+ if (gpio_get_value(work->gpio_bossac_dat) != 0x0) {
|
||||
+ auth_bit = 1;
|
||||
+ }
|
||||
+
|
||||
+ erase_reset_work = (erase_reset_work_t *)work;
|
||||
+
|
||||
+ nowsec = local_clock();
|
||||
+ rem_nsec = do_div(nowsec, 1000000000) ;
|
||||
+ msec_since_last_irq = (((unsigned long)nowsec * 1000) + rem_nsec/1000000 ) - (((unsigned long)erase_reset_work->last_int_time_in_sec * 1000) + erase_reset_work->last_int_time_in_ns/1000000);
|
||||
+
|
||||
+ if (msec_since_last_irq > MAX_MSEC_SINCE_LAST_IRQ) {
|
||||
+ erase_reset_work->step = 0;
|
||||
+#ifdef DEBUG
|
||||
+ printk("[bossac] Reset authentication timeout!\n");
|
||||
+#endif
|
||||
+ }
|
||||
+
|
||||
+#ifdef DEBUG
|
||||
+ printk("[bossac] STEP %d -> 0x%d \n", erase_reset_work->step, auth_bit);
|
||||
+#endif
|
||||
+ erase_reset_work->last_int_time_in_ns = rem_nsec;
|
||||
+ erase_reset_work->last_int_time_in_sec = nowsec;
|
||||
+
|
||||
+ if ( erase_reset_work->step < 16 ) { // Authenticating received token bit.
|
||||
+ expected_bit = (( AUTH_TOKEN >> erase_reset_work->step ) & 0x01 );
|
||||
+ if ( auth_bit == expected_bit ) {
|
||||
+ erase_reset_work->step = erase_reset_work->step + 1;
|
||||
+ } else {
|
||||
+ erase_reset_work->step = 0;
|
||||
+ }
|
||||
+ } else { // Passed all authentication step. Receiving command code.
|
||||
+ erase_reset_work->cmdcode = erase_reset_work->cmdcode | (auth_bit << (erase_reset_work->step - 16));
|
||||
+ erase_reset_work->step = erase_reset_work->step + 1;
|
||||
+ }
|
||||
+
|
||||
+#ifdef DEBUG
|
||||
+ printk("erase_reset_work->erase_reset_lock = %d \n", erase_reset_work->erase_reset_lock);
|
||||
+#endif
|
||||
+ if ( erase_reset_work->step == 20 ) { // Passed authentication and code acquiring step.
|
||||
+#ifdef DEBUG
|
||||
+ printk("[bossac] Received code = 0x%04x \n", erase_reset_work->cmdcode);
|
||||
+#endif
|
||||
+ if (erase_reset_work->cmdcode == 0xF) {
|
||||
+ if (erase_reset_work->erase_reset_lock == 0) {
|
||||
+ erase_reset_work->erase_reset_lock = 1;
|
||||
+ retval = queue_work( erase_reset_wq, (struct work_struct *)work );
|
||||
+ } else {
|
||||
+#ifdef DEBUG
|
||||
+ printk("Erase and reset operation already in progress. Do nothing.\n");
|
||||
+#endif
|
||||
+ }
|
||||
+ } else {
|
||||
+ enable_serial();
|
||||
+ }
|
||||
+ erase_reset_work->step = 0;
|
||||
+ erase_reset_work->cmdcode = 0;
|
||||
+ }
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Takes control of clock, data, erase, reset GPIOs.
|
||||
+ */
|
||||
+static int gpio_setup(void)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = gpio_request(work->gpio_bossac_clk, "BOSSA_CLK");
|
||||
+ if (ret) {
|
||||
+ printk(KERN_ERR "request BOSSA_CLK IRQ\n");
|
||||
+ return -1;
|
||||
+ } else {
|
||||
+ gpio_direction_input(work->gpio_bossac_clk);
|
||||
+ }
|
||||
+
|
||||
+ ret = gpio_request(work->gpio_bossac_dat, "BOSSA_DAT");
|
||||
+ if (ret) {
|
||||
+ printk(KERN_ERR "request BOSSA_DAT IRQ\n");
|
||||
+ return -1;
|
||||
+ } else {
|
||||
+ gpio_direction_input(work->gpio_bossac_dat);
|
||||
+ }
|
||||
+
|
||||
+ ret = gpio_request(work->gpio_ard_erase, "BOSSAC");
|
||||
+ if (ret) {
|
||||
+ printk(KERN_ERR "request GPIO FOR ARDUINO ERASE\n");
|
||||
+ return -1;
|
||||
+ } else {
|
||||
+ gpio_direction_input(work->gpio_ard_erase);
|
||||
+ }
|
||||
+
|
||||
+ ret = gpio_request(work->gpio_ard_reset, "BOSSAC");
|
||||
+ if (ret) {
|
||||
+ printk(KERN_ERR "request GPIO FOR ARDUINO RESET\n");
|
||||
+ return -1;
|
||||
+ } else {
|
||||
+ gpio_direction_output(work->gpio_ard_reset, 1);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static ssize_t device_write(struct file *filp, const char *buff, size_t len, loff_t *off)
|
||||
+{
|
||||
+ char msg[10];
|
||||
+ long res;
|
||||
+
|
||||
+ if (len > 10)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+
|
||||
+ res = copy_from_user(msg, buff, len);
|
||||
+ if (res) {
|
||||
+ return -EFAULT;
|
||||
+ }
|
||||
+ msg[len] = '\0';
|
||||
+
|
||||
+ if (strcmp(msg, "erase")==0) {
|
||||
+ erase_reset();
|
||||
+ } else if (strcmp(msg, "shutdown")==0) {
|
||||
+ shutdown_sam3x();
|
||||
+ } else if (strcmp(msg, "uartoff")==0) {
|
||||
+ disable_serial();
|
||||
+ } else if (strcmp(msg, "uarton")==0) {
|
||||
+ enable_serial();
|
||||
+ } else {
|
||||
+ printk("[bossac] udoo_ard invalid operation! %s", msg);
|
||||
+ }
|
||||
+
|
||||
+ return len;
|
||||
+}
|
||||
+
|
||||
+static struct file_operations fops = {
|
||||
+ .write = device_write,
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * If a fdt udoo_ard entry is found, we register an IRQ on bossac clock line
|
||||
+ * and we create /dev/udoo_ard
|
||||
+ */
|
||||
+static int udoo_ard_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int retval;
|
||||
+ struct device *temp_class;
|
||||
+ struct platform_device *bdev;
|
||||
+ struct device_node *np;
|
||||
+
|
||||
+ bdev = kzalloc(sizeof(*bdev), GFP_KERNEL);
|
||||
+ np = pdev->dev.of_node;
|
||||
+
|
||||
+ if (!np)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ work = (erase_reset_work_t *)kmalloc(sizeof(erase_reset_work_t), GFP_KERNEL);
|
||||
+ if (work) {
|
||||
+ work->gpio_ard_reset = of_get_named_gpio(np, "bossac-reset-gpio", 0);
|
||||
+ work->gpio_ard_erase = of_get_named_gpio(np, "bossac-erase-gpio", 0);
|
||||
+ work->gpio_bossac_clk = of_get_named_gpio(np, "bossac-clk-gpio", 0);
|
||||
+ work->gpio_bossac_dat = of_get_named_gpio(np, "bossac-dat-gpio", 0);
|
||||
+ work->pinctrl = devm_pinctrl_get(&pdev->dev);
|
||||
+ work->pins_default = pinctrl_lookup_state(work->pinctrl, PINCTRL_DEFAULT);
|
||||
+ } else {
|
||||
+ printk("[bossac] Failed to allocate data structure.");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ pinctrl_select_state(work->pinctrl, work->pins_default);
|
||||
+ gpio_setup();
|
||||
+
|
||||
+ printk("[bossac] Registering IRQ %d for BOSSAC Arduino erase/reset operation\n", gpio_to_irq(work->gpio_bossac_clk));
|
||||
+ retval = request_irq(gpio_to_irq(work->gpio_bossac_clk), udoo_bossac_req, IRQF_TRIGGER_FALLING, "UDOO", bdev);
|
||||
+
|
||||
+ major = register_chrdev(major, "udoo_ard", &fops);
|
||||
+ if (major < 0) {
|
||||
+ printk(KERN_ERR "[bossac] Cannot get major for UDOO Ard\n");
|
||||
+ return -EBUSY;
|
||||
+ }
|
||||
+
|
||||
+ udoo_class = class_create(THIS_MODULE, "udoo_ard");
|
||||
+ if (IS_ERR(udoo_class)) {
|
||||
+ return PTR_ERR(udoo_class);
|
||||
+ }
|
||||
+
|
||||
+ temp_class = device_create(udoo_class, NULL, MKDEV(major, 0), NULL, "udoo_ard");
|
||||
+ if (IS_ERR(temp_class)) {
|
||||
+ return PTR_ERR(temp_class);
|
||||
+ }
|
||||
+
|
||||
+ printk("[bossac] Created device file /dev/udoo_ard\n");
|
||||
+
|
||||
+ erase_reset_wq = create_workqueue("erase_reset_queue");
|
||||
+ if (erase_reset_wq) {
|
||||
+
|
||||
+ /* Queue some work (item 1) */
|
||||
+ if (work) {
|
||||
+ INIT_WORK( (struct work_struct *)work, erase_reset_wq_function );
|
||||
+ work->step = 1;
|
||||
+ work->cmdcode = 0;
|
||||
+ work->last_int_time_in_ns = 0;
|
||||
+ work->last_int_time_in_sec = 0;
|
||||
+ work->erase_reset_lock = 0;
|
||||
+ // retval = queue_work( erase_reset_wq, (struct work_struct *)work );
|
||||
+ }
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int udoo_ard_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ printk("[bossac] Unloading UDOO ard driver.\n");
|
||||
+ free_irq(gpio_to_irq(work->gpio_bossac_clk), NULL);
|
||||
+
|
||||
+ gpio_free(work->gpio_ard_reset);
|
||||
+ gpio_free(work->gpio_ard_erase);
|
||||
+ gpio_free(work->gpio_bossac_clk);
|
||||
+ gpio_free(work->gpio_bossac_dat);
|
||||
+
|
||||
+ device_destroy(udoo_class, MKDEV(major, 0));
|
||||
+ class_destroy(udoo_class);
|
||||
+ unregister_chrdev(major, "udoo_ard");
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver udoo_ard_driver = {
|
||||
+ .driver = {
|
||||
+ .name = DRIVER_NAME,
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = udoo_ard_dt_ids,
|
||||
+ },
|
||||
+ .id_table = udoo_ard_devtype,
|
||||
+ .probe = udoo_ard_probe,
|
||||
+ .remove = udoo_ard_remove,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(udoo_ard_driver);
|
||||
+
|
||||
+MODULE_ALIAS("platform:"DRIVER_NAME);
|
||||
+MODULE_LICENSE("GPL");
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,11 +0,0 @@
|
||||
--- ./arch/arm/mm/cache-feroceon-l2.c.orig 2013-04-26 13:18:32.000000000 -0600
|
||||
+++ ./arch/arm/mm/cache-feroceon-l2.c 2013-04-28 04:01:09.815592333 -0600
|
||||
@@ -117,7 +117,7 @@ static inline void l2_inv_pa_range(unsig
|
||||
l2_put_va(va_start);
|
||||
}
|
||||
|
||||
-static inline void l2_inv_all(void)
|
||||
+static void l2_inv_all(void)
|
||||
{
|
||||
__asm__("mcr p15, 1, %0, c15, c11, 0" : : "r" (0));
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
--- ./arch/arm/boot/dts/imx6qdl-hummingboard.dtsi.orig 2015-01-08 11:30:41.000000000 -0700
|
||||
+++ ./arch/arm/boot/dts/imx6qdl-hummingboard.dtsi 2015-01-13 14:19:29.696485445 -0700
|
||||
@@ -94,6 +94,31 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
+&i2c3 {
|
||||
+ clock-frequency = <100000>;
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&pinctrl_hummingboard_i2c3>;
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&ecspi2 {
|
||||
+ fsl,spi-num-chipselects = <2>;
|
||||
+ cs-gpios = <&gpio2 26 1>, <&gpio2 27 1>;
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&pinctrl_hummingboard_spi>;
|
||||
+ status = "okay";
|
||||
+ spidev@0x00 {
|
||||
+ compatible = "spidev";
|
||||
+ spi-max-frequency = <5000000>;
|
||||
+ reg = <0>;
|
||||
+ };
|
||||
+ spidev@0x01 {
|
||||
+ compatible = "spidev";
|
||||
+ spi-max-frequency = <5000000>;
|
||||
+ reg = <1>;
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
&iomuxc {
|
||||
hummingboard {
|
||||
pinctrl_hummingboard_flexcan1: hummingboard-flexcan1 {
|
||||
@@ -103,6 +128,17 @@
|
||||
>;
|
||||
};
|
||||
|
||||
+ pinctrl_hummingboard_spi: hummingboard_spi {
|
||||
+ fsl,pins = <
|
||||
+ MX6QDL_PAD_EIM_OE__ECSPI2_MISO 0x100b1
|
||||
+ MX6QDL_PAD_EIM_CS1__ECSPI2_MOSI 0x100b1
|
||||
+ MX6QDL_PAD_EIM_CS0__ECSPI2_SCLK 0x100b1
|
||||
+ /* MX6QDL_PAD_EIM_RW__ECSPI2_SS0 0x100b1 */
|
||||
+ MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x100b1
|
||||
+ MX6QDL_PAD_EIM_LBA__ECSPI2_SS1 0x100b1
|
||||
+ >;
|
||||
+ };
|
||||
+
|
||||
pinctrl_hummingboard_gpio3_5: hummingboard-gpio3_5 {
|
||||
fsl,pins = <
|
||||
MX6QDL_PAD_EIM_DA5__GPIO3_IO05 0x1b0b1
|
||||
@@ -129,6 +165,13 @@
|
||||
>;
|
||||
};
|
||||
|
||||
+ pinctrl_hummingboard_i2c3: hummingboard-i2c3 {
|
||||
+ fsl,pins = <
|
||||
+ MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1
|
||||
+ MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1
|
||||
+ >;
|
||||
+ };
|
||||
+
|
||||
pinctrl_hummingboard_spdif: hummingboard-spdif {
|
||||
fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x13091>;
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
--- ./fs/timerfd.c.orig 2015-11-09 15:37:56.000000000 -0700
|
||||
+++ ./fs/timerfd.c 2015-11-14 08:20:51.720068530 -0700
|
||||
@@ -134,7 +134,7 @@ static void timerfd_setup_cancel(struct
|
||||
{
|
||||
if ((ctx->clockid == CLOCK_REALTIME ||
|
||||
ctx->clockid == CLOCK_REALTIME_ALARM) &&
|
||||
- (flags & TFD_TIMER_ABSTIME) && (flags & TFD_TIMER_CANCEL_ON_SET)) {
|
||||
+ (flags & TFD_TIMER_CANCEL_ON_SET)) {
|
||||
if (!ctx->might_cancel) {
|
||||
ctx->might_cancel = true;
|
||||
spin_lock(&cancel_lock);
|
@ -1,287 +0,0 @@
|
||||
From 3ec70749ae3cb072f19d886981a217121f776415 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Pecovnik <igor.pecovnik@gmail.com>
|
||||
Date: Sat, 6 Nov 2021 19:15:23 +0100
|
||||
Subject: [PATCH] Revert "net: Remove net/ipx.h and uapi/linux/ipx.h header
|
||||
files"
|
||||
|
||||
This reverts commit 6c9b40844751ea30c72f7a2f92f4d704bc6b2927.
|
||||
---
|
||||
include/net/ipx.h | 171 +++++++++++++++++++++++++++++++++++++++
|
||||
include/uapi/linux/ipx.h | 87 ++++++++++++++++++++
|
||||
2 files changed, 258 insertions(+)
|
||||
create mode 100644 include/net/ipx.h
|
||||
create mode 100644 include/uapi/linux/ipx.h
|
||||
|
||||
diff --git a/include/net/ipx.h b/include/net/ipx.h
|
||||
new file mode 100644
|
||||
index 000000000000..9d1342807b59
|
||||
--- /dev/null
|
||||
+++ b/include/net/ipx.h
|
||||
@@ -0,0 +1,171 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0 */
|
||||
+#ifndef _NET_INET_IPX_H_
|
||||
+#define _NET_INET_IPX_H_
|
||||
+/*
|
||||
+ * The following information is in its entirety obtained from:
|
||||
+ *
|
||||
+ * Novell 'IPX Router Specification' Version 1.10
|
||||
+ * Part No. 107-000029-001
|
||||
+ *
|
||||
+ * Which is available from ftp.novell.com
|
||||
+ */
|
||||
+
|
||||
+#include <linux/netdevice.h>
|
||||
+#include <net/datalink.h>
|
||||
+#include <linux/ipx.h>
|
||||
+#include <linux/list.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/refcount.h>
|
||||
+
|
||||
+struct ipx_address {
|
||||
+ __be32 net;
|
||||
+ __u8 node[IPX_NODE_LEN];
|
||||
+ __be16 sock;
|
||||
+};
|
||||
+
|
||||
+#define ipx_broadcast_node "\377\377\377\377\377\377"
|
||||
+#define ipx_this_node "\0\0\0\0\0\0"
|
||||
+
|
||||
+#define IPX_MAX_PPROP_HOPS 8
|
||||
+
|
||||
+struct ipxhdr {
|
||||
+ __be16 ipx_checksum __packed;
|
||||
+#define IPX_NO_CHECKSUM cpu_to_be16(0xFFFF)
|
||||
+ __be16 ipx_pktsize __packed;
|
||||
+ __u8 ipx_tctrl;
|
||||
+ __u8 ipx_type;
|
||||
+#define IPX_TYPE_UNKNOWN 0x00
|
||||
+#define IPX_TYPE_RIP 0x01 /* may also be 0 */
|
||||
+#define IPX_TYPE_SAP 0x04 /* may also be 0 */
|
||||
+#define IPX_TYPE_SPX 0x05 /* SPX protocol */
|
||||
+#define IPX_TYPE_NCP 0x11 /* $lots for docs on this (SPIT) */
|
||||
+#define IPX_TYPE_PPROP 0x14 /* complicated flood fill brdcast */
|
||||
+ struct ipx_address ipx_dest __packed;
|
||||
+ struct ipx_address ipx_source __packed;
|
||||
+};
|
||||
+
|
||||
+/* From af_ipx.c */
|
||||
+extern int sysctl_ipx_pprop_broadcasting;
|
||||
+
|
||||
+struct ipx_interface {
|
||||
+ /* IPX address */
|
||||
+ __be32 if_netnum;
|
||||
+ unsigned char if_node[IPX_NODE_LEN];
|
||||
+ refcount_t refcnt;
|
||||
+
|
||||
+ /* physical device info */
|
||||
+ struct net_device *if_dev;
|
||||
+ struct datalink_proto *if_dlink;
|
||||
+ __be16 if_dlink_type;
|
||||
+
|
||||
+ /* socket support */
|
||||
+ unsigned short if_sknum;
|
||||
+ struct hlist_head if_sklist;
|
||||
+ spinlock_t if_sklist_lock;
|
||||
+
|
||||
+ /* administrative overhead */
|
||||
+ int if_ipx_offset;
|
||||
+ unsigned char if_internal;
|
||||
+ unsigned char if_primary;
|
||||
+
|
||||
+ struct list_head node; /* node in ipx_interfaces list */
|
||||
+};
|
||||
+
|
||||
+struct ipx_route {
|
||||
+ __be32 ir_net;
|
||||
+ struct ipx_interface *ir_intrfc;
|
||||
+ unsigned char ir_routed;
|
||||
+ unsigned char ir_router_node[IPX_NODE_LEN];
|
||||
+ struct list_head node; /* node in ipx_routes list */
|
||||
+ refcount_t refcnt;
|
||||
+};
|
||||
+
|
||||
+struct ipx_cb {
|
||||
+ u8 ipx_tctrl;
|
||||
+ __be32 ipx_dest_net;
|
||||
+ __be32 ipx_source_net;
|
||||
+ struct {
|
||||
+ __be32 netnum;
|
||||
+ int index;
|
||||
+ } last_hop;
|
||||
+};
|
||||
+
|
||||
+#include <net/sock.h>
|
||||
+
|
||||
+struct ipx_sock {
|
||||
+ /* struct sock has to be the first member of ipx_sock */
|
||||
+ struct sock sk;
|
||||
+ struct ipx_address dest_addr;
|
||||
+ struct ipx_interface *intrfc;
|
||||
+ __be16 port;
|
||||
+#ifdef CONFIG_IPX_INTERN
|
||||
+ unsigned char node[IPX_NODE_LEN];
|
||||
+#endif
|
||||
+ unsigned short type;
|
||||
+ /*
|
||||
+ * To handle special ncp connection-handling sockets for mars_nwe,
|
||||
+ * the connection number must be stored in the socket.
|
||||
+ */
|
||||
+ unsigned short ipx_ncp_conn;
|
||||
+};
|
||||
+
|
||||
+static inline struct ipx_sock *ipx_sk(struct sock *sk)
|
||||
+{
|
||||
+ return (struct ipx_sock *)sk;
|
||||
+}
|
||||
+
|
||||
+#define IPX_SKB_CB(__skb) ((struct ipx_cb *)&((__skb)->cb[0]))
|
||||
+
|
||||
+#define IPX_MIN_EPHEMERAL_SOCKET 0x4000
|
||||
+#define IPX_MAX_EPHEMERAL_SOCKET 0x7fff
|
||||
+
|
||||
+extern struct list_head ipx_routes;
|
||||
+extern rwlock_t ipx_routes_lock;
|
||||
+
|
||||
+extern struct list_head ipx_interfaces;
|
||||
+struct ipx_interface *ipx_interfaces_head(void);
|
||||
+extern spinlock_t ipx_interfaces_lock;
|
||||
+
|
||||
+extern struct ipx_interface *ipx_primary_net;
|
||||
+
|
||||
+int ipx_proc_init(void);
|
||||
+void ipx_proc_exit(void);
|
||||
+
|
||||
+const char *ipx_frame_name(__be16);
|
||||
+const char *ipx_device_name(struct ipx_interface *intrfc);
|
||||
+
|
||||
+static __inline__ void ipxitf_hold(struct ipx_interface *intrfc)
|
||||
+{
|
||||
+ refcount_inc(&intrfc->refcnt);
|
||||
+}
|
||||
+
|
||||
+void ipxitf_down(struct ipx_interface *intrfc);
|
||||
+struct ipx_interface *ipxitf_find_using_net(__be32 net);
|
||||
+int ipxitf_send(struct ipx_interface *intrfc, struct sk_buff *skb, char *node);
|
||||
+__be16 ipx_cksum(struct ipxhdr *packet, int length);
|
||||
+int ipxrtr_add_route(__be32 network, struct ipx_interface *intrfc,
|
||||
+ unsigned char *node);
|
||||
+void ipxrtr_del_routes(struct ipx_interface *intrfc);
|
||||
+int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx,
|
||||
+ struct msghdr *msg, size_t len, int noblock);
|
||||
+int ipxrtr_route_skb(struct sk_buff *skb);
|
||||
+struct ipx_route *ipxrtr_lookup(__be32 net);
|
||||
+int ipxrtr_ioctl(unsigned int cmd, void __user *arg);
|
||||
+
|
||||
+static __inline__ void ipxitf_put(struct ipx_interface *intrfc)
|
||||
+{
|
||||
+ if (refcount_dec_and_test(&intrfc->refcnt))
|
||||
+ ipxitf_down(intrfc);
|
||||
+}
|
||||
+
|
||||
+static __inline__ void ipxrtr_hold(struct ipx_route *rt)
|
||||
+{
|
||||
+ refcount_inc(&rt->refcnt);
|
||||
+}
|
||||
+
|
||||
+static __inline__ void ipxrtr_put(struct ipx_route *rt)
|
||||
+{
|
||||
+ if (refcount_dec_and_test(&rt->refcnt))
|
||||
+ kfree(rt);
|
||||
+}
|
||||
+#endif /* _NET_INET_IPX_H_ */
|
||||
diff --git a/include/uapi/linux/ipx.h b/include/uapi/linux/ipx.h
|
||||
new file mode 100644
|
||||
index 000000000000..3168137adae8
|
||||
--- /dev/null
|
||||
+++ b/include/uapi/linux/ipx.h
|
||||
@@ -0,0 +1,87 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
+#ifndef _IPX_H_
|
||||
+#define _IPX_H_
|
||||
+#include <linux/libc-compat.h> /* for compatibility with glibc netipx/ipx.h */
|
||||
+#include <linux/types.h>
|
||||
+#include <linux/sockios.h>
|
||||
+#include <linux/socket.h>
|
||||
+#define IPX_NODE_LEN 6
|
||||
+#define IPX_MTU 576
|
||||
+
|
||||
+#if __UAPI_DEF_SOCKADDR_IPX
|
||||
+struct sockaddr_ipx {
|
||||
+ __kernel_sa_family_t sipx_family;
|
||||
+ __be16 sipx_port;
|
||||
+ __be32 sipx_network;
|
||||
+ unsigned char sipx_node[IPX_NODE_LEN];
|
||||
+ __u8 sipx_type;
|
||||
+ unsigned char sipx_zero; /* 16 byte fill */
|
||||
+};
|
||||
+#endif /* __UAPI_DEF_SOCKADDR_IPX */
|
||||
+
|
||||
+/*
|
||||
+ * So we can fit the extra info for SIOCSIFADDR into the address nicely
|
||||
+ */
|
||||
+#define sipx_special sipx_port
|
||||
+#define sipx_action sipx_zero
|
||||
+#define IPX_DLTITF 0
|
||||
+#define IPX_CRTITF 1
|
||||
+
|
||||
+#if __UAPI_DEF_IPX_ROUTE_DEFINITION
|
||||
+struct ipx_route_definition {
|
||||
+ __be32 ipx_network;
|
||||
+ __be32 ipx_router_network;
|
||||
+ unsigned char ipx_router_node[IPX_NODE_LEN];
|
||||
+};
|
||||
+#endif /* __UAPI_DEF_IPX_ROUTE_DEFINITION */
|
||||
+
|
||||
+#if __UAPI_DEF_IPX_INTERFACE_DEFINITION
|
||||
+struct ipx_interface_definition {
|
||||
+ __be32 ipx_network;
|
||||
+ unsigned char ipx_device[16];
|
||||
+ unsigned char ipx_dlink_type;
|
||||
+#define IPX_FRAME_NONE 0
|
||||
+#define IPX_FRAME_SNAP 1
|
||||
+#define IPX_FRAME_8022 2
|
||||
+#define IPX_FRAME_ETHERII 3
|
||||
+#define IPX_FRAME_8023 4
|
||||
+#define IPX_FRAME_TR_8022 5 /* obsolete */
|
||||
+ unsigned char ipx_special;
|
||||
+#define IPX_SPECIAL_NONE 0
|
||||
+#define IPX_PRIMARY 1
|
||||
+#define IPX_INTERNAL 2
|
||||
+ unsigned char ipx_node[IPX_NODE_LEN];
|
||||
+};
|
||||
+#endif /* __UAPI_DEF_IPX_INTERFACE_DEFINITION */
|
||||
+
|
||||
+#if __UAPI_DEF_IPX_CONFIG_DATA
|
||||
+struct ipx_config_data {
|
||||
+ unsigned char ipxcfg_auto_select_primary;
|
||||
+ unsigned char ipxcfg_auto_create_interfaces;
|
||||
+};
|
||||
+#endif /* __UAPI_DEF_IPX_CONFIG_DATA */
|
||||
+
|
||||
+/*
|
||||
+ * OLD Route Definition for backward compatibility.
|
||||
+ */
|
||||
+
|
||||
+#if __UAPI_DEF_IPX_ROUTE_DEF
|
||||
+struct ipx_route_def {
|
||||
+ __be32 ipx_network;
|
||||
+ __be32 ipx_router_network;
|
||||
+#define IPX_ROUTE_NO_ROUTER 0
|
||||
+ unsigned char ipx_router_node[IPX_NODE_LEN];
|
||||
+ unsigned char ipx_device[16];
|
||||
+ unsigned short ipx_flags;
|
||||
+#define IPX_RT_SNAP 8
|
||||
+#define IPX_RT_8022 4
|
||||
+#define IPX_RT_BLUEBOOK 2
|
||||
+#define IPX_RT_ROUTED 1
|
||||
+};
|
||||
+#endif /* __UAPI_DEF_IPX_ROUTE_DEF */
|
||||
+
|
||||
+#define SIOCAIPXITFCRT (SIOCPROTOPRIVATE)
|
||||
+#define SIOCAIPXPRISLT (SIOCPROTOPRIVATE + 1)
|
||||
+#define SIOCIPXCFGDATA (SIOCPROTOPRIVATE + 2)
|
||||
+#define SIOCIPXNCPCONN (SIOCPROTOPRIVATE + 3)
|
||||
+#endif /* _IPX_H_ */
|
||||
--
|
||||
2.25.1
|
||||
|
@ -1,73 +0,0 @@
|
||||
From f5528e96b7dd2b30e1accc518df85d14baad6bae Mon Sep 17 00:00:00 2001
|
||||
From: Peter Chen <peter.chen@nxp.com>
|
||||
Date: Thu, 18 May 2017 08:48:57 +0800
|
||||
Subject: [PATCH 1/9] binding-doc: power: pwrseq-generic: add binding doc for
|
||||
generic power sequence library
|
||||
|
||||
Add binding doc for generic power sequence library.
|
||||
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
|
||||
Acked-by: Rob Herring <robh@kernel.org>
|
||||
---
|
||||
.../bindings/power/pwrseq/pwrseq-generic.txt | 48 +++++++++++++++++++
|
||||
1 file changed, 48 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt b/Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt
|
||||
new file mode 100644
|
||||
index 000000000000..ebf0d477b688
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt
|
||||
@@ -0,0 +1,48 @@
|
||||
+The generic power sequence library
|
||||
+
|
||||
+Some hard-wired devices (eg USB/MMC) need to do power sequence before
|
||||
+the device can be enumerated on the bus, the typical power sequence
|
||||
+like: enable USB PHY clock, toggle reset pin, etc. But current
|
||||
+Linux device driver lacks of such code to do it, it may cause some
|
||||
+hard-wired devices works abnormal or can't be recognized by
|
||||
+controller at all. The power sequence will be done before this device
|
||||
+can be found at the bus.
|
||||
+
|
||||
+The power sequence properties is under the device node.
|
||||
+
|
||||
+Optional properties:
|
||||
+- clocks: the input clocks for device.
|
||||
+- reset-gpios: Should specify the GPIO for reset.
|
||||
+- reset-duration-us: the duration in microsecond for assert reset signal.
|
||||
+
|
||||
+Below is the example of USB power sequence properties on USB device
|
||||
+nodes which have two level USB hubs.
|
||||
+
|
||||
+&usbotg1 {
|
||||
+ vbus-supply = <®_usb_otg1_vbus>;
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&pinctrl_usb_otg1_id>;
|
||||
+ status = "okay";
|
||||
+
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+ genesys: hub@1 {
|
||||
+ compatible = "usb5e3,608";
|
||||
+ reg = <1>;
|
||||
+
|
||||
+ clocks = <&clks IMX6SX_CLK_CKO>;
|
||||
+ reset-gpios = <&gpio4 5 GPIO_ACTIVE_LOW>; /* hub reset pin */
|
||||
+ reset-duration-us = <10>;
|
||||
+
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+ asix: ethernet@1 {
|
||||
+ compatible = "usbb95,1708";
|
||||
+ reg = <1>;
|
||||
+
|
||||
+ clocks = <&clks IMX6SX_CLK_IPG>;
|
||||
+ reset-gpios = <&gpio4 6 GPIO_ACTIVE_LOW>; /* ethernet_rst */
|
||||
+ reset-duration-us = <15>;
|
||||
+ };
|
||||
+ };
|
||||
+};
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,853 +0,0 @@
|
||||
From e42fbf22376c41b275d47b9cfac360c66ee718dc Mon Sep 17 00:00:00 2001
|
||||
From: Peter Chen <peter.chen@nxp.com>
|
||||
Date: Thu, 18 May 2017 08:48:58 +0800
|
||||
Subject: [PATCH 2/9] power: add power sequence library
|
||||
|
||||
We have an well-known problem that the device needs to do some power
|
||||
sequence before it can be recognized by related host, the typical
|
||||
example like hard-wired mmc devices and usb devices.
|
||||
|
||||
This power sequence is hard to be described at device tree and handled by
|
||||
related host driver, so we have created a common power sequence
|
||||
library to cover this requirement. The core code has supplied
|
||||
some common helpers for host driver, and individual power sequence
|
||||
libraries handle kinds of power sequence for devices. The pwrseq
|
||||
librares always need to allocate extra instance for compatible
|
||||
string match.
|
||||
|
||||
pwrseq_generic is intended for general purpose of power sequence, which
|
||||
handles gpios and clocks currently, and can cover other controls in
|
||||
future. The host driver just needs to call of_pwrseq_on/of_pwrseq_off
|
||||
if only one power sequence is needed, else call of_pwrseq_on_list
|
||||
/of_pwrseq_off_list instead (eg, USB hub driver).
|
||||
|
||||
For new power sequence library, it can add its compatible string
|
||||
to pwrseq_of_match_table, then the pwrseq core will match it with
|
||||
DT's, and choose this library at runtime.
|
||||
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
Tested-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
|
||||
Tested-by Joshua Clayton <stillcompiling@gmail.com>
|
||||
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
|
||||
Tested-by: Matthias Kaehlcke <mka@chromium.org>
|
||||
---
|
||||
Documentation/power/power-sequence/design.rst | 54 +++
|
||||
MAINTAINERS | 9 +
|
||||
drivers/power/Kconfig | 1 +
|
||||
drivers/power/Makefile | 1 +
|
||||
drivers/power/pwrseq/Kconfig | 20 ++
|
||||
drivers/power/pwrseq/Makefile | 2 +
|
||||
drivers/power/pwrseq/core.c | 335 ++++++++++++++++++
|
||||
drivers/power/pwrseq/pwrseq_generic.c | 234 ++++++++++++
|
||||
include/linux/power/pwrseq.h | 81 +++++
|
||||
9 files changed, 737 insertions(+)
|
||||
create mode 100644 Documentation/power/power-sequence/design.rst
|
||||
create mode 100644 drivers/power/pwrseq/Kconfig
|
||||
create mode 100644 drivers/power/pwrseq/Makefile
|
||||
create mode 100644 drivers/power/pwrseq/core.c
|
||||
create mode 100644 drivers/power/pwrseq/pwrseq_generic.c
|
||||
create mode 100644 include/linux/power/pwrseq.h
|
||||
|
||||
diff --git a/Documentation/power/power-sequence/design.rst b/Documentation/power/power-sequence/design.rst
|
||||
new file mode 100644
|
||||
index 000000000000..554608e5f3b6
|
||||
--- /dev/null
|
||||
+++ b/Documentation/power/power-sequence/design.rst
|
||||
@@ -0,0 +1,54 @@
|
||||
+====================================
|
||||
+Power Sequence Library
|
||||
+====================================
|
||||
+
|
||||
+:Date: Feb, 2017
|
||||
+:Author: Peter Chen <peter.chen@nxp.com>
|
||||
+
|
||||
+
|
||||
+Introduction
|
||||
+============
|
||||
+
|
||||
+We have an well-known problem that the device needs to do a power
|
||||
+sequence before it can be recognized by related host, the typical
|
||||
+examples are hard-wired mmc devices and usb devices. The host controller
|
||||
+can't know what kinds of this device is in its bus if the power
|
||||
+sequence has not done, since the related devices driver's probe calling
|
||||
+is determined by runtime according to eunumeration results. Besides,
|
||||
+the devices may have custom power sequence, so the power sequence library
|
||||
+which is independent with the devices is needed.
|
||||
+
|
||||
+Design
|
||||
+============
|
||||
+
|
||||
+The power sequence library includes the core file and customer power
|
||||
+sequence library. The core file exports interfaces are called by
|
||||
+host controller driver for power sequence and customer power sequence
|
||||
+library files to register its power sequence instance to global
|
||||
+power sequence list. The custom power sequence library creates power
|
||||
+sequence instance and implement custom power sequence.
|
||||
+
|
||||
+Since the power sequence describes hardware design, the description is
|
||||
+located at board description file, eg, device tree dts file. And
|
||||
+a specific power sequence belongs to device, so its description
|
||||
+is under the device node, please refer to:
|
||||
+Documentation/devicetree/bindings/power/pwrseq/pwrseq-generic.txt
|
||||
+
|
||||
+Custom power sequence library allocates one power sequence instance at
|
||||
+bootup periods using postcore_initcall, this static allocated instance is
|
||||
+used to compare with device-tree (DT) node to see if this library can be
|
||||
+used for the node or not. When the result is matched, the core API will
|
||||
+try to get resourses (->get, implemented at each library) for power
|
||||
+sequence, if all resources are got, it will try to allocate another
|
||||
+instance for next possible request from host driver.
|
||||
+
|
||||
+Then, the host controller driver can carry out power sequence on for this
|
||||
+DT node, the library will do corresponding operations, like open clocks,
|
||||
+toggle gpio, etc. The power sequence off routine will close and free the
|
||||
+resources, and is called when the parent is removed. And the power
|
||||
+sequence suspend and resume routine can be called at host driver's
|
||||
+suspend and resume routine if needed.
|
||||
+
|
||||
+The exported interfaces
|
||||
+.. kernel-doc:: drivers/power/pwrseq/core.c
|
||||
+ :export:
|
||||
diff --git a/MAINTAINERS b/MAINTAINERS
|
||||
index 429c6c624861..88fd31d1870f 100644
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -12599,6 +12599,15 @@ F: drivers/firmware/psci/
|
||||
F: include/linux/psci.h
|
||||
F: include/uapi/linux/psci.h
|
||||
|
||||
+POWER SEQUENCE LIBRARY
|
||||
+M: Peter Chen <Peter.Chen@nxp.com>
|
||||
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git
|
||||
+L: linux-pm@vger.kernel.org
|
||||
+S: Maintained
|
||||
+F: Documentation/devicetree/bindings/power/pwrseq/
|
||||
+F: drivers/power/pwrseq/
|
||||
+F: include/linux/power/pwrseq.h
|
||||
+
|
||||
POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS
|
||||
M: Sebastian Reichel <sre@kernel.org>
|
||||
L: linux-pm@vger.kernel.org
|
||||
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
|
||||
index ff0350ca3b74..78b6fa270cf9 100644
|
||||
--- a/drivers/power/Kconfig
|
||||
+++ b/drivers/power/Kconfig
|
||||
@@ -2,3 +2,4 @@
|
||||
source "drivers/power/avs/Kconfig"
|
||||
source "drivers/power/reset/Kconfig"
|
||||
source "drivers/power/supply/Kconfig"
|
||||
+source "drivers/power/pwrseq/Kconfig"
|
||||
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
|
||||
index b7c2e372186b..13046c7fb499 100644
|
||||
--- a/drivers/power/Makefile
|
||||
+++ b/drivers/power/Makefile
|
||||
@@ -2,3 +2,4 @@
|
||||
obj-$(CONFIG_POWER_AVS) += avs/
|
||||
obj-$(CONFIG_POWER_RESET) += reset/
|
||||
obj-$(CONFIG_POWER_SUPPLY) += supply/
|
||||
+obj-$(CONFIG_POWER_SEQUENCE) += pwrseq/
|
||||
diff --git a/drivers/power/pwrseq/Kconfig b/drivers/power/pwrseq/Kconfig
|
||||
new file mode 100644
|
||||
index 000000000000..c6b356926cca
|
||||
--- /dev/null
|
||||
+++ b/drivers/power/pwrseq/Kconfig
|
||||
@@ -0,0 +1,20 @@
|
||||
+#
|
||||
+# Power Sequence library
|
||||
+#
|
||||
+
|
||||
+menuconfig POWER_SEQUENCE
|
||||
+ bool "Power sequence control"
|
||||
+ help
|
||||
+ It is used for drivers which needs to do power sequence
|
||||
+ (eg, turn on clock, toggle reset gpio) before the related
|
||||
+ devices can be found by hardware, eg, USB bus.
|
||||
+
|
||||
+if POWER_SEQUENCE
|
||||
+
|
||||
+config PWRSEQ_GENERIC
|
||||
+ bool "Generic power sequence control"
|
||||
+ depends on OF
|
||||
+ help
|
||||
+ This is the generic power sequence control library, and is
|
||||
+ supposed to support common power sequence usage.
|
||||
+endif
|
||||
diff --git a/drivers/power/pwrseq/Makefile b/drivers/power/pwrseq/Makefile
|
||||
new file mode 100644
|
||||
index 000000000000..ad82389028c2
|
||||
--- /dev/null
|
||||
+++ b/drivers/power/pwrseq/Makefile
|
||||
@@ -0,0 +1,2 @@
|
||||
+obj-$(CONFIG_POWER_SEQUENCE) += core.o
|
||||
+obj-$(CONFIG_PWRSEQ_GENERIC) += pwrseq_generic.o
|
||||
diff --git a/drivers/power/pwrseq/core.c b/drivers/power/pwrseq/core.c
|
||||
new file mode 100644
|
||||
index 000000000000..3d19e62a2e76
|
||||
--- /dev/null
|
||||
+++ b/drivers/power/pwrseq/core.c
|
||||
@@ -0,0 +1,335 @@
|
||||
+/*
|
||||
+ * core.c power sequence core file
|
||||
+ *
|
||||
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
|
||||
+ * Author: Peter Chen <peter.chen@nxp.com>
|
||||
+ *
|
||||
+ * This program is free software: you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 of
|
||||
+ * the License as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/list.h>
|
||||
+#include <linux/mutex.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/power/pwrseq.h>
|
||||
+
|
||||
+static DEFINE_MUTEX(pwrseq_list_mutex);
|
||||
+static LIST_HEAD(pwrseq_list);
|
||||
+
|
||||
+static int pwrseq_get(struct device_node *np, struct pwrseq *p)
|
||||
+{
|
||||
+ if (p && p->get)
|
||||
+ return p->get(np, p);
|
||||
+
|
||||
+ return -ENOTSUPP;
|
||||
+}
|
||||
+
|
||||
+static int pwrseq_on(struct pwrseq *p)
|
||||
+{
|
||||
+ if (p && p->on)
|
||||
+ return p->on(p);
|
||||
+
|
||||
+ return -ENOTSUPP;
|
||||
+}
|
||||
+
|
||||
+static void pwrseq_off(struct pwrseq *p)
|
||||
+{
|
||||
+ if (p && p->off)
|
||||
+ p->off(p);
|
||||
+}
|
||||
+
|
||||
+static void pwrseq_put(struct pwrseq *p)
|
||||
+{
|
||||
+ if (p && p->put)
|
||||
+ p->put(p);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_register - Add pwrseq instance to global pwrseq list
|
||||
+ *
|
||||
+ * @pwrseq: the pwrseq instance
|
||||
+ */
|
||||
+void pwrseq_register(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ mutex_lock(&pwrseq_list_mutex);
|
||||
+ list_add(&pwrseq->node, &pwrseq_list);
|
||||
+ mutex_unlock(&pwrseq_list_mutex);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_register);
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_unregister - Remove pwrseq instance from global pwrseq list
|
||||
+ *
|
||||
+ * @pwrseq: the pwrseq instance
|
||||
+ */
|
||||
+void pwrseq_unregister(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ mutex_lock(&pwrseq_list_mutex);
|
||||
+ list_del(&pwrseq->node);
|
||||
+ mutex_unlock(&pwrseq_list_mutex);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_unregister);
|
||||
+
|
||||
+static struct pwrseq *pwrseq_find_available_instance(struct device_node *np)
|
||||
+{
|
||||
+ struct pwrseq *pwrseq;
|
||||
+
|
||||
+ mutex_lock(&pwrseq_list_mutex);
|
||||
+ list_for_each_entry(pwrseq, &pwrseq_list, node) {
|
||||
+ if (pwrseq->used)
|
||||
+ continue;
|
||||
+
|
||||
+ /* compare compatible string for pwrseq node */
|
||||
+ if (of_match_node(pwrseq->pwrseq_of_match_table, np)) {
|
||||
+ pwrseq->used = true;
|
||||
+ mutex_unlock(&pwrseq_list_mutex);
|
||||
+ return pwrseq;
|
||||
+ }
|
||||
+
|
||||
+ /* return generic pwrseq instance */
|
||||
+ if (!strcmp(pwrseq->pwrseq_of_match_table->compatible,
|
||||
+ "generic")) {
|
||||
+ pr_debug("using generic pwrseq instance for %s\n",
|
||||
+ np->full_name);
|
||||
+ pwrseq->used = true;
|
||||
+ mutex_unlock(&pwrseq_list_mutex);
|
||||
+ return pwrseq;
|
||||
+ }
|
||||
+ }
|
||||
+ mutex_unlock(&pwrseq_list_mutex);
|
||||
+ pr_debug("Can't find any pwrseq instances for %s\n", np->full_name);
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * of_pwrseq_on - Carry out power sequence on for device node
|
||||
+ *
|
||||
+ * @np: the device node would like to power on
|
||||
+ *
|
||||
+ * Carry out a single device power on. If multiple devices
|
||||
+ * need to be handled, use of_pwrseq_on_list() instead.
|
||||
+ *
|
||||
+ * Return a pointer to the power sequence instance on success,
|
||||
+ * or an error code otherwise.
|
||||
+ */
|
||||
+struct pwrseq *of_pwrseq_on(struct device_node *np)
|
||||
+{
|
||||
+ struct pwrseq *pwrseq;
|
||||
+ int ret;
|
||||
+
|
||||
+ pwrseq = pwrseq_find_available_instance(np);
|
||||
+ if (!pwrseq)
|
||||
+ return ERR_PTR(-ENOENT);
|
||||
+
|
||||
+ ret = pwrseq_get(np, pwrseq);
|
||||
+ if (ret) {
|
||||
+ /* Mark current pwrseq as unused */
|
||||
+ pwrseq->used = false;
|
||||
+ return ERR_PTR(ret);
|
||||
+ }
|
||||
+
|
||||
+ ret = pwrseq_on(pwrseq);
|
||||
+ if (ret)
|
||||
+ goto pwr_put;
|
||||
+
|
||||
+ return pwrseq;
|
||||
+
|
||||
+pwr_put:
|
||||
+ pwrseq_put(pwrseq);
|
||||
+ return ERR_PTR(ret);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(of_pwrseq_on);
|
||||
+
|
||||
+/**
|
||||
+ * of_pwrseq_off - Carry out power sequence off for this pwrseq instance
|
||||
+ *
|
||||
+ * @pwrseq: the pwrseq instance which related device would like to be off
|
||||
+ *
|
||||
+ * This API is used to power off single device, it is the opposite
|
||||
+ * operation for of_pwrseq_on.
|
||||
+ */
|
||||
+void of_pwrseq_off(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ pwrseq_off(pwrseq);
|
||||
+ pwrseq_put(pwrseq);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(of_pwrseq_off);
|
||||
+
|
||||
+/**
|
||||
+ * of_pwrseq_on_list - Carry out power sequence on for list
|
||||
+ *
|
||||
+ * @np: the device node would like to power on
|
||||
+ * @head: the list head for pwrseq list on this bus
|
||||
+ *
|
||||
+ * This API is used to power on multiple devices at single bus.
|
||||
+ * If there are several devices on bus (eg, USB bus), uses this
|
||||
+ * this API. Otherwise, use of_pwrseq_on instead. After the device
|
||||
+ * is powered on successfully, it will be added to pwrseq list for
|
||||
+ * this bus. The caller needs to use mutex_lock for concurrent.
|
||||
+ *
|
||||
+ * Return 0 on success, or an error value otherwise.
|
||||
+ */
|
||||
+int of_pwrseq_on_list(struct device_node *np, struct list_head *head)
|
||||
+{
|
||||
+ struct pwrseq *pwrseq;
|
||||
+ struct pwrseq_list_per_dev *pwrseq_list_node;
|
||||
+
|
||||
+ pwrseq_list_node = kzalloc(sizeof(*pwrseq_list_node), GFP_KERNEL);
|
||||
+ if (!pwrseq_list_node)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ pwrseq = of_pwrseq_on(np);
|
||||
+ if (IS_ERR(pwrseq)) {
|
||||
+ kfree(pwrseq_list_node);
|
||||
+ return PTR_ERR(pwrseq);
|
||||
+ }
|
||||
+
|
||||
+ pwrseq_list_node->pwrseq = pwrseq;
|
||||
+ list_add(&pwrseq_list_node->list, head);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(of_pwrseq_on_list);
|
||||
+
|
||||
+/**
|
||||
+ * of_pwrseq_off_list - Carry out power sequence off for the list
|
||||
+ *
|
||||
+ * @head: the list head for pwrseq instance list on this bus
|
||||
+ *
|
||||
+ * This API is used to power off all devices on this bus, it is
|
||||
+ * the opposite operation for of_pwrseq_on_list.
|
||||
+ * The caller needs to use mutex_lock for concurrent.
|
||||
+ */
|
||||
+void of_pwrseq_off_list(struct list_head *head)
|
||||
+{
|
||||
+ struct pwrseq *pwrseq;
|
||||
+ struct pwrseq_list_per_dev *pwrseq_list_node, *tmp_node;
|
||||
+
|
||||
+ list_for_each_entry_safe(pwrseq_list_node, tmp_node, head, list) {
|
||||
+ pwrseq = pwrseq_list_node->pwrseq;
|
||||
+ of_pwrseq_off(pwrseq);
|
||||
+ list_del(&pwrseq_list_node->list);
|
||||
+ kfree(pwrseq_list_node);
|
||||
+ }
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(of_pwrseq_off_list);
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_suspend - Carry out power sequence suspend for this pwrseq instance
|
||||
+ *
|
||||
+ * @pwrseq: the pwrseq instance
|
||||
+ *
|
||||
+ * This API is used to do suspend operation on pwrseq instance.
|
||||
+ *
|
||||
+ * Return 0 on success, or an error value otherwise.
|
||||
+ */
|
||||
+int pwrseq_suspend(struct pwrseq *p)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ if (p && p->suspend)
|
||||
+ ret = p->suspend(p);
|
||||
+ else
|
||||
+ return ret;
|
||||
+
|
||||
+ if (!ret)
|
||||
+ p->suspended = true;
|
||||
+ else
|
||||
+ pr_err("%s failed\n", __func__);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_suspend);
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_resume - Carry out power sequence resume for this pwrseq instance
|
||||
+ *
|
||||
+ * @pwrseq: the pwrseq instance
|
||||
+ *
|
||||
+ * This API is used to do resume operation on pwrseq instance.
|
||||
+ *
|
||||
+ * Return 0 on success, or an error value otherwise.
|
||||
+ */
|
||||
+int pwrseq_resume(struct pwrseq *p)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ if (p && p->resume)
|
||||
+ ret = p->resume(p);
|
||||
+ else
|
||||
+ return ret;
|
||||
+
|
||||
+ if (!ret)
|
||||
+ p->suspended = false;
|
||||
+ else
|
||||
+ pr_err("%s failed\n", __func__);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_resume);
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_suspend_list - Carry out power sequence suspend for list
|
||||
+ *
|
||||
+ * @head: the list head for pwrseq instance list on this bus
|
||||
+ *
|
||||
+ * This API is used to do suspend on all power sequence instances on this bus.
|
||||
+ * The caller needs to use mutex_lock for concurrent.
|
||||
+ */
|
||||
+int pwrseq_suspend_list(struct list_head *head)
|
||||
+{
|
||||
+ struct pwrseq *pwrseq;
|
||||
+ struct pwrseq_list_per_dev *pwrseq_list_node;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ list_for_each_entry(pwrseq_list_node, head, list) {
|
||||
+ ret = pwrseq_suspend(pwrseq_list_node->pwrseq);
|
||||
+ if (ret)
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (ret) {
|
||||
+ list_for_each_entry(pwrseq_list_node, head, list) {
|
||||
+ pwrseq = pwrseq_list_node->pwrseq;
|
||||
+ if (pwrseq->suspended)
|
||||
+ pwrseq_resume(pwrseq);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_suspend_list);
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_resume_list - Carry out power sequence resume for the list
|
||||
+ *
|
||||
+ * @head: the list head for pwrseq instance list on this bus
|
||||
+ *
|
||||
+ * This API is used to do resume on all power sequence instances on this bus.
|
||||
+ * The caller needs to use mutex_lock for concurrent.
|
||||
+ */
|
||||
+int pwrseq_resume_list(struct list_head *head)
|
||||
+{
|
||||
+ struct pwrseq_list_per_dev *pwrseq_list_node;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ list_for_each_entry(pwrseq_list_node, head, list) {
|
||||
+ ret = pwrseq_resume(pwrseq_list_node->pwrseq);
|
||||
+ if (ret)
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(pwrseq_resume_list);
|
||||
diff --git a/drivers/power/pwrseq/pwrseq_generic.c b/drivers/power/pwrseq/pwrseq_generic.c
|
||||
new file mode 100644
|
||||
index 000000000000..4e7c09086cfb
|
||||
--- /dev/null
|
||||
+++ b/drivers/power/pwrseq/pwrseq_generic.c
|
||||
@@ -0,0 +1,234 @@
|
||||
+/*
|
||||
+ * pwrseq_generic.c Generic power sequence handling
|
||||
+ *
|
||||
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
|
||||
+ * Author: Peter Chen <peter.chen@nxp.com>
|
||||
+ *
|
||||
+ * This program is free software: you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 of
|
||||
+ * the License as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/gpio.h>
|
||||
+#include <linux/gpio/consumer.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/of_gpio.h>
|
||||
+#include <linux/slab.h>
|
||||
+
|
||||
+#include <linux/power/pwrseq.h>
|
||||
+
|
||||
+struct pwrseq_generic {
|
||||
+ struct pwrseq pwrseq;
|
||||
+ struct gpio_desc *gpiod_reset;
|
||||
+ struct clk *clks[PWRSEQ_MAX_CLKS];
|
||||
+ u32 duration_us;
|
||||
+ bool suspended;
|
||||
+};
|
||||
+
|
||||
+#define to_generic_pwrseq(p) container_of(p, struct pwrseq_generic, pwrseq)
|
||||
+
|
||||
+static int pwrseq_generic_alloc_instance(void);
|
||||
+static const struct of_device_id generic_id_table[] = {
|
||||
+ { .compatible = "generic",},
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+
|
||||
+static int pwrseq_generic_suspend(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ int clk;
|
||||
+
|
||||
+ for (clk = PWRSEQ_MAX_CLKS - 1; clk >= 0; clk--)
|
||||
+ clk_disable_unprepare(pwrseq_gen->clks[clk]);
|
||||
+
|
||||
+ pwrseq_gen->suspended = true;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int pwrseq_generic_resume(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ int clk, ret = 0;
|
||||
+
|
||||
+ for (clk = 0; clk < PWRSEQ_MAX_CLKS && pwrseq_gen->clks[clk]; clk++) {
|
||||
+ ret = clk_prepare_enable(pwrseq_gen->clks[clk]);
|
||||
+ if (ret) {
|
||||
+ pr_err("Can't enable clock, ret=%d\n", ret);
|
||||
+ goto err_disable_clks;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ pwrseq_gen->suspended = false;
|
||||
+ return ret;
|
||||
+
|
||||
+err_disable_clks:
|
||||
+ while (--clk >= 0)
|
||||
+ clk_disable_unprepare(pwrseq_gen->clks[clk]);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void pwrseq_generic_put(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ int clk;
|
||||
+
|
||||
+ if (pwrseq_gen->gpiod_reset)
|
||||
+ gpiod_put(pwrseq_gen->gpiod_reset);
|
||||
+
|
||||
+ for (clk = 0; clk < PWRSEQ_MAX_CLKS; clk++)
|
||||
+ clk_put(pwrseq_gen->clks[clk]);
|
||||
+
|
||||
+ pwrseq_unregister(&pwrseq_gen->pwrseq);
|
||||
+ kfree(pwrseq_gen);
|
||||
+}
|
||||
+
|
||||
+static void pwrseq_generic_off(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ int clk;
|
||||
+
|
||||
+ if (pwrseq_gen->suspended)
|
||||
+ return;
|
||||
+
|
||||
+ for (clk = PWRSEQ_MAX_CLKS - 1; clk >= 0; clk--)
|
||||
+ clk_disable_unprepare(pwrseq_gen->clks[clk]);
|
||||
+}
|
||||
+
|
||||
+static int pwrseq_generic_on(struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ int clk, ret = 0;
|
||||
+ struct gpio_desc *gpiod_reset = pwrseq_gen->gpiod_reset;
|
||||
+
|
||||
+ for (clk = 0; clk < PWRSEQ_MAX_CLKS && pwrseq_gen->clks[clk]; clk++) {
|
||||
+ ret = clk_prepare_enable(pwrseq_gen->clks[clk]);
|
||||
+ if (ret) {
|
||||
+ pr_err("Can't enable clock, ret=%d\n", ret);
|
||||
+ goto err_disable_clks;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (gpiod_reset) {
|
||||
+ u32 duration_us = pwrseq_gen->duration_us;
|
||||
+
|
||||
+ if (duration_us <= 10)
|
||||
+ udelay(10);
|
||||
+ else
|
||||
+ usleep_range(duration_us, duration_us + 100);
|
||||
+ gpiod_set_value(gpiod_reset, 0);
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+
|
||||
+err_disable_clks:
|
||||
+ while (--clk >= 0)
|
||||
+ clk_disable_unprepare(pwrseq_gen->clks[clk]);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int pwrseq_generic_get(struct device_node *np, struct pwrseq *pwrseq)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen = to_generic_pwrseq(pwrseq);
|
||||
+ enum of_gpio_flags flags;
|
||||
+ int reset_gpio, clk, ret = 0;
|
||||
+
|
||||
+ for (clk = 0; clk < PWRSEQ_MAX_CLKS; clk++) {
|
||||
+ pwrseq_gen->clks[clk] = of_clk_get(np, clk);
|
||||
+ if (IS_ERR(pwrseq_gen->clks[clk])) {
|
||||
+ ret = PTR_ERR(pwrseq_gen->clks[clk]);
|
||||
+ if (ret != -ENOENT)
|
||||
+ goto err_put_clks;
|
||||
+ pwrseq_gen->clks[clk] = NULL;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ reset_gpio = of_get_named_gpio_flags(np, "reset-gpios", 0, &flags);
|
||||
+ if (gpio_is_valid(reset_gpio)) {
|
||||
+ unsigned long gpio_flags;
|
||||
+
|
||||
+ if (flags & OF_GPIO_ACTIVE_LOW)
|
||||
+ gpio_flags = GPIOF_ACTIVE_LOW | GPIOF_OUT_INIT_LOW;
|
||||
+ else
|
||||
+ gpio_flags = GPIOF_OUT_INIT_HIGH;
|
||||
+
|
||||
+ ret = gpio_request_one(reset_gpio, gpio_flags,
|
||||
+ "pwrseq-reset-gpios");
|
||||
+ if (ret)
|
||||
+ goto err_put_clks;
|
||||
+
|
||||
+ pwrseq_gen->gpiod_reset = gpio_to_desc(reset_gpio);
|
||||
+ of_property_read_u32(np, "reset-duration-us",
|
||||
+ &pwrseq_gen->duration_us);
|
||||
+ } else if (reset_gpio == -ENOENT) {
|
||||
+ ; /* no such gpio */
|
||||
+ } else {
|
||||
+ ret = reset_gpio;
|
||||
+ pr_err("Failed to get reset gpio on %s, err = %d\n",
|
||||
+ np->full_name, reset_gpio);
|
||||
+ goto err_put_clks;
|
||||
+ }
|
||||
+
|
||||
+ /* allocate new one for later pwrseq instance request */
|
||||
+ ret = pwrseq_generic_alloc_instance();
|
||||
+ if (ret)
|
||||
+ goto err_put_gpio;
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_put_gpio:
|
||||
+ if (pwrseq_gen->gpiod_reset)
|
||||
+ gpiod_put(pwrseq_gen->gpiod_reset);
|
||||
+err_put_clks:
|
||||
+ while (--clk >= 0)
|
||||
+ clk_put(pwrseq_gen->clks[clk]);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * pwrseq_generic_alloc_instance - power sequence instance allocation
|
||||
+ *
|
||||
+ * This function is used to allocate one generic power sequence instance,
|
||||
+ * it is called when the system boots up and after one power sequence
|
||||
+ * instance is got successfully.
|
||||
+ *
|
||||
+ * Return zero on success or an error code otherwise.
|
||||
+ */
|
||||
+static int pwrseq_generic_alloc_instance(void)
|
||||
+{
|
||||
+ struct pwrseq_generic *pwrseq_gen;
|
||||
+
|
||||
+ pwrseq_gen = kzalloc(sizeof(*pwrseq_gen), GFP_KERNEL);
|
||||
+ if (!pwrseq_gen)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ pwrseq_gen->pwrseq.pwrseq_of_match_table = generic_id_table;
|
||||
+ pwrseq_gen->pwrseq.get = pwrseq_generic_get;
|
||||
+ pwrseq_gen->pwrseq.on = pwrseq_generic_on;
|
||||
+ pwrseq_gen->pwrseq.off = pwrseq_generic_off;
|
||||
+ pwrseq_gen->pwrseq.put = pwrseq_generic_put;
|
||||
+ pwrseq_gen->pwrseq.suspend = pwrseq_generic_suspend;
|
||||
+ pwrseq_gen->pwrseq.resume = pwrseq_generic_resume;
|
||||
+
|
||||
+ pwrseq_register(&pwrseq_gen->pwrseq);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Allocate one pwrseq instance during boots up */
|
||||
+static int __init pwrseq_generic_register(void)
|
||||
+{
|
||||
+ return pwrseq_generic_alloc_instance();
|
||||
+}
|
||||
+postcore_initcall(pwrseq_generic_register)
|
||||
diff --git a/include/linux/power/pwrseq.h b/include/linux/power/pwrseq.h
|
||||
new file mode 100644
|
||||
index 000000000000..cbc344cdf9d2
|
||||
--- /dev/null
|
||||
+++ b/include/linux/power/pwrseq.h
|
||||
@@ -0,0 +1,81 @@
|
||||
+#ifndef __LINUX_PWRSEQ_H
|
||||
+#define __LINUX_PWRSEQ_H
|
||||
+
|
||||
+#include <linux/of.h>
|
||||
+
|
||||
+#define PWRSEQ_MAX_CLKS 3
|
||||
+
|
||||
+/**
|
||||
+ * struct pwrseq - the power sequence structure
|
||||
+ * @pwrseq_of_match_table: the OF device id table this pwrseq library supports
|
||||
+ * @node: the list pointer to be added to pwrseq list
|
||||
+ * @get: the API is used to get pwrseq instance from the device node
|
||||
+ * @on: do power on for this pwrseq instance
|
||||
+ * @off: do power off for this pwrseq instance
|
||||
+ * @put: release the resources on this pwrseq instance
|
||||
+ * @suspend: do suspend operation on this pwrseq instance
|
||||
+ * @resume: do resume operation on this pwrseq instance
|
||||
+ * @used: this pwrseq instance is used by device
|
||||
+ */
|
||||
+struct pwrseq {
|
||||
+ const struct of_device_id *pwrseq_of_match_table;
|
||||
+ struct list_head node;
|
||||
+ int (*get)(struct device_node *np, struct pwrseq *p);
|
||||
+ int (*on)(struct pwrseq *p);
|
||||
+ void (*off)(struct pwrseq *p);
|
||||
+ void (*put)(struct pwrseq *p);
|
||||
+ int (*suspend)(struct pwrseq *p);
|
||||
+ int (*resume)(struct pwrseq *p);
|
||||
+ bool used;
|
||||
+ bool suspended;
|
||||
+};
|
||||
+
|
||||
+/* used for power sequence instance list in one driver */
|
||||
+struct pwrseq_list_per_dev {
|
||||
+ struct pwrseq *pwrseq;
|
||||
+ struct list_head list;
|
||||
+};
|
||||
+
|
||||
+#if IS_ENABLED(CONFIG_POWER_SEQUENCE)
|
||||
+void pwrseq_register(struct pwrseq *pwrseq);
|
||||
+void pwrseq_unregister(struct pwrseq *pwrseq);
|
||||
+struct pwrseq *of_pwrseq_on(struct device_node *np);
|
||||
+void of_pwrseq_off(struct pwrseq *pwrseq);
|
||||
+int of_pwrseq_on_list(struct device_node *np, struct list_head *head);
|
||||
+void of_pwrseq_off_list(struct list_head *head);
|
||||
+int pwrseq_suspend(struct pwrseq *p);
|
||||
+int pwrseq_resume(struct pwrseq *p);
|
||||
+int pwrseq_suspend_list(struct list_head *head);
|
||||
+int pwrseq_resume_list(struct list_head *head);
|
||||
+#else
|
||||
+static inline void pwrseq_register(struct pwrseq *pwrseq) {}
|
||||
+static inline void pwrseq_unregister(struct pwrseq *pwrseq) {}
|
||||
+static inline struct pwrseq *of_pwrseq_on(struct device_node *np)
|
||||
+{
|
||||
+ return NULL;
|
||||
+}
|
||||
+static void of_pwrseq_off(struct pwrseq *pwrseq) {}
|
||||
+static int of_pwrseq_on_list(struct device_node *np, struct list_head *head)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+static void of_pwrseq_off_list(struct list_head *head) {}
|
||||
+static int pwrseq_suspend(struct pwrseq *p)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+static int pwrseq_resume(struct pwrseq *p)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+static int pwrseq_suspend_list(struct list_head *head)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+static int pwrseq_resume_list(struct list_head *head)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif /* CONFIG_POWER_SEQUENCE */
|
||||
+
|
||||
+#endif /* __LINUX_PWRSEQ_H */
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,49 +0,0 @@
|
||||
From bf1b3a63aa2f3438750f5acdf372705f8a1beb41 Mon Sep 17 00:00:00 2001
|
||||
From: Joshua Clayton <stillcompiling@gmail.com>
|
||||
Date: Thu, 18 May 2017 08:49:01 +0800
|
||||
Subject: [PATCH 5/9] ARM: dts: imx6qdl: Enable usb node children with <reg>
|
||||
|
||||
Give usb nodes #address and #size attributes, so that a child node
|
||||
representing a permanently connected device such as an onboard hub may
|
||||
be addressed with a <reg> attribute
|
||||
|
||||
Signed-off-by: Joshua Clayton <stillcompiling@gmail.com>
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
---
|
||||
arch/arm/boot/dts/imx6qdl.dtsi | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
|
||||
index fe17a3405edc..a5f2f981255f 100644
|
||||
--- a/arch/arm/boot/dts/imx6qdl.dtsi
|
||||
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
|
||||
@@ -977,6 +977,8 @@
|
||||
|
||||
usbh1: usb@2184200 {
|
||||
compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
reg = <0x02184200 0x200>;
|
||||
interrupts = <0 40 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX6QDL_CLK_USBOH3>;
|
||||
@@ -991,6 +993,8 @@
|
||||
|
||||
usbh2: usb@2184400 {
|
||||
compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
reg = <0x02184400 0x200>;
|
||||
interrupts = <0 41 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX6QDL_CLK_USBOH3>;
|
||||
@@ -1006,6 +1010,8 @@
|
||||
|
||||
usbh3: usb@2184600 {
|
||||
compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
reg = <0x02184600 0x200>;
|
||||
interrupts = <0 42 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX6QDL_CLK_USBOH3>;
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,74 +0,0 @@
|
||||
From 0ae59d1767a9cf9875b35a026b5df13eeb3694db Mon Sep 17 00:00:00 2001
|
||||
From: Joshua Clayton <stillcompiling@gmail.com>
|
||||
Date: Thu, 18 May 2017 08:49:03 +0800
|
||||
Subject: [PATCH 7/9] ARM: dts: imx6q-evi: Fix onboard hub reset line
|
||||
|
||||
Previously the onboard hub was made to work by treating its
|
||||
reset gpio as a regulator enable.
|
||||
Get rid of that kludge now that pwseq has added reset gpio support
|
||||
Move pin muxing the hub reset pin into the usbh1 group
|
||||
|
||||
Signed-off-by: Joshua Clayton <stillcompiling@gmail.com>
|
||||
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
||||
---
|
||||
arch/arm/boot/dts/imx6q-evi.dts | 25 +++++++------------------
|
||||
1 file changed, 7 insertions(+), 18 deletions(-)
|
||||
|
||||
diff --git a/arch/arm/boot/dts/imx6q-evi.dts b/arch/arm/boot/dts/imx6q-evi.dts
|
||||
index c63f371ede8b..546d9d4e8ca1 100644
|
||||
--- a/arch/arm/boot/dts/imx6q-evi.dts
|
||||
+++ b/arch/arm/boot/dts/imx6q-evi.dts
|
||||
@@ -55,18 +55,6 @@
|
||||
reg = <0x10000000 0x40000000>;
|
||||
};
|
||||
|
||||
- reg_usbh1_vbus: regulator-usbhubreset {
|
||||
- compatible = "regulator-fixed";
|
||||
- regulator-name = "usbh1_vbus";
|
||||
- regulator-min-microvolt = <5000000>;
|
||||
- regulator-max-microvolt = <5000000>;
|
||||
- enable-active-high;
|
||||
- startup-delay-us = <2>;
|
||||
- pinctrl-names = "default";
|
||||
- pinctrl-0 = <&pinctrl_usbh1_hubreset>;
|
||||
- gpio = <&gpio7 12 GPIO_ACTIVE_HIGH>;
|
||||
- };
|
||||
-
|
||||
reg_usb_otg_vbus: regulator-usbotgvbus {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "usb_otg_vbus";
|
||||
@@ -214,12 +202,18 @@
|
||||
};
|
||||
|
||||
&usbh1 {
|
||||
- vbus-supply = <®_usbh1_vbus>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_usbh1>;
|
||||
dr_mode = "host";
|
||||
disable-over-current;
|
||||
status = "okay";
|
||||
+
|
||||
+ usb2415host: hub@1 {
|
||||
+ compatible = "usb424,2513";
|
||||
+ reg = <1>;
|
||||
+ reset-gpios = <&gpio7 12 GPIO_ACTIVE_LOW>;
|
||||
+ reset-duration-us = <3000>;
|
||||
+ };
|
||||
};
|
||||
|
||||
&usbotg {
|
||||
@@ -482,11 +476,6 @@
|
||||
MX6QDL_PAD_GPIO_3__USB_H1_OC 0x1b0b0
|
||||
/* usbh1_b OC */
|
||||
MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x1b0b0
|
||||
- >;
|
||||
- };
|
||||
-
|
||||
- pinctrl_usbh1_hubreset: usbh1hubresetgrp {
|
||||
- fsl,pins = <
|
||||
MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x1b0b0
|
||||
>;
|
||||
};
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,11 +0,0 @@
|
||||
--- ./arch/arm/mm/cache-feroceon-l2.c.orig 2013-04-26 13:18:32.000000000 -0600
|
||||
+++ ./arch/arm/mm/cache-feroceon-l2.c 2013-04-28 04:01:09.815592333 -0600
|
||||
@@ -117,7 +117,7 @@ static inline void l2_inv_pa_range(unsig
|
||||
l2_put_va(va_start);
|
||||
}
|
||||
|
||||
-static inline void l2_inv_all(void)
|
||||
+static void l2_inv_all(void)
|
||||
{
|
||||
__asm__("mcr p15, 1, %0, c15, c11, 0" : : "r" (0));
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
--- ./arch/arm/boot/dts/imx6qdl-hummingboard.dtsi.orig 2015-01-08 11:30:41.000000000 -0700
|
||||
+++ ./arch/arm/boot/dts/imx6qdl-hummingboard.dtsi 2015-01-13 14:19:29.696485445 -0700
|
||||
@@ -94,6 +94,31 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
+&i2c3 {
|
||||
+ clock-frequency = <100000>;
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&pinctrl_hummingboard_i2c3>;
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&ecspi2 {
|
||||
+ fsl,spi-num-chipselects = <2>;
|
||||
+ cs-gpios = <&gpio2 26 1>, <&gpio2 27 1>;
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&pinctrl_hummingboard_spi>;
|
||||
+ status = "okay";
|
||||
+ spidev@0x00 {
|
||||
+ compatible = "spidev";
|
||||
+ spi-max-frequency = <5000000>;
|
||||
+ reg = <0>;
|
||||
+ };
|
||||
+ spidev@0x01 {
|
||||
+ compatible = "spidev";
|
||||
+ spi-max-frequency = <5000000>;
|
||||
+ reg = <1>;
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
&iomuxc {
|
||||
hummingboard {
|
||||
pinctrl_hummingboard_flexcan1: hummingboard-flexcan1 {
|
||||
@@ -103,6 +128,17 @@
|
||||
>;
|
||||
};
|
||||
|
||||
+ pinctrl_hummingboard_spi: hummingboard_spi {
|
||||
+ fsl,pins = <
|
||||
+ MX6QDL_PAD_EIM_OE__ECSPI2_MISO 0x100b1
|
||||
+ MX6QDL_PAD_EIM_CS1__ECSPI2_MOSI 0x100b1
|
||||
+ MX6QDL_PAD_EIM_CS0__ECSPI2_SCLK 0x100b1
|
||||
+ /* MX6QDL_PAD_EIM_RW__ECSPI2_SS0 0x100b1 */
|
||||
+ MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x100b1
|
||||
+ MX6QDL_PAD_EIM_LBA__ECSPI2_SS1 0x100b1
|
||||
+ >;
|
||||
+ };
|
||||
+
|
||||
pinctrl_hummingboard_gpio3_5: hummingboard-gpio3_5 {
|
||||
fsl,pins = <
|
||||
MX6QDL_PAD_EIM_DA5__GPIO3_IO05 0x1b0b1
|
||||
@@ -129,6 +165,13 @@
|
||||
>;
|
||||
};
|
||||
|
||||
+ pinctrl_hummingboard_i2c3: hummingboard-i2c3 {
|
||||
+ fsl,pins = <
|
||||
+ MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1
|
||||
+ MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1
|
||||
+ >;
|
||||
+ };
|
||||
+
|
||||
pinctrl_hummingboard_spdif: hummingboard-spdif {
|
||||
fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x13091>;
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
--- ./fs/timerfd.c.orig 2015-11-09 15:37:56.000000000 -0700
|
||||
+++ ./fs/timerfd.c 2015-11-14 08:20:51.720068530 -0700
|
||||
@@ -134,7 +134,7 @@ static void timerfd_setup_cancel(struct
|
||||
{
|
||||
if ((ctx->clockid == CLOCK_REALTIME ||
|
||||
ctx->clockid == CLOCK_REALTIME_ALARM) &&
|
||||
- (flags & TFD_TIMER_ABSTIME) && (flags & TFD_TIMER_CANCEL_ON_SET)) {
|
||||
+ (flags & TFD_TIMER_CANCEL_ON_SET)) {
|
||||
if (!ctx->might_cancel) {
|
||||
ctx->might_cancel = true;
|
||||
spin_lock(&cancel_lock);
|
@ -1,43 +0,0 @@
|
||||
config: # This is file 'patch/kernel/archive/meson64-6.4/0000.patching_config.yaml'
|
||||
|
||||
# Just some info stuff; not used by the patching scripts
|
||||
name: meson64-6.4
|
||||
kind: kernel
|
||||
type: mainline # or: vendor
|
||||
branch: linux-6.4.y
|
||||
last-known-good-tag: v6.4-rc5
|
||||
maintainers:
|
||||
- { github: rpardini, name: Ricardo Pardini, email: ricardo@pardini.net, armbian-forum: rpardini }
|
||||
|
||||
# Automatic grabbing of patches from mailing lists, using 'b4' tool 'am' command.
|
||||
# Patches will be grabbed and written to disk in the order they are listed here, before any other processing is done.
|
||||
#b4-am:
|
||||
# - { prefix: "0666", lore: "https://lore.kernel.org/r/20230706-topic-amlogic-upstream-dt-fixes-take3-v1-0-63ed070eeab2@linaro.org" }
|
||||
|
||||
# .dts files in these directories will be copied as-is to the build tree; later ones overwrite earlier ones.
|
||||
# This is meant to provide a way to "add a board DTS" without having to null-patch them in.
|
||||
dts-directories:
|
||||
# will copy patch/kernel/archive/meson64-6.4/dt-boards/*.dts to arch/arm64/boot/dts/amlogic
|
||||
- { source: "dt", target: "arch/arm64/boot/dts/amlogic" }
|
||||
|
||||
# every file in these directories will be copied as-is to the build tree; later ones overwrite earlier ones
|
||||
# This is meant as a way to have overlays, bare, in a directory, without having to null-patch them in.
|
||||
# @TODO need a solution to auto-Makefile the overlays as well
|
||||
overlay-directories:
|
||||
# will copy patch/kernel/archive/meson64-6.4/overlay/**/* to arch/arm64/boot/dts/amlogic/overlay
|
||||
- { source: "overlay", target: "arch/arm64/boot/dts/amlogic/overlay" }
|
||||
|
||||
# the Makefile in each of these directories will be magically patched to include the dts files copied
|
||||
# or patched-in; overlay subdir will be included "-y" if it exists.
|
||||
# No more Makefile patching needed, yay!
|
||||
auto-patch-dt-makefile:
|
||||
- { directory: "arch/arm64/boot/dts/amlogic", config-var: "CONFIG_ARCH_MESON" }
|
||||
|
||||
# configuration for when applying patches to git / auto-rewriting patches (development cycle helpers)
|
||||
patches-to-git:
|
||||
do-not-commit-files:
|
||||
- "MAINTAINERS" # constant churn, drop them. sorry.
|
||||
- "Documentation/devicetree/bindings/arm/amlogic.yaml" # constant churn, conflicts on every bump, drop it. sorry.
|
||||
do-not-commit-regexes: # Python-style regexes
|
||||
- "^arch/([a-zA-Z0-9]+)/boot/dts/([a-zA-Z0-9]+)/Makefile$" # ignore DT Makefile patches, we've an auto-patcher now
|
||||
|
@ -1,63 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Patrick Yavitz <pyavitz@gmail.com>
|
||||
Date: Thu, 1 Jun 2023 06:32:23 +0200
|
||||
Subject: arm64: dts: amlogic: pyavitz's fixes for the BananaPi CM4
|
||||
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4-cm4io.dts | 11 ++++++++--
|
||||
arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4.dtsi | 4 ++--
|
||||
2 files changed, 11 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4-cm4io.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4-cm4io.dts
|
||||
index 1b0c3881c6a1..cba456022918 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4-cm4io.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4-cm4io.dts
|
||||
@@ -20,6 +20,12 @@ aliases {
|
||||
i2c1 = &i2c3;
|
||||
};
|
||||
|
||||
+ reboot: meson64-reboot {
|
||||
+ compatible = "meson64,reboot";
|
||||
+ sys_reset = <0x84000009>;
|
||||
+ sys_poweroff = <0x84000008>;
|
||||
+ };
|
||||
+
|
||||
adc-keys {
|
||||
compatible = "adc-keys";
|
||||
io-channels = <&saradc 2>;
|
||||
@@ -50,14 +56,15 @@ leds {
|
||||
led-blue {
|
||||
color = <LED_COLOR_ID_BLUE>;
|
||||
function = LED_FUNCTION_STATUS;
|
||||
- gpios = <&gpio_ao GPIOAO_7 GPIO_ACTIVE_HIGH>;
|
||||
+ gpios = <&gpio_ao GPIOAO_7 GPIO_ACTIVE_LOW>;
|
||||
linux,default-trigger = "heartbeat";
|
||||
};
|
||||
|
||||
led-green {
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
function = LED_FUNCTION_STATUS;
|
||||
- gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_HIGH>;
|
||||
+ gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_LOW>;
|
||||
+ linux,default-trigger = "default-on";
|
||||
};
|
||||
};
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4.dtsi
|
||||
index 97e522921b06..074ced419dfa 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4.dtsi
|
||||
@@ -369,8 +369,8 @@ &uart_A {
|
||||
|
||||
bluetooth {
|
||||
compatible = "realtek,rtl8822cs-bt";
|
||||
- enable-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>;
|
||||
- host-wake-gpios = <&gpio GPIOX_19 GPIO_ACTIVE_HIGH>;
|
||||
+ enable-gpios = <&gpio GPIOX_19 GPIO_ACTIVE_HIGH>;
|
||||
+ //host-wake-gpios = <&gpio GPIOX_19 GPIO_ACTIVE_HIGH>;
|
||||
device-wake-gpios = <&gpio GPIOX_18 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
||||
--
|
||||
Armbian
|
||||
|
@ -1,31 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
|
||||
Date: Tue, 25 Jul 2023 16:27:03 +0200
|
||||
Subject: arm64: dts: amlogic: meson-g12b-bananapi: switch to enable-gpios
|
||||
|
||||
The recommended name for enable GPIOs property in regulator-gpio is
|
||||
enable-gpios. This is also required by bindings:
|
||||
|
||||
meson-g12b-bananapi-cm4-cm4io.dtb: regulator-vddio-c: Unevaluated properties are not allowed ('enable-gpio' was unexpected)
|
||||
|
||||
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4.dtsi | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4.dtsi
|
||||
index 074ced419dfa..ccfbbea5cf17 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4.dtsi
|
||||
@@ -56,7 +56,7 @@ vddio_c: regulator-vddio-c {
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
|
||||
- enable-gpio = <&gpio_ao GPIOAO_3 GPIO_OPEN_DRAIN>;
|
||||
+ enable-gpios = <&gpio_ao GPIOAO_3 GPIO_OPEN_DRAIN>;
|
||||
enable-active-high;
|
||||
regulator-always-on;
|
||||
|
||||
--
|
||||
Armbian
|
||||
|
@ -1,62 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Patrick Yavitz <pyavitz@xxxxx.com>
|
||||
Date: Fri, 21 Jul 2023 09:35:52 -0400
|
||||
Subject: Add support for the meson64-reboot driver
|
||||
|
||||
Signed-off-by: Patrick Yavitz <pyavitz@xxxxx.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-g12b-a311d-bananapi-m2s.dts | 4 ++++
|
||||
arch/arm64/boot/dts/amlogic/meson-g12b-bananapi.dtsi | 9 +++++++++
|
||||
arch/arm64/boot/dts/amlogic/meson-g12b-s922x-bananapi-m2s.dts | 4 ++++
|
||||
3 files changed, 17 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-a311d-bananapi-m2s.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-a311d-bananapi-m2s.dts
|
||||
index ac6f7ae1d103..55b691368598 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-g12b-a311d-bananapi-m2s.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-g12b-a311d-bananapi-m2s.dts
|
||||
@@ -18,6 +18,10 @@ aliases {
|
||||
};
|
||||
};
|
||||
|
||||
+&reboot {
|
||||
+ sd-vqen = <&gpio_ao GPIOAO_3 GPIO_ACTIVE_HIGH>;
|
||||
+};
|
||||
+
|
||||
/* Camera (CSI) bus */
|
||||
&i2c1 {
|
||||
status = "okay";
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi.dtsi
|
||||
index 83709787eb91..af102061d1d7 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi.dtsi
|
||||
@@ -17,6 +17,15 @@ aliases {
|
||||
rtc1 = &vrtc;
|
||||
};
|
||||
|
||||
+ reboot: meson64-reboot {
|
||||
+ compatible = "meson64,reboot";
|
||||
+ sys_reset = <0x84000009>;
|
||||
+ sys_poweroff = <0x84000008>;
|
||||
+
|
||||
+ sd-vqsw = <&gpio_ao GPIOAO_9 GPIO_ACTIVE_HIGH>;
|
||||
+ sd-vmmc = <&gpio_ao GPIOAO_8 GPIO_ACTIVE_HIGH>;
|
||||
+ };
|
||||
+
|
||||
chosen {
|
||||
stdout-path = "serial0:115200n8";
|
||||
};
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-s922x-bananapi-m2s.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-s922x-bananapi-m2s.dts
|
||||
index 7f66f263a2ce..3295649664d7 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-g12b-s922x-bananapi-m2s.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-g12b-s922x-bananapi-m2s.dts
|
||||
@@ -12,3 +12,7 @@ / {
|
||||
compatible = "bananapi,bpi-m2s", "amlogic,s922x", "amlogic,g12b";
|
||||
model = "BananaPi M2S";
|
||||
};
|
||||
+
|
||||
+&reboot {
|
||||
+ sd-vqen = <&gpio_ao GPIOAO_3 GPIO_ACTIVE_HIGH>;
|
||||
+};
|
||||
--
|
||||
Armbian
|
||||
|
@ -1,45 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Pecovnik <igor.pecovnik@gmail.com>
|
||||
Date: Sat, 11 Feb 2023 18:30:00 +0100
|
||||
Subject: BananaPi M5: 270 clock phase, via amlogic,mmc-phase
|
||||
|
||||
Rework of Ricardo Pardini <ricardo@pardini.net> patch.
|
||||
|
||||
Signed-off-by: Igor Pecovnik <igor.pecovnik@gmail.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-sm1-bananapi.dtsi | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1-bananapi.dtsi b/arch/arm64/boot/dts/amlogic/meson-sm1-bananapi.dtsi
|
||||
index 17045ff81c69..7e80151874f1 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-sm1-bananapi.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-sm1-bananapi.dtsi
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <dt-bindings/leds/common.h>
|
||||
#include <dt-bindings/input/linux-event-codes.h>
|
||||
#include <dt-bindings/gpio/meson-g12a-gpio.h>
|
||||
+#include <dt-bindings/mmc/meson-gx-mmc.h>
|
||||
|
||||
/ {
|
||||
adc-keys {
|
||||
@@ -394,6 +395,8 @@ &sd_emmc_b {
|
||||
cd-gpios = <&gpio GPIOC_6 GPIO_ACTIVE_LOW>;
|
||||
vmmc-supply = <&tflash_vdd>;
|
||||
vqmmc-supply = <&vddio_c>;
|
||||
+
|
||||
+ amlogic,mmc-phase = <CLK_PHASE_270 CLK_PHASE_0 CLK_PHASE_0>;
|
||||
};
|
||||
|
||||
/* eMMC */
|
||||
@@ -413,6 +416,8 @@ &sd_emmc_c {
|
||||
mmc-pwrseq = <&emmc_pwrseq>;
|
||||
vmmc-supply = <&vddao_3v3>;
|
||||
vqmmc-supply = <&emmc_1v8>;
|
||||
+
|
||||
+ amlogic,mmc-phase = <CLK_PHASE_270 CLK_PHASE_0 CLK_PHASE_0>;
|
||||
};
|
||||
|
||||
&uart_AO {
|
||||
--
|
||||
Armbian
|
||||
|
@ -1,112 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Patrick Yavitz <pyavitz@xxxxx.com>
|
||||
Date: Wed, 2 Aug 2023 19:36:07 -0400
|
||||
Subject: arch: arm64: dts: amlogic: add wifi/bt support to bananapi m5
|
||||
|
||||
The BPI-M5 has an optional RTL8822CS WiFi/BT mezzanine board. Describe
|
||||
the board but mark the sd_emmc_a and uart_A nodes disabled so they can
|
||||
be enabled via overlay or fdtput when the board is connected.
|
||||
|
||||
Signed-off-by: Patrick Yavitz <pyavitz@xxxxx.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-sm1-bananapi-m5.dts | 66 +++++++++-
|
||||
1 file changed, 65 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1-bananapi-m5.dts b/arch/arm64/boot/dts/amlogic/meson-sm1-bananapi-m5.dts
|
||||
index f045bf851638..5f6071ee84a6 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-sm1-bananapi-m5.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-sm1-bananapi-m5.dts
|
||||
@@ -25,6 +25,20 @@ cvbs_connector_in: endpoint {
|
||||
};
|
||||
};
|
||||
|
||||
+ sdio_pwrseq: sdio-pwrseq {
|
||||
+ compatible = "mmc-pwrseq-simple";
|
||||
+ reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>;
|
||||
+ clocks = <&wifi32k>;
|
||||
+ clock-names = "ext_clock";
|
||||
+ };
|
||||
+
|
||||
+ wifi32k: wifi32k {
|
||||
+ compatible = "pwm-clock";
|
||||
+ #clock-cells = <0>;
|
||||
+ clock-frequency = <32768>;
|
||||
+ pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */
|
||||
+ };
|
||||
+
|
||||
sound {
|
||||
compatible = "amlogic,axg-sound-card";
|
||||
model = "BPI-M5";
|
||||
@@ -149,7 +163,6 @@ &acodec {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
-
|
||||
&clkc_audio {
|
||||
status = "okay";
|
||||
};
|
||||
@@ -172,6 +185,42 @@ &frddr_c {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
+&pwm_ef {
|
||||
+ status = "okay";
|
||||
+ pinctrl-0 = <&pwm_e_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+};
|
||||
+
|
||||
+/* SDIO */
|
||||
+&sd_emmc_a {
|
||||
+ /* enable if WiFi/BT board connected */
|
||||
+ status = "disabled";
|
||||
+ pinctrl-0 = <&sdio_pins>;
|
||||
+ pinctrl-1 = <&sdio_clk_gate_pins>;
|
||||
+ pinctrl-names = "default", "clk-gate";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+
|
||||
+ bus-width = <4>;
|
||||
+ sd-uhs-sdr104;
|
||||
+ max-frequency = <50000000>;
|
||||
+
|
||||
+ non-removable;
|
||||
+ disable-wp;
|
||||
+
|
||||
+ /* WiFi firmware requires power in suspend */
|
||||
+ keep-power-in-suspend;
|
||||
+
|
||||
+ mmc-pwrseq = <&sdio_pwrseq>;
|
||||
+
|
||||
+ vmmc-supply = <&vddao_3v3>;
|
||||
+ vqmmc-supply = <&vddao_1v8>;
|
||||
+
|
||||
+ rtl8822cs: wifi@1 {
|
||||
+ reg = <1>;
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
&tdmif_b {
|
||||
status = "okay";
|
||||
};
|
||||
@@ -219,3 +268,18 @@ &toddr_b {
|
||||
&toddr_c {
|
||||
status = "okay";
|
||||
};
|
||||
+
|
||||
+&uart_A {
|
||||
+ /* enable if WiFi/BT board connected */
|
||||
+ status = "disabled";
|
||||
+ pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+ uart-has-rtscts;
|
||||
+
|
||||
+ bluetooth {
|
||||
+ compatible = "realtek,rtl8822cs-bt";
|
||||
+ enable-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>;
|
||||
+ host-wake-gpios = <&gpio GPIOX_19 GPIO_ACTIVE_HIGH>;
|
||||
+ device-wake-gpios = <&gpio GPIOX_18 GPIO_ACTIVE_HIGH>;
|
||||
+ };
|
||||
+};
|
||||
--
|
||||
Armbian
|
||||
|
@ -1,85 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Patrick Yavitz <pyavitz@xxxxx.com>
|
||||
Date: Thu, 21 Sep 2023 07:46:59 -0400
|
||||
Subject: arm64: dts: amlogic: meson-sm1-bananapi: add uart A and AO_B
|
||||
|
||||
Signed-off-by: Patrick Yavitz <pyavitz@xxxxx.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi | 9 +++++++++
|
||||
arch/arm64/boot/dts/amlogic/meson-sm1-bananapi-m2-pro.dts | 10 ++++++++++
|
||||
arch/arm64/boot/dts/amlogic/meson-sm1-bananapi.dtsi | 7 +++++++
|
||||
3 files changed, 26 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi
|
||||
index 0c49655cc90c..016529233345 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi
|
||||
@@ -1899,6 +1899,15 @@ mux {
|
||||
};
|
||||
};
|
||||
|
||||
+ uart_ao_b_pins: uart-b-ao {
|
||||
+ mux {
|
||||
+ groups = "uart_ao_b_tx_8",
|
||||
+ "uart_ao_b_rx_9";
|
||||
+ function = "uart_ao_b";
|
||||
+ bias-disable;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
uart_ao_a_cts_rts_pins: uart-ao-a-cts-rts {
|
||||
mux {
|
||||
groups = "uart_ao_a_cts",
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1-bananapi-m2-pro.dts b/arch/arm64/boot/dts/amlogic/meson-sm1-bananapi-m2-pro.dts
|
||||
index 586034316ec3..5ccdc91ac276 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-sm1-bananapi-m2-pro.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-sm1-bananapi-m2-pro.dts
|
||||
@@ -13,6 +13,10 @@ / {
|
||||
compatible = "bananapi,bpi-m2-pro", "amlogic,sm1";
|
||||
model = "Banana Pi BPI-M2-PRO";
|
||||
|
||||
+ aliases {
|
||||
+ serial1 = &uart_A;
|
||||
+ };
|
||||
+
|
||||
sound {
|
||||
compatible = "amlogic,axg-sound-card";
|
||||
model = "BPI-M2-PRO";
|
||||
@@ -95,3 +99,9 @@ &tdmout_b {
|
||||
&tohdmitx {
|
||||
status = "okay";
|
||||
};
|
||||
+
|
||||
+&uart_A {
|
||||
+ status = "disabled";
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&uart_a_pins>;
|
||||
+};
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1-bananapi.dtsi b/arch/arm64/boot/dts/amlogic/meson-sm1-bananapi.dtsi
|
||||
index 7e80151874f1..1ab93090dc4c 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-sm1-bananapi.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-sm1-bananapi.dtsi
|
||||
@@ -26,6 +26,7 @@ button-sw3 {
|
||||
|
||||
aliases {
|
||||
serial0 = &uart_AO;
|
||||
+ serial4 = &uart_AO_B;
|
||||
ethernet0 = ðmac;
|
||||
};
|
||||
|
||||
@@ -426,6 +427,12 @@ &uart_AO {
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
+&uart_AO_B {
|
||||
+ status = "disabled";
|
||||
+ pinctrl-0 = <&uart_ao_b_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+};
|
||||
+
|
||||
&usb {
|
||||
status = "okay";
|
||||
};
|
||||
--
|
||||
Armbian
|
||||
|
@ -1,37 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Hewitt <christianshewitt@gmail.com>
|
||||
Date: Fri, 21 Feb 2020 04:43:22 +0000
|
||||
Subject: WIP: arm64: dts: meson: khadas-vim3: fix missing i2c3 node
|
||||
|
||||
Fixes: c6d29c66e582 ("arm64: dts: meson-g12b-khadas-vim3: add initial device-tree")
|
||||
|
||||
The i2c3 node was missed in the original device-tree and is required for the
|
||||
optional Khadas 3705 fan to work.
|
||||
|
||||
Suggested-by: Art Nikpal <email2tema@gmail.com>
|
||||
Signed-off-by: Christian Hewittt <christianshewitt@gmail.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi b/arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi
|
||||
index c9705941e4ab..71a5c0aa2a9b 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi
|
||||
@@ -333,6 +333,13 @@ hdmi_tx_tmds_out: endpoint {
|
||||
};
|
||||
};
|
||||
|
||||
+&i2c3 {
|
||||
+ clock-frequency = <100000>;
|
||||
+ pinctrl-0 = <&i2c3_sda_a_pins>, <&i2c3_sck_a_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&i2c_AO {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&i2c_ao_sck_pins>, <&i2c_ao_sda_pins>;
|
||||
--
|
||||
Armbian
|
||||
|
@ -1,58 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Hewitt <christianshewitt@gmail.com>
|
||||
Date: Thu, 21 Jan 2021 01:35:36 +0000
|
||||
Subject: HACK: arm64: dts: meson: add rtc/vrtc aliases to Khadas VIM
|
||||
|
||||
Add aliases to ensure the vrtc time (which normally proves first) is /dev/rtc1
|
||||
while the onboard rtc chip claims /dev/rtc0.
|
||||
|
||||
Signed-off-by: Christian Hewitt <christianshewitt@gmail.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
|
||||
index 02f81839d4e3..2f88f78de5b7 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
|
||||
@@ -29,6 +29,8 @@ button-function {
|
||||
aliases {
|
||||
serial2 = &uart_AO_B;
|
||||
ethernet0 = ðmac;
|
||||
+ rtc0 = &rtc;
|
||||
+ rtc1 = &vrtc;
|
||||
};
|
||||
|
||||
gpio-keys-polled {
|
||||
--
|
||||
Armbian
|
||||
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Hewitt <christianshewitt@gmail.com>
|
||||
Date: Sat, 6 Nov 2021 13:01:08 +0000
|
||||
Subject: HACK: arm64: dts: meson: add rtc/vrtc aliases to Khadas VIM2
|
||||
|
||||
Add aliases to ensure the vrtc time (which normally proves first) is /dev/rtc1
|
||||
while the onboard rtc chip claims /dev/rtc0.
|
||||
|
||||
Signed-off-by: Christian Hewitt <christianshewitt@gmail.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
|
||||
index 74897a154891..be3e91bbfb2f 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
|
||||
@@ -18,6 +18,8 @@ / {
|
||||
aliases {
|
||||
serial0 = &uart_AO;
|
||||
serial2 = &uart_AO_B;
|
||||
+ rtc0 = &rtc;
|
||||
+ rtc1 = &vrtc;
|
||||
};
|
||||
|
||||
chosen {
|
||||
--
|
||||
Armbian
|
||||
|
@ -1,26 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Ayotte <martinayotte@yahoo.ca>
|
||||
Date: Thu, 6 Dec 2018 18:03:17 -0500
|
||||
Subject: add uartC alias for nanopi-k2
|
||||
|
||||
add uartC alias for nanopi-k2
|
||||
- 839f2f151073928ed1e62d415ba5317f525b9e24: 1553615840: Martin Ayotte <martinayotte@yahoo.ca>: 'add uartA overlay for Odroid-C2'
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
|
||||
index 7d94160f5802..cf577bc8d98b 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
|
||||
@@ -15,6 +15,7 @@ / {
|
||||
|
||||
aliases {
|
||||
serial0 = &uart_AO;
|
||||
+ serial2 = &uart_C;
|
||||
ethernet0 = ðmac;
|
||||
};
|
||||
|
||||
--
|
||||
Armbian
|
||||
|
@ -1,35 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Pecovnik <igor.pecovnik@gmail.com>
|
||||
Date: Tue, 4 Jun 2019 21:35:48 +0200
|
||||
Subject: nanopik2 - enable eMMC
|
||||
|
||||
[ nanopik2 ] enable eMMC support for u-boot and kernel
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts | 4 +---
|
||||
1 file changed, 1 insertion(+), 3 deletions(-)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
|
||||
index cf577bc8d98b..2ee48261a2ea 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
|
||||
@@ -359,7 +359,7 @@ &sd_emmc_b {
|
||||
|
||||
/* eMMC */
|
||||
&sd_emmc_c {
|
||||
- status = "disabled";
|
||||
+ status = "okay";
|
||||
pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>;
|
||||
pinctrl-1 = <&emmc_clk_gate_pins>;
|
||||
pinctrl-names = "default", "clk-gate";
|
||||
@@ -369,8 +369,6 @@ &sd_emmc_c {
|
||||
non-removable;
|
||||
disable-wp;
|
||||
cap-mmc-highspeed;
|
||||
- mmc-ddr-1_8v;
|
||||
- mmc-hs200-1_8v;
|
||||
|
||||
mmc-pwrseq = <&emmc_pwrseq>;
|
||||
vmmc-supply = <&vcc3v3>;
|
||||
--
|
||||
Armbian
|
||||
|
@ -1,50 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Ayotte <martinayotte@yahoo.ca>
|
||||
Date: Thu, 26 Oct 2017 16:31:22 +0300
|
||||
Subject: add uartA and uartC for Odroid-C2
|
||||
|
||||
add uartA and uartC for Odroid-C2
|
||||
|
||||
- 839f2f151073928ed1e62d415ba5317f525b9e24: Martin Ayotte <martinayotte@yahoo.ca>: 'add uartA overlay for Odroid-C2'
|
||||
- b5c9e6ee8d4a97c5092109a12164c131eb4b46e9: Martin Ayotte <martinayotte@yahoo.ca>: 'add uartA for odroidc2 in NEXT'
|
||||
- 22ca2b92a002fe22e2a61428741618295c424664: Martin Ayotte <martinayotte@yahoo.ca>: 'fix missing pinctrl-0 for ODroidC2 uartA'
|
||||
- 140da6ad43f4a0d47c221271f62bb7c0a57064ea: Martin Ayotte <martinayotte@yahoo.ca>: 'add uartC to OdroidC2'
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts | 14 ++++++++++
|
||||
1 file changed, 14 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
index 01356437a077..5923aa327e48 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
@@ -17,6 +17,8 @@ / {
|
||||
|
||||
aliases {
|
||||
serial0 = &uart_AO;
|
||||
+ serial1 = &uart_A;
|
||||
+ serial2 = &uart_C;
|
||||
ethernet0 = ðmac;
|
||||
};
|
||||
|
||||
@@ -384,6 +386,18 @@ &uart_AO {
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
+&uart_A {
|
||||
+ status = "disabled";
|
||||
+ pinctrl-0 = <&uart_a_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+};
|
||||
+
|
||||
+&uart_C {
|
||||
+ status = "disabled";
|
||||
+ pinctrl-0 = <&uart_c_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+};
|
||||
+
|
||||
&usb0_phy {
|
||||
status = "disabled";
|
||||
phy-supply = <&usb_otg_pwr>;
|
||||
--
|
||||
Armbian
|
||||
|
@ -1,52 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Thomas McKahan <tonymckahan@gmail.com>
|
||||
Date: Sat, 6 Oct 2018 22:50:14 -0400
|
||||
Subject: Odroid C2 enable SPI
|
||||
|
||||
Odroid C2 enable SPI
|
||||
|
||||
- f928b31d8a1983fd8cfd9c97de084e532283b106: 1543550719: Thomas McKahan <tonymckahan@gmail.com>: '[ meson64-dev ] fix Odroid C2 boot, add spidev'
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts | 26 ++++++++++
|
||||
1 file changed, 26 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
index 5923aa327e48..83e155cab673 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
@@ -176,6 +176,32 @@ hdmi_connector_in: endpoint {
|
||||
};
|
||||
};
|
||||
|
||||
+ spi-gpio {
|
||||
+ compatible = "spi-gpio";
|
||||
+ #address-cells = <0x1>;
|
||||
+ #size-cells = <0x0>;
|
||||
+ ranges;
|
||||
+ status = "disabled";
|
||||
+ sck-gpios = <&gpio GPIOX_2 0>;
|
||||
+ miso-gpios = <&gpio GPIOX_4 0>;
|
||||
+ mosi-gpios = <&gpio GPIOX_7 0>;
|
||||
+ cs-gpios = <&gpio GPIOX_3 0
|
||||
+ &gpio GPIOX_1 0>;
|
||||
+ num-chipselects = <2>;
|
||||
+
|
||||
+ /* clients */
|
||||
+ spidev0@0 {
|
||||
+ compatible = "spidev";
|
||||
+ reg = <0>;
|
||||
+ spi-max-frequency = <500000>;
|
||||
+ };
|
||||
+ spidev0@1 {
|
||||
+ compatible = "spidev";
|
||||
+ reg = <1>;
|
||||
+ spi-max-frequency = <500000>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
sound {
|
||||
compatible = "amlogic,gx-sound-card";
|
||||
model = "ODROID-C2";
|
||||
--
|
||||
Armbian
|
||||
|
@ -1,27 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: zador-blood-stained <zador-blood-stained@users.noreply.github.com>
|
||||
Date: Thu, 26 Oct 2017 16:31:22 +0300
|
||||
Subject: Enable odroidc2-dev DVFS
|
||||
|
||||
Enable odroidc2-dev DVFS (#763)
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
index 83e155cab673..ef74a35c8f4e 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
@@ -361,7 +361,8 @@ &saradc {
|
||||
};
|
||||
|
||||
&scpi_clocks {
|
||||
- status = "disabled";
|
||||
+ /* Works only with new blobs that have limited DVFS table */
|
||||
+ status = "okay";
|
||||
};
|
||||
|
||||
/* SD */
|
||||
--
|
||||
Armbian
|
||||
|
@ -1,33 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Hewitt <christianshewitt@gmail.com>
|
||||
Date: Mon, 3 Jan 2022 10:44:17 +0000
|
||||
Subject: LOCAL: usb: hub: disable autosuspend for Genesys Logic Hubs
|
||||
|
||||
Disable autosuspend in Genesys Logic hubs to allow USB devices on the
|
||||
Odroid C2 board to be used. The alternative to this patch is setting
|
||||
usbcore.autosuspend=-1 in boot params.
|
||||
|
||||
This patch only impacts GXBB devices as GXL/GXM onwards use the newer
|
||||
dwc3 core which does not have the problem.
|
||||
|
||||
Signed-off-by: Christian Hewitt <christianshewitt@gmail.com>
|
||||
---
|
||||
drivers/usb/core/hub.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
|
||||
index 26a27ff50408..60fe64551e5b 100644
|
||||
--- a/drivers/usb/core/hub.c
|
||||
+++ b/drivers/usb/core/hub.c
|
||||
@@ -5926,7 +5926,7 @@ static const struct usb_device_id hub_id_table[] = {
|
||||
| USB_DEVICE_ID_MATCH_INT_CLASS,
|
||||
.idVendor = USB_VENDOR_GENESYS_LOGIC,
|
||||
.bInterfaceClass = USB_CLASS_HUB,
|
||||
- .driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND},
|
||||
+ .driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND},
|
||||
{ .match_flags = USB_DEVICE_ID_MATCH_VENDOR
|
||||
| USB_DEVICE_ID_MATCH_PRODUCT,
|
||||
.idVendor = USB_VENDOR_TEXAS_INSTRUMENTS,
|
||||
--
|
||||
Armbian
|
||||
|
@ -1,35 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Ash Hughes <spirit.returned@gmail.com>
|
||||
Date: Sat, 18 Feb 2023 07:46:38 -0300
|
||||
Subject: adapted meson64-reboot driver, fix reboot on odroid C4 when using
|
||||
UHS-II SD cards
|
||||
|
||||
bring back fixed version of `odroid-reboot` driver (Fix reboot on odroid C4 when using UHS-II SD cards)
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-sm1-odroid-c4.dts | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-c4.dts b/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-c4.dts
|
||||
index d04768a66bfe..e0b7aca25d21 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-c4.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-c4.dts
|
||||
@@ -11,6 +11,16 @@ / {
|
||||
compatible = "hardkernel,odroid-c4", "amlogic,sm1";
|
||||
model = "Hardkernel ODROID-C4";
|
||||
|
||||
+ meson64-reboot {
|
||||
+ compatible = "meson64,reboot";
|
||||
+ sys_reset = <0x84000009>;
|
||||
+ sys_poweroff = <0x84000008>;
|
||||
+
|
||||
+ sd-vqen = <&gpio_ao GPIOE_2 GPIO_ACTIVE_HIGH>;
|
||||
+ sd-vqsw = <&gpio_ao GPIOAO_6 GPIO_ACTIVE_HIGH>;
|
||||
+ sd-vmmc = <&gpio_ao GPIOAO_3 GPIO_ACTIVE_HIGH>;
|
||||
+ };
|
||||
+
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
|
||||
--
|
||||
Armbian
|
||||
|
@ -1,29 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Ricardo Pardini <ricardo@pardini.net>
|
||||
Date: Sun, 26 Jun 2022 03:47:06 +0200
|
||||
Subject: ODROID-HC4: add DT attributes to enable fan1_input
|
||||
|
||||
- from vendor kernel modified DT
|
||||
- this allows userspace fancontrol/pwmconfig to work
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-sm1-odroid-hc4.dts | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-hc4.dts b/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-hc4.dts
|
||||
index 74088e7280fe..9b3d3e7930d1 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-hc4.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-sm1-odroid-hc4.dts
|
||||
@@ -23,6 +23,10 @@ fan0: pwm-fan {
|
||||
cooling-max-state = <3>;
|
||||
cooling-levels = <0 120 170 220>;
|
||||
pwms = <&pwm_cd 1 40000 0>;
|
||||
+ fan-supply = <&vcc_5v>;
|
||||
+ interrupt-parent = <&gpio_intc>;
|
||||
+ interrupts = <84 IRQ_TYPE_EDGE_FALLING>;
|
||||
+ pulses-per-revolutions = <2>;
|
||||
};
|
||||
|
||||
leds {
|
||||
--
|
||||
Armbian
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user