Merge tag 'dey-2.6-r1.3' into dey-2.6/master

Digi Embedded Yocto 2.6-r1.3

Manually changed recipes to use the master branches instead of the fixed SHA1
from the last release.

Signed-off-by: Arturo Buzarra <arturo.buzarra@digi.com>
This commit is contained in:
Arturo Buzarra 2019-04-24 12:19:38 +02:00
commit 21b09d616d
62 changed files with 11784 additions and 749 deletions

116
README.md
View File

@ -1,10 +1,10 @@
# Digi Embedded Yocto (DEY) 2.4
## Release 2.4-r2.2
# Digi Embedded Yocto (DEY) 2.6
## Release 2.6-r1.3
This document provides information about Digi Embedded Yocto,
Digi International's professional embedded Yocto development environment.
Digi Embedded Yocto 2.4 is based on the Yocto Project(TM) 2.4 (Rocko) release.
Digi Embedded Yocto 2.6 is based on the Yocto Project(TM) 2.6 (Thud) release.
For a full list of supported features and interfaces please refer to the
online documentation.
@ -32,32 +32,6 @@ Software for the following hardware platforms is in production support:
* [CC-WMX6UL-KIT](https://www.digi.com/products/models/cc-wmx6ul-kit) ([Get Started](https://www.digi.com/resources/documentation/digidocs/90001547/default.htm#concept/yocto/c_get_started_with_yocto.htm))
* [CC-SBP-WMX-JN58](https://www.digi.com/products/models/cc-sbp-wmx-jn58)
## ConnectCore 6
* ConnectCore 6 System-on-Module (SOM)
* [CC-WMX-J97C-TN](https://www.digi.com/products/models/cc-wmx-j97c-tn)
* [CC-WMX-L96C-TE](https://www.digi.com/products/models/cc-wmx-l96c-te)
* [CC-WMX-L87C-TE](https://www.digi.com/products/models/cc-wmx-l87c-te)
* [CC-MX-L76C-Z1](https://www.digi.com/products/models/cc-mx-l76c-z1)
* [CC-MX-L86C-Z1](https://www.digi.com/products/models/cc-mx-l86c-z1)
* [CC-MX-L96C-Z1](https://www.digi.com/products/models/cc-mx-l96c-z1)
* [CC-WMX-L76C-TE](https://www.digi.com/products/models/cc-wmx-l76c-te)
* CC-WMX-K87C-FJA
* CC-WMX-K77C-TE
* CC-WMX-L97D-TN
* CC-WMX-J98C-FJA
* CC-WMX-J98C-FJA-1
* ConnectCore 6 SBC
* [CC-WMX6-KIT](https://www.digi.com/products/models/cc-wmx6-kit) ([Get Started](https://www.digi.com/resources/documentation/digidocs/90001546/default.htm#concept/yocto/c_get_started_with_yocto.htm))
* [CC-SB-WMX-J97C-1](https://www.digi.com/products/models/cc-sb-wmx-j97c-1)
* [CC-SB-WMX-L87C-1](https://www.digi.com/products/models/cc-sb-wmx-l87c-1)
* [CC-SB-WMX-L76C-1](https://www.digi.com/products/models/cc-sb-wmx-l76c-1)
## ConnectCore 6 Plus
* ConnectCore 6 Plus System-on-Module (SOM)
* CC-WMX-KK8D-TN
* ConnectCore 6 Plus SBC
* CC-SB-WMX-KK8D
## ConnectCore 8X
* ConnectCore 8X System-on-Module (SOM)
* [CC-WMX-JM7D-NN](https://www.digi.com/cc8x)
@ -76,7 +50,7 @@ hardware.
# Installation
Digi Embedded Yocto is composed of a set of different Yocto layers that work in
parallel. The layers are specified on a [manifest](https://github.com/digi-embedded/dey-manifest/blob/rocko/default.xml) file.
parallel. The layers are specified on a [manifest](https://github.com/digi-embedded/dey-manifest/blob/thud/default.xml) file.
To install, please follow the instructions at the dey-manifest [README](https://github.com/digi-embedded/dey-manifest)
@ -86,42 +60,34 @@ Documentation is available online at https://www.digi.com/resources/documentatio
# Downloads
* Demo images: ftp://ftp1.digi.com/support/digiembeddedyocto/2.4/r2/images/
* Software Development Kit (SDK): ftp://ftp1.digi.com/support/digiembeddedyocto/2.4/r2/sdk/
* Demo images: ftp://ftp1.digi.com/support/digiembeddedyocto/2.6/r1/images/
* Software Development Kit (SDK): ftp://ftp1.digi.com/support/digiembeddedyocto/2.6/r1/sdk/
# Release Changelog
## 2.4-r2.1
## 2.6-r1
* Added support for ConnectCore 8X platform. Supported features:
* Bluetooth and Wireless interfaces (STA, SoftAP, P2P, Concurrence)
* MCA: Reset, Watchdog, RTC, GPIOs and ADCs
* Updated U-Boot to version 2017.03-r2
* Fixed XBee RESET_N polarity assertion. Requires updating polarity of the
``digi,reset-gpio`` property of node ``xbee`` on device tree files derived from
ConnectCore 6UL SBC Pro to use polarity **GPIO_ACTIVE_LOW**
* Updated AWS Greengrass core to version 1.7.0
* Updated kernel version to v4.9.135 for i.MX6 and i.MX6UL platforms.
## 2.4-r1
* Release based on [Yocto 2.4 (Rocko)](https://www.yoctoproject.org/downloads/core/rocko24) including:
* New toolchain based on GCC-7.2.0 and GLIBC-2.26
* Updated Qt 5.9.4
* Release based on [Yocto 2.6 (Thud)](https://www.yoctoproject.org/software-overview/downloads) including:
* New toolchain based on GLIBC-2.28
* Updated Qt 5.11.3
* Updated NetworkManager to v1.14.4
* Updated Wpa-supplicant to v2.6
* Updated gstreamer1.0 to v1.14.0
* Updated busybox to v1.29.2
* Updated bluez5 to v5.50
* Updated OpenSSL to v1.1.1a
* Package upgrades and security fixes
* Updated kernel version to v4.9 for ConnectCore 6 platform
* Updated U-Boot to version 2015.04-r12
* Updated Cryptoauthlib version to v3.0
* Added support for Goodix 10" display
* Updated documentation
* Updated kernel version to v4.14.111 for i.MX8X and i.MX6UL platforms
* Updated U-Boot to version 2018.03-r1 for i.MX8X platform
* Updated AWS Greengrass core to version 1.8.0
* Added support for Code Signing Tool 3.1.0
* Changed initialization manager in ConnectCore 8X platforms to systemd
# Known Issues and Limitations
This is a list of known issues and limitations at the time of release. An
updated list can be found on the online documentation.
* If TrustFence (TM) image encryption support is enabled, the uSD image will
boot a signed U-Boot only.
* Firmware update
* The software update package must be located in the root level of the
update media (subfolders are not yet supported).
@ -129,9 +95,9 @@ boot a signed U-Boot only.
* Remote file system management fails with long file names and paths
(over 255 characters).
* For P2P connections Digi recommends "Negotiated GO" modes. The QCA6564
devices (ConnectCore 6UL and ConnectCore 6 Plus) running a 4.9 kernel
version fail to join to autonomous groups.
* Trustfence secure console is not supported on U-Boot v2017.03. In order to use this functionality, U-Boot v2015.04 will be required.
devices (ConnectCore 6UL) running a 4.14 kernel version fail to join to
autonomous groups.
* Trustfence is not yet supported on U-Boot v2018.03.
## ConnectCore 6UL
@ -152,39 +118,9 @@ boot a signed U-Boot only.
currently supported.
* The QCA6564 wireless chip does not support Wake On Wireless LAN.
## ConnectCore 6
* ConnectCore 6 System-on-Module (SOM)
* NXP i.MX6 processor has a documented errata (ERR004512) whereby the maximum
performance of the Gigabit FEC is limited to 400Mbps (total for Tx and Rx).
* When using softAP mode on Band A on the Qualcomm AR6233, channels used for
Dynamic Frequency Selection (DFS) are not supported.
* The Qualcomm AR6233 firmware does not support the following configuration
modes:
* Concurrent modes involving P2P mode, such as P2P + softAP or P2P + STA.
* Bluetooth + softAP + STA concurrent mode.
* A maximum of five clients are supported when using Qualcomm's AR6233 in
softAP mode.
* A maximum of ten connected devices are supported when using Qualcomm's AR6233
Bluetooth Low Energy mode.
* ConnectCore 6 SBC
* The Micrel PHY KSZ9031 may take between five and six seconds to
auto-negotiate with Gigabit switches.
## ConnectCore 6 Plus
* ConnectCore 6 Plus System-on-Module (SOM)
* NXP i.MX6QP processor has a documented errata (ERR004512) whereby the maximum
performance of the Gigabit FEC is limited to 400Mbps (total for Tx and Rx).
* ConnectCore 6 Plus SBC
* The Micrel PHY KSZ9031 may take between five and six seconds to
auto-negotiate with Gigabit switches.
## ConnectCore 8X
* i.MX8QXP Processor
* The following processor features are not supported in this BSP release:
Power Management, PWM, ADC, RS485. They will be implemented in future releases.
* GPU maximum performance reduced. The maximum frequency targets are 850 MHz
for the shaders and 700 MHz for the core. However, in this hardware release
the maximum frequency is limited to 650 MHz for the shaders and 600 MHz for
@ -192,10 +128,8 @@ boot a signed U-Boot only.
be met in future releases of the hardware.
* BSDL operation is not supported. It will be available in future releases
of the hardware.
* ConnectCore 8X SBC Pro
* USB 3.0 not supported.
* Digi Embedded Yocto
* The following features are not supported in this release for the ConnectCore 8X plaform:
* The following features are not supported in this release for the ConnectCore 8X platform:
* Trustfence (TM)
* Digi Remote Manager

View File

@ -29,7 +29,6 @@ KERNEL_DEVICETREE ?= " \
KERNEL_DEVICETREE_use-mainline-bsp ?= "imx6ul-ccimx6ulsbcpro.dtb"
KERNEL_DEFCONFIG ?= "arch/arm/configs/ccimx6ul_defconfig"
KERNEL_DEFCONFIG_use-mainline-bsp ?= "arch/arm/configs/imx_v6_v7_defconfig"
SERIAL_CONSOLES ?= "115200;ttymxc4"

View File

@ -28,7 +28,6 @@ KERNEL_DEVICETREE ?= " \
KERNEL_DEVICETREE_use-mainline-bsp ?= "imx6ul-ccimx6ulsbcexpress.dtb"
KERNEL_DEFCONFIG ?= "arch/arm/configs/ccimx6ul_defconfig"
KERNEL_DEFCONFIG_use-mainline-bsp ?= "arch/arm/configs/imx_v6_v7_defconfig"
SERIAL_CONSOLES ?= "115200;ttymxc4"

View File

@ -32,6 +32,10 @@ SERIAL_CONSOLES ?= "115200;ttyLP2"
# Bluetooth tty
BT_TTY ?= "ttyLP1"
# XBee
XBEE_RESET_N_GPIO ?= "397"
XBEE_SLEEP_RQ_GPIO ?= "400"
# U-Boot script to be copied to the boot image
BOOT_SCRIPTS = "boot.scr:boot.scr"

View File

@ -32,6 +32,10 @@ SERIAL_CONSOLES ?= "115200;ttyLP2"
# Bluetooth tty
BT_TTY ?= "ttyLP1"
# XBee
XBEE_RESET_N_GPIO ?= "220"
XBEE_SLEEP_RQ_GPIO ?= "216"
# U-Boot script to be copied to the boot image
BOOT_SCRIPTS = "boot.scr:boot.scr"

View File

@ -34,6 +34,7 @@ MACHINE_EXTRA_RDEPENDS += " \
mca-tool \
parted \
u-boot-fw-utils \
xbee-init \
"
MACHINE_EXTRA_RRECOMMENDS += " \

View File

@ -3,7 +3,7 @@ PREFERRED_PROVIDER_jpeg-native ?= "jpeg-native"
PREFERRED_PROVIDER_u-boot ??= "u-boot-dey"
PREFERRED_PROVIDER_virtual/bootloader ??= "u-boot-dey"
PREFERRED_PROVIDER_virtual/kernel ??= "linux-dey"
PREFERRED_PROVIDER_virtual/kernel_use-mainline-bsp ??= "linux-4.20.y"
PREFERRED_PROVIDER_virtual/kernel_use-mainline-bsp ??= "linux-fslc"
PREFERRED_PROVIDER_virtual/xserver = "xserver-xorg"
#

View File

@ -14,6 +14,7 @@ IMX_M4_DEMOS = "imx-m4-demos"
# so set the appropriate dependencies
do_compile[depends] += " \
${@' '.join('%s:do_deploy' % r for r in '${IMX_M4_DEMOS}'.split() )} \
firmware-imx:do_deploy \
"
# This package aggregates dependencies with other packages,
@ -23,6 +24,7 @@ do_populate_lic[depends] += " \
${@' '.join('%s:do_populate_lic' % r for r in '${IMX_EXTRA_FIRMWARE}'.split() )} \
imx-atf:do_populate_lic \
${@' '.join('%s:do_populate_lic' % r for r in '${IMX_M4_DEMOS}'.split() )} \
firmware-imx:do_populate_lic \
"
UBOOT_NAME = "u-boot-${MACHINE}.bin"

View File

@ -11,7 +11,7 @@ else
#
# Set device tree filename depending on the hardware variant
#
if test "${module_variant}" = "0x02" || test "${module_variant}" = "0x04"; then
if test "${module_variant}" = "0x02" || test "${module_variant}" = "0x04" || test "${module_variant}" = "0x06"; then
setenv fdt_file imx6ul-ccimx6ulsbc-wb.dtb
elif test "${module_variant}" = "0x03" || test "${module_variant}" = "0x05"; then
setenv fdt_file imx6ul-ccimx6ulsbc.dtb

View File

@ -21,7 +21,7 @@ fi
# Determine U-Boot file to program basing on module variant
if test -n "${module_variant}"; then
if test "${module_variant}" = "0x02" || test "${module_variant}" = "0x03"; then
if test "${module_variant}" = "0x02" || test "${module_variant}" = "0x03" || test "${module_variant}" = "0x06"; then
setenv INSTALL_UBOOT_FILENAME u-boot-ccimx6ulsbc.imx;
elif test "${module_variant}" = "0x04" || test "${module_variant}" = "0x05"; then
setenv INSTALL_UBOOT_FILENAME u-boot-ccimx6ulsbc1GB.imx;

View File

@ -11,7 +11,7 @@ else
#
# Set device tree filename depending on the hardware variant
#
if test "${module_variant}" = "0x02" || test "${module_variant}" = "0x04"; then
if test "${module_variant}" = "0x02" || test "${module_variant}" = "0x04" || test "${module_variant}" = "0x06"; then
setenv fdt_file imx6ul-ccimx6ulstarter-wb.dtb
elif test "${module_variant}" = "0x03" || test "${module_variant}" = "0x05"; then
setenv fdt_file imx6ul-ccimx6ulstarter.dtb

View File

@ -21,7 +21,7 @@ fi
# Determine U-Boot file to program basing on module variant
if test -n "${module_variant}"; then
if test "${module_variant}" = "0x02" || test "${module_variant}" = "0x03"; then
if test "${module_variant}" = "0x02" || test "${module_variant}" = "0x03" || test "${module_variant}" = "0x06"; then
setenv INSTALL_UBOOT_FILENAME u-boot-ccimx6ulstarter.imx;
elif test "${module_variant}" = "0x04" || test "${module_variant}" = "0x05"; then
setenv INSTALL_UBOOT_FILENAME u-boot-ccimx6ulstarter1GB.imx;

View File

@ -0,0 +1,5 @@
# Copyright (C) 2019 Digi International.
# The most recent version of this tool is unable to boot closed devices.
# Revert to the version that was used in DEY 2.4.
SRCREV = "349286e25c3fd9b2d31b31e962340123bbc62d44"

View File

@ -1,11 +0,0 @@
# Copyright (C) 2019 Digi International
require recipes-kernel/linux/linux-dey.inc
SRCBRANCH = "v4.20.y"
SRCREV = "${AUTOREV}"
DEPENDS += "openssl-native"
HOST_EXTRACFLAGS += "-I${STAGING_INCDIR_NATIVE}"
COMPATIBLE_MACHINE = "(ccimx6ul)"

View File

@ -3,7 +3,6 @@
SUMMARY = "Linux kernel for Digi boards"
LICENSE = "GPLv2"
LIC_FILES_CHKSUM = "file://COPYING;md5=d7810fab7487fb0aad327b76f1be7cd7"
LIC_FILES_CHKSUM_use-mainline-bsp = "file://COPYING;md5=bbea815ee2795b2f4230826c0c6b8814"
DEPENDS += "lzop-native bc-native"
DEPENDS += "${@oe.utils.conditional('TRUSTFENCE_SIGN', '1', 'trustfence-sign-tools-native', '', d)}"

View File

@ -0,0 +1,167 @@
From 2313935f3b195aa7d930961bcd44a5fac61a945e Mon Sep 17 00:00:00 2001
From: Alex Gonzalez <alex.gonzalez@digi.com>
Date: Fri, 20 Apr 2018 19:13:02 +0200
Subject: [PATCH] ARM: Add support for the ConnectCore 6UL System-On-Module
* Getter functions for hwid information
* Define "digi,ccimx6ul" in the compatible property so the MCA can be
managed using the available tools.
Signed-off-by: Alex Gonzalez <alex.gonzalez@digi.com>
---
arch/arm/boot/dts/imx6ul-ccimx6ulsbcexpress.dts | 2 +-
arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts | 3 +-
arch/arm/configs/imx_v6_v7_defconfig | 2 +-
arch/arm/mach-imx/Kconfig | 8 +++
arch/arm/mach-imx/Makefile | 2 +-
arch/arm/mach-imx/som-ccimx6ul.c | 69 +++++++++++++++++++++++++
6 files changed, 82 insertions(+), 4 deletions(-)
create mode 100644 arch/arm/mach-imx/som-ccimx6ul.c
diff --git a/arch/arm/boot/dts/imx6ul-ccimx6ulsbcexpress.dts b/arch/arm/boot/dts/imx6ul-ccimx6ulsbcexpress.dts
index 3792679c0c90..dc773f350999 100644
--- a/arch/arm/boot/dts/imx6ul-ccimx6ulsbcexpress.dts
+++ b/arch/arm/boot/dts/imx6ul-ccimx6ulsbcexpress.dts
@@ -15,7 +15,7 @@
/ {
model = "Digi International ConnectCore 6UL SBC Express.";
compatible = "digi,ccimx6ulsbcexpress", "digi,ccimx6ulsom",
- "fsl,imx6ul";
+ "digi,ccimx6ul", "fsl,imx6ul";
};
&adc1 {
diff --git a/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts b/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts
index 3749fdda3611..aed1db57ed3b 100644
--- a/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts
+++ b/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts
@@ -14,7 +14,8 @@
/ {
model = "Digi International ConnectCore 6UL SBC Pro.";
- compatible = "digi,ccimx6ulsbcpro", "digi,ccimx6ulsom", "fsl,imx6ul";
+ compatible = "digi,ccimx6ulsbcpro", "digi,ccimx6ulsom",
+ "digi,ccimx6ul", "fsl,imx6ul";
lcd_backlight: backlight {
compatible = "pwm-backlight";
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 6985d61eddb3..2d32ab117fb5 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -36,7 +36,7 @@ CONFIG_SOC_IMX6Q=y
CONFIG_SOC_IMX6SL=y
CONFIG_SOC_IMX6SLL=y
CONFIG_SOC_IMX6SX=y
-CONFIG_SOC_IMX6UL=y
+CONFIG_SOM_CC6UL=y
CONFIG_SOC_IMX7D=y
CONFIG_SOC_VF610=y
CONFIG_PCI=y
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index abc337111eff..2451ee423496 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -523,6 +523,14 @@ config SOC_IMX6UL
help
This enables support for Freescale i.MX6 UltraLite processor.
+config SOM_CC6UL
+ bool "Digi ConnectCore 6UL System-On-Module support"
+ select SOC_IMX6UL
+ select SOC_IMX6
+
+ help
+ This enables support for Digi ConnectCore 6UL System-On-Module.
+
config SOC_LS1021A
bool "Freescale LS1021A support"
select ARM_GIC
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index bae179af21f6..0cd7cdfc5e49 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -83,7 +83,7 @@ obj-$(CONFIG_SOC_IMX6SX) += mach-imx6sx.o
obj-$(CONFIG_SOC_IMX6UL) += mach-imx6ul.o
obj-$(CONFIG_SOC_IMX7D_CA7) += mach-imx7d.o
obj-$(CONFIG_SOC_IMX7D_CM4) += mach-imx7d-cm4.o
-
+obj-$(CONFIG_SOM_CC6UL) += som-ccimx6ul.o
ifeq ($(CONFIG_SUSPEND),y)
AFLAGS_suspend-imx6.o :=-Wa,-march=armv7-a
obj-$(CONFIG_SOC_IMX6) += suspend-imx6.o
diff --git a/arch/arm/mach-imx/som-ccimx6ul.c b/arch/arm/mach-imx/som-ccimx6ul.c
new file mode 100644
index 000000000000..269b526ee020
--- /dev/null
+++ b/arch/arm/mach-imx/som-ccimx6ul.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2018 Digi International Inc
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/errno.h>
+#include <linux/of.h>
+#include <linux/string.h>
+
+static int digi_board_version = -EINVAL;
+
+int digi_get_board_version(void)
+{
+ struct device_node *np = NULL;
+ const char *boardver_str;
+ char buf[4];
+
+ /* Only need to read the carrier board once */
+ if (digi_board_version > 0)
+ return digi_board_version;
+
+ np = of_find_node_by_path("/");
+ if (!np)
+ return -EPERM;
+
+ if (!of_property_read_string(np, "digi,carrierboard,version",
+ &boardver_str)) {
+ strncpy(buf, boardver_str, sizeof(buf));
+ if (!kstrtoint(boardver_str, 10, &digi_board_version))
+ pr_debug("Board version: %d\n", digi_board_version);
+ }
+ of_node_put(np);
+
+ return digi_board_version;
+}
+EXPORT_SYMBOL(digi_get_board_version);
+
+static int digi_som_hv = -EINVAL;
+
+int digi_get_som_hv(void)
+{
+ struct device_node *np = NULL;
+ const char *som_hv_str;
+ char buf[4];
+
+ /* Only need to read the HV once */
+ if (digi_som_hv > 0)
+ return digi_som_hv;
+
+ np = of_find_node_by_path("/");
+ if (!np)
+ return -EPERM;
+
+ if (!of_property_read_string(np, "digi,hwid,hv", &som_hv_str)) {
+ strncpy(buf, som_hv_str, sizeof(buf));
+ if (!kstrtoint(som_hv_str, 16, &digi_som_hv))
+ pr_debug("SOM HV: %d\n", digi_som_hv);
+ }
+ of_node_put(np);
+
+ return digi_som_hv;
+}
+EXPORT_SYMBOL(digi_get_som_hv);

View File

@ -0,0 +1,65 @@
From d0520a166cdeccf2821a45483602fc24a1772569 Mon Sep 17 00:00:00 2001
From: Alex Gonzalez <alex.gonzalez@digi.com>
Date: Fri, 20 Apr 2018 20:20:30 +0200
Subject: [PATCH] mach-imx: pm-imx6: Add hooks for board specific
implementation
This commit implements two new pm hooks in pm_imx6.c (begin & end) that,
optionally, can be implemented by the platform code.
This is needed on platforms like the CC6UL where the i.MX6UL has to
notify the MCA when suspending the system or resuming from suspend.
Signed-off-by: Alex Gonzalez <alex.gonzalez@digi.com>
Signed-off-by: Pedro Perez de Heredia <pedro.perez@digi.com>
---
arch/arm/mach-imx/pm-imx6.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c
index 87f45b926c78..1a4d1ea92687 100644
--- a/arch/arm/mach-imx/pm-imx6.c
+++ b/arch/arm/mach-imx/pm-imx6.c
@@ -69,6 +69,14 @@ static void __iomem *suspend_ocram_base;
static void (*imx6_suspend_in_ocram_fn)(void __iomem *ocram_vbase);
/*
+ * Function pointers to optional board pm functions
+ */
+int (*imx6_board_pm_begin)(suspend_state_t);
+void (*imx6_board_pm_end)(void);
+EXPORT_SYMBOL(imx6_board_pm_begin);
+EXPORT_SYMBOL(imx6_board_pm_end);
+
+/*
* suspend ocram space layout:
* ======================== high address ======================
* .
@@ -427,12 +435,28 @@ static int imx6q_pm_enter(suspend_state_t state)
return 0;
}
+static int imx6q_pm_begin(suspend_state_t state)
+{
+ if (imx6_board_pm_begin)
+ return imx6_board_pm_begin(state);
+
+ return 0;
+}
+
+static void imx6q_pm_end(void)
+{
+ if (imx6_board_pm_end)
+ imx6_board_pm_end();
+}
+
static int imx6q_pm_valid(suspend_state_t state)
{
return (state == PM_SUSPEND_STANDBY || state == PM_SUSPEND_MEM);
}
static const struct platform_suspend_ops imx6q_pm_ops = {
+ .begin = imx6q_pm_begin,
+ .end = imx6q_pm_end,
.enter = imx6q_pm_enter,
.valid = imx6q_pm_valid,
};

View File

@ -0,0 +1,701 @@
From a2b055852d963729002f48155d8bbee7e2858e0a Mon Sep 17 00:00:00 2001
From: Alex Gonzalez <alex.gonzalez@digi.com>
Date: Mon, 23 Apr 2018 11:37:46 +0200
Subject: [PATCH] imx6ul: Add MCA GPIO support for the ConnectCore 6UL SOM
Synched with v4.14.78/master at:
3f8b03950b323db4ca89b1cdc1c2288f79facaa3
Signed-off-by: Alex Gonzalez <alex.gonzalez@digi.com>
---
arch/arm/boot/dts/imx6ul-ccimx6ulsbcexpress.dts | 2 +
arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts | 2 +
arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi | 11 +
arch/arm/configs/imx_v6_v7_defconfig | 1 +
drivers/gpio/Kconfig | 9 +
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-mca.c | 583 ++++++++++++++++++++++++
7 files changed, 609 insertions(+)
create mode 100644 drivers/gpio/gpio-mca.c
diff --git a/arch/arm/boot/dts/imx6ul-ccimx6ulsbcexpress.dts b/arch/arm/boot/dts/imx6ul-ccimx6ulsbcexpress.dts
index 3792679c0c90..148f1b95e46d 100644
--- a/arch/arm/boot/dts/imx6ul-ccimx6ulsbcexpress.dts
+++ b/arch/arm/boot/dts/imx6ul-ccimx6ulsbcexpress.dts
@@ -43,6 +43,8 @@
pinctrl-0 = <&pinctrl_enet1>;
phy-mode = "rmii";
phy-handle = <&ethphy0>;
+ phy-reset-gpios = <&mca_gpio 7 GPIO_ACTIVE_LOW>;
+ phy-reset-duration = <26>;
status = "okay";
mdio {
diff --git a/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts b/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts
index 3749fdda3611..5ad2c61276bc 100644
--- a/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts
+++ b/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts
@@ -79,6 +79,8 @@
pinctrl-0 = <&pinctrl_enet1>;
phy-mode = "rmii";
phy-handle = <&ethphy0>;
+ phy-reset-gpios = <&mca_gpio 7 GPIO_ACTIVE_LOW>;
+ phy-reset-duration = <26>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi b/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi
index 03c62926ca2b..8d475051acf2 100644
--- a/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi
+++ b/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi
@@ -58,6 +58,17 @@
fw-update-gpio = <&gpio4 14 GPIO_ACTIVE_LOW>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_mca_cc6ul>;
+
+ mca_gpio: gpio {
+ compatible = "digi,mca-cc6ul-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-parent = <&mca_cc6ul>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
};
pfuze3000: pmic@8 {
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 6985d61eddb3..6c3ede35e643 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -207,6 +207,7 @@ CONFIG_SPI_GPIO=y
CONFIG_SPI_IMX=y
CONFIG_SPI_FSL_DSPI=y
CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_MCA=y
CONFIG_GPIO_MAX732X=y
CONFIG_GPIO_MC9S08DZ60=y
CONFIG_GPIO_PCA953X=y
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 833a1b51c948..f7daae95b2a7 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -305,6 +305,15 @@ config GPIO_MB86S7X
help
Say yes here to support the GPIO controller in Fujitsu MB86S70 SoCs.
+config GPIO_MCA
+ tristate "Digi ConnectCore SOMs Micro Controller Assist GPIO support"
+ select MFD_MCA_CC6UL if SOC_IMX6UL
+ select MFD_MCA_CC8X if ARCH_FSL_IMX8QXP
+ select GPIOLIB_IRQCHIP
+ help
+ If you say yes here you will get support for the GPIOs in the
+ Micro Controller Assist of Digi ConnectCore system-on-modules.
+
config GPIO_MENZ127
tristate "MEN 16Z127 GPIO support"
depends on MCB
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 671c4477c951..481b23e8c27e 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_GPIO_MENZ127) += gpio-menz127.o
obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o
obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o
obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o
+obj-$(CONFIG_GPIO_MCA) += gpio-mca.o
obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o
obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o
obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o
diff --git a/drivers/gpio/gpio-mca.c b/drivers/gpio/gpio-mca.c
new file mode 100644
index 000000000000..75dd8af9f76e
--- /dev/null
+++ b/drivers/gpio/gpio-mca.c
@@ -0,0 +1,583 @@
+/* gpio-mca.c - GPIO driver for MCA devices.
+ *
+ * Copyright (C) 2017 - 2019 Digi International Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/mfd/mca-common/core.h>
+#include <linux/mfd/mca-common/registers.h>
+
+#define MCA_DRVNAME_GPIO "mca-gpio"
+
+/*
+ * The following macros return the register address to read/write for a given
+ * gpio number.
+ */
+#define GPIO_DIR_REG(x) (MCA_GPIO_DIR_0 + ((x) / 8))
+#define GPIO_DATA_REG(x) (MCA_GPIO_DATA_0 + ((x) / 8))
+#define GPIO_SET_REG(x) (MCA_GPIO_SET_0 + ((x) / 8))
+#define GPIO_CLEAR_REG(x) (MCA_GPIO_CLEAR_0 + ((x) / 8))
+#define GPIO_TOGGLE_REG(x) (MCA_GPIO_TOGGLE_0 + ((x) / 8))
+#define GPIO_IRQ_STATUS_REG(x) (MCA_GPIO_IRQ_STATUS_0 + (x))
+#define GPIO_IRQ_CFG_REG(x) (MCA_GPIO_IRQ_CFG_0 + (x))
+#define GPIO_DEB_CFG_REG(x) (MCA_GPIO_DEB_CFG_0 + ((x) / 8))
+#define GPIO_DEB_CNT_REG(x) (MCA_GPIO_DEB_CNT_0 + (x))
+
+#define GPIO_CFG_UPDATE BIT(6)
+#define GPIO_BYTE(i) ((i) / 8)
+#define BYTE_OFFSET(i) ((i) % 8)
+#define BIT_OFFSET(i) ((i) % 8)
+
+#ifdef CONFIG_OF
+enum mca_gpio_type {
+ CC6UL_MCA_GPIO,
+ CC8X_MCA_GPIO,
+ IOEXP_MCA_GPIO,
+};
+
+struct mca_gpio_data {
+ enum mca_gpio_type devtype;
+};
+#endif
+
+struct mca_gpio {
+ void * parent;
+ struct regmap *regmap;
+ struct device *dev;
+ struct gpio_chip gc;
+ struct mutex irq_lock;
+ uint8_t irq_cfg[MCA_MAX_IOS];
+ uint8_t irq_capable[MCA_MAX_IO_BYTES];
+ int irq[MCA_MAX_GPIO_IRQ_BANKS];
+ uint8_t deb_timer_cfg[MCA_MAX_GPIO_IRQ_BANKS];
+};
+
+static char const *const irq_gpio_bank_name[] = {
+ MCA_IRQ_GPIO_BANK_0_NAME,
+ MCA_IRQ_GPIO_BANK_1_NAME,
+ MCA_IRQ_GPIO_BANK_2_NAME,
+ MCA_IRQ_GPIO_BANK_3_NAME,
+ MCA_IRQ_GPIO_BANK_4_NAME,
+ MCA_IRQ_GPIO_BANK_5_NAME,
+};
+
+static inline struct mca_gpio *to_mca_gpio(struct gpio_chip *chip)
+{
+ return gpiochip_get_data(chip);
+}
+
+static inline bool mca_gpio_is_irq_capable(struct mca_gpio *gpio,
+ u32 offset)
+{
+ return ((gpio->irq_capable[GPIO_BYTE(offset)] &
+ (1 << BYTE_OFFSET(offset))) != 0);
+}
+
+static int mca_gpio_get(struct gpio_chip *gc, unsigned num)
+{
+ struct mca_gpio *gpio = to_mca_gpio(gc);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(gpio->regmap, GPIO_DATA_REG(num), &val);
+ if (ret < 0)
+ return ret;
+
+ return (val & (1 << BIT_OFFSET(num)) ? 1 : 0);
+}
+
+static void mca_gpio_set(struct gpio_chip *gc, unsigned num, int val)
+{
+ struct mca_gpio *gpio = to_mca_gpio(gc);
+ unsigned int reg = val ? GPIO_SET_REG(num) : GPIO_CLEAR_REG(num);
+
+ regmap_write(gpio->regmap, reg, 1 << BIT_OFFSET(num));
+}
+
+static int mca_gpio_direction_input(struct gpio_chip *gc, unsigned num)
+{
+ struct mca_gpio *gpio = to_mca_gpio(gc);
+
+ return regmap_update_bits(gpio->regmap, GPIO_DIR_REG(num),
+ 1 << BIT_OFFSET(num), 0);
+}
+
+static int mca_gpio_direction_output(struct gpio_chip *gc, unsigned num,
+ int val)
+{
+ struct mca_gpio *gpio = to_mca_gpio(gc);
+ int ret;
+
+ /* Set value before setting direction */
+ mca_gpio_set(gc, num, val);
+
+ ret = regmap_update_bits(gpio->regmap, GPIO_DIR_REG(num),
+ 1 << BIT_OFFSET(num), 1 << BIT_OFFSET(num));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+#define MCA_GPIO_MAX_DEB_VAL_TIMER_50MS (50 * 1000 * 255)
+#define MCA_GPIO_MAX_DEB_VAL_TIMER_1MS (255 * 1000)
+
+static int mca_gpio_set_debounce(struct gpio_chip *gc, unsigned int usecs,
+ unsigned int debounce)
+{
+ struct mca_gpio *mca_gc = to_mca_gpio(gc);
+ u8 deb_cnt;
+ int ret;
+
+ if (debounce > MCA_GPIO_MAX_DEB_VAL_TIMER_50MS) {
+ dev_warn(mca_gc->dev, "Value out of range %u, setting %u instead\n",
+ debounce, MCA_GPIO_MAX_DEB_VAL_TIMER_50MS);
+ debounce = MCA_GPIO_MAX_DEB_VAL_TIMER_50MS;
+ }
+
+ if (debounce > MCA_GPIO_MAX_DEB_VAL_TIMER_1MS) {
+ /* Set timer cfg period to 50ms */
+ mca_gc->deb_timer_cfg[GPIO_BYTE(usecs)] |= 1 << BIT_OFFSET(usecs);
+ deb_cnt = (debounce + 49999) / 50000;
+ } else {
+ /* Set timer cfg period to 1ms */
+ mca_gc->deb_timer_cfg[GPIO_BYTE(usecs)] &= ~(1 << BIT_OFFSET(usecs));
+ deb_cnt = (debounce + 999) / 1000;
+ }
+
+ ret = regmap_write(mca_gc->regmap, GPIO_DEB_CFG_REG(usecs),
+ mca_gc->deb_timer_cfg[GPIO_BYTE(usecs)]);
+ if (ret) {
+ dev_err(mca_gc->dev, "Failed to write GPIO_DEB_CFG_REG(%d) (%d)\n",
+ usecs, ret);
+ } else {
+ ret = regmap_write(mca_gc->regmap, GPIO_DEB_CNT_REG(usecs), deb_cnt);
+ if (ret)
+ dev_err(mca_gc->dev,
+ "Failed to write GPIO_DEB_CNT_REG(%d) (%d)\n",
+ usecs, ret);
+ }
+
+ return ret;
+}
+
+static int mca_gpio_set_config(struct gpio_chip *gc, unsigned int num,
+ unsigned long config)
+{
+ enum pin_config_param param = pinconf_to_config_param(config);
+ u32 arg = pinconf_to_config_argument(config);
+
+ if (param != PIN_CONFIG_INPUT_DEBOUNCE)
+ return -ENOTSUPP;
+
+ return mca_gpio_set_debounce(gc, num, arg);
+}
+
+static irqreturn_t mca_gpio_irq_handler(int irq, void *data)
+{
+ struct mca_gpio *gpio = data;
+ unsigned int pending_irqs, mask, this_irq;
+ int ret, i, j;
+
+ for (i = 0; i < (gpio->gc.ngpio + 7) / 8; i++) {
+ ret = regmap_read(gpio->regmap, GPIO_IRQ_STATUS_REG(i), &pending_irqs);
+ if (ret < 0) {
+ dev_err(gpio->dev,
+ "IRQ %d: Failed to read GPIO_IRQ_STATUS_REG (%d)\n",
+ irq, ret);
+ continue;
+ }
+
+ for (j = 0; j < 8; j++) {
+ mask = 1 << j;
+ if (pending_irqs & mask) {
+ /* Ack the irq and call the handler */
+ this_irq = irq_find_mapping(gpio->gc.irq.domain, j + i * 8);
+ ret = regmap_write(gpio->regmap,
+ GPIO_IRQ_STATUS_REG(i),
+ mask);
+ if (ret) {
+ dev_err(gpio->dev,
+ "Failed to ack IRQ %d (%d)\n",
+ this_irq, ret);
+ continue;
+ }
+
+ handle_nested_irq(this_irq);
+ }
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void mca_gpio_irq_disable(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct mca_gpio *gpio = to_mca_gpio(gc);
+
+ /*
+ * Update the IRQ_EN bit and also set the CFG_UPDATE flag to mark what
+ * registers have to be written later to the MCA, once we are out of
+ * atomic context. Note that this flag is not cleared before writing
+ * the MCA regsister.
+ */
+ gpio->irq_cfg[d->hwirq] |= GPIO_CFG_UPDATE;
+ gpio->irq_cfg[d->hwirq] &= ~MCA_GPIO_IRQ_EN;
+}
+
+static void mca_gpio_irq_enable(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct mca_gpio *gpio = to_mca_gpio(gc);
+
+ /*
+ * Update the IRQ_EN bit and also set the CFG_UPDATE flag to mark what
+ * registers have to be written later to the MCA, once we are out of
+ * atomic context. Note that this flag is not cleared before writing
+ * the MCA regsister.
+ */
+ gpio->irq_cfg[d->hwirq] |= GPIO_CFG_UPDATE | MCA_GPIO_IRQ_EN;
+}
+
+static void mca_gpio_irq_bus_lock(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct mca_gpio *gpio = to_mca_gpio(gc);
+
+ mutex_lock(&gpio->irq_lock);
+}
+
+static void mca_gpio_irq_bus_sync_unlock(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct mca_gpio *gpio = to_mca_gpio(gc);
+ int i, ret;
+
+ for (i = 0; i < gc->ngpio; i++) {
+ /* Update only those registers that were flagged (modified) */
+ if (!(gpio->irq_cfg[i] & GPIO_CFG_UPDATE))
+ continue;
+
+ gpio->irq_cfg[i] &= ~GPIO_CFG_UPDATE;
+
+ ret = regmap_write(gpio->regmap,
+ GPIO_IRQ_CFG_REG(i),
+ gpio->irq_cfg[i]);
+ if (ret) {
+ dev_err(gpio->dev,
+ "Failed to configure IRQ %d\n", d->irq);
+ }
+ }
+
+ mutex_unlock(&gpio->irq_lock);
+}
+
+static int mca_gpio_irq_set_type(struct irq_data *d, unsigned int type)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct mca_gpio *gpio = to_mca_gpio(gc);
+ u32 gpio_idx = d->hwirq;
+
+ if ((type & IRQ_TYPE_LEVEL_HIGH) || (type & IRQ_TYPE_LEVEL_LOW)) {
+ dev_err(gpio->dev,
+ "IRQ %d: level IRQs are not supported\n", d->irq);
+ return -EINVAL;
+ }
+
+ /*
+ * Update the edge flags based on type and set CFG_UPDATE to note that
+ * the register was modified and has to be written back to the MCA in
+ * mca_gpio_irq_bus_sync_unlock().
+ */
+ gpio->irq_cfg[gpio_idx] &= ~MCA_M_GPIO_IRQ_CFG;
+ gpio->irq_cfg[gpio_idx] |= GPIO_CFG_UPDATE;
+
+ if (type & IRQ_TYPE_EDGE_RISING)
+ gpio->irq_cfg[gpio_idx] |= MCA_GPIO_IRQ_EDGE_RISE;
+
+ if (type & IRQ_TYPE_EDGE_FALLING)
+ gpio->irq_cfg[gpio_idx] |= MCA_GPIO_IRQ_EDGE_FALL;
+
+ return 0;
+}
+
+static int mca_gpio_to_irq(struct gpio_chip *gc, u32 offset)
+{
+ struct mca_gpio *gpio = to_mca_gpio(gc);
+
+ if (GPIO_BYTE(offset) >= MCA_MAX_IO_BYTES)
+ return -EINVAL;
+
+ /* Discard non irq capable gpios */
+ if (!mca_gpio_is_irq_capable(gpio, offset))
+ return -EINVAL;
+
+ return irq_create_mapping(gc->irq.domain, offset);
+}
+
+static struct irq_chip mca_gpio_irq_chip = {
+ .name = "mca-gpio-irq",
+ .irq_disable = mca_gpio_irq_disable,
+ .irq_enable = mca_gpio_irq_enable,
+ .irq_bus_lock = mca_gpio_irq_bus_lock,
+ .irq_bus_sync_unlock = mca_gpio_irq_bus_sync_unlock,
+ .irq_set_type = mca_gpio_irq_set_type,
+};
+
+static int mca_gpio_irq_setup(struct mca_gpio *gpio)
+{
+ unsigned int val;
+ int ret, i;
+
+ mutex_init(&gpio->irq_lock);
+
+ for (i = 0; i < gpio->gc.ngpio; i++) {
+ gpio->irq_cfg[i] = 0;
+
+ ret = regmap_read(gpio->regmap, GPIO_IRQ_CFG_REG(i), &val);
+ if (ret) {
+ dev_err(gpio->dev,
+ "Failed to read GPIO[%d] irq config (%d)\n",
+ i, ret);
+ continue;
+ }
+
+ if (val & MCA_GPIO_IRQ_CAPABLE)
+ gpio->irq_capable[GPIO_BYTE(i)] |= 1 << BYTE_OFFSET(i);
+ else
+ gpio->irq_capable[GPIO_BYTE(i)] &= ~(1 << BYTE_OFFSET(i));
+ }
+
+ for (i = 0; i < MCA_MAX_GPIO_IRQ_BANKS; i++) {
+ if (gpio->irq[i] < 0)
+ continue;
+ ret = devm_request_threaded_irq(gpio->dev, gpio->irq[i],
+ NULL, mca_gpio_irq_handler,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ mca_gpio_irq_chip.name,
+ gpio);
+ if (ret) {
+ dev_err(gpio->dev, "Failed to request %s IRQ (%d)\n",
+ irq_gpio_bank_name[i], gpio->irq[i]);
+ return ret;
+ }
+ }
+
+ ret = gpiochip_irqchip_add_nested(&gpio->gc,
+ &mca_gpio_irq_chip,
+ 0,
+ handle_edge_irq,
+ IRQ_TYPE_NONE);
+ if (ret) {
+ dev_err(gpio->dev,
+ "Failed to connect irqchip to gpiochip (%d)\n", ret);
+ return ret;
+ }
+
+ /*
+ * gpiochip_irqchip_add_nested() sets .to_irq with its own implementation but
+ * we have to use our own version because not all GPIOs are irq capable.
+ * Therefore, we overwrite it.
+ */
+ gpio->gc.to_irq = mca_gpio_to_irq;
+
+ for (i = 0; i < MCA_MAX_GPIO_IRQ_BANKS; i++) {
+ if (gpio->irq[i] < 0)
+ continue;
+ gpiochip_set_nested_irqchip(&gpio->gc,
+ &mca_gpio_irq_chip,
+ gpio->irq[i]);
+ }
+
+ return 0;
+}
+
+static struct gpio_chip reference_gc = {
+ .label = "mca-gpio",
+ .owner = THIS_MODULE,
+ .get = mca_gpio_get,
+ .set = mca_gpio_set,
+ .direction_input = mca_gpio_direction_input,
+ .direction_output = mca_gpio_direction_output,
+ .to_irq = mca_gpio_to_irq,
+ .set_config = mca_gpio_set_config,
+ .can_sleep = 1,
+ .base = -1,
+};
+
+static int mca_gpio_probe(struct platform_device *pdev)
+{
+ struct mca_drv *mca = dev_get_drvdata(pdev->dev.parent);
+ struct device *mca_dev = mca->dev;
+ struct regmap *regmap = mca->regmap;
+ int *gpio_base = &mca->gpio_base;
+ struct mca_gpio *gpio;
+ struct device_node *np;
+ unsigned int val;
+ int ret, i;
+
+ gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
+ if (!gpio) {
+ dev_err(mca_dev, "Failed to allocate GPIO device\n");
+ return -ENOMEM;
+ }
+
+ if (!mca_dev)
+ return -EPROBE_DEFER;
+
+ gpio->dev = mca_dev;
+ gpio->regmap = regmap;
+
+ for (i = 0; i < MCA_MAX_GPIO_IRQ_BANKS; i++) {
+ gpio->irq[i] = platform_get_irq_byname(pdev,
+ irq_gpio_bank_name[i]);
+ }
+ gpio->gc = reference_gc;
+ gpio->gc.of_node = pdev->dev.of_node;
+ gpio->gc.parent = &pdev->dev;
+ platform_set_drvdata(pdev, gpio);
+
+ /* Find entry in device-tree */
+ if (mca_dev->of_node) {
+ const struct mca_gpio_data *devdata =
+ of_device_get_match_data(&pdev->dev);
+ const char * compatible = pdev->dev.driver->
+ of_match_table[devdata->devtype].compatible;
+
+ /* Return if node does not exist or if it is disabled */
+ np = of_find_compatible_node(mca_dev->of_node, NULL, compatible);
+ if (!np) {
+ ret = -ENODEV;
+ goto err;
+ }
+ if (!of_device_is_available(np)) {
+ ret = -ENODEV;
+ goto err;
+ }
+ }
+
+ /* Get number of GPIOs from MCA firmware */
+ if (regmap_read(regmap, MCA_GPIO_NUM, &val)) {
+ ret = -EINVAL;
+ dev_err(mca_dev, "Could not read number of gpios.\n");
+ goto err;
+ }
+ gpio->gc.ngpio = val & MCA_GPIO_NUM_MASK;
+ if (gpio->gc.ngpio < 1 || gpio->gc.ngpio > MCA_MAX_IOS) {
+ ret = -EINVAL;
+ dev_err(mca_dev, "Read invalid number of gpios (%d). "
+ "Valid range is 1..%d.\n", gpio->gc.ngpio,
+ MCA_MAX_IOS);
+ goto err;
+ }
+
+ ret = gpiochip_add_data(&gpio->gc, gpio);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
+ goto err;
+ }
+
+ ret = mca_gpio_irq_setup(gpio);
+ if (ret) {
+ gpiochip_remove(&gpio->gc);
+ goto err;
+ }
+
+ if (gpio_base)
+ *gpio_base = gpio->gc.base;
+
+ return 0;
+
+err:
+ gpio = NULL;
+ return ret;
+}
+
+static int mca_gpio_remove(struct platform_device *pdev)
+{
+ struct mca_gpio *gpio = platform_get_drvdata(pdev);
+ struct mca_drv *mca = (struct mca_drv *)gpio->parent; /* TODO */
+
+ mca->gpio_base = -1;
+ gpiochip_remove(&gpio->gc);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static struct mca_gpio_data mca_gpio_devdata[] = {
+ [CC6UL_MCA_GPIO] = {
+ .devtype = CC6UL_MCA_GPIO,
+ },
+ [CC8X_MCA_GPIO] = {
+ .devtype = CC8X_MCA_GPIO,
+ },
+ [IOEXP_MCA_GPIO] = {
+ .devtype = IOEXP_MCA_GPIO,
+ },
+};
+
+static const struct of_device_id mca_gpio_dt_ids[] = {
+ { .compatible = "digi,mca-cc6ul-gpio",
+ .data = &mca_gpio_devdata[CC6UL_MCA_GPIO]},
+ { .compatible = "digi,mca-cc8x-gpio",
+ .data = &mca_gpio_devdata[CC8X_MCA_GPIO]},
+ { .compatible = "digi,mca-ioexp-gpio",
+ .data = &mca_gpio_devdata[IOEXP_MCA_GPIO]},
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mca_gpio_dt_ids);
+#endif
+
+static struct platform_driver mca_gpio_driver = {
+ .probe = mca_gpio_probe,
+ .remove = mca_gpio_remove,
+ .driver = {
+ .name = MCA_DRVNAME_GPIO,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_OF
+ .of_match_table = mca_gpio_dt_ids,
+#endif
+ },
+};
+
+static int __init mca_gpio_init(void)
+{
+ return platform_driver_register(&mca_gpio_driver);
+}
+module_init(mca_gpio_init);
+
+static void __exit mca_gpio_exit(void)
+{
+ platform_driver_unregister(&mca_gpio_driver);
+}
+module_exit(mca_gpio_exit);
+
+/* Module information */
+MODULE_AUTHOR("Digi International Inc.");
+MODULE_DESCRIPTION("GPIO device driver for MCA of ConnectCore Modules");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" MCA_DRVNAME_GPIO);
+

View File

@ -0,0 +1,33 @@
From 7350cbc80f98eacb84a67049c2181f758ca3add6 Mon Sep 17 00:00:00 2001
From: Alex Gonzalez <alex.gonzalez@digi.com>
Date: Fri, 15 Jun 2018 09:18:15 +0200
Subject: [PATCH] imx6ul: Add MCA IOMUX support to the ConnectCore 6UL SOM
Synched with v4.14.78/master at.
3f8b03950b323db4ca89b1cdc1c2288f79facaa3
Signed-off-by: Alex Gonzalez <alex.gonzalez@digi.com>
---
arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi b/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi
index 8d475051acf2..b96a0873cd88 100644
--- a/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi
+++ b/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi
@@ -286,6 +286,15 @@
MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x3000
>;
};
+
+ pinctrl_mca_cc6ul: mcagrp {
+ fsl,pins = <
+ /* MCA_nINT */
+ MX6UL_PAD_SNVS_TAMPER4__GPIO5_IO04 0xb0b1
+ /* MCA_FW_UPDATE */
+ MX6UL_PAD_NAND_CE1_B__GPIO4_IO14 0x30
+ >;
+ };
};
&reg_arm {

View File

@ -0,0 +1,467 @@
From 1440e9a7f2812ebe7ac1d74e8a3c7515bcd67fa8 Mon Sep 17 00:00:00 2001
From: Alex Gonzalez <alex.gonzalez@digi.com>
Date: Mon, 23 Apr 2018 11:39:40 +0200
Subject: [PATCH] imx6ul: Add MCA watchdog support for the ConnectCore 6UL SOM
Synched with v4.14.78/master at:
3f8b03950b323db4ca89b1cdc1c2288f79facaa3
Signed-off-by: Alex Gonzalez <alex.gonzalez@digi.com>
---
.../devicetree/bindings/watchdog/mca-cc6ul-wdt.txt | 22 ++
arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi | 5 +
arch/arm/configs/imx_v6_v7_defconfig | 1 +
drivers/watchdog/Kconfig | 8 +
drivers/watchdog/Makefile | 1 +
drivers/watchdog/mca_wdt.c | 354 +++++++++++++++++++++
6 files changed, 391 insertions(+)
create mode 100644 Documentation/devicetree/bindings/watchdog/mca-cc6ul-wdt.txt
create mode 100644 drivers/watchdog/mca_wdt.c
diff --git a/Documentation/devicetree/bindings/watchdog/mca-cc6ul-wdt.txt b/Documentation/devicetree/bindings/watchdog/mca-cc6ul-wdt.txt
new file mode 100644
index 000000000000..c6dd2cfdd316
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/mca-cc6ul-wdt.txt
@@ -0,0 +1,22 @@
+* Digi Watchdog Timer for MCA of ConnectCore 6UL
+
+Required properties:
+- compatible: must be "digi,mca-cc6ul-wdt".
+
+Optional properties:
+- digi,timeout-sec: contains the watchdog timeout in seconds.
+- digi,irq-no-reset: if present, the watchdog will generate an interrupt instead
+ of a system reset.
+- digi,full-reset: if present, the watchdog will perform a full system reset,
+ including the MCA. Otherwise, only the microprocessor is reset. Note
+ that this option requires the system to be configured to generate a
+ reset and not an interrupt.
+
+Example:
+ mca: mca-cc6ul@7e {
+ watchdog {
+ compatible = "digi,mca-cc6ul-wdt";
+ digi,timeout-sec = <15>;
+ digi,irq-no-reset;
+ };
+ };
diff --git a/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi b/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi
index b96a0873cd88..848bf78dfceb 100644
--- a/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi
+++ b/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi
@@ -69,6 +69,11 @@
#interrupt-cells = <2>;
};
+ watchdog {
+ compatible = "digi,mca-cc6ul-wdt";
+ digi,full-reset;
+ };
+
};
pfuze3000: pmic@8 {
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 6c3ede35e643..9c693c7778a4 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -226,6 +226,7 @@ CONFIG_IMX_THERMAL=y
CONFIG_WATCHDOG=y
CONFIG_DA9062_WATCHDOG=y
CONFIG_RN5T618_WATCHDOG=y
+CONFIG_MCA_WATCHDOG=y
CONFIG_IMX2_WDT=y
CONFIG_MFD_DA9052_I2C=y
CONFIG_MFD_DA9062=y
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 2d64333f4782..800821bfdd7d 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -171,6 +171,14 @@ config MENZ069_WATCHDOG
This driver can also be built as a module. If so the module
will be called menz069_wdt.
+config MCA_WATCHDOG
+ tristate "Digi ConnectCore SOMs Micro Controller Assist Watchdog"
+ select WATCHDOG_CORE
+ select MFD_MCA_CC6UL if SOC_IMX6UL
+ select MFD_MCA_CC8X if ARCH_FSL_IMX8QXP
+ help
+ If you say yes here you will get support for the watchdog in the Micro Controller Assist of Digi ConnectCore system-on-modules.
+
config TANGOX_WATCHDOG
tristate "Sigma Designs SMP86xx/SMP87xx watchdog"
select WATCHDOG_CORE
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index f69cdff5ad7f..36a275937216 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -80,6 +80,7 @@ obj-$(CONFIG_TEGRA_WATCHDOG) += tegra_wdt.o
obj-$(CONFIG_MESON_GXBB_WATCHDOG) += meson_gxbb_wdt.o
obj-$(CONFIG_MESON_WATCHDOG) += meson_wdt.o
obj-$(CONFIG_MEDIATEK_WATCHDOG) += mtk_wdt.o
+obj-$(CONFIG_MCA_WATCHDOG) += mca_wdt.o
obj-$(CONFIG_DIGICOLOR_WATCHDOG) += digicolor_wdt.o
obj-$(CONFIG_LPC18XX_WATCHDOG) += lpc18xx_wdt.o
obj-$(CONFIG_BCM7038_WDT) += bcm7038_wdt.o
diff --git a/drivers/watchdog/mca_wdt.c b/drivers/watchdog/mca_wdt.c
new file mode 100644
index 000000000000..7d5e8b303ed5
--- /dev/null
+++ b/drivers/watchdog/mca_wdt.c
@@ -0,0 +1,354 @@
+/*
+ * Watchdog driver for MCA on ConnectCore modules
+ *
+ * Copyright(c) 2016 - 2018 Digi International Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+
+#include <linux/mfd/mca-common/core.h>
+
+#define MCA_DRVNAME_WATCHDOG "mca-watchdog"
+
+#define WDT_REFRESH_LEN (MCA_WDT_REFRESH_3 - \
+ MCA_WDT_REFRESH_0 + 1)
+#define WDT_REFRESH_PATTERN "WDTP"
+#define WATCHDOG_NAME "MCA Watchdog"
+#define DEFAULT_TIMEOUT 30 /* 30 sec default timeout */
+
+#ifdef CONFIG_OF
+enum mca_wdt_type {
+ CC6UL_MCA_WDT,
+ CC8X_MCA_WDT,
+};
+
+struct mca_wdt_data {
+ enum mca_wdt_type devtype;
+};
+#endif
+
+struct mca_wdt {
+ struct watchdog_device wdd;
+ struct mca_drv *mca;
+ struct kref kref;
+ unsigned int default_timeout;
+ bool irqnoreset;
+ bool nowayout;
+ bool fullreset;
+ unsigned int irq_timeout;
+};
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+ "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static int mca_wdt_set_timeout(struct watchdog_device *wdd,
+ unsigned int timeout)
+{
+ struct mca_wdt *wdt = watchdog_get_drvdata(wdd);
+ struct mca_drv *mca = wdt->mca;
+ int ret;
+
+ if (timeout < wdt->wdd.min_timeout ||
+ timeout > wdt->wdd.max_timeout) {
+ ret = -EINVAL;
+ } else {
+ ret = regmap_write(mca->regmap, MCA_WDT_TIMEOUT, timeout);
+ }
+
+ if (ret < 0) {
+ dev_err(mca->dev, "Failed to set timeout, %d\n", ret);
+ return ret;
+ }
+
+ wdd->timeout = timeout;
+
+ return 0;
+}
+
+static int mca_config_options(struct mca_wdt *wdt)
+{
+ int ret = 0;
+ u8 control = 0;
+
+ control |= wdt->nowayout ? MCA_WDT_NOWAYOUT : 0;
+ control |= wdt->irqnoreset ? MCA_WDT_IRQNORESET : 0;
+ control |= wdt->fullreset ? MCA_WDT_FULLRESET : 0;
+
+ ret = regmap_update_bits(wdt->mca->regmap, MCA_WDT_CONTROL,
+ MCA_WDT_NOWAYOUT | MCA_WDT_IRQNORESET |
+ MCA_WDT_FULLRESET, control);
+ if (ret)
+ goto err;
+
+ /* Set timeout */
+ ret = mca_wdt_set_timeout(&wdt->wdd, wdt->default_timeout);
+ if (ret) {
+ dev_err(wdt->mca->dev, "Could not set watchdog timeout (%d)\n",
+ ret);
+ goto err;
+ }
+
+err:
+ return ret;
+}
+
+static int mca_wdt_ping(struct watchdog_device *wdd)
+{
+ struct mca_wdt *wdt = watchdog_get_drvdata(wdd);
+ struct mca_drv *mca = wdt->mca;
+ const char *pattern = WDT_REFRESH_PATTERN;
+
+ /*
+ * Refresh the watchdog timer by writing refresh pattern to REFRESH_x
+ * registers
+ */
+ return regmap_bulk_write(mca->regmap, MCA_WDT_REFRESH_0,
+ pattern, WDT_REFRESH_LEN);
+}
+
+static void mca_wdt_release_resources(struct kref *r)
+{
+}
+
+static int mca_wdt_start(struct watchdog_device *wdd)
+{
+ struct mca_wdt *wdt = watchdog_get_drvdata(wdd);
+ int ret = 0;
+
+ /* Enable watchdog */
+ ret = regmap_update_bits(wdt->mca->regmap, MCA_WDT_CONTROL,
+ MCA_WDT_ENABLE, MCA_WDT_ENABLE);
+ if (ret) {
+ dev_err(wdt->mca->dev, "Could not enable watchdog (%d)\n", ret);
+ goto err;
+ }
+
+err:
+ return ret;
+}
+
+static int mca_wdt_stop(struct watchdog_device *wdd)
+{
+ struct mca_wdt *wdt = watchdog_get_drvdata(wdd);
+
+ /* Disable watchdog */
+ return regmap_update_bits(wdt->mca->regmap, MCA_WDT_CONTROL,
+ MCA_WDT_ENABLE, 0);
+}
+
+static irqreturn_t mca_wdt_timeout_event(int irq, void *data)
+{
+ return IRQ_HANDLED;
+}
+
+static struct watchdog_info mca_wdt_info = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | \
+ WDIOF_MAGICCLOSE,
+ .identity = WATCHDOG_NAME,
+};
+
+static const struct watchdog_ops mca_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = mca_wdt_start,
+ .stop = mca_wdt_stop,
+ .ping = mca_wdt_ping,
+ .set_timeout = mca_wdt_set_timeout,
+};
+
+static int of_mca_wdt_init(struct device_node *np,
+ struct mca_wdt *wdt)
+{
+ unsigned int timeout;
+
+ /* parse options */
+ wdt->irqnoreset = of_property_read_bool(np, "digi,irq-no-reset");
+ wdt->fullreset = of_property_read_bool(np, "digi,full-reset");
+
+ if (!of_property_read_u32_index(np, "digi,timeout-sec", 0, &timeout)) {
+ if (timeout < wdt->wdd.min_timeout ||
+ timeout > wdt->wdd.max_timeout)
+ dev_warn(wdt->mca->dev,
+ "Invalid timeout-sec value. Using default.\n");
+ else
+ wdt->default_timeout = timeout;
+ }
+
+ return 0;
+}
+
+static int mca_wdt_probe(struct platform_device *pdev)
+{
+ struct mca_drv *mca = dev_get_drvdata(pdev->dev.parent);
+ struct mca_wdt *wdt;
+ const struct mca_wdt_data *devdata = (struct mca_wdt_data *)pdev->id_entry->driver_data;
+ struct device_node *np;
+ int ret;
+
+ wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+ if (!wdt) {
+ dev_err(mca->dev, "Failed to allocate watchdog device\n");
+ return -ENOMEM;
+ }
+
+ wdt->mca = mca;
+ wdt->default_timeout = DEFAULT_TIMEOUT;
+ wdt->nowayout = nowayout;
+ wdt->wdd.min_timeout = 0;
+ wdt->wdd.max_timeout = 0xff;
+ wdt->wdd.info = &mca_wdt_info;
+ wdt->wdd.ops = &mca_wdt_ops;
+ wdt->wdd.parent = &pdev->dev;
+
+ watchdog_set_drvdata(&wdt->wdd, wdt);
+ kref_init(&wdt->kref);
+ platform_set_drvdata(pdev, wdt);
+
+ /* Find entry in device-tree */
+ if (mca->dev->of_node) {
+ const char * compatible = pdev->dev.driver->
+ of_match_table[devdata->devtype].compatible;
+
+ /*
+ * Return silently if watchdog node does not exist
+ * or if it is disabled
+ */
+ np = of_find_compatible_node(mca->dev->of_node, NULL, compatible);
+ if (!np) {
+ ret = -ENODEV;
+ goto err;
+ }
+ if (!of_device_is_available(np)) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ /* Parse DT properties */
+ ret = of_mca_wdt_init(np, wdt);
+ if (ret)
+ goto err;
+ }
+
+ /* Configure WDT options */
+ ret = mca_config_options(wdt);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to configure WDT options\n");
+ goto err;
+ }
+
+ /* Set nowayout option into watchdog device */
+ watchdog_set_nowayout(&wdt->wdd, nowayout);
+
+ /* Register interrupt if so configured */
+ if (wdt->irqnoreset) {
+ wdt->irq_timeout = platform_get_irq_byname(pdev,
+ MCA_IRQ_WATCHDOG_NAME);
+ ret = devm_request_threaded_irq(&pdev->dev, wdt->irq_timeout,
+ NULL, mca_wdt_timeout_event,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ MCA_IRQ_WATCHDOG_NAME, wdt);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to request %s IRQ. (%d)\n",
+ MCA_IRQ_WATCHDOG_NAME, wdt->irq_timeout);
+ wdt->irq_timeout = -ENXIO;
+ goto err;
+ }
+ }
+
+ ret = watchdog_register_device(&wdt->wdd);
+ if (ret != 0) {
+ dev_err(wdt->mca->dev,
+ "watchdog_register_device() failed: %d\n", ret);
+ goto err;
+ }
+
+ pr_info("Watchdog driver for MCA (timeout=%d sec, nowayout=%d, %s%s)\n",
+ wdt->default_timeout, nowayout,
+ wdt->irqnoreset ? "interrupt (no reset)" : "reset",
+ wdt->irqnoreset ? "" : wdt->fullreset ? " (full)" : " (MPU only)");
+ return 0;
+
+err:
+ wdt = NULL;
+ return ret;
+}
+
+static int mca_wdt_remove(struct platform_device *pdev)
+{
+ struct mca_wdt *wdt = platform_get_drvdata(pdev);
+
+ if(wdt->irq_timeout)
+ devm_free_irq(&pdev->dev, wdt->irq_timeout, wdt);
+ watchdog_unregister_device(&wdt->wdd);
+ kref_put(&wdt->kref, mca_wdt_release_resources);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static struct mca_wdt_data mca_wdt_devdata[] = {
+ [CC6UL_MCA_WDT] = {
+ .devtype = CC6UL_MCA_WDT,
+ },
+ [CC8X_MCA_WDT] = {
+ .devtype = CC8X_MCA_WDT,
+ },
+};
+
+static const struct platform_device_id mca_wdt_devtype[] = {
+ {
+ .name = "mca-cc6ul-watchdog",
+ .driver_data = (kernel_ulong_t)&mca_wdt_devdata[CC6UL_MCA_WDT],
+ }, {
+ .name = "mca-cc8x-watchdog",
+ .driver_data = (kernel_ulong_t)&mca_wdt_devdata[CC8X_MCA_WDT],
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(platform, mca_wdt_devtype);
+
+static const struct of_device_id mca_wdt_match[] = {
+ { .compatible = "digi,mca-cc6ul-wdt",
+ .data = &mca_wdt_devdata[CC6UL_MCA_WDT]},
+ { .compatible = "digi,mca-cc8x-wdt",
+ .data = &mca_wdt_devdata[CC8X_MCA_WDT]},
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mca_wdt_match);
+#endif
+
+static struct platform_driver mca_wdt_driver = {
+ .probe = mca_wdt_probe,
+ .remove = mca_wdt_remove,
+ .id_table = mca_wdt_devtype,
+ .driver = {
+ .name = MCA_DRVNAME_WATCHDOG,
+ .of_match_table = of_match_ptr(mca_wdt_match),
+ },
+};
+
+module_platform_driver(mca_wdt_driver);
+
+MODULE_AUTHOR("Digi International Inc.");
+MODULE_DESCRIPTION("Watchdog device driver for MCA of ConnectCore Modules");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" MCA_DRVNAME_WATCHDOG);

View File

@ -0,0 +1,937 @@
From bfc63af24c96ca3206e3f8e6b0fd437944e6519e Mon Sep 17 00:00:00 2001
From: Alex Gonzalez <alex.gonzalez@digi.com>
Date: Mon, 23 Apr 2018 11:42:42 +0200
Subject: [PATCH] imx6ul: Add MCA tamper support for ConnectCore 6UL SOM and
SBCs
Synched with v4.14.78/master at:
3f8b03950b323db4ca89b1cdc1c2288f79facaa3
Signed-off-by: Alex Gonzalez <alex.gonzalez@digi.com>
---
arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts | 7 +
arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi | 4 +
arch/arm/configs/imx_v6_v7_defconfig | 1 +
drivers/iio/Kconfig | 1 +
drivers/iio/Makefile | 1 +
drivers/iio/tamper/Kconfig | 20 +
drivers/iio/tamper/Makefile | 6 +
drivers/iio/tamper/mca_tamper.c | 801 ++++++++++++++++++++++++++++
8 files changed, 841 insertions(+)
create mode 100644 drivers/iio/tamper/Kconfig
create mode 100644 drivers/iio/tamper/Makefile
create mode 100644 drivers/iio/tamper/mca_tamper.c
diff --git a/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts b/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts
index acea9a56971e..7cbc14d56680 100644
--- a/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts
+++ b/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts
@@ -162,6 +162,13 @@
digi,adc-vref = <3000000>;
};
+/* Enable Tamper detection. There are 2 digital (0 and 1) and 2
+ * analog (2 and 3) tamper interfaces.
+ */
+&mca_tamper {
+ digi,tamper-if-list = <0 1 2 3>;
+};
+
&pwm1 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi b/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi
index b5efc58d362d..a20fb5ffc98b 100644
--- a/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi
+++ b/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi
@@ -79,6 +79,10 @@
digi,adc-vref = <3000000>;
};
+ mca_tamper: tamper {
+ compatible = "digi,mca-cc6ul-tamper";
+ };
+
};
pfuze3000: pmic@8 {
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 060c1de356ca..188fb4309851 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -390,6 +390,7 @@ CONFIG_VF610_ADC=y
CONFIG_SENSORS_ISL29018=y
CONFIG_MAG3110=y
CONFIG_MPL3115=y
+CONFIG_TAMPER_MCA=y
CONFIG_PWM=y
CONFIG_PWM_FSL_FTM=y
CONFIG_PWM_IMX=y
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index d08aeb41cd07..e4c3fd62ca92 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -94,6 +94,7 @@ source "drivers/iio/potentiostat/Kconfig"
source "drivers/iio/pressure/Kconfig"
source "drivers/iio/proximity/Kconfig"
source "drivers/iio/resolver/Kconfig"
+source "drivers/iio/tamper/Kconfig"
source "drivers/iio/temperature/Kconfig"
endif # IIO
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index cb5993251381..004de1adaf82 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -37,5 +37,6 @@ obj-y += potentiostat/
obj-y += pressure/
obj-y += proximity/
obj-y += resolver/
+obj-y += tamper/
obj-y += temperature/
obj-y += trigger/
diff --git a/drivers/iio/tamper/Kconfig b/drivers/iio/tamper/Kconfig
new file mode 100644
index 000000000000..2a9a395becf4
--- /dev/null
+++ b/drivers/iio/tamper/Kconfig
@@ -0,0 +1,20 @@
+#
+# Tamper Devices
+#
+
+menu "Tamper devices"
+
+config TAMPER_MCA
+ tristate "Tamper support for MCA on Digi ConnectCore SOMs"
+ select MFD_MCA_CC6UL if SOC_IMX6UL
+ select MFD_MCA_CC8X if ARCH_FSL_IMX8QXP
+
+ help
+ Say Y here to build the tamper driver on the MCA of the
+ ConnectCore system-on-modules.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mca_tamper
+
+endmenu
+
diff --git a/drivers/iio/tamper/Makefile b/drivers/iio/tamper/Makefile
new file mode 100644
index 000000000000..9f422a829081
--- /dev/null
+++ b/drivers/iio/tamper/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for IIO Tamper devices
+#
+
+# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_TAMPER_MCA) += mca_tamper.o
diff --git a/drivers/iio/tamper/mca_tamper.c b/drivers/iio/tamper/mca_tamper.c
new file mode 100644
index 000000000000..2c92624aed18
--- /dev/null
+++ b/drivers/iio/tamper/mca_tamper.c
@@ -0,0 +1,801 @@
+/* mca_tamper.c - Tamper driver for MCA on ConnectCore modules
+ *
+ * Copyright (C) 2016 - 2018 Digi International Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/acpi.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mfd/mca-common/core.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+
+#define MCA_DRVNAME_TAMPER "mca-tamper"
+
+#ifdef CONFIG_OF
+enum mca_tamper_type {
+ CC6UL_MCA_TAMPER,
+ CC8X_MCA_TAMPER,
+};
+
+struct mca_tamper_data {
+ enum mca_tamper_type devtype;
+ u16 num_tamper_ifaces;
+ u16 digital_tamper_cnt;
+};
+#endif
+
+struct mca_tamper {
+ struct mca_drv *mca;
+ struct iio_dev *iio;
+ char name[10];
+ uint8_t config0;
+ uint8_t config1;
+ uint8_t io_in;
+ uint8_t io_out;
+ uint8_t pwroff_delay_ms;
+ uint8_t event;
+ int irq;
+ int iface;
+};
+
+/* Tamper register offsets */
+enum {
+ CFG0 = 0,
+ CFG1 = MCA_TAMPER0_CFG1 - MCA_TAMPER0_CFG0,
+ IO_IN = MCA_TAMPER0_IO_IN - MCA_TAMPER0_CFG0,
+ IO_OUT = MCA_TAMPER0_IO_OUT - MCA_TAMPER0_CFG0,
+ DELAY_PWROFF = MCA_TAMPER0_DELAY_PWROFF - MCA_TAMPER0_CFG0,
+ DATE_YEAR_L = MCA_TAMPER0_DATE_START - MCA_TAMPER0_CFG0,
+ DATE_YEAR_H,
+ DATE_MONTH,
+ DATE_DAY,
+ DATE_HOUR,
+ DATE_MIN,
+ DATE_SEC,
+ EVENT = MCA_TAMPER0_EVENT - MCA_TAMPER0_CFG0,
+ TICKS = MCA_TAMPER2_TICKS_L - MCA_TAMPER2_CFG0,
+ THR_L = MCA_TAMPER2_THRESH_LO_L - MCA_TAMPER2_CFG0,
+ THR_H = MCA_TAMPER2_THRESH_HI_L - MCA_TAMPER2_CFG0,
+};
+
+static int mca_tamper_read_raw(struct iio_dev *iio,
+ struct iio_chan_spec const *ch,
+ int *val, int *val2, long mask)
+{
+ struct mca_tamper *tp = iio_priv(iio);
+ u32 value;
+ int ret;
+ unsigned int event_reg;
+
+ switch (tp->iface) {
+ case 0:
+ event_reg = MCA_TAMPER0_EVENT;
+ break;
+ case 1:
+ event_reg = MCA_TAMPER1_EVENT;
+ break;
+ case 2:
+ event_reg = MCA_TAMPER2_EVENT;
+ break;
+ case 3:
+ event_reg = MCA_TAMPER3_EVENT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = regmap_read(tp->mca->regmap, event_reg, &value);
+ if (ret < 0) {
+ dev_err(tp->mca->dev,
+ "Error reading Tamper%d event register (%d)\n",
+ ch->channel, ret);
+ return ret;
+ }
+
+ *val = value;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return IIO_VAL_INT;
+}
+
+static const struct iio_event_spec mca_tamper_events[] = {
+ {
+ .type = IIO_EV_TYPE_CHANGE,
+ .dir = IIO_EV_DIR_NONE,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+ },
+};
+
+static void mca_tamper_get_time(u8 *data, struct rtc_time *tm)
+{
+ tm->tm_year = ((data[DATE_YEAR_H] << 8) | data[DATE_YEAR_L]) - 1900;
+ tm->tm_mon = (data[DATE_MONTH] & MCA_RTC_MONTH_MASK) - 1;
+ tm->tm_mday = (data[DATE_DAY] & MCA_RTC_DAY_MASK);
+ tm->tm_hour = (data[DATE_HOUR] & MCA_RTC_HOUR_MASK);
+ tm->tm_min = (data[DATE_MIN] & MCA_RTC_MIN_MASK);
+ tm->tm_sec = (data[DATE_SEC] & MCA_RTC_SEC_MASK);
+}
+
+static unsigned int get_tamper_base_reg(unsigned int iface)
+{
+ switch (iface) {
+ case 0:
+ return MCA_TAMPER0_CFG0;
+ case 1:
+ return MCA_TAMPER1_CFG0;
+ case 2:
+ return MCA_TAMPER2_CFG0;
+ case 3:
+ return MCA_TAMPER3_CFG0;
+ default:
+ break;
+ }
+
+ return ~0;
+}
+
+/* Sysfs interface */
+#define TAMPER_SYSFS_SHOW_REG(reg, addr, type) \
+static ssize_t show_##reg(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct iio_dev *iio = dev_to_iio_dev(dev); \
+ struct mca_tamper *tp = iio_priv(iio); \
+ int ret; \
+ type val; \
+ unsigned int tamper_base_reg = get_tamper_base_reg(tp->iface); \
+ \
+ if (tamper_base_reg == ~0) \
+ return -1; \
+ \
+ ret = regmap_bulk_read(tp->mca->regmap, \
+ tamper_base_reg + addr, \
+ &val, sizeof(val)); \
+ if (ret != 0) { \
+ dev_err(tp->mca->dev, \
+ "Failed reading Tamper%d #reg register (%d)\n", \
+ tp->iface, ret); \
+ return 0; \
+ } \
+ return sprintf(buf, "0x%04x\n", (type)val); \
+}
+
+#define TAMPER_SYSFS_STORE_REG(reg, addr, type) \
+static ssize_t store_##reg(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct iio_dev *iio = dev_to_iio_dev(dev); \
+ struct mca_tamper *tp = iio_priv(iio); \
+ int ret; \
+ unsigned long val; \
+ unsigned int tamper_base_reg = get_tamper_base_reg(tp->iface); \
+ \
+ if (tamper_base_reg == ~0) \
+ return -1; \
+ \
+ ret = kstrtoul(buf, 0, &val); \
+ if (ret) { \
+ dev_err(tp->mca->dev, \
+ "%s: error parsing input (%s)\n", \
+ __func__, buf); \
+ return ret; \
+ } \
+ ret = regmap_bulk_write(tp->mca->regmap, \
+ tamper_base_reg + addr, \
+ &val, sizeof(type)); \
+ if (ret != 0) { \
+ dev_err(tp->mca->dev, \
+ "Failed write Tamper%d #reg register (%d)\n", \
+ tp->iface, ret); \
+ return 0; \
+ } \
+ return count; \
+}
+
+#define MCA_TAMPER_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr)
+
+static ssize_t show_tp_events(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *iio = dev_to_iio_dev(dev);
+ struct mca_tamper *tp = iio_priv(iio);
+ int ret;
+ unsigned int val;
+ unsigned int tamper_base_reg = get_tamper_base_reg(tp->iface);
+
+ if (tamper_base_reg == ~0)
+ return -1;
+
+ ret = regmap_read(tp->mca->regmap, tamper_base_reg + EVENT, &val);
+ if (ret != 0) {
+ dev_err(tp->mca->dev,
+ "Failed reading Tamper%d #reg register (%d)\n",
+ tp->iface, ret);
+ return 0;
+ }
+
+ switch (val) {
+ case 0x00:
+ ret = sprintf(buf, "none\n");
+ break;
+ case MCA_TAMPER_SIGNALED:
+ ret = sprintf(buf, "signaled\n");
+ break;
+ case (MCA_TAMPER_ACKED | MCA_TAMPER_SIGNALED):
+ ret = sprintf(buf, "signaled+acked\n");
+ break;
+ default:
+ ret = sprintf(buf, "unknown (0x%04x)\n", (u8)val);
+ break;
+ }
+ return ret;
+}
+
+static ssize_t store_tp_events(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iio_dev *iio = dev_to_iio_dev(dev);
+ struct mca_tamper *tp = iio_priv(iio);
+ int ret;
+ unsigned long val;
+ unsigned int tamper_base_reg = get_tamper_base_reg(tp->iface);
+
+ if (tamper_base_reg == ~0)
+ return -1;
+
+ if (!strncmp(buf, "ack", strlen("ack")))
+ val = MCA_TAMPER_ACKED;
+ else if (!strncmp(buf, "clear", strlen("clear")))
+ val = MCA_TAMPER_CLEAR;
+ else {
+ /* Check if string is a raw value */
+ ret = kstrtoul(buf, 0, &val);
+ if (ret || (val != MCA_TAMPER_CLEAR &&
+ val != MCA_TAMPER_ACKED)) {
+ dev_err(tp->mca->dev,
+ "%s: error parsing input (%s)\n",
+ __func__, buf);
+ return ret;
+ }
+ }
+
+ ret = regmap_write(tp->mca->regmap, tamper_base_reg + EVENT, val);
+ if (ret != 0) {
+ dev_err(tp->mca->dev,
+ "Failed write Tamper%d #reg register (%d)\n",
+ tp->iface, ret);
+ return 0;
+ }
+
+ return count;
+}
+
+static ssize_t show_timestamp(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *iio = dev_to_iio_dev(dev);
+ struct mca_tamper *tp = iio_priv(iio);
+ unsigned int tamper_base_reg = get_tamper_base_reg(tp->iface);
+ time64_t tamper_t64 = -1;
+ struct rtc_time tm;
+ u8 data[MCA_TAMPER_REGS_LEN];
+ int ret;
+
+ if (tamper_base_reg == ~0)
+ return -1;
+
+ ret = regmap_bulk_read(tp->mca->regmap, tamper_base_reg, data,
+ sizeof(data));
+ if (ret != 0) {
+ dev_err(tp->mca->dev, "Failed reading Tamper%d registers (%d)\n",
+ tp->iface, ret);
+ return ret;
+ }
+
+ /* Confirm the event and get the timestamp */
+ if (data[EVENT] & MCA_TAMPER_SIGNALED) {
+ mca_tamper_get_time(data, &tm);
+ tamper_t64 = rtc_tm_to_time64(&tm);
+ }
+
+ return sprintf(buf, "%lld\n", tamper_t64);
+}
+
+static IIO_DEVICE_ATTR(tamper_events, S_IRUGO | S_IWUSR, show_tp_events, store_tp_events, 0);
+static IIO_DEVICE_ATTR(timestamp, S_IRUGO, show_timestamp, NULL, 0);
+
+#ifdef MCA_TAMPER_HAS_EXTRA_SYSFS_ENTRIES
+TAMPER_SYSFS_SHOW_REG(config0, CFG0, u8)
+TAMPER_SYSFS_SHOW_REG(config1, CFG1, u8)
+TAMPER_SYSFS_SHOW_REG(io_in, IO_IN, u8)
+TAMPER_SYSFS_SHOW_REG(io_out, IO_OUT, u8)
+TAMPER_SYSFS_SHOW_REG(pwroff_delay_ms, DELAY_PWROFF, u8)
+TAMPER_SYSFS_SHOW_REG(srate, TICKS, u16)
+TAMPER_SYSFS_SHOW_REG(thr_l, THR_L, u16)
+TAMPER_SYSFS_SHOW_REG(thr_h, THR_H, u16)
+
+TAMPER_SYSFS_STORE_REG(config0, CFG0, u8)
+TAMPER_SYSFS_STORE_REG(config1, CFG1, u8)
+TAMPER_SYSFS_STORE_REG(io_in, IO_IN, u8)
+TAMPER_SYSFS_STORE_REG(io_out, IO_OUT, u8)
+TAMPER_SYSFS_STORE_REG(pwroff_delay_ms, DELAY_PWROFF, u8)
+TAMPER_SYSFS_STORE_REG(srate, TICKS, u16)
+TAMPER_SYSFS_STORE_REG(thr_l, THR_L, u16)
+TAMPER_SYSFS_STORE_REG(thr_h, THR_H, u16)
+
+static IIO_DEVICE_ATTR(config0, S_IRUGO | S_IWUSR, show_config0, store_config0, 0);
+static IIO_DEVICE_ATTR(config1, S_IRUGO | S_IWUSR, show_config1, store_config1, 0);
+static IIO_DEVICE_ATTR(io_in, S_IRUGO | S_IWUSR, show_io_in, store_io_in, 0);
+static IIO_DEVICE_ATTR(io_out, S_IRUGO | S_IWUSR, show_io_out, store_io_out, 0);
+static IIO_DEVICE_ATTR(pwroff_delay_ms, S_IRUGO | S_IWUSR, show_pwroff_delay_ms, store_pwroff_delay_ms, 0);
+static IIO_DEVICE_ATTR(srate, S_IRUGO | S_IWUSR, show_srate, store_srate, 0);
+static IIO_DEVICE_ATTR(thr_l, S_IRUGO | S_IWUSR, show_thr_l, store_thr_l, 0);
+static IIO_DEVICE_ATTR(thr_h, S_IRUGO | S_IWUSR, show_thr_h, store_thr_h, 0);
+
+static struct attribute *mca_tamper_attributes[] = {
+ MCA_TAMPER_DEV_ATTR(config0),
+ MCA_TAMPER_DEV_ATTR(io_in),
+ MCA_TAMPER_DEV_ATTR(io_out),
+ MCA_TAMPER_DEV_ATTR(pwroff_delay_ms),
+ MCA_TAMPER_DEV_ATTR(tamper_events),
+ NULL,
+};
+
+static struct attribute *mca_tamper_analog_attributes[] = {
+ MCA_TAMPER_DEV_ATTR(config0),
+ MCA_TAMPER_DEV_ATTR(config1),
+ MCA_TAMPER_DEV_ATTR(io_in),
+ MCA_TAMPER_DEV_ATTR(io_out),
+ MCA_TAMPER_DEV_ATTR(pwroff_delay_ms),
+ MCA_TAMPER_DEV_ATTR(tamper_events),
+ MCA_TAMPER_DEV_ATTR(timestamp),
+ MCA_TAMPER_DEV_ATTR(srate),
+ MCA_TAMPER_DEV_ATTR(thr_l),
+ MCA_TAMPER_DEV_ATTR(thr_h),
+ NULL,
+};
+
+static const struct attribute_group mca_tamper_analog_attribute_group = {
+ .name = "tamper_analog",
+ .attrs = mca_tamper_analog_attributes,
+};
+
+static const struct iio_info mca_tamper_analog_info = {
+ .attrs = &mca_tamper_analog_attribute_group,
+ .read_raw = &mca_tamper_read_raw,
+};
+
+#else
+static struct attribute *mca_tamper_attributes[] = {
+ MCA_TAMPER_DEV_ATTR(tamper_events),
+ MCA_TAMPER_DEV_ATTR(timestamp),
+ NULL,
+};
+#endif /* MCA_TAMPER_HAS_EXTRA_SYSFS_ENTRIES */
+
+static const struct attribute_group mca_tamper_attribute_group = {
+ .name = "tamper",
+ .attrs = mca_tamper_attributes,
+};
+
+static const struct iio_info mca_tamper_info = {
+ .attrs = &mca_tamper_attribute_group,
+ .read_raw = &mca_tamper_read_raw,
+};
+
+#ifdef MCA_TAMPER_DUMP_REGISTERS
+static void mca_tamper_regs_dump(u8 *data)
+{
+ printk("Tamper CFG0 = 0x%02x\n", data[CFG0]);
+ printk("Tamper CFG1 = 0x%02x\n", data[CFG1]);
+ printk("Tamper IO_IN = 0x%02x\n", data[IO_IN]);
+ printk("Tamper IO_OUT = 0x%02x\n", data[IO_OUT]);
+ printk("Tamper DELAY_PWROFF = 0x%02x\n", data[DELAY_PWROFF]);
+ printk("Tamper DATE_YEAR_L = 0x%02x\n", data[DATE_YEAR_L]);
+ printk("Tamper DATE_YEAR_H = 0x%02x\n", data[DATE_YEAR_H]);
+ printk("Tamper DATE_MONTH = 0x%02x\n", data[DATE_MONTH]);
+ printk("Tamper DATE_DAY = 0x%02x\n", data[DATE_DAY]);
+ printk("Tamper DATE_HOUR = 0x%02x\n", data[DATE_HOUR]);
+ printk("Tamper DATE_MIN = 0x%02x\n", data[DATE_MIN]);
+ printk("Tamper DATE_SEC = 0x%02x\n", data[DATE_SEC]);
+ printk("Tamper EVENT = 0x%02x\n", data[EVENT]);
+}
+#else
+static void mca_tamper_regs_dump(u8 *data) {}
+#endif
+
+static irqreturn_t mca_tamper_irq_handler(int irq, void *private)
+{
+ struct iio_dev *iio = private;
+ struct mca_tamper *tp = iio_priv(iio);
+ struct rtc_time tm;
+ u8 data[MCA_TAMPER_REGS_LEN];
+ time64_t tamper_t64;
+ u64 event;
+ int ret;
+ unsigned int tamper_base_reg = get_tamper_base_reg(tp->iface);
+
+ if (tamper_base_reg == ~0)
+ goto irq_out;
+
+ dev_dbg(tp->mca->dev, "Tamper %d IRQ (%d)\n", tp->iface, irq);
+
+ ret = regmap_bulk_read(tp->mca->regmap, tamper_base_reg, data,
+ sizeof(data));
+ if (ret != 0) {
+ dev_err(tp->mca->dev, "Failed reading Tamper%d registers (%d)\n",
+ tp->iface, ret);
+ goto irq_out;
+ }
+
+ /* Confirm the event and get the timestamp */
+ if (!(data[EVENT] & MCA_TAMPER_SIGNALED))
+ goto irq_out;
+
+ if (data[EVENT] & MCA_TAMPER_ACKED)
+ goto irq_out;
+
+ mca_tamper_regs_dump(data);
+ mca_tamper_get_time(data, &tm);
+ tamper_t64 = rtc_tm_to_time64(&tm);
+
+ /* Notify the event... */
+ event = IIO_MOD_EVENT_CODE(IIO_ACTIVITY, tp->iface, IIO_NO_MOD,
+ IIO_EV_TYPE_CHANGE, IIO_EV_DIR_NONE);
+ iio_push_event(iio, event, tamper_t64);
+
+irq_out:
+ return IRQ_HANDLED;
+}
+
+static int mca_tamper_is_enabled(struct mca_drv *mca, int iface)
+{
+ int ret;
+ u8 data[MCA_TAMPER_REGS_LEN];
+ unsigned int tamper_base_reg = get_tamper_base_reg(iface);
+
+ /* Get tamper configuration registers */
+ ret = regmap_bulk_read(mca->regmap,
+ tamper_base_reg,
+ data, sizeof(data));
+ if (ret != 0) {
+ dev_err(mca->dev,
+ "Failed reading tamper%d registers (%d)\n",
+ iface, ret);
+ return ret;
+ }
+
+ /* Verify if the tamper interface is enabled */
+ if (!(data[CFG0] & MCA_TAMPER_DET_EN))
+ return -1;
+ return 0;
+}
+
+static int mca_init_hardware(struct mca_tamper *tp)
+{
+ int ret;
+ u8 data[MCA_TAMPER_REGS_LEN];
+ unsigned int tamper_base_reg = get_tamper_base_reg(tp->iface);
+
+ /* Verify if the tamper interface is enabled */
+ ret = regmap_bulk_read(tp->mca->regmap,
+ tamper_base_reg,
+ data, sizeof(data));
+ if (ret != 0) {
+ dev_err(tp->mca->dev,
+ "Failed reading tamper%d registers (%d)\n",
+ tp->iface, ret);
+ return ret;
+ }
+
+ tp->config0 = data[CFG0];
+ tp->config1 = data[CFG1];
+ tp->io_in = data[IO_IN];
+ tp->io_out = data[IO_OUT];
+ tp->pwroff_delay_ms = data[DELAY_PWROFF];
+
+ if (!(data[CFG0] & MCA_TAMPER_DET_EN))
+ return -ENODEV;
+
+ if (tp->mca->gpio_base >= 0) {
+ ret = devm_gpio_request(tp->mca->dev,
+ tp->mca->gpio_base + tp->io_in,
+ "TAMPER IN");
+ if (ret != 0) {
+ dev_warn(tp->mca->dev,
+ "Error requesting GPIO %d for tamper %d input. It might be in use by other device.\n",
+ tp->mca->gpio_base + tp->io_in, tp->iface);
+ }
+
+ if (data[CFG0] & MCA_TAMPER_OUT_EN) {
+ ret = devm_gpio_request(tp->mca->dev,
+ tp->mca->gpio_base + tp->io_out,
+ "TAMPER OUT");
+ if (ret != 0) {
+ dev_warn(tp->mca->dev,
+ "Error requesting GPIO %d for tamper %d output. It might be in use by other device.\n",
+ tp->mca->gpio_base + tp->io_out,
+ tp->iface);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void mca_init_channel(struct iio_chan_spec *chan, int idx)
+{
+ chan->type = IIO_ACTIVITY;
+ chan->indexed = 1;
+ chan->channel = idx;
+ chan->scan_index = idx;
+ chan->scan_type.sign = 'u';
+ chan->scan_type.realbits = 1;
+ chan->scan_type.storagebits = 32;
+ chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
+ chan->event_spec = mca_tamper_events;
+ chan->num_event_specs = ARRAY_SIZE(mca_tamper_events);
+}
+
+static int mca_tamper_probe(struct platform_device *pdev)
+{
+ struct mca_drv *mca = dev_get_drvdata(pdev->dev.parent);
+ struct mca_tamper **mca_tamper = NULL;
+ const struct mca_tamper_data *devdata = of_device_get_match_data(&pdev->dev);
+ struct device_node *np;
+ struct property *prop;
+ const __be32 *cur;
+ u32 iface;
+ int ret = 0;
+ u16 num_tamper_ifaces;
+ u16 digital_tamper_cnt;
+
+ if (!mca || !mca->dev || !mca->dev->of_node || !devdata)
+ return -EPROBE_DEFER;
+
+ pr_info("Tamper driver for MCA\n");
+
+ num_tamper_ifaces = devdata->num_tamper_ifaces;
+ digital_tamper_cnt = devdata->digital_tamper_cnt;
+
+ mca_tamper = devm_kzalloc(&pdev->dev,
+ sizeof(*mca_tamper) * num_tamper_ifaces,
+ GFP_KERNEL);
+ if (!mca_tamper) {
+ dev_err(&pdev->dev, "Failed to allocate memory for mca_tamper\n");
+ ret = -ENOMEM;
+ goto exit_error;
+ }
+
+ platform_set_drvdata(pdev, mca_tamper);
+
+ for (iface = 0; iface < num_tamper_ifaces; iface++)
+ mca_tamper[iface] = NULL;
+
+ /* Return silently if RTC node does not exist or if it is disabled */
+ {
+ const char * compatible = pdev->dev.driver->
+ of_match_table[devdata->devtype].compatible;
+ np = of_find_compatible_node(mca->dev->of_node, NULL, compatible);
+ }
+ if (!np || !of_device_is_available(np)) {
+ ret = -ENODEV;
+ goto exit_error;
+ }
+
+ of_property_for_each_u32(np, "digi,tamper-if-list",
+ prop, cur, iface) {
+ struct iio_chan_spec *channels;
+ struct iio_dev *iiod = NULL;
+
+ if (iface >= num_tamper_ifaces)
+ continue;
+
+ if (mca_tamper_is_enabled(mca, iface) != 0) {
+ dev_info(&pdev->dev, "Tamper %d disabled\n", iface);
+ continue;
+ }
+
+ iiod = devm_iio_device_alloc(&pdev->dev,
+ sizeof(*mca_tamper));
+ if (!iiod) {
+ dev_err(&pdev->dev, "Failed to allocate iio device\n");
+ ret = -ENOMEM;
+ goto exit_error;
+ }
+ mca_tamper[iface] = iio_priv(iiod);
+ mca_tamper[iface]->mca = mca;
+ mca_tamper[iface]->iface = iface;
+ mca_tamper[iface]->iio = iiod;
+
+ iiod->dev.parent = &pdev->dev;
+ sprintf(mca_tamper[iface]->name, "TAMPER%d", iface);
+ iiod->name = mca_tamper[iface]->name;
+ iiod->modes = INDIO_DIRECT_MODE;
+ channels = devm_kzalloc(&pdev->dev,
+ sizeof(struct iio_chan_spec),
+ GFP_KERNEL);
+ iiod->channels = channels;
+ if (!iiod->channels) {
+ dev_err(&pdev->dev, "Failed to allocate iio channels\n");
+ ret = -ENOMEM;
+ goto exit_error;
+ }
+
+#ifdef MCA_TAMPER_HAS_EXTRA_SYSFS_ENTRIES
+ if (iface < digital_tamper_cnt)
+ iiod->info = &mca_tamper_info;
+ else
+ iiod->info = &mca_tamper_analog_info;
+#else
+ iiod->info = &mca_tamper_info;
+#endif
+ iiod->num_channels = 1;
+ mca_init_channel(channels, iface);
+
+ ret = mca_init_hardware(mca_tamper[iface]);
+ if (ret != 0) {
+ /* Skip the error msg if interface is not enabled */
+ if (ret != -ENODEV)
+ dev_err(&pdev->dev, "Failed to init Tamper %d\n",
+ iface);
+ continue;
+ }
+
+ mca_tamper[iface]->irq = platform_get_irq_byname(pdev,
+ mca_tamper[iface]->name);
+ if (mca_tamper[iface]->irq) {
+ ret = devm_request_threaded_irq(&pdev->dev,
+ mca_tamper[iface]->irq,
+ NULL, mca_tamper_irq_handler,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ mca_tamper[iface]->name,
+ iiod);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Requested TAMPER %d IRQ (%d).\n",
+ iface, mca_tamper[iface]->irq);
+ continue;
+ }
+ }
+
+ ret = iio_device_register(iiod);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to register mca tamper iio device\n");
+ continue;
+ }
+
+ dev_info(&pdev->dev, "Tamper %d enabled\n", iface);
+ }
+
+ return 0;
+
+exit_error:
+ for (iface = 0; iface < num_tamper_ifaces; iface++) {
+ if (mca_tamper[iface]) {
+ if (mca_tamper[iface]->iio)
+ kfree(mca_tamper[iface]->iio->channels);
+ kfree(mca_tamper[iface]->iio);
+ }
+ }
+ kfree(mca_tamper);
+
+ return ret;
+}
+
+static int mca_tamper_remove(struct platform_device *pdev)
+{
+ struct mca_tamper **mca_tamper = dev_get_drvdata(pdev->dev.parent);
+ struct mca_drv *mca;
+ const struct mca_tamper_data *devdata = of_device_get_match_data(&pdev->dev);
+ u16 num_tamper_ifaces = devdata->num_tamper_ifaces;
+ u32 iface;
+
+ for (iface = 0; iface < num_tamper_ifaces; iface++) {
+ if (mca_tamper[iface] == NULL)
+ continue;
+ /* Release the resources allocated */
+ mca = mca_tamper[iface]->mca;
+ if (mca->gpio_base >= 0) {
+ devm_gpio_free(&pdev->dev,
+ mca->gpio_base + mca_tamper[iface]->io_in);
+ if (mca_tamper[iface]->config0 & MCA_TAMPER_OUT_EN)
+ devm_gpio_free(&pdev->dev,
+ mca->gpio_base + mca_tamper[iface]->io_out);
+ }
+ devm_kfree(&pdev->dev, (void *)mca_tamper[iface]->iio->channels);
+ if (mca_tamper[iface]->irq)
+ devm_free_irq(&pdev->dev, mca_tamper[iface]->irq,
+ mca_tamper[iface]->iio);
+ iio_device_unregister(mca_tamper[iface]->iio);
+ devm_iio_device_free(&pdev->dev, mca_tamper[iface]->iio);
+ }
+ kfree(mca_tamper);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static struct mca_tamper_data mca_tamper_devdata[] = {
+ [CC6UL_MCA_TAMPER] = {
+ .devtype = CC6UL_MCA_TAMPER,
+ .num_tamper_ifaces = 4,
+ .digital_tamper_cnt = 2
+ },
+ [CC8X_MCA_TAMPER] = {
+ .devtype = CC8X_MCA_TAMPER,
+ .num_tamper_ifaces = 4,
+ .digital_tamper_cnt = 2
+ },
+};
+
+static const struct of_device_id mca_tamper_ids[] = {
+ { .compatible = "digi,mca-cc6ul-tamper",
+ .data = &mca_tamper_devdata[CC6UL_MCA_TAMPER]},
+ { .compatible = "digi,mca-cc8x-tamper",
+ .data = &mca_tamper_devdata[CC8X_MCA_TAMPER]},
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mca_tamper_ids);
+#endif
+
+static struct platform_driver mca_tamper_driver = {
+ .probe = mca_tamper_probe,
+ .remove = mca_tamper_remove,
+ .driver = {
+ .name = MCA_DRVNAME_TAMPER,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(mca_tamper_ids),
+ },
+};
+
+static int __init mca_tamper_init(void)
+{
+ return platform_driver_register(&mca_tamper_driver);
+}
+module_init(mca_tamper_init);
+
+static void __exit mca_tamper_exit(void)
+{
+ platform_driver_unregister(&mca_tamper_driver);
+}
+module_exit(mca_tamper_exit);
+
+MODULE_AUTHOR("Digi International Inc");
+MODULE_DESCRIPTION("Tamper driver for MCA of ConnectCore Modules");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" MCA_DRVNAME_TAMPER);

View File

@ -0,0 +1,540 @@
From 33fb650af68bcc05f59181ae7a4f8424a0949f91 Mon Sep 17 00:00:00 2001
From: Alex Gonzalez <alex.gonzalez@digi.com>
Date: Mon, 23 Apr 2018 11:44:37 +0200
Subject: [PATCH] imx6ul: Add RTC MCA support for ConnectCore 6UL SOM
Synched with v4.14.78/master at:
3f8b03950b323db4ca89b1cdc1c2288f79facaa3
Signed-off-by: Alex Gonzalez <alex.gonzalez@digi.com>
---
arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi | 4 +
arch/arm/configs/imx_v6_v7_defconfig | 1 +
drivers/rtc/Kconfig | 12 +
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-mca.c | 454 ++++++++++++++++++++++++++++++
5 files changed, 472 insertions(+)
create mode 100644 drivers/rtc/rtc-mca.c
diff --git a/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi b/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi
index c721320a4117..8163533c83b0 100644
--- a/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi
+++ b/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi
@@ -69,6 +69,10 @@
#interrupt-cells = <2>;
};
+ rtc {
+ compatible = "digi,mca-cc6ul-rtc";
+ };
+
watchdog {
compatible = "digi,mca-cc6ul-wdt";
digi,full-reset;
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 0a07b13ce593..8a763ab6a365 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -370,6 +370,7 @@ CONFIG_RTC_DRV_PCF8523=y
CONFIG_RTC_DRV_PCF8563=y
CONFIG_RTC_DRV_M41T80=y
CONFIG_RTC_DRV_DA9063=y
+CONFIG_RTC_DRV_MCA=y
CONFIG_RTC_DRV_MC13XXX=y
CONFIG_RTC_DRV_MXC=y
CONFIG_RTC_DRV_MXC_V2=y
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index a819ef07b7ec..303c17e8a909 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1106,6 +1106,18 @@ config RTC_DRV_M48T59
This driver can also be built as a module, if so, the module
will be called "rtc-m48t59".
+config RTC_DRV_MCA
+ tristate "Digi ConnectCore SOMs Micro Controller Assist RTC"
+ select MFD_MCA_CC6UL if SOC_IMX6UL
+ select MFD_MCA_CC8X if ARCH_FSL_IMX8QXP
+
+ help
+ If you say Y here you will get support for the RTC in the
+ Micro Controller Assist of Digi ConnectCore system-on-modules.
+
+ This driver can also be built as a module, if so, the module
+ will be called "rtc-mca".
+
config RTC_DRV_MSM6242
tristate "Oki MSM6242"
depends on HAS_IOMEM
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 290c1730fb0a..cd1b13723479 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -98,6 +98,7 @@ obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o
obj-$(CONFIG_RTC_DRV_MAX8997) += rtc-max8997.o
obj-$(CONFIG_RTC_DRV_MAX8998) += rtc-max8998.o
obj-$(CONFIG_RTC_DRV_MC13XXX) += rtc-mc13xxx.o
+obj-$(CONFIG_RTC_DRV_MCA) += rtc-mca.o
obj-$(CONFIG_RTC_DRV_MCP795) += rtc-mcp795.o
obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o
obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o
diff --git a/drivers/rtc/rtc-mca.c b/drivers/rtc/rtc-mca.c
new file mode 100644
index 000000000000..b0e3d17aa995
--- /dev/null
+++ b/drivers/rtc/rtc-mca.c
@@ -0,0 +1,454 @@
+/* rtc-mca.c - Real time clock device driver for MCA on ConnectCore modules
+ * Copyright (C) 2016 - 2018 Digi International
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mfd/mca-common/core.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+
+#define MCA_DRVNAME_RTC "mca-rtc"
+
+#define CLOCK_DATA_LEN (MCA_RTC_COUNT_SEC - MCA_RTC_COUNT_YEAR_L + 1)
+#define ALARM_DATA_LEN (MCA_RTC_ALARM_SEC - MCA_RTC_ALARM_YEAR_L + 1)
+
+#ifdef CONFIG_OF
+enum mca_rtc_type {
+ CC6UL_MCA_RTC,
+ CC8X_MCA_RTC,
+};
+
+struct mca_rtc_data {
+ enum mca_rtc_type devtype;
+};
+#endif
+
+struct mca_rtc {
+ struct rtc_device *rtc_dev;
+ struct mca_drv *mca;
+ int irq_alarm;
+ bool alarm_enabled;
+};
+
+enum {
+ DATA_YEAR_L,
+ DATA_YEAR_H,
+ DATA_MONTH,
+ DATA_DAY,
+ DATA_HOUR,
+ DATA_MIN,
+ DATA_SEC,
+};
+
+static void mca_data_to_tm(u8 *data, struct rtc_time *tm)
+{
+ /* conversion from MCA RTC to struct time is month-1 and year-1900 */
+ tm->tm_year = (((data[DATA_YEAR_H] &
+ MCA_RTC_YEAR_H_MASK) << 8) |
+ (data[DATA_YEAR_L] & MCA_RTC_YEAR_L_MASK)) -
+ 1900;
+ tm->tm_mon = (data[DATA_MONTH] & MCA_RTC_MONTH_MASK) - 1;
+ tm->tm_mday = (data[DATA_DAY] & MCA_RTC_DAY_MASK);
+ tm->tm_hour = (data[DATA_HOUR] & MCA_RTC_HOUR_MASK);
+ tm->tm_min = (data[DATA_MIN] & MCA_RTC_MIN_MASK);
+ tm->tm_sec = (data[DATA_SEC] & MCA_RTC_SEC_MASK);
+}
+
+static void mca_tm_to_data(struct rtc_time *tm, u8 *data)
+{
+ /* conversion from struct time to MCA RTC is year+1900 */
+ data[DATA_YEAR_L] &= (u8)~MCA_RTC_YEAR_L_MASK;
+ data[DATA_YEAR_H] &= (u8)~MCA_RTC_YEAR_H_MASK;
+ data[DATA_YEAR_L] |= (tm->tm_year + 1900) &
+ MCA_RTC_YEAR_L_MASK;
+ data[DATA_YEAR_H] |= ((tm->tm_year + 1900) >> 8) &
+ MCA_RTC_YEAR_H_MASK;
+
+ /* conversion from struct time to MCA RTC is month+1 */
+ data[DATA_MONTH] &= ~MCA_RTC_MONTH_MASK;
+ data[DATA_MONTH] |= (tm->tm_mon + 1) & MCA_RTC_MONTH_MASK;
+
+ data[DATA_DAY] &= ~MCA_RTC_DAY_MASK;
+ data[DATA_DAY] |= tm->tm_mday & MCA_RTC_DAY_MASK;
+
+ data[DATA_HOUR] &= ~MCA_RTC_HOUR_MASK;
+ data[DATA_HOUR] |= tm->tm_hour & MCA_RTC_HOUR_MASK;
+
+ data[DATA_MIN] &= ~MCA_RTC_MIN_MASK;
+ data[DATA_MIN] |= tm->tm_min & MCA_RTC_MIN_MASK;
+
+ data[DATA_SEC] &= ~MCA_RTC_SEC_MASK;
+ data[DATA_SEC] |= tm->tm_sec & MCA_RTC_SEC_MASK;
+}
+
+static int mca_rtc_stop_alarm(struct device *dev)
+{
+ struct mca_rtc *rtc = dev_get_drvdata(dev);
+
+ return regmap_update_bits(rtc->mca->regmap, MCA_RTC_CONTROL,
+ MCA_RTC_ALARM_EN, 0);
+}
+
+static int mca_rtc_start_alarm(struct device *dev)
+{
+ struct mca_rtc *rtc = dev_get_drvdata(dev);
+
+ return regmap_update_bits(rtc->mca->regmap, MCA_RTC_CONTROL,
+ MCA_RTC_ALARM_EN,
+ MCA_RTC_ALARM_EN);
+}
+
+static int mca_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct mca_rtc *rtc = dev_get_drvdata(dev);
+ u8 data[CLOCK_DATA_LEN] = { [0 ... (CLOCK_DATA_LEN - 1)] = 0 };
+ int ret;
+
+ ret = regmap_bulk_read(rtc->mca->regmap, MCA_RTC_COUNT_YEAR_L,
+ data, CLOCK_DATA_LEN);
+ if (ret < 0) {
+ dev_err(dev, "Failed to read RTC time data: %d\n", ret);
+ return ret;
+ }
+
+ mca_data_to_tm(data, tm);
+ return rtc_valid_tm(tm);
+}
+
+static int mca_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct mca_rtc *rtc = dev_get_drvdata(dev);
+ u8 data[CLOCK_DATA_LEN] = { [0 ... (CLOCK_DATA_LEN - 1)] = 0 };
+ int ret;
+
+ mca_tm_to_data(tm, data);
+
+ ret = regmap_bulk_write(rtc->mca->regmap, MCA_RTC_COUNT_YEAR_L,
+ data, CLOCK_DATA_LEN);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set RTC time data: %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+/*
+ * The MCA RTC alarm expires (triggers the irq) when the RTC time matches the
+ * value programmed in the alarm register and the RTC counter increments.
+ * This means, one second after the programmed value. To correct this, the
+ * alarm value is adjusted when it is being written/read, decrementing/incremen-
+ * ting the value by 1 second.
+ */
+static void mca_rtc_adjust_alarm_time(struct rtc_wkalrm *alrm, bool inc)
+{
+ unsigned long time;
+
+ rtc_tm_to_time(&alrm->time, &time);
+ time = inc ? time + 1 : time - 1;
+ rtc_time_to_tm(time, &alrm->time);
+}
+
+static int mca_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct mca_rtc *rtc = dev_get_drvdata(dev);
+ u8 data[CLOCK_DATA_LEN] = { [0 ... (CLOCK_DATA_LEN - 1)] = 0 };
+ int ret;
+ unsigned int val;
+
+ ret = regmap_bulk_read(rtc->mca->regmap, MCA_RTC_ALARM_YEAR_L,
+ data, ALARM_DATA_LEN);
+ if (ret < 0)
+ return ret;
+
+ mca_data_to_tm(data, &alrm->time);
+ mca_rtc_adjust_alarm_time(alrm, true);
+
+ /* Enable status */
+ ret = regmap_read(rtc->mca->regmap, MCA_RTC_CONTROL, &val);
+ if (ret < 0)
+ return ret;
+
+ /* Pending status */
+ ret = regmap_read(rtc->mca->regmap, MCA_IRQ_STATUS_0, &val);
+ if (ret < 0)
+ return ret;
+ alrm->pending = (val & MCA_RTC_ALARM) ? 1 : 0;
+
+ return 0;
+}
+
+static int mca_rtc_alarm_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ struct mca_rtc *rtc = dev_get_drvdata(dev);
+ int ret;
+
+ if (enabled) {
+ ret = mca_rtc_start_alarm(dev);
+ if (ret != 0) {
+ dev_err(dev, "Failed to enable alarm IRQ (%d)\n", ret);
+ goto exit_alarm_irq;
+ }
+ rtc->alarm_enabled = 1;
+ } else {
+ ret = mca_rtc_stop_alarm(dev);
+ if (ret != 0) {
+ dev_err(dev, "Failed to disable alarm IRQ (%d)\n", ret);
+ goto exit_alarm_irq;
+ }
+ rtc->alarm_enabled = 0;
+ }
+
+exit_alarm_irq:
+ return ret;
+}
+
+static int mca_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct mca_rtc *rtc = dev_get_drvdata(dev);
+ u8 data[CLOCK_DATA_LEN] = { [0 ... (CLOCK_DATA_LEN - 1)] = 0 };
+ int ret;
+
+ mca_rtc_adjust_alarm_time(alrm, false);
+ mca_tm_to_data(&alrm->time, data);
+
+ ret = regmap_bulk_write(rtc->mca->regmap, MCA_RTC_ALARM_YEAR_L,
+ data, ALARM_DATA_LEN);
+ if (ret < 0)
+ return ret;
+
+ return mca_rtc_alarm_irq_enable(dev, alrm->enabled);
+}
+
+static irqreturn_t mca_alarm_event(int irq, void *data)
+{
+ struct mca_rtc *rtc = data;
+
+ rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
+
+ return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops mca_rtc_ops = {
+ .read_time = mca_rtc_read_time,
+ .set_time = mca_rtc_set_time,
+ .read_alarm = mca_rtc_read_alarm,
+ .set_alarm = mca_rtc_set_alarm,
+ .alarm_irq_enable = mca_rtc_alarm_irq_enable,
+};
+
+static int mca_rtc_probe(struct platform_device *pdev)
+{
+ struct mca_drv *mca = dev_get_drvdata(pdev->dev.parent);
+ struct mca_rtc *rtc;
+ const struct mca_rtc_data *devdata =
+ of_device_get_match_data(&pdev->dev);
+ struct device_node *np = NULL;
+ int ret = 0;
+
+ if (!mca || !mca->dev->parent->of_node)
+ return -EPROBE_DEFER;
+
+ rtc = devm_kzalloc(&pdev->dev, sizeof *rtc, GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, rtc);
+ device_init_wakeup(&pdev->dev, 1);
+ rtc->mca = mca;
+
+ /* Find entry in device-tree */
+ if (mca->dev->of_node) {
+ const char * compatible = pdev->dev.driver->
+ of_match_table[devdata->devtype].compatible;
+
+ /*
+ * Return silently if RTC node does not exist
+ * or if it is disabled
+ */
+ np = of_find_compatible_node(mca->dev->of_node, NULL, compatible);
+ if (!np) {
+ ret = -ENODEV;
+ goto err;
+ }
+ if (!of_device_is_available(np)) {
+ ret = -ENODEV;
+ goto err;
+ }
+ }
+
+ /* Enable RTC hardware */
+ ret = regmap_update_bits(mca->regmap, MCA_RTC_CONTROL,
+ MCA_RTC_EN, MCA_RTC_EN);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to enable RTC.\n");
+ goto err;
+ }
+
+ /* Register RTC device */
+ rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
+
+ if (IS_ERR(rtc->rtc_dev)) {
+ dev_err(&pdev->dev, "Failed to allocate RTC device: %ld\n",
+ PTR_ERR(rtc->rtc_dev));
+ ret = PTR_ERR(rtc->rtc_dev);
+ goto err;
+ }
+
+ rtc->rtc_dev->ops = &mca_rtc_ops;
+ ret = rtc_register_device(rtc->rtc_dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to register RTC device.\n");
+ goto err;
+ }
+
+
+ /*
+ * Register interrupts. Complain on errors but let device
+ * to be registered at least for date/time.
+ */
+ rtc->irq_alarm = platform_get_irq_byname(pdev,
+ MCA_IRQ_RTC_ALARM_NAME);
+ ret = devm_request_threaded_irq(&pdev->dev, rtc->irq_alarm, NULL,
+ mca_alarm_event,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ MCA_IRQ_RTC_ALARM_NAME, rtc);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request %s IRQ. (%d)\n",
+ MCA_IRQ_RTC_ALARM_NAME, rtc->irq_alarm);
+ rtc->irq_alarm = -ENXIO;
+ }
+
+ return 0;
+
+err:
+ rtc = NULL;
+ return ret;
+}
+
+static int mca_rtc_remove(struct platform_device *pdev)
+{
+ struct mca_rtc *rtc = platform_get_drvdata(pdev);
+
+ if (rtc->irq_alarm >= 0)
+ devm_free_irq(&pdev->dev, rtc->irq_alarm, rtc);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int mca_rtc_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct mca_rtc *rtc = platform_get_drvdata(pdev);
+ int ret;
+
+ if (!device_may_wakeup(&pdev->dev) && rtc->alarm_enabled) {
+ /* Disable the alarm irq to avoid unwanted wakeups */
+ ret = mca_rtc_stop_alarm(&pdev->dev);
+ if (ret < 0)
+ dev_err(&pdev->dev, "Failed to disable RTC Alarm\n");
+ }
+
+ return 0;
+}
+
+static int mca_rtc_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct mca_rtc *rtc = platform_get_drvdata(pdev);
+ int ret;
+
+ if (!device_may_wakeup(&pdev->dev) && rtc->alarm_enabled) {
+ /* Enable the alarm irq, just in case it was disabled suspending */
+ ret = mca_rtc_start_alarm(&pdev->dev);
+ if (ret < 0)
+ dev_err(&pdev->dev, "Failed to restart RTC Alarm\n");
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops mca_rtc_pm_ops = {
+ .suspend = mca_rtc_suspend,
+ .resume = mca_rtc_resume,
+ .poweroff = mca_rtc_suspend,
+};
+#endif
+
+#ifdef CONFIG_OF
+static struct mca_rtc_data mca_rtc_devdata[] = {
+ [CC6UL_MCA_RTC] = {
+ .devtype = CC6UL_MCA_RTC,
+ },
+ [CC8X_MCA_RTC] = {
+ .devtype = CC8X_MCA_RTC,
+ },
+};
+
+static const struct of_device_id mca_rtc_dt_ids[] = {
+ { .compatible = "digi,mca-cc6ul-rtc",
+ .data = &mca_rtc_devdata[CC6UL_MCA_RTC]},
+ { .compatible = "digi,mca-cc8x-rtc",
+ .data = &mca_rtc_devdata[CC8X_MCA_RTC]},
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mca_rtc_dt_ids);
+#endif
+
+static struct platform_driver mca_rtc_driver = {
+ .probe = mca_rtc_probe,
+ .remove = mca_rtc_remove,
+ .driver = {
+ .name = MCA_DRVNAME_RTC,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &mca_rtc_pm_ops,
+#endif
+#ifdef CONFIG_OF
+ .of_match_table = mca_rtc_dt_ids,
+#endif
+ },
+};
+
+static int __init mca_rtc_init(void)
+{
+ return platform_driver_register(&mca_rtc_driver);
+}
+module_init(mca_rtc_init);
+
+static void __exit mca_rtc_exit(void)
+{
+ platform_driver_unregister(&mca_rtc_driver);
+}
+module_exit(mca_rtc_exit);
+
+/* Module information */
+MODULE_AUTHOR("Digi International Inc.");
+MODULE_DESCRIPTION("Real time clock device driver for MCA of ConnectCore Modules");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" MCA_DRVNAME_RTC);

View File

@ -0,0 +1,490 @@
From 052464d671eb993264a78b3e35170c1d9fd44268 Mon Sep 17 00:00:00 2001
From: Alex Gonzalez <alex.gonzalez@digi.com>
Date: Mon, 23 Apr 2018 11:45:16 +0200
Subject: [PATCH] imx6ul: Add MCA power key support for ConnectCore 6UL SOM
Synched with v4.14.78/master at:
3f8b03950b323db4ca89b1cdc1c2288f79facaa3
Signed-off-by: Alex Gonzalez <alex.gonzalez@digi.com>
---
arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi | 9 +
arch/arm/configs/imx_v6_v7_defconfig | 1 +
drivers/input/misc/Kconfig | 12 +
drivers/input/misc/Makefile | 1 +
drivers/input/misc/pwrkey-mca.c | 401 ++++++++++++++++++++++++++++++
5 files changed, 424 insertions(+)
create mode 100644 drivers/input/misc/pwrkey-mca.c
diff --git a/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi b/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi
index 8163533c83b0..f2a17f9b88d1 100644
--- a/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi
+++ b/arch/arm/boot/dts/imx6ul-ccimx6ulsom.dtsi
@@ -78,6 +78,15 @@
digi,full-reset;
};
+ pwrkey {
+ compatible = "digi,mca-cc6ul-pwrkey";
+ digi,key-power;
+ digi,key-sleep;
+ digi,debounce-ms = <100>;
+ digi,pwroff-delay-sec = <6>;
+ digi,pwroff-guard-sec = <30>;
+ };
+
mca_adc: adc {
compatible = "digi,mca-cc6ul-adc";
digi,adc-vref = <3000000>;
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 8a763ab6a365..31d02719c51e 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -186,6 +186,7 @@ CONFIG_TOUCHSCREEN_SX8654=y
CONFIG_TOUCHSCREEN_COLIBRI_VF50=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_MMA8450=y
+CONFIG_INPUT_MCA_PWRKEY=y
CONFIG_SERIO_SERPORT=m
# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_IMX=y
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index ca59a2be9bc5..cef9795466f7 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -851,4 +851,16 @@ config INPUT_SC27XX_VIBRA
To compile this driver as a module, choose M here. The module will
be called sc27xx_vibra.
+config INPUT_MCA_PWRKEY
+ tristate "Digi ConnectCore SOMs Micro Controller Assist Power key"
+ select MFD_MCA_CC6UL if SOC_IMX6UL
+ select MFD_MCA_CC8X if ARCH_FSL_IMX8QXP
+ help
+ If you say Y here you will get support for the Power Key in the
+ Micro Controller Assist of Digi ConnectCore system-on-modules,
+ as an input device, reporting the power input/button status.
+
+ This driver can also be built as a module, if so, the module
+ will be called "pwrkey-mca".
+
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 9d0f9d1ff68f..1ed17d1b0c68 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o
obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o
obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o
obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o
+obj-$(CONFIG_INPUT_MCA_PWRKEY) += pwrkey-mca.o
obj-$(CONFIG_INPUT_MMA8450) += mma8450.o
obj-$(CONFIG_INPUT_PALMAS_PWRBUTTON) += palmas-pwrbutton.o
obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o
diff --git a/drivers/input/misc/pwrkey-mca.c b/drivers/input/misc/pwrkey-mca.c
new file mode 100644
index 000000000000..ddb83ef77045
--- /dev/null
+++ b/drivers/input/misc/pwrkey-mca.c
@@ -0,0 +1,401 @@
+/* pwrkey-mca.c - Power Key device driver for MCA on ConnectCore modules
+ * Copyright (C) 2016 - 2018 Digi International Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/mfd/mca-common/core.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+
+#define MCA_DRVNAME_PWRKEY "mca-pwrkey"
+
+#define DEFAULT_PWR_KEY_DEBOUNCE 150 /* 150 ms */
+#define DEFAULT_PWR_KEY_DELAY 4 /* 4 seconds */
+#define DEFAULT_PWR_KEY_GUARD 25 /* 25 seconds */
+#define MAX_PWR_KEY_DEBOUNCE 255
+#define MAX_PWR_KEY_DELAY 255
+#define MAX_PWR_KEY_GUARD 255
+
+#ifdef CONFIG_OF
+enum mca_pwrkey_type {
+ CC6UL_MCA_PWRKEY,
+ CC8X_MCA_PWRKEY,
+};
+
+struct mca_pwrkey_data {
+ enum mca_pwrkey_type devtype;
+ char drv_name_phys[40];
+};
+#endif
+
+struct mca_pwrkey {
+ struct mca_drv *mca;
+ struct input_dev *input;
+ int irq_power;
+ int irq_sleep;
+ bool key_power;
+ bool key_sleep;
+ bool suspended;
+ uint32_t debounce_ms;
+ uint32_t pwroff_delay_sec;
+ uint32_t pwroff_guard_sec;
+};
+
+#ifdef CONFIG_PM_SLEEP
+static DEFINE_SPINLOCK(lock);
+#endif
+
+static irqreturn_t mca_pwrkey_power_off_irq_handler(int irq, void *data)
+{
+ struct mca_pwrkey *pwrkey = data;
+
+ dev_notice(&pwrkey->input->dev, "Power Button - KEY_POWER\n");
+
+ input_report_key(pwrkey->input, KEY_POWER, 1);
+ input_sync(pwrkey->input);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mca_pwrkey_sleep_irq_handler(int irq, void *data)
+{
+ struct mca_pwrkey *pwrkey = data;
+
+ /* Report the event only if not coming from suspend */
+ if (!pwrkey->suspended) {
+ dev_notice(&pwrkey->input->dev, "Power button - KEY_SLEEP\n");
+
+ input_report_key(pwrkey->input, KEY_SLEEP, 1);
+ input_report_key(pwrkey->input, KEY_SLEEP, 0);
+ input_sync(pwrkey->input);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int mca_pwrkey_initialize(struct mca_pwrkey *pwrkey)
+{
+ int ret;
+ uint8_t pwrctrl0 = 0;
+
+ ret = regmap_write(pwrkey->mca->regmap, MCA_PWR_KEY_DEBOUNCE,
+ (uint8_t)pwrkey->debounce_ms);
+ if (ret < 0) {
+ dev_err(pwrkey->mca->dev,
+ "Failed to set debounce time 0x%02x, %d\n",
+ (uint8_t)pwrkey->debounce_ms, ret);
+ return ret;
+ }
+
+ ret = regmap_write(pwrkey->mca->regmap, MCA_PWR_KEY_DELAY,
+ (uint8_t)pwrkey->pwroff_delay_sec);
+ if (ret < 0) {
+ dev_err(pwrkey->mca->dev,
+ "Failed to set delay time 0x%02x, %d\n",
+ (uint8_t)pwrkey->pwroff_delay_sec, ret);
+ return ret;
+ }
+
+ ret = regmap_write(pwrkey->mca->regmap, MCA_PWR_KEY_GUARD,
+ (uint8_t)pwrkey->pwroff_guard_sec);
+ if (ret < 0) {
+ dev_err(pwrkey->mca->dev,
+ "Failed to set guard time 0x%02x, %d\n",
+ (uint8_t)pwrkey->pwroff_guard_sec, ret);
+ return ret;
+ }
+
+ if (pwrkey->key_power)
+ pwrctrl0 |= MCA_PWR_KEY_OFF_EN;
+
+ if (pwrkey->key_sleep)
+ pwrctrl0 |= MCA_PWR_KEY_SLEEP_EN;
+
+ if (pwrkey->pwroff_guard_sec != 0)
+ pwrctrl0 |= MCA_PWR_GUARD_EN;
+
+ ret = regmap_write(pwrkey->mca->regmap, MCA_PWR_CTRL_0, pwrctrl0);
+ if (ret < 0) {
+ dev_err(pwrkey->mca->dev,
+ "Failed to set PWR_CTRL_0 0x%02x, %d\n",
+ pwrctrl0, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int of_mca_pwrkey_read_settings(struct device_node *np,
+ struct mca_pwrkey *pwrkey)
+{
+ uint32_t val;
+
+ /* Get driver configuration data from device tree */
+ pwrkey->debounce_ms = DEFAULT_PWR_KEY_DEBOUNCE;
+ pwrkey->pwroff_delay_sec = DEFAULT_PWR_KEY_DEBOUNCE;
+ pwrkey->pwroff_guard_sec = DEFAULT_PWR_KEY_GUARD;
+
+ pwrkey->key_power = of_property_read_bool(np, "digi,key-power");
+ pwrkey->key_sleep = of_property_read_bool(np, "digi,key-sleep");
+
+ if (!of_property_read_u32(np, "digi,debounce-ms", &val)) {
+ if (val <= MAX_PWR_KEY_DEBOUNCE)
+ pwrkey->debounce_ms = val;
+ else
+ dev_warn(pwrkey->mca->dev,
+ "Invalid debounce-ms value. Using default.\n");
+ }
+
+ if (!of_property_read_u32(np, "digi,pwroff-delay-sec", &val)) {
+ if (val <= MAX_PWR_KEY_DELAY)
+ pwrkey->pwroff_delay_sec = val;
+ else
+ dev_warn(pwrkey->mca->dev,
+ "Invalid pwroff-delay-sec value. Using default.\n");
+ }
+
+ if (!of_property_read_u32(np, "digi,pwroff-guard-sec", &val)) {
+ if (val <= MAX_PWR_KEY_GUARD)
+ pwrkey->pwroff_guard_sec = val;
+ else
+ dev_warn(pwrkey->mca->dev,
+ "Invalid pwroff-guard-sec value. Using default.\n");
+ }
+
+ return 0;
+}
+
+static int mca_pwrkey_probe(struct platform_device *pdev)
+{
+ struct mca_drv *mca = dev_get_drvdata(pdev->dev.parent);
+ struct mca_pwrkey *pwrkey;
+ const struct mca_pwrkey_data *devdata =
+ of_device_get_match_data(&pdev->dev);
+ struct device_node *np = NULL;
+ int ret = 0;
+
+ if (!mca || !mca->dev || !mca->dev->parent ||
+ !mca->dev->parent->of_node)
+ return -EPROBE_DEFER;
+
+ /* Find entry in device-tree */
+ if (mca->dev->of_node) {
+ const char * compatible = pdev->dev.driver->
+ of_match_table[devdata->devtype].compatible;
+
+ /* Return if pwrkey node does not exist or if it is disabled */
+ np = of_find_compatible_node(mca->dev->of_node, NULL, compatible);
+ if (!np || !of_device_is_available(np))
+ return -ENODEV;
+ }
+
+ pwrkey = devm_kzalloc(&pdev->dev, sizeof(struct mca_pwrkey),
+ GFP_KERNEL);
+ if (!pwrkey) {
+ dev_err(&pdev->dev, "Failed to allocate memory.\n");
+ return -ENOMEM;
+ }
+
+ pwrkey->input = input_allocate_device();
+ if (!pwrkey->input) {
+ dev_err(&pdev->dev, "Failed to allocated input device.\n");
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ platform_set_drvdata(pdev, pwrkey);
+ pwrkey->mca = mca;
+ pwrkey->irq_power = platform_get_irq_byname(pdev,
+ MCA_IRQ_PWR_OFF_NAME);
+ pwrkey->irq_sleep = platform_get_irq_byname(pdev,
+ MCA_IRQ_PWR_SLEEP_NAME);
+ pwrkey->input->name = dev_name(&pdev->dev);
+ pwrkey->input->phys = devdata->drv_name_phys;
+ pwrkey->input->dev.parent = &pdev->dev;
+
+ input_set_capability(pwrkey->input, EV_KEY, KEY_POWER);
+ input_set_capability(pwrkey->input, EV_KEY, KEY_SLEEP);
+
+ /* Initialize driver settings from device tree */
+ ret = of_mca_pwrkey_read_settings(np, pwrkey);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to get %s dtb settings\n",
+ dev_name(&pdev->dev));
+ goto err_free_inputdev;
+ }
+
+ ret = mca_pwrkey_initialize(pwrkey);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to initilize pwrkey registers\n");
+ goto err_free_inputdev;
+ }
+
+ if (pwrkey->key_power) {
+ ret = devm_request_threaded_irq(&pdev->dev, pwrkey->irq_power, NULL,
+ mca_pwrkey_power_off_irq_handler,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ MCA_IRQ_PWR_OFF_NAME, pwrkey);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request %s IRQ (%d).\n",
+ MCA_IRQ_PWR_OFF_NAME, pwrkey->irq_power);
+ goto err_free_inputdev;
+ }
+ }
+
+ if (pwrkey->key_sleep) {
+ ret = devm_request_threaded_irq(&pdev->dev, pwrkey->irq_sleep, NULL,
+ mca_pwrkey_sleep_irq_handler,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ MCA_IRQ_PWR_SLEEP_NAME, pwrkey);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request %s IRQ (%d).\n",
+ MCA_IRQ_PWR_SLEEP_NAME, pwrkey->irq_sleep);
+ goto err_irq1;
+ }
+ enable_irq_wake(pwrkey->irq_sleep);
+ }
+
+ ret = input_register_device(pwrkey->input);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register input device (%d).\n",
+ ret);
+ goto err_irq2;
+ }
+
+ return 0;
+
+err_irq2:
+ if (pwrkey->key_sleep)
+ free_irq(pwrkey->mca->irq_base + pwrkey->irq_sleep, pwrkey);
+err_irq1:
+ if (pwrkey->key_power)
+ free_irq(pwrkey->mca->irq_base + pwrkey->irq_power, pwrkey);
+err_free_inputdev:
+ input_free_device(pwrkey->input);
+err_free:
+ kfree(pwrkey);
+
+ return ret;
+}
+
+static int mca_pwrkey_remove(struct platform_device *pdev)
+{
+ struct mca_pwrkey *pwrkey = platform_get_drvdata(pdev);
+
+ if (pwrkey->key_power)
+ free_irq(pwrkey->irq_power, pwrkey);
+ if (pwrkey->key_sleep)
+ free_irq(pwrkey->irq_sleep, pwrkey);
+ input_unregister_device(pwrkey->input);
+ kfree(pwrkey);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int __maybe_unused mca_pwrkey_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct mca_pwrkey *pwrkey = platform_get_drvdata(pdev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&lock, flags);
+ pwrkey->suspended = false;
+ spin_unlock_irqrestore(&lock, flags);
+
+ return 0;
+}
+
+static int __maybe_unused mca_pwrkey_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct mca_pwrkey *pwrkey = platform_get_drvdata(pdev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&lock, flags);
+ pwrkey->suspended = true;
+ spin_unlock_irqrestore(&lock, flags);
+
+ return 0;
+}
+
+SIMPLE_DEV_PM_OPS(mca_pwrkey_pm_ops, mca_pwrkey_suspend, mca_pwrkey_resume);
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_OF
+static struct mca_pwrkey_data mca_pwrkey_devdata[] = {
+ [CC6UL_MCA_PWRKEY] = {
+ .devtype = CC6UL_MCA_PWRKEY,
+ .drv_name_phys= "mca-cc6ul-pwrkey/input0"
+ },
+ [CC8X_MCA_PWRKEY] = {
+ .devtype = CC8X_MCA_PWRKEY,
+ .drv_name_phys= "mca-cc8x-pwrkey/input0"
+ },
+};
+
+static const struct of_device_id mca_pwrkey_ids[] = {
+ { .compatible = "digi,mca-cc6ul-pwrkey",
+ .data = &mca_pwrkey_devdata[CC6UL_MCA_PWRKEY]},
+ { .compatible = "digi,mca-cc8x-pwrkey",
+ .data = &mca_pwrkey_devdata[CC8X_MCA_PWRKEY]},
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mca_pwrkey_ids);
+#endif
+
+static struct platform_driver mca_pwrkey_driver = {
+ .probe = mca_pwrkey_probe,
+ .remove = mca_pwrkey_remove,
+ .driver = {
+ .name = MCA_DRVNAME_PWRKEY,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(mca_pwrkey_ids),
+#ifdef CONFIG_PM_SLEEP
+ .pm = &mca_pwrkey_pm_ops,
+#endif
+ },
+};
+
+static int __init mca_pwrkey_init(void)
+{
+ return platform_driver_register(&mca_pwrkey_driver);
+}
+module_init(mca_pwrkey_init);
+
+static void __exit mca_pwrkey_exit(void)
+{
+ platform_driver_unregister(&mca_pwrkey_driver);
+}
+module_exit(mca_pwrkey_exit);
+
+MODULE_AUTHOR("Digi International Inc");
+MODULE_DESCRIPTION("pwrkey device driver for MCA of ConnectCore Modules");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" MCA_DRVNAME_PWRKEY);

View File

@ -0,0 +1,892 @@
From f56dbb1e8b6a501e84d69ac5f18ec7a66cb4faa7 Mon Sep 17 00:00:00 2001
From: Alex Gonzalez <alex.gonzalez@digi.com>
Date: Mon, 23 Apr 2018 11:46:52 +0200
Subject: [PATCH] ccimx6ulsbcpro: Add IOEXP core I2C support
Synched with v4.14.78/master at:
3f8b03950b323db4ca89b1cdc1c2288f79facaa3
Signed-off-by: Alex Gonzalez <alex.gonzalez@digi.com>
---
arch/arm/configs/imx_v6_v7_defconfig | 1 +
drivers/mfd/Kconfig | 10 +
drivers/mfd/Makefile | 4 +-
drivers/mfd/mca-ioexp-core.c | 415 ++++++++++++++++++++++++++++++++
drivers/mfd/mca-ioexp-i2c.c | 186 ++++++++++++++
drivers/mfd/mca-ioexp-irq.c | 89 +++++++
include/linux/mfd/mca-ioexp/core.h | 87 +++++++
include/linux/mfd/mca-ioexp/registers.h | 15 ++
8 files changed, 805 insertions(+), 2 deletions(-)
create mode 100644 drivers/mfd/mca-ioexp-core.c
create mode 100644 drivers/mfd/mca-ioexp-i2c.c
create mode 100644 drivers/mfd/mca-ioexp-irq.c
create mode 100644 include/linux/mfd/mca-ioexp/core.h
create mode 100644 include/linux/mfd/mca-ioexp/registers.h
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index ed31623082ac..a269983e3cba 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -242,6 +242,7 @@ CONFIG_MFD_DA9063=y
CONFIG_MFD_MC13XXX_SPI=y
CONFIG_MFD_MC13XXX_I2C=y
CONFIG_MFD_RN5T618=y
+CONFIG_MFD_MCA_IOEXP=y
CONFIG_MFD_STMPE=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 42c72334d645..5b87d592aece 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -458,6 +458,16 @@ config MFD_MCA_CC8X
Additional drivers must be enabled in order to use the functionality
of the device (RTC, watchdog, ...).
+config MFD_MCA_IOEXP
+ bool "Digi IO Expander"
+ select MFD_CORE
+ select REGMAP_I2C
+ select REGMAP_IRQ
+ depends on I2C=y
+ help
+ Select this option to enable support for the Digi IO Expander.
+ This includes the GPIO and ADC drivers.
+
config MFD_MX25_TSADC
tristate "Freescale i.MX25 integrated Touchscreen and ADC unit"
select REGMAP_MMIO
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 28443313ba92..bfbaaba0d74f 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -249,5 +249,5 @@ obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o
mca-cc6ul-objs := mca-cc6ul-core.o mca-cc6ul-irq.o mca-cc6ul-i2c.o
obj-$(CONFIG_MFD_MCA_CC6UL) += mca-cc6ul.o
-mca-cc8x-objs := mca-cc8x-core.o mca-cc8x-irq.o mca-cc8x-i2c.o
-obj-$(CONFIG_MFD_MCA_CC8X) += mca-cc8x.o
+mca-ioexp-objs := mca-ioexp-core.o mca-ioexp-irq.o mca-ioexp-i2c.o
+obj-$(CONFIG_MFD_MCA_IOEXP) += mca-ioexp.o
diff --git a/drivers/mfd/mca-ioexp-core.c b/drivers/mfd/mca-ioexp-core.c
new file mode 100644
index 000000000000..19b3c7f2b4be
--- /dev/null
+++ b/drivers/mfd/mca-ioexp-core.c
@@ -0,0 +1,415 @@
+/*
+ * Copyright 2017 - 2019 Digi International Inc
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/sysfs.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/suspend.h>
+#include <linux/proc_fs.h>
+#include <linux/kthread.h>
+#include <linux/uaccess.h>
+#include <linux/reboot.h>
+
+#include <linux/mfd/mca-common/core.h>
+#include <linux/mfd/mca-ioexp/core.h>
+
+#include <asm/unaligned.h>
+
+static struct resource mca_ioexp_gpios_resources[] = {
+ {
+ .name = MCA_IRQ_GPIO_BANK_0_NAME,
+ .start = MCA_IOEXP_IRQ_GPIO_BANK_0,
+ .end = MCA_IOEXP_IRQ_GPIO_BANK_0,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = MCA_IRQ_GPIO_BANK_1_NAME,
+ .start = MCA_IOEXP_IRQ_GPIO_BANK_1,
+ .end = MCA_IOEXP_IRQ_GPIO_BANK_1,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = MCA_IRQ_GPIO_BANK_2_NAME,
+ .start = MCA_IOEXP_IRQ_GPIO_BANK_2,
+ .end = MCA_IOEXP_IRQ_GPIO_BANK_2,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = MCA_IRQ_GPIO_BANK_3_NAME,
+ .start = MCA_IOEXP_IRQ_GPIO_BANK_3,
+ .end = MCA_IOEXP_IRQ_GPIO_BANK_3,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = MCA_IRQ_GPIO_BANK_4_NAME,
+ .start = MCA_IOEXP_IRQ_GPIO_BANK_4,
+ .end = MCA_IOEXP_IRQ_GPIO_BANK_4,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = MCA_IRQ_GPIO_BANK_5_NAME,
+ .start = MCA_IOEXP_IRQ_GPIO_BANK_5,
+ .end = MCA_IOEXP_IRQ_GPIO_BANK_5,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static const struct mfd_cell mca_ioexp_devs[] = {
+ {
+ .name = MCA_IOEXP_DRVNAME_GPIO,
+ .num_resources = ARRAY_SIZE(mca_ioexp_gpios_resources),
+ .resources = mca_ioexp_gpios_resources,
+ .of_compatible = "digi,mca-ioexp-gpio",
+ },
+ {
+ .name = MCA_IOEXP_DRVNAME_ADC,
+ .of_compatible = "digi,mca-ioexp-adc",
+ },
+};
+
+static ssize_t hwver_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct mca_ioexp *ioexp = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", ioexp->hw_version);
+}
+static DEVICE_ATTR(hw_version, S_IRUGO, hwver_show, NULL);
+
+static ssize_t fwver_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct mca_ioexp *ioexp = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d.%02d %s\n", MCA_FW_VER_MAJOR(ioexp->fw_version),
+ MCA_FW_VER_MINOR(ioexp->fw_version),
+ ioexp->fw_is_alpha ? "(alpha)" : "");
+}
+static DEVICE_ATTR(fw_version, S_IRUGO, fwver_show, NULL);
+
+static struct attribute *mca_ioexp_sysfs_entries[] = {
+ &dev_attr_hw_version.attr,
+ &dev_attr_fw_version.attr,
+ NULL,
+};
+
+static struct attribute_group mca_ioexp_attr_group = {
+ .name = NULL, /* put in device directory */
+ .attrs = mca_ioexp_sysfs_entries,
+};
+
+static int read_reg_group(struct mca_ioexp *ioexp,
+ unsigned int start_addr,
+ unsigned int count,
+ uint8_t *dest)
+{
+ unsigned int i;
+ unsigned int error;
+
+ if (count == 0 || !dest)
+ return -1;
+
+ for (i = 0; i < count; i++) {
+ const unsigned int reg_addr = start_addr + i;
+ unsigned int value;
+
+ error = regmap_read(ioexp->regmap, reg_addr, &value);
+ if (error) {
+ dev_err(ioexp->dev,
+ "Error reading register %02X (%d)\n",
+ reg_addr, error);
+ return -1;
+ }
+ dest[i] = value;
+ }
+
+ return 0;
+}
+
+int mca_ioexp_suspend(struct device *dev)
+{
+ struct mca_ioexp *ioexp = dev_get_drvdata(dev);
+ int error;
+
+ if (!ioexp->preserved_regs)
+ return 0;
+
+
+ error = read_reg_group(ioexp, MCA_GPIO_DIR_0,
+ ioexp->preserved_regs->gpio_dir.cnt,
+ ioexp->preserved_regs->gpio_dir.values);
+ if (error) {
+ dev_err(ioexp->dev,
+ "Failed to preserve MCA_GPIO_DIR registers.\n");
+ goto exit;
+ }
+
+ error = read_reg_group(ioexp, MCA_GPIO_DATA_0,
+ ioexp->preserved_regs->gpio_data.cnt,
+ ioexp->preserved_regs->gpio_data.values);
+ if (error) {
+ dev_err(ioexp->dev,
+ "Failed to preserve MCA_GPIO_DATA registers.\n");
+ goto exit;
+ }
+
+ error = read_reg_group(ioexp, MCA_GPIO_IRQ_CFG_0,
+ ioexp->preserved_regs->irq_cfg.cnt,
+ ioexp->preserved_regs->irq_cfg.values);
+ if (error) {
+ dev_err(ioexp->dev,
+ "Failed to preserve MCA_GPIO_IRQ_CFG registers.\n");
+ goto exit;
+ }
+
+ error = read_reg_group(ioexp, MCA_IRQ_MASK_0,
+ ioexp->preserved_regs->irq_mask.cnt,
+ ioexp->preserved_regs->irq_mask.values);
+ if (error) {
+ dev_err(ioexp->dev,
+ "Failed to preserve MCA_IRQ_MASK registers.\n");
+ goto exit;
+ }
+
+ error = read_reg_group(ioexp, MCA_REG_ADC_CFG0_0,
+ ioexp->preserved_regs->adc_cfg.cnt,
+ ioexp->preserved_regs->adc_cfg.values);
+ if (error) {
+ dev_err(ioexp->dev,
+ "Failed to preserve MCA_REG_ADC_CFG registers.\n");
+ goto exit;
+ }
+
+ disable_irq(ioexp->chip_irq);
+ return 0;
+
+exit:
+ if (error)
+ dev_err(ioexp->dev, "Configuration will be lost on resume. The IOs in use might need to be reconfigured in order to work properly.\n");
+
+ disable_irq(ioexp->chip_irq);
+
+ /* Do not return errors or the device will not go to sleep. */
+ return 0;
+}
+
+static int write_reg_group(struct mca_ioexp *ioexp,
+ unsigned int start_addr,
+ unsigned int count,
+ uint8_t *values)
+{
+ unsigned int i;
+ unsigned int error;
+
+ if (count == 0 || !values)
+ return -1;
+
+ for (i = 0; i < count; i++) {
+ const unsigned int reg_addr = start_addr + i;
+ const unsigned int value = values[i];
+
+ error = regmap_write(ioexp->regmap, reg_addr, value);
+ if (error) {
+ dev_err(ioexp->dev,
+ "Error writing register %02X (%d)\n",
+ reg_addr, error);
+ }
+ }
+
+ return error;
+}
+
+int mca_ioexp_resume(struct device *dev)
+{
+ struct mca_ioexp *ioexp = dev_get_drvdata(dev);
+ int error;
+
+ if (!ioexp->preserved_regs)
+ return 0;
+
+ error = write_reg_group(ioexp, MCA_GPIO_DIR_0,
+ ioexp->preserved_regs->gpio_dir.cnt,
+ ioexp->preserved_regs->gpio_dir.values);
+ if (error)
+ dev_err(ioexp->dev,
+ "Failed to restore MCA_GPIO_DIR registers.\n");
+
+ error = write_reg_group(ioexp, MCA_GPIO_DATA_0,
+ ioexp->preserved_regs->gpio_data.cnt,
+ ioexp->preserved_regs->gpio_data.values);
+ if (error)
+ dev_err(ioexp->dev,
+ "Failed to restore MCA_GPIO_DATA registers.\n");
+
+ error = write_reg_group(ioexp, MCA_GPIO_IRQ_CFG_0,
+ ioexp->preserved_regs->irq_cfg.cnt,
+ ioexp->preserved_regs->irq_cfg.values);
+ if (error)
+ dev_err(ioexp->dev,
+ "Failed to restore MCA_GPIO_IRQ_CFG registers.\n");
+
+ error = write_reg_group(ioexp, MCA_IRQ_MASK_0,
+ ioexp->preserved_regs->irq_mask.cnt,
+ ioexp->preserved_regs->irq_mask.values);
+ if (error)
+ dev_err(ioexp->dev,
+ "Failed to restore MCA_IRQ_MASK registers.\n");
+
+ error = write_reg_group(ioexp, MCA_REG_ADC_CFG0_0,
+ ioexp->preserved_regs->adc_cfg.cnt,
+ ioexp->preserved_regs->adc_cfg.values);
+ if (error)
+ dev_err(ioexp->dev,
+ "Failed to restore MCA_REG_ADC_CFG registers.\n");
+
+ enable_irq(ioexp->chip_irq);
+ return 0;
+}
+
+int mca_ioexp_device_init(struct mca_ioexp *ioexp, u32 irq)
+{
+ int ret;
+ unsigned int val;
+
+ ret = regmap_read(ioexp->regmap, MCA_DEVICE_ID, &val);
+ if (ret) {
+ dev_err(ioexp->dev,
+ "Cannot read MCA IO Expander Device ID (%d)\n",
+ ret);
+ return ret;
+ }
+ ioexp->dev_id = (u8)val;
+
+ if (ioexp->dev_id != MCA_IOEXP_DEVICE_ID_VAL) {
+ dev_err(ioexp->dev, "Invalid MCA IO Expander Device ID (%x)\n",
+ ioexp->dev_id);
+ return -ENODEV;
+ }
+
+ ret = regmap_read(ioexp->regmap, MCA_HW_VER, &val);
+ if (ret) {
+ dev_err(ioexp->dev, "Cannot read MCA Hardware Version (%d)\n",
+ ret);
+ return ret;
+ }
+ ioexp->hw_version = (u8)val;
+
+ ret = regmap_bulk_read(ioexp->regmap, MCA_FW_VER_L, &val, 2);
+ if (ret) {
+ dev_err(ioexp->dev,
+ "Cannot read MCA IO Expander Firmware Version (%d)\n",
+ ret);
+ return ret;
+ }
+ ioexp->fw_version = (u16)(val & ~MCA_FW_VER_ALPHA_MASK);
+ ioexp->fw_is_alpha = val & MCA_FW_VER_ALPHA_MASK ? true : false;
+
+ ioexp->chip_irq = irq;
+ ioexp->gpio_base = -1;
+
+ if (of_find_property(ioexp->dev->of_node, "restore-config-on-resume",
+ NULL)) {
+ unsigned int gpio_num;
+
+ ioexp->preserved_regs = kzalloc(sizeof *ioexp->preserved_regs,
+ GFP_KERNEL | GFP_DMA);
+ if (!ioexp->preserved_regs) {
+ dev_err(ioexp->dev,
+ "Failed to allocate memory for preserved registers.\n");
+ return -ENOMEM;
+ }
+
+ ret = regmap_read(ioexp->regmap, MCA_GPIO_NUM, &gpio_num);
+ if (ret) {
+ dev_err(ioexp->dev,
+ "Error reading MCA_GPIO_NUM (%d)\n", ret);
+ return ret;
+ }
+
+ ioexp->preserved_regs->gpio_dir.cnt = (gpio_num + 7) / 8;
+ ioexp->preserved_regs->gpio_dir.values =
+ kzalloc(ioexp->preserved_regs->gpio_dir.cnt,
+ GFP_KERNEL | GFP_DMA);
+ ioexp->preserved_regs->gpio_data.cnt = (gpio_num + 7) / 8;
+ ioexp->preserved_regs->gpio_data.values =
+ kzalloc(ioexp->preserved_regs->gpio_data.cnt,
+ GFP_KERNEL | GFP_DMA);
+ ioexp->preserved_regs->irq_cfg.cnt = gpio_num;
+ ioexp->preserved_regs->irq_cfg.values =
+ kzalloc(ioexp->preserved_regs->irq_cfg.cnt,
+ GFP_KERNEL | GFP_DMA);
+ ioexp->preserved_regs->irq_mask.cnt = 4;
+ ioexp->preserved_regs->irq_mask.values =
+ kzalloc(ioexp->preserved_regs->irq_mask.cnt,
+ GFP_KERNEL | GFP_DMA);
+ ioexp->preserved_regs->adc_cfg.cnt = gpio_num;
+ ioexp->preserved_regs->adc_cfg.values =
+ kzalloc(ioexp->preserved_regs->adc_cfg.cnt,
+ GFP_KERNEL | GFP_DMA);
+
+ } else {
+ ioexp->preserved_regs = NULL;
+ }
+ ret = mca_ioexp_irq_init(ioexp);
+ if (ret) {
+ dev_err(ioexp->dev, "Cannot initialize interrupts (%d)\n", ret);
+ return ret;
+ }
+
+ ret = mfd_add_devices(ioexp->dev, -1, mca_ioexp_devs,
+ ARRAY_SIZE(mca_ioexp_devs), NULL, ioexp->irq_base,
+ regmap_irq_get_domain(ioexp->regmap_irq));
+
+ if (ret) {
+ dev_err(ioexp->dev, "Cannot add MFD cells (%d)\n", ret);
+ goto out_irq;
+ }
+
+ ret = sysfs_create_group(&ioexp->dev->kobj, &mca_ioexp_attr_group);
+ if (ret) {
+ dev_err(ioexp->dev, "Cannot create sysfs entries (%d)\n", ret);
+ goto out_dev;
+ }
+
+ return 0;
+
+out_dev:
+ mfd_remove_devices(ioexp->dev);
+out_irq:
+ mca_ioexp_irq_exit(ioexp);
+
+ return ret;
+}
+
+void mca_ioexp_device_exit(struct mca_ioexp *ioexp)
+{
+ sysfs_remove_group(&ioexp->dev->kobj, &mca_ioexp_attr_group);
+ mfd_remove_devices(ioexp->dev);
+ mca_ioexp_irq_exit(ioexp);
+
+ if (!ioexp->preserved_regs) {
+ kfree(ioexp->preserved_regs->gpio_dir.values);
+ kfree(ioexp->preserved_regs->gpio_data.values);
+ kfree(ioexp->preserved_regs->irq_cfg.values);
+ kfree(ioexp->preserved_regs->irq_mask.values);
+ kfree(ioexp->preserved_regs->adc_cfg.values);
+ kfree(ioexp->preserved_regs);
+
+ ioexp->preserved_regs = NULL;
+ }
+}
+
+MODULE_AUTHOR("Digi International Inc");
+MODULE_DESCRIPTION("MCA IO Expander driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/mca-ioexp-i2c.c b/drivers/mfd/mca-ioexp-i2c.c
new file mode 100644
index 000000000000..29a5587ce683
--- /dev/null
+++ b/drivers/mfd/mca-ioexp-i2c.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2017 - 2019 Digi International Inc
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+
+#include <linux/mfd/core.h>
+#include <linux/mfd/mca-common/core.h>
+#include <linux/mfd/mca-ioexp/core.h>
+
+static const struct regmap_range mca_ioexp_readable_ranges[] = {
+};
+
+static const struct regmap_range mca_ioexp_writeable_ranges[] = {
+ regmap_reg_range(MCA_IRQ_STATUS_0, MCA_IRQ_MASK_3),
+ regmap_reg_range(MCA_GPIO_DIR_0, MCA_GPIO_IRQ_CFG_63),
+ regmap_reg_range(MCA_REG_ADC_CFG0_0, MCA_REG_ADC_CFG0_31),
+ regmap_reg_range(MCA_REG_ADC_CFG1_0, MCA_REG_ADC_CFG1_31),
+ regmap_reg_range(MCA_REG_ADC_CFG2_0, MCA_REG_ADC_CFG2_31),
+};
+
+static const struct regmap_range mca_ioexp_volatile_ranges[] = {
+ /* Real volatile registers */
+ regmap_reg_range(MCA_IRQ_STATUS_0, MCA_IRQ_STATUS_3),
+ regmap_reg_range(MCA_GPIO_DATA_0, MCA_GPIO_DATA_7),
+ regmap_reg_range(MCA_GPIO_IRQ_STATUS_0, MCA_GPIO_IRQ_STATUS_7),
+ regmap_reg_range(MCA_REG_ADC_VAL_L_0, MCA_REG_ADC_VAL_H_31),
+
+ /*
+ * Fake volatile registers.
+ *
+ * These registers could be cached but non-volatile registers makes
+ * regmap access each register one by one which has some drawbacks:
+ * - Breaks CRC in the protocol.
+ * - Requires the MCA firmware to process each access as a separate
+ * access, even when the data requested must be returned in bulk.
+ *
+ * For this reasons we will consider all registers volatile.
+ */
+ regmap_reg_range(MCA_DEVICE_ID, MCA_UID_9),
+ regmap_reg_range(MCA_IRQ_MASK_0, MCA_IRQ_MASK_3),
+ regmap_reg_range(MCA_GPIO_NUM, MCA_GPIO_DIR_7),
+ regmap_reg_range(MCA_GPIO_IRQ_CFG_0, MCA_GPIO_IRQ_CFG_63),
+ regmap_reg_range(MCA_REG_ADC_NUM_CH, MCA_REG_ADC_NUM_BYTES),
+ regmap_reg_range(MCA_REG_ADC_CFG0_0, MCA_REG_ADC_CFG0_31),
+ regmap_reg_range(MCA_REG_ADC_CFG1_0, MCA_REG_ADC_CFG1_31),
+ regmap_reg_range(MCA_REG_ADC_CFG2_0, MCA_REG_ADC_CFG2_31),
+};
+
+static const struct regmap_access_table mca_ioexp_readable_table = {
+ .yes_ranges = mca_ioexp_readable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(mca_ioexp_readable_ranges),
+};
+
+static const struct regmap_access_table mca_ioexp_writeable_table = {
+ .yes_ranges = mca_ioexp_writeable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(mca_ioexp_writeable_ranges),
+};
+
+static const struct regmap_access_table mca_ioexp_volatile_table = {
+ .yes_ranges = mca_ioexp_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(mca_ioexp_volatile_ranges),
+};
+
+static struct regmap_config mca_ioexp_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = 0xFFFF,
+
+ .rd_table = &mca_ioexp_readable_table,
+ .wr_table = &mca_ioexp_writeable_table,
+ .volatile_table = &mca_ioexp_volatile_table,
+
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static const struct of_device_id mca_ioexp_dt_ids[] = {
+ { .compatible = "digi,mca_ioexp", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mca_ioexp_dt_ids);
+
+static int mca_ioexp_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct mca_ioexp *ioexp;
+ int ret;
+
+ ioexp = devm_kzalloc(&i2c->dev, sizeof(struct mca_ioexp), GFP_KERNEL);
+ if (ioexp == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, ioexp);
+ ioexp->dev = &i2c->dev;
+ ioexp->chip_irq = i2c->irq;
+ ioexp->regmap = devm_regmap_init_i2c(i2c, &mca_ioexp_regmap_config);
+ if (IS_ERR(ioexp->regmap)) {
+ ret = PTR_ERR(ioexp->regmap);
+ dev_err(ioexp->dev, "Failed to allocate register map (%d)\n", ret);
+ goto err_regmap;
+ }
+
+ ret = mca_ioexp_device_init(ioexp, i2c->irq);
+ if (ret) {
+ dev_err(ioexp->dev, "Failed to init i2c device (%d)\n", ret);
+ goto err_regmap;
+ }
+
+ return 0;
+
+err_regmap:
+ devm_kfree(ioexp->dev, ioexp);
+
+ return ret;
+}
+
+static int mca_ioexp_i2c_remove(struct i2c_client *i2c)
+{
+ struct mca_ioexp *ioexp = i2c_get_clientdata(i2c);
+
+ mca_ioexp_device_exit(ioexp);
+ devm_kfree(ioexp->dev, ioexp);
+
+ return 0;
+}
+
+static void mca_ioexp_i2c_shutdown(struct i2c_client *i2c)
+{
+ struct mca_ioexp *ioexp = i2c_get_clientdata(i2c);
+
+ /*
+ * Disable the IRQ so that the I/O Expander does not wake-up the MCA
+ * when powered off.
+ */
+ disable_irq(ioexp->chip_irq);
+}
+
+#ifdef CONFIG_PM
+static int mca_ioexp_i2c_suspend(struct device *dev)
+{
+ return mca_ioexp_suspend(dev);
+}
+
+static int mca_ioexp_i2c_resume(struct device *dev)
+{
+ return mca_ioexp_resume(dev);
+}
+
+static SIMPLE_DEV_PM_OPS(mca_ioexp_i2c_pm_ops,
+ mca_ioexp_i2c_suspend,
+ mca_ioexp_i2c_resume);
+#endif
+
+static const struct i2c_device_id mca_ioexp_i2c_id[] = {
+ {"mca_ioexp", 0},
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, mca_ioexp_i2c_id);
+
+static struct i2c_driver mca_ioexp_i2c_driver = {
+ .driver = {
+ .name = "mca_ioexp",
+ .of_match_table = of_match_ptr(mca_ioexp_dt_ids),
+#ifdef CONFIG_PM
+ .pm = &mca_ioexp_i2c_pm_ops,
+#endif
+ },
+ .probe = mca_ioexp_i2c_probe,
+ .remove = mca_ioexp_i2c_remove,
+ .shutdown = mca_ioexp_i2c_shutdown,
+ .id_table = mca_ioexp_i2c_id,
+};
+
+module_i2c_driver(mca_ioexp_i2c_driver);
diff --git a/drivers/mfd/mca-ioexp-irq.c b/drivers/mfd/mca-ioexp-irq.c
new file mode 100644
index 000000000000..439149765dd0
--- /dev/null
+++ b/drivers/mfd/mca-ioexp-irq.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2017 - 2019 Digi International Inc
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/mfd/core.h>
+#include <linux/interrupt.h>
+#include <linux/regmap.h>
+#include <linux/mfd/mca-ioexp/core.h>
+#include <linux/mfd/mca-common/core.h>
+
+#define MCA_IOEXP_IRQ_0_OFFSET 0
+#define MCA_IOEXP_IRQ_1_OFFSET 1
+#define MCA_IOEXP_IRQ_2_OFFSET 2
+#define MCA_IOEXP_IRQ_3_OFFSET 3
+
+static const struct regmap_irq mca_ioexp_irqs[] = {
+ [MCA_IOEXP_IRQ_GPIO_BANK_0] = {
+ .reg_offset = MCA_IOEXP_IRQ_1_OFFSET,
+ .mask = MCA_GPIO_BANK_0,
+ },
+ [MCA_IOEXP_IRQ_GPIO_BANK_1] = {
+ .reg_offset = MCA_IOEXP_IRQ_1_OFFSET,
+ .mask = MCA_GPIO_BANK_1,
+ },
+ [MCA_IOEXP_IRQ_GPIO_BANK_2] = {
+ .reg_offset = MCA_IOEXP_IRQ_1_OFFSET,
+ .mask = MCA_GPIO_BANK_2,
+ },
+ [MCA_IOEXP_IRQ_GPIO_BANK_3] = {
+ .reg_offset = MCA_IOEXP_IRQ_1_OFFSET,
+ .mask = MCA_GPIO_BANK_3,
+ },
+ [MCA_IOEXP_IRQ_GPIO_BANK_4] = {
+ .reg_offset = MCA_IOEXP_IRQ_1_OFFSET,
+ .mask = MCA_GPIO_BANK_4,
+ },
+ [MCA_IOEXP_IRQ_GPIO_BANK_5] = {
+ .reg_offset = MCA_IOEXP_IRQ_1_OFFSET,
+ .mask = MCA_GPIO_BANK_5,
+ },
+};
+
+static const struct regmap_irq_chip mca_ioexp_irq_chip = {
+ .name = "mca-ioexp-irq",
+ .irqs = mca_ioexp_irqs,
+ .num_irqs = ARRAY_SIZE(mca_ioexp_irqs),
+ .num_regs = MCA_IOEXP_NUM_IRQ_REGS,
+ .status_base = MCA_IRQ_STATUS_0,
+ .mask_base = MCA_IRQ_MASK_0,
+ .ack_base = MCA_IRQ_STATUS_0,
+ .init_ack_masked = true,
+};
+
+int mca_ioexp_irq_init(struct mca_ioexp *ioexp)
+{
+ int ret;
+ const int irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED;
+
+ if (!ioexp->chip_irq) {
+ dev_err(ioexp->dev, "No IRQ configured\n");
+ return -EINVAL;
+ }
+
+ ioexp->irq_base = -1;
+ ret = regmap_add_irq_chip(ioexp->regmap, ioexp->chip_irq,
+ irq_flags,
+ ioexp->irq_base, &mca_ioexp_irq_chip,
+ &ioexp->regmap_irq);
+ if (ret) {
+ dev_err(ioexp->dev, "Failed to request IRQ %d (%d)\n",
+ ioexp->chip_irq, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+void mca_ioexp_irq_exit(struct mca_ioexp *ioexp)
+{
+ regmap_del_irq_chip(ioexp->chip_irq, ioexp->regmap_irq);
+}
diff --git a/include/linux/mfd/mca-ioexp/core.h b/include/linux/mfd/mca-ioexp/core.h
new file mode 100644
index 000000000000..cb9969262da5
--- /dev/null
+++ b/include/linux/mfd/mca-ioexp/core.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2017 - 2019 Digi International Inc
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef MFD_MCA_IOEXP_CORE_H_
+#define MFD_MCA_IOEXP_CORE_H_
+
+#include <linux/interrupt.h>
+#include <linux/mfd/mca-ioexp/registers.h>
+
+#define MCA_IOEXP_DRVNAME_ADC "mca-ioexp-adc"
+#define MCA_IOEXP_DRVNAME_GPIO "mca-ioexp-gpio"
+
+#define MCA_IOEXP_DEVICE_ID_VAL 0x37
+#define MCA_IOEXP_ADDR_LEN 2
+#define MCA_IOEXP_MAX_FRAME_DATA_LEN 256
+
+/* Interrupts */
+enum mca_ioexp_irqs {
+ MCA_IOEXP_IRQ_GPIO_BANK_0,
+ MCA_IOEXP_IRQ_GPIO_BANK_1,
+ MCA_IOEXP_IRQ_GPIO_BANK_2,
+ MCA_IOEXP_IRQ_GPIO_BANK_3,
+ MCA_IOEXP_IRQ_GPIO_BANK_4,
+ MCA_IOEXP_IRQ_GPIO_BANK_5,
+ /* ... */
+
+ MCA_IOEXP_NUM_IRQS,
+};
+
+/* Number of interrupt registers */
+#define MCA_IOEXP_NUM_IRQ_REGS 4
+
+struct mca_ioexp {
+ struct device *dev;
+ u8 dev_id;
+ u8 hw_version;
+ bool fw_is_alpha;
+ u16 fw_version;
+ u32 flags;
+ struct regmap *regmap;
+ struct regmap_irq_chip_data *regmap_irq;
+ int chip_irq;
+ u32 irq_base;
+ int gpio_base;
+
+ struct {
+ struct {
+ uint8_t *values;
+ uint8_t cnt;
+ } gpio_dir;
+
+ struct {
+ uint8_t *values;
+ uint8_t cnt;
+ } gpio_data;
+
+ struct {
+ uint8_t *values;
+ uint8_t cnt;
+ } irq_cfg;
+
+ struct {
+ uint8_t *values;
+ uint8_t cnt;
+ } irq_mask;
+
+ struct {
+ uint8_t *values;
+ uint8_t cnt;
+ } adc_cfg;
+ } *preserved_regs;
+};
+
+int mca_ioexp_device_init(struct mca_ioexp *ioexp, u32 irq);
+int mca_ioexp_irq_init(struct mca_ioexp *ioexp);
+void mca_ioexp_device_exit(struct mca_ioexp *ioexp);
+void mca_ioexp_irq_exit(struct mca_ioexp *ioexp);
+int mca_ioexp_suspend(struct device *dev);
+int mca_ioexp_resume(struct device *dev);
+
+#endif /* MFD_MCA_IOEXP_CORE_H_ */
diff --git a/include/linux/mfd/mca-ioexp/registers.h b/include/linux/mfd/mca-ioexp/registers.h
new file mode 100644
index 000000000000..9359c9953e0d
--- /dev/null
+++ b/include/linux/mfd/mca-ioexp/registers.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2017 - 2019 Digi International Inc
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef MCA_IOEXP_REGISTERS_H_
+#define MCA_IOEXP_REGISTERS_H_
+
+#include <linux/bitops.h>
+
+#endif /* MCA_IOEXP_REGISTERS_H_ */

View File

@ -0,0 +1,47 @@
From 4a2907834799eda9bd681ccd85557d6433666903 Mon Sep 17 00:00:00 2001
From: Alex Gonzalez <alex.gonzalez@digi.com>
Date: Mon, 23 Apr 2018 11:47:38 +0200
Subject: [PATCH] ccimx6ulsbcpro: Add IOEXP GPIO support
Synched with v4.14.78/master at:
3f8b03950b323db4ca89b1cdc1c2288f79facaa3
Signed-off-by: Alex Gonzalez <alex.gonzalez@digi.com>
---
arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts b/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts
index afc87b34f441..a818aec68959 100644
--- a/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts
+++ b/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts
@@ -130,6 +130,29 @@
irq-gpios = <&gpio5 2 GPIO_ACTIVE_HIGH>;
status = "okay";
};
+
+ mca_ioexp: mca_io@6e {
+ compatible = "digi,mca_ioexp";
+ reg = <0x6e>;
+ interrupt-parent = <&mca_gpio>;
+ interrupts = <0 IRQ_TYPE_EDGE_FALLING>;
+ restore-config-on-resume;
+ status = "okay";
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ pinctrl-names = "default";
+
+ mca_ioexp_gpio: gpio {
+ compatible = "digi,mca-ioexp-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-parent = <&mca_ioexp>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
};
&lcdif {

View File

@ -0,0 +1,35 @@
From d39028a304c0059ee16c65462e3e653670482aca Mon Sep 17 00:00:00 2001
From: Alex Gonzalez <alex.gonzalez@digi.com>
Date: Mon, 23 Apr 2018 11:48:15 +0200
Subject: [PATCH] ccimx6ulsbcpro: Add IOEXP ADC support
Synched with v4.14.78/master at:
3f8b03950b323db4ca89b1cdc1c2288f79facaa3
Signed-off-by: Alex Gonzalez <alex.gonzalez@digi.com>
---
arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts b/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts
index 7df31112cabf..b2b6a49391f4 100644
--- a/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts
+++ b/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts
@@ -153,6 +153,12 @@
interrupt-controller;
#interrupt-cells = <2>;
};
+
+ mca_ioexp_adc: adc {
+ compatible = "digi,mca-ioexp-adc";
+ digi,adc-ch-list = <3 4 5>;
+ digi,adc-vref = <3300000>;
+ };
};
};
@@ -482,4 +488,3 @@
>;
};
};
-

View File

@ -0,0 +1,38 @@
From ac65a7be2a14e2c5f90319674527257a53e59402 Mon Sep 17 00:00:00 2001
From: Alex Gonzalez <alex.gonzalez@digi.com>
Date: Tue, 8 Jan 2019 16:42:40 +0100
Subject: [PATCH] ARM: dts: ccimx6ulsbcpro: Configure touch GPIO reset line
The Goodix touch requires both the INT and reset lines in order to fix
an I2C address at startup.
This commit uses the IOEXP GPIO29 to control the DISP_5V supply which
controls the voltage source for the reset line pull-up. It also sets the
internal pull-up on the INT line so the line is not left floating.
Signed-off-by: Alex Gonzalez <alex.gonzalez@digi.com>
---
arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts b/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts
index 14274a0d6435..62133ede2736 100644
--- a/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts
+++ b/arch/arm/boot/dts/imx6ul-ccimx6ulsbcpro.dts
@@ -128,6 +128,7 @@
interrupt-parent = <&gpio5>;
interrupts = <2 IRQ_TYPE_EDGE_RISING>;
irq-gpios = <&gpio5 2 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&mca_ioexp_gpio 29 GPIO_ACTIVE_HIGH>;
status = "okay";
};
@@ -366,7 +367,7 @@
pinctrl_goodix_touch: goodixgrp{
fsl,pins = <
- MX6UL_PAD_SNVS_TAMPER2__GPIO5_IO02 0x1020
+ MX6UL_PAD_SNVS_TAMPER2__GPIO5_IO02 0x1b0b0
>;
};

View File

@ -0,0 +1,452 @@
CONFIG_KERNEL_LZO=y
CONFIG_SYSVIPC=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_PREEMPT_VOLUNTARY=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=18
CONFIG_CGROUPS=y
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_EXPERT=y
CONFIG_PERF_EVENTS=y
# CONFIG_SLUB_DEBUG is not set
# CONFIG_COMPAT_BRK is not set
CONFIG_ARCH_MULTI_V6=y
CONFIG_ARCH_MXC=y
CONFIG_MACH_MX31LILLY=y
CONFIG_MACH_MX31LITE=y
CONFIG_MACH_PCM037=y
CONFIG_MACH_PCM037_EET=y
CONFIG_MACH_MX31_3DS=y
CONFIG_MACH_MX31MOBOARD=y
CONFIG_MACH_QONG=y
CONFIG_MACH_ARMADILLO5X0=y
CONFIG_MACH_KZM_ARM11_01=y
CONFIG_MACH_IMX31_DT=y
CONFIG_MACH_IMX35_DT=y
CONFIG_MACH_PCM043=y
CONFIG_MACH_MX35_3DS=y
CONFIG_MACH_VPR200=y
CONFIG_SOC_IMX50=y
CONFIG_SOC_IMX51=y
CONFIG_SOC_IMX53=y
CONFIG_SOC_IMX6Q=y
CONFIG_SOC_IMX6SL=y
CONFIG_SOC_IMX6SLL=y
CONFIG_SOC_IMX6SX=y
CONFIG_SOM_CC6UL=y
CONFIG_SOC_IMX7D=y
CONFIG_SOC_VF610=y
CONFIG_PCI=y
CONFIG_PCI_MSI=y
CONFIG_PCI_IMX6=y
CONFIG_SMP=y
CONFIG_ARM_PSCI=y
CONFIG_HIGHMEM=y
CONFIG_FORCE_MAX_ZONEORDER=14
CONFIG_CMDLINE="noinitrd console=ttymxc0,115200"
CONFIG_KEXEC=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_STAT=y
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
CONFIG_CPUFREQ_DT=y
CONFIG_ARM_IMX6Q_CPUFREQ=y
CONFIG_CPU_IDLE=y
CONFIG_ARM_CPUIDLE=y
CONFIG_VFP=y
CONFIG_NEON=y
CONFIG_PM_DEBUG=y
CONFIG_PM_TEST_SUSPEND=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
# CONFIG_BLK_DEV_BSG is not set
CONFIG_BINFMT_MISC=m
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
# CONFIG_INET_XFRM_MODE_TUNNEL is not set
# CONFIG_INET_XFRM_MODE_BEET is not set
CONFIG_NETFILTER=y
CONFIG_CAN=y
CONFIG_CAN_FLEXCAN=y
CONFIG_BT=y
CONFIG_BT_HCIUART=y
CONFIG_BT_HCIUART_LL=y
CONFIG_CFG80211=y
CONFIG_CFG80211_WEXT=y
CONFIG_MAC80211=y
CONFIG_RFKILL=y
CONFIG_RFKILL_INPUT=y
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_STANDALONE is not set
CONFIG_FW_LOADER_USER_HELPER=y
CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
CONFIG_CMA_SIZE_MBYTES=64
CONFIG_IMX_WEIM=y
CONFIG_CONNECTOR=y
CONFIG_MTD=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_CFI=y
CONFIG_MTD_JEDECPROBE=y
CONFIG_MTD_CFI_INTELEXT=y
CONFIG_MTD_CFI_AMDSTD=y
CONFIG_MTD_CFI_STAA=y
CONFIG_MTD_PHYSMAP_OF=y
CONFIG_MTD_DATAFLASH=y
CONFIG_MTD_M25P80=y
CONFIG_MTD_SST25L=y
CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_GPMI_NAND=y
CONFIG_MTD_NAND_VF610_NFC=y
CONFIG_MTD_NAND_MXC=y
CONFIG_MTD_SPI_NOR=y
CONFIG_SPI_FSL_QUADSPI=y
CONFIG_MTD_UBI=y
CONFIG_MTD_UBI_FASTMAP=y
CONFIG_MTD_UBI_BLOCK=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=65536
CONFIG_EEPROM_AT24=y
CONFIG_EEPROM_AT25=y
# CONFIG_SCSI_PROC_FS is not set
CONFIG_BLK_DEV_SD=y
CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_LOGGING=y
CONFIG_SCSI_SCAN_ASYNC=y
# CONFIG_SCSI_LOWLEVEL is not set
CONFIG_ATA=y
CONFIG_SATA_AHCI_PLATFORM=y
CONFIG_AHCI_IMX=y
CONFIG_PATA_IMX=y
CONFIG_NETDEVICES=y
# CONFIG_NET_VENDOR_BROADCOM is not set
CONFIG_CS89x0=y
CONFIG_CS89x0_PLATFORM=y
# CONFIG_NET_VENDOR_FARADAY is not set
# CONFIG_NET_VENDOR_INTEL is not set
# CONFIG_NET_VENDOR_MARVELL is not set
# CONFIG_NET_VENDOR_MICREL is not set
# CONFIG_NET_VENDOR_MICROCHIP is not set
# CONFIG_NET_VENDOR_NATSEMI is not set
# CONFIG_NET_VENDOR_SEEQ is not set
CONFIG_SMC91X=y
CONFIG_SMC911X=y
CONFIG_SMSC911X=y
# CONFIG_NET_VENDOR_STMICRO is not set
CONFIG_AT803X_PHY=y
CONFIG_MICREL_PHY=y
CONFIG_SMSC_PHY=y
CONFIG_USB_PEGASUS=m
CONFIG_USB_RTL8150=m
CONFIG_USB_RTL8152=y
CONFIG_USB_LAN78XX=y
CONFIG_USB_USBNET=y
CONFIG_USB_NET_CDC_EEM=m
CONFIG_USB_NET_SMSC95XX=y
CONFIG_USB_NET_MCS7830=y
CONFIG_BRCMFMAC=m
CONFIG_MWIFIEX=m
CONFIG_MWIFIEX_SDIO=m
CONFIG_MWIFIEX_PCIE=m
CONFIG_WL12XX=m
CONFIG_WL18XX=m
CONFIG_WLCORE_SDIO=m
# CONFIG_WILINK_PLATFORM_DATA is not set
CONFIG_INPUT_EVDEV=y
CONFIG_KEYBOARD_GPIO=y
CONFIG_KEYBOARD_SNVS_PWRKEY=y
CONFIG_KEYBOARD_IMX=y
CONFIG_MOUSE_PS2=m
CONFIG_MOUSE_PS2_ELANTECH=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ADS7846=y
CONFIG_TOUCHSCREEN_EGALAX=y
CONFIG_TOUCHSCREEN_MAX11801=y
CONFIG_TOUCHSCREEN_IMX6UL_TSC=y
CONFIG_TOUCHSCREEN_EDT_FT5X06=y
CONFIG_TOUCHSCREEN_MC13783=y
CONFIG_TOUCHSCREEN_TSC2004=y
CONFIG_TOUCHSCREEN_TSC2007=y
CONFIG_TOUCHSCREEN_STMPE=y
CONFIG_TOUCHSCREEN_SX8654=y
CONFIG_TOUCHSCREEN_COLIBRI_VF50=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_MMA8450=y
CONFIG_INPUT_MCA_PWRKEY=y
CONFIG_SERIO_SERPORT=m
# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_IMX=y
CONFIG_SERIAL_IMX_CONSOLE=y
CONFIG_SERIAL_MCA_CC6UL=y
CONFIG_SERIAL_FSL_LPUART=y
CONFIG_SERIAL_FSL_LPUART_CONSOLE=y
CONFIG_SERIAL_DEV_BUS=y
# CONFIG_I2C_COMPAT is not set
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_MUX=y
CONFIG_I2C_MUX_GPIO=y
# CONFIG_I2C_HELPER_AUTO is not set
CONFIG_I2C_ALGOPCF=m
CONFIG_I2C_ALGOPCA=m
CONFIG_I2C_GPIO=y
CONFIG_I2C_IMX=y
CONFIG_SPI=y
CONFIG_SPI_GPIO=y
CONFIG_SPI_IMX=y
CONFIG_SPI_FSL_DSPI=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_MCA=y
CONFIG_GPIO_MAX732X=y
CONFIG_GPIO_MC9S08DZ60=y
CONFIG_GPIO_PCA953X=y
CONFIG_GPIO_STMPE=y
CONFIG_GPIO_74X164=y
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_SYSCON=y
CONFIG_POWER_RESET_SYSCON_POWEROFF=y
CONFIG_POWER_SUPPLY=y
CONFIG_SENSORS_MC13783_ADC=y
CONFIG_SENSORS_GPIO_FAN=y
CONFIG_SENSORS_IIO_HWMON=y
CONFIG_THERMAL_WRITABLE_TRIPS=y
CONFIG_CPU_THERMAL=y
CONFIG_IMX_THERMAL=y
CONFIG_WATCHDOG=y
CONFIG_DA9062_WATCHDOG=y
CONFIG_RN5T618_WATCHDOG=y
CONFIG_MCA_WATCHDOG=y
CONFIG_IMX2_WDT=y
CONFIG_MFD_DA9052_I2C=y
CONFIG_MFD_DA9062=y
CONFIG_MFD_MC13XXX_SPI=y
CONFIG_MFD_MC13XXX_I2C=y
CONFIG_MFD_RN5T618=y
CONFIG_MFD_MCA_IOEXP=y
CONFIG_MFD_STMPE=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_ANATOP=y
CONFIG_REGULATOR_DA9052=y
CONFIG_REGULATOR_DA9062=y
CONFIG_REGULATOR_GPIO=y
CONFIG_REGULATOR_MC13783=y
CONFIG_REGULATOR_MC13892=y
CONFIG_REGULATOR_PFUZE100=y
CONFIG_REGULATOR_RN5T618=y
CONFIG_RC_CORE=y
CONFIG_RC_DEVICES=y
CONFIG_IR_GPIO_CIR=y
CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_CAMERA_SUPPORT=y
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
CONFIG_MEDIA_USB_SUPPORT=y
CONFIG_USB_VIDEO_CLASS=m
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_VIDEO_MUX=y
CONFIG_SOC_CAMERA=y
CONFIG_V4L_MEM2MEM_DRIVERS=y
CONFIG_VIDEO_CODA=m
# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
CONFIG_VIDEO_ADV7180=m
CONFIG_VIDEO_OV5640=m
CONFIG_IMX_IPUV3_CORE=y
CONFIG_DRM=y
CONFIG_DRM_PANEL_LVDS=y
CONFIG_DRM_PANEL_SIMPLE=y
CONFIG_DRM_PANEL_SEIKO_43WVF1G=y
CONFIG_DRM_DW_HDMI_AHB_AUDIO=m
CONFIG_DRM_DW_HDMI_CEC=y
CONFIG_DRM_IMX=y
CONFIG_DRM_IMX_PARALLEL_DISPLAY=y
CONFIG_DRM_IMX_TVE=y
CONFIG_DRM_IMX_LDB=y
CONFIG_DRM_IMX_HDMI=y
CONFIG_DRM_ETNAVIV=y
CONFIG_DRM_MXSFB=y
CONFIG_FB_MODE_HELPERS=y
CONFIG_LCD_CLASS_DEVICE=y
CONFIG_LCD_L4F00242T03=y
CONFIG_LCD_PLATFORM=y
CONFIG_BACKLIGHT_PWM=y
CONFIG_BACKLIGHT_GPIO=y
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_LOGO=y
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_USB_AUDIO=m
CONFIG_SND_SOC=y
CONFIG_SND_SOC_FSL_ASRC=y
CONFIG_SND_IMX_SOC=y
CONFIG_SND_SOC_PHYCORE_AC97=y
CONFIG_SND_SOC_EUKREA_TLV320=y
CONFIG_SND_SOC_IMX_ES8328=y
CONFIG_SND_SOC_IMX_SGTL5000=y
CONFIG_SND_SOC_IMX_SPDIF=y
CONFIG_SND_SOC_IMX_MC13783=y
CONFIG_SND_SOC_FSL_ASOC_CARD=y
CONFIG_SND_SOC_AC97_CODEC=y
CONFIG_SND_SOC_CS42XX8_I2C=y
CONFIG_SND_SOC_TLV320AIC3X=y
CONFIG_SND_SOC_WM8960=y
CONFIG_SND_SOC_WM8962=y
CONFIG_SND_SIMPLE_CARD=y
CONFIG_HID_MULTITOUCH=y
CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_MXC=y
CONFIG_USB_STORAGE=y
CONFIG_USB_CHIPIDEA=y
CONFIG_USB_CHIPIDEA_UDC=y
CONFIG_USB_CHIPIDEA_HOST=y
CONFIG_USB_SERIAL=m
CONFIG_USB_SERIAL_GENERIC=y
CONFIG_USB_SERIAL_FTDI_SIO=m
CONFIG_USB_SERIAL_OPTION=m
CONFIG_USB_TEST=m
CONFIG_USB_EHSET_TEST_FIXTURE=m
CONFIG_NOP_USB_XCEIV=y
CONFIG_USB_MXS_PHY=y
CONFIG_USB_GADGET=y
CONFIG_USB_FSL_USB2=y
CONFIG_USB_CONFIGFS=m
CONFIG_USB_CONFIGFS_SERIAL=y
CONFIG_USB_CONFIGFS_ACM=y
CONFIG_USB_CONFIGFS_OBEX=y
CONFIG_USB_CONFIGFS_NCM=y
CONFIG_USB_CONFIGFS_ECM=y
CONFIG_USB_CONFIGFS_ECM_SUBSET=y
CONFIG_USB_CONFIGFS_RNDIS=y
CONFIG_USB_CONFIGFS_EEM=y
CONFIG_USB_CONFIGFS_MASS_STORAGE=y
CONFIG_USB_CONFIGFS_F_LB_SS=y
CONFIG_USB_CONFIGFS_F_FS=y
CONFIG_USB_CONFIGFS_F_UAC1=y
CONFIG_USB_CONFIGFS_F_UAC2=y
CONFIG_USB_CONFIGFS_F_MIDI=y
CONFIG_USB_CONFIGFS_F_HID=y
CONFIG_USB_CONFIGFS_F_UVC=y
CONFIG_USB_CONFIGFS_F_PRINTER=y
CONFIG_USB_ZERO=m
CONFIG_USB_AUDIO=m
CONFIG_USB_ETH=m
CONFIG_USB_G_NCM=m
CONFIG_USB_GADGETFS=m
CONFIG_USB_FUNCTIONFS=m
CONFIG_USB_MASS_STORAGE=m
CONFIG_USB_G_SERIAL=m
CONFIG_MMC=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_ESDHC_IMX=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_GPIO=y
CONFIG_LEDS_PWM=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_LEDS_TRIGGER_ONESHOT=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_LEDS_TRIGGER_BACKLIGHT=y
CONFIG_LEDS_TRIGGER_GPIO=y
CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_INTF_DEV_UIE_EMUL=y
CONFIG_RTC_DRV_DS1307=y
CONFIG_RTC_DRV_ISL1208=y
CONFIG_RTC_DRV_PCF8523=y
CONFIG_RTC_DRV_PCF8563=y
CONFIG_RTC_DRV_M41T80=y
CONFIG_RTC_DRV_DA9063=y
CONFIG_RTC_DRV_MCA=y
CONFIG_RTC_DRV_MC13XXX=y
CONFIG_RTC_DRV_MXC=y
CONFIG_RTC_DRV_MXC_V2=y
CONFIG_RTC_DRV_SNVS=y
CONFIG_DMADEVICES=y
CONFIG_FSL_EDMA=y
CONFIG_IMX_SDMA=y
CONFIG_MXS_DMA=y
CONFIG_DMATEST=m
CONFIG_STAGING=y
CONFIG_STAGING_MEDIA=y
CONFIG_VIDEO_IMX_MEDIA=y
CONFIG_COMMON_CLK_PWM=y
CONFIG_IIO=y
CONFIG_MMA8452=y
CONFIG_IMX7D_ADC=y
CONFIG_MCA_ADC=y
CONFIG_VF610_ADC=y
CONFIG_SENSORS_ISL29018=y
CONFIG_MAG3110=y
CONFIG_MPL3115=y
CONFIG_TAMPER_MCA=y
CONFIG_PWM=y
CONFIG_PWM_FSL_FTM=y
CONFIG_PWM_IMX=y
CONFIG_NVMEM_IMX_OCOTP=y
CONFIG_NVMEM_VF610_OCOTP=y
CONFIG_TEE=y
CONFIG_OPTEE=y
CONFIG_MUX_MMIO=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT2_FS_POSIX_ACL=y
CONFIG_EXT2_FS_SECURITY=y
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_POSIX_ACL=y
CONFIG_EXT3_FS_SECURITY=y
CONFIG_QUOTA=y
CONFIG_QUOTA_NETLINK_INTERFACE=y
# CONFIG_PRINT_QUOTA_WARNING is not set
CONFIG_AUTOFS4_FS=y
CONFIG_FUSE_FS=y
CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y
CONFIG_ZISOFS=y
CONFIG_UDF_FS=m
CONFIG_MSDOS_FS=m
CONFIG_VFAT_FS=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_JFFS2_FS=y
CONFIG_UBIFS_FS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3_ACL=y
CONFIG_NFS_V4=y
CONFIG_ROOT_NFS=y
CONFIG_NLS_DEFAULT="cp437"
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=y
CONFIG_NLS_ISO8859_15=m
CONFIG_NLS_UTF8=y
CONFIG_SECURITYFS=y
CONFIG_CRYPTO_DEV_FSL_CAAM=y
CONFIG_CRYPTO_DEV_SAHARA=y
CONFIG_CRC_CCITT=m
CONFIG_CRC_T10DIF=y
CONFIG_CRC7=m
CONFIG_LIBCRC32C=m
CONFIG_FONTS=y
CONFIG_FONT_8x8=y
CONFIG_FONT_8x16=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_SCHED_DEBUG is not set
CONFIG_PROVE_LOCKING=y
# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_FTRACE is not set

View File

@ -0,0 +1,22 @@
FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
SRC_URI_append_ccimx6ul_use-mainline-bsp = " \
file://0001-ARM-Add-support-for-the-ConnectCore-6UL-System-On-Mo.patch \
file://0002-mach-imx-pm-imx6-Add-hooks-for-board-specific-implem.patch \
file://0003-imx6ul-Add-MCA-core-I2C-driver-support.patch \
file://0004-imx6ul-Add-MCA-GPIO-support-for-the-ConnectCore-6UL-.patch \
file://0005-imx6ul-Add-MCA-IOMUX-support-to-the-ConnectCore-6UL-.patch \
file://0006-imx6ul-Add-MCA-watchdog-support-for-the-ConnectCore-.patch \
file://0007-imx6ul-Add-MCA-ADC-support-for-ConnectCore-6UL-SOM-a.patch \
file://0008-imx6ul-Add-MCA-tamper-support-for-ConnectCore-6UL-SO.patch \
file://0009-imx6ul-Add-MCA-UART-support-for-ConnectCore-6UL-SOM-.patch \
file://0010-imx6ul-Add-RTC-MCA-support-for-ConnectCore-6UL-SOM.patch \
file://0011-imx6ul-Add-MCA-power-key-support-for-ConnectCore-6UL.patch \
"
SRC_URI_append_ccimx6ulsbc_use-mainline-bsp = " \
file://0001-ccimx6ulsbcpro-Add-IOEXP-core-I2C-support.patch \
file://0002-ccimx6ulsbcpro-Add-IOEXP-GPIO-support.patch \
file://0003-ccimx6ulsbcpro-Add-IOEXP-ADC-support.patch \
file://0004-ARM-dts-ccimx6ulsbcpro-Configure-touch-GPIO-reset-li.patch \
"

View File

@ -1,10 +1,10 @@
#ACTION!="add|change|move", GOTO="mm_digi_xbee_cellular_modem_end"
ACTION!="add|change|move", GOTO="mm_digi_xbee_cellular_modem_end"
# By default, ModemManager expects a default baudrate of 57600bps. Different
# baudrates may be used by setting the ID_MM_TTY_BAUDRATE udev tag.
# ModemManager documentation states that the best practice is to use the DEVPATH
# this way rather than other rules such as KERNEL, so be careful when modifying
#DEVPATH=="/devices/platform/5a060000.serial/tty/ttyLP0", ENV{ID_MM_PLATFORM_DRIVER_PROBE}="1", ENV{ID_MM_PHYSDEV_UID}="Digi XBee Cellular"
DEVPATH=="/devices/platform/5a800000.i2c/i2c-0/0-0063/mca-cc8x-uart/tty/ttyMCA0", ENV{ID_MM_PLATFORM_DRIVER_PROBE}="1", ENV{ID_MM_PHYSDEV_UID}="Digi XBee Cellular"
#LABEL="mm_digi_xbee_cellular_modem_end"
LABEL="mm_digi_xbee_cellular_modem_end"

View File

@ -0,0 +1,8 @@
[Unit]
Description=Late modems scan
Requires=ModemManager.service
After=ModemManager.service xbee-init.service time-sync.target
[Service]
Type=oneshot
ExecStart=mmcli --scan-modems 1>/dev/null 2>&1

View File

@ -0,0 +1,8 @@
[Unit]
Description=Late modems scan timer
[Timer]
OnActiveSec=40s
[Install]
WantedBy=multi-user.target

View File

@ -5,6 +5,8 @@ FILESEXTRAPATHS_prepend := "${THISDIR}/${BPN}:"
SRC_URI += " \
file://78-mm-digi-xbee-cellular.rules \
file://80-mm-net-device-blacklist.rules \
file://late-modems-scan.service \
file://late-modems-scan.timer \
"
# 'polkit' depends on 'consolekit', and this requires 'x11' distro feature. So
@ -19,6 +21,14 @@ do_install_append() {
# Install udev rules for ModemManager blacklist devices
install -m 0644 ${WORKDIR}/80-mm-net-device-blacklist.rules ${D}${nonarch_base_libdir}/udev/rules.d/
# Install systemd service for scanning late modems
install -d ${D}${systemd_unitdir}/system/
install -m 0644 ${WORKDIR}/late-modems-scan.service ${D}${systemd_unitdir}/system/
install -m 0644 ${WORKDIR}/late-modems-scan.timer ${D}${systemd_unitdir}/system/
}
SYSTEMD_SERVICE_${PN}_append = " late-modems-scan.timer"
FILES_${PN}_append = " late-modems-scan.timer"
PACKAGE_ARCH = "${MACHINE_ARCH}"

View File

@ -0,0 +1,40 @@
# Copyright (C) 2019 Digi International Inc.
SUMMARY = "Digi XBee initialization"
DESCRIPTION = "Initialization scripts for XBee hardware of Digi boards"
SECTION = "base"
LICENSE = "GPL-2.0"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6"
SRC_URI = " \
file://xbee-init \
file://xbee-init.service \
"
S = "${WORKDIR}"
do_install() {
install -d ${D}${sysconfdir}/init.d/
install -m 0755 ${WORKDIR}/xbee-init ${D}${sysconfdir}/
ln -sf /etc/xbee-init ${D}${sysconfdir}/init.d/xbee-init
sed -i -e "s,##XBEE_RESET_N_GPIO##,${XBEE_RESET_N_GPIO},g" \
-e "s,##XBEE_SLEEP_RQ_GPIO##,${XBEE_SLEEP_RQ_GPIO},g" \
${D}${sysconfdir}/xbee-init
install -d ${D}${systemd_unitdir}/system/
install -m 0644 ${WORKDIR}/xbee-init.service ${D}${systemd_unitdir}/system/
}
PACKAGES =+ "${PN}-init"
FILES_${PN}-init = " \
${sysconfdir}/xbee-init \
${sysconfdir}/init.d/xbee-init \
${systemd_unitdir}/system/xbee-init.service \
"
INITSCRIPT_PACKAGES += "${PN}-init"
INITSCRIPT_NAME_${PN}-init = "xbee-init"
INITSCRIPT_PARAMS_${PN}-init = "start 19 2 3 4 5 . stop 21 0 1 6 ."
SYSTEMD_SERVICE_${PN}-init = "xbee-init.service"
PACKAGE_ARCH = "${MACHINE_ARCH}"
COMPATIBLE_MACHINE = "(ccimx8x)"

View File

@ -0,0 +1,70 @@
#!/bin/sh
# Linux GPIOs on XBee lines
XBEE_RESET_N_GPIO="##XBEE_RESET_N_GPIO##"
XBEE_SLEEP_RQ_GPIO="##XBEE_SLEEP_RQ_GPIO##"
# request_gpio <gpio_nr>
request_gpio_out() {
local SG_GPIONR="${1}"
local SG_GPIOPATH="/sys/class/gpio/gpio${SG_GPIONR}"
[ -d "${SG_GPIOPATH}" ] || printf "%s" "${SG_GPIONR}" > /sys/class/gpio/export
printf out > "${SG_GPIOPATH}/direction" && sleep .2
}
# free_gpio <gpio_nr>
free_gpio() {
local SG_GPIONR="${1}"
local SG_GPIOPATH="/sys/class/gpio/gpio${SG_GPIONR}"
[ -d "${SG_GPIOPATH}" ] && printf "%s" "${SG_GPIONR}" > /sys/class/gpio/unexport
}
# set_gpio_value <gpio_nr> <value>
set_gpio_value() {
local SG_GPIONR="${1}"
local SG_GPIOVAL="${2}"
local SG_GPIOPATH="/sys/class/gpio/gpio${SG_GPIONR}"
printf out > "${SG_GPIOPATH}/direction" && sleep .2
printf "${SG_GPIOVAL}" > "${SG_GPIOPATH}/value" && sleep .2
}
xbee_init() {
# Power cycle XBEE_RESET_N
request_gpio_out ${XBEE_RESET_N_GPIO}
set_gpio_value ${XBEE_RESET_N_GPIO} 0
set_gpio_value ${XBEE_RESET_N_GPIO} 1
# Set low XBEE_SLEEP_RQ
request_gpio_out ${XBEE_SLEEP_RQ_GPIO}
set_gpio_value ${XBEE_SLEEP_RQ_GPIO} 0
}
xbee_stop() {
free_gpio ${XBEE_RESET_N_GPIO}
free_gpio ${XBEE_SLEEP_RQ_GPIO}
}
case "$1" in
start)
echo -n "Starting XBee hardware: "
xbee_init
echo "done."
;;
stop)
echo -n "Stopping XBee hardware: "
xbee_stop
echo "done."
;;
restart)
$0 stop
sleep 1
$0 start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
;;
esac

View File

@ -0,0 +1,12 @@
[Unit]
Description=XBee GPIOs initialization
Before=ModemManager.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/etc/xbee-init start
ExecStop=/etc/xbee-init stop
[Install]
WantedBy=multi-user.target

View File

@ -13,9 +13,7 @@ IMAGE_FEATURES += " \
${@bb.utils.contains('MACHINE_FEATURES', 'wifi', 'dey-wireless', '', d)} \
"
IMAGE_INSTALL = " \
dey-examples-digiapix \
"
CORE_IMAGE_BASE_INSTALL += "dey-examples-digiapix"
# SDK features (for toolchains generated from an image with populate_sdk)
SDKIMAGE_FEATURES ?= "dev-pkgs dbg-pkgs staticdev-pkgs"

View File

@ -0,0 +1,30 @@
From: Gabriel Valcazar <gabriel.valcazar@digi.com>
Date: Thu, 28 Mar 2019 17:40:00 +0100
Subject: [PATCH] sd-resolve: forcefully cancel worker threads during
resolve_free
For services that use sd-resolve, such as timesyncd, this prevents the system
from stalling whenever the service stops while a worker thread is busy calling
getaddrinfo().
Signed-off-by: Gabriel Valcazar <gabriel.valcazar@digi.com>
---
src/libsystemd/sd-resolve/sd-resolve.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c
index a189f14..571604c 100644
--- a/src/libsystemd/sd-resolve/sd-resolve.c
+++ b/src/libsystemd/sd-resolve/sd-resolve.c
@@ -577,8 +577,10 @@ static void resolve_free(sd_resolve *resolve) {
/* Now terminate them and wait until they are gone.
If we get an error than most likely the thread already exited. */
- for (i = 0; i < resolve->n_valid_workers; i++)
+ for (i = 0; i < resolve->n_valid_workers; i++) {
+ pthread_cancel(resolve->workers[i]);
(void) pthread_join(resolve->workers[i], NULL);
+ }
/* Close all communication channels */
close_many(resolve->fds, _FD_MAX);

View File

@ -1,6 +1,9 @@
FILESEXTRAPATHS_prepend := "${THISDIR}/${BPN}:"
SRC_URI += "file://0001-udev-use-the-usual-set-of-load-paths-for-udev-rules.patch"
SRC_URI += " \
file://0001-udev-use-the-usual-set-of-load-paths-for-udev-rules.patch \
file://0002-sd-resolve-forcefully-cancel-worker-threads-during-r.patch \
"
#FIX-it: Workaround as missing ending slash in FIRMWARE_PATH [YOCIMX-2831]
EXTRA_OEMESON_remove = "-Dfirmware-path=${nonarch_base_libdir}/firmware "

View File

@ -0,0 +1,25 @@
# Copyright (C) 2019 Digi International Inc.
# Re-add the base RDEPENDS to class-target since they are being overwritten in the
# original recipe
RDEPENDS_${PN}_class-target_append = " \
${PYTHON_PN}-unittest \
${PYTHON_PN}-difflib \
${PYTHON_PN}-pprint \
${PYTHON_PN}-pickle \
${PYTHON_PN}-shell \
${PYTHON_PN}-nose \
${PYTHON_PN}-doctest \
${PYTHON_PN}-datetime \
${PYTHON_PN}-distutils \
${PYTHON_PN}-misc \
${PYTHON_PN}-mmap \
${PYTHON_PN}-netclient \
${PYTHON_PN}-numbers \
${PYTHON_PN}-pydoc \
${PYTHON_PN}-pkgutil \
${PYTHON_PN}-email \
${PYTHON_PN}-compression \
${PYTHON_PN}-ctypes \
${PYTHON_PN}-threading \
"

View File

@ -14,4 +14,4 @@ do_install() {
install -m 0755 hdp-test.py ${D}${bindir}
}
RDEPENDS_${PN} = "python3 python3-argparse python3-crypt python3-dbus python3-pygobject"
RDEPENDS_${PN} = "python3 python3-crypt python3-dbus python3-pygobject"

View File

@ -19,4 +19,4 @@ SUBSYSTEM=="spidev", GROUP="digiapix", MODE="0660"
SUBSYSTEM=="gpio", KERNEL=="gpiochip0", ACTION=="add", RUN="/etc/udev/scripts/digiapix.sh"
SUBSYSTEM=="gpio", KERNEL!="gpiochip*", ACTION=="add", RUN="/etc/udev/scripts/digiapix.sh"
SUBSYSTEM=="pwm", ACTION=="add", RUN="/etc/udev/scripts/digiapix.sh"
SUBSYSTEM=="pwm", ACTION=="add|change", RUN="/etc/udev/scripts/digiapix.sh"

View File

@ -5,12 +5,13 @@ model = Digi International ConnectCore 6 QuadPlus Single Board Computer.
# USER LED (RED) - GPIO02_IO02
USER_LED = 34
USER_LED0 = 34
# USER LED (ORANGE) - GPIO02_IO03
USER_LED_2 = 35
USER_LED1 = 35
# USER LED (GREEN) - GPIO02_IO04
USER_LED_3 = 36
USER_LED2 = 36
# USER BUTTON - GPIO02_IO05
USER_BUTTON = 37

View File

@ -5,12 +5,13 @@ model = Digi International ConnectCore 6 Single Board Computer.
# USER LED (RED) - GPIO02_IO02
USER_LED = 34
USER_LED0 = 34
# USER LED (ORANGE) - GPIO02_IO03
USER_LED_2 = 35
USER_LED1 = 35
# USER LED (GREEN) - GPIO02_IO04
USER_LED_3 = 36
USER_LED2 = 36
# USER BUTTON - GPIO02_IO05
USER_BUTTON = 37

View File

@ -26,5 +26,5 @@ DEFAULT_PWM = 7,0
[ADC]
# TODO: only MCA ADCs are supported at the moment, with them being disabled by default
# ADC_IN0 on Expansion connector
DEFAULT_ADC = 0,0

View File

@ -4,10 +4,14 @@ model = Digi International ConnectCore 8X SBC Pro.
[GPIO]
# USER LED0 - MCA_IO18
USER_LED = 222
USER_LED = 223
USER_LED0 = 223
# USER_LED1 - MCA_IO10
USER_LED1 = 215
# USER BUTTON - MCA_IO05
USER_BUTTON = 209
USER_BUTTON = 210
[I2C]
@ -26,5 +30,5 @@ DEFAULT_PWM = 7,0
[ADC]
# TODO: only MCA ADCs are supported at the moment, with them being disabled by default
# ADC_IN0 on Expansion connector
DEFAULT_ADC = 0,0

View File

@ -19,13 +19,17 @@ if basename "${DEVPATH}" | grep -qs "gpiochip0$"; then
# Use 'gpiochip0' event to set group and mode for 'export/unexport' files
chown root:digiapix /sys/class/gpio/export /sys/class/gpio/unexport
chmod g+w /sys/class/gpio/export /sys/class/gpio/unexport
elif basename "${DEVPATH}" | grep -qs "pwmchip[0-9]\+$"; then
elif basename "${DEVPATH}" | grep -qs "pwmchip[0-9]\+$" && [ "${ACTION}" = "add" ] ; then
# Set group and mode for pwmchip's 'export/unexport' files
chown root:digiapix /sys${DEVPATH}/export /sys${DEVPATH}/unexport
chmod g+w /sys${DEVPATH}/export /sys${DEVPATH}/unexport
elif basename "${DEVPATH}" | grep -qs "pwmchip[0-9]\+$" && [ "${ACTION}" = "change" ] ; then
# Set group and mode for 'pwmX' channel and all files inside it...
chown root:digiapix /sys${DEVPATH}/${EXPORT} /sys${DEVPATH}/${EXPORT}/*
chmod g+w /sys${DEVPATH}/${EXPORT}/*
else
# Change group and mode of the sysfs files created whenever a 'gpioX'
# or 'pwmX' is exported
# is exported
chown -h root:digiapix /sys${DEVPATH}/*
chmod g+w /sys${DEVPATH}/*
fi

View File

@ -19,7 +19,7 @@ LIBDIGIAPIX_GIT_URI ?= "${@oe.utils.conditional('DIGI_INTERNAL_GIT', '1' , '${LI
SRC_URI = " \
${LIBDIGIAPIX_GIT_URI};branch=${SRCBRANCH} \
file://99-digiapix.rules \
file://board.conf \
file://libdigiapix.conf \
file://digiapix.sh \
"
@ -36,7 +36,7 @@ do_install() {
install -m 0755 ${WORKDIR}/digiapix.sh ${D}${sysconfdir}/udev/scripts/
# Install board config file
install -m 0644 ${WORKDIR}/board.conf ${D}${sysconfdir}/libdigiapix.conf
install -m 0644 ${WORKDIR}/libdigiapix.conf ${D}${sysconfdir}/
}
USERADD_PACKAGES = "${PN}"

View File

@ -193,7 +193,7 @@ int main( int argc, char** argv )
}
if( filename != NULL ) {
if( ( fd_file = open( filename, O_RDWR | O_CREAT ) ) < 0 ) {
if( ( fd_file = open( filename, O_RDWR | O_CREAT , 0600 ) ) < 0 ) {
fprintf( stderr, "Error opening file: %s (%d)\n",
filename, errno );
release_resources_and_exit( EXIT_FAILURE );

View File

@ -22,7 +22,7 @@
set -e
AVAILABLE_PLATFORMS="ccimx8x-sbc-pro ccimx8x-sbc-express ccimx6qpsbc ccimx6sbc ccimx6ulsbc ccimx6ulstarter"
AVAILABLE_PLATFORMS="ccimx8x-sbc-pro ccimx8x-sbc-express ccimx6ulsbc ccimx6ulstarter"
MANIFEST_URL="https://github.com/digi-embedded/dey-manifest.git"
@ -123,8 +123,6 @@ while read _pl _tgt; do
done<<-_EOF_
ccimx8x-sbc-pro dey-image-qt
ccimx8x-sbc-express dey-image-qt
ccimx6qpsbc dey-image-qt
ccimx6sbc dey-image-qt
ccimx6ulsbc dey-image-qt
ccimx6ulstarter core-image-base
_EOF_

View File

@ -173,8 +173,6 @@ while read _pl _var _tgt; do
done<<-_EOF_
ccimx8x-sbc-pro DONTBUILDVARIANTS dey-image-qt,dey-image-aws
ccimx8x-sbc-express DONTBUILDVARIANTS dey-image-qt,dey-image-aws
ccimx6qpsbc DONTBUILDVARIANTS dey-image-qt,dey-image-aws
ccimx6sbc DONTBUILDVARIANTS dey-image-qt,dey-image-aws
ccimx6ulsbc DONTBUILDVARIANTS dey-image-qt,dey-image-aws
ccimx6ulstarter DONTBUILDVARIANTS core-image-base,dey-image-aws
ccimx6ulsom DONTBUILDVARIANTS dey-image-mft-module-min

View File

@ -1,22 +0,0 @@
# POKY_BBLAYERS_CONF_VERSION is increased each time build/conf/bblayers.conf
# changes incompatibly
POKY_BBLAYERS_CONF_VERSION = "2"
BBPATH = "${TOPDIR}"
BBFILES ?= ""
BBLAYERS ?= " \
##OEROOT##/meta \
##OEROOT##/meta-poky \
##OEROOT##/meta-yocto-bsp \
##DIGIBASE##/meta-openembedded/meta-oe \
##DIGIBASE##/meta-openembedded/meta-python \
##DIGIBASE##/meta-openembedded/meta-networking \
##DIGIBASE##/meta-openembedded/meta-webserver \
##DIGIBASE##/meta-qt5 \
##DIGIBASE##/meta-swupdate \
##DIGIBASE##/meta-freescale \
##DIGIBASE##/meta-fsl-demos \
##DIGIBASE##/meta-digi/meta-digi-arm \
##DIGIBASE##/meta-digi/meta-digi-dey \
"

View File

@ -1,18 +0,0 @@
Digi Embedded Yocto provides the following image recipes:
* dey-image-qt: graphical QT image
By default the image is X11-based so it provides a full SATO theme
desktop environment.
To compile the image for the framebuffer (instead of X11) add the
following line to the project's conf/local.conf:
DISTRO_FEATURES_remove = "x11"
* dey-image-aws: console-only image supporting Amazon Web Services IoT
This image includes the AWS Greengrass Core and an AWS IoT platform
example application. For more information on AWS support in Digi
Embedded Yocto see the online documentation.

View File

@ -1,266 +0,0 @@
#
# This file is your local configuration file and is where all local user settings
# are placed. The comments in this file give some guide to the options a new user
# to the system might want to change but pretty much any configuration option can
# be set in this file. More adventurous users can look at local.conf.extended
# which contains other examples of configuration which can be placed in this file
# but new users likely won't need any of them initially.
#
# Lines starting with the '#' character are commented out and in some cases the
# default values are provided as comments to show people example syntax. Enabling
# the option is a question of removing the # character and making any change to the
# variable as required.
#
# Machine Selection
#
# You need to select a specific machine to target the build with. There are a selection
# of emulated machines available which can boot and run in the QEMU emulator:
#
#MACHINE ?= "qemuarm"
#MACHINE ?= "qemuarm64"
#MACHINE ?= "qemumips"
#MACHINE ?= "qemumips64"
#MACHINE ?= "qemuppc"
#MACHINE ?= "qemux86"
#MACHINE ?= "qemux86-64"
#
# There are also the following hardware board target machines included for
# demonstration purposes:
#
#MACHINE ?= "beaglebone-yocto"
#MACHINE ?= "genericx86"
#MACHINE ?= "genericx86-64"
#MACHINE ?= "mpc8315e-rdb"
#MACHINE ?= "edgerouter"
#
# This sets the default machine to be qemux86 if no other machine is selected:
#MACHINE ??= "qemux86"
MACHINE = "ccimx6qpsbc"
#
# Use Digi's internal git repositories
#
#DIGI_INTERNAL_GIT ?= "1"
#
# Where to place downloads
#
# During a first build the system will download many different source code tarballs
# from various upstream projects. This can take a while, particularly if your network
# connection is slow. These are all stored in DL_DIR. When wiping and rebuilding you
# can preserve this directory to speed up this part of subsequent builds. This directory
# is safe to share between multiple builds on the same machine too.
#
# The default is a downloads directory under TOPDIR which is the build directory.
#
#DL_DIR ?= "${TOPDIR}/downloads"
#
# Where to place shared-state files
#
# BitBake has the capability to accelerate builds based on previously built output.
# This is done using "shared state" files which can be thought of as cache objects
# and this option determines where those files are placed.
#
# You can wipe out TMPDIR leaving this directory intact and the build would regenerate
# from these files if no changes were made to the configuration. If changes were made
# to the configuration, only shared state files where the state was still valid would
# be used (done using checksums).
#
# The default is a sstate-cache directory under TOPDIR.
#
#SSTATE_DIR ?= "${TOPDIR}/sstate-cache"
#
# Where to place the build output
#
# This option specifies where the bulk of the building work should be done and
# where BitBake should place its temporary files and output. Keep in mind that
# this includes the extraction and compilation of many applications and the toolchain
# which can use Gigabytes of hard disk space.
#
# The default is a tmp directory under TOPDIR.
#
#TMPDIR = "${TOPDIR}/tmp"
#
# Default policy config
#
# The distribution setting controls which policy settings are used as defaults.
# The default value is fine for general Yocto project use, at least initially.
# Ultimately when creating custom policy, people will likely end up subclassing
# these defaults.
#
DISTRO ?= "dey"
# As an example of a subclass there is a "bleeding" edge policy configuration
# where many versions are set to the absolute latest code from the upstream
# source control systems. This is just mentioned here as an example, its not
# useful to most new users.
# DISTRO ?= "poky-bleeding"
#
# Package Management configuration
#
# This variable lists which packaging formats to enable. Multiple package backends
# can be enabled at once and the first item listed in the variable will be used
# to generate the root filesystems.
# Options are:
# - 'package_deb' for debian style deb files
# - 'package_ipk' for ipk files are used by opkg (a debian style embedded package manager)
# - 'package_rpm' for rpm style packages
# E.g.: PACKAGE_CLASSES ?= "package_rpm package_deb package_ipk"
# We default to rpm:
PACKAGE_CLASSES ?= "package_rpm"
#
# SDK target architecture
#
# This variable specifies the architecture to build SDK items for and means
# you can build the SDK packages for architectures other than the machine you are
# running the build on (i.e. building i686 packages on an x86_64 host).
# Supported values are i686 and x86_64
#SDKMACHINE ?= "i686"
#
# Extra image configuration defaults
#
# The EXTRA_IMAGE_FEATURES variable allows extra packages to be added to the generated
# images. Some of these options are added to certain image types automatically. The
# variable can contain the following options:
# "dbg-pkgs" - add -dbg packages for all installed packages
# (adds symbol information for debugging/profiling)
# "dev-pkgs" - add -dev packages for all installed packages
# (useful if you want to develop against libs in the image)
# "ptest-pkgs" - add -ptest packages for all ptest-enabled packages
# (useful if you want to run the package test suites)
# "tools-sdk" - add development tools (gcc, make, pkgconfig etc.)
# "tools-debug" - add debugging tools (gdb, strace)
# "eclipse-debug" - add Eclipse remote debugging support
# "tools-profile" - add profiling tools (oprofile, lttng, valgrind)
# "tools-testapps" - add useful testing tools (ts_print, aplay, arecord etc.)
# "debug-tweaks" - make an image suitable for development
# e.g. ssh root access has a blank password
# There are other application targets that can be used here too, see
# meta/classes/image.bbclass and meta/classes/core-image.bbclass for more details.
# We default to enabling the debugging tweaks.
EXTRA_IMAGE_FEATURES ?= "debug-tweaks"
#
# Additional image features
#
# The following is a list of additional classes to use when building images which
# enable extra features. Some available options which can be included in this variable
# are:
# - 'buildstats' collect build statistics
# - 'image-mklibs' to reduce shared library files size for an image
# - 'image-prelink' in order to prelink the filesystem image
# NOTE: if listing mklibs & prelink both, then make sure mklibs is before prelink
# NOTE: mklibs also needs to be explicitly enabled for a given image, see local.conf.extended
USER_CLASSES ?= "buildstats image-mklibs image-prelink"
#
# Runtime testing of images
#
# The build system can test booting virtual machine images under qemu (an emulator)
# after any root filesystems are created and run tests against those images. It can also
# run tests against any SDK that are built. To enable this uncomment these lines.
# See classes/test{image,sdk}.bbclass for further details.
#IMAGE_CLASSES += "testimage testsdk"
#TESTIMAGE_AUTO_qemuall = "1"
#
# Interactive shell configuration
#
# Under certain circumstances the system may need input from you and to do this it
# can launch an interactive shell. It needs to do this since the build is
# multithreaded and needs to be able to handle the case where more than one parallel
# process may require the user's attention. The default is iterate over the available
# terminal types to find one that works.
#
# Examples of the occasions this may happen are when resolving patches which cannot
# be applied, to use the devshell or the kernel menuconfig
#
# Supported values are auto, gnome, xfce, rxvt, screen, konsole (KDE 3.x only), none
# Note: currently, Konsole support only works for KDE 3.x due to the way
# newer Konsole versions behave
#OE_TERMINAL = "auto"
# By default disable interactive patch resolution (tasks will just fail instead):
PATCHRESOLVE = "noop"
#
# Disk Space Monitoring during the build
#
# Monitor the disk space during the build. If there is less that 1GB of space or less
# than 100K inodes in any key build location (TMPDIR, DL_DIR, SSTATE_DIR), gracefully
# shutdown the build. If there is less that 100MB or 1K inodes, perform a hard abort
# of the build. The reason for this is that running completely out of space can corrupt
# files and damages the build in ways which may not be easily recoverable.
# It's necesary to monitor /tmp, if there is no space left the build will fail
# with very exotic errors.
BB_DISKMON_DIRS ??= "\
STOPTASKS,${TMPDIR},1G,100K \
STOPTASKS,${DL_DIR},1G,100K \
STOPTASKS,${SSTATE_DIR},1G,100K \
STOPTASKS,/tmp,100M,100K \
ABORT,${TMPDIR},100M,1K \
ABORT,${DL_DIR},100M,1K \
ABORT,${SSTATE_DIR},100M,1K \
ABORT,/tmp,10M,1K"
#
# Shared-state files from other locations
#
# As mentioned above, shared state files are prebuilt cache data objects which can
# used to accelerate build time. This variable can be used to configure the system
# to search other mirror locations for these objects before it builds the data itself.
#
# This can be a filesystem directory, or a remote url such as http or ftp. These
# would contain the sstate-cache results from previous builds (possibly from other
# machines). This variable works like fetcher MIRRORS/PREMIRRORS and points to the
# cache locations to check for the shared objects.
# NOTE: if the mirror uses the same structure as SSTATE_DIR, you need to add PATH
# at the end as shown in the examples below. This will be substituted with the
# correct path within the directory structure.
#SSTATE_MIRRORS ?= "\
#file://.* http://someserver.tld/share/sstate/PATH;downloadfilename=PATH \n \
#file://.* file:///some/local/dir/sstate/PATH"
#
# Yocto Project SState Mirror
#
# The Yocto Project has prebuilt artefacts available for its releases, you can enable
# use of these by uncommenting the following line. This will mean the build uses
# the network to check for artefacts at the start of builds, which does slow it down
# equally, it will also speed up the builds by not having to build things if they are
# present in the cache. It assumes you can download something faster than you can build it
# which will depend on your network.
#
#SSTATE_MIRRORS ?= "file://.* http://sstate.yoctoproject.org/2.5/PATH;downloadfilename=PATH"
#
# Qemu configuration
#
# By default qemu will build with a builtin VNC server where graphical output can be
# seen. The two lines below enable the SDL backend too. By default libsdl2-native will
# be built, if you want to use your host's libSDL instead of the minimal libsdl built
# by libsdl2-native then uncomment the ASSUME_PROVIDED line below.
PACKAGECONFIG_append_pn-qemu-native = " sdl"
PACKAGECONFIG_append_pn-nativesdk-qemu = " sdl"
#ASSUME_PROVIDED += "libsdl2-native"
# CONF_VERSION is increased each time build/conf/ changes incompatibly and is used to
# track the version of this file when it was generated. This can safely be ignored if
# this doesn't mean anything to you.
CONF_VERSION = "1"
#
# Enable local PR server
#
PRSERV_HOST = "localhost:0"
#
# Some libraries and packages are covered by NXP EULA
#
#ACCEPT_FSL_EULA = "1"

View File

@ -1,22 +0,0 @@
# POKY_BBLAYERS_CONF_VERSION is increased each time build/conf/bblayers.conf
# changes incompatibly
POKY_BBLAYERS_CONF_VERSION = "2"
BBPATH = "${TOPDIR}"
BBFILES ?= ""
BBLAYERS ?= " \
##OEROOT##/meta \
##OEROOT##/meta-poky \
##OEROOT##/meta-yocto-bsp \
##DIGIBASE##/meta-openembedded/meta-oe \
##DIGIBASE##/meta-openembedded/meta-python \
##DIGIBASE##/meta-openembedded/meta-networking \
##DIGIBASE##/meta-openembedded/meta-webserver \
##DIGIBASE##/meta-qt5 \
##DIGIBASE##/meta-swupdate \
##DIGIBASE##/meta-freescale \
##DIGIBASE##/meta-fsl-demos \
##DIGIBASE##/meta-digi/meta-digi-arm \
##DIGIBASE##/meta-digi/meta-digi-dey \
"

View File

@ -1,18 +0,0 @@
Digi Embedded Yocto provides the following image recipes:
* dey-image-qt: graphical QT image
By default the image is X11-based so it provides a full SATO theme
desktop environment.
To compile the image for the framebuffer (instead of X11) add the
following line to the project's conf/local.conf:
DISTRO_FEATURES_remove = "x11"
* dey-image-aws: console-only image supporting Amazon Web Services IoT
This image includes the AWS Greengrass Core and an AWS IoT platform
example application. For more information on AWS support in Digi
Embedded Yocto see the online documentation.

View File

@ -1,266 +0,0 @@
#
# This file is your local configuration file and is where all local user settings
# are placed. The comments in this file give some guide to the options a new user
# to the system might want to change but pretty much any configuration option can
# be set in this file. More adventurous users can look at local.conf.extended
# which contains other examples of configuration which can be placed in this file
# but new users likely won't need any of them initially.
#
# Lines starting with the '#' character are commented out and in some cases the
# default values are provided as comments to show people example syntax. Enabling
# the option is a question of removing the # character and making any change to the
# variable as required.
#
# Machine Selection
#
# You need to select a specific machine to target the build with. There are a selection
# of emulated machines available which can boot and run in the QEMU emulator:
#
#MACHINE ?= "qemuarm"
#MACHINE ?= "qemuarm64"
#MACHINE ?= "qemumips"
#MACHINE ?= "qemumips64"
#MACHINE ?= "qemuppc"
#MACHINE ?= "qemux86"
#MACHINE ?= "qemux86-64"
#
# There are also the following hardware board target machines included for
# demonstration purposes:
#
#MACHINE ?= "beaglebone-yocto"
#MACHINE ?= "genericx86"
#MACHINE ?= "genericx86-64"
#MACHINE ?= "mpc8315e-rdb"
#MACHINE ?= "edgerouter"
#
# This sets the default machine to be qemux86 if no other machine is selected:
#MACHINE ??= "qemux86"
MACHINE = "ccimx6sbc"
#
# Use Digi's internal git repositories
#
#DIGI_INTERNAL_GIT ?= "1"
#
# Where to place downloads
#
# During a first build the system will download many different source code tarballs
# from various upstream projects. This can take a while, particularly if your network
# connection is slow. These are all stored in DL_DIR. When wiping and rebuilding you
# can preserve this directory to speed up this part of subsequent builds. This directory
# is safe to share between multiple builds on the same machine too.
#
# The default is a downloads directory under TOPDIR which is the build directory.
#
#DL_DIR ?= "${TOPDIR}/downloads"
#
# Where to place shared-state files
#
# BitBake has the capability to accelerate builds based on previously built output.
# This is done using "shared state" files which can be thought of as cache objects
# and this option determines where those files are placed.
#
# You can wipe out TMPDIR leaving this directory intact and the build would regenerate
# from these files if no changes were made to the configuration. If changes were made
# to the configuration, only shared state files where the state was still valid would
# be used (done using checksums).
#
# The default is a sstate-cache directory under TOPDIR.
#
#SSTATE_DIR ?= "${TOPDIR}/sstate-cache"
#
# Where to place the build output
#
# This option specifies where the bulk of the building work should be done and
# where BitBake should place its temporary files and output. Keep in mind that
# this includes the extraction and compilation of many applications and the toolchain
# which can use Gigabytes of hard disk space.
#
# The default is a tmp directory under TOPDIR.
#
#TMPDIR = "${TOPDIR}/tmp"
#
# Default policy config
#
# The distribution setting controls which policy settings are used as defaults.
# The default value is fine for general Yocto project use, at least initially.
# Ultimately when creating custom policy, people will likely end up subclassing
# these defaults.
#
DISTRO ?= "dey"
# As an example of a subclass there is a "bleeding" edge policy configuration
# where many versions are set to the absolute latest code from the upstream
# source control systems. This is just mentioned here as an example, its not
# useful to most new users.
# DISTRO ?= "poky-bleeding"
#
# Package Management configuration
#
# This variable lists which packaging formats to enable. Multiple package backends
# can be enabled at once and the first item listed in the variable will be used
# to generate the root filesystems.
# Options are:
# - 'package_deb' for debian style deb files
# - 'package_ipk' for ipk files are used by opkg (a debian style embedded package manager)
# - 'package_rpm' for rpm style packages
# E.g.: PACKAGE_CLASSES ?= "package_rpm package_deb package_ipk"
# We default to rpm:
PACKAGE_CLASSES ?= "package_rpm"
#
# SDK target architecture
#
# This variable specifies the architecture to build SDK items for and means
# you can build the SDK packages for architectures other than the machine you are
# running the build on (i.e. building i686 packages on an x86_64 host).
# Supported values are i686 and x86_64
#SDKMACHINE ?= "i686"
#
# Extra image configuration defaults
#
# The EXTRA_IMAGE_FEATURES variable allows extra packages to be added to the generated
# images. Some of these options are added to certain image types automatically. The
# variable can contain the following options:
# "dbg-pkgs" - add -dbg packages for all installed packages
# (adds symbol information for debugging/profiling)
# "dev-pkgs" - add -dev packages for all installed packages
# (useful if you want to develop against libs in the image)
# "ptest-pkgs" - add -ptest packages for all ptest-enabled packages
# (useful if you want to run the package test suites)
# "tools-sdk" - add development tools (gcc, make, pkgconfig etc.)
# "tools-debug" - add debugging tools (gdb, strace)
# "eclipse-debug" - add Eclipse remote debugging support
# "tools-profile" - add profiling tools (oprofile, lttng, valgrind)
# "tools-testapps" - add useful testing tools (ts_print, aplay, arecord etc.)
# "debug-tweaks" - make an image suitable for development
# e.g. ssh root access has a blank password
# There are other application targets that can be used here too, see
# meta/classes/image.bbclass and meta/classes/core-image.bbclass for more details.
# We default to enabling the debugging tweaks.
EXTRA_IMAGE_FEATURES ?= "debug-tweaks"
#
# Additional image features
#
# The following is a list of additional classes to use when building images which
# enable extra features. Some available options which can be included in this variable
# are:
# - 'buildstats' collect build statistics
# - 'image-mklibs' to reduce shared library files size for an image
# - 'image-prelink' in order to prelink the filesystem image
# NOTE: if listing mklibs & prelink both, then make sure mklibs is before prelink
# NOTE: mklibs also needs to be explicitly enabled for a given image, see local.conf.extended
USER_CLASSES ?= "buildstats image-mklibs image-prelink"
#
# Runtime testing of images
#
# The build system can test booting virtual machine images under qemu (an emulator)
# after any root filesystems are created and run tests against those images. It can also
# run tests against any SDK that are built. To enable this uncomment these lines.
# See classes/test{image,sdk}.bbclass for further details.
#IMAGE_CLASSES += "testimage testsdk"
#TESTIMAGE_AUTO_qemuall = "1"
#
# Interactive shell configuration
#
# Under certain circumstances the system may need input from you and to do this it
# can launch an interactive shell. It needs to do this since the build is
# multithreaded and needs to be able to handle the case where more than one parallel
# process may require the user's attention. The default is iterate over the available
# terminal types to find one that works.
#
# Examples of the occasions this may happen are when resolving patches which cannot
# be applied, to use the devshell or the kernel menuconfig
#
# Supported values are auto, gnome, xfce, rxvt, screen, konsole (KDE 3.x only), none
# Note: currently, Konsole support only works for KDE 3.x due to the way
# newer Konsole versions behave
#OE_TERMINAL = "auto"
# By default disable interactive patch resolution (tasks will just fail instead):
PATCHRESOLVE = "noop"
#
# Disk Space Monitoring during the build
#
# Monitor the disk space during the build. If there is less that 1GB of space or less
# than 100K inodes in any key build location (TMPDIR, DL_DIR, SSTATE_DIR), gracefully
# shutdown the build. If there is less that 100MB or 1K inodes, perform a hard abort
# of the build. The reason for this is that running completely out of space can corrupt
# files and damages the build in ways which may not be easily recoverable.
# It's necesary to monitor /tmp, if there is no space left the build will fail
# with very exotic errors.
BB_DISKMON_DIRS ??= "\
STOPTASKS,${TMPDIR},1G,100K \
STOPTASKS,${DL_DIR},1G,100K \
STOPTASKS,${SSTATE_DIR},1G,100K \
STOPTASKS,/tmp,100M,100K \
ABORT,${TMPDIR},100M,1K \
ABORT,${DL_DIR},100M,1K \
ABORT,${SSTATE_DIR},100M,1K \
ABORT,/tmp,10M,1K"
#
# Shared-state files from other locations
#
# As mentioned above, shared state files are prebuilt cache data objects which can
# used to accelerate build time. This variable can be used to configure the system
# to search other mirror locations for these objects before it builds the data itself.
#
# This can be a filesystem directory, or a remote url such as http or ftp. These
# would contain the sstate-cache results from previous builds (possibly from other
# machines). This variable works like fetcher MIRRORS/PREMIRRORS and points to the
# cache locations to check for the shared objects.
# NOTE: if the mirror uses the same structure as SSTATE_DIR, you need to add PATH
# at the end as shown in the examples below. This will be substituted with the
# correct path within the directory structure.
#SSTATE_MIRRORS ?= "\
#file://.* http://someserver.tld/share/sstate/PATH;downloadfilename=PATH \n \
#file://.* file:///some/local/dir/sstate/PATH"
#
# Yocto Project SState Mirror
#
# The Yocto Project has prebuilt artefacts available for its releases, you can enable
# use of these by uncommenting the following line. This will mean the build uses
# the network to check for artefacts at the start of builds, which does slow it down
# equally, it will also speed up the builds by not having to build things if they are
# present in the cache. It assumes you can download something faster than you can build it
# which will depend on your network.
#
#SSTATE_MIRRORS ?= "file://.* http://sstate.yoctoproject.org/2.5/PATH;downloadfilename=PATH"
#
# Qemu configuration
#
# By default qemu will build with a builtin VNC server where graphical output can be
# seen. The two lines below enable the SDL backend too. By default libsdl2-native will
# be built, if you want to use your host's libSDL instead of the minimal libsdl built
# by libsdl2-native then uncomment the ASSUME_PROVIDED line below.
PACKAGECONFIG_append_pn-qemu-native = " sdl"
PACKAGECONFIG_append_pn-nativesdk-qemu = " sdl"
#ASSUME_PROVIDED += "libsdl2-native"
# CONF_VERSION is increased each time build/conf/ changes incompatibly and is used to
# track the version of this file when it was generated. This can safely be ignored if
# this doesn't mean anything to you.
CONF_VERSION = "1"
#
# Enable local PR server
#
PRSERV_HOST = "localhost:0"
#
# Some libraries and packages are covered by NXP EULA
#
#ACCEPT_FSL_EULA = "1"