summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--meta-edison-arduino/conf/layer.conf10
-rw-r--r--meta-edison-arduino/recipes-core/images/edison-image.bbappend2
-rw-r--r--meta-edison-arduino/recipes-devtools/clloader/clloader.bb53
-rw-r--r--meta-edison-arduino/recipes-devtools/clloader/files/clloader.service10
-rw-r--r--meta-edison-arduino/recipes-devtools/clloader/files/sketch_reset.service11
-rw-r--r--meta-edison-devenv/conf/layer.conf14
-rw-r--r--meta-edison-devenv/recipes-bsp/u-boot/u-boot-fw-utils_2014.04.bbappend3
-rw-r--r--meta-edison-devenv/recipes-bsp/u-boot/u-boot-internal-devenv.inc6
-rw-r--r--meta-edison-devenv/recipes-bsp/u-boot/u-boot-tools_2014.04.bbappend2
-rw-r--r--meta-edison-devenv/recipes-bsp/u-boot/u-boot_2014.04.bbappend5
-rw-r--r--meta-edison-devenv/recipes-kernel/linux/linux-externalsrc.bb44
-rw-r--r--meta-edison-devtools/COPYING.MIT17
-rw-r--r--meta-edison-devtools/conf/layer.conf10
-rw-r--r--meta-edison-devtools/recipes-benchmark/bonnie/bonnie++_1.03c.bb30
-rw-r--r--meta-edison-devtools/recipes-benchmark/bonnie/files/gcc-4.3-fixes.patch20
-rw-r--r--meta-edison-devtools/recipes-connectivity/bcm43340-tools/dhdutil.bb15
-rw-r--r--meta-edison-devtools/recipes-connectivity/bcm43340-tools/wlx.bb19
-rw-r--r--meta-edison-devtools/recipes-connectivity/wfa-tool/wfa-tool.bb37
-rw-r--r--meta-edison-devtools/recipes-support/peeknpoke/peeknpoke_1.1.bb13
-rw-r--r--meta-edison-distro/COPYING.MIT17
-rw-r--r--meta-edison-distro/README118
-rw-r--r--meta-edison-distro/README.sources17
-rw-r--r--meta-edison-distro/conf/distro/poky-edison.conf20
-rw-r--r--meta-edison-distro/conf/layer.conf10
-rw-r--r--meta-edison-distro/files/fs-perms.txt69
-rw-r--r--meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/000-Iperf_Fix-CPU-Usage.diff164
-rw-r--r--meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/001-cast-to-max_size_t-instead-of-int.patch14
-rw-r--r--meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/003-fix-hyphen-used-as-minus-sign.patch178
-rw-r--r--meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/004-svn-r43-ro.patch117
-rw-r--r--meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/005-iperf-die-on-bind-fail.patch15
-rw-r--r--meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/006-iperf-die-on-connect-fail.patch15
-rw-r--r--meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/007-iperf-reporter-deadlock.patch68
-rw-r--r--meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/008-numofreport.patch15
-rw-r--r--meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/009-delayloop.patch22
-rw-r--r--meta-edison-distro/recipes-benchmark/iperf/iperf_2.0.4.bb46
-rw-r--r--meta-edison-distro/recipes-connectivity/bluetooth-rfkill-event/COPYING14
-rw-r--r--meta-edison-distro/recipes-connectivity/bluetooth-rfkill-event/bluetooth-rfkill-event_1.0.bb41
-rw-r--r--meta-edison-distro/recipes-connectivity/bluetooth-rfkill-event/files/bcm43341.conf32
-rw-r--r--meta-edison-distro/recipes-connectivity/bluetooth-rfkill-event/files/bluetooth-rfkill-event.service10
-rw-r--r--meta-edison-distro/recipes-connectivity/bluetooth-rfkill-event/files/bluetooth_rfkill_event.c614
-rw-r--r--meta-edison-distro/recipes-connectivity/bluez5/bluez5_5.15.bbappend62
-rw-r--r--meta-edison-distro/recipes-connectivity/bluez5/files/bluetooth.conf24
-rw-r--r--meta-edison-distro/recipes-connectivity/bluez5/files/obex_set_dbus_session_service.patch10
-rw-r--r--meta-edison-distro/recipes-connectivity/connman/connman.inc215
-rw-r--r--meta-edison-distro/recipes-connectivity/connman/connman/0001-plugin.h-Change-visibility-to-default-for-debug-symb.patch35
-rw-r--r--meta-edison-distro/recipes-connectivity/connman/connman/add_xuser_dbus_permission.patch21
-rw-r--r--meta-edison-distro/recipes-connectivity/connman/connman/connman83
-rw-r--r--meta-edison-distro/recipes-connectivity/connman/connman/disable_p2p.patch15
-rw-r--r--meta-edison-distro/recipes-connectivity/connman/connman_1.27.bb11
-rw-r--r--meta-edison-distro/recipes-connectivity/connman/connman_1.27.bbappend35
-rw-r--r--meta-edison-distro/recipes-connectivity/hostapd/files/defconfig145
-rw-r--r--meta-edison-distro/recipes-connectivity/hostapd/files/hostapd.conf-sane1662
-rw-r--r--meta-edison-distro/recipes-connectivity/hostapd/files/hostapd.service23
-rw-r--r--meta-edison-distro/recipes-connectivity/hostapd/files/udhcpd-for-hostapd.conf107
-rw-r--r--meta-edison-distro/recipes-connectivity/hostapd/files/udhcpd-for-hostapd.service15
-rw-r--r--meta-edison-distro/recipes-connectivity/hostapd/hostapd-daemon_2.1.bb51
-rw-r--r--meta-edison-distro/recipes-connectivity/libpcap/libpcap_1.5.3.bbappend2
-rw-r--r--meta-edison-distro/recipes-connectivity/ofono/ofono_1.14.bbappend1
-rw-r--r--meta-edison-distro/recipes-connectivity/openssh/openssh/sshd.socket13
-rw-r--r--meta-edison-distro/recipes-connectivity/openssh/openssh/sshdgenkeys.service7
-rw-r--r--meta-edison-distro/recipes-connectivity/openssh/openssh_%.bbappend1
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/cryptodev-linux_1.6.bb22
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl.inc173
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/configure-targets.patch34
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/debian/c_rehash-compat.patch45
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/debian/ca.patch22
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/debian/debian-targets.patch66
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/debian/make-targets.patch15
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/debian/man-dir.patch15
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/debian/man-section.patch34
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/debian/no-rpath.patch15
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/debian/no-symbolic.patch15
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/debian/pic.patch177
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/debian/version-script.patch4670
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/engines-install-in-libdir-ssl.patch56
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/find.pl54
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/fix-cipher-des-ede3-cfb1.patch22
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/initial-aarch64-bits.patch119
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/oe-ldflags.patch24
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-1.0.1e-cve-2014-0195.patch40
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-1.0.1e-cve-2014-0198.patch38
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-1.0.1e-cve-2014-0221.patch38
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-1.0.1e-cve-2014-0224.patch103
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-1.0.1e-cve-2014-3470.patch31
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-CVE-2010-5298.patch24
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-CVE-2014-0198-fix.patch23
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-avoid-NULL-pointer-dereference-in-EVP_DigestInit_ex.patch21
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-avoid-NULL-pointer-dereference-in-dh_pub_encode.patch39
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-fix-des.pod-error.patch19
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-fix-doc.patch401
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-fix-link.patch35
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/openssl_fix_for_x32.patch90
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl/shared-libs.patch41
-rw-r--r--meta-edison-distro/recipes-connectivity/openssl/openssl_1.0.1j.bb54
-rw-r--r--meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/99_wpa_supplicant1
-rw-r--r--meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/defconfig-gnutls440
-rw-r--r--meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/fi.w1.wpa_supplicant1.service5
-rw-r--r--meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/fix-libnl3-host-contamination.patch42
-rw-r--r--meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/p2p_supplicant.conf-sane12
-rw-r--r--meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/register-autoscan-correctly.patch51
-rw-r--r--meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/udhcpd-p2p.conf107
-rw-r--r--meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa-supplicant-android-4.4.4_r2.0.1.patch184
-rw-r--r--meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa-supplicant.sh85
-rw-r--r--meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa_cli-actions.sh88
-rw-r--r--meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa_supplicant.conf-sane10
-rw-r--r--meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa_supplicant.service21
-rw-r--r--meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa_supplicant_p2p_event.service13
-rw-r--r--meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa_supplicant_wlan0_event.service13
-rw-r--r--meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant_2.1.bbappend96
-rw-r--r--meta-edison-distro/recipes-core/base-files/base-files/factory.mount12
-rw-r--r--meta-edison-distro/recipes-core/base-files/base-files/fstab9
-rw-r--r--meta-edison-distro/recipes-core/base-files/base-files/media-sdcard.automount11
-rw-r--r--meta-edison-distro/recipes-core/base-files/base-files/media-sdcard.mount9
-rw-r--r--meta-edison-distro/recipes-core/base-files/base-files/share/dot.profile9
-rw-r--r--meta-edison-distro/recipes-core/base-files/base-files_3.0.14.bbappend33
-rw-r--r--meta-edison-distro/recipes-core/busybox/busybox_1.22.1.bbappend5
-rw-r--r--meta-edison-distro/recipes-core/busybox/files/brctl-utilities.cfg2
-rw-r--r--meta-edison-distro/recipes-core/busybox/files/busybox-log.cfg3
-rw-r--r--meta-edison-distro/recipes-core/first-install/files/first-install.service9
-rw-r--r--meta-edison-distro/recipes-core/first-install/files/first-install.sh185
-rw-r--r--meta-edison-distro/recipes-core/first-install/files/first-install.target7
-rw-r--r--meta-edison-distro/recipes-core/first-install/first-install.bb40
-rw-r--r--meta-edison-distro/recipes-core/images/edison-image.bb130
-rw-r--r--meta-edison-distro/recipes-core/ota-update/files/ota-update.service9
-rw-r--r--meta-edison-distro/recipes-core/ota-update/files/ota-update.sh149
-rw-r--r--meta-edison-distro/recipes-core/ota-update/files/ota-update.target7
-rw-r--r--meta-edison-distro/recipes-core/ota-update/ota-update.bb40
-rw-r--r--meta-edison-distro/recipes-core/readline/files/readline-fix-segfault-when-pressing-DEL-key-twice.patch39
-rw-r--r--meta-edison-distro/recipes-core/readline/readline_6.3.bbappend4
-rw-r--r--meta-edison-distro/recipes-core/resize-rootfs/files/resize-rootfs.service14
-rw-r--r--meta-edison-distro/recipes-core/resize-rootfs/resize-rootfs.bb24
-rw-r--r--meta-edison-distro/recipes-core/systemd/files/edison-machine-id.service14
-rw-r--r--meta-edison-distro/recipes-core/systemd/files/hsu-pm-runtime.service14
-rw-r--r--meta-edison-distro/recipes-core/systemd/files/journald.conf36
-rw-r--r--meta-edison-distro/recipes-core/systemd/files/system.conf45
-rw-r--r--meta-edison-distro/recipes-core/systemd/files/systemd-reboot-service.patch9
-rw-r--r--meta-edison-distro/recipes-core/systemd/files/timesyncd.conf12
-rw-r--r--meta-edison-distro/recipes-core/systemd/files/usb0.network6
-rw-r--r--meta-edison-distro/recipes-core/systemd/systemd-compat-units.bb41
-rw-r--r--meta-edison-distro/recipes-core/systemd/systemd-serialgetty.bb49
-rw-r--r--meta-edison-distro/recipes-core/systemd/systemd-serialgetty/serial-getty@.service37
-rw-r--r--meta-edison-distro/recipes-core/systemd/systemd-systemctl-native.bb15
-rwxr-xr-xmeta-edison-distro/recipes-core/systemd/systemd-systemctl/systemctl153
-rw-r--r--meta-edison-distro/recipes-core/systemd/systemd/00-create-volatile.conf6
-rw-r--r--meta-edison-distro/recipes-core/systemd/systemd/0001-uClibc-doesn-t-implement-pwritev-preadv.patch34
-rw-r--r--meta-edison-distro/recipes-core/systemd/systemd/binfmt-install.patch56
-rw-r--r--meta-edison-distro/recipes-core/systemd/systemd/init104
-rw-r--r--meta-edison-distro/recipes-core/systemd/systemd/optional_secure_getenv.patch19
-rw-r--r--meta-edison-distro/recipes-core/systemd/systemd/run-ptest3
-rw-r--r--meta-edison-distro/recipes-core/systemd/systemd/systemd-older-kernel.patch56
-rw-r--r--meta-edison-distro/recipes-core/systemd/systemd/systemd-pam-configure-check-uclibc.patch32
-rw-r--r--meta-edison-distro/recipes-core/systemd/systemd/systemd-pam-fix-execvpe.patch29
-rw-r--r--meta-edison-distro/recipes-core/systemd/systemd/systemd-pam-fix-fallocate.patch92
-rw-r--r--meta-edison-distro/recipes-core/systemd/systemd/systemd-pam-fix-getty-unit.patch35
-rw-r--r--meta-edison-distro/recipes-core/systemd/systemd/systemd-pam-fix-mkostemp.patch30
-rw-r--r--meta-edison-distro/recipes-core/systemd/systemd/touchscreen.rules18
-rw-r--r--meta-edison-distro/recipes-core/systemd/systemd/uclibc-get-physmem.patch37
-rw-r--r--meta-edison-distro/recipes-core/systemd/systemd/uclibc-sysinfo_h.patch19
-rw-r--r--meta-edison-distro/recipes-core/systemd/systemd_%.bbappend34
-rw-r--r--meta-edison-distro/recipes-core/systemd/systemd_213.bb351
-rw-r--r--meta-edison-distro/recipes-devtools/e2fsprogs/e2fsprogs_%.bbappend11
-rw-r--r--meta-edison-distro/recipes-devtools/swig/swig.inc63
-rw-r--r--meta-edison-distro/recipes-devtools/swig/swig/0001-Use-proc-self-exe-for-swig-swiglib-on-non-Win32-plat.patch56
-rw-r--r--meta-edison-distro/recipes-devtools/swig/swig/0001-configure-use-pkg-config-for-pcre-detection.patch55
-rw-r--r--meta-edison-distro/recipes-devtools/swig/swig_3.0.2.bb8
-rw-r--r--meta-edison-distro/recipes-multimedia/alsa/alsa-utils_%.bbappend13
-rw-r--r--meta-edison-distro/recipes-multimedia/alsa/files/asound.state14141
-rw-r--r--meta-edison-distro/recipes-multimedia/libav/libav_0.8.9.bbappend23
-rw-r--r--meta-edison-distro/recipes-multimedia/mplayer/mplayer-common.bb22
-rw-r--r--meta-edison-distro/recipes-multimedia/mplayer/mplayer-common/mplayer.conf15
-rw-r--r--meta-edison-distro/recipes-multimedia/mplayer/mplayer2/cross.compile.codec-cfg.patch16
-rw-r--r--meta-edison-distro/recipes-multimedia/mplayer/mplayer2_git.bb161
-rw-r--r--meta-edison-distro/recipes-multimedia/pulseaudio/files/pulseaudio.service12
-rw-r--r--meta-edison-distro/recipes-multimedia/pulseaudio/files/system.pa66
-rw-r--r--meta-edison-distro/recipes-multimedia/pulseaudio/pulseaudio-service_1.0.bb28
-rw-r--r--meta-edison-distro/recipes-multimedia/pulseaudio/pulseaudio_5.0.bbappend22
-rw-r--r--meta-edison-distro/recipes-support/blink-led/blink-led_0.1.bb23
-rwxr-xr-xmeta-edison-distro/recipes-support/blink-led/files/blink-led109
-rw-r--r--meta-edison-distro/recipes-support/blink-led/files/blink-led.service10
-rw-r--r--meta-edison-distro/recipes-support/cleanjournal/cleanjournal.bb31
-rw-r--r--meta-edison-distro/recipes-support/cleanjournal/files/clean_journal.sh60
-rw-r--r--meta-edison-distro/recipes-support/cleanjournal/files/cleanjournal.service10
-rw-r--r--meta-edison-distro/recipes-support/crashlog/crashlog.bb31
-rw-r--r--meta-edison-distro/recipes-support/crashlog/files/crashlog.service10
-rwxr-xr-xmeta-edison-distro/recipes-support/crashlog/files/retrieve_crashlog.sh98
-rw-r--r--meta-edison-distro/recipes-support/edison-mcu/files/intel_mcu.binbin0 -> 12212 bytes
-rw-r--r--meta-edison-distro/recipes-support/edison-mcu/files/mcu_fw_loader.service10
-rw-r--r--meta-edison-distro/recipes-support/edison-mcu/files/mcu_fw_loader.sh12
-rw-r--r--meta-edison-distro/recipes-support/edison-mcu/mcu-fw-bin_0.1.bb17
-rw-r--r--meta-edison-distro/recipes-support/edison-mcu/mcu-fw-load_0.1.bb23
-rw-r--r--meta-edison-distro/recipes-support/edison-sst/files/fw_sst_119a.binbin0 -> 464927 bytes
-rw-r--r--meta-edison-distro/recipes-support/edison-sst/sst-fw-bin_0.1.bb19
-rw-r--r--meta-edison-distro/recipes-support/i2c-tools/i2c-tools-3.0.3/Module.mk72
-rw-r--r--meta-edison-distro/recipes-support/i2c-tools/i2c-tools_3.0.3.bb24
-rw-r--r--meta-edison-distro/recipes-support/pwr-button-handler/files/pwr-button-handler.c167
-rw-r--r--meta-edison-distro/recipes-support/pwr-button-handler/files/pwr-button-handler.service10
-rw-r--r--meta-edison-distro/recipes-support/pwr-button-handler/pwr-button-handler_0.1.bb37
-rw-r--r--meta-edison-distro/recipes-support/tcpdump/tcpdump-4.1.1/0001-minimal-IEEE802.15.4-allowed.patch22
-rw-r--r--meta-edison-distro/recipes-support/tcpdump/tcpdump-4.1.1/configure.patch29
-rw-r--r--meta-edison-distro/recipes-support/tcpdump/tcpdump-4.1.1/ipv6-cross.patch41
-rw-r--r--meta-edison-distro/recipes-support/tcpdump/tcpdump-4.1.1/tcpdump_configure_no_-O2.patch42
-rw-r--r--meta-edison-distro/recipes-support/tcpdump/tcpdump_4.1.1.bb41
-rw-r--r--meta-edison-distro/recipes-support/watchdog-sample/watchdog-sample.bb46
-rw-r--r--meta-edison-distro/recipes-support/watchdog-sample/watchdog-sample/watchdog-sample.c92
-rw-r--r--meta-edison-distro/recipes-support/watchdog-sample/watchdog-sample/watchdog-sample.service15
-rw-r--r--meta-edison-middleware/conf/layer.conf13
-rw-r--r--meta-edison-middleware/recipes-connectivity/c-ares/c-ares_1.10.0.bb13
-rw-r--r--meta-edison-middleware/recipes-connectivity/mdns/files/build.patch191
-rw-r--r--meta-edison-middleware/recipes-connectivity/mdns/files/mdns.service15
-rw-r--r--meta-edison-middleware/recipes-connectivity/mdns/mdns_544.bb76
-rw-r--r--meta-edison-middleware/recipes-connectivity/mosquitto/files/build.patch71
-rw-r--r--meta-edison-middleware/recipes-connectivity/mosquitto/files/mosquitto.service15
-rw-r--r--meta-edison-middleware/recipes-connectivity/mosquitto/mosquitto_1.3.4.bb55
-rw-r--r--meta-edison-middleware/recipes-connectivity/paho-mqtt/files/makefile.patch19
-rw-r--r--meta-edison-middleware/recipes-connectivity/paho-mqtt/paho-mqtt_3.1.bb39
-rw-r--r--meta-edison-middleware/recipes-connectivity/sshpass/sshpass.inc10
-rw-r--r--meta-edison-middleware/recipes-connectivity/sshpass/sshpass_1.05.bb8
-rw-r--r--meta-edison-middleware/recipes-connectivity/zeromq/cppzmq_git.bb19
-rw-r--r--meta-edison-middleware/recipes-connectivity/zeromq/zeromq_4.0.4.bb15
-rw-r--r--meta-edison-middleware/recipes-core/images/edison-image.bbappend28
-rw-r--r--meta-edison-middleware/recipes-devtools/iotkit-agent/iotkit-agent_0.2.0.bb84
-rw-r--r--meta-edison-middleware/recipes-devtools/iotkit-comm-c/iotkit-comm-c_0.1.1.bb114
-rw-r--r--meta-edison-middleware/recipes-devtools/iotkit-comm-js/iotkit-comm-js_0.1.1.bb100
-rw-r--r--meta-edison-middleware/recipes-devtools/iotkit-lib-c/iotkit-lib-c_0.1.0.bb49
-rw-r--r--meta-edison-middleware/recipes-devtools/iotkit-opkg/files/iotkit.conf1
-rw-r--r--meta-edison-middleware/recipes-devtools/iotkit-opkg/iotkit-opkg_0.0.1.bb22
-rw-r--r--meta-edison-middleware/recipes-devtools/mraa/mraa_0.5.2.bb27
-rw-r--r--meta-edison-middleware/recipes-devtools/nodejs/nodejs_0.10.28.bb85
-rw-r--r--meta-edison-middleware/recipes-devtools/oobe/oobe_0.0.1.bb64
-rw-r--r--meta-edison-middleware/recipes-devtools/upm/upm_0.1.8.bb17
-rw-r--r--meta-edison-middleware/recipes-devtools/xdk-daemon/files/xdk-daemon-0.0.27.tar.bz2bin0 -> 56415 bytes
-rw-r--r--meta-edison-middleware/recipes-devtools/xdk-daemon/xdk-daemon_0.0.27.bb68
-rw-r--r--meta-edison/COPYING.MIT17
-rw-r--r--meta-edison/README118
-rw-r--r--meta-edison/README.sources17
-rw-r--r--meta-edison/conf/layer.conf10
-rw-r--r--meta-edison/conf/machine/edison.conf21
-rw-r--r--meta-edison/recipes-bsp/u-boot/files/edison.env56
-rw-r--r--meta-edison/recipes-bsp/u-boot/files/fw_env.config11
-rw-r--r--meta-edison/recipes-bsp/u-boot/files/target_env/blankcdc.env10
-rw-r--r--meta-edison/recipes-bsp/u-boot/files/target_env/blankrndis.env10
-rw-r--r--meta-edison/recipes-bsp/u-boot/files/target_env/defaultcdc.env10
-rw-r--r--meta-edison/recipes-bsp/u-boot/files/target_env/defaultrndis.env10
-rw-r--r--meta-edison/recipes-bsp/u-boot/files/target_env/ifwi.env7
-rw-r--r--meta-edison/recipes-bsp/u-boot/files/target_env/prod.env6
-rw-r--r--meta-edison/recipes-bsp/u-boot/files/upstream_to_edison.patch11158
-rw-r--r--meta-edison/recipes-bsp/u-boot/u-boot-fw-utils_2014.04.bb28
-rw-r--r--meta-edison/recipes-bsp/u-boot/u-boot-internal.inc10
-rw-r--r--meta-edison/recipes-bsp/u-boot/u-boot-osip.inc208
-rw-r--r--meta-edison/recipes-bsp/u-boot/u-boot-target-env.inc93
-rw-r--r--meta-edison/recipes-bsp/u-boot/u-boot-tools_2014.04.bb22
-rw-r--r--meta-edison/recipes-bsp/u-boot/u-boot_2014.04.bb7
-rw-r--r--meta-edison/recipes-kernel/bcm43340-bt/bcm43340-bt_1.0.bb26
-rw-r--r--meta-edison/recipes-kernel/bcm43340/.gitignore1
-rw-r--r--meta-edison/recipes-kernel/bcm43340/bcm43340-fw.bb29
-rw-r--r--meta-edison/recipes-kernel/bcm43340/bcm43340-mod.bb14
-rw-r--r--meta-edison/recipes-kernel/linux/files/defconfig3768
-rw-r--r--meta-edison/recipes-kernel/linux/files/upstream_to_edison.patch99340
-rw-r--r--meta-edison/recipes-kernel/linux/linux-yocto_3.10.bbappend8
-rw-r--r--meta-mingw/conf/layer.conf5
-rw-r--r--meta-mingw/recipes-devtools/pthreads-win32/pthreads-win32_2.9.1.bbappend1
-rwxr-xr-xsetup.sh300
-rw-r--r--utils/0001-bash-fix-CVE-2014-6271.patch254
-rw-r--r--utils/0001-busybox-handle-syslog-related-files-properly.patch74
-rw-r--r--utils/0001-kernel-kernel-yocto-fix-external-src-builds-when-S-B-poky-dora.patch170
-rw-r--r--utils/0001-libarchive-avoid-dependency-on-e2fsprogs.patch55
-rw-r--r--utils/0001-openssh-avoid-screen-sessions-being-killed-on-discon.patch36
-rw-r--r--utils/0002-bash-Fix-CVE-2014-7169.patch93
-rw-r--r--utils/Makefile.mk182
-rwxr-xr-xutils/create-debian-image.sh226
-rwxr-xr-xutils/create_devtools_package.sh35
-rwxr-xr-xutils/create_src_package.sh69
-rw-r--r--utils/darwin-daisy.tar.bz2bin0 -> 7200524 bytes
-rw-r--r--utils/flash/.gitignore1
-rw-r--r--utils/flash/filter-dfu-out.js38
-rw-r--r--utils/flash/flashall.bat234
-rwxr-xr-xutils/flash/flashall.sh240
-rw-r--r--utils/flash/ifwi/edison/edison_dnx_fwr.binbin0 -> 98196 bytes
-rw-r--r--utils/flash/ifwi/edison/edison_dnx_osr.binbin0 -> 148996 bytes
-rw-r--r--utils/flash/ifwi/edison/edison_ifwi-dbg-00.binbin0 -> 4194468 bytes
-rw-r--r--utils/flash/ifwi/edison/edison_ifwi-dbg-01.binbin0 -> 4194468 bytes
-rw-r--r--utils/flash/ifwi/edison/edison_ifwi-dbg-02.binbin0 -> 4194468 bytes
-rw-r--r--utils/flash/ifwi/edison/edison_ifwi-dbg-03.binbin0 -> 4194468 bytes
-rw-r--r--utils/flash/ifwi/edison/edison_ifwi-dbg-04.binbin0 -> 4194468 bytes
-rw-r--r--utils/flash/ifwi/edison/edison_ifwi-dbg-05.binbin0 -> 4194468 bytes
-rw-r--r--utils/flash/ifwi/edison/edison_ifwi-dbg-06.binbin0 -> 4194468 bytes
-rw-r--r--utils/flash/ota_update.cmd338
-rw-r--r--utils/flash/pft-config-edison-00.xml28
-rw-r--r--utils/flash/pft-config-edison-01.xml28
-rw-r--r--utils/flash/pft-config-edison-02.xml28
-rw-r--r--utils/flash/pft-config-edison-03.xml28
-rw-r--r--utils/flash/pft-config-edison-04.xml28
-rw-r--r--utils/flash/pft-config-edison-05.xml28
-rw-r--r--utils/flash/pft-config-edison-06.xml28
-rw-r--r--utils/flash/pft-config-edison.xml28
-rwxr-xr-xutils/flash/postBuild.sh89
-rwxr-xr-xutils/generate-recipes-patches.sh56
-rwxr-xr-xutils/handle_bash_func.patch41
-rwxr-xr-xutils/invalidate_sstate.sh20
-rw-r--r--utils/mingw-daisy.tar.bz2bin0 -> 4664 bytes
-rw-r--r--utils/poky-daisy-11.0.1.tar.bz2bin0 -> 15116359 bytes
-rw-r--r--utils/sdk-populate-clean-broken-links.patch29
303 files changed, 149215 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4326d6a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+toFlash
+poky
+!.gitignore
+*~
+
diff --git a/meta-edison-arduino/conf/layer.conf b/meta-edison-arduino/conf/layer.conf
new file mode 100644
index 0000000..77ff005
--- /dev/null
+++ b/meta-edison-arduino/conf/layer.conf
@@ -0,0 +1,10 @@
+# We have a conf and classes directory, add to BBPATH
+BBPATH := "${BBPATH}:${LAYERDIR}"
+
+# We have a recipes-* directories, add to BBFILES
+BBFILES := "${BBFILES} ${LAYERDIR}/recipes-*/*/*.bb \
+ ${LAYERDIR}/recipes-*/*/*.bbappend"
+
+BBFILE_COLLECTIONS += "edison-arduino"
+BBFILE_PATTERN_edison-arduino = "^${LAYERDIR}/"
+BBFILE_PRIORITY_edison-arduino = "6"
diff --git a/meta-edison-arduino/recipes-core/images/edison-image.bbappend b/meta-edison-arduino/recipes-core/images/edison-image.bbappend
new file mode 100644
index 0000000..5a93c35
--- /dev/null
+++ b/meta-edison-arduino/recipes-core/images/edison-image.bbappend
@@ -0,0 +1,2 @@
+IMAGE_INSTALL += "clloader"
+
diff --git a/meta-edison-arduino/recipes-devtools/clloader/clloader.bb b/meta-edison-arduino/recipes-devtools/clloader/clloader.bb
new file mode 100644
index 0000000..5248900
--- /dev/null
+++ b/meta-edison-arduino/recipes-devtools/clloader/clloader.bb
@@ -0,0 +1,53 @@
+DESCRIPTION = "This is the edison arduino sketch download daemon."
+HOMEPAGE = "http://www.intel.com"
+LICENSE = "LGPLv2.1"
+
+S = "${EDISONREPO_TOP_DIR}/arduino/clloader"
+
+SRC_URI += "file://clloader.service \
+ file://sketch_reset.service"
+
+LIC_FILES_CHKSUM = " \
+ file://clloader.c;endline=29;md5=4b30a8a8eefba8a23997c11e77c6fd24 \
+"
+
+do_clean() {
+ make clean
+}
+
+do_compile() {
+ make
+}
+
+do_install () {
+ install -d ${D}/sketch
+ install -d ${D}/opt/edison
+ install -m 0755 ${B}/clloader ${D}/opt/edison
+ install -m 0755 ${B}/sketch_reset ${D}/opt/edison/
+ install -m 0755 ${B}/scripts/launcher.sh ${D}/opt/edison/
+ install -m 0755 ${B}/scripts/sketch_reset.sh ${D}/opt/edison/
+
+ install -d ${D}${systemd_unitdir}/system/
+ install -m 0644 ${WORKDIR}/clloader.service ${D}${systemd_unitdir}/system/
+ install -m 0644 ${WORKDIR}/sketch_reset.service ${D}${systemd_unitdir}/system/
+}
+
+pkg_postinst_${PN} () {
+
+}
+
+pkg_prerm_${PN} () {
+
+}
+
+inherit systemd
+
+SYSTEMD_SERVICE_${PN} = "clloader.service sketch_reset.service"
+
+FILES_${PN} += "${systemd_unitdir}/system/clloader.service \
+ ${systemd_unitdir}/system/sketch_reset.service \
+ opt/edison \
+ sketch \
+ "
+
+FILES_${PN}-dbg += "opt/edison/.debug sketch/.debug"
diff --git a/meta-edison-arduino/recipes-devtools/clloader/files/clloader.service b/meta-edison-arduino/recipes-devtools/clloader/files/clloader.service
new file mode 100644
index 0000000..802be94
--- /dev/null
+++ b/meta-edison-arduino/recipes-devtools/clloader/files/clloader.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Daemon to handle arduino sketches
+After=syslog.target
+
+[Service]
+ExecStart=/opt/edison/launcher.sh
+
+[Install]
+WantedBy=multi-user.target
+
diff --git a/meta-edison-arduino/recipes-devtools/clloader/files/sketch_reset.service b/meta-edison-arduino/recipes-devtools/clloader/files/sketch_reset.service
new file mode 100644
index 0000000..ba7e971
--- /dev/null
+++ b/meta-edison-arduino/recipes-devtools/clloader/files/sketch_reset.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Daemon to reset sketches
+After=clloader.service
+Requires=clloader.service
+
+[Service]
+ExecStart=/opt/edison/sketch_reset -i 207 -o 215 -s /opt/edison/sketch_reset.sh
+
+[Install]
+WantedBy=multi-user.target
+
diff --git a/meta-edison-devenv/conf/layer.conf b/meta-edison-devenv/conf/layer.conf
new file mode 100644
index 0000000..5a73ad6
--- /dev/null
+++ b/meta-edison-devenv/conf/layer.conf
@@ -0,0 +1,14 @@
+# We have a conf and classes directory, add to BBPATH
+BBPATH := "${BBPATH}:${LAYERDIR}"
+
+# We have a recipes-* directories, add to BBFILES
+BBFILES := "${BBFILES} ${LAYERDIR}/recipes-*/*/*.bb \
+ ${LAYERDIR}/recipes-*/*/*.bbappend"
+
+BBFILE_COLLECTIONS += "edison-devenv"
+BBFILE_PATTERN_edison-devenv = "^${LAYERDIR}/"
+BBFILE_PRIORITY_edison-devenv = "6"
+
+PREFERRED_PROVIDER_virtual/kernel = "linux-externalsrc"
+PREFERRED_VERSION_linux-externalsrc = "1.0"
+
diff --git a/meta-edison-devenv/recipes-bsp/u-boot/u-boot-fw-utils_2014.04.bbappend b/meta-edison-devenv/recipes-bsp/u-boot/u-boot-fw-utils_2014.04.bbappend
new file mode 100644
index 0000000..b14416f
--- /dev/null
+++ b/meta-edison-devenv/recipes-bsp/u-boot/u-boot-fw-utils_2014.04.bbappend
@@ -0,0 +1,3 @@
+require u-boot-internal-devenv.inc
+
+SRC_URI += "file://fw_env.config"
diff --git a/meta-edison-devenv/recipes-bsp/u-boot/u-boot-internal-devenv.inc b/meta-edison-devenv/recipes-bsp/u-boot/u-boot-internal-devenv.inc
new file mode 100644
index 0000000..12f5df3
--- /dev/null
+++ b/meta-edison-devenv/recipes-bsp/u-boot/u-boot-internal-devenv.inc
@@ -0,0 +1,6 @@
+S = "${EDISONREPO_TOP_DIR}/u-boot"
+SRC_URI = ""
+SRCREV = ""
+
+SRC_URI += "file://${MACHINE}.env"
+SRC_URI += "file://target/*.env"
diff --git a/meta-edison-devenv/recipes-bsp/u-boot/u-boot-tools_2014.04.bbappend b/meta-edison-devenv/recipes-bsp/u-boot/u-boot-tools_2014.04.bbappend
new file mode 100644
index 0000000..114cf57
--- /dev/null
+++ b/meta-edison-devenv/recipes-bsp/u-boot/u-boot-tools_2014.04.bbappend
@@ -0,0 +1,2 @@
+require u-boot-internal-devenv.inc
+
diff --git a/meta-edison-devenv/recipes-bsp/u-boot/u-boot_2014.04.bbappend b/meta-edison-devenv/recipes-bsp/u-boot/u-boot_2014.04.bbappend
new file mode 100644
index 0000000..dfc9924
--- /dev/null
+++ b/meta-edison-devenv/recipes-bsp/u-boot/u-boot_2014.04.bbappend
@@ -0,0 +1,5 @@
+EXTERNALSRC_pn_u-boot = "${EDISONREPO_TOP_DIR}/u-boot"
+INHERIT += "externalsrc"
+
+require u-boot-internal-devenv.inc
+
diff --git a/meta-edison-devenv/recipes-kernel/linux/linux-externalsrc.bb b/meta-edison-devenv/recipes-kernel/linux/linux-externalsrc.bb
new file mode 100644
index 0000000..c96a415
--- /dev/null
+++ b/meta-edison-devenv/recipes-kernel/linux/linux-externalsrc.bb
@@ -0,0 +1,44 @@
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://COPYING;md5=d7810fab7487fb0aad327b76f1be7cd7"
+
+inherit kernel
+require recipes-kernel/linux/linux-yocto.inc
+
+# Allows to avoid fetching, unpacking and patching, since our code is already cloned by repo
+inherit externalsrc
+
+# Don't use Yocto kernel configuration system, we instead simply override do_configure
+# to copy our defconfig in the build directory just before building.
+# I agree this is very ad hoc, but maybe it's good enough for our development environment
+do_configure() {
+ cp "${EDISONREPO_TOP_DIR}/linux-kernel/arch/x86/configs/i386_edison_defconfig" "${B}/.config"
+}
+
+EXTERNALSRC_pn-linux-externalsrc = "${S}"
+EXTERNALSRC_BUILD_pn-linux-externalsrc = "${B}"
+
+LINUX_VERSION ?= "3.10"
+LINUX_VERSION_EXTENSION = "-edison-${LINUX_KERNEL_TYPE}"
+
+S = "${EDISONREPO_TOP_DIR}/linux-kernel"
+B = "${WORKDIR}/${BP}"
+
+# This is required for kernel to do the build out-of-tree.
+# If this is not set, most of the kernel make targets won't work properly
+# as they'll be executed in the sources
+export KBUILD_OUTPUT="${B}"
+
+# The previous line should not be necessary when those 2 are added
+# but it doesn't work..
+KBUILD_OUTPUT = "${B}"
+OE_TERMINAL_EXPORTS += "KBUILD_OUTPUT"
+
+PR = "r2"
+
+COMPATIBLE_MACHINE = "edison"
+
+do_deploy() {
+ kernel_do_deploy
+ install ${B}/vmlinux ${DEPLOYDIR}/vmlinux
+}
+
diff --git a/meta-edison-devtools/COPYING.MIT b/meta-edison-devtools/COPYING.MIT
new file mode 100644
index 0000000..89de354
--- /dev/null
+++ b/meta-edison-devtools/COPYING.MIT
@@ -0,0 +1,17 @@
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/meta-edison-devtools/conf/layer.conf b/meta-edison-devtools/conf/layer.conf
new file mode 100644
index 0000000..85b26a5
--- /dev/null
+++ b/meta-edison-devtools/conf/layer.conf
@@ -0,0 +1,10 @@
+# We have a conf and classes directory, add to BBPATH
+BBPATH := "${BBPATH}:${LAYERDIR}"
+
+# We have a recipes-* directories, add to BBFILES
+BBFILES := "${BBFILES} ${LAYERDIR}/recipes-*/*/*.bb \
+ ${LAYERDIR}/recipes-*/*/*.bbappend"
+
+BBFILE_COLLECTIONS += "edison-devtools"
+BBFILE_PATTERN_edison-devtools = "^${LAYERDIR}/"
+BBFILE_PRIORITY_edison-devtools = "6"
diff --git a/meta-edison-devtools/recipes-benchmark/bonnie/bonnie++_1.03c.bb b/meta-edison-devtools/recipes-benchmark/bonnie/bonnie++_1.03c.bb
new file mode 100644
index 0000000..26e649d
--- /dev/null
+++ b/meta-edison-devtools/recipes-benchmark/bonnie/bonnie++_1.03c.bb
@@ -0,0 +1,30 @@
+DESCRIPTION = "Tests large file IO and creation/deletion of small files."
+HOMEPAGE = "http://www.coker.com.au/bonnie++/"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://copyright.txt;md5=cd4dde95a6b9d122f0a9150ae9cc3ee0"
+
+SRC_URI = "http://www.coker.com.au/bonnie++/bonnie++-${PV}.tgz \
+ file://gcc-4.3-fixes.patch \
+"
+SRC_URI[md5sum] = "77a1ba78f37bdd7f024b67e1e36ad151"
+SRC_URI[sha256sum] = "c674f1182f4c20f1e6d038feceb0a6617fc3e7658dfbbac89396043b49612a26"
+
+inherit autotools
+
+SCRIPTS = "bon_csv2html bon_csv2txt"
+EXES = "bonnie++ zcav"
+
+TARGET_CC_ARCH += "${LDFLAGS}"
+
+do_install () {
+ install -d ${D}/bin
+ install -d ${D}/sbin
+ install -m 0755 ${EXES} ${D}/sbin
+ install -m 0755 ${SCRIPTS} ${D}/bin
+}
+
+PACKAGES =+ "bonnie-scripts"
+
+FILES_${PN} = "${base_sbindir}"
+FILES_bonnie-scripts = "${base_bindir}"
+
diff --git a/meta-edison-devtools/recipes-benchmark/bonnie/files/gcc-4.3-fixes.patch b/meta-edison-devtools/recipes-benchmark/bonnie/files/gcc-4.3-fixes.patch
new file mode 100644
index 0000000..3a62a92
--- /dev/null
+++ b/meta-edison-devtools/recipes-benchmark/bonnie/files/gcc-4.3-fixes.patch
@@ -0,0 +1,20 @@
+Includes string.h to one of the source file.
+
+Upstream-Status: Inappropriate [not author.]
+---
+ zcav.cpp | 1 +
+ 1 file changed, 1 insertion(+)
+
+Index: bonnie++-1.03a/zcav.cpp
+===================================================================
+--- bonnie++-1.03a.orig/zcav.cpp
++++ bonnie++-1.03a/zcav.cpp
+@@ -15,6 +15,7 @@ using namespace std;
+ #else
+ #include <vector.h>
+ #endif
++#include <string.h>
+
+ // Read the specified number of megabytes of data from the fd and return the
+ // amount of time elapsed in seconds.
+
diff --git a/meta-edison-devtools/recipes-connectivity/bcm43340-tools/dhdutil.bb b/meta-edison-devtools/recipes-connectivity/bcm43340-tools/dhdutil.bb
new file mode 100644
index 0000000..3f08096
--- /dev/null
+++ b/meta-edison-devtools/recipes-connectivity/bcm43340-tools/dhdutil.bb
@@ -0,0 +1,15 @@
+SUMMARY = "dhdutil utility"
+DESCRIPTION = "dhdutil utility for BCM chipset"
+SECTION = "test-tools"
+LICENSE = "CLOSED"
+
+PV = "r1.141"
+PR = "r47"
+
+S = "${EDISONREPO_TOP_DIR}/broadcom_tools/wlan/dhdutil"
+
+do_install() {
+ install -v -d ${D}/usr/sbin/
+ install -m 0755 ${B}/dhdutil ${D}/usr/sbin
+}
+
diff --git a/meta-edison-devtools/recipes-connectivity/bcm43340-tools/wlx.bb b/meta-edison-devtools/recipes-connectivity/bcm43340-tools/wlx.bb
new file mode 100644
index 0000000..3d88e6e
--- /dev/null
+++ b/meta-edison-devtools/recipes-connectivity/bcm43340-tools/wlx.bb
@@ -0,0 +1,19 @@
+SUMMARY = "wlx utility"
+DESCRIPTION = "wlx utility for BCM chipset"
+SECTION = "test-tools"
+LICENSE = "CLOSED"
+
+PV = "r6.10.190"
+PR = "r40"
+
+S = "${EDISONREPO_TOP_DIR}/broadcom_tools/wlan/wlx"
+
+do_compile () {
+ oe_runmake -C wl/exe
+}
+
+do_install() {
+ install -v -d ${D}/usr/sbin/
+ install -m 0755 ${B}/wl/exe/wlx ${D}/usr/sbin
+}
+
diff --git a/meta-edison-devtools/recipes-connectivity/wfa-tool/wfa-tool.bb b/meta-edison-devtools/recipes-connectivity/wfa-tool/wfa-tool.bb
new file mode 100644
index 0000000..1d21cfe
--- /dev/null
+++ b/meta-edison-devtools/recipes-connectivity/wfa-tool/wfa-tool.bb
@@ -0,0 +1,37 @@
+SUMMARY = "Sigma WFA agent"
+DESCRIPTION = "Sigma WFA agent tool used for Wifi pre-certification"
+SECTION = "test-tools"
+LICENSE = "CLOSED"
+
+PV = "r4.0"
+PR = "0"
+
+S = "${EDISONREPO_TOP_DIR}/test_tools/PRIVATE/wfa_tool"
+
+do_install() {
+ install -v -d ${D}/usr/sbin/
+ install -m 0755 ${B}/ca/wfa_ca ${D}/usr/sbin
+ install -m 0755 ${B}/dut/wfa_dut ${D}/usr/sbin
+ install -m 0755 ${S}/scripts/wfa_send_ping ${D}/usr/sbin
+ install -m 0755 ${S}/scripts/wfa_send_ping6 ${D}/usr/sbin
+ install -m 0755 ${S}/scripts/wfa_service ${D}/usr/sbin
+ install -m 0755 ${S}/scripts/wfa_start_iperf ${D}/usr/sbin
+ install -m 0755 ${S}/scripts/wfa_stop_iperf ${D}/usr/sbin
+ install -m 0755 ${S}/scripts/wfa_stop_ping ${D}/usr/sbin
+ install -m 0755 ${S}/scripts/wfa_start_dhcp_client ${D}/usr/sbin
+ install -m 0755 ${S}/scripts/wfa_stop_dhcp_client ${D}/usr/sbin
+ install -m 0755 ${S}/scripts/wfa_start_dhcp_server ${D}/usr/sbin
+ install -m 0755 ${S}/scripts/wfa_stop_dhcp_server ${D}/usr/sbin
+
+ install -v -d ${D}${sysconfdir}/sigma
+ install -m 644 ${S}/scripts/udhcpd.conf ${D}${sysconfdir}/sigma
+ install -m 644 ${S}/certificates/cas.pem ${D}${sysconfdir}/sigma
+ install -m 644 ${S}/certificates/root.pem ${D}${sysconfdir}/sigma
+ install -m 644 ${S}/certificates/wifiuser.pem ${D}${sysconfdir}/sigma
+ install -m 644 ${S}/certificates/fast-mschapv2.pac ${D}${sysconfdir}/sigma
+}
+
+do_clean() {
+ make clean
+}
+
diff --git a/meta-edison-devtools/recipes-support/peeknpoke/peeknpoke_1.1.bb b/meta-edison-devtools/recipes-support/peeknpoke/peeknpoke_1.1.bb
new file mode 100644
index 0000000..5ed5077
--- /dev/null
+++ b/meta-edison-devtools/recipes-support/peeknpoke/peeknpoke_1.1.bb
@@ -0,0 +1,13 @@
+DESCRIPTION = "peeknpoke tool"
+SECTION = "base"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://COPYING;md5=d32239bcb673463ab874e80d47fae504"
+
+# These 2 lines allows to use the local version of the sources for buiding
+# It is cloned by the repo tool in the peeknpoke top directory
+S = "${EDISONREPO_TOP_DIR}/tools/PRIVATE/peeknpoke"
+
+# This recipe unfortunately doesn't support out-of-source build
+B = "${EDISONREPO_TOP_DIR}/tools/PRIVATE/peeknpoke"
+
+inherit autotools
diff --git a/meta-edison-distro/COPYING.MIT b/meta-edison-distro/COPYING.MIT
new file mode 100644
index 0000000..89de354
--- /dev/null
+++ b/meta-edison-distro/COPYING.MIT
@@ -0,0 +1,17 @@
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/meta-edison-distro/README b/meta-edison-distro/README
new file mode 100644
index 0000000..3237326
--- /dev/null
+++ b/meta-edison-distro/README
@@ -0,0 +1,118 @@
+This README file contains information on building the meta-edison
+BSP layer, and booting the images contained in the /binary directory.
+Please see the corresponding sections below for details.
+
+
+Dependencies
+============
+
+This layer depends on:
+
+ URI: git://git.openembedded.org/bitbake
+ branch: master
+
+ URI: git://git.openembedded.org/openembedded-core
+ layers: meta
+ branch: master
+
+ URI: git://git.yoctoproject.org/xxxx
+ layers: xxxx
+ branch: master
+
+
+Patches
+=======
+
+Please submit any patches against this BSP to the Yocto mailing list
+(yocto@yoctoproject.org) and cc: the maintainer:
+
+Maintainer: XXX YYYYYY <xxx.yyyyyy@zzzzz.com>
+
+Please see the meta-xxxx/MAINTAINERS file for more details.
+
+
+Table of Contents
+=================
+
+ I. Building the meta-edison BSP layer
+ II. Booting the images in /binary
+
+
+I. Building the meta-edison BSP layer
+========================================
+
+--- replace with specific instructions for your layer ---
+
+In order to build an image with BSP support for a given release, you
+need to download the corresponding BSP tarball from the 'Board Support
+Package (BSP) Downloads' page of the Yocto Project website.
+
+Having done that, and assuming you extracted the BSP tarball contents
+at the top-level of your yocto build tree, you can build a
+edison image by adding the location of the meta-edison
+layer to bblayers.conf, along with any other layers needed (to access
+common metadata shared between BSPs) e.g.:
+
+ yocto/meta-xxxx \
+ yocto/meta-xxxx/meta-edison \
+
+To enable the edison layer, add the edison MACHINE to local.conf:
+
+ MACHINE ?= "edison"
+
+You should then be able to build a edison image as such:
+
+ $ source oe-init-build-env
+ $ bitbake core-image-sato
+
+At the end of a successful build, you should have a live image that
+you can boot from a USB flash drive (see instructions on how to do
+that below, in the section 'Booting the images from /binary').
+
+As an alternative to downloading the BSP tarball, you can also work
+directly from the meta-xxxx git repository. For each BSP in the
+'meta-xxxx' repository, there are multiple branches, one corresponding
+to each major release starting with 'laverne' (0.90), in addition to
+the latest code which tracks the current master (note that not all
+BSPs are present in every release). Instead of extracting a BSP
+tarball at the top level of your yocto build tree, you can
+equivalently check out the appropriate branch from the meta-xxxx
+repository at the same location.
+
+
+II. Booting the images in /binary
+=================================
+
+--- replace with specific instructions for your platform ---
+
+This BSP contains bootable live images, which can be used to directly
+boot Yocto off of a USB flash drive.
+
+Under Linux, insert a USB flash drive. Assuming the USB flash drive
+takes device /dev/sdf, use dd to copy the live image to it. For
+example:
+
+# dd if=core-image-sato-edison-20101207053738.hddimg of=/dev/sdf
+# sync
+# eject /dev/sdf
+
+This should give you a bootable USB flash device. Insert the device
+into a bootable USB socket on the target, and power on. This should
+result in a system booted to the Sato graphical desktop.
+
+If you want a terminal, use the arrows at the top of the UI to move to
+different pages of available applications, one of which is named
+'Terminal'. Clicking that should give you a root terminal.
+
+If you want to ssh into the system, you can use the root terminal to
+ifconfig the IP address and use that to ssh in. The root password is
+empty, so to log in type 'root' for the user name and hit 'Enter' at
+the Password prompt: and you should be in.
+
+----
+
+If you find you're getting corrupt images on the USB (it doesn't show
+the syslinux boot: prompt, or the boot: prompt contains strange
+characters), try doing this first:
+
+# dd if=/dev/zero of=/dev/sdf bs=1M count=512
diff --git a/meta-edison-distro/README.sources b/meta-edison-distro/README.sources
new file mode 100644
index 0000000..3c4cb7b
--- /dev/null
+++ b/meta-edison-distro/README.sources
@@ -0,0 +1,17 @@
+The sources for the packages comprising the images shipped with this
+BSP can be found at the following location:
+
+http://downloads.yoctoproject.org/mirror/sources/
+
+The metadata used to generate the images shipped with this BSP, in
+addition to the code contained in this BSP, can be found at the
+following location:
+
+http://www.yoctoproject.org/downloads/yocto-1.1/poky-edison-6.0.tar.bz2
+
+The metadata used to generate the images shipped with this BSP, in
+addition to the code contained in this BSP, can also be found at the
+following locations:
+
+git://git.yoctoproject.org/poky.git
+git://git.yoctoproject.org/meta-xxxx
diff --git a/meta-edison-distro/conf/distro/poky-edison.conf b/meta-edison-distro/conf/distro/poky-edison.conf
new file mode 100644
index 0000000..a0e7466
--- /dev/null
+++ b/meta-edison-distro/conf/distro/poky-edison.conf
@@ -0,0 +1,20 @@
+require conf/distro/poky.conf
+DISTRO = "poky-edison"
+
+PREFERRED_PROVIDER_virtual/kernel ?= "linux-yocto"
+PREFERRED_VERSION_linux-yocto = "3.10%"
+PREFERRED_PROVIDER_virtual/bootloader ?= "u-boot"
+PREFERRED_VERSION_u-boot ?= "2014.04-1"
+PREFERRED_VERSION_u-boot-fw-utils ?= "2014.04-1"
+PREFERRED_VERSION_connman ?= "1.27"
+PREFERRED_VERSION_openssl ?= "1.0.1j"
+PREFERRED_VERSION_systemd ?= "213+gitAUTOINC+c9679c652b"
+
+DISTRO_FEATURES = "systemd alsa argp bluetooth ext2 largefile usbgadget usbhost wifi xattr nfs zeroconf pci ${DISTRO_FEATURES_LIBC}"
+
+# Disable sysvinit for recipes with systemd support
+DISTRO_FEATURES_BACKFILL_CONSIDERED += "sysvinit"
+VIRTUAL-RUNTIME_initscripts = ""
+VIRTUAL-RUNTIME_init_manager = "systemd"
+# Uncomment to completely disable support for sysv scripts:
+PACKAGECONFIG_pn-systemd = "xz"
diff --git a/meta-edison-distro/conf/layer.conf b/meta-edison-distro/conf/layer.conf
new file mode 100644
index 0000000..3b58c57
--- /dev/null
+++ b/meta-edison-distro/conf/layer.conf
@@ -0,0 +1,10 @@
+# We have a conf and classes directory, add to BBPATH
+BBPATH := "${BBPATH}:${LAYERDIR}"
+
+# We have a recipes-* directories, add to BBFILES
+BBFILES := "${BBFILES} ${LAYERDIR}/recipes-*/*/*.bb \
+ ${LAYERDIR}/recipes-*/*/*.bbappend"
+
+BBFILE_COLLECTIONS += "edison-distro"
+BBFILE_PATTERN_edison-distro = "^${LAYERDIR}/"
+BBFILE_PRIORITY_edison-distro = "6"
diff --git a/meta-edison-distro/files/fs-perms.txt b/meta-edison-distro/files/fs-perms.txt
new file mode 100644
index 0000000..a497017
--- /dev/null
+++ b/meta-edison-distro/files/fs-perms.txt
@@ -0,0 +1,69 @@
+# This file contains a list of files and directories with known permissions.
+# It is used by the packaging class to ensure that the permissions, owners and
+# group of listed files and directories are in sync across the system.
+#
+# The format of this file
+#
+#<path> <mode> <uid> <gid> <walk> <fmode> <fuid> <fgid>
+#
+# or
+#
+#<path> link <target>
+#
+# <path>: directory path
+# <mode>: mode for directory
+# <uid>: uid for directory
+# <gid>: gid for directory
+# <walk>: recursively walk the directory? true or false
+# <fmode>: if walking, new mode for files
+# <fuid>: if walking, new uid for files
+# <fgid>: if walking, new gid for files
+# <target>: turn the directory into a symlink point to target
+#
+# in mode, uid or gid, a "-" means don't change any existing values
+#
+# /usr/src 0755 root root false - - -
+# /usr/share/man 0755 root root true 0644 root root
+
+# Note: all standard config directories are automatically assigned "0755 root root false - - -"
+
+# Documentation should always be corrected
+${mandir} 0755 root root true 0644 root root
+${infodir} 0755 root root true 0644 root root
+${docdir} 0755 root root true 0644 root root
+${datadir}/gtk-doc 0755 root root true 0644 root root
+
+# Fixup locales
+${datadir}/locale 0755 root root true 0644 root root
+
+# Cleanup headers
+${includedir} 0755 root root true 0644 root root
+${oldincludedir} 0755 root root true 0644 root root
+
+# Cleanup debug src
+/usr/src/debug 0755 root root true - root root
+
+# Log directory
+${localstatedir}/log 0777 root root false - - -
+
+# Items from base-files
+# Links
+${localstatedir}/run link /run
+${localstatedir}/lock link /run/lock
+${localstatedir}/tmp link volatile/tmp
+
+# Special permissions from base-files
+# Set 1777
+/tmp 01777 root root false - - -
+${localstatedir}/volatile/tmp 01777 root root false - - -
+
+# Set 2775
+/home 02755 root root false - - -
+${prefix}/src 02755 root root false - - -
+${localstatedir}/local 02755 root root false - - -
+
+# Set 3755
+/srv 0755 root root false - - -
+
+# Set 4775
+/var/mail 02755 root root false - - -
diff --git a/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/000-Iperf_Fix-CPU-Usage.diff b/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/000-Iperf_Fix-CPU-Usage.diff
new file mode 100644
index 0000000..7e89953
--- /dev/null
+++ b/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/000-Iperf_Fix-CPU-Usage.diff
@@ -0,0 +1,164 @@
+[Thread]: Replace thread_rest() with condition variables
+
+This applies the patch by Ingo Molnar from
+
+ http://marc.info/?l=linux-kernel&m=119088670113210&w=2
+
+by reverting previous changes that coincided with changes made by this
+patch. Other than that, the patch is the original from the above URL.
+
+Gerrit
+---
+ compat/Thread.c | 6 ------
+ src/Reporter.c | 37 +++++++++----------------------------
+ src/main.cpp | 2 ++
+ 3 files changed, 11 insertions(+), 34 deletions(-)
+
+rover: changed two remaining thread_rest.
+
+--- a/compat/Thread.c
++++ b/compat/Thread.c
+@@ -405,12 +405,6 @@ int thread_numuserthreads( void ) {
+ void thread_rest ( void ) {
+ #if defined( HAVE_THREAD )
+ #if defined( HAVE_POSIX_THREAD )
+-#if defined( _POSIX_PRIORITY_SCHEDULING )
+- sched_yield();
+-#else
+- usleep( 0 );
+-#endif
+-
+ #else // Win32
+ SwitchToThread( );
+ #endif
+--- a/src/Reporter.c
++++ b/src/Reporter.c
+@@ -110,9 +110,8 @@
+
+ char buffer[64]; // Buffer for printing
+ ReportHeader *ReportRoot = NULL;
+-int threadWait = 0;
+-int threadSleeping = 0;
+ extern Condition ReportCond;
++extern Condition ReportDoneCond;
+ int reporter_process_report ( ReportHeader *report );
+ void process_report ( ReportHeader *report );
+ int reporter_handle_packet( ReportHeader *report );
+@@ -340,7 +339,7 @@
+ // item
+ while ( index == 0 ) {
+ Condition_Signal( &ReportCond );
+- thread_rest();
++ Condition_Wait( &ReportDoneCond );
+ index = agent->reporterindex;
+ }
+ agent->agentindex = 0;
+@@ -348,11 +347,9 @@
+ // Need to make sure that reporter is not about to be "lapped"
+ while ( index - 1 == agent->agentindex ) {
+ Condition_Signal( &ReportCond );
+- thread_rest();
++ Condition_Wait( &ReportDoneCond );
+ index = agent->reporterindex;
+ }
+- if (threadSleeping)
+- Condition_Signal( &ReportCond );
+
+ // Put the information there
+ memcpy( agent->data + agent->agentindex, packet, sizeof(ReportStruct) );
+@@ -382,9 +379,6 @@
+ packet->packetLen = 0;
+ ReportPacket( agent, packet );
+ packet->packetID = agent->report.cntDatagrams;
+- if (threadSleeping)
+- Condition_Signal( &ReportCond );
+-
+ }
+ }
+
+@@ -396,11 +390,8 @@
+ void EndReport( ReportHeader *agent ) {
+ if ( agent != NULL ) {
+ int index = agent->reporterindex;
+- if (threadSleeping)
+- Condition_Signal( &ReportCond );
+-
+ while ( index != -1 ) {
+- thread_rest();
++ Condition_Wait( &ReportDoneCond );
+ index = agent->reporterindex;
+ }
+ agent->agentindex = -1;
+@@ -421,7 +412,7 @@
+ Transfer_Info *GetReport( ReportHeader *agent ) {
+ int index = agent->reporterindex;
+ while ( index != -1 ) {
+- thread_rest();
++ Condition_Wait( &ReportDoneCond );
+ index = agent->reporterindex;
+ }
+ return &agent->report.info;
+@@ -467,10 +458,6 @@
+ * Update the ReportRoot to include this report.
+ */
+ Condition_Lock( ReportCond );
+- if ( isUDP(agent) )
+- threadWait = 0;
+- else
+- threadWait = 1;
+ reporthdr->next = ReportRoot;
+ ReportRoot = reporthdr;
+ Condition_Signal( &ReportCond );
+@@ -567,6 +554,7 @@
+ }
+ Condition_Unlock ( ReportCond );
+
++again:
+ if ( ReportRoot != NULL ) {
+ ReportHeader *temp = ReportRoot;
+ //Condition_Unlock ( ReportCond );
+@@ -589,19 +577,12 @@
+ // finished with report so free it
+ free( temp );
+ Condition_Unlock ( ReportCond );
++ Condition_Signal( &ReportDoneCond );
++ if (ReportRoot)
++ goto again;
+ }
+- // yield control of CPU is another thread is waiting
+- // sleep on a condition variable, as it is much cheaper
+- // on most platforms than issuing schedyield or usleep
+- // syscalls
+- Condition_Lock ( ReportCond );
+- if ( threadWait && ReportRoot != NULL) {
+- threadSleeping = 1;
+- Condition_TimedWait (& ReportCond, 1 );
+- threadSleeping = 0;
+- }
+- Condition_Unlock ( ReportCond );
+-
++ Condition_Signal( &ReportDoneCond );
++ usleep(10000);
+ } else {
+ //Condition_Unlock ( ReportCond );
+ }
+--- a/src/main.cpp
++++ b/src/main.cpp
+@@ -96,6 +96,7 @@ extern "C" {
+ // records being accessed in a report and also to
+ // serialize modification of the report list
+ Condition ReportCond;
++ Condition ReportDoneCond;
+ }
+
+ // global variables only accessed within this file
+@@ -142,6 +143,7 @@ int main( int argc, char **argv ) {
+
+ // Initialize global mutexes and conditions
+ Condition_Initialize ( &ReportCond );
++ Condition_Initialize ( &ReportDoneCond );
+ Mutex_Initialize( &groupCond );
+ Mutex_Initialize( &clients_mutex );
+
+
+
diff --git a/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/001-cast-to-max_size_t-instead-of-int.patch b/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/001-cast-to-max_size_t-instead-of-int.patch
new file mode 100644
index 0000000..b6728d4
--- /dev/null
+++ b/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/001-cast-to-max_size_t-instead-of-int.patch
@@ -0,0 +1,14 @@
+Import Debian patches and fix a lot of real bugs.
+
+Upstream-Status: Inappropriate [not author. Above message was get from oe.dev c10c33f86903c93611023197a7f812459c2dfe2d]
+--- iperf-2.0.4.orig/src/Settings.cpp.orig 2008-04-08 04:37:54.000000000 +0200
++++ iperf-2.0.4/src/Settings.cpp 2008-05-07 17:41:03.923942801 +0200
+@@ -458,7 +458,7 @@
+ case 't': // seconds to write for
+ // time mode (instead of amount mode)
+ setModeTime( mExtSettings );
+- mExtSettings->mAmount = (int) (atof( optarg ) * 100.0);
++ mExtSettings->mAmount = (max_size_t) (atof( optarg ) * 100.0);
+ break;
+
+ case 'u': // UDP instead of TCP
diff --git a/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/003-fix-hyphen-used-as-minus-sign.patch b/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/003-fix-hyphen-used-as-minus-sign.patch
new file mode 100644
index 0000000..929b5ac
--- /dev/null
+++ b/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/003-fix-hyphen-used-as-minus-sign.patch
@@ -0,0 +1,178 @@
+Import Debian patches and fix a lot of real bugs.
+
+Upstream-Status: Inappropriate [not author. Above message was get from oe.dev c10c33f86903c93611023197a7f812459c2dfe2d]
+
+--- iperf-2.0.4.orig/man/iperf.1 2008-08-21 00:21:49.290527643 +0200
++++ iperf-2.0.4/man/iperf.1 2008-08-21 00:35:17.850640445 +0200
+@@ -2,21 +2,21 @@
+ .SH NAME
+ iperf \- perform network throughput tests
+ .SH SYNOPSIS
+-.B iperf -s [
++.B iperf \-s [
+ .I options
+ .B ]
+
+-.B iperf -c
++.B iperf \-c
+ .I server
+ .B [
+ .I options
+ .B ]
+
+-.B iperf -u -s [
++.B iperf \-u \-s [
+ .I options
+ .B ]
+
+-.B iperf -u -c
++.B iperf \-u \-c
+ .I server
+ .B [
+ .I options
+@@ -28,103 +28,103 @@
+ traffic).
+ .SH "GENERAL OPTIONS"
+ .TP
+-.BR -f ", " --format " "
++.BR \-f ", " \-\-format " "
+ [kmKM] format to report: Kbits, Mbits, KBytes, MBytes
+ .TP
+-.BR -h ", " --help " "
++.BR \-h ", " \-\-help " "
+ print a help synopsis
+ .TP
+-.BR -i ", " --interval " \fIn\fR"
++.BR \-i ", " \-\-interval " \fIn\fR"
+ pause \fIn\fR seconds between periodic bandwidth reports
+ .TP
+-.BR -l ", " --len " \fIn\fR[KM]"
++.BR \-l ", " \-\-len " \fIn\fR[KM]"
+ set length read/write buffer to \fIn\fR (default 8 KB)
+ .TP
+-.BR -m ", " --print_mss " "
++.BR \-m ", " \-\-print_mss " "
+ print TCP maximum segment size (MTU - TCP/IP header)
+ .TP
+-.BR -o ", " --output " <filename>"
++.BR \-o ", " \-\-output " <filename>"
+ output the report or error message to this specified file
+ .TP
+-.BR -p ", " --port " \fIn\fR"
++.BR \-p ", " \-\-port " \fIn\fR"
+ set server port to listen on/connect to to \fIn\fR (default 5001)
+ .TP
+-.BR -u ", " --udp " "
++.BR \-u ", " \-\-udp " "
+ use UDP rather than TCP
+ .TP
+-.BR -w ", " --window " \fIn\fR[KM]"
++.BR \-w ", " \-\-window " \fIn\fR[KM]"
+ TCP window size (socket buffer size)
+ .TP
+-.BR -B ", " --bind " <host>"
++.BR \-B ", " \-\-bind " <host>"
+ bind to <host>, an interface or multicast address
+ .TP
+-.BR -C ", " --compatibility " "
++.BR \-C ", " \-\-compatibility " "
+ for use with older versions does not sent extra msgs
+ .TP
+-.BR -M ", " --mss " \fIn\fR"
++.BR \-M ", " \-\-mss " \fIn\fR"
+ set TCP maximum segment size (MTU - 40 bytes)
+ .TP
+-.BR -N ", " --nodelay " "
++.BR \-N ", " \-\-nodelay " "
+ set TCP no delay, disabling Nagle's Algorithm
+ .TP
+-.BR -v ", " --version " "
++.BR \-v ", " \-\-version " "
+ print version information and quit
+ .TP
+-.BR -V ", " --IPv6Version " "
++.BR \-V ", " \-\-IPv6Version " "
+ Set the domain to IPv6
+ .TP
+-.BR -x ", " --reportexclude " "
++.BR \-x ", " \-\-reportexclude " "
+ [CDMSV] exclude C(connection) D(data) M(multicast) S(settings) V(server) reports
+ .TP
+-.BR -y ", " --reportstyle " C|c"
++.BR \-y ", " \-\-reportstyle " C|c"
+ if set to C or c report results as CSV (comma separated values)
+ .SH "SERVER SPECIFIC OPTIONS"
+ .TP
+-.BR -s ", " --server " "
++.BR \-s ", " \-\-server " "
+ run in server mode
+ .TP
+-.BR -U ", " --single_udp " "
++.BR \-U ", " \-\-single_udp " "
+ run in single threaded UDP mode
+ .TP
+-.BR -D ", " --daemon " "
++.BR \-D ", " \-\-daemon " "
+ run the server as a daemon
+ .SH "CLIENT SPECIFIC OPTIONS"
+ .TP
+-.BR -b ", " --bandwidth " \fIn\fR[KM]"
++.BR \-b ", " \-\-bandwidth " \fIn\fR[KM]"
+ set target bandwidth to \fIn\fR bits/sec (default 1 Mbit/sec).
+-This setting requires UDP (-u).
++This setting requires UDP (\-u).
+ .TP
+-.BR -c ", " --client " <host>"
++.BR \-c ", " \-\-client " <host>"
+ run in client mode, connecting to <host>
+ .TP
+-.BR -d ", " --dualtest " "
++.BR \-d ", " \-\-dualtest " "
+ Do a bidirectional test simultaneously
+ .TP
+-.BR -n ", " --num " \fIn\fR[KM]"
+-number of bytes to transmit (instead of -t)
++.BR \-n ", " \-\-num " \fIn\fR[KM]"
++number of bytes to transmit (instead of \-t)
+ .TP
+-.BR -r ", " --tradeoff " "
++.BR \-r ", " \-\-tradeoff " "
+ Do a bidirectional test individually
+ .TP
+-.BR -t ", " --time " \fIn\fR"
++.BR \-t ", " \-\-time " \fIn\fR"
+ time in seconds to transmit for (default 10 secs)
+ .TP
+-.BR -F ", " --fileinput " <name>"
++.BR \-F ", " \-\-fileinput " <name>"
+ input the data to be transmitted from a file
+ .TP
+-.BR -I ", " --stdin " "
++.BR \-I ", " \-\-stdin " "
+ input the data to be transmitted from stdin
+ .TP
+-.BR -L ", " --listenport " \fIn\fR"
++.BR \-L ", " \-\-listenport " \fIn\fR"
+ port to recieve bidirectional tests back on
+ .TP
+-.BR -P ", " --parallel " \fIn\fR"
++.BR \-P ", " \-\-parallel " \fIn\fR"
+ number of parallel client threads to run
+ .TP
+-.BR -T ", " --ttl " \fIn\fR"
++.BR \-T ", " \-\-ttl " \fIn\fR"
+ time-to-live, for multicast (default 1)
+ .TP
+-.BR -Z ", " --linux-congestion " <algo>"
++.BR \-Z ", " \-\-linux\-congestion " <algo>"
+ set TCP congestion control algorithm (Linux only)
+ .SH ENVIRONMENT
+ .TP
+@@ -143,6 +143,6 @@
+ Kevin Gibbs,
+ John Estabrook <jestabro at ncsa.uiuc.edu>,
+ Andrew Gallatin <gallatin at gmail.com>,
+-Stephen Hemminger <shemminger at linux-foundation.org>
++Stephen Hemminger <shemminger at linux\-foundation.org>
+ .SH "SEE ALSO"
+ http://iperf.sourceforge.net/
diff --git a/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/004-svn-r43-ro.patch b/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/004-svn-r43-ro.patch
new file mode 100644
index 0000000..8340148
--- /dev/null
+++ b/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/004-svn-r43-ro.patch
@@ -0,0 +1,117 @@
+Import Debian patches and fix a lot of real bugs.
+
+Upstream-Status: Inappropriate [not author. Above message was get from oe.dev c10c33f86903c93611023197a7f812459c2dfe2d]
+
+--- iperf-2.0.4-4/AUTHORS 2009-07-06 12:02:24.159696747 +0200
++++ iperf-2.0.4/AUTHORS 2009-07-06 12:14:32.236079541 +0200
+@@ -28,3 +28,7 @@
+
+ Stephen Hemminger <shemminger@linux-foundation.org>
+ * Linux congestion control selection and theading improvements
++
++Nathan Jones <nmjones@users.sourceforge.net>
++ * patch for underflow when value specified in -n is not a multiple of -l
++
+--- iperf-2.0.4-4/ChangeLog 2009-07-06 12:02:24.166276642 +0200
++++ iperf-2.0.4/ChangeLog 2009-07-06 12:15:28.883699655 +0200
+@@ -1,3 +1,18 @@
++2008-05-09 Jon Dugan <jdugan@x1024.net>
++
++* change currLen to unsigned to squelch warning generated by Nathan's patch
++
++2008-05-09 Nathan Jones <nmjones@users.sourceforge.net>
++
++* prevent underflow when the amount of data to be transmitted (-n) is not a
++multiple of the buffer size (-l) Patch:
++https://sourceforge.net/tracker/index.php?func=detail&aid=1943432&group_id=128336&atid=711373
++
++2008-04-08 Jon Dugan <jdugan@x1024.net>
++
++* print report headers only once
++* use appropriate report header for UDP tests
++
+ 2008-04-07 Jon Dugan <jdugan@x1024.net>
+
+ * Add man page to autoconf goo
+diff -urN 204orig/src/Client.cpp trunk/src/Client.cpp
+--- 204orig/src/Client.cpp 2008-04-08 04:37:54.000000000 +0200
++++ trunk/src/Client.cpp 2008-05-10 05:18:35.000000000 +0200
+@@ -116,7 +116,7 @@
+ const int kBytes_to_Bits = 8;
+
+ void Client::RunTCP( void ) {
+- long currLen = 0;
++ unsigned long currLen = 0;
+ struct itimerval it;
+ max_size_t totLen = 0;
+
+@@ -170,7 +170,12 @@
+ }
+
+ if ( !mMode_Time ) {
+- mSettings->mAmount -= currLen;
++ /* mAmount may be unsigned, so don't let it underflow! */
++ if( mSettings->mAmount >= currLen ) {
++ mSettings->mAmount -= currLen;
++ } else {
++ mSettings->mAmount = 0;
++ }
+ }
+
+ } while ( ! (sInterupted ||
+@@ -198,7 +203,7 @@
+
+ void Client::Run( void ) {
+ struct UDP_datagram* mBuf_UDP = (struct UDP_datagram*) mBuf;
+- long currLen = 0;
++ unsigned long currLen = 0;
+
+ int delay_target = 0;
+ int delay = 0;
+@@ -310,7 +315,12 @@
+ delay_loop( delay );
+ }
+ if ( !mMode_Time ) {
+- mSettings->mAmount -= currLen;
++ /* mAmount may be unsigned, so don't let it underflow! */
++ if( mSettings->mAmount >= currLen ) {
++ mSettings->mAmount -= currLen;
++ } else {
++ mSettings->mAmount = 0;
++ }
+ }
+
+ } while ( ! (sInterupted ||
+diff -urN 204orig/src/ReportDefault.c trunk/src/ReportDefault.c
+--- 204orig/src/ReportDefault.c 2008-04-08 04:37:54.000000000 +0200
++++ trunk/src/ReportDefault.c 2008-04-09 02:08:11.000000000 +0200
+@@ -67,6 +67,7 @@
+ * Prints transfer reports in default style
+ */
+ void reporter_printstats( Transfer_Info *stats ) {
++ static char header_printed = 0;
+
+ byte_snprintf( buffer, sizeof(buffer)/2, (double) stats->TotalLen,
+ toupper( stats->mFormat));
+@@ -76,13 +77,19 @@
+
+ if ( stats->mUDP != (char)kMode_Server ) {
+ // TCP Reporting
+- printf( report_bw_header);
++ if( !header_printed ) {
++ printf( report_bw_header);
++ header_printed = 1;
++ }
+ printf( report_bw_format, stats->transferID,
+ stats->startTime, stats->endTime,
+ buffer, &buffer[sizeof(buffer)/2] );
+ } else {
+ // UDP Reporting
+- printf( report_bw_jitter_loss_header);
++ if( !header_printed ) {
++ printf( report_bw_jitter_loss_header);
++ header_printed = 1;
++ }
+ printf( report_bw_jitter_loss_format, stats->transferID,
+ stats->startTime, stats->endTime,
+ buffer, &buffer[sizeof(buffer)/2],
diff --git a/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/005-iperf-die-on-bind-fail.patch b/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/005-iperf-die-on-bind-fail.patch
new file mode 100644
index 0000000..ec13d6b
--- /dev/null
+++ b/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/005-iperf-die-on-bind-fail.patch
@@ -0,0 +1,15 @@
+Import Debian patches and fix a lot of real bugs.
+
+Upstream-Status: Inappropriate [not author. Above message was get from oe.dev c10c33f86903c93611023197a7f812459c2dfe2d]
+
+--- iperf-2.0.4/src/Listener.cpp 2009-02-23 16:20:31.000000000 -0500
++++ iperf-2.0.4-fixed/src/Listener.cpp 2009-02-23 16:20:40.000000000 -0500
+@@ -333,7 +333,7 @@
+ #endif
+ {
+ rc = bind( mSettings->mSock, (sockaddr*) &mSettings->local, mSettings->size_local );
+- WARN_errno( rc == SOCKET_ERROR, "bind" );
++ FAIL_errno( rc == SOCKET_ERROR, "bind", mSettings );
+ }
+ // listen for connections (TCP only).
+ // default backlog traditionally 5
diff --git a/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/006-iperf-die-on-connect-fail.patch b/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/006-iperf-die-on-connect-fail.patch
new file mode 100644
index 0000000..9e17e6d
--- /dev/null
+++ b/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/006-iperf-die-on-connect-fail.patch
@@ -0,0 +1,15 @@
+Import Debian patches and fix a lot of real bugs.
+
+Upstream-Status: Inappropriate [not author. Above message was get from oe.dev c10c33f86903c93611023197a7f812459c2dfe2d]
+
+--- iperf-2.0.4/src/Client.cpp 2008-04-07 22:37:54.000000000 -0400
++++ iperf-2.0.4-fixed/src/Client.cpp 2009-03-03 12:30:02.000000000 -0500
+@@ -403,7 +403,7 @@
+ // connect socket
+ rc = connect( mSettings->mSock, (sockaddr*) &mSettings->peer,
+ SockAddr_get_sizeof_sockaddr( &mSettings->peer ));
+- WARN_errno( rc == SOCKET_ERROR, "connect" );
++ FAIL_errno( rc == SOCKET_ERROR, "connect", mSettings );
+
+ getsockname( mSettings->mSock, (sockaddr*) &mSettings->local,
+ &mSettings->size_local );
diff --git a/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/007-iperf-reporter-deadlock.patch b/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/007-iperf-reporter-deadlock.patch
new file mode 100644
index 0000000..4b5f914
--- /dev/null
+++ b/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/007-iperf-reporter-deadlock.patch
@@ -0,0 +1,68 @@
+by Kirby Zhou < kirbyzhou \x40 sohu-rd.com >
+add a Condition_Wait_Event for ReporterDoneCond
+
+Upstream-Status: Inappropriate [not author]
+
+--- iperf-2.0.4.orig/include/Condition.h 2007-08-30 00:06:19.000000000 +0200
++++ iperf-2.0.4/include/Condition.h 2009-07-06 11:45:02.407700310 +0200
+@@ -115,6 +115,11 @@ typedef struct Condition {
+ // sleep this thread, waiting for condition signal
+ #if defined( HAVE_POSIX_THREAD )
+ #define Condition_Wait( Cond ) pthread_cond_wait( &(Cond)->mCondition, &(Cond)->mMutex )
++ #define Condition_Wait_Event( Cond ) do { \
++ Mutex_Lock( &(Cond)->mMutex ); \
++ pthread_cond_wait( &(Cond)->mCondition, &(Cond)->mMutex ); \
++ Mutex_Unlock( &(Cond)->mMutex ); \
++ } while ( 0 )
+ #elif defined( HAVE_WIN32_THREAD )
+ // atomically release mutex and wait on condition,
+ // then re-acquire the mutex
+@@ -122,6 +127,10 @@ typedef struct Condition {
+ SignalObjectAndWait( (Cond)->mMutex, (Cond)->mCondition, INFINITE, false ); \
+ Mutex_Lock( &(Cond)->mMutex ); \
+ } while ( 0 )
++ #define Condition_Wait_Event( Cond ) do { \
++ Mutex_Lock( &(Cond)->mMutex ); \
++ SignalObjectAndWait( (Cond)->mMutex, (Cond)->mCondition, INFINITE, false ); \
++ } while ( 0 )
+ #else
+ #define Condition_Wait( Cond )
+ #endif
+--- iperf-2.0.4.orig/src/Reporter.c 2009-07-06 11:49:05.996443011 +0200
++++ iperf-2.0.4/src/Reporter.c 2009-07-06 11:46:52.919699530 +0200
+@@ -339,7 +339,7 @@ void ReportPacket( ReportHeader* agent,
+ // item
+ while ( index == 0 ) {
+ Condition_Signal( &ReportCond );
+- Condition_Wait( &ReportDoneCond );
++ Condition_Wait_Event( &ReportDoneCond );
+ index = agent->reporterindex;
+ }
+ agent->agentindex = 0;
+@@ -347,7 +347,7 @@ void ReportPacket( ReportHeader* agent,
+ // Need to make sure that reporter is not about to be "lapped"
+ while ( index - 1 == agent->agentindex ) {
+ Condition_Signal( &ReportCond );
+- Condition_Wait( &ReportDoneCond );
++ Condition_Wait_Event( &ReportDoneCond );
+ index = agent->reporterindex;
+ }
+
+@@ -391,7 +391,7 @@ void EndReport( ReportHeader *agent ) {
+ if ( agent != NULL ) {
+ int index = agent->reporterindex;
+ while ( index != -1 ) {
+- Condition_Wait( &ReportDoneCond );
++ Condition_Wait_Event( &ReportDoneCond );
+ index = agent->reporterindex;
+ }
+ agent->agentindex = -1;
+@@ -412,7 +412,7 @@ void EndReport( ReportHeader *agent ) {
+ Transfer_Info *GetReport( ReportHeader *agent ) {
+ int index = agent->reporterindex;
+ while ( index != -1 ) {
+- Condition_Wait( &ReportDoneCond );
++ Condition_Wait_Event( &ReportDoneCond );
+ index = agent->reporterindex;
+ }
+ return &agent->report.info;
diff --git a/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/008-numofreport.patch b/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/008-numofreport.patch
new file mode 100644
index 0000000..c5d85b1
--- /dev/null
+++ b/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/008-numofreport.patch
@@ -0,0 +1,15 @@
+by Kirby Zhou < kirbyzhou \x40 sohu-rd.com >
+increase the queue length to avoid thread racing
+
+Upstream-Status: Inappropriate [not author]
+--- iperf-2.0.4.orig/include/Reporter.h 2008-04-08 04:37:54.000000000 +0200
++++ iperf-2.0.4/include/Reporter.h 2009-07-06 11:53:58.700541554 +0200
+@@ -61,7 +61,7 @@ struct server_hdr;
+
+ #include "Settings.hpp"
+
+-#define NUM_REPORT_STRUCTS 700
++#define NUM_REPORT_STRUCTS 5700
+ #define NUM_MULTI_SLOTS 5
+
+ #ifdef __cplusplus
diff --git a/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/009-delayloop.patch b/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/009-delayloop.patch
new file mode 100644
index 0000000..a2a0797
--- /dev/null
+++ b/meta-edison-distro/recipes-benchmark/iperf/iperf-2.0.4/009-delayloop.patch
@@ -0,0 +1,22 @@
+by Kirby Zhou < kirbyzhou \x40 sohu-rd.com >
+using sched_yield to schedule other threads, so multiple iperf can run simultaneously
+using usleep with delay-loop between 2 package is long than 1.25ms.
+
+Upstream-Status: Inappropriate [not author]
+
+--- iperf-2.0.4-4/compat/delay.cpp 2009-07-06 12:02:24.166276642 +0200
++++ iperf-2.0.4/compat/delay.cpp 2009-07-06 12:01:33.858384005 +0200
+@@ -69,6 +69,13 @@ void delay_loop( unsigned long usec ) {
+
+ Timestamp now;
+ while ( now.before( end ) ) {
++ long diff = end.subUsec(now);
++ if (diff >= 1250) {
++ usleep(0);
++ }
++ if (diff >= 2) {
++ sched_yield();
++ }
+ now.setnow();
+ }
+ }
diff --git a/meta-edison-distro/recipes-benchmark/iperf/iperf_2.0.4.bb b/meta-edison-distro/recipes-benchmark/iperf/iperf_2.0.4.bb
new file mode 100644
index 0000000..bd8bac1
--- /dev/null
+++ b/meta-edison-distro/recipes-benchmark/iperf/iperf_2.0.4.bb
@@ -0,0 +1,46 @@
+DESCRIPTION = "Iperf is a tool to measure maximum TCP bandwidth, allowing the tuning of various parameters and UDP characteristics"
+HOMEPAGE = "http://dast.nlanr.net/Projects/Iperf/"
+SECTION = "console/network"
+LICENSE = "NewBSD"
+LIC_FILES_CHKSUM = "file://COPYING;md5=e8478eae9f479e39bc34975193360298"
+
+SRC_URI = " \
+ ${SOURCEFORGE_MIRROR}/iperf/iperf-${PV}.tar.gz \
+ file://000-Iperf_Fix-CPU-Usage.diff \
+ file://001-cast-to-max_size_t-instead-of-int.patch \
+ file://003-fix-hyphen-used-as-minus-sign.patch \
+ file://004-svn-r43-ro.patch \
+ file://005-iperf-die-on-bind-fail.patch \
+ file://006-iperf-die-on-connect-fail.patch \
+ file://007-iperf-reporter-deadlock.patch \
+ file://008-numofreport.patch \
+ file://009-delayloop.patch \
+ "
+
+
+SRC_URI[md5sum] = "8c5bc14cc2ea55f18f22afe3c23e3dcb"
+SRC_URI[sha256sum] = "3b52f1c178d6a99c27114929d5469c009197d15379c967b329bafb956f397944"
+
+inherit autotools
+
+S="${WORKDIR}/iperf-${PV}"
+
+EXTRA_OECONF = "--exec-prefix=${STAGING_DIR_HOST}${layout_exec_prefix}"
+
+do_configure() {
+ export ac_cv_func_malloc_0_nonnull=yes
+ gnu-configize
+ oe_runconf
+}
+
+do_compile() {
+ cd ${WORKDIR}/iperf-${PV}
+ oe_runmake
+}
+
+do_install() {
+ cd ${WORKDIR}/iperf-${PV}/src
+ oe_runmake DESTDIR=${D} install
+}
+
+
diff --git a/meta-edison-distro/recipes-connectivity/bluetooth-rfkill-event/COPYING b/meta-edison-distro/recipes-connectivity/bluetooth-rfkill-event/COPYING
new file mode 100644
index 0000000..48172c1
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/bluetooth-rfkill-event/COPYING
@@ -0,0 +1,14 @@
+ Copyright (c) 2014, Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59
+ Temple Place - Suite 330, Boston, MA 02111-1307, USA.
diff --git a/meta-edison-distro/recipes-connectivity/bluetooth-rfkill-event/bluetooth-rfkill-event_1.0.bb b/meta-edison-distro/recipes-connectivity/bluetooth-rfkill-event/bluetooth-rfkill-event_1.0.bb
new file mode 100644
index 0000000..72bfc01
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/bluetooth-rfkill-event/bluetooth-rfkill-event_1.0.bb
@@ -0,0 +1,41 @@
+DESCRIPTION = "Bluetooth rfkill event daemon for Bluetooth chips"
+SECTION = "connectivity"
+
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://${THISDIR}/COPYING;md5=3fa94220fac4e7b1463e6fd8d63140c5"
+
+DEPENDS = "glib-2.0 bluez5"
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/files/"
+
+inherit systemd
+
+SYSTEMD_SERVICE_${PN} = "bluetooth-rfkill-event.service"
+
+SRC_URI = "file://bluetooth_rfkill_event.c \
+ file://bluetooth-rfkill-event.service \
+ file://bcm43341.conf"
+
+S = "${WORKDIR}"
+
+INC_DIRS = "-I${STAGING_INCDIR}/glib-2.0 -I${STAGING_LIBDIR}/glib-2.0/include/"
+
+LIBS = "-lglib-2.0"
+
+do_compile() {
+ ${CC} $CFLAGS -o bluetooth_rfkill_event bluetooth_rfkill_event.c ${INC_DIRS} ${LIBS}
+}
+
+do_install() {
+ install -v -d ${D}${sbindir}
+ install -m 0755 bluetooth_rfkill_event ${D}${sbindir}
+
+ if ${@base_contains('DISTRO_FEATURES','systemd','true','false',d)}; then
+ # Copy file service
+ install -d ${D}/${systemd_unitdir}/system
+ install -m 644 ${WORKDIR}/bluetooth-rfkill-event.service ${D}/${systemd_unitdir}/system
+ fi
+
+ install -v -d ${D}/etc/firmware/
+ install -m 0755 ${WORKDIR}/bcm43341.conf ${D}/etc/firmware/bcm43341.conf
+}
diff --git a/meta-edison-distro/recipes-connectivity/bluetooth-rfkill-event/files/bcm43341.conf b/meta-edison-distro/recipes-connectivity/bluetooth-rfkill-event/files/bcm43341.conf
new file mode 100644
index 0000000..d43b051
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/bluetooth-rfkill-event/files/bcm43341.conf
@@ -0,0 +1,32 @@
+###########################################################################
+#
+# Configuration file for Broadcom hciattach utility (brcm_patchram_plus)
+#
+# option are loaded by rfkill event daemon and passed to brcm_patchram_plus
+#
+###########################################################################
+[General]
+
+# fork
+fork = true
+
+# Low Power Mode
+lpm = true
+
+# register HCI device
+reg_hci = true
+
+# set baudrate; possible values:
+# 115200, 230400, 460800, 500000, 576000, 921600
+# 1000000, 1152000, 1500000, 2000000, 2500000, 3000000, 3500000, 4000000
+baud_rate = 3000000
+
+# FW patch file
+fw_patch = /etc/firmware/bcm43341.hcd
+
+# UART device
+uart_dev = /dev/ttyMFD0
+
+# SCO settings
+# configure sco routing to Transport (HCI);
+scopcm = 1,0,0,0,0,0,0,0,0,0
diff --git a/meta-edison-distro/recipes-connectivity/bluetooth-rfkill-event/files/bluetooth-rfkill-event.service b/meta-edison-distro/recipes-connectivity/bluetooth-rfkill-event/files/bluetooth-rfkill-event.service
new file mode 100644
index 0000000..a0565f5
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/bluetooth-rfkill-event/files/bluetooth-rfkill-event.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Bluetooth rf kill event daemon
+
+[Service]
+Type=simple
+ExecStart=/usr/sbin/bluetooth_rfkill_event
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-edison-distro/recipes-connectivity/bluetooth-rfkill-event/files/bluetooth_rfkill_event.c b/meta-edison-distro/recipes-connectivity/bluetooth-rfkill-event/files/bluetooth_rfkill_event.c
new file mode 100644
index 0000000..9d69805
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/bluetooth-rfkill-event/files/bluetooth_rfkill_event.c
@@ -0,0 +1,614 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2014, Intel Corporation.
+
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *******************************************************************************/
+
+/*******************************************************************************
+ **
+ ** Name: bluetooth_rfkill_event.c
+ **
+ ** Description: This program is listening rfkill event and detect when a
+ ** 'power' rfkill interface is unblocked and trigger FW patch
+ ** download for detected chip.
+ **
+ *******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/poll.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <limits.h>
+#include <glib.h>
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+
+enum {
+ BT_PWR,
+ BT_HCI,
+};
+
+/* list of all supported chips:
+ name is defined in the kernel driver implementing rfkill interface for power */
+#define BCM_RFKILL_NAME "bcm43xx Bluetooth\n"
+#define BCM_43341_UART_DEV "/dev/ttyMFD0"
+#define BD_ADD_FACTORY_FILE "/factory/bluetooth_address"
+char factory_bd_add[18];
+const char default_bd_addr[] = "00:43:34:b1:be:ef";
+
+/* attempt to set hci dev UP */
+#define MAX_RETRY 10
+
+enum rfkill_operation {
+ RFKILL_OP_ADD = 0,
+ RFKILL_OP_DEL,
+ RFKILL_OP_CHANGE,
+ RFKILL_OP_CHANGE_ALL,
+};
+
+enum rfkill_type {
+ RFKILL_TYPE_ALL = 0,
+ RFKILL_TYPE_WLAN,
+ RFKILL_TYPE_BLUETOOTH,
+ RFKILL_TYPE_UWB,
+ RFKILL_TYPE_WIMAX,
+ RFKILL_TYPE_WWAN,
+ RFKILL_TYPE_GPS,
+ RFKILL_TYPE_FM,
+ NUM_RFKILL_TYPES,
+};
+
+struct rfkill_event {
+ unsigned int idx;
+ unsigned char type;
+ unsigned char op;
+ unsigned char soft, hard;
+} __packed;
+
+/* HCI UART driver initialization utility; usually it takes care of FW patch download as well */
+char hciattach[PATH_MAX];
+char hciattach_options[PATH_MAX];
+char hci_uart_default_dev[PATH_MAX] = BCM_43341_UART_DEV;
+
+gboolean hci_dev_registered;
+int bt_pwr_rfkill_idx;
+
+struct main_opts {
+ /* 'fork' will keep running in background the hciattach utility; N/A if enable_hci is FALSE */
+ gboolean enable_fork;
+ /* send enable Low Power Mode to Broadcom bluetooth controller; needed if power driver implements it */
+ gboolean enable_lpm;
+ /* register the hci device */
+ gboolean enable_hci;
+ /* set UART baud rate */
+ gboolean set_baud_rate;
+ int baud_rate;
+ /* download FW patch */
+ gboolean dl_patch;
+ char* fw_patch;
+ /* UART device used for bluetooth; platform dependant */
+ char* uart_dev;
+ /* configure BD address */
+ gboolean set_bd;
+ char* bd_add;
+ /* set SCO routing for audio interface */
+ gboolean set_scopcm;
+ char* scopcm;
+};
+
+struct main_opts main_opts;
+
+static const char * const supported_options[] = {
+ "fork",
+ "lpm",
+ "reg_hci",
+ "baud_rate",
+ "fw_patch",
+ "uart_dev",
+ "scopcm",
+};
+
+void init_config()
+{
+ memset(&main_opts, 0, sizeof(main_opts));
+
+ main_opts.enable_fork = TRUE;
+ main_opts.enable_lpm = TRUE;
+ main_opts.enable_hci = FALSE;
+ main_opts.set_baud_rate = FALSE;
+ main_opts.dl_patch = FALSE;
+ main_opts.set_bd = FALSE;
+ main_opts.set_scopcm = FALSE;
+}
+
+GKeyFile *load_config(const char *file)
+{
+ GError *err = NULL;
+ GKeyFile *keyfile;
+
+ keyfile = g_key_file_new();
+
+ g_key_file_set_list_separator(keyfile, ',');
+
+ if (!g_key_file_load_from_file(keyfile, file, 0, &err)) {
+ if (!g_error_matches(err, G_FILE_ERROR, G_FILE_ERROR_NOENT))
+ error("Parsing %s failed: %s", file, err->message);
+ g_error_free(err);
+ g_key_file_free(keyfile);
+ return NULL;
+ }
+
+ return keyfile;
+}
+
+void check_config(GKeyFile *config)
+{
+ char **keys;
+ int i;
+
+ if (!config)
+ return;
+
+ keys = g_key_file_get_groups(config, NULL);
+
+ for (i = 0; keys != NULL && keys[i] != NULL; i++) {
+ if (!g_str_equal(keys[i], "General"))
+ warn("Unknown group %s in main.conf", keys[i]);
+ }
+
+ g_strfreev(keys);
+
+ keys = g_key_file_get_keys(config, "General", NULL, NULL);
+
+ for (i = 0; keys != NULL && keys[i] != NULL; i++) {
+ gboolean found;
+ unsigned int j;
+
+ found = FALSE;
+ for (j = 0; j < G_N_ELEMENTS(supported_options); j++) {
+ if (g_str_equal(keys[i], supported_options[j])) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found)
+ warn("Unknown key %s in main.conf", keys[i]);
+ }
+
+ g_strfreev(keys);
+}
+
+void parse_config(GKeyFile *config)
+{
+ GError *err = NULL;
+ char *str;
+ int val;
+ gboolean boolean;
+
+ if (!config)
+ return;
+
+ check_config(config);
+
+ boolean = g_key_file_get_boolean(config, "General", "fork", &err);
+ if (err) {
+ g_clear_error(&err);
+ } else
+ main_opts.enable_fork = boolean;
+
+ boolean = g_key_file_get_boolean(config, "General", "lpm", &err);
+ if (err) {
+ g_clear_error(&err);
+ } else
+ main_opts.enable_lpm = boolean;
+
+ boolean = g_key_file_get_boolean(config, "General", "reg_hci", &err);
+ if (err) {
+ g_clear_error(&err);
+ } else
+ main_opts.enable_hci = boolean;
+
+ val = g_key_file_get_integer(config, "General", "baud_rate", &err);
+ if (err) {
+ g_clear_error(&err);
+ } else {
+ main_opts.baud_rate = val;
+ main_opts.set_baud_rate = TRUE;
+ }
+
+ str = g_key_file_get_string(config, "General", "fw_patch", &err);
+ if (err) {
+ g_clear_error(&err);
+ } else {
+ g_free(main_opts.fw_patch);
+ main_opts.fw_patch = str;
+ main_opts.dl_patch = TRUE;
+ }
+
+ str = g_key_file_get_string(config, "General", "uart_dev", &err);
+ if (err) {
+ g_clear_error(&err);
+ main_opts.uart_dev = hci_uart_default_dev;
+ } else {
+ g_free(main_opts.uart_dev);
+ main_opts.uart_dev = str;
+ }
+
+ str = g_key_file_get_string(config, "General", "scopcm", &err);
+ if (err) {
+ g_clear_error(&err);
+ } else {
+ g_free(main_opts.scopcm);
+ main_opts.scopcm = str;
+ main_opts.set_scopcm = TRUE;
+ }
+}
+
+gboolean check_bd_format(const char* bd_add)
+{
+ int i, len;
+
+ len = strlen(bd_add);
+
+ if (len != 17)
+ return FALSE;
+
+ for (i = 0 ; i < len; i++)
+ {
+ /* check that format is xx:xx: ... etc. */
+ if ((isxdigit(bd_add[i]) && i%3 != 2) ||
+ (bd_add[i] == ':' && i%3 == 2))
+ {
+ ;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+void load_bd_add(void)
+{
+ FILE *fp;
+ int ret;
+
+ fp = fopen(BD_ADD_FACTORY_FILE, "r");
+
+ /* if BD add file has not been provisioned do not send VSC to set BD address: the one configured in OTP will be used or default FW one */
+ if (fp == NULL)
+ {
+ main_opts.set_bd = FALSE;
+ return;
+ }
+
+ ret = fscanf(fp, "%17c", factory_bd_add);
+
+ /* if factory BD address is not well formatted or not present do not send VSC to set BD address: the one configured in OTP will be used or default FW one */
+ if (!(ret == 1 && check_bd_format(factory_bd_add)))
+ {
+ main_opts.set_bd = FALSE;
+ }
+ else
+ {
+ main_opts.bd_add = factory_bd_add;
+ main_opts.set_bd = TRUE;
+ }
+
+ fclose(fp);
+
+}
+
+void read_config(char* file)
+{
+ GKeyFile *config;
+ char *cur = hciattach_options;
+ const char *end = hciattach_options + sizeof(hciattach_options);
+
+ /* set first default values and then load configured ones */
+ init_config();
+ config = load_config(file);
+ parse_config(config);
+ load_bd_add();
+
+ /* set always configured options: use same configured baud-rate also for download, and ignore first 2 bytes (needed by bcm43341 and more recent brcm bt chip) */
+ cur += snprintf(cur, end-cur, "%s", "--use_baudrate_for_download --no2bytes");
+
+ /* concatenate configured options */
+ if ((cur < end) && (main_opts.enable_fork)) {
+ cur += snprintf(cur, end-cur," %s", "--enable_fork");
+ }
+ if ((cur < end) && (main_opts.enable_lpm)) {
+ cur += snprintf(cur, end-cur," %s", "--enable_lpm");
+ }
+ if ((cur < end) && (main_opts.enable_hci)) {
+ cur += snprintf(cur, end-cur," %s", "--enable_hci");
+ }
+ if ((cur < end) && (main_opts.set_baud_rate)) {
+ cur += snprintf(cur, end-cur," --baudrate %d", main_opts.baud_rate);
+ }
+ if ((cur < end) && (main_opts.dl_patch)) {
+ cur += snprintf(cur, end-cur," --patchram %s", main_opts.fw_patch);
+ }
+ if ((cur < end) && (main_opts.set_bd)) {
+ cur += snprintf(cur, end-cur," --bd_addr %s", main_opts.bd_add);
+ }
+ if ((cur < end) && (main_opts.set_scopcm)) {
+ cur += snprintf(cur, end-cur," --scopcm %s", main_opts.scopcm);
+ }
+}
+
+void free_hci()
+{
+ char cmd[PATH_MAX];
+
+ snprintf(cmd, sizeof(cmd), "pidof %s", hciattach);
+
+ if (!system(cmd))
+ {
+ snprintf(cmd, sizeof(cmd), "killall %s", hciattach);
+ system(cmd);
+ printf("killing %s\n", hciattach);
+ fflush(stdout);
+ }
+}
+
+void attach_hci()
+{
+ char hci_execute[PATH_MAX];
+
+ snprintf(hci_execute, sizeof(hci_execute), "%s %s %s", hciattach, hciattach_options, main_opts.uart_dev);
+
+ printf("execute %s\n", hci_execute);
+ fflush(stdout);
+
+ system(hci_execute);
+
+ /* remember if hci device has been registered (in case conf file is changed) */
+ hci_dev_registered = main_opts.enable_hci;
+}
+
+void up_hci(int hci_idx)
+{
+ int sk, i;
+ struct hci_dev_info hci_info;
+
+ sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+
+ if (sk < 0)
+ {
+ perror("Fail to create bluetooth hci socket");
+ return;
+ }
+
+ memset(&hci_info, 0, sizeof(hci_info));
+
+ hci_info.dev_id = hci_idx;
+
+ for (i = 0; i < MAX_RETRY; i++)
+ {
+ if (ioctl(sk, HCIGETDEVINFO, (void *) &hci_info) < 0)
+ {
+ perror("Failed to get HCI device information");
+ /* sleep 100ms */
+ usleep(100*1000);
+ continue;
+ }
+
+ if (hci_test_bit(HCI_RUNNING, &hci_info.flags) && !hci_test_bit(HCI_INIT, &hci_info.flags))
+ {
+ /* check if kernel has already set device UP... */
+ if (!hci_test_bit(HCI_UP, &hci_info.flags))
+ {
+ if (ioctl(sk, HCIDEVUP, hci_idx) < 0)
+ {
+ /* ignore if device is already UP and ready */
+ if (errno == EALREADY)
+ break;
+
+ perror("Fail to set hci device UP");
+ }
+ }
+ break;
+ }
+
+ /* sleep 100ms */
+ usleep(100*1000);
+ }
+
+ close(sk);
+}
+
+/* calling this routine to be sure to have rfkill hci bluetooth interface unblocked:
+ if user does:
+ - 'rfkill block bluetooth' and then
+ - 'rfkill unblock 2'
+ once hci bluetooth is registered back it will be blocked */
+void rfkill_bluetooth_unblock()
+{
+ int fd, sk, times;
+ int ret = -1;
+ struct rfkill_event event;
+
+ fd = open("/dev/rfkill", O_RDWR | O_CLOEXEC);
+ if (fd < 0)
+ {
+ perror("fail to open rfkill interface");
+ return;
+ }
+ memset(&event, 0, sizeof(event));
+ event.op = RFKILL_OP_CHANGE_ALL;
+ event.type = RFKILL_TYPE_BLUETOOTH;
+ event.soft = 0;
+ if (write(fd, &event, sizeof(event)) < 0)
+ {
+ perror("fail to unblock rfkill bluetooth");
+ }
+ close(fd);
+
+}
+
+int main(int argc, char **argv)
+{
+ struct rfkill_event event;
+ struct timeval tv;
+ struct pollfd p;
+ ssize_t len;
+ int fd, fd_name, n, type;
+ int ret, hci_dev_id;
+ char *script;
+ char sysname[PATH_MAX];
+
+ /* this code is ispired by rfkill source code */
+
+ fd = open("/dev/rfkill", O_RDONLY);
+ if (fd < 0) {
+ perror("Can't open RFKILL control device");
+ return fd;
+ }
+
+ memset(&p, 0, sizeof(p));
+ p.fd = fd;
+ p.events = POLLIN | POLLHUP;
+
+ while (1) {
+ n = poll(&p, 1, -1);
+ if (n < 0) {
+ perror("Failed to poll RFKILL control device");
+ break;
+ }
+
+ if (n == 0)
+ continue;
+
+ len = read(fd, &event, sizeof(event));
+ if (len < 0) {
+ perror("Reading of RFKILL events failed");
+ break;
+ }
+
+ if (len != sizeof(event)) {
+ perror("Wrong size of RFKILL event");
+ break;
+ }
+
+ /* ignore event for others interfaces (not bluetooth) */
+ if (event.type != RFKILL_TYPE_BLUETOOTH)
+ continue;
+
+ gettimeofday(&tv, NULL);
+ printf("%ld.%06u: idx %u type %u op %u soft %u hard %u\n",
+ (long) tv.tv_sec, (unsigned int) tv.tv_usec,
+ event.idx, event.type, event.op, event.soft, event.hard);
+ fflush(stdout);
+
+ /* try to read rfkill interface name only if event is not a remove one, in this case call free_hci */
+ if (event.op != RFKILL_OP_DEL)
+ {
+ /* get the name to check the bt chip */
+ snprintf(sysname, sizeof(sysname), "/sys/class/rfkill/rfkill%u/name", event.idx);
+
+ fd_name = open(sysname, O_RDONLY);
+ if (fd_name < 0)
+ {
+ perror("fail to open rfkill name");
+ continue;
+ }
+
+ memset(sysname, 0, sizeof(sysname));
+
+ /* read name */
+ if (read(fd_name, sysname, sizeof(sysname) - 1) < 0)
+ {
+ perror("fail to read rfkill name");
+ close(fd_name);
+ continue;
+ }
+
+ close(fd_name);
+
+ /* based on chip read its config file, if any, and define the hciattach utility used to dowload the patch */
+ if (strncmp(BCM_RFKILL_NAME,sysname, sizeof(BCM_RFKILL_NAME)) == 0)
+ {
+ read_config("/etc/firmware/bcm43341.conf");
+ snprintf(hciattach, sizeof(hciattach), "brcm_patchram_plus");
+ type = BT_PWR;
+ }
+ else if (g_str_has_prefix(sysname, "hci") )
+ {
+ type = BT_HCI;
+ hci_dev_id = atoi(sysname + 3);
+ }
+ else
+ continue;
+ }
+
+ switch (event.op) {
+ case RFKILL_OP_CHANGE:
+ case RFKILL_OP_CHANGE_ALL:
+ case RFKILL_OP_ADD:
+ if (event.soft == 0 && event.hard == 0)
+ {
+ if (type == BT_PWR)
+ {
+ /* if unblock is for power interface: download patch and eventually register hci device */
+ free_hci();
+ attach_hci();
+ /* force to unblock also the bluetooth hci rfkill interface if hci device was registered */
+ if (hci_dev_registered)
+ rfkill_bluetooth_unblock();
+ }
+ else if (type == BT_HCI && hci_dev_registered)
+ {
+ /* wait unblock on hci bluetooth interface and force device UP */
+ up_hci(hci_dev_id);
+ }
+ }
+ else if (type == BT_PWR && hci_dev_registered)
+ {
+ /* for a block event on power interface force unblock of hci device interface */
+ free_hci();
+ }
+
+ /* save index of rfkill interface for bluetooth power */
+ if (event.op == RFKILL_OP_ADD && type == BT_PWR)
+ bt_pwr_rfkill_idx = event.idx;
+ break;
+ case RFKILL_OP_DEL:
+ /* in case pwr rfkill interface is removed, unregister hci dev if it was registered */
+ if (bt_pwr_rfkill_idx == event.idx && hci_dev_registered)
+ free_hci();
+ break;
+ default:
+ continue;
+ }
+
+ }
+
+ close(fd);
+
+ return 0;
+}
diff --git a/meta-edison-distro/recipes-connectivity/bluez5/bluez5_5.15.bbappend b/meta-edison-distro/recipes-connectivity/bluez5/bluez5_5.15.bbappend
new file mode 100644
index 0000000..3aad093
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/bluez5/bluez5_5.15.bbappend
@@ -0,0 +1,62 @@
+# overwrite to 5.24 version and its checksum
+
+PV = "5.24"
+
+SRC_URI[md5sum] = "37b785185fb98269b45e51b254bd8d3d"
+SRC_URI[sha256sum] = "e870c5fba0bf3496856fc720e2d217856fcf40b59829f8cc0c05902ebb9fb837"
+
+# to get bluetooth.conf
+FILESEXTRAPATHS_prepend := "${THISDIR}/files/"
+
+# few overwrite for 5.24 version
+SRC_URI = "\
+ ${KERNELORG_MIRROR}/linux/bluetooth/bluez-${PV}.tar.xz \
+ file://bluetooth.conf \
+ file://obex_set_dbus_session_service.patch \
+"
+
+RDEPENDS_${PN} += "eglibc-gconv-utf-16"
+
+PACKAGECONFIG[alsa] = ""
+
+EXTRA_OECONF = "\
+ --enable-sixaxis \
+ --enable-tools \
+ --disable-cups \
+ --enable-test \
+ --enable-datafiles \
+ ${@base_contains('DISTRO_FEATURES', 'systemd', '--with-systemdsystemunitdir=${systemd_unitdir}/system/', '--disable-systemd', d)} \
+ --enable-library \
+ --enable-experimental \
+"
+
+do_install_append() {
+ install -d ${D}${sysconfdir}/bluetooth/
+ if [ -f ${S}/profiles/audio/audio.conf ]; then
+ install -m 0644 ${S}/profiles/audio/audio.conf ${D}/${sysconfdir}/bluetooth/
+ fi
+ if [ -f ${S}/profiles/proximity/proximity.conf ]; then
+ install -m 0644 ${S}/profiles/proximity/proximity.conf ${D}/${sysconfdir}/bluetooth/
+ fi
+ if [ -f ${S}/profiles/network/network.conf ]; then
+ install -m 0644 ${S}/profiles/network/network.conf ${D}/${sysconfdir}/bluetooth/
+ fi
+ if [ -f ${S}/profiles/input/input.conf ]; then
+ install -m 0644 ${S}/profiles/input/input.conf ${D}/${sysconfdir}/bluetooth/
+ fi
+ if [ -f ${S}/src/main.conf ]; then
+ install -m 0644 ${S}/src/main.conf ${D}/${sysconfdir}/bluetooth/
+ fi
+ if [ -f ${S}/tools/obexctl ]; then
+ install -m 0755 ${S}/tools/obexctl ${D}${bindir}
+ fi
+
+ if ${@base_contains('DISTRO_FEATURES','systemd','true','false',d)}; then
+ # Copy file service
+ install -d ${D}/${systemd_unitdir}/system
+ install -m 644 ${S}/obexd/src/obex.service ${D}/${systemd_unitdir}/system/
+ fi
+
+ # at_console doesn't really work with the current state of OE, so punch some more holes so people can actually use BT
+ install -m 0644 ${WORKDIR}/bluetooth.conf ${D}/${sysconfdir}/dbus-1/system.d/
+}
diff --git a/meta-edison-distro/recipes-connectivity/bluez5/files/bluetooth.conf b/meta-edison-distro/recipes-connectivity/bluez5/files/bluetooth.conf
new file mode 100644
index 0000000..162c803
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/bluez5/files/bluetooth.conf
@@ -0,0 +1,24 @@
+<!-- This configuration file specifies the required security policies
+ for Bluetooth core daemon to work. -->
+
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+
+ <!-- ../system.conf have denied everything, so we just punch some holes -->
+
+ <policy context="default">
+ <allow own="org.bluez"/>
+ <allow own="org.bluez.obex"/>
+ <allow send_destination="org.bluez"/>
+ <allow send_destination="org.bluez.obex"/>
+ <allow send_interface="org.bluez.Agent1"/>
+ <allow send_interface="org.bluez.MediaEndpoint1"/>
+ <allow send_interface="org.bluez.Profile1"/>
+ <allow send_interface="org.bluez.ThermometerWatcher1"/>
+ <allow send_interface="org.bluez.AlertAgent1"/>
+ <allow send_interface="org.bluez.HeartRateWatcher1"/>
+ <allow send_interface="org.bluez.CyclingSpeedWatcher1"/>
+ </policy>
+
+</busconfig>
diff --git a/meta-edison-distro/recipes-connectivity/bluez5/files/obex_set_dbus_session_service.patch b/meta-edison-distro/recipes-connectivity/bluez5/files/obex_set_dbus_session_service.patch
new file mode 100644
index 0000000..4000aaf
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/bluez5/files/obex_set_dbus_session_service.patch
@@ -0,0 +1,10 @@
+--- a/obexd/src/obex.service.in 2014-10-30 14:40:00.832479049 +0100
++++ b/obexd/src/obex.service.in 2014-10-30 14:40:41.032477622 +0100
+@@ -4,6 +4,7 @@
+ [Service]
+ Type=dbus
+ BusName=org.bluez.obex
++Environment="DBUS_SESSION_BUS_ADDRESS=unix:path=/var/run/dbus/system_bus_socket"
+ ExecStart=@libexecdir@/obexd
+
+ [Install]
diff --git a/meta-edison-distro/recipes-connectivity/connman/connman.inc b/meta-edison-distro/recipes-connectivity/connman/connman.inc
new file mode 100644
index 0000000..b3147c9
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/connman/connman.inc
@@ -0,0 +1,215 @@
+SUMMARY = "A daemon for managing internet connections within embedded devices"
+DESCRIPTION = "The ConnMan project provides a daemon for managing \
+internet connections within embedded devices running the Linux \
+operating system. The Connection Manager is designed to be slim and \
+to use as few resources as possible, so it can be easily integrated. \
+It is a fully modular system that can be extended, through plug-ins, \
+to support all kinds of wired or wireless technologies. Also, \
+configuration methods, like DHCP and domain name resolving, are \
+implemented using plug-ins."
+HOMEPAGE = "http://connman.net/"
+BUGTRACKER = "https://01.org/jira/browse/CM"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://COPYING;md5=12f884d2ae1ff87c09e5b7ccc2c4ca7e \
+ file://src/main.c;beginline=1;endline=20;md5=d6a1ac98a6791c5294e8a7f176ecd66d"
+
+DEPENDS = "dbus glib-2.0 ppp iptables"
+
+INC_PR = "r20"
+
+EXTRA_OECONF += "\
+ ac_cv_path_WPASUPPLICANT=${sbindir}/wpa_supplicant \
+ ac_cv_path_PPPD=${sbindir}/pppd \
+ --enable-debug \
+ --enable-loopback \
+ --enable-ethernet \
+ --enable-tools \
+ --enable-test \
+ --disable-polkit \
+ --enable-client \
+ ${@base_contains('DISTRO_FEATURES', 'systemd', '--with-systemdunitdir=${systemd_unitdir}/system/', '--with-systemdunitdir=', d)} \
+"
+
+PACKAGECONFIG ??= "wispr \
+ ${@base_contains('DISTRO_FEATURES', 'wifi','wifi', '', d)} \
+ ${@base_contains('DISTRO_FEATURES', 'bluetooth','bluetooth', '', d)} \
+ ${@base_contains('DISTRO_FEATURES', '3g','3g', '', d)} \
+"
+
+# If you want ConnMan to support VPN, add following statement into
+# local.conf or distro config
+# PACKAGECONFIG_append_pn-connman = " openvpn vpnc l2tp pptp"
+
+PACKAGECONFIG[wifi] = "--enable-wifi, --disable-wifi, wpa-supplicant"
+PACKAGECONFIG[bluetooth] = "--enable-bluetooth, --disable-bluetooth, bluez4"
+PACKAGECONFIG[3g] = "--enable-ofono, --disable-ofono, ofono"
+PACKAGECONFIG[tist] = "--enable-tist,--disable-tist,"
+PACKAGECONFIG[openvpn] = "--enable-openvpn --with-openvpn=${sbindir}/openvpn,--disable-openvpn,,openvpn"
+PACKAGECONFIG[vpnc] = "--enable-vpnc --with-vpnc=${sbindir}/vpnc,--disable-vpnc,,vpnc"
+PACKAGECONFIG[l2tp] = "--enable-l2tp --with-l2tp=${sbindir}/xl2tpd,--disable-l2tp,,xl2tpd"
+PACKAGECONFIG[pptp] = "--enable-pptp --with-pptp=${sbindir}/pptp,--disable-pptp,,pptp-linux"
+# WISPr support for logging into hotspots, requires TLS
+PACKAGECONFIG[wispr] = "--enable-wispr,--disable-wispr,gnutls,"
+
+INITSCRIPT_NAME = "connman"
+INITSCRIPT_PARAMS = "start 05 5 2 3 . stop 22 0 1 6 ."
+
+python __anonymous () {
+ systemd_packages = "${PN}"
+ pkgconfig = d.getVar('PACKAGECONFIG', True)
+ if ('openvpn' or 'vpnc' or 'l2tp' or 'pptp') in pkgconfig.split():
+ systemd_packages += " ${PN}-vpn"
+ d.setVar('SYSTEMD_PACKAGES', systemd_packages)
+}
+
+SYSTEMD_SERVICE_${PN} = "connman.service"
+SYSTEMD_SERVICE_${PN}-vpn = "connman-vpn.service"
+SYSTEMD_WIRED_SETUP = "ExecStartPre=-${libdir}/connman/wired-setup"
+
+inherit autotools-brokensep pkgconfig systemd update-rc.d
+
+do_configure_append () {
+ sed -i "s#ExecStart=#${SYSTEMD_WIRED_SETUP}\nExecStart=#" ${S}/src/connman.service
+}
+
+# This allows *everyone* to access ConnMan over DBus, without any access
+# control. Really the at_console flag should work, which would mean that
+# both this and the xuser patch can be dropped.
+do_compile_append() {
+ sed -i -e s:deny:allow:g src/connman-dbus.conf
+ sed -i -e s:deny:allow:g vpn/vpn-dbus.conf
+}
+
+do_install_append() {
+ if ${@base_contains('DISTRO_FEATURES','sysvinit','true','false',d)}; then
+ install -d ${D}${sysconfdir}/init.d
+ install -m 0755 ${WORKDIR}/connman ${D}${sysconfdir}/init.d/connman
+ sed -i s%@LIBDIR@%${libdir}% ${D}${sysconfdir}/init.d/connman
+ fi
+
+ install -d ${D}${bindir}
+ install -m 0755 ${S}/tools/*-test ${D}${bindir}
+ if [ -e ${S}/tools/wispr ]; then
+ install -m 0755 ${S}/tools/wispr ${D}${bindir}
+ fi
+ install -m 0755 ${B}/client/connmanctl ${D}${bindir}
+
+ # We don't need to package an empty directory
+ rmdir --ignore-fail-on-non-empty ${D}${libdir}/connman/scripts
+
+ # Automake 1.12 won't install empty directories, but we need the
+ # plugins directory to be present for ownership
+ mkdir -p ${D}${libdir}/connman/plugins
+}
+
+# These used to be plugins, but now they are core
+RPROVIDES_${PN} = "\
+ connman-plugin-loopback \
+ connman-plugin-ethernet \
+ ${@base_contains('PACKAGECONFIG', 'bluetooth','connman-plugin-bluetooth', '', d)} \
+ ${@base_contains('PACKAGECONFIG', 'wifi','connman-plugin-wifi', '', d)} \
+ ${@base_contains('PACKAGECONFIG', '3g','connman-plugin-ofono', '', d)} \
+ "
+
+RDEPENDS_${PN} = "\
+ dbus \
+ ${@base_contains('PACKAGECONFIG', 'bluetooth', 'bluez4', '', d)} \
+ ${@base_contains('PACKAGECONFIG', 'wifi','wpa-supplicant', '', d)} \
+ ${@base_contains('PACKAGECONFIG', '3g','ofono', '', d)} \
+ xuser-account \
+ "
+
+PACKAGES_DYNAMIC += "^${PN}-plugin-.*"
+
+def add_rdepends(bb, d, file, pkg, depmap, multilib_prefix, add_insane_skip):
+ plugintype = pkg.split( '-' )[-1]
+ if plugintype in depmap:
+ rdepends = map(lambda x: multilib_prefix + x, \
+ depmap[plugintype].split())
+ d.setVar("RDEPENDS_%s" % pkg, " ".join(rdepends))
+ if add_insane_skip:
+ d.appendVar("INSANE_SKIP_%s" % pkg, "dev-so")
+
+python populate_packages_prepend() {
+ depmap = dict(pppd="ppp")
+ multilib_prefix = (d.getVar("MLPREFIX", True) or "")
+
+ hook = lambda file,pkg,x,y,z: \
+ add_rdepends(bb, d, file, pkg, depmap, multilib_prefix, False)
+ plugin_dir = d.expand('${libdir}/connman/plugins/')
+ plugin_name = d.expand('${PN}-plugin-%s')
+ do_split_packages(d, plugin_dir, '^(.*).so$', plugin_name, \
+ '${PN} plugin for %s', extra_depends='', hook=hook, prepend=True )
+
+ hook = lambda file,pkg,x,y,z: \
+ add_rdepends(bb, d, file, pkg, depmap, multilib_prefix, True)
+ plugin_dir = d.expand('${libdir}/connman/plugins-vpn/')
+ plugin_name = d.expand('${PN}-plugin-vpn-%s')
+ do_split_packages(d, plugin_dir, '^(.*).so$', plugin_name, \
+ '${PN} VPN plugin for %s', extra_depends='', hook=hook, prepend=True )
+}
+
+PACKAGES =+ "${PN}-tools ${PN}-tests ${PN}-client"
+
+FILES_${PN}-tools = "${bindir}/wispr"
+
+FILES_${PN}-tests = "${bindir}/*-test ${libdir}/${BPN}/test/*"
+RDEPENDS_${PN}-tests = "python-dbus python-pygobject python-textutils python-subprocess python-fcntl python-netclient"
+
+FILES_${PN}-client = "${bindir}/connmanctl"
+
+FILES_${PN} = "${bindir}/* ${sbindir}/* ${libexecdir}/* ${libdir}/lib*.so.* \
+ ${libdir}/connman/plugins \
+ ${sysconfdir} ${sharedstatedir} ${localstatedir} \
+ ${base_bindir}/* ${base_sbindir}/* ${base_libdir}/*.so* ${datadir}/${PN} \
+ ${datadir}/dbus-1/system-services/*"
+
+FILES_${PN}-dbg += "${libdir}/connman/*/.debug"
+
+FILES_${PN}-dev += "${libdir}/connman/*/*.la"
+
+PACKAGES =+ "${PN}-vpn"
+
+SUMMARY_${PN}-vpn = "A daemon for managing VPN connections within embedded devices"
+DESCRIPTION_${PN}-vpn = "The ConnMan VPN provides a daemon for \
+managing VPN connections within embedded devices running the Linux \
+operating system. The connman-vpnd handles all the VPN connections \
+and starts/stops VPN client processes when necessary. The connman-vpnd \
+provides a DBus API for managing VPN connections. All the different \
+VPN technogies are implemented using plug-ins."
+FILES_${PN}-vpn += "${sbindir}/connman-vpnd \
+ ${sysconfdir}/dbus-1/system.d/connman-vpn-dbus.conf \
+ ${datadir}/dbus-1/system-services/net.connman.vpn.service \
+ ${systemd_unitdir}/system/connman-vpn.service"
+
+SUMMARY_${PN}-plugin-vpn-openvpn = "An OpenVPN plugin for ConnMan VPN"
+DESCRIPTION_${PN}-plugin-vpn-openvpn = "The ConnMan OpenVPN plugin uses openvpn client \
+to create a VPN connection to OpenVPN server."
+FILES_${PN}-plugin-vpn-openvpn += "${libdir}/connman/scripts/openvpn-script \
+ ${libdir}/connman/plugins-vpn/openvpn.so"
+RDEPENDS_${PN}-plugin-vpn-openvpn += "${PN}-vpn"
+RRECOMMENDS_${PN} += "${@base_contains('PACKAGECONFIG','openvpn','${PN}-plugin-vpn-openvpn', '', d)}"
+
+SUMMARY_${PN}-plugin-vpn-vpnc = "A vpnc plugin for ConnMan VPN"
+DESCRIPTION_${PN}-plugin-vpn-vpnc = "The ConnMan vpnc plugin uses vpnc client \
+to create a VPN connection to Cisco3000 VPN Concentrator."
+FILES_${PN}-plugin-vpn-vpnc += "${libdir}/connman/scripts/openconnect-script \
+ ${libdir}/connman/plugins-vpn/vpnc.so"
+RDEPENDS_${PN}-plugin-vpn-vpnc += "${PN}-vpn"
+RRECOMMENDS_${PN} += "${@base_contains('PACKAGECONFIG','vpnc','${PN}-plugin-vpn-vpnc', '', d)}"
+
+SUMMARY_${PN}-plugin-vpn-l2tp = "A L2TP plugin for ConnMan VPN"
+DESCRIPTION_${PN}-plugin-vpn-l2tp = "The ConnMan L2TP plugin uses xl2tpd daemon \
+to create a VPN connection to L2TP server."
+FILES_${PN}-plugin-vpn-l2tp += "${libdir}/connman/scripts/libppp-plugin.so* \
+ ${libdir}/connman/plugins-vpn/l2tp.so"
+RDEPENDS_${PN}-plugin-vpn-l2tp += "${PN}-vpn"
+RRECOMMENDS_${PN} += "${@base_contains('PACKAGECONFIG','l2tp','${PN}-plugin-vpn-l2tp', '', d)}"
+
+SUMMARY_${PN}-plugin-vpn-pptp = "A PPTP plugin for ConnMan VPN"
+DESCRIPTION_${PN}-plugin-vpn-pptp = "The ConnMan PPTP plugin uses pptp-linux client \
+to create a VPN connection to PPTP server."
+FILES_${PN}-plugin-vpn-pptp += "${libdir}/connman/scripts/libppp-plugin.so* \
+ ${libdir}/connman/plugins-vpn/pptp.so"
+RDEPENDS_${PN}-plugin-vpn-pptp += "${PN}-vpn"
+RRECOMMENDS_${PN} += "${@base_contains('PACKAGECONFIG','pptp','${PN}-plugin-vpn-pptp', '', d)}"
diff --git a/meta-edison-distro/recipes-connectivity/connman/connman/0001-plugin.h-Change-visibility-to-default-for-debug-symb.patch b/meta-edison-distro/recipes-connectivity/connman/connman/0001-plugin.h-Change-visibility-to-default-for-debug-symb.patch
new file mode 100644
index 0000000..e6f03e6
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/connman/connman/0001-plugin.h-Change-visibility-to-default-for-debug-symb.patch
@@ -0,0 +1,35 @@
+From 4ddaf78dad5a9ee4a0658235f71b75132192123e Mon Sep 17 00:00:00 2001
+From: Khem Raj <raj.khem@gmail.com>
+Date: Sat, 7 Apr 2012 18:52:12 -0700
+Subject: [PATCH] plugin.h: Change visibility to default for debug symbols
+
+gold refuses to link in undefined weak symbols which
+have hidden visibility
+
+Signed-off-by: Khem Raj <raj.khem@gmail.com>
+
+
+Upstream-Status: Pending
+---
+ include/plugin.h | 4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/include/plugin.h b/include/plugin.h
+index 692a4e5..a9361c3 100644
+--- a/include/plugin.h
++++ b/include/plugin.h
+@@ -89,9 +89,9 @@ struct connman_plugin_desc {
+ #else
+ #define CONNMAN_PLUGIN_DEFINE(name, description, version, priority, init, exit) \
+ extern struct connman_debug_desc __start___debug[] \
+- __attribute__ ((weak, visibility("hidden"))); \
++ __attribute__ ((weak, visibility("default"))); \
+ extern struct connman_debug_desc __stop___debug[] \
+- __attribute__ ((weak, visibility("hidden"))); \
++ __attribute__ ((weak, visibility("default"))); \
+ extern struct connman_plugin_desc connman_plugin_desc \
+ __attribute__ ((visibility("default"))); \
+ struct connman_plugin_desc connman_plugin_desc = { \
+--
+1.7.5.4
+
diff --git a/meta-edison-distro/recipes-connectivity/connman/connman/add_xuser_dbus_permission.patch b/meta-edison-distro/recipes-connectivity/connman/connman/add_xuser_dbus_permission.patch
new file mode 100644
index 0000000..707b3ca
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/connman/connman/add_xuser_dbus_permission.patch
@@ -0,0 +1,21 @@
+Because Poky doesn't support at_console we need to special-case the session
+user.
+
+Upstream-Status: Inappropriate [configuration]
+
+Signed-off-by: Ross Burton <ross.burton@intel.com>
+
+diff --git a/src/connman-dbus.conf b/src/connman-dbus.conf
+index 98a773e..466809c 100644
+--- a/src/connman-dbus.conf
++++ b/src/connman-dbus.conf
+@@ -8,6 +8,9 @@
+ <allow send_interface="net.connman.Counter"/>
+ <allow send_interface="net.connman.Notification"/>
+ </policy>
++ <policy user="xuser">
++ <allow send_destination="net.connman"/>
++ </policy>
+ <policy at_console="true">
+ <allow send_destination="net.connman"/>
+ </policy>
diff --git a/meta-edison-distro/recipes-connectivity/connman/connman/connman b/meta-edison-distro/recipes-connectivity/connman/connman/connman
new file mode 100644
index 0000000..bf7a94a
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/connman/connman/connman
@@ -0,0 +1,83 @@
+#!/bin/sh
+
+DAEMON=/usr/sbin/connmand
+PIDFILE=/var/run/connmand.pid
+DESC="Connection Manager"
+
+if [ -f /etc/default/connman ] ; then
+ . /etc/default/connman
+fi
+
+set -e
+
+nfsroot=0
+
+exec 9<&0 < /proc/mounts
+while read dev mtpt fstype rest; do
+ if test $mtpt = "/" ; then
+ case $fstype in
+ nfs | nfs4)
+ nfsroot=1
+ break
+ ;;
+ *)
+ ;;
+ esac
+ fi
+done
+
+do_start() {
+ EXTRA_PARAM=""
+ if test $nfsroot -eq 1 ; then
+ NET_DEVS=`cat /proc/net/dev | sed -ne 's/^\([a-zA-Z0-9 ]*\):.*$/\1/p'`
+ NET_ADDR=`cat /proc/cmdline | sed -ne 's/^.*ip=\([^ :]*\).*$/\1/p'`
+
+ if [ ! -z "$NET_ADDR" ]; then
+ if [ "$NET_ADDR" = dhcp ]; then
+ ethn=`ifconfig | grep "^eth" | sed -e "s/\(eth[0-9]\)\(.*\)/\1/"`
+ if [ ! -z "$ethn" ]; then
+ EXTRA_PARAM="-I $ethn"
+ fi
+ else
+ for i in $NET_DEVS; do
+ ADDR=`ifconfig $i | sed 's/addr://g' | sed -ne 's/^.*inet \([0-9.]*\) .*$/\1/p'`
+ if [ "$NET_ADDR" = "$ADDR" ]; then
+ EXTRA_PARAM="-I $i"
+ break
+ fi
+ done
+ fi
+ fi
+ fi
+ if [ -f @LIBDIR@/connman/wired-setup ] ; then
+ . @LIBDIR@/connman/wired-setup
+ fi
+ $DAEMON $EXTRA_PARAM
+}
+
+do_stop() {
+ start-stop-daemon --stop --name connmand --quiet
+}
+
+case "$1" in
+ start)
+ echo "Starting $DESC"
+ do_start
+ ;;
+ stop)
+ echo "Stopping $DESC"
+ do_stop
+ ;;
+ restart|force-reload)
+ echo "Restarting $DESC"
+ do_stop
+ sleep 1
+ do_start
+ ;;
+ *)
+ echo "Usage: $0 {start|stop|restart|force-reload}" >&2
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/meta-edison-distro/recipes-connectivity/connman/connman/disable_p2p.patch b/meta-edison-distro/recipes-connectivity/connman/connman/disable_p2p.patch
new file mode 100644
index 0000000..6cce2e3
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/connman/connman/disable_p2p.patch
@@ -0,0 +1,15 @@
+--- a/gsupplicant/supplicant.c
++++ b/gsupplicant/supplicant.c
+@@ -1963,8 +1963,11 @@
+ if (g_strcmp0(key, "Capabilities") == 0) {
+ supplicant_dbus_property_foreach(iter, interface_capability,
+ interface);
++#if 0
++ /* Disable temporarely p2p */
+ if (interface->mode_capa & G_SUPPLICANT_CAPABILITY_MODE_P2P)
+ interface->p2p_support = true;
++#endif
+ } else if (g_strcmp0(key, "State") == 0) {
+ const char *str = NULL;
+
+
diff --git a/meta-edison-distro/recipes-connectivity/connman/connman_1.27.bb b/meta-edison-distro/recipes-connectivity/connman/connman_1.27.bb
new file mode 100644
index 0000000..70993ac
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/connman/connman_1.27.bb
@@ -0,0 +1,11 @@
+require connman.inc
+
+SRC_URI = "${KERNELORG_MIRROR}/linux/network/${BPN}/${BP}.tar.xz \
+ file://0001-plugin.h-Change-visibility-to-default-for-debug-symb.patch \
+ file://add_xuser_dbus_permission.patch \
+ file://disable_p2p.patch \
+ file://connman \
+ "
+SRC_URI[md5sum] = "4f4b3be54da000c65b153c1b9afcadf2"
+SRC_URI[sha256sum] = "13997824c076af150c68d6d79e48277216e8192278a5c6615cfd4905d65600f5"
+RRECOMMENDS_${PN} = "connman-conf"
diff --git a/meta-edison-distro/recipes-connectivity/connman/connman_1.27.bbappend b/meta-edison-distro/recipes-connectivity/connman/connman_1.27.bbappend
new file mode 100644
index 0000000..80e7b38
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/connman/connman_1.27.bbappend
@@ -0,0 +1,35 @@
+
+
+LIC_FILES_CHKSUM = "file://COPYING;md5=12f884d2ae1ff87c09e5b7ccc2c4ca7e \
+ file://src/main.c;beginline=1;endline=20;md5=486a279a6ab0c8d152bcda3a5b5edc36"
+
+PACKAGECONFIG ??= "wispr \
+ ${@base_contains('DISTRO_FEATURES', 'wifi','wifi', '', d)} \
+ ${@base_contains('DISTRO_FEATURES', 'bluetooth','bluetooth', '', d)} \
+"
+
+PACKAGECONFIG[bluetooth] = "--enable-bluetooth, --disable-bluetooth, bluez5"
+PACKAGECONFIG[3g] = ""
+
+SYSTEMD_AUTO_ENABLE = "disable"
+
+do_configure_append () {
+ # Do not usb0 as it is used for SSH connection
+ sed -i "s/ExecStart=.*/& --nodevice=usb0/" ${S}/src/connman.service
+}
+
+
+# These used to be plugins, but now they are core
+RPROVIDES_${PN} = "\
+ connman-plugin-loopback \
+ connman-plugin-ethernet \
+ ${@base_contains('PACKAGECONFIG', 'bluetooth','connman-plugin-bluetooth', '', d)} \
+ ${@base_contains('PACKAGECONFIG', 'wifi','connman-plugin-wifi', '', d)} \
+ "
+
+RDEPENDS_${PN} = "\
+ dbus \
+ ${@base_contains('PACKAGECONFIG', 'bluetooth', 'bluez5', '', d)} \
+ ${@base_contains('PACKAGECONFIG', 'wifi','wpa-supplicant', '', d)} \
+ "
+
diff --git a/meta-edison-distro/recipes-connectivity/hostapd/files/defconfig b/meta-edison-distro/recipes-connectivity/hostapd/files/defconfig
new file mode 100644
index 0000000..2789640
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/hostapd/files/defconfig
@@ -0,0 +1,145 @@
+# Example hostapd build time configuration
+#
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cass, these lines should use += in order not
+# to override previous values of the variables.
+
+# Driver interface for Host AP driver
+CONFIG_DRIVER_HOSTAP=y
+
+# Driver interface for wired authenticator
+CONFIG_DRIVER_WIRED=y
+
+# Driver interface for madwifi driver
+#CONFIG_DRIVER_MADWIFI=y
+#CFLAGS += -I../../madwifi # change to the madwifi source directory
+
+# Driver interface for Prism54 driver
+CONFIG_DRIVER_PRISM54=y
+
+# Driver interface for drivers using the nl80211 kernel interface
+CONFIG_DRIVER_NL80211=y
+CONFIG_LIBNL32=y
+# driver_nl80211.c requires a rather new libnl (version 1.1) which may not be
+# shipped with your distribution yet. If that is the case, you need to build
+# newer libnl version and point the hostapd build to use it.
+#LIBNL=/usr/src/libnl
+#CFLAGS += -I$(LIBNL)/include
+#LIBS += -L$(LIBNL)/lib
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+
+# Driver interface for no driver (e.g., RADIUS server only)
+#CONFIG_DRIVER_NONE=y
+
+# IEEE 802.11F/IAPP
+CONFIG_IAPP=y
+
+# WPA2/IEEE 802.11i RSN pre-authentication
+CONFIG_RSN_PREAUTH=y
+
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection)
+# This version is an experimental implementation based on IEEE 802.11w/D1.0
+# draft and is subject to change since the standard has not yet been finalized.
+# Driver support is also needed for IEEE 802.11w.
+#CONFIG_IEEE80211W=y
+
+# Integrated EAP server
+CONFIG_EAP=y
+
+# EAP-MD5 for the integrated EAP server
+CONFIG_EAP_MD5=y
+
+# EAP-TLS for the integrated EAP server
+CONFIG_EAP_TLS=y
+
+# EAP-MSCHAPv2 for the integrated EAP server
+CONFIG_EAP_MSCHAPV2=y
+
+# EAP-PEAP for the integrated EAP server
+CONFIG_EAP_PEAP=y
+
+# EAP-GTC for the integrated EAP server
+CONFIG_EAP_GTC=y
+
+# EAP-TTLS for the integrated EAP server
+CONFIG_EAP_TTLS=y
+
+# EAP-SIM for the integrated EAP server
+#CONFIG_EAP_SIM=y
+
+# EAP-AKA for the integrated EAP server
+#CONFIG_EAP_AKA=y
+
+# EAP-AKA' for the integrated EAP server
+# This requires CONFIG_EAP_AKA to be enabled, too.
+#CONFIG_EAP_AKA_PRIME=y
+
+# EAP-PAX for the integrated EAP server
+#CONFIG_EAP_PAX=y
+
+# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
+#CONFIG_EAP_PSK=y
+
+# EAP-SAKE for the integrated EAP server
+#CONFIG_EAP_SAKE=y
+
+# EAP-GPSK for the integrated EAP server
+#CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+#CONFIG_EAP_GPSK_SHA256=y
+
+# EAP-FAST for the integrated EAP server
+# Note: Default OpenSSL package does not include support for all the
+# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
+# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch)
+# to add the needed functions.
+#CONFIG_EAP_FAST=y
+
+# Wi-Fi Protected Setup (WPS)
+CONFIG_WPS=y
+# Enable UPnP support for external WPS Registrars
+#CONFIG_WPS_UPNP=y
+
+# EAP-IKEv2
+#CONFIG_EAP_IKEV2=y
+
+# Trusted Network Connect (EAP-TNC)
+#CONFIG_EAP_TNC=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+CONFIG_PKCS12=y
+
+# RADIUS authentication server. This provides access to the integrated EAP
+# server from external hosts using RADIUS.
+CONFIG_RADIUS_SERVER=y
+
+# Build IPv6 support for RADIUS operations
+CONFIG_IPV6=y
+
+# IEEE Std 802.11r-2008 (Fast BSS Transition)
+#CONFIG_IEEE80211R=y
+
+# Use the hostapd's IEEE 802.11 authentication (ACL), but without
+# the IEEE 802.11 Management capability (e.g., madwifi or FreeBSD/net80211)
+CONFIG_DRIVER_RADIUS_ACL=y
+
+# IEEE 802.11n (High Throughput) support
+CONFIG_IEEE80211N=y
+
+# Remove debugging code that is printing out debug messages to stdout.
+# This can be used to reduce the size of the hostapd considerably if debugging
+# code is not needed.
+#CONFIG_NO_STDOUT_DEBUG=y
diff --git a/meta-edison-distro/recipes-connectivity/hostapd/files/hostapd.conf-sane b/meta-edison-distro/recipes-connectivity/hostapd/files/hostapd.conf-sane
new file mode 100644
index 0000000..3e7d794
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/hostapd/files/hostapd.conf-sane
@@ -0,0 +1,1662 @@
+##### hostapd configuration file ##############################################
+# Empty lines and lines starting with # are ignored
+
+# AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for
+# management frames); ath0 for madwifi
+interface=wlan0
+
+# In case of madwifi, atheros, and nl80211 driver interfaces, an additional
+# configuration parameter, bridge, may be used to notify hostapd if the
+# interface is included in a bridge. This parameter is not used with Host AP
+# driver. If the bridge parameter is not set, the drivers will automatically
+# figure out the bridge interface (assuming sysfs is enabled and mounted to
+# /sys) and this parameter may not be needed.
+#
+# For nl80211, this parameter can be used to request the AP interface to be
+# added to the bridge automatically (brctl may refuse to do this before hostapd
+# has been started to change the interface mode). If needed, the bridge
+# interface is also created.
+#bridge=br0
+
+# Driver interface type (hostap/wired/madwifi/test/none/nl80211/bsd);
+# default: hostap). nl80211 is used with all Linux mac80211 drivers.
+# Use driver=none if building hostapd as a standalone RADIUS server that does
+# not control any wireless/wired driver.
+driver=nl80211
+
+# hostapd event logger configuration
+#
+# Two output method: syslog and stdout (only usable if not forking to
+# background).
+#
+# Module bitfield (ORed bitfield of modules that will be logged; -1 = all
+# modules):
+# bit 0 (1) = IEEE 802.11
+# bit 1 (2) = IEEE 802.1X
+# bit 2 (4) = RADIUS
+# bit 3 (8) = WPA
+# bit 4 (16) = driver interface
+# bit 5 (32) = IAPP
+# bit 6 (64) = MLME
+#
+# Levels (minimum value for logged events):
+# 0 = verbose debugging
+# 1 = debugging
+# 2 = informational messages
+# 3 = notification
+# 4 = warning
+#
+logger_syslog=-1
+logger_syslog_level=2
+logger_stdout=-1
+logger_stdout_level=2
+
+# Interface for separate control program. If this is specified, hostapd
+# will create this directory and a UNIX domain socket for listening to requests
+# from external programs (CLI/GUI, etc.) for status information and
+# configuration. The socket file will be named based on the interface name, so
+# multiple hostapd processes/interfaces can be run at the same time if more
+# than one interface is used.
+# /var/run/hostapd is the recommended directory for sockets and by default,
+# hostapd_cli will use it when trying to connect with hostapd.
+ctrl_interface=/var/run/hostapd
+
+# Access control for the control interface can be configured by setting the
+# directory to allow only members of a group to use sockets. This way, it is
+# possible to run hostapd as root (since it needs to change network
+# configuration and open raw sockets) and still allow GUI/CLI components to be
+# run as non-root users. However, since the control interface can be used to
+# change the network configuration, this access needs to be protected in many
+# cases. By default, hostapd is configured to use gid 0 (root). If you
+# want to allow non-root users to use the contron interface, add a new group
+# and change this value to match with that group. Add users that should have
+# control interface access to this group.
+#
+# This variable can be a group name or gid.
+#ctrl_interface_group=wheel
+ctrl_interface_group=0
+
+
+##### IEEE 802.11 related configuration #######################################
+
+# SSID to be used in IEEE 802.11 management frames
+# The SSID is dynamically modified by the script /etc/hostapd/hostpad_ssid.sh
+# to get a unique SSID among mutiple Edison boards (see the content of this script)
+# See the header of this script if you want to disable this dynamic setting
+# and to set a manual and static SSID
+ssid=edison_ap
+
+# UTF-8 SSID: Whether the SSID is to be interpreted using UTF-8 encoding
+#utf8_ssid=1
+
+# Country code (ISO/IEC 3166-1). Used to set regulatory domain.
+# Set as needed to indicate country in which device is operating.
+# This can limit available channels and transmit power.
+#country_code=US
+
+# Enable IEEE 802.11d. This advertises the country_code and the set of allowed
+# channels and transmit power levels based on the regulatory limits. The
+# country_code setting must be configured with the correct country for
+# IEEE 802.11d functions.
+# (default: 0 = disabled)
+#ieee80211d=1
+
+# Enable IEEE 802.11h. This enables radar detection and DFS support if
+# available. DFS support is required on outdoor 5 GHz channels in most countries
+# of the world. This can be used only with ieee80211d=1.
+# (default: 0 = disabled)
+#ieee80211h=1
+
+# Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g,
+# ad = IEEE 802.11ad (60 GHz); a/g options are used with IEEE 802.11n, too, to
+# specify band)
+# Default: IEEE 802.11b
+hw_mode=g
+
+# Channel number (IEEE 802.11)
+# (default: 0, i.e., not set)
+# Please note that some drivers do not use this value from hostapd and the
+# channel will need to be configured separately with iwconfig.
+#
+# If CONFIG_ACS build option is enabled, the channel can be selected
+# automatically at run time by setting channel=acs_survey or channel=0, both of
+# which will enable the ACS survey based algorithm.
+channel=1
+
+# ACS tuning - Automatic Channel Selection
+# See: http://wireless.kernel.org/en/users/Documentation/acs
+#
+# You can customize the ACS survey algorithm with following variables:
+#
+# acs_num_scans requirement is 1..100 - number of scans to be performed that
+# are used to trigger survey data gathering of an underlying device driver.
+# Scans are passive and typically take a little over 100ms (depending on the
+# driver) on each available channel for given hw_mode. Increasing this value
+# means sacrificing startup time and gathering more data wrt channel
+# interference that may help choosing a better channel. This can also help fine
+# tune the ACS scan time in case a driver has different scan dwell times.
+#
+# Defaults:
+#acs_num_scans=5
+
+# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
+beacon_int=100
+
+# DTIM (delivery traffic information message) period (range 1..255):
+# number of beacons between DTIMs (1 = every beacon includes DTIM element)
+# (default: 2)
+dtim_period=2
+
+# Maximum number of stations allowed in station table. New stations will be
+# rejected after the station table is full. IEEE 802.11 has a limit of 2007
+# different association IDs, so this number should not be larger than that.
+# (default: 2007)
+max_num_sta=255
+
+# RTS/CTS threshold; 2347 = disabled (default); range 0..2347
+# If this field is not included in hostapd.conf, hostapd will not control
+# RTS threshold and 'iwconfig wlan# rts <val>' can be used to set it.
+rts_threshold=2347
+
+# Fragmentation threshold; 2346 = disabled (default); range 256..2346
+# If this field is not included in hostapd.conf, hostapd will not control
+# fragmentation threshold and 'iwconfig wlan# frag <val>' can be used to set
+# it.
+fragm_threshold=2346
+
+# Rate configuration
+# Default is to enable all rates supported by the hardware. This configuration
+# item allows this list be filtered so that only the listed rates will be left
+# in the list. If the list is empty, all rates are used. This list can have
+# entries that are not in the list of rates the hardware supports (such entries
+# are ignored). The entries in this list are in 100 kbps, i.e., 11 Mbps = 110.
+# If this item is present, at least one rate have to be matching with the rates
+# hardware supports.
+# default: use the most common supported rate setting for the selected
+# hw_mode (i.e., this line can be removed from configuration file in most
+# cases)
+#supported_rates=10 20 55 110 60 90 120 180 240 360 480 540
+
+# Basic rate set configuration
+# List of rates (in 100 kbps) that are included in the basic rate set.
+# If this item is not included, usually reasonable default set is used.
+#basic_rates=10 20
+#basic_rates=10 20 55 110
+#basic_rates=60 120 240
+
+# Short Preamble
+# This parameter can be used to enable optional use of short preamble for
+# frames sent at 2 Mbps, 5.5 Mbps, and 11 Mbps to improve network performance.
+# This applies only to IEEE 802.11b-compatible networks and this should only be
+# enabled if the local hardware supports use of short preamble. If any of the
+# associated STAs do not support short preamble, use of short preamble will be
+# disabled (and enabled when such STAs disassociate) dynamically.
+# 0 = do not allow use of short preamble (default)
+# 1 = allow use of short preamble
+#preamble=1
+
+# Station MAC address -based authentication
+# Please note that this kind of access control requires a driver that uses
+# hostapd to take care of management frame processing and as such, this can be
+# used with driver=hostap or driver=nl80211, but not with driver=madwifi.
+# 0 = accept unless in deny list
+# 1 = deny unless in accept list
+# 2 = use external RADIUS server (accept/deny lists are searched first)
+macaddr_acl=0
+
+# Accept/deny lists are read from separate files (containing list of
+# MAC addresses, one per line). Use absolute path name to make sure that the
+# files can be read on SIGHUP configuration reloads.
+#accept_mac_file=/etc/hostapd.accept
+#deny_mac_file=/etc/hostapd.deny
+
+# IEEE 802.11 specifies two authentication algorithms. hostapd can be
+# configured to allow both of these or only one. Open system authentication
+# should be used with IEEE 802.1X.
+# Bit fields of allowed authentication algorithms:
+# bit 0 = Open System Authentication
+# bit 1 = Shared Key Authentication (requires WEP)
+auth_algs=1
+
+# Send empty SSID in beacons and ignore probe request frames that do not
+# specify full SSID, i.e., require stations to know SSID.
+# default: disabled (0)
+# 1 = send empty (length=0) SSID in beacon and ignore probe request for
+# broadcast SSID
+# 2 = clear SSID (ASCII 0), but keep the original length (this may be required
+# with some clients that do not support empty SSID) and ignore probe
+# requests for broadcast SSID
+ignore_broadcast_ssid=0
+
+# Additional vendor specfic elements for Beacon and Probe Response frames
+# This parameter can be used to add additional vendor specific element(s) into
+# the end of the Beacon and Probe Response frames. The format for these
+# element(s) is a hexdump of the raw information elements (id+len+payload for
+# one or more elements)
+#vendor_elements=dd0411223301
+
+# TX queue parameters (EDCF / bursting)
+# tx_queue_<queue name>_<param>
+# queues: data0, data1, data2, data3, after_beacon, beacon
+# (data0 is the highest priority queue)
+# parameters:
+# aifs: AIFS (default 2)
+# cwmin: cwMin (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023)
+# cwmax: cwMax (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023); cwMax >= cwMin
+# burst: maximum length (in milliseconds with precision of up to 0.1 ms) for
+# bursting
+#
+# Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e):
+# These parameters are used by the access point when transmitting frames
+# to the clients.
+#
+# Low priority / AC_BK = background
+#tx_queue_data3_aifs=7
+#tx_queue_data3_cwmin=15
+#tx_queue_data3_cwmax=1023
+#tx_queue_data3_burst=0
+# Note: for IEEE 802.11b mode: cWmin=31 cWmax=1023 burst=0
+#
+# Normal priority / AC_BE = best effort
+#tx_queue_data2_aifs=3
+#tx_queue_data2_cwmin=15
+#tx_queue_data2_cwmax=63
+#tx_queue_data2_burst=0
+# Note: for IEEE 802.11b mode: cWmin=31 cWmax=127 burst=0
+#
+# High priority / AC_VI = video
+#tx_queue_data1_aifs=1
+#tx_queue_data1_cwmin=7
+#tx_queue_data1_cwmax=15
+#tx_queue_data1_burst=3.0
+# Note: for IEEE 802.11b mode: cWmin=15 cWmax=31 burst=6.0
+#
+# Highest priority / AC_VO = voice
+#tx_queue_data0_aifs=1
+#tx_queue_data0_cwmin=3
+#tx_queue_data0_cwmax=7
+#tx_queue_data0_burst=1.5
+# Note: for IEEE 802.11b mode: cWmin=7 cWmax=15 burst=3.3
+
+# 802.1D Tag (= UP) to AC mappings
+# WMM specifies following mapping of data frames to different ACs. This mapping
+# can be configured using Linux QoS/tc and sch_pktpri.o module.
+# 802.1D Tag 802.1D Designation Access Category WMM Designation
+# 1 BK AC_BK Background
+# 2 - AC_BK Background
+# 0 BE AC_BE Best Effort
+# 3 EE AC_BE Best Effort
+# 4 CL AC_VI Video
+# 5 VI AC_VI Video
+# 6 VO AC_VO Voice
+# 7 NC AC_VO Voice
+# Data frames with no priority information: AC_BE
+# Management frames: AC_VO
+# PS-Poll frames: AC_BE
+
+# Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e):
+# for 802.11a or 802.11g networks
+# These parameters are sent to WMM clients when they associate.
+# The parameters will be used by WMM clients for frames transmitted to the
+# access point.
+#
+# note - txop_limit is in units of 32microseconds
+# note - acm is admission control mandatory flag. 0 = admission control not
+# required, 1 = mandatory
+# note - here cwMin and cmMax are in exponent form. the actual cw value used
+# will be (2^n)-1 where n is the value given here
+#
+wmm_enabled=1
+#
+# WMM-PS Unscheduled Automatic Power Save Delivery [U-APSD]
+# Enable this flag if U-APSD supported outside hostapd (eg., Firmware/driver)
+#uapsd_advertisement_enabled=1
+#
+# Low priority / AC_BK = background
+wmm_ac_bk_cwmin=4
+wmm_ac_bk_cwmax=10
+wmm_ac_bk_aifs=7
+wmm_ac_bk_txop_limit=0
+wmm_ac_bk_acm=0
+# Note: for IEEE 802.11b mode: cWmin=5 cWmax=10
+#
+# Normal priority / AC_BE = best effort
+wmm_ac_be_aifs=3
+wmm_ac_be_cwmin=4
+wmm_ac_be_cwmax=10
+wmm_ac_be_txop_limit=0
+wmm_ac_be_acm=0
+# Note: for IEEE 802.11b mode: cWmin=5 cWmax=7
+#
+# High priority / AC_VI = video
+wmm_ac_vi_aifs=2
+wmm_ac_vi_cwmin=3
+wmm_ac_vi_cwmax=4
+wmm_ac_vi_txop_limit=94
+wmm_ac_vi_acm=0
+# Note: for IEEE 802.11b mode: cWmin=4 cWmax=5 txop_limit=188
+#
+# Highest priority / AC_VO = voice
+wmm_ac_vo_aifs=2
+wmm_ac_vo_cwmin=2
+wmm_ac_vo_cwmax=3
+wmm_ac_vo_txop_limit=47
+wmm_ac_vo_acm=0
+# Note: for IEEE 802.11b mode: cWmin=3 cWmax=4 burst=102
+
+# Static WEP key configuration
+#
+# The key number to use when transmitting.
+# It must be between 0 and 3, and the corresponding key must be set.
+# default: not set
+#wep_default_key=0
+# The WEP keys to use.
+# A key may be a quoted string or unquoted hexadecimal digits.
+# The key length should be 5, 13, or 16 characters, or 10, 26, or 32
+# digits, depending on whether 40-bit (64-bit), 104-bit (128-bit), or
+# 128-bit (152-bit) WEP is used.
+# Only the default key must be supplied; the others are optional.
+# default: not set
+#wep_key0=123456789a
+#wep_key1="vwxyz"
+#wep_key2=0102030405060708090a0b0c0d
+#wep_key3=".2.4.6.8.0.23"
+
+# Station inactivity limit
+#
+# If a station does not send anything in ap_max_inactivity seconds, an
+# empty data frame is sent to it in order to verify whether it is
+# still in range. If this frame is not ACKed, the station will be
+# disassociated and then deauthenticated. This feature is used to
+# clear station table of old entries when the STAs move out of the
+# range.
+#
+# The station can associate again with the AP if it is still in range;
+# this inactivity poll is just used as a nicer way of verifying
+# inactivity; i.e., client will not report broken connection because
+# disassociation frame is not sent immediately without first polling
+# the STA with a data frame.
+# default: 300 (i.e., 5 minutes)
+#ap_max_inactivity=300
+#
+# The inactivity polling can be disabled to disconnect stations based on
+# inactivity timeout so that idle stations are more likely to be disconnected
+# even if they are still in range of the AP. This can be done by setting
+# skip_inactivity_poll to 1 (default 0).
+#skip_inactivity_poll=0
+
+# Disassociate stations based on excessive transmission failures or other
+# indications of connection loss. This depends on the driver capabilities and
+# may not be available with all drivers.
+#disassoc_low_ack=1
+
+# Maximum allowed Listen Interval (how many Beacon periods STAs are allowed to
+# remain asleep). Default: 65535 (no limit apart from field size)
+#max_listen_interval=100
+
+# WDS (4-address frame) mode with per-station virtual interfaces
+# (only supported with driver=nl80211)
+# This mode allows associated stations to use 4-address frames to allow layer 2
+# bridging to be used.
+#wds_sta=1
+
+# If bridge parameter is set, the WDS STA interface will be added to the same
+# bridge by default. This can be overridden with the wds_bridge parameter to
+# use a separate bridge.
+#wds_bridge=wds-br0
+
+# Start the AP with beaconing disabled by default.
+#start_disabled=0
+
+# Client isolation can be used to prevent low-level bridging of frames between
+# associated stations in the BSS. By default, this bridging is allowed.
+#ap_isolate=1
+
+# Fixed BSS Load value for testing purposes
+# This field can be used to configure hostapd to add a fixed BSS Load element
+# into Beacon and Probe Response frames for testing purposes. The format is
+# <station count>:<channel utilization>:<available admission capacity>
+#bss_load_test=12:80:20000
+
+##### IEEE 802.11n related configuration ######################################
+
+# ieee80211n: Whether IEEE 802.11n (HT) is enabled
+# 0 = disabled (default)
+# 1 = enabled
+# Note: You will also need to enable WMM for full HT functionality.
+ieee80211n=1
+
+# ht_capab: HT capabilities (list of flags)
+# LDPC coding capability: [LDPC] = supported
+# Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary
+# channel below the primary channel; [HT40+] = both 20 MHz and 40 MHz
+# with secondary channel below the primary channel
+# (20 MHz only if neither is set)
+# Note: There are limits on which channels can be used with HT40- and
+# HT40+. Following table shows the channels that may be available for
+# HT40- and HT40+ use per IEEE 802.11n Annex J:
+# freq HT40- HT40+
+# 2.4 GHz 5-13 1-7 (1-9 in Europe/Japan)
+# 5 GHz 40,48,56,64 36,44,52,60
+# (depending on the location, not all of these channels may be available
+# for use)
+# Please note that 40 MHz channels may switch their primary and secondary
+# channels if needed or creation of 40 MHz channel maybe rejected based
+# on overlapping BSSes. These changes are done automatically when hostapd
+# is setting up the 40 MHz channel.
+# Spatial Multiplexing (SM) Power Save: [SMPS-STATIC] or [SMPS-DYNAMIC]
+# (SMPS disabled if neither is set)
+# HT-greenfield: [GF] (disabled if not set)
+# Short GI for 20 MHz: [SHORT-GI-20] (disabled if not set)
+# Short GI for 40 MHz: [SHORT-GI-40] (disabled if not set)
+# Tx STBC: [TX-STBC] (disabled if not set)
+# Rx STBC: [RX-STBC1] (one spatial stream), [RX-STBC12] (one or two spatial
+# streams), or [RX-STBC123] (one, two, or three spatial streams); Rx STBC
+# disabled if none of these set
+# HT-delayed Block Ack: [DELAYED-BA] (disabled if not set)
+# Maximum A-MSDU length: [MAX-AMSDU-7935] for 7935 octets (3839 octets if not
+# set)
+# DSSS/CCK Mode in 40 MHz: [DSSS_CCK-40] = allowed (not allowed if not set)
+# PSMP support: [PSMP] (disabled if not set)
+# L-SIG TXOP protection support: [LSIG-TXOP-PROT] (disabled if not set)
+#ht_capab=[HT40-][SHORT-GI-20][SHORT-GI-40]
+
+# Require stations to support HT PHY (reject association if they do not)
+#require_ht=1
+
+# If set non-zero, require stations to perform scans of overlapping
+# channels to test for stations which would be affected by 40 MHz traffic.
+# This parameter sets the interval in seconds between these scans. This
+# is useful only for testing that stations properly set the OBSS interval,
+# since the other parameters in the OBSS scan parameters IE are set to 0.
+#obss_interval=0
+
+##### IEEE 802.11ac related configuration #####################################
+
+# ieee80211ac: Whether IEEE 802.11ac (VHT) is enabled
+# 0 = disabled (default)
+# 1 = enabled
+# Note: You will also need to enable WMM for full VHT functionality.
+#ieee80211ac=1
+
+# vht_capab: VHT capabilities (list of flags)
+#
+# vht_max_mpdu_len: [MAX-MPDU-7991] [MAX-MPDU-11454]
+# Indicates maximum MPDU length
+# 0 = 3895 octets (default)
+# 1 = 7991 octets
+# 2 = 11454 octets
+# 3 = reserved
+#
+# supported_chan_width: [VHT160] [VHT160-80PLUS80]
+# Indicates supported Channel widths
+# 0 = 160 MHz & 80+80 channel widths are not supported (default)
+# 1 = 160 MHz channel width is supported
+# 2 = 160 MHz & 80+80 channel widths are supported
+# 3 = reserved
+#
+# Rx LDPC coding capability: [RXLDPC]
+# Indicates support for receiving LDPC coded pkts
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Short GI for 80 MHz: [SHORT-GI-80]
+# Indicates short GI support for reception of packets transmitted with TXVECTOR
+# params format equal to VHT and CBW = 80Mhz
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Short GI for 160 MHz: [SHORT-GI-160]
+# Indicates short GI support for reception of packets transmitted with TXVECTOR
+# params format equal to VHT and CBW = 160Mhz
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Tx STBC: [TX-STBC-2BY1]
+# Indicates support for the transmission of at least 2x1 STBC
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Rx STBC: [RX-STBC-1] [RX-STBC-12] [RX-STBC-123] [RX-STBC-1234]
+# Indicates support for the reception of PPDUs using STBC
+# 0 = Not supported (default)
+# 1 = support of one spatial stream
+# 2 = support of one and two spatial streams
+# 3 = support of one, two and three spatial streams
+# 4 = support of one, two, three and four spatial streams
+# 5,6,7 = reserved
+#
+# SU Beamformer Capable: [SU-BEAMFORMER]
+# Indicates support for operation as a single user beamformer
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# SU Beamformee Capable: [SU-BEAMFORMEE]
+# Indicates support for operation as a single user beamformee
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Compressed Steering Number of Beamformer Antennas Supported: [BF-ANTENNA-2]
+# Beamformee's capability indicating the maximum number of beamformer
+# antennas the beamformee can support when sending compressed beamforming
+# feedback
+# If SU beamformer capable, set to maximum value minus 1
+# else reserved (default)
+#
+# Number of Sounding Dimensions: [SOUNDING-DIMENSION-2]
+# Beamformer's capability indicating the maximum value of the NUM_STS parameter
+# in the TXVECTOR of a VHT NDP
+# If SU beamformer capable, set to maximum value minus 1
+# else reserved (default)
+#
+# MU Beamformer Capable: [MU-BEAMFORMER]
+# Indicates support for operation as an MU beamformer
+# 0 = Not supported or sent by Non-AP STA (default)
+# 1 = Supported
+#
+# MU Beamformee Capable: [MU-BEAMFORMEE]
+# Indicates support for operation as an MU beamformee
+# 0 = Not supported or sent by AP (default)
+# 1 = Supported
+#
+# VHT TXOP PS: [VHT-TXOP-PS]
+# Indicates whether or not the AP supports VHT TXOP Power Save Mode
+# or whether or not the STA is in VHT TXOP Power Save mode
+# 0 = VHT AP doesnt support VHT TXOP PS mode (OR) VHT Sta not in VHT TXOP PS
+# mode
+# 1 = VHT AP supports VHT TXOP PS mode (OR) VHT Sta is in VHT TXOP power save
+# mode
+#
+# +HTC-VHT Capable: [HTC-VHT]
+# Indicates whether or not the STA supports receiving a VHT variant HT Control
+# field.
+# 0 = Not supported (default)
+# 1 = supported
+#
+# Maximum A-MPDU Length Exponent: [MAX-A-MPDU-LEN-EXP0]..[MAX-A-MPDU-LEN-EXP7]
+# Indicates the maximum length of A-MPDU pre-EOF padding that the STA can recv
+# This field is an integer in the range of 0 to 7.
+# The length defined by this field is equal to
+# 2 pow(13 + Maximum A-MPDU Length Exponent) -1 octets
+#
+# VHT Link Adaptation Capable: [VHT-LINK-ADAPT2] [VHT-LINK-ADAPT3]
+# Indicates whether or not the STA supports link adaptation using VHT variant
+# HT Control field
+# If +HTC-VHTcapable is 1
+# 0 = (no feedback) if the STA does not provide VHT MFB (default)
+# 1 = reserved
+# 2 = (Unsolicited) if the STA provides only unsolicited VHT MFB
+# 3 = (Both) if the STA can provide VHT MFB in response to VHT MRQ and if the
+# STA provides unsolicited VHT MFB
+# Reserved if +HTC-VHTcapable is 0
+#
+# Rx Antenna Pattern Consistency: [RX-ANTENNA-PATTERN]
+# Indicates the possibility of Rx antenna pattern change
+# 0 = Rx antenna pattern might change during the lifetime of an association
+# 1 = Rx antenna pattern does not change during the lifetime of an association
+#
+# Tx Antenna Pattern Consistency: [TX-ANTENNA-PATTERN]
+# Indicates the possibility of Tx antenna pattern change
+# 0 = Tx antenna pattern might change during the lifetime of an association
+# 1 = Tx antenna pattern does not change during the lifetime of an association
+#vht_capab=[SHORT-GI-80][HTC-VHT]
+#
+# Require stations to support VHT PHY (reject association if they do not)
+#require_vht=1
+
+# 0 = 20 or 40 MHz operating Channel width
+# 1 = 80 MHz channel width
+# 2 = 160 MHz channel width
+# 3 = 80+80 MHz channel width
+#vht_oper_chwidth=1
+#
+# center freq = 5 GHz + (5 * index)
+# So index 42 gives center freq 5.210 GHz
+# which is channel 42 in 5G band
+#
+#vht_oper_centr_freq_seg0_idx=42
+#
+# center freq = 5 GHz + (5 * index)
+# So index 159 gives center freq 5.795 GHz
+# which is channel 159 in 5G band
+#
+#vht_oper_centr_freq_seg1_idx=159
+
+##### IEEE 802.1X-2004 related configuration ##################################
+
+# Require IEEE 802.1X authorization
+#ieee8021x=1
+
+# IEEE 802.1X/EAPOL version
+# hostapd is implemented based on IEEE Std 802.1X-2004 which defines EAPOL
+# version 2. However, there are many client implementations that do not handle
+# the new version number correctly (they seem to drop the frames completely).
+# In order to make hostapd interoperate with these clients, the version number
+# can be set to the older version (1) with this configuration value.
+#eapol_version=2
+
+# Optional displayable message sent with EAP Request-Identity. The first \0
+# in this string will be converted to ASCII-0 (nul). This can be used to
+# separate network info (comma separated list of attribute=value pairs); see,
+# e.g., RFC 4284.
+#eap_message=hello
+#eap_message=hello\0networkid=netw,nasid=foo,portid=0,NAIRealms=example.com
+
+# WEP rekeying (disabled if key lengths are not set or are set to 0)
+# Key lengths for default/broadcast and individual/unicast keys:
+# 5 = 40-bit WEP (also known as 64-bit WEP with 40 secret bits)
+# 13 = 104-bit WEP (also known as 128-bit WEP with 104 secret bits)
+#wep_key_len_broadcast=5
+#wep_key_len_unicast=5
+# Rekeying period in seconds. 0 = do not rekey (i.e., set keys only once)
+#wep_rekey_period=300
+
+# EAPOL-Key index workaround (set bit7) for WinXP Supplicant (needed only if
+# only broadcast keys are used)
+eapol_key_index_workaround=0
+
+# EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable
+# reauthentication).
+#eap_reauth_period=3600
+
+# Use PAE group address (01:80:c2:00:00:03) instead of individual target
+# address when sending EAPOL frames with driver=wired. This is the most common
+# mechanism used in wired authentication, but it also requires that the port
+# is only used by one station.
+#use_pae_group_addr=1
+
+##### Integrated EAP server ###################################################
+
+# Optionally, hostapd can be configured to use an integrated EAP server
+# to process EAP authentication locally without need for an external RADIUS
+# server. This functionality can be used both as a local authentication server
+# for IEEE 802.1X/EAPOL and as a RADIUS server for other devices.
+
+# Use integrated EAP server instead of external RADIUS authentication
+# server. This is also needed if hostapd is configured to act as a RADIUS
+# authentication server.
+eap_server=0
+
+# Path for EAP server user database
+# If SQLite support is included, this can be set to "sqlite:/path/to/sqlite.db"
+# to use SQLite database instead of a text file.
+#eap_user_file=/etc/hostapd.eap_user
+
+# CA certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
+#ca_cert=/etc/hostapd.ca.pem
+
+# Server certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
+#server_cert=/etc/hostapd.server.pem
+
+# Private key matching with the server certificate for EAP-TLS/PEAP/TTLS
+# This may point to the same file as server_cert if both certificate and key
+# are included in a single file. PKCS#12 (PFX) file (.p12/.pfx) can also be
+# used by commenting out server_cert and specifying the PFX file as the
+# private_key.
+#private_key=/etc/hostapd.server.prv
+
+# Passphrase for private key
+#private_key_passwd=secret passphrase
+
+# Server identity
+# EAP methods that provide mechanism for authenticated server identity delivery
+# use this value. If not set, "hostapd" is used as a default.
+#server_id=server.example.com
+
+# Enable CRL verification.
+# Note: hostapd does not yet support CRL downloading based on CDP. Thus, a
+# valid CRL signed by the CA is required to be included in the ca_cert file.
+# This can be done by using PEM format for CA certificate and CRL and
+# concatenating these into one file. Whenever CRL changes, hostapd needs to be
+# restarted to take the new CRL into use.
+# 0 = do not verify CRLs (default)
+# 1 = check the CRL of the user certificate
+# 2 = check all CRLs in the certificate path
+#check_crl=1
+
+# Cached OCSP stapling response (DER encoded)
+# If set, this file is sent as a certificate status response by the EAP server
+# if the EAP peer requests certificate status in the ClientHello message.
+# This cache file can be updated, e.g., by running following command
+# periodically to get an update from the OCSP responder:
+# openssl ocsp \
+# -no_nonce \
+# -CAfile /etc/hostapd.ca.pem \
+# -issuer /etc/hostapd.ca.pem \
+# -cert /etc/hostapd.server.pem \
+# -url http://ocsp.example.com:8888/ \
+# -respout /tmp/ocsp-cache.der
+#ocsp_stapling_response=/tmp/ocsp-cache.der
+
+# dh_file: File path to DH/DSA parameters file (in PEM format)
+# This is an optional configuration file for setting parameters for an
+# ephemeral DH key exchange. In most cases, the default RSA authentication does
+# not use this configuration. However, it is possible setup RSA to use
+# ephemeral DH key exchange. In addition, ciphers with DSA keys always use
+# ephemeral DH keys. This can be used to achieve forward secrecy. If the file
+# is in DSA parameters format, it will be automatically converted into DH
+# params. This parameter is required if anonymous EAP-FAST is used.
+# You can generate DH parameters file with OpenSSL, e.g.,
+# "openssl dhparam -out /etc/hostapd.dh.pem 1024"
+#dh_file=/etc/hostapd.dh.pem
+
+# Fragment size for EAP methods
+#fragment_size=1400
+
+# Finite cyclic group for EAP-pwd. Number maps to group of domain parameters
+# using the IANA repository for IKE (RFC 2409).
+#pwd_group=19
+
+# Configuration data for EAP-SIM database/authentication gateway interface.
+# This is a text string in implementation specific format. The example
+# implementation in eap_sim_db.c uses this as the UNIX domain socket name for
+# the HLR/AuC gateway (e.g., hlr_auc_gw). In this case, the path uses "unix:"
+# prefix. If hostapd is built with SQLite support (CONFIG_SQLITE=y in .config),
+# database file can be described with an optional db=<path> parameter.
+#eap_sim_db=unix:/tmp/hlr_auc_gw.sock
+#eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/hostapd.db
+
+# Encryption key for EAP-FAST PAC-Opaque values. This key must be a secret,
+# random value. It is configured as a 16-octet value in hex format. It can be
+# generated, e.g., with the following command:
+# od -tx1 -v -N16 /dev/random | colrm 1 8 | tr -d ' '
+#pac_opaque_encr_key=000102030405060708090a0b0c0d0e0f
+
+# EAP-FAST authority identity (A-ID)
+# A-ID indicates the identity of the authority that issues PACs. The A-ID
+# should be unique across all issuing servers. In theory, this is a variable
+# length field, but due to some existing implementations requiring A-ID to be
+# 16 octets in length, it is strongly recommended to use that length for the
+# field to provid interoperability with deployed peer implementations. This
+# field is configured in hex format.
+#eap_fast_a_id=101112131415161718191a1b1c1d1e1f
+
+# EAP-FAST authority identifier information (A-ID-Info)
+# This is a user-friendly name for the A-ID. For example, the enterprise name
+# and server name in a human-readable format. This field is encoded as UTF-8.
+#eap_fast_a_id_info=test server
+
+# Enable/disable different EAP-FAST provisioning modes:
+#0 = provisioning disabled
+#1 = only anonymous provisioning allowed
+#2 = only authenticated provisioning allowed
+#3 = both provisioning modes allowed (default)
+#eap_fast_prov=3
+
+# EAP-FAST PAC-Key lifetime in seconds (hard limit)
+#pac_key_lifetime=604800
+
+# EAP-FAST PAC-Key refresh time in seconds (soft limit on remaining hard
+# limit). The server will generate a new PAC-Key when this number of seconds
+# (or fewer) of the lifetime remains.
+#pac_key_refresh_time=86400
+
+# EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND
+# (default: 0 = disabled).
+#eap_sim_aka_result_ind=1
+
+# Trusted Network Connect (TNC)
+# If enabled, TNC validation will be required before the peer is allowed to
+# connect. Note: This is only used with EAP-TTLS and EAP-FAST. If any other
+# EAP method is enabled, the peer will be allowed to connect without TNC.
+#tnc=1
+
+
+##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) #######################
+
+# Interface to be used for IAPP broadcast packets
+#iapp_interface=eth0
+
+
+##### RADIUS client configuration #############################################
+# for IEEE 802.1X with external Authentication Server, IEEE 802.11
+# authentication with external ACL for MAC addresses, and accounting
+
+# The own IP address of the access point (used as NAS-IP-Address)
+own_ip_addr=127.0.0.1
+
+# Optional NAS-Identifier string for RADIUS messages. When used, this should be
+# a unique to the NAS within the scope of the RADIUS server. For example, a
+# fully qualified domain name can be used here.
+# When using IEEE 802.11r, nas_identifier must be set and must be between 1 and
+# 48 octets long.
+#nas_identifier=ap.example.com
+
+# RADIUS authentication server
+#auth_server_addr=127.0.0.1
+#auth_server_port=1812
+#auth_server_shared_secret=secret
+
+# RADIUS accounting server
+#acct_server_addr=127.0.0.1
+#acct_server_port=1813
+#acct_server_shared_secret=secret
+
+# Secondary RADIUS servers; to be used if primary one does not reply to
+# RADIUS packets. These are optional and there can be more than one secondary
+# server listed.
+#auth_server_addr=127.0.0.2
+#auth_server_port=1812
+#auth_server_shared_secret=secret2
+#
+#acct_server_addr=127.0.0.2
+#acct_server_port=1813
+#acct_server_shared_secret=secret2
+
+# Retry interval for trying to return to the primary RADIUS server (in
+# seconds). RADIUS client code will automatically try to use the next server
+# when the current server is not replying to requests. If this interval is set,
+# primary server will be retried after configured amount of time even if the
+# currently used secondary server is still working.
+#radius_retry_primary_interval=600
+
+
+# Interim accounting update interval
+# If this is set (larger than 0) and acct_server is configured, hostapd will
+# send interim accounting updates every N seconds. Note: if set, this overrides
+# possible Acct-Interim-Interval attribute in Access-Accept message. Thus, this
+# value should not be configured in hostapd.conf, if RADIUS server is used to
+# control the interim interval.
+# This value should not be less 600 (10 minutes) and must not be less than
+# 60 (1 minute).
+#radius_acct_interim_interval=600
+
+# Request Chargeable-User-Identity (RFC 4372)
+# This parameter can be used to configure hostapd to request CUI from the
+# RADIUS server by including Chargeable-User-Identity attribute into
+# Access-Request packets.
+#radius_request_cui=1
+
+# Dynamic VLAN mode; allow RADIUS authentication server to decide which VLAN
+# is used for the stations. This information is parsed from following RADIUS
+# attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN),
+# Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value
+# VLANID as a string). Optionally, the local MAC ACL list (accept_mac_file) can
+# be used to set static client MAC address to VLAN ID mapping.
+# 0 = disabled (default)
+# 1 = option; use default interface if RADIUS server does not include VLAN ID
+# 2 = required; reject authentication if RADIUS server does not include VLAN ID
+#dynamic_vlan=0
+
+# VLAN interface list for dynamic VLAN mode is read from a separate text file.
+# This list is used to map VLAN ID from the RADIUS server to a network
+# interface. Each station is bound to one interface in the same way as with
+# multiple BSSIDs or SSIDs. Each line in this text file is defining a new
+# interface and the line must include VLAN ID and interface name separated by
+# white space (space or tab).
+# If no entries are provided by this file, the station is statically mapped
+# to <bss-iface>.<vlan-id> interfaces.
+#vlan_file=/etc/hostapd.vlan
+
+# Interface where 802.1q tagged packets should appear when a RADIUS server is
+# used to determine which VLAN a station is on. hostapd creates a bridge for
+# each VLAN. Then hostapd adds a VLAN interface (associated with the interface
+# indicated by 'vlan_tagged_interface') and the appropriate wireless interface
+# to the bridge.
+#vlan_tagged_interface=eth0
+
+# Bridge (prefix) to add the wifi and the tagged interface to. This gets the
+# VLAN ID appended. It defaults to brvlan%d if no tagged interface is given
+# and br%s.%d if a tagged interface is given, provided %s = tagged interface
+# and %d = VLAN ID.
+#vlan_bridge=brvlan
+
+# When hostapd creates a VLAN interface on vlan_tagged_interfaces, it needs
+# to know how to name it.
+# 0 = vlan<XXX>, e.g., vlan1
+# 1 = <vlan_tagged_interface>.<XXX>, e.g. eth0.1
+#vlan_naming=0
+
+# Arbitrary RADIUS attributes can be added into Access-Request and
+# Accounting-Request packets by specifying the contents of the attributes with
+# the following configuration parameters. There can be multiple of these to
+# add multiple attributes. These parameters can also be used to override some
+# of the attributes added automatically by hostapd.
+# Format: <attr_id>[:<syntax:value>]
+# attr_id: RADIUS attribute type (e.g., 26 = Vendor-Specific)
+# syntax: s = string (UTF-8), d = integer, x = octet string
+# value: attribute value in format indicated by the syntax
+# If syntax and value parts are omitted, a null value (single 0x00 octet) is
+# used.
+#
+# Additional Access-Request attributes
+# radius_auth_req_attr=<attr_id>[:<syntax:value>]
+# Examples:
+# Operator-Name = "Operator"
+#radius_auth_req_attr=126:s:Operator
+# Service-Type = Framed (2)
+#radius_auth_req_attr=6:d:2
+# Connect-Info = "testing" (this overrides the automatically generated value)
+#radius_auth_req_attr=77:s:testing
+# Same Connect-Info value set as a hexdump
+#radius_auth_req_attr=77:x:74657374696e67
+
+#
+# Additional Accounting-Request attributes
+# radius_acct_req_attr=<attr_id>[:<syntax:value>]
+# Examples:
+# Operator-Name = "Operator"
+#radius_acct_req_attr=126:s:Operator
+
+# Dynamic Authorization Extensions (RFC 5176)
+# This mechanism can be used to allow dynamic changes to user session based on
+# commands from a RADIUS server (or some other disconnect client that has the
+# needed session information). For example, Disconnect message can be used to
+# request an associated station to be disconnected.
+#
+# This is disabled by default. Set radius_das_port to non-zero UDP port
+# number to enable.
+#radius_das_port=3799
+#
+# DAS client (the host that can send Disconnect/CoA requests) and shared secret
+#radius_das_client=192.168.1.123 shared secret here
+#
+# DAS Event-Timestamp time window in seconds
+#radius_das_time_window=300
+#
+# DAS require Event-Timestamp
+#radius_das_require_event_timestamp=1
+
+##### RADIUS authentication server configuration ##############################
+
+# hostapd can be used as a RADIUS authentication server for other hosts. This
+# requires that the integrated EAP server is also enabled and both
+# authentication services are sharing the same configuration.
+
+# File name of the RADIUS clients configuration for the RADIUS server. If this
+# commented out, RADIUS server is disabled.
+#radius_server_clients=/etc/hostapd.radius_clients
+
+# The UDP port number for the RADIUS authentication server
+#radius_server_auth_port=1812
+
+# Use IPv6 with RADIUS server (IPv4 will also be supported using IPv6 API)
+#radius_server_ipv6=1
+
+
+##### WPA/IEEE 802.11i configuration ##########################################
+
+# Enable WPA. Setting this variable configures the AP to require WPA (either
+# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either
+# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK.
+# Instead of wpa_psk / wpa_passphrase, wpa_psk_radius might suffice.
+# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys),
+# RADIUS authentication server must be configured, and WPA-EAP must be included
+# in wpa_key_mgmt.
+# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0)
+# and/or WPA2 (full IEEE 802.11i/RSN):
+# bit0 = WPA
+# bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled)
+wpa=2
+
+# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
+# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
+# (8..63 characters) that will be converted to PSK. This conversion uses SSID
+# so the PSK changes when ASCII passphrase is used and the SSID is changed.
+# wpa_psk (dot11RSNAConfigPSKValue)
+# wpa_passphrase (dot11RSNAConfigPSKPassPhrase)
+#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
+wpa_passphrase=12345678
+
+# Optionally, WPA PSKs can be read from a separate text file (containing list
+# of (PSK,MAC address) pairs. This allows more than one PSK to be configured.
+# Use absolute path name to make sure that the files can be read on SIGHUP
+# configuration reloads.
+#wpa_psk_file=/etc/hostapd.wpa_psk
+
+# Optionally, WPA passphrase can be received from RADIUS authentication server
+# This requires macaddr_acl to be set to 2 (RADIUS)
+# 0 = disabled (default)
+# 1 = optional; use default passphrase/psk if RADIUS server does not include
+# Tunnel-Password
+# 2 = required; reject authentication if RADIUS server does not include
+# Tunnel-Password
+#wpa_psk_radius=0
+
+# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
+# entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be
+# added to enable SHA256-based stronger algorithms.
+# (dot11RSNAConfigAuthenticationSuitesTable)
+wpa_key_mgmt=WPA-PSK
+
+# Set of accepted cipher suites (encryption algorithms) for pairwise keys
+# (unicast packets). This is a space separated list of algorithms:
+# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
+# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
+# Group cipher suite (encryption algorithm for broadcast and multicast frames)
+# is automatically selected based on this configuration. If only CCMP is
+# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
+# TKIP will be used as the group cipher.
+# (dot11RSNAConfigPairwiseCiphersTable)
+# Pairwise cipher for WPA (v1) (default: TKIP)
+wpa_pairwise=TKIP CCMP
+# Pairwise cipher for RSN/WPA2 (default: use wpa_pairwise value)
+rsn_pairwise=CCMP
+
+# Time interval for rekeying GTK (broadcast/multicast encryption keys) in
+# seconds. (dot11RSNAConfigGroupRekeyTime)
+#wpa_group_rekey=600
+
+# Rekey GTK when any STA that possesses the current GTK is leaving the BSS.
+# (dot11RSNAConfigGroupRekeyStrict)
+#wpa_strict_rekey=1
+
+# Time interval for rekeying GMK (master key used internally to generate GTKs
+# (in seconds).
+#wpa_gmk_rekey=86400
+
+# Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of
+# PTK to mitigate some attacks against TKIP deficiencies.
+#wpa_ptk_rekey=600
+
+# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up
+# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
+# authentication and key handshake before actually associating with a new AP.
+# (dot11RSNAPreauthenticationEnabled)
+#rsn_preauth=1
+#
+# Space separated list of interfaces from which pre-authentication frames are
+# accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all
+# interface that are used for connections to other APs. This could include
+# wired interfaces and WDS links. The normal wireless data interface towards
+# associated stations (e.g., wlan0) should not be added, since
+# pre-authentication is only used with APs other than the currently associated
+# one.
+#rsn_preauth_interfaces=eth0
+
+# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e) is
+# allowed. This is only used with RSN/WPA2.
+# 0 = disabled (default)
+# 1 = enabled
+#peerkey=1
+
+# ieee80211w: Whether management frame protection (MFP) is enabled
+# 0 = disabled (default)
+# 1 = optional
+# 2 = required
+#ieee80211w=0
+
+# Association SA Query maximum timeout (in TU = 1.024 ms; for MFP)
+# (maximum time to wait for a SA Query response)
+# dot11AssociationSAQueryMaximumTimeout, 1...4294967295
+#assoc_sa_query_max_timeout=1000
+
+# Association SA Query retry timeout (in TU = 1.024 ms; for MFP)
+# (time between two subsequent SA Query requests)
+# dot11AssociationSAQueryRetryTimeout, 1...4294967295
+#assoc_sa_query_retry_timeout=201
+
+# disable_pmksa_caching: Disable PMKSA caching
+# This parameter can be used to disable caching of PMKSA created through EAP
+# authentication. RSN preauthentication may still end up using PMKSA caching if
+# it is enabled (rsn_preauth=1).
+# 0 = PMKSA caching enabled (default)
+# 1 = PMKSA caching disabled
+#disable_pmksa_caching=0
+
+# okc: Opportunistic Key Caching (aka Proactive Key Caching)
+# Allow PMK cache to be shared opportunistically among configured interfaces
+# and BSSes (i.e., all configurations within a single hostapd process).
+# 0 = disabled (default)
+# 1 = enabled
+#okc=1
+
+# SAE threshold for anti-clogging mechanism (dot11RSNASAEAntiCloggingThreshold)
+# This parameter defines how many open SAE instances can be in progress at the
+# same time before the anti-clogging mechanism is taken into use.
+#sae_anti_clogging_threshold=5
+
+# Enabled SAE finite cyclic groups
+# SAE implementation are required to support group 19 (ECC group defined over a
+# 256-bit prime order field). All groups that are supported by the
+# implementation are enabled by default. This configuration parameter can be
+# used to specify a limited set of allowed groups. The group values are listed
+# in the IANA registry:
+# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9
+#sae_groups=19 20 21 25 26
+
+##### IEEE 802.11r configuration ##############################################
+
+# Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
+# MDID is used to indicate a group of APs (within an ESS, i.e., sharing the
+# same SSID) between which a STA can use Fast BSS Transition.
+# 2-octet identifier as a hex string.
+#mobility_domain=a1b2
+
+# PMK-R0 Key Holder identifier (dot11FTR0KeyHolderID)
+# 1 to 48 octet identifier.
+# This is configured with nas_identifier (see RADIUS client section above).
+
+# Default lifetime of the PMK-RO in minutes; range 1..65535
+# (dot11FTR0KeyLifetime)
+#r0_key_lifetime=10000
+
+# PMK-R1 Key Holder identifier (dot11FTR1KeyHolderID)
+# 6-octet identifier as a hex string.
+#r1_key_holder=000102030405
+
+# Reassociation deadline in time units (TUs / 1.024 ms; range 1000..65535)
+# (dot11FTReassociationDeadline)
+#reassociation_deadline=1000
+
+# List of R0KHs in the same Mobility Domain
+# format: <MAC address> <NAS Identifier> <128-bit key as hex string>
+# This list is used to map R0KH-ID (NAS Identifier) to a destination MAC
+# address when requesting PMK-R1 key from the R0KH that the STA used during the
+# Initial Mobility Domain Association.
+#r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f
+#r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff
+# And so on.. One line per R0KH.
+
+# List of R1KHs in the same Mobility Domain
+# format: <MAC address> <R1KH-ID> <128-bit key as hex string>
+# This list is used to map R1KH-ID to a destination MAC address when sending
+# PMK-R1 key from the R0KH. This is also the list of authorized R1KHs in the MD
+# that can request PMK-R1 keys.
+#r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f
+#r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff
+# And so on.. One line per R1KH.
+
+# Whether PMK-R1 push is enabled at R0KH
+# 0 = do not push PMK-R1 to all configured R1KHs (default)
+# 1 = push PMK-R1 to all configured R1KHs whenever a new PMK-R0 is derived
+#pmk_r1_push=1
+
+##### Neighbor table ##########################################################
+# Maximum number of entries kept in AP table (either for neigbor table or for
+# detecting Overlapping Legacy BSS Condition). The oldest entry will be
+# removed when adding a new entry that would make the list grow over this
+# limit. Note! WFA certification for IEEE 802.11g requires that OLBC is
+# enabled, so this field should not be set to 0 when using IEEE 802.11g.
+# default: 255
+#ap_table_max_size=255
+
+# Number of seconds of no frames received after which entries may be deleted
+# from the AP table. Since passive scanning is not usually performed frequently
+# this should not be set to very small value. In addition, there is no
+# guarantee that every scan cycle will receive beacon frames from the
+# neighboring APs.
+# default: 60
+#ap_table_expiration_time=3600
+
+
+##### Wi-Fi Protected Setup (WPS) #############################################
+
+# WPS state
+# 0 = WPS disabled (default)
+# 1 = WPS enabled, not configured
+# 2 = WPS enabled, configured
+#wps_state=2
+
+# Whether to manage this interface independently from other WPS interfaces
+# By default, a single hostapd process applies WPS operations to all configured
+# interfaces. This parameter can be used to disable that behavior for a subset
+# of interfaces. If this is set to non-zero for an interface, WPS commands
+# issued on that interface do not apply to other interfaces and WPS operations
+# performed on other interfaces do not affect this interface.
+#wps_independent=0
+
+# AP can be configured into a locked state where new WPS Registrar are not
+# accepted, but previously authorized Registrars (including the internal one)
+# can continue to add new Enrollees.
+#ap_setup_locked=1
+
+# Universally Unique IDentifier (UUID; see RFC 4122) of the device
+# This value is used as the UUID for the internal WPS Registrar. If the AP
+# is also using UPnP, this value should be set to the device's UPnP UUID.
+# If not configured, UUID will be generated based on the local MAC address.
+#uuid=12345678-9abc-def0-1234-56789abcdef0
+
+# Note: If wpa_psk_file is set, WPS is used to generate random, per-device PSKs
+# that will be appended to the wpa_psk_file. If wpa_psk_file is not set, the
+# default PSK (wpa_psk/wpa_passphrase) will be delivered to Enrollees. Use of
+# per-device PSKs is recommended as the more secure option (i.e., make sure to
+# set wpa_psk_file when using WPS with WPA-PSK).
+
+# When an Enrollee requests access to the network with PIN method, the Enrollee
+# PIN will need to be entered for the Registrar. PIN request notifications are
+# sent to hostapd ctrl_iface monitor. In addition, they can be written to a
+# text file that could be used, e.g., to populate the AP administration UI with
+# pending PIN requests. If the following variable is set, the PIN requests will
+# be written to the configured file.
+#wps_pin_requests=/var/run/hostapd_wps_pin_requests
+
+# Device Name
+# User-friendly description of device; up to 32 octets encoded in UTF-8
+#device_name=Wireless AP
+
+# Manufacturer
+# The manufacturer of the device (up to 64 ASCII characters)
+#manufacturer=Company
+
+# Model Name
+# Model of the device (up to 32 ASCII characters)
+#model_name=WAP
+
+# Model Number
+# Additional device description (up to 32 ASCII characters)
+#model_number=123
+
+# Serial Number
+# Serial number of the device (up to 32 characters)
+#serial_number=12345
+
+# Primary Device Type
+# Used format: <categ>-<OUI>-<subcateg>
+# categ = Category as an integer value
+# OUI = OUI and type octet as a 4-octet hex-encoded value; 0050F204 for
+# default WPS OUI
+# subcateg = OUI-specific Sub Category as an integer value
+# Examples:
+# 1-0050F204-1 (Computer / PC)
+# 1-0050F204-2 (Computer / Server)
+# 5-0050F204-1 (Storage / NAS)
+# 6-0050F204-1 (Network Infrastructure / AP)
+#device_type=6-0050F204-1
+
+# OS Version
+# 4-octet operating system version number (hex string)
+#os_version=01020300
+
+# Config Methods
+# List of the supported configuration methods
+# Available methods: usba ethernet label display ext_nfc_token int_nfc_token
+# nfc_interface push_button keypad virtual_display physical_display
+# virtual_push_button physical_push_button
+#config_methods=label virtual_display virtual_push_button keypad
+
+# WPS capability discovery workaround for PBC with Windows 7
+# Windows 7 uses incorrect way of figuring out AP's WPS capabilities by acting
+# as a Registrar and using M1 from the AP. The config methods attribute in that
+# message is supposed to indicate only the configuration method supported by
+# the AP in Enrollee role, i.e., to add an external Registrar. For that case,
+# PBC shall not be used and as such, the PushButton config method is removed
+# from M1 by default. If pbc_in_m1=1 is included in the configuration file,
+# the PushButton config method is left in M1 (if included in config_methods
+# parameter) to allow Windows 7 to use PBC instead of PIN (e.g., from a label
+# in the AP).
+#pbc_in_m1=1
+
+# Static access point PIN for initial configuration and adding Registrars
+# If not set, hostapd will not allow external WPS Registrars to control the
+# access point. The AP PIN can also be set at runtime with hostapd_cli
+# wps_ap_pin command. Use of temporary (enabled by user action) and random
+# AP PIN is much more secure than configuring a static AP PIN here. As such,
+# use of the ap_pin parameter is not recommended if the AP device has means for
+# displaying a random PIN.
+#ap_pin=12345670
+
+# Skip building of automatic WPS credential
+# This can be used to allow the automatically generated Credential attribute to
+# be replaced with pre-configured Credential(s).
+#skip_cred_build=1
+
+# Additional Credential attribute(s)
+# This option can be used to add pre-configured Credential attributes into M8
+# message when acting as a Registrar. If skip_cred_build=1, this data will also
+# be able to override the Credential attribute that would have otherwise been
+# automatically generated based on network configuration. This configuration
+# option points to an external file that much contain the WPS Credential
+# attribute(s) as binary data.
+#extra_cred=hostapd.cred
+
+# Credential processing
+# 0 = process received credentials internally (default)
+# 1 = do not process received credentials; just pass them over ctrl_iface to
+# external program(s)
+# 2 = process received credentials internally and pass them over ctrl_iface
+# to external program(s)
+# Note: With wps_cred_processing=1, skip_cred_build should be set to 1 and
+# extra_cred be used to provide the Credential data for Enrollees.
+#
+# wps_cred_processing=1 will disabled automatic updates of hostapd.conf file
+# both for Credential processing and for marking AP Setup Locked based on
+# validation failures of AP PIN. An external program is responsible on updating
+# the configuration appropriately in this case.
+#wps_cred_processing=0
+
+# AP Settings Attributes for M7
+# By default, hostapd generates the AP Settings Attributes for M7 based on the
+# current configuration. It is possible to override this by providing a file
+# with pre-configured attributes. This is similar to extra_cred file format,
+# but the AP Settings attributes are not encapsulated in a Credential
+# attribute.
+#ap_settings=hostapd.ap_settings
+
+# WPS UPnP interface
+# If set, support for external Registrars is enabled.
+#upnp_iface=br0
+
+# Friendly Name (required for UPnP)
+# Short description for end use. Should be less than 64 characters.
+#friendly_name=WPS Access Point
+
+# Manufacturer URL (optional for UPnP)
+#manufacturer_url=http://www.example.com/
+
+# Model Description (recommended for UPnP)
+# Long description for end user. Should be less than 128 characters.
+#model_description=Wireless Access Point
+
+# Model URL (optional for UPnP)
+#model_url=http://www.example.com/model/
+
+# Universal Product Code (optional for UPnP)
+# 12-digit, all-numeric code that identifies the consumer package.
+#upc=123456789012
+
+# WPS RF Bands (a = 5G, b = 2.4G, g = 2.4G, ag = dual band)
+# This value should be set according to RF band(s) supported by the AP if
+# hw_mode is not set. For dual band dual concurrent devices, this needs to be
+# set to ag to allow both RF bands to be advertized.
+#wps_rf_bands=ag
+
+# NFC password token for WPS
+# These parameters can be used to configure a fixed NFC password token for the
+# AP. This can be generated, e.g., with nfc_pw_token from wpa_supplicant. When
+# these parameters are used, the AP is assumed to be deployed with a NFC tag
+# that includes the matching NFC password token (e.g., written based on the
+# NDEF record from nfc_pw_token).
+#
+#wps_nfc_dev_pw_id: Device Password ID (16..65535)
+#wps_nfc_dh_pubkey: Hexdump of DH Public Key
+#wps_nfc_dh_privkey: Hexdump of DH Private Key
+#wps_nfc_dev_pw: Hexdump of Device Password
+
+##### Wi-Fi Direct (P2P) ######################################################
+
+# Enable P2P Device management
+#manage_p2p=1
+
+# Allow cross connection
+#allow_cross_connection=1
+
+#### TDLS (IEEE 802.11z-2010) #################################################
+
+# Prohibit use of TDLS in this BSS
+#tdls_prohibit=1
+
+# Prohibit use of TDLS Channel Switching in this BSS
+#tdls_prohibit_chan_switch=1
+
+##### IEEE 802.11v-2011 #######################################################
+
+# Time advertisement
+# 0 = disabled (default)
+# 2 = UTC time at which the TSF timer is 0
+#time_advertisement=2
+
+# Local time zone as specified in 8.3 of IEEE Std 1003.1-2004:
+# stdoffset[dst[offset][,start[/time],end[/time]]]
+#time_zone=EST5
+
+# WNM-Sleep Mode (extended sleep mode for stations)
+# 0 = disabled (default)
+# 1 = enabled (allow stations to use WNM-Sleep Mode)
+#wnm_sleep_mode=1
+
+# BSS Transition Management
+# 0 = disabled (default)
+# 1 = enabled
+#bss_transition=1
+
+##### IEEE 802.11u-2011 #######################################################
+
+# Enable Interworking service
+#interworking=1
+
+# Access Network Type
+# 0 = Private network
+# 1 = Private network with guest access
+# 2 = Chargeable public network
+# 3 = Free public network
+# 4 = Personal device network
+# 5 = Emergency services only network
+# 14 = Test or experimental
+# 15 = Wildcard
+#access_network_type=0
+
+# Whether the network provides connectivity to the Internet
+# 0 = Unspecified
+# 1 = Network provides connectivity to the Internet
+#internet=1
+
+# Additional Step Required for Access
+# Note: This is only used with open network, i.e., ASRA shall ne set to 0 if
+# RSN is used.
+#asra=0
+
+# Emergency services reachable
+#esr=0
+
+# Unauthenticated emergency service accessible
+#uesa=0
+
+# Venue Info (optional)
+# The available values are defined in IEEE Std 802.11u-2011, 7.3.1.34.
+# Example values (group,type):
+# 0,0 = Unspecified
+# 1,7 = Convention Center
+# 1,13 = Coffee Shop
+# 2,0 = Unspecified Business
+# 7,1 Private Residence
+#venue_group=7
+#venue_type=1
+
+# Homogeneous ESS identifier (optional; dot11HESSID)
+# If set, this shall be identifical to one of the BSSIDs in the homogeneous
+# ESS and this shall be set to the same value across all BSSs in homogeneous
+# ESS.
+#hessid=02:03:04:05:06:07
+
+# Roaming Consortium List
+# Arbitrary number of Roaming Consortium OIs can be configured with each line
+# adding a new OI to the list. The first three entries are available through
+# Beacon and Probe Response frames. Any additional entry will be available only
+# through ANQP queries. Each OI is between 3 and 15 octets and is configured as
+# a hexstring.
+#roaming_consortium=021122
+#roaming_consortium=2233445566
+
+# Venue Name information
+# This parameter can be used to configure one or more Venue Name Duples for
+# Venue Name ANQP information. Each entry has a two or three character language
+# code (ISO-639) separated by colon from the venue name string.
+# Note that venue_group and venue_type have to be set for Venue Name
+# information to be complete.
+#venue_name=eng:Example venue
+#venue_name=fin:Esimerkkipaikka
+# Alternative format for language:value strings:
+# (double quoted string, printf-escaped string)
+#venue_name=P"eng:Example\nvenue"
+
+# Network Authentication Type
+# This parameter indicates what type of network authentication is used in the
+# network.
+# format: <network auth type indicator (1-octet hex str)> [redirect URL]
+# Network Authentication Type Indicator values:
+# 00 = Acceptance of terms and conditions
+# 01 = On-line enrollment supported
+# 02 = http/https redirection
+# 03 = DNS redirection
+#network_auth_type=00
+#network_auth_type=02http://www.example.com/redirect/me/here/
+
+# IP Address Type Availability
+# format: <1-octet encoded value as hex str>
+# (ipv4_type & 0x3f) << 2 | (ipv6_type & 0x3)
+# ipv4_type:
+# 0 = Address type not available
+# 1 = Public IPv4 address available
+# 2 = Port-restricted IPv4 address available
+# 3 = Single NATed private IPv4 address available
+# 4 = Double NATed private IPv4 address available
+# 5 = Port-restricted IPv4 address and single NATed IPv4 address available
+# 6 = Port-restricted IPv4 address and double NATed IPv4 address available
+# 7 = Availability of the address type is not known
+# ipv6_type:
+# 0 = Address type not available
+# 1 = Address type available
+# 2 = Availability of the address type not known
+#ipaddr_type_availability=14
+
+# Domain Name
+# format: <variable-octet str>[,<variable-octet str>]
+#domain_name=example.com,another.example.com,yet-another.example.com
+
+# 3GPP Cellular Network information
+# format: <MCC1,MNC1>[;<MCC2,MNC2>][;...]
+#anqp_3gpp_cell_net=244,91;310,026;234,56
+
+# NAI Realm information
+# One or more realm can be advertised. Each nai_realm line adds a new realm to
+# the set. These parameters provide information for stations using Interworking
+# network selection to allow automatic connection to a network based on
+# credentials.
+# format: <encoding>,<NAI Realm(s)>[,<EAP Method 1>][,<EAP Method 2>][,...]
+# encoding:
+# 0 = Realm formatted in accordance with IETF RFC 4282
+# 1 = UTF-8 formatted character string that is not formatted in
+# accordance with IETF RFC 4282
+# NAI Realm(s): Semi-colon delimited NAI Realm(s)
+# EAP Method: <EAP Method>[:<[AuthParam1:Val1]>][<[AuthParam2:Val2]>][...]
+# AuthParam (Table 8-188 in IEEE Std 802.11-2012):
+# ID 2 = Non-EAP Inner Authentication Type
+# 1 = PAP, 2 = CHAP, 3 = MSCHAP, 4 = MSCHAPV2
+# ID 3 = Inner authentication EAP Method Type
+# ID 5 = Credential Type
+# 1 = SIM, 2 = USIM, 3 = NFC Secure Element, 4 = Hardware Token,
+# 5 = Softoken, 6 = Certificate, 7 = username/password, 9 = Anonymous,
+# 10 = Vendor Specific
+#nai_realm=0,example.com;example.net
+# EAP methods EAP-TLS with certificate and EAP-TTLS/MSCHAPv2 with
+# username/password
+#nai_realm=0,example.org,13[5:6],21[2:4][5:7]
+
+# QoS Map Set configuration
+#
+# Comma delimited QoS Map Set in decimal values
+# (see IEEE Std 802.11-2012, 8.4.2.97)
+#
+# format:
+# [<DSCP Exceptions[DSCP,UP]>,]<UP 0 range[low,high]>,...<UP 7 range[low,high]>
+#
+# There can be up to 21 optional DSCP Exceptions which are pairs of DSCP Value
+# (0..63 or 255) and User Priority (0..7). This is followed by eight DSCP Range
+# descriptions with DSCP Low Value and DSCP High Value pairs (0..63 or 255) for
+# each UP starting from 0. If both low and high value are set to 255, the
+# corresponding UP is not used.
+#
+# default: not set
+#qos_map_set=53,2,22,6,8,15,0,7,255,255,16,31,32,39,255,255,40,47,255,255
+
+##### Hotspot 2.0 #############################################################
+
+# Enable Hotspot 2.0 support
+#hs20=1
+
+# Disable Downstream Group-Addressed Forwarding (DGAF)
+# This can be used to configure a network where no group-addressed frames are
+# allowed. The AP will not forward any group-address frames to the stations and
+# random GTKs are issued for each station to prevent associated stations from
+# forging such frames to other stations in the BSS.
+#disable_dgaf=1
+
+# Operator Friendly Name
+# This parameter can be used to configure one or more Operator Friendly Name
+# Duples. Each entry has a two or three character language code (ISO-639)
+# separated by colon from the operator friendly name string.
+#hs20_oper_friendly_name=eng:Example operator
+#hs20_oper_friendly_name=fin:Esimerkkioperaattori
+
+# Connection Capability
+# This can be used to advertise what type of IP traffic can be sent through the
+# hotspot (e.g., due to firewall allowing/blocking protocols/ports).
+# format: <IP Protocol>:<Port Number>:<Status>
+# IP Protocol: 1 = ICMP, 6 = TCP, 17 = UDP
+# Port Number: 0..65535
+# Status: 0 = Closed, 1 = Open, 2 = Unknown
+# Each hs20_conn_capab line is added to the list of advertised tuples.
+#hs20_conn_capab=1:0:2
+#hs20_conn_capab=6:22:1
+#hs20_conn_capab=17:5060:0
+
+# WAN Metrics
+# format: <WAN Info>:<DL Speed>:<UL Speed>:<DL Load>:<UL Load>:<LMD>
+# WAN Info: B0-B1: Link Status, B2: Symmetric Link, B3: At Capabity
+# (encoded as two hex digits)
+# Link Status: 1 = Link up, 2 = Link down, 3 = Link in test state
+# Downlink Speed: Estimate of WAN backhaul link current downlink speed in kbps;
+# 1..4294967295; 0 = unknown
+# Uplink Speed: Estimate of WAN backhaul link current uplink speed in kbps
+# 1..4294967295; 0 = unknown
+# Downlink Load: Current load of downlink WAN connection (scaled to 255 = 100%)
+# Uplink Load: Current load of uplink WAN connection (scaled to 255 = 100%)
+# Load Measurement Duration: Duration for measuring downlink/uplink load in
+# tenths of a second (1..65535); 0 if load cannot be determined
+#hs20_wan_metrics=01:8000:1000:80:240:3000
+
+# Operating Class Indication
+# List of operating classes the BSSes in this ESS use. The Global operating
+# classes in Table E-4 of IEEE Std 802.11-2012 Annex E define the values that
+# can be used in this.
+# format: hexdump of operating class octets
+# for example, operating classes 81 (2.4 GHz channels 1-13) and 115 (5 GHz
+# channels 36-48):
+#hs20_operating_class=5173
+
+##### TESTING OPTIONS #########################################################
+#
+# The options in this section are only available when the build configuration
+# option CONFIG_TESTING_OPTIONS is set while compiling hostapd. They allow
+# testing some scenarios that are otherwise difficult to reproduce.
+#
+# Ignore probe requests sent to hostapd with the given probability, must be a
+# floating point number in the range [0, 1).
+#ignore_probe_probability=0.0
+#
+# Ignore authentication frames with the given probability
+#ignore_auth_probability=0.0
+#
+# Ignore association requests with the given probability
+#ignore_assoc_probability=0.0
+#
+# Ignore reassociation requests with the given probability
+#ignore_reassoc_probability=0.0
+#
+# Corrupt Key MIC in GTK rekey EAPOL-Key frames with the given probability
+#corrupt_gtk_rekey_mic_probability=0.0
+
+##### Multiple BSSID support ##################################################
+#
+# Above configuration is using the default interface (wlan#, or multi-SSID VLAN
+# interfaces). Other BSSIDs can be added by using separator 'bss' with
+# default interface name to be allocated for the data packets of the new BSS.
+#
+# hostapd will generate BSSID mask based on the BSSIDs that are
+# configured. hostapd will verify that dev_addr & MASK == dev_addr. If this is
+# not the case, the MAC address of the radio must be changed before starting
+# hostapd (ifconfig wlan0 hw ether <MAC addr>). If a BSSID is configured for
+# every secondary BSS, this limitation is not applied at hostapd and other
+# masks may be used if the driver supports them (e.g., swap the locally
+# administered bit)
+#
+# BSSIDs are assigned in order to each BSS, unless an explicit BSSID is
+# specified using the 'bssid' parameter.
+# If an explicit BSSID is specified, it must be chosen such that it:
+# - results in a valid MASK that covers it and the dev_addr
+# - is not the same as the MAC address of the radio
+# - is not the same as any other explicitly specified BSSID
+#
+# Please note that hostapd uses some of the values configured for the first BSS
+# as the defaults for the following BSSes. However, it is recommended that all
+# BSSes include explicit configuration of all relevant configuration items.
+#
+#bss=wlan0_0
+#ssid=test2
+# most of the above items can be used here (apart from radio interface specific
+# items, like channel)
+
+#bss=wlan0_1
+#bssid=00:13:10:95:fe:0b
+# ...
diff --git a/meta-edison-distro/recipes-connectivity/hostapd/files/hostapd.service b/meta-edison-distro/recipes-connectivity/hostapd/files/hostapd.service
new file mode 100644
index 0000000..df99402
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/hostapd/files/hostapd.service
@@ -0,0 +1,23 @@
+[Unit]
+Description=Hostap daemon service
+Requires=sys-subsystem-net-devices-wlan0.device udhcpd-for-hostapd.service
+After=sys-subsystem-net-devices-wlan0.device
+Before=udhcpd-for-hostapd.service
+
+[Service]
+Type=simple
+
+# reload the driver for softap mode
+ExecStartPre=/sbin/modprobe -r bcm4334x
+ExecStartPre=/sbin/modprobe bcm4334x op_mode=2
+
+# start the service hostapd
+ExecStart=/usr/sbin/hostapd /etc/hostapd/hostapd.conf
+
+# reload the driver for sta/p2p mode
+ExecStopPost=/sbin/modprobe -r bcm4334x
+ExecStopPost=/sbin/modprobe bcm4334x
+
+[Install]
+WantedBy=multi-user.target
+
diff --git a/meta-edison-distro/recipes-connectivity/hostapd/files/udhcpd-for-hostapd.conf b/meta-edison-distro/recipes-connectivity/hostapd/files/udhcpd-for-hostapd.conf
new file mode 100644
index 0000000..1015e39
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/hostapd/files/udhcpd-for-hostapd.conf
@@ -0,0 +1,107 @@
+# Sample udhcpd configuration file (/etc/udhcpd.conf)
+
+# The start and end of the IP lease block
+
+start 192.168.42.20 #default: 192.168.0.20
+end 192.168.42.254 #default: 192.168.0.254
+
+
+# The interface that udhcpd will use
+
+interface wlan0 #default: eth0
+
+
+# The maximim number of leases (includes addressesd reserved
+# by OFFER's, DECLINE's, and ARP conficts
+
+#max_leases 254 #default: 254
+
+
+# If remaining is true (default), udhcpd will store the time
+# remaining for each lease in the udhcpd leases file. This is
+# for embedded systems that cannot keep time between reboots.
+# If you set remaining to no, the absolute time that the lease
+# expires at will be stored in the dhcpd.leases file.
+
+remaining yes #default: yes
+
+
+# The time period at which udhcpd will write out a dhcpd.leases
+# file. If this is 0, udhcpd will never automatically write a
+# lease file. (specified in seconds)
+
+#auto_time 7200 #default: 7200 (2 hours)
+
+
+# The amount of time that an IP will be reserved (leased) for if a
+# DHCP decline message is received (seconds).
+
+#decline_time 3600 #default: 3600 (1 hour)
+
+
+# The amount of time that an IP will be reserved (leased) for if an
+# ARP conflct occurs. (seconds
+
+#conflict_time 3600 #default: 3600 (1 hour)
+
+
+# How long an offered address is reserved (leased) in seconds
+
+#offer_time 60 #default: 60 (1 minute)
+
+# If a lease to be given is below this value, the full lease time is
+# instead used (seconds).
+
+#min_lease 60 #defult: 60
+
+
+# The location of the leases file
+
+#lease_file /var/lib/misc/udhcpd.leases #defualt: /var/lib/misc/udhcpd.leases
+
+# The location of the pid file
+pidfile /var/run/udhcpd-wlan0.pid #default: /var/run/udhcpd.pid
+
+# Every time udhcpd writes a leases file, the below script will be called.
+# Useful for writing the lease file to flash every few hours.
+
+#notify_file #default: (no script)
+
+#notify_file dumpleases # <--- useful for debugging
+
+# The following are bootp specific options, setable by udhcpd.
+
+#siaddr 192.168.0.22 #default: 0.0.0.0
+
+#sname zorak #default: (none)
+
+#boot_file /var/nfs_root #default: (none)
+
+# The remainer of options are DHCP options and can be specifed with the
+# keyword 'opt' or 'option'. If an option can take multiple items, such
+# as the dns option, they can be listed on the same line, or multiple
+# lines. The only option with a default is 'lease'.
+
+# Currently supported options, for more info, see options.c
+opt subnet 255.255.255.0
+#opt timezone
+#opt router
+#opt timesvr
+#opt namesvr
+#opt dns
+#opt logsvr
+#opt cookiesvr
+#opt lprsvr
+#opt bootsize
+#opt domain
+#opt swapsvr
+#opt rootpath
+#opt ipttl
+#opt mtu
+#opt broadcast
+#opt wins
+#opt lease
+#opt ntpsrv
+#opt tftp
+#opt bootfile
+
diff --git a/meta-edison-distro/recipes-connectivity/hostapd/files/udhcpd-for-hostapd.service b/meta-edison-distro/recipes-connectivity/hostapd/files/udhcpd-for-hostapd.service
new file mode 100644
index 0000000..b7ca3ba
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/hostapd/files/udhcpd-for-hostapd.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=udhcpd daemon for hostapd
+Requires=hostapd.service
+After=hostapd.service
+StopWhenUnneeded=true
+
+[Service]
+Type=simple
+ExecStartPre=/sbin/ifconfig wlan0 192.168.42.1 up
+ExecStart=/usr/sbin/udhcpd -f -S /etc/hostapd/udhcpd-for-hostapd.conf
+Restart=on-failure
+RestartSec=1
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-edison-distro/recipes-connectivity/hostapd/hostapd-daemon_2.1.bb b/meta-edison-distro/recipes-connectivity/hostapd/hostapd-daemon_2.1.bb
new file mode 100644
index 0000000..2e348f6
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/hostapd/hostapd-daemon_2.1.bb
@@ -0,0 +1,51 @@
+HOMEPAGE = "http://hostap.epitest.fi"
+SECTION = "kernel/userland"
+LICENSE = "GPLv2 | BSD"
+LIC_FILES_CHKSUM = "file://README;md5=0854a4da34ac3990770794d771fac7fd"
+DEPENDS = "libnl openssl"
+SUMMARY = "User space daemon for extended IEEE 802.11 management"
+
+inherit systemd
+
+SYSTEMD_SERVICE_${PN} = "hostapd.service udhcpd-for-hostapd.service"
+SYSTEMD_AUTO_ENABLE = "disable"
+
+SRC_URI = " \
+ http://hostap.epitest.fi/releases/hostapd-${PV}.tar.gz \
+ file://defconfig \
+ file://hostapd.service \
+ file://udhcpd-for-hostapd.service \
+ file://hostapd.conf-sane \
+ file://udhcpd-for-hostapd.conf \
+"
+
+S = "${WORKDIR}/hostapd-${PV}/hostapd"
+
+do_configure() {
+ install -m 0644 ${WORKDIR}/defconfig ${S}/.config
+ echo "CFLAGS +=\"-I${STAGING_INCDIR}/libnl3\"" >> ${S}/.config
+}
+
+do_compile() {
+ make
+}
+
+do_install() {
+ install -d ${D}${sbindir}
+ install -m 0755 ${S}/hostapd ${D}${sbindir}
+ install -m 0755 ${S}/hostapd_cli ${D}${sbindir}
+
+ install -d ${D}${sysconfdir}/hostapd
+ install -m 0644 ${WORKDIR}/hostapd.conf-sane ${D}${sysconfdir}/hostapd/hostapd.conf
+ install -m 0644 ${WORKDIR}/udhcpd-for-hostapd.conf ${D}${sysconfdir}/hostapd
+
+ if ${@base_contains('DISTRO_FEATURES','systemd','true','false',d)}; then
+ # Install hostapd service
+ install -d ${D}/${systemd_unitdir}/system
+ install -m 644 ${WORKDIR}/hostapd.service ${D}${systemd_unitdir}/system
+ install -m 644 ${WORKDIR}/udhcpd-for-hostapd.service ${D}${systemd_unitdir}/system
+ fi
+}
+
+SRC_URI[md5sum] = "bb9c50e87c5af6f89f387e63911effac"
+SRC_URI[sha256sum] = "5c7110f55b6092e5277e26edc961eda2def12b94218129d116f5681e34bb2f88"
diff --git a/meta-edison-distro/recipes-connectivity/libpcap/libpcap_1.5.3.bbappend b/meta-edison-distro/recipes-connectivity/libpcap/libpcap_1.5.3.bbappend
new file mode 100644
index 0000000..b3c0900
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/libpcap/libpcap_1.5.3.bbappend
@@ -0,0 +1,2 @@
+PROVIDES = "libpcap"
+PACKAGECONFIG[bluetooth] = "--enable-bluetooth,--disable-bluetooth,bluez5"
diff --git a/meta-edison-distro/recipes-connectivity/ofono/ofono_1.14.bbappend b/meta-edison-distro/recipes-connectivity/ofono/ofono_1.14.bbappend
new file mode 100644
index 0000000..6fd9ffe
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/ofono/ofono_1.14.bbappend
@@ -0,0 +1 @@
+DEPENDS = "dbus glib-2.0 udev mobile-broadband-provider-info ${@base_contains('DISTRO_FEATURES', 'bluetooth','bluez5', '', d)}"
diff --git a/meta-edison-distro/recipes-connectivity/openssh/openssh/sshd.socket b/meta-edison-distro/recipes-connectivity/openssh/openssh/sshd.socket
new file mode 100644
index 0000000..2a1b012
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssh/openssh/sshd.socket
@@ -0,0 +1,13 @@
+[Unit]
+Conflicts=sshd.service
+
+[Socket]
+ExecStartPre=/bin/mkdir -p /var/run/sshd
+ListenStream=22
+# restrict access to wired access for security reasons
+# comment this line to remove restriction
+BindToDevice=usb0
+Accept=yes
+
+[Install]
+WantedBy=sockets.target
diff --git a/meta-edison-distro/recipes-connectivity/openssh/openssh/sshdgenkeys.service b/meta-edison-distro/recipes-connectivity/openssh/openssh/sshdgenkeys.service
new file mode 100644
index 0000000..e8133e4
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssh/openssh/sshdgenkeys.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=OpenSSH Key Generation
+
+[Service]
+ExecStart=@BASE_BINDIR@/sh -c "if ! sshd -t &> /dev/null ; then rm /etc/ssh/*_key* ; ssh-keygen -A ; sync ; fi"
+Type=oneshot
+RemainAfterExit=yes
diff --git a/meta-edison-distro/recipes-connectivity/openssh/openssh_%.bbappend b/meta-edison-distro/recipes-connectivity/openssh/openssh_%.bbappend
new file mode 100644
index 0000000..1e72f89
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssh/openssh_%.bbappend
@@ -0,0 +1 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/openssh"
diff --git a/meta-edison-distro/recipes-connectivity/openssl/cryptodev-linux_1.6.bb b/meta-edison-distro/recipes-connectivity/openssl/cryptodev-linux_1.6.bb
new file mode 100644
index 0000000..320716d
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/cryptodev-linux_1.6.bb
@@ -0,0 +1,22 @@
+SUMMARY = "A /dev/crypto device driver"
+HOMEPAGE = "http://cryptodev-linux.org/"
+
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263"
+
+SRC_URI = "http://download.gna.org/cryptodev-linux/${BPN}-${PV}.tar.gz"
+
+SRC_URI[md5sum] = "eade38998313c25fd7934719cdf8a2ea"
+SRC_URI[sha256sum] = "75f1425c8ea1f8cae523905a5a046a35092327a6152800b0b86efc4e56fb3e2f"
+
+do_compile() {
+ :
+}
+
+# Just install cryptodev.h which is the only header file needed to be exported
+do_install() {
+ install -D ${S}/crypto/cryptodev.h ${D}${includedir}/crypto/cryptodev.h
+}
+
+ALLOW_EMPTY_${PN} = "1"
+BBCLASSEXTEND = "native nativesdk"
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl.inc b/meta-edison-distro/recipes-connectivity/openssl/openssl.inc
new file mode 100644
index 0000000..ee02fb7
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl.inc
@@ -0,0 +1,173 @@
+SUMMARY = "Secure Socket Layer"
+DESCRIPTION = "Secure Socket Layer (SSL) binary and related cryptographic tools."
+HOMEPAGE = "http://www.openssl.org/"
+BUGTRACKER = "http://www.openssl.org/news/vulnerabilities.html"
+SECTION = "libs/network"
+
+# "openssl | SSLeay" dual license
+LICENSE = "openssl"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=f9a8f968107345e0b75aa8c2ecaa7ec8"
+
+DEPENDS = "perl-native-runtime"
+
+SRC_URI = "http://www.openssl.org/source/openssl-${PV}.tar.gz \
+ "
+S = "${WORKDIR}/openssl-${PV}"
+
+PACKAGECONFIG[perl] = ",,,"
+
+AR_append = " r"
+# Avoid binaries being marked as requiring an executable stack since it
+# doesn't(which causes and this causes issues with SELinux
+CFLAG = "${@base_conditional('SITEINFO_ENDIANNESS', 'le', '-DL_ENDIAN', '-DB_ENDIAN', d)} \
+ -DTERMIO ${CFLAGS} -Wall -Wa,--noexecstack"
+
+# -02 does not work on mipsel: ssh hangs when it tries to read /dev/urandom
+CFLAG_mtx-1 := "${@'${CFLAG}'.replace('-O2', '')}"
+CFLAG_mtx-2 := "${@'${CFLAG}'.replace('-O2', '')}"
+
+export DIRS = "crypto ssl apps"
+export EX_LIBS = "-lgcc -ldl"
+export AS = "${CC} -c"
+
+inherit pkgconfig siteinfo multilib_header
+
+PACKAGES =+ "libcrypto libssl ${PN}-misc openssl-conf"
+FILES_libcrypto = "${base_libdir}/libcrypto${SOLIBS}"
+FILES_libssl = "${libdir}/libssl.so.*"
+FILES_${PN} =+ " ${libdir}/ssl/*"
+FILES_${PN}-misc = "${libdir}/ssl/misc ${bindir}/c_rehash"
+RDEPENDS_${PN}-misc = "${@base_contains('PACKAGECONFIG', 'perl', 'perl', '', d)}"
+FILES_${PN}-dev += "${base_libdir}/libcrypto${SOLIBSDEV}"
+
+# Add the openssl.cnf file to the openssl-conf package. Make the libcrypto
+# package RRECOMMENDS on this package. This will enable the configuration
+# file to be installed for both the base openssl package and the libcrypto
+# package since the base openssl package depends on the libcrypto package.
+FILES_openssl-conf = "${libdir}/ssl/openssl.cnf"
+CONFFILES_openssl-conf = "${libdir}/ssl/openssl.cnf"
+RRECOMMENDS_libcrypto += "openssl-conf"
+
+do_configure_prepend_darwin () {
+ sed -i -e '/version-script=openssl\.ld/d' Configure
+}
+
+do_configure () {
+ cd util
+ perl perlpath.pl ${STAGING_BINDIR_NATIVE}
+ cd ..
+ ln -sf apps/openssl.pod crypto/crypto.pod ssl/ssl.pod doc/
+
+ os=${HOST_OS}
+ if [ "x$os" = "xlinux-uclibc" ]; then
+ os=linux
+ elif [ "x$os" = "xlinux-uclibceabi" ]; then
+ os=linux
+ elif [ "x$os" = "xlinux-uclibcspe" ]; then
+ os=linux
+ elif [ "x$os" = "xlinux-gnuspe" ]; then
+ os=linux
+ elif [ "x$os" = "xlinux-gnueabi" ]; then
+ os=linux
+ fi
+ target="$os-${HOST_ARCH}"
+ case $target in
+ linux-arm)
+ target=linux-armv4
+ ;;
+ linux-armeb)
+ target=linux-elf-armeb
+ ;;
+ linux-aarch64*)
+ target=linux-generic64
+ ;;
+ linux-sh3)
+ target=debian-sh3
+ ;;
+ linux-sh4)
+ target=debian-sh4
+ ;;
+ linux-i486)
+ target=debian-i386-i486
+ ;;
+ linux-i586 | linux-viac3)
+ target=debian-i386-i586
+ ;;
+ linux-i686)
+ target=debian-i386-i686/cmov
+ ;;
+ linux-gnux32-x86_64)
+ target=linux-x32
+ ;;
+ linux-gnu64-x86_64)
+ target=linux-x86_64
+ ;;
+ linux-mips)
+ target=debian-mips
+ ;;
+ linux-mipsel)
+ target=debian-mipsel
+ ;;
+ linux-*-mips64)
+ target=linux-mips
+ ;;
+ linux-powerpc)
+ target=linux-ppc
+ ;;
+ linux-powerpc64)
+ target=linux-ppc64
+ ;;
+ linux-supersparc)
+ target=linux-sparcv8
+ ;;
+ linux-sparc)
+ target=linux-sparcv8
+ ;;
+ darwin-i386)
+ target=darwin-i386-cc
+ ;;
+ esac
+ # inject machine-specific flags
+ sed -i -e "s|^\(\"$target\",\s*\"[^:]\+\):\([^:]\+\)|\1:${CFLAG}|g" Configure
+ useprefix=${prefix}
+ if [ "x$useprefix" = "x" ]; then
+ useprefix=/
+ fi
+ perl ./Configure ${EXTRA_OECONF} shared --prefix=$useprefix --openssldir=${libdir}/ssl --libdir=`basename ${libdir}` $target
+}
+
+do_compile () {
+ oe_runmake
+}
+
+do_install () {
+ oe_runmake INSTALL_PREFIX="${D}" MANDIR="${mandir}" install
+
+ oe_libinstall -so libcrypto ${D}${libdir}
+ oe_libinstall -so libssl ${D}${libdir}
+
+ # Moving libcrypto to /lib
+ if [ ! ${D}${libdir} -ef ${D}${base_libdir} ]; then
+ mkdir -p ${D}/${base_libdir}/
+ mv ${D}${libdir}/libcrypto* ${D}${base_libdir}/
+ sed -i s#libdir=\$\{exec_prefix\}\/lib#libdir=${base_libdir}# ${D}/${libdir}/pkgconfig/libcrypto.pc
+ fi
+
+ install -d ${D}${includedir}
+ cp --dereference -R include/openssl ${D}${includedir}
+
+ oe_multilib_header openssl/opensslconf.h
+ if [ "${@base_contains('PACKAGECONFIG', 'perl', 'perl', '', d)}" = "perl" ]; then
+ install -m 0755 ${S}/tools/c_rehash ${D}${bindir}
+ sed -i -e '1s,.*,#!${bindir}/env perl,' ${D}${bindir}/c_rehash
+ sed -i -e '1s,.*,#!${bindir}/env perl,' ${D}${libdir}/ssl/misc/CA.pl
+ sed -i -e '1s,.*,#!${bindir}/env perl,' ${D}${libdir}/ssl/misc/tsget
+ # The c_rehash utility isn't installed by the normal installation process.
+ else
+ rm -f ${D}${bindir}/c_rehash
+ rm -f ${D}${libdir}/ssl/misc/CA.pl ${D}${libdir}/ssl/misc/tsget
+ fi
+}
+
+BBCLASSEXTEND = "native nativesdk"
+
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/configure-targets.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/configure-targets.patch
new file mode 100644
index 0000000..c1f3d08
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/configure-targets.patch
@@ -0,0 +1,34 @@
+Upstream-Status: Inappropriate [embedded specific]
+
+The number of colons are important :)
+
+
+---
+ Configure | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+--- a/Configure
++++ b/Configure
+@@ -403,6 +403,22 @@ my %table=(
+ "linux-alpha-ccc","ccc:-fast -readonly_strings -DL_ENDIAN -DTERMIO::-D_REENTRANT:::SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_PTR DES_RISC1 DES_UNROLL:${alpha_asm}",
+ "linux-alpha+bwx-ccc","ccc:-fast -readonly_strings -DL_ENDIAN -DTERMIO::-D_REENTRANT:::SIXTY_FOUR_BIT_LONG RC4_CHAR RC4_CHUNK DES_INT DES_PTR DES_RISC1 DES_UNROLL:${alpha_asm}",
+
++ # Linux on ARM
++"linux-elf-arm","$ENV{'CC'}:-DL_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG DES_RISC1:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"linux-elf-armeb","$ENV{'CC'}:-DB_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG DES_RISC1:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"linux-gnueabi-arm","$ENV{'CC'}:-DL_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG DES_RISC1:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"linux-gnueabi-armeb","$ENV{'CC'}:-DB_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG DES_RISC1:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"linux-uclibceabi-arm","$ENV{'CC'}:-DL_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG DES_RISC1:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"linux-uclibceabi-armeb","$ENV{'CC'}:-DB_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG DES_RISC1:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++
++"linux-avr32","$ENV{'CC'}:-DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG DES_RISC1:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).",
++
++#### Linux on MIPS/MIPS64
++"linux-mips","$ENV{'CC'}:-DB_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC2_CHAR RC4_INDEX DES_INT DES_UNROLL DES_RISC2:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"linux-mips64","$ENV{'CC'}:-DB_ENDIAN -DTERMIO -mabi=64 -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC2_CHAR RC4_INDEX DES_INT DES_UNROLL DES_RISC2:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"linux-mips64el","$ENV{'CC'}:-DL_ENDIAN -DTERMIO -mabi=64 -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC2_CHAR RC4_INDEX DES_INT DES_UNROLL DES_RISC2:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"linux-mipsel","$ENV{'CC'}:-DL_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC2_CHAR RC4_INDEX DES_INT DES_UNROLL DES_RISC2:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++
+ # Android: linux-* but without -DTERMIO and pointers to headers and libs.
+ "android","gcc:-mandroid -I\$(ANDROID_DEV)/include -B\$(ANDROID_DEV)/lib -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
+ "android-x86","gcc:-mandroid -I\$(ANDROID_DEV)/include -B\$(ANDROID_DEV)/lib -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:".eval{my $asm=${x86_elf_asm};$asm=~s/:elf/:android/;$asm}.":dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/c_rehash-compat.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/c_rehash-compat.patch
new file mode 100644
index 0000000..ac1b19b
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/c_rehash-compat.patch
@@ -0,0 +1,45 @@
+Upstream-Status: Backport [debian]
+
+From 83f318d68bbdab1ca898c94576a838cc97df4700 Mon Sep 17 00:00:00 2001
+From: Ludwig Nussel <ludwig.nussel@suse.de>
+Date: Wed, 21 Apr 2010 15:52:10 +0200
+Subject: [PATCH] also create old hash for compatibility
+
+---
+ tools/c_rehash.in | 8 +++++++-
+ 1 files changed, 7 insertions(+), 1 deletions(-)
+
+Index: openssl-1.0.0d/tools/c_rehash.in
+===================================================================
+--- openssl-1.0.0d.orig/tools/c_rehash.in 2011-04-13 20:41:28.000000000 +0000
++++ openssl-1.0.0d/tools/c_rehash.in 2011-04-13 20:41:28.000000000 +0000
+@@ -86,6 +86,7 @@
+ }
+ }
+ link_hash_cert($fname) if($cert);
++ link_hash_cert_old($fname) if($cert);
+ link_hash_crl($fname) if($crl);
+ }
+ }
+@@ -119,8 +120,9 @@
+
+ sub link_hash_cert {
+ my $fname = $_[0];
++ my $hashopt = $_[1] || '-subject_hash';
+ $fname =~ s/'/'\\''/g;
+- my ($hash, $fprint) = `"$openssl" x509 -hash -fingerprint -noout -in "$fname"`;
++ my ($hash, $fprint) = `"$openssl" x509 $hashopt -fingerprint -noout -in "$fname"`;
+ chomp $hash;
+ chomp $fprint;
+ $fprint =~ s/^.*=//;
+@@ -150,6 +152,10 @@
+ $hashlist{$hash} = $fprint;
+ }
+
++sub link_hash_cert_old {
++ link_hash_cert($_[0], '-subject_hash_old');
++}
++
+ # Same as above except for a CRL. CRL links are of the form <hash>.r<n>
+
+ sub link_hash_crl {
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/ca.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/ca.patch
new file mode 100644
index 0000000..aba4d42
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/ca.patch
@@ -0,0 +1,22 @@
+Upstream-Status: Backport [debian]
+
+Index: openssl-0.9.8m/apps/CA.pl.in
+===================================================================
+--- openssl-0.9.8m.orig/apps/CA.pl.in 2006-04-28 00:28:51.000000000 +0000
++++ openssl-0.9.8m/apps/CA.pl.in 2010-02-27 00:36:51.000000000 +0000
+@@ -65,6 +65,7 @@
+ foreach (@ARGV) {
+ if ( /^(-\?|-h|-help)$/ ) {
+ print STDERR "usage: CA -newcert|-newreq|-newreq-nodes|-newca|-sign|-verify\n";
++ print STDERR "usage: CA -signcert certfile keyfile|-newcert|-newreq|-newca|-sign|-verify\n";
+ exit 0;
+ } elsif (/^-newcert$/) {
+ # create a certificate
+@@ -165,6 +166,7 @@
+ } else {
+ print STDERR "Unknown arg $_\n";
+ print STDERR "usage: CA -newcert|-newreq|-newreq-nodes|-newca|-sign|-verify\n";
++ print STDERR "usage: CA -signcert certfile keyfile|-newcert|-newreq|-newca|-sign|-verify\n";
+ exit 1;
+ }
+ }
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/debian-targets.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/debian-targets.patch
new file mode 100644
index 0000000..8101edf
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/debian-targets.patch
@@ -0,0 +1,66 @@
+Upstream-Status: Backport [debian]
+
+Index: openssl-1.0.1/Configure
+===================================================================
+--- openssl-1.0.1.orig/Configure 2012-03-17 15:37:54.000000000 +0000
++++ openssl-1.0.1/Configure 2012-03-17 16:13:49.000000000 +0000
+@@ -105,6 +105,10 @@
+
+ my $gcc_devteam_warn = "-Wall -pedantic -DPEDANTIC -Wno-long-long -Wsign-compare -Wmissing-prototypes -Wshadow -Wformat -Werror -DCRYPTO_MDEBUG_ALL -DCRYPTO_MDEBUG_ABORT -DREF_CHECK -DOPENSSL_NO_DEPRECATED";
+
++# There are no separate CFLAGS/CPPFLAGS/LDFLAGS, set everything in CFLAGS
++my $debian_cflags = `dpkg-buildflags --get CFLAGS` . `dpkg-buildflags --get CPPFLAGS` . `dpkg-buildflags --get LDFLAGS` . "-Wa,--noexecstack -Wall";
++$debian_cflags =~ s/\n/ /g;
++
+ my $strict_warnings = 0;
+
+ my $x86_gcc_des="DES_PTR DES_RISC1 DES_UNROLL";
+@@ -338,6 +342,48 @@
+ "osf1-alpha-cc", "cc:-std1 -tune host -O4 -readonly_strings::(unknown):::SIXTY_FOUR_BIT_LONG RC4_CHUNK:${alpha_asm}:dlfcn:alpha-osf1-shared:::.so",
+ "tru64-alpha-cc", "cc:-std1 -tune host -fast -readonly_strings::-pthread:::SIXTY_FOUR_BIT_LONG RC4_CHUNK:${alpha_asm}:dlfcn:alpha-osf1-shared::-msym:.so",
+
++# Debian GNU/* (various architectures)
++"debian-alpha","gcc:-DTERMIO ${debian_cflags}::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_RISC1 DES_UNROLL:${alpha_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-alpha-ev4","gcc:-DTERMIO ${debian_cflags} -mcpu=ev4::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_RISC1 DES_UNROLL:${alpha_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-alpha-ev5","gcc:-DTERMIO ${debian_cflags} -mcpu=ev5::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_RISC1 DES_UNROLL:${alpha_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-armeb","gcc:-DB_ENDIAN -DTERMIO ${debian_cflags}::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-armel","gcc:-DL_ENDIAN -DTERMIO ${debian_cflags}::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-armhf","gcc:-DL_ENDIAN -DTERMIO ${debian_cflags}::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-amd64", "gcc:-m64 -DL_ENDIAN -DTERMIO ${debian_cflags} -DMD32_REG_T=int::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_UNROLL:${x86_64_asm}:elf:dlfcn:linux-shared:-fPIC:-m64:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR):::",
++"debian-avr32", "gcc:-DB_ENDIAN -DTERMIO ${debian_cflags} -fomit-frame-pointer::-D_REENTRANT::-ldl:BN_LLONG_BF_PTR:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-kfreebsd-amd64","gcc:-m64 -DL_ENDIAN -DTERMIOS ${debian_cflags} -DMD32_REG_T=int::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_UNROLL:${x86_64_asm}:elf:dlfcn:linux-shared:-fPIC:-m64:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-kfreebsd-i386","gcc:-DL_ENDIAN -DTERMIOS ${debian_cflags} -march=i486::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-hppa","gcc:-DB_ENDIAN -DTERMIO ${debian_cflags}::-D_REENTRANT::-ldl:BN_LLONG MD2_CHAR RC4_INDEX:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-hurd-i386","gcc:-DL_ENDIAN -DTERMIOS -O3 -Wa,--noexecstack -g -mtune=i486 -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-ia64","gcc:-DTERMIO ${debian_cflags}::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_UNROLL DES_INT:${ia64_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-i386","gcc:-DL_ENDIAN -DTERMIO ${debian_cflags}::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-i386-i486","gcc:-DL_ENDIAN -DTERMIO ${debian_cflags} -march=i486::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-i386-i586","gcc:-DL_ENDIAN -DTERMIO ${debian_cflags} -march=i586::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-i386-i686/cmov","gcc:-DL_ENDIAN -DTERMIO ${debian_cflags} -march=i686::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-m68k","gcc:-DB_ENDIAN -DTERMIO ${debian_cflags}::-D_REENTRANT::-ldl:BN_LLONG MD2_CHAR RC4_INDEX:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-mips", "gcc:-DB_ENDIAN -DTERMIO ${debian_cflags}::-D_REENTRANT::-ldl:BN_LLONG RC2_CHAR RC4_INDEX DES_INT DES_UNROLL DES_RISC2:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-mipsel", "gcc:-DL_ENDIAN -DTERMIO ${debian_cflags}::-D_REENTRANT::-ldl:BN_LLONG RC2_CHAR RC4_INDEX DES_INT DES_UNROLL DES_RISC2:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-netbsd-i386", "gcc:-DL_ENDIAN -DTERMIOS ${debian_cflags} -m486::(unknown):::BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${no_asm}:dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-netbsd-m68k", "gcc:-DB_ENDIAN -DTERMIOS ${debian_cflags}::(unknown):::BN_LLONG MD2_CHAR RC4_INDEX DES_UNROLL:${no_asm}:dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-netbsd-sparc", "gcc:-DB_ENDIAN -DTERMIOS ${debian_cflags} -mv8::(unknown):::BN_LLONG MD2_CHAR RC4_INDEX DES_UNROLL:${no_asm}:dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-openbsd-alpha","gcc:-DTERMIOS ${debian_cflags}::(unknown):::SIXTY_FOUR_BIT_LONG DES_INT DES_PTR DES_RISC2:${no_asm}:dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-openbsd-i386", "gcc:-DL_ENDIAN -DTERMIOS ${debian_cflags} -m486::(unknown):::BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_asm}:a.out:dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-openbsd-mips","gcc:-DL_ENDIAN ${debian_cflags}::(unknown)::BN_LLONG MD2_CHAR RC4_INDEX RC4_CHAR DES_UNROLL DES_RISC2 DES_PTR BF_PTR:${no_asm}:dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-powerpc","gcc:-DB_ENDIAN -DTERMIO ${debian_cflags}::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_RISC1 DES_UNROLL:${ppc32_asm}:linux32:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-powerpcspe","gcc:-DB_ENDIAN -DTERMIO ${debian_cflags}::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_RISC1 DES_UNROLL:${ppc32_asm}:linux32:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-ppc64","gcc:-m64 -DB_ENDIAN -DTERMIO ${debian_cflags}::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHAR RC4_CHUNK DES_RISC1 DES_UNROLL:${ppc64_asm}:linux64:dlfcn:linux-shared:-fPIC:-m64:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-s390","gcc:-DB_ENDIAN -DTERMIO ${debian_cflags}::-D_REENTRANT::-ldl:RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-s390x","gcc:-DB_ENDIAN -DTERMIO ${debian_cflags}::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-sh3", "gcc:-DL_ENDIAN -DTERMIO ${debian_cflags}::-D_REENTRANT::-ldl:BN_LLONG:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-sh4", "gcc:-DL_ENDIAN -DTERMIO ${debian_cflags}::-D_REENTRANT::-ldl:BN_LLONG:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-sh3eb", "gcc:-DB_ENDIAN -DTERMIO ${debian_cflags}::-D_REENTRANT::-ldl:BN_LLONG:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-sh4eb", "gcc:-DB_ENDIAN -DTERMIO ${debian_cflags}::-D_REENTRANT::-ldl:BN_LLONG:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-m32r","gcc:-DB_ENDIAN -DTERMIO ${debian_cflags}::-D_REENTRANT::-ldl:BN_LLONG:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-sparc","gcc:-DB_ENDIAN -DTERMIO ${debian_cflags}::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:${sparcv9_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-sparc-v8","gcc:-DB_ENDIAN -DTERMIO ${debian_cflags} -mcpu=v8 -DBN_DIV2W::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:${sparcv8_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-sparc-v9","gcc:-DB_ENDIAN -DTERMIO ${debian_cflags} -mcpu=v9 -Wa,-Av8plus -DULTRASPARC -DBN_DIV2W::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:${sparcv9_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++"debian-sparc64","gcc:-m64 -DB_ENDIAN -DTERMIO ${debian_cflags} -DULTRASPARC -DBN_DIV2W::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_PTR DES_RISC1 DES_UNROLL BF_PTR:${sparcv9_asm}:dlfcn:linux-shared:-fPIC:-m64:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
++
+ ####
+ #### Variety of LINUX:-)
+ ####
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/make-targets.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/make-targets.patch
new file mode 100644
index 0000000..ee0a62c
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/make-targets.patch
@@ -0,0 +1,15 @@
+Upstream-Status: Backport [debian]
+
+Index: openssl-1.0.1/Makefile.org
+===================================================================
+--- openssl-1.0.1.orig/Makefile.org 2012-03-17 09:41:07.000000000 +0000
++++ openssl-1.0.1/Makefile.org 2012-03-17 09:41:21.000000000 +0000
+@@ -135,7 +135,7 @@
+
+ BASEADDR=
+
+-DIRS= crypto ssl engines apps test tools
++DIRS= crypto ssl engines apps tools
+ ENGDIRS= ccgost
+ SHLIBDIRS= crypto ssl
+
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/man-dir.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/man-dir.patch
new file mode 100644
index 0000000..4085e3b
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/man-dir.patch
@@ -0,0 +1,15 @@
+Upstream-Status: Backport [debian]
+
+Index: openssl-1.0.0c/Makefile.org
+===================================================================
+--- openssl-1.0.0c.orig/Makefile.org 2010-12-12 16:11:27.000000000 +0100
++++ openssl-1.0.0c/Makefile.org 2010-12-12 16:11:37.000000000 +0100
+@@ -131,7 +131,7 @@
+
+ MAKEFILE= Makefile
+
+-MANDIR=$(OPENSSLDIR)/man
++MANDIR=/usr/share/man
+ MAN1=1
+ MAN3=3
+ MANSUFFIX=
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/man-section.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/man-section.patch
new file mode 100644
index 0000000..21c1d1a
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/man-section.patch
@@ -0,0 +1,34 @@
+Upstream-Status: Backport [debian]
+
+Index: openssl-1.0.0c/Makefile.org
+===================================================================
+--- openssl-1.0.0c.orig/Makefile.org 2010-12-12 16:11:37.000000000 +0100
++++ openssl-1.0.0c/Makefile.org 2010-12-12 16:13:28.000000000 +0100
+@@ -160,7 +160,8 @@
+ MANDIR=/usr/share/man
+ MAN1=1
+ MAN3=3
+-MANSUFFIX=
++MANSUFFIX=ssl
++MANSECTION=SSL
+ HTMLSUFFIX=html
+ HTMLDIR=$(OPENSSLDIR)/html
+ SHELL=/bin/sh
+@@ -651,7 +652,7 @@
+ echo "installing man$$sec/$$fn.$${sec}$(MANSUFFIX)"; \
+ (cd `$(PERL) util/dirname.pl $$i`; \
+ sh -c "$$pod2man \
+- --section=$$sec --center=OpenSSL \
++ --section=$${sec}$(MANSECTION) --center=OpenSSL \
+ --release=$(VERSION) `basename $$i`") \
+ > $(INSTALL_PREFIX)$(MANDIR)/man$$sec/$$fn.$${sec}$(MANSUFFIX); \
+ $(PERL) util/extract-names.pl < $$i | \
+@@ -668,7 +669,7 @@
+ echo "installing man$$sec/$$fn.$${sec}$(MANSUFFIX)"; \
+ (cd `$(PERL) util/dirname.pl $$i`; \
+ sh -c "$$pod2man \
+- --section=$$sec --center=OpenSSL \
++ --section=$${sec}$(MANSECTION) --center=OpenSSL \
+ --release=$(VERSION) `basename $$i`") \
+ > $(INSTALL_PREFIX)$(MANDIR)/man$$sec/$$fn.$${sec}$(MANSUFFIX); \
+ $(PERL) util/extract-names.pl < $$i | \
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/no-rpath.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/no-rpath.patch
new file mode 100644
index 0000000..1ccb3b8
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/no-rpath.patch
@@ -0,0 +1,15 @@
+Upstream-Status: Backport [debian]
+
+Index: openssl-1.0.0c/Makefile.shared
+===================================================================
+--- openssl-1.0.0c.orig/Makefile.shared 2010-08-21 13:36:49.000000000 +0200
++++ openssl-1.0.0c/Makefile.shared 2010-12-12 16:13:36.000000000 +0100
+@@ -153,7 +153,7 @@
+ NOALLSYMSFLAGS='-Wl,--no-whole-archive'; \
+ SHAREDFLAGS="$(CFLAGS) $(SHARED_LDFLAGS) -shared -Wl,-Bsymbolic -Wl,-soname=$$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX"
+
+-DO_GNU_APP=LDFLAGS="$(CFLAGS) -Wl,-rpath,$(LIBRPATH)"
++DO_GNU_APP=LDFLAGS="$(CFLAGS)"
+
+ #This is rather special. It's a special target with which one can link
+ #applications without bothering with any features that have anything to
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/no-symbolic.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/no-symbolic.patch
new file mode 100644
index 0000000..cc4408a
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/no-symbolic.patch
@@ -0,0 +1,15 @@
+Upstream-Status: Backport [debian]
+
+Index: openssl-1.0.0c/Makefile.shared
+===================================================================
+--- openssl-1.0.0c.orig/Makefile.shared 2010-12-12 16:13:36.000000000 +0100
++++ openssl-1.0.0c/Makefile.shared 2010-12-12 16:13:44.000000000 +0100
+@@ -151,7 +151,7 @@
+ SHLIB_SUFFIX=; \
+ ALLSYMSFLAGS='-Wl,--whole-archive'; \
+ NOALLSYMSFLAGS='-Wl,--no-whole-archive'; \
+- SHAREDFLAGS="$(CFLAGS) $(SHARED_LDFLAGS) -shared -Wl,-Bsymbolic -Wl,-soname=$$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX"
++ SHAREDFLAGS="$(CFLAGS) $(SHARED_LDFLAGS) -shared -Wl,-soname=$$SHLIB$$SHLIB_SOVER$$SHLIB_SUFFIX"
+
+ DO_GNU_APP=LDFLAGS="$(CFLAGS)"
+
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/pic.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/pic.patch
new file mode 100644
index 0000000..bfda388
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/pic.patch
@@ -0,0 +1,177 @@
+Upstream-Status: Backport [debian]
+
+Index: openssl-1.0.1c/crypto/des/asm/desboth.pl
+===================================================================
+--- openssl-1.0.1c.orig/crypto/des/asm/desboth.pl 2001-10-24 23:20:56.000000000 +0200
++++ openssl-1.0.1c/crypto/des/asm/desboth.pl 2012-07-29 14:15:26.000000000 +0200
+@@ -16,6 +16,11 @@
+
+ &push("edi");
+
++ &call (&label("pic_point0"));
++ &set_label("pic_point0");
++ &blindpop("ebp");
++ &add ("ebp", "\$_GLOBAL_OFFSET_TABLE_+[.-" . &label("pic_point0") . "]");
++
+ &comment("");
+ &comment("Load the data words");
+ &mov($L,&DWP(0,"ebx","",0));
+@@ -47,15 +52,21 @@
+ &mov(&swtmp(2), (DWC(($enc)?"1":"0")));
+ &mov(&swtmp(1), "eax");
+ &mov(&swtmp(0), "ebx");
+- &call("DES_encrypt2");
++ &exch("ebx", "ebp");
++ &call("DES_encrypt2\@PLT");
++ &exch("ebx", "ebp");
+ &mov(&swtmp(2), (DWC(($enc)?"0":"1")));
+ &mov(&swtmp(1), "edi");
+ &mov(&swtmp(0), "ebx");
+- &call("DES_encrypt2");
++ &exch("ebx", "ebp");
++ &call("DES_encrypt2\@PLT");
++ &exch("ebx", "ebp");
+ &mov(&swtmp(2), (DWC(($enc)?"1":"0")));
+ &mov(&swtmp(1), "esi");
+ &mov(&swtmp(0), "ebx");
+- &call("DES_encrypt2");
++ &exch("ebx", "ebp");
++ &call("DES_encrypt2\@PLT");
++ &exch("ebx", "ebp");
+
+ &stack_pop(3);
+ &mov($L,&DWP(0,"ebx","",0));
+Index: openssl-1.0.1c/crypto/perlasm/cbc.pl
+===================================================================
+--- openssl-1.0.1c.orig/crypto/perlasm/cbc.pl 2011-07-13 08:22:46.000000000 +0200
++++ openssl-1.0.1c/crypto/perlasm/cbc.pl 2012-07-29 14:15:26.000000000 +0200
+@@ -122,7 +122,11 @@
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put in array for call
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+- &call($enc_func);
++ &call (&label("pic_point0"));
++ &set_label("pic_point0");
++ &blindpop("ebx");
++ &add ("ebx", "\$_GLOBAL_OFFSET_TABLE_+[.-" . &label("pic_point0") . "]");
++ &call("$enc_func\@PLT");
+
+ &mov("eax", &DWP($data_off,"esp","",0));
+ &mov("ebx", &DWP($data_off+4,"esp","",0));
+@@ -185,7 +189,11 @@
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put in array for call
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+- &call($enc_func);
++ &call (&label("pic_point1"));
++ &set_label("pic_point1");
++ &blindpop("ebx");
++ &add ("ebx", "\$_GLOBAL_OFFSET_TABLE_+[.-" . &label("pic_point1") . "]");
++ &call("$enc_func\@PLT");
+
+ &mov("eax", &DWP($data_off,"esp","",0));
+ &mov("ebx", &DWP($data_off+4,"esp","",0));
+@@ -218,7 +226,11 @@
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put back
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+- &call($dec_func);
++ &call (&label("pic_point2"));
++ &set_label("pic_point2");
++ &blindpop("ebx");
++ &add ("ebx", "\$_GLOBAL_OFFSET_TABLE_+[.-" . &label("pic_point2") . "]");
++ &call("$dec_func\@PLT");
+
+ &mov("eax", &DWP($data_off,"esp","",0)); # get return
+ &mov("ebx", &DWP($data_off+4,"esp","",0)); #
+@@ -261,7 +273,11 @@
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put back
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+- &call($dec_func);
++ &call (&label("pic_point3"));
++ &set_label("pic_point3");
++ &blindpop("ebx");
++ &add ("ebx", "\$_GLOBAL_OFFSET_TABLE_+[.-" . &label("pic_point3") . "]");
++ &call("$dec_func\@PLT");
+
+ &mov("eax", &DWP($data_off,"esp","",0)); # get return
+ &mov("ebx", &DWP($data_off+4,"esp","",0)); #
+Index: openssl-1.0.1c/crypto/perlasm/x86gas.pl
+===================================================================
+--- openssl-1.0.1c.orig/crypto/perlasm/x86gas.pl 2011-12-09 20:16:35.000000000 +0100
++++ openssl-1.0.1c/crypto/perlasm/x86gas.pl 2012-07-29 14:15:26.000000000 +0200
+@@ -161,6 +161,7 @@
+ if ($::macosx) { push (@out,"$tmp,2\n"); }
+ elsif ($::elf) { push (@out,"$tmp,4\n"); }
+ else { push (@out,"$tmp\n"); }
++ if ($::elf) { push (@out,".hidden\tOPENSSL_ia32cap_P\n"); }
+ }
+ push(@out,$initseg) if ($initseg);
+ }
+@@ -218,8 +219,23 @@
+ elsif ($::elf)
+ { $initseg.=<<___;
+ .section .init
++___
++ if ($::pic)
++ { $initseg.=<<___;
++ pushl %ebx
++ call .pic_point0
++.pic_point0:
++ popl %ebx
++ addl \$_GLOBAL_OFFSET_TABLE_+[.-.pic_point0],%ebx
++ call $f\@PLT
++ popl %ebx
++___
++ }
++ else
++ { $initseg.=<<___;
+ call $f
+ ___
++ }
+ }
+ elsif ($::coff)
+ { $initseg.=<<___; # applies to both Cygwin and Mingw
+Index: openssl-1.0.1c/crypto/x86cpuid.pl
+===================================================================
+--- openssl-1.0.1c.orig/crypto/x86cpuid.pl 2012-02-28 15:20:34.000000000 +0100
++++ openssl-1.0.1c/crypto/x86cpuid.pl 2012-07-29 14:15:26.000000000 +0200
+@@ -8,6 +8,8 @@
+
+ for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); }
+
++push(@out, ".hidden OPENSSL_ia32cap_P\n");
++
+ &function_begin("OPENSSL_ia32_cpuid");
+ &xor ("edx","edx");
+ &pushf ();
+@@ -139,9 +141,7 @@
+ &set_label("nocpuid");
+ &function_end("OPENSSL_ia32_cpuid");
+
+-&external_label("OPENSSL_ia32cap_P");
+-
+-&function_begin_B("OPENSSL_rdtsc","EXTRN\t_OPENSSL_ia32cap_P:DWORD");
++&function_begin_B("OPENSSL_rdtsc");
+ &xor ("eax","eax");
+ &xor ("edx","edx");
+ &picmeup("ecx","OPENSSL_ia32cap_P");
+@@ -155,7 +155,7 @@
+ # This works in Ring 0 only [read DJGPP+MS-DOS+privileged DPMI host],
+ # but it's safe to call it on any [supported] 32-bit platform...
+ # Just check for [non-]zero return value...
+-&function_begin_B("OPENSSL_instrument_halt","EXTRN\t_OPENSSL_ia32cap_P:DWORD");
++&function_begin_B("OPENSSL_instrument_halt");
+ &picmeup("ecx","OPENSSL_ia32cap_P");
+ &bt (&DWP(0,"ecx"),4);
+ &jnc (&label("nohalt")); # no TSC
+@@ -222,7 +222,7 @@
+ &ret ();
+ &function_end_B("OPENSSL_far_spin");
+
+-&function_begin_B("OPENSSL_wipe_cpu","EXTRN\t_OPENSSL_ia32cap_P:DWORD");
++&function_begin_B("OPENSSL_wipe_cpu");
+ &xor ("eax","eax");
+ &xor ("edx","edx");
+ &picmeup("ecx","OPENSSL_ia32cap_P");
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/version-script.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/version-script.patch
new file mode 100644
index 0000000..ece8b9b
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/debian/version-script.patch
@@ -0,0 +1,4670 @@
+Upstream-Status: Backport [debian]
+
+Index: openssl-1.0.1d/Configure
+===================================================================
+--- openssl-1.0.1d.orig/Configure 2013-02-06 19:41:43.000000000 +0100
++++ openssl-1.0.1d/Configure 2013-02-06 19:41:43.000000000 +0100
+@@ -1621,6 +1621,8 @@
+ }
+ }
+
++$shared_ldflag .= " -Wl,--version-script=openssl.ld";
++
+ open(IN,'<Makefile.org') || die "unable to read Makefile.org:$!\n";
+ unlink("$Makefile.new") || die "unable to remove old $Makefile.new:$!\n" if -e "$Makefile.new";
+ open(OUT,">$Makefile.new") || die "unable to create $Makefile.new:$!\n";
+Index: openssl-1.0.1d/openssl.ld
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ openssl-1.0.1d/openssl.ld 2013-02-06 19:44:25.000000000 +0100
+@@ -0,0 +1,4620 @@
++OPENSSL_1.0.0 {
++ global:
++ BIO_f_ssl;
++ BIO_new_buffer_ssl_connect;
++ BIO_new_ssl;
++ BIO_new_ssl_connect;
++ BIO_proxy_ssl_copy_session_id;
++ BIO_ssl_copy_session_id;
++ BIO_ssl_shutdown;
++ d2i_SSL_SESSION;
++ DTLSv1_client_method;
++ DTLSv1_method;
++ DTLSv1_server_method;
++ ERR_load_SSL_strings;
++ i2d_SSL_SESSION;
++ kssl_build_principal_2;
++ kssl_cget_tkt;
++ kssl_check_authent;
++ kssl_ctx_free;
++ kssl_ctx_new;
++ kssl_ctx_setkey;
++ kssl_ctx_setprinc;
++ kssl_ctx_setstring;
++ kssl_ctx_show;
++ kssl_err_set;
++ kssl_krb5_free_data_contents;
++ kssl_sget_tkt;
++ kssl_skip_confound;
++ kssl_validate_times;
++ PEM_read_bio_SSL_SESSION;
++ PEM_read_SSL_SESSION;
++ PEM_write_bio_SSL_SESSION;
++ PEM_write_SSL_SESSION;
++ SSL_accept;
++ SSL_add_client_CA;
++ SSL_add_dir_cert_subjects_to_stack;
++ SSL_add_dir_cert_subjs_to_stk;
++ SSL_add_file_cert_subjects_to_stack;
++ SSL_add_file_cert_subjs_to_stk;
++ SSL_alert_desc_string;
++ SSL_alert_desc_string_long;
++ SSL_alert_type_string;
++ SSL_alert_type_string_long;
++ SSL_callback_ctrl;
++ SSL_check_private_key;
++ SSL_CIPHER_description;
++ SSL_CIPHER_get_bits;
++ SSL_CIPHER_get_name;
++ SSL_CIPHER_get_version;
++ SSL_clear;
++ SSL_COMP_add_compression_method;
++ SSL_COMP_get_compression_methods;
++ SSL_COMP_get_compress_methods;
++ SSL_COMP_get_name;
++ SSL_connect;
++ SSL_copy_session_id;
++ SSL_ctrl;
++ SSL_CTX_add_client_CA;
++ SSL_CTX_add_session;
++ SSL_CTX_callback_ctrl;
++ SSL_CTX_check_private_key;
++ SSL_CTX_ctrl;
++ SSL_CTX_flush_sessions;
++ SSL_CTX_free;
++ SSL_CTX_get_cert_store;
++ SSL_CTX_get_client_CA_list;
++ SSL_CTX_get_client_cert_cb;
++ SSL_CTX_get_ex_data;
++ SSL_CTX_get_ex_new_index;
++ SSL_CTX_get_info_callback;
++ SSL_CTX_get_quiet_shutdown;
++ SSL_CTX_get_timeout;
++ SSL_CTX_get_verify_callback;
++ SSL_CTX_get_verify_depth;
++ SSL_CTX_get_verify_mode;
++ SSL_CTX_load_verify_locations;
++ SSL_CTX_new;
++ SSL_CTX_remove_session;
++ SSL_CTX_sess_get_get_cb;
++ SSL_CTX_sess_get_new_cb;
++ SSL_CTX_sess_get_remove_cb;
++ SSL_CTX_sessions;
++ SSL_CTX_sess_set_get_cb;
++ SSL_CTX_sess_set_new_cb;
++ SSL_CTX_sess_set_remove_cb;
++ SSL_CTX_set1_param;
++ SSL_CTX_set_cert_store;
++ SSL_CTX_set_cert_verify_callback;
++ SSL_CTX_set_cert_verify_cb;
++ SSL_CTX_set_cipher_list;
++ SSL_CTX_set_client_CA_list;
++ SSL_CTX_set_client_cert_cb;
++ SSL_CTX_set_client_cert_engine;
++ SSL_CTX_set_cookie_generate_cb;
++ SSL_CTX_set_cookie_verify_cb;
++ SSL_CTX_set_default_passwd_cb;
++ SSL_CTX_set_default_passwd_cb_userdata;
++ SSL_CTX_set_default_verify_paths;
++ SSL_CTX_set_def_passwd_cb_ud;
++ SSL_CTX_set_def_verify_paths;
++ SSL_CTX_set_ex_data;
++ SSL_CTX_set_generate_session_id;
++ SSL_CTX_set_info_callback;
++ SSL_CTX_set_msg_callback;
++ SSL_CTX_set_psk_client_callback;
++ SSL_CTX_set_psk_server_callback;
++ SSL_CTX_set_purpose;
++ SSL_CTX_set_quiet_shutdown;
++ SSL_CTX_set_session_id_context;
++ SSL_CTX_set_ssl_version;
++ SSL_CTX_set_timeout;
++ SSL_CTX_set_tmp_dh_callback;
++ SSL_CTX_set_tmp_ecdh_callback;
++ SSL_CTX_set_tmp_rsa_callback;
++ SSL_CTX_set_trust;
++ SSL_CTX_set_verify;
++ SSL_CTX_set_verify_depth;
++ SSL_CTX_use_cert_chain_file;
++ SSL_CTX_use_certificate;
++ SSL_CTX_use_certificate_ASN1;
++ SSL_CTX_use_certificate_chain_file;
++ SSL_CTX_use_certificate_file;
++ SSL_CTX_use_PrivateKey;
++ SSL_CTX_use_PrivateKey_ASN1;
++ SSL_CTX_use_PrivateKey_file;
++ SSL_CTX_use_psk_identity_hint;
++ SSL_CTX_use_RSAPrivateKey;
++ SSL_CTX_use_RSAPrivateKey_ASN1;
++ SSL_CTX_use_RSAPrivateKey_file;
++ SSL_do_handshake;
++ SSL_dup;
++ SSL_dup_CA_list;
++ SSLeay_add_ssl_algorithms;
++ SSL_free;
++ SSL_get1_session;
++ SSL_get_certificate;
++ SSL_get_cipher_list;
++ SSL_get_ciphers;
++ SSL_get_client_CA_list;
++ SSL_get_current_cipher;
++ SSL_get_current_compression;
++ SSL_get_current_expansion;
++ SSL_get_default_timeout;
++ SSL_get_error;
++ SSL_get_ex_data;
++ SSL_get_ex_data_X509_STORE_CTX_idx;
++ SSL_get_ex_d_X509_STORE_CTX_idx;
++ SSL_get_ex_new_index;
++ SSL_get_fd;
++ SSL_get_finished;
++ SSL_get_info_callback;
++ SSL_get_peer_cert_chain;
++ SSL_get_peer_certificate;
++ SSL_get_peer_finished;
++ SSL_get_privatekey;
++ SSL_get_psk_identity;
++ SSL_get_psk_identity_hint;
++ SSL_get_quiet_shutdown;
++ SSL_get_rbio;
++ SSL_get_read_ahead;
++ SSL_get_rfd;
++ SSL_get_servername;
++ SSL_get_servername_type;
++ SSL_get_session;
++ SSL_get_shared_ciphers;
++ SSL_get_shutdown;
++ SSL_get_SSL_CTX;
++ SSL_get_ssl_method;
++ SSL_get_verify_callback;
++ SSL_get_verify_depth;
++ SSL_get_verify_mode;
++ SSL_get_verify_result;
++ SSL_get_version;
++ SSL_get_wbio;
++ SSL_get_wfd;
++ SSL_has_matching_session_id;
++ SSL_library_init;
++ SSL_load_client_CA_file;
++ SSL_load_error_strings;
++ SSL_new;
++ SSL_peek;
++ SSL_pending;
++ SSL_read;
++ SSL_renegotiate;
++ SSL_renegotiate_pending;
++ SSL_rstate_string;
++ SSL_rstate_string_long;
++ SSL_SESSION_cmp;
++ SSL_SESSION_free;
++ SSL_SESSION_get_ex_data;
++ SSL_SESSION_get_ex_new_index;
++ SSL_SESSION_get_id;
++ SSL_SESSION_get_time;
++ SSL_SESSION_get_timeout;
++ SSL_SESSION_hash;
++ SSL_SESSION_new;
++ SSL_SESSION_print;
++ SSL_SESSION_print_fp;
++ SSL_SESSION_set_ex_data;
++ SSL_SESSION_set_time;
++ SSL_SESSION_set_timeout;
++ SSL_set1_param;
++ SSL_set_accept_state;
++ SSL_set_bio;
++ SSL_set_cipher_list;
++ SSL_set_client_CA_list;
++ SSL_set_connect_state;
++ SSL_set_ex_data;
++ SSL_set_fd;
++ SSL_set_generate_session_id;
++ SSL_set_info_callback;
++ SSL_set_msg_callback;
++ SSL_set_psk_client_callback;
++ SSL_set_psk_server_callback;
++ SSL_set_purpose;
++ SSL_set_quiet_shutdown;
++ SSL_set_read_ahead;
++ SSL_set_rfd;
++ SSL_set_session;
++ SSL_set_session_id_context;
++ SSL_set_session_secret_cb;
++ SSL_set_session_ticket_ext;
++ SSL_set_session_ticket_ext_cb;
++ SSL_set_shutdown;
++ SSL_set_SSL_CTX;
++ SSL_set_ssl_method;
++ SSL_set_tmp_dh_callback;
++ SSL_set_tmp_ecdh_callback;
++ SSL_set_tmp_rsa_callback;
++ SSL_set_trust;
++ SSL_set_verify;
++ SSL_set_verify_depth;
++ SSL_set_verify_result;
++ SSL_set_wfd;
++ SSL_shutdown;
++ SSL_state;
++ SSL_state_string;
++ SSL_state_string_long;
++ SSL_use_certificate;
++ SSL_use_certificate_ASN1;
++ SSL_use_certificate_file;
++ SSL_use_PrivateKey;
++ SSL_use_PrivateKey_ASN1;
++ SSL_use_PrivateKey_file;
++ SSL_use_psk_identity_hint;
++ SSL_use_RSAPrivateKey;
++ SSL_use_RSAPrivateKey_ASN1;
++ SSL_use_RSAPrivateKey_file;
++ SSLv23_client_method;
++ SSLv23_method;
++ SSLv23_server_method;
++ SSLv2_client_method;
++ SSLv2_method;
++ SSLv2_server_method;
++ SSLv3_client_method;
++ SSLv3_method;
++ SSLv3_server_method;
++ SSL_version;
++ SSL_want;
++ SSL_write;
++ TLSv1_client_method;
++ TLSv1_method;
++ TLSv1_server_method;
++
++
++ SSLeay;
++ SSLeay_version;
++ ASN1_BIT_STRING_asn1_meth;
++ ASN1_HEADER_free;
++ ASN1_HEADER_new;
++ ASN1_IA5STRING_asn1_meth;
++ ASN1_INTEGER_get;
++ ASN1_INTEGER_set;
++ ASN1_INTEGER_to_BN;
++ ASN1_OBJECT_create;
++ ASN1_OBJECT_free;
++ ASN1_OBJECT_new;
++ ASN1_PRINTABLE_type;
++ ASN1_STRING_cmp;
++ ASN1_STRING_dup;
++ ASN1_STRING_free;
++ ASN1_STRING_new;
++ ASN1_STRING_print;
++ ASN1_STRING_set;
++ ASN1_STRING_type_new;
++ ASN1_TYPE_free;
++ ASN1_TYPE_new;
++ ASN1_UNIVERSALSTRING_to_string;
++ ASN1_UTCTIME_check;
++ ASN1_UTCTIME_print;
++ ASN1_UTCTIME_set;
++ ASN1_check_infinite_end;
++ ASN1_d2i_bio;
++ ASN1_d2i_fp;
++ ASN1_digest;
++ ASN1_dup;
++ ASN1_get_object;
++ ASN1_i2d_bio;
++ ASN1_i2d_fp;
++ ASN1_object_size;
++ ASN1_parse;
++ ASN1_put_object;
++ ASN1_sign;
++ ASN1_verify;
++ BF_cbc_encrypt;
++ BF_cfb64_encrypt;
++ BF_ecb_encrypt;
++ BF_encrypt;
++ BF_ofb64_encrypt;
++ BF_options;
++ BF_set_key;
++ BIO_CONNECT_free;
++ BIO_CONNECT_new;
++ BIO_accept;
++ BIO_ctrl;
++ BIO_int_ctrl;
++ BIO_debug_callback;
++ BIO_dump;
++ BIO_dup_chain;
++ BIO_f_base64;
++ BIO_f_buffer;
++ BIO_f_cipher;
++ BIO_f_md;
++ BIO_f_null;
++ BIO_f_proxy_server;
++ BIO_fd_non_fatal_error;
++ BIO_fd_should_retry;
++ BIO_find_type;
++ BIO_free;
++ BIO_free_all;
++ BIO_get_accept_socket;
++ BIO_get_filter_bio;
++ BIO_get_host_ip;
++ BIO_get_port;
++ BIO_get_retry_BIO;
++ BIO_get_retry_reason;
++ BIO_gethostbyname;
++ BIO_gets;
++ BIO_new;
++ BIO_new_accept;
++ BIO_new_connect;
++ BIO_new_fd;
++ BIO_new_file;
++ BIO_new_fp;
++ BIO_new_socket;
++ BIO_pop;
++ BIO_printf;
++ BIO_push;
++ BIO_puts;
++ BIO_read;
++ BIO_s_accept;
++ BIO_s_connect;
++ BIO_s_fd;
++ BIO_s_file;
++ BIO_s_mem;
++ BIO_s_null;
++ BIO_s_proxy_client;
++ BIO_s_socket;
++ BIO_set;
++ BIO_set_cipher;
++ BIO_set_tcp_ndelay;
++ BIO_sock_cleanup;
++ BIO_sock_error;
++ BIO_sock_init;
++ BIO_sock_non_fatal_error;
++ BIO_sock_should_retry;
++ BIO_socket_ioctl;
++ BIO_write;
++ BN_CTX_free;
++ BN_CTX_new;
++ BN_MONT_CTX_free;
++ BN_MONT_CTX_new;
++ BN_MONT_CTX_set;
++ BN_add;
++ BN_add_word;
++ BN_hex2bn;
++ BN_bin2bn;
++ BN_bn2hex;
++ BN_bn2bin;
++ BN_clear;
++ BN_clear_bit;
++ BN_clear_free;
++ BN_cmp;
++ BN_copy;
++ BN_div;
++ BN_div_word;
++ BN_dup;
++ BN_free;
++ BN_from_montgomery;
++ BN_gcd;
++ BN_generate_prime;
++ BN_get_word;
++ BN_is_bit_set;
++ BN_is_prime;
++ BN_lshift;
++ BN_lshift1;
++ BN_mask_bits;
++ BN_mod;
++ BN_mod_exp;
++ BN_mod_exp_mont;
++ BN_mod_exp_simple;
++ BN_mod_inverse;
++ BN_mod_mul;
++ BN_mod_mul_montgomery;
++ BN_mod_word;
++ BN_mul;
++ BN_new;
++ BN_num_bits;
++ BN_num_bits_word;
++ BN_options;
++ BN_print;
++ BN_print_fp;
++ BN_rand;
++ BN_reciprocal;
++ BN_rshift;
++ BN_rshift1;
++ BN_set_bit;
++ BN_set_word;
++ BN_sqr;
++ BN_sub;
++ BN_to_ASN1_INTEGER;
++ BN_ucmp;
++ BN_value_one;
++ BUF_MEM_free;
++ BUF_MEM_grow;
++ BUF_MEM_new;
++ BUF_strdup;
++ CONF_free;
++ CONF_get_number;
++ CONF_get_section;
++ CONF_get_string;
++ CONF_load;
++ CRYPTO_add_lock;
++ CRYPTO_dbg_free;
++ CRYPTO_dbg_malloc;
++ CRYPTO_dbg_realloc;
++ CRYPTO_dbg_remalloc;
++ CRYPTO_free;
++ CRYPTO_get_add_lock_callback;
++ CRYPTO_get_id_callback;
++ CRYPTO_get_lock_name;
++ CRYPTO_get_locking_callback;
++ CRYPTO_get_mem_functions;
++ CRYPTO_lock;
++ CRYPTO_malloc;
++ CRYPTO_mem_ctrl;
++ CRYPTO_mem_leaks;
++ CRYPTO_mem_leaks_cb;
++ CRYPTO_mem_leaks_fp;
++ CRYPTO_realloc;
++ CRYPTO_remalloc;
++ CRYPTO_set_add_lock_callback;
++ CRYPTO_set_id_callback;
++ CRYPTO_set_locking_callback;
++ CRYPTO_set_mem_functions;
++ CRYPTO_thread_id;
++ DH_check;
++ DH_compute_key;
++ DH_free;
++ DH_generate_key;
++ DH_generate_parameters;
++ DH_new;
++ DH_size;
++ DHparams_print;
++ DHparams_print_fp;
++ DSA_free;
++ DSA_generate_key;
++ DSA_generate_parameters;
++ DSA_is_prime;
++ DSA_new;
++ DSA_print;
++ DSA_print_fp;
++ DSA_sign;
++ DSA_sign_setup;
++ DSA_size;
++ DSA_verify;
++ DSAparams_print;
++ DSAparams_print_fp;
++ ERR_clear_error;
++ ERR_error_string;
++ ERR_free_strings;
++ ERR_func_error_string;
++ ERR_get_err_state_table;
++ ERR_get_error;
++ ERR_get_error_line;
++ ERR_get_state;
++ ERR_get_string_table;
++ ERR_lib_error_string;
++ ERR_load_ASN1_strings;
++ ERR_load_BIO_strings;
++ ERR_load_BN_strings;
++ ERR_load_BUF_strings;
++ ERR_load_CONF_strings;
++ ERR_load_DH_strings;
++ ERR_load_DSA_strings;
++ ERR_load_ERR_strings;
++ ERR_load_EVP_strings;
++ ERR_load_OBJ_strings;
++ ERR_load_PEM_strings;
++ ERR_load_PROXY_strings;
++ ERR_load_RSA_strings;
++ ERR_load_X509_strings;
++ ERR_load_crypto_strings;
++ ERR_load_strings;
++ ERR_peek_error;
++ ERR_peek_error_line;
++ ERR_print_errors;
++ ERR_print_errors_fp;
++ ERR_put_error;
++ ERR_reason_error_string;
++ ERR_remove_state;
++ EVP_BytesToKey;
++ EVP_CIPHER_CTX_cleanup;
++ EVP_CipherFinal;
++ EVP_CipherInit;
++ EVP_CipherUpdate;
++ EVP_DecodeBlock;
++ EVP_DecodeFinal;
++ EVP_DecodeInit;
++ EVP_DecodeUpdate;
++ EVP_DecryptFinal;
++ EVP_DecryptInit;
++ EVP_DecryptUpdate;
++ EVP_DigestFinal;
++ EVP_DigestInit;
++ EVP_DigestUpdate;
++ EVP_EncodeBlock;
++ EVP_EncodeFinal;
++ EVP_EncodeInit;
++ EVP_EncodeUpdate;
++ EVP_EncryptFinal;
++ EVP_EncryptInit;
++ EVP_EncryptUpdate;
++ EVP_OpenFinal;
++ EVP_OpenInit;
++ EVP_PKEY_assign;
++ EVP_PKEY_copy_parameters;
++ EVP_PKEY_free;
++ EVP_PKEY_missing_parameters;
++ EVP_PKEY_new;
++ EVP_PKEY_save_parameters;
++ EVP_PKEY_size;
++ EVP_PKEY_type;
++ EVP_SealFinal;
++ EVP_SealInit;
++ EVP_SignFinal;
++ EVP_VerifyFinal;
++ EVP_add_alias;
++ EVP_add_cipher;
++ EVP_add_digest;
++ EVP_bf_cbc;
++ EVP_bf_cfb64;
++ EVP_bf_ecb;
++ EVP_bf_ofb;
++ EVP_cleanup;
++ EVP_des_cbc;
++ EVP_des_cfb64;
++ EVP_des_ecb;
++ EVP_des_ede;
++ EVP_des_ede3;
++ EVP_des_ede3_cbc;
++ EVP_des_ede3_cfb64;
++ EVP_des_ede3_ofb;
++ EVP_des_ede_cbc;
++ EVP_des_ede_cfb64;
++ EVP_des_ede_ofb;
++ EVP_des_ofb;
++ EVP_desx_cbc;
++ EVP_dss;
++ EVP_dss1;
++ EVP_enc_null;
++ EVP_get_cipherbyname;
++ EVP_get_digestbyname;
++ EVP_get_pw_prompt;
++ EVP_idea_cbc;
++ EVP_idea_cfb64;
++ EVP_idea_ecb;
++ EVP_idea_ofb;
++ EVP_md2;
++ EVP_md5;
++ EVP_md_null;
++ EVP_rc2_cbc;
++ EVP_rc2_cfb64;
++ EVP_rc2_ecb;
++ EVP_rc2_ofb;
++ EVP_rc4;
++ EVP_read_pw_string;
++ EVP_set_pw_prompt;
++ EVP_sha;
++ EVP_sha1;
++ MD2;
++ MD2_Final;
++ MD2_Init;
++ MD2_Update;
++ MD2_options;
++ MD5;
++ MD5_Final;
++ MD5_Init;
++ MD5_Update;
++ MDC2;
++ MDC2_Final;
++ MDC2_Init;
++ MDC2_Update;
++ NETSCAPE_SPKAC_free;
++ NETSCAPE_SPKAC_new;
++ NETSCAPE_SPKI_free;
++ NETSCAPE_SPKI_new;
++ NETSCAPE_SPKI_sign;
++ NETSCAPE_SPKI_verify;
++ OBJ_add_object;
++ OBJ_bsearch;
++ OBJ_cleanup;
++ OBJ_cmp;
++ OBJ_create;
++ OBJ_dup;
++ OBJ_ln2nid;
++ OBJ_new_nid;
++ OBJ_nid2ln;
++ OBJ_nid2obj;
++ OBJ_nid2sn;
++ OBJ_obj2nid;
++ OBJ_sn2nid;
++ OBJ_txt2nid;
++ PEM_ASN1_read;
++ PEM_ASN1_read_bio;
++ PEM_ASN1_write;
++ PEM_ASN1_write_bio;
++ PEM_SealFinal;
++ PEM_SealInit;
++ PEM_SealUpdate;
++ PEM_SignFinal;
++ PEM_SignInit;
++ PEM_SignUpdate;
++ PEM_X509_INFO_read;
++ PEM_X509_INFO_read_bio;
++ PEM_X509_INFO_write_bio;
++ PEM_dek_info;
++ PEM_do_header;
++ PEM_get_EVP_CIPHER_INFO;
++ PEM_proc_type;
++ PEM_read;
++ PEM_read_DHparams;
++ PEM_read_DSAPrivateKey;
++ PEM_read_DSAparams;
++ PEM_read_PKCS7;
++ PEM_read_PrivateKey;
++ PEM_read_RSAPrivateKey;
++ PEM_read_X509;
++ PEM_read_X509_CRL;
++ PEM_read_X509_REQ;
++ PEM_read_bio;
++ PEM_read_bio_DHparams;
++ PEM_read_bio_DSAPrivateKey;
++ PEM_read_bio_DSAparams;
++ PEM_read_bio_PKCS7;
++ PEM_read_bio_PrivateKey;
++ PEM_read_bio_RSAPrivateKey;
++ PEM_read_bio_X509;
++ PEM_read_bio_X509_CRL;
++ PEM_read_bio_X509_REQ;
++ PEM_write;
++ PEM_write_DHparams;
++ PEM_write_DSAPrivateKey;
++ PEM_write_DSAparams;
++ PEM_write_PKCS7;
++ PEM_write_PrivateKey;
++ PEM_write_RSAPrivateKey;
++ PEM_write_X509;
++ PEM_write_X509_CRL;
++ PEM_write_X509_REQ;
++ PEM_write_bio;
++ PEM_write_bio_DHparams;
++ PEM_write_bio_DSAPrivateKey;
++ PEM_write_bio_DSAparams;
++ PEM_write_bio_PKCS7;
++ PEM_write_bio_PrivateKey;
++ PEM_write_bio_RSAPrivateKey;
++ PEM_write_bio_X509;
++ PEM_write_bio_X509_CRL;
++ PEM_write_bio_X509_REQ;
++ PKCS7_DIGEST_free;
++ PKCS7_DIGEST_new;
++ PKCS7_ENCRYPT_free;
++ PKCS7_ENCRYPT_new;
++ PKCS7_ENC_CONTENT_free;
++ PKCS7_ENC_CONTENT_new;
++ PKCS7_ENVELOPE_free;
++ PKCS7_ENVELOPE_new;
++ PKCS7_ISSUER_AND_SERIAL_digest;
++ PKCS7_ISSUER_AND_SERIAL_free;
++ PKCS7_ISSUER_AND_SERIAL_new;
++ PKCS7_RECIP_INFO_free;
++ PKCS7_RECIP_INFO_new;
++ PKCS7_SIGNED_free;
++ PKCS7_SIGNED_new;
++ PKCS7_SIGNER_INFO_free;
++ PKCS7_SIGNER_INFO_new;
++ PKCS7_SIGN_ENVELOPE_free;
++ PKCS7_SIGN_ENVELOPE_new;
++ PKCS7_dup;
++ PKCS7_free;
++ PKCS7_new;
++ PROXY_ENTRY_add_noproxy;
++ PROXY_ENTRY_clear_noproxy;
++ PROXY_ENTRY_free;
++ PROXY_ENTRY_get_noproxy;
++ PROXY_ENTRY_new;
++ PROXY_ENTRY_set_server;
++ PROXY_add_noproxy;
++ PROXY_add_server;
++ PROXY_check_by_host;
++ PROXY_check_url;
++ PROXY_clear_noproxy;
++ PROXY_free;
++ PROXY_get_noproxy;
++ PROXY_get_proxies;
++ PROXY_get_proxy_entry;
++ PROXY_load_conf;
++ PROXY_new;
++ PROXY_print;
++ RAND_bytes;
++ RAND_cleanup;
++ RAND_file_name;
++ RAND_load_file;
++ RAND_screen;
++ RAND_seed;
++ RAND_write_file;
++ RC2_cbc_encrypt;
++ RC2_cfb64_encrypt;
++ RC2_ecb_encrypt;
++ RC2_encrypt;
++ RC2_ofb64_encrypt;
++ RC2_set_key;
++ RC4;
++ RC4_options;
++ RC4_set_key;
++ RSAPrivateKey_asn1_meth;
++ RSAPrivateKey_dup;
++ RSAPublicKey_dup;
++ RSA_PKCS1_SSLeay;
++ RSA_free;
++ RSA_generate_key;
++ RSA_new;
++ RSA_new_method;
++ RSA_print;
++ RSA_print_fp;
++ RSA_private_decrypt;
++ RSA_private_encrypt;
++ RSA_public_decrypt;
++ RSA_public_encrypt;
++ RSA_set_default_method;
++ RSA_sign;
++ RSA_sign_ASN1_OCTET_STRING;
++ RSA_size;
++ RSA_verify;
++ RSA_verify_ASN1_OCTET_STRING;
++ SHA;
++ SHA1;
++ SHA1_Final;
++ SHA1_Init;
++ SHA1_Update;
++ SHA_Final;
++ SHA_Init;
++ SHA_Update;
++ OpenSSL_add_all_algorithms;
++ OpenSSL_add_all_ciphers;
++ OpenSSL_add_all_digests;
++ TXT_DB_create_index;
++ TXT_DB_free;
++ TXT_DB_get_by_index;
++ TXT_DB_insert;
++ TXT_DB_read;
++ TXT_DB_write;
++ X509_ALGOR_free;
++ X509_ALGOR_new;
++ X509_ATTRIBUTE_free;
++ X509_ATTRIBUTE_new;
++ X509_CINF_free;
++ X509_CINF_new;
++ X509_CRL_INFO_free;
++ X509_CRL_INFO_new;
++ X509_CRL_add_ext;
++ X509_CRL_cmp;
++ X509_CRL_delete_ext;
++ X509_CRL_dup;
++ X509_CRL_free;
++ X509_CRL_get_ext;
++ X509_CRL_get_ext_by_NID;
++ X509_CRL_get_ext_by_OBJ;
++ X509_CRL_get_ext_by_critical;
++ X509_CRL_get_ext_count;
++ X509_CRL_new;
++ X509_CRL_sign;
++ X509_CRL_verify;
++ X509_EXTENSION_create_by_NID;
++ X509_EXTENSION_create_by_OBJ;
++ X509_EXTENSION_dup;
++ X509_EXTENSION_free;
++ X509_EXTENSION_get_critical;
++ X509_EXTENSION_get_data;
++ X509_EXTENSION_get_object;
++ X509_EXTENSION_new;
++ X509_EXTENSION_set_critical;
++ X509_EXTENSION_set_data;
++ X509_EXTENSION_set_object;
++ X509_INFO_free;
++ X509_INFO_new;
++ X509_LOOKUP_by_alias;
++ X509_LOOKUP_by_fingerprint;
++ X509_LOOKUP_by_issuer_serial;
++ X509_LOOKUP_by_subject;
++ X509_LOOKUP_ctrl;
++ X509_LOOKUP_file;
++ X509_LOOKUP_free;
++ X509_LOOKUP_hash_dir;
++ X509_LOOKUP_init;
++ X509_LOOKUP_new;
++ X509_LOOKUP_shutdown;
++ X509_NAME_ENTRY_create_by_NID;
++ X509_NAME_ENTRY_create_by_OBJ;
++ X509_NAME_ENTRY_dup;
++ X509_NAME_ENTRY_free;
++ X509_NAME_ENTRY_get_data;
++ X509_NAME_ENTRY_get_object;
++ X509_NAME_ENTRY_new;
++ X509_NAME_ENTRY_set_data;
++ X509_NAME_ENTRY_set_object;
++ X509_NAME_add_entry;
++ X509_NAME_cmp;
++ X509_NAME_delete_entry;
++ X509_NAME_digest;
++ X509_NAME_dup;
++ X509_NAME_entry_count;
++ X509_NAME_free;
++ X509_NAME_get_entry;
++ X509_NAME_get_index_by_NID;
++ X509_NAME_get_index_by_OBJ;
++ X509_NAME_get_text_by_NID;
++ X509_NAME_get_text_by_OBJ;
++ X509_NAME_hash;
++ X509_NAME_new;
++ X509_NAME_oneline;
++ X509_NAME_print;
++ X509_NAME_set;
++ X509_OBJECT_free_contents;
++ X509_OBJECT_retrieve_by_subject;
++ X509_OBJECT_up_ref_count;
++ X509_PKEY_free;
++ X509_PKEY_new;
++ X509_PUBKEY_free;
++ X509_PUBKEY_get;
++ X509_PUBKEY_new;
++ X509_PUBKEY_set;
++ X509_REQ_INFO_free;
++ X509_REQ_INFO_new;
++ X509_REQ_dup;
++ X509_REQ_free;
++ X509_REQ_get_pubkey;
++ X509_REQ_new;
++ X509_REQ_print;
++ X509_REQ_print_fp;
++ X509_REQ_set_pubkey;
++ X509_REQ_set_subject_name;
++ X509_REQ_set_version;
++ X509_REQ_sign;
++ X509_REQ_to_X509;
++ X509_REQ_verify;
++ X509_REVOKED_add_ext;
++ X509_REVOKED_delete_ext;
++ X509_REVOKED_free;
++ X509_REVOKED_get_ext;
++ X509_REVOKED_get_ext_by_NID;
++ X509_REVOKED_get_ext_by_OBJ;
++ X509_REVOKED_get_ext_by_critical;
++ X509_REVOKED_get_ext_by_critic;
++ X509_REVOKED_get_ext_count;
++ X509_REVOKED_new;
++ X509_SIG_free;
++ X509_SIG_new;
++ X509_STORE_CTX_cleanup;
++ X509_STORE_CTX_init;
++ X509_STORE_add_cert;
++ X509_STORE_add_lookup;
++ X509_STORE_free;
++ X509_STORE_get_by_subject;
++ X509_STORE_load_locations;
++ X509_STORE_new;
++ X509_STORE_set_default_paths;
++ X509_VAL_free;
++ X509_VAL_new;
++ X509_add_ext;
++ X509_asn1_meth;
++ X509_certificate_type;
++ X509_check_private_key;
++ X509_cmp_current_time;
++ X509_delete_ext;
++ X509_digest;
++ X509_dup;
++ X509_free;
++ X509_get_default_cert_area;
++ X509_get_default_cert_dir;
++ X509_get_default_cert_dir_env;
++ X509_get_default_cert_file;
++ X509_get_default_cert_file_env;
++ X509_get_default_private_dir;
++ X509_get_ext;
++ X509_get_ext_by_NID;
++ X509_get_ext_by_OBJ;
++ X509_get_ext_by_critical;
++ X509_get_ext_count;
++ X509_get_issuer_name;
++ X509_get_pubkey;
++ X509_get_pubkey_parameters;
++ X509_get_serialNumber;
++ X509_get_subject_name;
++ X509_gmtime_adj;
++ X509_issuer_and_serial_cmp;
++ X509_issuer_and_serial_hash;
++ X509_issuer_name_cmp;
++ X509_issuer_name_hash;
++ X509_load_cert_file;
++ X509_new;
++ X509_print;
++ X509_print_fp;
++ X509_set_issuer_name;
++ X509_set_notAfter;
++ X509_set_notBefore;
++ X509_set_pubkey;
++ X509_set_serialNumber;
++ X509_set_subject_name;
++ X509_set_version;
++ X509_sign;
++ X509_subject_name_cmp;
++ X509_subject_name_hash;
++ X509_to_X509_REQ;
++ X509_verify;
++ X509_verify_cert;
++ X509_verify_cert_error_string;
++ X509v3_add_ext;
++ X509v3_add_extension;
++ X509v3_add_netscape_extensions;
++ X509v3_add_standard_extensions;
++ X509v3_cleanup_extensions;
++ X509v3_data_type_by_NID;
++ X509v3_data_type_by_OBJ;
++ X509v3_delete_ext;
++ X509v3_get_ext;
++ X509v3_get_ext_by_NID;
++ X509v3_get_ext_by_OBJ;
++ X509v3_get_ext_by_critical;
++ X509v3_get_ext_count;
++ X509v3_pack_string;
++ X509v3_pack_type_by_NID;
++ X509v3_pack_type_by_OBJ;
++ X509v3_unpack_string;
++ _des_crypt;
++ a2d_ASN1_OBJECT;
++ a2i_ASN1_INTEGER;
++ a2i_ASN1_STRING;
++ asn1_Finish;
++ asn1_GetSequence;
++ bn_div_words;
++ bn_expand2;
++ bn_mul_add_words;
++ bn_mul_words;
++ BN_uadd;
++ BN_usub;
++ bn_sqr_words;
++ _ossl_old_crypt;
++ d2i_ASN1_BIT_STRING;
++ d2i_ASN1_BOOLEAN;
++ d2i_ASN1_HEADER;
++ d2i_ASN1_IA5STRING;
++ d2i_ASN1_INTEGER;
++ d2i_ASN1_OBJECT;
++ d2i_ASN1_OCTET_STRING;
++ d2i_ASN1_PRINTABLE;
++ d2i_ASN1_PRINTABLESTRING;
++ d2i_ASN1_SET;
++ d2i_ASN1_T61STRING;
++ d2i_ASN1_TYPE;
++ d2i_ASN1_UTCTIME;
++ d2i_ASN1_bytes;
++ d2i_ASN1_type_bytes;
++ d2i_DHparams;
++ d2i_DSAPrivateKey;
++ d2i_DSAPrivateKey_bio;
++ d2i_DSAPrivateKey_fp;
++ d2i_DSAPublicKey;
++ d2i_DSAparams;
++ d2i_NETSCAPE_SPKAC;
++ d2i_NETSCAPE_SPKI;
++ d2i_Netscape_RSA;
++ d2i_PKCS7;
++ d2i_PKCS7_DIGEST;
++ d2i_PKCS7_ENCRYPT;
++ d2i_PKCS7_ENC_CONTENT;
++ d2i_PKCS7_ENVELOPE;
++ d2i_PKCS7_ISSUER_AND_SERIAL;
++ d2i_PKCS7_RECIP_INFO;
++ d2i_PKCS7_SIGNED;
++ d2i_PKCS7_SIGNER_INFO;
++ d2i_PKCS7_SIGN_ENVELOPE;
++ d2i_PKCS7_bio;
++ d2i_PKCS7_fp;
++ d2i_PrivateKey;
++ d2i_PublicKey;
++ d2i_RSAPrivateKey;
++ d2i_RSAPrivateKey_bio;
++ d2i_RSAPrivateKey_fp;
++ d2i_RSAPublicKey;
++ d2i_X509;
++ d2i_X509_ALGOR;
++ d2i_X509_ATTRIBUTE;
++ d2i_X509_CINF;
++ d2i_X509_CRL;
++ d2i_X509_CRL_INFO;
++ d2i_X509_CRL_bio;
++ d2i_X509_CRL_fp;
++ d2i_X509_EXTENSION;
++ d2i_X509_NAME;
++ d2i_X509_NAME_ENTRY;
++ d2i_X509_PKEY;
++ d2i_X509_PUBKEY;
++ d2i_X509_REQ;
++ d2i_X509_REQ_INFO;
++ d2i_X509_REQ_bio;
++ d2i_X509_REQ_fp;
++ d2i_X509_REVOKED;
++ d2i_X509_SIG;
++ d2i_X509_VAL;
++ d2i_X509_bio;
++ d2i_X509_fp;
++ DES_cbc_cksum;
++ DES_cbc_encrypt;
++ DES_cblock_print_file;
++ DES_cfb64_encrypt;
++ DES_cfb_encrypt;
++ DES_decrypt3;
++ DES_ecb3_encrypt;
++ DES_ecb_encrypt;
++ DES_ede3_cbc_encrypt;
++ DES_ede3_cfb64_encrypt;
++ DES_ede3_ofb64_encrypt;
++ DES_enc_read;
++ DES_enc_write;
++ DES_encrypt1;
++ DES_encrypt2;
++ DES_encrypt3;
++ DES_fcrypt;
++ DES_is_weak_key;
++ DES_key_sched;
++ DES_ncbc_encrypt;
++ DES_ofb64_encrypt;
++ DES_ofb_encrypt;
++ DES_options;
++ DES_pcbc_encrypt;
++ DES_quad_cksum;
++ DES_random_key;
++ _ossl_old_des_random_seed;
++ _ossl_old_des_read_2passwords;
++ _ossl_old_des_read_password;
++ _ossl_old_des_read_pw;
++ _ossl_old_des_read_pw_string;
++ DES_set_key;
++ DES_set_odd_parity;
++ DES_string_to_2keys;
++ DES_string_to_key;
++ DES_xcbc_encrypt;
++ DES_xwhite_in2out;
++ fcrypt_body;
++ i2a_ASN1_INTEGER;
++ i2a_ASN1_OBJECT;
++ i2a_ASN1_STRING;
++ i2d_ASN1_BIT_STRING;
++ i2d_ASN1_BOOLEAN;
++ i2d_ASN1_HEADER;
++ i2d_ASN1_IA5STRING;
++ i2d_ASN1_INTEGER;
++ i2d_ASN1_OBJECT;
++ i2d_ASN1_OCTET_STRING;
++ i2d_ASN1_PRINTABLE;
++ i2d_ASN1_SET;
++ i2d_ASN1_TYPE;
++ i2d_ASN1_UTCTIME;
++ i2d_ASN1_bytes;
++ i2d_DHparams;
++ i2d_DSAPrivateKey;
++ i2d_DSAPrivateKey_bio;
++ i2d_DSAPrivateKey_fp;
++ i2d_DSAPublicKey;
++ i2d_DSAparams;
++ i2d_NETSCAPE_SPKAC;
++ i2d_NETSCAPE_SPKI;
++ i2d_Netscape_RSA;
++ i2d_PKCS7;
++ i2d_PKCS7_DIGEST;
++ i2d_PKCS7_ENCRYPT;
++ i2d_PKCS7_ENC_CONTENT;
++ i2d_PKCS7_ENVELOPE;
++ i2d_PKCS7_ISSUER_AND_SERIAL;
++ i2d_PKCS7_RECIP_INFO;
++ i2d_PKCS7_SIGNED;
++ i2d_PKCS7_SIGNER_INFO;
++ i2d_PKCS7_SIGN_ENVELOPE;
++ i2d_PKCS7_bio;
++ i2d_PKCS7_fp;
++ i2d_PrivateKey;
++ i2d_PublicKey;
++ i2d_RSAPrivateKey;
++ i2d_RSAPrivateKey_bio;
++ i2d_RSAPrivateKey_fp;
++ i2d_RSAPublicKey;
++ i2d_X509;
++ i2d_X509_ALGOR;
++ i2d_X509_ATTRIBUTE;
++ i2d_X509_CINF;
++ i2d_X509_CRL;
++ i2d_X509_CRL_INFO;
++ i2d_X509_CRL_bio;
++ i2d_X509_CRL_fp;
++ i2d_X509_EXTENSION;
++ i2d_X509_NAME;
++ i2d_X509_NAME_ENTRY;
++ i2d_X509_PKEY;
++ i2d_X509_PUBKEY;
++ i2d_X509_REQ;
++ i2d_X509_REQ_INFO;
++ i2d_X509_REQ_bio;
++ i2d_X509_REQ_fp;
++ i2d_X509_REVOKED;
++ i2d_X509_SIG;
++ i2d_X509_VAL;
++ i2d_X509_bio;
++ i2d_X509_fp;
++ idea_cbc_encrypt;
++ idea_cfb64_encrypt;
++ idea_ecb_encrypt;
++ idea_encrypt;
++ idea_ofb64_encrypt;
++ idea_options;
++ idea_set_decrypt_key;
++ idea_set_encrypt_key;
++ lh_delete;
++ lh_doall;
++ lh_doall_arg;
++ lh_free;
++ lh_insert;
++ lh_new;
++ lh_node_stats;
++ lh_node_stats_bio;
++ lh_node_usage_stats;
++ lh_node_usage_stats_bio;
++ lh_retrieve;
++ lh_stats;
++ lh_stats_bio;
++ lh_strhash;
++ sk_delete;
++ sk_delete_ptr;
++ sk_dup;
++ sk_find;
++ sk_free;
++ sk_insert;
++ sk_new;
++ sk_pop;
++ sk_pop_free;
++ sk_push;
++ sk_set_cmp_func;
++ sk_shift;
++ sk_unshift;
++ sk_zero;
++ BIO_f_nbio_test;
++ ASN1_TYPE_get;
++ ASN1_TYPE_set;
++ PKCS7_content_free;
++ ERR_load_PKCS7_strings;
++ X509_find_by_issuer_and_serial;
++ X509_find_by_subject;
++ PKCS7_ctrl;
++ PKCS7_set_type;
++ PKCS7_set_content;
++ PKCS7_SIGNER_INFO_set;
++ PKCS7_add_signer;
++ PKCS7_add_certificate;
++ PKCS7_add_crl;
++ PKCS7_content_new;
++ PKCS7_dataSign;
++ PKCS7_dataVerify;
++ PKCS7_dataInit;
++ PKCS7_add_signature;
++ PKCS7_cert_from_signer_info;
++ PKCS7_get_signer_info;
++ EVP_delete_alias;
++ EVP_mdc2;
++ PEM_read_bio_RSAPublicKey;
++ PEM_write_bio_RSAPublicKey;
++ d2i_RSAPublicKey_bio;
++ i2d_RSAPublicKey_bio;
++ PEM_read_RSAPublicKey;
++ PEM_write_RSAPublicKey;
++ d2i_RSAPublicKey_fp;
++ i2d_RSAPublicKey_fp;
++ BIO_copy_next_retry;
++ RSA_flags;
++ X509_STORE_add_crl;
++ X509_load_crl_file;
++ EVP_rc2_40_cbc;
++ EVP_rc4_40;
++ EVP_CIPHER_CTX_init;
++ HMAC;
++ HMAC_Init;
++ HMAC_Update;
++ HMAC_Final;
++ ERR_get_next_error_library;
++ EVP_PKEY_cmp_parameters;
++ HMAC_cleanup;
++ BIO_ptr_ctrl;
++ BIO_new_file_internal;
++ BIO_new_fp_internal;
++ BIO_s_file_internal;
++ BN_BLINDING_convert;
++ BN_BLINDING_invert;
++ BN_BLINDING_update;
++ RSA_blinding_on;
++ RSA_blinding_off;
++ i2t_ASN1_OBJECT;
++ BN_BLINDING_new;
++ BN_BLINDING_free;
++ EVP_cast5_cbc;
++ EVP_cast5_cfb64;
++ EVP_cast5_ecb;
++ EVP_cast5_ofb;
++ BF_decrypt;
++ CAST_set_key;
++ CAST_encrypt;
++ CAST_decrypt;
++ CAST_ecb_encrypt;
++ CAST_cbc_encrypt;
++ CAST_cfb64_encrypt;
++ CAST_ofb64_encrypt;
++ RC2_decrypt;
++ OBJ_create_objects;
++ BN_exp;
++ BN_mul_word;
++ BN_sub_word;
++ BN_dec2bn;
++ BN_bn2dec;
++ BIO_ghbn_ctrl;
++ CRYPTO_free_ex_data;
++ CRYPTO_get_ex_data;
++ CRYPTO_set_ex_data;
++ ERR_load_CRYPTO_strings;
++ ERR_load_CRYPTOlib_strings;
++ EVP_PKEY_bits;
++ MD5_Transform;
++ SHA1_Transform;
++ SHA_Transform;
++ X509_STORE_CTX_get_chain;
++ X509_STORE_CTX_get_current_cert;
++ X509_STORE_CTX_get_error;
++ X509_STORE_CTX_get_error_depth;
++ X509_STORE_CTX_get_ex_data;
++ X509_STORE_CTX_set_cert;
++ X509_STORE_CTX_set_chain;
++ X509_STORE_CTX_set_error;
++ X509_STORE_CTX_set_ex_data;
++ CRYPTO_dup_ex_data;
++ CRYPTO_get_new_lockid;
++ CRYPTO_new_ex_data;
++ RSA_set_ex_data;
++ RSA_get_ex_data;
++ RSA_get_ex_new_index;
++ RSA_padding_add_PKCS1_type_1;
++ RSA_padding_add_PKCS1_type_2;
++ RSA_padding_add_SSLv23;
++ RSA_padding_add_none;
++ RSA_padding_check_PKCS1_type_1;
++ RSA_padding_check_PKCS1_type_2;
++ RSA_padding_check_SSLv23;
++ RSA_padding_check_none;
++ bn_add_words;
++ d2i_Netscape_RSA_2;
++ CRYPTO_get_ex_new_index;
++ RIPEMD160_Init;
++ RIPEMD160_Update;
++ RIPEMD160_Final;
++ RIPEMD160;
++ RIPEMD160_Transform;
++ RC5_32_set_key;
++ RC5_32_ecb_encrypt;
++ RC5_32_encrypt;
++ RC5_32_decrypt;
++ RC5_32_cbc_encrypt;
++ RC5_32_cfb64_encrypt;
++ RC5_32_ofb64_encrypt;
++ BN_bn2mpi;
++ BN_mpi2bn;
++ ASN1_BIT_STRING_get_bit;
++ ASN1_BIT_STRING_set_bit;
++ BIO_get_ex_data;
++ BIO_get_ex_new_index;
++ BIO_set_ex_data;
++ X509v3_get_key_usage;
++ X509v3_set_key_usage;
++ a2i_X509v3_key_usage;
++ i2a_X509v3_key_usage;
++ EVP_PKEY_decrypt;
++ EVP_PKEY_encrypt;
++ PKCS7_RECIP_INFO_set;
++ PKCS7_add_recipient;
++ PKCS7_add_recipient_info;
++ PKCS7_set_cipher;
++ ASN1_TYPE_get_int_octetstring;
++ ASN1_TYPE_get_octetstring;
++ ASN1_TYPE_set_int_octetstring;
++ ASN1_TYPE_set_octetstring;
++ ASN1_UTCTIME_set_string;
++ ERR_add_error_data;
++ ERR_set_error_data;
++ EVP_CIPHER_asn1_to_param;
++ EVP_CIPHER_param_to_asn1;
++ EVP_CIPHER_get_asn1_iv;
++ EVP_CIPHER_set_asn1_iv;
++ EVP_rc5_32_12_16_cbc;
++ EVP_rc5_32_12_16_cfb64;
++ EVP_rc5_32_12_16_ecb;
++ EVP_rc5_32_12_16_ofb;
++ asn1_add_error;
++ d2i_ASN1_BMPSTRING;
++ i2d_ASN1_BMPSTRING;
++ BIO_f_ber;
++ BN_init;
++ COMP_CTX_new;
++ COMP_CTX_free;
++ COMP_CTX_compress_block;
++ COMP_CTX_expand_block;
++ X509_STORE_CTX_get_ex_new_index;
++ OBJ_NAME_add;
++ BIO_socket_nbio;
++ EVP_rc2_64_cbc;
++ OBJ_NAME_cleanup;
++ OBJ_NAME_get;
++ OBJ_NAME_init;
++ OBJ_NAME_new_index;
++ OBJ_NAME_remove;
++ BN_MONT_CTX_copy;
++ BIO_new_socks4a_connect;
++ BIO_s_socks4a_connect;
++ PROXY_set_connect_mode;
++ RAND_SSLeay;
++ RAND_set_rand_method;
++ RSA_memory_lock;
++ bn_sub_words;
++ bn_mul_normal;
++ bn_mul_comba8;
++ bn_mul_comba4;
++ bn_sqr_normal;
++ bn_sqr_comba8;
++ bn_sqr_comba4;
++ bn_cmp_words;
++ bn_mul_recursive;
++ bn_mul_part_recursive;
++ bn_sqr_recursive;
++ bn_mul_low_normal;
++ BN_RECP_CTX_init;
++ BN_RECP_CTX_new;
++ BN_RECP_CTX_free;
++ BN_RECP_CTX_set;
++ BN_mod_mul_reciprocal;
++ BN_mod_exp_recp;
++ BN_div_recp;
++ BN_CTX_init;
++ BN_MONT_CTX_init;
++ RAND_get_rand_method;
++ PKCS7_add_attribute;
++ PKCS7_add_signed_attribute;
++ PKCS7_digest_from_attributes;
++ PKCS7_get_attribute;
++ PKCS7_get_issuer_and_serial;
++ PKCS7_get_signed_attribute;
++ COMP_compress_block;
++ COMP_expand_block;
++ COMP_rle;
++ COMP_zlib;
++ ms_time_diff;
++ ms_time_new;
++ ms_time_free;
++ ms_time_cmp;
++ ms_time_get;
++ PKCS7_set_attributes;
++ PKCS7_set_signed_attributes;
++ X509_ATTRIBUTE_create;
++ X509_ATTRIBUTE_dup;
++ ASN1_GENERALIZEDTIME_check;
++ ASN1_GENERALIZEDTIME_print;
++ ASN1_GENERALIZEDTIME_set;
++ ASN1_GENERALIZEDTIME_set_string;
++ ASN1_TIME_print;
++ BASIC_CONSTRAINTS_free;
++ BASIC_CONSTRAINTS_new;
++ ERR_load_X509V3_strings;
++ NETSCAPE_CERT_SEQUENCE_free;
++ NETSCAPE_CERT_SEQUENCE_new;
++ OBJ_txt2obj;
++ PEM_read_NETSCAPE_CERT_SEQUENCE;
++ PEM_read_NS_CERT_SEQ;
++ PEM_read_bio_NETSCAPE_CERT_SEQUENCE;
++ PEM_read_bio_NS_CERT_SEQ;
++ PEM_write_NETSCAPE_CERT_SEQUENCE;
++ PEM_write_NS_CERT_SEQ;
++ PEM_write_bio_NETSCAPE_CERT_SEQUENCE;
++ PEM_write_bio_NS_CERT_SEQ;
++ X509V3_EXT_add;
++ X509V3_EXT_add_alias;
++ X509V3_EXT_add_conf;
++ X509V3_EXT_cleanup;
++ X509V3_EXT_conf;
++ X509V3_EXT_conf_nid;
++ X509V3_EXT_get;
++ X509V3_EXT_get_nid;
++ X509V3_EXT_print;
++ X509V3_EXT_print_fp;
++ X509V3_add_standard_extensions;
++ X509V3_add_value;
++ X509V3_add_value_bool;
++ X509V3_add_value_int;
++ X509V3_conf_free;
++ X509V3_get_value_bool;
++ X509V3_get_value_int;
++ X509V3_parse_list;
++ d2i_ASN1_GENERALIZEDTIME;
++ d2i_ASN1_TIME;
++ d2i_BASIC_CONSTRAINTS;
++ d2i_NETSCAPE_CERT_SEQUENCE;
++ d2i_ext_ku;
++ ext_ku_free;
++ ext_ku_new;
++ i2d_ASN1_GENERALIZEDTIME;
++ i2d_ASN1_TIME;
++ i2d_BASIC_CONSTRAINTS;
++ i2d_NETSCAPE_CERT_SEQUENCE;
++ i2d_ext_ku;
++ EVP_MD_CTX_copy;
++ i2d_ASN1_ENUMERATED;
++ d2i_ASN1_ENUMERATED;
++ ASN1_ENUMERATED_set;
++ ASN1_ENUMERATED_get;
++ BN_to_ASN1_ENUMERATED;
++ ASN1_ENUMERATED_to_BN;
++ i2a_ASN1_ENUMERATED;
++ a2i_ASN1_ENUMERATED;
++ i2d_GENERAL_NAME;
++ d2i_GENERAL_NAME;
++ GENERAL_NAME_new;
++ GENERAL_NAME_free;
++ GENERAL_NAMES_new;
++ GENERAL_NAMES_free;
++ d2i_GENERAL_NAMES;
++ i2d_GENERAL_NAMES;
++ i2v_GENERAL_NAMES;
++ i2s_ASN1_OCTET_STRING;
++ s2i_ASN1_OCTET_STRING;
++ X509V3_EXT_check_conf;
++ hex_to_string;
++ string_to_hex;
++ DES_ede3_cbcm_encrypt;
++ RSA_padding_add_PKCS1_OAEP;
++ RSA_padding_check_PKCS1_OAEP;
++ X509_CRL_print_fp;
++ X509_CRL_print;
++ i2v_GENERAL_NAME;
++ v2i_GENERAL_NAME;
++ i2d_PKEY_USAGE_PERIOD;
++ d2i_PKEY_USAGE_PERIOD;
++ PKEY_USAGE_PERIOD_new;
++ PKEY_USAGE_PERIOD_free;
++ v2i_GENERAL_NAMES;
++ i2s_ASN1_INTEGER;
++ X509V3_EXT_d2i;
++ name_cmp;
++ str_dup;
++ i2s_ASN1_ENUMERATED;
++ i2s_ASN1_ENUMERATED_TABLE;
++ BIO_s_log;
++ BIO_f_reliable;
++ PKCS7_dataFinal;
++ PKCS7_dataDecode;
++ X509V3_EXT_CRL_add_conf;
++ BN_set_params;
++ BN_get_params;
++ BIO_get_ex_num;
++ BIO_set_ex_free_func;
++ EVP_ripemd160;
++ ASN1_TIME_set;
++ i2d_AUTHORITY_KEYID;
++ d2i_AUTHORITY_KEYID;
++ AUTHORITY_KEYID_new;
++ AUTHORITY_KEYID_free;
++ ASN1_seq_unpack;
++ ASN1_seq_pack;
++ ASN1_unpack_string;
++ ASN1_pack_string;
++ PKCS12_pack_safebag;
++ PKCS12_MAKE_KEYBAG;
++ PKCS8_encrypt;
++ PKCS12_MAKE_SHKEYBAG;
++ PKCS12_pack_p7data;
++ PKCS12_pack_p7encdata;
++ PKCS12_add_localkeyid;
++ PKCS12_add_friendlyname_asc;
++ PKCS12_add_friendlyname_uni;
++ PKCS12_get_friendlyname;
++ PKCS12_pbe_crypt;
++ PKCS12_decrypt_d2i;
++ PKCS12_i2d_encrypt;
++ PKCS12_init;
++ PKCS12_key_gen_asc;
++ PKCS12_key_gen_uni;
++ PKCS12_gen_mac;
++ PKCS12_verify_mac;
++ PKCS12_set_mac;
++ PKCS12_setup_mac;
++ OPENSSL_asc2uni;
++ OPENSSL_uni2asc;
++ i2d_PKCS12_BAGS;
++ PKCS12_BAGS_new;
++ d2i_PKCS12_BAGS;
++ PKCS12_BAGS_free;
++ i2d_PKCS12;
++ d2i_PKCS12;
++ PKCS12_new;
++ PKCS12_free;
++ i2d_PKCS12_MAC_DATA;
++ PKCS12_MAC_DATA_new;
++ d2i_PKCS12_MAC_DATA;
++ PKCS12_MAC_DATA_free;
++ i2d_PKCS12_SAFEBAG;
++ PKCS12_SAFEBAG_new;
++ d2i_PKCS12_SAFEBAG;
++ PKCS12_SAFEBAG_free;
++ ERR_load_PKCS12_strings;
++ PKCS12_PBE_add;
++ PKCS8_add_keyusage;
++ PKCS12_get_attr_gen;
++ PKCS12_parse;
++ PKCS12_create;
++ i2d_PKCS12_bio;
++ i2d_PKCS12_fp;
++ d2i_PKCS12_bio;
++ d2i_PKCS12_fp;
++ i2d_PBEPARAM;
++ PBEPARAM_new;
++ d2i_PBEPARAM;
++ PBEPARAM_free;
++ i2d_PKCS8_PRIV_KEY_INFO;
++ PKCS8_PRIV_KEY_INFO_new;
++ d2i_PKCS8_PRIV_KEY_INFO;
++ PKCS8_PRIV_KEY_INFO_free;
++ EVP_PKCS82PKEY;
++ EVP_PKEY2PKCS8;
++ PKCS8_set_broken;
++ EVP_PBE_ALGOR_CipherInit;
++ EVP_PBE_alg_add;
++ PKCS5_pbe_set;
++ EVP_PBE_cleanup;
++ i2d_SXNET;
++ d2i_SXNET;
++ SXNET_new;
++ SXNET_free;
++ i2d_SXNETID;
++ d2i_SXNETID;
++ SXNETID_new;
++ SXNETID_free;
++ DSA_SIG_new;
++ DSA_SIG_free;
++ DSA_do_sign;
++ DSA_do_verify;
++ d2i_DSA_SIG;
++ i2d_DSA_SIG;
++ i2d_ASN1_VISIBLESTRING;
++ d2i_ASN1_VISIBLESTRING;
++ i2d_ASN1_UTF8STRING;
++ d2i_ASN1_UTF8STRING;
++ i2d_DIRECTORYSTRING;
++ d2i_DIRECTORYSTRING;
++ i2d_DISPLAYTEXT;
++ d2i_DISPLAYTEXT;
++ d2i_ASN1_SET_OF_X509;
++ i2d_ASN1_SET_OF_X509;
++ i2d_PBKDF2PARAM;
++ PBKDF2PARAM_new;
++ d2i_PBKDF2PARAM;
++ PBKDF2PARAM_free;
++ i2d_PBE2PARAM;
++ PBE2PARAM_new;
++ d2i_PBE2PARAM;
++ PBE2PARAM_free;
++ d2i_ASN1_SET_OF_GENERAL_NAME;
++ i2d_ASN1_SET_OF_GENERAL_NAME;
++ d2i_ASN1_SET_OF_SXNETID;
++ i2d_ASN1_SET_OF_SXNETID;
++ d2i_ASN1_SET_OF_POLICYQUALINFO;
++ i2d_ASN1_SET_OF_POLICYQUALINFO;
++ d2i_ASN1_SET_OF_POLICYINFO;
++ i2d_ASN1_SET_OF_POLICYINFO;
++ SXNET_add_id_asc;
++ SXNET_add_id_ulong;
++ SXNET_add_id_INTEGER;
++ SXNET_get_id_asc;
++ SXNET_get_id_ulong;
++ SXNET_get_id_INTEGER;
++ X509V3_set_conf_lhash;
++ i2d_CERTIFICATEPOLICIES;
++ CERTIFICATEPOLICIES_new;
++ CERTIFICATEPOLICIES_free;
++ d2i_CERTIFICATEPOLICIES;
++ i2d_POLICYINFO;
++ POLICYINFO_new;
++ d2i_POLICYINFO;
++ POLICYINFO_free;
++ i2d_POLICYQUALINFO;
++ POLICYQUALINFO_new;
++ d2i_POLICYQUALINFO;
++ POLICYQUALINFO_free;
++ i2d_USERNOTICE;
++ USERNOTICE_new;
++ d2i_USERNOTICE;
++ USERNOTICE_free;
++ i2d_NOTICEREF;
++ NOTICEREF_new;
++ d2i_NOTICEREF;
++ NOTICEREF_free;
++ X509V3_get_string;
++ X509V3_get_section;
++ X509V3_string_free;
++ X509V3_section_free;
++ X509V3_set_ctx;
++ s2i_ASN1_INTEGER;
++ CRYPTO_set_locked_mem_functions;
++ CRYPTO_get_locked_mem_functions;
++ CRYPTO_malloc_locked;
++ CRYPTO_free_locked;
++ BN_mod_exp2_mont;
++ ERR_get_error_line_data;
++ ERR_peek_error_line_data;
++ PKCS12_PBE_keyivgen;
++ X509_ALGOR_dup;
++ d2i_ASN1_SET_OF_DIST_POINT;
++ i2d_ASN1_SET_OF_DIST_POINT;
++ i2d_CRL_DIST_POINTS;
++ CRL_DIST_POINTS_new;
++ CRL_DIST_POINTS_free;
++ d2i_CRL_DIST_POINTS;
++ i2d_DIST_POINT;
++ DIST_POINT_new;
++ d2i_DIST_POINT;
++ DIST_POINT_free;
++ i2d_DIST_POINT_NAME;
++ DIST_POINT_NAME_new;
++ DIST_POINT_NAME_free;
++ d2i_DIST_POINT_NAME;
++ X509V3_add_value_uchar;
++ d2i_ASN1_SET_OF_X509_ATTRIBUTE;
++ i2d_ASN1_SET_OF_ASN1_TYPE;
++ d2i_ASN1_SET_OF_X509_EXTENSION;
++ d2i_ASN1_SET_OF_X509_NAME_ENTRY;
++ d2i_ASN1_SET_OF_ASN1_TYPE;
++ i2d_ASN1_SET_OF_X509_ATTRIBUTE;
++ i2d_ASN1_SET_OF_X509_EXTENSION;
++ i2d_ASN1_SET_OF_X509_NAME_ENTRY;
++ X509V3_EXT_i2d;
++ X509V3_EXT_val_prn;
++ X509V3_EXT_add_list;
++ EVP_CIPHER_type;
++ EVP_PBE_CipherInit;
++ X509V3_add_value_bool_nf;
++ d2i_ASN1_UINTEGER;
++ sk_value;
++ sk_num;
++ sk_set;
++ i2d_ASN1_SET_OF_X509_REVOKED;
++ sk_sort;
++ d2i_ASN1_SET_OF_X509_REVOKED;
++ i2d_ASN1_SET_OF_X509_ALGOR;
++ i2d_ASN1_SET_OF_X509_CRL;
++ d2i_ASN1_SET_OF_X509_ALGOR;
++ d2i_ASN1_SET_OF_X509_CRL;
++ i2d_ASN1_SET_OF_PKCS7_SIGNER_INFO;
++ i2d_ASN1_SET_OF_PKCS7_RECIP_INFO;
++ d2i_ASN1_SET_OF_PKCS7_SIGNER_INFO;
++ d2i_ASN1_SET_OF_PKCS7_RECIP_INFO;
++ PKCS5_PBE_add;
++ PEM_write_bio_PKCS8;
++ i2d_PKCS8_fp;
++ PEM_read_bio_PKCS8_PRIV_KEY_INFO;
++ PEM_read_bio_P8_PRIV_KEY_INFO;
++ d2i_PKCS8_bio;
++ d2i_PKCS8_PRIV_KEY_INFO_fp;
++ PEM_write_bio_PKCS8_PRIV_KEY_INFO;
++ PEM_write_bio_P8_PRIV_KEY_INFO;
++ PEM_read_PKCS8;
++ d2i_PKCS8_PRIV_KEY_INFO_bio;
++ d2i_PKCS8_fp;
++ PEM_write_PKCS8;
++ PEM_read_PKCS8_PRIV_KEY_INFO;
++ PEM_read_P8_PRIV_KEY_INFO;
++ PEM_read_bio_PKCS8;
++ PEM_write_PKCS8_PRIV_KEY_INFO;
++ PEM_write_P8_PRIV_KEY_INFO;
++ PKCS5_PBE_keyivgen;
++ i2d_PKCS8_bio;
++ i2d_PKCS8_PRIV_KEY_INFO_fp;
++ i2d_PKCS8_PRIV_KEY_INFO_bio;
++ BIO_s_bio;
++ PKCS5_pbe2_set;
++ PKCS5_PBKDF2_HMAC_SHA1;
++ PKCS5_v2_PBE_keyivgen;
++ PEM_write_bio_PKCS8PrivateKey;
++ PEM_write_PKCS8PrivateKey;
++ BIO_ctrl_get_read_request;
++ BIO_ctrl_pending;
++ BIO_ctrl_wpending;
++ BIO_new_bio_pair;
++ BIO_ctrl_get_write_guarantee;
++ CRYPTO_num_locks;
++ CONF_load_bio;
++ CONF_load_fp;
++ i2d_ASN1_SET_OF_ASN1_OBJECT;
++ d2i_ASN1_SET_OF_ASN1_OBJECT;
++ PKCS7_signatureVerify;
++ RSA_set_method;
++ RSA_get_method;
++ RSA_get_default_method;
++ RSA_check_key;
++ OBJ_obj2txt;
++ DSA_dup_DH;
++ X509_REQ_get_extensions;
++ X509_REQ_set_extension_nids;
++ BIO_nwrite;
++ X509_REQ_extension_nid;
++ BIO_nread;
++ X509_REQ_get_extension_nids;
++ BIO_nwrite0;
++ X509_REQ_add_extensions_nid;
++ BIO_nread0;
++ X509_REQ_add_extensions;
++ BIO_new_mem_buf;
++ DH_set_ex_data;
++ DH_set_method;
++ DSA_OpenSSL;
++ DH_get_ex_data;
++ DH_get_ex_new_index;
++ DSA_new_method;
++ DH_new_method;
++ DH_OpenSSL;
++ DSA_get_ex_new_index;
++ DH_get_default_method;
++ DSA_set_ex_data;
++ DH_set_default_method;
++ DSA_get_ex_data;
++ X509V3_EXT_REQ_add_conf;
++ NETSCAPE_SPKI_print;
++ NETSCAPE_SPKI_set_pubkey;
++ NETSCAPE_SPKI_b64_encode;
++ NETSCAPE_SPKI_get_pubkey;
++ NETSCAPE_SPKI_b64_decode;
++ UTF8_putc;
++ UTF8_getc;
++ RSA_null_method;
++ ASN1_tag2str;
++ BIO_ctrl_reset_read_request;
++ DISPLAYTEXT_new;
++ ASN1_GENERALIZEDTIME_free;
++ X509_REVOKED_get_ext_d2i;
++ X509_set_ex_data;
++ X509_reject_set_bit_asc;
++ X509_NAME_add_entry_by_txt;
++ X509_NAME_add_entry_by_NID;
++ X509_PURPOSE_get0;
++ PEM_read_X509_AUX;
++ d2i_AUTHORITY_INFO_ACCESS;
++ PEM_write_PUBKEY;
++ ACCESS_DESCRIPTION_new;
++ X509_CERT_AUX_free;
++ d2i_ACCESS_DESCRIPTION;
++ X509_trust_clear;
++ X509_TRUST_add;
++ ASN1_VISIBLESTRING_new;
++ X509_alias_set1;
++ ASN1_PRINTABLESTRING_free;
++ EVP_PKEY_get1_DSA;
++ ASN1_BMPSTRING_new;
++ ASN1_mbstring_copy;
++ ASN1_UTF8STRING_new;
++ DSA_get_default_method;
++ i2d_ASN1_SET_OF_ACCESS_DESCRIPTION;
++ ASN1_T61STRING_free;
++ DSA_set_method;
++ X509_get_ex_data;
++ ASN1_STRING_type;
++ X509_PURPOSE_get_by_sname;
++ ASN1_TIME_free;
++ ASN1_OCTET_STRING_cmp;
++ ASN1_BIT_STRING_new;
++ X509_get_ext_d2i;
++ PEM_read_bio_X509_AUX;
++ ASN1_STRING_set_default_mask_asc;
++ ASN1_STRING_set_def_mask_asc;
++ PEM_write_bio_RSA_PUBKEY;
++ ASN1_INTEGER_cmp;
++ d2i_RSA_PUBKEY_fp;
++ X509_trust_set_bit_asc;
++ PEM_write_bio_DSA_PUBKEY;
++ X509_STORE_CTX_free;
++ EVP_PKEY_set1_DSA;
++ i2d_DSA_PUBKEY_fp;
++ X509_load_cert_crl_file;
++ ASN1_TIME_new;
++ i2d_RSA_PUBKEY;
++ X509_STORE_CTX_purpose_inherit;
++ PEM_read_RSA_PUBKEY;
++ d2i_X509_AUX;
++ i2d_DSA_PUBKEY;
++ X509_CERT_AUX_print;
++ PEM_read_DSA_PUBKEY;
++ i2d_RSA_PUBKEY_bio;
++ ASN1_BIT_STRING_num_asc;
++ i2d_PUBKEY;
++ ASN1_UTCTIME_free;
++ DSA_set_default_method;
++ X509_PURPOSE_get_by_id;
++ ACCESS_DESCRIPTION_free;
++ PEM_read_bio_PUBKEY;
++ ASN1_STRING_set_by_NID;
++ X509_PURPOSE_get_id;
++ DISPLAYTEXT_free;
++ OTHERNAME_new;
++ X509_CERT_AUX_new;
++ X509_TRUST_cleanup;
++ X509_NAME_add_entry_by_OBJ;
++ X509_CRL_get_ext_d2i;
++ X509_PURPOSE_get0_name;
++ PEM_read_PUBKEY;
++ i2d_DSA_PUBKEY_bio;
++ i2d_OTHERNAME;
++ ASN1_OCTET_STRING_free;
++ ASN1_BIT_STRING_set_asc;
++ X509_get_ex_new_index;
++ ASN1_STRING_TABLE_cleanup;
++ X509_TRUST_get_by_id;
++ X509_PURPOSE_get_trust;
++ ASN1_STRING_length;
++ d2i_ASN1_SET_OF_ACCESS_DESCRIPTION;
++ ASN1_PRINTABLESTRING_new;
++ X509V3_get_d2i;
++ ASN1_ENUMERATED_free;
++ i2d_X509_CERT_AUX;
++ X509_STORE_CTX_set_trust;
++ ASN1_STRING_set_default_mask;
++ X509_STORE_CTX_new;
++ EVP_PKEY_get1_RSA;
++ DIRECTORYSTRING_free;
++ PEM_write_X509_AUX;
++ ASN1_OCTET_STRING_set;
++ d2i_DSA_PUBKEY_fp;
++ d2i_RSA_PUBKEY;
++ X509_TRUST_get0_name;
++ X509_TRUST_get0;
++ AUTHORITY_INFO_ACCESS_free;
++ ASN1_IA5STRING_new;
++ d2i_DSA_PUBKEY;
++ X509_check_purpose;
++ ASN1_ENUMERATED_new;
++ d2i_RSA_PUBKEY_bio;
++ d2i_PUBKEY;
++ X509_TRUST_get_trust;
++ X509_TRUST_get_flags;
++ ASN1_BMPSTRING_free;
++ ASN1_T61STRING_new;
++ ASN1_UTCTIME_new;
++ i2d_AUTHORITY_INFO_ACCESS;
++ EVP_PKEY_set1_RSA;
++ X509_STORE_CTX_set_purpose;
++ ASN1_IA5STRING_free;
++ PEM_write_bio_X509_AUX;
++ X509_PURPOSE_get_count;
++ CRYPTO_add_info;
++ X509_NAME_ENTRY_create_by_txt;
++ ASN1_STRING_get_default_mask;
++ X509_alias_get0;
++ ASN1_STRING_data;
++ i2d_ACCESS_DESCRIPTION;
++ X509_trust_set_bit;
++ ASN1_BIT_STRING_free;
++ PEM_read_bio_RSA_PUBKEY;
++ X509_add1_reject_object;
++ X509_check_trust;
++ PEM_read_bio_DSA_PUBKEY;
++ X509_PURPOSE_add;
++ ASN1_STRING_TABLE_get;
++ ASN1_UTF8STRING_free;
++ d2i_DSA_PUBKEY_bio;
++ PEM_write_RSA_PUBKEY;
++ d2i_OTHERNAME;
++ X509_reject_set_bit;
++ PEM_write_DSA_PUBKEY;
++ X509_PURPOSE_get0_sname;
++ EVP_PKEY_set1_DH;
++ ASN1_OCTET_STRING_dup;
++ ASN1_BIT_STRING_set;
++ X509_TRUST_get_count;
++ ASN1_INTEGER_free;
++ OTHERNAME_free;
++ i2d_RSA_PUBKEY_fp;
++ ASN1_INTEGER_dup;
++ d2i_X509_CERT_AUX;
++ PEM_write_bio_PUBKEY;
++ ASN1_VISIBLESTRING_free;
++ X509_PURPOSE_cleanup;
++ ASN1_mbstring_ncopy;
++ ASN1_GENERALIZEDTIME_new;
++ EVP_PKEY_get1_DH;
++ ASN1_OCTET_STRING_new;
++ ASN1_INTEGER_new;
++ i2d_X509_AUX;
++ ASN1_BIT_STRING_name_print;
++ X509_cmp;
++ ASN1_STRING_length_set;
++ DIRECTORYSTRING_new;
++ X509_add1_trust_object;
++ PKCS12_newpass;
++ SMIME_write_PKCS7;
++ SMIME_read_PKCS7;
++ DES_set_key_checked;
++ PKCS7_verify;
++ PKCS7_encrypt;
++ DES_set_key_unchecked;
++ SMIME_crlf_copy;
++ i2d_ASN1_PRINTABLESTRING;
++ PKCS7_get0_signers;
++ PKCS7_decrypt;
++ SMIME_text;
++ PKCS7_simple_smimecap;
++ PKCS7_get_smimecap;
++ PKCS7_sign;
++ PKCS7_add_attrib_smimecap;
++ CRYPTO_dbg_set_options;
++ CRYPTO_remove_all_info;
++ CRYPTO_get_mem_debug_functions;
++ CRYPTO_is_mem_check_on;
++ CRYPTO_set_mem_debug_functions;
++ CRYPTO_pop_info;
++ CRYPTO_push_info_;
++ CRYPTO_set_mem_debug_options;
++ PEM_write_PKCS8PrivateKey_nid;
++ PEM_write_bio_PKCS8PrivateKey_nid;
++ PEM_write_bio_PKCS8PrivKey_nid;
++ d2i_PKCS8PrivateKey_bio;
++ ASN1_NULL_free;
++ d2i_ASN1_NULL;
++ ASN1_NULL_new;
++ i2d_PKCS8PrivateKey_bio;
++ i2d_PKCS8PrivateKey_fp;
++ i2d_ASN1_NULL;
++ i2d_PKCS8PrivateKey_nid_fp;
++ d2i_PKCS8PrivateKey_fp;
++ i2d_PKCS8PrivateKey_nid_bio;
++ i2d_PKCS8PrivateKeyInfo_fp;
++ i2d_PKCS8PrivateKeyInfo_bio;
++ PEM_cb;
++ i2d_PrivateKey_fp;
++ d2i_PrivateKey_bio;
++ d2i_PrivateKey_fp;
++ i2d_PrivateKey_bio;
++ X509_reject_clear;
++ X509_TRUST_set_default;
++ d2i_AutoPrivateKey;
++ X509_ATTRIBUTE_get0_type;
++ X509_ATTRIBUTE_set1_data;
++ X509at_get_attr;
++ X509at_get_attr_count;
++ X509_ATTRIBUTE_create_by_NID;
++ X509_ATTRIBUTE_set1_object;
++ X509_ATTRIBUTE_count;
++ X509_ATTRIBUTE_create_by_OBJ;
++ X509_ATTRIBUTE_get0_object;
++ X509at_get_attr_by_NID;
++ X509at_add1_attr;
++ X509_ATTRIBUTE_get0_data;
++ X509at_delete_attr;
++ X509at_get_attr_by_OBJ;
++ RAND_add;
++ BIO_number_written;
++ BIO_number_read;
++ X509_STORE_CTX_get1_chain;
++ ERR_load_RAND_strings;
++ RAND_pseudo_bytes;
++ X509_REQ_get_attr_by_NID;
++ X509_REQ_get_attr;
++ X509_REQ_add1_attr_by_NID;
++ X509_REQ_get_attr_by_OBJ;
++ X509at_add1_attr_by_NID;
++ X509_REQ_add1_attr_by_OBJ;
++ X509_REQ_get_attr_count;
++ X509_REQ_add1_attr;
++ X509_REQ_delete_attr;
++ X509at_add1_attr_by_OBJ;
++ X509_REQ_add1_attr_by_txt;
++ X509_ATTRIBUTE_create_by_txt;
++ X509at_add1_attr_by_txt;
++ BN_pseudo_rand;
++ BN_is_prime_fasttest;
++ BN_CTX_end;
++ BN_CTX_start;
++ BN_CTX_get;
++ EVP_PKEY2PKCS8_broken;
++ ASN1_STRING_TABLE_add;
++ CRYPTO_dbg_get_options;
++ AUTHORITY_INFO_ACCESS_new;
++ CRYPTO_get_mem_debug_options;
++ DES_crypt;
++ PEM_write_bio_X509_REQ_NEW;
++ PEM_write_X509_REQ_NEW;
++ BIO_callback_ctrl;
++ RAND_egd;
++ RAND_status;
++ bn_dump1;
++ DES_check_key_parity;
++ lh_num_items;
++ RAND_event;
++ DSO_new;
++ DSO_new_method;
++ DSO_free;
++ DSO_flags;
++ DSO_up;
++ DSO_set_default_method;
++ DSO_get_default_method;
++ DSO_get_method;
++ DSO_set_method;
++ DSO_load;
++ DSO_bind_var;
++ DSO_METHOD_null;
++ DSO_METHOD_openssl;
++ DSO_METHOD_dlfcn;
++ DSO_METHOD_win32;
++ ERR_load_DSO_strings;
++ DSO_METHOD_dl;
++ NCONF_load;
++ NCONF_load_fp;
++ NCONF_new;
++ NCONF_get_string;
++ NCONF_free;
++ NCONF_get_number;
++ CONF_dump_fp;
++ NCONF_load_bio;
++ NCONF_dump_fp;
++ NCONF_get_section;
++ NCONF_dump_bio;
++ CONF_dump_bio;
++ NCONF_free_data;
++ CONF_set_default_method;
++ ERR_error_string_n;
++ BIO_snprintf;
++ DSO_ctrl;
++ i2d_ASN1_SET_OF_ASN1_INTEGER;
++ i2d_ASN1_SET_OF_PKCS12_SAFEBAG;
++ i2d_ASN1_SET_OF_PKCS7;
++ BIO_vfree;
++ d2i_ASN1_SET_OF_ASN1_INTEGER;
++ d2i_ASN1_SET_OF_PKCS12_SAFEBAG;
++ ASN1_UTCTIME_get;
++ X509_REQ_digest;
++ X509_CRL_digest;
++ d2i_ASN1_SET_OF_PKCS7;
++ EVP_CIPHER_CTX_set_key_length;
++ EVP_CIPHER_CTX_ctrl;
++ BN_mod_exp_mont_word;
++ RAND_egd_bytes;
++ X509_REQ_get1_email;
++ X509_get1_email;
++ X509_email_free;
++ i2d_RSA_NET;
++ d2i_RSA_NET_2;
++ d2i_RSA_NET;
++ DSO_bind_func;
++ CRYPTO_get_new_dynlockid;
++ sk_new_null;
++ CRYPTO_set_dynlock_destroy_callback;
++ CRYPTO_set_dynlock_destroy_cb;
++ CRYPTO_destroy_dynlockid;
++ CRYPTO_set_dynlock_size;
++ CRYPTO_set_dynlock_create_callback;
++ CRYPTO_set_dynlock_create_cb;
++ CRYPTO_set_dynlock_lock_callback;
++ CRYPTO_set_dynlock_lock_cb;
++ CRYPTO_get_dynlock_lock_callback;
++ CRYPTO_get_dynlock_lock_cb;
++ CRYPTO_get_dynlock_destroy_callback;
++ CRYPTO_get_dynlock_destroy_cb;
++ CRYPTO_get_dynlock_value;
++ CRYPTO_get_dynlock_create_callback;
++ CRYPTO_get_dynlock_create_cb;
++ c2i_ASN1_BIT_STRING;
++ i2c_ASN1_BIT_STRING;
++ RAND_poll;
++ c2i_ASN1_INTEGER;
++ i2c_ASN1_INTEGER;
++ BIO_dump_indent;
++ ASN1_parse_dump;
++ c2i_ASN1_OBJECT;
++ X509_NAME_print_ex_fp;
++ ASN1_STRING_print_ex_fp;
++ X509_NAME_print_ex;
++ ASN1_STRING_print_ex;
++ MD4;
++ MD4_Transform;
++ MD4_Final;
++ MD4_Update;
++ MD4_Init;
++ EVP_md4;
++ i2d_PUBKEY_bio;
++ i2d_PUBKEY_fp;
++ d2i_PUBKEY_bio;
++ ASN1_STRING_to_UTF8;
++ BIO_vprintf;
++ BIO_vsnprintf;
++ d2i_PUBKEY_fp;
++ X509_cmp_time;
++ X509_STORE_CTX_set_time;
++ X509_STORE_CTX_get1_issuer;
++ X509_OBJECT_retrieve_match;
++ X509_OBJECT_idx_by_subject;
++ X509_STORE_CTX_set_flags;
++ X509_STORE_CTX_trusted_stack;
++ X509_time_adj;
++ X509_check_issued;
++ ASN1_UTCTIME_cmp_time_t;
++ DES_set_weak_key_flag;
++ DES_check_key;
++ DES_rw_mode;
++ RSA_PKCS1_RSAref;
++ X509_keyid_set1;
++ BIO_next;
++ DSO_METHOD_vms;
++ BIO_f_linebuffer;
++ BN_bntest_rand;
++ OPENSSL_issetugid;
++ BN_rand_range;
++ ERR_load_ENGINE_strings;
++ ENGINE_set_DSA;
++ ENGINE_get_finish_function;
++ ENGINE_get_default_RSA;
++ ENGINE_get_BN_mod_exp;
++ DSA_get_default_openssl_method;
++ ENGINE_set_DH;
++ ENGINE_set_def_BN_mod_exp_crt;
++ ENGINE_set_default_BN_mod_exp_crt;
++ ENGINE_init;
++ DH_get_default_openssl_method;
++ RSA_set_default_openssl_method;
++ ENGINE_finish;
++ ENGINE_load_public_key;
++ ENGINE_get_DH;
++ ENGINE_ctrl;
++ ENGINE_get_init_function;
++ ENGINE_set_init_function;
++ ENGINE_set_default_DSA;
++ ENGINE_get_name;
++ ENGINE_get_last;
++ ENGINE_get_prev;
++ ENGINE_get_default_DH;
++ ENGINE_get_RSA;
++ ENGINE_set_default;
++ ENGINE_get_RAND;
++ ENGINE_get_first;
++ ENGINE_by_id;
++ ENGINE_set_finish_function;
++ ENGINE_get_def_BN_mod_exp_crt;
++ ENGINE_get_default_BN_mod_exp_crt;
++ RSA_get_default_openssl_method;
++ ENGINE_set_RSA;
++ ENGINE_load_private_key;
++ ENGINE_set_default_RAND;
++ ENGINE_set_BN_mod_exp;
++ ENGINE_remove;
++ ENGINE_free;
++ ENGINE_get_BN_mod_exp_crt;
++ ENGINE_get_next;
++ ENGINE_set_name;
++ ENGINE_get_default_DSA;
++ ENGINE_set_default_BN_mod_exp;
++ ENGINE_set_default_RSA;
++ ENGINE_get_default_RAND;
++ ENGINE_get_default_BN_mod_exp;
++ ENGINE_set_RAND;
++ ENGINE_set_id;
++ ENGINE_set_BN_mod_exp_crt;
++ ENGINE_set_default_DH;
++ ENGINE_new;
++ ENGINE_get_id;
++ DSA_set_default_openssl_method;
++ ENGINE_add;
++ DH_set_default_openssl_method;
++ ENGINE_get_DSA;
++ ENGINE_get_ctrl_function;
++ ENGINE_set_ctrl_function;
++ BN_pseudo_rand_range;
++ X509_STORE_CTX_set_verify_cb;
++ ERR_load_COMP_strings;
++ PKCS12_item_decrypt_d2i;
++ ASN1_UTF8STRING_it;
++ ASN1_UTF8STRING_it;
++ ENGINE_unregister_ciphers;
++ ENGINE_get_ciphers;
++ d2i_OCSP_BASICRESP;
++ KRB5_CHECKSUM_it;
++ KRB5_CHECKSUM_it;
++ EC_POINT_add;
++ ASN1_item_ex_i2d;
++ OCSP_CERTID_it;
++ OCSP_CERTID_it;
++ d2i_OCSP_RESPBYTES;
++ X509V3_add1_i2d;
++ PKCS7_ENVELOPE_it;
++ PKCS7_ENVELOPE_it;
++ UI_add_input_boolean;
++ ENGINE_unregister_RSA;
++ X509V3_EXT_nconf;
++ ASN1_GENERALSTRING_free;
++ d2i_OCSP_CERTSTATUS;
++ X509_REVOKED_set_serialNumber;
++ X509_print_ex;
++ OCSP_ONEREQ_get1_ext_d2i;
++ ENGINE_register_all_RAND;
++ ENGINE_load_dynamic;
++ PBKDF2PARAM_it;
++ PBKDF2PARAM_it;
++ EXTENDED_KEY_USAGE_new;
++ EC_GROUP_clear_free;
++ OCSP_sendreq_bio;
++ ASN1_item_digest;
++ OCSP_BASICRESP_delete_ext;
++ OCSP_SIGNATURE_it;
++ OCSP_SIGNATURE_it;
++ X509_CRL_it;
++ X509_CRL_it;
++ OCSP_BASICRESP_add_ext;
++ KRB5_ENCKEY_it;
++ KRB5_ENCKEY_it;
++ UI_method_set_closer;
++ X509_STORE_set_purpose;
++ i2d_ASN1_GENERALSTRING;
++ OCSP_response_status;
++ i2d_OCSP_SERVICELOC;
++ ENGINE_get_digest_engine;
++ EC_GROUP_set_curve_GFp;
++ OCSP_REQUEST_get_ext_by_OBJ;
++ _ossl_old_des_random_key;
++ ASN1_T61STRING_it;
++ ASN1_T61STRING_it;
++ EC_GROUP_method_of;
++ i2d_KRB5_APREQ;
++ _ossl_old_des_encrypt;
++ ASN1_PRINTABLE_new;
++ HMAC_Init_ex;
++ d2i_KRB5_AUTHENT;
++ OCSP_archive_cutoff_new;
++ EC_POINT_set_Jprojective_coordinates_GFp;
++ EC_POINT_set_Jproj_coords_GFp;
++ _ossl_old_des_is_weak_key;
++ OCSP_BASICRESP_get_ext_by_OBJ;
++ EC_POINT_oct2point;
++ OCSP_SINGLERESP_get_ext_count;
++ UI_ctrl;
++ _shadow_DES_rw_mode;
++ _shadow_DES_rw_mode;
++ asn1_do_adb;
++ ASN1_template_i2d;
++ ENGINE_register_DH;
++ UI_construct_prompt;
++ X509_STORE_set_trust;
++ UI_dup_input_string;
++ d2i_KRB5_APREQ;
++ EVP_MD_CTX_copy_ex;
++ OCSP_request_is_signed;
++ i2d_OCSP_REQINFO;
++ KRB5_ENCKEY_free;
++ OCSP_resp_get0;
++ GENERAL_NAME_it;
++ GENERAL_NAME_it;
++ ASN1_GENERALIZEDTIME_it;
++ ASN1_GENERALIZEDTIME_it;
++ X509_STORE_set_flags;
++ EC_POINT_set_compressed_coordinates_GFp;
++ EC_POINT_set_compr_coords_GFp;
++ OCSP_response_status_str;
++ d2i_OCSP_REVOKEDINFO;
++ OCSP_basic_add1_cert;
++ ERR_get_implementation;
++ EVP_CipherFinal_ex;
++ OCSP_CERTSTATUS_new;
++ CRYPTO_cleanup_all_ex_data;
++ OCSP_resp_find;
++ BN_nnmod;
++ X509_CRL_sort;
++ X509_REVOKED_set_revocationDate;
++ ENGINE_register_RAND;
++ OCSP_SERVICELOC_new;
++ EC_POINT_set_affine_coordinates_GFp;
++ EC_POINT_set_affine_coords_GFp;
++ _ossl_old_des_options;
++ SXNET_it;
++ SXNET_it;
++ UI_dup_input_boolean;
++ PKCS12_add_CSPName_asc;
++ EC_POINT_is_at_infinity;
++ ENGINE_load_cryptodev;
++ DSO_convert_filename;
++ POLICYQUALINFO_it;
++ POLICYQUALINFO_it;
++ ENGINE_register_ciphers;
++ BN_mod_lshift_quick;
++ DSO_set_filename;
++ ASN1_item_free;
++ KRB5_TKTBODY_free;
++ AUTHORITY_KEYID_it;
++ AUTHORITY_KEYID_it;
++ KRB5_APREQBODY_new;
++ X509V3_EXT_REQ_add_nconf;
++ ENGINE_ctrl_cmd_string;
++ i2d_OCSP_RESPDATA;
++ EVP_MD_CTX_init;
++ EXTENDED_KEY_USAGE_free;
++ PKCS7_ATTR_SIGN_it;
++ PKCS7_ATTR_SIGN_it;
++ UI_add_error_string;
++ KRB5_CHECKSUM_free;
++ OCSP_REQUEST_get_ext;
++ ENGINE_load_ubsec;
++ ENGINE_register_all_digests;
++ PKEY_USAGE_PERIOD_it;
++ PKEY_USAGE_PERIOD_it;
++ PKCS12_unpack_authsafes;
++ ASN1_item_unpack;
++ NETSCAPE_SPKAC_it;
++ NETSCAPE_SPKAC_it;
++ X509_REVOKED_it;
++ X509_REVOKED_it;
++ ASN1_STRING_encode;
++ EVP_aes_128_ecb;
++ KRB5_AUTHENT_free;
++ OCSP_BASICRESP_get_ext_by_critical;
++ OCSP_BASICRESP_get_ext_by_crit;
++ OCSP_cert_status_str;
++ d2i_OCSP_REQUEST;
++ UI_dup_info_string;
++ _ossl_old_des_xwhite_in2out;
++ PKCS12_it;
++ PKCS12_it;
++ OCSP_SINGLERESP_get_ext_by_critical;
++ OCSP_SINGLERESP_get_ext_by_crit;
++ OCSP_CERTSTATUS_free;
++ _ossl_old_des_crypt;
++ ASN1_item_i2d;
++ EVP_DecryptFinal_ex;
++ ENGINE_load_openssl;
++ ENGINE_get_cmd_defns;
++ ENGINE_set_load_privkey_function;
++ ENGINE_set_load_privkey_fn;
++ EVP_EncryptFinal_ex;
++ ENGINE_set_default_digests;
++ X509_get0_pubkey_bitstr;
++ asn1_ex_i2c;
++ ENGINE_register_RSA;
++ ENGINE_unregister_DSA;
++ _ossl_old_des_key_sched;
++ X509_EXTENSION_it;
++ X509_EXTENSION_it;
++ i2d_KRB5_AUTHENT;
++ SXNETID_it;
++ SXNETID_it;
++ d2i_OCSP_SINGLERESP;
++ EDIPARTYNAME_new;
++ PKCS12_certbag2x509;
++ _ossl_old_des_ofb64_encrypt;
++ d2i_EXTENDED_KEY_USAGE;
++ ERR_print_errors_cb;
++ ENGINE_set_ciphers;
++ d2i_KRB5_APREQBODY;
++ UI_method_get_flusher;
++ X509_PUBKEY_it;
++ X509_PUBKEY_it;
++ _ossl_old_des_enc_read;
++ PKCS7_ENCRYPT_it;
++ PKCS7_ENCRYPT_it;
++ i2d_OCSP_RESPONSE;
++ EC_GROUP_get_cofactor;
++ PKCS12_unpack_p7data;
++ d2i_KRB5_AUTHDATA;
++ OCSP_copy_nonce;
++ KRB5_AUTHDATA_new;
++ OCSP_RESPDATA_new;
++ EC_GFp_mont_method;
++ OCSP_REVOKEDINFO_free;
++ UI_get_ex_data;
++ KRB5_APREQBODY_free;
++ EC_GROUP_get0_generator;
++ UI_get_default_method;
++ X509V3_set_nconf;
++ PKCS12_item_i2d_encrypt;
++ X509_add1_ext_i2d;
++ PKCS7_SIGNER_INFO_it;
++ PKCS7_SIGNER_INFO_it;
++ KRB5_PRINCNAME_new;
++ PKCS12_SAFEBAG_it;
++ PKCS12_SAFEBAG_it;
++ EC_GROUP_get_order;
++ d2i_OCSP_RESPID;
++ OCSP_request_verify;
++ NCONF_get_number_e;
++ _ossl_old_des_decrypt3;
++ X509_signature_print;
++ OCSP_SINGLERESP_free;
++ ENGINE_load_builtin_engines;
++ i2d_OCSP_ONEREQ;
++ OCSP_REQUEST_add_ext;
++ OCSP_RESPBYTES_new;
++ EVP_MD_CTX_create;
++ OCSP_resp_find_status;
++ X509_ALGOR_it;
++ X509_ALGOR_it;
++ ASN1_TIME_it;
++ ASN1_TIME_it;
++ OCSP_request_set1_name;
++ OCSP_ONEREQ_get_ext_count;
++ UI_get0_result;
++ PKCS12_AUTHSAFES_it;
++ PKCS12_AUTHSAFES_it;
++ EVP_aes_256_ecb;
++ PKCS12_pack_authsafes;
++ ASN1_IA5STRING_it;
++ ASN1_IA5STRING_it;
++ UI_get_input_flags;
++ EC_GROUP_set_generator;
++ _ossl_old_des_string_to_2keys;
++ OCSP_CERTID_free;
++ X509_CERT_AUX_it;
++ X509_CERT_AUX_it;
++ CERTIFICATEPOLICIES_it;
++ CERTIFICATEPOLICIES_it;
++ _ossl_old_des_ede3_cbc_encrypt;
++ RAND_set_rand_engine;
++ DSO_get_loaded_filename;
++ X509_ATTRIBUTE_it;
++ X509_ATTRIBUTE_it;
++ OCSP_ONEREQ_get_ext_by_NID;
++ PKCS12_decrypt_skey;
++ KRB5_AUTHENT_it;
++ KRB5_AUTHENT_it;
++ UI_dup_error_string;
++ RSAPublicKey_it;
++ RSAPublicKey_it;
++ i2d_OCSP_REQUEST;
++ PKCS12_x509crl2certbag;
++ OCSP_SERVICELOC_it;
++ OCSP_SERVICELOC_it;
++ ASN1_item_sign;
++ X509_CRL_set_issuer_name;
++ OBJ_NAME_do_all_sorted;
++ i2d_OCSP_BASICRESP;
++ i2d_OCSP_RESPBYTES;
++ PKCS12_unpack_p7encdata;
++ HMAC_CTX_init;
++ ENGINE_get_digest;
++ OCSP_RESPONSE_print;
++ KRB5_TKTBODY_it;
++ KRB5_TKTBODY_it;
++ ACCESS_DESCRIPTION_it;
++ ACCESS_DESCRIPTION_it;
++ PKCS7_ISSUER_AND_SERIAL_it;
++ PKCS7_ISSUER_AND_SERIAL_it;
++ PBE2PARAM_it;
++ PBE2PARAM_it;
++ PKCS12_certbag2x509crl;
++ PKCS7_SIGNED_it;
++ PKCS7_SIGNED_it;
++ ENGINE_get_cipher;
++ i2d_OCSP_CRLID;
++ OCSP_SINGLERESP_new;
++ ENGINE_cmd_is_executable;
++ RSA_up_ref;
++ ASN1_GENERALSTRING_it;
++ ASN1_GENERALSTRING_it;
++ ENGINE_register_DSA;
++ X509V3_EXT_add_nconf_sk;
++ ENGINE_set_load_pubkey_function;
++ PKCS8_decrypt;
++ PEM_bytes_read_bio;
++ DIRECTORYSTRING_it;
++ DIRECTORYSTRING_it;
++ d2i_OCSP_CRLID;
++ EC_POINT_is_on_curve;
++ CRYPTO_set_locked_mem_ex_functions;
++ CRYPTO_set_locked_mem_ex_funcs;
++ d2i_KRB5_CHECKSUM;
++ ASN1_item_dup;
++ X509_it;
++ X509_it;
++ BN_mod_add;
++ KRB5_AUTHDATA_free;
++ _ossl_old_des_cbc_cksum;
++ ASN1_item_verify;
++ CRYPTO_set_mem_ex_functions;
++ EC_POINT_get_Jprojective_coordinates_GFp;
++ EC_POINT_get_Jproj_coords_GFp;
++ ZLONG_it;
++ ZLONG_it;
++ CRYPTO_get_locked_mem_ex_functions;
++ CRYPTO_get_locked_mem_ex_funcs;
++ ASN1_TIME_check;
++ UI_get0_user_data;
++ HMAC_CTX_cleanup;
++ DSA_up_ref;
++ _ossl_old_des_ede3_cfb64_encrypt;
++ _ossl_odes_ede3_cfb64_encrypt;
++ ASN1_BMPSTRING_it;
++ ASN1_BMPSTRING_it;
++ ASN1_tag2bit;
++ UI_method_set_flusher;
++ X509_ocspid_print;
++ KRB5_ENCDATA_it;
++ KRB5_ENCDATA_it;
++ ENGINE_get_load_pubkey_function;
++ UI_add_user_data;
++ OCSP_REQUEST_delete_ext;
++ UI_get_method;
++ OCSP_ONEREQ_free;
++ ASN1_PRINTABLESTRING_it;
++ ASN1_PRINTABLESTRING_it;
++ X509_CRL_set_nextUpdate;
++ OCSP_REQUEST_it;
++ OCSP_REQUEST_it;
++ OCSP_BASICRESP_it;
++ OCSP_BASICRESP_it;
++ AES_ecb_encrypt;
++ BN_mod_sqr;
++ NETSCAPE_CERT_SEQUENCE_it;
++ NETSCAPE_CERT_SEQUENCE_it;
++ GENERAL_NAMES_it;
++ GENERAL_NAMES_it;
++ AUTHORITY_INFO_ACCESS_it;
++ AUTHORITY_INFO_ACCESS_it;
++ ASN1_FBOOLEAN_it;
++ ASN1_FBOOLEAN_it;
++ UI_set_ex_data;
++ _ossl_old_des_string_to_key;
++ ENGINE_register_all_RSA;
++ d2i_KRB5_PRINCNAME;
++ OCSP_RESPBYTES_it;
++ OCSP_RESPBYTES_it;
++ X509_CINF_it;
++ X509_CINF_it;
++ ENGINE_unregister_digests;
++ d2i_EDIPARTYNAME;
++ d2i_OCSP_SERVICELOC;
++ ENGINE_get_digests;
++ _ossl_old_des_set_odd_parity;
++ OCSP_RESPDATA_free;
++ d2i_KRB5_TICKET;
++ OTHERNAME_it;
++ OTHERNAME_it;
++ EVP_MD_CTX_cleanup;
++ d2i_ASN1_GENERALSTRING;
++ X509_CRL_set_version;
++ BN_mod_sub;
++ OCSP_SINGLERESP_get_ext_by_NID;
++ ENGINE_get_ex_new_index;
++ OCSP_REQUEST_free;
++ OCSP_REQUEST_add1_ext_i2d;
++ X509_VAL_it;
++ X509_VAL_it;
++ EC_POINTs_make_affine;
++ EC_POINT_mul;
++ X509V3_EXT_add_nconf;
++ X509_TRUST_set;
++ X509_CRL_add1_ext_i2d;
++ _ossl_old_des_fcrypt;
++ DISPLAYTEXT_it;
++ DISPLAYTEXT_it;
++ X509_CRL_set_lastUpdate;
++ OCSP_BASICRESP_free;
++ OCSP_BASICRESP_add1_ext_i2d;
++ d2i_KRB5_AUTHENTBODY;
++ CRYPTO_set_ex_data_implementation;
++ CRYPTO_set_ex_data_impl;
++ KRB5_ENCDATA_new;
++ DSO_up_ref;
++ OCSP_crl_reason_str;
++ UI_get0_result_string;
++ ASN1_GENERALSTRING_new;
++ X509_SIG_it;
++ X509_SIG_it;
++ ERR_set_implementation;
++ ERR_load_EC_strings;
++ UI_get0_action_string;
++ OCSP_ONEREQ_get_ext;
++ EC_POINT_method_of;
++ i2d_KRB5_APREQBODY;
++ _ossl_old_des_ecb3_encrypt;
++ CRYPTO_get_mem_ex_functions;
++ ENGINE_get_ex_data;
++ UI_destroy_method;
++ ASN1_item_i2d_bio;
++ OCSP_ONEREQ_get_ext_by_OBJ;
++ ASN1_primitive_new;
++ ASN1_PRINTABLE_it;
++ ASN1_PRINTABLE_it;
++ EVP_aes_192_ecb;
++ OCSP_SIGNATURE_new;
++ LONG_it;
++ LONG_it;
++ ASN1_VISIBLESTRING_it;
++ ASN1_VISIBLESTRING_it;
++ OCSP_SINGLERESP_add1_ext_i2d;
++ d2i_OCSP_CERTID;
++ ASN1_item_d2i_fp;
++ CRL_DIST_POINTS_it;
++ CRL_DIST_POINTS_it;
++ GENERAL_NAME_print;
++ OCSP_SINGLERESP_delete_ext;
++ PKCS12_SAFEBAGS_it;
++ PKCS12_SAFEBAGS_it;
++ d2i_OCSP_SIGNATURE;
++ OCSP_request_add1_nonce;
++ ENGINE_set_cmd_defns;
++ OCSP_SERVICELOC_free;
++ EC_GROUP_free;
++ ASN1_BIT_STRING_it;
++ ASN1_BIT_STRING_it;
++ X509_REQ_it;
++ X509_REQ_it;
++ _ossl_old_des_cbc_encrypt;
++ ERR_unload_strings;
++ PKCS7_SIGN_ENVELOPE_it;
++ PKCS7_SIGN_ENVELOPE_it;
++ EDIPARTYNAME_free;
++ OCSP_REQINFO_free;
++ EC_GROUP_new_curve_GFp;
++ OCSP_REQUEST_get1_ext_d2i;
++ PKCS12_item_pack_safebag;
++ asn1_ex_c2i;
++ ENGINE_register_digests;
++ i2d_OCSP_REVOKEDINFO;
++ asn1_enc_restore;
++ UI_free;
++ UI_new_method;
++ EVP_EncryptInit_ex;
++ X509_pubkey_digest;
++ EC_POINT_invert;
++ OCSP_basic_sign;
++ i2d_OCSP_RESPID;
++ OCSP_check_nonce;
++ ENGINE_ctrl_cmd;
++ d2i_KRB5_ENCKEY;
++ OCSP_parse_url;
++ OCSP_SINGLERESP_get_ext;
++ OCSP_CRLID_free;
++ OCSP_BASICRESP_get1_ext_d2i;
++ RSAPrivateKey_it;
++ RSAPrivateKey_it;
++ ENGINE_register_all_DH;
++ i2d_EDIPARTYNAME;
++ EC_POINT_get_affine_coordinates_GFp;
++ EC_POINT_get_affine_coords_GFp;
++ OCSP_CRLID_new;
++ ENGINE_get_flags;
++ OCSP_ONEREQ_it;
++ OCSP_ONEREQ_it;
++ UI_process;
++ ASN1_INTEGER_it;
++ ASN1_INTEGER_it;
++ EVP_CipherInit_ex;
++ UI_get_string_type;
++ ENGINE_unregister_DH;
++ ENGINE_register_all_DSA;
++ OCSP_ONEREQ_get_ext_by_critical;
++ bn_dup_expand;
++ OCSP_cert_id_new;
++ BASIC_CONSTRAINTS_it;
++ BASIC_CONSTRAINTS_it;
++ BN_mod_add_quick;
++ EC_POINT_new;
++ EVP_MD_CTX_destroy;
++ OCSP_RESPBYTES_free;
++ EVP_aes_128_cbc;
++ OCSP_SINGLERESP_get1_ext_d2i;
++ EC_POINT_free;
++ DH_up_ref;
++ X509_NAME_ENTRY_it;
++ X509_NAME_ENTRY_it;
++ UI_get_ex_new_index;
++ BN_mod_sub_quick;
++ OCSP_ONEREQ_add_ext;
++ OCSP_request_sign;
++ EVP_DigestFinal_ex;
++ ENGINE_set_digests;
++ OCSP_id_issuer_cmp;
++ OBJ_NAME_do_all;
++ EC_POINTs_mul;
++ ENGINE_register_complete;
++ X509V3_EXT_nconf_nid;
++ ASN1_SEQUENCE_it;
++ ASN1_SEQUENCE_it;
++ UI_set_default_method;
++ RAND_query_egd_bytes;
++ UI_method_get_writer;
++ UI_OpenSSL;
++ PEM_def_callback;
++ ENGINE_cleanup;
++ DIST_POINT_it;
++ DIST_POINT_it;
++ OCSP_SINGLERESP_it;
++ OCSP_SINGLERESP_it;
++ d2i_KRB5_TKTBODY;
++ EC_POINT_cmp;
++ OCSP_REVOKEDINFO_new;
++ i2d_OCSP_CERTSTATUS;
++ OCSP_basic_add1_nonce;
++ ASN1_item_ex_d2i;
++ BN_mod_lshift1_quick;
++ UI_set_method;
++ OCSP_id_get0_info;
++ BN_mod_sqrt;
++ EC_GROUP_copy;
++ KRB5_ENCDATA_free;
++ _ossl_old_des_cfb_encrypt;
++ OCSP_SINGLERESP_get_ext_by_OBJ;
++ OCSP_cert_to_id;
++ OCSP_RESPID_new;
++ OCSP_RESPDATA_it;
++ OCSP_RESPDATA_it;
++ d2i_OCSP_RESPDATA;
++ ENGINE_register_all_complete;
++ OCSP_check_validity;
++ PKCS12_BAGS_it;
++ PKCS12_BAGS_it;
++ OCSP_url_svcloc_new;
++ ASN1_template_free;
++ OCSP_SINGLERESP_add_ext;
++ KRB5_AUTHENTBODY_it;
++ KRB5_AUTHENTBODY_it;
++ X509_supported_extension;
++ i2d_KRB5_AUTHDATA;
++ UI_method_get_opener;
++ ENGINE_set_ex_data;
++ OCSP_REQUEST_print;
++ CBIGNUM_it;
++ CBIGNUM_it;
++ KRB5_TICKET_new;
++ KRB5_APREQ_new;
++ EC_GROUP_get_curve_GFp;
++ KRB5_ENCKEY_new;
++ ASN1_template_d2i;
++ _ossl_old_des_quad_cksum;
++ OCSP_single_get0_status;
++ BN_swap;
++ POLICYINFO_it;
++ POLICYINFO_it;
++ ENGINE_set_destroy_function;
++ asn1_enc_free;
++ OCSP_RESPID_it;
++ OCSP_RESPID_it;
++ EC_GROUP_new;
++ EVP_aes_256_cbc;
++ i2d_KRB5_PRINCNAME;
++ _ossl_old_des_encrypt2;
++ _ossl_old_des_encrypt3;
++ PKCS8_PRIV_KEY_INFO_it;
++ PKCS8_PRIV_KEY_INFO_it;
++ OCSP_REQINFO_it;
++ OCSP_REQINFO_it;
++ PBEPARAM_it;
++ PBEPARAM_it;
++ KRB5_AUTHENTBODY_new;
++ X509_CRL_add0_revoked;
++ EDIPARTYNAME_it;
++ EDIPARTYNAME_it;
++ NETSCAPE_SPKI_it;
++ NETSCAPE_SPKI_it;
++ UI_get0_test_string;
++ ENGINE_get_cipher_engine;
++ ENGINE_register_all_ciphers;
++ EC_POINT_copy;
++ BN_kronecker;
++ _ossl_old_des_ede3_ofb64_encrypt;
++ _ossl_odes_ede3_ofb64_encrypt;
++ UI_method_get_reader;
++ OCSP_BASICRESP_get_ext_count;
++ ASN1_ENUMERATED_it;
++ ASN1_ENUMERATED_it;
++ UI_set_result;
++ i2d_KRB5_TICKET;
++ X509_print_ex_fp;
++ EVP_CIPHER_CTX_set_padding;
++ d2i_OCSP_RESPONSE;
++ ASN1_UTCTIME_it;
++ ASN1_UTCTIME_it;
++ _ossl_old_des_enc_write;
++ OCSP_RESPONSE_new;
++ AES_set_encrypt_key;
++ OCSP_resp_count;
++ KRB5_CHECKSUM_new;
++ ENGINE_load_cswift;
++ OCSP_onereq_get0_id;
++ ENGINE_set_default_ciphers;
++ NOTICEREF_it;
++ NOTICEREF_it;
++ X509V3_EXT_CRL_add_nconf;
++ OCSP_REVOKEDINFO_it;
++ OCSP_REVOKEDINFO_it;
++ AES_encrypt;
++ OCSP_REQUEST_new;
++ ASN1_ANY_it;
++ ASN1_ANY_it;
++ CRYPTO_ex_data_new_class;
++ _ossl_old_des_ncbc_encrypt;
++ i2d_KRB5_TKTBODY;
++ EC_POINT_clear_free;
++ AES_decrypt;
++ asn1_enc_init;
++ UI_get_result_maxsize;
++ OCSP_CERTID_new;
++ ENGINE_unregister_RAND;
++ UI_method_get_closer;
++ d2i_KRB5_ENCDATA;
++ OCSP_request_onereq_count;
++ OCSP_basic_verify;
++ KRB5_AUTHENTBODY_free;
++ ASN1_item_d2i;
++ ASN1_primitive_free;
++ i2d_EXTENDED_KEY_USAGE;
++ i2d_OCSP_SIGNATURE;
++ asn1_enc_save;
++ ENGINE_load_nuron;
++ _ossl_old_des_pcbc_encrypt;
++ PKCS12_MAC_DATA_it;
++ PKCS12_MAC_DATA_it;
++ OCSP_accept_responses_new;
++ asn1_do_lock;
++ PKCS7_ATTR_VERIFY_it;
++ PKCS7_ATTR_VERIFY_it;
++ KRB5_APREQBODY_it;
++ KRB5_APREQBODY_it;
++ i2d_OCSP_SINGLERESP;
++ ASN1_item_ex_new;
++ UI_add_verify_string;
++ _ossl_old_des_set_key;
++ KRB5_PRINCNAME_it;
++ KRB5_PRINCNAME_it;
++ EVP_DecryptInit_ex;
++ i2d_OCSP_CERTID;
++ ASN1_item_d2i_bio;
++ EC_POINT_dbl;
++ asn1_get_choice_selector;
++ i2d_KRB5_CHECKSUM;
++ ENGINE_set_table_flags;
++ AES_options;
++ ENGINE_load_chil;
++ OCSP_id_cmp;
++ OCSP_BASICRESP_new;
++ OCSP_REQUEST_get_ext_by_NID;
++ KRB5_APREQ_it;
++ KRB5_APREQ_it;
++ ENGINE_get_destroy_function;
++ CONF_set_nconf;
++ ASN1_PRINTABLE_free;
++ OCSP_BASICRESP_get_ext_by_NID;
++ DIST_POINT_NAME_it;
++ DIST_POINT_NAME_it;
++ X509V3_extensions_print;
++ _ossl_old_des_cfb64_encrypt;
++ X509_REVOKED_add1_ext_i2d;
++ _ossl_old_des_ofb_encrypt;
++ KRB5_TKTBODY_new;
++ ASN1_OCTET_STRING_it;
++ ASN1_OCTET_STRING_it;
++ ERR_load_UI_strings;
++ i2d_KRB5_ENCKEY;
++ ASN1_template_new;
++ OCSP_SIGNATURE_free;
++ ASN1_item_i2d_fp;
++ KRB5_PRINCNAME_free;
++ PKCS7_RECIP_INFO_it;
++ PKCS7_RECIP_INFO_it;
++ EXTENDED_KEY_USAGE_it;
++ EXTENDED_KEY_USAGE_it;
++ EC_GFp_simple_method;
++ EC_GROUP_precompute_mult;
++ OCSP_request_onereq_get0;
++ UI_method_set_writer;
++ KRB5_AUTHENT_new;
++ X509_CRL_INFO_it;
++ X509_CRL_INFO_it;
++ DSO_set_name_converter;
++ AES_set_decrypt_key;
++ PKCS7_DIGEST_it;
++ PKCS7_DIGEST_it;
++ PKCS12_x5092certbag;
++ EVP_DigestInit_ex;
++ i2a_ACCESS_DESCRIPTION;
++ OCSP_RESPONSE_it;
++ OCSP_RESPONSE_it;
++ PKCS7_ENC_CONTENT_it;
++ PKCS7_ENC_CONTENT_it;
++ OCSP_request_add0_id;
++ EC_POINT_make_affine;
++ DSO_get_filename;
++ OCSP_CERTSTATUS_it;
++ OCSP_CERTSTATUS_it;
++ OCSP_request_add1_cert;
++ UI_get0_output_string;
++ UI_dup_verify_string;
++ BN_mod_lshift;
++ KRB5_AUTHDATA_it;
++ KRB5_AUTHDATA_it;
++ asn1_set_choice_selector;
++ OCSP_basic_add1_status;
++ OCSP_RESPID_free;
++ asn1_get_field_ptr;
++ UI_add_input_string;
++ OCSP_CRLID_it;
++ OCSP_CRLID_it;
++ i2d_KRB5_AUTHENTBODY;
++ OCSP_REQUEST_get_ext_count;
++ ENGINE_load_atalla;
++ X509_NAME_it;
++ X509_NAME_it;
++ USERNOTICE_it;
++ USERNOTICE_it;
++ OCSP_REQINFO_new;
++ OCSP_BASICRESP_get_ext;
++ CRYPTO_get_ex_data_implementation;
++ CRYPTO_get_ex_data_impl;
++ ASN1_item_pack;
++ i2d_KRB5_ENCDATA;
++ X509_PURPOSE_set;
++ X509_REQ_INFO_it;
++ X509_REQ_INFO_it;
++ UI_method_set_opener;
++ ASN1_item_ex_free;
++ ASN1_BOOLEAN_it;
++ ASN1_BOOLEAN_it;
++ ENGINE_get_table_flags;
++ UI_create_method;
++ OCSP_ONEREQ_add1_ext_i2d;
++ _shadow_DES_check_key;
++ _shadow_DES_check_key;
++ d2i_OCSP_REQINFO;
++ UI_add_info_string;
++ UI_get_result_minsize;
++ ASN1_NULL_it;
++ ASN1_NULL_it;
++ BN_mod_lshift1;
++ d2i_OCSP_ONEREQ;
++ OCSP_ONEREQ_new;
++ KRB5_TICKET_it;
++ KRB5_TICKET_it;
++ EVP_aes_192_cbc;
++ KRB5_TICKET_free;
++ UI_new;
++ OCSP_response_create;
++ _ossl_old_des_xcbc_encrypt;
++ PKCS7_it;
++ PKCS7_it;
++ OCSP_REQUEST_get_ext_by_critical;
++ OCSP_REQUEST_get_ext_by_crit;
++ ENGINE_set_flags;
++ _ossl_old_des_ecb_encrypt;
++ OCSP_response_get1_basic;
++ EVP_Digest;
++ OCSP_ONEREQ_delete_ext;
++ ASN1_TBOOLEAN_it;
++ ASN1_TBOOLEAN_it;
++ ASN1_item_new;
++ ASN1_TIME_to_generalizedtime;
++ BIGNUM_it;
++ BIGNUM_it;
++ AES_cbc_encrypt;
++ ENGINE_get_load_privkey_function;
++ ENGINE_get_load_privkey_fn;
++ OCSP_RESPONSE_free;
++ UI_method_set_reader;
++ i2d_ASN1_T61STRING;
++ EC_POINT_set_to_infinity;
++ ERR_load_OCSP_strings;
++ EC_POINT_point2oct;
++ KRB5_APREQ_free;
++ ASN1_OBJECT_it;
++ ASN1_OBJECT_it;
++ OCSP_crlID_new;
++ OCSP_crlID2_new;
++ CONF_modules_load_file;
++ CONF_imodule_set_usr_data;
++ ENGINE_set_default_string;
++ CONF_module_get_usr_data;
++ ASN1_add_oid_module;
++ CONF_modules_finish;
++ OPENSSL_config;
++ CONF_modules_unload;
++ CONF_imodule_get_value;
++ CONF_module_set_usr_data;
++ CONF_parse_list;
++ CONF_module_add;
++ CONF_get1_default_config_file;
++ CONF_imodule_get_flags;
++ CONF_imodule_get_module;
++ CONF_modules_load;
++ CONF_imodule_get_name;
++ ERR_peek_top_error;
++ CONF_imodule_get_usr_data;
++ CONF_imodule_set_flags;
++ ENGINE_add_conf_module;
++ ERR_peek_last_error_line;
++ ERR_peek_last_error_line_data;
++ ERR_peek_last_error;
++ DES_read_2passwords;
++ DES_read_password;
++ UI_UTIL_read_pw;
++ UI_UTIL_read_pw_string;
++ ENGINE_load_aep;
++ ENGINE_load_sureware;
++ OPENSSL_add_all_algorithms_noconf;
++ OPENSSL_add_all_algo_noconf;
++ OPENSSL_add_all_algorithms_conf;
++ OPENSSL_add_all_algo_conf;
++ OPENSSL_load_builtin_modules;
++ AES_ofb128_encrypt;
++ AES_ctr128_encrypt;
++ AES_cfb128_encrypt;
++ ENGINE_load_4758cca;
++ _ossl_096_des_random_seed;
++ EVP_aes_256_ofb;
++ EVP_aes_192_ofb;
++ EVP_aes_128_cfb128;
++ EVP_aes_256_cfb128;
++ EVP_aes_128_ofb;
++ EVP_aes_192_cfb128;
++ CONF_modules_free;
++ NCONF_default;
++ OPENSSL_no_config;
++ NCONF_WIN32;
++ ASN1_UNIVERSALSTRING_new;
++ EVP_des_ede_ecb;
++ i2d_ASN1_UNIVERSALSTRING;
++ ASN1_UNIVERSALSTRING_free;
++ ASN1_UNIVERSALSTRING_it;
++ ASN1_UNIVERSALSTRING_it;
++ d2i_ASN1_UNIVERSALSTRING;
++ EVP_des_ede3_ecb;
++ X509_REQ_print_ex;
++ ENGINE_up_ref;
++ BUF_MEM_grow_clean;
++ CRYPTO_realloc_clean;
++ BUF_strlcat;
++ BIO_indent;
++ BUF_strlcpy;
++ OpenSSLDie;
++ OPENSSL_cleanse;
++ ENGINE_setup_bsd_cryptodev;
++ ERR_release_err_state_table;
++ EVP_aes_128_cfb8;
++ FIPS_corrupt_rsa;
++ FIPS_selftest_des;
++ EVP_aes_128_cfb1;
++ EVP_aes_192_cfb8;
++ FIPS_mode_set;
++ FIPS_selftest_dsa;
++ EVP_aes_256_cfb8;
++ FIPS_allow_md5;
++ DES_ede3_cfb_encrypt;
++ EVP_des_ede3_cfb8;
++ FIPS_rand_seeded;
++ AES_cfbr_encrypt_block;
++ AES_cfb8_encrypt;
++ FIPS_rand_seed;
++ FIPS_corrupt_des;
++ EVP_aes_192_cfb1;
++ FIPS_selftest_aes;
++ FIPS_set_prng_key;
++ EVP_des_cfb8;
++ FIPS_corrupt_dsa;
++ FIPS_test_mode;
++ FIPS_rand_method;
++ EVP_aes_256_cfb1;
++ ERR_load_FIPS_strings;
++ FIPS_corrupt_aes;
++ FIPS_selftest_sha1;
++ FIPS_selftest_rsa;
++ FIPS_corrupt_sha1;
++ EVP_des_cfb1;
++ FIPS_dsa_check;
++ AES_cfb1_encrypt;
++ EVP_des_ede3_cfb1;
++ FIPS_rand_check;
++ FIPS_md5_allowed;
++ FIPS_mode;
++ FIPS_selftest_failed;
++ sk_is_sorted;
++ X509_check_ca;
++ HMAC_CTX_set_flags;
++ d2i_PROXY_CERT_INFO_EXTENSION;
++ PROXY_POLICY_it;
++ PROXY_POLICY_it;
++ i2d_PROXY_POLICY;
++ i2d_PROXY_CERT_INFO_EXTENSION;
++ d2i_PROXY_POLICY;
++ PROXY_CERT_INFO_EXTENSION_new;
++ PROXY_CERT_INFO_EXTENSION_free;
++ PROXY_CERT_INFO_EXTENSION_it;
++ PROXY_CERT_INFO_EXTENSION_it;
++ PROXY_POLICY_free;
++ PROXY_POLICY_new;
++ BN_MONT_CTX_set_locked;
++ FIPS_selftest_rng;
++ EVP_sha384;
++ EVP_sha512;
++ EVP_sha224;
++ EVP_sha256;
++ FIPS_selftest_hmac;
++ FIPS_corrupt_rng;
++ BN_mod_exp_mont_consttime;
++ RSA_X931_hash_id;
++ RSA_padding_check_X931;
++ RSA_verify_PKCS1_PSS;
++ RSA_padding_add_X931;
++ RSA_padding_add_PKCS1_PSS;
++ PKCS1_MGF1;
++ BN_X931_generate_Xpq;
++ RSA_X931_generate_key;
++ BN_X931_derive_prime;
++ BN_X931_generate_prime;
++ RSA_X931_derive;
++ BIO_new_dgram;
++ BN_get0_nist_prime_384;
++ ERR_set_mark;
++ X509_STORE_CTX_set0_crls;
++ ENGINE_set_STORE;
++ ENGINE_register_ECDSA;
++ STORE_meth_set_list_start_fn;
++ STORE_method_set_list_start_function;
++ BN_BLINDING_invert_ex;
++ NAME_CONSTRAINTS_free;
++ STORE_ATTR_INFO_set_number;
++ BN_BLINDING_get_thread_id;
++ X509_STORE_CTX_set0_param;
++ POLICY_MAPPING_it;
++ POLICY_MAPPING_it;
++ STORE_parse_attrs_start;
++ POLICY_CONSTRAINTS_free;
++ EVP_PKEY_add1_attr_by_NID;
++ BN_nist_mod_192;
++ EC_GROUP_get_trinomial_basis;
++ STORE_set_method;
++ GENERAL_SUBTREE_free;
++ NAME_CONSTRAINTS_it;
++ NAME_CONSTRAINTS_it;
++ ECDH_get_default_method;
++ PKCS12_add_safe;
++ EC_KEY_new_by_curve_name;
++ STORE_meth_get_update_store_fn;
++ STORE_method_get_update_store_function;
++ ENGINE_register_ECDH;
++ SHA512_Update;
++ i2d_ECPrivateKey;
++ BN_get0_nist_prime_192;
++ STORE_modify_certificate;
++ EC_POINT_set_affine_coordinates_GF2m;
++ EC_POINT_set_affine_coords_GF2m;
++ BN_GF2m_mod_exp_arr;
++ STORE_ATTR_INFO_modify_number;
++ X509_keyid_get0;
++ ENGINE_load_gmp;
++ pitem_new;
++ BN_GF2m_mod_mul_arr;
++ STORE_list_public_key_endp;
++ o2i_ECPublicKey;
++ EC_KEY_copy;
++ BIO_dump_fp;
++ X509_policy_node_get0_parent;
++ EC_GROUP_check_discriminant;
++ i2o_ECPublicKey;
++ EC_KEY_precompute_mult;
++ a2i_IPADDRESS;
++ STORE_meth_set_initialise_fn;
++ STORE_method_set_initialise_function;
++ X509_STORE_CTX_set_depth;
++ X509_VERIFY_PARAM_inherit;
++ EC_POINT_point2bn;
++ STORE_ATTR_INFO_set_dn;
++ X509_policy_tree_get0_policies;
++ EC_GROUP_new_curve_GF2m;
++ STORE_destroy_method;
++ ENGINE_unregister_STORE;
++ EVP_PKEY_get1_EC_KEY;
++ STORE_ATTR_INFO_get0_number;
++ ENGINE_get_default_ECDH;
++ EC_KEY_get_conv_form;
++ ASN1_OCTET_STRING_NDEF_it;
++ ASN1_OCTET_STRING_NDEF_it;
++ STORE_delete_public_key;
++ STORE_get_public_key;
++ STORE_modify_arbitrary;
++ ENGINE_get_static_state;
++ pqueue_iterator;
++ ECDSA_SIG_new;
++ OPENSSL_DIR_end;
++ BN_GF2m_mod_sqr;
++ EC_POINT_bn2point;
++ X509_VERIFY_PARAM_set_depth;
++ EC_KEY_set_asn1_flag;
++ STORE_get_method;
++ EC_KEY_get_key_method_data;
++ ECDSA_sign_ex;
++ STORE_parse_attrs_end;
++ EC_GROUP_get_point_conversion_form;
++ EC_GROUP_get_point_conv_form;
++ STORE_method_set_store_function;
++ STORE_ATTR_INFO_in;
++ PEM_read_bio_ECPKParameters;
++ EC_GROUP_get_pentanomial_basis;
++ EVP_PKEY_add1_attr_by_txt;
++ BN_BLINDING_set_flags;
++ X509_VERIFY_PARAM_set1_policies;
++ X509_VERIFY_PARAM_set1_name;
++ X509_VERIFY_PARAM_set_purpose;
++ STORE_get_number;
++ ECDSA_sign_setup;
++ BN_GF2m_mod_solve_quad_arr;
++ EC_KEY_up_ref;
++ POLICY_MAPPING_free;
++ BN_GF2m_mod_div;
++ X509_VERIFY_PARAM_set_flags;
++ EC_KEY_free;
++ STORE_meth_set_list_next_fn;
++ STORE_method_set_list_next_function;
++ PEM_write_bio_ECPrivateKey;
++ d2i_EC_PUBKEY;
++ STORE_meth_get_generate_fn;
++ STORE_method_get_generate_function;
++ STORE_meth_set_list_end_fn;
++ STORE_method_set_list_end_function;
++ pqueue_print;
++ EC_GROUP_have_precompute_mult;
++ EC_KEY_print_fp;
++ BN_GF2m_mod_arr;
++ PEM_write_bio_X509_CERT_PAIR;
++ EVP_PKEY_cmp;
++ X509_policy_level_node_count;
++ STORE_new_engine;
++ STORE_list_public_key_start;
++ X509_VERIFY_PARAM_new;
++ ECDH_get_ex_data;
++ EVP_PKEY_get_attr;
++ ECDSA_do_sign;
++ ENGINE_unregister_ECDH;
++ ECDH_OpenSSL;
++ EC_KEY_set_conv_form;
++ EC_POINT_dup;
++ GENERAL_SUBTREE_new;
++ STORE_list_crl_endp;
++ EC_get_builtin_curves;
++ X509_policy_node_get0_qualifiers;
++ X509_pcy_node_get0_qualifiers;
++ STORE_list_crl_end;
++ EVP_PKEY_set1_EC_KEY;
++ BN_GF2m_mod_sqrt_arr;
++ i2d_ECPrivateKey_bio;
++ ECPKParameters_print_fp;
++ pqueue_find;
++ ECDSA_SIG_free;
++ PEM_write_bio_ECPKParameters;
++ STORE_method_set_ctrl_function;
++ STORE_list_public_key_end;
++ EC_KEY_set_private_key;
++ pqueue_peek;
++ STORE_get_arbitrary;
++ STORE_store_crl;
++ X509_policy_node_get0_policy;
++ PKCS12_add_safes;
++ BN_BLINDING_convert_ex;
++ X509_policy_tree_free;
++ OPENSSL_ia32cap_loc;
++ BN_GF2m_poly2arr;
++ STORE_ctrl;
++ STORE_ATTR_INFO_compare;
++ BN_get0_nist_prime_224;
++ i2d_ECParameters;
++ i2d_ECPKParameters;
++ BN_GENCB_call;
++ d2i_ECPKParameters;
++ STORE_meth_set_generate_fn;
++ STORE_method_set_generate_function;
++ ENGINE_set_ECDH;
++ NAME_CONSTRAINTS_new;
++ SHA256_Init;
++ EC_KEY_get0_public_key;
++ PEM_write_bio_EC_PUBKEY;
++ STORE_ATTR_INFO_set_cstr;
++ STORE_list_crl_next;
++ STORE_ATTR_INFO_in_range;
++ ECParameters_print;
++ STORE_meth_set_delete_fn;
++ STORE_method_set_delete_function;
++ STORE_list_certificate_next;
++ ASN1_generate_nconf;
++ BUF_memdup;
++ BN_GF2m_mod_mul;
++ STORE_meth_get_list_next_fn;
++ STORE_method_get_list_next_function;
++ STORE_ATTR_INFO_get0_dn;
++ STORE_list_private_key_next;
++ EC_GROUP_set_seed;
++ X509_VERIFY_PARAM_set_trust;
++ STORE_ATTR_INFO_free;
++ STORE_get_private_key;
++ EVP_PKEY_get_attr_count;
++ STORE_ATTR_INFO_new;
++ EC_GROUP_get_curve_GF2m;
++ STORE_meth_set_revoke_fn;
++ STORE_method_set_revoke_function;
++ STORE_store_number;
++ BN_is_prime_ex;
++ STORE_revoke_public_key;
++ X509_STORE_CTX_get0_param;
++ STORE_delete_arbitrary;
++ PEM_read_X509_CERT_PAIR;
++ X509_STORE_set_depth;
++ ECDSA_get_ex_data;
++ SHA224;
++ BIO_dump_indent_fp;
++ EC_KEY_set_group;
++ BUF_strndup;
++ STORE_list_certificate_start;
++ BN_GF2m_mod;
++ X509_REQ_check_private_key;
++ EC_GROUP_get_seed_len;
++ ERR_load_STORE_strings;
++ PEM_read_bio_EC_PUBKEY;
++ STORE_list_private_key_end;
++ i2d_EC_PUBKEY;
++ ECDSA_get_default_method;
++ ASN1_put_eoc;
++ X509_STORE_CTX_get_explicit_policy;
++ X509_STORE_CTX_get_expl_policy;
++ X509_VERIFY_PARAM_table_cleanup;
++ STORE_modify_private_key;
++ X509_VERIFY_PARAM_free;
++ EC_METHOD_get_field_type;
++ EC_GFp_nist_method;
++ STORE_meth_set_modify_fn;
++ STORE_method_set_modify_function;
++ STORE_parse_attrs_next;
++ ENGINE_load_padlock;
++ EC_GROUP_set_curve_name;
++ X509_CERT_PAIR_it;
++ X509_CERT_PAIR_it;
++ STORE_meth_get_revoke_fn;
++ STORE_method_get_revoke_function;
++ STORE_method_set_get_function;
++ STORE_modify_number;
++ STORE_method_get_store_function;
++ STORE_store_private_key;
++ BN_GF2m_mod_sqr_arr;
++ RSA_setup_blinding;
++ BIO_s_datagram;
++ STORE_Memory;
++ sk_find_ex;
++ EC_GROUP_set_curve_GF2m;
++ ENGINE_set_default_ECDSA;
++ POLICY_CONSTRAINTS_new;
++ BN_GF2m_mod_sqrt;
++ ECDH_set_default_method;
++ EC_KEY_generate_key;
++ SHA384_Update;
++ BN_GF2m_arr2poly;
++ STORE_method_get_get_function;
++ STORE_meth_set_cleanup_fn;
++ STORE_method_set_cleanup_function;
++ EC_GROUP_check;
++ d2i_ECPrivateKey_bio;
++ EC_KEY_insert_key_method_data;
++ STORE_meth_get_lock_store_fn;
++ STORE_method_get_lock_store_function;
++ X509_VERIFY_PARAM_get_depth;
++ SHA224_Final;
++ STORE_meth_set_update_store_fn;
++ STORE_method_set_update_store_function;
++ SHA224_Update;
++ d2i_ECPrivateKey;
++ ASN1_item_ndef_i2d;
++ STORE_delete_private_key;
++ ERR_pop_to_mark;
++ ENGINE_register_all_STORE;
++ X509_policy_level_get0_node;
++ i2d_PKCS7_NDEF;
++ EC_GROUP_get_degree;
++ ASN1_generate_v3;
++ STORE_ATTR_INFO_modify_cstr;
++ X509_policy_tree_level_count;
++ BN_GF2m_add;
++ EC_KEY_get0_group;
++ STORE_generate_crl;
++ STORE_store_public_key;
++ X509_CERT_PAIR_free;
++ STORE_revoke_private_key;
++ BN_nist_mod_224;
++ SHA512_Final;
++ STORE_ATTR_INFO_modify_dn;
++ STORE_meth_get_initialise_fn;
++ STORE_method_get_initialise_function;
++ STORE_delete_number;
++ i2d_EC_PUBKEY_bio;
++ BIO_dgram_non_fatal_error;
++ EC_GROUP_get_asn1_flag;
++ STORE_ATTR_INFO_in_ex;
++ STORE_list_crl_start;
++ ECDH_get_ex_new_index;
++ STORE_meth_get_modify_fn;
++ STORE_method_get_modify_function;
++ v2i_ASN1_BIT_STRING;
++ STORE_store_certificate;
++ OBJ_bsearch_ex;
++ X509_STORE_CTX_set_default;
++ STORE_ATTR_INFO_set_sha1str;
++ BN_GF2m_mod_inv;
++ BN_GF2m_mod_exp;
++ STORE_modify_public_key;
++ STORE_meth_get_list_start_fn;
++ STORE_method_get_list_start_function;
++ EC_GROUP_get0_seed;
++ STORE_store_arbitrary;
++ STORE_meth_set_unlock_store_fn;
++ STORE_method_set_unlock_store_function;
++ BN_GF2m_mod_div_arr;
++ ENGINE_set_ECDSA;
++ STORE_create_method;
++ ECPKParameters_print;
++ EC_KEY_get0_private_key;
++ PEM_write_EC_PUBKEY;
++ X509_VERIFY_PARAM_set1;
++ ECDH_set_method;
++ v2i_GENERAL_NAME_ex;
++ ECDH_set_ex_data;
++ STORE_generate_key;
++ BN_nist_mod_521;
++ X509_policy_tree_get0_level;
++ EC_GROUP_set_point_conversion_form;
++ EC_GROUP_set_point_conv_form;
++ PEM_read_EC_PUBKEY;
++ i2d_ECDSA_SIG;
++ ECDSA_OpenSSL;
++ STORE_delete_crl;
++ EC_KEY_get_enc_flags;
++ ASN1_const_check_infinite_end;
++ EVP_PKEY_delete_attr;
++ ECDSA_set_default_method;
++ EC_POINT_set_compressed_coordinates_GF2m;
++ EC_POINT_set_compr_coords_GF2m;
++ EC_GROUP_cmp;
++ STORE_revoke_certificate;
++ BN_get0_nist_prime_256;
++ STORE_meth_get_delete_fn;
++ STORE_method_get_delete_function;
++ SHA224_Init;
++ PEM_read_ECPrivateKey;
++ SHA512_Init;
++ STORE_parse_attrs_endp;
++ BN_set_negative;
++ ERR_load_ECDSA_strings;
++ EC_GROUP_get_basis_type;
++ STORE_list_public_key_next;
++ i2v_ASN1_BIT_STRING;
++ STORE_OBJECT_free;
++ BN_nist_mod_384;
++ i2d_X509_CERT_PAIR;
++ PEM_write_ECPKParameters;
++ ECDH_compute_key;
++ STORE_ATTR_INFO_get0_sha1str;
++ ENGINE_register_all_ECDH;
++ pqueue_pop;
++ STORE_ATTR_INFO_get0_cstr;
++ POLICY_CONSTRAINTS_it;
++ POLICY_CONSTRAINTS_it;
++ STORE_get_ex_new_index;
++ EVP_PKEY_get_attr_by_OBJ;
++ X509_VERIFY_PARAM_add0_policy;
++ BN_GF2m_mod_solve_quad;
++ SHA256;
++ i2d_ECPrivateKey_fp;
++ X509_policy_tree_get0_user_policies;
++ X509_pcy_tree_get0_usr_policies;
++ OPENSSL_DIR_read;
++ ENGINE_register_all_ECDSA;
++ X509_VERIFY_PARAM_lookup;
++ EC_POINT_get_affine_coordinates_GF2m;
++ EC_POINT_get_affine_coords_GF2m;
++ EC_GROUP_dup;
++ ENGINE_get_default_ECDSA;
++ EC_KEY_new;
++ SHA256_Transform;
++ EC_KEY_set_enc_flags;
++ ECDSA_verify;
++ EC_POINT_point2hex;
++ ENGINE_get_STORE;
++ SHA512;
++ STORE_get_certificate;
++ ECDSA_do_sign_ex;
++ ECDSA_do_verify;
++ d2i_ECPrivateKey_fp;
++ STORE_delete_certificate;
++ SHA512_Transform;
++ X509_STORE_set1_param;
++ STORE_method_get_ctrl_function;
++ STORE_free;
++ PEM_write_ECPrivateKey;
++ STORE_meth_get_unlock_store_fn;
++ STORE_method_get_unlock_store_function;
++ STORE_get_ex_data;
++ EC_KEY_set_public_key;
++ PEM_read_ECPKParameters;
++ X509_CERT_PAIR_new;
++ ENGINE_register_STORE;
++ RSA_generate_key_ex;
++ DSA_generate_parameters_ex;
++ ECParameters_print_fp;
++ X509V3_NAME_from_section;
++ EVP_PKEY_add1_attr;
++ STORE_modify_crl;
++ STORE_list_private_key_start;
++ POLICY_MAPPINGS_it;
++ POLICY_MAPPINGS_it;
++ GENERAL_SUBTREE_it;
++ GENERAL_SUBTREE_it;
++ EC_GROUP_get_curve_name;
++ PEM_write_X509_CERT_PAIR;
++ BIO_dump_indent_cb;
++ d2i_X509_CERT_PAIR;
++ STORE_list_private_key_endp;
++ asn1_const_Finish;
++ i2d_EC_PUBKEY_fp;
++ BN_nist_mod_256;
++ X509_VERIFY_PARAM_add0_table;
++ pqueue_free;
++ BN_BLINDING_create_param;
++ ECDSA_size;
++ d2i_EC_PUBKEY_bio;
++ BN_get0_nist_prime_521;
++ STORE_ATTR_INFO_modify_sha1str;
++ BN_generate_prime_ex;
++ EC_GROUP_new_by_curve_name;
++ SHA256_Final;
++ DH_generate_parameters_ex;
++ PEM_read_bio_ECPrivateKey;
++ STORE_meth_get_cleanup_fn;
++ STORE_method_get_cleanup_function;
++ ENGINE_get_ECDH;
++ d2i_ECDSA_SIG;
++ BN_is_prime_fasttest_ex;
++ ECDSA_sign;
++ X509_policy_check;
++ EVP_PKEY_get_attr_by_NID;
++ STORE_set_ex_data;
++ ENGINE_get_ECDSA;
++ EVP_ecdsa;
++ BN_BLINDING_get_flags;
++ PKCS12_add_cert;
++ STORE_OBJECT_new;
++ ERR_load_ECDH_strings;
++ EC_KEY_dup;
++ EVP_CIPHER_CTX_rand_key;
++ ECDSA_set_method;
++ a2i_IPADDRESS_NC;
++ d2i_ECParameters;
++ STORE_list_certificate_end;
++ STORE_get_crl;
++ X509_POLICY_NODE_print;
++ SHA384_Init;
++ EC_GF2m_simple_method;
++ ECDSA_set_ex_data;
++ SHA384_Final;
++ PKCS7_set_digest;
++ EC_KEY_print;
++ STORE_meth_set_lock_store_fn;
++ STORE_method_set_lock_store_function;
++ ECDSA_get_ex_new_index;
++ SHA384;
++ POLICY_MAPPING_new;
++ STORE_list_certificate_endp;
++ X509_STORE_CTX_get0_policy_tree;
++ EC_GROUP_set_asn1_flag;
++ EC_KEY_check_key;
++ d2i_EC_PUBKEY_fp;
++ PKCS7_set0_type_other;
++ PEM_read_bio_X509_CERT_PAIR;
++ pqueue_next;
++ STORE_meth_get_list_end_fn;
++ STORE_method_get_list_end_function;
++ EVP_PKEY_add1_attr_by_OBJ;
++ X509_VERIFY_PARAM_set_time;
++ pqueue_new;
++ ENGINE_set_default_ECDH;
++ STORE_new_method;
++ PKCS12_add_key;
++ DSO_merge;
++ EC_POINT_hex2point;
++ BIO_dump_cb;
++ SHA256_Update;
++ pqueue_insert;
++ pitem_free;
++ BN_GF2m_mod_inv_arr;
++ ENGINE_unregister_ECDSA;
++ BN_BLINDING_set_thread_id;
++ get_rfc3526_prime_8192;
++ X509_VERIFY_PARAM_clear_flags;
++ get_rfc2409_prime_1024;
++ DH_check_pub_key;
++ get_rfc3526_prime_2048;
++ get_rfc3526_prime_6144;
++ get_rfc3526_prime_1536;
++ get_rfc3526_prime_3072;
++ get_rfc3526_prime_4096;
++ get_rfc2409_prime_768;
++ X509_VERIFY_PARAM_get_flags;
++ EVP_CIPHER_CTX_new;
++ EVP_CIPHER_CTX_free;
++ Camellia_cbc_encrypt;
++ Camellia_cfb128_encrypt;
++ Camellia_cfb1_encrypt;
++ Camellia_cfb8_encrypt;
++ Camellia_ctr128_encrypt;
++ Camellia_cfbr_encrypt_block;
++ Camellia_decrypt;
++ Camellia_ecb_encrypt;
++ Camellia_encrypt;
++ Camellia_ofb128_encrypt;
++ Camellia_set_key;
++ EVP_camellia_128_cbc;
++ EVP_camellia_128_cfb128;
++ EVP_camellia_128_cfb1;
++ EVP_camellia_128_cfb8;
++ EVP_camellia_128_ecb;
++ EVP_camellia_128_ofb;
++ EVP_camellia_192_cbc;
++ EVP_camellia_192_cfb128;
++ EVP_camellia_192_cfb1;
++ EVP_camellia_192_cfb8;
++ EVP_camellia_192_ecb;
++ EVP_camellia_192_ofb;
++ EVP_camellia_256_cbc;
++ EVP_camellia_256_cfb128;
++ EVP_camellia_256_cfb1;
++ EVP_camellia_256_cfb8;
++ EVP_camellia_256_ecb;
++ EVP_camellia_256_ofb;
++ a2i_ipadd;
++ ASIdentifiers_free;
++ i2d_ASIdOrRange;
++ EVP_CIPHER_block_size;
++ v3_asid_is_canonical;
++ IPAddressChoice_free;
++ EVP_CIPHER_CTX_set_app_data;
++ BIO_set_callback_arg;
++ v3_addr_add_prefix;
++ IPAddressOrRange_it;
++ IPAddressOrRange_it;
++ BIO_set_flags;
++ ASIdentifiers_it;
++ ASIdentifiers_it;
++ v3_addr_get_range;
++ BIO_method_type;
++ v3_addr_inherits;
++ IPAddressChoice_it;
++ IPAddressChoice_it;
++ AES_ige_encrypt;
++ v3_addr_add_range;
++ EVP_CIPHER_CTX_nid;
++ d2i_ASRange;
++ v3_addr_add_inherit;
++ v3_asid_add_id_or_range;
++ v3_addr_validate_resource_set;
++ EVP_CIPHER_iv_length;
++ EVP_MD_type;
++ v3_asid_canonize;
++ IPAddressRange_free;
++ v3_asid_add_inherit;
++ EVP_CIPHER_CTX_key_length;
++ IPAddressRange_new;
++ ASIdOrRange_new;
++ EVP_MD_size;
++ EVP_MD_CTX_test_flags;
++ BIO_clear_flags;
++ i2d_ASRange;
++ IPAddressRange_it;
++ IPAddressRange_it;
++ IPAddressChoice_new;
++ ASIdentifierChoice_new;
++ ASRange_free;
++ EVP_MD_pkey_type;
++ EVP_MD_CTX_clear_flags;
++ IPAddressFamily_free;
++ i2d_IPAddressFamily;
++ IPAddressOrRange_new;
++ EVP_CIPHER_flags;
++ v3_asid_validate_resource_set;
++ d2i_IPAddressRange;
++ AES_bi_ige_encrypt;
++ BIO_get_callback;
++ IPAddressOrRange_free;
++ v3_addr_subset;
++ d2i_IPAddressFamily;
++ v3_asid_subset;
++ BIO_test_flags;
++ i2d_ASIdentifierChoice;
++ ASRange_it;
++ ASRange_it;
++ d2i_ASIdentifiers;
++ ASRange_new;
++ d2i_IPAddressChoice;
++ v3_addr_get_afi;
++ EVP_CIPHER_key_length;
++ EVP_Cipher;
++ i2d_IPAddressOrRange;
++ ASIdOrRange_it;
++ ASIdOrRange_it;
++ EVP_CIPHER_nid;
++ i2d_IPAddressChoice;
++ EVP_CIPHER_CTX_block_size;
++ ASIdentifiers_new;
++ v3_addr_validate_path;
++ IPAddressFamily_new;
++ EVP_MD_CTX_set_flags;
++ v3_addr_is_canonical;
++ i2d_IPAddressRange;
++ IPAddressFamily_it;
++ IPAddressFamily_it;
++ v3_asid_inherits;
++ EVP_CIPHER_CTX_cipher;
++ EVP_CIPHER_CTX_get_app_data;
++ EVP_MD_block_size;
++ EVP_CIPHER_CTX_flags;
++ v3_asid_validate_path;
++ d2i_IPAddressOrRange;
++ v3_addr_canonize;
++ ASIdentifierChoice_it;
++ ASIdentifierChoice_it;
++ EVP_MD_CTX_md;
++ d2i_ASIdentifierChoice;
++ BIO_method_name;
++ EVP_CIPHER_CTX_iv_length;
++ ASIdOrRange_free;
++ ASIdentifierChoice_free;
++ BIO_get_callback_arg;
++ BIO_set_callback;
++ d2i_ASIdOrRange;
++ i2d_ASIdentifiers;
++ SEED_decrypt;
++ SEED_encrypt;
++ SEED_cbc_encrypt;
++ EVP_seed_ofb;
++ SEED_cfb128_encrypt;
++ SEED_ofb128_encrypt;
++ EVP_seed_cbc;
++ SEED_ecb_encrypt;
++ EVP_seed_ecb;
++ SEED_set_key;
++ EVP_seed_cfb128;
++ X509_EXTENSIONS_it;
++ X509_EXTENSIONS_it;
++ X509_get1_ocsp;
++ OCSP_REQ_CTX_free;
++ i2d_X509_EXTENSIONS;
++ OCSP_sendreq_nbio;
++ OCSP_sendreq_new;
++ d2i_X509_EXTENSIONS;
++ X509_ALGORS_it;
++ X509_ALGORS_it;
++ X509_ALGOR_get0;
++ X509_ALGOR_set0;
++ AES_unwrap_key;
++ AES_wrap_key;
++ X509at_get0_data_by_OBJ;
++ ASN1_TYPE_set1;
++ ASN1_STRING_set0;
++ i2d_X509_ALGORS;
++ BIO_f_zlib;
++ COMP_zlib_cleanup;
++ d2i_X509_ALGORS;
++ CMS_ReceiptRequest_free;
++ PEM_write_CMS;
++ CMS_add0_CertificateChoices;
++ CMS_unsigned_add1_attr_by_OBJ;
++ ERR_load_CMS_strings;
++ CMS_sign_receipt;
++ i2d_CMS_ContentInfo;
++ CMS_signed_delete_attr;
++ d2i_CMS_bio;
++ CMS_unsigned_get_attr_by_NID;
++ CMS_verify;
++ SMIME_read_CMS;
++ CMS_decrypt_set1_key;
++ CMS_SignerInfo_get0_algs;
++ CMS_add1_cert;
++ CMS_set_detached;
++ CMS_encrypt;
++ CMS_EnvelopedData_create;
++ CMS_uncompress;
++ CMS_add0_crl;
++ CMS_SignerInfo_verify_content;
++ CMS_unsigned_get0_data_by_OBJ;
++ PEM_write_bio_CMS;
++ CMS_unsigned_get_attr;
++ CMS_RecipientInfo_ktri_cert_cmp;
++ CMS_RecipientInfo_ktri_get0_algs;
++ CMS_RecipInfo_ktri_get0_algs;
++ CMS_ContentInfo_free;
++ CMS_final;
++ CMS_add_simple_smimecap;
++ CMS_SignerInfo_verify;
++ CMS_data;
++ CMS_ContentInfo_it;
++ CMS_ContentInfo_it;
++ d2i_CMS_ReceiptRequest;
++ CMS_compress;
++ CMS_digest_create;
++ CMS_SignerInfo_cert_cmp;
++ CMS_SignerInfo_sign;
++ CMS_data_create;
++ i2d_CMS_bio;
++ CMS_EncryptedData_set1_key;
++ CMS_decrypt;
++ int_smime_write_ASN1;
++ CMS_unsigned_delete_attr;
++ CMS_unsigned_get_attr_count;
++ CMS_add_smimecap;
++ PEM_read_CMS;
++ CMS_signed_get_attr_by_OBJ;
++ d2i_CMS_ContentInfo;
++ CMS_add_standard_smimecap;
++ CMS_ContentInfo_new;
++ CMS_RecipientInfo_type;
++ CMS_get0_type;
++ CMS_is_detached;
++ CMS_sign;
++ CMS_signed_add1_attr;
++ CMS_unsigned_get_attr_by_OBJ;
++ SMIME_write_CMS;
++ CMS_EncryptedData_decrypt;
++ CMS_get0_RecipientInfos;
++ CMS_add0_RevocationInfoChoice;
++ CMS_decrypt_set1_pkey;
++ CMS_SignerInfo_set1_signer_cert;
++ CMS_get0_signers;
++ CMS_ReceiptRequest_get0_values;
++ CMS_signed_get0_data_by_OBJ;
++ CMS_get0_SignerInfos;
++ CMS_add0_cert;
++ CMS_EncryptedData_encrypt;
++ CMS_digest_verify;
++ CMS_set1_signers_certs;
++ CMS_signed_get_attr;
++ CMS_RecipientInfo_set0_key;
++ CMS_SignedData_init;
++ CMS_RecipientInfo_kekri_get0_id;
++ CMS_verify_receipt;
++ CMS_ReceiptRequest_it;
++ CMS_ReceiptRequest_it;
++ PEM_read_bio_CMS;
++ CMS_get1_crls;
++ CMS_add0_recipient_key;
++ SMIME_read_ASN1;
++ CMS_ReceiptRequest_new;
++ CMS_get0_content;
++ CMS_get1_ReceiptRequest;
++ CMS_signed_add1_attr_by_OBJ;
++ CMS_RecipientInfo_kekri_id_cmp;
++ CMS_add1_ReceiptRequest;
++ CMS_SignerInfo_get0_signer_id;
++ CMS_unsigned_add1_attr_by_NID;
++ CMS_unsigned_add1_attr;
++ CMS_signed_get_attr_by_NID;
++ CMS_get1_certs;
++ CMS_signed_add1_attr_by_NID;
++ CMS_unsigned_add1_attr_by_txt;
++ CMS_dataFinal;
++ CMS_RecipientInfo_ktri_get0_signer_id;
++ CMS_RecipInfo_ktri_get0_sigr_id;
++ i2d_CMS_ReceiptRequest;
++ CMS_add1_recipient_cert;
++ CMS_dataInit;
++ CMS_signed_add1_attr_by_txt;
++ CMS_RecipientInfo_decrypt;
++ CMS_signed_get_attr_count;
++ CMS_get0_eContentType;
++ CMS_set1_eContentType;
++ CMS_ReceiptRequest_create0;
++ CMS_add1_signer;
++ CMS_RecipientInfo_set0_pkey;
++ ENGINE_set_load_ssl_client_cert_function;
++ ENGINE_set_ld_ssl_clnt_cert_fn;
++ ENGINE_get_ssl_client_cert_function;
++ ENGINE_get_ssl_client_cert_fn;
++ ENGINE_load_ssl_client_cert;
++ ENGINE_load_capi;
++ OPENSSL_isservice;
++ FIPS_dsa_sig_decode;
++ EVP_CIPHER_CTX_clear_flags;
++ FIPS_rand_status;
++ FIPS_rand_set_key;
++ CRYPTO_set_mem_info_functions;
++ RSA_X931_generate_key_ex;
++ int_ERR_set_state_func;
++ int_EVP_MD_set_engine_callbacks;
++ int_CRYPTO_set_do_dynlock_callback;
++ FIPS_rng_stick;
++ EVP_CIPHER_CTX_set_flags;
++ BN_X931_generate_prime_ex;
++ FIPS_selftest_check;
++ FIPS_rand_set_dt;
++ CRYPTO_dbg_pop_info;
++ FIPS_dsa_free;
++ RSA_X931_derive_ex;
++ FIPS_rsa_new;
++ FIPS_rand_bytes;
++ fips_cipher_test;
++ EVP_CIPHER_CTX_test_flags;
++ CRYPTO_malloc_debug_init;
++ CRYPTO_dbg_push_info;
++ FIPS_corrupt_rsa_keygen;
++ FIPS_dh_new;
++ FIPS_corrupt_dsa_keygen;
++ FIPS_dh_free;
++ fips_pkey_signature_test;
++ EVP_add_alg_module;
++ int_RAND_init_engine_callbacks;
++ int_EVP_CIPHER_set_engine_callbacks;
++ int_EVP_MD_init_engine_callbacks;
++ FIPS_rand_test_mode;
++ FIPS_rand_reset;
++ FIPS_dsa_new;
++ int_RAND_set_callbacks;
++ BN_X931_derive_prime_ex;
++ int_ERR_lib_init;
++ int_EVP_CIPHER_init_engine_callbacks;
++ FIPS_rsa_free;
++ FIPS_dsa_sig_encode;
++ CRYPTO_dbg_remove_all_info;
++ OPENSSL_init;
++ CRYPTO_strdup;
++ JPAKE_STEP3A_process;
++ JPAKE_STEP1_release;
++ JPAKE_get_shared_key;
++ JPAKE_STEP3B_init;
++ JPAKE_STEP1_generate;
++ JPAKE_STEP1_init;
++ JPAKE_STEP3B_process;
++ JPAKE_STEP2_generate;
++ JPAKE_CTX_new;
++ JPAKE_CTX_free;
++ JPAKE_STEP3B_release;
++ JPAKE_STEP3A_release;
++ JPAKE_STEP2_process;
++ JPAKE_STEP3B_generate;
++ JPAKE_STEP1_process;
++ JPAKE_STEP3A_generate;
++ JPAKE_STEP2_release;
++ JPAKE_STEP3A_init;
++ ERR_load_JPAKE_strings;
++ JPAKE_STEP2_init;
++ pqueue_size;
++ i2d_TS_ACCURACY;
++ i2d_TS_MSG_IMPRINT_fp;
++ i2d_TS_MSG_IMPRINT;
++ EVP_PKEY_print_public;
++ EVP_PKEY_CTX_new;
++ i2d_TS_TST_INFO;
++ EVP_PKEY_asn1_find;
++ DSO_METHOD_beos;
++ TS_CONF_load_cert;
++ TS_REQ_get_ext;
++ EVP_PKEY_sign_init;
++ ASN1_item_print;
++ TS_TST_INFO_set_nonce;
++ TS_RESP_dup;
++ ENGINE_register_pkey_meths;
++ EVP_PKEY_asn1_add0;
++ PKCS7_add0_attrib_signing_time;
++ i2d_TS_TST_INFO_fp;
++ BIO_asn1_get_prefix;
++ TS_TST_INFO_set_time;
++ EVP_PKEY_meth_set_decrypt;
++ EVP_PKEY_set_type_str;
++ EVP_PKEY_CTX_get_keygen_info;
++ TS_REQ_set_policy_id;
++ d2i_TS_RESP_fp;
++ ENGINE_get_pkey_asn1_meth_engine;
++ ENGINE_get_pkey_asn1_meth_eng;
++ WHIRLPOOL_Init;
++ TS_RESP_set_status_info;
++ EVP_PKEY_keygen;
++ EVP_DigestSignInit;
++ TS_ACCURACY_set_millis;
++ TS_REQ_dup;
++ GENERAL_NAME_dup;
++ ASN1_SEQUENCE_ANY_it;
++ ASN1_SEQUENCE_ANY_it;
++ WHIRLPOOL;
++ X509_STORE_get1_crls;
++ ENGINE_get_pkey_asn1_meth;
++ EVP_PKEY_asn1_new;
++ BIO_new_NDEF;
++ ENGINE_get_pkey_meth;
++ TS_MSG_IMPRINT_set_algo;
++ i2d_TS_TST_INFO_bio;
++ TS_TST_INFO_set_ordering;
++ TS_TST_INFO_get_ext_by_OBJ;
++ CRYPTO_THREADID_set_pointer;
++ TS_CONF_get_tsa_section;
++ SMIME_write_ASN1;
++ TS_RESP_CTX_set_signer_key;
++ EVP_PKEY_encrypt_old;
++ EVP_PKEY_encrypt_init;
++ CRYPTO_THREADID_cpy;
++ ASN1_PCTX_get_cert_flags;
++ i2d_ESS_SIGNING_CERT;
++ TS_CONF_load_key;
++ i2d_ASN1_SEQUENCE_ANY;
++ d2i_TS_MSG_IMPRINT_bio;
++ EVP_PKEY_asn1_set_public;
++ b2i_PublicKey_bio;
++ BIO_asn1_set_prefix;
++ EVP_PKEY_new_mac_key;
++ BIO_new_CMS;
++ CRYPTO_THREADID_cmp;
++ TS_REQ_ext_free;
++ EVP_PKEY_asn1_set_free;
++ EVP_PKEY_get0_asn1;
++ d2i_NETSCAPE_X509;
++ EVP_PKEY_verify_recover_init;
++ EVP_PKEY_CTX_set_data;
++ EVP_PKEY_keygen_init;
++ TS_RESP_CTX_set_status_info;
++ TS_MSG_IMPRINT_get_algo;
++ TS_REQ_print_bio;
++ EVP_PKEY_CTX_ctrl_str;
++ EVP_PKEY_get_default_digest_nid;
++ PEM_write_bio_PKCS7_stream;
++ TS_MSG_IMPRINT_print_bio;
++ BN_asc2bn;
++ TS_REQ_get_policy_id;
++ ENGINE_set_default_pkey_asn1_meths;
++ ENGINE_set_def_pkey_asn1_meths;
++ d2i_TS_ACCURACY;
++ DSO_global_lookup;
++ TS_CONF_set_tsa_name;
++ i2d_ASN1_SET_ANY;
++ ENGINE_load_gost;
++ WHIRLPOOL_BitUpdate;
++ ASN1_PCTX_get_flags;
++ TS_TST_INFO_get_ext_by_NID;
++ TS_RESP_new;
++ ESS_CERT_ID_dup;
++ TS_STATUS_INFO_dup;
++ TS_REQ_delete_ext;
++ EVP_DigestVerifyFinal;
++ EVP_PKEY_print_params;
++ i2d_CMS_bio_stream;
++ TS_REQ_get_msg_imprint;
++ OBJ_find_sigid_by_algs;
++ TS_TST_INFO_get_serial;
++ TS_REQ_get_nonce;
++ X509_PUBKEY_set0_param;
++ EVP_PKEY_CTX_set0_keygen_info;
++ DIST_POINT_set_dpname;
++ i2d_ISSUING_DIST_POINT;
++ ASN1_SET_ANY_it;
++ ASN1_SET_ANY_it;
++ EVP_PKEY_CTX_get_data;
++ TS_STATUS_INFO_print_bio;
++ EVP_PKEY_derive_init;
++ d2i_TS_TST_INFO;
++ EVP_PKEY_asn1_add_alias;
++ d2i_TS_RESP_bio;
++ OTHERNAME_cmp;
++ GENERAL_NAME_set0_value;
++ PKCS7_RECIP_INFO_get0_alg;
++ TS_RESP_CTX_new;
++ TS_RESP_set_tst_info;
++ PKCS7_final;
++ EVP_PKEY_base_id;
++ TS_RESP_CTX_set_signer_cert;
++ TS_REQ_set_msg_imprint;
++ EVP_PKEY_CTX_ctrl;
++ TS_CONF_set_digests;
++ d2i_TS_MSG_IMPRINT;
++ EVP_PKEY_meth_set_ctrl;
++ TS_REQ_get_ext_by_NID;
++ PKCS5_pbe_set0_algor;
++ BN_BLINDING_thread_id;
++ TS_ACCURACY_new;
++ X509_CRL_METHOD_free;
++ ASN1_PCTX_get_nm_flags;
++ EVP_PKEY_meth_set_sign;
++ CRYPTO_THREADID_current;
++ EVP_PKEY_decrypt_init;
++ NETSCAPE_X509_free;
++ i2b_PVK_bio;
++ EVP_PKEY_print_private;
++ GENERAL_NAME_get0_value;
++ b2i_PVK_bio;
++ ASN1_UTCTIME_adj;
++ TS_TST_INFO_new;
++ EVP_MD_do_all_sorted;
++ TS_CONF_set_default_engine;
++ TS_ACCURACY_set_seconds;
++ TS_TST_INFO_get_time;
++ PKCS8_pkey_get0;
++ EVP_PKEY_asn1_get0;
++ OBJ_add_sigid;
++ PKCS7_SIGNER_INFO_sign;
++ EVP_PKEY_paramgen_init;
++ EVP_PKEY_sign;
++ OBJ_sigid_free;
++ EVP_PKEY_meth_set_init;
++ d2i_ESS_ISSUER_SERIAL;
++ ISSUING_DIST_POINT_new;
++ ASN1_TIME_adj;
++ TS_OBJ_print_bio;
++ EVP_PKEY_meth_set_verify_recover;
++ EVP_PKEY_meth_set_vrfy_recover;
++ TS_RESP_get_status_info;
++ CMS_stream;
++ EVP_PKEY_CTX_set_cb;
++ PKCS7_to_TS_TST_INFO;
++ ASN1_PCTX_get_oid_flags;
++ TS_TST_INFO_add_ext;
++ EVP_PKEY_meth_set_derive;
++ i2d_TS_RESP_fp;
++ i2d_TS_MSG_IMPRINT_bio;
++ TS_RESP_CTX_set_accuracy;
++ TS_REQ_set_nonce;
++ ESS_CERT_ID_new;
++ ENGINE_pkey_asn1_find_str;
++ TS_REQ_get_ext_count;
++ BUF_reverse;
++ TS_TST_INFO_print_bio;
++ d2i_ISSUING_DIST_POINT;
++ ENGINE_get_pkey_meths;
++ i2b_PrivateKey_bio;
++ i2d_TS_RESP;
++ b2i_PublicKey;
++ TS_VERIFY_CTX_cleanup;
++ TS_STATUS_INFO_free;
++ TS_RESP_verify_token;
++ OBJ_bsearch_ex_;
++ ASN1_bn_print;
++ EVP_PKEY_asn1_get_count;
++ ENGINE_register_pkey_asn1_meths;
++ ASN1_PCTX_set_nm_flags;
++ EVP_DigestVerifyInit;
++ ENGINE_set_default_pkey_meths;
++ TS_TST_INFO_get_policy_id;
++ TS_REQ_get_cert_req;
++ X509_CRL_set_meth_data;
++ PKCS8_pkey_set0;
++ ASN1_STRING_copy;
++ d2i_TS_TST_INFO_fp;
++ X509_CRL_match;
++ EVP_PKEY_asn1_set_private;
++ TS_TST_INFO_get_ext_d2i;
++ TS_RESP_CTX_add_policy;
++ d2i_TS_RESP;
++ TS_CONF_load_certs;
++ TS_TST_INFO_get_msg_imprint;
++ ERR_load_TS_strings;
++ TS_TST_INFO_get_version;
++ EVP_PKEY_CTX_dup;
++ EVP_PKEY_meth_set_verify;
++ i2b_PublicKey_bio;
++ TS_CONF_set_certs;
++ EVP_PKEY_asn1_get0_info;
++ TS_VERIFY_CTX_free;
++ TS_REQ_get_ext_by_critical;
++ TS_RESP_CTX_set_serial_cb;
++ X509_CRL_get_meth_data;
++ TS_RESP_CTX_set_time_cb;
++ TS_MSG_IMPRINT_get_msg;
++ TS_TST_INFO_ext_free;
++ TS_REQ_get_version;
++ TS_REQ_add_ext;
++ EVP_PKEY_CTX_set_app_data;
++ OBJ_bsearch_;
++ EVP_PKEY_meth_set_verifyctx;
++ i2d_PKCS7_bio_stream;
++ CRYPTO_THREADID_set_numeric;
++ PKCS7_sign_add_signer;
++ d2i_TS_TST_INFO_bio;
++ TS_TST_INFO_get_ordering;
++ TS_RESP_print_bio;
++ TS_TST_INFO_get_exts;
++ HMAC_CTX_copy;
++ PKCS5_pbe2_set_iv;
++ ENGINE_get_pkey_asn1_meths;
++ b2i_PrivateKey;
++ EVP_PKEY_CTX_get_app_data;
++ TS_REQ_set_cert_req;
++ CRYPTO_THREADID_set_callback;
++ TS_CONF_set_serial;
++ TS_TST_INFO_free;
++ d2i_TS_REQ_fp;
++ TS_RESP_verify_response;
++ i2d_ESS_ISSUER_SERIAL;
++ TS_ACCURACY_get_seconds;
++ EVP_CIPHER_do_all;
++ b2i_PrivateKey_bio;
++ OCSP_CERTID_dup;
++ X509_PUBKEY_get0_param;
++ TS_MSG_IMPRINT_dup;
++ PKCS7_print_ctx;
++ i2d_TS_REQ_bio;
++ EVP_whirlpool;
++ EVP_PKEY_asn1_set_param;
++ EVP_PKEY_meth_set_encrypt;
++ ASN1_PCTX_set_flags;
++ i2d_ESS_CERT_ID;
++ TS_VERIFY_CTX_new;
++ TS_RESP_CTX_set_extension_cb;
++ ENGINE_register_all_pkey_meths;
++ TS_RESP_CTX_set_status_info_cond;
++ TS_RESP_CTX_set_stat_info_cond;
++ EVP_PKEY_verify;
++ WHIRLPOOL_Final;
++ X509_CRL_METHOD_new;
++ EVP_DigestSignFinal;
++ TS_RESP_CTX_set_def_policy;
++ NETSCAPE_X509_it;
++ NETSCAPE_X509_it;
++ TS_RESP_create_response;
++ PKCS7_SIGNER_INFO_get0_algs;
++ TS_TST_INFO_get_nonce;
++ EVP_PKEY_decrypt_old;
++ TS_TST_INFO_set_policy_id;
++ TS_CONF_set_ess_cert_id_chain;
++ EVP_PKEY_CTX_get0_pkey;
++ d2i_TS_REQ;
++ EVP_PKEY_asn1_find_str;
++ BIO_f_asn1;
++ ESS_SIGNING_CERT_new;
++ EVP_PBE_find;
++ X509_CRL_get0_by_cert;
++ EVP_PKEY_derive;
++ i2d_TS_REQ;
++ TS_TST_INFO_delete_ext;
++ ESS_ISSUER_SERIAL_free;
++ ASN1_PCTX_set_str_flags;
++ ENGINE_get_pkey_asn1_meth_str;
++ TS_CONF_set_signer_key;
++ TS_ACCURACY_get_millis;
++ TS_RESP_get_token;
++ TS_ACCURACY_dup;
++ ENGINE_register_all_pkey_asn1_meths;
++ ENGINE_reg_all_pkey_asn1_meths;
++ X509_CRL_set_default_method;
++ CRYPTO_THREADID_hash;
++ CMS_ContentInfo_print_ctx;
++ TS_RESP_free;
++ ISSUING_DIST_POINT_free;
++ ESS_ISSUER_SERIAL_new;
++ CMS_add1_crl;
++ PKCS7_add1_attrib_digest;
++ TS_RESP_CTX_add_md;
++ TS_TST_INFO_dup;
++ ENGINE_set_pkey_asn1_meths;
++ PEM_write_bio_Parameters;
++ TS_TST_INFO_get_accuracy;
++ X509_CRL_get0_by_serial;
++ TS_TST_INFO_set_version;
++ TS_RESP_CTX_get_tst_info;
++ TS_RESP_verify_signature;
++ CRYPTO_THREADID_get_callback;
++ TS_TST_INFO_get_tsa;
++ TS_STATUS_INFO_new;
++ EVP_PKEY_CTX_get_cb;
++ TS_REQ_get_ext_d2i;
++ GENERAL_NAME_set0_othername;
++ TS_TST_INFO_get_ext_count;
++ TS_RESP_CTX_get_request;
++ i2d_NETSCAPE_X509;
++ ENGINE_get_pkey_meth_engine;
++ EVP_PKEY_meth_set_signctx;
++ EVP_PKEY_asn1_copy;
++ ASN1_TYPE_cmp;
++ EVP_CIPHER_do_all_sorted;
++ EVP_PKEY_CTX_free;
++ ISSUING_DIST_POINT_it;
++ ISSUING_DIST_POINT_it;
++ d2i_TS_MSG_IMPRINT_fp;
++ X509_STORE_get1_certs;
++ EVP_PKEY_CTX_get_operation;
++ d2i_ESS_SIGNING_CERT;
++ TS_CONF_set_ordering;
++ EVP_PBE_alg_add_type;
++ TS_REQ_set_version;
++ EVP_PKEY_get0;
++ BIO_asn1_set_suffix;
++ i2d_TS_STATUS_INFO;
++ EVP_MD_do_all;
++ TS_TST_INFO_set_accuracy;
++ PKCS7_add_attrib_content_type;
++ ERR_remove_thread_state;
++ EVP_PKEY_meth_add0;
++ TS_TST_INFO_set_tsa;
++ EVP_PKEY_meth_new;
++ WHIRLPOOL_Update;
++ TS_CONF_set_accuracy;
++ ASN1_PCTX_set_oid_flags;
++ ESS_SIGNING_CERT_dup;
++ d2i_TS_REQ_bio;
++ X509_time_adj_ex;
++ TS_RESP_CTX_add_flags;
++ d2i_TS_STATUS_INFO;
++ TS_MSG_IMPRINT_set_msg;
++ BIO_asn1_get_suffix;
++ TS_REQ_free;
++ EVP_PKEY_meth_free;
++ TS_REQ_get_exts;
++ TS_RESP_CTX_set_clock_precision_digits;
++ TS_RESP_CTX_set_clk_prec_digits;
++ TS_RESP_CTX_add_failure_info;
++ i2d_TS_RESP_bio;
++ EVP_PKEY_CTX_get0_peerkey;
++ PEM_write_bio_CMS_stream;
++ TS_REQ_new;
++ TS_MSG_IMPRINT_new;
++ EVP_PKEY_meth_find;
++ EVP_PKEY_id;
++ TS_TST_INFO_set_serial;
++ a2i_GENERAL_NAME;
++ TS_CONF_set_crypto_device;
++ EVP_PKEY_verify_init;
++ TS_CONF_set_policies;
++ ASN1_PCTX_new;
++ ESS_CERT_ID_free;
++ ENGINE_unregister_pkey_meths;
++ TS_MSG_IMPRINT_free;
++ TS_VERIFY_CTX_init;
++ PKCS7_stream;
++ TS_RESP_CTX_set_certs;
++ TS_CONF_set_def_policy;
++ ASN1_GENERALIZEDTIME_adj;
++ NETSCAPE_X509_new;
++ TS_ACCURACY_free;
++ TS_RESP_get_tst_info;
++ EVP_PKEY_derive_set_peer;
++ PEM_read_bio_Parameters;
++ TS_CONF_set_clock_precision_digits;
++ TS_CONF_set_clk_prec_digits;
++ ESS_ISSUER_SERIAL_dup;
++ TS_ACCURACY_get_micros;
++ ASN1_PCTX_get_str_flags;
++ NAME_CONSTRAINTS_check;
++ ASN1_BIT_STRING_check;
++ X509_check_akid;
++ ENGINE_unregister_pkey_asn1_meths;
++ ENGINE_unreg_pkey_asn1_meths;
++ ASN1_PCTX_free;
++ PEM_write_bio_ASN1_stream;
++ i2d_ASN1_bio_stream;
++ TS_X509_ALGOR_print_bio;
++ EVP_PKEY_meth_set_cleanup;
++ EVP_PKEY_asn1_free;
++ ESS_SIGNING_CERT_free;
++ TS_TST_INFO_set_msg_imprint;
++ GENERAL_NAME_cmp;
++ d2i_ASN1_SET_ANY;
++ ENGINE_set_pkey_meths;
++ i2d_TS_REQ_fp;
++ d2i_ASN1_SEQUENCE_ANY;
++ GENERAL_NAME_get0_otherName;
++ d2i_ESS_CERT_ID;
++ OBJ_find_sigid_algs;
++ EVP_PKEY_meth_set_keygen;
++ PKCS5_PBKDF2_HMAC;
++ EVP_PKEY_paramgen;
++ EVP_PKEY_meth_set_paramgen;
++ BIO_new_PKCS7;
++ EVP_PKEY_verify_recover;
++ TS_ext_print_bio;
++ TS_ASN1_INTEGER_print_bio;
++ check_defer;
++ DSO_pathbyaddr;
++ EVP_PKEY_set_type;
++ TS_ACCURACY_set_micros;
++ TS_REQ_to_TS_VERIFY_CTX;
++ EVP_PKEY_meth_set_copy;
++ ASN1_PCTX_set_cert_flags;
++ TS_TST_INFO_get_ext;
++ EVP_PKEY_asn1_set_ctrl;
++ TS_TST_INFO_get_ext_by_critical;
++ EVP_PKEY_CTX_new_id;
++ TS_REQ_get_ext_by_OBJ;
++ TS_CONF_set_signer_cert;
++ X509_NAME_hash_old;
++ ASN1_TIME_set_string;
++ EVP_MD_flags;
++ TS_RESP_CTX_free;
++ DSAparams_dup;
++ DHparams_dup;
++ OCSP_REQ_CTX_add1_header;
++ OCSP_REQ_CTX_set1_req;
++ X509_STORE_set_verify_cb;
++ X509_STORE_CTX_get0_current_crl;
++ X509_STORE_CTX_get0_parent_ctx;
++ X509_STORE_CTX_get0_current_issuer;
++ X509_STORE_CTX_get0_cur_issuer;
++ X509_issuer_name_hash_old;
++ X509_subject_name_hash_old;
++ EVP_CIPHER_CTX_copy;
++ UI_method_get_prompt_constructor;
++ UI_method_get_prompt_constructr;
++ UI_method_set_prompt_constructor;
++ UI_method_set_prompt_constructr;
++ EVP_read_pw_string_min;
++ CRYPTO_cts128_encrypt;
++ CRYPTO_cts128_decrypt_block;
++ CRYPTO_cfb128_1_encrypt;
++ CRYPTO_cbc128_encrypt;
++ CRYPTO_ctr128_encrypt;
++ CRYPTO_ofb128_encrypt;
++ CRYPTO_cts128_decrypt;
++ CRYPTO_cts128_encrypt_block;
++ CRYPTO_cbc128_decrypt;
++ CRYPTO_cfb128_encrypt;
++ CRYPTO_cfb128_8_encrypt;
++
++ local:
++ *;
++};
++
++
++OPENSSL_1.0.1 {
++ global:
++ SSL_renegotiate_abbreviated;
++ TLSv1_1_method;
++ TLSv1_1_client_method;
++ TLSv1_1_server_method;
++ SSL_CTX_set_srp_client_pwd_callback;
++ SSL_CTX_set_srp_client_pwd_cb;
++ SSL_get_srp_g;
++ SSL_CTX_set_srp_username_callback;
++ SSL_CTX_set_srp_un_cb;
++ SSL_get_srp_userinfo;
++ SSL_set_srp_server_param;
++ SSL_set_srp_server_param_pw;
++ SSL_get_srp_N;
++ SSL_get_srp_username;
++ SSL_CTX_set_srp_password;
++ SSL_CTX_set_srp_strength;
++ SSL_CTX_set_srp_verify_param_callback;
++ SSL_CTX_set_srp_vfy_param_cb;
++ SSL_CTX_set_srp_cb_arg;
++ SSL_CTX_set_srp_username;
++ SSL_CTX_SRP_CTX_init;
++ SSL_SRP_CTX_init;
++ SRP_Calc_A_param;
++ SRP_generate_server_master_secret;
++ SRP_gen_server_master_secret;
++ SSL_CTX_SRP_CTX_free;
++ SRP_generate_client_master_secret;
++ SRP_gen_client_master_secret;
++ SSL_srp_server_param_with_username;
++ SSL_srp_server_param_with_un;
++ SSL_SRP_CTX_free;
++ SSL_set_debug;
++ SSL_SESSION_get0_peer;
++ TLSv1_2_client_method;
++ SSL_SESSION_set1_id_context;
++ TLSv1_2_server_method;
++ SSL_cache_hit;
++ SSL_get0_kssl_ctx;
++ SSL_set0_kssl_ctx;
++ SSL_set_state;
++ SSL_CIPHER_get_id;
++ TLSv1_2_method;
++ kssl_ctx_get0_client_princ;
++ SSL_export_keying_material;
++ SSL_set_tlsext_use_srtp;
++ SSL_CTX_set_next_protos_advertised_cb;
++ SSL_CTX_set_next_protos_adv_cb;
++ SSL_get0_next_proto_negotiated;
++ SSL_get_selected_srtp_profile;
++ SSL_CTX_set_tlsext_use_srtp;
++ SSL_select_next_proto;
++ SSL_get_srtp_profiles;
++ SSL_CTX_set_next_proto_select_cb;
++ SSL_CTX_set_next_proto_sel_cb;
++ SSL_SESSION_get_compress_id;
++
++ SRP_VBASE_get_by_user;
++ SRP_Calc_server_key;
++ SRP_create_verifier;
++ SRP_create_verifier_BN;
++ SRP_Calc_u;
++ SRP_VBASE_free;
++ SRP_Calc_client_key;
++ SRP_get_default_gN;
++ SRP_Calc_x;
++ SRP_Calc_B;
++ SRP_VBASE_new;
++ SRP_check_known_gN_param;
++ SRP_Calc_A;
++ SRP_Verify_A_mod_N;
++ SRP_VBASE_init;
++ SRP_Verify_B_mod_N;
++ EC_KEY_set_public_key_affine_coordinates;
++ EC_KEY_set_pub_key_aff_coords;
++ EVP_aes_192_ctr;
++ EVP_PKEY_meth_get0_info;
++ EVP_PKEY_meth_copy;
++ ERR_add_error_vdata;
++ EVP_aes_128_ctr;
++ EVP_aes_256_ctr;
++ EC_GFp_nistp224_method;
++ EC_KEY_get_flags;
++ RSA_padding_add_PKCS1_PSS_mgf1;
++ EVP_aes_128_xts;
++ EVP_aes_256_xts;
++ EVP_aes_128_gcm;
++ EC_KEY_clear_flags;
++ EC_KEY_set_flags;
++ EVP_aes_256_ccm;
++ RSA_verify_PKCS1_PSS_mgf1;
++ EVP_aes_128_ccm;
++ EVP_aes_192_gcm;
++ X509_ALGOR_set_md;
++ RAND_init_fips;
++ EVP_aes_256_gcm;
++ EVP_aes_192_ccm;
++ CMAC_CTX_copy;
++ CMAC_CTX_free;
++ CMAC_CTX_get0_cipher_ctx;
++ CMAC_CTX_cleanup;
++ CMAC_Init;
++ CMAC_Update;
++ CMAC_resume;
++ CMAC_CTX_new;
++ CMAC_Final;
++ CRYPTO_ctr128_encrypt_ctr32;
++ CRYPTO_gcm128_release;
++ CRYPTO_ccm128_decrypt_ccm64;
++ CRYPTO_ccm128_encrypt;
++ CRYPTO_gcm128_encrypt;
++ CRYPTO_xts128_encrypt;
++ EVP_rc4_hmac_md5;
++ CRYPTO_nistcts128_decrypt_block;
++ CRYPTO_gcm128_setiv;
++ CRYPTO_nistcts128_encrypt;
++ EVP_aes_128_cbc_hmac_sha1;
++ CRYPTO_gcm128_tag;
++ CRYPTO_ccm128_encrypt_ccm64;
++ ENGINE_load_rdrand;
++ CRYPTO_ccm128_setiv;
++ CRYPTO_nistcts128_encrypt_block;
++ CRYPTO_gcm128_aad;
++ CRYPTO_ccm128_init;
++ CRYPTO_nistcts128_decrypt;
++ CRYPTO_gcm128_new;
++ CRYPTO_ccm128_tag;
++ CRYPTO_ccm128_decrypt;
++ CRYPTO_ccm128_aad;
++ CRYPTO_gcm128_init;
++ CRYPTO_gcm128_decrypt;
++ ENGINE_load_rsax;
++ CRYPTO_gcm128_decrypt_ctr32;
++ CRYPTO_gcm128_encrypt_ctr32;
++ CRYPTO_gcm128_finish;
++ EVP_aes_256_cbc_hmac_sha1;
++ PKCS5_pbkdf2_set;
++ CMS_add0_recipient_password;
++ CMS_decrypt_set1_password;
++ CMS_RecipientInfo_set0_password;
++ RAND_set_fips_drbg_type;
++ X509_REQ_sign_ctx;
++ RSA_PSS_PARAMS_new;
++ X509_CRL_sign_ctx;
++ X509_signature_dump;
++ d2i_RSA_PSS_PARAMS;
++ RSA_PSS_PARAMS_it;
++ RSA_PSS_PARAMS_it;
++ RSA_PSS_PARAMS_free;
++ X509_sign_ctx;
++ i2d_RSA_PSS_PARAMS;
++ ASN1_item_sign_ctx;
++ EC_GFp_nistp521_method;
++ EC_GFp_nistp256_method;
++ OPENSSL_stderr;
++ OPENSSL_cpuid_setup;
++ OPENSSL_showfatal;
++ BIO_new_dgram_sctp;
++ BIO_dgram_sctp_msg_waiting;
++ BIO_dgram_sctp_wait_for_dry;
++ BIO_s_datagram_sctp;
++ BIO_dgram_is_sctp;
++ BIO_dgram_sctp_notification_cb;
++} OPENSSL_1.0.0;
++
++OPENSSL_1.0.1d {
++ global:
++ CRYPTO_memcmp;
++} OPENSSL_1.0.1;
++
+Index: openssl-1.0.1d/engines/openssl.ld
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ openssl-1.0.1d/engines/openssl.ld 2013-02-06 19:41:43.000000000 +0100
+@@ -0,0 +1,10 @@
++OPENSSL_1.0.0 {
++ global:
++ bind_engine;
++ v_check;
++ OPENSSL_init;
++ OPENSSL_finish;
++ local:
++ *;
++};
++
+Index: openssl-1.0.1d/engines/ccgost/openssl.ld
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ openssl-1.0.1d/engines/ccgost/openssl.ld 2013-02-06 19:41:43.000000000 +0100
+@@ -0,0 +1,10 @@
++OPENSSL_1.0.0 {
++ global:
++ bind_engine;
++ v_check;
++ OPENSSL_init;
++ OPENSSL_finish;
++ local:
++ *;
++};
++
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/engines-install-in-libdir-ssl.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/engines-install-in-libdir-ssl.patch
new file mode 100644
index 0000000..d8a6f1a
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/engines-install-in-libdir-ssl.patch
@@ -0,0 +1,56 @@
+Upstream-Status: Inappropriate [configuration]
+
+
+Index: openssl-1.0.0/engines/Makefile
+===================================================================
+--- openssl-1.0.0.orig/engines/Makefile
++++ openssl-1.0.0/engines/Makefile
+@@ -107,7 +107,7 @@
+ @[ -n "$(INSTALLTOP)" ] # should be set by top Makefile...
+ @if [ -n "$(SHARED_LIBS)" ]; then \
+ set -e; \
+- $(PERL) $(TOP)/util/mkdir-p.pl $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/engines; \
++ $(PERL) $(TOP)/util/mkdir-p.pl $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/ssl/engines; \
+ for l in $(LIBNAMES); do \
+ ( echo installing $$l; \
+ pfx=lib; \
+@@ -119,13 +119,13 @@
+ *DSO_WIN32*) sfx="eay32.dll"; pfx=;; \
+ *) sfx=".bad";; \
+ esac; \
+- cp $$pfx$$l$$sfx $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/engines/$$pfx$$l$$sfx.new; \
++ cp $$pfx$$l$$sfx $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/ssl/engines/$$pfx$$l$$sfx.new; \
+ else \
+ sfx=".so"; \
+- cp cyg$$l.dll $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/engines/$$pfx$$l$$sfx.new; \
++ cp cyg$$l.dll $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/ssl/engines/$$pfx$$l$$sfx.new; \
+ fi; \
+- chmod 555 $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/engines/$$pfx$$l$$sfx.new; \
+- mv -f $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/engines/$$pfx$$l$$sfx.new $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/engines/$$pfx$$l$$sfx ); \
++ chmod 555 $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/ssl/engines/$$pfx$$l$$sfx.new; \
++ mv -f $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/ssl/engines/$$pfx$$l$$sfx.new $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/ssl/engines/$$pfx$$l$$sfx ); \
+ done; \
+ fi
+ @target=install; $(RECURSIVE_MAKE)
+Index: openssl-1.0.0/engines/ccgost/Makefile
+===================================================================
+--- openssl-1.0.0.orig/engines/ccgost/Makefile
++++ openssl-1.0.0/engines/ccgost/Makefile
+@@ -53,13 +53,13 @@
+ *DSO_WIN32*) sfx="eay32.dll"; pfx=;; \
+ *) sfx=".bad";; \
+ esac; \
+- cp $${pfx}$(LIBNAME)$$sfx $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/engines/$${pfx}$(LIBNAME)$$sfx.new; \
++ cp $${pfx}$(LIBNAME)$$sfx $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/ssl/engines/$${pfx}$(LIBNAME)$$sfx.new; \
+ else \
+ sfx=".so"; \
+- cp cyg$(LIBNAME).dll $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/engines/$${pfx}$(LIBNAME)$$sfx.new; \
++ cp cyg$(LIBNAME).dll $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/ssl/engines/$${pfx}$(LIBNAME)$$sfx.new; \
+ fi; \
+- chmod 555 $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/engines/$${pfx}$(LIBNAME)$$sfx.new; \
+- mv -f $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/engines/$${pfx}$(LIBNAME)$$sfx.new $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/engines/$${pfx}$(LIBNAME)$$sfx; \
++ chmod 555 $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/ssl/engines/$${pfx}$(LIBNAME)$$sfx.new; \
++ mv -f $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/ssl/engines/$${pfx}$(LIBNAME)$$sfx.new $(INSTALL_PREFIX)$(INSTALLTOP)/$(LIBDIR)/ssl/engines/$${pfx}$(LIBNAME)$$sfx; \
+ fi
+
+ links:
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/find.pl b/meta-edison-distro/recipes-connectivity/openssl/openssl/find.pl
new file mode 100644
index 0000000..8e1b42c
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/find.pl
@@ -0,0 +1,54 @@
+warn "Legacy library @{[(caller(0))[6]]} will be removed from the Perl core distribution in the next major release. Please install it from the CPAN distribution Perl4::CoreLibs. It is being used at @{[(caller)[1]]}, line @{[(caller)[2]]}.\n";
+
+# This library is deprecated and unmaintained. It is included for
+# compatibility with Perl 4 scripts which may use it, but it will be
+# removed in a future version of Perl. Please use the File::Find module
+# instead.
+
+# Usage:
+# require "find.pl";
+#
+# &find('/foo','/bar');
+#
+# sub wanted { ... }
+# where wanted does whatever you want. $dir contains the
+# current directory name, and $_ the current filename within
+# that directory. $name contains "$dir/$_". You are cd'ed
+# to $dir when the function is called. The function may
+# set $prune to prune the tree.
+#
+# For example,
+#
+# find / -name .nfs\* -mtime +7 -exec rm -f {} \; -o -fstype nfs -prune
+#
+# corresponds to this
+#
+# sub wanted {
+# /^\.nfs.*$/ &&
+# (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
+# int(-M _) > 7 &&
+# unlink($_)
+# ||
+# ($nlink || (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_))) &&
+# $dev < 0 &&
+# ($prune = 1);
+# }
+#
+# Set the variable $dont_use_nlink if you're using AFS, since AFS cheats.
+
+use File::Find ();
+
+*name = *File::Find::name;
+*prune = *File::Find::prune;
+*dir = *File::Find::dir;
+*topdir = *File::Find::topdir;
+*topdev = *File::Find::topdev;
+*topino = *File::Find::topino;
+*topmode = *File::Find::topmode;
+*topnlink = *File::Find::topnlink;
+
+sub find {
+ &File::Find::find(\&wanted, @_);
+}
+
+1;
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/fix-cipher-des-ede3-cfb1.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/fix-cipher-des-ede3-cfb1.patch
new file mode 100644
index 0000000..f0e1778
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/fix-cipher-des-ede3-cfb1.patch
@@ -0,0 +1,22 @@
+Upstream-Status: Submitted
+
+This patch adds the fix for one of the ciphers used in openssl, namely
+the cipher des-ede3-cfb1. Complete bug log and patch is present here:
+http://rt.openssl.org/Ticket/Display.html?id=2867
+
+Signed-Off-By: Muhammad Shakeel <muhammad_shakeel@mentor.com>
+
+diff --git a/crypto/evp/e_des3.c b/crypto/evp/e_des3.c
+index 3232cfe..df84922 100644
+===================================================================
+--- a/crypto/evp/e_des3.c
++++ b/crypto/evp/e_des3.c
+@@ -173,7 +173,7 @@ static int des_ede3_cfb1_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+ size_t n;
+ unsigned char c[1],d[1];
+
+- for(n=0 ; n < inl ; ++n)
++ for(n=0 ; n < inl*8 ; ++n)
+ {
+ c[0]=(in[n/8]&(1 << (7-n%8))) ? 0x80 : 0;
+ DES_ede3_cfb_encrypt(c,d,1,1,
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/initial-aarch64-bits.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/initial-aarch64-bits.patch
new file mode 100644
index 0000000..2185ff8
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/initial-aarch64-bits.patch
@@ -0,0 +1,119 @@
+From: Andy Polyakov <appro@openssl.org>
+Date: Sun, 13 Oct 2013 17:15:15 +0000 (+0200)
+Subject: Initial aarch64 bits.
+X-Git-Url: http://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff_plain;h=039081b80977e2a5de84e1f88f8b4d025b559956
+
+Initial aarch64 bits.
+---
+ crypto/bn/bn_lcl.h | 9 +++++++++
+ crypto/md32_common.h | 18 ++++++++++++++++++
+ crypto/modes/modes_lcl.h | 8 ++++++++
+ crypto/sha/sha512.c | 13 +++++++++++++
+ 4 files changed, 48 insertions(+)
+
+Index: openssl-1.0.1f/crypto/bn/bn_lcl.h
+===================================================================
+--- openssl-1.0.1f.orig/crypto/bn/bn_lcl.h 2014-01-06 15:47:42.000000000 +0200
++++ openssl-1.0.1f/crypto/bn/bn_lcl.h 2014-02-28 10:37:55.495979037 +0200
+@@ -300,6 +300,15 @@
+ : "r"(a), "r"(b));
+ # endif
+ # endif
++# elif defined(__aarch64__) && defined(SIXTY_FOUR_BIT_LONG)
++# if defined(__GNUC__) && __GNUC__>=2
++# define BN_UMULT_HIGH(a,b) ({ \
++ register BN_ULONG ret; \
++ asm ("umulh %0,%1,%2" \
++ : "=r"(ret) \
++ : "r"(a), "r"(b)); \
++ ret; })
++# endif
+ # endif /* cpu */
+ #endif /* OPENSSL_NO_ASM */
+
+Index: openssl-1.0.1f/crypto/md32_common.h
+===================================================================
+--- openssl-1.0.1f.orig/crypto/md32_common.h 2014-01-06 15:47:42.000000000 +0200
++++ openssl-1.0.1f/crypto/md32_common.h 2014-02-28 10:39:21.751979107 +0200
+@@ -213,6 +213,24 @@
+ asm ("bswapl %0":"=r"(r):"0"(r)); \
+ *((unsigned int *)(c))=r; (c)+=4; r; })
+ # endif
++# elif defined(__aarch64__)
++# if defined(__BYTE_ORDER__)
++# if defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
++# define HOST_c2l(c,l) ({ unsigned int r; \
++ asm ("rev %w0,%w1" \
++ :"=r"(r) \
++ :"r"(*((const unsigned int *)(c))));\
++ (c)+=4; (l)=r; })
++# define HOST_l2c(l,c) ({ unsigned int r; \
++ asm ("rev %w0,%w1" \
++ :"=r"(r) \
++ :"r"((unsigned int)(l)));\
++ *((unsigned int *)(c))=r; (c)+=4; r; })
++# elif defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
++# define HOST_c2l(c,l) ((l)=*((const unsigned int *)(c)), (c)+=4, (l))
++# define HOST_l2c(l,c) (*((unsigned int *)(c))=(l), (c)+=4, (l))
++# endif
++# endif
+ # endif
+ # endif
+ #endif
+Index: openssl-1.0.1f/crypto/modes/modes_lcl.h
+===================================================================
+--- openssl-1.0.1f.orig/crypto/modes/modes_lcl.h 2014-02-28 10:47:48.731979011 +0200
++++ openssl-1.0.1f/crypto/modes/modes_lcl.h 2014-02-28 10:48:49.707978919 +0200
+@@ -29,6 +29,7 @@
+ #if defined(__i386) || defined(__i386__) || \
+ defined(__x86_64) || defined(__x86_64__) || \
+ defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64) || \
++ defined(__aarch64__) || \
+ defined(__s390__) || defined(__s390x__)
+ # undef STRICT_ALIGNMENT
+ #endif
+@@ -50,6 +51,13 @@
+ # define BSWAP4(x) ({ u32 ret=(x); \
+ asm ("bswapl %0" \
+ : "+r"(ret)); ret; })
++# elif defined(__aarch64__)
++# define BSWAP8(x) ({ u64 ret; \
++ asm ("rev %0,%1" \
++ : "=r"(ret) : "r"(x)); ret; })
++# define BSWAP4(x) ({ u32 ret; \
++ asm ("rev %w0,%w1" \
++ : "=r"(ret) : "r"(x)); ret; })
+ # elif (defined(__arm__) || defined(__arm)) && !defined(STRICT_ALIGNMENT)
+ # define BSWAP8(x) ({ u32 lo=(u64)(x)>>32,hi=(x); \
+ asm ("rev %0,%0; rev %1,%1" \
+Index: openssl-1.0.1f/crypto/sha/sha512.c
+===================================================================
+--- openssl-1.0.1f.orig/crypto/sha/sha512.c 2014-01-06 15:47:42.000000000 +0200
++++ openssl-1.0.1f/crypto/sha/sha512.c 2014-02-28 10:52:14.579978981 +0200
+@@ -55,6 +55,7 @@
+ #if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
+ defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) || \
+ defined(__s390__) || defined(__s390x__) || \
++ defined(__aarch64__) || \
+ defined(SHA512_ASM)
+ #define SHA512_BLOCK_CAN_MANAGE_UNALIGNED_DATA
+ #endif
+@@ -347,6 +348,18 @@
+ asm ("rotrdi %0,%1,%2" \
+ : "=r"(ret) \
+ : "r"(a),"K"(n)); ret; })
++# elif defined(__aarch64__)
++# define ROTR(a,n) ({ SHA_LONG64 ret; \
++ asm ("ror %0,%1,%2" \
++ : "=r"(ret) \
++ : "r"(a),"I"(n)); ret; })
++# if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
++ __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
++# define PULL64(x) ({ SHA_LONG64 ret; \
++ asm ("rev %0,%1" \
++ : "=r"(ret) \
++ : "r"(*((const SHA_LONG64 *)(&(x))))); ret; })
++# endif
+ # endif
+ # elif defined(_MSC_VER)
+ # if defined(_WIN64) /* applies to both IA-64 and AMD64 */
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/oe-ldflags.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/oe-ldflags.patch
new file mode 100644
index 0000000..292e13d
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/oe-ldflags.patch
@@ -0,0 +1,24 @@
+Upstream-Status: Inappropriate [open-embedded]
+
+Index: openssl-1.0.0/Makefile.shared
+===================================================================
+--- openssl-1.0.0.orig/Makefile.shared
++++ openssl-1.0.0/Makefile.shared
+@@ -92,7 +92,7 @@
+ LINK_APP= \
+ ( $(SET_X); \
+ LIBDEPS="$${LIBDEPS:-$(LIBDEPS)}"; \
+- LDCMD="$${LDCMD:-$(CC)}"; LDFLAGS="$${LDFLAGS:-$(CFLAGS)}"; \
++ LDCMD="$${LDCMD:-$(CC)}"; LDFLAGS="$(OE_LDFLAGS) $${LDFLAGS:-$(CFLAGS)}"; \
+ LIBPATH=`for x in $$LIBDEPS; do echo $$x; done | sed -e 's/^ *-L//;t' -e d | uniq`; \
+ LIBPATH=`echo $$LIBPATH | sed -e 's/ /:/g'`; \
+ LD_LIBRARY_PATH=$$LIBPATH:$$LD_LIBRARY_PATH \
+@@ -102,7 +102,7 @@
+ ( $(SET_X); \
+ LIBDEPS="$${LIBDEPS:-$(LIBDEPS)}"; \
+ SHAREDCMD="$${SHAREDCMD:-$(CC)}"; \
+- SHAREDFLAGS="$${SHAREDFLAGS:-$(CFLAGS) $(SHARED_LDFLAGS)}"; \
++ SHAREDFLAGS="$(OE_LDFLAGS) $${SHAREDFLAGS:-$(CFLAGS) $(SHARED_LDFLAGS)}"; \
+ LIBPATH=`for x in $$LIBDEPS; do echo $$x; done | sed -e 's/^ *-L//;t' -e d | uniq`; \
+ LIBPATH=`echo $$LIBPATH | sed -e 's/ /:/g'`; \
+ LD_LIBRARY_PATH=$$LIBPATH:$$LD_LIBRARY_PATH \
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-1.0.1e-cve-2014-0195.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-1.0.1e-cve-2014-0195.patch
new file mode 100644
index 0000000..0c43919
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-1.0.1e-cve-2014-0195.patch
@@ -0,0 +1,40 @@
+commit 208d54db20d58c9a5e45e856a0650caadd7d9612
+Author: Dr. Stephen Henson <steve@openssl.org>
+Date: Tue May 13 18:48:31 2014 +0100
+
+ Fix for CVE-2014-0195
+
+ A buffer overrun attack can be triggered by sending invalid DTLS fragments
+ to an OpenSSL DTLS client or server. This is potentially exploitable to
+ run arbitrary code on a vulnerable client or server.
+
+ Fixed by adding consistency check for DTLS fragments.
+
+ Thanks to Jüri Aedla for reporting this issue.
+
+Patch borrowed from Fedora
+Upstream-Status: Backport
+Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
+
+diff --git a/ssl/d1_both.c b/ssl/d1_both.c
+index 2e8cf68..07f67f8 100644
+--- a/ssl/d1_both.c
++++ b/ssl/d1_both.c
+@@ -627,7 +627,16 @@ dtls1_reassemble_fragment(SSL *s, struct hm_header_st* msg_hdr, int *ok)
+ frag->msg_header.frag_off = 0;
+ }
+ else
++ {
+ frag = (hm_fragment*) item->data;
++ if (frag->msg_header.msg_len != msg_hdr->msg_len)
++ {
++ item = NULL;
++ frag = NULL;
++ goto err;
++ }
++ }
++
+
+ /* If message is already reassembled, this must be a
+ * retransmit and can be dropped.
+
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-1.0.1e-cve-2014-0198.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-1.0.1e-cve-2014-0198.patch
new file mode 100644
index 0000000..12dcfb7
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-1.0.1e-cve-2014-0198.patch
@@ -0,0 +1,38 @@
+From: Matt Caswell <matt@openssl.org>
+Date: Sun, 11 May 2014 23:38:37 +0000 (+0100)
+Subject: Fixed NULL pointer dereference. See PR#3321
+X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff_plain;h=b107586
+
+Fixed NULL pointer dereference. See PR#3321
+
+Patch borrowed from Fedora
+Upstream-Status: Backport
+Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
+
+---
+
+diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c
+index 40eb0dd..d961d12 100644
+--- a/ssl/s3_pkt.c
++++ b/ssl/s3_pkt.c
+@@ -657,9 +657,6 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
+ SSL3_BUFFER *wb=&(s->s3->wbuf);
+ SSL_SESSION *sess;
+
+- if (wb->buf == NULL)
+- if (!ssl3_setup_write_buffer(s))
+- return -1;
+
+ /* first check if there is a SSL3_BUFFER still being written
+ * out. This will happen with non blocking IO */
+@@ -675,6 +672,10 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
+ /* if it went, fall through and send more stuff */
+ }
+
++ if (wb->buf == NULL)
++ if (!ssl3_setup_write_buffer(s))
++ return -1;
++
+ if (len == 0 && !create_empty_fragment)
+ return 0;
+
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-1.0.1e-cve-2014-0221.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-1.0.1e-cve-2014-0221.patch
new file mode 100644
index 0000000..bf730a8
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-1.0.1e-cve-2014-0221.patch
@@ -0,0 +1,38 @@
+commit d30e582446b027868cdabd0994681643682045a4
+Author: Dr. Stephen Henson <steve@openssl.org>
+Date: Fri May 16 13:00:45 2014 +0100
+
+ Fix CVE-2014-0221
+
+ Unnecessary recursion when receiving a DTLS hello request can be used to
+ crash a DTLS client. Fixed by handling DTLS hello request without recursion.
+
+ Thanks to Imre Rad (Search-Lab Ltd.) for discovering this issue.
+
+Patch borrowed from Fedora
+Upstream-Status: Backport
+Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
+
+diff --git a/ssl/d1_both.c b/ssl/d1_both.c
+index 07f67f8..4c2fd03 100644
+--- a/ssl/d1_both.c
++++ b/ssl/d1_both.c
+@@ -793,6 +793,7 @@ dtls1_get_message_fragment(SSL *s, int st1, int stn, long max, int *ok)
+ int i,al;
+ struct hm_header_st msg_hdr;
+
++ redo:
+ /* see if we have the required fragment already */
+ if ((frag_len = dtls1_retrieve_buffered_fragment(s,max,ok)) || *ok)
+ {
+@@ -851,8 +852,7 @@ dtls1_get_message_fragment(SSL *s, int st1, int stn, long max, int *ok)
+ s->msg_callback_arg);
+
+ s->init_num = 0;
+- return dtls1_get_message_fragment(s, st1, stn,
+- max, ok);
++ goto redo;
+ }
+ else /* Incorrectly formated Hello request */
+ {
+
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-1.0.1e-cve-2014-0224.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-1.0.1e-cve-2014-0224.patch
new file mode 100644
index 0000000..0ed1d12
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-1.0.1e-cve-2014-0224.patch
@@ -0,0 +1,103 @@
+Fix for CVE-2014-0224
+
+Only accept change cipher spec when it is expected instead of at any
+time. This prevents premature setting of session keys before the master
+secret is determined which an attacker could use as a MITM attack.
+
+Thanks to KIKUCHI Masashi (Lepidum Co. Ltd.) for reporting this issue
+and providing the initial fix this patch is based on.
+
+
+Patch borrowed from Fedora
+Upstream-Status: Backport
+Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
+
+
+diff -up openssl-1.0.1e/ssl/ssl3.h.keying-mitm openssl-1.0.1e/ssl/ssl3.h
+--- openssl-1.0.1e/ssl/ssl3.h.keying-mitm 2014-06-02 19:48:04.518100562 +0200
++++ openssl-1.0.1e/ssl/ssl3.h 2014-06-02 19:48:04.642103429 +0200
+@@ -388,6 +388,7 @@ typedef struct ssl3_buffer_st
+ #define TLS1_FLAGS_TLS_PADDING_BUG 0x0008
+ #define TLS1_FLAGS_SKIP_CERT_VERIFY 0x0010
+ #define TLS1_FLAGS_KEEP_HANDSHAKE 0x0020
++#define SSL3_FLAGS_CCS_OK 0x0080
+
+ /* SSL3_FLAGS_SGC_RESTART_DONE is set when we
+ * restart a handshake because of MS SGC and so prevents us
+diff -up openssl-1.0.1e/ssl/s3_clnt.c.keying-mitm openssl-1.0.1e/ssl/s3_clnt.c
+--- openssl-1.0.1e/ssl/s3_clnt.c.keying-mitm 2013-02-11 16:26:04.000000000 +0100
++++ openssl-1.0.1e/ssl/s3_clnt.c 2014-06-02 19:49:57.042701985 +0200
+@@ -559,6 +559,7 @@ int ssl3_connect(SSL *s)
+ case SSL3_ST_CR_FINISHED_A:
+ case SSL3_ST_CR_FINISHED_B:
+
++ s->s3->flags |= SSL3_FLAGS_CCS_OK;
+ ret=ssl3_get_finished(s,SSL3_ST_CR_FINISHED_A,
+ SSL3_ST_CR_FINISHED_B);
+ if (ret <= 0) goto end;
+@@ -916,6 +917,7 @@ int ssl3_get_server_hello(SSL *s)
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT);
+ goto f_err;
+ }
++ s->s3->flags |= SSL3_FLAGS_CCS_OK;
+ s->hit=1;
+ }
+ else /* a miss or crap from the other end */
+diff -up openssl-1.0.1e/ssl/s3_pkt.c.keying-mitm openssl-1.0.1e/ssl/s3_pkt.c
+--- openssl-1.0.1e/ssl/s3_pkt.c.keying-mitm 2014-06-02 19:48:04.640103383 +0200
++++ openssl-1.0.1e/ssl/s3_pkt.c 2014-06-02 19:48:04.643103452 +0200
+@@ -1298,6 +1298,15 @@ start:
+ goto f_err;
+ }
+
++ if (!(s->s3->flags & SSL3_FLAGS_CCS_OK))
++ {
++ al=SSL_AD_UNEXPECTED_MESSAGE;
++ SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_CCS_RECEIVED_EARLY);
++ goto f_err;
++ }
++
++ s->s3->flags &= ~SSL3_FLAGS_CCS_OK;
++
+ rr->length=0;
+
+ if (s->msg_callback)
+@@ -1432,7 +1441,7 @@ int ssl3_do_change_cipher_spec(SSL *s)
+
+ if (s->s3->tmp.key_block == NULL)
+ {
+- if (s->session == NULL)
++ if (s->session == NULL || s->session->master_key_length == 0)
+ {
+ /* might happen if dtls1_read_bytes() calls this */
+ SSLerr(SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC,SSL_R_CCS_RECEIVED_EARLY);
+diff -up openssl-1.0.1e/ssl/s3_srvr.c.keying-mitm openssl-1.0.1e/ssl/s3_srvr.c
+--- openssl-1.0.1e/ssl/s3_srvr.c.keying-mitm 2014-06-02 19:48:04.630103151 +0200
++++ openssl-1.0.1e/ssl/s3_srvr.c 2014-06-02 19:48:04.643103452 +0200
+@@ -673,6 +673,7 @@ int ssl3_accept(SSL *s)
+ case SSL3_ST_SR_CERT_VRFY_A:
+ case SSL3_ST_SR_CERT_VRFY_B:
+
++ s->s3->flags |= SSL3_FLAGS_CCS_OK;
+ /* we should decide if we expected this one */
+ ret=ssl3_get_cert_verify(s);
+ if (ret <= 0) goto end;
+@@ -700,6 +701,7 @@ int ssl3_accept(SSL *s)
+
+ case SSL3_ST_SR_FINISHED_A:
+ case SSL3_ST_SR_FINISHED_B:
++ s->s3->flags |= SSL3_FLAGS_CCS_OK;
+ ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A,
+ SSL3_ST_SR_FINISHED_B);
+ if (ret <= 0) goto end;
+@@ -770,7 +772,10 @@ int ssl3_accept(SSL *s)
+ s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;
+ #else
+ if (s->s3->next_proto_neg_seen)
++ {
++ s->s3->flags |= SSL3_FLAGS_CCS_OK;
+ s->s3->tmp.next_state=SSL3_ST_SR_NEXT_PROTO_A;
++ }
+ else
+ s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;
+ #endif
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-1.0.1e-cve-2014-3470.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-1.0.1e-cve-2014-3470.patch
new file mode 100644
index 0000000..025727f
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-1.0.1e-cve-2014-3470.patch
@@ -0,0 +1,31 @@
+commit 4ad43d511f6cf064c66eb4bfd0fb0919b5dd8a86
+Author: Dr. Stephen Henson <steve@openssl.org>
+Date: Thu May 29 15:00:05 2014 +0100
+
+ Fix CVE-2014-3470
+
+ Check session_cert is not NULL before dereferencing it.
+
+Patch borrowed from Fedora
+Upstream-Status: Backport
+Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
+
+
+diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
+index d35376d..4324f8d 100644
+--- a/ssl/s3_clnt.c
++++ b/ssl/s3_clnt.c
+@@ -2511,6 +2511,13 @@ int ssl3_send_client_key_exchange(SSL *s)
+ int ecdh_clnt_cert = 0;
+ int field_size = 0;
+
++ if (s->session->sess_cert == NULL)
++ {
++ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_UNEXPECTED_MESSAGE);
++ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_UNEXPECTED_MESSAGE);
++ goto err;
++ }
++
+ /* Did we send out the client's
+ * ECDH share for use in premaster
+ * computation as part of client certificate?
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-CVE-2010-5298.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-CVE-2010-5298.patch
new file mode 100644
index 0000000..417a774
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-CVE-2010-5298.patch
@@ -0,0 +1,24 @@
+openssl fix for CVE-2010-5298
+
+Upstream-Status: Backport
+
+Race condition in the ssl3_read_bytes function in s3_pkt.c in OpenSSL
+through 1.0.1g, when SSL_MODE_RELEASE_BUFFERS is enabled, allows remote
+attackers to inject data across sessions or cause a denial of service
+(use-after-free and parsing error) via an SSL connection in a
+multithreaded environment.
+
+http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2010-5298
+
+Signed-off-by: Yue Tao <Yue.Tao@windriver.com>
+--- a/ssl/s3_pkt.c
++++ b/ssl/s3_pkt.c
+@@ -1013,7 +1013,7 @@ start:
+ {
+ s->rstate=SSL_ST_READ_HEADER;
+ rr->off=0;
+- if (s->mode & SSL_MODE_RELEASE_BUFFERS)
++ if (s->mode & SSL_MODE_RELEASE_BUFFERS && s->s3->rbuf.left == 0)
+ ssl3_release_read_buffer(s);
+ }
+ }
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-CVE-2014-0198-fix.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-CVE-2014-0198-fix.patch
new file mode 100644
index 0000000..4c51d74
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-CVE-2014-0198-fix.patch
@@ -0,0 +1,23 @@
+Upstream-Status: Backport
+
+Reference: https://bugzilla.redhat.com/show_bug.cgi?id=1093837
+
+CVE-2014-0198: An attacker can trigger generation of an SSL
+alert which could cause a null pointer dereference.
+
+Signed-off-by: Maxin B. John <maxin.john@enea.com>
+---
+diff -Naur openssl-1.0.1g-orig/ssl/s3_pkt.c openssl-1.0.1g/ssl/s3_pkt.c
+--- openssl-1.0.1g-orig/ssl/s3_pkt.c 2014-03-17 17:14:20.000000000 +0100
++++ openssl-1.0.1g/ssl/s3_pkt.c 2014-05-06 02:32:43.862587660 +0200
+@@ -657,6 +657,10 @@
+ if (i <= 0)
+ return(i);
+ /* if it went, fall through and send more stuff */
++ /* we may have released our buffer, so get it again */
++ if (wb->buf == NULL)
++ if (!ssl3_setup_write_buffer(s))
++ return -1;
+ }
+
+ if (len == 0 && !create_empty_fragment)
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-avoid-NULL-pointer-dereference-in-EVP_DigestInit_ex.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-avoid-NULL-pointer-dereference-in-EVP_DigestInit_ex.patch
new file mode 100644
index 0000000..c161e62
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-avoid-NULL-pointer-dereference-in-EVP_DigestInit_ex.patch
@@ -0,0 +1,21 @@
+openssl: avoid NULL pointer dereference in EVP_DigestInit_ex()
+
+We should avoid accessing the type pointer if it's NULL,
+this could happen if ctx->digest is not NULL.
+
+Upstream-Status: Submitted
+http://www.mail-archive.com/openssl-dev@openssl.org/msg32860.html
+
+Signed-off-by: Xufeng Zhang <xufeng.zhang@windriver.com>
+---
+--- a/crypto/evp/digest.c
++++ b/crypto/evp/digest.c
+@@ -199,7 +199,7 @@
+ return 0;
+ }
+ #endif
+- if (ctx->digest != type)
++ if (type && (ctx->digest != type))
+ {
+ if (ctx->digest && ctx->digest->ctx_size)
+ OPENSSL_free(ctx->md_data);
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-avoid-NULL-pointer-dereference-in-dh_pub_encode.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-avoid-NULL-pointer-dereference-in-dh_pub_encode.patch
new file mode 100644
index 0000000..3e93fe4
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-avoid-NULL-pointer-dereference-in-dh_pub_encode.patch
@@ -0,0 +1,39 @@
+openssl: avoid NULL pointer dereference in dh_pub_encode()/dsa_pub_encode()
+
+We should avoid accessing the pointer if ASN1_STRING_new()
+allocates memory failed.
+
+Upstream-Status: Submitted
+http://www.mail-archive.com/openssl-dev@openssl.org/msg32859.html
+
+Signed-off-by: Xufeng Zhang <xufeng.zhang@windriver.com>
+---
+--- a/crypto/dh/dh_ameth.c
++++ b/crypto/dh/dh_ameth.c
+@@ -139,6 +139,12 @@
+ dh=pkey->pkey.dh;
+
+ str = ASN1_STRING_new();
++ if (!str)
++ {
++ DHerr(DH_F_DH_PUB_ENCODE, ERR_R_MALLOC_FAILURE);
++ goto err;
++ }
++
+ str->length = i2d_DHparams(dh, &str->data);
+ if (str->length <= 0)
+ {
+--- a/crypto/dsa/dsa_ameth.c
++++ b/crypto/dsa/dsa_ameth.c
+@@ -148,6 +148,11 @@
+ {
+ ASN1_STRING *str;
+ str = ASN1_STRING_new();
++ if (!str)
++ {
++ DSAerr(DSA_F_DSA_PUB_ENCODE, ERR_R_MALLOC_FAILURE);
++ goto err;
++ }
+ str->length = i2d_DSAparams(dsa, &str->data);
+ if (str->length <= 0)
+ {
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-fix-des.pod-error.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-fix-des.pod-error.patch
new file mode 100644
index 0000000..de49729
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-fix-des.pod-error.patch
@@ -0,0 +1,19 @@
+openssl: Fix pod2man des.pod error on Ubuntu 12.04
+
+This is a formatting fix, '=back' is required before
+'=head1' on Ubuntu 12.04.
+
+Upstream-Status: Pending
+Signed-off-by: Baogen Shang <baogen.shang@windriver.com>
+diff -urpN a_origin/des.pod b_modify/des.pod
+--- a_origin/crypto/des/des.pod 2013-08-15 15:02:56.211674589 +0800
++++ b_modify/crypto/des/des.pod 2013-08-15 15:04:14.439674580 +0800
+@@ -181,6 +181,8 @@ the uuencoded file to embed in the begin
+ output. If there is no name specified after the B<-u>, the name text.des
+ will be embedded in the header.
+
++=back
++
+ =head1 SEE ALSO
+
+ ps(1),
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-fix-doc.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-fix-doc.patch
new file mode 100644
index 0000000..451256e
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-fix-doc.patch
@@ -0,0 +1,401 @@
+Fix documentation build errors with Perl 5.18 pod2man
+
+This fixes errors building man pages with newer versions of pod2man
+included with Perl 5.18.
+
+Upstream-Status: Submitted
+Signed-off-by: Jonathan Liu
+
+Index: openssl-1.0.1f/doc/apps/cms.pod
+===================================================================
+--- openssl-1.0.1f.orig/doc/apps/cms.pod 2014-01-06 15:47:42.000000000 +0200
++++ openssl-1.0.1f/doc/apps/cms.pod 2014-02-28 10:13:51.899979213 +0200
+@@ -450,28 +450,28 @@
+
+ =over 4
+
+-=item 0
++=item Z<>0
+
+ the operation was completely successfully.
+
+-=item 1
++=item Z<>1
+
+ an error occurred parsing the command options.
+
+-=item 2
++=item Z<>2
+
+ one of the input files could not be read.
+
+-=item 3
++=item Z<>3
+
+ an error occurred creating the CMS file or when reading the MIME
+ message.
+
+-=item 4
++=item Z<>4
+
+ an error occurred decrypting or verifying the message.
+
+-=item 5
++=item Z<>5
+
+ the message was verified correctly but an error occurred writing out
+ the signers certificates.
+Index: openssl-1.0.1f/doc/apps/smime.pod
+===================================================================
+--- openssl-1.0.1f.orig/doc/apps/smime.pod 2014-01-06 15:47:42.000000000 +0200
++++ openssl-1.0.1f/doc/apps/smime.pod 2014-02-28 10:16:57.795979233 +0200
+@@ -308,28 +308,28 @@
+
+ =over 4
+
+-=item 0
++=item Z<>0
+
+ the operation was completely successfully.
+
+-=item 1
++=item Z<>1
+
+ an error occurred parsing the command options.
+
+-=item 2
++=item Z<>2
+
+ one of the input files could not be read.
+
+-=item 3
++=item Z<>3
+
+ an error occurred creating the PKCS#7 file or when reading the MIME
+ message.
+
+-=item 4
++=item Z<>4
+
+ an error occurred decrypting or verifying the message.
+
+-=item 5
++=item Z<>5
+
+ the message was verified correctly but an error occurred writing out
+ the signers certificates.
+Index: openssl-1.0.1f/doc/ssl/SSL_COMP_add_compression_method.pod
+===================================================================
+--- openssl-1.0.1f.orig/doc/ssl/SSL_COMP_add_compression_method.pod 2014-01-06 15:47:42.000000000 +0200
++++ openssl-1.0.1f/doc/ssl/SSL_COMP_add_compression_method.pod 2014-02-28 10:18:09.679979225 +0200
+@@ -53,11 +53,11 @@
+
+ =over 4
+
+-=item 0
++=item Z<>0
+
+ The operation succeeded.
+
+-=item 1
++=item Z<>1
+
+ The operation failed. Check the error queue to find out the reason.
+
+Index: openssl-1.0.1f/doc/ssl/SSL_CTX_add_session.pod
+===================================================================
+--- openssl-1.0.1f.orig/doc/ssl/SSL_CTX_add_session.pod 2014-01-06 15:47:42.000000000 +0200
++++ openssl-1.0.1f/doc/ssl/SSL_CTX_add_session.pod 2014-02-28 10:18:42.687979221 +0200
+@@ -52,13 +52,13 @@
+
+ =over 4
+
+-=item 0
++=item Z<>0
+
+ The operation failed. In case of the add operation, it was tried to add
+ the same (identical) session twice. In case of the remove operation, the
+ session was not found in the cache.
+
+-=item 1
++=item Z<>1
+
+ The operation succeeded.
+
+Index: openssl-1.0.1f/doc/ssl/SSL_CTX_load_verify_locations.pod
+===================================================================
+--- openssl-1.0.1f.orig/doc/ssl/SSL_CTX_load_verify_locations.pod 2014-01-06 15:47:42.000000000 +0200
++++ openssl-1.0.1f/doc/ssl/SSL_CTX_load_verify_locations.pod 2014-02-28 10:19:09.079979218 +0200
+@@ -100,13 +100,13 @@
+
+ =over 4
+
+-=item 0
++=item Z<>0
+
+ The operation failed because B<CAfile> and B<CApath> are NULL or the
+ processing at one of the locations specified failed. Check the error
+ stack to find out the reason.
+
+-=item 1
++=item Z<>1
+
+ The operation succeeded.
+
+Index: openssl-1.0.1f/doc/ssl/SSL_CTX_set_client_CA_list.pod
+===================================================================
+--- openssl-1.0.1f.orig/doc/ssl/SSL_CTX_set_client_CA_list.pod 2014-01-06 15:47:42.000000000 +0200
++++ openssl-1.0.1f/doc/ssl/SSL_CTX_set_client_CA_list.pod 2014-02-28 10:19:42.999979220 +0200
+@@ -66,13 +66,13 @@
+
+ =over 4
+
+-=item 0
++=item Z<>0
+
+ A failure while manipulating the STACK_OF(X509_NAME) object occurred or
+ the X509_NAME could not be extracted from B<cacert>. Check the error stack
+ to find out the reason.
+
+-=item 1
++=item Z<>1
+
+ The operation succeeded.
+
+Index: openssl-1.0.1f/doc/ssl/SSL_CTX_set_session_id_context.pod
+===================================================================
+--- openssl-1.0.1f.orig/doc/ssl/SSL_CTX_set_session_id_context.pod 2014-01-06 15:47:42.000000000 +0200
++++ openssl-1.0.1f/doc/ssl/SSL_CTX_set_session_id_context.pod 2014-02-28 10:20:06.495979211 +0200
+@@ -64,13 +64,13 @@
+
+ =over 4
+
+-=item 0
++=item Z<>0
+
+ The length B<sid_ctx_len> of the session id context B<sid_ctx> exceeded
+ the maximum allowed length of B<SSL_MAX_SSL_SESSION_ID_LENGTH>. The error
+ is logged to the error stack.
+
+-=item 1
++=item Z<>1
+
+ The operation succeeded.
+
+Index: openssl-1.0.1f/doc/ssl/SSL_CTX_set_ssl_version.pod
+===================================================================
+--- openssl-1.0.1f.orig/doc/ssl/SSL_CTX_set_ssl_version.pod 2014-01-06 15:47:42.000000000 +0200
++++ openssl-1.0.1f/doc/ssl/SSL_CTX_set_ssl_version.pod 2014-02-28 10:20:32.111979208 +0200
+@@ -42,11 +42,11 @@
+
+ =over 4
+
+-=item 0
++=item Z<>0
+
+ The new choice failed, check the error stack to find out the reason.
+
+-=item 1
++=item Z<>1
+
+ The operation succeeded.
+
+Index: openssl-1.0.1f/doc/ssl/SSL_CTX_use_psk_identity_hint.pod
+===================================================================
+--- openssl-1.0.1f.orig/doc/ssl/SSL_CTX_use_psk_identity_hint.pod 2014-01-06 15:47:42.000000000 +0200
++++ openssl-1.0.1f/doc/ssl/SSL_CTX_use_psk_identity_hint.pod 2014-02-28 10:21:12.351979203 +0200
+@@ -96,7 +96,7 @@
+ connection will fail with decryption_error before it will be finished
+ completely.
+
+-=item 0
++=item Z<>0
+
+ PSK identity was not found. An "unknown_psk_identity" alert message
+ will be sent and the connection setup fails.
+Index: openssl-1.0.1f/doc/ssl/SSL_accept.pod
+===================================================================
+--- openssl-1.0.1f.orig/doc/ssl/SSL_accept.pod 2014-01-06 15:47:42.000000000 +0200
++++ openssl-1.0.1f/doc/ssl/SSL_accept.pod 2014-02-28 10:21:51.535979215 +0200
+@@ -44,13 +44,13 @@
+
+ =over 4
+
+-=item 0
++=item Z<>0
+
+ The TLS/SSL handshake was not successful but was shut down controlled and
+ by the specifications of the TLS/SSL protocol. Call SSL_get_error() with the
+ return value B<ret> to find out the reason.
+
+-=item 1
++=item Z<>1
+
+ The TLS/SSL handshake was successfully completed, a TLS/SSL connection has been
+ established.
+Index: openssl-1.0.1f/doc/ssl/SSL_clear.pod
+===================================================================
+--- openssl-1.0.1f.orig/doc/ssl/SSL_clear.pod 2014-01-06 15:47:42.000000000 +0200
++++ openssl-1.0.1f/doc/ssl/SSL_clear.pod 2014-02-28 10:22:13.087979196 +0200
+@@ -56,12 +56,12 @@
+
+ =over 4
+
+-=item 0
++=item Z<>0
+
+ The SSL_clear() operation could not be performed. Check the error stack to
+ find out the reason.
+
+-=item 1
++=item Z<>1
+
+ The SSL_clear() operation was successful.
+
+Index: openssl-1.0.1f/doc/ssl/SSL_connect.pod
+===================================================================
+--- openssl-1.0.1f.orig/doc/ssl/SSL_connect.pod 2014-01-06 15:47:42.000000000 +0200
++++ openssl-1.0.1f/doc/ssl/SSL_connect.pod 2014-02-28 10:22:33.991979193 +0200
+@@ -41,13 +41,13 @@
+
+ =over 4
+
+-=item 0
++=item Z<>0
+
+ The TLS/SSL handshake was not successful but was shut down controlled and
+ by the specifications of the TLS/SSL protocol. Call SSL_get_error() with the
+ return value B<ret> to find out the reason.
+
+-=item 1
++=item Z<>1
+
+ The TLS/SSL handshake was successfully completed, a TLS/SSL connection has been
+ established.
+Index: openssl-1.0.1f/doc/ssl/SSL_do_handshake.pod
+===================================================================
+--- openssl-1.0.1f.orig/doc/ssl/SSL_do_handshake.pod 2014-01-06 15:47:42.000000000 +0200
++++ openssl-1.0.1f/doc/ssl/SSL_do_handshake.pod 2014-02-28 10:22:56.887979159 +0200
+@@ -45,13 +45,13 @@
+
+ =over 4
+
+-=item 0
++=item Z<>0
+
+ The TLS/SSL handshake was not successful but was shut down controlled and
+ by the specifications of the TLS/SSL protocol. Call SSL_get_error() with the
+ return value B<ret> to find out the reason.
+
+-=item 1
++=item Z<>1
+
+ The TLS/SSL handshake was successfully completed, a TLS/SSL connection has been
+ established.
+Index: openssl-1.0.1f/doc/ssl/SSL_read.pod
+===================================================================
+--- openssl-1.0.1f.orig/doc/ssl/SSL_read.pod 2014-01-06 15:47:42.000000000 +0200
++++ openssl-1.0.1f/doc/ssl/SSL_read.pod 2014-02-28 10:23:15.303979188 +0200
+@@ -86,7 +86,7 @@
+ The read operation was successful; the return value is the number of
+ bytes actually read from the TLS/SSL connection.
+
+-=item 0
++=item Z<>0
+
+ The read operation was not successful. The reason may either be a clean
+ shutdown due to a "close notify" alert sent by the peer (in which case
+Index: openssl-1.0.1f/doc/ssl/SSL_session_reused.pod
+===================================================================
+--- openssl-1.0.1f.orig/doc/ssl/SSL_session_reused.pod 2014-01-06 15:47:42.000000000 +0200
++++ openssl-1.0.1f/doc/ssl/SSL_session_reused.pod 2014-02-28 10:23:36.615979186 +0200
+@@ -27,11 +27,11 @@
+
+ =over 4
+
+-=item 0
++=item Z<>0
+
+ A new session was negotiated.
+
+-=item 1
++=item Z<>1
+
+ A session was reused.
+
+Index: openssl-1.0.1f/doc/ssl/SSL_set_fd.pod
+===================================================================
+--- openssl-1.0.1f.orig/doc/ssl/SSL_set_fd.pod 2014-01-06 15:47:42.000000000 +0200
++++ openssl-1.0.1f/doc/ssl/SSL_set_fd.pod 2014-02-28 10:23:57.599979183 +0200
+@@ -35,11 +35,11 @@
+
+ =over 4
+
+-=item 0
++=item Z<>0
+
+ The operation failed. Check the error stack to find out why.
+
+-=item 1
++=item Z<>1
+
+ The operation succeeded.
+
+Index: openssl-1.0.1f/doc/ssl/SSL_set_session.pod
+===================================================================
+--- openssl-1.0.1f.orig/doc/ssl/SSL_set_session.pod 2014-01-06 15:47:42.000000000 +0200
++++ openssl-1.0.1f/doc/ssl/SSL_set_session.pod 2014-02-28 10:24:16.943979181 +0200
+@@ -37,11 +37,11 @@
+
+ =over 4
+
+-=item 0
++=item Z<>0
+
+ The operation failed; check the error stack to find out the reason.
+
+-=item 1
++=item Z<>1
+
+ The operation succeeded.
+
+Index: openssl-1.0.1f/doc/ssl/SSL_shutdown.pod
+===================================================================
+--- openssl-1.0.1f.orig/doc/ssl/SSL_shutdown.pod 2014-01-06 15:47:42.000000000 +0200
++++ openssl-1.0.1f/doc/ssl/SSL_shutdown.pod 2014-02-28 10:25:03.623979175 +0200
+@@ -92,19 +92,19 @@
+
+ =over 4
+
+-=item 0
++=item Z<>0
+
+ The shutdown is not yet finished. Call SSL_shutdown() for a second time,
+ if a bidirectional shutdown shall be performed.
+ The output of L<SSL_get_error(3)|SSL_get_error(3)> may be misleading, as an
+ erroneous SSL_ERROR_SYSCALL may be flagged even though no error occurred.
+
+-=item 1
++=item Z<>1
+
+ The shutdown was successfully completed. The "close notify" alert was sent
+ and the peer's "close notify" alert was received.
+
+-=item -1
++=item Z<>-1
+
+ The shutdown was not successful because a fatal error occurred either
+ at the protocol level or a connection failure occurred. It can also occur if
+Index: openssl-1.0.1f/doc/ssl/SSL_write.pod
+===================================================================
+--- openssl-1.0.1f.orig/doc/ssl/SSL_write.pod 2014-01-06 15:47:42.000000000 +0200
++++ openssl-1.0.1f/doc/ssl/SSL_write.pod 2014-02-28 10:25:36.031979168 +0200
+@@ -79,7 +79,7 @@
+ The write operation was successful, the return value is the number of
+ bytes actually written to the TLS/SSL connection.
+
+-=item 0
++=item Z<>0
+
+ The write operation was not successful. Probably the underlying connection
+ was closed. Call SSL_get_error() with the return value B<ret> to find out,
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-fix-link.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-fix-link.patch
new file mode 100644
index 0000000..154106c
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl-fix-link.patch
@@ -0,0 +1,35 @@
+From aabfb6f78af8e337d3239142117ba303fce55e7e Mon Sep 17 00:00:00 2001
+From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+Date: Thu, 22 Sep 2011 08:55:26 +0200
+Subject: [PATCH] fix the parallel build regarding shared libraries.
+
+Upstream-Status: Pending
+---
+ .../openssl-1.0.0e/Makefile.org | 8 ++++----
+ 1 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/Makefile.org
+index 3c7aea1..6326cd6 100644
+--- a/Makefile.org
++++ b/Makefile.org
+@@ -243,13 +243,13 @@ build_libs: build_crypto build_ssl build_engines
+
+ build_crypto:
+ @dir=crypto; target=all; $(BUILD_ONE_CMD)
+-build_ssl:
++build_ssl: build_crypto
+ @dir=ssl; target=all; $(BUILD_ONE_CMD)
+-build_engines:
++build_engines: build_crypto
+ @dir=engines; target=all; $(BUILD_ONE_CMD)
+-build_apps:
++build_apps: build_crypto build_ssl
+ @dir=apps; target=all; $(BUILD_ONE_CMD)
+-build_tests:
++build_tests: build_crypto build_ssl
+ @dir=test; target=all; $(BUILD_ONE_CMD)
+ build_tools:
+ @dir=tools; target=all; $(BUILD_ONE_CMD)
+--
+1.6.6.1
+
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl_fix_for_x32.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl_fix_for_x32.patch
new file mode 100644
index 0000000..93ce034
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/openssl_fix_for_x32.patch
@@ -0,0 +1,90 @@
+Upstream-Status: Pending
+
+Received from H J Liu @ Intel
+Make the assembly syntax compatible with x32 gcc. Othewise x32 gcc throws errors.
+Signed-Off-By: Nitin A Kamble <nitin.a.kamble@intel.com> 2011/07/13
+
+ported the patch to the 1.0.0e version
+Signed-Off-By: Nitin A Kamble <nitin.a.kamble@intel.com> 2011/12/01
+Index: openssl-1.0.1e/Configure
+===================================================================
+--- openssl-1.0.1e.orig/Configure
++++ openssl-1.0.1e/Configure
+@@ -402,6 +402,7 @@ my %table=(
+ "linux-ia64-ecc","ecc:-DL_ENDIAN -DTERMIO -O2 -Wall -no_cpprt::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT:${ia64_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
+ "linux-ia64-icc","icc:-DL_ENDIAN -DTERMIO -O2 -Wall -no_cpprt::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_RISC1 DES_INT:${ia64_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
+ "linux-x86_64", "gcc:-m64 -DL_ENDIAN -DTERMIO -O3 -Wall::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHUNK DES_INT DES_UNROLL:${x86_64_asm}:elf:dlfcn:linux-shared:-fPIC:-m64:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR):::64",
++"linux-x32", "gcc:-mx32 -DL_ENDIAN -DTERMIO -O3 -Wall -DMD32_REG_T=int::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT RC4_CHUNK DES_INT DES_UNROLL:${x86_64_asm}:elf:dlfcn:linux-shared:-fPIC:-mx32:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR):::x32",
+ "linux64-s390x", "gcc:-m64 -DB_ENDIAN -DTERMIO -O3 -Wall::-D_REENTRANT::-ldl:SIXTY_FOUR_BIT_LONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL:${s390x_asm}:64:dlfcn:linux-shared:-fPIC:-m64:.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR):::64",
+ #### So called "highgprs" target for z/Architecture CPUs
+ # "Highgprs" is kernel feature first implemented in Linux 2.6.32, see
+Index: openssl-1.0.1e/crypto/bn/asm/x86_64-gcc.c
+===================================================================
+--- openssl-1.0.1e.orig/crypto/bn/asm/x86_64-gcc.c
++++ openssl-1.0.1e/crypto/bn/asm/x86_64-gcc.c
+@@ -55,7 +55,7 @@
+ * machine.
+ */
+
+-#ifdef _WIN64
++#if defined _WIN64 || !defined __LP64__
+ #define BN_ULONG unsigned long long
+ #else
+ #define BN_ULONG unsigned long
+@@ -192,9 +192,9 @@ BN_ULONG bn_add_words (BN_ULONG *rp, con
+ asm (
+ " subq %2,%2 \n"
+ ".p2align 4 \n"
+- "1: movq (%4,%2,8),%0 \n"
+- " adcq (%5,%2,8),%0 \n"
+- " movq %0,(%3,%2,8) \n"
++ "1: movq (%q4,%2,8),%0 \n"
++ " adcq (%q5,%2,8),%0 \n"
++ " movq %0,(%q3,%2,8) \n"
+ " leaq 1(%2),%2 \n"
+ " loop 1b \n"
+ " sbbq %0,%0 \n"
+@@ -215,9 +215,9 @@ BN_ULONG bn_sub_words (BN_ULONG *rp, con
+ asm (
+ " subq %2,%2 \n"
+ ".p2align 4 \n"
+- "1: movq (%4,%2,8),%0 \n"
+- " sbbq (%5,%2,8),%0 \n"
+- " movq %0,(%3,%2,8) \n"
++ "1: movq (%q4,%2,8),%0 \n"
++ " sbbq (%q5,%2,8),%0 \n"
++ " movq %0,(%q3,%2,8) \n"
+ " leaq 1(%2),%2 \n"
+ " loop 1b \n"
+ " sbbq %0,%0 \n"
+Index: openssl-1.0.1e/crypto/bn/bn.h
+===================================================================
+--- openssl-1.0.1e.orig/crypto/bn/bn.h
++++ openssl-1.0.1e/crypto/bn/bn.h
+@@ -172,6 +172,13 @@ extern "C" {
+ # endif
+ #endif
+
++/* Address type. */
++#ifdef _WIN64
++#define BN_ADDR unsigned long long
++#else
++#define BN_ADDR unsigned long
++#endif
++
+ /* assuming long is 64bit - this is the DEC Alpha
+ * unsigned long long is only 64 bits :-(, don't define
+ * BN_LLONG for the DEC Alpha */
+Index: openssl-1.0.1e/crypto/bn/bn_exp.c
+===================================================================
+--- openssl-1.0.1e.orig/crypto/bn/bn_exp.c
++++ openssl-1.0.1e/crypto/bn/bn_exp.c
+@@ -567,7 +567,7 @@ static int MOD_EXP_CTIME_COPY_FROM_PREBU
+
+ /* Given a pointer value, compute the next address that is a cache line multiple. */
+ #define MOD_EXP_CTIME_ALIGN(x_) \
+- ((unsigned char*)(x_) + (MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH - (((size_t)(x_)) & (MOD_EXP_CTIME_MIN_CACHE_LINE_MASK))))
++ ((unsigned char*)(x_) + (MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH - (((BN_ADDR)(x_)) & (MOD_EXP_CTIME_MIN_CACHE_LINE_MASK))))
+
+ /* This variant of BN_mod_exp_mont() uses fixed windows and the special
+ * precomputation memory layout to limit data-dependency to a minimum
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl/shared-libs.patch b/meta-edison-distro/recipes-connectivity/openssl/openssl/shared-libs.patch
new file mode 100644
index 0000000..a7ca0a3
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl/shared-libs.patch
@@ -0,0 +1,41 @@
+Upstream-Status: Inappropriate [configuration]
+
+Index: openssl-1.0.1e/crypto/Makefile
+===================================================================
+--- openssl-1.0.1e.orig/crypto/Makefile
++++ openssl-1.0.1e/crypto/Makefile
+@@ -108,7 +108,7 @@ $(LIB): $(LIBOBJ)
+
+ shared: buildinf.h lib subdirs
+ if [ -n "$(SHARED_LIBS)" ]; then \
+- (cd ..; $(MAKE) $(SHARED_LIB)); \
++ (cd ..; $(MAKE) -e $(SHARED_LIB)); \
+ fi
+
+ libs:
+Index: openssl-1.0.1e/Makefile.org
+===================================================================
+--- openssl-1.0.1e.orig/Makefile.org
++++ openssl-1.0.1e/Makefile.org
+@@ -310,7 +310,7 @@ libcrypto$(SHLIB_EXT): libcrypto.a fips_
+
+ libssl$(SHLIB_EXT): libcrypto$(SHLIB_EXT) libssl.a
+ @if [ "$(SHLIB_TARGET)" != "" ]; then \
+- $(MAKE) SHLIBDIRS=ssl SHLIBDEPS='-lcrypto' build-shared; \
++ $(MAKE) -e SHLIBDIRS=ssl SHLIBDEPS='-lcrypto' build-shared; \
+ else \
+ echo "There's no support for shared libraries on this platform" >&2; \
+ exit 1; \
+Index: openssl-1.0.1e/ssl/Makefile
+===================================================================
+--- openssl-1.0.1e.orig/ssl/Makefile
++++ openssl-1.0.1e/ssl/Makefile
+@@ -62,7 +62,7 @@ lib: $(LIBOBJ)
+
+ shared: lib
+ if [ -n "$(SHARED_LIBS)" ]; then \
+- (cd ..; $(MAKE) $(SHARED_LIB)); \
++ (cd ..; $(MAKE) -e $(SHARED_LIB)); \
+ fi
+
+ files:
diff --git a/meta-edison-distro/recipes-connectivity/openssl/openssl_1.0.1j.bb b/meta-edison-distro/recipes-connectivity/openssl/openssl_1.0.1j.bb
new file mode 100644
index 0000000..ecb31d0
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/openssl/openssl_1.0.1j.bb
@@ -0,0 +1,54 @@
+require openssl.inc
+
+# For target side versions of openssl enable support for OCF Linux driver
+# if they are available.
+DEPENDS += "cryptodev-linux"
+
+CFLAG += "-DHAVE_CRYPTODEV -DUSE_CRYPTODEV_DIGESTS"
+
+LIC_FILES_CHKSUM = "file://LICENSE;md5=f9a8f968107345e0b75aa8c2ecaa7ec8"
+
+export DIRS = "crypto ssl apps engines"
+export OE_LDFLAGS="${LDFLAGS}"
+
+SRC_URI += "file://configure-targets.patch \
+ file://shared-libs.patch \
+ file://oe-ldflags.patch \
+ file://engines-install-in-libdir-ssl.patch \
+ file://openssl-fix-link.patch \
+ file://debian/version-script.patch \
+ file://debian/pic.patch \
+ file://debian/c_rehash-compat.patch \
+ file://debian/ca.patch \
+ file://debian/make-targets.patch \
+ file://debian/no-rpath.patch \
+ file://debian/man-dir.patch \
+ file://debian/man-section.patch \
+ file://debian/no-symbolic.patch \
+ file://debian/debian-targets.patch \
+ file://openssl_fix_for_x32.patch \
+ file://fix-cipher-des-ede3-cfb1.patch \
+ file://openssl-avoid-NULL-pointer-dereference-in-EVP_DigestInit_ex.patch \
+ file://openssl-avoid-NULL-pointer-dereference-in-dh_pub_encode.patch \
+ file://initial-aarch64-bits.patch \
+ file://find.pl \
+ file://openssl-fix-des.pod-error.patch \
+ "
+
+SRC_URI[md5sum] = "f7175c9cd3c39bb1907ac8bba9df8ed3"
+SRC_URI[sha256sum] = "1b60ca8789ba6f03e8ef20da2293b8dc131c39d83814e775069f02d26354edf3"
+
+PACKAGES =+ " \
+ ${PN}-engines \
+ ${PN}-engines-dbg \
+ "
+
+FILES_${PN}-engines = "${libdir}/ssl/engines/*.so ${libdir}/engines"
+FILES_${PN}-engines-dbg = "${libdir}/ssl/engines/.debug"
+
+PARALLEL_MAKE = ""
+PARALLEL_MAKEINST = ""
+
+do_configure_prepend() {
+ cp ${WORKDIR}/find.pl ${S}/util/find.pl
+}
diff --git a/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/99_wpa_supplicant b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/99_wpa_supplicant
new file mode 100644
index 0000000..6ff4dd8
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/99_wpa_supplicant
@@ -0,0 +1 @@
+d root root 0700 /var/run/wpa_supplicant none
diff --git a/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/defconfig-gnutls b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/defconfig-gnutls
new file mode 100644
index 0000000..71f42e6
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/defconfig-gnutls
@@ -0,0 +1,440 @@
+# Example wpa_supplicant build time configuration
+#
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cases, these lines should use += in order not
+# to override previous values of the variables.
+
+
+# Uncomment following two lines and fix the paths if you have installed OpenSSL
+# or GnuTLS in non-default location
+#CFLAGS += -I/usr/local/openssl/include
+#LIBS += -L/usr/local/openssl/lib
+
+# Some Red Hat versions seem to include kerberos header files from OpenSSL, but
+# the kerberos files are not in the default include path. Following line can be
+# used to fix build issues on such systems (krb5.h not found).
+#CFLAGS += -I/usr/include/kerberos
+
+# Example configuration for various cross-compilation platforms
+
+#### sveasoft (e.g., for Linksys WRT54G) ######################################
+#CC=mipsel-uclibc-gcc
+#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
+#CFLAGS += -Os
+#CPPFLAGS += -I../src/include -I../../src/router/openssl/include
+#LIBS += -L/opt/brcm/hndtools-mipsel-uclibc-0.9.19/lib -lssl
+###############################################################################
+
+#### openwrt (e.g., for Linksys WRT54G) #######################################
+#CC=mipsel-uclibc-gcc
+#CC=/opt/brcm/hndtools-mipsel-uclibc/bin/mipsel-uclibc-gcc
+#CFLAGS += -Os
+#CPPFLAGS=-I../src/include -I../openssl-0.9.7d/include \
+# -I../WRT54GS/release/src/include
+#LIBS = -lssl
+###############################################################################
+
+
+# Driver interface for Host AP driver
+CONFIG_DRIVER_HOSTAP=y
+
+# Driver interface for Agere driver
+#CONFIG_DRIVER_HERMES=y
+# Change include directories to match with the local setup
+#CFLAGS += -I../../hcf -I../../include -I../../include/hcf
+#CFLAGS += -I../../include/wireless
+
+# Driver interface for madwifi driver
+# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
+#CONFIG_DRIVER_MADWIFI=y
+# Set include directory to the madwifi source tree
+#CFLAGS += -I../../madwifi
+
+# Driver interface for ndiswrapper
+# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
+#CONFIG_DRIVER_NDISWRAPPER=y
+
+# Driver interface for Atmel driver
+# CONFIG_DRIVER_ATMEL=y
+
+# Driver interface for old Broadcom driver
+# Please note that the newer Broadcom driver ("hybrid Linux driver") supports
+# Linux wireless extensions and does not need (or even work) with the old
+# driver wrapper. Use CONFIG_DRIVER_WEXT=y with that driver.
+#CONFIG_DRIVER_BROADCOM=y
+# Example path for wlioctl.h; change to match your configuration
+#CFLAGS += -I/opt/WRT54GS/release/src/include
+
+# Driver interface for Intel ipw2100/2200 driver
+# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
+#CONFIG_DRIVER_IPW=y
+
+# Driver interface for Ralink driver
+#CONFIG_DRIVER_RALINK=y
+
+# Driver interface for generic Linux wireless extensions
+#CONFIG_DRIVER_WEXT=y
+
+# Driver interface for Linux drivers using the nl80211 kernel interface
+CONFIG_LIBNL32=y
+CONFIG_DRIVER_NL80211=y
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+#LIBS_p += -L/usr/local/lib
+#LIBS_c += -L/usr/local/lib
+
+# Driver interface for Windows NDIS
+#CONFIG_DRIVER_NDIS=y
+#CFLAGS += -I/usr/include/w32api/ddk
+#LIBS += -L/usr/local/lib
+# For native build using mingw
+#CONFIG_NATIVE_WINDOWS=y
+# Additional directories for cross-compilation on Linux host for mingw target
+#CFLAGS += -I/opt/mingw/mingw32/include/ddk
+#LIBS += -L/opt/mingw/mingw32/lib
+#CC=mingw32-gcc
+# By default, driver_ndis uses WinPcap for low-level operations. This can be
+# replaced with the following option which replaces WinPcap calls with NDISUIO.
+# However, this requires that WZC is disabled (net stop wzcsvc) before starting
+# wpa_supplicant.
+# CONFIG_USE_NDISUIO=y
+
+# Driver interface for development testing
+#CONFIG_DRIVER_TEST=y
+
+# Include client MLME (management frame processing) for test driver
+# This can be used to test MLME operations in hostapd with the test interface.
+# space.
+#CONFIG_CLIENT_MLME=y
+
+# Driver interface for wired Ethernet drivers
+#CONFIG_DRIVER_WIRED=y
+
+# Driver interface for the Broadcom RoboSwitch family
+#CONFIG_DRIVER_ROBOSWITCH=y
+
+# Driver interface for no driver (e.g., WPS ER only)
+#CONFIG_DRIVER_NONE=y
+
+# Enable IEEE 802.1X Supplicant (automatically included if any EAP method is
+# included)
+CONFIG_IEEE8021X_EAPOL=y
+
+# EAP-MD5
+CONFIG_EAP_MD5=y
+
+# EAP-MSCHAPv2
+CONFIG_EAP_MSCHAPV2=y
+
+# EAP-TLS
+CONFIG_EAP_TLS=y
+
+# EAL-PEAP
+CONFIG_EAP_PEAP=y
+
+# EAP-TTLS
+CONFIG_EAP_TTLS=y
+
+# EAP-FAST
+# Note: Default OpenSSL package does not include support for all the
+# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
+# the OpenSSL library must be patched (openssl-0.9.8d-tls-extensions.patch)
+# to add the needed functions.
+CONFIG_EAP_FAST=y
+
+# EAP-GTC
+CONFIG_EAP_GTC=y
+
+# EAP-OTP
+CONFIG_EAP_OTP=y
+
+# EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used)
+#CONFIG_EAP_SIM=y
+
+# EAP-PSK (experimental; this is _not_ needed for WPA-PSK)
+#CONFIG_EAP_PSK=y
+
+# EAP-PAX
+#CONFIG_EAP_PAX=y
+
+# LEAP
+CONFIG_EAP_LEAP=y
+
+# EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used)
+#CONFIG_EAP_AKA=y
+
+# EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used).
+# This requires CONFIG_EAP_AKA to be enabled, too.
+#CONFIG_EAP_AKA_PRIME=y
+
+# Enable USIM simulator (Milenage) for EAP-AKA
+#CONFIG_USIM_SIMULATOR=y
+
+# EAP-SAKE
+#CONFIG_EAP_SAKE=y
+
+# EAP-GPSK
+#CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+#CONFIG_EAP_GPSK_SHA256=y
+
+# EAP-TNC and related Trusted Network Connect support (experimental)
+#CONFIG_EAP_TNC=y
+
+# Wi-Fi Protected Setup (WPS)
+CONFIG_WPS=y
+# Enable WSC 2.0 support
+CONFIG_WPS2=y
+
+# EAP-IKEv2
+#CONFIG_EAP_IKEV2=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+CONFIG_PKCS12=y
+
+# Smartcard support (i.e., private key on a smartcard), e.g., with openssl
+# engine.
+CONFIG_SMARTCARD=y
+
+# PC/SC interface for smartcards (USIM, GSM SIM)
+# Enable this if EAP-SIM or EAP-AKA is included
+#CONFIG_PCSC=y
+
+# Development testing
+#CONFIG_EAPOL_TEST=y
+
+# Select control interface backend for external programs, e.g, wpa_cli:
+# unix = UNIX domain sockets (default for Linux/*BSD)
+# udp = UDP sockets using localhost (127.0.0.1)
+# named_pipe = Windows Named Pipe (default for Windows)
+# y = use default (backwards compatibility)
+# If this option is commented out, control interface is not included in the
+# build.
+CONFIG_CTRL_IFACE=y
+
+# Include support for GNU Readline and History Libraries in wpa_cli.
+# When building a wpa_cli binary for distribution, please note that these
+# libraries are licensed under GPL and as such, BSD license may not apply for
+# the resulting binary.
+#CONFIG_READLINE=y
+
+# Remove debugging code that is printing out debug message to stdout.
+# This can be used to reduce the size of the wpa_supplicant considerably
+# if debugging code is not needed. The size reduction can be around 35%
+# (e.g., 90 kB).
+#CONFIG_NO_STDOUT_DEBUG=y
+
+# Remove WPA support, e.g., for wired-only IEEE 802.1X supplicant, to save
+# 35-50 kB in code size.
+#CONFIG_NO_WPA=y
+
+# Remove WPA2 support. This allows WPA to be used, but removes WPA2 code to
+# save about 1 kB in code size when building only WPA-Personal (no EAP support)
+# or 6 kB if building for WPA-Enterprise.
+#CONFIG_NO_WPA2=y
+
+# Remove IEEE 802.11i/WPA-Personal ASCII passphrase support
+# This option can be used to reduce code size by removing support for
+# converting ASCII passphrases into PSK. If this functionality is removed, the
+# PSK can only be configured as the 64-octet hexstring (e.g., from
+# wpa_passphrase). This saves about 0.5 kB in code size.
+#CONFIG_NO_WPA_PASSPHRASE=y
+
+# Disable scan result processing (ap_mode=1) to save code size by about 1 kB.
+# This can be used if ap_scan=1 mode is never enabled.
+#CONFIG_NO_SCAN_PROCESSING=y
+
+# Select configuration backend:
+# file = text file (e.g., wpa_supplicant.conf; note: the configuration file
+# path is given on command line, not here; this option is just used to
+# select the backend that allows configuration files to be used)
+# winreg = Windows registry (see win_example.reg for an example)
+CONFIG_BACKEND=file
+
+# Remove configuration write functionality (i.e., to allow the configuration
+# file to be updated based on runtime configuration changes). The runtime
+# configuration can still be changed, the changes are just not going to be
+# persistent over restarts. This option can be used to reduce code size by
+# about 3.5 kB.
+#CONFIG_NO_CONFIG_WRITE=y
+
+# Remove support for configuration blobs to reduce code size by about 1.5 kB.
+#CONFIG_NO_CONFIG_BLOBS=y
+
+# Select program entry point implementation:
+# main = UNIX/POSIX like main() function (default)
+# main_winsvc = Windows service (read parameters from registry)
+# main_none = Very basic example (development use only)
+#CONFIG_MAIN=main
+
+# Select wrapper for operatins system and C library specific functions
+# unix = UNIX/POSIX like systems (default)
+# win32 = Windows systems
+# none = Empty template
+#CONFIG_OS=unix
+
+# Select event loop implementation
+# eloop = select() loop (default)
+# eloop_win = Windows events and WaitForMultipleObject() loop
+# eloop_none = Empty template
+#CONFIG_ELOOP=eloop
+
+# Select layer 2 packet implementation
+# linux = Linux packet socket (default)
+# pcap = libpcap/libdnet/WinPcap
+# freebsd = FreeBSD libpcap
+# winpcap = WinPcap with receive thread
+# ndis = Windows NDISUIO (note: requires CONFIG_USE_NDISUIO=y)
+# none = Empty template
+#CONFIG_L2_PACKET=linux
+
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection)
+# This version is an experimental implementation based on IEEE 802.11w/D1.0
+# draft and is subject to change since the standard has not yet been finalized.
+# Driver support is also needed for IEEE 802.11w.
+#CONFIG_IEEE80211W=y
+
+# Select TLS implementation
+# openssl = OpenSSL (default)
+# gnutls = GnuTLS (needed for TLS/IA, see also CONFIG_GNUTLS_EXTRA)
+# internal = Internal TLSv1 implementation (experimental)
+# none = Empty template
+CONFIG_TLS=openssl
+
+# Whether to enable TLS/IA support, which is required for EAP-TTLSv1.
+# You need CONFIG_TLS=gnutls for this to have any effect. Please note that
+# even though the core GnuTLS library is released under LGPL, this extra
+# library uses GPL and as such, the terms of GPL apply to the combination
+# of wpa_supplicant and GnuTLS if this option is enabled. BSD license may not
+# apply for distribution of the resulting binary.
+#CONFIG_GNUTLS_EXTRA=y
+
+# If CONFIG_TLS=internal is used, additional library and include paths are
+# needed for LibTomMath. Alternatively, an integrated, minimal version of
+# LibTomMath can be used. See beginning of libtommath.c for details on benefits
+# and drawbacks of this option.
+#CONFIG_INTERNAL_LIBTOMMATH=y
+#ifndef CONFIG_INTERNAL_LIBTOMMATH
+#LTM_PATH=/usr/src/libtommath-0.39
+#CFLAGS += -I$(LTM_PATH)
+#LIBS += -L$(LTM_PATH)
+#LIBS_p += -L$(LTM_PATH)
+#endif
+# At the cost of about 4 kB of additional binary size, the internal LibTomMath
+# can be configured to include faster routines for exptmod, sqr, and div to
+# speed up DH and RSA calculation considerably
+#CONFIG_INTERNAL_LIBTOMMATH_FAST=y
+
+# Include NDIS event processing through WMI into wpa_supplicant/wpasvc.
+# This is only for Windows builds and requires WMI-related header files and
+# WbemUuid.Lib from Platform SDK even when building with MinGW.
+#CONFIG_NDIS_EVENTS_INTEGRATED=y
+#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib"
+
+# Add support for old DBus control interface
+# (fi.epitest.hostap.WPASupplicant)
+#CONFIG_CTRL_IFACE_DBUS=y
+
+# Add support for new DBus control interface
+# (fi.w1.hostap.wpa_supplicant1)
+CONFIG_CTRL_IFACE_DBUS_NEW=y
+
+# Add introspection support for new DBus control interface
+#CONFIG_CTRL_IFACE_DBUS_INTRO=y
+
+# Add support for loading EAP methods dynamically as shared libraries.
+# When this option is enabled, each EAP method can be either included
+# statically (CONFIG_EAP_<method>=y) or dynamically (CONFIG_EAP_<method>=dyn).
+# Dynamic EAP methods are build as shared objects (eap_*.so) and they need to
+# be loaded in the beginning of the wpa_supplicant configuration file
+# (see load_dynamic_eap parameter in the example file) before being used in
+# the network blocks.
+#
+# Note that some shared parts of EAP methods are included in the main program
+# and in order to be able to use dynamic EAP methods using these parts, the
+# main program must have been build with the EAP method enabled (=y or =dyn).
+# This means that EAP-TLS/PEAP/TTLS/FAST cannot be added as dynamic libraries
+# unless at least one of them was included in the main build to force inclusion
+# of the shared code. Similarly, at least one of EAP-SIM/AKA must be included
+# in the main build to be able to load these methods dynamically.
+#
+# Please also note that using dynamic libraries will increase the total binary
+# size. Thus, it may not be the best option for targets that have limited
+# amount of memory/flash.
+#CONFIG_DYNAMIC_EAP_METHODS=y
+
+# IEEE Std 802.11r-2008 (Fast BSS Transition)
+#CONFIG_IEEE80211R=y
+
+# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt)
+CONFIG_DEBUG_FILE=y
+
+# Send debug messages to syslog instead of stdout
+CONFIG_DEBUG_SYSLOG=y
+
+# Enable privilege separation (see README 'Privilege separation' for details)
+#CONFIG_PRIVSEP=y
+
+# Enable mitigation against certain attacks against TKIP by delaying Michael
+# MIC error reports by a random amount of time between 0 and 60 seconds
+#CONFIG_DELAYED_MIC_ERROR_REPORT=y
+
+# Enable tracing code for developer debugging
+# This tracks use of memory allocations and other registrations and reports
+# incorrect use with a backtrace of call (or allocation) location.
+#CONFIG_WPA_TRACE=y
+# For BSD, comment out these.
+#LIBS += -lexecinfo
+#LIBS_p += -lexecinfo
+#LIBS_c += -lexecinfo
+
+# Use libbfd to get more details for developer debugging
+# This enables use of libbfd to get more detailed symbols for the backtraces
+# generated by CONFIG_WPA_TRACE=y.
+#CONFIG_WPA_TRACE_BFD=y
+# For BSD, comment out these.
+#LIBS += -lbfd -liberty -lz
+#LIBS_p += -lbfd -liberty -lz
+#LIBS_c += -lbfd -liberty -lz
+#CONFIG_TLS = gnutls
+#CONFIG_GNUTLS_EXTRA=y
+CONFIG_CTRL_IFACE_DBUS=y
+CONFIG_CTRL_IFACE_DBUS_NEW=y
+
+# AP mode operations with wpa_supplicant
+# This can be used for controlling AP mode operations with wpa_supplicant. It
+# should be noted that this is mainly aimed at simple cases like
+# WPA2-Personal while more complex configurations like WPA2-Enterprise with an
+# external RADIUS server can be supported with hostapd.
+CONFIG_AP=y
+
+# P2P (Wi-Fi Direct)
+# This can be used to enable P2P support in wpa_supplicant. See README-P2P for
+# more information on P2P operations.
+CONFIG_P2P=y
+CONFIG_BGSCAN_SIMPLE=y
+
+# Autoscan
+# This can be used to enable automatic scan support in wpa_supplicant.
+# See wpa_supplicant.conf for more information on autoscan usage.
+#
+# Enabling directly a module will enable autoscan support.
+# For exponential module:
+CONFIG_AUTOSCAN_EXPONENTIAL=y
+# For periodic module:
+#CONFIG_AUTOSCAN_PERIODIC=y
+
+CFLAGS += -DEDISON_TARGET
+CFLAGS += -DANDROID_P2P
diff --git a/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/fi.w1.wpa_supplicant1.service b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/fi.w1.wpa_supplicant1.service
new file mode 100644
index 0000000..845a246
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/fi.w1.wpa_supplicant1.service
@@ -0,0 +1,5 @@
+[D-BUS Service]
+Name=fi.w1.wpa_supplicant1
+Exec=/usr/sbin/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant.conf -iwlan0 -Dnl80211 -u -O /var/run/wpa_supplicant
+User=root
+SystemdService=wpa_supplicant.service
diff --git a/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/fix-libnl3-host-contamination.patch b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/fix-libnl3-host-contamination.patch
new file mode 100644
index 0000000..eb8036f
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/fix-libnl3-host-contamination.patch
@@ -0,0 +1,42 @@
+Upstream-Status: Pending
+
+From 37d6b3dd5a737cd67468e4a58b372bddd924a7be Mon Sep 17 00:00:00 2001
+From: Andreas Oberritter <obi@opendreambox.org>
+Date: Fri, 8 Mar 2013 22:55:19 +0100
+Subject: [PATCH] Revert "build: Use updated libnl3 header paths"
+
+This reverts commit e7ecddf33a446072effbc85a27a078a8e582c89e.
+---
+ src/drivers/drivers.mak | 2 +-
+ src/drivers/drivers.mk | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
+index 68ff910..1f38f57 100644
+--- a/src/drivers/drivers.mak
++++ b/src/drivers/drivers.mak
+@@ -30,7 +30,7 @@ NEED_RFKILL=y
+ ifdef CONFIG_LIBNL32
+ DRV_LIBS += -lnl-3
+ DRV_LIBS += -lnl-genl-3
+- DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
++ DRV_CFLAGS += -DCONFIG_LIBNL20
+ else
+ ifdef CONFIG_LIBNL_TINY
+ DRV_LIBS += -lnl-tiny
+diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
+index db8561a..c93e88d 100644
+--- a/src/drivers/drivers.mk
++++ b/src/drivers/drivers.mk
+@@ -30,7 +30,7 @@ NEED_RFKILL=y
+ ifdef CONFIG_LIBNL32
+ DRV_LIBS += -lnl-3
+ DRV_LIBS += -lnl-genl-3
+- DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
++ DRV_CFLAGS += -DCONFIG_LIBNL20
+ else
+ ifdef CONFIG_LIBNL_TINY
+ DRV_LIBS += -lnl-tiny
+--
+1.7.10.4
+
diff --git a/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/p2p_supplicant.conf-sane b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/p2p_supplicant.conf-sane
new file mode 100644
index 0000000..62e2236
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/p2p_supplicant.conf-sane
@@ -0,0 +1,12 @@
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=0
+config_methods=virtual_push_button virtual_display push_button keypad
+update_config=1
+fast_reauth=1
+device_name=Edison
+manufacturer=Intel
+model_name=Edison
+p2p_ssid_postfix=-Edison
+persistent_reconnect=1
+
+
diff --git a/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/register-autoscan-correctly.patch b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/register-autoscan-correctly.patch
new file mode 100644
index 0000000..453240f
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/register-autoscan-correctly.patch
@@ -0,0 +1,51 @@
+From f157b78166baff2c32ed3983b4e787417505b343 Mon Sep 17 00:00:00 2001
+From: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
+Date: Mon, 1 Jul 2013 19:11:34 +0300
+Subject: [PATCH] dbus: Register the AutoScan method call at the right place
+
+Upstream-Status: Accepted [hostap@lists.shmoo.com]
+
+Signed-hostap: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
+---
+ wpa_supplicant/dbus/dbus_new.c | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
+index 8bc6618..d076d2d 100644
+--- a/wpa_supplicant/dbus/dbus_new.c
++++ b/wpa_supplicant/dbus/dbus_new.c
+@@ -1917,15 +1917,6 @@ static const struct wpa_dbus_method_desc wpas_dbus_global_methods[] = {
+ END_ARGS
+ }
+ },
+-#ifdef CONFIG_AUTOSCAN
+- { "AutoScan", WPAS_DBUS_NEW_IFACE_INTERFACE,
+- (WPADBusMethodHandler) &wpas_dbus_handler_autoscan,
+- {
+- { "arg", "s", ARG_IN },
+- END_ARGS
+- }
+- },
+-#endif /* CONFIG_AUTOSCAN */
+ { NULL, NULL, NULL, { END_ARGS } }
+ };
+
+@@ -2649,6 +2640,15 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
+ }
+ },
+ #endif /* CONFIG_AP */
++#ifdef CONFIG_AUTOSCAN
++ { "AutoScan", WPAS_DBUS_NEW_IFACE_INTERFACE,
++ (WPADBusMethodHandler) &wpas_dbus_handler_autoscan,
++ {
++ { "arg", "s", ARG_IN },
++ END_ARGS
++ }
++ },
++#endif /* CONFIG_AUTOSCAN */
+ { NULL, NULL, NULL, { END_ARGS } }
+ };
+
+--
+1.8.1.2
+
diff --git a/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/udhcpd-p2p.conf b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/udhcpd-p2p.conf
new file mode 100644
index 0000000..dcd92f2
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/udhcpd-p2p.conf
@@ -0,0 +1,107 @@
+# Sample udhcpd configuration file (/etc/udhcpd.conf)
+
+# The start and end of the IP lease block
+
+start 192.168.42.20 #default: 192.168.0.20
+end 192.168.42.254 #default: 192.168.0.254
+
+
+# The interface that udhcpd will use
+
+interface INTERFACE #default: eth0
+
+
+# The maximim number of leases (includes addressesd reserved
+# by OFFER's, DECLINE's, and ARP conficts
+
+#max_leases 254 #default: 254
+
+
+# If remaining is true (default), udhcpd will store the time
+# remaining for each lease in the udhcpd leases file. This is
+# for embedded systems that cannot keep time between reboots.
+# If you set remaining to no, the absolute time that the lease
+# expires at will be stored in the dhcpd.leases file.
+
+#remaining yes #default: yes
+
+
+# The time period at which udhcpd will write out a dhcpd.leases
+# file. If this is 0, udhcpd will never automatically write a
+# lease file. (specified in seconds)
+
+#auto_time 7200 #default: 7200 (2 hours)
+
+
+# The amount of time that an IP will be reserved (leased) for if a
+# DHCP decline message is received (seconds).
+
+#decline_time 3600 #default: 3600 (1 hour)
+
+
+# The amount of time that an IP will be reserved (leased) for if an
+# ARP conflct occurs. (seconds
+
+#conflict_time 3600 #default: 3600 (1 hour)
+
+
+# How long an offered address is reserved (leased) in seconds
+
+#offer_time 60 #default: 60 (1 minute)
+
+# If a lease to be given is below this value, the full lease time is
+# instead used (seconds).
+
+#min_lease 60 #defult: 60
+
+
+# The location of the leases file
+
+#lease_file /var/lib/misc/udhcpd.leases #defualt: /var/lib/misc/udhcpd.leases
+
+# The location of the pid file
+pidfile /var/run/udhcpd-INTERFACE.pid #default: /var/run/udhcpd.pid
+
+# Every time udhcpd writes a leases file, the below script will be called.
+# Useful for writing the lease file to flash every few hours.
+
+#notify_file #default: (no script)
+
+#notify_file dumpleases # <--- useful for debugging
+
+# The following are bootp specific options, setable by udhcpd.
+
+#siaddr 192.168.0.22 #default: 0.0.0.0
+
+#sname zorak #default: (none)
+
+#boot_file /var/nfs_root #default: (none)
+
+# The remainer of options are DHCP options and can be specifed with the
+# keyword 'opt' or 'option'. If an option can take multiple items, such
+# as the dns option, they can be listed on the same line, or multiple
+# lines. The only option with a default is 'lease'.
+
+# Currently supported options, for more info, see options.c
+opt subnet 255.255.255.0
+#opt timezone
+#opt router
+#opt timesvr
+#opt namesvr
+#opt dns
+#opt logsvr
+#opt cookiesvr
+#opt lprsvr
+#opt bootsize
+#opt domain
+#opt swapsvr
+#opt rootpath
+#opt ipttl
+#opt mtu
+#opt broadcast
+#opt wins
+#opt lease
+#opt ntpsrv
+#opt tftp
+#opt bootfile
+
diff --git a/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa-supplicant-android-4.4.4_r2.0.1.patch b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa-supplicant-android-4.4.4_r2.0.1.patch
new file mode 100644
index 0000000..ceee40d
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa-supplicant-android-4.4.4_r2.0.1.patch
@@ -0,0 +1,184 @@
+
+--- a/wpa_supplicant/src/drivers/driver_nl80211.c 2014-10-01 16:44:14.819137037 +0200
++++ b/wpa_supplicant/src/drivers/driver_nl80211.c 2014-10-01 16:37:16.979149254 +0200
+@@ -321,7 +321,7 @@
+ struct wpa_driver_scan_params *params);
+ static int android_pno_stop(struct i802_bss *bss);
+ #endif /* ANDROID */
+-#ifdef ANDROID_P2P
++#if defined(ANDROID_P2P) && !defined(EDISON_TARGET)
+ int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration);
+ int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len);
+ int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow);
+@@ -10329,7 +10329,7 @@
+ "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow);
+
+ if (opp_ps != -1 || ctwindow != -1)
+-#ifdef ANDROID_P2P
++#if defined(ANDROID_P2P) && !defined(EDISON_TARGET)
+ wpa_driver_set_p2p_ps(priv, legacy_ps, opp_ps, ctwindow);
+ #else
+ return -1; /* Not yet supported */
+@@ -10832,7 +10832,7 @@
+ .update_ft_ies = wpa_driver_nl80211_update_ft_ies,
+ .get_mac_addr = wpa_driver_nl80211_get_macaddr,
+ .get_survey = wpa_driver_nl80211_get_survey,
+-#ifdef ANDROID_P2P
++#if defined(ANDROID_P2P) && !defined(EDISON_TARGET)
+ .set_noa = wpa_driver_set_p2p_noa,
+ .get_noa = wpa_driver_get_p2p_noa,
+ .set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
+
+--- a/wpa_supplicant/wpa_cli.c 2014-10-01 16:52:31.123122526 +0200
++++ b/wpa_supplicant/wpa_cli.c 2014-10-01 17:05:59.043098904 +0200
+@@ -3625,7 +3625,8 @@
+ continue;
+ #endif /* _DIRENT_HAVE_D_TYPE */
+ if (os_strcmp(dent->d_name, ".") == 0 ||
+- os_strcmp(dent->d_name, "..") == 0)
++ os_strcmp(dent->d_name, "..") == 0 ||
++ os_strstr(dent->d_name, "p2p"))
+ continue;
+ printf("Selected interface '%s'\n", dent->d_name);
+ ifname = os_strdup(dent->d_name);
+
+--- a/wpa_supplicant/p2p_supplicant.c 2014-09-26 12:09:39.856249682 +0200
++++ b/wpa_supplicant/p2p_supplicant.c 2014-12-17 16:42:39.535846212 +0100
+@@ -3061,6 +3061,13 @@
+ int cla, op;
+
+ if (wpa_s->hw.modes == NULL) {
++ wpa_printf(MSG_DEBUG, "P2P: Driver did not support fetching. "
++ "Use supported channels retrieved on interface wlan0");
++ wpa_s = wpa_s->global->ifaces;
++
++ }
++
++ if (wpa_s->hw.modes == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: Driver did not support fetching "
+ "of all supported channels; assume dualband "
+ "support");
+@@ -3172,7 +3179,8 @@
+ }
+
+
+-int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s)
++int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s,
++ const char *conf_p2p_dev)
+ {
+ struct wpa_interface iface;
+ struct wpa_supplicant *p2pdev_wpa_s;
+@@ -3198,7 +3206,20 @@
+ iface.ifname = wpa_s->pending_interface_name;
+ iface.driver = wpa_s->driver->name;
+ iface.driver_param = wpa_s->conf->driver_param;
+- iface.confname = wpa_s->confname;
++
++ /*
++ * If a P2P Device configuration file was given, use it as the interface
++ * configuration file (instead of using parent's configuration file.
++ */
++ if (conf_p2p_dev) {
++ iface.confname = conf_p2p_dev;
++ iface.ctrl_interface = NULL;
++ } else {
++ iface.confname = wpa_s->confname;
++ iface.ctrl_interface = wpa_s->conf->ctrl_interface;
++ }
++ iface.conf_p2p_dev = NULL;
++
+ p2pdev_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface);
+ if (!p2pdev_wpa_s) {
+ wpa_printf(MSG_DEBUG, "P2P: Failed to add P2P Device interface");
+
+--- a/wpa_supplicant/main.c 2014-09-26 12:09:39.856249682 +0200
++++ b/wpa_supplicant/main.c 2014-12-17 16:42:39.535846212 +0100
+@@ -83,6 +83,9 @@
+ #endif /* CONFIG_DBUS */
+ printf(" -v = show version\n"
+ " -W = wait for a control interface monitor before starting\n"
++#ifdef CONFIG_P2P
++ " -m = Configuration file for the P2P Device interface\n"
++#endif /* CONFIG_P2P */
+ " -N = start describing new interface\n");
+
+ printf("example:\n"
+@@ -160,7 +163,7 @@
+
+ for (;;) {
+ c = getopt(argc, argv,
+- "b:Bc:C:D:de:f:g:G:hi:I:KLNo:O:p:P:qsTtuvW");
++ "b:Bc:C:D:de:f:g:G:hi:I:KLm:No:O:p:P:qsTtuvW");
+ if (c < 0)
+ break;
+ switch (c) {
+@@ -220,6 +223,11 @@
+ license();
+ exitcode = 0;
+ goto out;
++#ifdef CONFIG_P2P
++ case 'm':
++ iface->conf_p2p_dev = optarg;
++ break;
++#endif /* CONFIG_P2P */
+ case 'o':
+ params.override_driver = optarg;
+ break;
+@@ -311,7 +319,7 @@
+ if (wpa_s->global->p2p == NULL &&
+ (wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
+- wpas_p2p_add_p2pdev_interface(wpa_s) < 0)
++ wpas_p2p_add_p2pdev_interface(wpa_s, iface->conf_p2p_dev) < 0)
+ exitcode = -1;
+ #endif /* CONFIG_P2P */
+ }
+
+--- a/wpa_supplicant/p2p_supplicant.h 2014-09-26 12:09:39.856249682 +0200
++++ b/wpa_supplicant/p2p_supplicant.h 2014-12-17 16:42:39.535846212 +0100
+@@ -19,7 +19,8 @@
+ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s);
+ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s);
+ void wpas_p2p_deinit_global(struct wpa_global *global);
+-int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s);
++int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s,
++ const char *conf_p2p_dev);
+ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
+ const char *pin, enum p2p_wps_method wps_method,
+ int persistent_group, int auto_join, int join,
+
+--- a/wpa_supplicant/wpa_supplicant_i.h 2014-09-26 12:09:39.856249682 +0200
++++ b/wpa_supplicant/wpa_supplicant_i.h 2014-12-17 16:42:39.535846212 +0100
+@@ -63,6 +63,17 @@
+ */
+ const char *confanother;
+
++#ifdef CONFIG_P2P
++ /**
++ * conf_p2p_dev - Configuration file used to hold the
++ * P2P Device configuration parameters.
++ *
++ * This can also be %NULL. In such a case, if a P2P Device dedicated
++ * interfaces is created, the main configuration file will be used.
++ */
++ const char *conf_p2p_dev;
++#endif /* CONFIG_P2P */
++
+ /**
+ * ctrl_interface - Control interface parameter
+ *
+
+@@ -904,0 +904,0 @@
+--- a/wpa_supplicant/scan.c 2014-09-26 12:09:39.856249682 +0200
++++ b/wpa_supplicant/scan.c 2014-12-17 16:42:39.535846212 +0100
+@@ -904,7 +904,7 @@
+ */
+ void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
+ {
+-#ifndef ANDROID
++#if !defined(ANDROID) && !defined(EDISON_TARGET)
+ /* If there's at least one network that should be specifically scanned
+ * then don't cancel the scan and reschedule. Some drivers do
+ * background scanning which generates frequent scan results, and that
+
+
diff --git a/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa-supplicant.sh b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa-supplicant.sh
new file mode 100644
index 0000000..5c9e5d3
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa-supplicant.sh
@@ -0,0 +1,85 @@
+#!/bin/sh
+
+
+WPA_SUP_BIN="/usr/sbin/wpa_supplicant"
+WPA_SUP_PNAME="wpa_supplicant"
+WPA_SUP_PIDFILE="/var/run/wpa_supplicant.$IFACE.pid"
+WPA_SUP_OPTIONS="-B -P $WPA_SUP_PIDFILE -i $IFACE"
+
+VERBOSITY=0
+
+
+if [ -s "$IF_WPA_CONF" ]; then
+ WPA_SUP_CONF="-c $IF_WPA_CONF"
+else
+ exit 0
+fi
+
+if [ ! -x "$WPA_SUP_BIN" ]; then
+
+ if [ "$VERBOSITY" = "1" ]; then
+ echo "$WPA_SUP_PNAME: binaries not executable or missing from $WPA_SUP_BIN"
+ fi
+
+ exit 1
+fi
+
+if [ "$MODE" = "start" ] ; then
+ # driver type of interface, defaults to wext when undefined
+ if [ -s "/etc/wpa_supplicant/driver.$IFACE" ]; then
+ IF_WPA_DRIVER=$(cat "/etc/wpa_supplicant/driver.$IFACE")
+ elif [ -z "$IF_WPA_DRIVER" ]; then
+
+ if [ "$VERBOSITY" = "1" ]; then
+ echo "$WPA_SUP_PNAME: wpa-driver not provided, using \"wext\""
+ fi
+
+ IF_WPA_DRIVER="wext"
+ fi
+
+ # if we have passed the criteria, start wpa_supplicant
+ if [ -n "$WPA_SUP_CONF" ]; then
+
+ if [ "$VERBOSITY" = "1" ]; then
+ echo "$WPA_SUP_PNAME: $WPA_SUP_BIN $WPA_SUP_OPTIONS $WPA_SUP_CONF -D $IF_WPA_DRIVER"
+ fi
+
+ start-stop-daemon --start --quiet \
+ --name $WPA_SUP_PNAME --startas $WPA_SUP_BIN --pidfile $WPA_SUP_PIDFILE \
+ -- $WPA_SUP_OPTIONS $WPA_SUP_CONF -D $IF_WPA_DRIVER
+ fi
+
+ # if the interface socket exists, then wpa_supplicant was invoked successfully
+ if [ -S "$WPA_COMMON_CTRL_IFACE/$IFACE" ]; then
+
+ if [ "$VERBOSITY" = "1" ]; then
+ echo "$WPA_SUP_PNAME: ctrl_interface socket located at $WPA_COMMON_CTRL_IFACE/$IFACE"
+ fi
+
+ exit 0
+
+ fi
+
+elif [ "$MODE" = "stop" ]; then
+
+ if [ -f "$WPA_SUP_PIDFILE" ]; then
+
+ if [ "$VERBOSITY" = "1" ]; then
+ echo "$WPA_SUP_PNAME: terminating $WPA_SUP_PNAME daemon"
+ fi
+
+ start-stop-daemon --stop --quiet \
+ --name $WPA_SUP_PNAME --pidfile $WPA_SUP_PIDFILE
+
+ if [ -S "$WPA_COMMON_CTRL_IFACE/$IFACE" ]; then
+ rm -f $WPA_COMMON_CTRL_IFACE/$IFACE
+ fi
+
+ if [ -f "$WPA_SUP_PIDFILE" ]; then
+ rm -f $WPA_SUP_PIDFILE
+ fi
+ fi
+
+fi
+
+exit 0
diff --git a/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa_cli-actions.sh b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa_cli-actions.sh
new file mode 100644
index 0000000..77b9086
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa_cli-actions.sh
@@ -0,0 +1,88 @@
+#!/bin/sh
+#
+# This script file is passed as parameter to wpa_cli, started as a daemon,
+# so that the wpa_supplicant events are sent to this script
+# and actions executed, like :
+# - start DHCP client when STA is connected.
+# - stop DHCP client when STA is disconnected.
+# - start DHCP client when P2P-GC is connected.
+# - stop DHCP server when P2P-GO is disconnected.
+#
+# This script skips events if connmand (connman.service) is started
+# Indeed, it is considered that the Wifi connection is managed through
+# connmand and not wpa_cli
+#
+
+IFNAME=$1
+CMD=$2
+
+kill_daemon() {
+ NAME=$1
+ PF=$2
+
+ if [ ! -r $PF ]; then
+ return
+ fi
+
+ PID=`cat $PF`
+ if [ $PID -gt 0 ]; then
+ if ps | grep $NAME | grep $PID; then
+ kill $PID
+ fi
+ fi
+ if [ -r $PF ]; then
+ # file can be removed by the deamon when killed
+ rm $PF
+ fi
+}
+
+echo "event $CMD received from wpa_supplicant"
+
+# if Connman is started, ignore wpa_supplicant
+# STA connection event because the DHCP connection
+# is triggerd by Connman
+if [ `systemctl is-active connman` == "active" ] ; then
+ if [ "$CMD" = "CONNECTED" ] || [ "$CMD" = "DISCONNECTED" ] ; then
+ echo "event $CMD ignored because Connman is started"
+ exit 0
+ fi
+fi
+
+if [ "$CMD" = "CONNECTED" ]; then
+ kill_daemon udhcpc /var/run/udhcpc-$IFNAME.pid
+ udhcpc -i $IFNAME -p /var/run/udhcpc-$IFNAME.pid -S
+fi
+
+if [ "$CMD" = "DISCONNECTED" ]; then
+ kill_daemon udhcpc /var/run/udhcpc-$IFNAME.pid
+ ifconfig $IFNAME 0.0.0.0
+fi
+
+if [ "$CMD" = "P2P-GROUP-STARTED" ]; then
+ GIFNAME=$3
+ if [ "$4" = "GO" ]; then
+ kill_daemon udhcpc /var/run/udhcpc-$GIFNAME.pid
+ ifconfig $GIFNAME 192.168.42.1 up
+ cp /etc/wpa_supplicant/udhcpd-p2p.conf /etc/wpa_supplicant/udhcpd-p2p-itf.conf
+ sed -i "s/INTERFACE/$GIFNAME/" /etc/wpa_supplicant/udhcpd-p2p-itf.conf
+ udhcpd /etc/wpa_supplicant/udhcpd-p2p-itf.conf
+ fi
+ if [ "$4" = "client" ]; then
+ kill_daemon udhcpc /var/run/udhcpc-$GIFNAME.pid
+ kill_daemon udhcpd /var/run/udhcpd-$GIFNAME.pid
+ udhcpc -i $GIFNAME -p /var/run/udhcpc-$GIFNAME.pid
+ fi
+fi
+
+if [ "$CMD" = "P2P-GROUP-REMOVED" ]; then
+ GIFNAME=$3
+ if [ "$4" = "GO" ]; then
+ kill_daemon udhcpd /var/run/udhcpd-$GIFNAME.pid
+ ifconfig $GIFNAME 0.0.0.0
+ fi
+ if [ "$4" = "client" ]; then
+ kill_daemon udhcpc /var/run/udhcpc-$GIFNAME.pid
+ ifconfig $GIFNAME 0.0.0.0
+ fi
+fi
+
diff --git a/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa_supplicant.conf-sane b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa_supplicant.conf-sane
new file mode 100644
index 0000000..4d37989
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa_supplicant.conf-sane
@@ -0,0 +1,10 @@
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=0
+config_methods=virtual_push_button virtual_display push_button keypad
+update_config=1
+fast_reauth=1
+device_name=Edison
+manufacturer=Intel
+model_name=Edison
+
+
diff --git a/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa_supplicant.service b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa_supplicant.service
new file mode 100644
index 0000000..ec363aa
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa_supplicant.service
@@ -0,0 +1,21 @@
+[Unit]
+Description=WPA supplicant service
+Requires=sys-subsystem-net-devices-wlan0.device
+After=sys-subsystem-net-devices-wlan0.device
+
+[Service]
+Type=simple
+
+# start wpa_supplicant service :
+# - the second interface p2p-dev-wlan0 is automatically created at startup
+# - the file wpa_supplicant is common to both interfaces wlan0 and p2p-dev-wlan0
+ExecStart=/usr/sbin/wpa_supplicant -u -c/etc/wpa_supplicant/wpa_supplicant.conf -iwlan0 -Dnl80211 -puse_p2p_group_interface=1p2p_device=1 -m/etc/wpa_supplicant/p2p_supplicant.conf -O /var/run/wpa_supplicant -e /etc/wpa_supplicant/entropy.bin
+
+# start wpa_supplicant_event service after the start of wpa_supplicant service
+ExecStartPost=/bin/systemctl start wpa_supplicant_wlan0_event ; /bin/systemctl start wpa_supplicant_p2p_event
+
+# stop wpa_supplicant_event service after the stop of wpa_supplicant service
+ExecStopPost=/bin/systemctl stop wpa_supplicant_wlan0_event ; /bin/systemctl stop wpa_supplicant_p2p_event
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa_supplicant_p2p_event.service b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa_supplicant_p2p_event.service
new file mode 100644
index 0000000..b5445a2
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa_supplicant_p2p_event.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=Daemon to receive the wpa_supplicant event
+Requires=sys-subsystem-net-devices-wlan0.device
+After=sys-subsystem-net-devices-wlan0.device
+
+[Service]
+Type=simple
+ExecStart=/usr/sbin/wpa_cli -a /etc/wpa_supplicant/wpa_cli-actions.sh -i p2p-dev-wlan0
+Restart=on-failure
+RestartSec=1
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa_supplicant_wlan0_event.service b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa_supplicant_wlan0_event.service
new file mode 100644
index 0000000..7428b4c
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant/wpa_supplicant_wlan0_event.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=Daemon to receive the wpa_supplicant event
+Requires=sys-subsystem-net-devices-wlan0.device
+After=sys-subsystem-net-devices-wlan0.device
+
+[Service]
+Type=simple
+ExecStart=/usr/sbin/wpa_cli -a /etc/wpa_supplicant/wpa_cli-actions.sh -i wlan0
+Restart=on-failure
+RestartSec=1
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant_2.1.bbappend b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant_2.1.bbappend
new file mode 100644
index 0000000..5063afd
--- /dev/null
+++ b/meta-edison-distro/recipes-connectivity/wpa_supplicant/wpa-supplicant_2.1.bbappend
@@ -0,0 +1,96 @@
+LIC_FILES_CHKSUM = "file://COPYING;md5=ab87f20cd7e8c0d0a6539b34d3791d0e \
+ file://README;md5=5c7cc1ea1a4d82b1cbe9a02fe92881b8 \
+ file://wpa_supplicant/wpa_supplicant.c;beginline=1;endline=12;md5=cba4fa09fa364da845ca546f21008909"
+
+RRECOMMENDS_${PN} = "wpa-supplicant-passphrase wpa-supplicant-cli"
+
+
+SYSTEMD_SERVICE_${PN} = "wpa_supplicant.service wpa_supplicant_wlan0_event.service wpa_supplicant_p2p_event.service"
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/wpa-supplicant:"
+
+PV = "android-4.4.4_r2.0.1"
+
+BASE_SRC_URI = "file://defconfig-gnutls \
+ file://wpa_supplicant.conf-sane \
+ file://p2p_supplicant.conf-sane \
+ file://99_wpa_supplicant \
+ file://fi.w1.wpa_supplicant1.service \
+ file://udhcpd-p2p.conf \
+ file://wpa_supplicant.service \
+ file://wpa_supplicant_wlan0_event.service \
+ file://wpa_supplicant_p2p_event.service \
+ file://wpa-supplicant.sh \
+ file://wpa-supplicant-${PV}.patch \
+ file://wpa_cli-actions.sh "
+
+SRC_URI = "${BASE_SRC_URI} \
+ git://android.googlesource.com/platform/external/wpa_supplicant_8;protocol=https;tag=android-4.4.4_r2.0.1"
+
+S = "${WORKDIR}/git"
+PR = "r1"
+
+SRC_URI[md5sum] = "f2ed8fef72cf63d8d446a2d0a6da630a"
+SRC_URI[sha256sum] = "eaaa5bf3055270e521b2dff64f2d203ec8040f71958b8588269a82c00c9d7b6a"
+
+FILES_${PN} += "${datadir}/dbus-1/system-services/* \
+ ${systemd_unitdir}/system/ \
+ ${sysconfdir}/systemd/"
+
+
+do_compile () {
+ unset CFLAGS CPPFLAGS CXXFLAGS
+ sed -e "s:CFLAGS\ =.*:& \$(EXTRA_CFLAGS):g" ${S}/src/lib.rules > ${B}/src/lib.rules
+ oe_runmake -C wpa_supplicant
+}
+
+# Use do_install instead of do_install_append to skip un-needed/un-used files
+# added by do_install() in wpa_supplicant.inc
+do_install () {
+ install -d ${D}${sbindir}
+ install -m 755 wpa_supplicant/wpa_supplicant ${D}${sbindir}
+ install -m 755 wpa_supplicant/wpa_cli ${D}${sbindir}
+
+ install -d ${D}${bindir}
+ install -m 755 wpa_supplicant/wpa_passphrase ${D}${bindir}
+
+ install -d ${D}${sysconfdir}/wpa_supplicant
+ install -m 600 ${WORKDIR}/wpa_supplicant.conf-sane ${D}${sysconfdir}/wpa_supplicant/wpa_supplicant.conf
+ install -m 600 ${WORKDIR}/p2p_supplicant.conf-sane ${D}${sysconfdir}/wpa_supplicant/p2p_supplicant.conf
+
+ install -d ${D}/${sysconfdir}/dbus-1/system.d
+ install -m 644 ${S}/wpa_supplicant/dbus/dbus-wpa_supplicant.conf ${D}/${sysconfdir}/dbus-1/system.d
+ install -d ${D}/${datadir}/dbus-1/system-services
+ install -m 644 ${B}/wpa_supplicant/dbus/*.service ${D}/${datadir}/dbus-1/system-services
+ # overwrite the service file with our modified one
+ install -m 644 ${WORKDIR}/fi.w1.wpa_supplicant1.service ${D}/${datadir}/dbus-1/system-services
+
+ if ${@base_contains('DISTRO_FEATURES','systemd','true','false',d)}; then
+
+ install -d ${D}/${systemd_unitdir}/system
+ install -d ${D}${sysconfdir}/systemd/system/multi-user.target.wants
+
+ # Install the wpa_supplicant service
+ install -m 644 ${WORKDIR}/wpa_supplicant.service ${D}${systemd_unitdir}/system
+
+ # Install wpa_supplicant_event service for udhcp client start/stop based on wifi connection/disconnection
+ install -m 755 ${WORKDIR}/wpa_cli-actions.sh ${D}${sysconfdir}/wpa_supplicant
+ install -m 644 ${WORKDIR}/wpa_supplicant_wlan0_event.service ${D}${systemd_unitdir}/system
+ install -m 644 ${WORKDIR}/wpa_supplicant_p2p_event.service ${D}${systemd_unitdir}/system
+
+ # Install udhcp server configuration file for P2P GO
+ install -m 644 ${WORKDIR}/udhcpd-p2p.conf ${D}${sysconfdir}/wpa_supplicant
+ fi
+
+ install -d ${D}/etc/default/volatiles
+ install -m 0644 ${WORKDIR}/99_wpa_supplicant ${D}/etc/default/volatiles
+}
+
+pkg_postinst_wpa-supplicant () {
+ # If we're offline, we don't need to do this.
+ if [ "x$D" != "x" ]; then
+ exit 0
+ fi
+
+ killall -q -HUP dbus-daemon || true
+}
diff --git a/meta-edison-distro/recipes-core/base-files/base-files/factory.mount b/meta-edison-distro/recipes-core/base-files/base-files/factory.mount
new file mode 100644
index 0000000..2619c96
--- /dev/null
+++ b/meta-edison-distro/recipes-core/base-files/base-files/factory.mount
@@ -0,0 +1,12 @@
+[Unit]
+Description=Mount for factory
+
+[Install]
+WantedBy=default.target
+
+[Mount]
+What=/dev/disk/by-partlabel/factory
+Where=/factory
+Options=ro,noauto,x-systemd.automount,nosuid,nodev,noatime,discard,barrier=1,data=ordered,noauto_da_alloc
+Type=ext4
+TimeoutSec=3
diff --git a/meta-edison-distro/recipes-core/base-files/base-files/fstab b/meta-edison-distro/recipes-core/base-files/base-files/fstab
new file mode 100644
index 0000000..55edeef
--- /dev/null
+++ b/meta-edison-distro/recipes-core/base-files/base-files/fstab
@@ -0,0 +1,9 @@
+rootfs / auto nodev,noatime,discard,barrier=1,data=ordered,noauto_da_alloc 1 1
+proc /proc proc defaults 0 0
+devpts /dev/pts devpts mode=0620,gid=5 0 0
+usbdevfs /proc/bus/usb usbdevfs auto 0 0
+tmpfs /run tmpfs mode=0755,nodev,nosuid,strictatime 0 0
+tmpfs /var/volatile tmpfs defaults 0 0
+
+/dev/disk/by-partlabel/boot /boot auto noauto,x-systemd.automount,nosuid,nodev,noatime,discard 1 1
+/dev/disk/by-partlabel/home /home auto noauto,x-systemd.automount,nosuid,nodev,noatime,discard,barrier=1,data=ordered,noauto_da_alloc 1 1
diff --git a/meta-edison-distro/recipes-core/base-files/base-files/media-sdcard.automount b/meta-edison-distro/recipes-core/base-files/base-files/media-sdcard.automount
new file mode 100644
index 0000000..a577591
--- /dev/null
+++ b/meta-edison-distro/recipes-core/base-files/base-files/media-sdcard.automount
@@ -0,0 +1,11 @@
+[Unit]
+Description=Automount for SDCard
+ConditionPathExists=/dev/mmcblk1p1
+RefuseManualStart=true
+RefuseManualStop=true
+
+[Automount]
+Where=/media/sdcard
+
+[Install]
+WantedBy=local-fs.target
diff --git a/meta-edison-distro/recipes-core/base-files/base-files/media-sdcard.mount b/meta-edison-distro/recipes-core/base-files/base-files/media-sdcard.mount
new file mode 100644
index 0000000..a9d310b
--- /dev/null
+++ b/meta-edison-distro/recipes-core/base-files/base-files/media-sdcard.mount
@@ -0,0 +1,9 @@
+[Unit]
+Description=Mount for SDCard
+BindsTo=dev-mmcblk1p1.device
+Conflicts=media-sdcard.automount
+
+[Mount]
+What=/dev/mmcblk1p1
+Where=/media/sdcard
+TimeoutSec=3
diff --git a/meta-edison-distro/recipes-core/base-files/base-files/share/dot.profile b/meta-edison-distro/recipes-core/base-files/base-files/share/dot.profile
new file mode 100644
index 0000000..4f1d2a0
--- /dev/null
+++ b/meta-edison-distro/recipes-core/base-files/base-files/share/dot.profile
@@ -0,0 +1,9 @@
+# ~/.profile: executed by Bourne-compatible login shells.
+
+if [ -f ~/.bashrc ]; then
+ . ~/.bashrc
+fi
+
+# path set by /etc/profile
+# export PATH
+
diff --git a/meta-edison-distro/recipes-core/base-files/base-files_3.0.14.bbappend b/meta-edison-distro/recipes-core/base-files/base-files_3.0.14.bbappend
new file mode 100644
index 0000000..dd8d96a
--- /dev/null
+++ b/meta-edison-distro/recipes-core/base-files/base-files_3.0.14.bbappend
@@ -0,0 +1,33 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/base-files:"
+SRC_URI += "file://fstab"
+SRC_URI += "file://media-sdcard.mount"
+SRC_URI += "file://media-sdcard.automount"
+SRC_URI += "file://factory.mount"
+SRC_URI += "file://share/dot.profile"
+
+# override default volatile to suppress var/log link creation
+volatiles = "tmp"
+
+do_install_append() {
+ install -m 0644 ${WORKDIR}/fstab ${D}${sysconfdir}/fstab
+ install -m 0755 ${WORKDIR}/share/dot.profile ${D}${sysconfdir}/skel/.profile
+
+ # enable mount of the SDCard in /media/sdcard when inserted
+ install -d ${D}${systemd_unitdir}/system
+ install -c -m 0644 ${WORKDIR}/media-sdcard.mount ${D}${systemd_unitdir}/system
+ install -c -m 0644 ${WORKDIR}/media-sdcard.automount ${D}${systemd_unitdir}/system
+ install -c -m 0644 ${WORKDIR}/factory.mount ${D}${systemd_unitdir}/system
+ # Enable the service
+ install -d ${D}${sysconfdir}/systemd/system/local-fs.target.wants
+ ln -sf ${systemd_unitdir}/system/media-sdcard.automount \
+ ${D}${sysconfdir}/systemd/system/local-fs.target.wants/media-sdcard.automount
+ install -d ${D}${sysconfdir}/systemd/system/default.target.wants
+ ln -sf ${systemd_unitdir}/system/factory.mount \
+ ${D}${sysconfdir}/systemd/system/default.target.wants/factory.mount
+
+}
+
+FILES_${PN} += "${base_libdir}/systemd/system/*.mount"
+FILES_${PN} += "${base_libdir}/systemd/system/*.automount"
+FILES_${PN} += "${sysconfdir}/systemd/system/default.target.wants/*.mount"
+FILES_${PN} += "${sysconfdir}/systemd/system/local-fs.target.wants/*.automount"
diff --git a/meta-edison-distro/recipes-core/busybox/busybox_1.22.1.bbappend b/meta-edison-distro/recipes-core/busybox/busybox_1.22.1.bbappend
new file mode 100644
index 0000000..faf18af
--- /dev/null
+++ b/meta-edison-distro/recipes-core/busybox/busybox_1.22.1.bbappend
@@ -0,0 +1,5 @@
+# to get brctl and log configuration settings
+FILESEXTRAPATHS_prepend := "${THISDIR}/files/:"
+
+SRC_URI += "file://brctl-utilities.cfg \
+ file://busybox-log.cfg "
diff --git a/meta-edison-distro/recipes-core/busybox/files/brctl-utilities.cfg b/meta-edison-distro/recipes-core/busybox/files/brctl-utilities.cfg
new file mode 100644
index 0000000..53d4ead
--- /dev/null
+++ b/meta-edison-distro/recipes-core/busybox/files/brctl-utilities.cfg
@@ -0,0 +1,2 @@
+CONFIG_BRCTL=y
+CONFIG_FEATURE_BRCTL_SHOW=y
diff --git a/meta-edison-distro/recipes-core/busybox/files/busybox-log.cfg b/meta-edison-distro/recipes-core/busybox/files/busybox-log.cfg
new file mode 100644
index 0000000..7b7408f
--- /dev/null
+++ b/meta-edison-distro/recipes-core/busybox/files/busybox-log.cfg
@@ -0,0 +1,3 @@
+CONFIG_KLOGD=n
+CONFIG_SYSLOGD=n
+
diff --git a/meta-edison-distro/recipes-core/first-install/files/first-install.service b/meta-edison-distro/recipes-core/first-install/files/first-install.service
new file mode 100644
index 0000000..3ebb9d7
--- /dev/null
+++ b/meta-edison-distro/recipes-core/first-install/files/first-install.service
@@ -0,0 +1,9 @@
+[Unit]
+Description=First install service
+OnFailure=reboot.target
+Requires=dev-disk-by\x2dpartlabel-home.device dev-disk-by\x2dpartlabel-update.device
+After=dev-disk-by\x2dpartlabel-home.device dev-disk-by\x2dpartlabel-update.device
+[Service]
+ExecStart=@BASE_BINDIR@/sh -c "shell='sh'; if [ -f /bin/bash ]; then shell='bash'; fi; @BASE_BINDIR@/$shell @BASE_SBINDIR@/first-install.sh systemd-service"
+StandardOutput=journal+console
+
diff --git a/meta-edison-distro/recipes-core/first-install/files/first-install.sh b/meta-edison-distro/recipes-core/first-install/files/first-install.sh
new file mode 100644
index 0000000..1b29245
--- /dev/null
+++ b/meta-edison-distro/recipes-core/first-install/files/first-install.sh
@@ -0,0 +1,185 @@
+#!/bin/bash
+# first install script to do post flash install
+
+# global variable set to 1 if output is systemd journal
+fi_journal_out=0
+
+export PATH="$PATH:/usr/sbin/"
+
+# handle argument, if first-install is called from systemd service
+# arg1 is "systemd-service"
+if [ "$1" == "systemd-service" ]; then fi_journal_out=1; fi;
+
+#echo function to output to journal system or in colored terminal
+#arg $1 message
+#arg $2 log level
+fi_echo () {
+ lg_lvl=${2:-"log"}
+ msg_prefix=""
+ msg_suffix=""
+ case "$lg_lvl" in
+ log) if [ $fi_journal_out -eq 1 ]; then msg_prefix="<5>"; else msg_prefix="\033[1m"; msg_suffix="\033[0m"; fi;;
+ err) if [ $fi_journal_out -eq 1 ]; then msg_prefix="<1>"; else msg_prefix="\033[31;40m\033[1m"; msg_suffix="\033[0m"; fi;;
+ esac
+ printf "${msg_prefix}${1}${msg_suffix}\n"
+}
+
+# set_retry_count to failure file
+# arg $1 new retry count
+set_retry_count () {
+ fw_setenv first_install_retry $1
+}
+
+# get_retry_count from failure from bootloader
+get_retry_count () {
+ retry_count=$(fw_printenv first_install_retry | tr -d "first_install_retry=")
+ [ -z $retry_count ] && { set_retry_count 0; retry_count=0;}
+ return $retry_count
+}
+
+# exit first_install by rebooting and handling the failure by setting
+# the firmware target according to failure or success
+# on failure increment fail count and reboot
+# on success reboot in multi-user target
+# arg $1 exit code
+exit_first_install () {
+ if [ $1 -eq 0 ]; then
+ # reset failure count
+ set_retry_count 0
+ # update firmware target
+ # next reboot will be on multi-user target
+ fw_setenv bootargs_target multi-user
+ fi
+ # dump journal to log file
+ journalctl -u first-install -o short-iso >> /first-install.log
+ systemctl daemon-reload
+ systemctl stop home.mount
+ systemctl default
+}
+
+# continue normal flow or exit on error code
+# arg $1 : return code to check
+# arg $2 : string resuming the action
+fi_assert () {
+ if [ $1 -ne 0 ]; then
+ fi_echo "${2} : Failed ret($1)" err;
+ exit_first_install $1;
+ else
+ fi_echo "${2} : Success";
+ fi
+}
+
+factory_partition () {
+ mkdir -p /factory
+ mount /dev/disk/by-partlabel/factory /factory
+ # test can fail if done during manufacturing
+ if [ $? -ne 0 ];
+ then
+ mkfs.ext4 /dev/disk/by-partlabel/factory
+ mount /dev/disk/by-partlabel/factory /factory
+ echo "00:11:22:33:55:66" > /factory/bluetooth_address
+ echo "VSPPYWWDXXXXXNNN" > /factory/serial_number
+ fi
+}
+
+# generate sshd keys
+sshd_init () {
+ rm -rf /etc/ssh/*key*
+ systemctl start sshdgenkeys
+}
+
+
+# Substitute the SSID and passphrase in the file /etc/hostapd/hostapd.conf
+# The SSID is built from the hostname and a serial number to have a
+# unique SSID in case of multiple Edison boards having their WLAN AP active.
+setup_ap_ssid_and_passphrase () {
+ # factory_serial is 16 bytes long
+ if [ -f /sys/class/net/wlan0/address ];
+ then
+ ifconfig wlan0 up
+ wlan0_addr=$(cat /sys/class/net/wlan0/address | tr '[:lower:]' '[:upper:]')
+ ssid="EDISON-${wlan0_addr:12:2}-${wlan0_addr:15:2}"
+
+ # Substitute the SSID
+ sed -i -e 's/^ssid=.*/ssid='${ssid}'/g' /etc/hostapd/hostapd.conf
+ fi
+
+ if [ -f /factory/serial_number ] ;
+ then
+ factory_serial=$(head -n1 /factory/serial_number | tr '[:lower:]' '[:upper:]')
+ passphrase="${factory_serial}"
+
+ # Substitute the passphrase
+ sed -i -e 's/^wpa_passphrase=.*/wpa_passphrase='${passphrase}'/g' /etc/hostapd/hostapd.conf
+ fi
+
+ sync
+}
+
+
+# script main part
+
+# print to journal the current retry count
+get_retry_count
+retry_count=$?
+set_retry_count $((${retry_count} + 1))
+fi_echo "Starting First Install (try: ${retry_count})"
+
+# format partition home to ext4
+mkfs.ext4 -m0 /dev/disk/by-partlabel/home
+fi_assert $? "Formatting home partition"
+
+# backup initial /home/root directory
+mkdir /tmp/oldhome
+cp -R /home/* /tmp/oldhome/
+fi_assert $? "Backup home/root contents of rootfs"
+
+# mount home partition on /home
+mount /dev/disk/by-partlabel/home /home
+fi_assert $? "Mount /home partition"
+
+# copy back contents to /home and cleanup
+mv /tmp/oldhome/* /home/
+rm -rf /tmp/oldhome
+fi_assert $? "Restore home/root contents on new /home partition"
+
+# create a fat32 primary partition on all available space
+echo -ne "n\np\n1\n\n\nt\nb\np\nw\n" | fdisk /dev/disk/by-partlabel/update
+
+# silent error code for now because fdisk failed to reread MBR correctly
+# MBR is correct but fdisk understand it as the main system MBR, which is
+# not the case.
+fi_assert 0 "Formatting update partition Step 1"
+
+# create a loop device on update disk
+losetup -o 8192 /dev/loop0 /dev/disk/by-partlabel/update
+fi_assert $? "Formatting update partition Step 2"
+
+# format update partition
+mkfs.vfat /dev/loop0 -n "Edison" -F 32
+fi_assert $? "Formatting update partition Step 3"
+
+# remove loop device on update disk
+losetup -d /dev/loop0
+fi_assert $? "Formatting update partition Step 4 final"
+
+# handle factory partition
+factory_partition
+
+# ssh
+sshd_init
+fi_assert $? "Generating sshd keys"
+
+# update entry in /etc/fstab to enable auto mount
+sed -i 's/#\/dev\/disk\/by-partlabel/\/dev\/disk\/by-partlabel/g' /etc/fstab
+fi_assert $? "Update file system table /etc/fstab"
+
+# Setup Access Point SSID and passphrase
+setup_ap_ssid_and_passphrase
+fi_assert $? "Generating Wifi Access Point SSID and passphrase"
+
+fi_echo "First install success"
+
+# end main part
+exit_first_install 0
+
diff --git a/meta-edison-distro/recipes-core/first-install/files/first-install.target b/meta-edison-distro/recipes-core/first-install/files/first-install.target
new file mode 100644
index 0000000..e005f55
--- /dev/null
+++ b/meta-edison-distro/recipes-core/first-install/files/first-install.target
@@ -0,0 +1,7 @@
+[Unit]
+Description=First Install target
+Requires=sysinit.target
+Conflicts=shutdown.target systemd-readahead-collect.service systemd-readahead-replay.service home.automount factory.automount
+After=sysinit.target
+Before=shutdown.target
+AllowIsolate=yes
diff --git a/meta-edison-distro/recipes-core/first-install/first-install.bb b/meta-edison-distro/recipes-core/first-install/first-install.bb
new file mode 100644
index 0000000..c04b930
--- /dev/null
+++ b/meta-edison-distro/recipes-core/first-install/first-install.bb
@@ -0,0 +1,40 @@
+DESCRIPTION = "First install systemd target"
+LICENSE = "GPLv2+"
+LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6"
+
+SRC_URI = "file://first-install.service \
+ file://first-install.target \
+ file://first-install.sh"
+
+SYSTEMD_SERVICE_${PN} = "first-install.service"
+
+RDEPENDS_${PN} = "systemd"
+
+do_install() {
+ install -d ${D}/sbin
+ install -c -m 0744 ${WORKDIR}/first-install.sh ${D}/sbin
+ install -d ${D}${systemd_unitdir}/system
+ install -d ${D}${sysconfdir}/systemd/system/first-install.target.wants
+ install -c -m 0644 ${WORKDIR}/first-install.target ${D}${systemd_unitdir}/system
+ install -c -m 0644 ${WORKDIR}/first-install.service ${D}${systemd_unitdir}/system
+ sed -i -e 's,@BASE_BINDIR@,${base_bindir},g' \
+ -e 's,@BASE_SBINDIR@,${base_sbindir},g' \
+ -e 's,@SBINDIR@,${sbindir},g' \
+ -e 's,@BINDIR@,${bindir},g' \
+ ${D}${systemd_unitdir}/system/first-install.service
+
+ # enable services
+ ln -sf ${systemd_unitdir}/system/first-install.service \
+ ${D}${sysconfdir}/systemd/system/first-install.target.wants/first-install.service
+}
+
+FILES_${PN} = "${base_libdir}/systemd/system/*.service \
+ ${base_libdir}/systemd/system/first-install.target \
+ ${sysconfdir} \
+ /sbin/first-install.sh"
+
+# As this package is tied to systemd, only build it when we're also building systemd.
+python () {
+ if not oe.utils.contains ('DISTRO_FEATURES', 'systemd', True, False, d):
+ raise bb.parse.SkipPackage("'systemd' not in DISTRO_FEATURES")
+}
diff --git a/meta-edison-distro/recipes-core/images/edison-image.bb b/meta-edison-distro/recipes-core/images/edison-image.bb
new file mode 100644
index 0000000..f106657
--- /dev/null
+++ b/meta-edison-distro/recipes-core/images/edison-image.bb
@@ -0,0 +1,130 @@
+DESCRIPTION = "A fully functional image to run EDISON"
+LIC_FILES_CHKSUM = "file://${COREBASE}/LICENSE;md5=4d92cd373abda3937c2bc47fbc49d690 \
+ file://${COREBASE}/meta/COPYING.MIT;md5=3da9cfbcb788c80a0384361b4de20420"
+LICENSE = "MIT"
+IMAGE_INSTALL = "packagegroup-core-boot ${ROOTFS_PKGMANAGE_BOOTSTRAP} ${CORE_IMAGE_EXTRA_INSTALL}"
+IMAGE_INSTALL += "openssh-sftp-server"
+
+IMAGE_LINGUAS = " "
+
+INITRD = ""
+INITRD_IMAGE = ""
+
+# Do not use legacy nor EFI BIOS
+PCBIOS = "0"
+# Do not support bootable USB stick
+NOISO = "1"
+ROOTFS = ""
+
+# This is useless stuff, but necessary for building because
+# inheriting bootimg also brings syslinux in..
+AUTO_SYSLINUXCFG = "1"
+SYSLINUX_ROOT = ""
+SYSLINUX_TIMEOUT ?= "10"
+SYSLINUX_LABELS ?= "boot install"
+LABELS_append = " ${SYSLINUX_LABELS} "
+
+
+# Specify rootfs image type
+IMAGE_FSTYPES = "ext4"
+
+inherit core-image
+
+# This has to be set after including core-image otherwise it's overriden with "1"
+# and this cancel creation of the boot hddimg
+NOHDD = "0"
+
+inherit bootimg
+do_bootimg[depends] += "${PN}:do_rootfs"
+
+IMAGE_ROOTFS_SIZE = "524288"
+
+IMAGE_FEATURES += "package-management ssh-server-openssh"
+# Allow passwordless root login and postinst logging
+IMAGE_FEATURES += "debug-tweaks"
+
+IMAGE_INSTALL += "connman"
+IMAGE_INSTALL += "connman-client"
+IMAGE_INSTALL += "connman-tools"
+IMAGE_INSTALL += "wireless-tools"
+IMAGE_INSTALL += "wpa-supplicant"
+IMAGE_INSTALL += "hostapd-daemon"
+IMAGE_INSTALL += "bluez5-dev"
+IMAGE_INSTALL += "bluez5-obex"
+IMAGE_INSTALL += "kernel-modules"
+IMAGE_INSTALL += "ethtool"
+IMAGE_INSTALL += "iptables"
+IMAGE_INSTALL += "libstdc++"
+IMAGE_INSTALL += "u-boot"
+IMAGE_INSTALL += "u-boot-fw-utils"
+IMAGE_INSTALL += "file"
+IMAGE_INSTALL += "pciutils"
+IMAGE_INSTALL += "usbutils"
+IMAGE_INSTALL += "ldd"
+IMAGE_INSTALL += "i2c-tools"
+IMAGE_INSTALL += "watchdog-sample"
+IMAGE_INSTALL += "pwr-button-handler"
+IMAGE_INSTALL += "blink-led"
+IMAGE_INSTALL += "first-install"
+IMAGE_INSTALL += "resize-rootfs"
+IMAGE_INSTALL += "systemd-analyze"
+IMAGE_INSTALL += "wget"
+IMAGE_INSTALL += "ota-update"
+
+# Allows to enable OpenMP feature
+IMAGE_INSTALL += "libgomp"
+
+# Add audio firmware
+IMAGE_INSTALL += "sst-fw-bin"
+
+# ALSA lib and utilities
+IMAGE_INSTALL += "alsa-lib"
+IMAGE_INSTALL += "alsa-utils-alsamixer alsa-utils-alsactl alsa-utils-aplay alsa-utils-amixer"
+
+# Python and some basic modules
+IMAGE_INSTALL += "python"
+IMAGE_INSTALL += "python-dbus python-smartpm python-pygobject python-argparse"
+IMAGE_INSTALL += "python-distutils python-pkgutil python-audio python-image python-imaging python-email python-netserver python-xmlrpc python-ctypes python-html python-json python-compile python-misc python-numbers python-unittest python-pydoc"
+
+# Wifi firmware
+IMAGE_INSTALL += "bcm43340-fw"
+# Bluetooth Firmware patch for 43340 and its patch utility
+IMAGE_INSTALL += "bcm43340-bt"
+# service daemon that listens to rfkill events and trigger FW patch download
+IMAGE_INSTALL += "bluetooth-rfkill-event"
+# Wifi driver built as a kernel module
+IMAGE_INSTALL += "bcm43340-mod"
+
+# Provides strace and gdb
+IMAGE_FEATURES += "tools-debug"
+IMAGE_INSTALL += "crashlog"
+
+# Clean corrupted journald entries
+IMAGE_INSTALL += "cleanjournal"
+
+# Adds various other tools
+IMAGE_INSTALL += "tcpdump"
+IMAGE_INSTALL += "net-tools"
+IMAGE_INSTALL += "lsof"
+IMAGE_INSTALL += "iperf"
+
+# Add pulseaudio
+IMAGE_INSTALL += "pulseaudio-server libpulsecore libpulsecommon libpulse libpulse-simple pulseaudio-misc pulseaudio-service"
+
+# Add Mplayer
+IMAGE_INSTALL += "mplayer"
+
+# Those are necessary to manually create partitions and file systems on the eMMC
+IMAGE_INSTALL += "parted"
+IMAGE_INSTALL += "e2fsprogs-e2fsck e2fsprogs-mke2fs e2fsprogs-tune2fs e2fsprogs-badblocks libcomerr libss libe2p libext2fs dosfstools"
+
+# Time related
+IMAGE_INSTALL += "tzdata"
+
+# SWIG
+IMAGE_INSTALL += "swig"
+
+# INTEL MCU FW
+IMAGE_INSTALL += "mcu-fw-load"
+IMAGE_INSTALL += "mcu-fw-bin"
+
diff --git a/meta-edison-distro/recipes-core/ota-update/files/ota-update.service b/meta-edison-distro/recipes-core/ota-update/files/ota-update.service
new file mode 100644
index 0000000..bc43401
--- /dev/null
+++ b/meta-edison-distro/recipes-core/ota-update/files/ota-update.service
@@ -0,0 +1,9 @@
+[Unit]
+Description=OTA update service
+OnFailure=reboot.target
+Requires=dev-disk-by\x2dpartlabel-home.device dev-disk-by\x2dpartlabel-update.device
+After=dev-disk-by\x2dpartlabel-home.device dev-disk-by\x2dpartlabel-update.device
+[Service]
+ExecStart=@BASE_BINDIR@/sh -c "shell='sh'; if [ -f /bin/bash ]; then shell='bash'; fi; @BASE_BINDIR@/$shell @BASE_SBINDIR@/ota-update.sh systemd-service"
+StandardOutput=journal+console
+
diff --git a/meta-edison-distro/recipes-core/ota-update/files/ota-update.sh b/meta-edison-distro/recipes-core/ota-update/files/ota-update.sh
new file mode 100644
index 0000000..cfbe8ea
--- /dev/null
+++ b/meta-edison-distro/recipes-core/ota-update/files/ota-update.sh
@@ -0,0 +1,149 @@
+#!/bin/bash
+# FIXME: function definition shall be moved to a common script
+
+# global variable set to 1 if output is systemd journal
+fi_journal_out=0
+
+export PATH="$PATH:/usr/sbin/"
+
+# handle argument, if ota-update is called from systemd service
+# arg1 is "systemd-service"
+if [ "$1" == "systemd-service" ]; then fi_journal_out=1; fi;
+
+#echo function to output to journal system or in colored terminal
+#arg $1 message
+#arg $2 log level
+fi_echo () {
+ lg_lvl=${2:-"log"}
+ msg_prefix=""
+ msg_suffix=""
+ case "$lg_lvl" in
+ log) if [ $fi_journal_out -eq 1 ]; then msg_prefix="<5>"; else msg_prefix="\033[1m"; msg_suffix="\033[0m"; fi;;
+ err) if [ $fi_journal_out -eq 1 ]; then msg_prefix="<1>"; else msg_prefix="\033[31;40m\033[1m"; msg_suffix="\033[0m"; fi;;
+ esac
+ printf "${msg_prefix}${1}${msg_suffix}\n"
+}
+
+# set_retry_count to failure file
+# arg $1 new retry count
+set_retry_count () {
+ fw_setenv ota_update_retry $1
+}
+
+# get_retry_count from failure from bootloader
+get_retry_count () {
+ retry_count=$(fw_printenv ota_update_retry | tr -d "ota_update_retry=")
+ [ -z $retry_count ] && { set_retry_count 0; retry_count=0;}
+ return $retry_count
+}
+
+# exit ota_update by rebooting and handling the failure by setting
+# the firmware target according to failure or success
+# on failure increment fail count and reboot
+# on success reboot in multi-user target
+# arg $1 exit code
+exit_ota_update () {
+ if [ $1 -eq 0 ]; then
+ # reset failure count
+ set_retry_count 0
+ # update firmware target
+ # next reboot will be on multi-user target
+ fw_setenv bootargs_target multi-user
+ fi
+
+ fi_echo "Rebooting...."
+ # dump journal to log file
+ journalctl -u ota-update -o short-iso >> /ota-update.log
+ systemctl daemon-reload
+ systemctl stop home.mount
+ systemctl default
+}
+
+# continue normal flow or exit on error code
+# arg $1 : return code to check
+# arg $2 : string resuming the action
+fi_assert () {
+ if [ $1 -ne 0 ]; then
+ fi_echo "${2} : Failed ret($1)" err;
+ exit_ota_update $1;
+ else
+ fi_echo "${2} : Success";
+ fi
+}
+
+factory_partition () {
+ mkdir -p /factory
+ mount /dev/disk/by-partlabel/factory /factory
+ # test can fail if done during manufacturing
+ if [ $? -ne 0 ];
+ then
+ mkfs.ext4 /dev/disk/by-partlabel/factory
+ mount /dev/disk/by-partlabel/factory /factory
+ echo "00:11:22:33:55:66" > /factory/bluetooth_address
+ echo "VSPPYWWDXXXXXNNN" > /factory/serial_number
+ fi
+}
+
+# generate sshd keys
+sshd_init () {
+ rm -rf /etc/ssh/*key*
+ systemctl start sshdgenkeys
+}
+
+
+# Substitute the SSID and passphrase in the file /etc/hostapd/hostapd.conf
+# The SSID is built from the hostname and a serial number to have a
+# unique SSID in case of multiple Edison boards having their WLAN AP active.
+setup_ap_ssid_and_passphrase () {
+ # factory_serial is 16 bytes long
+ if [ -f /sys/class/net/wlan0/address ];
+ then
+ ifconfig wlan0 up
+ wlan0_addr=$(cat /sys/class/net/wlan0/address | tr '[:lower:]' '[:upper:]')
+ ssid="EDISON-${wlan0_addr:12:2}-${wlan0_addr:15:2}"
+
+ # Substitute the SSID
+ sed -i -e 's/^ssid=.*/ssid='${ssid}'/g' /etc/hostapd/hostapd.conf
+ fi
+
+ if [ -f /factory/serial_number ] ;
+ then
+ factory_serial=$(head -n1 /factory/serial_number | tr '[:lower:]' '[:upper:]')
+ passphrase="${factory_serial}"
+
+ # Substitute the passphrase
+ sed -i -e 's/^wpa_passphrase=.*/wpa_passphrase='${passphrase}'/g' /etc/hostapd/hostapd.conf
+ fi
+
+ sync
+}
+
+
+# script main part
+
+# print to journal the current retry count
+get_retry_count
+retry_count=$?
+set_retry_count $((${retry_count} + 1))
+fi_echo "Starting OTA update (try: ${retry_count})"
+
+# handle factory partition
+factory_partition
+
+# ssh
+sshd_init
+fi_assert $? "Generating sshd keys"
+
+# update entry in /etc/fstab to enable auto mount
+sed -i 's/#\/dev\/disk\/by-partlabel/\/dev\/disk\/by-partlabel/g' /etc/fstab
+fi_assert $? "Update file system table /etc/fstab"
+
+# Setup Access Point SSID and passphrase
+setup_ap_ssid_and_passphrase
+fi_assert $? "Generating Wifi Access Point SSID and passphrase"
+
+fi_echo "OTA update success"
+
+# end main part
+exit_ota_update 0
+
diff --git a/meta-edison-distro/recipes-core/ota-update/files/ota-update.target b/meta-edison-distro/recipes-core/ota-update/files/ota-update.target
new file mode 100644
index 0000000..6b23e39
--- /dev/null
+++ b/meta-edison-distro/recipes-core/ota-update/files/ota-update.target
@@ -0,0 +1,7 @@
+[Unit]
+Description=OTA update target
+Requires=sysinit.target
+Conflicts=shutdown.target systemd-readahead-collect.service systemd-readahead-replay.service home.automount factory.automount
+After=sysinit.target
+Before=shutdown.target
+AllowIsolate=yes
diff --git a/meta-edison-distro/recipes-core/ota-update/ota-update.bb b/meta-edison-distro/recipes-core/ota-update/ota-update.bb
new file mode 100644
index 0000000..f41eb0d
--- /dev/null
+++ b/meta-edison-distro/recipes-core/ota-update/ota-update.bb
@@ -0,0 +1,40 @@
+DESCRIPTION = "OTA update systemd target"
+LICENSE = "GPLv2+"
+LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6"
+
+SRC_URI = "file://ota-update.service \
+ file://ota-update.target \
+ file://ota-update.sh"
+
+SYSTEMD_SERVICE_${PN} = "ota-update.service"
+
+RDEPENDS_${PN} = "systemd"
+
+do_install() {
+ install -d ${D}/sbin
+ install -c -m 0744 ${WORKDIR}/ota-update.sh ${D}/sbin
+ install -d ${D}${systemd_unitdir}/system
+ install -d ${D}${sysconfdir}/systemd/system/ota-update.target.wants
+ install -c -m 0644 ${WORKDIR}/ota-update.target ${D}${systemd_unitdir}/system
+ install -c -m 0644 ${WORKDIR}/ota-update.service ${D}${systemd_unitdir}/system
+ sed -i -e 's,@BASE_BINDIR@,${base_bindir},g' \
+ -e 's,@BASE_SBINDIR@,${base_sbindir},g' \
+ -e 's,@SBINDIR@,${sbindir},g' \
+ -e 's,@BINDIR@,${bindir},g' \
+ ${D}${systemd_unitdir}/system/ota-update.service
+
+ # enable services
+ ln -sf ${systemd_unitdir}/system/ota-update.service \
+ ${D}${sysconfdir}/systemd/system/ota-update.target.wants/ota-update.service
+}
+
+FILES_${PN} = "${base_libdir}/systemd/system/*.service \
+ ${base_libdir}/systemd/system/ota-update.target \
+ ${sysconfdir} \
+ /sbin/ota-update.sh"
+
+# As this package is tied to systemd, only build it when we're also building systemd.
+python () {
+ if not oe.utils.contains ('DISTRO_FEATURES', 'systemd', True, False, d):
+ raise bb.parse.SkipPackage("'systemd' not in DISTRO_FEATURES")
+}
diff --git a/meta-edison-distro/recipes-core/readline/files/readline-fix-segfault-when-pressing-DEL-key-twice.patch b/meta-edison-distro/recipes-core/readline/files/readline-fix-segfault-when-pressing-DEL-key-twice.patch
new file mode 100644
index 0000000..4dcaf89
--- /dev/null
+++ b/meta-edison-distro/recipes-core/readline/files/readline-fix-segfault-when-pressing-DEL-key-twice.patch
@@ -0,0 +1,39 @@
+From 8acbcaa6b3d855f3e85e6a108db323278584091e Mon Sep 17 00:00:00 2001
+From: Loic Akue <loicx.akue@intel.com>
+Date: Mon, 3 Nov 2014 16:26:42 +0100
+Subject: [PATCH] bug readline
+
+| READLINE PATCH REPORT
+| =====================
+|
+|Readline-Release: 6.3
+|Patch-ID: readline63-002
+|
+|Bug-Reported-by: Anatol Pomozov <anatol.pomozov@gmail.com>
+|Bug-Reference-ID: <CAOMFOmXy3mT2So5GQ5F-smCVArQuAeBwZ2QKzgCtMeXJoDeYOQ@mail.gmail.com>
+|Bug-Reference-URL: http://lists.gnu.org/archive/html/bug-readline/2014-03/msg00010.html
+|
+|Bug-Description:
+|
+|When in callback mode, some readline commands can cause readline to seg
+|fault by passing invalid contexts to callback functions.
+
+Signed-off-by: Loic Akue <loicx.akue@intel.com>
+
+diff --git a/readline.c b/readline.c
+index 03eefa6..55c0522 100644
+--- a/readline.c
++++ b/readline.c
+@@ -744,7 +744,8 @@ _rl_dispatch_callback (cxt)
+ r = _rl_subseq_result (r, cxt->oldmap, cxt->okey, (cxt->flags & KSEQ_SUBSEQ));
+
+ RL_CHECK_SIGNALS ();
+- if (r == 0) /* success! */
++ /* We only treat values < 0 specially to simulate recursion. */
++ if (r >= 0 || (r == -1 && (cxt->flags & KSEQ_SUBSEQ) == 0)) /* success! or failure! */
+ {
+ _rl_keyseq_chain_dispose ();
+ RL_UNSETSTATE (RL_STATE_MULTIKEY);
+--
+1.7.9.5
+
diff --git a/meta-edison-distro/recipes-core/readline/readline_6.3.bbappend b/meta-edison-distro/recipes-core/readline/readline_6.3.bbappend
new file mode 100644
index 0000000..c8ecc36
--- /dev/null
+++ b/meta-edison-distro/recipes-core/readline/readline_6.3.bbappend
@@ -0,0 +1,4 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
+SRC_URI += "\
+ file://readline-fix-segfault-when-pressing-DEL-key-twice.patch \
+ "
diff --git a/meta-edison-distro/recipes-core/resize-rootfs/files/resize-rootfs.service b/meta-edison-distro/recipes-core/resize-rootfs/files/resize-rootfs.service
new file mode 100644
index 0000000..708226f
--- /dev/null
+++ b/meta-edison-distro/recipes-core/resize-rootfs/files/resize-rootfs.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=Increases rootfs image size to fit partition
+Requires=dev-disk-by\x2dpartlabel-rootfs.device
+After=dev-disk-by\x2dpartlabel-rootfs.device
+
+[Service]
+Type=oneshot
+ExecStart=/sbin/resize2fs /dev/disk/by-partlabel/rootfs
+ExecStart=/bin/systemctl disable resize-rootfs.service
+
+StandardOutput=journal+console
+
+[Install]
+WantedBy=default.target
diff --git a/meta-edison-distro/recipes-core/resize-rootfs/resize-rootfs.bb b/meta-edison-distro/recipes-core/resize-rootfs/resize-rootfs.bb
new file mode 100644
index 0000000..f91e4ba
--- /dev/null
+++ b/meta-edison-distro/recipes-core/resize-rootfs/resize-rootfs.bb
@@ -0,0 +1,24 @@
+DESCRIPTION = "Resize Rootfs systemd service"
+LICENSE = "GPLv2+"
+LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6"
+
+SRC_URI = "file://resize-rootfs.service"
+
+inherit systemd
+
+SYSTEMD_SERVICE_${PN} = "resize-rootfs.service"
+
+RDEPENDS_${PN} = "systemd e2fsprogs-resize2fs"
+
+do_install() {
+ install -d ${D}${systemd_unitdir}/system
+ install -c -m 0644 ${WORKDIR}/resize-rootfs.service ${D}${systemd_unitdir}/system
+}
+
+FILES_${PN} = "${base_libdir}/systemd/system/resize-rootfs.service"
+
+# As this package is tied to systemd, only build it when we're also building systemd.
+python () {
+ if not oe.utils.contains ('DISTRO_FEATURES', 'systemd', True, False, d):
+ raise bb.parse.SkipPackage("'systemd' not in DISTRO_FEATURES")
+}
diff --git a/meta-edison-distro/recipes-core/systemd/files/edison-machine-id.service b/meta-edison-distro/recipes-core/systemd/files/edison-machine-id.service
new file mode 100644
index 0000000..3caa836
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/files/edison-machine-id.service
@@ -0,0 +1,14 @@
+[Unit]
+Description= Generate unique machine-id
+After=systemd-remount-fs.service
+
+[Service]
+Type=oneshot
+ExecStartPre=/bin/umount /etc/machine-id
+ExecStart=/bin/systemd-machine-id-setup
+ExecStartPost=/bin/systemctl disable edison-machine-id
+StandardOutput=journal+console
+
+[Install]
+WantedBy=basic.target
+
diff --git a/meta-edison-distro/recipes-core/systemd/files/hsu-pm-runtime.service b/meta-edison-distro/recipes-core/systemd/files/hsu-pm-runtime.service
new file mode 100644
index 0000000..e81b6ff
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/files/hsu-pm-runtime.service
@@ -0,0 +1,14 @@
+[Unit]
+Description= HSU runtime pm service
+Requires=getty.target
+After=getty.target
+
+[Service]
+Type=oneshot
+ExecStart=/bin/sh -c 'echo auto > /sys/devices/pci0000:00/0000:00:04.3/power/control'
+ExecStart=/bin/sh -c 'echo auto > /sys/devices/pci0000:00/0000:00:04.1/power/control'
+StandardOutput=null
+
+[Install]
+WantedBy=default.target
+
diff --git a/meta-edison-distro/recipes-core/systemd/files/journald.conf b/meta-edison-distro/recipes-core/systemd/files/journald.conf
new file mode 100644
index 0000000..e096485
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/files/journald.conf
@@ -0,0 +1,36 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# See journald.conf(5) for details
+
+[Journal]
+Storage=persistent
+#Compress=yes
+#Seal=yes
+#SplitMode=login
+#SyncIntervalSec=5m
+#RateLimitInterval=30s
+#RateLimitBurst=1000
+#SystemMaxUse=
+#SystemKeepFree=
+#SystemMaxFileSize=
+#RuntimeMaxUse=
+#RuntimeKeepFree=
+#RuntimeMaxFileSize=
+#MaxRetentionSec=
+#MaxFileSec=1month
+#ForwardToSyslog=yes
+#ForwardToKMsg=no
+#ForwardToConsole=no
+#ForwardToWall=yes
+#TTYPath=/dev/console
+#MaxLevelStore=debug
+#MaxLevelSyslog=debug
+#MaxLevelKMsg=notice
+#MaxLevelConsole=info
+#MaxLevelWall=emerg
+
diff --git a/meta-edison-distro/recipes-core/systemd/files/system.conf b/meta-edison-distro/recipes-core/systemd/files/system.conf
new file mode 100644
index 0000000..e21ba85
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/files/system.conf
@@ -0,0 +1,45 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# See systemd-system.conf(5) for details
+
+[Manager]
+#LogLevel=info
+#LogTarget=journal-or-kmsg
+#LogColor=yes
+#LogLocation=no
+#DumpCore=yes
+#CrashShell=no
+#ShowStatus=yes
+#CrashChVT=1
+#CPUAffinity=1 2
+#DefaultControllers=cpu
+#DefaultStandardOutput=journal
+#DefaultStandardError=inherit
+#JoinControllers=cpu,cpuacct,cpuset net_cls,net_prio
+# Watchdog timeout. Value must be between 35 and 170 seconds.
+RuntimeWatchdogSec=90
+#ShutdownWatchdogSec=10min
+#CapabilityBoundingSet=
+#TimerSlackNSec=
+#DefaultEnvironment=
+#DefaultLimitCPU=
+#DefaultLimitFSIZE=
+#DefaultLimitDATA=
+#DefaultLimitSTACK=
+#DefaultLimitCORE=
+#DefaultLimitRSS=
+#DefaultLimitNOFILE=
+#DefaultLimitAS=
+#DefaultLimitNPROC=
+#DefaultLimitMEMLOCK=
+#DefaultLimitLOCKS=
+#DefaultLimitSIGPENDING=
+#DefaultLimitMSGQUEUE=
+#DefaultLimitNICE=
+#DefaultLimitRTPRIO=
+#DefaultLimitRTTIME=
diff --git a/meta-edison-distro/recipes-core/systemd/files/systemd-reboot-service.patch b/meta-edison-distro/recipes-core/systemd/files/systemd-reboot-service.patch
new file mode 100644
index 0000000..aaf1121
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/files/systemd-reboot-service.patch
@@ -0,0 +1,9 @@
+diff --git a/units/systemd-reboot.service.in b/units/systemd-reboot.service.in
+index d99bd3e..4517cfe 100644
+--- a/units/systemd-reboot.service.in
++++ b/units/systemd-reboot.service.in
+@@ -15,3 +15,4 @@ After=shutdown.target umount.target final.target
+ [Service]
+ Type=oneshot
+ ExecStart=@SYSTEMCTL@ --force reboot
++ExecStartPre=/bin/sh -c " if test -e /run/systemd/reboot-param ; then read REBOOTPARAM < /run/systemd/reboot-param ; fw_setenv bootargs_mode $REBOOTPARAM ; fi "
diff --git a/meta-edison-distro/recipes-core/systemd/files/timesyncd.conf b/meta-edison-distro/recipes-core/systemd/files/timesyncd.conf
new file mode 100644
index 0000000..620ef45
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/files/timesyncd.conf
@@ -0,0 +1,12 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# See timesyncd.conf(5) for details
+
+[Time]
+Servers=time1.google.com time2.google.com time3.google.com time4.google.com
+
diff --git a/meta-edison-distro/recipes-core/systemd/files/usb0.network b/meta-edison-distro/recipes-core/systemd/files/usb0.network
new file mode 100644
index 0000000..b7d1042
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/files/usb0.network
@@ -0,0 +1,6 @@
+[Match]
+Name=usb0
+
+[Network]
+Address=192.168.2.15/24
+
diff --git a/meta-edison-distro/recipes-core/systemd/systemd-compat-units.bb b/meta-edison-distro/recipes-core/systemd/systemd-compat-units.bb
new file mode 100644
index 0000000..6419bc2
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/systemd-compat-units.bb
@@ -0,0 +1,41 @@
+SUMMARY = "Enhances systemd compatilibity with existing SysVinit scripts"
+
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://${COREBASE}/LICENSE;md5=4d92cd373abda3937c2bc47fbc49d690"
+
+PR = "r29"
+
+DEPENDS = "systemd-systemctl-native"
+
+inherit allarch
+
+ALLOW_EMPTY_${PN} = "1"
+
+SYSTEMD_DISABLED_SYSV_SERVICES = " \
+ busybox-udhcpc \
+ hwclock \
+ networking \
+ nfsserver \
+ nfscommon \
+ syslog.busybox \
+"
+
+pkg_postinst_${PN} () {
+ cd $D${sysconfdir}/init.d
+
+ echo "Disabling the following sysv scripts: "
+
+ OPTS=""
+
+ if [ -n "$D" ]; then
+ OPTS="--root=$D"
+ fi
+
+ for i in ${SYSTEMD_DISABLED_SYSV_SERVICES} ; do
+ if [ \( -e $i -o $i.sh \) -a ! \( -e $D${sysconfdir}/systemd/system/$i.service -o -e $D${systemd_unitdir}/system/$i.service \) ] ; then
+ echo -n "$i: " ; systemctl ${OPTS} mask $i.service
+ fi
+ done ; echo
+}
+
+RDPEPENDS_${PN} = "systemd"
diff --git a/meta-edison-distro/recipes-core/systemd/systemd-serialgetty.bb b/meta-edison-distro/recipes-core/systemd/systemd-serialgetty.bb
new file mode 100644
index 0000000..1c34d5c
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/systemd-serialgetty.bb
@@ -0,0 +1,49 @@
+SUMMARY = "Serial terminal support for systemd"
+LICENSE = "GPLv2+"
+LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6"
+
+PR = "r5"
+
+SERIAL_CONSOLE ?= "115200 ttyS0"
+
+SRC_URI = "file://serial-getty@.service"
+
+do_install() {
+ if [ ! -z "${SERIAL_CONSOLES}" ] ; then
+ default_baudrate=`echo "${SERIAL_CONSOLES}" | sed 's/\;.*//'`
+ install -d ${D}${systemd_unitdir}/system/
+ install -d ${D}${sysconfdir}/systemd/system/getty.target.wants/
+ install -m 0644 ${WORKDIR}/serial-getty@.service ${D}${systemd_unitdir}/system/
+ sed -i -e s/\@BAUDRATE\@/$default_baudrate/g ${D}${systemd_unitdir}/system/serial-getty@.service
+
+ tmp="${SERIAL_CONSOLES}"
+ for entry in $tmp ; do
+ baudrate=`echo $entry | sed 's/\;.*//'`
+ ttydev=`echo $entry | sed -e 's/^[0-9]*\;//' -e 's/\;.*//'`
+ if [ "$baudrate" = "$default_baudrate" ] ; then
+ # enable the service
+ ln -sf ${systemd_unitdir}/system/serial-getty@.service \
+ ${D}${sysconfdir}/systemd/system/getty.target.wants/serial-getty@$ttydev.service
+ else
+ # install custom service file for the non-default baudrate
+ install -m 0644 ${WORKDIR}/serial-getty@.service ${D}${systemd_unitdir}/system/serial-getty$baudrate@.service
+ sed -i -e s/\@BAUDRATE\@/$baudrate/g ${D}${systemd_unitdir}/system/serial-getty$baudrate@.service
+ # enable the service
+ ln -sf ${systemd_unitdir}/system/serial-getty$baudrate@.service \
+ ${D}${sysconfdir}/systemd/system/getty.target.wants/serial-getty$baudrate@$ttydev.service
+ fi
+ done
+ fi
+}
+
+RDEPENDS_${PN} = "systemd"
+
+# This is a machine specific file
+FILES_${PN} = "${systemd_unitdir}/system/*.service ${sysconfdir}"
+PACKAGE_ARCH = "${MACHINE_ARCH}"
+
+# As this package is tied to systemd, only build it when we're also building systemd.
+python () {
+ if not bb.utils.contains ('DISTRO_FEATURES', 'systemd', True, False, d):
+ raise bb.parse.SkipPackage("'systemd' not in DISTRO_FEATURES")
+}
diff --git a/meta-edison-distro/recipes-core/systemd/systemd-serialgetty/serial-getty@.service b/meta-edison-distro/recipes-core/systemd/systemd-serialgetty/serial-getty@.service
new file mode 100644
index 0000000..6dd335c
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/systemd-serialgetty/serial-getty@.service
@@ -0,0 +1,37 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+
+[Unit]
+Description=Serial Getty on %I
+Documentation=man:agetty(8) man:systemd-getty-generator(8)
+Documentation=http://0pointer.de/blog/projects/serial-console.html
+BindsTo=dev-%i.device
+After=dev-%i.device systemd-user-sessions.service plymouth-quit-wait.service
+After=rc-local.service
+
+# If additional gettys are spawned during boot then we should make
+# sure that this is synchronized before getty.target, even though
+# getty.target didn't actually pull it in.
+Before=getty.target
+IgnoreOnIsolate=yes
+
+[Service]
+Environment="TERM=xterm"
+ExecStart=-/sbin/agetty -8 --keep-baud %I @BAUDRATE@ $TERM
+Type=idle
+Restart=always
+RestartSec=0
+UtmpIdentifier=%I
+TTYPath=/dev/%I
+TTYReset=yes
+TTYVHangup=yes
+KillMode=process
+IgnoreSIGPIPE=no
+SendSIGHUP=yes
+
+[Install]
+WantedBy=getty.target
diff --git a/meta-edison-distro/recipes-core/systemd/systemd-systemctl-native.bb b/meta-edison-distro/recipes-core/systemd/systemd-systemctl-native.bb
new file mode 100644
index 0000000..72bc77d
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/systemd-systemctl-native.bb
@@ -0,0 +1,15 @@
+SUMMARY = "Wrapper for enabling systemd services"
+
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://${COREBASE}/LICENSE;md5=4d92cd373abda3937c2bc47fbc49d690"
+
+PR = "r6"
+
+inherit native
+
+SRC_URI = "file://systemctl"
+
+do_install() {
+ install -d ${D}${bindir}
+ install -m 0755 ${WORKDIR}/systemctl ${D}${bindir}
+}
diff --git a/meta-edison-distro/recipes-core/systemd/systemd-systemctl/systemctl b/meta-edison-distro/recipes-core/systemd/systemd-systemctl/systemctl
new file mode 100755
index 0000000..b37f27a
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/systemd-systemctl/systemctl
@@ -0,0 +1,153 @@
+#!/bin/sh
+echo "Started $0 $*"
+
+ROOT=
+
+# parse command line params
+action=
+while [ $# != 0 ]; do
+ opt="$1"
+
+ case "$opt" in
+ enable)
+ shift
+
+ action="$opt"
+ services="$1"
+ cmd_args="1"
+ shift
+ ;;
+ disable)
+ shift
+
+ action="$opt"
+ services="$1"
+ cmd_args="1"
+ shift
+ ;;
+ mask)
+ shift
+
+ action="$opt"
+ services="$1"
+ cmd_args="1"
+ shift
+ ;;
+ preset)
+ shift
+
+ action="$opt"
+ services="$1"
+ cmd_args="1"
+ shift
+ ;;
+ --root=*)
+ ROOT=${opt##--root=}
+ cmd_args="0"
+ shift
+ ;;
+ *)
+ if [ "$cmd_args" = "1" ]; then
+ services="$services $opt"
+ shift
+ else
+ echo "'$opt' is an unkown option; exiting with error"
+ exit 1
+ fi
+ ;;
+ esac
+done
+if [ "$action" = "preset" -a "$service_file" = "" ]; then
+ services=$(for f in `find $ROOT/etc/systemd/system $ROOT/lib/systemd/system $ROOT/usr/lib/systemd/system -type f 2>1`; do basename $f; done)
+ services="$services $opt"
+ presetall=1
+fi
+
+for service in $services; do
+ if [ "$presetall" = "1" ]; then
+ action="preset"
+ fi
+ if [ "$action" = "mask" ]; then
+ if [ ! -d $ROOT/etc/systemd/system/ ]; then
+ mkdir -p $ROOT/etc/systemd/system/
+ fi
+ cmd="ln -s /dev/null $ROOT/etc/systemd/system/$service"
+ echo "$cmd"
+ $cmd
+ exit 0
+ fi
+
+ echo "Try to find location of $service..."
+ # find service file
+ for p in $ROOT/etc/systemd/system \
+ $ROOT/lib/systemd/system \
+ $ROOT/usr/lib/systemd/system; do
+ if [ -e $p/$service ]; then
+ service_file=$p/$service
+ service_file=${service_file##$ROOT}
+ fi
+ done
+ if [ -z "$service_file" ]; then
+ echo "'$service' couldn't be found; exiting with error"
+ exit 1
+ fi
+ echo "Found $service in $service_file"
+
+ # If any new unit types are added to systemd they should be added
+ # to this regular expression.
+ unit_types_re='\.\(service\|socket\|device\|mount\|automount\|swap\|target\|path\|timer\|snapshot\)$'
+ if [ "$action" = "preset" ]; then
+ action=`egrep -sh $service $ROOT/etc/systemd/user-preset/*.preset | cut -f1 -d' '`
+ if [ -z "$action" ]; then
+ globalpreset=`egrep -sh '\*' $ROOT/etc/systemd/user-preset/*.preset | cut -f1 -d' '`
+ if [ -n "$globalpreset" ]; then
+ action="$globalpreset"
+ else
+ action="enable"
+ fi
+ fi
+ fi
+ # create the required symbolic links
+ wanted_by=$(sed '/^WantedBy[[:space:]]*=/s,[^=]*=,,p;d' "$ROOT/$service_file" \
+ | tr ',' '\n' \
+ | grep "$unit_types_re")
+
+ for r in $wanted_by; do
+ echo "WantedBy=$r found in $service"
+ if [ "$action" = "enable" ]; then
+ mkdir -p $ROOT/etc/systemd/system/$r.wants
+ ln -s $service_file $ROOT/etc/systemd/system/$r.wants
+ echo "Enabled $service for $wanted_by."
+ else
+ rm -f $ROOT/etc/systemd/system/$r.wants/$service
+ rmdir --ignore-fail-on-non-empty -p $ROOT/etc/systemd/system/$r.wants
+ echo "Disabled $service for $wanted_by."
+ fi
+ done
+
+ # create the required symbolic 'Alias' links
+ alias=$(sed '/^Alias[[:space:]]*=/s,[^=]*=,,p;d' "$ROOT/$service_file" \
+ | tr ',' '\n' \
+ | grep "$unit_types_re")
+
+ for r in $alias; do
+ if [ "$action" = "enable" ]; then
+ mkdir -p $ROOT/etc/systemd/system
+ ln -s $service_file $ROOT/etc/systemd/system/$r
+ echo "Enabled $service for $alias."
+ else
+ rm -f $ROOT/etc/systemd/system/$r
+ echo "Disabled $service for $alias."
+ fi
+ done
+
+ # call us for the other required scripts
+ also=$(sed '/^Also[[:space:]]*=/s,[^=]*=,,p;d' "$ROOT/$service_file" \
+ | tr ',' '\n')
+ for a in $also; do
+ echo "Also=$a found in $service"
+ if [ "$action" = "enable" ]; then
+ $0 --root=$ROOT enable $a
+ fi
+ done
+done
diff --git a/meta-edison-distro/recipes-core/systemd/systemd/00-create-volatile.conf b/meta-edison-distro/recipes-core/systemd/systemd/00-create-volatile.conf
new file mode 100644
index 0000000..01ec03e
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/systemd/00-create-volatile.conf
@@ -0,0 +1,6 @@
+#This goes hand-in-hand with the base-files of OE-Core. The file must
+# be sorted before 'systemd.conf' becuase this attempts to create a file
+# inside /var/log.
+
+
+d /var/volatile/tmp - - - -
diff --git a/meta-edison-distro/recipes-core/systemd/systemd/0001-uClibc-doesn-t-implement-pwritev-preadv.patch b/meta-edison-distro/recipes-core/systemd/systemd/0001-uClibc-doesn-t-implement-pwritev-preadv.patch
new file mode 100644
index 0000000..9fdb3c9
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/systemd/0001-uClibc-doesn-t-implement-pwritev-preadv.patch
@@ -0,0 +1,34 @@
+Upstream-Status: Inappropriate [uclibc specific]
+
+From 7be9273548bcb1f57d011fc252965e45dd2a058c Mon Sep 17 00:00:00 2001
+From: Khem Raj <raj.khem@gmail.com>
+Date: Wed, 21 Aug 2013 19:09:27 -0700
+Subject: [PATCH] uClibc doesn't implement pwritev/preadv
+
+Lets stub out the testcase for building.
+
+Signed-off-by: Khem Raj <raj.khem@gmail.com>
+---
+ src/libsystemd-bus/test-bus-memfd.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+Index: systemd-209/src/libsystemd/sd-bus/test-bus-memfd.c
+===================================================================
+--- systemd-209.orig/src/libsystemd/sd-bus/test-bus-memfd.c 2014-02-19 15:03:09.983254602 -0800
++++ systemd-209/src/libsystemd/sd-bus/test-bus-memfd.c 2014-02-19 23:42:10.636652864 -0800
+@@ -151,6 +151,7 @@
+ /* check content */
+ assert_se(memcmp(buf, "ll", 2) == 0);
+
++#ifndef __UCLIBC__
+ /* writev it out*/
+ iov[0].iov_base = (char *)"ABC";
+ iov[0].iov_len = 3;
+@@ -173,6 +174,7 @@
+ assert_se(memcmp(bufv[0], "ABC", 3) == 0);
+ assert_se(memcmp(bufv[1], "DEF", 3) == 0);
+ assert_se(memcmp(bufv[2], "GHI", 3) == 0);
++#endif /* __UCLIBC__ */
+
+ sd_memfd_free(m);
+
diff --git a/meta-edison-distro/recipes-core/systemd/systemd/binfmt-install.patch b/meta-edison-distro/recipes-core/systemd/systemd/binfmt-install.patch
new file mode 100644
index 0000000..c2d5099
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/systemd/binfmt-install.patch
@@ -0,0 +1,56 @@
+Don't install dependency links at install time for the binfmt services, use
+[Install] blocks so that they get created when the service is enabled like a
+traditional service.
+
+The [Install] blocks were rejected upstream as they don't have a way to "enable"
+it on install without static symlinks which can't be disabled, only masked. We
+however can do that in a postinst.
+
+Upstream-Status: Denied
+Signed-off-by: Ross Burton <ross.burton@intel.com>
+
+diff --git a/Makefile.am b/Makefile.am
+index 7933de6..78acb6f 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -3133,10 +3133,6 @@ INSTALL_DIRS += \
+ $(prefix)/lib/binfmt.d \
+ $(sysconfdir)/binfmt.d
+
+-SYSINIT_TARGET_WANTS += \
+- systemd-binfmt.service \
+- proc-sys-fs-binfmt_misc.automount
+-
+ endif
+
+ EXTRA_DIST += \
+diff --git a/units/proc-sys-fs-binfmt_misc.automount b/units/proc-sys-fs-binfmt_misc.automount
+index 6be3893..709adef 100644
+--- a/units/proc-sys-fs-binfmt_misc.automount
++++ b/units/proc-sys-fs-binfmt_misc.automount
+@@ -16,3 +16,6 @@ ConditionPathIsReadWrite=/proc/sys/
+
+ [Automount]
+ Where=/proc/sys/fs/binfmt_misc
++
++[Install]
++WantedBy=sysinit.target
+diff --git a/units/systemd-binfmt.service.in b/units/systemd-binfmt.service.in
+index 02dfe77..86d3481 100644
+--- a/units/systemd-binfmt.service.in
++++ b/units/systemd-binfmt.service.in
+@@ -11,6 +11,7 @@ Documentation=man:systemd-binfmt.service(8) man:binfmt.d(5)
+ Documentation=https://www.kernel.org/doc/Documentation/binfmt_misc.txt
+ DefaultDependencies=no
+ Conflicts=shutdown.target
++Wants=proc-sys-fs-binfmt_misc.automount
+ After=systemd-readahead-collect.service systemd-readahead-replay.service proc-sys-fs-binfmt_misc.automount
+ Before=sysinit.target shutdown.target
+ ConditionPathIsReadWrite=/proc/sys/
+@@ -24,3 +25,6 @@ ConditionDirectoryNotEmpty=|/run/binfmt.d
+ Type=oneshot
+ RemainAfterExit=yes
+ ExecStart=@rootlibexecdir@/systemd-binfmt
++
++[Install]
++WantedBy=sysinit.target
diff --git a/meta-edison-distro/recipes-core/systemd/systemd/init b/meta-edison-distro/recipes-core/systemd/systemd/init
new file mode 100644
index 0000000..ea52be4
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/systemd/init
@@ -0,0 +1,104 @@
+#!/bin/sh
+
+### BEGIN INIT INFO
+# Provides: udev
+# Required-Start: mountvirtfs
+# Required-Stop:
+# Default-Start: S
+# Default-Stop:
+# Short-Description: Start udevd, populate /dev and load drivers.
+### END INIT INFO
+
+. /etc/init.d/functions
+
+export TZ=/etc/localtime
+
+[ -d /sys/class ] || exit 1
+[ -r /proc/mounts ] || exit 1
+[ -x @UDEVD@ ] || exit 1
+[ -f /etc/default/udev-cache ] && . /etc/default/udev-cache
+[ -f /etc/udev/udev.conf ] && . /etc/udev/udev.conf
+
+readfile () {
+ filename=$1
+ READDATA=""
+ if [ -r $filename ]; then
+ while read line; do
+ READDATA="$READDATA$line"
+ done < $filename
+ fi
+}
+
+case "$1" in
+ start)
+ export ACTION=add
+ # propagate /dev from /sys
+ echo "Starting udev"
+
+ # mount the devtmpfs on /dev, if not already done
+ LANG=C awk '$2 == "/dev" && ($3 == "devtmpfs") { exit 1 }' /proc/mounts && {
+ mount -n -o mode=0755 -t devtmpfs none "/dev"
+ }
+ [ -e /dev/pts ] || mkdir -m 0755 /dev/pts
+ [ -e /dev/shm ] || mkdir -m 1777 /dev/shm
+ mount -a -t tmpfs 2>/dev/null
+
+ # cache handling
+ if [ "$DEVCACHE" != "" ]; then
+ readfile /proc/version
+ VERSION="$READDATA"
+ readfile /proc/cmdline
+ CMDLINE="$READDATA"
+ readfile /proc/devices
+ DEVICES="$READDATA"
+ readfile /proc/atags
+ ATAGS="$READDATA"
+
+ if [ -e $DEVCACHE ]; then
+ readfile /etc/udev/cache.data
+ if [ "$READDATA" = "$VERSION$CMDLINE$DEVICES$ATAGS" ]; then
+ (cd /; tar xf $DEVCACHE > /dev/null 2>&1)
+ not_first_boot=1
+ [ "$VERBOSE" != "no" ] && echo "udev: using cache file $DEVCACHE"
+ [ -e /dev/shm/udev.cache ] && rm -f /dev/shm/udev.cache
+ else
+ echo "$VERSION$CMDLINE$DEVICES$ATAGS" > /dev/shm/udev.cache
+ fi
+ else
+ echo "$VERSION$CMDLINE$DEVICES$ATAGS" > /dev/shm/udev.cache
+ fi
+ fi
+
+ # make_extra_nodes
+ killproc systemd-udevd > "/dev/null" 2>&1
+
+ # trigger the sorted events
+ echo -e '\000\000\000\000' > /proc/sys/kernel/hotplug
+ @UDEVD@ -d
+
+ udevadm control --env=STARTUP=1
+ if [ "$not_first_boot" != "" ];then
+ udevadm trigger --action=add --subsystem-nomatch=tty --subsystem-nomatch=mem --subsystem-nomatch=vc --subsystem-nomatch=vtconsole --subsystem-nomatch=misc --subsystem-nomatch=dcon --subsystem-nomatch=pci_bus --subsystem-nomatch=graphics --subsystem-nomatch=backlight --subsystem-nomatch=video4linux --subsystem-nomatch=platform
+ (udevadm settle --timeout=3; udevadm control --env=STARTUP=)&
+ else
+ udevadm trigger --action=add
+ udevadm settle
+ fi
+ ;;
+ stop)
+ echo "Stopping udevd"
+ start-stop-daemon --stop --name systemd-udevd --quiet
+ ;;
+ restart)
+ $0 stop
+ sleep 1
+ $0 start
+ ;;
+ status)
+ status systemd-udevd
+ ;;
+ *)
+ echo "Usage: $0 {start|stop|status|restart}"
+ exit 1
+esac
+exit 0
diff --git a/meta-edison-distro/recipes-core/systemd/systemd/optional_secure_getenv.patch b/meta-edison-distro/recipes-core/systemd/systemd/optional_secure_getenv.patch
new file mode 100644
index 0000000..2063268
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/systemd/optional_secure_getenv.patch
@@ -0,0 +1,19 @@
+on uclibc secure_getenv is not available
+therefore default to using getenv instead
+
+Upstream-Status: Denied [no desire for uclibc support]
+Signed-off-by: Khem Raj <raj.khem@gmail.com>
+
+Index: git/src/shared/missing.h
+===================================================================
+--- git.orig/src/shared/missing.h 2012-09-22 18:46:44.141282145 -0700
++++ git/src/shared/missing.h 2012-09-22 18:48:44.081276570 -0700
+@@ -233,6 +233,8 @@
+ #ifndef HAVE_SECURE_GETENV
+ # ifdef HAVE___SECURE_GETENV
+ # define secure_getenv __secure_getenv
++# elif defined __UCLIBC__
++# define secure_getenv getenv
+ # else
+ # error neither secure_getenv nor __secure_getenv are available
+ # endif
diff --git a/meta-edison-distro/recipes-core/systemd/systemd/run-ptest b/meta-edison-distro/recipes-core/systemd/systemd/run-ptest
new file mode 100644
index 0000000..2f6bd93
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/systemd/run-ptest
@@ -0,0 +1,3 @@
+tar -C test -xJf test/sys.tar.xz
+make test/rules-test.sh.log
+make test/udev-test.pl.log
diff --git a/meta-edison-distro/recipes-core/systemd/systemd/systemd-older-kernel.patch b/meta-edison-distro/recipes-core/systemd/systemd/systemd-older-kernel.patch
new file mode 100644
index 0000000..18b50e7
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/systemd/systemd-older-kernel.patch
@@ -0,0 +1,56 @@
+From 6109f02dcc4f2d7a461c5772bab494f5753a2203 Mon Sep 17 00:00:00 2001
+From: Robert Yang <liezhi.yang@windriver.com>
+Date: Thu, 29 May 2014 08:09:07 +0000
+Subject: [PATCH] rtnl-types.c: check IFLA_VLAN_PROTOCOL
+
+The older kernel's linux/if_link.h doesn't have IFLA_VLAN_PROTOCOL, we need
+check whether it has been defined or not.
+
+The maintainer said that he would fix it:
+
+http://thread.gmane.org/gmane.comp.sysutils.systemd.devel/18200
+
+Also we need redefine IFLA_MAX from 34 to 35 when define IFLA_CARRIER,
+otherwise there would be error:
+
+| src/libsystemd/sd-rtnl/rtnl-types.c:233:9: error: array index in initializer exceeds array bounds
+| [IFLA_CARRIER] = { .type = NLA_U8 },
+
+Upstream-Status: Pending
+
+Signed-off-by: Robert Yang <liezhi.yang@windriver.com>
+---
+ src/libsystemd/sd-rtnl/rtnl-types.c | 2 ++
+ src/shared/missing.h | 2 ++
+ 2 files changed, 4 insertions(+)
+
+diff --git a/src/libsystemd/sd-rtnl/rtnl-types.c b/src/libsystemd/sd-rtnl/rtnl-types.c
+index 44ac5ec..ab6161f 100644
+--- a/src/libsystemd/sd-rtnl/rtnl-types.c
++++ b/src/libsystemd/sd-rtnl/rtnl-types.c
+@@ -67,7 +67,9 @@ static const NLType rtnl_link_info_data_vlan_types[IFLA_VLAN_MAX + 1] = {
+ [IFLA_VLAN_EGRESS_QOS] = { .type = NLA_NESTED },
+ [IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED },
+ */
++#ifdef IFLA_VLAN_PROTOCOL
+ [IFLA_VLAN_PROTOCOL] = { .type = NLA_U16 },
++#endif
+ };
+
+ static const NLType rtnl_link_info_data_bond_types[IFLA_BOND_MAX + 1] = {
+diff --git a/src/shared/missing.h b/src/shared/missing.h
+index d5ec2f8..732853f 100644
+--- a/src/shared/missing.h
++++ b/src/shared/missing.h
+@@ -94,6 +94,8 @@
+
+ #ifndef IFLA_CARRIER
+ #define IFLA_CARRIER 33
++ #undef IFLA_MAX
++ #define IFLA_MAX 35
+ #ifndef IFLA_NUM_RX_QUEUES
+ #define IFLA_NUM_RX_QUEUES 32
+ #ifndef IFLA_NUM_TX_QUEUES
+--
+1.8.3.4
+
diff --git a/meta-edison-distro/recipes-core/systemd/systemd/systemd-pam-configure-check-uclibc.patch b/meta-edison-distro/recipes-core/systemd/systemd/systemd-pam-configure-check-uclibc.patch
new file mode 100644
index 0000000..4639532
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/systemd/systemd-pam-configure-check-uclibc.patch
@@ -0,0 +1,32 @@
+Upstream-Status: Denied [no desire for uclibc support]
+Signed-off-by: Khem Raj <raj.khem@gmail.com>
+
+Index: git/configure.ac
+===================================================================
+--- git.orig/configure.ac 2014-03-15 17:53:51.756340454 -0700
++++ git/configure.ac 2014-03-15 18:07:34.888355897 -0700
+@@ -78,6 +78,24 @@
+
+ M4_DEFINES=
+
++# check for few functions not implemented in uClibc
++
++AC_CHECK_FUNCS_ONCE(mkostemp execvpe posix_fallocate)
++
++# check for %ms format support - assume always no if cross compiling
++
++AC_MSG_CHECKING([whether %ms format is supported by *scanf])
++
++AC_LINK_IFELSE(
++ [AC_LANG_PROGRAM([
++ #include <stdio.h>
++ ],[
++ char *buf1, *buf2, *buf3, str="1 2.3 abcde" ;
++ int rc = sscanf(str, "%ms %ms %ms", &buf1, &buf2, &buf3) ;
++ return (rc==3)?0:1;])],
++ [AC_DEFINE([HAVE_MSFORMAT], [1], [Define if %ms format is supported by *scanf.])],
++ [AC_MSG_RESULT([no])])
++
+ # gtkdocize greps for '^GTK_DOC_CHECK', so it needs to be on its own line
+ m4_ifdef([GTK_DOC_CHECK], [
+ GTK_DOC_CHECK([1.18],[--flavour no-tmpl])],
diff --git a/meta-edison-distro/recipes-core/systemd/systemd/systemd-pam-fix-execvpe.patch b/meta-edison-distro/recipes-core/systemd/systemd/systemd-pam-fix-execvpe.patch
new file mode 100644
index 0000000..7170a38
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/systemd/systemd-pam-fix-execvpe.patch
@@ -0,0 +1,29 @@
+Upstream-Status: Denied [no desire for uclibc support]
+Signed-off-by: Khem Raj <raj.khem@gmail.com>
+
+Index: systemd-209/src/nspawn/nspawn.c
+===================================================================
+--- systemd-209.orig/src/nspawn/nspawn.c 2014-02-19 15:03:09.000000000 -0800
++++ systemd-209/src/nspawn/nspawn.c 2014-02-19 23:20:38.720628627 -0800
+@@ -91,6 +91,8 @@
+ LINK_GUEST
+ } LinkJournal;
+
++#include "config.h"
++
+ static char *arg_directory = NULL;
+ static char *arg_user = NULL;
+ static sd_id128_t arg_uuid = {};
+@@ -2045,7 +2047,12 @@
+ a[0] = (char*) "/sbin/init";
+ execve(a[0], a, env_use);
+ } else if (argc > optind)
++#ifdef HAVE_EXECVPE
+ execvpe(argv[optind], argv + optind, env_use);
++#else
++ environ = env_use;
++ execvp(argv[optind], argv + optind);
++#endif /* HAVE_EXECVPE */
+ else {
+ chdir(home ? home : "/root");
+ execle("/bin/bash", "-bash", NULL, env_use);
diff --git a/meta-edison-distro/recipes-core/systemd/systemd/systemd-pam-fix-fallocate.patch b/meta-edison-distro/recipes-core/systemd/systemd/systemd-pam-fix-fallocate.patch
new file mode 100644
index 0000000..f8e19ce
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/systemd/systemd-pam-fix-fallocate.patch
@@ -0,0 +1,92 @@
+Upstream-Status: Denied [no desire for uclibc support]
+
+This patch is uclibc specific, thus not suitable for upstream.
+
+Signed-off-by: Khem Raj <raj.khem@gmail.com>
+Signed-off-by: Chen Qi <Qi.Chen@windriver.com>
+---
+ src/journal/journal-file.c | 16 +++++++++++++++-
+ src/journal/journald-kmsg.c | 16 ++++++++++++++--
+ 2 files changed, 29 insertions(+), 3 deletions(-)
+
+diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
+index f2f1f35..092f87b 100644
+--- a/src/journal/journal-file.c
++++ b/src/journal/journal-file.c
+@@ -38,6 +38,8 @@
+ #include "compress.h"
+ #include "fsprg.h"
+
++#include "config.h"
++
+ #define DEFAULT_DATA_HASH_TABLE_SIZE (2047ULL*sizeof(HashItem))
+ #define DEFAULT_FIELD_HASH_TABLE_SIZE (333ULL*sizeof(HashItem))
+
+@@ -314,7 +316,7 @@ static int journal_file_verify_header(JournalFile *f) {
+
+ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size) {
+ uint64_t old_size, new_size;
+- int r;
++ int r = 0;
+
+ assert(f);
+
+@@ -362,9 +364,21 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size)
+ /* Note that the glibc fallocate() fallback is very
+ inefficient, hence we try to minimize the allocation area
+ as we can. */
++#ifdef HAVE_POSIX_FALLOCATE
+ r = posix_fallocate(f->fd, old_size, new_size - old_size);
+ if (r != 0)
+ return -r;
++#else
++ /* Write something every 512 bytes to make sure the block is allocated */
++ uint64_t len = new_size - old_size;
++ uint64_t offset = old_size;
++ for (offset += (len-1) % 512; len > 0; offset += 512) {
++ len -= 512;
++ if (pwrite(f->fd, "", 1, offset) != 1)
++ return -errno;
++ }
++
++#endif /* HAVE_POSIX_FALLOCATE */
+
+ if (fstat(f->fd, &f->last_stat) < 0)
+ return -errno;
+diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c
+index 12992e7..dc4fa93 100644
+--- a/src/journal/journald-kmsg.c
++++ b/src/journal/journald-kmsg.c
+@@ -437,6 +437,7 @@ fail:
+ int server_open_kernel_seqnum(Server *s) {
+ _cleanup_close_ int fd;
+ uint64_t *p;
++ int r = 0;
+
+ assert(s);
+
+@@ -449,8 +450,19 @@ int server_open_kernel_seqnum(Server *s) {
+ log_error("Failed to open /run/systemd/journal/kernel-seqnum, ignoring: %m");
+ return 0;
+ }
+-
+- if (posix_fallocate(fd, 0, sizeof(uint64_t)) < 0) {
++#ifdef HAVE_POSIX_FALLOCATE
++ r = posix_fallocate(fd, 0, sizeof(uint64_t));
++#else
++ /* Use good old method to write zeros into the journal file
++ perhaps very inefficient yet working. */
++ char *buf = alloca(sizeof(uint64_t));
++ off_t oldpos = lseek(fd, 0, SEEK_CUR);
++ bzero(buf, sizeof(uint64_t));
++ lseek(fd, 0, SEEK_SET);
++ r = write(fd, buf, sizeof(uint64_t));
++ lseek(fd, oldpos, SEEK_SET);
++#endif /* HAVE_POSIX_FALLOCATE */
++ if (r < 0) {
+ log_error("Failed to allocate sequential number file, ignoring: %m");
+ return 0;
+ }
+--
+1.7.9.5
+
diff --git a/meta-edison-distro/recipes-core/systemd/systemd/systemd-pam-fix-getty-unit.patch b/meta-edison-distro/recipes-core/systemd/systemd/systemd-pam-fix-getty-unit.patch
new file mode 100644
index 0000000..9b4c940
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/systemd/systemd-pam-fix-getty-unit.patch
@@ -0,0 +1,35 @@
+Prefer getty to agetty in console setup systemd units
+
+Upstream-Status: Inappropriate [configuration specific]
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ units/getty@.service.m4 | 2 +-
+ units/serial-getty@.service.m4 | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+Index: git/units/getty@.service.m4
+===================================================================
+--- git.orig/units/getty@.service.m4 2014-03-15 08:16:17.000000000 -0700
++++ git/units/getty@.service.m4 2014-03-15 08:21:11.007695825 -0700
+@@ -27,7 +27,7 @@
+
+ [Service]
+ # the VT is cleared by TTYVTDisallocate
+-ExecStart=-/sbin/agetty --noclear %I $TERM
++ExecStart=-/sbin/getty -L %I $TERM
+ Type=idle
+ Restart=always
+ RestartSec=0
+Index: git/units/serial-getty@.service.m4
+===================================================================
+--- git.orig/units/serial-getty@.service.m4 2014-03-15 08:16:17.000000000 -0700
++++ git/units/serial-getty@.service.m4 2014-03-15 08:22:31.291697331 -0700
+@@ -22,7 +22,7 @@
+ IgnoreOnIsolate=yes
+
+ [Service]
+-ExecStart=-/sbin/agetty --keep-baud 115200,38400,9600 %I $TERM
++ExecStart=-/sbin/getty -L 115200 %I $TERM
+ Type=idle
+ Restart=always
+ RestartSec=0
diff --git a/meta-edison-distro/recipes-core/systemd/systemd/systemd-pam-fix-mkostemp.patch b/meta-edison-distro/recipes-core/systemd/systemd/systemd-pam-fix-mkostemp.patch
new file mode 100644
index 0000000..8c7aa07
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/systemd/systemd-pam-fix-mkostemp.patch
@@ -0,0 +1,30 @@
+Upstream-Status: Denied [no desire for uclibc support]
+Signed-off-by: Khem Raj <raj.khem@gmail.com>
+
+Index: git/src/shared/util.c
+===================================================================
+--- git.orig/src/shared/util.c 2014-03-15 15:14:21.368160908 -0700
++++ git/src/shared/util.c 2014-03-15 15:44:21.988194688 -0700
+@@ -85,6 +85,8 @@
+ #include "def.h"
+ #include "missing.h"
+
++#include "config.h"
++
+ int saved_argc = 0;
+ char **saved_argv = NULL;
+
+@@ -6222,7 +6224,13 @@
+
+ u = umask(077);
+
++#ifdef HAVE_MKOSTEMP
+ fd = mkostemp(pattern, flags);
++#else
++ fd = mkstemp(pattern);
++ if (fd >= 0) fcntl(fd, F_SETFD, flags);
++#endif /* HAVE_MKOSTEMP */
++
+ if (fd < 0)
+ return -errno;
+
diff --git a/meta-edison-distro/recipes-core/systemd/systemd/touchscreen.rules b/meta-edison-distro/recipes-core/systemd/systemd/touchscreen.rules
new file mode 100644
index 0000000..d83fd16
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/systemd/touchscreen.rules
@@ -0,0 +1,18 @@
+# There are a number of modifiers that are allowed to be used in some
+# of the different fields. They provide the following subsitutions:
+#
+# %n the "kernel number" of the device.
+# For example, 'sda3' has a "kernel number" of '3'
+# %e the smallest number for that name which does not matches an existing node
+# %k the kernel name for the device
+# %M the kernel major number for the device
+# %m the kernel minor number for the device
+# %b the bus id for the device
+# %c the string returned by the PROGRAM
+# %s{filename} the content of a sysfs attribute
+# %% the '%' char itself
+#
+
+# Create a symlink to any touchscreen input device
+SUBSYSTEM=="input", KERNEL=="event[0-9]*", ATTRS{modalias}=="input:*-e0*,3,*a0,1,*18,*", SYMLINK+="input/touchscreen0"
+SUBSYSTEM=="input", KERNEL=="event[0-9]*", ATTRS{modalias}=="ads7846", SYMLINK+="input/touchscreen0"
diff --git a/meta-edison-distro/recipes-core/systemd/systemd/uclibc-get-physmem.patch b/meta-edison-distro/recipes-core/systemd/systemd/uclibc-get-physmem.patch
new file mode 100644
index 0000000..39dfc9e
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/systemd/uclibc-get-physmem.patch
@@ -0,0 +1,37 @@
+bypass unimplemented _SC_PHYS_PAGES system configuration API in uclibc
+
+Upstream-Status: Inappropriate [uclibc-specific]
+
+Signed-off-by: Khem Raj <raj.khem@gmail.com>
+
+Index: git/src/shared/util.c
+===================================================================
+--- git.orig/src/shared/util.c 2014-03-15 18:09:34.796358146 -0700
++++ git/src/shared/util.c 2014-03-15 20:16:33.836501084 -0700
+@@ -6332,11 +6332,24 @@
+
+ /* We return this as uint64_t in case we are running as 32bit
+ * process on a 64bit kernel with huge amounts of memory */
+-
++#ifdef __UCLIBC__
++ char line[128];
++ FILE *f = fopen("/proc/meminfo", "r");
++ if (f == NULL)
++ return 0;
++ while (!feof(f) && fgets(line, sizeof(line)-1, f)) {
++ if (sscanf(line, "MemTotal: %l kB", &mem) == 1) {
++ mem *= 1024;
++ break;
++ }
++ }
++ fclose(f);
++ return (uint64_t) mem;
++#else
+ mem = sysconf(_SC_PHYS_PAGES);
+ assert(mem > 0);
+-
+ return (uint64_t) mem * (uint64_t) page_size();
++#endif
+ }
+
+ char* mount_test_option(const char *haystack, const char *needle) {
diff --git a/meta-edison-distro/recipes-core/systemd/systemd/uclibc-sysinfo_h.patch b/meta-edison-distro/recipes-core/systemd/systemd/uclibc-sysinfo_h.patch
new file mode 100644
index 0000000..15645de
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/systemd/uclibc-sysinfo_h.patch
@@ -0,0 +1,19 @@
+Dont include sys/sysinfo.h on uclibc it conflicts with linux/sysinfo.h
+
+Signed-off-by: Khem Raj <raj.khem@gmail.com>
+Upstream-Status: Inappropriate [uclibc specific]
+
+Index: systemd-209/src/readahead/readahead-common.c
+===================================================================
+--- systemd-209.orig/src/readahead/readahead-common.c 2014-02-12 18:42:33.810685053 -0800
++++ systemd-209/src/readahead/readahead-common.c 2014-02-19 23:49:31.856661142 -0800
+@@ -22,7 +22,9 @@
+ #include <errno.h>
+ #include <stdlib.h>
+ #include <string.h>
++#ifndef __UCLIBC__
+ #include <sys/sysinfo.h>
++#endif
+ #include <sys/inotify.h>
+ #include <fcntl.h>
+ #include <sys/mman.h>
diff --git a/meta-edison-distro/recipes-core/systemd/systemd_%.bbappend b/meta-edison-distro/recipes-core/systemd/systemd_%.bbappend
new file mode 100644
index 0000000..07b6cb2
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/systemd_%.bbappend
@@ -0,0 +1,34 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
+SRC_URI += "file://journald.conf \
+ file://timesyncd.conf \
+ file://system.conf \
+ file://systemd-reboot-service.patch \
+ file://hsu-pm-runtime.service \
+ file://usb0.network \
+ file://edison-machine-id.service"
+
+do_install_append() {
+ # Push the custom conf files on target
+ install -m 0644 ${WORKDIR}/journald.conf ${D}${sysconfdir}/systemd
+ install -m 0644 ${WORKDIR}/system.conf ${D}${sysconfdir}/systemd
+ install -m 0644 ${WORKDIR}/timesyncd.conf ${D}${sysconfdir}/systemd
+ install -m 0644 ${WORKDIR}/usb0.network ${D}${sysconfdir}/systemd/network
+
+ # enable timesyncd service
+ install -d ${D}${sysconfdir}/systemd/system/sysinit.target.wants
+ ln -sf ${systemd_unitdir}/system/systemd-timesyncd.service \
+ ${D}${sysconfdir}/systemd/system/sysinit.target.wants/systemd-timesyncd.service
+
+ # enable a custom service to enable the hsu driver's runtime pm
+ install -d ${D}${sysconfdir}/systemd/system/default.target.wants
+ install -m 0644 ${WORKDIR}/hsu-pm-runtime.service \
+ ${D}${systemd_unitdir}/system/hsu-pm-runtime.service
+
+ # enable a custom service to provide a persistant machine-id value to Edison
+ install -d ${D}${sysconfdir}/systemd/system/basic.target.wants
+ install -m 0644 ${WORKDIR}/edison-machine-id.service \
+ ${D}${systemd_unitdir}/system/edison-machine-id.service
+ ln -sf ${systemd_unitdir}/system/edison-machine-id.service \
+ ${D}${sysconfdir}/systemd/system/basic.target.wants/edison-machine-id.service
+
+}
diff --git a/meta-edison-distro/recipes-core/systemd/systemd_213.bb b/meta-edison-distro/recipes-core/systemd/systemd_213.bb
new file mode 100644
index 0000000..003b33e
--- /dev/null
+++ b/meta-edison-distro/recipes-core/systemd/systemd_213.bb
@@ -0,0 +1,351 @@
+SUMMARY = "System and service manager for Linux, replacing SysVinit"
+HOMEPAGE = "http://www.freedesktop.org/wiki/Software/systemd"
+
+LICENSE = "GPLv2 & LGPLv2.1 & MIT"
+LIC_FILES_CHKSUM = "file://LICENSE.GPL2;md5=751419260aa954499f7abaabaa882bbe \
+ file://LICENSE.LGPL2.1;md5=4fbd65380cdd255951079008b364516c \
+ file://LICENSE.MIT;md5=544799d0b492f119fa04641d1b8868ed"
+
+PROVIDES = "udev"
+
+PE = "1"
+
+DEPENDS = "kmod docbook-sgml-dtd-4.1-native intltool-native gperf-native acl readline dbus libcap libcgroup glib-2.0 qemu-native util-linux"
+DEPENDS += "${@bb.utils.contains('DISTRO_FEATURES', 'pam', 'libpam', '', d)}"
+
+SECTION = "base/shell"
+
+inherit gtk-doc useradd pkgconfig autotools perlnative update-rc.d update-alternatives qemu systemd ptest
+
+SRCREV = "c9679c652b3c31f2510e8805d81630680ebc7e95"
+
+PV = "213+git${SRCPV}"
+
+SRC_URI = "git://anongit.freedesktop.org/systemd/systemd;branch=master;protocol=git \
+ file://binfmt-install.patch \
+ file://systemd-pam-configure-check-uclibc.patch \
+ file://systemd-pam-fix-execvpe.patch \
+ file://systemd-pam-fix-fallocate.patch \
+ file://systemd-pam-fix-mkostemp.patch \
+ file://optional_secure_getenv.patch \
+ file://0001-uClibc-doesn-t-implement-pwritev-preadv.patch \
+ file://uclibc-sysinfo_h.patch \
+ file://uclibc-get-physmem.patch \
+ file://touchscreen.rules \
+ file://00-create-volatile.conf \
+ file://init \
+ file://run-ptest \
+ file://systemd-older-kernel.patch \
+ "
+
+S = "${WORKDIR}/git"
+
+SRC_URI_append_libc-uclibc = "\
+ file://systemd-pam-fix-getty-unit.patch \
+ "
+LDFLAGS_append_libc-uclibc = " -lrt"
+
+GTKDOC_DOCDIR = "${S}/docs/"
+
+PACKAGECONFIG ??= "xz"
+# Sign the journal for anti-tampering
+PACKAGECONFIG[gcrypt] = "--enable-gcrypt,--disable-gcrypt,libgcrypt"
+# regardless of PACKAGECONFIG, libgcrypt is always required to expand
+# the AM_PATH_LIBGCRYPT autoconf macro
+DEPENDS += "libgcrypt"
+# Compress the journal
+PACKAGECONFIG[xz] = "--enable-xz,--disable-xz,xz"
+PACKAGECONFIG[cryptsetup] = "--enable-libcryptsetup,--disable-libcryptsetup,cryptsetup"
+PACKAGECONFIG[microhttpd] = "--enable-microhttpd,--disable-microhttpd,libmicrohttpd"
+
+CACHED_CONFIGUREVARS = "ac_cv_path_KILL=${base_bindir}/kill"
+
+# Helper variables to clarify locations. This mirrors the logic in systemd's
+# build system.
+rootprefix ?= "${base_prefix}"
+rootlibdir ?= "${base_libdir}"
+rootlibexecdir = "${rootprefix}/lib"
+
+# The gtk+ tools should get built as a separate recipe e.g. systemd-tools
+EXTRA_OECONF = " --with-rootprefix=${rootprefix} \
+ --with-rootlibdir=${rootlibdir} \
+ ${@bb.utils.contains('DISTRO_FEATURES', 'pam', '--enable-pam', '--disable-pam', d)} \
+ --disable-manpages \
+ --disable-coredump \
+ --disable-introspection \
+ --disable-kdbus \
+ --enable-split-usr \
+ --without-python \
+ --with-sysvrcnd-path=${sysconfdir} \
+ --with-firmware-path=/lib/firmware \
+ ac_cv_path_KILL=${base_bindir}/kill \
+ "
+# uclibc does not have NSS
+EXTRA_OECONF_append_libc-uclibc = " --disable-myhostname "
+
+do_configure_prepend() {
+ export CPP="${HOST_PREFIX}cpp ${TOOLCHAIN_OPTIONS} ${HOST_CC_ARCH}"
+ export NM="${HOST_PREFIX}gcc-nm"
+ export AR="${HOST_PREFIX}gcc-ar"
+ export RANLIB="${HOST_PREFIX}gcc-ranlib"
+ export KMOD="${base_bindir}/kmod"
+ if [ -d ${S}/units.pre_sed ] ; then
+ cp -r ${S}/units.pre_sed ${S}/units
+ else
+ cp -r ${S}/units ${S}/units.pre_sed
+ fi
+ sed -i -e 's:=/root:=${ROOT_HOME}:g' ${S}/units/*.service*
+ sed -i '/ln --relative --help/d' ${S}/configure.ac
+ sed -i -e 's:\$(LN_S) --relative -f:lnr:g' ${S}/Makefile.am
+ sed -i -e 's:\$(LN_S) --relative:lnr:g' ${S}/Makefile.am
+}
+
+do_install() {
+ autotools_do_install
+ install -d ${D}/${base_sbindir}
+ # Provided by a separate recipe
+ rm ${D}${systemd_unitdir}/system/serial-getty* -f
+
+ # Provide support for initramfs
+ [ ! -e ${D}/init ] && ln -s ${rootlibexecdir}/systemd/systemd ${D}/init
+ [ ! -e ${D}/${base_sbindir}/udevd ] && ln -s ${rootlibexecdir}/systemd/systemd-udevd ${D}/${base_sbindir}/udevd
+
+ # Create machine-id
+ # 20:12 < mezcalero> koen: you have three options: a) run systemd-machine-id-setup at install time, b) have / read-only and an empty file there (for stateless) and c) boot with / writable
+ touch ${D}${sysconfdir}/machine-id
+
+ install -m 0644 ${WORKDIR}/*.rules ${D}${sysconfdir}/udev/rules.d/
+
+ install -m 0644 ${WORKDIR}/00-create-volatile.conf ${D}${sysconfdir}/tmpfiles.d/
+
+ if ${@bb.utils.contains('DISTRO_FEATURES','sysvinit','true','false',d)}; then
+ install -d ${D}${sysconfdir}/init.d
+ install -m 0755 ${WORKDIR}/init ${D}${sysconfdir}/init.d/systemd-udevd
+ sed -i s%@UDEVD@%${rootlibexecdir}/systemd/systemd-udevd% ${D}${sysconfdir}/init.d/systemd-udevd
+ fi
+
+ # Delete journal README, as log can be symlinked inside volatile.
+ rm -f ${D}/${localstatedir}/log/README
+}
+
+do_install_ptest () {
+ install -d ${D}${PTEST_PATH}/test
+ cp -rf ${S}/test/* ${D}${PTEST_PATH}/test
+ install -m 0755 ${B}/test-udev ${D}${PTEST_PATH}/
+ install -d ${D}${PTEST_PATH}/build-aux
+ cp ${S}/build-aux/test-driver ${D}${PTEST_PATH}/build-aux/
+ cp -rf ${B}/rules ${D}${PTEST_PATH}/
+ # This directory needs to be there for udev-test.pl to work.
+ install -d ${D}${libdir}/udev/rules.d
+ cp ${B}/Makefile ${D}${PTEST_PATH}/
+ cp ${S}/test/sys.tar.xz ${D}${PTEST_PATH}/test
+ sed -i 's/"tree"/"ls"/' ${D}${PTEST_PATH}/test/udev-test.pl
+ sed -i 's#${S}#${PTEST_PATH}#g' ${D}${PTEST_PATH}/Makefile
+ sed -i 's#${B}#${PTEST_PATH}#g' ${D}${PTEST_PATH}/Makefile
+}
+
+python populate_packages_prepend (){
+ systemdlibdir = d.getVar("rootlibdir", True)
+ do_split_packages(d, systemdlibdir, '^lib(.*)\.so\.*', 'lib%s', 'Systemd %s library', extra_depends='', allow_links=True)
+}
+PACKAGES_DYNAMIC += "^lib(udev|gudev|systemd).*"
+
+PACKAGES =+ "${PN}-gui ${PN}-vconsole-setup ${PN}-initramfs ${PN}-analyze ${PN}-kernel-install \
+ ${PN}-rpm-macros ${PN}-binfmt ${PN}-pam ${PN}-zsh"
+
+SYSTEMD_PACKAGES = "${PN}-binfmt"
+SYSTEMD_SERVICE_${PN}-binfmt = "systemd-binfmt.service"
+
+USERADD_PACKAGES = "${PN}"
+USERADD_PARAM_${PN} += "--system systemd-journal-gateway;--system systemd-timesync"
+GROUPADD_PARAM_${PN} = "-r lock; -r systemd-journal"
+
+FILES_${PN}-analyze = "${bindir}/systemd-analyze"
+
+FILES_${PN}-initramfs = "/init"
+RDEPENDS_${PN}-initramfs = "${PN}"
+
+# The test cases need perl and bash to run correctly.
+RDEPENDS_${PN}-ptest += "perl bash"
+FILES_${PN}-ptest += "${libdir}/udev/rules.d"
+
+FILES_${PN}-dbg += "${libdir}/systemd/ptest/.debug"
+
+FILES_${PN}-gui = "${bindir}/systemadm"
+
+FILES_${PN}-vconsole-setup = "${rootlibexecdir}/systemd/systemd-vconsole-setup \
+ ${systemd_unitdir}/system/systemd-vconsole-setup.service \
+ ${systemd_unitdir}/system/sysinit.target.wants/systemd-vconsole-setup.service"
+
+FILES_${PN}-kernel-install = "${bindir}/kernel-install \
+ ${sysconfdir}/kernel/ \
+ ${exec_prefix}/lib/kernel \
+ "
+FILES_${PN}-rpm-macros = "${exec_prefix}/lib/rpm \
+ "
+
+FILES_${PN}-zsh = "${datadir}/zsh/site-functions"
+
+FILES_${PN}-binfmt = "${sysconfdir}/binfmt.d/ \
+ ${exec_prefix}/lib/binfmt.d \
+ ${rootlibexecdir}/systemd/systemd-binfmt \
+ ${systemd_unitdir}/system/proc-sys-fs-binfmt_misc.* \
+ ${systemd_unitdir}/system/systemd-binfmt.service"
+RRECOMMENDS_${PN}-binfmt = "kernel-module-binfmt-misc"
+
+RRECOMMENDS_${PN}-vconsole-setup = "kbd kbd-consolefonts"
+
+CONFFILES_${PN} = "${sysconfdir}/systemd/journald.conf \
+ ${sysconfdir}/systemd/logind.conf \
+ ${sysconfdir}/systemd/system.conf \
+ ${sysconfdir}/systemd/user.conf"
+
+FILES_${PN} = " ${base_bindir}/* \
+ ${datadir}/bash-completion \
+ ${datadir}/dbus-1/services \
+ ${datadir}/dbus-1/system-services \
+ ${datadir}/polkit-1 \
+ ${datadir}/${BPN} \
+ ${sysconfdir}/bash_completion.d/ \
+ ${sysconfdir}/dbus-1/ \
+ ${sysconfdir}/machine-id \
+ ${sysconfdir}/modules-load.d/ \
+ ${sysconfdir}/sysctl.d/ \
+ ${sysconfdir}/systemd/ \
+ ${sysconfdir}/tmpfiles.d/ \
+ ${sysconfdir}/xdg/ \
+ ${sysconfdir}/init.d/README \
+ ${rootlibexecdir}/systemd/* \
+ ${systemd_unitdir}/* \
+ ${base_libdir}/security/*.so \
+ ${libdir}/libnss_myhostname.so.2 \
+ /cgroup \
+ ${bindir}/systemd* \
+ ${bindir}/busctl \
+ ${bindir}/localectl \
+ ${bindir}/hostnamectl \
+ ${bindir}/timedatectl \
+ ${bindir}/bootctl \
+ ${bindir}/kernel-install \
+ ${exec_prefix}/lib/tmpfiles.d/*.conf \
+ ${exec_prefix}/lib/systemd \
+ ${exec_prefix}/lib/modules-load.d \
+ ${exec_prefix}/lib/sysctl.d \
+ ${localstatedir} \
+ /lib/udev/rules.d/70-uaccess.rules \
+ /lib/udev/rules.d/71-seat.rules \
+ /lib/udev/rules.d/73-seat-late.rules \
+ /lib/udev/rules.d/99-systemd.rules \
+ ${@bb.utils.contains('DISTRO_FEATURES', 'pam', '${sysconfdir}/pam.d', '', d)} \
+ "
+
+FILES_${PN}-dbg += "${rootlibdir}/.debug ${systemd_unitdir}/.debug ${systemd_unitdir}/*/.debug ${base_libdir}/security/.debug/"
+FILES_${PN}-dev += "${base_libdir}/security/*.la ${datadir}/dbus-1/interfaces/ ${sysconfdir}/rpm/macros.systemd"
+
+RDEPENDS_${PN} += "kmod dbus util-linux-mount udev (= ${EXTENDPKGV})"
+
+RRECOMMENDS_${PN} += "systemd-serialgetty systemd-compat-units \
+ util-linux-agetty \
+ util-linux-fsck e2fsprogs-e2fsck \
+ kernel-module-autofs4 kernel-module-unix kernel-module-ipv6 \
+"
+
+PACKAGES =+ "udev-dbg udev udev-hwdb"
+
+FILES_udev-dbg += "/lib/udev/.debug"
+
+RPROVIDES_udev = "hotplug"
+RRECOMMENDS_udev += "udev-hwdb"
+
+FILES_udev += "${base_sbindir}/udevd \
+ ${rootlibexecdir}/systemd/systemd-udevd \
+ ${rootlibexecdir}/udev/accelerometer \
+ ${rootlibexecdir}/udev/ata_id \
+ ${rootlibexecdir}/udev/cdrom_id \
+ ${rootlibexecdir}/udev/collect \
+ ${rootlibexecdir}/udev/findkeyboards \
+ ${rootlibexecdir}/udev/keyboard-force-release.sh \
+ ${rootlibexecdir}/udev/keymap \
+ ${rootlibexecdir}/udev/mtd_probe \
+ ${rootlibexecdir}/udev/scsi_id \
+ ${rootlibexecdir}/udev/v4l_id \
+ ${rootlibexecdir}/udev/keymaps \
+ ${rootlibexecdir}/udev/rules.d/4*.rules \
+ ${rootlibexecdir}/udev/rules.d/5*.rules \
+ ${rootlibexecdir}/udev/rules.d/6*.rules \
+ ${rootlibexecdir}/udev/rules.d/70-power-switch.rules \
+ ${rootlibexecdir}/udev/rules.d/75*.rules \
+ ${rootlibexecdir}/udev/rules.d/78*.rules \
+ ${rootlibexecdir}/udev/rules.d/8*.rules \
+ ${rootlibexecdir}/udev/rules.d/95*.rules \
+ ${sysconfdir}/udev \
+ ${sysconfdir}/init.d/systemd-udevd \
+ ${systemd_unitdir}/system/*udev* \
+ ${systemd_unitdir}/system/*.wants/*udev* \
+ ${base_bindir}/udevadm \
+ ${datadir}/bash-completion/completions/udevadm \
+ "
+
+FILES_udev-hwdb = "${rootlibexecdir}/udev/hwdb.d"
+
+INITSCRIPT_PACKAGES = "udev"
+INITSCRIPT_NAME_udev = "systemd-udevd"
+INITSCRIPT_PARAMS_udev = "start 03 S ."
+
+python __anonymous() {
+ if not bb.utils.contains('DISTRO_FEATURES', 'sysvinit', True, False, d):
+ d.setVar("INHIBIT_UPDATERCD_BBCLASS", "1")
+}
+
+# TODO:
+# u-a for runlevel and telinit
+
+ALTERNATIVE_${PN} = "init halt reboot shutdown poweroff runlevel"
+
+ALTERNATIVE_TARGET[init] = "${rootlibexecdir}/systemd/systemd"
+ALTERNATIVE_LINK_NAME[init] = "${base_sbindir}/init"
+ALTERNATIVE_PRIORITY[init] ?= "300"
+
+ALTERNATIVE_TARGET[halt] = "${base_bindir}/systemctl"
+ALTERNATIVE_LINK_NAME[halt] = "${base_sbindir}/halt"
+ALTERNATIVE_PRIORITY[halt] ?= "300"
+
+ALTERNATIVE_TARGET[reboot] = "${base_bindir}/systemctl"
+ALTERNATIVE_LINK_NAME[reboot] = "${base_sbindir}/reboot"
+ALTERNATIVE_PRIORITY[reboot] ?= "300"
+
+ALTERNATIVE_TARGET[shutdown] = "${base_bindir}/systemctl"
+ALTERNATIVE_LINK_NAME[shutdown] = "${base_sbindir}/shutdown"
+ALTERNATIVE_PRIORITY[shutdown] ?= "300"
+
+ALTERNATIVE_TARGET[poweroff] = "${base_bindir}/systemctl"
+ALTERNATIVE_LINK_NAME[poweroff] = "${base_sbindir}/poweroff"
+ALTERNATIVE_PRIORITY[poweroff] ?= "300"
+
+ALTERNATIVE_TARGET[runlevel] = "${base_bindir}/systemctl"
+ALTERNATIVE_LINK_NAME[runlevel] = "${base_sbindir}/runlevel"
+ALTERNATIVE_PRIORITY[runlevel] ?= "300"
+
+pkg_postinst_udev-hwdb () {
+ if test -n "$D"; then
+ ${@qemu_run_binary(d, '$D', '${base_bindir}/udevadm')} hwdb --update \
+ --root $D
+ else
+ udevadm hwdb --update
+ fi
+}
+
+pkg_prerm_udev-hwdb () {
+ if test -n "$D"; then
+ exit 1
+ fi
+
+ rm -f ${sysconfdir}/udev/hwdb.bin
+}
+
+# As this recipe builds udev, respect systemd being in DISTRO_FEATURES so
+# that we don't build both udev and systemd in world builds.
+python () {
+ if not bb.utils.contains ('DISTRO_FEATURES', 'systemd', True, False, d):
+ raise bb.parse.SkipPackage("'systemd' not in DISTRO_FEATURES")
+}
diff --git a/meta-edison-distro/recipes-devtools/e2fsprogs/e2fsprogs_%.bbappend b/meta-edison-distro/recipes-devtools/e2fsprogs/e2fsprogs_%.bbappend
new file mode 100644
index 0000000..01a6d33
--- /dev/null
+++ b/meta-edison-distro/recipes-devtools/e2fsprogs/e2fsprogs_%.bbappend
@@ -0,0 +1,11 @@
+# Add resize2fs tool
+
+
+EXTRA_OECONF += "\
+ --enable-resizer \
+"
+
+PACKAGES =+ "e2fsprogs-resize2fs"
+
+FILES_e2fsprogs-resize2fs = "${base_sbindir}/resize2fs"
+
diff --git a/meta-edison-distro/recipes-devtools/swig/swig.inc b/meta-edison-distro/recipes-devtools/swig/swig.inc
new file mode 100644
index 0000000..5571a55
--- /dev/null
+++ b/meta-edison-distro/recipes-devtools/swig/swig.inc
@@ -0,0 +1,63 @@
+DESCRIPTION = "SWIG - Simplified Wrapper and Interface Generator"
+HOMEPAGE = "http://swig.sourceforge.net/"
+LICENSE = "BSD & GPLv3"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=e7807a6282784a7dde4c846626b08fc6 \
+ file://LICENSE-GPL;md5=d32239bcb673463ab874e80d47fae504 \
+ file://LICENSE-UNIVERSITIES;md5=8ce9dcc8f7c994de4a408b205c72ba08"
+
+SECTION = "devel"
+
+DEPENDS = "libpcre python"
+
+SRC_URI = "${SOURCEFORGE_MIRROR}/${BPN}/${BPN}-${PV}.tar.gz"
+
+inherit autotools pythonnative
+
+EXTRA_OECONF = " \
+ --with-python=${PYTHON} \
+ --without-allegrocl \
+ --without-android \
+ --without-boost \
+ --without-chicken \
+ --without-clisp \
+ --without-csharp \
+ --without-d \
+ --without-gcj \
+ --without-go \
+ --without-guile \
+ --without-java \
+ --without-lua \
+ --without-mzscheme \
+ --without-ocaml \
+ --without-octave \
+ --without-perl5 \
+ --without-pike \
+ --without-php \
+ --without-python3 \
+ --without-r \
+ --without-ruby \
+ --without-tcl \
+"
+
+BBCLASSEXTEND = "native nativesdk"
+
+do_configure() {
+ install -m 0755 ${STAGING_DATADIR_NATIVE}/gnu-config/config.guess ${S}/Tools/config
+ install -m 0755 ${STAGING_DATADIR_NATIVE}/gnu-config/config.sub ${S}/Tools/config
+ install -m 0755 ${STAGING_DATADIR_NATIVE}/gnu-config/config.guess ${S}
+ install -m 0755 ${STAGING_DATADIR_NATIVE}/gnu-config/config.sub ${S}
+ oe_runconf
+}
+
+do_install_append_class-nativesdk() {
+ cd ${D}${bindir}
+ ln -s swig swig2.0
+}
+
+def swiglib_relpath(d):
+ swiglib = d.getVar('datadir', True) + "/" + d.getVar('BPN', True) + "/" + d.getVar('PV', True)
+ return os.path.relpath(swiglib, d.getVar('bindir', True))
+
+do_install_append_class-native() {
+ create_wrapper ${D}${bindir}/swig SWIG_LIB='`dirname $''realpath`'/${@swiglib_relpath(d)}
+} \ No newline at end of file
diff --git a/meta-edison-distro/recipes-devtools/swig/swig/0001-Use-proc-self-exe-for-swig-swiglib-on-non-Win32-plat.patch b/meta-edison-distro/recipes-devtools/swig/swig/0001-Use-proc-self-exe-for-swig-swiglib-on-non-Win32-plat.patch
new file mode 100644
index 0000000..4115469
--- /dev/null
+++ b/meta-edison-distro/recipes-devtools/swig/swig/0001-Use-proc-self-exe-for-swig-swiglib-on-non-Win32-plat.patch
@@ -0,0 +1,56 @@
+---
+ Source/Modules/main.cxx | 24 ++++++++++++++++++++++--
+ 1 file changed, 22 insertions(+), 2 deletions(-)
+
+diff --git a/Source/Modules/main.cxx b/Source/Modules/main.cxx
+index d2f5d3b..cbb0a12 100644
+--- a/Source/Modules/main.cxx
++++ b/Source/Modules/main.cxx
+@@ -26,6 +26,11 @@ char cvsroot_main_cxx[] = "$Id$";
+ #include "cparse.h"
+ #include <ctype.h>
+ #include <limits.h> // for INT_MAX
++#ifndef _WIN32
++#include <cstddef>
++#include <unistd.h> // for readlink
++#include <sys/stat.h> // for stat
++#endif
+
+ // Global variables
+
+@@ -902,9 +907,9 @@ int SWIG_main(int argc, char *argv[], Language *l) {
+
+ // Check for SWIG_LIB environment variable
+ if ((c = getenv("SWIG_LIB")) == (char *) 0) {
++ char *p;
+ #if defined(_WIN32)
+ char buf[MAX_PATH];
+- char *p;
+ if (!(GetModuleFileName(0, buf, MAX_PATH) == 0 || (p = strrchr(buf, '\\')) == 0)) {
+ *(p + 1) = '\0';
+ SwigLib = NewStringf("%sLib", buf); // Native windows installation path
+@@ -914,7 +919,22 @@ int SWIG_main(int argc, char *argv[], Language *l) {
+ if (Len(SWIG_LIB_WIN_UNIX) > 0)
+ SwigLibWinUnix = NewString(SWIG_LIB_WIN_UNIX); // Unix installation path using a drive letter (for msys/mingw)
+ #else
+- SwigLib = NewString(SWIG_LIB);
++ char buf[PATH_MAX];
++ if (0 < ::readlink("/proc/self/exe", buf, sizeof(buf)) &&
++ (p = ::strstr(buf, "/bin/swig"))) {
++ int major, minor, patch;
++ const int ret = ::sscanf(VERSION, "%d.%d.%d", &major, &minor, &patch);
++ if (3 == ret) {
++ const ::ptrdiff_t dir_part_len = p - buf;
++ ::snprintf(p, PATH_MAX - dir_part_len, "/share/swig/%d.%d.%d", major, minor, patch);
++ struct ::stat stat_res;
++ if (0 == ::stat(buf, &stat_res) && S_ISDIR(stat_res.st_mode)) {
++ SwigLib = NewString(buf);
++ }
++ }
++ }
++ if (NULL == SwigLib)
++ SwigLib = NewString(SWIG_LIB);
+ #endif
+ } else {
+ SwigLib = NewString(c);
+--
diff --git a/meta-edison-distro/recipes-devtools/swig/swig/0001-configure-use-pkg-config-for-pcre-detection.patch b/meta-edison-distro/recipes-devtools/swig/swig/0001-configure-use-pkg-config-for-pcre-detection.patch
new file mode 100644
index 0000000..5a05d7b
--- /dev/null
+++ b/meta-edison-distro/recipes-devtools/swig/swig/0001-configure-use-pkg-config-for-pcre-detection.patch
@@ -0,0 +1,55 @@
+---
+ configure.ac | 38 +++++++-------------------------------
+ 1 file changed, 7 insertions(+), 31 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 0c984b7..6edcec1 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -70,38 +70,14 @@ AC_MSG_RESULT([$with_pcre])
+
+ dnl To make configuring easier, check for a locally built PCRE using the Tools/pcre-build.sh script
+ if test x"${with_pcre}" = xyes ; then
+- AC_MSG_CHECKING([whether to use local PCRE])
+- local_pcre_config=no
+- if test -z $PCRE_CONFIG; then
+- if test -f `pwd`/pcre/pcre-swig-install/bin/pcre-config; then
+- PCRE_CONFIG=`pwd`/pcre/pcre-swig-install/bin/pcre-config
+- local_pcre_config=$PCRE_CONFIG
+- fi
+- fi
+- AC_MSG_RESULT([$local_pcre_config])
+-fi
+-AS_IF([test "x$with_pcre" != xno],
+- [AX_PATH_GENERIC([pcre],
+- [], dnl Minimal version of PCRE we need -- accept any
+- [], dnl custom sed script for version parsing is not needed
+- [AC_DEFINE([HAVE_PCRE], [1], [Define if you have PCRE library])
+- LIBS="$LIBS $PCRE_LIBS"
+- CPPFLAGS="$CPPFLAGS $PCRE_CFLAGS"
+- ],
+- [AC_MSG_FAILURE([
+- Cannot find pcre-config script from PCRE (Perl Compatible Regular Expressions)
+- library package. This dependency is needed for configure to complete,
+- Either:
+- - Install the PCRE developer package on your system (preferred approach).
+- - Download the PCRE source tarball, build and install on your system
+- as you would for any package built from source distribution.
+- - Use the Tools/pcre-build.sh script to build PCRE just for SWIG to statically
+- link against. Run 'Tools/pcre-build.sh --help' for instructions.
+- (quite easy and does not require privileges to install PCRE on your system)
+- - Use configure --without-pcre to disable regular expressions support in SWIG
+- (not recommended).])
+- ])
++ PKG_CHECK_MODULES([PCRE], [libpcre], [
++ AC_DEFINE([HAVE_PCRE], [1], [Define if you have PCRE library])
++ LIBS="$LIBS $PCRE_LIBS"
++ CPPFLAGS="$CPPFLAGS $PCRE_CFLAGS"
++ ], [
++ AC_MSG_WARN([$PCRE_PKG_ERRORS])
+ ])
++fi
+
+
+ dnl CCache
+--
diff --git a/meta-edison-distro/recipes-devtools/swig/swig_3.0.2.bb b/meta-edison-distro/recipes-devtools/swig/swig_3.0.2.bb
new file mode 100644
index 0000000..ac41914
--- /dev/null
+++ b/meta-edison-distro/recipes-devtools/swig/swig_3.0.2.bb
@@ -0,0 +1,8 @@
+require ${BPN}.inc
+
+SRC_URI += "file://0001-Use-proc-self-exe-for-swig-swiglib-on-non-Win32-plat.patch \
+ file://0001-configure-use-pkg-config-for-pcre-detection.patch \
+ "
+
+SRC_URI[md5sum] = "62f9b0d010cef36a13a010dc530d0d41"
+SRC_URI[sha256sum] = "a2669657cabcedc371f63c0457407a183e0b6b2ef4e7e303c1ec9a3964cc7813"
diff --git a/meta-edison-distro/recipes-multimedia/alsa/alsa-utils_%.bbappend b/meta-edison-distro/recipes-multimedia/alsa/alsa-utils_%.bbappend
new file mode 100644
index 0000000..ae82a2b
--- /dev/null
+++ b/meta-edison-distro/recipes-multimedia/alsa/alsa-utils_%.bbappend
@@ -0,0 +1,13 @@
+# Provide default alsa configuration for Edison
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/files/"
+
+SRC_URI += "\
+ file://asound.state \
+"
+
+do_install_append() {
+ install -v -d ${D}/var/lib/alsa/
+ install -m 644 ${WORKDIR}/asound.state ${D}/var/lib/alsa/
+}
+
diff --git a/meta-edison-distro/recipes-multimedia/alsa/files/asound.state b/meta-edison-distro/recipes-multimedia/alsa/files/asound.state
new file mode 100644
index 0000000..18aa6e2
--- /dev/null
+++ b/meta-edison-distro/recipes-multimedia/alsa/files/asound.state
@@ -0,0 +1,14141 @@
+state.wm8958audio {
+ control.1 {
+ iface MIXER
+ name 'ssp1_out mux 0'
+ value fm
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 fm
+ item.1 bt
+ }
+ }
+ control.2 {
+ iface MIXER
+ name 'aware_out aware 0 switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.3 {
+ iface MIXER
+ name 'modem_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.4 {
+ iface MIXER
+ name 'modem_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.5 {
+ iface MIXER
+ name 'modem_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.6 {
+ iface MIXER
+ name 'modem_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.7 {
+ iface MIXER
+ name 'modem_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.8 {
+ iface MIXER
+ name 'modem_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.9 {
+ iface MIXER
+ name 'modem_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.10 {
+ iface MIXER
+ name 'modem_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.11 {
+ iface MIXER
+ name 'modem_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.12 {
+ iface MIXER
+ name 'modem_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.13 {
+ iface MIXER
+ name 'modem_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.14 {
+ iface MIXER
+ name 'modem_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.15 {
+ iface MIXER
+ name 'modem_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.16 {
+ iface MIXER
+ name 'modem_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.17 {
+ iface MIXER
+ name 'modem_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.18 {
+ iface MIXER
+ name 'modem_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.19 {
+ iface MIXER
+ name 'fm_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.20 {
+ iface MIXER
+ name 'fm_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.21 {
+ iface MIXER
+ name 'fm_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.22 {
+ iface MIXER
+ name 'fm_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.23 {
+ iface MIXER
+ name 'fm_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.24 {
+ iface MIXER
+ name 'fm_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.25 {
+ iface MIXER
+ name 'fm_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.26 {
+ iface MIXER
+ name 'fm_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.27 {
+ iface MIXER
+ name 'fm_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.28 {
+ iface MIXER
+ name 'fm_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.29 {
+ iface MIXER
+ name 'fm_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.30 {
+ iface MIXER
+ name 'fm_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.31 {
+ iface MIXER
+ name 'fm_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.32 {
+ iface MIXER
+ name 'fm_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.33 {
+ iface MIXER
+ name 'fm_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.34 {
+ iface MIXER
+ name 'fm_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.35 {
+ iface MIXER
+ name 'bt_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.36 {
+ iface MIXER
+ name 'bt_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.37 {
+ iface MIXER
+ name 'bt_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.38 {
+ iface MIXER
+ name 'bt_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.39 {
+ iface MIXER
+ name 'bt_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.40 {
+ iface MIXER
+ name 'bt_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.41 {
+ iface MIXER
+ name 'bt_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.42 {
+ iface MIXER
+ name 'bt_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.43 {
+ iface MIXER
+ name 'bt_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.44 {
+ iface MIXER
+ name 'bt_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.45 {
+ iface MIXER
+ name 'bt_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.46 {
+ iface MIXER
+ name 'bt_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.47 {
+ iface MIXER
+ name 'bt_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.48 {
+ iface MIXER
+ name 'bt_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.49 {
+ iface MIXER
+ name 'bt_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.50 {
+ iface MIXER
+ name 'bt_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.51 {
+ iface MIXER
+ name 'codec_out1 mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.52 {
+ iface MIXER
+ name 'codec_out1 mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.53 {
+ iface MIXER
+ name 'codec_out1 mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.54 {
+ iface MIXER
+ name 'codec_out1 mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.55 {
+ iface MIXER
+ name 'codec_out1 mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.56 {
+ iface MIXER
+ name 'codec_out1 mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.57 {
+ iface MIXER
+ name 'codec_out1 mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.58 {
+ iface MIXER
+ name 'codec_out1 mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.59 {
+ iface MIXER
+ name 'codec_out1 mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.60 {
+ iface MIXER
+ name 'codec_out1 mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.61 {
+ iface MIXER
+ name 'codec_out1 mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.62 {
+ iface MIXER
+ name 'codec_out1 mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.63 {
+ iface MIXER
+ name 'codec_out1 mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.64 {
+ iface MIXER
+ name 'codec_out1 mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.65 {
+ iface MIXER
+ name 'codec_out1 mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.66 {
+ iface MIXER
+ name 'codec_out1 mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.67 {
+ iface MIXER
+ name 'codec_out0 mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.68 {
+ iface MIXER
+ name 'codec_out0 mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.69 {
+ iface MIXER
+ name 'codec_out0 mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.70 {
+ iface MIXER
+ name 'codec_out0 mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.71 {
+ iface MIXER
+ name 'codec_out0 mix 0 sprot_loop_in'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.72 {
+ iface MIXER
+ name 'codec_out0 mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.73 {
+ iface MIXER
+ name 'codec_out0 mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.74 {
+ iface MIXER
+ name 'codec_out0 mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.75 {
+ iface MIXER
+ name 'codec_out0 mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.76 {
+ iface MIXER
+ name 'codec_out0 mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.77 {
+ iface MIXER
+ name 'codec_out0 mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.78 {
+ iface MIXER
+ name 'codec_out0 mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.79 {
+ iface MIXER
+ name 'codec_out0 mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.80 {
+ iface MIXER
+ name 'codec_out0 mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.81 {
+ iface MIXER
+ name 'codec_out0 mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.82 {
+ iface MIXER
+ name 'codec_out0 mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.83 {
+ iface MIXER
+ name 'rxspeech_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.84 {
+ iface MIXER
+ name 'rxspeech_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.85 {
+ iface MIXER
+ name 'rxspeech_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.86 {
+ iface MIXER
+ name 'rxspeech_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.87 {
+ iface MIXER
+ name 'rxspeech_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.88 {
+ iface MIXER
+ name 'rxspeech_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.89 {
+ iface MIXER
+ name 'rxspeech_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.90 {
+ iface MIXER
+ name 'rxspeech_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.91 {
+ iface MIXER
+ name 'rxspeech_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.92 {
+ iface MIXER
+ name 'rxspeech_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.93 {
+ iface MIXER
+ name 'rxspeech_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.94 {
+ iface MIXER
+ name 'rxspeech_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.95 {
+ iface MIXER
+ name 'rxspeech_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.96 {
+ iface MIXER
+ name 'rxspeech_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.97 {
+ iface MIXER
+ name 'rxspeech_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.98 {
+ iface MIXER
+ name 'rxspeech_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.99 {
+ iface MIXER
+ name 'speech_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.100 {
+ iface MIXER
+ name 'speech_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.101 {
+ iface MIXER
+ name 'speech_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.102 {
+ iface MIXER
+ name 'speech_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.103 {
+ iface MIXER
+ name 'speech_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.104 {
+ iface MIXER
+ name 'speech_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.105 {
+ iface MIXER
+ name 'speech_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.106 {
+ iface MIXER
+ name 'speech_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.107 {
+ iface MIXER
+ name 'speech_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.108 {
+ iface MIXER
+ name 'speech_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.109 {
+ iface MIXER
+ name 'speech_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.110 {
+ iface MIXER
+ name 'speech_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.111 {
+ iface MIXER
+ name 'speech_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.112 {
+ iface MIXER
+ name 'speech_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.113 {
+ iface MIXER
+ name 'speech_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.114 {
+ iface MIXER
+ name 'speech_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.115 {
+ iface MIXER
+ name 'hf_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.116 {
+ iface MIXER
+ name 'hf_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.117 {
+ iface MIXER
+ name 'hf_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.118 {
+ iface MIXER
+ name 'hf_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.119 {
+ iface MIXER
+ name 'hf_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.120 {
+ iface MIXER
+ name 'hf_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.121 {
+ iface MIXER
+ name 'hf_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.122 {
+ iface MIXER
+ name 'hf_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.123 {
+ iface MIXER
+ name 'hf_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.124 {
+ iface MIXER
+ name 'hf_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.125 {
+ iface MIXER
+ name 'hf_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.126 {
+ iface MIXER
+ name 'hf_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.127 {
+ iface MIXER
+ name 'hf_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.128 {
+ iface MIXER
+ name 'hf_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.129 {
+ iface MIXER
+ name 'hf_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.130 {
+ iface MIXER
+ name 'hf_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.131 {
+ iface MIXER
+ name 'hf_sns_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.132 {
+ iface MIXER
+ name 'hf_sns_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.133 {
+ iface MIXER
+ name 'hf_sns_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.134 {
+ iface MIXER
+ name 'hf_sns_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.135 {
+ iface MIXER
+ name 'hf_sns_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.136 {
+ iface MIXER
+ name 'hf_sns_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.137 {
+ iface MIXER
+ name 'hf_sns_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.138 {
+ iface MIXER
+ name 'hf_sns_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.139 {
+ iface MIXER
+ name 'hf_sns_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.140 {
+ iface MIXER
+ name 'hf_sns_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.141 {
+ iface MIXER
+ name 'hf_sns_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.142 {
+ iface MIXER
+ name 'hf_sns_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.143 {
+ iface MIXER
+ name 'hf_sns_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.144 {
+ iface MIXER
+ name 'hf_sns_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.145 {
+ iface MIXER
+ name 'hf_sns_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.146 {
+ iface MIXER
+ name 'hf_sns_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.147 {
+ iface MIXER
+ name 'vad_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.148 {
+ iface MIXER
+ name 'vad_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.149 {
+ iface MIXER
+ name 'vad_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.150 {
+ iface MIXER
+ name 'vad_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.151 {
+ iface MIXER
+ name 'vad_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.152 {
+ iface MIXER
+ name 'vad_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.153 {
+ iface MIXER
+ name 'vad_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.154 {
+ iface MIXER
+ name 'vad_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.155 {
+ iface MIXER
+ name 'vad_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.156 {
+ iface MIXER
+ name 'vad_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.157 {
+ iface MIXER
+ name 'vad_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.158 {
+ iface MIXER
+ name 'vad_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.159 {
+ iface MIXER
+ name 'vad_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.160 {
+ iface MIXER
+ name 'vad_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.161 {
+ iface MIXER
+ name 'vad_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.162 {
+ iface MIXER
+ name 'vad_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.163 {
+ iface MIXER
+ name 'aware_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.164 {
+ iface MIXER
+ name 'aware_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.165 {
+ iface MIXER
+ name 'aware_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.166 {
+ iface MIXER
+ name 'aware_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.167 {
+ iface MIXER
+ name 'aware_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.168 {
+ iface MIXER
+ name 'aware_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.169 {
+ iface MIXER
+ name 'aware_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.170 {
+ iface MIXER
+ name 'aware_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.171 {
+ iface MIXER
+ name 'aware_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.172 {
+ iface MIXER
+ name 'aware_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.173 {
+ iface MIXER
+ name 'aware_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.174 {
+ iface MIXER
+ name 'aware_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.175 {
+ iface MIXER
+ name 'aware_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.176 {
+ iface MIXER
+ name 'aware_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.177 {
+ iface MIXER
+ name 'aware_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.178 {
+ iface MIXER
+ name 'aware_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.179 {
+ iface MIXER
+ name 'voip_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.180 {
+ iface MIXER
+ name 'voip_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.181 {
+ iface MIXER
+ name 'voip_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.182 {
+ iface MIXER
+ name 'voip_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.183 {
+ iface MIXER
+ name 'voip_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.184 {
+ iface MIXER
+ name 'voip_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.185 {
+ iface MIXER
+ name 'voip_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.186 {
+ iface MIXER
+ name 'voip_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.187 {
+ iface MIXER
+ name 'voip_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.188 {
+ iface MIXER
+ name 'voip_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.189 {
+ iface MIXER
+ name 'voip_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.190 {
+ iface MIXER
+ name 'voip_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.191 {
+ iface MIXER
+ name 'voip_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.192 {
+ iface MIXER
+ name 'voip_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.193 {
+ iface MIXER
+ name 'voip_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.194 {
+ iface MIXER
+ name 'voip_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.195 {
+ iface MIXER
+ name 'media_loop2_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.196 {
+ iface MIXER
+ name 'media_loop2_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.197 {
+ iface MIXER
+ name 'media_loop2_out mix 0 codec_in0'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.198 {
+ iface MIXER
+ name 'media_loop2_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.199 {
+ iface MIXER
+ name 'media_loop2_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.200 {
+ iface MIXER
+ name 'media_loop2_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.201 {
+ iface MIXER
+ name 'media_loop2_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.202 {
+ iface MIXER
+ name 'media_loop2_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.203 {
+ iface MIXER
+ name 'media_loop2_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.204 {
+ iface MIXER
+ name 'media_loop2_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.205 {
+ iface MIXER
+ name 'media_loop2_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.206 {
+ iface MIXER
+ name 'media_loop2_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.207 {
+ iface MIXER
+ name 'media_loop2_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.208 {
+ iface MIXER
+ name 'media_loop2_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.209 {
+ iface MIXER
+ name 'media_loop2_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.210 {
+ iface MIXER
+ name 'media_loop2_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.211 {
+ iface MIXER
+ name 'media_loop1_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.212 {
+ iface MIXER
+ name 'media_loop1_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.213 {
+ iface MIXER
+ name 'media_loop1_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.214 {
+ iface MIXER
+ name 'media_loop1_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.215 {
+ iface MIXER
+ name 'media_loop1_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.216 {
+ iface MIXER
+ name 'media_loop1_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.217 {
+ iface MIXER
+ name 'media_loop1_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.218 {
+ iface MIXER
+ name 'media_loop1_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.219 {
+ iface MIXER
+ name 'media_loop1_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.220 {
+ iface MIXER
+ name 'media_loop1_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.221 {
+ iface MIXER
+ name 'media_loop1_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.222 {
+ iface MIXER
+ name 'media_loop1_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.223 {
+ iface MIXER
+ name 'media_loop1_out mix 0 pcm0_in'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.224 {
+ iface MIXER
+ name 'media_loop1_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.225 {
+ iface MIXER
+ name 'media_loop1_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.226 {
+ iface MIXER
+ name 'media_loop1_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.227 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.228 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.229 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.230 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.231 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.232 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 media_loop1_in'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.233 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.234 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.235 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.236 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.237 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.238 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.239 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.240 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.241 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.242 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.243 {
+ iface MIXER
+ name 'pcm2_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.244 {
+ iface MIXER
+ name 'pcm2_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.245 {
+ iface MIXER
+ name 'pcm2_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.246 {
+ iface MIXER
+ name 'pcm2_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.247 {
+ iface MIXER
+ name 'pcm2_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.248 {
+ iface MIXER
+ name 'pcm2_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.249 {
+ iface MIXER
+ name 'pcm2_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.250 {
+ iface MIXER
+ name 'pcm2_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.251 {
+ iface MIXER
+ name 'pcm2_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.252 {
+ iface MIXER
+ name 'pcm2_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.253 {
+ iface MIXER
+ name 'pcm2_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.254 {
+ iface MIXER
+ name 'pcm2_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.255 {
+ iface MIXER
+ name 'pcm2_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.256 {
+ iface MIXER
+ name 'pcm2_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.257 {
+ iface MIXER
+ name 'pcm2_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.258 {
+ iface MIXER
+ name 'pcm2_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.259 {
+ iface MIXER
+ name 'pcm1_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.260 {
+ iface MIXER
+ name 'pcm1_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.261 {
+ iface MIXER
+ name 'pcm1_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.262 {
+ iface MIXER
+ name 'pcm1_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.263 {
+ iface MIXER
+ name 'pcm1_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.264 {
+ iface MIXER
+ name 'pcm1_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.265 {
+ iface MIXER
+ name 'pcm1_out mix 0 media_loop2_in'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.266 {
+ iface MIXER
+ name 'pcm1_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.267 {
+ iface MIXER
+ name 'pcm1_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.268 {
+ iface MIXER
+ name 'pcm1_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.269 {
+ iface MIXER
+ name 'pcm1_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.270 {
+ iface MIXER
+ name 'pcm1_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.271 {
+ iface MIXER
+ name 'pcm1_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.272 {
+ iface MIXER
+ name 'pcm1_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.273 {
+ iface MIXER
+ name 'pcm1_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.274 {
+ iface MIXER
+ name 'pcm1_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.275 {
+ iface MIXER
+ name 'pcm0_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.276 {
+ iface MIXER
+ name 'pcm0_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.277 {
+ iface MIXER
+ name 'pcm0_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.278 {
+ iface MIXER
+ name 'pcm0_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.279 {
+ iface MIXER
+ name 'pcm0_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.280 {
+ iface MIXER
+ name 'pcm0_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.281 {
+ iface MIXER
+ name 'pcm0_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.282 {
+ iface MIXER
+ name 'pcm0_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.283 {
+ iface MIXER
+ name 'pcm0_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.284 {
+ iface MIXER
+ name 'pcm0_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.285 {
+ iface MIXER
+ name 'pcm0_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.286 {
+ iface MIXER
+ name 'pcm0_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.287 {
+ iface MIXER
+ name 'pcm0_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.288 {
+ iface MIXER
+ name 'pcm0_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.289 {
+ iface MIXER
+ name 'pcm0_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.290 {
+ iface MIXER
+ name 'pcm0_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.291 {
+ iface MIXER
+ name 'media1_out mix 0 media0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.292 {
+ iface MIXER
+ name 'media1_out mix 0 media1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.293 {
+ iface MIXER
+ name 'media1_out mix 0 media2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.294 {
+ iface MIXER
+ name 'media1_out mix 0 media3_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.295 {
+ iface MIXER
+ name 'media0_out mix 0 media0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.296 {
+ iface MIXER
+ name 'media0_out mix 0 media1_in'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.297 {
+ iface MIXER
+ name 'media0_out mix 0 media2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.298 {
+ iface MIXER
+ name 'media0_out mix 0 media3_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.299 {
+ iface MIXER
+ name 'media0_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.300 {
+ iface MIXER
+ name 'media0_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.301 {
+ iface MIXER
+ name 'media0_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.302 {
+ iface MIXER
+ name 'media1_in gain 0 rampduration'
+ value 50
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.303 {
+ iface MIXER
+ name 'media1_in gain 0 mute'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.304 {
+ iface MIXER
+ name 'media1_in gain 0 volume'
+ value.0 0
+ value.1 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.305 {
+ iface MIXER
+ name 'media2_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.306 {
+ iface MIXER
+ name 'media2_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.307 {
+ iface MIXER
+ name 'media2_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.308 {
+ iface MIXER
+ name 'media3_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.309 {
+ iface MIXER
+ name 'media3_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.310 {
+ iface MIXER
+ name 'media3_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.311 {
+ iface MIXER
+ name 'pcm0_in gain 0 rampduration'
+ value 50
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.312 {
+ iface MIXER
+ name 'pcm0_in gain 0 mute'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.313 {
+ iface MIXER
+ name 'pcm0_in gain 0 volume'
+ value.0 0
+ value.1 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.314 {
+ iface MIXER
+ name 'pcm1_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.315 {
+ iface MIXER
+ name 'pcm1_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.316 {
+ iface MIXER
+ name 'pcm1_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.317 {
+ iface MIXER
+ name 'low_pcm0_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.318 {
+ iface MIXER
+ name 'low_pcm0_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.319 {
+ iface MIXER
+ name 'low_pcm0_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.320 {
+ iface MIXER
+ name 'pcm1_out gain 0 rampduration'
+ value 50
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.321 {
+ iface MIXER
+ name 'pcm1_out gain 0 mute'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.322 {
+ iface MIXER
+ name 'pcm1_out gain 0 volume'
+ value.0 0
+ value.1 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.323 {
+ iface MIXER
+ name 'pcm2_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.324 {
+ iface MIXER
+ name 'pcm2_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.325 {
+ iface MIXER
+ name 'pcm2_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.326 {
+ iface MIXER
+ name 'voip_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.327 {
+ iface MIXER
+ name 'voip_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.328 {
+ iface MIXER
+ name 'voip_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.329 {
+ iface MIXER
+ name 'voip_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.330 {
+ iface MIXER
+ name 'voip_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.331 {
+ iface MIXER
+ name 'voip_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.332 {
+ iface MIXER
+ name 'tone_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.333 {
+ iface MIXER
+ name 'tone_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.334 {
+ iface MIXER
+ name 'tone_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.335 {
+ iface MIXER
+ name 'aware_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.336 {
+ iface MIXER
+ name 'aware_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.337 {
+ iface MIXER
+ name 'aware_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.338 {
+ iface MIXER
+ name 'vad_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.339 {
+ iface MIXER
+ name 'vad_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.340 {
+ iface MIXER
+ name 'vad_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.341 {
+ iface MIXER
+ name 'hf_sns_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.342 {
+ iface MIXER
+ name 'hf_sns_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.343 {
+ iface MIXER
+ name 'hf_sns_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.344 {
+ iface MIXER
+ name 'hf_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.345 {
+ iface MIXER
+ name 'hf_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.346 {
+ iface MIXER
+ name 'hf_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.347 {
+ iface MIXER
+ name 'speech_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.348 {
+ iface MIXER
+ name 'speech_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.349 {
+ iface MIXER
+ name 'speech_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.350 {
+ iface MIXER
+ name 'txspeech_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.351 {
+ iface MIXER
+ name 'txspeech_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.352 {
+ iface MIXER
+ name 'txspeech_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.353 {
+ iface MIXER
+ name 'rxspeech_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.354 {
+ iface MIXER
+ name 'rxspeech_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.355 {
+ iface MIXER
+ name 'rxspeech_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.356 {
+ iface MIXER
+ name 'speech_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.357 {
+ iface MIXER
+ name 'speech_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.358 {
+ iface MIXER
+ name 'speech_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.359 {
+ iface MIXER
+ name 'codec_in0 gain 0 rampduration'
+ value 50
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.360 {
+ iface MIXER
+ name 'codec_in0 gain 0 mute'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.361 {
+ iface MIXER
+ name 'codec_in0 gain 0 volume'
+ value.0 0
+ value.1 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.362 {
+ iface MIXER
+ name 'codec_in1 gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.363 {
+ iface MIXER
+ name 'codec_in1 gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.364 {
+ iface MIXER
+ name 'codec_in1 gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.365 {
+ iface MIXER
+ name 'codec_out0 gain 0 rampduration'
+ value 50
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.366 {
+ iface MIXER
+ name 'codec_out0 gain 0 mute'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.367 {
+ iface MIXER
+ name 'codec_out0 gain 0 volume'
+ value.0 0
+ value.1 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.368 {
+ iface MIXER
+ name 'codec_out1 gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.369 {
+ iface MIXER
+ name 'codec_out1 gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.370 {
+ iface MIXER
+ name 'codec_out1 gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.371 {
+ iface MIXER
+ name 'bt_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.372 {
+ iface MIXER
+ name 'bt_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.373 {
+ iface MIXER
+ name 'bt_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.374 {
+ iface MIXER
+ name 'fm_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.375 {
+ iface MIXER
+ name 'fm_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.376 {
+ iface MIXER
+ name 'fm_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.377 {
+ iface MIXER
+ name 'bt_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.378 {
+ iface MIXER
+ name 'bt_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.379 {
+ iface MIXER
+ name 'bt_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.380 {
+ iface MIXER
+ name 'fm_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.381 {
+ iface MIXER
+ name 'fm_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.382 {
+ iface MIXER
+ name 'fm_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.383 {
+ iface MIXER
+ name 'modem_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.384 {
+ iface MIXER
+ name 'modem_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.385 {
+ iface MIXER
+ name 'modem_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.386 {
+ iface MIXER
+ name 'modem_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.387 {
+ iface MIXER
+ name 'modem_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.388 {
+ iface MIXER
+ name 'modem_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.389 {
+ iface MIXER
+ name 'media_loop1_out gain 0 rampduration'
+ value 50
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.390 {
+ iface MIXER
+ name 'media_loop1_out gain 0 mute'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.391 {
+ iface MIXER
+ name 'media_loop1_out gain 0 volume'
+ value.0 0
+ value.1 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.392 {
+ iface MIXER
+ name 'media_loop2_out gain 0 rampduration'
+ value 50
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.393 {
+ iface MIXER
+ name 'media_loop2_out gain 0 mute'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.394 {
+ iface MIXER
+ name 'media_loop2_out gain 0 volume'
+ value.0 0
+ value.1 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.395 {
+ iface MIXER
+ name 'sprot_loop_out gain 0 rampduration'
+ value 50
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.396 {
+ iface MIXER
+ name 'sprot_loop_out gain 0 mute'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.397 {
+ iface MIXER
+ name 'sprot_loop_out gain 0 volume'
+ value.0 0
+ value.1 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.398 {
+ iface MIXER
+ name 'media0_in volume 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.399 {
+ iface MIXER
+ name 'media0_in volume 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.400 {
+ iface MIXER
+ name 'media0_in volume 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.401 {
+ iface MIXER
+ name 'sidetone_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.402 {
+ iface MIXER
+ name 'sidetone_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.403 {
+ iface MIXER
+ name 'sidetone_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.404 {
+ iface MIXER
+ name 'speech_out gain 1 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.405 {
+ iface MIXER
+ name 'speech_out gain 1 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.406 {
+ iface MIXER
+ name 'speech_out gain 1 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.407 {
+ iface MIXER
+ name 'media_loop1_out fir 0 params'
+ value '8a0003000100400000000000150014001400130011000e0009000000f3ffe0ffc8ffa8ff81ff52ff1bffddfe97fe4afef8fda1fd47fdecfc92fc3afce7fb9afb56fb1bfbecfac9fab4fa707ab4fac9faecfa1bfb56fb9afbe7fb3afc92fcecfc47fda1fdf8fd4afe97feddfe1bff52ff81ffa8ffc8ffe0fff3ff000009000e0000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 138
+ }
+ }
+ control.408 {
+ iface MIXER
+ name 'media_loop1_out iir 0 params'
+ value '98000300010001005a5aefcdd0ca5c8c2e74006f573a0022518b006f573a000100005a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 300
+ }
+ }
+ control.409 {
+ iface MIXER
+ name 'media_loop1_out mdrp 0 params'
+ value '4c00030000000100010000000000000000000000000000000000000000000000000000500000003c000000060000001900000001000058020000000100001400000014000000400000000001'
+ comment {
+ access 'read write'
+ type BYTES
+ count 76
+ }
+ }
+ control.410 {
+ iface MIXER
+ name 'media_loop2_out fir 0 params'
+ value '100103000300400000000000fcffeaffdeffc6ffbbffa7ffa5ffa3ffb9ffc3ffdcffdcfff2ffeffffbffeaff150014001a00e5ff1800990083013900ddfda1fe51066209460c6e01a204de40a2046e01460c62095106a1feddfd3900830199001800e5ff1a0014001500eafffbffeffff2ffdcffdcffc3ffb9ffa3ffa5ffa7ff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 272
+ }
+ }
+ control.411 {
+ iface MIXER
+ name 'media_loop2_out iir 0 params'
+ value '2c010300030001005a5aefcdd0ca5c8c2e74006f573a0022518b006f573a1f0000005a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 300
+ }
+ }
+ control.412 {
+ iface MIXER
+ name 'media_loop2_out mdrp 0 params'
+ value '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 76
+ }
+ }
+ control.413 {
+ iface MIXER
+ name 'aware_out fir 0 params'
+ value '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 272
+ }
+ }
+ control.414 {
+ iface MIXER
+ name 'aware_out iir 0 params'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 300
+ }
+ }
+ control.415 {
+ iface MIXER
+ name 'aware_out aware 0 params'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 48
+ }
+ }
+ control.416 {
+ iface MIXER
+ name 'vad_out fir 0 params'
+ value '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 272
+ }
+ }
+ control.417 {
+ iface MIXER
+ name 'vad_out iir 0 params'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 300
+ }
+ }
+ control.418 {
+ iface MIXER
+ name 'sprot_loop_out lpro 0 params'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 192
+ }
+ }
+ control.419 {
+ iface MIXER
+ name 'codec_in0 dcr 0 params'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 300
+ }
+ }
+ control.420 {
+ iface MIXER
+ name 'codec_in1 dcr 0 params'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 300
+ }
+ }
+ control.421 {
+ iface MIXER
+ name 'speech_out ul_module 0 params fir_speech'
+ value '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 136
+ }
+ }
+ control.422 {
+ iface MIXER
+ name 'speech_out ul_module 0 params fir_hf_sns'
+ value '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 136
+ }
+ }
+ control.423 {
+ iface MIXER
+ name 'speech_out ul_module 0 params iir_speech'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 48
+ }
+ }
+ control.424 {
+ iface MIXER
+ name 'speech_out ul_module 0 params iir_hf_sns'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 48
+ }
+ }
+ control.425 {
+ iface MIXER
+ name 'speech_out ul_module 0 params aec'
+ value '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 640
+ }
+ }
+ control.426 {
+ iface MIXER
+ name 'speech_out ul_module 0 params nr'
+ value '0000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 38
+ }
+ }
+ control.427 {
+ iface MIXER
+ name 'speech_out ul_module 0 params agc'
+ value '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 58
+ }
+ }
+ control.428 {
+ iface MIXER
+ name 'speech_out ul_module 0 params biquad'
+ value '00000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 22
+ }
+ }
+ control.429 {
+ iface MIXER
+ name 'speech_out ul_module 0 params compr'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 36
+ }
+ }
+ control.430 {
+ iface MIXER
+ name 'speech_out ul_module 0 params sns'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 324
+ }
+ }
+ control.431 {
+ iface MIXER
+ name 'speech_out ul_module 0 params ser'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 42
+ }
+ }
+ control.432 {
+ iface MIXER
+ name 'speech_out ul_module 0 params cni'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 48
+ }
+ }
+ control.433 {
+ iface MIXER
+ name 'speech_out ul_module 0 params ref'
+ value '000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 24
+ }
+ }
+ control.434 {
+ iface MIXER
+ name 'speech_out ul_module 0 params delay'
+ value '000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 6
+ }
+ }
+ control.435 {
+ iface MIXER
+ name 'speech_out ul_module 0 params bmf'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 264
+ }
+ }
+ control.436 {
+ iface MIXER
+ name 'speech_out ul_module 0 params dnr'
+ value '000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 18
+ }
+ }
+ control.437 {
+ iface MIXER
+ name 'speech_in dl_module 0 params ana'
+ value '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 52
+ }
+ }
+ control.438 {
+ iface MIXER
+ name 'speech_in dl_module 0 params fir'
+ value '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 136
+ }
+ }
+ control.439 {
+ iface MIXER
+ name 'speech_in dl_module 0 params iir'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 48
+ }
+ }
+ control.440 {
+ iface MIXER
+ name 'speech_in dl_module 0 params nr'
+ value '0000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 38
+ }
+ }
+ control.441 {
+ iface MIXER
+ name 'speech_in dl_module 0 params biquad'
+ value '00000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 22
+ }
+ }
+ control.442 {
+ iface MIXER
+ name 'speech_in dl_module 0 params compr'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 36
+ }
+ }
+ control.443 {
+ iface MIXER
+ name 'speech_in dl_module 0 params cni'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 48
+ }
+ }
+ control.444 {
+ iface MIXER
+ name 'speech_in dl_module 0 params bwx'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 54
+ }
+ }
+ control.445 {
+ iface MIXER
+ name 'speech_in dl_module 0 params gmm'
+ value '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 586
+ }
+ }
+ control.446 {
+ iface MIXER
+ name 'speech_in dl_module 0 params glc'
+ value '000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 18
+ }
+ }
+ control.447 {
+ iface MIXER
+ name 'codec_out interleaver slot 0'
+ value codec_out0_0
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 none
+ item.1 codec_out0_0
+ item.2 codec_out0_1
+ item.3 codec_out1_0
+ item.4 codec_out1_1
+ }
+ }
+ control.448 {
+ iface MIXER
+ name 'codec_out interleaver slot 1'
+ value codec_out0_1
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 none
+ item.1 codec_out0_0
+ item.2 codec_out0_1
+ item.3 codec_out1_0
+ item.4 codec_out1_1
+ }
+ }
+ control.449 {
+ iface MIXER
+ name 'codec_out interleaver slot 2'
+ value codec_out1_0
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 none
+ item.1 codec_out0_0
+ item.2 codec_out0_1
+ item.3 codec_out1_0
+ item.4 codec_out1_1
+ }
+ }
+ control.450 {
+ iface MIXER
+ name 'codec_out interleaver slot 3'
+ value codec_out1_1
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 none
+ item.1 codec_out0_0
+ item.2 codec_out0_1
+ item.3 codec_out1_0
+ item.4 codec_out1_1
+ }
+ }
+ control.451 {
+ iface MIXER
+ name 'codec_in deinterleaver codec_in0_0'
+ value 'slot 0'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 none
+ item.1 'slot 0'
+ item.2 'slot 1'
+ item.3 'slot 2'
+ item.4 'slot 3'
+ }
+ }
+ control.452 {
+ iface MIXER
+ name 'codec_in deinterleaver codec_in0_1'
+ value 'slot 1'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 none
+ item.1 'slot 0'
+ item.2 'slot 1'
+ item.3 'slot 2'
+ item.4 'slot 3'
+ }
+ }
+ control.453 {
+ iface MIXER
+ name 'codec_in deinterleaver codec_in1_0'
+ value none
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 none
+ item.1 'slot 0'
+ item.2 'slot 1'
+ item.3 'slot 2'
+ item.4 'slot 3'
+ }
+ }
+ control.454 {
+ iface MIXER
+ name 'codec_in deinterleaver codec_in1_1'
+ value none
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 none
+ item.1 'slot 0'
+ item.2 'slot 1'
+ item.3 'slot 2'
+ item.4 'slot 3'
+ }
+ }
+ control.455 {
+ iface MIXER
+ name 'domain voice mode 0'
+ value narrowband
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 narrowband
+ item.1 wideband
+ }
+ }
+ control.456 {
+ iface MIXER
+ name 'domain bt mode 0'
+ value narrowband
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 narrowband
+ item.1 wideband
+ }
+ }
+ control.457 {
+ iface MIXER
+ name 'sst debug byte control'
+ value '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 512
+ }
+ }
+ control.458 {
+ iface MIXER
+ name 'probe out0 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.459 {
+ iface MIXER
+ name 'probe out1 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.460 {
+ iface MIXER
+ name 'probe out2 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.461 {
+ iface MIXER
+ name 'probe out3 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.462 {
+ iface MIXER
+ name 'probe out4 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.463 {
+ iface MIXER
+ name 'probe out5 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.464 {
+ iface MIXER
+ name 'probe out6 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.465 {
+ iface MIXER
+ name 'probe out7 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.466 {
+ iface MIXER
+ name 'probe in0 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.467 {
+ iface MIXER
+ name 'probe in1 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.468 {
+ iface MIXER
+ name 'probe in2 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.469 {
+ iface MIXER
+ name 'probe in3 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.470 {
+ iface MIXER
+ name 'probe in4 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.471 {
+ iface MIXER
+ name 'probe in5 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.472 {
+ iface MIXER
+ name 'probe in6 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.473 {
+ iface MIXER
+ name 'probe in7 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.474 {
+ iface MIXER
+ name 'AIF1.1 DRC'
+ value '00980845000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 10
+ }
+ }
+ control.475 {
+ iface MIXER
+ name 'AIF1.2 DRC'
+ value '00980845000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 10
+ }
+ }
+ control.476 {
+ iface MIXER
+ name 'AIF2 DRC'
+ value '00980845000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 10
+ }
+ }
+ control.477 {
+ iface MIXER
+ name 'AIF1DAC1 EQ1 Volume'
+ value 12
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 31'
+ dbmin -1200
+ dbmax 1900
+ dbvalue.0 0
+ }
+ }
+ control.478 {
+ iface MIXER
+ name 'AIF1DAC1 EQ2 Volume'
+ value 12
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 31'
+ dbmin -1200
+ dbmax 1900
+ dbvalue.0 0
+ }
+ }
+ control.479 {
+ iface MIXER
+ name 'AIF1DAC1 EQ3 Volume'
+ value 12
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 31'
+ dbmin -1200
+ dbmax 1900
+ dbvalue.0 0
+ }
+ }
+ control.480 {
+ iface MIXER
+ name 'AIF1DAC1 EQ4 Volume'
+ value 12
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 31'
+ dbmin -1200
+ dbmax 1900
+ dbvalue.0 0
+ }
+ }
+ control.481 {
+ iface MIXER
+ name 'AIF1DAC1 EQ5 Volume'
+ value 12
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 31'
+ dbmin -1200
+ dbmax 1900
+ dbvalue.0 0
+ }
+ }
+ control.482 {
+ iface MIXER
+ name 'AIF1DAC2 EQ1 Volume'
+ value 12
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 31'
+ dbmin -1200
+ dbmax 1900
+ dbvalue.0 0
+ }
+ }
+ control.483 {
+ iface MIXER
+ name 'AIF1DAC2 EQ2 Volume'
+ value 12
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 31'
+ dbmin -1200
+ dbmax 1900
+ dbvalue.0 0
+ }
+ }
+ control.484 {
+ iface MIXER
+ name 'AIF1DAC2 EQ3 Volume'
+ value 12
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 31'
+ dbmin -1200
+ dbmax 1900
+ dbvalue.0 0
+ }
+ }
+ control.485 {
+ iface MIXER
+ name 'AIF1DAC2 EQ4 Volume'
+ value 12
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 31'
+ dbmin -1200
+ dbmax 1900
+ dbvalue.0 0
+ }
+ }
+ control.486 {
+ iface MIXER
+ name 'AIF1DAC2 EQ5 Volume'
+ value 12
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 31'
+ dbmin -1200
+ dbmax 1900
+ dbvalue.0 0
+ }
+ }
+ control.487 {
+ iface MIXER
+ name 'AIF2 EQ1 Volume'
+ value 12
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 31'
+ dbmin -1200
+ dbmax 1900
+ dbvalue.0 0
+ }
+ }
+ control.488 {
+ iface MIXER
+ name 'AIF2 EQ2 Volume'
+ value 12
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 31'
+ dbmin -1200
+ dbmax 1900
+ dbvalue.0 0
+ }
+ }
+ control.489 {
+ iface MIXER
+ name 'AIF2 EQ3 Volume'
+ value 12
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 31'
+ dbmin -1200
+ dbmax 1900
+ dbvalue.0 0
+ }
+ }
+ control.490 {
+ iface MIXER
+ name 'AIF2 EQ4 Volume'
+ value 12
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 31'
+ dbmin -1200
+ dbmax 1900
+ dbvalue.0 0
+ }
+ }
+ control.491 {
+ iface MIXER
+ name 'AIF2 EQ5 Volume'
+ value 12
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 31'
+ dbmin -1200
+ dbmax 1900
+ dbvalue.0 0
+ }
+ }
+ control.492 {
+ iface MIXER
+ name 'IN1L Volume'
+ value 11
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 31'
+ dbmin -1650
+ dbmax 3000
+ dbvalue.0 0
+ }
+ }
+ control.493 {
+ iface MIXER
+ name 'IN1L Switch'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.494 {
+ iface MIXER
+ name 'IN1L ZC Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.495 {
+ iface MIXER
+ name 'IN1R Volume'
+ value 11
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 31'
+ dbmin -1650
+ dbmax 3000
+ dbvalue.0 0
+ }
+ }
+ control.496 {
+ iface MIXER
+ name 'IN1R Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.497 {
+ iface MIXER
+ name 'IN1R ZC Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.498 {
+ iface MIXER
+ name 'IN2L Volume'
+ value 11
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 31'
+ dbmin -1650
+ dbmax 3000
+ dbvalue.0 0
+ }
+ }
+ control.499 {
+ iface MIXER
+ name 'IN2L Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.500 {
+ iface MIXER
+ name 'IN2L ZC Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.501 {
+ iface MIXER
+ name 'IN2R Volume'
+ value 11
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 31'
+ dbmin -1650
+ dbmax 3000
+ dbvalue.0 0
+ }
+ }
+ control.502 {
+ iface MIXER
+ name 'IN2R Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.503 {
+ iface MIXER
+ name 'IN2R ZC Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.504 {
+ iface MIXER
+ name 'MIXINL IN2L Volume'
+ value 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 1'
+ dbmin 0
+ dbmax 3000
+ dbvalue.0 0
+ }
+ }
+ control.505 {
+ iface MIXER
+ name 'MIXINL IN1L Volume'
+ value 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 1'
+ dbmin 0
+ dbmax 3000
+ dbvalue.0 0
+ }
+ }
+ control.506 {
+ iface MIXER
+ name 'MIXINL Output Record Volume'
+ value 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin -9999999
+ dbmax 600
+ dbvalue.0 -9999999
+ }
+ }
+ control.507 {
+ iface MIXER
+ name 'MIXINL IN1LP Volume'
+ value 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin -9999999
+ dbmax 600
+ dbvalue.0 -9999999
+ }
+ }
+ control.508 {
+ iface MIXER
+ name 'MIXINL Direct Voice Volume'
+ value 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 6'
+ dbmin -9999999
+ dbmax 300
+ dbvalue.0 -9999999
+ }
+ }
+ control.509 {
+ iface MIXER
+ name 'MIXINR IN2R Volume'
+ value 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 1'
+ dbmin 0
+ dbmax 3000
+ dbvalue.0 0
+ }
+ }
+ control.510 {
+ iface MIXER
+ name 'MIXINR IN1R Volume'
+ value 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 1'
+ dbmin 0
+ dbmax 3000
+ dbvalue.0 0
+ }
+ }
+ control.511 {
+ iface MIXER
+ name 'MIXINR Output Record Volume'
+ value 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin -9999999
+ dbmax 600
+ dbvalue.0 -9999999
+ }
+ }
+ control.512 {
+ iface MIXER
+ name 'MIXINR IN1RP Volume'
+ value 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin -9999999
+ dbmax 600
+ dbvalue.0 -9999999
+ }
+ }
+ control.513 {
+ iface MIXER
+ name 'MIXINR Direct Voice Volume'
+ value 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 6'
+ dbmin -9999999
+ dbmax 300
+ dbvalue.0 -9999999
+ }
+ }
+ control.514 {
+ iface MIXER
+ name 'Left Output Mixer IN2RN Volume'
+ value 7
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin -2100
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.515 {
+ iface MIXER
+ name 'Left Output Mixer IN2LN Volume'
+ value 7
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin -2100
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.516 {
+ iface MIXER
+ name 'Left Output Mixer IN2LP Volume'
+ value 7
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin -2100
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.517 {
+ iface MIXER
+ name 'Left Output Mixer IN1L Volume'
+ value 7
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin -2100
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.518 {
+ iface MIXER
+ name 'Left Output Mixer IN1R Volume'
+ value 7
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin -2100
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.519 {
+ iface MIXER
+ name 'Left Output Mixer Right Input Volume'
+ value 7
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin -2100
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.520 {
+ iface MIXER
+ name 'Left Output Mixer Left Input Volume'
+ value 7
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin -2100
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.521 {
+ iface MIXER
+ name 'Left Output Mixer DAC Volume'
+ value 7
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin -2100
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.522 {
+ iface MIXER
+ name 'Right Output Mixer IN2LN Volume'
+ value 7
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin -2100
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.523 {
+ iface MIXER
+ name 'Right Output Mixer IN2RN Volume'
+ value 7
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin -2100
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.524 {
+ iface MIXER
+ name 'Right Output Mixer IN1L Volume'
+ value 7
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin -2100
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.525 {
+ iface MIXER
+ name 'Right Output Mixer IN1R Volume'
+ value 7
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin -2100
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.526 {
+ iface MIXER
+ name 'Right Output Mixer IN2RP Volume'
+ value 7
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin -2100
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.527 {
+ iface MIXER
+ name 'Right Output Mixer Left Input Volume'
+ value 7
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin -2100
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.528 {
+ iface MIXER
+ name 'Right Output Mixer Right Input Volume'
+ value 7
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin -2100
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.529 {
+ iface MIXER
+ name 'Right Output Mixer DAC Volume'
+ value 7
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin -2100
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.530 {
+ iface MIXER
+ name 'Output Volume'
+ value.0 57
+ value.1 57
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '0 - 63'
+ dbmin -5700
+ dbmax 600
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.531 {
+ iface MIXER
+ name 'Output Switch'
+ value.0 true
+ value.1 true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 2
+ }
+ }
+ control.532 {
+ iface MIXER
+ name 'Output ZC Switch'
+ value.0 true
+ value.1 true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 2
+ }
+ }
+ control.533 {
+ iface MIXER
+ name 'Earpiece Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.534 {
+ iface MIXER
+ name 'Earpiece Volume'
+ value 1
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 1'
+ dbmin -600
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.535 {
+ iface MIXER
+ name 'SPKL Input Volume'
+ value 1
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 1'
+ dbmin -300
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.536 {
+ iface MIXER
+ name 'SPKL IN1LP Volume'
+ value 1
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 1'
+ dbmin -300
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.537 {
+ iface MIXER
+ name 'SPKL Output Volume'
+ value 1
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 1'
+ dbmin -300
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.538 {
+ iface MIXER
+ name 'SPKR Input Volume'
+ value 1
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 1'
+ dbmin -300
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.539 {
+ iface MIXER
+ name 'SPKR IN1RP Volume'
+ value 1
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 1'
+ dbmin -300
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.540 {
+ iface MIXER
+ name 'SPKR Output Volume'
+ value 1
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 1'
+ dbmin -300
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.541 {
+ iface MIXER
+ name 'Speaker Mixer Volume'
+ value.0 3
+ value.1 3
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '0 - 3'
+ dbmin -9999999
+ dbmax 0
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.542 {
+ iface MIXER
+ name 'Speaker Volume'
+ value.0 57
+ value.1 57
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '0 - 63'
+ dbmin -5700
+ dbmax 600
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.543 {
+ iface MIXER
+ name 'Speaker Switch'
+ value.0 true
+ value.1 true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 2
+ }
+ }
+ control.544 {
+ iface MIXER
+ name 'Speaker ZC Switch'
+ value.0 true
+ value.1 true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 2
+ }
+ }
+ control.545 {
+ iface MIXER
+ name 'Speaker Boost Volume'
+ value.0 0
+ value.1 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '0 - 7'
+ dbmin 0
+ dbmax 1200
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.546 {
+ iface MIXER
+ name 'Speaker Reference'
+ value SPKVDD/2
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 SPKVDD/2
+ item.1 VMID
+ }
+ }
+ control.547 {
+ iface MIXER
+ name 'Speaker Mode'
+ value 'Class D'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'Class D'
+ item.1 'Class AB'
+ }
+ }
+ control.548 {
+ iface MIXER
+ name 'Headphone Volume'
+ value.0 45
+ value.1 45
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '0 - 63'
+ dbmin -5700
+ dbmax 600
+ dbvalue.0 -1200
+ dbvalue.1 -1200
+ }
+ }
+ control.549 {
+ iface MIXER
+ name 'Headphone Switch'
+ value.0 true
+ value.1 true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 2
+ }
+ }
+ control.550 {
+ iface MIXER
+ name 'Headphone ZC Switch'
+ value.0 true
+ value.1 true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 2
+ }
+ }
+ control.551 {
+ iface MIXER
+ name 'LINEOUT1N Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.552 {
+ iface MIXER
+ name 'LINEOUT1P Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.553 {
+ iface MIXER
+ name 'LINEOUT1 Volume'
+ value 1
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 1'
+ dbmin -600
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.554 {
+ iface MIXER
+ name 'LINEOUT2N Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.555 {
+ iface MIXER
+ name 'LINEOUT2P Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.556 {
+ iface MIXER
+ name 'LINEOUT2 Volume'
+ value 1
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 1'
+ dbmin -600
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.557 {
+ iface MIXER
+ name 'AIF1ADC1 Volume'
+ value.0 110
+ value.1 110
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '0 - 120'
+ dbmin -9999999
+ dbmax 1800
+ dbvalue.0 1050
+ dbvalue.1 1050
+ }
+ }
+ control.558 {
+ iface MIXER
+ name 'AIF1ADC2 Volume'
+ value.0 96
+ value.1 96
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '0 - 120'
+ dbmin -9999999
+ dbmax 1800
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.559 {
+ iface MIXER
+ name 'AIF2ADC Volume'
+ value.0 96
+ value.1 96
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '0 - 120'
+ dbmin -9999999
+ dbmax 1800
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.560 {
+ iface MIXER
+ name 'AIF1ADCL Source'
+ value Left
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 Left
+ item.1 Right
+ }
+ }
+ control.561 {
+ iface MIXER
+ name 'AIF1ADCR Source'
+ value Right
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 Left
+ item.1 Right
+ }
+ }
+ control.562 {
+ iface MIXER
+ name 'AIF2ADCL Source'
+ value Left
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 Left
+ item.1 Right
+ }
+ }
+ control.563 {
+ iface MIXER
+ name 'AIF2ADCR Source'
+ value Right
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 Left
+ item.1 Right
+ }
+ }
+ control.564 {
+ iface MIXER
+ name 'AIF1DACL Source'
+ value Left
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 Left
+ item.1 Right
+ }
+ }
+ control.565 {
+ iface MIXER
+ name 'AIF1DACR Source'
+ value Right
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 Left
+ item.1 Right
+ }
+ }
+ control.566 {
+ iface MIXER
+ name 'AIF2DACL Source'
+ value Left
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 Left
+ item.1 Right
+ }
+ }
+ control.567 {
+ iface MIXER
+ name 'AIF2DACR Source'
+ value Right
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 Left
+ item.1 Right
+ }
+ }
+ control.568 {
+ iface MIXER
+ name 'AIF1DAC1 Volume'
+ value.0 96
+ value.1 96
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '0 - 96'
+ dbmin -9999999
+ dbmax 0
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.569 {
+ iface MIXER
+ name 'AIF1DAC2 Volume'
+ value.0 96
+ value.1 96
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '0 - 96'
+ dbmin -9999999
+ dbmax 0
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.570 {
+ iface MIXER
+ name 'AIF2DAC Volume'
+ value.0 96
+ value.1 96
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '0 - 96'
+ dbmin -9999999
+ dbmax 0
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.571 {
+ iface MIXER
+ name 'AIF1 Boost Volume'
+ value 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 3'
+ dbmin 0
+ dbmax 1800
+ dbvalue.0 0
+ }
+ }
+ control.572 {
+ iface MIXER
+ name 'AIF2 Boost Volume'
+ value 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 3'
+ dbmin 0
+ dbmax 1800
+ dbvalue.0 0
+ }
+ }
+ control.573 {
+ iface MIXER
+ name 'AIF1DAC1 EQ Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.574 {
+ iface MIXER
+ name 'AIF1DAC2 EQ Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.575 {
+ iface MIXER
+ name 'AIF2 EQ Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.576 {
+ iface MIXER
+ name 'AIF1DAC1 DRC Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.577 {
+ iface MIXER
+ name 'AIF1ADC1L DRC Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.578 {
+ iface MIXER
+ name 'AIF1ADC1R DRC Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.579 {
+ iface MIXER
+ name 'AIF1DAC2 DRC Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.580 {
+ iface MIXER
+ name 'AIF1ADC2L DRC Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.581 {
+ iface MIXER
+ name 'AIF1ADC2R DRC Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.582 {
+ iface MIXER
+ name 'AIF2DAC DRC Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.583 {
+ iface MIXER
+ name 'AIF2ADCL DRC Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.584 {
+ iface MIXER
+ name 'AIF2ADCR DRC Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.585 {
+ iface MIXER
+ name 'DAC1 Right Sidetone Volume'
+ value 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 12'
+ dbmin -3600
+ dbmax 0
+ dbvalue.0 -3600
+ }
+ }
+ control.586 {
+ iface MIXER
+ name 'DAC1 Left Sidetone Volume'
+ value 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 12'
+ dbmin -3600
+ dbmax 0
+ dbvalue.0 -3600
+ }
+ }
+ control.587 {
+ iface MIXER
+ name 'DAC2 Right Sidetone Volume'
+ value 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 12'
+ dbmin -3600
+ dbmax 0
+ dbvalue.0 -3600
+ }
+ }
+ control.588 {
+ iface MIXER
+ name 'DAC2 Left Sidetone Volume'
+ value 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 12'
+ dbmin -3600
+ dbmax 0
+ dbvalue.0 -3600
+ }
+ }
+ control.589 {
+ iface MIXER
+ name 'Sidetone HPF Mux'
+ value '2.7kHz'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 '2.7kHz'
+ item.1 '1.35kHz'
+ item.2 '675Hz'
+ item.3 '370Hz'
+ item.4 '180Hz'
+ item.5 '90Hz'
+ item.6 '45Hz'
+ }
+ }
+ control.590 {
+ iface MIXER
+ name 'Sidetone HPF Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.591 {
+ iface MIXER
+ name 'AIF1ADC1 HPF Mode'
+ value HiFi
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 HiFi
+ item.1 'Voice 1'
+ item.2 'Voice 2'
+ item.3 'Voice 3'
+ }
+ }
+ control.592 {
+ iface MIXER
+ name 'AIF1ADC1 HPF Switch'
+ value.0 false
+ value.1 false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 2
+ }
+ }
+ control.593 {
+ iface MIXER
+ name 'AIF1ADC2 HPF Mode'
+ value HiFi
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 HiFi
+ item.1 'Voice 1'
+ item.2 'Voice 2'
+ item.3 'Voice 3'
+ }
+ }
+ control.594 {
+ iface MIXER
+ name 'AIF1ADC2 HPF Switch'
+ value.0 false
+ value.1 false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 2
+ }
+ }
+ control.595 {
+ iface MIXER
+ name 'AIF2ADC HPF Mode'
+ value HiFi
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 HiFi
+ item.1 'Voice 1'
+ item.2 'Voice 2'
+ item.3 'Voice 3'
+ }
+ }
+ control.596 {
+ iface MIXER
+ name 'AIF2ADC HPF Switch'
+ value.0 false
+ value.1 false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 2
+ }
+ }
+ control.597 {
+ iface MIXER
+ name 'ADC OSR'
+ value 'High Performance'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'Low Power'
+ item.1 'High Performance'
+ }
+ }
+ control.598 {
+ iface MIXER
+ name 'DAC OSR'
+ value 'Low Power'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'Low Power'
+ item.1 'High Performance'
+ }
+ }
+ control.599 {
+ iface MIXER
+ name 'DAC1 Volume'
+ value.0 96
+ value.1 96
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '0 - 112'
+ dbmin -9999999
+ dbmax 1200
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.600 {
+ iface MIXER
+ name 'DAC1 Switch'
+ value.0 true
+ value.1 true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 2
+ }
+ }
+ control.601 {
+ iface MIXER
+ name 'DAC2 Volume'
+ value.0 96
+ value.1 96
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '0 - 112'
+ dbmin -9999999
+ dbmax 1200
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.602 {
+ iface MIXER
+ name 'DAC2 Switch'
+ value.0 false
+ value.1 false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 2
+ }
+ }
+ control.603 {
+ iface MIXER
+ name 'SPKL DAC2 Volume'
+ value 1
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 1'
+ dbmin -300
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.604 {
+ iface MIXER
+ name 'SPKL DAC1 Volume'
+ value 1
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 1'
+ dbmin -300
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.605 {
+ iface MIXER
+ name 'SPKR DAC2 Volume'
+ value 1
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 1'
+ dbmin -300
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.606 {
+ iface MIXER
+ name 'SPKR DAC1 Volume'
+ value 1
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 1'
+ dbmin -300
+ dbmax 0
+ dbvalue.0 0
+ }
+ }
+ control.607 {
+ iface MIXER
+ name 'AIF1DAC1 3D Stereo Volume'
+ value 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 15'
+ dbmin -1600
+ dbmax 1145
+ dbvalue.0 -1600
+ }
+ }
+ control.608 {
+ iface MIXER
+ name 'AIF1DAC1 3D Stereo Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.609 {
+ iface MIXER
+ name 'AIF1DAC2 3D Stereo Volume'
+ value 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 15'
+ dbmin -1600
+ dbmax 1145
+ dbvalue.0 -1600
+ }
+ }
+ control.610 {
+ iface MIXER
+ name 'AIF1DAC2 3D Stereo Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.611 {
+ iface MIXER
+ name 'AIF2DAC 3D Stereo Volume'
+ value 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 15'
+ dbmin -1600
+ dbmax 1145
+ dbvalue.0 -1600
+ }
+ }
+ control.612 {
+ iface MIXER
+ name 'AIF2DAC 3D Stereo Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.613 {
+ iface MIXER
+ name 'MIXINL MIXOUTL Volume'
+ value 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin 0
+ dbmax 6300
+ dbvalue.0 0
+ }
+ }
+ control.614 {
+ iface MIXER
+ name 'MIXINR MIXOUTR Volume'
+ value 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin 0
+ dbmax 6300
+ dbvalue.0 0
+ }
+ }
+ control.615 {
+ iface MIXER
+ name 'AIF3 Boost Volume'
+ value 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 3'
+ dbmin 0
+ dbmax 1800
+ dbvalue.0 0
+ }
+ }
+ control.616 {
+ iface MIXER
+ name 'AIF1DAC1 Noise Gate Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.617 {
+ iface MIXER
+ name 'AIF1DAC1 Noise Gate Hold Time'
+ value '30ms'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 '30ms'
+ item.1 '125ms'
+ item.2 '250ms'
+ item.3 '500ms'
+ }
+ }
+ control.618 {
+ iface MIXER
+ name 'AIF1DAC1 Noise Gate Threshold Volume'
+ value 3
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin -10200
+ dbmax -6000
+ dbvalue.0 -8400
+ }
+ }
+ control.619 {
+ iface MIXER
+ name 'AIF1DAC2 Noise Gate Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.620 {
+ iface MIXER
+ name 'AIF1DAC2 Noise Gate Hold Time'
+ value '30ms'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 '30ms'
+ item.1 '125ms'
+ item.2 '250ms'
+ item.3 '500ms'
+ }
+ }
+ control.621 {
+ iface MIXER
+ name 'AIF1DAC2 Noise Gate Threshold Volume'
+ value 3
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin -10200
+ dbmax -6000
+ dbvalue.0 -8400
+ }
+ }
+ control.622 {
+ iface MIXER
+ name 'AIF2DAC Noise Gate Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.623 {
+ iface MIXER
+ name 'AIF2DAC Noise Gate Hold Time'
+ value '30ms'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 '30ms'
+ item.1 '125ms'
+ item.2 '250ms'
+ item.3 '500ms'
+ }
+ }
+ control.624 {
+ iface MIXER
+ name 'AIF2DAC Noise Gate Threshold Volume'
+ value 3
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '0 - 7'
+ dbmin -10200
+ dbmax -6000
+ dbvalue.0 -8400
+ }
+ }
+ control.625 {
+ iface MIXER
+ name 'AIF1DAC1 MBC Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.626 {
+ iface MIXER
+ name 'AIF1DAC2 MBC Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.627 {
+ iface MIXER
+ name 'AIF2DAC MBC Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.628 {
+ iface MIXER
+ name 'AIF1DAC1 VSS Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.629 {
+ iface MIXER
+ name 'AIF1DAC2 VSS Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.630 {
+ iface MIXER
+ name 'AIF2DAC VSS Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.631 {
+ iface MIXER
+ name 'AIF1DAC1 HPF1 Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.632 {
+ iface MIXER
+ name 'AIF1DAC2 HPF1 Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.633 {
+ iface MIXER
+ name 'AIF2DAC HPF1 Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.634 {
+ iface MIXER
+ name 'AIF1DAC1 HPF2 Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.635 {
+ iface MIXER
+ name 'AIF1DAC2 HPF2 Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.636 {
+ iface MIXER
+ name 'AIF2DAC HPF2 Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.637 {
+ iface MIXER
+ name 'AIF1DAC1 Enhanced EQ Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.638 {
+ iface MIXER
+ name 'AIF1DAC2 Enhanced EQ Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.639 {
+ iface MIXER
+ name 'AIF2DAC Enhanced EQ Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.640 {
+ iface MIXER
+ name 'ADCR Mux'
+ value DMIC
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 ADC
+ item.1 DMIC
+ }
+ }
+ control.641 {
+ iface MIXER
+ name 'ADCL Mux'
+ value DMIC
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 ADC
+ item.1 DMIC
+ }
+ }
+ control.642 {
+ iface MIXER
+ name 'Right Headphone Mux'
+ value Mixer
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 Mixer
+ item.1 DAC
+ }
+ }
+ control.643 {
+ iface MIXER
+ name 'Left Headphone Mux'
+ value Mixer
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 Mixer
+ item.1 DAC
+ }
+ }
+ control.644 {
+ iface MIXER
+ name 'SPKR DAC2 Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.645 {
+ iface MIXER
+ name 'SPKR Input Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.646 {
+ iface MIXER
+ name 'SPKR IN1RP Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.647 {
+ iface MIXER
+ name 'SPKR Output Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.648 {
+ iface MIXER
+ name 'SPKR DAC1 Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.649 {
+ iface MIXER
+ name 'SPKL DAC2 Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.650 {
+ iface MIXER
+ name 'SPKL Input Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.651 {
+ iface MIXER
+ name 'SPKL IN1LP Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.652 {
+ iface MIXER
+ name 'SPKL Output Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.653 {
+ iface MIXER
+ name 'SPKL DAC1 Switch'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.654 {
+ iface MIXER
+ name 'AIF3ADC Mux'
+ value AIF1ADCDAT
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 AIF1ADCDAT
+ item.1 AIF2ADCDAT
+ item.2 AIF2DACDAT
+ item.3 'Mono PCM'
+ }
+ }
+ control.655 {
+ iface MIXER
+ name 'AIF2DACR Mux'
+ value AIF2
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 AIF2
+ item.1 AIF3
+ }
+ }
+ control.656 {
+ iface MIXER
+ name 'AIF2DACL Mux'
+ value AIF2
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 AIF2
+ item.1 AIF3
+ }
+ }
+ control.657 {
+ iface MIXER
+ name 'Mono PCM Out Mux'
+ value None
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 None
+ item.1 AIF2ADCL
+ item.2 AIF2ADCR
+ }
+ }
+ control.658 {
+ iface MIXER
+ name 'AIF2 Loopback'
+ value None
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 None
+ item.1 ADCDAT
+ }
+ }
+ control.659 {
+ iface MIXER
+ name 'AIF1 Loopback'
+ value None
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 None
+ item.1 ADCDAT
+ }
+ }
+ control.660 {
+ iface MIXER
+ name 'AIF2ADC Mux'
+ value AIF2ADCDAT
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 AIF2ADCDAT
+ item.1 AIF3DACDAT
+ }
+ }
+ control.661 {
+ iface MIXER
+ name 'AIF2DAC Mux'
+ value AIF2DACDAT
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 AIF2DACDAT
+ item.1 AIF3DACDAT
+ }
+ }
+ control.662 {
+ iface MIXER
+ name 'AIF1DAC Mux'
+ value AIF1DACDAT
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 AIF1DACDAT
+ item.1 AIF3DACDAT
+ }
+ }
+ control.663 {
+ iface MIXER
+ name 'DAC1R Mixer Right Sidetone Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.664 {
+ iface MIXER
+ name 'DAC1R Mixer Left Sidetone Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.665 {
+ iface MIXER
+ name 'DAC1R Mixer AIF2 Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.666 {
+ iface MIXER
+ name 'DAC1R Mixer AIF1.2 Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.667 {
+ iface MIXER
+ name 'DAC1R Mixer AIF1.1 Switch'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.668 {
+ iface MIXER
+ name 'DAC1L Mixer Right Sidetone Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.669 {
+ iface MIXER
+ name 'DAC1L Mixer Left Sidetone Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.670 {
+ iface MIXER
+ name 'DAC1L Mixer AIF2 Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.671 {
+ iface MIXER
+ name 'DAC1L Mixer AIF1.2 Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.672 {
+ iface MIXER
+ name 'DAC1L Mixer AIF1.1 Switch'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.673 {
+ iface MIXER
+ name 'Right Sidetone'
+ value ADC/DMIC1
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 ADC/DMIC1
+ item.1 DMIC2
+ }
+ }
+ control.674 {
+ iface MIXER
+ name 'Left Sidetone'
+ value ADC/DMIC1
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 ADC/DMIC1
+ item.1 DMIC2
+ }
+ }
+ control.675 {
+ iface MIXER
+ name 'AIF2DAC2R Mixer Right Sidetone Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.676 {
+ iface MIXER
+ name 'AIF2DAC2R Mixer Left Sidetone Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.677 {
+ iface MIXER
+ name 'AIF2DAC2R Mixer AIF2 Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.678 {
+ iface MIXER
+ name 'AIF2DAC2R Mixer AIF1.2 Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.679 {
+ iface MIXER
+ name 'AIF2DAC2R Mixer AIF1.1 Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.680 {
+ iface MIXER
+ name 'AIF2DAC2L Mixer Right Sidetone Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.681 {
+ iface MIXER
+ name 'AIF2DAC2L Mixer Left Sidetone Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.682 {
+ iface MIXER
+ name 'AIF2DAC2L Mixer AIF2 Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.683 {
+ iface MIXER
+ name 'AIF2DAC2L Mixer AIF1.2 Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.684 {
+ iface MIXER
+ name 'AIF2DAC2L Mixer AIF1.1 Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.685 {
+ iface MIXER
+ name 'AIF1ADC2R Mixer DMIC Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.686 {
+ iface MIXER
+ name 'AIF1ADC2R Mixer AIF2 Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.687 {
+ iface MIXER
+ name 'AIF1ADC2L Mixer DMIC Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.688 {
+ iface MIXER
+ name 'AIF1ADC2L Mixer AIF2 Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.689 {
+ iface MIXER
+ name 'AIF1ADC1R Mixer ADC/DMIC Switch'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.690 {
+ iface MIXER
+ name 'AIF1ADC1R Mixer AIF2 Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.691 {
+ iface MIXER
+ name 'AIF1ADC1L Mixer ADC/DMIC Switch'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.692 {
+ iface MIXER
+ name 'AIF1ADC1L Mixer AIF2 Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.693 {
+ iface MIXER
+ name 'LINEOUT2P Mixer Right Output Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.694 {
+ iface MIXER
+ name 'LINEOUT2N Mixer Left Output Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.695 {
+ iface MIXER
+ name 'LINEOUT2N Mixer Right Output Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.696 {
+ iface MIXER
+ name 'LINEOUT1P Mixer Left Output Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.697 {
+ iface MIXER
+ name 'LINEOUT1N Mixer Left Output Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.698 {
+ iface MIXER
+ name 'LINEOUT1N Mixer Right Output Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.699 {
+ iface MIXER
+ name 'SPKR Boost Direct Voice Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.700 {
+ iface MIXER
+ name 'SPKR Boost SPKL Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.701 {
+ iface MIXER
+ name 'SPKR Boost SPKR Switch'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.702 {
+ iface MIXER
+ name 'SPKL Boost Direct Voice Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.703 {
+ iface MIXER
+ name 'SPKL Boost SPKL Switch'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.704 {
+ iface MIXER
+ name 'SPKL Boost SPKR Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.705 {
+ iface MIXER
+ name 'Earpiece Mixer Direct Voice Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.706 {
+ iface MIXER
+ name 'Earpiece Mixer Left Output Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.707 {
+ iface MIXER
+ name 'Earpiece Mixer Right Output Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.708 {
+ iface MIXER
+ name 'Right Output Mixer Left Input Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.709 {
+ iface MIXER
+ name 'Right Output Mixer Right Input Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.710 {
+ iface MIXER
+ name 'Right Output Mixer IN2LN Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.711 {
+ iface MIXER
+ name 'Right Output Mixer IN2RN Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.712 {
+ iface MIXER
+ name 'Right Output Mixer IN1L Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.713 {
+ iface MIXER
+ name 'Right Output Mixer IN1R Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.714 {
+ iface MIXER
+ name 'Right Output Mixer IN2RP Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.715 {
+ iface MIXER
+ name 'Right Output Mixer DAC Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.716 {
+ iface MIXER
+ name 'Left Output Mixer Right Input Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.717 {
+ iface MIXER
+ name 'Left Output Mixer Left Input Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.718 {
+ iface MIXER
+ name 'Left Output Mixer IN2RN Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.719 {
+ iface MIXER
+ name 'Left Output Mixer IN2LN Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.720 {
+ iface MIXER
+ name 'Left Output Mixer IN2LP Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.721 {
+ iface MIXER
+ name 'Left Output Mixer IN1R Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.722 {
+ iface MIXER
+ name 'Left Output Mixer IN1L Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.723 {
+ iface MIXER
+ name 'Left Output Mixer DAC Switch'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.724 {
+ iface MIXER
+ name 'MIXINR IN2R Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.725 {
+ iface MIXER
+ name 'MIXINR IN1R Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.726 {
+ iface MIXER
+ name 'MIXINL IN2L Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.727 {
+ iface MIXER
+ name 'MIXINL IN1L Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.728 {
+ iface MIXER
+ name 'IN2R PGA IN2RP Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.729 {
+ iface MIXER
+ name 'IN2R PGA IN2RN Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.730 {
+ iface MIXER
+ name 'IN2L PGA IN2LP Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.731 {
+ iface MIXER
+ name 'IN2L PGA IN2LN Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.732 {
+ iface MIXER
+ name 'IN1R PGA IN1RP Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.733 {
+ iface MIXER
+ name 'IN1R PGA IN1RN Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.734 {
+ iface MIXER
+ name 'IN1L PGA IN1LP Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.735 {
+ iface MIXER
+ name 'IN1L PGA IN1LN Switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+}
+state.dummyaudio {
+ control.1 {
+ iface MIXER
+ name 'ssp1_out mux 0'
+ value fm
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 fm
+ item.1 bt
+ }
+ }
+ control.2 {
+ iface MIXER
+ name 'aware_out aware 0 switch'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.3 {
+ iface MIXER
+ name 'modem_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.4 {
+ iface MIXER
+ name 'modem_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.5 {
+ iface MIXER
+ name 'modem_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.6 {
+ iface MIXER
+ name 'modem_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.7 {
+ iface MIXER
+ name 'modem_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.8 {
+ iface MIXER
+ name 'modem_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.9 {
+ iface MIXER
+ name 'modem_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.10 {
+ iface MIXER
+ name 'modem_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.11 {
+ iface MIXER
+ name 'modem_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.12 {
+ iface MIXER
+ name 'modem_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.13 {
+ iface MIXER
+ name 'modem_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.14 {
+ iface MIXER
+ name 'modem_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.15 {
+ iface MIXER
+ name 'modem_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.16 {
+ iface MIXER
+ name 'modem_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.17 {
+ iface MIXER
+ name 'modem_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.18 {
+ iface MIXER
+ name 'modem_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.19 {
+ iface MIXER
+ name 'fm_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.20 {
+ iface MIXER
+ name 'fm_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.21 {
+ iface MIXER
+ name 'fm_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.22 {
+ iface MIXER
+ name 'fm_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.23 {
+ iface MIXER
+ name 'fm_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.24 {
+ iface MIXER
+ name 'fm_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.25 {
+ iface MIXER
+ name 'fm_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.26 {
+ iface MIXER
+ name 'fm_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.27 {
+ iface MIXER
+ name 'fm_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.28 {
+ iface MIXER
+ name 'fm_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.29 {
+ iface MIXER
+ name 'fm_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.30 {
+ iface MIXER
+ name 'fm_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.31 {
+ iface MIXER
+ name 'fm_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.32 {
+ iface MIXER
+ name 'fm_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.33 {
+ iface MIXER
+ name 'fm_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.34 {
+ iface MIXER
+ name 'fm_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.35 {
+ iface MIXER
+ name 'bt_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.36 {
+ iface MIXER
+ name 'bt_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.37 {
+ iface MIXER
+ name 'bt_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.38 {
+ iface MIXER
+ name 'bt_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.39 {
+ iface MIXER
+ name 'bt_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.40 {
+ iface MIXER
+ name 'bt_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.41 {
+ iface MIXER
+ name 'bt_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.42 {
+ iface MIXER
+ name 'bt_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.43 {
+ iface MIXER
+ name 'bt_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.44 {
+ iface MIXER
+ name 'bt_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.45 {
+ iface MIXER
+ name 'bt_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.46 {
+ iface MIXER
+ name 'bt_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.47 {
+ iface MIXER
+ name 'bt_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.48 {
+ iface MIXER
+ name 'bt_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.49 {
+ iface MIXER
+ name 'bt_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.50 {
+ iface MIXER
+ name 'bt_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.51 {
+ iface MIXER
+ name 'codec_out1 mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.52 {
+ iface MIXER
+ name 'codec_out1 mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.53 {
+ iface MIXER
+ name 'codec_out1 mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.54 {
+ iface MIXER
+ name 'codec_out1 mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.55 {
+ iface MIXER
+ name 'codec_out1 mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.56 {
+ iface MIXER
+ name 'codec_out1 mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.57 {
+ iface MIXER
+ name 'codec_out1 mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.58 {
+ iface MIXER
+ name 'codec_out1 mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.59 {
+ iface MIXER
+ name 'codec_out1 mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.60 {
+ iface MIXER
+ name 'codec_out1 mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.61 {
+ iface MIXER
+ name 'codec_out1 mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.62 {
+ iface MIXER
+ name 'codec_out1 mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.63 {
+ iface MIXER
+ name 'codec_out1 mix 0 pcm0_in'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.64 {
+ iface MIXER
+ name 'codec_out1 mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.65 {
+ iface MIXER
+ name 'codec_out1 mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.66 {
+ iface MIXER
+ name 'codec_out1 mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.67 {
+ iface MIXER
+ name 'codec_out0 mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.68 {
+ iface MIXER
+ name 'codec_out0 mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.69 {
+ iface MIXER
+ name 'codec_out0 mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.70 {
+ iface MIXER
+ name 'codec_out0 mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.71 {
+ iface MIXER
+ name 'codec_out0 mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.72 {
+ iface MIXER
+ name 'codec_out0 mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.73 {
+ iface MIXER
+ name 'codec_out0 mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.74 {
+ iface MIXER
+ name 'codec_out0 mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.75 {
+ iface MIXER
+ name 'codec_out0 mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.76 {
+ iface MIXER
+ name 'codec_out0 mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.77 {
+ iface MIXER
+ name 'codec_out0 mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.78 {
+ iface MIXER
+ name 'codec_out0 mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.79 {
+ iface MIXER
+ name 'codec_out0 mix 0 pcm0_in'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.80 {
+ iface MIXER
+ name 'codec_out0 mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.81 {
+ iface MIXER
+ name 'codec_out0 mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.82 {
+ iface MIXER
+ name 'codec_out0 mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.83 {
+ iface MIXER
+ name 'rxspeech_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.84 {
+ iface MIXER
+ name 'rxspeech_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.85 {
+ iface MIXER
+ name 'rxspeech_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.86 {
+ iface MIXER
+ name 'rxspeech_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.87 {
+ iface MIXER
+ name 'rxspeech_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.88 {
+ iface MIXER
+ name 'rxspeech_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.89 {
+ iface MIXER
+ name 'rxspeech_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.90 {
+ iface MIXER
+ name 'rxspeech_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.91 {
+ iface MIXER
+ name 'rxspeech_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.92 {
+ iface MIXER
+ name 'rxspeech_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.93 {
+ iface MIXER
+ name 'rxspeech_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.94 {
+ iface MIXER
+ name 'rxspeech_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.95 {
+ iface MIXER
+ name 'rxspeech_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.96 {
+ iface MIXER
+ name 'rxspeech_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.97 {
+ iface MIXER
+ name 'rxspeech_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.98 {
+ iface MIXER
+ name 'rxspeech_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.99 {
+ iface MIXER
+ name 'speech_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.100 {
+ iface MIXER
+ name 'speech_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.101 {
+ iface MIXER
+ name 'speech_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.102 {
+ iface MIXER
+ name 'speech_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.103 {
+ iface MIXER
+ name 'speech_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.104 {
+ iface MIXER
+ name 'speech_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.105 {
+ iface MIXER
+ name 'speech_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.106 {
+ iface MIXER
+ name 'speech_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.107 {
+ iface MIXER
+ name 'speech_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.108 {
+ iface MIXER
+ name 'speech_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.109 {
+ iface MIXER
+ name 'speech_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.110 {
+ iface MIXER
+ name 'speech_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.111 {
+ iface MIXER
+ name 'speech_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.112 {
+ iface MIXER
+ name 'speech_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.113 {
+ iface MIXER
+ name 'speech_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.114 {
+ iface MIXER
+ name 'speech_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.115 {
+ iface MIXER
+ name 'hf_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.116 {
+ iface MIXER
+ name 'hf_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.117 {
+ iface MIXER
+ name 'hf_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.118 {
+ iface MIXER
+ name 'hf_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.119 {
+ iface MIXER
+ name 'hf_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.120 {
+ iface MIXER
+ name 'hf_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.121 {
+ iface MIXER
+ name 'hf_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.122 {
+ iface MIXER
+ name 'hf_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.123 {
+ iface MIXER
+ name 'hf_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.124 {
+ iface MIXER
+ name 'hf_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.125 {
+ iface MIXER
+ name 'hf_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.126 {
+ iface MIXER
+ name 'hf_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.127 {
+ iface MIXER
+ name 'hf_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.128 {
+ iface MIXER
+ name 'hf_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.129 {
+ iface MIXER
+ name 'hf_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.130 {
+ iface MIXER
+ name 'hf_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.131 {
+ iface MIXER
+ name 'hf_sns_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.132 {
+ iface MIXER
+ name 'hf_sns_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.133 {
+ iface MIXER
+ name 'hf_sns_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.134 {
+ iface MIXER
+ name 'hf_sns_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.135 {
+ iface MIXER
+ name 'hf_sns_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.136 {
+ iface MIXER
+ name 'hf_sns_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.137 {
+ iface MIXER
+ name 'hf_sns_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.138 {
+ iface MIXER
+ name 'hf_sns_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.139 {
+ iface MIXER
+ name 'hf_sns_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.140 {
+ iface MIXER
+ name 'hf_sns_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.141 {
+ iface MIXER
+ name 'hf_sns_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.142 {
+ iface MIXER
+ name 'hf_sns_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.143 {
+ iface MIXER
+ name 'hf_sns_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.144 {
+ iface MIXER
+ name 'hf_sns_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.145 {
+ iface MIXER
+ name 'hf_sns_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.146 {
+ iface MIXER
+ name 'hf_sns_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.147 {
+ iface MIXER
+ name 'vad_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.148 {
+ iface MIXER
+ name 'vad_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.149 {
+ iface MIXER
+ name 'vad_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.150 {
+ iface MIXER
+ name 'vad_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.151 {
+ iface MIXER
+ name 'vad_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.152 {
+ iface MIXER
+ name 'vad_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.153 {
+ iface MIXER
+ name 'vad_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.154 {
+ iface MIXER
+ name 'vad_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.155 {
+ iface MIXER
+ name 'vad_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.156 {
+ iface MIXER
+ name 'vad_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.157 {
+ iface MIXER
+ name 'vad_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.158 {
+ iface MIXER
+ name 'vad_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.159 {
+ iface MIXER
+ name 'vad_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.160 {
+ iface MIXER
+ name 'vad_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.161 {
+ iface MIXER
+ name 'vad_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.162 {
+ iface MIXER
+ name 'vad_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.163 {
+ iface MIXER
+ name 'aware_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.164 {
+ iface MIXER
+ name 'aware_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.165 {
+ iface MIXER
+ name 'aware_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.166 {
+ iface MIXER
+ name 'aware_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.167 {
+ iface MIXER
+ name 'aware_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.168 {
+ iface MIXER
+ name 'aware_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.169 {
+ iface MIXER
+ name 'aware_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.170 {
+ iface MIXER
+ name 'aware_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.171 {
+ iface MIXER
+ name 'aware_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.172 {
+ iface MIXER
+ name 'aware_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.173 {
+ iface MIXER
+ name 'aware_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.174 {
+ iface MIXER
+ name 'aware_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.175 {
+ iface MIXER
+ name 'aware_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.176 {
+ iface MIXER
+ name 'aware_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.177 {
+ iface MIXER
+ name 'aware_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.178 {
+ iface MIXER
+ name 'aware_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.179 {
+ iface MIXER
+ name 'voip_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.180 {
+ iface MIXER
+ name 'voip_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.181 {
+ iface MIXER
+ name 'voip_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.182 {
+ iface MIXER
+ name 'voip_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.183 {
+ iface MIXER
+ name 'voip_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.184 {
+ iface MIXER
+ name 'voip_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.185 {
+ iface MIXER
+ name 'voip_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.186 {
+ iface MIXER
+ name 'voip_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.187 {
+ iface MIXER
+ name 'voip_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.188 {
+ iface MIXER
+ name 'voip_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.189 {
+ iface MIXER
+ name 'voip_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.190 {
+ iface MIXER
+ name 'voip_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.191 {
+ iface MIXER
+ name 'voip_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.192 {
+ iface MIXER
+ name 'voip_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.193 {
+ iface MIXER
+ name 'voip_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.194 {
+ iface MIXER
+ name 'voip_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.195 {
+ iface MIXER
+ name 'media_loop2_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.196 {
+ iface MIXER
+ name 'media_loop2_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.197 {
+ iface MIXER
+ name 'media_loop2_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.198 {
+ iface MIXER
+ name 'media_loop2_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.199 {
+ iface MIXER
+ name 'media_loop2_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.200 {
+ iface MIXER
+ name 'media_loop2_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.201 {
+ iface MIXER
+ name 'media_loop2_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.202 {
+ iface MIXER
+ name 'media_loop2_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.203 {
+ iface MIXER
+ name 'media_loop2_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.204 {
+ iface MIXER
+ name 'media_loop2_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.205 {
+ iface MIXER
+ name 'media_loop2_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.206 {
+ iface MIXER
+ name 'media_loop2_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.207 {
+ iface MIXER
+ name 'media_loop2_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.208 {
+ iface MIXER
+ name 'media_loop2_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.209 {
+ iface MIXER
+ name 'media_loop2_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.210 {
+ iface MIXER
+ name 'media_loop2_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.211 {
+ iface MIXER
+ name 'media_loop1_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.212 {
+ iface MIXER
+ name 'media_loop1_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.213 {
+ iface MIXER
+ name 'media_loop1_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.214 {
+ iface MIXER
+ name 'media_loop1_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.215 {
+ iface MIXER
+ name 'media_loop1_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.216 {
+ iface MIXER
+ name 'media_loop1_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.217 {
+ iface MIXER
+ name 'media_loop1_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.218 {
+ iface MIXER
+ name 'media_loop1_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.219 {
+ iface MIXER
+ name 'media_loop1_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.220 {
+ iface MIXER
+ name 'media_loop1_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.221 {
+ iface MIXER
+ name 'media_loop1_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.222 {
+ iface MIXER
+ name 'media_loop1_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.223 {
+ iface MIXER
+ name 'media_loop1_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.224 {
+ iface MIXER
+ name 'media_loop1_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.225 {
+ iface MIXER
+ name 'media_loop1_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.226 {
+ iface MIXER
+ name 'media_loop1_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.227 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.228 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.229 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.230 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.231 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.232 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.233 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.234 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.235 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.236 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.237 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.238 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.239 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.240 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.241 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.242 {
+ iface MIXER
+ name 'sprot_loop_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.243 {
+ iface MIXER
+ name 'pcm2_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.244 {
+ iface MIXER
+ name 'pcm2_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.245 {
+ iface MIXER
+ name 'pcm2_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.246 {
+ iface MIXER
+ name 'pcm2_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.247 {
+ iface MIXER
+ name 'pcm2_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.248 {
+ iface MIXER
+ name 'pcm2_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.249 {
+ iface MIXER
+ name 'pcm2_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.250 {
+ iface MIXER
+ name 'pcm2_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.251 {
+ iface MIXER
+ name 'pcm2_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.252 {
+ iface MIXER
+ name 'pcm2_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.253 {
+ iface MIXER
+ name 'pcm2_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.254 {
+ iface MIXER
+ name 'pcm2_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.255 {
+ iface MIXER
+ name 'pcm2_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.256 {
+ iface MIXER
+ name 'pcm2_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.257 {
+ iface MIXER
+ name 'pcm2_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.258 {
+ iface MIXER
+ name 'pcm2_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.259 {
+ iface MIXER
+ name 'pcm1_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.260 {
+ iface MIXER
+ name 'pcm1_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.261 {
+ iface MIXER
+ name 'pcm1_out mix 0 codec_in0'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.262 {
+ iface MIXER
+ name 'pcm1_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.263 {
+ iface MIXER
+ name 'pcm1_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.264 {
+ iface MIXER
+ name 'pcm1_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.265 {
+ iface MIXER
+ name 'pcm1_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.266 {
+ iface MIXER
+ name 'pcm1_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.267 {
+ iface MIXER
+ name 'pcm1_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.268 {
+ iface MIXER
+ name 'pcm1_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.269 {
+ iface MIXER
+ name 'pcm1_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.270 {
+ iface MIXER
+ name 'pcm1_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.271 {
+ iface MIXER
+ name 'pcm1_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.272 {
+ iface MIXER
+ name 'pcm1_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.273 {
+ iface MIXER
+ name 'pcm1_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.274 {
+ iface MIXER
+ name 'pcm1_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.275 {
+ iface MIXER
+ name 'pcm0_out mix 0 modem_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.276 {
+ iface MIXER
+ name 'pcm0_out mix 0 bt_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.277 {
+ iface MIXER
+ name 'pcm0_out mix 0 codec_in0'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.278 {
+ iface MIXER
+ name 'pcm0_out mix 0 codec_in1'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.279 {
+ iface MIXER
+ name 'pcm0_out mix 0 sprot_loop_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.280 {
+ iface MIXER
+ name 'pcm0_out mix 0 media_loop1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.281 {
+ iface MIXER
+ name 'pcm0_out mix 0 media_loop2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.282 {
+ iface MIXER
+ name 'pcm0_out mix 0 sidetone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.283 {
+ iface MIXER
+ name 'pcm0_out mix 0 txspeech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.284 {
+ iface MIXER
+ name 'pcm0_out mix 0 speech_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.285 {
+ iface MIXER
+ name 'pcm0_out mix 0 tone_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.286 {
+ iface MIXER
+ name 'pcm0_out mix 0 voip_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.287 {
+ iface MIXER
+ name 'pcm0_out mix 0 pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.288 {
+ iface MIXER
+ name 'pcm0_out mix 0 pcm1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.289 {
+ iface MIXER
+ name 'pcm0_out mix 0 low_pcm0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.290 {
+ iface MIXER
+ name 'pcm0_out mix 0 fm_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.291 {
+ iface MIXER
+ name 'media1_out mix 0 media0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.292 {
+ iface MIXER
+ name 'media1_out mix 0 media1_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.293 {
+ iface MIXER
+ name 'media1_out mix 0 media2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.294 {
+ iface MIXER
+ name 'media1_out mix 0 media3_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.295 {
+ iface MIXER
+ name 'media0_out mix 0 media0_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.296 {
+ iface MIXER
+ name 'media0_out mix 0 media1_in'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.297 {
+ iface MIXER
+ name 'media0_out mix 0 media2_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.298 {
+ iface MIXER
+ name 'media0_out mix 0 media3_in'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.299 {
+ iface MIXER
+ name 'media0_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.300 {
+ iface MIXER
+ name 'media0_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.301 {
+ iface MIXER
+ name 'media0_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.302 {
+ iface MIXER
+ name 'media1_in gain 0 rampduration'
+ value 50
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.303 {
+ iface MIXER
+ name 'media1_in gain 0 mute'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.304 {
+ iface MIXER
+ name 'media1_in gain 0 volume'
+ value.0 0
+ value.1 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.305 {
+ iface MIXER
+ name 'media2_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.306 {
+ iface MIXER
+ name 'media2_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.307 {
+ iface MIXER
+ name 'media2_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.308 {
+ iface MIXER
+ name 'media3_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.309 {
+ iface MIXER
+ name 'media3_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.310 {
+ iface MIXER
+ name 'media3_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.311 {
+ iface MIXER
+ name 'pcm0_in gain 0 rampduration'
+ value 50
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.312 {
+ iface MIXER
+ name 'pcm0_in gain 0 mute'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.313 {
+ iface MIXER
+ name 'pcm0_in gain 0 volume'
+ value.0 0
+ value.1 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.314 {
+ iface MIXER
+ name 'pcm1_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.315 {
+ iface MIXER
+ name 'pcm1_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.316 {
+ iface MIXER
+ name 'pcm1_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.317 {
+ iface MIXER
+ name 'low_pcm0_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.318 {
+ iface MIXER
+ name 'low_pcm0_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.319 {
+ iface MIXER
+ name 'low_pcm0_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.320 {
+ iface MIXER
+ name 'pcm1_out gain 0 rampduration'
+ value 50
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.321 {
+ iface MIXER
+ name 'pcm1_out gain 0 mute'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.322 {
+ iface MIXER
+ name 'pcm1_out gain 0 volume'
+ value.0 0
+ value.1 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.323 {
+ iface MIXER
+ name 'pcm2_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.324 {
+ iface MIXER
+ name 'pcm2_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.325 {
+ iface MIXER
+ name 'pcm2_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.326 {
+ iface MIXER
+ name 'voip_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.327 {
+ iface MIXER
+ name 'voip_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.328 {
+ iface MIXER
+ name 'voip_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.329 {
+ iface MIXER
+ name 'voip_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.330 {
+ iface MIXER
+ name 'voip_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.331 {
+ iface MIXER
+ name 'voip_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.332 {
+ iface MIXER
+ name 'tone_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.333 {
+ iface MIXER
+ name 'tone_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.334 {
+ iface MIXER
+ name 'tone_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.335 {
+ iface MIXER
+ name 'aware_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.336 {
+ iface MIXER
+ name 'aware_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.337 {
+ iface MIXER
+ name 'aware_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.338 {
+ iface MIXER
+ name 'vad_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.339 {
+ iface MIXER
+ name 'vad_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.340 {
+ iface MIXER
+ name 'vad_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.341 {
+ iface MIXER
+ name 'hf_sns_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.342 {
+ iface MIXER
+ name 'hf_sns_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.343 {
+ iface MIXER
+ name 'hf_sns_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.344 {
+ iface MIXER
+ name 'hf_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.345 {
+ iface MIXER
+ name 'hf_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.346 {
+ iface MIXER
+ name 'hf_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.347 {
+ iface MIXER
+ name 'speech_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.348 {
+ iface MIXER
+ name 'speech_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.349 {
+ iface MIXER
+ name 'speech_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.350 {
+ iface MIXER
+ name 'txspeech_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.351 {
+ iface MIXER
+ name 'txspeech_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.352 {
+ iface MIXER
+ name 'txspeech_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.353 {
+ iface MIXER
+ name 'rxspeech_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.354 {
+ iface MIXER
+ name 'rxspeech_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.355 {
+ iface MIXER
+ name 'rxspeech_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.356 {
+ iface MIXER
+ name 'speech_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.357 {
+ iface MIXER
+ name 'speech_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.358 {
+ iface MIXER
+ name 'speech_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.359 {
+ iface MIXER
+ name 'codec_in0 gain 0 rampduration'
+ value 50
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.360 {
+ iface MIXER
+ name 'codec_in0 gain 0 mute'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.361 {
+ iface MIXER
+ name 'codec_in0 gain 0 volume'
+ value.0 0
+ value.1 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.362 {
+ iface MIXER
+ name 'codec_in1 gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.363 {
+ iface MIXER
+ name 'codec_in1 gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.364 {
+ iface MIXER
+ name 'codec_in1 gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.365 {
+ iface MIXER
+ name 'codec_out0 gain 0 rampduration'
+ value 50
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.366 {
+ iface MIXER
+ name 'codec_out0 gain 0 mute'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.367 {
+ iface MIXER
+ name 'codec_out0 gain 0 volume'
+ value.0 0
+ value.1 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.368 {
+ iface MIXER
+ name 'codec_out1 gain 0 rampduration'
+ value 50
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.369 {
+ iface MIXER
+ name 'codec_out1 gain 0 mute'
+ value false
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.370 {
+ iface MIXER
+ name 'codec_out1 gain 0 volume'
+ value.0 0
+ value.1 0
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 0
+ dbvalue.1 0
+ }
+ }
+ control.371 {
+ iface MIXER
+ name 'bt_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.372 {
+ iface MIXER
+ name 'bt_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.373 {
+ iface MIXER
+ name 'bt_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.374 {
+ iface MIXER
+ name 'fm_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.375 {
+ iface MIXER
+ name 'fm_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.376 {
+ iface MIXER
+ name 'fm_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.377 {
+ iface MIXER
+ name 'bt_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.378 {
+ iface MIXER
+ name 'bt_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.379 {
+ iface MIXER
+ name 'bt_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.380 {
+ iface MIXER
+ name 'fm_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.381 {
+ iface MIXER
+ name 'fm_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.382 {
+ iface MIXER
+ name 'fm_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.383 {
+ iface MIXER
+ name 'modem_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.384 {
+ iface MIXER
+ name 'modem_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.385 {
+ iface MIXER
+ name 'modem_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.386 {
+ iface MIXER
+ name 'modem_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.387 {
+ iface MIXER
+ name 'modem_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.388 {
+ iface MIXER
+ name 'modem_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.389 {
+ iface MIXER
+ name 'media_loop1_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.390 {
+ iface MIXER
+ name 'media_loop1_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.391 {
+ iface MIXER
+ name 'media_loop1_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.392 {
+ iface MIXER
+ name 'media_loop2_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.393 {
+ iface MIXER
+ name 'media_loop2_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.394 {
+ iface MIXER
+ name 'media_loop2_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.395 {
+ iface MIXER
+ name 'sprot_loop_out gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.396 {
+ iface MIXER
+ name 'sprot_loop_out gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.397 {
+ iface MIXER
+ name 'sprot_loop_out gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.398 {
+ iface MIXER
+ name 'media0_in volume 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.399 {
+ iface MIXER
+ name 'media0_in volume 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.400 {
+ iface MIXER
+ name 'media0_in volume 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.401 {
+ iface MIXER
+ name 'sidetone_in gain 0 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.402 {
+ iface MIXER
+ name 'sidetone_in gain 0 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.403 {
+ iface MIXER
+ name 'sidetone_in gain 0 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.404 {
+ iface MIXER
+ name 'speech_out gain 1 rampduration'
+ value 5
+ comment {
+ access 'read write'
+ type INTEGER
+ count 1
+ range '5 - 5000'
+ }
+ }
+ control.405 {
+ iface MIXER
+ name 'speech_out gain 1 mute'
+ value true
+ comment {
+ access 'read write'
+ type BOOLEAN
+ count 1
+ }
+ }
+ control.406 {
+ iface MIXER
+ name 'speech_out gain 1 volume'
+ value.0 -1440
+ value.1 -1440
+ comment {
+ access 'read write'
+ type INTEGER
+ count 2
+ range '-1440 - 360'
+ dbmin -14400
+ dbmax 3600
+ dbvalue.0 -14400
+ dbvalue.1 -14400
+ }
+ }
+ control.407 {
+ iface MIXER
+ name 'media_loop1_out fir 0 params'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 138
+ }
+ }
+ control.408 {
+ iface MIXER
+ name 'media_loop1_out iir 0 params'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 300
+ }
+ }
+ control.409 {
+ iface MIXER
+ name 'media_loop1_out mdrp 0 params'
+ value '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 76
+ }
+ }
+ control.410 {
+ iface MIXER
+ name 'media_loop2_out fir 0 params'
+ value '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 272
+ }
+ }
+ control.411 {
+ iface MIXER
+ name 'media_loop2_out iir 0 params'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 300
+ }
+ }
+ control.412 {
+ iface MIXER
+ name 'media_loop2_out mdrp 0 params'
+ value '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 76
+ }
+ }
+ control.413 {
+ iface MIXER
+ name 'aware_out fir 0 params'
+ value '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 272
+ }
+ }
+ control.414 {
+ iface MIXER
+ name 'aware_out iir 0 params'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 300
+ }
+ }
+ control.415 {
+ iface MIXER
+ name 'aware_out aware 0 params'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 48
+ }
+ }
+ control.416 {
+ iface MIXER
+ name 'vad_out fir 0 params'
+ value '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 272
+ }
+ }
+ control.417 {
+ iface MIXER
+ name 'vad_out iir 0 params'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 300
+ }
+ }
+ control.418 {
+ iface MIXER
+ name 'sprot_loop_out lpro 0 params'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 192
+ }
+ }
+ control.419 {
+ iface MIXER
+ name 'codec_in0 dcr 0 params'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 300
+ }
+ }
+ control.420 {
+ iface MIXER
+ name 'codec_in1 dcr 0 params'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 300
+ }
+ }
+ control.421 {
+ iface MIXER
+ name 'speech_out ul_module 0 params fir_speech'
+ value '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 136
+ }
+ }
+ control.422 {
+ iface MIXER
+ name 'speech_out ul_module 0 params fir_hf_sns'
+ value '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 136
+ }
+ }
+ control.423 {
+ iface MIXER
+ name 'speech_out ul_module 0 params iir_speech'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 48
+ }
+ }
+ control.424 {
+ iface MIXER
+ name 'speech_out ul_module 0 params iir_hf_sns'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 48
+ }
+ }
+ control.425 {
+ iface MIXER
+ name 'speech_out ul_module 0 params aec'
+ value '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 640
+ }
+ }
+ control.426 {
+ iface MIXER
+ name 'speech_out ul_module 0 params nr'
+ value '0000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 38
+ }
+ }
+ control.427 {
+ iface MIXER
+ name 'speech_out ul_module 0 params agc'
+ value '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 58
+ }
+ }
+ control.428 {
+ iface MIXER
+ name 'speech_out ul_module 0 params biquad'
+ value '00000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 22
+ }
+ }
+ control.429 {
+ iface MIXER
+ name 'speech_out ul_module 0 params compr'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 36
+ }
+ }
+ control.430 {
+ iface MIXER
+ name 'speech_out ul_module 0 params sns'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 324
+ }
+ }
+ control.431 {
+ iface MIXER
+ name 'speech_out ul_module 0 params ser'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 42
+ }
+ }
+ control.432 {
+ iface MIXER
+ name 'speech_out ul_module 0 params cni'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 48
+ }
+ }
+ control.433 {
+ iface MIXER
+ name 'speech_out ul_module 0 params ref'
+ value '000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 24
+ }
+ }
+ control.434 {
+ iface MIXER
+ name 'speech_out ul_module 0 params delay'
+ value '000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 6
+ }
+ }
+ control.435 {
+ iface MIXER
+ name 'speech_out ul_module 0 params bmf'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 264
+ }
+ }
+ control.436 {
+ iface MIXER
+ name 'speech_out ul_module 0 params dnr'
+ value '000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 18
+ }
+ }
+ control.437 {
+ iface MIXER
+ name 'speech_in dl_module 0 params ana'
+ value '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 52
+ }
+ }
+ control.438 {
+ iface MIXER
+ name 'speech_in dl_module 0 params fir'
+ value '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 136
+ }
+ }
+ control.439 {
+ iface MIXER
+ name 'speech_in dl_module 0 params iir'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 48
+ }
+ }
+ control.440 {
+ iface MIXER
+ name 'speech_in dl_module 0 params nr'
+ value '0000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 38
+ }
+ }
+ control.441 {
+ iface MIXER
+ name 'speech_in dl_module 0 params biquad'
+ value '00000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 22
+ }
+ }
+ control.442 {
+ iface MIXER
+ name 'speech_in dl_module 0 params compr'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 36
+ }
+ }
+ control.443 {
+ iface MIXER
+ name 'speech_in dl_module 0 params cni'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 48
+ }
+ }
+ control.444 {
+ iface MIXER
+ name 'speech_in dl_module 0 params bwx'
+ value '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 54
+ }
+ }
+ control.445 {
+ iface MIXER
+ name 'speech_in dl_module 0 params gmm'
+ value '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 586
+ }
+ }
+ control.446 {
+ iface MIXER
+ name 'speech_in dl_module 0 params glc'
+ value '000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 18
+ }
+ }
+ control.447 {
+ iface MIXER
+ name 'codec_out interleaver slot 0'
+ value codec_out0_0
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 none
+ item.1 codec_out0_0
+ item.2 codec_out0_1
+ item.3 codec_out1_0
+ item.4 codec_out1_1
+ }
+ }
+ control.448 {
+ iface MIXER
+ name 'codec_out interleaver slot 1'
+ value codec_out0_1
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 none
+ item.1 codec_out0_0
+ item.2 codec_out0_1
+ item.3 codec_out1_0
+ item.4 codec_out1_1
+ }
+ }
+ control.449 {
+ iface MIXER
+ name 'codec_out interleaver slot 2'
+ value codec_out1_0
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 none
+ item.1 codec_out0_0
+ item.2 codec_out0_1
+ item.3 codec_out1_0
+ item.4 codec_out1_1
+ }
+ }
+ control.450 {
+ iface MIXER
+ name 'codec_out interleaver slot 3'
+ value codec_out1_1
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 none
+ item.1 codec_out0_0
+ item.2 codec_out0_1
+ item.3 codec_out1_0
+ item.4 codec_out1_1
+ }
+ }
+ control.451 {
+ iface MIXER
+ name 'codec_in deinterleaver codec_in0_0'
+ value 'slot 0'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 none
+ item.1 'slot 0'
+ item.2 'slot 1'
+ item.3 'slot 2'
+ item.4 'slot 3'
+ }
+ }
+ control.452 {
+ iface MIXER
+ name 'codec_in deinterleaver codec_in0_1'
+ value 'slot 1'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 none
+ item.1 'slot 0'
+ item.2 'slot 1'
+ item.3 'slot 2'
+ item.4 'slot 3'
+ }
+ }
+ control.453 {
+ iface MIXER
+ name 'codec_in deinterleaver codec_in1_0'
+ value 'slot 2'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 none
+ item.1 'slot 0'
+ item.2 'slot 1'
+ item.3 'slot 2'
+ item.4 'slot 3'
+ }
+ }
+ control.454 {
+ iface MIXER
+ name 'codec_in deinterleaver codec_in1_1'
+ value 'slot 3'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 none
+ item.1 'slot 0'
+ item.2 'slot 1'
+ item.3 'slot 2'
+ item.4 'slot 3'
+ }
+ }
+ control.455 {
+ iface MIXER
+ name 'domain voice mode 0'
+ value narrowband
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 narrowband
+ item.1 wideband
+ }
+ }
+ control.456 {
+ iface MIXER
+ name 'domain bt mode 0'
+ value narrowband
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 narrowband
+ item.1 wideband
+ }
+ }
+ control.457 {
+ iface MIXER
+ name 'sst debug byte control'
+ value '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ comment {
+ access 'read write'
+ type BYTES
+ count 512
+ }
+ }
+ control.458 {
+ iface MIXER
+ name 'probe out0 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.459 {
+ iface MIXER
+ name 'probe out1 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.460 {
+ iface MIXER
+ name 'probe out2 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.461 {
+ iface MIXER
+ name 'probe out3 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.462 {
+ iface MIXER
+ name 'probe out4 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.463 {
+ iface MIXER
+ name 'probe out5 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.464 {
+ iface MIXER
+ name 'probe out6 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.465 {
+ iface MIXER
+ name 'probe out7 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.466 {
+ iface MIXER
+ name 'probe in0 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.467 {
+ iface MIXER
+ name 'probe in1 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.468 {
+ iface MIXER
+ name 'probe in2 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.469 {
+ iface MIXER
+ name 'probe in3 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.470 {
+ iface MIXER
+ name 'probe in4 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.471 {
+ iface MIXER
+ name 'probe in5 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.472 {
+ iface MIXER
+ name 'probe in6 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+ control.473 {
+ iface MIXER
+ name 'probe in7 connection'
+ value 'media0_in gain'
+ comment {
+ access 'read write'
+ type ENUMERATED
+ count 1
+ item.0 'media0_in gain'
+ item.1 'media1_in gain'
+ item.2 'media2_in gain'
+ item.3 'media3_in gain'
+ item.4 'pcm0_in gain'
+ item.5 'pcm1_in gain'
+ item.6 'pcm1_out gain'
+ item.7 'pcm2_out gain'
+ item.8 'voip_in gain'
+ item.9 'voip_out gain'
+ item.10 'aware_out gain'
+ item.11 'vad_out gain'
+ item.12 'hf_sns_out gain'
+ item.13 'hf_out gain'
+ item.14 'speech_out gain'
+ item.15 'txspeech_in gain'
+ item.16 'rxspeech_out gain'
+ item.17 'speech_in gain'
+ item.18 'media_loop1_out gain'
+ item.19 'media_loop2_out gain'
+ item.20 'tone_in gain'
+ item.21 'codec_out0 gain'
+ item.22 'codec_out1 gain'
+ item.23 'bt_out gain'
+ item.24 'fm_out gain'
+ item.25 'modem_out gain'
+ item.26 'codec_in0 gain'
+ item.27 'codec_in1 gain'
+ item.28 'bt_in gain'
+ item.29 'fm_in gain'
+ item.30 'modem_in gain'
+ }
+ }
+}
diff --git a/meta-edison-distro/recipes-multimedia/libav/libav_0.8.9.bbappend b/meta-edison-distro/recipes-multimedia/libav/libav_0.8.9.bbappend
new file mode 100644
index 0000000..939e988
--- /dev/null
+++ b/meta-edison-distro/recipes-multimedia/libav/libav_0.8.9.bbappend
@@ -0,0 +1,23 @@
+# Disable features that have potential commercial licensing restrictions
+EXTRA_OECONF += "\
+ --disable-encoder=libmp3lame \
+ --disable-decoder=mp3 \
+ --disable-decoder=mp3adu \
+ --disable-decoder=mp3adufloat \
+ --disable-decoder=mp3float \
+ --disable-decoder=mp3on4 \
+ --disable-decoder=mp3on4float \
+ --disable-muxer=mp3 \
+ --disable-demuxer=mp3 \
+ --disable-bsf=mp3_header_decompress \
+ --disable-bsf=mp3_header_compress \
+ \
+ --disable-encoder=mpeg2video \
+ --disable-decoder=mpeg2video \
+ --disable-hwaccel=mpeg2_vaapi\
+ --disable-hwaccel=mpeg2_dxva2\
+ --disable-muxer=mpeg2dvd \
+ --disable-muxer=mpeg2svcd \
+ --disable-muxer=mpeg2video \
+ --disable-muxer=mpeg2vob \
+"
diff --git a/meta-edison-distro/recipes-multimedia/mplayer/mplayer-common.bb b/meta-edison-distro/recipes-multimedia/mplayer/mplayer-common.bb
new file mode 100644
index 0000000..889bb95
--- /dev/null
+++ b/meta-edison-distro/recipes-multimedia/mplayer/mplayer-common.bb
@@ -0,0 +1,22 @@
+# Copyright Matthias Hentges <devel@hentges.net> (c) 2006
+# License: MIT (see COPYING.MIT)
+
+DESCRIPTION = "Preconfigured mplayer preferences"
+
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://${COREBASE}/meta/COPYING.MIT;md5=3da9cfbcb788c80a0384361b4de20420"
+
+PV = "0.0.1"
+
+SRC_URI = "file://mplayer.conf"
+
+# Yes, really /usr/etc!!!
+do_install() {
+ install -d "${D}/usr${sysconfdir}/mplayer"
+
+ install -m 0644 ${WORKDIR}/mplayer.conf "${D}/usr${sysconfdir}/mplayer"
+}
+
+FILES_${PN} = "/usr${sysconfdir}/mplayer"
+
+inherit allarch
diff --git a/meta-edison-distro/recipes-multimedia/mplayer/mplayer-common/mplayer.conf b/meta-edison-distro/recipes-multimedia/mplayer/mplayer-common/mplayer.conf
new file mode 100644
index 0000000..37ad65f
--- /dev/null
+++ b/meta-edison-distro/recipes-multimedia/mplayer/mplayer-common/mplayer.conf
@@ -0,0 +1,15 @@
+
+# You probably shouldn't touch these
+ac=mad,
+ao=alsa,
+
+# Required on SL-Cxxxx for correct rotation in the *VT*,
+# breaks rotation in X!
+# vf=rotate=1
+
+# Enable fullscreen display by default
+# fs=true
+
+# Drop frames to keep audio and video in sync
+framedrop=true
+
diff --git a/meta-edison-distro/recipes-multimedia/mplayer/mplayer2/cross.compile.codec-cfg.patch b/meta-edison-distro/recipes-multimedia/mplayer/mplayer2/cross.compile.codec-cfg.patch
new file mode 100644
index 0000000..7b290b5
--- /dev/null
+++ b/meta-edison-distro/recipes-multimedia/mplayer/mplayer2/cross.compile.codec-cfg.patch
@@ -0,0 +1,16 @@
+Upstream-Status: Pending
+Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com>
+
+diff --git a/Makefile b/Makefile
+index 6013ca3..28c6383 100644
+--- a/Makefile
++++ b/Makefile
+@@ -600,7 +602,7 @@ mplayer$(EXESUF):
+ $(CC) -o $@ $^ $(EXTRALIBS)
+
+ codec-cfg$(EXESUF): codec-cfg.c codec-cfg.h
+- $(HOST_CC) -O -DCODECS2HTML -I. -o $@ $<
++ $(BUILD_CC) -O -DCODECS2HTML -I. -Iffmpeg -o $@ $<
+
+ codecs.conf.h: codec-cfg$(EXESUF) etc/codecs.conf
+ ./$^ > $@
diff --git a/meta-edison-distro/recipes-multimedia/mplayer/mplayer2_git.bb b/meta-edison-distro/recipes-multimedia/mplayer/mplayer2_git.bb
new file mode 100644
index 0000000..820bffa
--- /dev/null
+++ b/meta-edison-distro/recipes-multimedia/mplayer/mplayer2_git.bb
@@ -0,0 +1,161 @@
+DESCRIPTION = "Open Source multimedia player."
+SECTION = "multimedia"
+HOMEPAGE = "http://www.mplayerhq.hu/"
+DEPENDS = "libtheora ffmpeg zlib libpng jpeg liba52 freetype fontconfig alsa-lib lzo ncurses lame pulseaudio \
+ ${@base_conditional('ENTERPRISE_DISTRO', '1', '', 'libmad liba52 lame', d)}"
+
+RDEPENDS_${PN} = "mplayer-common"
+PROVIDES = "mplayer"
+RPROVIDES_${PN} = "mplayer"
+RCONFLICTS_${PN} = "mplayer"
+
+LICENSE = "GPLv3"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=d32239bcb673463ab874e80d47fae504"
+
+SRC_URI = "git://repo.or.cz/mplayer.git;protocol=git;branch=master \
+ file://cross.compile.codec-cfg.patch \
+"
+
+SRCREV = "e3f5043233336d8b4b0731c6a8b42a8fda5535ac"
+
+ARM_INSTRUCTION_SET = "arm"
+
+PV = "2.0+gitr${SRCPV}"
+PR = "r8"
+
+PARALLEL_MAKE = ""
+
+S = "${WORKDIR}/git"
+
+FILES_${PN} = "${bindir}/mplayer ${libdir} /usr/etc/mplayer/"
+CONFFILES_${PN} += "/usr/etc/mplayer/input.conf \
+ /usr/etc/mplayer/example.conf \
+ /usr/etc/mplayer/codecs.conf \
+ "
+
+inherit autotools pkgconfig
+
+EXTRA_OECONF = " \
+ --prefix=/usr \
+ --mandir=${mandir} \
+ --target=${SIMPLE_TARGET_SYS} \
+ \
+ --disable-fontconfig \
+ --disable-libass \
+ --disable-lirc \
+ --disable-lircc \
+ --disable-joystick \
+ --disable-vm \
+ --disable-xf86keysym \
+ --disable-tv \
+ --disable-tv-v4l1 \
+ --disable-tv-v4l2 \
+ --disable-tv-bsdbt848 \
+ --enable-rtc \
+ --disable-networking \
+ --disable-smb \
+ --disable-live \
+ --disable-dvdnav \
+ --disable-dvdread \
+ --disable-dvdread-internal \
+ --disable-libdvdcss-internal \
+ --disable-cdparanoia \
+ --enable-freetype \
+ --disable-sortsub \
+ --disable-fribidi \
+ --disable-enca \
+ --disable-ftp \
+ --disable-vstream \
+ \
+ --disable-gif \
+ --disable-png \
+ --disable-jpeg \
+ --disable-libcdio \
+ --disable-qtx \
+ --disable-xanim \
+ --disable-real \
+ --disable-xvid \
+ \
+ --disable-mpg123 \
+ --disable-speex \
+ --enable-theora \
+ --disable-ladspa \
+ --disable-libdv \
+ --disable-mad \
+ --disable-xmms \
+ --disable-musepack \
+ \
+ --disable-gl \
+ --disable-vesa \
+ --disable-svga \
+ --disable-sdl \
+ --disable-aa \
+ --disable-caca \
+ --disable-ggi \
+ --disable-ggiwmh \
+ --disable-directx \
+ --disable-dxr3 \
+ --disable-dvb \
+ --disable-mga \
+ --disable-xmga \
+ --disable-xv \
+ --disable-vm \
+ --disable-xinerama \
+ --disable-x11 \
+ --disable-fbdev \
+ --disable-3dfx \
+ --disable-tdfxfb \
+ --disable-s3fb \
+ --disable-directfb \
+ --disable-bl \
+ --disable-tdfxvid \
+ --disable-tga \
+ --disable-pnm \
+ --disable-md5sum \
+ \
+ --disable-alsa \
+ --disable-ossaudio \
+ --disable-arts \
+ --disable-esd \
+ --enable-pulse \
+ --disable-jack \
+ --disable-openal \
+ --disable-nas \
+ --disable-sgiaudio \
+ --disable-sunaudio \
+ --disable-win32waveout \
+ --enable-select \
+ \
+ --extra-libs=' -lstdc++ -lvorbis ' \
+"
+
+EXTRA_OECONF_append_armv6 = " --enable-armv6"
+EXTRA_OECONF_append_armv7a = " --enable-armv6 --enable-neon"
+
+FULL_OPTIMIZATION = "-fexpensive-optimizations -fomit-frame-pointer -frename-registers -O4 -ffast-math"
+BUILD_OPTIMIZATION = "${FULL_OPTIMIZATION}"
+
+CFLAGS_append = " -I${S}/libdvdread4 "
+
+do_configure() {
+ sed -i 's|/usr/include|${STAGING_INCDIR}|g' ${S}/configure
+ sed -i 's|/usr/lib|${STAGING_LIBDIR}|g' ${S}/configure
+ sed -i 's|/usr/\S*include[\w/]*||g' ${S}/configure
+ sed -i 's|/usr/\S*lib[\w/]*||g' ${S}/configure
+ sed -i 's|_install_strip="-s"|_install_strip=""|g' ${S}/configure
+ sed -i 's|HOST_CC|BUILD_CC|' ${S}/Makefile
+
+ export SIMPLE_TARGET_SYS="$(echo ${TARGET_SYS} | sed s:${TARGET_VENDOR}::g)"
+ ./configure ${EXTRA_OECONF}
+}
+
+do_compile () {
+ oe_runmake
+}
+
+do_install_append() {
+ install -d ${D}/usr/etc/mplayer
+ install ${S}/etc/input.conf ${D}/usr/etc/mplayer/
+ install ${S}/etc/example.conf ${D}/usr/etc/mplayer/
+ install ${S}/etc/codecs.conf ${D}/usr/etc/mplayer/
+}
diff --git a/meta-edison-distro/recipes-multimedia/pulseaudio/files/pulseaudio.service b/meta-edison-distro/recipes-multimedia/pulseaudio/files/pulseaudio.service
new file mode 100644
index 0000000..0f43b1f
--- /dev/null
+++ b/meta-edison-distro/recipes-multimedia/pulseaudio/files/pulseaudio.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=PulseAudio Sound System
+After=alsa-restore.service
+
+[Service]
+BusName=org.pulseaudio.Server
+ExecStart=/usr/bin/pulseaudio --system --resample-method=src-sinc-fastest
+Restart=always
+
+[Install]
+WantedBy=multi-user.target
+
diff --git a/meta-edison-distro/recipes-multimedia/pulseaudio/files/system.pa b/meta-edison-distro/recipes-multimedia/pulseaudio/files/system.pa
new file mode 100644
index 0000000..77e5a35
--- /dev/null
+++ b/meta-edison-distro/recipes-multimedia/pulseaudio/files/system.pa
@@ -0,0 +1,66 @@
+#!/usr/bin/pulseaudio -nF
+#
+# This file is part of PulseAudio.
+#
+# PulseAudio is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# PulseAudio is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with PulseAudio; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+# This startup script is used only if PulseAudio is started in system
+# mode.
+
+### Automatically load driver modules depending on the hardware available
+.ifexists module-udev-detect.so
+load-module module-udev-detect
+.else
+### Use the static hardware detection module (for systems that lack udev/hal support)
+load-module module-detect
+.endif
+
+### Load several protocols
+.ifexists module-esound-protocol-unix.so
+load-module module-esound-protocol-unix
+.endif
+load-module module-native-protocol-unix
+
+### Load bluetooth modules
+.ifexists module-bluetooth-policy.so
+load-module module-bluetooth-policy
+.endif
+
+.ifexists module-bluez5-discover.so
+load-module module-bluez5-discover
+.endif
+
+### Automatically restore the volume of streams and devices
+load-module module-stream-restore
+load-module module-device-restore
+
+### Automatically restore the default sink/source when changed by the user
+### during runtime
+### NOTE: This should be loaded as early as possible so that subsequent modules
+### that look up the default sink/source get the right value
+load-module module-default-device-restore
+
+### Automatically move streams to the default sink if the sink they are
+### connected to dies, similar for sources
+load-module module-rescue-streams
+
+### Make sure we always have a sink around, even if it is a null sink.
+load-module module-always-sink
+
+### Automatically suspend sinks/sources that become idle for too long
+load-module module-suspend-on-idle
+
+### Enable positioned event sounds
+load-module module-position-event-sounds \ No newline at end of file
diff --git a/meta-edison-distro/recipes-multimedia/pulseaudio/pulseaudio-service_1.0.bb b/meta-edison-distro/recipes-multimedia/pulseaudio/pulseaudio-service_1.0.bb
new file mode 100644
index 0000000..e8e10b5
--- /dev/null
+++ b/meta-edison-distro/recipes-multimedia/pulseaudio/pulseaudio-service_1.0.bb
@@ -0,0 +1,28 @@
+DESCRIPTION = "Pulseaudio systemd service"
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+
+inherit systemd useradd
+
+DEPENDS = "pulseaudio"
+
+SRC_URI += "\
+ file://pulseaudio.service \
+ "
+
+SYSTEMD_SERVICE_${PN} = "pulseaudio.service"
+
+FILES_${PN} = " \
+ ${systemd_unitdir} \
+"
+
+USERADD_PACKAGES = "pulseaudio-service"
+GROUPMEMS_PARAM_pulseaudio-service = " --add root --group audio"
+
+do_install_append() {
+ if ${@base_contains('DISTRO_FEATURES','systemd','true','false',d)}; then
+ install -d ${D}${systemd_unitdir}/system
+ install -m 0644 ${WORKDIR}/pulseaudio.service ${D}/${systemd_unitdir}/system/
+ fi
+}
+
diff --git a/meta-edison-distro/recipes-multimedia/pulseaudio/pulseaudio_5.0.bbappend b/meta-edison-distro/recipes-multimedia/pulseaudio/pulseaudio_5.0.bbappend
new file mode 100644
index 0000000..7900344
--- /dev/null
+++ b/meta-edison-distro/recipes-multimedia/pulseaudio/pulseaudio_5.0.bbappend
@@ -0,0 +1,22 @@
+# Overlay the pulseaudio recipe to embed bluetooth modules for A2DP
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/files/"
+
+SRC_URI += "\
+ file://system.pa \
+ "
+
+PACKAGECONFIG ??= "${@base_contains('DISTRO_FEATURES', 'bluetooth', 'bluez5', '', d)} \
+ ${@base_contains('DISTRO_FEATURES', 'systemd', 'systemd', '', d)} \
+ ${@base_contains('DISTRO_FEATURES', 'zeroconf', 'avahi', '', d)} \
+ ${@base_contains('DISTRO_FEATURES', 'x11', 'x11', '', d)}"
+
+RDEPENDS_pulseaudio-server += " \
+ pulseaudio-module-loopback \
+ pulseaudio-module-bluez5-discover \
+ pulseaudio-module-bluez5-device \
+ pulseaudio-module-bluetooth-policy"
+
+do_install_append() {
+ install -m 0644 ${WORKDIR}/system.pa ${D}/${sysconfdir}/pulse/
+}
diff --git a/meta-edison-distro/recipes-support/blink-led/blink-led_0.1.bb b/meta-edison-distro/recipes-support/blink-led/blink-led_0.1.bb
new file mode 100644
index 0000000..9fff7d2
--- /dev/null
+++ b/meta-edison-distro/recipes-support/blink-led/blink-led_0.1.bb
@@ -0,0 +1,23 @@
+DESCRIPTION = "Blinks the Edison LED"
+SECTION = "base"
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/files/"
+
+SRC_URI = "file://blink-led"
+SRC_URI += "file://blink-led.service"
+
+S = "${WORKDIR}"
+
+do_install() {
+ install -d ${D}${bindir}
+ install -m 0755 blink-led ${D}${bindir}
+
+ # Copy service file
+ install -d ${D}/${systemd_unitdir}/system
+ install -m 644 ${WORKDIR}/blink-led.service ${D}/${systemd_unitdir}/system
+}
+
+FILES_${PN} += "${base_libdir}/systemd/system/blink-led.service"
+FILES_${PN} += "${bindir}/blink-led"
diff --git a/meta-edison-distro/recipes-support/blink-led/files/blink-led b/meta-edison-distro/recipes-support/blink-led/files/blink-led
new file mode 100755
index 0000000..f8b884f
--- /dev/null
+++ b/meta-edison-distro/recipes-support/blink-led/files/blink-led
@@ -0,0 +1,109 @@
+#!/usr/bin/env python
+
+#
+# Edison LED blinker
+#
+# Copyright (c) 2014, Intel Corporation.
+# Fabien Chereau <fabien.chereau@intel.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+# This is a very poor implementation as it uses subprocesses for init
+
+import subprocess
+import time
+import argparse
+import signal
+import sys
+
+initial_led_state = "high"
+
+def write_led(value):
+ with open("/sys/class/gpio/gpio40/direction","w") as lf:
+ lf.write(value)
+
+def blink_once():
+ write_led("low")
+ time.sleep(1./args.frequency*args.duty_cycle)
+ write_led("high")
+ time.sleep(1./args.frequency*(1.-args.duty_cycle))
+
+def deinit_led_gpio():
+ # Revert to default state with LED activated
+ write_led(initial_led_state)
+
+ # Deinit LED GPIO
+ subprocess.call("""
+ echo 40 >/sys/class/gpio/unexport
+ echo 214 >/sys/class/gpio/unexport
+ echo 243 >/sys/class/gpio/unexport
+ echo 261 >/sys/class/gpio/unexport
+ """, shell=True)
+
+def signal_term_handler(signal, frame):
+ print 'Signal intercepted: de-initing LED GPIOs'
+ deinit_led_gpio()
+ sys.exit(0)
+
+
+parser = argparse.ArgumentParser(description='Blink the Edison Arduino board LED.')
+parser.add_argument('--frequency', type=float, default=4, help='blink frequency in Hz')
+parser.add_argument('--duration', type=float, default=-1, help='duration of the blink in seconds. Negative value means no timeout, i.e. it will stop when the program is killed.')
+parser.add_argument('--duty_cycle', type=float, default=0.5, help='duty cycle between 0 and 1')
+
+args = parser.parse_args()
+
+# Allows to quit cleanly with CRTL+C or SIGTERM (systemd use SIGTERM to kill a service by default)
+signal.signal(signal.SIGTERM, signal_term_handler)
+signal.signal(signal.SIGINT, signal_term_handler)
+
+# Init GPIO mux for LED control
+subprocess.call("""
+echo 40 >/sys/class/gpio/export
+echo 214 >/sys/class/gpio/export
+echo 243 >/sys/class/gpio/export
+echo 261 >/sys/class/gpio/export
+echo high >/sys/class/gpio/gpio214/direction
+echo mode0 > /sys/kernel/debug/gpio_debug/gpio40/current_pinmux
+echo low >/sys/class/gpio/gpio243/direction
+echo high >/sys/class/gpio/gpio261/direction
+echo low >/sys/class/gpio/gpio214/direction""", shell=True)
+
+# Save current LED value for reverting to proper state at exit
+try:
+ lf = open("/sys/class/gpio/gpio40/value","r")
+ v = lf.read()
+ lf.close()
+ if v[0] == '0':
+ initial_led_state = "low"
+ else:
+ initial_led_state = "high"
+except:
+ print "Can't get current LED state"
+
+# Blink LED
+if args.duration >= 0:
+ for i in range(0, int(args.duration*args.frequency)):
+ blink_once()
+else:
+ while True:
+ blink_once()
+
+deinit_led_gpio()
+
diff --git a/meta-edison-distro/recipes-support/blink-led/files/blink-led.service b/meta-edison-distro/recipes-support/blink-led/files/blink-led.service
new file mode 100644
index 0000000..3dcb2ab
--- /dev/null
+++ b/meta-edison-distro/recipes-support/blink-led/files/blink-led.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Edison Arduino board LED Blinker
+
+[Service]
+ExecStart=/usr/bin/blink-led
+Restart=on-failure
+
+[Install]
+WantedBy=basic.target
+
diff --git a/meta-edison-distro/recipes-support/cleanjournal/cleanjournal.bb b/meta-edison-distro/recipes-support/cleanjournal/cleanjournal.bb
new file mode 100644
index 0000000..cc21638
--- /dev/null
+++ b/meta-edison-distro/recipes-support/cleanjournal/cleanjournal.bb
@@ -0,0 +1,31 @@
+DESCRIPTION = "Cleanjournal tool. Remove all corrupted journald entries at startup."
+SECTION = "base"
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+
+
+SRC_URI += "file://cleanjournal.service"
+SRC_URI += "file://clean_journal.sh"
+
+SYSTEMD_SERVICE_${PN} = "cleanjournal.service"
+
+RDEPENDS_${PN} = "systemd"
+DEPENDS = "systemd"
+inherit systemd
+
+do_install() {
+ # install service file
+ install -d ${D}${systemd_unitdir}/system
+ install -c -m 0644 ${WORKDIR}/cleanjournal.service ${D}${systemd_unitdir}/system
+
+ # install cleanjournal script
+ install -d ${D}${sbindir}
+ install -c -m 0755 ${WORKDIR}/clean_journal.sh ${D}${sbindir}
+}
+
+# As this package is tied to systemd, only build it when we're also building systemd.
+python () {
+ if not oe.utils.contains ('DISTRO_FEATURES', 'systemd', True, False, d):
+ raise bb.parse.SkipPackage("'systemd' not in DISTRO_FEATURES")
+}
+
diff --git a/meta-edison-distro/recipes-support/cleanjournal/files/clean_journal.sh b/meta-edison-distro/recipes-support/cleanjournal/files/clean_journal.sh
new file mode 100644
index 0000000..5758d09
--- /dev/null
+++ b/meta-edison-distro/recipes-support/cleanjournal/files/clean_journal.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+
+#
+# Cleanjournal script
+#
+# Copyright (c) 2014, Intel Corporation.
+# Fabien Rodriguez <fabienx.rodriguez@intel.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+
+#
+# This script checks if the remaining space in root partition is lower than 10%.
+# In that case, the corrupted journald entries (ended by '~') will be deleted
+# one by one until remaining space becomes greater or equal to 10%.
+# At each boot, the script is launched by systemd at startup.
+#
+
+# max allowed free space is 10%
+max_allowed_free_space=10
+
+# check remaining space and update clean_journal_needed variable
+check_free_space() {
+ current_free_space=$(df -h | grep /dev/root | awk '{print 100 - $5}' | sed 's/%//')
+ if [ "$current_free_space" -lt "$max_allowed_free_space" ]; then
+ clean_journal_needed=true
+ else
+ clean_journal_needed=false
+ fi
+}
+
+check_free_space
+if [ "$clean_journal_needed" = true ]; then
+ # delete each journald corrupted entry
+ # until remaining space becomes greater than 10%
+ for corrupted_journal_file in $(find /var/log/journal/ -name '*~'); do
+ rm "$corrupted_journal_file"
+ check_free_space
+ if [ "$clean_journal_needed" = false ]; then
+ break
+ fi
+ done
+fi
+
diff --git a/meta-edison-distro/recipes-support/cleanjournal/files/cleanjournal.service b/meta-edison-distro/recipes-support/cleanjournal/files/cleanjournal.service
new file mode 100644
index 0000000..ab704f3
--- /dev/null
+++ b/meta-edison-distro/recipes-support/cleanjournal/files/cleanjournal.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Cleanjournal service
+
+[Service]
+ExecStart=/usr/sbin/clean_journal.sh
+Restart=no
+
+[Install]
+WantedBy=basic.target
+
diff --git a/meta-edison-distro/recipes-support/crashlog/crashlog.bb b/meta-edison-distro/recipes-support/crashlog/crashlog.bb
new file mode 100644
index 0000000..2ef10ce
--- /dev/null
+++ b/meta-edison-distro/recipes-support/crashlog/crashlog.bb
@@ -0,0 +1,31 @@
+DESCRIPTION = "Crashlog tool. Retrieve last saved kernel message in case of crash"
+SECTION = "base"
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+
+
+SRC_URI += "file://crashlog.service"
+SRC_URI += "file://retrieve_crashlog.sh"
+
+SYSTEMD_SERVICE_${PN} = "crashlog.service"
+
+RDEPENDS_${PN} = "systemd"
+DEPENDS = "systemd"
+inherit systemd
+
+do_install() {
+ # install service file
+ install -d ${D}${systemd_unitdir}/system
+ install -c -m 0644 ${WORKDIR}/crashlog.service ${D}${systemd_unitdir}/system
+
+ # install crashlog script
+ install -d ${D}${sbindir}
+ install -c -m 0755 ${WORKDIR}/retrieve_crashlog.sh ${D}${sbindir}
+}
+
+# As this package is tied to systemd, only build it when we're also building systemd.
+python () {
+ if not oe.utils.contains ('DISTRO_FEATURES', 'systemd', True, False, d):
+ raise bb.parse.SkipPackage("'systemd' not in DISTRO_FEATURES")
+}
+
diff --git a/meta-edison-distro/recipes-support/crashlog/files/crashlog.service b/meta-edison-distro/recipes-support/crashlog/files/crashlog.service
new file mode 100644
index 0000000..a2c7aab
--- /dev/null
+++ b/meta-edison-distro/recipes-support/crashlog/files/crashlog.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Crashlog service
+
+[Service]
+ExecStart=/usr/sbin/retrieve_crashlog.sh
+Restart=no
+
+[Install]
+WantedBy=basic.target
+
diff --git a/meta-edison-distro/recipes-support/crashlog/files/retrieve_crashlog.sh b/meta-edison-distro/recipes-support/crashlog/files/retrieve_crashlog.sh
new file mode 100755
index 0000000..a7f007c
--- /dev/null
+++ b/meta-edison-distro/recipes-support/crashlog/files/retrieve_crashlog.sh
@@ -0,0 +1,98 @@
+#!/bin/sh
+
+#
+# Crashlog script
+#
+# Copyright (c) 2014, Intel Corporation.
+# Simon Desfarges <simonx.desfarges@intel.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+
+#
+# This script automatically gather kernel logs in case of crashing.
+# At each boot, the script is launched by systemd at startup.
+# It detects the boot reason and in case of watchdog reboot
+# (saying the platform hanged) the script will save the kernel
+# log into a file named crashlog_xxxx.
+#
+
+ipanic_console_path=/proc/emmc_ipanic_console
+crashlog_path=/home/root
+
+# line containing 'WAKESRC' looks like:
+# 'Jan 01 00:00:12 edison kernel: [BOOT] WAKESRC=[real reset] (osnib)'
+# wakesrc is the 4th field with [ and ] separators
+# List of available wake sources is in driver/platform/x86/intel_scu_ipcutil.c
+
+wakesrc=$(journalctl -k -b -0 | grep WAKESRC | awk -F'[][]' '{print $4}')
+
+# any watchdog boot implies a crash
+tmp=$(echo -n "${wakesrc}" | grep watchdog)
+if [ -n "${tmp}" ]; then
+ # get the last sequence number (ie for crashlog_00001, get the 1)
+ last_sequence_number=$(ls ${crashlog_path}/crashlog_* | tail -1 | awk -F_ '{print $NF}' | awk -F. '{print $NR}')
+ if [ -z $last_sequence_number ]; then
+ last_sequence_number="0"
+ fi
+
+ new_sequence_number=$(expr ${last_sequence_number} + 1)
+ new_name=$(printf "crashlog_%05d" $new_sequence_number)
+
+ # create working directory
+ mkdir ${crashlog_path}/${new_name}
+
+ # write crashfile
+ crashfile_path=${crashlog_path}/${new_name}/crashfile
+
+ event="CRASH"
+ manufacturer="Intel Corporation"
+ product_name=$(cat /factory/hardware_model)
+ version=$(cat /factory/hardware_version)
+ serial_number=$(cat /factory/serial_number)
+ linux_version=$(uname -a)
+ build_version=$(cat /etc/version)
+ date=$(date)
+
+ echo "EVENT=${event}" > ${crashfile_path}
+ echo "Manufacturer : ${manufacturer}" >> ${crashfile_path}
+ echo "Product name : ${product_name}" >> ${crashfile_path}
+ echo "Version : ${version}" >> ${crashfile_path}
+ echo "Serial Number : ${serial_number}" >> ${crashfile_path}
+ echo "Linux version : ${linux_version}" >> ${crashfile_path}
+ echo "Build version : ${build_version}" >> ${crashfile_path}
+ echo "Date : ${date}" >> ${crashfile_path}
+ echo -e "Wake source : ${wakesrc}" >> ${crashfile_path}
+
+ # write full journal binary & logs from previous boot
+ journalctl -b -1 -o short-monotonic > ${crashlog_path}/${new_name}/journal_logs
+ journalctl -b -1 -o export > ${crashlog_path}/${new_name}/journal_binary
+
+ # write panic trace
+ if [ -e ${ipanic_console_path} ]; then
+ cat ${ipanic_console_path} > ${crashlog_path}/${new_name}/panic
+ echo clear > ${ipanic_console_path}
+ fi
+
+ # create archive and clear folder
+ tar -zcf ${crashlog_path}/${new_name}.tar.gz -C ${crashlog_path} ${new_name}
+ rm -rf ${crashlog_path}/${new_name}
+
+fi
+
diff --git a/meta-edison-distro/recipes-support/edison-mcu/files/intel_mcu.bin b/meta-edison-distro/recipes-support/edison-mcu/files/intel_mcu.bin
new file mode 100644
index 0000000..dcf0544
--- /dev/null
+++ b/meta-edison-distro/recipes-support/edison-mcu/files/intel_mcu.bin
Binary files differ
diff --git a/meta-edison-distro/recipes-support/edison-mcu/files/mcu_fw_loader.service b/meta-edison-distro/recipes-support/edison-mcu/files/mcu_fw_loader.service
new file mode 100644
index 0000000..0057ab6
--- /dev/null
+++ b/meta-edison-distro/recipes-support/edison-mcu/files/mcu_fw_loader.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Daemon to load edison mcu app binary
+After=syslog.target
+
+[Service]
+ExecStart=/etc/intel_mcu/mcu_fw_loader.sh
+
+[Install]
+WantedBy=multi-user.target
+
diff --git a/meta-edison-distro/recipes-support/edison-mcu/files/mcu_fw_loader.sh b/meta-edison-distro/recipes-support/edison-mcu/files/mcu_fw_loader.sh
new file mode 100644
index 0000000..734352d
--- /dev/null
+++ b/meta-edison-distro/recipes-support/edison-mcu/files/mcu_fw_loader.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+#author: JiuJin Hong (jiujinx.hong@intel.com)
+if [ ! -d "/sys/devices/platform/intel_mcu" ];then
+ exit
+fi
+
+if [ ! -f "/lib/firmware/intel_mcu.bin" ];then
+ exit
+fi
+
+echo "load mcu app" > /sys/devices/platform/intel_mcu/control
+
diff --git a/meta-edison-distro/recipes-support/edison-mcu/mcu-fw-bin_0.1.bb b/meta-edison-distro/recipes-support/edison-mcu/mcu-fw-bin_0.1.bb
new file mode 100644
index 0000000..eafb813
--- /dev/null
+++ b/meta-edison-distro/recipes-support/edison-mcu/mcu-fw-bin_0.1.bb
@@ -0,0 +1,17 @@
+DESCRIPTION = "This is edison mcu fw binary."
+HOMEPAGE = "http://www.intel.com"
+LICENSE = "CLOSED"
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/files/"
+
+SRC_URI = "file://intel_mcu.bin"
+
+S = "${WORKDIR}"
+
+do_install () {
+ install -v -d ${D}/${base_libdir}/firmware/
+ install -m 644 intel_mcu.bin ${D}/${base_libdir}/firmware/
+}
+
+FILES_${PN} = "${base_libdir}/firmware/"
+
diff --git a/meta-edison-distro/recipes-support/edison-mcu/mcu-fw-load_0.1.bb b/meta-edison-distro/recipes-support/edison-mcu/mcu-fw-load_0.1.bb
new file mode 100644
index 0000000..a48aa10
--- /dev/null
+++ b/meta-edison-distro/recipes-support/edison-mcu/mcu-fw-load_0.1.bb
@@ -0,0 +1,23 @@
+DESCRIPTION = "This is intel mcu app download daemon."
+HOMEPAGE = "http://www.intel.com"
+LICENSE = "CLOSED"
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/files/"
+
+SRC_URI = "file://mcu_fw_loader.service \
+ file://mcu_fw_loader.sh"
+
+SYSTEMD_SERVICE_${PN} = "mcu_fw_loader.service"
+
+S = "${WORKDIR}"
+
+inherit systemd
+
+do_install () {
+ install -d ${D}${sysconfdir}/intel_mcu/
+ install -m 0755 mcu_fw_loader.sh ${D}${sysconfdir}/intel_mcu/
+
+ install -d ${D}${systemd_unitdir}/system/
+ install -m 0644 mcu_fw_loader.service ${D}${systemd_unitdir}/system/
+}
+
diff --git a/meta-edison-distro/recipes-support/edison-sst/files/fw_sst_119a.bin b/meta-edison-distro/recipes-support/edison-sst/files/fw_sst_119a.bin
new file mode 100644
index 0000000..b704fb6
--- /dev/null
+++ b/meta-edison-distro/recipes-support/edison-sst/files/fw_sst_119a.bin
Binary files differ
diff --git a/meta-edison-distro/recipes-support/edison-sst/sst-fw-bin_0.1.bb b/meta-edison-distro/recipes-support/edison-sst/sst-fw-bin_0.1.bb
new file mode 100644
index 0000000..a6c7021
--- /dev/null
+++ b/meta-edison-distro/recipes-support/edison-sst/sst-fw-bin_0.1.bb
@@ -0,0 +1,19 @@
+DESCRIPTION = "This is edison sst fw binary."
+HOMEPAGE = "http://www.intel.com"
+LICENSE = "CLOSED"
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/files/"
+
+SRC_URI = "file://fw_sst_119a.bin"
+
+S = "${WORKDIR}"
+
+do_install () {
+ install -v -d ${D}/${base_libdir}/firmware/
+ install -m 644 fw_sst_119a.bin ${D}/${base_libdir}/firmware/
+}
+
+INSANE_SKIP_${PN} = "arch"
+
+FILES_${PN} = "${base_libdir}/firmware/"
+
diff --git a/meta-edison-distro/recipes-support/i2c-tools/i2c-tools-3.0.3/Module.mk b/meta-edison-distro/recipes-support/i2c-tools/i2c-tools-3.0.3/Module.mk
new file mode 100644
index 0000000..7c7b636
--- /dev/null
+++ b/meta-edison-distro/recipes-support/i2c-tools/i2c-tools-3.0.3/Module.mk
@@ -0,0 +1,72 @@
+# EEPROMER
+#
+# Licensed under the GNU General Public License.
+
+EEPROMER_DIR := eepromer
+
+EEPROMER_CFLAGS := -Wstrict-prototypes -Wshadow -Wpointer-arith -Wcast-qual \
+ -Wcast-align -Wwrite-strings -Wnested-externs -Winline \
+ -W -Wundef -Wmissing-prototypes -Iinclude
+
+EEPROMER_TARGETS := eepromer eeprom eeprog
+
+#
+# Programs
+#
+
+$(EEPROMER_DIR)/eepromer: $(EEPROMER_DIR)/eepromer.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
+$(EEPROMER_DIR)/eeprom: $(EEPROMER_DIR)/eeprom.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
+$(EEPROMER_DIR)/eeprog: $(EEPROMER_DIR)/eeprog.o $(EEPROMER_DIR)/24cXX.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
+#
+# Objects
+#
+
+$(EEPROMER_DIR)/eepromer.o: $(EEPROMER_DIR)/eepromer.c
+ $(CC) $(CFLAGS) $(EEPROMER_CFLAGS) -c $< -o $@
+
+$(EEPROMER_DIR)/eeprom.o: $(EEPROMER_DIR)/eeprom.c
+ $(CC) $(CFLAGS) $(EEPROMER_CFLAGS) -c $< -o $@
+
+$(EEPROMER_DIR)/eeprog.o: $(EEPROMER_DIR)/eeprog.c
+ $(CC) $(CFLAGS) $(EEPROMER_CFLAGS) -c $< -o $@
+
+$(EEPROMER_DIR)/24cXX.o: $(EEPROMER_DIR)/24cXX.c
+ $(CC) $(CFLAGS) $(EEPROMER_CFLAGS) -c $< -o $@
+
+#
+# Commands
+#
+
+all-eepromer: $(addprefix $(EEPROMER_DIR)/,$(EEPROMER_TARGETS))
+
+strip-eepromer: $(addprefix $(EEPROMER_DIR)/,$(EEPROMER_TARGETS))
+ strip $(addprefix $(EEPROMER_DIR)/,$(EEPROMER_TARGETS))
+
+clean-eepromer:
+ $(RM) $(addprefix $(EEPROMER_DIR)/,*.o $(EEPROMER_TARGETS))
+
+install-eepromer: $(addprefix $(EEPROMER_DIR)/,$(EEPROMER_TARGETS))
+ $(INSTALL_DIR) $(DESTDIR)$(sbindir) $(DESTDIR)$(man8dir)
+ for program in $(EEPROMER_TARGETS) ; do \
+ $(INSTALL_PROGRAM) $(EEPROMER_DIR)/$$program $(DESTDIR)$(sbindir) ; done
+
+uninstall-eepromer:
+ for program in $(EEPROMER_TARGETS) ; do \
+ $(RM) $(DESTDIR)$(sbindir)/$$program ; \
+ $(RM) $(DESTDIR)$(man8dir)/$$program.8 ; done
+
+all: all-eepromer
+
+strip: strip-eepromer
+
+clean: clean-eepromer
+
+install: install-eepromer
+
+uninstall: uninstall-eepromer
diff --git a/meta-edison-distro/recipes-support/i2c-tools/i2c-tools_3.0.3.bb b/meta-edison-distro/recipes-support/i2c-tools/i2c-tools_3.0.3.bb
new file mode 100644
index 0000000..021090c
--- /dev/null
+++ b/meta-edison-distro/recipes-support/i2c-tools/i2c-tools_3.0.3.bb
@@ -0,0 +1,24 @@
+DESCRIPTION = "Set of i2c tools for linux"
+SECTION = "base"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://COPYING;md5=751419260aa954499f7abaabaa882bbe"
+
+SRC_URI = "http://dl.lm-sensors.org/i2c-tools/releases/i2c-tools-${PV}.tar.bz2 \
+ file://Module.mk \
+ "
+SRC_URI[md5sum] = "511376eed04455cdb277ef19c5f73bb4"
+SRC_URI[sha256sum] = "23b28e474741834e3f1b35b0686528769a13adc92d2ff5603cbda1d6bd5e5629"
+
+inherit autotools
+
+do_compile_prepend() {
+ cp ${WORKDIR}/Module.mk ${S}/eepromer/
+ sed -i 's#/usr/local#/usr#' Makefile
+ echo "include eepromer/Module.mk" >> Makefile
+}
+
+do_install_append() {
+ install -d ${D}${includedir}/linux
+ install -m 0644 include/linux/i2c-dev.h ${D}${includedir}/linux/i2c-dev-user.h
+ rm -f ${D}${includedir}/linux/i2c-dev.h
+}
diff --git a/meta-edison-distro/recipes-support/pwr-button-handler/files/pwr-button-handler.c b/meta-edison-distro/recipes-support/pwr-button-handler/files/pwr-button-handler.c
new file mode 100644
index 0000000..d598160
--- /dev/null
+++ b/meta-edison-distro/recipes-support/pwr-button-handler/files/pwr-button-handler.c
@@ -0,0 +1,167 @@
+/*
+ * Edison PWR button handler
+ *
+ * Copyright (c) 2014, Intel Corporation.
+ * Fabien Chereau <fabien.chereau@intel.com>
+ * Loïc Akue <loicx.akue@intel.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/poll.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+
+/* See full definitions in include/linux/input.h */
+/* Also find more doc in Documentation/input/input.txt */
+#define EV_KEY 0x01
+/* Edison Arduino board PWR button code */
+#define KEY_POWER 116
+
+/* We use 2 seconds for now */
+#define EDISON_OOBE_PRESS_TIMEOUT 2
+
+struct input_event {
+ struct timeval time;
+ unsigned short type;
+ unsigned short code;
+ unsigned int value;
+};
+
+
+int main(int argc, char **argv)
+{
+ struct timeval tv;
+ struct input_event event;
+ struct pollfd p;
+ int fd, n;
+ ssize_t len;
+
+ if (argc!=3)
+ {
+ printf("Usage:\n");
+ printf(" %s \"command_line1\" \"command_line2\"\n", argv[0]);
+ printf(" command_line1: a command line to execute when the PWR button is pressed for more than 2s\n");
+ printf(" command_line2: a second command line to execute when the PWR button is released (after being pressed for more than 2s)\n");
+ return -1;
+ }
+
+
+ /* Time of the last press event.
+ We reset this to zero when the button is released */
+ time_t time_at_last_press = 0;
+
+ int event_already_fired = 0;
+
+ fd = open("/dev/input/event1", O_RDONLY);
+ if (fd < 0) {
+ perror("Can't open /dev/input/event1 device");
+ return fd;
+ }
+
+ memset(&p, 0, sizeof(p));
+ p.fd = fd;
+ p.events = POLLIN;
+
+ while (1) {
+ /* Refresh every 20 ms if the user already started pressing the button */
+ n = poll(&p, 1, time_at_last_press==0 ? -1 : 20);
+ if (n < 0) {
+ perror("Failed to poll /dev/input/event1 device");
+ break;
+ }
+ if (n==0) {
+ /* Poll timed out */
+ gettimeofday(&tv, NULL);
+ if (tv.tv_sec - time_at_last_press >= EDISON_OOBE_PRESS_TIMEOUT && event_already_fired == 0)
+ {
+ event_already_fired = 1;
+ printf("Edison PWR button was pressed more than 2s\n");
+ fflush(stdout);
+ system(argv[1]);
+ }
+ continue;
+ }
+
+ len = read(fd, &event, sizeof(event));
+ if (len < 0) {
+ perror("Reading of /dev/input/event1 events failed");
+ break;
+ }
+
+ if (len != sizeof(event)) {
+ perror("Wrong size of input_event struct");
+ break;
+ }
+
+ /* ignore non KEY event, and non PWR button events */
+ if (event.type != EV_KEY || event.code != KEY_POWER)
+ continue;
+
+ gettimeofday(&tv, NULL);
+
+#ifndef NDEBUG
+ printf("%ld.%06u: type=%u code=%u value=%u\n",
+ (long) tv.tv_sec, (unsigned int) tv.tv_usec,
+ event.type, event.code, event.value);
+ fflush(stdout);
+#endif
+
+ switch (event.value)
+ {
+ case 1: /* Regular press */
+ assert(time_at_last_press==0);
+ assert(event_already_fired==0);
+ time_at_last_press = tv.tv_sec;
+ break;
+ case 2: /* Auto repeat press */
+ if (time_at_last_press == 0)
+ {
+ /* This could happen if the user start pressing before the kernel starts */
+ time_at_last_press = tv.tv_sec;
+ }
+ break;
+ case 0: /* Release */
+ if (event_already_fired != 0)
+ {
+ printf("Edison PWR button was pressed more than 2s and released\n");
+ fflush(stdout);
+ system(argv[2]);
+ }
+ time_at_last_press = 0;
+ event_already_fired = 0;
+ break;
+ default:
+ printf("Warning: unhandled PWR button event value: %u\n", event.value);
+ }
+ }
+
+ close(fd);
+
+ return 0;
+}
diff --git a/meta-edison-distro/recipes-support/pwr-button-handler/files/pwr-button-handler.service b/meta-edison-distro/recipes-support/pwr-button-handler/files/pwr-button-handler.service
new file mode 100644
index 0000000..a53c10b
--- /dev/null
+++ b/meta-edison-distro/recipes-support/pwr-button-handler/files/pwr-button-handler.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Edison PWR button handler
+
+[Service]
+ExecStart=/usr/bin/pwr_button_handler "/bin/systemctl start blink-led" "sh -c \"/bin/systemctl stop blink-led && /usr/bin/configure_edison --enableOneTimeSetup\""
+Restart=on-failure
+
+[Install]
+WantedBy=default.target
+
diff --git a/meta-edison-distro/recipes-support/pwr-button-handler/pwr-button-handler_0.1.bb b/meta-edison-distro/recipes-support/pwr-button-handler/pwr-button-handler_0.1.bb
new file mode 100644
index 0000000..f58aeb0
--- /dev/null
+++ b/meta-edison-distro/recipes-support/pwr-button-handler/pwr-button-handler_0.1.bb
@@ -0,0 +1,37 @@
+DESCRIPTION = "Daemon listening to Edison PWR long button press, and starting OOBE service when it happens"
+SECTION = "base"
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/files/"
+
+inherit systemd
+
+SYSTEMD_SERVICE_${PN} = "pwr-button-handler.service"
+
+SRC_URI = "file://pwr-button-handler.c"
+SRC_URI += "file://pwr-button-handler.service"
+
+S = "${WORKDIR}"
+
+do_compile() {
+ ${CC} $CFLAGS -DNDEBUG -o pwr_button_handler pwr-button-handler.c
+}
+
+do_install() {
+ install -d ${D}${bindir}
+ install -m 0755 pwr_button_handler ${D}${bindir}
+
+ # Copy service file
+ install -d ${D}/${systemd_unitdir}/system
+ install -m 644 ${WORKDIR}/pwr-button-handler.service ${D}/${systemd_unitdir}/system
+
+ # And enable it at startup
+ install -d ${D}${sysconfdir}/systemd/system/default.target.wants
+ ln -sf ${systemd_unitdir}/system/pwr-button-handler.service \
+ ${D}${sysconfdir}/systemd/system/default.target.wants/pwr-button-handler.service
+}
+
+FILES_${PN} = "${base_libdir}/systemd/system/pwr-button-handler.service"
+FILES_${PN} += "${sysconfdir}/systemd/system/default.target.wants/pwr-button-handler.service"
+FILES_${PN} += "${bindir}/pwr_button_handler"
diff --git a/meta-edison-distro/recipes-support/tcpdump/tcpdump-4.1.1/0001-minimal-IEEE802.15.4-allowed.patch b/meta-edison-distro/recipes-support/tcpdump/tcpdump-4.1.1/0001-minimal-IEEE802.15.4-allowed.patch
new file mode 100644
index 0000000..9d3d60d
--- /dev/null
+++ b/meta-edison-distro/recipes-support/tcpdump/tcpdump-4.1.1/0001-minimal-IEEE802.15.4-allowed.patch
@@ -0,0 +1,22 @@
+From: Sergey Lapin <slapin@slind.org>
+Date: Wed, 28 Jan 2009 16:34:15 +0300
+Subject: [PATCH] minimal IEEE802.15.4 allowed
+
+---
+ tcpdump.c | 3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
+
+diff --git a/tcpdump.c b/tcpdump.c
+index 06683af..fbc944c 100644
+--- a/tcpdump.c
++++ b/tcpdump.c
+@@ -282,6 +282,9 @@ static struct printer printers[] = {
+ #ifdef DLT_MFR
+ { mfr_if_print, DLT_MFR },
+ #endif
++#ifdef DLT_IEEE802_15_4
++ { raw_if_print, DLT_IEEE802_15_4 },
++#endif
+ #if defined(DLT_BLUETOOTH_HCI_H4_WITH_PHDR) && defined(HAVE_PCAP_BLUETOOTH_H)
+ { bt_if_print, DLT_BLUETOOTH_HCI_H4_WITH_PHDR},
+ #endif
diff --git a/meta-edison-distro/recipes-support/tcpdump/tcpdump-4.1.1/configure.patch b/meta-edison-distro/recipes-support/tcpdump/tcpdump-4.1.1/configure.patch
new file mode 100644
index 0000000..3955ddb
--- /dev/null
+++ b/meta-edison-distro/recipes-support/tcpdump/tcpdump-4.1.1/configure.patch
@@ -0,0 +1,29 @@
+---
+ aclocal.m4 | 1 -
+ configure.in | 1 +
+ 2 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/aclocal.m4 b/aclocal.m4
+index 40b5866..0c662b0 100644
+--- a/aclocal.m4
++++ b/aclocal.m4
+@@ -40,7 +40,6 @@ dnl
+ AC_DEFUN(AC_LBL_C_INIT_BEFORE_CC,
+ [AC_PREREQ(2.50)
+ AC_BEFORE([$0], [AC_LBL_C_INIT])
+- AC_BEFORE([$0], [AC_PROG_CC])
+ AC_BEFORE([$0], [AC_LBL_FIXINCLUDES])
+ AC_BEFORE([$0], [AC_LBL_DEVEL])
+ AC_ARG_WITH(gcc, [ --without-gcc don't use gcc])
+diff --git a/configure.in b/configure.in
+index 11257c9..7f9591c 100644
+--- a/configure.in
++++ b/configure.in
+@@ -19,6 +19,7 @@ AC_REVISION($Revision: 1.204 $)
+ AC_PREREQ(2.50)
+ AC_INIT(tcpdump.c)
+
++AC_PROG_CC
+ AC_CANONICAL_HOST
+
+ AC_LBL_C_INIT_BEFORE_CC(V_CCOPT, V_INCLS)
diff --git a/meta-edison-distro/recipes-support/tcpdump/tcpdump-4.1.1/ipv6-cross.patch b/meta-edison-distro/recipes-support/tcpdump/tcpdump-4.1.1/ipv6-cross.patch
new file mode 100644
index 0000000..c8a0373
--- /dev/null
+++ b/meta-edison-distro/recipes-support/tcpdump/tcpdump-4.1.1/ipv6-cross.patch
@@ -0,0 +1,41 @@
+---
+ configure.in | 12 ++++++++----
+ 1 files changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/configure.in b/configure.in
+index eb3e5e8..11257c9 100644
+--- a/configure.in
++++ b/configure.in
+@@ -181,8 +181,9 @@ yes) AC_MSG_RESULT(yes)
+ ipv6=no
+ ;;
+ esac ],
+-
+- AC_TRY_RUN([ /* AF_INET6 available check */
++[
++ if test x"$cross_compiling" != "xyes"; then
++ AC_TRY_RUN([ /* AF_INET6 avalable check */
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ main()
+@@ -201,7 +202,10 @@ main()
+ ipv6=no],
+ [ AC_MSG_RESULT(no)
+ ipv6=no]
+-))
++ )
++else
++ AC_MSG_FAILURE([Unable to check for ipv6 when crosscompiling, please specify.])
++fi])
+
+ ipv6type=unknown
+ ipv6lib=none
+@@ -316,7 +320,7 @@ if test "$ipv6" = "yes" -a "$ipv6lib" != "none"; then
+ fi
+
+
+-if test "$ipv6" = "yes"; then
++if test x"$cross_compiling" != "xyes" -a "$ipv6" = "yes"; then
+ #
+ # XXX - on Tru64 UNIX 5.1, there is no "getaddrinfo()"
+ # function in libc; there are "ngetaddrinfo()" and
diff --git a/meta-edison-distro/recipes-support/tcpdump/tcpdump-4.1.1/tcpdump_configure_no_-O2.patch b/meta-edison-distro/recipes-support/tcpdump/tcpdump-4.1.1/tcpdump_configure_no_-O2.patch
new file mode 100644
index 0000000..7929da5
--- /dev/null
+++ b/meta-edison-distro/recipes-support/tcpdump/tcpdump-4.1.1/tcpdump_configure_no_-O2.patch
@@ -0,0 +1,42 @@
+---
+ configure | 8 ++++----
+ 1 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/configure b/configure
+index cb51d19..73d51af 100755
+--- a/configure
++++ b/configure
+@@ -2691,13 +2691,13 @@ if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+ elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+- CFLAGS="-g -O2"
++ CFLAGS="-g"
+ else
+ CFLAGS="-g"
+ fi
+ else
+ if test "$GCC" = yes; then
+- CFLAGS="-O2"
++ CFLAGS=""
+ else
+ CFLAGS=
+ fi
+@@ -2830,7 +2830,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
+ if test "$GCC" = yes ; then
+ if test "$SHLICC2" = yes ; then
+ ac_cv_lbl_gcc_vers=2
+- V_CCOPT="-O2"
++ V_CCOPT=""
+ else
+ { echo "$as_me:$LINENO: checking gcc version" >&5
+ echo $ECHO_N "checking gcc version... $ECHO_C" >&6; }
+@@ -2847,7 +2847,7 @@ fi
+ { echo "$as_me:$LINENO: result: $ac_cv_lbl_gcc_vers" >&5
+ echo "${ECHO_T}$ac_cv_lbl_gcc_vers" >&6; }
+ if test $ac_cv_lbl_gcc_vers -gt 1 ; then
+- V_CCOPT="-O2"
++ V_CCOPT=""
+ fi
+ fi
+ else
diff --git a/meta-edison-distro/recipes-support/tcpdump/tcpdump_4.1.1.bb b/meta-edison-distro/recipes-support/tcpdump/tcpdump_4.1.1.bb
new file mode 100644
index 0000000..6b81ed0
--- /dev/null
+++ b/meta-edison-distro/recipes-support/tcpdump/tcpdump_4.1.1.bb
@@ -0,0 +1,41 @@
+DESCRIPTION = "A sophisticated network protocol analyzer"
+HOMEPAGE = "http://www.tcpdump.org/"
+LICENSE = "BSD"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=1d4b0366557951c84a94fabe3529f867"
+SECTION = "console/network"
+DEPENDS = "libpcap"
+PR = "r1"
+
+SRC_URI = " \
+ http://www.tcpdump.org/release/tcpdump-${PV}.tar.gz \
+ file://tcpdump_configure_no_-O2.patch \
+ file://0001-minimal-IEEE802.15.4-allowed.patch \
+ file://ipv6-cross.patch \
+ file://configure.patch \
+"
+
+inherit autotools
+# ac_cv_linux_vers=${ac_cv_linux_vers=2}
+
+EXTRA_OECONF = "--without-crypto \
+ ${@base_contains('DISTRO_FEATURES', 'ipv6', '--enable-ipv6', '--disable-ipv6', d)}"
+
+do_configure() {
+ # AC_CHECK_LIB(dlpi.. was looking to host /lib
+ sed -i 's:-L/lib:-L${STAGING_LIBDIR}:g' ./configure.in
+
+ gnu-configize
+ autoconf
+ oe_runconf
+ sed -i 's:/usr/lib:${STAGING_LIBDIR}:' ./Makefile
+ sed -i 's:/usr/include:${STAGING_INCDIR}:' ./Makefile
+}
+
+do_install_append() {
+ # tcpdump 4.1.1 installs a copy to /usr/sbin/tcpdump.4.1.1
+ rm -f ${D}${sbindir}/tcpdump.${PV}
+}
+
+SRC_URI[md5sum] = "d0dd58bbd6cd36795e05c6f1f74420b0"
+SRC_URI[sha256sum] = "e6cd4bbd61ec7adbb61ba8352c4b4734f67b8caaa845d88cb826bc0b9f1e7f0a"
+
diff --git a/meta-edison-distro/recipes-support/watchdog-sample/watchdog-sample.bb b/meta-edison-distro/recipes-support/watchdog-sample/watchdog-sample.bb
new file mode 100644
index 0000000..f0369bc
--- /dev/null
+++ b/meta-edison-distro/recipes-support/watchdog-sample/watchdog-sample.bb
@@ -0,0 +1,46 @@
+DESCRIPTION = "Watchdog sample daemon"
+SECTION = "base"
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/watchdog-sample/"
+
+SRC_URI += "file://watchdog-sample.service"
+SRC_URI += "file://watchdog-sample.c"
+
+SYSTEMD_SERVICE_${PN} = "watchdog-sample.service"
+
+RDEPENDS_${PN} = "systemd"
+DEPENDS = "systemd"
+
+S = "${WORKDIR}"
+
+do_compile() {
+ $CC $CFLAGS ${S}/watchdog-sample.c `pkg-config --cflags --libs --print-errors libsystemd` -o watchdog-sample
+}
+
+do_install() {
+ # install service file
+ install -d ${D}${systemd_unitdir}/system
+ install -c -m 0644 ${WORKDIR}/watchdog-sample.service ${D}${systemd_unitdir}/system
+
+ # enable the service
+ install -d ${D}${sysconfdir}/systemd/system/basic.target.wants
+ ln -sf ${systemd_unitdir}/system/watchdog-sample.service \
+ ${D}${sysconfdir}/systemd/system/basic.target.wants/watchdog-sample.service
+
+ # install watchdog binary
+ install -d ${D}${bindir}
+ install -c -m 0755 ${B}/watchdog-sample ${D}${bindir}
+}
+
+FILES_${PN} = "${base_libdir}/systemd/system/watchdog-sample.service"
+FILES_${PN} += "${sysconfdir}/systemd/system/basic.target.wants/watchdog-sample.service"
+FILES_${PN} += "${bindir}/watchdog-sample"
+
+# As this package is tied to systemd, only build it when we're also building systemd.
+python () {
+ if not oe.utils.contains ('DISTRO_FEATURES', 'systemd', True, False, d):
+ raise bb.parse.SkipPackage("'systemd' not in DISTRO_FEATURES")
+}
+
diff --git a/meta-edison-distro/recipes-support/watchdog-sample/watchdog-sample/watchdog-sample.c b/meta-edison-distro/recipes-support/watchdog-sample/watchdog-sample/watchdog-sample.c
new file mode 100644
index 0000000..7bba6ff
--- /dev/null
+++ b/meta-edison-distro/recipes-support/watchdog-sample/watchdog-sample/watchdog-sample.c
@@ -0,0 +1,92 @@
+/*
+ * Watchdog daemon sample code
+ *
+ * Copyright (c) 2014, Intel Corporation.
+ * Simon Desfarges <simonx.desfarges@intel.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/*
+ * This file is a simple example on the use of the systemd SW watchdog.
+ * At startup, the program will create a file in /tmp/watchdog-sample.tmp;
+ * if the file is removed while the program is running, the program will not
+ * ping systemd watchdog, resulting in a restart of the program (depending on
+ * the service configuration).
+ * This file allow to simulate a hang in the watchdog-critical program.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <systemd/sd-daemon.h>
+
+int main(int argc, char * argv[]) {
+ uint32_t wd_timeout; // in seconds
+ uint32_t sleep_time;
+ int err;
+ char path[] = "/tmp/watchdog-sample.tmp";
+ int fd;
+ if(argc == 2) {
+ wd_timeout = atoi(argv[1]);
+ fprintf(stderr, SD_WARNING "Will ping every %ds \n", wd_timeout/2);
+ } else {
+ errno=EINVAL;
+ sd_notifyf(0, SD_EMERG "STATUS=Failed to start up: %s\n"
+ "ERRNO=%i",
+ strerror(errno), errno);
+ exit(-1);
+ }
+
+ if(wd_timeout == 0) {
+ sd_notify(0, "Systemd SW watchdog disabled, nothing to do\n");
+ exit(0);
+ }
+
+ fd = open(path, O_RDWR | O_CREAT | O_SYNC, 777);
+ if(fd == -1) {
+ sd_notifyf(0, SD_EMERG "STATUS=Failed to create file: %s\n"
+ "ERRNO=%i",
+ strerror(errno), errno);
+ exit(-1);
+ }
+ write(fd,"A", 1);
+ fsync(fd);
+ close(fd);
+
+ /* Here, systemd WD is enabled and waiting for ping */
+ /* wd_timeout variable contains the timeout. We need to ping every wd_timeout/2 */
+ sleep_time = wd_timeout/2;
+ sd_notify(0, "READY=1\n");
+
+ while(1) {
+ sd_notify(0, "WATCHDOG=1\n");
+ sleep(sleep_time);
+
+ if(access(path, F_OK) == -1) {
+ sd_notify(0, SD_EMERG "TEMP file disappeared, falling in hang mode\n");
+ while(1);
+ }
+ }
+}
+
diff --git a/meta-edison-distro/recipes-support/watchdog-sample/watchdog-sample/watchdog-sample.service b/meta-edison-distro/recipes-support/watchdog-sample/watchdog-sample/watchdog-sample.service
new file mode 100644
index 0000000..dacb5e0
--- /dev/null
+++ b/meta-edison-distro/recipes-support/watchdog-sample/watchdog-sample/watchdog-sample.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=Watchdog sample daemon
+
+[Service]
+Environment="Timeout=30"
+ExecStart=/usr/bin/watchdog-sample ${Timeout}
+WatchdogSec=30s
+Restart=on-failure
+StartLimitInterval=4min
+StartLimitBurst=4
+StartLimitAction=reboot-force
+
+[Install]
+WantedBy=basic.target
+
diff --git a/meta-edison-middleware/conf/layer.conf b/meta-edison-middleware/conf/layer.conf
new file mode 100644
index 0000000..1def19c
--- /dev/null
+++ b/meta-edison-middleware/conf/layer.conf
@@ -0,0 +1,13 @@
+# We have a conf and classes directory, add to BBPATH
+BBPATH := "${BBPATH}:${LAYERDIR}"
+
+# We have a recipes-* directories, add to BBFILES
+BBFILES := "${BBFILES} ${LAYERDIR}/recipes-*/*/*.bb \
+ ${LAYERDIR}/recipes-*/*/*.bbappend"
+
+BBFILE_COLLECTIONS += "edison-middleware"
+BBFILE_PATTERN_edison-middleware = "^${LAYERDIR}/"
+BBFILE_PRIORITY_edison-middleware = "6"
+
+PREFERRED_VERSION_nodejs = "0.10.28"
+PREFERRED_VERSION_nodejs-native = "0.10.28"
diff --git a/meta-edison-middleware/recipes-connectivity/c-ares/c-ares_1.10.0.bb b/meta-edison-middleware/recipes-connectivity/c-ares/c-ares_1.10.0.bb
new file mode 100644
index 0000000..0d1ef9d
--- /dev/null
+++ b/meta-edison-middleware/recipes-connectivity/c-ares/c-ares_1.10.0.bb
@@ -0,0 +1,13 @@
+DESCRIPTION = "C library for asynchronous DNS requests (including name resolves)"
+HOMEPAGE = "http://c-ares.haxx.se/"
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://README;beginline=17;endline=23;md5=d08205a43bc63c12cf394ac1d2cce7c3"
+
+PR = "r0"
+
+SRC_URI = "http://c-ares.haxx.se/download/c-ares-${PV}.tar.gz"
+
+SRC_URI[md5sum] = "1196067641411a75d3cbebe074fd36d8"
+SRC_URI[sha256sum] = "3d701674615d1158e56a59aaede7891f2dde3da0f46a6d3c684e0ae70f52d3db"
+
+inherit autotools
diff --git a/meta-edison-middleware/recipes-connectivity/mdns/files/build.patch b/meta-edison-middleware/recipes-connectivity/mdns/files/build.patch
new file mode 100644
index 0000000..a1a2c89
--- /dev/null
+++ b/meta-edison-middleware/recipes-connectivity/mdns/files/build.patch
@@ -0,0 +1,191 @@
+--- a/Clients/Makefile
++++ b/Clients/Makefile
+@@ -30,9 +30,17 @@ TARGETS = build/dns-sd build/dns-sd64
+ LIBS =
+ else
+ TARGETS = build/dns-sd
++# Set up diverging paths for debug vs. prod builds
++DEBUG?=1
++ifeq ($(DEBUG),1)
++LIBS = -L../mDNSPosix/build/debug/ -ldns_sd
++else
+ LIBS = -L../mDNSPosix/build/prod/ -ldns_sd
+ endif
+
++
++endif
++
+ all: $(TARGETS)
+
+ clean:
+@@ -42,10 +50,10 @@ build:
+ mkdir build
+
+ build/dns-sd: build dns-sd.c ClientCommon.c
+- cc $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -Wall -o $@
++ $(CC) $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -Wall -o $@
+
+ build/dns-sd64: build dns-sd.c ClientCommon.c
+- cc $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -Wall -o $@ -m64
++ $(CC) $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -Wall -o $@ -m64
+
+ # Note, we can make a 'fat' version of dns-sd using 'lipo', as shown below, but we
+ # don't, because we don't want or need a 'fat' version of dns-sd, because it will
+--- a/mDNSPosix/Makefile
++++ b/mDNSPosix/Makefile
+@@ -50,6 +50,7 @@
+
+ LIBVERS = 1
+
++POSIXDIR = ../mDNSPosix
+ COREDIR = ../mDNSCore
+ SHAREDDIR ?= ../mDNSShared
+ JDK = /usr/jdk
+@@ -57,11 +58,11 @@ JDK = /usr/jdk
+ CC = @cc
+ BISON = @bison
+ FLEX = @flex
+-LD = ld -shared
++LD =@LD
+ CP = cp
+ RM = rm
+ LN = ln -s -f
+-CFLAGS_COMMON = -I$(COREDIR) -I$(SHAREDDIR) -I$(OBJDIR) -fwrapv -W -Wall -DPID_FILE=\"/var/run/mdnsd.pid\" -DMDNS_UDS_SERVERPATH=\"/var/run/mdnsd\"
++CFLAGS_COMMON = -I$(POSIXDIR) -I$(COREDIR) -I$(SHAREDDIR) -I$(OBJDIR) -fwrapv -W -Wall -DPID_FILE=\"/var/run/mdnsd.pid\" -DMDNS_UDS_SERVERPATH=\"/var/run/mdnsd\"
+ CFLAGS_PTHREAD =
+ LINKOPTS =
+ LINKOPTS_PTHREAD = -lpthread
+@@ -69,7 +70,7 @@ LDSUFFIX = so
+ JAVACFLAGS_OS = -fPIC -shared -ldns_sd
+
+ # Set up diverging paths for debug vs. prod builds
+-DEBUG=0
++DEBUG?=1
+ ifeq ($(DEBUG),1)
+ CFLAGS_DEBUG = -g -DMDNS_DEBUGMSGS=2
+ OBJDIR = objects/debug
+@@ -103,6 +104,7 @@ else
+ ifeq ($(findstring linux,$(os)),linux)
+ CFLAGS_OS = -D_GNU_SOURCE -DHAVE_IPV6 -DNOT_HAVE_SA_LEN -DUSES_NETLINK -DHAVE_LINUX -DTARGET_OS_LINUX -fno-strict-aliasing
+ LD = gcc -shared
++LINKOPTS = --hash-style=gnu
+ FLEXFLAGS_OS = -l
+ JAVACFLAGS_OS += -I$(JDK)/include/linux
+
+@@ -210,7 +212,7 @@ endif
+ endif
+ endif
+
+-CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_OS) $(CFLAGS_DEBUG)
++CFLAGS_BUILD = $(CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_OS) $(CFLAGS_DEBUG)
+
+ #############################################################################
+
+@@ -246,8 +248,7 @@ Daemon: setup $(BUILDDIR)/mdnsd
+ @echo "Responder daemon done"
+
+ $(BUILDDIR)/mdnsd: $(DAEMONOBJS)
+- $(CC) -o $@ $+ $(LINKOPTS)
+- @$(STRIP) $@
++ $(CC) -o $@ $+
+
+ # libdns_sd target builds the client library
+ libdns_sd: setup $(BUILDDIR)/libdns_sd.$(LDSUFFIX)
+@@ -256,22 +257,18 @@ libdns_sd: setup $(BUILDDIR)/libdns_sd.$
+ CLIENTLIBOBJS = $(OBJDIR)/dnssd_clientlib.c.so.o $(OBJDIR)/dnssd_clientstub.c.so.o $(OBJDIR)/dnssd_ipc.c.so.o
+
+ $(BUILDDIR)/libdns_sd.$(LDSUFFIX): $(CLIENTLIBOBJS)
+- @$(LD) $(LINKOPTS) -o $@ $+
+- @$(STRIP) $@
++ $(LD) -shared $(LINKOPTS) -o $@ $+
+
+-Clients: setup libdns_sd ../Clients/build/dns-sd
++Clients: setup libdns_sd
++ @$(MAKE) -C ../Clients DEBUG=${DEBUG}
+ @echo "Clients done"
+
+-../Clients/build/dns-sd:
+- @$(MAKE) -C ../Clients
+-
+ # nss_mdns target builds the Name Service Switch module
+ nss_mdns: setup $(BUILDDIR)/$(NSSLIBFILE)
+ @echo "Name Service Switch module done"
+
+ $(BUILDDIR)/$(NSSLIBFILE): $(CLIENTLIBOBJS) $(OBJDIR)/nss_mdns.c.so.o
+- @$(LD) $(LINKOPTS) -o $@ $+
+- @$(STRIP) $@
++ $(LD) -shared $(LINKOPTS) -o $@ $+
+
+ #############################################################################
+
+@@ -469,55 +466,55 @@ dnsextd: setup $(BUILDDIR)/dnsextd
+ @echo "dnsextd done"
+
+ $(BUILDDIR)/mDNSClientPosix: $(APPOBJ) $(OBJDIR)/Client.c.o
+- $(CC) $+ -o $@ $(LINKOPTS)
++ $(CC) $+ -o $@
+
+ $(BUILDDIR)/mDNSResponderPosix: $(COMMONOBJ) $(OBJDIR)/Responder.c.o
+- $(CC) $+ -o $@ $(LINKOPTS)
++ $(CC) $+ -o $@
+
+ $(BUILDDIR)/mDNSProxyResponderPosix: $(COMMONOBJ) $(OBJDIR)/ProxyResponder.c.o
+- $(CC) $+ -o $@ $(LINKOPTS)
++ $(CC) $+ -o $@
+
+ $(BUILDDIR)/mDNSIdentify: $(SPECIALOBJ) $(OBJDIR)/Identify.c.o
+- $(CC) $+ -o $@ $(LINKOPTS)
++ $(CC) $+ -o $@
+
+ $(OBJDIR)/Identify.c.o: $(COREDIR)/mDNS.c # Note: Identify.c textually imports mDNS.c
+
+ $(BUILDDIR)/mDNSNetMonitor: $(SPECIALOBJ) $(OBJDIR)/NetMonitor.c.o
+- $(CC) $+ -o $@ $(LINKOPTS)
++ $(CC) $+ -o $@
+
+ $(OBJDIR)/NetMonitor.c.o: $(COREDIR)/mDNS.c # Note: NetMonitor.c textually imports mDNS.c
+
+ $(BUILDDIR)/dnsextd: $(DNSEXTDOBJ) $(OBJDIR)/dnsextd.c.threadsafe.o
+- $(CC) $+ -o $@ $(LINKOPTS) $(LINKOPTS_PTHREAD)
++ $(CC) $+ -o $@ $(LINKOPTS_PTHREAD)
+
+ #############################################################################
+
+ # Implicit rules
+ $(OBJDIR)/%.c.o: %.c
+- $(CC) $(CFLAGS) -c -o $@ $<
++ $(CC) $(CFLAGS_BUILD) -c -o $@ $<
+
+ $(OBJDIR)/%.c.o: $(COREDIR)/%.c
+- $(CC) $(CFLAGS) -c -o $@ $<
++ $(CC) $(CFLAGS_BUILD) -c -o $@ $<
+
+ $(OBJDIR)/%.c.o: $(SHAREDDIR)/%.c
+- $(CC) $(CFLAGS) -c -o $@ $<
++ $(CC) $(CFLAGS_BUILD) -c -o $@ $<
+
+ $(OBJDIR)/%.c.threadsafe.o: %.c
+- $(CC) $(CFLAGS) $(CFLAGS_PTHREAD) -D_REENTRANT -c -o $@ $<
++ $(CC) $(CFLAGS_BUILD) $(CFLAGS_PTHREAD) -D_REENTRANT -c -o $@ $<
+
+ $(OBJDIR)/%.c.threadsafe.o: $(SHAREDDIR)/%.c
+- $(CC) $(CFLAGS) $(CFLAGS_PTHREAD) -D_REENTRANT -c -o $@ $<
++ $(CC) $(CFLAGS_BUILD) $(CFLAGS_PTHREAD) -D_REENTRANT -c -o $@ $<
+
+ $(OBJDIR)/%.c.so.o: %.c
+- $(CC) $(CFLAGS) -c -fPIC -o $@ $<
++ $(CC) $(CFLAGS_BUILD) -c -fPIC -o $@ $<
+
+ $(OBJDIR)/%.c.so.o: $(SHAREDDIR)/%.c
+- $(CC) $(CFLAGS) -c -fPIC -o $@ $<
++ $(CC) $(CFLAGS_BUILD) -c -fPIC -o $@ $<
+
+ $(OBJDIR)/%.y.o: $(SHAREDDIR)/%.y
+ $(BISON) -o $(OBJDIR)/$*.c -d $<
+- $(CC) $(CFLAGS) -c -o $@ $(OBJDIR)/$*.c
++ $(CC) $(CFLAGS_BUILD) -c -o $@ $(OBJDIR)/$*.c
+
+ $(OBJDIR)/%.l.o: $(SHAREDDIR)/%.l
+ $(FLEX) $(FLEXFLAGS_OS) -i -o$(OBJDIR)/$*.l.c $<
+- $(CC) $(CFLAGS) -Wno-error -c -o $@ $(OBJDIR)/$*.l.c
++ $(CC) $(CFLAGS_BUILD) -Wno-error -c -o $@ $(OBJDIR)/$*.l.c
diff --git a/meta-edison-middleware/recipes-connectivity/mdns/files/mdns.service b/meta-edison-middleware/recipes-connectivity/mdns/files/mdns.service
new file mode 100644
index 0000000..531d142
--- /dev/null
+++ b/meta-edison-middleware/recipes-connectivity/mdns/files/mdns.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=Zero-configuration networking
+After=network.target
+
+[Service]
+Type=forking
+ExecStartPre=/bin/rm -f /var/run/mdnsd.pid
+ExecStart=/usr/sbin/mdnsd
+ExecReload=/bin/kill -HUP $MAINPID
+PIDFile=/var/run/mdnsd.pid
+Restart=always
+RestartSec=10s
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-edison-middleware/recipes-connectivity/mdns/mdns_544.bb b/meta-edison-middleware/recipes-connectivity/mdns/mdns_544.bb
new file mode 100644
index 0000000..1d3f0bd
--- /dev/null
+++ b/meta-edison-middleware/recipes-connectivity/mdns/mdns_544.bb
@@ -0,0 +1,76 @@
+DESCRIPTION = "Bonjour, also known as zero-configuration networking, enables automatic discovery of computers, devices, and services on IP networks."
+HOMEPAGE = "http://developer.apple.com/networking/bonjour/"
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=31c50371921e0fb731003bbc665f29bf"
+
+PR = "r1"
+
+SRC_URI = "http://opensource.apple.com/tarballs/mDNSResponder/mDNSResponder-${PV}.tar.gz \
+ file://build.patch \
+ file://mdns.service \
+"
+
+SRC_URI[md5sum] = "39142ab70bd82a096801ce346f86cbab"
+SRC_URI[sha256sum] = "c6ad1d53c28d28c0e3689bdf5efd9ce6f5c4c3692e8ad76e5eeb4d0c248929ac"
+
+PARALLEL_MAKE = ""
+
+S = "${WORKDIR}/mDNSResponder-544"
+
+do_compile() {
+ cd mDNSPosix
+ oe_runmake os=linux DEBUG=0
+}
+
+do_install () {
+ install -d ${D}${sbindir}
+ install -m 0755 mDNSPosix/build/prod/mdnsd ${D}${sbindir}
+
+ install -d ${D}${libdir}
+ cp mDNSPosix/build/prod/libdns_sd.so ${D}${libdir}/libdns_sd.so.1
+ chmod 0644 ${D}${libdir}/libdns_sd.so.1
+ ln -s libdns_sd.so.1 ${D}${libdir}/libdns_sd.so
+
+ install -d ${D}${includedir}
+ install -m 0644 mDNSShared/dns_sd.h ${D}${includedir}
+
+ install -d ${D}${mandir}/man8
+ install -m 0644 mDNSShared/mDNSResponder.8 ${D}${mandir}/man8/mdnsd.8
+
+ install -d ${D}${bindir}
+ install -m 0755 Clients/build/dns-sd ${D}${bindir}
+
+ install -d ${D}${libdir}
+ oe_libinstall -C mDNSPosix/build/prod -so libnss_mdns-0.2 ${D}${libdir}
+ ln -s libnss_mdns-0.2.so ${D}${libdir}/libnss_mdns.so.2
+
+ install -d ${D}${sysconfdir}
+ install -m 0644 mDNSPosix/nss_mdns.conf ${D}${sysconfdir}
+
+ install -d ${D}${mandir}/man5
+ install -m 0644 mDNSPosix/nss_mdns.conf.5 ${D}${mandir}/man5
+
+ install -d ${D}${mandir}/man8
+ install -m 0644 mDNSPosix/libnss_mdns.8 ${D}${mandir}/man8
+
+ install -d ${D}${systemd_unitdir}/system/
+ install -m 0644 ${WORKDIR}/mdns.service ${D}${systemd_unitdir}/system/
+}
+
+pkg_postinst_${PN} () {
+ sed -e '/^hosts:/s/\s*\<mdns\>//' \
+ -e 's/\(^hosts:.*\)\(\<files\>\)\(.*\)\(\<dns\>\)\(.*\)/\1\2 mdns\3\4\5/' \
+ -i $D/etc/nsswitch.conf
+}
+
+pkg_prerm_${PN} () {
+ sed -e '/^hosts:/s/\s*\<mdns\>//' \
+ -e '/^hosts:/s/\s*mdns//' \
+ -i $D/etc/nsswitch.conf
+}
+
+inherit systemd
+
+SYSTEMD_SERVICE_${PN} = "mdns.service"
+
+FILES_${PN} += "${systemd_unitdir}/system/mdns.service"
diff --git a/meta-edison-middleware/recipes-connectivity/mosquitto/files/build.patch b/meta-edison-middleware/recipes-connectivity/mosquitto/files/build.patch
new file mode 100644
index 0000000..48c0653
--- /dev/null
+++ b/meta-edison-middleware/recipes-connectivity/mosquitto/files/build.patch
@@ -0,0 +1,71 @@
+Index: mosquitto-1.3.4/client/Makefile
+===================================================================
+--- mosquitto-1.3.4.orig/client/Makefile
++++ mosquitto-1.3.4/client/Makefile
+@@ -21,8 +21,8 @@ sub_client.o : sub_client.c ../lib/libmo
+
+ install : all
+ $(INSTALL) -d ${DESTDIR}$(prefix)/bin
+- $(INSTALL) -s --strip-program=$(STRIP) mosquitto_pub ${DESTDIR}${prefix}/bin/mosquitto_pub
+- $(INSTALL) -s --strip-program=$(STRIP) mosquitto_sub ${DESTDIR}${prefix}/bin/mosquitto_sub
++ $(INSTALL) mosquitto_pub ${DESTDIR}${prefix}/bin/mosquitto_pub
++ $(INSTALL) mosquitto_sub ${DESTDIR}${prefix}/bin/mosquitto_sub
+
+ uninstall :
+ -rm -f ${DESTDIR}${prefix}/bin/mosquitto_pub
+Index: mosquitto-1.3.4/config.mk
+===================================================================
+--- mosquitto-1.3.4.orig/config.mk
++++ mosquitto-1.3.4/config.mk
+@@ -213,7 +213,7 @@ endif
+
+
+ INSTALL?=install
+-prefix=/usr/local
++prefix=/usr
+ mandir=${prefix}/share/man
+ localedir=${prefix}/share/locale
+ STRIP?=strip
+Index: mosquitto-1.3.4/lib/Makefile
+===================================================================
+--- mosquitto-1.3.4.orig/lib/Makefile
++++ mosquitto-1.3.4/lib/Makefile
+@@ -25,7 +25,7 @@ all : libmosquitto.so.${SOVERSION} libmo
+
+ install : all
+ $(INSTALL) -d ${DESTDIR}$(prefix)/lib${LIB_SUFFIX}/
+- $(INSTALL) -s --strip-program=$(STRIP) libmosquitto.so.${SOVERSION} ${DESTDIR}${prefix}/lib${LIB_SUFFIX}/libmosquitto.so.${SOVERSION}
++ $(INSTALL) libmosquitto.so.${SOVERSION} ${DESTDIR}${prefix}/lib${LIB_SUFFIX}/libmosquitto.so.${SOVERSION}
+ ln -sf libmosquitto.so.${SOVERSION} ${DESTDIR}${prefix}/lib${LIB_SUFFIX}/libmosquitto.so
+ $(INSTALL) -d ${DESTDIR}${prefix}/include/
+ $(INSTALL) mosquitto.h ${DESTDIR}${prefix}/include/mosquitto.h
+Index: mosquitto-1.3.4/lib/cpp/Makefile
+===================================================================
+--- mosquitto-1.3.4.orig/lib/cpp/Makefile
++++ mosquitto-1.3.4/lib/cpp/Makefile
+@@ -10,7 +10,7 @@ all : libmosquittopp.so.${SOVERSION}
+
+ install : all
+ $(INSTALL) -d ${DESTDIR}$(prefix)/lib${LIB_SUFFIX}/
+- $(INSTALL) -s --strip-program=$(STRIP) libmosquittopp.so.${SOVERSION} ${DESTDIR}${prefix}/lib${LIB_SUFFIX}/libmosquittopp.so.${SOVERSION}
++ $(INSTALL) libmosquittopp.so.${SOVERSION} ${DESTDIR}${prefix}/lib${LIB_SUFFIX}/libmosquittopp.so.${SOVERSION}
+ ln -sf libmosquittopp.so.${SOVERSION} ${DESTDIR}${prefix}/lib${LIB_SUFFIX}/libmosquittopp.so
+ $(INSTALL) -d ${DESTDIR}${prefix}/include/
+ $(INSTALL) mosquittopp.h ${DESTDIR}${prefix}/include/mosquittopp.h
+Index: mosquitto-1.3.4/src/Makefile
+===================================================================
+--- mosquitto-1.3.4.orig/src/Makefile
++++ mosquitto-1.3.4/src/Makefile
+@@ -100,10 +100,10 @@ mosquitto_passwd.o : mosquitto_passwd.c
+
+ install : all
+ $(INSTALL) -d ${DESTDIR}$(prefix)/sbin
+- $(INSTALL) -s --strip-program=$(STRIP) mosquitto ${DESTDIR}${prefix}/sbin/mosquitto
++ $(INSTALL) mosquitto ${DESTDIR}${prefix}/sbin/mosquitto
+ $(INSTALL) mosquitto_plugin.h ${DESTDIR}${prefix}/include/mosquitto_plugin.h
+ ifeq ($(WITH_TLS),yes)
+- $(INSTALL) -s --strip-program=$(STRIP) mosquitto_passwd ${DESTDIR}${prefix}/bin/mosquitto_passwd
++ $(INSTALL) mosquitto_passwd ${DESTDIR}${prefix}/bin/mosquitto_passwd
+ endif
+
+ uninstall :
diff --git a/meta-edison-middleware/recipes-connectivity/mosquitto/files/mosquitto.service b/meta-edison-middleware/recipes-connectivity/mosquitto/files/mosquitto.service
new file mode 100644
index 0000000..25f68fa
--- /dev/null
+++ b/meta-edison-middleware/recipes-connectivity/mosquitto/files/mosquitto.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=Mosquitto - lightweight server implementation of the MQTT and MQTT-SN protocols
+ConditionPathExists=/etc/mosquitto/mosquitto.conf
+After=network.target
+
+[Service]
+Type=simple
+ExecStartPre=/bin/rm -f /var/run/mosquitto.pid
+ExecStart=/usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf
+ExecReload=/bin/kill -HUP $MAINPID
+PIDFile=/var/run/mosquitto.pid
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-edison-middleware/recipes-connectivity/mosquitto/mosquitto_1.3.4.bb b/meta-edison-middleware/recipes-connectivity/mosquitto/mosquitto_1.3.4.bb
new file mode 100644
index 0000000..84c3307
--- /dev/null
+++ b/meta-edison-middleware/recipes-connectivity/mosquitto/mosquitto_1.3.4.bb
@@ -0,0 +1,55 @@
+SUMMARY = "Open source MQTT v3.1 implemention"
+DESCRIPTION = "Mosquitto is an open source (BSD licensed) message broker that implements the MQ Telemetry Transport protocol version 3.1. MQTT provides a lightweight method of carrying out messaging using a publish/subscribe model. "
+HOMEPAGE = "http://mosquitto.org/"
+SECTION = "console/network"
+LICENSE = "BSD"
+LIC_FILES_CHKSUM = "file://LICENSE.txt;md5=89aa5ea5f32e4260d84c5d185ee3add4"
+
+DEPENDS = "openssl c-ares"
+
+PR = "r0"
+
+SRC_URI = "http://mosquitto.org/files/source/mosquitto-${PV}.tar.gz \
+ file://build.patch \
+ file://mosquitto.service \
+"
+
+SRC_URI[md5sum] = "9d729849efd74c6e3eee17a4a002e1e9"
+SRC_URI[sha256sum] = "0a3982d6b875a458909c8828731da04772035468700fa7eb2f0885f4bd6d0dbc"
+
+inherit autotools
+
+do_install_append () {
+ install -d ${D}${libbir}
+ install -m 0644 lib/libmosquitto.a ${D}${libdir}/
+
+ install -d ${D}${systemd_unitdir}/system/
+ install -m 0644 ${WORKDIR}/mosquitto.service ${D}${systemd_unitdir}/system/
+
+ cp ${D}${sysconfdir}/mosquitto/mosquitto.conf.example ${D}${sysconfdir}/mosquitto/mosquitto.conf
+ sed 's/#user mosquitto/user root/' -i ${D}${sysconfdir}/mosquitto/mosquitto.conf
+}
+
+PACKAGES += "libmosquitto1 libmosquittopp1 ${PN}-clients ${PN}-python"
+
+FILES_${PN} = "${sbindir}/mosquitto \
+ ${bindir}/mosquitto_passwd \
+ ${sysconfdir} \
+ ${systemd_unitdir}/system/mosquitto.service \
+"
+
+FILES_libmosquitto1 = "${libdir}/libmosquitto.so.1"
+
+FILES_libmosquittopp1 = "${libdir}/libmosquittopp.so.1"
+
+FILES_${PN}-clients = "${bindir}/mosquitto_pub \
+ ${bindir}/mosquitto_sub \
+"
+
+FILES_${PN}-staticdev += "${libdir}/libmosquitto.a"
+
+FILES_${PN}-python = "/usr/lib/python2.7/site-packages"
+
+inherit systemd
+
+SYSTEMD_SERVICE_${PN} = "mosquitto.service"
diff --git a/meta-edison-middleware/recipes-connectivity/paho-mqtt/files/makefile.patch b/meta-edison-middleware/recipes-connectivity/paho-mqtt/files/makefile.patch
new file mode 100644
index 0000000..4d1e25b
--- /dev/null
+++ b/meta-edison-middleware/recipes-connectivity/paho-mqtt/files/makefile.patch
@@ -0,0 +1,19 @@
+---
+ Makefile | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/Makefile b/Makefile
+index 33bd2d0..84262bd 100644
+--- a/Makefile
++++ b/Makefile
+@@ -115,7 +115,8 @@ LDFLAGS_AS = -shared -Wl,-soname,lib${MQTTLIB_AS}.so.${MAJOR_VERSION} -lpthread
+
+ all: build
+
+-build: | mkdir ${MQTTLIB_C_TARGET} ${MQTTLIB_CS_TARGET} ${MQTTLIB_A_TARGET} ${MQTTLIB_AS_TARGET} ${MQTTVERSION_TARGET} ${SYNC_SAMPLES} ${ASYNC_SAMPLES} ${SYNC_TESTS} ${SYNC_SSL_TESTS} ${ASYNC_TESTS} ${ASYNC_SSL_TESTS}
++build: | mkdir ${MQTTLIB_C_TARGET} ${MQTTLIB_CS_TARGET} ${MQTTLIB_A_TARGET} ${MQTTLIB_AS_TARGET}
++#${MQTTVERSION_TARGET} ${SYNC_SAMPLES} ${ASYNC_SAMPLES} ${SYNC_TESTS} ${SYNC_SSL_TESTS} ${ASYNC_TESTS} ${ASYNC_SSL_TESTS}
+
+ clean:
+ rm -rf ${blddir}/*
+--
diff --git a/meta-edison-middleware/recipes-connectivity/paho-mqtt/paho-mqtt_3.1.bb b/meta-edison-middleware/recipes-connectivity/paho-mqtt/paho-mqtt_3.1.bb
new file mode 100644
index 0000000..37cab21
--- /dev/null
+++ b/meta-edison-middleware/recipes-connectivity/paho-mqtt/paho-mqtt_3.1.bb
@@ -0,0 +1,39 @@
+DESCRIPTION = "Paho MQTT - user libraries for the MQTT and MQTT-SN protocols"
+DESCRIPTION = "Client implementation of open and standard messaging protocols for Machine-to-Machine (M2M) and Internet of Things (IoT)."
+HOMEPAGE = "http://www.eclipse.org/paho/"
+SECTION = "console/network"
+LICENSE = "EPL-1.0 | EDL-1.0"
+
+LIC_FILES_CHKSUM = " \
+ file://edl-v10;md5=3adfcc70f5aeb7a44f3f9b495aa1fbf3 \
+ file://epl-v10;md5=659c8e92a40b6df1d9e3dccf5ae45a08 \
+"
+
+PR = "r1"
+
+SRC_URI = "git://git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.c.git;protocol=http \
+ file://makefile.patch \
+"
+
+SRCREV = "93a064dbe9fd2fc84b8bb2701e10d2de8004a11c"
+
+S = "${WORKDIR}/git"
+
+do_compile() {
+ oe_runmake
+}
+
+do_install() {
+ install -d ${D}${libdir}
+ oe_libinstall -C build/output -so libpaho-mqtt3a ${D}${libdir}
+ oe_libinstall -C build/output -so libpaho-mqtt3as ${D}${libdir}
+ oe_libinstall -C build/output -so libpaho-mqtt3c ${D}${libdir}
+ oe_libinstall -C build/output -so libpaho-mqtt3cs ${D}${libdir}
+ install -d ${D}${includedir}
+ install -m 644 src/MQTTAsync.h ${D}${includedir}
+ install -m 644 src/MQTTClient.h ${D}${includedir}
+ install -m 644 src/MQTTClientPersistence.h ${D}${includedir}
+}
+
+DEPENDS = "openssl"
+RDEPENDS_${PN} = "openssl"
diff --git a/meta-edison-middleware/recipes-connectivity/sshpass/sshpass.inc b/meta-edison-middleware/recipes-connectivity/sshpass/sshpass.inc
new file mode 100644
index 0000000..b19ae43
--- /dev/null
+++ b/meta-edison-middleware/recipes-connectivity/sshpass/sshpass.inc
@@ -0,0 +1,10 @@
+DESCRIPTION = "Non-interactive ssh password auth"
+HOMEPAGE = "http://sshpass.sourceforge.net/"
+SECTION = "console/network"
+LICENSE = "GPLv2"
+
+SRC_URI = "${SOURCEFORGE_MIRROR}/sshpass/sshpass-${PV}.tar.gz"
+
+INC_PR = "r0"
+
+inherit autotools
diff --git a/meta-edison-middleware/recipes-connectivity/sshpass/sshpass_1.05.bb b/meta-edison-middleware/recipes-connectivity/sshpass/sshpass_1.05.bb
new file mode 100644
index 0000000..a345dbd
--- /dev/null
+++ b/meta-edison-middleware/recipes-connectivity/sshpass/sshpass_1.05.bb
@@ -0,0 +1,8 @@
+PR = "${INC_PR}.0"
+
+require sshpass.inc
+
+LIC_FILES_CHKSUM = "file://COPYING;md5=94d55d512a9ba36caa9b7df079bae19f"
+
+SRC_URI[md5sum] = "c52d65fdee0712af6f77eb2b60974ac7"
+SRC_URI[sha256sum] = "c3f78752a68a0c3f62efb3332cceea0c8a1f04f7cf6b46e00ec0c3000bc8483e"
diff --git a/meta-edison-middleware/recipes-connectivity/zeromq/cppzmq_git.bb b/meta-edison-middleware/recipes-connectivity/zeromq/cppzmq_git.bb
new file mode 100644
index 0000000..26e89b1
--- /dev/null
+++ b/meta-edison-middleware/recipes-connectivity/zeromq/cppzmq_git.bb
@@ -0,0 +1,19 @@
+DESCRIPTION = "C++ bindings for ZeroMQ"
+HOMEPAGE = "http://www.zeromq.org"
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=db174eaf7b55a34a7c89551197f66e94"
+DEPENDS = "zeromq"
+SRCREV = "ee47ae4cddc304741526c9bb2035f98c3274e0ec"
+
+SRC_URI = "git://github.com/zeromq/cppzmq.git"
+
+S = "${WORKDIR}/git"
+
+do_install () {
+ install -d ${D}/usr/include
+ install -m 0755 ${S}/zmq.hpp ${D}/usr/include/
+}
+
+PACKAGES = "${PN}-dev"
+
+RDEPENDS_${PN}-dev = "zeromq-dev"
diff --git a/meta-edison-middleware/recipes-connectivity/zeromq/zeromq_4.0.4.bb b/meta-edison-middleware/recipes-connectivity/zeromq/zeromq_4.0.4.bb
new file mode 100644
index 0000000..2b6b225
--- /dev/null
+++ b/meta-edison-middleware/recipes-connectivity/zeromq/zeromq_4.0.4.bb
@@ -0,0 +1,15 @@
+DESCRIPTION = "Zeromq - The Intelligent Transport Layer"
+HOMEPAGE = "http://www.zeromq.org"
+LICENSE = "LGPLv3+"
+
+PR = "r2"
+
+LIC_FILES_CHKSUM = " \
+ file://COPYING.LESSER;md5=d5311495d952062e0e4fbba39cbf3de1 \
+"
+
+SRC_URI = "http://download.zeromq.org/zeromq-${PV}.tar.gz"
+SRC_URI[md5sum] = "f3c3defbb5ef6cc000ca65e529fdab3b"
+SRC_URI[sha256sum] = "1ef71d46e94f33e27dd5a1661ed626cd39be4d2d6967792a275040e34457d399"
+
+inherit autotools gettext
diff --git a/meta-edison-middleware/recipes-core/images/edison-image.bbappend b/meta-edison-middleware/recipes-core/images/edison-image.bbappend
new file mode 100644
index 0000000..c43c465
--- /dev/null
+++ b/meta-edison-middleware/recipes-core/images/edison-image.bbappend
@@ -0,0 +1,28 @@
+IMAGE_INSTALL += "packagegroup-core-buildessential"
+
+IMAGE_INSTALL += "iotkit-opkg"
+IMAGE_INSTALL += "zeromq-dev"
+IMAGE_INSTALL += "cppzmq-dev"
+IMAGE_INSTALL += "paho-mqtt-dev"
+IMAGE_INSTALL += "mdns-dev"
+IMAGE_INSTALL += "iotkit-comm-js"
+IMAGE_INSTALL += "iotkit-comm-c-dev"
+IMAGE_INSTALL += "iotkit-agent"
+IMAGE_INSTALL += "iotkit-lib-c-dev"
+IMAGE_INSTALL += "xdk-daemon"
+IMAGE_INSTALL += "oobe"
+
+# mosquitto and dependencies
+IMAGE_INSTALL += "mosquitto-dev"
+IMAGE_INSTALL += "mosquitto-clients"
+
+# node and sub-components
+IMAGE_INSTALL += "nodejs-dev"
+IMAGE_INSTALL += "nodejs-npm"
+
+# MRAA
+IMAGE_INSTALL += "mraa-dev"
+IMAGE_INSTALL += "mraa-doc"
+
+# UPM
+IMAGE_INSTALL += "upm-dev"
diff --git a/meta-edison-middleware/recipes-devtools/iotkit-agent/iotkit-agent_0.2.0.bb b/meta-edison-middleware/recipes-devtools/iotkit-agent/iotkit-agent_0.2.0.bb
new file mode 100644
index 0000000..29d7d70
--- /dev/null
+++ b/meta-edison-middleware/recipes-devtools/iotkit-agent/iotkit-agent_0.2.0.bb
@@ -0,0 +1,84 @@
+DESCRIPTION = "Transparently implements the necessary message formats and transport security as well as device registration"
+HOMEPAGE = "http://enableiot.com"
+LICENSE = "BSD-2-Clause & BSD-3-Clause & GPL-2.0 & Apache-2.0 & MIT & PD"
+
+LIC_FILES_CHKSUM = "file://${WORKDIR}/git/LICENSE;md5=30c8ae0368f724cf5f753d08bf033034"
+
+DEPENDS = "nodejs-native"
+
+SRC_URI = "git://github.com/intel-iot-devkit/iotkit-agent.git;protocol=https;branch=dprelease;tag=prod-v${PV}"
+
+S = "${WORKDIR}/git"
+
+do_compile () {
+ # changing the home directory to the working directory, the .npmrc will be created in this directory
+ export HOME=${WORKDIR}
+
+ # does not build dev packages
+ npm config set dev false
+
+ # access npm registry using http
+ npm set strict-ssl false
+ npm config set registry http://registry.npmjs.org/
+
+ # configure http proxy if neccessary
+ if [ -n "${http_proxy}" ]; then
+ npm config set proxy ${http_proxy}
+ fi
+ if [ -n "${HTTP_PROXY}" ]; then
+ npm config set proxy ${HTTP_PROXY}
+ fi
+
+ # configure cache to be in working directory
+ npm set cache ${WORKDIR}/npm_cache
+
+ # clear local cache prior to each compile
+ npm cache clear
+
+ # compile and install node modules in source directory
+ npm --arch=${TARGET_ARCH} --production --verbose install
+}
+
+do_install () {
+ install -d ${D}${libdir}
+ install -d ${D}${libdir}/node_modules/
+ install -d ${D}${libdir}/node_modules/iotkit-agent/
+ install -d ${D}${sysconfdir}/iotkit-agent/
+ install -d ${D}${libdir}/node_modules/iotkit-agent/config/
+ install -m 0644 ${S}/package.json ${D}${libdir}/node_modules/iotkit-agent/
+ install -m 0644 ${S}/config/config.json ${D}${sysconfdir}/iotkit-agent/
+ install -d ${D}${datadir}/iotkit-agent/
+ install -d ${D}${bindir}
+
+ cp -r ${S}/node_modules ${D}${libdir}/node_modules/iotkit-agent/
+ cp -r ${S}/admin ${D}${libdir}/node_modules/iotkit-agent/
+ cp -r ${S}/api ${D}${libdir}/node_modules/iotkit-agent/
+ cp -r ${S}/bin ${D}${libdir}/node_modules/iotkit-agent/
+ cp -r ${S}/certs ${D}${datadir}/iotkit-agent/
+ cp -r ${S}/data ${D}${datadir}/iotkit-agent/
+ cp -r ${S}/lib ${D}${libdir}/node_modules/iotkit-agent/
+ cp -r ${S}/listeners ${D}${libdir}/node_modules/iotkit-agent/
+ install -m 0644 ${S}/config/index.js ${D}${libdir}/node_modules/iotkit-agent/config
+ install -m 0755 ${S}/iotkit-admin.js ${D}${libdir}/node_modules/iotkit-agent/
+ install -m 0755 ${S}/iotkit-agent.js ${D}${libdir}/node_modules/iotkit-agent/
+ ln -s ../lib/node_modules/iotkit-agent/iotkit-agent.js ${D}${bindir}/iotkit-agent
+ ln -s ../lib/node_modules/iotkit-agent/iotkit-admin.js ${D}${bindir}/iotkit-admin
+
+ install -d ${D}${systemd_unitdir}/system/
+ install -m 0644 ${S}/iotkit-agent.service ${D}${systemd_unitdir}/system/
+}
+
+inherit systemd
+
+# since the agent requires registration before running we don't want to start
+# the systemd service by default
+SYSTEMD_AUTO_ENABLE = "disable"
+SYSTEMD_SERVICE_${PN} = "iotkit-agent.service"
+
+FILES_${PN} = "${libdir}/node_modules/ \
+ ${bindir}/iotkit-agent \
+ ${bindir}/iotkit-admin \
+ ${datadir}/iotkit-agent/ \
+ ${sysconfdir}/iotkit-agent/"
+
+PACKAGES = "${PN}"
diff --git a/meta-edison-middleware/recipes-devtools/iotkit-comm-c/iotkit-comm-c_0.1.1.bb b/meta-edison-middleware/recipes-devtools/iotkit-comm-c/iotkit-comm-c_0.1.1.bb
new file mode 100644
index 0000000..c1c0260
--- /dev/null
+++ b/meta-edison-middleware/recipes-devtools/iotkit-comm-c/iotkit-comm-c_0.1.1.bb
@@ -0,0 +1,114 @@
+DESCRIPTION = "Inter of Things communication library for device-to-device and device-to-cloud messaging"
+LICENSE = "MIT"
+
+PR = "r2"
+
+SRC_URI = "git://github.com/intel-iot-devkit/iotkit-comm-c.git;protocol=git"
+SRCREV = "2367175b07852a8d2600677f5d893af49973f422"
+
+LIC_FILES_CHKSUM = " \
+ file://COPYING;md5=e8db6501ed294e65418a933925d12058 \
+"
+
+S = "${WORKDIR}/git"
+
+DEPENDS = "zeromq mdns paho-mqtt"
+
+inherit pkgconfig cmake
+
+do_configure() {
+ cd ${B}/
+ cmake ${S}/src
+}
+
+do_compile() {
+ cd ${B}/
+ oe_runmake
+}
+
+do_install() {
+ # Copy the header files to /usr/include/iotkit-comm
+ install -d ${D}${includedir}/iotkit-comm
+ install -m 644 ${S}/src/lib/cJSON/cJSON.h ${D}${includedir}/iotkit-comm/
+ install -m 644 ${S}/src/lib/libiotkit-comm/iotkit-comm.h ${D}${includedir}/iotkit-comm/
+ install -m 644 ${S}/src/lib/libiotkit-comm/iotkit-comm_mdns.h ${D}${includedir}/iotkit-comm/
+ install -m 644 ${S}/src/lib/libiotkit-comm/util.h ${D}${includedir}/iotkit-comm/
+
+ # Copy the shared libraries to /usr/lib
+ install -d ${D}${libdir}
+ install ${B}/lib/libiotkit-comm/libiotkit-comm.so ${D}${libdir}/
+ install ${B}/lib/plugins/libiotkitpubsub/libiotkit-agent-client.so ${D}${libdir}/
+ install ${B}/lib/plugins/libiotkitpubsub/libiotkit-agent-service.so ${D}${libdir}/
+ install ${B}/lib/plugins/libmqttpubsub/libmqttpubsub-client.so ${D}${libdir}/
+ install ${B}/lib/plugins/libmqttpubsub/libmqttpubsub-service.so ${D}${libdir}/
+ install ${B}/lib/plugins/libzmqpubsub/libzmqpubsub-client.so ${D}${libdir}/
+ install ${B}/lib/plugins/libzmqpubsub/libzmqpubsub-service.so ${D}${libdir}/
+ install ${B}/lib/plugins/libzmqreqrep/libzmqreqrep-client.so ${D}${libdir}/
+ install ${B}/lib/plugins/libzmqreqrep/libzmqreqrep-service.so ${D}${libdir}/
+
+ # Copy config files
+ install -d ${D}${sysconfdir}/iotkit-comm
+ install -m 644 ${S}/src/lib/libiotkit-comm/config.json ${D}${sysconfdir}/iotkit-comm/
+ cp -r ${S}/src/lib/libiotkit-comm/plugin-interfaces ${D}${sysconfdir}/iotkit-comm/
+
+ # Copy the Sample apps
+ install -d ${D}${datadir}/iotkit-comm
+ install -d ${D}${datadir}/iotkit-comm/examples
+ install -d ${D}${datadir}/iotkit-comm/examples/c
+ cp -r ${S}/src/examples/iotkit-apps ${D}${datadir}/iotkit-comm/examples/c/
+ cp -r ${S}/src/examples/zmq-apps ${D}${datadir}/iotkit-comm/examples/c/
+ cp -r ${S}/src/examples/mqtt-apps ${D}${datadir}/iotkit-comm/examples/c/
+ cp -r ${S}/src/examples/serviceQueries ${D}${datadir}/iotkit-comm/examples/c/
+ cp -r ${S}/src/examples/serviceSpecs ${D}${datadir}/iotkit-comm/examples/c/
+ cp -r ${S}/src/examples/distributed-thermostat ${D}${datadir}/iotkit-comm/examples/c/
+ rm -rf ${D}${datadir}/iotkit-comm/examples/c/iotkit-apps/CMakeLists.txt
+ rm -rf ${D}${datadir}/iotkit-comm/examples/c/mqtt-apps/CMakeLists.txt
+ rm -rf ${D}${datadir}/iotkit-comm/examples/c/zmq-apps/CMakeLists.txt
+ rm -rf ${D}${datadir}/iotkit-comm/examples/c/distributed-thermostat/CMakeLists.txt
+ rm -rf ${D}${datadir}/iotkit-comm/examples/c/distributed-thermostat/doxygen.conf
+ install ${B}/examples/distributed-thermostat/dashboard ${D}${datadir}/iotkit-comm/examples/c/
+ install ${B}/examples/distributed-thermostat/sensor ${D}${datadir}/iotkit-comm/examples/c/
+ install ${B}/examples/distributed-thermostat/thermostat ${D}${datadir}/iotkit-comm/examples/c/
+ install ${B}/examples/iotkit-apps/iotkitclient ${D}${datadir}/iotkit-comm/examples/c/
+ install ${B}/examples/iotkit-apps/iotkitservice ${D}${datadir}/iotkit-comm/examples/c/
+ install ${B}/examples/mqtt-apps/subscriber ${D}${datadir}/iotkit-comm/examples/c/
+ install ${B}/examples/mqtt-apps/publisher ${D}${datadir}/iotkit-comm/examples/c/
+ install ${B}/examples/zmq-apps/zmqsubclient ${D}${datadir}/iotkit-comm/examples/c/
+ install ${B}/examples/zmq-apps/zmqpubservice ${D}${datadir}/iotkit-comm/examples/c/
+ install ${B}/examples/zmq-apps/zmqreqclient ${D}${datadir}/iotkit-comm/examples/c/
+ install ${B}/examples/zmq-apps/zmqrepservice ${D}${datadir}/iotkit-comm/examples/c/
+
+ # Copy the invalid/valid config json files which are needed for Test programs
+ install -d ${D}${datadir}/iotkit-comm/tests/
+ install -d ${D}${datadir}/iotkit-comm/tests/c/
+ install -d ${D}${datadir}/iotkit-comm/tests/c/libiotkit-comm
+ cp ${S}/src/tests/libiotkit-comm/*.json ${D}${datadir}/iotkit-comm/tests/c/libiotkit-comm/
+
+ # Copy test programs
+ cp ${B}/tests/CTestTestfile.cmake ${D}${datadir}/iotkit-comm/tests/c/
+ install -d ${D}${datadir}/iotkit-comm/tests/c/iotkitpubsub
+ cp ${B}/tests/iotkitpubsub/iotkitpubsub* ${D}${datadir}/iotkit-comm/tests/c/iotkitpubsub/
+ cp ${B}/tests/iotkitpubsub/CTestTestfile.cmake ${D}${datadir}/iotkit-comm/tests/c/iotkitpubsub/
+ install -d ${D}${datadir}/iotkit-comm/tests/c/mqttpubsub
+ cp ${B}/tests/mqttpubsub/mqttpubsub* ${D}${datadir}/iotkit-comm/tests/c/mqttpubsub/
+ cp ${B}/tests/mqttpubsub/CTestTestfile.cmake ${D}${datadir}/iotkit-comm/tests/c/mqttpubsub/
+ install -d ${D}${datadir}/iotkit-comm/tests/c/zmqpubsub
+ cp ${B}/tests/zmqpubsub/zmqpubsub_* ${D}${datadir}/iotkit-comm/tests/c/zmqpubsub/
+ cp ${B}/tests/zmqpubsub/CTestTestfile.cmake ${D}${datadir}/iotkit-comm/tests/c/zmqpubsub/
+ cp ${B}/tests/libiotkit-comm/mdns_* ${D}${datadir}/iotkit-comm/tests/c/libiotkit-comm/
+ cp ${B}/tests/libiotkit-comm/iotkit-comm_* ${D}${datadir}/iotkit-comm/tests/c/libiotkit-comm/
+ cp ${B}/tests/libiotkit-comm/CTestTestfile.cmake ${D}${datadir}/iotkit-comm/tests/c/libiotkit-comm/
+ install -d ${D}${datadir}/iotkit-comm/tests/c/zmqreqrep
+ cp ${B}/tests/zmqreqrep/zmqreqrep_* ${D}${datadir}/iotkit-comm/tests/c/zmqreqrep/
+ cp ${B}/tests/zmqreqrep/CTestTestfile.cmake ${D}${datadir}/iotkit-comm/tests/c/zmqreqrep/
+}
+
+FILES_${PN} += "${libdir}"
+RDEPENDS_${PN} = "zeromq mdns paho-mqtt mosquitto sshpass"
+
+PACKAGES += "${PN}-tests"
+RDEPENDS_${PN}-tests += "${PN} gcov cmake"
+
+FILES_${PN}-dev = "${includedir} ${datadir}/iotkit-comm/examples/c/"
+FILES_${PN}-dbg += "${datadir}/iotkit-comm/examples/c/.debug/ ${datadir}/iotkit-comm/tests/c/iotkitpubsub/.debug/ ${datadir}/iotkit-comm/tests/c/mqttpubsub/.debug/ ${datadir}/iotkit-comm/tests/c/zmqpubsub/.debug/ ${datadir}/iotkit-comm/tests/c/libiotkit-comm/.debug/ ${datadir}/iotkit-comm/tests/c/zmqreqrep/.debug/"
+FILES_${PN}-tests += "${datadir}/iotkit-comm/tests/c/"
diff --git a/meta-edison-middleware/recipes-devtools/iotkit-comm-js/iotkit-comm-js_0.1.1.bb b/meta-edison-middleware/recipes-devtools/iotkit-comm-js/iotkit-comm-js_0.1.1.bb
new file mode 100644
index 0000000..8b0d20f
--- /dev/null
+++ b/meta-edison-middleware/recipes-devtools/iotkit-comm-js/iotkit-comm-js_0.1.1.bb
@@ -0,0 +1,100 @@
+DESCRIPTION = "Inter of Things communication library for device-to-device and device-to-cloud messaging"
+LICENSE = "MIT"
+
+PR = "r2"
+
+SRC_URI = "git://github.com/intel-iot-devkit/iotkit-comm-js.git;protocol=git"
+SRCREV = "5ccea56e88755c9f6e3cd37bb5fc5d747b8496aa"
+
+LIC_FILES_CHKSUM = " \
+ file://COPYING;md5=e8db6501ed294e65418a933925d12058 \
+"
+
+S = "${WORKDIR}/git"
+
+DEPENDS = "nodejs-native zeromq mdns paho-mqtt"
+
+do_compile () {
+ # changing the home directory to the working directory, the .npmrc will be created in this directory
+ export HOME=${WORKDIR}
+
+ # does not build dev packages
+ npm config set dev false
+
+ # access npm registry using http
+ npm set strict-ssl false
+ npm config set registry http://registry.npmjs.org/
+
+ # configure http proxy if neccessary
+ if [ -n "${http_proxy}" ]; then
+ npm config set proxy ${http_proxy}
+ fi
+ if [ -n "${HTTP_PROXY}" ]; then
+ npm config set proxy ${HTTP_PROXY}
+ fi
+
+ # configure cache to be in working directory
+ npm set cache ${WORKDIR}/npm_cache
+
+ # clear local cache prior to each compile
+ npm cache clear
+
+ # compile and install node modules in source directory
+ npm --arch=${TARGET_ARCH} --verbose install
+}
+
+do_install () {
+ install -d ${D}${libdir}/node_modules/iotkit-comm/
+ cp -r ${S}/node_modules ${D}${libdir}/node_modules/iotkit-comm/
+ install -m 644 ${S}/package.json ${D}${libdir}/node_modules/iotkit-comm/
+ install -m 644 ${S}/COPYING ${D}${libdir}/node_modules/iotkit-comm/
+ install -m 644 ${S}/README.md ${D}${libdir}/node_modules/iotkit-comm/
+ install -m 644 ${S}/jsdoc-conf.json ${D}${libdir}/node_modules/iotkit-comm/
+ cp -r ${S}/lib ${D}${libdir}/node_modules/iotkit-comm/
+ cp -r ${S}/test ${D}${libdir}/node_modules/iotkit-comm/
+ cp -r ${S}/doc ${D}${libdir}/node_modules/iotkit-comm/
+ install -d ${D}${datadir}/iotkit-comm/examples/node
+ cp -r ${S}/example/* ${D}${datadir}/iotkit-comm/examples/node
+
+ chmod 755 ${D}${libdir}/node_modules/iotkit-comm/lib/setup.js
+ install -d ${D}${bindir}
+ ln -s ../lib/node_modules/iotkit-comm/lib/setup.js ${D}${bindir}/iotkit-comm
+}
+
+INHIBIT_PACKAGE_STRIP = "1"
+
+PACKAGES = "${PN} ${PN}-test-dependencies"
+
+FILES_${PN}-test-dependencies = " \
+ ${libdir}/node_modules/iotkit-comm/node_modules/.bin/istanbul \
+ ${libdir}/node_modules/iotkit-comm/node_modules/.bin/jsdoc \
+ ${libdir}/node_modules/iotkit-comm/node_modules/.bin/mocha \
+ ${libdir}/node_modules/iotkit-comm/node_modules/.bin/_mocha \
+ ${libdir}/node_modules/iotkit-comm/node_modules/chai/ \
+ ${libdir}/node_modules/iotkit-comm/node_modules/istanbul/ \
+ ${libdir}/node_modules/iotkit-comm/node_modules/jsdoc/ \
+ ${libdir}/node_modules/iotkit-comm/node_modules/mocha/ \
+"
+
+FILES_${PN} = " \
+ ${libdir}/node_modules/iotkit-comm/doc/ \
+ ${libdir}/node_modules/iotkit-comm/jsdoc-conf.json \
+ ${libdir}/node_modules/iotkit-comm/COPYING \
+ ${libdir}/node_modules/iotkit-comm/lib/ \
+ ${libdir}/node_modules/iotkit-comm/package.json \
+ ${libdir}/node_modules/iotkit-comm/README.md \
+ ${libdir}/node_modules/iotkit-comm/test \
+ ${libdir}/node_modules/iotkit-comm/node_modules/.bin/mqtt_pub \
+ ${libdir}/node_modules/iotkit-comm/node_modules/.bin/mqtt_sub \
+ ${libdir}/node_modules/iotkit-comm/node_modules/async/ \
+ ${libdir}/node_modules/iotkit-comm/node_modules/commander/ \
+ ${libdir}/node_modules/iotkit-comm/node_modules/mdns2/ \
+ ${libdir}/node_modules/iotkit-comm/node_modules/mqtt/ \
+ ${libdir}/node_modules/iotkit-comm/node_modules/read/ \
+ ${libdir}/node_modules/iotkit-comm/node_modules/zmq/ \
+ ${datadir}/iotkit-comm/examples/ \
+ ${bindir}/iotkit-comm \
+"
+
+RDEPENDS_${PN} = "nodejs zeromq mdns paho-mqtt mosquitto sshpass"
+RDEPENDS_${PN}-test-dependencies = "${PN}"
diff --git a/meta-edison-middleware/recipes-devtools/iotkit-lib-c/iotkit-lib-c_0.1.0.bb b/meta-edison-middleware/recipes-devtools/iotkit-lib-c/iotkit-lib-c_0.1.0.bb
new file mode 100644
index 0000000..629cee7
--- /dev/null
+++ b/meta-edison-middleware/recipes-devtools/iotkit-lib-c/iotkit-lib-c_0.1.0.bb
@@ -0,0 +1,49 @@
+SUMMARY = "Transparently implements the necessary message formats and transport security as well as device registration"
+SECTION = "libs"
+HOMEPAGE = "http://enableiot.com"
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://COPYING;md5=e8db6501ed294e65418a933925d12058"
+
+DEPENDS = "nodejs-native swig-native curl"
+
+PR = "r1"
+
+SRC_URI = "git://github.com/enableiot/iotkit-lib-c.git;protocol=https;tag=v1.4.0"
+
+S = "${WORKDIR}/git"
+
+EXTRA_OECMAKE += " -DSTAGING_DIR_TARGET=${STAGING_DIR_TARGET}"
+
+inherit distutils-base pkgconfig python-dir cmake
+
+do_compile_prepend () {
+ # when yocto builds in ${D} it does not have access to ../git/.git so git
+ # describe --tags fails. In order not to tag our version as dirty we use this
+ # trick
+ sed -i 's/-dirty//' src/version.c
+}
+
+do_install_prepend () {
+ # Copy config file
+ install -d ${D}${sysconfdir}/iotkit-lib
+ install -d ${D}${datadir}/iotkit-lib
+ install -m 644 ${S}/config/config.json ${D}${sysconfdir}/iotkit-lib/
+
+ # Copy test programs
+ cp -r ${B}/tests/ ${D}${datadir}/iotkit-lib/
+ rm -rf ${D}${datadir}/iotkit-lib/tests/CMakeFiles/
+ touch ${D}${datadir}/iotkit-lib/.setup.done
+}
+
+PACKAGES =+ "${PN}-tests"
+
+FILES_${PN}-dbg += "${libdir}/node_modules/iotkitjs/.debug/ \
+ ${PYTHON_SITEPACKAGES_DIR}/.debug/ \
+ ${datadir}/iotkit-lib/tests/.debug/"
+
+FILES_${PN}-tests = "${datadir}/iotkit-lib/tests/*"
+
+FILES_${PN} += "${sysconfdir} \
+ ${datadir}/iotkit-lib/.setup.done"
+
+RDEPENDS_${PN}-tests += "${PN} gcov cmake"
diff --git a/meta-edison-middleware/recipes-devtools/iotkit-opkg/files/iotkit.conf b/meta-edison-middleware/recipes-devtools/iotkit-opkg/files/iotkit.conf
new file mode 100644
index 0000000..a44c5c0
--- /dev/null
+++ b/meta-edison-middleware/recipes-devtools/iotkit-opkg/files/iotkit.conf
@@ -0,0 +1 @@
+src iotkit http://iotdk.intel.com/repos/1.1/intelgalactic
diff --git a/meta-edison-middleware/recipes-devtools/iotkit-opkg/iotkit-opkg_0.0.1.bb b/meta-edison-middleware/recipes-devtools/iotkit-opkg/iotkit-opkg_0.0.1.bb
new file mode 100644
index 0000000..019c9ba
--- /dev/null
+++ b/meta-edison-middleware/recipes-devtools/iotkit-opkg/iotkit-opkg_0.0.1.bb
@@ -0,0 +1,22 @@
+DESCRIPTION="This configures the opkg sources for the iotkit packages"
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+
+SRC_URI = " \
+ file://iotkit.conf \
+"
+
+PR = "r0"
+
+do_install() {
+ install -d ${D}${sysconfdir}/opkg
+ install -m 0644 ${WORKDIR}/iotkit.conf ${D}${sysconfdir}/opkg
+}
+
+
+RDEPENDS_${PN} = "opkg"
+
+FILES_${PN} = "${sysconfdir}/opkg"
+
+PACKAGES = "${PN}"
+
diff --git a/meta-edison-middleware/recipes-devtools/mraa/mraa_0.5.2.bb b/meta-edison-middleware/recipes-devtools/mraa/mraa_0.5.2.bb
new file mode 100644
index 0000000..787c36b
--- /dev/null
+++ b/meta-edison-middleware/recipes-devtools/mraa/mraa_0.5.2.bb
@@ -0,0 +1,27 @@
+SUMMARY = "Low Level Skeleton Library for Communication on Intel platforms"
+SECTION = "libs"
+AUTHOR = "Brendan Le Foll, Tom Ingleby"
+
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://COPYING;md5=e8db6501ed294e65418a933925d12058"
+
+DEPENDS = "nodejs swig-native"
+
+SRC_URI = "git://github.com/intel-iot-devkit/mraa.git;protocol=git"
+SRCREV = "bb3228ad5854b5f289c32737a6a106b139e24a05"
+
+S = "${WORKDIR}/git"
+
+inherit distutils-base pkgconfig python-dir cmake
+
+FILES_${PN}-doc += "${datadir}/mraa/examples/"
+
+FILES_${PN}-dbg += "${libdir}/node_modules/mraajs/.debug/ \
+ ${PYTHON_SITEPACKAGES_DIR}/.debug/"
+
+do_compile_prepend () {
+ # when yocto builds in ${D} it does not have access to ../git/.git so git
+ # describe --tags fails. In order not to tag our version as dirty we use this
+ # trick
+ sed -i 's/-dirty//' src/version.c
+} \ No newline at end of file
diff --git a/meta-edison-middleware/recipes-devtools/nodejs/nodejs_0.10.28.bb b/meta-edison-middleware/recipes-devtools/nodejs/nodejs_0.10.28.bb
new file mode 100644
index 0000000..a463bc8
--- /dev/null
+++ b/meta-edison-middleware/recipes-devtools/nodejs/nodejs_0.10.28.bb
@@ -0,0 +1,85 @@
+DESCRIPTION = "nodeJS Evented I/O for V8 JavaScript"
+HOMEPAGE = "http://nodejs.org"
+# tools/wrk is under Apache-2.0
+LICENSE = "MIT & BSD & Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=4a31e6c424761191227143b86f58a1ef"
+
+DEPENDS = "openssl"
+DEPENDS_class-target = "nodejs-native"
+
+PR = "r1"
+
+SRC_URI = "git://github.com/joyent/node.git;protocol=https;branch=v0.10;tag=v0.10.28"
+
+S = "${WORKDIR}/git"
+
+# v8 errors out if you have set CCACHE
+CCACHE = ""
+
+ARCHFLAGS_arm = "${@bb.utils.contains('TUNE_FEATURES', 'callconvention-hard', '--with-arm-float-abi=hard', '--with-arm-float-abi=softfp', d)}"
+ARCHFLAGS ?= ""
+
+# Node is way too cool to use proper autotools, so we install two wrappers to forcefully inject proper arch cflags to workaround gypi
+do_configure () {
+ export LD="${CXX}"
+ ./configure --prefix=${prefix} --without-snapshot --shared-openssl ${ARCHFLAGS}
+}
+
+do_compile () {
+ export LD="${CXX}"
+ make BUILDTYPE=Release
+}
+
+do_install () {
+ oe_runmake install DESTDIR=${D}
+}
+
+do_install_append_class-target () {
+ # install node-gyp node hedaers in /usr/include/node-gyp/
+ cd ${D}/${libdir}/node_modules/npm/node_modules/node-gyp/
+ export HOME=${D}/usr/include/node-gyp
+
+ sed -i 's/\.node-gyp//' lib/node-gyp.js
+
+ # configure http proxy if neccessary
+ if [ -n "${http_proxy}" ]; then
+ ${STAGING_BINDIR_NATIVE}/node bin/node-gyp.js --verbose --proxy=${http_proxy} install
+ elif [ -n "${HTTP_PROXY}" ]; then
+ ${STAGING_BINDIR_NATIVE}/node bin/node-gyp.js --verbose --proxy=${HTTP_PROXY} install
+ else
+ ${STAGING_BINDIR_NATIVE}/node bin/node-gyp.js --verbose install
+ fi
+}
+
+do_install_append_class-native() {
+ # /usr/bin/npm is symlink to /usr/lib/node_modules/npm/bin/npm-cli.js
+ # use sed on npm-cli.js because otherwise symlink is replaced with normal file and
+ # npm-cli.js continues to use old shebang
+ sed "1s^.*^#\!/usr/bin/env node^g" -i ${D}${libdir}/node_modules/npm/bin/npm-cli.js
+}
+
+do_install_append_class-target() {
+ sed "1s^.*^#\!${bindir}/env node^g" -i ${D}${libdir}/node_modules/npm/bin/npm-cli.js
+}
+
+pkg_postinst_${PN} () {
+ sed -e '/^PATH=/aNODE_PATH=\/usr\/lib\/node_modules\/' \
+ -e 's/\(^export\)\(.*\)/\1 NODE_PATH\2/' \
+ -i $D/etc/profile
+}
+
+pkg_prerm_${PN} () {
+ sed -e '/^NODE_PATH.*$/d' \
+ -e 's/\(^export\)\(.*\)\(\<NODE_PATH\>\s\)\(.*\)/\1\2\4/' \
+ -i $D/etc/profile
+}
+
+RDEPENDS_${PN} = "curl"
+RDEPENDS_${PN}_class-native = ""
+
+PACKAGES += "${PN}-npm"
+FILES_${PN}-npm = "${libdir}/node_modules ${bindir}/npm"
+RDEPENDS_${PN}-npm = "python-shell python-datetime python-subprocess python-crypt python-textutils \
+ python-netclient python-ctypes python-misc python-compiler python-multiprocessing"
+
+BBCLASSEXTEND = "native"
diff --git a/meta-edison-middleware/recipes-devtools/oobe/oobe_0.0.1.bb b/meta-edison-middleware/recipes-devtools/oobe/oobe_0.0.1.bb
new file mode 100644
index 0000000..ebf73d0
--- /dev/null
+++ b/meta-edison-middleware/recipes-devtools/oobe/oobe_0.0.1.bb
@@ -0,0 +1,64 @@
+DESCRIPTION="The out-of-box configuration service"
+LICENSE = "MIT"
+
+S = "${EDISONREPO_TOP_DIR}/mw/oobe"
+
+LIC_FILES_CHKSUM = " \
+ file://LICENSE;md5=ea398a763463b76b18da15f013c0c531 \
+"
+
+DEPENDS = "nodejs-native"
+
+do_compile() {
+ # changing the home directory to the working directory, the .npmrc will be created in this directory
+ export HOME=${WORKDIR}
+
+ # does not build dev packages
+ npm config set dev false
+
+ # access npm registry using http
+ npm set strict-ssl false
+ npm config set registry http://registry.npmjs.org/
+
+ # configure http proxy if neccessary
+ if [ -n "${http_proxy}" ]; then
+ npm config set proxy ${http_proxy}
+ fi
+ if [ -n "${HTTP_PROXY}" ]; then
+ npm config set proxy ${HTTP_PROXY}
+ fi
+
+ # configure cache to be in working directory
+ npm set cache ${WORKDIR}/npm_cache
+
+ # clear local cache prior to each compile
+ npm cache clear
+
+ # compile and install node modules in source directory
+ npm --arch=${TARGET_ARCH} --verbose install
+}
+
+do_install() {
+ install -d ${D}${libdir}/edison_config_tools
+ install -d ${D}/var/lib/edison_config_tools
+ cp -r ${S}/src/public ${D}${libdir}/edison_config_tools
+ cp -r ${S}/node_modules ${D}${libdir}/edison_config_tools
+ install -m 0644 ${S}/src/server.js ${D}${libdir}/edison_config_tools/edison-config-server.js
+ install -d ${D}${systemd_unitdir}/system/
+ install -m 0644 ${S}/src/edison_config.service ${D}${systemd_unitdir}/system/
+ install -d ${D}${bindir}
+ install -m 0755 ${S}/src/configure_edison ${D}${bindir}
+}
+
+inherit systemd
+
+SYSTEMD_AUTO_ENABLE = "enable"
+SYSTEMD_SERVICE_${PN} = "edison_config.service"
+
+FILES_${PN} = "${libdir}/edison_config_tools \
+ ${systemd_unitdir}/system \
+ /var/lib/edison_config_tools \
+ ${bindir}/"
+
+PACKAGES = "${PN}"
+
diff --git a/meta-edison-middleware/recipes-devtools/upm/upm_0.1.8.bb b/meta-edison-middleware/recipes-devtools/upm/upm_0.1.8.bb
new file mode 100644
index 0000000..b259d42
--- /dev/null
+++ b/meta-edison-middleware/recipes-devtools/upm/upm_0.1.8.bb
@@ -0,0 +1,17 @@
+SUMMARY = "Sensor/Actuator repository for Mraa"
+SECTION = "libs"
+AUTHOR = "Brendan Le Foll, Tom Ingleby, Yevgeniy Kiveisha"
+
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://COPYING;md5=e8db6501ed294e65418a933925d12058"
+
+DEPENDS = "nodejs swig-native mraa"
+
+SRC_URI = "git://github.com/intel-iot-devkit/upm.git;protocol=git"
+SRCREV = "88eaced5a23c23d1cfe3badfe8deeedda582ae50"
+
+S = "${WORKDIR}/git"
+
+inherit distutils-base pkgconfig python-dir cmake
+
+FILES_${PN}-doc += "${datadir}/upm/examples/" \ No newline at end of file
diff --git a/meta-edison-middleware/recipes-devtools/xdk-daemon/files/xdk-daemon-0.0.27.tar.bz2 b/meta-edison-middleware/recipes-devtools/xdk-daemon/files/xdk-daemon-0.0.27.tar.bz2
new file mode 100644
index 0000000..cff4bee
--- /dev/null
+++ b/meta-edison-middleware/recipes-devtools/xdk-daemon/files/xdk-daemon-0.0.27.tar.bz2
Binary files differ
diff --git a/meta-edison-middleware/recipes-devtools/xdk-daemon/xdk-daemon_0.0.27.bb b/meta-edison-middleware/recipes-devtools/xdk-daemon/xdk-daemon_0.0.27.bb
new file mode 100644
index 0000000..90eb588
--- /dev/null
+++ b/meta-edison-middleware/recipes-devtools/xdk-daemon/xdk-daemon_0.0.27.bb
@@ -0,0 +1,68 @@
+DESCRIPTION = "Provides communication to the Intel XDK"
+LICENSE = "Proprietary"
+
+LIC_FILES_CHKSUM = "file://LICENSE;md5=8a05f85865f8c4b9ba29798e539f93b7"
+
+DEPENDS = "nodejs-native mdns"
+RDEPENDS_${PN} = "libarchive-bin"
+
+PR = "r0"
+
+# URI should point to some external http:// server
+SRC_URI = "file://xdk-daemon-${PV}.tar.bz2"
+
+# we don't care about debug for the few binary node modules
+INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
+
+do_compile () {
+ # changing the home directory to the working directory, the .npmrc will be created in this directory
+ export HOME=${WORKDIR}
+
+ # does not build dev packages
+ npm config set dev false
+
+ # access npm registry using http
+ npm set strict-ssl false
+ npm config set registry http://registry.npmjs.org/
+
+ # configure http proxy if neccessary
+ if [ -n "${http_proxy}" ]; then
+ npm config set proxy ${http_proxy}
+ fi
+ if [ -n "${HTTP_PROXY}" ]; then
+ npm config set proxy ${HTTP_PROXY}
+ fi
+
+ # configure cache to be in working directory
+ npm set cache ${WORKDIR}/npm_cache
+
+ # clear local cache prior to each compile
+ npm cache clear
+
+ npm install --arch=${TARGET_ARCH}
+ cd current/ && npm install --arch=${TARGET_ARCH}
+ cd node-inspector-server && npm install --arch=${TARGET_ARCH}
+
+ sed -i '/TM/d' ${S}/xdk-daemon
+}
+
+do_install () {
+ install -d ${D}/opt/xdk-daemon/
+ cp -a ${S}/* ${D}/opt/xdk-daemon/
+
+ install -d ${D}${systemd_unitdir}/system/
+ install -m 0644 ${S}/xdk-daemon.service ${D}${systemd_unitdir}/system/
+
+ install -d ${D}${bindir}
+ ln -s /opt/xdk-daemon/current/xdk-whitelist ${D}${bindir}/xdk-whitelist
+}
+
+inherit systemd
+
+SYSTEMD_SERVICE_${PN} = "xdk-daemon.service"
+
+FILES_${PN} = "/opt/xdk-daemon/ \
+ ${systemd_unitdir}/system/xdk-daemon.service \
+ ${bindir}/"
+
+PACKAGES = "${PN}"
diff --git a/meta-edison/COPYING.MIT b/meta-edison/COPYING.MIT
new file mode 100644
index 0000000..89de354
--- /dev/null
+++ b/meta-edison/COPYING.MIT
@@ -0,0 +1,17 @@
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/meta-edison/README b/meta-edison/README
new file mode 100644
index 0000000..3237326
--- /dev/null
+++ b/meta-edison/README
@@ -0,0 +1,118 @@
+This README file contains information on building the meta-edison
+BSP layer, and booting the images contained in the /binary directory.
+Please see the corresponding sections below for details.
+
+
+Dependencies
+============
+
+This layer depends on:
+
+ URI: git://git.openembedded.org/bitbake
+ branch: master
+
+ URI: git://git.openembedded.org/openembedded-core
+ layers: meta
+ branch: master
+
+ URI: git://git.yoctoproject.org/xxxx
+ layers: xxxx
+ branch: master
+
+
+Patches
+=======
+
+Please submit any patches against this BSP to the Yocto mailing list
+(yocto@yoctoproject.org) and cc: the maintainer:
+
+Maintainer: XXX YYYYYY <xxx.yyyyyy@zzzzz.com>
+
+Please see the meta-xxxx/MAINTAINERS file for more details.
+
+
+Table of Contents
+=================
+
+ I. Building the meta-edison BSP layer
+ II. Booting the images in /binary
+
+
+I. Building the meta-edison BSP layer
+========================================
+
+--- replace with specific instructions for your layer ---
+
+In order to build an image with BSP support for a given release, you
+need to download the corresponding BSP tarball from the 'Board Support
+Package (BSP) Downloads' page of the Yocto Project website.
+
+Having done that, and assuming you extracted the BSP tarball contents
+at the top-level of your yocto build tree, you can build a
+edison image by adding the location of the meta-edison
+layer to bblayers.conf, along with any other layers needed (to access
+common metadata shared between BSPs) e.g.:
+
+ yocto/meta-xxxx \
+ yocto/meta-xxxx/meta-edison \
+
+To enable the edison layer, add the edison MACHINE to local.conf:
+
+ MACHINE ?= "edison"
+
+You should then be able to build a edison image as such:
+
+ $ source oe-init-build-env
+ $ bitbake core-image-sato
+
+At the end of a successful build, you should have a live image that
+you can boot from a USB flash drive (see instructions on how to do
+that below, in the section 'Booting the images from /binary').
+
+As an alternative to downloading the BSP tarball, you can also work
+directly from the meta-xxxx git repository. For each BSP in the
+'meta-xxxx' repository, there are multiple branches, one corresponding
+to each major release starting with 'laverne' (0.90), in addition to
+the latest code which tracks the current master (note that not all
+BSPs are present in every release). Instead of extracting a BSP
+tarball at the top level of your yocto build tree, you can
+equivalently check out the appropriate branch from the meta-xxxx
+repository at the same location.
+
+
+II. Booting the images in /binary
+=================================
+
+--- replace with specific instructions for your platform ---
+
+This BSP contains bootable live images, which can be used to directly
+boot Yocto off of a USB flash drive.
+
+Under Linux, insert a USB flash drive. Assuming the USB flash drive
+takes device /dev/sdf, use dd to copy the live image to it. For
+example:
+
+# dd if=core-image-sato-edison-20101207053738.hddimg of=/dev/sdf
+# sync
+# eject /dev/sdf
+
+This should give you a bootable USB flash device. Insert the device
+into a bootable USB socket on the target, and power on. This should
+result in a system booted to the Sato graphical desktop.
+
+If you want a terminal, use the arrows at the top of the UI to move to
+different pages of available applications, one of which is named
+'Terminal'. Clicking that should give you a root terminal.
+
+If you want to ssh into the system, you can use the root terminal to
+ifconfig the IP address and use that to ssh in. The root password is
+empty, so to log in type 'root' for the user name and hit 'Enter' at
+the Password prompt: and you should be in.
+
+----
+
+If you find you're getting corrupt images on the USB (it doesn't show
+the syslinux boot: prompt, or the boot: prompt contains strange
+characters), try doing this first:
+
+# dd if=/dev/zero of=/dev/sdf bs=1M count=512
diff --git a/meta-edison/README.sources b/meta-edison/README.sources
new file mode 100644
index 0000000..3c4cb7b
--- /dev/null
+++ b/meta-edison/README.sources
@@ -0,0 +1,17 @@
+The sources for the packages comprising the images shipped with this
+BSP can be found at the following location:
+
+http://downloads.yoctoproject.org/mirror/sources/
+
+The metadata used to generate the images shipped with this BSP, in
+addition to the code contained in this BSP, can be found at the
+following location:
+
+http://www.yoctoproject.org/downloads/yocto-1.1/poky-edison-6.0.tar.bz2
+
+The metadata used to generate the images shipped with this BSP, in
+addition to the code contained in this BSP, can also be found at the
+following locations:
+
+git://git.yoctoproject.org/poky.git
+git://git.yoctoproject.org/meta-xxxx
diff --git a/meta-edison/conf/layer.conf b/meta-edison/conf/layer.conf
new file mode 100644
index 0000000..270675d
--- /dev/null
+++ b/meta-edison/conf/layer.conf
@@ -0,0 +1,10 @@
+# We have a conf and classes directory, add to BBPATH
+BBPATH := "${BBPATH}:${LAYERDIR}"
+
+# We have a recipes-* directories, add to BBFILES
+BBFILES := "${BBFILES} ${LAYERDIR}/recipes-*/*/*.bb \
+ ${LAYERDIR}/recipes-*/*/*.bbappend"
+
+BBFILE_COLLECTIONS += "edison"
+BBFILE_PATTERN_edison = "^${LAYERDIR}/"
+BBFILE_PRIORITY_edison = "6"
diff --git a/meta-edison/conf/machine/edison.conf b/meta-edison/conf/machine/edison.conf
new file mode 100644
index 0000000..6bc5606
--- /dev/null
+++ b/meta-edison/conf/machine/edison.conf
@@ -0,0 +1,21 @@
+#@TYPE: Machine
+#@NAME: edison
+
+#@DESCRIPTION: Machine configuration for edison systems
+
+# This sets compilation options close to what is used on android
+include conf/machine/include/tune-atom.inc
+TUNE_CCARGS .= " -mstackrealign -fno-omit-frame-pointer"
+
+MACHINE_FEATURES = "bluetooth alsa pci serial usbgadget usbhost wifi x86 ext3"
+KERNEL_IMAGETYPE = "bzImage"
+SERIAL_CONSOLES = "115200;ttyMFD2"
+UBOOT_MACHINE = "edison_config"
+
+module_autoload_bcm_bt_lpm = "bcm_bt_lpm"
+module_autoload_bcm4334x = "bcm4334x"
+module_conf_bcm4334x = "options bcm4334x firmware_path=/etc/firmware/fw_bcmdhd.bin nvram_path=/etc/firmware/bcmdhd.cal op_mode=4"
+module_autoload_g_multi = "g_multi"
+# FIXME: file parameter should be based on partition UUID (from U-Boot) or fixed
+# with label (label seems to work, but driver is probed too early)
+module_conf_g_multi = "options g_multi file=/dev/mmcblk0p9 stall=0 idVendor=0x8087 idProduct=0x0A9E iProduct=Edison iManufacturer=Intel"
diff --git a/meta-edison/recipes-bsp/u-boot/files/edison.env b/meta-edison/recipes-bsp/u-boot/files/edison.env
new file mode 100644
index 0000000..bd5a551
--- /dev/null
+++ b/meta-edison/recipes-bsp/u-boot/files/edison.env
@@ -0,0 +1,56 @@
+# Edison Environment File
+# Main part
+
+# Partition definition
+partitions=uuid_disk=${uuid_disk};name=u-boot0,start=1MiB,size=2MiB,uuid=${uuid_uboot0};name=u-boot-env0,size=1MiB,uuid=${uuid_uboot_env0};name=u-boot1,size=2MiB,uuid=${uuid_uboot1};name=u-boot-env1,size=1MiB,uuid=${uuid_uboot_env1};name=factory,size=1MiB,uuid=${uuid_factory};name=panic,size=24MiB,uuid=${uuid_panic};name=boot,size=32MiB,uuid=${uuid_boot};name=rootfs,size=1536MiB,uuid=${uuid_rootfs};name=update,size=768MiB,uuid=${uuid_update};name=home,size=-,uuid=${uuid_home};
+
+# Dfu Alternate setting definition
+do_dfu_alt_info_mmc=setenv dfu_alt_info "ifwi${hardware_id} mmc 0 8192 mmcpart 1;ifwib${hardware_id} mmc 0 8192 mmcpart 2;u-boot0 part 0 1;u-boot-env0 part 0 2;u-boot1 part 0 3;u-boot-env1 part 0 4;boot part 0 7;rootfs part 0 8;update part 0 9;home part 0 10;vmlinuz fat 0 7;initrd fat 0 7"
+dfu_alt_info_ram=kernel ram ${loadaddr} 0x800000
+do_dfu_alt_info_ifwi=setenv dfu_alt_info "ifwi${hardware_id} mmc 0 8192 mmcpart 1;ifwib${hardware_id} mmc 0 8192 mmcpart 2"
+dfu_alt_info_reset=reset ram 0x0 0x0
+
+# Kernel load configuration
+bootargs_console=console=ttyMFD2 earlyprintk=ttyMFD2,keep
+bootargs_debug=loglevel=4
+do_bootargs_rootfs=setenv bootargs_rootfs rootwait root=PARTUUID=${uuid_rootfs} rootfstype=ext4
+first_install_retry=0
+first_install_max_retries=3
+ota_update_retry=0
+ota_update_max_retries=3
+do_compute_target=if itest.b ${first_install_retry} -gt ${first_install_max_retries} || itest.b ${ota_update_retry} -gt ${ota_update_max_retries}; then echo "Switch to Rescue target"; setenv bootargs_target rescue; saveenv; fi
+mmc-bootargs=run do_bootargs_rootfs; setenv bootargs ${bootargs_rootfs} ${bootargs_console} ${bootargs_debug} g_multi.ethernet_config=${bootargs_ethconfig} systemd.unit=${bootargs_target}.target hardware_id=${hardware_id} g_multi.iSerialNumber=${serial#} g_multi.dev_addr=${usb0addr}
+loadaddr=0x100000
+load_kernel=fatload mmc 0:7 ${loadaddr} vmlinuz
+
+# Main functions
+do_partition_done=0
+do_partition=if itest.b ${do_partition_done} -eq 1; then echo "Partitioning already done..."; else run do_force_partition ; fi
+do_force_partition=echo "Partitioning using GPT"; gpt write mmc 0 ${partitions} ; mmc rescan; setenv do_partition_done 1 ; saveenv
+do_flash_ifwi=run do_dfu_alt_info_ifwi ; dfu 0 mmc 0
+do_flash_os=if itest.b ${do_flash_os_done} -eq 1 ; then echo "Flashing already done..." ; else run do_force_flash_os; fi
+do_force_flash_os=run do_dfu_alt_info_mmc ; sleep 1 ; setenv do_flash_os_done 1 ; saveenv ; dfu 0 mmc 0
+do_flashall=run do_partition;run do_flash_ifwi;run do_flash_os
+do_dnx=setenv dfu_alt_info ${dfu_alt_info_ram};dfu 0 ram 0 ram;run bootcmd
+init_dfu=run do_dfu_alt_info_mmc ; saveenv
+
+# Handle different boot mode
+bootcmd=echo "Target:${target_name}"; run do_partition; run do_handle_bootargs_mode;
+
+do_handle_bootargs_mode=run do_preprocess_bootargs_mode; if itest.s $bootargs_mode == "ota" ; then run do_ota; fi; if itest.s $bootargs_mode == "boot" ; then run do_boot; fi; if itest.s $bootargs_mode == "flash"; then run do_flash; fi; run do_fallback; exit;
+do_preprocess_bootargs_mode=if env exists bootargs_mode ; then ; else setenv bootargs_mode "boot" ;fi;
+
+do_fallback=echo "Unknown boot mode: $bootargs_mode"; env delete -f bootargs_mode; saveenv; echo "Resetting to default boot mode and reboot..."; reset;
+do_boot=run boot_target_cmd;
+do_flash=run do_force_flash_os;
+
+# OTA settings
+ota_script_addr=0x100000
+do_ota_init=setenv ota_status 1 ; env delete -f bootargs_mode
+do_load_ota_scr=if fatload mmc 0:9 $ota_script_addr ota_update.scr ; then setenv ota_status 0 ; else setenv ota_status 1 ; fi
+do_source_ota_scr=if test $ota_status -eq 0 ; then if source $ota_script_addr ; then setenv ota_status 0 ; else setenv ota_status 2 ; fi ; fi
+
+# do_ota_clean can be overriden by ota script
+do_ota_clean=saveenv ; reset
+
+do_ota=run do_ota_init ; run do_load_ota_scr ; run do_source_ota_scr ; run do_ota_clean
diff --git a/meta-edison/recipes-bsp/u-boot/files/fw_env.config b/meta-edison/recipes-bsp/u-boot/files/fw_env.config
new file mode 100644
index 0000000..392bb8e
--- /dev/null
+++ b/meta-edison/recipes-bsp/u-boot/files/fw_env.config
@@ -0,0 +1,11 @@
+# Configuration file for fw_(printenv/setenv) utility.
+# Up to two entries are valid, in this case the redundant
+# environment sector is assumed present.
+# Notice, that the "Number of sectors" is not required on NOR and SPI-dataflash.
+# Futhermore, if the Flash sector size is ommitted, this value is assumed to
+# be the same as the Environment size, which is valid for NOR and SPI-dataflash
+
+# MTD device name Device offset Env. size Flash sector size Number of sectors
+# On Edison, the u-boot environments are located on partitions 2 and 4 and both have a size of 64kB
+/dev/mmcblk0p2 0x0000 0x10000
+/dev/mmcblk0p4 0x0000 0x10000
diff --git a/meta-edison/recipes-bsp/u-boot/files/target_env/blankcdc.env b/meta-edison/recipes-bsp/u-boot/files/target_env/blankcdc.env
new file mode 100644
index 0000000..a04d786
--- /dev/null
+++ b/meta-edison/recipes-bsp/u-boot/files/target_env/blankcdc.env
@@ -0,0 +1,10 @@
+# U-Boot blank environment with CDC ECM ethernet config for gadget multi
+# used to erase all partitions and first boot setup
+target_name=blank
+bootdelay=1
+do_flash_os_done=1
+bootargs_target=first-install
+bootargs_ethconfig=cdc
+dfu_to_sec=3
+do_probe_dfu=run do_dfu_alt_info_mmc ; dfu 0 mmc 0 $dfu_to_sec
+boot_target_cmd=run do_flash_os;run do_probe_dfu;run do_compute_target;run mmc-bootargs;run load_kernel;zboot ${loadaddr}
diff --git a/meta-edison/recipes-bsp/u-boot/files/target_env/blankrndis.env b/meta-edison/recipes-bsp/u-boot/files/target_env/blankrndis.env
new file mode 100644
index 0000000..1fcf1ba
--- /dev/null
+++ b/meta-edison/recipes-bsp/u-boot/files/target_env/blankrndis.env
@@ -0,0 +1,10 @@
+# U-Boot blank environment with RNDIS ethernet config for gadget multi
+# used to erase all partitions and first boot setup
+target_name=blank
+bootdelay=1
+do_flash_os_done=1
+bootargs_target=first-install
+bootargs_ethconfig=rndis
+dfu_to_sec=3
+do_probe_dfu=run do_dfu_alt_info_mmc ; dfu 0 mmc 0 $dfu_to_sec
+boot_target_cmd=run do_flash_os;run do_probe_dfu;run do_compute_target;run mmc-bootargs;run load_kernel;zboot ${loadaddr}
diff --git a/meta-edison/recipes-bsp/u-boot/files/target_env/defaultcdc.env b/meta-edison/recipes-bsp/u-boot/files/target_env/defaultcdc.env
new file mode 100644
index 0000000..6a0edda
--- /dev/null
+++ b/meta-edison/recipes-bsp/u-boot/files/target_env/defaultcdc.env
@@ -0,0 +1,10 @@
+# U-Boot default environment
+# default end-user environment
+target_name=default
+bootdelay=1
+do_flash_os_done=1
+bootargs_target=multi-user
+bootargs_ethconfig=cdc
+dfu_to_sec=3
+do_probe_dfu=run do_dfu_alt_info_mmc ; dfu 0 mmc 0 $dfu_to_sec
+boot_target_cmd=run do_flash_os;run do_probe_dfu;run do_compute_target;run mmc-bootargs;run load_kernel;zboot ${loadaddr}
diff --git a/meta-edison/recipes-bsp/u-boot/files/target_env/defaultrndis.env b/meta-edison/recipes-bsp/u-boot/files/target_env/defaultrndis.env
new file mode 100644
index 0000000..84768c5
--- /dev/null
+++ b/meta-edison/recipes-bsp/u-boot/files/target_env/defaultrndis.env
@@ -0,0 +1,10 @@
+# U-Boot default environment
+# default end-user environment
+target_name=default
+bootdelay=1
+do_flash_os_done=1
+bootargs_target=multi-user
+bootargs_ethconfig=rndis
+dfu_to_sec=3
+do_probe_dfu=run do_dfu_alt_info_mmc ; dfu 0 mmc 0 $dfu_to_sec
+boot_target_cmd=run do_flash_os;run do_probe_dfu;run do_compute_target;run mmc-bootargs;run load_kernel;zboot ${loadaddr}
diff --git a/meta-edison/recipes-bsp/u-boot/files/target_env/ifwi.env b/meta-edison/recipes-bsp/u-boot/files/target_env/ifwi.env
new file mode 100644
index 0000000..e0a1286
--- /dev/null
+++ b/meta-edison/recipes-bsp/u-boot/files/target_env/ifwi.env
@@ -0,0 +1,7 @@
+# U-Boot IFWI environment
+# IFWI testing mode
+# this env is stitched with xfstk binary , do only dfu
+target_name=ifwi
+bootdelay=1
+do_flash_os_done=0
+boot_target_cmd=run do_partition;run do_force_flash_os
diff --git a/meta-edison/recipes-bsp/u-boot/files/target_env/prod.env b/meta-edison/recipes-bsp/u-boot/files/target_env/prod.env
new file mode 100644
index 0000000..7e68939
--- /dev/null
+++ b/meta-edison/recipes-bsp/u-boot/files/target_env/prod.env
@@ -0,0 +1,6 @@
+# U-Boot production environment
+# used in factory for flashing and calibrating
+target_name=prod
+bootdelay=3
+do_flash_os_done=0
+boot_target_cmd=run do_flash_ifwi;run do_force_flash_os
diff --git a/meta-edison/recipes-bsp/u-boot/files/upstream_to_edison.patch b/meta-edison/recipes-bsp/u-boot/files/upstream_to_edison.patch
new file mode 100644
index 0000000..cfe672c
--- /dev/null
+++ b/meta-edison/recipes-bsp/u-boot/files/upstream_to_edison.patch
@@ -0,0 +1,11158 @@
+From e888d015120e6d7a057dcb6b39ca243fa4f7cd70 Mon Sep 17 00:00:00 2001
+From: Fabien Chereau <fabien.chereau@intel.com>
+Date: Thu, 4 Sep 2014 11:11:05 +0200
+Subject: [PATCH] Squashed all commits from upstream to Edison
+
+Change-Id: I92371895c2c15236821a8008ef688bd27f237b32
+---
+ Makefile | 1 +
+ arch/x86/config.mk | 4 +-
+ arch/x86/cpu/config.mk | 2 +-
+ arch/x86/cpu/start.S | 2 +
+ arch/x86/cpu/tangier/Makefile | 1 +
+ arch/x86/cpu/tangier/board_id.c | 33 +
+ arch/x86/cpu/tangier/car.S | 13 +
+ arch/x86/cpu/tangier/pci.c | 49 +
+ arch/x86/cpu/tangier/sdram.c | 139 ++
+ arch/x86/cpu/tangier/tables.c | 26 +
+ arch/x86/cpu/tangier/tangier.c | 171 ++
+ arch/x86/include/asm/apic.h | 91 +
+ arch/x86/include/asm/arch-tangier/clk.h | 3 +
+ arch/x86/include/asm/arch-tangier/intel-mid.h | 29 +
+ arch/x86/include/asm/arch-tangier/ipchecksum.h | 37 +
+ arch/x86/include/asm/arch-tangier/mmc.h | 11 +
+ arch/x86/include/asm/arch-tangier/sysinfo.h | 62 +
+ arch/x86/include/asm/arch-tangier/tables.h | 294 ++++
+ arch/x86/include/asm/arch-tangier/timestamp.h | 59 +
+ arch/x86/include/asm/delay.h | 6 +
+ arch/x86/include/asm/io.h | 48 +
+ arch/x86/include/asm/mpspec.h | 74 +
+ arch/x86/include/asm/msr-index.h | 46 +-
+ arch/x86/include/asm/sfi.h | 119 ++
+ arch/x86/lib/Makefile | 1 +
+ arch/x86/lib/sfi.c | 162 ++
+ arch/x86/lib/tsc_timer.c | 6 +-
+ arch/x86/lib/zimage.c | 4 +
+ board/intel/edison/Makefile | 1 +
+ board/intel/edison/config.mk | 7 +
+ board/intel/edison/edison.c | 54 +
+ board/intel/edison/edison.h | 0
+ board/intel/edison/edison_start.S | 13 +
+ boards.cfg | 1 +
+ common/Makefile | 2 +
+ common/board_f.c | 20 +-
+ common/cmd_dfu.c | 46 +-
+ common/cmd_fastboot.c | 28 +
+ common/cmd_gpt.c | 2 +-
+ common/cmd_itest.c | 3 +-
+ common/cmd_part.c | 135 +-
+ disk/part_efi.c | 8 +-
+ drivers/dfu/dfu.c | 12 +
+ drivers/dfu/dfu_mmc.c | 48 +-
+ drivers/misc/Makefile | 1 +
+ drivers/misc/intel_scu_ipc.c | 150 ++
+ drivers/mmc/Makefile | 1 +
+ drivers/mmc/tangier_sdhci.c | 38 +
+ drivers/serial/Makefile | 1 +
+ drivers/serial/serial.c | 1 +
+ drivers/serial/serial_tng.c | 252 +++
+ drivers/usb/dwc3/Kconfig | 26 +
+ drivers/usb/dwc3/Makefile | 8 +
+ drivers/usb/dwc3/core.h | 814 +++++++++
+ drivers/usb/dwc3/debug.h | 49 +
+ drivers/usb/dwc3/debugfs.c | 521 ++++++
+ drivers/usb/dwc3/dwc3-omap.c | 418 +++++
+ drivers/usb/dwc3/dwc3-pci.c | 187 ++
+ drivers/usb/dwc3/dwc3_core.c | 513 ++++++
+ drivers/usb/dwc3/dwc3_ep0.c | 851 +++++++++
+ drivers/usb/dwc3/dwc3_gadget.c | 2184 ++++++++++++++++++++++++
+ drivers/usb/dwc3/dwc3_host.c | 102 ++
+ drivers/usb/dwc3/dwc3_misc.c | 20 +
+ drivers/usb/dwc3/gadget.h | 186 ++
+ drivers/usb/dwc3/io.h | 54 +
+ drivers/usb/dwc3/misc.h | 269 +++
+ drivers/usb/gadget/Makefile | 1 +
+ drivers/usb/gadget/f_dfu.c | 1 +
+ drivers/usb/gadget/f_fastboot.c | 559 ++++++
+ drivers/usb/gadget/g_fastboot.h | 20 +
+ drivers/usb/gadget/u_fastboot.c | 308 ++++
+ examples/standalone/Makefile | 4 +
+ fs/fat/fat.c | 37 +-
+ include/android_image.h | 102 ++
+ include/configs/coreboot.h | 1 +
+ include/configs/edison.h | 268 +++
+ include/dfu.h | 7 +
+ include/intel_scu_ipc.h | 69 +
+ include/linux/usb/gadget.h | 15 +-
+ include/usb/fastboot.h | 100 ++
+ pft-config.xml | 28 +
+ 81 files changed, 9997 insertions(+), 42 deletions(-)
+ create mode 100644 arch/x86/cpu/tangier/Makefile
+ create mode 100644 arch/x86/cpu/tangier/board_id.c
+ create mode 100644 arch/x86/cpu/tangier/car.S
+ create mode 100644 arch/x86/cpu/tangier/pci.c
+ create mode 100644 arch/x86/cpu/tangier/sdram.c
+ create mode 100644 arch/x86/cpu/tangier/tables.c
+ create mode 100644 arch/x86/cpu/tangier/tangier.c
+ create mode 100644 arch/x86/include/asm/apic.h
+ create mode 100644 arch/x86/include/asm/arch-tangier/clk.h
+ create mode 100644 arch/x86/include/asm/arch-tangier/intel-mid.h
+ create mode 100644 arch/x86/include/asm/arch-tangier/ipchecksum.h
+ create mode 100644 arch/x86/include/asm/arch-tangier/mmc.h
+ create mode 100644 arch/x86/include/asm/arch-tangier/sysinfo.h
+ create mode 100644 arch/x86/include/asm/arch-tangier/tables.h
+ create mode 100644 arch/x86/include/asm/arch-tangier/timestamp.h
+ create mode 100644 arch/x86/include/asm/delay.h
+ create mode 100644 arch/x86/include/asm/mpspec.h
+ create mode 100644 arch/x86/include/asm/sfi.h
+ create mode 100644 arch/x86/lib/sfi.c
+ create mode 100644 board/intel/edison/Makefile
+ create mode 100644 board/intel/edison/config.mk
+ create mode 100644 board/intel/edison/edison.c
+ create mode 100644 board/intel/edison/edison.h
+ create mode 100644 board/intel/edison/edison_start.S
+ create mode 100644 common/cmd_fastboot.c
+ create mode 100644 drivers/misc/intel_scu_ipc.c
+ create mode 100644 drivers/mmc/tangier_sdhci.c
+ create mode 100644 drivers/serial/serial_tng.c
+ create mode 100644 drivers/usb/dwc3/Kconfig
+ create mode 100644 drivers/usb/dwc3/Makefile
+ create mode 100644 drivers/usb/dwc3/core.h
+ create mode 100644 drivers/usb/dwc3/debug.h
+ create mode 100644 drivers/usb/dwc3/debugfs.c
+ create mode 100644 drivers/usb/dwc3/dwc3-omap.c
+ create mode 100644 drivers/usb/dwc3/dwc3-pci.c
+ create mode 100644 drivers/usb/dwc3/dwc3_core.c
+ create mode 100644 drivers/usb/dwc3/dwc3_ep0.c
+ create mode 100644 drivers/usb/dwc3/dwc3_gadget.c
+ create mode 100644 drivers/usb/dwc3/dwc3_host.c
+ create mode 100644 drivers/usb/dwc3/dwc3_misc.c
+ create mode 100644 drivers/usb/dwc3/gadget.h
+ create mode 100644 drivers/usb/dwc3/io.h
+ create mode 100644 drivers/usb/dwc3/misc.h
+ create mode 100644 drivers/usb/gadget/f_fastboot.c
+ create mode 100644 drivers/usb/gadget/g_fastboot.h
+ create mode 100644 drivers/usb/gadget/u_fastboot.c
+ create mode 100644 include/android_image.h
+ create mode 100644 include/configs/edison.h
+ create mode 100644 include/intel_scu_ipc.h
+ create mode 100644 include/usb/fastboot.h
+ create mode 100644 pft-config.xml
+
+diff --git a/Makefile b/Makefile
+index c91c10e..3846d2c 100644
+--- a/Makefile
++++ b/Makefile
+@@ -612,6 +612,7 @@ libs-y += drivers/usb/gadget/
+ libs-y += drivers/usb/host/
+ libs-y += drivers/usb/musb/
+ libs-y += drivers/usb/musb-new/
++libs-y += drivers/usb/dwc3/
+ libs-y += drivers/usb/phy/
+ libs-y += drivers/usb/ulpi/
+ libs-y += common/
+diff --git a/arch/x86/config.mk b/arch/x86/config.mk
+index 38cb7c9..9048a50 100644
+--- a/arch/x86/config.mk
++++ b/arch/x86/config.mk
+@@ -15,7 +15,8 @@ PF_CPPFLAGS_X86 := $(call cc-option, -fno-toplevel-reorder, \
+ $(call cc-option, -mpreferred-stack-boundary=2)
+ PLATFORM_CPPFLAGS += $(PF_CPPFLAGS_X86)
+ PLATFORM_CPPFLAGS += -fno-dwarf2-cfi-asm
+-PLATFORM_CPPFLAGS += -DREALMODE_BASE=0x7c0
++#PLATFORM_CPPFLAGS += -DREALMODE_BASE=0x7c0
++PLATFORM_CPPFLAGS += -m32
+
+ # Support generic board on x86
+ __HAVE_ARCH_GENERIC_BOARD := y
+@@ -23,6 +24,7 @@ __HAVE_ARCH_GENERIC_BOARD := y
+ PLATFORM_RELFLAGS += -ffunction-sections -fvisibility=hidden
+
+ PLATFORM_LDFLAGS += --emit-relocs -Bsymbolic -Bsymbolic-functions
++PLATFORM_LDFLAGS += -m elf_i386
+
+ LDFLAGS_FINAL += --gc-sections -pie
+ LDFLAGS_FINAL += --wrap=__divdi3 --wrap=__udivdi3
+diff --git a/arch/x86/cpu/config.mk b/arch/x86/cpu/config.mk
+index c1568cac..42a4425 100644
+--- a/arch/x86/cpu/config.mk
++++ b/arch/x86/cpu/config.mk
+@@ -5,7 +5,7 @@
+ # SPDX-License-Identifier: GPL-2.0+
+ #
+
+-CROSS_COMPILE ?= i386-linux-
++#CROSS_COMPILE ?= i386-linux-
+
+ PLATFORM_CPPFLAGS += -DCONFIG_X86 -D__I386__ -march=i386 -Werror
+
+diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S
+index 329bb3a..e4d1c53 100644
+--- a/arch/x86/cpu/start.S
++++ b/arch/x86/cpu/start.S
+@@ -50,6 +50,7 @@ _start:
+ movw $GD_FLG_COLD_BOOT, %bx
+ 1:
+
++#ifndef CONFIG_INHERIT_GDT
+ /* Load the segement registes to match the gdt loaded in start16.S */
+ movl $(X86_GDT_ENTRY_32BIT_DS * X86_GDT_ENTRY_SIZE), %eax
+ movw %ax, %fs
+@@ -57,6 +58,7 @@ _start:
+ movw %ax, %gs
+ movw %ax, %es
+ movw %ax, %ss
++#endif
+
+ /* Clear the interrupt vectors */
+ lidt blank_idt_ptr
+diff --git a/arch/x86/cpu/tangier/Makefile b/arch/x86/cpu/tangier/Makefile
+new file mode 100644
+index 0000000..2ef428b
+--- /dev/null
++++ b/arch/x86/cpu/tangier/Makefile
+@@ -0,0 +1 @@
++obj-y += car.o tangier.o pci.o sdram.o tables.o
+diff --git a/arch/x86/cpu/tangier/board_id.c b/arch/x86/cpu/tangier/board_id.c
+new file mode 100644
+index 0000000..b13b051
+--- /dev/null
++++ b/arch/x86/cpu/tangier/board_id.c
+@@ -0,0 +1,33 @@
++#include <common.h>
++#include <asm/arch/board_id.h>
++#include <asm/intel_scu_pmic.h>
++
++int _get_board_id(void)
++{
++ u8 i = 0;
++ u8 data = -1;
++ int value = 0;
++
++ for (i = 0x79; i <= 0x7c; i++) {
++ intel_scu_ipc_ioread8(i, &data);
++ value |= (data & 0x1) << (0x7c - i);
++ data = -1;
++ }
++
++ printf("[SCU_IPC_DEBUG] board ID: %x\n", value);
++
++ return value;
++}
++
++int get_board_id(void)
++{
++ static int clt_board_id = CLT_BOARD_NOT_IDENTIFIED;
++
++ if (clt_board_id != CLT_BOARD_NOT_IDENTIFIED)
++ return clt_board_id;
++
++ clt_board_id = _get_board_id();
++
++ return clt_board_id;
++}
++
+diff --git a/arch/x86/cpu/tangier/car.S b/arch/x86/cpu/tangier/car.S
+new file mode 100644
+index 0000000..6982106
+--- /dev/null
++++ b/arch/x86/cpu/tangier/car.S
+@@ -0,0 +1,13 @@
++/*
++ * Copyright (c) 2011 The Chromium OS Authors.
++ * (C) Copyright 2010-2011
++ * Graeme Russ, <graeme.russ@gmail.com>
++ *
++ * SPDX-License-Identifier: GPL-2.0+
++ */
++
++.section .text
++
++.globl car_init
++car_init:
++ jmp car_init_ret
+diff --git a/arch/x86/cpu/tangier/pci.c b/arch/x86/cpu/tangier/pci.c
+new file mode 100644
+index 0000000..af5ff2c
+--- /dev/null
++++ b/arch/x86/cpu/tangier/pci.c
+@@ -0,0 +1,49 @@
++/*
++ * Copyright (c) 2011 The Chromium OS Authors.
++ * (C) Copyright 2008,2009
++ * Graeme Russ, <graeme.russ@gmail.com>
++ *
++ * (C) Copyright 2002
++ * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
++ *
++ * SPDX-License-Identifier: GPL-2.0+
++ */
++
++#include <common.h>
++#include <pci.h>
++#include <asm/pci.h>
++
++static struct pci_controller tangier_hose;
++
++static void config_pci_bridge(struct pci_controller *hose, pci_dev_t dev,
++ struct pci_config_table *table)
++{
++ u8 secondary;
++ hose->read_byte(hose, dev, PCI_SECONDARY_BUS, &secondary);
++ hose->last_busno = max(hose->last_busno, secondary);
++ pci_hose_scan_bus(hose, secondary);
++}
++
++static struct pci_config_table pci_tangier_config_table[] = {
++ /* vendor, device, class, bus, dev, func */
++ { PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_BRIDGE_PCI,
++ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, &config_pci_bridge },
++ {}
++};
++
++void pci_init_board(void)
++{
++ tangier_hose.config_table = pci_tangier_config_table;
++ tangier_hose.first_busno = 0;
++ tangier_hose.last_busno = 0;
++
++ pci_set_region(tangier_hose.regions + 0, 0x0, 0x0, 0xffffffff,
++ PCI_REGION_MEM);
++ tangier_hose.region_count = 1;
++
++ pci_setup_type1(&tangier_hose);
++
++ pci_register_hose(&tangier_hose);
++
++ pci_hose_scan(&tangier_hose);
++}
+diff --git a/arch/x86/cpu/tangier/sdram.c b/arch/x86/cpu/tangier/sdram.c
+new file mode 100644
+index 0000000..f18b45e
+--- /dev/null
++++ b/arch/x86/cpu/tangier/sdram.c
+@@ -0,0 +1,139 @@
++/*
++ * Copyright (c) 2011 The Chromium OS Authors.
++ * (C) Copyright 2010,2011
++ * Graeme Russ, <graeme.russ@gmail.com>
++ *
++ * SPDX-License-Identifier: GPL-2.0+
++ */
++
++#include <common.h>
++#include <malloc.h>
++#include <asm/e820.h>
++#include <asm/u-boot-x86.h>
++#include <asm/global_data.h>
++#include <asm/processor.h>
++#include <asm/sections.h>
++#include <asm/arch/sysinfo.h>
++#include <asm/arch/tables.h>
++#ifdef CONFIG_SFI
++#include <asm/sfi.h>
++#endif
++
++DECLARE_GLOBAL_DATA_PTR;
++
++unsigned install_e820_map(unsigned max_entries, struct e820entry *entries)
++{
++#ifdef CONFIG_SFI
++ return sfi_setup_e820(max_entries, entries);
++#else
++ return 0;
++#endif
++}
++
++/*
++ * This function looks for the highest region of memory lower than 4GB which
++ * has enough space for U-Boot where U-Boot is aligned on a page boundary. It
++ * overrides the default implementation found elsewhere which simply picks the
++ * end of ram, wherever that may be. The location of the stack, the relocation
++ * address, and how far U-Boot is moved by relocation are set in the global
++ * data structure.
++ */
++ulong board_get_usable_ram_top(ulong total_size)
++{
++ uintptr_t dest_addr = 0x000000003F4FFFFF;
++/*
++ * int i;
++ *
++ * for (i = 0; i < lib_sysinfo.n_memranges; i++) {
++ * struct memrange *memrange = &lib_sysinfo.memrange[i];
++ * [> Force U-Boot to relocate to a page aligned address. <]
++ * uint64_t start = roundup(memrange->base, 1 << 12);
++ * uint64_t end = memrange->base + memrange->size;
++ *
++ * [> Ignore non-memory regions. <]
++ * if (memrange->type != CB_MEM_RAM)
++ * continue;
++ *
++ * [> Filter memory over 4GB. <]
++ * if (end > 0xffffffffULL)
++ * end = 0x100000000ULL;
++ * [> Skip this region if it's too small. <]
++ * if (end - start < total_size)
++ * continue;
++ *
++ * [> Use this address if it's the largest so far. <]
++ * if (end > dest_addr)
++ * dest_addr = end;
++ * }
++ *
++ * [> If no suitable area was found, return an error. <]
++ * if (!dest_addr)
++ * panic("No available memory found for relocation");
++ */
++
++ return (ulong)dest_addr;
++}
++
++int dram_init_f(void)
++{
++/*
++ * int i;
++ * phys_size_t ram_size = 0;
++ *
++ * for (i = 0; i < lib_sysinfo.n_memranges; i++) {
++ * struct memrange *memrange = &lib_sysinfo.memrange[i];
++ * unsigned long long end = memrange->base + memrange->size;
++ *
++ * if (memrange->type == CB_MEM_RAM && end > ram_size)
++ * ram_size = end;
++ * }
++ * gd->ram_size = ram_size;
++ * if (ram_size == 0)
++ * return -1;
++ */
++#ifdef CONFIG_SFI
++ gd->ram_size = sfi_get_ram_size();
++#endif
++ return 0;
++}
++
++int dram_init_banksize(void)
++{
++/*
++ * int i, j;
++ *
++ * if (CONFIG_NR_DRAM_BANKS) {
++ * for (i = 0, j = 0; i < lib_sysinfo.n_memranges; i++) {
++ * struct memrange *memrange = &lib_sysinfo.memrange[i];
++ *
++ * if (memrange->type == CB_MEM_RAM) {
++ * gd->bd->bi_dram[j].start = memrange->base;
++ * gd->bd->bi_dram[j].size = memrange->size;
++ * j++;
++ * if (j >= CONFIG_NR_DRAM_BANKS)
++ * break;
++ * }
++ * }
++ * }
++ */
++/*
++ *0: 0000000000000000-0000000000097FFF ( 0K - 608K) ram
++ *3: 0000000000100000-0000000003FFFFFF ( 1M - 64M) ram
++ *5: 0000000006000000-000000003F4FFFFF ( 96M - 1013M) ram
++ */
++ gd->bd->bi_dram[0].start = 0x0;
++ gd->bd->bi_dram[0].size = 0x97FFF;
++
++ gd->bd->bi_dram[1].start = 0x100000;
++ gd->bd->bi_dram[1].size = 0x3FFFFFF - gd->bd->bi_dram[1].start;
++
++ gd->bd->bi_dram[2].start = 0x6000000;
++ gd->bd->bi_dram[2].size = 0x3F4FFFFF - gd->bd->bi_dram[2].start;
++
++ return 0;
++}
++
++int dram_init(void)
++{
++ return dram_init_banksize();
++}
+diff --git a/arch/x86/cpu/tangier/tables.c b/arch/x86/cpu/tangier/tables.c
+new file mode 100644
+index 0000000..0568877
+--- /dev/null
++++ b/arch/x86/cpu/tangier/tables.c
+@@ -0,0 +1,26 @@
++/*
++ * This file is part of the libpayload project.
++ *
++ * Copyright (C) 2008 Advanced Micro Devices, Inc.
++ * Copyright (C) 2009 coresystems GmbH
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#include <common.h>
++#include <asm/arch-coreboot/ipchecksum.h>
++#include <asm/arch-coreboot/sysinfo.h>
++#include <asm/arch-coreboot/tables.h>
++
++/*
++ * This needs to be in the .data section so that it's copied over during
++ * relocation. By default it's put in the .bss section which is simply filled
++ * with zeroes when transitioning from "ROM", which is really RAM, to other
++ * RAM.
++ */
++struct sysinfo_t lib_sysinfo __attribute__ ((section(".data")));
++
++int get_coreboot_info(struct sysinfo_t *info)
++{
++ return 0;
++}
+diff --git a/arch/x86/cpu/tangier/tangier.c b/arch/x86/cpu/tangier/tangier.c
+new file mode 100644
+index 0000000..0fbe401
+--- /dev/null
++++ b/arch/x86/cpu/tangier/tangier.c
+@@ -0,0 +1,171 @@
++/*
++ * Copyright (c) 2011 The Chromium OS Authors.
++ * (C) Copyright 2008
++ * Graeme Russ, graeme.russ@gmail.com.
++ *
++ * SPDX-License-Identifier: GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/u-boot-x86.h>
++#include <asm/cache.h>
++#include <asm/io.h>
++#include <asm/errno.h>
++#include <asm/arch/mmc.h>
++#include <asm/msr.h>
++#include <asm/arch/intel-mid.h>
++#include <asm/arch/timestamp.h>
++#include <intel_scu_ipc.h>
++#include <u-boot/md5.h>
++
++DECLARE_GLOBAL_DATA_PTR;
++
++/*
++ * Miscellaneous platform dependent initializations
++ */
++int cpu_init_f(void)
++{
++ timer_set_base(1);
++ return 0;
++}
++
++int board_early_init_f(void)
++{
++ return 0;
++}
++
++int board_early_init_r(void)
++{
++ return 0;
++}
++
++int board_late_init(void)
++{
++ if (!getenv("serial#")) {
++
++ struct mmc *mmc = find_mmc_device(0);
++ unsigned char emmc_ssn[16];
++ char ssn[33];
++ char usb_gadget_addr[18];
++
++ if (mmc) {
++ int i;
++
++ md5((unsigned char *)mmc->cid, sizeof(mmc->cid), emmc_ssn);
++
++ for (i = 0; i < 16; i++)
++ snprintf(&(ssn[2*i]), 2, "%02x", emmc_ssn[i]);
++
++ snprintf(&(usb_gadget_addr[0]), sizeof(usb_gadget_addr),
++ "02:00:86:%02x:%02x:%02x", emmc_ssn[13], emmc_ssn[14],
++ emmc_ssn[15]);
++ setenv("usb0addr", usb_gadget_addr);
++ setenv("serial#", ssn);
++ saveenv();
++ }
++ }
++
++ if (!getenv("hardware_id")) {
++ union ipc_ifwi_version v;
++ int ret;
++ char hardware_id[4];
++
++ ret = intel_scu_ipc_command(IPCMSG_GET_FW_REVISION, 1,
++ NULL, 0, (u32 *) &(v.raw[0]), 4);
++ if (ret < 0) {
++ printf("Can't retrieve hardware revision\n");
++ }
++
++ snprintf(hardware_id, sizeof(hardware_id), "%02X", v.fw.hardware_id);
++ setenv("hardware_id", hardware_id);
++ saveenv();
++ }
++
++
++ return 0;
++}
++
++void show_boot_progress(int val)
++{
++ outb(val, 0x80);
++}
++
++int last_stage_init(void)
++{
++ /*
++ *if (gd->flags & GD_FLG_COLD_BOOT)
++ * timestamp_add_to_bootstage();
++ */
++
++ return 0;
++}
++
++int board_final_cleanup(void)
++{
++
++ return 0;
++}
++
++void panic_puts(const char *str)
++{
++}
++
++int board_mmc_init(bd_t * bis)
++{
++ int index = 0;
++ unsigned int base = CONFIG_SYS_EMMC_PORT_BASE + (0x40000 * index);
++
++ return tangier_sdhci_init(base, index, 4);
++}
++
++/* ovveride get_tbclk_mhz code see tsc_timer */
++/* Get the speed of the TSC timer in MHz */
++unsigned __attribute__((no_instrument_function)) long get_tbclk_mhz(void)
++{
++ u32 ratio , bus_freq;
++ u64 platform_info = native_read_msr(MSR_PLATFORM_INFO);
++ u64 msr_fsb_freq = native_read_msr(MSR_FSB_FREQ);
++
++ /* compute and correct ratio if necessary */
++ ratio = ((platform_info >> 8) & 0xff);
++ if(!ratio)
++ {
++ ratio = 4;
++ debug("Read a zero ratio, force tsc ratio to 4 ...\n");
++ }
++
++ /* compute fsb */
++ bus_freq = (u32) (msr_fsb_freq & 0x7);
++ /* lookup real bus freq in kHz according to its index */
++ switch(bus_freq)
++ {
++ case 2:
++ bus_freq = FSB_FREQ_133SKU;
++ break;
++ case 3:
++ bus_freq = FSB_FREQ_167SKU;
++ break;
++ case 4:
++ bus_freq = FSB_FREQ_83SKU;
++ break;
++ case 5:
++ bus_freq = FSB_FREQ_400SKU;
++ break;
++ case 6:
++ bus_freq = FSB_FREQ_267SKU;
++ break;
++ case 7:
++ bus_freq = FSB_FREQ_333SKU;
++ break;
++ default: /* handle also 0 and 1 */
++ bus_freq = FSB_FREQ_100SKU;
++ break;
++ }
++ // return Freq in Mhz
++ return ((bus_freq * ratio)/1000);
++}
++
++void reset_cpu(ulong addr)
++{
++ intel_scu_ipc_simple_command(IPCMSG_COLD_RESET, 0);
++}
+diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
+new file mode 100644
+index 0000000..7b63f48
+--- /dev/null
++++ b/arch/x86/include/asm/apic.h
+@@ -0,0 +1,91 @@
++#ifndef _APIC_H_
++#define _APIC_H_
++
++#include <asm/mpspec.h>
++
++#define IO_APIC_DEFAULT_PHYS_BASE 0xfec00000
++#define APIC_DEFAULT_PHYS_BASE 0xfee00000
++
++#define ALL (0xff << 24)
++#define NONE (0)
++#define DISABLED (1 << 16)
++#define ENABLED (0 << 16)
++#define TRIGGER_EDGE (0 << 15)
++#define TRIGGER_LEVEL (1 << 15)
++#define POLARITY_HIGH (0 << 13)
++#define POLARITY_LOW (1 << 13)
++#define PHYSICAL_DEST (0 << 11)
++#define LOGICAL_DEST (1 << 11)
++#define ExtINT (7 << 8)
++#define NMI (4 << 8)
++#define SMI (2 << 8)
++#define INT (1 << 8)
++
++#define SET_APIC_LOGICAL_ID(x) ((x) << 24)
++
++#define APIC_LVR 0x30
++#define APIC_INTEGRATED(x) ((x) & 0xF0u)
++#define GET_APIC_VERSION(x) ((x) & 0xFFu)
++#define GET_APIC_MAXLVT(x) (((x) >> 16) & 0xFFu)
++#define APIC_TASKPRI 0x80
++#define APIC_EOI 0xB0
++#define APIC_LDR 0xD0
++#define APIC_DFR 0xE0
++#define APIC_SPIV 0xF0
++
++#define APIC_TPRI_MASK 0xFFu
++#define APIC_LDR_MASK (0xFFu << 24)
++#define APIC_DFR_VALUE 0xFFFFFFFFul
++#define APIC_VECTOR_MASK 0x000FF
++#define APIC_SPIV_APIC_ENABLED (1 << 8)
++#define APIC_SPIV_FOCUS_DISABLED (1 << 9)
++
++#define LOCAL_TIMER_VECTOR 0xef
++#define ERROR_APIC_VECTOR 0xfe
++#define SPURIOUS_APIC_VECTOR 0xff
++
++#define APIC_ISR 0x100
++#define APIC_ESR 0x280
++#define APIC_LVTCMCI 0x2f0
++#define APIC_DM_NMI 0x00400
++#define APIC_LVTT 0x320
++#define APIC_LVTTHMR 0x330
++#define APIC_LVTPC 0x340
++#define APIC_LVT0 0x350
++#define APIC_LVT_TIMER_PERIODIC (1 << 17)
++#define SET_APIC_TIMER_BASE(x) (((x) << 18))
++#define APIC_TIMER_BASE_DIV 0x2
++#define APIC_LVT1 0x360
++#define APIC_LVTERR 0x370
++#define APIC_TMICT 0x380
++#ifdef CONFIG_X86_MRFLD
++#define APIC_TMICT_INIT_CNT 0x144b50
++#else
++#define APIC_TMICT_INIT_CNT 0xf3c00
++#endif
++#define APIC_TMCCT 0x390
++#define APIC_TDCR 0x3E0
++#define APIC_TDR_DIV_TMBASE (1 << 2)
++#define APIC_TDR_DIV_1 0xB
++#define APIC_TDR_DIV_2 0x0
++#define APIC_TDR_DIV_4 0x1
++#define APIC_TDR_DIV_8 0x2
++#define APIC_TDR_DIV_16 0x3
++#define APIC_TDR_DIV_32 0x8
++#define APIC_TDR_DIV_64 0x9
++#define APIC_TDR_DIV_128 0xA
++#define APIC_LVT_MASKED (1 << 16)
++#define APIC_DM_EXTINT 0x00700
++
++#define LAPIC_ID 0x020
++
++extern unsigned int lapic_timer_frequency;
++
++extern void apic_init(void);
++extern void apic_ack_irq(void);
++extern void apic_timer_setup(unsigned int clocks, int oneshot, int irqen);
++extern void apic_spurious_isr(void);
++extern void apic_mask_irq(void);
++extern void apic_unmask_irq(void);
++
++#endif /* _APIC_H_ */
+diff --git a/arch/x86/include/asm/arch-tangier/clk.h b/arch/x86/include/asm/arch-tangier/clk.h
+new file mode 100644
+index 0000000..ab887aa
+--- /dev/null
++++ b/arch/x86/include/asm/arch-tangier/clk.h
+@@ -0,0 +1,3 @@
++#ifndef _CLK_H
++#define _CLK_H
++#endif
+diff --git a/arch/x86/include/asm/arch-tangier/intel-mid.h b/arch/x86/include/asm/arch-tangier/intel-mid.h
+new file mode 100644
+index 0000000..de4857c
+--- /dev/null
++++ b/arch/x86/include/asm/arch-tangier/intel-mid.h
+@@ -0,0 +1,29 @@
++#ifndef _ASM_X86_INTEL_MID_H
++#define _ASM_X86_INTEL_MID_H
++
++/*
++ * Penwell uses spread spectrum clock, so the freq number is not exactly
++ * the same as reported by MSR based on SDM.
++ * CLVP A0 has 100MHz FSB and CLVP B0 has 133MHz FSB.
++ */
++#define FSB_FREQ_83SKU 83200
++#define FSB_FREQ_100SKU 99840
++#define FSB_FREQ_133SKU 133000
++
++#define FSB_FREQ_167SKU 167000
++#define FSB_FREQ_200SKU 200000
++#define FSB_FREQ_267SKU 267000
++#define FSB_FREQ_333SKU 333000
++#define FSB_FREQ_400SKU 400000
++
++/* Bus Select SoC Fuse value */
++#define BSEL_SOC_FUSE_MASK 0x7
++#define BSEL_SOC_FUSE_001 0x1 /* FSB 133MHz */
++#define BSEL_SOC_FUSE_101 0x5 /* FSB 100MHz */
++#define BSEL_SOC_FUSE_111 0x7 /* FSB 83MHz */
++
++extern unsigned int loops_per_jiffy;
++
++extern unsigned long calibrate_tsc(void);
++
++#endif /* _ASM_X86_INTEL_MID_H */
+diff --git a/arch/x86/include/asm/arch-tangier/ipchecksum.h b/arch/x86/include/asm/arch-tangier/ipchecksum.h
+new file mode 100644
+index 0000000..1d73b4d
+--- /dev/null
++++ b/arch/x86/include/asm/arch-tangier/ipchecksum.h
+@@ -0,0 +1,37 @@
++/*
++ * This file is part of the libpayload project.
++ *
++ * It has originally been taken from the FreeBSD project.
++ *
++ * Copyright (c) 2001 Charles Mott <cm@linktel.net>
++ * Copyright (c) 2008 coresystems GmbH
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++
++#ifndef _COREBOOT_IPCHECKSUM_H
++#define _COREBOOT_IPCHECKSUM_H
++
++unsigned short ipchksum(const void *vptr, unsigned long nbytes);
++
++#endif
+diff --git a/arch/x86/include/asm/arch-tangier/mmc.h b/arch/x86/include/asm/arch-tangier/mmc.h
+new file mode 100644
+index 0000000..2200a7f
+--- /dev/null
++++ b/arch/x86/include/asm/arch-tangier/mmc.h
+@@ -0,0 +1,11 @@
++#include <asm/types.h>
++#include <linux/types.h>
++#include <common.h>
++#include <malloc.h>
++#include <pci.h>
++#include <part.h>
++#include <mmc.h>
++#include <sdhci.h>
++
++int tangier_mmc_init(struct mmc *mmc);
++int tangier_sdhci_init(u32 regbase, int index, int bus_width);
+diff --git a/arch/x86/include/asm/arch-tangier/sysinfo.h b/arch/x86/include/asm/arch-tangier/sysinfo.h
+new file mode 100644
+index 0000000..8e4a61d
+--- /dev/null
++++ b/arch/x86/include/asm/arch-tangier/sysinfo.h
+@@ -0,0 +1,62 @@
++/*
++ * This file is part of the libpayload project.
++ *
++ * Copyright (C) 2008 Advanced Micro Devices, Inc.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#ifndef _COREBOOT_SYSINFO_H
++#define _COREBOOT_SYSINFO_H
++
++#include <common.h>
++#include <compiler.h>
++#include <libfdt.h>
++#include <asm/arch/tables.h>
++
++/* Allow a maximum of 16 memory range definitions. */
++#define SYSINFO_MAX_MEM_RANGES 16
++/* Allow a maximum of 8 GPIOs */
++#define SYSINFO_MAX_GPIOS 8
++
++struct sysinfo_t {
++ int n_memranges;
++ struct memrange {
++ unsigned long long base;
++ unsigned long long size;
++ unsigned int type;
++ } memrange[SYSINFO_MAX_MEM_RANGES];
++
++ u32 cmos_range_start;
++ u32 cmos_range_end;
++ u32 cmos_checksum_location;
++ u32 vbnv_start;
++ u32 vbnv_size;
++
++ char *version;
++ char *extra_version;
++ char *build;
++ char *compile_time;
++ char *compile_by;
++ char *compile_host;
++ char *compile_domain;
++ char *compiler;
++ char *linker;
++ char *assembler;
++
++ struct cb_framebuffer *framebuffer;
++
++ int num_gpios;
++ struct cb_gpio gpios[SYSINFO_MAX_GPIOS];
++
++ void *vdat_addr;
++ u32 vdat_size;
++ void *tstamp_table;
++ void *cbmem_cons;
++
++ struct cb_serial *serial;
++};
++
++extern struct sysinfo_t lib_sysinfo;
++
++#endif
+diff --git a/arch/x86/include/asm/arch-tangier/tables.h b/arch/x86/include/asm/arch-tangier/tables.h
+new file mode 100644
+index 0000000..0d02fe0
+--- /dev/null
++++ b/arch/x86/include/asm/arch-tangier/tables.h
+@@ -0,0 +1,294 @@
++/*
++ * This file is part of the libpayload project.
++ *
++ * Copyright (C) 2008 Advanced Micro Devices, Inc.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#ifndef _COREBOOT_TABLES_H
++#define _COREBOOT_TABLES_H
++
++#include <compiler.h>
++
++struct cbuint64 {
++ u32 lo;
++ u32 hi;
++};
++
++struct cb_header {
++ u8 signature[4];
++ u32 header_bytes;
++ u32 header_checksum;
++ u32 table_bytes;
++ u32 table_checksum;
++ u32 table_entries;
++};
++
++struct cb_record {
++ u32 tag;
++ u32 size;
++};
++
++#define CB_TAG_UNUSED 0x0000
++#define CB_TAG_MEMORY 0x0001
++
++struct cb_memory_range {
++ struct cbuint64 start;
++ struct cbuint64 size;
++ u32 type;
++};
++
++#define CB_MEM_RAM 1
++#define CB_MEM_RESERVED 2
++#define CB_MEM_ACPI 3
++#define CB_MEM_NVS 4
++#define CB_MEM_UNUSABLE 5
++#define CB_MEM_VENDOR_RSVD 6
++#define CB_MEM_TABLE 16
++
++struct cb_memory {
++ u32 tag;
++ u32 size;
++ struct cb_memory_range map[0];
++};
++
++#define CB_TAG_HWRPB 0x0002
++
++struct cb_hwrpb {
++ u32 tag;
++ u32 size;
++ u64 hwrpb;
++};
++
++#define CB_TAG_MAINBOARD 0x0003
++
++struct cb_mainboard {
++ u32 tag;
++ u32 size;
++ u8 vendor_idx;
++ u8 part_number_idx;
++ u8 strings[0];
++};
++
++#define CB_TAG_VERSION 0x0004
++#define CB_TAG_EXTRA_VERSION 0x0005
++#define CB_TAG_BUILD 0x0006
++#define CB_TAG_COMPILE_TIME 0x0007
++#define CB_TAG_COMPILE_BY 0x0008
++#define CB_TAG_COMPILE_HOST 0x0009
++#define CB_TAG_COMPILE_DOMAIN 0x000a
++#define CB_TAG_COMPILER 0x000b
++#define CB_TAG_LINKER 0x000c
++#define CB_TAG_ASSEMBLER 0x000d
++
++struct cb_string {
++ u32 tag;
++ u32 size;
++ u8 string[0];
++};
++
++#define CB_TAG_SERIAL 0x000f
++
++struct cb_serial {
++ u32 tag;
++ u32 size;
++#define CB_SERIAL_TYPE_IO_MAPPED 1
++#define CB_SERIAL_TYPE_MEMORY_MAPPED 2
++ u32 type;
++ u32 baseaddr;
++ u32 baud;
++};
++
++#define CB_TAG_CONSOLE 0x00010
++
++struct cb_console {
++ u32 tag;
++ u32 size;
++ u16 type;
++};
++
++#define CB_TAG_CONSOLE_SERIAL8250 0
++#define CB_TAG_CONSOLE_VGA 1 /* OBSOLETE */
++#define CB_TAG_CONSOLE_BTEXT 2 /* OBSOLETE */
++#define CB_TAG_CONSOLE_LOGBUF 3
++#define CB_TAG_CONSOLE_SROM 4 /* OBSOLETE */
++#define CB_TAG_CONSOLE_EHCI 5
++
++#define CB_TAG_FORWARD 0x00011
++
++struct cb_forward {
++ u32 tag;
++ u32 size;
++ u64 forward;
++};
++
++#define CB_TAG_FRAMEBUFFER 0x0012
++struct cb_framebuffer {
++ u32 tag;
++ u32 size;
++
++ u64 physical_address;
++ u32 x_resolution;
++ u32 y_resolution;
++ u32 bytes_per_line;
++ u8 bits_per_pixel;
++ u8 red_mask_pos;
++ u8 red_mask_size;
++ u8 green_mask_pos;
++ u8 green_mask_size;
++ u8 blue_mask_pos;
++ u8 blue_mask_size;
++ u8 reserved_mask_pos;
++ u8 reserved_mask_size;
++};
++
++#define CB_TAG_GPIO 0x0013
++#define GPIO_MAX_NAME_LENGTH 16
++struct cb_gpio {
++ u32 port;
++ u32 polarity;
++ u32 value;
++ u8 name[GPIO_MAX_NAME_LENGTH];
++};
++
++struct cb_gpios {
++ u32 tag;
++ u32 size;
++
++ u32 count;
++ struct cb_gpio gpios[0];
++};
++
++#define CB_TAG_FDT 0x0014
++struct cb_fdt {
++ uint32_t tag;
++ uint32_t size; /* size of the entire entry */
++ /* the actual FDT gets placed here */
++};
++
++#define CB_TAG_VDAT 0x0015
++struct cb_vdat {
++ uint32_t tag;
++ uint32_t size; /* size of the entire entry */
++ void *vdat_addr;
++ uint32_t vdat_size;
++};
++
++#define CB_TAG_TIMESTAMPS 0x0016
++#define CB_TAG_CBMEM_CONSOLE 0x0017
++#define CB_TAG_MRC_CACHE 0x0018
++struct cb_cbmem_tab {
++ uint32_t tag;
++ uint32_t size;
++ void *cbmem_tab;
++};
++
++#define CB_TAG_VBNV 0x0019
++struct cb_vbnv {
++ uint32_t tag;
++ uint32_t size;
++ uint32_t vbnv_start;
++ uint32_t vbnv_size;
++};
++
++#define CB_TAG_CMOS_OPTION_TABLE 0x00c8
++struct cb_cmos_option_table {
++ u32 tag;
++ u32 size;
++ u32 header_length;
++};
++
++#define CB_TAG_OPTION 0x00c9
++#define CMOS_MAX_NAME_LENGTH 32
++struct cb_cmos_entries {
++ u32 tag;
++ u32 size;
++ u32 bit;
++ u32 length;
++ u32 config;
++ u32 config_id;
++ u8 name[CMOS_MAX_NAME_LENGTH];
++};
++
++
++#define CB_TAG_OPTION_ENUM 0x00ca
++#define CMOS_MAX_TEXT_LENGTH 32
++struct cb_cmos_enums {
++ u32 tag;
++ u32 size;
++ u32 config_id;
++ u32 value;
++ u8 text[CMOS_MAX_TEXT_LENGTH];
++};
++
++#define CB_TAG_OPTION_DEFAULTS 0x00cb
++#define CMOS_IMAGE_BUFFER_SIZE 128
++struct cb_cmos_defaults {
++ u32 tag;
++ u32 size;
++ u32 name_length;
++ u8 name[CMOS_MAX_NAME_LENGTH];
++ u8 default_set[CMOS_IMAGE_BUFFER_SIZE];
++};
++
++#define CB_TAG_OPTION_CHECKSUM 0x00cc
++#define CHECKSUM_NONE 0
++#define CHECKSUM_PCBIOS 1
++struct cb_cmos_checksum {
++ u32 tag;
++ u32 size;
++ u32 range_start;
++ u32 range_end;
++ u32 location;
++ u32 type;
++};
++
++/* Helpful macros */
++
++#define MEM_RANGE_COUNT(_rec) \
++ (((_rec)->size - sizeof(*(_rec))) / sizeof((_rec)->map[0]))
++
++#define MEM_RANGE_PTR(_rec, _idx) \
++ (((u8 *) (_rec)) + sizeof(*(_rec)) \
++ + (sizeof((_rec)->map[0]) * (_idx)))
++
++#define MB_VENDOR_STRING(_mb) \
++ (((unsigned char *) ((_mb)->strings)) + (_mb)->vendor_idx)
++
++#define MB_PART_STRING(_mb) \
++ (((unsigned char *) ((_mb)->strings)) + (_mb)->part_number_idx)
++
++#define UNPACK_CB64(_in) \
++ ((((u64) _in.hi) << 32) | _in.lo)
++
++struct sysinfo_t;
++
++int get_coreboot_info(struct sysinfo_t *info);
++
++#define CBMEM_TOC_RESERVED 512
++#define MAX_CBMEM_ENTRIES 16
++#define CBMEM_MAGIC 0x434f5245
++
++struct cbmem_entry {
++ u32 magic;
++ u32 id;
++ u64 base;
++ u64 size;
++} __packed;
++
++#define CBMEM_ID_FREESPACE 0x46524545
++#define CBMEM_ID_GDT 0x4c474454
++#define CBMEM_ID_ACPI 0x41435049
++#define CBMEM_ID_CBTABLE 0x43425442
++#define CBMEM_ID_PIRQ 0x49525154
++#define CBMEM_ID_MPTABLE 0x534d5054
++#define CBMEM_ID_RESUME 0x5245534d
++#define CBMEM_ID_RESUME_SCRATCH 0x52455343
++#define CBMEM_ID_SMBIOS 0x534d4254
++#define CBMEM_ID_TIMESTAMP 0x54494d45
++#define CBMEM_ID_MRCDATA 0x4d524344
++#define CBMEM_ID_CONSOLE 0x434f4e53
++#define CBMEM_ID_NONE 0x00000000
++
++#endif
+diff --git a/arch/x86/include/asm/arch-tangier/timestamp.h b/arch/x86/include/asm/arch-tangier/timestamp.h
+new file mode 100644
+index 0000000..fcfc1d5
+--- /dev/null
++++ b/arch/x86/include/asm/arch-tangier/timestamp.h
+@@ -0,0 +1,59 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
++ *
++ * 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; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
++ */
++
++#ifndef __COREBOOT_TIMESTAMP_H__
++#define __COREBOOT_TIMESTAMP_H__
++
++enum timestamp_id {
++ /* coreboot specific timestamp IDs */
++ TS_START_ROMSTAGE = 1,
++ TS_BEFORE_INITRAM = 2,
++ TS_AFTER_INITRAM = 3,
++ TS_END_ROMSTAGE = 4,
++ TS_START_COPYRAM = 8,
++ TS_END_COPYRAM = 9,
++ TS_START_RAMSTAGE = 10,
++ TS_DEVICE_ENUMERATE = 30,
++ TS_DEVICE_CONFIGURE = 40,
++ TS_DEVICE_ENABLE = 50,
++ TS_DEVICE_INITIALIZE = 60,
++ TS_DEVICE_DONE = 70,
++ TS_CBMEM_POST = 75,
++ TS_WRITE_TABLES = 80,
++ TS_LOAD_PAYLOAD = 90,
++ TS_ACPI_WAKE_JUMP = 98,
++ TS_SELFBOOT_JUMP = 99,
++
++ /* U-Boot entry IDs start at 1000 */
++ TS_U_BOOT_INITTED = 1000, /* This is where u-boot starts */
++ TS_U_BOOT_START_KERNEL = 1100, /* Right before jumping to kernel. */
++};
++
++void timestamp_init(void);
++void timestamp_add(enum timestamp_id id, uint64_t ts_time);
++void timestamp_add_now(enum timestamp_id id);
++
++/**
++ * timestamp_add_to_bootstage - Add important coreboot timestamps to bootstage
++ *
++ * @return 0 if ok, -1 if no timestamps were found
++ */
++int timestamp_add_to_bootstage(void);
++
++#endif
+diff --git a/arch/x86/include/asm/delay.h b/arch/x86/include/asm/delay.h
+new file mode 100644
+index 0000000..18682f2
+--- /dev/null
++++ b/arch/x86/include/asm/delay.h
+@@ -0,0 +1,6 @@
++#ifndef _ASM_X86_DELAY_H
++#define _ASM_X86_DELAY_H
++
++extern void use_tsc_delay(void);
++
++#endif /* _ASM_X86_DELAY_H */
+diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h
+index 86bac90..9530cf7 100644
+--- a/arch/x86/include/asm/io.h
++++ b/arch/x86/include/asm/io.h
+@@ -69,6 +69,54 @@
+ #define memcpy_fromio(a,b,c) memcpy((a),(b),(c))
+ #define memcpy_toio(a,b,c) memcpy((a),(b),(c))
+
++#define out_arch(type,endian,a,v) __raw_write##type(cpu_to_##endian(v), a)
++#define in_arch(type,endian,a) endian##_to_cpu(__raw_read##type(a))
++
++#define out_le32(a,v) out_arch(l,le32,a,v)
++#define out_le16(a,v) out_arch(w,le16,a,v)
++
++#define in_le32(a) in_arch(l,le32,a)
++#define in_le16(a) in_arch(w,le16,a)
++
++#define out_be32(a,v) out_arch(l,be32,a,v)
++#define out_be16(a,v) out_arch(w,be16,a,v)
++
++#define in_be32(a) in_arch(l,be32,a)
++#define in_be16(a) in_arch(w,be16,a)
++
++#define out_8(a,v) __raw_writeb(v, a)
++#define in_8(a) __raw_readb(a)
++
++#define clrbits(type, addr, clear) \
++ out_##type((addr), in_##type(addr) & ~(clear))
++
++#define setbits(type, addr, set) \
++ out_##type((addr), in_##type(addr) | (set))
++
++#define clrsetbits(type, addr, clear, set) \
++ out_##type((addr), (in_##type(addr) & ~(clear)) | (set))
++
++#define clrbits_be32(addr, clear) clrbits(be32, addr, clear)
++#define setbits_be32(addr, set) setbits(be32, addr, set)
++#define clrsetbits_be32(addr, clear, set) clrsetbits(be32, addr, clear, set)
++
++#define clrbits_le32(addr, clear) clrbits(le32, addr, clear)
++#define setbits_le32(addr, set) setbits(le32, addr, set)
++#define clrsetbits_le32(addr, clear, set) clrsetbits(le32, addr, clear, set)
++
++#define clrbits_be16(addr, clear) clrbits(be16, addr, clear)
++#define setbits_be16(addr, set) setbits(be16, addr, set)
++#define clrsetbits_be16(addr, clear, set) clrsetbits(be16, addr, clear, set)
++
++#define clrbits_le16(addr, clear) clrbits(le16, addr, clear)
++#define setbits_le16(addr, set) setbits(le16, addr, set)
++#define clrsetbits_le16(addr, clear, set) clrsetbits(le16, addr, clear, set)
++
++#define clrbits_8(addr, clear) clrbits(8, addr, clear)
++#define setbits_8(addr, set) setbits(8, addr, set)
++#define clrsetbits_8(addr, clear, set) clrsetbits(8, addr, clear, set)
++
++
+ /*
+ * ISA space is 'always mapped' on a typical x86 system, no need to
+ * explicitly ioremap() it. The fact that the ISA IO space is mapped
+diff --git a/arch/x86/include/asm/mpspec.h b/arch/x86/include/asm/mpspec.h
+new file mode 100644
+index 0000000..7609db4
+--- /dev/null
++++ b/arch/x86/include/asm/mpspec.h
+@@ -0,0 +1,74 @@
++#ifndef _ASM_X86_MPSPEC_H
++#define _ASM_X86_MPSPEC_H
++
++/* from apicdef.h */
++# define MAX_IO_APICS 64
++# define MAX_LOCAL_APIC 256
++
++#define SFI_MTMR_MAX_NUM 8
++
++#define MP_PROCESSOR 0
++#define MP_BUS 1
++#define MP_IOAPIC 2
++#define MP_INTSRC 3
++#define MP_LINTSRC 4
++
++#define BITS_PER_BYTE 8
++
++#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
++
++#define PHYSID_ARRAY_SIZE BITS_TO_LONGS(MAX_LOCAL_APIC)
++
++#define MAX_MP_BUSSES 260
++
++struct physid_mask {
++ unsigned long mask[PHYSID_ARRAY_SIZE];
++};
++
++typedef struct physid_mask physid_mask_t;
++
++#define PHYSID_MASK_ALL { {[0 ... PHYSID_ARRAY_SIZE-1] = ~0UL} }
++#define PHYSID_MASK_NONE { {[0 ... PHYSID_ARRAY_SIZE-1] = 0UL} }
++
++#define physids_empty(map) \
++ bitmap_empty((map).mask, MAX_LOCAL_APIC)
++
++enum mp_irq_source_types {
++ mp_INT = 0,
++ mp_NMI = 1,
++ mp_SMI = 2,
++ mp_ExtINT = 3
++};
++
++#define MP_APIC_ALL 0xFF
++
++enum mp_bustype {
++ MP_BUS_ISA = 1,
++ MP_BUS_EISA,
++ MP_BUS_PCI,
++ MP_BUS_MCA,
++};
++
++#define MPC_APIC_USABLE 0x01
++
++struct mpc_ioapic {
++ unsigned char type;
++ unsigned char apicid;
++ unsigned char apicver;
++ unsigned char flags;
++ unsigned int apicaddr;
++};
++
++struct mpc_intsrc {
++ unsigned char type;
++ unsigned char irqtype;
++ unsigned short irqflag;
++ unsigned char srcbus;
++ unsigned char srcbusirq;
++ unsigned char dstapic;
++ unsigned char dstirq;
++};
++
++#define MAX_IRQ_SOURCES 256
++
++#endif
+diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
+index 0a36e17..a03b6da 100644
+--- a/arch/x86/include/asm/msr-index.h
++++ b/arch/x86/include/asm/msr-index.h
+@@ -1,12 +1,3 @@
+-/*
+- * Taken from the linux kernel file of the same name
+- *
+- * (C) Copyright 2012
+- * Graeme Russ, <graeme.russ@gmail.com>
+- *
+- * SPDX-License-Identifier: GPL-2.0+
+- */
+-
+ #ifndef _ASM_X86_MSR_INDEX_H
+ #define _ASM_X86_MSR_INDEX_H
+
+@@ -44,6 +35,7 @@
+ #define MSR_IA32_PERFCTR0 0x000000c1
+ #define MSR_IA32_PERFCTR1 0x000000c2
+ #define MSR_FSB_FREQ 0x000000cd
++#define MSR_PLATFORM_INFO 0x000000ce
+
+ #define MSR_NHM_SNB_PKG_CST_CFG_CTL 0x000000e2
+ #define NHM_C3_AUTO_DEMOTE (1UL << 25)
+@@ -65,6 +57,13 @@
+ #define MSR_OFFCORE_RSP_0 0x000001a6
+ #define MSR_OFFCORE_RSP_1 0x000001a7
+
++#define MSR_LBR_SELECT 0x000001c8
++#define MSR_LBR_TOS 0x000001c9
++#define MSR_LBR_NHM_FROM 0x00000680
++#define MSR_LBR_NHM_TO 0x000006c0
++#define MSR_LBR_CORE_FROM 0x00000040
++#define MSR_LBR_CORE_TO 0x00000060
++
+ #define MSR_IA32_PEBS_ENABLE 0x000003f1
+ #define MSR_IA32_DS_AREA 0x00000600
+ #define MSR_IA32_PERF_CAPABILITIES 0x00000345
+@@ -91,8 +90,8 @@
+ #define MSR_IA32_LASTINTTOIP 0x000001de
+
+ /* DEBUGCTLMSR bits (others vary by model): */
+-#define DEBUGCTLMSR_LBR (1UL << 0)
+-#define DEBUGCTLMSR_BTF (1UL << 1)
++#define DEBUGCTLMSR_LBR (1UL << 0) /* last branch recording */
++#define DEBUGCTLMSR_BTF (1UL << 1) /* single-step on branches */
+ #define DEBUGCTLMSR_TR (1UL << 6)
+ #define DEBUGCTLMSR_BTS (1UL << 7)
+ #define DEBUGCTLMSR_BTINT (1UL << 8)
+@@ -127,6 +126,7 @@
+ complete list. */
+
+ #define MSR_AMD64_PATCH_LEVEL 0x0000008b
++#define MSR_AMD64_TSC_RATIO 0xc0000104
+ #define MSR_AMD64_NB_CFG 0xc001001f
+ #define MSR_AMD64_PATCH_LOADER 0xc0010020
+ #define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140
+@@ -237,12 +237,19 @@
+ #define MSR_IA32_APICBASE_ENABLE (1<<11)
+ #define MSR_IA32_APICBASE_BASE (0xfffff<<12)
+
++#define MSR_IA32_TSCDEADLINE 0x000006e0
++
+ #define MSR_IA32_UCODE_WRITE 0x00000079
+ #define MSR_IA32_UCODE_REV 0x0000008b
+
+ #define MSR_IA32_PERF_STATUS 0x00000198
+ #define MSR_IA32_PERF_CTL 0x00000199
+
++#define MSR_IA32_POWER_MISC 0x00000120
++
++#define ENABLE_ULFM_AUTOCM (1 << 2)
++#define ENABLE_INDP_AUTOCM (1 << 3)
++
+ #define MSR_IA32_MPERF 0x000000e7
+ #define MSR_IA32_APERF 0x000000e8
+
+@@ -267,6 +274,9 @@
+ #define MSR_IA32_TEMPERATURE_TARGET 0x000001a2
+
+ #define MSR_IA32_ENERGY_PERF_BIAS 0x000001b0
++#define ENERGY_PERF_BIAS_PERFORMANCE 0
++#define ENERGY_PERF_BIAS_NORMAL 6
++#define ENERGY_PERF_BIAS_POWERSAVE 15
+
+ #define MSR_IA32_PACKAGE_THERM_STATUS 0x000001b1
+
+@@ -319,6 +329,8 @@
+ #define MSR_IA32_MISC_ENABLE_DCU_PREF_DISABLE (1ULL << 37)
+ #define MSR_IA32_MISC_ENABLE_TURBO_DISABLE (1ULL << 38)
+ #define MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE (1ULL << 39)
++#define MSR_IA32_TSC_DEADLINE 0x000006E0
++
+
+ /* P4/Xeon+ specific */
+ #define MSR_IA32_MCG_EAX 0x00000180
+@@ -446,6 +458,18 @@
+ #define MSR_IA32_VMX_VMCS_ENUM 0x0000048a
+ #define MSR_IA32_VMX_PROCBASED_CTLS2 0x0000048b
+ #define MSR_IA32_VMX_EPT_VPID_CAP 0x0000048c
++#define MSR_IA32_VMX_TRUE_PINBASED_CTLS 0x0000048d
++#define MSR_IA32_VMX_TRUE_PROCBASED_CTLS 0x0000048e
++#define MSR_IA32_VMX_TRUE_EXIT_CTLS 0x0000048f
++#define MSR_IA32_VMX_TRUE_ENTRY_CTLS 0x00000490
++
++/* VMX_BASIC bits and bitmasks */
++#define VMX_BASIC_VMCS_SIZE_SHIFT 32
++#define VMX_BASIC_64 0x0001000000000000LLU
++#define VMX_BASIC_MEM_TYPE_SHIFT 50
++#define VMX_BASIC_MEM_TYPE_MASK 0x003c000000000000LLU
++#define VMX_BASIC_MEM_TYPE_WB 6LLU
++#define VMX_BASIC_INOUT 0x0040000000000000LLU
+
+ /* AMD-V MSRs */
+
+diff --git a/arch/x86/include/asm/sfi.h b/arch/x86/include/asm/sfi.h
+new file mode 100644
+index 0000000..3d18f6e
+--- /dev/null
++++ b/arch/x86/include/asm/sfi.h
+@@ -0,0 +1,119 @@
++/* Copyright (c) 2012 Intel
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++#ifndef _SFI_H
++#define _SFI_H
++
++#include <asm/arch/sysinfo.h>
++#include <asm/e820.h>
++
++/* Memory type definitions */
++enum sfi_mem_type {
++ SFI_MEM_RESERVED,
++ SFI_LOADER_CODE,
++ SFI_LOADER_DATA,
++ SFI_BOOT_SERVICE_CODE,
++ SFI_BOOT_SERVICE_DATA,
++ SFI_RUNTIME_SERVICE_CODE,
++ SFI_RUNTIME_SERVICE_DATA,
++ SFI_MEM_CONV,
++ SFI_MEM_UNUSABLE,
++ SFI_ACPI_RECLAIM,
++ SFI_ACPI_NVS,
++ SFI_MEM_MMIO,
++ SFI_MEM_IOPORT,
++ SFI_PAL_CODE,
++ SFI_MEM_TYPEMAX,
++};
++
++#define SFI_SYST_MAGIC 0x54535953
++#define SFI_MMAP_MAGIC 0x50414d4d
++
++struct sfi_mem_entry {
++ enum sfi_mem_type type;
++ u64 phy_start;
++ u64 vir_start;
++ u64 pages;
++ u64 attrib;
++} __attribute__ ((packed));
++
++struct sfi_apic_table_entry {
++ u64 phys_addr; /* phy base addr for APIC reg */
++} __attribute__ ((packed));
++
++struct sfi_timer_table_entry {
++ u64 phys_addr; /* phy base addr for the timer */
++ u32 freq_hz; /* in HZ */
++ u32 irq;
++} __attribute__ ((packed));
++
++struct sfi_table_header {
++ char signature[4];
++ u32 length;
++ u8 revision;
++ u8 checksum;
++ char oem_id[6];
++ char oem_table_id[8];
++} __attribute__ ((packed));
++
++struct sfi_quad_word {
++ u32 low;
++ u32 high;
++};
++
++struct sfi_table {
++ struct sfi_table_header header;
++ union {
++ u64 pentry[1];
++ struct sfi_quad_word entry[1];
++ };
++} __attribute__ ((packed));
++
++#define SFI_TBL_HEADER_LEN 24
++
++#define SFI_GET_NUM_ENTRIES(ptable, entry_type) \
++ ((ptable->header.length - sizeof(struct sfi_table_header)) / \
++ (sizeof(entry_type)))
++
++#define SFI_GET_ENTRY_NUM(ptable, entry) \
++ ((ptable->header.length - SFI_TBL_HEADER_LEN) / \
++ (sizeof(struct entry)))
++
++#define SFI_BASE_ADDR 0x000E0000
++#define SFI_LENGTH 0x00020000
++
++extern int sfi_mtimer_num;
++
++void sfi_parse_mtmr(void);
++struct sfi_timer_table_entry *sfi_get_mtmr(int hint);
++void fill_memranges_from_e820(struct sysinfo_t *info);
++
++#ifdef CONFIG_X86_IO_APIC
++int sfi_parse_ioapic(void);
++#endif /* CONFIG_X86_IO_APIC */
++
++#ifdef CONFIG_DETECT_RAM_SIZE_WORKAROUND
++unsigned long long sfi_get_max_usable_ram(struct sysinfo_t *info);
++#endif
++
++#ifdef CONFIG_SFI
++extern phys_size_t sfi_get_ram_size(void);
++extern unsigned sfi_setup_e820(unsigned max_entries, struct e820entry *entries);
++#endif
++
++#endif /* _SFI_H */
+diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
+index f7303ab..85274ab 100644
+--- a/arch/x86/lib/Makefile
++++ b/arch/x86/lib/Makefile
+@@ -19,6 +19,7 @@ obj-y += string.o
+ obj-$(CONFIG_SYS_X86_TSC_TIMER) += tsc_timer.o
+ obj-$(CONFIG_VIDEO_VGA) += video.o
+ obj-$(CONFIG_CMD_ZBOOT) += zimage.o
++obj-$(CONFIG_SFI) += sfi.o
+
+ LIBGCC := $(notdir $(NORMAL_LIBGCC))
+ extra-y := $(LIBGCC)
+diff --git a/arch/x86/lib/sfi.c b/arch/x86/lib/sfi.c
+new file mode 100644
+index 0000000..675ad88
+--- /dev/null
++++ b/arch/x86/lib/sfi.c
+@@ -0,0 +1,162 @@
++#include <common.h>
++#include <asm/bootparam.h>
++#include <asm/sfi.h>
++
++#define SFI_BASE_ADDR 0x000E0000
++#define SFI_LENGTH 0x00020000
++#define SFI_TABLE_LENGTH 16
++
++static int sfi_table_check(struct sfi_table_header *sbh)
++{
++ char chksum = 0;
++ char *pos = (char *)sbh;
++ int i;
++
++ if (sbh->length < SFI_TABLE_LENGTH)
++ return -1;
++
++ if (sbh->length > SFI_LENGTH)
++ return -1;
++
++ for (i = 0; i < sbh->length; i++)
++ chksum += *pos++;
++
++ if (chksum)
++ error("sfi: Invalid checksum\n");
++
++ /* checksum is ok if zero */
++ return chksum;
++}
++
++static unsigned long sfi_search_mmap(void)
++{
++ u32 i = 0;
++ u32 *pos = (u32 *) SFI_BASE_ADDR;
++ u32 *end = (u32 *) (SFI_BASE_ADDR + SFI_LENGTH);
++ struct sfi_table_header *sbh;
++ struct sfi_table *sb;
++ u32 sys_entry_cnt = 0;
++
++ /* Find SYST table */
++ for (; pos < end; pos += 4) {
++ if (*pos == SFI_SYST_MAGIC) {
++ if (!sfi_table_check((struct sfi_table_header *)pos))
++ break;
++ }
++ }
++
++ if (pos >= end) {
++ error("failed to locate SFI SYST table\n");
++ return 0;
++ }
++
++ /* map table pointers */
++ sb = (struct sfi_table *)pos;
++ sbh = (struct sfi_table_header *)sb;
++
++ sys_entry_cnt = (sbh->length - sizeof(struct sfi_table_header)) >> 3;
++
++ /* Search through each SYST entry for MMAP table */
++ for (i = 0; i < sys_entry_cnt; i++) {
++ sbh = (struct sfi_table_header *)sb->entry[i].low;
++ if (*(u32 *) sbh->signature == SFI_MMAP_MAGIC) {
++ if (!sfi_table_check((struct sfi_table_header *)sbh))
++ return (unsigned long)sbh;
++ }
++ }
++
++ return 0;
++}
++
++unsigned sfi_setup_e820(unsigned max_entries, struct e820entry *entries)
++{
++ struct sfi_table *sb;
++ struct sfi_mem_entry *mentry;
++ unsigned long long start, end, size;
++ int i, num, type, total;
++
++ total = 0;
++
++ /* search for sfi mmap table */
++ sb = (struct sfi_table *)sfi_search_mmap();
++ if (!sb) {
++ error("failed to locate SFI MMAP table\n");
++ return 0;
++ }
++ debug("will use sfi mmap table for e820 table\n");
++ num = SFI_GET_ENTRY_NUM(sb, sfi_mem_entry);
++ mentry = (struct sfi_mem_entry *)sb->pentry;
++
++ for (i = 0; i < num; i++) {
++ start = mentry->phy_start;
++ size = mentry->pages << 12;
++ end = start + size;
++
++ if (start > end)
++ continue;
++
++ /* translate SFI mmap type to E820 map type */
++ switch (mentry->type) {
++ case SFI_MEM_CONV:
++ type = E820_RAM;
++ break;
++ case SFI_MEM_UNUSABLE:
++ case SFI_RUNTIME_SERVICE_DATA:
++ mentry++;
++ continue;
++ default:
++ type = E820_RESERVED;
++ }
++
++ if (total == E820MAX)
++ break;
++ entries[total].addr = start;
++ entries[total].size = size;
++ entries[total++].type = type;
++
++ mentry++;
++ }
++
++ return total;
++}
++
++phys_size_t sfi_get_ram_size(void)
++{
++ struct sfi_table *sb;
++ struct sfi_mem_entry *mentry;
++ unsigned long long start, end, size;
++ int i, num;
++ phys_size_t ram = 0;
++
++ /* search for sfi mmap table */
++ sb = (struct sfi_table *)sfi_search_mmap();
++ if (!sb) {
++ error("failed to locate SFI MMAP table\n");
++ return 0;
++ }
++ debug("will use sfi mmap table for e820 table\n");
++ num = SFI_GET_ENTRY_NUM(sb, sfi_mem_entry);
++ mentry = (struct sfi_mem_entry *)sb->pentry;
++
++ for (i = 0; i < num; i++, mentry++) {
++ if (mentry->type != SFI_MEM_CONV)
++ continue;
++
++ start = mentry->phy_start;
++ size = mentry->pages << 12;
++ end = start + size;
++
++ if (start > end)
++ continue;
++
++ if (ram < end)
++ ram = end;
++ }
++
++ /* round up to 512mb */
++ ram = (ram + (512 * 1024 * 1024 - 1)) & ~(512 * 1024 * 1024 - 1);
++
++ debug("ram size %llu\n", ram);
++
++ return ram;
++}
+diff --git a/arch/x86/lib/tsc_timer.c b/arch/x86/lib/tsc_timer.c
+index 8b38702..bd751ed 100644
+--- a/arch/x86/lib/tsc_timer.c
++++ b/arch/x86/lib/tsc_timer.c
+@@ -34,13 +34,13 @@ u64 __attribute__((no_instrument_function)) get_ticks(void)
+ return now_tick - gd->arch.tsc_base;
+ }
+
+-#define PLATFORM_INFO_MSR 0xce
++
+
+ /* Get the speed of the TSC timer in MHz */
+-unsigned __attribute__((no_instrument_function)) long get_tbclk_mhz(void)
++unsigned __weak __attribute__((no_instrument_function)) long get_tbclk_mhz(void)
+ {
+ u32 ratio;
+- u64 platform_info = native_read_msr(PLATFORM_INFO_MSR);
++ u64 platform_info = native_read_msr(MSR_PLATFORM_INFO);
+
+ /* 100MHz times Max Non Turbo ratio */
+ ratio = (platform_info >> 8) & 0xff;
+diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c
+index 1dab3cc..e1387bb 100644
+--- a/arch/x86/lib/zimage.c
++++ b/arch/x86/lib/zimage.c
+@@ -252,6 +252,10 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot,
+ hdr->setup_move_size = 0x9100;
+ }
+
++#ifdef CONFIG_INTEL_MID
++ hdr->hardware_subarch = X86_SUBARCH_MRST;
++#endif
++
+ /* build command line at COMMAND_LINE_OFFSET */
+ build_command_line(cmd_line, auto_boot);
+ return 0;
+diff --git a/board/intel/edison/Makefile b/board/intel/edison/Makefile
+new file mode 100644
+index 0000000..a29f512
+--- /dev/null
++++ b/board/intel/edison/Makefile
+@@ -0,0 +1 @@
++obj-y += edison_start.o edison.o
+diff --git a/board/intel/edison/config.mk b/board/intel/edison/config.mk
+new file mode 100644
+index 0000000..0c05dd0
+--- /dev/null
++++ b/board/intel/edison/config.mk
+@@ -0,0 +1,7 @@
++#
++# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
++#
++# SPDX-License-Identifier: GPL-2.0 BSD-3-Clause
++#
++
++HOSTCFLAGS_autoconf.mk.dep = -Wno-variadic-macros
+diff --git a/board/intel/edison/edison.c b/board/intel/edison/edison.c
+new file mode 100644
+index 0000000..8d8a6e6
+--- /dev/null
++++ b/board/intel/edison/edison.c
+@@ -0,0 +1,54 @@
++#include <common.h>
++#include <asm/cache.h>
++#include <usb.h>
++#include <linux/usb/gadget.h>
++#include <intel_scu_ipc.h>
++#include <watchdog.h>
++#include <asm/u-boot-x86.h>
++
++DECLARE_GLOBAL_DATA_PTR;
++
++#ifndef CONFIG_WATCHDOG_HEARTBEAT
++#define WATCHDOG_HEARTBEAT 30
++#else
++#define WATCHDOG_HEARTBEAT CONFIG_WATCHDOG_HEARTBEAT
++#endif
++
++enum {
++ SCU_WATCHDOG_START = 0,
++ SCU_WATCHDOG_STOP,
++ SCU_WATCHDOG_KEEPALIVE,
++ SCU_WATCHDOG_SET_ACTION_ON_TIMEOUT
++};
++
++#define IPC_CMD(cmd, sub) (sub << 12 | cmd)
++
++int board_usb_init(int index, enum usb_init_type init)
++{
++ return usb_gadget_init_udc();
++}
++
++void watchdog_reset(void)
++{
++ ulong now = timer_get_us();
++
++ /* do not flood SCU */
++ if (unlikely((now - gd->arch.tsc_prev) > (WATCHDOG_HEARTBEAT * 1000000)))
++ {
++ gd->arch.tsc_prev = now;
++ intel_scu_ipc_send_command(IPC_CMD(IPCMSG_WATCHDOG_TIMER,
++ SCU_WATCHDOG_KEEPALIVE));
++ }
++}
++
++int watchdog_disable(void)
++{
++ return (intel_scu_ipc_simple_command(IPCMSG_WATCHDOG_TIMER,
++ SCU_WATCHDOG_STOP));
++}
++
++int watchdog_init(void)
++{
++ return (intel_scu_ipc_simple_command(IPCMSG_WATCHDOG_TIMER,
++ SCU_WATCHDOG_START));
++}
+diff --git a/board/intel/edison/edison.h b/board/intel/edison/edison.h
+new file mode 100644
+index 0000000..e69de29
+diff --git a/board/intel/edison/edison_start.S b/board/intel/edison/edison_start.S
+new file mode 100644
+index 0000000..932fe6c
+--- /dev/null
++++ b/board/intel/edison/edison_start.S
+@@ -0,0 +1,13 @@
++/*
++ * Copyright (c) 2011 The Chromium OS Authors.
++ * (C) Copyright 2008
++ * Graeme Russ, graeme.russ@gmail.com.
++ *
++ * SPDX-License-Identifier: GPL-2.0+
++ */
++
++/* board early intialization */
++.globl early_board_init
++early_board_init:
++ /* No 32-bit board specific initialisation */
++ jmp early_board_init_ret
+diff --git a/boards.cfg b/boards.cfg
+index b4203f1..bf4c268 100644
+--- a/boards.cfg
++++ b/boards.cfg
+@@ -1191,6 +1191,7 @@ Active sparc leon3 - gaisler -
+ Active sparc leon3 - gaisler - gr_xc3s_1500 - -
+ Active sparc leon3 - gaisler - grsim - -
+ Active x86 x86 coreboot chromebook-x86 coreboot coreboot-x86 coreboot:SYS_TEXT_BASE=0x01110000 -
++Active x86 sivermont tangier intel edison edison edison:SYS_USB_OTG_BASE=0xf9100000,SYS_EMMC_PORT_BASE=0xff3fc000,SYS_TEXT_BASE=0x1101000 -
+ # The following were moved to "Orphan" in March, 2014
+ Orphan blackfin blackfin - - - cm-bf527 - Bluetechnix Tinyboards <bluetechnix@blackfin.uclinux.org>
+ Orphan blackfin blackfin - - - cm-bf533 - Bluetechnix Tinyboards <bluetechnix@blackfin.uclinux.org>
+diff --git a/common/Makefile b/common/Makefile
+index cecd81a..3c65100 100644
+--- a/common/Makefile
++++ b/common/Makefile
+@@ -175,6 +175,8 @@ obj-$(CONFIG_CMD_SPL) += cmd_spl.o
+ obj-$(CONFIG_CMD_ZIP) += cmd_zip.o
+ obj-$(CONFIG_CMD_ZFS) += cmd_zfs.o
+
++COBJS-$(CONFIG_CMD_FASTBOOT) += cmd_fastboot.o
++
+ # others
+ obj-$(CONFIG_BOOTSTAGE) += bootstage.o
+ obj-$(CONFIG_CONSOLE_MUX) += iomux.o
+diff --git a/common/board_f.c b/common/board_f.c
+index f285bad..52b715c 100644
+--- a/common/board_f.c
++++ b/common/board_f.c
+@@ -280,7 +280,7 @@ __weak int arch_cpu_init(void)
+ return 0;
+ }
+
+-#ifdef CONFIG_OF_HOSTFILE
++#if defined(CONFIG_USE_FDT) && defined(CONFIG_OF_HOSTFILE)
+
+ static int read_fdt_from_file(void)
+ {
+@@ -335,6 +335,7 @@ static int setup_ram_buf(void)
+ }
+ #endif
+
++#ifdef CONFIG_USE_FDT
+ static int setup_fdt(void)
+ {
+ #ifdef CONFIG_OF_EMBED
+@@ -354,6 +355,7 @@ static int setup_fdt(void)
+ (uintptr_t)gd->fdt_blob);
+ return 0;
+ }
++#endif
+
+ /* Get the top of usable RAM */
+ __weak ulong board_get_usable_ram_top(ulong total_size)
+@@ -549,6 +551,7 @@ static int reserve_global_data(void)
+ return 0;
+ }
+
++#ifdef CONFIG_USE_FDT
+ static int reserve_fdt(void)
+ {
+ /*
+@@ -567,6 +570,7 @@ static int reserve_fdt(void)
+
+ return 0;
+ }
++#endif
+
+ static int reserve_stacks(void)
+ {
+@@ -724,6 +728,7 @@ static int setup_dram_config(void)
+ return 0;
+ }
+
++#ifdef CONFIG_USE_FDT
+ static int reloc_fdt(void)
+ {
+ if (gd->new_fdt) {
+@@ -733,6 +738,7 @@ static int reloc_fdt(void)
+
+ return 0;
+ }
++#endif
+
+ static int setup_reloc(void)
+ {
+@@ -789,7 +795,9 @@ static init_fnc_t init_sequence_f[] = {
+ setup_ram_buf,
+ #endif
+ setup_mon_len,
++#ifdef CONFIG_USE_FDT
+ setup_fdt,
++#endif
+ trace_early_init,
+ #if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx)
+ /* TODO: can this go into arch_cpu_init()? */
+@@ -798,12 +806,12 @@ static init_fnc_t init_sequence_f[] = {
+ arch_cpu_init, /* basic arch cpu dependent setup */
+ #ifdef CONFIG_X86
+ cpu_init_f, /* TODO(sjg@chromium.org): remove */
+-# ifdef CONFIG_OF_CONTROL
++#if defined(CONFIG_USE_FDT) && defined(CONFIG_OF_CONTROL)
+ find_fdt, /* TODO(sjg@chromium.org): remove */
+ # endif
+ #endif
+ mark_bootstage,
+-#ifdef CONFIG_OF_CONTROL
++#if defined(CONFIG_USE_FDT) && defined(CONFIG_OF_CONTROL)
+ fdtdec_check_fdt,
+ #endif
+ #if defined(CONFIG_BOARD_EARLY_INIT_F)
+@@ -847,7 +855,7 @@ static init_fnc_t init_sequence_f[] = {
+ #ifdef CONFIG_SANDBOX
+ sandbox_early_getopt_check,
+ #endif
+-#ifdef CONFIG_OF_CONTROL
++#if defined(CONFIG_USE_FDT) && defined(CONFIG_OF_CONTROL)
+ fdtdec_prepare_fdt,
+ #endif
+ display_options, /* say that we are here */
+@@ -945,7 +953,9 @@ static init_fnc_t init_sequence_f[] = {
+ #endif
+ setup_machine,
+ reserve_global_data,
++#ifdef CONFIG_USE_FDT
+ reserve_fdt,
++#endif
+ reserve_stacks,
+ setup_dram_config,
+ show_dram_config,
+@@ -960,7 +970,9 @@ static init_fnc_t init_sequence_f[] = {
+ setup_board_extra,
+ #endif
+ INIT_FUNC_WATCHDOG_RESET
++#ifdef CONFIG_USE_FDT
+ reloc_fdt,
++#endif
+ setup_reloc,
+ #if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX)
+ jump_to_copy,
+diff --git a/common/cmd_dfu.c b/common/cmd_dfu.c
+index 5547678..ac7db5e 100644
+--- a/common/cmd_dfu.c
++++ b/common/cmd_dfu.c
+@@ -21,7 +21,9 @@ static int do_dfu(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+ char *usb_controller = argv[1];
+ char *interface = argv[2];
+ char *devstring = argv[3];
+-
++#ifdef CONFIG_DFU_TIMEOUT
++ ulong dfu_timeout = 0 * 1000;
++#endif
+ char *s = "dfu";
+ int ret, i = 0;
+
+@@ -34,11 +36,20 @@ static int do_dfu(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+ dfu_show_entities();
+ goto done;
+ }
++#ifdef CONFIG_DFU_TIMEOUT
++ if (argc > 4)
++ dfu_timeout = simple_strtoul(argv[4], NULL, 0) * 1000 ;
++#endif
+
+ int controller_index = simple_strtoul(usb_controller, NULL, 0);
+ board_usb_init(controller_index, USB_INIT_DEVICE);
+-
+ g_dnl_register(s);
++
++#ifdef CONFIG_DFU_TIMEOUT
++ ulong time_activity_start = get_timer(0);
++ ulong time_inactivity_start = time_activity_start + dfu_timeout;
++ ulong next_print_time = 0;
++#endif
+ while (1) {
+ if (dfu_reset())
+ /*
+@@ -48,10 +59,32 @@ static int do_dfu(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+ */
+ if (++i == 10)
+ goto exit;
+-
++#ifdef CONFIG_DFU_TIMEOUT
++ if (dfu_enum_done() && (time_inactivity_start != time_activity_start))
++ {
++ time_inactivity_start = time_activity_start;
++ debug("\nDFU connection established\n");
++ }
++#endif
+ if (ctrlc())
+ goto exit;
++#ifdef CONFIG_DFU_TIMEOUT
++ if (time_activity_start != time_inactivity_start)
++ {
++ ulong cur_time = get_timer(time_activity_start);
+
++ if ( cur_time > dfu_timeout )
++ {
++ debug("\nInactivity Timeout, Abort Dfu\n");
++ goto exit;
++ }
++ if ( next_print_time == 0 || (get_timer(next_print_time)> 800))
++ {
++ debug("\rAborting in %lu sec", (dfu_timeout - cur_time)/1000);
++ next_print_time = get_timer(0);
++ }
++ }
++#endif
+ usb_gadget_handle_interrupts();
+ }
+ exit:
+@@ -67,9 +100,16 @@ done:
+
+ U_BOOT_CMD(dfu, CONFIG_SYS_MAXARGS, 1, do_dfu,
+ "Device Firmware Upgrade",
++#ifdef CONFIG_DFU_TIMEOUT
++ "<USB_controller> <interface> <dev> [list|timeout]\n"
++#else
+ "<USB_controller> <interface> <dev> [list]\n"
++#endif
+ " - device firmware upgrade via <USB_controller>\n"
+ " on device <dev>, attached to interface\n"
+ " <interface>\n"
+ " [list] - list available alt settings\n"
++#ifdef CONFIG_DFU_TIMEOUT
++ " [timeout] - specify inactivity timeout in sec, doesn't work whit list"
++#endif
+ );
+diff --git a/common/cmd_fastboot.c b/common/cmd_fastboot.c
+new file mode 100644
+index 0000000..9a656dd
+--- /dev/null
++++ b/common/cmd_fastboot.c
+@@ -0,0 +1,28 @@
++#include <common.h>
++#include <command.h>
++#include <usb/fastboot.h>
++
++static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
++{
++ int ret = 1;
++
++ if (!fastboot_init()) {
++ printf("Fastboot entered...\n");
++
++ ret = 0;
++
++ while (1) {
++ if (fastboot_poll())
++ break;
++ }
++ }
++
++ fastboot_shutdown();
++ return ret;
++}
++
++U_BOOT_CMD(
++ fastboot, 1, 1, do_fastboot,
++ "fastboot- use USB Fastboot protocol\n",
++ ""
++);
+diff --git a/common/cmd_gpt.c b/common/cmd_gpt.c
+index e38422d..c8317b4 100644
+--- a/common/cmd_gpt.c
++++ b/common/cmd_gpt.c
+@@ -54,7 +54,7 @@ static int extract_env(const char *str, char **env)
+ if (e == NULL) {
+ #ifdef CONFIG_RANDOM_UUID
+ debug("%s unset. ", str);
+- gen_rand_uuid_str(uuid_str, UUID_STR_FORMAT_STD);
++ gen_rand_uuid_str(uuid_str, UUID_STR_FORMAT_GUID);
+ setenv(s, uuid_str);
+
+ e = getenv(s);
+diff --git a/common/cmd_itest.c b/common/cmd_itest.c
+index ae2527b..a965b15 100644
+--- a/common/cmd_itest.c
++++ b/common/cmd_itest.c
+@@ -63,7 +63,8 @@ static long evalexp(char *s, int w)
+ l = simple_strtoul(s, NULL, 16);
+ }
+
+- return (l & ((1 << (w * 8)) - 1));
++ /* avoid overflow on mask calculus */
++ return ((sizeof(long) <= w )? l : (l & ((1 << (w * 8)) - 1)));
+ }
+
+ static char * evalstr(char *s)
+diff --git a/common/cmd_part.c b/common/cmd_part.c
+index 1424854..79c0297 100644
+--- a/common/cmd_part.c
++++ b/common/cmd_part.c
+@@ -21,11 +21,127 @@
+ #include <command.h>
+ #include <part.h>
+ #include <vsprintf.h>
++#include <malloc.h>
+
+ #ifndef CONFIG_PARTITION_UUIDS
+ #error CONFIG_PARTITION_UUIDS must be enabled for CONFIG_CMD_PART to be enabled
+ #endif
+
++int do_part_info(int argc, char * const argv[])
++{
++ int part;
++ block_dev_desc_t *dev_desc;
++ disk_partition_t info;
++ char buf_convert[20];
++ if (argc < 2)
++ return CMD_RET_USAGE;
++ if (argc > 5)
++ return CMD_RET_USAGE;
++
++ part = get_device_and_partition(argv[0], argv[1], &dev_desc, &info, 0);
++ if (part < 0)
++ return 1;
++
++ snprintf(buf_convert, sizeof(buf_convert), LBAF, info.start);
++ if (argc > 2)
++ setenv(argv[2], buf_convert);
++ else
++ printf("Partition start :0x%s\n", buf_convert);
++
++ snprintf(buf_convert, sizeof(buf_convert), LBAF, info.size);
++ if (argc > 3)
++ setenv(argv[3], buf_convert);
++ else
++ printf("Partition size :0x%s\n", buf_convert);
++
++ snprintf(buf_convert, sizeof(buf_convert), "%lx", info.blksz);
++ if (argc > 4)
++ setenv(argv[4], buf_convert);
++ else
++ printf("Block size :0x%s bytes\n", buf_convert);
++ return 0;
++}
++
++#define MAX_SEARCH_PARTITIONS 128
++int do_part_find(int argc, char * const argv[])
++{
++ int part, dev, i, ret=1;
++ block_dev_desc_t *dev_desc;
++ disk_partition_t info;
++ size_t mnb_of;
++ const char *value_str;
++ char *dup_str = NULL;
++ const char *criteria_str;
++ char buf_str[4];
++
++ if (argc < 3)
++ return CMD_RET_USAGE;
++ if (argc > 4)
++ return CMD_RET_USAGE;
++
++ dev = get_device(argv[0], argv[1], &dev_desc);
++ if (dev < 0)
++ return 1;
++
++ /* check and split criteria:value */
++ value_str = strchr(argv[2],':');
++ if (!value_str)
++ return CMD_RET_USAGE;
++
++ dup_str = strdup(argv[2]);
++ if(!dup_str)
++ return 1;
++
++ if ( (value_str - argv[2]) > strlen(dup_str) )
++ return 1;
++
++ dup_str[value_str - argv[2]] = 0;
++ criteria_str = dup_str;
++ value_str++;
++
++ if(!strcmp(criteria_str, "uuid"))
++ mnb_of = offsetof(disk_partition_t, uuid);
++ else if(!strcmp(criteria_str, "label"))
++ mnb_of = offsetof(disk_partition_t, name);
++ else {
++ printf("Bad criteria: %s\n", criteria_str);
++ ret = CMD_RET_USAGE;
++ goto end_of_part_find;
++ }
++
++ part=-1;
++ for (i = 1; i <= MAX_SEARCH_PARTITIONS; i++) {
++ ret = get_partition_info(dev_desc, i, &info);
++ if (ret)
++ continue;
++
++ if(!strcmp(((char*)&info + mnb_of), value_str)) {
++ part = i;
++ ret = 0;
++ break;
++ }
++ }
++
++ if ( part == -1) {
++ printf("No partition found\n");
++ ret = 1;
++ goto end_of_part_find;
++ }
++
++ snprintf(buf_str, sizeof(buf_str), "%d", part);
++ if ( argc > 3)
++ setenv(argv[3],buf_str);
++ else
++ printf("Partition %s correspond to %s == %s\n",
++ buf_str, criteria_str, value_str);
++
++end_of_part_find:
++ if( dup_str )
++ free (dup_str);
++
++ return ret;
++}
++
+ int do_part_uuid(int argc, char * const argv[])
+ {
+ int part;
+@@ -75,17 +191,30 @@ int do_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+ return do_part_uuid(argc - 2, argv + 2);
+ else if (!strcmp(argv[1], "list"))
+ return do_part_list(argc - 2, argv + 2);
+-
++ else if (!strcmp(argv[1], "info"))
++ return do_part_info(argc - 2, argv + 2);
++ else if (!strcmp(argv[1], "find"))
++ return do_part_find(argc - 2, argv + 2);
+ return CMD_RET_USAGE;
+ }
+
+ U_BOOT_CMD(
+- part, 5, 1, do_part,
++ part, 7, 1, do_part,
+ "disk partition related commands",
++ "find <interface> <dev> <criteria>:<value>\n"
++ " - print first partition number corresponding to criteria:valuei\n"
++ " - criteria could be label or uuid\n"
++ "part find <interface> <dev> <criteria>:<value> <varname>\n"
++ " - set environment variable to first partition number corresponding to criteria:valuei\n"
++ " - criteria could be label or uuid\n"
+ "uuid <interface> <dev>:<part>\n"
+ " - print partition UUID\n"
+ "part uuid <interface> <dev>:<part> <varname>\n"
+ " - set environment variable to partition UUID\n"
+ "part list <interface> <dev>\n"
+- " - print a device's partition table"
++ " - print a device's partition table\n"
++ "part info <interface> <dev>:<part> <varname-start> <varname-size> <varname-blcksize>\n"
++ " - set environment variable varname-start to partition start in blocks\n"
++ " - set environment variable varname-size to partition size in blocks\n"
++ " - set environment variable varname-blcksize to partition block size in bytes\n"
+ );
+diff --git a/disk/part_efi.c b/disk/part_efi.c
+index 216a292..4b32049 100644
+--- a/disk/part_efi.c
++++ b/disk/part_efi.c
+@@ -201,10 +201,12 @@ static int set_protective_mbr(block_dev_desc_t *dev_desc)
+ ALLOC_CACHE_ALIGN_BUFFER(legacy_mbr, p_mbr, 1);
+ memset(p_mbr, 0, sizeof(*p_mbr));
+
+- if (p_mbr == NULL) {
+- printf("%s: calloc failed!\n", __func__);
++ /* Read MBR to backup boot_code if it exists */
++ if (dev_desc->block_read(dev_desc->dev, 0, 1, p_mbr) != 1) {
++ error("** Can't read from device %d **\n", dev_desc->dev);
+ return -1;
+ }
++
+ /* Append signature */
+ p_mbr->signature = MSDOS_MBR_SIGNATURE;
+ p_mbr->partition_record[0].sys_ind = EFI_PMBR_OSTYPE_EFI_GPT;
+@@ -324,7 +326,7 @@ int gpt_fill_pte(gpt_header *gpt_h, gpt_entry *gpt_e,
+ str_uuid = partitions[i].uuid;
+ bin_uuid = gpt_e[i].unique_partition_guid.b;
+
+- if (uuid_str_to_bin(str_uuid, bin_uuid, UUID_STR_FORMAT_STD)) {
++ if (uuid_str_to_bin(str_uuid, bin_uuid, UUID_STR_FORMAT_GUID)) {
+ printf("Partition no. %d: invalid guid: %s\n",
+ i, str_uuid);
+ return -1;
+diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c
+index 8a09aaf..fa4bfc3 100644
+--- a/drivers/dfu/dfu.c
++++ b/drivers/dfu/dfu.c
+@@ -17,6 +17,7 @@
+ #include <linux/compiler.h>
+
+ static bool dfu_reset_request;
++static bool dfu_enum_request;
+ static LIST_HEAD(dfu_list);
+ static int dfu_alt_num;
+ static int alt_num_cnt;
+@@ -31,6 +32,16 @@ void dfu_trigger_reset()
+ dfu_reset_request = true;
+ }
+
++bool dfu_enum_done(void)
++{
++ return dfu_enum_request;
++}
++
++void dfu_trigger_enum_done()
++{
++ dfu_enum_request = true;
++}
++
+ static int dfu_find_alt_num(const char *s)
+ {
+ int i = 0;
+@@ -61,6 +72,7 @@ int dfu_init_env_entities(char *interface, int dev)
+ return ret;
+ }
+
++ dfu_enum_request = false;
+ free(env_bkp);
+ return 0;
+ }
+diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c
+index 651cfff..a7224b6 100644
+--- a/drivers/dfu/dfu_mmc.c
++++ b/drivers/dfu/dfu_mmc.c
+@@ -18,11 +18,29 @@ static unsigned char __aligned(CONFIG_SYS_CACHELINE_SIZE)
+ dfu_file_buf[CONFIG_SYS_DFU_MAX_FILE_SIZE];
+ static long dfu_file_buf_len;
+
++static int mmc_access_part(struct dfu_entity *dfu, struct mmc *mmc, int part)
++{
++ int ret;
++
++ if (part == mmc->part_num)
++ return 0;
++
++ ret = mmc_switch_part(dfu->dev_num, part);
++ if (ret) {
++ error("Cannot switch to partition %d\n", part);
++ return ret;
++ }
++ mmc->part_num = part;
++
++ return 0;
++}
++
+ static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
+ u64 offset, void *buf, long *len)
+ {
+ struct mmc *mmc = find_mmc_device(dfu->dev_num);
+ u32 blk_start, blk_count, n = 0;
++ int ret, part_num_bkp = 0;
+
+ /*
+ * We must ensure that we work in lba_blk_size chunks, so ALIGN
+@@ -39,6 +57,13 @@ static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
+ return -EINVAL;
+ }
+
++ if (dfu->data.mmc.partition_access != DFU_NOT_SUPPORTED) {
++ part_num_bkp = mmc->part_num;
++ ret = mmc_access_part(dfu, mmc, dfu->data.mmc.partition_access);
++ if (ret)
++ return ret;
++ }
++
+ debug("%s: %s dev: %d start: %d cnt: %d buf: 0x%p\n", __func__,
+ op == DFU_OP_READ ? "MMC READ" : "MMC WRITE", dfu->dev_num,
+ blk_start, blk_count, buf);
+@@ -57,9 +82,17 @@ static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
+
+ if (n != blk_count) {
+ error("MMC operation failed");
++ if (dfu->data.mmc.partition_access != DFU_NOT_SUPPORTED)
++ mmc_access_part(dfu, mmc, part_num_bkp);
+ return -EIO;
+ }
+
++ if (dfu->data.mmc.partition_access != DFU_NOT_SUPPORTED) {
++ ret = mmc_access_part(dfu, mmc, part_num_bkp);
++ if (ret)
++ return ret;
++ }
++
+ return 0;
+ }
+
+@@ -193,12 +226,22 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s)
+ char *st;
+
+ dfu->dev_type = DFU_DEV_MMC;
++ dfu->data.mmc.partition_access = DFU_NOT_SUPPORTED;
++
+ st = strsep(&s, " ");
+ if (!strcmp(st, "mmc")) {
+ dfu->layout = DFU_RAW_ADDR;
+ dfu->data.mmc.lba_start = simple_strtoul(s, &s, 16);
+- dfu->data.mmc.lba_size = simple_strtoul(++s, &s, 16);
++ s++;
++ dfu->data.mmc.lba_size = simple_strtoul(s, &s, 16);
+ dfu->data.mmc.lba_blk_size = get_mmc_blk_size(dfu->dev_num);
++ if (*s) {
++ s++;
++ st = strsep(&s, " ");
++ if (!strcmp(st, "mmcpart"))
++ dfu->data.mmc.partition_access =
++ simple_strtoul(s, &s, 0);
++ }
+ } else if (!strcmp(st, "fat")) {
+ dfu->layout = DFU_FS_FAT;
+ } else if (!strcmp(st, "ext4")) {
+@@ -236,7 +279,8 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s)
+
+ if (dfu->layout == DFU_FS_EXT4 || dfu->layout == DFU_FS_FAT) {
+ dfu->data.mmc.dev = simple_strtoul(s, &s, 10);
+- dfu->data.mmc.part = simple_strtoul(++s, &s, 10);
++ s++;
++ dfu->data.mmc.part = simple_strtoul(s, &s, 10);
+ }
+
+ dfu->read_medium = dfu_read_medium_mmc;
+diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
+index 2f2e48f..889fe05 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -23,3 +23,4 @@ obj-$(CONFIG_PDSP188x) += pdsp188x.o
+ obj-$(CONFIG_STATUS_LED) += status_led.o
+ obj-$(CONFIG_TWL4030_LED) += twl4030_led.o
+ obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
++obj-$(CONFIG_INTEL_SCU) += intel_scu_ipc.o
+diff --git a/drivers/misc/intel_scu_ipc.c b/drivers/misc/intel_scu_ipc.c
+new file mode 100644
+index 0000000..5843fc8
+--- /dev/null
++++ b/drivers/misc/intel_scu_ipc.c
+@@ -0,0 +1,150 @@
++#include <common.h>
++#include <asm/io.h>
++#include <asm-generic/errno.h>
++#include <intel_scu_ipc.h>
++
++#define IPC_STATUS_ADDR 0x04
++#define IPC_SPTR_ADDR 0x08
++#define IPC_DPTR_ADDR 0x0C
++#define IPC_READ_BUFFER 0x90
++#define IPC_WRITE_BUFFER 0x80
++#define IPC_IOC 0x100
++
++/*
++ * Command Register (Write Only):
++ * A write to this register results in an interrupt to the SCU core processor
++ * Format:
++ * |rfu2(8) | size(8) | command id(4) | rfu1(3) | ioc(1) | command(8)|
++ */
++void intel_scu_ipc_send_command(u32 cmd)
++{
++ writel(cmd | IPC_IOC, CONFIG_SCU_IPC_BASE);
++}
++
++/*
++ * IPC Write Buffer (Write Only):
++ * 16-byte buffer for sending data associated with IPC command to
++ * SCU. Size of the data is specified in the IPC_COMMAND_REG register
++ */
++void ipc_data_writel(u32 data, u32 offset)
++{ /* Write ipc data */
++ writel(data, CONFIG_SCU_IPC_BASE + IPC_WRITE_BUFFER + offset);
++}
++
++/*
++ * Status Register (Read Only):
++ * Driver will read this register to get the ready/busy status of the IPC
++ * block and error status of the IPC command that was just processed by SCU
++ * Format:
++ * |rfu3(8)|error code(8)|initiator id(8)|cmd id(4)|rfu1(2)|error(1)|busy(1)|
++ */
++
++u32 ipc_read_status(void)
++{
++ return readl(CONFIG_SCU_IPC_BASE + IPC_STATUS_ADDR);
++}
++
++u8 ipc_data_readb(u32 offset)
++{ /* Read ipc byte data */
++ return readb(CONFIG_SCU_IPC_BASE + IPC_READ_BUFFER + offset);
++}
++
++u32 ipc_data_readl(u32 offset)
++{ /* Read ipc u32 data */
++ return readl(CONFIG_SCU_IPC_BASE + IPC_READ_BUFFER + offset);
++}
++
++int intel_scu_ipc_check_status(void)
++{
++ int ret = 0;
++ int status = 0;
++ int loop_count = 3000000;
++
++ while ((ipc_read_status() & 1) && --loop_count)
++ udelay(1);
++ if (loop_count == 0)
++ ret = -ETIMEDOUT;
++
++ status = ipc_read_status();
++
++ if (status & 0x2) {
++ printf("%s() status=0x%08x\n", __func__, status);
++ return -EIO;
++ }
++ status++;
++ return ret;
++}
++
++/**
++ * intel_scu_ipc_simple_command - send a simple command
++ * @cmd: command
++ * @sub: sub type
++ *
++ * Issue a simple command to the SCU. Do not use this interface if
++ * you must then access data as any data values may be overwritten
++ * by another SCU access by the time this function returns.
++ *
++ * This function may sleep. Locking for SCU accesses is handled for
++ * the caller.
++ */
++int intel_scu_ipc_simple_command(int cmd, int sub)
++{
++ int err = 0;
++
++ intel_scu_ipc_send_command(sub << 12 | cmd);
++ err = intel_scu_ipc_check_status();
++ return err;
++}
++
++int intel_scu_ipc_raw_cmd(u32 cmd, u32 sub, u8 * in, u8 inlen, u32 * out,
++ u32 outlen, u32 dptr, u32 sptr)
++{
++ int i, err;
++ u32 wbuf[4];
++
++ if (inlen > 16)
++ return -EINVAL;
++
++ memcpy(wbuf, in, inlen);
++
++ writel(dptr, CONFIG_SCU_IPC_BASE + IPC_DPTR_ADDR);
++ writel(sptr, CONFIG_SCU_IPC_BASE + IPC_SPTR_ADDR);
++
++ /**
++ * SRAM controller don't support 8bit write, it only supports
++ * 32bit write, so we have to write into the WBUF in 32bit,
++ * and SCU FW will use the inlen to determine the actual input
++ * data length in the WBUF.
++ */
++ for (i = 0; i < ((inlen + 3) / 4); i++)
++ ipc_data_writel(wbuf[i], 4 * i);
++
++ /**
++ * Watchdog IPC command is an exception here using double word
++ * as the unit of input data size because of some historical
++ * reasons and SCU FW is doing so.
++ */
++ if ((cmd & 0xFF) == IPCMSG_WATCHDOG_TIMER)
++ inlen = (inlen + 3) / 4;
++
++ intel_scu_ipc_send_command((inlen << 16) | (sub << 12) | cmd);
++ err = intel_scu_ipc_check_status();
++
++ for (i = 0; i < outlen; i++)
++ *out++ = ipc_data_readl(4 * i);
++
++ return err;
++}
++
++int intel_scu_ipc_command(u32 cmd, u32 sub, u8 * in, u8 inlen,
++ u32 * out, u32 outlen)
++{
++ int ret;
++ ret = intel_scu_ipc_raw_cmd(cmd, sub, in, inlen, out, outlen, 0, 0);
++ return ret;
++}
++
++int init_scu_ipc(void)
++{
++ return 0;
++}
+diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
+index 931922b..c88b42b 100644
+--- a/drivers/mmc/Makefile
++++ b/drivers/mmc/Makefile
+@@ -30,6 +30,7 @@ obj-$(CONFIG_DWMMC) += dw_mmc.o
+ obj-$(CONFIG_EXYNOS_DWMMC) += exynos_dw_mmc.o
+ obj-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o
+ obj-$(CONFIG_SOCFPGA_DWMMC) += socfpga_dw_mmc.o
++obj-$(CONFIG_TANGIER_SDHCI) += tangier_sdhci.o
+ ifdef CONFIG_SPL_BUILD
+ obj-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o
+ else
+diff --git a/drivers/mmc/tangier_sdhci.c b/drivers/mmc/tangier_sdhci.c
+new file mode 100644
+index 0000000..3337651
+--- /dev/null
++++ b/drivers/mmc/tangier_sdhci.c
+@@ -0,0 +1,38 @@
++#include <asm/types.h>
++#include <linux/types.h>
++#include <common.h>
++#include <malloc.h>
++#include <part.h>
++#include <mmc.h>
++#include <sdhci.h>
++#include <asm/arch/mmc.h>
++
++int tangier_sdhci_init(u32 regbase, int index, int bus_width)
++{
++ struct sdhci_host *host = NULL;
++
++ host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host));
++ if (!host) {
++ printf("sdhci__host malloc fail!\n");
++ return 1;
++ }
++
++ memset(host, 0x00, sizeof(struct sdhci_host));
++
++ host->name = "tangier_sdhci";
++ host->ioaddr = (void *)regbase;
++
++ host->quirks = SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE |
++ SDHCI_QUIRK_BROKEN_R1B | SDHCI_QUIRK_32BIT_DMA_ADDR |
++ SDHCI_QUIRK_WAIT_SEND_CMD;
++ host->voltages = MMC_VDD_165_195; //MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
++ host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
++
++ host->index = index;
++
++ host->host_caps = MMC_MODE_HC;
++
++ add_sdhci(host, 200000000, 400000);
++
++ return 0;
++}
+diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
+index 571c18f..1bdf0f5 100644
+--- a/drivers/serial/Makefile
++++ b/drivers/serial/Makefile
+@@ -6,6 +6,7 @@
+ #
+
+ obj-y += serial.o
++obj-y += serial_tng.o
+
+ obj-$(CONFIG_ALTERA_UART) += altera_uart.o
+ obj-$(CONFIG_ALTERA_JTAG_UART) += altera_jtag_uart.o
+diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c
+index df05bde..9e493dc 100644
+--- a/drivers/serial/serial.c
++++ b/drivers/serial/serial.c
+@@ -159,6 +159,7 @@ serial_initfunc(sa1100_serial_initialize);
+ serial_initfunc(sh_serial_initialize);
+ serial_initfunc(arm_dcc_initialize);
+ serial_initfunc(mxs_auart_initialize);
++serial_initfunc(tng_serial_initialize);
+ serial_initfunc(arc_serial_initialize);
+
+ /**
+diff --git a/drivers/serial/serial_tng.c b/drivers/serial/serial_tng.c
+new file mode 100644
+index 0000000..d6d6753
+--- /dev/null
++++ b/drivers/serial/serial_tng.c
+@@ -0,0 +1,252 @@
++/*
++ * (C) Copyright 2002
++ * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#include <common.h>
++#include <linux/compiler.h>
++
++#include <serial.h>
++
++#define cpu_relax() asm volatile("rep; nop")
++
++#define UART_GLOBAL 0xff010000
++
++#define UART_OFFSET 0x80
++
++#define SERIAL_BASE_ADDR (UART_GLOBAL + (UART_OFFSET * (dev_index + 1)))
++
++#define XMTRDY 0x20
++#define LSR_DR (0x01)
++
++#define DLAB 0x80
++
++#define TXR 0 /* Transmit register (WRITE) */
++#define RXR 0 /* Receive register (READ) */
++#define IER 1 /* Interrupt Enable */
++#define IIR 2 /* Interrupt ID */
++#define FCR 2 /* FIFO control */
++#define LCR 3 /* Line control */
++#define MCR 4 /* Modem control */
++#define LSR 5 /* Line Status */
++#define MSR 6 /* Modem Status */
++#define DLL 0 /* Divisor Latch Low */
++#define DLH 1 /* Divisor latch High */
++#define MUL 0x34 /* DDS Multiplier */
++#define DIV 0x38 /* DDS Divisor */
++
++/* Multi serial device functions */
++#define DECLARE_TNG_SERIAL_FUNCTIONS(port) \
++ int tng_serial##port##_init(void) \
++ { \
++ return serial_init_dev(port); \
++ } \
++ int tng_serial##port##_shutdown(void) \
++ { \
++ return serial_shutdown_dev(port); \
++ } \
++ void tng_serial##port##_setbrg(void) \
++ { \
++ serial_setbrg_dev(port); \
++ } \
++ int tng_serial##port##_getc(void) \
++ { \
++ return serial_getc_dev(port); \
++ } \
++ int tng_serial##port##_tstc(void) \
++ { \
++ return serial_tstc_dev(port); \
++ } \
++ void tng_serial##port##_putc(const char c) \
++ { \
++ serial_putc_dev(port, c); \
++ } \
++ void tng_serial##port##_puts(const char *s) \
++ { \
++ serial_puts_dev(port, s); \
++ }
++
++#define INIT_TNG_SERIAL_STRUCTURE(port, __name) { \
++ .name = __name, \
++ .start = tng_serial##port##_init, \
++ .stop = tng_serial##port##_shutdown, \
++ .setbrg = tng_serial##port##_setbrg, \
++ .getc = tng_serial##port##_getc, \
++ .tstc = tng_serial##port##_tstc, \
++ .putc = tng_serial##port##_putc, \
++ .puts = tng_serial##port##_puts, \
++}
++
++#ifdef CONFIG_HWFLOW
++static int hwflow;
++#endif
++
++void _serial_setbrg(const int dev_index)
++{
++ return;
++}
++
++static inline void serial_setbrg_dev(unsigned int dev_index)
++{
++ _serial_setbrg(dev_index);
++}
++
++/*
++ * Initialise the serial port.
++ */
++static int serial_init_dev(const int dev_index)
++{
++ unsigned char c;
++ unsigned divisor = 16;
++
++ c = readb(SERIAL_BASE_ADDR + LCR);
++ writeb(c | DLAB, SERIAL_BASE_ADDR + LCR);
++ writeb(divisor & 0xff, SERIAL_BASE_ADDR + DLL);
++ writeb((divisor >> 8) & 0xff, SERIAL_BASE_ADDR + DLH);
++ writeb(c & ~DLAB, SERIAL_BASE_ADDR + LCR);
++ writeb(0x2, SERIAL_BASE_ADDR + IER); /* TIE enable */
++ writeb(0x3, SERIAL_BASE_ADDR + LCR); /* 8n1 */
++ writeb(0, SERIAL_BASE_ADDR + FCR); /* no fifo */
++ writeb(0x3, SERIAL_BASE_ADDR + MCR); /* DTR + RTS */
++ writeb(7, SERIAL_BASE_ADDR + FCR);
++ writel(0x2ee0, SERIAL_BASE_ADDR + MUL);
++ writel(0x3d09, SERIAL_BASE_ADDR + DIV);
++
++ return 0;
++}
++
++/*
++ * Shutdown the serial port.
++ */
++static int serial_shutdown_dev(const int dev_index)
++{
++ unsigned char c;
++
++ writeb(0x0, SERIAL_BASE_ADDR + IER); /* TIE disable */
++ c = readb(SERIAL_BASE_ADDR + MCR);
++ writeb(c & ~0x08, SERIAL_BASE_ADDR + MCR); /* DTR + RTS */
++ c = readb(SERIAL_BASE_ADDR + LCR);
++ writeb(c & ~0x40, SERIAL_BASE_ADDR + LCR);
++ writeb(0x7, SERIAL_BASE_ADDR + FCR);
++ writeb(0x0, SERIAL_BASE_ADDR + FCR); /* no fifo */
++
++ return 0;
++}
++
++/*
++ * Read a single byte from the serial port.
++ */
++int _serial_getc(const int dev_index)
++{
++ while ((readb(SERIAL_BASE_ADDR + LSR) & LSR_DR) == 0) {
++ if (gd->have_console)
++ break;
++ }
++
++ return readb(SERIAL_BASE_ADDR + RXR) & 0xff;
++}
++
++static inline int serial_getc_dev(unsigned int dev_index)
++{
++ return _serial_getc(dev_index);
++}
++
++/*
++ * Output a single byte to the serial port.
++ */
++void _serial_putc(const char c, const int dev_index)
++{
++ while ((readb(SERIAL_BASE_ADDR + LSR) & XMTRDY) == 0)
++ cpu_relax();
++
++ writeb(c, SERIAL_BASE_ADDR + TXR);
++
++ /* If \n, also do \r */
++ if (c == '\n')
++ serial_putc('\r');
++}
++
++static inline void serial_putc_dev(unsigned int dev_index, const char c)
++{
++ _serial_putc(c, dev_index);
++}
++
++/*
++ * Test whether a character is in the RX buffer
++ */
++int _serial_tstc(const int dev_index)
++{
++ return (readb(SERIAL_BASE_ADDR + LSR) & LSR_DR) != 0;
++}
++
++static inline int serial_tstc_dev(unsigned int dev_index)
++{
++ return _serial_tstc(dev_index);
++}
++
++void _serial_puts(const char *s, const int dev_index)
++{
++ while (*s) {
++ _serial_putc(*s++, dev_index);
++ }
++ return;
++}
++
++static inline void serial_puts_dev(int dev_index, const char *s)
++{
++ return _serial_puts(s, dev_index);
++}
++
++DECLARE_TNG_SERIAL_FUNCTIONS(0);
++struct serial_device tng_serial0_device =
++INIT_TNG_SERIAL_STRUCTURE(0, "tng_serial0");
++DECLARE_TNG_SERIAL_FUNCTIONS(1);
++struct serial_device tng_serial1_device =
++INIT_TNG_SERIAL_STRUCTURE(1, "tng_serial1");
++DECLARE_TNG_SERIAL_FUNCTIONS(2);
++struct serial_device tng_serial2_device =
++INIT_TNG_SERIAL_STRUCTURE(2, "tng_serial2");
++
++__weak struct serial_device *default_serial_console(void)
++{
++#if defined(CONFIG_SYS_TNG_SERIAL0)
++ return &tng_serial0_device;
++#elif defined(CONFIG_SYS_TNG_SERIAL1)
++ return &tng_serial1_device;
++#elif defined(CONFIG_SYS_TNG_SERIAL2)
++ return &tng_serial2_device;
++#else
++#error "CONFIG_SERIAL? missing."
++#endif
++}
++
++void tng_serial_initialize(void)
++{
++#if defined(CONFIG_SYS_TNG_SERIAL0)
++ serial_init_dev(0);
++ serial_register(&tng_serial0_device);
++#endif
++#if defined(CONFIG_SYS_TNG_SERIAL1)
++ serial_init_dev(1);
++ serial_register(&tng_serial1_device);
++#endif
++#if defined(CONFIG_SYS_TNG_SERIAL2)
++ serial_init_dev(2);
++ serial_register(&tng_serial2_device);
++#endif
++}
+diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
+new file mode 100644
+index 0000000..2c05ec9
+--- /dev/null
++++ b/drivers/usb/dwc3/Kconfig
+@@ -0,0 +1,26 @@
++config USB_DWC3
++ tristate "DesignWare USB3 DRD Core Support"
++ depends on (USB || USB_GADGET)
++ select USB_OTG_UTILS
++ select USB_XHCI_PLATFORM
++ help
++ Say Y or M here if your system has a Dual Role SuperSpeed
++ USB controller based on the DesignWare USB3 IP Core.
++
++ If you choose to build this driver is a dynamically linked
++ module, the module will be called dwc3.ko.
++
++if USB_DWC3
++
++config USB_DWC3_DEBUG
++ bool "Enable Debugging Messages"
++ help
++ Say Y here to enable debugging messages on DWC3 Driver.
++
++config USB_DWC3_VERBOSE
++ bool "Enable Verbose Debugging Messages"
++ depends on USB_DWC3_DEBUG
++ help
++ Say Y here to enable verbose debugging messages on DWC3 Driver.
++
++endif
+diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
+new file mode 100644
+index 0000000..1b5d353
+--- /dev/null
++++ b/drivers/usb/dwc3/Makefile
+@@ -0,0 +1,8 @@
++obj-$(CONFIG_USB_DWC3) += dwc3_core.o dwc3_ep0.o dwc3_misc.o
++obj-$(CONFIG_USB_DWC3_GADGET) += dwc3_gadget.o
++obj-$(CONFIG_USB_DWC3_HOST) += dwc3_host.o
++
++ccflags-y := $(call cc-option,-Wno-unused-variable) \
++ $(call cc-option,-Wno-unused-but-set-variable) \
++ $(call cc-option,-Wno-unused-label)
++
+diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
+new file mode 100644
+index 0000000..46f0c2f
+--- /dev/null
++++ b/drivers/usb/dwc3/core.h
+@@ -0,0 +1,814 @@
++/**
++ * core.h - DesignWare USB3 DRD Core Header
++ *
++ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
++ *
++ * Authors: Felipe Balbi <balbi@ti.com>,
++ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __DRIVERS_USB_DWC3_CORE_H
++#define __DRIVERS_USB_DWC3_CORE_H
++
++#include <linux/usb/ch9.h>
++#include <linux/usb/gadget.h>
++#include <linux/compiler.h>
++#include "misc.h"
++
++/* Global constants */
++#define DWC3_ENDPOINTS_NUM 32
++
++#define DWC3_EVENT_BUFFERS_SIZE PAGE_SIZE
++#define DWC3_EVENT_TYPE_MASK 0xfe
++
++#define DWC3_EVENT_TYPE_DEV 0
++#define DWC3_EVENT_TYPE_CARKIT 3
++#define DWC3_EVENT_TYPE_I2C 4
++
++#define DWC3_DEVICE_EVENT_DISCONNECT 0
++#define DWC3_DEVICE_EVENT_RESET 1
++#define DWC3_DEVICE_EVENT_CONNECT_DONE 2
++#define DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE 3
++#define DWC3_DEVICE_EVENT_WAKEUP 4
++#define DWC3_DEVICE_EVENT_EOPF 6
++#define DWC3_DEVICE_EVENT_SOF 7
++#define DWC3_DEVICE_EVENT_ERRATIC_ERROR 9
++#define DWC3_DEVICE_EVENT_CMD_CMPL 10
++#define DWC3_DEVICE_EVENT_OVERFLOW 11
++
++#define DWC3_GEVNTCOUNT_MASK 0xfffc
++#define DWC3_GSNPSID_MASK 0xffff0000
++#define DWC3_GSNPSREV_MASK 0xffff
++
++/* Global Registers */
++#define DWC3_GSBUSCFG0 0xc100
++#define DWC3_GSBUSCFG1 0xc104
++#define DWC3_GTXTHRCFG 0xc108
++#define DWC3_GRXTHRCFG 0xc10c
++#define DWC3_GCTL 0xc110
++#define DWC3_GEVTEN 0xc114
++#define DWC3_GSTS 0xc118
++#define DWC3_GSNPSID 0xc120
++#define DWC3_GGPIO 0xc124
++#define DWC3_GUID 0xc128
++#define DWC3_GUCTL 0xc12c
++#define DWC3_GBUSERRADDR0 0xc130
++#define DWC3_GBUSERRADDR1 0xc134
++#define DWC3_GPRTBIMAP0 0xc138
++#define DWC3_GPRTBIMAP1 0xc13c
++#define DWC3_GHWPARAMS0 0xc140
++#define DWC3_GHWPARAMS1 0xc144
++#define DWC3_GHWPARAMS2 0xc148
++#define DWC3_GHWPARAMS3 0xc14c
++#define DWC3_GHWPARAMS4 0xc150
++#define DWC3_GHWPARAMS5 0xc154
++#define DWC3_GHWPARAMS6 0xc158
++#define DWC3_GHWPARAMS7 0xc15c
++#define DWC3_GDBGFIFOSPACE 0xc160
++#define DWC3_GDBGLTSSM 0xc164
++#define DWC3_GPRTBIMAP_HS0 0xc180
++#define DWC3_GPRTBIMAP_HS1 0xc184
++#define DWC3_GPRTBIMAP_FS0 0xc188
++#define DWC3_GPRTBIMAP_FS1 0xc18c
++
++#define DWC3_GUSB2PHYCFG(n) (0xc200 + (n * 0x04))
++#define DWC3_GUSB2I2CCTL(n) (0xc240 + (n * 0x04))
++
++#define DWC3_GUSB2PHYACC(n) (0xc280 + (n * 0x04))
++
++#define DWC3_GUSB3PIPECTL(n) (0xc2c0 + (n * 0x04))
++
++#define DWC3_GTXFIFOSIZ(n) (0xc300 + (n * 0x04))
++#define DWC3_GRXFIFOSIZ(n) (0xc380 + (n * 0x04))
++
++#define DWC3_GEVNTADRLO(n) (0xc400 + (n * 0x10))
++#define DWC3_GEVNTADRHI(n) (0xc404 + (n * 0x10))
++#define DWC3_GEVNTSIZ(n) (0xc408 + (n * 0x10))
++#define DWC3_GEVNTCOUNT(n) (0xc40c + (n * 0x10))
++
++#define DWC3_GHWPARAMS8 0xc600
++
++/* Device Registers */
++#define DWC3_DCFG 0xc700
++#define DWC3_DCTL 0xc704
++#define DWC3_DEVTEN 0xc708
++#define DWC3_DSTS 0xc70c
++#define DWC3_DGCMDPAR 0xc710
++#define DWC3_DGCMD 0xc714
++#define DWC3_DALEPENA 0xc720
++#define DWC3_DEPCMDPAR2(n) (0xc800 + (n * 0x10))
++#define DWC3_DEPCMDPAR1(n) (0xc804 + (n * 0x10))
++#define DWC3_DEPCMDPAR0(n) (0xc808 + (n * 0x10))
++#define DWC3_DEPCMD(n) (0xc80c + (n * 0x10))
++
++/* OTG Registers */
++#define DWC3_OCFG 0xcc00
++#define DWC3_OCTL 0xcc04
++#define DWC3_OEVTEN 0xcc08
++#define DWC3_OSTS 0xcc0C
++
++/* Bit fields */
++
++/* Global Configuration Register */
++#define DWC3_GCTL_PWRDNSCALE(n) (n << 19)
++#define DWC3_GCTL_U2RSTECN (1 << 16)
++#define DWC3_GCTL_RAMCLKSEL(x) ((x & DWC3_GCTL_CLK_MASK) << 6)
++#define DWC3_GCTL_CLK_BUS (0)
++#define DWC3_GCTL_CLK_PIPE (1)
++#define DWC3_GCTL_CLK_PIPEHALF (2)
++#define DWC3_GCTL_CLK_MASK (3)
++
++#define DWC3_GCTL_PRTCAP(n) (((n) & (3 << 12)) >> 12)
++#define DWC3_GCTL_PRTCAPDIR(n) (n << 12)
++#define DWC3_GCTL_PRTCAP_HOST 1
++#define DWC3_GCTL_PRTCAP_DEVICE 2
++#define DWC3_GCTL_PRTCAP_OTG 3
++
++#define DWC3_GCTL_CORESOFTRESET (1 << 11)
++#define DWC3_GCTL_SCALEDOWN(n) (n << 4)
++#define DWC3_GCTL_DISSCRAMBLE (1 << 3)
++#define DWC3_GCTL_DSBLCLKGTNG (1 << 0)
++
++/* Global USB2 PHY Configuration Register */
++#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31)
++#define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6)
++
++/* Global USB3 PIPE Control Register */
++#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
++#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
++
++/* Global HWPARAMS1 Register */
++#define DWC3_GHWPARAMS1_EN_PWROPT(n) ((n & (3 << 24)) >> 24)
++#define DWC3_GHWPARAMS1_EN_PWROPT_NO 0
++#define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1
++
++/* Device Configuration Register */
++#define DWC3_DCFG_DEVADDR(addr) ((addr) << 3)
++#define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f)
++
++#define DWC3_DCFG_SPEED_MASK (7 << 0)
++#define DWC3_DCFG_SUPERSPEED (4 << 0)
++#define DWC3_DCFG_HIGHSPEED (0 << 0)
++#define DWC3_DCFG_FULLSPEED2 (1 << 0)
++#define DWC3_DCFG_LOWSPEED (2 << 0)
++#define DWC3_DCFG_FULLSPEED1 (3 << 0)
++
++/* Device Control Register */
++#define DWC3_DCTL_RUN_STOP (1 << 31)
++#define DWC3_DCTL_CSFTRST (1 << 30)
++#define DWC3_DCTL_LSFTRST (1 << 29)
++
++#define DWC3_DCTL_HIRD_THRES_MASK (0x1f << 24)
++#define DWC3_DCTL_HIRD_THRES(n) (((n) & DWC3_DCTL_HIRD_THRES_MASK) >> 24)
++
++#define DWC3_DCTL_APPL1RES (1 << 23)
++
++#define DWC3_DCTL_INITU2ENA (1 << 12)
++#define DWC3_DCTL_ACCEPTU2ENA (1 << 11)
++#define DWC3_DCTL_INITU1ENA (1 << 10)
++#define DWC3_DCTL_ACCEPTU1ENA (1 << 9)
++#define DWC3_DCTL_TSTCTRL_MASK (0xf << 1)
++
++#define DWC3_DCTL_ULSTCHNGREQ_MASK (0x0f << 5)
++#define DWC3_DCTL_ULSTCHNGREQ(n) (((n) << 5) & DWC3_DCTL_ULSTCHNGREQ_MASK)
++
++#define DWC3_DCTL_ULSTCHNG_NO_ACTION (DWC3_DCTL_ULSTCHNGREQ(0))
++#define DWC3_DCTL_ULSTCHNG_SS_DISABLED (DWC3_DCTL_ULSTCHNGREQ(4))
++#define DWC3_DCTL_ULSTCHNG_RX_DETECT (DWC3_DCTL_ULSTCHNGREQ(5))
++#define DWC3_DCTL_ULSTCHNG_SS_INACTIVE (DWC3_DCTL_ULSTCHNGREQ(6))
++#define DWC3_DCTL_ULSTCHNG_RECOVERY (DWC3_DCTL_ULSTCHNGREQ(8))
++#define DWC3_DCTL_ULSTCHNG_COMPLIANCE (DWC3_DCTL_ULSTCHNGREQ(10))
++#define DWC3_DCTL_ULSTCHNG_LOOPBACK (DWC3_DCTL_ULSTCHNGREQ(11))
++
++/* Device Event Enable Register */
++#define DWC3_DEVTEN_VNDRDEVTSTRCVEDEN (1 << 12)
++#define DWC3_DEVTEN_EVNTOVERFLOWEN (1 << 11)
++#define DWC3_DEVTEN_CMDCMPLTEN (1 << 10)
++#define DWC3_DEVTEN_ERRTICERREN (1 << 9)
++#define DWC3_DEVTEN_SOFEN (1 << 7)
++#define DWC3_DEVTEN_EOPFEN (1 << 6)
++#define DWC3_DEVTEN_WKUPEVTEN (1 << 4)
++#define DWC3_DEVTEN_ULSTCNGEN (1 << 3)
++#define DWC3_DEVTEN_CONNECTDONEEN (1 << 2)
++#define DWC3_DEVTEN_USBRSTEN (1 << 1)
++#define DWC3_DEVTEN_DISCONNEVTEN (1 << 0)
++
++/* Device Status Register */
++#define DWC3_DSTS_PWRUPREQ (1 << 24)
++#define DWC3_DSTS_COREIDLE (1 << 23)
++#define DWC3_DSTS_DEVCTRLHLT (1 << 22)
++
++#define DWC3_DSTS_USBLNKST_MASK (0x0f << 18)
++#define DWC3_DSTS_USBLNKST(n) (((n) & DWC3_DSTS_USBLNKST_MASK) >> 18)
++
++#define DWC3_DSTS_RXFIFOEMPTY (1 << 17)
++
++#define DWC3_DSTS_SOFFN_MASK (0x3ff << 3)
++#define DWC3_DSTS_SOFFN(n) (((n) & DWC3_DSTS_SOFFN_MASK) >> 3)
++
++#define DWC3_DSTS_CONNECTSPD (7 << 0)
++
++#define DWC3_DSTS_SUPERSPEED (4 << 0)
++#define DWC3_DSTS_HIGHSPEED (0 << 0)
++#define DWC3_DSTS_FULLSPEED2 (1 << 0)
++#define DWC3_DSTS_LOWSPEED (2 << 0)
++#define DWC3_DSTS_FULLSPEED1 (3 << 0)
++
++/* Device Generic Command Register */
++#define DWC3_DGCMD_SET_LMP 0x01
++#define DWC3_DGCMD_SET_PERIODIC_PAR 0x02
++#define DWC3_DGCMD_XMIT_FUNCTION 0x03
++#define DWC3_DGCMD_SELECTED_FIFO_FLUSH 0x09
++#define DWC3_DGCMD_ALL_FIFO_FLUSH 0x0a
++#define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c
++#define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK 0x10
++
++/* Device Endpoint Command Register */
++#define DWC3_DEPCMD_PARAM_SHIFT 16
++#define DWC3_DEPCMD_PARAM(x) (x << DWC3_DEPCMD_PARAM_SHIFT)
++#define DWC3_DEPCMD_GET_RSC_IDX(x) ((x >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
++#define DWC3_DEPCMD_STATUS_MASK (0x0f << 12)
++#define DWC3_DEPCMD_STATUS(x) ((x & DWC3_DEPCMD_STATUS_MASK) >> 12)
++#define DWC3_DEPCMD_HIPRI_FORCERM (1 << 11)
++#define DWC3_DEPCMD_CMDACT (1 << 10)
++#define DWC3_DEPCMD_CMDIOC (1 << 8)
++
++#define DWC3_DEPCMD_DEPSTARTCFG (0x09 << 0)
++#define DWC3_DEPCMD_ENDTRANSFER (0x08 << 0)
++#define DWC3_DEPCMD_UPDATETRANSFER (0x07 << 0)
++#define DWC3_DEPCMD_STARTTRANSFER (0x06 << 0)
++#define DWC3_DEPCMD_CLEARSTALL (0x05 << 0)
++#define DWC3_DEPCMD_SETSTALL (0x04 << 0)
++#define DWC3_DEPCMD_GETSEQNUMBER (0x03 << 0)
++#define DWC3_DEPCMD_SETTRANSFRESOURCE (0x02 << 0)
++#define DWC3_DEPCMD_SETEPCONFIG (0x01 << 0)
++
++/* The EP number goes 0..31 so ep0 is always out and ep1 is always in */
++#define DWC3_DALEPENA_EP(n) (1 << n)
++
++#define DWC3_DEPCMD_TYPE_CONTROL 0
++#define DWC3_DEPCMD_TYPE_ISOC 1
++#define DWC3_DEPCMD_TYPE_BULK 2
++#define DWC3_DEPCMD_TYPE_INTR 3
++
++/* Structures */
++
++struct dwc3_trb_hw;
++
++/**
++ * struct dwc3_event_buffer - Software event buffer representation
++ * @list: a list of event buffers
++ * @buf: _THE_ buffer
++ * @length: size of this buffer
++ * @dma: dma_addr_t
++ * @dwc: pointer to DWC controller
++ */
++struct dwc3_event_buffer {
++ void *buf;
++ unsigned length;
++ unsigned int lpos;
++
++ dma_addr_t dma;
++
++ struct dwc3 *dwc;
++};
++
++#define DWC3_EP_FLAG_STALLED (1 << 0)
++#define DWC3_EP_FLAG_WEDGED (1 << 1)
++
++#define DWC3_EP_DIRECTION_TX true
++#define DWC3_EP_DIRECTION_RX false
++
++#define DWC3_TRB_NUM 32
++#define DWC3_TRB_MASK (DWC3_TRB_NUM - 1)
++
++/**
++ * struct dwc3_ep - device side endpoint representation
++ * @endpoint: usb endpoint
++ * @request_list: list of requests for this endpoint
++ * @req_queued: list of requests on this ep which have TRBs setup
++ * @trb_pool: array of transaction buffers
++ * @trb_pool_dma: dma address of @trb_pool
++ * @free_slot: next slot which is going to be used
++ * @busy_slot: first slot which is owned by HW
++ * @desc: usb_endpoint_descriptor pointer
++ * @dwc: pointer to DWC controller
++ * @flags: endpoint flags (wedged, stalled, ...)
++ * @current_trb: index of current used trb
++ * @number: endpoint number (1 - 15)
++ * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
++ * @res_trans_idx: Resource transfer index
++ * @interval: the intervall on which the ISOC transfer is started
++ * @name: a human readable name e.g. ep1out-bulk
++ * @direction: true for TX, false for RX
++ * @stream_capable: true when streams are enabled
++ */
++struct dwc3_ep {
++ struct usb_ep endpoint;
++ struct list_head request_list;
++ struct list_head req_queued;
++
++ struct dwc3_trb_hw *trb_pool;
++ dma_addr_t trb_pool_dma;
++ u32 free_slot;
++ u32 busy_slot;
++ const struct usb_endpoint_descriptor *desc;
++ const struct usb_ss_ep_comp_descriptor *comp_desc;
++ struct dwc3 *dwc;
++
++ unsigned flags;
++#define DWC3_EP_ENABLED (1 << 0)
++#define DWC3_EP_STALL (1 << 1)
++#define DWC3_EP_WEDGE (1 << 2)
++#define DWC3_EP_BUSY (1 << 4)
++#define DWC3_EP_PENDING_REQUEST (1 << 5)
++
++ /* This last one is specific to EP0 */
++#define DWC3_EP0_DIR_IN (1 << 31)
++
++ unsigned current_trb;
++
++ u8 number;
++ u8 type;
++ u8 res_trans_idx;
++ u32 interval;
++
++ char name[20];
++
++ unsigned direction:1;
++ unsigned stream_capable:1;
++};
++
++enum dwc3_phy {
++ DWC3_PHY_UNKNOWN = 0,
++ DWC3_PHY_USB3,
++ DWC3_PHY_USB2,
++};
++
++enum dwc3_ep0_next {
++ DWC3_EP0_UNKNOWN = 0,
++ DWC3_EP0_COMPLETE,
++ DWC3_EP0_NRDY_SETUP,
++ DWC3_EP0_NRDY_DATA,
++ DWC3_EP0_NRDY_STATUS,
++};
++
++enum dwc3_ep0_state {
++ EP0_UNCONNECTED = 0,
++ EP0_SETUP_PHASE,
++ EP0_DATA_PHASE,
++ EP0_STATUS_PHASE,
++};
++
++enum dwc3_link_state {
++ /* In SuperSpeed */
++ DWC3_LINK_STATE_U0 = 0x00, /* in HS, means ON */
++ DWC3_LINK_STATE_U1 = 0x01,
++ DWC3_LINK_STATE_U2 = 0x02, /* in HS, means SLEEP */
++ DWC3_LINK_STATE_U3 = 0x03, /* in HS, means SUSPEND */
++ DWC3_LINK_STATE_SS_DIS = 0x04,
++ DWC3_LINK_STATE_RX_DET = 0x05, /* in HS, means Early Suspend */
++ DWC3_LINK_STATE_SS_INACT = 0x06,
++ DWC3_LINK_STATE_POLL = 0x07,
++ DWC3_LINK_STATE_RECOV = 0x08,
++ DWC3_LINK_STATE_HRESET = 0x09,
++ DWC3_LINK_STATE_CMPLY = 0x0a,
++ DWC3_LINK_STATE_LPBK = 0x0b,
++ DWC3_LINK_STATE_MASK = 0x0f,
++};
++
++enum dwc3_device_state {
++ DWC3_DEFAULT_STATE,
++ DWC3_ADDRESS_STATE,
++ DWC3_CONFIGURED_STATE,
++};
++
++/**
++ * struct dwc3_trb - transfer request block
++ * @bpl: lower 32bit of the buffer
++ * @bph: higher 32bit of the buffer
++ * @length: buffer size (up to 16mb - 1)
++ * @pcm1: packet count m1
++ * @trbsts: trb status
++ * 0 = ok
++ * 1 = missed isoc
++ * 2 = setup pending
++ * @hwo: hardware owner of descriptor
++ * @lst: last trb
++ * @chn: chain buffers
++ * @csp: continue on short packets (only supported on isoc eps)
++ * @trbctl: trb control
++ * 1 = normal
++ * 2 = control-setup
++ * 3 = control-status-2
++ * 4 = control-status-3
++ * 5 = control-data (first trb of data stage)
++ * 6 = isochronous-first (first trb of service interval)
++ * 7 = isochronous
++ * 8 = link trb
++ * others = reserved
++ * @isp_imi: interrupt on short packet / interrupt on missed isoc
++ * @ioc: interrupt on complete
++ * @sid_sofn: Stream ID / SOF Number
++ */
++struct dwc3_trb {
++ u64 bplh;
++
++ union {
++ struct {
++ u32 length:24;
++ u32 pcm1:2;
++ u32 reserved27_26:2;
++ u32 trbsts:4;
++#define DWC3_TRB_STS_OKAY 0
++#define DWC3_TRB_STS_MISSED_ISOC 1
++#define DWC3_TRB_STS_SETUP_PENDING 2
++ };
++ u32 len_pcm;
++ };
++
++ union {
++ struct {
++ u32 hwo:1;
++ u32 lst:1;
++ u32 chn:1;
++ u32 csp:1;
++ u32 trbctl:6;
++ u32 isp_imi:1;
++ u32 ioc:1;
++ u32 reserved13_12:2;
++ u32 sid_sofn:16;
++ u32 reserved31_30:2;
++ };
++ u32 control;
++ };
++} __packed;
++
++/**
++ * struct dwc3_trb_hw - transfer request block (hw format)
++ * @bpl: DW0-3
++ * @bph: DW4-7
++ * @size: DW8-B
++ * @trl: DWC-F
++ */
++struct dwc3_trb_hw {
++ __le32 bpl;
++ __le32 bph;
++ __le32 size;
++ __le32 ctrl;
++} __packed;
++
++static inline void dwc3_trb_to_hw(struct dwc3_trb *nat, struct dwc3_trb_hw *hw)
++{
++ hw->bpl = cpu_to_le32(lower_32_bits(nat->bplh));
++ hw->bph = cpu_to_le32(upper_32_bits(nat->bplh));
++ hw->size = cpu_to_le32p(&nat->len_pcm);
++ /* HWO is written last */
++ hw->ctrl = cpu_to_le32p(&nat->control);
++}
++
++static inline void dwc3_trb_to_nat(struct dwc3_trb_hw *hw, struct dwc3_trb *nat)
++{
++ u64 bplh;
++
++ bplh = le32_to_cpup(&hw->bpl);
++ bplh |= (u64) le32_to_cpup(&hw->bph) << 32;
++ nat->bplh = bplh;
++
++ nat->len_pcm = le32_to_cpup(&hw->size);
++ nat->control = le32_to_cpup(&hw->ctrl);
++}
++
++/**
++ * dwc3_hwparams - copy of HWPARAMS registers
++ * @hwparams0 - GHWPARAMS0
++ * @hwparams1 - GHWPARAMS1
++ * @hwparams2 - GHWPARAMS2
++ * @hwparams3 - GHWPARAMS3
++ * @hwparams4 - GHWPARAMS4
++ * @hwparams5 - GHWPARAMS5
++ * @hwparams6 - GHWPARAMS6
++ * @hwparams7 - GHWPARAMS7
++ * @hwparams8 - GHWPARAMS8
++ */
++struct dwc3_hwparams {
++ u32 hwparams0;
++ u32 hwparams1;
++ u32 hwparams2;
++ u32 hwparams3;
++ u32 hwparams4;
++ u32 hwparams5;
++ u32 hwparams6;
++ u32 hwparams7;
++ u32 hwparams8;
++};
++
++/* HWPARAMS0 */
++#define DWC3_MODE(n) ((n) & 0x7)
++
++#define DWC3_MODE_DEVICE 0
++#define DWC3_MODE_HOST 1
++#define DWC3_MODE_DRD 2
++#define DWC3_MODE_HUB 3
++
++/* HWPARAMS1 */
++#define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15)
++
++struct dwc3_request {
++ struct usb_request request;
++ struct list_head list;
++ struct dwc3_ep *dep;
++
++ u8 epnum;
++ struct dwc3_trb_hw *trb;
++ dma_addr_t trb_dma;
++
++ unsigned direction:1;
++ unsigned mapped:1;
++ unsigned queued:1;
++};
++
++/**
++ * struct dwc3 - representation of our controller
++ * @ctrl_req: usb control request which is used for ep0
++ * @ep0_trb: trb which is used for the ctrl_req
++ * @ep0_bounce: bounce buffer for ep0
++ * @setup_buf: used while precessing STD USB requests
++ * @ctrl_req_addr: dma address of ctrl_req
++ * @ep0_trb: dma address of ep0_trb
++ * @ep0_usb_req: dummy req used while handling STD USB requests
++ * @setup_buf_addr: dma address of setup_buf
++ * @ep0_bounce_addr: dma address of ep0_bounce
++ * @lock: for synchronizing
++ * @dev: pointer to our struct device
++ * @xhci: pointer to our xHCI child
++ * @event_buffer_list: a list of event buffers
++ * @gadget: device side representation of the peripheral controller
++ * @gadget_driver: pointer to the gadget driver
++ * @regs: base address for our registers
++ * @regs_size: address space size
++ * @irq: IRQ number
++ * @num_event_buffers: calculated number of event buffers
++ * @u1u2: only used on revisions <1.83a for workaround
++ * @maximum_speed: maximum speed requested (mainly for testing purposes)
++ * @revision: revision register contents
++ * @mode: mode of operation
++ * @is_selfpowered: true when we are selfpowered
++ * @three_stage_setup: set if we perform a three phase setup
++ * @ep0_bounced: true when we used bounce buffer
++ * @ep0_expect_in: true when we expect a DATA IN transfer
++ * @start_config_issued: true when StartConfig command has been issued
++ * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
++ * @ep0_next_event: hold the next expected event
++ * @ep0state: state of endpoint zero
++ * @link_state: link state
++ * @speed: device speed (super, high, full, low)
++ * @mem: points to start of memory which is used for this struct.
++ * @hwparams: copy of hwparams registers
++ * @root: debugfs root folder pointer
++ */
++struct dwc3 {
++ struct usb_ctrlrequest *ctrl_req;
++ struct dwc3_trb_hw *ep0_trb;
++ void *ep0_bounce;
++ u8 *setup_buf;
++ dma_addr_t ctrl_req_addr;
++ dma_addr_t ep0_trb_addr;
++ dma_addr_t setup_buf_addr;
++ dma_addr_t ep0_bounce_addr;
++ struct dwc3_request ep0_usb_req;
++ /* device lock */
++ spinlock_t lock;
++ struct device *dev;
++
++ struct platform_device *xhci;
++ struct resource *res;
++
++ struct dwc3_event_buffer **ev_buffs;
++ struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM];
++
++ struct usb_gadget gadget;
++ struct usb_gadget_driver *gadget_driver;
++
++ void __iomem *regs;
++ size_t regs_size;
++
++ int irq;
++
++ u32 num_event_buffers;
++ u32 u1u2;
++ u32 maximum_speed;
++ u32 revision;
++ u32 mode;
++
++#define DWC3_REVISION_173A 0x5533173a
++#define DWC3_REVISION_175A 0x5533175a
++#define DWC3_REVISION_180A 0x5533180a
++#define DWC3_REVISION_183A 0x5533183a
++#define DWC3_REVISION_185A 0x5533185a
++#define DWC3_REVISION_188A 0x5533188a
++#define DWC3_REVISION_190A 0x5533190a
++
++ unsigned is_selfpowered:1;
++ unsigned three_stage_setup:1;
++ unsigned ep0_bounced:1;
++ unsigned ep0_expect_in:1;
++ unsigned start_config_issued:1;
++ unsigned setup_packet_pending:1;
++ unsigned delayed_status:1;
++
++ enum dwc3_ep0_next ep0_next_event;
++ enum dwc3_ep0_state ep0state;
++ enum dwc3_link_state link_state;
++ enum dwc3_device_state dev_state;
++
++ u8 speed;
++ void *mem;
++
++ struct dwc3_hwparams hwparams;
++ struct dentry *root;
++};
++
++/* -------------------------------------------------------------------------- */
++
++#define DWC3_TRBSTS_OK 0
++#define DWC3_TRBSTS_MISSED_ISOC 1
++#define DWC3_TRBSTS_SETUP_PENDING 2
++
++#define DWC3_TRBCTL_NORMAL 1
++#define DWC3_TRBCTL_CONTROL_SETUP 2
++#define DWC3_TRBCTL_CONTROL_STATUS2 3
++#define DWC3_TRBCTL_CONTROL_STATUS3 4
++#define DWC3_TRBCTL_CONTROL_DATA 5
++#define DWC3_TRBCTL_ISOCHRONOUS_FIRST 6
++#define DWC3_TRBCTL_ISOCHRONOUS 7
++#define DWC3_TRBCTL_LINK_TRB 8
++
++/* -------------------------------------------------------------------------- */
++
++struct dwc3_event_type {
++ u32 is_devspec:1;
++ u32 type:6;
++ u32 reserved8_31:25;
++} __packed;
++
++#define DWC3_DEPEVT_XFERCOMPLETE 0x01
++#define DWC3_DEPEVT_XFERINPROGRESS 0x02
++#define DWC3_DEPEVT_XFERNOTREADY 0x03
++#define DWC3_DEPEVT_RXTXFIFOEVT 0x04
++#define DWC3_DEPEVT_STREAMEVT 0x06
++#define DWC3_DEPEVT_EPCMDCMPLT 0x07
++
++/**
++ * struct dwc3_event_depvt - Device Endpoint Events
++ * @one_bit: indicates this is an endpoint event (not used)
++ * @endpoint_number: number of the endpoint
++ * @endpoint_event: The event we have:
++ * 0x00 - Reserved
++ * 0x01 - XferComplete
++ * 0x02 - XferInProgress
++ * 0x03 - XferNotReady
++ * 0x04 - RxTxFifoEvt (IN->Underrun, OUT->Overrun)
++ * 0x05 - Reserved
++ * 0x06 - StreamEvt
++ * 0x07 - EPCmdCmplt
++ * @reserved11_10: Reserved, don't use.
++ * @status: Indicates the status of the event. Refer to databook for
++ * more information.
++ * @parameters: Parameters of the current event. Refer to databook for
++ * more information.
++ */
++struct dwc3_event_depevt {
++ u32 one_bit:1;
++ u32 endpoint_number:5;
++ u32 endpoint_event:4;
++ u32 reserved11_10:2;
++ u32 status:4;
++#define DEPEVT_STATUS_BUSERR (1 << 0)
++#define DEPEVT_STATUS_SHORT (1 << 1)
++#define DEPEVT_STATUS_IOC (1 << 2)
++#define DEPEVT_STATUS_LST (1 << 3)
++
++/* Stream event only */
++#define DEPEVT_STREAMEVT_FOUND 1
++#define DEPEVT_STREAMEVT_NOTFOUND 2
++
++/* Control-only Status */
++#define DEPEVT_STATUS_CONTROL_SETUP 0
++#define DEPEVT_STATUS_CONTROL_DATA 1
++#define DEPEVT_STATUS_CONTROL_STATUS 2
++
++ u32 parameters:16;
++} __packed;
++
++/**
++ * struct dwc3_event_devt - Device Events
++ * @one_bit: indicates this is a non-endpoint event (not used)
++ * @device_event: indicates it's a device event. Should read as 0x00
++ * @type: indicates the type of device event.
++ * 0 - DisconnEvt
++ * 1 - USBRst
++ * 2 - ConnectDone
++ * 3 - ULStChng
++ * 4 - WkUpEvt
++ * 5 - Reserved
++ * 6 - EOPF
++ * 7 - SOF
++ * 8 - Reserved
++ * 9 - ErrticErr
++ * 10 - CmdCmplt
++ * 11 - EvntOverflow
++ * 12 - VndrDevTstRcved
++ * @reserved15_12: Reserved, not used
++ * @event_info: Information about this event
++ * @reserved31_24: Reserved, not used
++ */
++struct dwc3_event_devt {
++ u32 one_bit:1;
++ u32 device_event:7;
++ u32 type:4;
++ u32 reserved15_12:4;
++ u32 event_info:8;
++ u32 reserved31_24:8;
++} __packed;
++
++/**
++ * struct dwc3_event_gevt - Other Core Events
++ * @one_bit: indicates this is a non-endpoint event (not used)
++ * @device_event: indicates it's (0x03) Carkit or (0x04) I2C event.
++ * @phy_port_number: self-explanatory
++ * @reserved31_12: Reserved, not used.
++ */
++struct dwc3_event_gevt {
++ u32 one_bit:1;
++ u32 device_event:7;
++ u32 phy_port_number:4;
++ u32 reserved31_12:20;
++} __packed;
++
++/**
++ * union dwc3_event - representation of Event Buffer contents
++ * @raw: raw 32-bit event
++ * @type: the type of the event
++ * @depevt: Device Endpoint Event
++ * @devt: Device Event
++ * @gevt: Global Event
++ */
++union dwc3_event {
++ u32 raw;
++ struct dwc3_event_type type;
++ struct dwc3_event_depevt depevt;
++ struct dwc3_event_devt devt;
++ struct dwc3_event_gevt gevt;
++};
++
++/*
++ * DWC3 Features to be used as Driver Data
++ */
++
++#define DWC3_HAS_PERIPHERAL BIT(0)
++#define DWC3_HAS_XHCI BIT(1)
++#define DWC3_HAS_OTG BIT(3)
++
++/* prototypes */
++void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
++
++int dwc3_host_init(struct dwc3 *dwc);
++static inline void dwc3_host_exit(struct dwc3 *dwc) {}
++
++int dwc3_gadget_init(struct dwc3 *dwc);
++void dwc3_gadget_exit(struct dwc3 *dwc);
++
++extern int dwc3_get_device_id(void);
++extern void dwc3_put_device_id(int id);
++
++#endif /* __DRIVERS_USB_DWC3_CORE_H */
+diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h
+new file mode 100644
+index 0000000..52d0227
+--- /dev/null
++++ b/drivers/usb/dwc3/debug.h
+@@ -0,0 +1,49 @@
++/**
++ * debug.h - DesignWare USB3 DRD Controller Debug Header
++ *
++ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
++ *
++ * Authors: Felipe Balbi <balbi@ti.com>,
++ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "core.h"
++
++#ifdef CONFIG_DEBUG_FS
++extern int dwc3_debugfs_init(struct dwc3 *);
++extern void dwc3_debugfs_exit(struct dwc3 *);
++#else
++static inline int dwc3_debugfs_init(struct dwc3 *d)
++{ return 0; }
++static inline void dwc3_debugfs_exit(struct dwc3 *d)
++{ }
++#endif
+diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
+new file mode 100644
+index 0000000..97b2c40
+--- /dev/null
++++ b/drivers/usb/dwc3/debugfs.c
+@@ -0,0 +1,521 @@
++/**
++ * debugfs.c - DesignWare USB3 DRD Controller DebugFS file
++ *
++ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
++ *
++ * Authors: Felipe Balbi <balbi@ti.com>,
++ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <common.h>
++#ifdef CONFIG_DWC3_off
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/ptrace.h>
++#include <linux/types.h>
++#include <linux/spinlock.h>
++#include <linux/debugfs.h>
++#include <linux/seq_file.h>
++#include <linux/delay.h>
++#include <linux/uaccess.h>
++
++#include "core.h"
++#include "gadget.h"
++#include "io.h"
++#include "debug.h"
++
++struct dwc3_register {
++ const char *name;
++ u32 offset;
++};
++
++#define dump_register(nm) \
++{ \
++ .name = __stringify(nm), \
++ .offset = DWC3_ ##nm, \
++}
++
++static const struct dwc3_register dwc3_regs[] = {
++ dump_register(GSBUSCFG0),
++ dump_register(GSBUSCFG1),
++ dump_register(GTXTHRCFG),
++ dump_register(GRXTHRCFG),
++ dump_register(GCTL),
++ dump_register(GEVTEN),
++ dump_register(GSTS),
++ dump_register(GSNPSID),
++ dump_register(GGPIO),
++ dump_register(GUID),
++ dump_register(GUCTL),
++ dump_register(GBUSERRADDR0),
++ dump_register(GBUSERRADDR1),
++ dump_register(GPRTBIMAP0),
++ dump_register(GPRTBIMAP1),
++ dump_register(GHWPARAMS0),
++ dump_register(GHWPARAMS1),
++ dump_register(GHWPARAMS2),
++ dump_register(GHWPARAMS3),
++ dump_register(GHWPARAMS4),
++ dump_register(GHWPARAMS5),
++ dump_register(GHWPARAMS6),
++ dump_register(GHWPARAMS7),
++ dump_register(GDBGFIFOSPACE),
++ dump_register(GDBGLTSSM),
++ dump_register(GPRTBIMAP_HS0),
++ dump_register(GPRTBIMAP_HS1),
++ dump_register(GPRTBIMAP_FS0),
++ dump_register(GPRTBIMAP_FS1),
++
++ dump_register(GUSB2PHYCFG(0)),
++ dump_register(GUSB2PHYCFG(1)),
++ dump_register(GUSB2PHYCFG(2)),
++ dump_register(GUSB2PHYCFG(3)),
++ dump_register(GUSB2PHYCFG(4)),
++ dump_register(GUSB2PHYCFG(5)),
++ dump_register(GUSB2PHYCFG(6)),
++ dump_register(GUSB2PHYCFG(7)),
++ dump_register(GUSB2PHYCFG(8)),
++ dump_register(GUSB2PHYCFG(9)),
++ dump_register(GUSB2PHYCFG(10)),
++ dump_register(GUSB2PHYCFG(11)),
++ dump_register(GUSB2PHYCFG(12)),
++ dump_register(GUSB2PHYCFG(13)),
++ dump_register(GUSB2PHYCFG(14)),
++ dump_register(GUSB2PHYCFG(15)),
++
++ dump_register(GUSB2I2CCTL(0)),
++ dump_register(GUSB2I2CCTL(1)),
++ dump_register(GUSB2I2CCTL(2)),
++ dump_register(GUSB2I2CCTL(3)),
++ dump_register(GUSB2I2CCTL(4)),
++ dump_register(GUSB2I2CCTL(5)),
++ dump_register(GUSB2I2CCTL(6)),
++ dump_register(GUSB2I2CCTL(7)),
++ dump_register(GUSB2I2CCTL(8)),
++ dump_register(GUSB2I2CCTL(9)),
++ dump_register(GUSB2I2CCTL(10)),
++ dump_register(GUSB2I2CCTL(11)),
++ dump_register(GUSB2I2CCTL(12)),
++ dump_register(GUSB2I2CCTL(13)),
++ dump_register(GUSB2I2CCTL(14)),
++ dump_register(GUSB2I2CCTL(15)),
++
++ dump_register(GUSB2PHYACC(0)),
++ dump_register(GUSB2PHYACC(1)),
++ dump_register(GUSB2PHYACC(2)),
++ dump_register(GUSB2PHYACC(3)),
++ dump_register(GUSB2PHYACC(4)),
++ dump_register(GUSB2PHYACC(5)),
++ dump_register(GUSB2PHYACC(6)),
++ dump_register(GUSB2PHYACC(7)),
++ dump_register(GUSB2PHYACC(8)),
++ dump_register(GUSB2PHYACC(9)),
++ dump_register(GUSB2PHYACC(10)),
++ dump_register(GUSB2PHYACC(11)),
++ dump_register(GUSB2PHYACC(12)),
++ dump_register(GUSB2PHYACC(13)),
++ dump_register(GUSB2PHYACC(14)),
++ dump_register(GUSB2PHYACC(15)),
++
++ dump_register(GUSB3PIPECTL(0)),
++ dump_register(GUSB3PIPECTL(1)),
++ dump_register(GUSB3PIPECTL(2)),
++ dump_register(GUSB3PIPECTL(3)),
++ dump_register(GUSB3PIPECTL(4)),
++ dump_register(GUSB3PIPECTL(5)),
++ dump_register(GUSB3PIPECTL(6)),
++ dump_register(GUSB3PIPECTL(7)),
++ dump_register(GUSB3PIPECTL(8)),
++ dump_register(GUSB3PIPECTL(9)),
++ dump_register(GUSB3PIPECTL(10)),
++ dump_register(GUSB3PIPECTL(11)),
++ dump_register(GUSB3PIPECTL(12)),
++ dump_register(GUSB3PIPECTL(13)),
++ dump_register(GUSB3PIPECTL(14)),
++ dump_register(GUSB3PIPECTL(15)),
++
++ dump_register(GTXFIFOSIZ(0)),
++ dump_register(GTXFIFOSIZ(1)),
++ dump_register(GTXFIFOSIZ(2)),
++ dump_register(GTXFIFOSIZ(3)),
++ dump_register(GTXFIFOSIZ(4)),
++ dump_register(GTXFIFOSIZ(5)),
++ dump_register(GTXFIFOSIZ(6)),
++ dump_register(GTXFIFOSIZ(7)),
++ dump_register(GTXFIFOSIZ(8)),
++ dump_register(GTXFIFOSIZ(9)),
++ dump_register(GTXFIFOSIZ(10)),
++ dump_register(GTXFIFOSIZ(11)),
++ dump_register(GTXFIFOSIZ(12)),
++ dump_register(GTXFIFOSIZ(13)),
++ dump_register(GTXFIFOSIZ(14)),
++ dump_register(GTXFIFOSIZ(15)),
++ dump_register(GTXFIFOSIZ(16)),
++ dump_register(GTXFIFOSIZ(17)),
++ dump_register(GTXFIFOSIZ(18)),
++ dump_register(GTXFIFOSIZ(19)),
++ dump_register(GTXFIFOSIZ(20)),
++ dump_register(GTXFIFOSIZ(21)),
++ dump_register(GTXFIFOSIZ(22)),
++ dump_register(GTXFIFOSIZ(23)),
++ dump_register(GTXFIFOSIZ(24)),
++ dump_register(GTXFIFOSIZ(25)),
++ dump_register(GTXFIFOSIZ(26)),
++ dump_register(GTXFIFOSIZ(27)),
++ dump_register(GTXFIFOSIZ(28)),
++ dump_register(GTXFIFOSIZ(29)),
++ dump_register(GTXFIFOSIZ(30)),
++ dump_register(GTXFIFOSIZ(31)),
++
++ dump_register(GRXFIFOSIZ(0)),
++ dump_register(GRXFIFOSIZ(1)),
++ dump_register(GRXFIFOSIZ(2)),
++ dump_register(GRXFIFOSIZ(3)),
++ dump_register(GRXFIFOSIZ(4)),
++ dump_register(GRXFIFOSIZ(5)),
++ dump_register(GRXFIFOSIZ(6)),
++ dump_register(GRXFIFOSIZ(7)),
++ dump_register(GRXFIFOSIZ(8)),
++ dump_register(GRXFIFOSIZ(9)),
++ dump_register(GRXFIFOSIZ(10)),
++ dump_register(GRXFIFOSIZ(11)),
++ dump_register(GRXFIFOSIZ(12)),
++ dump_register(GRXFIFOSIZ(13)),
++ dump_register(GRXFIFOSIZ(14)),
++ dump_register(GRXFIFOSIZ(15)),
++ dump_register(GRXFIFOSIZ(16)),
++ dump_register(GRXFIFOSIZ(17)),
++ dump_register(GRXFIFOSIZ(18)),
++ dump_register(GRXFIFOSIZ(19)),
++ dump_register(GRXFIFOSIZ(20)),
++ dump_register(GRXFIFOSIZ(21)),
++ dump_register(GRXFIFOSIZ(22)),
++ dump_register(GRXFIFOSIZ(23)),
++ dump_register(GRXFIFOSIZ(24)),
++ dump_register(GRXFIFOSIZ(25)),
++ dump_register(GRXFIFOSIZ(26)),
++ dump_register(GRXFIFOSIZ(27)),
++ dump_register(GRXFIFOSIZ(28)),
++ dump_register(GRXFIFOSIZ(29)),
++ dump_register(GRXFIFOSIZ(30)),
++ dump_register(GRXFIFOSIZ(31)),
++
++ dump_register(GEVNTADRLO(0)),
++ dump_register(GEVNTADRHI(0)),
++ dump_register(GEVNTSIZ(0)),
++ dump_register(GEVNTCOUNT(0)),
++
++ dump_register(GHWPARAMS8),
++ dump_register(DCFG),
++ dump_register(DCTL),
++ dump_register(DEVTEN),
++ dump_register(DSTS),
++ dump_register(DGCMDPAR),
++ dump_register(DGCMD),
++ dump_register(DALEPENA),
++
++ dump_register(DEPCMDPAR2(0)),
++ dump_register(DEPCMDPAR2(1)),
++ dump_register(DEPCMDPAR2(2)),
++ dump_register(DEPCMDPAR2(3)),
++ dump_register(DEPCMDPAR2(4)),
++ dump_register(DEPCMDPAR2(5)),
++ dump_register(DEPCMDPAR2(6)),
++ dump_register(DEPCMDPAR2(7)),
++ dump_register(DEPCMDPAR2(8)),
++ dump_register(DEPCMDPAR2(9)),
++ dump_register(DEPCMDPAR2(10)),
++ dump_register(DEPCMDPAR2(11)),
++ dump_register(DEPCMDPAR2(12)),
++ dump_register(DEPCMDPAR2(13)),
++ dump_register(DEPCMDPAR2(14)),
++ dump_register(DEPCMDPAR2(15)),
++ dump_register(DEPCMDPAR2(16)),
++ dump_register(DEPCMDPAR2(17)),
++ dump_register(DEPCMDPAR2(18)),
++ dump_register(DEPCMDPAR2(19)),
++ dump_register(DEPCMDPAR2(20)),
++ dump_register(DEPCMDPAR2(21)),
++ dump_register(DEPCMDPAR2(22)),
++ dump_register(DEPCMDPAR2(23)),
++ dump_register(DEPCMDPAR2(24)),
++ dump_register(DEPCMDPAR2(25)),
++ dump_register(DEPCMDPAR2(26)),
++ dump_register(DEPCMDPAR2(27)),
++ dump_register(DEPCMDPAR2(28)),
++ dump_register(DEPCMDPAR2(29)),
++ dump_register(DEPCMDPAR2(30)),
++ dump_register(DEPCMDPAR2(31)),
++
++ dump_register(DEPCMDPAR1(0)),
++ dump_register(DEPCMDPAR1(1)),
++ dump_register(DEPCMDPAR1(2)),
++ dump_register(DEPCMDPAR1(3)),
++ dump_register(DEPCMDPAR1(4)),
++ dump_register(DEPCMDPAR1(5)),
++ dump_register(DEPCMDPAR1(6)),
++ dump_register(DEPCMDPAR1(7)),
++ dump_register(DEPCMDPAR1(8)),
++ dump_register(DEPCMDPAR1(9)),
++ dump_register(DEPCMDPAR1(10)),
++ dump_register(DEPCMDPAR1(11)),
++ dump_register(DEPCMDPAR1(12)),
++ dump_register(DEPCMDPAR1(13)),
++ dump_register(DEPCMDPAR1(14)),
++ dump_register(DEPCMDPAR1(15)),
++ dump_register(DEPCMDPAR1(16)),
++ dump_register(DEPCMDPAR1(17)),
++ dump_register(DEPCMDPAR1(18)),
++ dump_register(DEPCMDPAR1(19)),
++ dump_register(DEPCMDPAR1(20)),
++ dump_register(DEPCMDPAR1(21)),
++ dump_register(DEPCMDPAR1(22)),
++ dump_register(DEPCMDPAR1(23)),
++ dump_register(DEPCMDPAR1(24)),
++ dump_register(DEPCMDPAR1(25)),
++ dump_register(DEPCMDPAR1(26)),
++ dump_register(DEPCMDPAR1(27)),
++ dump_register(DEPCMDPAR1(28)),
++ dump_register(DEPCMDPAR1(29)),
++ dump_register(DEPCMDPAR1(30)),
++ dump_register(DEPCMDPAR1(31)),
++
++ dump_register(DEPCMDPAR0(0)),
++ dump_register(DEPCMDPAR0(1)),
++ dump_register(DEPCMDPAR0(2)),
++ dump_register(DEPCMDPAR0(3)),
++ dump_register(DEPCMDPAR0(4)),
++ dump_register(DEPCMDPAR0(5)),
++ dump_register(DEPCMDPAR0(6)),
++ dump_register(DEPCMDPAR0(7)),
++ dump_register(DEPCMDPAR0(8)),
++ dump_register(DEPCMDPAR0(9)),
++ dump_register(DEPCMDPAR0(10)),
++ dump_register(DEPCMDPAR0(11)),
++ dump_register(DEPCMDPAR0(12)),
++ dump_register(DEPCMDPAR0(13)),
++ dump_register(DEPCMDPAR0(14)),
++ dump_register(DEPCMDPAR0(15)),
++ dump_register(DEPCMDPAR0(16)),
++ dump_register(DEPCMDPAR0(17)),
++ dump_register(DEPCMDPAR0(18)),
++ dump_register(DEPCMDPAR0(19)),
++ dump_register(DEPCMDPAR0(20)),
++ dump_register(DEPCMDPAR0(21)),
++ dump_register(DEPCMDPAR0(22)),
++ dump_register(DEPCMDPAR0(23)),
++ dump_register(DEPCMDPAR0(24)),
++ dump_register(DEPCMDPAR0(25)),
++ dump_register(DEPCMDPAR0(26)),
++ dump_register(DEPCMDPAR0(27)),
++ dump_register(DEPCMDPAR0(28)),
++ dump_register(DEPCMDPAR0(29)),
++ dump_register(DEPCMDPAR0(30)),
++ dump_register(DEPCMDPAR0(31)),
++
++ dump_register(DEPCMD(0)),
++ dump_register(DEPCMD(1)),
++ dump_register(DEPCMD(2)),
++ dump_register(DEPCMD(3)),
++ dump_register(DEPCMD(4)),
++ dump_register(DEPCMD(5)),
++ dump_register(DEPCMD(6)),
++ dump_register(DEPCMD(7)),
++ dump_register(DEPCMD(8)),
++ dump_register(DEPCMD(9)),
++ dump_register(DEPCMD(10)),
++ dump_register(DEPCMD(11)),
++ dump_register(DEPCMD(12)),
++ dump_register(DEPCMD(13)),
++ dump_register(DEPCMD(14)),
++ dump_register(DEPCMD(15)),
++ dump_register(DEPCMD(16)),
++ dump_register(DEPCMD(17)),
++ dump_register(DEPCMD(18)),
++ dump_register(DEPCMD(19)),
++ dump_register(DEPCMD(20)),
++ dump_register(DEPCMD(21)),
++ dump_register(DEPCMD(22)),
++ dump_register(DEPCMD(23)),
++ dump_register(DEPCMD(24)),
++ dump_register(DEPCMD(25)),
++ dump_register(DEPCMD(26)),
++ dump_register(DEPCMD(27)),
++ dump_register(DEPCMD(28)),
++ dump_register(DEPCMD(29)),
++ dump_register(DEPCMD(30)),
++ dump_register(DEPCMD(31)),
++
++ dump_register(OCFG),
++ dump_register(OCTL),
++ dump_register(OEVTEN),
++ dump_register(OSTS),
++};
++
++static int dwc3_regdump_show(struct seq_file *s, void *unused)
++{
++ struct dwc3 *dwc = s->private;
++ int i;
++
++ seq_printf(s, "DesignWare USB3 Core Register Dump\n");
++
++ for (i = 0; i < ARRAY_SIZE(dwc3_regs); i++) {
++ seq_printf(s, "%-20s : %08x\n", dwc3_regs[i].name,
++ dwc3_readl(dwc->regs, dwc3_regs[i].offset));
++ }
++
++ return 0;
++}
++
++static int dwc3_regdump_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, dwc3_regdump_show, inode->i_private);
++}
++
++static const struct file_operations dwc3_regdump_fops = {
++ .open = dwc3_regdump_open,
++ .read = seq_read,
++ .release = single_release,
++};
++
++static int dwc3_mode_show(struct seq_file *s, void *unused)
++{
++ struct dwc3 *dwc = s->private;
++ unsigned long flags;
++ u32 reg;
++
++ spin_lock_irqsave(&dwc->lock, flags);
++ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
++ spin_unlock_irqrestore(&dwc->lock, flags);
++
++ switch (DWC3_GCTL_PRTCAP(reg)) {
++ case DWC3_GCTL_PRTCAP_HOST:
++ seq_printf(s, "host\n");
++ break;
++ case DWC3_GCTL_PRTCAP_DEVICE:
++ seq_printf(s, "device\n");
++ break;
++ case DWC3_GCTL_PRTCAP_OTG:
++ seq_printf(s, "OTG\n");
++ break;
++ default:
++ seq_printf(s, "UNKNOWN %08x\n", DWC3_GCTL_PRTCAP(reg));
++ }
++
++ return 0;
++}
++
++static int dwc3_mode_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, dwc3_mode_show, inode->i_private);
++}
++
++static ssize_t dwc3_mode_write(struct file *file,
++ const char __user *ubuf, size_t count, loff_t *ppos)
++{
++ struct seq_file *s = file->private_data;
++ struct dwc3 *dwc = s->private;
++ unsigned long flags;
++ u32 mode = 0;
++ char buf[32];
++
++ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
++ return -EFAULT;
++
++ if (!strncmp(buf, "host", 4))
++ mode |= DWC3_GCTL_PRTCAP_HOST;
++
++ if (!strncmp(buf, "device", 6))
++ mode |= DWC3_GCTL_PRTCAP_DEVICE;
++
++ if (!strncmp(buf, "otg", 3))
++ mode |= DWC3_GCTL_PRTCAP_OTG;
++
++ if (mode) {
++ spin_lock_irqsave(&dwc->lock, flags);
++ dwc3_set_mode(dwc, mode);
++ spin_unlock_irqrestore(&dwc->lock, flags);
++ }
++ return count;
++}
++
++static const struct file_operations dwc3_mode_fops = {
++ .open = dwc3_mode_open,
++ .write = dwc3_mode_write,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
++{
++ struct dentry *root;
++ struct dentry *file;
++ int ret;
++
++ root = debugfs_create_dir(dev_name(dwc->dev), NULL);
++ if (IS_ERR(root)) {
++ ret = PTR_ERR(root);
++ goto err0;
++ }
++
++ dwc->root = root;
++
++ file = debugfs_create_file("regdump", S_IRUGO, root, dwc,
++ &dwc3_regdump_fops);
++ if (IS_ERR(file)) {
++ ret = PTR_ERR(file);
++ goto err1;
++ }
++
++ file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
++ dwc, &dwc3_mode_fops);
++ if (IS_ERR(file)) {
++ ret = PTR_ERR(file);
++ goto err1;
++ }
++
++ return 0;
++
++err1:
++ debugfs_remove_recursive(root);
++
++err0:
++ return ret;
++}
++
++void __devexit dwc3_debugfs_exit(struct dwc3 *dwc)
++{
++ debugfs_remove_recursive(dwc->root);
++ dwc->root = NULL;
++}
++#endif
+diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
+new file mode 100644
+index 0000000..11307c2
+--- /dev/null
++++ b/drivers/usb/dwc3/dwc3-omap.c
+@@ -0,0 +1,418 @@
++/**
++ * dwc3-omap.c - OMAP Specific Glue layer
++ *
++ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
++ *
++ * Authors: Felipe Balbi <balbi@ti.com>,
++ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <common.h>
++#ifdef CONFIG_DWC3_off
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <linux/platform_device.h>
++#include <linux/platform_data/dwc3-omap.h>
++#include <linux/dma-mapping.h>
++#include <linux/ioport.h>
++#include <linux/io.h>
++#include <linux/module.h>
++
++#include "core.h"
++#include "io.h"
++
++/*
++ * All these registers belong to OMAP's Wrapper around the
++ * DesignWare USB3 Core.
++ */
++
++#define USBOTGSS_REVISION 0x0000
++#define USBOTGSS_SYSCONFIG 0x0010
++#define USBOTGSS_IRQ_EOI 0x0020
++#define USBOTGSS_IRQSTATUS_RAW_0 0x0024
++#define USBOTGSS_IRQSTATUS_0 0x0028
++#define USBOTGSS_IRQENABLE_SET_0 0x002c
++#define USBOTGSS_IRQENABLE_CLR_0 0x0030
++#define USBOTGSS_IRQSTATUS_RAW_1 0x0034
++#define USBOTGSS_IRQSTATUS_1 0x0038
++#define USBOTGSS_IRQENABLE_SET_1 0x003c
++#define USBOTGSS_IRQENABLE_CLR_1 0x0040
++#define USBOTGSS_UTMI_OTG_CTRL 0x0080
++#define USBOTGSS_UTMI_OTG_STATUS 0x0084
++#define USBOTGSS_MMRAM_OFFSET 0x0100
++#define USBOTGSS_FLADJ 0x0104
++#define USBOTGSS_DEBUG_CFG 0x0108
++#define USBOTGSS_DEBUG_DATA 0x010c
++
++/* SYSCONFIG REGISTER */
++#define USBOTGSS_SYSCONFIG_DMADISABLE (1 << 16)
++#define USBOTGSS_SYSCONFIG_STANDBYMODE(x) ((x) << 4)
++
++#define USBOTGSS_STANDBYMODE_FORCE_STANDBY 0
++#define USBOTGSS_STANDBYMODE_NO_STANDBY 1
++#define USBOTGSS_STANDBYMODE_SMART_STANDBY 2
++#define USBOTGSS_STANDBYMODE_SMART_WAKEUP 3
++
++#define USBOTGSS_STANDBYMODE_MASK (0x03 << 4)
++
++#define USBOTGSS_SYSCONFIG_IDLEMODE(x) ((x) << 2)
++
++#define USBOTGSS_IDLEMODE_FORCE_IDLE 0
++#define USBOTGSS_IDLEMODE_NO_IDLE 1
++#define USBOTGSS_IDLEMODE_SMART_IDLE 2
++#define USBOTGSS_IDLEMODE_SMART_WAKEUP 3
++
++#define USBOTGSS_IDLEMODE_MASK (0x03 << 2)
++
++/* IRQ_EOI REGISTER */
++#define USBOTGSS_IRQ_EOI_LINE_NUMBER (1 << 0)
++
++/* IRQS0 BITS */
++#define USBOTGSS_IRQO_COREIRQ_ST (1 << 0)
++
++/* IRQ1 BITS */
++#define USBOTGSS_IRQ1_DMADISABLECLR (1 << 17)
++#define USBOTGSS_IRQ1_OEVT (1 << 16)
++#define USBOTGSS_IRQ1_DRVVBUS_RISE (1 << 13)
++#define USBOTGSS_IRQ1_CHRGVBUS_RISE (1 << 12)
++#define USBOTGSS_IRQ1_DISCHRGVBUS_RISE (1 << 11)
++#define USBOTGSS_IRQ1_IDPULLUP_RISE (1 << 8)
++#define USBOTGSS_IRQ1_DRVVBUS_FALL (1 << 5)
++#define USBOTGSS_IRQ1_CHRGVBUS_FALL (1 << 4)
++#define USBOTGSS_IRQ1_DISCHRGVBUS_FALL (1 << 3)
++#define USBOTGSS_IRQ1_IDPULLUP_FALL (1 << 0)
++
++/* UTMI_OTG_CTRL REGISTER */
++#define USBOTGSS_UTMI_OTG_CTRL_DRVVBUS (1 << 5)
++#define USBOTGSS_UTMI_OTG_CTRL_CHRGVBUS (1 << 4)
++#define USBOTGSS_UTMI_OTG_CTRL_DISCHRGVBUS (1 << 3)
++#define USBOTGSS_UTMI_OTG_CTRL_IDPULLUP (1 << 0)
++
++/* UTMI_OTG_STATUS REGISTER */
++#define USBOTGSS_UTMI_OTG_STATUS_SW_MODE (1 << 31)
++#define USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT (1 << 9)
++#define USBOTGSS_UTMI_OTG_STATUS_TXBITSTUFFENABLE (1 << 8)
++#define USBOTGSS_UTMI_OTG_STATUS_IDDIG (1 << 4)
++#define USBOTGSS_UTMI_OTG_STATUS_SESSEND (1 << 3)
++#define USBOTGSS_UTMI_OTG_STATUS_SESSVALID (1 << 2)
++#define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID (1 << 1)
++
++struct dwc3_omap {
++ /* device lock */
++ spinlock_t lock;
++
++ struct platform_device *dwc3;
++ struct device *dev;
++
++ int irq;
++ void __iomem *base;
++
++ void *context;
++ u32 resource_size;
++
++ u32 dma_status:1;
++};
++
++static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
++{
++ struct dwc3_omap *omap = _omap;
++ u32 reg;
++
++ spin_lock(&omap->lock);
++
++ reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_1);
++
++ if (reg & USBOTGSS_IRQ1_DMADISABLECLR) {
++ dev_dbg(omap->dev, "DMA Disable was Cleared\n");
++ omap->dma_status = false;
++ }
++
++ if (reg & USBOTGSS_IRQ1_OEVT)
++ dev_dbg(omap->dev, "OTG Event\n");
++
++ if (reg & USBOTGSS_IRQ1_DRVVBUS_RISE)
++ dev_dbg(omap->dev, "DRVVBUS Rise\n");
++
++ if (reg & USBOTGSS_IRQ1_CHRGVBUS_RISE)
++ dev_dbg(omap->dev, "CHRGVBUS Rise\n");
++
++ if (reg & USBOTGSS_IRQ1_DISCHRGVBUS_RISE)
++ dev_dbg(omap->dev, "DISCHRGVBUS Rise\n");
++
++ if (reg & USBOTGSS_IRQ1_IDPULLUP_RISE)
++ dev_dbg(omap->dev, "IDPULLUP Rise\n");
++
++ if (reg & USBOTGSS_IRQ1_DRVVBUS_FALL)
++ dev_dbg(omap->dev, "DRVVBUS Fall\n");
++
++ if (reg & USBOTGSS_IRQ1_CHRGVBUS_FALL)
++ dev_dbg(omap->dev, "CHRGVBUS Fall\n");
++
++ if (reg & USBOTGSS_IRQ1_DISCHRGVBUS_FALL)
++ dev_dbg(omap->dev, "DISCHRGVBUS Fall\n");
++
++ if (reg & USBOTGSS_IRQ1_IDPULLUP_FALL)
++ dev_dbg(omap->dev, "IDPULLUP Fall\n");
++
++ dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg);
++
++ reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_0);
++ dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg);
++
++ spin_unlock(&omap->lock);
++
++ return IRQ_HANDLED;
++}
++
++static int __devinit dwc3_omap_probe(struct platform_device *pdev)
++{
++ struct dwc3_omap_data *pdata = pdev->dev.platform_data;
++ struct platform_device *dwc3;
++ struct dwc3_omap *omap;
++ struct resource *res;
++
++ int devid;
++ int ret = -ENOMEM;
++ int irq;
++
++ u32 reg;
++
++ void __iomem *base;
++ void *context;
++
++ omap = kzalloc(sizeof(*omap), GFP_KERNEL);
++ if (!omap) {
++ dev_err(&pdev->dev, "not enough memory\n");
++ goto err0;
++ }
++
++ platform_set_drvdata(pdev, omap);
++
++ irq = platform_get_irq(pdev, 1);
++ if (irq < 0) {
++ dev_err(&pdev->dev, "missing IRQ resource\n");
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ if (!res) {
++ dev_err(&pdev->dev, "missing memory base resource\n");
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ base = ioremap_nocache(res->start, resource_size(res));
++ if (!base) {
++ dev_err(&pdev->dev, "ioremap failed\n");
++ goto err1;
++ }
++
++ devid = dwc3_get_device_id();
++ if (devid < 0)
++ goto err2;
++
++ dwc3 = platform_device_alloc("dwc3", devid);
++ if (!dwc3) {
++ dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
++ goto err3;
++ }
++
++ context = kzalloc(resource_size(res), GFP_KERNEL);
++ if (!context) {
++ dev_err(&pdev->dev, "couldn't allocate dwc3 context memory\n");
++ goto err4;
++ }
++
++ spin_lock_init(&omap->lock);
++ dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
++
++ dwc3->dev.parent = &pdev->dev;
++ dwc3->dev.dma_mask = pdev->dev.dma_mask;
++ dwc3->dev.dma_parms = pdev->dev.dma_parms;
++ omap->resource_size = resource_size(res);
++ omap->context = context;
++ omap->dev = &pdev->dev;
++ omap->irq = irq;
++ omap->base = base;
++ omap->dwc3 = dwc3;
++
++ reg = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
++
++ if (!pdata) {
++ dev_dbg(&pdev->dev, "missing platform data\n");
++ } else {
++ switch (pdata->utmi_mode) {
++ case DWC3_OMAP_UTMI_MODE_SW:
++ reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
++ break;
++ case DWC3_OMAP_UTMI_MODE_HW:
++ reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
++ break;
++ default:
++ dev_dbg(&pdev->dev, "UNKNOWN utmi mode %d\n",
++ pdata->utmi_mode);
++ }
++ }
++
++ dwc3_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
++
++ /* check the DMA Status */
++ reg = dwc3_readl(omap->base, USBOTGSS_SYSCONFIG);
++ omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
++
++ /* Set No-Idle and No-Standby */
++ reg &= ~(USBOTGSS_STANDBYMODE_MASK
++ | USBOTGSS_IDLEMODE_MASK);
++
++ reg |= (USBOTGSS_SYSCONFIG_STANDBYMODE(USBOTGSS_STANDBYMODE_NO_STANDBY)
++ | USBOTGSS_SYSCONFIG_IDLEMODE(USBOTGSS_IDLEMODE_NO_IDLE));
++
++ dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
++
++ ret = request_irq(omap->irq, dwc3_omap_interrupt, 0,
++ "dwc3-omap", omap);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to request IRQ #%d --> %d\n",
++ omap->irq, ret);
++ goto err5;
++ }
++
++ /* enable all IRQs */
++ reg = USBOTGSS_IRQO_COREIRQ_ST;
++ dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
++
++ reg = (USBOTGSS_IRQ1_OEVT |
++ USBOTGSS_IRQ1_DRVVBUS_RISE |
++ USBOTGSS_IRQ1_CHRGVBUS_RISE |
++ USBOTGSS_IRQ1_DISCHRGVBUS_RISE |
++ USBOTGSS_IRQ1_IDPULLUP_RISE |
++ USBOTGSS_IRQ1_DRVVBUS_FALL |
++ USBOTGSS_IRQ1_CHRGVBUS_FALL |
++ USBOTGSS_IRQ1_DISCHRGVBUS_FALL |
++ USBOTGSS_IRQ1_IDPULLUP_FALL);
++
++ dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
++
++ ret = platform_device_add_resources(dwc3, pdev->resource,
++ pdev->num_resources);
++ if (ret) {
++ dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
++ goto err6;
++ }
++
++ ret = platform_device_add(dwc3);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to register dwc3 device\n");
++ goto err6;
++ }
++
++ return 0;
++
++err6:
++ free_irq(omap->irq, omap);
++
++err5:
++ kfree(omap->context);
++
++err4:
++ platform_device_put(dwc3);
++
++err3:
++ dwc3_put_device_id(devid);
++
++err2:
++ iounmap(base);
++
++err1:
++ kfree(omap);
++
++err0:
++ return ret;
++}
++
++static int __devexit dwc3_omap_remove(struct platform_device *pdev)
++{
++ struct dwc3_omap *omap = platform_get_drvdata(pdev);
++
++ platform_device_unregister(omap->dwc3);
++
++ dwc3_put_device_id(omap->dwc3->id);
++ free_irq(omap->irq, omap);
++ iounmap(omap->base);
++
++ kfree(omap->context);
++ kfree(omap);
++
++ return 0;
++}
++
++static const struct of_device_id of_dwc3_match[] = {
++ {
++ "ti,omap5430-dwc3"
++ },
++ {
++ "ti,omap5-dwc3"
++ },
++ { },
++};
++MODULE_DEVICE_TABLE(of, of_dwc3_match);
++
++static struct platform_driver dwc3_omap_driver = {
++ .probe = dwc3_omap_probe,
++ .remove = __devexit_p(dwc3_omap_remove),
++ .driver = {
++ .name = "omap-dwc3",
++ .of_match_table = of_dwc3_match,
++ },
++};
++
++MODULE_ALIAS("platform:omap-dwc3");
++MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_DESCRIPTION("DesignWare USB3 OMAP Glue Layer");
++
++static int __init dwc3_omap_init(void)
++{
++ return platform_driver_register(&dwc3_omap_driver);
++}
++module_init(dwc3_omap_init);
++
++static void __exit dwc3_omap_exit(void)
++{
++ platform_driver_unregister(&dwc3_omap_driver);
++}
++module_exit(dwc3_omap_exit);
++#endif
+diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
+new file mode 100644
+index 0000000..dda702c
+--- /dev/null
++++ b/drivers/usb/dwc3/dwc3-pci.c
+@@ -0,0 +1,187 @@
++/**
++ * dwc3-pci.c - PCI Specific glue layer
++ *
++ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
++ *
++ * Authors: Felipe Balbi <balbi@ti.com>,
++ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <common.h>
++#ifdef CONFIG_DWC3_off
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/pci.h>
++#include <linux/platform_device.h>
++
++#include "core.h"
++
++/* FIXME define these in <linux/pci_ids.h> */
++#define PCI_VENDOR_ID_SYNOPSYS 0x16c3
++#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
++
++struct dwc3_pci {
++ struct device *dev;
++ struct platform_device *dwc3;
++};
++
++static int __devinit dwc3_pci_probe(struct pci_dev *pci,
++ const struct pci_device_id *id)
++{
++ struct resource res[2];
++ struct platform_device *dwc3;
++ struct dwc3_pci *glue;
++ int ret = -ENOMEM;
++ int devid;
++
++ glue = kzalloc(sizeof(*glue), GFP_KERNEL);
++ if (!glue) {
++ dev_err(&pci->dev, "not enough memory\n");
++ goto err0;
++ }
++
++ glue->dev = &pci->dev;
++
++ ret = pci_enable_device(pci);
++ if (ret) {
++ dev_err(&pci->dev, "failed to enable pci device\n");
++ goto err1;
++ }
++
++ pci_set_power_state(pci, PCI_D0);
++ pci_set_master(pci);
++
++ devid = dwc3_get_device_id();
++ if (devid < 0)
++ goto err2;
++
++ dwc3 = platform_device_alloc("dwc3", devid);
++ if (!dwc3) {
++ dev_err(&pci->dev, "couldn't allocate dwc3 device\n");
++ goto err3;
++ }
++
++ memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
++
++ res[0].start = pci_resource_start(pci, 0);
++ res[0].end = pci_resource_end(pci, 0);
++ res[0].name = "dwc_usb3";
++ res[0].flags = IORESOURCE_MEM;
++
++ res[1].start = pci->irq;
++ res[1].name = "dwc_usb3";
++ res[1].flags = IORESOURCE_IRQ;
++
++ ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
++ if (ret) {
++ dev_err(&pci->dev, "couldn't add resources to dwc3 device\n");
++ goto err4;
++ }
++
++ pci_set_drvdata(pci, glue);
++
++ dma_set_coherent_mask(&dwc3->dev, pci->dev.coherent_dma_mask);
++
++ dwc3->dev.dma_mask = pci->dev.dma_mask;
++ dwc3->dev.dma_parms = pci->dev.dma_parms;
++ dwc3->dev.parent = &pci->dev;
++ glue->dwc3 = dwc3;
++
++ ret = platform_device_add(dwc3);
++ if (ret) {
++ dev_err(&pci->dev, "failed to register dwc3 device\n");
++ goto err4;
++ }
++
++ return 0;
++
++err4:
++ pci_set_drvdata(pci, NULL);
++ platform_device_put(dwc3);
++
++err3:
++ dwc3_put_device_id(devid);
++
++err2:
++ pci_disable_device(pci);
++
++err1:
++ kfree(pci);
++
++err0:
++ return ret;
++}
++
++static void __devexit dwc3_pci_remove(struct pci_dev *pci)
++{
++ struct dwc3_pci *glue = pci_get_drvdata(pci);
++
++ dwc3_put_device_id(glue->dwc3->id);
++ platform_device_unregister(glue->dwc3);
++ pci_set_drvdata(pci, NULL);
++ pci_disable_device(pci);
++ kfree(glue);
++}
++
++static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
++ {
++ PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
++ PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
++ },
++ { } /* Terminating Entry */
++};
++MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
++
++static struct pci_driver dwc3_pci_driver = {
++ .name = "dwc3-pci",
++ .id_table = dwc3_pci_id_table,
++ .probe = dwc3_pci_probe,
++ .remove = __devexit_p(dwc3_pci_remove),
++};
++
++MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer");
++
++static int __init dwc3_pci_init(void)
++{
++ return pci_register_driver(&dwc3_pci_driver);
++}
++module_init(dwc3_pci_init);
++
++static void __exit dwc3_pci_exit(void)
++{
++ pci_unregister_driver(&dwc3_pci_driver);
++}
++module_exit(dwc3_pci_exit);
++#endif
+diff --git a/drivers/usb/dwc3/dwc3_core.c b/drivers/usb/dwc3/dwc3_core.c
+new file mode 100644
+index 0000000..26b6ff7
+--- /dev/null
++++ b/drivers/usb/dwc3/dwc3_core.c
+@@ -0,0 +1,513 @@
++/**
++ * core.c - DesignWare USB3 DRD Controller Core file
++ *
++ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
++ *
++ * Authors: Felipe Balbi <balbi@ti.com>,
++ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <common.h>
++#include <watchdog.h>
++
++#include <linux/usb/ch9.h>
++#include <linux/usb/gadget.h>
++
++#include "core.h"
++#include "gadget.h"
++#include "io.h"
++
++#include "debug.h"
++
++static char *maximum_speed = "super";
++/* -------------------------------------------------------------------------- */
++
++#define DWC3_DEVS_POSSIBLE 32
++
++
++int dwc3_get_device_id(void)
++{
++ static int dwc3_devs;
++
++ return dwc3_devs++;
++}
++
++void dwc3_put_device_id(int id)
++{
++}
++
++void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
++{
++ u32 reg;
++
++ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
++ reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
++ reg |= DWC3_GCTL_PRTCAPDIR(mode);
++ dwc3_writel(dwc->regs, DWC3_GCTL, reg);
++}
++
++/**
++ * dwc3_core_soft_reset - Issues core soft reset and PHY reset
++ * @dwc: pointer to our context structure
++ */
++static void dwc3_core_soft_reset(struct dwc3 *dwc)
++{
++ u32 reg;
++
++ /* Before Resetting PHY, put Core in Reset */
++ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
++ reg |= DWC3_GCTL_CORESOFTRESET;
++ dwc3_writel(dwc->regs, DWC3_GCTL, reg);
++
++ /* Assert USB3 PHY reset */
++ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
++ reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
++ dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
++
++ /* Assert USB2 PHY reset */
++ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
++ reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
++ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
++
++ mdelay(100);
++
++ /* Clear USB3 PHY reset */
++ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
++ reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
++ dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
++
++ /* Clear USB2 PHY reset */
++ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
++ reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
++ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
++
++ /* After PHYs are stable we can take Core out of reset state */
++ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
++ reg &= ~DWC3_GCTL_CORESOFTRESET;
++ dwc3_writel(dwc->regs, DWC3_GCTL, reg);
++}
++
++/**
++ * dwc3_free_one_event_buffer - Frees one event buffer
++ * @dwc: Pointer to our controller context structure
++ * @evt: Pointer to event buffer to be freed
++ */
++static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
++ struct dwc3_event_buffer *evt)
++{
++ dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma);
++ kfree(evt);
++}
++
++/**
++ * dwc3_alloc_one_event_buffer - Allocated one event buffer structure
++ * @dwc: Pointer to our controller context structure
++ * @length: size of the event buffer
++ *
++ * Returns a pointer to the allocated event buffer structure on succes
++ * otherwise ERR_PTR(errno).
++ */
++static struct dwc3_event_buffer *__devinit
++dwc3_alloc_one_event_buffer(struct dwc3 *dwc, unsigned length)
++{
++ struct dwc3_event_buffer *evt;
++
++ evt = kzalloc(sizeof(*evt), GFP_KERNEL);
++ if (!evt)
++ return ERR_PTR(-ENOMEM);
++
++ evt->dwc = dwc;
++ evt->length = length;
++ evt->buf = dma_alloc_coherent(dwc->dev, length,
++ &evt->dma, GFP_KERNEL);
++ if (!evt->buf) {
++ kfree(evt);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ return evt;
++}
++
++/**
++ * dwc3_free_event_buffers - frees all allocated event buffers
++ * @dwc: Pointer to our controller context structure
++ */
++static void dwc3_free_event_buffers(struct dwc3 *dwc)
++{
++ struct dwc3_event_buffer *evt;
++ int i;
++
++ for (i = 0; i < dwc->num_event_buffers; i++) {
++ evt = dwc->ev_buffs[i];
++ if (evt) {
++ dwc3_free_one_event_buffer(dwc, evt);
++ dwc->ev_buffs[i] = NULL;
++ }
++ }
++}
++
++/**
++ * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
++ * @dwc: Pointer to out controller context structure
++ * @length: size of event buffer
++ *
++ * Returns 0 on success otherwise negative errno. In error the case, dwc
++ * may contain some buffers allocated but not all which were requested.
++ */
++static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
++{
++ int num;
++ int i;
++
++ num = DWC3_NUM_INT(dwc->hwparams.hwparams1);
++ dwc->num_event_buffers = num;
++
++ dwc->ev_buffs = kzalloc(sizeof(*dwc->ev_buffs) * num, GFP_KERNEL);
++ if (!dwc->ev_buffs) {
++ dev_err(dwc->dev, "can't allocate event buffers array\n");
++ return -ENOMEM;
++ }
++
++ for (i = 0; i < num; i++) {
++ struct dwc3_event_buffer *evt;
++
++ evt = dwc3_alloc_one_event_buffer(dwc, length);
++ if (IS_ERR(evt)) {
++ dev_err(dwc->dev, "can't allocate event buffer\n");
++ return PTR_ERR(evt);
++ }
++ dwc->ev_buffs[i] = evt;
++ }
++
++ return 0;
++}
++
++/**
++ * dwc3_event_buffers_setup - setup our allocated event buffers
++ * @dwc: Pointer to out controller context structure
++ *
++ * Returns 0 on success otherwise negative errno.
++ */
++static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc)
++{
++ struct dwc3_event_buffer *evt;
++ int n;
++
++ for (n = 0; n < dwc->num_event_buffers; n++) {
++ evt = dwc->ev_buffs[n];
++ dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
++ evt->buf, (unsigned long long) evt->dma,
++ evt->length);
++
++ dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
++ lower_32_bits(evt->dma));
++ dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
++ upper_32_bits(evt->dma));
++ dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
++ evt->length & 0xffff);
++ dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
++ }
++
++ return 0;
++}
++
++static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
++{
++ struct dwc3_event_buffer *evt;
++ int n;
++
++ for (n = 0; n < dwc->num_event_buffers; n++) {
++ evt = dwc->ev_buffs[n];
++ dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
++ dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
++ dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0);
++ dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
++ }
++}
++
++static void __devinit dwc3_cache_hwparams(struct dwc3 *dwc)
++{
++ struct dwc3_hwparams *parms = &dwc->hwparams;
++
++ parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0);
++ parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1);
++ parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2);
++ parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3);
++ parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4);
++ parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5);
++ parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
++ parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
++ parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
++}
++
++/**
++ * dwc3_core_init - Low-level initialization of DWC3 Core
++ * @dwc: Pointer to our controller context structure
++ *
++ * Returns 0 on success otherwise negative errno.
++ */
++static int __devinit dwc3_core_init(struct dwc3 *dwc)
++{
++ unsigned long timeout;
++ u32 reg;
++ int ret;
++
++ reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
++ /* This should read as U3 followed by revision number */
++ if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) {
++ dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
++ ret = -ENODEV;
++ goto err0;
++ }
++ dwc->revision = reg & DWC3_GSNPSREV_MASK;
++
++ dwc3_core_soft_reset(dwc);
++
++ /* issue device SoftReset too */
++ timeout = 500;
++ dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
++ do {
++ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
++ if (!(reg & DWC3_DCTL_CSFTRST))
++ break;
++
++ mdelay(1);
++ timeout--;
++ if (!timeout) {
++ dev_err(dwc->dev, "Reset Timed Out\n");
++ ret = -ETIMEDOUT;
++ goto err0;
++ }
++
++ cpu_relax();
++ } while (true);
++
++ dwc3_cache_hwparams(dwc);
++
++ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
++ reg &= ~DWC3_GCTL_SCALEDOWN(3);
++ reg &= ~DWC3_GCTL_DISSCRAMBLE;
++
++ switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
++ case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
++ reg &= ~DWC3_GCTL_DSBLCLKGTNG;
++ break;
++ default:
++ dev_dbg(dwc->dev, "No power optimization available\n");
++ }
++
++ /*
++ * WORKAROUND: DWC3 revisions <1.90a have a bug
++ * when The device fails to connect at SuperSpeed
++ * and falls back to high-speed mode which causes
++ * the device to enter in a Connect/Disconnect loop
++ */
++ if (dwc->revision < DWC3_REVISION_190A)
++ reg |= DWC3_GCTL_U2RSTECN;
++
++ dwc3_writel(dwc->regs, DWC3_GCTL, reg);
++
++ ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
++ if (ret) {
++ dev_err(dwc->dev, "failed to allocate event buffers\n");
++ ret = -ENOMEM;
++ goto err1;
++ }
++
++ ret = dwc3_event_buffers_setup(dwc);
++ if (ret) {
++ dev_err(dwc->dev, "failed to setup event buffers\n");
++ goto err1;
++ }
++
++ return 0;
++
++err1:
++ dwc3_free_event_buffers(dwc);
++
++err0:
++ return ret;
++}
++
++static void dwc3_core_exit(struct dwc3 *dwc)
++{
++ dwc3_event_buffers_cleanup(dwc);
++ dwc3_free_event_buffers(dwc);
++}
++
++#define DWC3_ALIGN_MASK (16 - 1)
++
++struct dwc3 *global_dwc3;
++
++int __devinit dwc3_probe(struct platform_device *pdev)
++{
++ struct dwc3 *dwc;
++
++ int ret = -ENOMEM;
++
++ void __iomem *regs;
++ void *mem;
++
++ u8 mode;
++
++ mem = kzalloc(sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
++ if (!mem) {
++ dev_err(&pdev->dev, "not enough memory\n");
++ goto err0;
++ }
++ dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
++ dwc->mem = mem;
++ global_dwc3 = dwc;
++
++ dwc->regs = CONFIG_USB_DWC3_UDC_REGS;
++ dwc->regs_size = DWC3_USB_REGS_SIZE;
++ dwc->dev = &pdev->dev;
++ dwc->irq = 0;
++
++ if (!strncmp("super", maximum_speed, 5))
++ dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
++ else if (!strncmp("high", maximum_speed, 4))
++ dwc->maximum_speed = DWC3_DCFG_HIGHSPEED;
++ else if (!strncmp("full", maximum_speed, 4))
++ dwc->maximum_speed = DWC3_DCFG_FULLSPEED1;
++ else if (!strncmp("low", maximum_speed, 3))
++ dwc->maximum_speed = DWC3_DCFG_LOWSPEED;
++ else
++ dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
++
++ pm_runtime_enable(&pdev->dev);
++ pm_runtime_get_sync(&pdev->dev);
++ pm_runtime_forbid(&pdev->dev);
++
++ ret = dwc3_core_init(dwc);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to initialize core\n");
++ goto err3;
++ }
++
++ mode = DWC3_MODE_DEVICE /*DWC3_MODE(dwc->hwparams.hwparams0)*/;
++
++ switch (mode) {
++ case DWC3_MODE_DEVICE:
++ dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
++ ret = dwc3_gadget_init(dwc);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to initialize gadget\n");
++ goto err4;
++ }
++ break;
++ case DWC3_MODE_HOST:
++ dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
++ ret = dwc3_host_init(dwc);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to initialize host\n");
++ goto err4;
++ }
++ break;
++ case DWC3_MODE_DRD:
++ dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
++ ret = dwc3_host_init(dwc);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to initialize host\n");
++ goto err4;
++ }
++
++ ret = dwc3_gadget_init(dwc);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to initialize gadget\n");
++ goto err4;
++ }
++ break;
++ default:
++ dev_err(&pdev->dev, "Unsupported mode of operation %d\n", mode);
++ goto err4;
++ }
++ dwc->mode = mode;
++
++ pm_runtime_allow(&pdev->dev);
++
++ return 0;
++err4:
++ dwc3_core_exit(dwc);
++
++err3:
++ iounmap(regs);
++ kfree(dwc->mem);
++err0:
++ return ret;
++}
++
++int __devexit dwc3_remove(struct platform_device *pdev)
++{
++ struct dwc3 *dwc = global_dwc3;
++
++ dwc3_debugfs_exit(dwc);
++
++ switch (dwc->mode) {
++ case DWC3_MODE_DEVICE:
++ dwc3_gadget_exit(dwc);
++ break;
++ case DWC3_MODE_HOST:
++ dwc3_host_exit(dwc);
++ break;
++ case DWC3_MODE_DRD:
++ dwc3_host_exit(dwc);
++ dwc3_gadget_exit(dwc);
++ break;
++ default:
++ /* do nothing */
++ break;
++ }
++
++ dwc3_core_exit(dwc);
++ iounmap(dwc->regs);
++ kfree(dwc->mem);
++
++ return 0;
++}
++
++int usb_gadget_init_udc(void)
++{
++ return dwc3_probe(NULL);
++}
++void usb_gadget_exit_udc(void)
++{
++ dwc3_remove(NULL);
++}
++
++irqreturn_t dwc3_interrupt(int irq, void *_dwc);
++int usb_gadget_handle_interrupts(void)
++{
++ dwc3_interrupt(0, global_dwc3);
++ WATCHDOG_RESET();
++ return 0;
++}
+diff --git a/drivers/usb/dwc3/dwc3_ep0.c b/drivers/usb/dwc3/dwc3_ep0.c
+new file mode 100644
+index 0000000..2e0d466
+--- /dev/null
++++ b/drivers/usb/dwc3/dwc3_ep0.c
+@@ -0,0 +1,851 @@
++/**
++ * ep0.c - DesignWare USB3 DRD Controller Endpoint 0 Handling
++ *
++ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
++ *
++ * Authors: Felipe Balbi <balbi@ti.com>,
++ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <common.h>
++
++#include <linux/usb/ch9.h>
++#include <linux/usb/gadget.h>
++/* #include <linux/usb/composite.h> */
++
++#include "core.h"
++#include "gadget.h"
++#include "io.h"
++
++static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum);
++
++static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
++{
++ switch (state) {
++ case EP0_UNCONNECTED:
++ return "Unconnected";
++ case EP0_SETUP_PHASE:
++ return "Setup Phase";
++ case EP0_DATA_PHASE:
++ return "Data Phase";
++ case EP0_STATUS_PHASE:
++ return "Status Phase";
++ default:
++ return "UNKNOWN";
++ }
++}
++
++static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
++ u32 len, u32 type)
++{
++ struct dwc3_gadget_ep_cmd_params params;
++ struct dwc3_trb_hw *trb_hw;
++ struct dwc3_trb trb;
++ struct dwc3_ep *dep;
++
++ int ret;
++
++ dep = dwc->eps[epnum];
++ if (dep->flags & DWC3_EP_BUSY) {
++ dev_vdbg(dwc->dev, "%s: still busy\n", dep->name);
++ return 0;
++ }
++
++ trb_hw = dwc->ep0_trb;
++ memset(&trb, 0, sizeof(trb));
++
++ trb.trbctl = type;
++ trb.bplh = buf_dma;
++ trb.length = len;
++
++ trb.hwo = 1;
++ trb.lst = 1;
++ trb.ioc = 1;
++ trb.isp_imi = 1;
++
++ dwc3_trb_to_hw(&trb, trb_hw);
++
++ memset(&params, 0, sizeof(params));
++ params.param0 = upper_32_bits(dwc->ep0_trb_addr);
++ params.param1 = lower_32_bits(dwc->ep0_trb_addr);
++
++ ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
++ DWC3_DEPCMD_STARTTRANSFER, &params);
++ if (ret < 0) {
++ dev_dbg(dwc->dev, "failed to send STARTTRANSFER command\n");
++ return ret;
++ }
++
++ dep->flags |= DWC3_EP_BUSY;
++ dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
++ dep->number);
++
++ dwc->ep0_next_event = DWC3_EP0_COMPLETE;
++
++ return 0;
++}
++
++static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
++ struct dwc3_request *req)
++{
++ struct dwc3 *dwc = dep->dwc;
++ u32 type;
++ int ret = 0;
++
++ req->request.actual = 0;
++ req->request.status = -EINPROGRESS;
++ req->epnum = dep->number;
++
++ list_add_tail(&req->list, &dep->request_list);
++
++ /*
++ * Gadget driver might not be quick enough to queue a request
++ * before we get a Transfer Not Ready event on this endpoint.
++ *
++ * In that case, we will set DWC3_EP_PENDING_REQUEST. When that
++ * flag is set, it's telling us that as soon as Gadget queues the
++ * required request, we should kick the transfer here because the
++ * IRQ we were waiting for is long gone.
++ */
++ if (dep->flags & DWC3_EP_PENDING_REQUEST) {
++ unsigned direction;
++
++ direction = !!(dep->flags & DWC3_EP0_DIR_IN);
++
++ if (dwc->ep0state == EP0_STATUS_PHASE) {
++ type = dwc->three_stage_setup
++ ? DWC3_TRBCTL_CONTROL_STATUS3
++ : DWC3_TRBCTL_CONTROL_STATUS2;
++ } else if (dwc->ep0state == EP0_DATA_PHASE) {
++ type = DWC3_TRBCTL_CONTROL_DATA;
++ } else {
++ /* should never happen */
++ WARN_ON(1);
++ return 0;
++ }
++
++ ret = dwc3_ep0_start_trans(dwc, direction,
++ req->request.dma, req->request.length, type);
++ dep->flags &= ~(DWC3_EP_PENDING_REQUEST |
++ DWC3_EP0_DIR_IN);
++
++ } else if (dwc->delayed_status && (dwc->ep0state == EP0_STATUS_PHASE)) {
++ dwc->delayed_status = false;
++ dwc3_ep0_do_control_status(dwc, 1);
++ }
++
++ return ret;
++}
++
++int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
++ gfp_t gfp_flags)
++{
++ struct dwc3_request *req = to_dwc3_request(request);
++ struct dwc3_ep *dep = to_dwc3_ep(ep);
++ struct dwc3 *dwc = dep->dwc;
++
++ unsigned long flags;
++
++ int ret;
++
++ spin_lock_irqsave(&dwc->lock, flags);
++ if (!dep->desc) {
++ dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
++ request, dep->name);
++ ret = -ESHUTDOWN;
++ goto out;
++ }
++
++ /* we share one TRB for ep0/1 */
++ if (!list_empty(&dep->request_list)) {
++ ret = -EBUSY;
++ goto out;
++ }
++
++ dev_vdbg(dwc->dev, "queueing request %p to %s length %d, state '%s'\n",
++ request, dep->name, request->length,
++ dwc3_ep0_state_string(dwc->ep0state));
++
++ ret = __dwc3_gadget_ep0_queue(dep, req);
++
++out:
++ spin_unlock_irqrestore(&dwc->lock, flags);
++
++ return ret;
++}
++
++static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
++{
++ struct dwc3_ep *dep = dwc->eps[0];
++
++ /* stall is always issued on EP0 */
++ __dwc3_gadget_ep_set_halt(dep, 1);
++ dep->flags = DWC3_EP_ENABLED;
++ dwc->delayed_status = false;
++
++ if (!list_empty(&dep->request_list)) {
++ struct dwc3_request *req;
++
++ req = next_request(&dep->request_list);
++ dwc3_gadget_giveback(dep, req, -ECONNRESET);
++ }
++
++ dwc->ep0state = EP0_SETUP_PHASE;
++ dwc3_ep0_out_start(dwc);
++}
++
++void dwc3_ep0_out_start(struct dwc3 *dwc)
++{
++ int ret;
++
++ ret = dwc3_ep0_start_trans(dwc, 0, dwc->ctrl_req_addr, 8,
++ DWC3_TRBCTL_CONTROL_SETUP);
++ WARN_ON(ret < 0);
++}
++
++static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le)
++{
++ struct dwc3_ep *dep;
++ u32 windex = le16_to_cpu(wIndex_le);
++ u32 epnum;
++
++ epnum = (windex & USB_ENDPOINT_NUMBER_MASK) << 1;
++ if ((windex & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
++ epnum |= 1;
++
++ dep = dwc->eps[epnum];
++ if (dep->flags & DWC3_EP_ENABLED)
++ return dep;
++
++ return NULL;
++}
++
++static void dwc3_ep0_status_cmpl(struct usb_ep *ep, struct usb_request *req)
++{
++}
++/*
++ * ch 9.4.5
++ */
++static int dwc3_ep0_handle_status(struct dwc3 *dwc,
++ struct usb_ctrlrequest *ctrl)
++{
++ struct dwc3_ep *dep;
++ u32 recip;
++ u16 usb_status = 0;
++ __le16 *response_pkt;
++
++ recip = ctrl->bRequestType & USB_RECIP_MASK;
++ switch (recip) {
++ case USB_RECIP_DEVICE:
++ /*
++ * We are self-powered. U1/U2/LTM will be set later
++ * once we handle this states. RemoteWakeup is 0 on SS
++ */
++ usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED;
++ break;
++
++ case USB_RECIP_INTERFACE:
++ /*
++ * Function Remote Wake Capable D0
++ * Function Remote Wakeup D1
++ */
++ break;
++
++ case USB_RECIP_ENDPOINT:
++ dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
++ if (!dep)
++ return -EINVAL;
++
++ if (dep->flags & DWC3_EP_STALL)
++ usb_status = 1 << USB_ENDPOINT_HALT;
++ break;
++ default:
++ return -EINVAL;
++ };
++
++ response_pkt = (__le16 *) dwc->setup_buf;
++ *response_pkt = cpu_to_le16(usb_status);
++
++ dep = dwc->eps[0];
++ dwc->ep0_usb_req.dep = dep;
++ dwc->ep0_usb_req.request.length = sizeof(*response_pkt);
++ dwc->ep0_usb_req.request.dma = dwc->setup_buf_addr;
++ dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl;
++
++ return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req);
++}
++
++static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
++ struct usb_ctrlrequest *ctrl, int set)
++{
++ struct dwc3_ep *dep;
++ u32 recip;
++ u32 wValue;
++ u32 wIndex;
++ u32 reg;
++ int ret;
++ u32 mode;
++
++ wValue = le16_to_cpu(ctrl->wValue);
++ wIndex = le16_to_cpu(ctrl->wIndex);
++ recip = ctrl->bRequestType & USB_RECIP_MASK;
++ switch (recip) {
++ case USB_RECIP_DEVICE:
++
++ /*
++ * 9.4.1 says only only for SS, in AddressState only for
++ * default control pipe
++ */
++ switch (wValue) {
++ case USB_DEVICE_U1_ENABLE:
++ case USB_DEVICE_U2_ENABLE:
++ case USB_DEVICE_LTM_ENABLE:
++ if (dwc->dev_state != DWC3_CONFIGURED_STATE)
++ return -EINVAL;
++ if (dwc->speed != DWC3_DSTS_SUPERSPEED)
++ return -EINVAL;
++ }
++
++ /* XXX add U[12] & LTM */
++ switch (wValue) {
++ case USB_DEVICE_REMOTE_WAKEUP:
++ break;
++ case USB_DEVICE_U1_ENABLE:
++ break;
++ case USB_DEVICE_U2_ENABLE:
++ break;
++ case USB_DEVICE_LTM_ENABLE:
++ break;
++
++ case USB_DEVICE_TEST_MODE:
++ if ((wIndex & 0xff) != 0)
++ return -EINVAL;
++ if (!set)
++ return -EINVAL;
++
++ mode = wIndex >> 8;
++ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
++ reg &= ~DWC3_DCTL_TSTCTRL_MASK;
++
++ switch (mode) {
++ case TEST_J:
++ case TEST_K:
++ case TEST_SE0_NAK:
++ case TEST_PACKET:
++ case TEST_FORCE_EN:
++ reg |= mode << 1;
++ break;
++ default:
++ return -EINVAL;
++ }
++ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
++ break;
++ default:
++ return -EINVAL;
++ }
++ break;
++
++ case USB_RECIP_INTERFACE:
++ switch (wValue) {
++ case USB_INTRF_FUNC_SUSPEND:
++ if (wIndex & USB_INTRF_FUNC_SUSPEND_LP)
++ /* XXX enable Low power suspend */
++ ;
++ if (wIndex & USB_INTRF_FUNC_SUSPEND_RW)
++ /* XXX enable remote wakeup */
++ ;
++ break;
++ default:
++ return -EINVAL;
++ }
++ break;
++
++ case USB_RECIP_ENDPOINT:
++ switch (wValue) {
++ case USB_ENDPOINT_HALT:
++ dep = dwc3_wIndex_to_dep(dwc, wIndex);
++ if (!dep)
++ return -EINVAL;
++ ret = __dwc3_gadget_ep_set_halt(dep, set);
++ if (ret)
++ return -EINVAL;
++ break;
++ default:
++ return -EINVAL;
++ }
++ break;
++
++ default:
++ return -EINVAL;
++ };
++
++ return 0;
++}
++
++static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
++{
++ u32 addr;
++ u32 reg;
++
++ addr = le16_to_cpu(ctrl->wValue);
++ if (addr > 127) {
++ dev_dbg(dwc->dev, "invalid device address %d\n", addr);
++ return -EINVAL;
++ }
++
++ if (dwc->dev_state == DWC3_CONFIGURED_STATE) {
++ dev_dbg(dwc->dev, "trying to set address when configured\n");
++ return -EINVAL;
++ }
++
++ reg = dwc3_readl(dwc->regs, DWC3_DCFG);
++ reg &= ~(DWC3_DCFG_DEVADDR_MASK);
++ reg |= DWC3_DCFG_DEVADDR(addr);
++ dwc3_writel(dwc->regs, DWC3_DCFG, reg);
++
++ if (addr)
++ dwc->dev_state = DWC3_ADDRESS_STATE;
++ else
++ dwc->dev_state = DWC3_DEFAULT_STATE;
++
++ return 0;
++}
++
++static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
++{
++ int ret;
++
++ spin_unlock(&dwc->lock);
++ ret = dwc->gadget_driver->setup(&dwc->gadget, ctrl);
++ spin_lock(&dwc->lock);
++ return ret;
++}
++
++static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
++{
++ u32 cfg;
++ int ret;
++
++ dwc->start_config_issued = false;
++ cfg = le16_to_cpu(ctrl->wValue);
++
++ switch (dwc->dev_state) {
++ case DWC3_DEFAULT_STATE:
++ return -EINVAL;
++ break;
++
++ case DWC3_ADDRESS_STATE:
++ ret = dwc3_ep0_delegate_req(dwc, ctrl);
++ /* if the cfg matches and the cfg is non zero */
++ if (!ret && cfg)
++ dwc->dev_state = DWC3_CONFIGURED_STATE;
++ break;
++
++ case DWC3_CONFIGURED_STATE:
++ ret = dwc3_ep0_delegate_req(dwc, ctrl);
++ if (!cfg)
++ dwc->dev_state = DWC3_ADDRESS_STATE;
++ break;
++ default:
++ ret = -EINVAL;
++ }
++ return ret;
++}
++
++static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
++{
++ int ret;
++
++ switch (ctrl->bRequest) {
++ case USB_REQ_GET_STATUS:
++ dev_vdbg(dwc->dev, "USB_REQ_GET_STATUS\n");
++ ret = dwc3_ep0_handle_status(dwc, ctrl);
++ break;
++ case USB_REQ_CLEAR_FEATURE:
++ dev_vdbg(dwc->dev, "USB_REQ_CLEAR_FEATURE\n");
++ ret = dwc3_ep0_handle_feature(dwc, ctrl, 0);
++ break;
++ case USB_REQ_SET_FEATURE:
++ dev_vdbg(dwc->dev, "USB_REQ_SET_FEATURE\n");
++ ret = dwc3_ep0_handle_feature(dwc, ctrl, 1);
++ break;
++ case USB_REQ_SET_ADDRESS:
++ dev_vdbg(dwc->dev, "USB_REQ_SET_ADDRESS\n");
++ ret = dwc3_ep0_set_address(dwc, ctrl);
++ break;
++ case USB_REQ_SET_CONFIGURATION:
++ dev_vdbg(dwc->dev, "USB_REQ_SET_CONFIGURATION\n");
++ ret = dwc3_ep0_set_config(dwc, ctrl);
++ break;
++ default:
++ dev_vdbg(dwc->dev, "Forwarding to gadget driver\n");
++ ret = dwc3_ep0_delegate_req(dwc, ctrl);
++ break;
++ };
++
++ return ret;
++}
++
++static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
++ const struct dwc3_event_depevt *event)
++{
++ struct usb_ctrlrequest *ctrl = dwc->ctrl_req;
++ int ret;
++ u32 len;
++
++ if (!dwc->gadget_driver)
++ goto err;
++
++ len = le16_to_cpu(ctrl->wLength);
++ if (!len) {
++ dwc->three_stage_setup = false;
++ dwc->ep0_expect_in = false;
++ dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
++ } else {
++ dwc->three_stage_setup = true;
++ dwc->ep0_expect_in = !!(ctrl->bRequestType & USB_DIR_IN);
++ dwc->ep0_next_event = DWC3_EP0_NRDY_DATA;
++ }
++
++ if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
++ ret = dwc3_ep0_std_request(dwc, ctrl);
++ else
++ ret = dwc3_ep0_delegate_req(dwc, ctrl);
++
++ if (ret == USB_GADGET_DELAYED_STATUS)
++ dwc->delayed_status = true;
++
++ if (ret >= 0)
++ return;
++
++err:
++ dwc3_ep0_stall_and_restart(dwc);
++}
++
++static void dwc3_ep0_complete_data(struct dwc3 *dwc,
++ const struct dwc3_event_depevt *event)
++{
++ struct dwc3_request *r = NULL;
++ struct usb_request *ur;
++ struct dwc3_trb trb;
++ struct dwc3_ep *ep0;
++ u32 transferred;
++ u8 epnum;
++
++ epnum = event->endpoint_number;
++ ep0 = dwc->eps[0];
++
++ dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
++
++ r = next_request(&ep0->request_list);
++ ur = &r->request;
++
++ dwc3_trb_to_nat(dwc->ep0_trb, &trb);
++
++ if (dwc->ep0_bounced) {
++
++ transferred = min_t(u32, ur->length,
++ ep0->endpoint.maxpacket - trb.length);
++ memcpy(ur->buf, dwc->ep0_bounce, transferred);
++ dwc->ep0_bounced = false;
++ } else {
++ transferred = ur->length - trb.length;
++ ur->actual += transferred;
++ }
++
++ if ((epnum & 1) && ur->actual < ur->length) {
++ /* for some reason we did not get everything out */
++
++ dwc3_ep0_stall_and_restart(dwc);
++ } else {
++ /*
++ * handle the case where we have to send a zero packet. This
++ * seems to be case when req.length > maxpacket. Could it be?
++ */
++ if (r)
++ dwc3_gadget_giveback(ep0, r, 0);
++ }
++}
++
++static void dwc3_ep0_complete_req(struct dwc3 *dwc,
++ const struct dwc3_event_depevt *event)
++{
++ struct dwc3_request *r;
++ struct dwc3_ep *dep;
++
++ dep = dwc->eps[0];
++
++ if (!list_empty(&dep->request_list)) {
++ r = next_request(&dep->request_list);
++
++ dwc3_gadget_giveback(dep, r, 0);
++ }
++
++ dwc->ep0state = EP0_SETUP_PHASE;
++ dwc3_ep0_out_start(dwc);
++}
++
++static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
++ const struct dwc3_event_depevt *event)
++{
++ struct dwc3_ep *dep = dwc->eps[event->endpoint_number];
++
++ dep->flags &= ~DWC3_EP_BUSY;
++ dwc->setup_packet_pending = false;
++
++ switch (dwc->ep0state) {
++ case EP0_SETUP_PHASE:
++ dev_vdbg(dwc->dev, "Inspecting Setup Bytes\n");
++ dwc3_ep0_inspect_setup(dwc, event);
++ break;
++
++ case EP0_DATA_PHASE:
++ dev_vdbg(dwc->dev, "Data Phase\n");
++ dwc3_ep0_complete_data(dwc, event);
++ break;
++
++ case EP0_STATUS_PHASE:
++ dev_vdbg(dwc->dev, "Status Phase\n");
++ dwc3_ep0_complete_req(dwc, event);
++ break;
++ default:
++ WARN(true, "UNKNOWN ep0state %d\n", dwc->ep0state);
++ }
++}
++
++static void dwc3_ep0_do_control_setup(struct dwc3 *dwc,
++ const struct dwc3_event_depevt *event)
++{
++ dwc3_ep0_out_start(dwc);
++}
++
++static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
++ const struct dwc3_event_depevt *event)
++{
++ struct dwc3_ep *dep;
++ struct dwc3_request *req;
++ int ret;
++
++ dep = dwc->eps[0];
++
++ if (list_empty(&dep->request_list)) {
++ dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n");
++ dep->flags |= DWC3_EP_PENDING_REQUEST;
++
++ if (event->endpoint_number)
++ dep->flags |= DWC3_EP0_DIR_IN;
++ return;
++ }
++
++ req = next_request(&dep->request_list);
++ req->direction = !!event->endpoint_number;
++
++ if (req->request.length == 0) {
++ ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
++ dwc->ctrl_req_addr, 0,
++ DWC3_TRBCTL_CONTROL_DATA);
++ } else if ((req->request.length % dep->endpoint.maxpacket)
++ && (event->endpoint_number == 0)) {
++ dwc3_map_buffer_to_dma(req);
++
++ WARN_ON(req->request.length > dep->endpoint.maxpacket);
++
++ dwc->ep0_bounced = true;
++
++ /*
++ * REVISIT in case request length is bigger than EP0
++ * wMaxPacketSize, we will need two chained TRBs to handle
++ * the transfer.
++ */
++ ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
++ dwc->ep0_bounce_addr, dep->endpoint.maxpacket,
++ DWC3_TRBCTL_CONTROL_DATA);
++ } else {
++ dwc3_map_buffer_to_dma(req);
++
++ ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
++ req->request.dma, req->request.length,
++ DWC3_TRBCTL_CONTROL_DATA);
++ }
++
++ WARN_ON(ret < 0);
++}
++
++static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
++{
++ struct dwc3 *dwc = dep->dwc;
++ u32 type;
++
++ type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3
++ : DWC3_TRBCTL_CONTROL_STATUS2;
++
++ return dwc3_ep0_start_trans(dwc, dep->number,
++ dwc->ctrl_req_addr, 0, type);
++}
++
++static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum)
++{
++ struct dwc3_ep *dep = dwc->eps[epnum];
++
++ WARN_ON(dwc3_ep0_start_control_status(dep));
++}
++
++static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
++ const struct dwc3_event_depevt *event)
++{
++ dwc->setup_packet_pending = true;
++
++ /*
++ * This part is very tricky: If we has just handled
++ * XferNotReady(Setup) and we're now expecting a
++ * XferComplete but, instead, we receive another
++ * XferNotReady(Setup), we should STALL and restart
++ * the state machine.
++ *
++ * In all other cases, we just continue waiting
++ * for the XferComplete event.
++ *
++ * We are a little bit unsafe here because we're
++ * not trying to ensure that last event was, indeed,
++ * XferNotReady(Setup).
++ *
++ * Still, we don't expect any condition where that
++ * should happen and, even if it does, it would be
++ * another error condition.
++ */
++ if (dwc->ep0_next_event == DWC3_EP0_COMPLETE) {
++ switch (event->status) {
++ case DEPEVT_STATUS_CONTROL_SETUP:
++ dev_vdbg(dwc->dev, "Unexpected XferNotReady(Setup)\n");
++ dwc3_ep0_stall_and_restart(dwc);
++ break;
++ case DEPEVT_STATUS_CONTROL_DATA:
++ /* FALLTHROUGH */
++ case DEPEVT_STATUS_CONTROL_STATUS:
++ /* FALLTHROUGH */
++ default:
++ dev_vdbg(dwc->dev, "waiting for XferComplete\n");
++ }
++
++ return;
++ }
++
++ switch (event->status) {
++ case DEPEVT_STATUS_CONTROL_SETUP:
++ dev_vdbg(dwc->dev, "Control Setup\n");
++
++ dwc->ep0state = EP0_SETUP_PHASE;
++
++ dwc3_ep0_do_control_setup(dwc, event);
++ break;
++
++ case DEPEVT_STATUS_CONTROL_DATA:
++ dev_vdbg(dwc->dev, "Control Data\n");
++
++ dwc->ep0state = EP0_DATA_PHASE;
++
++ if (dwc->ep0_next_event != DWC3_EP0_NRDY_DATA) {
++ dev_vdbg(dwc->dev, "Expected %d got %d\n",
++ dwc->ep0_next_event,
++ DWC3_EP0_NRDY_DATA);
++
++ dwc3_ep0_stall_and_restart(dwc);
++ return;
++ }
++
++ /*
++ * One of the possible error cases is when Host _does_
++ * request for Data Phase, but it does so on the wrong
++ * direction.
++ *
++ * Here, we already know ep0_next_event is DATA (see above),
++ * so we only need to check for direction.
++ */
++ if (dwc->ep0_expect_in != event->endpoint_number) {
++ dev_vdbg(dwc->dev, "Wrong direction for Data phase\n");
++ dwc3_ep0_stall_and_restart(dwc);
++ return;
++ }
++
++ dwc3_ep0_do_control_data(dwc, event);
++ break;
++
++ case DEPEVT_STATUS_CONTROL_STATUS:
++ dev_vdbg(dwc->dev, "Control Status\n");
++
++ dwc->ep0state = EP0_STATUS_PHASE;
++
++ if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) {
++ dev_vdbg(dwc->dev, "Expected %d got %d\n",
++ dwc->ep0_next_event,
++ DWC3_EP0_NRDY_STATUS);
++
++ dwc3_ep0_stall_and_restart(dwc);
++ return;
++ }
++
++ if (dwc->delayed_status) {
++ WARN_ON_ONCE(event->endpoint_number != 1);
++ dev_vdbg(dwc->dev, "Mass Storage delayed status\n");
++ return;
++ }
++
++ dwc3_ep0_do_control_status(dwc, event->endpoint_number);
++ }
++}
++
++void dwc3_ep0_interrupt(struct dwc3 *dwc,
++ const struct dwc3_event_depevt *event)
++{
++ u8 epnum = event->endpoint_number;
++
++ dev_dbg(dwc->dev, "%s while ep%d%s in state '%s'\n",
++ dwc3_ep_event_string(event->endpoint_event),
++ epnum >> 1, (epnum & 1) ? "in" : "out",
++ dwc3_ep0_state_string(dwc->ep0state));
++
++ switch (event->endpoint_event) {
++ case DWC3_DEPEVT_XFERCOMPLETE:
++ dwc3_ep0_xfer_complete(dwc, event);
++ break;
++
++ case DWC3_DEPEVT_XFERNOTREADY:
++ dwc3_ep0_xfernotready(dwc, event);
++ break;
++
++ case DWC3_DEPEVT_XFERINPROGRESS:
++ case DWC3_DEPEVT_RXTXFIFOEVT:
++ case DWC3_DEPEVT_STREAMEVT:
++ case DWC3_DEPEVT_EPCMDCMPLT:
++ break;
++ }
++}
+diff --git a/drivers/usb/dwc3/dwc3_gadget.c b/drivers/usb/dwc3/dwc3_gadget.c
+new file mode 100644
+index 0000000..7c1a479
+--- /dev/null
++++ b/drivers/usb/dwc3/dwc3_gadget.c
+@@ -0,0 +1,2184 @@
++/**
++ * gadget.c - DesignWare USB3 DRD Controller Gadget Framework Link
++ *
++ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
++ *
++ * Authors: Felipe Balbi <balbi@ti.com>,
++ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <common.h>
++
++#include <linux/usb/ch9.h>
++#include <linux/usb/gadget.h>
++
++#include "core.h"
++#include "gadget.h"
++#include "io.h"
++
++#define DMA_ADDR_INVALID (~(dma_addr_t)0)
++
++void dwc3_map_buffer_to_dma(struct dwc3_request *req)
++{
++ struct dwc3 *dwc = req->dep->dwc;
++
++ if (req->request.length == 0) {
++ /* req->request.dma = dwc->setup_buf_addr; */
++ return;
++ }
++
++ if (req->request.dma == DMA_ADDR_INVALID) {
++ req->request.dma = dma_map_single(dwc->dev, req->request.buf,
++ req->request.length, req->direction
++ ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
++ req->mapped = true;
++ }
++}
++
++void dwc3_unmap_buffer_from_dma(struct dwc3_request *req)
++{
++ struct dwc3 *dwc = req->dep->dwc;
++
++ if (req->request.length == 0) {
++ req->request.dma = DMA_ADDR_INVALID;
++ return;
++ }
++
++ if (req->mapped) {
++ dma_unmap_single(dwc->dev, req->request.dma,
++ req->request.length, req->direction
++ ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
++ req->mapped = 0;
++ req->request.dma = DMA_ADDR_INVALID;
++ }
++}
++
++void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
++ int status)
++{
++ struct dwc3 *dwc = dep->dwc;
++
++ if (req->queued) {
++ dep->busy_slot++;
++ /*
++ * Skip LINK TRB. We can't use req->trb and check for
++ * DWC3_TRBCTL_LINK_TRB because it points the TRB we just
++ * completed (not the LINK TRB).
++ */
++ if (((dep->busy_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
++ usb_endpoint_xfer_isoc(dep->desc))
++ dep->busy_slot++;
++ }
++ list_del(&req->list);
++
++ if (req->request.status == -EINPROGRESS)
++ req->request.status = status;
++
++ dwc3_unmap_buffer_from_dma(req);
++
++ dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n",
++ req, dep->name, req->request.actual,
++ req->request.length, status);
++
++ spin_unlock(&dwc->lock);
++ req->request.complete(&req->dep->endpoint, &req->request);
++ spin_lock(&dwc->lock);
++}
++
++static const char *dwc3_gadget_ep_cmd_string(u8 cmd)
++{
++ switch (cmd) {
++ case DWC3_DEPCMD_DEPSTARTCFG:
++ return "Start New Configuration";
++ case DWC3_DEPCMD_ENDTRANSFER:
++ return "End Transfer";
++ case DWC3_DEPCMD_UPDATETRANSFER:
++ return "Update Transfer";
++ case DWC3_DEPCMD_STARTTRANSFER:
++ return "Start Transfer";
++ case DWC3_DEPCMD_CLEARSTALL:
++ return "Clear Stall";
++ case DWC3_DEPCMD_SETSTALL:
++ return "Set Stall";
++ case DWC3_DEPCMD_GETSEQNUMBER:
++ return "Get Data Sequence Number";
++ case DWC3_DEPCMD_SETTRANSFRESOURCE:
++ return "Set Endpoint Transfer Resource";
++ case DWC3_DEPCMD_SETEPCONFIG:
++ return "Set Endpoint Configuration";
++ default:
++ return "UNKNOWN command";
++ }
++}
++
++int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
++ unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
++{
++ struct dwc3_ep *dep = dwc->eps[ep];
++ u32 timeout = 500;
++ u32 reg;
++
++ dev_vdbg(dwc->dev, "%s: cmd '%s' params %08x %08x %08x\n",
++ dep->name,
++ dwc3_gadget_ep_cmd_string(cmd), params->param0,
++ params->param1, params->param2);
++
++ dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0);
++ dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1);
++ dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2);
++
++ dwc3_writel(dwc->regs, DWC3_DEPCMD(ep), cmd | DWC3_DEPCMD_CMDACT);
++ do {
++ reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep));
++ if (!(reg & DWC3_DEPCMD_CMDACT)) {
++ dev_vdbg(dwc->dev, "Command Complete --> %d\n",
++ DWC3_DEPCMD_STATUS(reg));
++ return 0;
++ }
++
++ /*
++ * We can't sleep here, because it is also called from
++ * interrupt context.
++ */
++ timeout--;
++ if (!timeout)
++ return -ETIMEDOUT;
++
++ udelay(1);
++ } while (1);
++}
++
++static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
++ struct dwc3_trb_hw *trb)
++{
++ u32 offset = (char *) trb - (char *) dep->trb_pool;
++
++ return dep->trb_pool_dma + offset;
++}
++
++static int dwc3_alloc_trb_pool(struct dwc3_ep *dep)
++{
++ struct dwc3 *dwc = dep->dwc;
++
++ if (dep->trb_pool)
++ return 0;
++
++ if (dep->number == 0 || dep->number == 1)
++ return 0;
++
++ dep->trb_pool = dma_alloc_coherent(dwc->dev,
++ sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
++ &dep->trb_pool_dma, GFP_KERNEL);
++ if (!dep->trb_pool) {
++ dev_err(dep->dwc->dev, "failed to allocate trb pool for %s\n",
++ dep->name);
++ return -ENOMEM;
++ }
++
++ return 0;
++}
++
++static void dwc3_free_trb_pool(struct dwc3_ep *dep)
++{
++ struct dwc3 *dwc = dep->dwc;
++
++ dma_free_coherent(dwc->dev, sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
++ dep->trb_pool, dep->trb_pool_dma);
++
++ dep->trb_pool = NULL;
++ dep->trb_pool_dma = 0;
++}
++
++static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
++{
++ struct dwc3_gadget_ep_cmd_params params;
++ u32 cmd;
++
++ memset(&params, 0x00, sizeof(params));
++
++ if (dep->number != 1) {
++ cmd = DWC3_DEPCMD_DEPSTARTCFG;
++ /* XferRscIdx == 0 for ep0 and 2 for the remaining */
++ if (dep->number > 1) {
++ if (dwc->start_config_issued)
++ return 0;
++ dwc->start_config_issued = true;
++ cmd |= DWC3_DEPCMD_PARAM(2);
++ }
++
++ return dwc3_send_gadget_ep_cmd(dwc, 0, cmd, &params);
++ }
++
++ return 0;
++}
++
++static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
++ const struct usb_endpoint_descriptor *desc,
++ const struct usb_ss_ep_comp_descriptor *comp_desc)
++{
++ struct dwc3_gadget_ep_cmd_params params;
++
++ memset(&params, 0x00, sizeof(params));
++
++ params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc))
++ | DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc))
++ | DWC3_DEPCFG_BURST_SIZE(dep->endpoint.maxburst);
++
++ params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN
++ | DWC3_DEPCFG_XFER_NOT_READY_EN;
++
++#if 0
++ if (comp_desc && USB_SS_MAX_STREAMS(comp_desc->bmAttributes)
++ && usb_endpoint_xfer_bulk(desc)) {
++ params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE
++ | DWC3_DEPCFG_STREAM_EVENT_EN;
++ dep->stream_capable = true;
++ }
++#endif
++
++ if (usb_endpoint_xfer_isoc(desc))
++ params.param1 |= DWC3_DEPCFG_XFER_IN_PROGRESS_EN;
++
++ /*
++ * We are doing 1:1 mapping for endpoints, meaning
++ * Physical Endpoints 2 maps to Logical Endpoint 2 and
++ * so on. We consider the direction bit as part of the physical
++ * endpoint number. So USB endpoint 0x81 is 0x03.
++ */
++ params.param1 |= DWC3_DEPCFG_EP_NUMBER(dep->number);
++
++ /*
++ * We must use the lower 16 TX FIFOs even though
++ * HW might have more
++ */
++ if (dep->direction)
++ params.param0 |= DWC3_DEPCFG_FIFO_NUMBER(dep->number >> 1);
++
++ if (desc->bInterval) {
++ params.param1 |= DWC3_DEPCFG_BINTERVAL_M1(desc->bInterval - 1);
++ dep->interval = 1 << (desc->bInterval - 1);
++ }
++
++ return dwc3_send_gadget_ep_cmd(dwc, dep->number,
++ DWC3_DEPCMD_SETEPCONFIG, &params);
++}
++
++static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep)
++{
++ struct dwc3_gadget_ep_cmd_params params;
++
++ memset(&params, 0x00, sizeof(params));
++
++ params.param0 = DWC3_DEPXFERCFG_NUM_XFER_RES(1);
++
++ return dwc3_send_gadget_ep_cmd(dwc, dep->number,
++ DWC3_DEPCMD_SETTRANSFRESOURCE, &params);
++}
++
++/**
++ * __dwc3_gadget_ep_enable - Initializes a HW endpoint
++ * @dep: endpoint to be initialized
++ * @desc: USB Endpoint Descriptor
++ *
++ * Caller should take care of locking
++ */
++static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
++ const struct usb_endpoint_descriptor *desc,
++ const struct usb_ss_ep_comp_descriptor *comp_desc)
++{
++ struct dwc3 *dwc = dep->dwc;
++ u32 reg;
++ int ret = -ENOMEM;
++
++ if (!(dep->flags & DWC3_EP_ENABLED)) {
++ ret = dwc3_gadget_start_config(dwc, dep);
++ if (ret)
++ return ret;
++ }
++
++ ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc);
++ if (ret)
++ return ret;
++
++ if (!(dep->flags & DWC3_EP_ENABLED)) {
++ struct dwc3_trb_hw *trb_st_hw;
++ struct dwc3_trb_hw *trb_link_hw;
++ struct dwc3_trb trb_link;
++
++ ret = dwc3_gadget_set_xfer_resource(dwc, dep);
++ if (ret)
++ return ret;
++
++ dep->desc = desc;
++ dep->comp_desc = comp_desc;
++ dep->type = usb_endpoint_type(desc);
++ dep->flags |= DWC3_EP_ENABLED;
++
++ reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
++ reg |= DWC3_DALEPENA_EP(dep->number);
++ dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
++
++ if (!usb_endpoint_xfer_isoc(desc))
++ return 0;
++
++ memset(&trb_link, 0, sizeof(trb_link));
++
++ /* Link TRB for ISOC. The HWO but is never reset */
++ trb_st_hw = &dep->trb_pool[0];
++
++ trb_link.bplh = dwc3_trb_dma_offset(dep, trb_st_hw);
++ trb_link.trbctl = DWC3_TRBCTL_LINK_TRB;
++ trb_link.hwo = true;
++
++ trb_link_hw = &dep->trb_pool[DWC3_TRB_NUM - 1];
++ dwc3_trb_to_hw(&trb_link, trb_link_hw);
++ }
++
++ return 0;
++}
++
++static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum);
++static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
++{
++ struct dwc3_request *req;
++
++ if (!list_empty(&dep->req_queued))
++ dwc3_stop_active_transfer(dwc, dep->number);
++
++ while (!list_empty(&dep->request_list)) {
++ req = next_request(&dep->request_list);
++
++ dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
++ }
++}
++
++/**
++ * __dwc3_gadget_ep_disable - Disables a HW endpoint
++ * @dep: the endpoint to disable
++ *
++ * This function also removes requests which are currently processed ny the
++ * hardware and those which are not yet scheduled.
++ * Caller should take care of locking.
++ */
++static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
++{
++ struct dwc3 *dwc = dep->dwc;
++ u32 reg;
++
++ dwc3_remove_requests(dwc, dep);
++
++ reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
++ reg &= ~DWC3_DALEPENA_EP(dep->number);
++ dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
++
++ dep->stream_capable = false;
++ dep->desc = NULL;
++ dep->comp_desc = NULL;
++ dep->type = 0;
++ dep->flags = 0;
++
++ return 0;
++}
++
++/* -------------------------------------------------------------------------- */
++
++static int dwc3_gadget_ep0_enable(struct usb_ep *ep,
++ const struct usb_endpoint_descriptor *desc)
++{
++ return -EINVAL;
++}
++
++static int dwc3_gadget_ep0_disable(struct usb_ep *ep)
++{
++ return -EINVAL;
++}
++
++/* -------------------------------------------------------------------------- */
++
++static int dwc3_gadget_ep_enable(struct usb_ep *ep,
++ const struct usb_endpoint_descriptor *desc)
++{
++ struct dwc3_ep *dep;
++ struct dwc3 *dwc;
++ unsigned long flags;
++ int ret;
++
++ if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) {
++ pr_debug("dwc3: invalid parameters\n");
++ return -EINVAL;
++ }
++
++ if (!desc->wMaxPacketSize) {
++ pr_debug("dwc3: missing wMaxPacketSize\n");
++ return -EINVAL;
++ }
++
++ dep = to_dwc3_ep(ep);
++ dwc = dep->dwc;
++
++ switch (usb_endpoint_type(desc)) {
++ case USB_ENDPOINT_XFER_CONTROL:
++ strncat(dep->name, "-control", sizeof(dep->name));
++ break;
++ case USB_ENDPOINT_XFER_ISOC:
++ strncat(dep->name, "-isoc", sizeof(dep->name));
++ break;
++ case USB_ENDPOINT_XFER_BULK:
++ strncat(dep->name, "-bulk", sizeof(dep->name));
++ break;
++ case USB_ENDPOINT_XFER_INT:
++ strncat(dep->name, "-int", sizeof(dep->name));
++ break;
++ default:
++ dev_err(dwc->dev, "invalid endpoint transfer type\n");
++ }
++
++ if (dep->flags & DWC3_EP_ENABLED) {
++ dev_WARN_ONCE(dwc->dev, true, "%s is already enabled\n",
++ dep->name);
++ return 0;
++ }
++
++ dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
++
++ spin_lock_irqsave(&dwc->lock, flags);
++ ret = __dwc3_gadget_ep_enable(dep, desc, NULL /*ep->comp_desc*/);
++ spin_unlock_irqrestore(&dwc->lock, flags);
++
++ return ret;
++}
++
++static int dwc3_gadget_ep_disable(struct usb_ep *ep)
++{
++ struct dwc3_ep *dep;
++ struct dwc3 *dwc;
++ unsigned long flags;
++ int ret;
++
++ if (!ep) {
++ pr_debug("dwc3: invalid parameters\n");
++ return -EINVAL;
++ }
++
++ dep = to_dwc3_ep(ep);
++ dwc = dep->dwc;
++
++ if (!(dep->flags & DWC3_EP_ENABLED)) {
++ dev_WARN_ONCE(dwc->dev, true, "%s is already disabled\n",
++ dep->name);
++ return 0;
++ }
++
++ snprintf(dep->name, sizeof(dep->name), "ep%d%s",
++ dep->number >> 1,
++ (dep->number & 1) ? "in" : "out");
++
++ spin_lock_irqsave(&dwc->lock, flags);
++ ret = __dwc3_gadget_ep_disable(dep);
++ spin_unlock_irqrestore(&dwc->lock, flags);
++
++ return ret;
++}
++
++static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep,
++ gfp_t gfp_flags)
++{
++ struct dwc3_request *req;
++ struct dwc3_ep *dep = to_dwc3_ep(ep);
++
++ req = kzalloc(sizeof(*req), gfp_flags);
++ if (!req) {
++ dev_err(dwc->dev, "not enough memory\n");
++ return NULL;
++ }
++
++ req->epnum = dep->number;
++ req->dep = dep;
++ req->request.dma = DMA_ADDR_INVALID;
++
++ return &req->request;
++}
++
++static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
++ struct usb_request *request)
++{
++ struct dwc3_request *req = to_dwc3_request(request);
++
++ kfree(req);
++}
++
++/*
++ * dwc3_prepare_trbs - setup TRBs from requests
++ * @dep: endpoint for which requests are being prepared
++ * @starting: true if the endpoint is idle and no requests are queued.
++ *
++ * The functions goes through the requests list and setups TRBs for the
++ * transfers. The functions returns once there are not more TRBs available or
++ * it run out of requests.
++ */
++static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep,
++ bool starting)
++{
++ struct dwc3_request *req, *n, *ret = NULL;
++ struct dwc3_trb_hw *trb_hw;
++ struct dwc3_trb trb;
++ u32 trbs_left;
++
++ BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
++
++ /* the first request must not be queued */
++ trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
++ /*
++ * if busy & slot are equal than it is either full or empty. If we are
++ * starting to proceed requests then we are empty. Otherwise we ar
++ * full and don't do anything
++ */
++ if (!trbs_left) {
++ if (!starting)
++ return NULL;
++ trbs_left = DWC3_TRB_NUM;
++ /*
++ * In case we start from scratch, we queue the ISOC requests
++ * starting from slot 1. This is done because we use ring
++ * buffer and have no LST bit to stop us. Instead, we place
++ * IOC bit TRB_NUM/4. We try to avoid to having an interrupt
++ * after the first request so we start at slot 1 and have
++ * 7 requests proceed before we hit the first IOC.
++ * Other transfer types don't use the ring buffer and are
++ * processed from the first TRB until the last one. Since we
++ * don't wrap around we have to start at the beginning.
++ */
++ if (usb_endpoint_xfer_isoc(dep->desc)) {
++ dep->busy_slot = 1;
++ dep->free_slot = 1;
++ } else {
++ dep->busy_slot = 0;
++ dep->free_slot = 0;
++ }
++ }
++
++ /* The last TRB is a link TRB, not used for xfer */
++ if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->desc))
++ return NULL;
++
++ list_for_each_entry_safe(req, n, &dep->request_list, list) {
++ unsigned int last_one = 0;
++ unsigned int cur_slot;
++
++ trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
++ cur_slot = dep->free_slot;
++ dep->free_slot++;
++
++ /* Skip the LINK-TRB on ISOC */
++ if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
++ usb_endpoint_xfer_isoc(dep->desc))
++ continue;
++
++ dwc3_gadget_move_request_queued(req);
++ memset(&trb, 0, sizeof(trb));
++ trbs_left--;
++
++ /* Is our TRB pool empty? */
++ if (!trbs_left)
++ last_one = 1;
++ /* Is this the last request? */
++ if (list_empty(&dep->request_list))
++ last_one = 1;
++
++ /*
++ * FIXME we shouldn't need to set LST bit always but we are
++ * facing some weird problem with the Hardware where it doesn't
++ * complete even though it has been previously started.
++ *
++ * While we're debugging the problem, as a workaround to
++ * multiple TRBs handling, use only one TRB at a time.
++ */
++ last_one = 1;
++
++ req->trb = trb_hw;
++ if (!ret)
++ ret = req;
++
++ trb.bplh = req->request.dma;
++
++ if (usb_endpoint_xfer_isoc(dep->desc)) {
++ trb.isp_imi = true;
++ trb.csp = true;
++ } else {
++ trb.lst = last_one;
++ }
++
++ if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
++ trb.sid_sofn = req->request.stream_id;
++
++ switch (usb_endpoint_type(dep->desc)) {
++ case USB_ENDPOINT_XFER_CONTROL:
++ trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
++ break;
++
++ case USB_ENDPOINT_XFER_ISOC:
++ trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
++
++ /* IOC every DWC3_TRB_NUM / 4 so we can refill */
++ if (!(cur_slot % (DWC3_TRB_NUM / 4)))
++ trb.ioc = last_one;
++ break;
++
++ case USB_ENDPOINT_XFER_BULK:
++ case USB_ENDPOINT_XFER_INT:
++ trb.trbctl = DWC3_TRBCTL_NORMAL;
++ break;
++ default:
++ /*
++ * This is only possible with faulty memory because we
++ * checked it already :)
++ */
++ BUG();
++ }
++
++ trb.length = req->request.length;
++ trb.hwo = true;
++
++ dwc3_trb_to_hw(&trb, trb_hw);
++ req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw);
++
++ if (last_one)
++ break;
++ }
++
++ return ret;
++}
++
++static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
++ int start_new)
++{
++ struct dwc3_gadget_ep_cmd_params params;
++ struct dwc3_request *req;
++ struct dwc3 *dwc = dep->dwc;
++ int ret;
++ u32 cmd;
++
++ if (start_new && (dep->flags & DWC3_EP_BUSY)) {
++ dev_vdbg(dwc->dev, "%s: endpoint busy\n", dep->name);
++ return -EBUSY;
++ }
++ dep->flags &= ~DWC3_EP_PENDING_REQUEST;
++
++ /*
++ * If we are getting here after a short-out-packet we don't enqueue any
++ * new requests as we try to set the IOC bit only on the last request.
++ */
++ if (start_new) {
++ if (list_empty(&dep->req_queued))
++ dwc3_prepare_trbs(dep, start_new);
++
++ /* req points to the first request which will be sent */
++ req = next_request(&dep->req_queued);
++ } else {
++ /*
++ * req points to the first request where HWO changed
++ * from 0 to 1
++ */
++ req = dwc3_prepare_trbs(dep, start_new);
++ }
++ if (!req) {
++ dep->flags |= DWC3_EP_PENDING_REQUEST;
++ return 0;
++ }
++
++ memset(&params, 0, sizeof(params));
++ params.param0 = upper_32_bits(req->trb_dma);
++ params.param1 = lower_32_bits(req->trb_dma);
++
++ if (start_new)
++ cmd = DWC3_DEPCMD_STARTTRANSFER;
++ else
++ cmd = DWC3_DEPCMD_UPDATETRANSFER;
++
++ cmd |= DWC3_DEPCMD_PARAM(cmd_param);
++ ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
++ if (ret < 0) {
++ dev_dbg(dwc->dev, "failed to send STARTTRANSFER command\n");
++
++ /*
++ * FIXME we need to iterate over the list of requests
++ * here and stop, unmap, free and del each of the linked
++ * requests instead of we do now.
++ */
++ dwc3_unmap_buffer_from_dma(req);
++ list_del(&req->list);
++ return ret;
++ }
++
++ dep->flags |= DWC3_EP_BUSY;
++ dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
++ dep->number);
++ return 0;
++}
++
++static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
++{
++ req->request.actual = 0;
++ req->request.status = -EINPROGRESS;
++ req->direction = dep->direction;
++ req->epnum = dep->number;
++
++ /*
++ * We only add to our list of requests now and
++ * start consuming the list once we get XferNotReady
++ * IRQ.
++ *
++ * That way, we avoid doing anything that we don't need
++ * to do now and defer it until the point we receive a
++ * particular token from the Host side.
++ *
++ * This will also avoid Host cancelling URBs due to too
++ * many NACKs.
++ */
++ dwc3_map_buffer_to_dma(req);
++ list_add_tail(&req->list, &dep->request_list);
++
++ /*
++ * There is one special case: XferNotReady with
++ * empty list of requests. We need to kick the
++ * transfer here in that situation, otherwise
++ * we will be NAKing forever.
++ *
++ * If we get XferNotReady before gadget driver
++ * has a chance to queue a request, we will ACK
++ * the IRQ but won't be able to receive the data
++ * until the next request is queued. The following
++ * code is handling exactly that.
++ */
++ if (dep->flags & DWC3_EP_PENDING_REQUEST) {
++ int ret;
++ int start_trans;
++
++ start_trans = 1;
++ if (usb_endpoint_xfer_isoc(dep->desc) &&
++ dep->flags & DWC3_EP_BUSY)
++ start_trans = 0;
++
++ ret = __dwc3_gadget_kick_transfer(dep, 0, start_trans);
++ if (ret && ret != -EBUSY) {
++ struct dwc3 *dwc = dep->dwc;
++
++ dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
++ dep->name);
++ }
++ };
++
++ return 0;
++}
++
++static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
++ gfp_t gfp_flags)
++{
++ struct dwc3_request *req = to_dwc3_request(request);
++ struct dwc3_ep *dep = to_dwc3_ep(ep);
++ struct dwc3 *dwc = dep->dwc;
++
++ unsigned long flags;
++
++ int ret;
++
++ if (!dep->desc) {
++ dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
++ request, ep->name);
++ return -ESHUTDOWN;
++ }
++
++ dev_vdbg(dwc->dev, "queing request %p to %s length %d\n",
++ request, ep->name, request->length);
++
++ spin_lock_irqsave(&dwc->lock, flags);
++ ret = __dwc3_gadget_ep_queue(dep, req);
++ spin_unlock_irqrestore(&dwc->lock, flags);
++
++ return ret;
++}
++
++static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
++ struct usb_request *request)
++{
++ struct dwc3_request *req = to_dwc3_request(request);
++ struct dwc3_request *r = NULL;
++
++ struct dwc3_ep *dep = to_dwc3_ep(ep);
++ struct dwc3 *dwc = dep->dwc;
++
++ unsigned long flags;
++ int ret = 0;
++
++ spin_lock_irqsave(&dwc->lock, flags);
++
++ list_for_each_entry(r, &dep->request_list, list) {
++ if (r == req)
++ break;
++ }
++
++ if (r != req) {
++ list_for_each_entry(r, &dep->req_queued, list) {
++ if (r == req)
++ break;
++ }
++ if (r == req) {
++ /* wait until it is processed */
++ dwc3_stop_active_transfer(dwc, dep->number);
++ goto out0;
++ }
++ dev_err(dwc->dev, "request %p was not queued to %s\n",
++ request, ep->name);
++ ret = -EINVAL;
++ goto out0;
++ }
++
++ /* giveback the request */
++ dwc3_gadget_giveback(dep, req, -ECONNRESET);
++
++out0:
++ spin_unlock_irqrestore(&dwc->lock, flags);
++
++ return ret;
++}
++
++int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value)
++{
++ struct dwc3_gadget_ep_cmd_params params;
++ struct dwc3 *dwc = dep->dwc;
++ int ret;
++
++ memset(&params, 0x00, sizeof(params));
++
++ if (value) {
++ if (dep->number == 0 || dep->number == 1) {
++ /*
++ * Whenever EP0 is stalled, we will restart
++ * the state machine, thus moving back to
++ * Setup Phase
++ */
++ dwc->ep0state = EP0_SETUP_PHASE;
++ }
++
++ ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
++ DWC3_DEPCMD_SETSTALL, &params);
++ if (ret)
++ dev_err(dwc->dev, "failed to %s STALL on %s\n",
++ value ? "set" : "clear",
++ dep->name);
++ else
++ dep->flags |= DWC3_EP_STALL;
++ } else {
++ if (dep->flags & DWC3_EP_WEDGE)
++ return 0;
++
++ ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
++ DWC3_DEPCMD_CLEARSTALL, &params);
++ if (ret)
++ dev_err(dwc->dev, "failed to %s STALL on %s\n",
++ value ? "set" : "clear",
++ dep->name);
++ else
++ dep->flags &= ~DWC3_EP_STALL;
++ }
++
++ return ret;
++}
++
++static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value)
++{
++ struct dwc3_ep *dep = to_dwc3_ep(ep);
++
++ unsigned long flags;
++
++ int ret;
++
++ spin_lock_irqsave(&dwc->lock, flags);
++
++ if (usb_endpoint_xfer_isoc(dep->desc)) {
++ dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name);
++ ret = -EINVAL;
++ goto out;
++ }
++
++ ret = __dwc3_gadget_ep_set_halt(dep, value);
++out:
++ spin_unlock_irqrestore(&dwc->lock, flags);
++
++ return ret;
++}
++
++/* -------------------------------------------------------------------------- */
++
++static struct usb_endpoint_descriptor dwc3_gadget_ep0_desc = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
++};
++
++static const struct usb_ep_ops dwc3_gadget_ep0_ops = {
++ .enable = dwc3_gadget_ep0_enable,
++ .disable = dwc3_gadget_ep0_disable,
++ .alloc_request = dwc3_gadget_ep_alloc_request,
++ .free_request = dwc3_gadget_ep_free_request,
++ .queue = dwc3_gadget_ep0_queue,
++ .dequeue = dwc3_gadget_ep_dequeue,
++ .set_halt = dwc3_gadget_ep_set_halt,
++};
++
++static const struct usb_ep_ops dwc3_gadget_ep_ops = {
++ .enable = dwc3_gadget_ep_enable,
++ .disable = dwc3_gadget_ep_disable,
++ .alloc_request = dwc3_gadget_ep_alloc_request,
++ .free_request = dwc3_gadget_ep_free_request,
++ .queue = dwc3_gadget_ep_queue,
++ .dequeue = dwc3_gadget_ep_dequeue,
++ .set_halt = dwc3_gadget_ep_set_halt,
++};
++
++/* -------------------------------------------------------------------------- */
++
++static int dwc3_gadget_get_frame(struct usb_gadget *g)
++{
++ struct dwc3 *dwc = gadget_to_dwc(g);
++ u32 reg;
++
++ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
++ return DWC3_DSTS_SOFFN(reg);
++}
++
++static int dwc3_gadget_wakeup(struct usb_gadget *g)
++{
++ struct dwc3 *dwc = gadget_to_dwc(g);
++
++ unsigned long timeout;
++ unsigned long flags;
++
++ u32 reg;
++
++ int ret = 0;
++
++ u8 link_state;
++ u8 speed;
++
++ spin_lock_irqsave(&dwc->lock, flags);
++
++ /*
++ * According to the Databook Remote wakeup request should
++ * be issued only when the device is in early suspend state.
++ *
++ * We can check that via USB Link State bits in DSTS register.
++ */
++ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
++
++ speed = reg & DWC3_DSTS_CONNECTSPD;
++ if (speed == DWC3_DSTS_SUPERSPEED) {
++ dev_dbg(dwc->dev, "no wakeup on SuperSpeed\n");
++ ret = -EINVAL;
++ goto out;
++ }
++
++ link_state = DWC3_DSTS_USBLNKST(reg);
++
++ switch (link_state) {
++ case DWC3_LINK_STATE_RX_DET: /* in HS, means Early Suspend */
++ case DWC3_LINK_STATE_U3: /* in HS, means SUSPEND */
++ break;
++ default:
++ dev_dbg(dwc->dev, "can't wakeup from link state %d\n",
++ link_state);
++ ret = -EINVAL;
++ goto out;
++ }
++
++ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
++
++ /*
++ * Switch link state to Recovery. In HS/FS/LS this means
++ * RemoteWakeup Request
++ */
++ reg |= DWC3_DCTL_ULSTCHNG_RECOVERY;
++ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
++
++ /* wait for at least 2000us */
++ usleep_range(2000, 2500);
++
++ /* write zeroes to Link Change Request */
++ reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
++ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
++
++ /* pool until Link State change to ON */
++ timeout = 100;
++
++ while (timeout) {
++ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
++
++ /* in HS, means ON */
++ if (DWC3_DSTS_USBLNKST(reg) == DWC3_LINK_STATE_U0)
++ break;
++ timeout--;
++ mdelay(1);
++ }
++
++ if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) {
++ dev_err(dwc->dev, "failed to send remote wakeup\n");
++ ret = -EINVAL;
++ }
++
++out:
++ spin_unlock_irqrestore(&dwc->lock, flags);
++
++ return ret;
++}
++
++static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
++ int is_selfpowered)
++{
++ struct dwc3 *dwc = gadget_to_dwc(g);
++
++ dwc->is_selfpowered = !!is_selfpowered;
++
++ return 0;
++}
++
++static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
++{
++ u32 reg;
++ u32 timeout = 500;
++
++ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
++ if (is_on)
++ reg |= DWC3_DCTL_RUN_STOP;
++ else
++ reg &= ~DWC3_DCTL_RUN_STOP;
++
++ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
++
++ do {
++ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
++ if (is_on) {
++ if (!(reg & DWC3_DSTS_DEVCTRLHLT))
++ break;
++ } else {
++ if (reg & DWC3_DSTS_DEVCTRLHLT)
++ break;
++ }
++ timeout--;
++ if (!timeout)
++ break;
++ udelay(1);
++ } while (1);
++}
++
++static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
++{
++ struct dwc3 *dwc = gadget_to_dwc(g);
++ unsigned long flags;
++
++ is_on = !!is_on;
++
++ spin_lock_irqsave(&dwc->lock, flags);
++ dwc3_gadget_run_stop(dwc, is_on);
++ spin_unlock_irqrestore(&dwc->lock, flags);
++
++ return 0;
++}
++
++static int dwc3_gadget_start(struct usb_gadget *g,
++ struct usb_gadget_driver *driver)
++{
++ struct dwc3 *dwc = gadget_to_dwc(g);
++ struct dwc3_ep *dep;
++ unsigned long flags;
++ int ret = 0;
++ u32 reg;
++
++ spin_lock_irqsave(&dwc->lock, flags);
++
++ if (dwc->gadget_driver) {
++ dev_err(dwc->dev, "%s is already bound\n",
++ dwc->gadget.name);
++ ret = -EBUSY;
++ goto err0;
++ }
++
++ dwc->gadget_driver = driver;
++ /* dwc->gadget.dev.driver = &driver->driver; */
++
++ reg = dwc3_readl(dwc->regs, DWC3_DCFG);
++ reg &= ~(DWC3_DCFG_SPEED_MASK);
++ reg |= dwc->maximum_speed;
++ dwc3_writel(dwc->regs, DWC3_DCFG, reg);
++
++ dwc->start_config_issued = false;
++
++ /* Start with SuperSpeed Default */
++ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
++
++ dep = dwc->eps[0];
++ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
++ if (ret) {
++ dev_err(dwc->dev, "failed to enable %s\n", dep->name);
++ goto err0;
++ }
++
++ dep = dwc->eps[1];
++ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
++ if (ret) {
++ dev_err(dwc->dev, "failed to enable %s\n", dep->name);
++ goto err1;
++ }
++
++ /* begin to receive SETUP packets */
++ dwc->ep0state = EP0_SETUP_PHASE;
++ dwc3_ep0_out_start(dwc);
++
++ spin_unlock_irqrestore(&dwc->lock, flags);
++
++ return 0;
++
++err1:
++ __dwc3_gadget_ep_disable(dwc->eps[0]);
++
++err0:
++ spin_unlock_irqrestore(&dwc->lock, flags);
++
++ return ret;
++}
++
++#if 0
++static int dwc3_gadget_stop(struct usb_gadget *g,
++ struct usb_gadget_driver *driver)
++{
++ struct dwc3 *dwc = gadget_to_dwc(g);
++ unsigned long flags;
++
++ spin_lock_irqsave(&dwc->lock, flags);
++
++ __dwc3_gadget_ep_disable(dwc->eps[0]);
++ __dwc3_gadget_ep_disable(dwc->eps[1]);
++
++ dwc->gadget_driver = NULL;
++
++ spin_unlock_irqrestore(&dwc->lock, flags);
++
++ return 0;
++}
++#endif
++static const struct usb_gadget_ops dwc3_gadget_ops = {
++ .get_frame = dwc3_gadget_get_frame,
++ .wakeup = dwc3_gadget_wakeup,
++ .set_selfpowered = dwc3_gadget_set_selfpowered,
++ .pullup = dwc3_gadget_pullup,
++
++
++};
++
++int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
++ int (*bind)(struct usb_gadget *))
++{
++ int ret;
++
++ ret = bind(&global_dwc3->gadget);
++ if (ret)
++ return ret;
++ ret = dwc3_gadget_start(&global_dwc3->gadget, driver);
++ if (ret)
++ return ret;
++ ret = usb_gadget_connect(&global_dwc3->gadget);
++ if (ret)
++ return ret;
++ return 0;
++}
++
++/* -------------------------------------------------------------------------- */
++
++static int __devinit dwc3_gadget_init_endpoints(struct dwc3 *dwc)
++{
++ struct dwc3_ep *dep;
++ u8 epnum;
++
++ INIT_LIST_HEAD(&dwc->gadget.ep_list);
++
++ for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
++ dep = kzalloc(sizeof(*dep), GFP_KERNEL);
++ if (!dep) {
++ dev_err(dwc->dev, "can't allocate endpoint %d\n",
++ epnum);
++ return -ENOMEM;
++ }
++
++ dep->dwc = dwc;
++ dep->number = epnum;
++ dwc->eps[epnum] = dep;
++
++ snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1,
++ (epnum & 1) ? "in" : "out");
++ dep->endpoint.name = dep->name;
++ dep->direction = (epnum & 1);
++
++ if (epnum == 0 || epnum == 1) {
++ dep->endpoint.maxpacket = 64;
++ dep->endpoint.ops = &dwc3_gadget_ep0_ops;
++ if (!epnum)
++ dwc->gadget.ep0 = &dep->endpoint;
++ } else {
++ int ret;
++
++ dep->endpoint.maxpacket = 1024;
++ dep->endpoint.ops = &dwc3_gadget_ep_ops;
++ list_add_tail(&dep->endpoint.ep_list,
++ &dwc->gadget.ep_list);
++
++ ret = dwc3_alloc_trb_pool(dep);
++ if (ret)
++ return ret;
++ }
++
++ INIT_LIST_HEAD(&dep->request_list);
++ INIT_LIST_HEAD(&dep->req_queued);
++ }
++
++ return 0;
++}
++
++static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
++{
++ struct dwc3_ep *dep;
++ u8 epnum;
++
++ for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
++ dep = dwc->eps[epnum];
++ dwc3_free_trb_pool(dep);
++
++ if (epnum != 0 && epnum != 1)
++ list_del(&dep->endpoint.ep_list);
++
++ kfree(dep);
++ }
++}
++
++static struct dwc3 *the_dwc;
++
++/* -------------------------------------------------------------------------- */
++static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
++ const struct dwc3_event_depevt *event, int status)
++{
++ struct dwc3_request *req;
++ struct dwc3_trb trb;
++ unsigned int count;
++ unsigned int s_pkt = 0;
++
++ do {
++ req = next_request(&dep->req_queued);
++ if (!req) {
++ WARN_ON_ONCE(1);
++ return 1;
++ }
++
++ dwc3_trb_to_nat(req->trb, &trb);
++
++ if (trb.hwo && status != -ESHUTDOWN)
++ /*
++ * We continue despite the error. There is not much we
++ * can do. If we don't clean in up we loop for ever. If
++ * we skip the TRB than it gets overwritten reused after
++ * a while since we use them in a ring buffer. a BUG()
++ * would help. Lets hope that if this occures, someone
++ * fixes the root cause instead of looking away :)
++ */
++ dev_err(dwc->dev, "%s's TRB (%p) still owned by HW\n",
++ dep->name, req->trb);
++ count = trb.length;
++
++ if (dep->direction) {
++ if (count) {
++ dev_err(dwc->dev, "incomplete IN transfer %s\n",
++ dep->name);
++ status = -ECONNRESET;
++ }
++ } else {
++ if (count && (event->status & DEPEVT_STATUS_SHORT))
++ s_pkt = 1;
++ }
++
++ /*
++ * We assume here we will always receive the entire data block
++ * which we should receive. Meaning, if we program RX to
++ * receive 4K but we receive only 2K, we assume that's all we
++ * should receive and we simply bounce the request back to the
++ * gadget driver for further processing.
++ */
++ req->request.actual += req->request.length - count;
++ dwc3_gadget_giveback(dep, req, status);
++ if (s_pkt)
++ break;
++ if ((event->status & DEPEVT_STATUS_LST) && trb.lst)
++ break;
++ if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
++ break;
++ } while (1);
++
++ if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
++ return 0;
++ return 1;
++}
++
++static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
++ struct dwc3_ep *dep, const struct dwc3_event_depevt *event,
++ int start_new)
++{
++ unsigned status = 0;
++ int clean_busy;
++
++ if (event->status & DEPEVT_STATUS_BUSERR)
++ status = -ECONNRESET;
++
++ clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status);
++ if (clean_busy) {
++ dep->flags &= ~DWC3_EP_BUSY;
++ dep->res_trans_idx = 0;
++ }
++
++ /*
++ * WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround.
++ * See dwc3_gadget_linksts_change_interrupt() for 1st half.
++ */
++ if (dwc->revision < DWC3_REVISION_183A) {
++ u32 reg;
++ int i;
++
++ for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) {
++ struct dwc3_ep *dep = dwc->eps[i];
++
++ if (!(dep->flags & DWC3_EP_ENABLED))
++ continue;
++
++ if (!list_empty(&dep->req_queued))
++ return;
++ }
++
++ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
++ reg |= dwc->u1u2;
++ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
++
++ dwc->u1u2 = 0;
++ }
++}
++
++static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
++ struct dwc3_ep *dep, const struct dwc3_event_depevt *event)
++{
++ u32 uf;
++
++ if (list_empty(&dep->request_list)) {
++ dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n",
++ dep->name);
++ return;
++ }
++
++ if (event->parameters) {
++ u32 mask;
++
++ mask = ~(dep->interval - 1);
++ uf = event->parameters & mask;
++ /* 4 micro frames in the future */
++ uf += dep->interval * 4;
++ } else {
++ uf = 0;
++ }
++
++ __dwc3_gadget_kick_transfer(dep, uf, 1);
++}
++
++static void dwc3_process_ep_cmd_complete(struct dwc3_ep *dep,
++ const struct dwc3_event_depevt *event)
++{
++ struct dwc3 *dwc = dep->dwc;
++ struct dwc3_event_depevt mod_ev = *event;
++
++ /*
++ * We were asked to remove one requests. It is possible that this
++ * request and a few other were started together and have the same
++ * transfer index. Since we stopped the complete endpoint we don't
++ * know how many requests were already completed (and not yet)
++ * reported and how could be done (later). We purge them all until
++ * the end of the list.
++ */
++ mod_ev.status = DEPEVT_STATUS_LST;
++ dwc3_cleanup_done_reqs(dwc, dep, &mod_ev, -ESHUTDOWN);
++ dep->flags &= ~DWC3_EP_BUSY;
++ /* pending requets are ignored and are queued on XferNotReady */
++}
++
++static void dwc3_ep_cmd_compl(struct dwc3_ep *dep,
++ const struct dwc3_event_depevt *event)
++{
++ u32 param = event->parameters;
++ u32 cmd_type = (param >> 8) & ((1 << 5) - 1);
++
++ switch (cmd_type) {
++ case DWC3_DEPCMD_ENDTRANSFER:
++ dwc3_process_ep_cmd_complete(dep, event);
++ break;
++ case DWC3_DEPCMD_STARTTRANSFER:
++ dep->res_trans_idx = param & 0x7f;
++ break;
++ default:
++ break;
++ };
++}
++
++static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
++ const struct dwc3_event_depevt *event)
++{
++ struct dwc3_ep *dep;
++ u8 epnum = event->endpoint_number;
++
++ dep = dwc->eps[epnum];
++
++ dev_vdbg(dwc->dev, "%s: %s\n", dep->name,
++ dwc3_ep_event_string(event->endpoint_event));
++
++ if (epnum == 0 || epnum == 1) {
++ dwc3_ep0_interrupt(dwc, event);
++ return;
++ }
++
++ switch (event->endpoint_event) {
++ case DWC3_DEPEVT_XFERCOMPLETE:
++ if (usb_endpoint_xfer_isoc(dep->desc)) {
++ dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n",
++ dep->name);
++ return;
++ }
++
++ dwc3_endpoint_transfer_complete(dwc, dep, event, 1);
++ break;
++ case DWC3_DEPEVT_XFERINPROGRESS:
++ if (!usb_endpoint_xfer_isoc(dep->desc)) {
++ dev_dbg(dwc->dev, "%s is not an Isochronous endpoint\n",
++ dep->name);
++ return;
++ }
++
++ dwc3_endpoint_transfer_complete(dwc, dep, event, 0);
++ break;
++ case DWC3_DEPEVT_XFERNOTREADY:
++ if (usb_endpoint_xfer_isoc(dep->desc)) {
++ dwc3_gadget_start_isoc(dwc, dep, event);
++ } else {
++ int ret;
++
++ dev_vdbg(dwc->dev, "%s: reason %s\n",
++ dep->name, event->status
++ ? "Transfer Active"
++ : "Transfer Not Active");
++
++ ret = __dwc3_gadget_kick_transfer(dep, 0, 1);
++ if (!ret || ret == -EBUSY)
++ return;
++ dev_dbg(dwc->dev, "%s: failed to kick transfers %d.\n",
++ dep->name, ret);
++ }
++
++ break;
++ case DWC3_DEPEVT_STREAMEVT:
++ if (!usb_endpoint_xfer_bulk(dep->desc)) {
++ dev_err(dwc->dev, "Stream event for non-Bulk %s\n",
++ dep->name);
++ return;
++ }
++
++ switch (event->status) {
++ case DEPEVT_STREAMEVT_FOUND:
++ dev_vdbg(dwc->dev, "Stream %d found and started\n",
++ event->parameters);
++
++ break;
++ case DEPEVT_STREAMEVT_NOTFOUND:
++ /* FALLTHROUGH */
++ default:
++ dev_dbg(dwc->dev, "Couldn't find suitable stream\n");
++ }
++ break;
++ case DWC3_DEPEVT_RXTXFIFOEVT:
++ dev_dbg(dwc->dev, "%s FIFO Overrun\n", dep->name);
++ break;
++ case DWC3_DEPEVT_EPCMDCMPLT:
++ dwc3_ep_cmd_compl(dep, event);
++ break;
++ }
++}
++
++static void dwc3_disconnect_gadget(struct dwc3 *dwc)
++{
++ if (dwc->gadget_driver && dwc->gadget_driver->disconnect) {
++ spin_unlock(&dwc->lock);
++ dwc->gadget_driver->disconnect(&dwc->gadget);
++ spin_lock(&dwc->lock);
++ }
++}
++
++static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
++{
++ struct dwc3_ep *dep;
++ struct dwc3_gadget_ep_cmd_params params;
++ u32 cmd;
++ int ret;
++
++ dep = dwc->eps[epnum];
++
++ WARN_ON(!dep->res_trans_idx);
++ if (dep->res_trans_idx) {
++ cmd = DWC3_DEPCMD_ENDTRANSFER;
++ cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC;
++ cmd |= DWC3_DEPCMD_PARAM(dep->res_trans_idx);
++ memset(&params, 0, sizeof(params));
++ ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
++ WARN_ON_ONCE(ret);
++ dep->res_trans_idx = 0;
++ }
++}
++
++static void dwc3_stop_active_transfers(struct dwc3 *dwc)
++{
++ u32 epnum;
++
++ for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
++ struct dwc3_ep *dep;
++
++ dep = dwc->eps[epnum];
++ if (!(dep->flags & DWC3_EP_ENABLED))
++ continue;
++
++ dwc3_remove_requests(dwc, dep);
++ }
++}
++
++static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
++{
++ u32 epnum;
++
++ for (epnum = 1; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
++ struct dwc3_ep *dep;
++ struct dwc3_gadget_ep_cmd_params params;
++ int ret;
++
++ dep = dwc->eps[epnum];
++
++ if (!(dep->flags & DWC3_EP_STALL))
++ continue;
++
++ dep->flags &= ~DWC3_EP_STALL;
++
++ memset(&params, 0, sizeof(params));
++ ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
++ DWC3_DEPCMD_CLEARSTALL, &params);
++ WARN_ON_ONCE(ret);
++ }
++}
++
++static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
++{
++ dev_vdbg(dwc->dev, "%s\n", __func__);
++#if 0
++ XXX
++ U1/U2 is powersave optimization. Skip it for now. Anyway we need to
++ enable it before we can disable it.
++
++ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
++ reg &= ~DWC3_DCTL_INITU1ENA;
++ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
++
++ reg &= ~DWC3_DCTL_INITU2ENA;
++ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
++#endif
++
++ dwc3_stop_active_transfers(dwc);
++ dwc3_disconnect_gadget(dwc);
++ dwc->start_config_issued = false;
++
++ dwc->gadget.speed = USB_SPEED_UNKNOWN;
++ dwc->setup_packet_pending = false;
++}
++
++static void dwc3_gadget_usb3_phy_power(struct dwc3 *dwc, int on)
++{
++ u32 reg;
++
++ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
++
++ if (on)
++ reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
++ else
++ reg |= DWC3_GUSB3PIPECTL_SUSPHY;
++
++ dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
++}
++
++static void dwc3_gadget_usb2_phy_power(struct dwc3 *dwc, int on)
++{
++ u32 reg;
++
++ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
++
++ if (on)
++ reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
++ else
++ reg |= DWC3_GUSB2PHYCFG_SUSPHY;
++
++ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
++}
++
++static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
++{
++ u32 reg;
++
++ dev_vdbg(dwc->dev, "%s\n", __func__);
++
++ /*
++ * WORKAROUND: DWC3 revisions <1.88a have an issue which
++ * would cause a missing Disconnect Event if there's a
++ * pending Setup Packet in the FIFO.
++ *
++ * There's no suggested workaround on the official Bug
++ * report, which states that "unless the driver/application
++ * is doing any special handling of a disconnect event,
++ * there is no functional issue".
++ *
++ * Unfortunately, it turns out that we _do_ some special
++ * handling of a disconnect event, namely complete all
++ * pending transfers, notify gadget driver of the
++ * disconnection, and so on.
++ *
++ * Our suggested workaround is to follow the Disconnect
++ * Event steps here, instead, based on a setup_packet_pending
++ * flag. Such flag gets set whenever we have a XferNotReady
++ * event on EP0 and gets cleared on XferComplete for the
++ * same endpoint.
++ *
++ * Refers to:
++ *
++ * STAR#9000466709: RTL: Device : Disconnect event not
++ * generated if setup packet pending in FIFO
++ */
++ if (dwc->revision < DWC3_REVISION_188A) {
++ if (dwc->setup_packet_pending)
++ dwc3_gadget_disconnect_interrupt(dwc);
++ }
++
++ /* Enable PHYs */
++ dwc3_gadget_usb2_phy_power(dwc, true);
++ dwc3_gadget_usb3_phy_power(dwc, true);
++
++ if (dwc->gadget.speed != USB_SPEED_UNKNOWN)
++ dwc3_disconnect_gadget(dwc);
++
++ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
++ reg &= ~DWC3_DCTL_TSTCTRL_MASK;
++ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
++
++ dwc3_stop_active_transfers(dwc);
++ dwc3_clear_stall_all_ep(dwc);
++ dwc->start_config_issued = false;
++
++ /* Reset device address to zero */
++ reg = dwc3_readl(dwc->regs, DWC3_DCFG);
++ reg &= ~(DWC3_DCFG_DEVADDR_MASK);
++ dwc3_writel(dwc->regs, DWC3_DCFG, reg);
++}
++
++static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed)
++{
++ u32 reg;
++ u32 usb30_clock = DWC3_GCTL_CLK_BUS;
++
++ /*
++ * We change the clock only at SS but I dunno why I would want to do
++ * this. Maybe it becomes part of the power saving plan.
++ */
++
++ if (speed != DWC3_DSTS_SUPERSPEED)
++ return;
++
++ /*
++ * RAMClkSel is reset to 0 after USB reset, so it must be reprogrammed
++ * each time on Connect Done.
++ */
++ if (!usb30_clock)
++ return;
++
++ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
++ reg |= DWC3_GCTL_RAMCLKSEL(usb30_clock);
++ dwc3_writel(dwc->regs, DWC3_GCTL, reg);
++}
++
++static void dwc3_gadget_disable_phy(struct dwc3 *dwc, u8 speed)
++{
++ switch (speed) {
++ case USB_SPEED_SUPER:
++ dwc3_gadget_usb2_phy_power(dwc, false);
++ break;
++ case USB_SPEED_HIGH:
++ case USB_SPEED_FULL:
++ case USB_SPEED_LOW:
++ dwc3_gadget_usb3_phy_power(dwc, false);
++ break;
++ }
++}
++
++static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
++{
++ struct dwc3_gadget_ep_cmd_params params;
++ struct dwc3_ep *dep;
++ int ret;
++ u32 reg;
++ u8 speed;
++
++ dev_vdbg(dwc->dev, "%s\n", __func__);
++
++ memset(&params, 0x00, sizeof(params));
++
++ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
++ speed = reg & DWC3_DSTS_CONNECTSPD;
++ dwc->speed = speed;
++
++ dwc3_update_ram_clk_sel(dwc, speed);
++
++ switch (speed) {
++ case DWC3_DCFG_SUPERSPEED:
++ /*
++ * WORKAROUND: DWC3 revisions <1.90a have an issue which
++ * would cause a missing USB3 Reset event.
++ *
++ * In such situations, we should force a USB3 Reset
++ * event by calling our dwc3_gadget_reset_interrupt()
++ * routine.
++ *
++ * Refers to:
++ *
++ * STAR#9000483510: RTL: SS : USB3 reset event may
++ * not be generated always when the link enters poll
++ */
++ if (dwc->revision < DWC3_REVISION_190A)
++ dwc3_gadget_reset_interrupt(dwc);
++
++ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
++ dwc->gadget.ep0->maxpacket = 512;
++ dwc->gadget.speed = USB_SPEED_SUPER;
++ break;
++ case DWC3_DCFG_HIGHSPEED:
++ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
++ dwc->gadget.ep0->maxpacket = 64;
++ dwc->gadget.speed = USB_SPEED_HIGH;
++ break;
++ case DWC3_DCFG_FULLSPEED2:
++ case DWC3_DCFG_FULLSPEED1:
++ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
++ dwc->gadget.ep0->maxpacket = 64;
++ dwc->gadget.speed = USB_SPEED_FULL;
++ break;
++ case DWC3_DCFG_LOWSPEED:
++ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(8);
++ dwc->gadget.ep0->maxpacket = 8;
++ dwc->gadget.speed = USB_SPEED_LOW;
++ break;
++ }
++
++ /* Disable unneded PHY */
++ dwc3_gadget_disable_phy(dwc, dwc->gadget.speed);
++
++ dep = dwc->eps[0];
++ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
++ if (ret) {
++ dev_err(dwc->dev, "failed to enable %s\n", dep->name);
++ return;
++ }
++
++ dep = dwc->eps[1];
++ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
++ if (ret) {
++ dev_err(dwc->dev, "failed to enable %s\n", dep->name);
++ return;
++ }
++
++ /*
++ * Configure PHY via GUSB3PIPECTLn if required.
++ *
++ * Update GTXFIFOSIZn
++ *
++ * In both cases reset values should be sufficient.
++ */
++}
++
++static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
++{
++ dev_vdbg(dwc->dev, "%s\n", __func__);
++
++ /*
++ * TODO take core out of low power mode when that's
++ * implemented.
++ */
++
++ dwc->gadget_driver->resume(&dwc->gadget);
++}
++
++static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
++ unsigned int evtinfo)
++{
++ enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK;
++
++ /*
++ * WORKAROUND: DWC3 Revisions <1.83a have an issue which, depending
++ * on the link partner, the USB session might do multiple entry/exit
++ * of low power states before a transfer takes place.
++ *
++ * Due to this problem, we might experience lower throughput. The
++ * suggested workaround is to disable DCTL[12:9] bits if we're
++ * transitioning from U1/U2 to U0 and enable those bits again
++ * after a transfer completes and there are no pending transfers
++ * on any of the enabled endpoints.
++ *
++ * This is the first half of that workaround.
++ *
++ * Refers to:
++ *
++ * STAR#9000446952: RTL: Device SS : if U1/U2 ->U0 takes >128us
++ * core send LGO_Ux entering U0
++ */
++ if (dwc->revision < DWC3_REVISION_183A) {
++ if (next == DWC3_LINK_STATE_U0) {
++ u32 u1u2;
++ u32 reg;
++
++ switch (dwc->link_state) {
++ case DWC3_LINK_STATE_U1:
++ case DWC3_LINK_STATE_U2:
++ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
++ u1u2 = reg & (DWC3_DCTL_INITU2ENA
++ | DWC3_DCTL_ACCEPTU2ENA
++ | DWC3_DCTL_INITU1ENA
++ | DWC3_DCTL_ACCEPTU1ENA);
++
++ if (!dwc->u1u2)
++ dwc->u1u2 = reg & u1u2;
++
++ reg &= ~u1u2;
++
++ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
++ break;
++ default:
++ /* do nothing */
++ break;
++ }
++ }
++ }
++
++ dwc->link_state = next;
++
++ dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);
++}
++
++static void dwc3_gadget_interrupt(struct dwc3 *dwc,
++ const struct dwc3_event_devt *event)
++{
++ switch (event->type) {
++ case DWC3_DEVICE_EVENT_DISCONNECT:
++ dwc3_gadget_disconnect_interrupt(dwc);
++ break;
++ case DWC3_DEVICE_EVENT_RESET:
++ dwc3_gadget_reset_interrupt(dwc);
++ break;
++ case DWC3_DEVICE_EVENT_CONNECT_DONE:
++ dwc3_gadget_conndone_interrupt(dwc);
++ break;
++ case DWC3_DEVICE_EVENT_WAKEUP:
++ dwc3_gadget_wakeup_interrupt(dwc);
++ break;
++ case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
++ dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
++ break;
++ case DWC3_DEVICE_EVENT_EOPF:
++ dev_vdbg(dwc->dev, "End of Periodic Frame\n");
++ break;
++ case DWC3_DEVICE_EVENT_SOF:
++ dev_vdbg(dwc->dev, "Start of Periodic Frame\n");
++ break;
++ case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
++ dev_vdbg(dwc->dev, "Erratic Error\n");
++ break;
++ case DWC3_DEVICE_EVENT_CMD_CMPL:
++ dev_vdbg(dwc->dev, "Command Complete\n");
++ break;
++ case DWC3_DEVICE_EVENT_OVERFLOW:
++ dev_vdbg(dwc->dev, "Overflow\n");
++ break;
++ default:
++ dev_dbg(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
++ }
++}
++
++static void dwc3_process_event_entry(struct dwc3 *dwc,
++ const union dwc3_event *event)
++{
++ /* Endpoint IRQ, handle it and return early */
++ if (event->type.is_devspec == 0) {
++ /* depevt */
++ return dwc3_endpoint_interrupt(dwc, &event->depevt);
++ }
++
++ switch (event->type.type) {
++ case DWC3_EVENT_TYPE_DEV:
++ dwc3_gadget_interrupt(dwc, &event->devt);
++ break;
++ /* REVISIT what to do with Carkit and I2C events ? */
++ default:
++ dev_err(dwc->dev, "UNKNOWN IRQ type %d\n", event->raw);
++ }
++}
++
++static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
++{
++ struct dwc3_event_buffer *evt;
++ int left;
++ u32 count;
++
++ count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf));
++ count &= DWC3_GEVNTCOUNT_MASK;
++ if (!count)
++ return IRQ_NONE;
++
++ evt = dwc->ev_buffs[buf];
++ left = count;
++
++ while (left > 0) {
++ union dwc3_event event;
++
++ memcpy(&event.raw, (evt->buf + evt->lpos), sizeof(event.raw));
++ dwc3_process_event_entry(dwc, &event);
++ /*
++ * XXX we wrap around correctly to the next entry as almost all
++ * entries are 4 bytes in size. There is one entry which has 12
++ * bytes which is a regular entry followed by 8 bytes data. ATM
++ * I don't know how things are organized if were get next to the
++ * a boundary so I worry about that once we try to handle that.
++ */
++ evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
++ left -= 4;
++
++ dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
++ }
++
++ return IRQ_HANDLED;
++}
++
++irqreturn_t dwc3_interrupt(int irq, void *_dwc)
++{
++ struct dwc3 *dwc = _dwc;
++ int i;
++ irqreturn_t ret = IRQ_NONE;
++
++ spin_lock(&dwc->lock);
++
++ for (i = 0; i < dwc->num_event_buffers; i++) {
++ irqreturn_t status;
++
++ status = dwc3_process_event_buf(dwc, i);
++ if (status == IRQ_HANDLED)
++ ret = status;
++ }
++
++ spin_unlock(&dwc->lock);
++
++ return ret;
++}
++
++/**
++ * dwc3_gadget_init - Initializes gadget related registers
++ * @dwc: Pointer to out controller context structure
++ *
++ * Returns 0 on success otherwise negative errno.
++ */
++int __devinit dwc3_gadget_init(struct dwc3 *dwc)
++{
++ u32 reg;
++ int ret;
++
++ dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
++ &dwc->ctrl_req_addr, GFP_KERNEL);
++ if (!dwc->ctrl_req) {
++ dev_err(dwc->dev, "failed to allocate ctrl request\n");
++ ret = -ENOMEM;
++ goto err0;
++ }
++
++ dwc->ep0_trb = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
++ &dwc->ep0_trb_addr, GFP_KERNEL);
++ if (!dwc->ep0_trb) {
++ dev_err(dwc->dev, "failed to allocate ep0 trb\n");
++ ret = -ENOMEM;
++ goto err1;
++ }
++
++ dwc->setup_buf = dma_alloc_coherent(dwc->dev,
++ sizeof(*dwc->setup_buf) * 2,
++ &dwc->setup_buf_addr, GFP_KERNEL);
++ if (!dwc->setup_buf) {
++ dev_err(dwc->dev, "failed to allocate setup buffer\n");
++ ret = -ENOMEM;
++ goto err2;
++ }
++
++ dwc->ep0_bounce = dma_alloc_coherent(dwc->dev,
++ 512, &dwc->ep0_bounce_addr, GFP_KERNEL);
++ if (!dwc->ep0_bounce) {
++ dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n");
++ ret = -ENOMEM;
++ goto err3;
++ }
++
++ dev_set_name(&dwc->gadget.dev, "gadget");
++
++ dwc->gadget.ops = &dwc3_gadget_ops;
++ dwc->gadget.is_dualspeed = true;
++ dwc->gadget.speed = USB_SPEED_UNKNOWN;
++
++ dwc->gadget.name = "dwc3-gadget";
++
++ the_dwc = dwc;
++
++ /*
++ * REVISIT: Here we should clear all pending IRQs to be
++ * sure we're starting from a well known location.
++ */
++
++ ret = dwc3_gadget_init_endpoints(dwc);
++ if (ret)
++ goto err4;
++
++ /* Enable all but Start and End of Frame IRQs */
++ reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
++ DWC3_DEVTEN_EVNTOVERFLOWEN |
++ DWC3_DEVTEN_CMDCMPLTEN |
++ DWC3_DEVTEN_ERRTICERREN |
++ DWC3_DEVTEN_WKUPEVTEN |
++ DWC3_DEVTEN_ULSTCNGEN |
++ DWC3_DEVTEN_CONNECTDONEEN |
++ DWC3_DEVTEN_USBRSTEN |
++ DWC3_DEVTEN_DISCONNEVTEN);
++ dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
++ return 0;
++
++ device_unregister(&dwc->gadget.dev);
++ dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
++ dwc3_gadget_free_endpoints(dwc);
++
++err4:
++ dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
++ dwc->ep0_bounce_addr);
++
++err3:
++ dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
++ dwc->setup_buf, dwc->setup_buf_addr);
++
++err2:
++ dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
++ dwc->ep0_trb, dwc->ep0_trb_addr);
++
++err1:
++ dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
++ dwc->ctrl_req, dwc->ctrl_req_addr);
++
++err0:
++ return ret;
++}
++
++void dwc3_gadget_exit(struct dwc3 *dwc)
++{
++ dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
++
++ dwc3_gadget_free_endpoints(dwc);
++
++ dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
++ dwc->ep0_bounce_addr);
++
++ dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
++ dwc->setup_buf, dwc->setup_buf_addr);
++
++ dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
++ dwc->ep0_trb, dwc->ep0_trb_addr);
++
++ dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
++ dwc->ctrl_req, dwc->ctrl_req_addr);
++
++ device_unregister(&dwc->gadget.dev);
++
++ the_dwc = NULL;
++}
++
++/* -------------------------------------------------------------------------- */
++
++int usb_gadget_register_driver(struct usb_gadget_driver *driver)
++{
++ return usb_gadget_probe_driver(driver, driver->bind);
++}
++
++/**
++ * usb_gadget_unregister_driver - unregisters a gadget driver.
++ * @driver: the gadget driver to unregister
++ */
++int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
++{
++ struct dwc3 *dwc = the_dwc;
++ unsigned long flags;
++
++ if (!driver || !driver->unbind)
++ return -EINVAL;
++
++ if (!dwc)
++ return -ENODEV;
++
++ if (dwc->gadget_driver != driver)
++ return -EINVAL;
++
++ driver->disconnect(&dwc->gadget);
++ driver->unbind(&dwc->gadget);
++
++ spin_lock_irqsave(&dwc->lock, flags);
++
++ dwc->gadget_driver = NULL;
++
++ spin_unlock_irqrestore(&dwc->lock, flags);
++
++ return 0;
++}
+diff --git a/drivers/usb/dwc3/dwc3_host.c b/drivers/usb/dwc3/dwc3_host.c
+new file mode 100644
+index 0000000..7cfe211
+--- /dev/null
++++ b/drivers/usb/dwc3/dwc3_host.c
+@@ -0,0 +1,102 @@
++/**
++ * host.c - DesignWare USB3 DRD Controller Host Glue
++ *
++ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com
++ *
++ * Authors: Felipe Balbi <balbi@ti.com>,
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/platform_device.h>
++
++#include "core.h"
++
++static struct resource generic_resources[] = {
++ {
++ .flags = IORESOURCE_IRQ,
++ },
++ {
++ .flags = IORESOURCE_MEM,
++ },
++};
++
++int dwc3_host_init(struct dwc3 *dwc)
++{
++ struct platform_device *xhci;
++ int ret;
++
++ xhci = platform_device_alloc("xhci", -1);
++ if (!xhci) {
++ dev_err(dwc->dev, "couldn't allocate xHCI device\n");
++ ret = -ENOMEM;
++ goto err0;
++ }
++
++ dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask);
++
++ xhci->dev.parent = dwc->dev;
++ xhci->dev.dma_mask = dwc->dev->dma_mask;
++ xhci->dev.dma_parms = dwc->dev->dma_parms;
++
++ dwc->xhci = xhci;
++
++ /* setup resources */
++ generic_resources[0].start = dwc->irq;
++
++ generic_resources[1].start = dwc->res->start;
++ generic_resources[1].end = dwc->res->start + 0x7fff;
++
++ ret = platform_device_add_resources(xhci, generic_resources,
++ ARRAY_SIZE(generic_resources));
++ if (ret) {
++ dev_err(dwc->dev, "couldn't add resources to xHCI device\n");
++ goto err1;
++ }
++
++ ret = platform_device_add(xhci);
++ if (ret) {
++ dev_err(dwc->dev, "failed to register xHCI device\n");
++ goto err1;
++ }
++
++ return 0;
++
++err1:
++ platform_device_put(xhci);
++
++err0:
++ return ret;
++}
++
++void dwc3_host_exit(struct dwc3 *dwc)
++{
++ platform_device_unregister(dwc->xhci);
++}
+diff --git a/drivers/usb/dwc3/dwc3_misc.c b/drivers/usb/dwc3/dwc3_misc.c
+new file mode 100644
+index 0000000..628e11e
+--- /dev/null
++++ b/drivers/usb/dwc3/dwc3_misc.c
+@@ -0,0 +1,20 @@
++#include <common.h>
++
++#include <linux/usb/ch9.h>
++#include <linux/usb/gadget.h>
++
++#include "misc.h"
++#if 0
++int snprintf(char *buf, size_t size, const char *fmt, ...)
++{
++ va_list args;
++ int i;
++
++ va_start(args, fmt);
++ i = vsprintf(buf, fmt, args);
++ va_end(args);
++ if (i > size)
++ printf("*** Wrote too much bytes into the buffer ***\n");
++ return i;
++}
++#endif
+diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
+new file mode 100644
+index 0000000..d97f467
+--- /dev/null
++++ b/drivers/usb/dwc3/gadget.h
+@@ -0,0 +1,186 @@
++/**
++ * gadget.h - DesignWare USB3 DRD Gadget Header
++ *
++ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
++ *
++ * Authors: Felipe Balbi <balbi@ti.com>,
++ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __DRIVERS_USB_DWC3_GADGET_H
++#define __DRIVERS_USB_DWC3_GADGET_H
++
++#include <linux/list.h>
++#include <linux/usb/gadget.h>
++#include "io.h"
++
++struct dwc3;
++#define to_dwc3_ep(ep) (container_of(ep, struct dwc3_ep, endpoint))
++#define gadget_to_dwc(g) (container_of(g, struct dwc3, gadget))
++
++/* DEPCFG parameter 1 */
++#define DWC3_DEPCFG_INT_NUM(n) ((n) << 0)
++#define DWC3_DEPCFG_XFER_COMPLETE_EN (1 << 8)
++#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN (1 << 9)
++#define DWC3_DEPCFG_XFER_NOT_READY_EN (1 << 10)
++#define DWC3_DEPCFG_FIFO_ERROR_EN (1 << 11)
++#define DWC3_DEPCFG_STREAM_EVENT_EN (1 << 13)
++#define DWC3_DEPCFG_BINTERVAL_M1(n) ((n) << 16)
++#define DWC3_DEPCFG_STREAM_CAPABLE (1 << 24)
++#define DWC3_DEPCFG_EP_NUMBER(n) ((n) << 25)
++#define DWC3_DEPCFG_BULK_BASED (1 << 30)
++#define DWC3_DEPCFG_FIFO_BASED (1 << 31)
++
++/* DEPCFG parameter 0 */
++#define DWC3_DEPCFG_EP_TYPE(n) ((n) << 1)
++#define DWC3_DEPCFG_MAX_PACKET_SIZE(n) ((n) << 3)
++#define DWC3_DEPCFG_FIFO_NUMBER(n) ((n) << 17)
++#define DWC3_DEPCFG_BURST_SIZE(n) ((n) << 22)
++#define DWC3_DEPCFG_DATA_SEQ_NUM(n) ((n) << 26)
++#define DWC3_DEPCFG_IGN_SEQ_NUM (1 << 31)
++
++/* DEPXFERCFG parameter 0 */
++#define DWC3_DEPXFERCFG_NUM_XFER_RES(n) ((n) & 0xffff)
++
++struct dwc3_gadget_ep_cmd_params {
++ u32 param2;
++ u32 param1;
++ u32 param0;
++};
++
++/* -------------------------------------------------------------------------- */
++
++#define to_dwc3_request(r) (container_of(r, struct dwc3_request, request))
++
++static inline struct dwc3_request *next_request(struct list_head *list)
++{
++ if (list_empty(list))
++ return NULL;
++
++ return list_first_entry(list, struct dwc3_request, list);
++}
++
++static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)
++{
++ struct dwc3_ep *dep = req->dep;
++
++ req->queued = true;
++ list_move_tail(&req->list, &dep->req_queued);
++}
++
++void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
++ int status);
++
++void dwc3_ep0_interrupt(struct dwc3 *dwc,
++ const struct dwc3_event_depevt *event);
++void dwc3_ep0_out_start(struct dwc3 *dwc);
++int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
++ gfp_t gfp_flags);
++int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
++int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
++ unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
++void dwc3_map_buffer_to_dma(struct dwc3_request *req);
++void dwc3_unmap_buffer_from_dma(struct dwc3_request *req);
++
++/**
++ * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
++ * @dwc: DesignWare USB3 Pointer
++ * @number: DWC endpoint number
++ *
++ * Caller should take care of locking
++ */
++static inline u32 dwc3_gadget_ep_get_transfer_index(struct dwc3 *dwc, u8 number)
++{
++ u32 res_id;
++
++ res_id = dwc3_readl(dwc->regs, DWC3_DEPCMD(number));
++
++ return DWC3_DEPCMD_GET_RSC_IDX(res_id);
++}
++
++/**
++ * dwc3_gadget_event_string - returns event name
++ * @event: the event code
++ */
++static inline const char *dwc3_gadget_event_string(u8 event)
++{
++ switch (event) {
++ case DWC3_DEVICE_EVENT_DISCONNECT:
++ return "Disconnect";
++ case DWC3_DEVICE_EVENT_RESET:
++ return "Reset";
++ case DWC3_DEVICE_EVENT_CONNECT_DONE:
++ return "Connection Done";
++ case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
++ return "Link Status Change";
++ case DWC3_DEVICE_EVENT_WAKEUP:
++ return "WakeUp";
++ case DWC3_DEVICE_EVENT_EOPF:
++ return "End-Of-Frame";
++ case DWC3_DEVICE_EVENT_SOF:
++ return "Start-Of-Frame";
++ case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
++ return "Erratic Error";
++ case DWC3_DEVICE_EVENT_CMD_CMPL:
++ return "Command Complete";
++ case DWC3_DEVICE_EVENT_OVERFLOW:
++ return "Overflow";
++ }
++
++ return "UNKNOWN";
++}
++
++/**
++ * dwc3_ep_event_string - returns event name
++ * @event: then event code
++ */
++static inline const char *dwc3_ep_event_string(u8 event)
++{
++ switch (event) {
++ case DWC3_DEPEVT_XFERCOMPLETE:
++ return "Transfer Complete";
++ case DWC3_DEPEVT_XFERINPROGRESS:
++ return "Transfer In-Progress";
++ case DWC3_DEPEVT_XFERNOTREADY:
++ return "Transfer Not Ready";
++ case DWC3_DEPEVT_RXTXFIFOEVT:
++ return "FIFO";
++ case DWC3_DEPEVT_STREAMEVT:
++ return "Stream";
++ case DWC3_DEPEVT_EPCMDCMPLT:
++ return "Endpoint Command Complete";
++ }
++
++ return "UNKNOWN";
++}
++
++#endif /* __DRIVERS_USB_DWC3_GADGET_H */
+diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h
+new file mode 100644
+index 0000000..bc957db
+--- /dev/null
++++ b/drivers/usb/dwc3/io.h
+@@ -0,0 +1,54 @@
++/**
++ * io.h - DesignWare USB3 DRD IO Header
++ *
++ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
++ *
++ * Authors: Felipe Balbi <balbi@ti.com>,
++ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef __DRIVERS_USB_DWC3_IO_H
++#define __DRIVERS_USB_DWC3_IO_H
++
++#include <asm/io.h>
++
++static inline u32 dwc3_readl(void __iomem *base, u32 offset)
++{
++ return readl(base + offset);
++}
++
++static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
++{
++ writel(value, base + offset);
++}
++
++#endif /* __DRIVERS_USB_DWC3_IO_H */
+diff --git a/drivers/usb/dwc3/misc.h b/drivers/usb/dwc3/misc.h
+new file mode 100644
+index 0000000..da9012c
+--- /dev/null
++++ b/drivers/usb/dwc3/misc.h
+@@ -0,0 +1,269 @@
++#ifndef dwc3_misc_h
++#define dwc3_misc_h
++
++#include <linux/compiler.h>
++#include <malloc.h>
++#include <asm/io.h>
++#include <errno.h>
++
++#define DWC3_USB_REGS_SIZE (CONFIG_USB_DWC3_UDC_REGS - \
++ CONFIG_USB_DWC3_UDC_REGS_END + 1)
++#define DWC3_WRAPPER_REGS_SIZE (CONFIG_USB_DWC3_WRAP_REGS - \
++ CONFIG_USB_DWC3_WRAP_REGS_END + 1)
++
++#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16))
++#define lower_32_bits(n) ((u32)(n))
++
++extern struct dwc3 *global_dwc3;
++
++typedef int mutex_t;
++typedef int spinlock_t;
++/*
++enum {
++ false = 0,
++ true = 1
++};
++typedef unsigned int bool;
++*/
++#define min_t(type, x, y) ({ \
++ type __min1 = (x); \
++ type __min2 = (y); \
++ __min1 < __min2 ? __min1: __min2; })
++
++#define __init
++#define __devinit
++#define __devinitconst
++#define __devexit
++
++static inline void *dma_alloc_coherent(void *dev, size_t size,
++ dma_addr_t *dma_handle, gfp_t gfp)
++{
++ void *p;
++
++ p = malloc(size);
++ *dma_handle = (unsigned long)p;
++ return p;
++}
++
++
++static inline void dma_free_coherent(struct device *dev, size_t size,
++ void *vaddr, dma_addr_t bus)
++{
++ free(vaddr);
++}
++
++static inline void kfree(void *p)
++{
++ free(p);
++}
++
++static inline void *kzalloc(unsigned int size, unsigned int flags)
++{
++ void *p;
++
++ p = malloc(size);
++ memset(p, 0, size);
++ return p;
++}
++
++#define GFP_KERNEL 0
++
++#define MAX_ERRNO 4095
++
++#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
++
++static inline void *ERR_PTR(long error)
++{
++ return (void *) error;
++}
++
++static inline long PTR_ERR(const void *ptr)
++{
++ return (long) ptr;
++}
++
++static inline long IS_ERR(const void *ptr)
++{
++ return IS_ERR_VALUE((unsigned long)ptr);
++}
++
++#define dev_err(dev, format, ...) printf(format, ## __VA_ARGS__)
++#if 0
++#define dev_dbg(dev, format, ...) printf(format, ## __VA_ARGS__)
++#define dev_vdbg(dev, format, ...) printf(format, ## __VA_ARGS__)
++#define pr_debug(format, ...) printf(format, ## __VA_ARGS__)
++#else
++static inline void dwc3_valength_dummy(void *p, char *fmt, ...) {}
++#define dev_dbg(dev, format, ...) dwc3_valength_dummy(dev, format, ## __VA_ARGS__)
++#define dev_vdbg(dev, format, ...) dwc3_valength_dummy(dev, format, ## __VA_ARGS__)
++#define pr_debug(format, ...) dwc3_valength_dummy(NULL, format, ## __VA_ARGS__)
++#endif
++
++static inline void pm_runtime_enable(struct device *dev) {}
++static inline void pm_runtime_get_sync(struct device *dev) {}
++static inline void pm_runtime_forbid(struct device *dev) {}
++static inline void pm_runtime_allow(struct device *dev) {}
++
++#define PTR_ALIGN(p, a) ((typeof(p))ALIGN((unsigned long)(p), (a)))
++
++#define PAGE_SHIFT 12
++#define PAGE_SIZE (1UL << PAGE_SHIFT)
++#define PAGE_MASK (~(PAGE_SIZE-1))
++
++struct platform_device {
++ struct device dev;
++};
++
++static inline void __arch_iounmap(void *p) {}
++
++#define cpu_relax() asm volatile("" ::: "memory")
++
++enum dma_data_direction {
++ DMA_BIDIRECTIONAL = 0,
++ DMA_TO_DEVICE = 1,
++ DMA_FROM_DEVICE = 2,
++};
++
++static inline dma_addr_t dma_map_single(struct device *dev, void *ptr,
++ size_t size,
++ enum dma_data_direction dir)
++{
++ return (unsigned long)ptr;
++}
++
++static inline void dma_unmap_single(struct device *dev, dma_addr_t addr,
++ size_t size,
++ enum dma_data_direction dir)
++{
++}
++
++static inline void dma_sync_single_for_device(struct device *dev,
++ dma_addr_t addr, size_t size,
++ enum dma_data_direction dir)
++{
++}
++static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr,
++ size_t size,
++ enum dma_data_direction dir)
++{
++}
++
++static inline int device_register(struct device *dev)
++{
++ return 0;
++}
++
++static inline void device_unregister(struct device *dev)
++{
++}
++
++static inline int dev_set_name(struct device *dev, const char *fmt, ...)
++{
++ return 0;
++}
++
++#define spin_lock(x)
++#define spin_unlock(x)
++#define spin_lock_irqsave(x, y) y = 0;
++#define spin_unlock_irqrestore(x, y)
++#if 0
++static inline void mdelay(unsigned int msec)
++{
++ int i;
++
++ /* XXX VirtIO currently hangs on udelay(10+) */
++ for (i = 0; i < msec; i++)
++ udelay(5);
++}
++#endif
++static inline void msleep(unsigned int msec)
++{
++ mdelay(msec);
++}
++
++static inline void usleep_range(unsigned long min, unsigned long max)
++{
++ udelay(min);
++}
++
++#define container_of(ptr, type, member) ({ \
++ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
++ (type *)( (char *)__mptr - offsetof(type,member) );})
++
++#define __WARN_printf(arg...) do { printf("WarnON() in %s: %s(%d)\n", __FILE__, __func__, __LINE__); printf(arg); } while (0)
++
++#define WARN(condition, format...) ({ \
++ int __ret_warn_on = !!(condition); \
++ if (unlikely(__ret_warn_on)) \
++ __WARN_printf(format); \
++ unlikely(__ret_warn_on); \
++ })
++
++#define WARN_ONCE(condition, format...) ({ \
++ static bool __warned; \
++ int __ret_warn_once = !!(condition); \
++ \
++ if (unlikely(__ret_warn_once)) \
++ if (WARN(!__warned, format)) \
++ __warned = true; \
++ unlikely(__ret_warn_once); \
++ })
++
++#define dev_WARN_ONCE(dev, condition, format, arg...) \
++ WARN_ONCE(condition, format, ## arg)
++
++#define WARN_ON(condition) ({ \
++ int __ret_warn_on = !!(condition); \
++ if (unlikely(__ret_warn_on)) \
++ printf("WarnON() in %s: %s(%d)\n", __FILE__, __func__, __LINE__); \
++ unlikely(__ret_warn_on); \
++ })
++
++#define WARN_ON_ONCE(condition) ({ \
++ static bool __warned; \
++ int __ret_warn_once = !!(condition); \
++ \
++ if (unlikely(__ret_warn_once)) \
++ if (WARN_ON(!__warned)) \
++ __warned = true; \
++ unlikely(__ret_warn_once); \
++ })
++
++#define BUILD_BUG_ON_NOT_POWER_OF_2(n) \
++ BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0))
++#if 0
++/* never do isoc */
++static inline int usb_endpoint_xfer_isoc(
++ const struct usb_endpoint_descriptor *epd)
++{
++ return 0;
++}
++static inline int usb_endpoint_type(const struct usb_endpoint_descriptor *epd)
++{
++ return epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
++}
++#endif
++
++enum irqreturn {
++ IRQ_NONE,
++ IRQ_HANDLED,
++ IRQ_WAKE_THREAD,
++};
++
++typedef enum irqreturn irqreturn_t;
++
++int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
++ int (*bind)(struct usb_gadget *));
++int usb_gadget_unregister_driver(struct usb_gadget_driver *driver);
++
++struct dwc3;
++int snprintf(char *buf, size_t size, const char *fmt, ...);
++int __devinit dwc3_probe(struct platform_device *pdev);
++int __devexit dwc3_remove(struct platform_device *pdev);
++
++extern unsigned int dwc3_cable_connected;
++extern unsigned int dwc3_high_speed;
++
++#define USB_GADGET_DELAYED_STATUS 0x7fff /* Impossibly large value */
++
++#endif
+diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
+index 804a2bd..1ada7bb 100644
+--- a/drivers/usb/gadget/Makefile
++++ b/drivers/usb/gadget/Makefile
+@@ -17,6 +17,7 @@ obj-$(CONFIG_THOR_FUNCTION) += f_thor.o
+ obj-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
+ obj-$(CONFIG_DFU_FUNCTION) += f_dfu.o
+ obj-$(CONFIG_USB_GADGET_MASS_STORAGE) += f_mass_storage.o
++obj-$(CONFIG_USB_FASTBOOT) += f_fastboot.o u_fastboot.o
+ endif
+ ifdef CONFIG_USB_ETHER
+ obj-y += ether.o
+diff --git a/drivers/usb/gadget/f_dfu.c b/drivers/usb/gadget/f_dfu.c
+index de75ff1..3b8b48b 100644
+--- a/drivers/usb/gadget/f_dfu.c
++++ b/drivers/usb/gadget/f_dfu.c
+@@ -601,6 +601,7 @@ dfu_handle(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+ (w_value >> 8) == DFU_DT_FUNC) {
+ value = min(len, (u16) sizeof(dfu_func));
+ memcpy(req->buf, &dfu_func, value);
++ dfu_trigger_enum_done();
+ }
+ } else /* DFU specific request */
+ value = dfu_state[f_dfu->dfu_state] (f_dfu, ctrl, gadget, req);
+diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
+new file mode 100644
+index 0000000..7570440
+--- /dev/null
++++ b/drivers/usb/gadget/f_fastboot.c
+@@ -0,0 +1,559 @@
++/*
++ * (C) Copyright 2008 - 2009
++ * Windriver, <www.windriver.com>
++ * Tom Rix <Tom.Rix@windriver.com>
++ *
++ * Copyright (c) 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++#include <common.h>
++#include <errno.h>
++#include <usb/fastboot.h>
++#include <linux/usb/ch9.h>
++#include <linux/usb/gadget.h>
++#include <linux/compiler.h>
++
++#include "g_fastboot.h"
++
++#define CONFIGURATION_NORMAL 1
++#define BULK_ENDPOINT 1
++#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0 (0x0200)
++#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1 (0x0040)
++#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE (0x0040)
++
++static struct usb_string def_usb_fb_strings[] = {
++ { FB_STR_PRODUCT_IDX, "Default Product" },
++ { FB_STR_SERIAL_IDX, "1234567890" },
++ { FB_STR_CONFIG_IDX, "Android Fastboot" },
++ { FB_STR_INTERFACE_IDX, "Android Fastboot" },
++ { FB_STR_MANUFACTURER_IDX, "Default Manufacturer" },
++ { FB_STR_PROC_REV_IDX, "Default 1.0" },
++ { FB_STR_PROC_TYPE_IDX, "Emulator" },
++ { }
++};
++
++static struct usb_gadget_strings def_fb_strings = {
++ .language = 0x0409, /* en-us */
++ .strings = def_usb_fb_strings,
++};
++
++static struct usb_gadget_strings *vendor_fb_strings;
++
++static unsigned int gadget_is_connected;
++
++static u8 ep0_buffer[512];
++static u8 ep_out_buffer[EP_BUFFER_SIZE];
++static u8 ep_in_buffer[EP_BUFFER_SIZE];
++static int current_config;
++
++/* e1 */
++static struct usb_endpoint_descriptor fs_ep_in = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_IN, /* IN */
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++ .wMaxPacketSize = TX_ENDPOINT_MAXIMUM_PACKET_SIZE,
++ .bInterval = 0x00,
++};
++
++/* e2 */
++static struct usb_endpoint_descriptor fs_ep_out = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_OUT, /* OUT */
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++ .wMaxPacketSize = RX_ENDPOINT_MAXIMUM_PACKET_SIZE_1_1,
++ .bInterval = 0x00,
++};
++
++static struct usb_endpoint_descriptor hs_ep_out = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_OUT, /* OUT */
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++ .wMaxPacketSize = RX_ENDPOINT_MAXIMUM_PACKET_SIZE_2_0,
++ .bInterval = 0x00,
++};
++
++const char *fb_find_usb_string(unsigned int id)
++{
++ struct usb_string *s;
++
++ for (s = vendor_fb_strings->strings; s && s->s; s++) {
++ if (s->id == id)
++ break;
++ }
++ if (!s || !s->s) {
++ for (s = def_fb_strings.strings; s && s->s; s++) {
++ if (s->id == id)
++ break;
++ }
++ }
++ if (!s)
++ return NULL;
++ return s->s;
++}
++
++static struct usb_gadget *g;
++static struct usb_request *ep0_req;
++
++struct usb_ep *ep_in;
++struct usb_request *req_in;
++
++struct usb_ep *ep_out;
++struct usb_request *req_out;
++
++static void fastboot_ep0_complete(struct usb_ep *ep, struct usb_request *req)
++{
++ int status = req->status;
++
++ if (!status)
++ return;
++ printf("ep0 status %d\n", status);
++}
++
++static int fastboot_bind(struct usb_gadget *gadget)
++{
++
++ g = gadget;
++ ep0_req = usb_ep_alloc_request(g->ep0, 0);
++ if (!ep0_req)
++ goto err;
++ ep0_req->buf = ep0_buffer;
++ ep0_req->complete = fastboot_ep0_complete;
++
++ ep_in = usb_ep_autoconfig(gadget, &fs_ep_in);
++ if (!ep_in)
++ goto err;
++ ep_in->driver_data = ep_in;
++
++ ep_out = usb_ep_autoconfig(gadget, &fs_ep_out);
++ if (!ep_out)
++ goto err;
++ ep_out->driver_data = ep_out;
++
++ hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
++ return 0;
++err:
++ return -1;
++}
++
++static void fastboot_unbind(struct usb_gadget *gadget)
++{
++ usb_ep_free_request(g->ep0, ep0_req);
++ ep_in->driver_data = NULL;
++ ep_out->driver_data = NULL;
++}
++
++/* This is the TI USB vendor id a product ID from TI's internal tree */
++#define DEVICE_VENDOR_ID 0x0451
++#define DEVICE_PRODUCT_ID 0xd022
++#define DEVICE_BCD 0x0100
++
++struct usb_device_descriptor fb_descriptor = {
++ .bLength = sizeof(fb_descriptor),
++ .bDescriptorType = USB_DT_DEVICE,
++ .bcdUSB = 0x200,
++ .bMaxPacketSize0 = 0x40,
++ .idVendor = DEVICE_VENDOR_ID,
++ .idProduct = DEVICE_PRODUCT_ID,
++ .bcdDevice = DEVICE_BCD,
++ .iManufacturer = FB_STR_MANUFACTURER_IDX,
++ .iProduct = FB_STR_PRODUCT_IDX,
++ .iSerialNumber = FB_STR_SERIAL_IDX,
++ .bNumConfigurations = 1,
++};
++
++#define TOT_CFG_DESC_LEN (USB_DT_CONFIG_SIZE + USB_DT_INTERFACE_SIZE + \
++ USB_DT_ENDPOINT_SIZE + USB_DT_ENDPOINT_SIZE)
++
++static struct usb_config_descriptor config_desc = {
++ .bLength = USB_DT_CONFIG_SIZE,
++ .bDescriptorType = USB_DT_CONFIG,
++ .wTotalLength = cpu_to_le16(TOT_CFG_DESC_LEN),
++ .bNumInterfaces = 1,
++ .bConfigurationValue = CONFIGURATION_NORMAL,
++ .iConfiguration = FB_STR_CONFIG_IDX,
++ .bmAttributes = 0xc0,
++ .bMaxPower = 0x32,
++};
++
++static struct usb_interface_descriptor interface_desc = {
++ .bLength = USB_DT_INTERFACE_SIZE,
++ .bDescriptorType = USB_DT_INTERFACE,
++ .bInterfaceNumber = 0x00,
++ .bAlternateSetting = 0x00,
++ .bNumEndpoints = 0x02,
++ .bInterfaceClass = FASTBOOT_INTERFACE_CLASS,
++ .bInterfaceSubClass = FASTBOOT_INTERFACE_SUB_CLASS,
++ .bInterfaceProtocol = FASTBOOT_INTERFACE_PROTOCOL,
++ .iInterface = FB_STR_INTERFACE_IDX,
++};
++
++static struct usb_qualifier_descriptor qual_desc = {
++ .bLength = sizeof(qual_desc),
++ .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
++ .bcdUSB = 0x200,
++ .bMaxPacketSize0 = 0x40,
++ .bNumConfigurations = 1,
++};
++
++static int fastboot_setup_get_descr(struct usb_gadget *gadget,
++ const struct usb_ctrlrequest *ctrl)
++{
++ u16 w_value = le16_to_cpu(ctrl->wValue);
++ u16 w_length = le16_to_cpu(ctrl->wLength);
++ u16 val;
++ int ret;
++ u32 bytes_remaining;
++ u32 bytes_total;
++ u32 this_inc;
++
++ val = w_value >> 8;
++
++ switch (val) {
++ case USB_DT_DEVICE:
++
++ memcpy(ep0_buffer, &fb_descriptor, sizeof(fb_descriptor));
++ ep0_req->length = min(w_length, sizeof(fb_descriptor));
++ ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
++ break;
++
++ case USB_DT_CONFIG:
++
++ bytes_remaining = min(w_length, sizeof(ep0_buffer));
++ bytes_total = 0;
++
++ /* config */
++ this_inc = min(bytes_remaining, USB_DT_CONFIG_SIZE);
++ bytes_remaining -= this_inc;
++ memcpy(ep0_buffer + bytes_total, &config_desc, this_inc);
++ bytes_total += this_inc;
++
++ /* interface */
++ this_inc = min(bytes_remaining, USB_DT_INTERFACE_SIZE);
++ bytes_remaining -= this_inc;
++ memcpy(ep0_buffer + bytes_total, &interface_desc, this_inc);
++ bytes_total += this_inc;
++
++ /* ep in */
++ this_inc = min(bytes_remaining, USB_DT_ENDPOINT_SIZE);
++ bytes_remaining -= this_inc;
++ memcpy(ep0_buffer + bytes_total, &fs_ep_in, this_inc);
++ bytes_total += this_inc;
++
++ /* ep out */
++ this_inc = min(bytes_remaining, USB_DT_ENDPOINT_SIZE);
++
++ if (gadget->speed == USB_SPEED_HIGH)
++ memcpy(ep0_buffer + bytes_total, &hs_ep_out,
++ this_inc);
++ else
++ memcpy(ep0_buffer + bytes_total, &fs_ep_out,
++ this_inc);
++ bytes_total += this_inc;
++
++ ep0_req->length = bytes_total;
++ ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
++ break;
++
++ case USB_DT_STRING:
++
++ ret = usb_gadget_get_string(vendor_fb_strings,
++ w_value & 0xff, ep0_buffer);
++ if (ret < 0)
++ ret = usb_gadget_get_string(&def_fb_strings,
++ w_value & 0xff, ep0_buffer);
++ if (ret < 0)
++ break;
++
++ ep0_req->length = ret;
++ ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
++ break;
++
++ case USB_DT_DEVICE_QUALIFIER:
++
++ memcpy(ep0_buffer, &qual_desc, sizeof(qual_desc));
++ ep0_req->length = min(w_length, sizeof(qual_desc));
++ ret = usb_ep_queue(gadget->ep0, ep0_req, 0);
++ break;
++ default:
++ ret = -EINVAL;
++ }
++ return ret;
++}
++
++static int fastboot_setup_get_conf(struct usb_gadget *gadget,
++ const struct usb_ctrlrequest *ctrl)
++{
++ u16 w_length = le16_to_cpu(ctrl->wLength);
++
++ if (w_length == 0)
++ return -1;
++
++ ep0_buffer[0] = current_config;
++ ep0_req->length = 1;
++ return usb_ep_queue(gadget->ep0, ep0_req, 0);
++}
++
++static void fastboot_complete_in(struct usb_ep *ep, struct usb_request *req)
++{
++ int status = req->status;
++
++ if (status)
++ printf("status: %d ep_in trans: %d\n",
++ status,
++ req->actual);
++}
++
++static int fastboot_disable_ep(struct usb_gadget *gadget)
++{
++ if (req_out) {
++ usb_ep_free_request(ep_out, req_out);
++ req_out = NULL;
++ }
++ if (req_in) {
++ usb_ep_free_request(ep_in, req_in);
++ req_in = NULL;
++ }
++ usb_ep_disable(ep_out);
++ usb_ep_disable(ep_in);
++
++ return 0;
++}
++
++static int fastboot_enable_ep(struct usb_gadget *gadget)
++{
++ int ret;
++
++ /* make sure we don't enable the ep twice */
++ if (gadget->speed == USB_SPEED_HIGH)
++ ret = usb_ep_enable(ep_out, &hs_ep_out);
++ else
++ ret = usb_ep_enable(ep_out, &fs_ep_out);
++ if (ret) {
++ printf("failed to enable out ep\n");
++ goto err;
++ }
++
++ req_out = usb_ep_alloc_request(ep_out, 0);
++ if (!req_out) {
++ printf("failed to alloc out req\n");
++ goto err;
++ }
++
++ ret = usb_ep_enable(ep_in, &fs_ep_in);
++ if (ret) {
++ printf("failed to enable in ep\n");
++ goto err;
++ }
++ req_in = usb_ep_alloc_request(ep_in, 0);
++ if (!req_in) {
++ printf("failed alloc req in\n");
++ goto err;
++ }
++
++ req_out->complete = rx_handler_command;
++ req_out->buf = ep_out_buffer;
++ req_out->length = sizeof(ep_out_buffer);
++
++ req_in->buf = ep_in_buffer;
++ req_in->length = sizeof(ep_in_buffer);
++
++ ret = usb_ep_queue(ep_out, req_out, 0);
++ if (ret)
++ goto err;
++
++ return 0;
++err:
++ fastboot_disable_ep(gadget);
++ return -1;
++}
++
++static int fastboot_set_interface(struct usb_gadget *gadget, u32 enable)
++{
++ if (enable && req_out)
++ return 0;
++ if (!enable && !req_out)
++ return 0;
++
++ if (enable)
++ return fastboot_enable_ep(gadget);
++ else
++ return fastboot_disable_ep(gadget);
++}
++
++static int fastboot_setup_out_req(struct usb_gadget *gadget,
++ const struct usb_ctrlrequest *req)
++{
++ switch (req->bRequestType & USB_RECIP_MASK) {
++ case USB_RECIP_DEVICE:
++ switch (req->bRequest) {
++ case USB_REQ_SET_CONFIGURATION:
++
++ ep0_req->length = 0;
++ if (req->wValue == CONFIGURATION_NORMAL) {
++ current_config = CONFIGURATION_NORMAL;
++ fastboot_set_interface(gadget, 1);
++ return usb_ep_queue(gadget->ep0,
++ ep0_req, 0);
++ }
++ if (req->wValue == 0) {
++ current_config = 0;
++ fastboot_set_interface(gadget, 0);
++ return usb_ep_queue(gadget->ep0,
++ ep0_req, 0);
++ }
++ return -1;
++ break;
++ default:
++ return -1;
++ };
++
++ case USB_RECIP_INTERFACE:
++ switch (req->bRequest) {
++ case USB_REQ_SET_INTERFACE:
++
++ ep0_req->length = 0;
++ if (!fastboot_set_interface(gadget, 1))
++ return usb_ep_queue(gadget->ep0,
++ ep0_req, 0);
++ return -1;
++ break;
++ default:
++ return -1;
++ }
++
++ case USB_RECIP_ENDPOINT:
++ switch (req->bRequest) {
++ case USB_REQ_CLEAR_FEATURE:
++
++ return usb_ep_queue(gadget->ep0, ep0_req, 0);
++ break;
++ default:
++ return -1;
++ }
++ }
++ return -1;
++}
++
++static int fastboot_setup(struct usb_gadget *gadget,
++ const struct usb_ctrlrequest *req)
++{
++ if ((req->bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD)
++ return -1;
++
++ if ((req->bRequestType & USB_DIR_IN) == 0)
++ /* host-to-device */
++ return fastboot_setup_out_req(gadget, req);
++
++ /* device-to-host */
++ if ((req->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
++ switch (req->bRequest) {
++ case USB_REQ_GET_DESCRIPTOR:
++ return fastboot_setup_get_descr(gadget, req);
++ break;
++
++ case USB_REQ_GET_CONFIGURATION:
++ return fastboot_setup_get_conf(gadget, req);
++ break;
++ default:
++ return -1;
++ }
++ }
++ return -1;
++}
++
++static void fastboot_disconnect(struct usb_gadget *gadget)
++{
++ fastboot_disable_ep(gadget);
++ gadget_is_connected = 0;
++}
++
++struct usb_gadget_driver fast_gadget = {
++ .bind = fastboot_bind,
++ .unbind = fastboot_unbind,
++ .setup = fastboot_setup,
++ .disconnect = fastboot_disconnect,
++};
++
++static int udc_is_probbed;
++
++int fastboot_init(void)
++{
++ int ret;
++
++ ret = fastboot_board_init(&fb_cfg, &vendor_fb_strings);
++ if (ret)
++ return ret;
++ if (!vendor_fb_strings)
++ return -EINVAL;
++
++ ret = usb_gadget_init_udc();
++ if (ret) {
++ printf("gadget probe failed\n");
++ return 1;
++ }
++ udc_is_probbed = 1;
++
++ ret = usb_gadget_register_driver(&fast_gadget);
++ if (ret) {
++ printf("Add gadget failed\n");
++ goto err;
++ }
++
++ gadget_is_connected = 1;
++ usb_gadget_handle_interrupts();
++ return 0;
++
++err:
++ fastboot_shutdown();
++ return 1;
++}
++
++int fastboot_poll(void)
++{
++ usb_gadget_handle_interrupts();
++
++ if (gadget_is_connected)
++ return 0;
++ else
++ return 1;
++}
++
++void fastboot_shutdown(void)
++{
++ if (!udc_is_probbed)
++ return;
++ udc_is_probbed = 0;
++ usb_gadget_exit_udc();
++}
++
++int fastboot_tx_write(const char *buffer, unsigned int buffer_size)
++{
++ int ret;
++
++ if (req_in->complete == NULL)
++ req_in->complete = fastboot_complete_in;
++
++ memcpy(req_in->buf, buffer, buffer_size);
++ req_in->length = buffer_size;
++ ret = usb_ep_queue(ep_in, req_in, 0);
++ if (ret)
++ printf("Error %d on queue\n", ret);
++ return 0;
++}
+diff --git a/drivers/usb/gadget/g_fastboot.h b/drivers/usb/gadget/g_fastboot.h
+new file mode 100644
+index 0000000..ff2621c
+--- /dev/null
++++ b/drivers/usb/gadget/g_fastboot.h
+@@ -0,0 +1,20 @@
++#ifndef _G_FASTBOOT_H_
++#define _G_FASTBOOT_H_
++
++#define EP_BUFFER_SIZE 4096
++#define FASTBOOT_INTERFACE_CLASS 0xff
++#define FASTBOOT_INTERFACE_SUB_CLASS 0x42
++#define FASTBOOT_INTERFACE_PROTOCOL 0x03
++#define FASTBOOT_VERSION "0.4"
++
++extern struct fastboot_config fb_cfg;
++extern struct usb_ep *ep_in;
++extern struct usb_request *req_in;
++extern struct usb_ep *ep_out;
++extern struct usb_request *req_out;
++
++void rx_handler_command(struct usb_ep *ep, struct usb_request *req);
++int fastboot_tx_write(const char *buffer, unsigned int buffer_size);
++const char *fb_find_usb_string(unsigned int id);
++
++#endif
+diff --git a/drivers/usb/gadget/u_fastboot.c b/drivers/usb/gadget/u_fastboot.c
+new file mode 100644
+index 0000000..00762aa
+--- /dev/null
++++ b/drivers/usb/gadget/u_fastboot.c
+@@ -0,0 +1,308 @@
++/*
++ * (C) Copyright 2008 - 2009
++ * Windriver, <www.windriver.com>
++ * Tom Rix <Tom.Rix@windriver.com>
++ *
++ * Copyright (c) 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ *
++ * Part of the rx_handler were copied from the Android project.
++ * Specifically rx command parsing in the usb_rx_data_complete
++ * function of the file bootable/bootloader/legacy/usbloader/usbloader.c
++ *
++ * The logical naming of flash comes from the Android project
++ * Thse structures and functions that look like fastboot_flash_*
++ * They come from bootable/bootloader/legacy/libboot/flash.c
++ *
++ * This is their Copyright:
++ *
++ * Copyright (C) 2008 The Android Open Source Project
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in
++ * the documentation and/or other materials provided with the
++ * distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
++ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
++ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
++ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
++ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++#include <common.h>
++#include <usb/fastboot.h>
++#include <linux/usb/ch9.h>
++#include <linux/usb/gadget.h>
++#include "g_fastboot.h"
++
++/* The 64 defined bytes plus \0 */
++#define RESPONSE_LEN (64 + 1)
++
++struct fastboot_config fb_cfg;
++
++static unsigned int download_size;
++static unsigned int download_bytes;
++
++static int fastboot_tx_write_str(const char *buffer)
++{
++ return fastboot_tx_write(buffer, strlen(buffer));
++}
++
++static void compl_do_reset(struct usb_ep *ep, struct usb_request *req)
++{
++ do_reset(NULL, 0, 0, NULL);
++}
++
++static void cb_reboot(struct usb_ep *ep, struct usb_request *req)
++{
++ req_in->complete = compl_do_reset;
++ fastboot_tx_write_str("OKAY");
++}
++
++static int strcmp_l1(const char *s1, const char *s2)
++{
++ return strncmp(s1, s2, strlen(s1));
++}
++
++static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
++{
++ char *cmd = req->buf;
++ char response[RESPONSE_LEN];
++ const char *s;
++
++ strcpy(response, "OKAY");
++ strsep(&cmd, ":");
++ if (!cmd) {
++ fastboot_tx_write_str("FAILmissing var");
++ return;
++ }
++
++ if (!strcmp_l1("version", cmd)) {
++ strncat(response, FASTBOOT_VERSION, sizeof(response));
++
++ } else if (!strcmp_l1("downloadsize", cmd)) {
++ char str_num[12];
++
++ sprintf(str_num, "%08x", fb_cfg.transfer_buffer_size);
++ strncat(response, str_num, sizeof(response));
++
++ } else if (!strcmp_l1("product", cmd)) {
++
++ s = fb_find_usb_string(FB_STR_PRODUCT_IDX);
++ if (s)
++ strncat(response, s, sizeof(response));
++ else
++ strcpy(response, "FAILValue not set");
++
++ } else if (!strcmp_l1("serialno", cmd)) {
++
++ s = fb_find_usb_string(FB_STR_SERIAL_IDX);
++ if (s)
++ strncat(response, s, sizeof(response));
++ else
++ strcpy(response, "FAILValue not set");
++
++ } else if (!strcmp_l1("cpurev", cmd)) {
++
++ s = fb_find_usb_string(FB_STR_PROC_REV_IDX);
++ if (s)
++ strncat(response, s, sizeof(response));
++ else
++ strcpy(response, "FAILValue not set");
++ } else if (!strcmp_l1("secure", cmd)) {
++
++ s = fb_find_usb_string(FB_STR_PROC_TYPE_IDX);
++ if (s)
++ strncat(response, s, sizeof(response));
++ else
++ strcpy(response, "FAILValue not set");
++ } else {
++ strcpy(response, "FAILVariable not implemented");
++ }
++ fastboot_tx_write_str(response);
++}
++
++static unsigned int rx_bytes_expected(void)
++{
++ int rx_remain = download_size - download_bytes;
++ if (rx_remain < 0)
++ return 0;
++ if (rx_remain > EP_BUFFER_SIZE)
++ return EP_BUFFER_SIZE;
++ return rx_remain;
++}
++
++#define BYTES_PER_DOT 32768
++static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
++{
++ char response[RESPONSE_LEN];
++ unsigned int transfer_size = download_size - download_bytes;
++ const unsigned char *buffer = req->buf;
++ unsigned int buffer_size = req->actual;
++
++ if (req->status != 0) {
++ printf("Bad status: %d\n", req->status);
++ return;
++ }
++
++ if (buffer_size < transfer_size)
++ transfer_size = buffer_size;
++
++ memcpy(fb_cfg.transfer_buffer + download_bytes,
++ buffer, transfer_size);
++
++ download_bytes += transfer_size;
++
++ /* Check if transfer is done */
++ if (download_bytes >= download_size) {
++ /*
++ * Reset global transfer variable, keep download_bytes because
++ * it will be used in the next possible flashing command
++ */
++ download_size = 0;
++ req->complete = rx_handler_command;
++ req->length = EP_BUFFER_SIZE;
++
++ sprintf(response, "OKAY");
++ fastboot_tx_write_str(response);
++
++ printf("\ndownloading of %d bytes finished\n",
++ download_bytes);
++ } else
++ req->length = rx_bytes_expected();
++
++ if (download_bytes && !(download_bytes % BYTES_PER_DOT)) {
++ printf(".");
++ if (!(download_bytes % (74 * BYTES_PER_DOT)))
++ printf("\n");
++
++ }
++ req->actual = 0;
++ usb_ep_queue(ep, req, 0);
++}
++
++static void cb_download(struct usb_ep *ep, struct usb_request *req)
++{
++ char *cmd = req->buf;
++ char response[RESPONSE_LEN];
++
++ strsep(&cmd, ":");
++ download_size = simple_strtoul(cmd, NULL, 16);
++ download_bytes = 0;
++
++ printf("Starting download of %d bytes\n",
++ download_size);
++
++ if (0 == download_size) {
++ sprintf(response, "FAILdata invalid size");
++ } else if (download_size >
++ fb_cfg.transfer_buffer_size) {
++ download_size = 0;
++ sprintf(response, "FAILdata too large");
++ } else {
++ sprintf(response, "DATA%08x", download_size);
++ req->complete = rx_handler_dl_image;
++ req->length = rx_bytes_expected();
++ }
++ fastboot_tx_write_str(response);
++}
++
++static char boot_addr_start[32];
++static char *bootm_args[] = { "bootm", boot_addr_start, NULL };
++
++static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req)
++{
++ req->complete = NULL;
++ fastboot_shutdown();
++ printf("Booting kernel..\n");
++
++ do_bootm(NULL, 0, 2, bootm_args);
++
++ /* This only happens if image is somehow faulty so we start over */
++ do_reset(NULL, 0, 0, NULL);
++}
++
++static void cb_boot(struct usb_ep *ep, struct usb_request *req)
++{
++ sprintf(boot_addr_start, "0x%p", fb_cfg.transfer_buffer);
++
++ req_in->complete = do_bootm_on_complete;
++ fastboot_tx_write_str("OKAY");
++ return;
++}
++
++struct cmd_dispatch_info {
++ char *cmd;
++ void (*cb)(struct usb_ep *ep, struct usb_request *req);
++};
++
++static struct cmd_dispatch_info cmd_dispatch_info[] = {
++ {
++ .cmd = "reboot",
++ .cb = cb_reboot,
++ }, {
++ .cmd = "getvar:",
++ .cb = cb_getvar,
++ }, {
++ .cmd = "download:",
++ .cb = cb_download,
++ }, {
++ .cmd = "boot",
++ .cb = cb_boot,
++ },
++};
++
++void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
++{
++ char response[RESPONSE_LEN];
++ char *cmdbuf = req->buf;
++ void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL;
++ int i;
++
++ sprintf(response, "FAIL");
++
++ for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
++ if (!strcmp_l1(cmd_dispatch_info[i].cmd, cmdbuf)) {
++ func_cb = cmd_dispatch_info[i].cb;
++ break;
++ }
++ }
++
++ if (!func_cb)
++ fastboot_tx_write_str("FAILunknown command");
++ else
++ func_cb(ep, req);
++
++ if (req->status == 0) {
++ *cmdbuf = '\0';
++ req->actual = 0;
++ usb_ep_queue(ep, req, 0);
++ }
++}
+diff --git a/examples/standalone/Makefile b/examples/standalone/Makefile
+index 9ab5446..e0f6f52 100644
+--- a/examples/standalone/Makefile
++++ b/examples/standalone/Makefile
+@@ -40,6 +40,10 @@ ELF := $(addprefix $(obj)/,$(ELF))
+
+ gcclibdir := $(shell dirname `$(CC) -print-libgcc-file-name`)
+
++ifeq ($(ARCH) , x86)
++gcclibdir := $(shell dirname $(NORMAL_LIBGCC))
++endif
++
+ # For PowerPC there's no need to compile standalone applications as a
+ # relocatable executable. The relocation data is not needed, and
+ # also causes the entry point of the standalone application to be
+diff --git a/fs/fat/fat.c b/fs/fat/fat.c
+index 54f42ea..23e99d3 100644
+--- a/fs/fat/fat.c
++++ b/fs/fat/fat.c
+@@ -42,6 +42,7 @@ static disk_partition_t cur_part_info;
+ #define DOS_BOOT_MAGIC_OFFSET 0x1fe
+ #define DOS_FS_TYPE_OFFSET 0x36
+ #define DOS_FS32_TYPE_OFFSET 0x52
++#define DOS_PART_TBL_OFFSET 0x1be
+
+ static int disk_read(__u32 block, __u32 nr_blocks, void *buf)
+ {
+@@ -76,7 +77,37 @@ int fat_set_blk_dev(block_dev_desc_t *dev_desc, disk_partition_t *info)
+ return 0;
+ if (!memcmp(buffer + DOS_FS32_TYPE_OFFSET, "FAT32", 5))
+ return 0;
+-
++#ifdef CONFIG_FAT_MBR_SCAN
++ /* Test if it could be an MBR, and update start block to the
++ * first available primary partition
++ */
++ unsigned char *part_desc = (buffer + DOS_PART_TBL_OFFSET);
++ int i = 0;
++ for (i = 0; i < 4; i++, part_desc+=16) {
++ /* Check part type to be a primary FAT partition*/
++ if ((*(part_desc+4) == 0x1) || (*(part_desc+4) == 0x4) ||
++ (*(part_desc+4) == 0x6) || (*(part_desc+4) == 0xb) ||
++ (*(part_desc+4) == 0xc) || (*(part_desc+4) == 0xe) ){
++ int lba_start = (*(part_desc + 8 + 3) << 24) +
++ (*(part_desc + 8 + 2) << 16) +
++ (*(part_desc + 8 + 1) << 8) +
++ *(part_desc + 8 + 0);
++ int lba_size = (*(part_desc + 12 + 3) << 24) +
++ (*(part_desc + 12 + 2) << 16) +
++ (*(part_desc + 12 + 1) << 8) +
++ *(part_desc + 12 + 0);
++ debug("Found partition in MBR lba start:%d lba size:%d\n",
++ lba_start, lba_size);
++ debug("Old partition info lba start:"LBAFU" size:"LBAFU"\n",
++ cur_part_info.start, cur_part_info.size);
++ cur_part_info.start += lba_start;
++ cur_part_info.size = lba_size;
++ debug("New partition info lba start:"LBAFU" size:"LBAFU"\n",
++ cur_part_info.start, cur_part_info.size);
++ return 0;
++ }
++ }
++#endif
+ cur_dev = NULL;
+ return -1;
+ }
+@@ -185,7 +216,7 @@ static __u32 get_fatent(fsdata *mydata, __u32 entry)
+ }
+
+ debug("FAT%d: entry: 0x%04x = %d, offset: 0x%04x = %d\n",
+- mydata->fatsize, entry, entry, offset, offset);
++ mydata->fatsize, entry, entry, offset, offset);
+
+ /* Read a new block of FAT entries into the cache. */
+ if (bufnum != mydata->fatbufnum) {
+@@ -246,7 +277,7 @@ static __u32 get_fatent(fsdata *mydata, __u32 entry)
+ break;
+ }
+ debug("FAT%d: ret: %08x, offset: %04x\n",
+- mydata->fatsize, ret, offset);
++ mydata->fatsize, ret, offset);
+
+ return ret;
+ }
+diff --git a/include/android_image.h b/include/android_image.h
+new file mode 100644
+index 0000000..5af32c5
+--- /dev/null
++++ b/include/android_image.h
+@@ -0,0 +1,102 @@
++/*
++ * This is from the Android Project,
++ * bootloader/legacy/include/boot/bootimg.h
++ *
++ * Copyright (C) 2008 The Android Open Source Project
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in
++ * the documentation and/or other materials provided with the
++ * distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
++ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
++ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
++ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
++ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++
++#ifndef _ANDROID_IMAGE_H_
++#define _ANDROID_IMAGE_H_
++
++#define ANDR_BOOT_MAGIC "ANDROID!"
++#define ANDR_BOOT_MAGIC_SIZE 8
++#define ANDR_BOOT_NAME_SIZE 16
++#define ANDR_BOOT_ARGS_SIZE 512
++
++struct andr_img_hdr {
++ u8 magic[ANDR_BOOT_MAGIC_SIZE];
++
++ u32 kernel_size; /* size in bytes */
++ u32 kernel_addr; /* physical load addr */
++
++ u32 ramdisk_size; /* size in bytes */
++ u32 ramdisk_addr; /* physical load addr */
++
++ u32 second_size; /* size in bytes */
++ u32 second_addr; /* physical load addr */
++
++ u32 tags_addr; /* physical addr for kernel tags */
++ u32 page_size; /* flash page size we assume */
++ u32 unused[2]; /* future expansion: should be 0 */
++
++ char name[ANDR_BOOT_NAME_SIZE]; /* asciiz product name */
++
++ char cmdline[ANDR_BOOT_ARGS_SIZE];
++
++ u32 id[8]; /* timestamp / checksum / sha1 / etc */
++};
++
++#ifdef CONFIG_ANDROID_BOOT_IMAGE
++u32 android_img_get_end(struct andr_img_hdr *hdr);
++u32 android_img_get_kload(struct andr_img_hdr *hdr);
++int android_image_get_kernel(struct andr_img_hdr *hdr, int verify);
++#else
++static inline u32 android_img_get_end(struct andr_img_hdr *hdr) { return 0; }
++static inline u32 android_img_get_kload(struct andr_img_hdr *hdr) { return 0; }
++static inline int android_image_get_kernel(struct andr_img_hdr *hdr, int verify)
++{
++ return -1;
++}
++#endif
++
++/*
++ * +-----------------+
++ * | boot header | 1 page
++ * +-----------------+
++ * | kernel | n pages
++ * +-----------------+
++ * | ramdisk | m pages
++ * +-----------------+
++ * | second stage | o pages
++ * +-----------------+
++ *
++ * n = (kernel_size + page_size - 1) / page_size
++ * m = (ramdisk_size + page_size - 1) / page_size
++ * o = (second_size + page_size - 1) / page_size
++ *
++ * 0. all entities are page_size aligned in flash
++ * 1. kernel and ramdisk are required (size != 0)
++ * 2. second is optional (second_size == 0 -> no second)
++ * 3. load each element (kernel, ramdisk, second) at
++ * the specified physical address (kernel_addr, etc)
++ * 4. prepare tags at tag_addr. kernel_args[] is
++ * appended to the kernel commandline in the tags.
++ * 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
++ * 6. if second_size != 0: jump to second_addr
++ * else: jump to kernel_addr
++ */
++#endif
+diff --git a/include/configs/coreboot.h b/include/configs/coreboot.h
+index d1d732f..b5b1f7f 100644
+--- a/include/configs/coreboot.h
++++ b/include/configs/coreboot.h
+@@ -27,6 +27,7 @@
+ #define CONFIG_SYS_EARLY_PCI_INIT
+
+ #define CONFIG_LMB
++#define CONFIG_USE_FDT
+ #define CONFIG_OF_LIBFDT
+ #define CONFIG_OF_CONTROL
+ #define CONFIG_OF_SEPARATE
+diff --git a/include/configs/edison.h b/include/configs/edison.h
+new file mode 100644
+index 0000000..fe0759f
+--- /dev/null
++++ b/include/configs/edison.h
+@@ -0,0 +1,268 @@
++#ifndef _EDISON_H
++#define _EDISON_H
++
++#define CONFIG_WATCHDOG
++#define CONFIG_WATCHDOG_HEARTBEAT 30
++#define CONFIG_SFI
++#define CONFIG_BOARD_LATE_INIT
++
++/*-----------------------------------------------------------------------
++ * Misc
++ */
++
++#define CONFIG_CMD_ITEST
++#define CONFIG_CMD_ASKENV
++#define CONFIG_CMD_BDI
++#define CONFIG_CMD_BSP
++#define CONFIG_CMD_BOOTD
++#define CONFIG_CMD_CACHE
++#define CONFIG_CMD_CONSOLE
++/*
++ *#define CONFIG_CMD_DATE
++ */
++#define CONFIG_CMD_DIAG
++#define CONFIG_CMD_ECHO
++#define CONFIG_CMD_EDITENV
++#define CONFIG_CMD_ELF
++#define CONFIG_CMD_ENV_CALLBACK
++#define CONFIG_CMD_ENV_FLAGS
++#define CONFIG_CMD_ENV_EXISTS
++/*
++ *#define CONFIG_CMD_GETTIME
++ */
++#define CONFIG_CMD_GREPENV
++#define CONFIG_CMD_HASH
++#define CONFIG_CMD_INI
++/*
++ *#define CONFIG_CMD_KGDB
++ */
++/*
++ *#define CONFIG_CMD_MD5SUM
++ */
++#define CONFIG_CMD_MEMINFO
++#define CONFIG_CMD_MEMORY
++#define CONFIG_CMD_PORTIO
++#define CONFIG_CMD_READ
++#define CONFIG_CMD_REGINFO
++/*
++ *#define CONFIG_CMD_I2C
++ *#define CONFIG_SYS_I2C_SPEED 50000
++ */
++/*
++ *#define CONFIG_CMD_SHA1SUM
++ */
++#define CONFIG_CMD_SOURCE
++/*
++ *#define CONFIG_CMD_SPI
++ */
++#define CONFIG_CMD_TIMER
++
++/*
++ *#define CONFIG_CMD_TRACE
++ */
++/*
++ *#define CONFIG_CMD_DATE
++ */
++#define CONFIG_CMD_ECHO
++/*
++ *#define CONFIG_CMD_GPIO
++ */
++#define CONFIG_CMD_LOADB
++#define CONFIG_CMD_LOADS
++#define CONFIG_CMD_IRQ
++#define CONFIG_CMD_MEMORY
++#define CONFIG_CMD_MISC
++#define CONFIG_CMD_PCI
++#define CONFIG_CMD_SOURCE
++/*
++ *#define CONFIG_CMD_TIME
++ *#define CONFIG_CMD_GETTIME
++ */
++/*
++ *#define CONFIG_CMD_USB
++ */
++/*
++ *#define EARLY_TRACE
++ *#define FTRACE
++ */
++
++
++/*-----------------------------------------------------------------------
++ * Boot
++ */
++
++#define CONFIG_ZBOOT_32
++#define CONFIG_CMD_ZBOOT
++#define CONFIG_AUTOBOOT
++#define CONFIG_BOOTCOMMAND "run bootcmd"
++#define CONFIG_BOOTDELAY 3
++
++/*-----------------------------------------------------------------------
++ * DEBUG
++ */
++
++/*
++ *#define DEBUG
++ */
++
++/*
++ *#define CONFIG_PRE_CONSOLE_BUFFER
++ *#define CONFIG_PRE_CON_BUF_SZ (1024*1024*2)
++ *#define CONFIG_PRE_CON_BUF_ADDR 0x29200000
++ */
++
++/*-----------------------------------------------------------------------
++ * Serial
++ */
++
++#define CONFIG_SERIAL
++#define CONFIG_SYS_TNG_SERIAL
++#define CONFIG_SYS_TNG_SERIAL2
++#define CONFIG_BAUDRATE 115200
++
++/*
++* MMC
++ */
++#define CONFIG_MD5
++#define CONFIG_GENERIC_MMC
++#define CONFIG_MMC
++#define CONFIG_SDHCI
++#define CONFIG_TANGIER_SDHCI
++#define CONFIG_CMD_MMC
++#define CONFIG_MMC_SDMA
++/*#define CONFIG_MMC_TRACE*/
++
++/************************************************************
++ * DISK Partition support
++ ************************************************************/
++#define CONFIG_EFI_PARTITION
++#define CONFIG_DOS_PARTITION
++#define CONFIG_MAC_PARTITION
++
++#define CONFIG_FS_FAT
++#define CONFIG_CMD_FAT
++#define CONFIG_FAT_MBR_SCAN
++#define CONFIG_FAT_WRITE
++
++#define CONFIG_CMD_GPT
++#define CONFIG_CMD_PART
++#define CONFIG_CMD_EXT4
++#define CONFIG_CMD_EXT4_WRITE
++#define CONFIG_PARTITION_UUIDS
++#define CONFIG_RANDOM_UUID
++#define CONFIG_CMD_FS_GENERIC
++ /*
++ * Miscellaneous configurable options
++ */
++#define CONFIG_SYS_LONGHELP
++#define CONFIG_SYS_PROMPT "boot > "
++#define CONFIG_SYS_CBSIZE 2048
++#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \
++ sizeof(CONFIG_SYS_PROMPT) + \
++ 16)
++#define CONFIG_SYS_MAXARGS 128
++#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE
++#define CONFIG_AUTO_COMPLETE
++#define CONFIG_SYS_HUSH_PARSER
++
++#define CONFIG_SHA1
++#define CONFIG_CMD_SHA1SUM
++/*-----------------------------------------------------------------------
++ * Board Features
++ */
++
++#define CONFIG_SYS_NO_FLASH
++#define CONFIG_INHERIT_GDT
++
++/*-----------------------------------------------------------------------
++ * Memory
++ */
++
++#define CONFIG_SYS_LOAD_ADDR 0x100000
++#define CONFIG_PHYSMEM
++
++#define CONFIG_SYS_CACHELINE_SIZE 64
++
++#define CONFIG_NR_DRAM_BANKS 3
++
++#define CONFIG_SYS_STACK_SIZE (32 * 1024)
++
++#define CONFIG_SYS_CAR_ADDR 0x19200000
++#define CONFIG_SYS_CAR_SIZE (16 * 1024)
++
++#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE
++#define CONFIG_SYS_MONITOR_LEN (256 * 1024)
++
++#define CONFIG_SYS_MALLOC_LEN ( 128 * 1024 * 1024)
++
++#define CONFIG_SYS_HEAP_SIZE (128*1024*1024)
++#define CONFIG_SYS_HEAP_MINI_SIZE (5*1024*1024)
++
++#define CONFIG_SYS_MEMTEST_START 0x00100000
++#define CONFIG_SYS_MEMTEST_END 0x01000000
++
++/*-----------------------------------------------------------------------
++ * CPU Features
++ */
++
++#define CONFIG_SYS_X86_TSC_TIMER
++#define CONFIG_SYS_NUM_IRQS 16
++#define CONFIG_PCI
++#define CONFIG_SYS_PCAT_INTERRUPTS
++
++#define CONFIG_CMD_GETTIME
++#define CONFIG_INTEL_MID
++
++/*-----------------------------------------------------------------------
++ * Environment
++ */
++#define CONFIG_ENV_IS_IN_MMC
++#define CONFIG_SYS_MMC_ENV_DEV 0
++#define CONFIG_SYS_MMC_ENV_PART 0
++#define CONFIG_ENV_SIZE (64*1024)
++#define CONFIG_ENV_OFFSET (3 * 1024 * 1024)
++#define CONFIG_ENV_OFFSET_REDUND (6 * 1024 * 1024)
++#define CONFIG_CMD_SAVEENV
++#define CONFIG_CMD_RUN
++#define CONFIG_SUPPORT_EMMC_BOOT
++#define CONFIG_CMD_SETEXPR
++
++/*-----------------------------------------------------------------------
++ * USB
++ */
++#define iounmap(x)
++#define CONFIG_USB_DWC3
++#define CONFIG_USB_DWC3_UDC_REGS (void *) 0xf9100000
++#define CONFIG_USB_DWC3_UDC_REGS_END (void *) 0xf9100400
++
++
++#define CONFIG_USB_DWC3_GADGET
++#define CONFIG_USB_DEVICE
++#define CONFIG_USB_GADGET
++#define CONFIG_USB_GADGET_VBUS_DRAW 2
++#define CONFIG_USB_GADGET_DUALSPEED
++
++#define CONFIG_USBDOWNLOAD_GADGET
++#define CONFIG_G_DNL_MANUFACTURER "Intel"
++#define CONFIG_G_DNL_VENDOR_NUM 0x8087
++#define CONFIG_G_DNL_PRODUCT_NUM 0x0a99
++
++#define CONFIG_DFU_FUNCTION
++#define CONFIG_CMD_DFU
++#define CONFIG_DFU_TIMEOUT
++#define CONFIG_DFU_MMC
++#define CONFIG_DFU_RAM
++
++/*-----------------------------------------------------------------------
++ * SCU
++ */
++
++#define CONFIG_INTEL_SCU
++#define CONFIG_SCU_BASE_ADDR 0xff000000
++#define CONFIG_SCU_IPC_BASE 0xff009000
++#define CONFIG_SCU_I2C_BASE 0xff00d000
++#define CONFIG_CPU_CHIP 4
++#define CONFIG_X86_MRFLD
++
++
++#endif
+diff --git a/include/dfu.h b/include/dfu.h
+index 6c71ecb..d3fdf97 100644
+--- a/include/dfu.h
++++ b/include/dfu.h
+@@ -37,12 +37,17 @@ enum dfu_op {
+ DFU_OP_WRITE,
+ };
+
++#define DFU_NOT_SUPPORTED -1
++
+ struct mmc_internal_data {
+ /* RAW programming */
+ unsigned int lba_start;
+ unsigned int lba_size;
+ unsigned int lba_blk_size;
+
++ /* Partition access */
++ int partition_access;
++
+ /* FAT/EXT */
+ unsigned int dev;
+ unsigned int part;
+@@ -132,8 +137,10 @@ const char *dfu_get_layout(enum dfu_layout l);
+ struct dfu_entity *dfu_get_entity(int alt);
+ char *dfu_extract_token(char** e, int *n);
+ void dfu_trigger_reset(void);
++void dfu_trigger_enum_done(void);
+ int dfu_get_alt(char *name);
+ bool dfu_reset(void);
++bool dfu_enum_done(void);
+ int dfu_init_env_entities(char *interface, int dev);
+ unsigned char *dfu_get_buf(void);
+ unsigned char *dfu_free_buf(void);
+diff --git a/include/intel_scu_ipc.h b/include/intel_scu_ipc.h
+new file mode 100644
+index 0000000..a9cf406
+--- /dev/null
++++ b/include/intel_scu_ipc.h
+@@ -0,0 +1,69 @@
++#ifndef _INTEL_SCU_IPC_H_
++#define _INTEL_SCU_IPC_H_
++
++/* IPC defines the following message types */
++#define IPCMSG_WARM_RESET 0xF0
++#define IPCMSG_COLD_RESET 0xF1
++#define IPCMSG_SOFT_RESET 0xF2
++#define IPCMSG_COLD_BOOT 0xF3
++#define IPCMSG_GET_FW_REVISION 0xF4
++#define IPCMSG_WATCHDOG_TIMER 0xF8 /* Set Kernel Watchdog Threshold */
++
++#define IPC_ERR_NONE 0
++#define IPC_ERR_CMD_NOT_SUPPORTED 1
++#define IPC_ERR_CMD_NOT_SERVICED 2
++#define IPC_ERR_UNABLE_TO_SERVICE 3
++#define IPC_ERR_CMD_INVALID 4
++#define IPC_ERR_CMD_FAILED 5
++#define IPC_ERR_EMSECURITY 6
++
++/* Command id associated with message IPCMSG_VRTC */
++#define IPC_CMD_VRTC_SETTIME 1 /* Set time */
++#define IPC_CMD_VRTC_SETALARM 2 /* Set alarm */
++#define IPC_CMD_VRTC_SYNC_RTC 3 /* Sync MSIC/PMIC RTC to VRTC */
++
++union ipc_ifwi_version {
++ u8 raw[16];
++ struct {
++ u16 ifwi_minor;
++ u8 ifwi_major;
++ u8 hardware_id;
++ u32 reserved[3];
++ } fw __attribute__((packed));
++} __attribute__((packed));
++
++/* Issue commands to the SCU with or without data */
++void intel_scu_ipc_send_command(u32 cmd);
++int intel_scu_ipc_check_status(void);
++int intel_scu_ipc_simple_command(int cmd, int sub);
++void intel_scu_ipc_lock(void);
++void intel_scu_ipc_unlock(void);
++int intel_scu_ipc_command(u32 cmd, u32 sub, u8 * in, u8 inlen,
++ u32 * out, u32 outlen);
++int intel_scu_ipc_raw_cmd(u32 cmd, u32 sub, u8 * in, u8 inlen,
++ u32 * out, u32 outlen, u32 dptr, u32 sptr);
++
++
++void ipc_data_writel(u32 data, u32 offset); /* Write ipc data */
++u32 ipc_read_status(void);
++u8 ipc_data_readb(u32 offset); /* Read ipc byte data */
++u32 ipc_data_readl(u32 offset); /* Read ipc u32 data */
++int intel_scu_ipc_command(u32 cmd, u32 sub, u8 * in, u8 inlen, u32 * out,
++ u32 outlen);
++int init_scu_ipc(void);
++
++enum intel_mid_cpu_type {
++ INTEL_CPU_CHIP_NOTMID = 0,
++ INTEL_MID_CPU_CHIP_LINCROFT,
++ INTEL_MID_CPU_CHIP_PENWELL,
++ INTEL_MID_CPU_CHIP_CLOVERVIEW,
++ INTEL_MID_CPU_CHIP_TANGIER,
++};
++
++static inline enum intel_mid_cpu_type intel_mid_identify_cpu(void)
++{
++ return INTEL_MID_CPU_CHIP_TANGIER;
++}
++
++
++#endif //_INTEL_SCU_IPC_H_
+diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
+index a8a5763..118a736 100644
+--- a/include/linux/usb/gadget.h
++++ b/include/linux/usb/gadget.h
+@@ -20,6 +20,7 @@
+
+ #include <errno.h>
+ #include <linux/list.h>
++#include <errno.h>
+
+ struct usb_ep;
+
+@@ -95,6 +96,7 @@ struct usb_request {
+
+ int status;
+ unsigned actual;
++ unsigned stream_id;
+ };
+
+ /*-------------------------------------------------------------------------*/
+@@ -145,6 +147,8 @@ struct usb_ep {
+ const struct usb_ep_ops *ops;
+ struct list_head ep_list;
+ unsigned maxpacket:16;
++ unsigned max_streams:16;
++ unsigned maxburst:16;
+ };
+
+ /*-------------------------------------------------------------------------*/
+@@ -412,7 +416,6 @@ struct usb_gadget_ops {
+
+ struct device {
+ void *driver_data; /* data private to the driver */
+- void *device_data; /* data private to the device */
+ };
+
+ /**
+@@ -483,11 +486,6 @@ static inline void *get_gadget_data(struct usb_gadget *gadget)
+ return gadget->dev.driver_data;
+ }
+
+-static inline struct usb_gadget *dev_to_usb_gadget(struct device *dev)
+-{
+- return container_of(dev, struct usb_gadget, dev);
+-}
+-
+ /* iterates the non-control endpoints; 'tmp' is a struct usb_ep pointer */
+ #define gadget_for_each_ep(tmp, gadget) \
+ list_for_each_entry(tmp, &(gadget)->ep_list, ep_list)
+@@ -861,4 +859,9 @@ extern void usb_ep_autoconfig_reset(struct usb_gadget *);
+
+ extern int usb_gadget_handle_interrupts(void);
+
++extern int usb_gadget_init_udc(void);
++extern void usb_gadget_exit_udc(void);
++extern int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
++ int (*bind)(struct usb_gadget *));
++
+ #endif /* __LINUX_USB_GADGET_H */
+diff --git a/include/usb/fastboot.h b/include/usb/fastboot.h
+new file mode 100644
+index 0000000..e55149a
+--- /dev/null
++++ b/include/usb/fastboot.h
+@@ -0,0 +1,100 @@
++/*
++ * (C) Copyright 2008 - 2009
++ * Windriver, <www.windriver.com>
++ * Tom Rix <Tom.Rix@windriver.com>
++ *
++ * Copyright (c) 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de>
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ *
++ * The logical naming of flash comes from the Android project
++ * Thse structures and functions that look like fastboot_flash_*
++ * They come from bootloader/legacy/include/boot/flash.h
++ *
++ * The boot_img_hdr structure and associated magic numbers also
++ * come from the Android project. They are from
++ * bootloader/legacy/include/boot/bootimg.h
++ *
++ * Here are their copyrights
++ *
++ * Copyright (C) 2008 The Android Open Source Project
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in
++ * the documentation and/or other materials provided with the
++ * distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
++ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
++ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
++ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
++ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ *
++ */
++
++#ifndef FASTBOOT_H
++#define FASTBOOT_H
++
++#include <common.h>
++#include <command.h>
++#include <linux/usb/ch9.h>
++#include <linux/usb/gadget.h>
++#include <android_image.h>
++
++struct fastboot_config {
++
++ /*
++ * Transfer buffer for storing data sent by the client. It should be
++ * able to hold a kernel image and flash partitions. Care should be
++ * take so it does not overrun bootloader memory
++ */
++ unsigned char *transfer_buffer;
++
++ /* Size of the buffer mentioned above */
++ unsigned int transfer_buffer_size;
++};
++
++#define FB_STR_PRODUCT_IDX 1
++#define FB_STR_SERIAL_IDX 2
++#define FB_STR_CONFIG_IDX 3
++#define FB_STR_INTERFACE_IDX 4
++#define FB_STR_MANUFACTURER_IDX 5
++#define FB_STR_PROC_REV_IDX 6
++#define FB_STR_PROC_TYPE_IDX 7
++
++#if (CONFIG_CMD_FASTBOOT)
++
++int fastboot_init(void);
++void fastboot_shutdown(void);
++int fastboot_poll(void);
++
++int fastboot_board_init(struct fastboot_config *interface,
++ struct usb_gadget_strings **str);
++#endif
++#endif
+diff --git a/pft-config.xml b/pft-config.xml
+new file mode 100644
+index 0000000..885875f
+--- /dev/null
++++ b/pft-config.xml
+@@ -0,0 +1,28 @@
++<?xml version="1.0" encoding="utf-8"?>
++<flashfile version="1">
++ <id>system</id>
++ <platform>saltbay</platform>
++ <gpflag>
++ <value>0x80000007</value>
++ </gpflag>
++ <code_group name="FIRMWARE">
++ <file TYPE="IFWI">
++ <name>ifwi_saltbay_pr2.bin</name>
++ <version>0003.008d</version>
++ </file>
++ <file TYPE="FW_DNX">
++ <name>dnx_fwr_saltbay_pr2.bin</name>
++ <version>0003.008d</version>
++ </file>
++ <file TYPE="OS_DNX">
++ <name>dnx_osr_saltbay_pr2.bin</name>
++ <version>0003.008d</version>
++ </file>
++ </code_group>
++ <code_group name="BOOTLOADER">
++ <file TYPE="KBOOT">
++ <name>u-boot.bin.osip</name>
++ <version>main-weekly-1115</version>
++ </file>
++ </code_group>
++</flashfile>
+--
+1.8.3.2
+
diff --git a/meta-edison/recipes-bsp/u-boot/u-boot-fw-utils_2014.04.bb b/meta-edison/recipes-bsp/u-boot/u-boot-fw-utils_2014.04.bb
new file mode 100644
index 0000000..0c2353c
--- /dev/null
+++ b/meta-edison/recipes-bsp/u-boot/u-boot-fw-utils_2014.04.bb
@@ -0,0 +1,28 @@
+DESCRIPTION = "U-boot bootloader fw_printenv/setenv utils"
+LICENSE = "GPLv2+"
+LIC_FILES_CHKSUM = "file://Licenses/README;md5=025bf9f768cbcb1a165dbe1a110babfb"
+SECTION = "bootloader"
+
+require u-boot-internal.inc
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
+SRC_URI += "file://fw_env.config"
+
+EXTRA_OEMAKE = 'CROSS_COMPILE=${TARGET_PREFIX} CC="${TARGET_PREFIX}gcc ${TOOLCHAIN_OPTIONS}"'
+
+do_compile () {
+ oe_runmake ${UBOOT_MACHINE}
+ oe_runmake env
+}
+
+do_install () {
+ install -d ${D}${sbindir}
+ install -m 755 ${S}/tools/env/fw_printenv_unstripped ${D}${sbindir}/fw_printenv
+ # This is not a typo, this tool checks the args[0] to change its behavior a-la-busybox
+ install -m 755 ${S}/tools/env/fw_printenv_unstripped ${D}${sbindir}/fw_setenv
+}
+
+FILES_${PN} = "${sbindir}/*"
+FILES_${PN} += "${sysconfdir}/fw_env.config"
+
+DEPENDS = "u-boot"
diff --git a/meta-edison/recipes-bsp/u-boot/u-boot-internal.inc b/meta-edison/recipes-bsp/u-boot/u-boot-internal.inc
new file mode 100644
index 0000000..35698d7
--- /dev/null
+++ b/meta-edison/recipes-bsp/u-boot/u-boot-internal.inc
@@ -0,0 +1,10 @@
+PV = "2014.04-1"
+S = "${WORKDIR}/git"
+
+PACKAGE_ARCH = "${MACHINE_ARCH}"
+
+SRC_URI = "git://git.denx.de/u-boot.git;branch=master"
+SRC_URI += "file://upstream_to_edison.patch"
+SRC_URI += "file://${MACHINE}.env"
+SRC_URI += "file://target_env/*.env"
+SRCREV = "dda0dbfc69f3d560c87f5be85f127ed862ea6721"
diff --git a/meta-edison/recipes-bsp/u-boot/u-boot-osip.inc b/meta-edison/recipes-bsp/u-boot/u-boot-osip.inc
new file mode 100644
index 0000000..d05d440
--- /dev/null
+++ b/meta-edison/recipes-bsp/u-boot/u-boot-osip.inc
@@ -0,0 +1,208 @@
+OSIP_STARTING_LBA = "2048"
+OSIP_DESTINATION_POINTER = "17825792"
+OSIP_HANDOFF_POINTER = "17829888"
+
+# env is U-Boot primary environment where internal U-Boot variables are stored
+# this default generated binary environment, is embedded in a raw OSIP image
+# use by XFSTK tools to do the initial boot
+ENV_IMAGE = "${S}/env.bin"
+BASE_IMAGE = "${S}/u-boot.bin"
+UBOOT_OSIP_SUFFIX = "img"
+UBOOT_TMP_IMG = "${S}/u-boot.${UBOOT_OSIP_SUFFIX}.no-osip"
+UBOOT_IMG = "${S}/u-boot.${UBOOT_OSIP_SUFFIX}"
+UBOOT_OSIP_IMAGE = "u-boot-${MACHINE}-${PV}-${PR}.${UBOOT_OSIP_SUFFIX}"
+UBOOT_OSIP_BINARY = "u-boot.${UBOOT_OSIP_SUFFIX}"
+UBOOT_OSIP_SYMLINK = "u-boot-${MACHINE}.${UBOOT_OSIP_SUFFIX}"
+
+
+do_uboot_padding() {
+ # U-Boot.bin map
+ # 0x000000 - 0x001000 | padding with 0
+ # 0x001000 - 0x200000 | u-boot0
+ dd if=/dev/zero of=u-boot.padding bs=4096 count=1
+ cat u-boot.padding ${BASE_IMAGE} | dd of=u-boot.bin.padded
+
+ # Align u-boot.bin to 4K for dfu
+ filesize=$(stat -c %s u-boot.bin.padded)
+ alignment=$(echo "4096 - (${filesize} % 4096)" | bc)
+ if [ ${alignment} -ne 0 ];
+ then
+ dd if=/dev/zero of=u-boot.bin.padded bs=1 count=${alignment} conv=notrunc seek=${filesize}
+ fi
+
+ cp u-boot.bin.padded ${BASE_IMAGE}
+}
+
+do_uboot_uboot_env_mkimage() {
+
+ # U-Boot.img map
+ # 0x000000 - 0x001000 | padding with 0
+ # 0x001000 - 0x200000 | u-boot0
+ # 0x200000 - 0x300000 | primary environment
+ # 0x300000 - 0x500000 | reserved
+ # 0x500000 - 0x600000 | secondary environment
+
+ # U-Boot.img on eMMC in LBA (LBA size: 512 bytes)
+ # | description | OSII | GPT label
+ # 0x000000 - 0x000001 | MBR + OSIP | - | -
+ # 0x000001 - 0x000022 | GPT | - | -
+ # 0x000022 - 0x000800 | padding with 0 (alignment) | - | -
+ # 0x000800 - 0x001800 | u-boot0 | 1 | u-boot0
+ # 0x001800 - 0x002600 | primary environment | - | u-boot-env0
+ # 0x002600 - 0x003600 | u-boot1 | 2 | u-boot1
+ # 0x003600 - 0x004400 | secondary environment | - | u-boot-env1
+
+
+ # Fill U-Boot.img with 0
+ dd if=/dev/zero of=${UBOOT_TMP_IMG} bs=6M count=1
+ # copy u-boot.bin in u-boot.img (u-boot0)
+ dd if=${BASE_IMAGE} of=${UBOOT_TMP_IMG} bs=1M conv=notrunc
+ # copy (offset 2M) u-boot_env0.bin in u-boot.img (u-boot0)
+ dd if=${ENV_IMAGE} of=${UBOOT_TMP_IMG} bs=1M conv=notrunc seek=2
+ # copy (offset 5M) u-boot_env1.bin in u-boot.img (u-boot0)
+ dd if=${ENV_IMAGE} of=${UBOOT_TMP_IMG} bs=1M conv=notrunc seek=5
+}
+
+python do_osip_mkimage() {
+ #
+ # Stitch an image to create an OSIP image (OS Image Profile).
+ # This script currently supports only one OSII (OS Image Identifier)
+ # If more is necessary, it will need to be adjusted.
+ #
+ # This is the C struct for one OSII (size = 24 bytes)
+ # struct OSII { //os image identifier
+ # uint16_t os_rev_minor;
+ # uint16_t os_rev_major;
+ # uint32_t logical_start_block; //units defined by get_block_size() if
+ # //reading/writing to/from nand, units of
+ # //512 bytes if cracking a stitched image
+ # uint32_t ddr_load_address;
+ # uint32_t entry_point;
+ # uint32_t size_of_os_image; //units defined by get_page_size() if
+ # //reading/writing to/from nand, units of
+ # //512 bytes if cracking a stitched image
+ # uint8_t attribute;
+ # uint8_t reserved[3];
+ # };
+
+ # This is what a full OSIP header contains
+ # Its size is 512 bytes
+ # Offset Size (bytes) Description
+ # 0x000 4 OSIP Signature "$OS$"
+ # 0x004 1 Reserved
+ # 0x005 1 Header minor revision
+ # 0x006 1 Header major revision
+ # 0x007 1 Header checksum
+ # 0x008 1 Number of pointers
+ # 0x009 1 Number of images
+ # 0x00a 2 Header size
+ # 0x00c 20 Reserved
+ # 0x020 24 1st bootable image descriptor (OSII)
+ # 0x038 24 2nd bootable image descriptor (OSII)
+ # ... ... ...
+ # 0x170 24 15th bootable image descriptor (OSII)
+ # 0x188 48 Not used
+ # 0x1B8 4 Disk signature
+ # 0x1BC 2 Null (0x0000)
+ # 0x1BE 16 1st primary partition descriptor
+ # 0x1CE 16 2nd primary partition descriptor
+ # 0x1DE 16 3rd primary partition descriptor
+ # 0x1EE 16 4th primary partition descriptor
+ # 0x1FE 1 0x55
+ # 0x1FF 1 0xaa
+
+ import os
+ import sys
+ import argparse
+ import struct
+
+ # As only a small portion of the OSIP header needs to be changed
+ # we simply store a full binary copy and we'll change just the
+ # necessary values in it
+ OSIP_HEADER_HEX_DATA = \
+ '244f532400000121010138000000000000000000000000000000000000' \
+ '00000000000000220000000000100100101001380100000f000000ffff' \
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' \
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' \
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' \
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' \
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' \
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' \
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' \
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' \
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' \
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' \
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' \
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' \
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' \
+ 'ffffffffff00000000000000000000ee0000000100000000e0a3030000' \
+ '0000000000000000000000000000000000000000000000000000000000' \
+ '000000000000000000000000000000000055aa'
+
+ def main():
+ input_file = "${UBOOT_TMP_IMG}"
+ output_file = "${UBOOT_IMG}"
+ handoff_pointer = ${OSIP_HANDOFF_POINTER}
+ destination_pointer = ${OSIP_DESTINATION_POINTER}
+ starting_lba = ${OSIP_STARTING_LBA}
+
+ in_file_data = open(input_file, 'rb').read()
+
+ out_file = open(output_file, 'wb')
+
+ # Write OSIP header data
+ osip_header_data = bytearray(OSIP_HEADER_HEX_DATA.decode('hex'))
+
+ # Override some values
+
+ # Overrides starting LBA of imge in eMMC
+ starting_lba_packed = struct.pack("I", starting_lba)
+ osip_header_data[0x24:0x27+1]=starting_lba_packed
+
+ # Overrides destination pointer to image in DDR
+ destination_pointer_packed = struct.pack("I", destination_pointer)
+ osip_header_data[0x28:0x2B+1]=destination_pointer_packed
+
+ # Overrides pointer to handoff entry point in image
+ handoff_pointer_packed = struct.pack("I", handoff_pointer)
+ osip_header_data[0x2C:0x2F+1]=handoff_pointer_packed
+
+ # The file needs to be padded to be multiple of 512 bytes
+
+ # Overrides passed image size (in unit of 512 bytes blocks)
+ padding_len_packed_block = struct.pack("I", ( (6*1024*1024) / 512))
+ osip_header_data[0x30:0x33+1]=padding_len_packed_block
+
+ # Compute XOR checksum
+ osip_header_size = 1*0x18+0x20 # 24 bytes per OSII + 32 bytes header
+ osip_header_data[0x07]=0
+ crc = osip_header_data[0]
+ for i in range(1, osip_header_size):
+ crc ^= osip_header_data[i]
+ osip_header_data[0x07]=crc
+
+ out_file.write(osip_header_data)
+
+ # Write image content
+ out_file.write(in_file_data)
+
+ out_file.close()
+
+ return 0
+
+ main()
+}
+
+do_deploy_append() {
+ install -d ${DEPLOYDIR}
+ install ${UBOOT_IMG} ${DEPLOYDIR}/${UBOOT_OSIP_IMAGE}
+
+ cd ${DEPLOYDIR}
+ rm -f ${UBOOT_IMG} ${UBOOT_OSIP_SYMLINK}
+ ln -sf ${UBOOT_OSIP_IMAGE} ${UBOOT_OSIP_SYMLINK}
+ ln -sf ${UBOOT_OSIP_IMAGE} ${UBOOT_OSIP_BINARY}
+}
+
+addtask uboot_padding before do_environment_mkimage before do_deploy after do_compile
+addtask uboot_uboot_env_mkimage before do_osip_mkimage after do_environment_mkimage
+addtask osip_mkimage before do_deploy after do_uboot_uboot_env_mkimage
diff --git a/meta-edison/recipes-bsp/u-boot/u-boot-target-env.inc b/meta-edison/recipes-bsp/u-boot/u-boot-target-env.inc
new file mode 100644
index 0000000..6dee3d1
--- /dev/null
+++ b/meta-edison/recipes-bsp/u-boot/u-boot-target-env.inc
@@ -0,0 +1,93 @@
+# Handle severals environments generation for u-boot
+# and link the default one for Ifwi to u-boot-osip recipe
+
+#Env binary size
+ENV_SIZE = "0x10000"
+
+#Env base Name
+ENV_BASE_NAME = "${MACHINE}"
+# Env base file correspond to common part of all environment
+ENV_BASE_FILE = "${WORKDIR}/${ENV_BASE_NAME}.env"
+
+# Env directory is where target variant files are stored
+ENV_DIR = "${WORKDIR}/target_env"
+# Env composed is directory where target env are composed
+# by concatening of base environment file and variant files
+# pattern name is applied the resulting files: base-variant.env
+ENV_COMPOSED_DIR = "${WORKDIR}/target_composed"
+# Env bin is directory where target env are store in binary form
+# filename follows pattern name above : base-variant.bin
+ENV_BIN_DIR = "${WORKDIR}/target_env_bin"
+
+# Env deploy dir is the name of directory where binary envs will be deployed
+ENV_DEPLOY_DIR="u-boot-envs"
+
+# Env deploy src dir is the name of directory where txt envs will be deployed
+ENV_SRC_DEPLOY_DIR="u-boot-envs-src"
+
+# Env target to use for IFWI stitching process
+ENV_IFWI_TARGET_NAME="ifwi"
+# Env image is U-Boot primary environment (where internal U-Boot variables are stored)
+# The same vairiable is also defined in u-boot-osip recip in charge of doing stitching
+# process for IFWI
+ENV_IMAGE = "${S}/env.bin"
+
+do_build_mkimage_tool () {
+ HOSTCC="${CC}" HOSTLD="${LD}" HOSTLDFLAGS="${LDFLAGS}" HOSTSTRIP=true oe_runmake tools
+}
+
+python do_environment_mkimage() {
+ import subprocess
+ import shutil
+ # list env variant target files
+ target_root_dir = d.getVar('ENV_DIR',True)
+ env_files = os.listdir(target_root_dir )
+ # builds absolute paths
+ env_files = [ os.path.join(target_root_dir,f) for f in env_files]
+
+ env_bin_dir = d.getVar("ENV_BIN_DIR",True)
+ # cleans if it exists env_bin directory
+ shutil.rmtree(env_bin_dir, ignore_errors=True)
+ # create env bin directory
+ os.mkdir(env_bin_dir)
+ # if a previous env image used for osip process exists delete it
+ env_image = d.getVar('ENV_IMAGE',True)
+ try:
+ os.unlink(env_image)
+ except OSError: pass
+ print 'Building binary environments in : %s' % env_bin_dir
+ # iterate targets list to build binary environment files
+ for target_env in env_files :
+ # get only filename without path and extension
+ target_filename = os.path.splitext(os.path.basename(target_env))[0]
+ # build output file path with ext
+ target_bin = os.path.join(env_bin_dir,
+ d.getVar('ENV_BASE_NAME',True) + '-' + target_filename + '.bin')
+ # generated mkenvimage tool command line
+ cmd_mkimg ='cat %s %s | grep -v -E "^$|^\#" |' \
+ ' ./tools/mkenvimage -s %s -r -o %s -' \
+ % ( d.getVar('ENV_BASE_FILE',True),target_env,
+ d.getVar("ENV_SIZE",True), target_bin)
+ print 'Building binary for %s target:' % (target_filename)
+ print '%s' % cmd_mkimg
+ # execute shell command
+ ret = subprocess.call(cmd_mkimg, shell=True)
+ if ret: return ret
+ if d.getVar('ENV_IFWI_TARGET_NAME',True) in target_bin :
+ # create a symbolic link on default binary file env file to
+ # avoid modifying to much osip part
+ print 'Create for IFWI stitching symlink %s to %s' % (env_image, target_bin)
+ os.symlink(target_bin, env_image)
+ return 0
+}
+
+do_deploy_append() {
+ install -d ${DEPLOYDIR}
+ # deploy binary U-boot environments
+ echo "Deploying U-boot Environments binary files in ${DEPLOYDIR}/${ENV_DEPLOY_DIR}"
+ install -d ${DEPLOYDIR}/${ENV_DEPLOY_DIR}
+ cp ${ENV_BIN_DIR}/*.bin ${DEPLOYDIR}/${ENV_DEPLOY_DIR}
+}
+
+addtask build_mkimage_tool after do_compile before do_environment_mkimage
+addtask environment_mkimage after do_build_mkimage_tool before do_deploy
diff --git a/meta-edison/recipes-bsp/u-boot/u-boot-tools_2014.04.bb b/meta-edison/recipes-bsp/u-boot/u-boot-tools_2014.04.bb
new file mode 100644
index 0000000..ebbef01
--- /dev/null
+++ b/meta-edison/recipes-bsp/u-boot/u-boot-tools_2014.04.bb
@@ -0,0 +1,22 @@
+DESCRIPTION = "U-boot bootloader mkimage tool"
+LICENSE = "GPLv2+"
+LIC_FILES_CHKSUM = "file://Licenses/README;md5=025bf9f768cbcb1a165dbe1a110babfb"
+SECTION = "bootloader"
+
+require u-boot-internal.inc
+
+EXTRA_OEMAKE = 'HOSTCC="${CC}" HOSTLD="${LD}" HOSTLDFLAGS="${LDFLAGS}" HOSTSTRIP=true'
+
+do_compile () {
+ oe_runmake tools
+}
+
+do_install () {
+ install -d ${D}${bindir}
+ install -m 0755 tools/mkimage ${D}${bindir}/uboot-mkimage
+ install -m 0755 tools/mkenvimage ${D}${bindir}/uboot-mkenvimage
+ ln -sf uboot-mkimage ${D}${bindir}/mkimage
+ ln -sf uboot-mkenvimage ${D}${bindir}/mkenvimage
+}
+
+BBCLASSEXTEND = "native nativesdk"
diff --git a/meta-edison/recipes-bsp/u-boot/u-boot_2014.04.bb b/meta-edison/recipes-bsp/u-boot/u-boot_2014.04.bb
new file mode 100644
index 0000000..3785576
--- /dev/null
+++ b/meta-edison/recipes-bsp/u-boot/u-boot_2014.04.bb
@@ -0,0 +1,7 @@
+require u-boot-internal.inc
+require recipes-bsp/u-boot/u-boot.inc
+require u-boot-target-env.inc
+require u-boot-osip.inc
+
+LICENSE = "GPLv2+"
+LIC_FILES_CHKSUM = "file://Licenses/README;md5=025bf9f768cbcb1a165dbe1a110babfb"
diff --git a/meta-edison/recipes-kernel/bcm43340-bt/bcm43340-bt_1.0.bb b/meta-edison/recipes-kernel/bcm43340-bt/bcm43340-bt_1.0.bb
new file mode 100644
index 0000000..d2c1c1e
--- /dev/null
+++ b/meta-edison/recipes-kernel/bcm43340-bt/bcm43340-bt_1.0.bb
@@ -0,0 +1,26 @@
+DESCRIPTION = "Broadcom Bluetooth fw files and patch utility"
+SECTION = "connectivity"
+
+FILESEXTRAPATHS_prepend := "${EDISONREPO_TOP_DIR}/broadcom_cws/bluetooth/firmware/"
+
+SRC_URI = "file://BCM43341B0_002.001.014.0122.0166.hcd \
+ file://brcm_patchram_plus.c \
+ file://LICENCE.broadcom_bcm43xx"
+
+LICENSE = "Proprietary"
+LIC_FILES_CHKSUM = "file://LICENCE.broadcom_bcm43xx;md5=3160c14df7228891b868060e1951dfbc"
+
+S = "${WORKDIR}"
+
+FILESDIR = "${FILE_DIRNAME}/files/"
+
+do_compile() {
+ ${CC} -O2 -Wall -o brcm_patchram_plus brcm_patchram_plus.c
+}
+
+do_install() {
+ install -v -d ${D}/etc/firmware/
+ install -m 0755 BCM43341B0_002.001.014.0122.0166.hcd ${D}/etc/firmware/bcm43341.hcd
+ install -v -d ${D}/usr/sbin/
+ install -m 0755 brcm_patchram_plus ${D}/usr/sbin/
+}
diff --git a/meta-edison/recipes-kernel/bcm43340/.gitignore b/meta-edison/recipes-kernel/bcm43340/.gitignore
new file mode 100644
index 0000000..be1970b
--- /dev/null
+++ b/meta-edison/recipes-kernel/bcm43340/.gitignore
@@ -0,0 +1 @@
+PRIVATE
diff --git a/meta-edison/recipes-kernel/bcm43340/bcm43340-fw.bb b/meta-edison/recipes-kernel/bcm43340/bcm43340-fw.bb
new file mode 100644
index 0000000..89c9f6d
--- /dev/null
+++ b/meta-edison/recipes-kernel/bcm43340/bcm43340-fw.bb
@@ -0,0 +1,29 @@
+DESCRIPTION = "Firmware files for use with Linux kernel"
+SECTION = "kernel"
+
+FILESEXTRAPATHS_prepend := "${EDISONREPO_TOP_DIR}/broadcom_cws/wlan/firmware/"
+
+SRC_URI = "file://bcmdhd_aob.cal_4334x_b0 \
+ file://bcmdhd.cal_4334x_b0 \
+ file://fw_bcmdhd_p2p.bin_4334x_b0 \
+ file://LICENCE.broadcom_bcm43xx"
+
+LICENSE = "Proprietary"
+LIC_FILES_CHKSUM = "file://LICENCE.broadcom_bcm43xx;md5=3160c14df7228891b868060e1951dfbc"
+
+PV = "6.20.190"
+PR = "r2"
+
+S = "${WORKDIR}"
+
+inherit allarch update-alternatives
+
+FILESDIR = "${FILE_DIRNAME}/files/"
+
+do_install() {
+ install -v -d ${D}/etc/firmware/
+ install -m 0755 bcmdhd_aob.cal_4334x_b0 ${D}/etc/firmware/bcmdhd_aob.cal
+ install -m 0755 bcmdhd.cal_4334x_b0 ${D}/etc/firmware/bcmdhd.cal
+ install -m 0755 fw_bcmdhd_p2p.bin_4334x_b0 ${D}/etc/firmware/fw_bcmdhd.bin
+ install -m 0755 LICENCE.broadcom_bcm43xx ${D}/etc/firmware/
+}
diff --git a/meta-edison/recipes-kernel/bcm43340/bcm43340-mod.bb b/meta-edison/recipes-kernel/bcm43340/bcm43340-mod.bb
new file mode 100644
index 0000000..2a86839
--- /dev/null
+++ b/meta-edison/recipes-kernel/bcm43340/bcm43340-mod.bb
@@ -0,0 +1,14 @@
+DESCRIPTION = "Broadcom wifi driver for the 43340"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://COPYING;md5=f9986853fb3b3403700e7535a392d014"
+
+inherit module
+
+PV = "1.141"
+PR = "r47"
+
+S = "${EDISONREPO_TOP_DIR}/broadcom_cws/wlan/driver_bcm43x/"
+
+do_clean() {
+ make clean
+}
diff --git a/meta-edison/recipes-kernel/linux/files/defconfig b/meta-edison/recipes-kernel/linux/files/defconfig
new file mode 100644
index 0000000..7f3e626
--- /dev/null
+++ b/meta-edison/recipes-kernel/linux/files/defconfig
@@ -0,0 +1,3768 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux/x86 3.10.17 Kernel Configuration
+#
+# CONFIG_64BIT is not set
+CONFIG_X86_32=y
+CONFIG_X86=y
+CONFIG_INSTRUCTION_DECODER=y
+CONFIG_OUTPUT_FORMAT="elf32-i386"
+CONFIG_ARCH_DEFCONFIG="arch/x86/configs/i386_defconfig"
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_MMU=y
+CONFIG_NEED_SG_DMA_LENGTH=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_HAS_CPU_RELAX=y
+CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
+CONFIG_ARCH_HAS_CPU_AUTOPROBE=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
+CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_ZONE_DMA32 is not set
+# CONFIG_AUDIT_ARCH is not set
+CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
+CONFIG_X86_32_SMP=y
+CONFIG_X86_HT=y
+CONFIG_X86_32_LAZY_GS=y
+CONFIG_ARCH_HWEIGHT_CFLAGS="-fcall-saved-ecx -fcall-saved-edx"
+CONFIG_ARCH_CPU_PROBE_RELEASE=y
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_IRQ_WORK=y
+CONFIG_BUILDTIME_EXTABLE_SORT=y
+
+#
+# General setup
+#
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION="-poky-edison"
+CONFIG_LOCALVERSION_AUTO=n
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_XZ is not set
+# CONFIG_KERNEL_LZO is not set
+CONFIG_DEFAULT_HOSTNAME="(none)"
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+CONFIG_FHANDLE=y
+CONFIG_AUDIT=y
+CONFIG_AUDITSYSCALL=y
+CONFIG_AUDIT_WATCH=y
+CONFIG_AUDIT_TREE=y
+# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_PENDING_IRQ=y
+CONFIG_IRQ_DOMAIN=y
+# CONFIG_IRQ_DOMAIN_DEBUG is not set
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_CLOCKSOURCE_WATCHDOG=y
+CONFIG_KTIME_SCALAR=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+
+#
+# Timers subsystem
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ_COMMON=y
+# CONFIG_HZ_PERIODIC is not set
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+
+#
+# CPU/Task time and stats accounting
+#
+# CONFIG_TICK_CPU_ACCOUNTING is not set
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_PREEMPT_RCU=y
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_RCU_FANOUT=32
+CONFIG_RCU_FANOUT_LEAF=16
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_RCU_FAST_NO_HZ is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_RCU_BOOST is not set
+# CONFIG_RCU_NOCB_CPU is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=18
+CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
+CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y
+CONFIG_ARCH_WANTS_PROT_NUMA_PROT_NONE=y
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_PROC_PID_CPUSET=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+# CONFIG_MEMCG is not set
+CONFIG_CGROUP_PERF=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_CFS_BANDWIDTH is not set
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_CGROUP=y
+# CONFIG_DEBUG_BLK_CGROUP is not set
+# CONFIG_CHECKPOINT_RESTORE is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_UIDGID_CONVERTED=y
+# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_HAVE_UID16=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_HOTPLUG=y
+CONFIG_HAVE_PCSPKR_PLATFORM=y
+CONFIG_EXPERT=y
+# CONFIG_UPTIME_LIMITED_KERNEL is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_PCSPKR_PLATFORM=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_EMBEDDED=y
+CONFIG_HAVE_PERF_EVENTS=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_PERF_EVENTS=y
+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_TRACEPOINTS=y
+CONFIG_OPROFILE=y
+# CONFIG_OPROFILE_EVENT_MULTIPLEX is not set
+CONFIG_HAVE_OPROFILE=y
+CONFIG_OPROFILE_NMI_TIMER=y
+CONFIG_KPROBES=y
+# CONFIG_JUMP_LABEL is not set
+CONFIG_KPROBES_ON_FTRACE=y
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_ARCH_USE_BUILTIN_BSWAP=y
+CONFIG_KRETPROBES=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_OPTPROBES=y
+CONFIG_HAVE_KPROBES_ON_FTRACE=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_HW_BREAKPOINT=y
+CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y
+CONFIG_HAVE_USER_RETURN_NOTIFIER=y
+CONFIG_HAVE_PERF_EVENTS_NMI=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
+CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
+CONFIG_HAVE_CMPXCHG_LOCAL=y
+CONFIG_HAVE_CMPXCHG_DOUBLE=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_OLD_SIGACTION=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_MODULE_SIG is not set
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+CONFIG_BLK_DEV_BSG=y
+# CONFIG_BLK_DEV_BSGLIB is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+CONFIG_BLK_DEV_THROTTLING=y
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+CONFIG_OSF_PARTITION=y
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+CONFIG_SUN_PARTITION=y
+# CONFIG_KARMA_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CFQ_GROUP_IOSCHED is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_ASN1=y
+CONFIG_UNINLINE_SPIN_UNLOCK=y
+CONFIG_FREEZER=y
+
+#
+# Processor type and features
+#
+CONFIG_ZONE_DMA=y
+CONFIG_SMP=y
+CONFIG_X86_MPPARSE=y
+# CONFIG_X86_BIGSMP is not set
+CONFIG_X86_EXTENDED_PLATFORM=y
+# CONFIG_X86_GOLDFISH is not set
+CONFIG_X86_WANT_INTEL_MID=y
+CONFIG_X86_INTEL_MID=y
+# CONFIG_X86_MDFLD is not set
+CONFIG_ATOM_SOC_POWER=y
+# CONFIG_REMOVEME_INTEL_ATOM_MDFLD_POWER is not set
+# CONFIG_REMOVEME_INTEL_ATOM_CLV_POWER is not set
+CONFIG_REMOVEME_INTEL_ATOM_MRFLD_POWER=y
+CONFIG_INTEL_DEBUG_FEATURE=y
+# CONFIG_X86_RDC321X is not set
+# CONFIG_X86_32_NON_STANDARD is not set
+CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y
+# CONFIG_X86_32_IRIS is not set
+# CONFIG_SCHED_OMIT_FRAME_POINTER is not set
+# CONFIG_HYPERVISOR_GUEST is not set
+CONFIG_NO_BOOTMEM=y
+# CONFIG_MEMTEST is not set
+# CONFIG_M486 is not set
+# CONFIG_M586 is not set
+# CONFIG_M586TSC is not set
+# CONFIG_M586MMX is not set
+# CONFIG_M686 is not set
+# CONFIG_MPENTIUMII is not set
+# CONFIG_MPENTIUMIII is not set
+# CONFIG_MPENTIUMM is not set
+# CONFIG_MPENTIUM4 is not set
+# CONFIG_MK6 is not set
+# CONFIG_MK7 is not set
+# CONFIG_MK8 is not set
+# CONFIG_MCRUSOE is not set
+# CONFIG_MEFFICEON is not set
+# CONFIG_MWINCHIPC6 is not set
+# CONFIG_MWINCHIP3D is not set
+# CONFIG_MELAN is not set
+# CONFIG_MGEODEGX1 is not set
+# CONFIG_MGEODE_LX is not set
+# CONFIG_MCYRIXIII is not set
+# CONFIG_MVIAC3_2 is not set
+# CONFIG_MVIAC7 is not set
+# CONFIG_MCORE2 is not set
+# CONFIG_MATOM is not set
+CONFIG_MSLM=y
+CONFIG_X86_GENERIC=y
+CONFIG_X86_INTERNODE_CACHE_SHIFT=6
+CONFIG_X86_L1_CACHE_SHIFT=6
+CONFIG_X86_INTEL_USERCOPY=y
+CONFIG_X86_USE_PPRO_CHECKSUM=y
+CONFIG_X86_TSC=y
+CONFIG_X86_CMPXCHG64=y
+CONFIG_X86_CMOV=y
+CONFIG_X86_MINIMUM_CPU_FAMILY=5
+CONFIG_X86_DEBUGCTLMSR=y
+# CONFIG_PROCESSOR_SELECT is not set
+CONFIG_CPU_SUP_INTEL=y
+CONFIG_CPU_SUP_CYRIX_32=y
+CONFIG_CPU_SUP_AMD=y
+CONFIG_CPU_SUP_CENTAUR=y
+CONFIG_CPU_SUP_TRANSMETA_32=y
+CONFIG_CPU_SUP_UMC_32=y
+# CONFIG_HPET_TIMER is not set
+# CONFIG_APB_TIMER is not set
+CONFIG_ARCH_NR_GPIO=512
+CONFIG_DMI=y
+CONFIG_NR_CPUS=2
+CONFIG_SCHED_SMT=y
+CONFIG_SCHED_MC=y
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_COUNT=y
+CONFIG_X86_LOCAL_APIC=y
+CONFIG_X86_IO_APIC=y
+# CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set
+CONFIG_X86_MCE=y
+CONFIG_X86_MCE_INTEL=y
+# CONFIG_X86_MCE_AMD is not set
+# CONFIG_X86_ANCIENT_MCE is not set
+CONFIG_X86_MCE_THRESHOLD=y
+# CONFIG_X86_MCE_INJECT is not set
+CONFIG_X86_THERMAL_VECTOR=y
+CONFIG_VM86=y
+# CONFIG_TOSHIBA is not set
+# CONFIG_I8K is not set
+CONFIG_X86_REBOOTFIXUPS=y
+# CONFIG_MICROCODE is not set
+CONFIG_X86_MSR=y
+CONFIG_X86_CPUID=y
+# CONFIG_NOHIGHMEM is not set
+# CONFIG_HIGHMEM4G is not set
+CONFIG_HIGHMEM64G=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_HIGHMEM=y
+CONFIG_X86_PAE=y
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ILLEGAL_POINTER_VALUE=0
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_SPARSEMEM_STATIC=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
+CONFIG_ARCH_DISCARD_MEMBLOCK=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=999999
+# CONFIG_COMPACTION is not set
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
+CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y
+# CONFIG_MEMORY_FAILURE is not set
+# CONFIG_TRANSPARENT_HUGEPAGE is not set
+CONFIG_CROSS_MEMORY_ATTACH=y
+# CONFIG_CLEANCACHE is not set
+# CONFIG_HIGHPTE is not set
+CONFIG_X86_CHECK_BIOS_CORRUPTION=y
+# CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK is not set
+CONFIG_X86_RESERVE_LOW=64
+# CONFIG_MATH_EMULATION is not set
+CONFIG_MTRR=y
+CONFIG_MTRR_SANITIZER=y
+CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=1
+CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=1
+CONFIG_X86_PAT=y
+CONFIG_ARCH_USES_PG_UNCACHED=y
+# CONFIG_ARCH_RANDOM is not set
+CONFIG_X86_SMAP=y
+# CONFIG_SECCOMP is not set
+# CONFIG_CC_STACKPROTECTOR is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+CONFIG_SCHED_HRTICK=y
+CONFIG_KEXEC=y
+# CONFIG_CRASH_DUMP is not set
+CONFIG_PHYSICAL_START=0x1200000
+# CONFIG_RELOCATABLE is not set
+CONFIG_PHYSICAL_ALIGN=0x100000
+CONFIG_HOTPLUG_CPU=y
+# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set
+# CONFIG_DEBUG_HOTPLUG_CPU0 is not set
+# CONFIG_COMPAT_VDSO is not set
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+
+#
+# Power management and ACPI options
+#
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_PM_SLEEP=y
+CONFIG_PM_SLEEP_SMP=y
+# CONFIG_PM_AUTOSLEEP is not set
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=100
+CONFIG_PM_WAKELOCKS_GC=y
+CONFIG_PM_RUNTIME=y
+CONFIG_PM=y
+CONFIG_PM_DEBUG=y
+CONFIG_PM_ADVANCED_DEBUG=y
+# CONFIG_PM_TEST_SUSPEND is not set
+CONFIG_PM_SLEEP_DEBUG=y
+# CONFIG_PM_TRACE_RTC is not set
+# CONFIG_ACPI is not set
+CONFIG_SFI=y
+# CONFIG_APM is not set
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+CONFIG_CPU_FREQ_GOV_COMMON=y
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+
+#
+# x86 CPU frequency scaling drivers
+#
+# CONFIG_X86_INTEL_PSTATE is not set
+CONFIG_X86_SFI_CPUFREQ=y
+# CONFIG_X86_POWERNOW_K6 is not set
+# CONFIG_X86_POWERNOW_K7 is not set
+# CONFIG_X86_GX_SUSPMOD is not set
+# CONFIG_X86_SPEEDSTEP_CENTRINO is not set
+# CONFIG_X86_SPEEDSTEP_ICH is not set
+# CONFIG_X86_SPEEDSTEP_SMI is not set
+# CONFIG_X86_P4_CLOCKMOD is not set
+# CONFIG_X86_CPUFREQ_NFORCE2 is not set
+# CONFIG_X86_LONGRUN is not set
+
+#
+# shared options
+#
+# CONFIG_X86_SPEEDSTEP_LIB is not set
+CONFIG_CPU_IDLE=y
+# CONFIG_CPU_IDLE_MULTIPLE_DRIVERS is not set
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
+CONFIG_INTEL_IDLE=y
+
+#
+# Bus options (PCI etc.)
+#
+CONFIG_PCI=y
+# CONFIG_PCI_GOBIOS is not set
+# CONFIG_PCI_GOMMCONFIG is not set
+# CONFIG_PCI_GODIRECT is not set
+CONFIG_PCI_GOANY=y
+CONFIG_PCI_BIOS=y
+CONFIG_PCI_DIRECT=y
+CONFIG_PCI_MMCONFIG=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_CNB20LE_QUIRK is not set
+CONFIG_PCIEPORTBUS=y
+# CONFIG_PCIEAER is not set
+CONFIG_PCIEASPM=y
+# CONFIG_PCIEASPM_DEBUG is not set
+# CONFIG_PCIEASPM_DEFAULT is not set
+# CONFIG_PCIEASPM_POWERSAVE is not set
+CONFIG_PCIEASPM_PERFORMANCE=y
+CONFIG_PCIE_PME=y
+CONFIG_ARCH_SUPPORTS_MSI=y
+CONFIG_PCI_MSI=y
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set
+# CONFIG_PCI_STUB is not set
+CONFIG_HT_IRQ=y
+# CONFIG_PCI_IOV is not set
+# CONFIG_PCI_PRI is not set
+# CONFIG_PCI_PASID is not set
+CONFIG_PCI_LABEL=y
+CONFIG_ISA_DMA_API=y
+# CONFIG_ISA is not set
+# CONFIG_SCx200 is not set
+# CONFIG_ALIX is not set
+# CONFIG_NET5501 is not set
+# CONFIG_GEOS is not set
+CONFIG_AMD_NB=y
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_RAPIDIO is not set
+
+#
+# Executable file formats / Emulations
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+CONFIG_BINFMT_SCRIPT=y
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+CONFIG_COREDUMP=y
+CONFIG_HAVE_ATOMIC_IOMAP=y
+CONFIG_HAVE_TEXT_POKE_SMP=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_DIAG is not set
+CONFIG_UNIX=y
+# CONFIG_UNIX_DIAG is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_ALGO=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_SUB_POLICY=y
+CONFIG_XFRM_MIGRATE=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+# CONFIG_IP_FIB_TRIE_STATS is not set
+CONFIG_IP_MULTIPLE_TABLES=y
+# CONFIG_IP_ROUTE_MULTIPATH is not set
+# CONFIG_IP_ROUTE_VERBOSE is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE_DEMUX is not set
+CONFIG_NET_IP_TUNNEL=y
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_NET_IPVTI is not set
+# CONFIG_INET_AH is not set
+CONFIG_INET_ESP=y
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_LRO=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_INET_UDP_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+CONFIG_TCP_MD5SIG=y
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
+# CONFIG_IPV6_SIT_6RD is not set
+CONFIG_IPV6_NDISC_NODETYPE=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_GRE is not set
+CONFIG_IPV6_MULTIPLE_TABLES=y
+# CONFIG_IPV6_SUBTREES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETLABEL is not set
+CONFIG_NETWORK_SECMARK=y
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=y
+# CONFIG_NETFILTER_NETLINK_ACCT is not set
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_MARK=y
+# CONFIG_NF_CONNTRACK_SECMARK is not set
+CONFIG_NF_CONNTRACK_PROCFS=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+# CONFIG_NF_CONNTRACK_TIMEOUT is not set
+# CONFIG_NF_CONNTRACK_TIMESTAMP is not set
+# CONFIG_NF_CT_PROTO_DCCP is not set
+# CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CT_PROTO_UDPLITE is not set
+# CONFIG_NF_CONNTRACK_AMANDA is not set
+# CONFIG_NF_CONNTRACK_FTP is not set
+# CONFIG_NF_CONNTRACK_H323 is not set
+# CONFIG_NF_CONNTRACK_IRC is not set
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_SNMP is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+# CONFIG_NF_CONNTRACK_SANE is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+# CONFIG_NF_CONNTRACK_TFTP is not set
+# CONFIG_NF_CT_NETLINK is not set
+# CONFIG_NF_CT_NETLINK_TIMEOUT is not set
+CONFIG_NF_NAT=y
+CONFIG_NF_NAT_NEEDED=y
+# CONFIG_NF_NAT_AMANDA is not set
+# CONFIG_NF_NAT_FTP is not set
+# CONFIG_NF_NAT_IRC is not set
+# CONFIG_NF_NAT_SIP is not set
+# CONFIG_NF_NAT_TFTP is not set
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XTABLES=y
+
+#
+# Xtables combined modules
+#
+CONFIG_NETFILTER_XT_MARK=y
+CONFIG_NETFILTER_XT_CONNMARK=y
+
+#
+# Xtables targets
+#
+# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set
+# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+# CONFIG_NETFILTER_XT_TARGET_CT is not set
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+CONFIG_NETFILTER_XT_TARGET_HL=y
+# CONFIG_NETFILTER_XT_TARGET_HMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set
+# CONFIG_NETFILTER_XT_TARGET_LED is not set
+# CONFIG_NETFILTER_XT_TARGET_LOG is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+CONFIG_NETFILTER_XT_TARGET_NETMAP=y
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+CONFIG_NETFILTER_XT_TARGET_REDIRECT=y
+# CONFIG_NETFILTER_XT_TARGET_TEE is not set
+# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set
+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
+# CONFIG_NETFILTER_XT_TARGET_SECMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
+
+#
+# Xtables matches
+#
+# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_BPF is not set
+CONFIG_NETFILTER_XT_MATCH_CLUSTER=y
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
+# CONFIG_NETFILTER_XT_MATCH_CPU is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ECN is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_HL=y
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set
+# CONFIG_NETFILTER_XT_MATCH_OSF is not set
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+# CONFIG_IP_SET is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_AH is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_RPFILTER is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+# CONFIG_IP_NF_TARGET_ULOG is not set
+CONFIG_NF_NAT_IPV4=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+# CONFIG_NF_NAT_PPTP is not set
+# CONFIG_NF_NAT_H323 is not set
+CONFIG_IP_NF_MANGLE=y
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_TTL is not set
+CONFIG_IP_NF_RAW=y
+# CONFIG_IP_NF_SECURITY is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV6=y
+# CONFIG_NF_CONNTRACK_IPV6 is not set
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_AH=y
+CONFIG_IP6_NF_MATCH_EUI64=y
+CONFIG_IP6_NF_MATCH_FRAG=y
+CONFIG_IP6_NF_MATCH_OPTS=y
+CONFIG_IP6_NF_MATCH_HL=y
+CONFIG_IP6_NF_MATCH_IPV6HEADER=y
+CONFIG_IP6_NF_MATCH_MH=y
+# CONFIG_IP6_NF_MATCH_RPFILTER is not set
+CONFIG_IP6_NF_MATCH_RT=y
+CONFIG_IP6_NF_TARGET_HL=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+# CONFIG_IP6_NF_SECURITY is not set
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+CONFIG_L2TP=y
+# CONFIG_L2TP_DEBUGFS is not set
+# CONFIG_L2TP_V3 is not set
+CONFIG_STP=y
+CONFIG_BRIDGE=y
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+CONFIG_HAVE_NET_DSA=y
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+CONFIG_DNS_RESOLVER=y
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_OPENVSWITCH is not set
+# CONFIG_VSOCKETS is not set
+# CONFIG_NETLINK_MMAP is not set
+# CONFIG_NETLINK_DIAG is not set
+CONFIG_RPS=y
+CONFIG_RFS_ACCEL=y
+CONFIG_XPS=y
+# CONFIG_NETPRIO_CGROUP is not set
+CONFIG_BQL=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_TCPPROBE is not set
+# CONFIG_NET_DROP_MONITOR is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BT_HCIBTUSB is not set
+# CONFIG_BT_HCIBTSDIO is not set
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+# CONFIG_BT_HCIUART_BCSP is not set
+# CONFIG_BT_HCIUART_ATH3K is not set
+# CONFIG_BT_HCIUART_LL is not set
+# CONFIG_BT_HCIUART_3WIRE is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_BT_MRVL is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_FIB_RULES=y
+CONFIG_WIRELESS=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_CFG80211=y
+# CONFIG_NL80211_TESTMODE is not set
+CONFIG_CFG80211_DEVELOPER_WARNINGS=y
+# CONFIG_CFG80211_REG_DEBUG is not set
+# CONFIG_CFG80211_CERTIFICATION_ONUS is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_CFG80211_DEBUGFS is not set
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+CONFIG_CFG80211_WEXT=y
+# CONFIG_LIB80211 is not set
+CONFIG_MAC80211=m
+CONFIG_MAC80211_HAS_RC=y
+# CONFIG_MAC80211_RC_PID is not set
+CONFIG_MAC80211_RC_MINSTREL=y
+CONFIG_MAC80211_RC_MINSTREL_HT=y
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
+# CONFIG_MAC80211_MESH is not set
+# CONFIG_MAC80211_LEDS is not set
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_MESSAGE_TRACING is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+# CONFIG_WIMAX is not set
+CONFIG_RFKILL=y
+CONFIG_RFKILL_LEDS=y
+CONFIG_RFKILL_INPUT=y
+# CONFIG_RFKILL_REGULATOR is not set
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB is not set
+# CONFIG_NFC is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH=""
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+CONFIG_FW_LOADER_USER_HELPER=y
+# CONFIG_DEBUG_DRIVER is not set
+CONFIG_DEBUG_DEVRES=y
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_GENERIC_CPU_DEVICES is not set
+CONFIG_REGMAP=y
+CONFIG_REGMAP_I2C=y
+CONFIG_REGMAP_SPI=y
+CONFIG_REGMAP_IRQ=y
+CONFIG_DMA_SHARED_BUFFER=y
+# CONFIG_CMA is not set
+
+#
+# Bus devices
+#
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_DRBD is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_NVME is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_VIRTIO_BLK is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_RBD is not set
+# CONFIG_BLK_DEV_RSXX is not set
+
+#
+# Misc devices
+#
+# CONFIG_SENSORS_LIS3LV02D is not set
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_DUMMY_IRQ is not set
+# CONFIG_IBM_ASM is not set
+# CONFIG_PHANTOM is not set
+CONFIG_INTEL_MID_PTI=y
+CONFIG_INTEL_PTI_STM=y
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ATMEL_SSC is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_APDS9802ALS is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_ISL29020 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_BH1780 is not set
+# CONFIG_SENSORS_BH1770 is not set
+# CONFIG_SENSORS_APDS990X is not set
+# CONFIG_HMC6352 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
+# CONFIG_BMP085_I2C is not set
+# CONFIG_BMP085_SPI is not set
+# CONFIG_PCH_PHUB is not set
+# CONFIG_USB_SWITCH_FSA9480 is not set
+# CONFIG_LATTICE_ECP3_CONFIG is not set
+# CONFIG_SRAM is not set
+CONFIG_EMMC_IPANIC=y
+CONFIG_EMMC_IPANIC_PLABEL="panic"
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_EEPROM_93XX46 is not set
+# CONFIG_CB710_CORE is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+# CONFIG_TI_ST is not set
+# CONFIG_SENSORS_LIS3_SPI is not set
+# CONFIG_SENSORS_LIS3_I2C is not set
+
+#
+# Altera FPGA firmware download module
+#
+# CONFIG_ALTERA_STAPL is not set
+# CONFIG_VMWARE_VMCI is not set
+CONFIG_BCM_BT_LPM=m
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_TARGET_CORE is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_FIREWIRE_NOSY is not set
+# CONFIG_I2O is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+CONFIG_NET_CORE=y
+# CONFIG_BONDING is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_NET_FC is not set
+CONFIG_MII=y
+# CONFIG_NET_TEAM is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_VXLAN is not set
+CONFIG_NETCONSOLE=y
+# CONFIG_NETCONSOLE_DYNAMIC is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+CONFIG_TUN=y
+# CONFIG_VETH is not set
+# CONFIG_VIRTIO_NET is not set
+# CONFIG_ARCNET is not set
+
+#
+# CAIF transport drivers
+#
+# CONFIG_VHOST_NET is not set
+
+#
+# Distributed Switch Architecture drivers
+#
+# CONFIG_NET_DSA_MV88E6XXX is not set
+# CONFIG_NET_DSA_MV88E6060 is not set
+# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set
+# CONFIG_NET_DSA_MV88E6131 is not set
+# CONFIG_NET_DSA_MV88E6123_61_65 is not set
+# CONFIG_ETHERNET is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_AT803X_PHY is not set
+# CONFIG_AMD_PHY is not set
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_BCM87XX_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_MICREL_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+# CONFIG_MICREL_KS8995MA is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_RTL8152 is not set
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+# CONFIG_USB_NET_AX88179_178A is not set
+# CONFIG_USB_NET_CDCETHER is not set
+# CONFIG_USB_NET_CDC_EEM is not set
+CONFIG_USB_NET_CDC_NCM=y
+# CONFIG_USB_NET_CDC_MBIM is not set
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_SMSC75XX is not set
+# CONFIG_USB_NET_SMSC95XX is not set
+# CONFIG_USB_NET_GL620A is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+CONFIG_USB_NET_CDC_SUBSET=y
+# CONFIG_USB_ALI_M5632 is not set
+# CONFIG_USB_AN2720 is not set
+# CONFIG_USB_BELKIN is not set
+# CONFIG_USB_ARMLINUX is not set
+# CONFIG_USB_EPSON2888 is not set
+# CONFIG_USB_KC2190 is not set
+# CONFIG_USB_NET_ZAURUS is not set
+# CONFIG_USB_NET_CX82310_ETH is not set
+# CONFIG_USB_NET_KALMIA is not set
+# CONFIG_USB_NET_QMI_WWAN is not set
+# CONFIG_USB_HSO is not set
+# CONFIG_USB_NET_INT51X1 is not set
+# CONFIG_USB_IPHETH is not set
+# CONFIG_USB_SIERRA_NET is not set
+CONFIG_WLAN=y
+# CONFIG_LIBERTAS_THINFIRM is not set
+# CONFIG_AIRO is not set
+# CONFIG_ATMEL is not set
+# CONFIG_AT76C50X_USB is not set
+# CONFIG_PRISM54 is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_RTL8180 is not set
+# CONFIG_RTL8187 is not set
+# CONFIG_ADM8211 is not set
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_MWL8K is not set
+CONFIG_WIFI_CONTROL_FUNC=y
+CONFIG_WIFI_PLATFORM_DATA=y
+# CONFIG_ATH_CARDS is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_BRCMFMAC is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+# CONFIG_IWLWIFI is not set
+# CONFIG_IWL4965 is not set
+# CONFIG_IWL3945 is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_HERMES is not set
+# CONFIG_P54_COMMON is not set
+# CONFIG_RT2X00 is not set
+# CONFIG_RTLWIFI is not set
+# CONFIG_WL_TI is not set
+# CONFIG_ZD1211RW is not set
+# CONFIG_MWIFIEX is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+# CONFIG_VMXNET3 is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+CONFIG_INPUT_POLLDEV=y
+CONFIG_INPUT_SPARSEKMAP=y
+# CONFIG_INPUT_MATRIXKMAP is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ADP5589 is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_QT1070 is not set
+# CONFIG_KEYBOARD_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_GPIO_POLLED=y
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_TCA8418 is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_LM8333 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_MCS is not set
+# CONFIG_KEYBOARD_MPR121 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_INPUT_MOUSE=y
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_CYAPA is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_GPIO is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C is not set
+# CONFIG_MOUSE_SYNAPTICS_USB is not set
+CONFIG_INPUT_JOYSTICK=y
+# CONFIG_JOYSTICK_ANALOG is not set
+# CONFIG_JOYSTICK_A3D is not set
+# CONFIG_JOYSTICK_ADI is not set
+# CONFIG_JOYSTICK_COBRA is not set
+# CONFIG_JOYSTICK_GF2K is not set
+# CONFIG_JOYSTICK_GRIP is not set
+# CONFIG_JOYSTICK_GRIP_MP is not set
+# CONFIG_JOYSTICK_GUILLEMOT is not set
+# CONFIG_JOYSTICK_INTERACT is not set
+# CONFIG_JOYSTICK_SIDEWINDER is not set
+# CONFIG_JOYSTICK_TMDC is not set
+# CONFIG_JOYSTICK_IFORCE is not set
+# CONFIG_JOYSTICK_WARRIOR is not set
+# CONFIG_JOYSTICK_MAGELLAN is not set
+# CONFIG_JOYSTICK_SPACEORB is not set
+# CONFIG_JOYSTICK_SPACEBALL is not set
+# CONFIG_JOYSTICK_STINGER is not set
+# CONFIG_JOYSTICK_TWIDJOY is not set
+# CONFIG_JOYSTICK_ZHENHUA is not set
+# CONFIG_JOYSTICK_AS5011 is not set
+# CONFIG_JOYSTICK_JOYDUMP is not set
+# CONFIG_JOYSTICK_XPAD is not set
+CONFIG_INPUT_TABLET=y
+# CONFIG_TABLET_USB_ACECAD is not set
+# CONFIG_TABLET_USB_AIPTEK is not set
+# CONFIG_TABLET_USB_GTCO is not set
+# CONFIG_TABLET_USB_HANWANG is not set
+# CONFIG_TABLET_USB_KBTAB is not set
+# CONFIG_TABLET_USB_WACOM is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set
+# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set
+# CONFIG_TOUCHSCREEN_BU21013 is not set
+# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set
+# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set
+# CONFIG_TOUCHSCREEN_DYNAPRO is not set
+# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_ILI210X is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_WACOM_I2C is not set
+# CONFIG_TOUCHSCREEN_MAX11801 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
+# CONFIG_TOUCHSCREEN_MMS114 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_INTEL_MID is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_PIXCIR is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC_SERIO is not set
+# CONFIG_TOUCHSCREEN_TSC2005 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_ST1232 is not set
+# CONFIG_TOUCHSCREEN_TPS6507X is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_AD714X is not set
+# CONFIG_INPUT_BMA150 is not set
+# CONFIG_INPUT_PCSPKR is not set
+# CONFIG_INPUT_MMA8450 is not set
+# CONFIG_INPUT_MPU3050 is not set
+# CONFIG_INPUT_APANEL is not set
+# CONFIG_INPUT_GP2A is not set
+# CONFIG_INPUT_GPIO_TILT_POLLED is not set
+# CONFIG_INPUT_WISTRON_BTNS is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_KXTJ9 is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
+CONFIG_INPUT_UINPUT=y
+# CONFIG_INPUT_PCF8574 is not set
+# CONFIG_INPUT_PWM_BEEPER is not set
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+# CONFIG_INPUT_ADXL34X is not set
+# CONFIG_INPUT_IMS_PCU is not set
+# CONFIG_INPUT_CMA3000 is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_SERIO_PS2MULT is not set
+# CONFIG_SERIO_ARC_PS2 is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_TTY=y
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_VT_CONSOLE_SLEEP=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_ROCKETPORT is not set
+# CONFIG_CYCLADES is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_SYNCLINK is not set
+# CONFIG_SYNCLINKMP is not set
+# CONFIG_SYNCLINK_GT is not set
+# CONFIG_NOZOMI is not set
+# CONFIG_ISI is not set
+# CONFIG_N_HDLC is not set
+CONFIG_N_GSM=y
+# CONFIG_TRACE_SINK is not set
+CONFIG_DEVKMEM=y
+# CONFIG_STALDRV is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+CONFIG_FIX_EARLYCON_MEM=y
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+# CONFIG_SERIAL_MAX310X is not set
+CONFIG_SERIAL_MRST_MAX3110=y
+CONFIG_SERIAL_MFD_HSU=y
+CONFIG_SERIAL_MFD_HSU_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_SCCNXP is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_IFX6X60 is not set
+# CONFIG_SERIAL_PCH_UART is not set
+# CONFIG_SERIAL_ARC is not set
+# CONFIG_SERIAL_RP2 is not set
+# CONFIG_TTY_PRINTK is not set
+# CONFIG_VIRTIO_CONSOLE is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+CONFIG_HW_RANDOM_INTEL=y
+CONFIG_HW_RANDOM_AMD=y
+CONFIG_HW_RANDOM_GEODE=y
+CONFIG_HW_RANDOM_VIA=y
+# CONFIG_HW_RANDOM_VIRTIO is not set
+CONFIG_NVRAM=y
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_SONYPI is not set
+# CONFIG_MWAVE is not set
+# CONFIG_PC8736x_GPIO is not set
+# CONFIG_NSC_GPIO is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_HANGCHECK_TIMER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+CONFIG_DEVPORT=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_MUX is not set
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_ALGOBIT=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_ISCH is not set
+# CONFIG_I2C_ISMT is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_CBUS_GPIO is not set
+CONFIG_I2C_DESIGNWARE_CORE_FORK=y
+CONFIG_I2C_DESIGNWARE_PCI_FORK=y
+# CONFIG_I2C_DESIGNWARE_PLATFORM_FORK is not set
+# CONFIG_I2C_DW_SPEED_MODE_DEBUG is not set
+CONFIG_I2C_PMIC=y
+# CONFIG_I2C_DESIGNWARE_PCI is not set
+# CONFIG_I2C_EG20T is not set
+CONFIG_I2C_GPIO=y
+# CONFIG_I2C_INTEL_MID is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_PXA_PCI is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_DIOLAN_U2C is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_ALTERA is not set
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_GPIO=y
+CONFIG_SPI_INTEL_MID_SSP=y
+# CONFIG_SPI_OC_TINY is not set
+# CONFIG_SPI_PXA2XX is not set
+# CONFIG_SPI_PXA2XX_PCI is not set
+# CONFIG_SPI_SC18IS602 is not set
+# CONFIG_SPI_TOPCLIFF_PCH is not set
+# CONFIG_SPI_XCOMM is not set
+# CONFIG_SPI_XILINX is not set
+CONFIG_SPI_DESIGNWARE=y
+CONFIG_SPI_DW_PCI=y
+CONFIG_SPI_DW_MID_DMA=y
+
+#
+# SPI Protocol Masters
+#
+CONFIG_SPI_SPIDEV=y
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# Qualcomm MSM SSBI bus support
+#
+# CONFIG_SSBI is not set
+# CONFIG_HSI is not set
+
+#
+# PPS support
+#
+CONFIG_PPS=y
+# CONFIG_PPS_DEBUG is not set
+
+#
+# PPS clients support
+#
+# CONFIG_PPS_CLIENT_KTIMER is not set
+# CONFIG_PPS_CLIENT_LDISC is not set
+# CONFIG_PPS_CLIENT_GPIO is not set
+
+#
+# PPS generators support
+#
+
+#
+# PTP clock support
+#
+CONFIG_PTP_1588_CLOCK=y
+
+#
+# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
+#
+# CONFIG_PTP_1588_CLOCK_PCH is not set
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_GPIO_DEVRES=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIODEBUG=y
+
+#
+# Memory mapped GPIO drivers:
+#
+# CONFIG_GPIO_GENERIC_PLATFORM is not set
+# CONFIG_GPIO_IT8761E is not set
+# CONFIG_GPIO_TS5500 is not set
+# CONFIG_GPIO_SCH is not set
+# CONFIG_GPIO_ICH is not set
+# CONFIG_GPIO_VX855 is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX7300 is not set
+# CONFIG_GPIO_MAX732X is not set
+CONFIG_GPIO_PCA953X=y
+CONFIG_GPIO_PCA953X_IRQ=y
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_SX150X is not set
+# CONFIG_GPIO_WM8994 is not set
+# CONFIG_GPIO_ADP5588 is not set
+
+#
+# PCI GPIO expanders:
+#
+# CONFIG_GPIO_BT8XX is not set
+# CONFIG_GPIO_AMD8111 is not set
+CONFIG_GPIO_LANGWELL=y
+# CONFIG_GPIO_PCH is not set
+# CONFIG_GPIO_ML_IOH is not set
+# CONFIG_GPIO_RDC321X is not set
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+# CONFIG_GPIO_74X164 is not set
+
+#
+# AC97 GPIO expanders:
+#
+
+#
+# MODULbus GPIO expanders:
+#
+# CONFIG_GPIO_MSIC is not set
+
+#
+# USB GPIO expanders:
+#
+# CONFIG_W1 is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+CONFIG_PMIC_CCSM=y
+CONFIG_BQ24261_CHARGER=y
+# CONFIG_PDA_POWER is not set
+# CONFIG_GENERIC_ADC_BATTERY is not set
+# CONFIG_TEST_POWER is not set
+# CONFIG_BATTERY_DS2780 is not set
+# CONFIG_BATTERY_DS2781 is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_SBS is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BATTERY_MAX17040 is not set
+CONFIG_BATTERY_MAX17042=y
+# CONFIG_BATTERY_INTEL_MID is not set
+# CONFIG_CHARGER_ISP1704 is not set
+# CONFIG_CHARGER_MAX8903 is not set
+# CONFIG_CHARGER_LP8727 is not set
+# CONFIG_CHARGER_GPIO is not set
+# CONFIG_CHARGER_MANAGER is not set
+# CONFIG_CHARGER_BQ2415X is not set
+# CONFIG_CHARGER_SMB347 is not set
+# CONFIG_BATTERY_GOLDFISH is not set
+# CONFIG_POWER_RESET is not set
+# CONFIG_POWER_AVS is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
+# CONFIG_SENSORS_AD7314 is not set
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADCXX is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7310 is not set
+# CONFIG_SENSORS_ADT7410 is not set
+# CONFIG_SENSORS_ADT7411 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ASC7621 is not set
+# CONFIG_SENSORS_K8TEMP is not set
+# CONFIG_SENSORS_K10TEMP is not set
+# CONFIG_SENSORS_FAM15H_POWER is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS620 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_FSCHMD is not set
+# CONFIG_SENSORS_G760A is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_GPIO_FAN is not set
+# CONFIG_SENSORS_HIH6130 is not set
+CONFIG_SENSORS_CORETEMP=y
+CONFIG_SENSORS_CORETEMP_INTERRUPT=y
+# CONFIG_SENSORS_IIO_HWMON is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_JC42 is not set
+# CONFIG_SENSORS_LINEAGE is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM73 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4151 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LTC4261 is not set
+# CONFIG_SENSORS_LM95234 is not set
+# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_LM95245 is not set
+CONFIG_MSIC_GPADC=y
+# CONFIG_SENSORS_MAX1111 is not set
+# CONFIG_SENSORS_MAX16065 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX1668 is not set
+# CONFIG_SENSORS_MAX197 is not set
+# CONFIG_SENSORS_MAX6639 is not set
+# CONFIG_SENSORS_MAX6642 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_MAX6697 is not set
+# CONFIG_SENSORS_MCP3021 is not set
+# CONFIG_SENSORS_NCT6775 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_PMBUS is not set
+# CONFIG_SENSORS_SHT15 is not set
+# CONFIG_SENSORS_SHT21 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMM665 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_EMC1403 is not set
+# CONFIG_SENSORS_EMC2103 is not set
+# CONFIG_SENSORS_EMC6W201 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SCH56XX_COMMON is not set
+# CONFIG_SENSORS_SCH5627 is not set
+# CONFIG_SENSORS_SCH5636 is not set
+# CONFIG_SENSORS_ADS1015 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_ADS7871 is not set
+# CONFIG_SENSORS_AMC6821 is not set
+# CONFIG_SENSORS_INA209 is not set
+# CONFIG_SENSORS_INA2XX is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP102 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
+# CONFIG_SENSORS_VIA_CPUTEMP is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83795 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_APPLESMC is not set
+CONFIG_THERMAL=y
+CONFIG_THERMAL_HWMON=y
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
+# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
+# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
+# CONFIG_THERMAL_GOV_FAIR_SHARE is not set
+CONFIG_THERMAL_GOV_STEP_WISE=y
+# CONFIG_THERMAL_GOV_USER_SPACE is not set
+# CONFIG_CPU_THERMAL is not set
+# CONFIG_THERMAL_EMULATION is not set
+# CONFIG_INTEL_POWERCLAMP is not set
+CONFIG_SENSORS_THERMAL_MRFLD=y
+CONFIG_SOC_THERMAL=y
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_CORE is not set
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM1535_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_F71808E_WDT is not set
+# CONFIG_SP5100_TCO is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_SBC_FITPC2_WATCHDOG is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+# CONFIG_IBMASR is not set
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I6300ESB_WDT is not set
+# CONFIG_IE6XX_WDT is not set
+# CONFIG_INTEL_SCU_WATCHDOG is not set
+CONFIG_INTEL_SCU_WATCHDOG_EVO=y
+CONFIG_DISABLE_SCU_WATCHDOG=y
+# CONFIG_ITCO_WDT is not set
+# CONFIG_IT8712F_WDT is not set
+# CONFIG_IT87_WDT is not set
+# CONFIG_HP_WATCHDOG is not set
+# CONFIG_SC1200_WDT is not set
+# CONFIG_PC87413_WDT is not set
+# CONFIG_NV_TCO is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_SBC8360_WDT is not set
+# CONFIG_SBC7240_WDT is not set
+# CONFIG_CPU5_WDT is not set
+# CONFIG_SMSC_SCH311X_WDT is not set
+# CONFIG_SMSC37B787_WDT is not set
+# CONFIG_VIA_WDT is not set
+# CONFIG_W83627HF_WDT is not set
+# CONFIG_W83697HF_WDT is not set
+# CONFIG_W83697UG_WDT is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_W83977F_WDT is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_SBC_EPX_C3_WATCHDOG is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_BCMA_POSSIBLE=y
+
+#
+# Broadcom specific AMBA
+#
+# CONFIG_BCMA is not set
+
+#
+# Multifunction device drivers
+#
+CONFIG_MFD_CORE=y
+# CONFIG_MFD_CS5535 is not set
+# CONFIG_MFD_AS3711 is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_AAT2870_CORE is not set
+# CONFIG_MFD_CROS_EC is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_DA9052_SPI is not set
+# CONFIG_MFD_DA9052_I2C is not set
+# CONFIG_MFD_DA9055 is not set
+# CONFIG_MFD_MC13XXX_SPI is not set
+# CONFIG_MFD_MC13XXX_I2C is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_HTC_I2CPLD is not set
+# CONFIG_LPC_ICH is not set
+# CONFIG_LPC_SCH is not set
+CONFIG_MFD_INTEL_MSIC=y
+# CONFIG_MFD_JANZ_CMODIO is not set
+# CONFIG_MFD_88PM800 is not set
+# CONFIG_MFD_88PM805 is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_MAX77686 is not set
+# CONFIG_MFD_MAX77693 is not set
+# CONFIG_MFD_MAX8907 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8997 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_MFD_VIPERBOARD is not set
+# CONFIG_MFD_RETU is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_RTSX_PCI is not set
+# CONFIG_MFD_RC5T583 is not set
+# CONFIG_MFD_SEC_CORE is not set
+# CONFIG_MFD_SI476X_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_SMSC is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_SYSCON is not set
+# CONFIG_MFD_TI_AM335X_TSCADC is not set
+# CONFIG_MFD_LP8788 is not set
+# CONFIG_MFD_PALMAS is not set
+# CONFIG_TPS6105X is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_MFD_TPS65090 is not set
+# CONFIG_MFD_TPS65217 is not set
+# CONFIG_MFD_TPS6586X is not set
+# CONFIG_MFD_TPS65910 is not set
+# CONFIG_MFD_TPS65912 is not set
+# CONFIG_MFD_TPS65912_I2C is not set
+# CONFIG_MFD_TPS65912_SPI is not set
+# CONFIG_MFD_TPS80031 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_TWL6040_CORE is not set
+# CONFIG_MFD_WL1273_CORE is not set
+# CONFIG_MFD_LM3533 is not set
+# CONFIG_MFD_TIMBERDALE is not set
+# CONFIG_MFD_TC3589X is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_VX855 is not set
+# CONFIG_MFD_ARIZONA_I2C is not set
+# CONFIG_MFD_ARIZONA_SPI is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM831X_SPI is not set
+# CONFIG_MFD_WM8350_I2C is not set
+CONFIG_MFD_WM8994=y
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_DUMMY is not set
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_GPIO is not set
+# CONFIG_REGULATOR_AD5398 is not set
+# CONFIG_REGULATOR_FAN53555 is not set
+# CONFIG_REGULATOR_ISL6271A is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_MAX8649 is not set
+# CONFIG_REGULATOR_MAX8660 is not set
+# CONFIG_REGULATOR_MAX8952 is not set
+# CONFIG_REGULATOR_MAX8973 is not set
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_LP3972 is not set
+# CONFIG_REGULATOR_LP872X is not set
+# CONFIG_REGULATOR_LP8755 is not set
+# CONFIG_REGULATOR_TPS51632 is not set
+# CONFIG_REGULATOR_TPS62360 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+# CONFIG_REGULATOR_TPS6524X is not set
+CONFIG_REGULATOR_WM8994=y
+CONFIG_REGULATOR_PMIC_BASIN_COVE=y
+CONFIG_MEDIA_SUPPORT=y
+
+#
+# Multimedia core support
+#
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
+# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
+# CONFIG_MEDIA_RADIO_SUPPORT is not set
+# CONFIG_MEDIA_RC_SUPPORT is not set
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_VIDEO_V4L2=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+# CONFIG_VIDEO_V4L2_INT_DEVICE is not set
+# CONFIG_TTPCI_EEPROM is not set
+
+#
+# Media drivers
+#
+# CONFIG_MEDIA_USB_SUPPORT is not set
+# CONFIG_MEDIA_PCI_SUPPORT is not set
+# CONFIG_V4L_PLATFORM_DRIVERS is not set
+# CONFIG_V4L_MEM2MEM_DRIVERS is not set
+# CONFIG_V4L_TEST_DRIVERS is not set
+
+#
+# Supported MMC/SDIO adapters
+#
+# CONFIG_CYPRESS_FIRMWARE is not set
+
+#
+# Media ancillary drivers (tuners, sensors, i2c, frontends)
+#
+# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
+
+#
+# Encoders, decoders, sensors and other helper chips
+#
+
+#
+# Audio decoders, processors and mixers
+#
+# CONFIG_VIDEO_TVAUDIO is not set
+# CONFIG_VIDEO_TDA7432 is not set
+# CONFIG_VIDEO_TDA9840 is not set
+# CONFIG_VIDEO_TEA6415C is not set
+# CONFIG_VIDEO_TEA6420 is not set
+# CONFIG_VIDEO_MSP3400 is not set
+# CONFIG_VIDEO_CS5345 is not set
+# CONFIG_VIDEO_CS53L32A is not set
+# CONFIG_VIDEO_TLV320AIC23B is not set
+# CONFIG_VIDEO_UDA1342 is not set
+# CONFIG_VIDEO_WM8775 is not set
+# CONFIG_VIDEO_WM8739 is not set
+# CONFIG_VIDEO_VP27SMPX is not set
+# CONFIG_VIDEO_SONY_BTF_MPX is not set
+
+#
+# RDS decoders
+#
+# CONFIG_VIDEO_SAA6588 is not set
+
+#
+# Video decoders
+#
+# CONFIG_VIDEO_ADV7180 is not set
+# CONFIG_VIDEO_ADV7183 is not set
+# CONFIG_VIDEO_ADV7604 is not set
+# CONFIG_VIDEO_BT819 is not set
+# CONFIG_VIDEO_BT856 is not set
+# CONFIG_VIDEO_BT866 is not set
+# CONFIG_VIDEO_KS0127 is not set
+# CONFIG_VIDEO_SAA7110 is not set
+# CONFIG_VIDEO_SAA711X is not set
+# CONFIG_VIDEO_SAA7191 is not set
+# CONFIG_VIDEO_TVP514X is not set
+# CONFIG_VIDEO_TVP5150 is not set
+# CONFIG_VIDEO_TVP7002 is not set
+# CONFIG_VIDEO_TW2804 is not set
+# CONFIG_VIDEO_TW9903 is not set
+# CONFIG_VIDEO_TW9906 is not set
+# CONFIG_VIDEO_VPX3220 is not set
+
+#
+# Video and audio decoders
+#
+# CONFIG_VIDEO_SAA717X is not set
+# CONFIG_VIDEO_CX25840 is not set
+
+#
+# Video encoders
+#
+# CONFIG_VIDEO_SAA7127 is not set
+# CONFIG_VIDEO_SAA7185 is not set
+# CONFIG_VIDEO_ADV7170 is not set
+# CONFIG_VIDEO_ADV7175 is not set
+# CONFIG_VIDEO_ADV7343 is not set
+# CONFIG_VIDEO_ADV7393 is not set
+# CONFIG_VIDEO_AD9389B is not set
+# CONFIG_VIDEO_AK881X is not set
+
+#
+# Camera sensor devices
+#
+# CONFIG_VIDEO_OV7640 is not set
+# CONFIG_VIDEO_OV7670 is not set
+# CONFIG_VIDEO_OV9650 is not set
+# CONFIG_VIDEO_VS6624 is not set
+# CONFIG_VIDEO_MT9M032 is not set
+# CONFIG_VIDEO_MT9P031 is not set
+# CONFIG_VIDEO_MT9T001 is not set
+# CONFIG_VIDEO_MT9V011 is not set
+# CONFIG_VIDEO_MT9V032 is not set
+# CONFIG_VIDEO_SR030PC30 is not set
+# CONFIG_VIDEO_NOON010PC30 is not set
+# CONFIG_VIDEO_M5MOLS is not set
+# CONFIG_VIDEO_S5K6AA is not set
+# CONFIG_VIDEO_S5K4ECGX is not set
+# CONFIG_VIDEO_S5C73M3 is not set
+
+#
+# Flash devices
+#
+# CONFIG_VIDEO_ADP1653 is not set
+# CONFIG_VIDEO_AS3645A is not set
+
+#
+# Video improvement chips
+#
+# CONFIG_VIDEO_UPD64031A is not set
+# CONFIG_VIDEO_UPD64083 is not set
+
+#
+# Miscelaneous helper chips
+#
+# CONFIG_VIDEO_THS7303 is not set
+# CONFIG_VIDEO_M52790 is not set
+
+#
+# Sensors used on soc_camera driver
+#
+
+#
+# Customise DVB Frontends
+#
+# CONFIG_DVB_AU8522_V4L is not set
+CONFIG_DVB_TUNER_DIB0070=m
+CONFIG_DVB_TUNER_DIB0090=m
+
+#
+# Tools to develop new frontends
+#
+# CONFIG_DVB_DUMMY_FE is not set
+
+#
+# Graphics support
+#
+CONFIG_AGP=y
+# CONFIG_AGP_ALI is not set
+# CONFIG_AGP_ATI is not set
+# CONFIG_AGP_AMD is not set
+CONFIG_AGP_AMD64=y
+CONFIG_AGP_INTEL=y
+# CONFIG_AGP_NVIDIA is not set
+# CONFIG_AGP_SIS is not set
+# CONFIG_AGP_SWORKS is not set
+# CONFIG_AGP_VIA is not set
+# CONFIG_AGP_EFFICEON is not set
+CONFIG_VGA_ARB=y
+CONFIG_VGA_ARB_MAX_GPUS=16
+CONFIG_DRM=y
+# CONFIG_DRM_TDFX is not set
+# CONFIG_DRM_R128 is not set
+# CONFIG_DRM_RADEON is not set
+# CONFIG_DRM_NOUVEAU is not set
+# CONFIG_DRM_I915 is not set
+# CONFIG_DRM_MGA is not set
+# CONFIG_DRM_SIS is not set
+# CONFIG_DRM_VIA is not set
+# CONFIG_DRM_SAVAGE is not set
+# CONFIG_DRM_VMWGFX is not set
+# CONFIG_DRM_GMA500 is not set
+# CONFIG_DRM_UDL is not set
+# CONFIG_DRM_AST is not set
+# CONFIG_DRM_MGAG200 is not set
+# CONFIG_DRM_CIRRUS_QEMU is not set
+# CONFIG_DRM_QXL is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_HDMI=y
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ARC is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_UVESA is not set
+# CONFIG_FB_VESA is not set
+# CONFIG_FB_N411 is not set
+# CONFIG_FB_HGA is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_I740 is not set
+# CONFIG_FB_I810 is not set
+# CONFIG_FB_LE80578 is not set
+# CONFIG_FB_INTEL is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_VIA is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_CARMINE is not set
+# CONFIG_FB_GEODE is not set
+# CONFIG_FB_TMIO is not set
+# CONFIG_FB_SMSCUFX is not set
+# CONFIG_FB_UDL is not set
+# CONFIG_FB_GOLDFISH is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_FB_AUO_K190X is not set
+# CONFIG_EXYNOS_VIDEO is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+# CONFIG_BACKLIGHT_PWM is not set
+# CONFIG_BACKLIGHT_SAHARA is not set
+# CONFIG_BACKLIGHT_ADP8860 is not set
+# CONFIG_BACKLIGHT_ADP8870 is not set
+# CONFIG_BACKLIGHT_LM3630 is not set
+# CONFIG_BACKLIGHT_LM3639 is not set
+# CONFIG_BACKLIGHT_LP855X is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_LOGO is not set
+CONFIG_SOUND=y
+# CONFIG_SOUND_OSS_CORE is not set
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_COMPRESS_OFFLOAD=y
+CONFIG_SND_JACK=y
+CONFIG_SND_SEQUENCER=y
+# CONFIG_SND_SEQ_DUMMY is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_SEQUENCER_OSS is not set
+# CONFIG_SND_HRTIMER is not set
+CONFIG_SND_DYNAMIC_MINORS=y
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_DMA_SGBUF=y
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_PCSP is not set
+# CONFIG_SND_DUMMY is not set
+CONFIG_SND_ALOOP=y
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+# CONFIG_SND_PCI is not set
+# CONFIG_SND_SPI is not set
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_UA101 is not set
+# CONFIG_SND_USB_USX2Y is not set
+# CONFIG_SND_USB_CAIAQ is not set
+# CONFIG_SND_USB_US122L is not set
+# CONFIG_SND_USB_6FIRE is not set
+CONFIG_SND_SOC=y
+# CONFIG_SND_ATMEL_SOC is not set
+# CONFIG_SND_MFLD_MACHINE is not set
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+# CONFIG_SND_SIMPLE_CARD is not set
+# CONFIG_SOUND_PRIME is not set
+
+#
+# HID support
+#
+CONFIG_HID=y
+# CONFIG_HID_BATTERY_STRENGTH is not set
+CONFIG_HIDRAW=y
+CONFIG_UHID=y
+CONFIG_HID_GENERIC=y
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_ACRUX is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_APPLEIR is not set
+# CONFIG_HID_AUREAL is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_PRODIKEYS is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EMS_FF is not set
+# CONFIG_HID_ELECOM is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_HOLTEK is not set
+# CONFIG_HID_KEYTOUCH is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_UCLOGIC is not set
+# CONFIG_HID_WALTOP is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_ICADE is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LCPOWER is not set
+# CONFIG_HID_LENOVO_TPKBD is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MAGICMOUSE is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_MULTITOUCH is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_PRIMAX is not set
+# CONFIG_HID_PS3REMOTE is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_SAITEK is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SPEEDLINK is not set
+# CONFIG_HID_STEELSERIES is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TIVO is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THINGM is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_WACOM is not set
+# CONFIG_HID_WIIMOTE is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+# CONFIG_HID_SENSOR_HUB is not set
+
+#
+# USB HID support
+#
+CONFIG_USB_HID=y
+CONFIG_HID_PID=y
+CONFIG_USB_HIDDEV=y
+
+#
+# I2C HID support
+#
+# CONFIG_I2C_HID is not set
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB_ARCH_HAS_XHCI=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_COMMON=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEFAULT_PERSIST=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_PLATFORM=y
+# CONFIG_USB_XHCI_HCD_DEBUGGING is not set
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_EHCI_PCI=y
+# CONFIG_USB_EHCI_HCD_PLATFORM is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_RENESAS_USBHS is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=y
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_REALTEK is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_STORAGE_ENE_UB6250 is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+CONFIG_USB_DWC3=y
+# CONFIG_USB_DWC3_HOST is not set
+CONFIG_USB_DWC3_GADGET=y
+# CONFIG_USB_DWC3_DUAL_ROLE is not set
+
+#
+# Platform Glue Driver Support
+#
+# CONFIG_USB_DWC3_PCI is not set
+CONFIG_USB_DWC3_OTG=y
+CONFIG_USB_DWC3_INTEL_MRFL=y
+# CONFIG_USB_DWC3_INTEL_BYT is not set
+CONFIG_USB_DWC3_DEVICE_INTEL=y
+CONFIG_USB_DWC3_HOST_INTEL=y
+
+#
+# Debugging features
+#
+# CONFIG_USB_DWC3_DEBUG is not set
+# CONFIG_USB_CHIPIDEA is not set
+
+#
+# USB port drivers
+#
+CONFIG_USB_SERIAL=y
+# CONFIG_USB_SERIAL_CONSOLE is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP210X is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_F81232 is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_IUU is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_METRO is not set
+# CONFIG_USB_SERIAL_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_MOTOROLA is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+CONFIG_USB_SERIAL_PL2303=y
+# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_QCAUX is not set
+# CONFIG_USB_SERIAL_QUALCOMM is not set
+# CONFIG_USB_SERIAL_SPCP8X5 is not set
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SIEMENS_MPI is not set
+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_SYMBOL is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_OPTICON is not set
+# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set
+# CONFIG_USB_SERIAL_XSENS_MT is not set
+# CONFIG_USB_SERIAL_ZIO is not set
+# CONFIG_USB_SERIAL_WISHBONE is not set
+# CONFIG_USB_SERIAL_ZTE is not set
+# CONFIG_USB_SERIAL_SSU100 is not set
+# CONFIG_USB_SERIAL_QT2 is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_YUREX is not set
+# CONFIG_USB_EZUSB_FX2 is not set
+# CONFIG_USB_HSIC_USB3503 is not set
+CONFIG_USB_PHY=y
+CONFIG_NOP_USB_XCEIV=y
+# CONFIG_OMAP_CONTROL_USB is not set
+# CONFIG_OMAP_USB3 is not set
+# CONFIG_SAMSUNG_USBPHY is not set
+# CONFIG_SAMSUNG_USB2PHY is not set
+# CONFIG_SAMSUNG_USB3PHY is not set
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_USB_ISP1301 is not set
+# CONFIG_USB_RCAR_PHY is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_DEBUG_FS is not set
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
+
+#
+# USB Peripheral Controller
+#
+# CONFIG_USB_R8A66597 is not set
+# CONFIG_USB_PXA27X is not set
+# CONFIG_USB_MV_UDC is not set
+# CONFIG_USB_MV_U3D is not set
+# CONFIG_USB_M66592 is not set
+# CONFIG_USB_AMD5536UDC is not set
+# CONFIG_USB_NET2272 is not set
+# CONFIG_USB_NET2280 is not set
+# CONFIG_USB_GOKU is not set
+# CONFIG_USB_EG20T is not set
+# CONFIG_USB_DUMMY_HCD is not set
+CONFIG_USB_LIBCOMPOSITE=m
+CONFIG_USB_F_ACM=m
+CONFIG_USB_U_SERIAL=m
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_G_NCM is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FUNCTIONFS is not set
+# CONFIG_USB_MASS_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+# CONFIG_USB_G_ACM_MS is not set
+CONFIG_USB_G_MULTI=m
+CONFIG_USB_G_MULTI_RNDIS=y
+# CONFIG_USB_G_MULTI_CDC is not set
+# CONFIG_USB_G_HID is not set
+# CONFIG_USB_G_DBGP is not set
+# CONFIG_USB_G_WEBCAM is not set
+# CONFIG_UWB is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_UNSAFE_RESUME=y
+# CONFIG_MMC_CLKGATE is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PCI=y
+# CONFIG_MMC_RICOH_MMC is not set
+# CONFIG_MMC_SDHCI_PLTFM is not set
+# CONFIG_MMC_WBSD is not set
+# CONFIG_MMC_TIFM_SD is not set
+# CONFIG_MMC_CB710 is not set
+# CONFIG_MMC_VIA_SDMMC is not set
+# CONFIG_MMC_VUB300 is not set
+# CONFIG_MMC_USHC is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_LM3530 is not set
+# CONFIG_LEDS_LM3642 is not set
+# CONFIG_LEDS_PCA9532 is not set
+# CONFIG_LEDS_GPIO is not set
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_LP5521 is not set
+# CONFIG_LEDS_LP5523 is not set
+# CONFIG_LEDS_LP5562 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_PCA9633 is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_PWM is not set
+# CONFIG_LEDS_REGULATOR is not set
+# CONFIG_LEDS_BD2802 is not set
+# CONFIG_LEDS_INTEL_SS4200 is not set
+# CONFIG_LEDS_LT3593 is not set
+# CONFIG_LEDS_TCA6507 is not set
+# CONFIG_LEDS_LM355x is not set
+# CONFIG_LEDS_OT200 is not set
+# CONFIG_LEDS_BLINKM is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+# CONFIG_LEDS_TRIGGER_ONESHOT is not set
+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_CPU is not set
+# CONFIG_LEDS_TRIGGER_GPIO is not set
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+# CONFIG_LEDS_TRIGGER_TRANSIENT is not set
+# CONFIG_LEDS_TRIGGER_CAMERA is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+CONFIG_EDAC=y
+CONFIG_EDAC_LEGACY_SYSFS=y
+# CONFIG_EDAC_DEBUG is not set
+# CONFIG_EDAC_MM_EDAC is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_SYSTOHC=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_DS3232 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_ISL12022 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8523 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_BQ32K is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+# CONFIG_RTC_DRV_EM3027 is not set
+# CONFIG_RTC_DRV_RV3029C2 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T93 is not set
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+# CONFIG_RTC_DRV_RX4581 is not set
+
+#
+# Platform RTC drivers
+#
+CONFIG_RTC_DRV_CMOS=y
+# CONFIG_RTC_DRV_VRTC is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+# CONFIG_RTC_DRV_DS2404 is not set
+
+#
+# on-CPU RTC drivers
+#
+
+#
+# HID Sensor RTC drivers
+#
+# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set
+CONFIG_DMADEVICES=y
+# CONFIG_DMADEVICES_DEBUG is not set
+
+#
+# DMA Devices
+#
+CONFIG_INTEL_MID_DMAC=y
+# CONFIG_INTEL_IOATDMA is not set
+# CONFIG_DW_DMAC is not set
+# CONFIG_TIMB_DMA is not set
+# CONFIG_PCH_DMA is not set
+CONFIG_DMA_ENGINE=y
+
+#
+# DMA Clients
+#
+# CONFIG_NET_DMA is not set
+# CONFIG_ASYNC_TX_DMA is not set
+# CONFIG_DMATEST is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+# CONFIG_VIRT_DRIVERS is not set
+CONFIG_VIRTIO=y
+
+#
+# Virtio drivers
+#
+# CONFIG_VIRTIO_PCI is not set
+# CONFIG_VIRTIO_BALLOON is not set
+# CONFIG_VIRTIO_MMIO is not set
+
+#
+# Microsoft Hyper-V guest support
+#
+CONFIG_STAGING=y
+# CONFIG_ET131X is not set
+# CONFIG_SLICOSS is not set
+# CONFIG_USBIP_CORE is not set
+# CONFIG_W35UND is not set
+# CONFIG_PRISM2_USB is not set
+# CONFIG_ECHO is not set
+# CONFIG_COMEDI is not set
+# CONFIG_ASUS_OLED is not set
+# CONFIG_R8187SE is not set
+# CONFIG_RTL8192U is not set
+# CONFIG_RTLLIB is not set
+# CONFIG_R8712U is not set
+# CONFIG_RTS5139 is not set
+# CONFIG_TRANZPORT is not set
+# CONFIG_LINE6_USB is not set
+# CONFIG_USB_SERIAL_QUATECH2 is not set
+# CONFIG_VT6655 is not set
+# CONFIG_VT6656 is not set
+# CONFIG_DX_SEP is not set
+
+#
+# IIO staging drivers
+#
+
+#
+# Accelerometers
+#
+# CONFIG_ADIS16201 is not set
+# CONFIG_ADIS16203 is not set
+# CONFIG_ADIS16204 is not set
+# CONFIG_ADIS16209 is not set
+# CONFIG_ADIS16220 is not set
+# CONFIG_ADIS16240 is not set
+# CONFIG_LIS3L02DQ is not set
+# CONFIG_SCA3000 is not set
+
+#
+# Analog to digital converters
+#
+# CONFIG_AD7291 is not set
+# CONFIG_AD7606 is not set
+# CONFIG_AD799X is not set
+# CONFIG_AD7780 is not set
+# CONFIG_AD7816 is not set
+# CONFIG_AD7192 is not set
+# CONFIG_AD7280 is not set
+
+#
+# Analog digital bi-direction converters
+#
+# CONFIG_ADT7316 is not set
+
+#
+# Capacitance to digital converters
+#
+# CONFIG_AD7150 is not set
+# CONFIG_AD7152 is not set
+# CONFIG_AD7746 is not set
+
+#
+# Direct Digital Synthesis
+#
+# CONFIG_AD5930 is not set
+# CONFIG_AD9832 is not set
+# CONFIG_AD9834 is not set
+# CONFIG_AD9850 is not set
+# CONFIG_AD9852 is not set
+# CONFIG_AD9910 is not set
+# CONFIG_AD9951 is not set
+
+#
+# Digital gyroscope sensors
+#
+# CONFIG_ADIS16060 is not set
+# CONFIG_ADIS16130 is not set
+# CONFIG_ADIS16260 is not set
+
+#
+# Network Analyzer, Impedance Converters
+#
+# CONFIG_AD5933 is not set
+
+#
+# Light sensors
+#
+# CONFIG_SENSORS_ISL29018 is not set
+# CONFIG_SENSORS_ISL29028 is not set
+# CONFIG_TSL2583 is not set
+# CONFIG_TSL2x7x is not set
+
+#
+# Magnetometer sensors
+#
+# CONFIG_SENSORS_HMC5843 is not set
+
+#
+# Active energy metering IC
+#
+# CONFIG_ADE7753 is not set
+# CONFIG_ADE7754 is not set
+# CONFIG_ADE7758 is not set
+# CONFIG_ADE7759 is not set
+# CONFIG_ADE7854 is not set
+
+#
+# Resolver to digital converters
+#
+# CONFIG_AD2S90 is not set
+# CONFIG_AD2S1200 is not set
+# CONFIG_AD2S1210 is not set
+
+#
+# Triggers - standalone
+#
+# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set
+# CONFIG_IIO_GPIO_TRIGGER is not set
+CONFIG_IIO_SYSFS_TRIGGER=m
+# CONFIG_IIO_SIMPLE_DUMMY is not set
+# CONFIG_ZSMALLOC is not set
+# CONFIG_FB_SM7XX is not set
+# CONFIG_CRYSTALHD is not set
+# CONFIG_FB_XGI is not set
+# CONFIG_USB_ENESTORAGE is not set
+# CONFIG_BCM_WIMAX is not set
+# CONFIG_FT1000 is not set
+
+#
+# Speakup console speech
+#
+# CONFIG_SPEAKUP is not set
+# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set
+# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set
+# CONFIG_STAGING_MEDIA is not set
+
+#
+# Android
+#
+# CONFIG_ANDROID is not set
+# CONFIG_USB_WPAN_HCD is not set
+# CONFIG_WIMAX_GDM72XX is not set
+# CONFIG_CSR_WIFI is not set
+# CONFIG_NET_VENDOR_SILICOM is not set
+# CONFIG_CED1401 is not set
+# CONFIG_DGRP is not set
+# CONFIG_USB_DWC2 is not set
+CONFIG_X86_PLATFORM_DEVICES=y
+# CONFIG_CHROMEOS_LAPTOP is not set
+# CONFIG_AMILO_RFKILL is not set
+# CONFIG_SENSORS_HDAPS is not set
+CONFIG_INTEL_SCU_IPC=y
+CONFIG_INTEL_SCU_IPC_INTR_MODE=y
+# CONFIG_INTEL_SCU_IPC_POLL_MODE is not set
+CONFIG_INTEL_SCU_IPC_UTIL=y
+CONFIG_GPIO_INTEL_PMIC=y
+CONFIG_INTEL_MID_POWER_BUTTON=y
+# CONFIG_INTEL_MFLD_THERMAL is not set
+# CONFIG_IBM_RTL is not set
+# CONFIG_SAMSUNG_LAPTOP is not set
+CONFIG_INTEL_SCU_FLIS=y
+
+#
+# Hardware Spinlock drivers
+#
+CONFIG_CLKSRC_I8253=y
+CONFIG_CLKEVT_I8253=y
+CONFIG_I8253_LOCK=y
+CONFIG_CLKBLD_I8253=y
+# CONFIG_MAILBOX is not set
+CONFIG_IOMMU_SUPPORT=y
+
+#
+# Remoteproc drivers
+#
+CONFIG_REMOTEPROC=y
+# CONFIG_STE_MODEM_RPROC is not set
+CONFIG_INTEL_MID_REMOTEPROC=y
+
+#
+# Rpmsg drivers
+#
+CONFIG_RPMSG=y
+CONFIG_RPMSG_IPC=y
+CONFIG_PM_DEVFREQ=y
+
+#
+# DEVFREQ Governors
+#
+CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y
+CONFIG_DEVFREQ_GOV_PERFORMANCE=y
+CONFIG_DEVFREQ_GOV_POWERSAVE=y
+CONFIG_DEVFREQ_GOV_USERSPACE=y
+
+#
+# DEVFREQ Drivers
+#
+CONFIG_EXTCON=y
+
+#
+# Extcon Device Drivers
+#
+# CONFIG_EXTCON_GPIO is not set
+# CONFIG_EXTCON_ADC_JACK is not set
+# CONFIG_MEMORY is not set
+CONFIG_IIO=y
+CONFIG_IIO_BUFFER=y
+# CONFIG_IIO_BUFFER_CB is not set
+CONFIG_IIO_KFIFO_BUF=y
+CONFIG_IIO_TRIGGERED_BUFFER=y
+CONFIG_IIO_TRIGGER=y
+CONFIG_IIO_CONSUMERS_PER_TRIGGER=2
+
+#
+# Accelerometers
+#
+# CONFIG_KXSD9 is not set
+# CONFIG_IIO_ST_ACCEL_3AXIS is not set
+
+#
+# Analog to digital converters
+#
+# CONFIG_AD7266 is not set
+# CONFIG_AD7298 is not set
+# CONFIG_AD7923 is not set
+# CONFIG_AD7791 is not set
+# CONFIG_AD7793 is not set
+# CONFIG_AD7476 is not set
+# CONFIG_AD7887 is not set
+# CONFIG_MAX1363 is not set
+# CONFIG_TI_ADC081C is not set
+CONFIG_TI_ADS7955_ADC=y
+CONFIG_IIO_BASINCOVE_GPADC=y
+
+#
+# Amplifiers
+#
+# CONFIG_AD8366 is not set
+
+#
+# Hid Sensor IIO Common
+#
+
+#
+# Digital to analog converters
+#
+# CONFIG_AD5064 is not set
+# CONFIG_AD5360 is not set
+# CONFIG_AD5380 is not set
+# CONFIG_AD5421 is not set
+# CONFIG_AD5624R_SPI is not set
+# CONFIG_AD5446 is not set
+# CONFIG_AD5449 is not set
+# CONFIG_AD5504 is not set
+# CONFIG_AD5755 is not set
+# CONFIG_AD5764 is not set
+# CONFIG_AD5791 is not set
+# CONFIG_AD5686 is not set
+# CONFIG_MAX517 is not set
+# CONFIG_MCP4725 is not set
+
+#
+# Frequency Synthesizers DDS/PLL
+#
+
+#
+# Clock Generator/Distribution
+#
+# CONFIG_AD9523 is not set
+
+#
+# Phase-Locked Loop (PLL) frequency synthesizers
+#
+# CONFIG_ADF4350 is not set
+
+#
+# Digital gyroscope sensors
+#
+# CONFIG_ADIS16080 is not set
+# CONFIG_ADIS16136 is not set
+# CONFIG_ADXRS450 is not set
+# CONFIG_IIO_ST_GYRO_3AXIS is not set
+# CONFIG_ITG3200 is not set
+
+#
+# Inertial measurement units
+#
+# CONFIG_ADIS16400 is not set
+# CONFIG_ADIS16480 is not set
+# CONFIG_INV_MPU6050_IIO is not set
+
+#
+# Light sensors
+#
+# CONFIG_ADJD_S311 is not set
+# CONFIG_SENSORS_TSL2563 is not set
+# CONFIG_VCNL4000 is not set
+
+#
+# Magnetometer sensors
+#
+# CONFIG_AK8975 is not set
+# CONFIG_IIO_ST_MAGN_3AXIS is not set
+# CONFIG_VME_BUS is not set
+CONFIG_PWM=y
+CONFIG_PWM_SYSFS=y
+CONFIG_PWM_INTEL_MID=y
+# CONFIG_IPACK_BUS is not set
+# CONFIG_RESET_CONTROLLER is not set
+
+#
+# Firmware Drivers
+#
+# CONFIG_EDD is not set
+CONFIG_FIRMWARE_MEMMAP=y
+# CONFIG_DELL_RBU is not set
+# CONFIG_DCDBAS is not set
+CONFIG_DMIID=y
+# CONFIG_DMI_SYSFS is not set
+# CONFIG_ISCSI_IBFT_FIND is not set
+# CONFIG_GOOGLE_FIRMWARE is not set
+
+#
+# File systems
+#
+CONFIG_DCACHE_WORD_ACCESS=y
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+# CONFIG_EXT4_FS_POSIX_ACL is not set
+CONFIG_EXT4_FS_SECURITY=y
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_JBD2=y
+# CONFIG_JBD2_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_FANOTIFY=y
+# CONFIG_FANOTIFY_ACCESS_PERMISSIONS is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+CONFIG_AUTOFS4_FS=y
+CONFIG_FUSE_FS=y
+# CONFIG_CUSE is not set
+CONFIG_GENERIC_ACL=y
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+# CONFIG_VFAT_FS_NO_DUALNAMES is not set
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_VFAT_NO_CREATE_WITH_LONGNAMES is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_TMPFS_XATTR=y
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_CONFIGFS_FS=y
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ECRYPT_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_LOGFS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX6FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_PSTORE=y
+CONFIG_PSTORE_CONSOLE=y
+CONFIG_PSTORE_FTRACE=y
+CONFIG_PSTORE_RAM=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_F2FS_FS is not set
+# CONFIG_AUFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V2=y
+CONFIG_NFS_DEF_FILE_IO_SIZE=4096
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_SWAP is not set
+# CONFIG_NFS_V4_1 is not set
+# CONFIG_NFS_USE_LEGACY_DNS is not set
+CONFIG_NFS_USE_KERNEL_DNS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_DEBUG is not set
+# CONFIG_CEPH_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_MAC_ROMAN is not set
+# CONFIG_NLS_MAC_CELTIC is not set
+# CONFIG_NLS_MAC_CENTEURO is not set
+# CONFIG_NLS_MAC_CROATIAN is not set
+# CONFIG_NLS_MAC_CYRILLIC is not set
+# CONFIG_NLS_MAC_GAELIC is not set
+# CONFIG_NLS_MAC_GREEK is not set
+# CONFIG_NLS_MAC_ICELAND is not set
+# CONFIG_NLS_MAC_INUIT is not set
+# CONFIG_NLS_MAC_ROMANIAN is not set
+# CONFIG_NLS_MAC_TURKISH is not set
+CONFIG_NLS_UTF8=y
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=2048
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_READABLE_ASM is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_SECTION_MISMATCH=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_HARDLOCKUP_DETECTOR=y
+CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y
+CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=1
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=1
+# CONFIG_PANIC_ON_OOPS is not set
+CONFIG_PANIC_ON_OOPS_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=400
+# CONFIG_DEBUG_KMEMLEAK_TEST is not set
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+CONFIG_TRACE_IRQFLAGS=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+CONFIG_DEBUG_STACK_USAGE=y
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_INFO_REDUCED is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_VIRTUAL is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_LIST=y
+CONFIG_TEST_LIST_SORT=y
+CONFIG_DEBUG_SG=y
+CONFIG_DEBUG_NOTIFIERS=y
+# CONFIG_DEBUG_CREDENTIALS is not set
+CONFIG_ARCH_WANT_FRAME_POINTERS=y
+CONFIG_FRAME_POINTER=y
+CONFIG_BOOT_PRINTK_DELAY=y
+
+#
+# RCU Debugging
+#
+# CONFIG_PROVE_RCU_DELAY is not set
+CONFIG_SPARSE_RCU_POINTER=y
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+CONFIG_RCU_CPU_STALL_VERBOSE=y
+CONFIG_RCU_CPU_STALL_INFO=y
+# CONFIG_RCU_TRACE is not set
+# CONFIG_KPROBES_SANITY_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_DEBUG_PER_CPU_MAPS is not set
+# CONFIG_LKDTM is not set
+# CONFIG_NOTIFIER_ERROR_INJECTION is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS=y
+# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_USER_STACKTRACE_SUPPORT=y
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST=y
+CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_TRACER_MAX_TRACE=y
+CONFIG_TRACE_CLOCK=y
+CONFIG_RING_BUFFER=y
+CONFIG_EVENT_TRACING=y
+CONFIG_CONTEXT_SWITCH_TRACER=y
+CONFIG_RING_BUFFER_ALLOW_SWAP=y
+CONFIG_TRACING=y
+CONFIG_GENERIC_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+CONFIG_FUNCTION_TRACER=y
+CONFIG_FUNCTION_GRAPH_TRACER=y
+CONFIG_IRQSOFF_TRACER=y
+CONFIG_PREEMPT_TRACER=y
+CONFIG_SCHED_TRACER=y
+CONFIG_FTRACE_SYSCALLS=y
+CONFIG_TRACER_SNAPSHOT=y
+CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP=y
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+CONFIG_BLK_DEV_IO_TRACE=y
+# CONFIG_KPROBE_EVENT is not set
+# CONFIG_UPROBE_EVENT is not set
+# CONFIG_PROBE_EVENTS is not set
+CONFIG_DYNAMIC_FTRACE=y
+CONFIG_DYNAMIC_FTRACE_WITH_REGS=y
+CONFIG_FUNCTION_PROFILER=y
+CONFIG_FTRACE_MCOUNT_RECORD=y
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_MMIOTRACE is not set
+# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_RING_BUFFER_STARTUP_TEST is not set
+# CONFIG_RBTREE_TEST is not set
+# CONFIG_INTERVAL_TREE_TEST is not set
+CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
+CONFIG_DYNAMIC_DEBUG=y
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_HAVE_ARCH_KMEMCHECK=y
+# CONFIG_TEST_STRING_HELPERS is not set
+# CONFIG_TEST_KSTRTOX is not set
+# CONFIG_STRICT_DEVMEM is not set
+CONFIG_X86_VERBOSE_BOOTUP=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_EARLY_PRINTK_INTEL_MID=y
+# CONFIG_EARLY_PRINTK_DBGP is not set
+CONFIG_DEBUG_STACKOVERFLOW=y
+# CONFIG_X86_PTDUMP is not set
+CONFIG_DEBUG_RODATA=y
+# CONFIG_DEBUG_RODATA_TEST is not set
+CONFIG_DEBUG_SET_MODULE_RONX=y
+CONFIG_DEBUG_NX_TEST=m
+CONFIG_DOUBLEFAULT=y
+# CONFIG_DEBUG_TLBFLUSH is not set
+# CONFIG_IOMMU_STRESS is not set
+CONFIG_HAVE_MMIOTRACE_SUPPORT=y
+# CONFIG_X86_DECODER_SELFTEST is not set
+CONFIG_IO_DELAY_TYPE_0X80=0
+CONFIG_IO_DELAY_TYPE_0XED=1
+CONFIG_IO_DELAY_TYPE_UDELAY=2
+CONFIG_IO_DELAY_TYPE_NONE=3
+CONFIG_IO_DELAY_0X80=y
+# CONFIG_IO_DELAY_0XED is not set
+# CONFIG_IO_DELAY_UDELAY is not set
+# CONFIG_IO_DELAY_NONE is not set
+CONFIG_DEFAULT_IO_DELAY_TYPE=0
+CONFIG_DEBUG_BOOT_PARAMS=y
+# CONFIG_CPA_DEBUG is not set
+CONFIG_OPTIMIZE_INLINING=y
+# CONFIG_DEBUG_NMI_SELFTEST is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_ENCRYPTED_KEYS is not set
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITYFS is not set
+CONFIG_SECURITY_NETWORK=y
+# CONFIG_SECURITY_NETWORK_XFRM is not set
+# CONFIG_SECURITY_PATH is not set
+CONFIG_LSM_MMAP_MIN_ADDR=65536
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=1
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set
+# CONFIG_SECURITY_SMACK is not set
+# CONFIG_SECURITY_TOMOYO is not set
+# CONFIG_SECURITY_APPARMOR is not set
+# CONFIG_SECURITY_YAMA is not set
+# CONFIG_IMA is not set
+# CONFIG_EVM is not set
+CONFIG_DEFAULT_SECURITY_SELINUX=y
+# CONFIG_DEFAULT_SECURITY_DAC is not set
+CONFIG_DEFAULT_SECURITY="selinux"
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTODEV is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_USER is not set
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+CONFIG_CRYPTO_GF128MUL=y
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_PCRYPT is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_CRYPTO_CRYPTD=y
+CONFIG_CRYPTO_AUTHENC=y
+# CONFIG_CRYPTO_TEST is not set
+CONFIG_CRYPTO_ABLK_HELPER_X86=y
+
+#
+# Authenticated Encryption with Associated Data
+#
+CONFIG_CRYPTO_CCM=y
+# CONFIG_CRYPTO_GCM is not set
+CONFIG_CRYPTO_SEQIV=y
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CTR=y
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_LRW=y
+# CONFIG_CRYPTO_PCBC is not set
+CONFIG_CRYPTO_XTS=y
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_CMAC is not set
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_CRC32C_INTEL is not set
+# CONFIG_CRYPTO_CRC32 is not set
+# CONFIG_CRYPTO_CRC32_PCLMUL is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_AES_586=y
+CONFIG_CRYPTO_AES_NI_INTEL=y
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SALSA20_586 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_SERPENT_SSE2_586 is not set
+# CONFIG_CRYPTO_TEA is not set
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_TWOFISH_COMMON=y
+CONFIG_CRYPTO_TWOFISH_586=y
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_PADLOCK is not set
+# CONFIG_CRYPTO_DEV_GEODE is not set
+CONFIG_ASYMMETRIC_KEY_TYPE=y
+CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
+CONFIG_PUBLIC_KEY_ALGO_RSA=y
+CONFIG_X509_CERTIFICATE_PARSER=y
+CONFIG_HAVE_KVM=y
+CONFIG_VIRTUALIZATION=y
+# CONFIG_KVM is not set
+# CONFIG_LGUEST is not set
+CONFIG_BINARY_PRINTF=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GENERIC_FIND_FIRST_BIT=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_GENERIC_IO=y
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC32_SELFTEST is not set
+# CONFIG_CRC32_SLICEBY8 is not set
+# CONFIG_CRC32_SLICEBY4 is not set
+# CONFIG_CRC32_SARWATE is not set
+CONFIG_CRC32_BIT=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+# CONFIG_CRC8 is not set
+CONFIG_AUDIT_GENERIC=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_XZ_DEC=y
+CONFIG_XZ_DEC_X86=y
+CONFIG_XZ_DEC_POWERPC=y
+CONFIG_XZ_DEC_IA64=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_ARMTHUMB=y
+CONFIG_XZ_DEC_SPARC=y
+CONFIG_XZ_DEC_BCJ=y
+# CONFIG_XZ_DEC_TEST is not set
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_REED_SOLOMON=y
+CONFIG_REED_SOLOMON_ENC8=y
+CONFIG_REED_SOLOMON_DEC8=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_CPU_RMAP=y
+CONFIG_DQL=y
+CONFIG_NLATTR=y
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_AVERAGE=y
+CONFIG_CLZ_TAB=y
+# CONFIG_CORDIC is not set
+# CONFIG_DDR is not set
+CONFIG_MPILIB=y
+CONFIG_OID_REGISTRY=y
diff --git a/meta-edison/recipes-kernel/linux/files/upstream_to_edison.patch b/meta-edison/recipes-kernel/linux/files/upstream_to_edison.patch
new file mode 100644
index 0000000..8d8aaea
--- /dev/null
+++ b/meta-edison/recipes-kernel/linux/files/upstream_to_edison.patch
@@ -0,0 +1,99340 @@
+From 13c68cde952e979e0234c8b545ac34fa5450faaa Mon Sep 17 00:00:00 2001
+From: Fabien Chereau <fabien.chereau@intel.com>
+Date: Thu, 4 Sep 2014 11:11:37 +0200
+Subject: [PATCH] Squashed all commits from upstream to Edison
+
+Change-Id: Ic55424357d5e3a9ff5bcdd4d02ce06bbe4191acc
+---
+ Documentation/kernel-parameters.txt | 6 +-
+ arch/x86/Kconfig | 62 +-
+ arch/x86/Kconfig.cpu | 19 +-
+ arch/x86/Makefile | 2 +
+ arch/x86/Makefile_32.cpu | 2 +
+ arch/x86/configs/i386_edison_defconfig | 3768 +++++++++++++
+ arch/x86/configs/i386_mrfl_defconfig | 3980 ++++++++++++++
+ arch/x86/include/asm/apb_timer.h | 1 +
+ arch/x86/include/asm/bcm_bt_lpm.h | 46 +
+ arch/x86/include/asm/fixmap.h | 1 +
+ arch/x86/include/asm/gpio.h | 23 +
+ arch/x86/include/asm/intel-mid.h | 248 +
+ arch/x86/include/asm/intel_basincove_gpadc.h | 61 +
+ arch/x86/include/asm/intel_basincove_ocd.h | 161 +
+ arch/x86/include/asm/intel_mid_gpadc.h | 19 +
+ arch/x86/include/asm/intel_mid_hsu.h | 69 +
+ arch/x86/include/asm/intel_mid_pcihelpers.h | 25 +
+ arch/x86/include/asm/intel_mid_powerbtn.h | 14 +
+ arch/x86/include/asm/intel_mid_pwm.h | 30 +
+ arch/x86/include/asm/intel_mid_remoteproc.h | 117 +
+ arch/x86/include/asm/intel_mid_rpmsg.h | 77 +
+ arch/x86/include/asm/intel_mid_thermal.h | 77 +
+ arch/x86/include/asm/intel_mid_vrtc.h | 9 +
+ arch/x86/include/asm/intel_mip.h | 32 +
+ arch/x86/include/asm/intel_scu_flis.h | 326 ++
+ arch/x86/include/asm/intel_scu_ipc.h | 105 +-
+ arch/x86/include/asm/intel_scu_ipcutil.h | 135 +
+ arch/x86/include/asm/intel_scu_pmic.h | 16 +
+ arch/x86/include/asm/intel_soc_debug.h | 43 +
+ arch/x86/include/asm/module.h | 2 +-
+ arch/x86/include/asm/mrst-vrtc.h | 9 -
+ arch/x86/include/asm/mrst.h | 81 -
+ arch/x86/include/asm/mwait.h | 6 +
+ arch/x86/include/asm/pmic_pdata.h | 45 +
+ arch/x86/include/asm/required-features.h | 2 +-
+ arch/x86/include/asm/scu_ipc_rpmsg.h | 19 +
+ arch/x86/include/asm/setup.h | 4 +-
+ arch/x86/include/uapi/asm/bootparam.h | 2 +-
+ arch/x86/include/uapi/asm/msr-index.h | 5 +
+ arch/x86/kernel/apb_timer.c | 10 +-
+ arch/x86/kernel/apic/apic.c | 25 +-
+ arch/x86/kernel/apic/io_apic.c | 24 +
+ arch/x86/kernel/cpu/common.c | 6 +-
+ arch/x86/kernel/cpu/intel.c | 1 +
+ arch/x86/kernel/cpu/mcheck/therm_throt.c | 19 +-
+ arch/x86/kernel/early_printk.c | 9 +-
+ arch/x86/kernel/head32.c | 4 +-
+ arch/x86/kernel/irq.c | 4 +-
+ arch/x86/kernel/rtc.c | 36 +-
+ arch/x86/kernel/smpboot.c | 45 +-
+ arch/x86/pci/mrst.c | 21 +-
+ arch/x86/platform/Makefile | 2 +-
+ arch/x86/platform/intel-mid/Makefile | 27 +
+ arch/x86/platform/intel-mid/board.c | 160 +
+ arch/x86/platform/intel-mid/device_libs/Makefile | 64 +
+ .../platform/intel-mid/device_libs/pci/Makefile | 6 +
+ .../intel-mid/device_libs/pci/platform_sdhci_pci.c | 588 ++
+ .../intel-mid/device_libs/pci/platform_sdhci_pci.h | 30 +
+ .../intel-mid/device_libs/pci/platform_usb_otg.c | 93 +
+ .../intel-mid/device_libs/platform_ads7955.c | 37 +
+ .../intel-mid/device_libs/platform_ads7955.h | 20 +
+ .../intel-mid/device_libs/platform_bcove_adc.c | 143 +
+ .../intel-mid/device_libs/platform_bcove_adc.h | 17 +
+ .../intel-mid/device_libs/platform_bq24261.c | 77 +
+ .../intel-mid/device_libs/platform_bq24261.h | 26 +
+ .../intel-mid/device_libs/platform_btlpm.c | 80 +
+ .../intel-mid/device_libs/platform_dw_i2c.c | 113 +
+ .../intel-mid/device_libs/platform_emc1403.c | 33 +
+ .../intel-mid/device_libs/platform_emc1403.h | 16 +
+ .../intel-mid/device_libs/platform_gpio_keys.c | 89 +
+ .../intel-mid/device_libs/platform_gpio_keys.h | 16 +
+ .../platform/intel-mid/device_libs/platform_hsu.c | 440 ++
+ .../platform/intel-mid/device_libs/platform_hsu.h | 56 +
+ .../platform/intel-mid/device_libs/platform_ipc.c | 38 +
+ .../platform/intel-mid/device_libs/platform_ipc.h | 17 +
+ .../intel-mid/device_libs/platform_lis331.c | 32 +
+ .../intel-mid/device_libs/platform_lis331.h | 16 +
+ .../intel-mid/device_libs/platform_max3111.c | 61 +
+ .../intel-mid/device_libs/platform_max3111.h | 20 +
+ .../intel-mid/device_libs/platform_max7315.c | 64 +
+ .../intel-mid/device_libs/platform_max7315.h | 19 +
+ .../intel-mid/device_libs/platform_mid_pwm.c | 121 +
+ .../intel-mid/device_libs/platform_mid_pwm.h | 21 +
+ .../intel-mid/device_libs/platform_mpu3050.c | 28 +
+ .../intel-mid/device_libs/platform_mpu3050.h | 16 +
+ .../intel-mid/device_libs/platform_mrfl_ocd.c | 68 +
+ .../intel-mid/device_libs/platform_mrfl_ocd.h | 19 +
+ .../intel-mid/device_libs/platform_mrfl_pmic.c | 54 +
+ .../intel-mid/device_libs/platform_mrfl_pmic.h | 17 +
+ .../intel-mid/device_libs/platform_mrfl_pmic_i2c.c | 49 +
+ .../intel-mid/device_libs/platform_mrfl_pmic_i2c.h | 17 +
+ .../device_libs/platform_mrfl_regulator.c | 125 +
+ .../intel-mid/device_libs/platform_mrfl_thermal.c | 133 +
+ .../intel-mid/device_libs/platform_mrfl_thermal.h | 26 +
+ .../platform/intel-mid/device_libs/platform_msic.c | 92 +
+ .../platform/intel-mid/device_libs/platform_msic.h | 21 +
+ .../intel-mid/device_libs/platform_msic_adc.c | 56 +
+ .../intel-mid/device_libs/platform_msic_adc.h | 18 +
+ .../intel-mid/device_libs/platform_msic_audio.c | 36 +
+ .../intel-mid/device_libs/platform_msic_audio.h | 16 +
+ .../intel-mid/device_libs/platform_msic_battery.c | 26 +
+ .../intel-mid/device_libs/platform_msic_battery.h | 17 +
+ .../intel-mid/device_libs/platform_msic_gpio.c | 79 +
+ .../intel-mid/device_libs/platform_msic_gpio.h | 18 +
+ .../intel-mid/device_libs/platform_msic_ocd.c | 39 +
+ .../intel-mid/device_libs/platform_msic_ocd.h | 16 +
+ .../device_libs/platform_msic_power_btn.c | 73 +
+ .../device_libs/platform_msic_power_btn.h | 19 +
+ .../intel-mid/device_libs/platform_msic_thermal.c | 185 +
+ .../intel-mid/device_libs/platform_msic_thermal.h | 26 +
+ .../intel-mid/device_libs/platform_pcal9555a.c | 68 +
+ .../intel-mid/device_libs/platform_pcal9555a.h | 19 +
+ .../intel-mid/device_libs/platform_pmic_gpio.c | 36 +
+ .../intel-mid/device_libs/platform_pmic_gpio.h | 16 +
+ .../intel-mid/device_libs/platform_scu_flis.c | 290 +
+ .../intel-mid/device_libs/platform_scu_flis.h | 17 +
+ .../device_libs/platform_sdio_regulator.c | 235 +
+ .../intel-mid/device_libs/platform_soc_thermal.c | 136 +
+ .../intel-mid/device_libs/platform_soc_thermal.h | 20 +
+ .../intel-mid/device_libs/platform_spidev.c | 73 +
+ .../intel-mid/device_libs/platform_spidev.h | 20 +
+ .../intel-mid/device_libs/platform_tc35876x.c | 26 +
+ .../intel-mid/device_libs/platform_tc35876x.h | 16 +
+ .../intel-mid/device_libs/platform_tca6416.c | 45 +
+ .../intel-mid/device_libs/platform_tca6416.h | 20 +
+ .../platform/intel-mid/device_libs/platform_wifi.c | 128 +
+ .../platform/intel-mid/device_libs/platform_wifi.h | 21 +
+ .../intel-mid/device_libs/platform_wl12xx.c | 182 +
+ .../intel-mid/device_libs/platform_wl12xx.h | 21 +
+ .../platform/intel-mid/early_printk_intel_mid.c | 637 +++
+ arch/x86/platform/intel-mid/intel-mid.c | 239 +
+ arch/x86/platform/intel-mid/intel_mid_pcihelpers.c | 105 +
+ arch/x86/platform/intel-mid/intel_mid_scu.c | 92 +
+ arch/x86/platform/intel-mid/intel_mid_scu.h | 15 +
+ arch/x86/platform/intel-mid/intel_mid_sfi.c | 588 ++
+ arch/x86/platform/intel-mid/intel_mid_vrtc.c | 169 +
+ arch/x86/platform/intel-mid/intel_mid_weak_decls.h | 22 +
+ arch/x86/platform/intel-mid/intel_soc_clv.c | 146 +
+ arch/x86/platform/intel-mid/intel_soc_clv.h | 352 ++
+ arch/x86/platform/intel-mid/intel_soc_debug.c | 202 +
+ arch/x86/platform/intel-mid/intel_soc_dump.c | 1586 ++++++
+ arch/x86/platform/intel-mid/intel_soc_mdfld.c | 178 +
+ arch/x86/platform/intel-mid/intel_soc_mdfld.h | 353 ++
+ .../intel-mid/intel_soc_mdfld_clv_common.c | 451 ++
+ arch/x86/platform/intel-mid/intel_soc_mrfld.c | 446 ++
+ arch/x86/platform/intel-mid/intel_soc_mrfld.h | 161 +
+ arch/x86/platform/intel-mid/intel_soc_pm_debug.c | 2518 +++++++++
+ arch/x86/platform/intel-mid/intel_soc_pm_debug.h | 234 +
+ arch/x86/platform/intel-mid/intel_soc_pmu.c | 2143 ++++++++
+ arch/x86/platform/intel-mid/intel_soc_pmu.h | 511 ++
+ arch/x86/platform/intel-mid/mfld.c | 94 +
+ arch/x86/platform/intel-mid/mrfl.c | 161 +
+ arch/x86/platform/intel-mid/pmu_tng.c | 218 +
+ arch/x86/platform/intel-mid/pmu_tng.h | 180 +
+ arch/x86/platform/mrst/Makefile | 3 -
+ arch/x86/platform/mrst/early_printk_mrst.c | 324 --
+ arch/x86/platform/mrst/mrst.c | 1052 ----
+ arch/x86/platform/mrst/vrtc.c | 177 -
+ drivers/acpi/acpi_platform.c | 3 +-
+ drivers/acpi/osl.c | 5 +
+ drivers/bluetooth/hci_ldisc.c | 25 +-
+ drivers/bluetooth/hci_uart.h | 1 +
+ drivers/cpufreq/Kconfig.x86 | 15 +
+ drivers/cpufreq/Makefile | 1 +
+ drivers/cpufreq/sfi-cpufreq.c | 581 ++
+ drivers/cpufreq/sfi-cpufreq.h | 65 +
+ drivers/dma/Makefile | 2 +-
+ drivers/dma/intel_mid_dma.c | 1278 +++--
+ drivers/dma/intel_mid_dma_acpi.c | 177 +
+ drivers/dma/intel_mid_dma_regs.h | 164 +-
+ drivers/gpio/Kconfig | 11 +
+ drivers/gpio/Makefile | 1 +
+ drivers/gpio/gpio-langwell.c | 1061 +++-
+ drivers/gpio/gpio-pca953x.c | 151 +-
+ drivers/gpio/gpiodebug.c | 540 ++
+ drivers/gpio/gpiodebug.h | 108 +
+ drivers/gpio/gpiolib.c | 55 +
+ drivers/gpu/drm/gma500/mdfld_dsi_output.h | 2 +-
+ drivers/gpu/drm/gma500/oaktrail_device.c | 2 +-
+ drivers/gpu/drm/gma500/oaktrail_lvds.c | 2 +-
+ drivers/hwmon/Kconfig | 16 +
+ drivers/hwmon/Makefile | 1 +
+ drivers/hwmon/coretemp.c | 362 +-
+ drivers/hwmon/intel_mid_gpadc.c | 1212 ++++
+ drivers/i2c/busses/Kconfig | 46 +
+ drivers/i2c/busses/Makefile | 8 +
+ drivers/i2c/busses/i2c-designware-core.c | 1151 +++-
+ drivers/i2c/busses/i2c-designware-core.h | 255 +-
+ drivers/i2c/busses/i2c-designware-pcidrv.c | 327 +-
+ drivers/i2c/busses/i2c-designware-platdrv.c | 255 +-
+ drivers/i2c/busses/i2c-pmic-regs.h | 78 +
+ drivers/i2c/busses/i2c-pmic.c | 452 ++
+ drivers/idle/intel_idle.c | 376 +-
+ drivers/iio/adc/Kconfig | 18 +
+ drivers/iio/adc/Makefile | 2 +
+ drivers/iio/adc/iio_basincove_gpadc.c | 596 ++
+ drivers/iio/adc/ti-ads7955.c | 421 ++
+ drivers/iio/industrialio-core.c | 1 +
+ drivers/iio/inkern.c | 60 +
+ drivers/mfd/intel_msic.c | 2 +-
+ drivers/misc/Kconfig | 27 +
+ drivers/misc/Makefile | 3 +
+ drivers/misc/bcm-lpm/Kconfig | 6 +
+ drivers/misc/bcm-lpm/Makefile | 1 +
+ drivers/misc/bcm-lpm/bcm_bt_lpm.c | 581 ++
+ drivers/misc/emmc_ipanic.c | 1158 ++++
+ drivers/misc/emmc_ipanic.h | 96 +
+ drivers/misc/pti.c | 95 +-
+ drivers/misc/stm.c | 470 ++
+ drivers/misc/stm.h | 114 +
+ drivers/mmc/card/block.c | 6 +
+ drivers/mmc/card/queue.c | 3 +-
+ drivers/mmc/card/queue.h | 1 +
+ drivers/mmc/core/Makefile | 2 +-
+ drivers/mmc/core/bus.c | 3 +-
+ drivers/mmc/core/core.c | 25 +-
+ drivers/mmc/core/debugfs.c | 3 +
+ drivers/mmc/core/mmc.c | 161 +-
+ drivers/mmc/core/mmc_ops.c | 4 +-
+ drivers/mmc/core/mmc_panic_ops.c | 837 +++
+ drivers/mmc/core/sdio_cis.c | 129 +-
+ drivers/mmc/host/sdhci-pci.c | 819 ++-
+ drivers/mmc/host/sdhci.c | 1452 ++++-
+ drivers/mmc/host/sdhci.h | 13 +-
+ drivers/net/wireless/Kconfig | 10 +
+ drivers/pci/Makefile | 1 +
+ drivers/pci/pci-atom_soc.c | 78 +
+ drivers/pci/pci.c | 5 +-
+ drivers/pci/quirks.c | 6 +-
+ drivers/platform/x86/Kconfig | 23 +
+ drivers/platform/x86/Makefile | 4 +-
+ drivers/platform/x86/intel_mid_powerbtn.c | 252 +-
+ drivers/platform/x86/intel_mid_thermal.c | 574 --
+ drivers/platform/x86/intel_pmic_gpio.c | 2 +-
+ drivers/platform/x86/intel_scu_flis.c | 747 +++
+ drivers/platform/x86/intel_scu_fw_update.c | 1087 ++++
+ drivers/platform/x86/intel_scu_ipc.c | 636 +--
+ drivers/platform/x86/intel_scu_ipcutil.c | 2587 ++++++++-
+ drivers/platform/x86/intel_scu_mip.c | 776 +++
+ drivers/platform/x86/intel_scu_pmic.c | 477 ++
+ drivers/power/Kconfig | 20 +
+ drivers/power/Makefile | 12 +-
+ drivers/power/battery_id.c | 68 +
+ drivers/power/bq24261_charger.c | 1887 +++++++
+ drivers/power/charging_algo_pse.c | 180 +
+ drivers/power/pmic_ccsm.c | 1914 +++++++
+ drivers/power/pmic_ccsm.h | 356 ++
+ drivers/power/power_supply.h | 21 +
+ drivers/power/power_supply_charger.c | 1151 ++++
+ drivers/power/power_supply_charger.h | 244 +
+ drivers/power/power_supply_core.c | 104 +-
+ drivers/power/power_supply_sysfs.c | 15 +-
+ drivers/pwm/Kconfig | 13 +
+ drivers/pwm/Makefile | 2 +
+ drivers/pwm/core.c | 25 +-
+ drivers/pwm/pwm-intel-mid.c | 405 ++
+ drivers/pwm/sysfs.c | 353 ++
+ drivers/regulator/Kconfig | 6 +-
+ drivers/regulator/Makefile | 2 +
+ drivers/regulator/pmic_basin_cove.c | 302 +
+ drivers/remoteproc/Kconfig | 11 +
+ drivers/remoteproc/Makefile | 1 +
+ drivers/remoteproc/intel_mid_rproc_core.c | 269 +
+ drivers/remoteproc/intel_mid_rproc_core.h | 82 +
+ drivers/remoteproc/intel_mid_rproc_scu.c | 438 ++
+ drivers/rpmsg/Kconfig | 9 +
+ drivers/rpmsg/Makefile | 1 +
+ drivers/rpmsg/intel_mid_rpmsg.c | 446 ++
+ drivers/rpmsg/virtio_rpmsg_bus.c | 12 +-
+ drivers/rtc/rtc-mrst.c | 296 +-
+ drivers/spi/Kconfig | 9 +
+ drivers/spi/Makefile | 1 +
+ drivers/spi/intel_mid_ssp_spi.c | 1642 ++++++
+ drivers/spi/spi-dw-mid.c | 133 +-
+ drivers/spi/spi-dw-pci.c | 102 +-
+ drivers/spi/spi-dw.c | 151 +-
+ drivers/spi/spi-dw.h | 7 +-
+ drivers/thermal/Kconfig | 28 +
+ drivers/thermal/Makefile | 9 +
+ drivers/thermal/intel_mid_thermal.c | 754 +++
+ drivers/thermal/intel_mrfl_thermal.c | 909 +++
+ drivers/thermal/intel_soc_thermal.c | 834 +++
+ drivers/thermal/thermal_core.c | 177 +-
+ drivers/tty/serial/Kconfig | 12 +-
+ drivers/tty/serial/Makefile | 2 +-
+ drivers/tty/serial/mfd.c | 1502 -----
+ drivers/tty/serial/mfd.h | 252 +
+ drivers/tty/serial/mfd_core.c | 2479 +++++++++
+ drivers/tty/serial/mfd_dma.c | 753 +++
+ drivers/tty/serial/mfd_pci.c | 298 +
+ drivers/tty/serial/mfd_plat.c | 244 +
+ drivers/tty/serial/mfd_trace.h | 197 +
+ drivers/tty/serial/mrst_max3110.c | 83 +-
+ drivers/tty/serial/serial_core.c | 3 +
+ drivers/usb/core/hcd.c | 23 +-
+ drivers/usb/dwc3/Kconfig | 66 +
+ drivers/usb/dwc3/Makefile | 10 +-
+ drivers/usb/dwc3/core.c | 21 +-
+ drivers/usb/dwc3/core.h | 71 +
+ drivers/usb/dwc3/debugfs.c | 49 +
+ drivers/usb/dwc3/dwc3-device-intel.c | 648 +++
+ drivers/usb/dwc3/dwc3-host-intel.c | 724 +++
+ drivers/usb/dwc3/dwc3-intel-byt.c | 970 ++++
+ drivers/usb/dwc3/dwc3-intel-mrfl.c | 992 ++++
+ drivers/usb/dwc3/dwc3-pci.c | 4 +
+ drivers/usb/dwc3/ep0.c | 37 +-
+ drivers/usb/dwc3/gadget.c | 1085 +++-
+ drivers/usb/dwc3/gadget.h | 7 +
+ drivers/usb/dwc3/otg.c | 1509 +++++
+ drivers/usb/dwc3/otg.h | 432 ++
+ drivers/usb/gadget/epautoconf.c | 42 +
+ drivers/usb/gadget/f_dvc_dfx.c | 922 ++++
+ drivers/usb/gadget/f_dvc_trace.c | 887 +++
+ drivers/usb/gadget/f_mass_storage.c | 2 +-
+ drivers/usb/gadget/gadget_chips.h | 5 +-
+ drivers/usb/gadget/u_ether.c | 2 -
+ drivers/usb/gadget/u_serial.c | 2 +-
+ drivers/usb/gadget/udc-core.c | 12 +-
+ drivers/usb/host/ehci-pci.c | 2 +-
+ drivers/usb/host/xhci-plat.c | 11 +
+ drivers/usb/phy/penwell_otg.c | 5780 ++++++++++++++++++++
+ drivers/watchdog/Kconfig | 21 +
+ drivers/watchdog/Makefile | 1 +
+ drivers/watchdog/intel_scu_watchdog.c | 568 --
+ drivers/watchdog/intel_scu_watchdog_evo.c | 1403 +++++
+ drivers/watchdog/intel_scu_watchdog_evo.h | 68 +
+ firmware/Makefile | 1 +
+ firmware/intel_mid/intel_mid_remoteproc.fw.ihex | 280 +
+ fs/ecryptfs/crypto.c | 4 +-
+ include/asm-generic/gpio.h | 3 +
+ include/linux/iio/consumer.h | 3 +
+ include/linux/iio/iio.h | 3 +
+ include/linux/iio/types.h | 1 +
+ include/linux/intel_mid_dma.h | 7 +
+ include/linux/intel_mid_pm.h | 234 +
+ include/linux/intel_pidv_acpi.h | 54 +
+ include/linux/irq.h | 1 +
+ include/linux/irqdesc.h | 7 +
+ include/linux/lnw_gpio.h | 14 +
+ include/linux/mfd/intel_msic.h | 42 +
+ include/linux/mmc/card.h | 5 +
+ include/linux/mmc/core.h | 1 +
+ include/linux/mmc/host.h | 64 +
+ include/linux/mmc/mmc.h | 5 +
+ include/linux/mmc/sdhci-pci-data.h | 16 +
+ include/linux/mmc/sdhci.h | 52 +
+ include/linux/mmc/sdio_ids.h | 2 +
+ include/linux/panic_gbuffer.h | 37 +
+ include/linux/pci_ids.h | 13 +
+ include/linux/platform_data/intel_mid_remoteproc.h | 119 +
+ include/linux/platform_data/ti-ads7955.h | 21 +
+ include/linux/power/battery_id.h | 78 +
+ include/linux/power/bq24261_charger.h | 56 +
+ include/linux/power_supply.h | 92 +-
+ include/linux/pwm.h | 30 +-
+ include/linux/regulator/intel_basin_cove_pmic.h | 59 +
+ include/linux/regulator/intel_pmic.h | 54 +
+ include/linux/sdm.h | 60 +
+ include/linux/serial_core.h | 1 +
+ include/linux/serial_max3110.h | 16 +
+ include/linux/serial_mfd.h | 7 +-
+ include/linux/sfi.h | 5 +
+ include/linux/spi/intel_mid_ssp_spi.h | 352 ++
+ include/linux/thermal.h | 26 +-
+ include/linux/tty_ldisc.h | 5 +-
+ include/linux/usb/debug.h | 253 +
+ include/linux/usb/dwc3-intel-mid.h | 190 +
+ include/linux/usb/dwc3-intel-mrfl.h | 168 +
+ include/linux/usb/gadget.h | 4 +
+ include/linux/usb/hcd.h | 3 +
+ include/linux/usb/penwell_otg.h | 515 ++
+ include/linux/usb/phy.h | 14 +
+ include/linux/wl12xx.h | 5 +
+ include/linux/wlan_plat.h | 29 +
+ include/uapi/linux/usb/ch9.h | 1 +
+ init/main.c | 2 +
+ kernel/cgroup.c | 6 +-
+ kernel/irq/chip.c | 1 +
+ kernel/irq/settings.h | 7 +
+ kernel/power/process.c | 2 +
+ kernel/printk.c | 18 +-
+ kernel/trace/trace.c | 5 +-
+ sound/soc/codecs/sn95031.c | 2 +-
+ 383 files changed, 83788 insertions(+), 6462 deletions(-)
+ create mode 100644 arch/x86/configs/i386_edison_defconfig
+ create mode 100644 arch/x86/configs/i386_mrfl_defconfig
+ create mode 100644 arch/x86/include/asm/bcm_bt_lpm.h
+ create mode 100644 arch/x86/include/asm/intel-mid.h
+ create mode 100644 arch/x86/include/asm/intel_basincove_gpadc.h
+ create mode 100644 arch/x86/include/asm/intel_basincove_ocd.h
+ create mode 100644 arch/x86/include/asm/intel_mid_gpadc.h
+ create mode 100644 arch/x86/include/asm/intel_mid_hsu.h
+ create mode 100644 arch/x86/include/asm/intel_mid_pcihelpers.h
+ create mode 100644 arch/x86/include/asm/intel_mid_powerbtn.h
+ create mode 100644 arch/x86/include/asm/intel_mid_pwm.h
+ create mode 100644 arch/x86/include/asm/intel_mid_remoteproc.h
+ create mode 100644 arch/x86/include/asm/intel_mid_rpmsg.h
+ create mode 100644 arch/x86/include/asm/intel_mid_thermal.h
+ create mode 100644 arch/x86/include/asm/intel_mid_vrtc.h
+ create mode 100644 arch/x86/include/asm/intel_mip.h
+ create mode 100644 arch/x86/include/asm/intel_scu_flis.h
+ create mode 100644 arch/x86/include/asm/intel_scu_ipcutil.h
+ create mode 100644 arch/x86/include/asm/intel_scu_pmic.h
+ create mode 100644 arch/x86/include/asm/intel_soc_debug.h
+ delete mode 100644 arch/x86/include/asm/mrst-vrtc.h
+ delete mode 100644 arch/x86/include/asm/mrst.h
+ create mode 100644 arch/x86/include/asm/pmic_pdata.h
+ create mode 100644 arch/x86/include/asm/scu_ipc_rpmsg.h
+ create mode 100644 arch/x86/platform/intel-mid/Makefile
+ create mode 100644 arch/x86/platform/intel-mid/board.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/Makefile
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/pci/Makefile
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/pci/platform_sdhci_pci.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/pci/platform_sdhci_pci.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/pci/platform_usb_otg.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_ads7955.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_ads7955.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_bcove_adc.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_bcove_adc.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_bq24261.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_bq24261.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_btlpm.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_dw_i2c.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_emc1403.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_emc1403.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_gpio_keys.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_gpio_keys.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_hsu.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_hsu.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_ipc.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_ipc.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_lis331.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_lis331.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_max3111.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_max3111.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_max7315.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_max7315.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_mid_pwm.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_mid_pwm.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_mpu3050.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_mpu3050.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_mrfl_ocd.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_mrfl_ocd.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_mrfl_pmic.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_mrfl_pmic.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_mrfl_pmic_i2c.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_mrfl_pmic_i2c.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_mrfl_regulator.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_mrfl_thermal.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_mrfl_thermal.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_msic.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_msic.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_msic_adc.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_msic_adc.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_msic_audio.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_msic_audio.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_msic_battery.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_msic_battery.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_msic_gpio.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_msic_gpio.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_msic_ocd.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_msic_ocd.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_msic_power_btn.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_msic_power_btn.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_msic_thermal.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_msic_thermal.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_pcal9555a.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_pcal9555a.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_pmic_gpio.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_pmic_gpio.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_scu_flis.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_scu_flis.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_sdio_regulator.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_soc_thermal.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_soc_thermal.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_spidev.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_spidev.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_tc35876x.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_tc35876x.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_tca6416.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_tca6416.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_wifi.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_wifi.h
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_wl12xx.c
+ create mode 100644 arch/x86/platform/intel-mid/device_libs/platform_wl12xx.h
+ create mode 100644 arch/x86/platform/intel-mid/early_printk_intel_mid.c
+ create mode 100644 arch/x86/platform/intel-mid/intel-mid.c
+ create mode 100644 arch/x86/platform/intel-mid/intel_mid_pcihelpers.c
+ create mode 100644 arch/x86/platform/intel-mid/intel_mid_scu.c
+ create mode 100644 arch/x86/platform/intel-mid/intel_mid_scu.h
+ create mode 100644 arch/x86/platform/intel-mid/intel_mid_sfi.c
+ create mode 100644 arch/x86/platform/intel-mid/intel_mid_vrtc.c
+ create mode 100644 arch/x86/platform/intel-mid/intel_mid_weak_decls.h
+ create mode 100644 arch/x86/platform/intel-mid/intel_soc_clv.c
+ create mode 100644 arch/x86/platform/intel-mid/intel_soc_clv.h
+ create mode 100644 arch/x86/platform/intel-mid/intel_soc_debug.c
+ create mode 100644 arch/x86/platform/intel-mid/intel_soc_dump.c
+ create mode 100644 arch/x86/platform/intel-mid/intel_soc_mdfld.c
+ create mode 100644 arch/x86/platform/intel-mid/intel_soc_mdfld.h
+ create mode 100644 arch/x86/platform/intel-mid/intel_soc_mdfld_clv_common.c
+ create mode 100644 arch/x86/platform/intel-mid/intel_soc_mrfld.c
+ create mode 100644 arch/x86/platform/intel-mid/intel_soc_mrfld.h
+ create mode 100644 arch/x86/platform/intel-mid/intel_soc_pm_debug.c
+ create mode 100644 arch/x86/platform/intel-mid/intel_soc_pm_debug.h
+ create mode 100644 arch/x86/platform/intel-mid/intel_soc_pmu.c
+ create mode 100644 arch/x86/platform/intel-mid/intel_soc_pmu.h
+ create mode 100644 arch/x86/platform/intel-mid/mfld.c
+ create mode 100644 arch/x86/platform/intel-mid/mrfl.c
+ create mode 100644 arch/x86/platform/intel-mid/pmu_tng.c
+ create mode 100644 arch/x86/platform/intel-mid/pmu_tng.h
+ delete mode 100644 arch/x86/platform/mrst/Makefile
+ delete mode 100644 arch/x86/platform/mrst/early_printk_mrst.c
+ delete mode 100644 arch/x86/platform/mrst/mrst.c
+ delete mode 100644 arch/x86/platform/mrst/vrtc.c
+ create mode 100644 drivers/cpufreq/sfi-cpufreq.c
+ create mode 100644 drivers/cpufreq/sfi-cpufreq.h
+ create mode 100644 drivers/dma/intel_mid_dma_acpi.c
+ create mode 100644 drivers/gpio/gpiodebug.c
+ create mode 100644 drivers/gpio/gpiodebug.h
+ create mode 100644 drivers/hwmon/intel_mid_gpadc.c
+ create mode 100644 drivers/i2c/busses/i2c-pmic-regs.h
+ create mode 100644 drivers/i2c/busses/i2c-pmic.c
+ create mode 100644 drivers/iio/adc/iio_basincove_gpadc.c
+ create mode 100644 drivers/iio/adc/ti-ads7955.c
+ create mode 100644 drivers/misc/bcm-lpm/Kconfig
+ create mode 100644 drivers/misc/bcm-lpm/Makefile
+ create mode 100644 drivers/misc/bcm-lpm/bcm_bt_lpm.c
+ create mode 100644 drivers/misc/emmc_ipanic.c
+ create mode 100644 drivers/misc/emmc_ipanic.h
+ create mode 100644 drivers/misc/stm.c
+ create mode 100644 drivers/misc/stm.h
+ create mode 100644 drivers/mmc/core/mmc_panic_ops.c
+ create mode 100644 drivers/pci/pci-atom_soc.c
+ delete mode 100644 drivers/platform/x86/intel_mid_thermal.c
+ create mode 100644 drivers/platform/x86/intel_scu_flis.c
+ create mode 100644 drivers/platform/x86/intel_scu_fw_update.c
+ create mode 100644 drivers/platform/x86/intel_scu_mip.c
+ create mode 100644 drivers/platform/x86/intel_scu_pmic.c
+ create mode 100644 drivers/power/battery_id.c
+ create mode 100644 drivers/power/bq24261_charger.c
+ create mode 100644 drivers/power/charging_algo_pse.c
+ create mode 100644 drivers/power/pmic_ccsm.c
+ create mode 100644 drivers/power/pmic_ccsm.h
+ create mode 100644 drivers/power/power_supply_charger.c
+ create mode 100644 drivers/power/power_supply_charger.h
+ create mode 100644 drivers/pwm/pwm-intel-mid.c
+ create mode 100644 drivers/pwm/sysfs.c
+ create mode 100644 drivers/regulator/pmic_basin_cove.c
+ create mode 100644 drivers/remoteproc/intel_mid_rproc_core.c
+ create mode 100644 drivers/remoteproc/intel_mid_rproc_core.h
+ create mode 100644 drivers/remoteproc/intel_mid_rproc_scu.c
+ create mode 100644 drivers/rpmsg/intel_mid_rpmsg.c
+ create mode 100644 drivers/spi/intel_mid_ssp_spi.c
+ create mode 100644 drivers/thermal/intel_mid_thermal.c
+ create mode 100644 drivers/thermal/intel_mrfl_thermal.c
+ create mode 100644 drivers/thermal/intel_soc_thermal.c
+ delete mode 100644 drivers/tty/serial/mfd.c
+ create mode 100644 drivers/tty/serial/mfd.h
+ create mode 100644 drivers/tty/serial/mfd_core.c
+ create mode 100644 drivers/tty/serial/mfd_dma.c
+ create mode 100644 drivers/tty/serial/mfd_pci.c
+ create mode 100644 drivers/tty/serial/mfd_plat.c
+ create mode 100644 drivers/tty/serial/mfd_trace.h
+ create mode 100644 drivers/usb/dwc3/dwc3-device-intel.c
+ create mode 100644 drivers/usb/dwc3/dwc3-host-intel.c
+ create mode 100644 drivers/usb/dwc3/dwc3-intel-byt.c
+ create mode 100644 drivers/usb/dwc3/dwc3-intel-mrfl.c
+ create mode 100644 drivers/usb/dwc3/otg.c
+ create mode 100644 drivers/usb/dwc3/otg.h
+ create mode 100644 drivers/usb/gadget/f_dvc_dfx.c
+ create mode 100644 drivers/usb/gadget/f_dvc_trace.c
+ create mode 100644 drivers/usb/phy/penwell_otg.c
+ delete mode 100644 drivers/watchdog/intel_scu_watchdog.c
+ create mode 100644 drivers/watchdog/intel_scu_watchdog_evo.c
+ create mode 100644 drivers/watchdog/intel_scu_watchdog_evo.h
+ create mode 100644 firmware/intel_mid/intel_mid_remoteproc.fw.ihex
+ create mode 100644 include/linux/intel_mid_pm.h
+ create mode 100644 include/linux/intel_pidv_acpi.h
+ create mode 100644 include/linux/lnw_gpio.h
+ create mode 100644 include/linux/panic_gbuffer.h
+ create mode 100644 include/linux/platform_data/intel_mid_remoteproc.h
+ create mode 100644 include/linux/platform_data/ti-ads7955.h
+ create mode 100644 include/linux/power/battery_id.h
+ create mode 100644 include/linux/power/bq24261_charger.h
+ create mode 100644 include/linux/regulator/intel_basin_cove_pmic.h
+ create mode 100644 include/linux/regulator/intel_pmic.h
+ create mode 100644 include/linux/sdm.h
+ create mode 100644 include/linux/serial_max3110.h
+ create mode 100644 include/linux/spi/intel_mid_ssp_spi.h
+ create mode 100644 include/linux/usb/debug.h
+ create mode 100644 include/linux/usb/dwc3-intel-mid.h
+ create mode 100644 include/linux/usb/dwc3-intel-mrfl.h
+ create mode 100644 include/linux/usb/penwell_otg.h
+ create mode 100644 include/linux/wlan_plat.h
+
+diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
+index 2fe6e76..8ec1e55 100644
+--- a/Documentation/kernel-parameters.txt
++++ b/Documentation/kernel-parameters.txt
+@@ -3345,11 +3345,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
+ default x2apic cluster mode on platforms
+ supporting x2apic.
+
+- x86_mrst_timer= [X86-32,APBT]
+- Choose timer option for x86 Moorestown MID platform.
++ x86_intel_mid_timer= [X86-32,APBT]
++ Choose timer option for x86 Intel MID platform.
+ Two valid options are apbt timer only and lapic timer
+ plus one apbt timer for broadcast timer.
+- x86_mrst_timer=apbt_only | lapic_and_apbt
++ x86_intel_mid_timer=apbt_only | lapic_and_apbt
+
+ xen_emul_unplug= [HW,X86,XEN]
+ Unplug Xen emulated devices
+diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
+index fe120da..82b8dca 100644
+--- a/arch/x86/Kconfig
++++ b/arch/x86/Kconfig
+@@ -442,29 +442,65 @@ config X86_WANT_INTEL_MID
+ if X86_WANT_INTEL_MID
+
+ config X86_INTEL_MID
+- bool
+-
+-config X86_MDFLD
+- bool "Medfield MID platform"
++ bool "Intel MID platform"
+ depends on PCI
+ depends on PCI_GOANY
+ depends on X86_IO_APIC
+- select X86_INTEL_MID
+ select SFI
++ select INTEL_SCU_IPC
++ select X86_PLATFORM_DEVICES
++ select ARCH_HAVE_CUSTOM_GPIO_H
++ ---help---
++ Intel MID is Intel's Low Power Intel Architecture (LPIA) based Mobile
++ Internet Device(MID) platform.
++ Unlike standard x86 PCs, Intel MID does not have many legacy devices
++ nor standard legacy replacement devices/features. e.g. It does not
++ contain i8259, i8254, HPET, legacy BIOS, most of the io ports.
++
++config X86_MDFLD
++ bool "Medfield MID platform"
++ depends on X86_INTEL_MID
+ select DW_APB_TIMER
+ select APB_TIMER
+ select I2C
+ select SPI
+- select INTEL_SCU_IPC
+- select X86_PLATFORM_DEVICES
+ select MFD_INTEL_MSIC
+ ---help---
+ Medfield is Intel's Low Power Intel Architecture (LPIA) based Moblin
+- Internet Device(MID) platform.
++ Internet Device(MID) platform.
+ Unlike standard x86 PCs, Medfield does not have many legacy devices
+ nor standard legacy replacement devices/features. e.g. Medfield does
+ not contain i8259, i8254, HPET, legacy BIOS, most of the io ports.
+
++config ATOM_SOC_POWER
++ bool "Select Atom SOC Power"
++
++choice
++ prompt "Select PMU support"
++ depends on ATOM_SOC_POWER
++ default REMOVEME_INTEL_ATOM_MDFLD_POWER
++
++config REMOVEME_INTEL_ATOM_MDFLD_POWER
++ bool "Medfield"
++
++config REMOVEME_INTEL_ATOM_CLV_POWER
++ bool "Clovertrail"
++
++config REMOVEME_INTEL_ATOM_MRFLD_POWER
++ bool "Merrifield"
++
++endchoice
++
++config INTEL_DEBUG_FEATURE
++ bool "Debug feature interface on Intel MID platform"
++ depends on X86_INTEL_MID
++ ---help---
++ Provides an interface to list the debug features
++ that are enabled on an Intel MID platform. The
++ enabling of the debug features depends on the mode
++ the device is in (e.g. manufacturing, production,
++ end user, etc...).
++
+ endif
+
+ config X86_INTEL_LPSS
+@@ -723,6 +759,16 @@ config APB_TIMER
+ as it is off-chip. APB timers are always running regardless of CPU
+ C states, they are used as per CPU clockevent device when possible.
+
++config ARCH_NR_GPIO
++ int
++ depends on ARCH_HAVE_CUSTOM_GPIO_H
++ default 512 if X86_INTEL_MID
++ default 0
++ help
++ Maximum number of GPIOs in the system.
++
++ If unsure, leave the default value.
++
+ # Mark as expert because too many people got it wrong.
+ # The code disables itself when not needed.
+ config DMI
+diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
+index c026cca..0a7e986 100644
+--- a/arch/x86/Kconfig.cpu
++++ b/arch/x86/Kconfig.cpu
+@@ -269,6 +269,15 @@ config MATOM
+ accordingly optimized code. Use a recent GCC with specific Atom
+ support in order to fully benefit from selecting this option.
+
++config MSLM
++ bool "Intel Silvermont (Atom)"
++ ---help---
++
++ Select this for the Intel Silvermont (Atom) platform. Intel Atom
++ CPUs have an in-order pipelining architecture and thus can benefit
++ from accordingly optimized code. Use a recent GCC with specific
++ Atom support in order to fully benefit from selecting this option.
++
+ config GENERIC_CPU
+ bool "Generic-x86-64"
+ depends on X86_64
+@@ -300,7 +309,7 @@ config X86_INTERNODE_CACHE_SHIFT
+ config X86_L1_CACHE_SHIFT
+ int
+ default "7" if MPENTIUM4 || MPSC
+- default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MATOM || MVIAC7 || X86_GENERIC || GENERIC_CPU
++ default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MATOM || MSLM || MVIAC7 || X86_GENERIC || GENERIC_CPU
+ default "4" if MELAN || M486 || MGEODEGX1
+ default "5" if MWINCHIP3D || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX
+
+@@ -335,7 +344,7 @@ config X86_INTEL_USERCOPY
+
+ config X86_USE_PPRO_CHECKSUM
+ def_bool y
+- depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MVIAC7 || MEFFICEON || MGEODE_LX || MCORE2 || MATOM
++ depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MVIAC7 || MEFFICEON || MGEODE_LX || MCORE2 || MATOM || MSLM
+
+ config X86_USE_3DNOW
+ def_bool y
+@@ -363,17 +372,17 @@ config X86_P6_NOP
+
+ config X86_TSC
+ def_bool y
+- depends on ((MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2 || MATOM) && !X86_NUMAQ) || X86_64
++ depends on ((MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2 || MATOM || MSLM) && !X86_NUMAQ) || X86_64
+
+ config X86_CMPXCHG64
+ def_bool y
+- depends on X86_PAE || X86_64 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MATOM
++ depends on X86_PAE || X86_64 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MATOM || MSLM
+
+ # this should be set for all -march=.. options where the compiler
+ # generates cmov.
+ config X86_CMOV
+ def_bool y
+- depends on (MK8 || MK7 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64 || MATOM || MGEODE_LX)
++ depends on (MK8 || MK7 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64 || MATOM || MSLM || MGEODE_LX)
+
+ config X86_MINIMUM_CPU_FAMILY
+ int
+diff --git a/arch/x86/Makefile b/arch/x86/Makefile
+index 5c47726..726f3b8 100644
+--- a/arch/x86/Makefile
++++ b/arch/x86/Makefile
+@@ -68,6 +68,8 @@ else
+ $(call cc-option,-march=core2,$(call cc-option,-mtune=generic))
+ cflags-$(CONFIG_MATOM) += $(call cc-option,-march=atom) \
+ $(call cc-option,-mtune=atom,$(call cc-option,-mtune=generic))
++ cflags-$(CONFIG_MSLM) += $(call cc-option,-march=slm) \
++ $(call cc-option,-mtune=slm,$(call cc-option,-mtune=generic))
+ cflags-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mtune=generic)
+ KBUILD_CFLAGS += $(cflags-y)
+
+diff --git a/arch/x86/Makefile_32.cpu b/arch/x86/Makefile_32.cpu
+index 6647ed4..a2eb6c6 100644
+--- a/arch/x86/Makefile_32.cpu
++++ b/arch/x86/Makefile_32.cpu
+@@ -34,6 +34,8 @@ cflags-$(CONFIG_MVIAC7) += -march=i686
+ cflags-$(CONFIG_MCORE2) += -march=i686 $(call tune,core2)
+ cflags-$(CONFIG_MATOM) += $(call cc-option,-march=atom,$(call cc-option,-march=core2,-march=i686)) \
+ $(call cc-option,-mtune=atom,$(call cc-option,-mtune=generic))
++cflags-$(CONFIG_MSLM) += $(call cc-option,-march=slm,$(call cc-option,-march=core2,-march=i686)) \
++ $(call cc-option,-mtune=slm,$(call cc-option,-mtune=generic))
+
+ # AMD Elan support
+ cflags-$(CONFIG_MELAN) += -march=i486
+diff --git a/arch/x86/configs/i386_edison_defconfig b/arch/x86/configs/i386_edison_defconfig
+new file mode 100644
+index 0000000..7f3e626
+--- /dev/null
++++ b/arch/x86/configs/i386_edison_defconfig
+@@ -0,0 +1,3768 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/x86 3.10.17 Kernel Configuration
++#
++# CONFIG_64BIT is not set
++CONFIG_X86_32=y
++CONFIG_X86=y
++CONFIG_INSTRUCTION_DECODER=y
++CONFIG_OUTPUT_FORMAT="elf32-i386"
++CONFIG_ARCH_DEFCONFIG="arch/x86/configs/i386_defconfig"
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_MMU=y
++CONFIG_NEED_SG_DMA_LENGTH=y
++CONFIG_GENERIC_ISA_DMA=y
++CONFIG_GENERIC_BUG=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_ARCH_MAY_HAVE_PC_FDC=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_ARCH_HAS_CPU_RELAX=y
++CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
++CONFIG_ARCH_HAS_CPU_AUTOPROBE=y
++CONFIG_HAVE_SETUP_PER_CPU_AREA=y
++CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
++CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=y
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++# CONFIG_ZONE_DMA32 is not set
++# CONFIG_AUDIT_ARCH is not set
++CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
++CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
++CONFIG_X86_32_SMP=y
++CONFIG_X86_HT=y
++CONFIG_X86_32_LAZY_GS=y
++CONFIG_ARCH_HWEIGHT_CFLAGS="-fcall-saved-ecx -fcall-saved-edx"
++CONFIG_ARCH_CPU_PROBE_RELEASE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++CONFIG_LOCALVERSION="-poky-edison"
++CONFIG_LOCALVERSION_AUTO=n
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_BZIP2=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_BZIP2 is not set
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_POSIX_MQUEUE_SYSCTL=y
++CONFIG_FHANDLE=y
++CONFIG_AUDIT=y
++CONFIG_AUDITSYSCALL=y
++CONFIG_AUDIT_WATCH=y
++CONFIG_AUDIT_TREE=y
++# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set
++CONFIG_HAVE_GENERIC_HARDIRQS=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_GENERIC_PENDING_IRQ=y
++CONFIG_IRQ_DOMAIN=y
++# CONFIG_IRQ_DOMAIN_DEBUG is not set
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_CLOCKSOURCE_WATCHDOG=y
++CONFIG_KTIME_SCALAR=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
++CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y
++CONFIG_GENERIC_CMOS_UPDATE=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ_COMMON=y
++# CONFIG_HZ_PERIODIC is not set
++CONFIG_NO_HZ_IDLE=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++
++#
++# CPU/Task time and stats accounting
++#
++# CONFIG_TICK_CPU_ACCOUNTING is not set
++CONFIG_IRQ_TIME_ACCOUNTING=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++CONFIG_TASKSTATS=y
++CONFIG_TASK_DELAY_ACCT=y
++CONFIG_TASK_XACCT=y
++CONFIG_TASK_IO_ACCOUNTING=y
++
++#
++# RCU Subsystem
++#
++CONFIG_TREE_PREEMPT_RCU=y
++CONFIG_PREEMPT_RCU=y
++CONFIG_RCU_STALL_COMMON=y
++CONFIG_RCU_FANOUT=32
++CONFIG_RCU_FANOUT_LEAF=16
++# CONFIG_RCU_FANOUT_EXACT is not set
++# CONFIG_RCU_FAST_NO_HZ is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_BOOST is not set
++# CONFIG_RCU_NOCB_CPU is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=18
++CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
++CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y
++CONFIG_ARCH_WANTS_PROT_NUMA_PROT_NONE=y
++CONFIG_CGROUPS=y
++# CONFIG_CGROUP_DEBUG is not set
++CONFIG_CGROUP_FREEZER=y
++CONFIG_CGROUP_DEVICE=y
++CONFIG_CPUSETS=y
++CONFIG_PROC_PID_CPUSET=y
++CONFIG_CGROUP_CPUACCT=y
++CONFIG_RESOURCE_COUNTERS=y
++# CONFIG_MEMCG is not set
++CONFIG_CGROUP_PERF=y
++CONFIG_CGROUP_SCHED=y
++CONFIG_FAIR_GROUP_SCHED=y
++# CONFIG_CFS_BANDWIDTH is not set
++CONFIG_RT_GROUP_SCHED=y
++CONFIG_BLK_CGROUP=y
++# CONFIG_DEBUG_BLK_CGROUP is not set
++# CONFIG_CHECKPOINT_RESTORE is not set
++CONFIG_NAMESPACES=y
++# CONFIG_UTS_NS is not set
++# CONFIG_IPC_NS is not set
++# CONFIG_USER_NS is not set
++# CONFIG_PID_NS is not set
++# CONFIG_NET_NS is not set
++CONFIG_UIDGID_CONVERTED=y
++# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set
++CONFIG_SCHED_AUTOGROUP=y
++CONFIG_SYSFS_DEPRECATED=y
++# CONFIG_SYSFS_DEPRECATED_V2 is not set
++CONFIG_RELAY=y
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_RD_GZIP=y
++# CONFIG_RD_BZIP2 is not set
++# CONFIG_RD_LZMA is not set
++# CONFIG_RD_XZ is not set
++# CONFIG_RD_LZO is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_SYSCTL_EXCEPTION_TRACE=y
++CONFIG_HOTPLUG=y
++CONFIG_HAVE_PCSPKR_PLATFORM=y
++CONFIG_EXPERT=y
++# CONFIG_UPTIME_LIMITED_KERNEL is not set
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_PCSPKR_PLATFORM=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_PCI_QUIRKS=y
++CONFIG_EMBEDDED=y
++CONFIG_HAVE_PERF_EVENTS=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_SLUB_DEBUG=y
++# CONFIG_COMPAT_BRK is not set
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++# CONFIG_SLOB is not set
++CONFIG_PROFILING=y
++CONFIG_TRACEPOINTS=y
++CONFIG_OPROFILE=y
++# CONFIG_OPROFILE_EVENT_MULTIPLEX is not set
++CONFIG_HAVE_OPROFILE=y
++CONFIG_OPROFILE_NMI_TIMER=y
++CONFIG_KPROBES=y
++# CONFIG_JUMP_LABEL is not set
++CONFIG_KPROBES_ON_FTRACE=y
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=y
++CONFIG_KRETPROBES=y
++CONFIG_HAVE_IOREMAP_PROT=y
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_OPTPROBES=y
++CONFIG_HAVE_KPROBES_ON_FTRACE=y
++CONFIG_HAVE_ARCH_TRACEHOOK=y
++CONFIG_HAVE_DMA_ATTRS=y
++CONFIG_HAVE_DMA_CONTIGUOUS=y
++CONFIG_USE_GENERIC_SMP_HELPERS=y
++CONFIG_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_HW_BREAKPOINT=y
++CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y
++CONFIG_HAVE_USER_RETURN_NOTIFIER=y
++CONFIG_HAVE_PERF_EVENTS_NMI=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
++CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
++CONFIG_HAVE_CMPXCHG_LOCAL=y
++CONFIG_HAVE_CMPXCHG_DOUBLE=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_GCOV_KERNEL is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++CONFIG_STOP_MACHINE=y
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_DEV_THROTTLING=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++CONFIG_OSF_PARTITION=y
++# CONFIG_AMIGA_PARTITION is not set
++# CONFIG_ATARI_PARTITION is not set
++# CONFIG_MAC_PARTITION is not set
++CONFIG_MSDOS_PARTITION=y
++CONFIG_BSD_DISKLABEL=y
++CONFIG_MINIX_SUBPARTITION=y
++CONFIG_SOLARIS_X86_PARTITION=y
++CONFIG_UNIXWARE_DISKLABEL=y
++# CONFIG_LDM_PARTITION is not set
++CONFIG_SGI_PARTITION=y
++# CONFIG_ULTRIX_PARTITION is not set
++CONFIG_SUN_PARTITION=y
++# CONFIG_KARMA_PARTITION is not set
++CONFIG_EFI_PARTITION=y
++# CONFIG_SYSV68_PARTITION is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++# CONFIG_IOSCHED_DEADLINE is not set
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_CFQ_GROUP_IOSCHED is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++CONFIG_ASN1=y
++CONFIG_UNINLINE_SPIN_UNLOCK=y
++CONFIG_FREEZER=y
++
++#
++# Processor type and features
++#
++CONFIG_ZONE_DMA=y
++CONFIG_SMP=y
++CONFIG_X86_MPPARSE=y
++# CONFIG_X86_BIGSMP is not set
++CONFIG_X86_EXTENDED_PLATFORM=y
++# CONFIG_X86_GOLDFISH is not set
++CONFIG_X86_WANT_INTEL_MID=y
++CONFIG_X86_INTEL_MID=y
++# CONFIG_X86_MDFLD is not set
++CONFIG_ATOM_SOC_POWER=y
++# CONFIG_REMOVEME_INTEL_ATOM_MDFLD_POWER is not set
++# CONFIG_REMOVEME_INTEL_ATOM_CLV_POWER is not set
++CONFIG_REMOVEME_INTEL_ATOM_MRFLD_POWER=y
++CONFIG_INTEL_DEBUG_FEATURE=y
++# CONFIG_X86_RDC321X is not set
++# CONFIG_X86_32_NON_STANDARD is not set
++CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y
++# CONFIG_X86_32_IRIS is not set
++# CONFIG_SCHED_OMIT_FRAME_POINTER is not set
++# CONFIG_HYPERVISOR_GUEST is not set
++CONFIG_NO_BOOTMEM=y
++# CONFIG_MEMTEST is not set
++# CONFIG_M486 is not set
++# CONFIG_M586 is not set
++# CONFIG_M586TSC is not set
++# CONFIG_M586MMX is not set
++# CONFIG_M686 is not set
++# CONFIG_MPENTIUMII is not set
++# CONFIG_MPENTIUMIII is not set
++# CONFIG_MPENTIUMM is not set
++# CONFIG_MPENTIUM4 is not set
++# CONFIG_MK6 is not set
++# CONFIG_MK7 is not set
++# CONFIG_MK8 is not set
++# CONFIG_MCRUSOE is not set
++# CONFIG_MEFFICEON is not set
++# CONFIG_MWINCHIPC6 is not set
++# CONFIG_MWINCHIP3D is not set
++# CONFIG_MELAN is not set
++# CONFIG_MGEODEGX1 is not set
++# CONFIG_MGEODE_LX is not set
++# CONFIG_MCYRIXIII is not set
++# CONFIG_MVIAC3_2 is not set
++# CONFIG_MVIAC7 is not set
++# CONFIG_MCORE2 is not set
++# CONFIG_MATOM is not set
++CONFIG_MSLM=y
++CONFIG_X86_GENERIC=y
++CONFIG_X86_INTERNODE_CACHE_SHIFT=6
++CONFIG_X86_L1_CACHE_SHIFT=6
++CONFIG_X86_INTEL_USERCOPY=y
++CONFIG_X86_USE_PPRO_CHECKSUM=y
++CONFIG_X86_TSC=y
++CONFIG_X86_CMPXCHG64=y
++CONFIG_X86_CMOV=y
++CONFIG_X86_MINIMUM_CPU_FAMILY=5
++CONFIG_X86_DEBUGCTLMSR=y
++# CONFIG_PROCESSOR_SELECT is not set
++CONFIG_CPU_SUP_INTEL=y
++CONFIG_CPU_SUP_CYRIX_32=y
++CONFIG_CPU_SUP_AMD=y
++CONFIG_CPU_SUP_CENTAUR=y
++CONFIG_CPU_SUP_TRANSMETA_32=y
++CONFIG_CPU_SUP_UMC_32=y
++# CONFIG_HPET_TIMER is not set
++# CONFIG_APB_TIMER is not set
++CONFIG_ARCH_NR_GPIO=512
++CONFIG_DMI=y
++CONFIG_NR_CPUS=2
++CONFIG_SCHED_SMT=y
++CONFIG_SCHED_MC=y
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_COUNT=y
++CONFIG_X86_LOCAL_APIC=y
++CONFIG_X86_IO_APIC=y
++# CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set
++CONFIG_X86_MCE=y
++CONFIG_X86_MCE_INTEL=y
++# CONFIG_X86_MCE_AMD is not set
++# CONFIG_X86_ANCIENT_MCE is not set
++CONFIG_X86_MCE_THRESHOLD=y
++# CONFIG_X86_MCE_INJECT is not set
++CONFIG_X86_THERMAL_VECTOR=y
++CONFIG_VM86=y
++# CONFIG_TOSHIBA is not set
++# CONFIG_I8K is not set
++CONFIG_X86_REBOOTFIXUPS=y
++# CONFIG_MICROCODE is not set
++CONFIG_X86_MSR=y
++CONFIG_X86_CPUID=y
++# CONFIG_NOHIGHMEM is not set
++# CONFIG_HIGHMEM4G is not set
++CONFIG_HIGHMEM64G=y
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++CONFIG_HIGHMEM=y
++CONFIG_X86_PAE=y
++CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
++CONFIG_ARCH_DMA_ADDR_T_64BIT=y
++CONFIG_ARCH_FLATMEM_ENABLE=y
++CONFIG_ARCH_SPARSEMEM_ENABLE=y
++CONFIG_ARCH_SELECT_MEMORY_MODEL=y
++CONFIG_ILLEGAL_POINTER_VALUE=0
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++# CONFIG_SPARSEMEM_MANUAL is not set
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_SPARSEMEM_STATIC=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
++CONFIG_ARCH_DISCARD_MEMBLOCK=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=999999
++# CONFIG_COMPACTION is not set
++CONFIG_PHYS_ADDR_T_64BIT=y
++CONFIG_ZONE_DMA_FLAG=1
++CONFIG_BOUNCE=y
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
++CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y
++# CONFIG_MEMORY_FAILURE is not set
++# CONFIG_TRANSPARENT_HUGEPAGE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_CLEANCACHE is not set
++# CONFIG_HIGHPTE is not set
++CONFIG_X86_CHECK_BIOS_CORRUPTION=y
++# CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK is not set
++CONFIG_X86_RESERVE_LOW=64
++# CONFIG_MATH_EMULATION is not set
++CONFIG_MTRR=y
++CONFIG_MTRR_SANITIZER=y
++CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=1
++CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=1
++CONFIG_X86_PAT=y
++CONFIG_ARCH_USES_PG_UNCACHED=y
++# CONFIG_ARCH_RANDOM is not set
++CONFIG_X86_SMAP=y
++# CONFIG_SECCOMP is not set
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_HZ_100=y
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=100
++CONFIG_SCHED_HRTICK=y
++CONFIG_KEXEC=y
++# CONFIG_CRASH_DUMP is not set
++CONFIG_PHYSICAL_START=0x1200000
++# CONFIG_RELOCATABLE is not set
++CONFIG_PHYSICAL_ALIGN=0x100000
++CONFIG_HOTPLUG_CPU=y
++# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set
++# CONFIG_DEBUG_HOTPLUG_CPU0 is not set
++# CONFIG_COMPAT_VDSO is not set
++# CONFIG_CMDLINE_BOOL is not set
++CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
++
++#
++# Power management and ACPI options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_PM_SLEEP=y
++CONFIG_PM_SLEEP_SMP=y
++# CONFIG_PM_AUTOSLEEP is not set
++CONFIG_PM_WAKELOCKS=y
++CONFIG_PM_WAKELOCKS_LIMIT=100
++CONFIG_PM_WAKELOCKS_GC=y
++CONFIG_PM_RUNTIME=y
++CONFIG_PM=y
++CONFIG_PM_DEBUG=y
++CONFIG_PM_ADVANCED_DEBUG=y
++# CONFIG_PM_TEST_SUSPEND is not set
++CONFIG_PM_SLEEP_DEBUG=y
++# CONFIG_PM_TRACE_RTC is not set
++# CONFIG_ACPI is not set
++CONFIG_SFI=y
++# CONFIG_APM is not set
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_TABLE=y
++CONFIG_CPU_FREQ_GOV_COMMON=y
++CONFIG_CPU_FREQ_STAT=y
++CONFIG_CPU_FREQ_STAT_DETAILS=y
++CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++
++#
++# x86 CPU frequency scaling drivers
++#
++# CONFIG_X86_INTEL_PSTATE is not set
++CONFIG_X86_SFI_CPUFREQ=y
++# CONFIG_X86_POWERNOW_K6 is not set
++# CONFIG_X86_POWERNOW_K7 is not set
++# CONFIG_X86_GX_SUSPMOD is not set
++# CONFIG_X86_SPEEDSTEP_CENTRINO is not set
++# CONFIG_X86_SPEEDSTEP_ICH is not set
++# CONFIG_X86_SPEEDSTEP_SMI is not set
++# CONFIG_X86_P4_CLOCKMOD is not set
++# CONFIG_X86_CPUFREQ_NFORCE2 is not set
++# CONFIG_X86_LONGRUN is not set
++
++#
++# shared options
++#
++# CONFIG_X86_SPEEDSTEP_LIB is not set
++CONFIG_CPU_IDLE=y
++# CONFIG_CPU_IDLE_MULTIPLE_DRIVERS is not set
++CONFIG_CPU_IDLE_GOV_LADDER=y
++CONFIG_CPU_IDLE_GOV_MENU=y
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++CONFIG_INTEL_IDLE=y
++
++#
++# Bus options (PCI etc.)
++#
++CONFIG_PCI=y
++# CONFIG_PCI_GOBIOS is not set
++# CONFIG_PCI_GOMMCONFIG is not set
++# CONFIG_PCI_GODIRECT is not set
++CONFIG_PCI_GOANY=y
++CONFIG_PCI_BIOS=y
++CONFIG_PCI_DIRECT=y
++CONFIG_PCI_MMCONFIG=y
++CONFIG_PCI_DOMAINS=y
++# CONFIG_PCI_CNB20LE_QUIRK is not set
++CONFIG_PCIEPORTBUS=y
++# CONFIG_PCIEAER is not set
++CONFIG_PCIEASPM=y
++# CONFIG_PCIEASPM_DEBUG is not set
++# CONFIG_PCIEASPM_DEFAULT is not set
++# CONFIG_PCIEASPM_POWERSAVE is not set
++CONFIG_PCIEASPM_PERFORMANCE=y
++CONFIG_PCIE_PME=y
++CONFIG_ARCH_SUPPORTS_MSI=y
++CONFIG_PCI_MSI=y
++# CONFIG_PCI_DEBUG is not set
++# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set
++# CONFIG_PCI_STUB is not set
++CONFIG_HT_IRQ=y
++# CONFIG_PCI_IOV is not set
++# CONFIG_PCI_PRI is not set
++# CONFIG_PCI_PASID is not set
++CONFIG_PCI_LABEL=y
++CONFIG_ISA_DMA_API=y
++# CONFIG_ISA is not set
++# CONFIG_SCx200 is not set
++# CONFIG_ALIX is not set
++# CONFIG_NET5501 is not set
++# CONFIG_GEOS is not set
++CONFIG_AMD_NB=y
++# CONFIG_PCCARD is not set
++# CONFIG_HOTPLUG_PCI is not set
++# CONFIG_RAPIDIO is not set
++
++#
++# Executable file formats / Emulations
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
++CONFIG_BINFMT_SCRIPT=y
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++CONFIG_BINFMT_MISC=y
++CONFIG_COREDUMP=y
++CONFIG_HAVE_ATOMIC_IOMAP=y
++CONFIG_HAVE_TEXT_POKE_SMP=y
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++# CONFIG_PACKET_DIAG is not set
++CONFIG_UNIX=y
++# CONFIG_UNIX_DIAG is not set
++CONFIG_XFRM=y
++CONFIG_XFRM_ALGO=y
++CONFIG_XFRM_USER=y
++CONFIG_XFRM_SUB_POLICY=y
++CONFIG_XFRM_MIGRATE=y
++CONFIG_XFRM_STATISTICS=y
++CONFIG_NET_KEY=y
++CONFIG_NET_KEY_MIGRATE=y
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++CONFIG_IP_ADVANCED_ROUTER=y
++# CONFIG_IP_FIB_TRIE_STATS is not set
++CONFIG_IP_MULTIPLE_TABLES=y
++# CONFIG_IP_ROUTE_MULTIPATH is not set
++# CONFIG_IP_ROUTE_VERBOSE is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE_DEMUX is not set
++CONFIG_NET_IP_TUNNEL=y
++# CONFIG_IP_MROUTE is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_IPVTI is not set
++# CONFIG_INET_AH is not set
++CONFIG_INET_ESP=y
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++CONFIG_INET_TUNNEL=y
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++CONFIG_TCP_MD5SIG=y
++CONFIG_IPV6=y
++CONFIG_IPV6_PRIVACY=y
++CONFIG_IPV6_ROUTER_PREF=y
++CONFIG_IPV6_ROUTE_INFO=y
++CONFIG_IPV6_OPTIMISTIC_DAD=y
++# CONFIG_INET6_AH is not set
++# CONFIG_INET6_ESP is not set
++# CONFIG_INET6_IPCOMP is not set
++# CONFIG_IPV6_MIP6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++CONFIG_INET6_XFRM_MODE_TRANSPORT=y
++CONFIG_INET6_XFRM_MODE_TUNNEL=y
++CONFIG_INET6_XFRM_MODE_BEET=y
++# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
++CONFIG_IPV6_SIT=y
++# CONFIG_IPV6_SIT_6RD is not set
++CONFIG_IPV6_NDISC_NODETYPE=y
++# CONFIG_IPV6_TUNNEL is not set
++# CONFIG_IPV6_GRE is not set
++CONFIG_IPV6_MULTIPLE_TABLES=y
++# CONFIG_IPV6_SUBTREES is not set
++# CONFIG_IPV6_MROUTE is not set
++# CONFIG_NETLABEL is not set
++CONFIG_NETWORK_SECMARK=y
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++CONFIG_NETFILTER=y
++# CONFIG_NETFILTER_DEBUG is not set
++CONFIG_NETFILTER_ADVANCED=y
++CONFIG_BRIDGE_NETFILTER=y
++
++#
++# Core Netfilter Configuration
++#
++CONFIG_NETFILTER_NETLINK=y
++# CONFIG_NETFILTER_NETLINK_ACCT is not set
++# CONFIG_NETFILTER_NETLINK_QUEUE is not set
++CONFIG_NETFILTER_NETLINK_LOG=y
++CONFIG_NF_CONNTRACK=y
++CONFIG_NF_CONNTRACK_MARK=y
++# CONFIG_NF_CONNTRACK_SECMARK is not set
++CONFIG_NF_CONNTRACK_PROCFS=y
++CONFIG_NF_CONNTRACK_EVENTS=y
++# CONFIG_NF_CONNTRACK_TIMEOUT is not set
++# CONFIG_NF_CONNTRACK_TIMESTAMP is not set
++# CONFIG_NF_CT_PROTO_DCCP is not set
++# CONFIG_NF_CT_PROTO_SCTP is not set
++# CONFIG_NF_CT_PROTO_UDPLITE is not set
++# CONFIG_NF_CONNTRACK_AMANDA is not set
++# CONFIG_NF_CONNTRACK_FTP is not set
++# CONFIG_NF_CONNTRACK_H323 is not set
++# CONFIG_NF_CONNTRACK_IRC is not set
++# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
++# CONFIG_NF_CONNTRACK_SNMP is not set
++# CONFIG_NF_CONNTRACK_PPTP is not set
++# CONFIG_NF_CONNTRACK_SANE is not set
++# CONFIG_NF_CONNTRACK_SIP is not set
++# CONFIG_NF_CONNTRACK_TFTP is not set
++# CONFIG_NF_CT_NETLINK is not set
++# CONFIG_NF_CT_NETLINK_TIMEOUT is not set
++CONFIG_NF_NAT=y
++CONFIG_NF_NAT_NEEDED=y
++# CONFIG_NF_NAT_AMANDA is not set
++# CONFIG_NF_NAT_FTP is not set
++# CONFIG_NF_NAT_IRC is not set
++# CONFIG_NF_NAT_SIP is not set
++# CONFIG_NF_NAT_TFTP is not set
++CONFIG_NETFILTER_TPROXY=y
++CONFIG_NETFILTER_XTABLES=y
++
++#
++# Xtables combined modules
++#
++CONFIG_NETFILTER_XT_MARK=y
++CONFIG_NETFILTER_XT_CONNMARK=y
++
++#
++# Xtables targets
++#
++# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set
++# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set
++# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
++CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
++# CONFIG_NETFILTER_XT_TARGET_CT is not set
++# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
++CONFIG_NETFILTER_XT_TARGET_HL=y
++# CONFIG_NETFILTER_XT_TARGET_HMARK is not set
++# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set
++# CONFIG_NETFILTER_XT_TARGET_LED is not set
++# CONFIG_NETFILTER_XT_TARGET_LOG is not set
++# CONFIG_NETFILTER_XT_TARGET_MARK is not set
++CONFIG_NETFILTER_XT_TARGET_NETMAP=y
++# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
++# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
++# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
++# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
++CONFIG_NETFILTER_XT_TARGET_REDIRECT=y
++# CONFIG_NETFILTER_XT_TARGET_TEE is not set
++# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set
++# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
++# CONFIG_NETFILTER_XT_TARGET_SECMARK is not set
++# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
++# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
++
++#
++# Xtables matches
++#
++# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set
++# CONFIG_NETFILTER_XT_MATCH_BPF is not set
++CONFIG_NETFILTER_XT_MATCH_CLUSTER=y
++# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
++# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
++# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set
++# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
++# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set
++# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
++# CONFIG_NETFILTER_XT_MATCH_CPU is not set
++# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
++# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set
++# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
++# CONFIG_NETFILTER_XT_MATCH_ECN is not set
++# CONFIG_NETFILTER_XT_MATCH_ESP is not set
++# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
++CONFIG_NETFILTER_XT_MATCH_HELPER=y
++CONFIG_NETFILTER_XT_MATCH_HL=y
++# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
++# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
++# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
++# CONFIG_NETFILTER_XT_MATCH_MAC is not set
++# CONFIG_NETFILTER_XT_MATCH_MARK is not set
++CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
++# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set
++# CONFIG_NETFILTER_XT_MATCH_OSF is not set
++# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
++# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
++# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
++# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
++CONFIG_NETFILTER_XT_MATCH_QUOTA=y
++# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
++# CONFIG_NETFILTER_XT_MATCH_REALM is not set
++# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
++# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
++CONFIG_NETFILTER_XT_MATCH_SOCKET=y
++CONFIG_NETFILTER_XT_MATCH_STATE=y
++# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
++# CONFIG_NETFILTER_XT_MATCH_STRING is not set
++# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
++# CONFIG_NETFILTER_XT_MATCH_TIME is not set
++# CONFIG_NETFILTER_XT_MATCH_U32 is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++CONFIG_NF_DEFRAG_IPV4=y
++CONFIG_NF_CONNTRACK_IPV4=y
++CONFIG_NF_CONNTRACK_PROC_COMPAT=y
++CONFIG_IP_NF_IPTABLES=y
++# CONFIG_IP_NF_MATCH_AH is not set
++# CONFIG_IP_NF_MATCH_ECN is not set
++# CONFIG_IP_NF_MATCH_RPFILTER is not set
++# CONFIG_IP_NF_MATCH_TTL is not set
++CONFIG_IP_NF_FILTER=y
++CONFIG_IP_NF_TARGET_REJECT=y
++# CONFIG_IP_NF_TARGET_ULOG is not set
++CONFIG_NF_NAT_IPV4=y
++CONFIG_IP_NF_TARGET_MASQUERADE=y
++CONFIG_IP_NF_TARGET_NETMAP=y
++CONFIG_IP_NF_TARGET_REDIRECT=y
++# CONFIG_NF_NAT_PPTP is not set
++# CONFIG_NF_NAT_H323 is not set
++CONFIG_IP_NF_MANGLE=y
++# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
++# CONFIG_IP_NF_TARGET_ECN is not set
++# CONFIG_IP_NF_TARGET_TTL is not set
++CONFIG_IP_NF_RAW=y
++# CONFIG_IP_NF_SECURITY is not set
++# CONFIG_IP_NF_ARPTABLES is not set
++
++#
++# IPv6: Netfilter Configuration
++#
++CONFIG_NF_DEFRAG_IPV6=y
++# CONFIG_NF_CONNTRACK_IPV6 is not set
++CONFIG_IP6_NF_IPTABLES=y
++CONFIG_IP6_NF_MATCH_AH=y
++CONFIG_IP6_NF_MATCH_EUI64=y
++CONFIG_IP6_NF_MATCH_FRAG=y
++CONFIG_IP6_NF_MATCH_OPTS=y
++CONFIG_IP6_NF_MATCH_HL=y
++CONFIG_IP6_NF_MATCH_IPV6HEADER=y
++CONFIG_IP6_NF_MATCH_MH=y
++# CONFIG_IP6_NF_MATCH_RPFILTER is not set
++CONFIG_IP6_NF_MATCH_RT=y
++CONFIG_IP6_NF_TARGET_HL=y
++CONFIG_IP6_NF_FILTER=y
++CONFIG_IP6_NF_TARGET_REJECT=y
++CONFIG_IP6_NF_MANGLE=y
++CONFIG_IP6_NF_RAW=y
++# CONFIG_IP6_NF_SECURITY is not set
++# CONFIG_BRIDGE_NF_EBTABLES is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++CONFIG_L2TP=y
++# CONFIG_L2TP_DEBUGFS is not set
++# CONFIG_L2TP_V3 is not set
++CONFIG_STP=y
++CONFIG_BRIDGE=y
++CONFIG_BRIDGE_IGMP_SNOOPING=y
++CONFIG_HAVE_NET_DSA=y
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++CONFIG_LLC=y
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++CONFIG_DNS_RESOLVER=y
++# CONFIG_BATMAN_ADV is not set
++# CONFIG_OPENVSWITCH is not set
++# CONFIG_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++CONFIG_RPS=y
++CONFIG_RFS_ACCEL=y
++CONFIG_XPS=y
++# CONFIG_NETPRIO_CGROUP is not set
++CONFIG_BQL=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_NET_TCPPROBE is not set
++# CONFIG_NET_DROP_MONITOR is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++CONFIG_BT=y
++CONFIG_BT_RFCOMM=y
++CONFIG_BT_RFCOMM_TTY=y
++CONFIG_BT_BNEP=y
++CONFIG_BT_BNEP_MC_FILTER=y
++CONFIG_BT_BNEP_PROTO_FILTER=y
++CONFIG_BT_HIDP=y
++
++#
++# Bluetooth device drivers
++#
++# CONFIG_BT_HCIBTUSB is not set
++# CONFIG_BT_HCIBTSDIO is not set
++CONFIG_BT_HCIUART=y
++CONFIG_BT_HCIUART_H4=y
++# CONFIG_BT_HCIUART_BCSP is not set
++# CONFIG_BT_HCIUART_ATH3K is not set
++# CONFIG_BT_HCIUART_LL is not set
++# CONFIG_BT_HCIUART_3WIRE is not set
++# CONFIG_BT_HCIBCM203X is not set
++# CONFIG_BT_HCIBPA10X is not set
++# CONFIG_BT_HCIBFUSB is not set
++# CONFIG_BT_HCIVHCI is not set
++# CONFIG_BT_MRVL is not set
++# CONFIG_AF_RXRPC is not set
++CONFIG_FIB_RULES=y
++CONFIG_WIRELESS=y
++CONFIG_WEXT_CORE=y
++CONFIG_WEXT_PROC=y
++CONFIG_CFG80211=y
++# CONFIG_NL80211_TESTMODE is not set
++CONFIG_CFG80211_DEVELOPER_WARNINGS=y
++# CONFIG_CFG80211_REG_DEBUG is not set
++# CONFIG_CFG80211_CERTIFICATION_ONUS is not set
++CONFIG_CFG80211_DEFAULT_PS=y
++# CONFIG_CFG80211_DEBUGFS is not set
++# CONFIG_CFG80211_INTERNAL_REGDB is not set
++CONFIG_CFG80211_WEXT=y
++# CONFIG_LIB80211 is not set
++CONFIG_MAC80211=m
++CONFIG_MAC80211_HAS_RC=y
++# CONFIG_MAC80211_RC_PID is not set
++CONFIG_MAC80211_RC_MINSTREL=y
++CONFIG_MAC80211_RC_MINSTREL_HT=y
++CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
++CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
++# CONFIG_MAC80211_MESH is not set
++# CONFIG_MAC80211_LEDS is not set
++# CONFIG_MAC80211_DEBUGFS is not set
++# CONFIG_MAC80211_MESSAGE_TRACING is not set
++# CONFIG_MAC80211_DEBUG_MENU is not set
++# CONFIG_WIMAX is not set
++CONFIG_RFKILL=y
++CONFIG_RFKILL_LEDS=y
++CONFIG_RFKILL_INPUT=y
++# CONFIG_RFKILL_REGULATOR is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++# CONFIG_NFC is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH=""
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++CONFIG_FW_LOADER_USER_HELPER=y
++# CONFIG_DEBUG_DRIVER is not set
++CONFIG_DEBUG_DEVRES=y
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_GENERIC_CPU_DEVICES is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_I2C=y
++CONFIG_REGMAP_SPI=y
++CONFIG_REGMAP_IRQ=y
++CONFIG_DMA_SHARED_BUFFER=y
++# CONFIG_CMA is not set
++
++#
++# Bus devices
++#
++CONFIG_CONNECTOR=y
++CONFIG_PROC_EVENTS=y
++# CONFIG_MTD is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_FD is not set
++# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_NVME is not set
++# CONFIG_BLK_DEV_SX8 is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_VIRTIO_BLK is not set
++# CONFIG_BLK_DEV_HD is not set
++# CONFIG_BLK_DEV_RBD is not set
++# CONFIG_BLK_DEV_RSXX is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_DUMMY_IRQ is not set
++# CONFIG_IBM_ASM is not set
++# CONFIG_PHANTOM is not set
++CONFIG_INTEL_MID_PTI=y
++CONFIG_INTEL_PTI_STM=y
++# CONFIG_SGI_IOC4 is not set
++# CONFIG_TIFM_CORE is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ATMEL_SSC is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_HP_ILO is not set
++# CONFIG_APDS9802ALS is not set
++# CONFIG_ISL29003 is not set
++# CONFIG_ISL29020 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_SENSORS_BH1780 is not set
++# CONFIG_SENSORS_BH1770 is not set
++# CONFIG_SENSORS_APDS990X is not set
++# CONFIG_HMC6352 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_TI_DAC7512 is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_PCH_PHUB is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++CONFIG_EMMC_IPANIC=y
++CONFIG_EMMC_IPANIC_PLABEL="panic"
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++# CONFIG_CB710_CORE is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# CONFIG_TI_ST is not set
++# CONFIG_SENSORS_LIS3_SPI is not set
++# CONFIG_SENSORS_LIS3_I2C is not set
++
++#
++# Altera FPGA firmware download module
++#
++# CONFIG_ALTERA_STAPL is not set
++# CONFIG_VMWARE_VMCI is not set
++CONFIG_BCM_BT_LPM=m
++CONFIG_HAVE_IDE=y
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=y
++CONFIG_BLK_DEV_SR_VENDOR=y
++CONFIG_CHR_DEV_SG=y
++# CONFIG_CHR_DEV_SCH is not set
++CONFIG_SCSI_MULTI_LUN=y
++CONFIG_SCSI_CONSTANTS=y
++# CONFIG_SCSI_LOGGING is not set
++# CONFIG_SCSI_SCAN_ASYNC is not set
++
++#
++# SCSI Transports
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++# CONFIG_SCSI_LOWLEVEL is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++# CONFIG_ATA is not set
++# CONFIG_MD is not set
++# CONFIG_TARGET_CORE is not set
++# CONFIG_FUSION is not set
++
++#
++# IEEE 1394 (FireWire) support
++#
++# CONFIG_FIREWIRE is not set
++# CONFIG_FIREWIRE_NOSY is not set
++# CONFIG_I2O is not set
++# CONFIG_MACINTOSH_DRIVERS is not set
++CONFIG_NETDEVICES=y
++CONFIG_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_NET_FC is not set
++CONFIG_MII=y
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++CONFIG_NETCONSOLE=y
++# CONFIG_NETCONSOLE_DYNAMIC is not set
++CONFIG_NETPOLL=y
++# CONFIG_NETPOLL_TRAP is not set
++CONFIG_NET_POLL_CONTROLLER=y
++CONFIG_TUN=y
++# CONFIG_VETH is not set
++# CONFIG_VIRTIO_NET is not set
++# CONFIG_ARCNET is not set
++
++#
++# CAIF transport drivers
++#
++# CONFIG_VHOST_NET is not set
++
++#
++# Distributed Switch Architecture drivers
++#
++# CONFIG_NET_DSA_MV88E6XXX is not set
++# CONFIG_NET_DSA_MV88E6060 is not set
++# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set
++# CONFIG_NET_DSA_MV88E6131 is not set
++# CONFIG_NET_DSA_MV88E6123_61_65 is not set
++# CONFIG_ETHERNET is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_MARVELL_PHY is not set
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM87XX_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_RTL8152 is not set
++CONFIG_USB_USBNET=y
++CONFIG_USB_NET_AX8817X=y
++# CONFIG_USB_NET_AX88179_178A is not set
++# CONFIG_USB_NET_CDCETHER is not set
++# CONFIG_USB_NET_CDC_EEM is not set
++CONFIG_USB_NET_CDC_NCM=y
++# CONFIG_USB_NET_CDC_MBIM is not set
++# CONFIG_USB_NET_DM9601 is not set
++# CONFIG_USB_NET_SMSC75XX is not set
++# CONFIG_USB_NET_SMSC95XX is not set
++# CONFIG_USB_NET_GL620A is not set
++# CONFIG_USB_NET_NET1080 is not set
++# CONFIG_USB_NET_PLUSB is not set
++# CONFIG_USB_NET_MCS7830 is not set
++# CONFIG_USB_NET_RNDIS_HOST is not set
++CONFIG_USB_NET_CDC_SUBSET=y
++# CONFIG_USB_ALI_M5632 is not set
++# CONFIG_USB_AN2720 is not set
++# CONFIG_USB_BELKIN is not set
++# CONFIG_USB_ARMLINUX is not set
++# CONFIG_USB_EPSON2888 is not set
++# CONFIG_USB_KC2190 is not set
++# CONFIG_USB_NET_ZAURUS is not set
++# CONFIG_USB_NET_CX82310_ETH is not set
++# CONFIG_USB_NET_KALMIA is not set
++# CONFIG_USB_NET_QMI_WWAN is not set
++# CONFIG_USB_HSO is not set
++# CONFIG_USB_NET_INT51X1 is not set
++# CONFIG_USB_IPHETH is not set
++# CONFIG_USB_SIERRA_NET is not set
++CONFIG_WLAN=y
++# CONFIG_LIBERTAS_THINFIRM is not set
++# CONFIG_AIRO is not set
++# CONFIG_ATMEL is not set
++# CONFIG_AT76C50X_USB is not set
++# CONFIG_PRISM54 is not set
++# CONFIG_USB_ZD1201 is not set
++# CONFIG_USB_NET_RNDIS_WLAN is not set
++# CONFIG_RTL8180 is not set
++# CONFIG_RTL8187 is not set
++# CONFIG_ADM8211 is not set
++# CONFIG_MAC80211_HWSIM is not set
++# CONFIG_MWL8K is not set
++CONFIG_WIFI_CONTROL_FUNC=y
++CONFIG_WIFI_PLATFORM_DATA=y
++# CONFIG_ATH_CARDS is not set
++# CONFIG_B43 is not set
++# CONFIG_B43LEGACY is not set
++# CONFIG_BRCMFMAC is not set
++# CONFIG_HOSTAP is not set
++# CONFIG_IPW2100 is not set
++# CONFIG_IPW2200 is not set
++# CONFIG_IWLWIFI is not set
++# CONFIG_IWL4965 is not set
++# CONFIG_IWL3945 is not set
++# CONFIG_LIBERTAS is not set
++# CONFIG_HERMES is not set
++# CONFIG_P54_COMMON is not set
++# CONFIG_RT2X00 is not set
++# CONFIG_RTLWIFI is not set
++# CONFIG_WL_TI is not set
++# CONFIG_ZD1211RW is not set
++# CONFIG_MWIFIEX is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_VMXNET3 is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++CONFIG_INPUT_POLLDEV=y
++CONFIG_INPUT_SPARSEKMAP=y
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++# CONFIG_KEYBOARD_ADP5588 is not set
++# CONFIG_KEYBOARD_ADP5589 is not set
++# CONFIG_KEYBOARD_ATKBD is not set
++# CONFIG_KEYBOARD_QT1070 is not set
++# CONFIG_KEYBOARD_QT2160 is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++CONFIG_KEYBOARD_GPIO=y
++CONFIG_KEYBOARD_GPIO_POLLED=y
++# CONFIG_KEYBOARD_TCA6416 is not set
++# CONFIG_KEYBOARD_TCA8418 is not set
++# CONFIG_KEYBOARD_MATRIX is not set
++# CONFIG_KEYBOARD_LM8323 is not set
++# CONFIG_KEYBOARD_LM8333 is not set
++# CONFIG_KEYBOARD_MAX7359 is not set
++# CONFIG_KEYBOARD_MCS is not set
++# CONFIG_KEYBOARD_MPR121 is not set
++# CONFIG_KEYBOARD_NEWTON is not set
++# CONFIG_KEYBOARD_OPENCORES is not set
++# CONFIG_KEYBOARD_STOWAWAY is not set
++# CONFIG_KEYBOARD_SUNKBD is not set
++# CONFIG_KEYBOARD_XTKBD is not set
++CONFIG_INPUT_MOUSE=y
++# CONFIG_MOUSE_PS2 is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_CYAPA is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_GPIO is not set
++# CONFIG_MOUSE_SYNAPTICS_I2C is not set
++# CONFIG_MOUSE_SYNAPTICS_USB is not set
++CONFIG_INPUT_JOYSTICK=y
++# CONFIG_JOYSTICK_ANALOG is not set
++# CONFIG_JOYSTICK_A3D is not set
++# CONFIG_JOYSTICK_ADI is not set
++# CONFIG_JOYSTICK_COBRA is not set
++# CONFIG_JOYSTICK_GF2K is not set
++# CONFIG_JOYSTICK_GRIP is not set
++# CONFIG_JOYSTICK_GRIP_MP is not set
++# CONFIG_JOYSTICK_GUILLEMOT is not set
++# CONFIG_JOYSTICK_INTERACT is not set
++# CONFIG_JOYSTICK_SIDEWINDER is not set
++# CONFIG_JOYSTICK_TMDC is not set
++# CONFIG_JOYSTICK_IFORCE is not set
++# CONFIG_JOYSTICK_WARRIOR is not set
++# CONFIG_JOYSTICK_MAGELLAN is not set
++# CONFIG_JOYSTICK_SPACEORB is not set
++# CONFIG_JOYSTICK_SPACEBALL is not set
++# CONFIG_JOYSTICK_STINGER is not set
++# CONFIG_JOYSTICK_TWIDJOY is not set
++# CONFIG_JOYSTICK_ZHENHUA is not set
++# CONFIG_JOYSTICK_AS5011 is not set
++# CONFIG_JOYSTICK_JOYDUMP is not set
++# CONFIG_JOYSTICK_XPAD is not set
++CONFIG_INPUT_TABLET=y
++# CONFIG_TABLET_USB_ACECAD is not set
++# CONFIG_TABLET_USB_AIPTEK is not set
++# CONFIG_TABLET_USB_GTCO is not set
++# CONFIG_TABLET_USB_HANWANG is not set
++# CONFIG_TABLET_USB_KBTAB is not set
++# CONFIG_TABLET_USB_WACOM is not set
++CONFIG_INPUT_TOUCHSCREEN=y
++# CONFIG_TOUCHSCREEN_ADS7846 is not set
++# CONFIG_TOUCHSCREEN_AD7877 is not set
++# CONFIG_TOUCHSCREEN_AD7879 is not set
++# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set
++# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set
++# CONFIG_TOUCHSCREEN_BU21013 is not set
++# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set
++# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set
++# CONFIG_TOUCHSCREEN_DYNAPRO is not set
++# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
++# CONFIG_TOUCHSCREEN_EETI is not set
++# CONFIG_TOUCHSCREEN_FUJITSU is not set
++# CONFIG_TOUCHSCREEN_ILI210X is not set
++# CONFIG_TOUCHSCREEN_GUNZE is not set
++# CONFIG_TOUCHSCREEN_ELO is not set
++# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
++# CONFIG_TOUCHSCREEN_WACOM_I2C is not set
++# CONFIG_TOUCHSCREEN_MAX11801 is not set
++# CONFIG_TOUCHSCREEN_MCS5000 is not set
++# CONFIG_TOUCHSCREEN_MMS114 is not set
++# CONFIG_TOUCHSCREEN_MTOUCH is not set
++# CONFIG_TOUCHSCREEN_INEXIO is not set
++# CONFIG_TOUCHSCREEN_INTEL_MID is not set
++# CONFIG_TOUCHSCREEN_MK712 is not set
++# CONFIG_TOUCHSCREEN_PENMOUNT is not set
++# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set
++# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
++# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
++# CONFIG_TOUCHSCREEN_PIXCIR is not set
++# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
++# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
++# CONFIG_TOUCHSCREEN_TSC_SERIO is not set
++# CONFIG_TOUCHSCREEN_TSC2005 is not set
++# CONFIG_TOUCHSCREEN_TSC2007 is not set
++# CONFIG_TOUCHSCREEN_ST1232 is not set
++# CONFIG_TOUCHSCREEN_TPS6507X is not set
++CONFIG_INPUT_MISC=y
++# CONFIG_INPUT_AD714X is not set
++# CONFIG_INPUT_BMA150 is not set
++# CONFIG_INPUT_PCSPKR is not set
++# CONFIG_INPUT_MMA8450 is not set
++# CONFIG_INPUT_MPU3050 is not set
++# CONFIG_INPUT_APANEL is not set
++# CONFIG_INPUT_GP2A is not set
++# CONFIG_INPUT_GPIO_TILT_POLLED is not set
++# CONFIG_INPUT_WISTRON_BTNS is not set
++# CONFIG_INPUT_ATI_REMOTE2 is not set
++# CONFIG_INPUT_KEYSPAN_REMOTE is not set
++# CONFIG_INPUT_KXTJ9 is not set
++# CONFIG_INPUT_POWERMATE is not set
++# CONFIG_INPUT_YEALINK is not set
++# CONFIG_INPUT_CM109 is not set
++CONFIG_INPUT_UINPUT=y
++# CONFIG_INPUT_PCF8574 is not set
++# CONFIG_INPUT_PWM_BEEPER is not set
++# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
++# CONFIG_INPUT_ADXL34X is not set
++# CONFIG_INPUT_IMS_PCU is not set
++# CONFIG_INPUT_CMA3000 is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++# CONFIG_SERIO_I8042 is not set
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_CT82C710 is not set
++# CONFIG_SERIO_PCIPS2 is not set
++# CONFIG_SERIO_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_SERIO_ARC_PS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++CONFIG_VT_HW_CONSOLE_BINDING=y
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++CONFIG_SERIAL_NONSTANDARD=y
++# CONFIG_ROCKETPORT is not set
++# CONFIG_CYCLADES is not set
++# CONFIG_MOXA_INTELLIO is not set
++# CONFIG_MOXA_SMARTIO is not set
++# CONFIG_SYNCLINK is not set
++# CONFIG_SYNCLINKMP is not set
++# CONFIG_SYNCLINK_GT is not set
++# CONFIG_NOZOMI is not set
++# CONFIG_ISI is not set
++# CONFIG_N_HDLC is not set
++CONFIG_N_GSM=y
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVKMEM=y
++# CONFIG_STALDRV is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
++CONFIG_FIX_EARLYCON_MEM=y
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_MAX3100 is not set
++# CONFIG_SERIAL_MAX310X is not set
++CONFIG_SERIAL_MRST_MAX3110=y
++CONFIG_SERIAL_MFD_HSU=y
++CONFIG_SERIAL_MFD_HSU_CONSOLE=y
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_JSM is not set
++# CONFIG_SERIAL_SCCNXP is not set
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_PCH_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_RP2 is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_VIRTIO_CONSOLE is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++CONFIG_HW_RANDOM_INTEL=y
++CONFIG_HW_RANDOM_AMD=y
++CONFIG_HW_RANDOM_GEODE=y
++CONFIG_HW_RANDOM_VIA=y
++# CONFIG_HW_RANDOM_VIRTIO is not set
++CONFIG_NVRAM=y
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++# CONFIG_SONYPI is not set
++# CONFIG_MWAVE is not set
++# CONFIG_PC8736x_GPIO is not set
++# CONFIG_NSC_GPIO is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_HANGCHECK_TIMER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_TELCLOCK is not set
++CONFIG_DEVPORT=y
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_MUX is not set
++CONFIG_I2C_HELPER_AUTO=y
++CONFIG_I2C_ALGOBIT=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# PC SMBus host controller drivers
++#
++# CONFIG_I2C_ALI1535 is not set
++# CONFIG_I2C_ALI1563 is not set
++# CONFIG_I2C_ALI15X3 is not set
++# CONFIG_I2C_AMD756 is not set
++# CONFIG_I2C_AMD8111 is not set
++# CONFIG_I2C_I801 is not set
++# CONFIG_I2C_ISCH is not set
++# CONFIG_I2C_ISMT is not set
++# CONFIG_I2C_PIIX4 is not set
++# CONFIG_I2C_NFORCE2 is not set
++# CONFIG_I2C_SIS5595 is not set
++# CONFIG_I2C_SIS630 is not set
++# CONFIG_I2C_SIS96X is not set
++# CONFIG_I2C_VIA is not set
++# CONFIG_I2C_VIAPRO is not set
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_CBUS_GPIO is not set
++CONFIG_I2C_DESIGNWARE_CORE_FORK=y
++CONFIG_I2C_DESIGNWARE_PCI_FORK=y
++# CONFIG_I2C_DESIGNWARE_PLATFORM_FORK is not set
++# CONFIG_I2C_DW_SPEED_MODE_DEBUG is not set
++CONFIG_I2C_PMIC=y
++# CONFIG_I2C_DESIGNWARE_PCI is not set
++# CONFIG_I2C_EG20T is not set
++CONFIG_I2C_GPIO=y
++# CONFIG_I2C_INTEL_MID is not set
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_PXA_PCI is not set
++# CONFIG_I2C_SIMTEC is not set
++# CONFIG_I2C_XILINX is not set
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_DIOLAN_U2C is not set
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_SCx200_ACB is not set
++# CONFIG_I2C_STUB is not set
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++# CONFIG_SPI_ALTERA is not set
++CONFIG_SPI_BITBANG=y
++CONFIG_SPI_GPIO=y
++CONFIG_SPI_INTEL_MID_SSP=y
++# CONFIG_SPI_OC_TINY is not set
++# CONFIG_SPI_PXA2XX is not set
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_SC18IS602 is not set
++# CONFIG_SPI_TOPCLIFF_PCH is not set
++# CONFIG_SPI_XCOMM is not set
++# CONFIG_SPI_XILINX is not set
++CONFIG_SPI_DESIGNWARE=y
++CONFIG_SPI_DW_PCI=y
++CONFIG_SPI_DW_MID_DMA=y
++
++#
++# SPI Protocol Masters
++#
++CONFIG_SPI_SPIDEV=y
++# CONFIG_SPI_TLE62X0 is not set
++
++#
++# Qualcomm MSM SSBI bus support
++#
++# CONFIG_SSBI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++CONFIG_PPS=y
++# CONFIG_PPS_DEBUG is not set
++
++#
++# PPS clients support
++#
++# CONFIG_PPS_CLIENT_KTIMER is not set
++# CONFIG_PPS_CLIENT_LDISC is not set
++# CONFIG_PPS_CLIENT_GPIO is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++CONFIG_PTP_1588_CLOCK=y
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++# CONFIG_PTP_1588_CLOCK_PCH is not set
++CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++CONFIG_GPIO_DEVRES=y
++CONFIG_GPIOLIB=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++CONFIG_GPIODEBUG=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++# CONFIG_GPIO_IT8761E is not set
++# CONFIG_GPIO_TS5500 is not set
++# CONFIG_GPIO_SCH is not set
++# CONFIG_GPIO_ICH is not set
++# CONFIG_GPIO_VX855 is not set
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++CONFIG_GPIO_PCA953X=y
++CONFIG_GPIO_PCA953X_IRQ=y
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_WM8994 is not set
++# CONFIG_GPIO_ADP5588 is not set
++
++#
++# PCI GPIO expanders:
++#
++# CONFIG_GPIO_BT8XX is not set
++# CONFIG_GPIO_AMD8111 is not set
++CONFIG_GPIO_LANGWELL=y
++# CONFIG_GPIO_PCH is not set
++# CONFIG_GPIO_ML_IOH is not set
++# CONFIG_GPIO_RDC321X is not set
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++# CONFIG_GPIO_MSIC is not set
++
++#
++# USB GPIO expanders:
++#
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++CONFIG_PMIC_CCSM=y
++CONFIG_BQ24261_CHARGER=y
++# CONFIG_PDA_POWER is not set
++# CONFIG_GENERIC_ADC_BATTERY is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++CONFIG_BATTERY_MAX17042=y
++# CONFIG_BATTERY_INTEL_MID is not set
++# CONFIG_CHARGER_ISP1704 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_GPIO is not set
++# CONFIG_CHARGER_MANAGER is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_SMB347 is not set
++# CONFIG_BATTERY_GOLDFISH is not set
++# CONFIG_POWER_RESET is not set
++# CONFIG_POWER_AVS is not set
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
++
++#
++# Native drivers
++#
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_ABITUGURU3 is not set
++# CONFIG_SENSORS_AD7314 is not set
++# CONFIG_SENSORS_AD7414 is not set
++# CONFIG_SENSORS_AD7418 is not set
++# CONFIG_SENSORS_ADCXX is not set
++# CONFIG_SENSORS_ADM1021 is not set
++# CONFIG_SENSORS_ADM1025 is not set
++# CONFIG_SENSORS_ADM1026 is not set
++# CONFIG_SENSORS_ADM1029 is not set
++# CONFIG_SENSORS_ADM1031 is not set
++# CONFIG_SENSORS_ADM9240 is not set
++# CONFIG_SENSORS_ADT7310 is not set
++# CONFIG_SENSORS_ADT7410 is not set
++# CONFIG_SENSORS_ADT7411 is not set
++# CONFIG_SENSORS_ADT7462 is not set
++# CONFIG_SENSORS_ADT7470 is not set
++# CONFIG_SENSORS_ADT7475 is not set
++# CONFIG_SENSORS_ASC7621 is not set
++# CONFIG_SENSORS_K8TEMP is not set
++# CONFIG_SENSORS_K10TEMP is not set
++# CONFIG_SENSORS_FAM15H_POWER is not set
++# CONFIG_SENSORS_ASB100 is not set
++# CONFIG_SENSORS_ATXP1 is not set
++# CONFIG_SENSORS_DS620 is not set
++# CONFIG_SENSORS_DS1621 is not set
++# CONFIG_SENSORS_I5K_AMB is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_F71882FG is not set
++# CONFIG_SENSORS_F75375S is not set
++# CONFIG_SENSORS_FSCHMD is not set
++# CONFIG_SENSORS_G760A is not set
++# CONFIG_SENSORS_GL518SM is not set
++# CONFIG_SENSORS_GL520SM is not set
++# CONFIG_SENSORS_GPIO_FAN is not set
++# CONFIG_SENSORS_HIH6130 is not set
++CONFIG_SENSORS_CORETEMP=y
++CONFIG_SENSORS_CORETEMP_INTERRUPT=y
++# CONFIG_SENSORS_IIO_HWMON is not set
++# CONFIG_SENSORS_IT87 is not set
++# CONFIG_SENSORS_JC42 is not set
++# CONFIG_SENSORS_LINEAGE is not set
++# CONFIG_SENSORS_LM63 is not set
++# CONFIG_SENSORS_LM70 is not set
++# CONFIG_SENSORS_LM73 is not set
++# CONFIG_SENSORS_LM75 is not set
++# CONFIG_SENSORS_LM77 is not set
++# CONFIG_SENSORS_LM78 is not set
++# CONFIG_SENSORS_LM80 is not set
++# CONFIG_SENSORS_LM83 is not set
++# CONFIG_SENSORS_LM85 is not set
++# CONFIG_SENSORS_LM87 is not set
++# CONFIG_SENSORS_LM90 is not set
++# CONFIG_SENSORS_LM92 is not set
++# CONFIG_SENSORS_LM93 is not set
++# CONFIG_SENSORS_LTC4151 is not set
++# CONFIG_SENSORS_LTC4215 is not set
++# CONFIG_SENSORS_LTC4245 is not set
++# CONFIG_SENSORS_LTC4261 is not set
++# CONFIG_SENSORS_LM95234 is not set
++# CONFIG_SENSORS_LM95241 is not set
++# CONFIG_SENSORS_LM95245 is not set
++CONFIG_MSIC_GPADC=y
++# CONFIG_SENSORS_MAX1111 is not set
++# CONFIG_SENSORS_MAX16065 is not set
++# CONFIG_SENSORS_MAX1619 is not set
++# CONFIG_SENSORS_MAX1668 is not set
++# CONFIG_SENSORS_MAX197 is not set
++# CONFIG_SENSORS_MAX6639 is not set
++# CONFIG_SENSORS_MAX6642 is not set
++# CONFIG_SENSORS_MAX6650 is not set
++# CONFIG_SENSORS_MAX6697 is not set
++# CONFIG_SENSORS_MCP3021 is not set
++# CONFIG_SENSORS_NCT6775 is not set
++# CONFIG_SENSORS_PC87360 is not set
++# CONFIG_SENSORS_PC87427 is not set
++# CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_PMBUS is not set
++# CONFIG_SENSORS_SHT15 is not set
++# CONFIG_SENSORS_SHT21 is not set
++# CONFIG_SENSORS_SIS5595 is not set
++# CONFIG_SENSORS_SMM665 is not set
++# CONFIG_SENSORS_DME1737 is not set
++# CONFIG_SENSORS_EMC1403 is not set
++# CONFIG_SENSORS_EMC2103 is not set
++# CONFIG_SENSORS_EMC6W201 is not set
++# CONFIG_SENSORS_SMSC47M1 is not set
++# CONFIG_SENSORS_SMSC47M192 is not set
++# CONFIG_SENSORS_SMSC47B397 is not set
++# CONFIG_SENSORS_SCH56XX_COMMON is not set
++# CONFIG_SENSORS_SCH5627 is not set
++# CONFIG_SENSORS_SCH5636 is not set
++# CONFIG_SENSORS_ADS1015 is not set
++# CONFIG_SENSORS_ADS7828 is not set
++# CONFIG_SENSORS_ADS7871 is not set
++# CONFIG_SENSORS_AMC6821 is not set
++# CONFIG_SENSORS_INA209 is not set
++# CONFIG_SENSORS_INA2XX is not set
++# CONFIG_SENSORS_THMC50 is not set
++# CONFIG_SENSORS_TMP102 is not set
++# CONFIG_SENSORS_TMP401 is not set
++# CONFIG_SENSORS_TMP421 is not set
++# CONFIG_SENSORS_VIA_CPUTEMP is not set
++# CONFIG_SENSORS_VIA686A is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_SENSORS_VT8231 is not set
++# CONFIG_SENSORS_W83781D is not set
++# CONFIG_SENSORS_W83791D is not set
++# CONFIG_SENSORS_W83792D is not set
++# CONFIG_SENSORS_W83793 is not set
++# CONFIG_SENSORS_W83795 is not set
++# CONFIG_SENSORS_W83L785TS is not set
++# CONFIG_SENSORS_W83L786NG is not set
++# CONFIG_SENSORS_W83627HF is not set
++# CONFIG_SENSORS_W83627EHF is not set
++# CONFIG_SENSORS_APPLESMC is not set
++CONFIG_THERMAL=y
++CONFIG_THERMAL_HWMON=y
++CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
++# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
++# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
++# CONFIG_THERMAL_GOV_FAIR_SHARE is not set
++CONFIG_THERMAL_GOV_STEP_WISE=y
++# CONFIG_THERMAL_GOV_USER_SPACE is not set
++# CONFIG_CPU_THERMAL is not set
++# CONFIG_THERMAL_EMULATION is not set
++# CONFIG_INTEL_POWERCLAMP is not set
++CONFIG_SENSORS_THERMAL_MRFLD=y
++CONFIG_SOC_THERMAL=y
++CONFIG_WATCHDOG=y
++# CONFIG_WATCHDOG_CORE is not set
++# CONFIG_WATCHDOG_NOWAYOUT is not set
++
++#
++# Watchdog Device Drivers
++#
++# CONFIG_SOFT_WATCHDOG is not set
++# CONFIG_ACQUIRE_WDT is not set
++# CONFIG_ADVANTECH_WDT is not set
++# CONFIG_ALIM1535_WDT is not set
++# CONFIG_ALIM7101_WDT is not set
++# CONFIG_F71808E_WDT is not set
++# CONFIG_SP5100_TCO is not set
++# CONFIG_SC520_WDT is not set
++# CONFIG_SBC_FITPC2_WATCHDOG is not set
++# CONFIG_EUROTECH_WDT is not set
++# CONFIG_IB700_WDT is not set
++# CONFIG_IBMASR is not set
++# CONFIG_WAFER_WDT is not set
++# CONFIG_I6300ESB_WDT is not set
++# CONFIG_IE6XX_WDT is not set
++# CONFIG_INTEL_SCU_WATCHDOG is not set
++CONFIG_INTEL_SCU_WATCHDOG_EVO=y
++CONFIG_DISABLE_SCU_WATCHDOG=y
++# CONFIG_ITCO_WDT is not set
++# CONFIG_IT8712F_WDT is not set
++# CONFIG_IT87_WDT is not set
++# CONFIG_HP_WATCHDOG is not set
++# CONFIG_SC1200_WDT is not set
++# CONFIG_PC87413_WDT is not set
++# CONFIG_NV_TCO is not set
++# CONFIG_60XX_WDT is not set
++# CONFIG_SBC8360_WDT is not set
++# CONFIG_SBC7240_WDT is not set
++# CONFIG_CPU5_WDT is not set
++# CONFIG_SMSC_SCH311X_WDT is not set
++# CONFIG_SMSC37B787_WDT is not set
++# CONFIG_VIA_WDT is not set
++# CONFIG_W83627HF_WDT is not set
++# CONFIG_W83697HF_WDT is not set
++# CONFIG_W83697UG_WDT is not set
++# CONFIG_W83877F_WDT is not set
++# CONFIG_W83977F_WDT is not set
++# CONFIG_MACHZ_WDT is not set
++# CONFIG_SBC_EPX_C3_WATCHDOG is not set
++
++#
++# PCI-based Watchdog Cards
++#
++# CONFIG_PCIPCWATCHDOG is not set
++# CONFIG_WDTPCI is not set
++
++#
++# USB-based Watchdog Cards
++#
++# CONFIG_USBPCWATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_BCMA_POSSIBLE=y
++
++#
++# Broadcom specific AMBA
++#
++# CONFIG_BCMA is not set
++
++#
++# Multifunction device drivers
++#
++CONFIG_MFD_CORE=y
++# CONFIG_MFD_CS5535 is not set
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_LPC_ICH is not set
++# CONFIG_LPC_SCH is not set
++CONFIG_MFD_INTEL_MSIC=y
++# CONFIG_MFD_JANZ_CMODIO is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX77686 is not set
++# CONFIG_MFD_MAX77693 is not set
++# CONFIG_MFD_MAX8907 is not set
++# CONFIG_MFD_MAX8925 is not set
++# CONFIG_MFD_MAX8997 is not set
++# CONFIG_MFD_MAX8998 is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_RDC321X is not set
++# CONFIG_MFD_RTSX_PCI is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++# CONFIG_MFD_SYSCON is not set
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TIMBERDALE is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_VX855 is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++CONFIG_MFD_WM8994=y
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_DUMMY is not set
++CONFIG_REGULATOR_FIXED_VOLTAGE=y
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_GPIO is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++CONFIG_REGULATOR_WM8994=y
++CONFIG_REGULATOR_PMIC_BASIN_COVE=y
++CONFIG_MEDIA_SUPPORT=y
++
++#
++# Multimedia core support
++#
++CONFIG_MEDIA_CAMERA_SUPPORT=y
++# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
++# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
++# CONFIG_MEDIA_RADIO_SUPPORT is not set
++# CONFIG_MEDIA_RC_SUPPORT is not set
++CONFIG_MEDIA_CONTROLLER=y
++CONFIG_VIDEO_DEV=y
++CONFIG_VIDEO_V4L2_SUBDEV_API=y
++CONFIG_VIDEO_V4L2=y
++# CONFIG_VIDEO_ADV_DEBUG is not set
++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
++# CONFIG_VIDEO_V4L2_INT_DEVICE is not set
++# CONFIG_TTPCI_EEPROM is not set
++
++#
++# Media drivers
++#
++# CONFIG_MEDIA_USB_SUPPORT is not set
++# CONFIG_MEDIA_PCI_SUPPORT is not set
++# CONFIG_V4L_PLATFORM_DRIVERS is not set
++# CONFIG_V4L_MEM2MEM_DRIVERS is not set
++# CONFIG_V4L_TEST_DRIVERS is not set
++
++#
++# Supported MMC/SDIO adapters
++#
++# CONFIG_CYPRESS_FIRMWARE is not set
++
++#
++# Media ancillary drivers (tuners, sensors, i2c, frontends)
++#
++# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
++
++#
++# Encoders, decoders, sensors and other helper chips
++#
++
++#
++# Audio decoders, processors and mixers
++#
++# CONFIG_VIDEO_TVAUDIO is not set
++# CONFIG_VIDEO_TDA7432 is not set
++# CONFIG_VIDEO_TDA9840 is not set
++# CONFIG_VIDEO_TEA6415C is not set
++# CONFIG_VIDEO_TEA6420 is not set
++# CONFIG_VIDEO_MSP3400 is not set
++# CONFIG_VIDEO_CS5345 is not set
++# CONFIG_VIDEO_CS53L32A is not set
++# CONFIG_VIDEO_TLV320AIC23B is not set
++# CONFIG_VIDEO_UDA1342 is not set
++# CONFIG_VIDEO_WM8775 is not set
++# CONFIG_VIDEO_WM8739 is not set
++# CONFIG_VIDEO_VP27SMPX is not set
++# CONFIG_VIDEO_SONY_BTF_MPX is not set
++
++#
++# RDS decoders
++#
++# CONFIG_VIDEO_SAA6588 is not set
++
++#
++# Video decoders
++#
++# CONFIG_VIDEO_ADV7180 is not set
++# CONFIG_VIDEO_ADV7183 is not set
++# CONFIG_VIDEO_ADV7604 is not set
++# CONFIG_VIDEO_BT819 is not set
++# CONFIG_VIDEO_BT856 is not set
++# CONFIG_VIDEO_BT866 is not set
++# CONFIG_VIDEO_KS0127 is not set
++# CONFIG_VIDEO_SAA7110 is not set
++# CONFIG_VIDEO_SAA711X is not set
++# CONFIG_VIDEO_SAA7191 is not set
++# CONFIG_VIDEO_TVP514X is not set
++# CONFIG_VIDEO_TVP5150 is not set
++# CONFIG_VIDEO_TVP7002 is not set
++# CONFIG_VIDEO_TW2804 is not set
++# CONFIG_VIDEO_TW9903 is not set
++# CONFIG_VIDEO_TW9906 is not set
++# CONFIG_VIDEO_VPX3220 is not set
++
++#
++# Video and audio decoders
++#
++# CONFIG_VIDEO_SAA717X is not set
++# CONFIG_VIDEO_CX25840 is not set
++
++#
++# Video encoders
++#
++# CONFIG_VIDEO_SAA7127 is not set
++# CONFIG_VIDEO_SAA7185 is not set
++# CONFIG_VIDEO_ADV7170 is not set
++# CONFIG_VIDEO_ADV7175 is not set
++# CONFIG_VIDEO_ADV7343 is not set
++# CONFIG_VIDEO_ADV7393 is not set
++# CONFIG_VIDEO_AD9389B is not set
++# CONFIG_VIDEO_AK881X is not set
++
++#
++# Camera sensor devices
++#
++# CONFIG_VIDEO_OV7640 is not set
++# CONFIG_VIDEO_OV7670 is not set
++# CONFIG_VIDEO_OV9650 is not set
++# CONFIG_VIDEO_VS6624 is not set
++# CONFIG_VIDEO_MT9M032 is not set
++# CONFIG_VIDEO_MT9P031 is not set
++# CONFIG_VIDEO_MT9T001 is not set
++# CONFIG_VIDEO_MT9V011 is not set
++# CONFIG_VIDEO_MT9V032 is not set
++# CONFIG_VIDEO_SR030PC30 is not set
++# CONFIG_VIDEO_NOON010PC30 is not set
++# CONFIG_VIDEO_M5MOLS is not set
++# CONFIG_VIDEO_S5K6AA is not set
++# CONFIG_VIDEO_S5K4ECGX is not set
++# CONFIG_VIDEO_S5C73M3 is not set
++
++#
++# Flash devices
++#
++# CONFIG_VIDEO_ADP1653 is not set
++# CONFIG_VIDEO_AS3645A is not set
++
++#
++# Video improvement chips
++#
++# CONFIG_VIDEO_UPD64031A is not set
++# CONFIG_VIDEO_UPD64083 is not set
++
++#
++# Miscelaneous helper chips
++#
++# CONFIG_VIDEO_THS7303 is not set
++# CONFIG_VIDEO_M52790 is not set
++
++#
++# Sensors used on soc_camera driver
++#
++
++#
++# Customise DVB Frontends
++#
++# CONFIG_DVB_AU8522_V4L is not set
++CONFIG_DVB_TUNER_DIB0070=m
++CONFIG_DVB_TUNER_DIB0090=m
++
++#
++# Tools to develop new frontends
++#
++# CONFIG_DVB_DUMMY_FE is not set
++
++#
++# Graphics support
++#
++CONFIG_AGP=y
++# CONFIG_AGP_ALI is not set
++# CONFIG_AGP_ATI is not set
++# CONFIG_AGP_AMD is not set
++CONFIG_AGP_AMD64=y
++CONFIG_AGP_INTEL=y
++# CONFIG_AGP_NVIDIA is not set
++# CONFIG_AGP_SIS is not set
++# CONFIG_AGP_SWORKS is not set
++# CONFIG_AGP_VIA is not set
++# CONFIG_AGP_EFFICEON is not set
++CONFIG_VGA_ARB=y
++CONFIG_VGA_ARB_MAX_GPUS=16
++CONFIG_DRM=y
++# CONFIG_DRM_TDFX is not set
++# CONFIG_DRM_R128 is not set
++# CONFIG_DRM_RADEON is not set
++# CONFIG_DRM_NOUVEAU is not set
++# CONFIG_DRM_I915 is not set
++# CONFIG_DRM_MGA is not set
++# CONFIG_DRM_SIS is not set
++# CONFIG_DRM_VIA is not set
++# CONFIG_DRM_SAVAGE is not set
++# CONFIG_DRM_VMWGFX is not set
++# CONFIG_DRM_GMA500 is not set
++# CONFIG_DRM_UDL is not set
++# CONFIG_DRM_AST is not set
++# CONFIG_DRM_MGAG200 is not set
++# CONFIG_DRM_CIRRUS_QEMU is not set
++# CONFIG_DRM_QXL is not set
++# CONFIG_VGASTATE is not set
++CONFIG_VIDEO_OUTPUT_CONTROL=y
++CONFIG_HDMI=y
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++CONFIG_FB_MODE_HELPERS=y
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_CIRRUS is not set
++# CONFIG_FB_PM2 is not set
++# CONFIG_FB_CYBER2000 is not set
++# CONFIG_FB_ARC is not set
++# CONFIG_FB_ASILIANT is not set
++# CONFIG_FB_IMSTT is not set
++# CONFIG_FB_VGA16 is not set
++# CONFIG_FB_UVESA is not set
++# CONFIG_FB_VESA is not set
++# CONFIG_FB_N411 is not set
++# CONFIG_FB_HGA is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_NVIDIA is not set
++# CONFIG_FB_RIVA is not set
++# CONFIG_FB_I740 is not set
++# CONFIG_FB_I810 is not set
++# CONFIG_FB_LE80578 is not set
++# CONFIG_FB_INTEL is not set
++# CONFIG_FB_MATROX is not set
++# CONFIG_FB_RADEON is not set
++# CONFIG_FB_ATY128 is not set
++# CONFIG_FB_ATY is not set
++# CONFIG_FB_S3 is not set
++# CONFIG_FB_SAVAGE is not set
++# CONFIG_FB_SIS is not set
++# CONFIG_FB_VIA is not set
++# CONFIG_FB_NEOMAGIC is not set
++# CONFIG_FB_KYRO is not set
++# CONFIG_FB_3DFX is not set
++# CONFIG_FB_VOODOO1 is not set
++# CONFIG_FB_VT8623 is not set
++# CONFIG_FB_TRIDENT is not set
++# CONFIG_FB_ARK is not set
++# CONFIG_FB_PM3 is not set
++# CONFIG_FB_CARMINE is not set
++# CONFIG_FB_GEODE is not set
++# CONFIG_FB_TMIO is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_GOLDFISH is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_MB862XX is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_EXYNOS_VIDEO is not set
++CONFIG_BACKLIGHT_LCD_SUPPORT=y
++# CONFIG_LCD_CLASS_DEVICE is not set
++CONFIG_BACKLIGHT_CLASS_DEVICE=y
++CONFIG_BACKLIGHT_GENERIC=y
++# CONFIG_BACKLIGHT_PWM is not set
++# CONFIG_BACKLIGHT_SAHARA is not set
++# CONFIG_BACKLIGHT_ADP8860 is not set
++# CONFIG_BACKLIGHT_ADP8870 is not set
++# CONFIG_BACKLIGHT_LM3630 is not set
++# CONFIG_BACKLIGHT_LM3639 is not set
++# CONFIG_BACKLIGHT_LP855X is not set
++
++#
++# Console display driver support
++#
++CONFIG_VGA_CONSOLE=y
++# CONFIG_VGACON_SOFT_SCROLLBACK is not set
++CONFIG_DUMMY_CONSOLE=y
++CONFIG_FRAMEBUFFER_CONSOLE=y
++CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
++# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
++# CONFIG_FONTS is not set
++CONFIG_FONT_8x8=y
++CONFIG_FONT_8x16=y
++# CONFIG_LOGO is not set
++CONFIG_SOUND=y
++# CONFIG_SOUND_OSS_CORE is not set
++CONFIG_SND=y
++CONFIG_SND_TIMER=y
++CONFIG_SND_PCM=y
++CONFIG_SND_COMPRESS_OFFLOAD=y
++CONFIG_SND_JACK=y
++CONFIG_SND_SEQUENCER=y
++# CONFIG_SND_SEQ_DUMMY is not set
++# CONFIG_SND_MIXER_OSS is not set
++# CONFIG_SND_PCM_OSS is not set
++# CONFIG_SND_SEQUENCER_OSS is not set
++# CONFIG_SND_HRTIMER is not set
++CONFIG_SND_DYNAMIC_MINORS=y
++# CONFIG_SND_SUPPORT_OLD_API is not set
++# CONFIG_SND_VERBOSE_PROCFS is not set
++# CONFIG_SND_VERBOSE_PRINTK is not set
++# CONFIG_SND_DEBUG is not set
++CONFIG_SND_DMA_SGBUF=y
++# CONFIG_SND_RAWMIDI_SEQ is not set
++# CONFIG_SND_OPL3_LIB_SEQ is not set
++# CONFIG_SND_OPL4_LIB_SEQ is not set
++# CONFIG_SND_SBAWE_SEQ is not set
++# CONFIG_SND_EMU10K1_SEQ is not set
++CONFIG_SND_DRIVERS=y
++# CONFIG_SND_PCSP is not set
++# CONFIG_SND_DUMMY is not set
++CONFIG_SND_ALOOP=y
++# CONFIG_SND_VIRMIDI is not set
++# CONFIG_SND_MTPAV is not set
++# CONFIG_SND_SERIAL_U16550 is not set
++# CONFIG_SND_MPU401 is not set
++# CONFIG_SND_PCI is not set
++# CONFIG_SND_SPI is not set
++CONFIG_SND_USB=y
++# CONFIG_SND_USB_AUDIO is not set
++# CONFIG_SND_USB_UA101 is not set
++# CONFIG_SND_USB_USX2Y is not set
++# CONFIG_SND_USB_CAIAQ is not set
++# CONFIG_SND_USB_US122L is not set
++# CONFIG_SND_USB_6FIRE is not set
++CONFIG_SND_SOC=y
++# CONFIG_SND_ATMEL_SOC is not set
++# CONFIG_SND_MFLD_MACHINE is not set
++CONFIG_SND_SOC_I2C_AND_SPI=y
++# CONFIG_SND_SOC_ALL_CODECS is not set
++# CONFIG_SND_SIMPLE_CARD is not set
++# CONFIG_SOUND_PRIME is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++CONFIG_HIDRAW=y
++CONFIG_UHID=y
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++# CONFIG_HID_A4TECH is not set
++# CONFIG_HID_ACRUX is not set
++# CONFIG_HID_APPLE is not set
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++# CONFIG_HID_BELKIN is not set
++# CONFIG_HID_CHERRY is not set
++# CONFIG_HID_CHICONY is not set
++# CONFIG_HID_PRODIKEYS is not set
++# CONFIG_HID_CYPRESS is not set
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_EZKEY is not set
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_KEYTOUCH is not set
++# CONFIG_HID_KYE is not set
++# CONFIG_HID_UCLOGIC is not set
++# CONFIG_HID_WALTOP is not set
++# CONFIG_HID_GYRATION is not set
++# CONFIG_HID_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++# CONFIG_HID_KENSINGTON is not set
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO_TPKBD is not set
++# CONFIG_HID_LOGITECH is not set
++# CONFIG_HID_MAGICMOUSE is not set
++# CONFIG_HID_MICROSOFT is not set
++# CONFIG_HID_MONTEREY is not set
++# CONFIG_HID_MULTITOUCH is not set
++# CONFIG_HID_NTRIG is not set
++# CONFIG_HID_ORTEK is not set
++# CONFIG_HID_PANTHERLORD is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_PS3REMOTE is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SONY is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_GREENASIA is not set
++# CONFIG_HID_SMARTJOYPLUS is not set
++# CONFIG_HID_TIVO is not set
++# CONFIG_HID_TOPSEED is not set
++# CONFIG_HID_THINGM is not set
++# CONFIG_HID_THRUSTMASTER is not set
++# CONFIG_HID_WACOM is not set
++# CONFIG_HID_WIIMOTE is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=y
++CONFIG_HID_PID=y
++CONFIG_USB_HIDDEV=y
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_ARCH_HAS_OHCI=y
++CONFIG_USB_ARCH_HAS_EHCI=y
++CONFIG_USB_ARCH_HAS_XHCI=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEFAULT_PERSIST=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++CONFIG_USB_OTG=y
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++CONFIG_USB_MON=y
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_XHCI_HCD=y
++CONFIG_USB_XHCI_PLATFORM=y
++# CONFIG_USB_XHCI_HCD_DEBUGGING is not set
++CONFIG_USB_EHCI_HCD=y
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++# CONFIG_USB_EHCI_TT_NEWSCHED is not set
++CONFIG_USB_EHCI_PCI=y
++# CONFIG_USB_EHCI_HCD_PLATFORM is not set
++# CONFIG_USB_OXU210HP_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++# CONFIG_USB_ISP1760_HCD is not set
++# CONFIG_USB_ISP1362_HCD is not set
++# CONFIG_USB_OHCI_HCD is not set
++# CONFIG_USB_UHCI_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_RENESAS_USBHS is not set
++
++#
++# USB Device Class drivers
++#
++CONFIG_USB_ACM=y
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++CONFIG_USB_DWC3=y
++# CONFIG_USB_DWC3_HOST is not set
++CONFIG_USB_DWC3_GADGET=y
++# CONFIG_USB_DWC3_DUAL_ROLE is not set
++
++#
++# Platform Glue Driver Support
++#
++# CONFIG_USB_DWC3_PCI is not set
++CONFIG_USB_DWC3_OTG=y
++CONFIG_USB_DWC3_INTEL_MRFL=y
++# CONFIG_USB_DWC3_INTEL_BYT is not set
++CONFIG_USB_DWC3_DEVICE_INTEL=y
++CONFIG_USB_DWC3_HOST_INTEL=y
++
++#
++# Debugging features
++#
++# CONFIG_USB_DWC3_DEBUG is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++CONFIG_USB_SERIAL=y
++# CONFIG_USB_SERIAL_CONSOLE is not set
++# CONFIG_USB_SERIAL_GENERIC is not set
++# CONFIG_USB_SERIAL_AIRCABLE is not set
++# CONFIG_USB_SERIAL_ARK3116 is not set
++# CONFIG_USB_SERIAL_BELKIN is not set
++# CONFIG_USB_SERIAL_CH341 is not set
++# CONFIG_USB_SERIAL_WHITEHEAT is not set
++# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
++# CONFIG_USB_SERIAL_CP210X is not set
++# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
++# CONFIG_USB_SERIAL_EMPEG is not set
++# CONFIG_USB_SERIAL_FTDI_SIO is not set
++# CONFIG_USB_SERIAL_FUNSOFT is not set
++# CONFIG_USB_SERIAL_VISOR is not set
++# CONFIG_USB_SERIAL_IPAQ is not set
++# CONFIG_USB_SERIAL_IR is not set
++# CONFIG_USB_SERIAL_EDGEPORT is not set
++# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
++# CONFIG_USB_SERIAL_F81232 is not set
++# CONFIG_USB_SERIAL_GARMIN is not set
++# CONFIG_USB_SERIAL_IPW is not set
++# CONFIG_USB_SERIAL_IUU is not set
++# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
++# CONFIG_USB_SERIAL_KEYSPAN is not set
++# CONFIG_USB_SERIAL_KLSI is not set
++# CONFIG_USB_SERIAL_KOBIL_SCT is not set
++# CONFIG_USB_SERIAL_MCT_U232 is not set
++# CONFIG_USB_SERIAL_METRO is not set
++# CONFIG_USB_SERIAL_MOS7720 is not set
++# CONFIG_USB_SERIAL_MOS7840 is not set
++# CONFIG_USB_SERIAL_MOTOROLA is not set
++# CONFIG_USB_SERIAL_NAVMAN is not set
++CONFIG_USB_SERIAL_PL2303=y
++# CONFIG_USB_SERIAL_OTI6858 is not set
++# CONFIG_USB_SERIAL_QCAUX is not set
++# CONFIG_USB_SERIAL_QUALCOMM is not set
++# CONFIG_USB_SERIAL_SPCP8X5 is not set
++# CONFIG_USB_SERIAL_HP4X is not set
++# CONFIG_USB_SERIAL_SAFE is not set
++# CONFIG_USB_SERIAL_SIEMENS_MPI is not set
++# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
++# CONFIG_USB_SERIAL_SYMBOL is not set
++# CONFIG_USB_SERIAL_TI is not set
++# CONFIG_USB_SERIAL_CYBERJACK is not set
++# CONFIG_USB_SERIAL_XIRCOM is not set
++# CONFIG_USB_SERIAL_OPTION is not set
++# CONFIG_USB_SERIAL_OMNINET is not set
++# CONFIG_USB_SERIAL_OPTICON is not set
++# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set
++# CONFIG_USB_SERIAL_XSENS_MT is not set
++# CONFIG_USB_SERIAL_ZIO is not set
++# CONFIG_USB_SERIAL_WISHBONE is not set
++# CONFIG_USB_SERIAL_ZTE is not set
++# CONFIG_USB_SERIAL_SSU100 is not set
++# CONFIG_USB_SERIAL_QT2 is not set
++# CONFIG_USB_SERIAL_DEBUG is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++CONFIG_USB_PHY=y
++CONFIG_NOP_USB_XCEIV=y
++# CONFIG_OMAP_CONTROL_USB is not set
++# CONFIG_OMAP_USB3 is not set
++# CONFIG_SAMSUNG_USBPHY is not set
++# CONFIG_SAMSUNG_USB2PHY is not set
++# CONFIG_SAMSUNG_USB3PHY is not set
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_RCAR_PHY is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++# CONFIG_USB_GADGET_DEBUG_FS is not set
++CONFIG_USB_GADGET_VBUS_DRAW=500
++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
++
++#
++# USB Peripheral Controller
++#
++# CONFIG_USB_R8A66597 is not set
++# CONFIG_USB_PXA27X is not set
++# CONFIG_USB_MV_UDC is not set
++# CONFIG_USB_MV_U3D is not set
++# CONFIG_USB_M66592 is not set
++# CONFIG_USB_AMD5536UDC is not set
++# CONFIG_USB_NET2272 is not set
++# CONFIG_USB_NET2280 is not set
++# CONFIG_USB_GOKU is not set
++# CONFIG_USB_EG20T is not set
++# CONFIG_USB_DUMMY_HCD is not set
++CONFIG_USB_LIBCOMPOSITE=m
++CONFIG_USB_F_ACM=m
++CONFIG_USB_U_SERIAL=m
++# CONFIG_USB_ZERO is not set
++# CONFIG_USB_AUDIO is not set
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_G_NCM is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FUNCTIONFS is not set
++# CONFIG_USB_MASS_STORAGE is not set
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_MIDI_GADGET is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++# CONFIG_USB_G_ACM_MS is not set
++CONFIG_USB_G_MULTI=m
++CONFIG_USB_G_MULTI_RNDIS=y
++# CONFIG_USB_G_MULTI_CDC is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++# CONFIG_USB_G_WEBCAM is not set
++# CONFIG_UWB is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++CONFIG_MMC_UNSAFE_RESUME=y
++# CONFIG_MMC_CLKGATE is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_MINORS=32
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++CONFIG_MMC_SDHCI=y
++CONFIG_MMC_SDHCI_PCI=y
++# CONFIG_MMC_RICOH_MMC is not set
++# CONFIG_MMC_SDHCI_PLTFM is not set
++# CONFIG_MMC_WBSD is not set
++# CONFIG_MMC_TIFM_SD is not set
++# CONFIG_MMC_CB710 is not set
++# CONFIG_MMC_VIA_SDMMC is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MEMSTICK is not set
++CONFIG_NEW_LEDS=y
++CONFIG_LEDS_CLASS=y
++
++#
++# LED drivers
++#
++# CONFIG_LEDS_LM3530 is not set
++# CONFIG_LEDS_LM3642 is not set
++# CONFIG_LEDS_PCA9532 is not set
++# CONFIG_LEDS_GPIO is not set
++# CONFIG_LEDS_LP3944 is not set
++# CONFIG_LEDS_LP5521 is not set
++# CONFIG_LEDS_LP5523 is not set
++# CONFIG_LEDS_LP5562 is not set
++# CONFIG_LEDS_PCA955X is not set
++# CONFIG_LEDS_PCA9633 is not set
++# CONFIG_LEDS_DAC124S085 is not set
++# CONFIG_LEDS_PWM is not set
++# CONFIG_LEDS_REGULATOR is not set
++# CONFIG_LEDS_BD2802 is not set
++# CONFIG_LEDS_INTEL_SS4200 is not set
++# CONFIG_LEDS_LT3593 is not set
++# CONFIG_LEDS_TCA6507 is not set
++# CONFIG_LEDS_LM355x is not set
++# CONFIG_LEDS_OT200 is not set
++# CONFIG_LEDS_BLINKM is not set
++
++#
++# LED Triggers
++#
++CONFIG_LEDS_TRIGGERS=y
++# CONFIG_LEDS_TRIGGER_TIMER is not set
++# CONFIG_LEDS_TRIGGER_ONESHOT is not set
++# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
++# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
++# CONFIG_LEDS_TRIGGER_CPU is not set
++# CONFIG_LEDS_TRIGGER_GPIO is not set
++# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
++
++#
++# iptables trigger is under Netfilter config (LED target)
++#
++# CONFIG_LEDS_TRIGGER_TRANSIENT is not set
++# CONFIG_LEDS_TRIGGER_CAMERA is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_INFINIBAND is not set
++CONFIG_EDAC=y
++CONFIG_EDAC_LEGACY_SYSFS=y
++# CONFIG_EDAC_DEBUG is not set
++# CONFIG_EDAC_MM_EDAC is not set
++CONFIG_RTC_LIB=y
++CONFIG_RTC_CLASS=y
++CONFIG_RTC_HCTOSYS=y
++CONFIG_RTC_SYSTOHC=y
++CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
++# CONFIG_RTC_DEBUG is not set
++
++#
++# RTC interfaces
++#
++CONFIG_RTC_INTF_SYSFS=y
++CONFIG_RTC_INTF_PROC=y
++CONFIG_RTC_INTF_DEV=y
++# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
++# CONFIG_RTC_DRV_TEST is not set
++
++#
++# I2C RTC drivers
++#
++# CONFIG_RTC_DRV_DS1307 is not set
++# CONFIG_RTC_DRV_DS1374 is not set
++# CONFIG_RTC_DRV_DS1672 is not set
++# CONFIG_RTC_DRV_DS3232 is not set
++# CONFIG_RTC_DRV_MAX6900 is not set
++# CONFIG_RTC_DRV_RS5C372 is not set
++# CONFIG_RTC_DRV_ISL1208 is not set
++# CONFIG_RTC_DRV_ISL12022 is not set
++# CONFIG_RTC_DRV_X1205 is not set
++# CONFIG_RTC_DRV_PCF8523 is not set
++# CONFIG_RTC_DRV_PCF8563 is not set
++# CONFIG_RTC_DRV_PCF8583 is not set
++# CONFIG_RTC_DRV_M41T80 is not set
++# CONFIG_RTC_DRV_BQ32K is not set
++# CONFIG_RTC_DRV_S35390A is not set
++# CONFIG_RTC_DRV_FM3130 is not set
++# CONFIG_RTC_DRV_RX8581 is not set
++# CONFIG_RTC_DRV_RX8025 is not set
++# CONFIG_RTC_DRV_EM3027 is not set
++# CONFIG_RTC_DRV_RV3029C2 is not set
++
++#
++# SPI RTC drivers
++#
++# CONFIG_RTC_DRV_M41T93 is not set
++# CONFIG_RTC_DRV_M41T94 is not set
++# CONFIG_RTC_DRV_DS1305 is not set
++# CONFIG_RTC_DRV_DS1390 is not set
++# CONFIG_RTC_DRV_MAX6902 is not set
++# CONFIG_RTC_DRV_R9701 is not set
++# CONFIG_RTC_DRV_RS5C348 is not set
++# CONFIG_RTC_DRV_DS3234 is not set
++# CONFIG_RTC_DRV_PCF2123 is not set
++# CONFIG_RTC_DRV_RX4581 is not set
++
++#
++# Platform RTC drivers
++#
++CONFIG_RTC_DRV_CMOS=y
++# CONFIG_RTC_DRV_VRTC is not set
++# CONFIG_RTC_DRV_DS1286 is not set
++# CONFIG_RTC_DRV_DS1511 is not set
++# CONFIG_RTC_DRV_DS1553 is not set
++# CONFIG_RTC_DRV_DS1742 is not set
++# CONFIG_RTC_DRV_STK17TA8 is not set
++# CONFIG_RTC_DRV_M48T86 is not set
++# CONFIG_RTC_DRV_M48T35 is not set
++# CONFIG_RTC_DRV_M48T59 is not set
++# CONFIG_RTC_DRV_MSM6242 is not set
++# CONFIG_RTC_DRV_BQ4802 is not set
++# CONFIG_RTC_DRV_RP5C01 is not set
++# CONFIG_RTC_DRV_V3020 is not set
++# CONFIG_RTC_DRV_DS2404 is not set
++
++#
++# on-CPU RTC drivers
++#
++
++#
++# HID Sensor RTC drivers
++#
++# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set
++CONFIG_DMADEVICES=y
++# CONFIG_DMADEVICES_DEBUG is not set
++
++#
++# DMA Devices
++#
++CONFIG_INTEL_MID_DMAC=y
++# CONFIG_INTEL_IOATDMA is not set
++# CONFIG_DW_DMAC is not set
++# CONFIG_TIMB_DMA is not set
++# CONFIG_PCH_DMA is not set
++CONFIG_DMA_ENGINE=y
++
++#
++# DMA Clients
++#
++# CONFIG_NET_DMA is not set
++# CONFIG_ASYNC_TX_DMA is not set
++# CONFIG_DMATEST is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++CONFIG_VIRTIO=y
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_PCI is not set
++# CONFIG_VIRTIO_BALLOON is not set
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++CONFIG_STAGING=y
++# CONFIG_ET131X is not set
++# CONFIG_SLICOSS is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_W35UND is not set
++# CONFIG_PRISM2_USB is not set
++# CONFIG_ECHO is not set
++# CONFIG_COMEDI is not set
++# CONFIG_ASUS_OLED is not set
++# CONFIG_R8187SE is not set
++# CONFIG_RTL8192U is not set
++# CONFIG_RTLLIB is not set
++# CONFIG_R8712U is not set
++# CONFIG_RTS5139 is not set
++# CONFIG_TRANZPORT is not set
++# CONFIG_LINE6_USB is not set
++# CONFIG_USB_SERIAL_QUATECH2 is not set
++# CONFIG_VT6655 is not set
++# CONFIG_VT6656 is not set
++# CONFIG_DX_SEP is not set
++
++#
++# IIO staging drivers
++#
++
++#
++# Accelerometers
++#
++# CONFIG_ADIS16201 is not set
++# CONFIG_ADIS16203 is not set
++# CONFIG_ADIS16204 is not set
++# CONFIG_ADIS16209 is not set
++# CONFIG_ADIS16220 is not set
++# CONFIG_ADIS16240 is not set
++# CONFIG_LIS3L02DQ is not set
++# CONFIG_SCA3000 is not set
++
++#
++# Analog to digital converters
++#
++# CONFIG_AD7291 is not set
++# CONFIG_AD7606 is not set
++# CONFIG_AD799X is not set
++# CONFIG_AD7780 is not set
++# CONFIG_AD7816 is not set
++# CONFIG_AD7192 is not set
++# CONFIG_AD7280 is not set
++
++#
++# Analog digital bi-direction converters
++#
++# CONFIG_ADT7316 is not set
++
++#
++# Capacitance to digital converters
++#
++# CONFIG_AD7150 is not set
++# CONFIG_AD7152 is not set
++# CONFIG_AD7746 is not set
++
++#
++# Direct Digital Synthesis
++#
++# CONFIG_AD5930 is not set
++# CONFIG_AD9832 is not set
++# CONFIG_AD9834 is not set
++# CONFIG_AD9850 is not set
++# CONFIG_AD9852 is not set
++# CONFIG_AD9910 is not set
++# CONFIG_AD9951 is not set
++
++#
++# Digital gyroscope sensors
++#
++# CONFIG_ADIS16060 is not set
++# CONFIG_ADIS16130 is not set
++# CONFIG_ADIS16260 is not set
++
++#
++# Network Analyzer, Impedance Converters
++#
++# CONFIG_AD5933 is not set
++
++#
++# Light sensors
++#
++# CONFIG_SENSORS_ISL29018 is not set
++# CONFIG_SENSORS_ISL29028 is not set
++# CONFIG_TSL2583 is not set
++# CONFIG_TSL2x7x is not set
++
++#
++# Magnetometer sensors
++#
++# CONFIG_SENSORS_HMC5843 is not set
++
++#
++# Active energy metering IC
++#
++# CONFIG_ADE7753 is not set
++# CONFIG_ADE7754 is not set
++# CONFIG_ADE7758 is not set
++# CONFIG_ADE7759 is not set
++# CONFIG_ADE7854 is not set
++
++#
++# Resolver to digital converters
++#
++# CONFIG_AD2S90 is not set
++# CONFIG_AD2S1200 is not set
++# CONFIG_AD2S1210 is not set
++
++#
++# Triggers - standalone
++#
++# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set
++# CONFIG_IIO_GPIO_TRIGGER is not set
++CONFIG_IIO_SYSFS_TRIGGER=m
++# CONFIG_IIO_SIMPLE_DUMMY is not set
++# CONFIG_ZSMALLOC is not set
++# CONFIG_FB_SM7XX is not set
++# CONFIG_CRYSTALHD is not set
++# CONFIG_FB_XGI is not set
++# CONFIG_USB_ENESTORAGE is not set
++# CONFIG_BCM_WIMAX is not set
++# CONFIG_FT1000 is not set
++
++#
++# Speakup console speech
++#
++# CONFIG_SPEAKUP is not set
++# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set
++# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set
++# CONFIG_STAGING_MEDIA is not set
++
++#
++# Android
++#
++# CONFIG_ANDROID is not set
++# CONFIG_USB_WPAN_HCD is not set
++# CONFIG_WIMAX_GDM72XX is not set
++# CONFIG_CSR_WIFI is not set
++# CONFIG_NET_VENDOR_SILICOM is not set
++# CONFIG_CED1401 is not set
++# CONFIG_DGRP is not set
++# CONFIG_USB_DWC2 is not set
++CONFIG_X86_PLATFORM_DEVICES=y
++# CONFIG_CHROMEOS_LAPTOP is not set
++# CONFIG_AMILO_RFKILL is not set
++# CONFIG_SENSORS_HDAPS is not set
++CONFIG_INTEL_SCU_IPC=y
++CONFIG_INTEL_SCU_IPC_INTR_MODE=y
++# CONFIG_INTEL_SCU_IPC_POLL_MODE is not set
++CONFIG_INTEL_SCU_IPC_UTIL=y
++CONFIG_GPIO_INTEL_PMIC=y
++CONFIG_INTEL_MID_POWER_BUTTON=y
++# CONFIG_INTEL_MFLD_THERMAL is not set
++# CONFIG_IBM_RTL is not set
++# CONFIG_SAMSUNG_LAPTOP is not set
++CONFIG_INTEL_SCU_FLIS=y
++
++#
++# Hardware Spinlock drivers
++#
++CONFIG_CLKSRC_I8253=y
++CONFIG_CLKEVT_I8253=y
++CONFIG_I8253_LOCK=y
++CONFIG_CLKBLD_I8253=y
++# CONFIG_MAILBOX is not set
++CONFIG_IOMMU_SUPPORT=y
++
++#
++# Remoteproc drivers
++#
++CONFIG_REMOTEPROC=y
++# CONFIG_STE_MODEM_RPROC is not set
++CONFIG_INTEL_MID_REMOTEPROC=y
++
++#
++# Rpmsg drivers
++#
++CONFIG_RPMSG=y
++CONFIG_RPMSG_IPC=y
++CONFIG_PM_DEVFREQ=y
++
++#
++# DEVFREQ Governors
++#
++CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y
++CONFIG_DEVFREQ_GOV_PERFORMANCE=y
++CONFIG_DEVFREQ_GOV_POWERSAVE=y
++CONFIG_DEVFREQ_GOV_USERSPACE=y
++
++#
++# DEVFREQ Drivers
++#
++CONFIG_EXTCON=y
++
++#
++# Extcon Device Drivers
++#
++# CONFIG_EXTCON_GPIO is not set
++# CONFIG_EXTCON_ADC_JACK is not set
++# CONFIG_MEMORY is not set
++CONFIG_IIO=y
++CONFIG_IIO_BUFFER=y
++# CONFIG_IIO_BUFFER_CB is not set
++CONFIG_IIO_KFIFO_BUF=y
++CONFIG_IIO_TRIGGERED_BUFFER=y
++CONFIG_IIO_TRIGGER=y
++CONFIG_IIO_CONSUMERS_PER_TRIGGER=2
++
++#
++# Accelerometers
++#
++# CONFIG_KXSD9 is not set
++# CONFIG_IIO_ST_ACCEL_3AXIS is not set
++
++#
++# Analog to digital converters
++#
++# CONFIG_AD7266 is not set
++# CONFIG_AD7298 is not set
++# CONFIG_AD7923 is not set
++# CONFIG_AD7791 is not set
++# CONFIG_AD7793 is not set
++# CONFIG_AD7476 is not set
++# CONFIG_AD7887 is not set
++# CONFIG_MAX1363 is not set
++# CONFIG_TI_ADC081C is not set
++CONFIG_TI_ADS7955_ADC=y
++CONFIG_IIO_BASINCOVE_GPADC=y
++
++#
++# Amplifiers
++#
++# CONFIG_AD8366 is not set
++
++#
++# Hid Sensor IIO Common
++#
++
++#
++# Digital to analog converters
++#
++# CONFIG_AD5064 is not set
++# CONFIG_AD5360 is not set
++# CONFIG_AD5380 is not set
++# CONFIG_AD5421 is not set
++# CONFIG_AD5624R_SPI is not set
++# CONFIG_AD5446 is not set
++# CONFIG_AD5449 is not set
++# CONFIG_AD5504 is not set
++# CONFIG_AD5755 is not set
++# CONFIG_AD5764 is not set
++# CONFIG_AD5791 is not set
++# CONFIG_AD5686 is not set
++# CONFIG_MAX517 is not set
++# CONFIG_MCP4725 is not set
++
++#
++# Frequency Synthesizers DDS/PLL
++#
++
++#
++# Clock Generator/Distribution
++#
++# CONFIG_AD9523 is not set
++
++#
++# Phase-Locked Loop (PLL) frequency synthesizers
++#
++# CONFIG_ADF4350 is not set
++
++#
++# Digital gyroscope sensors
++#
++# CONFIG_ADIS16080 is not set
++# CONFIG_ADIS16136 is not set
++# CONFIG_ADXRS450 is not set
++# CONFIG_IIO_ST_GYRO_3AXIS is not set
++# CONFIG_ITG3200 is not set
++
++#
++# Inertial measurement units
++#
++# CONFIG_ADIS16400 is not set
++# CONFIG_ADIS16480 is not set
++# CONFIG_INV_MPU6050_IIO is not set
++
++#
++# Light sensors
++#
++# CONFIG_ADJD_S311 is not set
++# CONFIG_SENSORS_TSL2563 is not set
++# CONFIG_VCNL4000 is not set
++
++#
++# Magnetometer sensors
++#
++# CONFIG_AK8975 is not set
++# CONFIG_IIO_ST_MAGN_3AXIS is not set
++# CONFIG_VME_BUS is not set
++CONFIG_PWM=y
++CONFIG_PWM_SYSFS=y
++CONFIG_PWM_INTEL_MID=y
++# CONFIG_IPACK_BUS is not set
++# CONFIG_RESET_CONTROLLER is not set
++
++#
++# Firmware Drivers
++#
++# CONFIG_EDD is not set
++CONFIG_FIRMWARE_MEMMAP=y
++# CONFIG_DELL_RBU is not set
++# CONFIG_DCDBAS is not set
++CONFIG_DMIID=y
++# CONFIG_DMI_SYSFS is not set
++# CONFIG_ISCSI_IBFT_FIND is not set
++# CONFIG_GOOGLE_FIRMWARE is not set
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++CONFIG_EXT2_FS=y
++# CONFIG_EXT2_FS_XATTR is not set
++# CONFIG_EXT2_FS_XIP is not set
++CONFIG_EXT3_FS=y
++# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
++CONFIG_EXT3_FS_XATTR=y
++CONFIG_EXT3_FS_POSIX_ACL=y
++CONFIG_EXT3_FS_SECURITY=y
++CONFIG_EXT4_FS=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++CONFIG_EXT4_FS_SECURITY=y
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY_USER=y
++CONFIG_FANOTIFY=y
++# CONFIG_FANOTIFY_ACCESS_PERMISSIONS is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++CONFIG_AUTOFS4_FS=y
++CONFIG_FUSE_FS=y
++# CONFIG_CUSE is not set
++CONFIG_GENERIC_ACL=y
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++# CONFIG_VFAT_FS_NO_DUALNAMES is not set
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_VFAT_NO_CREATE_WITH_LONGNAMES is not set
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++# CONFIG_PROC_KCORE is not set
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++CONFIG_TMPFS_POSIX_ACL=y
++CONFIG_TMPFS_XATTR=y
++# CONFIG_HUGETLBFS is not set
++# CONFIG_HUGETLB_PAGE is not set
++CONFIG_CONFIGFS_FS=y
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_ECRYPT_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_LOGFS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_SQUASHFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX6FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_PSTORE=y
++CONFIG_PSTORE_CONSOLE=y
++CONFIG_PSTORE_FTRACE=y
++CONFIG_PSTORE_RAM=y
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_F2FS_FS is not set
++# CONFIG_AUFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_DEF_FILE_IO_SIZE=4096
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++CONFIG_NFS_V4=y
++# CONFIG_NFS_SWAP is not set
++# CONFIG_NFS_V4_1 is not set
++# CONFIG_NFS_USE_LEGACY_DNS is not set
++CONFIG_NFS_USE_KERNEL_DNS=y
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++CONFIG_SUNRPC_GSS=y
++# CONFIG_SUNRPC_DEBUG is not set
++# CONFIG_CEPH_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="utf8"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++CONFIG_NLS_ASCII=y
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_MAC_ROMAN is not set
++# CONFIG_NLS_MAC_CELTIC is not set
++# CONFIG_NLS_MAC_CENTEURO is not set
++# CONFIG_NLS_MAC_CROATIAN is not set
++# CONFIG_NLS_MAC_CYRILLIC is not set
++# CONFIG_NLS_MAC_GAELIC is not set
++# CONFIG_NLS_MAC_GREEK is not set
++# CONFIG_NLS_MAC_ICELAND is not set
++# CONFIG_NLS_MAC_INUIT is not set
++# CONFIG_NLS_MAC_ROMANIAN is not set
++# CONFIG_NLS_MAC_TURKISH is not set
++CONFIG_NLS_UTF8=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_PRINTK_TIME=y
++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=2048
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_SECTION_MISMATCH=y
++CONFIG_DEBUG_KERNEL=y
++CONFIG_DEBUG_SHIRQ=y
++CONFIG_LOCKUP_DETECTOR=y
++CONFIG_HARDLOCKUP_DETECTOR=y
++CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y
++CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=1
++CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
++CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=1
++# CONFIG_PANIC_ON_OOPS is not set
++CONFIG_PANIC_ON_OOPS_VALUE=0
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
++# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
++CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
++CONFIG_SCHED_DEBUG=y
++CONFIG_SCHEDSTATS=y
++CONFIG_TIMER_STATS=y
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_SLUB_DEBUG_ON is not set
++# CONFIG_SLUB_STATS is not set
++CONFIG_HAVE_DEBUG_KMEMLEAK=y
++CONFIG_DEBUG_KMEMLEAK=y
++CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=400
++# CONFIG_DEBUG_KMEMLEAK_TEST is not set
++CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
++CONFIG_DEBUG_PREEMPT=y
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++CONFIG_DEBUG_SPINLOCK=y
++CONFIG_DEBUG_MUTEXES=y
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++CONFIG_TRACE_IRQFLAGS=y
++CONFIG_DEBUG_ATOMIC_SLEEP=y
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++CONFIG_STACKTRACE=y
++CONFIG_DEBUG_STACK_USAGE=y
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_HIGHMEM is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_INFO_REDUCED is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_VIRTUAL is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++CONFIG_DEBUG_LIST=y
++CONFIG_TEST_LIST_SORT=y
++CONFIG_DEBUG_SG=y
++CONFIG_DEBUG_NOTIFIERS=y
++# CONFIG_DEBUG_CREDENTIALS is not set
++CONFIG_ARCH_WANT_FRAME_POINTERS=y
++CONFIG_FRAME_POINTER=y
++CONFIG_BOOT_PRINTK_DELAY=y
++
++#
++# RCU Debugging
++#
++# CONFIG_PROVE_RCU_DELAY is not set
++CONFIG_SPARSE_RCU_POINTER=y
++# CONFIG_RCU_TORTURE_TEST is not set
++CONFIG_RCU_CPU_STALL_TIMEOUT=60
++CONFIG_RCU_CPU_STALL_VERBOSE=y
++CONFIG_RCU_CPU_STALL_INFO=y
++# CONFIG_RCU_TRACE is not set
++# CONFIG_KPROBES_SANITY_TEST is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_DEBUG_PER_CPU_MAPS is not set
++# CONFIG_LKDTM is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP is not set
++CONFIG_ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS=y
++# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set
++# CONFIG_DEBUG_PAGEALLOC is not set
++CONFIG_USER_STACKTRACE_SUPPORT=y
++CONFIG_NOP_TRACER=y
++CONFIG_HAVE_FUNCTION_TRACER=y
++CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
++CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST=y
++CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
++CONFIG_HAVE_DYNAMIC_FTRACE=y
++CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
++CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
++CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
++CONFIG_HAVE_C_RECORDMCOUNT=y
++CONFIG_TRACER_MAX_TRACE=y
++CONFIG_TRACE_CLOCK=y
++CONFIG_RING_BUFFER=y
++CONFIG_EVENT_TRACING=y
++CONFIG_CONTEXT_SWITCH_TRACER=y
++CONFIG_RING_BUFFER_ALLOW_SWAP=y
++CONFIG_TRACING=y
++CONFIG_GENERIC_TRACER=y
++CONFIG_TRACING_SUPPORT=y
++CONFIG_FTRACE=y
++CONFIG_FUNCTION_TRACER=y
++CONFIG_FUNCTION_GRAPH_TRACER=y
++CONFIG_IRQSOFF_TRACER=y
++CONFIG_PREEMPT_TRACER=y
++CONFIG_SCHED_TRACER=y
++CONFIG_FTRACE_SYSCALLS=y
++CONFIG_TRACER_SNAPSHOT=y
++CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP=y
++CONFIG_BRANCH_PROFILE_NONE=y
++# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
++# CONFIG_PROFILE_ALL_BRANCHES is not set
++# CONFIG_STACK_TRACER is not set
++CONFIG_BLK_DEV_IO_TRACE=y
++# CONFIG_KPROBE_EVENT is not set
++# CONFIG_UPROBE_EVENT is not set
++# CONFIG_PROBE_EVENTS is not set
++CONFIG_DYNAMIC_FTRACE=y
++CONFIG_DYNAMIC_FTRACE_WITH_REGS=y
++CONFIG_FUNCTION_PROFILER=y
++CONFIG_FTRACE_MCOUNT_RECORD=y
++# CONFIG_FTRACE_STARTUP_TEST is not set
++# CONFIG_MMIOTRACE is not set
++# CONFIG_RING_BUFFER_BENCHMARK is not set
++# CONFIG_RING_BUFFER_STARTUP_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
++CONFIG_DYNAMIC_DEBUG=y
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++CONFIG_HAVE_ARCH_KMEMCHECK=y
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_STRICT_DEVMEM is not set
++CONFIG_X86_VERBOSE_BOOTUP=y
++CONFIG_EARLY_PRINTK=y
++CONFIG_EARLY_PRINTK_INTEL_MID=y
++# CONFIG_EARLY_PRINTK_DBGP is not set
++CONFIG_DEBUG_STACKOVERFLOW=y
++# CONFIG_X86_PTDUMP is not set
++CONFIG_DEBUG_RODATA=y
++# CONFIG_DEBUG_RODATA_TEST is not set
++CONFIG_DEBUG_SET_MODULE_RONX=y
++CONFIG_DEBUG_NX_TEST=m
++CONFIG_DOUBLEFAULT=y
++# CONFIG_DEBUG_TLBFLUSH is not set
++# CONFIG_IOMMU_STRESS is not set
++CONFIG_HAVE_MMIOTRACE_SUPPORT=y
++# CONFIG_X86_DECODER_SELFTEST is not set
++CONFIG_IO_DELAY_TYPE_0X80=0
++CONFIG_IO_DELAY_TYPE_0XED=1
++CONFIG_IO_DELAY_TYPE_UDELAY=2
++CONFIG_IO_DELAY_TYPE_NONE=3
++CONFIG_IO_DELAY_0X80=y
++# CONFIG_IO_DELAY_0XED is not set
++# CONFIG_IO_DELAY_UDELAY is not set
++# CONFIG_IO_DELAY_NONE is not set
++CONFIG_DEFAULT_IO_DELAY_TYPE=0
++CONFIG_DEBUG_BOOT_PARAMS=y
++# CONFIG_CPA_DEBUG is not set
++CONFIG_OPTIMIZE_INLINING=y
++# CONFIG_DEBUG_NMI_SELFTEST is not set
++
++#
++# Security options
++#
++CONFIG_KEYS=y
++# CONFIG_ENCRYPTED_KEYS is not set
++CONFIG_KEYS_DEBUG_PROC_KEYS=y
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++CONFIG_SECURITY=y
++# CONFIG_SECURITYFS is not set
++CONFIG_SECURITY_NETWORK=y
++# CONFIG_SECURITY_NETWORK_XFRM is not set
++# CONFIG_SECURITY_PATH is not set
++CONFIG_LSM_MMAP_MIN_ADDR=65536
++CONFIG_SECURITY_SELINUX=y
++CONFIG_SECURITY_SELINUX_BOOTPARAM=y
++CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=1
++CONFIG_SECURITY_SELINUX_DISABLE=y
++CONFIG_SECURITY_SELINUX_DEVELOP=y
++CONFIG_SECURITY_SELINUX_AVC_STATS=y
++CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
++# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set
++# CONFIG_SECURITY_SMACK is not set
++# CONFIG_SECURITY_TOMOYO is not set
++# CONFIG_SECURITY_APPARMOR is not set
++# CONFIG_SECURITY_YAMA is not set
++# CONFIG_IMA is not set
++# CONFIG_EVM is not set
++CONFIG_DEFAULT_SECURITY_SELINUX=y
++# CONFIG_DEFAULT_SECURITY_DAC is not set
++CONFIG_DEFAULT_SECURITY="selinux"
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++# CONFIG_CRYPTODEV is not set
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_PCOMP2=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_USER is not set
++CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
++CONFIG_CRYPTO_GF128MUL=y
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_PCRYPT is not set
++CONFIG_CRYPTO_WORKQUEUE=y
++CONFIG_CRYPTO_CRYPTD=y
++CONFIG_CRYPTO_AUTHENC=y
++# CONFIG_CRYPTO_TEST is not set
++CONFIG_CRYPTO_ABLK_HELPER_X86=y
++
++#
++# Authenticated Encryption with Associated Data
++#
++CONFIG_CRYPTO_CCM=y
++# CONFIG_CRYPTO_GCM is not set
++CONFIG_CRYPTO_SEQIV=y
++
++#
++# Block modes
++#
++CONFIG_CRYPTO_CBC=y
++CONFIG_CRYPTO_CTR=y
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=y
++CONFIG_CRYPTO_LRW=y
++# CONFIG_CRYPTO_PCBC is not set
++CONFIG_CRYPTO_XTS=y
++
++#
++# Hash modes
++#
++# CONFIG_CRYPTO_CMAC is not set
++CONFIG_CRYPTO_HMAC=y
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32C_INTEL is not set
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRC32_PCLMUL is not set
++# CONFIG_CRYPTO_GHASH is not set
++# CONFIG_CRYPTO_MD4 is not set
++CONFIG_CRYPTO_MD5=y
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++CONFIG_CRYPTO_SHA1=y
++CONFIG_CRYPTO_SHA256=y
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++CONFIG_CRYPTO_AES=y
++CONFIG_CRYPTO_AES_586=y
++CONFIG_CRYPTO_AES_NI_INTEL=y
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++CONFIG_CRYPTO_DES=y
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SALSA20_586 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_SERPENT_SSE2_586 is not set
++# CONFIG_CRYPTO_TEA is not set
++CONFIG_CRYPTO_TWOFISH=y
++CONFIG_CRYPTO_TWOFISH_COMMON=y
++CONFIG_CRYPTO_TWOFISH_586=y
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_CRYPTO_DEV_PADLOCK is not set
++# CONFIG_CRYPTO_DEV_GEODE is not set
++CONFIG_ASYMMETRIC_KEY_TYPE=y
++CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
++CONFIG_PUBLIC_KEY_ALGO_RSA=y
++CONFIG_X509_CERTIFICATE_PARSER=y
++CONFIG_HAVE_KVM=y
++CONFIG_VIRTUALIZATION=y
++# CONFIG_KVM is not set
++# CONFIG_LGUEST is not set
++CONFIG_BINARY_PRINTF=y
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_FIND_FIRST_BIT=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_CRC_CCITT=y
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC32_SELFTEST is not set
++# CONFIG_CRC32_SLICEBY8 is not set
++# CONFIG_CRC32_SLICEBY4 is not set
++# CONFIG_CRC32_SARWATE is not set
++CONFIG_CRC32_BIT=y
++# CONFIG_CRC7 is not set
++CONFIG_LIBCRC32C=y
++# CONFIG_CRC8 is not set
++CONFIG_AUDIT_GENERIC=y
++CONFIG_ZLIB_INFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_REED_SOLOMON=y
++CONFIG_REED_SOLOMON_ENC8=y
++CONFIG_REED_SOLOMON_DEC8=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_CPU_RMAP=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
++CONFIG_AVERAGE=y
++CONFIG_CLZ_TAB=y
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_MPILIB=y
++CONFIG_OID_REGISTRY=y
+diff --git a/arch/x86/configs/i386_mrfl_defconfig b/arch/x86/configs/i386_mrfl_defconfig
+new file mode 100644
+index 0000000..db31fcc
+--- /dev/null
++++ b/arch/x86/configs/i386_mrfl_defconfig
+@@ -0,0 +1,3980 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/i386 3.10.17 Kernel Configuration
++#
++# CONFIG_64BIT is not set
++CONFIG_X86_32=y
++CONFIG_X86=y
++CONFIG_INSTRUCTION_DECODER=y
++CONFIG_OUTPUT_FORMAT="elf32-i386"
++CONFIG_ARCH_DEFCONFIG="arch/x86/configs/i386_defconfig"
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_MMU=y
++CONFIG_NEED_SG_DMA_LENGTH=y
++CONFIG_GENERIC_ISA_DMA=y
++CONFIG_GENERIC_BUG=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_ARCH_MAY_HAVE_PC_FDC=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_ARCH_HAS_CPU_RELAX=y
++CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
++CONFIG_ARCH_HAS_CPU_AUTOPROBE=y
++CONFIG_HAVE_SETUP_PER_CPU_AREA=y
++CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
++CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=y
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++# CONFIG_ZONE_DMA32 is not set
++# CONFIG_AUDIT_ARCH is not set
++CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
++CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
++CONFIG_X86_32_SMP=y
++CONFIG_X86_HT=y
++CONFIG_X86_32_LAZY_GS=y
++CONFIG_ARCH_HWEIGHT_CFLAGS="-fcall-saved-ecx -fcall-saved-edx"
++CONFIG_ARCH_CPU_PROBE_RELEASE=y
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_BZIP2=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_BZIP2 is not set
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_POSIX_MQUEUE_SYSCTL=y
++# CONFIG_FHANDLE is not set
++CONFIG_AUDIT=y
++CONFIG_AUDITSYSCALL=y
++CONFIG_AUDIT_WATCH=y
++CONFIG_AUDIT_TREE=y
++# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set
++CONFIG_HAVE_GENERIC_HARDIRQS=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_GENERIC_PENDING_IRQ=y
++CONFIG_IRQ_DOMAIN=y
++# CONFIG_IRQ_DOMAIN_DEBUG is not set
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_CLOCKSOURCE_WATCHDOG=y
++CONFIG_KTIME_SCALAR=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
++CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y
++CONFIG_GENERIC_CMOS_UPDATE=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ_COMMON=y
++# CONFIG_HZ_PERIODIC is not set
++CONFIG_NO_HZ_IDLE=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++
++#
++# CPU/Task time and stats accounting
++#
++# CONFIG_TICK_CPU_ACCOUNTING is not set
++CONFIG_IRQ_TIME_ACCOUNTING=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++CONFIG_TASKSTATS=y
++CONFIG_TASK_DELAY_ACCT=y
++CONFIG_TASK_XACCT=y
++CONFIG_TASK_IO_ACCOUNTING=y
++
++#
++# RCU Subsystem
++#
++CONFIG_TREE_PREEMPT_RCU=y
++CONFIG_PREEMPT_RCU=y
++CONFIG_RCU_STALL_COMMON=y
++CONFIG_RCU_FANOUT=32
++CONFIG_RCU_FANOUT_LEAF=16
++# CONFIG_RCU_FANOUT_EXACT is not set
++# CONFIG_RCU_FAST_NO_HZ is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_BOOST is not set
++# CONFIG_RCU_NOCB_CPU is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=18
++CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
++CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y
++CONFIG_ARCH_WANTS_PROT_NUMA_PROT_NONE=y
++CONFIG_CGROUPS=y
++# CONFIG_CGROUP_DEBUG is not set
++CONFIG_CGROUP_FREEZER=y
++CONFIG_CGROUP_DEVICE=y
++CONFIG_CPUSETS=y
++CONFIG_PROC_PID_CPUSET=y
++CONFIG_CGROUP_CPUACCT=y
++CONFIG_RESOURCE_COUNTERS=y
++# CONFIG_MEMCG is not set
++CONFIG_CGROUP_PERF=y
++CONFIG_CGROUP_SCHED=y
++CONFIG_FAIR_GROUP_SCHED=y
++# CONFIG_CFS_BANDWIDTH is not set
++CONFIG_RT_GROUP_SCHED=y
++CONFIG_BLK_CGROUP=y
++# CONFIG_DEBUG_BLK_CGROUP is not set
++# CONFIG_CHECKPOINT_RESTORE is not set
++CONFIG_NAMESPACES=y
++# CONFIG_UTS_NS is not set
++# CONFIG_IPC_NS is not set
++# CONFIG_USER_NS is not set
++# CONFIG_PID_NS is not set
++# CONFIG_NET_NS is not set
++CONFIG_UIDGID_CONVERTED=y
++# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set
++CONFIG_SCHED_AUTOGROUP=y
++CONFIG_SYSFS_DEPRECATED=y
++# CONFIG_SYSFS_DEPRECATED_V2 is not set
++CONFIG_RELAY=y
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_RD_GZIP=y
++# CONFIG_RD_BZIP2 is not set
++# CONFIG_RD_LZMA is not set
++# CONFIG_RD_XZ is not set
++# CONFIG_RD_LZO is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_SYSCTL_EXCEPTION_TRACE=y
++CONFIG_HOTPLUG=y
++CONFIG_HAVE_PCSPKR_PLATFORM=y
++CONFIG_EXPERT=y
++# CONFIG_UPTIME_LIMITED_KERNEL is not set
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_PCSPKR_PLATFORM=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_PCI_QUIRKS=y
++CONFIG_EMBEDDED=y
++CONFIG_HAVE_PERF_EVENTS=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_SLUB_DEBUG=y
++# CONFIG_COMPAT_BRK is not set
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++# CONFIG_SLOB is not set
++CONFIG_PROFILING=y
++CONFIG_TRACEPOINTS=y
++CONFIG_OPROFILE=y
++# CONFIG_OPROFILE_EVENT_MULTIPLEX is not set
++CONFIG_HAVE_OPROFILE=y
++CONFIG_OPROFILE_NMI_TIMER=y
++CONFIG_KPROBES=y
++# CONFIG_JUMP_LABEL is not set
++CONFIG_KPROBES_ON_FTRACE=y
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_ARCH_USE_BUILTIN_BSWAP=y
++CONFIG_KRETPROBES=y
++CONFIG_HAVE_IOREMAP_PROT=y
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_OPTPROBES=y
++CONFIG_HAVE_KPROBES_ON_FTRACE=y
++CONFIG_HAVE_ARCH_TRACEHOOK=y
++CONFIG_HAVE_DMA_ATTRS=y
++CONFIG_HAVE_DMA_CONTIGUOUS=y
++CONFIG_USE_GENERIC_SMP_HELPERS=y
++CONFIG_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_HW_BREAKPOINT=y
++CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y
++CONFIG_HAVE_USER_RETURN_NOTIFIER=y
++CONFIG_HAVE_PERF_EVENTS_NMI=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
++CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
++CONFIG_HAVE_CMPXCHG_LOCAL=y
++CONFIG_HAVE_CMPXCHG_DOUBLE=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_GCOV_KERNEL is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_MODULE_SIG=y
++CONFIG_MODULE_SIG_FORCE=y
++CONFIG_MODULE_SIG_ALL=y
++# CONFIG_MODULE_SIG_SHA1 is not set
++# CONFIG_MODULE_SIG_SHA224 is not set
++CONFIG_MODULE_SIG_SHA256=y
++# CONFIG_MODULE_SIG_SHA384 is not set
++# CONFIG_MODULE_SIG_SHA512 is not set
++CONFIG_MODULE_SIG_HASH="sha256"
++CONFIG_STOP_MACHINE=y
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++CONFIG_BLK_DEV_THROTTLING=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++CONFIG_OSF_PARTITION=y
++# CONFIG_AMIGA_PARTITION is not set
++# CONFIG_ATARI_PARTITION is not set
++# CONFIG_MAC_PARTITION is not set
++CONFIG_MSDOS_PARTITION=y
++CONFIG_BSD_DISKLABEL=y
++CONFIG_MINIX_SUBPARTITION=y
++CONFIG_SOLARIS_X86_PARTITION=y
++CONFIG_UNIXWARE_DISKLABEL=y
++# CONFIG_LDM_PARTITION is not set
++CONFIG_SGI_PARTITION=y
++# CONFIG_ULTRIX_PARTITION is not set
++CONFIG_SUN_PARTITION=y
++# CONFIG_KARMA_PARTITION is not set
++CONFIG_EFI_PARTITION=y
++# CONFIG_SYSV68_PARTITION is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++# CONFIG_IOSCHED_DEADLINE is not set
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_CFQ_GROUP_IOSCHED is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++CONFIG_ASN1=y
++CONFIG_UNINLINE_SPIN_UNLOCK=y
++CONFIG_FREEZER=y
++
++#
++# Processor type and features
++#
++CONFIG_ZONE_DMA=y
++CONFIG_SMP=y
++CONFIG_X86_MPPARSE=y
++# CONFIG_X86_BIGSMP is not set
++CONFIG_X86_EXTENDED_PLATFORM=y
++# CONFIG_X86_GOLDFISH is not set
++CONFIG_X86_WANT_INTEL_MID=y
++CONFIG_X86_INTEL_MID=y
++# CONFIG_X86_MDFLD is not set
++CONFIG_ATOM_SOC_POWER=y
++# CONFIG_REMOVEME_INTEL_ATOM_MDFLD_POWER is not set
++# CONFIG_REMOVEME_INTEL_ATOM_CLV_POWER is not set
++CONFIG_REMOVEME_INTEL_ATOM_MRFLD_POWER=y
++CONFIG_INTEL_DEBUG_FEATURE=y
++# CONFIG_X86_RDC321X is not set
++# CONFIG_X86_32_NON_STANDARD is not set
++CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y
++# CONFIG_X86_32_IRIS is not set
++# CONFIG_SCHED_OMIT_FRAME_POINTER is not set
++# CONFIG_HYPERVISOR_GUEST is not set
++CONFIG_NO_BOOTMEM=y
++# CONFIG_MEMTEST is not set
++# CONFIG_M486 is not set
++# CONFIG_M586 is not set
++# CONFIG_M586TSC is not set
++# CONFIG_M586MMX is not set
++# CONFIG_M686 is not set
++# CONFIG_MPENTIUMII is not set
++# CONFIG_MPENTIUMIII is not set
++# CONFIG_MPENTIUMM is not set
++# CONFIG_MPENTIUM4 is not set
++# CONFIG_MK6 is not set
++# CONFIG_MK7 is not set
++# CONFIG_MK8 is not set
++# CONFIG_MCRUSOE is not set
++# CONFIG_MEFFICEON is not set
++# CONFIG_MWINCHIPC6 is not set
++# CONFIG_MWINCHIP3D is not set
++# CONFIG_MELAN is not set
++# CONFIG_MGEODEGX1 is not set
++# CONFIG_MGEODE_LX is not set
++# CONFIG_MCYRIXIII is not set
++# CONFIG_MVIAC3_2 is not set
++# CONFIG_MVIAC7 is not set
++# CONFIG_MCORE2 is not set
++# CONFIG_MATOM is not set
++CONFIG_MSLM=y
++CONFIG_X86_GENERIC=y
++CONFIG_X86_INTERNODE_CACHE_SHIFT=6
++CONFIG_X86_L1_CACHE_SHIFT=6
++CONFIG_X86_INTEL_USERCOPY=y
++CONFIG_X86_USE_PPRO_CHECKSUM=y
++CONFIG_X86_TSC=y
++CONFIG_X86_CMPXCHG64=y
++CONFIG_X86_CMOV=y
++CONFIG_X86_MINIMUM_CPU_FAMILY=5
++CONFIG_X86_DEBUGCTLMSR=y
++# CONFIG_PROCESSOR_SELECT is not set
++CONFIG_CPU_SUP_INTEL=y
++CONFIG_CPU_SUP_CYRIX_32=y
++CONFIG_CPU_SUP_AMD=y
++CONFIG_CPU_SUP_CENTAUR=y
++CONFIG_CPU_SUP_TRANSMETA_32=y
++CONFIG_CPU_SUP_UMC_32=y
++# CONFIG_HPET_TIMER is not set
++# CONFIG_APB_TIMER is not set
++CONFIG_DMI=y
++CONFIG_NR_CPUS=2
++CONFIG_SCHED_SMT=y
++CONFIG_SCHED_MC=y
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_COUNT=y
++CONFIG_X86_LOCAL_APIC=y
++CONFIG_X86_IO_APIC=y
++# CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set
++CONFIG_X86_MCE=y
++CONFIG_X86_MCE_INTEL=y
++# CONFIG_X86_MCE_AMD is not set
++# CONFIG_X86_ANCIENT_MCE is not set
++CONFIG_X86_MCE_THRESHOLD=y
++# CONFIG_X86_MCE_INJECT is not set
++CONFIG_X86_THERMAL_VECTOR=y
++CONFIG_VM86=y
++# CONFIG_TOSHIBA is not set
++# CONFIG_I8K is not set
++CONFIG_X86_REBOOTFIXUPS=y
++# CONFIG_MICROCODE is not set
++CONFIG_X86_MSR=y
++CONFIG_X86_CPUID=y
++# CONFIG_NOHIGHMEM is not set
++# CONFIG_HIGHMEM4G is not set
++CONFIG_HIGHMEM64G=y
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++CONFIG_HIGHMEM=y
++CONFIG_X86_PAE=y
++CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
++CONFIG_ARCH_DMA_ADDR_T_64BIT=y
++CONFIG_ARCH_FLATMEM_ENABLE=y
++CONFIG_ARCH_SPARSEMEM_ENABLE=y
++CONFIG_ARCH_SELECT_MEMORY_MODEL=y
++CONFIG_ILLEGAL_POINTER_VALUE=0
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++# CONFIG_SPARSEMEM_MANUAL is not set
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_SPARSEMEM_STATIC=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
++CONFIG_ARCH_DISCARD_MEMBLOCK=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=999999
++# CONFIG_COMPACTION is not set
++CONFIG_PHYS_ADDR_T_64BIT=y
++CONFIG_ZONE_DMA_FLAG=1
++CONFIG_BOUNCE=y
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
++CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y
++# CONFIG_MEMORY_FAILURE is not set
++# CONFIG_TRANSPARENT_HUGEPAGE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++# CONFIG_CLEANCACHE is not set
++# CONFIG_HIGHPTE is not set
++CONFIG_X86_CHECK_BIOS_CORRUPTION=y
++# CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK is not set
++CONFIG_X86_RESERVE_LOW=64
++# CONFIG_MATH_EMULATION is not set
++CONFIG_MTRR=y
++CONFIG_MTRR_SANITIZER=y
++CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=1
++CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=1
++CONFIG_X86_PAT=y
++CONFIG_ARCH_USES_PG_UNCACHED=y
++# CONFIG_ARCH_RANDOM is not set
++CONFIG_X86_SMAP=y
++# CONFIG_SECCOMP is not set
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_HZ_100=y
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=100
++CONFIG_SCHED_HRTICK=y
++CONFIG_KEXEC=y
++# CONFIG_CRASH_DUMP is not set
++CONFIG_PHYSICAL_START=0x1200000
++# CONFIG_RELOCATABLE is not set
++CONFIG_PHYSICAL_ALIGN=0x100000
++CONFIG_HOTPLUG_CPU=y
++# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set
++# CONFIG_DEBUG_HOTPLUG_CPU0 is not set
++# CONFIG_COMPAT_VDSO is not set
++# CONFIG_CMDLINE_BOOL is not set
++CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
++
++#
++# Power management and ACPI options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_PM_SLEEP=y
++CONFIG_PM_SLEEP_SMP=y
++# CONFIG_PM_AUTOSLEEP is not set
++CONFIG_PM_WAKELOCKS=y
++CONFIG_PM_WAKELOCKS_LIMIT=100
++CONFIG_PM_WAKELOCKS_GC=y
++CONFIG_PM_RUNTIME=y
++CONFIG_PM=y
++CONFIG_PM_DEBUG=y
++CONFIG_PM_ADVANCED_DEBUG=y
++# CONFIG_PM_TEST_SUSPEND is not set
++CONFIG_PM_SLEEP_DEBUG=y
++# CONFIG_PM_TRACE_RTC is not set
++# CONFIG_ACPI is not set
++CONFIG_SFI=y
++# CONFIG_APM is not set
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_TABLE=y
++CONFIG_CPU_FREQ_GOV_COMMON=y
++CONFIG_CPU_FREQ_STAT=y
++CONFIG_CPU_FREQ_STAT_DETAILS=y
++CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++
++#
++# x86 CPU frequency scaling drivers
++#
++# CONFIG_X86_INTEL_PSTATE is not set
++CONFIG_X86_SFI_CPUFREQ=y
++# CONFIG_X86_POWERNOW_K6 is not set
++# CONFIG_X86_POWERNOW_K7 is not set
++# CONFIG_X86_GX_SUSPMOD is not set
++# CONFIG_X86_SPEEDSTEP_CENTRINO is not set
++# CONFIG_X86_SPEEDSTEP_ICH is not set
++# CONFIG_X86_SPEEDSTEP_SMI is not set
++# CONFIG_X86_P4_CLOCKMOD is not set
++# CONFIG_X86_CPUFREQ_NFORCE2 is not set
++# CONFIG_X86_LONGRUN is not set
++
++#
++# shared options
++#
++# CONFIG_X86_SPEEDSTEP_LIB is not set
++CONFIG_CPU_IDLE=y
++# CONFIG_CPU_IDLE_MULTIPLE_DRIVERS is not set
++CONFIG_CPU_IDLE_GOV_LADDER=y
++CONFIG_CPU_IDLE_GOV_MENU=y
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++CONFIG_INTEL_IDLE=y
++
++#
++# Bus options (PCI etc.)
++#
++CONFIG_PCI=y
++# CONFIG_PCI_GOBIOS is not set
++# CONFIG_PCI_GOMMCONFIG is not set
++# CONFIG_PCI_GODIRECT is not set
++CONFIG_PCI_GOANY=y
++CONFIG_PCI_BIOS=y
++CONFIG_PCI_DIRECT=y
++CONFIG_PCI_MMCONFIG=y
++CONFIG_PCI_DOMAINS=y
++# CONFIG_PCI_CNB20LE_QUIRK is not set
++CONFIG_PCIEPORTBUS=y
++# CONFIG_PCIEAER is not set
++CONFIG_PCIEASPM=y
++# CONFIG_PCIEASPM_DEBUG is not set
++# CONFIG_PCIEASPM_DEFAULT is not set
++# CONFIG_PCIEASPM_POWERSAVE is not set
++CONFIG_PCIEASPM_PERFORMANCE=y
++CONFIG_PCIE_PME=y
++CONFIG_ARCH_SUPPORTS_MSI=y
++CONFIG_PCI_MSI=y
++# CONFIG_PCI_DEBUG is not set
++# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set
++# CONFIG_PCI_STUB is not set
++CONFIG_HT_IRQ=y
++# CONFIG_PCI_IOV is not set
++# CONFIG_PCI_PRI is not set
++# CONFIG_PCI_PASID is not set
++CONFIG_PCI_LABEL=y
++CONFIG_ISA_DMA_API=y
++# CONFIG_ISA is not set
++# CONFIG_SCx200 is not set
++# CONFIG_ALIX is not set
++# CONFIG_NET5501 is not set
++# CONFIG_GEOS is not set
++CONFIG_AMD_NB=y
++# CONFIG_PCCARD is not set
++# CONFIG_HOTPLUG_PCI is not set
++# CONFIG_RAPIDIO is not set
++
++#
++# Executable file formats / Emulations
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
++CONFIG_BINFMT_SCRIPT=y
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++CONFIG_BINFMT_MISC=y
++CONFIG_COREDUMP=y
++CONFIG_HAVE_ATOMIC_IOMAP=y
++CONFIG_HAVE_TEXT_POKE_SMP=y
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++# CONFIG_PACKET_DIAG is not set
++CONFIG_UNIX=y
++# CONFIG_UNIX_DIAG is not set
++CONFIG_XFRM=y
++CONFIG_XFRM_ALGO=y
++CONFIG_XFRM_USER=y
++CONFIG_XFRM_SUB_POLICY=y
++CONFIG_XFRM_MIGRATE=y
++CONFIG_XFRM_STATISTICS=y
++CONFIG_NET_KEY=y
++CONFIG_NET_KEY_MIGRATE=y
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++CONFIG_IP_ADVANCED_ROUTER=y
++# CONFIG_IP_FIB_TRIE_STATS is not set
++CONFIG_IP_MULTIPLE_TABLES=y
++# CONFIG_IP_ROUTE_MULTIPATH is not set
++# CONFIG_IP_ROUTE_VERBOSE is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE_DEMUX is not set
++CONFIG_NET_IP_TUNNEL=y
++# CONFIG_IP_MROUTE is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_NET_IPVTI is not set
++# CONFIG_INET_AH is not set
++CONFIG_INET_ESP=y
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++CONFIG_INET_TUNNEL=y
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++CONFIG_TCP_MD5SIG=y
++CONFIG_IPV6=y
++CONFIG_IPV6_PRIVACY=y
++CONFIG_IPV6_ROUTER_PREF=y
++CONFIG_IPV6_ROUTE_INFO=y
++CONFIG_IPV6_OPTIMISTIC_DAD=y
++# CONFIG_INET6_AH is not set
++# CONFIG_INET6_ESP is not set
++# CONFIG_INET6_IPCOMP is not set
++# CONFIG_IPV6_MIP6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++CONFIG_INET6_XFRM_MODE_TRANSPORT=y
++CONFIG_INET6_XFRM_MODE_TUNNEL=y
++CONFIG_INET6_XFRM_MODE_BEET=y
++# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
++CONFIG_IPV6_SIT=y
++# CONFIG_IPV6_SIT_6RD is not set
++CONFIG_IPV6_NDISC_NODETYPE=y
++# CONFIG_IPV6_TUNNEL is not set
++# CONFIG_IPV6_GRE is not set
++CONFIG_IPV6_MULTIPLE_TABLES=y
++# CONFIG_IPV6_SUBTREES is not set
++# CONFIG_IPV6_MROUTE is not set
++# CONFIG_NETLABEL is not set
++CONFIG_NETWORK_SECMARK=y
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++CONFIG_NETFILTER=y
++# CONFIG_NETFILTER_DEBUG is not set
++CONFIG_NETFILTER_ADVANCED=y
++
++#
++# Core Netfilter Configuration
++#
++CONFIG_NETFILTER_NETLINK=y
++# CONFIG_NETFILTER_NETLINK_ACCT is not set
++# CONFIG_NETFILTER_NETLINK_QUEUE is not set
++CONFIG_NETFILTER_NETLINK_LOG=y
++CONFIG_NF_CONNTRACK=y
++CONFIG_NF_CONNTRACK_MARK=y
++# CONFIG_NF_CONNTRACK_SECMARK is not set
++CONFIG_NF_CONNTRACK_PROCFS=y
++CONFIG_NF_CONNTRACK_EVENTS=y
++# CONFIG_NF_CONNTRACK_TIMEOUT is not set
++# CONFIG_NF_CONNTRACK_TIMESTAMP is not set
++# CONFIG_NF_CT_PROTO_DCCP is not set
++# CONFIG_NF_CT_PROTO_SCTP is not set
++# CONFIG_NF_CT_PROTO_UDPLITE is not set
++# CONFIG_NF_CONNTRACK_AMANDA is not set
++# CONFIG_NF_CONNTRACK_FTP is not set
++# CONFIG_NF_CONNTRACK_H323 is not set
++# CONFIG_NF_CONNTRACK_IRC is not set
++# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
++# CONFIG_NF_CONNTRACK_SNMP is not set
++# CONFIG_NF_CONNTRACK_PPTP is not set
++# CONFIG_NF_CONNTRACK_SANE is not set
++# CONFIG_NF_CONNTRACK_SIP is not set
++# CONFIG_NF_CONNTRACK_TFTP is not set
++# CONFIG_NF_CT_NETLINK is not set
++# CONFIG_NF_CT_NETLINK_TIMEOUT is not set
++CONFIG_NF_NAT=y
++CONFIG_NF_NAT_NEEDED=y
++# CONFIG_NF_NAT_AMANDA is not set
++# CONFIG_NF_NAT_FTP is not set
++# CONFIG_NF_NAT_IRC is not set
++# CONFIG_NF_NAT_SIP is not set
++# CONFIG_NF_NAT_TFTP is not set
++CONFIG_NETFILTER_TPROXY=y
++CONFIG_NETFILTER_XTABLES=y
++
++#
++# Xtables combined modules
++#
++CONFIG_NETFILTER_XT_MARK=y
++CONFIG_NETFILTER_XT_CONNMARK=y
++
++#
++# Xtables targets
++#
++# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set
++# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set
++# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
++CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
++# CONFIG_NETFILTER_XT_TARGET_CT is not set
++# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
++CONFIG_NETFILTER_XT_TARGET_HL=y
++# CONFIG_NETFILTER_XT_TARGET_HMARK is not set
++# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set
++# CONFIG_NETFILTER_XT_TARGET_LED is not set
++# CONFIG_NETFILTER_XT_TARGET_LOG is not set
++# CONFIG_NETFILTER_XT_TARGET_MARK is not set
++CONFIG_NETFILTER_XT_TARGET_NETMAP=y
++# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
++# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
++# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
++# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
++CONFIG_NETFILTER_XT_TARGET_REDIRECT=y
++# CONFIG_NETFILTER_XT_TARGET_TEE is not set
++# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set
++# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
++# CONFIG_NETFILTER_XT_TARGET_SECMARK is not set
++# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
++# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
++
++#
++# Xtables matches
++#
++# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set
++# CONFIG_NETFILTER_XT_MATCH_BPF is not set
++CONFIG_NETFILTER_XT_MATCH_CLUSTER=y
++# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
++# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
++# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set
++# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
++# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set
++# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
++# CONFIG_NETFILTER_XT_MATCH_CPU is not set
++# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
++# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set
++# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
++# CONFIG_NETFILTER_XT_MATCH_ECN is not set
++# CONFIG_NETFILTER_XT_MATCH_ESP is not set
++# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
++CONFIG_NETFILTER_XT_MATCH_HELPER=y
++CONFIG_NETFILTER_XT_MATCH_HL=y
++# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
++# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
++# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
++# CONFIG_NETFILTER_XT_MATCH_MAC is not set
++# CONFIG_NETFILTER_XT_MATCH_MARK is not set
++CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
++# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set
++# CONFIG_NETFILTER_XT_MATCH_OSF is not set
++# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
++# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
++# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
++CONFIG_NETFILTER_XT_MATCH_QUOTA=y
++# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
++# CONFIG_NETFILTER_XT_MATCH_REALM is not set
++# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
++# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
++CONFIG_NETFILTER_XT_MATCH_SOCKET=y
++CONFIG_NETFILTER_XT_MATCH_STATE=y
++# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
++# CONFIG_NETFILTER_XT_MATCH_STRING is not set
++# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
++# CONFIG_NETFILTER_XT_MATCH_TIME is not set
++# CONFIG_NETFILTER_XT_MATCH_U32 is not set
++# CONFIG_IP_SET is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++CONFIG_NF_DEFRAG_IPV4=y
++CONFIG_NF_CONNTRACK_IPV4=y
++CONFIG_NF_CONNTRACK_PROC_COMPAT=y
++CONFIG_IP_NF_IPTABLES=y
++# CONFIG_IP_NF_MATCH_AH is not set
++# CONFIG_IP_NF_MATCH_ECN is not set
++# CONFIG_IP_NF_MATCH_RPFILTER is not set
++# CONFIG_IP_NF_MATCH_TTL is not set
++CONFIG_IP_NF_FILTER=y
++CONFIG_IP_NF_TARGET_REJECT=y
++# CONFIG_IP_NF_TARGET_ULOG is not set
++CONFIG_NF_NAT_IPV4=y
++CONFIG_IP_NF_TARGET_MASQUERADE=y
++CONFIG_IP_NF_TARGET_NETMAP=y
++CONFIG_IP_NF_TARGET_REDIRECT=y
++# CONFIG_NF_NAT_PPTP is not set
++# CONFIG_NF_NAT_H323 is not set
++CONFIG_IP_NF_MANGLE=y
++# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
++# CONFIG_IP_NF_TARGET_ECN is not set
++# CONFIG_IP_NF_TARGET_TTL is not set
++CONFIG_IP_NF_RAW=y
++# CONFIG_IP_NF_SECURITY is not set
++# CONFIG_IP_NF_ARPTABLES is not set
++
++#
++# IPv6: Netfilter Configuration
++#
++CONFIG_NF_DEFRAG_IPV6=y
++# CONFIG_NF_CONNTRACK_IPV6 is not set
++CONFIG_IP6_NF_IPTABLES=y
++CONFIG_IP6_NF_MATCH_AH=y
++CONFIG_IP6_NF_MATCH_EUI64=y
++CONFIG_IP6_NF_MATCH_FRAG=y
++CONFIG_IP6_NF_MATCH_OPTS=y
++CONFIG_IP6_NF_MATCH_HL=y
++CONFIG_IP6_NF_MATCH_IPV6HEADER=y
++CONFIG_IP6_NF_MATCH_MH=y
++# CONFIG_IP6_NF_MATCH_RPFILTER is not set
++CONFIG_IP6_NF_MATCH_RT=y
++CONFIG_IP6_NF_TARGET_HL=y
++CONFIG_IP6_NF_FILTER=y
++CONFIG_IP6_NF_TARGET_REJECT=y
++CONFIG_IP6_NF_MANGLE=y
++CONFIG_IP6_NF_RAW=y
++# CONFIG_IP6_NF_SECURITY is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++CONFIG_L2TP=y
++# CONFIG_L2TP_DEBUGFS is not set
++# CONFIG_L2TP_V3 is not set
++# CONFIG_BRIDGE is not set
++CONFIG_HAVE_NET_DSA=y
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++CONFIG_DNS_RESOLVER=y
++# CONFIG_BATMAN_ADV is not set
++# CONFIG_OPENVSWITCH is not set
++# CONFIG_VSOCKETS is not set
++# CONFIG_NETLINK_MMAP is not set
++# CONFIG_NETLINK_DIAG is not set
++CONFIG_RPS=y
++CONFIG_RFS_ACCEL=y
++CONFIG_XPS=y
++# CONFIG_NETPRIO_CGROUP is not set
++CONFIG_BQL=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_NET_TCPPROBE is not set
++# CONFIG_NET_DROP_MONITOR is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++CONFIG_FIB_RULES=y
++CONFIG_WIRELESS=y
++CONFIG_CFG80211=m
++# CONFIG_NL80211_TESTMODE is not set
++# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
++# CONFIG_CFG80211_REG_DEBUG is not set
++# CONFIG_CFG80211_CERTIFICATION_ONUS is not set
++CONFIG_CFG80211_DEFAULT_PS=y
++# CONFIG_CFG80211_DEBUGFS is not set
++# CONFIG_CFG80211_INTERNAL_REGDB is not set
++# CONFIG_CFG80211_WEXT is not set
++# CONFIG_LIB80211 is not set
++CONFIG_MAC80211=m
++CONFIG_MAC80211_HAS_RC=y
++# CONFIG_MAC80211_RC_PID is not set
++CONFIG_MAC80211_RC_MINSTREL=y
++CONFIG_MAC80211_RC_MINSTREL_HT=y
++CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
++CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
++# CONFIG_MAC80211_MESH is not set
++# CONFIG_MAC80211_LEDS is not set
++# CONFIG_MAC80211_DEBUGFS is not set
++# CONFIG_MAC80211_MESSAGE_TRACING is not set
++# CONFIG_MAC80211_DEBUG_MENU is not set
++# CONFIG_WIMAX is not set
++CONFIG_RFKILL=y
++CONFIG_RFKILL_LEDS=y
++# CONFIG_RFKILL_INPUT is not set
++# CONFIG_RFKILL_REGULATOR is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++CONFIG_NFC=y
++# CONFIG_NFC_NCI is not set
++# CONFIG_NFC_HCI is not set
++
++#
++# Near Field Communication (NFC) devices
++#
++# CONFIG_NFC_PN533 is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH=""
++# CONFIG_DEVTMPFS is not set
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++CONFIG_FW_LOADER_USER_HELPER=y
++# CONFIG_DEBUG_DRIVER is not set
++CONFIG_DEBUG_DEVRES=y
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_GENERIC_CPU_DEVICES is not set
++CONFIG_REGMAP=y
++CONFIG_REGMAP_I2C=y
++CONFIG_REGMAP_SPI=y
++CONFIG_REGMAP_IRQ=y
++CONFIG_DMA_SHARED_BUFFER=y
++# CONFIG_CMA is not set
++
++#
++# Bus devices
++#
++CONFIG_CONNECTOR=y
++CONFIG_PROC_EVENTS=y
++# CONFIG_MTD is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_FD is not set
++# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_NVME is not set
++# CONFIG_BLK_DEV_SX8 is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_VIRTIO_BLK is not set
++# CONFIG_BLK_DEV_HD is not set
++# CONFIG_BLK_DEV_RBD is not set
++# CONFIG_BLK_DEV_RSXX is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_DUMMY_IRQ is not set
++# CONFIG_IBM_ASM is not set
++# CONFIG_PHANTOM is not set
++CONFIG_INTEL_MID_PTI=y
++CONFIG_INTEL_PTI_STM=y
++# CONFIG_SGI_IOC4 is not set
++# CONFIG_TIFM_CORE is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ATMEL_SSC is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_HP_ILO is not set
++# CONFIG_APDS9802ALS is not set
++# CONFIG_ISL29003 is not set
++# CONFIG_ISL29020 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_SENSORS_BH1780 is not set
++# CONFIG_SENSORS_BH1770 is not set
++# CONFIG_SENSORS_APDS990X is not set
++# CONFIG_HMC6352 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_TI_DAC7512 is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_PCH_PHUB is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++# CONFIG_CB710_CORE is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# CONFIG_TI_ST is not set
++# CONFIG_SENSORS_LIS3_SPI is not set
++# CONFIG_SENSORS_LIS3_I2C is not set
++
++#
++# Altera FPGA firmware download module
++#
++# CONFIG_ALTERA_STAPL is not set
++# CONFIG_VMWARE_VMCI is not set
++CONFIG_HAVE_IDE=y
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=y
++CONFIG_BLK_DEV_SR_VENDOR=y
++CONFIG_CHR_DEV_SG=y
++# CONFIG_CHR_DEV_SCH is not set
++CONFIG_SCSI_MULTI_LUN=y
++CONFIG_SCSI_CONSTANTS=y
++# CONFIG_SCSI_LOGGING is not set
++# CONFIG_SCSI_SCAN_ASYNC is not set
++
++#
++# SCSI Transports
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++# CONFIG_SCSI_LOWLEVEL is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++CONFIG_ATA=y
++# CONFIG_ATA_NONSTANDARD is not set
++CONFIG_ATA_VERBOSE_ERROR=y
++CONFIG_SATA_PMP=y
++
++#
++# Controllers with non-SFF native interface
++#
++CONFIG_SATA_AHCI=y
++# CONFIG_SATA_AHCI_PLATFORM is not set
++# CONFIG_SATA_INIC162X is not set
++# CONFIG_SATA_ACARD_AHCI is not set
++# CONFIG_SATA_SIL24 is not set
++CONFIG_ATA_SFF=y
++
++#
++# SFF controllers with custom DMA interface
++#
++# CONFIG_PDC_ADMA is not set
++# CONFIG_SATA_QSTOR is not set
++# CONFIG_SATA_SX4 is not set
++CONFIG_ATA_BMDMA=y
++
++#
++# SATA SFF controllers with BMDMA
++#
++CONFIG_ATA_PIIX=y
++# CONFIG_SATA_HIGHBANK is not set
++# CONFIG_SATA_MV is not set
++# CONFIG_SATA_NV is not set
++# CONFIG_SATA_PROMISE is not set
++# CONFIG_SATA_SIL is not set
++# CONFIG_SATA_SIS is not set
++# CONFIG_SATA_SVW is not set
++# CONFIG_SATA_ULI is not set
++# CONFIG_SATA_VIA is not set
++# CONFIG_SATA_VITESSE is not set
++
++#
++# PATA SFF controllers with BMDMA
++#
++# CONFIG_PATA_ALI is not set
++CONFIG_PATA_AMD=y
++# CONFIG_PATA_ARASAN_CF is not set
++# CONFIG_PATA_ARTOP is not set
++# CONFIG_PATA_ATIIXP is not set
++# CONFIG_PATA_ATP867X is not set
++# CONFIG_PATA_CMD64X is not set
++# CONFIG_PATA_CS5520 is not set
++# CONFIG_PATA_CS5530 is not set
++# CONFIG_PATA_CS5535 is not set
++# CONFIG_PATA_CS5536 is not set
++# CONFIG_PATA_CYPRESS is not set
++# CONFIG_PATA_EFAR is not set
++# CONFIG_PATA_HPT366 is not set
++# CONFIG_PATA_HPT37X is not set
++# CONFIG_PATA_HPT3X2N is not set
++# CONFIG_PATA_HPT3X3 is not set
++# CONFIG_PATA_IT8213 is not set
++# CONFIG_PATA_IT821X is not set
++# CONFIG_PATA_JMICRON is not set
++# CONFIG_PATA_MARVELL is not set
++# CONFIG_PATA_NETCELL is not set
++# CONFIG_PATA_NINJA32 is not set
++# CONFIG_PATA_NS87415 is not set
++CONFIG_PATA_OLDPIIX=y
++# CONFIG_PATA_OPTIDMA is not set
++# CONFIG_PATA_PDC2027X is not set
++# CONFIG_PATA_PDC_OLD is not set
++# CONFIG_PATA_RADISYS is not set
++# CONFIG_PATA_RDC is not set
++# CONFIG_PATA_SC1200 is not set
++CONFIG_PATA_SCH=y
++# CONFIG_PATA_SERVERWORKS is not set
++# CONFIG_PATA_SIL680 is not set
++# CONFIG_PATA_SIS is not set
++# CONFIG_PATA_TOSHIBA is not set
++# CONFIG_PATA_TRIFLEX is not set
++# CONFIG_PATA_VIA is not set
++# CONFIG_PATA_WINBOND is not set
++
++#
++# PIO-only SFF controllers
++#
++# CONFIG_PATA_CMD640_PCI is not set
++CONFIG_PATA_MPIIX=y
++# CONFIG_PATA_NS87410 is not set
++# CONFIG_PATA_OPTI is not set
++# CONFIG_PATA_PLATFORM is not set
++# CONFIG_PATA_RZ1000 is not set
++
++#
++# Generic fallback / legacy drivers
++#
++CONFIG_ATA_GENERIC=y
++# CONFIG_PATA_LEGACY is not set
++CONFIG_MD=y
++CONFIG_BLK_DEV_MD=y
++CONFIG_MD_AUTODETECT=y
++# CONFIG_MD_LINEAR is not set
++# CONFIG_MD_RAID0 is not set
++# CONFIG_MD_RAID1 is not set
++# CONFIG_MD_RAID10 is not set
++# CONFIG_MD_RAID456 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_MD_FAULTY is not set
++# CONFIG_BCACHE is not set
++CONFIG_BLK_DEV_DM=y
++# CONFIG_DM_DEBUG is not set
++CONFIG_DM_CRYPT=y
++# CONFIG_DM_SNAPSHOT is not set
++# CONFIG_DM_THIN_PROVISIONING is not set
++# CONFIG_DM_CACHE is not set
++CONFIG_DM_MIRROR=y
++# CONFIG_DM_RAID is not set
++# CONFIG_DM_LOG_USERSPACE is not set
++CONFIG_DM_ZERO=y
++# CONFIG_DM_MULTIPATH is not set
++# CONFIG_DM_DELAY is not set
++CONFIG_DM_UEVENT=y
++# CONFIG_DM_FLAKEY is not set
++# CONFIG_DM_VERITY is not set
++# CONFIG_TARGET_CORE is not set
++# CONFIG_FUSION is not set
++
++#
++# IEEE 1394 (FireWire) support
++#
++# CONFIG_FIREWIRE is not set
++# CONFIG_FIREWIRE_NOSY is not set
++# CONFIG_I2O is not set
++# CONFIG_MACINTOSH_DRIVERS is not set
++CONFIG_NETDEVICES=y
++CONFIG_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_NET_FC is not set
++CONFIG_MII=y
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++CONFIG_NETCONSOLE=y
++# CONFIG_NETCONSOLE_DYNAMIC is not set
++CONFIG_NETPOLL=y
++# CONFIG_NETPOLL_TRAP is not set
++CONFIG_NET_POLL_CONTROLLER=y
++CONFIG_TUN=y
++# CONFIG_VETH is not set
++# CONFIG_VIRTIO_NET is not set
++# CONFIG_ARCNET is not set
++
++#
++# CAIF transport drivers
++#
++# CONFIG_VHOST_NET is not set
++
++#
++# Distributed Switch Architecture drivers
++#
++# CONFIG_NET_DSA_MV88E6XXX is not set
++# CONFIG_NET_DSA_MV88E6060 is not set
++# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set
++# CONFIG_NET_DSA_MV88E6131 is not set
++# CONFIG_NET_DSA_MV88E6123_61_65 is not set
++CONFIG_ETHERNET=y
++CONFIG_NET_VENDOR_3COM=y
++# CONFIG_VORTEX is not set
++# CONFIG_TYPHOON is not set
++CONFIG_NET_VENDOR_ADAPTEC=y
++# CONFIG_ADAPTEC_STARFIRE is not set
++CONFIG_NET_VENDOR_ALTEON=y
++# CONFIG_ACENIC is not set
++CONFIG_NET_VENDOR_AMD=y
++# CONFIG_AMD8111_ETH is not set
++# CONFIG_PCNET32 is not set
++CONFIG_NET_VENDOR_ATHEROS=y
++# CONFIG_ATL2 is not set
++# CONFIG_ATL1 is not set
++# CONFIG_ATL1E is not set
++# CONFIG_ATL1C is not set
++# CONFIG_ALX is not set
++CONFIG_NET_CADENCE=y
++# CONFIG_ARM_AT91_ETHER is not set
++# CONFIG_MACB is not set
++CONFIG_NET_VENDOR_BROADCOM=y
++# CONFIG_B44 is not set
++CONFIG_BNX2=y
++# CONFIG_CNIC is not set
++CONFIG_TIGON3=y
++# CONFIG_BNX2X is not set
++CONFIG_NET_VENDOR_BROCADE=y
++# CONFIG_BNA is not set
++# CONFIG_NET_CALXEDA_XGMAC is not set
++CONFIG_NET_VENDOR_CHELSIO=y
++# CONFIG_CHELSIO_T1 is not set
++# CONFIG_CHELSIO_T3 is not set
++# CONFIG_CHELSIO_T4 is not set
++# CONFIG_CHELSIO_T4VF is not set
++CONFIG_NET_VENDOR_CISCO=y
++# CONFIG_ENIC is not set
++# CONFIG_DNET is not set
++CONFIG_NET_VENDOR_DEC=y
++CONFIG_NET_TULIP=y
++# CONFIG_DE2104X is not set
++# CONFIG_TULIP is not set
++# CONFIG_DE4X5 is not set
++# CONFIG_WINBOND_840 is not set
++# CONFIG_DM9102 is not set
++# CONFIG_ULI526X is not set
++CONFIG_NET_VENDOR_DLINK=y
++# CONFIG_DL2K is not set
++# CONFIG_SUNDANCE is not set
++CONFIG_NET_VENDOR_EMULEX=y
++# CONFIG_BE2NET is not set
++CONFIG_NET_VENDOR_EXAR=y
++# CONFIG_S2IO is not set
++# CONFIG_VXGE is not set
++CONFIG_NET_VENDOR_HP=y
++# CONFIG_HP100 is not set
++CONFIG_NET_VENDOR_INTEL=y
++CONFIG_E100=y
++CONFIG_E1000=y
++CONFIG_E1000E=y
++# CONFIG_IGB is not set
++# CONFIG_IGBVF is not set
++# CONFIG_IXGB is not set
++# CONFIG_IXGBE is not set
++# CONFIG_IXGBEVF is not set
++CONFIG_NET_VENDOR_I825XX=y
++# CONFIG_IP1000 is not set
++# CONFIG_JME is not set
++CONFIG_NET_VENDOR_MARVELL=y
++# CONFIG_MVMDIO is not set
++# CONFIG_SKGE is not set
++# CONFIG_SKY2 is not set
++CONFIG_NET_VENDOR_MELLANOX=y
++# CONFIG_MLX4_EN is not set
++# CONFIG_MLX4_CORE is not set
++CONFIG_NET_VENDOR_MICREL=y
++# CONFIG_KS8842 is not set
++# CONFIG_KS8851 is not set
++# CONFIG_KS8851_MLL is not set
++# CONFIG_KSZ884X_PCI is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++CONFIG_NET_VENDOR_MYRI=y
++# CONFIG_MYRI10GE is not set
++# CONFIG_FEALNX is not set
++CONFIG_NET_VENDOR_NATSEMI=y
++# CONFIG_NATSEMI is not set
++# CONFIG_NS83820 is not set
++CONFIG_NET_VENDOR_8390=y
++CONFIG_NE2K_PCI=y
++CONFIG_NET_VENDOR_NVIDIA=y
++CONFIG_FORCEDETH=y
++CONFIG_NET_VENDOR_OKI=y
++# CONFIG_PCH_GBE is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_PACKET_ENGINE is not set
++CONFIG_NET_VENDOR_QLOGIC=y
++# CONFIG_QLA3XXX is not set
++# CONFIG_QLCNIC is not set
++# CONFIG_QLGE is not set
++# CONFIG_NETXEN_NIC is not set
++CONFIG_NET_VENDOR_REALTEK=y
++# CONFIG_8139CP is not set
++CONFIG_8139TOO=y
++# CONFIG_8139TOO_PIO is not set
++# CONFIG_8139TOO_TUNE_TWISTER is not set
++# CONFIG_8139TOO_8129 is not set
++# CONFIG_8139_OLD_RX_RESET is not set
++CONFIG_R8169=y
++CONFIG_NET_VENDOR_RDC=y
++# CONFIG_R6040 is not set
++CONFIG_NET_VENDOR_SEEQ=y
++CONFIG_NET_VENDOR_SILAN=y
++# CONFIG_SC92031 is not set
++CONFIG_NET_VENDOR_SIS=y
++# CONFIG_SIS900 is not set
++# CONFIG_SIS190 is not set
++# CONFIG_SFC is not set
++CONFIG_NET_VENDOR_SMSC=y
++# CONFIG_EPIC100 is not set
++# CONFIG_SMSC9420 is not set
++CONFIG_NET_VENDOR_STMICRO=y
++# CONFIG_STMMAC_ETH is not set
++CONFIG_NET_VENDOR_SUN=y
++# CONFIG_HAPPYMEAL is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_CASSINI is not set
++# CONFIG_NIU is not set
++CONFIG_NET_VENDOR_TEHUTI=y
++# CONFIG_TEHUTI is not set
++CONFIG_NET_VENDOR_TI=y
++# CONFIG_TLAN is not set
++CONFIG_NET_VENDOR_VIA=y
++# CONFIG_VIA_RHINE is not set
++# CONFIG_VIA_VELOCITY is not set
++CONFIG_NET_VENDOR_WIZNET=y
++# CONFIG_WIZNET_W5100 is not set
++# CONFIG_WIZNET_W5300 is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_MARVELL_PHY is not set
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM87XX_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_RTL8152 is not set
++CONFIG_USB_USBNET=y
++CONFIG_USB_NET_AX8817X=y
++# CONFIG_USB_NET_AX88179_178A is not set
++# CONFIG_USB_NET_CDCETHER is not set
++# CONFIG_USB_NET_CDC_EEM is not set
++CONFIG_USB_NET_CDC_NCM=y
++# CONFIG_USB_NET_CDC_MBIM is not set
++# CONFIG_USB_NET_DM9601 is not set
++# CONFIG_USB_NET_SMSC75XX is not set
++# CONFIG_USB_NET_SMSC95XX is not set
++# CONFIG_USB_NET_GL620A is not set
++# CONFIG_USB_NET_NET1080 is not set
++# CONFIG_USB_NET_PLUSB is not set
++# CONFIG_USB_NET_MCS7830 is not set
++# CONFIG_USB_NET_RNDIS_HOST is not set
++CONFIG_USB_NET_CDC_SUBSET=y
++# CONFIG_USB_ALI_M5632 is not set
++# CONFIG_USB_AN2720 is not set
++# CONFIG_USB_BELKIN is not set
++# CONFIG_USB_ARMLINUX is not set
++# CONFIG_USB_EPSON2888 is not set
++# CONFIG_USB_KC2190 is not set
++# CONFIG_USB_NET_ZAURUS is not set
++# CONFIG_USB_NET_CX82310_ETH is not set
++# CONFIG_USB_NET_KALMIA is not set
++# CONFIG_USB_NET_QMI_WWAN is not set
++# CONFIG_USB_HSO is not set
++# CONFIG_USB_NET_INT51X1 is not set
++# CONFIG_USB_IPHETH is not set
++# CONFIG_USB_SIERRA_NET is not set
++CONFIG_WLAN=y
++# CONFIG_LIBERTAS_THINFIRM is not set
++# CONFIG_AIRO is not set
++# CONFIG_ATMEL is not set
++# CONFIG_AT76C50X_USB is not set
++# CONFIG_PRISM54 is not set
++# CONFIG_USB_ZD1201 is not set
++# CONFIG_USB_NET_RNDIS_WLAN is not set
++# CONFIG_RTL8180 is not set
++# CONFIG_RTL8187 is not set
++# CONFIG_ADM8211 is not set
++# CONFIG_MAC80211_HWSIM is not set
++# CONFIG_MWL8K is not set
++CONFIG_WIFI_CONTROL_FUNC=y
++CONFIG_WIFI_PLATFORM_DATA=y
++# CONFIG_ATH_CARDS is not set
++# CONFIG_B43 is not set
++# CONFIG_B43LEGACY is not set
++# CONFIG_BRCMFMAC is not set
++# CONFIG_HOSTAP is not set
++# CONFIG_IPW2100 is not set
++# CONFIG_IWLWIFI is not set
++# CONFIG_IWL4965 is not set
++# CONFIG_IWL3945 is not set
++# CONFIG_LIBERTAS is not set
++# CONFIG_P54_COMMON is not set
++# CONFIG_RT2X00 is not set
++# CONFIG_RTLWIFI is not set
++# CONFIG_WL_TI is not set
++# CONFIG_ZD1211RW is not set
++# CONFIG_MWIFIEX is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_VMXNET3 is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++CONFIG_INPUT_POLLDEV=y
++CONFIG_INPUT_SPARSEKMAP=y
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++# CONFIG_KEYBOARD_ADP5588 is not set
++# CONFIG_KEYBOARD_ADP5589 is not set
++# CONFIG_KEYBOARD_ATKBD is not set
++# CONFIG_KEYBOARD_QT1070 is not set
++# CONFIG_KEYBOARD_QT2160 is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++CONFIG_KEYBOARD_GPIO=y
++CONFIG_KEYBOARD_GPIO_POLLED=y
++# CONFIG_KEYBOARD_TCA6416 is not set
++# CONFIG_KEYBOARD_TCA8418 is not set
++# CONFIG_KEYBOARD_MATRIX is not set
++# CONFIG_KEYBOARD_LM8323 is not set
++# CONFIG_KEYBOARD_LM8333 is not set
++# CONFIG_KEYBOARD_MAX7359 is not set
++# CONFIG_KEYBOARD_MCS is not set
++# CONFIG_KEYBOARD_MPR121 is not set
++# CONFIG_KEYBOARD_NEWTON is not set
++# CONFIG_KEYBOARD_OPENCORES is not set
++# CONFIG_KEYBOARD_STOWAWAY is not set
++# CONFIG_KEYBOARD_SUNKBD is not set
++# CONFIG_KEYBOARD_XTKBD is not set
++CONFIG_INPUT_MOUSE=y
++# CONFIG_MOUSE_PS2 is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_CYAPA is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_GPIO is not set
++# CONFIG_MOUSE_SYNAPTICS_I2C is not set
++# CONFIG_MOUSE_SYNAPTICS_USB is not set
++CONFIG_INPUT_JOYSTICK=y
++# CONFIG_JOYSTICK_ANALOG is not set
++# CONFIG_JOYSTICK_A3D is not set
++# CONFIG_JOYSTICK_ADI is not set
++# CONFIG_JOYSTICK_COBRA is not set
++# CONFIG_JOYSTICK_GF2K is not set
++# CONFIG_JOYSTICK_GRIP is not set
++# CONFIG_JOYSTICK_GRIP_MP is not set
++# CONFIG_JOYSTICK_GUILLEMOT is not set
++# CONFIG_JOYSTICK_INTERACT is not set
++# CONFIG_JOYSTICK_SIDEWINDER is not set
++# CONFIG_JOYSTICK_TMDC is not set
++# CONFIG_JOYSTICK_IFORCE is not set
++# CONFIG_JOYSTICK_WARRIOR is not set
++# CONFIG_JOYSTICK_MAGELLAN is not set
++# CONFIG_JOYSTICK_SPACEORB is not set
++# CONFIG_JOYSTICK_SPACEBALL is not set
++# CONFIG_JOYSTICK_STINGER is not set
++# CONFIG_JOYSTICK_TWIDJOY is not set
++# CONFIG_JOYSTICK_ZHENHUA is not set
++# CONFIG_JOYSTICK_AS5011 is not set
++# CONFIG_JOYSTICK_JOYDUMP is not set
++# CONFIG_JOYSTICK_XPAD is not set
++CONFIG_INPUT_TABLET=y
++# CONFIG_TABLET_USB_ACECAD is not set
++# CONFIG_TABLET_USB_AIPTEK is not set
++# CONFIG_TABLET_USB_GTCO is not set
++# CONFIG_TABLET_USB_HANWANG is not set
++# CONFIG_TABLET_USB_KBTAB is not set
++# CONFIG_TABLET_USB_WACOM is not set
++CONFIG_INPUT_TOUCHSCREEN=y
++# CONFIG_TOUCHSCREEN_ADS7846 is not set
++# CONFIG_TOUCHSCREEN_AD7877 is not set
++# CONFIG_TOUCHSCREEN_AD7879 is not set
++# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set
++# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set
++# CONFIG_TOUCHSCREEN_BU21013 is not set
++# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set
++# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set
++# CONFIG_TOUCHSCREEN_DYNAPRO is not set
++# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
++# CONFIG_TOUCHSCREEN_EETI is not set
++# CONFIG_TOUCHSCREEN_FUJITSU is not set
++# CONFIG_TOUCHSCREEN_ILI210X is not set
++# CONFIG_TOUCHSCREEN_GUNZE is not set
++# CONFIG_TOUCHSCREEN_ELO is not set
++# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
++# CONFIG_TOUCHSCREEN_WACOM_I2C is not set
++# CONFIG_TOUCHSCREEN_MAX11801 is not set
++# CONFIG_TOUCHSCREEN_MCS5000 is not set
++# CONFIG_TOUCHSCREEN_MMS114 is not set
++# CONFIG_TOUCHSCREEN_MTOUCH is not set
++# CONFIG_TOUCHSCREEN_INEXIO is not set
++# CONFIG_TOUCHSCREEN_INTEL_MID is not set
++# CONFIG_TOUCHSCREEN_MK712 is not set
++# CONFIG_TOUCHSCREEN_PENMOUNT is not set
++# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set
++# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
++# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
++# CONFIG_TOUCHSCREEN_PIXCIR is not set
++# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
++# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
++# CONFIG_TOUCHSCREEN_TSC_SERIO is not set
++# CONFIG_TOUCHSCREEN_TSC2005 is not set
++# CONFIG_TOUCHSCREEN_TSC2007 is not set
++# CONFIG_TOUCHSCREEN_ST1232 is not set
++# CONFIG_TOUCHSCREEN_TPS6507X is not set
++CONFIG_INPUT_MISC=y
++# CONFIG_INPUT_AD714X is not set
++# CONFIG_INPUT_BMA150 is not set
++# CONFIG_INPUT_PCSPKR is not set
++# CONFIG_INPUT_MMA8450 is not set
++# CONFIG_INPUT_MPU3050 is not set
++# CONFIG_INPUT_APANEL is not set
++# CONFIG_INPUT_GP2A is not set
++# CONFIG_INPUT_GPIO_TILT_POLLED is not set
++# CONFIG_INPUT_WISTRON_BTNS is not set
++# CONFIG_INPUT_ATI_REMOTE2 is not set
++# CONFIG_INPUT_KEYSPAN_REMOTE is not set
++# CONFIG_INPUT_KXTJ9 is not set
++# CONFIG_INPUT_POWERMATE is not set
++# CONFIG_INPUT_YEALINK is not set
++# CONFIG_INPUT_CM109 is not set
++CONFIG_INPUT_UINPUT=y
++# CONFIG_INPUT_PCF8574 is not set
++# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
++# CONFIG_INPUT_ADXL34X is not set
++# CONFIG_INPUT_IMS_PCU is not set
++# CONFIG_INPUT_CMA3000 is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++# CONFIG_SERIO_I8042 is not set
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_CT82C710 is not set
++# CONFIG_SERIO_PCIPS2 is not set
++# CONFIG_SERIO_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_SERIO_ARC_PS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++CONFIG_VT_HW_CONSOLE_BINDING=y
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++CONFIG_SERIAL_NONSTANDARD=y
++# CONFIG_ROCKETPORT is not set
++# CONFIG_CYCLADES is not set
++# CONFIG_MOXA_INTELLIO is not set
++# CONFIG_MOXA_SMARTIO is not set
++# CONFIG_SYNCLINK is not set
++# CONFIG_SYNCLINKMP is not set
++# CONFIG_SYNCLINK_GT is not set
++# CONFIG_NOZOMI is not set
++# CONFIG_ISI is not set
++# CONFIG_N_HDLC is not set
++CONFIG_N_GSM=y
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVKMEM=y
++# CONFIG_STALDRV is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
++CONFIG_FIX_EARLYCON_MEM=y
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_MAX3100 is not set
++# CONFIG_SERIAL_MAX310X is not set
++CONFIG_SERIAL_MRST_MAX3110=y
++# CONFIG_SERIAL_MFD_HSU is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_JSM is not set
++# CONFIG_SERIAL_SCCNXP is not set
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_PCH_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_RP2 is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_VIRTIO_CONSOLE is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++CONFIG_HW_RANDOM_INTEL=y
++CONFIG_HW_RANDOM_AMD=y
++CONFIG_HW_RANDOM_GEODE=y
++CONFIG_HW_RANDOM_VIA=y
++# CONFIG_HW_RANDOM_VIRTIO is not set
++CONFIG_NVRAM=y
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++# CONFIG_SONYPI is not set
++# CONFIG_MWAVE is not set
++# CONFIG_PC8736x_GPIO is not set
++# CONFIG_NSC_GPIO is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_HANGCHECK_TIMER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_TELCLOCK is not set
++CONFIG_DEVPORT=y
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_MUX is not set
++CONFIG_I2C_HELPER_AUTO=y
++CONFIG_I2C_ALGOBIT=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# PC SMBus host controller drivers
++#
++# CONFIG_I2C_ALI1535 is not set
++# CONFIG_I2C_ALI1563 is not set
++# CONFIG_I2C_ALI15X3 is not set
++# CONFIG_I2C_AMD756 is not set
++# CONFIG_I2C_AMD8111 is not set
++# CONFIG_I2C_I801 is not set
++# CONFIG_I2C_ISCH is not set
++# CONFIG_I2C_ISMT is not set
++# CONFIG_I2C_PIIX4 is not set
++# CONFIG_I2C_NFORCE2 is not set
++# CONFIG_I2C_SIS5595 is not set
++# CONFIG_I2C_SIS630 is not set
++# CONFIG_I2C_SIS96X is not set
++# CONFIG_I2C_VIA is not set
++# CONFIG_I2C_VIAPRO is not set
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_CBUS_GPIO is not set
++# CONFIG_I2C_DESIGNWARE_PCI is not set
++# CONFIG_I2C_EG20T is not set
++CONFIG_I2C_GPIO=y
++# CONFIG_I2C_INTEL_MID is not set
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_PXA_PCI is not set
++# CONFIG_I2C_SIMTEC is not set
++# CONFIG_I2C_XILINX is not set
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_DIOLAN_U2C is not set
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_SCx200_ACB is not set
++# CONFIG_I2C_STUB is not set
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++# CONFIG_SPI_ALTERA is not set
++CONFIG_SPI_BITBANG=y
++CONFIG_SPI_GPIO=y
++# CONFIG_SPI_OC_TINY is not set
++# CONFIG_SPI_PXA2XX is not set
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_SC18IS602 is not set
++# CONFIG_SPI_TOPCLIFF_PCH is not set
++# CONFIG_SPI_XCOMM is not set
++# CONFIG_SPI_XILINX is not set
++CONFIG_SPI_DESIGNWARE=y
++CONFIG_SPI_DW_PCI=y
++CONFIG_SPI_DW_MID_DMA=y
++
++#
++# SPI Protocol Masters
++#
++# CONFIG_SPI_SPIDEV is not set
++# CONFIG_SPI_TLE62X0 is not set
++
++#
++# Qualcomm MSM SSBI bus support
++#
++# CONFIG_SSBI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++CONFIG_PPS=y
++# CONFIG_PPS_DEBUG is not set
++
++#
++# PPS clients support
++#
++# CONFIG_PPS_CLIENT_KTIMER is not set
++# CONFIG_PPS_CLIENT_LDISC is not set
++# CONFIG_PPS_CLIENT_GPIO is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++CONFIG_PTP_1588_CLOCK=y
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++# CONFIG_PTP_1588_CLOCK_PCH is not set
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++CONFIG_GPIO_DEVRES=y
++CONFIG_GPIOLIB=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++CONFIG_GPIODEBUG=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++# CONFIG_GPIO_IT8761E is not set
++# CONFIG_GPIO_TS5500 is not set
++# CONFIG_GPIO_SCH is not set
++# CONFIG_GPIO_ICH is not set
++# CONFIG_GPIO_VX855 is not set
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_WM8994 is not set
++# CONFIG_GPIO_ADP5588 is not set
++
++#
++# PCI GPIO expanders:
++#
++# CONFIG_GPIO_BT8XX is not set
++# CONFIG_GPIO_AMD8111 is not set
++CONFIG_GPIO_LANGWELL=y
++# CONFIG_GPIO_PCH is not set
++# CONFIG_GPIO_ML_IOH is not set
++# CONFIG_GPIO_RDC321X is not set
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++# CONFIG_GPIO_MSIC is not set
++
++#
++# USB GPIO expanders:
++#
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_GENERIC_ADC_BATTERY is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++CONFIG_BATTERY_MAX17042=y
++# CONFIG_BATTERY_INTEL_MID is not set
++# CONFIG_CHARGER_ISP1704 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_GPIO is not set
++# CONFIG_CHARGER_MANAGER is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_SMB347 is not set
++# CONFIG_BATTERY_GOLDFISH is not set
++# CONFIG_POWER_RESET is not set
++# CONFIG_POWER_AVS is not set
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
++
++#
++# Native drivers
++#
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_ABITUGURU3 is not set
++# CONFIG_SENSORS_AD7314 is not set
++# CONFIG_SENSORS_AD7414 is not set
++# CONFIG_SENSORS_AD7418 is not set
++# CONFIG_SENSORS_ADCXX is not set
++# CONFIG_SENSORS_ADM1021 is not set
++# CONFIG_SENSORS_ADM1025 is not set
++# CONFIG_SENSORS_ADM1026 is not set
++# CONFIG_SENSORS_ADM1029 is not set
++# CONFIG_SENSORS_ADM1031 is not set
++# CONFIG_SENSORS_ADM9240 is not set
++# CONFIG_SENSORS_ADT7310 is not set
++# CONFIG_SENSORS_ADT7410 is not set
++# CONFIG_SENSORS_ADT7411 is not set
++# CONFIG_SENSORS_ADT7462 is not set
++# CONFIG_SENSORS_ADT7470 is not set
++# CONFIG_SENSORS_ADT7475 is not set
++# CONFIG_SENSORS_ASC7621 is not set
++# CONFIG_SENSORS_K8TEMP is not set
++# CONFIG_SENSORS_K10TEMP is not set
++# CONFIG_SENSORS_FAM15H_POWER is not set
++# CONFIG_SENSORS_ASB100 is not set
++# CONFIG_SENSORS_ATXP1 is not set
++# CONFIG_SENSORS_DS620 is not set
++# CONFIG_SENSORS_DS1621 is not set
++# CONFIG_SENSORS_I5K_AMB is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_F71882FG is not set
++# CONFIG_SENSORS_F75375S is not set
++# CONFIG_SENSORS_FSCHMD is not set
++# CONFIG_SENSORS_G760A is not set
++# CONFIG_SENSORS_GL518SM is not set
++# CONFIG_SENSORS_GL520SM is not set
++# CONFIG_SENSORS_GPIO_FAN is not set
++# CONFIG_SENSORS_HIH6130 is not set
++CONFIG_SENSORS_CORETEMP=y
++CONFIG_SENSORS_CORETEMP_INTERRUPT=y
++# CONFIG_SENSORS_IIO_HWMON is not set
++# CONFIG_SENSORS_IT87 is not set
++# CONFIG_SENSORS_JC42 is not set
++# CONFIG_SENSORS_LINEAGE is not set
++# CONFIG_SENSORS_LM63 is not set
++# CONFIG_SENSORS_LM70 is not set
++# CONFIG_SENSORS_LM73 is not set
++# CONFIG_SENSORS_LM75 is not set
++# CONFIG_SENSORS_LM77 is not set
++# CONFIG_SENSORS_LM78 is not set
++# CONFIG_SENSORS_LM80 is not set
++# CONFIG_SENSORS_LM83 is not set
++# CONFIG_SENSORS_LM85 is not set
++# CONFIG_SENSORS_LM87 is not set
++# CONFIG_SENSORS_LM90 is not set
++# CONFIG_SENSORS_LM92 is not set
++# CONFIG_SENSORS_LM93 is not set
++# CONFIG_SENSORS_LTC4151 is not set
++# CONFIG_SENSORS_LTC4215 is not set
++# CONFIG_SENSORS_LTC4245 is not set
++# CONFIG_SENSORS_LTC4261 is not set
++# CONFIG_SENSORS_LM95234 is not set
++# CONFIG_SENSORS_LM95241 is not set
++# CONFIG_SENSORS_LM95245 is not set
++CONFIG_MSIC_GPADC=y
++# CONFIG_SENSORS_MAX1111 is not set
++# CONFIG_SENSORS_MAX16065 is not set
++# CONFIG_SENSORS_MAX1619 is not set
++# CONFIG_SENSORS_MAX1668 is not set
++# CONFIG_SENSORS_MAX197 is not set
++# CONFIG_SENSORS_MAX6639 is not set
++# CONFIG_SENSORS_MAX6642 is not set
++# CONFIG_SENSORS_MAX6650 is not set
++# CONFIG_SENSORS_MAX6697 is not set
++# CONFIG_SENSORS_MCP3021 is not set
++# CONFIG_SENSORS_NCT6775 is not set
++# CONFIG_SENSORS_PC87360 is not set
++# CONFIG_SENSORS_PC87427 is not set
++# CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_PMBUS is not set
++# CONFIG_SENSORS_SHT15 is not set
++# CONFIG_SENSORS_SHT21 is not set
++# CONFIG_SENSORS_SIS5595 is not set
++# CONFIG_SENSORS_SMM665 is not set
++# CONFIG_SENSORS_DME1737 is not set
++# CONFIG_SENSORS_EMC1403 is not set
++# CONFIG_SENSORS_EMC2103 is not set
++# CONFIG_SENSORS_EMC6W201 is not set
++# CONFIG_SENSORS_SMSC47M1 is not set
++# CONFIG_SENSORS_SMSC47M192 is not set
++# CONFIG_SENSORS_SMSC47B397 is not set
++# CONFIG_SENSORS_SCH56XX_COMMON is not set
++# CONFIG_SENSORS_SCH5627 is not set
++# CONFIG_SENSORS_SCH5636 is not set
++# CONFIG_SENSORS_ADS1015 is not set
++# CONFIG_SENSORS_ADS7828 is not set
++# CONFIG_SENSORS_ADS7871 is not set
++# CONFIG_SENSORS_AMC6821 is not set
++# CONFIG_SENSORS_INA209 is not set
++# CONFIG_SENSORS_INA2XX is not set
++# CONFIG_SENSORS_THMC50 is not set
++# CONFIG_SENSORS_TMP102 is not set
++# CONFIG_SENSORS_TMP401 is not set
++# CONFIG_SENSORS_TMP421 is not set
++# CONFIG_SENSORS_VIA_CPUTEMP is not set
++# CONFIG_SENSORS_VIA686A is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_SENSORS_VT8231 is not set
++# CONFIG_SENSORS_W83781D is not set
++# CONFIG_SENSORS_W83791D is not set
++# CONFIG_SENSORS_W83792D is not set
++# CONFIG_SENSORS_W83793 is not set
++# CONFIG_SENSORS_W83795 is not set
++# CONFIG_SENSORS_W83L785TS is not set
++# CONFIG_SENSORS_W83L786NG is not set
++# CONFIG_SENSORS_W83627HF is not set
++# CONFIG_SENSORS_W83627EHF is not set
++# CONFIG_SENSORS_APPLESMC is not set
++CONFIG_THERMAL=y
++CONFIG_THERMAL_HWMON=y
++CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
++# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
++# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
++# CONFIG_THERMAL_GOV_FAIR_SHARE is not set
++CONFIG_THERMAL_GOV_STEP_WISE=y
++# CONFIG_THERMAL_GOV_USER_SPACE is not set
++# CONFIG_CPU_THERMAL is not set
++# CONFIG_THERMAL_EMULATION is not set
++# CONFIG_INTEL_POWERCLAMP is not set
++CONFIG_SENSORS_THERMAL_MRFLD=y
++CONFIG_SOC_THERMAL=y
++CONFIG_WATCHDOG=y
++# CONFIG_WATCHDOG_CORE is not set
++# CONFIG_WATCHDOG_NOWAYOUT is not set
++
++#
++# Watchdog Device Drivers
++#
++# CONFIG_SOFT_WATCHDOG is not set
++# CONFIG_ACQUIRE_WDT is not set
++# CONFIG_ADVANTECH_WDT is not set
++# CONFIG_ALIM1535_WDT is not set
++# CONFIG_ALIM7101_WDT is not set
++# CONFIG_F71808E_WDT is not set
++# CONFIG_SP5100_TCO is not set
++# CONFIG_SC520_WDT is not set
++# CONFIG_SBC_FITPC2_WATCHDOG is not set
++# CONFIG_EUROTECH_WDT is not set
++# CONFIG_IB700_WDT is not set
++# CONFIG_IBMASR is not set
++# CONFIG_WAFER_WDT is not set
++# CONFIG_I6300ESB_WDT is not set
++# CONFIG_IE6XX_WDT is not set
++# CONFIG_INTEL_SCU_WATCHDOG is not set
++CONFIG_INTEL_SCU_WATCHDOG_EVO=y
++CONFIG_DISABLE_SCU_WATCHDOG=y
++# CONFIG_ITCO_WDT is not set
++# CONFIG_IT8712F_WDT is not set
++# CONFIG_IT87_WDT is not set
++# CONFIG_HP_WATCHDOG is not set
++# CONFIG_SC1200_WDT is not set
++# CONFIG_PC87413_WDT is not set
++# CONFIG_NV_TCO is not set
++# CONFIG_60XX_WDT is not set
++# CONFIG_SBC8360_WDT is not set
++# CONFIG_SBC7240_WDT is not set
++# CONFIG_CPU5_WDT is not set
++# CONFIG_SMSC_SCH311X_WDT is not set
++# CONFIG_SMSC37B787_WDT is not set
++# CONFIG_VIA_WDT is not set
++# CONFIG_W83627HF_WDT is not set
++# CONFIG_W83697HF_WDT is not set
++# CONFIG_W83697UG_WDT is not set
++# CONFIG_W83877F_WDT is not set
++# CONFIG_W83977F_WDT is not set
++# CONFIG_MACHZ_WDT is not set
++# CONFIG_SBC_EPX_C3_WATCHDOG is not set
++
++#
++# PCI-based Watchdog Cards
++#
++# CONFIG_PCIPCWATCHDOG is not set
++# CONFIG_WDTPCI is not set
++
++#
++# USB-based Watchdog Cards
++#
++# CONFIG_USBPCWATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_BCMA_POSSIBLE=y
++
++#
++# Broadcom specific AMBA
++#
++# CONFIG_BCMA is not set
++
++#
++# Multifunction device drivers
++#
++CONFIG_MFD_CORE=y
++# CONFIG_MFD_CS5535 is not set
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_LPC_ICH is not set
++# CONFIG_LPC_SCH is not set
++CONFIG_MFD_INTEL_MSIC=y
++# CONFIG_MFD_JANZ_CMODIO is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX77686 is not set
++# CONFIG_MFD_MAX77693 is not set
++# CONFIG_MFD_MAX8907 is not set
++# CONFIG_MFD_MAX8925 is not set
++# CONFIG_MFD_MAX8997 is not set
++# CONFIG_MFD_MAX8998 is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_RDC321X is not set
++# CONFIG_MFD_RTSX_PCI is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++# CONFIG_MFD_SYSCON is not set
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TIMBERDALE is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_VX855 is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++CONFIG_MFD_WM8994=y
++CONFIG_REGULATOR=y
++# CONFIG_REGULATOR_DEBUG is not set
++# CONFIG_REGULATOR_DUMMY is not set
++CONFIG_REGULATOR_FIXED_VOLTAGE=y
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_GPIO is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_FAN53555 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++CONFIG_REGULATOR_WM8994=y
++CONFIG_REGULATOR_PMIC_BASIN_COVE=y
++CONFIG_MEDIA_SUPPORT=y
++
++#
++# Multimedia core support
++#
++CONFIG_MEDIA_CAMERA_SUPPORT=y
++# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
++# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
++# CONFIG_MEDIA_RADIO_SUPPORT is not set
++# CONFIG_MEDIA_RC_SUPPORT is not set
++CONFIG_MEDIA_CONTROLLER=y
++CONFIG_VIDEO_DEV=y
++CONFIG_VIDEO_V4L2_SUBDEV_API=y
++CONFIG_VIDEO_V4L2=y
++# CONFIG_VIDEO_ADV_DEBUG is not set
++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
++# CONFIG_VIDEO_V4L2_INT_DEVICE is not set
++# CONFIG_TTPCI_EEPROM is not set
++
++#
++# Media drivers
++#
++# CONFIG_MEDIA_USB_SUPPORT is not set
++# CONFIG_MEDIA_PCI_SUPPORT is not set
++# CONFIG_V4L_PLATFORM_DRIVERS is not set
++# CONFIG_V4L_MEM2MEM_DRIVERS is not set
++# CONFIG_V4L_TEST_DRIVERS is not set
++
++#
++# Supported MMC/SDIO adapters
++#
++# CONFIG_CYPRESS_FIRMWARE is not set
++
++#
++# Media ancillary drivers (tuners, sensors, i2c, frontends)
++#
++# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
++
++#
++# Encoders, decoders, sensors and other helper chips
++#
++
++#
++# Audio decoders, processors and mixers
++#
++# CONFIG_VIDEO_TVAUDIO is not set
++# CONFIG_VIDEO_TDA7432 is not set
++# CONFIG_VIDEO_TDA9840 is not set
++# CONFIG_VIDEO_TEA6415C is not set
++# CONFIG_VIDEO_TEA6420 is not set
++# CONFIG_VIDEO_MSP3400 is not set
++# CONFIG_VIDEO_CS5345 is not set
++# CONFIG_VIDEO_CS53L32A is not set
++# CONFIG_VIDEO_TLV320AIC23B is not set
++# CONFIG_VIDEO_UDA1342 is not set
++# CONFIG_VIDEO_WM8775 is not set
++# CONFIG_VIDEO_WM8739 is not set
++# CONFIG_VIDEO_VP27SMPX is not set
++# CONFIG_VIDEO_SONY_BTF_MPX is not set
++
++#
++# RDS decoders
++#
++# CONFIG_VIDEO_SAA6588 is not set
++
++#
++# Video decoders
++#
++# CONFIG_VIDEO_ADV7180 is not set
++# CONFIG_VIDEO_ADV7183 is not set
++# CONFIG_VIDEO_ADV7604 is not set
++# CONFIG_VIDEO_BT819 is not set
++# CONFIG_VIDEO_BT856 is not set
++# CONFIG_VIDEO_BT866 is not set
++# CONFIG_VIDEO_KS0127 is not set
++# CONFIG_VIDEO_SAA7110 is not set
++# CONFIG_VIDEO_SAA711X is not set
++# CONFIG_VIDEO_SAA7191 is not set
++# CONFIG_VIDEO_TVP514X is not set
++# CONFIG_VIDEO_TVP5150 is not set
++# CONFIG_VIDEO_TVP7002 is not set
++# CONFIG_VIDEO_TW2804 is not set
++# CONFIG_VIDEO_TW9903 is not set
++# CONFIG_VIDEO_TW9906 is not set
++# CONFIG_VIDEO_VPX3220 is not set
++
++#
++# Video and audio decoders
++#
++# CONFIG_VIDEO_SAA717X is not set
++# CONFIG_VIDEO_CX25840 is not set
++
++#
++# Video encoders
++#
++# CONFIG_VIDEO_SAA7127 is not set
++# CONFIG_VIDEO_SAA7185 is not set
++# CONFIG_VIDEO_ADV7170 is not set
++# CONFIG_VIDEO_ADV7175 is not set
++# CONFIG_VIDEO_ADV7343 is not set
++# CONFIG_VIDEO_ADV7393 is not set
++# CONFIG_VIDEO_AD9389B is not set
++# CONFIG_VIDEO_AK881X is not set
++
++#
++# Camera sensor devices
++#
++# CONFIG_VIDEO_OV7640 is not set
++# CONFIG_VIDEO_OV7670 is not set
++# CONFIG_VIDEO_OV9650 is not set
++# CONFIG_VIDEO_VS6624 is not set
++# CONFIG_VIDEO_MT9M032 is not set
++# CONFIG_VIDEO_MT9P031 is not set
++# CONFIG_VIDEO_MT9T001 is not set
++# CONFIG_VIDEO_MT9V011 is not set
++# CONFIG_VIDEO_MT9V032 is not set
++# CONFIG_VIDEO_SR030PC30 is not set
++# CONFIG_VIDEO_NOON010PC30 is not set
++# CONFIG_VIDEO_M5MOLS is not set
++# CONFIG_VIDEO_S5K6AA is not set
++# CONFIG_VIDEO_S5K4ECGX is not set
++# CONFIG_VIDEO_S5C73M3 is not set
++
++#
++# Flash devices
++#
++# CONFIG_VIDEO_ADP1653 is not set
++# CONFIG_VIDEO_AS3645A is not set
++
++#
++# Video improvement chips
++#
++# CONFIG_VIDEO_UPD64031A is not set
++# CONFIG_VIDEO_UPD64083 is not set
++
++#
++# Miscelaneous helper chips
++#
++# CONFIG_VIDEO_THS7303 is not set
++# CONFIG_VIDEO_M52790 is not set
++
++#
++# Sensors used on soc_camera driver
++#
++
++#
++# Customise DVB Frontends
++#
++# CONFIG_DVB_AU8522_V4L is not set
++CONFIG_DVB_TUNER_DIB0070=m
++CONFIG_DVB_TUNER_DIB0090=m
++
++#
++# Tools to develop new frontends
++#
++# CONFIG_DVB_DUMMY_FE is not set
++
++#
++# Graphics support
++#
++CONFIG_AGP=y
++# CONFIG_AGP_ALI is not set
++# CONFIG_AGP_ATI is not set
++# CONFIG_AGP_AMD is not set
++CONFIG_AGP_AMD64=y
++CONFIG_AGP_INTEL=y
++# CONFIG_AGP_NVIDIA is not set
++# CONFIG_AGP_SIS is not set
++# CONFIG_AGP_SWORKS is not set
++# CONFIG_AGP_VIA is not set
++# CONFIG_AGP_EFFICEON is not set
++CONFIG_VGA_ARB=y
++CONFIG_VGA_ARB_MAX_GPUS=16
++CONFIG_DRM=y
++# CONFIG_DRM_TDFX is not set
++# CONFIG_DRM_R128 is not set
++# CONFIG_DRM_RADEON is not set
++# CONFIG_DRM_NOUVEAU is not set
++# CONFIG_DRM_I915 is not set
++# CONFIG_DRM_MGA is not set
++# CONFIG_DRM_SIS is not set
++# CONFIG_DRM_VIA is not set
++# CONFIG_DRM_SAVAGE is not set
++# CONFIG_DRM_VMWGFX is not set
++# CONFIG_DRM_GMA500 is not set
++# CONFIG_DRM_UDL is not set
++# CONFIG_DRM_AST is not set
++# CONFIG_DRM_MGAG200 is not set
++# CONFIG_DRM_CIRRUS_QEMU is not set
++# CONFIG_DRM_QXL is not set
++# CONFIG_VGASTATE is not set
++CONFIG_VIDEO_OUTPUT_CONTROL=y
++CONFIG_HDMI=y
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++# CONFIG_FB_CFB_FILLRECT is not set
++# CONFIG_FB_CFB_COPYAREA is not set
++# CONFIG_FB_CFB_IMAGEBLIT is not set
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++CONFIG_FB_MODE_HELPERS=y
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_CIRRUS is not set
++# CONFIG_FB_PM2 is not set
++# CONFIG_FB_CYBER2000 is not set
++# CONFIG_FB_ARC is not set
++# CONFIG_FB_ASILIANT is not set
++# CONFIG_FB_IMSTT is not set
++# CONFIG_FB_VGA16 is not set
++# CONFIG_FB_UVESA is not set
++# CONFIG_FB_VESA is not set
++# CONFIG_FB_N411 is not set
++# CONFIG_FB_HGA is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_NVIDIA is not set
++# CONFIG_FB_RIVA is not set
++# CONFIG_FB_I740 is not set
++# CONFIG_FB_I810 is not set
++# CONFIG_FB_LE80578 is not set
++# CONFIG_FB_INTEL is not set
++# CONFIG_FB_MATROX is not set
++# CONFIG_FB_RADEON is not set
++# CONFIG_FB_ATY128 is not set
++# CONFIG_FB_ATY is not set
++# CONFIG_FB_S3 is not set
++# CONFIG_FB_SAVAGE is not set
++# CONFIG_FB_SIS is not set
++# CONFIG_FB_VIA is not set
++# CONFIG_FB_NEOMAGIC is not set
++# CONFIG_FB_KYRO is not set
++# CONFIG_FB_3DFX is not set
++# CONFIG_FB_VOODOO1 is not set
++# CONFIG_FB_VT8623 is not set
++# CONFIG_FB_TRIDENT is not set
++# CONFIG_FB_ARK is not set
++# CONFIG_FB_PM3 is not set
++# CONFIG_FB_CARMINE is not set
++# CONFIG_FB_GEODE is not set
++# CONFIG_FB_TMIO is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_GOLDFISH is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_MB862XX is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_EXYNOS_VIDEO is not set
++CONFIG_BACKLIGHT_LCD_SUPPORT=y
++# CONFIG_LCD_CLASS_DEVICE is not set
++CONFIG_BACKLIGHT_CLASS_DEVICE=y
++CONFIG_BACKLIGHT_GENERIC=y
++# CONFIG_BACKLIGHT_SAHARA is not set
++# CONFIG_BACKLIGHT_ADP8860 is not set
++# CONFIG_BACKLIGHT_ADP8870 is not set
++# CONFIG_BACKLIGHT_LM3630 is not set
++# CONFIG_BACKLIGHT_LM3639 is not set
++# CONFIG_BACKLIGHT_LP855X is not set
++
++#
++# Console display driver support
++#
++CONFIG_VGA_CONSOLE=y
++# CONFIG_VGACON_SOFT_SCROLLBACK is not set
++CONFIG_DUMMY_CONSOLE=y
++CONFIG_FRAMEBUFFER_CONSOLE=y
++CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
++# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
++# CONFIG_FONTS is not set
++CONFIG_FONT_8x8=y
++CONFIG_FONT_8x16=y
++# CONFIG_LOGO is not set
++CONFIG_SOUND=y
++# CONFIG_SOUND_OSS_CORE is not set
++CONFIG_SND=y
++CONFIG_SND_TIMER=y
++CONFIG_SND_PCM=y
++CONFIG_SND_COMPRESS_OFFLOAD=y
++CONFIG_SND_JACK=y
++CONFIG_SND_SEQUENCER=y
++# CONFIG_SND_SEQ_DUMMY is not set
++# CONFIG_SND_MIXER_OSS is not set
++# CONFIG_SND_PCM_OSS is not set
++# CONFIG_SND_SEQUENCER_OSS is not set
++# CONFIG_SND_HRTIMER is not set
++CONFIG_SND_DYNAMIC_MINORS=y
++# CONFIG_SND_SUPPORT_OLD_API is not set
++# CONFIG_SND_VERBOSE_PROCFS is not set
++# CONFIG_SND_VERBOSE_PRINTK is not set
++# CONFIG_SND_DEBUG is not set
++CONFIG_SND_DMA_SGBUF=y
++# CONFIG_SND_RAWMIDI_SEQ is not set
++# CONFIG_SND_OPL3_LIB_SEQ is not set
++# CONFIG_SND_OPL4_LIB_SEQ is not set
++# CONFIG_SND_SBAWE_SEQ is not set
++# CONFIG_SND_EMU10K1_SEQ is not set
++CONFIG_SND_DRIVERS=y
++# CONFIG_SND_PCSP is not set
++# CONFIG_SND_DUMMY is not set
++CONFIG_SND_ALOOP=y
++# CONFIG_SND_VIRMIDI is not set
++# CONFIG_SND_MTPAV is not set
++# CONFIG_SND_SERIAL_U16550 is not set
++# CONFIG_SND_MPU401 is not set
++# CONFIG_SND_PCI is not set
++# CONFIG_SND_SPI is not set
++CONFIG_SND_USB=y
++# CONFIG_SND_USB_AUDIO is not set
++# CONFIG_SND_USB_UA101 is not set
++# CONFIG_SND_USB_USX2Y is not set
++# CONFIG_SND_USB_CAIAQ is not set
++# CONFIG_SND_USB_US122L is not set
++# CONFIG_SND_USB_6FIRE is not set
++CONFIG_SND_SOC=y
++# CONFIG_SND_ATMEL_SOC is not set
++# CONFIG_SND_MFLD_MACHINE is not set
++CONFIG_SND_SOC_I2C_AND_SPI=y
++# CONFIG_SND_SOC_ALL_CODECS is not set
++# CONFIG_SND_SIMPLE_CARD is not set
++# CONFIG_SOUND_PRIME is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++CONFIG_HIDRAW=y
++CONFIG_UHID=y
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++# CONFIG_HID_A4TECH is not set
++# CONFIG_HID_ACRUX is not set
++# CONFIG_HID_APPLE is not set
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++# CONFIG_HID_BELKIN is not set
++# CONFIG_HID_CHERRY is not set
++# CONFIG_HID_CHICONY is not set
++# CONFIG_HID_PRODIKEYS is not set
++# CONFIG_HID_CYPRESS is not set
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_EZKEY is not set
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_KEYTOUCH is not set
++# CONFIG_HID_KYE is not set
++# CONFIG_HID_UCLOGIC is not set
++# CONFIG_HID_WALTOP is not set
++# CONFIG_HID_GYRATION is not set
++# CONFIG_HID_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++# CONFIG_HID_KENSINGTON is not set
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO_TPKBD is not set
++# CONFIG_HID_LOGITECH is not set
++# CONFIG_HID_MAGICMOUSE is not set
++# CONFIG_HID_MICROSOFT is not set
++# CONFIG_HID_MONTEREY is not set
++# CONFIG_HID_MULTITOUCH is not set
++# CONFIG_HID_NTRIG is not set
++# CONFIG_HID_ORTEK is not set
++# CONFIG_HID_PANTHERLORD is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_PS3REMOTE is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SONY is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_GREENASIA is not set
++# CONFIG_HID_SMARTJOYPLUS is not set
++# CONFIG_HID_TIVO is not set
++# CONFIG_HID_TOPSEED is not set
++# CONFIG_HID_THINGM is not set
++# CONFIG_HID_THRUSTMASTER is not set
++# CONFIG_HID_WACOM is not set
++# CONFIG_HID_WIIMOTE is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=y
++CONFIG_HID_PID=y
++CONFIG_USB_HIDDEV=y
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_ARCH_HAS_OHCI=y
++CONFIG_USB_ARCH_HAS_EHCI=y
++CONFIG_USB_ARCH_HAS_XHCI=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEFAULT_PERSIST=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++CONFIG_USB_OTG=y
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++CONFIG_USB_MON=y
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_XHCI_HCD=y
++CONFIG_USB_XHCI_PLATFORM=y
++# CONFIG_USB_XHCI_HCD_DEBUGGING is not set
++CONFIG_USB_EHCI_HCD=y
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++# CONFIG_USB_EHCI_TT_NEWSCHED is not set
++CONFIG_USB_EHCI_PCI=y
++# CONFIG_USB_EHCI_HCD_PLATFORM is not set
++# CONFIG_USB_OXU210HP_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++# CONFIG_USB_ISP1760_HCD is not set
++# CONFIG_USB_ISP1362_HCD is not set
++# CONFIG_USB_OHCI_HCD is not set
++# CONFIG_USB_UHCI_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_RENESAS_USBHS is not set
++
++#
++# USB Device Class drivers
++#
++CONFIG_USB_ACM=y
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++CONFIG_USB_DWC3=y
++# CONFIG_USB_DWC3_HOST is not set
++CONFIG_USB_DWC3_GADGET=y
++# CONFIG_USB_DWC3_DUAL_ROLE is not set
++
++#
++# Platform Glue Driver Support
++#
++# CONFIG_USB_DWC3_PCI is not set
++CONFIG_USB_DWC3_OTG=y
++CONFIG_USB_DWC3_INTEL_MRFL=y
++# CONFIG_USB_DWC3_INTEL_BYT is not set
++CONFIG_USB_DWC3_DEVICE_INTEL=y
++CONFIG_USB_DWC3_HOST_INTEL=y
++
++#
++# Debugging features
++#
++# CONFIG_USB_DWC3_DEBUG is not set
++# CONFIG_USB_CHIPIDEA is not set
++
++#
++# USB port drivers
++#
++CONFIG_USB_SERIAL=y
++# CONFIG_USB_SERIAL_CONSOLE is not set
++# CONFIG_USB_SERIAL_GENERIC is not set
++# CONFIG_USB_SERIAL_AIRCABLE is not set
++# CONFIG_USB_SERIAL_ARK3116 is not set
++# CONFIG_USB_SERIAL_BELKIN is not set
++# CONFIG_USB_SERIAL_CH341 is not set
++# CONFIG_USB_SERIAL_WHITEHEAT is not set
++# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
++# CONFIG_USB_SERIAL_CP210X is not set
++# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
++# CONFIG_USB_SERIAL_EMPEG is not set
++# CONFIG_USB_SERIAL_FTDI_SIO is not set
++# CONFIG_USB_SERIAL_FUNSOFT is not set
++# CONFIG_USB_SERIAL_VISOR is not set
++# CONFIG_USB_SERIAL_IPAQ is not set
++# CONFIG_USB_SERIAL_IR is not set
++# CONFIG_USB_SERIAL_EDGEPORT is not set
++# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
++# CONFIG_USB_SERIAL_F81232 is not set
++# CONFIG_USB_SERIAL_GARMIN is not set
++# CONFIG_USB_SERIAL_IPW is not set
++# CONFIG_USB_SERIAL_IUU is not set
++# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
++# CONFIG_USB_SERIAL_KEYSPAN is not set
++# CONFIG_USB_SERIAL_KLSI is not set
++# CONFIG_USB_SERIAL_KOBIL_SCT is not set
++# CONFIG_USB_SERIAL_MCT_U232 is not set
++# CONFIG_USB_SERIAL_METRO is not set
++# CONFIG_USB_SERIAL_MOS7720 is not set
++# CONFIG_USB_SERIAL_MOS7840 is not set
++# CONFIG_USB_SERIAL_MOTOROLA is not set
++# CONFIG_USB_SERIAL_NAVMAN is not set
++CONFIG_USB_SERIAL_PL2303=y
++# CONFIG_USB_SERIAL_OTI6858 is not set
++# CONFIG_USB_SERIAL_QCAUX is not set
++# CONFIG_USB_SERIAL_QUALCOMM is not set
++# CONFIG_USB_SERIAL_SPCP8X5 is not set
++# CONFIG_USB_SERIAL_HP4X is not set
++# CONFIG_USB_SERIAL_SAFE is not set
++# CONFIG_USB_SERIAL_SIEMENS_MPI is not set
++# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
++# CONFIG_USB_SERIAL_SYMBOL is not set
++# CONFIG_USB_SERIAL_TI is not set
++# CONFIG_USB_SERIAL_CYBERJACK is not set
++# CONFIG_USB_SERIAL_XIRCOM is not set
++# CONFIG_USB_SERIAL_OPTION is not set
++# CONFIG_USB_SERIAL_OMNINET is not set
++# CONFIG_USB_SERIAL_OPTICON is not set
++# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set
++# CONFIG_USB_SERIAL_XSENS_MT is not set
++# CONFIG_USB_SERIAL_ZIO is not set
++# CONFIG_USB_SERIAL_WISHBONE is not set
++# CONFIG_USB_SERIAL_ZTE is not set
++# CONFIG_USB_SERIAL_SSU100 is not set
++# CONFIG_USB_SERIAL_QT2 is not set
++# CONFIG_USB_SERIAL_DEBUG is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++# CONFIG_USB_HSIC_USB3503 is not set
++CONFIG_USB_PHY=y
++CONFIG_NOP_USB_XCEIV=y
++# CONFIG_OMAP_CONTROL_USB is not set
++# CONFIG_OMAP_USB3 is not set
++# CONFIG_SAMSUNG_USBPHY is not set
++# CONFIG_SAMSUNG_USB2PHY is not set
++# CONFIG_SAMSUNG_USB3PHY is not set
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_RCAR_PHY is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++# CONFIG_USB_GADGET_DEBUG_FS is not set
++CONFIG_USB_GADGET_VBUS_DRAW=500
++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
++
++#
++# USB Peripheral Controller
++#
++# CONFIG_USB_R8A66597 is not set
++# CONFIG_USB_PXA27X is not set
++# CONFIG_USB_MV_UDC is not set
++# CONFIG_USB_MV_U3D is not set
++# CONFIG_USB_M66592 is not set
++# CONFIG_USB_AMD5536UDC is not set
++# CONFIG_USB_NET2272 is not set
++# CONFIG_USB_NET2280 is not set
++# CONFIG_USB_GOKU is not set
++# CONFIG_USB_EG20T is not set
++# CONFIG_USB_DUMMY_HCD is not set
++# CONFIG_USB_ZERO is not set
++# CONFIG_USB_AUDIO is not set
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_G_NCM is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FUNCTIONFS is not set
++# CONFIG_USB_MASS_STORAGE is not set
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_MIDI_GADGET is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++# CONFIG_USB_G_ACM_MS is not set
++# CONFIG_USB_G_MULTI is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++# CONFIG_USB_G_WEBCAM is not set
++# CONFIG_UWB is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++CONFIG_MMC_UNSAFE_RESUME=y
++# CONFIG_MMC_CLKGATE is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_MINORS=10
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++CONFIG_MMC_SDHCI=y
++CONFIG_MMC_SDHCI_PCI=y
++# CONFIG_MMC_RICOH_MMC is not set
++# CONFIG_MMC_SDHCI_PLTFM is not set
++# CONFIG_MMC_WBSD is not set
++# CONFIG_MMC_TIFM_SD is not set
++# CONFIG_MMC_CB710 is not set
++# CONFIG_MMC_VIA_SDMMC is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MEMSTICK is not set
++CONFIG_NEW_LEDS=y
++CONFIG_LEDS_CLASS=y
++
++#
++# LED drivers
++#
++# CONFIG_LEDS_LM3530 is not set
++# CONFIG_LEDS_LM3642 is not set
++# CONFIG_LEDS_PCA9532 is not set
++# CONFIG_LEDS_GPIO is not set
++# CONFIG_LEDS_LP3944 is not set
++# CONFIG_LEDS_LP5521 is not set
++# CONFIG_LEDS_LP5523 is not set
++# CONFIG_LEDS_LP5562 is not set
++# CONFIG_LEDS_PCA955X is not set
++# CONFIG_LEDS_PCA9633 is not set
++# CONFIG_LEDS_DAC124S085 is not set
++# CONFIG_LEDS_REGULATOR is not set
++# CONFIG_LEDS_BD2802 is not set
++# CONFIG_LEDS_INTEL_SS4200 is not set
++# CONFIG_LEDS_LT3593 is not set
++# CONFIG_LEDS_TCA6507 is not set
++# CONFIG_LEDS_LM355x is not set
++# CONFIG_LEDS_OT200 is not set
++# CONFIG_LEDS_BLINKM is not set
++
++#
++# LED Triggers
++#
++CONFIG_LEDS_TRIGGERS=y
++# CONFIG_LEDS_TRIGGER_TIMER is not set
++# CONFIG_LEDS_TRIGGER_ONESHOT is not set
++# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
++# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
++# CONFIG_LEDS_TRIGGER_CPU is not set
++# CONFIG_LEDS_TRIGGER_GPIO is not set
++# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
++
++#
++# iptables trigger is under Netfilter config (LED target)
++#
++# CONFIG_LEDS_TRIGGER_TRANSIENT is not set
++# CONFIG_LEDS_TRIGGER_CAMERA is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_INFINIBAND is not set
++CONFIG_EDAC=y
++CONFIG_EDAC_LEGACY_SYSFS=y
++# CONFIG_EDAC_DEBUG is not set
++# CONFIG_EDAC_MM_EDAC is not set
++CONFIG_RTC_LIB=y
++CONFIG_RTC_CLASS=y
++CONFIG_RTC_HCTOSYS=y
++CONFIG_RTC_SYSTOHC=y
++CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
++# CONFIG_RTC_DEBUG is not set
++
++#
++# RTC interfaces
++#
++CONFIG_RTC_INTF_SYSFS=y
++CONFIG_RTC_INTF_PROC=y
++CONFIG_RTC_INTF_DEV=y
++# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
++# CONFIG_RTC_DRV_TEST is not set
++
++#
++# I2C RTC drivers
++#
++# CONFIG_RTC_DRV_DS1307 is not set
++# CONFIG_RTC_DRV_DS1374 is not set
++# CONFIG_RTC_DRV_DS1672 is not set
++# CONFIG_RTC_DRV_DS3232 is not set
++# CONFIG_RTC_DRV_MAX6900 is not set
++# CONFIG_RTC_DRV_RS5C372 is not set
++# CONFIG_RTC_DRV_ISL1208 is not set
++# CONFIG_RTC_DRV_ISL12022 is not set
++# CONFIG_RTC_DRV_X1205 is not set
++# CONFIG_RTC_DRV_PCF8523 is not set
++# CONFIG_RTC_DRV_PCF8563 is not set
++# CONFIG_RTC_DRV_PCF8583 is not set
++# CONFIG_RTC_DRV_M41T80 is not set
++# CONFIG_RTC_DRV_BQ32K is not set
++# CONFIG_RTC_DRV_S35390A is not set
++# CONFIG_RTC_DRV_FM3130 is not set
++# CONFIG_RTC_DRV_RX8581 is not set
++# CONFIG_RTC_DRV_RX8025 is not set
++# CONFIG_RTC_DRV_EM3027 is not set
++# CONFIG_RTC_DRV_RV3029C2 is not set
++
++#
++# SPI RTC drivers
++#
++# CONFIG_RTC_DRV_M41T93 is not set
++# CONFIG_RTC_DRV_M41T94 is not set
++# CONFIG_RTC_DRV_DS1305 is not set
++# CONFIG_RTC_DRV_DS1390 is not set
++# CONFIG_RTC_DRV_MAX6902 is not set
++# CONFIG_RTC_DRV_R9701 is not set
++# CONFIG_RTC_DRV_RS5C348 is not set
++# CONFIG_RTC_DRV_DS3234 is not set
++# CONFIG_RTC_DRV_PCF2123 is not set
++# CONFIG_RTC_DRV_RX4581 is not set
++
++#
++# Platform RTC drivers
++#
++CONFIG_RTC_DRV_CMOS=y
++# CONFIG_RTC_DRV_VRTC is not set
++# CONFIG_RTC_DRV_DS1286 is not set
++# CONFIG_RTC_DRV_DS1511 is not set
++# CONFIG_RTC_DRV_DS1553 is not set
++# CONFIG_RTC_DRV_DS1742 is not set
++# CONFIG_RTC_DRV_STK17TA8 is not set
++# CONFIG_RTC_DRV_M48T86 is not set
++# CONFIG_RTC_DRV_M48T35 is not set
++# CONFIG_RTC_DRV_M48T59 is not set
++# CONFIG_RTC_DRV_MSM6242 is not set
++# CONFIG_RTC_DRV_BQ4802 is not set
++# CONFIG_RTC_DRV_RP5C01 is not set
++# CONFIG_RTC_DRV_V3020 is not set
++# CONFIG_RTC_DRV_DS2404 is not set
++
++#
++# on-CPU RTC drivers
++#
++
++#
++# HID Sensor RTC drivers
++#
++# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set
++CONFIG_DMADEVICES=y
++# CONFIG_DMADEVICES_DEBUG is not set
++
++#
++# DMA Devices
++#
++CONFIG_INTEL_MID_DMAC=y
++# CONFIG_INTEL_IOATDMA is not set
++# CONFIG_DW_DMAC is not set
++# CONFIG_TIMB_DMA is not set
++# CONFIG_PCH_DMA is not set
++CONFIG_DMA_ENGINE=y
++
++#
++# DMA Clients
++#
++# CONFIG_NET_DMA is not set
++# CONFIG_ASYNC_TX_DMA is not set
++# CONFIG_DMATEST is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++CONFIG_VIRTIO=y
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_PCI is not set
++# CONFIG_VIRTIO_BALLOON is not set
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++CONFIG_STAGING=y
++# CONFIG_ET131X is not set
++# CONFIG_SLICOSS is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_W35UND is not set
++# CONFIG_PRISM2_USB is not set
++# CONFIG_ECHO is not set
++# CONFIG_COMEDI is not set
++# CONFIG_ASUS_OLED is not set
++# CONFIG_R8187SE is not set
++# CONFIG_RTL8192U is not set
++# CONFIG_RTLLIB is not set
++# CONFIG_R8712U is not set
++# CONFIG_RTS5139 is not set
++# CONFIG_TRANZPORT is not set
++# CONFIG_IDE_PHISON is not set
++# CONFIG_LINE6_USB is not set
++# CONFIG_USB_SERIAL_QUATECH2 is not set
++# CONFIG_VT6655 is not set
++# CONFIG_VT6656 is not set
++# CONFIG_DX_SEP is not set
++
++#
++# IIO staging drivers
++#
++
++#
++# Accelerometers
++#
++# CONFIG_ADIS16201 is not set
++# CONFIG_ADIS16203 is not set
++# CONFIG_ADIS16204 is not set
++# CONFIG_ADIS16209 is not set
++# CONFIG_ADIS16220 is not set
++# CONFIG_ADIS16240 is not set
++# CONFIG_LIS3L02DQ is not set
++
++#
++# Analog to digital converters
++#
++# CONFIG_AD7291 is not set
++# CONFIG_AD7606 is not set
++# CONFIG_AD799X is not set
++# CONFIG_AD7780 is not set
++# CONFIG_AD7816 is not set
++# CONFIG_AD7192 is not set
++# CONFIG_AD7280 is not set
++
++#
++# Analog digital bi-direction converters
++#
++# CONFIG_ADT7316 is not set
++
++#
++# Capacitance to digital converters
++#
++# CONFIG_AD7150 is not set
++# CONFIG_AD7152 is not set
++# CONFIG_AD7746 is not set
++
++#
++# Direct Digital Synthesis
++#
++# CONFIG_AD5930 is not set
++# CONFIG_AD9832 is not set
++# CONFIG_AD9834 is not set
++# CONFIG_AD9850 is not set
++# CONFIG_AD9852 is not set
++# CONFIG_AD9910 is not set
++# CONFIG_AD9951 is not set
++
++#
++# Digital gyroscope sensors
++#
++# CONFIG_ADIS16060 is not set
++# CONFIG_ADIS16130 is not set
++# CONFIG_ADIS16260 is not set
++
++#
++# Network Analyzer, Impedance Converters
++#
++# CONFIG_AD5933 is not set
++
++#
++# Light sensors
++#
++# CONFIG_SENSORS_ISL29018 is not set
++# CONFIG_SENSORS_ISL29028 is not set
++# CONFIG_TSL2583 is not set
++# CONFIG_TSL2x7x is not set
++
++#
++# Magnetometer sensors
++#
++# CONFIG_SENSORS_HMC5843 is not set
++
++#
++# Active energy metering IC
++#
++# CONFIG_ADE7753 is not set
++# CONFIG_ADE7754 is not set
++# CONFIG_ADE7758 is not set
++# CONFIG_ADE7759 is not set
++# CONFIG_ADE7854 is not set
++
++#
++# Resolver to digital converters
++#
++# CONFIG_AD2S90 is not set
++# CONFIG_AD2S1200 is not set
++# CONFIG_AD2S1210 is not set
++
++#
++# Triggers - standalone
++#
++# CONFIG_IIO_SIMPLE_DUMMY is not set
++# CONFIG_ZSMALLOC is not set
++# CONFIG_FB_SM7XX is not set
++# CONFIG_CRYSTALHD is not set
++# CONFIG_FB_XGI is not set
++# CONFIG_USB_ENESTORAGE is not set
++# CONFIG_BCM_WIMAX is not set
++# CONFIG_FT1000 is not set
++
++#
++# Speakup console speech
++#
++# CONFIG_SPEAKUP is not set
++# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set
++# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set
++# CONFIG_STAGING_MEDIA is not set
++
++#
++# Android
++#
++CONFIG_ANDROID=y
++CONFIG_ANDROID_BINDER_IPC=y
++CONFIG_ASHMEM=y
++CONFIG_ANDROID_LOGGER=y
++CONFIG_ANDROID_TIMED_OUTPUT=y
++# CONFIG_ANDROID_TIMED_GPIO is not set
++CONFIG_ANDROID_LOW_MEMORY_KILLER=y
++CONFIG_ANDROID_INTF_ALARM_DEV=y
++CONFIG_SYNC=y
++CONFIG_SW_SYNC=y
++CONFIG_SW_SYNC_USER=y
++# CONFIG_USB_WPAN_HCD is not set
++# CONFIG_WIMAX_GDM72XX is not set
++# CONFIG_NET_VENDOR_SILICOM is not set
++# CONFIG_CED1401 is not set
++# CONFIG_DGRP is not set
++# CONFIG_USB_DWC2 is not set
++CONFIG_X86_PLATFORM_DEVICES=y
++# CONFIG_CHROMEOS_LAPTOP is not set
++# CONFIG_AMILO_RFKILL is not set
++# CONFIG_SENSORS_HDAPS is not set
++CONFIG_INTEL_SCU_IPC=y
++CONFIG_INTEL_SCU_IPC_INTR_MODE=y
++# CONFIG_INTEL_SCU_IPC_POLL_MODE is not set
++CONFIG_INTEL_SCU_IPC_UTIL=y
++CONFIG_GPIO_INTEL_PMIC=y
++CONFIG_INTEL_MID_POWER_BUTTON=y
++# CONFIG_INTEL_MFLD_THERMAL is not set
++# CONFIG_IBM_RTL is not set
++# CONFIG_SAMSUNG_LAPTOP is not set
++CONFIG_INTEL_SCU_FLIS=y
++
++#
++# Hardware Spinlock drivers
++#
++CONFIG_CLKSRC_I8253=y
++CONFIG_CLKEVT_I8253=y
++CONFIG_I8253_LOCK=y
++CONFIG_CLKBLD_I8253=y
++# CONFIG_MAILBOX is not set
++CONFIG_IOMMU_SUPPORT=y
++
++#
++# Remoteproc drivers
++#
++CONFIG_REMOTEPROC=y
++# CONFIG_STE_MODEM_RPROC is not set
++CONFIG_INTEL_MID_REMOTEPROC=y
++
++#
++# Rpmsg drivers
++#
++CONFIG_RPMSG=y
++CONFIG_RPMSG_IPC=y
++CONFIG_PM_DEVFREQ=y
++
++#
++# DEVFREQ Governors
++#
++CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y
++CONFIG_DEVFREQ_GOV_PERFORMANCE=y
++CONFIG_DEVFREQ_GOV_POWERSAVE=y
++CONFIG_DEVFREQ_GOV_USERSPACE=y
++
++#
++# DEVFREQ Drivers
++#
++CONFIG_EXTCON=y
++
++#
++# Extcon Device Drivers
++#
++# CONFIG_EXTCON_GPIO is not set
++# CONFIG_EXTCON_ADC_JACK is not set
++# CONFIG_MEMORY is not set
++CONFIG_IIO=y
++# CONFIG_IIO_BUFFER is not set
++# CONFIG_IIO_TRIGGER is not set
++
++#
++# Accelerometers
++#
++# CONFIG_KXSD9 is not set
++# CONFIG_IIO_ST_ACCEL_3AXIS is not set
++
++#
++# Analog to digital converters
++#
++# CONFIG_AD7266 is not set
++# CONFIG_AD7298 is not set
++# CONFIG_AD7923 is not set
++# CONFIG_AD7791 is not set
++# CONFIG_AD7793 is not set
++# CONFIG_AD7476 is not set
++# CONFIG_AD7887 is not set
++# CONFIG_MAX1363 is not set
++# CONFIG_TI_ADC081C is not set
++CONFIG_IIO_BASINCOVE_GPADC=y
++
++#
++# Amplifiers
++#
++# CONFIG_AD8366 is not set
++
++#
++# Hid Sensor IIO Common
++#
++
++#
++# Digital to analog converters
++#
++# CONFIG_AD5064 is not set
++# CONFIG_AD5360 is not set
++# CONFIG_AD5380 is not set
++# CONFIG_AD5421 is not set
++# CONFIG_AD5624R_SPI is not set
++# CONFIG_AD5446 is not set
++# CONFIG_AD5449 is not set
++# CONFIG_AD5504 is not set
++# CONFIG_AD5755 is not set
++# CONFIG_AD5764 is not set
++# CONFIG_AD5791 is not set
++# CONFIG_AD5686 is not set
++# CONFIG_MAX517 is not set
++# CONFIG_MCP4725 is not set
++
++#
++# Frequency Synthesizers DDS/PLL
++#
++
++#
++# Clock Generator/Distribution
++#
++# CONFIG_AD9523 is not set
++
++#
++# Phase-Locked Loop (PLL) frequency synthesizers
++#
++# CONFIG_ADF4350 is not set
++
++#
++# Digital gyroscope sensors
++#
++# CONFIG_ADIS16080 is not set
++# CONFIG_ADIS16136 is not set
++# CONFIG_ADXRS450 is not set
++# CONFIG_IIO_ST_GYRO_3AXIS is not set
++# CONFIG_ITG3200 is not set
++
++#
++# Inertial measurement units
++#
++# CONFIG_ADIS16400 is not set
++# CONFIG_ADIS16480 is not set
++# CONFIG_INV_MPU6050_IIO is not set
++
++#
++# Light sensors
++#
++# CONFIG_ADJD_S311 is not set
++# CONFIG_SENSORS_TSL2563 is not set
++# CONFIG_VCNL4000 is not set
++
++#
++# Magnetometer sensors
++#
++# CONFIG_AK8975 is not set
++# CONFIG_IIO_ST_MAGN_3AXIS is not set
++# CONFIG_VME_BUS is not set
++# CONFIG_PWM is not set
++# CONFIG_IPACK_BUS is not set
++# CONFIG_RESET_CONTROLLER is not set
++
++#
++# Firmware Drivers
++#
++# CONFIG_EDD is not set
++CONFIG_FIRMWARE_MEMMAP=y
++# CONFIG_DELL_RBU is not set
++# CONFIG_DCDBAS is not set
++CONFIG_DMIID=y
++# CONFIG_DMI_SYSFS is not set
++# CONFIG_ISCSI_IBFT_FIND is not set
++# CONFIG_GOOGLE_FIRMWARE is not set
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++CONFIG_EXT2_FS=y
++# CONFIG_EXT2_FS_XATTR is not set
++# CONFIG_EXT2_FS_XIP is not set
++CONFIG_EXT3_FS=y
++# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
++CONFIG_EXT3_FS_XATTR=y
++CONFIG_EXT3_FS_POSIX_ACL=y
++CONFIG_EXT3_FS_SECURITY=y
++CONFIG_EXT4_FS=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++CONFIG_EXT4_FS_SECURITY=y
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY_USER=y
++CONFIG_FANOTIFY=y
++# CONFIG_FANOTIFY_ACCESS_PERMISSIONS is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++# CONFIG_AUTOFS4_FS is not set
++CONFIG_FUSE_FS=y
++# CONFIG_CUSE is not set
++CONFIG_GENERIC_ACL=y
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++# CONFIG_VFAT_FS_NO_DUALNAMES is not set
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_VFAT_NO_CREATE_WITH_LONGNAMES is not set
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++# CONFIG_PROC_KCORE is not set
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++CONFIG_TMPFS_POSIX_ACL=y
++CONFIG_TMPFS_XATTR=y
++# CONFIG_HUGETLBFS is not set
++# CONFIG_HUGETLB_PAGE is not set
++CONFIG_CONFIGFS_FS=y
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_ECRYPT_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_LOGFS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_SQUASHFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX6FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_PSTORE=y
++CONFIG_PSTORE_CONSOLE=y
++CONFIG_PSTORE_FTRACE=y
++CONFIG_PSTORE_RAM=y
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_F2FS_FS is not set
++# CONFIG_AUFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_DEF_FILE_IO_SIZE=4096
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++CONFIG_NFS_V4=y
++# CONFIG_NFS_SWAP is not set
++# CONFIG_NFS_V4_1 is not set
++# CONFIG_NFS_USE_LEGACY_DNS is not set
++CONFIG_NFS_USE_KERNEL_DNS=y
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++CONFIG_SUNRPC_GSS=y
++# CONFIG_SUNRPC_DEBUG is not set
++# CONFIG_CEPH_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="utf8"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++CONFIG_NLS_ASCII=y
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_MAC_ROMAN is not set
++# CONFIG_NLS_MAC_CELTIC is not set
++# CONFIG_NLS_MAC_CENTEURO is not set
++# CONFIG_NLS_MAC_CROATIAN is not set
++# CONFIG_NLS_MAC_CYRILLIC is not set
++# CONFIG_NLS_MAC_GAELIC is not set
++# CONFIG_NLS_MAC_GREEK is not set
++# CONFIG_NLS_MAC_ICELAND is not set
++# CONFIG_NLS_MAC_INUIT is not set
++# CONFIG_NLS_MAC_ROMANIAN is not set
++# CONFIG_NLS_MAC_TURKISH is not set
++CONFIG_NLS_UTF8=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_PRINTK_TIME=y
++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=2048
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_SECTION_MISMATCH=y
++CONFIG_DEBUG_KERNEL=y
++CONFIG_DEBUG_SHIRQ=y
++CONFIG_LOCKUP_DETECTOR=y
++CONFIG_HARDLOCKUP_DETECTOR=y
++CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y
++CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=1
++CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
++CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=1
++# CONFIG_PANIC_ON_OOPS is not set
++CONFIG_PANIC_ON_OOPS_VALUE=0
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
++# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
++CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
++CONFIG_SCHED_DEBUG=y
++CONFIG_SCHEDSTATS=y
++CONFIG_TIMER_STATS=y
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_SLUB_DEBUG_ON is not set
++# CONFIG_SLUB_STATS is not set
++CONFIG_HAVE_DEBUG_KMEMLEAK=y
++CONFIG_DEBUG_KMEMLEAK=y
++CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=400
++# CONFIG_DEBUG_KMEMLEAK_TEST is not set
++CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
++CONFIG_DEBUG_PREEMPT=y
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++CONFIG_DEBUG_SPINLOCK=y
++CONFIG_DEBUG_MUTEXES=y
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++CONFIG_TRACE_IRQFLAGS=y
++CONFIG_DEBUG_ATOMIC_SLEEP=y
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++CONFIG_STACKTRACE=y
++CONFIG_DEBUG_STACK_USAGE=y
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_HIGHMEM is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_INFO_REDUCED is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_VIRTUAL is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++CONFIG_DEBUG_LIST=y
++CONFIG_TEST_LIST_SORT=y
++CONFIG_DEBUG_SG=y
++CONFIG_DEBUG_NOTIFIERS=y
++# CONFIG_DEBUG_CREDENTIALS is not set
++CONFIG_ARCH_WANT_FRAME_POINTERS=y
++CONFIG_FRAME_POINTER=y
++CONFIG_BOOT_PRINTK_DELAY=y
++
++#
++# RCU Debugging
++#
++# CONFIG_PROVE_RCU_DELAY is not set
++CONFIG_SPARSE_RCU_POINTER=y
++# CONFIG_RCU_TORTURE_TEST is not set
++CONFIG_RCU_CPU_STALL_TIMEOUT=60
++CONFIG_RCU_CPU_STALL_VERBOSE=y
++CONFIG_RCU_CPU_STALL_INFO=y
++# CONFIG_RCU_TRACE is not set
++# CONFIG_KPROBES_SANITY_TEST is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_DEBUG_PER_CPU_MAPS is not set
++# CONFIG_LKDTM is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP is not set
++CONFIG_ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS=y
++# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set
++# CONFIG_DEBUG_PAGEALLOC is not set
++CONFIG_USER_STACKTRACE_SUPPORT=y
++CONFIG_NOP_TRACER=y
++CONFIG_HAVE_FUNCTION_TRACER=y
++CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
++CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST=y
++CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
++CONFIG_HAVE_DYNAMIC_FTRACE=y
++CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
++CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
++CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
++CONFIG_HAVE_C_RECORDMCOUNT=y
++CONFIG_TRACER_MAX_TRACE=y
++CONFIG_TRACE_CLOCK=y
++CONFIG_RING_BUFFER=y
++CONFIG_EVENT_TRACING=y
++CONFIG_CONTEXT_SWITCH_TRACER=y
++CONFIG_RING_BUFFER_ALLOW_SWAP=y
++CONFIG_TRACING=y
++CONFIG_GENERIC_TRACER=y
++CONFIG_TRACING_SUPPORT=y
++CONFIG_FTRACE=y
++CONFIG_FUNCTION_TRACER=y
++CONFIG_FUNCTION_GRAPH_TRACER=y
++CONFIG_IRQSOFF_TRACER=y
++CONFIG_PREEMPT_TRACER=y
++CONFIG_SCHED_TRACER=y
++CONFIG_FTRACE_SYSCALLS=y
++CONFIG_TRACER_SNAPSHOT=y
++CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP=y
++CONFIG_BRANCH_PROFILE_NONE=y
++# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
++# CONFIG_PROFILE_ALL_BRANCHES is not set
++# CONFIG_STACK_TRACER is not set
++CONFIG_BLK_DEV_IO_TRACE=y
++# CONFIG_KPROBE_EVENT is not set
++# CONFIG_UPROBE_EVENT is not set
++# CONFIG_PROBE_EVENTS is not set
++CONFIG_DYNAMIC_FTRACE=y
++CONFIG_DYNAMIC_FTRACE_WITH_REGS=y
++CONFIG_FUNCTION_PROFILER=y
++CONFIG_FTRACE_MCOUNT_RECORD=y
++# CONFIG_FTRACE_STARTUP_TEST is not set
++# CONFIG_MMIOTRACE is not set
++# CONFIG_RING_BUFFER_BENCHMARK is not set
++# CONFIG_RING_BUFFER_STARTUP_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
++CONFIG_DYNAMIC_DEBUG=y
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++CONFIG_HAVE_ARCH_KMEMCHECK=y
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_STRICT_DEVMEM is not set
++CONFIG_X86_VERBOSE_BOOTUP=y
++CONFIG_EARLY_PRINTK=y
++CONFIG_EARLY_PRINTK_INTEL_MID=y
++# CONFIG_EARLY_PRINTK_DBGP is not set
++CONFIG_DEBUG_STACKOVERFLOW=y
++# CONFIG_X86_PTDUMP is not set
++CONFIG_DEBUG_RODATA=y
++# CONFIG_DEBUG_RODATA_TEST is not set
++CONFIG_DEBUG_SET_MODULE_RONX=y
++CONFIG_DEBUG_NX_TEST=m
++CONFIG_DOUBLEFAULT=y
++# CONFIG_DEBUG_TLBFLUSH is not set
++# CONFIG_IOMMU_STRESS is not set
++CONFIG_HAVE_MMIOTRACE_SUPPORT=y
++# CONFIG_X86_DECODER_SELFTEST is not set
++CONFIG_IO_DELAY_TYPE_0X80=0
++CONFIG_IO_DELAY_TYPE_0XED=1
++CONFIG_IO_DELAY_TYPE_UDELAY=2
++CONFIG_IO_DELAY_TYPE_NONE=3
++CONFIG_IO_DELAY_0X80=y
++# CONFIG_IO_DELAY_0XED is not set
++# CONFIG_IO_DELAY_UDELAY is not set
++# CONFIG_IO_DELAY_NONE is not set
++CONFIG_DEFAULT_IO_DELAY_TYPE=0
++CONFIG_DEBUG_BOOT_PARAMS=y
++# CONFIG_CPA_DEBUG is not set
++CONFIG_OPTIMIZE_INLINING=y
++# CONFIG_DEBUG_NMI_SELFTEST is not set
++
++#
++# Security options
++#
++CONFIG_KEYS=y
++# CONFIG_ENCRYPTED_KEYS is not set
++CONFIG_KEYS_DEBUG_PROC_KEYS=y
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++CONFIG_SECURITY=y
++# CONFIG_SECURITYFS is not set
++CONFIG_SECURITY_NETWORK=y
++# CONFIG_SECURITY_NETWORK_XFRM is not set
++# CONFIG_SECURITY_PATH is not set
++CONFIG_LSM_MMAP_MIN_ADDR=65536
++CONFIG_SECURITY_SELINUX=y
++CONFIG_SECURITY_SELINUX_BOOTPARAM=y
++CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=1
++CONFIG_SECURITY_SELINUX_DISABLE=y
++CONFIG_SECURITY_SELINUX_DEVELOP=y
++CONFIG_SECURITY_SELINUX_AVC_STATS=y
++CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
++# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set
++# CONFIG_SECURITY_SMACK is not set
++# CONFIG_SECURITY_TOMOYO is not set
++# CONFIG_SECURITY_APPARMOR is not set
++# CONFIG_SECURITY_YAMA is not set
++# CONFIG_IMA is not set
++# CONFIG_EVM is not set
++CONFIG_DEFAULT_SECURITY_SELINUX=y
++# CONFIG_DEFAULT_SECURITY_DAC is not set
++CONFIG_DEFAULT_SECURITY="selinux"
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++# CONFIG_CRYPTODEV is not set
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_PCOMP2=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_USER is not set
++CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
++CONFIG_CRYPTO_GF128MUL=y
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_PCRYPT is not set
++CONFIG_CRYPTO_WORKQUEUE=y
++CONFIG_CRYPTO_CRYPTD=y
++CONFIG_CRYPTO_AUTHENC=y
++# CONFIG_CRYPTO_TEST is not set
++CONFIG_CRYPTO_ABLK_HELPER_X86=y
++
++#
++# Authenticated Encryption with Associated Data
++#
++CONFIG_CRYPTO_CCM=y
++# CONFIG_CRYPTO_GCM is not set
++CONFIG_CRYPTO_SEQIV=y
++
++#
++# Block modes
++#
++CONFIG_CRYPTO_CBC=y
++CONFIG_CRYPTO_CTR=y
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=y
++CONFIG_CRYPTO_LRW=y
++# CONFIG_CRYPTO_PCBC is not set
++CONFIG_CRYPTO_XTS=y
++
++#
++# Hash modes
++#
++# CONFIG_CRYPTO_CMAC is not set
++CONFIG_CRYPTO_HMAC=y
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32C_INTEL is not set
++# CONFIG_CRYPTO_CRC32 is not set
++# CONFIG_CRYPTO_CRC32_PCLMUL is not set
++# CONFIG_CRYPTO_GHASH is not set
++# CONFIG_CRYPTO_MD4 is not set
++CONFIG_CRYPTO_MD5=y
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++CONFIG_CRYPTO_SHA1=y
++CONFIG_CRYPTO_SHA256=y
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++CONFIG_CRYPTO_AES=y
++CONFIG_CRYPTO_AES_586=y
++CONFIG_CRYPTO_AES_NI_INTEL=y
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++CONFIG_CRYPTO_DES=y
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SALSA20_586 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_SERPENT_SSE2_586 is not set
++# CONFIG_CRYPTO_TEA is not set
++CONFIG_CRYPTO_TWOFISH=y
++CONFIG_CRYPTO_TWOFISH_COMMON=y
++CONFIG_CRYPTO_TWOFISH_586=y
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_CRYPTO_DEV_PADLOCK is not set
++# CONFIG_CRYPTO_DEV_GEODE is not set
++CONFIG_ASYMMETRIC_KEY_TYPE=y
++CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
++CONFIG_PUBLIC_KEY_ALGO_RSA=y
++CONFIG_X509_CERTIFICATE_PARSER=y
++CONFIG_HAVE_KVM=y
++CONFIG_VIRTUALIZATION=y
++# CONFIG_KVM is not set
++# CONFIG_LGUEST is not set
++CONFIG_BINARY_PRINTF=y
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_FIND_FIRST_BIT=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_CRC_CCITT=y
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC32_SELFTEST is not set
++# CONFIG_CRC32_SLICEBY8 is not set
++# CONFIG_CRC32_SLICEBY4 is not set
++# CONFIG_CRC32_SARWATE is not set
++CONFIG_CRC32_BIT=y
++# CONFIG_CRC7 is not set
++CONFIG_LIBCRC32C=y
++# CONFIG_CRC8 is not set
++CONFIG_AUDIT_GENERIC=y
++CONFIG_ZLIB_INFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_REED_SOLOMON=y
++CONFIG_REED_SOLOMON_ENC8=y
++CONFIG_REED_SOLOMON_DEC8=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_CPU_RMAP=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
++CONFIG_AVERAGE=y
++CONFIG_CLZ_TAB=y
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_MPILIB=y
++CONFIG_OID_REGISTRY=y
+diff --git a/arch/x86/include/asm/apb_timer.h b/arch/x86/include/asm/apb_timer.h
+index 0acbac2..2a67dda 100644
+--- a/arch/x86/include/asm/apb_timer.h
++++ b/arch/x86/include/asm/apb_timer.h
+@@ -44,6 +44,7 @@ extern int sfi_mtimer_num;
+
+ static inline unsigned long apbt_quick_calibrate(void) {return 0; }
+ static inline void apbt_time_init(void) { }
++static inline void apbt_setup_secondary_clock(void) { }
+
+ #endif
+ #endif /* ASM_X86_APBT_H */
+diff --git a/arch/x86/include/asm/bcm_bt_lpm.h b/arch/x86/include/asm/bcm_bt_lpm.h
+new file mode 100644
+index 0000000..d6d0557
+--- /dev/null
++++ b/arch/x86/include/asm/bcm_bt_lpm.h
+@@ -0,0 +1,46 @@
++/*
++ * Copyright (C) 2009 Google, Inc.
++*
++* This software is licensed under the terms of the GNU General Public
++* License version 2, as published by the Free Software Foundation, and
++* may be copied, distributed, and modified under those terms.
++*
++* This program is distributed in the hope that it will be useful,
++* but WITHOUT ANY WARRANTY; without even the implied warranty of
++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++* GNU General Public License for more details.
++*/
++
++#ifndef BCM_BT_LMP_H
++#define BCM_BT_LMP_H
++
++#include <linux/serial_core.h>
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++
++/* Uart driver must call this every time it beings TX, to ensure
++* this driver keeps WAKE asserted during TX. Called with uart
++* spinlock held. */
++extern void bcm_bt_lpm_exit_lpm_locked(struct device *dev,
++ struct hci_dev *hdev);
++
++struct bcm_bt_lpm_platform_data {
++ int gpio_wake; /* CPU -> BCM wakeup gpio */
++ int gpio_host_wake; /* BCM -> CPU wakeup gpio */
++ int int_host_wake; /* BCM -> CPU wakeup irq */
++ int gpio_enable; /* GPIO enable/disable BT/FM */
++
++ int port; /* UART port to use with BT/FM */
++ /*
++ * Callback to request the uart driver to clock off.
++ * Called with uart spinlock held.
++ */
++ void (*uart_disable)(struct device *tty);
++ /*
++ * Callback to request the uart driver to clock on.
++ * Called with uart spinlock held.
++ */
++ void (*uart_enable)(struct device *tty);
++};
++
++#endif
+diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h
+index 0dc7d9e..b8e3120 100644
+--- a/arch/x86/include/asm/fixmap.h
++++ b/arch/x86/include/asm/fixmap.h
+@@ -119,6 +119,7 @@ enum fixed_addresses {
+ FIX_TEXT_POKE0, /* first page is last, because allocation is backward */
+ #ifdef CONFIG_X86_INTEL_MID
+ FIX_LNW_VRTC,
++ FIX_CLOCK_CTL,
+ #endif
+ __end_of_permanent_fixed_addresses,
+
+diff --git a/arch/x86/include/asm/gpio.h b/arch/x86/include/asm/gpio.h
+index b3799d8..131c96d 100644
+--- a/arch/x86/include/asm/gpio.h
++++ b/arch/x86/include/asm/gpio.h
+@@ -1,4 +1,27 @@
++#ifndef _ARCH_X86_GPIO_H
++#define _ARCH_X86_GPIO_H
++
++#if CONFIG_ARCH_HAVE_CUSTOM_GPIO_H
++
++#if CONFIG_ARCH_NR_GPIO > 0
++#define ARCH_NR_GPIOS CONFIG_ARCH_NR_GPIO
++#endif
++
++#include <asm-generic/gpio.h>
++
++/* The trivial gpiolib dispatchers */
++#define gpio_get_value __gpio_get_value
++#define gpio_set_value __gpio_set_value
++#define gpio_cansleep __gpio_cansleep
++#define gpio_to_irq __gpio_to_irq
++
++#else /* ! CONFIG_ARCH_HAVE_CUSTOM_GPIO_H */
++
+ #ifndef __LINUX_GPIO_H
+ #warning Include linux/gpio.h instead of asm/gpio.h
+ #include <linux/gpio.h>
+ #endif
++
++#endif /* ! CONFIG_ARCH_HAVE_CUSTOM_GPIO_H */
++
++#endif /* _ARCH_X86_GPIO_H */
+diff --git a/arch/x86/include/asm/intel-mid.h b/arch/x86/include/asm/intel-mid.h
+new file mode 100644
+index 0000000..c5860b4
+--- /dev/null
++++ b/arch/x86/include/asm/intel-mid.h
+@@ -0,0 +1,248 @@
++/*
++ * intel-mid.h: Intel MID specific setup code
++ *
++ * (C) Copyright 2009 Intel Corporation
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _ASM_X86_INTEL_MID_H
++#define _ASM_X86_INTEL_MID_H
++
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/sfi.h>
++#include <linux/pci.h>
++#include <linux/platform_device.h>
++#include <asm/intel_mid_pcihelpers.h>
++
++#ifdef CONFIG_SFI
++extern int get_gpio_by_name(const char *name);
++extern void install_irq_resource(struct platform_device *pdev, int irq);
++#else
++static inline int get_gpio_by_name(const char *name) { return -ENODEV; }
++/* Dummy function to prevent compilation error in byt */
++static inline void install_irq_resource(struct platform_device *pdev, int irq)
++{};
++#endif
++
++extern int intel_mid_pci_init(void);
++extern void *get_oem0_table(void);
++extern void intel_delayed_device_register(void *dev,
++ void (*delayed_callback)(void *dev_desc));
++extern void intel_scu_device_register(struct platform_device *pdev);
++extern struct devs_id *get_device_id(u8 type, char *name);
++extern int __init sfi_parse_mrtc(struct sfi_table_header *table);
++extern int __init sfi_parse_mtmr(struct sfi_table_header *table);
++extern int sfi_mrtc_num;
++extern struct sfi_rtc_table_entry sfi_mrtc_array[];
++extern void *get_oem0_table(void);
++extern void register_rpmsg_service(char *name, int id, u32 addr);
++extern int sdhci_pci_request_regulators(void);
++
++/* Define soft platform ID to comply with the OEMB table format. But SPID is not supported */
++#define INTEL_PLATFORM_SSN_SIZE 32
++struct soft_platform_id {
++ u16 customer_id; /*Defines the final customer for the product */
++ u16 vendor_id; /* Defines who owns the final product delivery */
++ u16 manufacturer_id; /* Defines who build the hardware. This can be
++ * different for the same product */
++ u16 platform_family_id; /* Defined by vendor and defines the family of
++ * the product with the same root components */
++ u16 product_line_id; /* Defined by vendor and defines the name of the
++ * product. This can be used to differentiate the
++ * feature set for the same product family (low
++ * cost vs full feature). */
++ u16 hardware_id; /* Defined by vendor and defines the physical hardware
++ * component set present on the PCB/FAB */
++ u8 fru[SPID_FRU_SIZE]; /* Field Replaceabl Unit */
++} __packed;
++
++/* OEMB table */
++struct sfi_table_oemb {
++ struct sfi_table_header header;
++ u32 board_id;
++ u32 board_fab;
++ u8 iafw_major_version;
++ u8 iafw_main_version;
++ u8 val_hooks_major_version;
++ u8 val_hooks_minor_version;
++ u8 ia_suppfw_major_version;
++ u8 ia_suppfw_minor_version;
++ u8 scu_runtime_major_version;
++ u8 scu_runtime_minor_version;
++ u8 ifwi_major_version;
++ u8 ifwi_minor_version;
++ struct soft_platform_id spid;
++ u8 ssn[INTEL_PLATFORM_SSN_SIZE];
++} __packed;
++
++/*
++ * Here defines the array of devices platform data that IAFW would export
++ * through SFI "DEVS" table, we use name and type to match the device and
++ * its platform data.
++ */
++struct devs_id {
++ char name[SFI_NAME_LEN + 1];
++ u8 type;
++ u8 delay;
++ void *(*get_platform_data)(void *info);
++ void (*device_handler)(struct sfi_device_table_entry *pentry,
++ struct devs_id *dev);
++ /* Custom handler for devices */
++ u8 trash_itp;/* true if this driver uses pin muxed with XDB connector */
++};
++
++#define SD_NAME_SIZE 16
++/**
++ * struct sd_board_info - template for device creation
++ * @name: Initializes sdio_device.name; identifies the driver.
++ * @bus_num: board-specific identifier for a given SDIO controller.
++ * @board_ref_clock: Initializes sd_device.board_ref_clock;
++ * @platform_data: Initializes sd_device.platform_data; the particular
++ * data stored there is driver-specific.
++ *
++ */
++struct sd_board_info {
++ char name[SD_NAME_SIZE];
++ int bus_num;
++ unsigned short addr;
++ u32 board_ref_clock;
++ void *platform_data;
++};
++
++
++/*
++ * Medfield is the follow-up of Moorestown, it combines two chip solution into
++ * one. Other than that it also added always-on and constant tsc and lapic
++ * timers. Medfield is the platform name, and the chip name is called Penwell
++ * we treat Medfield/Penwell as a variant of Moorestown. Penwell can be
++ * identified via MSRs.
++ */
++enum intel_mid_cpu_type {
++ INTEL_CPU_CHIP_NOTMID = 0,
++ /* 1 was Moorestown */
++ INTEL_MID_CPU_CHIP_PENWELL = 2,
++ INTEL_MID_CPU_CHIP_CLOVERVIEW,
++ INTEL_MID_CPU_CHIP_TANGIER,
++ INTEL_MID_CPU_CHIP_VALLEYVIEW2,
++ INTEL_MID_CPU_CHIP_ANNIEDALE,
++ INTEL_MID_CPU_CHIP_CARBONCANYON,
++};
++
++extern enum intel_mid_cpu_type __intel_mid_cpu_chip;
++
++/**
++ * struct intel_mid_ops - Interface between intel-mid & sub archs
++ * @arch_setup: arch_setup function to re-initialize platform
++ * structures (x86_init, x86_platform_init)
++ *
++ * This structure can be extended if any new interface is required
++ * between intel-mid & its sub arch files.
++ */
++struct intel_mid_ops {
++ void (*arch_setup)(void);
++};
++
++/* Helper API's for INTEL_MID_OPS_INIT */
++#define DECLARE_INTEL_MID_OPS_INIT(cpuname, cpuid)[cpuid] = \
++ get_##cpuname##_ops,
++
++/* Maximum number of CPU ops */
++#define MAX_CPU_OPS(a) (sizeof(a)/sizeof(void *))
++
++/*
++ * For every new cpu addition, a weak get_<cpuname>_ops() function needs be
++ * declared in arch/x86/platform/intel_mid/intel_mid_weak_decls.h.
++ */
++#define INTEL_MID_OPS_INIT {\
++ DECLARE_INTEL_MID_OPS_INIT(penwell, INTEL_MID_CPU_CHIP_PENWELL) \
++ DECLARE_INTEL_MID_OPS_INIT(cloverview, INTEL_MID_CPU_CHIP_CLOVERVIEW) \
++ DECLARE_INTEL_MID_OPS_INIT(tangier, INTEL_MID_CPU_CHIP_TANGIER) \
++};
++
++static inline enum intel_mid_cpu_type intel_mid_identify_cpu(void)
++{
++#ifdef CONFIG_X86_INTEL_MID
++ return __intel_mid_cpu_chip;
++#else
++ return INTEL_CPU_CHIP_NOTMID;
++#endif
++}
++
++enum intel_mid_timer_options {
++ INTEL_MID_TIMER_DEFAULT,
++ INTEL_MID_TIMER_APBT_ONLY,
++ INTEL_MID_TIMER_LAPIC_APBT,
++};
++
++extern enum intel_mid_timer_options intel_mid_timer_options;
++
++/*
++ * Penwell uses spread spectrum clock, so the freq number is not exactly
++ * the same as reported by MSR based on SDM.
++ */
++#define FSB_FREQ_83SKU 83200
++#define FSB_FREQ_100SKU 99840
++#define FSB_FREQ_133SKU 133000
++
++#define FSB_FREQ_167SKU 167000
++#define FSB_FREQ_200SKU 200000
++#define FSB_FREQ_267SKU 267000
++#define FSB_FREQ_333SKU 333000
++#define FSB_FREQ_400SKU 400000
++
++/* Bus Select SoC Fuse value */
++#define BSEL_SOC_FUSE_MASK 0x7
++#define BSEL_SOC_FUSE_001 0x1 /* FSB 133MHz */
++#define BSEL_SOC_FUSE_101 0x5 /* FSB 100MHz */
++#define BSEL_SOC_FUSE_111 0x7 /* FSB 83MHz */
++
++#define SFI_MTMR_MAX_NUM 8
++#define SFI_MRTC_MAX 8
++
++extern struct console early_mrst_console;
++extern void mrst_early_console_init(void);
++
++extern struct console early_mrfld_console;
++extern void mrfld_early_console_init(void);
++
++extern struct console early_hsu_console;
++extern void hsu_early_console_init(const char *);
++
++extern struct console early_pti_console;
++
++extern void intel_scu_devices_create(void);
++extern void intel_scu_devices_destroy(void);
++extern void intel_psh_devices_create(void);
++extern void intel_psh_devices_destroy(void);
++
++/* VRTC timer */
++#define MRST_VRTC_MAP_SZ (1024)
++/*#define MRST_VRTC_PGOFFSET (0xc00) */
++
++extern void intel_mid_rtc_init(void);
++
++enum intel_mid_sim_type {
++ INTEL_MID_CPU_SIMULATION_NONE = 0,
++ INTEL_MID_CPU_SIMULATION_VP,
++ INTEL_MID_CPU_SIMULATION_SLE,
++ INTEL_MID_CPU_SIMULATION_HVP,
++};
++extern enum intel_mid_sim_type __intel_mid_sim_platform;
++static inline enum intel_mid_sim_type intel_mid_identify_sim(void)
++{
++#ifdef CONFIG_X86_INTEL_MID
++ return __intel_mid_sim_platform;
++#else
++ return INTEL_MID_CPU_SIMULATION_NONE;
++#endif
++}
++
++#define INTEL_MID_IRQ_OFFSET 0x100
++
++extern void pstore_ram_reserve_memory(void);
++
++#endif /* _ASM_X86_INTEL_MID_H */
+diff --git a/arch/x86/include/asm/intel_basincove_gpadc.h b/arch/x86/include/asm/intel_basincove_gpadc.h
+new file mode 100644
+index 0000000..d4d1ffa
+--- /dev/null
++++ b/arch/x86/include/asm/intel_basincove_gpadc.h
+@@ -0,0 +1,61 @@
++#ifndef __INTEL_BASINCOVE_GPADC_H__
++#define __INTEL_BASINCOVE_GPADC_H__
++
++#define GPADC_VBAT (1 << 0)
++#define GPADC_BATID (1 << 1)
++#define GPADC_IBAT (1 << 2)
++#define GPADC_PMICTEMP (1 << 3)
++#define GPADC_BATTEMP0 (1 << 4)
++#define GPADC_BATTEMP1 (1 << 5)
++#define GPADC_SYSTEMP0 (1 << 6)
++#define GPADC_SYSTEMP1 (1 << 7)
++#define GPADC_SYSTEMP2 (1 << 8)
++#define GPADC_CH_NUM 9
++
++#define MBATTEMP (1 << 2)
++#define MSYSTEMP (1 << 3)
++#define MBATT (1 << 4)
++#define MVIBATT (1 << 5)
++#define MCCTICK (1 << 7)
++
++#define GPADC_RSL(channel, res) (res->data[ffs(channel)-1])
++
++struct gpadc_regmap_t {
++ char *name;
++ int cntl; /* GPADC Conversion Control Bit indicator */
++ int rslth; /* GPADC Conversion Result Register Addr High */
++ int rsltl; /* GPADC Conversion Result Register Addr Low */
++};
++
++struct gpadc_regs_t {
++ u16 gpadcreq;
++ u16 gpadcreq_irqen;
++ u16 gpadcreq_busy;
++ u16 mirqlvl1;
++ u16 mirqlvl1_adc;
++ u16 adc1cntl;
++ u16 adcirq;
++ u16 madcirq;
++};
++
++struct iio_dev;
++
++struct intel_basincove_gpadc_platform_data {
++ int channel_num;
++ unsigned long intr;
++ u8 intr_mask;
++ struct iio_map *gpadc_iio_maps;
++ struct gpadc_regmap_t *gpadc_regmaps;
++ struct gpadc_regs_t *gpadc_regs;
++ const struct iio_chan_spec *gpadc_channels;
++};
++
++struct gpadc_result {
++ int data[GPADC_CH_NUM];
++};
++
++int iio_basincove_gpadc_sample(struct iio_dev *indio_dev,
++ int ch, struct gpadc_result *res);
++
++int intel_basincove_gpadc_sample(int ch, struct gpadc_result *res);
++#endif
+diff --git a/arch/x86/include/asm/intel_basincove_ocd.h b/arch/x86/include/asm/intel_basincove_ocd.h
+new file mode 100644
+index 0000000..eff495e
+--- /dev/null
++++ b/arch/x86/include/asm/intel_basincove_ocd.h
+@@ -0,0 +1,161 @@
++#ifndef __INTEL_BASINCOVE_OCD_H__
++#define __INTEL_BASINCOVE_OCD_H__
++
++#define DRIVER_NAME "bcove_bcu"
++#define DEVICE_NAME "mrfl_pmic_bcu"
++
++/* Generic bit representaion macros */
++#define B0 (1 << 0)
++#define B1 (1 << 1)
++#define B2 (1 << 2)
++#define B3 (1 << 3)
++#define B4 (1 << 4)
++#define B5 (1 << 5)
++#define B6 (1 << 6)
++#define B7 (1 << 7)
++
++/* 30 seconds delay macro for VWARN1 interrupt Unmask (enable) */
++#define VWARN2_INTR_EN_DELAY (30 * HZ)
++
++/* IRQ registers */
++#define BCUIRQ 0x05
++#define IRQLVL1 0x01
++#define MIRQLVL1 0x0C
++
++/* Status registers */
++#define S_BCUINT 0x3B
++#define S_BCUCTRL 0x49
++
++/* PMIC SRAM address for BCU register */
++#define PMIC_SRAM_BCU_ADDR 0xFFFFF614
++#define IOMAP_LEN 1
++
++#define NUM_VOLT_LEVELS 3
++#define NUM_CURR_LEVELS 2
++
++#define VWARN_EN_MASK B3
++#define ICCMAXVCC_EN_MASK B6
++
++#define MVWARN1_MASK B0
++#define MVWARN2_MASK B1
++#define MVCRIT_MASK B2
++
++#define MVCRIT B2
++#define MVWARN2 B1
++#define MVWARN1 B0
++
++#define ICCMAXVCC_EN (1 << 6)
++#define VWARN_EN (1 << 3)
++#define VCRIT_SHUTDOWN (1 << 4)
++
++#define BCU_ALERT (1 << 3)
++#define VWARN1_IRQ (1 << 0)
++#define VWARN2_IRQ (1 << 1)
++#define VCRIT_IRQ (1 << 2)
++#define GSMPULSE_IRQ (1 << 3)
++#define TXPWRTH_IRQ (1 << 4)
++
++/* Number of configurable thresholds for current and voltage */
++#define NUM_THRESHOLDS 8
++
++/* BCU real time status flags for corresponding input signals */
++#define SVWARN1 (1<<0)
++#define SVWARN2 (1<<1)
++#define SVCRIT (1<<2)
++
++/* S_BCUCTRL register status bits */
++#define S_CAMFLTORCH B3
++#define S_CAMFLDIS B2
++#define S_BCUDISW2 B1
++
++#define S_BCUDISW2_MASK B1
++#define S_CAMFLDIS_MASK B2
++#define S_CAMFLTORCH_MASK B3
++
++/* check whether bit is sticky or not by checking 5th bit */
++#define IS_STICKY(data) (!!(data & 0x10))
++
++/* check whether signal asserted for VW1/VW2/VC */
++#define IS_ASSRT_ON_VW1(data) (!!(data & 0x01))
++#define IS_ASSRT_ON_VW2(data) (!!(data & 0x02))
++#define IS_ASSRT_ON_VC(data) (!!(data & 0x04))
++
++/* Configuration registers that monitor the voltage drop */
++#define VWARN1_CFG 0x3C
++#define VWARN2_CFG 0x3D
++#define VCRIT_CFG 0x3E
++#define ICCMAXVSYS_CFG 0x3F
++#define ICCMAXVCC_CFG 0x40
++#define ICCMAXVNN_CFG 0x41
++
++/* Behaviour registers */
++#define VFLEXSRC_BEH 0x42
++#define VFLEXDIS_BEH 0x43
++#define VIBDIS_BEH 0x44
++#define CAMFLTORCH_BEH 0x45
++#define CAMFLDIS_BEH 0x46
++#define BCUDISW2_BEH 0x47
++#define BCUDISCRIT_BEH 0x48
++
++/*IRQ Mask Register*/
++#define MBCUIRQ 0x10
++
++#define MRFL_SMIP_SRAM_ADDR 0xFFFCE000
++
++/* SMIP offset address from where the BCU related info should be read */
++#define BCU_SMIP_OFFSET 0x3BA
++
++/* No of Bytes we have to read from SMIP from BCU_SMIP_BASE*/
++#define NUM_SMIP_BYTES 14
++
++/* Max length of the register name string */
++#define MAX_REGNAME_LEN 15
++
++/* String to send the uevent along with env info to user space */
++#define EVT_STR "BCUEVT="
++
++/* Macro to get the mode of acess for the BCU registers */
++#define MODE(m) (((m != S_BCUINT) && (m != BCUIRQ) && (m != IRQLVL1)) \
++ ? (S_IRUGO | S_IWUSR) : S_IRUGO)
++
++/* Generic macro to assign the parameters (reg name and address) */
++#define reg_info(x) { .name = #x, .addr = x, .mode = MODE(x) }
++
++/* Generic macro to fill the environmental data for bcu uevent */
++#define get_envp(evt) (EVT_STR#evt)
++
++/*
++* These values are read from SMIP.
++* SMIP contains these entries - default register configurations
++* BCU is programmed to these default values during boot time.
++*/
++
++struct ocd_bcove_config_data {
++ uint8_t vwarn1_cfg;
++ uint8_t vwarn2_cfg;
++ uint8_t vcrit_cfg;
++ uint8_t iccmaxvsys_cfg;
++ uint8_t iccmaxvcc_cfg;
++ uint8_t iccmaxvnn_cfg;
++ uint8_t vflexsrc_beh;
++ uint8_t vflexdis_beh;
++ uint8_t vibdis_beh;
++ uint8_t camfltorch_beh;
++ uint8_t camfldis_beh;
++ uint8_t bcudisw2_beh;
++ uint8_t bcudiscrit_beh;
++ uint8_t mbcuirq;
++} __packed;
++
++struct ocd_platform_data {
++ int (*bcu_config_data) (struct ocd_bcove_config_data *);
++};
++
++struct bcu_reg_info {
++ char name[MAX_REGNAME_LEN]; /* register name */
++ u16 addr; /* offset address */
++ u16 mode; /* permission mode */
++};
++
++#endif
++
+diff --git a/arch/x86/include/asm/intel_mid_gpadc.h b/arch/x86/include/asm/intel_mid_gpadc.h
+new file mode 100644
+index 0000000..ba62f83
+--- /dev/null
++++ b/arch/x86/include/asm/intel_mid_gpadc.h
+@@ -0,0 +1,19 @@
++#ifndef __INTEL_MID_GPADC_H__
++#define __INTEL_MID_GPADC_H__
++
++struct intel_mid_gpadc_platform_data {
++ unsigned long intr;
++};
++
++#define CH_NEED_VREF (1 << 8)
++#define CH_NEED_VCALIB (1 << 9)
++#define CH_NEED_ICALIB (1 << 10)
++
++int intel_mid_gpadc_gsmpulse_sample(int *vol, int *cur);
++int intel_mid_gpadc_sample(void *handle, int sample_count, ...);
++int get_gpadc_sample(void *handle, int sample_count, int *buffer);
++void intel_mid_gpadc_free(void *handle);
++void *intel_mid_gpadc_alloc(int count, ...);
++void *gpadc_alloc_channels(int count, int *channel_info);
++#endif
++
+diff --git a/arch/x86/include/asm/intel_mid_hsu.h b/arch/x86/include/asm/intel_mid_hsu.h
+new file mode 100644
+index 0000000..36b91fc
+--- /dev/null
++++ b/arch/x86/include/asm/intel_mid_hsu.h
+@@ -0,0 +1,69 @@
++#ifndef __INTEL_MID_HSU_H__
++#define __INTEL_MID_HSU_H__
++
++#define hsu_port_func_max 4
++
++enum {
++ hsu_port0,
++ hsu_port1,
++ hsu_port2,
++ hsu_port_share,
++ hsu_port_max,
++ hsu_dma,
++};
++
++enum {
++ bt_port,
++ modem_port,
++ gps_port,
++ debug_port,
++};
++
++enum {
++ hsu_intel,
++ hsu_dw,
++};
++
++struct hsu_port_cfg {
++ int type;
++ int hw_ip;
++ int index;
++ char *name;
++ int idle;
++ int has_alt;
++ int alt;
++ int force_suspend;
++ int preamble;
++ int hw_context_save;
++ int hw_ctrl_cts;
++ struct device *dev;
++ int (*hw_init)(struct device *dev, int port);
++ void(*hw_set_alt)(int port);
++ void(*hw_set_rts)(int port, int value);
++ void(*hw_suspend)(int port, struct device *dev, irq_handler_t wake_isr);
++ void(*hw_suspend_post)(int port);
++ void(*hw_resume)(int port, struct device *dev);
++ unsigned int (*hw_get_clk)(void);
++ void (*wake_peer)(struct device *tty);
++ void (*set_clk)(unsigned int m, unsigned int n,
++ void __iomem *addr);
++ void (*hw_reset)(void __iomem *addr);
++};
++
++
++void intel_mid_hsu_suspend(int port, struct device *dev,
++ irq_handler_t wake_isr);
++void intel_mid_hsu_resume(int port, struct device *dev);
++void intel_mid_hsu_rts(int port, int value);
++void intel_mid_hsu_switch(int port);
++int intel_mid_hsu_init(struct device *dev, int port);
++int intel_mid_hsu_func_to_port(unsigned int func);
++unsigned int intel_mid_hsu_get_clk(void);
++int hsu_register_board_info(void *inf);
++void intel_mid_hsu_suspend_post(int port);
++struct device *intel_mid_hsu_set_wake_peer(int port,
++ void (*wake_peer)(struct device *));
++void intel_mid_hsu_reset(void __iomem *addr);
++void intel_mid_hsu_set_clk(unsigned int m, unsigned int n,
++ void __iomem *addr);
++#endif
+diff --git a/arch/x86/include/asm/intel_mid_pcihelpers.h b/arch/x86/include/asm/intel_mid_pcihelpers.h
+new file mode 100644
+index 0000000..d48026f
+--- /dev/null
++++ b/arch/x86/include/asm/intel_mid_pcihelpers.h
+@@ -0,0 +1,25 @@
++/*
++ * Access to message bus through three registers
++ * in CUNIT(0:0:0) PCI configuration space.
++ * MSGBUS_CTRL_REG(0xD0):
++ * 31:24 = message bus opcode
++ * 23:16 = message bus port
++ * 15:8 = message bus address, low 8 bits.
++ * 7:4 = message bus byte enables
++ * MSGBUS_CTRL_EXT_REG(0xD8):
++ * 31:8 = message bus address, high 24 bits.
++ * MSGBUS_DATA_REG(0xD4):
++ * hold the data for write or read
++ */
++#define PCI_ROOT_MSGBUS_CTRL_REG 0xD0
++#define PCI_ROOT_MSGBUS_DATA_REG 0xD4
++#define PCI_ROOT_MSGBUS_CTRL_EXT_REG 0xD8
++#define PCI_ROOT_MSGBUS_READ 0x10
++#define PCI_ROOT_MSGBUS_WRITE 0x11
++#define PCI_ROOT_MSGBUS_DWORD_ENABLE 0xf0
++
++u32 intel_mid_msgbus_read32_raw(u32 cmd);
++u32 intel_mid_msgbus_read32(u8 port, u32 addr);
++void intel_mid_msgbus_write32_raw(u32 cmd, u32 data);
++void intel_mid_msgbus_write32(u8 port, u32 addr, u32 data);
++u32 intel_mid_soc_stepping(void);
+diff --git a/arch/x86/include/asm/intel_mid_powerbtn.h b/arch/x86/include/asm/intel_mid_powerbtn.h
+new file mode 100644
+index 0000000..a0b4c87
+--- /dev/null
++++ b/arch/x86/include/asm/intel_mid_powerbtn.h
+@@ -0,0 +1,14 @@
++#ifndef __INTEL_MID_POWERBTN_H__
++#define __INTEL_MID_POWERBTN_H__
++
++struct intel_msic_power_btn_platform_data {
++ u32 pbstat;
++ u16 pb_level;
++ u16 irq_lvl1_mask;
++ int (*irq_ack)(struct intel_msic_power_btn_platform_data *);
++};
++
++#define MSIC_PB_LEN 1
++#define MSIC_PWRBTNM (1 << 0)
++
++#endif
+diff --git a/arch/x86/include/asm/intel_mid_pwm.h b/arch/x86/include/asm/intel_mid_pwm.h
+new file mode 100644
+index 0000000..fdd5221
+--- /dev/null
++++ b/arch/x86/include/asm/intel_mid_pwm.h
+@@ -0,0 +1,30 @@
++#ifndef __INTEL_MID_PWM_H__
++#define __INTEL_MID_PWM_H__
++
++#define MAX_DUTYCYCLE_PERCENTAGE 100
++
++enum {
++ PWM_LED = 0,
++ PWM_VIBRATOR,
++ PWM_LCD_BACKLIGHT,
++ PWM_NUM,
++};
++
++struct intel_mid_pwm_device_data {
++ u16 reg_clkdiv0;
++ u16 reg_clkdiv1;
++ u16 reg_dutycyc;
++ u8 val_clkdiv0;
++ u8 val_clkdiv1;
++};
++
++struct intel_mid_pwm_platform_data {
++ int pwm_num;
++ struct intel_mid_pwm_device_data *ddata;
++ u16 reg_clksel;
++ u8 val_clksel;
++};
++
++int intel_mid_pwm(int id, int value);
++#endif
++
+diff --git a/arch/x86/include/asm/intel_mid_remoteproc.h b/arch/x86/include/asm/intel_mid_remoteproc.h
+new file mode 100644
+index 0000000..d65a8139
+--- /dev/null
++++ b/arch/x86/include/asm/intel_mid_remoteproc.h
+@@ -0,0 +1,117 @@
++/*
++ * INTEL MID Remote Processor Head File
++ *
++ * Copyright (C) 2012 Intel, Inc.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++#ifndef _ASM_INTEL_MID_REMOTEPROC_H
++#define _ASM_INTEL_MID_REMOTEPROC_H
++
++#define RP_IPC_COMMAND 0xA0
++#define RP_IPC_SIMPLE_COMMAND 0xA1
++#define RP_IPC_RAW_COMMAND 0xA2
++
++#define RP_PMIC_ACCESS 0xFF
++#define RP_DFU_REQUEST 0xFE
++#define RP_SET_WATCHDOG 0xF8
++#define RP_FLIS_ACCESS 0xF5
++#define RP_GET_FW_REVISION 0xF4
++#define RP_COLD_BOOT 0xF3
++#define RP_COLD_RESET 0xF1
++#define RP_COLD_OFF 0x80
++#define RP_MIP_ACCESS 0xEC
++#define RP_GET_HOBADDR 0xE5
++#define RP_OSC_CLK_CTRL 0xE6
++#define RP_S0IX_COUNTER 0xE8
++#define RP_WRITE_OSNIB 0xE4
++#define RP_FW_UPDATE 0xFE
++#define RP_VRTC 0xFA
++#define RP_PMDB 0xE0
++#define RP_INDIRECT_WRITE 0x05
++
++/*
++ * Assigning some temp ids for following devices
++ * TODO: Need to change it to some meaningful
++ * values.
++ */
++#define RP_PMIC_GPIO 0X02
++#define RP_PMIC_AUDIO 0x03
++#define RP_MSIC_GPIO 0x05
++#define RP_MSIC_AUDIO 0x06
++#define RP_MSIC_OCD 0x07
++#define RP_MSIC_BATTERY 0XEF
++#define RP_MSIC_THERMAL 0x09
++#define RP_MSIC_POWER_BTN 0x10
++#define RP_IPC 0X11
++#define RP_IPC_UTIL 0X12
++#define RP_FW_ACCESS 0X13
++#define RP_UMIP_ACCESS 0x14
++#define RP_OSIP_ACCESS 0x15
++#define RP_MSIC_ADC 0x16
++#define RP_BQ24192 0x17
++#define RP_MSIC_CLV_AUDIO 0x18
++#define RP_PMIC_CCSM 0x19
++#define RP_PMIC_I2C 0x20
++#define RP_MSIC_MRFLD_AUDIO 0x21
++#define RP_MSIC_PWM 0x22
++#define RP_MSIC_KPD_LED 0x23
++#define RP_BCOVE_ADC 0x24
++#define RP_BCOVE_THERMAL 0x25
++#define RP_MRFL_OCD 0x26
++#define RP_FW_LOGGING 0x27
++#define RP_PMIC_CHARGER 0x28
++
++enum rproc_type {
++ RPROC_SCU = 0,
++ RPROC_PSH,
++ RPROC_NUM,
++};
++
++struct rproc_ops;
++struct platform_device;
++struct rpmsg_ns_msg;
++
++struct rpmsg_ns_info {
++ enum rproc_type type;
++ char name[RPMSG_NAME_SIZE];
++ u32 addr;
++ u32 flags;
++ struct list_head node;
++};
++
++struct rpmsg_ns_list {
++ struct list_head list;
++ struct mutex lock;
++};
++
++extern struct rpmsg_ns_info *rpmsg_ns_alloc(const char *name,
++ int id, u32 addr);
++extern void rpmsg_ns_add_to_list(struct rpmsg_ns_info *info,
++ struct rpmsg_ns_list *nslist);
++
++/*
++ * struct intel_mid_rproc_pdata - intel mid remoteproc's platform data
++ * @name: the remoteproc's name
++ * @firmware: name of firmware file to load
++ * @ops: start/stop rproc handlers
++ * @device_enable: handler for enabling a device
++ * @device_shutdown: handler for shutting down a device
++ */
++struct intel_mid_rproc_pdata {
++ const char *name;
++ const char *firmware;
++ const struct rproc_ops *ops;
++ int (*device_enable) (struct platform_device *pdev);
++ int (*device_shutdown) (struct platform_device *pdev);
++ struct rpmsg_ns_list *nslist;
++};
++
++#endif /* _ASM_INTEL_MID_REMOTEPROC_H */
+diff --git a/arch/x86/include/asm/intel_mid_rpmsg.h b/arch/x86/include/asm/intel_mid_rpmsg.h
+new file mode 100644
+index 0000000..6a666a2
+--- /dev/null
++++ b/arch/x86/include/asm/intel_mid_rpmsg.h
+@@ -0,0 +1,77 @@
++#ifndef _INTEL_MID_RPMSG_H_
++#define _INTEL_MID_RPMSG_H_
++
++#include <asm/scu_ipc_rpmsg.h>
++#include <linux/rpmsg.h>
++
++#ifdef ANDROID_BUILD
++#include <linux/wakelock.h>
++#endif
++
++#define RPMSG_TX_TIMEOUT (5 * HZ)
++
++struct rpmsg_instance {
++ struct rpmsg_channel *rpdev;
++ struct mutex instance_lock;
++ struct tx_ipc_msg *tx_msg;
++ struct rx_ipc_msg *rx_msg;
++ struct mutex rx_lock;
++ struct completion reply_arrived;
++ struct rpmsg_endpoint *endpoint;
++};
++
++struct rpmsg_lock {
++ struct mutex lock;
++ int locked_prev; /* locked prev flag */
++ atomic_t pending;
++};
++
++extern int rpmsg_send_command(struct rpmsg_instance *instance, u32 cmd,
++ u32 sub, u8 *in,
++ u32 *out, u32 inlen,
++ u32 outlen);
++
++extern int rpmsg_send_raw_command(struct rpmsg_instance *instance, u32 cmd,
++ u32 sub, u8 *in,
++ u32 *out, u32 inlen,
++ u32 outlen, u32 sptr,
++ u32 dptr);
++
++extern int rpmsg_send_simple_command(struct rpmsg_instance *instance, u32 cmd,
++ u32 sub);
++
++extern int alloc_rpmsg_instance(struct rpmsg_channel *rpdev,
++ struct rpmsg_instance **pInstance);
++
++extern void free_rpmsg_instance(struct rpmsg_channel *rpdev,
++ struct rpmsg_instance **pInstance);
++
++extern void init_rpmsg_instance(struct rpmsg_instance *instance);
++
++extern int rpmsg_send_generic_command(u32 cmd, u32 sub, u8 *in, u32 inlen,
++ u32 *out, u32 outlen);
++
++extern int rpmsg_send_generic_simple_command(u32 cmd, u32 sub);
++
++extern int rpmsg_send_generic_raw_command(u32 cmd, u32 sub,
++ u8 *in, u32 inlen,
++ u32 *out, u32 outlen,
++ u32 dptr, u32 sptr);
++
++struct rpmsg_device_data {
++ char name[RPMSG_NAME_SIZE];
++ struct rpmsg_channel *rpdev;
++ struct rpmsg_instance *rpmsg_instance;
++};
++
++enum rpmsg_ipc_command_type {
++ RPMSG_IPC_COMMAND = 0,
++ RPMSG_IPC_SIMPLE_COMMAND,
++ RPMSG_IPC_RAW_COMMAND,
++ RPMSG_IPC_COMMAND_TYPE_NUM,
++};
++
++extern void rpmsg_global_lock(void);
++extern void rpmsg_global_unlock(void);
++
++#endif
+diff --git a/arch/x86/include/asm/intel_mid_thermal.h b/arch/x86/include/asm/intel_mid_thermal.h
+new file mode 100644
+index 0000000..6a604a1
+--- /dev/null
++++ b/arch/x86/include/asm/intel_mid_thermal.h
+@@ -0,0 +1,77 @@
++#ifndef __INTEL_MID_THERMAL_H__
++#define __INTEL_MID_THERMAL_H__
++
++#include <linux/thermal.h>
++
++#define BPTHERM_NAME "bptherm"
++#define SKIN0_NAME "skin0"
++#define SKIN1_NAME "skin1"
++#define MSIC_DIE_NAME "msicdie"
++#define MSIC_SYS_NAME "sys"
++#define SYSTHERM2 "systherm2"
++/**
++ * struct intel_mid_thermal_sensor - intel_mid_thermal sensor information
++ * @name: name of the sensor
++ * @index: index number of sensor
++ * @slope: slope used for temp calculation
++ * @intercept: intercept used for temp calculation
++ * @adc_channel: adc channel id|flags
++ * @direct: If true then direct conversion is used.
++ * @priv: private sensor data
++ * @temp_correlation: temp correlation function
++ */
++struct intel_mid_thermal_sensor {
++ char name[THERMAL_NAME_LENGTH];
++ int index;
++ long slope;
++ long intercept;
++ int adc_channel;
++ bool direct;
++ void *priv;
++ int (*temp_correlation)(void *info, long temp, long *res);
++};
++
++/**
++ * struct soc_throttle_data - SoC level power limits for thermal throttling
++ * @power_limit: power limit value
++ * @floor_freq: The CPU frequency may not go below this value
++ */
++struct soc_throttle_data {
++ int power_limit;
++ int floor_freq;
++};
++
++/**
++ * struct intel_mid_thermal_platform_data - Platform data for
++ * intel mid thermal driver
++ *
++ * @num_sensors: Maximum number of sensors supported
++ * @sensors: sensor info
++ * @soc_cooling: True or false
++ */
++struct intel_mid_thermal_platform_data {
++ int num_sensors;
++ struct intel_mid_thermal_sensor *sensors;
++ bool soc_cooling;
++};
++
++/**
++ * struct skin1_private_info - skin1 sensor private data
++ *
++ * @dependent: dependency on other sensors
++ 0 - no dependency,
++ > 0 - depends on other sensors
++ * @sensors: dependent sensor address.
++ */
++struct skin1_private_info {
++ int dependent;
++ struct intel_mid_thermal_sensor **sensors;
++};
++
++/* skin0 sensor temperature correlation function*/
++int skin0_temp_correlation(void *info, long temp, long *res);
++/* skin1 sensor temperature correlation function*/
++int skin1_temp_correlation(void *info, long temp, long *res);
++/* bptherm sensor temperature correlation function*/
++int bptherm_temp_correlation(void *info, long temp, long *res);
++#endif
+diff --git a/arch/x86/include/asm/intel_mid_vrtc.h b/arch/x86/include/asm/intel_mid_vrtc.h
+new file mode 100644
+index 0000000..11ababf
+--- /dev/null
++++ b/arch/x86/include/asm/intel_mid_vrtc.h
+@@ -0,0 +1,9 @@
++#ifndef _INTEL_MID_VRTC_H
++#define _INTEL_MID_VRTC_H
++
++extern unsigned char vrtc_cmos_read(unsigned char reg);
++extern void vrtc_cmos_write(unsigned char val, unsigned char reg);
++extern unsigned long vrtc_get_time(void);
++extern int vrtc_set_mmss(unsigned long nowtime);
++
++#endif
+diff --git a/arch/x86/include/asm/intel_mip.h b/arch/x86/include/asm/intel_mip.h
+new file mode 100644
+index 0000000..f05fc05
+--- /dev/null
++++ b/arch/x86/include/asm/intel_mip.h
+@@ -0,0 +1,32 @@
++#ifndef _ASM_X86_INTEL_MIP_H_
++#define _ASM_X86_INTEL_MIP_H_
++
++#include <asm/intel-mid.h>
++
++/* SMIP property related definitions */
++#define SCU_MIP_DEV_NAME "intel_scu_mip"
++#define SMIP_NUM_CONFIG_PROPS 6
++#define SMIP_MAX_PROP_LEN 4
++
++enum platform_prop {
++ USB_COMPLIANCE,
++ CHARGE_TERMINATION,
++ SHUTDOWN_METHODOLOGY,
++ MOS_TRANS_CAPACITY,
++ NFC_RESV_CAPACITY,
++ TEMP_CRIT_SHUTDOWN,
++};
++
++struct smip_platform_prop {
++ unsigned int offset;
++ unsigned int len;
++ bool is_bit_field;
++ unsigned int mask;
++};
++
++struct scu_mip_platform_data {
++ struct smip_platform_prop smip_prop[SMIP_NUM_CONFIG_PROPS];
++};
++
++int get_smip_property_by_name(enum platform_prop);
++#endif
+diff --git a/arch/x86/include/asm/intel_scu_flis.h b/arch/x86/include/asm/intel_scu_flis.h
+new file mode 100644
+index 0000000..7cea735
+--- /dev/null
++++ b/arch/x86/include/asm/intel_scu_flis.h
+@@ -0,0 +1,326 @@
++#ifndef _ASM_X86_INTEL_SCU_FLIS_H_
++#define _ASM_X86_INTEL_SCU_FLIS_H_
++
++enum flis_param_t {
++ PULL,
++ MUX,
++ OPEN_DRAIN,
++};
++
++/* For MERR */
++
++#define PULL_MASK ((7 << 4) | (3 << 8))
++#define MUX_MASK (0xF << 12)
++#define OPEN_DRAIN_MASK BIT(21)
++
++#define PULL_UP (1 << 8)
++#define PULL_DOWN (2 << 8)
++#define R2Kohms (0 << 4)
++#define R20Kohms (1 << 4)
++#define R50Kohms (2 << 4)
++#define R910ohms (3 << 4)
++
++#define UP_2K (PULL_UP | R2Kohms)
++#define UP_20K (PULL_UP | R20Kohms)
++#define UP_50K (PULL_UP | R50Kohms)
++#define UP_910 (PULL_UP | R910ohms)
++#define DOWN_2K (PULL_DOWN | R2Kohms)
++#define DOWN_20K (PULL_DOWN | R20Kohms)
++#define DOWN_50K (PULL_DOWN | R50Kohms)
++#define DOWN_910 (PULL_DOWN | R910ohms)
++
++#define OD_DISABLE (0 << 21)
++#define OD_ENABLE (1 << 21)
++
++#define MUX_EN_INPUT_EN (2 << 12)
++#define INPUT_EN (1 << 12)
++#define MUX_EN_OUTPUT_EN (8 << 12)
++#define OUTPUT_EN (4 << 12)
++
++/* Add prefix "tng_" to avoid name duplication with ctp pins */
++enum tng_pinname_t {
++ tng_usb_ulpi_0_clk = 0,
++ tng_usb_ulpi_0_data_0 = 1,
++ tng_usb_ulpi_0_data_1 = 2,
++ tng_usb_ulpi_0_data_2 = 3,
++ tng_usb_ulpi_0_data_3 = 4,
++ tng_usb_ulpi_0_data_4 = 5,
++ tng_usb_ulpi_0_data_5 = 6,
++ tng_usb_ulpi_0_data_6 = 7,
++ tng_usb_ulpi_0_data_7 = 8,
++ tng_usb_ulpi_0_dir = 9,
++ tng_usb_ulpi_0_nxt = 10,
++ tng_usb_ulpi_0_refclk = 11,
++ tng_usb_ulpi_0_stp = 12,
++ tng_emmc_0_clk = 13,
++ tng_emmc_0_cmd = 14,
++ tng_emmc_0_d_0 = 15,
++ tng_emmc_0_d_1 = 16,
++ tng_emmc_0_d_2 = 17,
++ tng_emmc_0_d_3 = 18,
++ tng_emmc_0_d_4 = 19,
++ tng_emmc_0_d_5 = 20,
++ tng_emmc_0_d_6 = 21,
++ tng_emmc_0_d_7 = 22,
++ tng_emmc_0_rst_b = 23,
++ tng_gp_emmc_1_clk = 24,
++ tng_gp_emmc_1_cmd = 25,
++ tng_gp_emmc_1_d_0 = 26,
++ tng_gp_emmc_1_d_1 = 27,
++ tng_gp_emmc_1_d_2 = 28,
++ tng_gp_emmc_1_d_3 = 29,
++ tng_gp_emmc_1_d_4 = 30,
++ tng_gp_emmc_1_d_5 = 31,
++ tng_gp_emmc_1_d_6 = 32,
++ tng_gp_emmc_1_d_7 = 33,
++ tng_gp_emmc_1_rst_b = 34,
++ tng_gp_28 = 35,
++ tng_gp_29 = 36,
++ tng_gp_sdio_0_cd_b = 37,
++ tng_gp_sdio_0_clk = 38,
++ tng_gp_sdio_0_cmd = 39,
++ tng_gp_sdio_0_dat_0 = 40,
++ tng_gp_sdio_0_dat_1 = 41,
++ tng_gp_sdio_0_dat_2 = 42,
++ tng_gp_sdio_0_dat_3 = 43,
++ tng_gp_sdio_0_lvl_clk_fb = 44,
++ tng_gp_sdio_0_lvl_cmd_dir = 45,
++ tng_gp_sdio_0_lvl_dat_dir = 46,
++ tng_gp_sdio_0_lvl_sel = 47,
++ tng_gp_sdio_0_powerdown_b = 48,
++ tng_gp_sdio_0_wp = 49,
++ tng_gp_sdio_1_clk = 50,
++ tng_gp_sdio_1_cmd = 51,
++ tng_gp_sdio_1_dat_0 = 52,
++ tng_gp_sdio_1_dat_1 = 53,
++ tng_gp_sdio_1_dat_2 = 54,
++ tng_gp_sdio_1_dat_3 = 55,
++ tng_gp_sdio_1_powerdown_b = 56,
++ tng_mhsi_acdata = 57,
++ tng_mhsi_acflag = 58,
++ tng_mhsi_acready = 59,
++ tng_mhsi_acwake = 60,
++ tng_mhsi_cadata = 61,
++ tng_mhsi_caflag = 62,
++ tng_mhsi_caready = 63,
++ tng_mhsi_cawake = 64,
++ tng_gp_mslim_0_bclk = 65,
++ tng_gp_mslim_0_bdat = 66,
++ tng_gp_ssp_0_clk = 67,
++ tng_gp_ssp_0_fs = 68,
++ tng_gp_ssp_0_rxd = 69,
++ tng_gp_ssp_0_txd = 70,
++ tng_gp_ssp_1_clk = 71,
++ tng_gp_ssp_1_fs = 72,
++ tng_gp_ssp_1_rxd = 73,
++ tng_gp_ssp_1_txd = 74,
++ tng_gp_ssp_2_clk = 75,
++ tng_gp_ssp_2_fs = 76,
++ tng_gp_ssp_2_rxd = 77,
++ tng_gp_ssp_2_txd = 78,
++ tng_gp_ssp_3_clk = 79,
++ tng_gp_ssp_3_fs = 80,
++ tng_gp_ssp_3_rxd = 81,
++ tng_gp_ssp_3_txd = 82,
++ tng_gp_ssp_4_clk = 83,
++ tng_gp_ssp_4_fs_0 = 84,
++ tng_gp_ssp_4_fs_1 = 85,
++ tng_gp_ssp_4_fs_2 = 86,
++ tng_gp_ssp_4_fs_3 = 87,
++ tng_gp_ssp_4_rxd = 88,
++ tng_gp_ssp_4_txd = 89,
++ tng_gp_ssp_5_clk = 90,
++ tng_gp_ssp_5_fs_0 = 91,
++ tng_gp_ssp_5_fs_1 = 92,
++ tng_gp_ssp_5_fs_2 = 93,
++ tng_gp_ssp_5_fs_3 = 94,
++ tng_gp_ssp_5_rxd = 95,
++ tng_gp_ssp_5_txd = 96,
++ tng_gp_ssp_6_clk = 97,
++ tng_gp_ssp_6_fs = 98,
++ tng_gp_ssp_6_rxd = 99,
++ tng_gp_ssp_6_txd = 100,
++ tng_gp_i2c_1_scl = 101,
++ tng_gp_i2c_1_sda = 102,
++ tng_gp_i2c_2_scl = 103,
++ tng_gp_i2c_2_sda = 104,
++ tng_gp_i2c_3_scl = 105,
++ tng_gp_i2c_3_sda = 106,
++ tng_gp_i2c_4_scl = 107,
++ tng_gp_i2c_4_sda = 108,
++ tng_gp_i2c_5_scl = 109,
++ tng_gp_i2c_5_sda = 110,
++ tng_gp_i2c_6_scl = 111,
++ tng_gp_i2c_6_sda = 112,
++ tng_gp_i2c_7_scl = 113,
++ tng_gp_i2c_7_sda = 114,
++ tng_gp_uart_0_cts = 115,
++ tng_gp_uart_0_rts = 116,
++ tng_gp_uart_0_rx = 117,
++ tng_gp_uart_0_tx = 118,
++ tng_gp_uart_1_cts = 119,
++ tng_gp_uart_1_rts = 120,
++ tng_gp_uart_1_rx = 121,
++ tng_gp_uart_1_tx = 122,
++ tng_gp_uart_2_cts = 123,
++ tng_gp_uart_2_rts = 124,
++ tng_gp_uart_2_rx = 125,
++ tng_gp_uart_2_tx = 126,
++ tng_gp_13 = 127,
++ tng_gp_14 = 128,
++ tng_gp_15 = 129,
++ tng_gp_16 = 130,
++ tng_gp_17 = 131,
++ tng_gp_18 = 132,
++ tng_gp_19 = 133,
++ tng_gp_20 = 134,
++ tng_gp_21 = 135,
++ tng_gp_22 = 136,
++ tng_gp_23 = 137,
++ tng_gp_24 = 138,
++ tng_gp_25 = 139,
++ tng_gp_fast_int_0 = 140,
++ tng_gp_fast_int_1 = 141,
++ tng_gp_fast_int_2 = 142,
++ tng_gp_fast_int_3 = 143,
++ tng_gp_pwm_0 = 144,
++ tng_gp_pwm_1 = 145,
++ tng_gp_camerasb_0 = 146,
++ tng_gp_camerasb_1 = 147,
++ tng_gp_camerasb_2 = 148,
++ tng_gp_camerasb_3 = 149,
++ tng_gp_camerasb_4 = 150,
++ tng_gp_camerasb_5 = 151,
++ tng_gp_camerasb_6 = 152,
++ tng_gp_camerasb_7 = 153,
++ tng_gp_camerasb_8 = 154,
++ tng_gp_camerasb_9 = 155,
++ tng_gp_camerasb_10 = 156,
++ tng_gp_camerasb_11 = 157,
++ tng_gp_clkph_0 = 158,
++ tng_gp_clkph_1 = 159,
++ tng_gp_clkph_2 = 160,
++ tng_gp_clkph_3 = 161,
++ tng_gp_clkph_4 = 162,
++ tng_gp_clkph_5 = 163,
++ tng_gp_hdmi_hpd = 164,
++ tng_gp_intd_dsi_te1 = 165,
++ tng_gp_intd_dsi_te2 = 166,
++ tng_osc_clk_ctrl_0 = 167,
++ tng_osc_clk_ctrl_1 = 168,
++ tng_osc_clk_out_0 = 169,
++ tng_osc_clk_out_1 = 170,
++ tng_osc_clk_out_2 = 171,
++ tng_osc_clk_out_3 = 172,
++ tng_osc_clk_out_4 = 173,
++ tng_resetout_b = 174,
++ tng_xxpmode = 175,
++ tng_xxprdy = 176,
++ tng_xxpreq_b = 177,
++ tng_gp_26 = 178,
++ tng_gp_27 = 179,
++ tng_i2c_0_scl = 180,
++ tng_i2c_0_sda = 181,
++ tng_ierr_b = 182,
++ tng_jtag_tckc = 183,
++ tng_jtag_tdic = 184,
++ tng_jtag_tdoc = 185,
++ tng_jtag_tmsc = 186,
++ tng_jtag_trst_b = 187,
++ tng_prochot_b = 188,
++ tng_rtc_clk = 189,
++ tng_svid_vclk = 190,
++ tng_svid_vdio = 191,
++ tng_thermtrip_b = 192,
++ tng_standby = 193,
++ tng_gp_kbd_dkin_0 = 194,
++ tng_gp_kbd_dkin_1 = 195,
++ tng_gp_kbd_dkin_2 = 196,
++ tng_gp_kbd_dkin_3 = 197,
++ tng_gp_kbd_mkin_0 = 198,
++ tng_gp_kbd_mkin_1 = 199,
++ tng_gp_kbd_mkin_2 = 200,
++ tng_gp_kbd_mkin_3 = 201,
++ tng_gp_kbd_mkin_4 = 202,
++ tng_gp_kbd_mkin_5 = 203,
++ tng_gp_kbd_mkin_6 = 204,
++ tng_gp_kbd_mkin_7 = 205,
++ tng_gp_kbd_mkout_0 = 206,
++ tng_gp_kbd_mkout_1 = 207,
++ tng_gp_kbd_mkout_2 = 208,
++ tng_gp_kbd_mkout_3 = 209,
++ tng_gp_kbd_mkout_4 = 210,
++ tng_gp_kbd_mkout_5 = 211,
++ tng_gp_kbd_mkout_6 = 212,
++ tng_gp_kbd_mkout_7 = 213,
++ tng_gp_0 = 214,
++ tng_gp_1 = 215,
++ tng_gp_2 = 216,
++ tng_gp_3 = 217,
++ tng_gp_4 = 218,
++ tng_gp_5 = 219,
++ tng_gp_6 = 220,
++ tng_gp_7 = 221,
++ tng_gp_8 = 222,
++ tng_gp_9 = 223,
++ tng_gp_10 = 224,
++ tng_gp_11 = 225,
++ tng_gp_12 = 226,
++ tng_gp_mpti_clk = 227,
++ tng_gp_mpti_data_0 = 228,
++ tng_gp_mpti_data_1 = 229,
++ tng_gp_mpti_data_2 = 230,
++ tng_gp_mpti_data_3 = 231,
++ TNG_PIN_NUM,
++};
++
++struct pinstruct_t {
++ bool valid; /* the pin is allowed to be configured or not */
++ u8 bus_address;
++ u8 pullup_offset;
++ u8 pullup_lsb_pos;
++ u8 direction_offset;
++ u8 direction_lsb_pos;
++ u8 open_drain_offset;
++ u8 open_drain_bit;
++};
++
++enum ACCESS_CTRL {
++ readonly = (1 << 0),
++ writable = (1 << 1),
++};
++
++struct pin_mmio_flis_t {
++ u8 access_ctrl; /* mmio flis access control */
++ u32 offset; /* pin offset from flis base address */
++};
++
++struct intel_scu_flis_platform_data {
++ struct pinstruct_t *pin_t;
++ int pin_num;
++ u32 flis_base;
++ u32 flis_len;
++ struct pin_mmio_flis_t *mmio_flis_t;
++};
++
++#define OPS_STR_LEN 10
++
++enum {
++ DBG_SHIM_FLIS_ADDR,
++ DBG_SHIM_OFFSET,
++ DBG_SHIM_DATA,
++
++ DBG_PARAM_VAL,
++ DBG_PARAM_TYPE,
++ DBG_PIN_NAME,
++};
++
++int intel_scu_ipc_write_shim(u32 data, u32 flis_addr, u32 offset);
++int intel_scu_ipc_read_shim(u32 *data, u32 flis_addr, u32 offset);
++int intel_scu_ipc_update_shim(u32 data, u32 mask, u32 flis_addr, u32 offset);
++int config_pin_flis(unsigned int name, enum flis_param_t param, u32 val);
++int get_pin_flis(unsigned int name, enum flis_param_t param, u32 *val);
++u32 get_flis_value(u32 offset);
++void set_flis_value(u32 value, u32 offset);
++
++#endif
+diff --git a/arch/x86/include/asm/intel_scu_ipc.h b/arch/x86/include/asm/intel_scu_ipc.h
+index 925b605..3536ec9 100644
+--- a/arch/x86/include/asm/intel_scu_ipc.h
++++ b/arch/x86/include/asm/intel_scu_ipc.h
+@@ -2,53 +2,88 @@
+ #define _ASM_X86_INTEL_SCU_IPC_H_
+
+ #include <linux/notifier.h>
++#include <asm/intel-mid.h>
+
++/* IPC defines the following message types */
++#define IPCMSG_GET_HOBADDR 0xE5 /* OSHOB access. */
++#define IPCMSG_BATTERY 0xEF /* Coulomb Counter Accumulator */
++#define IPCMSG_MIP_ACCESS 0xEC /* IA MIP access */
++#define IPCMSG_PMDB_CMD 0xE0
+ #define IPCMSG_WARM_RESET 0xF0
+ #define IPCMSG_COLD_RESET 0xF1
+ #define IPCMSG_SOFT_RESET 0xF2
+ #define IPCMSG_COLD_BOOT 0xF3
+-
++#define IPCMSG_COLD_OFF 0x80 /* for TNG only */
++#define IPCMSG_FW_REVISION 0xF4 /* Get firmware revision */
++#define IPCMSG_SHIM_CONFIG 0xF5 /* Configure SHIM */
++#define IPCMSG_WATCHDOG_TIMER 0xF8 /* Set Kernel Watchdog Threshold */
+ #define IPCMSG_VRTC 0xFA /* Set vRTC device */
+- /* Command id associated with message IPCMSG_VRTC */
+- #define IPC_CMD_VRTC_SETTIME 1 /* Set time */
+- #define IPC_CMD_VRTC_SETALARM 2 /* Set alarm */
+-
+-/* Read single register */
+-int intel_scu_ipc_ioread8(u16 addr, u8 *data);
+-
+-/* Read two sequential registers */
+-int intel_scu_ipc_ioread16(u16 addr, u16 *data);
+-
+-/* Read four sequential registers */
+-int intel_scu_ipc_ioread32(u16 addr, u32 *data);
+-
+-/* Read a vector */
+-int intel_scu_ipc_readv(u16 *addr, u8 *data, int len);
+-
+-/* Write single register */
+-int intel_scu_ipc_iowrite8(u16 addr, u8 data);
++#define IPCMSG_FW_UPDATE 0xFE /* Firmware update */
++#define IPCMSG_PCNTRL 0xFF /* Power controller unit read/write */
++#define IPCMSG_OSC_CLK 0xE6 /* Turn on/off osc clock */
++#define IPCMSG_S0IX_COUNTER 0xEB /* Get S0ix residency */
++#define IPCMSG_CLEAR_FABERROR 0xE3 /* Clear fabric error log */
++#define IPCMSG_STORE_NV_DATA 0xCD /* Store the Non Volatile data to RAM */
++
++#define IPC_CMD_UMIP_RD 0
++#define IPC_CMD_UMIP_WR 1
++#define IPC_CMD_SMIP_RD 2
++
++/* Command id associated with message IPCMSG_PCNTRL */
++#define IPC_CMD_PCNTRL_W 0 /* Register write */
++#define IPC_CMD_PCNTRL_R 1 /* Register read */
++#define IPC_CMD_PCNTRL_M 2 /* Register read-modify-write */
++
++#define IPC_ERR_NONE 0
++#define IPC_ERR_CMD_NOT_SUPPORTED 1
++#define IPC_ERR_CMD_NOT_SERVICED 2
++#define IPC_ERR_UNABLE_TO_SERVICE 3
++#define IPC_ERR_CMD_INVALID 4
++#define IPC_ERR_CMD_FAILED 5
++#define IPC_ERR_EMSECURITY 6
++#define IPC_ERR_UNSIGNEDKERNEL 7
++
++#define MSIC_DEBUG_FILE "msic"
++#define MSIC_ALL_DEBUG_FILE "msic_all"
++#define MAX_MSIC_REG 0x3FF
++#define MIN_MSIC_REG 0x0
++
++
++
++/* Command id associated with message IPCMSG_VRTC */
++#define IPC_CMD_VRTC_SETTIME 1 /* Set time */
++#define IPC_CMD_VRTC_SETALARM 2 /* Set alarm */
++#define IPC_CMD_VRTC_SYNC_RTC 3 /* Sync MSIC/PMIC RTC to VRTC */
++
++/* Command id associated with message IPCMSG_SHIM_CONFIG */
++#define IPC_CMD_SHIM_RD 0 /* SHIM read */
++#define IPC_CMD_SHIM_WR 1 /* SHIM write */
++
++/* check ipc status */
++int intel_scu_ipc_check_status(void);
+
+-/* Write two sequential registers */
+-int intel_scu_ipc_iowrite16(u16 addr, u16 data);
++/* I2C control api */
++int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data);
+
+-/* Write four sequential registers */
+-int intel_scu_ipc_iowrite32(u16 addr, u32 data);
++/* Update FW version */
++int intel_scu_ipc_fw_update(void);
++int intel_scu_ipc_mrstfw_update(u8 *buffer, u32 length);
++int intel_scu_ipc_medfw_prepare(void __user *arg);
+
+-/* Write a vector */
+-int intel_scu_ipc_writev(u16 *addr, u8 *data, int len);
++int intel_scu_ipc_read_mip(u8 *data, int len, int offset, int issigned);
++int intel_scu_ipc_write_umip(u8 *data, int len, int offset);
+
+-/* Update single register based on the mask */
+-int intel_scu_ipc_update_register(u16 addr, u8 data, u8 mask);
++/* NVRAM access */
++u32 intel_scu_ipc_get_nvram_size(void);
++u32 intel_scu_ipc_get_nvram_addr(void);
+
+-/* Issue commands to the SCU with or without data */
+-int intel_scu_ipc_simple_command(int cmd, int sub);
+-int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
+- u32 *out, int outlen);
+-/* I2C control api */
+-int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data);
++/* Penwell has 4 osc clocks */
++#define OSC_CLK_AUDIO 0 /* Audio */
++#define OSC_CLK_CAM0 1 /* Primary camera */
++#define OSC_CLK_CAM1 2 /* Secondary camera */
++#define OSC_CLK_DISP 3 /* Display buffer */
+
+-/* Update FW version */
+-int intel_scu_ipc_fw_update(u8 *buffer, u32 length);
++int intel_scu_ipc_osc_clk(u8 clk, unsigned int khz);
+
+ extern struct blocking_notifier_head intel_scu_notifier;
+
+diff --git a/arch/x86/include/asm/intel_scu_ipcutil.h b/arch/x86/include/asm/intel_scu_ipcutil.h
+new file mode 100644
+index 0000000..0153882
+--- /dev/null
++++ b/arch/x86/include/asm/intel_scu_ipcutil.h
+@@ -0,0 +1,135 @@
++#ifndef _ASM_X86_INTEL_SCU_IPCUTIL_H_
++#define _ASM_X86_INTEL_SCU_IPCUTIL_H_
++
++#include <linux/types.h>
++
++/* ioctl commnds */
++#define INTEL_SCU_IPC_REGISTER_READ 0
++#define INTEL_SCU_IPC_REGISTER_WRITE 1
++#define INTEL_SCU_IPC_REGISTER_UPDATE 2
++#define INTEL_SCU_IPC_FW_UPDATE 0xA2
++#define INTEL_SCU_IPC_MEDFIELD_FW_UPDATE 0xA3
++#define INTEL_SCU_IPC_FW_REVISION_GET 0xB0
++#define INTEL_SCU_IPC_FW_REVISION_EXT_GET 0xB1
++#define INTEL_SCU_IPC_S0IX_RESIDENCY 0xB8
++#define INTEL_SCU_IPC_READ_RR_FROM_OSNIB 0xC1
++#define INTEL_SCU_IPC_WRITE_RR_TO_OSNIB 0xC2
++#define INTEL_SCU_IPC_READ_VBATTCRIT 0xC4
++#define INTEL_SCU_IPC_WRITE_ALARM_FLAG_TO_OSNIB 0xC5
++#define INTEL_SCU_IPC_OSC_CLK_CNTL 0xC6
++#define INTEL_SCU_IPC_PMDB_ACCESS 0xD0
++
++#define SIGNED_MOS_ATTR 0x0
++#define SIGNED_COS_ATTR 0x0A
++#define SIGNED_RECOVERY_ATTR 0x0C
++#define SIGNED_POS_ATTR 0x0E
++#define SIGNED_FACTORY_ATTR 0x12
++
++enum intel_scu_ipc_wake_src {
++ WAKE_BATT_INSERT,
++ WAKE_PWR_BUTTON_PRESS,
++ WAKE_RTC_TIMER,
++ WAKE_USB_CHRG_INSERT,
++ WAKE_RESERVED,
++ WAKE_REAL_RESET,
++ WAKE_COLD_BOOT,
++ WAKE_UNKNOWN,
++ WAKE_KERNEL_WATCHDOG_RESET,
++ WAKE_SECURITY_WATCHDOG_RESET,
++ WAKE_WATCHDOG_COUNTER_EXCEEDED,
++ WAKE_POWER_SUPPLY_DETECTED,
++ WAKE_FASTBOOT_BUTTONS_COMBO,
++ WAKE_NO_MATCHING_OSIP_ENTRY,
++ WAKE_CRITICAL_BATTERY,
++ WAKE_INVALID_CHECKSUM,
++ WAKE_FORCED_RESET,
++ WAKE_ACDC_CHRG_INSERT,
++ WAKE_PMIC_WATCHDOG_RESET,
++ WAKE_PLATFORM_WATCHDOG_RESET,
++ WAKE_SC_WATCHDOG_RESET
++};
++
++struct scu_ipc_data {
++ __u32 count; /* No. of registers */
++ __u16 addr[5]; /* Register addresses */
++ __u8 data[5]; /* Register data */
++ __u8 mask; /* Valid for read-modify-write */
++};
++
++struct scu_ipc_version {
++ __u32 count; /* length of version info */
++ __u8 data[16]; /* version data */
++};
++
++struct osc_clk_t {
++ __u32 id; /* clock id */
++ __u32 khz; /* clock frequency */
++};
++
++/* PMDB buffer, cmd, and limits */
++#define PMDB_SIZE 512
++#define PMDB_WMDB_SIZE 76
++#define PMDB_OTPDB_SIZE 384
++#define PMDB_OTPCTL_SIZE 48
++#define PMDB_ACCESS_SIZE 16
++
++#define PMDB_SUB_CMD_R_WMDB 0
++#define PMDB_SUB_CMD_R_OTPDB 1
++#define PMDB_SUB_CMD_W_WMDB 2
++#define PMDB_SUB_CMD_W_OTPDB 3
++#define PMDB_SUB_CMD_R_OTPCTL 4
++
++struct scu_ipc_pmdb_buffer {
++ __u32 sub; /* sub cmd of SCU's PMDB IPC commands */
++ __u32 count; /* length of PMDB buffer */
++ __u32 offset; /* buffer start offset for each PMDB component */
++ __u8 data[PMDB_SIZE]; /* PMDB buffer */
++};
++
++/* Penwell has 4 osc clocks */
++#define OSC_CLK_AUDIO 0 /* Audio */
++#define OSC_CLK_CAM0 1 /* Primary camera */
++#define OSC_CLK_CAM1 2 /* Secondary camera */
++#define OSC_CLK_DISP 3 /* Display buffer */
++
++#ifdef __KERNEL__
++
++int intel_scu_ipc_osc_clk(u8 clk, unsigned int khz);
++
++enum clk0_mode {
++ CLK0_AUDIENCE = 0x4,
++ CLK0_VIBRA1 = 0x8,
++ CLK0_VIBRA2 = 0x10,
++ CLK0_MSIC = 0x20,
++ CLK0_DEBUG = 0x100,
++ CLK0_QUERY = 0x1000,
++};
++
++int intel_scu_ipc_set_osc_clk0(unsigned int enable, enum clk0_mode mode);
++
++/* Helpers to turn on/off msic vprog1 and vprog2 */
++int intel_scu_ipc_msic_vprog1(int on);
++int intel_scu_ipc_msic_vprog2(int on);
++
++/* OSHOB-OS Handoff Buffer read */
++int intel_scu_ipc_get_oshob_base(void);
++int intel_scu_ipc_get_oshob_size(void);
++
++/* SCU trace buffer interface */
++u32 intel_scu_ipc_get_scu_trace_buffer(void);
++u32 intel_scu_ipc_get_scu_trace_buffer_size(void);
++u32 intel_scu_ipc_get_fabricerror_buf1_offset(void);
++u32 intel_scu_ipc_get_fabricerror_buf2_offset(void);
++
++/* OSNIB interface. */
++int intel_scu_ipc_write_osnib(u8 *data, int len, int offset);
++int intel_scu_ipc_read_osnib(u8 *data, int len, int offset);
++int intel_scu_ipc_write_osnib_extend(u8 *data, int len, int offset);
++int intel_scu_ipc_read_osnib_extend(u8 *data, int len, int offset);
++int intel_scu_ipc_write_osnib_rr(u8 rr);
++int intel_scu_ipc_read_osnib_rr(u8 *rr);
++int intel_scu_ipc_read_osnib_wd(u8 *wd);
++int intel_scu_ipc_write_osnib_wd(u8 *wd);
++#endif
++
++#endif
+diff --git a/arch/x86/include/asm/intel_scu_pmic.h b/arch/x86/include/asm/intel_scu_pmic.h
+new file mode 100644
+index 0000000..308afa6
+--- /dev/null
++++ b/arch/x86/include/asm/intel_scu_pmic.h
+@@ -0,0 +1,16 @@
++#ifndef __INTEL_SCU_PMIC_H__
++#define __INTEL_SCU_PMIC_H__
++
++#include <asm/types.h>
++
++#define KOBJ_PMIC_ATTR(_name, _mode, _show, _store) \
++ struct kobj_attribute _name##_attr = __ATTR(_name, _mode, _show, _store)
++
++extern int intel_scu_ipc_ioread8(u16 addr, u8 *data);
++extern int intel_scu_ipc_ioread32(u16 addr, u32 *data);
++extern int intel_scu_ipc_readv(u16 *addr, u8 *data, int len);
++extern int intel_scu_ipc_iowrite8(u16 addr, u8 data);
++extern int intel_scu_ipc_writev(u16 *addr, u8 *data, int len);
++extern int intel_scu_ipc_update_register(u16 addr, u8 data, u8 mask);
++
++#endif /*__INTEL_SCU_PMIC_H__ */
+diff --git a/arch/x86/include/asm/intel_soc_debug.h b/arch/x86/include/asm/intel_soc_debug.h
+new file mode 100644
+index 0000000..9edb166
+--- /dev/null
++++ b/arch/x86/include/asm/intel_soc_debug.h
+@@ -0,0 +1,43 @@
++/*
++ * intel_soc_debug.h
++ * Copyright (c) 2013, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#ifndef INTEL_SOC_DEBUG_H
++#define INTEL_SOC_DEBUG_H
++
++#define DEBUG_FEATURE_PTI 0x00000001
++#define DEBUG_FEATURE_RTIT 0x00000002
++#define DEBUG_FEATURE_LAKEMORE 0x00000004
++#define DEBUG_FEATURE_SOCHAPS 0x00000008
++#define DEBUG_FEATURE_USB3DFX 0x00000010
++
++/* cpu_has_debug_feature checks whether the debug
++ * feature passed as parameter is enabled.
++ * The passed parameter shall be one (and only one)
++ * of the above values (DEBUG_FEATURE_XXX).
++ * The function returns 1 if the debug feature is
++ * enabled and 0 otherwise.
++ */
++
++#ifdef CONFIG_INTEL_DEBUG_FEATURE
++extern int cpu_has_debug_feature(u32 bit);
++#else
++static inline int cpu_has_debug_feature(u32 bit) { return 0; };
++#endif
++
++#endif
+diff --git a/arch/x86/include/asm/module.h b/arch/x86/include/asm/module.h
+index e3b7819..a11269b 100644
+--- a/arch/x86/include/asm/module.h
++++ b/arch/x86/include/asm/module.h
+@@ -15,7 +15,7 @@
+ #define MODULE_PROC_FAMILY "586MMX "
+ #elif defined CONFIG_MCORE2
+ #define MODULE_PROC_FAMILY "CORE2 "
+-#elif defined CONFIG_MATOM
++#elif (defined CONFIG_MATOM) || (defined CONFIG_MSLM)
+ #define MODULE_PROC_FAMILY "ATOM "
+ #elif defined CONFIG_M686
+ #define MODULE_PROC_FAMILY "686 "
+diff --git a/arch/x86/include/asm/mrst-vrtc.h b/arch/x86/include/asm/mrst-vrtc.h
+deleted file mode 100644
+index 73668ab..0000000
+--- a/arch/x86/include/asm/mrst-vrtc.h
++++ /dev/null
+@@ -1,9 +0,0 @@
+-#ifndef _MRST_VRTC_H
+-#define _MRST_VRTC_H
+-
+-extern unsigned char vrtc_cmos_read(unsigned char reg);
+-extern void vrtc_cmos_write(unsigned char val, unsigned char reg);
+-extern unsigned long vrtc_get_time(void);
+-extern int vrtc_set_mmss(unsigned long nowtime);
+-
+-#endif
+diff --git a/arch/x86/include/asm/mrst.h b/arch/x86/include/asm/mrst.h
+deleted file mode 100644
+index fc18bf3..0000000
+--- a/arch/x86/include/asm/mrst.h
++++ /dev/null
+@@ -1,81 +0,0 @@
+-/*
+- * mrst.h: Intel Moorestown platform specific setup code
+- *
+- * (C) Copyright 2009 Intel Corporation
+- *
+- * 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; version 2
+- * of the License.
+- */
+-#ifndef _ASM_X86_MRST_H
+-#define _ASM_X86_MRST_H
+-
+-#include <linux/sfi.h>
+-
+-extern int pci_mrst_init(void);
+-extern int __init sfi_parse_mrtc(struct sfi_table_header *table);
+-extern int sfi_mrtc_num;
+-extern struct sfi_rtc_table_entry sfi_mrtc_array[];
+-
+-/*
+- * Medfield is the follow-up of Moorestown, it combines two chip solution into
+- * one. Other than that it also added always-on and constant tsc and lapic
+- * timers. Medfield is the platform name, and the chip name is called Penwell
+- * we treat Medfield/Penwell as a variant of Moorestown. Penwell can be
+- * identified via MSRs.
+- */
+-enum mrst_cpu_type {
+- /* 1 was Moorestown */
+- MRST_CPU_CHIP_PENWELL = 2,
+-};
+-
+-extern enum mrst_cpu_type __mrst_cpu_chip;
+-
+-#ifdef CONFIG_X86_INTEL_MID
+-
+-static inline enum mrst_cpu_type mrst_identify_cpu(void)
+-{
+- return __mrst_cpu_chip;
+-}
+-
+-#else /* !CONFIG_X86_INTEL_MID */
+-
+-#define mrst_identify_cpu() (0)
+-
+-#endif /* !CONFIG_X86_INTEL_MID */
+-
+-enum mrst_timer_options {
+- MRST_TIMER_DEFAULT,
+- MRST_TIMER_APBT_ONLY,
+- MRST_TIMER_LAPIC_APBT,
+-};
+-
+-extern enum mrst_timer_options mrst_timer_options;
+-
+-/*
+- * Penwell uses spread spectrum clock, so the freq number is not exactly
+- * the same as reported by MSR based on SDM.
+- */
+-#define PENWELL_FSB_FREQ_83SKU 83200
+-#define PENWELL_FSB_FREQ_100SKU 99840
+-
+-#define SFI_MTMR_MAX_NUM 8
+-#define SFI_MRTC_MAX 8
+-
+-extern struct console early_mrst_console;
+-extern void mrst_early_console_init(void);
+-
+-extern struct console early_hsu_console;
+-extern void hsu_early_console_init(const char *);
+-
+-extern void intel_scu_devices_create(void);
+-extern void intel_scu_devices_destroy(void);
+-
+-/* VRTC timer */
+-#define MRST_VRTC_MAP_SZ (1024)
+-/*#define MRST_VRTC_PGOFFSET (0xc00) */
+-
+-extern void mrst_rtc_init(void);
+-
+-#endif /* _ASM_X86_MRST_H */
+diff --git a/arch/x86/include/asm/mwait.h b/arch/x86/include/asm/mwait.h
+index 2f366d0..2d34917 100644
+--- a/arch/x86/include/asm/mwait.h
++++ b/arch/x86/include/asm/mwait.h
+@@ -13,4 +13,10 @@
+
+ #define MWAIT_ECX_INTERRUPT_BREAK 0x1
+
++#ifdef CONFIG_ATOM_SOC_POWER
++#define MWAIT_MAX_NUM_CSTATES 10
++#else
++#define MWAIT_MAX_NUM_CSTATES 8
++#endif
++
+ #endif /* _ASM_X86_MWAIT_H */
+diff --git a/arch/x86/include/asm/pmic_pdata.h b/arch/x86/include/asm/pmic_pdata.h
+new file mode 100644
+index 0000000..d88c64a
+--- /dev/null
++++ b/arch/x86/include/asm/pmic_pdata.h
+@@ -0,0 +1,45 @@
++#ifndef __PMIC_PDATA_H__
++#define __PMIC_PDATA_H__
++
++struct temp_lookup {
++ int adc_val;
++ int temp;
++ int temp_err;
++};
++
++/*
++ * pmic cove charger driver info
++ */
++struct pmic_platform_data {
++ void (*cc_to_reg)(int, u8*);
++ void (*cv_to_reg)(int, u8*);
++ void (*inlmt_to_reg)(int, u8*);
++ int max_tbl_row_cnt;
++ struct temp_lookup *adc_tbl;
++};
++
++extern int pmic_get_status(void);
++extern int pmic_enable_charging(bool);
++extern int pmic_set_cc(int);
++extern int pmic_set_cv(int);
++extern int pmic_set_ilimma(int);
++extern int pmic_enable_vbus(bool enable);
++/* WA for ShadyCove VBUS removal detect issue */
++extern int pmic_handle_low_supply(void);
++
++extern void dump_pmic_regs(void);
++#ifdef CONFIG_PMIC_CCSM
++extern int pmic_get_health(void);
++extern int pmic_get_battery_pack_temp(int *);
++#else
++static int pmic_get_health(void)
++{
++ return 0;
++}
++static int pmic_get_battery_pack_temp(int *temp)
++{
++ return 0;
++}
++#endif
++
++#endif
+diff --git a/arch/x86/include/asm/required-features.h b/arch/x86/include/asm/required-features.h
+index 5c6e4fb..ee177f7 100644
+--- a/arch/x86/include/asm/required-features.h
++++ b/arch/x86/include/asm/required-features.h
+@@ -47,7 +47,7 @@
+ # define NEED_NOPL 0
+ #endif
+
+-#ifdef CONFIG_MATOM
++#if defined(CONFIG_MATOM) || defined(CONFIG_MSLM)
+ # define NEED_MOVBE (1<<(X86_FEATURE_MOVBE & 31))
+ #else
+ # define NEED_MOVBE 0
+diff --git a/arch/x86/include/asm/scu_ipc_rpmsg.h b/arch/x86/include/asm/scu_ipc_rpmsg.h
+new file mode 100644
+index 0000000..f4aded0
+--- /dev/null
++++ b/arch/x86/include/asm/scu_ipc_rpmsg.h
+@@ -0,0 +1,19 @@
++#ifndef _SCU_IPC_RPMSG_H_
++#define _SCU_IPC_RPMSG_H_
++
++struct tx_ipc_msg {
++ u32 cmd;
++ u32 sub;
++ u8 *in;
++ u32 *out;
++ u32 inlen; /* number of bytes to be written */
++ u32 outlen; /* number of dwords to be read */
++ u32 sptr; /* needed for raw ipc command */
++ u32 dptr; /* needed for raw ipc command */
++};
++
++struct rx_ipc_msg {
++ u32 status; /* Indicate IPC status, 0-success, 1-fail */
++};
++
++#endif
+diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h
+index b7bf350..cafa665 100644
+--- a/arch/x86/include/asm/setup.h
++++ b/arch/x86/include/asm/setup.h
+@@ -49,9 +49,9 @@ extern void i386_reserve_resources(void);
+ extern void setup_default_timer_irq(void);
+
+ #ifdef CONFIG_X86_INTEL_MID
+-extern void x86_mrst_early_setup(void);
++extern void x86_intel_mid_early_setup(void);
+ #else
+-static inline void x86_mrst_early_setup(void) { }
++static inline void x86_intel_mid_early_setup(void) { }
+ #endif
+
+ #ifdef CONFIG_X86_INTEL_CE
+diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
+index c15ddaf..9c3733c 100644
+--- a/arch/x86/include/uapi/asm/bootparam.h
++++ b/arch/x86/include/uapi/asm/bootparam.h
+@@ -158,7 +158,7 @@ enum {
+ X86_SUBARCH_PC = 0,
+ X86_SUBARCH_LGUEST,
+ X86_SUBARCH_XEN,
+- X86_SUBARCH_MRST,
++ X86_SUBARCH_INTEL_MID,
+ X86_SUBARCH_CE4100,
+ X86_NR_SUBARCHS,
+ };
+diff --git a/arch/x86/include/uapi/asm/msr-index.h b/arch/x86/include/uapi/asm/msr-index.h
+index 2af848d..65eb2c4 100644
+--- a/arch/x86/include/uapi/asm/msr-index.h
++++ b/arch/x86/include/uapi/asm/msr-index.h
+@@ -310,6 +310,11 @@
+ #define MSR_AMD_PERF_STATUS 0xc0010063
+ #define MSR_AMD_PERF_CTL 0xc0010062
+
++#define MSR_IA32_POWER_MISC 0x00000120
++
++#define ENABLE_ULFM_AUTOCM (1 << 2)
++#define ENABLE_INDP_AUTOCM (1 << 3)
++
+ #define MSR_IA32_MPERF 0x000000e7
+ #define MSR_IA32_APERF 0x000000e8
+
+diff --git a/arch/x86/kernel/apb_timer.c b/arch/x86/kernel/apb_timer.c
+index c9876ef..af5b08a 100644
+--- a/arch/x86/kernel/apb_timer.c
++++ b/arch/x86/kernel/apb_timer.c
+@@ -40,7 +40,7 @@
+
+ #include <asm/fixmap.h>
+ #include <asm/apb_timer.h>
+-#include <asm/mrst.h>
++#include <asm/intel-mid.h>
+ #include <asm/time.h>
+
+ #define APBT_CLOCKEVENT_RATING 110
+@@ -157,13 +157,13 @@ static int __init apbt_clockevent_register(void)
+
+ adev->num = smp_processor_id();
+ adev->timer = dw_apb_clockevent_init(smp_processor_id(), "apbt0",
+- mrst_timer_options == MRST_TIMER_LAPIC_APBT ?
++ intel_mid_timer_options == INTEL_MID_TIMER_LAPIC_APBT ?
+ APBT_CLOCKEVENT_RATING - 100 : APBT_CLOCKEVENT_RATING,
+ adev_virt_addr(adev), 0, apbt_freq);
+ /* Firmware does EOI handling for us. */
+ adev->timer->eoi = NULL;
+
+- if (mrst_timer_options == MRST_TIMER_LAPIC_APBT) {
++ if (intel_mid_timer_options == INTEL_MID_TIMER_LAPIC_APBT) {
+ global_clock_event = &adev->timer->ced;
+ printk(KERN_DEBUG "%s clockevent registered as global\n",
+ global_clock_event->name);
+@@ -253,7 +253,7 @@ static int apbt_cpuhp_notify(struct notifier_block *n,
+
+ static __init int apbt_late_init(void)
+ {
+- if (mrst_timer_options == MRST_TIMER_LAPIC_APBT ||
++ if (intel_mid_timer_options == INTEL_MID_TIMER_LAPIC_APBT ||
+ !apb_timer_block_enabled)
+ return 0;
+ /* This notifier should be called after workqueue is ready */
+@@ -340,7 +340,7 @@ void __init apbt_time_init(void)
+ }
+ #ifdef CONFIG_SMP
+ /* kernel cmdline disable apb timer, so we will use lapic timers */
+- if (mrst_timer_options == MRST_TIMER_LAPIC_APBT) {
++ if (intel_mid_timer_options == INTEL_MID_TIMER_LAPIC_APBT) {
+ printk(KERN_INFO "apbt: disabled per cpu timer\n");
+ return;
+ }
+diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
+index 904611b..021ae33 100644
+--- a/arch/x86/kernel/apic/apic.c
++++ b/arch/x86/kernel/apic/apic.c
+@@ -54,6 +54,7 @@
+ #include <asm/mce.h>
+ #include <asm/tsc.h>
+ #include <asm/hypervisor.h>
++#include <asm/intel-mid.h>
+
+ unsigned int num_processors;
+
+@@ -700,7 +701,7 @@ static int __init calibrate_APIC_clock(void)
+ lapic_clockevent.mult = div_sc(lapic_timer_frequency/APIC_DIVISOR,
+ TICK_NSEC, lapic_clockevent.shift);
+ lapic_clockevent.max_delta_ns =
+- clockevent_delta2ns(0x7FFFFF, &lapic_clockevent);
++ clockevent_delta2ns(0x7FFFFFFF, &lapic_clockevent);
+ lapic_clockevent.min_delta_ns =
+ clockevent_delta2ns(0xF, &lapic_clockevent);
+ lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
+@@ -2224,6 +2225,19 @@ static int lapic_suspend(void)
+ unsigned long flags;
+ int maxlvt;
+
++ /*
++ * On intel_mid, the suspend flow is a bit different, and the lapic
++ * hw implementation, and integration is not supporting standard
++ * suspension.
++ * This implementation is only putting high value to the timer, so that
++ * AONT global timer will be updated with this big value at s0i3 entry,
++ * and wont produce timer based wake up event.
++ */
++ if (intel_mid_identify_cpu() != 0) {
++ apic_write(APIC_TMICT, ~0);
++ return 0;
++ }
++
+ if (!apic_pm_state.active)
+ return 0;
+
+@@ -2262,6 +2276,15 @@ static void lapic_resume(void)
+ unsigned long flags;
+ int maxlvt;
+
++ /*
++ * On intel_mid, the resume flow is a bit different.
++ * Refer explanation on lapic_suspend.
++ */
++ if (intel_mid_identify_cpu() != 0) {
++ apic_write(APIC_TMICT, 10);
++ return;
++ }
++
+ if (!apic_pm_state.active)
+ return;
+
+diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
+index 9ed796c..d80c6d2 100644
+--- a/arch/x86/kernel/apic/io_apic.c
++++ b/arch/x86/kernel/apic/io_apic.c
+@@ -316,6 +316,24 @@ void io_apic_eoi(unsigned int apic, unsigned int vector)
+ writel(vector, &io_apic->eoi);
+ }
+
++/*
++ * This index matches with 1024 - 4 address in SCU RTE table area.
++ * That is not used for anything. Works in CLVP only
++ */
++#define LAST_INDEX_IN_IO_APIC_SPACE 255
++#define KERNEL_TO_SCU_PANIC_REQUEST (0x0515dead)
++void apic_scu_panic_dump(void)
++{
++ unsigned long flags;
++
++ printk(KERN_ERR "Request SCU panic dump");
++ raw_spin_lock_irqsave(&ioapic_lock, flags);
++ io_apic_write(0, LAST_INDEX_IN_IO_APIC_SPACE,
++ KERNEL_TO_SCU_PANIC_REQUEST);
++ raw_spin_unlock_irqrestore(&ioapic_lock, flags);
++}
++EXPORT_SYMBOL_GPL(apic_scu_panic_dump);
++
+ unsigned int native_io_apic_read(unsigned int apic, unsigned int reg)
+ {
+ struct io_apic __iomem *io_apic = io_apic_base(apic);
+@@ -2355,6 +2373,10 @@ int native_ioapic_set_affinity(struct irq_data *data,
+ return ret;
+ }
+
++static int ioapic_set_wake(struct irq_data *data, unsigned int on)
++{
++ return 0;
++}
+ static void ack_apic_edge(struct irq_data *data)
+ {
+ irq_complete_move(data->chip_data);
+@@ -2519,7 +2541,9 @@ static struct irq_chip ioapic_chip __read_mostly = {
+ .irq_ack = ack_apic_edge,
+ .irq_eoi = ack_apic_level,
+ .irq_set_affinity = native_ioapic_set_affinity,
++ .irq_set_wake = ioapic_set_wake,
+ .irq_retrigger = ioapic_retrigger_irq,
++ .flags = IRQCHIP_SKIP_SET_WAKE,
+ };
+
+ static inline void init_IO_APIC_traps(void)
+diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
+index 22018f7..d70d8a7 100644
+--- a/arch/x86/kernel/cpu/common.c
++++ b/arch/x86/kernel/cpu/common.c
+@@ -1181,15 +1181,17 @@ DEFINE_PER_CPU_ALIGNED(struct stack_canary, stack_canary);
+ */
+ static void clear_all_debug_regs(void)
+ {
+- int i;
++/* int i;
+
+ for (i = 0; i < 8; i++) {
++*/
+ /* Ignore db4, db5 */
+- if ((i == 4) || (i == 5))
++/* if ((i == 4) || (i == 5))
+ continue;
+
+ set_debugreg(0, i);
+ }
++*/
+ }
+
+ #ifdef CONFIG_KGDB
+diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
+index 9b0c441..bd080a4 100644
+--- a/arch/x86/kernel/cpu/intel.c
++++ b/arch/x86/kernel/cpu/intel.c
+@@ -101,6 +101,7 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
+ switch (c->x86_model) {
+ case 0x27: /* Penwell */
+ case 0x35: /* Cloverview */
++ case 0x4A: /* Merrifield */
+ set_cpu_cap(c, X86_FEATURE_NONSTOP_TSC_S3);
+ break;
+ default:
+diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c
+index 47a1870..95db10f 100644
+--- a/arch/x86/kernel/cpu/mcheck/therm_throt.c
++++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c
+@@ -30,8 +30,17 @@
+ #include <asm/mce.h>
+ #include <asm/msr.h>
+
+-/* How long to wait between reporting thermal events */
++/*
++ * How long to wait between reporting thermal events ?
++ * If Interrupt is enabled for Coretemp driver, the BIOS
++ * takes care of hysteresis and thus there are no spurious
++ * interrupts expected. Hence making this interval to 0.
++ */
++#ifdef CONFIG_SENSORS_CORETEMP_INTERRUPT
++#define CHECK_INTERVAL (0)
++#else
+ #define CHECK_INTERVAL (300 * HZ)
++#endif
+
+ #define THERMAL_THROTTLING_EVENT 0
+ #define POWER_LIMIT_EVENT 1
+@@ -177,12 +186,12 @@ static int therm_throt_process(bool new_event, int event, int level)
+ /* if we just entered the thermal event */
+ if (new_event) {
+ if (event == THERMAL_THROTTLING_EVENT)
+- printk(KERN_CRIT "CPU%d: %s temperature above threshold, cpu clock throttled (total events = %lu)\n",
++ pr_crit_ratelimited("CPU%d: %s temperature above threshold, cpu clock throttled (total events = %lu)\n",
+ this_cpu,
+ level == CORE_LEVEL ? "Core" : "Package",
+ state->count);
+ else
+- printk(KERN_CRIT "CPU%d: %s power limit notification (total events = %lu)\n",
++ pr_crit_ratelimited("CPU%d: %s power limit notification (total events = %lu)\n",
+ this_cpu,
+ level == CORE_LEVEL ? "Core" : "Package",
+ state->count);
+@@ -190,11 +199,11 @@ static int therm_throt_process(bool new_event, int event, int level)
+ }
+ if (old_event) {
+ if (event == THERMAL_THROTTLING_EVENT)
+- printk(KERN_INFO "CPU%d: %s temperature/speed normal\n",
++ pr_info_ratelimited("CPU%d: %s temperature/speed normal\n",
+ this_cpu,
+ level == CORE_LEVEL ? "Core" : "Package");
+ else
+- printk(KERN_INFO "CPU%d: %s power limit normal\n",
++ pr_info_ratelimited("CPU%d: %s power limit normal\n",
+ this_cpu,
+ level == CORE_LEVEL ? "Core" : "Package");
+ return 1;
+diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
+index d15f575..3b78cb7 100644
+--- a/arch/x86/kernel/early_printk.c
++++ b/arch/x86/kernel/early_printk.c
+@@ -14,7 +14,7 @@
+ #include <xen/hvc-console.h>
+ #include <asm/pci-direct.h>
+ #include <asm/fixmap.h>
+-#include <asm/mrst.h>
++#include <asm/intel-mid.h>
+ #include <asm/pgtable.h>
+ #include <linux/usb/ehci_def.h>
+
+@@ -228,11 +228,16 @@ static int __init setup_early_printk(char *buf)
+ mrst_early_console_init();
+ early_console_register(&early_mrst_console, keep);
+ }
+-
++ if (!strncmp(buf, "mrfld", 5)) {
++ mrfld_early_console_init();
++ early_console_register(&early_mrfld_console, keep);
++ }
+ if (!strncmp(buf, "hsu", 3)) {
+ hsu_early_console_init(buf + 3);
+ early_console_register(&early_hsu_console, keep);
+ }
++ if (!strncmp(buf, "pti", 3))
++ early_console_register(&early_pti_console, keep);
+ #endif
+ buf++;
+ }
+diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c
+index 138463a..8f344e7 100644
+--- a/arch/x86/kernel/head32.c
++++ b/arch/x86/kernel/head32.c
+@@ -35,8 +35,8 @@ void __init i386_start_kernel(void)
+
+ /* Call the subarch specific early setup function */
+ switch (boot_params.hdr.hardware_subarch) {
+- case X86_SUBARCH_MRST:
+- x86_mrst_early_setup();
++ case X86_SUBARCH_INTEL_MID:
++ x86_intel_mid_early_setup();
+ break;
+ case X86_SUBARCH_CE4100:
+ x86_ce4100_early_setup();
+diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
+index ac0631d..bfa0766 100644
+--- a/arch/x86/kernel/irq.c
++++ b/arch/x86/kernel/irq.c
+@@ -273,7 +273,9 @@ void fixup_irqs(void)
+
+ data = irq_desc_get_irq_data(desc);
+ affinity = data->affinity;
+- if (!irq_has_action(irq) || irqd_is_per_cpu(data) ||
++ /* include IRQs who have no action, but are chained */
++ if ((!irq_has_action(irq) && !irq_is_chained(irq)) ||
++ irqd_is_per_cpu(data) ||
+ cpumask_subset(affinity, cpu_online_mask)) {
+ raw_spin_unlock(&desc->lock);
+ continue;
+diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c
+index 198eb20..bf00e20 100644
+--- a/arch/x86/kernel/rtc.c
++++ b/arch/x86/kernel/rtc.c
+@@ -11,9 +11,10 @@
+
+ #include <asm/vsyscall.h>
+ #include <asm/x86_init.h>
++#include <asm/intel-mid.h>
+ #include <asm/time.h>
+-#include <asm/mrst.h>
+ #include <asm/rtc.h>
++#include <asm/io_apic.h>
+
+ #ifdef CONFIG_X86_32
+ /*
+@@ -149,6 +150,26 @@ void read_persistent_clock(struct timespec *ts)
+ ts->tv_nsec = 0;
+ }
+
++static int handle_mrfl_dev_ioapic(int irq)
++{
++ int ret = 0;
++ int ioapic;
++ struct io_apic_irq_attr irq_attr;
++
++ ioapic = mp_find_ioapic(irq);
++ if (ioapic >= 0) {
++ irq_attr.ioapic = ioapic;
++ irq_attr.ioapic_pin = irq;
++ irq_attr.trigger = 1;
++ irq_attr.polarity = 0; /* Active high */
++ io_apic_set_pci_routing(NULL, irq, &irq_attr);
++ } else {
++ pr_warn("can not find interrupt %d in ioapic\n", irq);
++ ret = -EINVAL;
++ }
++
++ return ret;
++}
+
+ static struct resource rtc_resources[] = {
+ [0] = {
+@@ -172,6 +193,8 @@ static struct platform_device rtc_device = {
+
+ static __init int add_rtc_cmos(void)
+ {
++ int ret;
++
+ #ifdef CONFIG_PNP
+ static const char * const const ids[] __initconst =
+ { "PNP0b00", "PNP0b01", "PNP0b02", };
+@@ -191,10 +214,17 @@ static __init int add_rtc_cmos(void)
+ if (of_have_populated_dt())
+ return 0;
+
+- /* Intel MID platforms don't have ioport rtc */
+- if (mrst_identify_cpu())
++ /* Intel MID platforms don't have ioport rtc
++ * except Tangier platform, which doesn't have vRTC
++ */
++ if (intel_mid_identify_cpu() &&
++ intel_mid_identify_cpu() != INTEL_MID_CPU_CHIP_TANGIER)
+ return -ENODEV;
+
++ ret = handle_mrfl_dev_ioapic(RTC_IRQ);
++ if (ret)
++ return ret;
++
+ platform_device_register(&rtc_device);
+ dev_info(&rtc_device.dev,
+ "registered platform RTC device (no PNP device found)\n");
+diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
+index bfd348e..2192c1c 100644
+--- a/arch/x86/kernel/smpboot.c
++++ b/arch/x86/kernel/smpboot.c
+@@ -1315,21 +1315,25 @@ int native_cpu_disable(void)
+ return 0;
+ }
+
++/*
++ * We let cpus' idle tasks announce their own death to complete
++ * logical cpu unplug sequence.
++ */
++DECLARE_COMPLETION(cpu_die_comp);
++
+ void native_cpu_die(unsigned int cpu)
+ {
+ /* We don't do anything here: idle task is faking death itself. */
+- unsigned int i;
++ unsigned long timeout = HZ; /* 1 sec */
+
+- for (i = 0; i < 10; i++) {
+- /* They ack this in play_dead by setting CPU_DEAD */
+- if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
+- if (system_state == SYSTEM_RUNNING)
+- pr_info("CPU %u is now offline\n", cpu);
+- return;
+- }
+- msleep(100);
+- }
+- pr_err("CPU %u didn't die...\n", cpu);
++ /* They ack this in play_dead by setting CPU_DEAD */
++ wait_for_completion_timeout(&cpu_die_comp, timeout);
++ if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
++ if (system_state == SYSTEM_RUNNING)
++ pr_info("CPU %u is now offline\n", cpu);
++ return;
++ } else
++ pr_err("CPU %u didn't die...\n", cpu);
+ }
+
+ void play_dead_common(void)
+@@ -1341,6 +1345,7 @@ void play_dead_common(void)
+ mb();
+ /* Ack it */
+ __this_cpu_write(cpu_state, CPU_DEAD);
++ complete(&cpu_die_comp);
+
+ /*
+ * With physical CPU hotplug, we should halt the cpu
+@@ -1393,8 +1398,15 @@ static inline void mwait_play_dead(void)
+ highest_subcstate = edx & MWAIT_SUBSTATE_MASK;
+ }
+ }
+- eax = (highest_cstate << MWAIT_SUBSTATE_SIZE) |
+- (highest_subcstate - 1);
++
++ if (highest_cstate < 6) {
++ eax = (highest_cstate << MWAIT_SUBSTATE_SIZE) |
++ (highest_subcstate - 1);
++ } else {
++ /* For s0i3 substate code is 4 */
++ eax = (highest_cstate << MWAIT_SUBSTATE_SIZE) |
++ ((highest_subcstate - 1) * 2);
++ }
+ }
+
+ /*
+@@ -1406,6 +1418,13 @@ static inline void mwait_play_dead(void)
+
+ wbinvd();
+
++ /*
++ * FIXME: SCU will abort S3 entry with ACK C6 timeout
++ * if the lapic timer value programmed is low.
++ * Hence program a high value before offlineing the CPU
++ */
++ apic_write(APIC_TMICT, ~0);
++
+ while (1) {
+ /*
+ * The CLFLUSH is a workaround for erratum AAI65 for
+diff --git a/arch/x86/pci/mrst.c b/arch/x86/pci/mrst.c
+index 6eb18c4..f02406b 100644
+--- a/arch/x86/pci/mrst.c
++++ b/arch/x86/pci/mrst.c
+@@ -31,6 +31,7 @@
+ #include <asm/pci_x86.h>
+ #include <asm/hw_irq.h>
+ #include <asm/io_apic.h>
++#include <asm/intel-mid.h>
+
+ #define PCIE_CAP_OFFSET 0x100
+
+@@ -203,7 +204,7 @@ static int pci_write(struct pci_bus *bus, unsigned int devfn, int where,
+ where, size, value);
+ }
+
+-static int mrst_pci_irq_enable(struct pci_dev *dev)
++static int intel_mid_pci_irq_enable(struct pci_dev *dev)
+ {
+ u8 pin;
+ struct io_apic_irq_attr irq_attr;
+@@ -214,31 +215,36 @@ static int mrst_pci_irq_enable(struct pci_dev *dev)
+ * IOAPIC RTE entries, so we just enable RTE for the device.
+ */
+ irq_attr.ioapic = mp_find_ioapic(dev->irq);
++ if (irq_attr.ioapic < 0)
++ return -1;
+ irq_attr.ioapic_pin = dev->irq;
+ irq_attr.trigger = 1; /* level */
+- irq_attr.polarity = 1; /* active low */
++ if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER)
++ irq_attr.polarity = 0; /* active high */
++ else
++ irq_attr.polarity = 1; /* active low */
+ io_apic_set_pci_routing(&dev->dev, dev->irq, &irq_attr);
+
+ return 0;
+ }
+
+-struct pci_ops pci_mrst_ops = {
++struct pci_ops intel_mid_pci_ops = {
+ .read = pci_read,
+ .write = pci_write,
+ };
+
+ /**
+- * pci_mrst_init - installs pci_mrst_ops
++ * intel_mid_pci_init - installs intel_mid_pci_ops
+ *
+ * Moorestown has an interesting PCI implementation (see above).
+ * Called when the early platform detection installs it.
+ */
+-int __init pci_mrst_init(void)
++int __init intel_mid_pci_init(void)
+ {
+ printk(KERN_INFO "Intel MID platform detected, using MID PCI ops\n");
+ pci_mmcfg_late_init();
+- pcibios_enable_irq = mrst_pci_irq_enable;
+- pci_root_ops = pci_mrst_ops;
++ pcibios_enable_irq = intel_mid_pci_irq_enable;
++ pci_root_ops = intel_mid_pci_ops;
+ pci_soc_mode = 1;
+ /* Continue with standard init */
+ return 1;
+@@ -259,6 +265,7 @@ static void pci_d3delay_fixup(struct pci_dev *dev)
+ if (type1_access_ok(dev->bus->number, dev->devfn, PCI_DEVICE_ID))
+ return;
+ dev->d3_delay = 0;
++ dev->d3cold_delay = 0;
+ }
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_d3delay_fixup);
+
+diff --git a/arch/x86/platform/Makefile b/arch/x86/platform/Makefile
+index 01e0231..20342d4 100644
+--- a/arch/x86/platform/Makefile
++++ b/arch/x86/platform/Makefile
+@@ -4,7 +4,7 @@ obj-y += efi/
+ obj-y += geode/
+ obj-y += goldfish/
+ obj-y += iris/
+-obj-y += mrst/
++obj-y += intel-mid/
+ obj-y += olpc/
+ obj-y += scx200/
+ obj-y += sfi/
+diff --git a/arch/x86/platform/intel-mid/Makefile b/arch/x86/platform/intel-mid/Makefile
+new file mode 100644
+index 0000000..57886ea
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/Makefile
+@@ -0,0 +1,27 @@
++obj-$(CONFIG_X86_INTEL_MID) += intel-mid.o
++obj-$(CONFIG_X86_INTEL_MID) += intel_mid_vrtc.o
++obj-$(CONFIG_EARLY_PRINTK_INTEL_MID) += early_printk_intel_mid.o
++
++# SFI specific code
++obj-$(CONFIG_SFI) += intel_mid_sfi.o
++
++# platform configuration for board devices
++obj-y += device_libs/
++
++# SoC specific files
++obj-$(CONFIG_X86_INTEL_MID) += mfld.o mrfl.o
++obj-$(CONFIG_X86_WANT_INTEL_MID) += intel_mid_pcihelpers.o
++obj-$(CONFIG_X86_INTEL_MID) += intel_mid_scu.o
++
++# BOARD files
++obj-$(CONFIG_X86_INTEL_MID) += board.o
++
++# PMU driver
++obj-$(CONFIG_ATOM_SOC_POWER) += intel_soc_pmu.o intel_soc_pm_debug.o intel_soc_dump.o
++obj-$(CONFIG_REMOVEME_INTEL_ATOM_MDFLD_POWER) += intel_soc_mdfld.o intel_soc_mdfld_clv_common.o
++obj-$(CONFIG_REMOVEME_INTEL_ATOM_CLV_POWER) += intel_soc_clv.o intel_soc_mdfld_clv_common.o
++obj-$(CONFIG_REMOVEME_INTEL_ATOM_MRFLD_POWER) += intel_soc_mrfld.o
++obj-$(CONFIG_REMOVEME_INTEL_ATOM_MRFLD_POWER) += pmu_tng.o
++
++# Debug features driver
++obj-$(CONFIG_INTEL_DEBUG_FEATURE) += intel_soc_debug.o
+diff --git a/arch/x86/platform/intel-mid/board.c b/arch/x86/platform/intel-mid/board.c
+new file mode 100644
+index 0000000..eb9d098
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/board.c
+@@ -0,0 +1,160 @@
++/*
++ * board-blackbay.c: Intel Medfield based board (Blackbay)
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/scatterlist.h>
++#include <linux/sfi.h>
++#include <linux/intel_pmic_gpio.h>
++#include <linux/spi/spi.h>
++#include <linux/i2c.h>
++#include <linux/i2c/pca953x.h>
++#include <linux/gpio.h>
++#include <linux/gpio_keys.h>
++#include <linux/input.h>
++#include <linux/platform_device.h>
++#include <linux/mfd/intel_msic.h>
++#include <linux/irq.h>
++#include <linux/module.h>
++#include <linux/notifier.h>
++#include <linux/i2c-gpio.h>
++
++#include <asm/setup.h>
++#include <asm/mpspec_def.h>
++#include <asm/hw_irq.h>
++#include <asm/apic.h>
++#include <asm/io_apic.h>
++#include <asm/intel-mid.h>
++#include <asm/intel_mid_vrtc.h>
++#include <asm/io.h>
++#include <asm/i8259.h>
++#include <asm/intel_scu_ipc.h>
++#include <asm/apb_timer.h>
++#include <asm/reboot.h>
++
++/*
++ * IPC devices
++ */
++#include "device_libs/platform_ipc.h"
++#include "device_libs/platform_pmic_gpio.h"
++#include "device_libs/platform_msic.h"
++#include "device_libs/platform_msic_battery.h"
++#include "device_libs/platform_msic_gpio.h"
++#include "device_libs/platform_msic_audio.h"
++#include "device_libs/platform_msic_power_btn.h"
++#include "device_libs/platform_msic_ocd.h"
++#include "device_libs/platform_mrfl_pmic.h"
++#include "device_libs/platform_mrfl_pmic_i2c.h"
++#include "device_libs/platform_mrfl_ocd.h"
++#include "device_libs/platform_msic_thermal.h"
++#include "device_libs/platform_soc_thermal.h"
++#include "device_libs/platform_msic_adc.h"
++#include "device_libs/platform_bcove_adc.h"
++#include "device_libs/platform_mrfl_thermal.h"
++
++/*
++ * I2C devices
++ */
++#include "device_libs/platform_max7315.h"
++#include "device_libs/platform_tca6416.h"
++#include "device_libs/platform_mpu3050.h"
++#include "device_libs/platform_emc1403.h"
++#include "device_libs/platform_lis331.h"
++#include "device_libs/platform_mpu3050.h"
++#include "device_libs/platform_tc35876x.h"
++#include "device_libs/platform_bq24261.h"
++#include "device_libs/platform_pcal9555a.h"
++
++/*
++ * SPI devices
++ */
++#include "device_libs/platform_max3111.h"
++#include "device_libs/platform_spidev.h"
++#include "device_libs/platform_ads7955.h"
++
++/* WIFI devices */
++#include "device_libs/platform_wl12xx.h"
++#include "device_libs/platform_wifi.h"
++
++static void __init *no_platform_data(void *info)
++{
++ return NULL;
++}
++
++struct devs_id __initconst device_ids[] = {
++ /* SD devices */
++ {"wl12xx_clk_vmmc", SFI_DEV_TYPE_SD, 0, &wl12xx_platform_data, NULL},
++ {"bcm43xx_clk_vmmc", SFI_DEV_TYPE_SD, 0, &wifi_platform_data, NULL},
++ {"bcm43xx_vmmc", SFI_DEV_TYPE_SD, 0, &wifi_platform_data, NULL},
++ {"iwlwifi_clk_vmmc", SFI_DEV_TYPE_SD, 0, &wifi_platform_data, NULL},
++ {"WLAN_FAST_IRQ", SFI_DEV_TYPE_SD, 0, &no_platform_data,
++ &wifi_platform_data_fastirq},
++
++ /* I2C devices*/
++ {"pcal9555a-1", SFI_DEV_TYPE_I2C, 1, &pcal9555a_platform_data, NULL},
++ {"pcal9555a-2", SFI_DEV_TYPE_I2C, 1, &pcal9555a_platform_data, NULL},
++ {"pcal9555a-3", SFI_DEV_TYPE_I2C, 1, &pcal9555a_platform_data, NULL},
++ {"pcal9555a-4", SFI_DEV_TYPE_I2C, 1, &pcal9555a_platform_data, NULL},
++
++ /* SPI devices */
++ {"spidev", SFI_DEV_TYPE_SPI, 0, &spidev_platform_data, NULL},
++ {"ads7955", SFI_DEV_TYPE_SPI, 0, &ads7955_platform_data, NULL},
++ {"bma023", SFI_DEV_TYPE_I2C, 1, &no_platform_data, NULL},
++ {"pmic_gpio", SFI_DEV_TYPE_SPI, 1, &pmic_gpio_platform_data, NULL},
++ {"pmic_gpio", SFI_DEV_TYPE_IPC, 1, &pmic_gpio_platform_data,
++ &ipc_device_handler},
++ {"spi_max3111", SFI_DEV_TYPE_SPI, 0, &max3111_platform_data, NULL},
++ {"i2c_max7315", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data, NULL},
++ {"i2c_max7315_2", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data, NULL},
++ {"tca6416", SFI_DEV_TYPE_I2C, 1, &tca6416_platform_data, NULL},
++ {"emc1403", SFI_DEV_TYPE_I2C, 1, &emc1403_platform_data, NULL},
++ {"i2c_accel", SFI_DEV_TYPE_I2C, 0, &lis331dl_platform_data, NULL},
++ {"pmic_audio", SFI_DEV_TYPE_IPC, 1, &no_platform_data,
++ &ipc_device_handler},
++ {"mpu3050", SFI_DEV_TYPE_I2C, 1, &mpu3050_platform_data, NULL},
++ {"i2c_disp_brig", SFI_DEV_TYPE_I2C, 0, &tc35876x_platform_data, NULL},
++
++ /* MSIC subdevices */
++ {"msic_adc", SFI_DEV_TYPE_IPC, 1, &msic_adc_platform_data,
++ &ipc_device_handler},
++ {"bcove_power_btn", SFI_DEV_TYPE_IPC, 1, &msic_power_btn_platform_data,
++ &ipc_device_handler},
++ {"msic_battery", SFI_DEV_TYPE_IPC, 1, &msic_battery_platform_data,
++ &ipc_device_handler},
++ {"msic_gpio", SFI_DEV_TYPE_IPC, 1, &msic_gpio_platform_data,
++ &ipc_device_handler},
++ {"msic_audio", SFI_DEV_TYPE_IPC, 1, &msic_audio_platform_data,
++ &ipc_device_handler},
++ {"msic_power_btn", SFI_DEV_TYPE_IPC, 1, &msic_power_btn_platform_data,
++ &ipc_device_handler},
++ {"msic_ocd", SFI_DEV_TYPE_IPC, 1, &msic_ocd_platform_data,
++ &ipc_device_handler},
++ {"bcove_bcu", SFI_DEV_TYPE_IPC, 1, &mrfl_ocd_platform_data,
++ &ipc_device_handler},
++ {"msic_thermal", SFI_DEV_TYPE_IPC, 1, &msic_thermal_platform_data,
++ &ipc_device_handler},
++ {"bcove_adc", SFI_DEV_TYPE_IPC, 1, &bcove_adc_platform_data,
++ &ipc_device_handler},
++ {"bcove_thrm", SFI_DEV_TYPE_IPC, 1, &mrfl_thermal_platform_data,
++ &ipc_device_handler},
++
++ /* IPC devices */
++ {"pmic_charger", SFI_DEV_TYPE_IPC, 1, &no_platform_data, NULL},
++ {"pmic_ccsm", SFI_DEV_TYPE_IPC, 1, &mrfl_pmic_ccsm_platform_data,
++ &ipc_device_handler},
++ {"i2c_pmic_adap", SFI_DEV_TYPE_IPC, 1, &mrfl_pmic_i2c_platform_data,
++ &ipc_device_handler},
++ {"soc_thrm", SFI_DEV_TYPE_IPC, 1, &no_platform_data,
++ &soc_thrm_device_handler},
++ {},
++};
+diff --git a/arch/x86/platform/intel-mid/device_libs/Makefile b/arch/x86/platform/intel-mid/device_libs/Makefile
+new file mode 100644
+index 0000000..750ac8f
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/Makefile
+@@ -0,0 +1,64 @@
++# IPC Devices
++obj-y += platform_mrfl_regulator.o
++obj-y += platform_soc_thermal.o
++obj-$(subst m,y,$(CONFIG_SND_BYT_MACHINE)) += platform_byt_audio.o
++obj-$(subst m,y,$(CONFIG_SND_MRFLD_MACHINE)) += platform_mrfld_audio.o
++obj-$(subst m,y,$(CONFIG_SND_CTP_MACHINE)) += platform_ctp_audio.o
++obj-y += platform_ipc.o
++obj-y += platform_msic.o
++obj-y += platform_msic_audio.o
++obj-y += platform_msic_gpio.o
++obj-y += platform_msic_ocd.o
++obj-y += platform_tc35876x.o
++obj-y += pci/
++obj-$(subst m,y,$(CONFIG_BATTERY_INTEL_MDF)) += platform_msic_battery.o
++obj-$(subst m,y,$(CONFIG_INTEL_MID_POWER_BUTTON)) += platform_msic_power_btn.o
++obj-$(subst m,y,$(CONFIG_GPIO_INTEL_PMIC)) += platform_pmic_gpio.o
++obj-$(subst m,y,$(CONFIG_MID_PWM)) += platform_mid_pwm.o
++obj-$(subst m,y,$(CONFIG_INTEL_MFLD_THERMAL)) += platform_msic_thermal.o
++obj-$(subst m,y,$(CONFIG_SENSORS_MID_VDD)) += platform_msic_vdd.o
++obj-$(subst m,y,$(CONFIG_SENSORS_MRFL_OCD)) += platform_mrfl_ocd.o
++obj-$(subst m,y,$(CONFIG_PMIC_CCSM)) += platform_mrfl_pmic.o
++obj-$(subst m,y,$(CONFIG_I2C_PMIC)) += platform_mrfl_pmic_i2c.o
++ifdef CONFIG_INTEL_BYT_THERMAL
++obj-$(subst m,y,$(CONFIG_INTEL_BYT_THERMAL)) += platform_byt_thermal.o
++else
++obj-$(subst m,y,$(CONFIG_INTEL_BYT_EC_THERMAL)) += platform_byt_thermal.o
++endif
++obj-$(subst m,y,$(CONFIG_SENSORS_THERMAL_MRFLD)) += platform_mrfl_thermal.o
++obj-$(subst m,y,$(CONFIG_INTEL_SCU_FLIS)) += platform_scu_flis.o
++# I2C Devices
++obj-$(subst m,y,$(CONFIG_I2C_DESIGNWARE_CORE_FORK)) += platform_dw_i2c.o
++obj-$(subst m,y,$(CONFIG_SENSORS_EMC1403)) += platform_emc1403.o
++obj-$(subst m,y,$(CONFIG_SENSORS_LIS3LV02D)) += platform_lis331.o
++obj-$(subst m,y,$(CONFIG_GPIO_PCA953X)) += platform_max7315.o
++obj-$(subst m,y,$(CONFIG_SENSORS_MPU3050)) += platform_mpu3050.o
++obj-$(subst m,y,$(CONFIG_GPIO_PCA953X)) += platform_tca6416.o
++obj-$(subst m,y,$(CONFIG_BQ24261_CHARGER)) += platform_bq24261.o
++obj-$(subst m,y,$(CONFIG_GPIO_PCA953X)) += platform_pcal9555a.o
++# SPI Devices
++obj-$(subst m,y,$(CONFIG_SERIAL_MRST_MAX3110)) += platform_max3111.o
++obj-$(subst m,y,$(CONFIG_SPI_SPIDEV)) += platform_spidev.o
++obj-$(subst m,y,$(CONFIG_TI_ADS7955_ADC)) += platform_ads7955.o
++# MISC Devices
++obj-$(subst m,y,$(CONFIG_KEYBOARD_GPIO)) += platform_gpio_keys.o
++# ADC
++obj-$(subst m,y,$(CONFIG_MSIC_GPADC)) += platform_msic_adc.o
++obj-$(subst m,y,$(CONFIG_IIO_BASINCOVE_GPADC)) += platform_bcove_adc.o
++# UART Devices
++obj-$(subst m,y,$(CONFIG_SERIAL_MFD_HSU)) += platform_hsu.o
++# SD Devices
++obj-$(subst m,y,$(CONFIG_WILINK_PLATFORM_DATA)) += platform_wl12xx.o
++ifndef CONFIG_ACPI
++obj-$(subst m,y,$(CONFIG_BCM_BT_LPM)) += platform_btlpm.o
++endif
++#I2C Devices
++# Panel Control Device
++obj-$(subst m,y,$(CONFIG_DRM_MRFLD)) += platform_panel.o
++# GPS
++obj-$(subst m,y,$(CONFIG_INTEL_MID_GPS)) += platform_gps.o
++# WIFI devices
++obj-$(subst m,y,$(CONFIG_WIFI_PLATFORM_DATA)) += platform_wifi.o
++obj-$(subst m,y,$(CONFIG_MMC_SDHCI_ACPI)) += platform_sdio_regulator.o
++# SCU log
++obj-$(subst m,y,$(CONFIG_SCU_LOGGING)) += platform_scu_log.o
+diff --git a/arch/x86/platform/intel-mid/device_libs/pci/Makefile b/arch/x86/platform/intel-mid/device_libs/pci/Makefile
+new file mode 100644
+index 0000000..47c7b78
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/pci/Makefile
+@@ -0,0 +1,6 @@
++# MMC Sdhci pci host controller platform data
++obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += platform_sdhci_pci.o
++# USB OTG controller platform data
++obj-$(subst m,y,$(CONFIG_USB_PENWELL_OTG)) += platform_usb_otg.o
++obj-$(subst m,y,$(CONFIG_USB_DWC3_OTG)) += platform_usb_otg.o
++obj-$(subst m,y,$(CONFIG_SND_INTEL_SST)) += platform_sst_pci.o
+diff --git a/arch/x86/platform/intel-mid/device_libs/pci/platform_sdhci_pci.c b/arch/x86/platform/intel-mid/device_libs/pci/platform_sdhci_pci.c
+new file mode 100644
+index 0000000..3b22e3b
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/pci/platform_sdhci_pci.c
+@@ -0,0 +1,588 @@
++/*
++ * platform_mmc_sdhci_pci.c: mmc sdhci pci platform data initilization file
++ *
++ * (C) Copyright 2012 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <asm/intel-mid.h>
++#include <linux/mmc/sdhci-pci-data.h>
++#include <linux/gpio.h>
++#include <linux/lnw_gpio.h>
++#include <linux/delay.h>
++#include <asm/intel_scu_ipc.h>
++#include <asm/intel_scu_pmic.h>
++#include <linux/intel_mid_pm.h>
++#include <linux/hardirq.h>
++#include <linux/mmc/sdhci.h>
++#include <linux/regulator/machine.h>
++#include <linux/regulator/fixed.h>
++#include <linux/acpi.h>
++#include <linux/acpi_gpio.h>
++
++#include "platform_sdhci_pci.h"
++
++#ifdef CONFIG_ATOM_SOC_POWER
++static int panic_mode_emmc0_power_up(void *data)
++{
++ int ret;
++ bool atomic_context;
++ /*
++ * Since pmu_set_emmc_to_d0i0_atomic function can
++ * only be used in atomic context, before call this
++ * function, do a check first and make sure this function
++ * is used in atomic context.
++ */
++ atomic_context = (!preemptible() || in_atomic_preempt_off());
++
++ if (!atomic_context) {
++ pr_err("%s: not in atomic context!\n", __func__);
++ return -EPERM;
++ }
++
++ ret = pmu_set_emmc_to_d0i0_atomic();
++ if (ret) {
++ pr_err("%s: power up host failed with err %d\n",
++ __func__, ret);
++ }
++
++ return ret;
++}
++#else
++static int panic_mode_emmc0_power_up(void *data)
++{
++ return 0;
++}
++#endif
++
++static unsigned int sdhci_pdata_quirks = SDHCI_QUIRK2_ADVERTISE_2V0_FORCE_1V8
++ | SDHCI_QUIRK2_ENABLE_MMC_PM_IGNORE_PM_NOTIFY;
++
++int sdhci_pdata_set_quirks(const unsigned int quirks)
++{
++ sdhci_pdata_quirks = quirks;
++ return 0;
++}
++
++static int mrfl_flis_check(void *data, unsigned int clk);
++static int mrfl_sdio_setup(struct sdhci_pci_data *data);
++static void mrfl_sdio_cleanup(struct sdhci_pci_data *data);
++
++static void (*sdhci_embedded_control)(void *dev_id, void (*virtual_cd)
++ (void *dev_id, int card_present));
++
++/*****************************************************************************\
++ * *
++ * Regulator declaration for WLAN SDIO card *
++ * *
++\*****************************************************************************/
++
++#define DELAY_ONOFF 250
++
++static struct regulator_consumer_supply wlan_vmmc_supply = {
++ .supply = "vmmc",
++};
++
++static struct regulator_init_data wlan_vmmc_data = {
++ .constraints = {
++ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
++ },
++ .num_consumer_supplies = 1,
++ .consumer_supplies = &wlan_vmmc_supply,
++};
++
++static struct fixed_voltage_config vwlan = {
++ .supply_name = "vwlan",
++ .microvolts = 1800000,
++ .gpio = -EINVAL,
++ .startup_delay = 1000 * DELAY_ONOFF,
++ .enable_high = 1,
++ .enabled_at_boot = 0,
++ .init_data = &wlan_vmmc_data,
++};
++
++static void vwlan_device_release(struct device *dev) {}
++
++static struct platform_device vwlan_device = {
++ .name = "reg-fixed-voltage",
++ .id = PLATFORM_DEVID_AUTO,
++ .dev = {
++ .platform_data = &vwlan,
++ .release = vwlan_device_release,
++ },
++};
++
++
++/* Board specific setup related to SDIO goes here */
++static int mfld_sdio_setup(struct sdhci_pci_data *data)
++{
++ struct pci_dev *pdev = data->pdev;
++ /* Control card power through a regulator */
++ wlan_vmmc_supply.dev_name = dev_name(&pdev->dev);
++ vwlan.gpio = get_gpio_by_name("WLAN-enable");
++ if (vwlan.gpio < 0)
++ pr_err("%s: No WLAN-enable GPIO in SFI table\n",
++ __func__);
++ pr_info("vwlan gpio %d\n", vwlan.gpio);
++ /* add a regulator to control wlan enable gpio */
++ if (platform_device_register(&vwlan_device))
++ pr_err("regulator register failed\n");
++ else
++ sdhci_pci_request_regulators();
++
++ return 0;
++}
++
++
++/* MFLD platform data */
++static struct sdhci_pci_data mfld_sdhci_pci_data[] = {
++ [EMMC0_INDEX] = {
++ .pdev = NULL,
++ .slotno = 0,
++ .rst_n_gpio = -EINVAL,
++ .cd_gpio = -EINVAL,
++ .setup = 0,
++ .cleanup = 0,
++ .power_up = panic_mode_emmc0_power_up,
++ },
++ [EMMC1_INDEX] = {
++ .pdev = NULL,
++ .slotno = 0,
++ .rst_n_gpio = -EINVAL,
++ .cd_gpio = -EINVAL,
++ .setup = 0,
++ .cleanup = 0,
++ },
++ [SD_INDEX] = {
++ .pdev = NULL,
++ .slotno = 0,
++ .rst_n_gpio = -EINVAL,
++ .cd_gpio = 69,
++ .setup = 0,
++ .cleanup = 0,
++ },
++ [SDIO_INDEX] = {
++ .pdev = NULL,
++ .slotno = 0,
++ .rst_n_gpio = -EINVAL,
++ .cd_gpio = -EINVAL,
++ .quirks = 0,
++ .platform_quirks = 0,
++ .setup = mfld_sdio_setup,
++ .cleanup = 0,
++ },
++};
++
++/* Board specific setup related to SDIO goes here */
++static int clv_sdio_setup(struct sdhci_pci_data *data)
++{
++ struct pci_dev *pdev = data->pdev;
++ /* Control card power through a regulator */
++ wlan_vmmc_supply.dev_name = dev_name(&pdev->dev);
++ vwlan.gpio = get_gpio_by_name("WLAN-enable");
++ if (vwlan.gpio < 0)
++ pr_err("%s: No WLAN-enable GPIO in SFI table\n",
++ __func__);
++ pr_info("vwlan gpio %d\n", vwlan.gpio);
++ /* add a regulator to control wlan enable gpio */
++ if (platform_device_register(&vwlan_device))
++ pr_err("regulator register failed\n");
++ else
++ sdhci_pci_request_regulators();
++
++ return 0;
++}
++
++/* CLV platform data */
++static struct sdhci_pci_data clv_sdhci_pci_data[] = {
++ [EMMC0_INDEX] = {
++ .pdev = NULL,
++ .slotno = 0,
++ .rst_n_gpio = -EINVAL,
++ .cd_gpio = -EINVAL,
++ .setup = 0,
++ .cleanup = 0,
++ .power_up = panic_mode_emmc0_power_up,
++ },
++ [EMMC1_INDEX] = {
++ .pdev = NULL,
++ .slotno = 0,
++ .rst_n_gpio = -EINVAL,
++ .cd_gpio = -EINVAL,
++ .setup = 0,
++ .cleanup = 0,
++ },
++ [SD_INDEX] = {
++ .pdev = NULL,
++ .slotno = 0,
++ .rst_n_gpio = -EINVAL,
++ .cd_gpio = 69,
++ .setup = 0,
++ .cleanup = 0,
++ },
++ [SDIO_INDEX] = {
++ .pdev = NULL,
++ .slotno = 0,
++ .rst_n_gpio = -EINVAL,
++ .cd_gpio = -EINVAL,
++ .quirks = 0,
++ .platform_quirks = 0,
++ .setup = clv_sdio_setup,
++ .cleanup = 0,
++ },
++};
++
++#define TNG_EMMC_0_FLIS_ADDR 0xff0c0900
++#define TNG_EMMC_FLIS_SLEW 0x00000400
++#define TNG_EMMC_0_CLK_PULLDOWN 0x00000200
++static int mrfl_flis_slew_change(int slew)
++{
++ void __iomem *flis_addr;
++ unsigned int reg;
++ int i, ret = 0;
++
++ flis_addr = ioremap_nocache(TNG_EMMC_0_FLIS_ADDR, 64);
++
++ if (!flis_addr) {
++ pr_err("flis_addr ioremap fail!\n");
++ ret = -ENOMEM;
++ } else {
++ pr_info("flis_addr mapped addr: %p\n", flis_addr);
++ /*
++ * Change TNG gpio FLIS settings for all eMMC0
++ * CLK/CMD/DAT pins.
++ * That is, including emmc_0_clk, emmc_0_cmd,
++ * emmc_0_d_0, emmc_0_d_1, emmc_0_d_2, emmc_0_d_3,
++ * emmc_0_d_4, emmc_0_d_5, emmc_0_d_6, emmc_0_d_7
++ */
++ for (i = 0; i < 10; i++) {
++ reg = readl(flis_addr + (i * 4));
++ if (slew)
++ reg |= TNG_EMMC_FLIS_SLEW; /* SLEW B */
++ else
++ reg &= ~TNG_EMMC_FLIS_SLEW; /* SLEW A */
++ writel(reg, flis_addr + (i * 4));
++ }
++
++ /* Disable PullDown for emmc_0_clk */
++ reg = readl(flis_addr);
++ reg &= ~TNG_EMMC_0_CLK_PULLDOWN;
++ writel(reg, flis_addr);
++
++ ret = 0;
++ }
++
++ if (flis_addr)
++ iounmap(flis_addr);
++
++ return ret;
++}
++
++static int mrfl_flis_check(void *data, unsigned int clk)
++{
++ struct sdhci_host *host = data;
++ int ret = 0;
++
++ if ((host->clock <= 52000000) && (clk > 52000000))
++ ret = mrfl_flis_slew_change(1);
++ else if ((host->clock > 52000000) && (clk <= 52000000))
++ ret = mrfl_flis_slew_change(0);
++
++ return ret;
++}
++
++/* Board specific setup related to eMMC goes here */
++static int mrfl_emmc_setup(struct sdhci_pci_data *data)
++{
++ struct pci_dev *pdev = data->pdev;
++ int ret = 0;
++
++ if (pdev->revision == 0x01) /* TNB B0 stepping */
++ ret = mrfl_flis_slew_change(1); /* HS200 FLIS slew setting */
++
++ return ret;
++}
++
++/* Board specific setup related to SD goes here */
++static int mrfl_sd_setup(struct sdhci_pci_data *data)
++{
++ u8 vldocnt = 0;
++ int err;
++
++ /*
++ * Change necessary GPIO pin mode for SD card working.
++ * This is something should be done in IA firmware.
++ * But, anyway, just do it here in case IA firmware
++ * forget to do so.
++ */
++ lnw_gpio_set_alt(MRFLD_GPIO_SDIO_0_CD, 0);
++
++ err = intel_scu_ipc_ioread8(MRFLD_PMIC_VLDOCNT, &vldocnt);
++ if (err) {
++ pr_err("PMIC vldocnt IPC read error: %d\n", err);
++ return err;
++ }
++
++ vldocnt |= MRFLD_PMIC_VLDOCNT_VSWITCH_BIT;
++ err = intel_scu_ipc_iowrite8(MRFLD_PMIC_VLDOCNT, vldocnt);
++ if (err) {
++ pr_err("PMIC vldocnt IPC write error: %d\n", err);
++ return err;
++ }
++ msleep(20);
++
++ return 0;
++}
++
++/* Board specific cleanup related to SD goes here */
++static void mrfl_sd_cleanup(struct sdhci_pci_data *data)
++{
++}
++
++/* Board specific setup related to SDIO goes here */
++static int mrfl_sdio_setup(struct sdhci_pci_data *data)
++{
++ struct pci_dev *pdev = data->pdev;
++ /* Control card power through a regulator */
++ wlan_vmmc_supply.dev_name = dev_name(&pdev->dev);
++ vwlan.gpio = get_gpio_by_name("WLAN-enable");
++ if (vwlan.gpio < 0)
++ pr_err("%s: No WLAN-enable GPIO in SFI table\n",
++ __func__);
++ pr_info("vwlan gpio %d\n", vwlan.gpio);
++ /* add a regulator to control wlan enable gpio */
++ if (platform_device_register(&vwlan_device))
++ pr_err("regulator register failed\n");
++ else
++ sdhci_pci_request_regulators();
++
++ return 0;
++}
++
++/* Board specific cleanup related to SDIO goes here */
++static void mrfl_sdio_cleanup(struct sdhci_pci_data *data)
++{
++}
++
++/* MRFL platform data */
++static struct sdhci_pci_data mrfl_sdhci_pci_data[] = {
++ [EMMC0_INDEX] = {
++ .pdev = NULL,
++ .slotno = EMMC0_INDEX,
++ .rst_n_gpio = -EINVAL,
++ .cd_gpio = -EINVAL,
++ .quirks = 0,
++ .platform_quirks = 0,
++ .setup = mrfl_emmc_setup,
++ .cleanup = 0,
++ .power_up = panic_mode_emmc0_power_up,
++ },
++ [SD_INDEX] = {
++ .pdev = NULL,
++ .slotno = SD_INDEX,
++ .rst_n_gpio = -EINVAL,
++ .cd_gpio = 77,
++ .quirks = 0,
++ .platform_quirks = 0,
++ .setup = mrfl_sd_setup,
++ .cleanup = mrfl_sd_cleanup,
++ },
++ [SDIO_INDEX] = {
++ .pdev = NULL,
++ .slotno = SDIO_INDEX,
++ .rst_n_gpio = -EINVAL,
++ .cd_gpio = -EINVAL,
++ .quirks = 0,
++ .platform_quirks = 0,
++ .setup = mrfl_sdio_setup,
++ .cleanup = mrfl_sdio_cleanup,
++ },
++};
++
++/* Board specific setup related to SDIO goes here */
++static int byt_sdio_setup(struct sdhci_pci_data *data)
++{
++ struct pci_dev *pdev = data->pdev;
++#ifdef CONFIG_ACPI
++ acpi_handle handle;
++ acpi_status status;
++#endif
++
++ /* Control card power through a regulator */
++ wlan_vmmc_supply.dev_name = dev_name(&pdev->dev);
++
++#ifdef CONFIG_ACPI
++ status = acpi_get_handle(NULL, "\\_SB.SDHB", &handle);
++ if (ACPI_FAILURE(status))
++ pr_err("wlan: cannot get SDHB acpi handle");
++ ACPI_HANDLE_SET(&pdev->dev, handle);
++ vwlan.gpio = acpi_get_gpio_by_index(&pdev->dev, 0, NULL);
++#endif
++ if (vwlan.gpio < 0)
++ pr_err("%s: No wlan-enable GPIO in SDHB ACPI block\n",
++ __func__);
++
++ pr_info("vwlan gpio %d\n", vwlan.gpio);
++
++ /* add a regulator to control wlan enable gpio */
++ if (platform_device_register(&vwlan_device))
++ pr_err("regulator register failed\n");
++ else
++ sdhci_pci_request_regulators();
++
++ return 0;
++}
++
++
++/* BYT platform data */
++static struct sdhci_pci_data byt_sdhci_pci_data[] = {
++ [SDIO_INDEX] = {
++ .pdev = NULL,
++ .slotno = 0,
++ .rst_n_gpio = -EINVAL,
++ .cd_gpio = -EINVAL,
++ .quirks = 0,
++ .platform_quirks = 0,
++ .setup = byt_sdio_setup,
++ .cleanup = NULL,
++ },
++};
++
++static struct sdhci_pci_data *get_sdhci_platform_data(struct pci_dev *pdev)
++{
++ struct sdhci_pci_data *pdata = NULL;
++
++ switch (pdev->device) {
++ case PCI_DEVICE_ID_INTEL_MFD_EMMC0:
++ pdata = &mfld_sdhci_pci_data[EMMC0_INDEX];
++ break;
++ case PCI_DEVICE_ID_INTEL_MFD_EMMC1:
++ pdata = &mfld_sdhci_pci_data[EMMC1_INDEX];
++ break;
++ case PCI_DEVICE_ID_INTEL_MFD_SD:
++ pdata = &mfld_sdhci_pci_data[SD_INDEX];
++ break;
++ case PCI_DEVICE_ID_INTEL_MFD_SDIO1:
++ pdata = &mfld_sdhci_pci_data[SDIO_INDEX];
++ pdata->quirks = sdhci_pdata_quirks;
++ pdata->register_embedded_control = sdhci_embedded_control;
++ break;
++ case PCI_DEVICE_ID_INTEL_CLV_EMMC0:
++ pdata = &clv_sdhci_pci_data[EMMC0_INDEX];
++ pdata->rst_n_gpio = get_gpio_by_name("emmc0_rst");
++ break;
++ case PCI_DEVICE_ID_INTEL_CLV_EMMC1:
++ pdata = &clv_sdhci_pci_data[EMMC1_INDEX];
++ pdata->rst_n_gpio = get_gpio_by_name("emmc1_rst");
++ break;
++ case PCI_DEVICE_ID_INTEL_CLV_SDIO0:
++ pdata = &clv_sdhci_pci_data[SD_INDEX];
++ break;
++ case PCI_DEVICE_ID_INTEL_CLV_SDIO1:
++ pdata = &clv_sdhci_pci_data[SDIO_INDEX];
++ pdata->quirks = sdhci_pdata_quirks;
++ pdata->register_embedded_control = sdhci_embedded_control;
++ break;
++ case PCI_DEVICE_ID_INTEL_MRFL_MMC:
++ switch (PCI_FUNC(pdev->devfn)) {
++ case 0:
++ pdata = &mrfl_sdhci_pci_data[EMMC0_INDEX];
++ /*
++ * The current eMMC device simulation in Merrifield
++ * VP only implements boot partition 0, does not
++ * implements boot partition 1. And the VP will
++ * crash if eMMC boot partition 1 is accessed
++ * during kernel boot. So, we just disable boot
++ * partition support for Merrifield VP platform.
++ */
++ if (intel_mid_identify_sim() ==
++ INTEL_MID_CPU_SIMULATION_VP)
++ pdata->platform_quirks |=
++ PLFM_QUIRK_NO_EMMC_BOOT_PART;
++ if (intel_mid_identify_sim() ==
++ INTEL_MID_CPU_SIMULATION_HVP)
++ pdata->platform_quirks |=
++ PLFM_QUIRK_NO_HIGH_SPEED;
++ break;
++ case 1:
++ pdata = &mrfl_sdhci_pci_data[EMMC1_INDEX];
++ if (intel_mid_identify_sim() ==
++ INTEL_MID_CPU_SIMULATION_VP)
++ pdata->platform_quirks |=
++ PLFM_QUIRK_NO_EMMC_BOOT_PART;
++ /*
++ * Merrifield HVP platform only implements
++ * eMMC0 host controller in its FPGA, and
++ * does not implements other 3 Merrifield
++ * SDHCI host controllers.
++ */
++ if (intel_mid_identify_sim() ==
++ INTEL_MID_CPU_SIMULATION_HVP)
++ pdata->platform_quirks |=
++ PLFM_QUIRK_NO_HOST_CTRL_HW;
++ break;
++ case 2:
++ pdata = &mrfl_sdhci_pci_data[SD_INDEX];
++ if (intel_mid_identify_sim() ==
++ INTEL_MID_CPU_SIMULATION_HVP)
++ pdata->platform_quirks |=
++ PLFM_QUIRK_NO_HOST_CTRL_HW;
++ break;
++ case 3:
++ pdata = &mrfl_sdhci_pci_data[SDIO_INDEX];
++ if (intel_mid_identify_sim() ==
++ INTEL_MID_CPU_SIMULATION_HVP)
++ pdata->platform_quirks |=
++ PLFM_QUIRK_NO_HOST_CTRL_HW;
++ pdata->quirks = sdhci_pdata_quirks;
++ pdata->register_embedded_control =
++ sdhci_embedded_control;
++ break;
++ default:
++ pr_err("%s func %s: Invalid PCI Dev func no. (%d)\n",
++ __FILE__, __func__, PCI_FUNC(pdev->devfn));
++ break;
++ }
++ break;
++ case PCI_DEVICE_ID_INTEL_BYT_SDIO:
++ pr_err("setting quirks/embedded controls on SDIO");
++ pdata = &byt_sdhci_pci_data[SDIO_INDEX];
++ pdata->quirks = sdhci_pdata_quirks;
++ pdata->register_embedded_control = sdhci_embedded_control;
++ break;
++ default:
++ break;
++ }
++ return pdata;
++}
++
++int sdhci_pdata_set_embedded_control(void (*fnp)
++ (void *dev_id, void (*virtual_cd)
++ (void *dev_id, int card_present)))
++{
++ WARN_ON(sdhci_embedded_control);
++ sdhci_embedded_control = fnp;
++ return 0;
++}
++
++struct sdhci_pci_data *mmc_sdhci_pci_get_data(struct pci_dev *pci_dev, int slotno)
++{
++ return get_sdhci_platform_data(pci_dev);
++}
++
++static int __init init_sdhci_get_data(void)
++{
++ sdhci_pci_get_data = mmc_sdhci_pci_get_data;
++
++ return 0;
++}
++
++arch_initcall(init_sdhci_get_data);
++
+diff --git a/arch/x86/platform/intel-mid/device_libs/pci/platform_sdhci_pci.h b/arch/x86/platform/intel-mid/device_libs/pci/platform_sdhci_pci.h
+new file mode 100644
+index 0000000..9f14952
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/pci/platform_sdhci_pci.h
+@@ -0,0 +1,30 @@
++/*
++ * platform_mmc_sdhci_pci.h: mmc sdhci pci platform data header file
++ *
++ * (C) Copyright 2012 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_MMC_SDHCI_PCI_H_
++#define _PLATFORM_MMC_SDHCI_PCI_H_
++
++#define EMMC0_INDEX 0
++#define EMMC1_INDEX 1
++#define SD_INDEX 2
++#define SDIO_INDEX 3
++
++#define MRFLD_GPIO_SDIO_0_CD 77
++
++#define MRFLD_PMIC_VLDOCNT 0xaf
++#define MRFLD_PMIC_VLDOCNT_VSWITCH_BIT 0x02
++
++int sdhci_pdata_set_quirks(const unsigned int quirks);
++int sdhci_pdata_set_embedded_control(void (*fnp)
++ (void *dev_id, void (*virtual_cd)
++ (void *dev_id, int card_present)));
++#endif
++
+diff --git a/arch/x86/platform/intel-mid/device_libs/pci/platform_usb_otg.c b/arch/x86/platform/intel-mid/device_libs/pci/platform_usb_otg.c
+new file mode 100644
+index 0000000..4deead8
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/pci/platform_usb_otg.c
+@@ -0,0 +1,93 @@
++/*
++ * platform_otg_pci.c: USB OTG platform data initilization file
++ *
++ * (C) Copyright 2013 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/pci.h>
++#include <asm/intel-mid.h>
++#include <asm/intel_scu_ipc.h>
++#include <linux/dma-mapping.h>
++
++#ifdef CONFIG_USB_DWC3_OTG
++#include <linux/usb/dwc3-intel-mid.h>
++static struct intel_dwc_otg_pdata dwc_otg_pdata;
++
++static bool dwc_otg_get_usbspecoverride(void)
++{
++ void __iomem *usb_comp_iomap;
++ bool usb_spec_override;
++
++ /* Read MISCFLAGS byte from offset 0x717 */
++ usb_comp_iomap = ioremap_nocache(0xFFFCE717, 4);
++ /* MISCFLAGS.BIT[6] indicates USB spec override */
++ usb_spec_override = ioread8(usb_comp_iomap) & 0x40;
++ iounmap(usb_comp_iomap);
++
++ return usb_spec_override;
++}
++
++static struct intel_dwc_otg_pdata *get_otg_platform_data(struct pci_dev *pdev)
++{
++ switch (pdev->device) {
++ case PCI_DEVICE_ID_INTEL_MRFL_DWC3_OTG:
++ dwc_otg_pdata.pmic_type = BASIN_COVE;
++ dwc_otg_pdata.charger_detect_enable = 1;
++
++ dwc_otg_pdata.charging_compliance =
++ dwc_otg_get_usbspecoverride();
++
++ return &dwc_otg_pdata;
++ default:
++ break;
++ }
++
++ return NULL;
++}
++#endif
++
++#ifdef CONFIG_USB_PENWELL_OTG
++#include <linux/usb/penwell_otg.h>
++static struct intel_mid_otg_pdata otg_pdata = {
++ .gpio_vbus = 0,
++ .gpio_cs = 0,
++ .gpio_reset = 0,
++ .charging_compliance = 0,
++ .hnp_poll_support = 0,
++ .power_budget = 500
++};
++
++static struct intel_mid_otg_pdata *get_otg_platform_data(struct pci_dev *pdev)
++{
++ struct intel_mid_otg_pdata *pdata = &otg_pdata;
++
++ switch (pdev->device) {
++ case PCI_DEVICE_ID_INTEL_MRFL_DWC3_OTG:
++ dwc_otg_pdata.pmic_type = BASIN_COVE;
++ dwc_otg_pdata.charger_detect_enable = 1;
++
++ dwc_otg_pdata.charging_compliance =
++ dwc_otg_get_usbspecoverride();
++ return &dwc_otg_pdata;
++
++ default:
++ break;
++ }
++
++ return pdata;
++}
++#endif
++
++static void otg_pci_early_quirks(struct pci_dev *pci_dev)
++{
++ pci_dev->dev.platform_data = get_otg_platform_data(pci_dev);
++}
++
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFL_DWC3_OTG,
++ otg_pci_early_quirks);
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_ads7955.c b/arch/x86/platform/intel-mid/device_libs/platform_ads7955.c
+new file mode 100644
+index 0000000..c0d07aa
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_ads7955.c
+@@ -0,0 +1,37 @@
++/*
++ * platform_ads7955.c: ads7955 platform data initialization file
++ *
++ * (C) Copyright 2014 Intel Corporation
++ * Author: Dan O'Donovan <dan@emutex.com>
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/gpio.h>
++#include <linux/spi/spi.h>
++#include <linux/lnw_gpio.h>
++#include <linux/spi/intel_mid_ssp_spi.h>
++#include <asm/intel-mid.h>
++#include "platform_ads7955.h"
++
++static struct intel_mid_ssp_spi_chip chip = {
++ .burst_size = DFLT_FIFO_BURST_SIZE,
++ .timeout = DFLT_TIMEOUT_VAL,
++ /* SPI DMA is current not usable on Tangier */
++ .dma_enabled = false,
++};
++
++void __init *ads7955_platform_data(void *info)
++{
++ struct spi_board_info *spi_info = info;
++
++ spi_info->mode = SPI_MODE_0;
++
++ spi_info->controller_data = &chip;
++ spi_info->bus_num = FORCE_SPI_BUS_NUM;
++
++ return NULL;
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_ads7955.h b/arch/x86/platform/intel-mid/device_libs/platform_ads7955.h
+new file mode 100644
+index 0000000..114958f
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_ads7955.h
+@@ -0,0 +1,20 @@
++/*
++ * platform_ads7955.h: ads7955 platform data header file
++ *
++ * (C) Copyright 2014 Intel Corporation
++ * Author: Dan O'Donovan <dan@emutex.com>
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_ADS7955_H_
++#define _PLATFORM_ADS7955_H_
++
++/* REVERT ME workaround[MRFL] for invalid bus number in IAFW .25 */
++#define FORCE_SPI_BUS_NUM 5
++#define FORCE_CHIP_SELECT 0
++
++extern void *ads7955_platform_data(void *info) __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_bcove_adc.c b/arch/x86/platform/intel-mid/device_libs/platform_bcove_adc.c
+new file mode 100644
+index 0000000..88125ac
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_bcove_adc.c
+@@ -0,0 +1,143 @@
++/*
++ * platform_bcove_adc.c: Platform data for Merrifield Basincove GPADC driver
++ *
++ * (C) Copyright 2012 Intel Corporation
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/sfi.h>
++#include <linux/iio/iio.h>
++#include <linux/iio/machine.h>
++#include <linux/iio/types.h>
++#include <asm/intel-mid.h>
++#include <asm/intel_basincove_gpadc.h>
++#include <asm/intel_mid_remoteproc.h>
++
++#include "platform_bcove_adc.h"
++
++/* SRAM address where the GPADC interrupt register is cached */
++#define GPADC_SRAM_INTR_ADDR 0xfffff615
++
++static struct gpadc_regmap_t basincove_gpadc_regmaps[GPADC_CH_NUM] = {
++ {"VBAT", 5, 0xE9, 0xEA, },
++ {"BATID", 4, 0xEB, 0xEC, },
++ {"IBAT", 5, 0xED, 0xEE, },
++ {"PMICTEMP", 3, 0xCC, 0xCD, },
++ {"BATTEMP0", 2, 0xC8, 0xC9, },
++ {"BATTEMP1", 2, 0xCA, 0xCB, },
++ {"SYSTEMP0", 3, 0xC2, 0xC3, },
++ {"SYSTEMP1", 3, 0xC4, 0xC5, },
++ {"SYSTEMP2", 3, 0xC6, 0xC7, },
++};
++
++static struct gpadc_regs_t basincove_gpadc_regs = {
++ .gpadcreq = 0xDC,
++ .gpadcreq_irqen = (1 << 1),
++ .gpadcreq_busy = (1 << 0),
++ .mirqlvl1 = 0x0C,
++ .mirqlvl1_adc = (1 << 4),
++ .adc1cntl = 0xDD,
++ .adcirq = 0x06,
++ .madcirq = 0x11,
++};
++
++#define MSIC_ADC_MAP(_adc_channel_label, \
++ _consumer_dev_name, \
++ _consumer_channel) \
++ { \
++ .adc_channel_label = _adc_channel_label, \
++ .consumer_dev_name = _consumer_dev_name, \
++ .consumer_channel = _consumer_channel, \
++ }
++
++struct iio_map basincove_iio_maps[] = {
++ MSIC_ADC_MAP("CH0", "VIBAT", "VBAT"),
++ MSIC_ADC_MAP("CH1", "BATID", "BATID"),
++ MSIC_ADC_MAP("CH2", "VIBAT", "IBAT"),
++ MSIC_ADC_MAP("CH3", "PMICTEMP", "PMICTEMP"),
++ MSIC_ADC_MAP("CH4", "BATTEMP", "BATTEMP0"),
++ MSIC_ADC_MAP("CH5", "BATTEMP", "BATTEMP1"),
++ MSIC_ADC_MAP("CH6", "SYSTEMP", "SYSTEMP0"),
++ MSIC_ADC_MAP("CH7", "SYSTEMP", "SYSTEMP1"),
++ MSIC_ADC_MAP("CH8", "SYSTEMP", "SYSTEMP2"),
++ MSIC_ADC_MAP("CH6", "bcove_thrm", "SYSTEMP0"),
++ MSIC_ADC_MAP("CH7", "bcove_thrm", "SYSTEMP1"),
++ MSIC_ADC_MAP("CH8", "bcove_thrm", "SYSTEMP2"),
++ MSIC_ADC_MAP("CH3", "bcove_thrm", "PMICTEMP"),
++ { },
++};
++
++#define MSIC_ADC_CHANNEL(_type, _channel, _datasheet_name) \
++ { \
++ .indexed = 1, \
++ .type = _type, \
++ .channel = _channel, \
++ .datasheet_name = _datasheet_name, \
++ }
++
++static const struct iio_chan_spec const basincove_adc_channels[] = {
++ MSIC_ADC_CHANNEL(IIO_VOLTAGE, 0, "CH0"),
++ MSIC_ADC_CHANNEL(IIO_RESISTANCE, 1, "CH1"),
++ MSIC_ADC_CHANNEL(IIO_CURRENT, 2, "CH2"),
++ MSIC_ADC_CHANNEL(IIO_TEMP, 3, "CH3"),
++ MSIC_ADC_CHANNEL(IIO_TEMP, 4, "CH4"),
++ MSIC_ADC_CHANNEL(IIO_TEMP, 5, "CH5"),
++ MSIC_ADC_CHANNEL(IIO_TEMP, 6, "CH6"),
++ MSIC_ADC_CHANNEL(IIO_TEMP, 7, "CH7"),
++ MSIC_ADC_CHANNEL(IIO_TEMP, 8, "CH8"),
++};
++
++static struct intel_basincove_gpadc_platform_data bcove_adc_pdata = {
++ .channel_num = GPADC_CH_NUM,
++ .intr = GPADC_SRAM_INTR_ADDR,
++ .gpadc_iio_maps = basincove_iio_maps,
++ .gpadc_regmaps = basincove_gpadc_regmaps,
++ .gpadc_regs = &basincove_gpadc_regs,
++ .gpadc_channels = basincove_adc_channels,
++};
++
++void __init *bcove_adc_platform_data(void *info)
++{
++ struct platform_device *pdev = NULL;
++ struct sfi_device_table_entry *entry = info;
++ int ret;
++
++ pdev = platform_device_alloc(BCOVE_ADC_DEV_NAME, -1);
++
++ if (!pdev) {
++ pr_err("out of memory for SFI platform dev %s\n",
++ BCOVE_ADC_DEV_NAME);
++ goto out;
++ }
++
++ bcove_adc_pdata.channel_num = GPADC_CH_NUM;
++ bcove_adc_pdata.intr = GPADC_SRAM_INTR_ADDR;
++ bcove_adc_pdata.intr_mask = MBATTEMP | MSYSTEMP | MBATT
++ | MVIBATT | MCCTICK;
++ bcove_adc_pdata.gpadc_iio_maps = basincove_iio_maps;
++ bcove_adc_pdata.gpadc_regmaps = basincove_gpadc_regmaps;
++ bcove_adc_pdata.gpadc_regs = &basincove_gpadc_regs;
++ bcove_adc_pdata.gpadc_channels = basincove_adc_channels;
++
++ pdev->dev.platform_data = &bcove_adc_pdata;
++
++ ret = platform_device_add(pdev);
++ if (ret) {
++ pr_err("failed to add bcove adc platform device\n");
++ platform_device_put(pdev);
++ goto out;
++ }
++
++ install_irq_resource(pdev, entry->irq);
++
++ register_rpmsg_service("rpmsg_bcove_adc", RPROC_SCU,
++ RP_BCOVE_ADC);
++out:
++ return &bcove_adc_pdata;
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_bcove_adc.h b/arch/x86/platform/intel-mid/device_libs/platform_bcove_adc.h
+new file mode 100644
+index 0000000..044adc7
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_bcove_adc.h
+@@ -0,0 +1,17 @@
++/*
++ * platform_bcove_adc.h: Head File for Merrifield Basincove GPADC driver
++ *
++ * (C) Copyright 2012 Intel Corporation
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_BCOVE_ADC_H_
++#define _PLATFORM_BCOVE_ADC_H_
++
++#define BCOVE_ADC_DEV_NAME "bcove_adc"
++
++extern void __init *bcove_adc_platform_data(void *info) __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_bq24261.c b/arch/x86/platform/intel-mid/device_libs/platform_bq24261.c
+new file mode 100644
+index 0000000..1c1a583
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_bq24261.c
+@@ -0,0 +1,77 @@
++/*
++ * platform_mrfl_bq24261.c: Platform data for bq24261 charger driver
++ *
++ * (C) Copyright 2012 Intel Corporation
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/scatterlist.h>
++#include <linux/init.h>
++#include <linux/sfi.h>
++#include <linux/power_supply.h>
++#include <asm/pmic_pdata.h>
++#include <linux/power/bq24261_charger.h>
++#include <asm/intel-mid.h>
++
++#include "platform_ipc.h"
++#include "platform_bq24261.h"
++
++#define BOOST_CUR_LIM 500
++
++static struct power_supply_throttle bq24261_throttle_states[] = {
++ {
++ .throttle_action = PSY_THROTTLE_CC_LIMIT,
++ .throttle_val = BQ24261_CHRG_CUR_NOLIMIT,
++
++ },
++ {
++ .throttle_action = PSY_THROTTLE_CC_LIMIT,
++ .throttle_val = BQ24261_CHRG_CUR_MEDIUM,
++
++ },
++ {
++ .throttle_action = PSY_THROTTLE_DISABLE_CHARGING,
++ },
++ {
++ .throttle_action = PSY_THROTTLE_DISABLE_CHARGER,
++ },
++
++};
++
++char *bq24261_supplied_to[] = {
++ "max170xx_battery",
++ "max17047_battery",
++};
++
++
++void __init *bq24261_platform_data(void *info)
++{
++ static struct bq24261_plat_data bq24261_pdata;
++
++
++ bq24261_pdata.irq_map = PMIC_SRAM_INTR_MAP;
++ bq24261_pdata.irq_mask = PMIC_EXT_INTR_MASK;
++ bq24261_pdata.supplied_to = bq24261_supplied_to;
++ bq24261_pdata.num_supplicants = ARRAY_SIZE(bq24261_supplied_to);
++ bq24261_pdata.throttle_states = bq24261_throttle_states;
++ bq24261_pdata.num_throttle_states = ARRAY_SIZE(bq24261_throttle_states);
++ bq24261_pdata.enable_charger = NULL;
++#ifdef CONFIG_PMIC_CCSM
++ bq24261_pdata.enable_charging = pmic_enable_charging;
++ bq24261_pdata.set_inlmt = pmic_set_ilimma;
++ bq24261_pdata.set_cc = pmic_set_cc;
++ bq24261_pdata.set_cv = pmic_set_cv;
++ bq24261_pdata.dump_master_regs = dump_pmic_regs;
++ bq24261_pdata.enable_vbus = pmic_enable_vbus;
++#endif
++ bq24261_pdata.set_iterm = NULL;
++ bq24261_pdata.boost_mode_ma = BOOST_CUR_LIM;
++
++ return &bq24261_pdata;
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_bq24261.h b/arch/x86/platform/intel-mid/device_libs/platform_bq24261.h
+new file mode 100644
+index 0000000..6b97380
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_bq24261.h
+@@ -0,0 +1,26 @@
++/*
++ * platform_mrfl_bq24261.h: platform data for bq24261 driver
++ *
++ * (C) Copyright 2012 Intel Corporation
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_MRFL_BQ24261_H_
++#define _PLATFORM_MRFL_BQ24261_H_
++
++#define MRFL_CHRGR_DEV_NAME "bq24261_charger"
++
++#define PMIC_SRAM_INTR_MAP 0xFFFFF616
++#define PMIC_EXT_INTR_MASK 0x01
++
++#define BQ24261_CHRG_CUR_LOW 100 /* 100mA */
++#define BQ24261_CHRG_CUR_MEDIUM 500 /* 500mA */
++#define BQ24261_CHRG_CUR_HIGH 900 /* 900mA */
++#define BQ24261_CHRG_CUR_NOLIMIT 1500 /* 1500mA */
++
++extern void __init *bq24261_platform_data(
++ void *info) __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_btlpm.c b/arch/x86/platform/intel-mid/device_libs/platform_btlpm.c
+new file mode 100644
+index 0000000..084452d
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_btlpm.c
+@@ -0,0 +1,80 @@
++/*
++ * platform_btlpm: btlpm platform data initialization file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#include <linux/init.h>
++#include <linux/pm_runtime.h>
++#include <asm/bcm_bt_lpm.h>
++#include <asm/intel-mid.h>
++#include <linux/gpio.h>
++
++#define UART_PORT_NO 0 /* Bluetooth is using UART port number 0 */
++
++#define LPM_ON
++
++static struct bcm_bt_lpm_platform_data bcm_bt_lpm_pdata = {
++ .gpio_wake = -EINVAL,
++ .gpio_host_wake = -EINVAL,
++ .int_host_wake = -EINVAL,
++ .gpio_enable = -EINVAL,
++ .port = UART_PORT_NO,
++};
++
++struct platform_device bcm_bt_lpm_device = {
++ .name = "bcm_bt_lpm",
++ .id = 0,
++ .dev = {
++ .platform_data = &bcm_bt_lpm_pdata,
++ },
++};
++
++static int __init bluetooth_init(void)
++{
++
++ int error_reg;
++
++ /* Get the GPIO numbers from the SFI table */
++
++ bcm_bt_lpm_pdata.gpio_enable = get_gpio_by_name("BT-reset");
++ if (!gpio_is_valid(bcm_bt_lpm_pdata.gpio_enable)) {
++ pr_err("%s: gpio %s not found\n", __func__, "BT-reset");
++ return -ENODEV;
++ }
++
++#ifdef LPM_ON
++ bcm_bt_lpm_pdata.gpio_host_wake = get_gpio_by_name("bt_uart_enable");
++ if (!gpio_is_valid(bcm_bt_lpm_pdata.gpio_host_wake)) {
++ pr_err("%s: gpio %s not found\n", __func__, "bt_uart_enable");
++ return -ENODEV;
++ }
++
++ bcm_bt_lpm_pdata.int_host_wake =
++ gpio_to_irq(bcm_bt_lpm_pdata.gpio_host_wake);
++
++ bcm_bt_lpm_pdata.gpio_wake = get_gpio_by_name("bt_wakeup");
++ if (!gpio_is_valid(bcm_bt_lpm_pdata.gpio_wake)) {
++ pr_err("%s: gpio %s not found\n", __func__, "bt_wakeup");
++ return -ENODEV;
++ }
++
++ pr_debug("%s: gpio_wake %d, gpio_host_wake %d\n", __func__,
++ bcm_bt_lpm_pdata.gpio_wake, bcm_bt_lpm_pdata.gpio_host_wake);
++#endif
++
++ error_reg = platform_device_register(&bcm_bt_lpm_device);
++ if (error_reg < 0) {
++ pr_err("%s: platform_device_register for %s failed\n",
++ __func__, bcm_bt_lpm_device.name);
++ return -ENODEV;
++ }
++ return 0;
++}
++
++device_initcall(bluetooth_init);
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_dw_i2c.c b/arch/x86/platform/intel-mid/device_libs/platform_dw_i2c.c
+new file mode 100644
+index 0000000..9f1822d
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_dw_i2c.c
+@@ -0,0 +1,113 @@
++/*
++ * platform_dw_i2c.c: I2C platform data initilization file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/lnw_gpio.h>
++#include <linux/gpio.h>
++#include <asm/intel-mid.h>
++
++struct i2c_pin_cfg {
++ int scl_gpio;
++ int scl_alt;
++ int sda_gpio;
++ int sda_alt;
++};
++
++enum {
++ BOARD_NONE = 0,
++ BOARD_VTB,
++ BOARD_SALTBAY,
++};
++
++static struct i2c_pin_cfg dw_i2c_pin_cfgs[][10] = {
++ [BOARD_NONE] = {},
++ [BOARD_VTB] = {
++ [1] = {27, 1, 26, 1},
++ },
++ [BOARD_SALTBAY] = {
++ [1] = {19, 1, 20, 1},
++ },
++};
++
++int intel_mid_dw_i2c_abort(int busnum)
++{
++ int i;
++ int ret = -EBUSY;
++ struct i2c_pin_cfg *pins = &dw_i2c_pin_cfgs[BOARD_NONE][busnum];
++
++ switch (intel_mid_identify_cpu()) {
++ case INTEL_MID_CPU_CHIP_CLOVERVIEW:
++ pins = &dw_i2c_pin_cfgs[BOARD_VTB][busnum];
++ break;
++ case INTEL_MID_CPU_CHIP_TANGIER:
++ pins = &dw_i2c_pin_cfgs[BOARD_SALTBAY][busnum];
++ break;
++ default:
++ break;
++ }
++
++ if (!pins->scl_gpio || !pins->sda_gpio) {
++ pr_err("i2c-%d: recovery ignore\n", busnum);
++ return 0;
++ }
++ pr_err("i2c-%d: try to abort xfer, scl_gpio %d, sda_gpio %d\n",
++ busnum, pins->scl_gpio, pins->sda_gpio);
++ gpio_request(pins->scl_gpio, "scl");
++ gpio_request(pins->sda_gpio, "sda");
++ lnw_gpio_set_alt(pins->scl_gpio, LNW_GPIO);
++ lnw_gpio_set_alt(pins->sda_gpio, LNW_GPIO);
++ gpio_direction_input(pins->scl_gpio);
++ gpio_direction_input(pins->sda_gpio);
++ usleep_range(10, 10);
++ pr_err("i2c-%d: scl_gpio val %d, sda_gpio val %d\n",
++ busnum,
++ gpio_get_value(pins->scl_gpio) ? 1 : 0,
++ gpio_get_value(pins->sda_gpio) ? 1 : 0);
++ gpio_direction_output(pins->scl_gpio, 1);
++ pr_err("i2c-%d: toggle begin\n", busnum);
++ for (i = 0; i < 9; i++) {
++ if (gpio_get_value(pins->sda_gpio)) {
++ if (gpio_get_value(pins->scl_gpio)) {
++ pr_err("i2c-%d: recovery success\n", busnum);
++ break;
++ } else {
++ gpio_direction_output(pins->scl_gpio, 0);
++ pr_err("i2c-%d: scl_gpio val 0, sda_gpio val 1\n",
++ busnum);
++ }
++ }
++ gpio_set_value(pins->scl_gpio, 0);
++ usleep_range(10, 20);
++ gpio_set_value(pins->scl_gpio, 1);
++ usleep_range(10, 20);
++ pr_err("i2c-%d: toggle SCL loop %d\n", busnum, i);
++ }
++ pr_err("i2c-%d: toggle end\n", busnum);
++ gpio_direction_output(pins->scl_gpio, 1);
++ gpio_direction_output(pins->sda_gpio, 0);
++ gpio_set_value(pins->scl_gpio, 0);
++ usleep_range(10, 20);
++ gpio_set_value(pins->scl_gpio, 1);
++ usleep_range(10, 20);
++ gpio_set_value(pins->sda_gpio, 0);
++ lnw_gpio_set_alt(pins->scl_gpio, pins->scl_alt);
++ lnw_gpio_set_alt(pins->sda_gpio, pins->sda_alt);
++ usleep_range(10, 10);
++ gpio_free(pins->scl_gpio);
++ gpio_free(pins->sda_gpio);
++
++ return ret;
++}
++EXPORT_SYMBOL(intel_mid_dw_i2c_abort);
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_emc1403.c b/arch/x86/platform/intel-mid/device_libs/platform_emc1403.c
+new file mode 100644
+index 0000000..b7760f2
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_emc1403.c
+@@ -0,0 +1,33 @@
++/*
++ * platform_emc1403.c: emc1403 platform data initilization file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/init.h>
++#include <linux/gpio.h>
++#include <linux/i2c.h>
++#include <asm/intel-mid.h>
++#include "platform_emc1403.h"
++
++void __init *emc1403_platform_data(void *info)
++{
++ static short intr2nd_pdata;
++ struct i2c_board_info *i2c_info = info;
++ int intr = get_gpio_by_name("thermal_int");
++ int intr2nd = get_gpio_by_name("thermal_alert");
++
++ if (intr == -1 || intr2nd == -1)
++ return NULL;
++
++ i2c_info->irq = intr + INTEL_MID_IRQ_OFFSET;
++ intr2nd_pdata = intr2nd + INTEL_MID_IRQ_OFFSET;
++
++ return &intr2nd_pdata;
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_emc1403.h b/arch/x86/platform/intel-mid/device_libs/platform_emc1403.h
+new file mode 100644
+index 0000000..0229438
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_emc1403.h
+@@ -0,0 +1,16 @@
++/*
++ * platform_emc1403.h: emc1403 platform data header file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_EMC1403_H_
++#define _PLATFORM_EMC1403_H_
++
++extern void __init *emc1403_platform_data(void *info) __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_gpio_keys.c b/arch/x86/platform/intel-mid/device_libs/platform_gpio_keys.c
+new file mode 100644
+index 0000000..395e051
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_gpio_keys.c
+@@ -0,0 +1,89 @@
++/*
++ * platform_gpio_keys.c: gpio_keys platform data initilization file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/input.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/gpio.h>
++#include <linux/gpio_keys.h>
++#include <linux/platform_device.h>
++#include <asm/intel-mid.h>
++#include "platform_gpio_keys.h"
++
++/*
++ * we will search these buttons in SFI GPIO table (by name)
++ * and register them dynamically. Please add all possible
++ * buttons here, we will shrink them if no GPIO found.
++ */
++static struct gpio_keys_button gpio_button[] = {
++ {
++ .code = KEY_POWER,
++ .gpio = -1, /* GPIO number */
++ .active_low = 1,
++ .desc = "power_btn",/*Button description*/
++ .type = EV_KEY,
++ .wakeup = 0,
++ .debounce_interval = 3000,
++ },
++ {
++ .code = KEY_PROG1,
++ .gpio = 61,
++ .active_low = 1,
++ .desc = "SW1UI4",
++ .type = EV_KEY,
++ .wakeup = 0,
++ .debounce_interval = 50,
++ },
++};
++
++static struct gpio_keys_platform_data gpio_keys = {
++ .buttons = gpio_button,
++ .rep = 1,
++ .nbuttons = -1, /* will fill it after search */
++};
++
++static struct platform_device pb_device = {
++ .name = DEVICE_NAME,
++ .id = -1,
++ .dev = {
++ .platform_data = &gpio_keys,
++ },
++};
++
++/*
++ * Shrink the non-existent buttons, register the gpio button
++ * device if there is some
++ */
++static int __init pb_keys_init(void)
++{
++ struct gpio_keys_button *gb = gpio_button;
++ int i, num, good = 0;
++
++ num = sizeof(gpio_button) / sizeof(struct gpio_keys_button);
++ for (i = 0; i < num; i++) {
++ pr_info("info[%2d]: name = %s, gpio = %d\n",
++ i, gb[i].desc, gb[i].gpio);
++ if (gb[i].gpio == -1)
++ continue;
++
++ if (i != good)
++ gb[good] = gb[i];
++ good++;
++ }
++
++ if (good) {
++ gpio_keys.nbuttons = good;
++ return platform_device_register(&pb_device);
++ }
++ return 0;
++}
++late_initcall(pb_keys_init);
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_gpio_keys.h b/arch/x86/platform/intel-mid/device_libs/platform_gpio_keys.h
+new file mode 100644
+index 0000000..5095329
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_gpio_keys.h
+@@ -0,0 +1,16 @@
++/*
++ * platform_gpio_keys.h: gpio_keys platform data header file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_GPIO_KEYS_H_
++#define _PLATFORM_GPIO_KEYS_H_
++
++#define DEVICE_NAME "gpio-keys"
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_hsu.c b/arch/x86/platform/intel-mid/device_libs/platform_hsu.c
+new file mode 100644
+index 0000000..293793e
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_hsu.c
+@@ -0,0 +1,440 @@
++/*
++ * platform_hsu.c: hsu platform data initilization file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/pm_runtime.h>
++#include <linux/lnw_gpio.h>
++#include <linux/gpio.h>
++#include <asm/setup.h>
++#include <asm/intel-mid.h>
++#include <asm/intel_mid_hsu.h>
++
++#include "platform_hsu.h"
++
++#define TNG_CLOCK_CTL 0xFF00B830
++#define TNG_CLOCK_SC 0xFF00B868
++
++#define VLV_HSU_CLOCK 0x0800
++#define VLV_HSU_RESET 0x0804
++
++static unsigned int clock;
++static struct hsu_port_pin_cfg *hsu_port_gpio_mux;
++static struct hsu_port_cfg *platform_hsu_info;
++
++static struct
++hsu_port_pin_cfg hsu_port_pin_cfgs[][hsu_pid_max][hsu_port_max] = {
++ [hsu_tng] = {
++ [hsu_pid_def] = {
++ [hsu_port0] = {
++ .id = 0,
++ .name = HSU_BT_PORT,
++ .rx_gpio = 126,
++ .rx_alt = 1,
++ .tx_gpio = 127,
++ .tx_alt = 1,
++ .cts_gpio = 124,
++ .cts_alt = 1,
++ .rts_gpio = 125,
++ .rts_alt = 1,
++ },
++ [hsu_port1] = {
++ .id = 1,
++ .name = HSU_GPS_PORT,
++ .wake_gpio = 130,
++ .rx_gpio = 130,
++ .rx_alt = 1,
++ .tx_gpio = 131,
++ .tx_alt = 1,
++ .cts_gpio = 128,
++ .cts_alt = 1,
++ .rts_gpio = 129,
++ .rts_alt = 1,
++ },
++ [hsu_port2] = {
++ .id = 2,
++ .name = HSU_DEBUG_PORT,
++ .wake_gpio = 134,
++ .rx_gpio = 134,
++ .rx_alt = 1,
++ .cts_gpio = 132,
++ .cts_alt = 1,
++ .rts_gpio = 133,
++ .rts_alt = 1,
++ },
++ },
++ },
++
++};
++
++static struct hsu_port_cfg hsu_port_cfgs[][hsu_port_max] = {
++ [hsu_tng] = {
++ [hsu_port0] = {
++ .type = bt_port,
++ .hw_ip = hsu_intel,
++ .index = 0,
++ .name = HSU_BT_PORT,
++ .idle = 20,
++ .hw_init = intel_mid_hsu_init,
++ .hw_set_alt = intel_mid_hsu_switch,
++ .hw_set_rts = intel_mid_hsu_rts,
++ .hw_suspend = intel_mid_hsu_suspend,
++ .hw_resume = intel_mid_hsu_resume,
++ .hw_get_clk = intel_mid_hsu_get_clk,
++ .hw_context_save = 1,
++ },
++ [hsu_port1] = {
++ .type = gps_port,
++ .hw_ip = hsu_intel,
++ .index = 1,
++ .name = HSU_GPS_PORT,
++ .idle = 30,
++ .preamble = 1,
++ .hw_init = intel_mid_hsu_init,
++ .hw_set_alt = intel_mid_hsu_switch,
++ .hw_set_rts = intel_mid_hsu_rts,
++ .hw_suspend = intel_mid_hsu_suspend,
++ .hw_suspend_post = intel_mid_hsu_suspend_post,
++ .hw_resume = intel_mid_hsu_resume,
++ .hw_get_clk = intel_mid_hsu_get_clk,
++ .hw_context_save = 1,
++ },
++ [hsu_port2] = {
++ .type = debug_port,
++ .hw_ip = hsu_intel,
++ .index = 2,
++ .name = HSU_DEBUG_PORT,
++ .idle = 5000,
++ .hw_init = intel_mid_hsu_init,
++ .hw_set_alt = intel_mid_hsu_switch,
++ .hw_suspend = intel_mid_hsu_suspend,
++ .hw_resume = intel_mid_hsu_resume,
++ .hw_get_clk = intel_mid_hsu_get_clk,
++ .hw_context_save = 1,
++ },
++ },
++};
++
++static struct hsu_func2port hsu_port_func_id_tlb[][hsu_port_func_max] = {
++ [hsu_tng] = {
++ [0] = {
++ .func = 0,
++ .port = -1,
++ },
++ [1] = {
++ .func = 1,
++ .port = hsu_port0,
++ },
++ [2] = {
++ .func = 2,
++ .port = hsu_port1,
++ },
++ [3] = {
++ .func = 3,
++ .port = hsu_port2,
++ },
++ },
++};
++
++static void hsu_port_enable(int port)
++{
++ struct hsu_port_pin_cfg *info = hsu_port_gpio_mux + port;
++
++ if (info->rx_gpio) {
++ lnw_gpio_set_alt(info->rx_gpio, info->rx_alt);
++ gpio_direction_input(info->rx_gpio);
++ }
++ if (info->tx_gpio) {
++ gpio_direction_output(info->tx_gpio, 1);
++ lnw_gpio_set_alt(info->tx_gpio, info->tx_alt);
++ usleep_range(10, 10);
++ gpio_direction_output(info->tx_gpio, 0);
++
++ }
++ if (info->cts_gpio) {
++ lnw_gpio_set_alt(info->cts_gpio, info->cts_alt);
++ gpio_direction_input(info->cts_gpio);
++ }
++ if (info->rts_gpio) {
++ gpio_direction_output(info->rts_gpio, 0);
++ lnw_gpio_set_alt(info->rts_gpio, info->rts_alt);
++ }
++}
++
++static void hsu_port_disable(int port)
++{
++ struct hsu_port_pin_cfg *info = hsu_port_gpio_mux + port;
++
++ if (info->rx_gpio) {
++ lnw_gpio_set_alt(info->rx_gpio, LNW_GPIO);
++ gpio_direction_input(info->rx_gpio);
++ }
++ if (info->tx_gpio) {
++ gpio_direction_output(info->tx_gpio, 1);
++ lnw_gpio_set_alt(info->tx_gpio, LNW_GPIO);
++ usleep_range(10, 10);
++ gpio_direction_input(info->tx_gpio);
++ }
++ if (info->cts_gpio) {
++ lnw_gpio_set_alt(info->cts_gpio, LNW_GPIO);
++ gpio_direction_input(info->cts_gpio);
++ }
++ if (info->rts_gpio) {
++ lnw_gpio_set_alt(info->rts_gpio, LNW_GPIO);
++ gpio_direction_input(info->rts_gpio);
++ }
++}
++
++void intel_mid_hsu_suspend(int port, struct device *dev,
++ irq_handler_t wake_isr)
++{
++ int ret;
++ struct hsu_port_pin_cfg *info = hsu_port_gpio_mux + port;
++
++ info->dev = dev;
++ info->wake_isr = wake_isr;
++
++ if (info->wake_gpio) {
++ lnw_gpio_set_alt(info->wake_gpio, LNW_GPIO);
++ gpio_direction_input(info->wake_gpio);
++ udelay(10);
++ ret = request_irq(gpio_to_irq(info->wake_gpio), info->wake_isr,
++ IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING,
++ info->name, info->dev);
++ if (ret)
++ dev_err(info->dev, "failed to register wakeup irq\n");
++ }
++}
++
++void intel_mid_hsu_resume(int port, struct device *dev)
++{
++ struct hsu_port_pin_cfg *info = hsu_port_gpio_mux + port;
++
++ if (info->wake_gpio)
++ free_irq(gpio_to_irq(info->wake_gpio), info->dev);
++
++ if (info->rx_gpio) {
++ lnw_gpio_set_alt(info->rx_gpio, info->rx_alt);
++ gpio_direction_input(info->rx_gpio);
++ }
++ if (info->tx_gpio) {
++ gpio_direction_output(info->tx_gpio, 1);
++ lnw_gpio_set_alt(info->tx_gpio, info->tx_alt);
++ usleep_range(10, 10);
++ gpio_direction_output(info->tx_gpio, 0);
++
++ }
++ if (info->cts_gpio) {
++ lnw_gpio_set_alt(info->cts_gpio, info->cts_alt);
++ gpio_direction_input(info->cts_gpio);
++ }
++}
++
++void intel_mid_hsu_switch(int port)
++{
++ int i;
++ struct hsu_port_pin_cfg *tmp;
++ struct hsu_port_pin_cfg *info = hsu_port_gpio_mux + port;
++
++ for (i = 0; i < hsu_port_max; i++) {
++ tmp = hsu_port_gpio_mux + i;
++ if (tmp != info && tmp->id == info->id)
++ hsu_port_disable(i);
++ }
++ hsu_port_enable(port);
++}
++
++void intel_mid_hsu_rts(int port, int value)
++{
++ struct hsu_port_pin_cfg *info = hsu_port_gpio_mux + port;
++
++ if (!info->rts_gpio)
++ return;
++
++ if (value) {
++ gpio_direction_output(info->rts_gpio, 1);
++ lnw_gpio_set_alt(info->rts_gpio, LNW_GPIO);
++ } else
++ lnw_gpio_set_alt(info->rts_gpio, info->rts_alt);
++}
++
++void intel_mid_hsu_suspend_post(int port)
++{
++ struct hsu_port_pin_cfg *info = hsu_port_gpio_mux + port;
++
++ if (info->rts_gpio && info->wake_gpio
++ && info->wake_gpio == info->rx_gpio) {
++ gpio_direction_output(info->rts_gpio, 0);
++ lnw_gpio_set_alt(info->rts_gpio, LNW_GPIO);
++ }
++}
++
++void intel_mid_hsu_set_clk(unsigned int m, unsigned int n,
++ void __iomem *addr)
++{
++ unsigned int param, update_bit;
++
++ update_bit = 1 << 31;
++ param = (m << 1) | (n << 16) | 0x1;
++
++ writel(param, addr + VLV_HSU_CLOCK);
++ writel((param | update_bit), addr + VLV_HSU_CLOCK);
++ writel(param, addr + VLV_HSU_CLOCK);
++}
++
++void intel_mid_hsu_reset(void __iomem *addr)
++{
++ writel(0, addr + VLV_HSU_RESET);
++ writel(3, addr + VLV_HSU_RESET);
++}
++
++unsigned int intel_mid_hsu_get_clk(void)
++{
++ return clock;
++}
++
++int intel_mid_hsu_func_to_port(unsigned int func)
++{
++ int i;
++ struct hsu_func2port *tbl = NULL;
++
++ switch (intel_mid_identify_cpu()) {
++ case INTEL_MID_CPU_CHIP_TANGIER:
++ tbl = &hsu_port_func_id_tlb[hsu_tng][0];
++ break;
++ default:
++ /* FIXME: VALLEYVIEW2? */
++ /* 1e.3 and 1e.4 */
++ tbl = &hsu_port_func_id_tlb[hsu_vlv2][0];
++ break;
++ }
++
++ for (i = 0; i < hsu_port_func_max; i++) {
++ if (tbl->func == func)
++ return tbl->port;
++ tbl++;
++ }
++
++ return -1;
++}
++
++int intel_mid_hsu_init(struct device *dev, int port)
++{
++ struct hsu_port_cfg *port_cfg = platform_hsu_info + port;
++ struct hsu_port_pin_cfg *info;
++
++ if (port >= hsu_port_max)
++ return -ENODEV;
++
++ port_cfg->dev = dev;
++
++ info = hsu_port_gpio_mux + port;
++ if (info->wake_gpio) {
++ gpio_request(info->wake_gpio, "hsu");
++ }
++ if (info->rx_gpio) {
++ gpio_request(info->rx_gpio, "hsu");
++ gpio_export(info->rx_gpio, 1);
++ }
++ if (info->tx_gpio) {
++ gpio_request(info->tx_gpio, "hsu");
++ gpio_export(info->tx_gpio, 1);
++ }
++ if (info->cts_gpio) {
++ gpio_request(info->cts_gpio, "hsu");
++ gpio_export(info->cts_gpio, 1);
++ }
++ if (info->rts_gpio) {
++ gpio_request(info->rts_gpio, "hsu");
++ gpio_export(info->rts_gpio, 1);
++ }
++
++ return 1;
++}
++
++static void hsu_platform_clk(enum intel_mid_cpu_type cpu_type)
++{
++ void __iomem *clkctl, *clksc;
++ u32 clk_src, clk_div;
++
++ switch (cpu_type) {
++ case INTEL_MID_CPU_CHIP_TANGIER:
++ clock = 100000;
++ clkctl = ioremap_nocache(TNG_CLOCK_CTL, 4);
++ if (!clkctl) {
++ pr_err("tng scu clk ctl ioremap error\n");
++ break;
++ }
++
++ clksc = ioremap_nocache(TNG_CLOCK_SC, 4);
++ if (!clksc) {
++ pr_err("tng scu clk sc ioremap error\n");
++ iounmap(clkctl);
++ break;
++ }
++
++ clk_src = readl(clkctl);
++ clk_div = readl(clksc);
++
++ if (clk_src & (1 << 16))
++ /* source SCU fabric 100M */
++ clock = clock / ((clk_div & 0x7) + 1);
++ else {
++ if (clk_src & (1 << 31))
++ /* source OSCX2 38.4M */
++ clock = 38400;
++ else
++ /* source OSC clock 19.2M */
++ clock = 19200;
++ }
++
++ iounmap(clkctl);
++ iounmap(clksc);
++ break;
++
++ default:
++ /* FIXME: VALLEYVIEW2? */
++ clock = 100000;
++ break;
++ }
++
++ pr_info("hsu core clock %u M\n", clock / 1000);
++}
++
++static __init int hsu_dev_platform_data(void)
++{
++ switch (intel_mid_identify_cpu()) {
++ case INTEL_MID_CPU_CHIP_TANGIER:
++ platform_hsu_info = &hsu_port_cfgs[hsu_tng][0];
++ hsu_port_gpio_mux = &hsu_port_pin_cfgs[hsu_tng][hsu_pid_def][0];
++ break;
++ default:
++ platform_hsu_info = NULL;
++ hsu_port_gpio_mux = NULL;
++ break;
++ }
++
++ if (platform_hsu_info == NULL)
++ return -ENODEV;
++
++ if (hsu_port_gpio_mux == NULL)
++ return -ENODEV;
++
++ hsu_register_board_info(platform_hsu_info);
++ hsu_platform_clk(intel_mid_identify_cpu());
++
++ return 0;
++}
++
++fs_initcall(hsu_dev_platform_data);
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_hsu.h b/arch/x86/platform/intel-mid/device_libs/platform_hsu.h
+new file mode 100644
+index 0000000..1a0182c
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_hsu.h
+@@ -0,0 +1,56 @@
++/*
++ * platform_hsu.h: hsu platform data header file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_HSU_H_
++#define _PLATFORM_HSU_H_
++
++#define HSU_BT_PORT "hsu_bt_port"
++#define HSU_MODEM_PORT "hsu_modem_port"
++#define HSU_GPS_PORT "hsu_gps_port"
++#define HSU_DEBUG_PORT "hsu_debug_port"
++
++enum hsu_core {
++ hsu_pnw,
++ hsu_clv,
++ hsu_tng,
++ hsu_vlv2,
++};
++
++enum hsu_pid {
++ hsu_pid_def = 0,
++ hsu_pid_rhb = 0,
++ hsu_pid_vtb_pro = 1,
++ hsu_pid_vtb_eng = 2,
++ hsu_pid_max,
++};
++
++struct hsu_func2port {
++ int func;
++ int port;
++};
++
++struct hsu_port_pin_cfg {
++ char *name;
++ int id;
++ int wake_gpio;
++ int rx_gpio;
++ int rx_alt;
++ int tx_gpio;
++ int tx_alt;
++ int cts_gpio;
++ int cts_alt;
++ int rts_gpio;
++ int rts_alt;
++ struct device *dev;
++ irq_handler_t wake_isr;
++};
++
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_ipc.c b/arch/x86/platform/intel-mid/device_libs/platform_ipc.c
+new file mode 100644
+index 0000000..5a71b82
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_ipc.c
+@@ -0,0 +1,38 @@
++/*
++ * platform_ipc.c: IPC platform library file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/sfi.h>
++#include <linux/gpio.h>
++#include <asm/intel-mid.h>
++#include "platform_ipc.h"
++
++void ipc_device_handler(struct sfi_device_table_entry *pentry,
++ struct devs_id *dev) {
++ void *pdata = NULL;
++ /*
++ * IPC device creation is handled by the MSIC
++ * MFD driver so we don't need to do it here.
++ */
++
++ /*
++ * We need to call platform init of IPC devices to fill
++ * misc_pdata structure. It will be used in msic_init for
++ * initialization.
++ */
++ pr_info("IPC bus, name = %16.16s, irq = 0x%2x\n",
++ pentry->name, pentry->irq);
++ if (dev != NULL)
++ pdata = dev->get_platform_data(pentry);
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_ipc.h b/arch/x86/platform/intel-mid/device_libs/platform_ipc.h
+new file mode 100644
+index 0000000..984b549
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_ipc.h
+@@ -0,0 +1,17 @@
++/*
++ * platform_ipc.h: IPC platform library header file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_IPC_H_
++#define _PLATFORM_IPC_H_
++
++extern void ipc_device_handler(struct sfi_device_table_entry *pentry,
++ struct devs_id *dev) __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_lis331.c b/arch/x86/platform/intel-mid/device_libs/platform_lis331.c
+new file mode 100644
+index 0000000..05536ea
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_lis331.c
+@@ -0,0 +1,32 @@
++/*
++ * platform_lis331.c: lis331 platform data initilization file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/i2c.h>
++#include <linux/gpio.h>
++#include <asm/intel-mid.h>
++#include "platform_lis331.h"
++
++void __init *lis331dl_platform_data(void *info)
++{
++ static short intr2nd_pdata;
++ struct i2c_board_info *i2c_info = info;
++ int intr = get_gpio_by_name("accel_int");
++ int intr2nd = get_gpio_by_name("accel_2");
++
++ if (intr == -1 || intr2nd == -1)
++ return NULL;
++
++ i2c_info->irq = intr + INTEL_MID_IRQ_OFFSET;
++ intr2nd_pdata = intr2nd + INTEL_MID_IRQ_OFFSET;
++
++ return &intr2nd_pdata;
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_lis331.h b/arch/x86/platform/intel-mid/device_libs/platform_lis331.h
+new file mode 100644
+index 0000000..37fbe0c
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_lis331.h
+@@ -0,0 +1,16 @@
++/*
++ * platform_lis331.h: lis331 platform data header file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_LIS331_H_
++#define _PLATFORM_LIS331_H_
++
++extern void __init *lis331dl_platform_data(void *info) __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_max3111.c b/arch/x86/platform/intel-mid/device_libs/platform_max3111.c
+new file mode 100644
+index 0000000..cf6b88b
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_max3111.c
+@@ -0,0 +1,61 @@
++/*
++ * platform_max3111.c: max3111 platform data initilization file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/gpio.h>
++#include <linux/spi/spi.h>
++#include <linux/lnw_gpio.h>
++#include <linux/serial_max3110.h>
++#include <linux/spi/intel_mid_ssp_spi.h>
++#include <asm/intel-mid.h>
++#include "platform_max3111.h"
++
++static struct intel_mid_ssp_spi_chip chip = {
++ .burst_size = DFLT_FIFO_BURST_SIZE,
++ .timeout = DFLT_TIMEOUT_VAL,
++ /* UART DMA is not supported in VP */
++ .dma_enabled = false,
++};
++
++void __init *max3111_platform_data(void *info)
++{
++ struct spi_board_info *spi_info = info;
++ int intr;
++ static struct plat_max3110 max3110_pdata;
++
++ spi_info->mode = SPI_MODE_0;
++
++ /* max 3110 interrupt not supported by sim platforms */
++ if (intel_mid_identify_sim()) {
++ spi_info->controller_data = &chip;
++ spi_info->bus_num = FORCE_SPI_BUS_NUM;
++ return &max3110_pdata;
++ }
++
++ spi_info->controller_data = &chip;
++ spi_info->bus_num = FORCE_SPI_BUS_NUM;
++
++ /* use fast_int_1 (IRQ 41) on MRFL */
++ max3110_pdata.irq_edge_triggered = 0;
++
++ /*force polling for HVP and VP simulation platforms
++ * on TANGIER AND ANNIEDALE.
++ */
++ if ((intel_mid_identify_sim() == INTEL_MID_CPU_SIMULATION_VP) ||
++ (intel_mid_identify_sim() == INTEL_MID_CPU_SIMULATION_HVP)) {
++ if ((intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER) ||
++ (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_ANNIEDALE)) {
++ spi_info->irq = 0;
++ }
++ }
++
++ return &max3110_pdata;
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_max3111.h b/arch/x86/platform/intel-mid/device_libs/platform_max3111.h
+new file mode 100644
+index 0000000..fe2c361
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_max3111.h
+@@ -0,0 +1,20 @@
++/*
++ * platform_max3111.h: max3111 platform data header file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_MAX3111_H_
++#define _PLATFORM_MAX3111_H_
++
++/* REVERT ME workaround[MRFL] for invalid bus number in IAFW .25 */
++#define FORCE_SPI_BUS_NUM 5
++#define FORCE_CHIP_SELECT 0
++
++extern void *max3111_platform_data(void *info) __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_max7315.c b/arch/x86/platform/intel-mid/device_libs/platform_max7315.c
+new file mode 100644
+index 0000000..b682f0a
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_max7315.c
+@@ -0,0 +1,64 @@
++/*
++ * platform_max7315.c: max7315 platform data initilization file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/init.h>
++#include <linux/gpio.h>
++#include <linux/i2c.h>
++#include <linux/i2c/pca953x.h>
++#include <asm/intel-mid.h>
++#include "platform_max7315.h"
++
++
++void __init *max7315_platform_data(void *info)
++{
++ static struct pca953x_platform_data max7315_pdata[MAX7315_NUM];
++ static int nr;
++ struct pca953x_platform_data *max7315 = &max7315_pdata[nr];
++ struct i2c_board_info *i2c_info = info;
++ int gpio_base, intr;
++ char base_pin_name[SFI_NAME_LEN + 1];
++ char intr_pin_name[SFI_NAME_LEN + 1];
++
++ if (nr >= MAX7315_NUM) {
++ pr_err("too many max7315s, we only support %d\n",
++ MAX7315_NUM);
++ return NULL;
++ }
++ /* we have several max7315 on the board, we only need load several
++ * instances of the same pca953x driver to cover them
++ */
++ strcpy(i2c_info->type, "max7315");
++ if (nr++) {
++ snprintf(base_pin_name, sizeof(base_pin_name),
++ "max7315_%d_base", nr);
++ snprintf(intr_pin_name, sizeof(intr_pin_name),
++ "max7315_%d_int", nr);
++ } else {
++ strcpy(base_pin_name, "max7315_base");
++ strcpy(intr_pin_name, "max7315_int");
++ }
++
++ gpio_base = get_gpio_by_name(base_pin_name);
++ intr = get_gpio_by_name(intr_pin_name);
++
++ if (gpio_base == -1)
++ return NULL;
++ max7315->gpio_base = gpio_base;
++ if (intr != -1) {
++ i2c_info->irq = intr + INTEL_MID_IRQ_OFFSET;
++ max7315->irq_base = gpio_base + INTEL_MID_IRQ_OFFSET;
++ } else {
++ i2c_info->irq = -1;
++ max7315->irq_base = -1;
++ }
++ return max7315;
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_max7315.h b/arch/x86/platform/intel-mid/device_libs/platform_max7315.h
+new file mode 100644
+index 0000000..d62daa5
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_max7315.h
+@@ -0,0 +1,19 @@
++/*
++ * platform_max7315.h: max7315 platform data header file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_MAX7315_H_
++#define _PLATFORM_MAX7315_H_
++
++/* we have multiple max7315 on the board ... */
++#define MAX7315_NUM 2
++
++extern void __init *max7315_platform_data(void *info) __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_mid_pwm.c b/arch/x86/platform/intel-mid/device_libs/platform_mid_pwm.c
+new file mode 100644
+index 0000000..c184fed
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_mid_pwm.c
+@@ -0,0 +1,121 @@
++/*
++ * platform_mid_pwm.c: mid_pwm platform data initilization file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/input.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/gpio.h>
++#include <linux/platform_device.h>
++#include <linux/lnw_gpio.h>
++
++#include <asm/intel-mid.h>
++#include <asm/intel_mid_pwm.h>
++#include <asm/intel_mid_remoteproc.h>
++
++#include "platform_mid_pwm.h"
++
++static struct intel_mid_pwm_device_data mfld_pwms[] = {
++ [PWM_LED] = {
++ .reg_clkdiv0 = 0x62,
++ .reg_clkdiv1 = 0x61,
++ .reg_dutycyc = 0x67,
++ .val_clkdiv1 = 0x00,
++ .val_clkdiv0 = 0x03,
++ },
++ [PWM_VIBRATOR] = {
++ .reg_clkdiv0 = 0x64,
++ .reg_clkdiv1 = 0x63,
++ .reg_dutycyc = 0x68,
++ .val_clkdiv1 = 0x00,
++ .val_clkdiv0 = 0x03,
++ },
++ [PWM_LCD_BACKLIGHT] = {
++ .reg_clkdiv0 = 0x66,
++ .reg_clkdiv1 = 0x65,
++ .reg_dutycyc = 0x69,
++ .val_clkdiv1 = 0x00,
++ .val_clkdiv0 = 0x03,
++ },
++};
++
++static struct intel_mid_pwm_device_data ctp_pwms[] = {
++ [PWM_LED] = {
++ .reg_clkdiv0 = 0x62,
++ .reg_clkdiv1 = 0x61,
++ .reg_dutycyc = 0x67,
++ .val_clkdiv1 = 0x00,
++ .val_clkdiv0 = 0x00,
++ },
++ [PWM_VIBRATOR] = {
++ .reg_clkdiv0 = 0x64,
++ .reg_clkdiv1 = 0x63,
++ .reg_dutycyc = 0x68,
++ .val_clkdiv1 = 0x00,
++ .val_clkdiv0 = 0x03,
++ },
++ [PWM_LCD_BACKLIGHT] = {
++ .reg_clkdiv0 = 0x66,
++ .reg_clkdiv1 = 0x65,
++ .reg_dutycyc = 0x69,
++ .val_clkdiv1 = 0x00,
++ .val_clkdiv0 = 0x03,
++ },
++};
++
++static struct intel_mid_pwm_platform_data pdata[] = {
++ [mfld_pwm] = {
++ .pwm_num = PWM_NUM,
++ .ddata = mfld_pwms,
++ .reg_clksel = 0x38F,
++ .val_clksel = 0x01,
++ },
++ [ctp_pwm] = {
++ .pwm_num = PWM_NUM,
++ .ddata = ctp_pwms,
++ .reg_clksel = 0x38F,
++ .val_clksel = 0x00,
++ },
++};
++
++static void *get_pwm_platform_data(void)
++{
++ pr_info("%s, MFLD board detected\n", __func__);
++ return &pdata[mfld_pwm];
++}
++
++static int __init intel_mid_pwm_init(void)
++{
++ struct platform_device *pdev = NULL;
++ int ret = 0;
++
++ pdev = platform_device_alloc(DEVICE_NAME, -1);
++
++ if (!pdev) {
++ pr_err("out of memory for platform dev %s\n",
++ DEVICE_NAME);
++ return -1;
++ }
++
++ pdev->dev.platform_data = get_pwm_platform_data();
++
++ ret = platform_device_add(pdev);
++ if (ret) {
++ pr_err("failed to add platform device %s\n",
++ DEVICE_NAME);
++ platform_device_put(pdev);
++ return -1;
++ }
++
++ return 0;
++}
++
++fs_initcall(intel_mid_pwm_init);
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_mid_pwm.h b/arch/x86/platform/intel-mid/device_libs/platform_mid_pwm.h
+new file mode 100644
+index 0000000..fb9a26c
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_mid_pwm.h
+@@ -0,0 +1,21 @@
++/*
++ * platform_mid_pwm.h: mid_pwm platform data header file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_MID_PWM_H_
++#define _PLATFORM_MID_PWM_H_
++
++#define DEVICE_NAME "intel_mid_pwm"
++
++enum {
++ mfld_pwm,
++ ctp_pwm,
++};
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_mpu3050.c b/arch/x86/platform/intel-mid/device_libs/platform_mpu3050.c
+new file mode 100644
+index 0000000..715274f
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_mpu3050.c
+@@ -0,0 +1,28 @@
++/*
++ * platform_mpu3050.c: mpu3050 platform data initilization file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/gpio.h>
++#include <linux/i2c.h>
++#include <asm/intel-mid.h>
++#include "platform_mpu3050.h"
++
++void *mpu3050_platform_data(void *info)
++{
++ struct i2c_board_info *i2c_info = info;
++ int intr = get_gpio_by_name("mpu3050_int");
++
++ if (intr == -1)
++ return NULL;
++
++ i2c_info->irq = intr + INTEL_MID_IRQ_OFFSET;
++ return NULL;
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_mpu3050.h b/arch/x86/platform/intel-mid/device_libs/platform_mpu3050.h
+new file mode 100644
+index 0000000..c324c16
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_mpu3050.h
+@@ -0,0 +1,16 @@
++/*
++ * platform_mpu3050.h: mpu3050 platform data header file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_MPU3050_H_
++#define _PLATFORM_MPU3050_H_
++
++extern void *mpu3050_platform_data(void *info) __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_mrfl_ocd.c b/arch/x86/platform/intel-mid/device_libs/platform_mrfl_ocd.c
+new file mode 100644
+index 0000000..a179255
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_mrfl_ocd.c
+@@ -0,0 +1,68 @@
++/*
++ * platform_mrfl_ocd.c: Platform data for Merrifield Platform OCD Driver
++ *
++ * (C) Copyright 2013 Intel Corporation
++ * Author: Saranya Gopal <saranya.gopal@intel.com>
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <asm/intel-mid.h>
++#include <asm/intel_mid_remoteproc.h>
++#include <asm/intel_scu_ipc.h>
++#include <asm/intel_basincove_ocd.h>
++
++#include "platform_msic.h"
++#include "platform_mrfl_ocd.h"
++
++static int get_bcu_config(struct ocd_bcove_config_data *ocd_smip_data)
++{
++ int i;
++ void __iomem *bcu_smip_sram_addr;
++ u8 *plat_smip_data;
++
++ if (!ocd_smip_data)
++ return -ENXIO;
++
++ plat_smip_data = (u8 *)ocd_smip_data;
++ bcu_smip_sram_addr = ioremap_nocache(MRFL_SMIP_SRAM_ADDR +
++ BCU_SMIP_OFFSET, NUM_SMIP_BYTES);
++
++ for (i = 0; i < NUM_SMIP_BYTES; i++)
++ *(plat_smip_data + i) = ioread8(bcu_smip_sram_addr + i);
++
++ return 0;
++}
++
++static struct ocd_platform_data ocd_data;
++
++void __init *mrfl_ocd_platform_data(void *info)
++{
++ struct sfi_device_table_entry *entry = info;
++ struct platform_device *pdev;
++
++ pdev = platform_device_alloc(MRFL_OCD_DEV_NAME, -1);
++ if (!pdev) {
++ pr_err("out of memory for SFI platform dev %s\n",
++ MRFL_OCD_DEV_NAME);
++ return NULL;
++ }
++
++ if (platform_device_add(pdev)) {
++ pr_err("failed to add merrifield ocd platform device\n");
++ platform_device_put(pdev);
++ return NULL;
++ }
++
++ install_irq_resource(pdev, entry->irq);
++ ocd_data.bcu_config_data = &get_bcu_config;
++ pdev->dev.platform_data = &ocd_data;
++ register_rpmsg_service("rpmsg_mrfl_ocd", RPROC_SCU, RP_MRFL_OCD);
++
++ return &ocd_data;
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_mrfl_ocd.h b/arch/x86/platform/intel-mid/device_libs/platform_mrfl_ocd.h
+new file mode 100644
+index 0000000..d817e7d
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_mrfl_ocd.h
+@@ -0,0 +1,19 @@
++/*
++ * platform_mrfl_ocd.h: msic_thermal platform data header file
++ *
++ * (C) Copyright 2013 Intel Corporation
++ * Author: Saranya Gopal <saranya.gopal@intel.com>
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_MRFL_OCD_H_
++#define _PLATFORM_MRFL_OCD_H_
++
++#define MRFL_OCD_DEV_NAME "bcove_bcu"
++
++extern void __init *mrfl_ocd_platform_data(void *info)
++ __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_mrfl_pmic.c b/arch/x86/platform/intel-mid/device_libs/platform_mrfl_pmic.c
+new file mode 100644
+index 0000000..9f69867
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_mrfl_pmic.c
+@@ -0,0 +1,54 @@
++/*
++ * platform_mrfl_pmic.c: Platform data for Merrifield PMIC driver
++ *
++ * (C) Copyright 2012 Intel Corporation
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/scatterlist.h>
++#include <linux/init.h>
++#include <linux/sfi.h>
++#include <asm/intel-mid.h>
++#include <asm/pmic_pdata.h>
++#include <asm/intel_mid_remoteproc.h>
++#include <linux/power/bq24261_charger.h>
++
++#include "platform_ipc.h"
++#include "platform_mrfl_pmic.h"
++
++void __init *mrfl_pmic_ccsm_platform_data(void *info)
++{
++ struct sfi_device_table_entry *entry = info;
++ static struct pmic_platform_data pmic_pdata;
++ struct platform_device *pdev = NULL;
++ int ret;
++
++ pdev = platform_device_alloc(entry->name, -1);
++ if (!pdev) {
++ pr_err("Out of memory for SFI platform dev %s\n", entry->name);
++ goto out;
++ }
++ pdev->dev.platform_data = &pmic_pdata;
++ ret = platform_device_add(pdev);
++ if (ret) {
++ pr_err("Failed to add adc platform device\n");
++ platform_device_put(pdev);
++ goto out;
++ }
++ install_irq_resource(pdev, entry->irq);
++#ifdef CONFIG_BQ24261_CHARGER
++ pmic_pdata.cc_to_reg = bq24261_cc_to_reg;
++ pmic_pdata.cv_to_reg = bq24261_cv_to_reg;
++#endif
++ register_rpmsg_service("rpmsg_pmic_ccsm", RPROC_SCU,
++ RP_PMIC_CCSM);
++out:
++ return &pmic_pdata;
++}
++
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_mrfl_pmic.h b/arch/x86/platform/intel-mid/device_libs/platform_mrfl_pmic.h
+new file mode 100644
+index 0000000..5eb3ed5
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_mrfl_pmic.h
+@@ -0,0 +1,17 @@
++/*
++ * platform_mrfl_pmic.h: platform data for pmic driver
++ *
++ * (C) Copyright 2012 Intel Corporation
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_MRFL_PMIC_H_
++#define _PLATFORM_MRFL_PMIC_H_
++
++extern void __init *mrfl_pmic_ccsm_platform_data(
++ void *info) __attribute__((weak));
++
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_mrfl_pmic_i2c.c b/arch/x86/platform/intel-mid/device_libs/platform_mrfl_pmic_i2c.c
+new file mode 100644
+index 0000000..c6ad12b
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_mrfl_pmic_i2c.c
+@@ -0,0 +1,49 @@
++/*
++ * platform_mrfl_pmic_i2c.c: Platform data for Merrifield PMIC I2C
++ * adapter driver.
++ *
++ * (C) Copyright 2012 Intel Corporation
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/scatterlist.h>
++#include <linux/init.h>
++#include <linux/sfi.h>
++#include <asm/intel-mid.h>
++#include <asm/pmic_pdata.h>
++#include <asm/intel_mid_remoteproc.h>
++#include <linux/power/bq24261_charger.h>
++
++#include "platform_ipc.h"
++#include "platform_mrfl_pmic_i2c.h"
++
++void __init *mrfl_pmic_i2c_platform_data(void *info)
++{
++ struct sfi_device_table_entry *entry = info;
++ struct platform_device *pdev = NULL;
++ int ret;
++
++ pdev = platform_device_alloc(entry->name, -1);
++ if (!pdev) {
++ pr_err("Out of memory for SFI platform dev %s\n", entry->name);
++ goto out;
++ }
++ pdev->dev.platform_data = NULL;
++ ret = platform_device_add(pdev);
++ if (ret) {
++ pr_err("Failed to add adc platform device\n");
++ platform_device_put(pdev);
++ goto out;
++ }
++ install_irq_resource(pdev, entry->irq);
++ register_rpmsg_service("rpmsg_i2c_pmic_adap", RPROC_SCU,
++ RP_PMIC_I2C);
++out:
++ return NULL;
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_mrfl_pmic_i2c.h b/arch/x86/platform/intel-mid/device_libs/platform_mrfl_pmic_i2c.h
+new file mode 100644
+index 0000000..3034a7f
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_mrfl_pmic_i2c.h
+@@ -0,0 +1,17 @@
++/*
++ * platform_mrfl_pmic_i2c.h: platform data for pmic i2c adapter driver
++ *
++ * (C) Copyright 2012 Intel Corporation
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_MRFL_PMIC_I2C_H_
++#define _PLATFORM_MRFL_PMIC_I2C_H_
++
++extern void __init *mrfl_pmic_i2c_platform_data(
++ void *info) __attribute__((weak));
++
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_mrfl_regulator.c b/arch/x86/platform/intel-mid/device_libs/platform_mrfl_regulator.c
+new file mode 100644
+index 0000000..f7d38fa
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_mrfl_regulator.c
+@@ -0,0 +1,125 @@
++/*
++ * platform_mrfl_regulator.c - Merrifield regulator machine drvier
++ * Copyright (c) 2012, Intel Corporation.
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#include <linux/platform_device.h>
++#include <linux/regulator/intel_basin_cove_pmic.h>
++#include <linux/regulator/machine.h>
++
++#include <asm/intel-mid.h>
++
++/***********VPROG1 REGUATOR platform data*************/
++static struct regulator_consumer_supply vprog1_consumer[] = {
++};
++static struct regulator_init_data vprog1_data = {
++ .constraints = {
++ .min_uV = 1500000,
++ .max_uV = 2800000,
++ .valid_ops_mask = REGULATOR_CHANGE_STATUS
++ | REGULATOR_CHANGE_VOLTAGE,
++ .valid_modes_mask = REGULATOR_MODE_NORMAL,
++ },
++ .num_consumer_supplies = ARRAY_SIZE(vprog1_consumer),
++ .consumer_supplies = vprog1_consumer,
++};
++
++static struct intel_pmic_info vprog1_info = {
++ .pmic_reg = VPROG1CNT_ADDR,
++ .init_data = &vprog1_data,
++ .table_len = ARRAY_SIZE(VPROG1_VSEL_table),
++ .table = VPROG1_VSEL_table,
++};
++static struct platform_device vprog1_device = {
++ .name = "intel_regulator",
++ .id = VPROG1,
++ .dev = {
++ .platform_data = &vprog1_info,
++ },
++};
++/***********VPROG2 REGUATOR platform data*************/
++static struct regulator_consumer_supply vprog2_consumer[] = {
++};
++static struct regulator_init_data vprog2_data = {
++ .constraints = {
++ .min_uV = 1500000,
++ .max_uV = 2850000,
++ .valid_ops_mask = REGULATOR_CHANGE_STATUS
++ | REGULATOR_CHANGE_VOLTAGE,
++ .valid_modes_mask = REGULATOR_MODE_NORMAL
++ },
++ .num_consumer_supplies = ARRAY_SIZE(vprog2_consumer),
++ .consumer_supplies = vprog2_consumer,
++};
++static struct intel_pmic_info vprog2_info = {
++ .pmic_reg = VPROG2CNT_ADDR,
++ .init_data = &vprog2_data,
++ .table_len = ARRAY_SIZE(VPROG2_VSEL_table),
++ .table = VPROG2_VSEL_table,
++};
++static struct platform_device vprog2_device = {
++ .name = "intel_regulator",
++ .id = VPROG2,
++ .dev = {
++ .platform_data = &vprog2_info,
++ },
++};
++
++/***********VPROG3 REGUATOR platform data*************/
++static struct regulator_consumer_supply vprog3_consumer[] = {
++};
++static struct regulator_init_data vprog3_data = {
++ .constraints = {
++ .min_uV = 1050000,
++ .max_uV = 2800000,
++ .valid_ops_mask = REGULATOR_CHANGE_STATUS
++ | REGULATOR_CHANGE_VOLTAGE,
++ .valid_modes_mask = REGULATOR_MODE_NORMAL
++ },
++ .num_consumer_supplies = ARRAY_SIZE(vprog2_consumer),
++ .consumer_supplies = vprog3_consumer,
++};
++static struct intel_pmic_info vprog3_info = {
++ .pmic_reg = VPROG3CNT_ADDR,
++ .init_data = &vprog3_data,
++ .table_len = ARRAY_SIZE(VPROG3_VSEL_table),
++ .table = VPROG3_VSEL_table,
++};
++static struct platform_device vprog3_device = {
++ .name = "intel_regulator",
++ .id = VPROG3,
++ .dev = {
++ .platform_data = &vprog3_info,
++ },
++};
++
++static struct platform_device *regulator_devices[] __initdata = {
++ &vprog1_device,
++ &vprog2_device,
++ &vprog3_device,
++};
++
++static int __init regulator_init(void)
++{
++ /* register the regulator only if SoC is Tangier */
++ if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER)
++ platform_add_devices(regulator_devices,
++ ARRAY_SIZE(regulator_devices));
++
++ return 0;
++}
++device_initcall(regulator_init);
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_mrfl_thermal.c b/arch/x86/platform/intel-mid/device_libs/platform_mrfl_thermal.c
+new file mode 100644
+index 0000000..8e118a4
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_mrfl_thermal.c
+@@ -0,0 +1,133 @@
++/*
++ * platform_mrfl_thermal.c: Platform data initilization file for
++ * Intel Merrifield Platform thermal driver
++ *
++ * (C) Copyright 2013 Intel Corporation
++ * Author: Durgadoss R <durgadoss.r@intel.com>
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/init.h>
++#include <linux/input.h>
++#include <linux/kernel.h>
++#include <linux/mfd/intel_msic.h>
++#include <linux/platform_device.h>
++#include <asm/intel_mid_thermal.h>
++#include <asm/intel-mid.h>
++#include <asm/intel_mid_remoteproc.h>
++#include "platform_mrfl_thermal.h"
++
++/* 'enum' of Thermal ADC channels */
++enum thermal_adc_channels { SYS0, SYS1, SYS2, PMIC_DIE };
++
++static int linear_temp_correlation(void *info, long temp, long *res)
++{
++ struct intel_mid_thermal_sensor *sensor = info;
++
++ *res = ((temp * sensor->slope) / 1000) + sensor->intercept;
++
++ return 0;
++}
++
++/*
++ * Naming convention:
++ * skin0 -> front skin,
++ * skin1--> back skin
++ */
++
++static struct intel_mid_thermal_sensor mrfl_sensors[] = {
++ {
++ .name = SKIN0_NAME,
++ .index = SYS2,
++ .slope = 969,
++ .intercept = -3741,
++ .temp_correlation = linear_temp_correlation,
++ .direct = false,
++ },
++ {
++ .name = SKIN1_NAME,
++ .index = SYS0,
++ .slope = 966,
++ .intercept = -2052,
++ .temp_correlation = linear_temp_correlation,
++ .direct = false,
++ },
++ {
++ .name = MSIC_DIE_NAME,
++ .index = PMIC_DIE,
++ .slope = 1000,
++ .intercept = 0,
++ .temp_correlation = linear_temp_correlation,
++ .direct = true,
++ },
++};
++
++/* Bodegabay - PRh thermal sensor list */
++static struct intel_mid_thermal_sensor bdgb_sensors[] = {
++ {
++ .name = SKIN0_NAME,
++ .index = SYS0,
++ .slope = 410,
++ .intercept = 16808,
++ .temp_correlation = linear_temp_correlation,
++ .direct = false,
++ },
++ {
++ .name = SKIN1_NAME,
++ .index = SYS0,
++ .slope = 665,
++ .intercept = 8375,
++ .temp_correlation = linear_temp_correlation,
++ .direct = false,
++ },
++ {
++ .name = MSIC_DIE_NAME,
++ .index = PMIC_DIE,
++ .slope = 1000,
++ .intercept = 0,
++ .temp_correlation = linear_temp_correlation,
++ .direct = true,
++ },
++};
++
++static struct intel_mid_thermal_platform_data pdata[] = {
++ [mrfl_thermal] = {
++ .num_sensors = 3,
++ .sensors = mrfl_sensors,
++ },
++ [bdgb_thermal] = {
++ .num_sensors = 3,
++ .sensors = bdgb_sensors,
++ },
++};
++
++void __init *mrfl_thermal_platform_data(void *info)
++{
++ struct platform_device *pdev;
++ struct sfi_device_table_entry *entry = info;
++
++ pdev = platform_device_alloc(MRFL_THERM_DEV_NAME, -1);
++ if (!pdev) {
++ pr_err("out of memory for SFI platform dev %s\n",
++ MRFL_THERM_DEV_NAME);
++ return NULL;
++ }
++
++ if (platform_device_add(pdev)) {
++ pr_err("failed to add thermal platform device\n");
++ platform_device_put(pdev);
++ return NULL;
++ }
++
++ pdev->dev.platform_data = &pdata[mrfl_thermal];
++
++ install_irq_resource(pdev, entry->irq);
++ register_rpmsg_service("rpmsg_mrfl_thermal", RPROC_SCU,
++ RP_BCOVE_THERMAL);
++
++ return 0;
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_mrfl_thermal.h b/arch/x86/platform/intel-mid/device_libs/platform_mrfl_thermal.h
+new file mode 100644
+index 0000000..f1011a1
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_mrfl_thermal.h
+@@ -0,0 +1,26 @@
++/*
++ * platform_mrfl_thermal.h: Platform data initilization file for
++ * Intel Merrifield Platform thermal driver
++ *
++ * (C) Copyright 2013 Intel Corporation
++ * Author: Durgadoss R <durgadoss.r@intel.com>
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_MRFL_THERMAL_H_
++#define _PLATFORM_MRFL_THERMAL_H_
++
++#define MRFL_THERM_DEV_NAME "bcove_thrm"
++
++extern void __init *mrfl_thermal_platform_data(void *)
++ __attribute__((weak));
++
++enum {
++ mrfl_thermal,
++ bdgb_thermal,
++};
++
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_msic.c b/arch/x86/platform/intel-mid/device_libs/platform_msic.c
+new file mode 100644
+index 0000000..a601f2c
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_msic.c
+@@ -0,0 +1,92 @@
++/*
++ * platform_msic.c: MSIC platform data initilization file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/scatterlist.h>
++#include <linux/init.h>
++#include <linux/sfi.h>
++#include <linux/mfd/intel_msic.h>
++#include <asm/intel_scu_ipc.h>
++#include <asm/intel-mid.h>
++#include "platform_msic.h"
++
++struct intel_msic_platform_data msic_pdata;
++
++static struct resource msic_resources[] = {
++ {
++ .start = INTEL_MSIC_IRQ_PHYS_BASE,
++ .end = INTEL_MSIC_IRQ_PHYS_BASE + 64 - 1,
++ .flags = IORESOURCE_MEM,
++ },
++};
++
++static struct platform_device msic_device = {
++ .name = "intel_msic",
++ .id = -1,
++ .dev = {
++ .platform_data = &msic_pdata,
++ },
++ .num_resources = ARRAY_SIZE(msic_resources),
++ .resource = msic_resources,
++};
++
++inline bool intel_mid_has_msic(void)
++{
++ return (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_PENWELL);
++}
++
++static int msic_scu_status_change(struct notifier_block *nb,
++ unsigned long code, void *data)
++{
++ if (code == SCU_DOWN) {
++ platform_device_unregister(&msic_device);
++ return 0;
++ }
++
++ return platform_device_register(&msic_device);
++}
++
++static int __init msic_init(void)
++{
++ static struct notifier_block msic_scu_notifier = {
++ .notifier_call = msic_scu_status_change,
++ };
++
++ /*
++ * We need to be sure that the SCU IPC is ready before MSIC device
++ * can be registered.
++ */
++ if (intel_mid_has_msic())
++ intel_scu_notifier_add(&msic_scu_notifier);
++
++ return 0;
++}
++arch_initcall(msic_init);
++
++/*
++ * msic_generic_platform_data - sets generic platform data for the block
++ * @info: pointer to the SFI device table entry for this block
++ * @block: MSIC block
++ *
++ * Function sets IRQ number from the SFI table entry for given device to
++ * the MSIC platform data.
++ */
++void *msic_generic_platform_data(void *info, enum intel_msic_block block)
++{
++ struct sfi_device_table_entry *entry = info;
++
++ BUG_ON(block < 0 || block >= INTEL_MSIC_BLOCK_LAST);
++ msic_pdata.irq[block] = entry->irq;
++
++ return NULL;
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_msic.h b/arch/x86/platform/intel-mid/device_libs/platform_msic.h
+new file mode 100644
+index 0000000..6abcfc7
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_msic.h
+@@ -0,0 +1,21 @@
++/*
++ * platform_msic.h: MSIC platform data header file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_MSIC_H_
++#define _PLATFORM_MSIC_H_
++
++#include <linux/mfd/intel_msic.h>
++
++extern struct intel_msic_platform_data msic_pdata;
++
++extern void *msic_generic_platform_data(void *info,
++ enum intel_msic_block block) __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_msic_adc.c b/arch/x86/platform/intel-mid/device_libs/platform_msic_adc.c
+new file mode 100644
+index 0000000..f1ed88e
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_msic_adc.c
+@@ -0,0 +1,56 @@
++/*
++ * platform_msic_adc.c: MSIC ADC platform data initilization file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/scatterlist.h>
++#include <linux/init.h>
++#include <linux/sfi.h>
++#include <asm/intel-mid.h>
++#include <asm/intel_mid_gpadc.h>
++#include <asm/intel_mid_remoteproc.h>
++#include "platform_msic.h"
++#include "platform_msic_adc.h"
++
++void __init *msic_adc_platform_data(void *info)
++{
++ struct platform_device *pdev = NULL;
++ struct sfi_device_table_entry *entry = info;
++ static struct intel_mid_gpadc_platform_data msic_adc_pdata;
++ int ret = 0;
++
++ pdev = platform_device_alloc(ADC_DEVICE_NAME, -1);
++
++ if (!pdev) {
++ pr_err("out of memory for SFI platform dev %s\n",
++ ADC_DEVICE_NAME);
++ goto out;
++ }
++
++ msic_adc_pdata.intr = 0xffff7fc0;
++
++ pdev->dev.platform_data = &msic_adc_pdata;
++
++ ret = platform_device_add(pdev);
++ if (ret) {
++ pr_err("failed to add adc platform device\n");
++ platform_device_put(pdev);
++ goto out;
++ }
++
++ install_irq_resource(pdev, entry->irq);
++
++ register_rpmsg_service("rpmsg_msic_adc", RPROC_SCU,
++ RP_MSIC_ADC);
++out:
++ return &msic_adc_pdata;
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_msic_adc.h b/arch/x86/platform/intel-mid/device_libs/platform_msic_adc.h
+new file mode 100644
+index 0000000..8e1f901
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_msic_adc.h
+@@ -0,0 +1,18 @@
++/*
++ * platform_msic_adc.h: MSIC ADC platform data header file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_MSIC_ADC_H_
++#define _PLATFORM_MSIC_ADC_H_
++
++#define ADC_DEVICE_NAME "msic_adc"
++
++extern void __init *msic_adc_platform_data(void *info) __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_msic_audio.c b/arch/x86/platform/intel-mid/device_libs/platform_msic_audio.c
+new file mode 100644
+index 0000000..a8aadfb
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_msic_audio.c
+@@ -0,0 +1,36 @@
++/*
++ * platform_msic_audio.c: MSIC audio platform data initilization file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/scatterlist.h>
++#include <linux/init.h>
++#include <linux/sfi.h>
++#include <linux/platform_device.h>
++#include <linux/mfd/intel_msic.h>
++#include <asm/intel-mid.h>
++#include "platform_msic.h"
++#include "platform_msic_audio.h"
++
++void *msic_audio_platform_data(void *info)
++{
++ struct platform_device *pdev;
++
++ pdev = platform_device_register_simple("sst-platform", -1, NULL, 0);
++
++ if (IS_ERR(pdev)) {
++ pr_err("failed to create audio platform device\n");
++ return NULL;
++ }
++
++ return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_AUDIO);
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_msic_audio.h b/arch/x86/platform/intel-mid/device_libs/platform_msic_audio.h
+new file mode 100644
+index 0000000..1fca68f
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_msic_audio.h
+@@ -0,0 +1,16 @@
++/*
++ * platform_msic_audio.h: MSIC audio platform data header file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_MSIC_AUDIO_H_
++#define _PLATFORM_MSIC_AUDIO_H_
++
++extern void __init *msic_audio_platform_data(void *info) __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_msic_battery.c b/arch/x86/platform/intel-mid/device_libs/platform_msic_battery.c
+new file mode 100644
+index 0000000..133448b
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_msic_battery.c
+@@ -0,0 +1,26 @@
++/*
++ * platform_msic_battery.c: MSIC battery platform data initilization file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/scatterlist.h>
++#include <linux/init.h>
++#include <linux/sfi.h>
++#include <linux/mfd/intel_msic.h>
++#include <asm/intel-mid.h>
++#include "platform_msic.h"
++#include "platform_msic_battery.h"
++
++void __init *msic_battery_platform_data(void *info)
++{
++ return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_BATTERY);
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_msic_battery.h b/arch/x86/platform/intel-mid/device_libs/platform_msic_battery.h
+new file mode 100644
+index 0000000..9be705d
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_msic_battery.h
+@@ -0,0 +1,17 @@
++/*
++ * platform_msic_battery.h: MSIC battery platform data header file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_MSIC_BATTERY_H_
++#define _PLATFORM_MSIC_BATTERY_H_
++
++extern void __init *msic_battery_platform_data(void *info)
++ __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_msic_gpio.c b/arch/x86/platform/intel-mid/device_libs/platform_msic_gpio.c
+new file mode 100644
+index 0000000..1b11038
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_msic_gpio.c
+@@ -0,0 +1,79 @@
++/*
++ * platform_msic_gpio.c: MSIC GPIO platform data initilization file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/init.h>
++#include <linux/gpio.h>
++#include <linux/mfd/intel_msic.h>
++#include <asm/intel-mid.h>
++#include <linux/platform_data/intel_mid_remoteproc.h>
++#include "platform_msic.h"
++#include "platform_msic_gpio.h"
++
++void __init *msic_gpio_platform_data(void *info)
++{
++ struct platform_device *pdev = NULL;
++ struct sfi_device_table_entry *entry = info;
++ static struct intel_msic_gpio_pdata msic_gpio_pdata;
++ int ret;
++ int gpio;
++ struct resource res;
++
++ pdev = platform_device_alloc(MSIC_GPIO_DEVICE_NAME, -1);
++
++ if (!pdev) {
++ pr_err("out of memory for SFI platform dev %s\n",
++ MSIC_GPIO_DEVICE_NAME);
++ return NULL;
++ }
++
++ gpio = get_gpio_by_name("msic_gpio_base");
++
++ if (gpio < 0)
++ return NULL;
++
++ /* Basincove PMIC GPIO has total 8 GPIO pins,
++ * GPIO[5:2,0] support 1.8V, GPIO[7:6,1] support 1.8V and 3.3V,
++ * We group GPIO[5:2] to low voltage and GPIO[7:6] to
++ * high voltage. Because the CTL registers are contiguous,
++ * this grouping method doesn't affect the driver usage but
++ * easy for the driver sharing among multiple platforms.
++ */
++ msic_gpio_pdata.ngpio_lv = 6;
++ msic_gpio_pdata.ngpio_hv = 2;
++ msic_gpio_pdata.gpio0_lv_ctlo = 0x7E;
++ msic_gpio_pdata.gpio0_lv_ctli = 0x8E;
++ msic_gpio_pdata.gpio0_hv_ctlo = 0x84;
++ msic_gpio_pdata.gpio0_hv_ctli = 0x94;
++
++ msic_gpio_pdata.can_sleep = 1;
++ msic_gpio_pdata.gpio_base = gpio;
++
++ pdev->dev.platform_data = &msic_gpio_pdata;
++
++ ret = platform_device_add(pdev);
++ if (ret) {
++ pr_err("failed to add msic gpio platform device\n");
++ platform_device_put(pdev);
++ return NULL;
++ }
++
++ res.name = "IRQ",
++ res.flags = IORESOURCE_IRQ,
++ res.start = entry->irq;
++ platform_device_add_resources(pdev, &res, 1);
++
++ register_rpmsg_service("rpmsg_msic_gpio", RPROC_SCU, RP_MSIC_GPIO);
++
++ return &msic_gpio_pdata;
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_msic_gpio.h b/arch/x86/platform/intel-mid/device_libs/platform_msic_gpio.h
+new file mode 100644
+index 0000000..b78b236
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_msic_gpio.h
+@@ -0,0 +1,18 @@
++/*
++ * platform_msic_gpio.h: MSIC GPIO platform data header file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_MSIC_GPIO_H_
++#define _PLATFORM_MSIC_GPIO_H_
++
++#define MSIC_GPIO_DEVICE_NAME "msic_gpio"
++
++extern void __init *msic_gpio_platform_data(void *info) __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_msic_ocd.c b/arch/x86/platform/intel-mid/device_libs/platform_msic_ocd.c
+new file mode 100644
+index 0000000..1782389
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_msic_ocd.c
+@@ -0,0 +1,39 @@
++/*
++ * platform_msic_ocd.c: MSIC OCD platform data initilization file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/scatterlist.h>
++#include <linux/sfi.h>
++#include <linux/init.h>
++#include <linux/gpio.h>
++#include <linux/mfd/intel_msic.h>
++#include <asm/intel-mid.h>
++#include "platform_msic.h"
++#include "platform_msic_ocd.h"
++
++void __init *msic_ocd_platform_data(void *info)
++{
++ static struct intel_msic_ocd_pdata msic_ocd_pdata;
++ int gpio;
++
++ gpio = get_gpio_by_name("ocd_gpio");
++
++ if (gpio < 0)
++ return NULL;
++
++ msic_ocd_pdata.gpio = gpio;
++ msic_pdata.ocd = &msic_ocd_pdata;
++
++ return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_OCD);
++}
++
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_msic_ocd.h b/arch/x86/platform/intel-mid/device_libs/platform_msic_ocd.h
+new file mode 100644
+index 0000000..7caa13b
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_msic_ocd.h
+@@ -0,0 +1,16 @@
++/*
++ * platform_msic_ocd.h: MSIC OCD platform data header file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_MSIC_OCD_H_
++#define _PLATFORM_MSIC_OCD_H_
++
++extern void __init *msic_ocd_platform_data(void *info) __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_msic_power_btn.c b/arch/x86/platform/intel-mid/device_libs/platform_msic_power_btn.c
+new file mode 100644
+index 0000000..f745750
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_msic_power_btn.c
+@@ -0,0 +1,73 @@
++/*
++ * platform_msic_power_btn.c: MSIC power btn platform data initilization file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/scatterlist.h>
++#include <linux/sfi.h>
++#include <linux/init.h>
++#include <asm/intel-mid.h>
++#include <asm/intel_mid_powerbtn.h>
++#include <asm/intel_scu_ipc.h>
++#include <asm/intel_scu_pmic.h>
++#include "platform_msic_power_btn.h"
++#include <linux/platform_data/intel_mid_remoteproc.h>
++
++#define BCOVE_PBIRQ 0x02
++#define BCOVE_PBIRQMASK 0x0d
++
++static struct intel_msic_power_btn_platform_data msic_power_btn_pdata;
++
++static int mrfl_pb_irq_ack(struct intel_msic_power_btn_platform_data *pdata)
++{
++ intel_scu_ipc_update_register(BCOVE_PBIRQ, 0, MSIC_PWRBTNM);
++ intel_scu_ipc_update_register(BCOVE_PBIRQMASK, 0, MSIC_PWRBTNM);
++
++ return 0;
++}
++
++void __init *msic_power_btn_platform_data(void *info)
++{
++ int ret;
++ struct platform_device *pdev;
++ struct sfi_device_table_entry *entry = info;
++ struct resource res;
++
++ pdev = platform_device_alloc(INTEL_MID_POWERBTN_DEV_NAME, -1);
++ if (!pdev) {
++ pr_err("%s(): out of memory\n", __func__);
++ return NULL;
++ }
++
++ msic_power_btn_pdata.pbstat = 0xfffff61a;
++ msic_power_btn_pdata.pb_level = (1 << 4);
++ msic_power_btn_pdata.irq_lvl1_mask = 0x0c;
++ msic_power_btn_pdata.irq_ack = mrfl_pb_irq_ack;
++
++ pdev->dev.platform_data = &msic_power_btn_pdata;
++
++ ret = platform_device_add(pdev);
++ if (ret) {
++ pr_err("%s(): platform_device_add() failed\n", __func__);
++ platform_device_put(pdev);
++ return NULL;
++ }
++
++ res.name = "IRQ",
++ res.flags = IORESOURCE_IRQ,
++ res.start = entry->irq;
++ platform_device_add_resources(pdev, &res, 1);
++
++ register_rpmsg_service("rpmsg_mid_powerbtn",
++ RPROC_SCU, RP_MSIC_POWER_BTN);
++
++ return &msic_power_btn_pdata;
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_msic_power_btn.h b/arch/x86/platform/intel-mid/device_libs/platform_msic_power_btn.h
+new file mode 100644
+index 0000000..3de94ca
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_msic_power_btn.h
+@@ -0,0 +1,19 @@
++/*
++ * platform_msic_power_btn.h: MSIC power btn platform data header file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_MSIC_POWER_BTN_H_
++#define _PLATFORM_MSIC_POWER_BTN_H_
++
++#define INTEL_MID_POWERBTN_DEV_NAME "mid_powerbtn"
++
++extern void __init *msic_power_btn_platform_data(void *info)
++ __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_msic_thermal.c b/arch/x86/platform/intel-mid/device_libs/platform_msic_thermal.c
+new file mode 100644
+index 0000000..7c24a14
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_msic_thermal.c
+@@ -0,0 +1,185 @@
++/*
++ * platform_msic_thermal.c: msic_thermal platform data initilization file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/input.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/gpio.h>
++#include <linux/platform_device.h>
++#include <linux/mfd/intel_msic.h>
++#include <asm/intel-mid.h>
++#include <asm/intel_mid_gpadc.h>
++#include <asm/intel_mid_thermal.h>
++#include <linux/platform_data/intel_mid_remoteproc.h>
++#include "platform_msic.h"
++#include "platform_msic_thermal.h"
++
++/* ctp thermal sensor list */
++static struct intel_mid_thermal_sensor ctp_sensors[] = {
++ {
++ .name = SKIN0_NAME,
++ .index = 0,
++ .slope = 410,
++ .intercept = 16808,
++ .adc_channel = 0x04 | CH_NEED_VREF | CH_NEED_VCALIB,
++ .temp_correlation = skin0_temp_correlation,
++ .direct = false,
++ },
++ {
++ .name = SKIN1_NAME,
++ .index = 1,
++ .slope = 665,
++ .intercept = 8375,
++ .adc_channel = 0x04 | CH_NEED_VREF | CH_NEED_VCALIB,
++ .temp_correlation = skin0_temp_correlation,
++ .direct = false,
++ },
++ {
++ .name = MSIC_DIE_NAME,
++ .index = 2,
++ .slope = 368,
++ .intercept = 219560,
++ .adc_channel = 0x03 | CH_NEED_VCALIB,
++ .direct = true,
++ },
++ {
++ .name = BPTHERM_NAME,
++ .index = 3,
++ .slope = 788,
++ .intercept = 5065,
++ .adc_channel = 0x09 | CH_NEED_VREF | CH_NEED_VCALIB,
++ .temp_correlation = bptherm_temp_correlation,
++ .direct = false,
++ },
++
++};
++
++/* mfld thermal sensor list */
++static struct intel_mid_thermal_sensor mfld_sensors[] = {
++ {
++ .name = SKIN0_NAME,
++ .index = 0,
++ .slope = 851,
++ .intercept = 2800,
++ .adc_channel = 0x08 | CH_NEED_VREF | CH_NEED_VCALIB,
++ .temp_correlation = skin0_temp_correlation,
++ .direct = false,
++ },
++ {
++ .name = SKIN1_NAME,
++ .index = 1,
++ .slope = 806,
++ .intercept = 1800,
++ .adc_channel = 0x08 | CH_NEED_VREF | CH_NEED_VCALIB,
++ .temp_correlation = skin1_temp_correlation,
++ .direct = false,
++ },
++ {
++ .name = MSIC_SYS_NAME,
++ .index = 2,
++ .slope = 0,
++ .intercept = 0,
++ .adc_channel = 0x0A | CH_NEED_VREF | CH_NEED_VCALIB,
++ .direct = false,
++ },
++ {
++ .name = MSIC_DIE_NAME,
++ .index = 3,
++ .slope = 368,
++ .intercept = 219560,
++ .adc_channel = 0x03 | CH_NEED_VCALIB,
++ .direct = true,
++ },
++
++};
++
++/* LEX thermal sensor list */
++static struct intel_mid_thermal_sensor lex_sensors[] = {
++ {
++ .name = SKIN0_NAME,
++ .index = 0,
++ .slope = 851,
++ .intercept = 2800,
++ .adc_channel = 0x08 | CH_NEED_VREF | CH_NEED_VCALIB,
++ .temp_correlation = skin0_temp_correlation,
++ .direct = false,
++ },
++ {
++ .name = SKIN1_NAME,
++ .index = 1,
++ .slope = 806,
++ .intercept = 1800,
++ .adc_channel = 0x08 | CH_NEED_VREF | CH_NEED_VCALIB,
++ .temp_correlation = skin1_temp_correlation,
++ .direct = false,
++ },
++ {
++ .name = MSIC_SYS_NAME,
++ .index = 2,
++ .slope = 0,
++ .intercept = 0,
++ .adc_channel = 0x0A | CH_NEED_VREF | CH_NEED_VCALIB,
++ .direct = false,
++ },
++ {
++ .name = MSIC_DIE_NAME,
++ .index = 3,
++ .slope = 368,
++ .intercept = 219560,
++ .adc_channel = 0x03 | CH_NEED_VCALIB,
++ .direct = true,
++ },
++
++};
++
++
++static struct intel_mid_thermal_platform_data pdata[] = {
++ [mfld_thermal] = {
++ .num_sensors = 4,
++ .sensors = mfld_sensors,
++ .soc_cooling = false,
++ },
++ [ctp_thermal] = {
++ .num_sensors = 4,
++ .sensors = ctp_sensors,
++ .soc_cooling = true,
++ },
++ [lex_thermal] = {
++ .num_sensors = 4,
++ .sensors = lex_sensors,
++ .soc_cooling = false,
++ },
++};
++
++void __init *msic_thermal_platform_data(void *info)
++{
++ struct platform_device *pdev;
++
++ pdev = platform_device_alloc(MSIC_THERM_DEV_NAME, -1);
++ if (!pdev) {
++ pr_err("out of memory for SFI platform dev %s\n",
++ MSIC_THERM_DEV_NAME);
++ return NULL;
++ }
++
++ if (platform_device_add(pdev)) {
++ pr_err("failed to add thermal platform device\n");
++ platform_device_put(pdev);
++ return NULL;
++ }
++
++ pdev->dev.platform_data = &pdata[mfld_thermal];
++
++ register_rpmsg_service("rpmsg_mid_thermal", RPROC_SCU, RP_MSIC_THERMAL);
++
++ return 0;
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_msic_thermal.h b/arch/x86/platform/intel-mid/device_libs/platform_msic_thermal.h
+new file mode 100644
+index 0000000..c4f3404
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_msic_thermal.h
+@@ -0,0 +1,26 @@
++/*
++ * platform_msic_thermal.h: msic_thermal platform data header file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_MSIC_THERMAL_H_
++#define _PLATFORM_MSIC_THERMAL_H_
++
++#define MSIC_THERM_DEV_NAME "msic_thermal"
++
++extern void __init *msic_thermal_platform_data(void *info)
++ __attribute__((weak));
++enum {
++ mfld_thermal,
++ ctp_thermal,
++ lex_thermal,
++ vb_thermal,
++};
++
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_pcal9555a.c b/arch/x86/platform/intel-mid/device_libs/platform_pcal9555a.c
+new file mode 100644
+index 0000000..6625edc
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_pcal9555a.c
+@@ -0,0 +1,68 @@
++/*
++ * platform_pcal9555a.c: pcal9555a platform data initilization file
++ *
++ * (C) Copyright 2014 Intel Corporation
++ * Author: Dan O'Donovan <dan@emutex.com>
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/init.h>
++#include <linux/gpio.h>
++#include <linux/i2c.h>
++#include <linux/i2c/pca953x.h>
++#include <asm/intel-mid.h>
++#include "platform_pcal9555a.h"
++
++
++void __init *pcal9555a_platform_data(void *info)
++{
++ static struct pca953x_platform_data pcal9555a_pdata[PCAL9555A_NUM];
++ static int nr;
++ struct pca953x_platform_data *pcal9555a;
++ struct i2c_board_info *i2c_info = info;
++ int gpio_base, intr;
++ char base_pin_name[SFI_NAME_LEN + 1];
++ char intr_pin_name[SFI_NAME_LEN + 1];
++
++ if (!info) {
++ pr_err("%s: invalid info pointer\n", __func__);
++ return NULL;
++ }
++
++ if (nr >= PCAL9555A_NUM) {
++ pr_err("%s: too many pcal9555a, we only support %d\n",
++ __func__, PCAL9555A_NUM);
++ return NULL;
++ }
++ pcal9555a = &pcal9555a_pdata[nr++];
++
++ /* we have several pcal9555a on the board, we only need load several
++ * instances of the same pca953x driver to cover them
++ */
++
++ snprintf(base_pin_name, sizeof(base_pin_name),
++ "%s_base", i2c_info->type);
++ snprintf(intr_pin_name, sizeof(intr_pin_name),
++ "%s_int", i2c_info->type);
++
++ strcpy(i2c_info->type, "pcal9555a");
++
++ gpio_base = get_gpio_by_name(base_pin_name);
++ intr = get_gpio_by_name(intr_pin_name);
++
++ if (gpio_base == -1)
++ return NULL;
++ pcal9555a->gpio_base = gpio_base;
++ if (intr != -1) {
++ i2c_info->irq = intr + INTEL_MID_IRQ_OFFSET;
++ pcal9555a->irq_base = gpio_base + INTEL_MID_IRQ_OFFSET;
++ } else {
++ i2c_info->irq = -1;
++ pcal9555a->irq_base = -1;
++ }
++ return pcal9555a;
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_pcal9555a.h b/arch/x86/platform/intel-mid/device_libs/platform_pcal9555a.h
+new file mode 100644
+index 0000000..5593db2
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_pcal9555a.h
+@@ -0,0 +1,19 @@
++/*
++ * platform_pcal9555a.h: pcal9555a platform data header file
++ *
++ * (C) Copyright 2014 Intel Corporation
++ * Author: Dan O'Donovan <dan@emutex.com>
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_PCAL9555A_H_
++#define _PLATFORM_PCAL9555A_H_
++
++/* we have multiple pcal9555a on the board ... */
++#define PCAL9555A_NUM 4
++
++extern void __init *pcal9555a_platform_data(void *info) __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_pmic_gpio.c b/arch/x86/platform/intel-mid/device_libs/platform_pmic_gpio.c
+new file mode 100644
+index 0000000..1526663
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_pmic_gpio.c
+@@ -0,0 +1,36 @@
++/*
++ * platform_pmic_gpio.c: PMIC GPIO platform data initilization file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/scatterlist.h>
++#include <linux/gpio.h>
++#include <linux/init.h>
++#include <linux/sfi.h>
++#include <asm/intel-mid.h>
++#include <linux/intel_pmic_gpio.h>
++#include "platform_pmic_gpio.h"
++
++void __init *pmic_gpio_platform_data(void *info)
++{
++ static struct intel_pmic_gpio_platform_data pmic_gpio_pdata;
++ int gpio_base = get_gpio_by_name("pmic_gpio_base");
++
++ if (gpio_base == -1)
++ gpio_base = 64;
++ pmic_gpio_pdata.gpio_base = gpio_base;
++ pmic_gpio_pdata.irq_base = gpio_base + INTEL_MID_IRQ_OFFSET;
++ pmic_gpio_pdata.gpiointr = 0xffffeff8;
++
++ return &pmic_gpio_pdata;
++}
++
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_pmic_gpio.h b/arch/x86/platform/intel-mid/device_libs/platform_pmic_gpio.h
+new file mode 100644
+index 0000000..0bce0de
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_pmic_gpio.h
+@@ -0,0 +1,16 @@
++/*
++ * platform_pmic_gpio.h: PMIC GPIO platform data header file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_PMIC_GPIO_H_
++#define _PLATFORM_PMIC_GPIO_H_
++
++extern void __init *pmic_gpio_platform_data(void *info) __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_scu_flis.c b/arch/x86/platform/intel-mid/device_libs/platform_scu_flis.c
+new file mode 100644
+index 0000000..778f70c
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_scu_flis.c
+@@ -0,0 +1,290 @@
++/*
++ * platform_scu_flis.c: scu_flis platform data initilization file
++ *
++ * (C) Copyright 2013 Intel Corporation
++ * Author: Ning Li <ning.li@intel.com>
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/input.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <asm/intel-mid.h>
++#include <asm/intel_mid_remoteproc.h>
++#include <asm/intel_scu_flis.h>
++#include "platform_scu_flis.h"
++
++static struct pin_mmio_flis_t tng_pin_mmio_flis_table[TNG_PIN_NUM] = {
++ [tng_usb_ulpi_0_clk] = { writable, 0x0500 },
++ [tng_usb_ulpi_0_data_0] = { writable, 0x0504 },
++ [tng_usb_ulpi_0_data_1] = { writable, 0x0508 },
++ [tng_usb_ulpi_0_data_2] = { writable, 0x050C },
++ [tng_usb_ulpi_0_data_3] = { writable, 0x0510 },
++ [tng_usb_ulpi_0_data_4] = { writable, 0x0514 },
++ [tng_usb_ulpi_0_data_5] = { writable, 0x0518 },
++ [tng_usb_ulpi_0_data_6] = { writable, 0x051C },
++ [tng_usb_ulpi_0_data_7] = { writable, 0x0520 },
++ [tng_usb_ulpi_0_dir] = { writable, 0x0524 },
++ [tng_usb_ulpi_0_nxt] = { writable, 0x0528 },
++ [tng_usb_ulpi_0_refclk] = { writable, 0x052C },
++ [tng_usb_ulpi_0_stp] = { writable, 0x0530 },
++ [tng_emmc_0_clk] = { writable, 0x0900 },
++ [tng_emmc_0_cmd] = { writable, 0x0904 },
++ [tng_emmc_0_d_0] = { writable, 0x0908 },
++ [tng_emmc_0_d_1] = { writable, 0x090C },
++ [tng_emmc_0_d_2] = { writable, 0x0910 },
++ [tng_emmc_0_d_3] = { writable, 0x0914 },
++ [tng_emmc_0_d_4] = { writable, 0x0918 },
++ [tng_emmc_0_d_5] = { writable, 0x091C },
++ [tng_emmc_0_d_6] = { writable, 0x0920 },
++ [tng_emmc_0_d_7] = { writable, 0x0924 },
++ [tng_emmc_0_rst_b] = { writable, 0x0928 },
++ [tng_gp_emmc_1_clk] = { writable, 0x092C },
++ [tng_gp_emmc_1_cmd] = { writable, 0x0930 },
++ [tng_gp_emmc_1_d_0] = { writable, 0x0934 },
++ [tng_gp_emmc_1_d_1] = { writable, 0x0938 },
++ [tng_gp_emmc_1_d_2] = { writable, 0x093C },
++ [tng_gp_emmc_1_d_3] = { writable, 0x0940 },
++ [tng_gp_emmc_1_d_4] = { writable, 0x0944 },
++ [tng_gp_emmc_1_d_5] = { writable, 0x0948 },
++ [tng_gp_emmc_1_d_6] = { writable, 0x094C },
++ [tng_gp_emmc_1_d_7] = { writable, 0x0950 },
++ [tng_gp_emmc_1_rst_b] = { writable, 0x0954 },
++ [tng_gp_28] = { writable, 0x0958 },
++ [tng_gp_29] = { writable, 0x095C },
++ [tng_gp_sdio_0_cd_b] = { writable, 0x0D00 },
++ [tng_gp_sdio_0_clk] = { writable, 0x0D04 },
++ [tng_gp_sdio_0_cmd] = { writable, 0x0D08 },
++ [tng_gp_sdio_0_dat_0] = { writable, 0x0D0C },
++ [tng_gp_sdio_0_dat_1] = { writable, 0x0D10 },
++ [tng_gp_sdio_0_dat_2] = { writable, 0x0D14 },
++ [tng_gp_sdio_0_dat_3] = { writable, 0x0D18 },
++ [tng_gp_sdio_0_lvl_clk_fb] = { writable, 0x0D1C },
++ [tng_gp_sdio_0_lvl_cmd_dir] = { writable, 0x0D20 },
++ [tng_gp_sdio_0_lvl_dat_dir] = { writable, 0x0D24 },
++ [tng_gp_sdio_0_lvl_sel] = { writable, 0x0D28 },
++ [tng_gp_sdio_0_powerdown_b] = { writable, 0x0D2C },
++ [tng_gp_sdio_0_wp] = { writable, 0x0D30 },
++ [tng_gp_sdio_1_clk] = { writable, 0x0D34 },
++ [tng_gp_sdio_1_cmd] = { writable, 0x0D38 },
++ [tng_gp_sdio_1_dat_0] = { writable, 0x0D3C },
++ [tng_gp_sdio_1_dat_1] = { writable, 0x0D40 },
++ [tng_gp_sdio_1_dat_2] = { writable, 0x0D44 },
++ [tng_gp_sdio_1_dat_3] = { writable, 0x0D48 },
++ [tng_gp_sdio_1_powerdown_b] = { writable, 0x0D4C },
++ [tng_mhsi_acdata] = { writable, 0x1100 },
++ [tng_mhsi_acflag] = { writable, 0x1104 },
++ [tng_mhsi_acready] = { writable, 0x1108 },
++ [tng_mhsi_acwake] = { writable, 0x110C },
++ [tng_mhsi_cadata] = { writable, 0x1110 },
++ [tng_mhsi_caflag] = { writable, 0x1114 },
++ [tng_mhsi_caready] = { writable, 0x1118 },
++ [tng_mhsi_cawake] = { writable, 0x111C },
++ [tng_gp_mslim_0_bclk] = { writable, 0x1500 },
++ [tng_gp_mslim_0_bdat] = { writable, 0x1504 },
++ [tng_gp_ssp_0_clk] = { writable, 0x1508 },
++ [tng_gp_ssp_0_fs] = { writable, 0x150C },
++ [tng_gp_ssp_0_rxd] = { writable, 0x1510 },
++ [tng_gp_ssp_0_txd] = { writable, 0x1514 },
++ [tng_gp_ssp_1_clk] = { writable, 0x1518 },
++ [tng_gp_ssp_1_fs] = { writable, 0x151C },
++ [tng_gp_ssp_1_rxd] = { writable, 0x1520 },
++ [tng_gp_ssp_1_txd] = { writable, 0x1524 },
++ [tng_gp_ssp_2_clk] = { writable, 0x1528 },
++ [tng_gp_ssp_2_fs] = { writable, 0x152C },
++ [tng_gp_ssp_2_rxd] = { writable, 0x1530 },
++ [tng_gp_ssp_2_txd] = { writable, 0x1534 },
++ [tng_gp_ssp_3_clk] = { writable, 0x1900 },
++ [tng_gp_ssp_3_fs] = { writable, 0x1904 },
++ [tng_gp_ssp_3_rxd] = { writable, 0x1908 },
++ [tng_gp_ssp_3_txd] = { writable, 0x190C },
++ [tng_gp_ssp_4_clk] = { writable, 0x1910 },
++ [tng_gp_ssp_4_fs_0] = { writable, 0x1914 },
++ [tng_gp_ssp_4_fs_1] = { writable, 0x1918 },
++ [tng_gp_ssp_4_fs_2] = { writable, 0x191C },
++ [tng_gp_ssp_4_fs_3] = { writable, 0x1920 },
++ [tng_gp_ssp_4_rxd] = { writable, 0x1924 },
++ [tng_gp_ssp_4_txd] = { writable, 0x1928 },
++ [tng_gp_ssp_5_clk] = { writable, 0x192C },
++ [tng_gp_ssp_5_fs_0] = { writable, 0x1930 },
++ [tng_gp_ssp_5_fs_1] = { writable, 0x1934 },
++ [tng_gp_ssp_5_fs_2] = { writable, 0x1938 },
++ [tng_gp_ssp_5_fs_3] = { writable, 0x193C },
++ [tng_gp_ssp_5_rxd] = { writable, 0x1940 },
++ [tng_gp_ssp_5_txd] = { writable, 0x1944 },
++ [tng_gp_ssp_6_clk] = { writable, 0x1948 },
++ [tng_gp_ssp_6_fs] = { writable, 0x194C },
++ [tng_gp_ssp_6_rxd] = { writable, 0x1950 },
++ [tng_gp_ssp_6_txd] = { writable, 0x1954 },
++ [tng_gp_i2c_1_scl] = { writable, 0x1D00 },
++ [tng_gp_i2c_1_sda] = { writable, 0x1D04 },
++ [tng_gp_i2c_2_scl] = { writable, 0x1D08 },
++ [tng_gp_i2c_2_sda] = { writable, 0x1D0C },
++ [tng_gp_i2c_3_scl] = { writable, 0x1D10 },
++ [tng_gp_i2c_3_sda] = { writable, 0x1D14 },
++ [tng_gp_i2c_4_scl] = { writable, 0x1D18 },
++ [tng_gp_i2c_4_sda] = { writable, 0x1D1C },
++ [tng_gp_i2c_5_scl] = { writable, 0x1D20 },
++ [tng_gp_i2c_5_sda] = { writable, 0x1D24 },
++ [tng_gp_i2c_6_scl] = { writable, 0x1D28 },
++ [tng_gp_i2c_6_sda] = { writable, 0x1D2C },
++ [tng_gp_i2c_7_scl] = { writable, 0x1D30 },
++ [tng_gp_i2c_7_sda] = { writable, 0x1D34 },
++ [tng_gp_uart_0_cts] = { writable, 0x2100 },
++ [tng_gp_uart_0_rts] = { writable, 0x2104 },
++ [tng_gp_uart_0_rx] = { writable, 0x2108 },
++ [tng_gp_uart_0_tx] = { writable, 0x210C },
++ [tng_gp_uart_1_cts] = { writable, 0x2110 },
++ [tng_gp_uart_1_rts] = { writable, 0x2114 },
++ [tng_gp_uart_1_rx] = { writable, 0x2118 },
++ [tng_gp_uart_1_tx] = { writable, 0x211C },
++ [tng_gp_uart_2_cts] = { writable, 0x2120 },
++ [tng_gp_uart_2_rts] = { writable, 0x2124 },
++ [tng_gp_uart_2_rx] = { writable, 0x2128 },
++ [tng_gp_uart_2_tx] = { writable, 0x212C },
++ [tng_gp_13] = { writable, 0x2500 },
++ [tng_gp_14] = { writable, 0x2504 },
++ [tng_gp_15] = { writable, 0x2508 },
++ [tng_gp_16] = { writable, 0x250C },
++ [tng_gp_17] = { writable, 0x2510 },
++ [tng_gp_18] = { writable, 0x2514 },
++ [tng_gp_19] = { writable, 0x2518 },
++ [tng_gp_20] = { writable, 0x251C },
++ [tng_gp_21] = { writable, 0x2520 },
++ [tng_gp_22] = { writable, 0x2524 },
++ [tng_gp_23] = { writable, 0x2528 },
++ [tng_gp_24] = { writable, 0x252C },
++ [tng_gp_25] = { writable, 0x2530 },
++ [tng_gp_fast_int_0] = { writable, 0x2534 },
++ [tng_gp_fast_int_1] = { writable, 0x2538 },
++ [tng_gp_fast_int_2] = { writable, 0x253C },
++ [tng_gp_fast_int_3] = { writable, 0x2540 },
++ [tng_gp_pwm_0] = { writable, 0x2544 },
++ [tng_gp_pwm_1] = { writable, 0x2548 },
++ [tng_gp_camerasb_0] = { writable, 0x2900 },
++ [tng_gp_camerasb_1] = { writable, 0x2904 },
++ [tng_gp_camerasb_2] = { writable, 0x2908 },
++ [tng_gp_camerasb_3] = { writable, 0x290C },
++ [tng_gp_camerasb_4] = { writable, 0x2910 },
++ [tng_gp_camerasb_5] = { writable, 0x2914 },
++ [tng_gp_camerasb_6] = { writable, 0x2918 },
++ [tng_gp_camerasb_7] = { writable, 0x291C },
++ [tng_gp_camerasb_8] = { writable, 0x2920 },
++ [tng_gp_camerasb_9] = { writable, 0x2924 },
++ [tng_gp_camerasb_10] = { writable, 0x2928 },
++ [tng_gp_camerasb_11] = { writable, 0x292C },
++ [tng_gp_clkph_0] = { writable, 0x2D00 },
++ [tng_gp_clkph_1] = { writable, 0x2D04 },
++ [tng_gp_clkph_2] = { writable, 0x2D08 },
++ [tng_gp_clkph_3] = { writable, 0x2D0C },
++ [tng_gp_clkph_4] = { writable, 0x2D10 },
++ [tng_gp_clkph_5] = { writable, 0x2D14 },
++ [tng_gp_hdmi_hpd] = { writable, 0x2D18 },
++ [tng_gp_intd_dsi_te1] = { writable, 0x2D1C },
++ [tng_gp_intd_dsi_te2] = { writable, 0x2D20 },
++ [tng_osc_clk_ctrl_0] = { writable, 0x2D24 },
++ [tng_osc_clk_ctrl_1] = { writable, 0x2D28 },
++ [tng_osc_clk_out_0] = { writable, 0x2D2C },
++ [tng_osc_clk_out_1] = { writable, 0x2D30 },
++ [tng_osc_clk_out_2] = { writable, 0x2D34 },
++ [tng_osc_clk_out_3] = { writable, 0x2D38 },
++ [tng_osc_clk_out_4] = { writable, 0x2D3C },
++ [tng_resetout_b] = { writable, 0x2D40 },
++ [tng_xxpmode] = { writable, 0x2D44 },
++ [tng_xxprdy] = { writable, 0x2D48 },
++ [tng_xxpreq_b] = { writable, 0x2D4C },
++ [tng_gp_26] = { writable, 0x2D50 },
++ [tng_gp_27] = { writable, 0x2D54 },
++ [tng_i2c_0_scl] = { writable, 0x3100 },
++ [tng_i2c_0_sda] = { writable, 0x3104 },
++ [tng_ierr_b] = { writable, 0x3108 },
++ [tng_jtag_tckc] = { writable, 0x310C },
++ [tng_jtag_tdic] = { writable, 0x3110 },
++ [tng_jtag_tdoc] = { writable, 0x3114 },
++ [tng_jtag_tmsc] = { writable, 0x3118 },
++ [tng_jtag_trst_b] = { writable, 0x311C },
++ [tng_prochot_b] = { writable, 0x3120 },
++ [tng_rtc_clk] = { writable, 0x3124 },
++ [tng_svid_vclk] = { writable, 0x3128 },
++ [tng_svid_vdio] = { writable, 0x3130 },
++ [tng_thermtrip_b] = { writable, 0x3134 },
++ [tng_standby] = { writable, 0x3138 },
++ [tng_gp_kbd_dkin_0] = { writable, 0x3500 },
++ [tng_gp_kbd_dkin_1] = { writable, 0x3504 },
++ [tng_gp_kbd_dkin_2] = { writable, 0x3508 },
++ [tng_gp_kbd_dkin_3] = { writable, 0x350C },
++ [tng_gp_kbd_mkin_0] = { writable, 0x3510 },
++ [tng_gp_kbd_mkin_1] = { writable, 0x3514 },
++ [tng_gp_kbd_mkin_2] = { writable, 0x3518 },
++ [tng_gp_kbd_mkin_3] = { writable, 0x351C },
++ [tng_gp_kbd_mkin_4] = { writable, 0x3520 },
++ [tng_gp_kbd_mkin_5] = { writable, 0x3524 },
++ [tng_gp_kbd_mkin_6] = { writable, 0x3528 },
++ [tng_gp_kbd_mkin_7] = { writable, 0x352C },
++ [tng_gp_kbd_mkout_0] = { writable, 0x3530 },
++ [tng_gp_kbd_mkout_1] = { writable, 0x3534 },
++ [tng_gp_kbd_mkout_2] = { writable, 0x3538 },
++ [tng_gp_kbd_mkout_3] = { writable, 0x353C },
++ [tng_gp_kbd_mkout_4] = { writable, 0x3540 },
++ [tng_gp_kbd_mkout_5] = { writable, 0x3544 },
++ [tng_gp_kbd_mkout_6] = { writable, 0x3548 },
++ [tng_gp_kbd_mkout_7] = { writable, 0x354C },
++ [tng_gp_0] = { writable, 0x3900 },
++ [tng_gp_1] = { writable, 0x3904 },
++ [tng_gp_2] = { writable, 0x3908 },
++ [tng_gp_3] = { writable, 0x390C },
++ [tng_gp_4] = { writable, 0x3910 },
++ [tng_gp_5] = { writable, 0x3914 },
++ [tng_gp_6] = { writable, 0x3918 },
++ [tng_gp_7] = { writable, 0x391C },
++ [tng_gp_8] = { writable, 0x3920 },
++ [tng_gp_9] = { writable, 0x3924 },
++ [tng_gp_10] = { writable, 0x3928 },
++ [tng_gp_11] = { writable, 0x392C },
++ [tng_gp_12] = { writable, 0x3930 },
++ [tng_gp_mpti_clk] = { writable, 0x3D00 },
++ [tng_gp_mpti_data_0] = { writable, 0x3D04 },
++ [tng_gp_mpti_data_1] = { writable, 0x3D08 },
++ [tng_gp_mpti_data_2] = { writable, 0x3D0C },
++ [tng_gp_mpti_data_3] = { writable, 0x3D10 },
++};
++
++static int __init intel_scu_flis_init(void)
++{
++ int ret;
++ struct platform_device *pdev = NULL;
++ static struct intel_scu_flis_platform_data flis_pdata;
++
++ flis_pdata.pin_t = NULL;
++ flis_pdata.pin_num = TNG_PIN_NUM;
++ flis_pdata.flis_base = 0xFF0C0000;
++ flis_pdata.flis_len = 0x8000;
++ flis_pdata.mmio_flis_t = tng_pin_mmio_flis_table;
++
++ pdev = platform_device_alloc(FLIS_DEVICE_NAME, -1);
++ if (!pdev) {
++ pr_err("out of memory for platform dev %s\n", FLIS_DEVICE_NAME);
++ ret = -EINVAL;
++ goto out;
++ }
++
++ pdev->dev.platform_data = &flis_pdata;
++
++ ret = platform_device_add(pdev);
++ if (ret) {
++ pr_err("failed to add flis platform device\n");
++ platform_device_put(pdev);
++ goto out;
++ }
++
++ pr_info("intel_scu_flis platform device created\n");
++out:
++ return ret;
++}
++fs_initcall(intel_scu_flis_init);
++
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_scu_flis.h b/arch/x86/platform/intel-mid/device_libs/platform_scu_flis.h
+new file mode 100644
+index 0000000..cf48ae5
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_scu_flis.h
+@@ -0,0 +1,17 @@
++/*
++ * platform_scu_flis.h: scu_flis platform data header file
++ *
++ * (C) Copyright 2012 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_SCU_FLIS_H_
++#define _PLATFORM_SCU_FLIS_H_
++
++#define FLIS_DEVICE_NAME "intel_scu_flis"
++
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_sdio_regulator.c b/arch/x86/platform/intel-mid/device_libs/platform_sdio_regulator.c
+new file mode 100644
+index 0000000..01953a6
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_sdio_regulator.c
+@@ -0,0 +1,235 @@
++/*
++ * platform_sdio_regulator.c: sdio regulator platform device initilization file
++ *
++ * (C) Copyright 2011 Intel Corporation
++ * Author: chuanxiao.dong@intel.com, feiyix.ning@intel.com
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <asm/intel-mid.h>
++#include <linux/gpio.h>
++#include <linux/lnw_gpio.h>
++#include <linux/delay.h>
++#include <linux/regulator/machine.h>
++#include <linux/regulator/fixed.h>
++#include <linux/acpi.h>
++#include <linux/acpi_gpio.h>
++
++#define DELAY_ONOFF 250
++
++struct acpi_ids { char *hid; char *uid; };
++
++static struct acpi_ids intel_sdio_ids[] = {
++ {"INT33BB", "2"}, /* BYT SDIO */
++ { },
++};
++
++static struct acpi_ids intel_brc_ids[] = {
++ {"BCM4321", NULL}, /* BYT SDIO */
++ { },
++};
++
++static struct regulator_consumer_supply wlan_vmmc_supply = {
++ .supply = "vmmc",
++};
++
++static struct regulator_init_data wlan_vmmc_data = {
++ .constraints = {
++ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
++ },
++ .num_consumer_supplies = 1,
++ .consumer_supplies = &wlan_vmmc_supply,
++};
++
++static struct fixed_voltage_config vwlan = {
++ .supply_name = "wlan_en_acpi",
++ .microvolts = 1800000,
++ .gpio = -EINVAL,
++ .startup_delay = 1000 * DELAY_ONOFF,
++ .enable_high = 1,
++ .enabled_at_boot = 0,
++ .init_data = &wlan_vmmc_data,
++};
++
++static void vwlan_device_release(struct device *dev) {}
++
++static struct platform_device vwlan_device = {
++ .name = "reg-fixed-voltage",
++ .id = PLATFORM_DEVID_AUTO,
++ .dev = {
++ .platform_data = &vwlan,
++ .release = vwlan_device_release,
++ },
++};
++
++static struct acpi_device *acpi_bus_get_parent(acpi_handle handle)
++{
++ struct acpi_device *device = NULL;
++ acpi_status status;
++ int result;
++ struct acpi_device *acpi_root;
++
++ result = acpi_bus_get_device(ACPI_ROOT_OBJECT, &acpi_root);
++ if (result)
++ return NULL;
++
++ /*
++ * Fixed hardware devices do not appear in the namespace and do not
++ * have handles, but we fabricate acpi_devices for them, so we have
++ * to deal with them specially.
++ */
++ if (!handle)
++ return acpi_root;
++
++ do {
++ status = acpi_get_parent(handle, &handle);
++ if (ACPI_FAILURE(status))
++ return status == AE_NULL_ENTRY ? NULL : acpi_root;
++ } while (acpi_bus_get_device(handle, &device));
++
++ return device;
++}
++
++static int sdio_acpi_match(struct device *dev, void *data)
++{
++ struct acpi_ids *ids = data;
++ struct acpi_handle *handle = ACPI_HANDLE(dev);
++ struct acpi_device_info *info;
++ char *uid = NULL;
++ acpi_status status;
++
++ status = acpi_get_object_info(handle, &info);
++ if (!ACPI_FAILURE(status) && (info->valid & ACPI_VALID_UID))
++ uid = info->unique_id.string;
++ else
++ return false;
++
++ if (!strncmp(ids->hid, dev_name(dev), strlen(ids->hid)))
++ if (!strcmp(ids->uid, uid))
++ return true;
++
++ return false;
++}
++
++static int brc_acpi_match(struct device *dev, void *data)
++{
++ struct acpi_ids *ids = data;
++
++ if (!strncmp(ids->hid, dev_name(dev), strlen(ids->hid)))
++ return true;
++
++ return false;
++}
++
++
++static int brc_fixed_regulator_register_by_acpi(struct platform_device *pdev)
++{
++ struct device *dev;
++ struct acpi_ids *brc_ids;
++ struct fixed_voltage_config *fixedcfg = NULL;
++ struct regulator_init_data *data = NULL;
++ struct acpi_handle *handle;
++ struct acpi_device *parent;
++
++ if (!pdev)
++ return -ENODEV;
++ fixedcfg = pdev->dev.platform_data;
++ if (!fixedcfg)
++ return -ENODEV;
++ data = fixedcfg->init_data;
++ if (!data || !data->consumer_supplies)
++ return -ENODEV;
++
++ /* get the GPIO pin from ACPI device first */
++ for (brc_ids = intel_brc_ids; brc_ids->hid; brc_ids++) {
++ dev = bus_find_device(&platform_bus_type, NULL,
++ brc_ids, brc_acpi_match);
++ if (dev) {
++ handle = ACPI_HANDLE(dev);
++ if (!ACPI_HANDLE(dev))
++ continue;
++ parent = acpi_bus_get_parent(handle);
++ if (!parent)
++ continue;
++
++ data->consumer_supplies->dev_name =
++ dev_name(&parent->dev);
++ fixedcfg->gpio = acpi_get_gpio_by_index(dev, 1, NULL);
++ if (fixedcfg->gpio < 0) {
++ dev_info(dev, "No wlan-enable GPIO\n");
++ continue;
++ }
++ dev_info(dev, "wlan-enable GPIO %d found\n",
++ fixedcfg->gpio);
++ break;
++ }
++ }
++
++ if (brc_ids->hid) {
++ /* add a regulator to control wlan enable gpio */
++ return platform_device_register(&vwlan_device);
++ }
++
++ return -ENODEV;
++}
++
++static int sdio_fixed_regulator_register_by_acpi(struct platform_device *pdev)
++{
++ struct device *dev;
++ struct acpi_ids *sdio_ids;
++ struct fixed_voltage_config *fixedcfg = NULL;
++ struct regulator_init_data *data = NULL;
++
++ if (!pdev)
++ return -ENODEV;
++ fixedcfg = pdev->dev.platform_data;
++ if (!fixedcfg)
++ return -ENODEV;
++ data = fixedcfg->init_data;
++ if (!data || !data->consumer_supplies)
++ return -ENODEV;
++
++ /* get the GPIO pin from ACPI device first */
++ for (sdio_ids = intel_sdio_ids; sdio_ids->hid; sdio_ids++) {
++ dev = bus_find_device(&platform_bus_type, NULL,
++ sdio_ids, sdio_acpi_match);
++ if (dev) {
++ data->consumer_supplies->dev_name = dev_name(dev);
++
++ fixedcfg->gpio = acpi_get_gpio_by_index(dev, 0, NULL);
++ if (fixedcfg->gpio < 0) {
++ dev_info(dev, "No wlan-enable GPIO\n");
++ continue;
++ }
++ dev_info(dev, "wlan-enable GPIO %d found\n",
++ fixedcfg->gpio);
++ break;
++ }
++ }
++
++ if (sdio_ids->hid) {
++ /* add a regulator to control wlan enable gpio */
++ return platform_device_register(&vwlan_device);
++ }
++
++ return -ENODEV;
++}
++
++static int __init wifi_regulator_init(void)
++{
++ int ret;
++ /* register fixed regulator through ACPI device */
++ ret = brc_fixed_regulator_register_by_acpi(&vwlan_device);
++ if (!ret)
++ return ret;
++
++ pr_err("%s: No SDIO host in platform devices\n", __func__);
++ return ret;
++}
++rootfs_initcall(wifi_regulator_init);
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_soc_thermal.c b/arch/x86/platform/intel-mid/device_libs/platform_soc_thermal.c
+new file mode 100644
+index 0000000..004784a
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_soc_thermal.c
+@@ -0,0 +1,136 @@
++/*
++ * platform_soc_thermal.c: Platform data for SoC DTS driver
++ *
++ * (C) Copyright 2013 Intel Corporation
++ * Author: Durgadoss R <durgadoss.r@intel.com>
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#define pr_fmt(fmt) "intel_soc_thermal: " fmt
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++
++#include "platform_soc_thermal.h"
++
++#include <asm/intel-mid.h>
++#include <asm/intel_mid_thermal.h>
++
++#define BYT_SOC_THRM_IRQ 86
++#define BYT_SOC_THRM "soc_thrm"
++
++static struct resource res = {
++ .flags = IORESOURCE_IRQ,
++};
++
++static struct soc_throttle_data tng_soc_data[] = {
++ {
++ .power_limit = 0x9C,
++ .floor_freq = 0x00,
++ },
++ {
++ .power_limit = 0x8C,
++ .floor_freq = 0x00,
++ },
++ {
++ .power_limit = 0x7C,
++ .floor_freq = 0x00,
++ },
++ {
++ .power_limit = 0x6C,
++ .floor_freq = 0x00,
++ },
++};
++
++static struct soc_throttle_data vlv2_soc_data[] = {
++ {
++ .power_limit = 0xDA, /* 7W */
++ .floor_freq = 0x00,
++ },
++ {
++ .power_limit = 0x6D, /* 3.5W */
++ .floor_freq = 0x01,
++ },
++ {
++ .power_limit = 0x2E, /* 1.5W */
++ .floor_freq = 0x01,
++ },
++ {
++ .power_limit = 0x2E, /* 1.5W */
++ .floor_freq = 0x01,
++ },
++};
++
++void soc_thrm_device_handler(struct sfi_device_table_entry *pentry,
++ struct devs_id *dev)
++{
++ int ret;
++ struct platform_device *pdev;
++
++ pr_info("IPC bus = %d, name = %16.16s, irq = 0x%2x\n",
++ pentry->host_num, pentry->name, pentry->irq);
++
++ res.start = pentry->irq;
++
++ pdev = platform_device_register_simple(pentry->name, -1,
++ (const struct resource *)&res, 1);
++ if (IS_ERR(pdev)) {
++ ret = PTR_ERR(pdev);
++ pr_err("platform_soc_thermal:pdev_register failed: %d\n", ret);
++ }
++
++ pdev->dev.platform_data = &tng_soc_data;
++}
++
++static inline int byt_program_ioapic(int irq, int trigger, int polarity)
++{
++ struct io_apic_irq_attr irq_attr;
++ int ioapic;
++
++ ioapic = mp_find_ioapic(irq);
++ if (ioapic < 0)
++ return -EINVAL;
++ irq_attr.ioapic = ioapic;
++ irq_attr.ioapic_pin = irq;
++ irq_attr.trigger = trigger;
++ irq_attr.polarity = polarity;
++ return io_apic_set_pci_routing(NULL, irq, &irq_attr);
++}
++
++static int __init byt_soc_thermal_init(void)
++{
++ int ret;
++ struct platform_device *pdev;
++
++ res.start = BYT_SOC_THRM_IRQ;
++
++ pdev = platform_device_register_simple(BYT_SOC_THRM, -1,
++ (const struct resource *)&res, 1);
++ if (IS_ERR(pdev)) {
++ ret = PTR_ERR(pdev);
++ pr_err("byt_soc_thermal:pdev_register failed: %d\n", ret);
++ return ret;
++ }
++
++ ret = byt_program_ioapic(BYT_SOC_THRM_IRQ, 0, 1);
++ if (ret) {
++ pr_err("%s: ioapic programming failed", __func__);
++ platform_device_unregister(pdev);
++ }
++
++ pdev->dev.platform_data = &vlv2_soc_data;
++
++ return ret;
++}
++
++static int __init platform_soc_thermal_init(void)
++{
++ return 0;
++}
++device_initcall(platform_soc_thermal_init);
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_soc_thermal.h b/arch/x86/platform/intel-mid/device_libs/platform_soc_thermal.h
+new file mode 100644
+index 0000000..c8ece32
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_soc_thermal.h
+@@ -0,0 +1,20 @@
++/*
++ * platform_soc_thermal.h: platform SoC thermal driver library header file
++ *
++ * (C) Copyright 2013 Intel Corporation
++ * Author: Durgadoss R <durgadoss.r@intel.com>
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_SOC_THERMAL_H_
++#define _PLATFORM_SOC_THERMAL_H_
++
++#include <linux/sfi.h>
++#include <asm/intel-mid.h>
++
++extern void soc_thrm_device_handler(struct sfi_device_table_entry *,
++ struct devs_id *) __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_spidev.c b/arch/x86/platform/intel-mid/device_libs/platform_spidev.c
+new file mode 100644
+index 0000000..8eaa92f
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_spidev.c
+@@ -0,0 +1,73 @@
++/*
++ * platform_spidev.c: spidev platform data initilization file
++ *
++ * (C) Copyright 2014 Intel Corporation
++ * Author: Dan O'Donovan <dan@emutex.com>
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/spi/spi.h>
++#include <linux/spi/intel_mid_ssp_spi.h>
++#include <asm/intel-mid.h>
++#include <linux/gpio.h>
++#include <linux/lnw_gpio.h>
++#include "platform_spidev.h"
++
++static void tng_ssp_spi_cs_control(u32 command);
++static void tng_ssp_spi_platform_pinmux(void);
++
++static int tng_ssp_spi2_FS_gpio = 111;
++
++static struct intel_mid_ssp_spi_chip chip = {
++ .burst_size = DFLT_FIFO_BURST_SIZE,
++ .timeout = DFLT_TIMEOUT_VAL,
++ /* SPI DMA is currently not usable on Tangier */
++ .dma_enabled = false,
++ .cs_control = tng_ssp_spi_cs_control,
++ .platform_pinmux = tng_ssp_spi_platform_pinmux,
++};
++
++static void tng_ssp_spi_cs_control(u32 command)
++{
++ gpio_set_value(tng_ssp_spi2_FS_gpio, (command == CS_ASSERT) ? 0 : 1);
++}
++
++static void tng_ssp_spi_platform_pinmux(void)
++{
++ int err;
++ int saved_muxing;
++ /* Request Chip Select gpios */
++ saved_muxing = gpio_get_alt(tng_ssp_spi2_FS_gpio);
++
++ lnw_gpio_set_alt(tng_ssp_spi2_FS_gpio, LNW_GPIO);
++ err = gpio_request_one(tng_ssp_spi2_FS_gpio,
++ GPIOF_DIR_OUT|GPIOF_INIT_HIGH, "Arduino Shield SS");
++ if (err) {
++ pr_err("%s: unable to get Chip Select GPIO,\
++ fallback to legacy CS mode \n", __func__);
++ lnw_gpio_set_alt(tng_ssp_spi2_FS_gpio, saved_muxing);
++ chip.cs_control = NULL;
++ chip.platform_pinmux = NULL;
++ }
++}
++
++void __init *spidev_platform_data(void *info)
++{
++ struct spi_board_info *spi_info = info;
++
++ if (!spi_info) {
++ pr_err("%s: invalid info pointer\n", __func__);
++ return NULL;
++ }
++
++ spi_info->mode = SPI_MODE_0;
++
++ spi_info->controller_data = &chip;
++ spi_info->bus_num = FORCE_SPI_BUS_NUM;
++
++ return NULL;
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_spidev.h b/arch/x86/platform/intel-mid/device_libs/platform_spidev.h
+new file mode 100644
+index 0000000..a40ef8f
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_spidev.h
+@@ -0,0 +1,20 @@
++/*
++ * platform_spidev.h: spidev platform data header file
++ *
++ * (C) Copyright 2014 Intel Corporation
++ * Author: Dan O'Donovan <dan@emutex.com>
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_SPIDEV_H_
++#define _PLATFORM_SPIDEV_H_
++
++/* REVERT ME workaround[MRFL] for invalid bus number in IAFW .25 */
++#define FORCE_SPI_BUS_NUM 5
++#define FORCE_CHIP_SELECT 1
++
++extern void *spidev_platform_data(void *info) __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_tc35876x.c b/arch/x86/platform/intel-mid/device_libs/platform_tc35876x.c
+new file mode 100644
+index 0000000..127091d
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_tc35876x.c
+@@ -0,0 +1,26 @@
++/*
++ * platform_tc35876x.c: tc35876x platform data initilization file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/gpio.h>
++#include <linux/i2c/tc35876x.h>
++#include <asm/intel-mid.h>
++#include "platform_tc35876x.h"
++
++/*tc35876x DSI_LVDS bridge chip and panel platform data*/
++void *tc35876x_platform_data(void *data)
++{
++ static struct tc35876x_platform_data pdata;
++ pdata.gpio_bridge_reset = get_gpio_by_name("LCMB_RXEN");
++ pdata.gpio_panel_bl_en = get_gpio_by_name("6S6P_BL_EN");
++ pdata.gpio_panel_vadd = get_gpio_by_name("EN_VREG_LCD_V3P3");
++ return &pdata;
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_tc35876x.h b/arch/x86/platform/intel-mid/device_libs/platform_tc35876x.h
+new file mode 100644
+index 0000000..56a74eb
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_tc35876x.h
+@@ -0,0 +1,16 @@
++/*
++ * platform_tc35876x.h: tc35876x platform data header file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_TC35876X_H_
++#define _PLATFORM_TC35876X_H_
++
++extern void *tc35876x_platform_data(void *info) __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_tca6416.c b/arch/x86/platform/intel-mid/device_libs/platform_tca6416.c
+new file mode 100644
+index 0000000..98a6cd1
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_tca6416.c
+@@ -0,0 +1,45 @@
++/*
++ * platform_tca6416.c: tca6416 platform data initilization file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/i2c/pca953x.h>
++#include <linux/i2c.h>
++#include <linux/gpio.h>
++#include <asm/intel-mid.h>
++#include "platform_tca6416.h"
++
++void *tca6416_platform_data(void *info)
++{
++ static struct pca953x_platform_data tca6416;
++ struct i2c_board_info *i2c_info = info;
++ int gpio_base, intr;
++ char base_pin_name[SFI_NAME_LEN + 1];
++ char intr_pin_name[SFI_NAME_LEN + 1];
++
++ strcpy(i2c_info->type, TCA6416_NAME);
++ strcpy(base_pin_name, TCA6416_BASE);
++ strcpy(intr_pin_name, TCA6416_INTR);
++
++ gpio_base = get_gpio_by_name(base_pin_name);
++ intr = get_gpio_by_name(intr_pin_name);
++
++ if (gpio_base == -1)
++ return NULL;
++ tca6416.gpio_base = gpio_base;
++ if (intr != -1) {
++ i2c_info->irq = intr + INTEL_MID_IRQ_OFFSET;
++ tca6416.irq_base = gpio_base + INTEL_MID_IRQ_OFFSET;
++ } else {
++ i2c_info->irq = -1;
++ tca6416.irq_base = -1;
++ }
++ return &tca6416;
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_tca6416.h b/arch/x86/platform/intel-mid/device_libs/platform_tca6416.h
+new file mode 100644
+index 0000000..69802d6
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_tca6416.h
+@@ -0,0 +1,20 @@
++/*
++ * platform_tca6416.h: tca6416 platform data header file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_TCA6416_H_
++#define _PLATFORM_TCA6416_H_
++
++#define TCA6416_NAME "tca6416"
++#define TCA6416_BASE "tca6416_base"
++#define TCA6416_INTR "tca6416_int"
++
++extern void *tca6416_platform_data(void *info) __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_wifi.c b/arch/x86/platform/intel-mid/device_libs/platform_wifi.c
+new file mode 100644
+index 0000000..ad0b6b4
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_wifi.c
+@@ -0,0 +1,128 @@
++/*
++ * platform_bcm43xx.c: bcm43xx platform data initilization file
++ *
++ * (C) Copyright 2011 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/gpio.h>
++#include <linux/lnw_gpio.h>
++#include <asm/intel-mid.h>
++#include <linux/wlan_plat.h>
++#include <linux/interrupt.h>
++#include <linux/mmc/sdhci.h>
++#include <linux/delay.h>
++#include <linux/platform_device.h>
++#include "pci/platform_sdhci_pci.h"
++#include "platform_wifi.h"
++
++static struct resource wifi_res[] = {
++ {
++ .name = "wlan_irq",
++ .start = -1,
++ .end = -1,
++ .flags = IORESOURCE_IRQ | IRQF_TRIGGER_FALLING ,
++ },
++};
++
++static struct wifi_platform_data pdata;
++
++static struct platform_device wifi_device = {
++ .name = "wlan",
++ .dev = {
++ .platform_data = &pdata,
++ },
++ .num_resources = ARRAY_SIZE(wifi_res),
++ .resource = wifi_res,
++};
++
++static const unsigned int sdhci_quirk = SDHCI_QUIRK2_ADVERTISE_2V0_FORCE_1V8
++ | SDHCI_QUIRK2_ENABLE_MMC_PM_IGNORE_PM_NOTIFY
++ | SDHCI_QUIRK2_ADVERTISE_3V0_FORCE_1V8
++ | SDHCI_QUIRK2_NON_STD_CIS;
++
++static void __init wifi_platform_data_init_sfi_fastirq(struct sfi_device_table_entry *pentry,
++ bool should_register)
++{
++ int wifi_irq_gpio = -1;
++
++ /* If the GPIO mode was previously called, this code overloads
++ the IRQ anyway */
++ wifi_res[0].start = wifi_res[0].end = pentry->irq;
++ wifi_res[0].flags = IORESOURCE_IRQ | IRQF_TRIGGER_HIGH;
++
++ pr_info("wifi_platform_data: IRQ == %d\n", pentry->irq);
++
++ if (should_register && platform_device_register(&wifi_device) < 0)
++ pr_err("platform_device_register failed for wifi_device\n");
++}
++
++/* Called if SFI device WLAN is present */
++void __init wifi_platform_data_fastirq(struct sfi_device_table_entry *pe,
++ struct devs_id *dev)
++{
++ /* This is used in the driver to know if it is GPIO/FastIRQ */
++ pdata.use_fast_irq = true;
++
++ if (wifi_res[0].start == -1) {
++ pr_info("Using WiFi platform data (Fast IRQ)\n");
++
++ /* Set vendor specific SDIO quirks */
++ sdhci_pdata_set_quirks(sdhci_quirk);
++ wifi_platform_data_init_sfi_fastirq(pe, true);
++ } else {
++ pr_info("Using WiFi platform data (Fast IRQ, overloading GPIO mode set previously)\n");
++ /* We do not register platform device, as it's already been
++ done by wifi_platform_data */
++ wifi_platform_data_init_sfi_fastirq(pe, false);
++ }
++
++}
++
++/* GPIO legacy code path */
++static void __init wifi_platform_data_init_sfi_gpio(void)
++{
++ int wifi_irq_gpio = -1;
++
++ /*Get GPIO numbers from the SFI table*/
++ wifi_irq_gpio = get_gpio_by_name(WIFI_SFI_GPIO_IRQ_NAME);
++ if (wifi_irq_gpio < 0) {
++ pr_err("%s: Unable to find " WIFI_SFI_GPIO_IRQ_NAME
++ " WLAN-interrupt GPIO in the SFI table\n",
++ __func__);
++ return;
++ }
++
++ wifi_res[0].start = wifi_res[0].end = wifi_irq_gpio;
++ pr_info("wifi_platform_data: GPIO == %d\n", wifi_irq_gpio);
++
++ if (platform_device_register(&wifi_device) < 0)
++ pr_err("platform_device_register failed for wifi_device\n");
++}
++
++/* Called from board.c */
++void __init *wifi_platform_data(void *info)
++{
++ /* When fast IRQ platform data has been called first, don't pursue */
++ if (wifi_res[0].start != -1)
++ return NULL;
++
++ pr_info("Using generic wifi platform data\n");
++
++ /* Set vendor specific SDIO quirks */
++#ifdef CONFIG_MMC_SDHCI_PCI
++ sdhci_pdata_set_quirks(sdhci_quirk);
++#endif
++
++#ifndef CONFIG_ACPI
++ /* We are SFI here, register platform device */
++ wifi_platform_data_init_sfi_gpio();
++#endif
++
++ return &wifi_device;
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_wifi.h b/arch/x86/platform/intel-mid/device_libs/platform_wifi.h
+new file mode 100644
+index 0000000..7f1f710
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_wifi.h
+@@ -0,0 +1,21 @@
++/*
++ * platform_wifi.h: WiFi platform data header file
++ *
++ * (C) Copyright 2011 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_WIFI_H_
++#define _PLATFORM_WIFI_H_
++
++#define WIFI_SFI_GPIO_IRQ_NAME "WLAN-interrupt"
++#define WIFI_SFI_GPIO_ENABLE_NAME "WLAN-enable"
++
++extern void __init *wifi_platform_data(void *info) __attribute__((weak));
++extern void wifi_platform_data_fastirq(struct sfi_device_table_entry *pe,
++ struct devs_id *dev) __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_wl12xx.c b/arch/x86/platform/intel-mid/device_libs/platform_wl12xx.c
+new file mode 100644
+index 0000000..53b8544
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_wl12xx.c
+@@ -0,0 +1,182 @@
++/*
++ * platform_wl12xx.c: wl12xx platform data initilization file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/gpio.h>
++#include <linux/lnw_gpio.h>
++#include <linux/wl12xx.h>
++#include <linux/regulator/machine.h>
++#include <linux/regulator/fixed.h>
++#include <asm/intel-mid.h>
++#include "platform_wl12xx.h"
++
++static int wl12xx_platform_init(struct wl12xx_platform_data *platform_data);
++static void wl12xx_platform_deinit(struct wl12xx_platform_data *platform_data);
++
++static struct wl12xx_platform_data mid_wifi_control = {
++ .board_ref_clock = 1,
++ .irq = 2,
++ .gpio = -EINVAL,
++ .board_tcxo_clock = 1,
++ .platform_quirks = WL12XX_PLATFORM_QUIRK_EDGE_IRQ,
++ .hw_init = wl12xx_platform_init,
++ .hw_deinit = wl12xx_platform_deinit,
++};
++
++static struct regulator_consumer_supply wl12xx_vmmc3_supply = {
++ .supply = "vmmc",
++ .dev_name = "0000:00:00.0", /*default value*/
++};
++
++static struct regulator_init_data wl12xx_vmmc3 = {
++ .constraints = {
++ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
++ },
++ .num_consumer_supplies = 1,
++ .consumer_supplies = &wl12xx_vmmc3_supply,
++};
++
++static struct fixed_voltage_config wl12xx_vwlan = {
++ .supply_name = "vwl1271",
++ .microvolts = 1800000,
++ .gpio = 75,
++ .startup_delay = 70000,
++ .enable_high = 1,
++ .enabled_at_boot = 0,
++ .init_data = &wl12xx_vmmc3,
++};
++
++static struct platform_device wl12xx_vwlan_device = {
++ .name = "reg-fixed-voltage",
++ .id = 1,
++ .dev = {
++ .platform_data = &wl12xx_vwlan,
++ },
++};
++
++void __init wl12xx_platform_data_init(void *info)
++{
++ struct sd_board_info *sd_info = info;
++ int err;
++
++ /*Get GPIO numbers from the SFI table*/
++ mid_wifi_control.gpio = get_gpio_by_name(WL12XX_SFI_GPIO_IRQ_NAME);
++ if (mid_wifi_control.gpio == -1) {
++ pr_err("%s: Unable to find WLAN-interrupt GPIO in the SFI table\n",
++ __func__);
++ return;
++ }
++
++ /* Set our board_ref_clock from SFI SD board info */
++ if (sd_info->board_ref_clock == ICDK_BOARD_REF_CLK)
++ /*iCDK board*/
++ /*26Mhz TCXO clock ref*/
++ mid_wifi_control.board_ref_clock = 1;
++ else if (sd_info->board_ref_clock == NCDK_BOARD_REF_CLK)
++ /*nCDK board*/
++ /*38,4Mhz TCXO clock ref*/
++ mid_wifi_control.board_ref_clock = 2;
++ err = wl12xx_set_platform_data(&mid_wifi_control);
++ if (err < 0)
++ pr_err("error setting wl12xx data\n");
++
++ /* this is the fake regulator that mmc stack use to power of the
++ wifi sdio card via runtime_pm apis */
++ wl12xx_vwlan.gpio = get_gpio_by_name(WL12XX_SFI_GPIO_ENABLE_NAME);
++ if (wl12xx_vwlan.gpio == -1) {
++ pr_err("%s: Unable to find WLAN-enable GPIO in the SFI table\n",
++ __func__);
++ return;
++ }
++ /* format vmmc reg address from sfi table */
++ sprintf((char *)wl12xx_vmmc3_supply.dev_name, "0000:00:%02x.%01x",
++ (sd_info->addr)>>8, sd_info->addr&0xFF);
++
++ err = platform_device_register(&wl12xx_vwlan_device);
++ if (err < 0)
++ pr_err("error platform_device_register\n");
++
++}
++
++void __init *wl12xx_platform_data(void *info)
++{
++ wl12xx_platform_data_init(info);
++
++ return &mid_wifi_control;
++}
++
++static int wl12xx_platform_init(struct wl12xx_platform_data *platform_data)
++{
++ int err = 0;
++
++ if (IS_ERR(platform_data)) {
++ err = PTR_ERR(platform_data);
++ pr_err("%s: missing wlan platform data: %d\n", __func__, err);
++ goto out;
++ }
++
++ /* gpio must be set to -EINVAL by platform code if
++ gpio based irq is not used*/
++
++ if (gpio_is_valid(platform_data->gpio)) {
++ if (!platform_data->gpio)
++ pr_warn("using GPIO %d for wl12xx\n",
++ platform_data->gpio);
++
++ /* Request gpio */
++ err = gpio_request(platform_data->gpio, "wl12xx");
++ if (err < 0) {
++ pr_err("%s: Unable to request GPIO:%d, err:%d\n",
++ __func__, platform_data->gpio, err);
++ goto out;
++ }
++
++ /* set gpio direction */
++ err = gpio_direction_input(platform_data->gpio);
++ if (err < 0) {
++ pr_err("%s: Unable to set GPIO:%d direction, err:%d\n",
++ __func__, platform_data->gpio, err);
++ goto out;
++ }
++
++ /* convert gpio to irq */
++ platform_data->irq = gpio_to_irq(platform_data->gpio);
++ if (platform_data->irq < 0) {
++ pr_err("%s: Error gpio_to_irq:%d->%d\n", __func__,
++ platform_data->gpio,
++ platform_data->irq);
++ goto out;
++ }
++ }
++
++ sdhci_pci_request_regulators();
++
++ pr_info("%s done\n", __func__);
++out:
++ return err;
++}
++
++static void wl12xx_platform_deinit(struct wl12xx_platform_data *pdata)
++{
++ /* get platform data and free the gpio */
++ if (IS_ERR(pdata)) {
++ pr_err("%s: missing wlan platform data\n", __func__);
++ goto out;
++ }
++
++ if (gpio_is_valid(pdata->gpio)) {
++ if (!pdata->gpio)
++ pr_warn("using GPIO %d for wl12xx\n", pdata->gpio);
++ gpio_free(pdata->gpio);
++ }
++out:
++ return ;
++}
+diff --git a/arch/x86/platform/intel-mid/device_libs/platform_wl12xx.h b/arch/x86/platform/intel-mid/device_libs/platform_wl12xx.h
+new file mode 100644
+index 0000000..909f697
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/device_libs/platform_wl12xx.h
+@@ -0,0 +1,21 @@
++/*
++ * platform_wl12xx.h: wl12xx platform data header file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _PLATFORM_WL12XX_H_
++#define _PLATFORM_WL12XX_H_
++
++#define WL12XX_SFI_GPIO_IRQ_NAME "WLAN-interrupt"
++#define WL12XX_SFI_GPIO_ENABLE_NAME "WLAN-enable"
++#define ICDK_BOARD_REF_CLK 26000000
++#define NCDK_BOARD_REF_CLK 38400000
++
++extern void __init *wl12xx_platform_data(void *info) __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/early_printk_intel_mid.c b/arch/x86/platform/intel-mid/early_printk_intel_mid.c
+new file mode 100644
+index 0000000..3b361bd
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/early_printk_intel_mid.c
+@@ -0,0 +1,637 @@
++/*
++ * early_printk_intel_mid.c - early consoles for Intel MID platforms
++ *
++ * Copyright (c) 2008-2010, Intel Corporation
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++/*
++ * Currently we have 3 types of early printk consoles: PTI, HSU and
++ * MAX3110 SPI-UART.
++ * PTI is available for mdfld, clv and mrfld.
++ * HSU is available for mdfld, clv and mrfld. But it depends on board design.
++ * Some boards don't have HSU UART pins routed to the connector so we can't
++ * use it.
++ * Max3110 SPI-UART is a stand-alone chip with SPI interface located in the
++ * debug card. Drivers can access to this chip via Soc's SPI controller or SSP
++ * controller(working in SPI mode).
++ * Max3110 is available for mrst, mdfld, clv and mrfld. But for mrst, mdfld
++ * and clv, MAX3110 is connected to SPI controller, for mrfld, MAX3110 is
++ * connected to SSP controller.
++ */
++
++#include <linux/serial_reg.h>
++#include <linux/serial_mfd.h>
++#include <linux/kmsg_dump.h>
++#include <linux/console.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/sched.h>
++#include <linux/hardirq.h>
++#include <linux/pti.h>
++
++#include <asm/fixmap.h>
++#include <asm/pgtable.h>
++#include <asm/intel-mid.h>
++
++#define MRST_SPI_TIMEOUT 0x200000
++#define MRST_REGBASE_SPI0 0xff128000
++#define MRST_REGBASE_SPI1 0xff128400
++#define CLV_REGBASE_SPI1 0xff135000
++#define MRST_CLK_SPI0_REG 0xff11d86c
++#define MRFLD_SSP_TIMEOUT 0x200000
++#define MRFLD_REGBASE_SSP5 0xff189000
++
++/* Bit fields in CTRLR0 */
++#define SPI_DFS_OFFSET 0
++
++#define SPI_FRF_OFFSET 4
++#define SPI_FRF_SPI 0x0
++#define SPI_FRF_SSP 0x1
++#define SPI_FRF_MICROWIRE 0x2
++#define SPI_FRF_RESV 0x3
++
++#define SPI_MODE_OFFSET 6
++#define SPI_SCPH_OFFSET 6
++#define SPI_SCOL_OFFSET 7
++#define SPI_TMOD_OFFSET 8
++#define SPI_TMOD_TR 0x0 /* xmit & recv */
++#define SPI_TMOD_TO 0x1 /* xmit only */
++#define SPI_TMOD_RO 0x2 /* recv only */
++#define SPI_TMOD_EPROMREAD 0x3 /* eeprom read mode */
++
++#define SPI_SLVOE_OFFSET 10
++#define SPI_SRL_OFFSET 11
++#define SPI_CFS_OFFSET 12
++
++/* Bit fields in SR, 7 bits */
++#define SR_MASK 0x7f /* cover 7 bits */
++#define SR_BUSY (1 << 0)
++#define SR_TF_NOT_FULL (1 << 1)
++#define SR_TF_EMPT (1 << 2)
++#define SR_RF_NOT_EMPT (1 << 3)
++#define SR_RF_FULL (1 << 4)
++#define SR_TX_ERR (1 << 5)
++#define SR_DCOL (1 << 6)
++
++/* SR bit fields for SSP*/
++#define SSP_SR_TF_NOT_FULL (1 << 2)
++
++static int ssp_timing_wr; /* Tangier A0 SSP timing workaround */
++
++static unsigned int early_pti_console_channel;
++static unsigned int early_pti_control_channel;
++
++/* SPI controller registers */
++struct dw_spi_reg {
++ u32 ctrl0;
++ u32 ctrl1;
++ u32 ssienr;
++ u32 mwcr;
++ u32 ser;
++ u32 baudr;
++ u32 txfltr;
++ u32 rxfltr;
++ u32 txflr;
++ u32 rxflr;
++ u32 sr;
++ u32 imr;
++ u32 isr;
++ u32 risr;
++ u32 txoicr;
++ u32 rxoicr;
++ u32 rxuicr;
++ u32 msticr;
++ u32 icr;
++ u32 dmacr;
++ u32 dmatdlr;
++ u32 dmardlr;
++ u32 idr;
++ u32 version;
++
++ /* Currently operates as 32 bits, though only the low 16 bits matter */
++ u32 dr;
++} __packed;
++
++/* SSP controler registers */
++struct dw_ssp_reg {
++ u32 ctrl0;
++ u32 ctrl1;
++ u32 sr;
++ u32 ssitr;
++ u32 dr;
++} __packed;
++
++#define dw_readl(dw, name) __raw_readl(&(dw)->name)
++#define dw_writel(dw, name, val) __raw_writel((val), &(dw)->name)
++
++/* Default use SPI0 register for mrst, we will detect Penwell and use SPI1 */
++static unsigned long mrst_spi_paddr = MRST_REGBASE_SPI0;
++
++static u32 *pclk_spi0;
++/* Always contains an accessible address, start with 0 */
++static struct dw_spi_reg *pspi;
++static struct dw_ssp_reg *pssp;
++
++static struct kmsg_dumper dw_dumper;
++static int dumper_registered;
++
++static void dw_kmsg_dump(struct kmsg_dumper *dumper,
++ enum kmsg_dump_reason reason)
++{
++ static char line[1024];
++ size_t len;
++
++ /* When run to this, we'd better re-init the HW */
++ mrst_early_console_init();
++
++ while (kmsg_dump_get_line(dumper, true, line, sizeof(line), &len))
++ early_mrst_console.write(&early_mrst_console, line, len);
++}
++
++/* Set the ratio rate to 115200, 8n1, IRQ disabled */
++static void max3110_spi_write_config(void)
++{
++ u16 config;
++
++ config = 0xc001;
++ dw_writel(pspi, dr, config);
++}
++
++/* Translate char to a eligible word and send to max3110 */
++static void max3110_spi_write_data(char c)
++{
++ u16 data;
++
++ data = 0x8000 | c;
++ dw_writel(pspi, dr, data);
++}
++
++/* similar to max3110_spi_write_config, but via SSP controller */
++static void max3110_ssp_write_config(void)
++{
++ u16 config;
++
++ config = 0xc001;
++ dw_writel(pssp, dr, config);
++ dw_readl(pssp, dr);
++ udelay(10);
++ return;
++}
++
++/* similar to max3110_spi_write_data, but via SSP controller */
++static void max3110_ssp_write_data(char c)
++{
++ u16 data;
++
++ data = 0x8000 | c;
++ dw_writel(pssp, dr, data);
++ dw_readl(pssp, dr);
++ udelay(10);
++ return;
++}
++
++void mrst_early_console_init(void)
++{
++ u32 ctrlr0 = 0;
++ u32 spi0_cdiv;
++ u32 freq; /* Freqency info only need be searched once */
++
++ /* Base clk is 100 MHz, the actual clk = 100M / (clk_divider + 1) */
++ pclk_spi0 = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,
++ MRST_CLK_SPI0_REG);
++ spi0_cdiv = ((*pclk_spi0) & 0xe00) >> 9;
++ freq = 100000000 / (spi0_cdiv + 1);
++
++ if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_PENWELL)
++ mrst_spi_paddr = MRST_REGBASE_SPI1;
++ else if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_CLOVERVIEW)
++ mrst_spi_paddr = CLV_REGBASE_SPI1;
++
++ pspi = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,
++ mrst_spi_paddr);
++
++ /* Disable SPI controller */
++ dw_writel(pspi, ssienr, 0);
++
++ /* Set control param, 8 bits, transmit only mode */
++ ctrlr0 = dw_readl(pspi, ctrl0);
++
++ ctrlr0 &= 0xfcc0;
++ ctrlr0 |= 0xf | (SPI_FRF_SPI << SPI_FRF_OFFSET)
++ | (SPI_TMOD_TO << SPI_TMOD_OFFSET);
++ dw_writel(pspi, ctrl0, ctrlr0);
++
++ /*
++ * Change the spi0 clk to comply with 115200 bps, use 100000 to
++ * calculate the clk dividor to make the clock a little slower
++ * than real baud rate.
++ */
++ dw_writel(pspi, baudr, freq/100000);
++
++ /* Disable all INT for early phase */
++ dw_writel(pspi, imr, 0x0);
++
++ /* Set the cs to spi-uart */
++ dw_writel(pspi, ser, 0x2);
++
++ /* Enable the HW, the last step for HW init */
++ dw_writel(pspi, ssienr, 0x1);
++
++ /* Set the default configuration */
++ max3110_spi_write_config();
++
++ /* Register the kmsg dumper */
++ if (!dumper_registered) {
++ dw_dumper.dump = dw_kmsg_dump;
++ kmsg_dump_register(&dw_dumper);
++ dumper_registered = 1;
++ }
++}
++
++/* Slave select should be called in the read/write function */
++static void early_mrst_spi_putc(char c)
++{
++ unsigned int timeout;
++ u32 sr;
++
++ timeout = MRST_SPI_TIMEOUT;
++ /* Early putc needs to make sure the TX FIFO is not full */
++ while (--timeout) {
++ sr = dw_readl(pspi, sr);
++ if (!(sr & SR_TF_NOT_FULL))
++ cpu_relax();
++ else
++ break;
++ }
++
++ if (!timeout)
++ pr_warn("MRST earlycon: timed out\n");
++ else
++ max3110_spi_write_data(c);
++}
++
++/* Early SPI only uses polling mode */
++static void early_mrst_spi_write(struct console *con, const char *str,
++ unsigned n)
++{
++ int i;
++
++ for (i = 0; i < n && *str; i++) {
++ if (*str == '\n')
++ early_mrst_spi_putc('\r');
++ early_mrst_spi_putc(*str);
++ str++;
++ }
++}
++
++struct console early_mrst_console = {
++ .name = "earlymrst",
++ .write = early_mrst_spi_write,
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
++};
++
++void mrfld_early_console_init(void)
++{
++ u32 ctrlr0 = 0;
++
++ set_fixmap_nocache(FIX_EARLYCON_MEM_BASE, MRFLD_REGBASE_SSP5);
++
++ pssp = (void *)(__fix_to_virt(FIX_EARLYCON_MEM_BASE) +
++ (MRFLD_REGBASE_SSP5 & (PAGE_SIZE - 1)));
++
++ if (intel_mid_identify_sim() == INTEL_MID_CPU_SIMULATION_NONE)
++ ssp_timing_wr = 1;
++
++ /* mask interrupts, clear enable and set DSS config */
++ /* SSPSCLK on active transfers only */
++ if (ssp_timing_wr) {
++ dw_writel(pssp, ctrl0, 0xc12c0f);
++ dw_writel(pssp, ctrl1, 0x0);
++ } else {
++ dw_writel(pssp, ctrl0, 0xc0000f);
++ dw_writel(pssp, ctrl1, 0x10000000);
++ }
++
++ dw_readl(pssp, sr);
++
++ /* enable port */
++ ctrlr0 = dw_readl(pssp, ctrl0);
++ ctrlr0 |= 0x80;
++ dw_writel(pssp, ctrl0, ctrlr0);
++}
++
++/* slave select should be called in the read/write function */
++static int early_mrfld_putc(char c)
++{
++ unsigned int timeout;
++ u32 sr;
++
++ timeout = MRFLD_SSP_TIMEOUT;
++ /* early putc need make sure the TX FIFO is not full*/
++ while (timeout--) {
++ sr = dw_readl(pssp, sr);
++ if (ssp_timing_wr) {
++ if (sr & 0xF00)
++ cpu_relax();
++ else
++ break;
++ } else {
++ if (!(sr & SSP_SR_TF_NOT_FULL))
++ cpu_relax();
++ else
++ break;
++ }
++ }
++
++ if (timeout == 0xffffffff) {
++ pr_info("SSP: waiting timeout\n");
++ return -1;
++ }
++
++ max3110_ssp_write_data(c);
++ return 0;
++}
++
++static void early_mrfld_write(struct console *con,
++ const char *str, unsigned n)
++{
++ int i;
++
++ for (i = 0; i < n && *str; i++) {
++ if (*str == '\n')
++ early_mrfld_putc('\r');
++ early_mrfld_putc(*str);
++
++ str++;
++ }
++}
++
++struct console early_mrfld_console = {
++ .name = "earlymrfld",
++ .write = early_mrfld_write,
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
++};
++
++void mrfld_early_printk(const char *fmt, ...)
++{
++ char buf[512];
++ int n;
++ va_list ap;
++
++ va_start(ap, fmt);
++ n = vscnprintf(buf, 512, fmt, ap);
++ va_end(ap);
++
++ early_mrfld_console.write(&early_mrfld_console, buf, n);
++}
++
++/*
++ * Following is the early console based on High Speed UART device.
++ */
++#define MERR_HSU_PORT_BASE 0xff010180
++#define MERR_HSU_CLK_CTL 0xff00b830
++#define MFLD_HSU_PORT_BASE 0xffa28080
++
++static void __iomem *phsu;
++
++void hsu_early_console_init(const char *s)
++{
++ unsigned long paddr, port = 0;
++ u8 lcr;
++ int *clkctl;
++
++ if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER) {
++ paddr = MERR_HSU_PORT_BASE;
++ clkctl = (int *)set_fixmap_offset_nocache(FIX_CLOCK_CTL,
++ MERR_HSU_CLK_CTL);
++ } else {
++ paddr = MFLD_HSU_PORT_BASE;
++ clkctl = NULL;
++ }
++
++ /*
++ * Select the early HSU console port if specified by user in the
++ * kernel command line.
++ */
++ if (*s && !kstrtoul(s, 10, &port))
++ port = clamp_val(port, 0, 2);
++
++ paddr += port * 0x80;
++ phsu = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE, paddr);
++
++ /* Disable FIFO */
++ writeb(0x0, phsu + UART_FCR);
++
++ /* Set to default 115200 bps, 8n1 */
++ lcr = readb(phsu + UART_LCR);
++ writeb((0x80 | lcr), phsu + UART_LCR);
++ writeb(0x01, phsu + UART_DLL);
++ writeb(0x00, phsu + UART_DLM);
++ writeb(lcr, phsu + UART_LCR);
++ writel(0x0010, phsu + UART_ABR * 4);
++ writel(0x0010, phsu + UART_PS * 4);
++
++ if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER) {
++ /* detect HSU clock is 50M or 19.2M */
++ if (clkctl && *clkctl & (1 << 16))
++ writel(0x0120, phsu + UART_MUL * 4); /* for 50M */
++ else
++ writel(0x05DC, phsu + UART_MUL * 4); /* for 19.2M */
++ } else
++ writel(0x0240, phsu + UART_MUL * 4);
++
++ writel(0x3D09, phsu + UART_DIV * 4);
++
++ writeb(0x8, phsu + UART_MCR);
++ writeb(0x7, phsu + UART_FCR);
++ writeb(0x3, phsu + UART_LCR);
++
++ /* Clear IRQ status */
++ readb(phsu + UART_LSR);
++ readb(phsu + UART_RX);
++ readb(phsu + UART_IIR);
++ readb(phsu + UART_MSR);
++
++ /* Enable FIFO */
++ writeb(0x7, phsu + UART_FCR);
++}
++
++#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
++
++static void early_hsu_putc(char ch)
++{
++ unsigned int timeout = 10000; /* 10ms */
++ u8 status;
++
++ while (--timeout) {
++ status = readb(phsu + UART_LSR);
++ if (status & BOTH_EMPTY)
++ break;
++ udelay(1);
++ }
++
++ /* Only write the char when there was no timeout */
++ if (timeout)
++ writeb(ch, phsu + UART_TX);
++}
++
++static void early_hsu_write(struct console *con, const char *str, unsigned n)
++{
++ int i;
++
++ for (i = 0; i < n && *str; i++) {
++ if (*str == '\n')
++ early_hsu_putc('\r');
++ early_hsu_putc(*str);
++ str++;
++ }
++}
++
++struct console early_hsu_console = {
++ .name = "earlyhsu",
++ .write = early_hsu_write,
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
++};
++
++void hsu_early_printk(const char *fmt, ...)
++{
++ char buf[512];
++ int n;
++ va_list ap;
++
++ va_start(ap, fmt);
++ n = vscnprintf(buf, 512, fmt, ap);
++ va_end(ap);
++
++ early_hsu_console.write(&early_hsu_console, buf, n);
++}
++
++#define PTI_ADDRESS 0xfd800000
++#define CONTROL_FRAME_LEN 32 /* PTI control frame maximum size */
++
++static void early_pti_write_to_aperture(struct pti_masterchannel *mc,
++ u8 *buf, int len)
++{
++ int dwordcnt, final, i;
++ u32 ptiword;
++ u8 *p ;
++ u32 pti_phys_address ;
++ u32 __iomem *aperture;
++
++ p = buf;
++
++ /*
++ calculate the aperture offset from the base using the master and
++ channel id's.
++ */
++ pti_phys_address = PTI_ADDRESS +
++ (mc->master << 15) + (mc->channel << 8);
++
++ set_fixmap_nocache(FIX_EARLYCON_MEM_BASE, pti_phys_address);
++ aperture = (void *)(__fix_to_virt(FIX_EARLYCON_MEM_BASE) +
++ (pti_phys_address & (PAGE_SIZE - 1)));
++
++ dwordcnt = len >> 2;
++ final = len - (dwordcnt << 2); /* final = trailing bytes */
++ if (final == 0 && dwordcnt != 0) { /* always have a final dword */
++ final += 4;
++ dwordcnt--;
++ }
++
++ for (i = 0; i < dwordcnt; i++) {
++ ptiword = be32_to_cpu(*(u32 *)p);
++ p += 4;
++ iowrite32(ptiword, aperture);
++ }
++
++ aperture += PTI_LASTDWORD_DTS; /* adding DTS signals that is EOM */
++ ptiword = 0;
++
++ for (i = 0; i < final; i++)
++ ptiword |= *p++ << (24-(8*i));
++
++ iowrite32(ptiword, aperture);
++
++ return;
++}
++
++static int pti_early_console_init(void)
++{
++ early_pti_console_channel = 0;
++ early_pti_control_channel = 0;
++ return 0;
++}
++
++static void early_pti_write(struct console *con,
++ const char *str, unsigned n)
++{
++ static struct pti_masterchannel mccontrol = {.master = 72,
++ .channel = 0};
++ static struct pti_masterchannel mcconsole = {.master = 73,
++ .channel = 0};
++ const char *control_format = "%3d %3d %s";
++
++ /*
++ * Since we access the comm member in current's task_struct,
++ * we only need to be as large as what 'comm' in that
++ * structure is.
++ */
++ char comm[TASK_COMM_LEN];
++ u8 control_frame[CONTROL_FRAME_LEN];
++
++ /* task information */
++ if (in_irq())
++ strncpy(comm, "hardirq", sizeof(comm));
++ else if (in_softirq())
++ strncpy(comm, "softirq", sizeof(comm));
++ else
++ strncpy(comm, current->comm, sizeof(comm));
++
++ /* Absolutely ensure our buffer is zero terminated */
++ comm[TASK_COMM_LEN-1] = 0;
++
++ mccontrol.channel = early_pti_control_channel;
++ early_pti_control_channel = (early_pti_control_channel + 1) & 0x7f;
++
++ mcconsole.channel = early_pti_console_channel;
++ early_pti_console_channel = (early_pti_console_channel + 1) & 0x7f;
++
++ snprintf(control_frame, CONTROL_FRAME_LEN, control_format,
++ mcconsole.master, mcconsole.channel, comm);
++
++ early_pti_write_to_aperture(&mccontrol, control_frame,
++ strlen(control_frame));
++ early_pti_write_to_aperture(&mcconsole, (u8 *)str, n);
++
++}
++
++struct console early_pti_console = {
++ .name = "earlypti",
++ .early_setup = pti_early_console_init,
++ .write = early_pti_write,
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
++};
++
++void pti_early_printk(const char *fmt, ...)
++{
++ char buf[512];
++ int n;
++ va_list ap;
++
++ va_start(ap, fmt);
++ n = vscnprintf(buf, sizeof(buf), fmt, ap);
++ va_end(ap);
++
++ early_pti_console.write(&early_pti_console, buf, n);
++}
+diff --git a/arch/x86/platform/intel-mid/intel-mid.c b/arch/x86/platform/intel-mid/intel-mid.c
+new file mode 100644
+index 0000000..a7635b3
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/intel-mid.c
+@@ -0,0 +1,239 @@
++/*
++ * intel-mid.c: Intel MID platform setup code
++ *
++ * (C) Copyright 2012 Intel Corporation
++ * Author: Jacob Pan (jacob.jun.pan@intel.com)
++ * Author: Sathyanarayanan KN(sathyanarayanan.kuppuswamy@intel.com)
++ *
++ * 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; version 2
++ * of the License.
++ */
++#define SFI_SIG_OEM0 "OEM0"
++#define pr_fmt(fmt) "intel_mid: " fmt
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/scatterlist.h>
++#include <linux/sfi.h>
++#include <linux/irq.h>
++#include <linux/module.h>
++#include <linux/notifier.h>
++#include <linux/spinlock.h>
++
++#include <asm/setup.h>
++#include <asm/mpspec_def.h>
++#include <asm/hw_irq.h>
++#include <asm/apic.h>
++#include <asm/io_apic.h>
++#include <asm/intel-mid.h>
++#include <asm/io.h>
++#include <asm/i8259.h>
++#include <asm/intel_scu_ipc.h>
++#include <asm/intel_mid_rpmsg.h>
++#include <asm/apb_timer.h>
++#include <asm/reboot.h>
++#include "intel_mid_weak_decls.h"
++#include "intel_soc_pmu.h"
++
++/*
++ * the clockevent devices on Moorestown/Medfield can be APBT or LAPIC clock,
++ * cmdline option x86_intel_mid_timer can be used to override the configuration
++ * to prefer one or the other.
++ * at runtime, there are basically three timer configurations:
++ * 1. per cpu apbt clock only
++ * 2. per cpu always-on lapic clocks only, this is Penwell/Medfield only
++ * 3. per cpu lapic clock (C3STOP) and one apbt clock, with broadcast.
++ *
++ * by default (without cmdline option), platform code first detects cpu type
++ * to see if we are on lincroft or penwell, then set up both lapic or apbt
++ * clocks accordingly.
++ * i.e. by default, medfield uses configuration #2, moorestown uses #1.
++ * config #3 is supported but not recommended on medfield.
++ *
++ * rating and feature summary:
++ * lapic (with C3STOP) --------- 100
++ * apbt (always-on) ------------ 110
++ * lapic (always-on,ARAT) ------ 150
++ */
++__cpuinitdata enum intel_mid_timer_options intel_mid_timer_options;
++
++/* intel_mid_ops to store sub arch ops */
++struct intel_mid_ops *intel_mid_ops;
++/* getter function for sub arch ops*/
++static void *(*get_intel_mid_ops[])(void) = INTEL_MID_OPS_INIT;
++enum intel_mid_cpu_type __intel_mid_cpu_chip;
++EXPORT_SYMBOL_GPL(__intel_mid_cpu_chip);
++
++static int force_cold_boot;
++module_param(force_cold_boot, int, 0644);
++MODULE_PARM_DESC(force_cold_boot,
++ "Set to Y to force a COLD BOOT instead of a COLD RESET "
++ "on the next reboot system call.");
++u32 nbr_hsi_clients = 2;
++static void intel_mid_power_off(void)
++{
++ pmu_power_off();
++};
++
++static void intel_mid_reboot(void)
++{
++ if (intel_scu_ipc_fw_update()) {
++ pr_debug("intel_scu_fw_update: IFWI upgrade failed...\n");
++ }
++ if (force_cold_boot)
++ rpmsg_send_generic_simple_command(IPCMSG_COLD_BOOT, 0);
++ else
++ rpmsg_send_generic_simple_command(IPCMSG_COLD_RESET, 0);
++}
++
++static unsigned long __init intel_mid_calibrate_tsc(void)
++{
++ return 0;
++}
++
++static void __init intel_mid_time_init(void)
++{
++
++#ifdef CONFIG_SFI
++ sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr);
++#endif
++ switch (intel_mid_timer_options) {
++ case INTEL_MID_TIMER_APBT_ONLY:
++ break;
++ case INTEL_MID_TIMER_LAPIC_APBT:
++ x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock;
++ x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock;
++ break;
++ default:
++ if (!boot_cpu_has(X86_FEATURE_ARAT))
++ break;
++ x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock;
++ x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock;
++ return;
++ }
++ /* we need at least one APB timer */
++ pre_init_apic_IRQ0();
++ apbt_time_init();
++}
++
++static void __cpuinit intel_mid_arch_setup(void)
++{
++ if (boot_cpu_data.x86 != 6) {
++ pr_err("Unknown Intel MID CPU (%d:%d), default to Penwell\n",
++ boot_cpu_data.x86, boot_cpu_data.x86_model);
++ __intel_mid_cpu_chip = INTEL_MID_CPU_CHIP_PENWELL;
++ return;
++ }
++ switch (boot_cpu_data.x86_model) {
++ case 0x35:
++ __intel_mid_cpu_chip = INTEL_MID_CPU_CHIP_CLOVERVIEW;
++ break;
++ case 0x3C:
++ case 0x4A:
++ __intel_mid_cpu_chip = INTEL_MID_CPU_CHIP_TANGIER;
++ break;
++ case 0x5A:
++ __intel_mid_cpu_chip = INTEL_MID_CPU_CHIP_ANNIEDALE;
++ break;
++ case 0x5D:
++ __intel_mid_cpu_chip = INTEL_MID_CPU_CHIP_CARBONCANYON;
++ break;
++ case 0x27:
++ default:
++ __intel_mid_cpu_chip = INTEL_MID_CPU_CHIP_PENWELL;
++ break;
++ }
++
++ if (__intel_mid_cpu_chip < MAX_CPU_OPS(get_intel_mid_ops))
++ intel_mid_ops = get_intel_mid_ops[__intel_mid_cpu_chip]();
++ else {
++ intel_mid_ops = get_intel_mid_ops[INTEL_MID_CPU_CHIP_PENWELL]();
++ pr_info("ARCH: Uknown SoC, assuming PENWELL!\n");
++ }
++
++ if (intel_mid_ops->arch_setup)
++ intel_mid_ops->arch_setup();
++}
++
++/* MID systems don't have i8042 controller */
++static int intel_mid_i8042_detect(void)
++{
++ return 0;
++}
++
++/*
++ * Moorestown does not have external NMI source nor port 0x61 to report
++ * NMI status. The possible NMI sources are from pmu as a result of NMI
++ * watchdog or lock debug. Reading io port 0x61 results in 0xff which
++ * misled NMI handler.
++ */
++static unsigned char intel_mid_get_nmi_reason(void)
++{
++ return 0;
++}
++
++/*
++ * Moorestown specific x86_init function overrides and early setup
++ * calls.
++ */
++void __init x86_intel_mid_early_setup(void)
++{
++ x86_init.resources.probe_roms = x86_init_noop;
++ x86_init.resources.reserve_resources = x86_init_noop;
++ x86_init.oem.arch_setup = intel_mid_arch_setup;
++ x86_init.timers.setup_percpu_clockev = x86_init_noop;
++ x86_cpuinit.setup_percpu_clockev = apbt_setup_secondary_clock;
++
++ x86_init.timers.timer_init = intel_mid_time_init;
++ x86_init.timers.setup_percpu_clockev = x86_init_noop;
++
++ x86_init.irqs.pre_vector_init = x86_init_noop;
++
++ x86_init.oem.arch_setup = intel_mid_arch_setup;
++
++ x86_cpuinit.setup_percpu_clockev = apbt_setup_secondary_clock;
++
++ x86_platform.calibrate_tsc = intel_mid_calibrate_tsc;
++ x86_platform.i8042_detect = intel_mid_i8042_detect;
++ x86_init.timers.wallclock_init = intel_mid_rtc_init;
++ x86_platform.get_nmi_reason = intel_mid_get_nmi_reason;
++
++ x86_init.pci.init = intel_mid_pci_init;
++ x86_init.pci.fixup_irqs = x86_init_noop;
++
++ legacy_pic = &null_legacy_pic;
++
++ pm_power_off = intel_mid_power_off;
++ machine_ops.emergency_restart = intel_mid_reboot;
++
++ /* Avoid searching for BIOS MP tables */
++ x86_init.mpparse.find_smp_config = x86_init_noop;
++ x86_init.mpparse.get_smp_config = x86_init_uint_noop;
++ set_bit(MP_BUS_ISA, mp_bus_not_pci);
++}
++
++/*
++ * if user does not want to use per CPU apb timer, just give it a lower rating
++ * than local apic timer and skip the late per cpu timer init.
++ */
++static inline int __init setup_x86_intel_mid_timer(char *arg)
++{
++ if (!arg)
++ return -EINVAL;
++
++ if (strcmp("apbt_only", arg) == 0)
++ intel_mid_timer_options = INTEL_MID_TIMER_APBT_ONLY;
++ else if (strcmp("lapic_and_apbt", arg) == 0)
++ intel_mid_timer_options = INTEL_MID_TIMER_LAPIC_APBT;
++ else {
++ pr_warn("X86 INTEL_MID timer option %s not recognised"
++ " use x86_intel_mid_timer=apbt_only or lapic_and_apbt\n",
++ arg);
++ return -EINVAL;
++ }
++ return 0;
++}
++__setup("x86_intel_mid_timer=", setup_x86_intel_mid_timer);
+diff --git a/arch/x86/platform/intel-mid/intel_mid_pcihelpers.c b/arch/x86/platform/intel-mid/intel_mid_pcihelpers.c
+new file mode 100644
+index 0000000..85d4be8
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/intel_mid_pcihelpers.c
+@@ -0,0 +1,105 @@
++#include <linux/export.h>
++#include <linux/pci.h>
++
++#include <asm/intel_mid_pcihelpers.h>
++
++/* Unified message bus read/write operation */
++static DEFINE_SPINLOCK(msgbus_lock);
++
++static struct pci_dev *pci_root;
++
++static int intel_mid_msgbus_init(void)
++{
++ pci_root = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0));
++ if (!pci_root) {
++ printk(KERN_ALERT "%s: Error: msgbus PCI handle NULL",
++ __func__);
++ return -ENODEV;
++ }
++ return 0;
++}
++fs_initcall(intel_mid_msgbus_init);
++
++u32 intel_mid_msgbus_read32_raw(u32 cmd)
++{
++ unsigned long irq_flags;
++ u32 data;
++
++ spin_lock_irqsave(&msgbus_lock, irq_flags);
++ pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd);
++ pci_read_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG, &data);
++ spin_unlock_irqrestore(&msgbus_lock, irq_flags);
++
++ return data;
++}
++EXPORT_SYMBOL(intel_mid_msgbus_read32_raw);
++
++void intel_mid_msgbus_write32_raw(u32 cmd, u32 data)
++{
++ unsigned long irq_flags;
++
++ spin_lock_irqsave(&msgbus_lock, irq_flags);
++ pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG, data);
++ pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd);
++ spin_unlock_irqrestore(&msgbus_lock, irq_flags);
++}
++EXPORT_SYMBOL(intel_mid_msgbus_write32_raw);
++
++u32 intel_mid_msgbus_read32(u8 port, u32 addr)
++{
++ unsigned long irq_flags;
++ u32 data;
++ u32 cmd;
++ u32 cmdext;
++
++ cmd = (PCI_ROOT_MSGBUS_READ << 24) | (port << 16) |
++ ((addr & 0xff) << 8) | PCI_ROOT_MSGBUS_DWORD_ENABLE;
++ cmdext = addr & 0xffffff00;
++
++ spin_lock_irqsave(&msgbus_lock, irq_flags);
++
++ if (cmdext) {
++ /* This resets to 0 automatically, no need to write 0 */
++ pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_EXT_REG,
++ cmdext);
++ }
++
++ pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd);
++ pci_read_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG, &data);
++ spin_unlock_irqrestore(&msgbus_lock, irq_flags);
++
++ return data;
++}
++
++EXPORT_SYMBOL(intel_mid_msgbus_read32);
++void intel_mid_msgbus_write32(u8 port, u32 addr, u32 data)
++{
++ unsigned long irq_flags;
++ u32 cmd;
++ u32 cmdext;
++
++ cmd = (PCI_ROOT_MSGBUS_WRITE << 24) | (port << 16) |
++ ((addr & 0xFF) << 8) | PCI_ROOT_MSGBUS_DWORD_ENABLE;
++ cmdext = addr & 0xffffff00;
++
++ spin_lock_irqsave(&msgbus_lock, irq_flags);
++ pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG, data);
++
++ if (cmdext) {
++ /* This resets to 0 automatically, no need to write 0 */
++ pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_EXT_REG,
++ cmdext);
++ }
++
++ pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd);
++ spin_unlock_irqrestore(&msgbus_lock, irq_flags);
++}
++EXPORT_SYMBOL(intel_mid_msgbus_write32);
++
++/* called only from where is later then fs_initcall */
++u32 intel_mid_soc_stepping(void)
++{
++ return pci_root->revision;
++}
++EXPORT_SYMBOL(intel_mid_soc_stepping);
++
+diff --git a/arch/x86/platform/intel-mid/intel_mid_scu.c b/arch/x86/platform/intel-mid/intel_mid_scu.c
+new file mode 100644
+index 0000000..a8e633c
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/intel_mid_scu.c
+@@ -0,0 +1,92 @@
++/*
++ * intel_mid_scu.c: Intel MID SCU platform initialization code
++ *
++ * (C) Copyright 2012 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/scatterlist.h>
++#include <linux/sfi.h>
++#include <linux/intel_pmic_gpio.h>
++#include <linux/irq.h>
++#include <linux/rpmsg.h>
++#include <linux/module.h>
++#include <linux/list.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++
++#include <linux/platform_data/intel_mid_remoteproc.h>
++
++struct rpmsg_ns_list nslist = {
++ .list = LIST_HEAD_INIT(nslist.list),
++ .lock = __MUTEX_INITIALIZER(nslist.lock),
++};
++
++static struct intel_mid_rproc_pdata intel_scu_pdata = {
++ .name = "intel_rproc_scu",
++ .firmware = "intel_mid/intel_mid_remoteproc.fw",
++ .nslist = &nslist,
++};
++
++static u64 intel_scu_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device intel_scu_device = {
++ .name = "intel_rproc_scu",
++ .id = -1,
++ .dev = {
++ .platform_data = &intel_scu_pdata,
++ .dma_mask = &intel_scu_dmamask,
++ },
++};
++
++void register_rpmsg_service(char *name, int id, u32 addr)
++{
++ struct rpmsg_ns_info *info;
++ info = rpmsg_ns_alloc(name, id, addr);
++ rpmsg_ns_add_to_list(info, &nslist);
++}
++
++int intel_mid_rproc_init(void)
++{
++ int err;
++
++ /* generic rpmsg channels */
++ register_rpmsg_service("rpmsg_ipc_command", RPROC_SCU, RP_IPC_COMMAND);
++ register_rpmsg_service("rpmsg_ipc_simple_command",
++ RPROC_SCU, RP_IPC_SIMPLE_COMMAND);
++ register_rpmsg_service("rpmsg_ipc_raw_command",
++ RPROC_SCU, RP_IPC_RAW_COMMAND);
++
++ register_rpmsg_service("rpmsg_pmic", RPROC_SCU, RP_PMIC_ACCESS);
++ register_rpmsg_service("rpmsg_mip", RPROC_SCU, RP_MIP_ACCESS);
++ register_rpmsg_service("rpmsg_fw_update",
++ RPROC_SCU, RP_FW_ACCESS);
++ register_rpmsg_service("rpmsg_ipc_util",
++ RPROC_SCU, RP_IPC_UTIL);
++ register_rpmsg_service("rpmsg_flis", RPROC_SCU, RP_FLIS_ACCESS);
++ register_rpmsg_service("rpmsg_watchdog", RPROC_SCU, RP_SET_WATCHDOG);
++ register_rpmsg_service("rpmsg_umip", RPROC_SCU, RP_UMIP_ACCESS);
++ register_rpmsg_service("rpmsg_osip", RPROC_SCU, RP_OSIP_ACCESS);
++ register_rpmsg_service("rpmsg_vrtc", RPROC_SCU, RP_VRTC);
++ register_rpmsg_service("rpmsg_fw_logging", RPROC_SCU, RP_FW_LOGGING);
++ register_rpmsg_service("rpmsg_kpd_led", RPROC_SCU,
++ RP_MSIC_KPD_LED);
++ register_rpmsg_service("rpmsg_modem_nvram", RPROC_SCU,
++ RP_IPC_RAW_COMMAND);
++ register_rpmsg_service("rpmsg_mid_pwm", RPROC_SCU,
++ RP_MSIC_PWM);
++
++ err = platform_device_register(&intel_scu_device);
++ if (err < 0)
++ pr_err("Fail to register intel-mid-rproc platform device.\n");
++
++ return 0;
++}
++arch_initcall_sync(intel_mid_rproc_init);
+diff --git a/arch/x86/platform/intel-mid/intel_mid_scu.h b/arch/x86/platform/intel-mid/intel_mid_scu.h
+new file mode 100644
+index 0000000..0601fe9
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/intel_mid_scu.h
+@@ -0,0 +1,15 @@
++/*
++ * intel_mid_scu.h: SCU initialization header file
++ *
++ * (C) Copyright 2012 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++#ifndef _INTEL_MID_SCU_H_
++#define _INTEL_MID_SCU_H_
++extern int intel_mid_rproc_init(void) __attribute__((weak));
++#endif
+diff --git a/arch/x86/platform/intel-mid/intel_mid_sfi.c b/arch/x86/platform/intel-mid/intel_mid_sfi.c
+new file mode 100644
+index 0000000..41f98c4
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/intel_mid_sfi.c
+@@ -0,0 +1,588 @@
++/*
++ * intel_mid_sfi.c: Intel MID SFI initialization code
++ *
++ * (C) Copyright 2012 Intel Corporation
++ * Author: Sathyanarayanan KN
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/scatterlist.h>
++#include <linux/sfi.h>
++#include <linux/intel_pmic_gpio.h>
++#include <linux/spi/spi.h>
++#include <linux/i2c.h>
++#include <linux/skbuff.h>
++#include <linux/gpio.h>
++#include <linux/gpio_keys.h>
++#include <linux/input.h>
++#include <linux/platform_device.h>
++#include <linux/irq.h>
++#include <linux/module.h>
++#include <linux/notifier.h>
++#include <linux/mmc/core.h>
++#include <linux/mmc/card.h>
++#include <linux/blkdev.h>
++
++#include <asm/setup.h>
++#include <asm/mpspec_def.h>
++#include <asm/hw_irq.h>
++#include <asm/apic.h>
++#include <asm/io_apic.h>
++#include <asm/intel-mid.h>
++#include <asm/intel_mid_vrtc.h>
++#include <asm/io.h>
++#include <asm/i8259.h>
++#include <asm/intel_scu_ipc.h>
++#include <asm/apb_timer.h>
++#include <asm/reboot.h>
++#include "intel_mid_weak_decls.h"
++
++#define SFI_SIG_OEM0 "OEM0"
++#define MAX_IPCDEVS 24
++#define MAX_SCU_SPI 24
++#define MAX_SCU_I2C 24
++
++static struct platform_device *ipc_devs[MAX_IPCDEVS];
++static struct spi_board_info *spi_devs[MAX_SCU_SPI];
++static struct i2c_board_info *i2c_devs[MAX_SCU_I2C];
++static struct sfi_gpio_table_entry *gpio_table;
++static struct sfi_timer_table_entry sfi_mtimer_array[SFI_MTMR_MAX_NUM];
++static int ipc_next_dev;
++static int spi_next_dev;
++static int i2c_next_dev;
++static int i2c_bus[MAX_SCU_I2C];
++static int gpio_num_entry;
++static u32 sfi_mtimer_usage[SFI_MTMR_MAX_NUM];
++int sfi_mrtc_num;
++int sfi_mtimer_num;
++
++struct sfi_rtc_table_entry sfi_mrtc_array[SFI_MRTC_MAX];
++EXPORT_SYMBOL_GPL(sfi_mrtc_array);
++
++struct blocking_notifier_head intel_scu_notifier =
++ BLOCKING_NOTIFIER_INIT(intel_scu_notifier);
++EXPORT_SYMBOL_GPL(intel_scu_notifier);
++
++/* parse all the mtimer info to a static mtimer array */
++int __init sfi_parse_mtmr(struct sfi_table_header *table)
++{
++ struct sfi_table_simple *sb;
++ struct sfi_timer_table_entry *pentry;
++ struct mpc_intsrc mp_irq;
++ int totallen;
++
++ sb = (struct sfi_table_simple *)table;
++ if (!sfi_mtimer_num) {
++ sfi_mtimer_num = SFI_GET_NUM_ENTRIES(sb,
++ struct sfi_timer_table_entry);
++ pentry = (struct sfi_timer_table_entry *) sb->pentry;
++ totallen = sfi_mtimer_num * sizeof(*pentry);
++ memcpy(sfi_mtimer_array, pentry, totallen);
++ }
++
++ pr_debug("SFI MTIMER info (num = %d):\n", sfi_mtimer_num);
++ pentry = sfi_mtimer_array;
++ for (totallen = 0; totallen < sfi_mtimer_num; totallen++, pentry++) {
++ pr_debug("timer[%d]: paddr = 0x%08x, freq = %dHz, irq = %d\n",
++ totallen, (u32)pentry->phys_addr,
++ pentry->freq_hz, pentry->irq);
++ if (!pentry->irq)
++ continue;
++ mp_irq.type = MP_INTSRC;
++ mp_irq.irqtype = mp_INT;
++/* triggering mode edge bit 2-3, active high polarity bit 0-1 */
++ mp_irq.irqflag = 5;
++ mp_irq.srcbus = MP_BUS_ISA;
++ mp_irq.srcbusirq = pentry->irq; /* IRQ */
++ mp_irq.dstapic = MP_APIC_ALL;
++ mp_irq.dstirq = pentry->irq;
++ mp_save_irq(&mp_irq);
++ }
++
++ return 0;
++}
++
++struct sfi_timer_table_entry *sfi_get_mtmr(int hint)
++{
++ int i;
++ if (hint < sfi_mtimer_num) {
++ if (!sfi_mtimer_usage[hint]) {
++ pr_debug("hint taken for timer %d irq %d\n",
++ hint, sfi_mtimer_array[hint].irq);
++ sfi_mtimer_usage[hint] = 1;
++ return &sfi_mtimer_array[hint];
++ }
++ }
++ /* take the first timer available */
++ for (i = 0; i < sfi_mtimer_num;) {
++ if (!sfi_mtimer_usage[i]) {
++ sfi_mtimer_usage[i] = 1;
++ return &sfi_mtimer_array[i];
++ }
++ i++;
++ }
++ return NULL;
++}
++
++void sfi_free_mtmr(struct sfi_timer_table_entry *mtmr)
++{
++ int i;
++ for (i = 0; i < sfi_mtimer_num;) {
++ if (mtmr->irq == sfi_mtimer_array[i].irq) {
++ sfi_mtimer_usage[i] = 0;
++ return;
++ }
++ i++;
++ }
++}
++
++/* parse all the mrtc info to a global mrtc array */
++int __init sfi_parse_mrtc(struct sfi_table_header *table)
++{
++ struct sfi_table_simple *sb;
++ struct sfi_rtc_table_entry *pentry;
++ struct mpc_intsrc mp_irq;
++
++ int totallen;
++
++ sb = (struct sfi_table_simple *)table;
++ if (!sfi_mrtc_num) {
++ sfi_mrtc_num = SFI_GET_NUM_ENTRIES(sb,
++ struct sfi_rtc_table_entry);
++ pentry = (struct sfi_rtc_table_entry *)sb->pentry;
++ totallen = sfi_mrtc_num * sizeof(*pentry);
++ memcpy(sfi_mrtc_array, pentry, totallen);
++ }
++
++ pr_debug("SFI RTC info (num = %d):\n", sfi_mrtc_num);
++ pentry = sfi_mrtc_array;
++ for (totallen = 0; totallen < sfi_mrtc_num; totallen++, pentry++) {
++ pr_debug("RTC[%d]: paddr = 0x%08x, irq = %d\n",
++ totallen, (u32)pentry->phys_addr, pentry->irq);
++ mp_irq.type = MP_INTSRC;
++ mp_irq.irqtype = mp_INT;
++ mp_irq.irqflag = 0xf; /* level trigger and active low */
++ mp_irq.srcbus = MP_BUS_ISA;
++ mp_irq.srcbusirq = pentry->irq; /* IRQ */
++ mp_irq.dstapic = MP_APIC_ALL;
++ mp_irq.dstirq = pentry->irq;
++ mp_save_irq(&mp_irq);
++ }
++ return 0;
++}
++
++
++/*
++ * Parsing GPIO table first, since the DEVS table will need this table
++ * to map the pin name to the actual pin.
++ */
++static int __init sfi_parse_gpio(struct sfi_table_header *table)
++{
++ struct sfi_table_simple *sb;
++ struct sfi_gpio_table_entry *pentry;
++ int num, i;
++
++ if (gpio_table)
++ return 0;
++ sb = (struct sfi_table_simple *)table;
++ num = SFI_GET_NUM_ENTRIES(sb, struct sfi_gpio_table_entry);
++ pentry = (struct sfi_gpio_table_entry *)sb->pentry;
++
++ gpio_table = (struct sfi_gpio_table_entry *)
++ kmalloc(num * sizeof(*pentry), GFP_KERNEL);
++ if (!gpio_table)
++ return -1;
++ memcpy(gpio_table, pentry, num * sizeof(*pentry));
++ gpio_num_entry = num;
++
++ pr_debug("GPIO pin info:\n");
++ for (i = 0; i < num; i++, pentry++)
++ pr_debug("info[%2d]: controller = %16.16s, pin_name = %16.16s,"
++ " pin = %d\n", i,
++ pentry->controller_name,
++ pentry->pin_name,
++ pentry->pin_no);
++ return 0;
++}
++
++int get_gpio_by_name(const char *name)
++{
++ struct sfi_gpio_table_entry *pentry = gpio_table;
++ int i;
++
++ if (!pentry)
++ return -1;
++ for (i = 0; i < gpio_num_entry; i++, pentry++) {
++ if (!strncmp(name, pentry->pin_name, SFI_NAME_LEN))
++ return pentry->pin_no;
++ }
++ return -1;
++}
++
++void __init intel_scu_device_register(struct platform_device *pdev)
++{
++ if (ipc_next_dev == MAX_IPCDEVS)
++ pr_err("too many SCU IPC devices");
++ else
++ ipc_devs[ipc_next_dev++] = pdev;
++}
++
++static void __init intel_scu_spi_device_register(struct spi_board_info *sdev)
++{
++ struct spi_board_info *new_dev;
++
++ if (spi_next_dev == MAX_SCU_SPI) {
++ pr_err("too many SCU SPI devices");
++ return;
++ }
++
++ new_dev = kzalloc(sizeof(*sdev), GFP_KERNEL);
++ if (!new_dev) {
++ pr_err("failed to alloc mem for delayed spi dev %s\n",
++ sdev->modalias);
++ return;
++ }
++ memcpy(new_dev, sdev, sizeof(*sdev));
++
++ spi_devs[spi_next_dev++] = new_dev;
++}
++
++static void __init intel_scu_i2c_device_register(int bus,
++ struct i2c_board_info *idev)
++{
++ struct i2c_board_info *new_dev;
++
++ if (i2c_next_dev == MAX_SCU_I2C) {
++ pr_err("too many SCU I2C devices");
++ return;
++ }
++
++ new_dev = kzalloc(sizeof(*idev), GFP_KERNEL);
++ if (!new_dev) {
++ pr_err("failed to alloc mem for delayed i2c dev %s\n",
++ idev->type);
++ return;
++ }
++ memcpy(new_dev, idev, sizeof(*idev));
++
++ i2c_bus[i2c_next_dev] = bus;
++ i2c_devs[i2c_next_dev++] = new_dev;
++}
++
++/* Called by IPC driver */
++void intel_scu_devices_create(void)
++{
++ int i;
++
++ for (i = 0; i < ipc_next_dev; i++)
++ platform_device_add(ipc_devs[i]);
++
++ for (i = 0; i < spi_next_dev; i++)
++ spi_register_board_info(spi_devs[i], 1);
++
++ for (i = 0; i < i2c_next_dev; i++) {
++ struct i2c_adapter *adapter;
++ struct i2c_client *client;
++
++ adapter = i2c_get_adapter(i2c_bus[i]);
++ if (adapter) {
++ client = i2c_new_device(adapter, i2c_devs[i]);
++ if (!client)
++ pr_err("can't create i2c device %s\n",
++ i2c_devs[i]->type);
++ } else
++ i2c_register_board_info(i2c_bus[i], i2c_devs[i], 1);
++ }
++ intel_scu_notifier_post(SCU_AVAILABLE, NULL);
++}
++EXPORT_SYMBOL_GPL(intel_scu_devices_create);
++
++/* Called by IPC driver */
++void intel_scu_devices_destroy(void)
++{
++ int i;
++
++ intel_scu_notifier_post(SCU_DOWN, NULL);
++
++ for (i = 0; i < ipc_next_dev; i++)
++ platform_device_del(ipc_devs[i]);
++}
++EXPORT_SYMBOL_GPL(intel_scu_devices_destroy);
++
++void __init install_irq_resource(struct platform_device *pdev, int irq)
++{
++ /* Single threaded */
++ static struct resource __initdata res = {
++ .name = "IRQ",
++ .flags = IORESOURCE_IRQ,
++ };
++ res.start = irq;
++ platform_device_add_resources(pdev, &res, 1);
++}
++
++static void __init sfi_handle_ipc_dev(struct sfi_device_table_entry *pentry,
++ struct devs_id *dev)
++{
++ struct platform_device *pdev;
++ void *pdata = NULL;
++ pr_info("IPC bus, name = %16.16s, irq = 0x%2x\n",
++ pentry->name, pentry->irq);
++ pdata = dev->get_platform_data(pentry);
++ pdev = platform_device_alloc(pentry->name, 0);
++ if (pdev == NULL) {
++ pr_err("out of memory for SFI platform device '%s'.\n",
++ pentry->name);
++ return;
++ }
++ install_irq_resource(pdev, pentry->irq);
++
++ pdev->dev.platform_data = pdata;
++ intel_scu_device_register(pdev);
++}
++
++static void __init sfi_handle_spi_dev(struct sfi_device_table_entry *pentry,
++ struct devs_id *dev)
++{
++ struct spi_board_info spi_info;
++ void *pdata = NULL;
++
++ memset(&spi_info, 0, sizeof(spi_info));
++ strncpy(spi_info.modalias, pentry->name, SFI_NAME_LEN);
++ spi_info.irq = ((pentry->irq == (u8)0xff) ? 0 : pentry->irq);
++ spi_info.bus_num = pentry->host_num;
++ spi_info.chip_select = pentry->addr;
++ spi_info.max_speed_hz = pentry->max_freq;
++ pr_info("SPI bus=%d, name=%16.16s, irq=0x%2x, max_freq=%d, cs=%d\n",
++ spi_info.bus_num,
++ spi_info.modalias,
++ spi_info.irq,
++ spi_info.max_speed_hz,
++ spi_info.chip_select);
++
++ pdata = dev->get_platform_data(&spi_info);
++
++ spi_info.platform_data = pdata;
++ if (dev->delay)
++ intel_scu_spi_device_register(&spi_info);
++ else
++ spi_register_board_info(&spi_info, 1);
++}
++
++static void __init sfi_handle_i2c_dev(struct sfi_device_table_entry *pentry,
++ struct devs_id *dev)
++{
++ struct i2c_board_info i2c_info;
++ void *pdata = NULL;
++
++ memset(&i2c_info, 0, sizeof(i2c_info));
++ strncpy(i2c_info.type, pentry->name, SFI_NAME_LEN);
++ i2c_info.irq = ((pentry->irq == (u8)0xff) ? 0 : pentry->irq);
++ i2c_info.addr = pentry->addr;
++ pr_info("I2C bus = %d, name = %16.16s, irq = 0x%2x, addr = 0x%x\n",
++ pentry->host_num,
++ i2c_info.type,
++ i2c_info.irq,
++ i2c_info.addr);
++ pdata = dev->get_platform_data(&i2c_info);
++ i2c_info.platform_data = pdata;
++
++ if (dev->delay)
++ intel_scu_i2c_device_register(pentry->host_num, &i2c_info);
++ else
++ i2c_register_board_info(pentry->host_num, &i2c_info, 1);
++}
++
++static void __init sfi_handle_sd_dev(struct sfi_device_table_entry *pentry,
++ struct devs_id *dev)
++{
++ struct sd_board_info sd_info;
++ void *pdata = NULL;
++
++ memset(&sd_info, 0, sizeof(sd_info));
++ strncpy(sd_info.name, pentry->name, 16);
++ sd_info.bus_num = pentry->host_num;
++ sd_info.board_ref_clock = pentry->max_freq;
++ sd_info.addr = pentry->addr;
++ pr_info("SDIO bus = %d, name = %16.16s, "
++ "ref_clock = %d, addr =0x%x\n",
++ sd_info.bus_num,
++ sd_info.name,
++ sd_info.board_ref_clock,
++ sd_info.addr);
++ pdata = dev->get_platform_data(&sd_info);
++ sd_info.platform_data = pdata;
++}
++
++struct devs_id __init *get_device_id(u8 type, char *name)
++{
++ struct devs_id *dev = device_ids;
++
++ if (device_ids == NULL)
++ return NULL;
++
++ while (dev->name[0]) {
++ if (dev->type == type &&
++ !strncmp(dev->name, name, SFI_NAME_LEN)) {
++ return dev;
++ }
++ dev++;
++ }
++
++ return NULL;
++}
++
++static int __init sfi_parse_devs(struct sfi_table_header *table)
++{
++ struct sfi_table_simple *sb;
++ struct sfi_device_table_entry *pentry;
++ struct devs_id *dev = NULL;
++ int num, i;
++ int ioapic;
++ struct io_apic_irq_attr irq_attr;
++
++ sb = (struct sfi_table_simple *)table;
++ num = SFI_GET_NUM_ENTRIES(sb, struct sfi_device_table_entry);
++ pentry = (struct sfi_device_table_entry *)sb->pentry;
++
++ for (i = 0; i < num; i++, pentry++) {
++ int irq = pentry->irq;
++
++ if (irq != (u8)0xff) { /* native RTE case */
++ /* these SPI2 devices are not exposed to system as PCI
++ * devices, but they have separate RTE entry in IOAPIC
++ * so we have to enable them one by one here
++ */
++ ioapic = mp_find_ioapic(irq);
++ if (ioapic >= 0) {
++ irq_attr.ioapic = ioapic;
++ irq_attr.ioapic_pin = irq;
++ irq_attr.trigger = 1;
++ if (intel_mid_identify_cpu() ==
++ INTEL_MID_CPU_CHIP_TANGIER) {
++ if (!strncmp(pentry->name,
++ "r69001-ts-i2c", 13))
++ /* active low */
++ irq_attr.polarity = 1;
++ else if (!strncmp(pentry->name,
++ "synaptics_3202", 14))
++ /* active low */
++ irq_attr.polarity = 1;
++ else if (irq == 41)
++ /* fast_int_1 */
++ irq_attr.polarity = 1;
++ else
++ /* active high */
++ irq_attr.polarity = 0;
++ } else {
++ /* PNW and CLV go with active low */
++ irq_attr.polarity = 1;
++ }
++ io_apic_set_pci_routing(NULL, irq, &irq_attr);
++ } else
++ printk(KERN_INFO "APIC entry not found for: name=%s, irq=%d, ioapic=%d\n",
++ pentry->name, irq, ioapic);
++ }
++ dev = get_device_id(pentry->type, pentry->name);
++
++ if ((dev == NULL) || (dev->get_platform_data == NULL))
++ continue;
++
++ if (dev->device_handler) {
++ dev->device_handler(pentry, dev);
++ } else {
++ switch (pentry->type) {
++ case SFI_DEV_TYPE_IPC:
++ sfi_handle_ipc_dev(pentry, dev);
++ break;
++ case SFI_DEV_TYPE_SPI:
++ sfi_handle_spi_dev(pentry, dev);
++ break;
++ case SFI_DEV_TYPE_I2C:
++ sfi_handle_i2c_dev(pentry, dev);
++ break;
++ case SFI_DEV_TYPE_SD:
++ sfi_handle_sd_dev(pentry, dev);
++ break;
++ case SFI_DEV_TYPE_HSI:
++ case SFI_DEV_TYPE_UART:
++ default:
++ break;
++ }
++ }
++ }
++
++ return 0;
++}
++
++static int __init sfi_parse_oemb(struct sfi_table_header *table)
++{
++ struct sfi_table_oemb *oemb;
++ u32 board_id;
++ u8 sig[SFI_SIGNATURE_SIZE + 1] = {'\0'};
++ u8 oem_id[SFI_OEM_ID_SIZE + 1] = {'\0'};
++ u8 oem_table_id[SFI_OEM_TABLE_ID_SIZE + 1] = {'\0'};
++
++ oemb = (struct sfi_table_oemb *) table;
++ if (!oemb) {
++ pr_err("%s: fail to read SFI OEMB Layout\n",
++ __func__);
++ return -ENODEV;
++ }
++
++ board_id = oemb->board_id | (oemb->board_fab << 4);
++
++ snprintf(sig, (SFI_SIGNATURE_SIZE + 1), "%s", oemb->header.sig);
++ snprintf(oem_id, (SFI_OEM_ID_SIZE + 1), "%s", oemb->header.oem_id);
++ snprintf(oem_table_id, (SFI_OEM_TABLE_ID_SIZE + 1), "%s",
++ oemb->header.oem_table_id);
++ pr_info("SFI OEMB Layout\n");
++ pr_info("\tOEMB signature : %s\n"
++ "\tOEMB length : %d\n"
++ "\tOEMB revision : %d\n"
++ "\tOEMB checksum : 0x%X\n"
++ "\tOEMB oem_id : %s\n"
++ "\tOEMB oem_table_id : %s\n"
++ "\tOEMB board_id : 0x%02X\n"
++ "\tOEMB iafw version : %03d.%03d\n"
++ "\tOEMB val_hooks version : %03d.%03d\n"
++ "\tOEMB ia suppfw version : %03d.%03d\n"
++ "\tOEMB scu runtime version : %03d.%03d\n"
++ "\tOEMB ifwi version : %03d.%03d\n",
++ sig,
++ oemb->header.len,
++ oemb->header.rev,
++ oemb->header.csum,
++ oem_id,
++ oem_table_id,
++ board_id,
++ oemb->iafw_major_version,
++ oemb->iafw_main_version,
++ oemb->val_hooks_major_version,
++ oemb->val_hooks_minor_version,
++ oemb->ia_suppfw_major_version,
++ oemb->ia_suppfw_minor_version,
++ oemb->scu_runtime_major_version,
++ oemb->scu_runtime_minor_version,
++ oemb->ifwi_major_version,
++ oemb->ifwi_minor_version
++ );
++ return 0;
++}
++
++static int __init intel_mid_platform_init(void)
++{
++ /* Get SFI OEMB Layout */
++ sfi_table_parse(SFI_SIG_OEMB, NULL, NULL, sfi_parse_oemb);
++ sfi_table_parse(SFI_SIG_GPIO, NULL, NULL, sfi_parse_gpio);
++ sfi_table_parse(SFI_SIG_DEVS, NULL, NULL, sfi_parse_devs);
++
++ return 0;
++}
++arch_initcall(intel_mid_platform_init);
+diff --git a/arch/x86/platform/intel-mid/intel_mid_vrtc.c b/arch/x86/platform/intel-mid/intel_mid_vrtc.c
+new file mode 100644
+index 0000000..80f3edd
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/intel_mid_vrtc.c
+@@ -0,0 +1,169 @@
++/*
++ * intel_mid_vrtc.c: Driver for virtual RTC device on Intel MID platform
++ *
++ * (C) Copyright 2009 Intel Corporation
++ *
++ * 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; version 2
++ * of the License.
++ *
++ * Note:
++ * VRTC is emulated by system controller firmware, the real HW
++ * RTC is located in the PMIC device. SCU FW shadows PMIC RTC
++ * in a memory mapped IO space that is visible to the host IA
++ * processor.
++ *
++ * This driver is based on RTC CMOS driver.
++ */
++
++#include <linux/kernel.h>
++#include <linux/export.h>
++#include <linux/init.h>
++#include <linux/sfi.h>
++#include <linux/platform_device.h>
++
++#include <asm/intel-mid.h>
++#include <asm/intel_mid_vrtc.h>
++#include <asm/time.h>
++#include <asm/fixmap.h>
++
++static unsigned char __iomem *vrtc_virt_base;
++
++unsigned char vrtc_cmos_read(unsigned char reg)
++{
++ unsigned char retval;
++
++ /* vRTC's registers range from 0x0 to 0xD */
++ if (reg > 0xd || !vrtc_virt_base)
++ return 0xff;
++
++ lock_cmos_prefix(reg);
++ retval = __raw_readb(vrtc_virt_base + (reg << 2));
++ lock_cmos_suffix(reg);
++ return retval;
++}
++EXPORT_SYMBOL_GPL(vrtc_cmos_read);
++
++void vrtc_cmos_write(unsigned char val, unsigned char reg)
++{
++ if (reg > 0xd || !vrtc_virt_base)
++ return;
++
++ lock_cmos_prefix(reg);
++ __raw_writeb(val, vrtc_virt_base + (reg << 2));
++ lock_cmos_suffix(reg);
++}
++EXPORT_SYMBOL_GPL(vrtc_cmos_write);
++
++unsigned long vrtc_get_time(void)
++{
++ u8 sec, min, hour, mday, mon;
++ unsigned long flags;
++ u32 year;
++
++ spin_lock_irqsave(&rtc_lock, flags);
++
++ while ((vrtc_cmos_read(RTC_FREQ_SELECT) & RTC_UIP))
++ cpu_relax();
++
++ sec = vrtc_cmos_read(RTC_SECONDS);
++ min = vrtc_cmos_read(RTC_MINUTES);
++ hour = vrtc_cmos_read(RTC_HOURS);
++ mday = vrtc_cmos_read(RTC_DAY_OF_MONTH);
++ mon = vrtc_cmos_read(RTC_MONTH);
++ year = vrtc_cmos_read(RTC_YEAR);
++
++ spin_unlock_irqrestore(&rtc_lock, flags);
++
++ /* vRTC YEAR reg contains the offset to 1972 */
++ year += 1972;
++
++ pr_info("vRTC: sec: %d min: %d hour: %d day: %d "
++ "mon: %d year: %d\n", sec, min, hour, mday, mon, year);
++
++ return mktime(year, mon, mday, hour, min, sec);
++}
++
++/* Only care about the minutes and seconds */
++int vrtc_set_mmss(unsigned long nowtime)
++{
++ int real_sec, real_min;
++ unsigned long flags;
++ int vrtc_min;
++
++ spin_lock_irqsave(&rtc_lock, flags);
++ vrtc_min = vrtc_cmos_read(RTC_MINUTES);
++
++ real_sec = nowtime % 60;
++ real_min = nowtime / 60;
++ if (((abs(real_min - vrtc_min) + 15)/30) & 1)
++ real_min += 30;
++ real_min %= 60;
++
++ vrtc_cmos_write(real_sec, RTC_SECONDS);
++ vrtc_cmos_write(real_min, RTC_MINUTES);
++ spin_unlock_irqrestore(&rtc_lock, flags);
++
++ return 0;
++}
++
++void __init intel_mid_rtc_init(void)
++{
++ unsigned long vrtc_paddr;
++
++ sfi_table_parse(SFI_SIG_MRTC, NULL, NULL, sfi_parse_mrtc);
++
++ vrtc_paddr = sfi_mrtc_array[0].phys_addr;
++ if (!sfi_mrtc_num || !vrtc_paddr)
++ return;
++
++ vrtc_virt_base = (void __iomem *)set_fixmap_offset_nocache(FIX_LNW_VRTC,
++ vrtc_paddr);
++ x86_platform.get_wallclock = vrtc_get_time;
++ x86_platform.set_wallclock = vrtc_set_mmss;
++}
++
++/*
++ * The Moorestown platform has a memory mapped virtual RTC device that emulates
++ * the programming interface of the RTC.
++ */
++
++static struct resource vrtc_resources[] = {
++ [0] = {
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .flags = IORESOURCE_IRQ,
++ }
++};
++
++static struct platform_device vrtc_device = {
++ .name = "rtc_mrst",
++ .id = -1,
++ .resource = vrtc_resources,
++ .num_resources = ARRAY_SIZE(vrtc_resources),
++};
++
++/* Register the RTC device if appropriate */
++static int __init intel_mid_device_create(void)
++{
++ /* No Moorestown, no device */
++ if (!intel_mid_identify_cpu())
++ return -ENODEV;
++ /* No timer, no device */
++ if (!sfi_mrtc_num)
++ return -ENODEV;
++
++ /* iomem resource */
++ vrtc_resources[0].start = sfi_mrtc_array[0].phys_addr;
++ vrtc_resources[0].end = sfi_mrtc_array[0].phys_addr +
++ MRST_VRTC_MAP_SZ;
++ /* irq resource */
++ vrtc_resources[1].start = sfi_mrtc_array[0].irq;
++ vrtc_resources[1].end = sfi_mrtc_array[0].irq;
++
++ return platform_device_register(&vrtc_device);
++}
++
++module_init(intel_mid_device_create);
+diff --git a/arch/x86/platform/intel-mid/intel_mid_weak_decls.h b/arch/x86/platform/intel-mid/intel_mid_weak_decls.h
+new file mode 100644
+index 0000000..015bf42
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/intel_mid_weak_decls.h
+@@ -0,0 +1,22 @@
++/*
++ * intel_mid_weak_decls.h: Weak declarations of intel-mid.c
++ *
++ * (C) Copyright 2012 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++
++/* __attribute__((weak)) makes these declarations overridable */
++extern struct devs_id __initconst device_ids[] __attribute__((weak));
++/* For every CPU addition a new get_<cpuname>_ops interface needs
++ * to be added.
++ */
++extern void * __init get_penwell_ops(void) __attribute__((weak));
++extern void * __init get_cloverview_ops(void) __attribute__((weak));
++extern void * __init get_tangier_ops(void) __attribute__((weak));
++extern void * __init get_anniedale_ops(void) __attribute__((weak));
+diff --git a/arch/x86/platform/intel-mid/intel_soc_clv.c b/arch/x86/platform/intel-mid/intel_soc_clv.c
+new file mode 100644
+index 0000000..76303b1
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/intel_soc_clv.c
+@@ -0,0 +1,146 @@
++/*
++ * intel_soc_clv.c - This driver provides utility api's for
++ * Cloverview platform
++ * Copyright (c) 2012, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#include "intel_soc_pmu.h"
++
++
++static unsigned short fastonoff_flag;
++
++static ssize_t fastonoff_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return sprintf(buf, "%hu\n", fastonoff_flag);
++}
++
++static ssize_t fastonoff_store(struct kobject *kobj,
++ struct kobj_attribute *attr, const char *buf, size_t n)
++{
++ unsigned short value;
++ if (sscanf(buf, "%hu", &value) != 1 ||
++ (value != 0 && value != 1)) {
++ printk(KERN_ERR "fastonoff_store: Invalid value\n");
++ return -EINVAL;
++ }
++ fastonoff_flag = value;
++ return n;
++}
++
++static struct kobj_attribute fast_onoff_attr =
++ __ATTR(fastonoff, 0644, fastonoff_show, fastonoff_store);
++
++
++static void clv_init_sysfsfs(void)
++{
++ int error;
++ error = sysfs_create_file(power_kobj, &fast_onoff_attr.attr);
++ if (error)
++ printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
++}
++
++static int clv_pmu_init(void)
++{
++ mid_pmu_cxt->s3_hint = C6_HINT;
++ clv_init_sysfsfs();
++ return 0;
++}
++
++static bool clv_pmu_enter(int s0ix_state)
++{
++ u32 s0ix_value;
++ int num_retry = PMU_MISC_SET_TIMEOUT;
++
++ if (fastonoff_flag && (s0ix_state == MID_S3_STATE))
++ s0ix_value = get_s0ix_val_set_pm_ssc(MID_FAST_ON_OFF_STATE);
++ else
++ s0ix_value = get_s0ix_val_set_pm_ssc(s0ix_state);
++
++ /* issue a command to SCU */
++ pmu_set_interrupt_enable();
++ writel(s0ix_value, &mid_pmu_cxt->pmu_reg->pm_cmd);
++
++ do {
++ if (readl(&mid_pmu_cxt->pmu_reg->pm_msic))
++ break;
++ udelay(1);
++ } while (--num_retry);
++
++ if (!num_retry && !readl(&mid_pmu_cxt->pmu_reg->pm_msic))
++ WARN(1, "%s: pm_msic not set.\n", __func__);
++
++ mid_pmu_cxt->s0ix_entered = s0ix_state;
++
++ return true;
++}
++
++static void clv_pmu_remove(void)
++{
++ /* Place holder */
++}
++
++static void clv_pmu_wakeup(void)
++{
++
++ /* Wakeup allother CPU's */
++ if (mid_pmu_cxt->s0ix_entered)
++ apic->send_IPI_allbutself(RESCHEDULE_VECTOR);
++}
++
++static pci_power_t clv_pmu_choose_state(int device_lss)
++{
++ pci_power_t state;
++
++ switch (device_lss) {
++ case PMU_SECURITY_LSS_04:
++ state = PCI_D2;
++ break;
++
++ case PMU_USB_OTG_LSS_06:
++ case PMU_USB_HSIC_LSS_07:
++ case PMU_UART2_LSS_41:
++ state = PCI_D1;
++ break;
++
++ default:
++ state = PCI_D3hot;
++ break;
++ }
++
++ return state;
++}
++
++/**
++ * platform_set_pmu_ops - Set the global pmu method table.
++ * @ops: Pointer to ops structure.
++ */
++void platform_set_pmu_ops(void)
++{
++ pmu_ops = &clv_pmu_ops;
++}
++
++struct platform_pmu_ops clv_pmu_ops = {
++ .init = clv_pmu_init,
++ .enter = clv_pmu_enter,
++ .wakeup = clv_pmu_wakeup,
++ .remove = clv_pmu_remove,
++ .pci_choose_state = clv_pmu_choose_state,
++ .set_power_state_ops = pmu_set_s0ix_possible,
++ .set_s0ix_complete = s0ix_complete,
++ .nc_set_power_state = mdfld_clv_nc_set_power_state,
++};
+diff --git a/arch/x86/platform/intel-mid/intel_soc_clv.h b/arch/x86/platform/intel-mid/intel_soc_clv.h
+new file mode 100644
+index 0000000..0b8294e
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/intel_soc_clv.h
+@@ -0,0 +1,352 @@
++/*
++ * intel_soc_clv.h
++ * Copyright (c) 2012, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#ifdef CONFIG_REMOVEME_INTEL_ATOM_CLV_POWER
++
++#define PM_SUPPORT 0x21
++
++#define ISP_POS 7
++#define ISP_SUB_CLASS 0x80
++#define PMU_MISC_SET_TIMEOUT 15000
++
++#define PMU1_MAX_DEVS 8
++#define PMU2_MAX_DEVS 55
++
++#define GFX_LSS_INDEX 1
++#define PMU_SDIO0_LSS_00 0
++#define PMU_EMMC0_LSS_01 1
++#define PMU_AONT_LSS_02 2
++#define PMU_HSI_LSS_03 3
++#define PMU_SECURITY_LSS_04 4
++#define PMU_EMMC1_LSS_05 5
++#define PMU_USB_OTG_LSS_06 6
++#define PMU_USB_HSIC_LSS_07 7
++#define PMU_AUDIO_ENGINE_LSS_08 8
++#define PMU_AUDIO_DMA_LSS_09 9
++#define PMU_SRAM_LSS_10 10
++#define PMU_SRAM_LSS_11 11
++#define PMU_SRAM_LSS_12 12
++#define PMU_SRAM_LSS_13 13
++#define PMU_SDIO2_LSS_14 14
++#define PMU_PTI_DAFCA_LSS_15 15
++#define PMU_SC_DMA_LSS_16 16
++#define PMU_SPIO_LSS_17 17
++#define PMU_SPI1_LSS_18 18
++#define PMU_SPI2_LSS_19 19
++#define PMU_I2C0_LSS_20 20
++#define PMU_I2C1_LSS_21 21
++#define PMU_HPET_LSS_22 22
++#define PMU_EXTTMR_LSS_23 23
++#define PMU_SC_FABRIC_LSS_24 24
++#define PMU_AUDIO_RAM_LSS_25 25
++#define PMU_SCU_ROM_LSS_26 26
++#define PMU_I2C2_LSS_27 27
++#define PMU_SSC_LSS_28 28
++#define PMU_SECURITY_LSS_29 29
++#define PMU_SDIO1_LSS_30 30
++#define PMU_vRTC_LSS_31 31
++#define PMU_SEC_TIMER_LSS_32 32
++#define PMU_I2C3_LSS_33 33
++#define PMU_I2C4_LSS_34 34
++#define PMU_I2C5_LSS_35 35
++#define PMU_SPI3_LSS_36 36
++#define PMU_GPIO1_LSS_37 37
++#define PMU_PWR_BUTTON_LSS_38 38
++#define PMU_GPIO0_LSS_39 39
++#define PMU_KEYBRD_LSS_40 40
++#define PMU_UART2_LSS_41 41
++#define PMU_ADC_LSS_42 42
++#define PMU_CHARGER_LSS_43 43
++#define PMU_SEC_TAPC_LSS_44 44
++#define PMU_RTC_LSS_45 45
++#define PMU_GPI_LSS_46 46
++#define PMU_BCU_LSS_47 47
++#define PMU_SSP2_LSS_48 48
++#define PMU_AUDIO_SLIM1_LSS_49 49
++#define PMU_AUDIO_SLIM2_LSS_50 50
++#define PMU_AUDIO_SSP0_LSS_51 51
++#define PMU_AUDIO_SSP1_LSS_52 52
++#define PMU_IOSF_OCP_BRG_LSS_53 53
++#define PMU_GP_DMA_LSS_54 54
++#define PMU_MSIC_RESET_LSS_55 55
++#define PMU_SOC_FUSE_LSS_56 56
++#define PMU_RSVD3_LSS_57 57
++#define PMU_SSP4_LSS_58 58
++#define PMU_RSVD5_LSS_59 59
++#define PMU_RSVD6_LSS_60 60
++#define PMU_RSVD7_LSS_61 61
++#define PMU_RSVD8_LSS_62 62
++#define PMU_RSVD9_LSS_63 63
++
++#define PMU_MAX_LSS 63
++#define PMU_LSS_IN_FIRST_DWORD 32
++
++#define EMMC0_LSS PMU_EMMC0_LSS_01
++
++#define S0IX_TARGET_SSS0_MASK ( \
++ SSMSK(D0I3_MASK, PMU_SDIO0_LSS_00) | \
++ SSMSK(D0I3_MASK, PMU_EMMC0_LSS_01) | \
++ SSMSK(D0I3_MASK, PMU_HSI_LSS_03) | \
++ SSMSK(D0I3_MASK, PMU_SECURITY_LSS_04) | \
++ SSMSK(D0I3_MASK, PMU_EMMC1_LSS_05) | \
++ SSMSK(D0I3_MASK, PMU_USB_OTG_LSS_06) | \
++ SSMSK(D0I3_MASK, PMU_USB_HSIC_LSS_07) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_ENGINE_LSS_08) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_DMA_LSS_09) | \
++ SSMSK(D0I3_MASK, PMU_SDIO2_LSS_14))
++
++#define S0IX_TARGET_SSS1_MASK ( \
++ SSMSK(D0I3_MASK, PMU_SPI1_LSS_18-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C0_LSS_20-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C1_LSS_21-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C2_LSS_27-16) | \
++ SSMSK(D0I3_MASK, PMU_SDIO1_LSS_30-16))
++#define S0IX_TARGET_SSS2_MASK ( \
++ SSMSK(D0I3_MASK, PMU_I2C3_LSS_33-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C4_LSS_34-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C5_LSS_35-32) | \
++ SSMSK(D0I3_MASK, PMU_SPI3_LSS_36-32) | \
++ SSMSK(D0I3_MASK, PMU_UART2_LSS_41-32))
++
++#define S0IX_TARGET_SSS3_MASK ( \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP0_LSS_51-48) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP1_LSS_52-48))
++
++#define S0IX_TARGET_SSS0 ( \
++ SSMSK(D0I3_MASK, PMU_SDIO0_LSS_00) | \
++ SSMSK(D0I3_MASK, PMU_EMMC0_LSS_01) | \
++ SSMSK(D0I3_MASK, PMU_HSI_LSS_03) | \
++ SSMSK(D0I2_MASK, PMU_SECURITY_LSS_04) | \
++ SSMSK(D0I3_MASK, PMU_EMMC1_LSS_05) | \
++ SSMSK(D0I1_MASK, PMU_USB_OTG_LSS_06) | \
++ SSMSK(D0I1_MASK, PMU_USB_HSIC_LSS_07) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_ENGINE_LSS_08) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_DMA_LSS_09) | \
++ SSMSK(D0I3_MASK, PMU_SDIO2_LSS_14))
++
++#define S0IX_TARGET_SSS1 ( \
++ SSMSK(D0I3_MASK, PMU_SPI1_LSS_18-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C0_LSS_20-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C1_LSS_21-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C2_LSS_27-16) | \
++ SSMSK(D0I3_MASK, PMU_SDIO1_LSS_30-16))
++
++#define S0IX_TARGET_SSS2 ( \
++ SSMSK(D0I3_MASK, PMU_I2C3_LSS_33-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C4_LSS_34-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C5_LSS_35-32) | \
++ SSMSK(D0I3_MASK, PMU_SPI3_LSS_36-32) | \
++ SSMSK(D0I1_MASK, PMU_UART2_LSS_41-32))
++
++#define S0IX_TARGET_SSS3 ( \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP0_LSS_51-48) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP1_LSS_52-48))
++
++#define LPMP3_TARGET_SSS0_MASK ( \
++ SSMSK(D0I3_MASK, PMU_SDIO0_LSS_00) | \
++ SSMSK(D0I3_MASK, PMU_EMMC0_LSS_01) | \
++ SSMSK(D0I3_MASK, PMU_HSI_LSS_03) | \
++ SSMSK(D0I3_MASK, PMU_SECURITY_LSS_04) | \
++ SSMSK(D0I3_MASK, PMU_EMMC1_LSS_05) | \
++ SSMSK(D0I3_MASK, PMU_USB_OTG_LSS_06) | \
++ SSMSK(D0I3_MASK, PMU_USB_HSIC_LSS_07) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_ENGINE_LSS_08) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_DMA_LSS_09) | \
++ SSMSK(D0I3_MASK, PMU_SDIO2_LSS_14))
++
++#define LPMP3_TARGET_SSS1_MASK ( \
++ SSMSK(D0I3_MASK, PMU_SPI1_LSS_18-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C0_LSS_20-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C1_LSS_21-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C2_LSS_27-16) | \
++ SSMSK(D0I3_MASK, PMU_SDIO1_LSS_30-16))
++
++#define LPMP3_TARGET_SSS2_MASK ( \
++ SSMSK(D0I3_MASK, PMU_I2C3_LSS_33-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C4_LSS_34-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C5_LSS_35-32) | \
++ SSMSK(D0I3_MASK, PMU_SPI3_LSS_36-32) | \
++ SSMSK(D0I3_MASK, PMU_UART2_LSS_41-32))
++
++#define LPMP3_TARGET_SSS3_MASK ( \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP0_LSS_51-48) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP1_LSS_52-48))
++
++#define LPMP3_TARGET_SSS0 ( \
++ SSMSK(D0I3_MASK, PMU_SDIO0_LSS_00) | \
++ SSMSK(D0I3_MASK, PMU_EMMC0_LSS_01) | \
++ SSMSK(D0I3_MASK, PMU_HSI_LSS_03) | \
++ SSMSK(D0I2_MASK, PMU_SECURITY_LSS_04) | \
++ SSMSK(D0I3_MASK, PMU_EMMC1_LSS_05) | \
++ SSMSK(D0I1_MASK, PMU_USB_OTG_LSS_06) | \
++ SSMSK(D0I1_MASK, PMU_USB_HSIC_LSS_07) | \
++ SSMSK(D0I0_MASK, PMU_AUDIO_ENGINE_LSS_08) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_DMA_LSS_09) | \
++ SSMSK(D0I3_MASK, PMU_SDIO2_LSS_14))
++
++#define LPMP3_TARGET_SSS1 ( \
++ SSMSK(D0I3_MASK, PMU_SPI1_LSS_18-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C0_LSS_20-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C1_LSS_21-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C2_LSS_27-16) | \
++ SSMSK(D0I3_MASK, PMU_SDIO1_LSS_30-16))
++
++#define LPMP3_TARGET_SSS2 ( \
++ SSMSK(D0I3_MASK, PMU_I2C3_LSS_33-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C4_LSS_34-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C5_LSS_35-32) | \
++ SSMSK(D0I3_MASK, PMU_SPI3_LSS_36-32) | \
++ SSMSK(D0I1_MASK, PMU_UART2_LSS_41-32))
++
++#define LPMP3_TARGET_SSS3 ( \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP0_LSS_51-48) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP1_LSS_52-48))
++
++#define IGNORE_SSS0 ( \
++ SSMSK(D0I3_MASK, PMU_SRAM_LSS_10) | \
++ SSMSK(D0I3_MASK, PMU_SRAM_LSS_11) | \
++ SSMSK(D0I3_MASK, PMU_SRAM_LSS_12) | \
++ SSMSK(D0I3_MASK, PMU_SRAM_LSS_13) | \
++ SSMSK(D0I3_MASK, PMU_PTI_DAFCA_LSS_15))
++
++#define IGNORE_SSS1 ( \
++ SSMSK(D0I3_MASK, PMU_SC_DMA_LSS_16-16) | \
++ SSMSK(D0I3_MASK, PMU_SPIO_LSS_17-16) | \
++ SSMSK(D0I3_MASK, PMU_HPET_LSS_22-16) | \
++ SSMSK(D0I3_MASK, PMU_EXTTMR_LSS_23-16) | \
++ SSMSK(D0I3_MASK, PMU_SC_FABRIC_LSS_24-16) | \
++ SSMSK(D0I3_MASK, PMU_SCU_ROM_LSS_26-16) | \
++ SSMSK(D0I3_MASK, PMU_SSC_LSS_28-16) | \
++ SSMSK(D0I3_MASK, PMU_SECURITY_LSS_29-16) | \
++ SSMSK(D0I3_MASK, PMU_vRTC_LSS_31-16))
++
++#define IGNORE_SSS2 ( \
++ SSMSK(D0I3_MASK, PMU_SEC_TIMER_LSS_32-32) | \
++ SSMSK(D0I3_MASK, PMU_GPIO1_LSS_37-32) | \
++ SSMSK(D0I3_MASK, PMU_PWR_BUTTON_LSS_38-32) | \
++ SSMSK(D0I3_MASK, PMU_GPIO0_LSS_39-32) | \
++ SSMSK(D0I3_MASK, PMU_ADC_LSS_42-32) | \
++ SSMSK(D0I3_MASK, PMU_CHARGER_LSS_43-32) | \
++ SSMSK(D0I3_MASK, PMU_SEC_TAPC_LSS_44-32) | \
++ SSMSK(D0I3_MASK, PMU_RTC_LSS_45-32) | \
++ SSMSK(D0I3_MASK, PMU_GPI_LSS_46-32) | \
++ SSMSK(D0I3_MASK, PMU_BCU_LSS_47-32))
++
++#define IGNORE_SSS3 ( \
++ SSMSK(D0I3_MASK, PMU_IOSF_OCP_BRG_LSS_53-48) | \
++ SSMSK(D0I3_MASK, PMU_MSIC_RESET_LSS_55-48) | \
++ SSMSK(D0I3_MASK, PMU_SOC_FUSE_LSS_56-48) | \
++ SSMSK(D0I3_MASK, PMU_RSVD3_LSS_57-48) | \
++ SSMSK(D0I3_MASK, PMU_SSP4_LSS_58-48) | \
++ SSMSK(D0I3_MASK, PMU_RSVD5_LSS_59-48) | \
++ SSMSK(D0I3_MASK, PMU_RSVD6_LSS_60-48) | \
++ SSMSK(D0I3_MASK, PMU_RSVD7_LSS_61-48) | \
++ SSMSK(D0I3_MASK, PMU_RSVD8_LSS_62-48) | \
++ SSMSK(D0I3_MASK, PMU_RSVD9_LSS_63-48))
++
++#define IGNORE_S3_WKC0 SSWKC(PMU_AONT_LSS_02)
++#define IGNORE_S3_WKC1 SSWKC(PMU_ADC_LSS_42-32)
++
++/* FIXME:: CVT Platform gives SRAM Error if SRAM is put in D0i3 */
++#define S0I3_SSS0 ( \
++ SSMSK(D0I3_MASK, PMU_SDIO0_LSS_00) | \
++ SSMSK(D0I3_MASK, PMU_EMMC0_LSS_01) | \
++ SSMSK(D0I3_MASK, PMU_AONT_LSS_02) | \
++ SSMSK(D0I3_MASK, PMU_HSI_LSS_03) | \
++ SSMSK(D0I2_MASK, PMU_SECURITY_LSS_04) | \
++ SSMSK(D0I3_MASK, PMU_EMMC1_LSS_05) | \
++ SSMSK(D0I1_MASK, PMU_USB_OTG_LSS_06) | \
++ SSMSK(D0I1_MASK, PMU_USB_HSIC_LSS_07) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_ENGINE_LSS_08) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_DMA_LSS_09) | \
++ SSMSK(D0I3_MASK, PMU_SDIO2_LSS_14))
++
++#define S0I3_SSS1 ( \
++ SSMSK(D0I3_MASK, PMU_SPI1_LSS_18-16) | \
++ SSMSK(D0I3_MASK, PMU_SPI2_LSS_19-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C0_LSS_20-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C1_LSS_21-16) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_RAM_LSS_25-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C2_LSS_27-16) | \
++ SSMSK(D0I3_MASK, PMU_SDIO1_LSS_30-16))
++
++#define S0I3_SSS2 ( \
++ SSMSK(D0I3_MASK, PMU_I2C3_LSS_33-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C4_LSS_34-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C5_LSS_35-32) | \
++ SSMSK(D0I3_MASK, PMU_SPI3_LSS_36-32) | \
++ SSMSK(D0I3_MASK, PMU_GPIO1_LSS_37-32) | \
++ SSMSK(D0I3_MASK, PMU_PWR_BUTTON_LSS_38-32) | \
++ SSMSK(D0I3_MASK, PMU_KEYBRD_LSS_40-32) | \
++ SSMSK(D0I1_MASK, PMU_UART2_LSS_41-32))
++
++#define S0I3_SSS3 ( \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SLIM1_LSS_49-48) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SLIM2_LSS_50-48) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP0_LSS_51-48) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP1_LSS_52-48) | \
++ SSMSK(D0I3_MASK, PMU_GP_DMA_LSS_54-48))
++
++#define S0I1_SSS0 S0I3_SSS0
++#define S0I1_SSS1 S0I3_SSS1
++#define S0I1_SSS2 S0I3_SSS2
++#define S0I1_SSS3 S0I3_SSS3
++
++#define LPMP3_SSS0 ( \
++ SSMSK(D0I3_MASK, PMU_SDIO0_LSS_00) | \
++ SSMSK(D0I3_MASK, PMU_EMMC0_LSS_01) | \
++ SSMSK(D0I3_MASK, PMU_AONT_LSS_02) | \
++ SSMSK(D0I3_MASK, PMU_HSI_LSS_03) | \
++ SSMSK(D0I2_MASK, PMU_SECURITY_LSS_04) | \
++ SSMSK(D0I3_MASK, PMU_EMMC1_LSS_05) | \
++ SSMSK(D0I1_MASK, PMU_USB_OTG_LSS_06) | \
++ SSMSK(D0I1_MASK, PMU_USB_HSIC_LSS_07) | \
++ SSMSK(D0I3_MASK, PMU_SDIO2_LSS_14))
++
++#define LPMP3_SSS1 ( \
++ SSMSK(D0I3_MASK, PMU_SPI1_LSS_18-16) | \
++ SSMSK(D0I3_MASK, PMU_SPI2_LSS_19-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C0_LSS_20-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C1_LSS_21-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C2_LSS_27-16) | \
++ SSMSK(D0I3_MASK, PMU_SDIO1_LSS_30-16))
++
++#define LPMP3_SSS2 ( \
++ SSMSK(D0I3_MASK, PMU_I2C3_LSS_33-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C4_LSS_34-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C5_LSS_35-32) | \
++ SSMSK(D0I3_MASK, PMU_SPI3_LSS_36-32) | \
++ SSMSK(D0I3_MASK, PMU_GPIO1_LSS_37-32) | \
++ SSMSK(D0I3_MASK, PMU_PWR_BUTTON_LSS_38-32) | \
++ SSMSK(D0I3_MASK, PMU_KEYBRD_LSS_40-32) | \
++ SSMSK(D0I1_MASK, PMU_UART2_LSS_41-32))
++
++#define LPMP3_SSS3 ( \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SLIM1_LSS_49-48) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SLIM2_LSS_50-48) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP0_LSS_51-48) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP1_LSS_52-48) | \
++ SSMSK(D0I3_MASK, PMU_GP_DMA_LSS_54-48))
++
++extern void pmu_set_s0ix_possible(int state);
++extern void log_wakeup_irq(void);
++extern void s0ix_complete(void);
++extern int mdfld_clv_nc_set_power_state(int, int, int, int *);
++
++#endif
+diff --git a/arch/x86/platform/intel-mid/intel_soc_debug.c b/arch/x86/platform/intel-mid/intel_soc_debug.c
+new file mode 100644
+index 0000000..d824e59
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/intel_soc_debug.c
+@@ -0,0 +1,202 @@
++/*
++ * intel_soc_debug.c - This driver provides utility debug api's
++ * Copyright (c) 2013, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, 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/types.h>
++#include <linux/debugfs.h>
++#include <linux/seq_file.h>
++#include <asm/intel-mid.h>
++#include <asm/intel_soc_debug.h>
++
++/* This module currently only supports Intel Tangier
++ * and Anniedale SOCs (CONFIG_INTEL_DEBUG_FEATURE will
++ * only be set in i386_mrfl_defconfig and i386_moor_defconfig).
++ * In addition, a platform check is done in soc_debug_init()
++ * to make sure that this module is only used by appropriate
++ * platforms.
++ */
++#define PGRR_BASE 0xff03a0bc
++#define MAX_MODE_NUMBER 9
++#define MAX_DEBUG_NUMBER 5
++
++static struct dentry *dfs_entry;
++
++enum pgrr_mode {
++ manufacturing_mode = 0x0F,
++ production_mode = 0x07,
++ intel_production_mode = 0x04,
++ oem_production_mode = 0x05,
++ gfx_production_mode = 0x0E,
++ end_user_mode = 0x0B,
++ intel_end_user_mode = 0x08,
++ rma_mode = 0x03,
++ permanent_mode = 0x00
++};
++
++static struct debug_mode {
++ enum pgrr_mode mode;
++ u32 bitmask;
++ char *name;
++} asset_array[] = {
++ { manufacturing_mode,
++ DEBUG_FEATURE_PTI | DEBUG_FEATURE_RTIT | DEBUG_FEATURE_USB3DFX |
++ DEBUG_FEATURE_SOCHAPS | DEBUG_FEATURE_LAKEMORE,
++ "ManufacturingMode",
++ },
++ { production_mode,
++ DEBUG_FEATURE_SOCHAPS | DEBUG_FEATURE_LAKEMORE,
++ "ProductionMode",
++ },
++ { intel_production_mode,
++ DEBUG_FEATURE_PTI | DEBUG_FEATURE_RTIT | DEBUG_FEATURE_USB3DFX |
++ DEBUG_FEATURE_SOCHAPS | DEBUG_FEATURE_LAKEMORE,
++ "IntelProductionMode",
++ },
++ { oem_production_mode,
++ DEBUG_FEATURE_PTI | DEBUG_FEATURE_RTIT | DEBUG_FEATURE_USB3DFX |
++ DEBUG_FEATURE_SOCHAPS | DEBUG_FEATURE_LAKEMORE,
++ "OemProductionMode",
++ },
++ { gfx_production_mode,
++ DEBUG_FEATURE_SOCHAPS | DEBUG_FEATURE_LAKEMORE,
++ "GfxProductionMode",
++ },
++ { intel_end_user_mode,
++ DEBUG_FEATURE_PTI | DEBUG_FEATURE_RTIT | DEBUG_FEATURE_USB3DFX |
++ DEBUG_FEATURE_SOCHAPS | DEBUG_FEATURE_LAKEMORE,
++ "IntelEndUserMode",
++ },
++ { end_user_mode,
++ DEBUG_FEATURE_SOCHAPS | DEBUG_FEATURE_LAKEMORE,
++ "EndUserMode",
++ },
++ { rma_mode,
++ DEBUG_FEATURE_PTI | DEBUG_FEATURE_RTIT | DEBUG_FEATURE_USB3DFX |
++ DEBUG_FEATURE_SOCHAPS | DEBUG_FEATURE_LAKEMORE,
++ "RmaMode",
++ },
++ { permanent_mode,
++ DEBUG_FEATURE_SOCHAPS | DEBUG_FEATURE_LAKEMORE,
++ "PermanentMode",
++ }
++};
++
++static int debug_mode_idx; /* index in asset_array */
++
++static struct debug_feature {
++ u32 bit;
++ char *name;
++} debug_feature_array[] = {
++ { DEBUG_FEATURE_PTI,
++ "PTI",
++ },
++ { DEBUG_FEATURE_RTIT,
++ "RTIT",
++ },
++ { DEBUG_FEATURE_LAKEMORE,
++ "LAKERMORE",
++ },
++ { DEBUG_FEATURE_SOCHAPS,
++ "SOCHAPS",
++ },
++ { DEBUG_FEATURE_USB3DFX,
++ "USB3DFX",
++ },
++};
++
++int cpu_has_debug_feature(u32 bit)
++{
++ if (asset_array[debug_mode_idx].bitmask & bit)
++ return 1;
++
++ return 0;
++}
++EXPORT_SYMBOL(cpu_has_debug_feature);
++
++static int show_debug_feature(struct seq_file *s, void *unused)
++{
++ int i = 0;
++
++ if (debug_mode_idx >= 0 && (debug_mode_idx < MAX_MODE_NUMBER)) {
++ seq_printf(s, "Profile: %s\n",
++ asset_array[debug_mode_idx].name);
++
++ for (i = 0; i < MAX_DEBUG_NUMBER; i++)
++ if (cpu_has_debug_feature(debug_feature_array[i].bit))
++ seq_printf(s, "%s\n",
++ debug_feature_array[i].name);
++ }
++
++ return 0;
++}
++
++static int debug_feature_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, show_debug_feature, NULL);
++}
++
++static const struct file_operations debug_feature_ops = {
++ .open = debug_feature_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++int __init soc_debug_init(void)
++{
++ u32 __iomem *pgrr;
++ int i = 0;
++ enum pgrr_mode soc_debug_setting = 0;
++
++ if ((intel_mid_identify_cpu() != INTEL_MID_CPU_CHIP_TANGIER) &&
++ (intel_mid_identify_cpu() != INTEL_MID_CPU_CHIP_ANNIEDALE))
++ return -EINVAL;
++
++ /* Read Policy Generator Result Register */
++ pgrr = ioremap_nocache(PGRR_BASE, sizeof(u32));
++ if (pgrr == NULL)
++ return -EFAULT;
++
++ pr_info("pgrr = %08x\n", *pgrr);
++ soc_debug_setting = *pgrr & 0x0F;
++ iounmap(pgrr);
++
++ for (i = 0; i < MAX_MODE_NUMBER; i++)
++ if (asset_array[i].mode == soc_debug_setting)
++ break;
++
++ if (i == MAX_MODE_NUMBER)
++ return -EFAULT;
++
++ debug_mode_idx = i;
++
++ dfs_entry = debugfs_create_file("debug_feature", S_IFREG | S_IRUGO,
++ NULL, NULL, &debug_feature_ops);
++
++ return 0;
++}
++arch_initcall(soc_debug_init);
++
++void __exit soc_debug_exit(void)
++{
++ debugfs_remove(dfs_entry);
++}
++module_exit(soc_debug_exit);
+diff --git a/arch/x86/platform/intel-mid/intel_soc_dump.c b/arch/x86/platform/intel-mid/intel_soc_dump.c
+new file mode 100644
+index 0000000..2441b1c
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/intel_soc_dump.c
+@@ -0,0 +1,1586 @@
++/*
++ * intel_soc_dump.c - This driver provides a debugfs interface to read or
++ * write any registers inside the SoC. Supported access methods are:
++ * mmio, msg_bus, pci and i2c.
++ *
++ * Copyright (c) 2012, Intel Corporation.
++ * Author: Bin Gao <bin.gao@intel.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++/*
++ * Two files are created in debugfs root folder: dump_cmd and dump_output.
++ * Echo a dump command to the file dump_cmd, and then cat the file dump_output.
++ * Even for write command, you still have to run "cat dump_output", otherwise
++ * the data will not be really written.
++ *
++ * It works like this:
++ * $ echo "dump command" > dump_cmd
++ * $ cat dump_output
++ *
++ * I/O memory read: echo "r[1|2|4] mmio <addr> [<len>]" > dump_cmd
++ * e.g. echo "r mmio 0xff180000" > dump_cmd
++ *
++ * I/O memory write: echo "w[1|2|4] <addr> <val>" > dump_cmd
++ * e.g. echo "w mmio 0xff190000 0xf0107a08" > dump_cmd
++ *
++ * I/O port read: echo "r[1|2|4] port <port>" > dump_cmd
++ * e.g. echo "r port 0xcf8" > dump_cmd
++ *
++ * I/O port write: echo "w[1|2|4] <port> <val>" > dump_cmd
++ * e.g. echo "w4 port 0xcfc 0x80002188" > dump_cmd
++ *
++ * message bus read: echo "r msg_bus <port> <addr> [<len>]" > dump_cmd
++ * e.g. echo "r msg_bus 0x02 0x30" > dump_cmd
++ *
++ * message bus write: echo "w msg_bus <port> <addr> <val>" > dump_cmd
++ * e.g. echo "w msg_bus 0x02 0x30 0x1020003f" > dump_cmd
++ *
++ * pci config read: echo "r[1|2|4] pci <bus> <dev> <func> <reg> [<len>]" >
++ * dump_cmd
++ * e.g. echo "r1 pci 0 2 0 0x20" > dump_cmd
++ *
++ * pci config write: echo "w[1|2|4] pci <bus> <dev> <func> <reg> <value>" >
++ * dump_cmd
++ * e.g. echo "w pci 0 2 0 0x20 0x380020f3" > dump_cmd
++ *
++ * msr read: echo "r[4|8] msr [<cpu>|all] <reg>" > dump_cmd
++ * read cab be 32bit(r4) or 64bit(r8), default is r8 (=r)
++ * cpu can be 0, 1, 2, 3, ... or all, default is all
++ * e.g. echo "r msr 0 0xcd" > dump_cmd
++ * (read all cpu's msr reg 0xcd in 64bit mode)
++ *
++ * msr write: echo "w[4|8] msr [<cpu>|all] <reg> <val>" > dump_cmd
++ * write cab be 32bit(w4) or 64bit(w8), default is w8 (=w)
++ * cpu can be 0, 1, 2, 3, ... or all, default is all
++ * e.g. echo "w msr 1 289 0xf03090a0cc73be64" > dump_cmd
++ * (write value 0xf03090a0cc73be64 to cpu 1's msr reg 289 in 64bit mode)
++ *
++ * i2c read: echo "r i2c <bus> <addr>" > dump_cmd
++ * e.g. echo "r i2c 1 0x3e" > dump_cmd
++ *
++ * i2c write: echo "w i2c <bus> <addr> <val>" > dump_cmd
++ * e.g. echo "w i2c 2 0x70 0x0f" > dump_cmd
++ *
++ * SCU indirect memory read: echo "r[4] scu <addr>" > dump_cmd
++ * e.g. echo "r scu 0xff108194" > dump_cmd
++ *
++ * SCU indirect memory write: echo "w[4] scu <addr> <val>" > dump_cmd
++ * e.g. echo "w scu 0xff108194 0x03000001" > dump_cmd
++ *
++ * SCU indirect read/write is limited to those addresses in
++ * IndRdWrValidAddrRange array in SCU FW.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <linux/debugfs.h>
++#include <linux/io.h>
++#include <linux/err.h>
++#include <linux/seq_file.h>
++#include <linux/i2c.h>
++#include <linux/pm_runtime.h>
++#include <asm/uaccess.h>
++#include <asm/intel-mid.h>
++#include <asm/processor.h>
++#include <asm/msr.h>
++#include <asm/intel_mid_rpmsg.h>
++
++#define MAX_CMDLEN 96
++#define MAX_ERRLEN 255
++#define MIN_ARGS_NUM 3
++#define MAX_ARGS_NUM 8
++#define MAX_MMIO_PCI_LEN 4096
++#define MAX_MSG_BUS_LEN 64
++
++#define ACCESS_WIDTH_DEFAULT 0
++#define ACCESS_WIDTH_8BIT 1
++#define ACCESS_WIDTH_16BIT 2
++#define ACCESS_WIDTH_32BIT 4
++#define ACCESS_WIDTH_64BIT 8
++
++#define ACCESS_BUS_MMIO 1 /* I/O memory */
++#define ACCESS_BUS_PORT 2 /* I/O port */
++#define ACCESS_BUS_MSG_BUS 3 /* message bus */
++#define ACCESS_BUS_PCI 4 /* PCI bus */
++#define ACCESS_BUS_MSR 5 /* MSR registers */
++#define ACCESS_BUS_I2C 6 /* I2C bus */
++#define ACCESS_BUS_SCU_INDRW 7 /* SCU indirect read/write */
++
++#define ACCESS_DIR_READ 1
++#define ACCESS_DIR_WRITE 2
++
++#define RP_INDIRECT_READ 0x02 /* MSG_ID for indirect read via SCU */
++#define RP_INDIRECT_WRITE 0x05 /* MSG_ID for indirect write via SCU */
++
++#define SHOW_NUM_PER_LINE (32 / access_width)
++#define LINE_WIDTH (access_width * SHOW_NUM_PER_LINE)
++#define IS_WHITESPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
++#define ADDR_RANGE(start, size, addr) \
++ ((addr >= start) && (addr < (start + size)))
++
++/* mmio <--> device map */
++struct mmio_pci_map {
++ u32 start;
++ size_t size;
++ u32 pci_bus:8;
++ u32 pci_dev:8;
++ u32 pci_func:8;
++ char name[24];
++};
++
++static struct dentry *dump_cmd_dentry, *dump_output_dentry;
++static int dump_cmd_was_set;
++static char dump_cmd_buf[MAX_CMDLEN], err_buf[MAX_ERRLEN + 1];
++
++static int access_dir, access_width, access_bus, access_len;
++static u32 access_value;
++static u64 access_value_64;
++
++/* I/O memory */
++static u32 mmio_addr;
++
++/* I/O port */
++static unsigned port_addr;
++
++/* msg_bus */
++static u8 msg_bus_port;
++static u32 msg_bus_addr;
++
++/* pci */
++static u8 pci_bus, pci_dev, pci_func;
++static u16 pci_reg;
++
++/* msr */
++static int msr_cpu;
++static u32 msr_reg;
++
++/* i2c */
++static u8 i2c_bus;
++static u32 i2c_addr;
++
++/* scu */
++static u32 scu_addr;
++
++static const struct mmio_pci_map soc_pnw_map[] = {
++ { 0xff128000, 0x400, 0, 0, 1, "SPI0" },
++ { 0xff128400, 0x400, 0, 0, 2, "SPI1" },
++ { 0xff128800, 0x400, 0, 2, 4, "SPI2" },
++
++ { 0xff12a000, 0x400, 0, 0, 3, "I2C0" },
++ { 0xff12a400, 0x400, 0, 0, 4, "I2C1" },
++ { 0xff12a800, 0x400, 0, 0, 5, "I2C2" },
++ { 0xff12ac00, 0x400, 0, 3, 2, "I2C3" },
++ { 0xff12b000, 0x400, 0, 3, 3, "I2C4" },
++ { 0xff12b400, 0x400, 0, 3, 4, "I2C5" },
++
++ { 0xffae5800, 0x400, 0, 2, 7, "SSP0" },
++ { 0xffae6000, 0x400, 0, 1, 4, "SSP1" },
++ { 0xffae6400, 0x400, 0, 1, 3, "SSP2" },
++ { 0xffaf0000, 0x800, 0, 2, 6, "LPE DMA1" },
++
++ { 0xff0d0000, 0x10000, 0, 1, 5, "SEP SECURITY" },
++ { 0xff11c000, 0x400, 0, 1, 7, "SCU IPC1" },
++
++ { 0xdff00000, 0x100000, 0, 2, 0, "GVD BAR0" },
++ { 0x40000000, 0x10000000, 0, 2, 0, "GVD BAR2" },
++ { 0xdfec0000, 0x40000, 0, 2, 0, "GVD BAR3" },
++
++ { 0xff11d000, 0x1000, 0, 2, 2, "PMU" },
++ { 0xffa60000, 0x20000, 0, 2, 3, "USB OTG" },
++
++ { 0xdf800000, 0x400000, 0, 3, 0, "ISP" },
++
++ { 0xff12c000, 0x800, 0, 2, 1, "GPIO0" },
++ { 0xff12c800, 0x800, 0, 3, 5, "GPIO1" },
++ { 0xff12b800, 0x800, 0, 2, 5, "GP DMA" },
++
++ { 0xffa58000, 0x100, 0, 4, 0, "SDIO0(HC2)" },
++ { 0xffa5c000, 0x100, 0, 4, 1, "SDIO1(HC1a)" },
++ { 0xffa2a000, 0x100, 0, 4, 2, "SDIO3(HC1b)" },
++ { 0xffa50000, 0x100, 0, 1, 0, "SDIO3/eMMC0(HC0a)" },
++ { 0xffa54000, 0x100, 0, 1, 1, "SDIO4/eMMC1(HC0b)" },
++
++ { 0xffa28080, 0x80, 0, 5, 0, "UART0" },
++ { 0xffa28100, 0x80, 0, 5, 1, "UART1" },
++ { 0xffa28180, 0x80, 0, 5, 2, "UART2" },
++ { 0xffa28400, 0x400, 0, 5, 3, "UART DMA" },
++
++ { 0xffa2e000, 0x400, 0, 6, 0, "PTI" },
++
++ /* no address assigned: { 0x0, 0, 0, 6, 1, "xx" }, */
++
++ { 0xffa29000, 0x800, 0, 6, 3, "HSI" },
++ { 0xffa29800, 0x800, 0, 6, 4, "HSI DMA" },
++};
++
++static const struct mmio_pci_map soc_clv_map[] = {
++ { 0xff138000, 0x400, 0, 0, 3, "I2C0" },
++ { 0xff139000, 0x400, 0, 0, 4, "I2C1" },
++ { 0xff13a000, 0x400, 0, 0, 5, "I2C2" },
++ { 0xff13b000, 0x400, 0, 3, 2, "I2C3" },
++ { 0xff13c000, 0x400, 0, 3, 3, "I2C4" },
++ { 0xff13d000, 0x400, 0, 3, 4, "I2C5" },
++
++ { 0xff128000, 0x400, 0, 0, 1, "SPI0/MSIC" },
++ { 0xff135000, 0x400, 0, 0, 2, "SPI1" },
++ { 0xff136000, 0x400, 0, 2, 4, "SPI2" },
++ /* invisible to IA: { 0xff137000, 0, -1, -1, -1, "SPI3" }, */
++
++ { 0xffa58000, 0x100, 0, 4, 0, "SDIO0 (HC2)" },
++ { 0xffa48000, 0x100, 0, 4, 1, "SDIO1 (HC1a)" },
++ { 0xffa4c000, 0x100, 0, 4, 2, "SDIO2 (HC1b)" },
++ { 0xffa50000, 0x100, 0, 1, 0, "SDIO3/eMMC0 (HC0a)" },
++ { 0xffa54000, 0x100, 0, 1, 1, "SDIO4/eMMC1 (HC0b)" },
++
++ { 0xff119000, 0x800, 0, 2, 1, "GPIO0" },
++ { 0xff13f000, 0x800, 0, 3, 5, "GPIO1" },
++ { 0xff13e000, 0x800, 0, 2, 5, "GP DMA" },
++
++ { 0xffa20000, 0x400, 0, 2, 7, "SSP0" },
++ { 0xffa21000, 0x400, 0, 1, 4, "SSP1" },
++ { 0xffa22000, 0x400, 0, 1, 3, "SSP2" },
++ /* invisible to IA: { 0xffa23000, 0, -1, -1, -1, "SSP3" }, */
++
++ /* invisible to IA: { 0xffaf8000, 0, -1, -1, -1, "LPE DMA0" }, */
++ { 0xffaf0000, 0x800, 0, 2, 6, "LPE DMA1" },
++ { 0xffae8000, 0x1000, 0, 1, 3, "LPE SHIM" },
++ /* { 0xffae9000, 0, 0, 6, 5, "VIBRA" }, LPE SHIM BASE + 0x1000 */
++
++ { 0xffa28080, 0x80, 0, 5, 0, "UART0" },
++ { 0xffa28100, 0x80, 0, 5, 1, "UART1" },
++ { 0xffa28180, 0x80, 0, 5, 2, "UART2" },
++ { 0xffa28400, 0x400, 0, 5, 3, "UART DMA" },
++
++ { 0xffa29000, 0x800, 0, 6, 3, "HSI" },
++ { 0xffa2a000, 0x800, 0, 6, 4, "HSI DMA" },
++
++ { 0xffa60000, 0x20000, 0, 2, 3, "USB OTG" },
++ { 0xffa80000, 0x60000, 0, 6, 5, "USB SPH" },
++
++ { 0xff0d0000, 0x10000, 0, 1, 5, "SEP SECURITY" },
++
++ { 0xdff00000, 0x100000, 0, 2, 0, "GVD BAR0" },
++ { 0x40000000, 0x10000000, 0, 2, 0, "GVD BAR2" },
++ { 0xdfec0000, 0x40000, 0, 2, 0, "GVD BAR3" },
++ /* No address assigned: { 0x0, 0, 0, 6, 1, "HDMI HOTPLUG" }, */
++
++ { 0xdf800000, 0x400000, 0, 3, 0, "ISP" },
++
++ { 0xffa2e000, 0x400, 0, 6, 0, "PTI" },
++ { 0xff11c000, 0x400, 0, 1, 7, "SCU IPC1" },
++ { 0xff11d000, 0x1000, 0, 2, 2, "PMU" },
++};
++
++static const struct mmio_pci_map soc_tng_map[] = {
++ /* I2C0 is reserved for SCU<-->PMIC communication */
++ { 0xff18b000, 0x400, 0, 8, 0, "I2C1" },
++ { 0xff18c000, 0x400, 0, 8, 1, "I2C2" },
++ { 0xff18d000, 0x400, 0, 8, 2, "I2C3" },
++ { 0xff18e000, 0x400, 0, 8, 3, "I2C4" },
++ { 0xff18f000, 0x400, 0, 9, 0, "I2C5" },
++ { 0xff190000, 0x400, 0, 9, 1, "I2C6" },
++ { 0xff191000, 0x400, 0, 9, 2, "I2C7" },
++
++ /* SDIO controllers number: 4 (compared to 5 of PNW/CLV) */
++ { 0xff3fa000, 0x100, 0, 1, 2, "SDIO0 (HC2)" },
++ { 0xff3fb000, 0x100, 0, 1, 3, "SDIO1 (HC1a)" },
++ { 0xff3fc000, 0x100, 0, 1, 0, "SDIO3/eMMC0 (HC0a)" },
++ { 0xff3fd000, 0x100, 0, 1, 1, "SDIO4/eMMC1 (HC0b)" },
++
++ /* GPIO0 and GPIO1 are merged to one GPIO controller in TNG */
++ { 0xff008000, 0x1000, 0, 12, 0, "GPIO" },
++ { 0xff192000, 0x1000, 0, 21, 0, "GP DMA" },
++
++ /* SSP Audio: SSP0: Modem, SSP1: Audio Codec, SSP2: Bluetooth */
++
++ /* LPE */
++ { 0xff340000, 0x4000, 0, 13, 0, "LPE SHIM" },
++ { 0xff344000, 0x1000, 0, 13, 0, "MAILBOX RAM" },
++ { 0xff2c0000, 0x14000, 0, 13, 0, "ICCM" },
++ { 0xff300000, 0x28000, 0, 13, 0, "DCCM" },
++ { 0xff298000, 0x4000, 0, 14, 0, "LPE DMA0" },
++ /* invisible to IA: { 0xff29c000, 0x4000, -1, -1, -1, "LPE DMA1" }, */
++
++
++ /* SSP SC: SSP4: used by SCU for SPI Debug Card */
++ /* invisible to IA: { 0xff00e000, 0x1000, -1, -1, -1, "SSP SC" }, */
++
++ /* SSP General Purpose */
++ { 0xff188000, 0x1000, 0, 7, 0, "SSP3" },
++ { 0xff189000, 0x1000, 0, 7, 1, "SSP5" },
++ { 0xff18a000, 0x1000, 0, 7, 2, "SSP6" },
++
++ /* UART */
++ { 0xff010080, 0x80, 0, 4, 1, "UART0" },
++ { 0xff011000, 0x80, 0, 4, 2, "UART1" },
++ { 0xff011080, 0x80, 0, 4, 3, "UART2" },
++ { 0xff011400, 0x400, 0, 5, 0, "UART DMA" },
++
++ /* HSI */
++ { 0xff3f8000, 0x1000, 0, 10, 0, "HSI" },
++
++ /* USB */
++ { 0xf9040000, 0x20000, 0, 15, 0, "USB2 OTG" },
++ { 0xf9060000, 0x20000, 0, 16, 0, "USB2 MPH/HSIC" },
++ { 0xf9100000, 0x100000, 0, 17, 0, "USB3 OTG" },
++ /* { 0xf90f0000, 0x1000, -1, -1, -1, "USB3 PHY" }, */
++ /* { 0xf90a0000, 0x10000, -1, -1, -1, "USB3 DMA FETCH" }, */
++
++ /* Security/Chaabi */
++ { 0xf9030000, 0x1000, 0, 11, 0, "SEP SECURITY" },
++
++ /* Graphics/Display */
++ { 0xc0000000, 0x2000000, 0, 2, 0, "GVD BAR0" },
++ { 0x80000000, 0x10000000, 0, 2, 0, "GVD BAR2" },
++
++ /* ISP */
++ { 0xc2000000, 0x400000, 0, 3, 0, "ISP" },
++
++ /* PTI */
++ { 0xf9009000, 0x1000, 0, 18, 0, "PTI STM" },
++ { 0xf90a0000, 0x10000, 0, 18, 0, "PTI USB3 DMA FETCH" },
++ { 0xfa000000, 0x1000000, 0, 18, 0, "PTI APERTURE A" },
++
++ { 0xff009000, 0x1000, 0, 19, 0, "SCU-IA IPC" },
++ { 0xff00b000, 0x1000, 0, 20, 0, "PMU" },
++};
++
++static struct pci_dev *mmio_to_pci(u32 addr, char **name)
++{
++ int i, count;
++ struct mmio_pci_map *map;
++
++ if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_PENWELL) {
++ count = ARRAY_SIZE(soc_pnw_map);
++ map = (struct mmio_pci_map *) &soc_pnw_map[0];
++ } else if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_CLOVERVIEW) {
++ count = ARRAY_SIZE(soc_clv_map);
++ map = (struct mmio_pci_map *) &soc_clv_map[0];
++ } else if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER) {
++ count = ARRAY_SIZE(soc_tng_map);
++ map = (struct mmio_pci_map *) &soc_tng_map[0];
++ } else {
++ return NULL;
++ }
++
++ for (i = 0; i < count; i++) {
++ if (ADDR_RANGE(map[i].start, map[i].size, addr))
++ break;
++ }
++
++ if (i >= count)
++ return NULL;
++
++ *name = &map[i].name[0];
++ return pci_get_bus_and_slot(map[i].pci_bus,
++ PCI_DEVFN(map[i].pci_dev, map[i].pci_func));
++}
++
++static int parse_argument(char *input, char **args)
++{
++ int count, located;
++ char *p = input;
++ int input_len = strlen(input);
++
++ count = 0;
++ located = 0;
++ while (*p != 0) {
++ if (p - input >= input_len)
++ break;
++
++ /* Locate the first character of a argument */
++ if (!IS_WHITESPACE(*p)) {
++ if (!located) {
++ located = 1;
++ args[count++] = p;
++ if (count > MAX_ARGS_NUM)
++ break;
++ }
++ } else {
++ if (located) {
++ *p = 0;
++ located = 0;
++ }
++ }
++ p++;
++ }
++
++ return count;
++}
++
++static int dump_cmd_show(struct seq_file *s, void *unused)
++{
++ seq_printf(s, dump_cmd_buf);
++ return 0;
++}
++
++static int dump_cmd_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, dump_cmd_show, NULL);
++}
++
++static int parse_mmio_args(char **arg_list, int arg_num)
++{
++ int ret;
++
++ if (arg_num < 3) {
++ snprintf(err_buf, MAX_ERRLEN, "too few arguments\n"
++ "usage: r[1|2|4] <mmio> <addr> [<len>]\n"
++ " w[1|2|4] <mmio> <addr> <val>\n");
++ goto failed;
++ }
++
++ if (access_width == ACCESS_WIDTH_DEFAULT)
++ access_width = ACCESS_WIDTH_32BIT;
++
++ ret = kstrtou32(arg_list[2], 0, &mmio_addr);
++ if (ret) {
++ snprintf(err_buf, MAX_ERRLEN, "invalid mmio address %s\n",
++ arg_list[2]);
++ goto failed;
++ }
++
++ if ((access_width == ACCESS_WIDTH_32BIT) &&
++ (mmio_addr % 4)) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "addr %x is not 4 bytes aligned!\n",
++ mmio_addr);
++ goto failed;
++ }
++
++ if ((access_width == ACCESS_WIDTH_16BIT) &&
++ (mmio_addr % 2)) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "addr %x is not 2 bytes aligned!\n",
++ mmio_addr);
++ goto failed;
++ }
++
++ if (access_dir == ACCESS_DIR_READ) {
++ if (arg_num == 4) {
++ ret = kstrtou32(arg_list[3], 0, &access_len);
++ if (ret) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "invalid mmio read length %s\n",
++ arg_list[3]);
++ goto failed;
++ }
++ } else if (arg_num > 4) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "usage: r[1|2|4] mmio <addr> "
++ "[<len>]\n");
++ goto failed;
++ }
++ }
++
++ if (access_dir == ACCESS_DIR_WRITE) {
++ if (arg_num != 4) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "need exact 4 arguments for "
++ "mmio write.\n");
++ goto failed;
++ }
++ ret = kstrtou32(arg_list[3], 0, &access_value);
++ if (ret) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "invalid mmio address %s\n",
++ arg_list[3]);
++ goto failed;
++ }
++ }
++
++ return 0;
++
++failed:
++ return -EINVAL;
++}
++
++static int parse_port_args(char **arg_list, int arg_num)
++{
++ int ret;
++
++ if (arg_num < 2) {
++ snprintf(err_buf, MAX_ERRLEN, "too few arguments\n"
++ "usage: r[1|2|4] port <port>\n"
++ " w[1|2|4] port <port> <val>\n");
++ goto failed;
++ }
++
++ if (access_width == ACCESS_WIDTH_DEFAULT)
++ access_width = ACCESS_WIDTH_8BIT;
++
++ ret = kstrtou16(arg_list[2], 0, (u16 *)&port_addr);
++ if (ret) {
++ snprintf(err_buf, MAX_ERRLEN, "invalid port address %s\n",
++ arg_list[2]);
++ goto failed;
++ }
++
++ if ((access_width == ACCESS_WIDTH_32BIT) &&
++ (port_addr % ACCESS_WIDTH_32BIT)) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "port %x is not 4 bytes aligned!\n", port_addr);
++ goto failed;
++ }
++
++ if ((access_width == ACCESS_WIDTH_16BIT) &&
++ (port_addr % ACCESS_WIDTH_16BIT)) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "port %x is not 2 bytes aligned!\n", port_addr);
++ goto failed;
++ }
++
++ if (access_dir == ACCESS_DIR_READ) {
++ if (arg_num != 3) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "usage: r[1|2|4] port <port>\n");
++ goto failed;
++ }
++ }
++
++ if (access_dir == ACCESS_DIR_WRITE) {
++ if (arg_num != 4) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "need exact 4 arguments for port write.\n");
++ goto failed;
++ }
++ ret = kstrtou32(arg_list[3], 0, &access_value);
++ if (ret) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "invalid value %s\n", arg_list[3]);
++ goto failed;
++ }
++ }
++
++ return 0;
++
++failed:
++ return -EINVAL;
++}
++
++static int parse_msg_bus_args(char **arg_list, int arg_num)
++{
++ int ret;
++
++ if (arg_num < 4) {
++ snprintf(err_buf, MAX_ERRLEN, "too few arguments\n"
++ "usage: r msg_bus <port> <addr> [<len>]\n"
++ " w msg_bus <port> <addr> <val>\n");
++ goto failed;
++ }
++
++ if (access_width == ACCESS_WIDTH_DEFAULT)
++ access_width = ACCESS_WIDTH_32BIT;
++
++ if (access_width != ACCESS_WIDTH_32BIT) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "only 32bit read/write are supported.\n");
++ goto failed;
++ }
++
++ ret = kstrtou8(arg_list[2], 0, &msg_bus_port);
++ if (ret || msg_bus_port > 255) {
++ snprintf(err_buf, MAX_ERRLEN, "invalid msg_bus port %s\n",
++ arg_list[2]);
++ goto failed;
++ }
++
++ ret = kstrtou32(arg_list[3], 0, &msg_bus_addr);
++ if (ret) {
++ snprintf(err_buf, MAX_ERRLEN, "invalid msg_bus address %s\n",
++ arg_list[3]);
++ goto failed;
++ }
++
++ if (access_dir == ACCESS_DIR_READ) {
++ if (arg_num == 5) {
++ ret = kstrtou32(arg_list[4], 0, &access_len);
++ if (ret) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "invalid msg_bus read length %s\n",
++ arg_list[4]);
++ goto failed;
++ }
++ } else if (arg_num > 5) {
++ snprintf(err_buf, MAX_ERRLEN, "too many arguments\n"
++ "usage: r[1|2|4] msg_bus "
++ "<port> <addr> [<len>]\n");
++ goto failed;
++ }
++ }
++
++ if (access_dir == ACCESS_DIR_WRITE) {
++ if (arg_num != 5) {
++ snprintf(err_buf, MAX_ERRLEN, "too few arguments\n"
++ "usage: w msg_bus <port> <addr> <val>]\n");
++ goto failed;
++ }
++ ret = kstrtou32(arg_list[4], 0, &access_value);
++ if (ret) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "invalid value for msg_bus write %s\n",
++ arg_list[4]);
++ goto failed;
++ }
++ }
++
++ return 0;
++
++failed:
++ return -EINVAL;
++}
++
++static int parse_pci_args(char **arg_list, int arg_num)
++{
++ int ret;
++
++ if (arg_num < 6) {
++ snprintf(err_buf, MAX_ERRLEN, "too few arguments\n"
++ "usage: r[1|2|4] pci <bus> <dev> <func> <reg> [<len>]\n"
++ " w[1|2|4] pci <bus> <dev> <func> <reg> <val>\n");
++ goto failed;
++ }
++
++ if (access_width == ACCESS_WIDTH_DEFAULT)
++ access_width = ACCESS_WIDTH_32BIT;
++
++ ret = kstrtou8(arg_list[2], 0, &pci_bus);
++ if (ret || pci_bus > 255) {
++ snprintf(err_buf, MAX_ERRLEN, "invalid pci bus %s\n",
++ arg_list[2]);
++ goto failed;
++ }
++
++ ret = kstrtou8(arg_list[3], 0, &pci_dev);
++ if (ret || pci_dev > 255) {
++ snprintf(err_buf, MAX_ERRLEN, "invalid pci device %s\n",
++ arg_list[3]);
++ goto failed;
++ }
++
++ ret = kstrtou8(arg_list[4], 0, &pci_func);
++ if (ret || pci_func > 255) {
++ snprintf(err_buf, MAX_ERRLEN, "invalid pci function %s\n",
++ arg_list[4]);
++ goto failed;
++ }
++
++ ret = kstrtou16(arg_list[5], 0, &pci_reg);
++ if (ret || pci_reg > 4 * 1024) {
++ snprintf(err_buf, MAX_ERRLEN, "invalid pci register %s\n",
++ arg_list[5]);
++ goto failed;
++ }
++
++ if ((access_width == ACCESS_WIDTH_32BIT) && (pci_reg % 4)) {
++ snprintf(err_buf, MAX_ERRLEN, "reg %x is not 4 bytes aligned!\n"
++ , (u32) pci_reg);
++ goto failed;
++ }
++
++ if ((access_width == ACCESS_WIDTH_16BIT) && (pci_reg % 2)) {
++ snprintf(err_buf, MAX_ERRLEN, "reg %x is not 2 bytes aligned\n",
++ pci_reg);
++ goto failed;
++ }
++
++ if (access_dir == ACCESS_DIR_READ) {
++ if (arg_num == 7) {
++ ret = kstrtou32(arg_list[6], 0, &access_len);
++ if (ret || access_len > 4 * 1024) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "invalid pci read length %s\n",
++ arg_list[6]);
++ return ret;
++ }
++ } else if (arg_num > 7) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "max 7 args are allowed for pci read\n"
++ "usage: r[1|2|4] pci <bus> <dev> <func> "
++ "<reg> [<len>]\n");
++ goto failed;
++ }
++ }
++
++ if (access_dir == ACCESS_DIR_WRITE) {
++ if (arg_num != 7) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "need exact 7 args for pci write.\n");
++ goto failed;
++ }
++ ret = kstrtou32(arg_list[6], 0, &access_value);
++ if (ret) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "invalid value for pci write %s\n",
++ arg_list[6]);
++ goto failed;
++ }
++ }
++
++ return 0;
++
++failed:
++ return -EINVAL;
++}
++
++static int parse_msr_args(char **arg_list, int arg_num)
++{
++ int ret, arg_reg, arg_val;
++
++ if (((access_dir == ACCESS_DIR_READ) && (arg_num < 3)) ||
++ ((access_dir == ACCESS_DIR_WRITE) && (arg_num < 4))) {
++ snprintf(err_buf, MAX_ERRLEN, "too few arguments\n"
++ "usage: r[4|8] msr [<cpu> | all] <reg>]\n"
++ " w[4|8] msr [<cpu> | all] <reg> <val>]\n");
++ goto failed;
++ }
++
++ if (((access_dir == ACCESS_DIR_READ) && (arg_num > 4)) ||
++ ((access_dir == ACCESS_DIR_WRITE) && (arg_num > 5))) {
++ snprintf(err_buf, MAX_ERRLEN, "too many arguments\n"
++ "usage: r[4|8] msr [<cpu> | all] <reg>]\n"
++ " w[4|8] msr [<cpu> | all] <reg> <val>]\n");
++ goto failed;
++ }
++
++ if (access_width == ACCESS_WIDTH_DEFAULT)
++ access_width = ACCESS_WIDTH_64BIT;
++
++ if (!strncmp(arg_list[2], "all", 3)) {
++ msr_cpu = -1;
++ arg_reg = 3;
++ arg_val = 4;
++ } else if ((access_dir == ACCESS_DIR_READ && arg_num == 4) ||
++ (access_dir == ACCESS_DIR_WRITE && arg_num == 5)) {
++ ret = kstrtou32(arg_list[2], 0, &msr_cpu);
++ if (ret) {
++ snprintf(err_buf, MAX_ERRLEN, "invalid cpu: %s\n",
++ arg_list[2]);
++ goto failed;
++ }
++ arg_reg = 3;
++ arg_val = 4;
++ } else {
++ /* Default cpu for msr read is all, for msr write is 0 */
++ if (access_dir == ACCESS_DIR_READ)
++ msr_cpu = -1;
++ else
++ msr_cpu = 0;
++ arg_reg = 2;
++ arg_val = 3;
++ }
++
++
++ ret = kstrtou32(arg_list[arg_reg], 0, &msr_reg);
++ if (ret) {
++ snprintf(err_buf, MAX_ERRLEN, "invalid msr reg: %s\n",
++ arg_list[2]);
++ goto failed;
++ }
++ if (access_dir == ACCESS_DIR_WRITE) {
++ if (access_width == ACCESS_WIDTH_32BIT)
++ ret = kstrtou32(arg_list[arg_val], 0, &access_value);
++ else
++ ret = kstrtou64(arg_list[arg_val], 0, &access_value_64);
++ if (ret) {
++ snprintf(err_buf, MAX_ERRLEN, "invalid value: %s\n",
++ arg_list[arg_val]);
++ goto failed;
++ }
++ }
++
++ return 0;
++
++failed:
++ return -EINVAL;
++}
++
++static int parse_i2c_args(char **arg_list, int arg_num)
++{
++ int ret;
++
++ if ((access_dir == ACCESS_DIR_READ && arg_num != 4) ||
++ (access_dir == ACCESS_DIR_WRITE && arg_num != 5)) {
++ snprintf(err_buf, MAX_ERRLEN, "usage: r i2c <bus> <addr>\n"
++ " w i2c <bus> <addr> <val>\n");
++ goto failed;
++ }
++
++ if (access_width == ACCESS_WIDTH_DEFAULT)
++ access_width = ACCESS_WIDTH_8BIT;
++
++ if (access_width != ACCESS_WIDTH_8BIT) {
++ snprintf(err_buf, MAX_ERRLEN, "only 8bit access is allowed\n");
++ goto failed;
++ }
++
++ ret = kstrtou8(arg_list[2], 0, &i2c_bus);
++ if (ret || i2c_bus > 9) {
++ snprintf(err_buf, MAX_ERRLEN, "invalid i2c bus %s\n",
++ arg_list[2]);
++ goto failed;
++ }
++
++ ret = kstrtou32(arg_list[3], 0, &i2c_addr);
++
++ pr_err("ret = %d, i2c_addr is 0x%x\n", ret, i2c_addr);
++ if (ret || (i2c_addr > 1024)) {
++ snprintf(err_buf, MAX_ERRLEN, "invalid i2c address %s\n",
++ arg_list[3]);
++ goto failed;
++ }
++
++ if (access_dir == ACCESS_DIR_WRITE) {
++ ret = kstrtou32(arg_list[4], 0, &access_value);
++ if (ret) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "invalid value for i2c write %s\n",
++ arg_list[4]);
++ goto failed;
++ }
++ }
++ return 0;
++
++failed:
++ return -EINVAL;
++}
++
++static int parse_scu_args(char **arg_list, int arg_num)
++{
++ int ret;
++
++ if (access_width != ACCESS_WIDTH_32BIT)
++ access_width = ACCESS_WIDTH_32BIT;
++
++ ret = kstrtou32(arg_list[2], 0, &scu_addr);
++ if (ret) {
++ snprintf(err_buf, MAX_ERRLEN, "invalid scu address %s\n",
++ arg_list[2]);
++ goto failed;
++ }
++
++ if (scu_addr % 4) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "addr %x is not 4 bytes aligned!\n",
++ scu_addr);
++ goto failed;
++ }
++
++ if (access_dir == ACCESS_DIR_READ) {
++ if (arg_num != 3) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "usage: r[4] scu <addr>\n");
++ goto failed;
++ }
++ }
++
++ if (access_dir == ACCESS_DIR_WRITE) {
++ if (arg_num != 4) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "usage: w[4] scu <addr> <val>\n");
++ goto failed;
++ }
++ ret = kstrtou32(arg_list[3], 0, &access_value);
++ if (ret) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "invalid scu write value %s\n",
++ arg_list[3]);
++ goto failed;
++ }
++ }
++
++ return 0;
++
++failed:
++ return -EINVAL;
++}
++
++static ssize_t dump_cmd_write(struct file *file, const char __user *buf,
++ size_t len, loff_t *offset)
++{
++ char cmd[MAX_CMDLEN];
++ char *arg_list[MAX_ARGS_NUM];
++ int arg_num, ret = -EINVAL;
++
++ err_buf[0] = 0;
++
++ if (len >= MAX_CMDLEN) {
++ snprintf(err_buf, MAX_ERRLEN, "input command is too long.\n"
++ "max allowed input length is %d\n",
++ MAX_CMDLEN);
++ goto done;
++ }
++
++ if (copy_from_user(cmd, buf, len)) {
++ snprintf(err_buf, MAX_ERRLEN, "copy_from_user() failed.\n");
++ goto done;
++ }
++ cmd[len] = 0;
++
++ dump_cmd_buf[0] = 0;
++ strncpy(dump_cmd_buf, cmd, len);
++ dump_cmd_buf[len] = 0;
++
++ arg_num = parse_argument(cmd, arg_list);
++ if (arg_num < MIN_ARGS_NUM) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "invalid command(too few arguments): "
++ "%s\n", dump_cmd_buf);
++ goto done;
++ }
++ if (arg_num > MAX_ARGS_NUM) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "invalid command(too many arguments): "
++ "%s\n", dump_cmd_buf);
++ goto done;
++ }
++
++ /* arg 1: direction(read/write) and mode (8/16/32/64 bit) */
++ if (!strncmp(arg_list[0], "r8", 2)) {
++ access_dir = ACCESS_DIR_READ;
++ access_width = ACCESS_WIDTH_64BIT;
++ } else if (!strncmp(arg_list[0], "r4", 2)) {
++ access_dir = ACCESS_DIR_READ;
++ access_width = ACCESS_WIDTH_32BIT;
++ } else if (!strncmp(arg_list[0], "r2", 2)) {
++ access_dir = ACCESS_DIR_READ;
++ access_width = ACCESS_WIDTH_16BIT;
++ } else if (!strncmp(arg_list[0], "r1", 2)) {
++ access_dir = ACCESS_DIR_READ;
++ access_width = ACCESS_WIDTH_8BIT;
++ } else if (!strncmp(arg_list[0], "r", 1)) {
++ access_dir = ACCESS_DIR_READ;
++ access_width = ACCESS_WIDTH_DEFAULT;
++ } else if (!strncmp(arg_list[0], "w8", 2)) {
++ access_dir = ACCESS_DIR_WRITE;
++ access_width = ACCESS_WIDTH_64BIT;
++ } else if (!strncmp(arg_list[0], "w4", 2)) {
++ access_dir = ACCESS_DIR_WRITE;
++ access_width = ACCESS_WIDTH_32BIT;
++ } else if (!strncmp(arg_list[0], "w2", 2)) {
++ access_dir = ACCESS_DIR_WRITE;
++ access_width = ACCESS_WIDTH_16BIT;
++ } else if (!strncmp(arg_list[0], "w1", 2)) {
++ access_dir = ACCESS_DIR_WRITE;
++ access_width = ACCESS_WIDTH_8BIT;
++ } else if (!strncmp(arg_list[0], "w", 1)) {
++ access_dir = ACCESS_DIR_WRITE;
++ access_width = ACCESS_WIDTH_DEFAULT;
++ } else {
++ snprintf(err_buf, MAX_ERRLEN, "unknown argument: %s\n",
++ arg_list[0]);
++ goto done;
++ }
++
++ /* arg2: bus type(mmio, msg_bus, pci or i2c) */
++ access_len = 1;
++ if (!strncmp(arg_list[1], "mmio", 4)) {
++ access_bus = ACCESS_BUS_MMIO;
++ ret = parse_mmio_args(arg_list, arg_num);
++ } else if (!strncmp(arg_list[1], "port", 4)) {
++ access_bus = ACCESS_BUS_PORT;
++ ret = parse_port_args(arg_list, arg_num);
++ } else if (!strncmp(arg_list[1], "msg_bus", 7)) {
++ access_bus = ACCESS_BUS_MSG_BUS;
++ ret = parse_msg_bus_args(arg_list, arg_num);
++ } else if (!strncmp(arg_list[1], "pci", 3)) {
++ access_bus = ACCESS_BUS_PCI;
++ ret = parse_pci_args(arg_list, arg_num);
++ } else if (!strncmp(arg_list[1], "msr", 3)) {
++ access_bus = ACCESS_BUS_MSR;
++ ret = parse_msr_args(arg_list, arg_num);
++ } else if (!strncmp(arg_list[1], "i2c", 3)) {
++ access_bus = ACCESS_BUS_I2C;
++ ret = parse_i2c_args(arg_list, arg_num);
++ } else if (!strncmp(arg_list[1], "scu", 3)) {
++ access_bus = ACCESS_BUS_SCU_INDRW;
++ ret = parse_scu_args(arg_list, arg_num);
++ } else {
++ snprintf(err_buf, MAX_ERRLEN, "unknown argument: %s\n",
++ arg_list[1]);
++ }
++
++ if (access_len == 0) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "access length must be larger than 0\n");
++ ret = -EINVAL;
++ goto done;
++ }
++
++ if ((access_bus == ACCESS_BUS_MMIO || access_bus == ACCESS_BUS_PCI) &&
++ (access_len > MAX_MMIO_PCI_LEN)) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "%d exceeds max mmio/pci read length(%d)\n",
++ access_len, MAX_MMIO_PCI_LEN);
++ ret = -EINVAL;
++ goto done;
++ }
++
++ if ((access_bus == ACCESS_BUS_MSG_BUS) &&
++ (access_len > MAX_MSG_BUS_LEN)) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "%d exceeds max msg_bus read length(%d)\n",
++ access_len, MAX_MSG_BUS_LEN);
++ ret = -EINVAL;
++ }
++
++ if (access_bus == ACCESS_BUS_MSR) {
++ if ((access_width != ACCESS_WIDTH_32BIT) &&
++ (access_width != ACCESS_WIDTH_64BIT) &&
++ (access_width != ACCESS_WIDTH_DEFAULT)) {
++ snprintf(err_buf, MAX_ERRLEN,
++ "only 32bit or 64bit is allowed for msr\n");
++ ret = -EINVAL;
++ }
++ }
++
++done:
++ dump_cmd_was_set = ret ? 0 : 1;
++ return ret ? ret : len;
++}
++
++static int dump_output_show_mmio(struct seq_file *s)
++{
++ void __iomem *base;
++ int i, comp1, comp2;
++ u32 start, end, end_natural;
++ struct pci_dev *pdev;
++ char *name;
++
++ pdev = mmio_to_pci(mmio_addr, &name);
++ if (pdev && pm_runtime_get_sync(&pdev->dev) < 0) {
++ seq_printf(s, "can't put device %s into D0i0 state\n", name);
++ return 0;
++ }
++
++ if (access_dir == ACCESS_DIR_WRITE) {
++ base = ioremap_nocache(mmio_addr, access_width);
++ if (!base) {
++ seq_printf(s, "can't map physical address: %x\n",
++ mmio_addr);
++ if (pdev)
++ pm_runtime_put_sync(&pdev->dev);
++ return 0;
++ }
++ switch (access_width) {
++ case ACCESS_WIDTH_8BIT:
++ iowrite8((u8) access_value, base);
++ break;
++ case ACCESS_WIDTH_16BIT:
++ iowrite16((u16) access_value, base);
++ break;
++ case ACCESS_WIDTH_32BIT:
++ case ACCESS_WIDTH_DEFAULT:
++ iowrite32(access_value, base);
++ break;
++ default:
++ break; /* never happen */
++ }
++ seq_printf(s, "write succeeded\n");
++ } else {
++ start = (mmio_addr / LINE_WIDTH) * LINE_WIDTH;
++ end_natural = mmio_addr + (access_len - 1) * access_width;
++ end = (end_natural / LINE_WIDTH + 1) * LINE_WIDTH -
++ access_width;
++ comp1 = (mmio_addr - start) / access_width;
++ comp2 = (end - end_natural) / access_width;
++
++ base = ioremap_nocache(start, (comp1 + comp2 +
++ access_len) * access_width);
++ if (!base) {
++ seq_printf(s, "can't map physical address: %x\n",
++ mmio_addr);
++ if (pdev)
++ pm_runtime_put_sync(&pdev->dev);
++ return 0;
++ }
++
++ for (i = 0; i < comp1 + comp2 + access_len; i++) {
++ if ((i % SHOW_NUM_PER_LINE) == 0)
++ seq_printf(s, "[%08x]", start + i * 4);
++
++ if (i < comp1 || i >= access_len + comp1) {
++ switch (access_width) {
++ case ACCESS_WIDTH_32BIT:
++ seq_printf(s, " ");
++ break;
++ case ACCESS_WIDTH_16BIT:
++ seq_printf(s, " ");
++ break;
++ case ACCESS_WIDTH_8BIT:
++ seq_printf(s, " ");
++ break;
++ }
++
++ } else {
++ switch (access_width) {
++ case ACCESS_WIDTH_32BIT:
++ seq_printf(s, " %08x",
++ ioread32(base + i * 4));
++ break;
++ case ACCESS_WIDTH_16BIT:
++ seq_printf(s, " %04x",
++ (u16) ioread16(base + i * 2));
++ break;
++ case ACCESS_WIDTH_8BIT:
++ seq_printf(s, " %02x",
++ (u8) ioread8(base + i));
++ break;
++ }
++ }
++
++ if ((i + 1) % SHOW_NUM_PER_LINE == 0)
++ seq_printf(s, "\n");
++ }
++ }
++
++ iounmap(base);
++ if (pdev)
++ pm_runtime_put_sync(&pdev->dev);
++ return 0;
++}
++
++static int dump_output_show_port(struct seq_file *s)
++{
++ if (access_dir == ACCESS_DIR_WRITE) {
++ switch (access_width) {
++ case ACCESS_WIDTH_8BIT:
++ case ACCESS_WIDTH_DEFAULT:
++ outb((u8) access_value, port_addr);
++ break;
++ case ACCESS_WIDTH_16BIT:
++ outw((u16) access_value, port_addr);
++ break;
++ case ACCESS_WIDTH_32BIT:
++ outl(access_value, port_addr);
++ break;
++ default:
++ break; /* never happen */
++ }
++ seq_printf(s, "write succeeded\n");
++ } else {
++ switch (access_width) {
++ case ACCESS_WIDTH_32BIT:
++ seq_printf(s, " %08x\n", inl(port_addr));
++ break;
++ case ACCESS_WIDTH_16BIT:
++ seq_printf(s, " %04x\n", (u16) inw(port_addr));
++ break;
++ case ACCESS_WIDTH_8BIT:
++ seq_printf(s, " %02x\n", (u8) inb(port_addr));
++ break;
++ default:
++ break;
++ }
++ }
++
++ return 0;
++}
++
++static int dump_output_show_msg_bus(struct seq_file *s)
++{
++ int i, comp1, comp2;
++ u32 start, end, end_natural;
++
++ if (access_dir == ACCESS_DIR_WRITE) {
++ intel_mid_msgbus_write32(msg_bus_port,
++ msg_bus_addr, access_value);
++ seq_printf(s, "write succeeded\n");
++ } else {
++ start = (msg_bus_addr / LINE_WIDTH) * LINE_WIDTH;
++ end_natural = msg_bus_addr + (access_len - 1) * access_width;
++ end = (end_natural / LINE_WIDTH + 1) * LINE_WIDTH -
++ access_width;
++ comp1 = (msg_bus_addr - start) / access_width;
++ comp2 = (end - end_natural) / access_width;
++
++ for (i = 0; i < comp1 + comp2 + access_len; i++) {
++ if ((i % SHOW_NUM_PER_LINE) == 0)
++ seq_printf(s, "[%08x]", start + i * 4);
++
++ if (i < comp1 || i >= access_len + comp1)
++ seq_printf(s, " ");
++
++ else
++ seq_printf(s, " %08x", intel_mid_msgbus_read32(
++ msg_bus_port, msg_bus_addr + i));
++
++ if ((i + 1) % SHOW_NUM_PER_LINE == 0)
++ seq_printf(s, "\n");
++ }
++ }
++
++ return 0;
++}
++
++static int dump_output_show_pci(struct seq_file *s)
++{
++ int i, comp1, comp2;
++ u32 start, end, end_natural, val;
++ struct pci_dev *pdev;
++
++ pdev = pci_get_bus_and_slot(pci_bus, PCI_DEVFN(pci_dev, pci_func));
++ if (!pdev) {
++ seq_printf(s, "pci bus %d:%d:%d doesn't exist\n",
++ pci_bus, pci_dev, pci_func);
++ return 0;
++ }
++
++ if (pm_runtime_get_sync(&pdev->dev) < 0) {
++ seq_printf(s, "can't put pci device %d:%d:%d into D0i0 state\n",
++ pci_bus, pci_dev, pci_func);
++ return 0;
++ }
++
++ if (access_dir == ACCESS_DIR_WRITE) {
++ switch (access_width) {
++ case ACCESS_WIDTH_8BIT:
++ pci_write_config_byte(pdev, (int)pci_reg,
++ (u8)access_value);
++ break;
++ case ACCESS_WIDTH_16BIT:
++ pci_write_config_word(pdev, (int)pci_reg,
++ (u16)access_value);
++ break;
++ case ACCESS_WIDTH_32BIT:
++ case ACCESS_WIDTH_DEFAULT:
++ pci_write_config_dword(pdev, (int)pci_reg,
++ access_value);
++ break;
++ default:
++ break; /* never happen */
++ }
++ seq_printf(s, "write succeeded\n");
++ } else {
++ start = (pci_reg / LINE_WIDTH) * LINE_WIDTH;
++ end_natural = pci_reg + (access_len - 1) * access_width;
++ end = (end_natural / LINE_WIDTH + 1) * LINE_WIDTH -
++ access_width;
++ comp1 = (pci_reg - start) / access_width;
++ comp2 = (end - end_natural) / access_width;
++
++ for (i = 0; i < comp1 + comp2 + access_len; i++) {
++ if ((i % SHOW_NUM_PER_LINE) == 0)
++ seq_printf(s, "[%08x]", start + i * 4);
++
++ if (i < comp1 || i >= access_len + comp1) {
++ switch (access_width) {
++ case ACCESS_WIDTH_32BIT:
++ seq_printf(s, " ");
++ break;
++ case ACCESS_WIDTH_16BIT:
++ seq_printf(s, " ");
++ break;
++ case ACCESS_WIDTH_8BIT:
++ seq_printf(s, " ");
++ break;
++ }
++
++ } else {
++ switch (access_width) {
++ case ACCESS_WIDTH_32BIT:
++ pci_read_config_dword(pdev,
++ start + i * 4, &val);
++ seq_printf(s, " %08x", val);
++ break;
++ case ACCESS_WIDTH_16BIT:
++ pci_read_config_word(pdev,
++ start + i * 2, (u16 *) &val);
++ seq_printf(s, " %04x", (u16)val);
++ break;
++ case ACCESS_WIDTH_8BIT:
++ pci_read_config_byte(pdev,
++ start + i, (u8 *) &val);
++ seq_printf(s, " %04x", (u8)val);
++ break;
++ }
++ }
++
++ if ((i + 1) % SHOW_NUM_PER_LINE == 0)
++ seq_printf(s, "\n");
++ }
++ }
++
++ return 0;
++}
++
++static int dump_output_show_msr(struct seq_file *s)
++{
++ int ret, i, count;
++ u32 data[2];
++
++ if (access_dir == ACCESS_DIR_READ) {
++ if (msr_cpu < 0) {
++ /* loop for all cpus */
++ i = 0;
++ count = nr_cpu_ids;
++ } else if (msr_cpu >= nr_cpu_ids || msr_cpu < 0) {
++ seq_printf(s, "cpu should be between 0 - %d\n",
++ nr_cpu_ids - 1);
++ return 0;
++ } else {
++ /* loop for one cpu */
++ i = msr_cpu;
++ count = msr_cpu + 1;
++ }
++ for (; i < count; i++) {
++ ret = rdmsr_safe_on_cpu(i, msr_reg, &data[0], &data[1]);
++ if (ret) {
++ seq_printf(s, "msr read error: %d\n", ret);
++ return 0;
++ } else {
++ if (access_width == ACCESS_WIDTH_32BIT)
++ seq_printf(s, "[cpu %1d] %08x\n",
++ i, data[0]);
++ else
++ seq_printf(s, "[cpu %1d] %08x%08x\n",
++ i, data[1], data[0]);
++ }
++ }
++ } else {
++ if (access_width == ACCESS_WIDTH_32BIT) {
++ ret = rdmsr_safe_on_cpu(msr_cpu, msr_reg,
++ &data[0], &data[1]);
++ if (ret) {
++ seq_printf(s, "msr write error: %d\n", ret);
++ return 0;
++ }
++ data[0] = access_value;
++ } else {
++ data[0] = (u32)access_value_64;
++ data[1] = (u32)(access_value_64 >> 32);
++ }
++ if (msr_cpu < 0) {
++ /* loop for all cpus */
++ i = 0;
++ count = nr_cpu_ids;
++ } else {
++ if (msr_cpu >= nr_cpu_ids || msr_cpu < 0) {
++ seq_printf(s, "cpu should be between 0 - %d\n",
++ nr_cpu_ids - 1);
++ return 0;
++ }
++ /* loop for one cpu */
++ i = msr_cpu;
++ count = msr_cpu + 1;
++ }
++ for (; i < count; i++) {
++ ret = wrmsr_safe_on_cpu(i, msr_reg, data[0], data[1]);
++ if (ret) {
++ seq_printf(s, "msr write error: %d\n", ret);
++ return 0;
++ } else {
++ seq_printf(s, "write succeeded.\n");
++ }
++ }
++ }
++
++ return 0;
++}
++
++static int dump_output_show_i2c(struct seq_file *s)
++{
++ int ret;
++ struct i2c_adapter *adap;
++ struct i2c_msg msg;
++ u8 val;
++
++ adap = i2c_get_adapter(i2c_bus);
++ if (!adap) {
++ seq_printf(s, "can't find bus adapter for i2c bus %d\n",
++ i2c_bus);
++ return 0;
++ }
++
++ if (access_dir == ACCESS_DIR_WRITE) {
++ msg.addr = i2c_addr;
++ msg.len = 1;
++ msg.buf = (u8 *) &access_value;
++ ret = i2c_transfer(adap, &msg, 1);
++ if (ret != 1)
++ seq_printf(s, "i2c write error: %d\n", ret);
++ else
++ seq_printf(s, "write succeeded.\n");
++ } else {
++ msg.flags |= I2C_M_RD;
++ msg.addr = i2c_addr;
++ msg.len = 1;
++ msg.buf = &val;
++ ret = i2c_transfer(adap, &msg, 1);
++ if (ret != 1)
++ seq_printf(s, "i2c read error: %d\n", ret);
++ else
++ seq_printf(s, "%02x\n", val);
++ }
++
++ return 0;
++}
++
++static int dump_output_show_scu(struct seq_file *s)
++{
++ struct pci_dev *pdev;
++ char *name;
++ int ret;
++ u32 cmd, sub = 0, dptr = 0, sptr = 0;
++ u8 wbuflen = 4, rbuflen = 4;
++ u8 wbuf[16];
++ u8 rbuf[16];
++
++ memset(wbuf, 0, 16);
++ memset(rbuf, 0, 16);
++
++ pdev = mmio_to_pci(scu_addr, &name);
++ if (pdev && pm_runtime_get_sync(&pdev->dev) < 0) {
++ seq_printf(s, "can't put device %s into D0i0 state\n", name);
++ return 0;
++ }
++
++ if (access_dir == ACCESS_DIR_WRITE) {
++ cmd = RP_INDIRECT_WRITE;
++ dptr = scu_addr;
++ wbuf[0] = (u8) (access_value & 0xff);
++ wbuf[1] = (u8) ((access_value >> 8) & 0xff);
++ wbuf[2] = (u8) ((access_value >> 16) & 0xff);
++ wbuf[3] = (u8) ((access_value >> 24) & 0xff);
++
++ ret = rpmsg_send_generic_raw_command(cmd, sub, wbuf, wbuflen,
++ (u32 *)rbuf, rbuflen, dptr, sptr);
++
++ if (ret) {
++ seq_printf(s,
++ "Indirect write failed (check dmesg): "
++ "[%08x]\n", scu_addr);
++ } else {
++ seq_printf(s, "write succeeded\n");
++ }
++ } else if (access_dir == ACCESS_DIR_READ) {
++ cmd = RP_INDIRECT_READ;
++ sptr = scu_addr;
++
++ ret = rpmsg_send_generic_raw_command(cmd, sub, wbuf, wbuflen,
++ (u32 *)rbuf, rbuflen, dptr, sptr);
++
++ if (ret) {
++ seq_printf(s,
++ "Indirect read failed (check dmesg): "
++ "[%08x]\n", scu_addr);
++ } else {
++ access_value = (rbuf[3] << 24) | (rbuf[2] << 16) |
++ (rbuf[1] << 8) | (rbuf[0]);
++ seq_printf(s, "[%08x] %08x\n", scu_addr, access_value);
++ }
++ }
++
++ if (pdev)
++ pm_runtime_put_sync(&pdev->dev);
++
++ return 0;
++}
++
++static int dump_output_show(struct seq_file *s, void *unused)
++{
++ int ret = 0;
++
++ if (!dump_cmd_was_set) {
++ seq_printf(s, "%s", err_buf);
++ return 0;
++ }
++
++ switch (access_bus) {
++ case ACCESS_BUS_MMIO:
++ ret = dump_output_show_mmio(s);
++ break;
++ case ACCESS_BUS_PORT:
++ ret = dump_output_show_port(s);
++ break;
++ case ACCESS_BUS_MSG_BUS:
++ ret = dump_output_show_msg_bus(s);
++ break;
++ case ACCESS_BUS_PCI:
++ ret = dump_output_show_pci(s);
++ break;
++ case ACCESS_BUS_MSR:
++ ret = dump_output_show_msr(s);
++ break;
++ case ACCESS_BUS_I2C:
++ ret = dump_output_show_i2c(s);
++ break;
++ case ACCESS_BUS_SCU_INDRW:
++ ret = dump_output_show_scu(s);
++ break;
++ default:
++ seq_printf(s, "unknow bus type: %d\n", access_bus);
++ break;
++
++ }
++
++ return ret;
++}
++
++static const struct file_operations dump_cmd_fops = {
++ .owner = THIS_MODULE,
++ .open = dump_cmd_open,
++ .read = seq_read,
++ .write = dump_cmd_write,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++static int dump_output_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, dump_output_show, NULL);
++}
++
++static const struct file_operations dump_output_fops = {
++ .owner = THIS_MODULE,
++ .open = dump_output_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++static int __init intel_mid_dump_init(void)
++{
++ dump_cmd_dentry = debugfs_create_file("dump_cmd",
++ S_IFREG | S_IRUGO | S_IWUSR, NULL, NULL, &dump_cmd_fops);
++ dump_output_dentry = debugfs_create_file("dump_output",
++ S_IFREG | S_IRUGO, NULL, NULL, &dump_output_fops);
++ if (!dump_cmd_dentry || !dump_output_dentry) {
++ pr_err("intel_mid_dump: can't create debugfs node\n");
++ return -EFAULT;
++ }
++ return 0;
++}
++module_init(intel_mid_dump_init);
++
++static void __exit intel_mid_dump_exit(void)
++{
++ if (dump_cmd_dentry)
++ debugfs_remove(dump_cmd_dentry);
++ if (dump_output_dentry)
++ debugfs_remove(dump_output_dentry);
++}
++module_exit(intel_mid_dump_exit);
++
++MODULE_DESCRIPTION("Intel Atom SoC register dump driver");
++MODULE_VERSION("1.0");
++MODULE_AUTHOR("Bin Gao <bin.gao@intel.com>");
++MODULE_LICENSE("GPL v2");
+diff --git a/arch/x86/platform/intel-mid/intel_soc_mdfld.c b/arch/x86/platform/intel-mid/intel_soc_mdfld.c
+new file mode 100644
+index 0000000..e86d1b5
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/intel_soc_mdfld.c
+@@ -0,0 +1,178 @@
++/*
++ * intel_soc_mdfld.c - This driver provides utility api's for medfield
++ * platform
++ * Copyright (c) 2012, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#include "intel_soc_pmu.h"
++
++/* To CLEAR C6 offload Bit(LSB) in MSR 120 */
++static inline void clear_c6offload_bit(void)
++{
++ u32 msr_low, msr_high;
++
++ rdmsr(MSR_C6OFFLOAD_CTL_REG, msr_low, msr_high);
++ msr_low = msr_low & ~MSR_C6OFFLOAD_SET_LOW;
++ msr_high = msr_high & ~MSR_C6OFFLOAD_SET_HIGH;
++ wrmsr(MSR_C6OFFLOAD_CTL_REG, msr_low, msr_high);
++}
++
++/* To SET C6 offload Bit(LSB) in MSR 120 */
++static inline void set_c6offload_bit(void)
++{
++ u32 msr_low, msr_high;
++
++ rdmsr(MSR_C6OFFLOAD_CTL_REG, msr_low, msr_high);
++ msr_low = msr_low | MSR_C6OFFLOAD_SET_LOW;
++ msr_high = msr_high | MSR_C6OFFLOAD_SET_HIGH;
++ wrmsr(MSR_C6OFFLOAD_CTL_REG, msr_low, msr_high);
++}
++
++static bool mfld_pmu_enter(int s0ix_state)
++{
++ u32 s0ix_value;
++ u32 ssw_val;
++ int num_retry = PMU_MISC_SET_TIMEOUT;
++
++ s0ix_value = get_s0ix_val_set_pm_ssc(s0ix_state);
++
++ clear_c6offload_bit();
++
++ /* issue a command to SCU */
++ pmu_set_interrupt_enable();
++ writel(s0ix_value, &mid_pmu_cxt->pmu_reg->pm_cmd);
++
++ pmu_log_command(s0ix_value, NULL);
++
++ do {
++ if (readl(&mid_pmu_cxt->pmu_reg->pm_msic))
++ break;
++ udelay(1);
++ } while (--num_retry);
++
++ if (!num_retry && !readl(&mid_pmu_cxt->pmu_reg->pm_msic))
++ WARN(1, "%s: pm_msic not set.\n", __func__);
++
++ num_retry = PMU_C6OFFLOAD_ACCESS_TIMEOUT;
++
++ /* At this point we have committed an S0ix command
++ * will have to wait for the SCU s0ix complete
++ * intertupt to proceed further.
++ */
++ mid_pmu_cxt->s0ix_entered = s0ix_state;
++
++ if (s0ix_value == S0I3_VALUE) {
++ do {
++ ssw_val = readl(mid_pmu_cxt->base_addr.offload_reg);
++ if ((ssw_val & C6OFFLOAD_BIT_MASK) == C6OFFLOAD_BIT) {
++ set_c6offload_bit();
++ break;
++ }
++
++ udelay(1);
++ } while (--num_retry);
++
++ if (unlikely(!num_retry)) {
++ WARN(1, "mid_pmu: error cpu offload bit not set.\n");
++ pmu_stat_clear();
++ return false;
++ }
++ }
++
++ return true;
++}
++
++static void mfld_pmu_wakeup(void)
++{
++
++ /* Wakeup allother CPU's */
++ if (mid_pmu_cxt->s0ix_entered)
++ apic->send_IPI_allbutself(RESCHEDULE_VECTOR);
++
++ clear_c6offload_bit();
++}
++
++static void mfld_pmu_remove(void)
++{
++ /* Freeing up memory allocated for PMU1 & PMU2 */
++ iounmap(mid_pmu_cxt->base_addr.offload_reg);
++ mid_pmu_cxt->base_addr.offload_reg = NULL;
++
++}
++
++static pci_power_t mfld_pmu_choose_state(int device_lss)
++{
++ pci_power_t state;
++
++ switch (device_lss) {
++ case PMU_SECURITY_LSS_04:
++ state = PCI_D2;
++ break;
++
++ case PMU_USB_OTG_LSS_06:
++ case PMU_USB_HSIC_LSS_07:
++ case PMU_UART2_LSS_41:
++ state = PCI_D1;
++ break;
++
++ default:
++ state = PCI_D3hot;
++ break;
++ }
++
++ return state;
++}
++
++static int mfld_pmu_init(void)
++{
++ int ret = PMU_SUCCESS;
++
++ /* Map the memory of offload_reg */
++ mid_pmu_cxt->base_addr.offload_reg =
++ ioremap_nocache(C6_OFFLOAD_REG_ADDR, 4);
++ if (mid_pmu_cxt->base_addr.offload_reg == NULL) {
++ dev_dbg(&mid_pmu_cxt->pmu_dev->dev,
++ "Unable to map the offload_reg address space\n");
++ ret = PMU_FAILED;
++ goto out_err;
++ }
++
++ mid_pmu_cxt->s3_hint = C6_HINT;
++
++out_err:
++ return ret;
++}
++
++/**
++ * platform_set_pmu_ops - Set the global pmu method table.
++ * @ops: Pointer to ops structure.
++ */
++void platform_set_pmu_ops(void)
++{
++ pmu_ops = &mfld_pmu_ops;
++}
++
++struct platform_pmu_ops mfld_pmu_ops = {
++ .init = mfld_pmu_init,
++ .enter = mfld_pmu_enter,
++ .wakeup = mfld_pmu_wakeup,
++ .remove = mfld_pmu_remove,
++ .pci_choose_state = mfld_pmu_choose_state,
++ .set_power_state_ops = pmu_set_s0ix_possible,
++ .set_s0ix_complete = s0ix_complete,
++ .nc_set_power_state = mdfld_clv_nc_set_power_state,
++};
+diff --git a/arch/x86/platform/intel-mid/intel_soc_mdfld.h b/arch/x86/platform/intel-mid/intel_soc_mdfld.h
+new file mode 100644
+index 0000000..85c25b5
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/intel_soc_mdfld.h
+@@ -0,0 +1,353 @@
++/*
++ * intel_soc_mdfld.h
++ * Copyright (c) 2012, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#ifdef CONFIG_REMOVEME_INTEL_REMOVEME_ATOM_MDFLD_POWER
++
++#define PM_SUPPORT 0x21
++
++#define ISP_POS 7
++#define ISP_SUB_CLASS 0x80
++#define C6_OFFLOAD_REG_ADDR 0xffd01ffc
++#define PMU_MISC_SET_TIMEOUT 50 /* 50usec timeout */
++#define PMU_C6OFFLOAD_ACCESS_TIMEOUT 1500 /* 1.5msecs timeout */
++
++#define PMU1_MAX_DEVS 8
++#define PMU2_MAX_DEVS 55
++
++#define GFX_LSS_INDEX 1
++#define PMU_SDIO0_LSS_00 0
++#define PMU_EMMC0_LSS_01 1
++#define PMU_AONT_LSS_02 2
++#define PMU_HSI_LSS_03 3
++#define PMU_SECURITY_LSS_04 4
++#define PMU_EMMC1_LSS_05 5
++#define PMU_USB_OTG_LSS_06 6
++#define PMU_USB_HSIC_LSS_07 7
++#define PMU_AUDIO_ENGINE_LSS_08 8
++#define PMU_AUDIO_DMA_LSS_09 9
++#define PMU_SRAM_LSS_10 10
++#define PMU_SRAM_LSS_11 11
++#define PMU_SRAM_LSS_12 12
++#define PMU_SRAM_LSS_13 13
++#define PMU_SDIO2_LSS_14 14
++#define PMU_PTI_DAFCA_LSS_15 15
++#define PMU_SC_DMA_LSS_16 16
++#define PMU_SPIO_LSS_17 17
++#define PMU_SPI1_LSS_18 18
++#define PMU_SPI2_LSS_19 19
++#define PMU_I2C0_LSS_20 20
++#define PMU_I2C1_LSS_21 21
++#define PMU_MAIN_FABRIC_LSS_22 22
++#define PMU_SEC_FABRIC_LSS_23 23
++#define PMU_SC_FABRIC_LSS_24 24
++#define PMU_AUDIO_RAM_LSS_25 25
++#define PMU_SCU_ROM_LSS_26 26
++#define PMU_I2C2_LSS_27 27
++#define PMU_SSC_LSS_28 28
++#define PMU_SECURITY_LSS_29 29
++#define PMU_SDIO1_LSS_30 30
++#define PMU_SCU_RAM0_LSS_31 31
++#define PMU_SCU_RAM1_LSS_32 32
++#define PMU_I2C3_LSS_33 33
++#define PMU_I2C4_LSS_34 34
++#define PMU_I2C5_LSS_35 35
++#define PMU_SPI3_LSS_36 36
++#define PMU_GPIO1_LSS_37 37
++#define PMU_PWR_BUTTON_LSS_38 38
++#define PMU_GPIO0_LSS_39 39
++#define PMU_KEYBRD_LSS_40 40
++#define PMU_UART2_LSS_41 41
++#define PMU_ADC_LSS_42 42
++#define PMU_CHARGER_LSS_43 43
++#define PMU_SEC_TAPC_LSS_44 44
++#define PMU_RTC_LSS_45 45
++#define PMU_GPI_LSS_46 46
++#define PMU_HDMI_VREG_LSS_47 47
++#define PMU_RESERVED_LSS_48 48
++#define PMU_AUDIO_SLIM1_LSS_49 49
++#define PMU_RESET_LSS_50 50
++#define PMU_AUDIO_SSP0_LSS_51 51
++#define PMU_AUDIO_SSP1_LSS_52 52
++#define PMU_IOSF_OCP_BRG_LSS_53 53
++#define PMU_GP_DMA_LSS_54 54
++#define PMU_SVID_LSS_55 55
++#define PMU_SOC_FUSE_LSS_56 56
++#define PMU_RSVD3_LSS_57 57
++#define PMU_RSVD4_LSS_58 58
++#define PMU_RSVD5_LSS_59 59
++#define PMU_RSVD6_LSS_60 60
++#define PMU_RSVD7_LSS_61 61
++#define PMU_RSVD8_LSS_62 62
++#define PMU_RSVD9_LSS_63 63
++
++#define PMU_MAX_LSS 63
++#define PMU_LSS_IN_FIRST_DWORD 32
++
++#define EMMC0_LSS PMU_EMMC0_LSS_01
++
++#define S0IX_TARGET_SSS0_MASK ( \
++ SSMSK(D0I3_MASK, PMU_SDIO0_LSS_00) | \
++ SSMSK(D0I3_MASK, PMU_EMMC0_LSS_01) | \
++ SSMSK(D0I3_MASK, PMU_HSI_LSS_03) | \
++ SSMSK(D0I3_MASK, PMU_SECURITY_LSS_04) | \
++ SSMSK(D0I3_MASK, PMU_EMMC1_LSS_05) | \
++ SSMSK(D0I3_MASK, PMU_USB_OTG_LSS_06) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_ENGINE_LSS_08) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_DMA_LSS_09) | \
++ SSMSK(D0I3_MASK, PMU_SDIO2_LSS_14))
++
++#define S0IX_TARGET_SSS1_MASK ( \
++ SSMSK(D0I3_MASK, PMU_SPI1_LSS_18-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C0_LSS_20-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C1_LSS_21-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C2_LSS_27-16) | \
++ SSMSK(D0I3_MASK, PMU_SDIO1_LSS_30-16))
++#define S0IX_TARGET_SSS2_MASK ( \
++ SSMSK(D0I3_MASK, PMU_I2C3_LSS_33-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C4_LSS_34-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C5_LSS_35-32) | \
++ SSMSK(D0I3_MASK, PMU_SPI3_LSS_36-32) | \
++ SSMSK(D0I3_MASK, PMU_UART2_LSS_41-32))
++
++#define S0IX_TARGET_SSS3_MASK ( \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP0_LSS_51-48) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP1_LSS_52-48))
++
++#define S0IX_TARGET_SSS0 ( \
++ SSMSK(D0I3_MASK, PMU_SDIO0_LSS_00) | \
++ SSMSK(D0I3_MASK, PMU_EMMC0_LSS_01) | \
++ SSMSK(D0I3_MASK, PMU_HSI_LSS_03) | \
++ SSMSK(D0I2_MASK, PMU_SECURITY_LSS_04) | \
++ SSMSK(D0I3_MASK, PMU_EMMC1_LSS_05) | \
++ SSMSK(D0I1_MASK, PMU_USB_OTG_LSS_06) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_ENGINE_LSS_08) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_DMA_LSS_09) | \
++ SSMSK(D0I3_MASK, PMU_SDIO2_LSS_14))
++
++#define S0IX_TARGET_SSS1 ( \
++ SSMSK(D0I3_MASK, PMU_SPI1_LSS_18-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C0_LSS_20-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C1_LSS_21-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C2_LSS_27-16) | \
++ SSMSK(D0I3_MASK, PMU_SDIO1_LSS_30-16))
++
++#define S0IX_TARGET_SSS2 ( \
++ SSMSK(D0I3_MASK, PMU_I2C3_LSS_33-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C4_LSS_34-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C5_LSS_35-32) | \
++ SSMSK(D0I3_MASK, PMU_SPI3_LSS_36-32) | \
++ SSMSK(D0I1_MASK, PMU_UART2_LSS_41-32))
++
++#define S0IX_TARGET_SSS3 ( \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP0_LSS_51-48) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP1_LSS_52-48))
++
++#define LPMP3_TARGET_SSS0_MASK ( \
++ SSMSK(D0I3_MASK, PMU_SDIO0_LSS_00) | \
++ SSMSK(D0I3_MASK, PMU_EMMC0_LSS_01) | \
++ SSMSK(D0I3_MASK, PMU_HSI_LSS_03) | \
++ SSMSK(D0I3_MASK, PMU_SECURITY_LSS_04) | \
++ SSMSK(D0I3_MASK, PMU_EMMC1_LSS_05) | \
++ SSMSK(D0I3_MASK, PMU_USB_OTG_LSS_06) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_ENGINE_LSS_08) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_DMA_LSS_09) | \
++ SSMSK(D0I3_MASK, PMU_SDIO2_LSS_14))
++
++#define LPMP3_TARGET_SSS1_MASK ( \
++ SSMSK(D0I3_MASK, PMU_SPI1_LSS_18-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C0_LSS_20-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C1_LSS_21-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C2_LSS_27-16) | \
++ SSMSK(D0I3_MASK, PMU_SDIO1_LSS_30-16))
++
++#define LPMP3_TARGET_SSS2_MASK ( \
++ SSMSK(D0I3_MASK, PMU_I2C3_LSS_33-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C4_LSS_34-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C5_LSS_35-32) | \
++ SSMSK(D0I3_MASK, PMU_SPI3_LSS_36-32) | \
++ SSMSK(D0I3_MASK, PMU_UART2_LSS_41-32))
++
++#define LPMP3_TARGET_SSS3_MASK ( \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP0_LSS_51-48) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP1_LSS_52-48))
++
++#define LPMP3_TARGET_SSS0 ( \
++ SSMSK(D0I3_MASK, PMU_SDIO0_LSS_00) | \
++ SSMSK(D0I3_MASK, PMU_EMMC0_LSS_01) | \
++ SSMSK(D0I3_MASK, PMU_HSI_LSS_03) | \
++ SSMSK(D0I2_MASK, PMU_SECURITY_LSS_04) | \
++ SSMSK(D0I3_MASK, PMU_EMMC1_LSS_05) | \
++ SSMSK(D0I1_MASK, PMU_USB_OTG_LSS_06) | \
++ SSMSK(D0I0_MASK, PMU_AUDIO_ENGINE_LSS_08) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_DMA_LSS_09) | \
++ SSMSK(D0I3_MASK, PMU_SDIO2_LSS_14))
++
++#define LPMP3_TARGET_SSS1 ( \
++ SSMSK(D0I3_MASK, PMU_SPI1_LSS_18-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C0_LSS_20-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C1_LSS_21-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C2_LSS_27-16) | \
++ SSMSK(D0I3_MASK, PMU_SDIO1_LSS_30-16))
++
++#define LPMP3_TARGET_SSS2 ( \
++ SSMSK(D0I3_MASK, PMU_I2C3_LSS_33-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C4_LSS_34-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C5_LSS_35-32) | \
++ SSMSK(D0I3_MASK, PMU_SPI3_LSS_36-32) | \
++ SSMSK(D0I1_MASK, PMU_UART2_LSS_41-32))
++
++#define LPMP3_TARGET_SSS3 ( \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP0_LSS_51-48) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP1_LSS_52-48))
++
++#define IGNORE_SSS0 ( \
++ SSMSK(D0I3_MASK, PMU_USB_HSIC_LSS_07) | \
++ SSMSK(D0I3_MASK, PMU_SRAM_LSS_10) | \
++ SSMSK(D0I3_MASK, PMU_SRAM_LSS_11) | \
++ SSMSK(D0I3_MASK, PMU_SRAM_LSS_12) | \
++ SSMSK(D0I3_MASK, PMU_SRAM_LSS_13) | \
++ SSMSK(D0I3_MASK, PMU_PTI_DAFCA_LSS_15))
++
++#define IGNORE_SSS1 ( \
++ SSMSK(D0I3_MASK, PMU_SC_DMA_LSS_16-16) | \
++ SSMSK(D0I3_MASK, PMU_SPIO_LSS_17-16) | \
++ SSMSK(D0I3_MASK, PMU_MAIN_FABRIC_LSS_22-16) | \
++ SSMSK(D0I3_MASK, PMU_SEC_FABRIC_LSS_23-16) | \
++ SSMSK(D0I3_MASK, PMU_SC_FABRIC_LSS_24-16) | \
++ SSMSK(D0I3_MASK, PMU_SCU_ROM_LSS_26-16) | \
++ SSMSK(D0I3_MASK, PMU_SSC_LSS_28-16) | \
++ SSMSK(D0I3_MASK, PMU_SECURITY_LSS_29-16) | \
++ SSMSK(D0I3_MASK, PMU_SCU_RAM0_LSS_31-16))
++
++#define IGNORE_SSS2 ( \
++ SSMSK(D0I3_MASK, PMU_SCU_RAM1_LSS_32-32) | \
++ SSMSK(D0I3_MASK, PMU_GPIO1_LSS_37-32) | \
++ SSMSK(D0I3_MASK, PMU_PWR_BUTTON_LSS_38-32) | \
++ SSMSK(D0I3_MASK, PMU_GPIO0_LSS_39-32) | \
++ SSMSK(D0I3_MASK, PMU_ADC_LSS_42-32) | \
++ SSMSK(D0I3_MASK, PMU_CHARGER_LSS_43-32) | \
++ SSMSK(D0I3_MASK, PMU_SEC_TAPC_LSS_44-32) | \
++ SSMSK(D0I3_MASK, PMU_RTC_LSS_45-32) | \
++ SSMSK(D0I3_MASK, PMU_GPI_LSS_46-32) | \
++ SSMSK(D0I3_MASK, PMU_HDMI_VREG_LSS_47-32))
++
++#define IGNORE_SSS3 ( \
++ SSMSK(D0I3_MASK, PMU_IOSF_OCP_BRG_LSS_53-48) | \
++ SSMSK(D0I3_MASK, PMU_SVID_LSS_55-48) | \
++ SSMSK(D0I3_MASK, PMU_SOC_FUSE_LSS_56-48) | \
++ SSMSK(D0I3_MASK, PMU_RSVD3_LSS_57-48) | \
++ SSMSK(D0I3_MASK, PMU_RSVD4_LSS_58-48) | \
++ SSMSK(D0I3_MASK, PMU_RSVD5_LSS_59-48) | \
++ SSMSK(D0I3_MASK, PMU_RSVD6_LSS_60-48) | \
++ SSMSK(D0I3_MASK, PMU_RSVD7_LSS_61-48) | \
++ SSMSK(D0I3_MASK, PMU_RSVD8_LSS_62-48) | \
++ SSMSK(D0I3_MASK, PMU_RSVD9_LSS_63-48))
++
++#define IGNORE_S3_WKC0 SSWKC(PMU_AONT_LSS_02)
++#define IGNORE_S3_WKC1 SSWKC(PMU_ADC_LSS_42-32)
++
++#define S0I3_SSS0 ( \
++ SSMSK(D0I3_MASK, PMU_SDIO0_LSS_00) | \
++ SSMSK(D0I3_MASK, PMU_EMMC0_LSS_01) | \
++ SSMSK(D0I3_MASK, PMU_AONT_LSS_02) | \
++ SSMSK(D0I3_MASK, PMU_HSI_LSS_03) | \
++ SSMSK(D0I2_MASK, PMU_SECURITY_LSS_04) | \
++ SSMSK(D0I3_MASK, PMU_EMMC1_LSS_05) | \
++ SSMSK(D0I1_MASK, PMU_USB_OTG_LSS_06) | \
++ SSMSK(D0I1_MASK, PMU_USB_HSIC_LSS_07) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_ENGINE_LSS_08) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_DMA_LSS_09) | \
++ SSMSK(D0I3_MASK, PMU_SRAM_LSS_12) | \
++ SSMSK(D0I3_MASK, PMU_SRAM_LSS_13) | \
++ SSMSK(D0I3_MASK, PMU_SDIO2_LSS_14))
++
++#define S0I3_SSS1 ( \
++ SSMSK(D0I3_MASK, PMU_SPI1_LSS_18-16) | \
++ SSMSK(D0I3_MASK, PMU_SPI2_LSS_19-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C0_LSS_20-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C1_LSS_21-16) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_RAM_LSS_25-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C2_LSS_27-16) | \
++ SSMSK(D0I3_MASK, PMU_SDIO1_LSS_30-16))
++
++#define S0I3_SSS2 ( \
++ SSMSK(D0I3_MASK, PMU_I2C3_LSS_33-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C4_LSS_34-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C5_LSS_35-32) | \
++ SSMSK(D0I3_MASK, PMU_SPI3_LSS_36-32) | \
++ SSMSK(D0I3_MASK, PMU_GPIO1_LSS_37-32) | \
++ SSMSK(D0I3_MASK, PMU_PWR_BUTTON_LSS_38-32) | \
++ SSMSK(D0I3_MASK, PMU_KEYBRD_LSS_40-32) | \
++ SSMSK(D0I1_MASK, PMU_UART2_LSS_41-32))
++
++#define S0I3_SSS3 ( \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SLIM1_LSS_49-48) | \
++ SSMSK(D0I3_MASK, PMU_RESET_LSS_50-48) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP0_LSS_51-48) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP1_LSS_52-48) | \
++ SSMSK(D0I3_MASK, PMU_GP_DMA_LSS_54-48))
++
++#define S0I1_SSS0 S0I3_SSS0
++#define S0I1_SSS1 S0I3_SSS1
++#define S0I1_SSS2 S0I3_SSS2
++#define S0I1_SSS3 S0I3_SSS3
++
++#define LPMP3_SSS0 ( \
++ SSMSK(D0I3_MASK, PMU_SDIO0_LSS_00) | \
++ SSMSK(D0I3_MASK, PMU_EMMC0_LSS_01) | \
++ SSMSK(D0I3_MASK, PMU_AONT_LSS_02) | \
++ SSMSK(D0I3_MASK, PMU_HSI_LSS_03) | \
++ SSMSK(D0I2_MASK, PMU_SECURITY_LSS_04) | \
++ SSMSK(D0I3_MASK, PMU_EMMC1_LSS_05) | \
++ SSMSK(D0I1_MASK, PMU_USB_OTG_LSS_06) | \
++ SSMSK(D0I1_MASK, PMU_USB_HSIC_LSS_07) | \
++ SSMSK(D0I3_MASK, PMU_SDIO2_LSS_14))
++
++#define LPMP3_SSS1 ( \
++ SSMSK(D0I3_MASK, PMU_SPI1_LSS_18-16) | \
++ SSMSK(D0I3_MASK, PMU_SPI2_LSS_19-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C0_LSS_20-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C1_LSS_21-16) | \
++ SSMSK(D0I3_MASK, PMU_I2C2_LSS_27-16) | \
++ SSMSK(D0I3_MASK, PMU_SDIO1_LSS_30-16))
++
++#define LPMP3_SSS2 ( \
++ SSMSK(D0I3_MASK, PMU_I2C3_LSS_33-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C4_LSS_34-32) | \
++ SSMSK(D0I3_MASK, PMU_I2C5_LSS_35-32) | \
++ SSMSK(D0I3_MASK, PMU_SPI3_LSS_36-32) | \
++ SSMSK(D0I3_MASK, PMU_GPIO1_LSS_37-32) | \
++ SSMSK(D0I3_MASK, PMU_PWR_BUTTON_LSS_38-32) | \
++ SSMSK(D0I3_MASK, PMU_KEYBRD_LSS_40-32) | \
++ SSMSK(D0I1_MASK, PMU_UART2_LSS_41-32))
++
++#define LPMP3_SSS3 ( \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SLIM1_LSS_49-48) | \
++ SSMSK(D0I3_MASK, PMU_RESET_LSS_50-48) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP0_LSS_51-48) | \
++ SSMSK(D0I3_MASK, PMU_AUDIO_SSP1_LSS_52-48) | \
++ SSMSK(D0I3_MASK, PMU_GP_DMA_LSS_54-48))
++
++extern void pmu_set_s0ix_possible(int state);
++extern void log_wakeup_irq(void);
++extern void s0ix_complete(void);
++extern int mdfld_clv_nc_set_power_state(int, int, int, int *);
++
++
++#endif
+diff --git a/arch/x86/platform/intel-mid/intel_soc_mdfld_clv_common.c b/arch/x86/platform/intel-mid/intel_soc_mdfld_clv_common.c
+new file mode 100644
+index 0000000..8ae0930
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/intel_soc_mdfld_clv_common.c
+@@ -0,0 +1,451 @@
++/*
++ * intel_soc_mdfld_clv_common.c - This driver provides utility api's common for
++ * mdfld and clv platforms
++ * Copyright (c) 2012, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#include "intel_soc_pmu.h"
++
++static int extended_cstate_mode = MID_S0IX_STATE;
++int set_extended_cstate_mode(const char *val, struct kernel_param *kp)
++{
++ char valcp[5];
++ int cstate_mode;
++
++ memcpy(valcp, val, 5);
++ valcp[4] = '\0';
++
++ if (strcmp(valcp, "s0i1") == 0)
++ cstate_mode = MID_S0I1_STATE;
++ else if (strcmp(valcp, "lmp3") == 0)
++ cstate_mode = MID_LPMP3_STATE;
++ else if (strcmp(valcp, "s0i3") == 0)
++ cstate_mode = MID_S0I3_STATE;
++ else if (strcmp(valcp, "i1i3") == 0)
++ cstate_mode = MID_I1I3_STATE;
++ else if (strcmp(valcp, "lpi1") == 0)
++ cstate_mode = MID_LPI1_STATE;
++ else if (strcmp(valcp, "lpi3") == 0)
++ cstate_mode = MID_LPI3_STATE;
++ else if (strcmp(valcp, "s0ix") == 0)
++ cstate_mode = MID_S0IX_STATE;
++ else {
++ cstate_mode = 0;
++ strncpy(valcp, "none", 5);
++ }
++ memcpy(s0ix, valcp, 5);
++
++ down(&mid_pmu_cxt->scu_ready_sem);
++ extended_cstate_mode = cstate_mode;
++ up(&mid_pmu_cxt->scu_ready_sem);
++
++ return 0;
++}
++
++int get_extended_cstate_mode(char *buffer, struct kernel_param *kp)
++{
++ strcpy(buffer, s0ix);
++ return 4;
++}
++
++/*
++ *Decide which state the platfrom can go to based on user and
++ *platfrom inputs
++*/
++static int get_final_state(unsigned long *eax)
++{
++ int ret = 0;
++ int possible = mid_pmu_cxt->s0ix_possible;
++
++ switch (extended_cstate_mode) {
++ case MID_S0I1_STATE:
++ case MID_S0I3_STATE:
++ case MID_I1I3_STATE:
++ /* user asks s0i1/s0i3 then only
++ * do s0i1/s0i3, dont do lpmp3
++ */
++ if (possible == MID_S0IX_STATE)
++ ret = extended_cstate_mode & possible;
++ break;
++
++ case MID_LPMP3_STATE:
++ /* user asks lpmp3 then only
++ * do lpmp3
++ */
++ if (possible == MID_LPMP3_STATE)
++ ret = MID_LPMP3_STATE;
++ break;
++
++ case MID_LPI1_STATE:
++ case MID_LPI3_STATE:
++ /* user asks lpmp3/i1/i3 then only
++ * do lpmp3/i1/i3
++ */
++ if (possible == MID_LPMP3_STATE)
++ ret = MID_LPMP3_STATE;
++ else if (possible == MID_S0IX_STATE)
++ ret = extended_cstate_mode >> REMOVE_LP_FROM_LPIX;
++ break;
++
++ case MID_S0IX_STATE:
++ ret = possible;
++ break;
++ }
++
++ if ((ret == MID_S0IX_STATE) &&
++ (*eax == MID_LPMP3_STATE))
++ ret = MID_S0I1_STATE;
++ else if ((ret <= *eax ||
++ (ret == MID_S0IX_STATE)))
++ ret = ret & *eax;
++ else
++ ret = 0;
++
++ return ret;
++}
++
++static bool check_s0ix_possible(struct pmu_ss_states *pmsss)
++{
++ if (((pmsss->pmu2_states[0] & S0IX_TARGET_SSS0_MASK) ==
++ S0IX_TARGET_SSS0) &&
++ ((pmsss->pmu2_states[1] & S0IX_TARGET_SSS1_MASK) ==
++ S0IX_TARGET_SSS1) &&
++ ((pmsss->pmu2_states[2] & S0IX_TARGET_SSS2_MASK) ==
++ S0IX_TARGET_SSS2) &&
++ ((pmsss->pmu2_states[3] & S0IX_TARGET_SSS3_MASK) ==
++ S0IX_TARGET_SSS3))
++ return true;
++
++ return false;
++}
++
++static bool check_lpmp3_possible(struct pmu_ss_states *pmsss)
++{
++ if (((pmsss->pmu2_states[0] & LPMP3_TARGET_SSS0_MASK) ==
++ LPMP3_TARGET_SSS0) &&
++ ((pmsss->pmu2_states[1] & LPMP3_TARGET_SSS1_MASK) ==
++ LPMP3_TARGET_SSS1) &&
++ ((pmsss->pmu2_states[2] & LPMP3_TARGET_SSS2_MASK) ==
++ LPMP3_TARGET_SSS2) &&
++ ((pmsss->pmu2_states[3] & LPMP3_TARGET_SSS3_MASK) ==
++ LPMP3_TARGET_SSS3))
++ return true;
++
++ return false;
++}
++
++void pmu_set_s0ix_possible(int state)
++{
++ /* assume S0ix not possible */
++ mid_pmu_cxt->s0ix_possible = 0;
++
++ if (state != PCI_D0) {
++ struct pmu_ss_states cur_pmsss;
++
++ pmu_read_sss(&cur_pmsss);
++
++ if (likely(check_s0ix_possible(&cur_pmsss)))
++ mid_pmu_cxt->s0ix_possible = MID_S0IX_STATE;
++ else if (check_lpmp3_possible(&cur_pmsss))
++ mid_pmu_cxt->s0ix_possible = MID_LPMP3_STATE;
++ }
++}
++
++int get_target_platform_state(unsigned long *eax)
++{
++ int ret = 0;
++
++ if (unlikely(!pmu_initialized))
++ goto ret;
++
++ /* dont do s0ix if suspend in progress */
++ if (unlikely(mid_pmu_cxt->suspend_started))
++ goto ret;
++
++ /* dont do s0ix if shutdown in progress */
++ if (unlikely(mid_pmu_cxt->shutdown_started))
++ goto ret;
++
++ if (nc_device_state())
++ goto ret;
++
++ ret = get_final_state(eax);
++
++ret:
++ *eax = C6_HINT;
++ return ret;
++}
++EXPORT_SYMBOL(get_target_platform_state);
++
++u32 get_s0ix_val_set_pm_ssc(int s0ix_state)
++{
++ u32 s0ix_value = 0;
++
++ switch (s0ix_state) {
++ case MID_S0I1_STATE:
++ writel(S0I1_SSS0, &mid_pmu_cxt->pmu_reg->pm_ssc[0]);
++ writel(S0I1_SSS1, &mid_pmu_cxt->pmu_reg->pm_ssc[1]);
++ writel(S0I1_SSS2, &mid_pmu_cxt->pmu_reg->pm_ssc[2]);
++ writel(S0I1_SSS3, &mid_pmu_cxt->pmu_reg->pm_ssc[3]);
++ pmu_stat_start(SYS_STATE_S0I1);
++ s0ix_value = S0I1_VALUE;
++ break;
++ case MID_LPMP3_STATE:
++ writel(LPMP3_SSS0, &mid_pmu_cxt->pmu_reg->pm_ssc[0]);
++ writel(LPMP3_SSS1, &mid_pmu_cxt->pmu_reg->pm_ssc[1]);
++ writel(LPMP3_SSS2, &mid_pmu_cxt->pmu_reg->pm_ssc[2]);
++ writel(LPMP3_SSS3, &mid_pmu_cxt->pmu_reg->pm_ssc[3]);
++ pmu_stat_start(SYS_STATE_S0I2);
++ s0ix_value = LPMP3_VALUE;
++ break;
++ case MID_S0I3_STATE:
++ writel(S0I3_SSS0, &mid_pmu_cxt->pmu_reg->pm_ssc[0]);
++ writel(S0I3_SSS1, &mid_pmu_cxt->pmu_reg->pm_ssc[1]);
++ writel(S0I3_SSS2, &mid_pmu_cxt->pmu_reg->pm_ssc[2]);
++ writel(S0I3_SSS3, &mid_pmu_cxt->pmu_reg->pm_ssc[3]);
++ pmu_stat_start(SYS_STATE_S0I3);
++ s0ix_value = S0I3_VALUE;
++ break;
++ case MID_S3_STATE:
++ writel(S0I3_SSS0, &mid_pmu_cxt->pmu_reg->pm_ssc[0]);
++ writel(S0I3_SSS1, &mid_pmu_cxt->pmu_reg->pm_ssc[1]);
++ writel(S0I3_SSS2, &mid_pmu_cxt->pmu_reg->pm_ssc[2]);
++ writel(S0I3_SSS3, &mid_pmu_cxt->pmu_reg->pm_ssc[3]);
++ pmu_stat_start(SYS_STATE_S3);
++ s0ix_value = S0I3_VALUE;
++ break;
++ case MID_FAST_ON_OFF_STATE:
++ writel(S0I3_SSS0, &mid_pmu_cxt->pmu_reg->pm_ssc[0]);
++ writel(S0I3_SSS1, &mid_pmu_cxt->pmu_reg->pm_ssc[1]);
++ writel(S0I3_SSS2, &mid_pmu_cxt->pmu_reg->pm_ssc[2]);
++ writel(S0I3_SSS3, &mid_pmu_cxt->pmu_reg->pm_ssc[3]);
++ pmu_stat_start(SYS_STATE_S3);
++ s0ix_value = FAST_ON_OFF_VALUE;
++ break;
++ default:
++ pmu_dump_logs();
++ BUG_ON(1);
++ }
++ return s0ix_value;
++}
++
++void platform_update_all_lss_states(struct pmu_ss_states *pmu_config,
++ int *PCIALLDEV_CFG)
++{
++ /* We shutdown devices that are in the target config, and that are
++ not in the pci table, some devices are indeed not advertised in pci
++ table for certain firmwares. This is the case for HSI firmwares,
++ SPI3 device is not advertised, and would then prevent s0i3. */
++ /* Also take IGNORE_CFG in account (for e.g. GPIO1)*/
++ pmu_config->pmu2_states[0] |= S0IX_TARGET_SSS0_MASK & ~PCIALLDEV_CFG[0];
++ pmu_config->pmu2_states[0] &= ~IGNORE_SSS0;
++ pmu_config->pmu2_states[1] |= S0IX_TARGET_SSS1_MASK & ~PCIALLDEV_CFG[1];
++ pmu_config->pmu2_states[1] &= ~IGNORE_SSS1;
++ pmu_config->pmu2_states[2] |= S0IX_TARGET_SSS2_MASK & ~PCIALLDEV_CFG[2];
++ pmu_config->pmu2_states[2] &= ~IGNORE_SSS2;
++ pmu_config->pmu2_states[3] |= S0IX_TARGET_SSS3_MASK & ~PCIALLDEV_CFG[3];
++ pmu_config->pmu2_states[3] &= ~IGNORE_SSS3;
++}
++
++void s0ix_complete(void)
++{
++ if (unlikely(mid_pmu_cxt->s0ix_entered))
++ writel(0, &mid_pmu_cxt->pmu_reg->pm_msic);
++}
++
++/*
++ * Valid wake source: lss_number 0 to 63
++ * Returns true if 'lss_number' is wake source
++ * else false
++ */
++bool mid_pmu_is_wake_source(u32 lss_number)
++{
++ u32 wake = 0;
++ bool ret = false;
++
++ if (lss_number > PMU_MAX_LSS)
++ return ret;
++
++ if (lss_number < PMU_LSS_IN_FIRST_DWORD) {
++ wake = readl(&mid_pmu_cxt->pmu_reg->pm_wks[0]);
++ wake &= (1 << lss_number);
++ } else {
++ wake = readl(&mid_pmu_cxt->pmu_reg->pm_wks[1]);
++ wake &= (1 << (lss_number - PMU_LSS_IN_FIRST_DWORD));
++ }
++
++ if (wake)
++ ret = true;
++
++ return ret;
++}
++
++static void log_wakeup_source(int source)
++{
++ enum sys_state type = mid_pmu_cxt->pmu_current_state;
++
++ mid_pmu_cxt->num_wakes[source][type]++;
++
++ trace_printk("wake_from_lss%d\n",
++ source - mid_pmu_cxt->pmu1_max_devs);
++
++ if ((mid_pmu_cxt->pmu_current_state != SYS_STATE_S3)
++ || !mid_pmu_cxt->suspend_started)
++ return;
++
++ switch (source - mid_pmu_cxt->pmu1_max_devs) {
++ case PMU_USB_OTG_LSS_06:
++ pr_info("wakeup from USB.\n");
++ break;
++ case PMU_GPIO0_LSS_39:
++ pr_info("wakeup from GPIO.\n");
++ break;
++ case PMU_HSI_LSS_03:
++ pr_info("wakeup from HSI.\n");
++ break;
++ default:
++ pr_info("wakeup from LSS%02d.\n",
++ source - mid_pmu_cxt->pmu1_max_devs);
++ break;
++ }
++}
++
++/* return the last wake source id, and make statistics about wake sources */
++int pmu_get_wake_source(void)
++{
++ u32 wake0, wake1;
++ int i;
++ int source = INVALID_WAKE_SRC;
++
++ wake0 = readl(&mid_pmu_cxt->pmu_reg->pm_wks[0]);
++ wake1 = readl(&mid_pmu_cxt->pmu_reg->pm_wks[1]);
++
++ if (!wake0 && !wake1) {
++ log_wakeup_irq();
++ goto out;
++ }
++
++ while (wake0) {
++ i = fls(wake0) - 1;
++ source = i + mid_pmu_cxt->pmu1_max_devs;
++ log_wakeup_source(source);
++ wake0 &= ~(1<<i);
++ }
++
++ while (wake1) {
++ i = fls(wake1) - 1;
++ source = i + 32 + mid_pmu_cxt->pmu1_max_devs;
++ log_wakeup_source(source);
++ wake1 &= ~(1<<i);
++ }
++out:
++ return source;
++}
++
++static int wait_for_nc_pmcmd_complete(int verify_mask, int state_type
++ , int reg_type)
++{
++ int pwr_sts;
++ int count = 0;
++ u32 addr;
++
++ switch (reg_type) {
++ case APM_REG_TYPE:
++ addr = mid_pmu_cxt->apm_base + APM_STS;
++ break;
++ case OSPM_REG_TYPE:
++ addr = mid_pmu_cxt->ospm_base + OSPM_PM_SSS;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ while (true) {
++ pwr_sts = inl(addr);
++ if (state_type == OSPM_ISLAND_DOWN) {
++ if ((pwr_sts & verify_mask) == verify_mask)
++ break;
++ else
++ udelay(10);
++ } else if (state_type == OSPM_ISLAND_UP) {
++ if (pwr_sts == verify_mask)
++ break;
++ else
++ udelay(10);
++ }
++ count++;
++ if (WARN_ONCE(count > 500000, "Timed out waiting for P-Unit"))
++ return -EBUSY;
++ }
++ return 0;
++}
++
++int mdfld_clv_nc_set_power_state(int islands, int state_type,
++ int reg_type, int *change)
++{
++ u32 pwr_cnt = 0;
++ u32 pwr_mask = 0;
++ int i, lss, mask;
++ int ret = 0;
++
++ *change = 0;
++
++ switch (reg_type) {
++ case APM_REG_TYPE:
++ pwr_cnt = inl(mid_pmu_cxt->apm_base + APM_STS);
++ break;
++ case OSPM_REG_TYPE:
++ pwr_cnt = inl(mid_pmu_cxt->ospm_base + OSPM_PM_SSS);
++ break;
++ default:
++ ret = -EINVAL;
++ goto unlock;
++ }
++
++ pwr_mask = pwr_cnt;
++ for (i = 0; i < OSPM_MAX_POWER_ISLANDS; i++) {
++ lss = islands & (0x1 << i);
++ if (lss) {
++ mask = D0I3_MASK << (BITS_PER_LSS * i);
++ if (state_type == OSPM_ISLAND_DOWN)
++ pwr_mask |= mask;
++ else if (state_type == OSPM_ISLAND_UP)
++ pwr_mask &= ~mask;
++ }
++ }
++
++ if (pwr_mask != pwr_cnt) {
++ switch (reg_type) {
++ case APM_REG_TYPE:
++ outl(pwr_mask, mid_pmu_cxt->apm_base + APM_CMD);
++ break;
++ case OSPM_REG_TYPE:
++ outl(pwr_mask, mid_pmu_cxt->ospm_base + OSPM_PM_SSC);
++ break;
++ }
++
++ ret =
++ wait_for_nc_pmcmd_complete(pwr_mask, state_type, reg_type);
++ if (!ret)
++ *change = 1;
++ if (nc_report_power_state)
++ nc_report_power_state(pwr_mask, reg_type);
++ }
++
++unlock:
++ return ret;
++}
+diff --git a/arch/x86/platform/intel-mid/intel_soc_mrfld.c b/arch/x86/platform/intel-mid/intel_soc_mrfld.c
+new file mode 100644
+index 0000000..0683935
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/intel_soc_mrfld.c
+@@ -0,0 +1,446 @@
++/*
++ * intel_soc_mrfld.c - This driver provides utility api's for merrifield
++ * platform
++ * Copyright (c) 2012, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#include "intel_soc_pmu.h"
++
++u32 __iomem *residency[SYS_STATE_MAX];
++u32 __iomem *s0ix_counter[SYS_STATE_MAX];
++
++/* list of north complex devices */
++char *mrfl_nc_devices[] = {
++ "GFXSLC",
++ "GSDKCK",
++ "GRSCD",
++ "VED",
++ "VEC",
++ "DPA",
++ "DPB",
++ "DPC",
++ "VSP",
++ "ISP",
++ "MIO",
++ "HDMIO",
++ "GFXSLCLDO"
++};
++
++int mrfl_no_of_nc_devices =
++ sizeof(mrfl_nc_devices)/sizeof(mrfl_nc_devices[0]);
++
++static int mrfld_pmu_init(void)
++{
++ mid_pmu_cxt->s3_hint = MRFLD_S3_HINT;
++
++
++ /* Put all unused LSS in D0i3 */
++ mid_pmu_cxt->os_sss[0] = (SSMSK(D0I3_MASK, PMU_RESERVED_LSS_03) |
++ SSMSK(D0I3_MASK, PMU_HSI_LSS_05) |
++ SSMSK(D0I3_MASK, PMU_SECURITY_LSS_06) |
++ SSMSK(D0I3_MASK, PMU_RESERVED_LSS_07) |
++ SSMSK(D0I3_MASK, PMU_RESERVED_LSS_11) |
++ SSMSK(D0I3_MASK, PMU_RESERVED_LSS_12) |
++ SSMSK(D0I3_MASK, PMU_RESERVED_LSS_13) |
++ SSMSK(D0I3_MASK, PMU_RESERVED_LSS_14) |
++ SSMSK(D0I3_MASK, PMU_RESERVED_LSS_15));
++
++ /* Put LSS8 as unused on Tangier */
++ mid_pmu_cxt->os_sss[0] |= \
++ SSMSK(D0I3_MASK, PMU_USB_MPH_LSS_08);
++
++ mid_pmu_cxt->os_sss[1] = (SSMSK(D0I3_MASK, PMU_RESERVED_LSS_16-16)|
++ SSMSK(D0I3_MASK, PMU_SSP3_LSS_17-16)|
++ SSMSK(D0I3_MASK, PMU_SSP6_LSS_19-16)|
++ SSMSK(D0I3_MASK, PMU_USB_OTG_LSS_28-16)|
++ SSMSK(D0I3_MASK, PMU_RESERVED_LSS_29-16)|
++ SSMSK(D0I3_MASK, PMU_RESERVED_LSS_30-16));
++
++ /* Excpet for LSS 35 keep all in D0i3 */
++ mid_pmu_cxt->os_sss[2] = 0xFFFFFFFF;
++ mid_pmu_cxt->os_sss[3] = 0xFFFFFFFF;
++
++ mid_pmu_cxt->os_sss[2] &= ~SSMSK(D0I3_MASK, PMU_SSP4_LSS_35-32);
++
++ /* Map S0ix residency counters */
++ residency[SYS_STATE_S0I1] = ioremap_nocache(S0I1_RES_ADDR, sizeof(u64));
++ if (residency[SYS_STATE_S0I1] == NULL)
++ goto err1;
++ residency[SYS_STATE_LPMP3] = ioremap_nocache(LPMP3_RES_ADDR,
++ sizeof(u64));
++ if (residency[SYS_STATE_LPMP3] == NULL)
++ goto err2;
++ residency[SYS_STATE_S0I2] = ioremap_nocache(S0I2_RES_ADDR, sizeof(u64));
++ if (residency[SYS_STATE_S0I2] == NULL)
++ goto err3;
++ residency[SYS_STATE_S0I3] = ioremap_nocache(S0I3_RES_ADDR, sizeof(u64));
++ if (residency[SYS_STATE_S0I3] == NULL)
++ goto err4;
++
++ /* Map S0ix iteration counters */
++ s0ix_counter[SYS_STATE_S0I1] = ioremap_nocache(S0I1_COUNT_ADDR,
++ sizeof(u32));
++ if (s0ix_counter[SYS_STATE_S0I1] == NULL)
++ goto err5;
++ s0ix_counter[SYS_STATE_LPMP3] = ioremap_nocache(LPMP3_COUNT_ADDR,
++ sizeof(u32));
++ if (s0ix_counter[SYS_STATE_LPMP3] == NULL)
++ goto err6;
++ s0ix_counter[SYS_STATE_S0I2] = ioremap_nocache(S0I2_COUNT_ADDR,
++ sizeof(u32));
++ if (s0ix_counter[SYS_STATE_S0I2] == NULL)
++ goto err7;
++ s0ix_counter[SYS_STATE_S0I3] = ioremap_nocache(S0I3_COUNT_ADDR,
++ sizeof(u32));
++ if (s0ix_counter[SYS_STATE_S0I3] == NULL)
++ goto err8;
++ /* Keep PSH LSS's 00, 33, 34 in D0i0 if PM is disabled */
++ if (!enable_s0ix && !enable_s3) {
++ mid_pmu_cxt->os_sss[2] &=
++ ~SSMSK(D0I3_MASK, PMU_I2C8_LSS_33-32);
++ mid_pmu_cxt->os_sss[2] &=
++ ~SSMSK(D0I3_MASK, PMU_I2C9_LSS_34-32);
++ } else {
++ mid_pmu_cxt->os_sss[0] |= SSMSK(D0I3_MASK, PMU_PSH_LSS_00);
++ }
++
++ /* Disable the Interrupt Enable bit in PM ICS register */
++ pmu_clear_interrupt_enable();
++
++ return PMU_SUCCESS;
++
++err8:
++ iounmap(s0ix_counter[SYS_STATE_S0I3]);
++ s0ix_counter[SYS_STATE_S0I3] = NULL;
++err7:
++ iounmap(s0ix_counter[SYS_STATE_S0I2]);
++ s0ix_counter[SYS_STATE_S0I2] = NULL;
++err6:
++ iounmap(s0ix_counter[SYS_STATE_LPMP3]);
++ s0ix_counter[SYS_STATE_LPMP3] = NULL;
++err5:
++ iounmap(s0ix_counter[SYS_STATE_S0I1]);
++ s0ix_counter[SYS_STATE_S0I1] = NULL;
++err4:
++ iounmap(residency[SYS_STATE_S0I3]);
++ residency[SYS_STATE_S0I3] = NULL;
++err3:
++ iounmap(residency[SYS_STATE_S0I2]);
++ residency[SYS_STATE_S0I2] = NULL;
++err2:
++ iounmap(residency[SYS_STATE_LPMP3]);
++ residency[SYS_STATE_LPMP3] = NULL;
++err1:
++ iounmap(residency[SYS_STATE_S0I1]);
++ residency[SYS_STATE_S0I1] = NULL;
++
++ pr_err("Cannot map memory to read S0ix residency and count\n");
++ return PMU_FAILED;
++}
++
++/* This function checks north complex (NC) and
++ * south complex (SC) device status in MRFLD.
++ * returns TRUE if all NC and SC devices are in d0i3
++ * else FALSE.
++ */
++static bool mrfld_nc_sc_status_check(void)
++{
++ int i;
++ u32 val, nc_pwr_sts;
++ struct pmu_ss_states cur_pmsss;
++ bool nc_status, sc_status;
++
++ /* assuming nc and sc are good */
++ nc_status = true;
++ sc_status = true;
++
++ /* Check south complex device status */
++ pmu_read_sss(&cur_pmsss);
++
++ if (!(((cur_pmsss.pmu2_states[0] & S0IX_TARGET_SSS0_MASK) ==
++ S0IX_TARGET_SSS0) &&
++ ((cur_pmsss.pmu2_states[1] & S0IX_TARGET_SSS1_MASK) ==
++ S0IX_TARGET_SSS1) &&
++ ((cur_pmsss.pmu2_states[2] & S0IX_TARGET_SSS2_MASK) ==
++ S0IX_TARGET_SSS2) &&
++ ((cur_pmsss.pmu2_states[3] & S0IX_TARGET_SSS3_MASK) ==
++ (S0IX_TARGET_SSS3)))) {
++ sc_status = false;
++ pr_warn("SC device/devices not in d0i3!!\n");
++ for (i = 0; i < 4; i++)
++ pr_warn("pmu2_states[%d] = %08lX\n", i,
++ cur_pmsss.pmu2_states[i]);
++ }
++
++ if (sc_status) {
++ /* Check north complex status */
++ nc_pwr_sts =
++ intel_mid_msgbus_read32(PUNIT_PORT, NC_PM_SSS);
++ /* loop through the status to see if any of nc power island
++ * is not in D0i3 state
++ */
++ for (i = 0; i < mrfl_no_of_nc_devices; i++) {
++ val = nc_pwr_sts & 3;
++ if (val != 3) {
++ nc_status = false;
++ pr_warn("NC device (%s) is not in d0i3!!\n",
++ mrfl_nc_devices[i]);
++ pr_warn("nc_pm_sss = %08X\n", nc_pwr_sts);
++ break;
++ }
++ nc_pwr_sts >>= BITS_PER_LSS;
++ }
++ }
++
++ return nc_status & sc_status;
++}
++
++/* FIXME: Need to start the counter only if debug is
++ * needed. This will save SCU cycles if debug is
++ * disabled
++ */
++static int __init start_scu_s0ix_res_counters(void)
++{
++ int ret;
++
++ ret = intel_scu_ipc_simple_command(START_RES_COUNTER, 0);
++ if (ret) {
++ pr_err("IPC command to start res counter failed\n");
++ BUG();
++ return ret;
++ }
++ return 0;
++}
++late_initcall(start_scu_s0ix_res_counters);
++
++void platform_update_all_lss_states(struct pmu_ss_states *pmu_config,
++ int *PCIALLDEV_CFG)
++{
++ /* Overwrite the pmu_config values that we get */
++ pmu_config->pmu2_states[0] =
++ (SSMSK(D0I3_MASK, PMU_RESERVED_LSS_03) |
++ SSMSK(D0I3_MASK, PMU_HSI_LSS_05) |
++ SSMSK(D0I3_MASK, PMU_SECURITY_LSS_06) |
++ SSMSK(D0I3_MASK, PMU_RESERVED_LSS_07) |
++ SSMSK(D0I3_MASK, PMU_RESERVED_LSS_11) |
++ SSMSK(D0I3_MASK, PMU_RESERVED_LSS_12) |
++ SSMSK(D0I3_MASK, PMU_RESERVED_LSS_13) |
++ SSMSK(D0I3_MASK, PMU_RESERVED_LSS_14) |
++ SSMSK(D0I3_MASK, PMU_RESERVED_LSS_15));
++
++ /* Put LSS8 as unused on Tangier */
++ pmu_config->pmu2_states[0] |= \
++ SSMSK(D0I3_MASK, PMU_USB_MPH_LSS_08);
++
++ pmu_config->pmu2_states[1] =
++ (SSMSK(D0I3_MASK, PMU_RESERVED_LSS_16-16)|
++ SSMSK(D0I3_MASK, PMU_SSP3_LSS_17-16)|
++ SSMSK(D0I3_MASK, PMU_SSP6_LSS_19-16)|
++ SSMSK(D0I3_MASK, PMU_USB_OTG_LSS_28-16) |
++ SSMSK(D0I3_MASK, PMU_RESERVED_LSS_29-16)|
++ SSMSK(D0I3_MASK, PMU_RESERVED_LSS_30-16));
++
++ pmu_config->pmu2_states[0] &= ~IGNORE_SSS0;
++ pmu_config->pmu2_states[1] &= ~IGNORE_SSS1;
++ pmu_config->pmu2_states[2] = ~IGNORE_SSS2;
++ pmu_config->pmu2_states[3] = ~IGNORE_SSS3;
++
++ /* Excpet for LSS 35 keep all in D0i3 */
++ pmu_config->pmu2_states[2] &= ~SSMSK(D0I3_MASK, PMU_SSP4_LSS_35-32);
++
++ /* Keep PSH LSS's 00, 33, 34 in D0i0 if PM is disabled */
++ if (!enable_s0ix && !enable_s3) {
++ pmu_config->pmu2_states[2] &=
++ ~SSMSK(D0I3_MASK, PMU_I2C8_LSS_33-32);
++ pmu_config->pmu2_states[2] &=
++ ~SSMSK(D0I3_MASK, PMU_I2C9_LSS_34-32);
++ } else {
++ pmu_config->pmu2_states[0] |= SSMSK(D0I3_MASK, PMU_PSH_LSS_00);
++ }
++}
++
++/*
++ * In MDFLD and CLV this callback is used to issue
++ * PM_CMD which is not required in MRFLD
++ */
++static bool mrfld_pmu_enter(int s0ix_state)
++{
++ mid_pmu_cxt->s0ix_entered = s0ix_state;
++ if (s0ix_state == MID_S3_STATE) {
++ mid_pmu_cxt->pmu_current_state = SYS_STATE_S3;
++ pmu_set_interrupt_enable();
++ }
++
++ return true;
++}
++
++/**
++ * platform_set_pmu_ops - Set the global pmu method table.
++ * @ops: Pointer to ops structure.
++ */
++void platform_set_pmu_ops(void)
++{
++ pmu_ops = &mrfld_pmu_ops;
++}
++
++/*
++ * As of now since there is no sequential mapping between
++ * LSS abd WKS bits the following two calls are dummy
++ */
++
++bool mid_pmu_is_wake_source(u32 lss_number)
++{
++ return false;
++}
++
++/* return the last wake source id, and make statistics about wake sources */
++int pmu_get_wake_source(void)
++{
++ return INVALID_WAKE_SRC;
++}
++
++
++int set_extended_cstate_mode(const char *val, struct kernel_param *kp)
++{
++ return 0;
++}
++
++int get_extended_cstate_mode(char *buffer, struct kernel_param *kp)
++{
++ const char *default_string = "not supported";
++ strcpy(buffer, default_string);
++ return strlen(default_string);
++}
++
++static int wait_for_nc_pmcmd_complete(int verify_mask,
++ int status_mask, int state_type , int reg)
++{
++ int pwr_sts;
++ int count = 0;
++
++ while (true) {
++ pwr_sts = intel_mid_msgbus_read32(PUNIT_PORT, reg);
++ pwr_sts = pwr_sts >> SSS_SHIFT;
++ if (state_type == OSPM_ISLAND_DOWN ||
++ state_type == OSPM_ISLAND_SR) {
++ if ((pwr_sts & status_mask) ==
++ (verify_mask & status_mask))
++ break;
++ else
++ udelay(10);
++ } else if (state_type == OSPM_ISLAND_UP) {
++ if ((~pwr_sts & status_mask) ==
++ (~verify_mask & status_mask))
++ break;
++ else
++ udelay(10);
++ }
++
++ count++;
++ if (WARN_ONCE(count > 500000, "Timed out waiting for P-Unit"))
++ return -EBUSY;
++ }
++ return 0;
++}
++
++static int mrfld_nc_set_power_state(int islands, int state_type,
++ int reg, int *change)
++{
++ u32 pwr_sts = 0;
++ u32 pwr_mask = 0;
++ int i, lss, mask;
++ int ret = 0;
++ int status_mask = 0;
++
++ *change = 0;
++ pwr_sts = intel_mid_msgbus_read32(PUNIT_PORT, reg);
++ pwr_mask = pwr_sts;
++
++ for (i = 0; i < OSPM_MAX_POWER_ISLANDS; i++) {
++ lss = islands & (0x1 << i);
++ if (lss) {
++ mask = D0I3_MASK << (BITS_PER_LSS * i);
++ status_mask = status_mask | mask;
++ if (state_type == OSPM_ISLAND_DOWN)
++ pwr_mask |= mask;
++ else if (state_type == OSPM_ISLAND_UP)
++ pwr_mask &= ~mask;
++ /* Soft reset case */
++ else if (state_type == OSPM_ISLAND_SR) {
++ pwr_mask &= ~mask;
++ mask = SR_MASK << (BITS_PER_LSS * i);
++ pwr_mask |= mask;
++ }
++ }
++ }
++
++ if (pwr_mask != pwr_sts) {
++ intel_mid_msgbus_write32(PUNIT_PORT, reg, pwr_mask);
++ ret = wait_for_nc_pmcmd_complete(pwr_mask,
++ status_mask, state_type, reg);
++ if (!ret)
++ *change = 1;
++ if (nc_report_power_state)
++ nc_report_power_state(pwr_mask, reg);
++ }
++
++ return ret;
++}
++
++void s0ix_complete(void)
++{
++ if (mid_pmu_cxt->s0ix_entered) {
++ log_wakeup_irq();
++
++ if (mid_pmu_cxt->s0ix_entered == SYS_STATE_S3)
++ pmu_clear_interrupt_enable();
++
++ mid_pmu_cxt->pmu_current_state =
++ mid_pmu_cxt->s0ix_entered = 0;
++ }
++}
++
++bool could_do_s0ix(void)
++{
++ bool ret = false;
++ if (unlikely(!pmu_initialized))
++ goto ret;
++
++ /* dont do s0ix if suspend in progress */
++ if (unlikely(mid_pmu_cxt->suspend_started))
++ goto ret;
++
++ /* dont do s0ix if shutdown in progress */
++ if (unlikely(mid_pmu_cxt->shutdown_started))
++ goto ret;
++
++ if (nc_device_state())
++ goto ret;
++
++ ret = true;
++ret:
++ return ret;
++}
++EXPORT_SYMBOL(could_do_s0ix);
++
++struct platform_pmu_ops mrfld_pmu_ops = {
++ .init = mrfld_pmu_init,
++ .enter = mrfld_pmu_enter,
++ .set_s0ix_complete = s0ix_complete,
++ .nc_set_power_state = mrfld_nc_set_power_state,
++ .check_nc_sc_status = mrfld_nc_sc_status_check,
++};
+diff --git a/arch/x86/platform/intel-mid/intel_soc_mrfld.h b/arch/x86/platform/intel-mid/intel_soc_mrfld.h
+new file mode 100644
+index 0000000..dd14cba
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/intel_soc_mrfld.h
+@@ -0,0 +1,161 @@
++/*
++ * intel_soc_mrfld.h
++ * Copyright (c) 2012, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#ifdef CONFIG_REMOVEME_INTEL_ATOM_MRFLD_POWER
++
++#define PM_SUPPORT 0x21
++
++#define ISP_POS 7
++#define ISP_SUB_CLASS 0x80
++
++#define PUNIT_PORT 0x04
++#define SSS_SHIFT 24
++
++/* Soft reset mask */
++#define SR_MASK 0x2
++
++#define PMU1_MAX_DEVS 8
++#define PMU2_MAX_DEVS 55
++
++#define MRFLD_S3_HINT 0x64
++
++#define PUNIT_PORT 0x04
++#define NC_PM_SSS 0x3F
++
++/* SRAM locations to get S0ix residency */
++#define S0I1_RES_ADDR 0xFFFFF560
++#define LPMP3_RES_ADDR 0xFFFFF578
++#define S0I2_RES_ADDR 0xFFFFF568
++#define S0I3_RES_ADDR 0xFFFFF570
++
++/* SRAM locations to get S0ix count */
++#define S0I1_COUNT_ADDR 0xFFFFF588
++#define LPMP3_COUNT_ADDR 0xFFFFF594
++#define S0I2_COUNT_ADDR 0xFFFFF58C
++#define S0I3_COUNT_ADDR 0xFFFFF590
++
++/* IPC commands to start, stop and
++ * dump S0ix residency counters */
++#define START_RES_COUNTER 0x00EB
++#define STOP_RES_COUNTER 0x10EB
++#define DUMP_RES_COUNTER 0x20EB
++
++/* IPC commands to start/reset and
++ * dump S0ix count */
++#define START_S0IX_COUNT 0x00E1
++#define DUMP_S0IX_COUNT 0x10E1
++
++#define GFX_LSS_INDEX 1
++
++#define PMU_PSH_LSS_00 0
++#define PMU_SDIO0_LSS_01 1
++#define PMU_EMMC0_LSS_02 2
++#define PMU_RESERVED_LSS_03 3
++#define PMU_SDIO1_LSS_04 4
++#define PMU_HSI_LSS_05 5
++#define PMU_SECURITY_LSS_06 6
++#define PMU_RESERVED_LSS_07 7
++#define PMU_USB_MPH_LSS_08 8
++#define PMU_USB3_LSS_09 9
++#define PMU_AUDIO_LSS_10 10
++#define PMU_RESERVED_LSS_11 11
++#define PMU_RESERVED_LSS_12 12
++#define PMU_RESERVED_LSS_13 13
++#define PMU_RESERVED_LSS_14 14
++#define PMU_RESERVED_LSS_15 15
++#define PMU_RESERVED_LSS_16 16
++#define PMU_SSP3_LSS_17 17
++#define PMU_SSP5_LSS_18 18
++#define PMU_SSP6_LSS_19 19
++#define PMU_I2C1_LSS_20 20
++#define PMU_I2C2_LSS_21 21
++#define PMU_I2C3_LSS_22 22
++#define PMU_I2C4_LSS_23 23
++#define PMU_I2C5_LSS_24 24
++#define PMU_GP_DMA_LSS_25 25
++#define PMU_I2C6_LSS_26 26
++#define PMU_I2C7_LSS_27 27
++#define PMU_USB_OTG_LSS_28 28
++#define PMU_RESERVED_LSS_29 29
++#define PMU_RESERVED_LSS_30 30
++#define PMU_UART0_LSS_31 31
++#define PMU_UART1_LSS_31 31
++#define PMU_UART2_LSS_31 31
++
++#define PMU_I2C8_LSS_33 33
++#define PMU_I2C9_LSS_34 34
++#define PMU_SSP4_LSS_35 35
++#define PMU_PMW_LSS_36 36
++
++#define EMMC0_LSS PMU_EMMC0_LSS_02
++
++#define IGNORE_SSS0 0
++#define IGNORE_SSS1 0
++#define IGNORE_SSS2 0
++#define IGNORE_SSS3 0
++
++#define PMU_WAKE_GPIO0 (1 << 0)
++#define PMU_WAKE_GPIO1 (1 << 1)
++#define PMU_WAKE_GPIO2 (1 << 2)
++#define PMU_WAKE_GPIO3 (1 << 3)
++#define PMU_WAKE_GPIO4 (1 << 4)
++#define PMU_WAKE_GPIO5 (1 << 5)
++#define PMU_WAKE_TIMERS (1 << 6)
++#define PMU_WAKE_SECURITY (1 << 7)
++#define PMU_WAKE_AONT32K (1 << 8)
++#define PMU_WAKE_AONT (1 << 9)
++#define PMU_WAKE_SVID_ALERT (1 << 10)
++#define PMU_WAKE_AUDIO (1 << 11)
++#define PMU_WAKE_USB2 (1 << 12)
++#define PMU_WAKE_USB3 (1 << 13)
++#define PMU_WAKE_ILB (1 << 14)
++#define PMU_WAKE_TAP (1 << 15)
++#define PMU_WAKE_WATCHDOG (1 << 16)
++#define PMU_WAKE_HSIC (1 << 17)
++#define PMU_WAKE_PSH (1 << 18)
++#define PMU_WAKE_PSH_GPIO (1 << 19)
++#define PMU_WAKE_PSH_AONT (1 << 20)
++#define PMU_WAKE_PSH_HALT (1 << 21)
++#define PMU_GLBL_WAKE_MASK (1 << 31)
++
++/* Ignore AONT WAKES and ALL from WKC1 */
++#define IGNORE_S3_WKC0 (PMU_WAKE_AONT32K | PMU_WAKE_AONT)
++#define IGNORE_S3_WKC1 (~0)
++
++#define S0IX_TARGET_SSS0_MASK (0xFFF3FFFF)
++#define S0IX_TARGET_SSS1_MASK (0xFFFFFFFF)
++#define S0IX_TARGET_SSS2_MASK (0xFFFFFFFF)
++#define S0IX_TARGET_SSS3_MASK (0xFFFFFFFF)
++
++#define S0IX_TARGET_SSS0 (0xFFF3FFFF)
++#define S0IX_TARGET_SSS1 (0xFFFFFFFF)
++#define S0IX_TARGET_SSS2 (0xFFFFFF3F)
++#define S0IX_TARGET_SSS3 (0xFFFFFFFF)
++
++#define LPMP3_TARGET_SSS0_MASK (0xFFF3FFFF)
++#define LPMP3_TARGET_SSS0 (0xFFC3FFFF)
++
++extern char *mrfl_nc_devices[];
++extern int mrfl_no_of_nc_devices;
++extern int intel_scu_ipc_simple_command(int, int);
++extern void log_wakeup_irq(void);
++extern void s0ix_complete(void);
++extern bool could_do_s0ix(void);
++
++#endif
+diff --git a/arch/x86/platform/intel-mid/intel_soc_pm_debug.c b/arch/x86/platform/intel-mid/intel_soc_pm_debug.c
+new file mode 100644
+index 0000000..8ce4c81
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/intel_soc_pm_debug.c
+@@ -0,0 +1,2518 @@
++/*
++ * intel_soc_pm_debug.c - This driver provides debug utilities across
++ * multiple platforms
++ * Copyright (c) 2012, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++#include <linux/time.h>
++#include <asm/intel_mid_rpmsg.h>
++#include <linux/cpuidle.h>
++#include "intel_soc_pm_debug.h"
++#include <asm-generic/io-64-nonatomic-hi-lo.h>
++#include <asm/tsc.h>
++
++#ifdef CONFIG_PM_DEBUG
++#define MAX_CSTATES_POSSIBLE 32
++
++
++
++static struct latency_stat *lat_stat;
++
++static void latency_measure_enable_disable(bool enable_measure)
++{
++ int err;
++ u32 sub;
++
++ if (enable_measure == lat_stat->latency_measure)
++ return;
++
++ if (enable_measure)
++ sub = IPC_SUB_MEASURE_START_CLVP;
++ else
++ sub = IPC_SUB_MEASURE_STOP_CLVP;
++
++ err = rpmsg_send_generic_command(IPC_CMD_S0IX_LATENCY_CLVP,
++ sub, NULL, 0, NULL, 0);
++ if (unlikely(err)) {
++ pr_err("IPC to %s S0IX Latency Measurement failed!\n",
++ enable_measure ? "start" : "stop");
++ return;
++ }
++
++ if (enable_measure) {
++ memset(lat_stat->scu_latency, 0, sizeof(lat_stat->scu_latency));
++ memset(lat_stat->os_latency, 0, sizeof(lat_stat->os_latency));
++ memset(lat_stat->s3_parts_lat, 0,
++ sizeof(lat_stat->s3_parts_lat));
++ memset(lat_stat->count, 0, sizeof(lat_stat->count));
++ }
++
++ lat_stat->latency_measure = enable_measure;
++}
++
++static void print_simple_stat(struct seq_file *s, int divisor, int rem_div,
++ int count, struct simple_stat stat)
++{
++ unsigned long long min, avg, max;
++ unsigned long min_rem = 0, avg_rem = 0, max_rem = 0;
++
++ min = stat.min;
++ max = stat.max;
++ avg = stat.total;
++
++ if (count)
++ do_div(avg, count);
++
++ if (divisor > 1) {
++ min_rem = do_div(min, divisor);
++ max_rem = do_div(max, divisor);
++ avg_rem = do_div(avg, divisor);
++ }
++
++ if (rem_div > 1) {
++ min_rem /= rem_div;
++ max_rem /= rem_div;
++ avg_rem /= rem_div;
++ }
++
++ seq_printf(s, " %5llu.%03lu/%5llu.%03lu/%5llu.%03lu",
++ min, min_rem, avg, avg_rem, max, max_rem);
++}
++
++static int show_pmu_s0ix_lat(struct seq_file *s, void *unused)
++{
++ int i = 0;
++
++ char *states[] = {
++ "S0I1",
++ "LPMP3",
++ "S0I3",
++ "S3"
++ };
++
++ char *s3_parts_names[] = {
++ "PROC_FRZ",
++ "DEV_SUS",
++ "NB_CPU_OFF",
++ "NB_CPU_ON",
++ "DEV_RES",
++ "PROC_UNFRZ"
++ };
++
++ seq_printf(s, "%29s %35s\n", "SCU Latency", "OS Latency");
++ seq_printf(s, "%33s %35s\n", "min/avg/max(msec)", "min/avg/max(msec)");
++
++ for (i = SYS_STATE_S0I1; i <= SYS_STATE_S3; i++) {
++ seq_printf(s, "\n%s(%llu)", states[i - SYS_STATE_S0I1],
++ lat_stat->count[i]);
++
++ seq_printf(s, "\n%5s", "entry");
++ print_simple_stat(s, USEC_PER_MSEC, 1, lat_stat->count[i],
++ lat_stat->scu_latency[i].entry);
++ seq_printf(s, " ");
++ print_simple_stat(s, NSEC_PER_MSEC, NSEC_PER_USEC,
++ lat_stat->count[i], lat_stat->os_latency[i].entry);
++
++ seq_printf(s, "\n%5s", "exit");
++ print_simple_stat(s, USEC_PER_MSEC, 1, lat_stat->count[i],
++ lat_stat->scu_latency[i].exit);
++ seq_printf(s, " ");
++ print_simple_stat(s, NSEC_PER_MSEC, NSEC_PER_USEC,
++ lat_stat->count[i], lat_stat->os_latency[i].exit);
++
++ }
++
++ seq_printf(s, "\n\n");
++
++ if (!lat_stat->count[SYS_STATE_S3])
++ return 0;
++
++ seq_printf(s, "S3 Latency dissection:\n");
++ seq_printf(s, "%38s\n", "min/avg/max(msec)");
++
++ for (i = 0; i < MAX_S3_PARTS; i++) {
++ seq_printf(s, "%10s\t", s3_parts_names[i]);
++ print_simple_stat(s, NSEC_PER_MSEC, NSEC_PER_USEC,
++ lat_stat->count[SYS_STATE_S3],
++ lat_stat->s3_parts_lat[i]);
++ seq_printf(s, "\n");
++ }
++
++ return 0;
++}
++
++static int pmu_s0ix_lat_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, show_pmu_s0ix_lat, NULL);
++}
++
++static ssize_t pmu_s0ix_lat_write(struct file *file,
++ const char __user *userbuf, size_t count, loff_t *ppos)
++{
++ char buf[32];
++ int buf_size = min(count, sizeof(buf)-1);
++
++ if (copy_from_user(buf, userbuf, buf_size))
++ return -EFAULT;
++
++
++ buf[buf_size] = 0;
++
++ if (((strlen("start") + 1) == buf_size) &&
++ !strncmp(buf, "start", strlen("start"))) {
++ latency_measure_enable_disable(true);
++ } else if (((strlen("stop") + 1) == buf_size) &&
++ !strncmp(buf, "stop", strlen("stop"))) {
++ latency_measure_enable_disable(false);
++ }
++
++ return buf_size;
++}
++
++static const struct file_operations s0ix_latency_ops = {
++ .open = pmu_s0ix_lat_open,
++ .read = seq_read,
++ .write = pmu_s0ix_lat_write,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++static void update_simple_stat(struct simple_stat *simple_stat, int count)
++{
++ u64 duration = simple_stat->curr;
++
++ if (!count) {
++ simple_stat->min =
++ simple_stat->max =
++ simple_stat->total = duration;
++ } else {
++ if (duration < simple_stat->min)
++ simple_stat->min = duration;
++ else if (duration > simple_stat->max)
++ simple_stat->max = duration;
++ simple_stat->total += duration;
++ }
++}
++
++void s0ix_scu_latency_stat(int type)
++{
++ if (!lat_stat || !lat_stat->latency_measure)
++ return;
++
++ if (type < SYS_STATE_S0I1 || type > SYS_STATE_S3)
++ return;
++
++ lat_stat->scu_latency[type].entry.curr =
++ readl(lat_stat->scu_s0ix_lat_addr);
++ lat_stat->scu_latency[type].exit.curr =
++ readl(lat_stat->scu_s0ix_lat_addr + 1);
++
++ update_simple_stat(&lat_stat->scu_latency[type].entry,
++ lat_stat->count[type]);
++ update_simple_stat(&lat_stat->scu_latency[type].exit,
++ lat_stat->count[type]);
++}
++
++void s0ix_lat_stat_init(void)
++{
++ if (!platform_is(INTEL_ATOM_CLV))
++ return;
++
++ lat_stat = kzalloc(sizeof(struct latency_stat), GFP_KERNEL);
++ if (unlikely(!lat_stat)) {
++ pr_err("Failed to allocate memory for s0ix latency!\n");
++ goto out_err0;
++ }
++
++ lat_stat->scu_s0ix_lat_addr =
++ ioremap_nocache(S0IX_LAT_SRAM_ADDR_CLVP,
++ S0IX_LAT_SRAM_SIZE_CLVP);
++ if (unlikely(!lat_stat->scu_s0ix_lat_addr)) {
++ pr_err("Failed to map SCU_S0IX_LAT_ADDR!\n");
++ goto out_err1;
++ }
++
++ lat_stat->dentry = debugfs_create_file("s0ix_latency",
++ S_IFREG | S_IRUGO, NULL, NULL, &s0ix_latency_ops);
++ if (unlikely(!lat_stat->dentry)) {
++ pr_err("Failed to create debugfs for s0ix latency!\n");
++ goto out_err2;
++ }
++
++ return;
++
++out_err2:
++ iounmap(lat_stat->scu_s0ix_lat_addr);
++out_err1:
++ kfree(lat_stat);
++ lat_stat = NULL;
++out_err0:
++ pr_err("%s: Initialization failed\n", __func__);
++}
++
++void s0ix_lat_stat_finish(void)
++{
++ if (!platform_is(INTEL_ATOM_CLV))
++ return;
++
++ if (unlikely(!lat_stat))
++ return;
++
++ if (likely(lat_stat->scu_s0ix_lat_addr))
++ iounmap(lat_stat->scu_s0ix_lat_addr);
++
++ if (likely(lat_stat->dentry))
++ debugfs_remove(lat_stat->dentry);
++
++ kfree(lat_stat);
++ lat_stat = NULL;
++}
++
++void time_stamp_in_suspend_flow(int mark, bool start)
++{
++ if (!lat_stat || !lat_stat->latency_measure)
++ return;
++
++ if (start) {
++ lat_stat->s3_parts_lat[mark].curr = cpu_clock(0);
++ return;
++ }
++
++ lat_stat->s3_parts_lat[mark].curr = cpu_clock(0) -
++ lat_stat->s3_parts_lat[mark].curr;
++}
++
++static void collect_sleep_state_latency_stat(int sleep_state)
++{
++ int i;
++ if (sleep_state == SYS_STATE_S3)
++ for (i = 0; i < MAX_S3_PARTS; i++)
++ update_simple_stat(&lat_stat->s3_parts_lat[i],
++ lat_stat->count[sleep_state]);
++
++ update_simple_stat(&lat_stat->os_latency[sleep_state].entry,
++ lat_stat->count[sleep_state]);
++ update_simple_stat(&lat_stat->os_latency[sleep_state].exit,
++ lat_stat->count[sleep_state]);
++ lat_stat->count[sleep_state]++;
++}
++
++void time_stamp_for_sleep_state_latency(int sleep_state, bool start, bool entry)
++{
++ if (!lat_stat || !lat_stat->latency_measure)
++ return;
++
++ if (start) {
++ if (entry)
++ lat_stat->os_latency[sleep_state].entry.curr =
++ cpu_clock(0);
++ else
++ lat_stat->os_latency[sleep_state].exit.curr =
++ cpu_clock(0);
++ return;
++ }
++
++ if (entry)
++ lat_stat->os_latency[sleep_state].entry.curr = cpu_clock(0) -
++ lat_stat->os_latency[sleep_state].entry.curr;
++ else {
++ lat_stat->os_latency[sleep_state].exit.curr = cpu_clock(0) -
++ lat_stat->os_latency[sleep_state].exit.curr;
++ collect_sleep_state_latency_stat(sleep_state);
++ }
++}
++#else /* CONFIG_PM_DEBUG */
++void s0ix_scu_latency_stat(int type) {}
++void s0ix_lat_stat_init(void) {}
++void s0ix_lat_stat_finish(void) {}
++void time_stamp_for_sleep_state_latency(int sleep_state, bool start,
++ bool entry) {}
++void time_stamp_in_suspend_flow(int mark, bool start) {}
++inline unsigned int pmu_get_new_cstate
++ (unsigned int cstate, int *index) { return cstate; };
++#endif /* CONFIG_PM_DEBUG */
++
++static char *dstates[] = {"D0", "D0i1", "D0i2", "D0i3"};
++
++/* This can be used to report NC power transitions */
++void (*nc_report_power_state) (u32, int);
++
++#if defined(CONFIG_REMOVEME_INTEL_ATOM_MDFLD_POWER) \
++ || defined(CONFIG_REMOVEME_INTEL_ATOM_CLV_POWER)
++
++#define PMU_DEBUG_PRINT_STATS (1U << 0)
++static int debug_mask;
++module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
++
++#define DEBUG_PRINT(logging_type, s, debug_level_mask, args...) \
++ do { \
++ if (logging_type) \
++ seq_printf(s, args); \
++ else if (debug_mask & \
++ PMU_DEBUG_PRINT_##debug_level_mask) \
++ pr_info(args); \
++ } while (0)
++
++static struct island display_islands[] = {
++ {APM_REG_TYPE, APM_GRAPHICS_ISLAND, "GFX"},
++ {APM_REG_TYPE, APM_VIDEO_DEC_ISLAND, "Video Decoder"},
++ {APM_REG_TYPE, APM_VIDEO_ENC_ISLAND, "Video Encoder"},
++ {APM_REG_TYPE, APM_GL3_CACHE_ISLAND, "GL3 Cache"},
++ {OSPM_REG_TYPE, OSPM_DISPLAY_A_ISLAND, "Display A"},
++ {OSPM_REG_TYPE, OSPM_DISPLAY_B_ISLAND, "Display B"},
++ {OSPM_REG_TYPE, OSPM_DISPLAY_C_ISLAND, "Display C"},
++ {OSPM_REG_TYPE, OSPM_MIPI_ISLAND, "MIPI-DSI"}
++};
++
++static struct island camera_islands[] = {
++ {APM_REG_TYPE, APM_ISP_ISLAND, "ISP"},
++ {APM_REG_TYPE, APM_IPH_ISLAND, "Iunit PHY"}
++};
++
++static char *lss_device_status[4] = { "D0i0", "D0i1", "D0i2", "D0i3" };
++
++static int lsses_num =
++ sizeof(lsses)/sizeof(lsses[0]);
++
++#ifdef LOG_PMU_EVENTS
++static void pmu_log_timestamp(struct timespec *ts)
++{
++ if (timekeeping_suspended) {
++ ts->tv_sec = 0;
++ ts->tv_nsec = 0;
++ } else {
++ ktime_get_ts(ts);
++ }
++}
++
++void pmu_log_pmu_irq(int status)
++{
++ struct mid_pmu_pmu_irq_log *log =
++ &mid_pmu_cxt->pmu_irq_log[mid_pmu_cxt->pmu_irq_log_idx];
++
++ log->status = status;
++ pmu_log_timestamp(&log->ts);
++ mid_pmu_cxt->pmu_irq_log_idx =
++ (mid_pmu_cxt->pmu_irq_log_idx + 1) % LOG_SIZE;
++}
++
++static void pmu_dump_pmu_irq_log(void)
++{
++ struct mid_pmu_pmu_irq_log *log;
++ int i = mid_pmu_cxt->pmu_irq_log_idx, j;
++
++ printk(KERN_ERR"%d last pmu irqs:\n", LOG_SIZE);
++
++ for (j = 0; j < LOG_SIZE; j++) {
++ i ? i-- : (i = LOG_SIZE - 1);
++ log = &mid_pmu_cxt->pmu_irq_log[i];
++ printk(KERN_ERR"Timestamp: %lu.%09lu\n",
++ log->ts.tv_sec, log->ts.tv_nsec);
++ printk(KERN_ERR"Status = 0x%02x", log->status);
++ printk(KERN_ERR"\n");
++ }
++}
++
++void pmu_log_ipc_irq(void)
++{
++ struct mid_pmu_ipc_irq_log *log =
++ &mid_pmu_cxt->ipc_irq_log[mid_pmu_cxt->ipc_irq_log_idx];
++
++ pmu_log_timestamp(&log->ts);
++ mid_pmu_cxt->ipc_irq_log_idx =
++ (mid_pmu_cxt->ipc_irq_log_idx + 1) % LOG_SIZE;
++}
++
++static void pmu_dump_ipc_irq_log(void)
++{
++ struct mid_pmu_ipc_irq_log *log;
++ int i = mid_pmu_cxt->ipc_irq_log_idx, j;
++
++ printk(KERN_ERR"%d last ipc irqs:\n", LOG_SIZE);
++
++ for (j = 0; j < LOG_SIZE; j++) {
++ i ? i-- : (i = LOG_SIZE - 1);
++ log = &mid_pmu_cxt->ipc_irq_log[i];
++ printk(KERN_ERR"Timestamp: %lu.%09lu\n",
++ log->ts.tv_sec, log->ts.tv_nsec);
++ printk(KERN_ERR"\n");
++ }
++}
++
++void pmu_log_ipc(u32 command)
++{
++ struct mid_pmu_ipc_log *log =
++ &mid_pmu_cxt->ipc_log[mid_pmu_cxt->ipc_log_idx];
++
++ log->command = command;
++ pmu_log_timestamp(&log->ts);
++ mid_pmu_cxt->ipc_log_idx = (mid_pmu_cxt->ipc_log_idx + 1) % LOG_SIZE;
++}
++
++static void pmu_dump_ipc_log(void)
++{
++ struct mid_pmu_ipc_log *log;
++ int i = mid_pmu_cxt->ipc_log_idx, j;
++
++ printk(KERN_ERR"%d last ipc commands:\n", LOG_SIZE);
++
++ for (j = 0; j < LOG_SIZE; j++) {
++ i ? i-- : (i = LOG_SIZE - 1);
++ log = &mid_pmu_cxt->ipc_log[i];
++ printk(KERN_ERR"Timestamp: %lu.%09lu\n",
++ log->ts.tv_sec, log->ts.tv_nsec);
++ printk(KERN_ERR"Command: 0x%08x", log->command);
++ printk(KERN_ERR"\n");
++ }
++}
++
++void pmu_log_command(u32 command, struct pmu_ss_states *pm_ssc)
++{
++ struct mid_pmu_cmd_log *log =
++ &mid_pmu_cxt->cmd_log[mid_pmu_cxt->cmd_log_idx];
++
++ if (pm_ssc != NULL)
++ memcpy(&log->pm_ssc, pm_ssc, sizeof(struct pmu_ss_states));
++ else
++ memset(&log->pm_ssc, 0, sizeof(struct pmu_ss_states));
++ log->command = command;
++ pmu_log_timestamp(&log->ts);
++ mid_pmu_cxt->cmd_log_idx = (mid_pmu_cxt->cmd_log_idx + 1) % LOG_SIZE;
++}
++
++static void pmu_dump_command_log(void)
++{
++ struct mid_pmu_cmd_log *log;
++ int i = mid_pmu_cxt->cmd_log_idx, j, k;
++ u32 cmd_state;
++ printk(KERN_ERR"%d last pmu commands:\n", LOG_SIZE);
++
++ for (j = 0; j < LOG_SIZE; j++) {
++ i ? i-- : (i = LOG_SIZE - 1);
++ log = &mid_pmu_cxt->cmd_log[i];
++ cmd_state = log->command;
++ printk(KERN_ERR"Timestamp: %lu.%09lu\n",
++ log->ts.tv_sec, log->ts.tv_nsec);
++ switch (cmd_state) {
++ case INTERACTIVE_VALUE:
++ printk(KERN_ERR"PM_CMD = Interactive_CMD IOC bit not set.\n");
++ break;
++ case INTERACTIVE_IOC_VALUE:
++ printk(KERN_ERR"PM_CMD = Interactive_CMD IOC bit set.\n");
++ break;
++ case S0I1_VALUE:
++ printk(KERN_ERR"PM_CMD = S0i1_CMD\n");
++ break;
++ case S0I3_VALUE:
++ printk(KERN_ERR"PM_CMD = S0i3_CMD\n");
++ break;
++ case LPMP3_VALUE:
++ printk(KERN_ERR"PM_CMD = LPMP3_CMD\n");
++ break;
++ default:
++ printk(KERN_ERR "Invalid PM_CMD\n");
++ break;
++ }
++ for (k = 0; k < 4; k++)
++ printk(KERN_ERR"pmu2_states[%d]: 0x%08lx\n",
++ k, log->pm_ssc.pmu2_states[k]);
++ printk(KERN_ERR"\n");
++ }
++}
++
++void pmu_dump_logs(void)
++{
++ struct timespec ts;
++
++ pmu_log_timestamp(&ts);
++ printk(KERN_ERR"Dumping out pmu logs\n");
++ printk(KERN_ERR"Timestamp: %lu.%09lu\n\n", ts.tv_sec, ts.tv_nsec);
++ printk(KERN_ERR"---------------------------------------\n\n");
++ pmu_dump_command_log();
++ printk(KERN_ERR"---------------------------------------\n\n");
++ pmu_dump_pmu_irq_log();
++ printk(KERN_ERR"---------------------------------------\n\n");
++ pmu_dump_ipc_log();
++ printk(KERN_ERR"---------------------------------------\n\n");
++ pmu_dump_ipc_irq_log();
++}
++#else
++void pmu_log_pmu_irq(int status) {}
++void pmu_log_command(u32 command, struct pmu_ss_states *pm_ssc) {}
++void pmu_dump_logs(void) {}
++#endif /* LOG_PMU_EVENTS */
++
++void pmu_stat_start(enum sys_state type)
++{
++ mid_pmu_cxt->pmu_current_state = type;
++ mid_pmu_cxt->pmu_stats[type].last_try = cpu_clock(smp_processor_id());
++}
++
++void pmu_stat_end(void)
++{
++ enum sys_state type = mid_pmu_cxt->pmu_current_state;
++
++ if (type > SYS_STATE_S0I0 && type < SYS_STATE_MAX) {
++ mid_pmu_cxt->pmu_stats[type].last_entry =
++ mid_pmu_cxt->pmu_stats[type].last_try;
++
++ if (!mid_pmu_cxt->pmu_stats[type].count)
++ mid_pmu_cxt->pmu_stats[type].first_entry =
++ mid_pmu_cxt->pmu_stats[type].last_entry;
++
++ mid_pmu_cxt->pmu_stats[type].time +=
++ cpu_clock(smp_processor_id())
++ - mid_pmu_cxt->pmu_stats[type].last_entry;
++
++ mid_pmu_cxt->pmu_stats[type].count++;
++
++ s0ix_scu_latency_stat(type);
++ if (type >= SYS_STATE_S0I1 && type <= SYS_STATE_S0I3)
++ /* time stamp for end of s0ix exit */
++ time_stamp_for_sleep_state_latency(type, false, false);
++ }
++
++ mid_pmu_cxt->pmu_current_state = SYS_STATE_S0I0;
++}
++
++void pmu_stat_error(u8 err_type)
++{
++ enum sys_state type = mid_pmu_cxt->pmu_current_state;
++ u8 err_index;
++
++ if (type > SYS_STATE_S0I0 && type < SYS_STATE_MAX) {
++ switch (err_type) {
++ case SUBSYS_POW_ERR_INT:
++ trace_printk("S0ix_POW_ERR_INT\n");
++ err_index = 0;
++ break;
++ case S0ix_MISS_INT:
++ trace_printk("S0ix_MISS_INT\n");
++ err_index = 1;
++ break;
++ case NO_ACKC6_INT:
++ trace_printk("S0ix_NO_ACKC6_INT\n");
++ err_index = 2;
++ break;
++ default:
++ err_index = 3;
++ break;
++ }
++
++ if (err_index < 3)
++ mid_pmu_cxt->pmu_stats[type].err_count[err_index]++;
++ }
++}
++
++static void pmu_stat_seq_printf(struct seq_file *s, int type, char *typestr)
++{
++ unsigned long long t;
++ unsigned long nanosec_rem, remainder;
++ unsigned long time, init_2_now_time;
++
++ seq_printf(s, "%s\t%5llu\t%10llu\t%9llu\t%9llu\t", typestr,
++ mid_pmu_cxt->pmu_stats[type].count,
++ mid_pmu_cxt->pmu_stats[type].err_count[0],
++ mid_pmu_cxt->pmu_stats[type].err_count[1],
++ mid_pmu_cxt->pmu_stats[type].err_count[2]);
++
++ t = mid_pmu_cxt->pmu_stats[type].time;
++ nanosec_rem = do_div(t, NANO_SEC);
++
++ /* convert time in secs */
++ time = (unsigned long)t;
++
++ seq_printf(s, "%5lu.%06lu\t",
++ (unsigned long) t, nanosec_rem / 1000);
++
++ t = mid_pmu_cxt->pmu_stats[type].last_entry;
++ nanosec_rem = do_div(t, NANO_SEC);
++ seq_printf(s, "%5lu.%06lu\t",
++ (unsigned long) t, nanosec_rem / 1000);
++
++ t = mid_pmu_cxt->pmu_stats[type].first_entry;
++ nanosec_rem = do_div(t, NANO_SEC);
++ seq_printf(s, "%5lu.%06lu\t",
++ (unsigned long) t, nanosec_rem / 1000);
++
++ t = cpu_clock(raw_smp_processor_id());
++ t -= mid_pmu_cxt->pmu_init_time;
++ nanosec_rem = do_div(t, NANO_SEC);
++
++ init_2_now_time = (unsigned long) t;
++
++ /* for calculating percentage residency */
++ t = (u64) time;
++ t *= 100;
++
++ /* take care of divide by zero */
++ if (init_2_now_time) {
++ remainder = do_div(t, init_2_now_time);
++ time = (unsigned long) t;
++
++ /* for getting 3 digit precision after
++ * decimal dot */
++ t = (u64) remainder;
++ t *= 1000;
++ remainder = do_div(t, init_2_now_time);
++ } else
++ time = t = 0;
++
++ seq_printf(s, "%5lu.%03lu\n", time, (unsigned long) t);
++}
++
++static unsigned long pmu_dev_res_print(int index, unsigned long *precision,
++ unsigned long *sampled_time, bool dev_state)
++{
++ unsigned long long t, delta_time = 0;
++ unsigned long nanosec_rem, remainder;
++ unsigned long time, init_to_now_time;
++
++ t = cpu_clock(raw_smp_processor_id());
++
++ if (dev_state) {
++ /* print for d0ix */
++ if ((mid_pmu_cxt->pmu_dev_res[index].state != PCI_D0))
++ delta_time = t -
++ mid_pmu_cxt->pmu_dev_res[index].d0i3_entry;
++
++ delta_time += mid_pmu_cxt->pmu_dev_res[index].d0i3_acc;
++ } else {
++ /* print for d0i0 */
++ if ((mid_pmu_cxt->pmu_dev_res[index].state == PCI_D0))
++ delta_time = t -
++ mid_pmu_cxt->pmu_dev_res[index].d0i0_entry;
++
++ delta_time += mid_pmu_cxt->pmu_dev_res[index].d0i0_acc;
++ }
++
++ t -= mid_pmu_cxt->pmu_dev_res[index].start;
++ nanosec_rem = do_div(t, NANO_SEC);
++
++ init_to_now_time = (unsigned long) t;
++
++ t = delta_time;
++ nanosec_rem = do_div(t, NANO_SEC);
++
++ /* convert time in secs */
++ time = (unsigned long)t;
++ *sampled_time = time;
++
++ /* for calculating percentage residency */
++ t = (u64) time;
++ t *= 100;
++
++ /* take care of divide by zero */
++ if (init_to_now_time) {
++ remainder = do_div(t, init_to_now_time);
++ time = (unsigned long) t;
++
++ /* for getting 3 digit precision after
++ * decimal dot */
++ t = (u64) remainder;
++ t *= 1000;
++ remainder = do_div(t, init_to_now_time);
++ } else
++ time = t = 0;
++
++ *precision = (unsigned long)t;
++
++ return time;
++}
++
++static void nc_device_state_show(struct seq_file *s, struct pci_dev *pdev)
++{
++ int off, i, islands_num, state;
++ struct island *islands;
++
++ if (PCI_SLOT(pdev->devfn) == DEV_GFX &&
++ PCI_FUNC(pdev->devfn) == FUNC_GFX) {
++ off = mid_pmu_cxt->display_off;
++ islands_num = ISLANDS_GFX;
++ islands = &display_islands[0];
++ } else if (PCI_SLOT(pdev->devfn) == DEV_ISP &&
++ PCI_FUNC(pdev->devfn) == FUNC_ISP) {
++ off = mid_pmu_cxt->camera_off;
++ islands_num = ISLANDS_ISP;
++ islands = &camera_islands[0];
++ } else {
++ return;
++ }
++
++ seq_printf(s, "pci %04x %04X %s %20s: %41s %s\n",
++ pdev->vendor, pdev->device, dev_name(&pdev->dev),
++ dev_driver_string(&pdev->dev),
++ "", off ? "" : "blocking s0ix");
++ for (i = 0; i < islands_num; i++) {
++ state = pmu_nc_get_power_state(islands[i].index,
++ islands[i].type);
++ seq_printf(s, "%52s %15s %17s %s\n",
++ "|------->", islands[i].name, "",
++ (state >= 0) ? dstates[state & 3] : "ERR");
++ }
++}
++
++static int pmu_devices_state_show(struct seq_file *s, void *unused)
++{
++ struct pci_dev *pdev = NULL;
++ int index, i, pmu_num, ss_idx, ss_pos;
++ unsigned int base_class;
++ u32 target_mask, mask, val, needed;
++ struct pmu_ss_states cur_pmsss;
++
++ /* Acquire the scu_ready_sem */
++ down(&mid_pmu_cxt->scu_ready_sem);
++ _pmu2_wait_not_busy();
++ pmu_read_sss(&cur_pmsss);
++ up(&mid_pmu_cxt->scu_ready_sem);
++
++ seq_printf(s, "TARGET_CFG: ");
++ seq_printf(s, "SSS0:%08X ", S0IX_TARGET_SSS0_MASK);
++ seq_printf(s, "SSS1:%08X ", S0IX_TARGET_SSS1_MASK);
++ seq_printf(s, "SSS2:%08X ", S0IX_TARGET_SSS2_MASK);
++ seq_printf(s, "SSS3:%08X ", S0IX_TARGET_SSS3_MASK);
++
++ seq_printf(s, "\n");
++ seq_printf(s, "CONDITION FOR S0I3: ");
++ seq_printf(s, "SSS0:%08X ", S0IX_TARGET_SSS0);
++ seq_printf(s, "SSS1:%08X ", S0IX_TARGET_SSS1);
++ seq_printf(s, "SSS2:%08X ", S0IX_TARGET_SSS2);
++ seq_printf(s, "SSS3:%08X ", S0IX_TARGET_SSS3);
++
++ seq_printf(s, "\n");
++ seq_printf(s, "SSS: ");
++
++ for (i = 0; i < 4; i++)
++ seq_printf(s, "%08lX ", cur_pmsss.pmu2_states[i]);
++
++ if (!mid_pmu_cxt->display_off)
++ seq_printf(s, "display not suspended: blocking s0ix\n");
++ else if (!mid_pmu_cxt->camera_off)
++ seq_printf(s, "camera not suspended: blocking s0ix\n");
++ else if (mid_pmu_cxt->s0ix_possible & MID_S0IX_STATE)
++ seq_printf(s, "can enter s0i1 or s0i3\n");
++ else if (mid_pmu_cxt->s0ix_possible & MID_LPMP3_STATE)
++ seq_printf(s, "can enter lpmp3\n");
++ else
++ seq_printf(s, "blocking s0ix\n");
++
++ seq_printf(s, "cmd_error_int count: %d\n", mid_pmu_cxt->cmd_error_int);
++
++ seq_printf(s,
++ "\tcount\tsybsys_pow\ts0ix_miss\tno_ack_c6\ttime (secs)\tlast_entry");
++ seq_printf(s, "\tfirst_entry\tresidency(%%)\n");
++
++ pmu_stat_seq_printf(s, SYS_STATE_S0I1, "s0i1");
++ pmu_stat_seq_printf(s, SYS_STATE_S0I2, "lpmp3");
++ pmu_stat_seq_printf(s, SYS_STATE_S0I3, "s0i3");
++ pmu_stat_seq_printf(s, SYS_STATE_S3, "s3");
++
++ for_each_pci_dev(pdev) {
++ /* find the base class info */
++ base_class = pdev->class >> 16;
++
++ if (base_class == PCI_BASE_CLASS_BRIDGE)
++ continue;
++
++ if (pmu_pci_to_indexes(pdev, &index, &pmu_num, &ss_idx,
++ &ss_pos))
++ continue;
++
++ if (pmu_num == PMU_NUM_1) {
++ nc_device_state_show(s, pdev);
++ continue;
++ }
++
++ mask = (D0I3_MASK << (ss_pos * BITS_PER_LSS));
++ val = (cur_pmsss.pmu2_states[ss_idx] & mask) >>
++ (ss_pos * BITS_PER_LSS);
++ switch (ss_idx) {
++ case 0:
++ target_mask = S0IX_TARGET_SSS0_MASK;
++ break;
++ case 1:
++ target_mask = S0IX_TARGET_SSS1_MASK;
++ break;
++ case 2:
++ target_mask = S0IX_TARGET_SSS2_MASK;
++ break;
++ case 3:
++ target_mask = S0IX_TARGET_SSS3_MASK;
++ break;
++ default:
++ target_mask = 0;
++ break;
++ }
++ needed = ((target_mask & mask) != 0);
++
++ seq_printf(s, "pci %04x %04X %s %20s: lss:%02d reg:%d"
++ "mask:%08X wk:%02d:%02d:%02d:%03d %s %s\n",
++ pdev->vendor, pdev->device, dev_name(&pdev->dev),
++ dev_driver_string(&pdev->dev),
++ index - mid_pmu_cxt->pmu1_max_devs, ss_idx, mask,
++ mid_pmu_cxt->num_wakes[index][SYS_STATE_S0I1],
++ mid_pmu_cxt->num_wakes[index][SYS_STATE_S0I2],
++ mid_pmu_cxt->num_wakes[index][SYS_STATE_S0I3],
++ mid_pmu_cxt->num_wakes[index][SYS_STATE_S3],
++ dstates[val & 3],
++ (needed && !val) ? "blocking s0ix" : "");
++
++ }
++
++ return 0;
++}
++
++static int devices_state_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, pmu_devices_state_show, NULL);
++}
++
++static ssize_t devices_state_write(struct file *file,
++ const char __user *userbuf, size_t count, loff_t *ppos)
++{
++ char buf[32];
++ int buf_size = min(count, sizeof(buf)-1);
++
++ if (copy_from_user(buf, userbuf, buf_size))
++ return -EFAULT;
++
++
++ buf[buf_size] = 0;
++
++ if (((strlen("clear")+1) == buf_size) &&
++ !strncmp(buf, "clear", strlen("clear"))) {
++ down(&mid_pmu_cxt->scu_ready_sem);
++ memset(mid_pmu_cxt->pmu_stats, 0,
++ sizeof(mid_pmu_cxt->pmu_stats));
++ memset(mid_pmu_cxt->num_wakes, 0,
++ sizeof(mid_pmu_cxt->num_wakes));
++ mid_pmu_cxt->pmu_current_state = SYS_STATE_S0I0;
++ mid_pmu_cxt->pmu_init_time =
++ cpu_clock(raw_smp_processor_id());
++ clear_d0ix_stats();
++ up(&mid_pmu_cxt->scu_ready_sem);
++ }
++
++ return buf_size;
++}
++
++static const struct file_operations devices_state_operations = {
++ .open = devices_state_open,
++ .read = seq_read,
++ .write = devices_state_write,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++static int show_pmu_lss_status(struct seq_file *s, void *unused)
++{
++ int sss_reg_index;
++ int offset;
++ int lss;
++ unsigned long status;
++ unsigned long sub_status;
++ unsigned long lss_status[4];
++ struct lss_definition *entry;
++
++ down(&mid_pmu_cxt->scu_ready_sem);
++
++ lss_status[0] = readl(&mid_pmu_cxt->pmu_reg->pm_sss[0]);
++ lss_status[1] = readl(&mid_pmu_cxt->pmu_reg->pm_sss[1]);
++ lss_status[2] = readl(&mid_pmu_cxt->pmu_reg->pm_sss[2]);
++ lss_status[3] = readl(&mid_pmu_cxt->pmu_reg->pm_sss[3]);
++
++ up(&mid_pmu_cxt->scu_ready_sem);
++
++ lss = 0;
++ seq_printf(s, "%5s\t%12s %35s %5s %4s %4s %4s %4s\n",
++ "lss", "block", "subsystem", "state", "D0i0", "D0i1",
++ "D0i2", "D0i3");
++ seq_printf(s, "====================================================="
++ "=====================\n");
++ for (sss_reg_index = 0; sss_reg_index < 4; sss_reg_index++) {
++ status = lss_status[sss_reg_index];
++ for (offset = 0; offset < sizeof(unsigned long) * 8 / 2;
++ offset++) {
++ sub_status = status & 3;
++ if (lss >= lsses_num)
++ entry = &lsses[lsses_num - 1];
++ else
++ entry = &lsses[lss];
++ seq_printf(s, "%5s\t%12s %35s %4s %4d %4d %4d %4d\n",
++ entry->lss_name, entry->block,
++ entry->subsystem,
++ lss_device_status[sub_status],
++ get_d0ix_stat(lss, SS_STATE_D0I0),
++ get_d0ix_stat(lss, SS_STATE_D0I1),
++ get_d0ix_stat(lss, SS_STATE_D0I2),
++ get_d0ix_stat(lss, SS_STATE_D0I3));
++
++ status >>= 2;
++ lss++;
++ }
++ }
++
++ return 0;
++}
++
++static int pmu_sss_state_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, show_pmu_lss_status, NULL);
++}
++
++static const struct file_operations pmu_sss_state_operations = {
++ .open = pmu_sss_state_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++static int show_pmu_dev_stats(struct seq_file *s, void *unused)
++{
++ struct pci_dev *pdev = NULL;
++ unsigned long sampled_time, precision;
++ int index, pmu_num, ss_idx, ss_pos;
++ unsigned int base_class;
++
++ seq_printf(s, "%5s\t%20s\t%10s\t%10s\t%s\n",
++ "lss", "Name", "D0_res", "D0ix_res", "Sampled_Time");
++ seq_printf(s,
++ "==================================================================\n");
++
++ for_each_pci_dev(pdev) {
++ /* find the base class info */
++ base_class = pdev->class >> 16;
++
++ if (base_class == PCI_BASE_CLASS_BRIDGE)
++ continue;
++
++ if (pmu_pci_to_indexes(pdev, &index, &pmu_num, &ss_idx,
++ &ss_pos))
++ continue;
++
++ if (pmu_num == PMU_NUM_1) {
++ seq_printf(s,
++ "%5s%20s\t%5lu.%03lu%%\t%5lu.%03lu%%\t%lu\n",
++ "NC", dev_driver_string(&pdev->dev),
++ pmu_dev_res_print(index, &precision,
++ &sampled_time, false),
++ precision,
++ pmu_dev_res_print(index, &precision,
++ &sampled_time, true),
++ precision, sampled_time);
++ continue;
++ }
++
++ /* Print for South Complex devices */
++ seq_printf(s, "%5d\t%20s\t%5lu.%03lu%%\t%5lu.%03lu%%\t%lu\n",
++ index - mid_pmu_cxt->pmu1_max_devs,
++ dev_driver_string(&pdev->dev),
++ pmu_dev_res_print(index, &precision, &sampled_time, false),
++ precision,
++ pmu_dev_res_print(index, &precision, &sampled_time, true),
++ precision, sampled_time);
++ }
++ return 0;
++}
++
++static int pmu_dev_stat_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, show_pmu_dev_stats, NULL);
++}
++
++static const struct file_operations pmu_dev_stat_operations = {
++ .open = pmu_dev_stat_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++#ifdef CONFIG_PM_DEBUG
++static int pmu_stats_interval = PMU_LOG_INTERVAL_SECS;
++module_param_named(pmu_stats_interval, pmu_stats_interval,
++ int, S_IRUGO | S_IWUSR | S_IWGRP);
++
++void pmu_s0ix_demotion_stat(int req_state, int grant_state)
++{
++ struct pmu_ss_states cur_pmsss;
++ int i, req_sys_state, offset;
++ unsigned long status, sub_status;
++ unsigned long s0ix_target_sss_mask[4] = {
++ S0IX_TARGET_SSS0_MASK,
++ S0IX_TARGET_SSS1_MASK,
++ S0IX_TARGET_SSS2_MASK,
++ S0IX_TARGET_SSS3_MASK};
++
++ unsigned long s0ix_target_sss[4] = {
++ S0IX_TARGET_SSS0,
++ S0IX_TARGET_SSS1,
++ S0IX_TARGET_SSS2,
++ S0IX_TARGET_SSS3};
++
++ unsigned long lpmp3_target_sss_mask[4] = {
++ LPMP3_TARGET_SSS0_MASK,
++ LPMP3_TARGET_SSS1_MASK,
++ LPMP3_TARGET_SSS2_MASK,
++ LPMP3_TARGET_SSS3_MASK};
++
++ unsigned long lpmp3_target_sss[4] = {
++ LPMP3_TARGET_SSS0,
++ LPMP3_TARGET_SSS1,
++ LPMP3_TARGET_SSS2,
++ LPMP3_TARGET_SSS3};
++
++ req_sys_state = mid_state_to_sys_state(req_state);
++ if ((grant_state >= C4_STATE_IDX) && (grant_state <= S0I3_STATE_IDX))
++ mid_pmu_cxt->pmu_stats
++ [req_sys_state].demote_count
++ [grant_state-C4_STATE_IDX]++;
++
++ if (down_trylock(&mid_pmu_cxt->scu_ready_sem))
++ return;
++
++ pmu_read_sss(&cur_pmsss);
++ up(&mid_pmu_cxt->scu_ready_sem);
++
++ if (!mid_pmu_cxt->camera_off)
++ mid_pmu_cxt->pmu_stats[req_sys_state].camera_blocker_count++;
++
++ if (!mid_pmu_cxt->display_off)
++ mid_pmu_cxt->pmu_stats[req_sys_state].display_blocker_count++;
++
++ if (!mid_pmu_cxt->s0ix_possible) {
++ for (i = 0; i < 4; i++) {
++ unsigned int lss_per_register;
++ if (req_state == MID_LPMP3_STATE)
++ status = lpmp3_target_sss[i] ^
++ (cur_pmsss.pmu2_states[i] &
++ lpmp3_target_sss_mask[i]);
++ else
++ status = s0ix_target_sss[i] ^
++ (cur_pmsss.pmu2_states[i] &
++ s0ix_target_sss_mask[i]);
++ if (!status)
++ continue;
++
++ lss_per_register =
++ (sizeof(unsigned long)*8)/BITS_PER_LSS;
++
++ for (offset = 0; offset < lss_per_register; offset++) {
++ sub_status = status & SS_IDX_MASK;
++ if (sub_status) {
++ mid_pmu_cxt->pmu_stats[req_sys_state].
++ blocker_count
++ [offset + lss_per_register*i]++;
++ }
++
++ status >>= BITS_PER_LSS;
++ }
++ }
++ }
++}
++EXPORT_SYMBOL(pmu_s0ix_demotion_stat);
++
++static void pmu_log_s0ix_status(int type, char *typestr,
++ struct seq_file *s, bool logging_type)
++{
++ unsigned long long t;
++ unsigned long time, remainder, init_2_now_time;
++
++ t = mid_pmu_cxt->pmu_stats[type].time;
++ remainder = do_div(t, NANO_SEC);
++
++ /* convert time in secs */
++ time = (unsigned long)t;
++
++ t = cpu_clock(0);
++ t -= mid_pmu_cxt->pmu_init_time;
++ remainder = do_div(t, NANO_SEC);
++
++ init_2_now_time = (unsigned long) t;
++
++ /* for calculating percentage residency */
++ t = (u64) time;
++ t *= 100;
++
++ /* take care of divide by zero */
++ if (init_2_now_time) {
++ remainder = do_div(t, init_2_now_time);
++ time = (unsigned long) t;
++
++ /* for getting 3 digit precision after
++ * decimal dot */
++ t = (u64) remainder;
++ t *= 1000;
++ remainder = do_div(t, init_2_now_time);
++ } else
++ time = t = 0;
++ DEBUG_PRINT(logging_type, s, STATS,
++ "%s\t%5llu\t%9llu\t%9llu\t%5lu.%03lu\n"
++ , typestr, mid_pmu_cxt->pmu_stats[type].count,
++ mid_pmu_cxt->pmu_stats[type].err_count[1],
++ mid_pmu_cxt->pmu_stats[type].err_count[2],
++ time, (unsigned long) t);
++}
++
++static void pmu_log_s0ix_demotion(int type, char *typestr,
++ struct seq_file *s, bool logging_type)
++{
++ DEBUG_PRINT(logging_type, s, STATS, "%s:\t%6d\t%6d\t%6d\t%6d\t%6d\n",
++ typestr,
++ mid_pmu_cxt->pmu_stats[type].demote_count[0],
++ mid_pmu_cxt->pmu_stats[type].demote_count[1],
++ mid_pmu_cxt->pmu_stats[type].demote_count[2],
++ mid_pmu_cxt->pmu_stats[type].demote_count[3],
++ mid_pmu_cxt->pmu_stats[type].demote_count[4]);
++}
++
++static void pmu_log_s0ix_lss_blocked(int type, char *typestr,
++ struct seq_file *s, bool logging_type)
++{
++ int i, block_count;
++
++ DEBUG_PRINT(logging_type, s, STATS, "%s: Block Count\n", typestr);
++
++ block_count = mid_pmu_cxt->pmu_stats[type].display_blocker_count;
++
++ if (block_count)
++ DEBUG_PRINT(logging_type, s, STATS,
++ "\tDisplay blocked: %d times\n", block_count);
++
++ block_count = mid_pmu_cxt->pmu_stats[type].camera_blocker_count;
++
++ if (block_count)
++ DEBUG_PRINT(logging_type, s, STATS,
++ "\tCamera blocked: %d times\n", block_count);
++
++ DEBUG_PRINT(logging_type, s, STATS, "\tLSS\t #blocked\n");
++
++ for (i = 0; i < MAX_LSS_POSSIBLE; i++) {
++ block_count = mid_pmu_cxt->pmu_stats[type].blocker_count[i];
++ if (block_count)
++ DEBUG_PRINT(logging_type, s, STATS, "\t%02d\t %6d\n", i,
++ block_count);
++ }
++ DEBUG_PRINT(logging_type, s, STATS, "\n");
++}
++
++static void pmu_stats_logger(bool logging_type, struct seq_file *s)
++{
++
++ if (!logging_type)
++ DEBUG_PRINT(logging_type, s, STATS,
++ "\n----MID_PMU_STATS_LOG_BEGIN----\n");
++
++ DEBUG_PRINT(logging_type, s, STATS,
++ "\tcount\ts0ix_miss\tno_ack_c6\tresidency(%%)\n");
++ pmu_log_s0ix_status(SYS_STATE_S0I1, "s0i1", s, logging_type);
++ pmu_log_s0ix_status(SYS_STATE_S0I2, "lpmp3", s, logging_type);
++ pmu_log_s0ix_status(SYS_STATE_S0I3, "s0i3", s, logging_type);
++ pmu_log_s0ix_status(SYS_STATE_S3, "s3", s, logging_type);
++
++ DEBUG_PRINT(logging_type, s, STATS, "\nFrom:\tTo\n");
++ DEBUG_PRINT(logging_type, s, STATS,
++ "\t C4\t C6\t S0i1\t Lpmp3\t S0i3\n");
++
++ /* storing C6 demotion info in S0I0 */
++ pmu_log_s0ix_demotion(SYS_STATE_S0I0, " C6", s, logging_type);
++
++ pmu_log_s0ix_demotion(SYS_STATE_S0I1, "s0i1", s, logging_type);
++ pmu_log_s0ix_demotion(SYS_STATE_S0I2, "lpmp3", s, logging_type);
++ pmu_log_s0ix_demotion(SYS_STATE_S0I3, "s0i3", s, logging_type);
++
++ DEBUG_PRINT(logging_type, s, STATS, "\n");
++ pmu_log_s0ix_lss_blocked(SYS_STATE_S0I1, "s0i1", s, logging_type);
++ pmu_log_s0ix_lss_blocked(SYS_STATE_S0I2, "lpmp3", s, logging_type);
++ pmu_log_s0ix_lss_blocked(SYS_STATE_S0I3, "s0i3", s, logging_type);
++
++ if (!logging_type)
++ DEBUG_PRINT(logging_type, s, STATS,
++ "\n----MID_PMU_STATS_LOG_END----\n");
++}
++
++static void pmu_log_stat(struct work_struct *work)
++{
++
++ pmu_stats_logger(false, NULL);
++
++ schedule_delayed_work(&mid_pmu_cxt->log_work,
++ msecs_to_jiffies(pmu_stats_interval*1000));
++}
++
++static int show_pmu_stats_log(struct seq_file *s, void *unused)
++{
++ pmu_stats_logger(true, s);
++ return 0;
++}
++
++static int pmu_stats_log_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, show_pmu_stats_log, NULL);
++}
++
++static const struct file_operations pmu_stats_log_operations = {
++ .open = pmu_stats_log_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++#else
++void pmu_s0ix_demotion_stat(int req_state, int grant_state) {}
++EXPORT_SYMBOL(pmu_s0ix_demotion_stat);
++#endif
++
++void pmu_stats_init(void)
++{
++ struct dentry *fentry;
++
++ /* /sys/kernel/debug/mid_pmu_states */
++ (void) debugfs_create_file("mid_pmu_states", S_IFREG | S_IRUGO,
++ NULL, NULL, &devices_state_operations);
++
++ /* /sys/kernel/debug/pmu_sss_states */
++ (void) debugfs_create_file("pmu_sss_states", S_IFREG | S_IRUGO,
++ NULL, NULL, &pmu_sss_state_operations);
++
++ /* /sys/kernel/debug/pmu_dev_stats */
++ (void) debugfs_create_file("pmu_dev_stats", S_IFREG | S_IRUGO,
++ NULL, NULL, &pmu_dev_stat_operations);
++
++ s0ix_lat_stat_init();
++
++#ifdef CONFIG_PM_DEBUG
++ /* dynamic debug tracing in every 5 mins */
++ INIT_DEFERRABLE_WORK(&mid_pmu_cxt->log_work, pmu_log_stat);
++ schedule_delayed_work(&mid_pmu_cxt->log_work,
++ msecs_to_jiffies(pmu_stats_interval*1000));
++
++ debug_mask = PMU_DEBUG_PRINT_STATS;
++
++ /* /sys/kernel/debug/pmu_stats_log */
++ fentry = debugfs_create_file("pmu_stats_log", S_IFREG | S_IRUGO,
++ NULL, NULL, &pmu_stats_log_operations);
++ if (fentry == NULL)
++ printk(KERN_ERR "Failed to create pmu_stats_log debugfs\n");
++#endif
++}
++
++void pmu_s3_stats_update(int enter)
++{
++
++}
++
++void pmu_stats_finish(void)
++{
++#ifdef CONFIG_PM_DEBUG
++ cancel_delayed_work_sync(&mid_pmu_cxt->log_work);
++#endif
++ s0ix_lat_stat_finish();
++}
++
++#endif /*if CONFIG_X86_MDFLD_POWER || CONFIG_X86_CLV_POWER*/
++
++#ifdef CONFIG_REMOVEME_INTEL_ATOM_MRFLD_POWER
++
++static u32 prev_s0ix_cnt[SYS_STATE_MAX];
++static unsigned long long prev_s0ix_res[SYS_STATE_MAX];
++static unsigned long long cur_s0ix_res[SYS_STATE_MAX];
++static unsigned long long cur_s0ix_cnt[SYS_STATE_MAX];
++static u32 S3_count;
++static unsigned long long S3_res;
++
++static void pmu_stat_seq_printf(struct seq_file *s, int type, char *typestr,
++ long long uptime)
++{
++ unsigned long long t;
++ u32 scu_val = 0, time = 0;
++ u32 remainder;
++ unsigned long init_2_now_time;
++ unsigned long long tsc_freq = 1330000;
++
++ /* If tsc calibration fails use the default as 1330Mhz */
++ if (tsc_khz)
++ tsc_freq = tsc_khz;
++
++ /* Print S0ix residency counter */
++ if (type == SYS_STATE_S0I0) {
++ for (t = SYS_STATE_S0I1; t <= SYS_STATE_S3; t++)
++ time += cur_s0ix_res[t];
++ } else if (type < SYS_STATE_S3) {
++ t = readq(residency[type]);
++ if (t < prev_s0ix_res[type])
++ t += (((unsigned long long)~0) - prev_s0ix_res[type]);
++ else
++ t -= prev_s0ix_res[type];
++
++ if (type == SYS_STATE_S0I3)
++ t -= prev_s0ix_res[SYS_STATE_S3];
++ } else
++ t = prev_s0ix_res[SYS_STATE_S3];
++
++ if (type == SYS_STATE_S0I0) {
++ /* uptime(nanoS) - sum_res(miliSec) */
++ t = uptime;
++ do_div(t, MICRO_SEC);
++ time = t - time;
++ } else {
++ /* s0ix residency counters are in TSC cycle count domain
++ * convert this to milli second time domain
++ */
++ remainder = do_div(t, tsc_freq);
++
++ /* store time in millisecs */
++ time = (unsigned int)t;
++ }
++ cur_s0ix_res[type] = (unsigned int)time;
++
++ seq_printf(s, "%s\t%5lu.%03lu\t", typestr,
++ (unsigned long)(time/1000), (unsigned long)(time%1000));
++
++ t = uptime;
++ do_div(t, MICRO_SEC); /* time in milli secs */
++
++ /* Note: with millisecs accuracy we get more
++ * precise residency percentages, but we have
++ * to trade off with the max number of days
++ * that we can run without clearing counters,
++ * with 32bit counter this value is ~50days.
++ */
++ init_2_now_time = (unsigned long) t;
++
++ /* for calculating percentage residency */
++ t = (u64)(time);
++ t *= 100;
++
++ /* take care of divide by zero */
++ if (init_2_now_time) {
++ remainder = do_div(t, init_2_now_time);
++ time = (unsigned long) t;
++
++ /* for getting 3 digit precision after
++ * decimal dot */
++ t = (u64) remainder;
++ t *= 1000;
++ remainder = do_div(t, init_2_now_time);
++ } else
++ time = t = 0;
++
++ seq_printf(s, "%5lu.%03lu\t", (unsigned long) time, (unsigned long) t);
++
++ /* Print S0ix counters */
++ if (type == SYS_STATE_S0I0) {
++ for (t = SYS_STATE_S0I1; t <= SYS_STATE_S3; t++)
++ scu_val += cur_s0ix_cnt[t];
++ if (scu_val == 0) /* S0I0 residency 100% */
++ scu_val = 1;
++ } else if (type < SYS_STATE_S3) {
++ scu_val = readl(s0ix_counter[type]);
++ if (scu_val < prev_s0ix_cnt[type])
++ scu_val += (((u32)~0) - prev_s0ix_cnt[type]);
++ else
++ scu_val -= prev_s0ix_cnt[type];
++
++ if (type == SYS_STATE_S0I3)
++ scu_val -= prev_s0ix_cnt[SYS_STATE_S3];
++ } else
++ scu_val = prev_s0ix_cnt[SYS_STATE_S3];
++
++ if (type != SYS_STATE_S0I0)
++ cur_s0ix_cnt[type] = scu_val;
++
++ seq_printf(s, "%5lu\t", (unsigned long) scu_val);
++
++ remainder = 0;
++ t = cur_s0ix_res[type];
++ if (scu_val) { /* s0ix_time in millisecs */
++ do_div(t, scu_val);
++ remainder = do_div(t, 1000);
++ }
++ seq_printf(s, "%5lu.%03lu\n", (unsigned long) t,
++ (unsigned long) remainder);
++}
++
++static int pmu_devices_state_show(struct seq_file *s, void *unused)
++{
++ struct pci_dev *pdev = NULL;
++ int index, i, pmu_num, ss_idx, ss_pos;
++ unsigned int base_class;
++ u32 mask, val, nc_pwr_sts;
++ struct pmu_ss_states cur_pmsss;
++ long long uptime;
++ int ret;
++
++ if (!pmu_initialized)
++ return 0;
++
++ /* Acquire the scu_ready_sem */
++ down(&mid_pmu_cxt->scu_ready_sem);
++ _pmu2_wait_not_busy();
++ pmu_read_sss(&cur_pmsss);
++ up(&mid_pmu_cxt->scu_ready_sem);
++
++ seq_printf(s, "SSS: ");
++
++ for (i = 0; i < 4; i++)
++ seq_printf(s, "%08lX ", cur_pmsss.pmu2_states[i]);
++
++ seq_printf(s, "cmd_error_int count: %d\n", mid_pmu_cxt->cmd_error_int);
++
++ seq_printf(s, "\ttime(secs)\tresidency(%%)\tcount\tAvg.Res(Sec)\n");
++
++ down(&mid_pmu_cxt->scu_ready_sem);
++ /* Dump S0ix residency counters */
++ ret = intel_scu_ipc_simple_command(DUMP_RES_COUNTER, 0);
++ if (ret)
++ seq_printf(s, "IPC command to DUMP S0ix residency failed\n");
++
++ /* Dump number of interations of S0ix */
++ ret = intel_scu_ipc_simple_command(DUMP_S0IX_COUNT, 0);
++ if (ret)
++ seq_printf(s, "IPC command to DUMP S0ix count failed\n");
++ up(&mid_pmu_cxt->scu_ready_sem);
++
++ uptime = cpu_clock(0);
++ uptime -= mid_pmu_cxt->pmu_init_time;
++ pmu_stat_seq_printf(s, SYS_STATE_S0I1, "s0i1", uptime);
++ pmu_stat_seq_printf(s, SYS_STATE_LPMP3, "lpmp3", uptime);
++ pmu_stat_seq_printf(s, SYS_STATE_S0I2, "s0i2", uptime);
++ pmu_stat_seq_printf(s, SYS_STATE_S0I3, "s0i3", uptime);
++ pmu_stat_seq_printf(s, SYS_STATE_S3, "s3", uptime);
++ pmu_stat_seq_printf(s, SYS_STATE_S0I0, "s0", uptime);
++
++ val = do_div(uptime, NANO_SEC);
++ seq_printf(s, "\n\nTotal time: %5lu.%03lu Sec\n", (unsigned long)uptime,
++ (unsigned long) val/1000000);
++
++ seq_printf(s, "\nNORTH COMPLEX DEVICES :\n\n");
++
++ nc_pwr_sts = intel_mid_msgbus_read32(PUNIT_PORT, NC_PM_SSS);
++ for (i = 0; i < mrfl_no_of_nc_devices; i++) {
++ val = nc_pwr_sts & 3;
++ nc_pwr_sts >>= BITS_PER_LSS;
++ seq_printf(s, "%9s : %s\n", mrfl_nc_devices[i], dstates[val]);
++ }
++
++ seq_printf(s, "\nSOUTH COMPLEX DEVICES :\n\n");
++
++ for_each_pci_dev(pdev) {
++ /* find the base class info */
++ base_class = pdev->class >> 16;
++
++ if (base_class == PCI_BASE_CLASS_BRIDGE)
++ continue;
++
++ if (pmu_pci_to_indexes(pdev, &index, &pmu_num, &ss_idx,
++ &ss_pos))
++ continue;
++
++ if (pmu_num == PMU_NUM_1)
++ continue;
++
++ mask = (D0I3_MASK << (ss_pos * BITS_PER_LSS));
++ val = (cur_pmsss.pmu2_states[ss_idx] & mask) >>
++ (ss_pos * BITS_PER_LSS);
++
++ seq_printf(s, "pci %04x %04X %s %20.20s: lss:%02d reg:%d ",
++ pdev->vendor, pdev->device, dev_name(&pdev->dev),
++ dev_driver_string(&pdev->dev),
++ index - mid_pmu_cxt->pmu1_max_devs, ss_idx);
++ seq_printf(s, "mask:%08X %s\n", mask, dstates[val & 3]);
++ }
++
++ return 0;
++}
++
++static int devices_state_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, pmu_devices_state_show, NULL);
++}
++
++static ssize_t devices_state_write(struct file *file,
++ const char __user *userbuf, size_t count, loff_t *ppos)
++{
++ char buf[32];
++ int ret;
++ int buf_size = min(count, sizeof(buf)-1);
++
++ if (copy_from_user(buf, userbuf, buf_size))
++ return -EFAULT;
++ buf[buf_size] = 0;
++
++ if (((strlen("clear")+1) == buf_size) &&
++ !strncmp(buf, "clear", strlen("clear"))) {
++ down(&mid_pmu_cxt->scu_ready_sem);
++
++ /* Dump S0ix residency counters */
++ ret = intel_scu_ipc_simple_command(DUMP_RES_COUNTER, 0);
++ if (ret)
++ printk(KERN_ERR "IPC command to DUMP S0ix residency failed\n");
++
++ /* Dump number of interations of S0ix */
++ ret = intel_scu_ipc_simple_command(DUMP_S0IX_COUNT, 0);
++ if (ret)
++ printk(KERN_ERR "IPC command to DUMP S0ix count failed\n");
++ up(&mid_pmu_cxt->scu_ready_sem);
++
++ mid_pmu_cxt->pmu_init_time = cpu_clock(0);
++ prev_s0ix_cnt[SYS_STATE_S0I1] = readl(s0ix_counter[SYS_STATE_S0I1]);
++ prev_s0ix_cnt[SYS_STATE_LPMP3] = readl(s0ix_counter[SYS_STATE_LPMP3]);
++ prev_s0ix_cnt[SYS_STATE_S0I2] = readl(s0ix_counter[SYS_STATE_S0I2]);
++ prev_s0ix_cnt[SYS_STATE_S0I3] = readl(s0ix_counter[SYS_STATE_S0I3]);
++ prev_s0ix_cnt[SYS_STATE_S3] = 0;
++ prev_s0ix_res[SYS_STATE_S0I1] = readq(residency[SYS_STATE_S0I1]);
++ prev_s0ix_res[SYS_STATE_LPMP3] = readq(residency[SYS_STATE_LPMP3]);
++ prev_s0ix_res[SYS_STATE_S0I2] = readq(residency[SYS_STATE_S0I2]);
++ prev_s0ix_res[SYS_STATE_S0I3] = readq(residency[SYS_STATE_S0I3]);
++ prev_s0ix_res[SYS_STATE_S3] = 0 ;
++ }
++ return buf_size;
++}
++
++
++static const struct file_operations devices_state_operations = {
++ .open = devices_state_open,
++ .read = seq_read,
++ .write = devices_state_write,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++#ifdef CONFIG_PM_DEBUG
++static int ignore_lss_show(struct seq_file *s, void *unused)
++{
++ u32 local_ignore_lss[4];
++
++ /* Acquire the scu_ready_sem */
++ down(&mid_pmu_cxt->scu_ready_sem);
++ memcpy(local_ignore_lss, mid_pmu_cxt->ignore_lss, (sizeof(u32)*4));
++ up(&mid_pmu_cxt->scu_ready_sem);
++
++ seq_printf(s, "IGNORE_LSS[0]: %08X\n", local_ignore_lss[0]);
++ seq_printf(s, "IGNORE_LSS[1]: %08X\n", local_ignore_lss[1]);
++ seq_printf(s, "IGNORE_LSS[2]: %08X\n", local_ignore_lss[2]);
++ seq_printf(s, "IGNORE_LSS[3]: %08X\n", local_ignore_lss[3]);
++
++ return 0;
++}
++
++static int ignore_add_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, ignore_lss_show, NULL);
++}
++
++static ssize_t ignore_add_write(struct file *file,
++ const char __user *userbuf, size_t count, loff_t *ppos)
++{
++ char buf[32];
++ int res;
++ int buf_size = min(count, sizeof(buf)-1);
++ int sub_sys_pos, sub_sys_index;
++ u32 lss, local_ignore_lss[4];
++ u32 pm_cmd_val;
++
++ if (copy_from_user(buf, userbuf, buf_size))
++ return -EFAULT;
++
++ buf[buf_size] = 0;
++
++ res = kstrtou32(buf, 10, &lss);
++
++ if (res)
++ return -EINVAL;
++
++ if (lss > MAX_LSS_POSSIBLE)
++ return -EINVAL;
++
++ /* Acquire the scu_ready_sem */
++ down(&mid_pmu_cxt->scu_ready_sem);
++ memcpy(local_ignore_lss, mid_pmu_cxt->ignore_lss, (sizeof(u32)*4));
++ up(&mid_pmu_cxt->scu_ready_sem);
++
++ /* If set to MAX_LSS_POSSIBLE it means
++ * ignore all.
++ */
++ if (lss == MAX_LSS_POSSIBLE) {
++ local_ignore_lss[0] = 0xFFFFFFFF;
++ local_ignore_lss[1] = 0xFFFFFFFF;
++ local_ignore_lss[2] = 0xFFFFFFFF;
++ local_ignore_lss[3] = 0xFFFFFFFF;
++ } else {
++ sub_sys_index = lss / mid_pmu_cxt->ss_per_reg;
++ sub_sys_pos = lss % mid_pmu_cxt->ss_per_reg;
++
++ pm_cmd_val =
++ (D0I3_MASK << (sub_sys_pos * BITS_PER_LSS));
++ local_ignore_lss[sub_sys_index] |= pm_cmd_val;
++ }
++
++ /* Acquire the scu_ready_sem */
++ down(&mid_pmu_cxt->scu_ready_sem);
++ memcpy(mid_pmu_cxt->ignore_lss, local_ignore_lss, (sizeof(u32)*4));
++ up(&mid_pmu_cxt->scu_ready_sem);
++
++ return buf_size;
++}
++
++static const struct file_operations ignore_add_ops = {
++ .open = ignore_add_open,
++ .read = seq_read,
++ .write = ignore_add_write,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++static int ignore_remove_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, ignore_lss_show, NULL);
++}
++
++static ssize_t ignore_remove_write(struct file *file,
++ const char __user *userbuf, size_t count, loff_t *ppos)
++{
++ char buf[32];
++ int res;
++ int buf_size = min(count, sizeof(buf)-1);
++ int sub_sys_pos, sub_sys_index;
++ u32 lss, local_ignore_lss[4];
++ u32 pm_cmd_val;
++
++ if (copy_from_user(buf, userbuf, buf_size))
++ return -EFAULT;
++
++ buf[buf_size] = 0;
++
++ res = kstrtou32(buf, 10, &lss);
++
++ if (res)
++ return -EINVAL;
++
++ if (lss > MAX_LSS_POSSIBLE)
++ return -EINVAL;
++
++ /* Acquire the scu_ready_sem */
++ down(&mid_pmu_cxt->scu_ready_sem);
++ memcpy(local_ignore_lss, mid_pmu_cxt->ignore_lss, (sizeof(u32)*4));
++ up(&mid_pmu_cxt->scu_ready_sem);
++
++ /* If set to MAX_LSS_POSSIBLE it means
++ * remove all from ignore list.
++ */
++ if (lss == MAX_LSS_POSSIBLE) {
++ local_ignore_lss[0] = 0;
++ local_ignore_lss[1] = 0;
++ local_ignore_lss[2] = 0;
++ local_ignore_lss[3] = 0;
++ } else {
++ sub_sys_index = lss / mid_pmu_cxt->ss_per_reg;
++ sub_sys_pos = lss % mid_pmu_cxt->ss_per_reg;
++
++ pm_cmd_val =
++ (D0I3_MASK << (sub_sys_pos * BITS_PER_LSS));
++ local_ignore_lss[sub_sys_index] &= ~pm_cmd_val;
++ }
++
++ /* Acquire the scu_ready_sem */
++ down(&mid_pmu_cxt->scu_ready_sem);
++ memcpy(mid_pmu_cxt->ignore_lss, local_ignore_lss, (sizeof(u32)*4));
++ up(&mid_pmu_cxt->scu_ready_sem);
++
++ return buf_size;
++}
++
++static const struct file_operations ignore_remove_ops = {
++ .open = ignore_remove_open,
++ .read = seq_read,
++ .write = ignore_remove_write,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++static int pmu_sync_d0ix_show(struct seq_file *s, void *unused)
++{
++ int i;
++ u32 local_os_sss[4];
++ struct pmu_ss_states cur_pmsss;
++
++ /* Acquire the scu_ready_sem */
++ down(&mid_pmu_cxt->scu_ready_sem);
++ _pmu2_wait_not_busy();
++ /* Read SCU SSS */
++ pmu_read_sss(&cur_pmsss);
++ /* Read OS SSS */
++ memcpy(local_os_sss, mid_pmu_cxt->os_sss, (sizeof(u32)*4));
++ up(&mid_pmu_cxt->scu_ready_sem);
++
++ for (i = 0; i < 4; i++)
++ seq_printf(s, "OS_SSS[%d]: %08X\tSSS[%d]: %08lX\n", i,
++ local_os_sss[i], i, cur_pmsss.pmu2_states[i]);
++
++ return 0;
++}
++
++static int pmu_sync_d0ix_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, pmu_sync_d0ix_show, NULL);
++}
++
++static ssize_t pmu_sync_d0ix_write(struct file *file,
++ const char __user *userbuf, size_t count, loff_t *ppos)
++{
++ char buf[32];
++ int res, i;
++ bool send_cmd;
++ int buf_size = min(count, sizeof(buf)-1);
++ u32 lss, local_os_sss[4];
++ int sub_sys_pos, sub_sys_index;
++ u32 pm_cmd_val;
++ u32 temp_sss;
++
++ struct pmu_ss_states cur_pmsss;
++
++
++ if (copy_from_user(buf, userbuf, buf_size))
++ return -EFAULT;
++
++ buf[buf_size] = 0;
++
++ res = kstrtou32(buf, 10, &lss);
++
++ if (res)
++ return -EINVAL;
++
++ if (lss > MAX_LSS_POSSIBLE)
++ return -EINVAL;
++
++ /* Acquire the scu_ready_sem */
++ down(&mid_pmu_cxt->scu_ready_sem);
++ _pmu2_wait_not_busy();
++ /* Read SCU SSS */
++ pmu_read_sss(&cur_pmsss);
++
++ for (i = 0; i < 4; i++)
++ local_os_sss[i] = mid_pmu_cxt->os_sss[i] &
++ ~mid_pmu_cxt->ignore_lss[i];
++
++ send_cmd = false;
++ for (i = 0; i < 4; i++) {
++ if (local_os_sss[i] != cur_pmsss.pmu2_states[i]) {
++ send_cmd = true;
++ break;
++ }
++ }
++
++ if (send_cmd) {
++ int status;
++
++ if (lss == MAX_LSS_POSSIBLE) {
++ memcpy(cur_pmsss.pmu2_states, local_os_sss,
++ (sizeof(u32)*4));
++ } else {
++ bool same;
++ sub_sys_index = lss / mid_pmu_cxt->ss_per_reg;
++ sub_sys_pos = lss % mid_pmu_cxt->ss_per_reg;
++ pm_cmd_val =
++ (D0I3_MASK << (sub_sys_pos * BITS_PER_LSS));
++
++ /* dont send d0ix request if its same */
++ same =
++ ((cur_pmsss.pmu2_states[sub_sys_index] & pm_cmd_val)
++ == (mid_pmu_cxt->os_sss[sub_sys_index] & pm_cmd_val));
++
++ if (same)
++ goto unlock;
++
++ cur_pmsss.pmu2_states[sub_sys_index] &= ~pm_cmd_val;
++ temp_sss =
++ mid_pmu_cxt->os_sss[sub_sys_index] & pm_cmd_val;
++ cur_pmsss.pmu2_states[sub_sys_index] |= temp_sss;
++ }
++
++ /* Issue the pmu command to PMU 2
++ * flag is needed to distinguish between
++ * S0ix vs interactive command in pmu_sc_irq()
++ */
++ status = pmu_issue_interactive_command(&cur_pmsss, false,
++ false);
++
++ if (unlikely(status != PMU_SUCCESS)) {
++ dev_dbg(&mid_pmu_cxt->pmu_dev->dev,
++ "Failed to Issue a PM command to PMU2\n");
++ goto unlock;
++ }
++
++ /*
++ * Wait for interactive command to complete.
++ * If we dont wait, there is a possibility that
++ * the driver may access the device before its
++ * powered on in SCU.
++ *
++ */
++ status = _pmu2_wait_not_busy();
++ if (unlikely(status)) {
++ printk(KERN_CRIT "%s: D0ix transition failure\n",
++ __func__);
++ }
++ }
++
++unlock:
++ up(&mid_pmu_cxt->scu_ready_sem);
++
++ return buf_size;
++}
++
++static const struct file_operations pmu_sync_d0ix_ops = {
++ .open = pmu_sync_d0ix_open,
++ .read = seq_read,
++ .write = pmu_sync_d0ix_write,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++static int pmu_force_d0ix_show(struct seq_file *s, void *unused)
++{
++ int i;
++ u32 local_os_sss[4];
++
++ /* Acquire the scu_ready_sem */
++ down(&mid_pmu_cxt->scu_ready_sem);
++ /* Read OS SSS */
++ memcpy(local_os_sss, mid_pmu_cxt->os_sss, (sizeof(u32)*4));
++ up(&mid_pmu_cxt->scu_ready_sem);
++
++ for (i = 0; i < 4; i++)
++ seq_printf(s, "OS_SSS[%d]: %08X\n", i, local_os_sss[i]);
++
++ return 0;
++}
++
++static int pmu_force_d0ix_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, pmu_force_d0ix_show, NULL);
++}
++
++static ssize_t pmu_force_d0i3_write(struct file *file,
++ const char __user *userbuf, size_t count, loff_t *ppos)
++{
++ char buf[32];
++ int res;
++ int buf_size = min(count, sizeof(buf)-1);
++ u32 lss, local_os_sss[4];
++ int sub_sys_pos, sub_sys_index;
++ u32 pm_cmd_val;
++
++ if (copy_from_user(buf, userbuf, buf_size))
++ return -EFAULT;
++
++ buf[buf_size] = 0;
++
++ res = kstrtou32(buf, 10, &lss);
++
++ if (res)
++ return -EINVAL;
++
++ if (lss > MAX_LSS_POSSIBLE)
++ return -EINVAL;
++
++ /* Acquire the scu_ready_sem */
++ down(&mid_pmu_cxt->scu_ready_sem);
++
++ if (lss == MAX_LSS_POSSIBLE) {
++ local_os_sss[0] =
++ local_os_sss[1] =
++ local_os_sss[2] =
++ local_os_sss[3] = 0xFFFFFFFF;
++ } else {
++ memcpy(local_os_sss, mid_pmu_cxt->os_sss, (sizeof(u32)*4));
++ sub_sys_index = lss / mid_pmu_cxt->ss_per_reg;
++ sub_sys_pos = lss % mid_pmu_cxt->ss_per_reg;
++ pm_cmd_val =
++ (D0I3_MASK << (sub_sys_pos * BITS_PER_LSS));
++
++ local_os_sss[sub_sys_index] |= pm_cmd_val;
++ }
++
++ memcpy(mid_pmu_cxt->os_sss, local_os_sss, (sizeof(u32)*4));
++
++ up(&mid_pmu_cxt->scu_ready_sem);
++
++ return buf_size;
++}
++
++static const struct file_operations pmu_force_d0i3_ops = {
++ .open = pmu_force_d0ix_open,
++ .read = seq_read,
++ .write = pmu_force_d0i3_write,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++static ssize_t pmu_force_d0i0_write(struct file *file,
++ const char __user *userbuf, size_t count, loff_t *ppos)
++{
++ char buf[32];
++ int res;
++ int buf_size = min(count, sizeof(buf)-1);
++ u32 lss, local_os_sss[4];
++ int sub_sys_pos, sub_sys_index;
++ u32 pm_cmd_val;
++
++ if (copy_from_user(buf, userbuf, buf_size))
++ return -EFAULT;
++
++ buf[buf_size] = 0;
++
++ res = kstrtou32(buf, 10, &lss);
++
++ if (res)
++ return -EINVAL;
++
++ if (lss > MAX_LSS_POSSIBLE)
++ return -EINVAL;
++
++ /* Acquire the scu_ready_sem */
++ down(&mid_pmu_cxt->scu_ready_sem);
++
++ if (lss == MAX_LSS_POSSIBLE) {
++ local_os_sss[0] =
++ local_os_sss[1] =
++ local_os_sss[2] =
++ local_os_sss[3] = 0;
++ } else {
++ memcpy(local_os_sss, mid_pmu_cxt->os_sss, (sizeof(u32)*4));
++ sub_sys_index = lss / mid_pmu_cxt->ss_per_reg;
++ sub_sys_pos = lss % mid_pmu_cxt->ss_per_reg;
++ pm_cmd_val =
++ (D0I3_MASK << (sub_sys_pos * BITS_PER_LSS));
++
++ local_os_sss[sub_sys_index] &= ~pm_cmd_val;
++ }
++
++ memcpy(mid_pmu_cxt->os_sss, local_os_sss, (sizeof(u32)*4));
++
++ up(&mid_pmu_cxt->scu_ready_sem);
++
++ return buf_size;
++}
++
++static const struct file_operations pmu_force_d0i0_ops = {
++ .open = pmu_force_d0ix_open,
++ .read = seq_read,
++ .write = pmu_force_d0i0_write,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++static int cstate_ignore_add_show(struct seq_file *s, void *unused)
++{
++ int i;
++ seq_printf(s, "CSTATES IGNORED: ");
++ for (i = 0; i < CPUIDLE_STATE_MAX; i++)
++ if ((mid_pmu_cxt->cstate_ignore & (1 << i)))
++ seq_printf(s, "%d, ", i+1);
++
++ seq_printf(s, "\n");
++ return 0;
++}
++
++static int cstate_ignore_add_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, cstate_ignore_add_show, NULL);
++}
++
++static ssize_t cstate_ignore_add_write(struct file *file,
++ const char __user *userbuf, size_t count, loff_t *ppos)
++{
++ char buf[32];
++ int res;
++ int cstate;
++ int buf_size = min(count, sizeof(buf)-1);
++
++ if (copy_from_user(buf, userbuf, buf_size))
++ return -EFAULT;
++
++ buf[buf_size] = 0;
++
++ res = kstrtou32(buf, 10, &cstate);
++
++ if (res)
++ return -EINVAL;
++
++ if (cstate > MAX_CSTATES_POSSIBLE)
++ return -EINVAL;
++
++ /* cannot add/remove C0, C1 */
++ if (((cstate == 0) || (cstate == 1))) {
++ printk(KERN_CRIT "C0 C1 state cannot be used.\n");
++ return -EINVAL;
++ }
++
++ if (!mid_pmu_cxt->cstate_qos)
++ return -EINVAL;
++
++ if (cstate == MAX_CSTATES_POSSIBLE) {
++ mid_pmu_cxt->cstate_ignore = ((1 << CPUIDLE_STATE_MAX) - 1);
++ pm_qos_update_request(mid_pmu_cxt->cstate_qos,
++ CSTATE_EXIT_LATENCY_C1 - 1);
++ } else {
++ u32 cstate_exit_latency[CPUIDLE_STATE_MAX+1];
++ u32 local_cstate_allowed;
++ int max_cstate_allowed;
++
++ /* 0 is C1 state */
++ cstate--;
++ mid_pmu_cxt->cstate_ignore |= (1 << cstate);
++
++ /* by default remove C1 from ignore list */
++ mid_pmu_cxt->cstate_ignore &= ~(1 << 0);
++
++ /* populate cstate latency table */
++ cstate_exit_latency[0] = CSTATE_EXIT_LATENCY_C1;
++ cstate_exit_latency[1] = CSTATE_EXIT_LATENCY_C2;
++ cstate_exit_latency[2] = CSTATE_EXIT_LATENCY_C2;
++ cstate_exit_latency[3] = CSTATE_EXIT_LATENCY_C2;
++ cstate_exit_latency[4] = CSTATE_EXIT_LATENCY_C2;
++ cstate_exit_latency[5] = CSTATE_EXIT_LATENCY_C6;
++ cstate_exit_latency[6] = CSTATE_EXIT_LATENCY_S0i1;
++ cstate_exit_latency[7] = CSTATE_EXIT_LATENCY_S0i2;
++ cstate_exit_latency[8] = CSTATE_EXIT_LATENCY_S0i3;
++ cstate_exit_latency[9] = PM_QOS_DEFAULT_VALUE;
++ cstate_exit_latency[10] = PM_QOS_DEFAULT_VALUE;
++
++ local_cstate_allowed = ~mid_pmu_cxt->cstate_ignore;
++
++ /* restrict to max c-states */
++ local_cstate_allowed &= ((1<<CPUIDLE_STATE_MAX)-1);
++
++ /* If no states allowed will return 0 */
++ max_cstate_allowed = fls(local_cstate_allowed);
++
++ printk(KERN_CRIT "max_cstate: %d local_cstate_allowed = %x\n",
++ max_cstate_allowed, local_cstate_allowed);
++ printk(KERN_CRIT "exit latency = %d\n",
++ (cstate_exit_latency[max_cstate_allowed]-1));
++ pm_qos_update_request(mid_pmu_cxt->cstate_qos,
++ (cstate_exit_latency[max_cstate_allowed]-1));
++ }
++
++ return buf_size;
++}
++
++static const struct file_operations cstate_ignore_add_ops = {
++ .open = cstate_ignore_add_open,
++ .read = seq_read,
++ .write = cstate_ignore_add_write,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++static int cstate_ignore_remove_show(struct seq_file *s, void *unused)
++{
++ int i;
++ seq_printf(s, "CSTATES ALLOWED: ");
++ for (i = 0; i < CPUIDLE_STATE_MAX; i++)
++ if (!(mid_pmu_cxt->cstate_ignore & (1 << i)))
++ seq_printf(s, "%d, ", i+1);
++
++ seq_printf(s, "\n");
++
++ return 0;
++}
++
++static int cstate_ignore_remove_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, cstate_ignore_remove_show, NULL);
++}
++
++static ssize_t cstate_ignore_remove_write(struct file *file,
++ const char __user *userbuf, size_t count, loff_t *ppos)
++{
++ char buf[32];
++ int res;
++ int cstate;
++ int buf_size = min(count, sizeof(buf)-1);
++
++ if (copy_from_user(buf, userbuf, buf_size))
++ return -EFAULT;
++
++ buf[buf_size] = 0;
++
++ res = kstrtou32(buf, 10, &cstate);
++
++ if (res)
++ return -EINVAL;
++
++ if (cstate > MAX_CSTATES_POSSIBLE)
++ return -EINVAL;
++
++ /* cannot add/remove C0, C1 */
++ if (((cstate == 0) || (cstate == 1))) {
++ printk(KERN_CRIT "C0 C1 state cannot be used.\n");
++ return -EINVAL;
++ }
++
++ if (!mid_pmu_cxt->cstate_qos)
++ return -EINVAL;
++
++ if (cstate == MAX_CSTATES_POSSIBLE) {
++ mid_pmu_cxt->cstate_ignore =
++ ~((1 << CPUIDLE_STATE_MAX) - 1);
++ /* Ignore C2, C3, C5, C8 and C10 states */
++ mid_pmu_cxt->cstate_ignore |= (1 << 1);
++ mid_pmu_cxt->cstate_ignore |= (1 << 2);
++ mid_pmu_cxt->cstate_ignore |= (1 << 4);
++ mid_pmu_cxt->cstate_ignore |= (1 << 7);
++ mid_pmu_cxt->cstate_ignore |= (1 << 9);
++
++ pm_qos_update_request(mid_pmu_cxt->cstate_qos,
++ PM_QOS_DEFAULT_VALUE);
++ } else {
++ u32 cstate_exit_latency[CPUIDLE_STATE_MAX+1];
++ u32 local_cstate_allowed;
++ int max_cstate_allowed;
++
++ /* populate cstate latency table */
++ cstate_exit_latency[0] = CSTATE_EXIT_LATENCY_C1;
++ cstate_exit_latency[1] = CSTATE_EXIT_LATENCY_C2;
++ cstate_exit_latency[2] = CSTATE_EXIT_LATENCY_C2;
++ cstate_exit_latency[3] = CSTATE_EXIT_LATENCY_C2;
++ cstate_exit_latency[4] = CSTATE_EXIT_LATENCY_C2;
++ cstate_exit_latency[5] = CSTATE_EXIT_LATENCY_C6;
++ cstate_exit_latency[6] = CSTATE_EXIT_LATENCY_S0i1;
++ cstate_exit_latency[7] = CSTATE_EXIT_LATENCY_S0i2;
++ cstate_exit_latency[8] = CSTATE_EXIT_LATENCY_S0i3;
++ cstate_exit_latency[9] = PM_QOS_DEFAULT_VALUE;
++ cstate_exit_latency[10] = PM_QOS_DEFAULT_VALUE;
++
++ /* 0 is C1 state */
++ cstate--;
++ mid_pmu_cxt->cstate_ignore &= ~(1 << cstate);
++
++ /* by default remove C1 from ignore list */
++ mid_pmu_cxt->cstate_ignore &= ~(1 << 0);
++
++ /* Ignore C2, C3, C5, C8 and C10 states */
++ mid_pmu_cxt->cstate_ignore |= (1 << 1);
++ mid_pmu_cxt->cstate_ignore |= (1 << 2);
++ mid_pmu_cxt->cstate_ignore |= (1 << 4);
++ mid_pmu_cxt->cstate_ignore |= (1 << 7);
++ mid_pmu_cxt->cstate_ignore |= (1 << 9);
++
++ local_cstate_allowed = ~mid_pmu_cxt->cstate_ignore;
++ /* restrict to max c-states */
++ local_cstate_allowed &= ((1<<CPUIDLE_STATE_MAX)-1);
++
++ /* If no states allowed will return 0 */
++ max_cstate_allowed = fls(local_cstate_allowed);
++ printk(KERN_CRIT "max_cstate: %d local_cstate_allowed = %x\n",
++ max_cstate_allowed, local_cstate_allowed);
++ printk(KERN_CRIT "exit latency = %d\n",
++ (cstate_exit_latency[max_cstate_allowed]-1));
++ pm_qos_update_request(mid_pmu_cxt->cstate_qos,
++ (cstate_exit_latency[max_cstate_allowed]-1));
++ }
++
++ return buf_size;
++}
++
++static const struct file_operations cstate_ignore_remove_ops = {
++ .open = cstate_ignore_remove_open,
++ .read = seq_read,
++ .write = cstate_ignore_remove_write,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++static int s3_ctrl_show(struct seq_file *s, void *unused)
++{
++ seq_printf(s, "%d\n", enable_s3);
++ return 0;
++}
++
++static int s3_ctrl_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, s3_ctrl_show, NULL);
++}
++
++static ssize_t s3_ctrl_write(struct file *file,
++ const char __user *userbuf, size_t count, loff_t *ppos)
++{
++ char buf[32];
++ int res;
++ int local_s3_ctrl;
++ int buf_size = min(count, sizeof(buf)-1);
++
++ if (copy_from_user(buf, userbuf, buf_size))
++ return -EFAULT;
++
++ buf[buf_size] = 0;
++
++ res = kstrtou32(buf, 10, &local_s3_ctrl);
++
++ if (res)
++ return -EINVAL;
++
++ enable_s3 = local_s3_ctrl ? 1 : 0;
++
++ if (enable_s3)
++ __pm_relax(mid_pmu_cxt->pmu_wake_lock);
++ else
++ __pm_stay_awake(mid_pmu_cxt->pmu_wake_lock);
++
++ return buf_size;
++}
++
++static const struct file_operations s3_ctrl_ops = {
++ .open = s3_ctrl_open,
++ .read = seq_read,
++ .write = s3_ctrl_write,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++
++unsigned int pmu_get_new_cstate(unsigned int cstate, int *index)
++{
++ static int cstate_index_table[CPUIDLE_STATE_MAX] = {
++ 1, 1, 1, 1, 1, 2, 3, 3, 4, 4};
++ unsigned int new_cstate = cstate;
++ u32 local_cstate = (u32)(cstate);
++ u32 local_cstate_allowed = ~mid_pmu_cxt->cstate_ignore;
++ u32 cstate_mask, cstate_no_s0ix_mask = (u32)((1 << 6) - 1);
++
++ if (platform_is(INTEL_ATOM_MRFLD)) {
++ /* cstate is also 7 for C9 so correct */
++ if ((local_cstate == 7) && (*index == 4))
++ local_cstate = 9;
++
++ /* get next low cstate allowed */
++ cstate_mask = (u32)((1 << local_cstate)-1);
++ /* in case if cstate == 0 which should not be the case*/
++ cstate_mask |= 1;
++ local_cstate_allowed &= ((1<<CPUIDLE_STATE_MAX)-1);
++ local_cstate_allowed &= cstate_mask;
++ if (!could_do_s0ix())
++ local_cstate_allowed &= cstate_no_s0ix_mask;
++ new_cstate = fls(local_cstate_allowed);
++
++ *index = cstate_index_table[new_cstate-1];
++ }
++
++ return new_cstate;
++}
++#endif
++
++DEFINE_PER_CPU(u64[NUM_CSTATES_RES_MEASURE], c_states_res);
++
++static int read_c_states_res(void)
++{
++ int cpu, i;
++ u32 lo, hi;
++
++ u32 c_states_res_msr[NUM_CSTATES_RES_MEASURE] = {
++ PUNIT_CR_CORE_C1_RES_MSR,
++ PUNIT_CR_CORE_C4_RES_MSR,
++ PUNIT_CR_CORE_C6_RES_MSR
++ };
++
++ for_each_online_cpu(cpu)
++ for (i = 0; i < NUM_CSTATES_RES_MEASURE; i++) {
++ u64 temp;
++ rdmsr_on_cpu(cpu, c_states_res_msr[i], &lo, &hi);
++ temp = hi;
++ temp <<= 32;
++ temp |= lo;
++ per_cpu(c_states_res, cpu)[i] = temp;
++ }
++
++ return 0;
++}
++
++static int c_states_stat_show(struct seq_file *s, void *unused)
++{
++ char *c_states_name[] = {
++ "C1",
++ "C4",
++ "C6"
++ };
++
++ int i, cpu;
++
++ seq_printf(s, "C STATES: %20s\n", "Residecy");
++ for_each_online_cpu(cpu)
++ seq_printf(s, "%18s %d", "Core", cpu);
++ seq_printf(s, "\n");
++
++ read_c_states_res();
++ for (i = 0; i < NUM_CSTATES_RES_MEASURE; i++) {
++ seq_printf(s, "%s", c_states_name[i]);
++ for_each_online_cpu(cpu)
++ seq_printf(s, "%18llu", per_cpu(c_states_res, cpu)[i]);
++ seq_printf(s, "\n");
++ }
++ return 0;
++}
++
++static int c_states_stat_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, c_states_stat_show, NULL);
++}
++
++static const struct file_operations c_states_stat_ops = {
++ .open = c_states_stat_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++/*These are place holders and will be enabled in next patch*/
++
++void pmu_log_pmu_irq(int status) { return; };
++void pmu_log_ipc_irq(void) { return; };
++void pmu_log_ipc(u32 command) { return; };
++void pmu_log_command(u32 command, struct pmu_ss_states *pm_ssc) { return; };
++void pmu_dump_logs(void) { return; };
++void pmu_stat_start(enum sys_state type) { return; };
++void pmu_stat_end(void) { return; };
++void pmu_stat_error(u8 err_type) { return; };
++void pmu_s0ix_demotion_stat(int req_state, int grant_state) { return; };
++EXPORT_SYMBOL(pmu_s0ix_demotion_stat);
++
++void pmu_stats_finish(void)
++{
++#ifdef CONFIG_PM_DEBUG
++ if (mid_pmu_cxt->cstate_qos) {
++ pm_qos_remove_request(mid_pmu_cxt->cstate_qos);
++ kfree(mid_pmu_cxt->cstate_qos);
++ mid_pmu_cxt->cstate_qos = NULL;
++ }
++#endif
++
++ return;
++}
++
++void pmu_s3_stats_update(int enter)
++{
++#ifdef CONFIG_PM_DEBUG
++ int ret;
++
++ down(&mid_pmu_cxt->scu_ready_sem);
++ /* Dump S0ix residency counters */
++ ret = intel_scu_ipc_simple_command(DUMP_RES_COUNTER, 0);
++ if (ret)
++ printk(KERN_ERR "IPC command to DUMP S0ix residency failed\n");
++
++ /* Dump number of interations of S0ix */
++ ret = intel_scu_ipc_simple_command(DUMP_S0IX_COUNT, 0);
++ if (ret)
++ printk(KERN_ERR "IPC command to DUMP S0ix count failed\n");
++
++ up(&mid_pmu_cxt->scu_ready_sem);
++
++ if (enter == 1) {
++ S3_count = readl(s0ix_counter[SYS_STATE_S0I3]);
++ S3_res = readq(residency[SYS_STATE_S0I3]);
++ } else {
++ prev_s0ix_cnt[SYS_STATE_S3] +=
++ (readl(s0ix_counter[SYS_STATE_S0I3])) - S3_count;
++ prev_s0ix_res[SYS_STATE_S3] += (readq(residency[SYS_STATE_S0I3])) - S3_res;
++ }
++
++#endif
++ return;
++}
++
++
++void pmu_stats_init(void)
++{
++ /* /sys/kernel/debug/mid_pmu_states */
++ (void) debugfs_create_file("mid_pmu_states", S_IFREG | S_IRUGO,
++ NULL, NULL, &devices_state_operations);
++
++ /* /sys/kernel/debug/c_p_states_stat */
++ (void) debugfs_create_file("c_states_stat", S_IFREG | S_IRUGO,
++ NULL, NULL, &c_states_stat_ops);
++#ifdef CONFIG_PM_DEBUG
++ if (platform_is(INTEL_ATOM_MRFLD)) {
++ /* If s0ix is disabled then restrict to C6 */
++ if (!enable_s0ix) {
++ mid_pmu_cxt->cstate_ignore =
++ ~((1 << CPUIDLE_STATE_MAX) - 1);
++
++ /* Ignore C2, C3, C5 states */
++ mid_pmu_cxt->cstate_ignore |= (1 << 1);
++ mid_pmu_cxt->cstate_ignore |= (1 << 2);
++ mid_pmu_cxt->cstate_ignore |= (1 << 4);
++
++ /* For now ignore C7, C8, C9, C10 states */
++ mid_pmu_cxt->cstate_ignore |= (1 << 6);
++ mid_pmu_cxt->cstate_ignore |= (1 << 7);
++ mid_pmu_cxt->cstate_ignore |= (1 << 8);
++ mid_pmu_cxt->cstate_ignore |= (1 << 9);
++ } else {
++ mid_pmu_cxt->cstate_ignore =
++ ~((1 << CPUIDLE_STATE_MAX) - 1);
++
++ /* Ignore C2, C3, C5, C8 and C10 states */
++ mid_pmu_cxt->cstate_ignore |= (1 << 1);
++ mid_pmu_cxt->cstate_ignore |= (1 << 2);
++ mid_pmu_cxt->cstate_ignore |= (1 << 4);
++ mid_pmu_cxt->cstate_ignore |= (1 << 7);
++ mid_pmu_cxt->cstate_ignore |= (1 << 9);
++ }
++
++ mid_pmu_cxt->cstate_qos =
++ kzalloc(sizeof(struct pm_qos_request), GFP_KERNEL);
++ if (mid_pmu_cxt->cstate_qos) {
++ pm_qos_add_request(mid_pmu_cxt->cstate_qos,
++ PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
++ }
++
++ /* If s0ix is disabled then restrict to C6 */
++ if (!enable_s0ix) {
++ /* Restrict platform Cx state to C6 */
++ pm_qos_update_request(mid_pmu_cxt->cstate_qos,
++ (CSTATE_EXIT_LATENCY_S0i1-1));
++ }
++
++ /* /sys/kernel/debug/ignore_add */
++ (void) debugfs_create_file("ignore_add", S_IFREG | S_IRUGO,
++ NULL, NULL, &ignore_add_ops);
++ /* /sys/kernel/debug/ignore_remove */
++ (void) debugfs_create_file("ignore_remove", S_IFREG | S_IRUGO,
++ NULL, NULL, &ignore_remove_ops);
++ /* /sys/kernel/debug/pmu_sync_d0ix */
++ (void) debugfs_create_file("pmu_sync_d0ix", S_IFREG | S_IRUGO,
++ NULL, NULL, &pmu_sync_d0ix_ops);
++ /* /sys/kernel/debug/pmu_force_d0i0 */
++ (void) debugfs_create_file("pmu_force_d0i0", S_IFREG | S_IRUGO,
++ NULL, NULL, &pmu_force_d0i0_ops);
++ /* /sys/kernel/debug/pmu_force_d0i3 */
++ (void) debugfs_create_file("pmu_force_d0i3", S_IFREG | S_IRUGO,
++ NULL, NULL, &pmu_force_d0i3_ops);
++ /* /sys/kernel/debug/cstate_ignore_add */
++ (void) debugfs_create_file("cstate_ignore_add",
++ S_IFREG | S_IRUGO, NULL, NULL, &cstate_ignore_add_ops);
++ /* /sys/kernel/debug/cstate_ignore_remove */
++ (void) debugfs_create_file("cstate_ignore_remove",
++ S_IFREG | S_IRUGO, NULL, NULL, &cstate_ignore_remove_ops);
++ /* /sys/kernel/debug/cstate_ignore_remove */
++ (void) debugfs_create_file("s3_ctrl",
++ S_IFREG | S_IRUGO, NULL, NULL, &s3_ctrl_ops);
++ }
++#endif
++}
++
++#endif /*if CONFIG_REMOVEME_INTEL_ATOM_MRFLD_POWER*/
+diff --git a/arch/x86/platform/intel-mid/intel_soc_pm_debug.h b/arch/x86/platform/intel-mid/intel_soc_pm_debug.h
+new file mode 100644
+index 0000000..51e0871
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/intel_soc_pm_debug.h
+@@ -0,0 +1,234 @@
++/*
++ * intel_soc_pm_debug.h
++ * Copyright (c) 2012, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++#ifndef _INTEL_SOC_PM_DEBUG_H
++#define _INTEL_SOC_PM_DEBUG_H
++#include <linux/intel_mid_pm.h>
++
++#include "intel_soc_pmu.h"
++
++
++#define NANO_SEC 1000000000UL /* 10^9 in sec */
++#define MICRO_SEC 1000000UL /* 10^6 in sec */
++#define PMU_LOG_INTERVAL_SECS (60*5) /* 5 mins in secs */
++
++#define S0IX_LAT_SRAM_ADDR_CLVP 0xFFFF7FD0
++#define S0IX_LAT_SRAM_SIZE_CLVP 8
++
++#define IPC_CMD_S0IX_LATENCY_CLVP 0xCE
++#define IPC_SUB_MEASURE_START_CLVP 0x00
++#define IPC_SUB_MEASURE_STOP_CLVP 0x01
++
++struct simple_stat {
++ u64 min;
++ u64 max;
++ u64 total;
++ u64 curr;
++};
++
++struct entry_exit_stat {
++ struct simple_stat entry;
++ struct simple_stat exit;
++};
++
++struct latency_stat {
++ struct entry_exit_stat scu_latency[SYS_STATE_MAX];
++ struct entry_exit_stat os_latency[SYS_STATE_MAX];
++ struct simple_stat s3_parts_lat[MAX_S3_PARTS];
++ u64 count[SYS_STATE_MAX];
++ u32 __iomem *scu_s0ix_lat_addr;
++ struct dentry *dentry;
++ bool latency_measure;
++};
++
++struct island {
++ int type;
++ int index;
++ char *name;
++};
++
++struct lss_definition {
++ char *lss_name;
++ char *block;
++ char *subsystem;
++};
++
++#ifdef CONFIG_REMOVEME_INTEL_ATOM_MRFLD_POWER
++#define PUNIT_CR_CORE_C1_RES_MSR 0x660
++#define PUNIT_CR_CORE_C4_RES_MSR 0x3fc
++#define PUNIT_CR_CORE_C6_RES_MSR 0x3fd
++
++#define NUM_CSTATES_RES_MEASURE 3
++
++extern unsigned int enable_s3;
++extern unsigned int enable_s0ix;
++
++extern u32 __iomem *residency[];
++extern u32 __iomem *s0ix_counter[];
++
++#endif
++
++/* platform dependency starts */
++#ifdef CONFIG_INTEL_REMOVEME_ATOM_MDFLD_POWER
++
++#define DEV_GFX 2
++#define FUNC_GFX 0
++#define ISLANDS_GFX 8
++#define DEV_ISP 3
++#define FUNC_ISP 0
++#define ISLANDS_ISP 2
++#define NC_DEVS 2
++
++static struct lss_definition lsses[] = {
++ {"Lss00", "Storage", "SDIO0 (HC2)"},
++ {"Lss01", "Storage", "eMMC0 (HC0a)"},
++ {"NA", "Storage", "ND_CTL (Note 5)"},
++ {"Lss03", "H S I", "H S I DMA"},
++ {"Lss04", "Security", "RNG"},
++ {"Lss05", "Storage", "eMMC1 (HC0b)"},
++ {"Lss06", "USB", "USB OTG (ULPI)"},
++ {"Lss07", "USB", "USB_SPH"},
++ {"Lss08", "Audio", ""},
++ {"Lss09", "Audio", ""},
++ {"Lss10", "SRAM", " SRAM CTL+SRAM_16KB"},
++ {"Lss11", "SRAM", " SRAM CTL+SRAM_16KB"},
++ {"Lss12", "SRAM", "SRAM BANK (16KB+3x32KBKB)"},
++ {"Lss13", "SRAM", "SRAM BANK(4x32KB)"},
++ {"Lss14", "SDIO COMMS", "SDIO2 (HC1b)"},
++ {"Lss15", "PTI, DAFCA", " DFX Blocks"},
++ {"Lss16", "SC", " DMA"},
++ {"NA", "SC", "SPI0/MSIC"},
++ {"Lss18", "GP", "SPI1"},
++ {"Lss19", "GP", " SPI2"},
++ {"Lss20", "GP", " I2C0"},
++ {"Lss21", "GP", " I2C1"},
++ {"NA", "Fabrics", " Main Fabric"},
++ {"NA", "Fabrics", " Secondary Fabric"},
++ {"NA", "SC", "SC Fabric"},
++ {"Lss25", "Audio", " I-RAM BANK1 (32 + 256KB)"},
++ {"NA", "SCU", " ROM BANK1 (18KB+18KB+18KB)"},
++ {"Lss27", "GP", "I2C2"},
++ {"NA", "SSC", "SSC (serial bus controller to FLIS)"},
++ {"Lss29", "Security", "Chaabi AON Registers"},
++ {"Lss30", "SDIO COMMS", "SDIO1 (HC1a)"},
++ {"NA", "SCU", "I-RAM BANK0 (32KB)"},
++ {"NA", "SCU", "I-RAM BANK1 (32KB)"},
++ {"Lss33", "GP", "I2C3 (HDMI)"},
++ {"Lss34", "GP", "I2C4"},
++ {"Lss35", "GP", "I2C5"},
++ {"Lss36", "GP", "SSP (SPI3)"},
++ {"Lss37", "GP", "GPIO1"},
++ {"NA", "GP", "GP Fabric"},
++ {"Lss39", "SC", "GPIO0"},
++ {"Lss40", "SC", "KBD"},
++ {"Lss41", "SC", "UART2:0"},
++ {"NA", "NA", "NA"},
++ {"NA", "NA", "NA"},
++ {"Lss44", "Security", " Security TAPC"},
++ {"NA", "MISC", "AON Timers"},
++ {"NA", "PLL", "LFHPLL and Spread Spectrum"},
++ {"NA", "PLL", "USB PLL"},
++ {"NA", "NA", "NA"},
++ {"NA", "Audio", "SLIMBUS CTL 1 (note 5)"},
++ {"NA", "Audio", "SLIMBUS CTL 2 (note 5)"},
++ {"Lss51", "Audio", "SSP0"},
++ {"Lss52", "Audio", "SSP1"},
++ {"NA", "Bridge", "IOSF to OCP Bridge"},
++ {"Lss54", "GP", "DMA"},
++ {"NA", "SC", "SVID (Serial Voltage ID)"},
++ {"NA", "SOC Fuse", "SoC Fuse Block (note 3)"},
++ {"NA", "NA", "NA"},
++};
++#endif
++
++
++#ifdef CONFIG_REMOVEME_INTEL_ATOM_CLV_POWER
++
++#define DEV_GFX 2
++#define FUNC_GFX 0
++#define ISLANDS_GFX 8
++#define DEV_ISP 3
++#define FUNC_ISP 0
++#define ISLANDS_ISP 2
++#define NC_DEVS 2
++
++static struct lss_definition lsses[] = {
++ {"Lss00", "Storage", "SDIO0 (HC2)"},
++ {"Lss01", "Storage", "eMMC0 (HC0a)"},
++ {"NA", "Timer", "AONT"},
++ {"Lss03", "H S I", "H S I DMA"},
++ {"Lss04", "Security", "RNG"},
++ {"Lss05", "Storage", "eMMC1 (HC0b)"},
++ {"Lss06", "USB", "USB OTG (ULPI)"},
++ {"Lss07", "USB", "USB_SPH"},
++ {"Lss08", "Audio", "Audio ENGINE"},
++ {"Lss09", "Audio", "Audio DMA"},
++ {"Lss10", "SRAM", " SRAM CTL+SRAM_16KB"},
++ {"Lss11", "SRAM", " SRAM CTL+SRAM_16KB"},
++ {"Lss12", "SRAM", "SRAM BANK (16KB+3x32KBKB)"},
++ {"Lss13", "SRAM", "SRAM BANK(4x32KB)"},
++ {"Lss14", "SDIO COMMS", "SDIO2 (HC1b)"},
++ {"Lss15", "PTI, DAFCA", " DFX Blocks"},
++ {"Lss16", "SC", " DMA"},
++ {"NA", "SC", "SPI0/MSIC"},
++ {"Lss18", "GP", "SPI1"},
++ {"Lss19", "GP", " SPI2"},
++ {"Lss20", "GP", " I2C0"},
++ {"Lss21", "GP", " I2C1"},
++ {"NA", "Timer", "HPET"},
++ {"NA", "Timer", "External Timer"},
++ {"NA", "SC", "SC Fabric"},
++ {"Lss25", "Audio", " I-RAM BANK1 (32 + 256KB)"},
++ {"NA", "SCU", " ROM BANK1 (18KB+18KB+18KB)"},
++ {"Lss27", "GP", "I2C2"},
++ {"NA", "SSC", "SSC (serial bus controller to FLIS)"},
++ {"Lss29", "Security", "Chaabi AON Registers"},
++ {"Lss30", "SDIO COMMS", "SDIO1 (HC1a)"},
++ {"NA", "Timer", "vRTC"},
++ {"NA", "Security", "Security Timer"},
++ {"Lss33", "GP", "I2C3 (HDMI)"},
++ {"Lss34", "GP", "I2C4"},
++ {"Lss35", "GP", "I2C5"},
++ {"Lss36", "GP", "SSP (SPI3)"},
++ {"Lss37", "GP", "GPIO1"},
++ {"NA", "MSIC", "Power Button"},
++ {"Lss39", "SC", "GPIO0"},
++ {"Lss40", "SC", "KBD"},
++ {"Lss41", "SC", "UART2:0"},
++ {"NA", "MSIC", "ADC"},
++ {"NA", "MSIC", "Charger"},
++ {"Lss44", "Security", " Security TAPC"},
++ {"NA", "MSIC", "AON Timers"},
++ {"NA", "MSIC", "GPI"},
++ {"NA", "MSIC", "BCU"},
++ {"NA", "NA", "SSP2"},
++ {"NA", "Audio", "SLIMBUS CTL 1 (note 5)"},
++ {"NA", "Audio", "SLIMBUS CTL 2 (note 5)"},
++ {"Lss51", "Audio", "SSP0"},
++ {"Lss52", "Audio", "SSP1"},
++ {"NA", "Bridge", "IOSF to OCP Bridge"},
++ {"Lss54", "GP", "DMA"},
++ {"NA", "MSIC", "RESET"},
++ {"NA", "SOC Fuse", "SoC Fuse Block (note 3)"},
++ {"NA", "NA", "NA"},
++ {"Lss58", "NA", "SSP4"},
++};
++#endif
++/* platform dependency ends */
++
++#endif
+diff --git a/arch/x86/platform/intel-mid/intel_soc_pmu.c b/arch/x86/platform/intel-mid/intel_soc_pmu.c
+new file mode 100644
+index 0000000..255880c
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/intel_soc_pmu.c
+@@ -0,0 +1,2143 @@
++/*
++ * intel_soc_pmu.c - This driver provides interface to configure the 2 pmu's
++ * Copyright (c) 2012, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#include "intel_soc_pmu.h"
++#include <linux/cpuidle.h>
++#include <linux/proc_fs.h>
++#include <asm/intel_mid_rpmsg.h>
++
++#ifdef CONFIG_DRM_INTEL_MID
++#define GFX_ENABLE
++#endif
++
++bool pmu_initialized;
++
++DEFINE_MUTEX(pci_root_lock);
++
++/* mid_pmu context structure */
++struct mid_pmu_dev *mid_pmu_cxt;
++
++struct platform_pmu_ops *pmu_ops;
++/*
++ * Locking strategy::
++ *
++ * one semaphore (scu_ready sem) is used for accessing busy bit,
++ * issuing interactive cmd in the code.
++ * The entry points in pmu driver are pmu_pci_set_power_state()
++ * and PMU interrupt handler contexts, so here is the flow of how
++ * the semaphore is used.
++ *
++ * In D0ix command case::
++ * set_power_state process context:
++ * set_power_state()->acquire_scu_ready_sem()->issue_interactive_cmd->
++ * wait_for_interactive_complete->release scu_ready sem
++ *
++ * PMU Interrupt context:
++ * pmu_interrupt_handler()->release interactive_complete->return
++ *
++ * In Idle handler case::
++ * Idle context:
++ * idle_handler()->try_acquire_scu_ready_sem->if acquired->
++ * issue s0ix command->return
++ *
++ * PMU Interrupt context:
++ * pmu_Interrupt_handler()->release scu_ready_sem->return
++ *
++ */
++
++/* Maps pci power states to SCU D0ix mask */
++static int pci_to_platform_state(pci_power_t pci_state)
++{
++
++ static int mask[] = {D0I0_MASK, D0I1_MASK,
++ D0I2_MASK, D0I3_MASK, D0I3_MASK};
++
++ int state = D0I0_MASK;
++
++ if (pci_state > 4)
++ WARN(1, "%s: wrong pci_state received.\n", __func__);
++
++ else
++ state = mask[pci_state];
++
++ return state;
++}
++
++/* Maps power states to pmu driver's internal indexes */
++int mid_state_to_sys_state(int mid_state)
++{
++ int sys_state = 0;
++ switch (mid_state) {
++ case MID_S0I1_STATE:
++ sys_state = SYS_STATE_S0I1;
++ break;
++ case MID_LPMP3_STATE:
++ sys_state = SYS_STATE_S0I2;
++ break;
++ case MID_S0I3_STATE:
++ sys_state = SYS_STATE_S0I3;
++ break;
++ case MID_S3_STATE:
++ sys_state = SYS_STATE_S3;
++ break;
++
++ case C6_HINT:
++ sys_state = SYS_STATE_S0I0;
++ }
++
++ return sys_state;
++}
++
++/* PCI Device Id structure */
++static DEFINE_PCI_DEVICE_TABLE(mid_pm_ids) = {
++ {PCI_VDEVICE(INTEL, MID_PMU_MFLD_DRV_DEV_ID), 0},
++ {PCI_VDEVICE(INTEL, MID_PMU_CLV_DRV_DEV_ID), 0},
++ {PCI_VDEVICE(INTEL, MID_PMU_MRFL_DRV_DEV_ID), 0},
++ {}
++};
++
++MODULE_DEVICE_TABLE(pci, mid_pm_ids);
++
++char s0ix[5] = "s0ix";
++
++module_param_call(s0ix, set_extended_cstate_mode,
++ get_extended_cstate_mode, NULL, 0644);
++
++MODULE_PARM_DESC(s0ix,
++ "setup extended c state s0ix mode [s0i3|s0i1|lmp3|"
++ "i1i3|lpi1|lpi3|s0ix|none]");
++
++/**
++ * This function set all devices in d0i0 and deactivates pmu driver.
++ * The function is used before IFWI update as it needs devices to be
++ * in d0i0 during IFWI update. Reboot is needed to work pmu
++ * driver properly again. After calling this function and IFWI
++ * update, system is always rebooted as IFWI update function,
++ * intel_scu_ipc_medfw_upgrade() is called from mrst_emergency_reboot().
++ */
++int pmu_set_devices_in_d0i0(void)
++{
++ int status;
++ struct pmu_ss_states cur_pmssc;
++
++ /* Ignore request until we have initialized */
++ if (unlikely((!pmu_initialized)))
++ return 0;
++
++ cur_pmssc.pmu2_states[0] = D0I0_MASK;
++ cur_pmssc.pmu2_states[1] = D0I0_MASK;
++ cur_pmssc.pmu2_states[2] = D0I0_MASK;
++ cur_pmssc.pmu2_states[3] = D0I0_MASK;
++
++ /* Restrict platform Cx state to C6 */
++ pm_qos_update_request(mid_pmu_cxt->s3_restrict_qos,
++ (CSTATE_EXIT_LATENCY_S0i1-1));
++
++ down(&mid_pmu_cxt->scu_ready_sem);
++
++ mid_pmu_cxt->shutdown_started = true;
++
++ /* Issue the pmu command to PMU 2
++ * flag is needed to distinguish between
++ * S0ix vs interactive command in pmu_sc_irq()
++ */
++ status = pmu_issue_interactive_command(&cur_pmssc, false, false);
++
++ if (unlikely(status != PMU_SUCCESS)) { /* pmu command failed */
++ printk(KERN_CRIT "%s: Failed to Issue a PM command to PMU2\n",
++ __func__);
++ mid_pmu_cxt->shutdown_started = false;
++
++ /* allow s0ix now */
++ pm_qos_update_request(mid_pmu_cxt->s3_restrict_qos,
++ PM_QOS_DEFAULT_VALUE);
++ goto unlock;
++ }
++
++ if (_pmu2_wait_not_busy()) {
++ pmu_dump_logs();
++ BUG();
++ }
++
++unlock:
++ up(&mid_pmu_cxt->scu_ready_sem);
++ return status;
++}
++EXPORT_SYMBOL(pmu_set_devices_in_d0i0);
++
++static int _pmu_read_status(int type)
++{
++ u32 temp;
++ union pmu_pm_status result;
++
++ temp = readl(&mid_pmu_cxt->pmu_reg->pm_sts);
++
++ /* extract the busy bit */
++ result.pmu_status_value = temp;
++
++ if (type == PMU_BUSY_STATUS)
++ return result.pmu_status_parts.pmu_busy;
++ else if (type == PMU_MODE_ID)
++ return result.pmu_status_parts.mode_id;
++
++ return 0;
++}
++
++int _pmu2_wait_not_busy(void)
++{
++ int pmu_busy_retry = PMU2_BUSY_TIMEOUT;
++
++ /* wait 500ms that the latest pmu command finished */
++ do {
++ if (_pmu_read_status(PMU_BUSY_STATUS) == 0)
++ return 0;
++
++ udelay(1);
++ } while (--pmu_busy_retry);
++
++ WARN(1, "pmu2 busy!");
++
++ return -EBUSY;
++}
++
++static int _pmu2_wait_not_busy_yield(void)
++{
++ int pmu_busy_retry = PMU2_BUSY_TIMEOUT;
++
++ /* wait max 500ms that the latest pmu command finished */
++ do {
++ if (_pmu_read_status(PMU_BUSY_STATUS) == 0)
++ return 0;
++
++ usleep_range(10, 12);
++ pmu_busy_retry -= 11;
++ } while (pmu_busy_retry > 0);
++
++ WARN(1, "pmu2 busy!");
++
++ return -EBUSY;
++}
++
++static void pmu_write_subsys_config(struct pmu_ss_states *pm_ssc)
++{
++ /* South complex in Penwell has multiple registers for
++ * PM_SSC, etc.
++ */
++ writel(pm_ssc->pmu2_states[0], &mid_pmu_cxt->pmu_reg->pm_ssc[0]);
++ writel(pm_ssc->pmu2_states[1], &mid_pmu_cxt->pmu_reg->pm_ssc[1]);
++ writel(pm_ssc->pmu2_states[2], &mid_pmu_cxt->pmu_reg->pm_ssc[2]);
++ writel(pm_ssc->pmu2_states[3], &mid_pmu_cxt->pmu_reg->pm_ssc[3]);
++}
++
++void log_wakeup_irq(void)
++{
++ unsigned int irr = 0, vector = 0;
++ int offset = 0, irq = 0;
++ struct irq_desc *desc;
++ const char *act_name;
++
++ if ((mid_pmu_cxt->pmu_current_state != SYS_STATE_S3)
++ || !mid_pmu_cxt->suspend_started)
++ return;
++
++ for (offset = (FIRST_EXTERNAL_VECTOR/32);
++ offset < (NR_VECTORS/32); offset++) {
++ irr = apic_read(APIC_IRR + (offset * 0x10));
++ while (irr) {
++ vector = __ffs(irr);
++ irr &= ~(1 << vector);
++ irq = __this_cpu_read(
++ vector_irq[vector + (offset * 32)]);
++ if (irq < 0)
++ continue;
++ pr_info("wakeup from IRQ %d\n", irq);
++
++ desc = irq_to_desc(irq);
++
++ if ((desc) && (desc->action)) {
++ act_name = desc->action->name;
++ pr_info("IRQ %d,action name:%s\n",
++ irq,
++ (act_name) ? (act_name) : "no action");
++ }
++ }
++ }
++ return;
++}
++
++static inline int pmu_interrupt_pending(void)
++{
++ u32 temp;
++ union pmu_pm_ics result;
++
++ /* read the pm interrupt status register */
++ temp = readl(&mid_pmu_cxt->pmu_reg->pm_ics);
++ result.pmu_pm_ics_value = temp;
++
++ /* return the pm interrupt status int pending bit info */
++ return result.pmu_pm_ics_parts.int_pend;
++}
++
++static inline void pmu_clear_pending_interrupt(void)
++{
++ u32 temp;
++
++ /* read the pm interrupt status register */
++ temp = readl(&mid_pmu_cxt->pmu_reg->pm_ics);
++
++ /* write into the PM_ICS register */
++ writel(temp, &mid_pmu_cxt->pmu_reg->pm_ics);
++}
++
++void pmu_set_interrupt_enable(void)
++{
++ u32 temp;
++ union pmu_pm_ics result;
++
++ /* read the pm interrupt status register */
++ temp = readl(&mid_pmu_cxt->pmu_reg->pm_ics);
++ result.pmu_pm_ics_value = temp;
++
++ /* Set the interrupt enable bit */
++ result.pmu_pm_ics_parts.int_enable = 1;
++
++ temp = result.pmu_pm_ics_value;
++
++ /* write into the PM_ICS register */
++ writel(temp, &mid_pmu_cxt->pmu_reg->pm_ics);
++}
++
++void pmu_clear_interrupt_enable(void)
++{
++ u32 temp;
++ union pmu_pm_ics result;
++
++ /* read the pm interrupt status register */
++ temp = readl(&mid_pmu_cxt->pmu_reg->pm_ics);
++ result.pmu_pm_ics_value = temp;
++
++ /* Clear the interrupt enable bit */
++ result.pmu_pm_ics_parts.int_enable = 0;
++
++ temp = result.pmu_pm_ics_value;
++
++ /* write into the PM_ICS register */
++ writel(temp, &mid_pmu_cxt->pmu_reg->pm_ics);
++}
++
++static inline int pmu_read_interrupt_status(void)
++{
++ u32 temp;
++ union pmu_pm_ics result;
++
++ /* read the pm interrupt status register */
++ temp = readl(&mid_pmu_cxt->pmu_reg->pm_ics);
++
++ result.pmu_pm_ics_value = temp;
++
++ if (result.pmu_pm_ics_parts.int_status == 0)
++ return PMU_FAILED;
++
++ /* return the pm interrupt status int pending bit info */
++ return result.pmu_pm_ics_parts.int_status;
++}
++
++/*This function is used for programming the wake capable devices*/
++static void pmu_prepare_wake(int s0ix_state)
++{
++
++ struct pmu_ss_states cur_pmsss;
++
++ /* setup the wake capable devices */
++ if (s0ix_state == MID_S3_STATE) {
++ writel(~IGNORE_S3_WKC0, &mid_pmu_cxt->pmu_reg->pm_wkc[0]);
++ writel(~IGNORE_S3_WKC1, &mid_pmu_cxt->pmu_reg->pm_wkc[1]);
++ }
++
++ if (platform_is(INTEL_ATOM_MFLD) || platform_is(INTEL_ATOM_CLV)) {
++
++ /* Re-program the sub systems state on wakeup as
++ * the current SSS
++ */
++ pmu_read_sss(&cur_pmsss);
++
++ writel(cur_pmsss.pmu2_states[0],
++ &mid_pmu_cxt->pmu_reg->pm_wssc[0]);
++ writel(cur_pmsss.pmu2_states[1],
++ &mid_pmu_cxt->pmu_reg->pm_wssc[1]);
++ writel(cur_pmsss.pmu2_states[2],
++ &mid_pmu_cxt->pmu_reg->pm_wssc[2]);
++ writel(cur_pmsss.pmu2_states[3],
++ &mid_pmu_cxt->pmu_reg->pm_wssc[3]);
++ }
++}
++
++int mid_s0ix_enter(int s0ix_state)
++{
++ int ret = 0;
++
++ if (unlikely(!pmu_ops || !pmu_ops->enter))
++ goto ret;
++
++ /* check if we can acquire scu_ready_sem
++ * if we are not able to then do a c6 */
++ if (down_trylock(&mid_pmu_cxt->scu_ready_sem))
++ goto ret;
++
++ /* If PMU is busy, we'll retry on next C6 */
++ if (unlikely(_pmu_read_status(PMU_BUSY_STATUS))) {
++ up(&mid_pmu_cxt->scu_ready_sem);
++ pr_debug("mid_pmu_cxt->scu_read_sem is up\n");
++ goto ret;
++ }
++
++ pmu_prepare_wake(s0ix_state);
++
++ /* no need to proceed if schedule pending */
++ if (unlikely(need_resched())) {
++ pmu_stat_clear();
++ /*set wkc to appropriate value suitable for s0ix*/
++ writel(mid_pmu_cxt->ss_config->wake_state.wake_enable[0],
++ &mid_pmu_cxt->pmu_reg->pm_wkc[0]);
++ writel(mid_pmu_cxt->ss_config->wake_state.wake_enable[1],
++ &mid_pmu_cxt->pmu_reg->pm_wkc[1]);
++ up(&mid_pmu_cxt->scu_ready_sem);
++ goto ret;
++ }
++
++ /* entry function for pmu driver ops */
++ if (pmu_ops->enter(s0ix_state))
++ ret = s0ix_state;
++ else {
++ /*set wkc to appropriate value suitable for s0ix*/
++ writel(mid_pmu_cxt->ss_config->wake_state.wake_enable[0],
++ &mid_pmu_cxt->pmu_reg->pm_wkc[0]);
++ writel(mid_pmu_cxt->ss_config->wake_state.wake_enable[1],
++ &mid_pmu_cxt->pmu_reg->pm_wkc[1]);
++ }
++
++ret:
++ return ret;
++}
++
++/**
++ * pmu_sc_irq - pmu driver interrupt handler
++ * Context: interrupt context
++ */
++static irqreturn_t pmu_sc_irq(int irq, void *ignored)
++{
++ int status;
++ irqreturn_t ret = IRQ_NONE;
++ int wake_source;
++
++ /* check if interrup pending bit is set, if not ignore interrupt */
++ if (unlikely(!pmu_interrupt_pending())) {
++ goto ret_no_clear;
++ }
++
++ /* read the interrupt status */
++ status = pmu_read_interrupt_status();
++ if (unlikely(status == PMU_FAILED))
++ dev_dbg(&mid_pmu_cxt->pmu_dev->dev, "Invalid interrupt source\n");
++
++ switch (status) {
++ case INVALID_INT:
++ goto ret_no_clear;
++
++ case CMD_COMPLETE_INT:
++ break;
++
++ case CMD_ERROR_INT:
++ mid_pmu_cxt->cmd_error_int++;
++ break;
++
++ case SUBSYS_POW_ERR_INT:
++ case NO_ACKC6_INT:
++ case S0ix_MISS_INT:
++ pmu_stat_error(status);
++ break;
++
++ case WAKE_RECEIVED_INT:
++ wake_source = pmu_get_wake_source();
++ trace_printk("wake_from_lss%d\n",
++ wake_source);
++ pmu_stat_end();
++ break;
++ case TRIGGERERR:
++ pmu_dump_logs();
++ WARN(1, "%s: TRIGGERERR caused, but proceeding...\n", __func__);
++ break;
++ }
++
++ pmu_stat_clear();
++
++ /* clear the interrupt pending bit */
++ pmu_clear_pending_interrupt();
++
++ if (pmu_ops->wakeup)
++ pmu_ops->wakeup();
++
++ if (platform_is(INTEL_ATOM_MFLD) ||
++ platform_is(INTEL_ATOM_CLV)) {
++ mid_pmu_cxt->s0ix_entered = 0;
++ /* S0ix case release it */
++ up(&mid_pmu_cxt->scu_ready_sem);
++ }
++
++ ret = IRQ_HANDLED;
++ret_no_clear:
++ /* clear interrupt enable bit */
++ pmu_clear_interrupt_enable();
++
++ return ret;
++}
++
++void pmu_set_s0ix_complete(void)
++{
++ if (pmu_ops->set_s0ix_complete)
++ pmu_ops->set_s0ix_complete();
++}
++EXPORT_SYMBOL(pmu_set_s0ix_complete);
++
++bool pmu_is_s0ix_in_progress(void)
++{
++ bool state = false;
++
++ if (pmu_initialized && mid_pmu_cxt->s0ix_entered)
++ state = true;
++
++ return state;
++}
++EXPORT_SYMBOL(pmu_is_s0ix_in_progress);
++
++static inline u32 find_index_in_hash(struct pci_dev *pdev, int *found)
++{
++ u32 h_index;
++ int i;
++
++ /* assuming pdev is not null */
++ WARN_ON(pdev == NULL);
++
++ /*assuming pdev pionter will not change from platfrom
++ *boot to shutdown*/
++ h_index = jhash_1word((u32) (long) pdev,
++ MID_PCI_INDEX_HASH_INITVALUE) & MID_PCI_INDEX_HASH_MASK;
++
++ /* assume not found */
++ *found = 0;
++
++ for (i = 0; i < MID_PCI_INDEX_HASH_SIZE; i++) {
++ if (likely(mid_pmu_cxt->pci_dev_hash[h_index].pdev == pdev)) {
++ *found = 1;
++ break;
++ }
++
++ /* assume no deletions, hence there shouldn't be any
++ * gaps ie., NULL's */
++ if (unlikely(mid_pmu_cxt->pci_dev_hash[h_index].pdev == NULL)) {
++ /* found NULL, that means we wont have
++ * it in hash */
++ break;
++ }
++
++ h_index = (h_index+1)%MID_PCI_INDEX_HASH_SIZE;
++ }
++
++ /* Assume hash table wont be full */
++ WARN_ON(i == MID_PCI_INDEX_HASH_SIZE);
++
++ return h_index;
++}
++
++static bool is_display_subclass(unsigned int sub_class)
++{
++ /* On MDFLD and CLV, we have display PCI device class 0x30000,
++ * On MRFLD, we have display PCI device class 0x38000
++ */
++
++ if ((sub_class == 0x0 &&
++ (platform_is(INTEL_ATOM_MFLD) ||
++ platform_is(INTEL_ATOM_CLV))) ||
++ (sub_class == 0x80 && platform_is(INTEL_ATOM_MRFLD)))
++ return true;
++
++ return false;
++}
++
++static int get_pci_to_pmu_index(struct pci_dev *pdev)
++{
++ int pm, type;
++ unsigned int base_class;
++ unsigned int sub_class;
++ u8 ss;
++ int index = PMU_FAILED;
++ u32 h_index;
++ int found;
++
++ h_index = find_index_in_hash(pdev, &found);
++
++ if (found)
++ return (int)mid_pmu_cxt->pci_dev_hash[h_index].index;
++
++ /* if not found, h_index would be where
++ * we can insert this */
++
++ base_class = pdev->class >> 16;
++ sub_class = (pdev->class & SUB_CLASS_MASK) >> 8;
++ pm = pci_find_capability(pdev, PCI_CAP_ID_VNDR);
++
++ /* read the logical sub system id & cap if present */
++ pci_read_config_byte(pdev, pm + 4, &ss);
++
++ type = ss & LOG_SS_MASK;
++ ss = ss & LOG_ID_MASK;
++
++ if ((base_class == PCI_BASE_CLASS_DISPLAY) &&
++ is_display_subclass(sub_class))
++ index = 1;
++ else if ((base_class == PCI_BASE_CLASS_MULTIMEDIA) &&
++ (sub_class == ISP_SUB_CLASS))
++ index = ISP_POS;
++ else if (type) {
++ WARN_ON(ss >= MAX_LSS_POSSIBLE);
++ index = mid_pmu_cxt->pmu1_max_devs + ss;
++ }
++
++ if (index != PMU_FAILED) {
++ /* insert into hash table */
++ mid_pmu_cxt->pci_dev_hash[h_index].pdev = pdev;
++
++ /* assume index never exceeds 0xff */
++ WARN_ON(index > 0xFF);
++
++ mid_pmu_cxt->pci_dev_hash[h_index].index = (u8)index;
++
++ if (index < mid_pmu_cxt->pmu1_max_devs) {
++ set_mid_pci_ss_idx(index, 0);
++ set_mid_pci_ss_pos(index, (u8)index);
++ set_mid_pci_pmu_num(index, PMU_NUM_1);
++ } else if (index >= mid_pmu_cxt->pmu1_max_devs &&
++ index < (mid_pmu_cxt->pmu1_max_devs +
++ mid_pmu_cxt->pmu2_max_devs)) {
++ set_mid_pci_ss_idx(index,
++ (u8)(ss / mid_pmu_cxt->ss_per_reg));
++ set_mid_pci_ss_pos(index,
++ (u8)(ss % mid_pmu_cxt->ss_per_reg));
++ set_mid_pci_pmu_num(index, PMU_NUM_2);
++ } else {
++ index = PMU_FAILED;
++ }
++
++ WARN_ON(index == PMU_FAILED);
++ }
++
++ return index;
++}
++
++static void get_pci_lss_info(struct pci_dev *pdev)
++{
++ int index, pm;
++ unsigned int base_class;
++ unsigned int sub_class;
++ u8 ss, cap;
++ int i;
++ base_class = pdev->class >> 16;
++ sub_class = (pdev->class & SUB_CLASS_MASK) >> 8;
++
++ pm = pci_find_capability(pdev, PCI_CAP_ID_VNDR);
++
++ /* read the logical sub system id & cap if present */
++ pci_read_config_byte(pdev, pm + 4, &ss);
++ pci_read_config_byte(pdev, pm + 5, &cap);
++
++ /* get the index for the copying of ss info */
++ index = get_pci_to_pmu_index(pdev);
++
++ if ((index == PMU_FAILED) || (index >= MAX_DEVICES))
++ return;
++
++ /* initialize gfx subsystem info */
++ if ((base_class == PCI_BASE_CLASS_DISPLAY) &&
++ is_display_subclass(sub_class)) {
++ set_mid_pci_log_id(index, (u32)index);
++ set_mid_pci_cap(index, PM_SUPPORT);
++ } else if ((base_class == PCI_BASE_CLASS_MULTIMEDIA) &&
++ (sub_class == ISP_SUB_CLASS)) {
++ set_mid_pci_log_id(index, (u32)index);
++ set_mid_pci_cap(index, PM_SUPPORT);
++ } else if (ss && cap) {
++ set_mid_pci_log_id(index, (u32)(ss & LOG_ID_MASK));
++ set_mid_pci_cap(index, cap);
++ }
++
++ for (i = 0; i < PMU_MAX_LSS_SHARE &&
++ get_mid_pci_drv(index, i); i++) {
++ /* do nothing */
++ }
++
++ WARN_ON(i >= PMU_MAX_LSS_SHARE);
++
++ if (i < PMU_MAX_LSS_SHARE) {
++ set_mid_pci_drv(index, i, pdev);
++ set_mid_pci_power_state(index, i, PCI_D3hot);
++ }
++}
++
++static void pmu_enumerate(void)
++{
++ struct pci_dev *pdev = NULL;
++ unsigned int base_class;
++
++ for_each_pci_dev(pdev) {
++ if (platform_is(INTEL_ATOM_MRFLD) &&
++ pdev->device == MID_MRFL_HDMI_DRV_DEV_ID)
++ continue;
++
++ /* find the base class info */
++ base_class = pdev->class >> 16;
++
++ if (base_class == PCI_BASE_CLASS_BRIDGE)
++ continue;
++
++ get_pci_lss_info(pdev);
++ }
++}
++
++void pmu_read_sss(struct pmu_ss_states *pm_ssc)
++{
++ pm_ssc->pmu2_states[0] =
++ readl(&mid_pmu_cxt->pmu_reg->pm_sss[0]);
++ pm_ssc->pmu2_states[1] =
++ readl(&mid_pmu_cxt->pmu_reg->pm_sss[1]);
++ pm_ssc->pmu2_states[2] =
++ readl(&mid_pmu_cxt->pmu_reg->pm_sss[2]);
++ pm_ssc->pmu2_states[3] =
++ readl(&mid_pmu_cxt->pmu_reg->pm_sss[3]);
++}
++
++
++/*
++ * For all devices in this lss, we check what is the weakest power state
++ *
++ * Thus we dont power down if another device needs more power
++ */
++
++static pci_power_t pmu_pci_get_weakest_state_for_lss(int lss_index,
++ struct pci_dev *pdev, pci_power_t state)
++{
++ int i;
++ pci_power_t weakest = state;
++
++ for (i = 0; i < PMU_MAX_LSS_SHARE; i++) {
++ if (get_mid_pci_drv(lss_index, i) == pdev)
++ set_mid_pci_power_state(lss_index, i, state);
++
++ if (get_mid_pci_drv(lss_index, i) &&
++ (get_mid_pci_power_state(lss_index, i) < weakest))
++ weakest = get_mid_pci_power_state(lss_index, i);
++ }
++ return weakest;
++}
++
++int pmu_pci_to_indexes(struct pci_dev *pdev, int *index,
++ int *pmu_num, int *ss_idx, int *ss_pos)
++{
++ int i;
++
++ i = get_pci_to_pmu_index(pdev);
++ if (i == PMU_FAILED)
++ return PMU_FAILED;
++
++ *index = i;
++ *ss_pos = get_mid_pci_ss_pos(i);
++ *ss_idx = get_mid_pci_ss_idx(i);
++ *pmu_num = get_mid_pci_pmu_num(i);
++
++ return PMU_SUCCESS;
++}
++
++static bool update_nc_device_states(int i, pci_power_t state)
++{
++ int status = 0;
++ int islands = 0;
++ int reg;
++
++ /* store the display status */
++ if (i == GFX_LSS_INDEX) {
++ mid_pmu_cxt->display_off = (state != PCI_D0);
++ return true;
++ }
++
++ /*Update the Camera status per ISP Driver Suspended/Resumed
++ * ISP power islands are also updated accordingly, otherwise Dx state
++ * in PMCSR refuses to change.
++ */
++ else if (i == ISP_POS) {
++ if (platform_is(INTEL_ATOM_MFLD) ||
++ platform_is(INTEL_ATOM_CLV)) {
++ islands = APM_ISP_ISLAND | APM_IPH_ISLAND;
++ reg = APM_REG_TYPE;
++ } else if (platform_is(INTEL_ATOM_MRFLD)) {
++ islands = TNG_ISP_ISLAND;
++ reg = ISP_SS_PM0;
++ } else
++ return false;
++ status = pmu_nc_set_power_state(islands,
++ (state != PCI_D0) ?
++ OSPM_ISLAND_DOWN : OSPM_ISLAND_UP,
++ reg);
++ if (status)
++ return false;
++ mid_pmu_cxt->camera_off = (state != PCI_D0);
++ return true;
++ }
++
++ return false;
++}
++
++void init_nc_device_states(void)
++{
++#if !IS_ENABLED(CONFIG_VIDEO_ATOMISP)
++ mid_pmu_cxt->camera_off = true;
++#endif
++
++#ifndef GFX_ENABLE
++ /* If Gfx is disabled
++ * assume s0ix is not blocked
++ * from gfx side
++ */
++ mid_pmu_cxt->display_off = true;
++#endif
++
++ return;
++}
++
++/* FIXME::Currently HSI Modem 7060 (BZ# 28529) is having a issue and
++* it will not go to Low Power State on CVT. So Standby will not work
++* if HSI is enabled.
++* We can choose between Standby/HSI based on enable_stadby 1/0.
++*/
++unsigned int enable_standby __read_mostly;
++module_param(enable_standby, uint, 0000);
++
++/* FIXME:: We have issues with S0ix/S3 enabling by default
++ * with display lockup, HSIC etc., so have a boot time option
++ * to enable S0ix/S3
++ */
++unsigned int enable_s3 __read_mostly = 1;
++int set_enable_s3(const char *val, struct kernel_param *kp)
++{
++ int rv = param_set_int(val, kp);
++ if (rv)
++ return rv;
++
++ if (unlikely((!pmu_initialized)))
++ return 0;
++
++ if (platform_is(INTEL_ATOM_MRFLD)) {
++ if (!enable_s3)
++ __pm_stay_awake(mid_pmu_cxt->pmu_wake_lock);
++ else
++ __pm_relax(mid_pmu_cxt->pmu_wake_lock);
++ }
++
++ return 0;
++}
++module_param_call(enable_s3, set_enable_s3, param_get_uint,
++ &enable_s3, S_IRUGO | S_IWUSR);
++
++/* FIXME:: We have issues with S0ix/S3 enabling by default
++ * with display lockup, HSIC etc., so have a boot time option
++ * to enable S0ix/S3
++ */
++unsigned int enable_s0ix __read_mostly = 1;
++int set_enable_s0ix(const char *val, struct kernel_param *kp)
++{
++ int rv = param_set_int(val, kp);
++ if (rv)
++ return rv;
++
++ if (unlikely((!pmu_initialized)))
++ return 0;
++
++ if (platform_is(INTEL_ATOM_MRFLD)) {
++ if (!enable_s0ix) {
++ mid_pmu_cxt->cstate_ignore =
++ ~((1 << CPUIDLE_STATE_MAX) - 1);
++
++ /* Ignore C2, C3, C5 states */
++ mid_pmu_cxt->cstate_ignore |= (1 << 1);
++ mid_pmu_cxt->cstate_ignore |= (1 << 2);
++ mid_pmu_cxt->cstate_ignore |= (1 << 4);
++
++ /* For now ignore C7, C8, C9, C10 states */
++ mid_pmu_cxt->cstate_ignore |= (1 << 6);
++ mid_pmu_cxt->cstate_ignore |= (1 << 7);
++ mid_pmu_cxt->cstate_ignore |= (1 << 8);
++ mid_pmu_cxt->cstate_ignore |= (1 << 9);
++
++ /* Restrict platform Cx state to C6 */
++ pm_qos_update_request(mid_pmu_cxt->cstate_qos,
++ (CSTATE_EXIT_LATENCY_S0i1-1));
++ } else {
++ mid_pmu_cxt->cstate_ignore =
++ ~((1 << CPUIDLE_STATE_MAX) - 1);
++
++ /* Ignore C2, C3, C5, C8 and C10 states */
++ mid_pmu_cxt->cstate_ignore |= (1 << 1);
++ mid_pmu_cxt->cstate_ignore |= (1 << 2);
++ mid_pmu_cxt->cstate_ignore |= (1 << 4);
++ mid_pmu_cxt->cstate_ignore |= (1 << 7);
++ mid_pmu_cxt->cstate_ignore |= (1 << 9);
++
++ pm_qos_update_request(mid_pmu_cxt->cstate_qos,
++ PM_QOS_DEFAULT_VALUE);
++ }
++ }
++
++ return 0;
++}
++module_param_call(enable_s0ix, set_enable_s0ix, param_get_uint,
++ &enable_s0ix, S_IRUGO | S_IWUSR);
++
++unsigned int pmu_ignore_lss0 __read_mostly = IGNORE_SSS0;
++module_param(pmu_ignore_lss0, uint, S_IRUGO | S_IWUSR);
++
++unsigned int pmu_ignore_lss1 __read_mostly = IGNORE_SSS1;
++module_param(pmu_ignore_lss1, uint, S_IRUGO | S_IWUSR);
++
++unsigned int pmu_ignore_lss2 __read_mostly = IGNORE_SSS2;
++module_param(pmu_ignore_lss2, uint, S_IRUGO | S_IWUSR);
++
++unsigned int pmu_ignore_lss3 __read_mostly = IGNORE_SSS3;
++module_param(pmu_ignore_lss3, uint, S_IRUGO | S_IWUSR);
++
++int pmu_set_emmc_to_d0i0_atomic(void)
++{
++ u32 pm_cmd_val;
++ u32 new_value;
++ int sub_sys_pos, sub_sys_index;
++ struct pmu_ss_states cur_pmssc;
++ int status = 0;
++
++ if (unlikely((!pmu_initialized)))
++ return 0;
++
++ /* LSS 01 is index = 0, pos = 1 */
++ sub_sys_index = EMMC0_LSS / mid_pmu_cxt->ss_per_reg;
++ sub_sys_pos = EMMC0_LSS % mid_pmu_cxt->ss_per_reg;
++
++ memset(&cur_pmssc, 0, sizeof(cur_pmssc));
++
++ /*
++ * Give time for possible previous PMU operation to finish in
++ * case where SCU is functioning normally. For SCU crashed case
++ * PMU may stay busy but check if the emmc is accessible.
++ */
++ status = _pmu2_wait_not_busy();
++ if (status) {
++ dev_err(&mid_pmu_cxt->pmu_dev->dev,
++ "PMU2 busy, ignoring as emmc might be already d0i0\n");
++ status = 0;
++ }
++
++ pmu_read_sss(&cur_pmssc);
++
++ /* set D0i0 the LSS bits */
++ pm_cmd_val =
++ (D0I3_MASK << (sub_sys_pos * BITS_PER_LSS));
++ new_value = cur_pmssc.pmu2_states[sub_sys_index] &
++ (~pm_cmd_val);
++ if (new_value == cur_pmssc.pmu2_states[sub_sys_index])
++ goto err;
++
++ status = _pmu2_wait_not_busy();
++ if (status)
++ goto err;
++
++ cur_pmssc.pmu2_states[sub_sys_index] = new_value;
++
++ /* Request SCU for PM interrupt enabling */
++ writel(PMU_PANIC_EMMC_UP_REQ_CMD, mid_pmu_cxt->emergeny_emmc_up_addr);
++
++ status = pmu_issue_interactive_command(&cur_pmssc, false, false);
++
++ if (unlikely(status != PMU_SUCCESS)) {
++ dev_dbg(&mid_pmu_cxt->pmu_dev->dev,
++ "Failed to Issue a PM command to PMU2\n");
++ goto err;
++
++ }
++
++ /*
++ * Wait for interactive command to complete.
++ * If we dont wait, there is a possibility that
++ * the driver may access the device before its
++ * powered on in SCU.
++ *
++ */
++ if (_pmu2_wait_not_busy()) {
++ pmu_dump_logs();
++ BUG();
++ }
++
++err:
++
++ return status;
++}
++
++
++#define SAVED_HISTORY_ADDRESS_NUM 10
++#define SAVED_HISTORY_NUM 20
++#define PCI_MAX_RECORD_NUM 10
++
++struct saved_nc_power_history {
++ unsigned long long ts;
++ unsigned short pci;
++ unsigned short cpu:4;
++ unsigned short state_type:8;
++ unsigned short real_change:2;
++ int reg_type;
++ int islands;
++ void *address[SAVED_HISTORY_ADDRESS_NUM];
++};
++
++static atomic_t saved_nc_power_history_current = ATOMIC_INIT(-1);
++static struct saved_nc_power_history all_history[SAVED_HISTORY_NUM];
++static struct saved_nc_power_history *get_new_record_history(void)
++{
++ unsigned int ret =
++ atomic_add_return(1, &saved_nc_power_history_current);
++ return &all_history[ret%SAVED_HISTORY_NUM];
++}
++
++static unsigned short pci_need_record[PCI_MAX_RECORD_NUM] = { 0x08c8, 0x0130, };
++static int num_pci_need_record = 2;
++module_param_array(pci_need_record, ushort, &num_pci_need_record, 0644);
++MODULE_PARM_DESC(pci_need_record,
++ "devices need be traced power state transition.");
++
++static bool pci_need_record_power_state(struct pci_dev *pdev)
++{
++ int i;
++ for (i = 0; i < num_pci_need_record; i++)
++ if (pdev->device == pci_need_record[i])
++ return true;
++
++ return false;
++}
++
++static void print_saved_record(struct saved_nc_power_history *record)
++{
++ int i;
++ unsigned long long ts = record->ts;
++ unsigned long nanosec_rem = do_div(ts, 1000000000);
++
++ printk(KERN_INFO "----\n");
++ printk(KERN_INFO "ts[%5lu.%06lu] cpu[%d] is pci[%04x] reg_type[%d] "
++ "state_type[%d] islands[%x] real_change[%d]\n",
++ (unsigned long)ts,
++ nanosec_rem / 1000,
++ record->cpu,
++ record->pci,
++ record->reg_type,
++ record->state_type,
++ record->islands,
++ record->real_change);
++ for (i = 0; i < SAVED_HISTORY_ADDRESS_NUM; i++) {
++ printk(KERN_INFO "%pf real_addr[%p]\n",
++ record->address[i],
++ record->address[i]);
++ }
++}
++
++int verify_stack_ok(unsigned int *good_ebp, unsigned int *_ebp)
++{
++ return ((unsigned int)_ebp & 0xffffe000) ==
++ ((unsigned int)good_ebp & 0xffffe000);
++}
++
++size_t backtrace_safe(void **array, size_t max_size)
++{
++ unsigned int *_ebp, *base_ebp;
++ unsigned int *caller;
++ unsigned int i;
++
++ asm ("movl %%ebp, %0"
++ : "=r" (_ebp)
++ );
++
++ base_ebp = _ebp;
++ caller = (unsigned int *) *(_ebp+1);
++
++ for (i = 0; i < max_size; i++)
++ array[i] = 0;
++ for (i = 0; i < max_size; i++) {
++ array[i] = caller;
++ _ebp = (unsigned int *) *_ebp;
++ if (!verify_stack_ok(base_ebp, _ebp))
++ break;
++ caller = (unsigned int *) *(_ebp+1);
++ }
++
++ return i + 1;
++}
++
++void dump_nc_power_history(void)
++{
++ int i, start;
++ unsigned int total = atomic_read(&saved_nc_power_history_current);
++
++ start = total % SAVED_HISTORY_NUM;
++ printk(KERN_INFO "<----current timestamp\n");
++ printk(KERN_INFO "start[%d] saved[%d]\n",
++ start, total);
++ for (i = start; i >= 0; i--)
++ print_saved_record(&all_history[i]);
++ for (i = SAVED_HISTORY_NUM - 1; i > start; i--)
++ print_saved_record(&all_history[i]);
++}
++EXPORT_SYMBOL(dump_nc_power_history);
++
++static ssize_t debug_read_history(struct file *file, char __user *buffer,
++ size_t count, loff_t *pos)
++{
++ dump_nc_power_history();
++
++ return 0;
++}
++
++static ssize_t debug_write_read_history_entry(struct file *file,
++ const char __user *buffer, size_t count, loff_t *pos)
++{
++ char buf[20] = "0";
++ unsigned long len = min(sizeof(buf) - 1, count);
++ u32 islands;
++ u32 on;
++ int ret;
++
++ /*do nothing if platform is nether medfield or clv*/
++ if (!platform_is(INTEL_ATOM_MFLD) && !platform_is(INTEL_ATOM_CLV))
++ return count;
++
++ if (copy_from_user(buf, buffer, len))
++ return -1;
++
++ buf[len] = 0;
++
++ ret = sscanf(buf, "%x%x", &islands, &on);
++ if (ret == 2)
++ pmu_nc_set_power_state(islands, on, OSPM_REG_TYPE);
++
++ return count;
++}
++
++static const struct file_operations proc_debug_operations = {
++ .owner = THIS_MODULE,
++ .read = debug_read_history,
++ .write = debug_write_read_history_entry,
++};
++
++static int __init debug_read_history_entry(void)
++{
++ struct proc_dir_entry *res = NULL;
++
++ res = proc_create("debug_read_history", S_IRUGO | S_IWUSR, NULL,
++ &proc_debug_operations);
++
++ if (!res)
++ return -ENOMEM;
++
++ return 0;
++}
++device_initcall(debug_read_history_entry);
++
++/**
++ * pmu_nc_set_power_state - Callback function is used by all the devices
++ * in north complex for a platform specific device power on/shutdown.
++ * Following assumptions are made by this function
++ *
++ * Every new request starts from scratch with no assumptions
++ * on previous/pending request to Punit.
++ * Caller is responsible to retry if request fails.
++ * Avoids multiple requests to Punit if target state is
++ * already in the expected state.
++ * spin_locks guarantee serialized access to these registers
++ * and avoid concurrent access from 2d/3d, VED, VEC, ISP & IPH.
++ *
++ */
++int pmu_nc_set_power_state(int islands, int state_type, int reg)
++{
++ unsigned long flags;
++ struct saved_nc_power_history *record = NULL;
++ int ret = 0;
++ int change;
++
++ spin_lock_irqsave(&mid_pmu_cxt->nc_ready_lock, flags);
++
++ record = get_new_record_history();
++ record->cpu = raw_smp_processor_id();
++ record->ts = cpu_clock(record->cpu);
++ record->islands = islands;
++ record->pci = 0;
++ record->state_type = state_type;
++ backtrace_safe(record->address, SAVED_HISTORY_ADDRESS_NUM);
++ record->real_change = 0;
++ record->reg_type = reg;
++
++ if (pmu_ops->nc_set_power_state) {
++ ret = pmu_ops->nc_set_power_state(islands, state_type,
++ reg, &change);
++ if (change) {
++ record->real_change = 1;
++ record->ts = cpu_clock(record->cpu);
++ }
++ }
++
++ spin_unlock_irqrestore(&mid_pmu_cxt->nc_ready_lock, flags);
++ return ret;
++}
++EXPORT_SYMBOL(pmu_nc_set_power_state);
++
++/**
++ * pmu_nc_get_power_state - Callback function is used to
++ * query power status of all the devices in north complex.
++ * Following assumptions are made by this function
++ *
++ * Every new request starts from scratch with no assumptions
++ * on previous/pending request to Punit.
++ * Caller is responsible to retry if request fails.
++ * Avoids multiple requests to Punit if target state is
++ * already in the expected state.
++ * spin_locks guarantee serialized access to these registers
++ * and avoid concurrent access from 2d/3d, VED, VEC, ISP & IPH.
++ *
++ */
++int pmu_nc_get_power_state(int island, int reg_type)
++{
++ u32 pwr_sts;
++ unsigned long flags;
++ int i, lss;
++ int ret = -EINVAL;
++
++ /*do nothing if platform is nether medfield or clv*/
++ if (!platform_is(INTEL_ATOM_MFLD) && !platform_is(INTEL_ATOM_CLV))
++ return 0;
++
++ spin_lock_irqsave(&mid_pmu_cxt->nc_ready_lock, flags);
++
++ switch (reg_type) {
++ case APM_REG_TYPE:
++ pwr_sts = inl(mid_pmu_cxt->apm_base + APM_STS);
++ break;
++ case OSPM_REG_TYPE:
++ pwr_sts = inl(mid_pmu_cxt->ospm_base + OSPM_PM_SSS);
++ break;
++ default:
++ pr_err("%s: invalid argument 'island': %d.\n",
++ __func__, island);
++ goto unlock;
++ }
++
++ for (i = 0; i < OSPM_MAX_POWER_ISLANDS; i++) {
++ lss = island & (0x1 << i);
++ if (lss) {
++ ret = (pwr_sts >> (2 * i)) & 0x3;
++ break;
++ }
++ }
++
++unlock:
++ spin_unlock_irqrestore(&mid_pmu_cxt->nc_ready_lock, flags);
++ return ret;
++}
++EXPORT_SYMBOL(pmu_nc_get_power_state);
++
++/*
++* update_dev_res - Calulates & Updates the device residency when
++* a device state change occurs.
++* Computation of respective device residency starts when
++* its first state tranisition happens after the pmu driver
++* is initialised.
++*
++*/
++void update_dev_res(int index, pci_power_t state)
++{
++ if (state != PCI_D0) {
++ if (mid_pmu_cxt->pmu_dev_res[index].start == 0) {
++ mid_pmu_cxt->pmu_dev_res[index].start = cpu_clock(0);
++ mid_pmu_cxt->pmu_dev_res[index].d0i3_entry =
++ mid_pmu_cxt->pmu_dev_res[index].start;
++ mid_pmu_cxt->pmu_dev_res[index].d0i0_acc = 0;
++ } else{
++ mid_pmu_cxt->pmu_dev_res[index].d0i3_entry =
++ cpu_clock(0);
++ mid_pmu_cxt->pmu_dev_res[index].d0i0_acc +=
++ (mid_pmu_cxt->pmu_dev_res[index].d0i3_entry -
++ mid_pmu_cxt->pmu_dev_res[index].d0i0_entry);
++ }
++ } else {
++ if (mid_pmu_cxt->pmu_dev_res[index].start == 0) {
++ mid_pmu_cxt->pmu_dev_res[index].start =
++ cpu_clock(0);
++ mid_pmu_cxt->pmu_dev_res[index].d0i0_entry
++ = mid_pmu_cxt->pmu_dev_res[index].start;
++ mid_pmu_cxt->pmu_dev_res[index].d0i3_acc = 0;
++ } else {
++ mid_pmu_cxt->pmu_dev_res[index].d0i0_entry =
++ cpu_clock(0);
++ mid_pmu_cxt->pmu_dev_res[index].d0i3_acc +=
++ (mid_pmu_cxt->pmu_dev_res[index].d0i0_entry -
++ mid_pmu_cxt->pmu_dev_res[index].d0i3_entry);
++ }
++ }
++ mid_pmu_cxt->pmu_dev_res[index].state = state;
++}
++
++/**
++ * pmu_pci_set_power_state - Callback function is used by all the PCI devices
++ * for a platform specific device power on/shutdown.
++ *
++ */
++int __ref pmu_pci_set_power_state(struct pci_dev *pdev, pci_power_t state)
++{
++ u32 new_value;
++ int i = 0;
++ u32 pm_cmd_val, chk_val;
++ int sub_sys_pos, sub_sys_index;
++ int pmu_num;
++ struct pmu_ss_states cur_pmssc;
++ int status = 0;
++ int retry_times = 0;
++ ktime_t calltime, delta, rettime;
++ struct saved_nc_power_history *record = NULL;
++ bool d3_cold = false;
++
++ /* Ignore callback from devices until we have initialized */
++ if (unlikely((!pmu_initialized)))
++ return 0;
++
++ might_sleep();
++
++ /* Try to acquire the scu_ready_sem, if not
++ * get blocked, until pmu_sc_irq() releases */
++ down(&mid_pmu_cxt->scu_ready_sem);
++
++ /*get LSS index corresponding to pdev, its position in
++ *32 bit register and its register numer*/
++ status =
++ pmu_pci_to_indexes(pdev, &i, &pmu_num,
++ &sub_sys_index, &sub_sys_pos);
++
++ if (status)
++ goto unlock;
++
++ if (pci_need_record_power_state(pdev)) {
++ record = get_new_record_history();
++ record->cpu = raw_smp_processor_id();
++ record->ts = cpu_clock(record->cpu);
++ record->islands = 0;
++ record->reg_type = 0;
++ record->pci = pdev->device;
++ record->state_type = state;
++ backtrace_safe(record->address, SAVED_HISTORY_ADDRESS_NUM);
++ record->real_change = 0;
++ }
++
++ /* Ignore HDMI HPD driver d0ix on LSS 0 on MRFLD */
++ if (platform_is(INTEL_ATOM_MRFLD) &&
++ pdev->device == MID_MRFL_HDMI_DRV_DEV_ID)
++ goto unlock;
++
++ /*in case a LSS is assigned to more than one pdev, we need
++ *to find the shallowest state the LSS should be put into*/
++ state = pmu_pci_get_weakest_state_for_lss(i, pdev, state);
++
++ /*If the LSS corresponds to northcomplex device, update
++ *the status and return*/
++ if (update_nc_device_states(i, state)) {
++ if (mid_pmu_cxt->pmu_dev_res[i].state == state)
++ goto nc_done;
++ else {
++ if (i < MAX_DEVICES)
++ update_dev_res(i, state);
++ goto nc_done;
++ }
++ }
++
++ /* initialize the current pmssc states */
++ memset(&cur_pmssc, 0, sizeof(cur_pmssc));
++
++ status = _pmu2_wait_not_busy();
++
++ if (status)
++ goto unlock;
++
++ pmu_read_sss(&cur_pmssc);
++
++ /* Read the pm_cmd val & update the value */
++ pm_cmd_val =
++ (D0I3_MASK << (sub_sys_pos * BITS_PER_LSS));
++
++ /* First clear the LSS bits */
++ new_value = cur_pmssc.pmu2_states[sub_sys_index] &
++ (~pm_cmd_val);
++ mid_pmu_cxt->os_sss[sub_sys_index] &= ~pm_cmd_val;
++
++ if (state != PCI_D0) {
++ pm_cmd_val =
++ (pci_to_platform_state(state) <<
++ (sub_sys_pos * BITS_PER_LSS));
++
++ new_value |= pm_cmd_val;
++
++ mid_pmu_cxt->os_sss[sub_sys_index] |= pm_cmd_val;
++ }
++
++ new_value &= ~mid_pmu_cxt->ignore_lss[sub_sys_index];
++
++ /* nothing to do, so dont do it... */
++ if (new_value == cur_pmssc.pmu2_states[sub_sys_index])
++ goto unlock;
++
++ cur_pmssc.pmu2_states[sub_sys_index] = new_value;
++
++ /* Check if the state is D3_cold or D3_Hot in TNG platform*/
++ if (platform_is(INTEL_ATOM_MRFLD) && (state == PCI_D3cold))
++ d3_cold = true;
++
++ /* Issue the pmu command to PMU 2
++ * flag is needed to distinguish between
++ * S0ix vs interactive command in pmu_sc_irq()
++ */
++ status = pmu_issue_interactive_command(&cur_pmssc, false, d3_cold);
++
++ if (unlikely(status != PMU_SUCCESS)) {
++ dev_dbg(&mid_pmu_cxt->pmu_dev->dev,
++ "Failed to Issue a PM command to PMU2\n");
++ goto unlock;
++ }
++
++ calltime = ktime_get();
++retry:
++ /*
++ * Wait for interactive command to complete.
++ * If we dont wait, there is a possibility that
++ * the driver may access the device before its
++ * powered on in SCU.
++ *
++ */
++ status = _pmu2_wait_not_busy_yield();
++ if (unlikely(status)) {
++ rettime = ktime_get();
++ delta = ktime_sub(rettime, calltime);
++ retry_times++;
++
++ printk(KERN_CRIT "%s: D0ix transition failure: %04x %04X %s %20s:\n",
++ __func__,
++ pdev->vendor, pdev->device,
++ dev_name(&pdev->dev),
++ dev_driver_string(&pdev->dev));
++ printk(KERN_CRIT "interrupt pending = %d\n",
++ pmu_interrupt_pending());
++ printk(KERN_CRIT "pmu_busy_status = %d\n",
++ _pmu_read_status(PMU_BUSY_STATUS));
++ printk(KERN_CRIT "suspend_started = %d\n",
++ mid_pmu_cxt->suspend_started);
++ printk(KERN_CRIT "shutdown_started = %d\n",
++ mid_pmu_cxt->shutdown_started);
++ printk(KERN_CRIT "camera_off = %d display_off = %d\n",
++ mid_pmu_cxt->camera_off,
++ mid_pmu_cxt->display_off);
++ printk(KERN_CRIT "s0ix_possible = 0x%x\n",
++ mid_pmu_cxt->s0ix_possible);
++ printk(KERN_CRIT "s0ix_entered = 0x%x\n",
++ mid_pmu_cxt->s0ix_entered);
++ printk(KERN_CRIT "pmu_current_state = %d\n",
++ mid_pmu_cxt->pmu_current_state);
++ printk(KERN_CRIT "PMU is BUSY! retry_times[%d] total_delay[%lli]ms. Retry ...\n",
++ retry_times, (long long) ktime_to_ms(delta));
++ pmu_dump_logs();
++
++ trigger_all_cpu_backtrace();
++ if (retry_times < 60)
++ goto retry;
++ else
++ BUG();
++ }
++ if (record) {
++ record->real_change = 1;
++ record->ts = cpu_clock(record->cpu);
++ }
++
++ if (pmu_ops->set_power_state_ops)
++ pmu_ops->set_power_state_ops(state);
++
++ /* update stats */
++ inc_d0ix_stat((i-mid_pmu_cxt->pmu1_max_devs),
++ pci_to_platform_state(state));
++
++ /* check if tranisition to requested state has happened */
++ pmu_read_sss(&cur_pmssc);
++
++ chk_val = cur_pmssc.pmu2_states[sub_sys_index] &
++ (D0I3_MASK << (sub_sys_pos * BITS_PER_LSS));
++ new_value &= (D0I3_MASK << (sub_sys_pos * BITS_PER_LSS));
++
++ if ((chk_val == new_value) && (i < MAX_DEVICES))
++ update_dev_res(i, state);
++
++ WARN_ON(chk_val != new_value);
++
++nc_done:
++#if !IS_ENABLED(CONFIG_VIDEO_ATOMISP)
++ /* ATOMISP is always powered up on system-resume path. It needs
++ * to be turned off here if there is no driver to do it. */
++ if (!mid_pmu_cxt->camera_off) {
++ /* power down isp */
++ pmu_nc_set_power_state(APM_ISP_ISLAND | APM_IPH_ISLAND,
++ OSPM_ISLAND_DOWN, APM_REG_TYPE);
++ /* power down DPHY */
++ new_value = intel_mid_msgbus_read32(0x09, 0x03);
++ new_value |= 0x300;
++ intel_mid_msgbus_write32(0x09, 0x03, new_value);
++ mid_pmu_cxt->camera_off = true;
++ }
++#endif
++
++ /* FIXME:: If S0ix is enabled when North Complex is ON we see
++ * Fabric errors, tracked in BZ: 115181, hence hold pm_qos
++ * to restrict s0ix during North Island in D0i0
++ */
++ if (nc_device_state()) {
++ if (!pm_qos_request_active(mid_pmu_cxt->nc_restrict_qos))
++ pm_qos_add_request(mid_pmu_cxt->nc_restrict_qos,
++ PM_QOS_CPU_DMA_LATENCY, (CSTATE_EXIT_LATENCY_S0i1-1));
++ } else {
++ if (pm_qos_request_active(mid_pmu_cxt->nc_restrict_qos))
++ pm_qos_remove_request(mid_pmu_cxt->nc_restrict_qos);
++ }
++
++unlock:
++ up(&mid_pmu_cxt->scu_ready_sem);
++
++ return status;
++}
++
++pci_power_t platfrom_pmu_choose_state(int lss)
++{
++ pci_power_t state = PCI_D3hot;
++
++ if (pmu_ops->pci_choose_state)
++ state = pmu_ops->pci_choose_state(lss);
++
++ return state;
++}
++
++/* return platform specific deepest states that the device can enter */
++pci_power_t pmu_pci_choose_state(struct pci_dev *pdev)
++{
++ int i;
++ int sub_sys_pos, sub_sys_index;
++ int status;
++ int device_lss;
++ int pmu_num;
++
++ pci_power_t state = PCI_D3hot;
++
++ if (pmu_initialized) {
++ status =
++ pmu_pci_to_indexes(pdev, &i, &pmu_num,
++ &sub_sys_index, &sub_sys_pos);
++
++ if ((status == PMU_SUCCESS) &&
++ (pmu_num == PMU_NUM_2)) {
++
++ device_lss =
++ (sub_sys_index * mid_pmu_cxt->ss_per_reg) +
++ sub_sys_pos;
++
++ state = platfrom_pmu_choose_state(device_lss);
++ }
++ }
++
++ return state;
++}
++
++int pmu_issue_interactive_command(struct pmu_ss_states *pm_ssc, bool ioc,
++ bool d3_cold)
++{
++ u32 command;
++
++ if (_pmu2_wait_not_busy()) {
++ dev_err(&mid_pmu_cxt->pmu_dev->dev,
++ "SCU BUSY. Operation not permitted\n");
++ return PMU_FAILED;
++ }
++
++ /* enable interrupts in PMU2 so that interrupts are
++ * propagated when ioc bit for a particular set
++ * command is set
++ */
++ /* Enable the hardware interrupt */
++ if (ioc)
++ pmu_set_interrupt_enable();
++
++ /* Configure the sub systems for pmu2 */
++ pmu_write_subsys_config(pm_ssc);
++
++ command = (ioc) ? INTERACTIVE_IOC_VALUE : INTERACTIVE_VALUE;
++
++ /* Special handling for PCI_D3cold in Tangier */
++ if (d3_cold)
++ command |= PM_CMD_D3_COLD;
++
++ /* send interactive command to SCU */
++ writel(command, &mid_pmu_cxt->pmu_reg->pm_cmd);
++
++ pmu_log_command(command, pm_ssc);
++
++ return 0;
++}
++
++/* Reads the status of each driver and updates the LSS values.
++ * To be called with scu_ready_sem mutex held, and pmu_config
++ * initialized with '0's
++ */
++static void update_all_lss_states(struct pmu_ss_states *pmu_config)
++{
++ int i;
++ u32 PCIALLDEV_CFG[4] = {0, 0, 0, 0};
++
++ if (platform_is(INTEL_ATOM_MFLD) || platform_is(INTEL_ATOM_CLV)) {
++ for (i = 0; i < MAX_DEVICES; i++) {
++ int pmu_num = get_mid_pci_pmu_num(i);
++ struct pci_dev *pdev = get_mid_pci_drv(i, 0);
++
++ if ((pmu_num == PMU_NUM_2) && pdev) {
++ int ss_idx, ss_pos;
++ pci_power_t state;
++
++ ss_idx = get_mid_pci_ss_idx(i);
++ ss_pos = get_mid_pci_ss_pos(i);
++ state = pdev->current_state;
++ /* The case of device not probed yet:
++ * Force D0i3 */
++ if (state == PCI_UNKNOWN)
++ state = pmu_pci_choose_state(pdev);
++
++ /* By default its set to '0' hence
++ * no need to update PCI_D0 state
++ */
++ state = pmu_pci_get_weakest_state_for_lss
++ (i, pdev, state);
++
++ pmu_config->pmu2_states[ss_idx] |=
++ (pci_to_platform_state(state) <<
++ (ss_pos * BITS_PER_LSS));
++
++ PCIALLDEV_CFG[ss_idx] |=
++ (D0I3_MASK << (ss_pos * BITS_PER_LSS));
++ }
++ }
++ }
++
++ platform_update_all_lss_states(pmu_config, PCIALLDEV_CFG);
++}
++
++static int pmu_init(void)
++{
++ int status;
++ struct pmu_ss_states pmu_config;
++ struct pmu_suspend_config *ss_config;
++ int ret = 0;
++ int retry_times = 0;
++
++
++ dev_dbg(&mid_pmu_cxt->pmu_dev->dev, "PMU Driver loaded\n");
++ spin_lock_init(&mid_pmu_cxt->nc_ready_lock);
++
++ /* enumerate the PCI configuration space */
++ pmu_enumerate();
++
++ /* initialize the stats for pmu driver */
++ pmu_stats_init();
++
++ /* register platform pmu ops */
++ platform_set_pmu_ops();
++
++ /* platform specific initialization */
++ if (pmu_ops->init) {
++ status = pmu_ops->init();
++ if (status) {
++ dev_dbg(&mid_pmu_cxt->pmu_dev->dev,
++ "pmu_ops->init failed\n");
++ goto out_err1;
++ }
++ }
++
++ /* initialize the state variables here */
++ ss_config = kzalloc(sizeof(struct pmu_suspend_config), GFP_KERNEL);
++
++ if (ss_config == NULL) {
++ dev_dbg(&mid_pmu_cxt->pmu_dev->dev,
++ "Allocation of memory for ss_config has failed\n");
++ status = PMU_FAILED;
++ goto out_err1;
++ }
++
++ memset(&pmu_config, 0, sizeof(pmu_config));
++
++ ss_config->ss_state = pmu_config;
++
++ /* initialize for the autonomous S0i3 */
++ mid_pmu_cxt->ss_config = ss_config;
++
++ /* setup the wake capable devices */
++ mid_pmu_cxt->ss_config->wake_state.wake_enable[0] = WAKE_ENABLE_0;
++ mid_pmu_cxt->ss_config->wake_state.wake_enable[1] = WAKE_ENABLE_1;
++
++ /* setup the ignore lss list */
++ mid_pmu_cxt->ignore_lss[0] = pmu_ignore_lss0;
++ mid_pmu_cxt->ignore_lss[1] = pmu_ignore_lss1;
++ mid_pmu_cxt->ignore_lss[2] = pmu_ignore_lss2;
++ mid_pmu_cxt->ignore_lss[3] = pmu_ignore_lss3;
++
++ /*set wkc to appropriate value suitable for s0ix*/
++ writel(mid_pmu_cxt->ss_config->wake_state.wake_enable[0],
++ &mid_pmu_cxt->pmu_reg->pm_wkc[0]);
++ writel(mid_pmu_cxt->ss_config->wake_state.wake_enable[1],
++ &mid_pmu_cxt->pmu_reg->pm_wkc[1]);
++
++ /* Acquire the scu_ready_sem */
++ down(&mid_pmu_cxt->scu_ready_sem);
++
++ /* Now we have initialized the driver
++ * Allow drivers to get blocked in
++ * pmu_pci_set_power_state(), until we finish
++ * first interactive command.
++ */
++
++ pmu_initialized = true;
++
++ /* get the current status of each of the driver
++ * and update it in SCU
++ */
++ update_all_lss_states(&pmu_config);
++
++ status = pmu_issue_interactive_command(&pmu_config, false,
++ false);
++ if (status != PMU_SUCCESS) {
++ dev_dbg(&mid_pmu_cxt->pmu_dev->dev,\
++ "Failure from pmu mode change to interactive."
++ " = %d\n", status);
++ status = PMU_FAILED;
++ up(&mid_pmu_cxt->scu_ready_sem);
++ goto out_err2;
++ }
++
++ /*
++ * Wait for interactive command to complete.
++ * If we dont wait, there is a possibility that
++ * the driver may access the device before its
++ * powered on in SCU.
++ *
++ */
++retry:
++ ret = _pmu2_wait_not_busy();
++ if (unlikely(ret)) {
++ retry_times++;
++ if (retry_times < 60) {
++ usleep_range(10, 500);
++ goto retry;
++ } else {
++ pmu_dump_logs();
++ BUG();
++ }
++ }
++
++ /* In cases were gfx is not enabled
++ * this will enable s0ix immediately
++ */
++ if (pmu_ops->set_power_state_ops)
++ pmu_ops->set_power_state_ops(PCI_D3hot);
++
++ up(&mid_pmu_cxt->scu_ready_sem);
++
++ return PMU_SUCCESS;
++
++out_err2:
++ kfree(ss_config);
++ mid_pmu_cxt->ss_config = NULL;
++out_err1:
++ return status;
++}
++
++/**
++ * mid_pmu_probe - This is the function where most of the PMU driver
++ * initialization happens.
++ */
++static int
++mid_pmu_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
++{
++ int ret;
++ struct mrst_pmu_reg __iomem *pmu;
++ u32 data;
++
++ mid_pmu_cxt->pmu_wake_lock =
++ wakeup_source_register("pmu_wake_lock");
++
++ if (!mid_pmu_cxt->pmu_wake_lock) {
++ pr_err("%s: unable to register pmu wake source.\n", __func__);
++ return -ENOMEM;
++ }
++
++ /* Init the device */
++ ret = pci_enable_device(dev);
++ if (ret) {
++ pr_err("Mid PM device cant be enabled\n");
++ goto out_err0;
++ }
++
++ /* store the dev */
++ mid_pmu_cxt->pmu_dev = dev;
++ dev_warn(&dev->dev, "PMU DRIVER Probe called\n");
++
++ ret = pci_request_regions(dev, PMU_DRV_NAME);
++ if (ret < 0) {
++ pr_err("pci request region has failed\n");
++ goto out_err1;
++ }
++
++ mid_pmu_cxt->pmu1_max_devs = PMU1_MAX_DEVS;
++ mid_pmu_cxt->pmu2_max_devs = PMU2_MAX_DEVS;
++ mid_pmu_cxt->ss_per_reg = 16;
++
++ /* Following code is used to map address required for NC PM
++ * which is not needed for all platforms
++ */
++ if (platform_is(INTEL_ATOM_MFLD) || platform_is(INTEL_ATOM_CLV)) {
++ data = intel_mid_msgbus_read32(OSPM_PUNIT_PORT, OSPM_APMBA);
++ mid_pmu_cxt->apm_base = data & 0xffff;
++
++ data = intel_mid_msgbus_read32(OSPM_PUNIT_PORT, OSPM_OSPMBA);
++ mid_pmu_cxt->ospm_base = data & 0xffff;
++ }
++
++ /* Map the memory of pmu1 PMU reg base */
++ pmu = pci_iomap(dev, 0, 0);
++ if (pmu == NULL) {
++ dev_dbg(&mid_pmu_cxt->pmu_dev->dev,
++ "Unable to map the PMU2 address space\n");
++ ret = PMU_FAILED;
++ goto out_err2;
++ }
++
++ mid_pmu_cxt->pmu_reg = pmu;
++
++ /* Map the memory of emergency emmc up */
++ mid_pmu_cxt->emergeny_emmc_up_addr =
++ ioremap_nocache(PMU_PANIC_EMMC_UP_ADDR, 4);
++ if (mid_pmu_cxt->emergeny_emmc_up_addr == NULL) {
++ dev_dbg(&mid_pmu_cxt->pmu_dev->dev,
++ "Unable to map the emergency emmc up address space\n");
++ ret = PMU_FAILED;
++ goto out_err3;
++ }
++
++ if (request_irq(dev->irq, pmu_sc_irq, IRQF_NO_SUSPEND, PMU_DRV_NAME,
++ NULL)) {
++ dev_dbg(&mid_pmu_cxt->pmu_dev->dev, "Registering isr has failed\n");
++ ret = PMU_FAILED;
++ goto out_err4;
++ }
++
++ /* call pmu init() for initialization of pmu interface */
++ ret = pmu_init();
++ if (ret != PMU_SUCCESS) {
++ dev_dbg(&mid_pmu_cxt->pmu_dev->dev, "PMU initialization has failed\n");
++ goto out_err5;
++ }
++ dev_warn(&mid_pmu_cxt->pmu_dev->dev, "after pmu initialization\n");
++
++ mid_pmu_cxt->pmu_init_time =
++ cpu_clock(raw_smp_processor_id());
++
++#ifdef CONFIG_PM_DEBUG
++ /*
++ * FIXME: Since S3 is not enabled yet we need to take
++ * a wake lock here. Else S3 will be triggered on display
++ * time out and platform will hang
++ */
++ if (platform_is(INTEL_ATOM_MRFLD) && !enable_s3)
++ __pm_stay_awake(mid_pmu_cxt->pmu_wake_lock);
++#endif
++
++ return 0;
++
++out_err5:
++ free_irq(dev->irq, &pmu_sc_irq);
++out_err4:
++ iounmap(mid_pmu_cxt->emergeny_emmc_up_addr);
++ mid_pmu_cxt->emergeny_emmc_up_addr = NULL;
++out_err3:
++ iounmap(mid_pmu_cxt->pmu_reg);
++ mid_pmu_cxt->base_addr.pmu1_base = NULL;
++ mid_pmu_cxt->base_addr.pmu2_base = NULL;
++out_err2:
++ pci_release_region(dev, 0);
++out_err1:
++ pci_disable_device(dev);
++out_err0:
++ wakeup_source_unregister(mid_pmu_cxt->pmu_wake_lock);
++ return ret;
++}
++
++static void mid_pmu_remove(struct pci_dev *dev)
++{
++ /* Freeing up the irq */
++ free_irq(dev->irq, &pmu_sc_irq);
++
++ if (pmu_ops->remove)
++ pmu_ops->remove();
++
++ iounmap(mid_pmu_cxt->emergeny_emmc_up_addr);
++ mid_pmu_cxt->emergeny_emmc_up_addr = NULL;
++
++ pci_iounmap(dev, mid_pmu_cxt->pmu_reg);
++ mid_pmu_cxt->base_addr.pmu1_base = NULL;
++ mid_pmu_cxt->base_addr.pmu2_base = NULL;
++
++ /* disable the current PCI device */
++ pci_release_region(dev, 0);
++ pci_disable_device(dev);
++
++ wakeup_source_unregister(mid_pmu_cxt->pmu_wake_lock);
++}
++
++static void mid_pmu_shutdown(struct pci_dev *dev)
++{
++ dev_dbg(&mid_pmu_cxt->pmu_dev->dev, "Mid PM mid_pmu_shutdown called\n");
++
++ if (mid_pmu_cxt) {
++ /* Restrict platform Cx state to C6 */
++ pm_qos_update_request(mid_pmu_cxt->s3_restrict_qos,
++ (CSTATE_EXIT_LATENCY_S0i1-1));
++
++ down(&mid_pmu_cxt->scu_ready_sem);
++ mid_pmu_cxt->shutdown_started = true;
++ up(&mid_pmu_cxt->scu_ready_sem);
++ }
++}
++
++static struct pci_driver driver = {
++ .name = PMU_DRV_NAME,
++ .id_table = mid_pm_ids,
++ .probe = mid_pmu_probe,
++ .remove = mid_pmu_remove,
++ .shutdown = mid_pmu_shutdown
++};
++
++static int standby_enter(void)
++{
++ u32 temp = 0;
++ int s3_state = mid_state_to_sys_state(MID_S3_STATE);
++
++ if (mid_s0ix_enter(MID_S3_STATE) != MID_S3_STATE) {
++ pmu_set_s0ix_complete();
++ return -EINVAL;
++ }
++
++ /* time stamp for end of s3 entry */
++ time_stamp_for_sleep_state_latency(s3_state, false, true);
++
++ __monitor((void *) &temp, 0, 0);
++ smp_mb();
++ __mwait(mid_pmu_cxt->s3_hint, 1);
++
++ /* time stamp for start of s3 exit */
++ time_stamp_for_sleep_state_latency(s3_state, true, false);
++
++ pmu_set_s0ix_complete();
++
++ /*set wkc to appropriate value suitable for s0ix*/
++ writel(mid_pmu_cxt->ss_config->wake_state.wake_enable[0],
++ &mid_pmu_cxt->pmu_reg->pm_wkc[0]);
++ writel(mid_pmu_cxt->ss_config->wake_state.wake_enable[1],
++ &mid_pmu_cxt->pmu_reg->pm_wkc[1]);
++
++ if (platform_is(INTEL_ATOM_MRFLD))
++ up(&mid_pmu_cxt->scu_ready_sem);
++
++ return 0;
++}
++
++static int mid_suspend_begin(suspend_state_t state)
++{
++ mid_pmu_cxt->suspend_started = true;
++ pmu_s3_stats_update(1);
++
++ /* Restrict to C6 during suspend */
++ pm_qos_update_request(mid_pmu_cxt->s3_restrict_qos,
++ (CSTATE_EXIT_LATENCY_S0i1-1));
++ return 0;
++}
++
++static int mid_suspend_valid(suspend_state_t state)
++{
++ int ret = 0;
++
++ switch (state) {
++ case PM_SUSPEND_ON:
++ case PM_SUSPEND_MEM:
++ /* check if we are ready */
++ if (likely(pmu_initialized))
++ ret = 1;
++ break;
++ }
++
++ return ret;
++}
++
++static int mid_suspend_prepare(void)
++{
++ return 0;
++}
++
++static int mid_suspend_prepare_late(void)
++{
++ return 0;
++}
++
++static int mid_suspend_enter(suspend_state_t state)
++{
++ int ret;
++
++ if (state != PM_SUSPEND_MEM)
++ return -EINVAL;
++
++ /* one last check before entering standby */
++ if (pmu_ops->check_nc_sc_status) {
++ if (!(pmu_ops->check_nc_sc_status())) {
++ trace_printk("Device d0ix status check failed! Aborting Standby entry!\n");
++ WARN_ON(1);
++ }
++ }
++
++ trace_printk("s3_entry\n");
++ ret = standby_enter();
++ trace_printk("s3_exit %d\n", ret);
++ if (ret != 0)
++ dev_dbg(&mid_pmu_cxt->pmu_dev->dev,
++ "Failed to enter S3 status: %d\n", ret);
++
++ return ret;
++}
++
++static void mid_suspend_end(void)
++{
++ /* allow s0ix now */
++ pm_qos_update_request(mid_pmu_cxt->s3_restrict_qos,
++ PM_QOS_DEFAULT_VALUE);
++
++ pmu_s3_stats_update(0);
++ mid_pmu_cxt->suspend_started = false;
++}
++
++static const struct platform_suspend_ops mid_suspend_ops = {
++ .begin = mid_suspend_begin,
++ .valid = mid_suspend_valid,
++ .prepare = mid_suspend_prepare,
++ .prepare_late = mid_suspend_prepare_late,
++ .enter = mid_suspend_enter,
++ .end = mid_suspend_end,
++};
++
++/**
++ * mid_pci_register_init - register the PMU driver as PCI device
++ */
++static int __init mid_pci_register_init(void)
++{
++ int ret;
++
++ mid_pmu_cxt = kzalloc(sizeof(struct mid_pmu_dev), GFP_KERNEL);
++
++ if (mid_pmu_cxt == NULL)
++ return -ENOMEM;
++
++ mid_pmu_cxt->s3_restrict_qos =
++ kzalloc(sizeof(struct pm_qos_request), GFP_KERNEL);
++ if (mid_pmu_cxt->s3_restrict_qos) {
++ pm_qos_add_request(mid_pmu_cxt->s3_restrict_qos,
++ PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
++ } else {
++ return -ENOMEM;
++ }
++
++ init_nc_device_states();
++
++ mid_pmu_cxt->nc_restrict_qos =
++ kzalloc(sizeof(struct pm_qos_request), GFP_KERNEL);
++ if (mid_pmu_cxt->nc_restrict_qos == NULL)
++ return -ENOMEM;
++
++ /* initialize the semaphores */
++ sema_init(&mid_pmu_cxt->scu_ready_sem, 1);
++
++ /* registering PCI device */
++ ret = pci_register_driver(&driver);
++ suspend_set_ops(&mid_suspend_ops);
++
++ return ret;
++}
++fs_initcall(mid_pci_register_init);
++
++void pmu_power_off(void)
++{
++ /* wait till SCU is ready */
++ if (!_pmu2_wait_not_busy())
++ writel(S5_VALUE, &mid_pmu_cxt->pmu_reg->pm_cmd);
++
++ if (!_pmu2_wait_not_busy())
++ rpmsg_send_generic_simple_command(IPCMSG_COLD_OFF, 1);
++}
++
++static void __exit mid_pci_cleanup(void)
++{
++ if (mid_pmu_cxt) {
++ if (mid_pmu_cxt->s3_restrict_qos)
++ pm_qos_remove_request(mid_pmu_cxt->s3_restrict_qos);
++
++ if (pm_qos_request_active(mid_pmu_cxt->nc_restrict_qos))
++ pm_qos_remove_request(mid_pmu_cxt->nc_restrict_qos);
++ }
++
++ suspend_set_ops(NULL);
++
++ /* registering PCI device */
++ pci_unregister_driver(&driver);
++
++ if (mid_pmu_cxt) {
++ pmu_stats_finish();
++ kfree(mid_pmu_cxt->ss_config);
++ }
++
++ kfree(mid_pmu_cxt);
++}
++module_exit(mid_pci_cleanup);
+diff --git a/arch/x86/platform/intel-mid/intel_soc_pmu.h b/arch/x86/platform/intel-mid/intel_soc_pmu.h
+new file mode 100644
+index 0000000..243ae47
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/intel_soc_pmu.h
+@@ -0,0 +1,511 @@
++/*
++ * intel_soc_pmu.h
++ * Copyright (c) 2012, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++#ifndef _MID_PMU_H_
++#define _MID_PMU_H_
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <linux/debugfs.h>
++#include <linux/seq_file.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/pci.h>
++#include <linux/semaphore.h>
++#include <linux/completion.h>
++#include <linux/spinlock.h>
++#include <linux/timer.h>
++#include <linux/jhash.h>
++#include <linux/suspend.h>
++#include <linux/workqueue.h>
++#include <linux/nmi.h>
++#include <linux/pm_qos.h>
++#include <linux/pm_wakeup.h>
++#include <asm/apic.h>
++#include <asm/intel_scu_ipc.h>
++#include <linux/intel_mid_pm.h>
++
++#include "intel_soc_mdfld.h"
++#include "intel_soc_clv.h"
++#include "intel_soc_mrfld.h"
++
++#define MID_PMU_MFLD_DRV_DEV_ID 0x0828
++#define MID_PMU_CLV_DRV_DEV_ID 0x08EC
++#define MID_PMU_MRFL_DRV_DEV_ID 0x11A1
++
++#define MID_MRFL_HDMI_DRV_DEV_ID 0x11A6
++
++/* SRAM address where PANIC START is written */
++#define PMU_PANIC_EMMC_UP_ADDR 0xFFFF3080
++#define PMU_PANIC_EMMC_UP_REQ_CMD 0xDEADBEEF
++
++#define MAX_DEVICES (PMU1_MAX_DEVS + PMU2_MAX_DEVS)
++#define PMU_MAX_LSS_SHARE 4
++
++#define PMU2_BUSY_TIMEOUT 500000
++#define HSU0_PCI_ID 0x81c
++#define HSU1_PCI_ID 0x81b
++#define HSI_PCI_ID 0x833
++
++#define MODE_ID_MAGIC_NUM 1
++
++#define LOG_ID_MASK 0x7F
++#define SUB_CLASS_MASK 0xFF00
++
++
++/* Definition for C6 Offload MSR Address */
++#define MSR_C6OFFLOAD_CTL_REG 0x120
++
++#define MSR_C6OFFLOAD_SET_LOW 1
++#define MSR_C6OFFLOAD_SET_HIGH 0
++
++#define C6OFFLOAD_BIT_MASK 0x2
++#define C6OFFLOAD_BIT 0x2
++
++#define PMU_DRV_NAME "intel_pmu_driver"
++
++#define MID_PCI_INDEX_HASH_BITS 8 /*size 256*/
++#define MID_PCI_INDEX_HASH_SIZE (1<<MID_PCI_INDEX_HASH_BITS)
++#define MID_PCI_INDEX_HASH_MASK (MID_PCI_INDEX_HASH_SIZE-1)
++
++/* some random number for initvalue */
++#define MID_PCI_INDEX_HASH_INITVALUE 0x27041975
++
++/*
++ * Values for programming the PM_CMD register based on the PM
++ * architecture speci
++*/
++
++#define S5_VALUE 0x309D2601
++#define S0I1_VALUE 0X30992601
++#define LPMP3_VALUE 0X40492601
++#define S0I3_VALUE 0X309B2601
++#define FAST_ON_OFF_VALUE 0X309E2601
++#define INTERACTIVE_VALUE 0X00002201
++#define INTERACTIVE_IOC_VALUE 0X00002301
++
++#define WAKE_ENABLE_0 0xffffffff
++#define WAKE_ENABLE_1 0xffffffff
++#define INVALID_WAKE_SRC 0xFFFF
++
++#define LOG_SS_MASK 0x80
++
++#define D0I0_MASK 0
++#define D0I1_MASK 1
++#define D0I2_MASK 2
++#define D0I3_MASK 3
++
++#define BITS_PER_LSS 2
++#define MAX_LSS_POSSIBLE 64
++#define SS_IDX_MASK 0x3
++#define SS_POS_MASK 0xF
++
++#define PMU_BASE_ADDR(pmu_num) ((pmu_num == 0) ? \
++ (u32) base_addr.pmu1_base :\
++ (u32) base_addr.pmu2_base);
++
++#define SSMSK(mask, lss) ((mask) << ((lss) * 2))
++#define SSWKC(lss) (1 << (lss))
++
++/* North Complex Power management */
++#define OSPM_PUNIT_PORT 0x04
++#define OSPM_OSPMBA 0x78
++#define OSPM_PM_SSC 0x20
++#define OSPM_PM_SSS 0x30
++
++#define OSPM_APMBA 0x7a
++#define APM_CMD 0x0
++#define APM_STS 0x04
++#define PM_CMD_D3_COLD (0x1 << 21)
++
++/* Size of command logging array */
++#define LOG_SIZE 5
++
++enum sys_state {
++ SYS_STATE_S0I0,
++ SYS_STATE_S0I1,
++ SYS_STATE_LPMP3,
++ SYS_STATE_S0I2,
++ SYS_STATE_S0I3,
++ SYS_STATE_S3,
++ SYS_STATE_S5,
++ SYS_STATE_MAX
++};
++
++enum int_status {
++ INVALID_INT = 0,
++ CMD_COMPLETE_INT = 1,
++ CMD_ERROR_INT = 2,
++ WAKE_RECEIVED_INT = 3,
++ SUBSYS_POW_ERR_INT = 4,
++ S0ix_MISS_INT = 5,
++ NO_ACKC6_INT = 6,
++ TRIGGERERR = 7,
++ INVALID_SRC_INT
++};
++
++enum pmu_number {
++ PMU_NUM_1,
++ PMU_NUM_2,
++ PMU_MAX_DEVS
++};
++
++enum pmu_ss_state {
++ SS_STATE_D0I0 = 0,
++ SS_STATE_D0I1 = 1,
++ SS_STATE_D0I2 = 2,
++ SS_STATE_D0I3 = 3
++};
++
++
++struct pmu_ss_states {
++ unsigned long pmu1_states;
++ unsigned long pmu2_states[4];
++};
++
++struct pci_dev_info {
++ u8 ss_pos;
++ u8 ss_idx;
++ u8 pmu_num;
++
++ u32 log_id;
++ u32 cap;
++ struct pci_dev *drv[PMU_MAX_LSS_SHARE];
++ pci_power_t power_state[PMU_MAX_LSS_SHARE];
++};
++
++struct pmu_wake_ss_states {
++ unsigned long wake_enable[2];
++ unsigned long pmu1_wake_states;
++ unsigned long pmu2_wake_states[4];
++};
++
++struct pmu_suspend_config {
++ struct pmu_ss_states ss_state;
++ struct pmu_wake_ss_states wake_state;
++};
++
++struct pci_dev_index {
++ struct pci_dev *pdev;
++ u8 index;
++};
++
++/* PMU register interface */
++struct mrst_pmu_reg {
++ u32 pm_sts; /* 0x00 */
++ u32 pm_cmd; /* 0x04 */
++ u32 pm_ics; /* 0x08 */
++ u32 _resv1;
++ u32 pm_wkc[2]; /* 0x10 */
++ u32 pm_wks[2]; /* 0x18 */
++ u32 pm_ssc[4]; /* 0x20 */
++ u32 pm_sss[4]; /* 0x30 */
++ u32 pm_wssc[4]; /* 0x40 */
++ u32 pm_c3c4; /* 0x50 */
++ u32 pm_c5c6; /* 0x54 */
++ u32 pm_msic; /* 0x58 */
++};
++
++struct mid_pmu_cmd_log {
++ struct timespec ts;
++ u32 command;
++ struct pmu_ss_states pm_ssc;
++};
++
++struct mid_pmu_irq_log {
++ struct timespec ts;
++ u32 status;
++};
++
++struct mid_pmu_ipc_log {
++ struct timespec ts;
++ u32 command;
++};
++
++struct mid_pmu_pmu_irq_log {
++ struct timespec ts;
++ u8 status;
++};
++
++struct mid_pmu_ipc_irq_log {
++ struct timespec ts;
++};
++
++union pmu_pm_status {
++ struct {
++ u32 pmu_rev:8;
++ u32 pmu_busy:1;
++ u32 mode_id:4;
++ u32 Reserved:19;
++ } pmu_status_parts;
++ u32 pmu_status_value;
++};
++
++union pmu_pm_ics {
++ struct {
++ u32 int_status:8;
++ u32 int_enable:1;
++ u32 int_pend:1;
++ /* New bit added in TNG to indicate device wakes*/
++ u32 sw_int_status:1;
++ u32 reserved:21;
++ } pmu_pm_ics_parts;
++ u32 pmu_pm_ics_value;
++};
++
++struct intel_mid_base_addr {
++ u32 *pmu1_base;
++ void __iomem *pmu2_base;
++ u32 *pm_table_base;
++ u32 __iomem *offload_reg;
++};
++
++#define MAX_PMU_LOG_STATES (S0I3_STATE_IDX - C4_STATE_IDX + 1)
++
++struct mid_pmu_stats {
++ u64 err_count[3];
++ u64 count;
++ u64 time;
++ u64 last_entry;
++ u64 last_try;
++ u64 first_entry;
++ u32 demote_count[MAX_PMU_LOG_STATES];
++ u32 display_blocker_count;
++ u32 camera_blocker_count;
++ u32 blocker_count[MAX_LSS_POSSIBLE];
++};
++
++struct device_residency {
++ u64 d0i0_entry;
++ u64 d0i3_entry;
++ u64 d0i0_acc;
++ u64 d0i3_acc;
++ u64 start;
++ pci_power_t state;
++};
++
++struct mid_pmu_dev {
++ bool suspend_started;
++ bool shutdown_started;
++ bool camera_off;
++ bool display_off;
++
++ u32 apm_base;
++ u32 ospm_base;
++ u32 pmu1_max_devs;
++ u32 pmu2_max_devs;
++ u32 ss_per_reg;
++ u32 d0ix_stat[MAX_LSS_POSSIBLE][SS_STATE_D0I3+1];
++ u32 num_wakes[MAX_DEVICES][SYS_STATE_MAX];
++ u32 ignore_lss[4];
++ u32 os_sss[4];
++#ifdef CONFIG_PM_DEBUG
++ u32 cstate_ignore;
++ struct pm_qos_request *cstate_qos;
++#endif
++
++ u32 __iomem *emergeny_emmc_up_addr;
++ u64 pmu_init_time;
++
++ int cmd_error_int;
++ int s0ix_possible;
++ int s0ix_entered;
++
++#ifdef LOG_PMU_EVENTS
++ int cmd_log_idx;
++ int ipc_log_idx;
++ int ipc_irq_log_idx;
++ int pmu_irq_log_idx;
++#endif
++
++ enum sys_state pmu_current_state;
++
++ struct pci_dev_info pci_devs[MAX_DEVICES];
++ struct pci_dev_index
++ pci_dev_hash[MID_PCI_INDEX_HASH_SIZE];
++ struct intel_mid_base_addr base_addr;
++ struct mrst_pmu_reg __iomem *pmu_reg;
++ struct semaphore scu_ready_sem;
++ struct mid_pmu_stats pmu_stats[SYS_STATE_MAX];
++ struct device_residency pmu_dev_res[MAX_DEVICES];
++ struct delayed_work log_work;
++ struct pm_qos_request *s3_restrict_qos;
++
++#ifdef LOG_PMU_EVENTS
++ struct mid_pmu_cmd_log cmd_log[LOG_SIZE];
++ struct mid_pmu_ipc_log ipc_log[LOG_SIZE];
++ struct mid_pmu_ipc_irq_log ipc_irq_log[LOG_SIZE];
++ struct mid_pmu_pmu_irq_log pmu_irq_log[LOG_SIZE];
++#endif
++ struct wakeup_source *pmu_wake_lock;
++
++ struct pmu_suspend_config *ss_config;
++ struct pci_dev *pmu_dev;
++ struct pm_qos_request *nc_restrict_qos;
++
++ spinlock_t nc_ready_lock;
++
++ int s3_hint;
++};
++
++struct platform_pmu_ops {
++ int (*init)(void);
++ void (*prepare)(int);
++ bool (*enter)(int);
++ void (*wakeup)(void);
++ void (*remove)(void);
++ pci_power_t (*pci_choose_state) (int);
++ void (*set_power_state_ops) (int);
++ void (*set_s0ix_complete) (void);
++ int (*nc_set_power_state) (int, int, int, int *);
++ bool (*check_nc_sc_status) (void);
++};
++
++extern char s0ix[5];
++extern struct platform_pmu_ops mfld_pmu_ops;
++extern struct platform_pmu_ops clv_pmu_ops;
++extern struct platform_pmu_ops mrfld_pmu_ops;
++extern struct platform_pmu_ops *get_platform_ops(void);
++extern void mfld_s0ix_sram_save_cleanup(void);
++extern void pmu_stats_init(void);
++extern void pmu_s3_stats_update(int enter);
++extern void pmu_stats_finish(void);
++extern void mfld_s0ix_sram_restore(u32 s0ix);
++extern void pmu_stat_error(u8 err_type);
++extern void pmu_stat_end(void);
++extern void pmu_stat_start(enum sys_state type);
++extern int pmu_pci_to_indexes(struct pci_dev *pdev, int *index,
++ int *pmu_num, int *ss_idx, int *ss_pos);
++extern struct mid_pmu_dev *mid_pmu_cxt;
++extern void platform_set_pmu_ops(void);
++extern void pmu_read_sss(struct pmu_ss_states *pm_ssc);
++extern int pmu_issue_interactive_command(struct pmu_ss_states *pm_ssc,
++ bool ioc, bool d3_cold);
++extern int _pmu2_wait_not_busy(void);
++extern u32 get_s0ix_val_set_pm_ssc(int);
++extern int pmu_get_wake_source(void);
++extern bool pmu_initialized;
++extern struct platform_pmu_ops *pmu_ops;
++extern void platform_update_all_lss_states(struct pmu_ss_states *, int *);
++extern int set_extended_cstate_mode(const char *val, struct kernel_param *kp);
++extern int get_extended_cstate_mode(char *buffer, struct kernel_param *kp);
++extern int byt_pmu_nc_set_power_state(int islands, int state_type, int reg);
++extern int byt_pmu_nc_get_power_state(int islands, int reg);
++extern void pmu_set_interrupt_enable(void);
++extern void pmu_clear_interrupt_enable(void);
++
++#ifdef LOG_PMU_EVENTS
++extern void pmu_log_pmu_irq(int status);
++extern void pmu_log_command(u32 command, struct pmu_ss_states *pm_ssc);
++extern void pmu_dump_logs(void);
++#endif
++
++/* Accessor function for pci_devs start */
++static inline void pmu_stat_clear(void)
++{
++ mid_pmu_cxt->pmu_current_state = SYS_STATE_S0I0;
++}
++
++static inline struct pci_dev *get_mid_pci_drv(int lss_index, int i)
++{
++ return mid_pmu_cxt->pci_devs[lss_index].drv[i];
++}
++
++static inline pci_power_t get_mid_pci_power_state(int lss_index, int i)
++{
++ return mid_pmu_cxt->pci_devs[lss_index].power_state[i];
++}
++
++static inline u8 get_mid_pci_ss_idx(int lss_index)
++{
++ return mid_pmu_cxt->pci_devs[lss_index].ss_idx & SS_IDX_MASK;
++}
++
++static inline u8 get_mid_pci_ss_pos(int lss_index)
++{
++ return mid_pmu_cxt->pci_devs[lss_index].ss_pos & SS_POS_MASK;
++}
++
++static inline u8 get_mid_pci_pmu_num(int lss_index)
++{
++ return mid_pmu_cxt->pci_devs[lss_index].pmu_num;
++}
++
++static inline void set_mid_pci_drv(int lss_index,
++ int i, struct pci_dev *pdev)
++{
++ mid_pmu_cxt->pci_devs[lss_index].drv[i] = pdev;
++}
++
++static inline void set_mid_pci_power_state(int lss_index,
++ int i, pci_power_t state)
++{
++ mid_pmu_cxt->pci_devs[lss_index].power_state[i] = state;
++}
++
++static inline void set_mid_pci_ss_idx(int lss_index, u8 ss_idx)
++{
++ mid_pmu_cxt->pci_devs[lss_index].ss_idx = ss_idx;
++}
++
++static inline void set_mid_pci_ss_pos(int lss_index, u8 ss_pos)
++{
++ mid_pmu_cxt->pci_devs[lss_index].ss_pos = ss_pos;
++}
++
++static inline void set_mid_pci_pmu_num(int lss_index, u8 pmu_num)
++{
++ mid_pmu_cxt->pci_devs[lss_index].pmu_num = pmu_num;
++}
++
++static inline void set_mid_pci_log_id(int lss_index, u32 log_id)
++{
++ mid_pmu_cxt->pci_devs[lss_index].log_id = log_id;
++}
++
++static inline void set_mid_pci_cap(int lss_index, u32 cap)
++{
++ mid_pmu_cxt->pci_devs[lss_index].cap = cap;
++}
++
++static inline u32 get_d0ix_stat(int lss_index, int state)
++{
++ return mid_pmu_cxt->d0ix_stat[lss_index][state];
++}
++
++static inline void inc_d0ix_stat(int lss_index, int state)
++{
++ mid_pmu_cxt->d0ix_stat[lss_index][state]++;
++}
++
++static inline void clear_d0ix_stats(void)
++{
++ memset(mid_pmu_cxt->d0ix_stat, 0, sizeof(mid_pmu_cxt->d0ix_stat));
++}
++
++/* Accessor functions for pci_devs end */
++
++static inline bool nc_device_state(void)
++{
++ return !mid_pmu_cxt->display_off || !mid_pmu_cxt->camera_off;
++}
++
++#endif
+diff --git a/arch/x86/platform/intel-mid/mfld.c b/arch/x86/platform/intel-mid/mfld.c
+new file mode 100644
+index 0000000..d0aa010
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/mfld.c
+@@ -0,0 +1,94 @@
++/*
++ * mfld.c: Intel Medfield platform setup code
++ *
++ * (C) Copyright 2012 Intel Corporation
++ * Author:
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/input.h>
++#include <linux/platform_device.h>
++#include <linux/mfd/intel_msic.h>
++#include <linux/irq.h>
++#include <linux/module.h>
++#include <linux/notifier.h>
++#include <linux/intel_pmic_gpio.h>
++#include <linux/gpio.h>
++#include <linux/gpio_keys.h>
++
++#include <asm/setup.h>
++#include <asm/mpspec_def.h>
++#include <asm/hw_irq.h>
++#include <asm/apic.h>
++#include <asm/io_apic.h>
++#include <asm/intel-mid.h>
++#include <asm/intel_mid_vrtc.h>
++#include <asm/io.h>
++#include <asm/i8259.h>
++#include <asm/intel_scu_ipc.h>
++#include <asm/apb_timer.h>
++#include <asm/reboot.h>
++
++static void penwell_arch_setup(void);
++/* penwell arch ops */
++static struct intel_mid_ops penwell_ops = {
++ .arch_setup = penwell_arch_setup,
++};
++
++static void mfld_power_off(void)
++{
++}
++
++static unsigned long __init mfld_calibrate_tsc(void)
++{
++ unsigned long fast_calibrate;
++ u32 lo, hi, ratio, fsb;
++
++ rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
++ pr_debug("IA32 perf status is 0x%x, 0x%0x\n", lo, hi);
++ ratio = (hi >> 8) & 0x1f;
++ pr_debug("ratio is %d\n", ratio);
++ if (!ratio) {
++ pr_err("read a zero ratio, should be incorrect!\n");
++ pr_err("force tsc ratio to 16 ...\n");
++ ratio = 16;
++ }
++ rdmsr(MSR_FSB_FREQ, lo, hi);
++ if ((lo & 0x7) == 0x7)
++ fsb = FSB_FREQ_83SKU;
++ else
++ fsb = FSB_FREQ_100SKU;
++ fast_calibrate = ratio * fsb;
++ pr_debug("read penwell tsc %lu khz\n", fast_calibrate);
++ lapic_timer_frequency = fsb * 1000 / HZ;
++ /* mark tsc clocksource as reliable */
++ set_cpu_cap(&boot_cpu_data, X86_FEATURE_TSC_RELIABLE);
++
++ if (fast_calibrate)
++ return fast_calibrate;
++
++ return 0;
++}
++
++static void penwell_arch_setup()
++{
++ x86_platform.calibrate_tsc = mfld_calibrate_tsc;
++ pm_power_off = mfld_power_off;
++}
++
++void *get_penwell_ops()
++{
++ return &penwell_ops;
++}
++
++void *get_cloverview_ops()
++{
++ return &penwell_ops;
++}
+diff --git a/arch/x86/platform/intel-mid/mrfl.c b/arch/x86/platform/intel-mid/mrfl.c
+new file mode 100644
+index 0000000..0e952f8
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/mrfl.c
+@@ -0,0 +1,161 @@
++/*
++ * mrfl.c: Intel Merrifield platform specific setup code
++ *
++ * (C) Copyright 2012 Intel Corporation
++ * Author: Mark F. Brown <mark.f.brown@intel.com>
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/module.h>
++#include <asm/setup.h>
++#include <asm/intel-mid.h>
++#include <asm/processor.h>
++
++#define APIC_DIVISOR 16
++
++enum intel_mid_sim_type __intel_mid_sim_platform;
++EXPORT_SYMBOL_GPL(__intel_mid_sim_platform);
++
++static void (*intel_mid_timer_init)(void);
++
++static void tangier_arch_setup(void);
++
++/* tangier arch ops */
++static struct intel_mid_ops tangier_ops = {
++ .arch_setup = tangier_arch_setup,
++};
++
++static unsigned long __init tangier_calibrate_tsc(void)
++{
++ /* [REVERT ME] fast timer calibration method to be defined */
++ if ((intel_mid_identify_sim() == INTEL_MID_CPU_SIMULATION_VP) ||
++ (intel_mid_identify_sim() == INTEL_MID_CPU_SIMULATION_HVP)) {
++ lapic_timer_frequency = 50000;
++ return 1000000;
++ }
++
++ if ((intel_mid_identify_sim() == INTEL_MID_CPU_SIMULATION_SLE) ||
++ (intel_mid_identify_sim() == INTEL_MID_CPU_SIMULATION_NONE)) {
++
++ unsigned long fast_calibrate;
++ u32 lo, hi, ratio, fsb, bus_freq;
++
++ /* *********************** */
++ /* Compute TSC:Ratio * FSB */
++ /* *********************** */
++
++ /* Compute Ratio */
++ rdmsr(MSR_PLATFORM_INFO, lo, hi);
++ pr_debug("IA32 PLATFORM_INFO is 0x%x : %x\n", hi, lo);
++
++ ratio = (lo >> 8) & 0xFF;
++ pr_debug("ratio is %d\n", ratio);
++ if (!ratio) {
++ pr_err("Read a zero ratio, force tsc ratio to 4 ...\n");
++ ratio = 4;
++ }
++
++ /* Compute FSB */
++ rdmsr(MSR_FSB_FREQ, lo, hi);
++ pr_debug("Actual FSB frequency detected by SOC 0x%x : %x\n",
++ hi, lo);
++
++ bus_freq = lo & 0x7;
++ pr_debug("bus_freq = 0x%x\n", bus_freq);
++
++ if (bus_freq == 0)
++ fsb = FSB_FREQ_100SKU;
++ else if (bus_freq == 1)
++ fsb = FSB_FREQ_100SKU;
++ else if (bus_freq == 2)
++ fsb = FSB_FREQ_133SKU;
++ else if (bus_freq == 3)
++ fsb = FSB_FREQ_167SKU;
++ else if (bus_freq == 4)
++ fsb = FSB_FREQ_83SKU;
++ else if (bus_freq == 5)
++ fsb = FSB_FREQ_400SKU;
++ else if (bus_freq == 6)
++ fsb = FSB_FREQ_267SKU;
++ else if (bus_freq == 7)
++ fsb = FSB_FREQ_333SKU;
++ else {
++ BUG();
++ pr_err("Invalid bus_freq! Setting to minimal value!\n");
++ fsb = FSB_FREQ_100SKU;
++ }
++
++ /* TSC = FSB Freq * Resolved HFM Ratio */
++ fast_calibrate = ratio * fsb;
++ pr_debug("calculate tangier tsc %lu KHz\n", fast_calibrate);
++
++ /* ************************************ */
++ /* Calculate Local APIC Timer Frequency */
++ /* ************************************ */
++ lapic_timer_frequency = (fsb * 1000) / HZ;
++
++ pr_debug("Setting lapic_timer_frequency = %d\n",
++ lapic_timer_frequency);
++
++ /* mark tsc clocksource as reliable */
++ set_cpu_cap(&boot_cpu_data, X86_FEATURE_TSC_RELIABLE);
++
++ if (fast_calibrate)
++ return fast_calibrate;
++ }
++ return 0;
++}
++
++/* Allow user to enable simulator quirks settings for kernel */
++static int __init set_simulation_platform(char *str)
++{
++ int platform;
++
++ __intel_mid_sim_platform = INTEL_MID_CPU_SIMULATION_NONE;
++ if (get_option(&str, &platform)) {
++ __intel_mid_sim_platform = platform;
++ pr_info("simulator mode %d enabled.\n",
++ __intel_mid_sim_platform);
++ return 0;
++ }
++
++ return -EINVAL;
++}
++early_param("mrfld_simulation", set_simulation_platform);
++
++static void __init tangier_time_init(void)
++{
++ /* [REVERT ME] ARAT capability not set in VP. Force setting */
++ if (intel_mid_identify_sim() == INTEL_MID_CPU_SIMULATION_VP ||
++ intel_mid_identify_sim() == INTEL_MID_CPU_SIMULATION_HVP)
++ set_cpu_cap(&boot_cpu_data, X86_FEATURE_ARAT);
++
++ if (intel_mid_timer_init)
++ intel_mid_timer_init();
++}
++
++static void __init tangier_arch_setup(void)
++{
++ x86_platform.calibrate_tsc = tangier_calibrate_tsc;
++ intel_mid_timer_init = x86_init.timers.timer_init;
++ x86_init.timers.timer_init = tangier_time_init;
++}
++
++void *get_tangier_ops()
++{
++ return &tangier_ops;
++}
++
++/* piggy back on anniedale ops right now */
++void *get_anniedale_ops()
++{
++ return &tangier_ops;
++}
+diff --git a/arch/x86/platform/intel-mid/pmu_tng.c b/arch/x86/platform/intel-mid/pmu_tng.c
+new file mode 100644
+index 0000000..dd69354
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/pmu_tng.c
+@@ -0,0 +1,218 @@
++/**************************************************************************
++ * Copyright (c) 2012, Intel Corporation.
++ * All Rights Reserved.
++
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++ * SOFTWARE.
++ *
++ * Authors:
++ * Dale B. Stimson <dale.b.stimson@intel.com>
++ *
++ */
++
++
++#include <linux/kernel.h>
++#include <linux/printk.h>
++#include <linux/delay.h>
++
++#include <asm/intel-mid.h>
++#include "pmu_tng.h"
++
++
++#if (defined DEBUG_PM_CMD) && DEBUG_PM_CMD
++const char *pm_cmd_reg_name(u32 reg_addr)
++{
++ const char *pstr;
++
++ switch (reg_addr) {
++ case GFX_SS_PM0:
++ pstr = "GFX_SS_PM0";
++ break;
++ case GFX_SS_PM1:
++ pstr = "GFX_SS_PM1";
++ break;
++ case VED_SS_PM0:
++ pstr = "VED_SS_PM0";
++ break;
++ case VED_SS_PM1:
++ pstr = "VED_SS_PM1";
++ break;
++ case VEC_SS_PM0:
++ pstr = "VEC_SS_PM0";
++ break;
++ case VEC_SS_PM1:
++ pstr = "VEC_SS_PM1";
++ break;
++ case DSP_SS_PM:
++ pstr = "DSP_SS_PM";
++ break;
++ case VSP_SS_PM0:
++ pstr = "VSP_SS_PM0";
++ break;
++ case VSP_SS_PM1:
++ pstr = "VSP_SS_PM1";
++ break;
++ case MIO_SS_PM:
++ pstr = "MIO_SS_PM";
++ break;
++ case HDMIO_SS_PM:
++ pstr = "HDMIO_SS_PM";
++ break;
++ case NC_PM_SSS:
++ pstr = "NC_PM_SSS";
++ break;
++ default:
++ pstr = "(unknown_pm_reg)";
++ break;
++ }
++
++ return pstr;
++}
++#endif /* if (defined DEBUG_PM_CMD) && DEBUG_PM_CMD */
++
++
++/**
++ * pmu_set_power_state_tng() - Send power management cmd to punit and
++ * wait for completion.
++ *
++ * This function implements Tangier/Merrifield punit-based power control.
++ *
++ * @reg_pm0 - Address of PM control register. Example: GFX_SS_PM0
++ *
++ * @si_mask: Control bits. "si" stands for "sub-islands".
++ * Bit mask specifying of one or more of the power islands to be affected.
++ * Each power island is a two bit field. These bits are set for every bit
++ * in each power island to be affected by this command.
++ * For each island, either 0 or all 2 of its bits may be specified, but it
++ * is an error to specify only 1 of its bits.
++ *
++ * @ns_mask: "ns" stands for "new state".
++ * New state for bits specified by si_mask.
++ * Bits in ns_mask that are not set in si_mask are ignored.
++ * Mask of new power state for the power islands specified by si_mask.
++ * These bits are 0b00 for full power off and 0b11 for full power on.
++ * Note that other values may be specified (0b01 and 0b10).
++ *
++ * Bit field values:
++ * TNG_SSC_I0 0b00 - i0 - power on, no clock or p[ower gating
++ * TNG_SSC_I1 0b01 - i1 - clock gated
++ * TNG_SSC_I2 0b01 - i2 - soft reset
++ * TNG_SSC_D3 0b11 - d3 - power off, hw state not retained
++ *
++ * NOTE: Bit mask ns_mask is inverted from the *actual* hardware register
++ * values being used for power control. This convention was adopted so that
++ * the API accepts 0b11 for full power-on and 0b00 for full power-off.
++ *
++ * Function return value: 0 if success, or -error_value.
++ *
++ * Example calls (ignoring return status):
++ * Turn on all gfx islands:
++ * si_mask = GFX_SLC_LDO_SSC | GFX_SLC_SSC | GFX_SDKCK_SSC | GFX_RSCD_SSC;
++ * ns_mask = GFX_SLC_LDO_SSC | GFX_SLC_SSC | GFX_SDKCK_SSC | GFX_RSCD_SSC;
++ * pmu_set_power_state_tng(GFX_SS_PM0, this_mask, new_state);
++ * Turn on all gfx islands: (Another way):
++ * si_mask = GFX_SLC_LDO_SSC | GFX_SLC_SSC | GFX_SDKCK_SSC | GFX_RSCD_SSC;
++ * ns_mask = 0xFFFFFFFF;
++ * pmu_set_power_state_tng(GFX_SS_PM0, this_mask, new_state);
++ * Turn off all gfx islands:
++ * si_mask = GFX_SLC_LDO_SSC | GFX_SLC_SSC | GFX_SDKCK_SSC | GFX_RSCD_SSC;
++ * ns_mask = 0;
++ * pmu_set_power_state_tng(GFX_SS_PM0, this_mask, new_state);
++ *
++ * Replaces (for Tangier):
++ * int pmu_nc_set_power_state(int islands, int state_type, int reg_type);
++ */
++int pmu_set_power_state_tng(u32 reg_pm0, u32 si_mask, u32 ns_mask)
++{
++ u32 pwr_cur;
++ u32 pwr_val;
++ int tcount;
++
++#if (defined DEBUG_PM_CMD) && DEBUG_PM_CMD
++ u32 pwr_prev;
++ int pwr_stored;
++#endif
++
++ ns_mask &= si_mask;
++
++#if (defined DEBUG_PM_CMD) && DEBUG_PM_CMD
++ printk(KERN_ALERT "%s(\"%s\"=%#x, %#x, %#x);\n", __func__,
++ pm_cmd_reg_name(reg_pm0), reg_pm0, si_mask, ns_mask);
++#endif
++
++ pwr_cur = intel_mid_msgbus_read32(PUNIT_PORT, reg_pm0);
++
++#if (defined DEBUG_PM_CMD) && DEBUG_PM_CMD
++ printk(KERN_ALERT "%s: before: %s: read: %#x\n",
++ __func__, pm_cmd_reg_name(reg_pm0), pwr_cur);
++#endif
++ /* Return if already in desired state. */
++ if ((((pwr_cur >> SSC_TO_SSS_SHIFT) ^ ns_mask) & si_mask) == 0)
++ return 0;
++
++ pwr_val = (pwr_cur & ~si_mask) | ns_mask;
++ intel_mid_msgbus_write32(PUNIT_PORT, reg_pm0, pwr_val);
++
++#if (defined DEBUG_PM_CMD) && DEBUG_PM_CMD
++ printk(KERN_ALERT "%s: %s: write: %#x\n",
++ __func__, pm_cmd_reg_name(reg_pm0), pwr_val);
++ pwr_prev = 0;
++ pwr_stored = 0;
++#endif
++
++ for (tcount = 0; ; tcount++) {
++ if (tcount > 50) {
++ WARN(1, "%s: P-Unit PM action request timeout",
++ __func__);
++ return -EBUSY;
++ }
++ pwr_cur = intel_mid_msgbus_read32(PUNIT_PORT, reg_pm0);
++
++#if (defined DEBUG_PM_CMD) && DEBUG_PM_CMD
++ if (!pwr_stored || (pwr_prev != pwr_cur)) {
++ printk(KERN_ALERT
++ "%s: tries=%d: %s: read: %#x\n",
++ __func__, tcount,
++ pm_cmd_reg_name(reg_pm0),
++ pwr_cur);
++ pwr_stored = 1;
++ pwr_prev = pwr_cur;
++ }
++#endif
++
++ if ((((pwr_cur >> SSC_TO_SSS_SHIFT) ^ ns_mask) & si_mask) == 0)
++ break;
++ udelay(10);
++ }
++
++ return 0;
++}
++
++static int __init pmu_nc_poweroff(void) {
++ /* Power off DPA */
++ pmu_set_power_state_tng (DSP_SS_PM, DPA_SSC, TNG_COMPOSITE_D3);
++ /* Power off MIO */
++ pmu_set_power_state_tng (MIO_SS_PM, MIO_SSC, TNG_COMPOSITE_D3);
++ /* Power off ISP */
++ pmu_set_power_state_tng (ISP_SS_PM0, ISP_SSC, TNG_COMPOSITE_D3);
++ return 0;
++}
++
++late_initcall(pmu_nc_poweroff);
++
+diff --git a/arch/x86/platform/intel-mid/pmu_tng.h b/arch/x86/platform/intel-mid/pmu_tng.h
+new file mode 100644
+index 0000000..ef91013
+--- /dev/null
++++ b/arch/x86/platform/intel-mid/pmu_tng.h
+@@ -0,0 +1,180 @@
++/**************************************************************************
++ * Copyright (c) 2012, Intel Corporation.
++ * All Rights Reserved.
++
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++ * SOFTWARE.
++ *
++ * Authors:
++ * Dale B. Stimson <dale.b.stimson@intel.com>
++ * Austin Hu <austin.hu@intel.com>
++ */
++
++#ifndef _PMU_TNG_H_
++#define _PMU_TNG_H_
++
++#include <linux/types.h>
++
++/* Per TNG Punit HAS */
++
++#define PUNIT_PORT 0x04
++
++/*
++ * Registers on msgbus port 4 (p-unit) for power/freq control.
++ * Bits 7:0 of the PM0 (or just PM) registers are power control bits, whereas
++ * bits 31:24 are the corresponding status bits.
++*/
++
++/* Subsystem status of all North Cluster IPs (bits NC_PM_SSS_*) */
++#define NC_PM_SSS 0x3f
++
++/*
++ * Bit masks for power islands, as present in PM0 or PM registers.
++ * These reside as control bits in bits 7:0 of each register and
++ * as status bits in bits 31:24 of each register.
++ * Each power island has a 2-bit field which contains a value of TNG_SSC_*.
++ */
++#define SSC_TO_SSS_SHIFT 24
++
++/* GFX_SS_PM0 island */
++#define GFX_SS_PM0 0x30
++#define GFX_SS_PM1 0x31
++
++#define GFX_SLC_SSC 0x03
++#define GFX_SDKCK_SSC 0x0c
++#define GFX_RSCD_SSC 0x30
++#define GFX_SLC_LDO_SSC 0xc0
++
++#define GFX_SLC_SHIFT 0
++#define GFX_SDKCK_SHIFT 2
++#define GFX_RSCD_SHIFT 4
++#define GFX_SLC_LDO_SHIFT 6
++
++/* VED_SS_PMx power island */
++#define VED_SS_PM0 0x32
++#define VED_SS_PM1 0x33
++
++#define VED_SSC 0x03
++
++/* VEC_SS_PMx power island */
++#define VEC_SS_PM0 0x34
++#define VEC_SS_PM1 0x35
++
++#define VEC_SSC 0x03
++
++/* DSP_SS_PM power islands */
++#define DSP_SS_PM 0x36
++
++#define DPA_SSC 0x03
++#define DPB_SSC 0x0c
++#define DPC_SSC 0x30
++
++#define DPA_SHIFT 0
++#define DPB_SHIFT 2
++#define DPC_SHIFT 4
++
++/* VSP_SS_PMx power islands */
++#define VSP_SS_PM0 0x37
++#define VSP_SS_PM1 0x38
++
++#define VSP_SSC 0x03
++
++/* ISP_SS_PMx power islands */
++#define ISP_SS_PM0 0x39
++#define ISP_SS_PM1 0x3a
++
++#define ISP_SSC 0x03
++
++/* MIO_SS_PM power island */
++#define MIO_SS_PM 0x3b
++
++#define MIO_SSC 0x03
++
++/* HDMIO_SS_PM power island */
++#define HDMIO_SS_PM 0x3c
++
++#define HDMIO_SSC 0x03
++
++/*
++ * Subsystem status bits for NC_PM_SSS. Status of all North Cluster IPs.
++ * These correspond to the above bits.
++ */
++#define NC_PM_SSS_GFX_SLC 0x00000003
++#define NC_PM_SSS_GFX_SDKCK 0x0000000c
++#define NC_PM_SSS_GFX_RSCD 0x00000030
++#define NC_PM_SSS_VED 0x000000c0
++#define NC_PM_SSS_VEC 0x00000300
++#define NC_PM_SSS_DPA 0x00000c00
++#define NC_PM_SSS_DPB 0x00003000
++#define NC_PM_SSS_DPC 0x0000c000
++#define NC_PM_SSS_VSP 0x00030000
++#define NC_PM_SSS_ISP 0x000c0000
++#define NC_PM_SSS_MIO 0x00300000
++#define NC_PM_SSS_HDMIO 0x00c00000
++#define NC_PM_SSS_GFX_SLC_LDO 0x03000000
++
++/*
++ * Frequency bits for *_PM1 registers above.
++ */
++#define IP_FREQ_VALID 0x80 /* Freq is valid bit */
++
++#define IP_FREQ_SIZE 5 /* number of bits in freq fields */
++#define IP_FREQ_MASK 0x1f /* Bit mask for freq field */
++
++/* Positions of various frequency fields */
++#define IP_FREQ_POS 0 /* Freq control [4:0] */
++#define IP_FREQ_GUAR_POS 8 /* Freq guar [12:8] */
++#define IP_FREQ_STAT_POS 24 /* Freq status [28:24] */
++
++#define IP_FREQ_100_00 0x1f /* 0b11111 100.00 */
++#define IP_FREQ_106_67 0x1d /* 0b11101 106.67 */
++#define IP_FREQ_133_30 0x17 /* 0b10111 133.30 */
++#define IP_FREQ_160_00 0x13 /* 0b10011 160.00 */
++#define IP_FREQ_177_78 0x11 /* 0b10001 177.78 */
++#define IP_FREQ_200_00 0x0f /* 0b01111 200.00 */
++#define IP_FREQ_213_33 0x0e /* 0b01110 213.33 */
++#define IP_FREQ_266_67 0x0b /* 0b01011 266.67 */
++#define IP_FREQ_320_00 0x09 /* 0b01001 320.00 */
++#define IP_FREQ_355_56 0x08 /* 0b01000 355.56 */
++#define IP_FREQ_400_00 0x07 /* 0b00111 400.00 */
++#define IP_FREQ_457_14 0x06 /* 0b00110 457.14 */
++#define IP_FREQ_533_33 0x05 /* 0b00101 533.33 */
++#define IP_FREQ_640_00 0x04 /* 0b00100 640.00 */
++#define IP_FREQ_800_00 0x03 /* 0b00011 800.00 */
++#define IP_FREQ_RESUME_SET 0x64
++
++/* Tangier power states for each island */
++#define TNG_SSC_I0 (0b00) /* i0 - power on, no clock or p[ower gating */
++#define TNG_SSC_I1 (0b01) /* i1 - clock gated */
++#define TNG_SSC_I2 (0b01) /* i2 - soft reset */
++#define TNG_SSC_D3 (0b11) /* d3 - power off, hw state not retained */
++
++#define TNG_SSC_MASK (0b11) /* bit mask of all involved bits. */
++
++/* Masks for the completely on and off states for 4 islands */
++#define TNG_COMPOSITE_I0 (0b00000000)
++#define TNG_COMPOSITE_D3 (0b11111111)
++
++#define DEBUG_PM_CMD 0
++#if !defined DEBUG_PM_CMD
++#define DEBUG_PM_CMD 1
++#endif
++
++int pmu_set_power_state_tng(u32 reg_pm0, u32 si_mask, u32 ns_mask);
++#endif /* ifndef _PMU_TNG_H_ */
+diff --git a/arch/x86/platform/mrst/Makefile b/arch/x86/platform/mrst/Makefile
+deleted file mode 100644
+index af1da7e..0000000
+--- a/arch/x86/platform/mrst/Makefile
++++ /dev/null
+@@ -1,3 +0,0 @@
+-obj-$(CONFIG_X86_INTEL_MID) += mrst.o
+-obj-$(CONFIG_X86_INTEL_MID) += vrtc.o
+-obj-$(CONFIG_EARLY_PRINTK_INTEL_MID) += early_printk_mrst.o
+diff --git a/arch/x86/platform/mrst/early_printk_mrst.c b/arch/x86/platform/mrst/early_printk_mrst.c
+deleted file mode 100644
+index 028454f..0000000
+--- a/arch/x86/platform/mrst/early_printk_mrst.c
++++ /dev/null
+@@ -1,324 +0,0 @@
+-/*
+- * early_printk_mrst.c - early consoles for Intel MID platforms
+- *
+- * Copyright (c) 2008-2010, Intel Corporation
+- *
+- * 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; version 2
+- * of the License.
+- */
+-
+-/*
+- * This file implements two early consoles named mrst and hsu.
+- * mrst is based on Maxim3110 spi-uart device, it exists in both
+- * Moorestown and Medfield platforms, while hsu is based on a High
+- * Speed UART device which only exists in the Medfield platform
+- */
+-
+-#include <linux/serial_reg.h>
+-#include <linux/serial_mfd.h>
+-#include <linux/kmsg_dump.h>
+-#include <linux/console.h>
+-#include <linux/kernel.h>
+-#include <linux/delay.h>
+-#include <linux/init.h>
+-#include <linux/io.h>
+-
+-#include <asm/fixmap.h>
+-#include <asm/pgtable.h>
+-#include <asm/mrst.h>
+-
+-#define MRST_SPI_TIMEOUT 0x200000
+-#define MRST_REGBASE_SPI0 0xff128000
+-#define MRST_REGBASE_SPI1 0xff128400
+-#define MRST_CLK_SPI0_REG 0xff11d86c
+-
+-/* Bit fields in CTRLR0 */
+-#define SPI_DFS_OFFSET 0
+-
+-#define SPI_FRF_OFFSET 4
+-#define SPI_FRF_SPI 0x0
+-#define SPI_FRF_SSP 0x1
+-#define SPI_FRF_MICROWIRE 0x2
+-#define SPI_FRF_RESV 0x3
+-
+-#define SPI_MODE_OFFSET 6
+-#define SPI_SCPH_OFFSET 6
+-#define SPI_SCOL_OFFSET 7
+-#define SPI_TMOD_OFFSET 8
+-#define SPI_TMOD_TR 0x0 /* xmit & recv */
+-#define SPI_TMOD_TO 0x1 /* xmit only */
+-#define SPI_TMOD_RO 0x2 /* recv only */
+-#define SPI_TMOD_EPROMREAD 0x3 /* eeprom read mode */
+-
+-#define SPI_SLVOE_OFFSET 10
+-#define SPI_SRL_OFFSET 11
+-#define SPI_CFS_OFFSET 12
+-
+-/* Bit fields in SR, 7 bits */
+-#define SR_MASK 0x7f /* cover 7 bits */
+-#define SR_BUSY (1 << 0)
+-#define SR_TF_NOT_FULL (1 << 1)
+-#define SR_TF_EMPT (1 << 2)
+-#define SR_RF_NOT_EMPT (1 << 3)
+-#define SR_RF_FULL (1 << 4)
+-#define SR_TX_ERR (1 << 5)
+-#define SR_DCOL (1 << 6)
+-
+-struct dw_spi_reg {
+- u32 ctrl0;
+- u32 ctrl1;
+- u32 ssienr;
+- u32 mwcr;
+- u32 ser;
+- u32 baudr;
+- u32 txfltr;
+- u32 rxfltr;
+- u32 txflr;
+- u32 rxflr;
+- u32 sr;
+- u32 imr;
+- u32 isr;
+- u32 risr;
+- u32 txoicr;
+- u32 rxoicr;
+- u32 rxuicr;
+- u32 msticr;
+- u32 icr;
+- u32 dmacr;
+- u32 dmatdlr;
+- u32 dmardlr;
+- u32 idr;
+- u32 version;
+-
+- /* Currently operates as 32 bits, though only the low 16 bits matter */
+- u32 dr;
+-} __packed;
+-
+-#define dw_readl(dw, name) __raw_readl(&(dw)->name)
+-#define dw_writel(dw, name, val) __raw_writel((val), &(dw)->name)
+-
+-/* Default use SPI0 register for mrst, we will detect Penwell and use SPI1 */
+-static unsigned long mrst_spi_paddr = MRST_REGBASE_SPI0;
+-
+-static u32 *pclk_spi0;
+-/* Always contains an accessible address, start with 0 */
+-static struct dw_spi_reg *pspi;
+-
+-static struct kmsg_dumper dw_dumper;
+-static int dumper_registered;
+-
+-static void dw_kmsg_dump(struct kmsg_dumper *dumper,
+- enum kmsg_dump_reason reason)
+-{
+- static char line[1024];
+- size_t len;
+-
+- /* When run to this, we'd better re-init the HW */
+- mrst_early_console_init();
+-
+- while (kmsg_dump_get_line(dumper, true, line, sizeof(line), &len))
+- early_mrst_console.write(&early_mrst_console, line, len);
+-}
+-
+-/* Set the ratio rate to 115200, 8n1, IRQ disabled */
+-static void max3110_write_config(void)
+-{
+- u16 config;
+-
+- config = 0xc001;
+- dw_writel(pspi, dr, config);
+-}
+-
+-/* Translate char to a eligible word and send to max3110 */
+-static void max3110_write_data(char c)
+-{
+- u16 data;
+-
+- data = 0x8000 | c;
+- dw_writel(pspi, dr, data);
+-}
+-
+-void mrst_early_console_init(void)
+-{
+- u32 ctrlr0 = 0;
+- u32 spi0_cdiv;
+- u32 freq; /* Freqency info only need be searched once */
+-
+- /* Base clk is 100 MHz, the actual clk = 100M / (clk_divider + 1) */
+- pclk_spi0 = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,
+- MRST_CLK_SPI0_REG);
+- spi0_cdiv = ((*pclk_spi0) & 0xe00) >> 9;
+- freq = 100000000 / (spi0_cdiv + 1);
+-
+- if (mrst_identify_cpu() == MRST_CPU_CHIP_PENWELL)
+- mrst_spi_paddr = MRST_REGBASE_SPI1;
+-
+- pspi = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,
+- mrst_spi_paddr);
+-
+- /* Disable SPI controller */
+- dw_writel(pspi, ssienr, 0);
+-
+- /* Set control param, 8 bits, transmit only mode */
+- ctrlr0 = dw_readl(pspi, ctrl0);
+-
+- ctrlr0 &= 0xfcc0;
+- ctrlr0 |= 0xf | (SPI_FRF_SPI << SPI_FRF_OFFSET)
+- | (SPI_TMOD_TO << SPI_TMOD_OFFSET);
+- dw_writel(pspi, ctrl0, ctrlr0);
+-
+- /*
+- * Change the spi0 clk to comply with 115200 bps, use 100000 to
+- * calculate the clk dividor to make the clock a little slower
+- * than real baud rate.
+- */
+- dw_writel(pspi, baudr, freq/100000);
+-
+- /* Disable all INT for early phase */
+- dw_writel(pspi, imr, 0x0);
+-
+- /* Set the cs to spi-uart */
+- dw_writel(pspi, ser, 0x2);
+-
+- /* Enable the HW, the last step for HW init */
+- dw_writel(pspi, ssienr, 0x1);
+-
+- /* Set the default configuration */
+- max3110_write_config();
+-
+- /* Register the kmsg dumper */
+- if (!dumper_registered) {
+- dw_dumper.dump = dw_kmsg_dump;
+- kmsg_dump_register(&dw_dumper);
+- dumper_registered = 1;
+- }
+-}
+-
+-/* Slave select should be called in the read/write function */
+-static void early_mrst_spi_putc(char c)
+-{
+- unsigned int timeout;
+- u32 sr;
+-
+- timeout = MRST_SPI_TIMEOUT;
+- /* Early putc needs to make sure the TX FIFO is not full */
+- while (--timeout) {
+- sr = dw_readl(pspi, sr);
+- if (!(sr & SR_TF_NOT_FULL))
+- cpu_relax();
+- else
+- break;
+- }
+-
+- if (!timeout)
+- pr_warning("MRST earlycon: timed out\n");
+- else
+- max3110_write_data(c);
+-}
+-
+-/* Early SPI only uses polling mode */
+-static void early_mrst_spi_write(struct console *con, const char *str, unsigned n)
+-{
+- int i;
+-
+- for (i = 0; i < n && *str; i++) {
+- if (*str == '\n')
+- early_mrst_spi_putc('\r');
+- early_mrst_spi_putc(*str);
+- str++;
+- }
+-}
+-
+-struct console early_mrst_console = {
+- .name = "earlymrst",
+- .write = early_mrst_spi_write,
+- .flags = CON_PRINTBUFFER,
+- .index = -1,
+-};
+-
+-/*
+- * Following is the early console based on Medfield HSU (High
+- * Speed UART) device.
+- */
+-#define HSU_PORT_BASE 0xffa28080
+-
+-static void __iomem *phsu;
+-
+-void hsu_early_console_init(const char *s)
+-{
+- unsigned long paddr, port = 0;
+- u8 lcr;
+-
+- /*
+- * Select the early HSU console port if specified by user in the
+- * kernel command line.
+- */
+- if (*s && !kstrtoul(s, 10, &port))
+- port = clamp_val(port, 0, 2);
+-
+- paddr = HSU_PORT_BASE + port * 0x80;
+- phsu = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE, paddr);
+-
+- /* Disable FIFO */
+- writeb(0x0, phsu + UART_FCR);
+-
+- /* Set to default 115200 bps, 8n1 */
+- lcr = readb(phsu + UART_LCR);
+- writeb((0x80 | lcr), phsu + UART_LCR);
+- writeb(0x18, phsu + UART_DLL);
+- writeb(lcr, phsu + UART_LCR);
+- writel(0x3600, phsu + UART_MUL*4);
+-
+- writeb(0x8, phsu + UART_MCR);
+- writeb(0x7, phsu + UART_FCR);
+- writeb(0x3, phsu + UART_LCR);
+-
+- /* Clear IRQ status */
+- readb(phsu + UART_LSR);
+- readb(phsu + UART_RX);
+- readb(phsu + UART_IIR);
+- readb(phsu + UART_MSR);
+-
+- /* Enable FIFO */
+- writeb(0x7, phsu + UART_FCR);
+-}
+-
+-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+-
+-static void early_hsu_putc(char ch)
+-{
+- unsigned int timeout = 10000; /* 10ms */
+- u8 status;
+-
+- while (--timeout) {
+- status = readb(phsu + UART_LSR);
+- if (status & BOTH_EMPTY)
+- break;
+- udelay(1);
+- }
+-
+- /* Only write the char when there was no timeout */
+- if (timeout)
+- writeb(ch, phsu + UART_TX);
+-}
+-
+-static void early_hsu_write(struct console *con, const char *str, unsigned n)
+-{
+- int i;
+-
+- for (i = 0; i < n && *str; i++) {
+- if (*str == '\n')
+- early_hsu_putc('\r');
+- early_hsu_putc(*str);
+- str++;
+- }
+-}
+-
+-struct console early_hsu_console = {
+- .name = "earlyhsu",
+- .write = early_hsu_write,
+- .flags = CON_PRINTBUFFER,
+- .index = -1,
+-};
+diff --git a/arch/x86/platform/mrst/mrst.c b/arch/x86/platform/mrst/mrst.c
+deleted file mode 100644
+index a0a0a43..0000000
+--- a/arch/x86/platform/mrst/mrst.c
++++ /dev/null
+@@ -1,1052 +0,0 @@
+-/*
+- * mrst.c: Intel Moorestown platform specific setup code
+- *
+- * (C) Copyright 2008 Intel Corporation
+- * Author: Jacob Pan (jacob.jun.pan@intel.com)
+- *
+- * 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; version 2
+- * of the License.
+- */
+-
+-#define pr_fmt(fmt) "mrst: " fmt
+-
+-#include <linux/init.h>
+-#include <linux/kernel.h>
+-#include <linux/interrupt.h>
+-#include <linux/scatterlist.h>
+-#include <linux/sfi.h>
+-#include <linux/intel_pmic_gpio.h>
+-#include <linux/spi/spi.h>
+-#include <linux/i2c.h>
+-#include <linux/i2c/pca953x.h>
+-#include <linux/gpio_keys.h>
+-#include <linux/input.h>
+-#include <linux/platform_device.h>
+-#include <linux/irq.h>
+-#include <linux/module.h>
+-#include <linux/notifier.h>
+-#include <linux/mfd/intel_msic.h>
+-#include <linux/gpio.h>
+-#include <linux/i2c/tc35876x.h>
+-
+-#include <asm/setup.h>
+-#include <asm/mpspec_def.h>
+-#include <asm/hw_irq.h>
+-#include <asm/apic.h>
+-#include <asm/io_apic.h>
+-#include <asm/mrst.h>
+-#include <asm/mrst-vrtc.h>
+-#include <asm/io.h>
+-#include <asm/i8259.h>
+-#include <asm/intel_scu_ipc.h>
+-#include <asm/apb_timer.h>
+-#include <asm/reboot.h>
+-
+-/*
+- * the clockevent devices on Moorestown/Medfield can be APBT or LAPIC clock,
+- * cmdline option x86_mrst_timer can be used to override the configuration
+- * to prefer one or the other.
+- * at runtime, there are basically three timer configurations:
+- * 1. per cpu apbt clock only
+- * 2. per cpu always-on lapic clocks only, this is Penwell/Medfield only
+- * 3. per cpu lapic clock (C3STOP) and one apbt clock, with broadcast.
+- *
+- * by default (without cmdline option), platform code first detects cpu type
+- * to see if we are on lincroft or penwell, then set up both lapic or apbt
+- * clocks accordingly.
+- * i.e. by default, medfield uses configuration #2, moorestown uses #1.
+- * config #3 is supported but not recommended on medfield.
+- *
+- * rating and feature summary:
+- * lapic (with C3STOP) --------- 100
+- * apbt (always-on) ------------ 110
+- * lapic (always-on,ARAT) ------ 150
+- */
+-
+-__cpuinitdata enum mrst_timer_options mrst_timer_options;
+-
+-static u32 sfi_mtimer_usage[SFI_MTMR_MAX_NUM];
+-static struct sfi_timer_table_entry sfi_mtimer_array[SFI_MTMR_MAX_NUM];
+-enum mrst_cpu_type __mrst_cpu_chip;
+-EXPORT_SYMBOL_GPL(__mrst_cpu_chip);
+-
+-int sfi_mtimer_num;
+-
+-struct sfi_rtc_table_entry sfi_mrtc_array[SFI_MRTC_MAX];
+-EXPORT_SYMBOL_GPL(sfi_mrtc_array);
+-int sfi_mrtc_num;
+-
+-static void mrst_power_off(void)
+-{
+-}
+-
+-static void mrst_reboot(void)
+-{
+- intel_scu_ipc_simple_command(IPCMSG_COLD_BOOT, 0);
+-}
+-
+-/* parse all the mtimer info to a static mtimer array */
+-static int __init sfi_parse_mtmr(struct sfi_table_header *table)
+-{
+- struct sfi_table_simple *sb;
+- struct sfi_timer_table_entry *pentry;
+- struct mpc_intsrc mp_irq;
+- int totallen;
+-
+- sb = (struct sfi_table_simple *)table;
+- if (!sfi_mtimer_num) {
+- sfi_mtimer_num = SFI_GET_NUM_ENTRIES(sb,
+- struct sfi_timer_table_entry);
+- pentry = (struct sfi_timer_table_entry *) sb->pentry;
+- totallen = sfi_mtimer_num * sizeof(*pentry);
+- memcpy(sfi_mtimer_array, pentry, totallen);
+- }
+-
+- pr_debug("SFI MTIMER info (num = %d):\n", sfi_mtimer_num);
+- pentry = sfi_mtimer_array;
+- for (totallen = 0; totallen < sfi_mtimer_num; totallen++, pentry++) {
+- pr_debug("timer[%d]: paddr = 0x%08x, freq = %dHz,"
+- " irq = %d\n", totallen, (u32)pentry->phys_addr,
+- pentry->freq_hz, pentry->irq);
+- if (!pentry->irq)
+- continue;
+- mp_irq.type = MP_INTSRC;
+- mp_irq.irqtype = mp_INT;
+-/* triggering mode edge bit 2-3, active high polarity bit 0-1 */
+- mp_irq.irqflag = 5;
+- mp_irq.srcbus = MP_BUS_ISA;
+- mp_irq.srcbusirq = pentry->irq; /* IRQ */
+- mp_irq.dstapic = MP_APIC_ALL;
+- mp_irq.dstirq = pentry->irq;
+- mp_save_irq(&mp_irq);
+- }
+-
+- return 0;
+-}
+-
+-struct sfi_timer_table_entry *sfi_get_mtmr(int hint)
+-{
+- int i;
+- if (hint < sfi_mtimer_num) {
+- if (!sfi_mtimer_usage[hint]) {
+- pr_debug("hint taken for timer %d irq %d\n",\
+- hint, sfi_mtimer_array[hint].irq);
+- sfi_mtimer_usage[hint] = 1;
+- return &sfi_mtimer_array[hint];
+- }
+- }
+- /* take the first timer available */
+- for (i = 0; i < sfi_mtimer_num;) {
+- if (!sfi_mtimer_usage[i]) {
+- sfi_mtimer_usage[i] = 1;
+- return &sfi_mtimer_array[i];
+- }
+- i++;
+- }
+- return NULL;
+-}
+-
+-void sfi_free_mtmr(struct sfi_timer_table_entry *mtmr)
+-{
+- int i;
+- for (i = 0; i < sfi_mtimer_num;) {
+- if (mtmr->irq == sfi_mtimer_array[i].irq) {
+- sfi_mtimer_usage[i] = 0;
+- return;
+- }
+- i++;
+- }
+-}
+-
+-/* parse all the mrtc info to a global mrtc array */
+-int __init sfi_parse_mrtc(struct sfi_table_header *table)
+-{
+- struct sfi_table_simple *sb;
+- struct sfi_rtc_table_entry *pentry;
+- struct mpc_intsrc mp_irq;
+-
+- int totallen;
+-
+- sb = (struct sfi_table_simple *)table;
+- if (!sfi_mrtc_num) {
+- sfi_mrtc_num = SFI_GET_NUM_ENTRIES(sb,
+- struct sfi_rtc_table_entry);
+- pentry = (struct sfi_rtc_table_entry *)sb->pentry;
+- totallen = sfi_mrtc_num * sizeof(*pentry);
+- memcpy(sfi_mrtc_array, pentry, totallen);
+- }
+-
+- pr_debug("SFI RTC info (num = %d):\n", sfi_mrtc_num);
+- pentry = sfi_mrtc_array;
+- for (totallen = 0; totallen < sfi_mrtc_num; totallen++, pentry++) {
+- pr_debug("RTC[%d]: paddr = 0x%08x, irq = %d\n",
+- totallen, (u32)pentry->phys_addr, pentry->irq);
+- mp_irq.type = MP_INTSRC;
+- mp_irq.irqtype = mp_INT;
+- mp_irq.irqflag = 0xf; /* level trigger and active low */
+- mp_irq.srcbus = MP_BUS_ISA;
+- mp_irq.srcbusirq = pentry->irq; /* IRQ */
+- mp_irq.dstapic = MP_APIC_ALL;
+- mp_irq.dstirq = pentry->irq;
+- mp_save_irq(&mp_irq);
+- }
+- return 0;
+-}
+-
+-static unsigned long __init mrst_calibrate_tsc(void)
+-{
+- unsigned long fast_calibrate;
+- u32 lo, hi, ratio, fsb;
+-
+- rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
+- pr_debug("IA32 perf status is 0x%x, 0x%0x\n", lo, hi);
+- ratio = (hi >> 8) & 0x1f;
+- pr_debug("ratio is %d\n", ratio);
+- if (!ratio) {
+- pr_err("read a zero ratio, should be incorrect!\n");
+- pr_err("force tsc ratio to 16 ...\n");
+- ratio = 16;
+- }
+- rdmsr(MSR_FSB_FREQ, lo, hi);
+- if ((lo & 0x7) == 0x7)
+- fsb = PENWELL_FSB_FREQ_83SKU;
+- else
+- fsb = PENWELL_FSB_FREQ_100SKU;
+- fast_calibrate = ratio * fsb;
+- pr_debug("read penwell tsc %lu khz\n", fast_calibrate);
+- lapic_timer_frequency = fsb * 1000 / HZ;
+- /* mark tsc clocksource as reliable */
+- set_cpu_cap(&boot_cpu_data, X86_FEATURE_TSC_RELIABLE);
+-
+- if (fast_calibrate)
+- return fast_calibrate;
+-
+- return 0;
+-}
+-
+-static void __init mrst_time_init(void)
+-{
+- sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr);
+- switch (mrst_timer_options) {
+- case MRST_TIMER_APBT_ONLY:
+- break;
+- case MRST_TIMER_LAPIC_APBT:
+- x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock;
+- x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock;
+- break;
+- default:
+- if (!boot_cpu_has(X86_FEATURE_ARAT))
+- break;
+- x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock;
+- x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock;
+- return;
+- }
+- /* we need at least one APB timer */
+- pre_init_apic_IRQ0();
+- apbt_time_init();
+-}
+-
+-static void __cpuinit mrst_arch_setup(void)
+-{
+- if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x27)
+- __mrst_cpu_chip = MRST_CPU_CHIP_PENWELL;
+- else {
+- pr_err("Unknown Intel MID CPU (%d:%d), default to Penwell\n",
+- boot_cpu_data.x86, boot_cpu_data.x86_model);
+- __mrst_cpu_chip = MRST_CPU_CHIP_PENWELL;
+- }
+-}
+-
+-/* MID systems don't have i8042 controller */
+-static int mrst_i8042_detect(void)
+-{
+- return 0;
+-}
+-
+-/*
+- * Moorestown does not have external NMI source nor port 0x61 to report
+- * NMI status. The possible NMI sources are from pmu as a result of NMI
+- * watchdog or lock debug. Reading io port 0x61 results in 0xff which
+- * misled NMI handler.
+- */
+-static unsigned char mrst_get_nmi_reason(void)
+-{
+- return 0;
+-}
+-
+-/*
+- * Moorestown specific x86_init function overrides and early setup
+- * calls.
+- */
+-void __init x86_mrst_early_setup(void)
+-{
+- x86_init.resources.probe_roms = x86_init_noop;
+- x86_init.resources.reserve_resources = x86_init_noop;
+-
+- x86_init.timers.timer_init = mrst_time_init;
+- x86_init.timers.setup_percpu_clockev = x86_init_noop;
+-
+- x86_init.irqs.pre_vector_init = x86_init_noop;
+-
+- x86_init.oem.arch_setup = mrst_arch_setup;
+-
+- x86_cpuinit.setup_percpu_clockev = apbt_setup_secondary_clock;
+-
+- x86_platform.calibrate_tsc = mrst_calibrate_tsc;
+- x86_platform.i8042_detect = mrst_i8042_detect;
+- x86_init.timers.wallclock_init = mrst_rtc_init;
+- x86_platform.get_nmi_reason = mrst_get_nmi_reason;
+-
+- x86_init.pci.init = pci_mrst_init;
+- x86_init.pci.fixup_irqs = x86_init_noop;
+-
+- legacy_pic = &null_legacy_pic;
+-
+- /* Moorestown specific power_off/restart method */
+- pm_power_off = mrst_power_off;
+- machine_ops.emergency_restart = mrst_reboot;
+-
+- /* Avoid searching for BIOS MP tables */
+- x86_init.mpparse.find_smp_config = x86_init_noop;
+- x86_init.mpparse.get_smp_config = x86_init_uint_noop;
+- set_bit(MP_BUS_ISA, mp_bus_not_pci);
+-}
+-
+-/*
+- * if user does not want to use per CPU apb timer, just give it a lower rating
+- * than local apic timer and skip the late per cpu timer init.
+- */
+-static inline int __init setup_x86_mrst_timer(char *arg)
+-{
+- if (!arg)
+- return -EINVAL;
+-
+- if (strcmp("apbt_only", arg) == 0)
+- mrst_timer_options = MRST_TIMER_APBT_ONLY;
+- else if (strcmp("lapic_and_apbt", arg) == 0)
+- mrst_timer_options = MRST_TIMER_LAPIC_APBT;
+- else {
+- pr_warning("X86 MRST timer option %s not recognised"
+- " use x86_mrst_timer=apbt_only or lapic_and_apbt\n",
+- arg);
+- return -EINVAL;
+- }
+- return 0;
+-}
+-__setup("x86_mrst_timer=", setup_x86_mrst_timer);
+-
+-/*
+- * Parsing GPIO table first, since the DEVS table will need this table
+- * to map the pin name to the actual pin.
+- */
+-static struct sfi_gpio_table_entry *gpio_table;
+-static int gpio_num_entry;
+-
+-static int __init sfi_parse_gpio(struct sfi_table_header *table)
+-{
+- struct sfi_table_simple *sb;
+- struct sfi_gpio_table_entry *pentry;
+- int num, i;
+-
+- if (gpio_table)
+- return 0;
+- sb = (struct sfi_table_simple *)table;
+- num = SFI_GET_NUM_ENTRIES(sb, struct sfi_gpio_table_entry);
+- pentry = (struct sfi_gpio_table_entry *)sb->pentry;
+-
+- gpio_table = kmalloc(num * sizeof(*pentry), GFP_KERNEL);
+- if (!gpio_table)
+- return -1;
+- memcpy(gpio_table, pentry, num * sizeof(*pentry));
+- gpio_num_entry = num;
+-
+- pr_debug("GPIO pin info:\n");
+- for (i = 0; i < num; i++, pentry++)
+- pr_debug("info[%2d]: controller = %16.16s, pin_name = %16.16s,"
+- " pin = %d\n", i,
+- pentry->controller_name,
+- pentry->pin_name,
+- pentry->pin_no);
+- return 0;
+-}
+-
+-static int get_gpio_by_name(const char *name)
+-{
+- struct sfi_gpio_table_entry *pentry = gpio_table;
+- int i;
+-
+- if (!pentry)
+- return -1;
+- for (i = 0; i < gpio_num_entry; i++, pentry++) {
+- if (!strncmp(name, pentry->pin_name, SFI_NAME_LEN))
+- return pentry->pin_no;
+- }
+- return -1;
+-}
+-
+-/*
+- * Here defines the array of devices platform data that IAFW would export
+- * through SFI "DEVS" table, we use name and type to match the device and
+- * its platform data.
+- */
+-struct devs_id {
+- char name[SFI_NAME_LEN + 1];
+- u8 type;
+- u8 delay;
+- void *(*get_platform_data)(void *info);
+-};
+-
+-/* the offset for the mapping of global gpio pin to irq */
+-#define MRST_IRQ_OFFSET 0x100
+-
+-static void __init *pmic_gpio_platform_data(void *info)
+-{
+- static struct intel_pmic_gpio_platform_data pmic_gpio_pdata;
+- int gpio_base = get_gpio_by_name("pmic_gpio_base");
+-
+- if (gpio_base == -1)
+- gpio_base = 64;
+- pmic_gpio_pdata.gpio_base = gpio_base;
+- pmic_gpio_pdata.irq_base = gpio_base + MRST_IRQ_OFFSET;
+- pmic_gpio_pdata.gpiointr = 0xffffeff8;
+-
+- return &pmic_gpio_pdata;
+-}
+-
+-static void __init *max3111_platform_data(void *info)
+-{
+- struct spi_board_info *spi_info = info;
+- int intr = get_gpio_by_name("max3111_int");
+-
+- spi_info->mode = SPI_MODE_0;
+- if (intr == -1)
+- return NULL;
+- spi_info->irq = intr + MRST_IRQ_OFFSET;
+- return NULL;
+-}
+-
+-/* we have multiple max7315 on the board ... */
+-#define MAX7315_NUM 2
+-static void __init *max7315_platform_data(void *info)
+-{
+- static struct pca953x_platform_data max7315_pdata[MAX7315_NUM];
+- static int nr;
+- struct pca953x_platform_data *max7315 = &max7315_pdata[nr];
+- struct i2c_board_info *i2c_info = info;
+- int gpio_base, intr;
+- char base_pin_name[SFI_NAME_LEN + 1];
+- char intr_pin_name[SFI_NAME_LEN + 1];
+-
+- if (nr == MAX7315_NUM) {
+- pr_err("too many max7315s, we only support %d\n",
+- MAX7315_NUM);
+- return NULL;
+- }
+- /* we have several max7315 on the board, we only need load several
+- * instances of the same pca953x driver to cover them
+- */
+- strcpy(i2c_info->type, "max7315");
+- if (nr++) {
+- sprintf(base_pin_name, "max7315_%d_base", nr);
+- sprintf(intr_pin_name, "max7315_%d_int", nr);
+- } else {
+- strcpy(base_pin_name, "max7315_base");
+- strcpy(intr_pin_name, "max7315_int");
+- }
+-
+- gpio_base = get_gpio_by_name(base_pin_name);
+- intr = get_gpio_by_name(intr_pin_name);
+-
+- if (gpio_base == -1)
+- return NULL;
+- max7315->gpio_base = gpio_base;
+- if (intr != -1) {
+- i2c_info->irq = intr + MRST_IRQ_OFFSET;
+- max7315->irq_base = gpio_base + MRST_IRQ_OFFSET;
+- } else {
+- i2c_info->irq = -1;
+- max7315->irq_base = -1;
+- }
+- return max7315;
+-}
+-
+-static void *tca6416_platform_data(void *info)
+-{
+- static struct pca953x_platform_data tca6416;
+- struct i2c_board_info *i2c_info = info;
+- int gpio_base, intr;
+- char base_pin_name[SFI_NAME_LEN + 1];
+- char intr_pin_name[SFI_NAME_LEN + 1];
+-
+- strcpy(i2c_info->type, "tca6416");
+- strcpy(base_pin_name, "tca6416_base");
+- strcpy(intr_pin_name, "tca6416_int");
+-
+- gpio_base = get_gpio_by_name(base_pin_name);
+- intr = get_gpio_by_name(intr_pin_name);
+-
+- if (gpio_base == -1)
+- return NULL;
+- tca6416.gpio_base = gpio_base;
+- if (intr != -1) {
+- i2c_info->irq = intr + MRST_IRQ_OFFSET;
+- tca6416.irq_base = gpio_base + MRST_IRQ_OFFSET;
+- } else {
+- i2c_info->irq = -1;
+- tca6416.irq_base = -1;
+- }
+- return &tca6416;
+-}
+-
+-static void *mpu3050_platform_data(void *info)
+-{
+- struct i2c_board_info *i2c_info = info;
+- int intr = get_gpio_by_name("mpu3050_int");
+-
+- if (intr == -1)
+- return NULL;
+-
+- i2c_info->irq = intr + MRST_IRQ_OFFSET;
+- return NULL;
+-}
+-
+-static void __init *emc1403_platform_data(void *info)
+-{
+- static short intr2nd_pdata;
+- struct i2c_board_info *i2c_info = info;
+- int intr = get_gpio_by_name("thermal_int");
+- int intr2nd = get_gpio_by_name("thermal_alert");
+-
+- if (intr == -1 || intr2nd == -1)
+- return NULL;
+-
+- i2c_info->irq = intr + MRST_IRQ_OFFSET;
+- intr2nd_pdata = intr2nd + MRST_IRQ_OFFSET;
+-
+- return &intr2nd_pdata;
+-}
+-
+-static void __init *lis331dl_platform_data(void *info)
+-{
+- static short intr2nd_pdata;
+- struct i2c_board_info *i2c_info = info;
+- int intr = get_gpio_by_name("accel_int");
+- int intr2nd = get_gpio_by_name("accel_2");
+-
+- if (intr == -1 || intr2nd == -1)
+- return NULL;
+-
+- i2c_info->irq = intr + MRST_IRQ_OFFSET;
+- intr2nd_pdata = intr2nd + MRST_IRQ_OFFSET;
+-
+- return &intr2nd_pdata;
+-}
+-
+-static void __init *no_platform_data(void *info)
+-{
+- return NULL;
+-}
+-
+-static struct resource msic_resources[] = {
+- {
+- .start = INTEL_MSIC_IRQ_PHYS_BASE,
+- .end = INTEL_MSIC_IRQ_PHYS_BASE + 64 - 1,
+- .flags = IORESOURCE_MEM,
+- },
+-};
+-
+-static struct intel_msic_platform_data msic_pdata;
+-
+-static struct platform_device msic_device = {
+- .name = "intel_msic",
+- .id = -1,
+- .dev = {
+- .platform_data = &msic_pdata,
+- },
+- .num_resources = ARRAY_SIZE(msic_resources),
+- .resource = msic_resources,
+-};
+-
+-static inline bool mrst_has_msic(void)
+-{
+- return mrst_identify_cpu() == MRST_CPU_CHIP_PENWELL;
+-}
+-
+-static int msic_scu_status_change(struct notifier_block *nb,
+- unsigned long code, void *data)
+-{
+- if (code == SCU_DOWN) {
+- platform_device_unregister(&msic_device);
+- return 0;
+- }
+-
+- return platform_device_register(&msic_device);
+-}
+-
+-static int __init msic_init(void)
+-{
+- static struct notifier_block msic_scu_notifier = {
+- .notifier_call = msic_scu_status_change,
+- };
+-
+- /*
+- * We need to be sure that the SCU IPC is ready before MSIC device
+- * can be registered.
+- */
+- if (mrst_has_msic())
+- intel_scu_notifier_add(&msic_scu_notifier);
+-
+- return 0;
+-}
+-arch_initcall(msic_init);
+-
+-/*
+- * msic_generic_platform_data - sets generic platform data for the block
+- * @info: pointer to the SFI device table entry for this block
+- * @block: MSIC block
+- *
+- * Function sets IRQ number from the SFI table entry for given device to
+- * the MSIC platform data.
+- */
+-static void *msic_generic_platform_data(void *info, enum intel_msic_block block)
+-{
+- struct sfi_device_table_entry *entry = info;
+-
+- BUG_ON(block < 0 || block >= INTEL_MSIC_BLOCK_LAST);
+- msic_pdata.irq[block] = entry->irq;
+-
+- return no_platform_data(info);
+-}
+-
+-static void *msic_battery_platform_data(void *info)
+-{
+- return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_BATTERY);
+-}
+-
+-static void *msic_gpio_platform_data(void *info)
+-{
+- static struct intel_msic_gpio_pdata pdata;
+- int gpio = get_gpio_by_name("msic_gpio_base");
+-
+- if (gpio < 0)
+- return NULL;
+-
+- pdata.gpio_base = gpio;
+- msic_pdata.gpio = &pdata;
+-
+- return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_GPIO);
+-}
+-
+-static void *msic_audio_platform_data(void *info)
+-{
+- struct platform_device *pdev;
+-
+- pdev = platform_device_register_simple("sst-platform", -1, NULL, 0);
+- if (IS_ERR(pdev)) {
+- pr_err("failed to create audio platform device\n");
+- return NULL;
+- }
+-
+- return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_AUDIO);
+-}
+-
+-static void *msic_power_btn_platform_data(void *info)
+-{
+- return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_POWER_BTN);
+-}
+-
+-static void *msic_ocd_platform_data(void *info)
+-{
+- static struct intel_msic_ocd_pdata pdata;
+- int gpio = get_gpio_by_name("ocd_gpio");
+-
+- if (gpio < 0)
+- return NULL;
+-
+- pdata.gpio = gpio;
+- msic_pdata.ocd = &pdata;
+-
+- return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_OCD);
+-}
+-
+-static void *msic_thermal_platform_data(void *info)
+-{
+- return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_THERMAL);
+-}
+-
+-/* tc35876x DSI-LVDS bridge chip and panel platform data */
+-static void *tc35876x_platform_data(void *data)
+-{
+- static struct tc35876x_platform_data pdata;
+-
+- /* gpio pins set to -1 will not be used by the driver */
+- pdata.gpio_bridge_reset = get_gpio_by_name("LCMB_RXEN");
+- pdata.gpio_panel_bl_en = get_gpio_by_name("6S6P_BL_EN");
+- pdata.gpio_panel_vadd = get_gpio_by_name("EN_VREG_LCD_V3P3");
+-
+- return &pdata;
+-}
+-
+-static const struct devs_id __initconst device_ids[] = {
+- {"bma023", SFI_DEV_TYPE_I2C, 1, &no_platform_data},
+- {"pmic_gpio", SFI_DEV_TYPE_SPI, 1, &pmic_gpio_platform_data},
+- {"pmic_gpio", SFI_DEV_TYPE_IPC, 1, &pmic_gpio_platform_data},
+- {"spi_max3111", SFI_DEV_TYPE_SPI, 0, &max3111_platform_data},
+- {"i2c_max7315", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data},
+- {"i2c_max7315_2", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data},
+- {"tca6416", SFI_DEV_TYPE_I2C, 1, &tca6416_platform_data},
+- {"emc1403", SFI_DEV_TYPE_I2C, 1, &emc1403_platform_data},
+- {"i2c_accel", SFI_DEV_TYPE_I2C, 0, &lis331dl_platform_data},
+- {"pmic_audio", SFI_DEV_TYPE_IPC, 1, &no_platform_data},
+- {"mpu3050", SFI_DEV_TYPE_I2C, 1, &mpu3050_platform_data},
+- {"i2c_disp_brig", SFI_DEV_TYPE_I2C, 0, &tc35876x_platform_data},
+-
+- /* MSIC subdevices */
+- {"msic_battery", SFI_DEV_TYPE_IPC, 1, &msic_battery_platform_data},
+- {"msic_gpio", SFI_DEV_TYPE_IPC, 1, &msic_gpio_platform_data},
+- {"msic_audio", SFI_DEV_TYPE_IPC, 1, &msic_audio_platform_data},
+- {"msic_power_btn", SFI_DEV_TYPE_IPC, 1, &msic_power_btn_platform_data},
+- {"msic_ocd", SFI_DEV_TYPE_IPC, 1, &msic_ocd_platform_data},
+- {"msic_thermal", SFI_DEV_TYPE_IPC, 1, &msic_thermal_platform_data},
+-
+- {},
+-};
+-
+-#define MAX_IPCDEVS 24
+-static struct platform_device *ipc_devs[MAX_IPCDEVS];
+-static int ipc_next_dev;
+-
+-#define MAX_SCU_SPI 24
+-static struct spi_board_info *spi_devs[MAX_SCU_SPI];
+-static int spi_next_dev;
+-
+-#define MAX_SCU_I2C 24
+-static struct i2c_board_info *i2c_devs[MAX_SCU_I2C];
+-static int i2c_bus[MAX_SCU_I2C];
+-static int i2c_next_dev;
+-
+-static void __init intel_scu_device_register(struct platform_device *pdev)
+-{
+- if(ipc_next_dev == MAX_IPCDEVS)
+- pr_err("too many SCU IPC devices");
+- else
+- ipc_devs[ipc_next_dev++] = pdev;
+-}
+-
+-static void __init intel_scu_spi_device_register(struct spi_board_info *sdev)
+-{
+- struct spi_board_info *new_dev;
+-
+- if (spi_next_dev == MAX_SCU_SPI) {
+- pr_err("too many SCU SPI devices");
+- return;
+- }
+-
+- new_dev = kzalloc(sizeof(*sdev), GFP_KERNEL);
+- if (!new_dev) {
+- pr_err("failed to alloc mem for delayed spi dev %s\n",
+- sdev->modalias);
+- return;
+- }
+- memcpy(new_dev, sdev, sizeof(*sdev));
+-
+- spi_devs[spi_next_dev++] = new_dev;
+-}
+-
+-static void __init intel_scu_i2c_device_register(int bus,
+- struct i2c_board_info *idev)
+-{
+- struct i2c_board_info *new_dev;
+-
+- if (i2c_next_dev == MAX_SCU_I2C) {
+- pr_err("too many SCU I2C devices");
+- return;
+- }
+-
+- new_dev = kzalloc(sizeof(*idev), GFP_KERNEL);
+- if (!new_dev) {
+- pr_err("failed to alloc mem for delayed i2c dev %s\n",
+- idev->type);
+- return;
+- }
+- memcpy(new_dev, idev, sizeof(*idev));
+-
+- i2c_bus[i2c_next_dev] = bus;
+- i2c_devs[i2c_next_dev++] = new_dev;
+-}
+-
+-BLOCKING_NOTIFIER_HEAD(intel_scu_notifier);
+-EXPORT_SYMBOL_GPL(intel_scu_notifier);
+-
+-/* Called by IPC driver */
+-void intel_scu_devices_create(void)
+-{
+- int i;
+-
+- for (i = 0; i < ipc_next_dev; i++)
+- platform_device_add(ipc_devs[i]);
+-
+- for (i = 0; i < spi_next_dev; i++)
+- spi_register_board_info(spi_devs[i], 1);
+-
+- for (i = 0; i < i2c_next_dev; i++) {
+- struct i2c_adapter *adapter;
+- struct i2c_client *client;
+-
+- adapter = i2c_get_adapter(i2c_bus[i]);
+- if (adapter) {
+- client = i2c_new_device(adapter, i2c_devs[i]);
+- if (!client)
+- pr_err("can't create i2c device %s\n",
+- i2c_devs[i]->type);
+- } else
+- i2c_register_board_info(i2c_bus[i], i2c_devs[i], 1);
+- }
+- intel_scu_notifier_post(SCU_AVAILABLE, NULL);
+-}
+-EXPORT_SYMBOL_GPL(intel_scu_devices_create);
+-
+-/* Called by IPC driver */
+-void intel_scu_devices_destroy(void)
+-{
+- int i;
+-
+- intel_scu_notifier_post(SCU_DOWN, NULL);
+-
+- for (i = 0; i < ipc_next_dev; i++)
+- platform_device_del(ipc_devs[i]);
+-}
+-EXPORT_SYMBOL_GPL(intel_scu_devices_destroy);
+-
+-static void __init install_irq_resource(struct platform_device *pdev, int irq)
+-{
+- /* Single threaded */
+- static struct resource __initdata res = {
+- .name = "IRQ",
+- .flags = IORESOURCE_IRQ,
+- };
+- res.start = irq;
+- platform_device_add_resources(pdev, &res, 1);
+-}
+-
+-static void __init sfi_handle_ipc_dev(struct sfi_device_table_entry *entry)
+-{
+- const struct devs_id *dev = device_ids;
+- struct platform_device *pdev;
+- void *pdata = NULL;
+-
+- while (dev->name[0]) {
+- if (dev->type == SFI_DEV_TYPE_IPC &&
+- !strncmp(dev->name, entry->name, SFI_NAME_LEN)) {
+- pdata = dev->get_platform_data(entry);
+- break;
+- }
+- dev++;
+- }
+-
+- /*
+- * On Medfield the platform device creation is handled by the MSIC
+- * MFD driver so we don't need to do it here.
+- */
+- if (mrst_has_msic())
+- return;
+-
+- pdev = platform_device_alloc(entry->name, 0);
+- if (pdev == NULL) {
+- pr_err("out of memory for SFI platform device '%s'.\n",
+- entry->name);
+- return;
+- }
+- install_irq_resource(pdev, entry->irq);
+-
+- pdev->dev.platform_data = pdata;
+- intel_scu_device_register(pdev);
+-}
+-
+-static void __init sfi_handle_spi_dev(struct spi_board_info *spi_info)
+-{
+- const struct devs_id *dev = device_ids;
+- void *pdata = NULL;
+-
+- while (dev->name[0]) {
+- if (dev->type == SFI_DEV_TYPE_SPI &&
+- !strncmp(dev->name, spi_info->modalias, SFI_NAME_LEN)) {
+- pdata = dev->get_platform_data(spi_info);
+- break;
+- }
+- dev++;
+- }
+- spi_info->platform_data = pdata;
+- if (dev->delay)
+- intel_scu_spi_device_register(spi_info);
+- else
+- spi_register_board_info(spi_info, 1);
+-}
+-
+-static void __init sfi_handle_i2c_dev(int bus, struct i2c_board_info *i2c_info)
+-{
+- const struct devs_id *dev = device_ids;
+- void *pdata = NULL;
+-
+- while (dev->name[0]) {
+- if (dev->type == SFI_DEV_TYPE_I2C &&
+- !strncmp(dev->name, i2c_info->type, SFI_NAME_LEN)) {
+- pdata = dev->get_platform_data(i2c_info);
+- break;
+- }
+- dev++;
+- }
+- i2c_info->platform_data = pdata;
+-
+- if (dev->delay)
+- intel_scu_i2c_device_register(bus, i2c_info);
+- else
+- i2c_register_board_info(bus, i2c_info, 1);
+- }
+-
+-
+-static int __init sfi_parse_devs(struct sfi_table_header *table)
+-{
+- struct sfi_table_simple *sb;
+- struct sfi_device_table_entry *pentry;
+- struct spi_board_info spi_info;
+- struct i2c_board_info i2c_info;
+- int num, i, bus;
+- int ioapic;
+- struct io_apic_irq_attr irq_attr;
+-
+- sb = (struct sfi_table_simple *)table;
+- num = SFI_GET_NUM_ENTRIES(sb, struct sfi_device_table_entry);
+- pentry = (struct sfi_device_table_entry *)sb->pentry;
+-
+- for (i = 0; i < num; i++, pentry++) {
+- int irq = pentry->irq;
+-
+- if (irq != (u8)0xff) { /* native RTE case */
+- /* these SPI2 devices are not exposed to system as PCI
+- * devices, but they have separate RTE entry in IOAPIC
+- * so we have to enable them one by one here
+- */
+- ioapic = mp_find_ioapic(irq);
+- irq_attr.ioapic = ioapic;
+- irq_attr.ioapic_pin = irq;
+- irq_attr.trigger = 1;
+- irq_attr.polarity = 1;
+- io_apic_set_pci_routing(NULL, irq, &irq_attr);
+- } else
+- irq = 0; /* No irq */
+-
+- switch (pentry->type) {
+- case SFI_DEV_TYPE_IPC:
+- pr_debug("info[%2d]: IPC bus, name = %16.16s, "
+- "irq = 0x%2x\n", i, pentry->name, pentry->irq);
+- sfi_handle_ipc_dev(pentry);
+- break;
+- case SFI_DEV_TYPE_SPI:
+- memset(&spi_info, 0, sizeof(spi_info));
+- strncpy(spi_info.modalias, pentry->name, SFI_NAME_LEN);
+- spi_info.irq = irq;
+- spi_info.bus_num = pentry->host_num;
+- spi_info.chip_select = pentry->addr;
+- spi_info.max_speed_hz = pentry->max_freq;
+- pr_debug("info[%2d]: SPI bus = %d, name = %16.16s, "
+- "irq = 0x%2x, max_freq = %d, cs = %d\n", i,
+- spi_info.bus_num,
+- spi_info.modalias,
+- spi_info.irq,
+- spi_info.max_speed_hz,
+- spi_info.chip_select);
+- sfi_handle_spi_dev(&spi_info);
+- break;
+- case SFI_DEV_TYPE_I2C:
+- memset(&i2c_info, 0, sizeof(i2c_info));
+- bus = pentry->host_num;
+- strncpy(i2c_info.type, pentry->name, SFI_NAME_LEN);
+- i2c_info.irq = irq;
+- i2c_info.addr = pentry->addr;
+- pr_debug("info[%2d]: I2C bus = %d, name = %16.16s, "
+- "irq = 0x%2x, addr = 0x%x\n", i, bus,
+- i2c_info.type,
+- i2c_info.irq,
+- i2c_info.addr);
+- sfi_handle_i2c_dev(bus, &i2c_info);
+- break;
+- case SFI_DEV_TYPE_UART:
+- case SFI_DEV_TYPE_HSI:
+- default:
+- ;
+- }
+- }
+- return 0;
+-}
+-
+-static int __init mrst_platform_init(void)
+-{
+- sfi_table_parse(SFI_SIG_GPIO, NULL, NULL, sfi_parse_gpio);
+- sfi_table_parse(SFI_SIG_DEVS, NULL, NULL, sfi_parse_devs);
+- return 0;
+-}
+-arch_initcall(mrst_platform_init);
+-
+-/*
+- * we will search these buttons in SFI GPIO table (by name)
+- * and register them dynamically. Please add all possible
+- * buttons here, we will shrink them if no GPIO found.
+- */
+-static struct gpio_keys_button gpio_button[] = {
+- {KEY_POWER, -1, 1, "power_btn", EV_KEY, 0, 3000},
+- {KEY_PROG1, -1, 1, "prog_btn1", EV_KEY, 0, 20},
+- {KEY_PROG2, -1, 1, "prog_btn2", EV_KEY, 0, 20},
+- {SW_LID, -1, 1, "lid_switch", EV_SW, 0, 20},
+- {KEY_VOLUMEUP, -1, 1, "vol_up", EV_KEY, 0, 20},
+- {KEY_VOLUMEDOWN, -1, 1, "vol_down", EV_KEY, 0, 20},
+- {KEY_CAMERA, -1, 1, "camera_full", EV_KEY, 0, 20},
+- {KEY_CAMERA_FOCUS, -1, 1, "camera_half", EV_KEY, 0, 20},
+- {SW_KEYPAD_SLIDE, -1, 1, "MagSw1", EV_SW, 0, 20},
+- {SW_KEYPAD_SLIDE, -1, 1, "MagSw2", EV_SW, 0, 20},
+-};
+-
+-static struct gpio_keys_platform_data mrst_gpio_keys = {
+- .buttons = gpio_button,
+- .rep = 1,
+- .nbuttons = -1, /* will fill it after search */
+-};
+-
+-static struct platform_device pb_device = {
+- .name = "gpio-keys",
+- .id = -1,
+- .dev = {
+- .platform_data = &mrst_gpio_keys,
+- },
+-};
+-
+-/*
+- * Shrink the non-existent buttons, register the gpio button
+- * device if there is some
+- */
+-static int __init pb_keys_init(void)
+-{
+- struct gpio_keys_button *gb = gpio_button;
+- int i, num, good = 0;
+-
+- num = sizeof(gpio_button) / sizeof(struct gpio_keys_button);
+- for (i = 0; i < num; i++) {
+- gb[i].gpio = get_gpio_by_name(gb[i].desc);
+- pr_debug("info[%2d]: name = %s, gpio = %d\n", i, gb[i].desc, gb[i].gpio);
+- if (gb[i].gpio == -1)
+- continue;
+-
+- if (i != good)
+- gb[good] = gb[i];
+- good++;
+- }
+-
+- if (good) {
+- mrst_gpio_keys.nbuttons = good;
+- return platform_device_register(&pb_device);
+- }
+- return 0;
+-}
+-late_initcall(pb_keys_init);
+diff --git a/arch/x86/platform/mrst/vrtc.c b/arch/x86/platform/mrst/vrtc.c
+deleted file mode 100644
+index d62b0a3..0000000
+--- a/arch/x86/platform/mrst/vrtc.c
++++ /dev/null
+@@ -1,177 +0,0 @@
+-/*
+- * vrtc.c: Driver for virtual RTC device on Intel MID platform
+- *
+- * (C) Copyright 2009 Intel Corporation
+- *
+- * 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; version 2
+- * of the License.
+- *
+- * Note:
+- * VRTC is emulated by system controller firmware, the real HW
+- * RTC is located in the PMIC device. SCU FW shadows PMIC RTC
+- * in a memory mapped IO space that is visible to the host IA
+- * processor.
+- *
+- * This driver is based on RTC CMOS driver.
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/export.h>
+-#include <linux/init.h>
+-#include <linux/sfi.h>
+-#include <linux/platform_device.h>
+-
+-#include <asm/mrst.h>
+-#include <asm/mrst-vrtc.h>
+-#include <asm/time.h>
+-#include <asm/fixmap.h>
+-
+-static unsigned char __iomem *vrtc_virt_base;
+-
+-unsigned char vrtc_cmos_read(unsigned char reg)
+-{
+- unsigned char retval;
+-
+- /* vRTC's registers range from 0x0 to 0xD */
+- if (reg > 0xd || !vrtc_virt_base)
+- return 0xff;
+-
+- lock_cmos_prefix(reg);
+- retval = __raw_readb(vrtc_virt_base + (reg << 2));
+- lock_cmos_suffix(reg);
+- return retval;
+-}
+-EXPORT_SYMBOL_GPL(vrtc_cmos_read);
+-
+-void vrtc_cmos_write(unsigned char val, unsigned char reg)
+-{
+- if (reg > 0xd || !vrtc_virt_base)
+- return;
+-
+- lock_cmos_prefix(reg);
+- __raw_writeb(val, vrtc_virt_base + (reg << 2));
+- lock_cmos_suffix(reg);
+-}
+-EXPORT_SYMBOL_GPL(vrtc_cmos_write);
+-
+-unsigned long vrtc_get_time(void)
+-{
+- u8 sec, min, hour, mday, mon;
+- unsigned long flags;
+- u32 year;
+-
+- spin_lock_irqsave(&rtc_lock, flags);
+-
+- while ((vrtc_cmos_read(RTC_FREQ_SELECT) & RTC_UIP))
+- cpu_relax();
+-
+- sec = vrtc_cmos_read(RTC_SECONDS);
+- min = vrtc_cmos_read(RTC_MINUTES);
+- hour = vrtc_cmos_read(RTC_HOURS);
+- mday = vrtc_cmos_read(RTC_DAY_OF_MONTH);
+- mon = vrtc_cmos_read(RTC_MONTH);
+- year = vrtc_cmos_read(RTC_YEAR);
+-
+- spin_unlock_irqrestore(&rtc_lock, flags);
+-
+- /* vRTC YEAR reg contains the offset to 1972 */
+- year += 1972;
+-
+- printk(KERN_INFO "vRTC: sec: %d min: %d hour: %d day: %d "
+- "mon: %d year: %d\n", sec, min, hour, mday, mon, year);
+-
+- return mktime(year, mon, mday, hour, min, sec);
+-}
+-
+-int vrtc_set_mmss(unsigned long nowtime)
+-{
+- unsigned long flags;
+- struct rtc_time tm;
+- int year;
+- int retval = 0;
+-
+- rtc_time_to_tm(nowtime, &tm);
+- if (!rtc_valid_tm(&tm) && tm.tm_year >= 72) {
+- /*
+- * tm.year is the number of years since 1900, and the
+- * vrtc need the years since 1972.
+- */
+- year = tm.tm_year - 72;
+- spin_lock_irqsave(&rtc_lock, flags);
+- vrtc_cmos_write(year, RTC_YEAR);
+- vrtc_cmos_write(tm.tm_mon, RTC_MONTH);
+- vrtc_cmos_write(tm.tm_mday, RTC_DAY_OF_MONTH);
+- vrtc_cmos_write(tm.tm_hour, RTC_HOURS);
+- vrtc_cmos_write(tm.tm_min, RTC_MINUTES);
+- vrtc_cmos_write(tm.tm_sec, RTC_SECONDS);
+- spin_unlock_irqrestore(&rtc_lock, flags);
+- } else {
+- printk(KERN_ERR
+- "%s: Invalid vRTC value: write of %lx to vRTC failed\n",
+- __FUNCTION__, nowtime);
+- retval = -EINVAL;
+- }
+- return retval;
+-}
+-
+-void __init mrst_rtc_init(void)
+-{
+- unsigned long vrtc_paddr;
+-
+- sfi_table_parse(SFI_SIG_MRTC, NULL, NULL, sfi_parse_mrtc);
+-
+- vrtc_paddr = sfi_mrtc_array[0].phys_addr;
+- if (!sfi_mrtc_num || !vrtc_paddr)
+- return;
+-
+- vrtc_virt_base = (void __iomem *)set_fixmap_offset_nocache(FIX_LNW_VRTC,
+- vrtc_paddr);
+- x86_platform.get_wallclock = vrtc_get_time;
+- x86_platform.set_wallclock = vrtc_set_mmss;
+-}
+-
+-/*
+- * The Moorestown platform has a memory mapped virtual RTC device that emulates
+- * the programming interface of the RTC.
+- */
+-
+-static struct resource vrtc_resources[] = {
+- [0] = {
+- .flags = IORESOURCE_MEM,
+- },
+- [1] = {
+- .flags = IORESOURCE_IRQ,
+- }
+-};
+-
+-static struct platform_device vrtc_device = {
+- .name = "rtc_mrst",
+- .id = -1,
+- .resource = vrtc_resources,
+- .num_resources = ARRAY_SIZE(vrtc_resources),
+-};
+-
+-/* Register the RTC device if appropriate */
+-static int __init mrst_device_create(void)
+-{
+- /* No Moorestown, no device */
+- if (!mrst_identify_cpu())
+- return -ENODEV;
+- /* No timer, no device */
+- if (!sfi_mrtc_num)
+- return -ENODEV;
+-
+- /* iomem resource */
+- vrtc_resources[0].start = sfi_mrtc_array[0].phys_addr;
+- vrtc_resources[0].end = sfi_mrtc_array[0].phys_addr +
+- MRST_VRTC_MAP_SZ;
+- /* irq resource */
+- vrtc_resources[1].start = sfi_mrtc_array[0].irq;
+- vrtc_resources[1].end = sfi_mrtc_array[0].irq;
+-
+- return platform_device_register(&vrtc_device);
+-}
+-
+-module_init(mrst_device_create);
+diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
+index fafec5d..e355255 100644
+--- a/drivers/acpi/acpi_platform.c
++++ b/drivers/acpi/acpi_platform.c
+@@ -29,7 +29,8 @@ ACPI_MODULE_NAME("platform");
+ static const struct acpi_device_id acpi_platform_device_ids[] = {
+
+ { "PNP0D40" },
+-
++ { "BCM43241" },
++ { "BCM2E1A" },
+ { }
+ };
+
+diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
+index e721863..1c25863 100644
+--- a/drivers/acpi/osl.c
++++ b/drivers/acpi/osl.c
+@@ -710,6 +710,11 @@ acpi_os_physical_table_override(struct acpi_table_header *existing_table,
+ table = acpi_os_map_memory(acpi_tables_addr + table_offset,
+ ACPI_HEADER_SIZE);
+
++ if (table == NULL) {
++ pr_err("Error mapping ACPI memory\n");
++ return AE_ERROR;
++ }
++
+ if (table_offset + table->length > all_tables_size) {
+ acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
+ WARN_ON(1);
+diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
+index bc68a44..c02e129 100644
+--- a/drivers/bluetooth/hci_ldisc.c
++++ b/drivers/bluetooth/hci_ldisc.c
+@@ -118,10 +118,6 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu)
+
+ int hci_uart_tx_wakeup(struct hci_uart *hu)
+ {
+- struct tty_struct *tty = hu->tty;
+- struct hci_dev *hdev = hu->hdev;
+- struct sk_buff *skb;
+-
+ if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) {
+ set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
+ return 0;
+@@ -129,6 +125,22 @@ int hci_uart_tx_wakeup(struct hci_uart *hu)
+
+ BT_DBG("");
+
++ schedule_work(&hu->write_work);
++
++ return 0;
++}
++
++static void hci_uart_write_work(struct work_struct *work)
++{
++ struct hci_uart *hu = container_of(work, struct hci_uart, write_work);
++ struct tty_struct *tty = hu->tty;
++ struct hci_dev *hdev = hu->hdev;
++ struct sk_buff *skb;
++
++ /* REVISIT: should we cope with bad skbs or ->write() returning
++ * and error value ?
++ */
++
+ restart:
+ clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
+
+@@ -153,7 +165,7 @@ restart:
+ goto restart;
+
+ clear_bit(HCI_UART_SENDING, &hu->tx_state);
+- return 0;
++
+ }
+
+ static void hci_uart_init_work(struct work_struct *work)
+@@ -289,6 +301,7 @@ static int hci_uart_tty_open(struct tty_struct *tty)
+ tty->receive_room = 65536;
+
+ INIT_WORK(&hu->init_ready, hci_uart_init_work);
++ INIT_WORK(&hu->write_work, hci_uart_write_work);
+
+ spin_lock_init(&hu->rx_lock);
+
+@@ -326,6 +339,8 @@ static void hci_uart_tty_close(struct tty_struct *tty)
+ if (hdev)
+ hci_uart_close(hdev);
+
++ cancel_work_sync(&hu->write_work);
++
+ if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
+ if (hdev) {
+ if (test_bit(HCI_UART_REGISTERED, &hu->flags))
+diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
+index fffa61f..12df101 100644
+--- a/drivers/bluetooth/hci_uart.h
++++ b/drivers/bluetooth/hci_uart.h
+@@ -68,6 +68,7 @@ struct hci_uart {
+ unsigned long hdev_flags;
+
+ struct work_struct init_ready;
++ struct work_struct write_work;
+
+ struct hci_uart_proto *proto;
+ void *priv;
+diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86
+index 6bd63d6..2a9d25e 100644
+--- a/drivers/cpufreq/Kconfig.x86
++++ b/drivers/cpufreq/Kconfig.x86
+@@ -58,6 +58,21 @@ config X86_ACPI_CPUFREQ_CPB
+ By enabling this option the acpi_cpufreq driver provides the old
+ entry in addition to the new boost ones, for compatibility reasons.
+
++config X86_SFI_CPUFREQ
++ tristate "SFI Processor P-States driver"
++ select CPU_FREQ_TABLE
++ depends on SFI
++ help
++ This driver adds a CPUFreq driver which utilizes the SFI
++ Processor Performance States enumeration.
++
++ To compile this driver as a module, choose M here: the
++ module will be called sfi-cpufreq.
++
++ For details, take a look at <file:Documentation/cpu-freq/>.
++
++ If in doubt, say N.
++
+ config ELAN_CPUFREQ
+ tristate "AMD Elan SC400 and SC410"
+ select CPU_FREQ_TABLE
+diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
+index 315b923..b1c516f 100644
+--- a/drivers/cpufreq/Makefile
++++ b/drivers/cpufreq/Makefile
+@@ -25,6 +25,7 @@ obj-$(CONFIG_GENERIC_CPUFREQ_CPU0) += cpufreq-cpu0.o
+
+ obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o mperf.o
+ obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o
++obj-$(CONFIG_X86_SFI_CPUFREQ) += sfi-cpufreq.o mperf.o
+ obj-$(CONFIG_X86_PCC_CPUFREQ) += pcc-cpufreq.o
+ obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o
+ obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o
+diff --git a/drivers/cpufreq/sfi-cpufreq.c b/drivers/cpufreq/sfi-cpufreq.c
+new file mode 100644
+index 0000000..2f9f9a2
+--- /dev/null
++++ b/drivers/cpufreq/sfi-cpufreq.c
+@@ -0,0 +1,581 @@
++/*
++ * sfi_cpufreq.c - sfi Processor P-States Driver
++ *
++ * (C) 2010-2011 Intel Corporation
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ * Author: Vishwesh M Rudramuni
++ * Contact information: Vishwesh Rudramuni <vishwesh.m.rudramuni@intel.com>
++ */
++
++/*
++ * This sfi Processor P-States Driver re-uses most part of the code available
++ * in acpi cpufreq driver.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/smp.h>
++#include <linux/sched.h>
++#include <linux/cpufreq.h>
++#include <linux/compiler.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/uaccess.h>
++#include <linux/sfi.h>
++#include <linux/io.h>
++
++#include <asm/msr.h>
++#include <asm/processor.h>
++#include <asm/cpufeature.h>
++
++#include "sfi-cpufreq.h"
++#include "mperf.h"
++
++MODULE_AUTHOR("Vishwesh Rudramuni");
++MODULE_DESCRIPTION("SFI Processor P-States Driver");
++MODULE_LICENSE("GPL");
++
++DEFINE_PER_CPU(struct sfi_processor *, sfi_processors);
++
++static DEFINE_MUTEX(performance_mutex);
++static int sfi_cpufreq_num;
++static u32 sfi_cpu_num;
++
++#define SFI_FREQ_MAX 32
++#define INTEL_MSR_RANGE 0xffff
++#define INTEL_MSR_BUSRATIO_MASK 0xff00
++#define SFI_CPU_MAX 8
++
++#define X86_ATOM_ARCH_SLM 0x4a
++
++struct sfi_cpufreq_data {
++ struct sfi_processor_performance *sfi_data;
++ struct cpufreq_frequency_table *freq_table;
++ unsigned int max_freq;
++ unsigned int resume;
++};
++
++static DEFINE_PER_CPU(struct sfi_cpufreq_data *, drv_data);
++struct sfi_freq_table_entry sfi_cpufreq_array[SFI_FREQ_MAX];
++static struct sfi_cpu_table_entry sfi_cpu_array[SFI_CPU_MAX];
++
++/* sfi_perf_data is a pointer to percpu data. */
++static struct sfi_processor_performance *sfi_perf_data;
++
++static struct cpufreq_driver sfi_cpufreq_driver;
++
++static int parse_freq(struct sfi_table_header *table)
++{
++ struct sfi_table_simple *sb;
++ struct sfi_freq_table_entry *pentry;
++ int totallen;
++
++ sb = (struct sfi_table_simple *)table;
++ if (!sb) {
++ printk(KERN_WARNING "SFI: Unable to map FREQ\n");
++ return -ENODEV;
++ }
++
++ if (!sfi_cpufreq_num) {
++ sfi_cpufreq_num = SFI_GET_NUM_ENTRIES(sb,
++ struct sfi_freq_table_entry);
++ pentry = (struct sfi_freq_table_entry *)sb->pentry;
++ totallen = sfi_cpufreq_num * sizeof(*pentry);
++ memcpy(sfi_cpufreq_array, pentry, totallen);
++ }
++
++ return 0;
++}
++
++static int sfi_processor_get_performance_states(struct sfi_processor *pr)
++{
++ int result = 0;
++ int i;
++
++ pr->performance->state_count = sfi_cpufreq_num;
++ pr->performance->states =
++ kmalloc(sizeof(struct sfi_processor_px) * sfi_cpufreq_num,
++ GFP_KERNEL);
++ if (!pr->performance->states)
++ result = -ENOMEM;
++
++ printk(KERN_INFO "Num p-states %d\n", sfi_cpufreq_num);
++
++ /* Populate the P-states info from the SFI table here */
++ for (i = 0; i < sfi_cpufreq_num; i++) {
++ pr->performance->states[i].core_frequency =
++ sfi_cpufreq_array[i].freq_mhz;
++ pr->performance->states[i].transition_latency =
++ sfi_cpufreq_array[i].latency;
++ pr->performance->states[i].control =
++ sfi_cpufreq_array[i].ctrl_val;
++ printk(KERN_INFO "State [%d]: core_frequency[%d] transition_latency[%d] control[0x%x]\n",
++ i,
++ (u32) pr->performance->states[i].core_frequency,
++ (u32) pr->performance->states[i].transition_latency,
++ (u32) pr->performance->states[i].control);
++ }
++
++ return result;
++}
++
++static int sfi_processor_register_performance(struct sfi_processor_performance
++ *performance, unsigned int cpu)
++{
++ struct sfi_processor *pr;
++
++ mutex_lock(&performance_mutex);
++
++ pr = per_cpu(sfi_processors, cpu);
++ if (!pr) {
++ mutex_unlock(&performance_mutex);
++ return -ENODEV;
++ }
++
++ if (pr->performance) {
++ mutex_unlock(&performance_mutex);
++ return -EBUSY;
++ }
++
++ WARN_ON(!performance);
++
++ pr->performance = performance;
++
++ /* parse the freq table from sfi */
++ sfi_cpufreq_num = 0;
++ sfi_table_parse(SFI_SIG_FREQ, NULL, NULL, parse_freq);
++
++ sfi_processor_get_performance_states(pr);
++
++ mutex_unlock(&performance_mutex);
++ return 0;
++}
++
++void sfi_processor_unregister_performance(struct sfi_processor_performance
++ *performance, unsigned int cpu)
++{
++ struct sfi_processor *pr;
++
++
++ mutex_lock(&performance_mutex);
++
++ pr = per_cpu(sfi_processors, cpu);
++ if (!pr) {
++ mutex_unlock(&performance_mutex);
++ return;
++ }
++
++ if (pr->performance)
++ kfree(pr->performance->states);
++ pr->performance = NULL;
++
++ mutex_unlock(&performance_mutex);
++
++ return;
++}
++
++static unsigned extract_freq(u32 msr, struct sfi_cpufreq_data *data)
++{
++ int i;
++ struct sfi_processor_performance *perf;
++ u32 sfi_ctrl;
++
++ msr &= INTEL_MSR_BUSRATIO_MASK;
++ perf = data->sfi_data;
++
++ for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
++ sfi_ctrl = perf->states[data->freq_table[i].index].control
++ & INTEL_MSR_BUSRATIO_MASK;
++ if (sfi_ctrl == msr)
++ return data->freq_table[i].frequency;
++ }
++ return data->freq_table[0].frequency;
++}
++
++
++static u32 get_cur_val(const struct cpumask *mask)
++{
++ u32 val, dummy;
++
++ if (unlikely(cpumask_empty(mask)))
++ return 0;
++
++ rdmsr_on_cpu(cpumask_any(mask), MSR_IA32_PERF_STATUS, &val, &dummy);
++
++ return val;
++}
++
++static unsigned int get_cur_freq_on_cpu(unsigned int cpu)
++{
++ struct sfi_cpufreq_data *data = per_cpu(drv_data, cpu);
++ unsigned int freq;
++ unsigned int cached_freq;
++
++ pr_debug("get_cur_freq_on_cpu (%d)\n", cpu);
++
++ if (unlikely(data == NULL ||
++ data->sfi_data == NULL || data->freq_table == NULL)) {
++ return 0;
++ }
++
++ cached_freq = data->freq_table[data->sfi_data->state].frequency;
++ freq = extract_freq(get_cur_val(cpumask_of(cpu)), data);
++ if (freq != cached_freq) {
++ /*
++ * The dreaded BIOS frequency change behind our back.
++ * Force set the frequency on next target call.
++ */
++ data->resume = 1;
++ }
++
++ pr_debug("cur freq = %u\n", freq);
++
++ return freq;
++}
++
++static int sfi_cpufreq_target(struct cpufreq_policy *policy,
++ unsigned int target_freq, unsigned int relation)
++{
++ struct sfi_cpufreq_data *data = per_cpu(drv_data, policy->cpu);
++ struct sfi_processor_performance *perf;
++ struct cpufreq_freqs freqs;
++ unsigned int next_state = 0; /* Index into freq_table */
++ unsigned int next_perf_state = 0; /* Index into perf table */
++ int result = 0;
++ u32 lo, hi;
++
++ pr_debug("sfi_cpufreq_target %d (%d)\n", target_freq, policy->cpu);
++
++ if (unlikely(data == NULL ||
++ data->sfi_data == NULL || data->freq_table == NULL)) {
++ return -ENODEV;
++ }
++
++ perf = data->sfi_data;
++ result = cpufreq_frequency_table_target(policy,
++ data->freq_table,
++ target_freq,
++ relation, &next_state);
++ if (unlikely(result))
++ return -ENODEV;
++
++ next_perf_state = data->freq_table[next_state].index;
++ if (perf->state == next_perf_state) {
++ if (unlikely(data->resume)) {
++ pr_debug("Called after resume, resetting to P%d\n",
++ next_perf_state);
++ data->resume = 0;
++ } else {
++ pr_debug("Already at target state (P%d)\n",
++ next_perf_state);
++ return 0;
++ }
++ }
++
++ freqs.old = perf->states[perf->state].core_frequency * 1000;
++ freqs.new = data->freq_table[next_state].frequency;
++
++ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
++
++ rdmsr_on_cpu(policy->cpu, MSR_IA32_PERF_CTL, &lo, &hi);
++ lo = (lo & ~INTEL_MSR_RANGE) |
++ ((u32) perf->states[next_perf_state].control & INTEL_MSR_RANGE);
++ wrmsr_on_cpu(policy->cpu, MSR_IA32_PERF_CTL, lo, hi);
++
++
++ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
++ perf->state = next_perf_state;
++
++ return result;
++}
++
++static int sfi_cpufreq_verify(struct cpufreq_policy *policy)
++{
++ struct sfi_cpufreq_data *data = per_cpu(drv_data, policy->cpu);
++
++ pr_debug("sfi_cpufreq_verify\n");
++
++ return cpufreq_frequency_table_verify(policy, data->freq_table);
++}
++
++/*
++ * sfi_cpufreq_early_init - initialize SFI P-States library
++ *
++ * Initialize the SFI P-States library (drivers/sfi/processor_perflib.c)
++ * in order to cope with the correct frequency and voltage pairings.
++ */
++static int __init sfi_cpufreq_early_init(void)
++{
++ sfi_perf_data = alloc_percpu(struct sfi_processor_performance);
++ if (!sfi_perf_data) {
++ pr_debug("Memory allocation error for sfi_perf_data.\n");
++ return -ENOMEM;
++ }
++
++ return 0;
++}
++
++
++static int sfi_cpufreq_cpu_init(struct cpufreq_policy *policy)
++{
++ unsigned int i;
++ unsigned int valid_states = 0;
++ unsigned int cpu = policy->cpu;
++ struct sfi_cpufreq_data *data;
++ unsigned int result = 0;
++ struct cpuinfo_x86 *c = &cpu_data(policy->cpu);
++ struct sfi_processor_performance *perf;
++ u32 lo, hi;
++
++ pr_debug("sfi_cpufreq_cpu_init CPU:%d\n", policy->cpu);
++
++ data = kzalloc(sizeof(struct sfi_cpufreq_data), GFP_KERNEL);
++ if (!data)
++ return -ENOMEM;
++
++ data->sfi_data = per_cpu_ptr(sfi_perf_data, cpu);
++ per_cpu(drv_data, cpu) = data;
++
++ sfi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS;
++
++
++ result = sfi_processor_register_performance(data->sfi_data, cpu);
++ if (result)
++ goto err_free;
++
++ perf = data->sfi_data;
++ policy->shared_type = CPUFREQ_SHARED_TYPE_HW;
++
++ cpumask_set_cpu(policy->cpu, policy->cpus);
++ cpumask_set_cpu(policy->cpu, policy->related_cpus);
++
++ /* capability check */
++ if (perf->state_count <= 1) {
++ pr_debug("No P-States\n");
++ result = -ENODEV;
++ goto err_unreg;
++ }
++
++ data->freq_table = kzalloc(sizeof(struct cpufreq_frequency_table) *
++ (perf->state_count+1), GFP_KERNEL);
++ if (!data->freq_table) {
++ result = -ENOMEM;
++ goto err_unreg;
++ }
++
++ /* detect transition latency */
++ policy->cpuinfo.transition_latency = 0;
++ for (i = 0; i < perf->state_count; i++) {
++ if ((perf->states[i].transition_latency * 1000) >
++ policy->cpuinfo.transition_latency)
++ policy->cpuinfo.transition_latency =
++ perf->states[i].transition_latency * 1000;
++ }
++
++ data->max_freq = perf->states[0].core_frequency * 1000;
++ /* table init */
++ for (i = 0; i < perf->state_count; i++) {
++ if (i > 0 && perf->states[i].core_frequency >=
++ data->freq_table[valid_states-1].frequency / 1000)
++ continue;
++
++ data->freq_table[valid_states].index = i;
++ data->freq_table[valid_states].frequency =
++ perf->states[i].core_frequency * 1000;
++ valid_states++;
++ }
++ data->freq_table[valid_states].frequency = CPUFREQ_TABLE_END;
++ perf->state = 0;
++
++ result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table);
++ if (result)
++ goto err_freqfree;
++
++ policy->cur = get_cur_freq_on_cpu(cpu);
++
++
++ /* Check for APERF/MPERF support in hardware */
++ if (cpu_has(c, X86_FEATURE_APERFMPERF))
++ sfi_cpufreq_driver.getavg = cpufreq_get_measured_perf;
++
++ /* enable eHALT for SLM */
++ if (boot_cpu_data.x86_model == X86_ATOM_ARCH_SLM) {
++ rdmsr_on_cpu(policy->cpu, MSR_IA32_POWER_MISC, &lo, &hi);
++ lo = lo | ENABLE_ULFM_AUTOCM | ENABLE_INDP_AUTOCM;
++ wrmsr_on_cpu(policy->cpu, MSR_IA32_POWER_MISC, lo, hi);
++ }
++
++ pr_debug("CPU%u - SFI performance management activated.\n", cpu);
++ for (i = 0; i < perf->state_count; i++)
++ pr_debug(" %cP%d: %d MHz, %d uS\n",
++ (i == perf->state ? '*' : ' '), i,
++ (u32) perf->states[i].core_frequency,
++ (u32) perf->states[i].transition_latency);
++
++ cpufreq_frequency_table_get_attr(data->freq_table, policy->cpu);
++
++ /*
++ * the first call to ->target() should result in us actually
++ * writing something to the appropriate registers.
++ */
++ data->resume = 1;
++
++ return result;
++
++err_freqfree:
++ kfree(data->freq_table);
++err_unreg:
++ sfi_processor_unregister_performance(perf, cpu);
++err_free:
++ kfree(data);
++ per_cpu(drv_data, cpu) = NULL;
++
++ return result;
++}
++
++static int sfi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
++{
++ struct sfi_cpufreq_data *data = per_cpu(drv_data, policy->cpu);
++
++ pr_debug("sfi_cpufreq_cpu_exit\n");
++
++ if (data) {
++ cpufreq_frequency_table_put_attr(policy->cpu);
++ per_cpu(drv_data, policy->cpu) = NULL;
++ sfi_processor_unregister_performance(data->sfi_data,
++ policy->cpu);
++ kfree(data->freq_table);
++ kfree(data);
++ }
++
++ return 0;
++}
++
++static int sfi_cpufreq_resume(struct cpufreq_policy *policy)
++{
++ struct sfi_cpufreq_data *data = per_cpu(drv_data, policy->cpu);
++
++ pr_debug("sfi_cpufreq_resume\n");
++
++ data->resume = 1;
++
++ return 0;
++}
++
++static struct freq_attr *sfi_cpufreq_attr[] = {
++ &cpufreq_freq_attr_scaling_available_freqs,
++ NULL,
++};
++
++static struct cpufreq_driver sfi_cpufreq_driver = {
++ .get = get_cur_freq_on_cpu,
++ .verify = sfi_cpufreq_verify,
++ .target = sfi_cpufreq_target,
++ .init = sfi_cpufreq_cpu_init,
++ .exit = sfi_cpufreq_cpu_exit,
++ .resume = sfi_cpufreq_resume,
++ .name = "sfi-cpufreq",
++ .owner = THIS_MODULE,
++ .attr = sfi_cpufreq_attr,
++};
++
++static int __init parse_cpus(struct sfi_table_header *table)
++{
++ struct sfi_table_simple *sb;
++ struct sfi_cpu_table_entry *pentry;
++ int i;
++
++ sb = (struct sfi_table_simple *)table;
++
++ sfi_cpu_num = SFI_GET_NUM_ENTRIES(sb, struct sfi_cpu_table_entry);
++
++ pentry = (struct sfi_cpu_table_entry *) sb->pentry;
++ for (i = 0; i < sfi_cpu_num; i++) {
++ sfi_cpu_array[i].apic_id = pentry->apic_id;
++ printk(KERN_INFO "APIC ID: %d\n", pentry->apic_id);
++ pentry++;
++ }
++
++ return 0;
++
++}
++
++
++static int __init init_sfi_processor_list(void)
++{
++ struct sfi_processor *pr;
++ int i;
++ int result;
++
++ /* parse the cpus from the sfi table */
++ result = sfi_table_parse(SFI_SIG_CPUS, NULL, NULL, parse_cpus);
++
++ if (result < 0)
++ return result;
++
++ pr = kzalloc(sfi_cpu_num * sizeof(struct sfi_processor), GFP_KERNEL);
++ if (!pr)
++ return -ENOMEM;
++
++ for (i = 0; i < sfi_cpu_num; i++) {
++ pr->id = sfi_cpu_array[i].apic_id;
++ per_cpu(sfi_processors, i) = pr;
++ pr++;
++ }
++
++ return 0;
++}
++
++static int __init sfi_cpufreq_init(void)
++{
++ int ret;
++
++ pr_debug("sfi_cpufreq_init\n");
++
++ ret = init_sfi_processor_list();
++ if (ret)
++ return ret;
++
++ ret = sfi_cpufreq_early_init();
++ if (ret)
++ return ret;
++
++ return cpufreq_register_driver(&sfi_cpufreq_driver);
++}
++
++static void __exit sfi_cpufreq_exit(void)
++{
++
++ struct sfi_processor *pr;
++
++ pr_debug("sfi_cpufreq_exit\n");
++
++ pr = per_cpu(sfi_processors, 0);
++ kfree(pr);
++
++ cpufreq_unregister_driver(&sfi_cpufreq_driver);
++
++ free_percpu(sfi_perf_data);
++
++ return;
++}
++late_initcall(sfi_cpufreq_init);
++module_exit(sfi_cpufreq_exit);
++
++MODULE_ALIAS("sfi");
+diff --git a/drivers/cpufreq/sfi-cpufreq.h b/drivers/cpufreq/sfi-cpufreq.h
+new file mode 100644
+index 0000000..7e01c1e
+--- /dev/null
++++ b/drivers/cpufreq/sfi-cpufreq.h
+@@ -0,0 +1,65 @@
++/*
++ * sfi_processor.h
++ * Copyright (c) 2010, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#ifndef __SFI_PROCESSOR_H__
++#define __SFI_PROCESSOR_H__
++
++#include <linux/sfi.h>
++#include <linux/cpuidle.h>
++
++struct sfi_processor_power {
++ struct cpuidle_device dev;
++ u32 default_state;
++ int count;
++ struct cpuidle_state *states;
++ struct sfi_cstate_table_entry *sfi_cstates;
++};
++
++struct sfi_processor_flags {
++ u8 valid;
++ u8 power;
++};
++
++struct sfi_processor {
++ u32 id;
++ struct sfi_processor_flags flags;
++ struct sfi_processor_power power;
++ struct sfi_processor_performance *performance;
++};
++
++/* Performance management */
++struct sfi_processor_px {
++ u32 core_frequency; /* megahertz */
++ u32 transition_latency; /* microseconds */
++ u32 control; /* control value */
++};
++
++struct sfi_processor_performance {
++ unsigned int state;
++ unsigned int state_count;
++ struct sfi_processor_px *states;
++};
++
++/* for communication between multiple parts of the processor kernel module */
++DECLARE_PER_CPU(struct sfi_processor *, sfi_processors);
++
++int sfi_processor_power_init(struct sfi_processor *pr);
++int sfi_processor_power_exit(struct sfi_processor *pr);
++
++#endif /*__SFI_PROCESSOR_H__*/
+diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
+index a2b0df5..4b82961 100644
+--- a/drivers/dma/Makefile
++++ b/drivers/dma/Makefile
+@@ -7,7 +7,7 @@ obj-$(CONFIG_DMA_ACPI) += acpi-dma.o
+ obj-$(CONFIG_DMA_OF) += of-dma.o
+
+ obj-$(CONFIG_NET_DMA) += iovlock.o
+-obj-$(CONFIG_INTEL_MID_DMAC) += intel_mid_dma.o
++obj-$(CONFIG_INTEL_MID_DMAC) += intel_mid_dma.o intel_mid_dma_acpi.o
+ obj-$(CONFIG_DMATEST) += dmatest.o
+ obj-$(CONFIG_INTEL_IOATDMA) += ioat/
+ obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o
+diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c
+index a0de82e..2a51cf7 100644
+--- a/drivers/dma/intel_mid_dma.c
++++ b/drivers/dma/intel_mid_dma.c
+@@ -28,34 +28,41 @@
+ #include <linux/pm_runtime.h>
+ #include <linux/intel_mid_dma.h>
+ #include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/platform_device.h>
+
+ #include "dmaengine.h"
+
+-#define MAX_CHAN 4 /*max ch across controllers*/
++#define MAX_CHAN 8 /*max ch across controllers*/
+ #include "intel_mid_dma_regs.h"
+
+ #define INTEL_MID_DMAC1_ID 0x0814
+ #define INTEL_MID_DMAC2_ID 0x0813
+ #define INTEL_MID_GP_DMAC2_ID 0x0827
+ #define INTEL_MFLD_DMAC1_ID 0x0830
+-#define LNW_PERIPHRAL_MASK_BASE 0xFFAE8008
+-#define LNW_PERIPHRAL_MASK_SIZE 0x10
+-#define LNW_PERIPHRAL_STATUS 0x0
+-#define LNW_PERIPHRAL_MASK 0x8
+-
+-struct intel_mid_dma_probe_info {
+- u8 max_chan;
+- u8 ch_base;
+- u16 block_size;
+- u32 pimr_mask;
+-};
+-
+-#define INFO(_max_chan, _ch_base, _block_size, _pimr_mask) \
++#define INTEL_CLV_GP_DMAC2_ID 0x08EF
++#define INTEL_CLV_DMAC1_ID 0x08F0
++#define INTEL_MRFLD_GP_DMAC2_ID 0x11A2
++#define INTEL_MRFLD_DMAC0_ID 0x119B
++#define INTEL_BYT_LPIO1_DMAC_ID 0x0F06
++#define INTEL_BYT_LPIO2_DMAC_ID 0x0F40
++#define INTEL_BYT_DMAC0_ID 0x0F28
++
++#define LNW_PERIPHRAL_MASK_SIZE 0x20
++
++#define INFO(_max_chan, _ch_base, _block_size, _pimr_mask, \
++ _pimr_base, _dword_trf, _pimr_offset, _pci_id, \
++ _pdma_ops) \
+ ((kernel_ulong_t)&(struct intel_mid_dma_probe_info) { \
+ .max_chan = (_max_chan), \
+ .ch_base = (_ch_base), \
+ .block_size = (_block_size), \
+ .pimr_mask = (_pimr_mask), \
++ .pimr_base = (_pimr_base), \
++ .dword_trf = (_dword_trf), \
++ .pimr_offset = (_pimr_offset), \
++ .pci_id = (_pci_id), \
++ .pdma_ops = (_pdma_ops) \
+ })
+
+ /*****************************************************************************
+@@ -65,32 +72,90 @@ Utility Functions*/
+ * @status: status mask
+ * @base: dma ch base value
+ *
+- * Modify the status mask and return the channel index needing
+- * attention (or -1 if neither)
++ * Returns the channel index by checking the status bits.
++ * If none of the bits in status are set, then returns -1.
+ */
+-static int get_ch_index(int *status, unsigned int base)
++static int get_ch_index(int status, unsigned int base)
+ {
+ int i;
+ for (i = 0; i < MAX_CHAN; i++) {
+- if (*status & (1 << (i + base))) {
+- *status = *status & ~(1 << (i + base));
+- pr_debug("MDMA: index %d New status %x\n", i, *status);
++ if (status & (1 << (i + base)))
+ return i;
+- }
+ }
+ return -1;
+ }
+
++static inline bool is_byt_lpio_dmac(struct middma_device *mid)
++{
++ return (mid->pci_id == INTEL_BYT_LPIO1_DMAC_ID ||
++ mid->pci_id == INTEL_BYT_LPIO2_DMAC_ID);
++}
++
++static void dump_dma_reg(struct dma_chan *chan)
++{
++ struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
++ struct middma_device *mid = to_middma_device(chan->device);
++
++ if (!mid->pimr_base)
++ return;
++
++ pr_debug("<<<<<<<<<<<< DMA Dump Start >>>>>>>>>>>>");
++ pr_debug("DMA Dump for Channel id:%d & Chnl Base:%p",
++ midc->ch_id, midc->ch_regs);
++ /* dump common DMA registers */
++ pr_debug("PIMR:\t%#x", readl(mid->mask_reg) - 8);
++ pr_debug("ISRX:\t%#x", readl(mid->mask_reg));
++ pr_debug("ISRD:\t%#x", readl(mid->mask_reg + 0x8));
++ pr_debug("IMRX:\t%#x", readl(mid->mask_reg + 0x10));
++ pr_debug("IMRD:\t%#x", readl(mid->mask_reg + 0x18));
++ pr_debug("DMA_CHAN_EN:\t%#x", readl(midc->dma_base + DMA_CHAN_EN));
++ pr_debug("DMA_CFG:\t%#x", readl(midc->dma_base + DMA_CFG));
++ pr_debug("INTR_STATUS:\t%#x", readl(midc->dma_base + INTR_STATUS));
++ pr_debug("MASK_TFR:\t%#x", readl(midc->dma_base + MASK_TFR));
++ pr_debug("MASK_BLOCK:\t%#x", readl(midc->dma_base + MASK_BLOCK));
++ pr_debug("MASK_ERR:\t%#x", readl(midc->dma_base + MASK_ERR));
++ pr_debug("RAW_TFR:\t%#x", readl(midc->dma_base + RAW_TFR));
++ pr_debug("RAW_BLOCK:\t%#x", readl(midc->dma_base + RAW_BLOCK));
++ pr_debug("RAW_ERR:\t%#x", readl(midc->dma_base + RAW_ERR));
++ pr_debug("STATUS_TFR:\t%#x", readl(midc->dma_base + STATUS_TFR));
++ pr_debug("STATUS_BLOCK:\t%#x", readl(midc->dma_base + STATUS_BLOCK));
++ pr_debug("STATUS_ERR:\t%#x", readl(midc->dma_base + STATUS_ERR));
++ if (!mid->dword_trf) {
++ pr_debug("FIFO_PARTITION0_LO:\t%#x",
++ readl(midc->dma_base + FIFO_PARTITION0_LO));
++ pr_debug("FIFO_PARTITION0_HI:\t%#x",
++ readl(midc->dma_base + FIFO_PARTITION0_HI));
++ pr_debug("FIFO_PARTITION1_LO:\t%#x",
++ readl(midc->dma_base + FIFO_PARTITION1_LO));
++ pr_debug("FIFO_PARTITION1_HI:\t%#x",
++ readl(midc->dma_base + FIFO_PARTITION1_HI));
++ pr_debug("CH_SAI_ERR:\t%#x", readl(midc->dma_base + CH_SAI_ERR));
++ }
++
++ /* dump channel specific registers */
++ pr_debug("SAR:\t%#x", readl(midc->ch_regs + SAR));
++ pr_debug("DAR:\t%#x", readl(midc->ch_regs + DAR));
++ pr_debug("LLP:\t%#x", readl(midc->ch_regs + LLP));
++ pr_debug("CTL_LOW:\t%#x", readl(midc->ch_regs + CTL_LOW));
++ pr_debug("CTL_HIGH:\t%#x", readl(midc->ch_regs + CTL_HIGH));
++ pr_debug("CFG_LOW:\t%#x", readl(midc->ch_regs + CFG_LOW));
++ pr_debug("CFG_HIGH:\t%#x", readl(midc->ch_regs + CFG_HIGH));
++ pr_debug("<<<<<<<<<<<< DMA Dump ends >>>>>>>>>>>>");
++}
++
+ /**
+ * get_block_ts - calculates dma transaction length
+ * @len: dma transfer length
+ * @tx_width: dma transfer src width
+ * @block_size: dma controller max block size
++ * @dword_trf: is transfer dword size aligned and needs the data transfer to
++ * be in terms of data items and not bytes
+ *
+ * Based on src width calculate the DMA trsaction length in data items
+ * return data items or FFFF if exceeds max length for block
+ */
+-static int get_block_ts(int len, int tx_width, int block_size)
++static unsigned int get_block_ts(int len, int tx_width,
++ int block_size, int dword_trf)
+ {
+ int byte_width = 0, block_ts = 0;
+
+@@ -106,13 +171,46 @@ static int get_block_ts(int len, int tx_width, int block_size)
+ byte_width = 4;
+ break;
+ }
+-
+- block_ts = len/byte_width;
++ if (dword_trf)
++ block_ts = len/byte_width;
++ else
++ block_ts = len;
+ if (block_ts > block_size)
+ block_ts = 0xFFFF;
+ return block_ts;
+ }
+
++/**
++ * get_reg_width - computes the DMA sample width
++ * @kernel_width: Kernel DMA slave bus width
++ *
++ * converts the DMA kernel slave bus width in the Intel DMA
++ * bus width
++ */
++static int get_reg_width(enum dma_slave_buswidth kernel_width)
++{
++ int reg_width = -1;
++
++ switch (kernel_width) {
++ case DMA_SLAVE_BUSWIDTH_1_BYTE:
++ reg_width = 0;
++ break;
++ case DMA_SLAVE_BUSWIDTH_2_BYTES:
++ reg_width = 1;
++ break;
++ case DMA_SLAVE_BUSWIDTH_4_BYTES:
++ reg_width = 2;
++ break;
++ case DMA_SLAVE_BUSWIDTH_UNDEFINED:
++ case DMA_SLAVE_BUSWIDTH_8_BYTES:
++ default:
++ pr_err("ERR_MDMA: get_reg_width unsupported reg width\n");
++ break;
++ }
++ return reg_width;
++}
++
++
+ /*****************************************************************************
+ DMAC1 interrupt Functions*/
+
+@@ -129,9 +227,9 @@ static void dmac1_mask_periphral_intr(struct middma_device *mid)
+ u32 pimr;
+
+ if (mid->pimr_mask) {
+- pimr = readl(mid->mask_reg + LNW_PERIPHRAL_MASK);
++ pimr = readl(mid->mask_reg + mid->pimr_offset);
+ pimr |= mid->pimr_mask;
+- writel(pimr, mid->mask_reg + LNW_PERIPHRAL_MASK);
++ writel(pimr, mid->mask_reg + mid->pimr_offset);
+ }
+ return;
+ }
+@@ -149,14 +247,37 @@ static void dmac1_unmask_periphral_intr(struct intel_mid_dma_chan *midc)
+ u32 pimr;
+ struct middma_device *mid = to_middma_device(midc->chan.device);
+
+- if (mid->pimr_mask) {
+- pimr = readl(mid->mask_reg + LNW_PERIPHRAL_MASK);
++ if (mid->pimr_mask && mid->dword_trf) {
++ pimr = readl(mid->mask_reg + mid->pimr_offset);
+ pimr &= ~mid->pimr_mask;
+- writel(pimr, mid->mask_reg + LNW_PERIPHRAL_MASK);
++ writel(pimr, mid->mask_reg + mid->pimr_offset);
++ }
++ if (mid->pimr_mask && !mid->dword_trf) {
++ pimr = readl(mid->mask_reg + mid->pimr_offset);
++ pimr &= ~(1 << (midc->ch_id + 16));
++ writel(pimr, mid->mask_reg + mid->pimr_offset);
+ }
+ return;
+ }
+
++/*
++ * Some consumer may need to know how many bytes have been
++ * really transfered for one specific dma channel
++ */
++inline dma_addr_t intel_dma_get_src_addr(struct dma_chan *chan)
++{
++ struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
++ return readl(midc->ch_regs + SAR);
++}
++EXPORT_SYMBOL(intel_dma_get_src_addr);
++
++inline dma_addr_t intel_dma_get_dst_addr(struct dma_chan *chan)
++{
++ struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
++ return readl(midc->ch_regs + DAR);
++}
++EXPORT_SYMBOL(intel_dma_get_dst_addr);
++
+ /**
+ * enable_dma_interrupt - enable the periphral interrupt
+ * @midc: dma channel for which enable interrupt is required
+@@ -167,10 +288,13 @@ static void dmac1_unmask_periphral_intr(struct intel_mid_dma_chan *midc)
+ */
+ static void enable_dma_interrupt(struct intel_mid_dma_chan *midc)
+ {
++ struct middma_device *mid = to_middma_device(midc->chan.device);
++
+ dmac1_unmask_periphral_intr(midc);
+
+ /*en ch interrupts*/
+ iowrite32(UNMASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_TFR);
++ set_bit(midc->ch_id, &mid->tfr_intr_mask);
+ iowrite32(UNMASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_ERR);
+ return;
+ }
+@@ -185,10 +309,39 @@ static void enable_dma_interrupt(struct intel_mid_dma_chan *midc)
+ */
+ static void disable_dma_interrupt(struct intel_mid_dma_chan *midc)
+ {
++ struct middma_device *mid = to_middma_device(midc->chan.device);
++ u32 pimr;
++
+ /*Check LPE PISR, make sure fwd is disabled*/
+ iowrite32(MASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_BLOCK);
++ clear_bit(midc->ch_id, &mid->block_intr_mask);
+ iowrite32(MASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_TFR);
++ clear_bit(midc->ch_id, &mid->tfr_intr_mask);
+ iowrite32(MASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_ERR);
++ if (mid->pimr_mask && !mid->dword_trf) {
++ pimr = readl(mid->mask_reg + mid->pimr_offset);
++ pimr |= (1 << (midc->ch_id + 16));
++ writel(pimr, mid->mask_reg + mid->pimr_offset);
++ }
++
++ return;
++}
++
++/**
++ * clear_dma_channel_interrupt - clear channel interrupt
++ * @midc: dma channel for which clear interrupt is required
++ *
++ */
++static void clear_dma_channel_interrupt(struct intel_mid_dma_chan *midc)
++{
++ struct middma_device *mid = to_middma_device(midc->chan.device);
++
++ /*clearing this interrupts first*/
++ iowrite32((1 << midc->ch_id), mid->dma_base + CLEAR_TFR);
++ iowrite32((1 << midc->ch_id), mid->dma_base + CLEAR_BLOCK);
++ iowrite32((1 << midc->ch_id), mid->dma_base + CLEAR_ERR);
++
++
+ return;
+ }
+
+@@ -243,7 +396,7 @@ static void midc_desc_put(struct intel_mid_dma_chan *midc,
+ * Load a transaction into the engine. This must be called with midc->lock
+ * held and bh disabled.
+ */
+-static void midc_dostart(struct intel_mid_dma_chan *midc,
++static int midc_dostart(struct intel_mid_dma_chan *midc,
+ struct intel_mid_dma_desc *first)
+ {
+ struct middma_device *mid = to_middma_device(midc->chan.device);
+@@ -253,7 +406,7 @@ static void midc_dostart(struct intel_mid_dma_chan *midc,
+ /*error*/
+ pr_err("ERR_MDMA: channel is busy in start\n");
+ /* The tasklet will hopefully advance the queue... */
+- return;
++ return -EBUSY;
+ }
+ midc->busy = true;
+ /*write registers and en*/
+@@ -264,12 +417,13 @@ static void midc_dostart(struct intel_mid_dma_chan *midc,
+ iowrite32(first->cfg_lo, midc->ch_regs + CFG_LOW);
+ iowrite32(first->ctl_lo, midc->ch_regs + CTL_LOW);
+ iowrite32(first->ctl_hi, midc->ch_regs + CTL_HIGH);
+- pr_debug("MDMA:TX SAR %x,DAR %x,CFGL %x,CFGH %x,CTLH %x, CTLL %x\n",
++ pr_debug("MDMA:TX SAR %x,DAR %x,CFGH %x,CFGL %x,CTLH %x, CTLL %x LLI %x",
+ (int)first->sar, (int)first->dar, first->cfg_hi,
+- first->cfg_lo, first->ctl_hi, first->ctl_lo);
++ first->cfg_lo, first->ctl_hi, first->ctl_lo, (int)first->lli_phys);
+ first->status = DMA_IN_PROGRESS;
+
+ iowrite32(ENABLE_CHANNEL(midc->ch_id), mid->dma_base + DMA_CHAN_EN);
++ return 0;
+ }
+
+ /**
+@@ -303,46 +457,65 @@ static void midc_descriptor_complete(struct intel_mid_dma_chan *midc,
+ else
+ desc->current_lli = 0;
+ }
+- spin_unlock_bh(&midc->lock);
+- if (callback_txd) {
+- pr_debug("MDMA: TXD callback set ... calling\n");
+- callback_txd(param_txd);
+- }
+ if (midc->raw_tfr) {
++ list_del(&desc->desc_node);
+ desc->status = DMA_SUCCESS;
+- if (desc->lli != NULL) {
+- pci_pool_free(desc->lli_pool, desc->lli,
++ if (desc->lli != NULL && desc->lli->llp != 0)
++ dma_pool_free(desc->lli_pool, desc->lli,
+ desc->lli_phys);
+- pci_pool_destroy(desc->lli_pool);
+- desc->lli = NULL;
+- }
+- list_move(&desc->desc_node, &midc->free_list);
++ list_add(&desc->desc_node, &midc->free_list);
+ midc->busy = false;
++ midc->raw_tfr = 0;
++ spin_unlock_bh(&midc->lock);
++ } else {
++ spin_unlock_bh(&midc->lock);
++ }
++ if (callback_txd) {
++ pr_debug("MDMA: TXD callback set ... calling\n");
++ callback_txd(param_txd);
+ }
++
+ spin_lock_bh(&midc->lock);
++}
+
++static struct
++intel_mid_dma_desc *midc_first_queued(struct intel_mid_dma_chan *midc)
++{
++ return list_entry(midc->queue.next, struct intel_mid_dma_desc, desc_node);
+ }
+-/**
+- * midc_scan_descriptors - check the descriptors in channel
+- * mark completed when tx is completete
+- * @mid: device
+- * @midc: channel to scan
+- *
+- * Walk the descriptor chain for the device and process any entries
+- * that are complete.
+- */
+-static void midc_scan_descriptors(struct middma_device *mid,
++
++static void midc_collect_descriptors(struct middma_device *mid,
+ struct intel_mid_dma_chan *midc)
+ {
+ struct intel_mid_dma_desc *desc = NULL, *_desc = NULL;
+-
+ /*tx is complete*/
+ list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
+ if (desc->status == DMA_IN_PROGRESS)
+ midc_descriptor_complete(midc, desc);
+ }
+- return;
++
++}
++
++/**
++ * midc_start_descriptors - start the descriptors in queue
++ *
++ * @mid: device
++ * @midc: channel to scan
++ *
++ */
++static void midc_start_descriptors(struct middma_device *mid,
++ struct intel_mid_dma_chan *midc)
++{
++ if (!list_empty(&midc->queue)) {
++ pr_debug("MDMA: submitting txn in queue\n");
++ if (0 == midc_dostart(midc, midc_first_queued(midc)))
++ list_splice_init(&midc->queue, &midc->active_list);
++ else
++ pr_warn("Submit failed as ch is busy\n");
+ }
++ return;
++}
++
+ /**
+ * midc_lli_fill_sg - Helper function to convert
+ * SG list to Linked List Items.
+@@ -357,7 +530,8 @@ static void midc_scan_descriptors(struct middma_device *mid,
+ */
+ static int midc_lli_fill_sg(struct intel_mid_dma_chan *midc,
+ struct intel_mid_dma_desc *desc,
+- struct scatterlist *sglist,
++ struct scatterlist *src_sglist,
++ struct scatterlist *dst_sglist,
+ unsigned int sglen,
+ unsigned int flags)
+ {
+@@ -366,18 +540,18 @@ static int midc_lli_fill_sg(struct intel_mid_dma_chan *midc,
+ dma_addr_t lli_next, sg_phy_addr;
+ struct intel_mid_dma_lli *lli_bloc_desc;
+ union intel_mid_dma_ctl_lo ctl_lo;
+- union intel_mid_dma_ctl_hi ctl_hi;
++ u32 ctl_hi;
+ int i;
+
+- pr_debug("MDMA: Entered midc_lli_fill_sg\n");
++ pr_debug("MDMA: Entered %s\n", __func__);
+ mids = midc->mid_slave;
+
+ lli_bloc_desc = desc->lli;
+ lli_next = desc->lli_phys;
+
+ ctl_lo.ctl_lo = desc->ctl_lo;
+- ctl_hi.ctl_hi = desc->ctl_hi;
+- for_each_sg(sglist, sg, sglen, i) {
++ ctl_hi = desc->ctl_hi;
++ for_each_sg(src_sglist, sg, sglen, i) {
+ /*Populate CTL_LOW and LLI values*/
+ if (i != sglen - 1) {
+ lli_next = lli_next +
+@@ -389,29 +563,37 @@ static int midc_lli_fill_sg(struct intel_mid_dma_chan *midc,
+ lli_next = desc->lli_phys;
+ } else {
+ lli_next = 0;
+- ctl_lo.ctlx.llp_dst_en = 0;
+- ctl_lo.ctlx.llp_src_en = 0;
++ /* llp_dst_en = 0 llp_src_en = 0 */
++ ctl_lo.ctl_lo &= ~(1 << CTL_LO_BIT_LLP_DST_EN);
++ ctl_lo.ctl_lo &= ~(1 << CTL_LO_BIT_LLP_SRC_EN);
+ }
+ }
+ /*Populate CTL_HI values*/
+- ctl_hi.ctlx.block_ts = get_block_ts(sg_dma_len(sg),
+- desc->width,
+- midc->dma->block_size);
++ ctl_hi = get_block_ts(sg->length, desc->width,
++ midc->dma->block_size, midc->dma->dword_trf);
+ /*Populate SAR and DAR values*/
+- sg_phy_addr = sg_dma_address(sg);
++ sg_phy_addr = sg_phys(sg);
+ if (desc->dirn == DMA_MEM_TO_DEV) {
+ lli_bloc_desc->sar = sg_phy_addr;
+ lli_bloc_desc->dar = mids->dma_slave.dst_addr;
+ } else if (desc->dirn == DMA_DEV_TO_MEM) {
+ lli_bloc_desc->sar = mids->dma_slave.src_addr;
+ lli_bloc_desc->dar = sg_phy_addr;
++ } else if (desc->dirn == DMA_MEM_TO_MEM && dst_sglist) {
++ lli_bloc_desc->sar = sg_phy_addr;
++ lli_bloc_desc->dar = sg_phys(dst_sglist);
+ }
+ /*Copy values into block descriptor in system memroy*/
+ lli_bloc_desc->llp = lli_next;
+ lli_bloc_desc->ctl_lo = ctl_lo.ctl_lo;
+- lli_bloc_desc->ctl_hi = ctl_hi.ctl_hi;
++ lli_bloc_desc->ctl_hi = ctl_hi;
+
++ pr_debug("MDMA:Calc CTL LO %x, CTL HI %x src: %x dest: %x sg->l:%x\n",
++ ctl_lo.ctl_lo, lli_bloc_desc->ctl_hi,
++ lli_bloc_desc->sar, lli_bloc_desc->dar, sg->length);
+ lli_bloc_desc++;
++ if (dst_sglist)
++ dst_sglist = sg_next(dst_sglist);
+ }
+ /*Copy very first LLI values to descriptor*/
+ desc->ctl_lo = desc->lli->ctl_lo;
+@@ -421,13 +603,14 @@ static int midc_lli_fill_sg(struct intel_mid_dma_chan *midc,
+
+ return 0;
+ }
++
+ /*****************************************************************************
+ DMA engine callback Functions*/
+ /**
+ * intel_mid_dma_tx_submit - callback to submit DMA transaction
+ * @tx: dma engine descriptor
+ *
+- * Submit the DMA transaction for this descriptor, start if ch idle
++ * Submit the DMA trasaction for this descriptor, start if ch idle
+ */
+ static dma_cookie_t intel_mid_dma_tx_submit(struct dma_async_tx_descriptor *tx)
+ {
+@@ -436,6 +619,14 @@ static dma_cookie_t intel_mid_dma_tx_submit(struct dma_async_tx_descriptor *tx)
+ dma_cookie_t cookie;
+
+ spin_lock_bh(&midc->lock);
++
++ if (unlikely(!midc->in_use)) {
++ spin_unlock_bh(&midc->lock);
++ WARN(1, "chan[%d] gets new request after close",
++ tx->chan->chan_id);
++ return -EIO;
++ }
++
+ cookie = dma_cookie_assign(tx);
+
+ if (list_empty(&midc->active_list))
+@@ -461,11 +652,74 @@ static void intel_mid_dma_issue_pending(struct dma_chan *chan)
+
+ spin_lock_bh(&midc->lock);
+ if (!list_empty(&midc->queue))
+- midc_scan_descriptors(to_middma_device(chan->device), midc);
++ midc_start_descriptors(to_middma_device(chan->device), midc);
+ spin_unlock_bh(&midc->lock);
+ }
+
+ /**
++ * dma_wait_for_suspend - performs following functionality
++ * 1. Suspends channel using mask bits
++ * 2. Wait till FIFO to get empty
++ * 3. Disable channel
++ * 4. restore the previous masked bits
++ *
++ * @chan: chan where pending trascation needs to be checked and submitted
++ * @mask: mask bits to be used for suspend operation
++ *
++ */
++static inline void dma_wait_for_suspend(struct dma_chan *chan, unsigned int mask)
++{
++ union intel_mid_dma_cfg_lo cfg_lo;
++ struct middma_device *mid = to_middma_device(chan->device);
++ struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
++ int i;
++
++ /* Suspend channel */
++ cfg_lo.cfg_lo = ioread32(midc->ch_regs + CFG_LOW);
++ cfg_lo.cfg_lo |= mask;
++ iowrite32(cfg_lo.cfg_lo, midc->ch_regs + CFG_LOW);
++ /* wait till FIFO gets empty */
++ /* FIFO should be cleared in couple of milli secs */
++ for (i = 0; i < 10; i++) {
++ cfg_lo.cfg_lo = ioread32(midc->ch_regs + CFG_LOW);
++ if (cfg_lo.cfgx.fifo_empty)
++ break;
++ /* use delay since this might called from atomic context */
++ mdelay(1);
++ }
++ pr_debug("waited for %d ms for FIFO to get empty", i);
++ iowrite32(DISABLE_CHANNEL(midc->ch_id), mid->dma_base + DMA_CHAN_EN);
++
++ cfg_lo.cfg_lo = ioread32(midc->ch_regs + CFG_LOW);
++ cfg_lo.cfg_lo &= ~mask;
++ iowrite32(cfg_lo.cfg_lo, midc->ch_regs + CFG_LOW);
++}
++/**
++ * intel_mid_dma_chan_suspend_v1 - suspends the given channel, waits
++ * till FIFO is cleared and disables channel.
++ * @chan: chan where pending trascation needs to be checked and submitted
++ *
++ */
++static void intel_mid_dma_chan_suspend_v1(struct dma_chan *chan)
++{
++
++ pr_debug("%s", __func__);
++ dma_wait_for_suspend(chan, CH_SUSPEND);
++}
++
++/**
++ * intel_mid_dma_chan_suspend_v2 - suspends the given channel, waits
++ * till FIFO is cleared and disables channel.
++ * @chan: chan where pending trascation needs to be checked and submitted
++ *
++ */
++static void intel_mid_dma_chan_suspend_v2(struct dma_chan *chan)
++{
++ pr_debug("%s", __func__);
++ dma_wait_for_suspend(chan, CH_SUSPEND | CH_DRAIN);
++}
++
++/**
+ * intel_mid_dma_tx_status - Return status of txn
+ * @chan: chan for where status needs to be checked
+ * @cookie: cookie for txn
+@@ -483,7 +737,7 @@ static enum dma_status intel_mid_dma_tx_status(struct dma_chan *chan,
+ ret = dma_cookie_status(chan, cookie, txstate);
+ if (ret != DMA_SUCCESS) {
+ spin_lock_bh(&midc->lock);
+- midc_scan_descriptors(to_middma_device(chan->device), midc);
++ midc_start_descriptors(to_middma_device(chan->device), midc);
+ spin_unlock_bh(&midc->lock);
+
+ ret = dma_cookie_status(chan, cookie, txstate);
+@@ -509,6 +763,7 @@ static int dma_slave_control(struct dma_chan *chan, unsigned long arg)
+ midc->mid_slave = mid_slave;
+ return 0;
+ }
++
+ /**
+ * intel_mid_dma_device_control - DMA device control
+ * @chan: chan for DMA control
+@@ -523,8 +778,8 @@ static int intel_mid_dma_device_control(struct dma_chan *chan,
+ struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
+ struct middma_device *mid = to_middma_device(chan->device);
+ struct intel_mid_dma_desc *desc, *_desc;
+- union intel_mid_dma_cfg_lo cfg_lo;
+
++ pr_debug("%s:CMD:%d for channel:%d\n", __func__, cmd, midc->ch_id);
+ if (cmd == DMA_SLAVE_CONFIG)
+ return dma_slave_control(chan, arg);
+
+@@ -536,30 +791,25 @@ static int intel_mid_dma_device_control(struct dma_chan *chan,
+ spin_unlock_bh(&midc->lock);
+ return 0;
+ }
+- /*Suspend and disable the channel*/
+- cfg_lo.cfg_lo = ioread32(midc->ch_regs + CFG_LOW);
+- cfg_lo.cfgx.ch_susp = 1;
+- iowrite32(cfg_lo.cfg_lo, midc->ch_regs + CFG_LOW);
+- iowrite32(DISABLE_CHANNEL(midc->ch_id), mid->dma_base + DMA_CHAN_EN);
+- midc->busy = false;
+- /* Disable interrupts */
++ /* Disable CH interrupts */
+ disable_dma_interrupt(midc);
++ /* clear channel interrupts */
++ clear_dma_channel_interrupt(midc);
++ mid->dma_ops.dma_chan_suspend(chan);
++ midc->busy = false;
+ midc->descs_allocated = 0;
+-
+- spin_unlock_bh(&midc->lock);
+ list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
+- if (desc->lli != NULL) {
+- pci_pool_free(desc->lli_pool, desc->lli,
++ list_del(&desc->desc_node);
++ if (desc->lli != NULL)
++ dma_pool_free(desc->lli_pool, desc->lli,
+ desc->lli_phys);
+- pci_pool_destroy(desc->lli_pool);
+- desc->lli = NULL;
+- }
+- list_move(&desc->desc_node, &midc->free_list);
++ list_add(&desc->desc_node, &midc->free_list);
+ }
++ spin_unlock_bh(&midc->lock);
++
+ return 0;
+ }
+
+-
+ /**
+ * intel_mid_dma_prep_memcpy - Prep memcpy txn
+ * @chan: chan for DMA transfer
+@@ -580,10 +830,12 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy(
+ struct intel_mid_dma_desc *desc = NULL;
+ struct intel_mid_dma_slave *mids;
+ union intel_mid_dma_ctl_lo ctl_lo;
+- union intel_mid_dma_ctl_hi ctl_hi;
++ u32 ctl_hi;
+ union intel_mid_dma_cfg_lo cfg_lo;
+ union intel_mid_dma_cfg_hi cfg_hi;
+ enum dma_slave_buswidth width;
++ int dst_reg_width = 0;
++ int src_reg_width = 0;
+
+ pr_debug("MDMA: Prep for memcpy\n");
+ BUG_ON(!chan);
+@@ -596,6 +848,11 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy(
+ mids = midc->mid_slave;
+ BUG_ON(!mids);
+
++ if (unlikely(!midc->in_use)) {
++ pr_err("ERR_MDMA: %s: channel not in use", __func__);
++ return NULL;
++ }
++
+ pr_debug("MDMA:called for DMA %x CH %d Length %zu\n",
+ midc->dma->pci_id, midc->ch_id, len);
+ pr_debug("MDMA:Cfg passed Mode %x, Dirn %x, HS %x, Width %x\n",
+@@ -634,36 +891,41 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy(
+ }
+ } else {
+ cfg_hi.cfgx.protctl = 0x1; /*default value*/
+- cfg_hi.cfgx.src_per = cfg_hi.cfgx.dst_per =
++ /* Baytrail DMAC uses dynamic device instance */
++ if (is_byt_lpio_dmac(midc->dma))
++ cfg_hi.cfgx.src_per = cfg_hi.cfgx.dst_per =
++ mids->device_instance;
++ else
++ cfg_hi.cfgx.src_per = cfg_hi.cfgx.dst_per =
+ midc->ch_id - midc->dma->chan_base;
+ }
+ }
+-
+ /*calculate CTL_HI*/
+- ctl_hi.ctlx.reser = 0;
+- ctl_hi.ctlx.done = 0;
+ width = mids->dma_slave.src_addr_width;
+-
+- ctl_hi.ctlx.block_ts = get_block_ts(len, width, midc->dma->block_size);
++ ctl_hi = get_block_ts(len, width, midc->dma->block_size, midc->dma->dword_trf);
+ pr_debug("MDMA:calc len %d for block size %d\n",
+- ctl_hi.ctlx.block_ts, midc->dma->block_size);
++ ctl_hi, midc->dma->block_size);
+ /*calculate CTL_LO*/
+ ctl_lo.ctl_lo = 0;
+ ctl_lo.ctlx.int_en = 1;
++
++ dst_reg_width = get_reg_width(mids->dma_slave.dst_addr_width);
++ if (dst_reg_width < 0) {
++ pr_err("ERR_MDMA: Failed to get DST reg width\n");
++ return NULL;
++
++ }
++ ctl_lo.ctlx.dst_tr_width = dst_reg_width;
++
++ src_reg_width = get_reg_width(mids->dma_slave.src_addr_width);
++ if (src_reg_width < 0) {
++ pr_err("ERR_MDMA: Failed to get SRC reg width\n");
++ return NULL;
++ }
++ ctl_lo.ctlx.src_tr_width = src_reg_width;
+ ctl_lo.ctlx.dst_msize = mids->dma_slave.src_maxburst;
+ ctl_lo.ctlx.src_msize = mids->dma_slave.dst_maxburst;
+
+- /*
+- * Here we need some translation from "enum dma_slave_buswidth"
+- * to the format for our dma controller
+- * standard intel_mid_dmac's format
+- * 1 Byte 0b000
+- * 2 Bytes 0b001
+- * 4 Bytes 0b010
+- */
+- ctl_lo.ctlx.dst_tr_width = mids->dma_slave.dst_addr_width / 2;
+- ctl_lo.ctlx.src_tr_width = mids->dma_slave.src_addr_width / 2;
+-
+ if (mids->cfg_mode == LNW_DMA_MEM_TO_MEM) {
+ ctl_lo.ctlx.tt_fc = 0;
+ ctl_lo.ctlx.sinc = 0;
+@@ -681,7 +943,7 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy(
+ }
+
+ pr_debug("MDMA:Calc CTL LO %x, CTL HI %x, CFG LO %x, CFG HI %x\n",
+- ctl_lo.ctl_lo, ctl_hi.ctl_hi, cfg_lo.cfg_lo, cfg_hi.cfg_hi);
++ ctl_lo.ctl_lo, ctl_hi, cfg_lo.cfg_lo, cfg_hi.cfg_hi);
+
+ enable_dma_interrupt(midc);
+
+@@ -694,7 +956,7 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy(
+ desc->cfg_hi = cfg_hi.cfg_hi;
+ desc->cfg_lo = cfg_lo.cfg_lo;
+ desc->ctl_lo = ctl_lo.ctl_lo;
+- desc->ctl_hi = ctl_hi.ctl_hi;
++ desc->ctl_hi = ctl_hi;
+ desc->width = width;
+ desc->dirn = mids->dma_slave.direction;
+ desc->lli_phys = 0;
+@@ -707,59 +969,193 @@ err_desc_get:
+ midc_desc_put(midc, desc);
+ return NULL;
+ }
++
+ /**
+- * intel_mid_dma_prep_slave_sg - Prep slave sg txn
++ * intel_mid_dma_prep_memcpy_v2 - Prep memcpy txn
+ * @chan: chan for DMA transfer
+- * @sgl: scatter gather list
+- * @sg_len: length of sg txn
+- * @direction: DMA transfer dirtn
++ * @dest: destn address
++ * @src: src address
++ * @len: DMA transfer len
+ * @flags: DMA flags
+- * @context: transfer context (ignored)
++ *
++ * Perform a DMA memcpy. Note we support slave periphral DMA transfers only
++ * The periphral txn details should be filled in slave structure properly
++ * Returns the descriptor for this txn
++ */
++static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy_v2(
++ struct dma_chan *chan, dma_addr_t dest,
++ dma_addr_t src, size_t len, unsigned long flags)
++{
++ struct intel_mid_dma_chan *midc;
++ struct intel_mid_dma_desc *desc = NULL;
++ struct intel_mid_dma_slave *mids;
++ union intel_mid_dma_ctl_lo ctl_lo;
++ u32 ctl_hi;
++ union intel_mid_dma_cfg_lo cfg_lo;
++ union intel_mid_dma_cfg_hi cfg_hi;
++ enum dma_slave_buswidth width;
++ int dst_reg_width = 0;
++ int src_reg_width = 0;
++
++ pr_debug("MDMA:%s\n", __func__);
++ BUG_ON(!chan);
++ if (!len)
++ return NULL;
++
++ midc = to_intel_mid_dma_chan(chan);
++ BUG_ON(!midc);
++
++ mids = midc->mid_slave;
++ BUG_ON(!mids);
++
++ if (unlikely(!midc->in_use)) {
++ pr_err("ERR_MDMA: %s: channel not in use", __func__);
++ return NULL;
++ }
++
++ pr_debug("MDMA:called for DMA %x CH %d Length %zu\n",
++ midc->dma->pci_id, midc->ch_id, len);
++ pr_debug("MDMA:Cfg passed Mode %x, Dirn %x, HS %x, Width %x\n",
++ mids->cfg_mode, mids->dma_slave.direction,
++ mids->hs_mode, mids->dma_slave.src_addr_width);
++
++ /*calculate CFG_LO*/
++ cfg_lo.cfgx_v2.dst_burst_align = 1;
++ cfg_lo.cfgx_v2.src_burst_align = 1;
++
++ /*calculate CFG_HI*/
++ if (mids->cfg_mode == LNW_DMA_MEM_TO_MEM) {
++ /*SW HS only*/
++ cfg_hi.cfg_hi = 0;
++ } else {
++ cfg_hi.cfg_hi = 0;
++ if (midc->dma->pimr_mask) {
++ if (mids->dma_slave.direction == DMA_MEM_TO_DEV) {
++ cfg_hi.cfgx_v2.src_per = 0;
++ if (mids->device_instance == 0)
++ cfg_hi.cfgx_v2.dst_per = 1;
++ if (mids->device_instance == 1)
++ cfg_hi.cfgx_v2.dst_per = 3;
++ } else if (mids->dma_slave.direction == DMA_DEV_TO_MEM) {
++ if (mids->device_instance == 0)
++ cfg_hi.cfgx_v2.src_per = 0;
++ if (mids->device_instance == 1)
++ cfg_hi.cfgx_v2.src_per = 2;
++ cfg_hi.cfgx_v2.dst_per = 0;
++ }
++ } else {
++ cfg_hi.cfgx_v2.src_per = cfg_hi.cfgx_v2.dst_per =
++ midc->ch_id - midc->dma->chan_base;
++ }
++ }
++ /*calculate CTL_HI*/
++ width = mids->dma_slave.src_addr_width;
++ ctl_hi = get_block_ts(len, width, midc->dma->block_size, midc->dma->dword_trf);
++ pr_debug("MDMA:calc len %d for block size %d\n",
++ ctl_hi, midc->dma->block_size);
++ /*calculate CTL_LO*/
++ ctl_lo.ctl_lo = 0;
++ ctl_lo.ctlx_v2.int_en = 1;
++
++ dst_reg_width = get_reg_width(mids->dma_slave.dst_addr_width);
++ if (dst_reg_width < 0) {
++ pr_err("ERR_MDMA: Failed to get DST reg width\n");
++ return NULL;
++
++ }
++ ctl_lo.ctlx_v2.dst_tr_width = dst_reg_width;
++
++ src_reg_width = get_reg_width(mids->dma_slave.src_addr_width);
++ if (src_reg_width < 0) {
++ pr_err("ERR_MDMA: Failed to get SRC reg width\n");
++ return NULL;
++ }
++ ctl_lo.ctlx_v2.src_tr_width = src_reg_width;
++ ctl_lo.ctlx_v2.dst_msize = mids->dma_slave.src_maxburst;
++ ctl_lo.ctlx_v2.src_msize = mids->dma_slave.dst_maxburst;
++
++ if (mids->cfg_mode == LNW_DMA_MEM_TO_MEM) {
++ ctl_lo.ctlx_v2.tt_fc = 0;
++ ctl_lo.ctlx_v2.sinc = 0;
++ ctl_lo.ctlx_v2.dinc = 0;
++ } else {
++ if (mids->dma_slave.direction == DMA_MEM_TO_DEV) {
++ ctl_lo.ctlx_v2.sinc = 0;
++ ctl_lo.ctlx_v2.dinc = 1;
++ ctl_lo.ctlx_v2.tt_fc = 1;
++ } else if (mids->dma_slave.direction == DMA_DEV_TO_MEM) {
++ ctl_lo.ctlx_v2.sinc = 1;
++ ctl_lo.ctlx_v2.dinc = 0;
++ ctl_lo.ctlx_v2.tt_fc = 2;
++ }
++ }
++
++ pr_debug("MDMA:Calc CTL LO %x, CTL HI %x, CFG LO %x, CFG HI %x\n",
++ ctl_lo.ctl_lo, ctl_hi, cfg_lo.cfg_lo, cfg_hi.cfg_hi);
++
++ enable_dma_interrupt(midc);
++
++ desc = midc_desc_get(midc);
++ if (desc == NULL)
++ goto err_desc_get;
++ desc->sar = src;
++ desc->dar = dest ;
++ desc->len = len;
++ desc->cfg_hi = cfg_hi.cfg_hi;
++ desc->cfg_lo = cfg_lo.cfg_lo;
++ desc->ctl_lo = ctl_lo.ctl_lo;
++ desc->ctl_hi = ctl_hi;
++ desc->width = width;
++ desc->dirn = mids->dma_slave.direction;
++ desc->lli_phys = 0;
++ desc->lli = NULL;
++ desc->lli_pool = NULL;
++ return &desc->txd;
++
++err_desc_get:
++ pr_err("ERR_MDMA: Failed to get desc\n");
++ midc_desc_put(midc, desc);
++ return NULL;
++}
++
++/**
++ * intel_mid_dma_chan_prep_desc
++ * @chan: chan for DMA transfer
++ * @src_sg: destination scatter gather list
++ * @dst_sg: source scatter gather list
++ * @flags: DMA flags
++ * @src_sg_len: length of src sg list
++ * @direction DMA transfer dirtn
+ *
+ * Prepares LLI based periphral transfer
+ */
+-static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg(
+- struct dma_chan *chan, struct scatterlist *sgl,
+- unsigned int sg_len, enum dma_transfer_direction direction,
+- unsigned long flags, void *context)
++static struct dma_async_tx_descriptor *intel_mid_dma_chan_prep_desc(
++ struct dma_chan *chan, struct scatterlist *src_sg,
++ struct scatterlist *dst_sg, unsigned long flags,
++ unsigned long src_sg_len,
++ enum dma_transfer_direction direction)
+ {
++ struct middma_device *mid = NULL;
+ struct intel_mid_dma_chan *midc = NULL;
+ struct intel_mid_dma_slave *mids = NULL;
+ struct intel_mid_dma_desc *desc = NULL;
+ struct dma_async_tx_descriptor *txd = NULL;
+ union intel_mid_dma_ctl_lo ctl_lo;
++ pr_debug("MDMA:intel_mid_dma_chan_prep_desc\n");
+
+- pr_debug("MDMA: Prep for slave SG\n");
+-
+- if (!sg_len) {
+- pr_err("MDMA: Invalid SG length\n");
+- return NULL;
+- }
+ midc = to_intel_mid_dma_chan(chan);
+ BUG_ON(!midc);
+
++ mid = to_middma_device(midc->chan.device);
+ mids = midc->mid_slave;
+ BUG_ON(!mids);
+
+ if (!midc->dma->pimr_mask) {
+- /* We can still handle sg list with only one item */
+- if (sg_len == 1) {
+- txd = intel_mid_dma_prep_memcpy(chan,
+- mids->dma_slave.dst_addr,
+- mids->dma_slave.src_addr,
+- sg_dma_len(sgl),
+- flags);
+- return txd;
+- } else {
+- pr_warn("MDMA: SG list is not supported by this controller\n");
+- return NULL;
+- }
++ pr_err("MDMA: SG list is not supported by this controller\n");
++ return NULL;
+ }
+
+- pr_debug("MDMA: SG Length = %d, direction = %d, Flags = %#lx\n",
+- sg_len, direction, flags);
+-
+- txd = intel_mid_dma_prep_memcpy(chan, 0, 0, sg_dma_len(sgl), flags);
++ txd = midc->dma->dma_ops.device_prep_dma_memcpy(chan, 0, 0, src_sg->length, flags);
+ if (NULL == txd) {
+ pr_err("MDMA: Prep memcpy failed\n");
+ return NULL;
+@@ -768,35 +1164,113 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg(
+ desc = to_intel_mid_dma_desc(txd);
+ desc->dirn = direction;
+ ctl_lo.ctl_lo = desc->ctl_lo;
+- ctl_lo.ctlx.llp_dst_en = 1;
+- ctl_lo.ctlx.llp_src_en = 1;
++ ctl_lo.ctl_lo |= (1 << CTL_LO_BIT_LLP_DST_EN);
++ ctl_lo.ctl_lo |= (1 << CTL_LO_BIT_LLP_SRC_EN);
+ desc->ctl_lo = ctl_lo.ctl_lo;
+- desc->lli_length = sg_len;
++ desc->lli_length = src_sg_len;
+ desc->current_lli = 0;
+ /* DMA coherent memory pool for LLI descriptors*/
+- desc->lli_pool = pci_pool_create("intel_mid_dma_lli_pool",
+- midc->dma->pdev,
+- (sizeof(struct intel_mid_dma_lli)*sg_len),
++ desc->lli_pool = dma_pool_create("intel_mid_dma_lli_pool",
++ midc->dma->dev,
++ (sizeof(struct intel_mid_dma_lli)*src_sg_len),
+ 32, 0);
+ if (NULL == desc->lli_pool) {
+ pr_err("MID_DMA:LLI pool create failed\n");
+ return NULL;
+ }
++ midc->lli_pool = desc->lli_pool;
+
+- desc->lli = pci_pool_alloc(desc->lli_pool, GFP_KERNEL, &desc->lli_phys);
++ desc->lli = dma_pool_alloc(desc->lli_pool, GFP_KERNEL, &desc->lli_phys);
+ if (!desc->lli) {
+ pr_err("MID_DMA: LLI alloc failed\n");
+- pci_pool_destroy(desc->lli_pool);
++ dma_pool_destroy(desc->lli_pool);
+ return NULL;
+ }
+-
+- midc_lli_fill_sg(midc, desc, sgl, sg_len, flags);
++ midc_lli_fill_sg(midc, desc, src_sg, dst_sg, src_sg_len, flags);
+ if (flags & DMA_PREP_INTERRUPT) {
++ /* Enable Block intr, disable TFR intr.
++ * It's not required to enable TFR, when Block intr is enabled
++ * Otherwise, for last block we will end up in invoking calltxd
++ * two times */
++
++ iowrite32(MASK_INTR_REG(midc->ch_id),
++ midc->dma_base + MASK_TFR);
++ clear_bit(midc->ch_id, &mid->tfr_intr_mask);
+ iowrite32(UNMASK_INTR_REG(midc->ch_id),
+- midc->dma_base + MASK_BLOCK);
+- pr_debug("MDMA:Enabled Block interrupt\n");
++ midc->dma_base + MASK_BLOCK);
++ set_bit(midc->ch_id, &mid->block_intr_mask);
++ midc->block_intr_status = true;
++ pr_debug("MDMA: Enabled Block Interrupt\n");
+ }
+ return &desc->txd;
++
++}
++
++/**
++ * intel_mid_dma_prep_sg - Prep sg txn
++ * @chan: chan for DMA transfer
++ * @dst_sg: destination scatter gather list
++ * @dst_sg_len: length of dest sg list
++ * @src_sg: source scatter gather list
++ * @src_sg_len: length of src sg list
++ * @flags: DMA flags
++ *
++ * Prepares LLI based periphral transfer
++ */
++static struct dma_async_tx_descriptor *intel_mid_dma_prep_sg(
++ struct dma_chan *chan, struct scatterlist *dst_sg,
++ unsigned int dst_sg_len, struct scatterlist *src_sg,
++ unsigned int src_sg_len, unsigned long flags)
++{
++
++ pr_debug("MDMA: Prep for memcpy SG\n");
++
++ if ((dst_sg_len != src_sg_len) || (dst_sg == NULL) ||
++ (src_sg == NULL)) {
++ pr_err("MDMA: Invalid SG length\n");
++ return NULL;
++ }
++
++ pr_debug("MDMA: SG Length = %d, Flags = %#lx, src_sg->length = %d\n",
++ src_sg_len, flags, src_sg->length);
++
++ return intel_mid_dma_chan_prep_desc(chan, src_sg, dst_sg, flags,
++ src_sg_len, DMA_MEM_TO_MEM);
++
++}
++
++/**
++ * intel_mid_dma_prep_slave_sg - Prep slave sg txn
++ * @chan: chan for DMA transfer
++ * @sgl: scatter gather list
++ * @sg_len: length of sg txn
++ * @direction: DMA transfer dirtn
++ * @flags: DMA flags
++ * @context: transfer context (ignored)
++ *
++ * Prepares LLI based periphral transfer
++ */
++static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg(
++ struct dma_chan *chan, struct scatterlist *sg,
++ unsigned int sg_len, enum dma_transfer_direction direction,
++ unsigned long flags, void *context)
++{
++
++ pr_debug("MDMA: Prep for slave SG\n");
++
++ if (!sg_len || sg == NULL) {
++ pr_err("MDMA: Invalid SG length\n");
++ return NULL;
++ }
++ pr_debug("MDMA: SG Length = %d, direction = %d, Flags = %#lx\n",
++ sg_len, direction, flags);
++ if (direction != DMA_MEM_TO_MEM) {
++ return intel_mid_dma_chan_prep_desc(chan, sg, NULL, flags,
++ sg_len, direction);
++ } else {
++ pr_err("MDMA: Invalid Direction\n");
++ return NULL;
++ }
+ }
+
+ /**
+@@ -811,31 +1285,52 @@ static void intel_mid_dma_free_chan_resources(struct dma_chan *chan)
+ struct middma_device *mid = to_middma_device(chan->device);
+ struct intel_mid_dma_desc *desc, *_desc;
+
++ pr_debug("entry:%s\n", __func__);
++ if (false == midc->in_use) {
++ pr_err("ERR_MDMA: try to free chnl already freed\n");
++ return;
++ }
+ if (true == midc->busy) {
+ /*trying to free ch in use!!!!!*/
+ pr_err("ERR_MDMA: trying to free ch in use\n");
++ dump_dma_reg(chan);
+ }
++
++ /* Disable CH interrupts */
++ disable_dma_interrupt(midc);
++ clear_dma_channel_interrupt(midc);
++
++ midc->block_intr_status = false;
++ midc->in_use = false;
++ midc->busy = false;
++
++ tasklet_unlock_wait(&mid->tasklet);
++
+ spin_lock_bh(&midc->lock);
+ midc->descs_allocated = 0;
+ list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
+ list_del(&desc->desc_node);
+- pci_pool_free(mid->dma_pool, desc, desc->txd.phys);
++ dma_pool_free(mid->dma_pool, desc, desc->txd.phys);
+ }
+ list_for_each_entry_safe(desc, _desc, &midc->free_list, desc_node) {
+ list_del(&desc->desc_node);
+- pci_pool_free(mid->dma_pool, desc, desc->txd.phys);
++ dma_pool_free(mid->dma_pool, desc, desc->txd.phys);
+ }
+ list_for_each_entry_safe(desc, _desc, &midc->queue, desc_node) {
+ list_del(&desc->desc_node);
+- pci_pool_free(mid->dma_pool, desc, desc->txd.phys);
++ dma_pool_free(mid->dma_pool, desc, desc->txd.phys);
+ }
++ midc->raw_tfr = 0;
+ spin_unlock_bh(&midc->lock);
+- midc->in_use = false;
+- midc->busy = false;
+- /* Disable CH interrupts */
+- iowrite32(MASK_INTR_REG(midc->ch_id), mid->dma_base + MASK_BLOCK);
+- iowrite32(MASK_INTR_REG(midc->ch_id), mid->dma_base + MASK_ERR);
+- pm_runtime_put(&mid->pdev->dev);
++
++ if (midc->lli_pool) {
++ dma_pool_destroy(midc->lli_pool);
++ midc->lli_pool = NULL;
++ }
++
++ /* Disable the channel */
++ iowrite32(DISABLE_CHANNEL(midc->ch_id), mid->dma_base + DMA_CHAN_EN);
++ pm_runtime_put(mid->dev);
+ }
+
+ /**
+@@ -853,20 +1348,19 @@ static int intel_mid_dma_alloc_chan_resources(struct dma_chan *chan)
+ dma_addr_t phys;
+ int i = 0;
+
+- pm_runtime_get_sync(&mid->pdev->dev);
++ pm_runtime_get_sync(mid->dev);
+
+ if (mid->state == SUSPENDED) {
+- if (dma_resume(&mid->pdev->dev)) {
++ if (dma_resume(mid->dev)) {
+ pr_err("ERR_MDMA: resume failed");
+ return -EFAULT;
+ }
+ }
+
+ /* ASSERT: channel is idle */
+- if (test_ch_en(mid->dma_base, midc->ch_id)) {
+- /*ch is not idle*/
++ if (midc->in_use == true) {
+ pr_err("ERR_MDMA: ch not idle\n");
+- pm_runtime_put(&mid->pdev->dev);
++ pm_runtime_put(mid->dev);
+ return -EIO;
+ }
+ dma_cookie_init(chan);
+@@ -874,10 +1368,10 @@ static int intel_mid_dma_alloc_chan_resources(struct dma_chan *chan)
+ spin_lock_bh(&midc->lock);
+ while (midc->descs_allocated < DESCS_PER_CHANNEL) {
+ spin_unlock_bh(&midc->lock);
+- desc = pci_pool_alloc(mid->dma_pool, GFP_KERNEL, &phys);
++ desc = dma_pool_alloc(mid->dma_pool, GFP_KERNEL, &phys);
+ if (!desc) {
+ pr_err("ERR_MDMA: desc failed\n");
+- pm_runtime_put(&mid->pdev->dev);
++ pm_runtime_put(mid->dev);
+ return -ENOMEM;
+ /*check*/
+ }
+@@ -889,9 +1383,10 @@ static int intel_mid_dma_alloc_chan_resources(struct dma_chan *chan)
+ i = ++midc->descs_allocated;
+ list_add_tail(&desc->desc_node, &midc->free_list);
+ }
++ midc->busy = false;
+ spin_unlock_bh(&midc->lock);
+ midc->in_use = true;
+- midc->busy = false;
++ midc->block_intr_status = false;
+ pr_debug("MID_DMA: Desc alloc done ret: %d desc\n", i);
+ return i;
+ }
+@@ -906,7 +1401,8 @@ static int intel_mid_dma_alloc_chan_resources(struct dma_chan *chan)
+ static void midc_handle_error(struct middma_device *mid,
+ struct intel_mid_dma_chan *midc)
+ {
+- midc_scan_descriptors(mid, midc);
++ midc_collect_descriptors(mid, midc);
++ midc_start_descriptors(mid, midc);
+ }
+
+ /**
+@@ -922,24 +1418,25 @@ static void dma_tasklet(unsigned long data)
+ struct intel_mid_dma_chan *midc = NULL;
+ u32 status, raw_tfr, raw_block;
+ int i;
+-
+ mid = (struct middma_device *)data;
+ if (mid == NULL) {
+ pr_err("ERR_MDMA: tasklet Null param\n");
+ return;
+ }
+- pr_debug("MDMA: in tasklet for device %x\n", mid->pci_id);
+ raw_tfr = ioread32(mid->dma_base + RAW_TFR);
+- raw_block = ioread32(mid->dma_base + RAW_BLOCK);
+- status = raw_tfr | raw_block;
+- status &= mid->intr_mask;
++ status = raw_tfr & mid->tfr_intr_mask;
++ pr_debug("MDMA: in tasklet for device %x\n", mid->pci_id);
++ pr_debug("tfr_mask:%#lx, raw_tfr:%#x, status:%#x\n",
++ mid->tfr_intr_mask, raw_tfr, status);
+ while (status) {
+ /*txn interrupt*/
+- i = get_ch_index(&status, mid->chan_base);
++ i = get_ch_index(status, mid->chan_base);
+ if (i < 0) {
+ pr_err("ERR_MDMA:Invalid ch index %x\n", i);
+ return;
+ }
++ /* clear the status bit */
++ status = status & ~(1 << (i + mid->chan_base));
+ midc = &mid->ch[i];
+ if (midc == NULL) {
+ pr_err("ERR_MDMA:Null param midc\n");
+@@ -947,38 +1444,69 @@ static void dma_tasklet(unsigned long data)
+ }
+ pr_debug("MDMA:Tx complete interrupt %x, Ch No %d Index %d\n",
+ status, midc->ch_id, i);
+- midc->raw_tfr = raw_tfr;
+- midc->raw_block = raw_block;
+ spin_lock_bh(&midc->lock);
++ midc->raw_tfr = raw_tfr;
+ /*clearing this interrupts first*/
+ iowrite32((1 << midc->ch_id), mid->dma_base + CLEAR_TFR);
+- if (raw_block) {
+- iowrite32((1 << midc->ch_id),
+- mid->dma_base + CLEAR_BLOCK);
++ if (likely(midc->in_use)) {
++ midc_collect_descriptors(mid, midc);
++ midc_start_descriptors(mid, midc);
+ }
+- midc_scan_descriptors(mid, midc);
+ pr_debug("MDMA:Scan of desc... complete, unmasking\n");
+ iowrite32(UNMASK_INTR_REG(midc->ch_id),
+- mid->dma_base + MASK_TFR);
+- if (raw_block) {
+- iowrite32(UNMASK_INTR_REG(midc->ch_id),
+- mid->dma_base + MASK_BLOCK);
++ mid->dma_base + MASK_TFR);
++ spin_unlock_bh(&midc->lock);
++ }
++
++ raw_block = ioread32(mid->dma_base + RAW_BLOCK);
++ status = raw_block & mid->block_intr_mask;
++ pr_debug("MDMA: in tasklet for device %x\n", mid->pci_id);
++ pr_debug("block_mask:%#lx, raw_block%#x, status:%#x\n",
++ mid->block_intr_mask, raw_block, status);
++ while (status) {
++ /*txn interrupt*/
++ i = get_ch_index(status, mid->chan_base);
++ if (i < 0) {
++ pr_err("ERR_MDMA:Invalid ch index %x\n", i);
++ return;
+ }
++ /* clear the status bit */
++ status = status & ~(1 << (i + mid->chan_base));
++ midc = &mid->ch[i];
++ if (midc == NULL) {
++ pr_err("ERR_MDMA:Null param midc\n");
++ return;
++ }
++ pr_debug("MDMA:Tx complete interrupt raw block %x, Ch No %d Index %d\n",
++ status, midc->ch_id, i);
++ spin_lock_bh(&midc->lock);
++ /*clearing this interrupts first*/
++
++ midc->raw_block = raw_block;
++ iowrite32((1 << midc->ch_id), mid->dma_base + CLEAR_BLOCK);
++ if (midc->block_intr_status) {
++ midc_collect_descriptors(mid, midc);
++ midc_start_descriptors(mid, midc);
++ }
++
++ iowrite32(UNMASK_INTR_REG(midc->ch_id),
++ mid->dma_base + MASK_BLOCK);
+ spin_unlock_bh(&midc->lock);
+ }
+
+ status = ioread32(mid->dma_base + RAW_ERR);
+- status &= mid->intr_mask;
++ pr_debug("MDMA:raw error status:%#x\n", status);
+ while (status) {
+ /*err interrupt*/
+- i = get_ch_index(&status, mid->chan_base);
++ i = get_ch_index(status, mid->chan_base);
+ if (i < 0) {
+- pr_err("ERR_MDMA:Invalid ch index %x\n", i);
++ pr_err("ERR_MDMA:Invalid ch index %x (raw err)\n", i);
+ return;
+ }
++ status = status & ~(1 << (i + mid->chan_base));
+ midc = &mid->ch[i];
+ if (midc == NULL) {
+- pr_err("ERR_MDMA:Null param midc\n");
++ pr_err("ERR_MDMA:Null param midc (raw err)\n");
+ return;
+ }
+ pr_debug("MDMA:Tx complete interrupt %x, Ch No %d Index %d\n",
+@@ -1018,33 +1546,59 @@ static void dma_tasklet2(unsigned long data)
+ static irqreturn_t intel_mid_dma_interrupt(int irq, void *data)
+ {
+ struct middma_device *mid = data;
+- u32 tfr_status, err_status;
+- int call_tasklet = 0;
++ u32 tfr_status, err_status, block_status;
++ u32 isr;
+
+- tfr_status = ioread32(mid->dma_base + RAW_TFR);
+- err_status = ioread32(mid->dma_base + RAW_ERR);
+- if (!tfr_status && !err_status)
++ /* On Baytrail, the DMAC is sharing IRQ with other devices */
++ if (is_byt_lpio_dmac(mid) && mid->state == SUSPENDED)
+ return IRQ_NONE;
+
+ /*DMA Interrupt*/
+ pr_debug("MDMA:Got an interrupt on irq %d\n", irq);
+- pr_debug("MDMA: Status %x, Mask %x\n", tfr_status, mid->intr_mask);
+- tfr_status &= mid->intr_mask;
++ if (!mid) {
++ pr_err("ERR_MDMA:null pointer mid\n");
++ return -EINVAL;
++ }
++
++ /* Read the interrupt status registers */
++ tfr_status = ioread32(mid->dma_base + STATUS_TFR);
++ err_status = ioread32(mid->dma_base + STATUS_ERR);
++ block_status = ioread32(mid->dma_base + STATUS_BLOCK);
++
++ /* Common case if the IRQ is shared with other devices */
++ if (!tfr_status && !err_status && !block_status)
++ return IRQ_NONE;
++
++ pr_debug("MDMA: trf_Status %x, Mask %x\n", tfr_status, mid->intr_mask);
+ if (tfr_status) {
+ /*need to disable intr*/
+- iowrite32((tfr_status << INT_MASK_WE), mid->dma_base + MASK_TFR);
+- iowrite32((tfr_status << INT_MASK_WE), mid->dma_base + MASK_BLOCK);
+- pr_debug("MDMA: Calling tasklet %x\n", tfr_status);
+- call_tasklet = 1;
++ iowrite32((tfr_status << INT_MASK_WE),
++ mid->dma_base + MASK_TFR);
++ }
++ if (block_status) {
++ /*need to disable intr*/
++ iowrite32((block_status << INT_MASK_WE),
++ mid->dma_base + MASK_BLOCK);
+ }
+- err_status &= mid->intr_mask;
+ if (err_status) {
+ iowrite32((err_status << INT_MASK_WE),
+ mid->dma_base + MASK_ERR);
+- call_tasklet = 1;
+ }
+- if (call_tasklet)
+- tasklet_schedule(&mid->tasklet);
++ /* in mrlfd we need to clear the pisr bits to stop intr as well
++ * so read the PISR register, see if we have pisr bits status and clear
++ * them
++ */
++ if (mid->pimr_mask && !mid->dword_trf) {
++ isr = readl(mid->mask_reg);
++ pr_debug("isr says: %x", isr);
++ if (isr) {
++ isr &= mid->pimr_mask;
++ pr_debug("writing isr: %x", isr);
++ writel(isr, mid->mask_reg);
++ }
++ }
++
++ tasklet_schedule(&mid->tasklet);
+
+ return IRQ_HANDLED;
+ }
+@@ -1059,6 +1613,41 @@ static irqreturn_t intel_mid_dma_interrupt2(int irq, void *data)
+ return intel_mid_dma_interrupt(irq, data);
+ }
+
++static void config_dma_fifo_partition(struct middma_device *dma)
++{
++ /* program FIFO Partition registers - 128 bytes for each ch */
++ iowrite32(DMA_FIFO_SIZE, dma->dma_base + FIFO_PARTITION0_HI);
++ iowrite32(DMA_FIFO_SIZE, dma->dma_base + FIFO_PARTITION1_LO);
++ iowrite32(DMA_FIFO_SIZE, dma->dma_base + FIFO_PARTITION1_HI);
++ iowrite32(DMA_FIFO_SIZE | BIT(26), dma->dma_base + FIFO_PARTITION0_LO);
++}
++
++/* v1 ops will be used for Medfield & CTP platforms */
++static struct intel_mid_dma_ops v1_dma_ops = {
++ .device_alloc_chan_resources = intel_mid_dma_alloc_chan_resources,
++ .device_free_chan_resources = intel_mid_dma_free_chan_resources,
++ .device_prep_dma_memcpy = intel_mid_dma_prep_memcpy,
++ .device_prep_dma_sg = intel_mid_dma_prep_sg,
++ .device_prep_slave_sg = intel_mid_dma_prep_slave_sg,
++ .device_control = intel_mid_dma_device_control,
++ .device_tx_status = intel_mid_dma_tx_status,
++ .device_issue_pending = intel_mid_dma_issue_pending,
++ .dma_chan_suspend = intel_mid_dma_chan_suspend_v1,
++};
++
++/* v2 ops will be used in Merrifield and beyond plantforms */
++static struct intel_mid_dma_ops v2_dma_ops = {
++ .device_alloc_chan_resources = intel_mid_dma_alloc_chan_resources,
++ .device_free_chan_resources = intel_mid_dma_free_chan_resources,
++ .device_prep_dma_memcpy = intel_mid_dma_prep_memcpy_v2,
++ .device_prep_dma_sg = intel_mid_dma_prep_sg,
++ .device_prep_slave_sg = intel_mid_dma_prep_slave_sg,
++ .device_control = intel_mid_dma_device_control,
++ .device_tx_status = intel_mid_dma_tx_status,
++ .device_issue_pending = intel_mid_dma_issue_pending,
++ .dma_chan_suspend = intel_mid_dma_chan_suspend_v2,
++};
++
+ /**
+ * mid_setup_dma - Setup the DMA controller
+ * @pdev: Controller PCI device structure
+@@ -1066,33 +1655,33 @@ static irqreturn_t intel_mid_dma_interrupt2(int irq, void *data)
+ * Initialize the DMA controller, channels, registers with DMA engine,
+ * ISR. Initialize DMA controller channels.
+ */
+-static int mid_setup_dma(struct pci_dev *pdev)
++int mid_setup_dma(struct device *dev)
+ {
+- struct middma_device *dma = pci_get_drvdata(pdev);
++ struct middma_device *dma = dev_get_drvdata(dev);
+ int err, i;
+
+ /* DMA coherent memory pool for DMA descriptor allocations */
+- dma->dma_pool = pci_pool_create("intel_mid_dma_desc_pool", pdev,
++ dma->dma_pool = dma_pool_create("intel_mid_dma_desc_pool", dev,
+ sizeof(struct intel_mid_dma_desc),
+ 32, 0);
+ if (NULL == dma->dma_pool) {
+- pr_err("ERR_MDMA:pci_pool_create failed\n");
++ pr_err("ERR_MDMA:dma_pool_create failed\n");
+ err = -ENOMEM;
++ kfree(dma);
+ goto err_dma_pool;
+ }
+
+ INIT_LIST_HEAD(&dma->common.channels);
+- dma->pci_id = pdev->device;
+ if (dma->pimr_mask) {
+- dma->mask_reg = ioremap(LNW_PERIPHRAL_MASK_BASE,
+- LNW_PERIPHRAL_MASK_SIZE);
++ dma->mask_reg = devm_ioremap(dma->dev, dma->pimr_base, LNW_PERIPHRAL_MASK_SIZE);
+ if (dma->mask_reg == NULL) {
+ pr_err("ERR_MDMA:Can't map periphral intr space !!\n");
+ err = -ENOMEM;
+- goto err_ioremap;
++ goto err_setup;
+ }
+- } else
++ } else {
+ dma->mask_reg = NULL;
++ }
+
+ pr_debug("MDMA:Adding %d channel for this controller\n", dma->max_chan);
+ /*init CH structures*/
+@@ -1137,18 +1726,17 @@ static int mid_setup_dma(struct pci_dev *pdev)
+ dma_cap_set(DMA_MEMCPY, dma->common.cap_mask);
+ dma_cap_set(DMA_SLAVE, dma->common.cap_mask);
+ dma_cap_set(DMA_PRIVATE, dma->common.cap_mask);
+- dma->common.dev = &pdev->dev;
++ dma->common.dev = dev;
+
+- dma->common.device_alloc_chan_resources =
+- intel_mid_dma_alloc_chan_resources;
+- dma->common.device_free_chan_resources =
+- intel_mid_dma_free_chan_resources;
++ dma->common.device_alloc_chan_resources = dma->dma_ops.device_alloc_chan_resources;
++ dma->common.device_free_chan_resources = dma->dma_ops.device_free_chan_resources;
+
+- dma->common.device_tx_status = intel_mid_dma_tx_status;
+- dma->common.device_prep_dma_memcpy = intel_mid_dma_prep_memcpy;
+- dma->common.device_issue_pending = intel_mid_dma_issue_pending;
+- dma->common.device_prep_slave_sg = intel_mid_dma_prep_slave_sg;
+- dma->common.device_control = intel_mid_dma_device_control;
++ dma->common.device_tx_status = dma->dma_ops.device_tx_status;
++ dma->common.device_prep_dma_memcpy = dma->dma_ops.device_prep_dma_memcpy;
++ dma->common.device_prep_dma_sg = dma->dma_ops.device_prep_dma_sg;
++ dma->common.device_issue_pending = dma->dma_ops.device_issue_pending;
++ dma->common.device_prep_slave_sg = dma->dma_ops.device_prep_slave_sg;
++ dma->common.device_control = dma->dma_ops.device_control;
+
+ /*enable dma cntrl*/
+ iowrite32(REG_BIT0, dma->dma_base + DMA_CFG);
+@@ -1156,23 +1744,23 @@ static int mid_setup_dma(struct pci_dev *pdev)
+ /*register irq */
+ if (dma->pimr_mask) {
+ pr_debug("MDMA:Requesting irq shared for DMAC1\n");
+- err = request_irq(pdev->irq, intel_mid_dma_interrupt1,
++ err = devm_request_irq(dma->dev, dma->irq, intel_mid_dma_interrupt1,
+ IRQF_SHARED, "INTEL_MID_DMAC1", dma);
+ if (0 != err)
+- goto err_irq;
++ goto err_setup;
+ } else {
+ dma->intr_mask = 0x03;
+ pr_debug("MDMA:Requesting irq for DMAC2\n");
+- err = request_irq(pdev->irq, intel_mid_dma_interrupt2,
++ err = devm_request_irq(dma->dev, dma->irq, intel_mid_dma_interrupt2,
+ IRQF_SHARED, "INTEL_MID_DMAC2", dma);
+ if (0 != err)
+- goto err_irq;
++ goto err_setup;
+ }
+ /*register device w/ engine*/
+ err = dma_async_device_register(&dma->common);
+ if (0 != err) {
+ pr_err("ERR_MDMA:device_register failed: %d\n", err);
+- goto err_engine;
++ goto err_dma_pool;
+ }
+ if (dma->pimr_mask) {
+ pr_debug("setting up tasklet1 for DMAC1\n");
+@@ -1181,15 +1769,15 @@ static int mid_setup_dma(struct pci_dev *pdev)
+ pr_debug("setting up tasklet2 for DMAC2\n");
+ tasklet_init(&dma->tasklet, dma_tasklet2, (unsigned long)dma);
+ }
++ if (!dma->dword_trf) {
++ config_dma_fifo_partition(dma);
++ /* Mask all interrupts from DMA controller to IA by default */
++ dmac1_mask_periphral_intr(dma);
++ }
+ return 0;
+
+-err_engine:
+- free_irq(pdev->irq, dma);
+-err_irq:
+- if (dma->mask_reg)
+- iounmap(dma->mask_reg);
+-err_ioremap:
+- pci_pool_destroy(dma->dma_pool);
++err_setup:
++ dma_pool_destroy(dma->dma_pool);
+ err_dma_pool:
+ pr_err("ERR_MDMA:setup_dma failed: %d\n", err);
+ return err;
+@@ -1198,25 +1786,42 @@ err_dma_pool:
+
+ /**
+ * middma_shutdown - Shutdown the DMA controller
+- * @pdev: Controller PCI device structure
++ * @dev: Controller device structure
+ *
+ * Called by remove
+ * Unregister DMa controller, clear all structures and free interrupt
+ */
+-static void middma_shutdown(struct pci_dev *pdev)
++void middma_shutdown(struct device *dev)
+ {
+- struct middma_device *device = pci_get_drvdata(pdev);
++ struct middma_device *device = dev_get_drvdata(dev);
+
+ dma_async_device_unregister(&device->common);
+- pci_pool_destroy(device->dma_pool);
+- if (device->mask_reg)
+- iounmap(device->mask_reg);
+- if (device->dma_base)
+- iounmap(device->dma_base);
+- free_irq(pdev->irq, device);
++ dma_pool_destroy(device->dma_pool);
+ return;
+ }
+
++struct middma_device *mid_dma_setup_context(struct device *dev,
++ struct intel_mid_dma_probe_info *info)
++{
++ struct middma_device *mid_device;
++ mid_device = devm_kzalloc(dev, sizeof(*mid_device), GFP_KERNEL);
++ if (!mid_device) {
++ pr_err("ERR_MDMA:kzalloc failed probe\n");
++ return NULL;
++ }
++ mid_device->dev = dev;
++ mid_device->max_chan = info->max_chan;
++ mid_device->chan_base = info->ch_base;
++ mid_device->block_size = info->block_size;
++ mid_device->pimr_mask = info->pimr_mask;
++ mid_device->pimr_base = info->pimr_base;
++ mid_device->dword_trf = info->dword_trf;
++ mid_device->pimr_offset = info->pimr_offset;
++ mid_device->pci_id = info->pci_id;
++ memcpy(&mid_device->dma_ops, info->pdma_ops, sizeof(struct intel_mid_dma_ops));
++ return mid_device;
++}
++
+ /**
+ * intel_mid_dma_probe - PCI Probe
+ * @pdev: Controller PCI device structure
+@@ -1255,42 +1860,41 @@ static int intel_mid_dma_probe(struct pci_dev *pdev,
+ if (err)
+ goto err_set_dma_mask;
+
+- device = kzalloc(sizeof(*device), GFP_KERNEL);
+- if (!device) {
+- pr_err("ERR_MDMA:kzalloc failed probe\n");
+- err = -ENOMEM;
++ pci_dev_get(pdev);
++ device = mid_dma_setup_context(&pdev->dev, info);
++ if (!device)
+ goto err_kzalloc;
+- }
+- device->pdev = pci_dev_get(pdev);
++
++ device->pci_id = pdev->device;
+
+ base_addr = pci_resource_start(pdev, 0);
+ bar_size = pci_resource_len(pdev, 0);
+- device->dma_base = ioremap_nocache(base_addr, DMA_REG_SIZE);
++ device->dma_base = devm_ioremap_nocache(&pdev->dev, base_addr, DMA_REG_SIZE);
+ if (!device->dma_base) {
+ pr_err("ERR_MDMA:ioremap failed\n");
+ err = -ENOMEM;
+ goto err_ioremap;
+ }
++ device->irq = pdev->irq;
+ pci_set_drvdata(pdev, device);
+ pci_set_master(pdev);
+- device->max_chan = info->max_chan;
+- device->chan_base = info->ch_base;
+- device->block_size = info->block_size;
+- device->pimr_mask = info->pimr_mask;
+
+- err = mid_setup_dma(pdev);
++#ifdef CONFIG_PRH_TEMP_WA_FOR_SPID
++ /* PRH uses, ch 4,5,6,7 override the info table data */
++ pr_info("Device is Bodegabay\n");
++ device->max_chan = 4;
++ device->chan_base = 4;
++#endif
++ err = mid_setup_dma(&pdev->dev);
+ if (err)
+- goto err_dma;
++ goto err_ioremap;
+
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_allow(&pdev->dev);
+ return 0;
+
+-err_dma:
+- iounmap(device->dma_base);
+ err_ioremap:
+ pci_dev_put(pdev);
+- kfree(device);
+ err_kzalloc:
+ err_set_dma_mask:
+ pci_release_regions(pdev);
+@@ -1310,31 +1914,26 @@ err_enable_device:
+ */
+ static void intel_mid_dma_remove(struct pci_dev *pdev)
+ {
+- struct middma_device *device = pci_get_drvdata(pdev);
+-
+ pm_runtime_get_noresume(&pdev->dev);
+ pm_runtime_forbid(&pdev->dev);
+- middma_shutdown(pdev);
++ middma_shutdown(&pdev->dev);
+ pci_dev_put(pdev);
+- kfree(device);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ }
+
+ /* Power Management */
+ /*
+-* dma_suspend - PCI suspend function
++* dma_suspend - suspend function
+ *
+-* @pci: PCI device structure
+-* @state: PM message
++* @dev: device structure
+ *
+ * This function is called by OS when a power event occurs
+ */
+-static int dma_suspend(struct device *dev)
++int dma_suspend(struct device *dev)
+ {
+- struct pci_dev *pci = to_pci_dev(dev);
+ int i;
+- struct middma_device *device = pci_get_drvdata(pci);
++ struct middma_device *device = dev_get_drvdata(dev);
+ pr_debug("MDMA: dma_suspend called\n");
+
+ for (i = 0; i < device->max_chan; i++) {
+@@ -1343,93 +1942,106 @@ static int dma_suspend(struct device *dev)
+ }
+ dmac1_mask_periphral_intr(device);
+ device->state = SUSPENDED;
+- pci_save_state(pci);
+- pci_disable_device(pci);
+- pci_set_power_state(pci, PCI_D3hot);
++
+ return 0;
+ }
+
+ /**
+-* dma_resume - PCI resume function
++* dma_resume - resume function
+ *
+-* @pci: PCI device structure
++* @dev: device structure
+ *
+ * This function is called by OS when a power event occurs
+ */
+ int dma_resume(struct device *dev)
+ {
+- struct pci_dev *pci = to_pci_dev(dev);
+- int ret;
+- struct middma_device *device = pci_get_drvdata(pci);
++ struct middma_device *device = dev_get_drvdata(dev);
+
+ pr_debug("MDMA: dma_resume called\n");
+- pci_set_power_state(pci, PCI_D0);
+- pci_restore_state(pci);
+- ret = pci_enable_device(pci);
+- if (ret) {
+- pr_err("MDMA: device can't be enabled for %x\n", pci->device);
+- return ret;
+- }
+ device->state = RUNNING;
+ iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
++
++ if (!device->dword_trf)
++ config_dma_fifo_partition(device);
++
+ return 0;
+ }
+
+ static int dma_runtime_suspend(struct device *dev)
+ {
+- struct pci_dev *pci_dev = to_pci_dev(dev);
+- struct middma_device *device = pci_get_drvdata(pci_dev);
+-
+- device->state = SUSPENDED;
+- return 0;
++ return dma_suspend(dev);
+ }
+
+ static int dma_runtime_resume(struct device *dev)
+ {
+- struct pci_dev *pci_dev = to_pci_dev(dev);
+- struct middma_device *device = pci_get_drvdata(pci_dev);
+-
+- device->state = RUNNING;
+- iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
+- return 0;
++ return dma_resume(dev);
+ }
+
+ static int dma_runtime_idle(struct device *dev)
+ {
+- struct pci_dev *pdev = to_pci_dev(dev);
+- struct middma_device *device = pci_get_drvdata(pdev);
++ struct middma_device *device = dev_get_drvdata(dev);
+ int i;
+
+ for (i = 0; i < device->max_chan; i++) {
+ if (device->ch[i].in_use)
+ return -EAGAIN;
+ }
+-
+- return pm_schedule_suspend(dev, 0);
++ return pm_schedule_suspend(dev, 0);;
+ }
+
+ /******************************************************************************
+ * PCI stuff
+ */
+ static struct pci_device_id intel_mid_dma_ids[] = {
+- { PCI_VDEVICE(INTEL, INTEL_MID_DMAC1_ID), INFO(2, 6, 4095, 0x200020)},
+- { PCI_VDEVICE(INTEL, INTEL_MID_DMAC2_ID), INFO(2, 0, 2047, 0)},
+- { PCI_VDEVICE(INTEL, INTEL_MID_GP_DMAC2_ID), INFO(2, 0, 2047, 0)},
+- { PCI_VDEVICE(INTEL, INTEL_MFLD_DMAC1_ID), INFO(4, 0, 4095, 0x400040)},
++ { PCI_VDEVICE(INTEL, INTEL_MID_DMAC1_ID),
++ INFO(2, 6, SST_MAX_DMA_LEN, 0x200020, 0xFFAE8008, 1, 0x8, INTEL_MID_DMAC1_ID, &v1_dma_ops)},
++ { PCI_VDEVICE(INTEL, INTEL_MID_DMAC2_ID),
++ INFO(2, 0, 2047, 0, 0, 1, 0, INTEL_MID_DMAC2_ID, &v1_dma_ops)},
++ { PCI_VDEVICE(INTEL, INTEL_MID_GP_DMAC2_ID),
++ INFO(2, 0, 2047, 0, 0, 1, 0, INTEL_MID_GP_DMAC2_ID, &v1_dma_ops)},
++ { PCI_VDEVICE(INTEL, INTEL_MFLD_DMAC1_ID),
++ INFO(4, 0, SST_MAX_DMA_LEN, 0x400040, 0xFFAE8008, 1, 0x8, INTEL_MFLD_DMAC1_ID, &v1_dma_ops)},
++ /* Cloverview support */
++ { PCI_VDEVICE(INTEL, INTEL_CLV_GP_DMAC2_ID),
++ INFO(2, 0, 2047, 0, 0, 1, 0, INTEL_CLV_GP_DMAC2_ID, &v1_dma_ops)},
++ { PCI_VDEVICE(INTEL, INTEL_CLV_DMAC1_ID),
++ INFO(4, 0, SST_MAX_DMA_LEN, 0x400040, 0xFFAE8008, 1, 0x8, INTEL_CLV_DMAC1_ID, &v1_dma_ops)},
++ /* Mrfld */
++ { PCI_VDEVICE(INTEL, INTEL_MRFLD_GP_DMAC2_ID),
++ INFO(4, 0, SST_MAX_DMA_LEN_MRFLD, 0, 0, 0, 0, INTEL_MRFLD_GP_DMAC2_ID, &v2_dma_ops)},
++ { PCI_VDEVICE(INTEL, INTEL_MRFLD_DMAC0_ID),
++ INFO(2, 6, SST_MAX_DMA_LEN_MRFLD, 0xFF0000, 0xFF340018, 0, 0x10, INTEL_MRFLD_DMAC0_ID, &v2_dma_ops)},
++ /* Baytrail Low Speed Peripheral DMA */
++ { PCI_VDEVICE(INTEL, INTEL_BYT_LPIO1_DMAC_ID),
++ INFO(6, 0, 2047, 0, 0, 1, 0, INTEL_BYT_LPIO1_DMAC_ID, &v1_dma_ops)},
++ { PCI_VDEVICE(INTEL, INTEL_BYT_LPIO2_DMAC_ID),
++ INFO(6, 0, 2047, 0, 0, 1, 0, INTEL_BYT_LPIO2_DMAC_ID, &v1_dma_ops)},
+ { 0, }
+ };
+ MODULE_DEVICE_TABLE(pci, intel_mid_dma_ids);
+
++struct intel_mid_dma_probe_info dma_byt_info = {
++ .max_chan = 4,
++ .ch_base = 4,
++ .block_size = 131071,
++ .pimr_mask = 0x00FF0000,
++ .pimr_base = 0xDF540018,
++ .dword_trf = 0,
++ .pimr_offset = 0x10,
++ .pci_id = INTEL_BYT_DMAC0_ID,
++ .pdma_ops = &v2_dma_ops,
++};
++
+ static const struct dev_pm_ops intel_mid_dma_pm = {
+- .runtime_suspend = dma_runtime_suspend,
+- .runtime_resume = dma_runtime_resume,
+- .runtime_idle = dma_runtime_idle,
+- .suspend = dma_suspend,
+- .resume = dma_resume,
++ SET_SYSTEM_SLEEP_PM_OPS(dma_suspend,
++ dma_resume)
++ SET_RUNTIME_PM_OPS(dma_runtime_suspend,
++ dma_runtime_resume,
++ dma_runtime_idle)
+ };
+
+ static struct pci_driver intel_mid_dma_pci_driver = {
+- .name = "Intel MID DMA",
++ .name = "intel_mid_dma",
+ .id_table = intel_mid_dma_ids,
+ .probe = intel_mid_dma_probe,
+ .remove = intel_mid_dma_remove,
+@@ -1440,17 +2052,55 @@ static struct pci_driver intel_mid_dma_pci_driver = {
+ #endif
+ };
+
++static const struct acpi_device_id dma_acpi_ids[];
++
++struct intel_mid_dma_probe_info *mid_get_acpi_driver_data(const char *hid)
++{
++ const struct acpi_device_id *id;
++
++ pr_debug("%s", __func__);
++ for (id = dma_acpi_ids; id->id[0]; id++)
++ if (!strncmp(id->id, hid, 16))
++ return (struct intel_mid_dma_probe_info *)id->driver_data;
++ return NULL;
++}
++static const struct acpi_device_id dma_acpi_ids[] = {
++ { "DMA0F28", (kernel_ulong_t)&dma_byt_info },
++ { },
++};
++
++static struct platform_driver intel_dma_acpi_driver = {
++ .driver = {
++ .name = "intel_dma_acpi",
++ .owner = THIS_MODULE,
++ .acpi_match_table = dma_acpi_ids,
++ .pm = &intel_mid_dma_pm,
++ },
++ .probe = dma_acpi_probe,
++ .remove = dma_acpi_remove,
++};
++
+ static int __init intel_mid_dma_init(void)
+ {
++ int ret;
++
+ pr_debug("INFO_MDMA: LNW DMA Driver Version %s\n",
+ INTEL_MID_DMA_DRIVER_VERSION);
+- return pci_register_driver(&intel_mid_dma_pci_driver);
++ ret = pci_register_driver(&intel_mid_dma_pci_driver);
++ if (ret)
++ pr_err("PCI dev registration failed");
++
++ ret = platform_driver_register(&intel_dma_acpi_driver);
++ if (ret)
++ pr_err("Platform dev registration failed");
++ return ret;
+ }
+-fs_initcall(intel_mid_dma_init);
++module_init(intel_mid_dma_init);
+
+ static void __exit intel_mid_dma_exit(void)
+ {
+ pci_unregister_driver(&intel_mid_dma_pci_driver);
++ platform_driver_unregister(&intel_dma_acpi_driver);
+ }
+ module_exit(intel_mid_dma_exit);
+
+@@ -1458,3 +2108,5 @@ MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
+ MODULE_DESCRIPTION("Intel (R) MID DMAC Driver");
+ MODULE_LICENSE("GPL v2");
+ MODULE_VERSION(INTEL_MID_DMA_DRIVER_VERSION);
++MODULE_ALIAS("pci:intel_mid_dma");
++MODULE_ALIAS("acpi:intel_dma_acpi");
+diff --git a/drivers/dma/intel_mid_dma_acpi.c b/drivers/dma/intel_mid_dma_acpi.c
+new file mode 100644
+index 0000000..65363b4
+--- /dev/null
++++ b/drivers/dma/intel_mid_dma_acpi.c
+@@ -0,0 +1,177 @@
++
++/* intel_mid_dma_acpi.c - Intel MID DMA driver init file for ACPI enumaration.
++ *
++ * Copyright (c) 2013, Intel Corporation.
++ *
++ * Authors: Ramesh Babu K V <Ramesh.Babu@intel.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/dma-mapping.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/intel_mid_dma.h>
++#include <linux/pm_runtime.h>
++#include <acpi/acpi_bus.h>
++
++#define MAX_CHAN 4 /*max ch across controllers*/
++#include "intel_mid_dma_regs.h"
++
++static struct device *acpi_dma_dev;
++
++struct device *intel_mid_get_acpi_dma(void)
++{
++ return acpi_dma_dev;
++}
++EXPORT_SYMBOL_GPL(intel_mid_get_acpi_dma);
++
++static int mid_get_and_map_rsrc(void **dest, struct platform_device *pdev,
++ unsigned int num)
++{
++ struct resource *rsrc;
++ rsrc = platform_get_resource(pdev, IORESOURCE_MEM, num);
++ if (!rsrc) {
++ pr_err("%s: Invalid resource - %d", __func__, num);
++ return -EIO;
++ }
++ pr_debug("rsrc #%d = %#x", num, rsrc->start);
++ *dest = devm_ioremap_nocache(&pdev->dev, rsrc->start, resource_size(rsrc));
++ if (!*dest) {
++ pr_err("%s: unable to map resource: %#x", __func__, rsrc->start);
++ return -EIO;
++ }
++ return 0;
++}
++
++static int mid_platform_get_resources(struct middma_device *mid_device,
++ struct platform_device *pdev)
++{
++ int ret;
++ pr_debug("%s", __func__);
++
++ /* All ACPI resource request here */
++ /* Get DDR addr from platform resource table */
++ ret = mid_get_and_map_rsrc(&mid_device->dma_base, pdev, 0);
++ if (ret)
++ return ret;
++ pr_debug("dma_base:%p", mid_device->dma_base);
++
++ ret = mid_get_and_map_rsrc(&mid_device->mask_reg, pdev, 1);
++ if (ret)
++ return ret;
++ /* mask_reg should point to ISRX register */
++ mid_device->mask_reg += 0x18;
++ pr_debug("pimr_base:%p", mid_device->mask_reg);
++
++ mid_device->irq = platform_get_irq(pdev, 0);
++ if (mid_device->irq < 0) {
++ pr_err("invalid irq:%d", mid_device->irq);
++ return mid_device->irq;
++ }
++ pr_debug("irq from pdev is:%d", mid_device->irq);
++
++ return 0;
++}
++
++#if IS_ENABLED(CONFIG_ACPI)
++int dma_acpi_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ acpi_handle handle = ACPI_HANDLE(dev);
++ struct acpi_device *device;
++ struct middma_device *mid_device;
++ struct intel_mid_dma_probe_info *info;
++ const char *hid;
++ int ret;
++
++ ret = acpi_bus_get_device(handle, &device);
++ if (ret) {
++ pr_err("%s: could not get acpi device - %d\n", __func__, ret);
++ return -ENODEV;
++ }
++
++ if (acpi_bus_get_status(device) || !device->status.present) {
++ pr_err("%s: device has invalid status", __func__);
++ return -ENODEV;
++ }
++
++ hid = acpi_device_hid(device);
++ pr_info("%s for %s", __func__, hid);
++
++ /* Apply default dma_mask if needed */
++ if (!pdev->dev.dma_mask) {
++ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
++ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
++ }
++
++ ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
++ if (ret) {
++ pr_err("dma_set_mask failed with err:%d", ret);
++ return ret;
++ }
++
++ ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
++ if (ret) {
++ pr_err("_coherent_mask failed with err:%d", ret);
++ return ret;
++ }
++ info = mid_get_acpi_driver_data(hid);
++ if (!info) {
++ pr_err("acpi driver data is null");
++ goto err_dma;
++ }
++
++ mid_device = mid_dma_setup_context(&pdev->dev, info);
++ if (!mid_device)
++ goto err_dma;
++
++ ret = mid_platform_get_resources(mid_device, pdev);
++ if (ret) {
++ pr_err("Error while get resources:%d", ret);
++ goto err_dma;
++ }
++ platform_set_drvdata(pdev, mid_device);
++ ret = mid_setup_dma(&pdev->dev);
++ if (ret)
++ goto err_dma;
++ pm_runtime_enable(&pdev->dev);
++ acpi_dma_dev = &pdev->dev;
++ pr_debug("%s:completed", __func__);
++ return 0;
++err_dma:
++ pr_err("ERR_MDMA:Probe failed %d\n", ret);
++ return ret;
++}
++#else
++int dma_acpi_probe(struct platform_device *pdev)
++{
++ return -EIO;
++}
++#endif
++
++int dma_acpi_remove(struct platform_device *pdev)
++{
++ pm_runtime_get_noresume(&pdev->dev);
++ pm_runtime_disable(&pdev->dev);
++ acpi_dma_dev = NULL;
++ middma_shutdown(&pdev->dev);
++ platform_set_drvdata(pdev, NULL);
++ return 0;
++}
+diff --git a/drivers/dma/intel_mid_dma_regs.h b/drivers/dma/intel_mid_dma_regs.h
+index 17b4219..e82cb8d 100644
+--- a/drivers/dma/intel_mid_dma_regs.h
++++ b/drivers/dma/intel_mid_dma_regs.h
+@@ -45,11 +45,13 @@
+ #define DISABLE_CHANNEL(chan_num) \
+ (REG_BIT8 << chan_num)
+
+-#define DESCS_PER_CHANNEL 16
++#define DESCS_PER_CHANNEL 128
+ /*DMA Registers*/
+ /*registers associated with channel programming*/
+ #define DMA_REG_SIZE 0x400
+ #define DMA_CH_SIZE 0x58
++#define DMA_FIFO_SIZE 0x100080
++
+
+ /*CH X REG = (DMA_CH_SIZE)*CH_NO + REG*/
+ #define SAR 0x00 /* Source Address Register*/
+@@ -83,6 +85,17 @@
+ #define INTR_STATUS 0x360
+ #define DMA_CFG 0x398
+ #define DMA_CHAN_EN 0x3A0
++#define FIFO_PARTITION0_LO 0x400
++#define FIFO_PARTITION0_HI 0x404
++#define FIFO_PARTITION1_LO 0x408
++#define FIFO_PARTITION1_HI 0x40C
++#define CH_SAI_ERR 0x410
++
++#define CTL_LO_BIT_LLP_DST_EN 27
++#define CTL_LO_BIT_LLP_SRC_EN 28
++
++#define CH_SUSPEND (BIT(8))
++#define CH_DRAIN (BIT(10))
+
+ /*DMA channel control registers*/
+ union intel_mid_dma_ctl_lo {
+@@ -111,6 +124,34 @@ union intel_mid_dma_ctl_lo {
+ u32 llp_src_en:1; /*enable/disable source LLP = 0*/
+ u32 reser2:3;
+ } ctlx;
++ struct {
++ u32 int_en:1; /*enable or disable interrupts*/
++ /*should be 0*/
++ u32 dst_tr_width:3; /*destination transfer width*/
++ /*usually 32 bits = 010*/
++ u32 src_tr_width:3; /*source transfer width*/
++ /*usually 32 bits = 010*/
++ u32 rsvd4:1;
++ u32 dinc:1; /*destination address inc/dec*/
++ u32 rsvd3:1;
++ /*For mem:INC=00, Periphral NoINC=11*/
++ u32 sinc:1; /*source address inc or dec, as above*/
++ u32 dst_msize:3; /*destination burst transaction length*/
++ /*always = 16 ie 011*/
++ u32 src_msize:3; /*source burst transaction length*/
++ /*always = 16 ie 011*/
++ u32 src_gather_en:1;
++ u32 dst_scatter_en:1;
++ u32 rsvd2:1;
++ u32 tt_fc:2; /*transfer type and flow controller*/
++ /*M-M = 000
++ P-M = 010
++ M-P = 001*/
++ u32 rsvd1:5;
++ u32 llp_dst_en:1; /*enable/disable destination LLP = 0*/
++ u32 llp_src_en:1; /*enable/disable source LLP = 0*/
++ u32 reser:3;
++ } ctlx_v2;
+ u32 ctl_lo;
+ };
+
+@@ -120,8 +161,13 @@ union intel_mid_dma_ctl_hi {
+ u32 done:1; /*Done - updated by DMAC*/
+ u32 reser:19; /*configured by DMAC*/
+ } ctlx;
++ struct {
++ u32 block_ts:12; /*block transfer size*/
++ u32 done:1; /*Done - updated by DMAC*/
++ u32 ch_weight:11;
++ u32 ch_class:2;
++ } ctlx_v2;
+ u32 ctl_hi;
+-
+ };
+
+ /*DMA channel configuration registers*/
+@@ -141,6 +187,33 @@ union intel_mid_dma_cfg_lo {
+ u32 reload_src:1; /*auto reload src addr =1 if src is P*/
+ u32 reload_dst:1; /*AR destn addr =1 if dstn is P*/
+ } cfgx;
++ struct {
++ u32 dst_burst_align:1;
++ u32 src_burst_align:1;
++ u32 all_np_wr:1;
++ u32 hshake_np_wr:1;
++ u32 rsvd4:1;
++ u32 ctl_hi_upd_en:1;
++ u32 ds_upd_en:1;
++ u32 ss_upd_en:1;
++ u32 ch_susp:1;
++ u32 fifo_empty:1;
++ u32 ch_drain:1;
++ u32 rsvd11:1;
++ u32 rd_snp:1;
++ u32 wr_snp:1;
++ u32 rd_llp_snp:1;
++ u32 rd_stat_snp:1;
++ u32 wr_stat_snp:1;
++ u32 wr_ctlhi_snp:1;
++ u32 dst_hs_pol:1;
++ u32 src_hs_pol:1;
++ u32 dst_opt_bl:1;
++ u32 src_opt_bl:1;
++ u32 rsvd_22_29:8;
++ u32 reload_src:1;
++ u32 reload_dst:1;
++ } cfgx_v2;
+ u32 cfg_lo;
+ };
+
+@@ -154,9 +227,43 @@ union intel_mid_dma_cfg_hi {
+ u32 dst_per:4; /*dstn hw HS interface*/
+ u32 reser2:17;
+ } cfgx;
++ struct {
++ u32 src_per:4; /*src hw HS interface*/
++ u32 dst_per:4; /*dstn hw HS interface*/
++ u32 rd_issue_thd:10;
++ u32 wr_issue_thd:10;
++ u32 src_per_ext:2;
++ u32 dst_per_ext:2;
++ } cfgx_v2;
+ u32 cfg_hi;
+ };
+
++struct intel_mid_dma_ops {
++ int (*device_alloc_chan_resources)(struct dma_chan *chan);
++ void (*device_free_chan_resources)(struct dma_chan *chan);
++
++ struct dma_async_tx_descriptor *(*device_prep_dma_memcpy)(
++ struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
++ size_t len, unsigned long flags);
++ struct dma_async_tx_descriptor *(*device_prep_dma_sg)(
++ struct dma_chan *chan,
++ struct scatterlist *dst_sg, unsigned int dst_nents,
++ struct scatterlist *src_sg, unsigned int src_nents,
++ unsigned long flags);
++
++ struct dma_async_tx_descriptor *(*device_prep_slave_sg)(
++ struct dma_chan *chan, struct scatterlist *sgl,
++ unsigned int sg_len, enum dma_transfer_direction direction,
++ unsigned long flags, void *context);
++ int (*device_control)(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
++ unsigned long arg);
++
++ enum dma_status (*device_tx_status)(struct dma_chan *chan,
++ dma_cookie_t cookie,
++ struct dma_tx_state *txstate);
++ void (*device_issue_pending)(struct dma_chan *chan);
++ void (*dma_chan_suspend)(struct dma_chan *chan);
++};
+
+ /**
+ * struct intel_mid_dma_chan - internal mid representation of a DMA channel
+@@ -168,13 +275,14 @@ union intel_mid_dma_cfg_hi {
+ * @active_list: current active descriptors
+ * @queue: current queued up descriptors
+ * @free_list: current free descriptors
+- * @slave: dma slave structure
+- * @descs_allocated: total number of descriptors allocated
+- * @dma: dma device structure pointer
++ * @slave: dma slave struture
++ * @descs_allocated: total number of decsiptors allocated
++ * @dma: dma device struture pointer
+ * @busy: bool representing if ch is busy (active txn) or not
+ * @in_use: bool representing if ch is in use or not
+ * @raw_tfr: raw trf interrupt received
+ * @raw_block: raw block interrupt received
++ * @block_intr_status: bool representing if block intr is enabled or not
+ */
+ struct intel_mid_dma_chan {
+ struct dma_chan chan;
+@@ -192,6 +300,8 @@ struct intel_mid_dma_chan {
+ u32 raw_tfr;
+ u32 raw_block;
+ struct intel_mid_dma_slave *mid_slave;
++ struct dma_pool *lli_pool;
++ bool block_intr_status;
+ };
+
+ static inline struct intel_mid_dma_chan *to_intel_mid_dma_chan(
+@@ -207,6 +317,8 @@ enum intel_mid_dma_state {
+ /**
+ * struct middma_device - internal representation of a DMA device
+ * @pdev: PCI device
++ * @dev : pointer to current device struct
++ * @irq : holds irq for the device
+ * @dma_base: MMIO register space pointer of DMA
+ * @dma_pool: for allocating DMA descriptors
+ * @common: embedded struct dma_device
+@@ -220,9 +332,12 @@ enum intel_mid_dma_state {
+ * @block_size: Block size of DMA transfer supported (from drv_data)
+ * @pimr_mask: MMIO register addr for periphral interrupt (from drv_data)
+ * @state: dma PM device state
++ * @tfr_intr_mask: hold the status of tfr intr mask register
++ * @block_intr_mask: hold the status of block intr mask register
+ */
+ struct middma_device {
+- struct pci_dev *pdev;
++ struct device *dev;
++ unsigned int irq;
+ void __iomem *dma_base;
+ struct pci_pool *dma_pool;
+ struct dma_device common;
+@@ -235,7 +350,13 @@ struct middma_device {
+ int max_chan;
+ int block_size;
+ unsigned int pimr_mask;
++ unsigned int pimr_base;
++ unsigned int dword_trf;
++ unsigned int pimr_offset;
++ unsigned long tfr_intr_mask;
++ unsigned long block_intr_mask;
+ enum intel_mid_dma_state state;
++ struct intel_mid_dma_ops dma_ops;
+ };
+
+ static inline struct middma_device *to_middma_device(struct dma_device *common)
+@@ -266,15 +387,30 @@ struct intel_mid_dma_desc {
+ enum intel_mid_dma_mode cfg_mode; /*mode configuration*/
+
+ };
+-
++/* struct intel_mid_dma_lli is used to provide the DMA IP with SAR,DAR,LLP etc.
++ Use u32 for the elements of this structure irrespective
++ of whether dma_addr_t is u32 or u64.This is necessary because
++ the DMA IP expects these elements to be 32 bit wide */
+ struct intel_mid_dma_lli {
+- dma_addr_t sar;
+- dma_addr_t dar;
+- dma_addr_t llp;
++ u32 sar;
++ u32 dar;
++ u32 llp;
+ u32 ctl_lo;
+ u32 ctl_hi;
+ } __attribute__ ((packed));
+
++struct intel_mid_dma_probe_info {
++ u8 max_chan;
++ u8 ch_base;
++ u32 block_size;
++ u32 pimr_mask;
++ u32 pimr_base;
++ u8 dword_trf;
++ u32 pimr_offset;
++ unsigned int pci_id;
++ struct intel_mid_dma_ops *pdma_ops;
++};
++
+ static inline int test_ch_en(void __iomem *dma, u32 ch_no)
+ {
+ u32 en_reg = ioread32(dma + DMA_CHAN_EN);
+@@ -294,6 +430,12 @@ static inline struct intel_mid_dma_slave *to_intel_mid_dma_slave
+ }
+
+
++struct middma_device *mid_dma_setup_context(struct device *dev,
++ struct intel_mid_dma_probe_info *info);
+ int dma_resume(struct device *dev);
+-
++int dma_acpi_probe(struct platform_device *pdev);
++int dma_acpi_remove(struct platform_device *pdev);
++struct intel_mid_dma_probe_info *mid_get_acpi_driver_data(const char *hid);
++int mid_setup_dma(struct device *dev);
++void middma_shutdown(struct device *dev);
+ #endif /*__INTEL_MID_DMAC_REGS_H__*/
+diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
+index 573c449..9d527a7 100644
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -81,6 +81,17 @@ config GPIO_SYSFS
+ Kernel drivers may also request that a particular GPIO be
+ exported to userspace; this can be useful when debugging.
+
++config GPIODEBUG
++ tristate "GPIO Setting DEBUG"
++ depends on DEBUG_FS
++ help
++ Say yes here to support GPIO/FLIS Setting Debug.
++
++ This is mostly useful to dump and set gpio/flis conguration.
++
++ Kernel drivers may also request that a particular GPIO be
++ exported to userspace; this can be useful when debugging.
++
+ config GPIO_GENERIC
+ tristate
+
+diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
+index 0cb2d65..2ecb796 100644
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -6,6 +6,7 @@ obj-$(CONFIG_GPIO_DEVRES) += devres.o
+ obj-$(CONFIG_GPIOLIB) += gpiolib.o
+ obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
+ obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
++obj-$(CONFIG_GPIODEBUG) += gpiodebug.o
+
+ # Device drivers. Generally keep list sorted alphabetically
+ obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
+diff --git a/drivers/gpio/gpio-langwell.c b/drivers/gpio/gpio-langwell.c
+index 62ef10a..f8b907d 100644
+--- a/drivers/gpio/gpio-langwell.c
++++ b/drivers/gpio/gpio-langwell.c
+@@ -1,7 +1,5 @@
+-/*
+- * Moorestown platform Langwell chip GPIO driver
+- *
+- * Copyright (c) 2008 - 2009, Intel Corporation.
++/* gpio-langwell.c Moorestown platform Langwell chip GPIO driver
++ * Copyright (c) 2008 - 2013, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+@@ -35,8 +33,18 @@
+ #include <linux/io.h>
+ #include <linux/gpio.h>
+ #include <linux/slab.h>
++#include <linux/lnw_gpio.h>
+ #include <linux/pm_runtime.h>
++#include <asm/intel-mid.h>
+ #include <linux/irqdomain.h>
++#include <asm/intel_scu_flis.h>
++#include "gpiodebug.h"
++
++#define IRQ_TYPE_EDGE (1 << 0)
++#define IRQ_TYPE_LEVEL (1 << 1)
++
++#define TANGIER_I2C_FLIS_START 0x1D00
++#define TANGIER_I2C_FLIS_END 0x1D34
+
+ /*
+ * Langwell chip has 64 pins and thus there are 2 32bit registers to control
+@@ -61,14 +69,149 @@ enum GPIO_REG {
+ GFER, /* falling edge detect */
+ GEDR, /* edge detect result */
+ GAFR, /* alt function */
++ GFBR = 9, /* glitch filter bypas */
++ GPIT, /* interrupt type */
++ GPIP = GFER, /* level interrupt polarity */
++ GPIM = GRER, /* level interrupt mask */
++
++ /* the following registers only exist on MRFLD */
++ GFBR_TNG = 6,
++ GIMR, /* interrupt mask */
++ GISR, /* interrupt source */
++ GITR = 32, /* interrupt type */
++ GLPR = 33, /* level-input polarity */
++};
++
++enum GPIO_CONTROLLERS {
++ LINCROFT_GPIO,
++ PENWELL_GPIO_AON,
++ PENWELL_GPIO_CORE,
++ CLOVERVIEW_GPIO_AON,
++ CLOVERVIEW_GPIO_CORE,
++ TANGIER_GPIO,
++};
++
++/* langwell gpio driver data */
++struct lnw_gpio_ddata_t {
++ u16 ngpio; /* number of gpio pins */
++ u32 gplr_offset; /* offset of first GPLR register from base */
++ u32 (*get_flis_offset)(int gpio);
++ u32 chip_irq_type; /* chip interrupt type */
++};
++
++struct gpio_flis_pair {
++ int gpio; /* gpio number */
++ int offset; /* register offset from FLIS base */
++};
++
++/*
++ * The following mapping table lists the pin and flis offset pair
++ * of some key gpio pins, the offset of other gpios can be calculated
++ * from the table.
++ */
++static struct gpio_flis_pair gpio_flis_mapping_table[] = {
++ { 0, 0x2900 },
++ { 12, 0x2544 },
++ { 14, 0x0958 },
++ { 16, 0x2D18 },
++ { 17, 0x1D10 },
++ { 19, 0x1D00 },
++ { 23, 0x1D18 },
++ { 31, -EINVAL }, /* No GPIO 31 in pin list */
++ { 32, 0x1508 },
++ { 44, 0x3500 },
++ { 64, 0x2534 },
++ { 68, 0x2D1C },
++ { 70, 0x1500 },
++ { 72, 0x3D00 },
++ { 77, 0x0D00 },
++ { 97, 0x0954 },
++ { 98, -EINVAL }, /* No GPIO 98-101 in pin list */
++ { 102, 0x1910 },
++ { 120, 0x1900 },
++ { 124, 0x2100 },
++ { 136, -EINVAL }, /* No GPIO 136 in pin list */
++ { 137, 0x2D00 },
++ { 143, -EINVAL }, /* No GPIO 143-153 in pin list */
++ { 154, 0x092C },
++ { 164, 0x3900 },
++ { 177, 0x2500 },
++ { 190, 0x2D50 },
++};
++
++/*
++ * In new version of FW for Merrifield, I2C FLIS register can not
++ * be written directly but go though a IPC way which is sleepable,
++ * so we shouldn't use spin_lock_irq to protect the access when
++ * is_merr_i2c_flis() return true.
++ */
++static inline bool is_merr_i2c_flis(u32 offset)
++{
++ return ((offset >= TANGIER_I2C_FLIS_START)
++ && (offset <= TANGIER_I2C_FLIS_END));
++}
++
++static u32 get_flis_offset_by_gpio(int gpio)
++{
++ int i;
++ int start;
++ u32 offset = -EINVAL;
++
++ for (i = 0; i < ARRAY_SIZE(gpio_flis_mapping_table) - 1; i++) {
++ if (gpio >= gpio_flis_mapping_table[i].gpio
++ && gpio < gpio_flis_mapping_table[i + 1].gpio)
++ break;
++ }
++
++ start = gpio_flis_mapping_table[i].gpio;
++
++ if (gpio_flis_mapping_table[i].offset != -EINVAL) {
++ offset = gpio_flis_mapping_table[i].offset
++ + (gpio - start) * 4;
++ }
++
++ return offset;
++}
++
++static struct lnw_gpio_ddata_t lnw_gpio_ddata[] = {
++ [LINCROFT_GPIO] = {
++ .ngpio = 64,
++ },
++ [PENWELL_GPIO_AON] = {
++ .ngpio = 96,
++ .chip_irq_type = IRQ_TYPE_EDGE,
++ },
++ [PENWELL_GPIO_CORE] = {
++ .ngpio = 96,
++ .chip_irq_type = IRQ_TYPE_EDGE,
++ },
++ [CLOVERVIEW_GPIO_AON] = {
++ .ngpio = 96,
++ .chip_irq_type = IRQ_TYPE_EDGE | IRQ_TYPE_LEVEL,
++ },
++ [CLOVERVIEW_GPIO_CORE] = {
++ .ngpio = 96,
++ .chip_irq_type = IRQ_TYPE_EDGE,
++ },
++ [TANGIER_GPIO] = {
++ .ngpio = 192,
++ .gplr_offset = 4,
++ .get_flis_offset = get_flis_offset_by_gpio,
++ .chip_irq_type = IRQ_TYPE_EDGE | IRQ_TYPE_LEVEL,
++ },
+ };
+
+ struct lnw_gpio {
+- struct gpio_chip chip;
+- void *reg_base;
+- spinlock_t lock;
+- struct pci_dev *pdev;
+- struct irq_domain *domain;
++ struct gpio_chip chip;
++ void *reg_base;
++ void *reg_gplr;
++ spinlock_t lock;
++ struct pci_dev *pdev;
++ struct irq_domain *domain;
++ u32 (*get_flis_offset)(int gpio);
++ u32 chip_irq_type;
++ int type;
++ struct gpio_debug *debug;
+ };
+
+ #define to_lnw_priv(chip) container_of(chip, struct lnw_gpio, chip)
+@@ -80,11 +223,162 @@ static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
+ unsigned nreg = chip->ngpio / 32;
+ u8 reg = offset / 32;
+ void __iomem *ptr;
++ void *base;
+
+- ptr = (void __iomem *)(lnw->reg_base + reg_type * nreg * 4 + reg * 4);
++ /**
++ * On TNG B0, GITR[0]'s address is 0xFF008300, while GPLR[0]'s address
++ * is 0xFF008004. To count GITR[0]'s address, it's easier to count
++ * from 0xFF008000. So for GITR,GLPR... we switch the base to reg_base.
++ * This does not affect PNW/CLV, since the reg_gplr is the reg_base,
++ * while on TNG, the reg_gplr has an offset of 0x4.
++ */
++ base = reg_type < GITR ? lnw->reg_gplr : lnw->reg_base;
++ ptr = (void __iomem *)(base + reg_type * nreg * 4 + reg * 4);
+ return ptr;
+ }
+
++void lnw_gpio_set_alt(int gpio, int alt)
++{
++ struct lnw_gpio *lnw;
++ u32 __iomem *mem;
++ int reg;
++ int bit;
++ u32 offset;
++ u32 value;
++ unsigned long flags;
++
++ /* use this trick to get memio */
++ lnw = irq_get_chip_data(gpio_to_irq(gpio));
++ if (!lnw) {
++ pr_err("langwell_gpio: can not find pin %d\n", gpio);
++ return;
++ }
++ if (gpio < lnw->chip.base || gpio >= lnw->chip.base + lnw->chip.ngpio) {
++ dev_err(lnw->chip.dev, "langwell_gpio: wrong pin %d to config alt\n", gpio);
++ return;
++ }
++#if 0
++ if (lnw->irq_base + gpio - lnw->chip.base != gpio_to_irq(gpio)) {
++ dev_err(lnw->chip.dev, "langwell_gpio: wrong chip data for pin %d\n", gpio);
++ return;
++ }
++#endif
++ gpio -= lnw->chip.base;
++
++ if (lnw->type != TANGIER_GPIO) {
++ reg = gpio / 16;
++ bit = gpio % 16;
++
++ mem = gpio_reg(&lnw->chip, 0, GAFR);
++ spin_lock_irqsave(&lnw->lock, flags);
++ value = readl(mem + reg);
++ value &= ~(3 << (bit * 2));
++ value |= (alt & 3) << (bit * 2);
++ writel(value, mem + reg);
++ spin_unlock_irqrestore(&lnw->lock, flags);
++ dev_dbg(lnw->chip.dev, "ALT: writing 0x%x to %p\n",
++ value, mem + reg);
++ } else {
++ offset = lnw->get_flis_offset(gpio);
++ if (WARN(offset == -EINVAL, "invalid pin %d\n", gpio))
++ return;
++
++ if (!is_merr_i2c_flis(offset))
++ spin_lock_irqsave(&lnw->lock, flags);
++
++ value = get_flis_value(offset);
++ value &= ~7;
++ value |= (alt & 7);
++ set_flis_value(value, offset);
++
++ if (!is_merr_i2c_flis(offset))
++ spin_unlock_irqrestore(&lnw->lock, flags);
++ }
++}
++EXPORT_SYMBOL_GPL(lnw_gpio_set_alt);
++
++int gpio_get_alt(int gpio)
++{
++ struct lnw_gpio *lnw;
++ u32 __iomem *mem;
++ int reg;
++ int bit;
++ u32 value;
++ u32 offset;
++
++ /* use this trick to get memio */
++ lnw = irq_get_chip_data(gpio_to_irq(gpio));
++ if (!lnw) {
++ pr_err("langwell_gpio: can not find pin %d\n", gpio);
++ return -1;
++ }
++ if (gpio < lnw->chip.base || gpio >= lnw->chip.base + lnw->chip.ngpio) {
++ dev_err(lnw->chip.dev,
++ "langwell_gpio: wrong pin %d to config alt\n", gpio);
++ return -1;
++ }
++#if 0
++ if (lnw->irq_base + gpio - lnw->chip.base != gpio_to_irq(gpio)) {
++ dev_err(lnw->chip.dev,
++ "langwell_gpio: wrong chip data for pin %d\n", gpio);
++ return -1;
++ }
++#endif
++ gpio -= lnw->chip.base;
++
++ if (lnw->type != TANGIER_GPIO) {
++ reg = gpio / 16;
++ bit = gpio % 16;
++
++ mem = gpio_reg(&lnw->chip, 0, GAFR);
++ value = readl(mem + reg);
++ value &= (3 << (bit * 2));
++ value >>= (bit * 2);
++ } else {
++ offset = lnw->get_flis_offset(gpio);
++ if (WARN(offset == -EINVAL, "invalid pin %d\n", gpio))
++ return -EINVAL;
++
++ value = get_flis_value(offset) & 7;
++ }
++
++ return value;
++}
++EXPORT_SYMBOL_GPL(gpio_get_alt);
++
++static int lnw_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
++ unsigned debounce)
++{
++ struct lnw_gpio *lnw = to_lnw_priv(chip);
++ void __iomem *gfbr;
++ unsigned long flags;
++ u32 value;
++ enum GPIO_REG reg_type;
++
++ reg_type = (lnw->type == TANGIER_GPIO) ? GFBR_TNG : GFBR;
++ gfbr = gpio_reg(chip, offset, reg_type);
++
++ if (lnw->pdev)
++ pm_runtime_get(&lnw->pdev->dev);
++
++ spin_lock_irqsave(&lnw->lock, flags);
++ value = readl(gfbr);
++ if (debounce) {
++ /* debounce bypass disable */
++ value &= ~BIT(offset % 32);
++ } else {
++ /* debounce bypass enable */
++ value |= BIT(offset % 32);
++ }
++ writel(value, gfbr);
++ spin_unlock_irqrestore(&lnw->lock, flags);
++
++ if (lnw->pdev)
++ pm_runtime_put(&lnw->pdev->dev);
++
++ return 0;
++}
++
+ static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset,
+ enum GPIO_REG reg_type)
+ {
+@@ -117,10 +411,50 @@ static int lnw_gpio_get(struct gpio_chip *chip, unsigned offset)
+ return readl(gplr) & BIT(offset % 32);
+ }
+
++#define PULLUP_ENABLE (1 << 8)
++#define PULLDOWN_ENABLE (1 << 9)
++#define PUPD_VAL_2K (0 << 4)
++#define PUPD_VAL_20K (1 << 4)
++#define PUPD_VAL_50K (2 << 4)
++#define PUPD_VAL_910 (3 << 4)
++
++static int lnw_gpio_set_pull(struct gpio_chip *chip, unsigned gpio, int value)
++{
++ u32 flis_offset, flis_value;
++ struct lnw_gpio *lnw = to_lnw_priv(chip);
++ unsigned long flags;
++
++ if (lnw->type != TANGIER_GPIO)
++ return 0;
++
++ flis_offset = lnw->get_flis_offset(gpio);
++ if (WARN(flis_offset == -EINVAL, "invalid pin %d\n", gpio))
++ return -EINVAL;
++ if (is_merr_i2c_flis(flis_offset))
++ return 0;
++
++ spin_lock_irqsave(&lnw->lock, flags);
++ flis_value = get_flis_value(flis_offset);
++ if (value) {
++ flis_value |= PULLUP_ENABLE;
++ flis_value &= ~PULLDOWN_ENABLE;
++ } else {
++ flis_value |= PULLDOWN_ENABLE;
++ flis_value &= ~PULLUP_ENABLE;
++ }
++ flis_value |= PUPD_VAL_50K;
++ set_flis_value(flis_value, flis_offset);
++ spin_unlock_irqrestore(&lnw->lock, flags);
++
++ return 0;
++}
++
+ static void lnw_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+ {
+ void __iomem *gpsr, *gpcr;
+
++ lnw_gpio_set_pull(chip, offset, value);
++
+ if (value) {
+ gpsr = gpio_reg(chip, offset, GPSR);
+ writel(BIT(offset % 32), gpsr);
+@@ -188,8 +522,10 @@ static int lnw_irq_type(struct irq_data *d, unsigned type)
+ u32 gpio = irqd_to_hwirq(d);
+ unsigned long flags;
+ u32 value;
++ int ret = 0;
+ void __iomem *grer = gpio_reg(&lnw->chip, gpio, GRER);
+ void __iomem *gfer = gpio_reg(&lnw->chip, gpio, GFER);
++ void __iomem *gpit, *gpip;
+
+ if (gpio >= lnw->chip.ngpio)
+ return -EINVAL;
+@@ -197,47 +533,217 @@ static int lnw_irq_type(struct irq_data *d, unsigned type)
+ if (lnw->pdev)
+ pm_runtime_get(&lnw->pdev->dev);
+
+- spin_lock_irqsave(&lnw->lock, flags);
+- if (type & IRQ_TYPE_EDGE_RISING)
+- value = readl(grer) | BIT(gpio % 32);
+- else
+- value = readl(grer) & (~BIT(gpio % 32));
+- writel(value, grer);
++ /* Chip that supports level interrupt has extra GPIT registers */
++ if (lnw->chip_irq_type & IRQ_TYPE_LEVEL) {
++ switch (lnw->type) {
++ case CLOVERVIEW_GPIO_AON:
++ gpit = gpio_reg(&lnw->chip, gpio, GPIT);
++ gpip = gpio_reg(&lnw->chip, gpio, GPIP);
++ break;
++ case TANGIER_GPIO:
++ gpit = gpio_reg(&lnw->chip, gpio, GITR);
++ gpip = gpio_reg(&lnw->chip, gpio, GLPR);
++ break;
++ default:
++ ret = -EINVAL;
++ goto out;
++ }
+
+- if (type & IRQ_TYPE_EDGE_FALLING)
+- value = readl(gfer) | BIT(gpio % 32);
+- else
+- value = readl(gfer) & (~BIT(gpio % 32));
+- writel(value, gfer);
+- spin_unlock_irqrestore(&lnw->lock, flags);
++ spin_lock_irqsave(&lnw->lock, flags);
++ if (type & IRQ_TYPE_LEVEL_MASK) {
++ /* To prevent glitches from triggering an unintended
++ * level interrupt, configure GLPR register first
++ * and then configure GITR.
++ */
++ if (type & IRQ_TYPE_LEVEL_LOW)
++ value = readl(gpip) | BIT(gpio % 32);
++ else
++ value = readl(gpip) & (~BIT(gpio % 32));
++ writel(value, gpip);
++
++ value = readl(gpit) | BIT(gpio % 32);
++ writel(value, gpit);
++
++ __irq_set_handler_locked(d->irq, handle_level_irq);
++ } else if (type & IRQ_TYPE_EDGE_BOTH) {
++ value = readl(gpit) & (~BIT(gpio % 32));
++ writel(value, gpit);
++
++ if (type & IRQ_TYPE_EDGE_RISING)
++ value = readl(grer) | BIT(gpio % 32);
++ else
++ value = readl(grer) & (~BIT(gpio % 32));
++ writel(value, grer);
++
++ if (type & IRQ_TYPE_EDGE_FALLING)
++ value = readl(gfer) | BIT(gpio % 32);
++ else
++ value = readl(gfer) & (~BIT(gpio % 32));
++ writel(value, gfer);
++
++ __irq_set_handler_locked(d->irq, handle_edge_irq);
++ }
++ spin_unlock_irqrestore(&lnw->lock, flags);
++ } else {
++ if (type & IRQ_TYPE_LEVEL_MASK) {
++ ret = -EINVAL;
++ } else if (type & IRQ_TYPE_EDGE_BOTH) {
++ spin_lock_irqsave(&lnw->lock, flags);
++
++ if (type & IRQ_TYPE_EDGE_RISING)
++ value = readl(grer) | BIT(gpio % 32);
++ else
++ value = readl(grer) & (~BIT(gpio % 32));
++ writel(value, grer);
++
++ if (type & IRQ_TYPE_EDGE_FALLING)
++ value = readl(gfer) | BIT(gpio % 32);
++ else
++ value = readl(gfer) & (~BIT(gpio % 32));
++ writel(value, gfer);
++
++ spin_unlock_irqrestore(&lnw->lock, flags);
++ }
++ }
+
++out:
+ if (lnw->pdev)
+ pm_runtime_put(&lnw->pdev->dev);
+
++ return ret;
++}
++
++static int lnw_set_maskunmask(struct irq_data *d, enum GPIO_REG reg_type,
++ unsigned unmask)
++{
++ struct lnw_gpio *lnw = irq_data_get_irq_chip_data(d);
++ u32 gpio = irqd_to_hwirq(d);
++ unsigned long flags;
++ u32 value;
++ void __iomem *gp_reg;
++
++ gp_reg = gpio_reg(&lnw->chip, gpio, reg_type);
++
++ spin_lock_irqsave(&lnw->lock, flags);
++
++ if (unmask) {
++ /* enable interrupt from GPIO input pin */
++ value = readl(gp_reg) | BIT(gpio % 32);
++ } else {
++ /* disable interrupt from GPIO input pin */
++ value = readl(gp_reg) & (~BIT(gpio % 32));
++ }
++
++ writel(value, gp_reg);
++
++ spin_unlock_irqrestore(&lnw->lock, flags);
++
+ return 0;
+ }
+
+ static void lnw_irq_unmask(struct irq_data *d)
+ {
++ struct lnw_gpio *lnw = irq_data_get_irq_chip_data(d);
++ u32 gpio = irqd_to_hwirq(d);
++ void __iomem *gpit;
++
++ if (gpio >= lnw->chip.ngpio)
++ return;
++
++ switch (lnw->type) {
++ case CLOVERVIEW_GPIO_AON:
++ gpit = gpio_reg(&lnw->chip, gpio, GPIT);
++
++ /* if it's level trigger, unmask GPIM */
++ if (readl(gpit) & BIT(gpio % 32))
++ lnw_set_maskunmask(d, GPIM, 1);
++
++ break;
++ case TANGIER_GPIO:
++ lnw_set_maskunmask(d, GIMR, 1);
++ break;
++ default:
++ break;
++ }
+ }
+
+ static void lnw_irq_mask(struct irq_data *d)
+ {
++ struct lnw_gpio *lnw = irq_data_get_irq_chip_data(d);
++ u32 gpio = irqd_to_hwirq(d);
++ void __iomem *gpit;
++
++ if (gpio >= lnw->chip.ngpio)
++ return;
++
++ switch (lnw->type) {
++ case CLOVERVIEW_GPIO_AON:
++ gpit = gpio_reg(&lnw->chip, gpio, GPIT);
++
++ /* if it's level trigger, mask GPIM */
++ if (readl(gpit) & BIT(gpio % 32))
++ lnw_set_maskunmask(d, GPIM, 0);
++
++ break;
++ case TANGIER_GPIO:
++ lnw_set_maskunmask(d, GIMR, 0);
++ break;
++ default:
++ break;
++ }
++}
++
++static int lwn_irq_set_wake(struct irq_data *d, unsigned on)
++{
++ return 0;
+ }
+
++static void lnw_irq_ack(struct irq_data *d)
++{
++}
++
++static void lnw_irq_shutdown(struct irq_data *d)
++{
++ struct lnw_gpio *lnw = irq_data_get_irq_chip_data(d);
++ u32 gpio = irqd_to_hwirq(d);
++ unsigned long flags;
++ u32 value;
++ void __iomem *grer = gpio_reg(&lnw->chip, gpio, GRER);
++ void __iomem *gfer = gpio_reg(&lnw->chip, gpio, GFER);
++
++ spin_lock_irqsave(&lnw->lock, flags);
++ value = readl(grer) & (~BIT(gpio % 32));
++ writel(value, grer);
++ value = readl(gfer) & (~BIT(gpio % 32));
++ writel(value, gfer);
++ spin_unlock_irqrestore(&lnw->lock, flags);
++};
++
++
+ static struct irq_chip lnw_irqchip = {
+ .name = "LNW-GPIO",
++ .flags = IRQCHIP_SET_TYPE_MASKED,
+ .irq_mask = lnw_irq_mask,
+ .irq_unmask = lnw_irq_unmask,
+ .irq_set_type = lnw_irq_type,
++ .irq_set_wake = lwn_irq_set_wake,
++ .irq_ack = lnw_irq_ack,
++ .irq_shutdown = lnw_irq_shutdown,
+ };
+
+ static DEFINE_PCI_DEVICE_TABLE(lnw_gpio_ids) = { /* pin number */
+- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f), .driver_data = 64 },
+- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081f), .driver_data = 96 },
+- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081a), .driver_data = 96 },
+- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08eb), .driver_data = 96 },
+- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08f7), .driver_data = 96 },
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f),
++ .driver_data = LINCROFT_GPIO },
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081f),
++ .driver_data = PENWELL_GPIO_AON },
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081a),
++ .driver_data = PENWELL_GPIO_CORE },
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08eb),
++ .driver_data = CLOVERVIEW_GPIO_AON },
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08f7),
++ .driver_data = CLOVERVIEW_GPIO_CORE },
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1199),
++ .driver_data = TANGIER_GPIO },
+ { 0, }
+ };
+ MODULE_DEVICE_TABLE(pci, lnw_gpio_ids);
+@@ -245,28 +751,446 @@ MODULE_DEVICE_TABLE(pci, lnw_gpio_ids);
+ static void lnw_irq_handler(unsigned irq, struct irq_desc *desc)
+ {
+ struct irq_data *data = irq_desc_get_irq_data(desc);
+- struct lnw_gpio *lnw = irq_data_get_irq_handler_data(data);
+ struct irq_chip *chip = irq_data_get_irq_chip(data);
++ struct lnw_gpio *lnw;
++ struct gpio_debug *debug;
+ u32 base, gpio, mask;
+ unsigned long pending;
+- void __iomem *gedr;
++ void __iomem *gp_reg;
++ enum GPIO_REG reg_type;
++ struct irq_desc *lnw_irq_desc;
++ unsigned int lnw_irq;
++
++ lnw = irq_data_get_irq_handler_data(data);
++
++ debug = lnw->debug;
++
++ reg_type = (lnw->type == TANGIER_GPIO) ? GISR : GEDR;
+
+ /* check GPIO controller to check which pin triggered the interrupt */
+ for (base = 0; base < lnw->chip.ngpio; base += 32) {
+- gedr = gpio_reg(&lnw->chip, base, GEDR);
+- while ((pending = readl(gedr))) {
++ gp_reg = gpio_reg(&lnw->chip, base, reg_type);
++ while ((pending = (lnw->type != TANGIER_GPIO) ?
++ readl(gp_reg) :
++ (readl(gp_reg) &
++ readl(gpio_reg(&lnw->chip, base, GIMR))))) {
+ gpio = __ffs(pending);
++ DEFINE_DEBUG_IRQ_CONUNT_INCREASE(lnw->chip.base +
++ base + gpio);
++ /* Mask irq if not requested in kernel */
++ lnw_irq = irq_find_mapping(lnw->domain, base + gpio);
++ lnw_irq_desc = irq_to_desc(lnw_irq);
++ if (lnw_irq_desc && unlikely(!lnw_irq_desc->action)) {
++ lnw_irq_mask(&lnw_irq_desc->irq_data);
++ continue;
++ }
++
+ mask = BIT(gpio);
+ /* Clear before handling so we can't lose an edge */
+- writel(mask, gedr);
+- generic_handle_irq(irq_find_mapping(lnw->domain,
+- base + gpio));
++ writel(mask, gp_reg);
++ generic_handle_irq(lnw_irq);
+ }
+ }
+
+ chip->irq_eoi(data);
+ }
+
++static char conf_reg_msg[] =
++ "\nGPIO configuration register:\n"
++ "\t[ 2: 0]\tpinmux\n"
++ "\t[ 6: 4]\tpull strength\n"
++ "\t[ 8: 8]\tpullup enable\n"
++ "\t[ 9: 9]\tpulldown enable\n"
++ "\t[10:10]\tslew A, B setting\n"
++ "\t[12:12]\toverride input enable\n"
++ "\t[13:13]\toverride input enable enable\n"
++ "\t[14:14]\toverride output enable\n"
++ "\t[15:15]\toverride output enable enable\n"
++ "\t[16:16]\toverride input value\n"
++ "\t[17:17]\tenable input data override\n"
++ "\t[18:18]\toverride output value\n"
++ "\t[19:19]\tenable output data override\n"
++ "\t[21:21]\topen drain enable\n"
++ "\t[22:22]\tenable OVR_IOSTBY_VAL\n"
++ "\t[23:23]\tOVR_IOSTBY_VAL\n"
++ "\t[24:24]\tSBY_OUTDATAOV_EN\n"
++ "\t[25:25]\tSBY_INDATAOV_EN\n"
++ "\t[26:26]\tSBY_OVOUTEN_EN\n"
++ "\t[27:27]\tSBY_OVINEN_EN\n"
++ "\t[29:28]\tstandby pullmode\n"
++ "\t[30:30]\tstandby open drain mode\n";
++
++static char *pinvalue[] = {"low", "high"};
++static char *pindirection[] = {"in", "out"};
++static char *irqtype[] = {"irq_none", "edge_rising", "edge_falling",
++ "edge_both"};
++static char *pinmux[] = {"mode0", "mode1", "mode2", "mode3", "mode4", "mode5",
++ "mode6", "mode7"};
++static char *pullmode[] = {"nopull", "pullup", "pulldown"};
++static char *pullstrength[] = {"2k", "20k", "50k", "910ohms"};
++static char *enable[] = {"disable", "enable"};
++static char *override_direction[] = {"no-override", "override-enable",
++ "override-disable"};
++static char *override_value[] = {"no-override", "override-high",
++ "override-low"};
++static char *standby_trigger[] = {"no-override", "override-trigger",
++ "override-notrigger"};
++static char *standby_pupd_state[] = {"keep", "pulldown", "pullup", "nopull"};
++
++static int gpio_get_pinvalue(struct gpio_control *control, void *private_data,
++ unsigned gpio)
++{
++ struct lnw_gpio *lnw = private_data;
++ u32 value;
++
++ value = lnw_gpio_get(&lnw->chip, gpio);
++
++ return value ? 1 : 0;
++}
++
++static int gpio_set_pinvalue(struct gpio_control *control, void *private_data,
++ unsigned gpio, unsigned int num)
++{
++ struct lnw_gpio *lnw = private_data;
++
++ lnw_gpio_set(&lnw->chip, gpio, num);
++ return 0;
++}
++
++static int gpio_get_normal(struct gpio_control *control, void *private_data,
++ unsigned gpio)
++{
++ struct lnw_gpio *lnw = private_data;
++ u32 __iomem *mem;
++ u32 value;
++
++ mem = gpio_reg(&lnw->chip, gpio, control->reg);
++
++ value = readl(mem);
++ value &= BIT(gpio % 32);
++
++ if (control->invert)
++ return value ? 0 : 1;
++ else
++ return value ? 1 : 0;
++}
++
++static int gpio_set_normal(struct gpio_control *control, void *private_data,
++ unsigned gpio, unsigned int num)
++{
++ struct lnw_gpio *lnw = private_data;
++ u32 __iomem *mem;
++ u32 value;
++ unsigned long flags;
++
++ mem = gpio_reg(&lnw->chip, gpio, control->reg);
++
++ spin_lock_irqsave(&lnw->lock, flags);
++ value = readl(mem);
++ value &= ~BIT(gpio % 32);
++ if (control->invert) {
++ if (num)
++ value &= ~BIT(gpio % 32);
++ else
++ value |= BIT(gpio % 32);
++ } else {
++ if (num)
++ value |= BIT(gpio % 32);
++ else
++ value &= ~BIT(gpio % 32);
++ }
++ writel(value, mem);
++ spin_unlock_irqrestore(&lnw->lock, flags);
++
++ return 0;
++}
++
++static int gpio_get_irqtype(struct gpio_control *control, void *private_data,
++ unsigned gpio)
++{
++ struct lnw_gpio *lnw = private_data;
++ void __iomem *grer = gpio_reg(&lnw->chip, gpio, GRER);
++ void __iomem *gfer = gpio_reg(&lnw->chip, gpio, GFER);
++ u32 value;
++ int num;
++
++ value = readl(grer) & BIT(gpio % 32);
++ num = value ? 1 : 0;
++ value = readl(gfer) & BIT(gpio % 32);
++ if (num)
++ num = value ? 3 : 1;
++ else
++ num = value ? 2 : 0;
++
++ return num;
++}
++
++static int flis_get_normal(struct gpio_control *control, void *private_data,
++ unsigned gpio)
++{
++ struct lnw_gpio *lnw = private_data;
++ u32 offset, value;
++ int num;
++
++ if (lnw->type == TANGIER_GPIO) {
++ offset = lnw->get_flis_offset(gpio);
++ if (WARN(offset == -EINVAL, "invalid pin %d\n", gpio))
++ return -1;
++
++ value = get_flis_value(offset);
++ num = (value >> control->shift) & control->mask;
++ if (num < control->num)
++ return num;
++ }
++
++ return -1;
++}
++
++static int flis_set_normal(struct gpio_control *control, void *private_data,
++ unsigned gpio, unsigned int num)
++{
++ struct lnw_gpio *lnw = private_data;
++ u32 shift = control->shift;
++ u32 mask = control->mask;
++ u32 offset, value;
++ unsigned long flags;
++
++ if (lnw->type == TANGIER_GPIO) {
++ offset = lnw->get_flis_offset(gpio);
++ if (WARN(offset == -EINVAL, "invalid pin %d\n", gpio))
++ return -1;
++
++ if (!is_merr_i2c_flis(offset))
++ spin_lock_irqsave(&lnw->lock, flags);
++ value = get_flis_value(offset);
++ value &= ~(mask << shift);
++ value |= ((num & mask) << shift);
++ set_flis_value(value, offset);
++ if (!is_merr_i2c_flis(offset))
++ spin_unlock_irqrestore(&lnw->lock, flags);
++ return 0;
++ }
++
++ return -1;
++}
++
++static int flis_get_override(struct gpio_control *control, void *private_data,
++ unsigned gpio)
++{
++ struct lnw_gpio *lnw = private_data;
++ u32 offset, value;
++ u32 val_bit, en_bit;
++ int num;
++
++ if (lnw->type == TANGIER_GPIO) {
++ offset = lnw->get_flis_offset(gpio);
++ if (WARN(offset == -EINVAL, "invalid pin %d\n", gpio))
++ return -1;
++
++ val_bit = 1 << control->shift;
++ en_bit = 1 << control->rshift;
++
++ value = get_flis_value(offset);
++
++ if (value & en_bit)
++ if (value & val_bit)
++ num = 1;
++ else
++ num = 2;
++ else
++ num = 0;
++
++ return num;
++ }
++
++ return -1;
++}
++
++static int flis_set_override(struct gpio_control *control, void *private_data,
++ unsigned gpio, unsigned int num)
++{
++ struct lnw_gpio *lnw = private_data;
++ u32 offset, value;
++ u32 val_bit, en_bit;
++ unsigned long flags;
++
++ if (lnw->type == TANGIER_GPIO) {
++ offset = lnw->get_flis_offset(gpio);
++ if (WARN(offset == -EINVAL, "invalid pin %d\n", gpio))
++ return -1;
++
++ val_bit = 1 << control->shift;
++ en_bit = 1 << control->rshift;
++
++ if (!is_merr_i2c_flis(offset))
++ spin_lock_irqsave(&lnw->lock, flags);
++ value = get_flis_value(offset);
++ switch (num) {
++ case 0:
++ value &= ~(en_bit | val_bit);
++ break;
++ case 1:
++ value |= (en_bit | val_bit);
++ break;
++ case 2:
++ value |= en_bit;
++ value &= ~val_bit;
++ break;
++ default:
++ break;
++ }
++ set_flis_value(value, offset);
++ if (!is_merr_i2c_flis(offset))
++ spin_unlock_irqrestore(&lnw->lock, flags);
++
++ return 0;
++ }
++
++ return -1;
++}
++
++#define GPIO_VALUE_CONTROL(xtype, xinfo, xnum) \
++{ .type = xtype, .pininfo = xinfo, .num = xnum, \
++ .get = gpio_get_pinvalue, .set = gpio_set_pinvalue}
++#define GPIO_NORMAL_CONTROL(xtype, xinfo, xnum, xreg, xinvert) \
++{ .type = xtype, .pininfo = xinfo, .num = xnum, .reg = xreg, \
++ .invert = xinvert, .get = gpio_get_normal, .set = gpio_set_normal}
++#define GPIO_IRQTYPE_CONTROL(xtype, xinfo, xnum) \
++{ .type = xtype, .pininfo = xinfo, .num = xnum, \
++ .get = gpio_get_irqtype, .set = NULL}
++#define FLIS_NORMAL_CONTROL(xtype, xinfo, xnum, xshift, xmask) \
++{ .type = xtype, .pininfo = xinfo, .num = xnum, .shift = xshift, \
++ .mask = xmask, .get = flis_get_normal, .set = flis_set_normal}
++#define FLIS_OVERRIDE_CONTROL(xtype, xinfo, xnum, xshift, xrshift) \
++{ .type = xtype, .pininfo = xinfo, .num = xnum, .shift = xshift, \
++ .rshift = xrshift, .get = flis_get_override, .set = flis_set_override}
++
++static struct gpio_control lnw_gpio_controls[] = {
++GPIO_VALUE_CONTROL(TYPE_PIN_VALUE, pinvalue, 2),
++GPIO_NORMAL_CONTROL(TYPE_DIRECTION, pindirection, 2, GPDR, 0),
++GPIO_IRQTYPE_CONTROL(TYPE_IRQ_TYPE, irqtype, 4),
++GPIO_NORMAL_CONTROL(TYPE_DEBOUNCE, enable, 2, GFBR_TNG, 1),
++FLIS_NORMAL_CONTROL(TYPE_PINMUX, pinmux, 8, 0, 0x7),
++FLIS_NORMAL_CONTROL(TYPE_PULLSTRENGTH, pullstrength, 4, 4, 0x7),
++FLIS_NORMAL_CONTROL(TYPE_PULLMODE, pullmode, 3, 8, 0x3),
++FLIS_NORMAL_CONTROL(TYPE_OPEN_DRAIN, enable, 2, 21, 0x1),
++FLIS_OVERRIDE_CONTROL(TYPE_OVERRIDE_INDIR, override_direction, 3, 12, 13),
++FLIS_OVERRIDE_CONTROL(TYPE_OVERRIDE_OUTDIR, override_direction, 3, 14, 15),
++FLIS_OVERRIDE_CONTROL(TYPE_OVERRIDE_INVAL, override_value, 3, 16, 17),
++FLIS_OVERRIDE_CONTROL(TYPE_OVERRIDE_OUTVAL, override_value, 3, 18, 19),
++FLIS_OVERRIDE_CONTROL(TYPE_SBY_OVR_IO, standby_trigger, 3, 23, 22),
++FLIS_OVERRIDE_CONTROL(TYPE_SBY_OVR_OUTVAL, override_value, 3, 18, 24),
++FLIS_OVERRIDE_CONTROL(TYPE_SBY_OVR_INVAL, override_value, 3, 16, 25),
++FLIS_OVERRIDE_CONTROL(TYPE_SBY_OVR_OUTDIR, override_direction, 3, 14, 26),
++FLIS_OVERRIDE_CONTROL(TYPE_SBY_OVR_INDIR, override_direction, 3, 12, 27),
++FLIS_NORMAL_CONTROL(TYPE_SBY_PUPD_STATE, standby_pupd_state, 4, 28, 0x3),
++FLIS_NORMAL_CONTROL(TYPE_SBY_OD_DIS, enable, 2, 30, 0x1),
++};
++
++static unsigned int lnw_get_conf_reg(struct gpio_debug *debug, unsigned gpio)
++{
++ struct lnw_gpio *lnw = debug->private_data;
++ u32 offset, value = 0;
++
++ if (lnw->type == TANGIER_GPIO) {
++ offset = lnw->get_flis_offset(gpio);
++ if (WARN(offset == -EINVAL, "invalid pin %d\n", gpio))
++ return -EINVAL;
++
++ value = get_flis_value(offset);
++ }
++
++ return value;
++}
++
++static void lnw_set_conf_reg(struct gpio_debug *debug, unsigned gpio,
++ unsigned int value)
++{
++ struct lnw_gpio *lnw = debug->private_data;
++ u32 offset;
++
++ if (lnw->type == TANGIER_GPIO) {
++ offset = lnw->get_flis_offset(gpio);
++ if (WARN(offset == -EINVAL, "invalid pin %d\n", gpio))
++ return;
++
++ set_flis_value(value, offset);
++ }
++
++ return;
++}
++
++static char **lnw_get_avl_pininfo(struct gpio_debug *debug, unsigned gpio,
++ unsigned int type, unsigned *num)
++{
++ struct gpio_control *control;
++
++ control = find_gpio_control(lnw_gpio_controls,
++ ARRAY_SIZE(lnw_gpio_controls), type);
++ if (control == NULL)
++ return NULL;
++
++ *num = control->num;
++
++ return control->pininfo;
++}
++
++static char *lnw_get_cul_pininfo(struct gpio_debug *debug, unsigned gpio,
++ unsigned int type)
++{
++ struct lnw_gpio *lnw = debug->private_data;
++ struct gpio_control *control;
++ int num;
++
++ control = find_gpio_control(lnw_gpio_controls,
++ ARRAY_SIZE(lnw_gpio_controls), type);
++ if (control == NULL)
++ return NULL;
++
++ num = control->get(control, lnw, gpio);
++ if (num == -1)
++ return NULL;
++
++ return *(control->pininfo + num);
++}
++
++static void lnw_set_pininfo(struct gpio_debug *debug, unsigned gpio,
++ unsigned int type, const char *info)
++{
++ struct lnw_gpio *lnw = debug->private_data;
++ struct gpio_control *control;
++ int num;
++
++ control = find_gpio_control(lnw_gpio_controls,
++ ARRAY_SIZE(lnw_gpio_controls), type);
++ if (control == NULL)
++ return;
++
++ num = find_pininfo_num(control, info);
++ if (num == -1)
++ return;
++
++ if (control->set)
++ control->set(control, lnw, gpio, num);
++}
++
++static int lnw_get_register_msg(char **buf, unsigned long *size)
++{
++ *buf = conf_reg_msg;
++ *size = strlen(conf_reg_msg);
++
++ return 0;
++}
++
++static struct gpio_debug_ops lnw_gpio_debug_ops = {
++ .get_conf_reg = lnw_get_conf_reg,
++ .set_conf_reg = lnw_set_conf_reg,
++ .get_avl_pininfo = lnw_get_avl_pininfo,
++ .get_cul_pininfo = lnw_get_cul_pininfo,
++ .set_pininfo = lnw_set_pininfo,
++ .get_register_msg = lnw_get_register_msg,
++};
++
+ static void lnw_irq_init_hw(struct lnw_gpio *lnw)
+ {
+ void __iomem *reg;
+@@ -303,6 +1227,16 @@ static const struct irq_domain_ops lnw_gpio_irq_ops = {
+ .xlate = irq_domain_xlate_twocell,
+ };
+
++static int lnw_gpio_runtime_resume(struct device *dev)
++{
++ return 0;
++}
++
++static int lnw_gpio_runtime_suspend(struct device *dev)
++{
++ return 0;
++}
++
+ static int lnw_gpio_runtime_idle(struct device *dev)
+ {
+ int err = pm_schedule_suspend(dev, 500);
+@@ -314,7 +1248,9 @@ static int lnw_gpio_runtime_idle(struct device *dev)
+ }
+
+ static const struct dev_pm_ops lnw_gpio_pm_ops = {
+- SET_RUNTIME_PM_OPS(NULL, NULL, lnw_gpio_runtime_idle)
++ SET_RUNTIME_PM_OPS(lnw_gpio_runtime_suspend,
++ lnw_gpio_runtime_resume,
++ lnw_gpio_runtime_idle)
+ };
+
+ static int lnw_gpio_probe(struct pci_dev *pdev,
+@@ -323,10 +1259,15 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
+ void *base;
+ resource_size_t start, len;
+ struct lnw_gpio *lnw;
++ struct gpio_debug *debug;
+ u32 gpio_base;
+ u32 irq_base;
+ int retval;
+- int ngpio = id->driver_data;
++ struct lnw_gpio_ddata_t *ddata;
++ int pid;
++
++ pid = id->driver_data;
++ ddata = &lnw_gpio_ddata[pid];
+
+ retval = pci_enable_device(pdev);
+ if (retval)
+@@ -367,20 +1308,29 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
+ goto err_ioremap;
+ }
+
++ lnw->type = pid;
+ lnw->reg_base = base;
++ lnw->reg_gplr = lnw->reg_base + ddata->gplr_offset;
++ lnw->get_flis_offset = ddata->get_flis_offset;
++ lnw->chip_irq_type = ddata->chip_irq_type;
+ lnw->chip.label = dev_name(&pdev->dev);
+ lnw->chip.request = lnw_gpio_request;
+ lnw->chip.direction_input = lnw_gpio_direction_input;
+ lnw->chip.direction_output = lnw_gpio_direction_output;
++ lnw->chip.set_pinmux = lnw_gpio_set_alt;
++ lnw->chip.get_pinmux = gpio_get_alt;
+ lnw->chip.get = lnw_gpio_get;
+ lnw->chip.set = lnw_gpio_set;
+ lnw->chip.to_irq = lnw_gpio_to_irq;
+ lnw->chip.base = gpio_base;
+- lnw->chip.ngpio = ngpio;
++ lnw->chip.ngpio = ddata->ngpio;
+ lnw->chip.can_sleep = 0;
++ lnw->chip.set_debounce = lnw_gpio_set_debounce;
++ lnw->chip.dev = &pdev->dev;
+ lnw->pdev = pdev;
+-
+- lnw->domain = irq_domain_add_simple(pdev->dev.of_node, ngpio, irq_base,
++ spin_lock_init(&lnw->lock);
++ lnw->domain = irq_domain_add_simple(pdev->dev.of_node,
++ lnw->chip.ngpio, irq_base,
+ &lnw_gpio_irq_ops, lnw);
+ if (!lnw->domain) {
+ retval = -ENOMEM;
+@@ -395,15 +1345,40 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
+ }
+
+ lnw_irq_init_hw(lnw);
+-
+ irq_set_handler_data(pdev->irq, lnw);
+ irq_set_chained_handler(pdev->irq, lnw_irq_handler);
+
+- spin_lock_init(&lnw->lock);
+-
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_allow(&pdev->dev);
+
++ /* add for gpiodebug */
++ debug = gpio_debug_alloc();
++ if (debug) {
++ __set_bit(TYPE_OVERRIDE_OUTDIR, debug->typebit);
++ __set_bit(TYPE_OVERRIDE_OUTVAL, debug->typebit);
++ __set_bit(TYPE_OVERRIDE_INDIR, debug->typebit);
++ __set_bit(TYPE_OVERRIDE_INVAL, debug->typebit);
++ __set_bit(TYPE_SBY_OVR_IO, debug->typebit);
++ __set_bit(TYPE_SBY_OVR_OUTVAL, debug->typebit);
++ __set_bit(TYPE_SBY_OVR_INVAL, debug->typebit);
++ __set_bit(TYPE_SBY_OVR_OUTDIR, debug->typebit);
++ __set_bit(TYPE_SBY_OVR_INDIR, debug->typebit);
++ __set_bit(TYPE_SBY_PUPD_STATE, debug->typebit);
++ __set_bit(TYPE_SBY_OD_DIS, debug->typebit);
++
++ debug->chip = &lnw->chip;
++ debug->ops = &lnw_gpio_debug_ops;
++ debug->private_data = lnw;
++ lnw->debug = debug;
++
++ retval = gpio_debug_register(debug);
++ if (retval) {
++ dev_err(&pdev->dev, "langwell gpio_debug_register failed %d\n",
++ retval);
++ gpio_debug_remove(debug);
++ }
++ }
++
+ return 0;
+
+ err_ioremap:
+@@ -506,4 +1481,4 @@ static int __init lnw_gpio_init(void)
+ return ret;
+ }
+
+-device_initcall(lnw_gpio_init);
++fs_initcall(lnw_gpio_init);
+diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
+index 426c51d..6d4499f 100644
+--- a/drivers/gpio/gpio-pca953x.c
++++ b/drivers/gpio/gpio-pca953x.c
+@@ -29,6 +29,10 @@
+ #define PCA953X_INVERT 2
+ #define PCA953X_DIRECTION 3
+
++#define PCAL953X_IN_LATCH 34
++#define PCAL953X_INT_MASK 37
++#define PCAL953X_INT_STAT 38
++
+ #define REG_ADDR_AI 0x80
+
+ #define PCA957X_IN 0
+@@ -44,30 +48,34 @@
+ #define PCA_INT 0x0100
+ #define PCA953X_TYPE 0x1000
+ #define PCA957X_TYPE 0x2000
++#define PCAL953X_TYPE 0x4000
+
+ static const struct i2c_device_id pca953x_id[] = {
+- { "pca9505", 40 | PCA953X_TYPE | PCA_INT, },
+- { "pca9534", 8 | PCA953X_TYPE | PCA_INT, },
+- { "pca9535", 16 | PCA953X_TYPE | PCA_INT, },
+- { "pca9536", 4 | PCA953X_TYPE, },
+- { "pca9537", 4 | PCA953X_TYPE | PCA_INT, },
+- { "pca9538", 8 | PCA953X_TYPE | PCA_INT, },
+- { "pca9539", 16 | PCA953X_TYPE | PCA_INT, },
+- { "pca9554", 8 | PCA953X_TYPE | PCA_INT, },
+- { "pca9555", 16 | PCA953X_TYPE | PCA_INT, },
+- { "pca9556", 8 | PCA953X_TYPE, },
+- { "pca9557", 8 | PCA953X_TYPE, },
+- { "pca9574", 8 | PCA957X_TYPE | PCA_INT, },
+- { "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
+-
+- { "max7310", 8 | PCA953X_TYPE, },
+- { "max7312", 16 | PCA953X_TYPE | PCA_INT, },
+- { "max7313", 16 | PCA953X_TYPE | PCA_INT, },
+- { "max7315", 8 | PCA953X_TYPE | PCA_INT, },
+- { "pca6107", 8 | PCA953X_TYPE | PCA_INT, },
+- { "tca6408", 8 | PCA953X_TYPE | PCA_INT, },
+- { "tca6416", 16 | PCA953X_TYPE | PCA_INT, },
+- { "tca6424", 24 | PCA953X_TYPE | PCA_INT, },
++ { "pca9505", 40 | PCA953X_TYPE | PCA_INT, },
++ { "pca9534", 8 | PCA953X_TYPE | PCA_INT, },
++ { "pca9535", 16 | PCA953X_TYPE | PCA_INT, },
++ { "pca9536", 4 | PCA953X_TYPE, },
++ { "pca9537", 4 | PCA953X_TYPE | PCA_INT, },
++ { "pca9538", 8 | PCA953X_TYPE | PCA_INT, },
++ { "pca9539", 16 | PCA953X_TYPE | PCA_INT, },
++ { "pca9554", 8 | PCA953X_TYPE | PCA_INT, },
++ { "pca9555", 16 | PCA953X_TYPE | PCA_INT, },
++ { "pca9556", 8 | PCA953X_TYPE, },
++ { "pca9557", 8 | PCA953X_TYPE, },
++ { "pca9574", 8 | PCA957X_TYPE | PCA_INT, },
++ { "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
++
++ { "pcal9535a", 16 | PCAL953X_TYPE | PCA_INT, },
++ { "pcal9555a", 16 | PCAL953X_TYPE | PCA_INT, },
++
++ { "max7310", 8 | PCA953X_TYPE, },
++ { "max7312", 16 | PCA953X_TYPE | PCA_INT, },
++ { "max7313", 16 | PCA953X_TYPE | PCA_INT, },
++ { "max7315", 8 | PCA953X_TYPE | PCA_INT, },
++ { "pca6107", 8 | PCA953X_TYPE | PCA_INT, },
++ { "tca6408", 8 | PCA953X_TYPE | PCA_INT, },
++ { "tca6416", 16 | PCA953X_TYPE | PCA_INT, },
++ { "tca6424", 24 | PCA953X_TYPE | PCA_INT, },
+ { }
+ };
+ MODULE_DEVICE_TABLE(i2c, pca953x_id);
+@@ -148,6 +156,7 @@ static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val)
+ NBANK(chip), val);
+ } else {
+ switch (chip->chip_type) {
++ case PCAL953X_TYPE:
+ case PCA953X_TYPE:
+ ret = i2c_smbus_write_word_data(chip->client,
+ reg << 1, (u16) *val);
+@@ -210,6 +219,7 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
+ reg_val = chip->reg_direction[off / BANK_SZ] | (1u << (off % BANK_SZ));
+
+ switch (chip->chip_type) {
++ case PCAL953X_TYPE:
+ case PCA953X_TYPE:
+ offset = PCA953X_DIRECTION;
+ break;
+@@ -247,6 +257,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
+ & ~(1u << (off % BANK_SZ));
+
+ switch (chip->chip_type) {
++ case PCAL953X_TYPE:
+ case PCA953X_TYPE:
+ offset = PCA953X_OUTPUT;
+ break;
+@@ -263,6 +274,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
+ /* then direction */
+ reg_val = chip->reg_direction[off / BANK_SZ] & ~(1u << (off % BANK_SZ));
+ switch (chip->chip_type) {
++ case PCAL953X_TYPE:
+ case PCA953X_TYPE:
+ offset = PCA953X_DIRECTION;
+ break;
+@@ -291,6 +303,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
+
+ mutex_lock(&chip->i2c_lock);
+ switch (chip->chip_type) {
++ case PCAL953X_TYPE:
+ case PCA953X_TYPE:
+ offset = PCA953X_INPUT;
+ break;
+@@ -328,6 +341,7 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
+ & ~(1u << (off % BANK_SZ));
+
+ switch (chip->chip_type) {
++ case PCAL953X_TYPE:
+ case PCA953X_TYPE:
+ offset = PCA953X_OUTPUT;
+ break;
+@@ -411,6 +425,17 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
+ level + (BANK_SZ * i));
+ new_irqs &= ~(1 << level);
+ }
++
++ if (chip->chip_type == PCAL953X_TYPE) {
++ /* Enable latch on interrupt-enabled inputs */
++ pca953x_write_single(chip, PCAL953X_IN_LATCH,
++ chip->irq_mask[i],
++ BANK_SZ * i);
++ /* Unmask enabled interrupts */
++ pca953x_write_single(chip, PCAL953X_INT_MASK,
++ ~chip->irq_mask[i],
++ BANK_SZ * i);
++ }
+ }
+
+ mutex_unlock(&chip->irq_lock);
+@@ -459,6 +484,7 @@ static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
+ int ret, i, offset = 0;
+
+ switch (chip->chip_type) {
++ case PCAL953X_TYPE:
+ case PCA953X_TYPE:
+ offset = PCA953X_INPUT;
+ break;
+@@ -496,14 +522,45 @@ static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
+ return pendings;
+ }
+
++static u32 pcal953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
++{
++ u8 cur_stat[MAX_BANK];
++ int ret, i = 0;
++ u8 pendings = 0;
++
++ /* Read the current interrupt status from the device */
++ ret = pca953x_read_regs(chip, PCAL953X_INT_STAT, pending);
++ if (ret)
++ return 0;
++
++ /* Check latched inputs and clear interrupt status */
++ ret = pca953x_read_regs(chip, PCA953X_INPUT, cur_stat);
++ if (ret)
++ return 0;
++
++ /* Apply filter for rising/falling edge selection */
++ for (i = 0; i < NBANK(chip); i++) {
++ pending[i] &= (~cur_stat[i] & chip->irq_trig_fall[i]) |
++ (cur_stat[i] & chip->irq_trig_raise[i]);
++ pendings += pending[i];
++ }
++
++ return pendings;
++}
++
+ static irqreturn_t pca953x_irq_handler(int irq, void *devid)
+ {
+ struct pca953x_chip *chip = devid;
+ u8 pending[MAX_BANK];
+ u8 level;
+- int i;
++ int i, pendings;
+
+- if (!pca953x_irq_pending(chip, pending))
++ if (chip->chip_type == PCAL953X_TYPE)
++ pendings = pcal953x_irq_pending(chip, pending);
++ else
++ pendings = pca953x_irq_pending(chip, pending);
++
++ if (!pendings)
+ return IRQ_HANDLED;
+
+ for (i = 0; i < NBANK(chip); i++) {
+@@ -549,25 +606,27 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
+ if (irq_base != -1
+ && (id->driver_data & PCA_INT)) {
+
+- switch (chip->chip_type) {
+- case PCA953X_TYPE:
+- offset = PCA953X_INPUT;
+- break;
+- case PCA957X_TYPE:
+- offset = PCA957X_IN;
+- break;
++ if (chip->chip_type != PCAL953X_TYPE) {
++ switch (chip->chip_type) {
++ case PCA953X_TYPE:
++ offset = PCA953X_INPUT;
++ break;
++ case PCA957X_TYPE:
++ offset = PCA957X_IN;
++ break;
++ }
++ ret = pca953x_read_regs(chip, offset, chip->irq_stat);
++ if (ret)
++ return ret;
++
++ /*
++ * There is no way to know which GPIO line generated the
++ * interrupt. We have to rely on the previous read for
++ * this purpose.
++ */
++ for (i = 0; i < NBANK(chip); i++)
++ chip->irq_stat[i] &= chip->reg_direction[i];
+ }
+- ret = pca953x_read_regs(chip, offset, chip->irq_stat);
+- if (ret)
+- return ret;
+-
+- /*
+- * There is no way to know which GPIO line generated the
+- * interrupt. We have to rely on the previous read for
+- * this purpose.
+- */
+- for (i = 0; i < NBANK(chip); i++)
+- chip->irq_stat[i] &= chip->reg_direction[i];
+ mutex_init(&chip->irq_lock);
+
+ chip->domain = irq_domain_add_simple(client->dev.of_node,
+@@ -748,7 +807,8 @@ static int pca953x_probe(struct i2c_client *client,
+
+ chip->client = client;
+
+- chip->chip_type = id->driver_data & (PCA953X_TYPE | PCA957X_TYPE);
++ chip->chip_type = id->driver_data &
++ (PCAL953X_TYPE | PCA953X_TYPE | PCA957X_TYPE);
+
+ mutex_init(&chip->i2c_lock);
+
+@@ -757,7 +817,7 @@ static int pca953x_probe(struct i2c_client *client,
+ */
+ pca953x_setup_gpio(chip, id->driver_data & PCA_GPIO_MASK);
+
+- if (chip->chip_type == PCA953X_TYPE)
++ if (chip->chip_type & (PCA953X_TYPE | PCAL953X_TYPE))
+ ret = device_pca953x_init(chip, invert);
+ else
+ ret = device_pca957x_init(chip, invert);
+@@ -824,6 +884,9 @@ static const struct of_device_id pca953x_dt_ids[] = {
+ { .compatible = "nxp,pca9574", },
+ { .compatible = "nxp,pca9575", },
+
++ { .compatible = "nxp,pcal9535a", },
++ { .compatible = "nxp,pcal9555a", },
++
+ { .compatible = "maxim,max7310", },
+ { .compatible = "maxim,max7312", },
+ { .compatible = "maxim,max7313", },
+diff --git a/drivers/gpio/gpiodebug.c b/drivers/gpio/gpiodebug.c
+new file mode 100644
+index 0000000..cc5159b
+--- /dev/null
++++ b/drivers/gpio/gpiodebug.c
+@@ -0,0 +1,540 @@
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include<linux/slab.h>
++#include <linux/debugfs.h>
++#include <linux/uaccess.h>
++#include <linux/ctype.h>
++#include "gpiodebug.h"
++
++struct gpiodebug_data {
++ struct gpio_debug *debug;
++ int gpio;
++ unsigned int type;
++};
++
++enum {
++ REGISTER_FOPS = 0,
++ NORMAL_FOPS,
++ COUNT_FOPS,
++};
++
++static struct {
++ unsigned fops_type;
++ unsigned type;
++ char *available_name;
++ char *current_name;
++} global_array[] = {
++ {REGISTER_FOPS, TYPE_CONF_REG, "conf_reg", "conf_reg"},
++ {NORMAL_FOPS, TYPE_PIN_VALUE, "available_value",
++ "current_value"},
++ {NORMAL_FOPS, TYPE_DIRECTION, "available_direction",
++ "current_direction"},
++ {NORMAL_FOPS, TYPE_IRQ_TYPE, "available_irqtype",
++ "current_irqtype"},
++ {NORMAL_FOPS, TYPE_PINMUX, "available_pinmux",
++ "current_pinmux"},
++ {NORMAL_FOPS, TYPE_PULLMODE, "available_pullmode",
++ "current_pullmode"},
++ {NORMAL_FOPS, TYPE_PULLSTRENGTH, "available_pullstrength",
++ "current_pullstrength"},
++ {NORMAL_FOPS, TYPE_OPEN_DRAIN, "available_opendrain",
++ "current_opendrain"},
++ {COUNT_FOPS, TYPE_IRQ_COUNT, "irq_count", "irq_count"},
++ {NORMAL_FOPS, TYPE_WAKEUP, "available_wakeup", "current_wakeup"},
++ {COUNT_FOPS, TYPE_WAKEUP_COUNT, "wakeup_count", "wakeup_count"},
++ {NORMAL_FOPS, TYPE_DEBOUNCE, "available_debounce",
++ "current_debounce"},
++ {NORMAL_FOPS, TYPE_OVERRIDE_OUTDIR, "available_override_outdir",
++ "current_override_outdir"},
++ {NORMAL_FOPS, TYPE_OVERRIDE_OUTVAL, "available_override_outval",
++ "current_override_outval"},
++ {NORMAL_FOPS, TYPE_OVERRIDE_INDIR, "available_override_indir",
++ "current_override_indir"},
++ {NORMAL_FOPS, TYPE_OVERRIDE_INVAL, "available_override_inval",
++ "current_override_inval"},
++ {NORMAL_FOPS, TYPE_SBY_OVR_IO, "available_standby_trigger",
++ "current_standby_trigger"},
++ {NORMAL_FOPS, TYPE_SBY_OVR_OUTVAL, "available_standby_outval",
++ "current_standby_outval"},
++ {NORMAL_FOPS, TYPE_SBY_OVR_INVAL, "available_standby_inval",
++ "current_standby_inval"},
++ {NORMAL_FOPS, TYPE_SBY_OVR_OUTDIR, "available_standby_outdir",
++ "current_standby_outdir"},
++ {NORMAL_FOPS, TYPE_SBY_OVR_INDIR, "available_standby_indir",
++ "current_standby_indir"},
++ {NORMAL_FOPS, TYPE_SBY_PUPD_STATE, "available_standby_pullmode",
++ "current_standby_pullmode"},
++ {NORMAL_FOPS, TYPE_SBY_OD_DIS, "available_standby_opendrain",
++ "current_standby_opendrain"},
++
++};
++
++static struct dentry *gpio_root[ARCH_NR_GPIOS];
++static struct gpiodebug_data global_data[ARCH_NR_GPIOS][TYPE_MAX];
++
++static struct dentry *gpiodebug_debugfs_root;
++
++struct gpio_control *find_gpio_control(struct gpio_control *control, int num,
++ unsigned type)
++{
++ int i;
++
++ for (i = 0; i < num; i++) {
++ if ((control+i)->type == type)
++ break;
++ }
++
++ if (i < num)
++ return control+i;
++
++ return NULL;
++}
++
++int find_pininfo_num(struct gpio_control *control, const char *info)
++{
++ int num = 0;
++
++ while (num < control->num) {
++ if (!strcmp(*(control->pininfo+num), info))
++ break;
++ num++;
++ }
++
++ if (num < control->num)
++ return num;
++
++ return -1;
++}
++
++static struct dentry *gpiodebug_create_file(const char *name,
++ umode_t mode, struct dentry *parent,
++ void *data, const struct file_operations *fops)
++{
++ struct dentry *ret;
++
++ ret = debugfs_create_file(name, mode, parent, data, fops);
++ if (!ret)
++ pr_warn("Could not create debugfs '%s' entry\n", name);
++
++ return ret;
++}
++
++static int gpiodebug_open_file(struct inode *inode, struct file *filp)
++{
++ filp->private_data = inode->i_private;
++ return 0;
++}
++
++static const char readme_msg[] =
++ "\n GPIO Debug Tool-HOWTO (Example):\n\n"
++ "# mount -t debugfs nodev /sys/kernel/debug\n\n"
++ "# cat /sys/kernel/debug/gpio_debug/gpio0/available_pullmode\n"
++ "nopull pullup pulldown\n\n"
++ "# cat /sys/kernel/debug/gpio_debug/gpio0/current_pullmode\n"
++ "nopull\n"
++ "# echo pullup > /sys/kernel/debug/gpio_debug/gpio0/current_pullmode\n"
++ "# cat /sys/kernel/debug/gpio_debug/gpio0/current_pullmode\n"
++ "pullup\n\n"
++ "# cat conf_reg\n"
++ "0x00003120\n"
++ "# echo 0x00003121 > conf_reg\n"
++ "0x00003121\n\n"
++ "# cat irq_count\n"
++ "1\n";
++
++/* gpio_readme_fops */
++static ssize_t show_gpio_readme(struct file *filp, char __user *ubuf,
++ size_t cnt, loff_t *ppos)
++{
++ ssize_t ret = 0;
++
++ if (*ppos < 0 || !cnt)
++ return -EINVAL;
++
++ ret = simple_read_from_buffer(ubuf, cnt, ppos, readme_msg,
++ strlen(readme_msg));
++
++ return ret;
++}
++
++static const struct file_operations gpio_readme_fops = {
++ .open = gpiodebug_open_file,
++ .read = show_gpio_readme,
++ .llseek = generic_file_llseek,
++};
++
++/* gpio_reginfo_fops */
++static ssize_t show_gpio_reginfo(struct file *filp, char __user *ubuf,
++ size_t cnt, loff_t *ppos)
++{
++ ssize_t ret = 0;
++ struct gpio_debug *debug = filp->private_data;
++ unsigned long size;
++ char *buf;
++
++ if (*ppos < 0 || !cnt)
++ return -EINVAL;
++
++ if (debug->ops->get_register_msg) {
++ debug->ops->get_register_msg(&buf, &size);
++ ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, size);
++ }
++
++ return ret;
++}
++
++static const struct file_operations gpio_reginfo_fops = {
++ .open = gpiodebug_open_file,
++ .read = show_gpio_reginfo,
++ .llseek = generic_file_llseek,
++};
++
++
++/* gpio_conf_fops */
++static ssize_t gpio_conf_read(struct file *filp, char __user *ubuf,
++ size_t cnt, loff_t *ppos)
++{
++ ssize_t ret = 0;
++ struct gpiodebug_data *data = filp->private_data;
++ struct gpio_debug *debug = data->debug;
++ int gpio = data->gpio;
++ char *buf;
++ unsigned int value = 0;
++
++ if (*ppos < 0 || !cnt)
++ return -EINVAL;
++
++ buf = kzalloc(cnt, GFP_KERNEL);
++ if (!buf)
++ return -ENOMEM;
++
++ if (debug->ops->get_conf_reg)
++ value = debug->ops->get_conf_reg(debug, gpio);
++
++ if (value == -EINVAL)
++ ret = sprintf(buf, "Invalid pin\n");
++ else
++ ret = sprintf(buf, "0x%08x\n", value);
++
++ ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, ret);
++
++ kfree(buf);
++ return ret;
++}
++
++static ssize_t gpio_conf_write(struct file *filp, const char __user *ubuf,
++ size_t cnt, loff_t *ppos)
++{
++ ssize_t ret = 0;
++ struct gpiodebug_data *data = filp->private_data;
++ struct gpio_debug *debug = data->debug;
++ int i, gpio = data->gpio;
++ char *buf, *start;
++ unsigned int value;
++
++ ret = cnt;
++
++ if (*ppos < 0 || !cnt)
++ return -EINVAL;
++
++ buf = kzalloc(cnt, GFP_KERNEL);
++ if (!buf)
++ return -ENOMEM;
++
++ if (copy_from_user(buf, ubuf, cnt))
++ return -EFAULT;
++
++ start = buf;
++
++ while (*start == ' ')
++ start++;
++
++ /* strip ending whitespace. */
++ for (i = cnt - 1; i > 0 && isspace(buf[i]); i--)
++ buf[i] = 0;
++
++ kstrtoul(start, 16, &value);
++
++ if (debug->ops->set_conf_reg)
++ debug->ops->set_conf_reg(debug, gpio, value);
++
++ *ppos += ret;
++
++ return ret;
++}
++
++static const struct file_operations gpio_conf_fops = {
++ .open = gpiodebug_open_file,
++ .read = gpio_conf_read,
++ .write = gpio_conf_write,
++ .llseek = generic_file_llseek,
++};
++
++/* show_gpiodebug_fops */
++static ssize_t gpiodebug_show_read(struct file *filp, char __user *ubuf,
++ size_t cnt, loff_t *ppos)
++{
++ ssize_t ret = 0;
++ struct gpiodebug_data *data = filp->private_data;
++ struct gpio_debug *debug = data->debug;
++ unsigned int type = data->type;
++ int i, num = 0;
++ int gpio = data->gpio;
++ char *buf, **avl_buf = NULL;
++
++ if (*ppos < 0 || !cnt)
++ return -EINVAL;
++
++ buf = kzalloc(cnt, GFP_KERNEL);
++ if (!buf)
++ return -ENOMEM;
++
++ /* debug->ops->get_avl_info */
++ if (debug->ops->get_avl_pininfo) {
++ avl_buf = debug->ops->get_avl_pininfo(debug, gpio, type, &num);
++
++ for (i = 0; i < num; i++)
++ sprintf(buf, "%s%s\t", buf, *(avl_buf+i));
++ }
++
++ ret = sprintf(buf, "%s\n", buf);
++
++ ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, ret);
++
++ kfree(buf);
++
++ return ret;
++}
++
++static const struct file_operations show_gpiodebug_fops = {
++ .open = gpiodebug_open_file,
++ .read = gpiodebug_show_read,
++ .llseek = generic_file_llseek,
++};
++
++/* set_gpiodebug_fops */
++static ssize_t gpiodebug_set_gpio_read(struct file *filp, char __user *ubuf,
++ size_t cnt, loff_t *ppos)
++{
++ ssize_t ret = 0;
++ struct gpiodebug_data *data = filp->private_data;
++ struct gpio_debug *debug = data->debug;
++ unsigned int type = data->type;
++ int gpio = data->gpio;
++ char *buf, *cur_info = NULL;
++
++ if (*ppos < 0 || !cnt)
++ return -EINVAL;
++
++ buf = kzalloc(cnt, GFP_KERNEL);
++ if (!buf)
++ return -ENOMEM;
++
++ if (debug->ops->get_cul_pininfo)
++ cur_info = debug->ops->get_cul_pininfo(debug, gpio, type);
++
++ if (cur_info)
++ ret = sprintf(buf, "%s\n", cur_info);
++ else
++ ret = sprintf(buf, "\n");
++
++ ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, ret);
++
++ kfree(buf);
++
++ return ret;
++}
++
++static ssize_t gpiodebug_set_gpio_write(struct file *filp,
++ const char __user *ubuf, size_t cnt, loff_t *ppos)
++{
++ ssize_t ret = 0;
++ struct gpiodebug_data *data = filp->private_data;
++ struct gpio_debug *debug = data->debug;
++ unsigned int type = data->type;
++ int i, gpio = data->gpio;
++ char *buf;
++
++ ret = cnt;
++
++ if (*ppos < 0 || !cnt)
++ return -EINVAL;
++
++ buf = kzalloc(cnt, GFP_KERNEL);
++ if (!buf)
++ return -ENOMEM;
++
++ if (copy_from_user(buf, ubuf, cnt))
++ return -EFAULT;
++
++ /* strip ending whitespace. */
++ for (i = cnt - 1; i > 0 && isspace(buf[i]); i--)
++ buf[i] = 0;
++
++ if (debug->ops->set_pininfo)
++ debug->ops->set_pininfo(debug, gpio, type, buf);
++
++ *ppos += ret;
++
++ return ret;
++}
++
++static const struct file_operations set_gpiodebug_fops = {
++ .open = gpiodebug_open_file,
++ .read = gpiodebug_set_gpio_read,
++ .write = gpiodebug_set_gpio_write,
++ .llseek = generic_file_llseek,
++};
++
++/* show_count_fops */
++static ssize_t show_count_read(struct file *filp, char __user *ubuf,
++ size_t cnt, loff_t *ppos)
++{
++ ssize_t ret = 0;
++ struct gpiodebug_data *data = filp->private_data;
++ struct gpio_debug *debug = data->debug;
++ unsigned int type = data->type;
++ unsigned long count = 0;
++ int gpio = data->gpio;
++ char *buf;
++
++ if (*ppos < 0 || !cnt)
++ return -EINVAL;
++
++ buf = kzalloc(cnt, GFP_KERNEL);
++ if (!buf)
++ return -ENOMEM;
++
++ if (type == TYPE_IRQ_COUNT)
++ count = debug->irq_count[gpio];
++ else if (type == TYPE_WAKEUP_COUNT)
++ count = debug->wakeup_count[gpio];
++
++ ret = sprintf(buf, "%ld\n", count);
++
++ ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, ret);
++
++ kfree(buf);
++
++ return ret;
++}
++
++static const struct file_operations show_count_fops = {
++ .open = gpiodebug_open_file,
++ .read = show_count_read,
++ .llseek = generic_file_llseek,
++};
++
++/******************************************************************************/
++struct gpio_debug *gpio_debug_alloc(void)
++{
++ struct gpio_debug *debug;
++
++ debug = kzalloc(sizeof(struct gpio_debug), GFP_KERNEL);
++ if (debug) {
++ __set_bit(TYPE_CONF_REG, debug->typebit);
++ __set_bit(TYPE_PIN_VALUE, debug->typebit);
++ __set_bit(TYPE_DIRECTION, debug->typebit);
++ __set_bit(TYPE_IRQ_TYPE, debug->typebit);
++ __set_bit(TYPE_PINMUX, debug->typebit);
++ __set_bit(TYPE_PULLMODE, debug->typebit);
++ __set_bit(TYPE_PULLSTRENGTH, debug->typebit);
++ __set_bit(TYPE_OPEN_DRAIN, debug->typebit);
++ __set_bit(TYPE_IRQ_COUNT, debug->typebit);
++ __set_bit(TYPE_DEBOUNCE, debug->typebit);
++ }
++
++ return debug;
++}
++
++void gpio_debug_remove(struct gpio_debug *debug)
++{
++ struct gpio_chip *chip = debug->chip;
++ int base = chip->base;
++ unsigned ngpio = chip->ngpio;
++ int i;
++
++ for (i = base; i < base+ngpio; i++)
++ debugfs_remove_recursive(gpio_root[i]);
++
++ kfree(debug);
++}
++
++int gpio_debug_register(struct gpio_debug *debug)
++{
++ struct gpio_chip *chip = debug->chip;
++ int base = chip->base;
++ unsigned ngpio = chip->ngpio;
++ int i, j;
++ char gpioname[32];
++
++ for (i = base; i < base+ngpio; i++) {
++ sprintf(gpioname, "gpio%d", i);
++ gpio_root[i] = debugfs_create_dir(gpioname,
++ gpiodebug_debugfs_root);
++ if (!gpio_root[i]) {
++ pr_warn("gpiodebug: Failed to create debugfs directory\n");
++ return -ENOMEM;
++ }
++
++ /* register info */
++ gpiodebug_create_file("register_info", 0444, gpio_root[i],
++ debug, &gpio_reginfo_fops);
++
++ for (j = 0; j < ARRAY_SIZE(global_array); j++) {
++ if (test_bit(global_array[j].type, debug->typebit)) {
++ global_data[i][j].gpio = i;
++ global_data[i][j].debug = debug;
++ global_data[i][j].type = global_array[j].type;
++
++ switch (global_array[j].fops_type) {
++ case REGISTER_FOPS:
++ gpiodebug_create_file(
++ global_array[j].current_name, 0644,
++ gpio_root[i], &global_data[i][j],
++ &gpio_conf_fops);
++ break;
++ case NORMAL_FOPS:
++ gpiodebug_create_file(
++ global_array[j].available_name, 0444,
++ gpio_root[i], &global_data[i][j],
++ &show_gpiodebug_fops);
++
++ gpiodebug_create_file(
++ global_array[j].current_name, 0644,
++ gpio_root[i], &global_data[i][j],
++ &set_gpiodebug_fops);
++ break;
++ case COUNT_FOPS:
++ gpiodebug_create_file(
++ global_array[j].current_name, 0444,
++ gpio_root[i], &global_data[i][j],
++ &show_count_fops);
++ break;
++ default:
++ break;
++ }
++ }
++ }
++ }
++
++ return 0;
++}
++
++static int __init gpio_debug_init(void)
++{
++ gpiodebug_debugfs_root = debugfs_create_dir("gpio_debug", NULL);
++ if (IS_ERR(gpiodebug_debugfs_root) || !gpiodebug_debugfs_root) {
++ pr_warn("gpiodebug: Failed to create debugfs directory\n");
++ gpiodebug_debugfs_root = NULL;
++ }
++
++ /* readme */
++ gpiodebug_create_file("readme", 0444, gpiodebug_debugfs_root,
++ NULL, &gpio_readme_fops);
++
++ return 0;
++}
++
++subsys_initcall(gpio_debug_init);
+diff --git a/drivers/gpio/gpiodebug.h b/drivers/gpio/gpiodebug.h
+new file mode 100644
+index 0000000..f1d58a5
+--- /dev/null
++++ b/drivers/gpio/gpiodebug.h
+@@ -0,0 +1,108 @@
++#ifndef __GPIO_DEBUG_H_
++#define __GPIO_DEBUG_H_
++
++#include <linux/gpio.h>
++
++struct gpio_debug;
++
++#define TYPE_CONF_REG 0x00
++#define TYPE_PIN_VALUE 0x01
++#define TYPE_DIRECTION 0x02
++#define TYPE_IRQ_TYPE 0x03
++#define TYPE_PINMUX 0x04
++#define TYPE_PULLMODE 0x05
++#define TYPE_PULLSTRENGTH 0x06
++#define TYPE_OPEN_DRAIN 0x07
++
++#define TYPE_IRQ_COUNT 0x08
++#define TYPE_WAKEUP 0x09
++#define TYPE_WAKEUP_COUNT 0x0A
++#define TYPE_OVERRIDE_OUTDIR 0x0B
++#define TYPE_OVERRIDE_OUTVAL 0x0C
++#define TYPE_OVERRIDE_INDIR 0x0D
++#define TYPE_OVERRIDE_INVAL 0x0E
++#define TYPE_DEBOUNCE 0x0F
++
++#define TYPE_SBY_OVR_IO 0x10
++#define TYPE_SBY_OVR_OUTVAL 0x11
++#define TYPE_SBY_OVR_INVAL 0x12
++#define TYPE_SBY_OVR_OUTDIR 0x13
++#define TYPE_SBY_OVR_INDIR 0x14
++#define TYPE_SBY_PUPD_STATE 0x15
++#define TYPE_SBY_OD_DIS 0x16
++#define TYPE_MAX 0x17
++
++struct gpio_control {
++ unsigned type, num;
++ char **pininfo;
++ u32 reg, invert;
++ u32 shift, rshift;
++ u32 mask;
++ int (*get)(struct gpio_control *control, void *private_data,
++ unsigned gpio);
++ int (*set)(struct gpio_control *control, void *private_data,
++ unsigned gpio, unsigned int num);
++};
++
++struct gpio_debug_ops {
++ unsigned int (*get_conf_reg)(struct gpio_debug *debug, unsigned gpio);
++ void (*set_conf_reg)(struct gpio_debug *debug, unsigned gpio,
++ unsigned int value);
++ char **(*get_avl_pininfo)(struct gpio_debug *debug, unsigned gpio,
++ unsigned int type, unsigned *num);
++ char *(*get_cul_pininfo)(struct gpio_debug *debug, unsigned gpio,
++ unsigned int type);
++ void (*set_pininfo)(struct gpio_debug *debug, unsigned gpio,
++ unsigned int type, const char *info);
++ int (*get_register_msg)(char **buf, unsigned long *size);
++};
++
++struct gpio_debug {
++ unsigned long typebit[BITS_TO_LONGS(TYPE_MAX)];
++ struct gpio_chip *chip;
++ struct gpio_debug_ops *ops;
++ unsigned long irq_count[ARCH_NR_GPIOS];
++ unsigned long wakeup_count[ARCH_NR_GPIOS];
++ void *private_data;
++};
++
++#ifdef CONFIG_GPIODEBUG
++
++#define DEFINE_DEBUG_IRQ_CONUNT_INCREASE(gpio) (debug->irq_count[gpio]++)
++
++struct gpio_control *find_gpio_control(struct gpio_control *control, int num,
++ unsigned type);
++int find_pininfo_num(struct gpio_control *control, const char *info);
++
++struct gpio_debug *gpio_debug_alloc(void);
++void gpio_debug_remove(struct gpio_debug *debug);
++int gpio_debug_register(struct gpio_debug *debug);
++#else
++
++#define DEFINE_DEBUG_IRQ_CONUNT_INCREASE(gpio)
++
++static inline struct gpio_control *find_gpio_control(
++ struct gpio_control *control, int num, unsigned type)
++{
++ return NULL;
++}
++static inline int find_pininfo_num(struct gpio_control *control,
++ const char *info)
++{
++ return 0;
++}
++static inline struct gpio_debug *gpio_debug_alloc(void)
++{
++ return NULL;
++}
++
++static inline void gpio_debug_remove(struct gpio_debug *debug)
++{
++ return NULL;
++}
++static inline int gpio_debug_register(struct gpio_debug *debug)
++{
++ return 0;
++}
++#endif
++#endif
+diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
+index c2534d6..2b09602 100644
+--- a/drivers/gpio/gpiolib.c
++++ b/drivers/gpio/gpiolib.c
+@@ -244,6 +244,9 @@ static DEFINE_MUTEX(sysfs_lock);
+
+ /*
+ * /sys/class/gpio/gpioN... only for GPIOs that are exported
++ * /pinmux
++ * * configures GPIO or alternate function
++ * * r/w as zero (normal GPIO) or alternate function number
+ * /direction
+ * * MAY BE OMITTED if kernel won't allow direction changes
+ * * is read/write as "in" or "out"
+@@ -262,6 +265,54 @@ static DEFINE_MUTEX(sysfs_lock);
+ * * also affects existing and subsequent "falling" and "rising"
+ * /edge configuration
+ */
++static ssize_t gpio_pinmux_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ const struct gpio_desc *desc = dev_get_drvdata(dev);
++ unsigned gpio = desc - gpio_desc;
++ struct gpio_chip *chip;
++ ssize_t status = -EINVAL;
++
++ mutex_lock(&sysfs_lock);
++
++ chip = desc->chip;
++
++ if (!test_bit(FLAG_EXPORT, &desc->flags))
++ status = -EIO;
++ else if (chip->get_pinmux != NULL)
++ status = sprintf(buf, "%d\n", chip->get_pinmux(gpio));
++
++ mutex_unlock(&sysfs_lock);
++ return status;
++}
++
++static ssize_t gpio_pinmux_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ const struct gpio_desc *desc = dev_get_drvdata(dev);
++ unsigned gpio = desc - gpio_desc;
++ ssize_t status = -EINVAL;
++ struct gpio_chip *chip;
++ long mux;
++
++ mutex_lock(&sysfs_lock);
++
++ chip = desc->chip;
++
++ if (!test_bit(FLAG_EXPORT, &desc->flags))
++ status = -EIO;
++ else if (chip->set_pinmux != NULL) {
++ status = kstrtol(buf, 0, &mux);
++ if (status == 0)
++ chip->set_pinmux(gpio, mux);
++ }
++
++ mutex_unlock(&sysfs_lock);
++ return status ? : size;
++}
++
++static DEVICE_ATTR(pinmux, 0644,
++ gpio_pinmux_show, gpio_pinmux_store);
+
+ static ssize_t gpio_direction_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+@@ -796,6 +847,10 @@ static int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
+ desc_to_gpio(desc));
+ if (IS_ERR(dev)) {
+ status = PTR_ERR(dev);
++ if (!status)
++ status = device_create_file(dev,
++ &dev_attr_pinmux);
++
+ goto fail_unlock;
+ }
+
+diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.h b/drivers/gpu/drm/gma500/mdfld_dsi_output.h
+index 36eb074..61cea74 100644
+--- a/drivers/gpu/drm/gma500/mdfld_dsi_output.h
++++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.h
+@@ -39,7 +39,7 @@
+ #include "psb_intel_reg.h"
+ #include "mdfld_output.h"
+
+-#include <asm/mrst.h>
++#include <asm/intel-mid.h>
+
+ #define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
+ #define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
+diff --git a/drivers/gpu/drm/gma500/oaktrail_device.c b/drivers/gpu/drm/gma500/oaktrail_device.c
+index 08747fd..7a9ce00 100644
+--- a/drivers/gpu/drm/gma500/oaktrail_device.c
++++ b/drivers/gpu/drm/gma500/oaktrail_device.c
+@@ -26,7 +26,7 @@
+ #include "psb_drv.h"
+ #include "psb_reg.h"
+ #include "psb_intel_reg.h"
+-#include <asm/mrst.h>
++#include <asm/intel-mid.h>
+ #include <asm/intel_scu_ipc.h>
+ #include "mid_bios.h"
+ #include "intel_bios.h"
+diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds.c b/drivers/gpu/drm/gma500/oaktrail_lvds.c
+index 325013a..d011e91 100644
+--- a/drivers/gpu/drm/gma500/oaktrail_lvds.c
++++ b/drivers/gpu/drm/gma500/oaktrail_lvds.c
+@@ -22,7 +22,7 @@
+
+ #include <linux/i2c.h>
+ #include <drm/drmP.h>
+-#include <asm/mrst.h>
++#include <asm/intel-mid.h>
+
+ #include "intel_bios.h"
+ #include "psb_drv.h"
+diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
+index df064e8..3899d25 100644
+--- a/drivers/hwmon/Kconfig
++++ b/drivers/hwmon/Kconfig
+@@ -504,6 +504,16 @@ config SENSORS_CORETEMP
+ sensor inside your CPU. Most of the family 6 CPUs
+ are supported. Check Documentation/hwmon/coretemp for details.
+
++config SENSORS_CORETEMP_INTERRUPT
++ tristate "Intel Core/Core2/Atom temperature sensor Interrupts"
++ depends on SENSORS_CORETEMP
++ help
++ If you say yes here you get support for interrupts when the
++ CPU temperature crosses the programmed threshold.
++
++ This is tested only for specific platforms(e.g Atom). If you
++ are not sure, say N here.
++
+ config SENSORS_IBMAEM
+ tristate "IBM Active Energy Manager temperature/power sensors and control"
+ select IPMI_SI
+@@ -822,6 +832,12 @@ config SENSORS_LM95245
+ This driver can also be built as a module. If so, the module
+ will be called lm95245.
+
++config MSIC_GPADC
++ tristate "MSIC GPADC driver for Intel Medfield platform"
++ depends on INTEL_SCU_IPC
++ help
++ Say Y here to enable MSIC GPADC driver on Intel Medfield Platform
++
+ config SENSORS_MAX1111
+ tristate "Maxim MAX1111 Serial 8-bit ADC chip and compatibles"
+ depends on SPI_MASTER
+diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
+index d17d3e6..4e1d647 100644
+--- a/drivers/hwmon/Makefile
++++ b/drivers/hwmon/Makefile
+@@ -140,6 +140,7 @@ obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o
+ obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o
+ obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o
+ obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
++obj-$(CONFIG_MSIC_GPADC) += intel_mid_gpadc.o
+
+ obj-$(CONFIG_PMBUS) += pmbus/
+
+diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
+index 658ce3a..7d091ab 100644
+--- a/drivers/hwmon/coretemp.c
++++ b/drivers/hwmon/coretemp.c
+@@ -37,6 +37,7 @@
+ #include <linux/smp.h>
+ #include <linux/moduleparam.h>
+ #include <asm/msr.h>
++#include <asm/mce.h>
+ #include <asm/processor.h>
+ #include <asm/cpu_device_id.h>
+
+@@ -52,9 +53,10 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius");
+
+ #define BASE_SYSFS_ATTR_NO 2 /* Sysfs Base attr no for coretemp */
+ #define NUM_REAL_CORES 32 /* Number of Real cores per cpu */
+-#define CORETEMP_NAME_LENGTH 17 /* String Length of attrs */
+-#define MAX_CORE_ATTRS 4 /* Maximum no of basic attrs */
+-#define TOTAL_ATTRS (MAX_CORE_ATTRS + 1)
++#define CORETEMP_NAME_LENGTH 33 /* String Length of attrs */
++#define MAX_CORE_ATTRS 5 /* Maximum no of basic attrs */
++#define MAX_THRESH_ATTRS 4 /* Maximum no of threshold attrs */
++#define TOTAL_ATTRS (MAX_CORE_ATTRS + MAX_THRESH_ATTRS)
+ #define MAX_CORE_DATA (NUM_REAL_CORES + BASE_SYSFS_ATTR_NO)
+
+ #define TO_PHYS_ID(cpu) (cpu_data(cpu).phys_proc_id)
+@@ -75,6 +77,8 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius");
+ * This value is passed as "id" field to rdmsr/wrmsr functions.
+ * @status_reg: One of IA32_THERM_STATUS or IA32_PACKAGE_THERM_STATUS,
+ * from where the temperature values should be read.
++ * @intrpt_reg: One of IA32_THERM_INTERRUPT or IA32_PACKAGE_THERM_INTERRUPT,
++ * from where the thresholds are read.
+ * @attr_size: Total number of pre-core attrs displayed in the sysfs.
+ * @is_pkg_data: If this is 1, the temp_data holds pkgtemp data.
+ * Otherwise, temp_data holds coretemp data.
+@@ -88,6 +92,7 @@ struct temp_data {
+ unsigned int cpu;
+ u32 cpu_core_id;
+ u32 status_reg;
++ u32 intrpt_reg;
+ int attr_size;
+ bool is_pkg_data;
+ bool valid;
+@@ -102,6 +107,7 @@ struct platform_data {
+ u16 phys_proc_id;
+ struct temp_data *core_data[MAX_CORE_DATA];
+ struct device_attribute name_attr;
++
+ };
+
+ struct pdev_entry {
+@@ -113,12 +119,119 @@ struct pdev_entry {
+ static LIST_HEAD(pdev_list);
+ static DEFINE_MUTEX(pdev_list_mutex);
+
++#ifdef CONFIG_SENSORS_CORETEMP_INTERRUPT
++static DEFINE_PER_CPU(struct delayed_work, core_threshold_work);
++#endif
+ static ssize_t show_name(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+ {
+ return sprintf(buf, "%s\n", DRVNAME);
+ }
+
++static ssize_t show_tx_triggered(struct device *dev,
++ struct device_attribute *devattr, char *buf,
++ u32 mask)
++{
++ u32 eax, edx;
++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++ struct platform_data *pdata = dev_get_drvdata(dev);
++ struct temp_data *tdata = pdata->core_data[attr->index];
++
++ rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx);
++
++ return sprintf(buf, "%d\n", !!(eax & mask));
++}
++
++static ssize_t show_t0_triggered(struct device *dev,
++ struct device_attribute *devattr, char *buf)
++{
++ return show_tx_triggered(dev, devattr, buf, THERM_STATUS_THRESHOLD0);
++}
++
++static ssize_t show_t1_triggered(struct device *dev,
++ struct device_attribute *devattr, char *buf)
++{
++ return show_tx_triggered(dev, devattr, buf, THERM_STATUS_THRESHOLD1);
++}
++
++static ssize_t show_tx(struct device *dev,
++ struct device_attribute *devattr, char *buf,
++ u32 mask, int shift)
++{
++ struct platform_data *pdata = dev_get_drvdata(dev);
++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++ struct temp_data *tdata = pdata->core_data[attr->index];
++ u32 eax, edx;
++ int t;
++
++ rdmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, &eax, &edx);
++ t = tdata->tjmax - ((eax & mask) >> shift) * 1000;
++ return sprintf(buf, "%d\n", t);
++}
++
++static ssize_t store_tx(struct device *dev,
++ struct device_attribute *devattr,
++ const char *buf, size_t count,
++ u32 mask, int shift)
++{
++ struct platform_data *pdata = dev_get_drvdata(dev);
++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
++ struct temp_data *tdata = pdata->core_data[attr->index];
++ u32 eax, edx;
++ unsigned long val;
++ int diff;
++
++ if (kstrtoul(buf, 10, &val))
++ return -EINVAL;
++
++ /*
++ * Thermal threshold mask is 7 bits wide. Values are entered in terms
++ * of milli degree celsius. Hence don't accept val > (127 * 1000)
++ */
++ if (val > tdata->tjmax || val > 127000)
++ return -EINVAL;
++
++ diff = (tdata->tjmax - val) / 1000;
++
++ mutex_lock(&tdata->update_lock);
++ rdmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, &eax, &edx);
++ eax = (eax & ~mask) | (diff << shift);
++ wrmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, eax, edx);
++ mutex_unlock(&tdata->update_lock);
++
++ return count;
++}
++
++static ssize_t show_t0(struct device *dev,
++ struct device_attribute *devattr, char *buf)
++{
++ return show_tx(dev, devattr, buf, THERM_MASK_THRESHOLD0,
++ THERM_SHIFT_THRESHOLD0);
++}
++
++static ssize_t store_t0(struct device *dev,
++ struct device_attribute *devattr,
++ const char *buf, size_t count)
++{
++ return store_tx(dev, devattr, buf, count, THERM_MASK_THRESHOLD0,
++ THERM_SHIFT_THRESHOLD0);
++}
++
++static ssize_t show_t1(struct device *dev,
++ struct device_attribute *devattr, char *buf)
++{
++ return show_tx(dev, devattr, buf, THERM_MASK_THRESHOLD1,
++ THERM_SHIFT_THRESHOLD1);
++}
++
++static ssize_t store_t1(struct device *dev,
++ struct device_attribute *devattr,
++ const char *buf, size_t count)
++{
++ return store_tx(dev, devattr, buf, count, THERM_MASK_THRESHOLD1,
++ THERM_SHIFT_THRESHOLD1);
++}
++
+ static ssize_t show_label(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+ {
+@@ -187,6 +300,7 @@ static ssize_t show_temp(struct device *dev,
+ }
+
+ mutex_unlock(&tdata->update_lock);
++
+ return tdata->valid ? sprintf(buf, "%d\n", tdata->temp) : -EAGAIN;
+ }
+
+@@ -198,7 +312,7 @@ struct tjmax {
+ static const struct tjmax __cpuinitconst tjmax_table[] = {
+ { "CPU 230", 100000 }, /* Model 0x1c, stepping 2 */
+ { "CPU 330", 125000 }, /* Model 0x1c, stepping 2 */
+- { "CPU CE4110", 110000 }, /* Model 0x1c, stepping 10 Sodaville */
++ { "CPU CE4110", 110000 }, /* Model 0x1c, stepping 10 */
+ { "CPU CE4150", 110000 }, /* Model 0x1c, stepping 10 */
+ { "CPU CE4170", 110000 }, /* Model 0x1c, stepping 10 */
+ };
+@@ -212,7 +326,7 @@ struct tjmax_model {
+ #define ANY 0xff
+
+ static const struct tjmax_model __cpuinitconst tjmax_model_table[] = {
+- { 0x1c, 10, 100000 }, /* D4xx, K4xx, N4xx, D5xx, K5xx, N5xx */
++ { 0x1c, 10, 100000 }, /* D4xx, N4xx, D5xx, N5xx */
+ { 0x1c, ANY, 90000 }, /* Z5xx, N2xx, possibly others
+ * Note: Also matches 230 and 330,
+ * which are covered by tjmax_table
+@@ -222,7 +336,7 @@ static const struct tjmax_model __cpuinitconst tjmax_model_table[] = {
+ * is undetectable by software
+ */
+ { 0x27, ANY, 90000 }, /* Atom Medfield (Z2460) */
+- { 0x35, ANY, 90000 }, /* Atom Clover Trail/Cloverview (Z2760) */
++ { 0x35, ANY, 90000 }, /* Atom Clovertrail */
+ { 0x36, ANY, 100000 }, /* Atom Cedar Trail/Cedarview (N2xxx, D2xxx) */
+ };
+
+@@ -357,6 +471,168 @@ static int __cpuinit get_tjmax(struct cpuinfo_x86 *c, u32 id,
+ return adjust_tjmax(c, id, dev);
+ }
+
++static struct platform_device *coretemp_get_pdev(unsigned int cpu)
++{
++ u16 phys_proc_id = TO_PHYS_ID(cpu);
++ struct pdev_entry *p;
++
++ mutex_lock(&pdev_list_mutex);
++
++ list_for_each_entry(p, &pdev_list, list)
++ if (p->phys_proc_id == phys_proc_id) {
++ mutex_unlock(&pdev_list_mutex);
++ return p->pdev;
++ }
++
++ mutex_unlock(&pdev_list_mutex);
++ return NULL;
++}
++
++#ifdef CONFIG_SENSORS_CORETEMP_INTERRUPT
++/* Interrupt Handler for Core Threshold Events */
++static int coretemp_interrupt(__u64 msr_val)
++{
++ unsigned int cpu = smp_processor_id();
++
++ schedule_delayed_work_on(cpu, &per_cpu(core_threshold_work, cpu), 0);
++ return 0;
++}
++
++static void core_threshold_work_fn(struct work_struct *work)
++{
++ u32 eax, edx;
++ int thresh, event, t0, t1, temp;
++ char *thermal_event[5];
++ bool notify = false;
++ unsigned int cpu = smp_processor_id();
++ int indx = TO_ATTR_NO(cpu);
++ struct platform_device *pdev = coretemp_get_pdev(cpu);
++ struct platform_data *pdata = platform_get_drvdata(pdev);
++ struct temp_data *tdata = pdata->core_data[indx];
++
++ if (!tdata) {
++ pr_err("Could not retrieve temp_data\n");
++ return;
++ }
++
++ rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &eax, &edx);
++ if (eax & THERM_LOG_THRESHOLD0) {
++ thresh = 0;
++ event = !!(eax & THERM_STATUS_THRESHOLD0);
++
++ /* Reset the Threshold0 interrupt */
++ eax = eax & ~THERM_LOG_THRESHOLD0;
++ wrmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, eax, edx);
++
++ /* Notify only when we go below the lower threshold */
++ if (event != 1)
++ notify = true;
++
++ } else if (eax & THERM_LOG_THRESHOLD1) {
++ thresh = 1;
++ event = !!(eax & THERM_STATUS_THRESHOLD1);
++
++ /* Reset the Threshold1 interrupt */
++ eax = eax & ~THERM_LOG_THRESHOLD1;
++ wrmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, eax, edx);
++
++ /* Notify only when we go above the upper threshold */
++ if (event != 0)
++ notify = true;
++ }
++
++ /*
++ * Read the current Temperature and send it to user land;
++ * so that the user space can avoid a sysfs read.
++ */
++ temp = tdata->tjmax - ((eax >> 16) & 0x7f) * 1000;
++
++ /* Read the threshold registers (only) to print threshold values. */
++ rdmsr_on_cpu(cpu, MSR_IA32_THERM_INTERRUPT, &eax, &edx);
++ t0 = tdata->tjmax - ((eax & THERM_MASK_THRESHOLD0) >> THERM_SHIFT_THRESHOLD0) * 1000;
++ t1 = tdata->tjmax - ((eax & THERM_MASK_THRESHOLD1) >> THERM_SHIFT_THRESHOLD1) * 1000;
++
++
++ if (!notify) {
++ pr_debug("Thermal Event: Sensor: Core %u, cur_temp: %d,\
++ event: %d, level: %d, t0: %d, t1: %d\n",
++ tdata->cpu_core_id, temp, event, thresh, t0, t1);
++ return;
++ } else {
++ pr_info("Thermal Event: Sensor: Core %u, cur_temp: %d,\
++ event: %d, level: %d, t0: %d, t1: %d\n",
++ tdata->cpu_core_id, temp, event, thresh, t0, t1);
++ }
++
++ thermal_event[0] = kasprintf(GFP_KERNEL, "NAME=Core %u",
++ tdata->cpu_core_id);
++ thermal_event[1] = kasprintf(GFP_KERNEL, "TEMP=%d", temp);
++ thermal_event[2] = kasprintf(GFP_KERNEL, "EVENT=%d", event);
++ thermal_event[3] = kasprintf(GFP_KERNEL, "LEVEL=%d", thresh);
++ thermal_event[4] = NULL;
++
++ kobject_uevent_env(&pdev->dev.kobj, KOBJ_CHANGE, thermal_event);
++
++ kfree(thermal_event[3]);
++ kfree(thermal_event[2]);
++ kfree(thermal_event[1]);
++ kfree(thermal_event[0]);
++}
++
++static void configure_apic(void *info)
++{
++ u32 l;
++ int *flag = (int *)info;
++
++ l = apic_read(APIC_LVTTHMR);
++
++ if (*flag) /* Non-Zero flag Masks the APIC */
++ apic_write(APIC_LVTTHMR, l | APIC_LVT_MASKED);
++ else /* Zero flag UnMasks the APIC */
++ apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
++}
++
++static int config_thresh_intrpt(struct temp_data *data, int enable)
++{
++ u32 eax, edx;
++ unsigned int cpu = data->cpu;
++ int flag = 1; /* Non-Zero Flag masks the apic */
++
++ smp_call_function_single(cpu, &configure_apic, &flag, 1);
++
++ rdmsr_on_cpu(cpu, MSR_IA32_THERM_INTERRUPT, &eax, &edx);
++
++ if (enable) {
++ INIT_DELAYED_WORK(&per_cpu(core_threshold_work, cpu),
++ core_threshold_work_fn);
++
++ eax |= (THERM_INT_THRESHOLD0_ENABLE |
++ THERM_INT_THRESHOLD1_ENABLE);
++ platform_thermal_notify = coretemp_interrupt;
++
++ pr_info("Enabled Aux0/Aux1 interrupts for coretemp\n");
++ } else {
++ eax &= (~(THERM_INT_THRESHOLD0_ENABLE |
++ THERM_INT_THRESHOLD1_ENABLE));
++ platform_thermal_notify = NULL;
++
++ cancel_delayed_work_sync(&per_cpu(core_threshold_work, cpu));
++ }
++
++ wrmsr_on_cpu(cpu, MSR_IA32_THERM_INTERRUPT, eax, edx);
++
++ flag = 0; /* Flag should be zero to unmask the apic */
++ smp_call_function_single(cpu, &configure_apic, &flag, 1);
++
++ return 0;
++}
++#else
++static inline int config_thresh_intrpt(struct temp_data *data, int enable)
++{
++ return 0;
++}
++#endif
++
+ static int create_name_attr(struct platform_data *pdata,
+ struct device *dev)
+ {
+@@ -368,24 +644,37 @@ static int create_name_attr(struct platform_data *pdata,
+ }
+
+ static int __cpuinit create_core_attrs(struct temp_data *tdata,
+- struct device *dev, int attr_no)
++ struct device *dev, int attr_no, bool have_ttarget)
+ {
+ int err, i;
+ static ssize_t (*const rd_ptr[TOTAL_ATTRS]) (struct device *dev,
+ struct device_attribute *devattr, char *buf) = {
+ show_label, show_crit_alarm, show_temp, show_tjmax,
+- show_ttarget };
++ show_ttarget, show_t0, show_t0_triggered,
++ show_t1, show_t1_triggered };
++ static ssize_t (*rw_ptr[TOTAL_ATTRS]) (struct device *dev,
++ struct device_attribute *devattr, const char *buf,
++ size_t count) = { NULL, NULL, NULL, NULL, NULL,
++ store_t0, NULL, store_t1, NULL };
+ static const char *const names[TOTAL_ATTRS] = {
+ "temp%d_label", "temp%d_crit_alarm",
+ "temp%d_input", "temp%d_crit",
+- "temp%d_max" };
++ "temp%d_max",
++ "temp%d_threshold1",
++ "temp%d_threshold1_triggered",
++ "temp%d_threshold2",
++ "temp%d_threshold2_triggered" };
+
+ for (i = 0; i < tdata->attr_size; i++) {
+- snprintf(tdata->attr_name[i], CORETEMP_NAME_LENGTH, names[i],
+- attr_no);
++ snprintf(tdata->attr_name[i], sizeof(tdata->attr_name[i]),
++ names[i], attr_no);
+ sysfs_attr_init(&tdata->sd_attrs[i].dev_attr.attr);
+ tdata->sd_attrs[i].dev_attr.attr.name = tdata->attr_name[i];
+ tdata->sd_attrs[i].dev_attr.attr.mode = S_IRUGO;
++ if (rw_ptr[i]) {
++ tdata->sd_attrs[i].dev_attr.attr.mode |= S_IWUSR;
++ tdata->sd_attrs[i].dev_attr.store = rw_ptr[i];
++ }
+ tdata->sd_attrs[i].dev_attr.show = rd_ptr[i];
+ tdata->sd_attrs[i].index = attr_no;
+ err = device_create_file(dev, &tdata->sd_attrs[i].dev_attr);
+@@ -395,8 +684,11 @@ static int __cpuinit create_core_attrs(struct temp_data *tdata,
+ return 0;
+
+ exit_free:
+- while (--i >= 0)
++ while (--i >= 0) {
++ if (!tdata->sd_attrs[i].dev_attr.attr.name)
++ continue;
+ device_remove_file(dev, &tdata->sd_attrs[i].dev_attr);
++ }
+ return err;
+ }
+
+@@ -411,29 +703,13 @@ static int __cpuinit chk_ucode_version(unsigned int cpu)
+ * fixed for stepping D0 (6EC).
+ */
+ if (c->x86_model == 0xe && c->x86_mask < 0xc && c->microcode < 0x39) {
+- pr_err("Errata AE18 not fixed, update BIOS or microcode of the CPU!\n");
++ pr_err("Errata AE18 not fixed, update BIOS or "
++ "microcode of the CPU!\n");
+ return -ENODEV;
+ }
+ return 0;
+ }
+
+-static struct platform_device __cpuinit *coretemp_get_pdev(unsigned int cpu)
+-{
+- u16 phys_proc_id = TO_PHYS_ID(cpu);
+- struct pdev_entry *p;
+-
+- mutex_lock(&pdev_list_mutex);
+-
+- list_for_each_entry(p, &pdev_list, list)
+- if (p->phys_proc_id == phys_proc_id) {
+- mutex_unlock(&pdev_list_mutex);
+- return p->pdev;
+- }
+-
+- mutex_unlock(&pdev_list_mutex);
+- return NULL;
+-}
+-
+ static struct temp_data __cpuinit *init_temp_data(unsigned int cpu,
+ int pkg_flag)
+ {
+@@ -445,6 +721,8 @@ static struct temp_data __cpuinit *init_temp_data(unsigned int cpu,
+
+ tdata->status_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_STATUS :
+ MSR_IA32_THERM_STATUS;
++ tdata->intrpt_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_INTERRUPT :
++ MSR_IA32_THERM_INTERRUPT;
+ tdata->is_pkg_data = pkg_flag;
+ tdata->cpu = cpu;
+ tdata->cpu_core_id = TO_CORE_ID(cpu);
+@@ -461,6 +739,7 @@ static int __cpuinit create_core_data(struct platform_device *pdev,
+ struct cpuinfo_x86 *c = &cpu_data(cpu);
+ u32 eax, edx;
+ int err, attr_no;
++ bool have_ttarget = false;
+
+ /*
+ * Find attr number for sysfs:
+@@ -506,17 +785,28 @@ static int __cpuinit create_core_data(struct platform_device *pdev,
+ if (!err) {
+ tdata->ttarget
+ = tdata->tjmax - ((eax >> 8) & 0xff) * 1000;
+- tdata->attr_size++;
++ have_ttarget = true;
+ }
+ }
+
++ /*
++ * Test if we can access the intrpt register. If so, increase
++ * 'size' enough to support t0 and t1 attributes.
++ */
++ err = rdmsr_safe_on_cpu(cpu, tdata->intrpt_reg, &eax, &edx);
++ if (!err)
++ tdata->attr_size += MAX_THRESH_ATTRS;
++
+ pdata->core_data[attr_no] = tdata;
+
+ /* Create sysfs interfaces */
+- err = create_core_attrs(tdata, &pdev->dev, attr_no);
++ err = create_core_attrs(tdata, &pdev->dev, attr_no, have_ttarget);
+ if (err)
+ goto exit_free;
+
++ /* Enable threshold interrupt support */
++ config_thresh_intrpt(tdata, 1);
++
+ return 0;
+ exit_free:
+ pdata->core_data[attr_no] = NULL;
+@@ -544,8 +834,14 @@ static void coretemp_remove_core(struct platform_data *pdata,
+ struct temp_data *tdata = pdata->core_data[indx];
+
+ /* Remove the sysfs attributes */
+- for (i = 0; i < tdata->attr_size; i++)
++ for (i = 0; i < tdata->attr_size; i++) {
++ if (!tdata->sd_attrs[i].dev_attr.attr.name)
++ continue;
+ device_remove_file(dev, &tdata->sd_attrs[i].dev_attr);
++ }
++
++ /* Enable threshold interrupt support */
++ config_thresh_intrpt(tdata, 0);
+
+ kfree(pdata->core_data[indx]);
+ pdata->core_data[indx] = NULL;
+diff --git a/drivers/hwmon/intel_mid_gpadc.c b/drivers/hwmon/intel_mid_gpadc.c
+new file mode 100644
+index 0000000..f4d0d2f
+--- /dev/null
++++ b/drivers/hwmon/intel_mid_gpadc.c
+@@ -0,0 +1,1212 @@
++/*
++ * intel_mdf_msic_gpadc.c - Intel Medfield MSIC GPADC Driver
++ *
++ * Copyright (C) 2010 Intel Corporation
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * 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; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ * Author: Jenny TC <jenny.tc@intel.com>
++ * Author: Bin Yang <bin.yang@intel.com>
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/io.h>
++#include <linux/interrupt.h>
++#include <linux/device.h>
++#include <linux/delay.h>
++#include <linux/sched.h>
++#include <linux/pm_qos.h>
++#include <linux/intel_mid_pm.h>
++#include <linux/workqueue.h>
++#include <linux/fs.h>
++#include <linux/rpmsg.h>
++
++#include <asm/intel_scu_pmic.h>
++#include <asm/intel_mid_rpmsg.h>
++#include <asm/intel_mid_remoteproc.h>
++#include <asm/intel_mid_gpadc.h>
++
++#define VAUDACNT 0x0DB
++#define MCCINT 0x013
++#define IRQLVL1 0x002
++#define IRQLVL1MSK 0x021
++#define ADC1INT 0x003
++#define ADC1ADDR0 0x1C5
++#define ADC1SNS0H 0x1D4
++#define ADC1OFFSETH 0x1C3
++#define ADC1OFFSETL 0x1C4
++#define ADC1CNTL1 0x1C0
++#define ADC1CNTL2 0x1C1
++#define ADC1CNTL3 0x1C2
++#define ADC1BV0H 0x1F2
++#define ADC1BI0H 0x1FA
++
++#ifdef CONFIG_BOARD_CTP
++#define EEPROMCAL1 0x309
++#define EEPROMCAL2 0x30A
++#else
++#define EEPROMCAL1 0x317
++#define EEPROMCAL2 0x318
++#endif
++
++#define MCCINT_MCCCAL (1 << 1)
++#define MCCINT_MOVERFLOW (1 << 0)
++
++#define IRQLVL1MSK_ADCM (1 << 1)
++
++#define ADC1CNTL1_AD1OFFSETEN (1 << 6)
++#define ADC1CNTL1_AD1CALEN (1 << 5)
++#define ADC1CNTL1_ADEN (1 << 4)
++#define ADC1CNTL1_ADSTRT (1 << 3)
++#define ADC1CNTL1_ADSLP 7
++#define ADC1CNTL1_ADSLP_DEF 1
++
++#define ADC1INT_ADC1CAL (1 << 2)
++#define ADC1INT_GSM (1 << 1)
++#define ADC1INT_RND (1 << 0)
++
++#define ADC1CNTL3_ADCTHERM (1 << 2)
++#define ADC1CNTL3_GSMDATARD (1 << 1)
++#define ADC1CNTL3_RRDATARD (1 << 0)
++
++#define ADC1CNTL2_DEF 0x7
++#define ADC1CNTL2_ADCGSMEN (1 << 7)
++
++#define MSIC_STOPCH (1 << 4)
++
++#define GPADC_CH_MAX 15
++
++#define GPADC_POWERON_DELAY 1
++
++#define SAMPLE_CH_MAX 2
++
++static void *adc_handle[GPADC_CH_MAX] = {};
++static int sample_result[GPADC_CH_MAX][SAMPLE_CH_MAX];
++static struct completion gsmadc_complete;
++static int vol_val;
++static int cur_val;
++
++struct gpadc_info {
++ int initialized;
++ int depth;
++
++ struct workqueue_struct *workq;
++ wait_queue_head_t trimming_wait;
++ struct work_struct trimming_work;
++ struct work_struct gsmpulse_work;
++ int trimming_start;
++
++ /* This mutex protects gpadc sample/config from concurrent conflict.
++ Any function, which does the sample or config, needs to
++ hold this lock.
++ If it is locked, it also means the gpadc is in active mode.
++ GSM mode sample does not need to hold this lock. It can be used with
++ normal sample concurrent without poweron.
++ */
++ struct mutex lock;
++ struct device *dev;
++ int irq;
++ void __iomem *intr;
++ int irq_status;
++
++ int vzse;
++ int vge;
++ int izse;
++ int ige;
++ int addr_mask;
++
++ wait_queue_head_t wait;
++ int rnd_done;
++ int conv_done;
++ int gsmpulse_done;
++
++ struct pm_qos_request pm_qos_request;
++ void (*gsmadc_notify)(int vol, int cur);
++
++ int pmic_ipc_status;
++};
++
++struct gpadc_request {
++ int count;
++ int vref;
++ int ch[GPADC_CH_MAX];
++ int addr[GPADC_CH_MAX];
++};
++
++static struct gpadc_info gpadc_info;
++
++static inline int gpadc_clear_bits(u16 addr, u8 mask)
++{
++ struct gpadc_info *mgi = &gpadc_info;
++ int ret;
++
++ if (mgi->pmic_ipc_status)
++ return -EINVAL;
++
++ ret = intel_scu_ipc_update_register(addr, 0, mask);
++ if (ret)
++ mgi->pmic_ipc_status = -EINVAL;
++
++ return ret;
++}
++
++static inline int gpadc_set_bits(u16 addr, u8 mask)
++{
++ struct gpadc_info *mgi = &gpadc_info;
++ int ret;
++
++ if (mgi->pmic_ipc_status)
++ return -EINVAL;
++
++ ret = intel_scu_ipc_update_register(addr, 0xff, mask);
++ if (ret)
++ mgi->pmic_ipc_status = -EINVAL;
++
++ return ret;
++}
++
++static inline int gpadc_write(u16 addr, u8 data)
++{
++ struct gpadc_info *mgi = &gpadc_info;
++ int ret;
++
++ if (mgi->pmic_ipc_status)
++ return -EINVAL;
++
++ ret = intel_scu_ipc_iowrite8(addr, data);
++ if (ret)
++ mgi->pmic_ipc_status = -EINVAL;
++
++ return ret;
++}
++
++static inline int gpadc_read(u16 addr, u8 *data)
++{
++ struct gpadc_info *mgi = &gpadc_info;
++ int ret;
++
++ if (mgi->pmic_ipc_status)
++ return -EINVAL;
++
++ ret = intel_scu_ipc_ioread8(addr, data);
++ if (ret)
++ mgi->pmic_ipc_status = -EINVAL;
++
++ return ret;
++}
++
++static void gpadc_dump(struct gpadc_info *mgi)
++{
++ u8 data;
++ int i;
++
++ dev_err(mgi->dev, "pmic ipc status: %s\n",
++ mgi->pmic_ipc_status ? "bad" : "good");
++ gpadc_read(VAUDACNT, &data);
++ dev_err(mgi->dev, "VAUDACNT: 0x%x\n", data);
++ gpadc_read(IRQLVL1MSK, &data);
++ dev_err(mgi->dev, "IRQLVL1MSK: 0x%x\n", data);
++ gpadc_read(IRQLVL1, &data);
++ dev_err(mgi->dev, "IRQLVL1: 0x%x\n", data);
++ gpadc_read(ADC1INT, &data);
++ dev_err(mgi->dev, "ADC1INT: 0x%x\n", data);
++ gpadc_read(ADC1CNTL1, &data);
++ dev_err(mgi->dev, "ADC1CNTL1: 0x%x\n", data);
++ gpadc_read(ADC1CNTL2, &data);
++ dev_err(mgi->dev, "ADC1CNTL2: 0x%x\n", data);
++ gpadc_read(ADC1CNTL3, &data);
++ dev_err(mgi->dev, "ADC1CNTL3: 0x%x\n", data);
++ for (i = 0; i < GPADC_CH_MAX; i++) {
++ gpadc_read(ADC1ADDR0+i, &data);
++ dev_err(mgi->dev, "ADC1ADDR[%d]: 0x%x\n", i, data);
++ }
++}
++
++static int gpadc_poweron(struct gpadc_info *mgi, int vref)
++{
++ if (!mgi->depth++) {
++ if (gpadc_set_bits(ADC1CNTL1, ADC1CNTL1_ADEN) != 0)
++ return -EIO;
++ msleep(GPADC_POWERON_DELAY);
++ }
++ if (vref) {
++ if (gpadc_set_bits(ADC1CNTL3, ADC1CNTL3_ADCTHERM) != 0)
++ return -EIO;
++ msleep(GPADC_POWERON_DELAY);
++ }
++ return 0;
++}
++
++static int gpadc_poweroff(struct gpadc_info *mgi)
++{
++ if (!--mgi->depth) {
++ if (gpadc_clear_bits(ADC1CNTL1, ADC1CNTL1_ADEN) != 0)
++ return -EIO;
++ if (gpadc_clear_bits(ADC1CNTL3, ADC1CNTL3_ADCTHERM) != 0)
++ return -EIO;
++ }
++ return 0;
++}
++
++static int gpadc_calib(int rc, int zse, int ge)
++{
++ struct gpadc_info *mgi = &gpadc_info;
++ int tmp;
++
++ if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_CLOVERVIEW) {
++ if (ge == 0) {
++ dev_err(mgi->dev, "calibration divider is zero\n");
++ return 0;
++ }
++
++ /**
++ * For Cloverview, using the calibration data, we have the
++ * voltage and current after calibration correction as below:
++ * V_CAL_CODE = 213.33 * (V_RAW_CODE - VZSE) / VGE
++ * I_CAL_CODE = 213.33 * (I_RAW_CODE - IZSE) / IGE
++ */
++
++ /* note: the input zse is multipled by 10,
++ * input ge is multipled by 100, need to handle them here
++ */
++ tmp = 21333 * (10 * rc - zse) / ge;
++ } else {
++ /**
++ * For Medfield, using the calibration data, we have the
++ * voltage and current after calibration correction as below:
++ * V_CAL_CODE = V_RAW_CODE - (VZSE + (VGE)* VRAW_CODE/1023)
++ * I_CAL_CODE = I_RAW_CODE - (IZSE + (IGE)* IRAW_CODE/1023)
++ */
++ tmp = (10230 * rc - (10230 * zse + 10 * ge * rc)) / 1023;
++ }
++
++ /* tmp is 10 times of result value,
++ * and it's used to obtain result's closest integer
++ */
++ return DIV_ROUND_CLOSEST(tmp, 10);
++
++}
++
++static void gpadc_calc_zse_ge(struct gpadc_info *mgi)
++{
++ u8 data;
++ int fse, zse, fse_sign, zse_sign, ge, ge_sign;
++
++ if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_CLOVERVIEW) {
++ gpadc_read(EEPROMCAL1, &data);
++ zse = data & 0xf;
++ ge = (data >> 4) & 0xf;
++ gpadc_read(EEPROMCAL2, &data);
++ zse_sign = (data & (1 << 6)) ? -1 : 1;
++ ge_sign = (data & (1 << 7)) ? -1 : 1;
++ zse *= zse_sign;
++ ge *= ge_sign;
++ /* vzse divided by 2 may cause 0.5, x10 to avoid float */
++ mgi->vzse = mgi->izse = zse * 10 / 2;
++ /* vge multiple 100 to avoid float */
++ mgi->vge = mgi->ige = 21333 - (ge * 100 / 4);
++ } else {
++ /* voltage trim */
++ gpadc_read(EEPROMCAL1, &data);
++ zse = (data & 0xf)/2;
++ fse = ((data >> 4) & 0xf)/2;
++ gpadc_read(EEPROMCAL2, &data);
++ zse_sign = (data & (1 << 6)) ? 1 : 0;
++ fse_sign = (data & (1 << 7)) ? 1 : 0;
++ zse *= zse_sign;
++ fse *= fse_sign;
++ mgi->vzse = zse;
++ mgi->vge = fse - zse;
++
++ /* current trim */
++ fse = (data & 0xf)/2;
++ fse_sign = (data & (1 << 5)) ? 1 : 0;
++ fse = ~(fse_sign * fse) + 1;
++ gpadc_read(ADC1OFFSETH, &data);
++ zse = data << 2;
++ gpadc_read(ADC1OFFSETL, &data);
++ zse += data & 0x3;
++ mgi->izse = zse;
++ mgi->ige = fse + zse;
++ }
++}
++
++static void gpadc_trimming(struct work_struct *work)
++{
++ u8 data;
++ struct gpadc_info *mgi =
++ container_of(work, struct gpadc_info, trimming_work);
++
++ mutex_lock(&mgi->lock);
++ mgi->trimming_start = 1;
++ wake_up(&mgi->trimming_wait);
++ if (gpadc_poweron(mgi, 1)) {
++ dev_err(mgi->dev, "power on failed\n");
++ goto failed;
++ }
++ /* calibration */
++ gpadc_read(ADC1CNTL1, &data);
++ data &= ~ADC1CNTL1_AD1OFFSETEN;
++ data |= ADC1CNTL1_AD1CALEN;
++ gpadc_write(ADC1CNTL1, data);
++ gpadc_read(ADC1INT, &data);
++
++ /*workarround: no calib int */
++ msleep(300);
++ gpadc_set_bits(ADC1INT, ADC1INT_ADC1CAL);
++ gpadc_clear_bits(ADC1CNTL1, ADC1CNTL1_AD1CALEN);
++
++ gpadc_calc_zse_ge(mgi);
++
++ if (gpadc_poweroff(mgi)) {
++ dev_err(mgi->dev, "power off failed\n");
++ goto failed;
++ }
++
++failed:
++ mutex_unlock(&mgi->lock);
++}
++
++static irqreturn_t msic_gpadc_isr(int irq, void *data)
++{
++ struct gpadc_info *mgi = data;
++
++ if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_CLOVERVIEW)
++ mgi->irq_status = ADC1INT_RND;
++ else
++ mgi->irq_status = readl(mgi->intr) >> 8 & 0xff;
++
++ return IRQ_WAKE_THREAD;
++}
++
++static irqreturn_t msic_gpadc_irq(int irq, void *data)
++{
++ struct gpadc_info *mgi = data;
++
++ if (mgi->irq_status & ADC1INT_GSM) {
++ mgi->gsmpulse_done = 1;
++ queue_work(mgi->workq, &mgi->gsmpulse_work);
++ } else if (mgi->irq_status & ADC1INT_RND) {
++ mgi->rnd_done = 1;
++ wake_up(&mgi->wait);
++ } else if (mgi->irq_status & ADC1INT_ADC1CAL) {
++ mgi->conv_done = 1;
++ wake_up(&mgi->wait);
++ } else {
++ /* coulomb counter should be handled by firmware. Ignore it */
++ dev_dbg(mgi->dev, "coulomb counter is not support\n");
++ }
++ return IRQ_HANDLED;
++}
++
++static int alloc_channel_addr(struct gpadc_info *mgi, int ch)
++{
++ int i;
++ int addr = -EBUSY;
++ int last = 0;
++
++ for (i = 0; i < GPADC_CH_MAX; i++)
++ if (mgi->addr_mask & (1 << i))
++ last = i;
++
++ for (i = 0; i < GPADC_CH_MAX; i++) {
++ if (!(mgi->addr_mask & (1 << i))) {
++ addr = i;
++ mgi->addr_mask |= 1 << i;
++ if (addr > last) {
++ gpadc_clear_bits(ADC1ADDR0+last, MSIC_STOPCH);
++ gpadc_write(ADC1ADDR0+addr, ch|MSIC_STOPCH);
++ } else {
++ gpadc_write(ADC1ADDR0+addr, ch);
++ }
++ break;
++ }
++ }
++ return addr;
++}
++
++static void free_channel_addr(struct gpadc_info *mgi, int addr)
++{
++ int last = 0;
++ int i;
++
++ mgi->addr_mask &= ~(1 << addr);
++ for (i = 0; i < GPADC_CH_MAX; i++)
++ if (mgi->addr_mask & (1 << i))
++ last = i;
++ if (addr > last)
++ gpadc_set_bits(ADC1ADDR0+last, MSIC_STOPCH);
++}
++
++static void gpadc_gsmpulse_work(struct work_struct *work)
++{
++ int i;
++ u8 data;
++ int tmp;
++ int vol, cur;
++ struct gpadc_info *mgi =
++ container_of(work, struct gpadc_info, gsmpulse_work);
++
++ mutex_lock(&mgi->lock);
++ gpadc_set_bits(ADC1CNTL3, ADC1CNTL3_GSMDATARD);
++
++ vol = 0;
++ cur = 0;
++ for (i = 0; i < 4; i++) {
++ gpadc_read(ADC1BV0H + i * 2, &data);
++ tmp = data << 2;
++ gpadc_read(ADC1BV0H + i * 2 + 1, &data);
++ tmp += data & 0x3;
++ if (tmp > vol)
++ vol = tmp;
++
++ gpadc_read(ADC1BI0H + i * 2, &data);
++ tmp = data << 2;
++ gpadc_read(ADC1BI0H + i * 2 + 1, &data);
++ tmp += data & 0x3;
++ if (tmp > cur)
++ cur = tmp;
++ }
++
++ vol = gpadc_calib(vol, mgi->vzse, mgi->vge);
++ cur = gpadc_calib(cur, mgi->izse, mgi->ige);
++
++ gpadc_set_bits(ADC1INT, ADC1INT_GSM);
++ gpadc_clear_bits(ADC1CNTL3, ADC1CNTL3_GSMDATARD);
++ if (mgi->gsmadc_notify)
++ mgi->gsmadc_notify(vol, cur);
++ mutex_unlock(&mgi->lock);
++}
++
++/**
++ * intel_mid_gpadc_gsmpulse_register - power on gsm adc and register a callback
++ * @fn: callback function after gsm adc conversion is completed
++ *
++ * Returns 0 on success or an error code.
++ *
++ * This function may sleep.
++ */
++int intel_mid_gpadc_gsmpulse_register(void(*fn)(int vol, int cur))
++{
++ int ret = 0;
++ struct gpadc_info *mgi = &gpadc_info;
++
++ if (!mgi->initialized)
++ return -ENODEV;
++ mutex_lock(&mgi->lock);
++ if (!mgi->gsmadc_notify) {
++ gpadc_write(ADC1CNTL2, ADC1CNTL2_DEF);
++ gpadc_set_bits(ADC1CNTL2, ADC1CNTL2_ADCGSMEN);
++ mgi->gsmadc_notify = fn;
++ } else {
++ ret = -EBUSY;
++ }
++ mutex_unlock(&mgi->lock);
++ return ret;
++}
++EXPORT_SYMBOL(intel_mid_gpadc_gsmpulse_register);
++
++/**
++ * intel_mid_gpadc_gsmpulse_unregister - power off gsm adc and unregister
++ * the callback
++ * @fn: callback function after gsm adc conversion is completed
++ *
++ * Returns 0 on success or an error code.
++ *
++ * This function may sleep.
++ */
++int intel_mid_gpadc_gsmpulse_unregister(void(*fn)(int vol, int cur))
++{
++ int ret = 0;
++ struct gpadc_info *mgi = &gpadc_info;
++
++ if (!mgi->initialized)
++ return -ENODEV;
++ mutex_lock(&mgi->lock);
++ if (mgi->gsmadc_notify == fn) {
++ mgi->gsmadc_notify = NULL;
++ gpadc_clear_bits(ADC1CNTL2, ADC1CNTL2_ADCGSMEN);
++ }
++ mutex_unlock(&mgi->lock);
++ return ret;
++}
++EXPORT_SYMBOL(intel_mid_gpadc_gsmpulse_unregister);
++
++/**
++ * intel_mid_gpadc_sample - do gpadc sample.
++ * @handle: the gpadc handle
++ * @sample_count: do sample serveral times and get the average value.
++ * @...: sampling resulting arguments of all channels. refer to sscanf.
++ * caller should not access it before return.
++ *
++ * Returns 0 on success or an error code.
++ *
++ * This function may sleep.
++ */
++int intel_mid_gpadc_sample(void *handle, int sample_count, ...)
++{
++
++ struct gpadc_request *rq = handle;
++ struct gpadc_info *mgi = &gpadc_info;
++ int i;
++ u8 data;
++ int ret = 0;
++ int count;
++ int tmp;
++ int *val[GPADC_CH_MAX];
++ va_list args;
++
++ if (!mgi->initialized)
++ return -ENODEV;
++
++ mutex_lock(&mgi->lock);
++ mgi->pmic_ipc_status = 0;
++
++ va_start(args, sample_count);
++ for (i = 0; i < rq->count; i++) {
++ val[i] = va_arg(args, int*);
++ *val[i] = 0;
++ }
++ va_end(args);
++
++ pm_qos_add_request(&mgi->pm_qos_request,
++ PM_QOS_CPU_DMA_LATENCY, CSTATE_EXIT_LATENCY_S0i1-1);
++ gpadc_poweron(mgi, rq->vref);
++ gpadc_clear_bits(ADC1CNTL1, ADC1CNTL1_AD1OFFSETEN);
++ gpadc_read(ADC1CNTL1, &data);
++ data = (data & ~ADC1CNTL1_ADSLP) + ADC1CNTL1_ADSLP_DEF;
++ gpadc_write(ADC1CNTL1, data);
++ mgi->rnd_done = 0;
++ gpadc_set_bits(ADC1CNTL1, ADC1CNTL1_ADSTRT);
++ for (count = 0; count < sample_count; count++) {
++ if (wait_event_timeout(mgi->wait, mgi->rnd_done, HZ) == 0) {
++ gpadc_dump(mgi);
++ dev_err(mgi->dev, "sample timeout\n");
++ ret = -ETIMEDOUT;
++ goto fail;
++ }
++ gpadc_set_bits(ADC1CNTL3, ADC1CNTL3_RRDATARD);
++ for (i = 0; i < rq->count; ++i) {
++ tmp = 0;
++ gpadc_read(ADC1SNS0H + 2 * rq->addr[i], &data);
++ tmp += data << 2;
++ gpadc_read(ADC1SNS0H + 2 * rq->addr[i] + 1, &data);
++ tmp += data & 0x3;
++
++ if (rq->ch[i] & CH_NEED_VCALIB)
++ tmp = gpadc_calib(tmp, mgi->vzse, mgi->vge);
++ if (rq->ch[i] & CH_NEED_ICALIB)
++ tmp = gpadc_calib(tmp, mgi->izse, mgi->ige);
++
++ *val[i] += tmp;
++ }
++ gpadc_clear_bits(ADC1CNTL3, ADC1CNTL3_RRDATARD);
++ mgi->rnd_done = 0;
++ }
++
++ for (i = 0; i < rq->count; ++i)
++ *val[i] /= sample_count;
++
++fail:
++ gpadc_clear_bits(ADC1CNTL1, ADC1CNTL1_ADSTRT);
++ gpadc_poweroff(mgi);
++ pm_qos_remove_request(&mgi->pm_qos_request);
++
++ if (mgi->pmic_ipc_status) {
++ dev_err(mgi->dev, "sample broken\n");
++ ret = mgi->pmic_ipc_status;
++ }
++ mutex_unlock(&mgi->lock);
++ return ret;
++}
++EXPORT_SYMBOL(intel_mid_gpadc_sample);
++
++/**
++ * get_gpadc_sample() - get gpadc sample.
++ * @handle: the gpadc handle
++ * @sample_count: do sample serveral times and get the average value.
++ * @buffer: sampling resulting arguments of all channels.
++ *
++ * Returns 0 on success or an error code.
++ *
++ * This function may sleep.
++ */
++int get_gpadc_sample(void *handle, int sample_count, int *buffer)
++{
++
++ struct gpadc_request *rq = handle;
++ struct gpadc_info *mgi = &gpadc_info;
++ int i;
++ u8 data;
++ int ret = 0;
++ int count;
++ int tmp;
++
++ if (!mgi->initialized)
++ return -ENODEV;
++
++ mutex_lock(&mgi->lock);
++ mgi->pmic_ipc_status = 0;
++
++ for (i = 0; i < rq->count; i++)
++ buffer[i] = 0;
++
++ pm_qos_add_request(&mgi->pm_qos_request,
++ PM_QOS_CPU_DMA_LATENCY, CSTATE_EXIT_LATENCY_S0i1-1);
++ gpadc_poweron(mgi, rq->vref);
++ gpadc_clear_bits(ADC1CNTL1, ADC1CNTL1_AD1OFFSETEN);
++ gpadc_read(ADC1CNTL1, &data);
++ data = (data & ~ADC1CNTL1_ADSLP) + ADC1CNTL1_ADSLP_DEF;
++ gpadc_write(ADC1CNTL1, data);
++ mgi->rnd_done = 0;
++ gpadc_set_bits(ADC1CNTL1, ADC1CNTL1_ADSTRT);
++ for (count = 0; count < sample_count; count++) {
++ if (wait_event_timeout(mgi->wait, mgi->rnd_done, HZ) == 0) {
++ gpadc_dump(mgi);
++ dev_err(mgi->dev, "sample timeout\n");
++ ret = -ETIMEDOUT;
++ goto fail;
++ }
++ gpadc_set_bits(ADC1CNTL3, ADC1CNTL3_RRDATARD);
++ for (i = 0; i < rq->count; ++i) {
++ tmp = 0;
++ gpadc_read(ADC1SNS0H + 2 * rq->addr[i], &data);
++ tmp += data << 2;
++ gpadc_read(ADC1SNS0H + 2 * rq->addr[i] + 1, &data);
++ tmp += data & 0x3;
++
++ if (rq->ch[i] & CH_NEED_VCALIB)
++ tmp = gpadc_calib(tmp, mgi->vzse, mgi->vge);
++ if (rq->ch[i] & CH_NEED_ICALIB)
++ tmp = gpadc_calib(tmp, mgi->izse, mgi->ige);
++ buffer[i] += tmp;
++ }
++ gpadc_clear_bits(ADC1CNTL3, ADC1CNTL3_RRDATARD);
++ mgi->rnd_done = 0;
++ }
++
++ for (i = 0; i < rq->count; ++i)
++ buffer[i] /= sample_count;
++
++fail:
++ gpadc_clear_bits(ADC1CNTL1, ADC1CNTL1_ADSTRT);
++ gpadc_poweroff(mgi);
++ pm_qos_remove_request(&mgi->pm_qos_request);
++ if (mgi->pmic_ipc_status) {
++ dev_err(mgi->dev, "sample broken\n");
++ ret = mgi->pmic_ipc_status;
++ }
++ mutex_unlock(&mgi->lock);
++ return ret;
++}
++EXPORT_SYMBOL(get_gpadc_sample);
++
++/**
++ * intel_mid_gpadc_free - free gpadc
++ * @handle: the gpadc handle
++ *
++ * This function may sleep.
++ */
++void intel_mid_gpadc_free(void *handle)
++{
++ struct gpadc_request *rq = handle;
++ struct gpadc_info *mgi = &gpadc_info;
++ int i;
++
++ mutex_lock(&mgi->lock);
++ mgi->pmic_ipc_status = 0;
++ for (i = 0; i < rq->count; i++)
++ free_channel_addr(mgi, rq->addr[i]);
++
++ if (mgi->pmic_ipc_status)
++ dev_err(mgi->dev, "gpadc free broken\n");
++
++ mutex_unlock(&mgi->lock);
++ kfree(rq);
++}
++EXPORT_SYMBOL(intel_mid_gpadc_free);
++
++/**
++ * intel_mid_gpadc_alloc - allocate gpadc for channels
++ * @count: the count of channels
++ * @...: the channel parameters. (channel idx | flags)
++ * flags:
++ * CH_NEED_VCALIB it needs voltage calibration
++ * CH_NEED_ICALIB it needs current calibration
++ *
++ * Returns gpadc handle on success or NULL on fail.
++ *
++ * This function may sleep.
++ */
++void *intel_mid_gpadc_alloc(int count, ...)
++{
++ struct gpadc_request *rq;
++ struct gpadc_info *mgi = &gpadc_info;
++ va_list args;
++ int ch;
++ int i;
++
++ if (!mgi->initialized)
++ return NULL;
++
++ rq = kzalloc(sizeof(struct gpadc_request), GFP_KERNEL);
++ if (rq == NULL)
++ return NULL;
++
++ va_start(args, count);
++ mutex_lock(&mgi->lock);
++ mgi->pmic_ipc_status = 0;
++
++ rq->count = count;
++ for (i = 0; i < count; i++) {
++ ch = va_arg(args, int);
++ rq->ch[i] = ch;
++ if (ch & CH_NEED_VREF)
++ rq->vref = 1;
++ ch &= 0xf;
++ rq->addr[i] = alloc_channel_addr(mgi, ch);
++ if (rq->addr[i] < 0) {
++ dev_err(mgi->dev, "alloc addr failed\n");
++ while (i-- > 0)
++ free_channel_addr(mgi, rq->addr[i]);
++ kfree(rq);
++ rq = NULL;
++ break;
++ }
++ }
++ if (mgi->pmic_ipc_status)
++ dev_err(mgi->dev, "gpadc alloc broken\n");
++
++ mutex_unlock(&mgi->lock);
++ va_end(args);
++
++ return rq;
++}
++EXPORT_SYMBOL(intel_mid_gpadc_alloc);
++
++ /**
++ * gpadc_alloc_channels - allocate gpadc for channels
++ * @count: the count of channels
++ * @...: the channel parameters. (channel idx | flags)
++ * flags:
++ * CH_NEED_VCALIB it needs voltage calibration
++ * CH_NEED_ICALIB it needs current calibration
++ *
++ * Returns gpadc handle on success or NULL on fail.
++ *
++ * This function may sleep.
++ *
++ * TODO: Cleanup intel_mid_gpadc_alloc() once all its users
++ * are moved to gpadc_alloc_channels()
++ *
++ */
++
++void *gpadc_alloc_channels(int n, int *channel_info)
++{
++ struct gpadc_request *rq;
++ struct gpadc_info *mgi = &gpadc_info;
++ int ch;
++ int i;
++
++ if (!mgi->initialized)
++ return NULL;
++
++ rq = kzalloc(sizeof(struct gpadc_request), GFP_KERNEL);
++ if (rq == NULL)
++ return NULL;
++
++ mutex_lock(&mgi->lock);
++ mgi->pmic_ipc_status = 0;
++
++ rq->count = n;
++ for (i = 0; i < n; i++) {
++ ch = channel_info[i];
++ rq->ch[i] = ch;
++ if (ch & CH_NEED_VREF)
++ rq->vref = 1;
++ ch &= 0xf;
++ rq->addr[i] = alloc_channel_addr(mgi, ch);
++ if (rq->addr[i] < 0) {
++ dev_err(mgi->dev, "alloc addr failed\n");
++ while (i-- > 0)
++ free_channel_addr(mgi, rq->addr[i]);
++ kfree(rq);
++ rq = NULL;
++ break;
++ }
++ }
++ if (mgi->pmic_ipc_status)
++ dev_err(mgi->dev, "gpadc alloc broken\n");
++
++ mutex_unlock(&mgi->lock);
++
++ return rq;
++}
++EXPORT_SYMBOL(gpadc_alloc_channels);
++
++static ssize_t intel_mid_gpadc_store_alloc_channel(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t size)
++{
++ int val, hdn;
++ int ch[SAMPLE_CH_MAX];
++
++ val = sscanf(buf, "%d %x %x", &hdn, &ch[0], &ch[1]);
++
++ if (val < 2 || val > 3) {
++ dev_err(dev, "invalid number of arguments");
++ return -EINVAL;
++ }
++
++ if (hdn < 1 || hdn > GPADC_CH_MAX) {
++ dev_err(dev, "invalid handle value");
++ return -EINVAL;
++ }
++
++ if (adc_handle[hdn - 1]) {
++ dev_err(dev, "adc handle %d has been occupied", hdn);
++ return -EBUSY;
++ }
++
++ if (val == 2)
++ adc_handle[hdn - 1] = intel_mid_gpadc_alloc(1, ch[0]);
++ else
++ adc_handle[hdn - 1] = intel_mid_gpadc_alloc(2, ch[0], ch[1]);
++
++ if (!adc_handle[hdn - 1]) {
++ dev_err(dev, "allocating adc handle %d failed", hdn);
++ return -ENOMEM;
++ }
++
++ return size;
++}
++
++static ssize_t intel_mid_gpadc_store_free_channel(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t size)
++{
++ int hdn;
++
++ if (sscanf(buf, "%d", &hdn) != 1) {
++ dev_err(dev, "invalid number of argument");
++ return -EINVAL;
++ }
++
++ if (hdn < 1 || hdn > GPADC_CH_MAX) {
++ dev_err(dev, "invalid handle value");
++ return -EINVAL;
++ }
++
++ if (adc_handle[hdn - 1]) {
++ intel_mid_gpadc_free(adc_handle[hdn - 1]);
++ adc_handle[hdn - 1] = NULL;
++ }
++
++ return size;
++}
++
++static ssize_t intel_mid_gpadc_store_sample(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t size)
++{
++ int hdn, spc;
++ int ret;
++ struct gpadc_request *rq;
++
++ if (sscanf(buf, "%d %d", &hdn, &spc) != 2) {
++ dev_err(dev, "invalid number of arguments");
++ return -EINVAL;
++ }
++
++ if (hdn < 1 || hdn > GPADC_CH_MAX) {
++ dev_err(dev, "invalid handle value");
++ return -EINVAL;
++ }
++
++ rq = adc_handle[hdn - 1];
++ if (!rq) {
++ dev_err(dev, "null handle");
++ return -EINVAL;
++ }
++
++ if (rq->count == 1)
++ ret = intel_mid_gpadc_sample(adc_handle[hdn-1],
++ spc, &sample_result[hdn - 1][0]);
++ else
++ ret = intel_mid_gpadc_sample(adc_handle[hdn - 1],
++ spc, &sample_result[hdn - 1][0],
++ &sample_result[hdn - 1][1]);
++
++ if (ret) {
++ dev_err(dev, "sampling failed. adc handle: %d", hdn);
++ return -EINVAL;
++ }
++
++ return size;
++}
++
++static ssize_t intel_mid_gpadc_show_sample(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ int hdc;
++ int used = 0;
++ struct gpadc_request *rq;
++
++ for (hdc = 0; hdc < GPADC_CH_MAX; hdc++) {
++ if (adc_handle[hdc]) {
++ rq = adc_handle[hdc];
++ if (rq->count == 1)
++ used += snprintf(buf + used, PAGE_SIZE - used,
++ "%d ", sample_result[hdc][0]);
++ else
++ used += snprintf(buf + used, PAGE_SIZE - used,
++ "%d %d ", sample_result[hdc][0],
++ sample_result[hdc][1]);
++ }
++ }
++
++ return used;
++}
++
++
++static void gsmpulse_sysfs_callback(int vol, int cur)
++{
++ vol_val = vol;
++ cur_val = cur;
++ complete(&gsmadc_complete);
++}
++
++static ssize_t intel_mid_gpadc_show_gsmpulse_sample(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ int ret;
++
++ INIT_COMPLETION(gsmadc_complete);
++ intel_mid_gpadc_gsmpulse_register(gsmpulse_sysfs_callback);
++ ret = wait_for_completion_interruptible(&gsmadc_complete);
++ intel_mid_gpadc_gsmpulse_unregister(gsmpulse_sysfs_callback);
++ if (ret)
++ return 0;
++ else
++ return snprintf(buf, PAGE_SIZE, "%d %d", vol_val, cur_val);
++}
++
++static DEVICE_ATTR(alloc_channel, S_IWUSR, NULL,
++ intel_mid_gpadc_store_alloc_channel);
++static DEVICE_ATTR(free_channel, S_IWUSR, NULL,
++ intel_mid_gpadc_store_free_channel);
++static DEVICE_ATTR(sample, S_IRUGO | S_IWUSR,
++ intel_mid_gpadc_show_sample, intel_mid_gpadc_store_sample);
++static DEVICE_ATTR(gsmpulse_sample, S_IRUGO,
++ intel_mid_gpadc_show_gsmpulse_sample, NULL);
++
++static struct attribute *intel_mid_gpadc_attrs[] = {
++ &dev_attr_alloc_channel.attr,
++ &dev_attr_free_channel.attr,
++ &dev_attr_sample.attr,
++ &dev_attr_gsmpulse_sample.attr,
++ NULL,
++};
++
++static struct attribute_group intel_mid_gpadc_attr_group = {
++ .name = "mid_gpadc",
++ .attrs = intel_mid_gpadc_attrs,
++};
++
++static int msic_gpadc_probe(struct platform_device *pdev)
++{
++ struct gpadc_info *mgi = &gpadc_info;
++ struct intel_mid_gpadc_platform_data *pdata = pdev->dev.platform_data;
++ int err = 0;
++
++ mutex_init(&mgi->lock);
++ init_waitqueue_head(&mgi->wait);
++ init_waitqueue_head(&mgi->trimming_wait);
++ mgi->workq = create_singlethread_workqueue(dev_name(&pdev->dev));
++ if (mgi->workq == NULL)
++ return -ENOMEM;
++
++ mgi->dev = &pdev->dev;
++ mgi->intr = ioremap_nocache(pdata->intr, 4);
++ mgi->irq = platform_get_irq(pdev, 0);
++
++ gpadc_clear_bits(IRQLVL1MSK, IRQLVL1MSK_ADCM);
++ if (request_threaded_irq(mgi->irq, msic_gpadc_isr, msic_gpadc_irq,
++ IRQF_ONESHOT, "msic_adc", mgi)) {
++ dev_err(&pdev->dev, "unable to register irq %d\n", mgi->irq);
++ err = -ENODEV;
++ goto err_exit;
++ }
++
++ gpadc_write(ADC1ADDR0, MSIC_STOPCH);
++ INIT_WORK(&mgi->trimming_work, gpadc_trimming);
++ INIT_WORK(&mgi->gsmpulse_work, gpadc_gsmpulse_work);
++ queue_work(mgi->workq, &mgi->trimming_work);
++ wait_event(mgi->trimming_wait, mgi->trimming_start);
++ mgi->initialized = 1;
++
++ init_completion(&gsmadc_complete);
++
++ err = sysfs_create_group(&pdev->dev.kobj,
++ &intel_mid_gpadc_attr_group);
++ if (err) {
++ dev_err(&pdev->dev, "Unable to export sysfs interface, error: %d\n",
++ err);
++ goto err_release_irq;
++ }
++
++ return 0;
++
++err_release_irq:
++ free_irq(mgi->irq, mgi);
++err_exit:
++ if (mgi->intr)
++ iounmap(mgi->intr);
++ return err;
++}
++
++static int msic_gpadc_remove(struct platform_device *pdev)
++{
++ struct gpadc_info *mgi = &gpadc_info;
++
++ sysfs_remove_group(&pdev->dev.kobj, &intel_mid_gpadc_attr_group);
++ free_irq(mgi->irq, mgi);
++ iounmap(mgi->intr);
++ flush_workqueue(mgi->workq);
++ destroy_workqueue(mgi->workq);
++ return 0;
++}
++
++#ifdef CONFIG_PM
++static int msic_gpadc_suspend_noirq(struct device *dev)
++{
++ struct gpadc_info *mgi = &gpadc_info;
++
++ /* If the gpadc is locked, it means gpadc is still in active mode. */
++ if (mutex_trylock(&mgi->lock))
++ return 0;
++ else
++ return -EBUSY;
++}
++
++static int msic_gpadc_resume_noirq(struct device *dev)
++{
++ struct gpadc_info *mgi = &gpadc_info;
++
++ mutex_unlock(&mgi->lock);
++ return 0;
++}
++#else
++#define msic_gpadc_suspend_noirq NULL
++#define msic_gpadc_resume_noirq NULL
++#endif
++
++static const struct dev_pm_ops msic_gpadc_driver_pm_ops = {
++ .suspend_noirq = msic_gpadc_suspend_noirq,
++ .resume_noirq = msic_gpadc_resume_noirq,
++};
++
++static struct platform_driver msic_gpadc_driver = {
++ .driver = {
++ .name = "msic_adc",
++ .owner = THIS_MODULE,
++ .pm = &msic_gpadc_driver_pm_ops,
++ },
++ .probe = msic_gpadc_probe,
++ .remove = msic_gpadc_remove,
++};
++
++static int msic_gpadc_module_init(void)
++{
++ return platform_driver_register(&msic_gpadc_driver);
++}
++
++static void msic_gpadc_module_exit(void)
++{
++ platform_driver_unregister(&msic_gpadc_driver);
++}
++
++static int msic_adc_rpmsg_probe(struct rpmsg_channel *rpdev)
++{
++ int ret = 0;
++
++ if (rpdev == NULL) {
++ pr_err("rpmsg channel not created\n");
++ ret = -ENODEV;
++ goto out;
++ }
++
++ dev_info(&rpdev->dev, "Probed msic_gpadc rpmsg device\n");
++
++ ret = msic_gpadc_module_init();
++
++out:
++ return ret;
++}
++
++static void msic_adc_rpmsg_remove(struct rpmsg_channel *rpdev)
++{
++ msic_gpadc_module_exit();
++ dev_info(&rpdev->dev, "Removed msic_gpadc rpmsg device\n");
++}
++
++static void msic_adc_rpmsg_cb(struct rpmsg_channel *rpdev, void *data,
++ int len, void *priv, u32 src)
++{
++ dev_warn(&rpdev->dev, "unexpected, message\n");
++
++ print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
++ data, len, true);
++}
++
++static struct rpmsg_device_id msic_adc_rpmsg_id_table[] = {
++ { .name = "rpmsg_msic_adc" },
++ { },
++};
++MODULE_DEVICE_TABLE(rpmsg, msic_adc_rpmsg_id_table);
++
++static struct rpmsg_driver msic_adc_rpmsg = {
++ .drv.name = KBUILD_MODNAME,
++ .drv.owner = THIS_MODULE,
++ .id_table = msic_adc_rpmsg_id_table,
++ .probe = msic_adc_rpmsg_probe,
++ .callback = msic_adc_rpmsg_cb,
++ .remove = msic_adc_rpmsg_remove,
++};
++
++static int __init msic_adc_rpmsg_init(void)
++{
++ return register_rpmsg_driver(&msic_adc_rpmsg);
++}
++
++#ifdef MODULE
++module_init(msic_adc_rpmsg_init);
++#else
++rootfs_initcall(msic_adc_rpmsg_init);
++#endif
++
++static void __exit msic_adc_rpmsg_exit(void)
++{
++ return unregister_rpmsg_driver(&msic_adc_rpmsg);
++}
++module_exit(msic_adc_rpmsg_exit);
++
++MODULE_AUTHOR("Jenny TC <jenny.tc@intel.com>");
++MODULE_DESCRIPTION("Intel Medfield MSIC GPADC Driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
+index 4faf02b..e0af003 100644
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -395,6 +395,52 @@ config I2C_DAVINCI
+ devices such as DaVinci NIC.
+ For details please see http://www.ti.com/davinci
+
++config I2C_DESIGNWARE_CORE_FORK
++ tristate "Synopsys DesignWare Controller"
++ help
++ If you say yes to this option, support will be included for the
++ Synopsys DesignWare adapter core. Only master mode is supported.
++ You need choose platform or pci driver for its driver support.
++
++ This driver can also be built as a module. If so, the module
++ will be called i2c-designware-core.
++
++config I2C_DESIGNWARE_PCI_FORK
++ tristate "Synopsys DesignWare PCI"
++ depends on PCI && I2C_DESIGNWARE_CORE_FORK
++ help
++ If you say yes to this option, support will be included for the
++ Synopsys DesignWare I2C adapter. Only master mode is supported.
++
++ This driver can also be built as a module. If so, the module
++ will be called i2c-designware-pci.
++
++config I2C_DESIGNWARE_PLATFORM_FORK
++ tristate "Synopsys DesignWare Platform"
++ depends on I2C_DESIGNWARE_CORE_FORK
++ help
++ If you say yes to this option, support will be included for the
++ Synopsys DesignWare I2C adapter. Only master mode is supported.
++
++ This driver can also be built as a module. If so, the module
++ will be called i2c-designware-platform.
++
++config I2C_DW_SPEED_MODE_DEBUG
++ bool "Designware I2C Speed Mode Debug"
++ depends on I2C_DESIGNWARE_CORE_FORK
++ help
++ If you say yes to this option, you could runtime change the I2C
++ controller bus speed mode.
++
++config I2C_PMIC
++ bool "PMIC I2C Adapter"
++ depends on INTEL_SCU_IPC
++ help
++ Say Y here if you have PMIC I2C adapter.
++
++ PMIC-I2C adapter driver to handle I2C transactions
++ in the PMIC's I2C bus.
++
+ config I2C_DESIGNWARE_CORE
+ tristate
+
+diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
+index 8f4fc23..030b4dd 100644
+--- a/drivers/i2c/busses/Makefile
++++ b/drivers/i2c/busses/Makefile
+@@ -92,4 +92,12 @@ obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
+ obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
+ obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
+
++obj-$(CONFIG_I2C_DESIGNWARE_CORE_FORK) += i2c-designware-core.o
++obj-$(CONFIG_I2C_DESIGNWARE_PCI_FORK) += i2c-designware-pci.o
++i2c-designware-pci-objs := i2c-designware-pcidrv.o
++obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM_FORK) += i2c-designware-platform.o
++i2c-designware-platform-objs := i2c-designware-platdrv.o
++
++obj-$(CONFIG_I2C_PMIC) += i2c-pmic.o
++
+ ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
+diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
+index c41ca63..b316ea3 100644
+--- a/drivers/i2c/busses/i2c-designware-core.c
++++ b/drivers/i2c/busses/i2c-designware-core.c
+@@ -25,7 +25,8 @@
+ * ----------------------------------------------------------------------------
+ *
+ */
+-#include <linux/export.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
+ #include <linux/clk.h>
+ #include <linux/errno.h>
+ #include <linux/err.h>
+@@ -33,112 +34,22 @@
+ #include <linux/interrupt.h>
+ #include <linux/io.h>
+ #include <linux/pm_runtime.h>
++#include <linux/nmi.h>
+ #include <linux/delay.h>
+-#include <linux/module.h>
++#include <linux/semaphore.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/acpi.h>
+ #include "i2c-designware-core.h"
+
+-/*
+- * Registers offset
+- */
+-#define DW_IC_CON 0x0
+-#define DW_IC_TAR 0x4
+-#define DW_IC_DATA_CMD 0x10
+-#define DW_IC_SS_SCL_HCNT 0x14
+-#define DW_IC_SS_SCL_LCNT 0x18
+-#define DW_IC_FS_SCL_HCNT 0x1c
+-#define DW_IC_FS_SCL_LCNT 0x20
+-#define DW_IC_INTR_STAT 0x2c
+-#define DW_IC_INTR_MASK 0x30
+-#define DW_IC_RAW_INTR_STAT 0x34
+-#define DW_IC_RX_TL 0x38
+-#define DW_IC_TX_TL 0x3c
+-#define DW_IC_CLR_INTR 0x40
+-#define DW_IC_CLR_RX_UNDER 0x44
+-#define DW_IC_CLR_RX_OVER 0x48
+-#define DW_IC_CLR_TX_OVER 0x4c
+-#define DW_IC_CLR_RD_REQ 0x50
+-#define DW_IC_CLR_TX_ABRT 0x54
+-#define DW_IC_CLR_RX_DONE 0x58
+-#define DW_IC_CLR_ACTIVITY 0x5c
+-#define DW_IC_CLR_STOP_DET 0x60
+-#define DW_IC_CLR_START_DET 0x64
+-#define DW_IC_CLR_GEN_CALL 0x68
+-#define DW_IC_ENABLE 0x6c
+-#define DW_IC_STATUS 0x70
+-#define DW_IC_TXFLR 0x74
+-#define DW_IC_RXFLR 0x78
+-#define DW_IC_TX_ABRT_SOURCE 0x80
+-#define DW_IC_ENABLE_STATUS 0x9c
+-#define DW_IC_COMP_PARAM_1 0xf4
+-#define DW_IC_COMP_TYPE 0xfc
+-#define DW_IC_COMP_TYPE_VALUE 0x44570140
+-
+-#define DW_IC_INTR_RX_UNDER 0x001
+-#define DW_IC_INTR_RX_OVER 0x002
+-#define DW_IC_INTR_RX_FULL 0x004
+-#define DW_IC_INTR_TX_OVER 0x008
+-#define DW_IC_INTR_TX_EMPTY 0x010
+-#define DW_IC_INTR_RD_REQ 0x020
+-#define DW_IC_INTR_TX_ABRT 0x040
+-#define DW_IC_INTR_RX_DONE 0x080
+-#define DW_IC_INTR_ACTIVITY 0x100
+-#define DW_IC_INTR_STOP_DET 0x200
+-#define DW_IC_INTR_START_DET 0x400
+-#define DW_IC_INTR_GEN_CALL 0x800
+-
+-#define DW_IC_INTR_DEFAULT_MASK (DW_IC_INTR_RX_FULL | \
+- DW_IC_INTR_TX_EMPTY | \
+- DW_IC_INTR_TX_ABRT | \
+- DW_IC_INTR_STOP_DET)
+-
+-#define DW_IC_STATUS_ACTIVITY 0x1
+-
+-#define DW_IC_ERR_TX_ABRT 0x1
+-
+-/*
+- * status codes
+- */
+-#define STATUS_IDLE 0x0
+-#define STATUS_WRITE_IN_PROGRESS 0x1
+-#define STATUS_READ_IN_PROGRESS 0x2
+-
+-#define TIMEOUT 20 /* ms */
+-
+-/*
+- * hardware abort codes from the DW_IC_TX_ABRT_SOURCE register
+- *
+- * only expected abort codes are listed here
+- * refer to the datasheet for the full list
+- */
+-#define ABRT_7B_ADDR_NOACK 0
+-#define ABRT_10ADDR1_NOACK 1
+-#define ABRT_10ADDR2_NOACK 2
+-#define ABRT_TXDATA_NOACK 3
+-#define ABRT_GCALL_NOACK 4
+-#define ABRT_GCALL_READ 5
+-#define ABRT_SBYTE_ACKDET 7
+-#define ABRT_SBYTE_NORSTRT 9
+-#define ABRT_10B_RD_NORSTRT 10
+-#define ABRT_MASTER_DIS 11
+-#define ARB_LOST 12
+-
+-#define DW_IC_TX_ABRT_7B_ADDR_NOACK (1UL << ABRT_7B_ADDR_NOACK)
+-#define DW_IC_TX_ABRT_10ADDR1_NOACK (1UL << ABRT_10ADDR1_NOACK)
+-#define DW_IC_TX_ABRT_10ADDR2_NOACK (1UL << ABRT_10ADDR2_NOACK)
+-#define DW_IC_TX_ABRT_TXDATA_NOACK (1UL << ABRT_TXDATA_NOACK)
+-#define DW_IC_TX_ABRT_GCALL_NOACK (1UL << ABRT_GCALL_NOACK)
+-#define DW_IC_TX_ABRT_GCALL_READ (1UL << ABRT_GCALL_READ)
+-#define DW_IC_TX_ABRT_SBYTE_ACKDET (1UL << ABRT_SBYTE_ACKDET)
+-#define DW_IC_TX_ABRT_SBYTE_NORSTRT (1UL << ABRT_SBYTE_NORSTRT)
+-#define DW_IC_TX_ABRT_10B_RD_NORSTRT (1UL << ABRT_10B_RD_NORSTRT)
+-#define DW_IC_TX_ABRT_MASTER_DIS (1UL << ABRT_MASTER_DIS)
+-#define DW_IC_TX_ARB_LOST (1UL << ARB_LOST)
+-
+-#define DW_IC_TX_ABRT_NOACK (DW_IC_TX_ABRT_7B_ADDR_NOACK | \
+- DW_IC_TX_ABRT_10ADDR1_NOACK | \
+- DW_IC_TX_ABRT_10ADDR2_NOACK | \
+- DW_IC_TX_ABRT_TXDATA_NOACK | \
+- DW_IC_TX_ABRT_GCALL_NOACK)
++int i2c_dw_init(struct dw_i2c_dev *dev);
++int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
++u32 i2c_dw_func(struct i2c_adapter *adap);
++void i2c_dw_enable(struct dw_i2c_dev *dev);
++void i2c_dw_disable(struct dw_i2c_dev *dev);
++irqreturn_t i2c_dw_isr(int this_irq, void *dev_id);
++void i2c_dw_disable_int(struct dw_i2c_dev *dev);
++void i2c_dw_clear_int(struct dw_i2c_dev *dev);
+
+ static char *abort_sources[] = {
+ [ABRT_7B_ADDR_NOACK] =
+@@ -167,15 +78,9 @@ static char *abort_sources[] = {
+
+ u32 dw_readl(struct dw_i2c_dev *dev, int offset)
+ {
+- u32 value;
+-
+- if (dev->accessor_flags & ACCESS_16BIT)
+- value = readw(dev->base + offset) |
+- (readw(dev->base + offset + 2) << 16);
+- else
+- value = readl(dev->base + offset);
++ u32 value = readl(dev->base + offset);
+
+- if (dev->accessor_flags & ACCESS_SWAP)
++ if (dev->swab)
+ return swab32(value);
+ else
+ return value;
+@@ -183,17 +88,778 @@ u32 dw_readl(struct dw_i2c_dev *dev, int offset)
+
+ void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset)
+ {
+- if (dev->accessor_flags & ACCESS_SWAP)
++ if (dev->swab)
+ b = swab32(b);
+
+- if (dev->accessor_flags & ACCESS_16BIT) {
+- writew((u16)b, dev->base + offset);
+- writew((u16)(b >> 16), dev->base + offset + 2);
++ writel(b, dev->base + offset);
++}
++
++static void i2c_dw_dump(struct dw_i2c_dev *dev)
++{
++ u32 value;
++
++ dev_err(dev->dev, "===== REGISTER DUMP (i2c) =====\n");
++ value = dw_readl(dev, DW_IC_CON);
++ dev_err(dev->dev, "DW_IC_CON: 0x%x\n", value);
++ value = dw_readl(dev, DW_IC_TAR);
++ dev_err(dev->dev, "DW_IC_TAR: 0x%x\n", value);
++ value = dw_readl(dev, DW_IC_SS_SCL_HCNT);
++ dev_err(dev->dev, "DW_IC_SS_SCL_HCNT: 0x%x\n", value);
++ value = dw_readl(dev, DW_IC_SS_SCL_LCNT);
++ dev_err(dev->dev, "DW_IC_SS_SCL_LCNT: 0x%x\n", value);
++ value = dw_readl(dev, DW_IC_FS_SCL_HCNT);
++ dev_err(dev->dev, "DW_IC_FS_SCL_HCNT: 0x%x\n", value);
++ value = dw_readl(dev, DW_IC_FS_SCL_LCNT);
++ dev_err(dev->dev, "DW_IC_FS_SCL_LCNT: 0x%x\n", value);
++ value = dw_readl(dev, DW_IC_INTR_STAT);
++ dev_err(dev->dev, "DW_IC_INTR_STAT: 0x%x\n", value);
++ value = dw_readl(dev, DW_IC_INTR_MASK);
++ dev_err(dev->dev, "DW_IC_INTR_MASK: 0x%x\n", value);
++ value = dw_readl(dev, DW_IC_RAW_INTR_STAT);
++ dev_err(dev->dev, "DW_IC_RAW_INTR_STAT: 0x%x\n", value);
++ value = dw_readl(dev, DW_IC_RX_TL);
++ dev_err(dev->dev, "DW_IC_RX_TL: 0x%x\n", value);
++ value = dw_readl(dev, DW_IC_TX_TL);
++ dev_err(dev->dev, "DW_IC_TX_TL: 0x%x\n", value);
++ value = dw_readl(dev, DW_IC_ENABLE);
++ dev_err(dev->dev, "DW_IC_ENABLE: 0x%x\n", value);
++ value = dw_readl(dev, DW_IC_STATUS);
++ dev_err(dev->dev, "DW_IC_STATUS: 0x%x\n", value);
++ value = dw_readl(dev, DW_IC_TXFLR);
++ dev_err(dev->dev, "DW_IC_TXFLR: 0x%x\n", value);
++ value = dw_readl(dev, DW_IC_RXFLR);
++ dev_err(dev->dev, "DW_IC_RXFLR: 0x%x\n", value);
++ value = dw_readl(dev, DW_IC_TX_ABRT_SOURCE);
++ dev_err(dev->dev, "DW_IC_TX_ABRT_SOURCE: 0x%x\n", value);
++ value = dw_readl(dev, DW_IC_DATA_CMD);
++ dev_err(dev->dev, "DW_IC_DATA_CMD: 0x%x\n", value);
++ dev_err(dev->dev, "===============================\n");
++}
++
++/* VLV2 PCI config space memio access to the controller is
++* enabled by
++* 1. Reset 0x804 and 0x808 offset from base address.
++* 2. Set 0x804 offset from base address to 0x3.
++*/
++static void vlv2_reset(struct dw_i2c_dev *dev)
++{
++ int i;
++
++ for (i = 0; i < 10; i++) {
++ dw_writel(dev, 0, 0x804);
++ dw_writel(dev, 0, 0x808);
++ usleep_range(10, 100);
++
++ dw_writel(dev, 3, 0x804);
++ usleep_range(10, 100);
++
++ if (dw_readl(dev, DW_IC_COMP_TYPE) != DW_IC_COMP_TYPE_VALUE)
++ continue;
++
++ return;
++ }
++
++ dev_warn(dev->dev, "vlv2 I2C reset failed\n");
++}
++
++static int mfld_i2c_scl_cfg(struct dw_i2c_dev *dev)
++{
++ dw_writel(dev, PNW_SS_SCLK_HCNT, DW_IC_SS_SCL_HCNT);
++ dw_writel(dev, PNW_SS_SCLK_LCNT, DW_IC_SS_SCL_LCNT);
++
++ dw_writel(dev, PNW_FS_SCLK_HCNT, DW_IC_FS_SCL_HCNT);
++ dw_writel(dev, PNW_FS_SCLK_LCNT, DW_IC_FS_SCL_LCNT);
++
++ return 0;
++}
++
++static int ctp_i2c_scl_cfg(struct dw_i2c_dev *dev)
++{
++ dw_writel(dev, CLV_SS_SCLK_HCNT, DW_IC_SS_SCL_HCNT);
++ dw_writel(dev, CLV_SS_SCLK_LCNT, DW_IC_SS_SCL_LCNT);
++
++ dw_writel(dev, CLV_FS_SCLK_HCNT, DW_IC_FS_SCL_HCNT);
++ dw_writel(dev, CLV_FS_SCLK_LCNT, DW_IC_FS_SCL_LCNT);
++
++ return 0;
++}
++
++static int merr_i2c_scl_cfg(struct dw_i2c_dev *dev)
++{
++ dw_writel(dev, MERR_SS_SCLK_HCNT, DW_IC_SS_SCL_HCNT);
++ dw_writel(dev, MERR_SS_SCLK_LCNT, DW_IC_SS_SCL_LCNT);
++
++ dw_writel(dev, MERR_FS_SCLK_HCNT, DW_IC_FS_SCL_HCNT);
++ dw_writel(dev, MERR_FS_SCLK_LCNT, DW_IC_FS_SCL_LCNT);
++
++ dw_writel(dev, MERR_HS_SCLK_HCNT, DW_IC_HS_SCL_HCNT);
++ dw_writel(dev, MERR_HS_SCLK_LCNT, DW_IC_HS_SCL_LCNT);
++
++ return 0;
++}
++
++static int vlv2_i2c_scl_cfg(struct dw_i2c_dev *dev)
++{
++ dw_writel(dev, VLV2_SS_SCLK_HCNT, DW_IC_SS_SCL_HCNT);
++ dw_writel(dev, VLV2_SS_SCLK_LCNT, DW_IC_SS_SCL_LCNT);
++
++ dw_writel(dev, VLV2_FS_SCLK_HCNT, DW_IC_FS_SCL_HCNT);
++ dw_writel(dev, VLV2_FS_SCLK_LCNT, DW_IC_FS_SCL_LCNT);
++
++ dw_writel(dev, VLV2_HS_SCLK_HCNT, DW_IC_HS_SCL_HCNT);
++ dw_writel(dev, VLV2_HS_SCLK_LCNT, DW_IC_HS_SCL_LCNT);
++
++ return 0;
++}
++
++static struct dw_controller dw_controllers[] = {
++ [moorestown_0] = {
++ .bus_num = 0,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 32,
++ .rx_fifo_depth = 32,
++ .clk_khz = 25000,
++ },
++ [moorestown_1] = {
++ .bus_num = 1,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 32,
++ .rx_fifo_depth = 32,
++ .clk_khz = 25000,
++ },
++ [moorestown_2] = {
++ .bus_num = 2,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 32,
++ .rx_fifo_depth = 32,
++ .clk_khz = 25000,
++ },
++ [medfield_0] = {
++ .bus_num = 0,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 256,
++ .rx_fifo_depth = 256,
++ .clk_khz = 17000,
++ .scl_cfg = mfld_i2c_scl_cfg,
++ },
++ [medfield_1] = {
++ .bus_num = 1,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_STD,
++ .tx_fifo_depth = 256,
++ .rx_fifo_depth = 256,
++ .clk_khz = 20500,
++ .scl_cfg = mfld_i2c_scl_cfg,
++ },
++ [medfield_2] = {
++ .bus_num = 2,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 256,
++ .rx_fifo_depth = 256,
++ .clk_khz = 17000,
++ .scl_cfg = mfld_i2c_scl_cfg,
++ },
++ [medfield_3] = {
++ .bus_num = 3,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_STD,
++ .tx_fifo_depth = 256,
++ .rx_fifo_depth = 256,
++ .clk_khz = 20500,
++ .scl_cfg = mfld_i2c_scl_cfg,
++ },
++ [medfield_4] = {
++ .bus_num = 4,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 256,
++ .rx_fifo_depth = 256,
++ .clk_khz = 17000,
++ .scl_cfg = mfld_i2c_scl_cfg,
++ },
++ [medfield_5] = {
++ .bus_num = 5,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 256,
++ .rx_fifo_depth = 256,
++ .clk_khz = 17000,
++ .scl_cfg = mfld_i2c_scl_cfg,
++ },
++
++ [cloverview_0] = {
++ .bus_num = 0,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 256,
++ .rx_fifo_depth = 256,
++ .clk_khz = 17000,
++ .scl_cfg = ctp_i2c_scl_cfg,
++ },
++ [cloverview_1] = {
++ .bus_num = 1,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 256,
++ .rx_fifo_depth = 256,
++ .clk_khz = 17000,
++ .scl_cfg = ctp_i2c_scl_cfg,
++ },
++ [cloverview_2] = {
++ .bus_num = 2,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 256,
++ .rx_fifo_depth = 256,
++ .clk_khz = 17000,
++ .scl_cfg = ctp_i2c_scl_cfg,
++ },
++ [cloverview_3] = {
++ .bus_num = 3,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_STD,
++ .tx_fifo_depth = 256,
++ .rx_fifo_depth = 256,
++ .clk_khz = 20500,
++ .scl_cfg = ctp_i2c_scl_cfg,
++ },
++ [cloverview_4] = {
++ .bus_num = 4,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 256,
++ .rx_fifo_depth = 256,
++ .clk_khz = 17000,
++ .scl_cfg = ctp_i2c_scl_cfg,
++ },
++ [cloverview_5] = {
++ .bus_num = 5,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 256,
++ .rx_fifo_depth = 256,
++ .clk_khz = 17000,
++ .scl_cfg = ctp_i2c_scl_cfg,
++ },
++
++ [merrifield_0] = {
++ .bus_num = 1,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 64,
++ .rx_fifo_depth = 64,
++ .enable_stop = 1,
++ .scl_cfg = merr_i2c_scl_cfg,
++ },
++ [merrifield_1] = {
++ .bus_num = 2,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_STD,
++ .tx_fifo_depth = 64,
++ .rx_fifo_depth = 64,
++ .enable_stop = 1,
++ .scl_cfg = merr_i2c_scl_cfg,
++ },
++ [merrifield_2] = {
++ .bus_num = 3,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 64,
++ .rx_fifo_depth = 64,
++ .enable_stop = 1,
++ .scl_cfg = merr_i2c_scl_cfg,
++ },
++ [merrifield_3] = {
++ .bus_num = 4,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 64,
++ .rx_fifo_depth = 64,
++ .enable_stop = 1,
++ .scl_cfg = merr_i2c_scl_cfg,
++ },
++ [merrifield_4] = {
++ .bus_num = 5,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 64,
++ .rx_fifo_depth = 64,
++ .enable_stop = 1,
++ .scl_cfg = merr_i2c_scl_cfg,
++ },
++ [merrifield_5] = {
++ .bus_num = 6,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 64,
++ .rx_fifo_depth = 64,
++ .enable_stop = 1,
++ .scl_cfg = merr_i2c_scl_cfg,
++ },
++ [merrifield_6] = {
++ .bus_num = 7,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 64,
++ .rx_fifo_depth = 64,
++ .enable_stop = 1,
++ .scl_cfg = merr_i2c_scl_cfg,
++ },
++ [valleyview_0] = {
++ .bus_num = 1,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 64,
++ .rx_fifo_depth = 64,
++ .enable_stop = 1,
++ .scl_cfg = vlv2_i2c_scl_cfg,
++ .reset = vlv2_reset,
++ .share_irq = 1,
++ .acpi_name = "\\_SB.I2C1"
++ },
++ [valleyview_1] = {
++ .bus_num = 2,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 64,
++ .rx_fifo_depth = 64,
++ .enable_stop = 1,
++ .scl_cfg = vlv2_i2c_scl_cfg,
++ .reset = vlv2_reset,
++ .share_irq = 1,
++ .acpi_name = "\\_SB.I2C2"
++ },
++ [valleyview_2] = {
++ .bus_num = 3,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 64,
++ .rx_fifo_depth = 64,
++ .enable_stop = 1,
++ .scl_cfg = vlv2_i2c_scl_cfg,
++ .reset = vlv2_reset,
++ .share_irq = 1,
++ .acpi_name = "\\_SB.I2C3"
++ },
++ [valleyview_3] = {
++ .bus_num = 4,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 64,
++ .rx_fifo_depth = 64,
++ .enable_stop = 1,
++ .scl_cfg = vlv2_i2c_scl_cfg,
++ .reset = vlv2_reset,
++ .share_irq = 1,
++ .acpi_name = "\\_SB.I2C4"
++ },
++ [valleyview_4] = {
++ .bus_num = 5,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 64,
++ .rx_fifo_depth = 64,
++ .enable_stop = 1,
++ .scl_cfg = vlv2_i2c_scl_cfg,
++ .reset = vlv2_reset,
++ .share_irq = 1,
++ .acpi_name = "\\_SB.I2C5"
++ },
++ [valleyview_5] = {
++ .bus_num = 6,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 64,
++ .rx_fifo_depth = 64,
++ .enable_stop = 1,
++ .scl_cfg = vlv2_i2c_scl_cfg,
++ .reset = vlv2_reset,
++ .share_irq = 1,
++ .acpi_name = "\\_SB.I2C6"
++ },
++ [valleyview_6] = {
++ .bus_num = 7,
++ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 64,
++ .rx_fifo_depth = 64,
++ .enable_stop = 1,
++ .scl_cfg = vlv2_i2c_scl_cfg,
++ .reset = vlv2_reset,
++ .share_irq = 1,
++ .acpi_name = "\\_SB.I2C7"
++ }
++};
++
++static struct i2c_algorithm i2c_dw_algo = {
++ .master_xfer = i2c_dw_xfer,
++ .functionality = i2c_dw_func,
++};
++
++int i2c_dw_suspend(struct dw_i2c_dev *dev, bool runtime)
++{
++ if (runtime)
++ i2c_dw_disable(dev);
++ else {
++ if (down_trylock(&dev->lock))
++ return -EBUSY;
++ i2c_dw_disable(dev);
++ dev->status &= ~STATUS_POWERON;
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL(i2c_dw_suspend);
++
++int i2c_dw_resume(struct dw_i2c_dev *dev, bool runtime)
++{
++ i2c_dw_init(dev);
++ if (!runtime) {
++ dev->status |= STATUS_POWERON;
++ up(&dev->lock);
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL(i2c_dw_resume);
++
++static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
++{
++ return dev->controller->clk_khz;
++}
++
++#ifdef CONFIG_I2C_DW_SPEED_MODE_DEBUG
++static ssize_t show_bus_num(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct dw_i2c_dev *i2c = dev_get_drvdata(dev);
++
++ return snprintf(buf, PAGE_SIZE, "%d\n", i2c->controller->bus_num);
++}
++
++#define MODE_NAME_SIZE 10
++
++static ssize_t store_mode(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t size)
++{
++ struct dw_i2c_dev *i2c = dev_get_drvdata(dev);
++ int ret = 0;
++ char mode[MODE_NAME_SIZE];
++
++ if (sscanf(buf, "%9s", mode) != 1) {
++ dev_err(dev, "input I2C speed mode: std/fast\n");
++ return -EINVAL;
++ }
++
++ down(&i2c->lock);
++ pm_runtime_get_sync(i2c->dev);
++
++ if (!strncmp("std", mode, MODE_NAME_SIZE)) {
++ i2c->master_cfg &= ~DW_IC_SPEED_MASK;
++ i2c->master_cfg |= DW_IC_CON_SPEED_STD;
++ } else if (!strncmp("fast", mode, MODE_NAME_SIZE)) {
++ i2c->master_cfg &= ~DW_IC_SPEED_MASK;
++ i2c->master_cfg |= DW_IC_CON_SPEED_FAST;
++ } else if (!strncmp("high", mode, MODE_NAME_SIZE)) {
++ i2c->master_cfg &= ~DW_IC_SPEED_MASK;
++ i2c->master_cfg |= DW_IC_CON_SPEED_HIGH;
+ } else {
+- writel(b, dev->base + offset);
++ ret = -EINVAL;
++ goto out;
++ }
++
++ /* init to configure the i2c master */
++ i2c_dw_init(i2c);
++
++ dev_info(dev, "I2C speed mode changed to %s\n", mode);
++
++out:
++ pm_runtime_mark_last_busy(i2c->dev);
++ pm_runtime_put_autosuspend(i2c->dev);
++ up(&i2c->lock);
++
++ return (ret < 0) ? ret : size;
++}
++
++static ssize_t show_mode(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++{
++ struct dw_i2c_dev *i2c = dev_get_drvdata(dev);
++ int ret;
++
++ switch (i2c->master_cfg & DW_IC_SPEED_MASK) {
++ case DW_IC_CON_SPEED_STD:
++ ret = snprintf(buf, PAGE_SIZE, "%s\n", "std");
++ break;
++ case DW_IC_CON_SPEED_FAST:
++ ret = snprintf(buf, PAGE_SIZE, "%s\n", "fast");
++ break;
++ case DW_IC_CON_SPEED_HIGH:
++ ret = snprintf(buf, PAGE_SIZE, "%s\n", "high");
++ break;
++ default:
++ ret = snprintf(buf, PAGE_SIZE, "%s\n", "Not Supported\n");
++ break;
++ }
++
++ return ret;
++}
++
++static DEVICE_ATTR(bus_num, S_IRUGO, show_bus_num, NULL);
++static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, show_mode, store_mode);
++
++static struct attribute *i2c_dw_attrs[] = {
++ &dev_attr_bus_num.attr,
++ &dev_attr_mode.attr,
++ NULL,
++};
++
++static struct attribute_group i2c_dw_attr_group = {
++ .name = "i2c_dw_sysnode",
++ .attrs = i2c_dw_attrs,
++};
++#endif
++
++static ssize_t store_lock_xfer(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t size)
++{
++ struct dw_i2c_dev *i2c = dev_get_drvdata(dev->parent);
++ ssize_t status = -EINVAL;
++ long lock;
++
++
++ status = kstrtol(buf, 0, &lock);
++ if (status == 0) {
++ if (lock && !i2c->lock_flag) {
++ down(&i2c->lock);
++ pm_runtime_get_sync(i2c->dev);
++ i2c->lock_flag = 1;
++ dev_info(dev, "lock i2c xfer\n");
++ } else if (!lock && i2c->lock_flag) {
++ pm_runtime_mark_last_busy(i2c->dev);
++ pm_runtime_put_autosuspend(i2c->dev);
++ i2c->lock_flag = 0;
++ up(&i2c->lock);
++ dev_info(dev, "unlock i2c xfer\n");
++ } else
++ return -EINVAL;
+ }
++
++ return status ? : size;
+ }
+
++static DEVICE_ATTR(lock_xfer, S_IWUSR, NULL, store_lock_xfer);
++
++struct dw_i2c_dev *i2c_dw_setup(struct device *pdev, int bus_idx,
++ unsigned long start, unsigned long len, int irq)
++{
++ struct dw_i2c_dev *dev;
++ struct i2c_adapter *adap;
++ void __iomem *base;
++ struct dw_controller *controller;
++ int r;
++
++ if (bus_idx >= ARRAY_SIZE(dw_controllers)) {
++ dev_err(pdev, "invalid bus index %d\n",
++ bus_idx);
++ r = -EINVAL;
++ goto exit;
++ }
++
++ controller = &dw_controllers[bus_idx];
++
++ base = ioremap_nocache(start, len);
++ if (!base) {
++ dev_err(pdev, "I/O memory remapping failed\n");
++ r = -ENOMEM;
++ goto exit;
++ }
++
++ dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL);
++ if (!dev) {
++ r = -ENOMEM;
++ goto err_iounmap;
++ }
++
++ init_completion(&dev->cmd_complete);
++ sema_init(&dev->lock, 1);
++ dev->status = STATUS_IDLE;
++ dev->clk = NULL;
++ dev->controller = controller;
++ dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
++ dev->base = base;
++ dev->dev = get_device(pdev);
++ dev->functionality =
++ I2C_FUNC_I2C |
++ I2C_FUNC_SMBUS_BYTE |
++ I2C_FUNC_SMBUS_BYTE_DATA |
++ I2C_FUNC_SMBUS_WORD_DATA |
++ I2C_FUNC_SMBUS_I2C_BLOCK;
++ dev->master_cfg = controller->bus_cfg;
++ dev->get_scl_cfg = controller->scl_cfg;
++ dev->enable_stop = controller->enable_stop;
++ dev->clk_khz = controller->clk_khz;
++ dev->speed_cfg = dev->master_cfg & DW_IC_SPEED_MASK;
++ dev->use_dyn_clk = 0;
++ dev->reset = controller->reset;
++ dev->irq = irq;
++ dev->share_irq = controller->share_irq;
++ dev->abort = intel_mid_dw_i2c_abort;
++ dev->tx_fifo_depth = controller->tx_fifo_depth;
++ dev->rx_fifo_depth = controller->rx_fifo_depth;
++
++ r = i2c_dw_init(dev);
++ if (r)
++ goto err_kfree;
++
++ adap = &dev->adapter;
++ i2c_set_adapdata(adap, dev);
++ adap->owner = THIS_MODULE;
++ adap->class = 0;
++ adap->algo = &i2c_dw_algo;
++ adap->dev.parent = pdev;
++ adap->nr = controller->bus_num;
++ snprintf(adap->name, sizeof(adap->name), "i2c-designware-%d",
++ adap->nr);
++
++ r = request_irq(irq, i2c_dw_isr, IRQF_SHARED, adap->name, dev);
++ if (r) {
++ dev_err(pdev, "failure requesting irq %i\n", irq);
++ goto err_kfree;
++ }
++
++ i2c_dw_disable_int(dev);
++ i2c_dw_clear_int(dev);
++ r = i2c_add_numbered_adapter(adap);
++ if (r) {
++ dev_err(pdev, "failure adding adapter\n");
++ goto err_free_irq;
++ }
++
++#ifdef CONFIG_I2C_DW_SPEED_MODE_DEBUG
++ r = sysfs_create_group(&pdev->kobj, &i2c_dw_attr_group);
++ if (r) {
++ dev_err(pdev,
++ "Unable to export sysfs interface, error: %d\n", r);
++ goto err_del_adap;
++ }
++#endif
++ r = device_create_file(&adap->dev, &dev_attr_lock_xfer);
++ if (r < 0)
++ dev_err(&adap->dev,
++ "Failed to add lock_xfer sysfs files: %d\n", r);
++
++ return dev;
++
++#ifdef CONFIG_I2C_DW_SPEED_MODE_DEBUG
++err_del_adap:
++ i2c_del_adapter(&dev->adapter);
++#endif
++err_free_irq:
++ free_irq(irq, dev);
++err_kfree:
++ put_device(pdev);
++ kfree(dev);
++err_iounmap:
++ iounmap(base);
++exit:
++ return ERR_PTR(r);
++}
++EXPORT_SYMBOL(i2c_dw_setup);
++
++#ifdef CONFIG_ACPI
++static int acpi_i2c_get_freq(struct acpi_resource *ares,
++ void *data)
++{
++ struct dw_i2c_dev *i2c = data;
++
++ if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
++ struct acpi_resource_i2c_serialbus *sb;
++
++ sb = &ares->data.i2c_serial_bus;
++ if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
++ i2c->freq = sb->connection_speed;
++ if (i2c->freq == DW_STD_SPEED) {
++ i2c->master_cfg &= ~DW_IC_SPEED_MASK;
++ i2c->master_cfg |= DW_IC_CON_SPEED_STD;
++ } else if (i2c->freq == DW_FAST_SPEED) {
++ i2c->master_cfg &= ~DW_IC_SPEED_MASK;
++ i2c->master_cfg |= DW_IC_CON_SPEED_FAST;
++ } else if (i2c->freq == DW_HIGH_SPEED) {
++ i2c->master_cfg &= ~DW_IC_SPEED_MASK;
++ i2c->master_cfg |= DW_IC_CON_SPEED_HIGH;
++ }
++
++ down(&i2c->lock);
++ i2c_dw_init(i2c);
++ up(&i2c->lock);
++ }
++ }
++
++ return 1;
++}
++
++static acpi_status acpi_i2c_find_device_speed(acpi_handle handle, u32 level,
++ void *data, void **return_value)
++{
++ struct dw_i2c_dev *i2c = data;
++ struct list_head resource_list;
++ struct acpi_device *adev;
++ acpi_status status;
++ unsigned long long sta = 0;
++ int ret;
++
++ if (acpi_bus_get_device(handle, &adev))
++ return AE_OK;
++ if (acpi_bus_get_status(adev) || !adev->status.present)
++ return AE_OK;
++
++ INIT_LIST_HEAD(&resource_list);
++ ret = acpi_dev_get_resources(adev, &resource_list,
++ acpi_i2c_get_freq, i2c);
++ acpi_dev_free_resource_list(&resource_list);
++
++ if (ret < 0)
++ return AE_OK;
++
++ pr_debug("i2c device: %s, freq: %dkHz\n",
++ dev_name(&adev->dev), i2c->freq/1000);
++
++ return AE_OK;
++}
++
++void i2c_acpi_devices_setup(struct device *pdev, struct dw_i2c_dev *dev)
++{
++ acpi_handle pdev_handle = ACPI_HANDLE(pdev);
++ acpi_handle handle = NULL;
++ acpi_status status;
++
++ if (pdev_handle) {
++ handle = pdev_handle;
++ } else if (dev->controller->acpi_name) {
++ acpi_get_handle(NULL,
++ dev->controller->acpi_name, &handle);
++
++ ACPI_HANDLE_SET(pdev, handle);
++ }
++
++ if (handle == NULL)
++ return;
++
++ acpi_i2c_register_devices(&dev->adapter);
++
++ /* Find I2C adapter bus frequency */
++ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
++ acpi_i2c_find_device_speed, NULL,
++ dev, NULL);
++ if (ACPI_FAILURE(status))
++ dev_warn(pdev, "failed to get I2C bus freq\n");
++
++ /* Set the handle back to its raw value */
++ ACPI_HANDLE_SET(pdev, pdev_handle);
++}
++#else
++void i2c_acpi_devices_setup(struct device *pdev, struct dw_i2c_dev *dev) { }
++#endif
++EXPORT_SYMBOL(i2c_acpi_devices_setup);
++
++void i2c_dw_free(struct device *pdev, struct dw_i2c_dev *dev)
++{
++ struct i2c_adapter *adap = &dev->adapter;
++
++ i2c_dw_disable(dev);
++
++ device_remove_file(&adap->dev, &dev_attr_lock_xfer);
++#ifdef CONFIG_I2C_DW_SPEED_MODE_DEBUG
++ sysfs_remove_group(&pdev->kobj, &i2c_dw_attr_group);
++#endif
++
++ i2c_del_adapter(&dev->adapter);
++ put_device(pdev);
++ free_irq(dev->irq, dev);
++ kfree(dev);
++}
++EXPORT_SYMBOL(i2c_dw_free);
++
+ static u32
+ i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
+ {
+@@ -249,27 +915,6 @@ static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
+ return ((ic_clk * (tLOW + tf) + 5000) / 10000) - 1 + offset;
+ }
+
+-static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable)
+-{
+- int timeout = 100;
+-
+- do {
+- dw_writel(dev, enable, DW_IC_ENABLE);
+- if ((dw_readl(dev, DW_IC_ENABLE_STATUS) & 1) == enable)
+- return;
+-
+- /*
+- * Wait 10 times the signaling period of the highest I2C
+- * transfer supported by the driver (for 400KHz this is
+- * 25us) as described in the DesignWare I2C databook.
+- */
+- usleep_range(25, 250);
+- } while (timeout--);
+-
+- dev_warn(dev->dev, "timeout in %sabling adapter\n",
+- enable ? "en" : "dis");
+-}
+-
+ /**
+ * i2c_dw_init() - initialize the designware i2c master hardware
+ * @dev: device private data
+@@ -284,63 +929,72 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
+ u32 hcnt, lcnt;
+ u32 reg;
+
++ if (dev->reset)
++ dev->reset(dev);
++
+ input_clock_khz = dev->get_clk_rate_khz(dev);
+
++ /* Configure register endianess access */
+ reg = dw_readl(dev, DW_IC_COMP_TYPE);
+ if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) {
+- /* Configure register endianess access */
+- dev->accessor_flags |= ACCESS_SWAP;
+- } else if (reg == (DW_IC_COMP_TYPE_VALUE & 0x0000ffff)) {
+- /* Configure register access mode 16bit */
+- dev->accessor_flags |= ACCESS_16BIT;
+- } else if (reg != DW_IC_COMP_TYPE_VALUE) {
++ dev->swab = 1;
++ reg = DW_IC_COMP_TYPE_VALUE;
++ }
++
++ if (reg != DW_IC_COMP_TYPE_VALUE) {
+ dev_err(dev->dev, "Unknown Synopsys component type: "
+ "0x%08x\n", reg);
+ return -ENODEV;
+ }
+
+ /* Disable the adapter */
+- __i2c_dw_enable(dev, false);
+-
+- /* set standard and fast speed deviders for high/low periods */
+-
+- /* Standard-mode */
+- hcnt = i2c_dw_scl_hcnt(input_clock_khz,
+- 40, /* tHD;STA = tHIGH = 4.0 us */
+- 3, /* tf = 0.3 us */
+- 0, /* 0: DW default, 1: Ideal */
+- 0); /* No offset */
+- lcnt = i2c_dw_scl_lcnt(input_clock_khz,
+- 47, /* tLOW = 4.7 us */
+- 3, /* tf = 0.3 us */
+- 0); /* No offset */
+- dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT);
+- dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT);
+- dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
+-
+- /* Fast-mode */
+- hcnt = i2c_dw_scl_hcnt(input_clock_khz,
+- 6, /* tHD;STA = tHIGH = 0.6 us */
+- 3, /* tf = 0.3 us */
+- 0, /* 0: DW default, 1: Ideal */
+- 0); /* No offset */
+- lcnt = i2c_dw_scl_lcnt(input_clock_khz,
+- 13, /* tLOW = 1.3 us */
+- 3, /* tf = 0.3 us */
+- 0); /* No offset */
+- dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT);
+- dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT);
+- dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
++ i2c_dw_disable(dev);
++
++ if (dev->get_scl_cfg)
++ dev->get_scl_cfg(dev);
++ else {
++ /* set standard and fast speed deviders for high/low periods */
++
++ /* Standard-mode */
++ hcnt = i2c_dw_scl_hcnt(input_clock_khz,
++ 227, /* tHD;STA = tHIGH = 22.7 us */
++ 3, /* tf = 0.3 us */
++ 0, /* 0: DW default, 1: Ideal */
++ 23); /* offset = 23 */
++ lcnt = i2c_dw_scl_lcnt(input_clock_khz,
++ 227, /* tLOW = 22.7 us */
++ 3, /* tf = 0.3 us */
++ 28); /* offset = 28 */
++ dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT);
++ dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT);
++ dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n",
++ hcnt, lcnt);
++
++ /* Fast-mode */
++ hcnt = i2c_dw_scl_hcnt(input_clock_khz,
++ 52, /* tHD;STA = tHIGH = 5.2 us */
++ 3, /* tf = 0.3 us */
++ 0, /* 0: DW default, 1: Ideal */
++ 11); /* offset = 11 */
++ lcnt = i2c_dw_scl_lcnt(input_clock_khz,
++ 72, /* tLOW = 7.2 us */
++ 3, /* tf = 0.3 us */
++ 12); /* offset = 12 */
++ dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT);
++ dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT);
++ dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
++ }
+
+ /* Configure Tx/Rx FIFO threshold levels */
+- dw_writel(dev, dev->tx_fifo_depth - 1, DW_IC_TX_TL);
+- dw_writel(dev, 0, DW_IC_RX_TL);
++ dw_writel(dev, dev->tx_fifo_depth/2, DW_IC_TX_TL);
++ dw_writel(dev, dev->rx_fifo_depth/2, DW_IC_RX_TL);
+
+ /* configure the i2c master */
+ dw_writel(dev, dev->master_cfg , DW_IC_CON);
++
+ return 0;
+ }
+-EXPORT_SYMBOL_GPL(i2c_dw_init);
++EXPORT_SYMBOL(i2c_dw_init);
+
+ /*
+ * Waiting for bus not busy
+@@ -355,7 +1009,7 @@ static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
+ return -ETIMEDOUT;
+ }
+ timeout--;
+- usleep_range(1000, 1100);
++ mdelay(1);
+ }
+
+ return 0;
+@@ -367,7 +1021,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
+ u32 ic_con;
+
+ /* Disable the adapter */
+- __i2c_dw_enable(dev, false);
++ i2c_dw_disable(dev);
+
+ /* set the slave (target) address */
+ dw_writel(dev, msgs[dev->msg_write_idx].addr, DW_IC_TAR);
+@@ -381,7 +1035,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
+ dw_writel(dev, ic_con, DW_IC_CON);
+
+ /* Enable the adapter */
+- __i2c_dw_enable(dev, true);
++ i2c_dw_enable(dev);
+
+ /* Clear and enable interrupts */
+ i2c_dw_clear_int(dev);
+@@ -394,19 +1048,32 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
+ * messages into the tx buffer. Even if the size of i2c_msg data is
+ * longer than the size of the tx buffer, it handles everything.
+ */
+-static void
++void
+ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
+ {
+ struct i2c_msg *msgs = dev->msgs;
+ u32 intr_mask;
+ int tx_limit, rx_limit;
++ int cmd;
+ u32 addr = msgs[dev->msg_write_idx].addr;
+ u32 buf_len = dev->tx_buf_len;
+ u8 *buf = dev->tx_buf;
++ unsigned long flags;
+
+ intr_mask = DW_IC_INTR_DEFAULT_MASK;
+
++ raw_local_irq_save(flags);
++ /* if fifo only has one byte, it is not safe */
++ if (!dev->enable_stop && (dev->status & STATUS_WRITE_IN_PROGRESS) &&
++ (dw_readl(dev, DW_IC_TXFLR) < 1)) {
++ dev_err(dev->dev, "TX FIFO underrun, addr: 0x%x.\n", addr);
++ dev->msg_err = -EAGAIN;
++ }
++
+ for (; dev->msg_write_idx < dev->msgs_num; dev->msg_write_idx++) {
++ if (dev->msg_err)
++ break;
++
+ /*
+ * if target address has changed, we need to
+ * reprogram the target address in the i2c
+@@ -436,27 +1103,12 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
+ rx_limit = dev->rx_fifo_depth - dw_readl(dev, DW_IC_RXFLR);
+
+ while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) {
+- u32 cmd = 0;
+-
+- /*
+- * If IC_EMPTYFIFO_HOLD_MASTER_EN is set we must
+- * manually set the stop bit. However, it cannot be
+- * detected from the registers so we set it always
+- * when writing/reading the last byte.
+- */
+- if (dev->msg_write_idx == dev->msgs_num - 1 &&
+- buf_len == 1)
+- cmd |= BIT(9);
+-
++ cmd = (dev->enable_stop && buf_len == 1
++ && dev->msg_write_idx == dev->msgs_num - 1) ?
++ DW_IC_CMD_STOP : 0;
+ if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {
+-
+- /* avoid rx buffer overrun */
+- if (rx_limit - dev->rx_outstanding <= 0)
+- break;
+-
+ dw_writel(dev, cmd | 0x100, DW_IC_DATA_CMD);
+ rx_limit--;
+- dev->rx_outstanding++;
+ } else
+ dw_writel(dev, cmd | *buf++, DW_IC_DATA_CMD);
+ tx_limit--; buf_len--;
+@@ -472,6 +1124,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
+ } else
+ dev->status &= ~STATUS_WRITE_IN_PROGRESS;
+ }
++ raw_local_irq_restore(flags);
+
+ /*
+ * If i2c_msg index search is completed, we don't need TX_EMPTY
+@@ -509,10 +1162,8 @@ i2c_dw_read(struct dw_i2c_dev *dev)
+
+ rx_valid = dw_readl(dev, DW_IC_RXFLR);
+
+- for (; len > 0 && rx_valid > 0; len--, rx_valid--) {
++ for (; len > 0 && rx_valid > 0; len--, rx_valid--)
+ *buf++ = dw_readl(dev, DW_IC_DATA_CMD);
+- dev->rx_outstanding--;
+- }
+
+ if (len > 0) {
+ dev->status |= STATUS_READ_IN_PROGRESS;
+@@ -555,10 +1206,11 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+ {
+ struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
+ int ret;
++ unsigned long timeout;
+
+ dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);
+
+- mutex_lock(&dev->lock);
++ down(&dev->lock);
+ pm_runtime_get_sync(dev->dev);
+
+ INIT_COMPLETION(dev->cmd_complete);
+@@ -570,7 +1222,6 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+ dev->msg_err = 0;
+ dev->status = STATUS_IDLE;
+ dev->abort_source = 0;
+- dev->rx_outstanding = 0;
+
+ ret = i2c_dw_wait_bus_not_busy(dev);
+ if (ret < 0)
+@@ -580,14 +1231,17 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+ i2c_dw_xfer_init(dev);
+
+ /* wait for tx to complete */
+- ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ);
+- if (ret == 0) {
+- dev_err(dev->dev, "controller timed out\n");
++ timeout = wait_for_completion_timeout(&dev->cmd_complete, 3*HZ);
++ if (timeout == 0) {
++ dev_WARN(dev->dev, "controller timed out\n");
++ i2c_dw_dump(dev);
++ trigger_all_cpu_backtrace();
++ if (dev->abort)
++ dev->abort(adap->nr);
+ i2c_dw_init(dev);
+ ret = -ETIMEDOUT;
+ goto done;
+- } else if (ret < 0)
+- goto done;
++ }
+
+ if (dev->msg_err) {
+ ret = dev->msg_err;
+@@ -597,7 +1251,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+ /* no error */
+ if (likely(!dev->cmd_err)) {
+ /* Disable the adapter */
+- __i2c_dw_enable(dev, false);
++ i2c_dw_disable(dev);
+ ret = num;
+ goto done;
+ }
+@@ -612,18 +1266,16 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+ done:
+ pm_runtime_mark_last_busy(dev->dev);
+ pm_runtime_put_autosuspend(dev->dev);
+- mutex_unlock(&dev->lock);
++ up(&dev->lock);
+
+ return ret;
+ }
+-EXPORT_SYMBOL_GPL(i2c_dw_xfer);
+
+ u32 i2c_dw_func(struct i2c_adapter *adap)
+ {
+ struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
+ return dev->functionality;
+ }
+-EXPORT_SYMBOL_GPL(i2c_dw_func);
+
+ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
+ {
+@@ -689,15 +1341,33 @@ irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
+ struct dw_i2c_dev *dev = dev_id;
+ u32 stat, enabled;
+
++ pm_runtime_get(dev->dev);
++#ifdef CONFIG_PM_RUNTIME
++ if (!pm_runtime_active(dev->dev)) {
++ pm_runtime_put_autosuspend(dev->dev);
++ if (dev->share_irq)
++ return IRQ_NONE;
++ else
++ return IRQ_HANDLED;
++ }
++#endif
+ enabled = dw_readl(dev, DW_IC_ENABLE);
+ stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
+ dev_dbg(dev->dev, "%s: %s enabled= 0x%x stat=0x%x\n", __func__,
+ dev->adapter.name, enabled, stat);
+- if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
+- return IRQ_NONE;
++ if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY)) {
++ pm_runtime_put_autosuspend(dev->dev);
++ if (dev->share_irq)
++ return IRQ_NONE;
++ else
++ return IRQ_HANDLED;
++ }
+
+ stat = i2c_dw_read_clear_intrbits(dev);
+
++ if (stat & DW_IC_INTR_RX_OVER)
++ dev_warn(dev->dev, "RX fifo overrun\n");
++
+ if (stat & DW_IC_INTR_TX_ABRT) {
+ dev->cmd_err |= DW_IC_ERR_TX_ABRT;
+ dev->status = STATUS_IDLE;
+@@ -723,25 +1393,49 @@ irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
+ */
+
+ tx_aborted:
+- if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err)
++ if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET))
++ || dev->msg_err) {
++ /*
++ * Check DW_IC_RXFLR register,
++ * read from the RX FIFO if it's not empty.
++ */
++ if ((stat & DW_IC_INTR_STOP_DET) &&
++ dw_readl(dev, DW_IC_RXFLR) > 0)
++ i2c_dw_read(dev);
++
+ complete(&dev->cmd_complete);
++ }
+
++ pm_runtime_put_autosuspend(dev->dev);
+ return IRQ_HANDLED;
+ }
+-EXPORT_SYMBOL_GPL(i2c_dw_isr);
+
+-void i2c_dw_enable(struct dw_i2c_dev *dev)
++u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev)
+ {
+- /* Enable the adapter */
+- __i2c_dw_enable(dev, true);
++ return dw_readl(dev, DW_IC_ENABLE_STATUS);
+ }
+-EXPORT_SYMBOL_GPL(i2c_dw_enable);
+
+-u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev)
++static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable)
++{
++ int timeout = 100;
++
++ do {
++ dw_writel(dev, enable, DW_IC_ENABLE);
++ if (i2c_dw_is_enabled(dev) == enable)
++ return;
++
++ usleep_range(25, 250);
++ } while (timeout-- > 0);
++
++ dev_warn(dev->dev, "timeout in %sabling adapter\n",
++ enable ? "en" : "dis");
++}
++
++void i2c_dw_enable(struct dw_i2c_dev *dev)
+ {
+- return dw_readl(dev, DW_IC_ENABLE);
++ /* Enable the adapter */
++ __i2c_dw_enable(dev, true);
+ }
+-EXPORT_SYMBOL_GPL(i2c_dw_is_enabled);
+
+ void i2c_dw_disable(struct dw_i2c_dev *dev)
+ {
+@@ -752,25 +1446,18 @@ void i2c_dw_disable(struct dw_i2c_dev *dev)
+ dw_writel(dev, 0, DW_IC_INTR_MASK);
+ dw_readl(dev, DW_IC_CLR_INTR);
+ }
+-EXPORT_SYMBOL_GPL(i2c_dw_disable);
+
+ void i2c_dw_clear_int(struct dw_i2c_dev *dev)
+ {
+ dw_readl(dev, DW_IC_CLR_INTR);
+ }
+-EXPORT_SYMBOL_GPL(i2c_dw_clear_int);
+
+ void i2c_dw_disable_int(struct dw_i2c_dev *dev)
+ {
+ dw_writel(dev, 0, DW_IC_INTR_MASK);
+ }
+-EXPORT_SYMBOL_GPL(i2c_dw_disable_int);
+
+ u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev)
+ {
+ return dw_readl(dev, DW_IC_COMP_PARAM_1);
+ }
+-EXPORT_SYMBOL_GPL(i2c_dw_read_comp_param);
+-
+-MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core");
+-MODULE_LICENSE("GPL");
+diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
+index e761ad1..4eb23a8 100644
+--- a/drivers/i2c/busses/i2c-designware-core.h
++++ b/drivers/i2c/busses/i2c-designware-core.h
+@@ -26,15 +26,171 @@
+ *
+ */
+
++/*
++ * Registers offset
++ */
++#define DW_IC_CON 0x0
++#define DW_IC_TAR 0x4
++#define DW_IC_DATA_CMD 0x10
++#define DW_IC_SS_SCL_HCNT 0x14
++#define DW_IC_SS_SCL_LCNT 0x18
++#define DW_IC_FS_SCL_HCNT 0x1c
++#define DW_IC_FS_SCL_LCNT 0x20
++#define DW_IC_HS_SCL_HCNT 0x24
++#define DW_IC_HS_SCL_LCNT 0x28
++#define DW_IC_INTR_STAT 0x2c
++#define DW_IC_INTR_MASK 0x30
++#define DW_IC_RAW_INTR_STAT 0x34
++#define DW_IC_RX_TL 0x38
++#define DW_IC_TX_TL 0x3c
++#define DW_IC_CLR_INTR 0x40
++#define DW_IC_CLR_RX_UNDER 0x44
++#define DW_IC_CLR_RX_OVER 0x48
++#define DW_IC_CLR_TX_OVER 0x4c
++#define DW_IC_CLR_RD_REQ 0x50
++#define DW_IC_CLR_TX_ABRT 0x54
++#define DW_IC_CLR_RX_DONE 0x58
++#define DW_IC_CLR_ACTIVITY 0x5c
++#define DW_IC_CLR_STOP_DET 0x60
++#define DW_IC_CLR_START_DET 0x64
++#define DW_IC_CLR_GEN_CALL 0x68
++#define DW_IC_ENABLE 0x6c
++#define DW_IC_STATUS 0x70
++#define DW_IC_TXFLR 0x74
++#define DW_IC_RXFLR 0x78
++#define DW_IC_TX_ABRT_SOURCE 0x80
++#define DW_IC_ENABLE_STATUS 0x9c
++#define DW_IC_COMP_PARAM_1 0xf4
++#define DW_IC_COMP_TYPE 0xfc
++#define DW_IC_COMP_TYPE_VALUE 0x44570140
+
+ #define DW_IC_CON_MASTER 0x1
+ #define DW_IC_CON_SPEED_STD 0x2
+ #define DW_IC_CON_SPEED_FAST 0x4
++#define DW_IC_CON_SPEED_HIGH 0x6
+ #define DW_IC_CON_10BITADDR_MASTER 0x10
+ #define DW_IC_CON_RESTART_EN 0x20
+ #define DW_IC_CON_SLAVE_DISABLE 0x40
+
++#define INTEL_MID_STD_CFG (DW_IC_CON_MASTER | \
++ DW_IC_CON_SLAVE_DISABLE | \
++ DW_IC_CON_RESTART_EN)
++
++#define DW_IC_INTR_RX_UNDER 0x001
++#define DW_IC_INTR_RX_OVER 0x002
++#define DW_IC_INTR_RX_FULL 0x004
++#define DW_IC_INTR_TX_OVER 0x008
++#define DW_IC_INTR_TX_EMPTY 0x010
++#define DW_IC_INTR_RD_REQ 0x020
++#define DW_IC_INTR_TX_ABRT 0x040
++#define DW_IC_INTR_RX_DONE 0x080
++#define DW_IC_INTR_ACTIVITY 0x100
++#define DW_IC_INTR_STOP_DET 0x200
++#define DW_IC_INTR_START_DET 0x400
++#define DW_IC_INTR_GEN_CALL 0x800
++
++#define DW_IC_INTR_DEFAULT_MASK (DW_IC_INTR_RX_FULL | \
++ DW_IC_INTR_TX_EMPTY | \
++ DW_IC_INTR_TX_ABRT | \
++ DW_IC_INTR_STOP_DET | \
++ DW_IC_INTR_RX_OVER)
++
++#define DW_IC_STATUS_ACTIVITY 0x1
++
++#define DW_IC_ERR_TX_ABRT 0x1
++
++#define DW_IC_CMD_STOP 0x200
++
++#define DW_IC_SPEED_MASK 0x6
++
++/*
++ * status codes
++ */
++#define STATUS_POWERON 0x0
++#define STATUS_IDLE STATUS_POWERON
++#define STATUS_WRITE_IN_PROGRESS 0x1
++#define STATUS_READ_IN_PROGRESS 0x2
++
++#define TIMEOUT 20 /* ms */
++
++/*
++ * hardware abort codes from the DW_IC_TX_ABRT_SOURCE register
++ *
++ * only expected abort codes are listed here
++ * refer to the datasheet for the full list
++ */
++#define ABRT_7B_ADDR_NOACK 0
++#define ABRT_10ADDR1_NOACK 1
++#define ABRT_10ADDR2_NOACK 2
++#define ABRT_TXDATA_NOACK 3
++#define ABRT_GCALL_NOACK 4
++#define ABRT_GCALL_READ 5
++#define ABRT_SBYTE_ACKDET 7
++#define ABRT_SBYTE_NORSTRT 9
++#define ABRT_10B_RD_NORSTRT 10
++#define ABRT_MASTER_DIS 11
++#define ARB_LOST 12
++
++#define DW_IC_TX_ABRT_7B_ADDR_NOACK (1UL << ABRT_7B_ADDR_NOACK)
++#define DW_IC_TX_ABRT_10ADDR1_NOACK (1UL << ABRT_10ADDR1_NOACK)
++#define DW_IC_TX_ABRT_10ADDR2_NOACK (1UL << ABRT_10ADDR2_NOACK)
++#define DW_IC_TX_ABRT_TXDATA_NOACK (1UL << ABRT_TXDATA_NOACK)
++#define DW_IC_TX_ABRT_GCALL_NOACK (1UL << ABRT_GCALL_NOACK)
++#define DW_IC_TX_ABRT_GCALL_READ (1UL << ABRT_GCALL_READ)
++#define DW_IC_TX_ABRT_SBYTE_ACKDET (1UL << ABRT_SBYTE_ACKDET)
++#define DW_IC_TX_ABRT_SBYTE_NORSTRT (1UL << ABRT_SBYTE_NORSTRT)
++#define DW_IC_TX_ABRT_10B_RD_NORSTRT (1UL << ABRT_10B_RD_NORSTRT)
++#define DW_IC_TX_ABRT_MASTER_DIS (1UL << ABRT_MASTER_DIS)
++#define DW_IC_TX_ARB_LOST (1UL << ARB_LOST)
+
++#define DW_IC_TX_ABRT_NOACK (DW_IC_TX_ABRT_7B_ADDR_NOACK | \
++ DW_IC_TX_ABRT_10ADDR1_NOACK | \
++ DW_IC_TX_ABRT_10ADDR2_NOACK | \
++ DW_IC_TX_ABRT_TXDATA_NOACK | \
++ DW_IC_TX_ABRT_GCALL_NOACK)
++
++/*
++ * i2c scl hcnt/lcnt setting
++ */
++#define PNW_SS_SCLK_HCNT 0x1EC
++#define PNW_SS_SCLK_LCNT 0x1F3
++#define PNW_FS_SCLK_HCNT 0x66
++#define PNW_FS_SCLK_LCNT 0x8B
++#define PNW_HS_SCLK_HCNT 0x9
++#define PNW_HS_SCLK_LCNT 0x17
++
++#define CLV_SS_SCLK_HCNT 0x1EC
++#define CLV_SS_SCLK_LCNT 0x1F3
++#define CLV_FS_SCLK_HCNT 0x59
++#define CLV_FS_SCLK_LCNT 0x98
++#define CLV_HS_SCLK_HCNT 0x8
++#define CLV_HS_SCLK_LCNT 0x17
++
++/* inofficial configuration
++#define MERR_SS_SCLK_HCNT 0x2c8
++#define MERR_SS_SCLK_LCNT 0x380
++#define MERR_FS_SCLK_HCNT 0x084
++#define MERR_FS_SCLK_LCNT 0x100
++*/
++#define MERR_SS_SCLK_HCNT 0x2f8
++#define MERR_SS_SCLK_LCNT 0x37b
++#define MERR_FS_SCLK_HCNT 0x087
++#define MERR_FS_SCLK_LCNT 0x10a
++#define MERR_HS_SCLK_HCNT 0x8
++#define MERR_HS_SCLK_LCNT 0x20
++
++#define VLV2_SS_SCLK_HCNT 0x214
++#define VLV2_SS_SCLK_LCNT 0x272
++#define VLV2_FS_SCLK_HCNT 0x50
++#define VLV2_FS_SCLK_LCNT 0xad
++#define VLV2_HS_SCLK_HCNT 0x6
++#define VLV2_HS_SCLK_LCNT 0x16
++
++#define DW_STD_SPEED 100000
++#define DW_FAST_SPEED 400000
++#define DW_HIGH_SPEED 3400000
++
++struct dw_controller;
+ /**
+ * struct dw_i2c_dev - private i2c-designware data
+ * @dev: driver model device node
+@@ -60,16 +216,20 @@
+ * @adapter: i2c subsystem adapter node
+ * @tx_fifo_depth: depth of the hardware tx fifo
+ * @rx_fifo_depth: depth of the hardware rx fifo
+- * @rx_outstanding: current master-rx elements in tx fifo
+ */
+ struct dw_i2c_dev {
+ struct device *dev;
+ void __iomem *base;
+ struct completion cmd_complete;
+- struct mutex lock;
++ struct semaphore lock;
+ struct clk *clk;
+ u32 (*get_clk_rate_khz) (struct dw_i2c_dev *dev);
+- struct dw_pci_controller *controller;
++ int (*get_scl_cfg) (struct dw_i2c_dev *dev);
++ void (*reset)(struct dw_i2c_dev *dev);
++ int (*abort)(int busnum);
++ struct dw_controller *controller;
++ int enable_stop;
++ int share_irq;
+ int cmd_err;
+ struct i2c_msg *msgs;
+ int msgs_num;
+@@ -83,28 +243,81 @@ struct dw_i2c_dev {
+ unsigned int status;
+ u32 abort_source;
+ int irq;
+- u32 accessor_flags;
++ int swab;
+ struct i2c_adapter adapter;
+ u32 functionality;
+ u32 master_cfg;
+ unsigned int tx_fifo_depth;
+ unsigned int rx_fifo_depth;
+- int rx_outstanding;
++ int use_dyn_clk; /* use dynamic clk setting */
++ u32 clk_khz; /* input clock */
++ u32 speed_cfg;
++ u32 lock_flag;
++ u32 freq;
++};
++
++struct dw_controller {
++ u32 bus_num;
++ u32 bus_cfg;
++ u32 tx_fifo_depth;
++ u32 rx_fifo_depth;
++ u32 clk_khz;
++ int enable_stop;
++ int share_irq;
++ char *acpi_name;
++ int (*scl_cfg) (struct dw_i2c_dev *dev);
++ void (*reset)(struct dw_i2c_dev *dev);
++};
++
++enum dw_ctl_id_t {
++ moorestown_0,
++ moorestown_1,
++ moorestown_2,
++
++ medfield_0,
++ medfield_1,
++ medfield_2,
++ medfield_3,
++ medfield_4,
++ medfield_5,
++
++ cloverview_0,
++ cloverview_1,
++ cloverview_2,
++ cloverview_3,
++ cloverview_4,
++ cloverview_5,
++
++ merrifield_0,
++ merrifield_1,
++ merrifield_2,
++ merrifield_3,
++ merrifield_4,
++ merrifield_5,
++ merrifield_6,
++
++ valleyview_0,
++ valleyview_1,
++ valleyview_2,
++ valleyview_3,
++ valleyview_4,
++ valleyview_5,
++ valleyview_6,
++
++ cherryview_0 = valleyview_0,
++ cherryview_1 = valleyview_1,
++ cherryview_2 = valleyview_2,
++ cherryview_3 = valleyview_3,
++ cherryview_4 = valleyview_4,
++ cherryview_5 = valleyview_5,
++ cherryview_6 = valleyview_6,
+ };
+
+-#define ACCESS_SWAP 0x00000001
+-#define ACCESS_16BIT 0x00000002
+-
+-extern u32 dw_readl(struct dw_i2c_dev *dev, int offset);
+-extern void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset);
+-extern int i2c_dw_init(struct dw_i2c_dev *dev);
+-extern int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
+- int num);
+-extern u32 i2c_dw_func(struct i2c_adapter *adap);
+-extern irqreturn_t i2c_dw_isr(int this_irq, void *dev_id);
+-extern void i2c_dw_enable(struct dw_i2c_dev *dev);
+-extern u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev);
+-extern void i2c_dw_disable(struct dw_i2c_dev *dev);
+-extern void i2c_dw_clear_int(struct dw_i2c_dev *dev);
+-extern void i2c_dw_disable_int(struct dw_i2c_dev *dev);
+-extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev);
++extern int intel_mid_dw_i2c_abort(int busnum);
++int i2c_dw_init(struct dw_i2c_dev *dev);
++struct dw_i2c_dev *i2c_dw_setup(struct device *pdev, int bus_idx,
++ unsigned long start, unsigned long len, int irq);
++void i2c_dw_free(struct device *pdev, struct dw_i2c_dev *dev);
++int i2c_dw_suspend(struct dw_i2c_dev *dev, bool runtime);
++int i2c_dw_resume(struct dw_i2c_dev *dev, bool runtime);
++void i2c_acpi_devices_setup(struct device *pdev, struct dw_i2c_dev *dev);
+diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c
+index f6ed06c..b150bc2 100644
+--- a/drivers/i2c/busses/i2c-designware-pcidrv.c
++++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
+@@ -39,113 +39,32 @@
+ #include <linux/slab.h>
+ #include <linux/pci.h>
+ #include <linux/pm_runtime.h>
++#include <linux/semaphore.h>
++#include <linux/fs.h>
++#include <linux/acpi.h>
+ #include "i2c-designware-core.h"
+
+ #define DRIVER_NAME "i2c-designware-pci"
++#define DW_I2C_STATIC_BUS_NUM 10
+
+-enum dw_pci_ctl_id_t {
+- moorestown_0,
+- moorestown_1,
+- moorestown_2,
+-
+- medfield_0,
+- medfield_1,
+- medfield_2,
+- medfield_3,
+- medfield_4,
+- medfield_5,
+-};
++static int i2c_dw_pci_suspend(struct device *dev)
++{
++ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
++ struct dw_i2c_dev *i2c = pci_get_drvdata(pdev);
+
+-struct dw_pci_controller {
+- u32 bus_num;
+- u32 bus_cfg;
+- u32 tx_fifo_depth;
+- u32 rx_fifo_depth;
+- u32 clk_khz;
+-};
++ dev_dbg(dev, "suspend called\n");
+
+-#define INTEL_MID_STD_CFG (DW_IC_CON_MASTER | \
+- DW_IC_CON_SLAVE_DISABLE | \
+- DW_IC_CON_RESTART_EN)
+-
+-static struct dw_pci_controller dw_pci_controllers[] = {
+- [moorestown_0] = {
+- .bus_num = 0,
+- .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+- .tx_fifo_depth = 32,
+- .rx_fifo_depth = 32,
+- .clk_khz = 25000,
+- },
+- [moorestown_1] = {
+- .bus_num = 1,
+- .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+- .tx_fifo_depth = 32,
+- .rx_fifo_depth = 32,
+- .clk_khz = 25000,
+- },
+- [moorestown_2] = {
+- .bus_num = 2,
+- .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+- .tx_fifo_depth = 32,
+- .rx_fifo_depth = 32,
+- .clk_khz = 25000,
+- },
+- [medfield_0] = {
+- .bus_num = 0,
+- .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+- .tx_fifo_depth = 32,
+- .rx_fifo_depth = 32,
+- .clk_khz = 25000,
+- },
+- [medfield_1] = {
+- .bus_num = 1,
+- .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+- .tx_fifo_depth = 32,
+- .rx_fifo_depth = 32,
+- .clk_khz = 25000,
+- },
+- [medfield_2] = {
+- .bus_num = 2,
+- .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+- .tx_fifo_depth = 32,
+- .rx_fifo_depth = 32,
+- .clk_khz = 25000,
+- },
+- [medfield_3] = {
+- .bus_num = 3,
+- .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_STD,
+- .tx_fifo_depth = 32,
+- .rx_fifo_depth = 32,
+- .clk_khz = 25000,
+- },
+- [medfield_4] = {
+- .bus_num = 4,
+- .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+- .tx_fifo_depth = 32,
+- .rx_fifo_depth = 32,
+- .clk_khz = 25000,
+- },
+- [medfield_5] = {
+- .bus_num = 5,
+- .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+- .tx_fifo_depth = 32,
+- .rx_fifo_depth = 32,
+- .clk_khz = 25000,
+- },
+-};
+-static struct i2c_algorithm i2c_dw_algo = {
+- .master_xfer = i2c_dw_xfer,
+- .functionality = i2c_dw_func,
+-};
++ return i2c_dw_suspend(i2c, false);
++}
+
+-static int i2c_dw_pci_suspend(struct device *dev)
++static int i2c_dw_pci_runtime_suspend(struct device *dev)
+ {
+ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+ struct dw_i2c_dev *i2c = pci_get_drvdata(pdev);
+ int err;
+
+-
+- i2c_dw_disable(i2c);
++ dev_dbg(dev, "runtime suspend called\n");
++ i2c_dw_suspend(i2c, true);
+
+ err = pci_save_state(pdev);
+ if (err) {
+@@ -166,130 +85,86 @@ static int i2c_dw_pci_resume(struct device *dev)
+ {
+ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+ struct dw_i2c_dev *i2c = pci_get_drvdata(pdev);
+- int err;
+- u32 enabled;
+
+- enabled = i2c_dw_is_enabled(i2c);
+- if (enabled)
+- return 0;
++ dev_dbg(dev, "resume called\n");
++ return i2c_dw_resume(i2c, false);
++}
++
++static int i2c_dw_pci_runtime_resume(struct device *dev)
++{
++ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
++ struct dw_i2c_dev *i2c = pci_get_drvdata(pdev);
++ int err;
+
++ dev_dbg(dev, "runtime resume called\n");
+ err = pci_set_power_state(pdev, PCI_D0);
+ if (err) {
+ dev_err(&pdev->dev, "pci_set_power_state() failed\n");
+ return err;
+ }
+-
+ pci_restore_state(pdev);
++ i2c_dw_resume(i2c, true);
+
+- i2c_dw_init(i2c);
+ return 0;
+ }
+
+-static int i2c_dw_pci_runtime_idle(struct device *dev)
+-{
+- int err = pm_schedule_suspend(dev, 500);
+- dev_dbg(dev, "runtime_idle called\n");
+-
+- if (err != 0)
+- return 0;
+- return -EBUSY;
+-}
+-
+ static const struct dev_pm_ops i2c_dw_pm_ops = {
+- .resume = i2c_dw_pci_resume,
+- .suspend = i2c_dw_pci_suspend,
+- SET_RUNTIME_PM_OPS(i2c_dw_pci_suspend, i2c_dw_pci_resume,
+- i2c_dw_pci_runtime_idle)
++ .suspend_late = i2c_dw_pci_suspend,
++ .resume_early = i2c_dw_pci_resume,
++ SET_RUNTIME_PM_OPS(i2c_dw_pci_runtime_suspend,
++ i2c_dw_pci_runtime_resume,
++ NULL)
+ };
+
+-static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
+-{
+- return dev->controller->clk_khz;
+-}
+-
+ static int i2c_dw_pci_probe(struct pci_dev *pdev,
+- const struct pci_device_id *id)
++const struct pci_device_id *id)
+ {
+ struct dw_i2c_dev *dev;
+- struct i2c_adapter *adap;
++ unsigned long start, len;
+ int r;
+- struct dw_pci_controller *controller;
+-
+- if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) {
+- dev_err(&pdev->dev, "%s: invalid driver data %ld\n", __func__,
+- id->driver_data);
+- return -EINVAL;
+- }
++ int bus_idx;
++ static int bus_num;
+
+- controller = &dw_pci_controllers[id->driver_data];
++ bus_idx = id->driver_data + bus_num;
++ bus_num++;
+
+- r = pcim_enable_device(pdev);
++ r = pci_enable_device(pdev);
+ if (r) {
+ dev_err(&pdev->dev, "Failed to enable I2C PCI device (%d)\n",
+ r);
+ return r;
+ }
+
+- r = pcim_iomap_regions(pdev, 1 << 0, pci_name(pdev));
++ /* Determine the address of the I2C area */
++ start = pci_resource_start(pdev, 0);
++ len = pci_resource_len(pdev, 0);
++ if (!start || len == 0) {
++ dev_err(&pdev->dev, "base address not set\n");
++ return -ENODEV;
++ }
++
++ r = pci_request_region(pdev, 0, DRIVER_NAME);
+ if (r) {
+- dev_err(&pdev->dev, "I/O memory remapping failed\n");
++ dev_err(&pdev->dev, "failed to request I2C region "
++ "0x%lx-0x%lx\n", start,
++ (unsigned long)pci_resource_end(pdev, 0));
+ return r;
+ }
+
+- dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL);
+- if (!dev)
+- return -ENOMEM;
+-
+- init_completion(&dev->cmd_complete);
+- mutex_init(&dev->lock);
+- dev->clk = NULL;
+- dev->controller = controller;
+- dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
+- dev->base = pcim_iomap_table(pdev)[0];
+- dev->dev = &pdev->dev;
+- dev->functionality =
+- I2C_FUNC_I2C |
+- I2C_FUNC_SMBUS_BYTE |
+- I2C_FUNC_SMBUS_BYTE_DATA |
+- I2C_FUNC_SMBUS_WORD_DATA |
+- I2C_FUNC_SMBUS_I2C_BLOCK;
+- dev->master_cfg = controller->bus_cfg;
++ dev = i2c_dw_setup(&pdev->dev, bus_idx, start, len, pdev->irq);
++ if (IS_ERR(dev)) {
++ pci_release_region(pdev, 0);
++ dev_err(&pdev->dev, "failed to setup i2c\n");
++ return -EINVAL;
++ }
+
+ pci_set_drvdata(pdev, dev);
+
+- dev->tx_fifo_depth = controller->tx_fifo_depth;
+- dev->rx_fifo_depth = controller->rx_fifo_depth;
+- r = i2c_dw_init(dev);
+- if (r)
+- return r;
+-
+- adap = &dev->adapter;
+- i2c_set_adapdata(adap, dev);
+- adap->owner = THIS_MODULE;
+- adap->class = 0;
+- adap->algo = &i2c_dw_algo;
+- adap->dev.parent = &pdev->dev;
+- adap->nr = controller->bus_num;
+- snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci-%d",
+- adap->nr);
+-
+- r = devm_request_irq(&pdev->dev, pdev->irq, i2c_dw_isr, IRQF_SHARED,
+- adap->name, dev);
+- if (r) {
+- dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
+- return r;
+- }
+-
+- i2c_dw_disable_int(dev);
+- i2c_dw_clear_int(dev);
+- r = i2c_add_numbered_adapter(adap);
+- if (r) {
+- dev_err(&pdev->dev, "failure adding adapter\n");
+- return r;
+- }
++ i2c_acpi_devices_setup(&pdev->dev, dev);
+
+- pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
++ pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
+ pm_runtime_use_autosuspend(&pdev->dev);
++ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_allow(&pdev->dev);
+
+ return 0;
+@@ -299,35 +174,60 @@ static void i2c_dw_pci_remove(struct pci_dev *pdev)
+ {
+ struct dw_i2c_dev *dev = pci_get_drvdata(pdev);
+
+- i2c_dw_disable(dev);
+ pm_runtime_forbid(&pdev->dev);
+- pm_runtime_get_noresume(&pdev->dev);
+-
+- i2c_del_adapter(&dev->adapter);
++ i2c_dw_free(&pdev->dev, dev);
++ pci_set_drvdata(pdev, NULL);
++ pci_release_region(pdev, 0);
+ }
+
+ /* work with hotplug and coldplug */
+ MODULE_ALIAS("i2c_designware-pci");
+
+-static DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = {
++DEFINE_PCI_DEVICE_TABLE(i2c_designware_pci_ids) = {
+ /* Moorestown */
+ { PCI_VDEVICE(INTEL, 0x0802), moorestown_0 },
+- { PCI_VDEVICE(INTEL, 0x0803), moorestown_1 },
+- { PCI_VDEVICE(INTEL, 0x0804), moorestown_2 },
++ { PCI_VDEVICE(INTEL, 0x0803), moorestown_0 },
++ { PCI_VDEVICE(INTEL, 0x0804), moorestown_0 },
+ /* Medfield */
+- { PCI_VDEVICE(INTEL, 0x0817), medfield_3,},
+- { PCI_VDEVICE(INTEL, 0x0818), medfield_4 },
+- { PCI_VDEVICE(INTEL, 0x0819), medfield_5 },
++ { PCI_VDEVICE(INTEL, 0x0817), medfield_0 },
++ { PCI_VDEVICE(INTEL, 0x0818), medfield_0 },
++ { PCI_VDEVICE(INTEL, 0x0819), medfield_0 },
+ { PCI_VDEVICE(INTEL, 0x082C), medfield_0 },
+- { PCI_VDEVICE(INTEL, 0x082D), medfield_1 },
+- { PCI_VDEVICE(INTEL, 0x082E), medfield_2 },
++ { PCI_VDEVICE(INTEL, 0x082D), medfield_0 },
++ { PCI_VDEVICE(INTEL, 0x082E), medfield_0 },
++ /* Cloverview */
++ { PCI_VDEVICE(INTEL, 0x08E2), cloverview_0 },
++ { PCI_VDEVICE(INTEL, 0x08E3), cloverview_0 },
++ { PCI_VDEVICE(INTEL, 0x08E4), cloverview_0 },
++ { PCI_VDEVICE(INTEL, 0x08F4), cloverview_0 },
++ { PCI_VDEVICE(INTEL, 0x08F5), cloverview_0 },
++ { PCI_VDEVICE(INTEL, 0x08F6), cloverview_0 },
++ /* Merrifield */
++ { PCI_VDEVICE(INTEL, 0x1195), merrifield_0 },
++ { PCI_VDEVICE(INTEL, 0x1196), merrifield_0 },
++ /* Valleyview 2 */
++ { PCI_VDEVICE(INTEL, 0x0F41), valleyview_0 },
++ { PCI_VDEVICE(INTEL, 0x0F42), valleyview_0 },
++ { PCI_VDEVICE(INTEL, 0x0F43), valleyview_0 },
++ { PCI_VDEVICE(INTEL, 0x0F44), valleyview_0 },
++ { PCI_VDEVICE(INTEL, 0x0F45), valleyview_0 },
++ { PCI_VDEVICE(INTEL, 0x0F46), valleyview_0 },
++ { PCI_VDEVICE(INTEL, 0x0F47), valleyview_0 },
++ /* Cherryview */
++ { PCI_VDEVICE(INTEL, 0x22C1), cherryview_0 },
++ { PCI_VDEVICE(INTEL, 0x22C2), cherryview_0 },
++ { PCI_VDEVICE(INTEL, 0x22C3), cherryview_0 },
++ { PCI_VDEVICE(INTEL, 0x22C4), cherryview_0 },
++ { PCI_VDEVICE(INTEL, 0x22C5), cherryview_0 },
++ { PCI_VDEVICE(INTEL, 0x22C6), cherryview_0 },
++ { PCI_VDEVICE(INTEL, 0x22C7), cherryview_0 },
+ { 0,}
+ };
+-MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids);
++MODULE_DEVICE_TABLE(pci, i2c_designware_pci_ids);
+
+ static struct pci_driver dw_i2c_driver = {
+ .name = DRIVER_NAME,
+- .id_table = i2_designware_pci_ids,
++ .id_table = i2c_designware_pci_ids,
+ .probe = i2c_dw_pci_probe,
+ .remove = i2c_dw_pci_remove,
+ .driver = {
+@@ -335,7 +235,38 @@ static struct pci_driver dw_i2c_driver = {
+ },
+ };
+
+-module_pci_driver(dw_i2c_driver);
++static int __init dw_i2c_init_driver(void)
++{
++ return pci_register_driver(&dw_i2c_driver);
++}
++module_init(dw_i2c_init_driver);
++
++static void __exit dw_i2c_exit_driver(void)
++{
++ pci_unregister_driver(&dw_i2c_driver);
++}
++module_exit(dw_i2c_exit_driver);
++
++#ifndef MODULE
++static int __init dw_i2c_reserve_static_bus(void)
++{
++ struct i2c_board_info dummy = {
++ I2C_BOARD_INFO("dummy", 0xff),
++ };
++
++ i2c_register_board_info(DW_I2C_STATIC_BUS_NUM, &dummy, 1);
++ return 0;
++}
++subsys_initcall(dw_i2c_reserve_static_bus);
++
++static void dw_i2c_pci_final_quirks(struct pci_dev *pdev)
++{
++ pdev->pm_cap = 0x80;
++}
++
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0F44,
++ dw_i2c_pci_final_quirks);
++#endif
+
+ MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
+ MODULE_DESCRIPTION("Synopsys DesignWare PCI I2C bus adapter");
+diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
+index 35b70a1..96a3bcf 100644
+--- a/drivers/i2c/busses/i2c-designware-platdrv.c
++++ b/drivers/i2c/busses/i2c-designware-platdrv.c
+@@ -34,58 +34,94 @@
+ #include <linux/sched.h>
+ #include <linux/err.h>
+ #include <linux/interrupt.h>
+-#include <linux/of_i2c.h>
+ #include <linux/platform_device.h>
+-#include <linux/pm.h>
+-#include <linux/pm_runtime.h>
+ #include <linux/io.h>
+ #include <linux/slab.h>
+ #include <linux/acpi.h>
++#include <linux/pci.h>
++#include <linux/pm_runtime.h>
+ #include "i2c-designware-core.h"
+
+-static struct i2c_algorithm i2c_dw_algo = {
+- .master_xfer = i2c_dw_xfer,
+- .functionality = i2c_dw_func,
++#ifdef CONFIG_ACPI
++static const struct acpi_device_id dw_i2c_acpi_ids[] = {
++ { "80860F41", valleyview_0 },
++ { "808622C1", cherryview_0 },
++ { }
+ };
+-static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
++MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_ids);
++#endif
++
++static int dw_i2c_plat_suspend(struct device *dev)
+ {
+- return clk_get_rate(dev->clk)/1000;
++ struct platform_device *pdev =
++ container_of(dev, struct platform_device, dev);
++ struct dw_i2c_dev *i2c = platform_get_drvdata(pdev);
++
++ dev_dbg(dev, "suspend called\n");
++ return i2c_dw_suspend(i2c, false);
+ }
+
+-#ifdef CONFIG_ACPI
+-static int dw_i2c_acpi_configure(struct platform_device *pdev)
++static int dw_i2c_plat_runtime_suspend(struct device *dev)
+ {
+- struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
++ struct platform_device *pdev =
++ container_of(dev, struct platform_device, dev);
++ struct dw_i2c_dev *i2c = platform_get_drvdata(pdev);
+
+- if (!ACPI_HANDLE(&pdev->dev))
+- return -ENODEV;
++ dev_dbg(dev, "runtime suspend called\n");
++ i2c_dw_suspend(i2c, true);
+
+- dev->adapter.nr = -1;
+- dev->tx_fifo_depth = 32;
+- dev->rx_fifo_depth = 32;
+ return 0;
+ }
+
+-static const struct acpi_device_id dw_i2c_acpi_match[] = {
+- { "INT33C2", 0 },
+- { "INT33C3", 0 },
+- { "80860F41", 0 },
+- { }
+-};
+-MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
+-#else
+-static inline int dw_i2c_acpi_configure(struct platform_device *pdev)
++static int dw_i2c_plat_resume(struct device *dev)
+ {
+- return -ENODEV;
++ struct platform_device *pdev =
++ container_of(dev, struct platform_device, dev);
++ struct dw_i2c_dev *i2c = platform_get_drvdata(pdev);
++
++ dev_dbg(dev, "resume called\n");
++ return i2c_dw_resume(i2c, false);
+ }
+-#endif
+
+-static int dw_i2c_probe(struct platform_device *pdev)
++static int dw_i2c_plat_runtime_resume(struct device *dev)
++{
++ struct platform_device *pdev =
++ container_of(dev, struct platform_device, dev);
++ struct dw_i2c_dev *i2c = platform_get_drvdata(pdev);
++
++ dev_dbg(dev, "runtime resume called\n");
++ i2c_dw_resume(i2c, true);
++
++ return 0;
++}
++
++static const struct dev_pm_ops dw_i2c_plat_pm_ops = {
++ SET_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend,
++ dw_i2c_plat_resume)
++ SET_RUNTIME_PM_OPS(dw_i2c_plat_runtime_suspend,
++ dw_i2c_plat_runtime_resume,
++ NULL)
++};
++
++static int __init dw_i2c_probe(struct platform_device *pdev)
+ {
+ struct dw_i2c_dev *dev;
+- struct i2c_adapter *adap;
+- struct resource *mem;
+- int irq, r;
++ struct resource *mem, *ioarea;
++ const struct acpi_device_id *id;
++ unsigned long start, len;
++ int bus_idx = 0;
++ static int bus_num;
++ int irq;
++
++#ifdef CONFIG_ACPI
++ for (id = dw_i2c_acpi_ids; id->id[0]; id++)
++ if (!strncmp(id->id, dev_name(&pdev->dev), strlen(id->id))) {
++ bus_idx = id->driver_data + bus_num;
++ bus_num++;
++ }
++#else
++ bus_idx = pdev->id;
++#endif
+
+ /* NOTE: driver uses the static register mapping */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+@@ -93,6 +129,8 @@ static int dw_i2c_probe(struct platform_device *pdev)
+ dev_err(&pdev->dev, "no mem resource?\n");
+ return -EINVAL;
+ }
++ start = mem->start;
++ len = resource_size(mem);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+@@ -100,132 +138,46 @@ static int dw_i2c_probe(struct platform_device *pdev)
+ return irq; /* -ENXIO */
+ }
+
+- dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL);
+- if (!dev)
+- return -ENOMEM;
+-
+- dev->base = devm_ioremap_resource(&pdev->dev, mem);
+- if (IS_ERR(dev->base))
+- return PTR_ERR(dev->base);
+-
+- init_completion(&dev->cmd_complete);
+- mutex_init(&dev->lock);
+- dev->dev = &pdev->dev;
+- dev->irq = irq;
+- platform_set_drvdata(pdev, dev);
+-
+- dev->clk = devm_clk_get(&pdev->dev, NULL);
+- dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
+-
+- if (IS_ERR(dev->clk))
+- return PTR_ERR(dev->clk);
+- clk_prepare_enable(dev->clk);
+-
+- dev->functionality =
+- I2C_FUNC_I2C |
+- I2C_FUNC_10BIT_ADDR |
+- I2C_FUNC_SMBUS_BYTE |
+- I2C_FUNC_SMBUS_BYTE_DATA |
+- I2C_FUNC_SMBUS_WORD_DATA |
+- I2C_FUNC_SMBUS_I2C_BLOCK;
+- dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
+- DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
+-
+- /* Try first if we can configure the device from ACPI */
+- r = dw_i2c_acpi_configure(pdev);
+- if (r) {
+- u32 param1 = i2c_dw_read_comp_param(dev);
+-
+- dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1;
+- dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1;
+- dev->adapter.nr = pdev->id;
++ ioarea = request_mem_region(mem->start, resource_size(mem),
++ pdev->name);
++ if (!ioarea) {
++ dev_err(&pdev->dev, "I2C region already claimed\n");
++ return -EBUSY;
+ }
+- r = i2c_dw_init(dev);
+- if (r)
+- return r;
+
+- i2c_dw_disable_int(dev);
+- r = devm_request_irq(&pdev->dev, dev->irq, i2c_dw_isr, IRQF_SHARED,
+- pdev->name, dev);
+- if (r) {
+- dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
+- return r;
++ dev = i2c_dw_setup(&pdev->dev, bus_idx, start, len, irq);
++ if (IS_ERR(dev)) {
++ release_mem_region(mem->start, resource_size(mem));
++ dev_err(&pdev->dev, "failed to setup i2c\n");
++ return -EINVAL;
+ }
+
+- adap = &dev->adapter;
+- i2c_set_adapdata(adap, dev);
+- adap->owner = THIS_MODULE;
+- adap->class = I2C_CLASS_HWMON;
+- strlcpy(adap->name, "Synopsys DesignWare I2C adapter",
+- sizeof(adap->name));
+- adap->algo = &i2c_dw_algo;
+- adap->dev.parent = &pdev->dev;
+- adap->dev.of_node = pdev->dev.of_node;
++ platform_set_drvdata(pdev, dev);
+
+- r = i2c_add_numbered_adapter(adap);
+- if (r) {
+- dev_err(&pdev->dev, "failure adding adapter\n");
+- return r;
+- }
+- of_i2c_register_devices(adap);
+- acpi_i2c_register_devices(adap);
++ acpi_i2c_register_devices(&dev->adapter);
+
+- pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
+- pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
++ pm_runtime_allow(&pdev->dev);
++ pm_runtime_use_autosuspend(&pdev->dev);
++ pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
+
+ return 0;
+ }
+
+-static int dw_i2c_remove(struct platform_device *pdev)
++static int __exit dw_i2c_remove(struct platform_device *pdev)
+ {
+ struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
++ struct resource *mem;
+
+- pm_runtime_get_sync(&pdev->dev);
+-
+- i2c_del_adapter(&dev->adapter);
+-
+- i2c_dw_disable(dev);
+-
+- pm_runtime_put(&pdev->dev);
+- pm_runtime_disable(&pdev->dev);
+-
+- return 0;
+-}
+-
+-#ifdef CONFIG_OF
+-static const struct of_device_id dw_i2c_of_match[] = {
+- { .compatible = "snps,designware-i2c", },
+- {},
+-};
+-MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
+-#endif
+-
+-#ifdef CONFIG_PM
+-static int dw_i2c_suspend(struct device *dev)
+-{
+- struct platform_device *pdev = to_platform_device(dev);
+- struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
+-
+- clk_disable_unprepare(i_dev->clk);
+-
+- return 0;
+-}
+-
+-static int dw_i2c_resume(struct device *dev)
+-{
+- struct platform_device *pdev = to_platform_device(dev);
+- struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
+-
+- clk_prepare_enable(i_dev->clk);
+- i2c_dw_init(i_dev);
+-
++ pm_runtime_forbid(&pdev->dev);
++ i2c_dw_free(&pdev->dev, dev);
++ platform_set_drvdata(pdev, NULL);
++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (mem)
++ release_mem_region(mem->start, resource_size(mem));
+ return 0;
+ }
+-#endif
+-
+-static SIMPLE_DEV_PM_OPS(dw_i2c_dev_pm_ops, dw_i2c_suspend, dw_i2c_resume);
+
+ /* work with hotplug and coldplug */
+ MODULE_ALIAS("platform:i2c_designware");
+@@ -235,17 +187,32 @@ static struct platform_driver dw_i2c_driver = {
+ .driver = {
+ .name = "i2c_designware",
+ .owner = THIS_MODULE,
+- .of_match_table = of_match_ptr(dw_i2c_of_match),
+- .acpi_match_table = ACPI_PTR(dw_i2c_acpi_match),
+- .pm = &dw_i2c_dev_pm_ops,
++ .pm = &dw_i2c_plat_pm_ops,
++#ifdef CONFIG_ACPI
++ .acpi_match_table = ACPI_PTR(dw_i2c_acpi_ids),
++#endif
+ },
+ };
+
+ static int __init dw_i2c_init_driver(void)
+ {
++ struct pci_dev *dw_pci;
++
++ /*
++ * Try to get pci device, if exist, then exit ACPI platform
++ * register, On BYT FDK, include two enum mode: PCI, ACPI,
++ * ignore ACPI enum mode.
++ */
++ dw_pci = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0F41, NULL);
++ if (dw_pci) {
++ pr_info("DW I2C: Find I2C controller in PCI device, "
++ "exit ACPI platform register!\n");
++ return 0;
++ }
++
+ return platform_driver_probe(&dw_i2c_driver, dw_i2c_probe);
+ }
+-subsys_initcall(dw_i2c_init_driver);
++module_init(dw_i2c_init_driver);
+
+ static void __exit dw_i2c_exit_driver(void)
+ {
+diff --git a/drivers/i2c/busses/i2c-pmic-regs.h b/drivers/i2c/busses/i2c-pmic-regs.h
+new file mode 100644
+index 0000000..e5a55ff
+--- /dev/null
++++ b/drivers/i2c/busses/i2c-pmic-regs.h
+@@ -0,0 +1,78 @@
++/*
++ * i2c-pmic-regs.h - PMIC I2C registers
++ *
++ * Copyright (C) 2011 Intel Corporation
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * 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; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ * Author: Yegnesh Iyer <yegnesh.s.iyer@intel.com>
++ */
++
++#ifndef __I2C_PMIC_REGS_H__
++#define __I2C_PMIC_REGS_H__
++
++#include <linux/mutex.h>
++
++/*********************************************************************
++ * Generic defines
++ *********************************************************************/
++
++#define D7 (1 << 7)
++#define D6 (1 << 6)
++#define D5 (1 << 5)
++#define D4 (1 << 4)
++#define D3 (1 << 3)
++#define D2 (1 << 2)
++#define D1 (1 << 1)
++#define D0 (1 << 0)
++
++#define PMIC_SRAM_INTR_ADDR 0xFFFFF616
++
++#define I2C_MSG_LEN 4
++
++#define I2COVRCTRL_ADDR 0x58
++#define I2COVRDADDR_ADDR 0x59
++#define I2COVROFFSET_ADDR 0x5A
++#define I2COVRWRDATA_ADDR 0x5B
++#define I2COVRRDDATA_ADDR 0x5C
++
++#define IRQLVL1_ADDR 0x01
++#define IRQLVL1_MASK_ADDR 0x0c
++#define IRQLVL1_CHRGR_MASK D5
++
++#define MCHGRIRQ1_ADDR 0x13
++#define MCHGRIRQ0_ADDR 0x12
++
++#define PMIC_I2C_INTR_MASK ((u8)(D3|D2|D1))
++#define I2COVRCTRL_I2C_RD D1
++#define I2COVRCTRL_I2C_WR D0
++#define CHGRIRQ0_ADDR 0x07
++
++#define IRQ0_I2C_BIT_POS 1
++
++struct pmic_i2c_dev {
++ int irq;
++ u32 pmic_intr_sram_addr;
++ struct i2c_adapter adapter;
++ int i2c_rw;
++ wait_queue_head_t i2c_wait;
++ struct mutex i2c_pmic_rw_lock;
++ void __iomem *pmic_intr_map;
++ struct device *dev;
++};
++
++#endif
+diff --git a/drivers/i2c/busses/i2c-pmic.c b/drivers/i2c/busses/i2c-pmic.c
+new file mode 100644
+index 0000000..9e96f10
+--- /dev/null
++++ b/drivers/i2c/busses/i2c-pmic.c
+@@ -0,0 +1,452 @@
++/*
++ * i2c-pmic.c: PMIC I2C adapter driver.
++ *
++ * Copyright (C) 2011 Intel Corporation
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * 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; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ * Author: Yegnesh Iyer <yegnesh.s.iyer@intel.com>
++ */
++
++#include <linux/slab.h>
++#include <linux/rpmsg.h>
++#include <linux/platform_device.h>
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/i2c.h>
++#include <linux/power_supply.h>
++#include <linux/interrupt.h>
++#include <linux/completion.h>
++#include <linux/pm_runtime.h>
++#include <asm/intel_scu_pmic.h>
++#include <asm/intel_mid_rpmsg.h>
++#include <asm/intel_mid_remoteproc.h>
++#include "i2c-pmic-regs.h"
++
++#define DRIVER_NAME "i2c_pmic_adap"
++#define PMIC_I2C_ADAPTER 8
++
++enum I2C_STATUS {
++ I2C_WR = 1,
++ I2C_RD,
++ I2C_NACK = 4
++};
++
++static struct pmic_i2c_dev *pmic_dev;
++
++/* Function Definitions */
++
++/* PMIC I2C read-write completion interrupt handler */
++static irqreturn_t pmic_i2c_handler(int irq, void *data)
++{
++ u8 irq0_int;
++
++ irq0_int = ioread8(pmic_dev->pmic_intr_map);
++ irq0_int &= PMIC_I2C_INTR_MASK;
++
++ if (irq0_int) {
++ pmic_dev->i2c_rw = (irq0_int >> IRQ0_I2C_BIT_POS);
++ return IRQ_WAKE_THREAD;
++ }
++
++ return IRQ_NONE;
++}
++
++
++static irqreturn_t pmic_thread_handler(int id, void *data)
++{
++#define IRQLVL1_MASK_ADDR 0x0c
++#define IRQLVL1_CHRGR_MASK D5
++
++ dev_dbg(pmic_dev->dev, "Clearing IRQLVL1_MASK_ADDR\n");
++
++ intel_scu_ipc_update_register(IRQLVL1_MASK_ADDR, 0x00,
++ IRQLVL1_CHRGR_MASK);
++ wake_up(&(pmic_dev->i2c_wait));
++ return IRQ_HANDLED;
++}
++
++/* PMIC i2c read msg */
++static inline int pmic_i2c_read_xfer(struct i2c_msg msg)
++{
++ int ret;
++ u16 i;
++ u8 mask = (I2C_RD | I2C_NACK);
++ u16 regs[I2C_MSG_LEN] = {0};
++ u8 data[I2C_MSG_LEN] = {0};
++
++ for (i = 0; i < msg.len ; i++) {
++ pmic_dev->i2c_rw = 0;
++ regs[0] = I2COVRDADDR_ADDR;
++ data[0] = msg.addr;
++ regs[1] = I2COVROFFSET_ADDR;
++ data[1] = msg.buf[0] + i;
++ /* intel_scu_ipc_function works fine for even number of bytes */
++ /* Hence adding a dummy byte transfer */
++ regs[2] = I2COVROFFSET_ADDR;
++ data[2] = msg.buf[0] + i;
++ regs[3] = I2COVRCTRL_ADDR;
++ data[3] = I2COVRCTRL_I2C_RD;
++ ret = intel_scu_ipc_writev(regs, data, I2C_MSG_LEN);
++ if (unlikely(ret))
++ return ret;
++
++ ret = wait_event_timeout(pmic_dev->i2c_wait,
++ (pmic_dev->i2c_rw & mask),
++ HZ);
++
++ if (ret == 0) {
++ ret = -ETIMEDOUT;
++ goto read_err_exit;
++ } else if (pmic_dev->i2c_rw == I2C_NACK) {
++ ret = -EIO;
++ goto read_err_exit;
++ } else {
++ ret = intel_scu_ipc_ioread8(I2COVRRDDATA_ADDR,
++ &(msg.buf[i]));
++ if (unlikely(ret)) {
++ ret = -EIO;
++ goto read_err_exit;
++ }
++ }
++ }
++ return 0;
++
++read_err_exit:
++ return ret;
++}
++
++/* PMIC i2c write msg */
++static inline int pmic_i2c_write_xfer(struct i2c_msg msg)
++{
++ int ret;
++ u16 i;
++ u8 mask = (I2C_WR | I2C_NACK);
++ u16 regs[I2C_MSG_LEN] = {0};
++ u8 data[I2C_MSG_LEN] = {0};
++
++ for (i = 1; i <= msg.len ; i++) {
++ pmic_dev->i2c_rw = 0;
++ regs[0] = I2COVRDADDR_ADDR;
++ data[0] = msg.addr;
++ regs[1] = I2COVRWRDATA_ADDR;
++ data[1] = msg.buf[i];
++ regs[2] = I2COVROFFSET_ADDR;
++ data[2] = msg.buf[0] + i - 1;
++ regs[3] = I2COVRCTRL_ADDR;
++ data[3] = I2COVRCTRL_I2C_WR;
++ ret = intel_scu_ipc_writev(regs, data, I2C_MSG_LEN);
++ if (unlikely(ret))
++ return ret;
++
++ ret = wait_event_timeout(pmic_dev->i2c_wait,
++ (pmic_dev->i2c_rw & mask),
++ HZ);
++ if (ret == 0)
++ return -ETIMEDOUT;
++ else if (pmic_dev->i2c_rw == I2C_NACK)
++ return -EIO;
++ }
++ return 0;
++}
++
++static int (*xfer_fn[]) (struct i2c_msg) = {
++ pmic_i2c_write_xfer,
++ pmic_i2c_read_xfer
++};
++
++/* PMIC I2C Master transfer algorithm function */
++static int pmic_master_xfer(struct i2c_adapter *adap,
++ struct i2c_msg msgs[],
++ int num)
++{
++ int ret = 0;
++ int i;
++ u8 index;
++
++ mutex_lock(&pmic_dev->i2c_pmic_rw_lock);
++ pm_runtime_get_sync(pmic_dev->dev);
++ for (i = 0 ; i < num ; i++) {
++ index = msgs[i].flags & I2C_M_RD;
++ ret = (xfer_fn[index])(msgs[i]);
++
++ if (ret == -EACCES)
++ dev_info(pmic_dev->dev, "Blocked Access!\n");
++
++ /* If access is restricted, return true to
++ * avoid extra error handling in client
++ */
++
++ if (ret != 0 && ret != -EACCES)
++ goto transfer_err_exit;
++ }
++
++ ret = num;
++
++transfer_err_exit:
++ mutex_unlock(&pmic_dev->i2c_pmic_rw_lock);
++ pm_runtime_put_sync(pmic_dev->dev);
++ intel_scu_ipc_update_register(IRQLVL1_MASK_ADDR, 0x00,
++ IRQLVL1_CHRGR_MASK);
++ return ret;
++}
++
++/* PMIC I2C adapter capability function */
++static u32 pmic_master_func(struct i2c_adapter *adap)
++{
++ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA;
++}
++
++static int pmic_smbus_xfer(struct i2c_adapter *adap, u16 addr,
++ unsigned short flags, char read_write,
++ u8 command, int size,
++ union i2c_smbus_data *data)
++{
++ struct i2c_msg msg;
++ u8 buf[2];
++ int ret;
++
++ msg.addr = addr;
++ msg.flags = flags & I2C_M_TEN;
++ msg.buf = buf;
++ msg.buf[0] = command;
++ if (read_write == I2C_SMBUS_WRITE) {
++ msg.len = 1;
++ msg.buf[1] = data->byte;
++ } else {
++ msg.flags |= I2C_M_RD;
++ msg.len = 1;
++ }
++
++ ret = pmic_master_xfer(adap, &msg, 1);
++ if (ret == 1) {
++ if (read_write == I2C_SMBUS_READ)
++ data->byte = msg.buf[0];
++ return 0;
++ }
++ return ret;
++}
++
++
++static const struct i2c_algorithm pmic_i2c_algo = {
++ .master_xfer = pmic_master_xfer,
++ .functionality = pmic_master_func,
++ .smbus_xfer = pmic_smbus_xfer,
++};
++
++static int pmic_i2c_probe(struct platform_device *pdev)
++{
++ struct i2c_adapter *adap;
++ int ret;
++
++ pmic_dev = kzalloc(sizeof(struct pmic_i2c_dev), GFP_KERNEL);
++ if (!pmic_dev)
++ return -ENOMEM;
++
++ pmic_dev->dev = &pdev->dev;
++ pmic_dev->irq = platform_get_irq(pdev, 0);
++
++
++
++ mutex_init(&pmic_dev->i2c_pmic_rw_lock);
++ init_waitqueue_head(&(pmic_dev->i2c_wait));
++
++ pmic_dev->pmic_intr_map = ioremap_nocache(PMIC_SRAM_INTR_ADDR, 8);
++ if (!pmic_dev->pmic_intr_map) {
++ dev_err(&pdev->dev, "ioremap Failed\n");
++ ret = -ENOMEM;
++ goto ioremap_failed;
++ }
++ ret = request_threaded_irq(pmic_dev->irq, pmic_i2c_handler,
++ pmic_thread_handler,
++ IRQF_SHARED|IRQF_NO_SUSPEND,
++ DRIVER_NAME, pmic_dev);
++ if (ret)
++ goto err_irq_request;
++
++ ret = intel_scu_ipc_update_register(IRQLVL1_MASK_ADDR, 0x00,
++ IRQLVL1_CHRGR_MASK);
++ if (unlikely(ret))
++ goto unmask_irq_failed;
++ ret = intel_scu_ipc_update_register(MCHGRIRQ0_ADDR, 0x00,
++ PMIC_I2C_INTR_MASK);
++ if (unlikely(ret))
++ goto unmask_irq_failed;
++
++ /* Init runtime PM state*/
++ pm_runtime_put_noidle(pmic_dev->dev);
++
++ adap = &pmic_dev->adapter;
++ adap->owner = THIS_MODULE;
++ adap->class = I2C_CLASS_HWMON;
++ adap->algo = &pmic_i2c_algo;
++ strcpy(adap->name, "PMIC I2C Adapter");
++ adap->nr = PMIC_I2C_ADAPTER;
++ ret = i2c_add_numbered_adapter(adap);
++
++ if (ret) {
++ dev_err(&pdev->dev, "Error adding the adapter\n");
++ goto err_adap_add;
++ }
++
++ pm_schedule_suspend(pmic_dev->dev, MSEC_PER_SEC);
++ return 0;
++
++err_adap_add:
++ free_irq(pmic_dev->irq, pmic_dev);
++unmask_irq_failed:
++err_irq_request:
++ iounmap(pmic_dev->pmic_intr_map);
++ioremap_failed:
++ kfree(pmic_dev);
++ return ret;
++}
++
++static int pmic_i2c_remove(struct platform_device *pdev)
++{
++ iounmap(pmic_dev->pmic_intr_map);
++ free_irq(pmic_dev->irq, pmic_dev);
++ pm_runtime_get_noresume(pmic_dev->dev);
++ kfree(pmic_dev);
++ return 0;
++}
++
++#ifdef CONFIG_PM
++static int pmic_i2c_suspend(struct device *dev)
++{
++ dev_info(dev, "%s\n", __func__);
++ return 0;
++}
++
++static int pmic_i2c_resume(struct device *dev)
++{
++ dev_info(dev, "%s\n", __func__);
++ return 0;
++}
++#endif
++
++#ifdef CONFIG_PM_RUNTIME
++static int pmic_i2c_runtime_suspend(struct device *dev)
++{
++ dev_info(dev, "%s\n", __func__);
++ return 0;
++}
++
++static int pmic_i2c_runtime_resume(struct device *dev)
++{
++ dev_info(dev, "%s\n", __func__);
++ return 0;
++}
++
++static int pmic_i2c_runtime_idle(struct device *dev)
++{
++ dev_info(dev, "%s\n", __func__);
++ return 0;
++}
++#endif
++
++static const struct dev_pm_ops pmic_i2c_pm_ops = {
++ SET_SYSTEM_SLEEP_PM_OPS(pmic_i2c_suspend,
++ pmic_i2c_resume)
++ SET_RUNTIME_PM_OPS(pmic_i2c_runtime_suspend,
++ pmic_i2c_runtime_resume,
++ pmic_i2c_runtime_idle)
++};
++
++struct platform_driver pmic_i2c_driver = {
++ .probe = pmic_i2c_probe,
++ .remove = pmic_i2c_remove,
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .pm = &pmic_i2c_pm_ops,
++ },
++};
++
++static int pmic_i2c_init(void)
++{
++ return platform_driver_register(&pmic_i2c_driver);
++}
++
++static void pmic_i2c_exit(void)
++{
++ platform_driver_unregister(&pmic_i2c_driver);
++}
++
++static int pmic_i2c_rpmsg_probe(struct rpmsg_channel *rpdev)
++{
++ int ret = 0;
++
++ if (rpdev == NULL) {
++ pr_err("rpmsg channel not created\n");
++ ret = -ENODEV;
++ goto out;
++ }
++
++ dev_info(&rpdev->dev, "Probed pmic_i2c rpmsg device\n");
++
++ ret = pmic_i2c_init();
++
++out:
++ return ret;
++}
++
++static void pmic_i2c_rpmsg_remove(struct rpmsg_channel *rpdev)
++{
++ pmic_i2c_exit();
++ dev_info(&rpdev->dev, "Removed pmic_i2c rpmsg device\n");
++}
++
++static void pmic_i2c_rpmsg_cb(struct rpmsg_channel *rpdev, void *data,
++ int len, void *priv, u32 src)
++{
++ dev_warn(&rpdev->dev, "unexpected, message\n");
++
++ print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
++ data, len, true);
++}
++
++static struct rpmsg_device_id pmic_i2c_rpmsg_id_table[] = {
++ { .name = "rpmsg_i2c_pmic_adap" },
++ { },
++};
++MODULE_DEVICE_TABLE(rpmsg, pmic_i2c_rpmsg_id_table);
++
++static struct rpmsg_driver pmic_i2c_rpmsg = {
++ .drv.name = KBUILD_MODNAME,
++ .drv.owner = THIS_MODULE,
++ .id_table = pmic_i2c_rpmsg_id_table,
++ .probe = pmic_i2c_rpmsg_probe,
++ .callback = pmic_i2c_rpmsg_cb,
++ .remove = pmic_i2c_rpmsg_remove,
++};
++
++static int __init pmic_i2c_rpmsg_init(void)
++{
++ return register_rpmsg_driver(&pmic_i2c_rpmsg);
++}
++
++static void __exit pmic_i2c_rpmsg_exit(void)
++{
++ return unregister_rpmsg_driver(&pmic_i2c_rpmsg);
++}
++module_init(pmic_i2c_rpmsg_init);
++module_exit(pmic_i2c_rpmsg_exit);
++
++MODULE_AUTHOR("Yegnesh Iyer <yegnesh.s.iyer@intel.com");
++MODULE_DESCRIPTION("PMIC I2C Master driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
+index fa6964d..2004fac 100644
+--- a/drivers/idle/intel_idle.c
++++ b/drivers/idle/intel_idle.c
+@@ -61,6 +61,7 @@
+ #include <linux/notifier.h>
+ #include <linux/cpu.h>
+ #include <linux/module.h>
++#include <linux/intel_mid_pm.h>
+ #include <asm/cpu_device_id.h>
+ #include <asm/mwait.h>
+ #include <asm/msr.h>
+@@ -330,6 +331,321 @@ static struct cpuidle_state atom_cstates[CPUIDLE_STATE_MAX] = {
+ .enter = NULL }
+ };
+
++static struct cpuidle_state vlv_cstates[CPUIDLE_STATE_MAX] = {
++ { /* MWAIT C1 */
++ .name = "C1-ATM",
++ .desc = "MWAIT 0x00",
++ .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
++ .exit_latency = 1,
++ .target_residency = 4,
++ .enter = &intel_idle },
++ { /* MWAIT C4 */
++ .name = "C4-ATM",
++ .desc = "MWAIT 0x30",
++ .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
++ .exit_latency = 100,
++ .target_residency = 400,
++ .enter = &intel_idle },
++ { /* MWAIT C6 */
++ .name = "C6-ATM",
++ .desc = "MWAIT 0x52",
++ .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
++ .exit_latency = 140,
++ .target_residency = 560,
++ .enter = &intel_idle },
++ { /* MWAIT C7-S0i1 */
++ .name = "S0i1-ATM",
++ .desc = "MWAIT 0x60",
++ .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
++ .exit_latency = 1200,
++ .target_residency = 4000,
++ .enter = &intel_idle },
++ { /* MWAIT C8-S0i2 */
++ .name = "S0i2-ATM",
++ .desc = "MWAIT 0x62",
++ .flags = MWAIT2flg(0x62) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
++ .exit_latency = 2000,
++ .target_residency = 8000,
++ .enter = &intel_idle },
++ { /* MWAIT C9-S0i3 */
++ .name = "S0i3-ATM",
++ .desc = "MWAIT 0x64",
++ .flags = MWAIT2flg(0x64) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
++ .exit_latency = 10000,
++ .target_residency = 20000,
++ .enter = &intel_idle },
++ {
++ .enter = NULL }
++};
++
++#if defined(CONFIG_REMOVEME_INTEL_ATOM_MRFLD_POWER)
++static struct cpuidle_state mrfld_cstates[CPUIDLE_STATE_MAX] = {
++ { /* MWAIT C1 */
++ .name = "C1-ATM",
++ .desc = "MWAIT 0x00",
++ .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
++ .exit_latency = 1,
++ .target_residency = 4,
++ .enter = &intel_idle },
++ { /* MWAIT C4 */
++ .name = "C4-ATM",
++ .desc = "MWAIT 0x30",
++ .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
++ .exit_latency = 100,
++ .target_residency = 400,
++ .enter = &intel_idle },
++ { /* MWAIT C6 */
++ .name = "C6-ATM",
++ .desc = "MWAIT 0x52",
++ .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
++ .exit_latency = 140,
++ .target_residency = 560,
++ .enter = &intel_idle },
++ { /* MWAIT C7-S0i1 */
++ .name = "S0i1-ATM",
++ .desc = "MWAIT 0x60",
++ .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
++ .exit_latency = 1200,
++ .target_residency = 4000,
++ .enter = &intel_idle },
++ { /* MWAIT C9-S0i3 */
++ .name = "S0i3-ATM",
++ .desc = "MWAIT 0x64",
++ .flags = MWAIT2flg(0x64) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
++ .exit_latency = 10000,
++ .target_residency = 20000,
++ .enter = &intel_idle },
++ {
++ .enter = NULL }
++};
++#else
++#define mrfld_cstates atom_cstates
++#endif
++
++#if defined(CONFIG_REMOVEME_INTEL_ATOM_MDFLD_POWER) || \
++ defined(CONFIG_REMOVEME_INTEL_ATOM_CLV_POWER)
++
++static struct cpuidle_state mfld_cstates[CPUIDLE_STATE_MAX] = {
++ { /* MWAIT C1 */
++ .name = "ATM-C1",
++ .desc = "MWAIT 0x00",
++ .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
++ .exit_latency = CSTATE_EXIT_LATENCY_C1,
++ .target_residency = 4,
++ .enter = &intel_idle },
++ { /* MWAIT C2 */
++ .name = "ATM-C2",
++ .desc = "MWAIT 0x10",
++ .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID,
++ .exit_latency = CSTATE_EXIT_LATENCY_C2,
++ .target_residency = 80,
++ .enter = &intel_idle },
++ { /* MWAIT C4 */
++ .name = "ATM-C4",
++ .desc = "MWAIT 0x30",
++ .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
++ .exit_latency = CSTATE_EXIT_LATENCY_C4,
++ .target_residency = 400,
++ .enter = &intel_idle },
++ { /* MWAIT C6 */
++ .name = "ATM-C6",
++ .desc = "MWAIT 0x52",
++ .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
++ .exit_latency = CSTATE_EXIT_LATENCY_C6,
++ .power_usage = C6_POWER_USAGE,
++ .target_residency = 560,
++ .enter = &soc_s0ix_idle },
++ {
++ .name = "ATM-S0i1",
++ .desc = "MWAIT 0x52",
++ .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
++ .exit_latency = CSTATE_EXIT_LATENCY_S0i1,
++ .power_usage = S0I1_POWER_USAGE,
++ .enter = &soc_s0ix_idle },
++ {
++ .name = "ATM-LpAudio",
++ .desc = "MWAIT 0x52",
++ .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
++ .exit_latency = CSTATE_EXIT_LATENCY_LPMP3,
++ .power_usage = LPMP3_POWER_USAGE,
++ .enter = &soc_s0ix_idle },
++ {
++ .name = "ATM-S0i3",
++ .desc = "MWAIT 0x52",
++ .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
++ .exit_latency = CSTATE_EXIT_LATENCY_S0i3,
++ .power_usage = S0I3_POWER_USAGE,
++ .enter = &soc_s0ix_idle },
++ {
++ .enter = NULL }
++};
++
++static int enter_s0ix_state(u32 eax, int gov_req_state, int s0ix_state,
++ struct cpuidle_device *dev, int index)
++{
++ int s0ix_entered = 0;
++ int selected_state = C6_STATE_IDX;
++
++ if (atomic_add_return(1, &nr_cpus_in_c6) == num_online_cpus() &&
++ s0ix_state) {
++ s0ix_entered = mid_s0ix_enter(s0ix_state);
++ if (!s0ix_entered) {
++ if (pmu_is_s0ix_in_progress()) {
++ atomic_dec(&nr_cpus_in_c6);
++ eax = C4_HINT;
++ }
++ pmu_set_s0ix_complete();
++ }
++ }
++ switch (s0ix_state) {
++ case MID_S0I1_STATE:
++ trace_cpu_idle(S0I1_STATE_IDX, dev->cpu);
++ break;
++ case MID_LPMP3_STATE:
++ trace_cpu_idle(LPMP3_STATE_IDX, dev->cpu);
++ break;
++ case MID_S0I3_STATE:
++ trace_cpu_idle(S0I3_STATE_IDX, dev->cpu);
++ break;
++ case MID_S3_STATE:
++ trace_cpu_idle(S0I3_STATE_IDX, dev->cpu);
++ break;
++ default:
++ trace_cpu_idle((eax >> 4) + 1, dev->cpu);
++ }
++ __monitor((void *)&current_thread_info()->flags, 0, 0);
++ smp_mb();
++ if (!need_resched())
++ __mwait(eax, 1);
++
++ if (likely(eax == C6_HINT))
++ atomic_dec(&nr_cpus_in_c6);
++
++ /* During s0ix exit inform scu that OS
++ * has exited. In case scu is still waiting
++ * for ack c6 trigger, it would exit out
++ * of the ack-c6 timeout loop
++ */
++ pmu_set_s0ix_complete();
++
++ /* In case of demotion to S0i1/lpmp3 update last_state */
++ if (s0ix_entered) {
++ selected_state = S0I3_STATE_IDX;
++
++ if (s0ix_state == MID_S0I1_STATE) {
++ index = S0I1_STATE_IDX;
++ selected_state = S0I1_STATE_IDX;
++ } else if (s0ix_state == MID_LPMP3_STATE) {
++ index = LPMP3_STATE_IDX;
++ selected_state = LPMP3_STATE_IDX;
++ }
++ } else if (eax == C4_HINT) {
++ index = C4_STATE_IDX;
++ selected_state = C4_STATE_IDX;
++ } else
++ index = C6_STATE_IDX;
++
++ pmu_s0ix_demotion_stat(gov_req_state, selected_state);
++
++ return index;
++}
++
++static int soc_s0ix_idle(struct cpuidle_device *dev,
++ struct cpuidle_driver *drv, int index)
++{
++ struct cpuidle_state *state = &drv->states[index];
++ unsigned long eax = flg2MWAIT(state->flags);
++ int cpu = smp_processor_id();
++ int s0ix_state = 0;
++ unsigned int cstate;
++ int gov_req_state = (int) eax;
++
++ /* Check if s0ix is already in progress,
++ * This is required to demote C6 while S0ix
++ * is in progress
++ */
++ if (unlikely(pmu_is_s0ix_in_progress()))
++ return intel_idle(dev, drv, C4_STATE_IDX);
++
++ /* check if we need/possible to do s0ix */
++ if (eax != C6_HINT)
++ s0ix_state = get_target_platform_state(&eax);
++
++ /*
++ * leave_mm() to avoid costly and often unnecessary wakeups
++ * for flushing the user TLB's associated with the active mm.
++ */
++ if (state->flags & CPUIDLE_FLAG_TLB_FLUSHED)
++ leave_mm(cpu);
++
++ cstate = (((eax) >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK) + 1;
++
++ if (!(lapic_timer_reliable_states & (1 << (cstate))))
++ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
++
++ stop_critical_timings();
++
++ if (!need_resched())
++ index = enter_s0ix_state(eax, gov_req_state,
++ s0ix_state, dev, index);
++
++ start_critical_timings();
++
++ if (!(lapic_timer_reliable_states & (1 << (cstate))))
++ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
++
++ return index;
++}
++#else
++#define mfld_cstates atom_cstates
++#endif
++
++#ifdef CONFIG_ATOM_SOC_POWER
++static unsigned int get_target_residency(unsigned int cstate)
++{
++ unsigned int t_sleep = cpuidle_state_table[cstate].target_residency;
++ unsigned int prev_idx;
++
++ /* get the previous lower sleep state */
++ if ((cstate == 8) || (cstate == 9))
++ prev_idx = cstate - 2;
++ else
++ prev_idx = cstate - 1;
++
++ /* calculate target_residency only if not defined already */
++ if (!t_sleep) {
++ unsigned int p_active = cpuidle_state_table[0].power_usage;
++ unsigned int prev_state_power = cpuidle_state_table
++ [prev_idx].power_usage;
++ unsigned int curr_state_power = cpuidle_state_table
++ [cstate].power_usage;
++ unsigned int prev_state_lat = cpuidle_state_table
++ [prev_idx].exit_latency;
++ unsigned int curr_state_lat = cpuidle_state_table
++ [cstate].exit_latency;
++
++ if (curr_state_power && prev_state_power && p_active &&
++ prev_state_lat && curr_state_lat &&
++ (curr_state_lat > prev_state_lat) &&
++ (prev_state_power > curr_state_power)) {
++ t_sleep = (p_active * (curr_state_lat - prev_state_lat)
++ + (prev_state_lat * prev_state_power)
++ - (curr_state_lat * curr_state_power)) /
++ (prev_state_power - curr_state_power);
++
++ /* round-up target_residency */
++ t_sleep++;
++ }
++ }
++
++ WARN_ON(!t_sleep);
++
++ pr_debug(PREFIX "cpuidle: target_residency[%d]= %d\n", cstate, t_sleep);
++
++ return t_sleep;
++}
++#endif
++
+ /**
+ * intel_idle
+ * @dev: cpuidle_device
+@@ -347,6 +663,17 @@ static int intel_idle(struct cpuidle_device *dev,
+ unsigned int cstate;
+ int cpu = smp_processor_id();
+
++#if (defined(CONFIG_REMOVEME_INTEL_ATOM_MRFLD_POWER) && \
++ defined(CONFIG_PM_DEBUG))
++ {
++ /* Get Cstate based on ignore table from PMU driver */
++ unsigned int ncstate;
++ cstate =
++ (((eax) >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK) + 1;
++ ncstate = pmu_get_new_cstate(cstate, &index);
++ eax = flg2MWAIT(drv->states[index].flags);
++ }
++#endif
+ cstate = (((eax) >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK) + 1;
+
+ /*
+@@ -462,6 +789,10 @@ static const struct idle_cpu idle_cpu_hsw = {
+ .disable_promotion_to_c1e = true,
+ };
+
++static const struct idle_cpu idle_cpu_mrfld = {
++ .state_table = mrfld_cstates,
++};
++
+ #define ICPU(model, cpu) \
+ { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&cpu }
+
+@@ -483,6 +814,7 @@ static const struct x86_cpu_id intel_idle_ids[] = {
+ ICPU(0x3f, idle_cpu_hsw),
+ ICPU(0x45, idle_cpu_hsw),
+ ICPU(0x46, idle_cpu_hsw),
++ ICPU(0x4a, idle_cpu_mrfld), /* Tangier SoC */
+ {}
+ };
+ MODULE_DEVICE_TABLE(x86cpu, intel_idle_ids);
+@@ -582,13 +914,25 @@ static int intel_idle_cpuidle_driver_init(void)
+ mwait_substate = MWAIT_HINT2SUBSTATE(mwait_hint);
+
+ /* does the state exist in CPUID.MWAIT? */
+- num_substates = (mwait_substates >> ((mwait_cstate + 1) * 4))
+- & MWAIT_SUBSTATE_MASK;
+
+- /* if sub-state in table is not enumerated by CPUID */
+- if ((mwait_substate + 1) > num_substates)
+- continue;
++ /* FIXME: Do not check number of substates for any states above C6
++ * as these are not real C states supported by the CPU, they
++ * are emulated c states for s0ix support.
++ */
++ if ((cstate + 1) < 6) {
++ num_substates = (mwait_substates >> ((mwait_cstate + 1) * 4))
++ & MWAIT_SUBSTATE_MASK;
++ if (num_substates == 0)
++ continue;
++ }
+
++#if !defined(CONFIG_ATOM_SOC_POWER)
++ if (boot_cpu_data.x86_model != 0x37) {
++ /* if sub-state in table is not enumerated by CPUID */
++ if ((mwait_substate + 1) > num_substates)
++ continue;
++ }
++#endif
+ if (((mwait_cstate + 1) > 2) &&
+ !boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
+ mark_tsc_unstable("TSC halts in idle"
+@@ -640,13 +984,25 @@ static int intel_idle_cpu_init(int cpu)
+ mwait_substate = MWAIT_HINT2SUBSTATE(mwait_hint);
+
+ /* does the state exist in CPUID.MWAIT? */
+- num_substates = (mwait_substates >> ((mwait_cstate + 1) * 4))
+- & MWAIT_SUBSTATE_MASK;
+
+- /* if sub-state in table is not enumerated by CPUID */
+- if ((mwait_substate + 1) > num_substates)
+- continue;
++ /* FIXME: Do not check number of substates for any states above C6
++ * as these are not real C states supported by the CPU, they
++ * are emulated c states for s0ix support.
++ */
++ if ((cstate + 1) < 6) {
++ num_substates = (mwait_substates >> ((mwait_cstate + 1) * 4))
++ & MWAIT_SUBSTATE_MASK;
++ if (num_substates == 0)
++ continue;
++ }
+
++#if !defined(CONFIG_ATOM_SOC_POWER)
++ if (boot_cpu_data.x86_model != 0x37) {
++ /* if sub-state in table is not enumerated by CPUID */
++ if ((mwait_substate + 1) > num_substates)
++ continue;
++ }
++#endif
+ dev->state_count += 1;
+ }
+
+diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
+index ab0767e6..a6e0341 100644
+--- a/drivers/iio/adc/Kconfig
++++ b/drivers/iio/adc/Kconfig
+@@ -143,6 +143,18 @@ config TI_ADC081C
+ This driver can also be built as a module. If so, the module will be
+ called ti-adc081c.
+
++config TI_ADS7955_ADC
++ tristate "Texas Instruments ADS7955 ADC driver"
++ depends on SPI
++ select IIO_BUFFER
++ select IIO_TRIGGERED_BUFFER
++ help
++ Say yes here to build support for Texas Instruments ADS7955
++ 8 Channel ADC.
++
++ To compile this driver as a module, choose M here: the
++ module will be called ti-ads7955.
++
+ config TI_AM335X_ADC
+ tristate "TI's ADC driver"
+ depends on MFD_TI_AM335X_TSCADC
+@@ -157,4 +169,10 @@ config VIPERBOARD_ADC
+ Say yes here to access the ADC part of the Nano River
+ Technologies Viperboard.
+
++config IIO_BASINCOVE_GPADC
++ tristate "IIO Basincove GPADC driver"
++ depends on IIO
++ help
++ Say yes here to build support for the IIO basincove GPADC driver.
++
+ endmenu
+diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
+index 0a825be..48f8fef0 100644
+--- a/drivers/iio/adc/Makefile
++++ b/drivers/iio/adc/Makefile
+@@ -15,5 +15,7 @@ obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
+ obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
+ obj-$(CONFIG_MAX1363) += max1363.o
+ obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
++obj-$(CONFIG_TI_ADS7955_ADC) += ti-ads7955.o
+ obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
+ obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o
++obj-$(CONFIG_IIO_BASINCOVE_GPADC) += iio_basincove_gpadc.o
+diff --git a/drivers/iio/adc/iio_basincove_gpadc.c b/drivers/iio/adc/iio_basincove_gpadc.c
+new file mode 100644
+index 0000000..c20b61b
+--- /dev/null
++++ b/drivers/iio/adc/iio_basincove_gpadc.c
+@@ -0,0 +1,596 @@
++/*
++ * iio_basincove_gpadc.c - Intel Merrifield Basin Cove GPADC Driver
++ *
++ * Copyright (C) 2012 Intel Corporation
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * 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; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ * Author: Bin Yang <bin.yang@intel.com>
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/io.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/device.h>
++#include <linux/sched.h>
++#include <linux/intel_mid_pm.h>
++#include <linux/rpmsg.h>
++
++#include <asm/intel_mid_rpmsg.h>
++#include <asm/intel_mid_remoteproc.h>
++#include <asm/intel_scu_pmic.h>
++#include <asm/intel_basincove_gpadc.h>
++
++#include <linux/iio/iio.h>
++#include <linux/iio/machine.h>
++#include <linux/iio/buffer.h>
++#include <linux/iio/driver.h>
++#include <linux/iio/types.h>
++#include <linux/iio/consumer.h>
++
++struct gpadc_info {
++ int initialized;
++ /* This mutex protects gpadc sample/config from concurrent conflict.
++ Any function, which does the sample or config, needs to
++ hold this lock.
++ If it is locked, it also means the gpadc is in active mode.
++ */
++ struct mutex lock;
++ struct device *dev;
++ int irq;
++ u8 irq_status;
++ wait_queue_head_t wait;
++ int sample_done;
++ void __iomem *intr;
++ int channel_num;
++ struct gpadc_regmap_t *gpadc_regmaps;
++ struct gpadc_regs_t *gpadc_regs;
++};
++
++static inline int gpadc_clear_bits(u16 addr, u8 mask)
++{
++ return intel_scu_ipc_update_register(addr, 0, mask);
++}
++
++static inline int gpadc_set_bits(u16 addr, u8 mask)
++{
++ return intel_scu_ipc_update_register(addr, 0xff, mask);
++}
++
++static inline int gpadc_write(u16 addr, u8 data)
++{
++ return intel_scu_ipc_iowrite8(addr, data);
++}
++
++static inline int gpadc_read(u16 addr, u8 *data)
++{
++ return intel_scu_ipc_ioread8(addr, data);
++}
++
++static int gpadc_busy_wait(struct gpadc_regs_t *regs)
++{
++ u8 tmp;
++ int timeout = 0;
++
++ gpadc_read(regs->gpadcreq, &tmp);
++ while (tmp & regs->gpadcreq_busy && timeout < 500) {
++ gpadc_read(regs->gpadcreq, &tmp);
++ usleep_range(1800, 2000);
++ timeout++;
++ }
++
++ if (tmp & regs->gpadcreq_busy)
++ return -EBUSY;
++ else
++ return 0;
++}
++
++static void gpadc_dump(struct gpadc_info *info)
++{
++ u8 tmp;
++ struct gpadc_regs_t *regs = info->gpadc_regs;
++
++ dev_err(info->dev, "GPADC registers dump:\n");
++ gpadc_read(regs->adcirq, &tmp);
++ dev_err(info->dev, "ADCIRQ: 0x%x\n", tmp);
++ gpadc_read(regs->madcirq, &tmp);
++ dev_err(info->dev, "MADCIRQ: 0x%x\n", tmp);
++ gpadc_read(regs->gpadcreq, &tmp);
++ dev_err(info->dev, "GPADCREQ: 0x%x\n", tmp);
++ gpadc_read(regs->adc1cntl, &tmp);
++ dev_err(info->dev, "ADC1CNTL: 0x%x\n", tmp);
++}
++
++static irqreturn_t gpadc_isr(int irq, void *data)
++{
++ struct gpadc_info *info = iio_priv(data);
++
++ info->irq_status = ioread8(info->intr);
++ info->sample_done = 1;
++ wake_up(&info->wait);
++ return IRQ_WAKE_THREAD;
++}
++
++static irqreturn_t gpadc_threaded_isr(int irq, void *data)
++{
++ struct gpadc_info *info = iio_priv(data);
++ struct gpadc_regs_t *regs = info->gpadc_regs;
++
++ /* Clear IRQLVL1MASK */
++ gpadc_clear_bits(regs->mirqlvl1, regs->mirqlvl1_adc);
++
++ return IRQ_HANDLED;
++}
++
++
++/**
++ * iio_basincove_gpadc_sample - do gpadc sample.
++ * @indio_dev: industrial IO GPADC device handle
++ * @ch: gpadc bit set of channels to sample, for example, set ch = (1<<0)|(1<<2)
++ * means you are going to sample both channel 0 and 2 at the same time.
++ * @res:gpadc sampling result
++ *
++ * Returns 0 on success or an error code.
++ *
++ * This function may sleep.
++ */
++
++int iio_basincove_gpadc_sample(struct iio_dev *indio_dev,
++ int ch, struct gpadc_result *res)
++{
++ struct gpadc_info *info = iio_priv(indio_dev);
++ int i, ret;
++ u8 tmp, th, tl;
++ u8 mask;
++ struct gpadc_regs_t *regs = info->gpadc_regs;
++
++ if (!info->initialized)
++ return -ENODEV;
++
++ mutex_lock(&info->lock);
++
++ mask = MBATTEMP | MSYSTEMP | MBATT | MVIBATT | MCCTICK;
++ gpadc_clear_bits(regs->madcirq, mask);
++ gpadc_clear_bits(regs->mirqlvl1, regs->mirqlvl1_adc);
++
++ tmp = regs->gpadcreq_irqen;
++
++ for (i = 0; i < info->channel_num; i++) {
++ if (ch & (1 << i))
++ tmp |= (1 << info->gpadc_regmaps[i].cntl);
++ }
++
++ info->sample_done = 0;
++
++ ret = gpadc_busy_wait(regs);
++ if (ret) {
++ dev_err(info->dev, "GPADC is busy\n");
++ goto done;
++ }
++
++ gpadc_write(regs->gpadcreq, tmp);
++
++ ret = wait_event_timeout(info->wait, info->sample_done, HZ);
++ if (ret == 0) {
++ gpadc_dump(info);
++ ret = -ETIMEDOUT;
++ dev_err(info->dev, "sample timeout, return %d\n", ret);
++ goto done;
++ } else {
++ ret = 0;
++ }
++
++ for (i = 0; i < info->channel_num; i++) {
++ if (ch & (1 << i)) {
++ gpadc_read(info->gpadc_regmaps[i].rslth, &th);
++ gpadc_read(info->gpadc_regmaps[i].rsltl, &tl);
++ res->data[i] = ((th & 0x3) << 8) + tl;
++ }
++ }
++
++done:
++ gpadc_set_bits(regs->mirqlvl1, regs->mirqlvl1_adc);
++ gpadc_set_bits(regs->madcirq, mask);
++ mutex_unlock(&info->lock);
++ return ret;
++}
++EXPORT_SYMBOL(iio_basincove_gpadc_sample);
++
++static struct gpadc_result sample_result;
++static int chs;
++
++static ssize_t intel_basincove_gpadc_store_channel(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t size)
++{
++ struct iio_dev *indio_dev = dev_get_drvdata(dev);
++ struct gpadc_info *info = iio_priv(indio_dev);
++
++ if (sscanf(buf, "%x", &chs) != 1) {
++ dev_err(dev, "one channel argument is needed\n");
++ return -EINVAL;
++ }
++
++ if (chs < (1 << 0) || chs >= (1 << info->channel_num)) {
++ dev_err(dev, "invalid channel, should be in [0x1 - 0x1FF]\n");
++ return -EINVAL;
++ }
++
++ return size;
++}
++
++static ssize_t intel_basincove_gpadc_show_channel(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "0x%x\n", chs);
++}
++
++static ssize_t intel_basincove_gpadc_store_sample(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t size)
++{
++ int value, ret;
++ struct iio_dev *indio_dev = dev_get_drvdata(dev);
++
++ memset(sample_result.data, 0, sizeof(sample_result.data));
++
++ if (sscanf(buf, "%d", &value) != 1) {
++ dev_err(dev, "one argument is needed\n");
++ return -EINVAL;
++ }
++
++ if (value == 1) {
++ ret = iio_basincove_gpadc_sample(indio_dev, chs,
++ &sample_result);
++ if (ret) {
++ dev_err(dev, "sample failed\n");
++ return ret;
++ }
++ } else {
++ dev_err(dev, "input '1' to sample\n");
++ return -EINVAL;
++ }
++
++ return size;
++}
++
++static ssize_t intel_basincove_gpadc_show_result(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ int i;
++ int used = 0;
++ struct iio_dev *indio_dev = dev_get_drvdata(dev);
++ struct gpadc_info *info = iio_priv(indio_dev);
++
++ for (i = 0; i < info->channel_num; i++) {
++ used += snprintf(buf + used, PAGE_SIZE - used,
++ "sample_result[%d] = %d\n", i, sample_result.data[i]);
++ }
++
++ return used;
++}
++
++
++static DEVICE_ATTR(channel, S_IWUSR | S_IRUGO,
++ intel_basincove_gpadc_show_channel,
++ intel_basincove_gpadc_store_channel);
++static DEVICE_ATTR(sample, S_IWUSR, NULL, intel_basincove_gpadc_store_sample);
++static DEVICE_ATTR(result, S_IRUGO, intel_basincove_gpadc_show_result, NULL);
++
++static struct attribute *intel_basincove_gpadc_attrs[] = {
++ &dev_attr_channel.attr,
++ &dev_attr_sample.attr,
++ &dev_attr_result.attr,
++ NULL,
++};
++static struct attribute_group intel_basincove_gpadc_attr_group = {
++ .name = "basincove_gpadc",
++ .attrs = intel_basincove_gpadc_attrs,
++};
++
++static int basincove_adc_read_raw(struct iio_dev *indio_dev,
++ struct iio_chan_spec const *chan,
++ int *val, int *val2, long m)
++{
++ int ret;
++ int ch = chan->channel;
++ struct gpadc_info *info = iio_priv(indio_dev);
++ struct gpadc_result res;
++
++ ret = iio_basincove_gpadc_sample(indio_dev, (1 << ch), &res);
++ if (ret) {
++ dev_err(info->dev, "sample failed\n");
++ return -EINVAL;
++ }
++
++ *val = res.data[ch];
++
++ return ret;
++}
++
++static int basincove_adc_read_all_raw(struct iio_channel *chan,
++ int *val)
++{
++ int ret;
++ int i, num = 0;
++ int ch = 0;
++ int *channels;
++ struct gpadc_info *info = iio_priv(chan->indio_dev);
++ struct gpadc_result res;
++
++ while (chan[num].indio_dev)
++ num++;
++
++ channels = kzalloc(sizeof(int) * num, GFP_KERNEL);
++ if (channels == NULL)
++ return -ENOMEM;
++
++ for (i = 0; i < num; i++) {
++ channels[i] = chan[i].channel->channel;
++ ch |= (1 << channels[i]);
++ }
++
++ ret = iio_basincove_gpadc_sample(chan->indio_dev, ch, &res);
++ if (ret) {
++ dev_err(info->dev, "sample failed\n");
++ ret = -EINVAL;
++ goto end;
++ }
++
++ for (i = 0; i < num; i++)
++ val[i] = res.data[channels[i]];
++
++end:
++ kfree(channels);
++ return ret;
++}
++
++static const struct iio_info basincove_adc_info = {
++ .read_raw = &basincove_adc_read_raw,
++ .read_all_raw = &basincove_adc_read_all_raw,
++ .driver_module = THIS_MODULE,
++};
++
++static int bcove_gpadc_probe(struct platform_device *pdev)
++{
++ int err;
++ struct gpadc_info *info;
++ struct iio_dev *indio_dev;
++ struct intel_basincove_gpadc_platform_data *pdata =
++ pdev->dev.platform_data;
++
++ if (!pdata) {
++ dev_err(&pdev->dev, "no platform data supplied\n");
++ err = -EINVAL;
++ goto out;
++ }
++
++ indio_dev = iio_device_alloc(sizeof(struct gpadc_info));
++ if (indio_dev == NULL) {
++ dev_err(&pdev->dev, "allocating iio device failed\n");
++ err = -ENOMEM;
++ goto out;
++ }
++
++ info = iio_priv(indio_dev);
++
++ mutex_init(&info->lock);
++ init_waitqueue_head(&info->wait);
++ info->dev = &pdev->dev;
++ info->irq = platform_get_irq(pdev, 0);
++ info->intr = ioremap_nocache(pdata->intr, 1);
++ if (!info->intr) {
++ dev_err(&pdev->dev, "ioremap of ADCIRQ failed\n");
++ err = -ENOMEM;
++ goto err_free;
++ }
++ info->channel_num = pdata->channel_num;
++ info->gpadc_regmaps = pdata->gpadc_regmaps;
++ info->gpadc_regs = pdata->gpadc_regs;
++
++ err = request_threaded_irq(info->irq, gpadc_isr, gpadc_threaded_isr,
++ IRQF_ONESHOT, "adc", indio_dev);
++ if (err) {
++ gpadc_dump(info);
++ dev_err(&pdev->dev, "unable to register irq %d\n", info->irq);
++ goto err_iounmap;
++ }
++
++ platform_set_drvdata(pdev, indio_dev);
++
++ indio_dev->dev.parent = &pdev->dev;
++ indio_dev->name = pdev->name;
++
++ indio_dev->channels = pdata->gpadc_channels;
++ indio_dev->num_channels = pdata->channel_num;
++ indio_dev->info = &basincove_adc_info;
++ indio_dev->modes = INDIO_DIRECT_MODE;
++
++ err = iio_map_array_register(indio_dev, pdata->gpadc_iio_maps);
++ if (err)
++ goto err_release_irq;
++
++ err = iio_device_register(indio_dev);
++ if (err < 0)
++ goto err_array_unregister;
++
++ err = sysfs_create_group(&pdev->dev.kobj,
++ &intel_basincove_gpadc_attr_group);
++ if (err) {
++ dev_err(&pdev->dev, "Unable to export sysfs interface, error: %d\n",
++ err);
++ goto err_iio_device_unregister;
++ }
++
++ info->initialized = 1;
++
++ dev_info(&pdev->dev, "bcove adc probed\n");
++
++ return 0;
++
++err_iio_device_unregister:
++ iio_device_unregister(indio_dev);
++err_array_unregister:
++ iio_map_array_unregister(indio_dev);
++err_release_irq:
++ free_irq(info->irq, info);
++err_iounmap:
++ iounmap(info->intr);
++err_free:
++ iio_device_free(indio_dev);
++out:
++ return err;
++}
++
++static int bcove_gpadc_remove(struct platform_device *pdev)
++{
++ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
++ struct gpadc_info *info = iio_priv(indio_dev);
++
++ sysfs_remove_group(&pdev->dev.kobj,
++ &intel_basincove_gpadc_attr_group);
++
++ iio_device_unregister(indio_dev);
++ iio_map_array_unregister(indio_dev);
++ free_irq(info->irq, info);
++ iounmap(info->intr);
++ iio_device_free(indio_dev);
++
++ return 0;
++}
++
++#ifdef CONFIG_PM
++static int bcove_gpadc_suspend(struct device *dev)
++{
++ struct iio_dev *indio_dev = dev_get_drvdata(dev);
++ struct gpadc_info *info = iio_priv(indio_dev);
++
++ if (!mutex_trylock(&info->lock))
++ return -EBUSY;
++
++ return 0;
++}
++
++static int bcove_gpadc_resume(struct device *dev)
++{
++ struct iio_dev *indio_dev = dev_get_drvdata(dev);
++ struct gpadc_info *info = iio_priv(indio_dev);
++
++ mutex_unlock(&info->lock);
++ return 0;
++}
++#else
++#define bcove_gpadc_suspend NULL
++#define bcove_gpadc_resume NULL
++#endif
++
++static const struct dev_pm_ops bcove_gpadc_driver_pm_ops = {
++ .suspend = bcove_gpadc_suspend,
++ .resume = bcove_gpadc_resume,
++};
++
++static struct platform_driver bcove_gpadc_driver = {
++ .driver = {
++ .name = "bcove_adc",
++ .owner = THIS_MODULE,
++ .pm = &bcove_gpadc_driver_pm_ops,
++ },
++ .probe = bcove_gpadc_probe,
++ .remove = bcove_gpadc_remove,
++};
++
++static int bcove_gpadc_module_init(void)
++{
++ return platform_driver_register(&bcove_gpadc_driver);
++}
++
++static void bcove_gpadc_module_exit(void)
++{
++ platform_driver_unregister(&bcove_gpadc_driver);
++}
++
++static int bcove_adc_rpmsg_probe(struct rpmsg_channel *rpdev)
++{
++ int ret = 0;
++
++ if (rpdev == NULL) {
++ pr_err("rpmsg channel not created\n");
++ ret = -ENODEV;
++ goto out;
++ }
++
++ dev_info(&rpdev->dev, "Probed bcove_gpadc rpmsg device\n");
++
++ ret = bcove_gpadc_module_init();
++
++out:
++ return ret;
++}
++
++static void bcove_adc_rpmsg_remove(struct rpmsg_channel *rpdev)
++{
++ bcove_gpadc_module_exit();
++ dev_info(&rpdev->dev, "Removed bcove_gpadc rpmsg device\n");
++}
++
++static void bcove_adc_rpmsg_cb(struct rpmsg_channel *rpdev, void *data,
++ int len, void *priv, u32 src)
++{
++ dev_warn(&rpdev->dev, "unexpected, message\n");
++
++ print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
++ data, len, true);
++}
++
++static struct rpmsg_device_id bcove_adc_rpmsg_id_table[] = {
++ { .name = "rpmsg_bcove_adc" },
++ { },
++};
++MODULE_DEVICE_TABLE(rpmsg, bcove_adc_rpmsg_id_table);
++
++static struct rpmsg_driver bcove_adc_rpmsg = {
++ .drv.name = KBUILD_MODNAME,
++ .drv.owner = THIS_MODULE,
++ .id_table = bcove_adc_rpmsg_id_table,
++ .probe = bcove_adc_rpmsg_probe,
++ .callback = bcove_adc_rpmsg_cb,
++ .remove = bcove_adc_rpmsg_remove,
++};
++
++static int __init bcove_adc_rpmsg_init(void)
++{
++ return register_rpmsg_driver(&bcove_adc_rpmsg);
++}
++
++#ifdef MODULE
++module_init(bcove_adc_rpmsg_init);
++#else
++rootfs_initcall(bcove_adc_rpmsg_init);
++#endif
++
++static void __exit bcove_adc_rpmsg_exit(void)
++{
++ return unregister_rpmsg_driver(&bcove_adc_rpmsg);
++}
++module_exit(bcove_adc_rpmsg_exit);
++
++MODULE_AUTHOR("Yang Bin<bin.yang@intel.com>");
++MODULE_DESCRIPTION("Intel Merrifield Basin Cove GPADC Driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/iio/adc/ti-ads7955.c b/drivers/iio/adc/ti-ads7955.c
+new file mode 100644
+index 0000000..fde230b
+--- /dev/null
++++ b/drivers/iio/adc/ti-ads7955.c
+@@ -0,0 +1,421 @@
++/*
++ * ADS7955 SPI ADC driver
++ *
++ * (C) Copyright 2014 Intel Corporation
++ * Author: Dave Hunt <dave.hunt@emutex.com>
++ *
++ * Licensed under the GPL-2.
++ */
++
++/*
++ * [FIXME]
++ * Notes: This version of the ti-ads7955 driver is written with a couple of
++ * workarounds for the functionality of the SPI driver on Edison at the time
++ * of writing.
++ * Issue 1: The CS is pushed low between every frame
++ * Issue 2: spi_message_add_tail() can only be called once in the driver.
++ * Subsequent messages are ignored.
++*/
++
++#include <linux/device.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/sysfs.h>
++#include <linux/spi/spi.h>
++#include <linux/regulator/consumer.h>
++#include <linux/err.h>
++#include <linux/delay.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/bitops.h>
++#include <linux/iio/iio.h>
++#include <linux/iio/sysfs.h>
++#include <linux/iio/buffer.h>
++#include <linux/iio/trigger_consumer.h>
++#include <linux/iio/triggered_buffer.h>
++
++#include <linux/platform_data/ti-ads7955.h>
++
++#define ADS7955_EXTREF true
++#define SPI_MAX_SPEED_HZ 20000000
++#define SPI_BITS_PER_WORD 16
++
++#define ADS7955_MANUAL_MODE (0x1 << 12) /* Selects Manual Mode */
++#define ADS7955_AUTO1_MODE (0x2 << 12) /* Selects Auto Mode 1 */
++#define ADS7955_AUTO2_MODE (0x3 << 12) /* Selects Auto Mode 2 */
++#define ADS7955_AUTO1_PROGRAM (0x8 << 12) /* Programming Auto Mode 1 */
++#define ADS7955_AUTO2_PROGRAM (0x9 << 12) /* Programming Auto Mode 2 */
++
++#define ADS7955_CONFIG BIT(11) /* program bits DI06-00 */
++#define ADS7955_AUTO1_RESET BIT(10) /* Reset to first channel */
++#define ADS7955_CHANNEL(x) ((x & 0xf) << 7)/* Channel select (DI10-07) */
++
++#define ADS7955_RANGE_1 0 /* Selects 2.5V input range */
++#define ADS7955_RANGE_2 BIT(6) /* Selects 5.0V input range */
++
++#define ADS7955_POWER_NORMAL 0 /* No Powerdown */
++#define ADS7955_POWER_DOWN BIT(5) /* Powerdown on last edge */
++
++#define ADS7955_GET_CONVERSION 0 /* High bits have ch index*/
++#define ADS7955_GET_GPIO BIT(4) /* High bits have GPIO bits */
++
++#define ADS7955_SET_READ (ADS7955_MANUAL_MODE | ADS7955_CONFIG | \
++ ADS7955_RANGE_2 | ADS7955_POWER_NORMAL | \
++ ADS7955_GET_CONVERSION)
++
++#define ADS7955_READ_AUTO1 (ADS7955_AUTO1_MODE | ADS7955_CONFIG | \
++ ADS7955_RANGE_2 | ADS7955_POWER_NORMAL | \
++ ADS7955_GET_CONVERSION)
++
++#define ADS7955_MAX_CHAN 8
++#define ADS7955_BITS 12
++#define ADS7955_STORAGE_BITS 16
++/*
++ * Define the Reference Voltage for the board on which this ADC is used.
++ * May change depending on jumper settings or wiring configuration.
++ */
++#define ADS7955_INTREF_mV 5000
++#define SPI_MSG_MAX_LEN 20 /* 8 channels plus timestamp */
++
++#define RES_MASK(bits) ((1 << (bits)) - 1)
++
++struct ads7955_state {
++ struct spi_device *spi;
++ struct regulator *reg;
++ unsigned ext_ref;
++ struct spi_transfer ring_xfer[10];
++ struct spi_transfer scan_single_xfer[3];
++ struct spi_message ring_msg;
++ struct spi_message scan_single_msg;
++ /*
++ * DMA (thus cache coherency maintenance) requires the
++ * transfer buffers to live in their own cache lines.
++ */
++ __u16 rx_buf[SPI_MSG_MAX_LEN] ____cacheline_aligned;
++ __u16 tx_buf[SPI_MSG_MAX_LEN];
++};
++
++#define ADS7955_V_CHAN(index) \
++ { \
++ .type = IIO_VOLTAGE, \
++ .indexed = 1, \
++ .channel = index, \
++ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
++ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
++ .address = index, \
++ .scan_index = index, \
++ .scan_type = { \
++ .sign = 'u', \
++ .realbits = ADS7955_BITS, \
++ .storagebits = ADS7955_STORAGE_BITS, \
++ .endianness = IIO_CPU, \
++ }, \
++ }
++
++static const struct iio_chan_spec ads7955_channels[] = {
++ ADS7955_V_CHAN(0),
++ ADS7955_V_CHAN(1),
++ ADS7955_V_CHAN(2),
++ ADS7955_V_CHAN(3),
++ ADS7955_V_CHAN(4),
++ ADS7955_V_CHAN(5),
++ ADS7955_V_CHAN(6),
++ ADS7955_V_CHAN(7),
++ IIO_CHAN_SOFT_TIMESTAMP(8),
++};
++
++/**
++ * ads7955_update_scan_mode() setup the spi transfer buffer for the scan mask
++ **/
++static int ads7955_update_scan_mode(struct iio_dev *indio_dev,
++ const unsigned long *active_scan_mask)
++{
++ struct ads7955_state *st = iio_priv(indio_dev);
++ int i, ret;
++ unsigned short channel_count;
++
++ /*
++ * For programming the auto1 mode, we need to send two words, one to
++ * specify program mode, and the other to give a bitmask of channels
++ * to be read when reading the auto sequence.
++ */
++ /*
++ * [FIXME]
++ * Workaround: Build up a custom SPI message containing all required
++ * frames (including space for expected responses), and send as one
++ * SPI messge. This is to get around the issue that the current SPI
++ * driver only supports the first 'spi_message_add_tail' call.
++ */
++ st->tx_buf[0] = ADS7955_AUTO1_PROGRAM;
++ st->tx_buf[1] = (unsigned short)*active_scan_mask;
++ st->tx_buf[2] = (ADS7955_SET_READ | ADS7955_POWER_DOWN);
++
++ ret = spi_sync(st->spi, &st->scan_single_msg);
++ if (ret)
++ return ret;
++
++ /*
++ * So now we've told the hardware about the channels we want to sample,
++ * now we set up the message sequence for when we're triggered.
++ */
++ /*
++ * [FIXME]
++ * Workaround: Build up a custom SPI message containing all required
++ * frames (including space for expected responses), and send as one
++ * SPI messge. This is to get around the issue that the current SPI
++ * driver only supports the first 'spi_message_add_tail' call.
++ */
++ channel_count = 0;
++ for (i = 0; i < ADS7955_MAX_CHAN; i++) {
++ if (test_bit(i, active_scan_mask)) {
++ if (channel_count == 0)
++ st->tx_buf[channel_count] = (ADS7955_READ_AUTO1
++ | ADS7955_AUTO1_RESET);
++ else
++ st->tx_buf[channel_count] =
++ (ADS7955_READ_AUTO1);
++ channel_count++;
++ }
++ }
++
++ /* Put in some extra tx frames to allow us to get the
++ rx frames (behind tx by two frames) */
++ st->tx_buf[channel_count++] = (ADS7955_READ_AUTO1);
++ st->tx_buf[channel_count++] = (ADS7955_READ_AUTO1 |
++ ADS7955_POWER_DOWN);
++
++ st->ring_xfer[0].tx_buf = &st->tx_buf[0];
++ st->ring_xfer[0].rx_buf = &st->rx_buf[0];
++ st->ring_xfer[0].len = channel_count * 2;
++ spi_message_init(&st->ring_msg);
++ spi_message_add_tail(&st->ring_xfer[0], &st->ring_msg);
++ return 0;
++}
++
++/**
++ * ads7955_trigger_handler() bh of trigger launched polling to ring buffer
++ **/
++static irqreturn_t ads7955_trigger_handler(int irq, void *p)
++{
++ struct iio_poll_func *pf = p;
++ struct iio_dev *indio_dev = pf->indio_dev;
++ struct ads7955_state *st = iio_priv(indio_dev);
++ u8 *return_data = (u8 *)&(st->rx_buf[2]);
++ s64 time_ns = 0;
++ int ret;
++
++ ret = spi_sync(st->spi, &st->ring_msg);
++ if (ret)
++ return IRQ_HANDLED;
++
++ if (indio_dev->scan_timestamp) {
++ time_ns = iio_get_time_ns();
++ memcpy(return_data +
++ indio_dev->scan_bytes - sizeof(s64),
++ &time_ns, sizeof(time_ns));
++ }
++
++ iio_push_to_buffers(indio_dev, return_data);
++
++ iio_trigger_notify_done(indio_dev->trig);
++
++ return IRQ_HANDLED;
++}
++
++static int ads7955_scan_direct(struct ads7955_state *st, unsigned ch)
++{
++ int ret;
++
++ /*
++ * [FIXME]
++ * Workaround: Build up a custom SPI message containing all required
++ * frames (including space for expected responses), and send as one
++ * SPI messge. This is to get around the issue that the current SPI
++ * driver only supports the first 'spi_message_add_tail' call.
++ */
++ st->tx_buf[0] = (ADS7955_SET_READ | ADS7955_CHANNEL(ch));
++ st->tx_buf[1] = (ADS7955_SET_READ | ADS7955_CHANNEL(ch));
++ st->tx_buf[2] = (ADS7955_SET_READ | ADS7955_CHANNEL(ch) |
++ ADS7955_POWER_DOWN);
++
++ ret = spi_sync(st->spi, &st->scan_single_msg);
++ if (ret)
++ return ret;
++ return st->rx_buf[2];
++}
++
++
++static int ads7955_get_ref_voltage(struct ads7955_state *st)
++{
++ int vref;
++
++ if (st->ext_ref) {
++ vref = regulator_get_voltage(st->reg);
++ if (vref < 0)
++ return vref;
++
++ return vref / 1000;
++ } else {
++ return ADS7955_INTREF_mV;
++ }
++}
++
++static int ads7955_read_raw(struct iio_dev *indio_dev,
++ struct iio_chan_spec const *chan,
++ int *val,
++ int *val2,
++ long m)
++{
++ int ret;
++ struct ads7955_state *st = iio_priv(indio_dev);
++
++ switch (m) {
++ case IIO_CHAN_INFO_RAW:
++ mutex_lock(&indio_dev->mlock);
++ if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED)
++ ret = -EBUSY;
++ else
++ ret = ads7955_scan_direct(st, chan->address);
++ mutex_unlock(&indio_dev->mlock);
++ if (ret < 0)
++ return ret;
++
++ *val = ret & RES_MASK(ADS7955_BITS);
++ return IIO_VAL_INT;
++ case IIO_CHAN_INFO_SCALE:
++ switch (chan->type) {
++ case IIO_VOLTAGE:
++ *val = ads7955_get_ref_voltage(st);
++ *val2 = chan->scan_type.realbits;
++ return IIO_VAL_FRACTIONAL_LOG2;
++ default:
++ return -EINVAL;
++ }
++ }
++ return -EINVAL;
++}
++
++static const struct iio_info ads7955_info = {
++ .read_raw = &ads7955_read_raw,
++ .update_scan_mode = ads7955_update_scan_mode,
++ .driver_module = THIS_MODULE,
++};
++
++static int ads7955_probe(struct spi_device *spi)
++{
++ struct ads7955_platform_data *pdata = spi->dev.platform_data;
++ struct ads7955_state *st;
++ struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
++ int ret;
++
++ if (indio_dev == NULL)
++ return -ENOMEM;
++
++ st = iio_priv(indio_dev);
++
++ if (pdata && pdata->ext_ref)
++ st->ext_ref = ADS7955_EXTREF;
++
++ if (st->ext_ref) {
++ st->reg = regulator_get(&spi->dev, "vref");
++ if (IS_ERR(st->reg)) {
++ ret = PTR_ERR(st->reg);
++ goto error_free;
++ }
++ ret = regulator_enable(st->reg);
++ if (ret)
++ goto error_put_reg;
++ }
++
++ spi_set_drvdata(spi, indio_dev);
++
++ st->spi = spi;
++
++ indio_dev->name = spi_get_device_id(spi)->name;
++ indio_dev->dev.parent = &spi->dev;
++ indio_dev->modes = INDIO_DIRECT_MODE;
++ indio_dev->channels = ads7955_channels;
++ indio_dev->num_channels = ARRAY_SIZE(ads7955_channels);
++ indio_dev->info = &ads7955_info;
++
++ /*
++ * Setup default message
++ * [FIXME]
++ * Workaround: Send each frame as 16 bits to get over the fact that
++ * the current SPI hardware pulls CS low between every frame.
++ */
++ spi->bits_per_word = SPI_BITS_PER_WORD;
++ spi->max_speed_hz = SPI_MAX_SPEED_HZ;
++ spi_setup(spi);
++
++ st->scan_single_xfer[0].tx_buf = &st->tx_buf[0];
++ st->scan_single_xfer[0].rx_buf = &st->rx_buf[0];
++ st->scan_single_xfer[0].len = 6;
++
++ spi_message_init(&st->scan_single_msg);
++ spi_message_add_tail(&st->scan_single_xfer[0], &st->scan_single_msg);
++
++ ret = iio_triggered_buffer_setup(indio_dev, NULL,
++ &ads7955_trigger_handler, NULL);
++ if (ret) {
++ dev_warn(&indio_dev->dev,
++ "Failed to set up iio_triggered_buffer_setup\n");
++ goto error_disable_reg;
++ }
++
++ ret = iio_device_register(indio_dev);
++ if (ret)
++ goto error_cleanup_ring;
++
++ return 0;
++
++error_cleanup_ring:
++ iio_triggered_buffer_cleanup(indio_dev);
++error_disable_reg:
++ if (st->ext_ref)
++ regulator_disable(st->reg);
++error_put_reg:
++ if (st->ext_ref)
++ regulator_put(st->reg);
++error_free:
++ iio_device_free(indio_dev);
++
++ return ret;
++}
++
++static int ads7955_remove(struct spi_device *spi)
++{
++ struct iio_dev *indio_dev = spi_get_drvdata(spi);
++ struct ads7955_state *st = iio_priv(indio_dev);
++
++ iio_device_unregister(indio_dev);
++ iio_triggered_buffer_cleanup(indio_dev);
++ if (st->ext_ref) {
++ regulator_disable(st->reg);
++ regulator_put(st->reg);
++ }
++ iio_device_free(indio_dev);
++
++ return 0;
++}
++
++static const struct spi_device_id ads7955_id[] = {
++ {"ads7955", 0},
++ {}
++};
++MODULE_DEVICE_TABLE(spi, ads7955_id);
++
++static struct spi_driver ads7955_driver = {
++ .driver = {
++ .name = "ads7955",
++ .owner = THIS_MODULE,
++ },
++ .probe = ads7955_probe,
++ .remove = ads7955_remove,
++ .id_table = ads7955_id,
++};
++module_spi_driver(ads7955_driver);
++
++MODULE_AUTHOR("Dave Hunt <dave.hunt@emutex.com>");
++MODULE_DESCRIPTION("Texas Instruments ADS7955 ADC");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
+index e145931..424dea1 100644
+--- a/drivers/iio/industrialio-core.c
++++ b/drivers/iio/industrialio-core.c
+@@ -66,6 +66,7 @@ static const char * const iio_chan_type_name_spec[] = {
+ [IIO_ALTVOLTAGE] = "altvoltage",
+ [IIO_CCT] = "cct",
+ [IIO_PRESSURE] = "pressure",
++ [IIO_RESISTANCE] = "resistance",
+ };
+
+ static const char * const iio_modifier_names[] = {
+diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
+index 0cf5f8e..060a833 100644
+--- a/drivers/iio/inkern.c
++++ b/drivers/iio/inkern.c
+@@ -413,6 +413,48 @@ void iio_channel_release_all(struct iio_channel *channels)
+ }
+ EXPORT_SYMBOL_GPL(iio_channel_release_all);
+
++int iio_channel_get_num(const struct iio_channel *chan)
++{
++ int num = 0;
++
++ if (chan == NULL)
++ return -ENODEV;
++
++ while (chan[num].indio_dev)
++ num++;
++
++ return num;
++}
++EXPORT_SYMBOL_GPL(iio_channel_get_num);
++
++int iio_channel_get_name(const struct iio_channel *chan, char **chan_name)
++{
++ int i = 0;
++ struct iio_map_internal *c = NULL;
++
++ if (chan == NULL)
++ return -ENODEV;
++
++ if (chan_name == NULL)
++ return -EINVAL;
++
++ while (chan[i].indio_dev) {
++ mutex_lock(&iio_map_list_lock);
++ list_for_each_entry(c, &iio_map_list, l) {
++ if (strcmp(chan[i].channel->datasheet_name,
++ c->map->adc_channel_label) != 0)
++ continue;
++ strcpy(chan_name[i], c->map->consumer_channel);
++ break;
++ }
++ mutex_unlock(&iio_map_list_lock);
++ i++;
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(iio_channel_get_name);
++
+ static int iio_channel_read(struct iio_channel *chan, int *val, int *val2,
+ enum iio_chan_info_enum info)
+ {
+@@ -443,6 +485,24 @@ err_unlock:
+ }
+ EXPORT_SYMBOL_GPL(iio_read_channel_raw);
+
++int iio_read_channel_all_raw(struct iio_channel *chan, int *val)
++{
++ int ret;
++
++ mutex_lock(&chan->indio_dev->info_exist_lock);
++ if (chan->indio_dev->info == NULL) {
++ ret = -ENODEV;
++ goto err_unlock;
++ }
++
++ ret = chan->indio_dev->info->read_all_raw(chan, val);
++err_unlock:
++ mutex_unlock(&chan->indio_dev->info_exist_lock);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(iio_read_channel_all_raw);
++
+ static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan,
+ int raw, int *processed, unsigned int scale)
+ {
+diff --git a/drivers/mfd/intel_msic.c b/drivers/mfd/intel_msic.c
+index d8d5137..44b60c9 100644
+--- a/drivers/mfd/intel_msic.c
++++ b/drivers/mfd/intel_msic.c
+@@ -18,7 +18,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
+
+-#include <asm/intel_scu_ipc.h>
++#include <asm/intel_scu_pmic.h>
+
+ #define MSIC_VENDOR(id) ((id >> 6) & 3)
+ #define MSIC_VERSION(id) (id & 0x3f)
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index c002d86..7daf746 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -147,6 +147,18 @@ config INTEL_MID_PTI
+ an Intel Atom (non-netbook) mobile device containing a MIPI
+ P1149.7 standard implementation.
+
++config INTEL_PTI_STM
++ tristate "MIPI Sytem Trace Macro (STM) for Intel"
++ default n
++ depends on INTEL_MID_PTI
++ help
++ The STM (Sytem Trace Monitor) driver control trace data
++ route through an Intel Tangier PTI port or through USB xDCI
++ interface with Debug-Class DvC.Trace support.
++
++ It provide the ability to PTI driver to setup the output and
++ to user to change the output with sysfs and exported header.
++
+ config SGI_IOC4
+ tristate "SGI IOC4 Base IO support"
+ depends on PCI
+@@ -527,6 +539,20 @@ config SRAM
+ the genalloc API. It is supposed to be used for small on-chip SRAM
+ areas found on many SoCs.
+
++config EMMC_IPANIC
++ bool "Intel kernel panic diagnostics driver FOR EMMC"
++ default n
++ ---help---
++ Driver which handles kernel panics and attempts to write
++ critical debugging data to EMMC.
++
++config EMMC_IPANIC_PLABEL
++ string "Intel kernel panic driver (EMMC_IPANIC) partition label"
++ depends on EMMC_IPANIC
++ default "panic"
++ ---help---
++ Set the default mmc partition label for EMMC_IPANIC driver.
++
+ source "drivers/misc/c2port/Kconfig"
+ source "drivers/misc/eeprom/Kconfig"
+ source "drivers/misc/cb710/Kconfig"
+@@ -536,4 +562,5 @@ source "drivers/misc/carma/Kconfig"
+ source "drivers/misc/altera-stapl/Kconfig"
+ source "drivers/misc/mei/Kconfig"
+ source "drivers/misc/vmw_vmci/Kconfig"
++source "drivers/misc/bcm-lpm/Kconfig"
+ endmenu
+diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
+index c235d5b..2e1ef8a 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -7,6 +7,7 @@ obj-$(CONFIG_AD525X_DPOT) += ad525x_dpot.o
+ obj-$(CONFIG_AD525X_DPOT_I2C) += ad525x_dpot-i2c.o
+ obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o
+ obj-$(CONFIG_INTEL_MID_PTI) += pti.o
++obj-$(CONFIG_INTEL_PTI_STM) += stm.o
+ obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o
+ obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
+ obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
+@@ -53,3 +54,5 @@ obj-$(CONFIG_INTEL_MEI) += mei/
+ obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/
+ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o
+ obj-$(CONFIG_SRAM) += sram.o
++obj-$(CONFIG_BCM_BT_LPM) +=bcm-lpm/
++obj-$(CONFIG_EMMC_IPANIC) += emmc_ipanic.o
+diff --git a/drivers/misc/bcm-lpm/Kconfig b/drivers/misc/bcm-lpm/Kconfig
+new file mode 100644
+index 0000000..cb8443a
+--- /dev/null
++++ b/drivers/misc/bcm-lpm/Kconfig
+@@ -0,0 +1,6 @@
++config BCM_BT_LPM
++ tristate "Broadcom Bluetooth Low Power Mode"
++ depends on SERIAL_MFD_HSU
++ default m
++ help
++ Select this module for Broadcom Bluetooth low power management.
+diff --git a/drivers/misc/bcm-lpm/Makefile b/drivers/misc/bcm-lpm/Makefile
+new file mode 100644
+index 0000000..6dd43fd
+--- /dev/null
++++ b/drivers/misc/bcm-lpm/Makefile
+@@ -0,0 +1 @@
++obj-$(CONFIG_BCM_BT_LPM) += bcm_bt_lpm.o
+diff --git a/drivers/misc/bcm-lpm/bcm_bt_lpm.c b/drivers/misc/bcm-lpm/bcm_bt_lpm.c
+new file mode 100644
+index 0000000..335a925
+--- /dev/null
++++ b/drivers/misc/bcm-lpm/bcm_bt_lpm.c
+@@ -0,0 +1,581 @@
++/*
++ * Bluetooth Broadcomm and low power control via GPIO
++ *
++ * Copyright (C) 2011 Google, 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/gpio.h>
++#include <linux/hrtimer.h>
++#include <linux/irq.h>
++#include <linux/rfkill.h>
++#include <linux/platform_device.h>
++#include <linux/interrupt.h>
++#include <linux/pm_runtime.h>
++#include <linux/delay.h>
++#include <asm/intel-mid.h>
++#include <asm/intel_mid_hsu.h>
++
++#ifndef CONFIG_ACPI
++#include <asm/bcm_bt_lpm.h>
++#else
++#include <linux/acpi.h>
++#include <linux/acpi_gpio.h>
++
++enum {
++ gpio_wake_acpi_idx,
++ gpio_enable_bt_acpi_idx,
++ host_wake_acpi_idx
++};
++#endif
++
++static struct rfkill *bt_rfkill;
++static bool bt_enabled;
++static bool host_wake_uart_enabled;
++static bool wake_uart_enabled;
++static bool int_handler_enabled;
++
++#define LPM_ON
++
++static void activate_irq_handler(void);
++
++struct bcm_bt_lpm {
++ unsigned int gpio_wake;
++ unsigned int gpio_host_wake;
++ unsigned int int_host_wake;
++ unsigned int gpio_enable_bt;
++
++ int wake;
++ int host_wake;
++
++ struct hrtimer enter_lpm_timer;
++ ktime_t enter_lpm_delay;
++
++ struct device *tty_dev;
++
++ int port;
++} bt_lpm;
++
++#ifdef LPM_ON
++static void uart_enable(struct device *tty)
++{
++ pr_debug("%s: runtime get\n", __func__);
++ /* Tell PM runtime to power on the tty device and block s0i3 */
++ pm_runtime_get(tty);
++}
++
++static void uart_disable(struct device *tty)
++{
++ pr_debug("%s: runtime put\n", __func__);
++ /* Tell PM runtime to release tty device and allow s0i3 */
++ pm_runtime_put(tty);
++}
++#endif
++
++#ifdef CONFIG_ACPI
++static int bcm_bt_lpm_acpi_probe(struct platform_device *pdev)
++{
++ struct acpi_gpio_info info;
++ acpi_handle handle;
++ acpi_integer port;
++
++ /*
++ * Handle ACPI specific initializations.
++ */
++ dev_dbg(&pdev->dev, "BCM2E1A ACPI specific probe\n");
++
++ bt_lpm.gpio_enable_bt = acpi_get_gpio_by_index(&pdev->dev,
++ gpio_enable_bt_acpi_idx, &info);
++ if (!gpio_is_valid(bt_lpm.gpio_enable_bt)) {
++ pr_err("%s: gpio %d for gpio_enable_bt not valid\n", __func__,
++ bt_lpm.gpio_enable_bt);
++ return -EINVAL;
++ }
++
++#ifdef LPM_ON
++ bt_lpm.gpio_wake = acpi_get_gpio_by_index(&pdev->dev,
++ gpio_wake_acpi_idx, &info);
++ if (!gpio_is_valid(bt_lpm.gpio_wake)) {
++ pr_err("%s: gpio %d for gpio_wake not valid\n", __func__,
++ bt_lpm.gpio_wake);
++ return -EINVAL;
++ }
++
++ bt_lpm.gpio_host_wake = acpi_get_gpio_by_index(&pdev->dev,
++ host_wake_acpi_idx, &info);
++ if (!gpio_is_valid(bt_lpm.gpio_host_wake)) {
++ pr_err("%s: gpio %d for gpio_host_wake not valid\n", __func__,
++ bt_lpm.gpio_host_wake);
++ return -EINVAL;
++ }
++
++ bt_lpm.int_host_wake = gpio_to_irq(bt_lpm.gpio_host_wake);
++
++ pr_debug("%s: gpio_wake %d, gpio_host_wake %d, int_host_wake %d\n",
++ __func__,
++ bt_lpm.gpio_wake,
++ bt_lpm.gpio_host_wake,
++ bt_lpm.int_host_wake);
++#endif
++
++ handle = DEVICE_ACPI_HANDLE(&pdev->dev);
++
++ if (ACPI_FAILURE(acpi_evaluate_integer(handle, "UART", NULL, &port))) {
++ dev_err(&pdev->dev, "Error evaluating UART port number\n");
++
++ /* FIXME - Force port 0 if the information is missing from the
++ * ACPI table.
++ * That will be removed once the ACPI tables will all have been
++ * updated.
++ */
++ port = 0;
++ }
++
++ bt_lpm.port = port;
++ pr_debug("%s: UART port %d\n", __func__, bt_lpm.port);
++
++ return 0;
++}
++#endif /* CONFIG_ACPI */
++
++static int bcm43xx_bt_rfkill_set_power(void *data, bool blocked)
++{
++ /* rfkill_ops callback. Turn transmitter on when blocked is false */
++
++ if (!blocked) {
++ gpio_set_value(bt_lpm.gpio_wake, 1);
++ /*
++ * Delay advice by BRCM is min 2.5ns,
++ * setting it between 10 and 50us for more confort
++ */
++ usleep_range(10, 50);
++
++ gpio_set_value(bt_lpm.gpio_enable_bt, 1);
++ pr_debug("%s: turn BT on\n", __func__);
++ } else {
++ gpio_set_value(bt_lpm.gpio_enable_bt, 0);
++ pr_debug("%s: turn BT off\n", __func__);
++ }
++
++ bt_enabled = !blocked;
++
++ return 0;
++}
++
++static const struct rfkill_ops bcm43xx_bt_rfkill_ops = {
++ .set_block = bcm43xx_bt_rfkill_set_power,
++};
++
++#ifdef LPM_ON
++static void set_wake_locked(int wake)
++{
++ bt_lpm.wake = wake;
++
++ if (!wake_uart_enabled && wake) {
++ WARN_ON(!bt_lpm.tty_dev);
++ uart_enable(bt_lpm.tty_dev);
++ }
++
++ gpio_set_value(bt_lpm.gpio_wake, wake);
++
++ if (wake_uart_enabled && !wake) {
++ WARN_ON(!bt_lpm.tty_dev);
++ uart_disable(bt_lpm.tty_dev);
++ }
++ wake_uart_enabled = wake;
++}
++
++static enum hrtimer_restart enter_lpm(struct hrtimer *timer)
++{
++ pr_debug("%s\n", __func__);
++
++ set_wake_locked(0);
++
++ return HRTIMER_NORESTART;
++}
++
++
++static void update_host_wake_locked(int host_wake)
++{
++ if (host_wake == bt_lpm.host_wake)
++ return;
++
++ bt_lpm.host_wake = host_wake;
++
++ if (host_wake) {
++ if (!host_wake_uart_enabled) {
++ WARN_ON(!bt_lpm.tty_dev);
++ uart_enable(bt_lpm.tty_dev);
++ }
++ } else {
++ if (host_wake_uart_enabled) {
++ WARN_ON(!bt_lpm.tty_dev);
++ uart_disable(bt_lpm.tty_dev);
++ }
++ }
++
++ host_wake_uart_enabled = host_wake;
++
++}
++
++static irqreturn_t host_wake_isr(int irq, void *dev)
++{
++ int host_wake;
++
++ host_wake = gpio_get_value(bt_lpm.gpio_host_wake);
++
++ pr_debug("%s: lpm %s\n", __func__, host_wake ? "off" : "on");
++
++ irq_set_irq_type(irq, host_wake ? IRQF_TRIGGER_FALLING :
++ IRQF_TRIGGER_RISING);
++
++ if (!bt_lpm.tty_dev) {
++ bt_lpm.host_wake = host_wake;
++ return IRQ_HANDLED;
++ }
++
++ update_host_wake_locked(host_wake);
++
++ return IRQ_HANDLED;
++}
++
++static void activate_irq_handler(void)
++{
++ int ret;
++
++ pr_debug("%s\n", __func__);
++
++ ret = request_irq(bt_lpm.int_host_wake, host_wake_isr,
++ IRQF_TRIGGER_RISING, "bt_host_wake", NULL);
++
++ if (ret < 0) {
++ pr_err("Error lpm request IRQ");
++ gpio_free(bt_lpm.gpio_wake);
++ gpio_free(bt_lpm.gpio_host_wake);
++ }
++}
++
++
++static void bcm_bt_lpm_wake_peer(struct device *dev)
++{
++ bt_lpm.tty_dev = dev;
++
++ /*
++ * the irq is enabled after the first host wake up signal.
++ * in the original code, the irq should be in levels but, since mfld
++ * does not support them, irq is triggering with edges.
++ */
++
++ if (!int_handler_enabled) {
++ int_handler_enabled = true;
++ activate_irq_handler();
++ }
++
++ hrtimer_try_to_cancel(&bt_lpm.enter_lpm_timer);
++
++ set_wake_locked(1);
++
++ hrtimer_start(&bt_lpm.enter_lpm_timer, bt_lpm.enter_lpm_delay,
++ HRTIMER_MODE_REL);
++
++}
++
++static int bcm_bt_lpm_init(struct platform_device *pdev)
++{
++ int ret;
++ struct device *tty_dev;
++
++ hrtimer_init(&bt_lpm.enter_lpm_timer, CLOCK_MONOTONIC,
++ HRTIMER_MODE_REL);
++ bt_lpm.enter_lpm_delay = ktime_set(1, 0); /* 1 sec */
++ bt_lpm.enter_lpm_timer.function = enter_lpm;
++
++ bt_lpm.host_wake = 0;
++
++ if (bt_lpm.gpio_host_wake < 0) {
++ pr_err("Error bt_lpm.gpio_host_wake\n");
++ return -ENODEV;
++ }
++
++ ret = irq_set_irq_wake(bt_lpm.int_host_wake, 1);
++ if (ret < 0) {
++ pr_err("Error lpm set irq IRQ");
++ gpio_free(bt_lpm.gpio_wake);
++ gpio_free(bt_lpm.gpio_host_wake);
++ return ret;
++ }
++
++ tty_dev = intel_mid_hsu_set_wake_peer(bt_lpm.port,
++ bcm_bt_lpm_wake_peer);
++ if (!tty_dev) {
++ pr_err("Error no tty dev");
++ gpio_free(bt_lpm.gpio_wake);
++ gpio_free(bt_lpm.gpio_host_wake);
++ return -ENODEV;
++ }
++
++ bcm_bt_lpm_wake_peer(tty_dev);
++ return 0;
++}
++#endif
++
++#ifndef CONFIG_ACPI
++static int bcm43xx_bluetooth_pdata_probe(struct platform_device *pdev)
++{
++ struct bcm_bt_lpm_platform_data *pdata = pdev->dev.platform_data;
++
++ if (pdata == NULL) {
++ pr_err("Cannot register bcm_bt_lpm drivers, pdata is NULL\n");
++ return -EINVAL;
++ }
++
++ if (!gpio_is_valid(pdata->gpio_enable)) {
++ pr_err("%s: gpio not valid\n", __func__);
++ return -EINVAL;
++ }
++
++#ifdef LPM_ON
++ if (!gpio_is_valid(pdata->gpio_wake) ||
++ !gpio_is_valid(pdata->gpio_host_wake)) {
++ pr_err("%s: gpio not valid\n", __func__);
++ return -EINVAL;
++ }
++#endif
++
++ bt_lpm.gpio_wake = pdata->gpio_wake;
++ bt_lpm.gpio_host_wake = pdata->gpio_host_wake;
++ bt_lpm.int_host_wake = pdata->int_host_wake;
++ bt_lpm.gpio_enable_bt = pdata->gpio_enable;
++
++ bt_lpm.port = pdata->port;
++
++ return 0;
++}
++#endif /* !CONFIG_ACPI */
++
++static int bcm43xx_bluetooth_probe(struct platform_device *pdev)
++{
++ bool default_state = true; /* off */
++ int ret = 0;
++
++ int_handler_enabled = false;
++
++#ifdef CONFIG_ACPI
++ if (ACPI_HANDLE(&pdev->dev)) {
++ /*
++ * acpi specific probe
++ */
++ pr_debug("%s for ACPI device %s\n", __func__,
++ dev_name(&pdev->dev));
++ if (bcm_bt_lpm_acpi_probe(pdev) < 0)
++ ret = -EINVAL;
++ } else
++ ret = -ENODEV;
++#else
++ ret = bcm43xx_bluetooth_pdata_probe(pdev);
++#endif
++
++ if (ret < 0) {
++ pr_err("%s: Cannot register platform data\n", __func__);
++ goto err_data_probe;
++ }
++
++ ret = gpio_request(bt_lpm.gpio_enable_bt, pdev->name);
++ if (ret < 0) {
++ pr_err("%s: Unable to request gpio %d\n", __func__,
++ bt_lpm.gpio_enable_bt);
++ goto err_gpio_enable_req;
++ }
++
++ ret = gpio_direction_output(bt_lpm.gpio_enable_bt, 0);
++ if (ret < 0) {
++ pr_err("%s: Unable to set int direction for gpio %d\n",
++ __func__, bt_lpm.gpio_enable_bt);
++ goto err_gpio_enable_dir;
++ }
++
++#ifdef LPM_ON
++ ret = gpio_request(bt_lpm.gpio_host_wake, pdev->name);
++ if (ret < 0) {
++ pr_err("%s: Unable to request gpio %d\n",
++ __func__, bt_lpm.gpio_host_wake);
++ goto err_gpio_host_wake_req;
++ }
++
++ ret = gpio_direction_input(bt_lpm.gpio_host_wake);
++ if (ret < 0) {
++ pr_err("%s: Unable to set direction for gpio %d\n", __func__,
++ bt_lpm.gpio_host_wake);
++ goto err_gpio_host_wake_dir;
++ }
++
++ ret = gpio_request(bt_lpm.gpio_wake, pdev->name);
++ if (ret < 0) {
++ pr_err("%s: Unable to request gpio %d\n", __func__,
++ bt_lpm.gpio_wake);
++ goto err_gpio_wake_req;
++ }
++
++ ret = gpio_direction_output(bt_lpm.gpio_wake, 0);
++ if (ret < 0) {
++ pr_err("%s: Unable to set direction for gpio %d\n", __func__,
++ bt_lpm.gpio_wake);
++ goto err_gpio_wake_dir;
++ }
++
++ pr_debug("%s: gpio_enable=%d, gpio_wake=%d, gpio_host_wake=%d\n",
++ __func__,
++ bt_lpm.gpio_enable_bt,
++ bt_lpm.gpio_wake,
++ bt_lpm.gpio_host_wake);
++#endif
++
++ bt_rfkill = rfkill_alloc("bcm43xx Bluetooth", &pdev->dev,
++ RFKILL_TYPE_BLUETOOTH, &bcm43xx_bt_rfkill_ops,
++ NULL);
++ if (unlikely(!bt_rfkill)) {
++ ret = -ENOMEM;
++ goto err_rfkill_alloc;
++ }
++
++ bcm43xx_bt_rfkill_set_power(NULL, default_state);
++ rfkill_init_sw_state(bt_rfkill, default_state);
++
++ ret = rfkill_register(bt_rfkill);
++ if (unlikely(ret))
++ goto err_rfkill_register;
++
++#ifdef LPM_ON
++ ret = bcm_bt_lpm_init(pdev);
++ if (ret)
++ goto err_lpm_init;
++#endif
++
++ return ret;
++
++err_lpm_init:
++ rfkill_unregister(bt_rfkill);
++err_rfkill_register:
++ rfkill_destroy(bt_rfkill);
++err_rfkill_alloc:
++#ifdef LPM_ON
++err_gpio_wake_dir:
++ gpio_free(bt_lpm.gpio_wake);
++err_gpio_wake_req:
++err_gpio_host_wake_dir:
++ gpio_free(bt_lpm.gpio_host_wake);
++err_gpio_host_wake_req:
++#endif
++err_gpio_enable_dir:
++ gpio_free(bt_lpm.gpio_enable_bt);
++err_gpio_enable_req:
++err_data_probe:
++ return ret;
++}
++
++static int bcm43xx_bluetooth_remove(struct platform_device *pdev)
++{
++ rfkill_unregister(bt_rfkill);
++ rfkill_destroy(bt_rfkill);
++
++ gpio_free(bt_lpm.gpio_enable_bt);
++#ifdef LPM_ON
++ gpio_free(bt_lpm.gpio_wake);
++ gpio_free(bt_lpm.gpio_host_wake);
++#endif
++ return 0;
++}
++#ifdef LPM_ON
++int bcm43xx_bluetooth_suspend(struct platform_device *pdev, pm_message_t state)
++{
++ int host_wake;
++
++ pr_debug("%s\n", __func__);
++
++ if (!bt_enabled)
++ return 0;
++
++ disable_irq(bt_lpm.int_host_wake);
++ host_wake = gpio_get_value(bt_lpm.gpio_host_wake);
++ if (host_wake) {
++ enable_irq(bt_lpm.int_host_wake);
++ pr_err("%s suspend error, gpio %d set\n", __func__,
++ bt_lpm.gpio_host_wake);
++ return -EBUSY;
++ }
++
++ return 0;
++}
++
++int bcm43xx_bluetooth_resume(struct platform_device *pdev)
++{
++ pr_debug("%s\n", __func__);
++
++ if (bt_enabled)
++ enable_irq(bt_lpm.int_host_wake);
++ return 0;
++}
++#endif
++
++#ifdef CONFIG_ACPI
++static struct acpi_device_id bcm_id_table[] = {
++ /* ACPI IDs here */
++ { "BCM2E1A", 0 },
++ { "BCM2E3A", 0 },
++ { }
++};
++
++MODULE_DEVICE_TABLE(acpi, bcm_id_table);
++#endif
++
++static struct platform_driver bcm43xx_bluetooth_platform_driver = {
++ .probe = bcm43xx_bluetooth_probe,
++ .remove = bcm43xx_bluetooth_remove,
++#ifdef LPM_ON
++ .suspend = bcm43xx_bluetooth_suspend,
++ .resume = bcm43xx_bluetooth_resume,
++#endif
++ .driver = {
++ .name = "bcm_bt_lpm",
++ .owner = THIS_MODULE,
++#ifdef CONFIG_ACPI
++ .acpi_match_table = ACPI_PTR(bcm_id_table),
++#endif
++ },
++};
++
++static int __init bcm43xx_bluetooth_init(void)
++{
++ bt_enabled = false;
++ return platform_driver_register(&bcm43xx_bluetooth_platform_driver);
++}
++
++static void __exit bcm43xx_bluetooth_exit(void)
++{
++ platform_driver_unregister(&bcm43xx_bluetooth_platform_driver);
++}
++
++
++module_init(bcm43xx_bluetooth_init);
++module_exit(bcm43xx_bluetooth_exit);
++
++MODULE_ALIAS("platform:bcm43xx");
++MODULE_DESCRIPTION("bcm43xx_bluetooth");
++MODULE_AUTHOR("Jaikumar Ganesh <jaikumar@google.com>");
++MODULE_LICENSE("GPL");
++
+diff --git a/drivers/misc/emmc_ipanic.c b/drivers/misc/emmc_ipanic.c
+new file mode 100644
+index 0000000..d1bdfdd
+--- /dev/null
++++ b/drivers/misc/emmc_ipanic.c
+@@ -0,0 +1,1158 @@
++/*
++ * drivers/misc/emmc_ipanic.c
++ *
++ * Copyright (C) 2011 Intel Corp
++ * Author: dongxing.zhang@intel.com
++ * Author: jun.zhang@intel.com
++ * Author: chuansheng.liu@intel.com
++ * 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; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/device.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <linux/sched.h>
++#include <linux/wait.h>
++#include <linux/platform_device.h>
++#include <linux/uaccess.h>
++#include <linux/notifier.h>
++#include <linux/mmc/host.h>
++#include <linux/debugfs.h>
++#include <linux/fs.h>
++#include <linux/proc_fs.h>
++#include <linux/mutex.h>
++#include <linux/workqueue.h>
++#include <linux/preempt.h>
++#include <linux/pci.h>
++#include <linux/nmi.h>
++#include <linux/blkdev.h>
++#include <linux/genhd.h>
++#include <linux/panic_gbuffer.h>
++#include "emmc_ipanic.h"
++
++#include <linux/kmsg_dump.h>
++
++static char *part_label = "";
++module_param(part_label, charp, 0);
++MODULE_PARM_DESC(part_label, "IPanic mmc partition device label (panic)");
++
++static u32 disable_emmc_ipanic;
++core_param(disable_emmc_ipanic, disable_emmc_ipanic, uint, 0644);
++
++static struct mmc_emergency_info emmc_info = {
++ .init = mmc_emergency_init,
++ .write = mmc_emergency_write,
++ .part_label = CONFIG_EMMC_IPANIC_PLABEL,
++};
++
++static unsigned char *ipanic_proc_entry_name[PROC_MAX_ENTRIES] = {
++ "emmc_ipanic_header",
++ "emmc_ipanic_console",
++ "emmc_ipanic_threads",
++ "emmc_ipanic_gbuffer"
++};
++
++static int in_panic;
++static struct emmc_ipanic_data drv_ctx;
++static struct work_struct proc_removal_work;
++static int log_offset[IPANIC_LOG_MAX];
++static int log_len[IPANIC_LOG_MAX]; /* sector count */
++static int log_size[IPANIC_LOG_MAX]; /* byte count */
++static size_t log_head[IPANIC_LOG_MAX];
++static size_t log_woff[IPANIC_LOG_MAX];
++static unsigned char last_chunk_buf[SECTOR_SIZE];
++static int last_chunk_buf_len;
++static DEFINE_MUTEX(drv_mutex);
++static void (*func_stream_emmc) (void);
++
++static struct kmsg_dumper ipanic_dumper;
++
++static void emmc_panic_erase(unsigned char *buffer, Sector * sect)
++{
++ struct emmc_ipanic_data *ctx = &drv_ctx;
++ struct mmc_emergency_info *emmc = ctx->emmc;
++ unsigned char *read_buf_ptr = buffer;
++ Sector new_sect;
++ int rc;
++
++ if (!emmc) {
++ pr_err("%s:invalid emmc infomation\n", __func__);
++ return;
++ }
++
++ if (!read_buf_ptr || !sect) {
++ sect = &new_sect;
++ if (!emmc->bdev) {
++ pr_err("%s:invalid emmc block device\n", __func__);
++ goto out;
++ }
++ /* make sure the block device is open rw */
++ rc = blkdev_get(emmc->bdev, FMODE_READ | FMODE_WRITE,
++ emmc_panic_erase);
++ if (rc < 0) {
++ pr_err("%s: blk_dev_get failed!\n", __func__);
++ goto out;
++ }
++
++ /*read panic header */
++ read_buf_ptr =
++ read_dev_sector(emmc->bdev, emmc->start_block, sect);
++ if (!read_buf_ptr) {
++ pr_err("%s: read sector error(%llu)!\n",
++ __func__, (u64) emmc->start_block);
++ goto out;
++ }
++ }
++
++ /*write all zero to panic header */
++ lock_page(sect->v);
++ memset(read_buf_ptr, 0, SECTOR_SIZE);
++ set_page_dirty(sect->v);
++ unlock_page(sect->v);
++ sync_blockdev(emmc->bdev);
++
++ if (!read_buf_ptr)
++ put_dev_sector(*sect);
++out:
++ memset(&ctx->hdr, 0, SECTOR_SIZE);
++ return;
++}
++
++static int emmc_read(struct mmc_emergency_info *emmc, void *holder,
++ char *buffer, off_t offset, int count, bool to_user)
++{
++ unsigned char *read_ptr;
++ unsigned int sector_no;
++ off_t sector_offset;
++ Sector sect;
++ int rc;
++
++ if (!emmc) {
++ pr_err("%s:invalid emmc infomation\n", __func__);
++ return 0;
++ }
++ if (!emmc->bdev) {
++ pr_err("%s:invalid emmc block device\n", __func__);
++ return 0;
++ }
++
++ sector_no = offset >> SECTOR_SIZE_SHIFT;
++ sector_offset = offset & (SECTOR_SIZE - 1);
++ if (sector_no >= emmc->block_count) {
++ pr_err("%s: reading an invalid address\n", __func__);
++ return -EINVAL;
++ }
++
++ /* make sure the block device is open rw */
++ rc = blkdev_get(emmc->bdev, FMODE_READ | FMODE_WRITE, holder);
++ if (rc < 0) {
++ pr_err("%s: blk_dev_get failed!\n", __func__);
++ return 0;
++ }
++
++ read_ptr = read_dev_sector(emmc->bdev, sector_no + emmc->start_block,
++ &sect);
++ if (!read_ptr) {
++ put_dev_sector(sect);
++ return -EINVAL;
++ }
++ /* count and read_ptr are updated to match flash page size */
++ if (count + sector_offset > SECTOR_SIZE)
++ count = SECTOR_SIZE - sector_offset;
++
++ if (sector_offset)
++ read_ptr += sector_offset;
++
++ if (to_user) {
++ if (copy_to_user(buffer, read_ptr, count)) {
++ pr_err("%s: Failed to copy buffer to User\n", __func__);
++ return 0;
++ }
++ } else
++ memcpy(buffer, read_ptr, count);
++
++ put_dev_sector(sect);
++
++ return count;
++}
++
++static ssize_t emmc_ipanic_gbuffer_proc_read(struct file *file,
++ char __user * buffer, size_t count,
++ loff_t * ppos)
++{
++ struct emmc_ipanic_data *ctx = &drv_ctx;
++ size_t log_len, log_head;
++ off_t log_off;
++ int rc;
++
++ if (!ctx) {
++ pr_err("%s:invalid panic handler\n", __func__);
++ return 0;
++ }
++
++ if (!count)
++ return 0;
++
++ mutex_lock(&drv_mutex);
++
++ log_off = ctx->curr.log_offset[IPANIC_LOG_GBUFFER];
++ log_len = ctx->curr.log_length[IPANIC_LOG_GBUFFER];
++ log_head = ctx->curr.log_head[IPANIC_LOG_GBUFFER];
++
++ if (*ppos >= log_len) {
++ mutex_unlock(&drv_mutex);
++ return 0;
++ }
++
++ if (*ppos < log_len - log_head) {
++ /* No overflow (log_head == 0)
++ * or
++ * overflow 2nd part buf (log_head = log_woff)
++ * |-------w--------|
++ * off^
++ * |--------|
++ */
++ log_off += log_head;
++ log_len -= log_head;
++ } else {
++ /* 1st part buf
++ * |-------w--------|
++ * off^
++ * |-------|
++ */
++ *ppos -= (log_len - log_head);
++ log_len = log_head;
++ }
++
++ if ((*ppos + count) > log_len)
++ count = log_len - *ppos;
++
++ rc = emmc_read(ctx->emmc, emmc_ipanic_gbuffer_proc_read,
++ buffer, log_off + *ppos, count, true);
++ if (rc <= 0) {
++ mutex_unlock(&drv_mutex);
++ pr_err
++ ("%s: emmc_read: invalid args: offset:0x%08llx, count:%zd",
++ __func__, (u64) (log_off + *ppos), count);
++ return rc;
++ }
++
++ *ppos += rc;
++
++ mutex_unlock(&drv_mutex);
++
++ return rc;
++}
++
++static ssize_t emmc_ipanic_proc_read_by_log(struct file *file,
++ char __user * buffer, size_t count,
++ loff_t * ppos, int log)
++{
++ struct emmc_ipanic_data *ctx = &drv_ctx;
++ size_t file_length;
++ off_t file_offset;
++ int rc;
++
++ if (!ctx) {
++ pr_err("%s:invalid panic handler\n", __func__);
++ return 0;
++ }
++
++ if (!count)
++ return 0;
++
++ if (log < 0 || log > IPANIC_LOG_MAX) {
++ pr_err("%s: Bad log number (%d)\n", __func__, log);
++ return -EINVAL;
++ }
++
++ mutex_lock(&drv_mutex);
++
++ if (log == IPANIC_LOG_HEADER) {
++ file_length = ctx->hdr.log_size;
++ file_offset = offsetof(struct panic_header, panic);
++ } else {
++ file_length = ctx->curr.log_length[log];
++ file_offset = ctx->curr.log_offset[log];
++ }
++
++ if (*ppos >= file_length) {
++ mutex_unlock(&drv_mutex);
++ return 0;
++ }
++
++ if ((*ppos + count) > file_length)
++ count = file_length - *ppos;
++
++ rc = emmc_read(ctx->emmc, emmc_ipanic_proc_read_by_log,
++ buffer, file_offset + *ppos, count, true);
++ if (rc <= 0) {
++ mutex_unlock(&drv_mutex);
++ pr_err
++ ("%s: emmc_read: invalid args: offset:0x%08llx, count:%zd",
++ __func__, (u64) (file_offset + *ppos), count);
++ return rc;
++ }
++
++ *ppos += rc;
++
++ mutex_unlock(&drv_mutex);
++
++ return rc;
++}
++
++static ssize_t emmc_ipanic_proc_read_hdr(struct file *file,
++ char __user * buffer, size_t count,
++ loff_t * ppos)
++{
++ return emmc_ipanic_proc_read_by_log(file, buffer, count, ppos,
++ IPANIC_LOG_HEADER);
++}
++
++static ssize_t emmc_ipanic_proc_read0(struct file *file, char __user * buffer,
++ size_t count, loff_t * ppos)
++{
++ return emmc_ipanic_proc_read_by_log(file, buffer, count, ppos,
++ IPANIC_LOG_CONSOLE);
++}
++
++static ssize_t emmc_ipanic_proc_read1(struct file *file, char __user * buffer,
++ size_t count, loff_t * ppos)
++{
++ return emmc_ipanic_proc_read_by_log(file, buffer, count, ppos,
++ IPANIC_LOG_THREADS);
++}
++
++static void emmc_ipanic_remove_proc_work(struct work_struct *work)
++{
++ struct emmc_ipanic_data *ctx = &drv_ctx;
++ int log;
++
++ mutex_lock(&drv_mutex);
++ emmc_panic_erase(NULL, NULL);
++
++ for (log = 0; log < PROC_MAX_ENTRIES; log++) {
++ if (ctx->ipanic_proc_entry[log]) {
++ remove_proc_entry(ctx->ipanic_proc_entry_name
++ [log], NULL);
++ ctx->ipanic_proc_entry[log] = NULL;
++ }
++ }
++ mutex_unlock(&drv_mutex);
++}
++
++static ssize_t emmc_ipanic_proc_write(struct file *file,
++ const char __user * buffer,
++ size_t count, loff_t * ppos)
++{
++ schedule_work(&proc_removal_work);
++ return count;
++}
++
++/* In section order inside panic partition : */
++static const struct file_operations ipanic_emmc_read_header_fops = {
++ .read = emmc_ipanic_proc_read_hdr,
++ .write = emmc_ipanic_proc_write,
++};
++
++static const struct file_operations ipanic_emmc0_fops = {
++ .read = emmc_ipanic_proc_read0,
++ .write = emmc_ipanic_proc_write,
++};
++
++static const struct file_operations ipanic_emmc1_fops = {
++ .read = emmc_ipanic_proc_read1,
++ .write = emmc_ipanic_proc_write,
++};
++
++static const struct file_operations ipanic_emmc_gbuffer_fops = {
++ .read = emmc_ipanic_gbuffer_proc_read,
++ .write = emmc_ipanic_proc_write
++};
++
++static void emmc_panic_notify_add(void)
++{
++ struct emmc_ipanic_data *ctx = &drv_ctx;
++ struct mmc_emergency_info *emmc;
++ unsigned char *read_buf_ptr;
++ Sector sect;
++ int rc, idx_log, idx_proc;
++ int proc_entry_created = 0;
++
++ if (!ctx) {
++ pr_err("%s:invalid panic handler\n", __func__);
++ return;
++ }
++
++ emmc = ctx->emmc;
++ if (!emmc) {
++ pr_err("%s:invalid emmc infomation\n", __func__);
++ goto out_err;
++ }
++
++ if (!emmc->bdev) {
++ pr_err("%s:invalid emmc block device\n", __func__);
++ goto out_err;
++ }
++
++ /* make sure the block device is open rw */
++ rc = blkdev_get(emmc->bdev, FMODE_READ | FMODE_WRITE,
++ emmc_panic_notify_add);
++ if (rc < 0) {
++ pr_err("%s: blk_dev_get failed!\n", __func__);
++ goto out_err;
++ }
++
++ /* read panic header */
++ read_buf_ptr = read_dev_sector(emmc->bdev, emmc->start_block, &sect);
++ if (!read_buf_ptr) {
++ pr_err("%s: read sector error(%llu)!\n", __func__,
++ (u64) emmc->start_block);
++ return;
++ }
++
++ memcpy(&ctx->hdr, read_buf_ptr, sizeof(struct panic_header));
++
++ if (ctx->hdr.magic != PANIC_MAGIC) {
++ pr_info("%s: bad magic %x, no data available\n",
++ __func__, ctx->hdr.magic);
++ emmc_panic_erase(read_buf_ptr, &sect);
++ goto put_sector;
++ }
++
++ pr_info("%s: Data available in panic partition\n", __func__);
++
++ if (ctx->hdr.version != PHDR_VERSION) {
++ pr_err("%s: Version mismatch (%d != %d)\n",
++ __func__, ctx->hdr.version, PHDR_VERSION);
++ emmc_panic_erase(read_buf_ptr, &sect);
++ goto put_sector;
++ }
++
++ /* Create proc entry for the panic header */
++ ctx->ipanic_proc_entry[PROC_HEADER_INDEX] =
++ proc_create(ctx->ipanic_proc_entry_name
++ [PROC_HEADER_INDEX], S_IFREG | S_IRUGO, NULL,
++ &ipanic_emmc_read_header_fops);
++
++ if (!ctx->ipanic_proc_entry[PROC_HEADER_INDEX])
++ pr_err("%s: failed creating proc file\n", __func__);
++ else {
++ proc_entry_created = 1;
++ pr_info("%s: proc entry created: %s\n", __func__,
++ ctx->ipanic_proc_entry_name[PROC_HEADER_INDEX]);
++ }
++
++ /* read log_info to retrieve block numbers and offsets */
++ read_buf_ptr =
++ read_dev_sector(emmc->bdev, emmc->start_block + 1, &sect);
++ if (!read_buf_ptr) {
++ pr_err("%s: read sector error(%llu)!\n", __func__,
++ (u64) emmc->start_block + 1);
++ return;
++ }
++
++ memcpy(&ctx->curr, read_buf_ptr, sizeof(struct log_info));
++
++ /* Log files other than header */
++ for (idx_log = 0; idx_log < IPANIC_LOG_MAX; idx_log++) {
++
++ pr_info("%s: log file %u(%u, %u)\n", __func__, idx_log,
++ ctx->curr.log_offset[idx_log],
++ ctx->curr.log_length[idx_log]);
++
++ /* Skip empty file. */
++ if (ctx->curr.log_length[idx_log] == 0) {
++ pr_info("%s: empty log file %u\n", __func__, idx_log);
++ continue;
++ }
++
++ /* Create proc entry for console, threads and gbuffer log. */
++ if (idx_log == IPANIC_LOG_CONSOLE) {
++ idx_proc = PROC_CONSOLE_INDEX;
++ ctx->ipanic_proc_entry[PROC_CONSOLE_INDEX] =
++ proc_create(ctx->ipanic_proc_entry_name
++ [PROC_CONSOLE_INDEX], S_IFREG | S_IRUGO,
++ NULL, &ipanic_emmc0_fops);
++ } else if (idx_log == IPANIC_LOG_THREADS) {
++ idx_proc = PROC_THREADS_INDEX;
++ ctx->ipanic_proc_entry[PROC_THREADS_INDEX] =
++ proc_create(ctx->ipanic_proc_entry_name
++ [PROC_THREADS_INDEX], S_IFREG | S_IRUGO,
++ NULL, &ipanic_emmc1_fops);
++ } else if (idx_log == IPANIC_LOG_GBUFFER) {
++ idx_proc = PROC_GBUFFER_INDEX;
++ ctx->ipanic_proc_entry[PROC_GBUFFER_INDEX] =
++ proc_create(ctx->ipanic_proc_entry_name
++ [PROC_GBUFFER_INDEX], S_IFREG | S_IRUGO,
++ NULL, &ipanic_emmc_gbuffer_fops);
++ } else {
++ /* No proc entry for this index */
++ idx_proc = 0;
++ continue;
++ }
++ if (!ctx->ipanic_proc_entry[idx_proc])
++ pr_err("%s: failed creating proc file\n", __func__);
++ else {
++ proc_entry_created = 1;
++ pr_info("%s: proc entry created: %s\n",
++ __func__,
++ ctx->ipanic_proc_entry_name[idx_proc]);
++ }
++ }
++
++ if (!proc_entry_created)
++ emmc_panic_erase(read_buf_ptr, &sect);
++
++put_sector:
++ put_dev_sector(sect);
++ return;
++out_err:
++ ctx->emmc = NULL;
++}
++
++static void emmc_panic_notify_remove(void)
++{
++ struct emmc_ipanic_data *ctx = &drv_ctx;
++
++ if (ctx->emmc && ctx->emmc->part_dev) {
++ put_device(ctx->emmc->part_dev);
++ ctx->emmc->bdev = NULL;
++ }
++
++ ctx->emmc = NULL;
++}
++
++static int emmc_ipanic_writeflashpage(struct mmc_emergency_info *emmc,
++ loff_t to, const u_char * buf)
++{
++ int rc;
++ size_t wlen = SECTOR_SIZE;
++
++ if (to >= emmc->start_block + emmc->block_count) {
++ pr_emerg("%s: panic partition is full.\n", __func__);
++ return 0;
++ }
++
++ rc = emmc->write((char *)buf, (unsigned int)to);
++ if (rc) {
++ pr_emerg("%s: Error writing data to flash (%d)\n",
++ __func__, rc);
++ return rc;
++ }
++
++ return wlen;
++}
++
++/*
++ * Writes the contents of the console to the specified offset in flash.
++ * Returns number of bytes written
++ */
++static int emmc_ipanic_write_console(struct mmc_emergency_info *emmc,
++ unsigned int off, int *actual_size)
++{
++ struct emmc_ipanic_data *ctx = &drv_ctx;
++ int saved_oip, rc, block_shift = 0, bounce_idx = 0;
++ size_t line_len = 0;
++ bool ret;
++
++ static unsigned char line[SECTOR_SIZE];
++
++ *actual_size = 0;
++ while (1) {
++ saved_oip = oops_in_progress;
++ oops_in_progress = 1;
++ bounce_idx = 0;
++
++ if (last_chunk_buf_len) {
++ memcpy(ctx->bounce, last_chunk_buf, last_chunk_buf_len);
++ bounce_idx += last_chunk_buf_len;
++ last_chunk_buf_len = 0;
++ }
++
++ do {
++ ret = kmsg_dump_get_line(&ipanic_dumper, false,
++ line, SECTOR_SIZE, &line_len);
++
++ if (ret) {
++ if (bounce_idx + line_len < SECTOR_SIZE) {
++ memcpy(ctx->bounce + bounce_idx,
++ line, line_len);
++ bounce_idx += line_len;
++ } else {
++ int len = SECTOR_SIZE - bounce_idx;
++ memcpy(ctx->bounce + bounce_idx,
++ line, len);
++ bounce_idx = SECTOR_SIZE;
++ memcpy(last_chunk_buf,
++ line + len, line_len - len);
++ last_chunk_buf_len = line_len - len;
++ }
++ }
++ } while (ret && (bounce_idx != SECTOR_SIZE));
++
++ oops_in_progress = saved_oip;
++
++ /* If it is the last chunk, just copy it to last chunk
++ * buffer and exit loop.
++ */
++ if (!ret) {
++ /* Leave the last chunk for next writing */
++ memcpy(last_chunk_buf, ctx->bounce, bounce_idx);
++ last_chunk_buf_len = bounce_idx;
++ break;
++ }
++
++ rc = emmc_ipanic_writeflashpage(emmc, off + block_shift,
++ ctx->bounce);
++ if (rc <= 0) {
++ pr_emerg("%s: Flash write failed (%d)\n", __func__, rc);
++ return block_shift;
++ }
++
++ block_shift++;
++ *actual_size += SECTOR_SIZE;
++ }
++
++ return block_shift;
++}
++
++static void emmc_ipanic_flush_lastchunk_emmc(loff_t to,
++ int *size_written,
++ int *sector_written)
++{
++ struct emmc_ipanic_data *ctx = &drv_ctx;
++ struct mmc_emergency_info *emmc = ctx->emmc;
++ int rc = 0;
++
++ if (last_chunk_buf_len) {
++ memset(last_chunk_buf + last_chunk_buf_len, 0,
++ SECTOR_SIZE - last_chunk_buf_len);
++
++ rc = emmc_ipanic_writeflashpage(emmc, to, last_chunk_buf);
++ if (rc <= 0) {
++ pr_emerg("emmc_ipanic: write last chunk failed (%d)\n",
++ rc);
++ return;
++ }
++
++ *size_written += last_chunk_buf_len;
++ (*sector_written)++;
++ last_chunk_buf_len = 0;
++ }
++ return;
++}
++
++static void emmc_ipanic_write_thread_func(void)
++{
++ struct emmc_ipanic_data *ctx = &drv_ctx;
++ struct mmc_emergency_info *emmc = ctx->emmc;
++ int size_written;
++ int thread_sector_count;
++
++ thread_sector_count =
++ emmc_ipanic_write_console(emmc,
++ log_offset[IPANIC_LOG_THREADS] +
++ log_len[IPANIC_LOG_THREADS],
++ &size_written);
++ if (thread_sector_count < 0) {
++ pr_emerg("Error writing threads to panic log! (%d)\n",
++ log_len[IPANIC_LOG_THREADS]);
++ return;
++ }
++ log_size[IPANIC_LOG_THREADS] += size_written;
++ log_len[IPANIC_LOG_THREADS] += thread_sector_count;
++
++ /*reset the log buffer */
++ log_buf_clear();
++ kmsg_dump_rewind(&ipanic_dumper);
++}
++
++static void emmc_ipanic_write_logbuf(struct mmc_emergency_info *emmc, int log)
++{
++ /*
++ * Write the log data from the third block :
++ * - the first block is reserved for panic header
++ * - the second one is reserved for offset information
++ */
++ log_offset[log] = emmc->start_block + 2;
++ log_len[log] = emmc_ipanic_write_console(emmc, log_offset[log],
++ &log_size[log]);
++ if (log_size[log] < 0) {
++ pr_emerg("Error writing console to panic log! (%d)\n",
++ log_len[log]);
++ log_size[log] = 0;
++ log_len[log] = 0;
++ }
++ /* flush last chunk buffer for console */
++ emmc_ipanic_flush_lastchunk_emmc(log_offset[log] +
++ log_len[log],
++ &log_size[log], &log_len[log]);
++}
++
++static void emmc_ipanic_write_calltrace(struct mmc_emergency_info *emmc,
++ int log)
++{
++ log_offset[log] = log_offset[log - 1] + log_len[log - 1];
++ /*
++ * config func_stream_emmc to emmc_ipanic_write_thread_func to
++ * stream thread call trace.
++ */
++ log_buf_clear();
++ kmsg_dump_rewind(&ipanic_dumper);
++ func_stream_emmc = emmc_ipanic_write_thread_func;
++ show_state_filter(0);
++
++ /* flush last chunk buffer */
++ emmc_ipanic_flush_lastchunk_emmc(log_offset[log] +
++ log_len[log],
++ &log_size[log], &log_len[log]);
++}
++
++static int emmc_ipanic_write_gbuffer_data(struct mmc_emergency_info *emmc,
++ struct g_buffer_header *gbuffer,
++ unsigned int off, int *actual_size)
++{
++ int rc, block_shift = 0;
++ size_t log_off = 0;
++ size_t log_size;
++ unsigned char *buf = gbuffer->base;
++
++ if (gbuffer->head)
++ /* has overflow */
++ log_size = gbuffer->size;
++ else
++ /* no overflow */
++ log_size = gbuffer->woff;
++
++ while (log_off < log_size) {
++ size_t size_copy = log_size - log_off;
++ if (size_copy < SECTOR_SIZE) {
++ /*
++ * flash page not complete, flushed with
++ * emmc_ipanic_flush_lastchunk_emmc
++ */
++ memcpy(last_chunk_buf, buf + log_off, size_copy);
++ last_chunk_buf_len = size_copy;
++ break;
++ }
++ rc = emmc_ipanic_writeflashpage(emmc, off + block_shift,
++ buf + log_off);
++ if (rc <= 0) {
++ pr_emerg("%s: Flash write failed (%d)\n", __func__, rc);
++ return 0;
++ }
++ log_off += rc;
++ block_shift++;
++ }
++ *actual_size = log_off;
++
++ return block_shift;
++}
++
++static struct g_buffer_header gbuffer = {
++ .base = NULL,
++};
++
++static void emmc_ipanic_write_gbuffer(struct mmc_emergency_info *emmc, int log)
++{
++ struct g_buffer_header *m_gbuffer = &gbuffer;
++
++ log_offset[log] = log_offset[log - 1] + log_len[log - 1];
++
++ pr_info("write gbuffer data\n");
++ if (!m_gbuffer->base) {
++ pr_err("Ipanic error, no gbuffer data\n");
++ return;
++ }
++
++ log_len[log] = emmc_ipanic_write_gbuffer_data(emmc, m_gbuffer,
++ log_offset[log],
++ &log_size[log]);
++ if (log_len[log] < 0) {
++ pr_emerg("Error writing gbuffer to panic log! (%d)\n",
++ log_len[log]);
++ log_size[log] = 0;
++ log_len[log] = 0;
++ }
++ /* flush last chunk buffer */
++ emmc_ipanic_flush_lastchunk_emmc(log_offset[log] + log_len[log],
++ &log_size[log], &log_len[log]);
++ log_head[log] = m_gbuffer->head;
++ log_woff[log] = m_gbuffer->woff;
++ pr_info("write gbuffer data END\n");
++}
++
++/*
++ * Exported in <linux/panic_gbuffer.h>
++ */
++void panic_set_gbuffer(struct g_buffer_header *buf)
++{
++ if (gbuffer.base) {
++ pr_err("%s: gbuffer already set to 0x%p, can not set again",
++ __func__, gbuffer.base);
++ return;
++ }
++
++ gbuffer.base = buf->base;
++ gbuffer.size = buf->size;
++ gbuffer.woff = buf->woff;
++ gbuffer.head = buf->head;
++}
++
++EXPORT_SYMBOL(panic_set_gbuffer);
++
++static void emmc_ipanic_write_pageheader(struct mmc_emergency_info *emmc)
++{
++ struct emmc_ipanic_data *ctx = &drv_ctx;
++ struct panic_header *hdr = (struct panic_header *)ctx->bounce;
++ int wc;
++ size_t len, total, max;
++
++ memset(ctx->bounce, 0, SECTOR_SIZE);
++ hdr->magic = PANIC_MAGIC;
++ hdr->version = PHDR_VERSION;
++
++ total = snprintf(hdr->panic, SECTOR_SIZE, "###Kernel panic###\n");
++
++ max = SECTOR_SIZE - offsetof(struct panic_header, panic) - total;
++ kmsg_dump_get_buffer(&ipanic_dumper, false, last_chunk_buf, max, &len);
++ kmsg_dump_rewind(&ipanic_dumper);
++
++ memcpy(hdr->panic + total, last_chunk_buf, len);
++ hdr->log_size = len + total;
++
++ /* Write header block */
++ wc = emmc_ipanic_writeflashpage(emmc, emmc->start_block, ctx->bounce);
++ if (wc <= 0) {
++ pr_emerg("emmc_ipanic: Info write failed (%d)\n", wc);
++ return;
++ }
++}
++
++static void emmc_ipanic_clean_loginfo(struct mmc_emergency_info *emmc)
++{
++ struct emmc_ipanic_data *ctx = &drv_ctx;
++ int rc;
++
++ memset(log_offset, 0, IPANIC_LOG_MAX * sizeof(int));
++ memset(log_len, 0, IPANIC_LOG_MAX * sizeof(int));
++ memset(log_size, 0, IPANIC_LOG_MAX * sizeof(int));
++
++ memset(ctx->bounce, 0, SECTOR_SIZE);
++
++ rc = emmc_ipanic_writeflashpage(emmc, emmc->start_block + 1,
++ ctx->bounce);
++ if (rc <= 0) {
++ pr_emerg("emmc_ipanic: Header write failed (%d)\n", rc);
++ return;
++ }
++}
++
++static void emmc_ipanic_write_loginfo(struct mmc_emergency_info *emmc,
++ int newlog)
++{
++ struct emmc_ipanic_data *ctx = &drv_ctx;
++ struct log_info *info = (struct log_info *)ctx->bounce;
++ int log = IPANIC_LOG_CONSOLE;
++ int rc;
++
++ if ((newlog < 0) || (newlog >= IPANIC_LOG_MAX))
++ return;
++
++ if (log_size[newlog] == 0)
++ return;
++
++ memset(ctx->bounce, 0, SECTOR_SIZE);
++ /*Fill up log offset and size */
++ while (log < IPANIC_LOG_MAX) {
++ /*Configurate log offset and log size */
++ info->log_offset[log] = (log_offset[log] - emmc->start_block)
++ << SECTOR_SIZE_SHIFT;
++ info->log_length[log] = log_size[log];
++ info->log_head[log] = log_head[log];
++ info->log_woff[log] = log_woff[log];
++ log++;
++ }
++ rc = emmc_ipanic_writeflashpage(emmc, emmc->start_block + 1,
++ ctx->bounce);
++ if (rc <= 0) {
++ pr_emerg("emmc_ipanic: Header write failed (%d)\n", rc);
++ return;
++ }
++}
++
++static int emmc_ipanic(struct notifier_block *this, unsigned long event,
++ void *ptr)
++{
++ struct emmc_ipanic_data *ctx = &drv_ctx;
++ struct mmc_emergency_info *emmc;
++ int rc, log;
++
++ pr_emerg("panic notified\n");
++
++ if (in_panic || disable_emmc_ipanic)
++ return NOTIFY_DONE;
++
++ in_panic = 1;
++
++#ifdef CONFIG_PREEMPT
++ /* Ensure that cond_resched() won't try to preempt anybody */
++ add_preempt_count(PREEMPT_ACTIVE);
++#endif
++ touch_nmi_watchdog();
++
++ if (!ctx)
++ goto out;
++ emmc = ctx->emmc;
++ if (!emmc)
++ goto out;
++ if (ctx->hdr.magic) {
++ pr_emerg("Crash partition in use!\n");
++ goto out;
++ }
++
++ rc = emmc->init();
++ if (rc) {
++ /* String too long to fit on 1 80-char line */
++ pr_emerg("%s %s, rc=%d\n",
++ "Emmc emergency driver is",
++ "not initialized successfully!", rc);
++ goto out;
++ }
++
++ /* Prepare kmsg dumper */
++ ipanic_dumper.active = 1;
++ /* Rewind kmsg dumper */
++ kmsg_dump_rewind(&ipanic_dumper);
++
++ /* Write emmc ipanic partition header */
++ emmc_ipanic_write_pageheader(emmc);
++ /* Clean emmc ipanic sections offsets */
++ emmc_ipanic_clean_loginfo(emmc);
++
++ /*Write all buffer into emmc */
++ log = IPANIC_LOG_CONSOLE;
++ while (log < IPANIC_LOG_MAX) {
++ /* Clear temporary buffer */
++ memset(ctx->bounce, 0, SECTOR_SIZE);
++ /* Log every buffer into emmc */
++ switch (log) {
++ case IPANIC_LOG_CONSOLE:
++ emmc_ipanic_write_logbuf(emmc, log);
++ break;
++ case IPANIC_LOG_THREADS:
++ emmc_ipanic_write_calltrace(emmc, log);
++ break;
++ case IPANIC_LOG_GBUFFER:
++ emmc_ipanic_write_gbuffer(emmc, log);
++ break;
++ default:
++ break;
++ }
++ /* Update emmc ipanic sections offsets */
++ emmc_ipanic_write_loginfo(emmc, log);
++ log++;
++ }
++ pr_info("Panic log data written done!\n");
++
++ ipanic_dumper.active = 0;
++
++out:
++#ifdef CONFIG_PREEMPT
++ sub_preempt_count(PREEMPT_ACTIVE);
++#endif
++ return NOTIFY_DONE;
++}
++
++static struct notifier_block panic_blk = {
++ .notifier_call = emmc_ipanic,
++ .priority = 100,
++};
++
++static int panic_dbg_get(void *data, u64 * val)
++{
++ emmc_ipanic(NULL, 0, NULL);
++ return 0;
++}
++
++static int panic_dbg_set(void *data, u64 val)
++{
++ BUG();
++ return -1;
++}
++
++DEFINE_SIMPLE_ATTRIBUTE(panic_dbg_fops, panic_dbg_get, panic_dbg_set, "%llu\n");
++
++static int match_dev_panic_part(struct device *dev, const void *data)
++{
++ struct hd_struct *part = dev_to_part(dev);
++ const char *name = (char *)data;
++
++ return part->info && !strcmp(name, part->info->volname);
++}
++
++static int emmc_panic_partition_notify(struct notifier_block *nb,
++ unsigned long action, void *data)
++{
++ struct device *dev = data;
++ struct emmc_ipanic_data *ctx = &drv_ctx;
++ struct mmc_emergency_info *emmc;
++ struct gendisk *disk;
++
++ if (!ctx) {
++ pr_err("%s:invalid panic handler\n", __func__);
++ return 0;
++ }
++
++ emmc = ctx->emmc;
++ if (!emmc) {
++ pr_err("%s:invalid emmc information\n", __func__);
++ return 0;
++ }
++
++ switch (action) {
++ case BUS_NOTIFY_ADD_DEVICE:
++ case BUS_NOTIFY_BOUND_DRIVER:
++ /* if emmc already found, exit the function */
++ if (emmc->bdev)
++ return 0;
++
++ emmc->part_dev = class_find_device(&block_class, NULL,
++ emmc->part_label,
++ &match_dev_panic_part);
++ if (emmc->part_dev) {
++ emmc->part = dev_to_part(emmc->part_dev);
++ if (!emmc->part) {
++ pr_err("unable to get partition\n");
++ goto put_dev;
++ }
++
++ disk = part_to_disk(emmc->part);
++ if (!disk) {
++ pr_err("unable to get disk\n");
++ goto put_dev;
++ }
++
++ /* get whole disk */
++ emmc->bdev = bdget_disk(disk, 0);
++ if (!emmc->bdev) {
++ pr_err("unable to get emmc block device\n");
++ goto put_dev;
++ }
++
++ emmc->start_block = emmc->part->start_sect;
++ emmc->block_count = emmc->part->nr_sects;
++
++ pr_info("panic partition found, label:%s, device:%s\n",
++ emmc->part_label, dev_name(emmc->part_dev));
++
++ /* notify to add the panic device */
++ emmc_panic_notify_add();
++
++ atomic_notifier_chain_register(&panic_notifier_list,
++ &panic_blk);
++
++ INIT_WORK(&proc_removal_work,
++ emmc_ipanic_remove_proc_work);
++ }
++ break;
++ case BUS_NOTIFY_DEL_DEVICE:
++ case BUS_NOTIFY_UNBIND_DRIVER:
++ if (match_dev_panic_part(dev, emmc->part_label)) {
++ pr_info("bus notify removed device '%s', cleaning.\n",
++ dev_name(dev));
++ flush_scheduled_work();
++ atomic_notifier_chain_unregister(&panic_notifier_list,
++ &panic_blk);
++ emmc_panic_notify_remove();
++ }
++ break;
++ case BUS_NOTIFY_BIND_DRIVER:
++ case BUS_NOTIFY_UNBOUND_DRIVER:
++ /* Nothing to do here, but we don't want
++ * these actions to generate error messages,
++ * so we need to catch them
++ */
++ break;
++ default:
++ pr_err("Unknown action (%lu) on %s\n", action, dev_name(dev));
++ return 0;
++ }
++ return 1;
++
++put_dev:
++ put_device(emmc->part_dev);
++ return 0;
++}
++
++static struct notifier_block panic_partition_notifier = {
++ .notifier_call = emmc_panic_partition_notify,
++};
++
++void emmc_ipanic_stream_emmc(void)
++{
++ if (func_stream_emmc)
++ (*func_stream_emmc) ();
++}
++
++EXPORT_SYMBOL(emmc_ipanic_stream_emmc);
++
++static struct dentry *emmc_ipanic_d;
++static struct dentry *emmc_ipanic_disable_d;
++
++static int __init emmc_ipanic_init(void)
++{
++ /* initialization of drv_ctx */
++ memset(&drv_ctx, 0, sizeof(drv_ctx));
++ drv_ctx.emmc = &emmc_info;
++
++ if (*part_label)
++ strcpy(emmc_info.part_label, part_label);
++
++ drv_ctx.ipanic_proc_entry_name = ipanic_proc_entry_name;
++ drv_ctx.bounce = (void *)__get_free_page(GFP_KERNEL);
++
++ bus_register_notifier(&pci_bus_type, &panic_partition_notifier);
++
++ emmc_ipanic_d = debugfs_create_file("emmc_ipanic", 0644, NULL, NULL,
++ &panic_dbg_fops);
++ emmc_ipanic_disable_d = debugfs_create_u32("disable_emmc_ipanic", 0644,
++ NULL, &disable_emmc_ipanic);
++
++ pr_info("init success\n");
++
++ return 0;
++}
++
++static void __exit emmc_ipanic_exit(void)
++{
++ debugfs_remove(emmc_ipanic_d);
++ debugfs_remove(emmc_ipanic_disable_d);
++ bus_unregister_notifier(&pci_bus_type, &panic_partition_notifier);
++ flush_scheduled_work();
++ atomic_notifier_chain_unregister(&panic_notifier_list, &panic_blk);
++ emmc_panic_notify_remove();
++}
++
++module_init(emmc_ipanic_init);
++module_exit(emmc_ipanic_exit);
+diff --git a/drivers/misc/emmc_ipanic.h b/drivers/misc/emmc_ipanic.h
+new file mode 100644
+index 0000000..541f613
+--- /dev/null
++++ b/drivers/misc/emmc_ipanic.h
+@@ -0,0 +1,96 @@
++/*
++ * drivers/misc/emmc_ipanic.h
++ *
++ * Copyright (C) 2011 Intel Corp
++ * Author: dongxing.zhang@intel.com
++ * Author: jun.zhang@intel.com
++ * Author: chuansheng.liu@intel.com
++ * 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; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ */
++
++#ifndef _LINUX_EMMC_IPANIC_H
++#define _LINUX_EMMC_IPANIC_H
++
++#include <linux/fs.h>
++#include <linux/proc_fs.h>
++#include <linux/blkdev.h>
++#include <linux/genhd.h>
++#include <linux/version.h>
++
++extern void log_buf_clear(void);
++
++#define SECTOR_SIZE_SHIFT (9)
++
++#define PROC_HEADER_INDEX 0
++#define PROC_CONSOLE_INDEX 1
++#define PROC_THREADS_INDEX 2
++#define PROC_GBUFFER_INDEX 3
++#define PROC_MAX_ENTRIES 4
++
++#define IPANIC_LOG_CONSOLE 0
++#define IPANIC_LOG_THREADS 1
++#define IPANIC_LOG_GBUFFER 2
++#define IPANIC_LOG_MAX 3
++#define IPANIC_LOG_HEADER IPANIC_LOG_MAX
++
++
++struct mmc_emergency_info {
++#define DISK_NAME_LENGTH 20
++ /* emmc panic partition label */
++ char part_label[PARTITION_META_INFO_VOLNAMELTH];
++
++ struct block_device *bdev;
++ struct device *part_dev;
++ struct hd_struct *part;
++
++ /*panic partition start block */
++ sector_t start_block;
++ /*panic partition block count */
++ sector_t block_count;
++
++ int (*init) (void);
++ int (*write) (char *, unsigned int);
++ int (*read) (char *, unsigned int);
++};
++
++struct panic_header {
++ u32 magic;
++#define PANIC_MAGIC 0xdeadf00d
++
++ u32 version;
++#define PHDR_VERSION 0x01
++ u32 log_size;
++
++ char panic[SECTOR_SIZE];
++};
++
++struct log_info {
++ u32 log_offset[IPANIC_LOG_MAX];
++ u32 log_length[IPANIC_LOG_MAX];
++
++ /* For logcat and generic buffer log status */
++ size_t log_head[IPANIC_LOG_MAX];
++ size_t log_woff[IPANIC_LOG_MAX];
++};
++
++struct emmc_ipanic_data {
++ struct mmc_emergency_info *emmc;
++ struct panic_header hdr;
++ struct log_info curr;
++ void *bounce;
++ struct proc_dir_entry *ipanic_proc_entry[PROC_MAX_ENTRIES];
++ unsigned char **ipanic_proc_entry_name;
++};
++
++#endif /* _LINUX_EMMC_IPANIC_H */
+diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c
+index f84ff0c..6ece8b6 100644
+--- a/drivers/misc/pti.c
++++ b/drivers/misc/pti.c
+@@ -21,6 +21,8 @@
+ * compact JTAG, standard.
+ */
+
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
+ #include <linux/init.h>
+ #include <linux/sched.h>
+ #include <linux/interrupt.h>
+@@ -36,6 +38,12 @@
+ #include <linux/slab.h>
+ #include <linux/uaccess.h>
+
++#include <asm/intel_scu_ipc.h>
++
++#ifdef CONFIG_INTEL_PTI_STM
++#include "stm.h"
++#endif
++
+ #define DRIVERNAME "pti"
+ #define PCINAME "pciPTI"
+ #define TTYNAME "ttyPTI"
+@@ -55,6 +63,55 @@
+ #define APERTURE_14 0x3800000 /* offset to first OS write addr */
+ #define APERTURE_LEN 0x400000 /* address length */
+
++#define SMIP_PTI_OFFSET 0x30C /* offset to PTI config in MIP header */
++#define SMIP_PTI_EN (1<<7) /* PTI enable bit in PTI configuration */
++
++#define PTI_PNW_PCI_ID 0x082B
++#define PTI_CLV_PCI_ID 0x0900
++#define PTI_TNG_PCI_ID 0x119F
++
++#define INTEL_PTI_PCI_DEVICE(dev, info) { \
++ .vendor = PCI_VENDOR_ID_INTEL, \
++ .device = dev, \
++ .subvendor = PCI_ANY_ID, \
++ .subdevice = PCI_ANY_ID, \
++ .driver_data = (unsigned long) info }
++
++struct pti_device_info {
++ u8 pci_bar;
++ u8 scu_secure_mode:1;
++ u8 has_d8_d16_support:1;
++};
++
++static const struct pti_device_info intel_pti_pnw_info = {
++ .pci_bar = 1,
++ .scu_secure_mode = 0,
++ .has_d8_d16_support = 0,
++};
++
++static const struct pti_device_info intel_pti_clv_info = {
++ .pci_bar = 1,
++ .scu_secure_mode = 1,
++ .has_d8_d16_support = 0,
++};
++
++static const struct pti_device_info intel_pti_tng_info = {
++ .pci_bar = 2,
++ .scu_secure_mode = 0,
++ .has_d8_d16_support = 1,
++};
++
++static DEFINE_PCI_DEVICE_TABLE(pci_ids) = {
++ INTEL_PTI_PCI_DEVICE(PTI_PNW_PCI_ID, &intel_pti_pnw_info),
++ INTEL_PTI_PCI_DEVICE(PTI_CLV_PCI_ID, &intel_pti_clv_info),
++ INTEL_PTI_PCI_DEVICE(PTI_TNG_PCI_ID, &intel_pti_tng_info),
++ {0}
++};
++
++#define GET_PCI_BAR(pti_dev) (pti_dev->pti_dev_info->pci_bar)
++#define HAS_SCU_SECURE_MODE(pti_dev) (pti_dev->pti_dev_info->scu_secure_mode)
++#define HAS_D8_D16_SUPPORT(pti_dev) (pti_dev->pti_dev_info->has_d8_d16_support)
++
+ struct pti_tty {
+ struct pti_masterchannel *mc;
+ };
+@@ -67,8 +124,16 @@ struct pti_dev {
+ u8 ia_app[MAX_APP_IDS];
+ u8 ia_os[MAX_OS_IDS];
+ u8 ia_modem[MAX_MODEM_IDS];
++ struct pti_device_info *pti_dev_info;
++#ifdef CONFIG_INTEL_PTI_STM
++ struct stm_dev stm;
++#endif
+ };
+
++static unsigned int stm_enabled;
++module_param(stm_enabled, uint, 0600);
++MODULE_PARM_DESC(stm_enabled, "set to 1 to enable stm");
++
+ /*
+ * This protects access to ia_app, ia_os, and ia_modem,
+ * which keeps track of channels allocated in
+@@ -76,11 +141,6 @@ struct pti_dev {
+ */
+ static DEFINE_MUTEX(alloclock);
+
+-static const struct pci_device_id pci_ids[] = {
+- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x82B)},
+- {0}
+-};
+-
+ static struct tty_driver *pti_tty_driver;
+ static struct pti_dev *drv_data;
+
+@@ -801,7 +861,6 @@ static int pti_pci_probe(struct pci_dev *pdev,
+ {
+ unsigned int a;
+ int retval = -EINVAL;
+- int pci_bar = 1;
+
+ dev_dbg(&pdev->dev, "%s %s(%d): PTI PCI ID %04x:%04x\n", __FILE__,
+ __func__, __LINE__, pdev->vendor, pdev->device);
+@@ -831,9 +890,13 @@ static int pti_pci_probe(struct pci_dev *pdev,
+ __func__, __LINE__);
+ goto err_disable_pci;
+ }
+- drv_data->pti_addr = pci_resource_start(pdev, pci_bar);
+
+- retval = pci_request_region(pdev, pci_bar, dev_name(&pdev->dev));
++ drv_data->pti_dev_info = (struct pti_device_info *)ent->driver_data;
++
++ drv_data->pti_addr = pci_resource_start(pdev, GET_PCI_BAR(drv_data));
++
++ retval = pci_request_region(pdev, GET_PCI_BAR(drv_data),
++ dev_name(&pdev->dev));
+ if (retval != 0) {
+ dev_err(&pdev->dev,
+ "%s(%d): pci_request_region() returned error %d\n",
+@@ -849,6 +912,14 @@ static int pti_pci_probe(struct pci_dev *pdev,
+ goto err_rel_reg;
+ }
+
++#ifdef CONFIG_INTEL_PTI_STM
++ /* Initialize STM resources */
++ if ((stm_enabled) && (stm_dev_init(pdev, &drv_data->stm) != 0)) {
++ retval = -ENOMEM;
++ goto err_rel_reg;
++ }
++#endif
++
+ pci_set_drvdata(pdev, drv_data);
+
+ for (a = 0; a < PTITTY_MINOR_NUM; a++) {
+@@ -863,7 +934,7 @@ static int pti_pci_probe(struct pci_dev *pdev,
+
+ return 0;
+ err_rel_reg:
+- pci_release_region(pdev, pci_bar);
++ pci_release_region(pdev, GET_PCI_BAR(drv_data));
+ err_free_dd:
+ kfree(drv_data);
+ err_disable_pci:
+@@ -891,10 +962,14 @@ static void pti_pci_remove(struct pci_dev *pdev)
+ tty_port_destroy(&drv_data->port[a]);
+ }
+
++#ifdef CONFIG_INTEL_PTI_STM
++ if (stm_enabled)
++ stm_dev_clean(pdev, &drv_data->stm);
++#endif
+ iounmap(drv_data->pti_ioaddr);
++ pci_release_region(pdev, GET_PCI_BAR(drv_data));
+ pci_set_drvdata(pdev, NULL);
+ kfree(drv_data);
+- pci_release_region(pdev, 1);
+ pci_disable_device(pdev);
+
+ misc_deregister(&pti_char_driver);
+diff --git a/drivers/misc/stm.c b/drivers/misc/stm.c
+new file mode 100644
+index 0000000..58b35ef
+--- /dev/null
++++ b/drivers/misc/stm.c
+@@ -0,0 +1,470 @@
++/*
++ * stm.c - MIPI STM Debug Unit driver
++ *
++ * Copyright (C) Intel 2013
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * The STM (Sytem Trace Macro) Unit driver configure trace output
++ * to the Intel Tangier PTI port and DWC3 USB xHCI controller
++ * out of the mobile device for analysis with a debugging tool
++ * (Lauterbach, Fido). This is part of a solution for the MIPI P1149.7,
++ * compact JTAG, standard and USB Debug-Class
++ *
++ * This header file will allow other parts of the OS to use the
++ * interface to write out it's contents for debugging a mobile system.
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/sdm.h>
++
++#include "stm.h"
++#include <asm/intel_soc_debug.h>
++#include "../usb/dwc3/core.h"
++
++/* STM Registers */
++#define STM_CTRL 0x0000
++#define STM_USB3DBGGTHR 0x0008
++#define STM_MASMSK 0x0010
++#define STM_CHMSK 0x0080
++#define STM_AGTBAR0 0x00C0
++#define STM_AGTBAR1 0x0140
++#define STM_AGTBAR2 0x01C0
++#define STM_AGTBAR3 0x0240
++#define STM_AGTBAR4 0x02C0
++#define STM_AGTBAR5 0x0340
++#define STM_AGTBAR6 0x03C0
++#define STM_AGTBAR7 0x0440
++#define STM_AGTBAR8 0x04C0
++#define STM_AGTBAR9 0x0540
++#define STM_AGTBAR10 0x05C0
++#define STM_AGTBAR11 0x0640
++
++/*
++ * STM registers
++ */
++#define STM_REG_BASE 0x0 /* registers base offset */
++#define STM_REG_LEN 0x20 /* address length */
++/*
++ * TRB buffers
++ */
++#define STM_TRB_BASE 0x400 /* TRB base offset */
++#define STM_TRB_LEN 0x100 /* address length */
++#define STM_TRB_NUM 16 /* number of TRBs */
++
++/*
++ * This protects R/W to stm registers
++ */
++static DEFINE_MUTEX(stmlock);
++
++static struct stm_dev *_dev_stm;
++
++static inline u32 stm_readl(void __iomem *base, u32 offset)
++{
++ return readl(base + offset);
++}
++
++static inline void stm_writel(void __iomem *base, u32 offset, u32 value)
++{
++ writel(value, base + offset);
++}
++
++/**
++ * stm_kernel_set_out()-
++ * Kernel API function used to
++ * set STM output configuration to PTI or USB.
++ *
++ * @bus_type:
++ * 0 = PTI 4-bits legacy end user
++ * 1 = PTI 4-bits NiDnT
++ * 2 = PTI 16-bits
++ * 3 = PTI 12-bits
++ * 4 = PTI 8-bits
++ * 15 = USB Debug-Class (DvC.Trace)
++ *
++ */
++int stm_kernel_set_out(int bus_type)
++{
++
++ struct stm_dev *drv_stm = _dev_stm;
++
++ /*
++ * since this function is exported, this is treated like an
++ * API function, thus, all parameters should
++ * be checked for validity.
++ */
++ if (drv_stm == NULL)
++ return 0;
++
++ mutex_lock(&stmlock);
++
++ drv_stm->stm_ctrl_hwreg.reg_word =
++ stm_readl(drv_stm->stm_ioaddr, (u32)STM_CTRL);
++
++ switch (bus_type) {
++ case STM_PTI_4BIT_LEGACY:
++ case STM_PTI_4BIT_NIDNT:
++ case STM_PTI_16BIT:
++ case STM_PTI_12BIT:
++ case STM_PTI_8BIT:
++ drv_stm->stm_ctrl_hwreg.pti_out_en = true;
++ drv_stm->stm_ctrl_hwreg.usb_debug_en = false;
++ drv_stm->stm_ctrl_hwreg.pti_out_mode_sel = bus_type;
++ stm_writel(drv_stm->stm_ioaddr, (u32)STM_CTRL,
++ drv_stm->stm_ctrl_hwreg.reg_word);
++ break;
++ case STM_USB:
++ drv_stm->stm_ctrl_hwreg.pti_out_en = false;
++ drv_stm->stm_ctrl_hwreg.usb_debug_en = true;
++ stm_writel(drv_stm->stm_ioaddr, (u32)STM_CTRL,
++ drv_stm->stm_ctrl_hwreg.reg_word);
++ break;
++ default:
++ /* N/A */
++ break;
++ }
++ mutex_unlock(&stmlock);
++
++ return 1;
++}
++EXPORT_SYMBOL_GPL(stm_kernel_set_out);
++
++/**
++ * stm_kernel_get_out()-
++ * Kernel API function used to get
++ * STM output cofiguration PTI or USB.
++ *
++ */
++int stm_kernel_get_out(void)
++{
++ struct stm_dev *drv_stm = _dev_stm;
++ int ret = -EOPNOTSUPP;
++
++ if (drv_stm == NULL)
++ return -EOPNOTSUPP;
++
++ mutex_lock(&stmlock);
++
++ drv_stm->stm_ctrl_hwreg.reg_word =
++ stm_readl(drv_stm->stm_ioaddr, (u32)STM_CTRL);
++
++ if (!drv_stm->stm_ctrl_hwreg.usb_debug_en) {
++ if (drv_stm->stm_ctrl_hwreg.pti_out_en)
++ ret = (int)drv_stm->stm_ctrl_hwreg.pti_out_mode_sel;
++ } else {
++ ret = (int)STM_USB;
++ }
++ mutex_unlock(&stmlock);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(stm_kernel_get_out);
++
++/**
++ * stm_set_out() - 'out' parameter set function from 'STM' module
++ *
++ * called when writing to 'out' parameter from 'STM' module in sysfs
++ */
++static int stm_set_out(const char *val, struct kernel_param *kp)
++{
++ int bus_type_value;
++ int ret = -EINVAL;
++
++ if (sscanf(val, "%2d", &bus_type_value) != 1)
++ return ret;
++
++ return stm_kernel_set_out(bus_type_value);
++}
++
++/**
++ * stm_get_out() - 'out' parameter get function from 'STM' module
++ *
++ * called when reading 'out' parameter from 'STM' module in sysfs
++ */
++static int stm_get_out(char *buffer, struct kernel_param *kp)
++{
++ int i;
++
++ i = stm_kernel_get_out();
++ if (i == -EOPNOTSUPP) {
++ buffer[0] = '\0';
++ return 0;
++ }
++
++ return sprintf(buffer, "%2d", i);
++}
++
++/**
++ * stm_init() - initialize stmsub3dbgthr register
++ *
++ * @return - 0 on Success
++ */
++static int stm_init(void)
++{
++ struct stm_dev *stm = _dev_stm;
++ struct stm_usb3_ctrl *usb3dbg;
++
++ if (!stm)
++ return -ENODEV;
++
++ usb3dbg = &stm->stm_usb3_hwreg;
++ usb3dbg->reg_word = stm_readl(stm->stm_ioaddr, (u32)STM_USB3DBGGTHR);
++
++ usb3dbg->reg_word = 0xFF;
++
++ stm_writel(stm->stm_ioaddr, (u32)STM_USB3DBGGTHR, usb3dbg->reg_word);
++
++ return 0;
++}
++
++/**
++ * stm_alloc_static_trb_pool() - set stm trb pool dma_addr and return
++ * trb_pool
++ *
++ * @dma_addr - trb pool dma physical address to set
++ * @return - trb pool address ioremaped pointer
++ */
++static void *stm_alloc_static_trb_pool(dma_addr_t *dma_addr)
++{
++ struct stm_dev *stm = _dev_stm;
++ if (!stm)
++ return NULL;
++
++ *dma_addr = stm->stm_trb_base;
++ return stm->trb_ioaddr;
++}
++
++static void ebc_io_free_static_trb_pool(void)
++{
++ /* Nothing to do, HW TRB */
++}
++
++static int stm_xfer_start(void)
++{
++ struct stm_dev *stm = _dev_stm;
++ struct stm_ctrl *stm_ctrl;
++
++ if (!stm)
++ return -ENODEV;
++
++ stm_ctrl = &stm->stm_ctrl_hwreg;
++ stm_ctrl->reg_word = stm_readl(stm->stm_ioaddr, (u32)STM_CTRL);
++
++ stm_ctrl->usb_debug_en = true;
++ stm_ctrl->pti_out_en = false;
++
++ stm_writel(stm->stm_ioaddr, (u32)STM_CTRL, stm_ctrl->reg_word);
++ pr_info("%s\n switch STM output to DvC.Trace ", __func__);
++
++ return 0;
++}
++
++static int stm_xfer_stop(void)
++{
++ struct stm_dev *stm = _dev_stm;
++ struct stm_ctrl *stm_ctrl;
++
++ if (!stm)
++ return -ENODEV;
++
++ stm_ctrl = &stm->stm_ctrl_hwreg;
++ stm_ctrl->reg_word = stm_readl(stm->stm_ioaddr, (u32)STM_CTRL);
++
++ stm_ctrl->usb_debug_en = false;
++ stm_ctrl->pti_out_en = true;
++
++ stm_writel(stm->stm_ioaddr, (u32)STM_CTRL, stm_ctrl->reg_word);
++ pr_info("%s\n switch STM to 4bits MIPI PTI (default)", __func__);
++
++ return 0;
++}
++
++static struct ebc_io stm_ebc_io_ops = {
++ .name = "stmbuf4kB",
++ .epname = "ep1in",
++ .epnum = 3,
++ .is_ondemand = 1,
++ .static_trb_pool_size = 4,
++ .init = stm_init,
++ .alloc_static_trb_pool = stm_alloc_static_trb_pool,
++ .free_static_trb_pool = ebc_io_free_static_trb_pool,
++ .xfer_start = stm_xfer_start,
++ .xfer_stop = stm_xfer_stop,
++};
++
++#define EXI_IN_TRB_POOL_OFFSET (4*16)
++static void *exi_inbound_alloc_static_trb_pool(dma_addr_t *dma_addr)
++{
++ struct stm_dev *stm = _dev_stm;
++ if (!stm)
++ return NULL;
++
++ *dma_addr = stm->stm_trb_base + EXI_IN_TRB_POOL_OFFSET;
++ return stm->trb_ioaddr + EXI_IN_TRB_POOL_OFFSET;
++}
++
++static struct ebc_io exi_in_ebc_io_ops = {
++ .name = "exi-inbound",
++ .epname = "ep8in",
++ .epnum = 17,
++ .is_ondemand = 0,
++ .static_trb_pool_size = 4,
++ .alloc_static_trb_pool = exi_inbound_alloc_static_trb_pool,
++ .free_static_trb_pool = ebc_io_free_static_trb_pool,
++};
++
++#define EXI_OUT_TRB_POOL_OFFSET (8*16)
++static void *exi_outbound_alloc_static_trb_pool(dma_addr_t *dma_addr)
++{
++ struct stm_dev *stm = _dev_stm;
++ if (!stm)
++ return NULL;
++
++ *dma_addr = stm->stm_trb_base + EXI_OUT_TRB_POOL_OFFSET;
++ return stm->trb_ioaddr + EXI_OUT_TRB_POOL_OFFSET;
++}
++
++static struct ebc_io exi_out_ebc_io_ops = {
++ .name = "exi-outbound",
++ .epname = "ep8out",
++ .epnum = 16,
++ .is_ondemand = 0,
++ .static_trb_pool_size = 2,
++ .alloc_static_trb_pool = exi_outbound_alloc_static_trb_pool,
++ .free_static_trb_pool = ebc_io_free_static_trb_pool,
++};
++
++int stm_is_enabled()
++{
++ return (_dev_stm != NULL);
++}
++EXPORT_SYMBOL_GPL(stm_is_enabled);
++
++/**
++ * stm_dev_init()- Used to setup STM resources on the pci bus.
++ *
++ * @pdev- pci_dev struct values for pti device.
++ * @stm- stm_dev struct managing stm resources
++ *
++ * Returns:
++ * 0 for success
++ * otherwise, error
++ */
++int stm_dev_init(struct pci_dev *pdev,
++ struct stm_dev *stm)
++{
++ int retval = 0;
++ int pci_bar = 0;
++
++ if (!cpu_has_debug_feature(DEBUG_FEATURE_PTI))
++ return -ENODEV;
++
++ dev_dbg(&pdev->dev, "%s %s(%d): STM PCI ID %04x:%04x\n", __FILE__,
++ __func__, __LINE__, pdev->vendor, pdev->device);
++
++ stm->stm_addr = pci_resource_start(pdev, pci_bar);
++
++ retval = pci_request_region(pdev, pci_bar, dev_name(&pdev->dev));
++ if (retval != 0) {
++ dev_err(&pdev->dev,
++ "%s(%d): pci_request_region() returned error %d\n",
++ __func__, __LINE__, retval);
++ return retval;
++ }
++ pr_info("stm add %x\n", stm->stm_addr);
++
++ stm->stm_reg_base = stm->stm_addr+STM_REG_BASE;
++ stm->stm_ioaddr = ioremap_nocache((u32)stm->stm_reg_base,
++ STM_REG_LEN);
++ if (!stm->stm_ioaddr) {
++ retval = -ENOMEM;
++ goto out_release_region;
++ }
++
++ stm->stm_trb_base = stm->stm_addr+STM_TRB_BASE;
++ stm->trb_ioaddr = ioremap_nocache((u32)stm->stm_trb_base,
++ STM_TRB_LEN);
++ if (!stm->trb_ioaddr) {
++ retval = -ENOMEM;
++ goto out_iounmap_stm_ioaddr;
++ }
++
++ stm->stm_ctrl_hwreg.reg_word = stm_readl(stm->stm_ioaddr,
++ (u32)STM_CTRL);
++ stm->stm_usb3_hwreg.reg_word = stm_readl(stm->stm_ioaddr,
++ (u32)STM_USB3DBGGTHR);
++
++ _dev_stm = stm;
++
++ dwc3_register_io_ebc(&stm_ebc_io_ops);
++ dwc3_register_io_ebc(&exi_in_ebc_io_ops);
++ dwc3_register_io_ebc(&exi_out_ebc_io_ops);
++
++ pr_info("successfully registered ebc io ops\n");
++
++ return retval;
++
++out_iounmap_stm_ioaddr:
++ pci_iounmap(pdev, stm->stm_ioaddr);
++
++out_release_region:
++ pci_release_region(pdev, pci_bar);
++
++ _dev_stm = NULL;
++ return retval;
++
++}
++EXPORT_SYMBOL_GPL(stm_dev_init);
++
++/**
++ * stm_dev_clean()- Driver exit method to free STM resources from
++ * PCI bus.
++ * @pdev: variable containing pci info of STM.
++ * @dev_stm: stm_dev resources to clean.
++ */
++void stm_dev_clean(struct pci_dev *pdev,
++ struct stm_dev *dev_stm)
++{
++ int pci_bar = 0;
++
++ /* If STM driver was not initialized properly,
++ * there is nothing to do.
++ */
++ if (_dev_stm == NULL)
++ return;
++
++ dwc3_unregister_io_ebc(&stm_ebc_io_ops);
++ dwc3_unregister_io_ebc(&exi_in_ebc_io_ops);
++ dwc3_unregister_io_ebc(&exi_out_ebc_io_ops);
++
++ if (dev_stm != NULL) {
++ pci_iounmap(pdev, dev_stm->stm_ioaddr);
++ pci_iounmap(pdev, dev_stm->trb_ioaddr);
++ }
++
++ pci_release_region(pdev, pci_bar);
++
++ _dev_stm = NULL;
++}
++EXPORT_SYMBOL_GPL(stm_dev_clean);
++
++module_param_call(stm_out, stm_set_out, stm_get_out, NULL, 0644);
++MODULE_PARM_DESC(stm_out, "configure System Trace Macro output");
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Florent Pirou");
++MODULE_DESCRIPTION("STM Driver");
+diff --git a/drivers/misc/stm.h b/drivers/misc/stm.h
+new file mode 100644
+index 0000000..1fb2d2e
+--- /dev/null
++++ b/drivers/misc/stm.h
+@@ -0,0 +1,114 @@
++/*
++ * stm.h
++ *
++ * Copyright (C) Intel 2011
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * The STM (Sytem Trace Macro) Unit driver configure trace output
++ * to the Intel Tangier PTI port and DWC3 USB xHCI controller
++ * out of the mobile device for analysis with a debugging tool
++ * (Lauterbach, Fido). This is part of a solution for the MIPI P1149.7,
++ * compact JTAG, standard and USB Debug-Class
++ *
++ * This header file will allow other parts of the OS to use the
++ * interface to write out it's contents for debugging a mobile system.
++ */
++
++#ifndef _STM_H
++#define _STM_H
++
++#include <linux/pci.h>
++
++/* STM_CTRL register bitmap */
++/**
++ * struct stm_ctrl - STM control block
++ * @usb_debug_en : STM needs to redirece the trace packet to the USB3
++ * @pti_io_idle_threshold : threshold for disabling the IO clock.
++ * @pkt_transfer_size : asserts the *buff_avail signal after it has
++ * 1 or 2 KB of data in buffer
++ * @dis_dcu7_use : disables the useage of DCU7 instead of PTI_Disable
++ * @en_sw_ms : enables software master usage
++ * @mst_id_en : enables the PTI unit to suppress sending the Master Command
++ * @d64_cmd_en : PTI unit to use the D64 commands
++ * @pti_out_mode_sel
++ * 0 = PTI 4-bits legacy end user
++ * 1 = PTI 4-bits NiDnT
++ * 2 = PTI 16-bits
++ * 3 = PTI 12-bits
++ * 4 = PTI 8-bits
++ * @pti_out_en : PTI output enable muxselects that propagate
++ * to the FLIS to be enabled
++ * @lossy_mode_enable : Output Agent will continue to accept writes,
++ * even if the queuese are full. The data will be dropped and the
++ * dropped packet indicator will be incremented
++ * @time_stamp_enable : Enable time stamping the final packet in trace record.
++ */
++struct stm_ctrl {
++ union {
++ struct {
++ u32 time_stamp_enable:1;
++ u32 lossy_mode_enable:1;
++ u32 pti_out_en:1;
++ u32 reserved:1;
++ u32 pti_out_mode_sel:4;
++ u32 d64_cmd_en:1;
++ u32 mst_id_en:1;
++ u32 en_sw_ms:1;
++ u32 dis_dcu7_use:1;
++ u32 pkt_transfer_size:1;
++ u32 pti_io_idle_threshold:5;
++ u32 usb_debug_en:1;
++ u32 reserved31_19:13;
++ };
++ u32 reg_word;
++ };
++} __packed;
++
++/**
++ * struct stm_usb3_ctrl - STM buffer USB3 hardware EBC
++ * @region_closure_threshold : This is the threshold for closing
++ * the 1KB region in the debug trace buffer. STM will wait for the
++ * configured time as specified in this field and then closes the region.
++ * The unit of this field is in 64 us. Eg when this field value is set
++ * to 0xffff, then it indicates 2 ms
++ * @empty_packets_threshold : When STM does not have data to send,
++ * it can send empty packets to keep the USB3 alive. This is useful
++ * in case of ISOC traffic, because in this mode the wake up latency
++ * is high. STM will send the configured number of empty packets as
++ * specified in this field.
++ */
++struct stm_usb3_ctrl {
++ union {
++ struct {
++ u32 region_closure_threshold:15;
++ u32 empty_packets_threshold:6;
++ u32 reserved31_21:11;
++ };
++ u32 reg_word;
++ };
++} __packed;
++
++struct stm_dev {
++ unsigned long stm_addr;
++ unsigned long stm_reg_base;
++ unsigned long stm_trb_base;
++ void __iomem *stm_ioaddr;
++ void __iomem *trb_ioaddr;
++ struct stm_ctrl stm_ctrl_hwreg;
++ struct stm_usb3_ctrl stm_usb3_hwreg;
++};
++
++int stm_dev_init(struct pci_dev *pdev, struct stm_dev *dev_stm);
++void stm_dev_clean(struct pci_dev *pdev, struct stm_dev *dev_stm);
++
++#endif /* _STM_H */
+diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
+index dd27b07..72bab34 100644
+--- a/drivers/mmc/card/block.c
++++ b/drivers/mmc/card/block.c
+@@ -161,6 +161,12 @@ static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
+ return md;
+ }
+
++int mmc_access_rpmb(struct mmc_queue *mq)
++{
++ struct mmc_blk_data *md = mq->data;
++ return md && md->part_type == EXT_CSD_PART_CONFIG_ACC_RPMB;
++}
++
+ static inline int mmc_get_devidx(struct gendisk *disk)
+ {
+ int devmaj = MAJOR(disk_devt(disk));
+diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
+index 9447a0e..2c84ec5 100644
+--- a/drivers/mmc/card/queue.c
++++ b/drivers/mmc/card/queue.c
+@@ -18,6 +18,7 @@
+
+ #include <linux/mmc/card.h>
+ #include <linux/mmc/host.h>
++#include <linux/mmc/mmc.h>
+ #include "queue.h"
+
+ #define MMC_QUEUE_BOUNCESZ 65536
+@@ -37,7 +38,7 @@ static int mmc_prep_request(struct request_queue *q, struct request *req)
+ return BLKPREP_KILL;
+ }
+
+- if (mq && mmc_card_removed(mq->card))
++ if (mq && mmc_card_removed(mq->card) || mmc_access_rpmb(mq))
+ return BLKPREP_KILL;
+
+ req->cmd_flags |= REQ_DONTPREP;
+diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
+index 5752d50..23460e6 100644
+--- a/drivers/mmc/card/queue.h
++++ b/drivers/mmc/card/queue.h
+@@ -73,4 +73,5 @@ extern void mmc_queue_bounce_post(struct mmc_queue_req *);
+ extern int mmc_packed_init(struct mmc_queue *, struct mmc_card *);
+ extern void mmc_packed_clean(struct mmc_queue *);
+
++int mmc_access_rpmb(struct mmc_queue *mq);
+ #endif
+diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile
+index 38ed210..d55cc5d 100644
+--- a/drivers/mmc/core/Makefile
++++ b/drivers/mmc/core/Makefile
+@@ -7,6 +7,6 @@ mmc_core-y := core.o bus.o host.o \
+ mmc.o mmc_ops.o sd.o sd_ops.o \
+ sdio.o sdio_ops.o sdio_bus.o \
+ sdio_cis.o sdio_io.o sdio_irq.o \
+- quirks.o slot-gpio.o
++ quirks.o slot-gpio.o mmc_panic_ops.o
+
+ mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o
+diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
+index e219c97..73c2bc5 100644
+--- a/drivers/mmc/core/bus.c
++++ b/drivers/mmc/core/bus.c
+@@ -309,11 +309,12 @@ int mmc_add_card(struct mmc_card *card)
+ mmc_card_ddr_mode(card) ? "DDR " : "",
+ type);
+ } else {
+- pr_info("%s: new %s%s%s%s%s card at address %04x\n",
++ pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
+ mmc_hostname(card->host),
+ mmc_card_uhs(card) ? "ultra high speed " :
+ (mmc_card_highspeed(card) ? "high speed " : ""),
+ (mmc_card_hs200(card) ? "HS200 " : ""),
++ (mmc_card_hs400(card) ? "HS400 " : ""),
+ mmc_card_ddr_mode(card) ? "DDR " : "",
+ uhs_bus_speed_mode, type, card->rca);
+ }
+diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
+index c40396f..2f2c572 100644
+--- a/drivers/mmc/core/core.c
++++ b/drivers/mmc/core/core.c
+@@ -1405,7 +1405,10 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
+ mmc_set_ios(host);
+
+ /* Wait for at least 1 ms according to spec */
+- mmc_delay(1);
++ if (host->ops->busy_wait)
++ host->ops->busy_wait(host, 1000);
++ else
++ mmc_delay(1);
+
+ /*
+ * Failure to switch is indicated by the card holding
+@@ -1468,6 +1471,9 @@ static void mmc_power_up(struct mmc_host *host)
+
+ mmc_host_clk_hold(host);
+
++ if (host->ops->set_dev_power)
++ host->ops->set_dev_power(host, true);
++
+ /* If ocr is set, we use it */
+ if (host->ocr)
+ bit = ffs(host->ocr) - 1;
+@@ -1492,7 +1498,7 @@ static void mmc_power_up(struct mmc_host *host)
+ * This delay should be sufficient to allow the power supply
+ * to reach the minimum voltage.
+ */
+- mmc_delay(10);
++ usleep_range(10000, 11000);
+
+ host->ios.clock = host->f_init;
+
+@@ -1503,7 +1509,7 @@ static void mmc_power_up(struct mmc_host *host)
+ * This delay must be at least 74 clock sizes, or 1 ms, or the
+ * time required to reach a stable voltage.
+ */
+- mmc_delay(10);
++ usleep_range(5000, 6000);
+
+ mmc_host_clk_release(host);
+ }
+@@ -1534,6 +1540,9 @@ void mmc_power_off(struct mmc_host *host)
+ host->ios.timing = MMC_TIMING_LEGACY;
+ mmc_set_ios(host);
+
++ if (host->ops->set_dev_power)
++ host->ops->set_dev_power(host, false);
++
+ /*
+ * Some configurations, such as the 802.11 SDIO card in the OLPC
+ * XO-1.5, require a short delay after poweroff before the card
+@@ -1690,7 +1699,7 @@ void mmc_init_erase(struct mmc_card *card)
+ card->erase_shift = ffs(card->ssr.au) - 1;
+ } else if (card->ext_csd.hc_erase_size) {
+ card->pref_erase = card->ext_csd.hc_erase_size;
+- } else {
++ } else if (card->erase_size) {
+ sz = (card->csd.capacity << (card->csd.read_blkbits - 9)) >> 11;
+ if (sz < 128)
+ card->pref_erase = 512 * 1024 / 512;
+@@ -1707,7 +1716,8 @@ void mmc_init_erase(struct mmc_card *card)
+ if (sz)
+ card->pref_erase += card->erase_size - sz;
+ }
+- }
++ } else
++ card->pref_erase = 0;
+ }
+
+ static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
+@@ -2408,7 +2418,8 @@ void mmc_rescan(struct work_struct *work)
+ mmc_release_host(host);
+
+ out:
+- if (host->caps & MMC_CAP_NEEDS_POLL)
++ mmc_emergency_setup(host);
++ if (host->caps & MMC_CAP_NEEDS_POLL)
+ mmc_schedule_delayed_work(&host->detect, HZ);
+ }
+
+@@ -2421,6 +2432,8 @@ void mmc_start_host(struct mmc_host *host)
+ else
+ mmc_power_up(host);
+ mmc_detect_change(host, 0);
++ if (host->caps2 & MMC_CAP2_INIT_CARD_SYNC)
++ flush_work_sync(&host->detect.work);
+ }
+
+ void mmc_stop_host(struct mmc_host *host)
+diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
+index 35c2f85..a0cb347 100644
+--- a/drivers/mmc/core/debugfs.c
++++ b/drivers/mmc/core/debugfs.c
+@@ -138,6 +138,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
+ case MMC_TIMING_MMC_HS200:
+ str = "mmc high-speed SDR200";
+ break;
++ case MMC_TIMING_MMC_HS400:
++ str = "mmc high-speed DDR200";
++ break;
+ default:
+ str = "invalid";
+ break;
+diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
+index 0cbd1ef..89d6082 100644
+--- a/drivers/mmc/core/mmc.c
++++ b/drivers/mmc/core/mmc.c
+@@ -239,7 +239,8 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
+ static void mmc_select_card_type(struct mmc_card *card)
+ {
+ struct mmc_host *host = card->host;
+- u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
++ u8 card_type = card->ext_csd.raw_card_type &
++ EXT_CSD_CARD_TYPE_MASK_FULL;
+ u32 caps = host->caps, caps2 = host->caps2;
+ unsigned int hs_max_dtr = 0;
+
+@@ -262,6 +263,12 @@ static void mmc_select_card_type(struct mmc_card *card)
+ card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
+ hs_max_dtr = MMC_HS200_MAX_DTR;
+
++ if ((caps2 & MMC_CAP2_HS400_1_8V_DDR &&
++ card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) ||
++ (caps2 & MMC_CAP2_HS400_1_2V_DDR &&
++ card_type & EXT_CSD_CARD_TYPE_HS400_1_2V))
++ hs_max_dtr = MMC_HS400_MAX_DTR;
++
+ card->ext_csd.hs_max_dtr = hs_max_dtr;
+ card->ext_csd.card_type = card_type;
+ }
+@@ -707,8 +714,12 @@ static int mmc_select_powerclass(struct mmc_card *card,
+ index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
+ EXT_CSD_PWR_CL_52_195 :
+ EXT_CSD_PWR_CL_DDR_52_195;
+- else if (host->ios.clock <= 200000000)
+- index = EXT_CSD_PWR_CL_200_195;
++ else if (host->ios.clock <= 200000000) {
++ if (mmc_card_hs400(card))
++ index = EXT_CSD_PWR_CL_200_DDR_195;
++ else
++ index = EXT_CSD_PWR_CL_200_195;
++ }
+ break;
+ case MMC_VDD_27_28:
+ case MMC_VDD_28_29:
+@@ -755,6 +766,81 @@ static int mmc_select_powerclass(struct mmc_card *card,
+ }
+
+ /*
++ * Support HS400:
++ * This function should be called after HS200 tuning.
++ */
++static int mmc_select_hs400_start(struct mmc_card *card)
++{
++ int err = -EINVAL;
++ struct mmc_host *host;
++ static unsigned ext_csd_bit = EXT_CSD_DDR_BUS_WIDTH_8;
++ static unsigned bus_width = MMC_BUS_WIDTH_8;
++
++ BUG_ON(!card);
++
++ host = card->host;
++ /* HS400 mode only supports 8bit bus.*/
++ if (!(host->caps & MMC_CAP_8_BIT_DATA)) {
++ pr_err("HS400: MMC host does not support 8bit bus, error!\n");
++ goto err;
++ }
++
++ /* Must set HS_TIMING to 1 after tuning completion. */
++ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
++ EXT_CSD_HS_TIMING, 1, 0);
++ if (!err) {
++ /* Set timing to DDR50 first */
++ mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
++ /* Then, set clock to 50MHz */
++ mmc_set_clock(host, MMC_HIGH_DDR_MAX_DTR);
++ } else {
++ goto err;
++ }
++
++ /*
++ * Host is capable of 8bit transfer, switch
++ * the device to work in 8bit transfer mode.
++ * On success set 8bit bus width on the host.
++ */
++ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
++ EXT_CSD_BUS_WIDTH,
++ ext_csd_bit,
++ card->ext_csd.generic_cmd6_time);
++ if (err)
++ goto err;
++
++ /* Bus test */
++ mmc_set_bus_width(card->host, bus_width);
++ if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
++ err = mmc_compare_ext_csds(card, bus_width);
++ else
++ err = mmc_bus_test(card, bus_width);
++ if (err)
++ goto err;
++
++err:
++ return err;
++}
++
++static int mmc_select_hs400_end(struct mmc_card *card, unsigned int max_dtr)
++{
++ int err = -EINVAL;
++
++ /* Switch timing to HS400 now. */
++ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
++ EXT_CSD_HS_TIMING, 3, 0);
++ if (!err) {
++ mmc_set_timing(card->host, MMC_TIMING_MMC_HS400);
++ /*
++ * After enablig HS400 mode, we should restore
++ * frequency to 200MHz.
++ */
++ mmc_set_clock(card->host, max_dtr);
++ }
++ return err;
++}
++
++/*
+ * Selects the desired buswidth and switch to the HS200 mode
+ * if bus width set without error
+ */
+@@ -775,12 +861,16 @@ static int mmc_select_hs200(struct mmc_card *card)
+
+ host = card->host;
+
+- if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
+- host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
++ if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
++ host->caps2 & MMC_CAP2_HS200_1_2V_SDR) ||
++ (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_HS400_1_2V &&
++ host->caps2 & MMC_CAP2_HS400_1_2V_DDR))
+ err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
+
+- if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
+- host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
++ if (err && ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
++ host->caps2 & MMC_CAP2_HS200_1_8V_SDR) ||
++ (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_HS400_1_8V &&
++ host->caps2 & MMC_CAP2_HS400_1_8V_DDR)))
+ err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
+
+ /* If fails try again during next card power cycle */
+@@ -1038,8 +1128,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
+ */
+ if (card->ext_csd.hs_max_dtr != 0) {
+ err = 0;
++ /* Support HS400: set to HS200 before tuning complete. */
+ if (card->ext_csd.hs_max_dtr > 52000000 &&
+- host->caps2 & MMC_CAP2_HS200)
++ (host->caps2 & MMC_CAP2_HS200 ||
++ host->caps2 & MMC_CAP2_HS400))
+ err = mmc_select_hs200(card);
+ else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+@@ -1055,6 +1147,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
+ err = 0;
+ } else {
+ if (card->ext_csd.hs_max_dtr > 52000000 &&
++ host->caps2 & MMC_CAP2_HS400 &&
++ (card->ext_csd.card_type &
++ EXT_CSD_CARD_TYPE_HS400_1_8V ||
++ card->ext_csd.card_type &
++ EXT_CSD_CARD_TYPE_HS400_1_2V)) {
++ mmc_card_set_hs400(card);
++ mmc_set_timing(card->host,
++ MMC_TIMING_MMC_HS200);
++ } else if (card->ext_csd.hs_max_dtr > 52000000 &&
+ host->caps2 & MMC_CAP2_HS200) {
+ mmc_card_set_hs200(card);
+ mmc_set_timing(card->host,
+@@ -1071,7 +1172,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
+ */
+ max_dtr = (unsigned int)-1;
+
+- if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
++ if (mmc_card_highspeed(card) ||
++ mmc_card_hs200(card) ||
++ mmc_card_hs400(card)) {
+ if (max_dtr > card->ext_csd.hs_max_dtr)
+ max_dtr = card->ext_csd.hs_max_dtr;
+ if (mmc_card_highspeed(card) && (max_dtr > 52000000))
+@@ -1099,9 +1202,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
+ }
+
+ /*
+- * Indicate HS200 SDR mode (if supported).
++ * Indicate HS200 SDR mode or HS400 DDR mode (if supported).
+ */
+- if (mmc_card_hs200(card)) {
++ if (mmc_card_hs200(card) || mmc_card_hs400(card)) {
+ u32 ext_csd_bits;
+ u32 bus_width = card->host->ios.bus_width;
+
+@@ -1116,7 +1219,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
+ * 3. set the clock to > 52Mhz <=200MHz and
+ * 4. execute tuning for HS200
+ */
+- if ((host->caps2 & MMC_CAP2_HS200) &&
++ /* Support HS400: tuning under HS200 mode. */
++ if ((host->caps2 & MMC_CAP2_HS200 ||
++ host->caps2 & MMC_CAP2_HS400) &&
+ card->host->ops->execute_tuning) {
+ mmc_host_clk_hold(card->host);
+ err = card->host->ops->execute_tuning(card->host,
+@@ -1129,19 +1234,45 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
+ goto err;
+ }
+
+- ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
++ /* Support HS400 */
++ if (mmc_card_hs400(card)) {
++ /*
++ * Per spec 5.0, follow below sequence to enable HS400:
++ * 1. Set HS_TIMING to 1 after HS200 tuning.
++ * 2. Set frequency below 52MHz.
++ * 3. Set bus width to DDR 8bit.
++ * 4. Set HS_TIMING to 3 as HS400.
++ */
++ err = mmc_select_hs400_start(card);
++ if (err) {
++ pr_warn("%s: hs400_start err=0x%x.\n",
++ mmc_hostname(card->host), err);
++ goto free_card;
++ }
++ ext_csd_bits = EXT_CSD_DDR_BUS_WIDTH_8;
++ } else {
++ ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+ EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
++ }
+ err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
+ if (err)
+- pr_warning("%s: power class selection to bus width %d"
++ pr_warn("%s: power class selection to bus width %d"
+ " failed\n", mmc_hostname(card->host),
+ 1 << bus_width);
++ if (mmc_card_hs400(card)) {
++ err = mmc_select_hs400_end(card, max_dtr);
++ if (err) {
++ pr_warn("%s: hs400_end err=0x%x.\n",
++ mmc_hostname(card->host), err);
++ goto free_card;
++ }
++ }
+ }
+
+ /*
+ * Activate wide bus and DDR (if supported).
+ */
+- if (!mmc_card_hs200(card) &&
++ if ((!mmc_card_hs200(card) && !mmc_card_hs400(card)) &&
+ (card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
+ (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
+ static unsigned ext_csd_bits[][2] = {
+diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
+index 49f04bc..a3d0615 100644
+--- a/drivers/mmc/core/mmc_ops.c
++++ b/drivers/mmc/core/mmc_ops.c
+@@ -141,7 +141,7 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+ cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
+
+- for (i = 100; i; i--) {
++ for (i = 200; i; i--) {
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err)
+ break;
+@@ -161,7 +161,7 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+
+ err = -ETIMEDOUT;
+
+- mmc_delay(10);
++ usleep_range(5000, 5500);
+ }
+
+ if (rocr && !mmc_host_is_spi(host))
+diff --git a/drivers/mmc/core/mmc_panic_ops.c b/drivers/mmc/core/mmc_panic_ops.c
+new file mode 100644
+index 0000000..2ed0204
+--- /dev/null
++++ b/drivers/mmc/core/mmc_panic_ops.c
+@@ -0,0 +1,837 @@
++/*
++ * linux/drivers/mmc/core/mmc_panic_ops.c
++ *
++ * Copyright (C) 2011 Intel Corp
++ * Author: dongxing.zhang@intel.com
++ * Author: jun.zhang@intel.com
++ * Author: chuansheng.liu@intel.com
++ * Author: chuanxiao.dong@intel.com
++ * 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; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ */
++#include <linux/module.h>
++#include <linux/device.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/slab.h>
++#include <linux/dma-mapping.h>
++
++#include <linux/mmc/host.h>
++#include <linux/mmc/card.h>
++#include <linux/mmc/mmc.h>
++#include <linux/mmc/sd.h>
++
++#include "core.h"
++#include "bus.h"
++#include "host.h"
++
++#include "mmc_ops.h"
++
++
++static struct mmc_panic_host *panic_host;
++
++static int mmc_emergency_prepare(void)
++{
++ struct mmc_host *mmc = panic_host->mmc;
++
++ if (mmc == NULL) {
++ pr_err("%s: panic host was not setup\n", __func__);
++ return -ENODEV;
++ }
++
++ /*
++ * once panic happened, we monopolize the host controller.
++ * so claim host without relase any more.
++ */
++ mmc->claimed = 1;
++ mmc->claimer = current;
++ mmc->claim_cnt += 1;
++#ifdef CONFIG_MMC_CLKGATE
++ /*
++ * disable the clock gating
++ */
++ mmc->clk_gated = false;
++ mmc->clk_requests++;
++ mmc->ios.clock = mmc->clk_old;
++#endif
++ return 0;
++}
++
++static void mmc_emergency_ready(void)
++{
++ panic_host->panic_ready = 1;
++}
++
++/*
++ * Return the card size in sectors.
++ *
++ * return value:
++ * the sector number
++ */
++static unsigned int mmc_get_capacity(struct mmc_card *card)
++{
++ if (!mmc_card_sd(card) && mmc_card_blockaddr(card))
++ return card->ext_csd.sectors;
++ else
++ return card->csd.capacity << (card->csd.read_blkbits - 9);
++}
++
++static void mmc_emergency_send_req(struct mmc_request *mrq)
++{
++ struct mmc_panic_host *host = panic_host;
++
++ mrq->cmd->error = 0;
++ mrq->cmd->mrq = mrq;
++
++ if (mrq->data) {
++ BUG_ON(mrq->data->blksz > host->max_blk_size);
++ BUG_ON(mrq->data->blocks > host->max_blk_count);
++ BUG_ON(mrq->data->blocks * mrq->data->blksz >
++ host->max_req_size);
++
++ mrq->cmd->data = mrq->data;
++ mrq->data->error = 0;
++ mrq->data->mrq = mrq;
++ if (mrq->stop) {
++ mrq->data->stop = mrq->stop;
++ mrq->stop->error = 0;
++ mrq->stop->mrq = mrq;
++ }
++ }
++
++ /*
++ * Send the request to host
++ *
++ * if request handling is successful, return.
++ * If request handling is failed and has rety, resend request.
++ * During retry, if request handling is still failed, core layer
++ * will keep on retry untill cmd->retries is 0.
++ *
++ * So in this way, makes retry blind to host driver. Totally
++ * controlled by core driver
++ */
++ host->panic_ops->request(host, mrq);
++
++ while ((mrq->cmd->error || (mrq->data && (mrq->data->error ||
++ (mrq->data->stop && mrq->data->stop->error)))) &&
++ mrq->cmd->retries > 0) {
++ /* clear errors */
++ mrq->cmd->error = 0;
++ if (mrq->data) {
++ mrq->data->error = 0;
++ if (mrq->stop)
++ mrq->stop->error = 0;
++ }
++ host->panic_ops->request(host, mrq);
++ mrq->cmd->retries--;
++ }
++}
++
++static int mmc_emergency_send_cmd(struct mmc_command *cmd, int retries)
++{
++ struct mmc_request mrq;
++
++ memset(&mrq, 0, sizeof(struct mmc_request));
++
++ memset(cmd->resp, 0, sizeof(cmd->resp));
++ cmd->retries = retries;
++
++ mrq.cmd = cmd;
++ cmd->data = NULL;
++
++ mmc_emergency_send_req(&mrq);
++
++ return cmd->error;
++}
++
++static int __mmc_emergency_write(unsigned int blk_id)
++{
++ struct mmc_request mrq;
++ struct mmc_command cmd;
++ struct mmc_data data;
++
++ memset(&mrq, 0, sizeof(struct mmc_request));
++ memset(&cmd, 0, sizeof(struct mmc_command));
++ memset(&data, 0, sizeof(struct mmc_data));
++
++ mrq.cmd = &cmd;
++ mrq.data = &data;
++ cmd.opcode = MMC_WRITE_BLOCK;
++ cmd.arg = blk_id;
++ if (!panic_host->blkaddr)
++ cmd.arg <<= 9;
++ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
++ /*
++ * Fix these values;
++ */
++ data.blksz = 512;
++ data.blocks = 1;
++ data.dmabuf = panic_host->dmabuf;
++
++ mmc_emergency_send_req(&mrq);
++
++ return cmd.error;
++}
++
++
++static int mmc_emergency_go_idle(struct mmc_panic_host *host)
++{
++ int err;
++ struct mmc_command cmd;
++
++ /*
++ * Non-SPI hosts need to prevent chipselect going active during
++ * GO_IDLE; that would put chips into SPI mode. Remind them of
++ * that in case of hardware that won't pull up DAT3/nCS otherwise.
++ *
++ * SPI hosts ignore ios.chip_select; it's managed according to
++ * rules that must accomodate non-MMC slaves which this layer
++ * won't even know about.
++ */
++ if (!mmc_host_is_spi(host)) {
++ host->ios.chip_select = MMC_CS_HIGH;
++ host->panic_ops->set_ios(host);
++ mdelay(1);
++ }
++
++ memset(&cmd, 0, sizeof(struct mmc_command));
++
++ cmd.opcode = MMC_GO_IDLE_STATE;
++ cmd.arg = 0;
++ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
++
++ err = mmc_emergency_send_cmd(&cmd, 0);
++
++ mdelay(1);
++
++ if (!mmc_host_is_spi(host)) {
++ host->ios.chip_select = MMC_CS_DONTCARE;
++ host->panic_ops->set_ios(host);
++ mdelay(1);
++ }
++
++ return err;
++}
++static int mmc_emergency_send_op_cond(struct mmc_panic_host *host,
++ u32 ocr, u32 *rocr)
++{
++ struct mmc_command cmd;
++ int i, err = 0;
++
++ memset(&cmd, 0, sizeof(struct mmc_command));
++
++ cmd.opcode = MMC_SEND_OP_COND;
++ cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
++ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
++
++ for (i = 100; i; i--) {
++ err = mmc_emergency_send_cmd(&cmd, 0);
++ if (err)
++ break;
++
++ /* if we're just probing, do a single pass */
++ if (ocr == 0)
++ break;
++
++ /* otherwise wait until reset completes */
++ if (mmc_host_is_spi(host)) {
++ if (!(cmd.resp[0] & R1_SPI_IDLE))
++ break;
++ } else {
++ if (cmd.resp[0] & MMC_CARD_BUSY)
++ break;
++ }
++
++ err = -ETIMEDOUT;
++
++ /*
++ * If command 1 is failed, wait 10ms and then
++ * have a retry. Card may need time to prepare
++ * for the next command 1
++ */
++ mdelay(10);
++ }
++
++ if (rocr && !mmc_host_is_spi(host))
++ *rocr = cmd.resp[0];
++
++ return err;
++}
++
++static int mmc_emergency_all_send_cid(u32 *cid)
++{
++ int err;
++ struct mmc_command cmd;
++
++ memset(&cmd, 0, sizeof(struct mmc_command));
++
++ cmd.opcode = MMC_ALL_SEND_CID;
++ cmd.arg = 0;
++ cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
++
++ err = mmc_emergency_send_cmd(&cmd, MMC_CMD_RETRIES);
++ if (err)
++ return err;
++
++ memcpy(cid, cmd.resp, sizeof(u32) * 4);
++
++ return 0;
++}
++
++static int mmc_emergency_set_relative_addr(struct mmc_card *card)
++{
++ int err;
++ struct mmc_command cmd;
++
++ memset(&cmd, 0, sizeof(struct mmc_command));
++
++ cmd.opcode = MMC_SET_RELATIVE_ADDR;
++ cmd.arg = card->rca << 16;
++ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
++
++ err = mmc_emergency_send_cmd(&cmd, MMC_CMD_RETRIES);
++ if (err)
++ return err;
++
++ return 0;
++}
++
++static int mmc_emergency_select_card(struct mmc_card *card)
++{
++ int err;
++ struct mmc_command cmd;
++
++ memset(&cmd, 0, sizeof(struct mmc_command));
++
++ cmd.opcode = MMC_SELECT_CARD;
++
++ if (card) {
++ cmd.arg = card->rca << 16;
++ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
++ } else {
++ cmd.arg = 0;
++ cmd.flags = MMC_RSP_NONE | MMC_CMD_AC;
++ }
++
++ err = mmc_emergency_send_cmd(&cmd, MMC_CMD_RETRIES);
++ if (err)
++ return err;
++
++ return 0;
++}
++
++static int mmc_emergency_send_status(struct mmc_panic_host *host, u32 *status)
++{
++ struct mmc_card *card = host->card;
++ int err;
++ struct mmc_command cmd;
++
++ memset(&cmd, 0, sizeof(struct mmc_command));
++
++ cmd.opcode = MMC_SEND_STATUS;
++ if (!mmc_host_is_spi(host))
++ cmd.arg = card->rca << 16;
++ cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
++
++ err = mmc_emergency_send_cmd(&cmd, MMC_CMD_RETRIES);
++ if (err)
++ return err;
++
++ /* NOTE: callers are required to understand the difference
++ * between "native" and SPI format status words!
++ */
++ if (status)
++ *status = cmd.resp[0];
++
++ return 0;
++}
++static int mmc_emergency_switch(struct mmc_panic_host *host,
++ u8 set, u8 index, u8 value)
++{
++ struct mmc_card *card = host->card;
++ int err;
++ struct mmc_command cmd;
++ u32 status;
++
++ memset(&cmd, 0, sizeof(struct mmc_command));
++
++ cmd.opcode = MMC_SWITCH;
++ cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
++ (index << 16) |
++ (value << 8) |
++ set;
++ cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
++
++ err = mmc_emergency_send_cmd(&cmd, MMC_CMD_RETRIES);
++ if (err)
++ return err;
++
++ /* Must check status to be sure of no errors */
++ do {
++ err = mmc_emergency_send_status(host, &status);
++ if (err)
++ return err;
++ if (host->caps & MMC_CAP_WAIT_WHILE_BUSY)
++ break;
++ if (mmc_host_is_spi(host))
++ break;
++ } while (R1_CURRENT_STATE(status) == 7);
++
++ if (mmc_host_is_spi(host)) {
++ if (status & R1_SPI_ILLEGAL_COMMAND)
++ return -EBADMSG;
++ } else {
++ if (status & 0xFDFFA000)
++ pr_warn("%s: unexpected status %#x after switch",
++ mmc_hostname(card->host), status);
++ if (status & R1_SWITCH_ERROR)
++ return -EBADMSG;
++ }
++
++ return 0;
++}
++
++static int mmc_emergency_spi_set_crc(struct mmc_panic_host *host, int use)
++{
++ return -1;
++}
++
++static int mmc_emergency_send_cid(struct mmc_panic_host *host, u32 *cid)
++{
++ return -1;
++}
++/*
++ * reinit card:
++ * should also consider about the SPI host
++ */
++static int mmc_emergency_reinit_card(void)
++{
++ struct mmc_panic_host *host = panic_host;
++ struct mmc_card *card = host->card;
++ u32 ocr = host->ocr;
++ int err, ddr = 0;
++ u32 cid[4];
++ unsigned int max_dtr;
++
++ /*
++ * low the clock to be init clock
++ */
++ if (mmc_host_is_spi(host)) {
++ host->ios.chip_select = MMC_CS_HIGH;
++ host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
++ } else {
++ host->ios.chip_select = MMC_CS_DONTCARE;
++ host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
++ }
++ host->ios.bus_width = MMC_BUS_WIDTH_1;
++ host->ios.timing = MMC_TIMING_LEGACY;
++ /*
++ * AS eMMC spec said, card init frequency cannot higher
++ * then 400Khz. But a good card should support for 400Khz
++ * frequence in initialize process.
++ */
++ host->ios.clock = 400000;
++ host->panic_ops->set_ios(host);
++
++ /*
++ * Since we're changing the OCR value, we seem to
++ * need to tell some cards to go back to the idle
++ * state. We wait 1ms to give cards time to
++ * respond.
++ */
++ mmc_emergency_go_idle(host);
++
++ /* The extra bit indicates that we support high capacity */
++ err = mmc_emergency_send_op_cond(host, ocr | (1 << 30), NULL);
++ if (err)
++ goto err;
++
++ /*
++ * For SPI, enable CRC as appropriate.
++ */
++ if (mmc_host_is_spi(host)) {
++ err = mmc_emergency_spi_set_crc(host, 1);
++ if (err)
++ goto err;
++ }
++
++ /*
++ * Fetch CID from card.
++ */
++ if (mmc_host_is_spi(host))
++ err = mmc_emergency_send_cid(host, cid);
++ else
++ err = mmc_emergency_all_send_cid(cid);
++ if (err)
++ goto err;
++
++ if (memcmp(cid, card->raw_cid, sizeof(cid)) != 0) {
++ err = -ENOENT;
++ goto err;
++ }
++
++ /*
++ * For native busses: set card RCA and quit open drain mode.
++ */
++ if (!mmc_host_is_spi(host)) {
++ err = mmc_emergency_set_relative_addr(card);
++ if (err)
++ goto err;
++
++ host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
++ host->panic_ops->set_ios(host);
++ }
++ /*
++ * Select card, as all following commands rely on that.
++ */
++ if (!mmc_host_is_spi(host)) {
++ err = mmc_emergency_select_card(card);
++ if (err)
++ goto err;
++ }
++
++ /*
++ * Activate high speed (if supported)
++ */
++ if ((card->ext_csd.hs_max_dtr != 0) &&
++ (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
++ err = mmc_emergency_switch(host, EXT_CSD_CMD_SET_NORMAL,
++ EXT_CSD_HS_TIMING, 1);
++ if (err && err != -EBADMSG)
++ goto err;
++
++ if (err) {
++ pr_warn("%s: switch to highspeed failed\n",
++ __func__);
++ err = 0;
++ } else {
++ mmc_card_set_highspeed(card);
++ host->ios.timing = MMC_TIMING_MMC_HS;
++ host->panic_ops->set_ios(host);
++ }
++ }
++
++ /*
++ * Compute bus speed.
++ */
++ max_dtr = (unsigned int)-1;
++
++ if (mmc_card_highspeed(card)) {
++ if (max_dtr > card->ext_csd.hs_max_dtr)
++ max_dtr = card->ext_csd.hs_max_dtr;
++ } else if (max_dtr > card->csd.max_dtr) {
++ max_dtr = card->csd.max_dtr;
++ }
++
++ host->ios.clock = max_dtr;
++ host->panic_ops->set_ios(host);
++
++ /*
++ * Activate wide bus.
++ * By default use SDR mode for panic write
++ */
++ if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
++ (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
++ unsigned ext_csd_bit, bus_width;
++
++ if (host->caps & MMC_CAP_8_BIT_DATA) {
++ ext_csd_bit = EXT_CSD_BUS_WIDTH_8;
++ bus_width = MMC_BUS_WIDTH_8;
++ } else {
++ ext_csd_bit = EXT_CSD_BUS_WIDTH_4;
++ bus_width = MMC_BUS_WIDTH_4;
++ }
++
++ err = mmc_emergency_switch(host, EXT_CSD_CMD_SET_NORMAL,
++ EXT_CSD_BUS_WIDTH, ext_csd_bit);
++
++ if (err && err != -EBADMSG)
++ goto err;
++
++ if (err) {
++ pr_warn("%s: switch to bus %dbit failed\n",
++ __func__, 1 << bus_width);
++ err = 0;
++ } else {
++ ddr = MMC_SDR_MODE;
++ host->ios.bus_width = bus_width;
++ host->panic_ops->set_ios(host);
++ }
++ }
++
++ return 0;
++err:
++ return err;
++}
++
++/*
++ * mmc_emergency_write - write 512Bytes to card in panic mode
++ * @data: data pointer which should pointed to an area no more than
++ * 512Bytes
++ * @blk_id: the block id need to write this 512B data
++ *
++ * This function is supplied to ipanic driver to write 512B data
++ * in panic mode. Please also make sure the data size should not be
++ * larger than 512B, otherwise data lossing.
++ */
++int mmc_emergency_write(char *data, unsigned int blk_id)
++{
++ struct mmc_panic_host *host = panic_host;
++ int ret;
++ if (host == NULL) {
++ pr_err("%s: no device for panic record\n", __func__);
++ return -ENODEV;
++ }
++
++ if (!host->panic_ready) {
++ pr_err("%s: device is not ready for panic record\n", __func__);
++ return -EPERM;
++ }
++
++ if (!data) {
++ pr_err("%s: invalided writing data\n", __func__);
++ return -EINVAL;
++ }
++
++ if (blk_id > host->totalsecs || blk_id < 0) {
++ pr_err("%s: invalided writing blk_id\n", __func__);
++ return -EINVAL;
++ }
++ /*
++ * everything is OK. So, let's start panic record.
++ *
++ * Copy the message data to logbuf
++ */
++ memcpy(host->logbuf, data, SECTOR_SIZE);
++
++ /* hold Dekker mutex first */
++ if (host->panic_ops->hold_mutex && host->panic_ops->release_mutex) {
++ ret = host->panic_ops->hold_mutex(host);
++ if (ret) {
++ pr_err("%s: hold Dekker mutex failed\n", __func__);
++ return ret;
++ }
++ }
++
++ ret = __mmc_emergency_write(blk_id);
++
++ /* release Dekker mutex */
++ if (host->panic_ops->hold_mutex && host->panic_ops->release_mutex)
++ host->panic_ops->release_mutex(host);
++
++ return ret;
++}
++EXPORT_SYMBOL(mmc_emergency_write);
++
++/*
++ * mmc_emergency_init: init host controller and emmc card
++ * when kernel panic occures
++ *
++ * return value:
++ * 0 - init successfully
++ * negative value - Failed during init
++ * -ENODEV - emmc card was removed by driver
++ */
++int mmc_emergency_init(void)
++{
++ struct mmc_panic_host *host = panic_host;
++ int ret;
++ if (host == NULL) {
++ pr_err("%s: no device for panic record\n", __func__);
++ return -ENODEV;
++ }
++
++ ret = mmc_emergency_prepare();
++ if (ret) {
++ pr_err("%s: prepare host controller failed\n", __func__);
++ return ret;
++ }
++
++ if (!host->panic_ops) {
++ pr_err("%s: no panic_ops for panic host\n", __func__);
++ return -EPERM;
++ }
++
++ /*
++ * prepare host controller
++ */
++ if (host->panic_ops->prepare)
++ host->panic_ops->prepare(host);
++
++ /*
++ * during init eMMC card, don't want to be interrupted by SCU FW
++ */
++ if (host->panic_ops->hold_mutex && host->panic_ops->release_mutex) {
++ ret = host->panic_ops->hold_mutex(host);
++ if (ret) {
++ pr_err("%s: hold Dekker mutex failed\n", __func__);
++ return ret;
++ }
++ } else if (host->panic_ops->power_on)
++ /* don't have Dekker mutex, just power on host controller */
++ host->panic_ops->power_on(host);
++
++ /*
++ * reset card since we are not sure whether card is in a good status
++ *
++ * Since in panic mode, we init a old card, so all the command to be
++ * used has no data. So we can reuse the sdhci ops
++ */
++ ret = mmc_emergency_reinit_card();
++ if (ret) {
++ pr_info("%s: reinit card failed\n", __func__);
++ goto out;
++ }
++
++ /*
++ * OK. we are ready
++ */
++ mmc_emergency_ready();
++out:
++ /* release Dekker mutex */
++ if (host->panic_ops->hold_mutex && host->panic_ops->release_mutex)
++ host->panic_ops->release_mutex(host);
++
++ return ret;
++}
++EXPORT_SYMBOL(mmc_emergency_init);
++
++/*
++ * mmc_emergency_setup - init panic_host which is used for panic writing
++ * @host: mmc host
++ *
++ * This function can sample some important value for panic_host use to init
++ * host controller and card. It only works for the driver which has already
++ * called mmc_alloc_panic_host in its probing process
++ */
++void mmc_emergency_setup(struct mmc_host *mmc)
++{
++ struct mmc_panic_host *host = panic_host;
++
++ /*
++ * mmc host has no panic host
++ */
++ if (!mmc->phost)
++ return;
++
++ /*
++ * before setup panic host, make sure panic host is
++ * allocated
++ */
++ if (host == NULL)
++ return;
++
++ /*
++ * panic host has already been setup
++ */
++ if (host->mmc)
++ return;
++
++ /*
++ * mmc host didn't init card
++ */
++ if (!mmc->card)
++ return;
++ /*
++ * if is SDIO card or SD card, by pass
++ */
++ if (mmc_card_sdio(mmc->card) ||
++ mmc_card_sd(mmc->card))
++ return;
++
++ host->card = kzalloc(sizeof(struct mmc_card), GFP_KERNEL);
++ if (!host->card) {
++ pr_err("%s: cannot alloc mmc_card for panic host\n",
++ __func__);
++ return;
++ }
++
++ memcpy(host->card, mmc->card, sizeof(struct mmc_card));
++ host->caps = mmc->caps;
++ host->mmc = mmc;
++ host->ocr = mmc->ocr;
++ host->totalsecs = mmc_get_capacity(mmc->card);
++ host->max_blk_size = mmc->max_blk_size;
++ host->max_blk_count = mmc->max_blk_count;
++ host->max_req_size = mmc->max_req_size;
++ if (mmc_card_blockaddr(mmc->card))
++ host->blkaddr = 1;
++ /*
++ * sample ios values
++ */
++ memcpy(&host->ios, &mmc->ios, sizeof(struct mmc_ios));
++#ifdef CONFIG_MMC_CLKGATE
++ if (mmc->ios.clock == 0)
++ host->ios.clock = mmc->clk_old;
++#endif
++ if (host->panic_ops && host->panic_ops->setup)
++ host->panic_ops->setup(host);
++
++ return;
++}
++EXPORT_SYMBOL(mmc_emergency_setup);
++/*
++ * mmc_alloc_panic_host - used for host layer driver to alloc mmc_panic_host.
++ * @host: mmc host
++ * @ops: this is a pointer which points to mmc_host_panic_ops. This ops should
++ * be defined in host layer driver
++ *
++ * This function need to know the mmc_host_panic_ops, host layer driver should
++ * call this function during probing.
++ *
++ */
++void mmc_alloc_panic_host(struct mmc_host *host,
++ const struct mmc_host_panic_ops *ops)
++{
++ if (panic_host) {
++ pr_info("%s: already allocate panic host\n", __func__);
++ return;
++ }
++
++ panic_host = kzalloc(sizeof(struct mmc_panic_host), GFP_KERNEL);
++ if (!panic_host) {
++ pr_err("%s %s: panic structure allocate error\n",
++ __func__, mmc_hostname(host));
++ return;
++ }
++ /*
++ * allocate log buffer and DMA buffer
++ * log buffer size is 512
++ */
++ panic_host->logbuf = kzalloc(SECTOR_SIZE, GFP_KERNEL);
++ if (!panic_host->logbuf) {
++ pr_err("%s %s: log buf allocate error\n",
++ __func__, mmc_hostname(host));
++ goto free_panic_host;
++ }
++
++ panic_host->dmabuf = dma_map_single(host->parent, panic_host->logbuf,
++ SECTOR_SIZE, DMA_TO_DEVICE);
++ if (!panic_host->dmabuf) {
++ pr_err("%s %s: DMA buf allocate error\n",
++ __func__, mmc_hostname(host));
++ goto free_logbuf;
++ }
++
++ panic_host->panic_ops = ops;
++ panic_host->mmc = NULL;
++ host->phost = panic_host;
++
++ return;
++
++free_logbuf:
++ kfree(panic_host->logbuf);
++free_panic_host:
++ kfree(panic_host);
++}
++EXPORT_SYMBOL(mmc_alloc_panic_host);
+diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c
+index 8e94e55..8b7539f 100644
+--- a/drivers/mmc/core/sdio_cis.c
++++ b/drivers/mmc/core/sdio_cis.c
+@@ -97,8 +97,6 @@ static const unsigned char speed_val[16] =
+ { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 };
+ static const unsigned int speed_unit[8] =
+ { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 };
+-
+-
+ typedef int (tpl_parse_t)(struct mmc_card *, struct sdio_func *,
+ const unsigned char *, unsigned);
+
+@@ -225,12 +223,77 @@ static const struct cis_tpl cis_tpl_list[] = {
+ { 0x22, 0, cistpl_funce },
+ };
+
++/***************************** WP B0 WA *******************************/
++
++unsigned char wp_tpl_codes[] = {
++ 0x21, 0x22, 0x20, 0x21, 0x22, 0x91, 0x15,
++};
++
++unsigned char wp_tpl_links[] = {
++ 0x2, 0x4, 0x4, 0x2, 0x2a, 0x2, 0x19,
++};
++
++unsigned char wp_tuple_data[7][42] = {
++ {
++ 12, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0
++ },
++ {
++ 0, 0, 2, 11, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0
++ },
++ {
++ 137, 0, 96, 114, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0
++ },
++ {
++ 12, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0
++ },
++ {
++ 1, 1, 48, 0, 0, 3, 0, 2, 0, 128,
++ 255, 0, 7, 0, 0, 7, 7, 255, 0, 16,
++ 0, 200, 100, 0, 0, 0, 0, 0, 16, 1,
++ 33, 2, 0, 0, 0, 0, 32, 4, 137, 0,
++ 96, 114
++ },
++ {
++ 7, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0
++ },
++ {
++ 8, 0, 73, 110, 116, 101, 108, 40, 82, 41,
++ 32, 87, 105, 114, 101, 108, 101, 115, 115, 32,
++ 67, 111, 114, 101, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0
++ },
++};
++
++/**********************************************************************/
++
+ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
+ {
+ int ret;
+ struct sdio_func_tuple *this, **prev;
+ unsigned i, ptr = 0;
+-
++ int count = 0;
++ bool replace = false;
+ /*
+ * Note that this works for the common CIS (function number 0) as
+ * well as a function's CIS * since SDIO_CCCR_CIS and SDIO_FBR_CIS
+@@ -245,7 +308,8 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
+ fn = 0;
+
+ ret = mmc_io_rw_direct(card, 0, 0,
+- SDIO_FBR_BASE(fn) + SDIO_FBR_CIS + i, 0, &x);
++ SDIO_FBR_BASE(fn) + SDIO_FBR_CIS + i,
++ 0, &x);
+ if (ret)
+ return ret;
+ ptr |= x << (i * 8);
+@@ -258,20 +322,45 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
+
+ BUG_ON(*prev);
+
++ if (card->quirks & MMC_QUIRK_NON_STD_CIS)
++ count = (func) ? 2 : -1;
++
+ do {
+ unsigned char tpl_code, tpl_link;
++ if (card->quirks & MMC_QUIRK_NON_STD_CIS) {
++ count++;
++ if ((func && (count > 6)) || (!func && (count > 2))) {
++ pr_debug("%s: break: count %d\n",
++ __func__, count);
++ break;
++ }
++ }
+
+ ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_code);
+ if (ret)
+ break;
+-
++ if (card->quirks & MMC_QUIRK_NON_STD_CIS) {
++ /* if the first tuple is 0 - then it's b0, so replace */
++ if ((count < 4) && (tpl_code == 0)) {
++ pr_info("%s card with non std CIS",
++ mmc_hostname(card->host));
++ /* disable UHS on buggy cards */
++ card->sw_caps.sd3_bus_mode = 0;
++ replace = true;
++ }
++ }
+ /* 0xff means we're done */
+ if (tpl_code == 0xff)
+ break;
+
+ /* null entries have no link field or data */
+- if (tpl_code == 0x00)
+- continue;
++ if (card->quirks & MMC_QUIRK_NON_STD_CIS) {
++ if ((tpl_code == 0x00) && (!replace))
++ continue;
++ } else {
++ if (tpl_code == 0x00)
++ continue;
++ }
+
+ ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_link);
+ if (ret)
+@@ -290,6 +379,7 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
+ ptr + i, 0, &this->data[i]);
+ if (ret)
+ break;
++ pr_debug("%d, ", this->data[i]);
+ }
+ if (ret) {
+ kfree(this);
+@@ -297,9 +387,28 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
+ }
+
+ /* Try to parse the CIS tuple */
+- ret = cis_tpl_parse(card, func, "CIS",
+- cis_tpl_list, ARRAY_SIZE(cis_tpl_list),
+- tpl_code, this->data, tpl_link);
++ if (card->quirks & MMC_QUIRK_NON_STD_CIS) {
++ if (!replace)
++ ret = cis_tpl_parse(card, func, "CIS",
++ cis_tpl_list,
++ ARRAY_SIZE(cis_tpl_list),
++ tpl_code, this->data,
++ tpl_link);
++ else
++ ret = cis_tpl_parse(card, func, "CIS",
++ cis_tpl_list,
++ ARRAY_SIZE(cis_tpl_list),
++ wp_tpl_codes[count],
++ wp_tuple_data[count],
++ wp_tpl_links[count]);
++ } else {
++ ret = cis_tpl_parse(card, func, "CIS",
++ cis_tpl_list,
++ ARRAY_SIZE(cis_tpl_list),
++ tpl_code, this->data,
++ tpl_link);
++ }
++
+ if (ret == -EILSEQ || ret == -ENOENT) {
+ /*
+ * The tuple is unknown or known but not parsed.
+diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
+index 701d06d..39696af 100644
+--- a/drivers/mmc/host/sdhci-pci.c
++++ b/drivers/mmc/host/sdhci-pci.c
+@@ -26,16 +26,21 @@
+ #include <linux/pm_runtime.h>
+ #include <linux/mmc/sdhci-pci-data.h>
+
++#include <asm/intel_mid_rpmsg.h>
++#include <asm/intel_scu_flis.h>
++#include <asm/intel_scu_pmic.h>
++
+ #include "sdhci.h"
+
++/* Settle down values copied from broadcom reference design. */
++#define DELAY_CARD_INSERTED 200
++#define DELAY_CARD_REMOVED 50
++
+ /*
+ * PCI device IDs
+ */
+ #define PCI_DEVICE_ID_INTEL_PCH_SDIO0 0x8809
+ #define PCI_DEVICE_ID_INTEL_PCH_SDIO1 0x880a
+-#define PCI_DEVICE_ID_INTEL_BYT_EMMC 0x0f14
+-#define PCI_DEVICE_ID_INTEL_BYT_SDIO 0x0f15
+-#define PCI_DEVICE_ID_INTEL_BYT_SD 0x0f16
+
+ /*
+ * PCI registers
+@@ -50,6 +55,18 @@
+ #define PCI_SLOT_INFO_FIRST_BAR_MASK 0x07
+
+ #define MAX_SLOTS 8
++#define IPC_EMMC_MUTEX_CMD 0xEE
++
++/* CLV SD card power resource */
++
++#define VCCSDIO_ADDR 0xd5
++#define VCCSDIO_OFF 0x4
++#define VCCSDIO_NORMAL 0x7
++#define ENCTRL0_ISOLATE 0x55555557
++#define ENCTRL1_ISOLATE 0x5555
++#define STORAGESTIO_FLISNUM 0x8
++#define ENCTRL0_OFF 0x10
++#define ENCTRL1_OFF 0x11
+
+ struct sdhci_pci_chip;
+ struct sdhci_pci_slot;
+@@ -77,6 +94,9 @@ struct sdhci_pci_slot {
+ int rst_n_gpio;
+ int cd_gpio;
+ int cd_irq;
++ bool dev_power;
++ struct mutex power_lock;
++ bool dma_enabled;
+ };
+
+ struct sdhci_pci_chip {
+@@ -85,10 +105,14 @@ struct sdhci_pci_chip {
+ unsigned int quirks;
+ unsigned int quirks2;
+ bool allow_runtime_pm;
++ unsigned int autosuspend_delay;
+ const struct sdhci_pci_fixes *fixes;
+
+ int num_slots; /* Slots on controller */
+ struct sdhci_pci_slot *slots[MAX_SLOTS]; /* Pointers to host slots */
++
++ unsigned int enctrl0_orig;
++ unsigned int enctrl1_orig;
+ };
+
+
+@@ -260,20 +284,240 @@ static inline void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot)
+
+ #endif
+
++#define MFD_SDHCI_DEKKER_BASE 0xffff7fb0
++static void mfd_emmc_mutex_register(struct sdhci_pci_slot *slot)
++{
++ u32 mutex_var_addr;
++#ifdef CONFIG_INTEL_SCU_IPC
++ int err;
++
++ err = rpmsg_send_generic_command(IPC_EMMC_MUTEX_CMD, 0,
++ NULL, 0, &mutex_var_addr, 1);
++ if (err) {
++ dev_err(&slot->chip->pdev->dev, "IPC error: %d\n", err);
++ dev_info(&slot->chip->pdev->dev, "Specify mutex address\n");
++ /*
++ * Since we failed to get mutex sram address, specify it
++ */
++ mutex_var_addr = MFD_SDHCI_DEKKER_BASE;
++ }
++#else
++ mutex_var_addr = MFD_SDHCI_DEKKER_BASE;
++#endif
++
++ /* 3 housekeeping mutex variables, 12 bytes length */
++ slot->host->sram_addr = ioremap_nocache(mutex_var_addr,
++ 3 * sizeof(u32));
++ if (!slot->host->sram_addr)
++ dev_err(&slot->chip->pdev->dev, "ioremap failed!\n");
++ else {
++ dev_info(&slot->chip->pdev->dev, "mapped addr: %p\n",
++ slot->host->sram_addr);
++ dev_info(&slot->chip->pdev->dev,
++ "current eMMC owner: %d, IA req: %d, SCU req: %d\n",
++ readl(slot->host->sram_addr +
++ DEKKER_EMMC_OWNER_OFFSET),
++ readl(slot->host->sram_addr +
++ DEKKER_IA_REQ_OFFSET),
++ readl(slot->host->sram_addr +
++ DEKKER_SCU_REQ_OFFSET));
++ }
++ spin_lock_init(&slot->host->dekker_lock);
++}
++
+ static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot)
+ {
++ switch (slot->chip->pdev->device) {
++ case PCI_DEVICE_ID_INTEL_MFD_EMMC0:
++ mfd_emmc_mutex_register(slot);
++ sdhci_alloc_panic_host(slot->host);
++ slot->host->mmc->caps2 |= MMC_CAP2_INIT_CARD_SYNC;
++ break;
++ case PCI_DEVICE_ID_INTEL_MFD_EMMC1:
++ break;
++ }
+ slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE;
+ slot->host->mmc->caps2 |= MMC_CAP2_BOOTPART_NOACC |
+ MMC_CAP2_HC_ERASE_SZ;
+ return 0;
+ }
+
++static void mfd_emmc_remove_slot(struct sdhci_pci_slot *slot, int dead)
++{
++ switch (slot->chip->pdev->device) {
++ case PCI_DEVICE_ID_INTEL_MFD_EMMC0:
++ if (slot->host->sram_addr)
++ iounmap(slot->host->sram_addr);
++ break;
++ case PCI_DEVICE_ID_INTEL_MFD_EMMC1:
++ break;
++ }
++}
++
+ static int mfd_sdio_probe_slot(struct sdhci_pci_slot *slot)
+ {
+ slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE;
+ return 0;
+ }
+
++#ifdef CONFIG_INTEL_SCU_FLIS
++/*
++ * Save the current power and shim status, if they are on, turn them off.
++ */
++static int ctp_sd_card_power_save(struct sdhci_pci_slot *slot)
++{
++ int err;
++ u16 addr;
++ u8 data;
++ struct sdhci_pci_chip *chip;
++
++ if (!slot->dev_power)
++ return 0;
++
++ chip = slot->chip;
++ err = intel_scu_ipc_read_shim(&chip->enctrl0_orig,
++ STORAGESTIO_FLISNUM, ENCTRL0_OFF);
++ if (err) {
++ pr_err("SDHCI device %04X: ENCTRL0 read failed, err %d\n",
++ chip->pdev->device, err);
++ chip->enctrl0_orig = ENCTRL0_ISOLATE;
++ chip->enctrl1_orig = ENCTRL1_ISOLATE;
++ /*
++ * stop to shut down VCCSDIO, since we cannot recover
++ * it.
++ * this should not block system entering S3
++ */
++ return 0;
++ }
++ err = intel_scu_ipc_read_shim(&chip->enctrl1_orig,
++ STORAGESTIO_FLISNUM, ENCTRL1_OFF);
++ if (err) {
++ pr_err("SDHCI device %04X: ENCTRL1 read failed, err %d\n",
++ chip->pdev->device, err);
++ chip->enctrl0_orig = ENCTRL0_ISOLATE;
++ chip->enctrl1_orig = ENCTRL1_ISOLATE;
++ /*
++ * stop to shut down VCCSDIO, since we cannot recover
++ * it.
++ * this should not block system entering S3
++ */
++ return 0;
++ }
++
++ /* isolate shim */
++ err = intel_scu_ipc_write_shim(ENCTRL0_ISOLATE,
++ STORAGESTIO_FLISNUM, ENCTRL0_OFF);
++ if (err) {
++ pr_err("SDHCI device %04X: ENCTRL0 ISOLATE failed, err %d\n",
++ chip->pdev->device, err);
++ /*
++ * stop to shut down VCCSDIO. Without isolate shim, the power
++ * may have leak if turn off VCCSDIO.
++ * during S3 resuming, shim and VCCSDIO will be recofigured
++ * this should not block system entering S3
++ */
++ return 0;
++ }
++
++ err = intel_scu_ipc_write_shim(ENCTRL1_ISOLATE,
++ STORAGESTIO_FLISNUM, ENCTRL1_OFF);
++ if (err) {
++ pr_err("SDHCI device %04X: ENCTRL1 ISOLATE failed, err %d\n",
++ chip->pdev->device, err);
++ /*
++ * stop to shut down VCCSDIO. Without isolate shim, the power
++ * may have leak if turn off VCCSDIO.
++ * during S3 resuming, shim and VCCSDIO will be recofigured
++ * this should not block system entering S3
++ */
++ return 0;
++ }
++
++ addr = VCCSDIO_ADDR;
++ data = VCCSDIO_OFF;
++ err = intel_scu_ipc_writev(&addr, &data, 1);
++ if (err) {
++ pr_err("SDHCI device %04X: VCCSDIO turn off failed, err %d\n",
++ chip->pdev->device, err);
++ /*
++ * during S3 resuming, VCCSDIO will be recofigured
++ * this should not block system entering S3.
++ */
++ }
++
++ slot->dev_power = false;
++ return 0;
++}
++
++/*
++ * Restore the power and shim if they are original on.
++ */
++static int ctp_sd_card_power_restore(struct sdhci_pci_slot *slot)
++{
++ int err;
++ u16 addr;
++ u8 data;
++ struct sdhci_pci_chip *chip;
++
++ if (slot->dev_power)
++ return 0;
++
++ chip = slot->chip;
++
++ addr = VCCSDIO_ADDR;
++ data = VCCSDIO_NORMAL;
++ err = intel_scu_ipc_writev(&addr, &data, 1);
++ if (err) {
++ pr_err("SDHCI device %04X: VCCSDIO turn on failed, err %d\n",
++ chip->pdev->device, err);
++ /*
++ * VCCSDIO trun on failed. This may impact the SD card
++ * init and the read/write functions. We just report a
++ * warning, and go on to have a try. Anyway, SD driver
++ * can encounter error if powering up is failed
++ */
++ WARN_ON(err);
++ }
++
++ if (chip->enctrl0_orig == ENCTRL0_ISOLATE &&
++ chip->enctrl1_orig == ENCTRL1_ISOLATE)
++ /* means we needn't to reconfigure the shim */
++ return 0;
++
++ /* reconnect shim */
++ err = intel_scu_ipc_write_shim(chip->enctrl0_orig,
++ STORAGESTIO_FLISNUM, ENCTRL0_OFF);
++
++ if (err) {
++ pr_err("SDHCI device %04X: ENCTRL0 CONNECT shim failed, err %d\n",
++ chip->pdev->device, err);
++ /* keep on setting enctrl1, but report a waring */
++ WARN_ON(err);
++ }
++
++ err = intel_scu_ipc_write_shim(chip->enctrl1_orig,
++ STORAGESTIO_FLISNUM, ENCTRL1_OFF);
++ if (err) {
++ pr_err("SDHCI device %04X: ENCTRL1 CONNECT shim failed, err %d\n",
++ chip->pdev->device, err);
++ /* leave this error to driver, but report a warning */
++ WARN_ON(err);
++ }
++
++ slot->dev_power = true;
++ return 0;
++}
++#else
++static int ctp_sd_card_power_save(struct sdhci_pci_slot *slot)
++{
++ return 0;
++}
++static int ctp_sd_card_power_restore(struct sdhci_pci_slot *slot)
++{
++ return 0;
++}
++#endif
++
+ static const struct sdhci_pci_fixes sdhci_intel_mrst_hc0 = {
+ .quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT,
+ .probe_slot = mrst_hc_probe_slot,
+@@ -284,9 +528,45 @@ static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1_hc2 = {
+ .probe = mrst_hc_probe,
+ };
+
++static int ctp_sd_probe_slot(struct sdhci_pci_slot *slot)
++{
++#ifdef CONFIG_INTEL_SCU_IPC
++ int err;
++ u16 addr;
++#endif
++ u8 data = VCCSDIO_OFF;
++
++ if (!slot || !slot->chip || !slot->chip->pdev)
++ return -ENODEV;
++
++ if (slot->chip->pdev->device != PCI_DEVICE_ID_INTEL_CLV_SDIO0)
++ return 0;
++
++ mutex_init(&slot->power_lock);
++
++ slot->host->flags |= SDHCI_POWER_CTRL_DEV;
++
++#ifdef CONFIG_INTEL_SCU_IPC
++ addr = VCCSDIO_ADDR;
++ err = intel_scu_ipc_readv(&addr, &data, 1);
++ if (err) {
++ /* suppose dev_power is true */
++ slot->dev_power = true;
++ return 0;
++ }
++#endif
++ if (data == VCCSDIO_NORMAL)
++ slot->dev_power = true;
++ else
++ slot->dev_power = false;
++
++ return 0;
++}
++
+ static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = {
+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
+ .allow_runtime_pm = true,
++ .probe_slot = ctp_sd_probe_slot,
+ };
+
+ static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = {
+@@ -300,6 +580,7 @@ static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc = {
+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
+ .allow_runtime_pm = true,
+ .probe_slot = mfd_emmc_probe_slot,
++ .remove_slot = mfd_emmc_remove_slot,
+ };
+
+ static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = {
+@@ -311,27 +592,206 @@ static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
+ {
+ slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE;
+ slot->host->mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ;
++
+ return 0;
+ }
+
+ static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
+ {
+ slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE;
++ switch (slot->chip->pdev->device) {
++ case PCI_DEVICE_ID_INTEL_BYT_SDIO:
++ /* add a delay after runtime resuming back from D0i3 */
++ slot->chip->pdev->d3_delay = 10;
++ /* reduce the auto suspend delay for SDIO to be 500ms */
++ slot->chip->autosuspend_delay = 500;
++ break;
++ }
++
+ return 0;
+ }
+
+-static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = {
++#define TNG_IOAPIC_IDX 0xfec00000
++static void mrfl_ioapic_rte_reg_addr_map(struct sdhci_pci_slot *slot)
++{
++ slot->host->rte_addr = ioremap_nocache(TNG_IOAPIC_IDX, 256);
++ if (!slot->host->rte_addr)
++ dev_err(&slot->chip->pdev->dev, "rte_addr ioremap fail!\n");
++ else
++ dev_info(&slot->chip->pdev->dev, "rte_addr mapped addr: %p\n",
++ slot->host->rte_addr);
++}
++
++/* Define Host controllers for Intel Merrifield platform */
++#define INTEL_MRFL_EMMC_0 0
++#define INTEL_MRFL_EMMC_1 1
++#define INTEL_MRFL_SD 2
++#define INTEL_MRFL_SDIO 3
++
++static int intel_mrfl_mmc_probe_slot(struct sdhci_pci_slot *slot)
++{
++ int ret = 0;
++
++ switch (PCI_FUNC(slot->chip->pdev->devfn)) {
++ case INTEL_MRFL_EMMC_0:
++ sdhci_alloc_panic_host(slot->host);
++ slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA |
++ MMC_CAP_NONREMOVABLE |
++ MMC_CAP_1_8V_DDR;
++ slot->host->mmc->caps2 |= MMC_CAP2_POLL_R1B_BUSY |
++ MMC_CAP2_INIT_CARD_SYNC |
++ MMC_CAP2_CACHE_CTRL;
++ if (slot->chip->pdev->revision == 0x1) { /* B0 stepping */
++ slot->host->mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
++ /* WA for async abort silicon issue */
++ slot->host->quirks2 |= SDHCI_QUIRK2_2MS_DELAY |
++ SDHCI_QUIRK2_WAIT_FOR_IDLE |
++ SDHCI_QUIRK2_TUNING_POLL;
++ }
++ mrfl_ioapic_rte_reg_addr_map(slot);
++ break;
++ case INTEL_MRFL_SD:
++ slot->host->quirks2 |= SDHCI_QUIRK2_WAIT_FOR_IDLE;
++ /* Force 3.3V signal voltage */
++ slot->host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
++ slot->host->mmc->caps2 |= MMC_CAP2_FIXED_NCRC;
++ break;
++ case INTEL_MRFL_SDIO:
++ slot->host->mmc->caps |= MMC_CAP_NONREMOVABLE;
++ break;
++ }
++
++ if (slot->data->platform_quirks & PLFM_QUIRK_NO_HIGH_SPEED) {
++ slot->host->quirks2 |= SDHCI_QUIRK2_DISABLE_HIGH_SPEED;
++ slot->host->mmc->caps &= ~MMC_CAP_1_8V_DDR;
++ }
++
++ if (slot->data->platform_quirks & PLFM_QUIRK_NO_EMMC_BOOT_PART)
++ slot->host->mmc->caps2 |= MMC_CAP2_BOOTPART_NOACC;
++
++ if (slot->data->platform_quirks & PLFM_QUIRK_NO_HOST_CTRL_HW) {
++ dev_info(&slot->chip->pdev->dev, "Disable MMC Func %d.\n",
++ PCI_FUNC(slot->chip->pdev->devfn));
++ ret = -ENODEV;
++ }
++
++ return ret;
++}
++
++static void intel_mrfl_mmc_remove_slot(struct sdhci_pci_slot *slot, int dead)
++{
++ if (PCI_FUNC(slot->chip->pdev->devfn) == INTEL_MRFL_EMMC_0)
++ if (slot->host->rte_addr)
++ iounmap(slot->host->rte_addr);
++}
++
++static const struct sdhci_pci_fixes sdhci_intel_mrfl_mmc = {
++ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
++ .quirks2 = SDHCI_QUIRK2_BROKEN_AUTO_CMD23 |
++ SDHCI_QUIRK2_HIGH_SPEED_SET_LATE |
++ SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+ .allow_runtime_pm = true,
+- .probe_slot = byt_emmc_probe_slot,
++ .probe_slot = intel_mrfl_mmc_probe_slot,
++ .remove_slot = intel_mrfl_mmc_remove_slot,
+ };
+
+-static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
+- .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON,
++static int intel_moor_emmc_probe_slot(struct sdhci_pci_slot *slot)
++{
++ slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA |
++ MMC_CAP_NONREMOVABLE |
++ MMC_CAP_1_8V_DDR;
++
++ sdhci_alloc_panic_host(slot->host);
++
++ slot->host->mmc->caps2 |= MMC_CAP2_POLL_R1B_BUSY |
++ MMC_CAP2_INIT_CARD_SYNC;
++
++ /* Enable HS200 and HS400 */
++ slot->host->mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
++
++ if (slot->chip->pdev->revision == 0x1) { /* B0 stepping */
++ slot->host->mmc->caps2 |= MMC_CAP2_HS400_1_8V_DDR;
++ }
++
++ if (slot->data)
++ if (slot->data->platform_quirks & PLFM_QUIRK_NO_HIGH_SPEED) {
++ slot->host->quirks2 |= SDHCI_QUIRK2_DISABLE_HIGH_SPEED;
++ slot->host->mmc->caps &= ~MMC_CAP_1_8V_DDR;
++ slot->host->mmc->caps2 &= ~MMC_CAP2_HS200_1_8V_SDR;
++ if (slot->chip->pdev->revision == 0x1) {
++ slot->host->mmc->caps2 &=
++ ~MMC_CAP2_HS400_1_8V_DDR;
++ }
++ }
++
++ if (slot->data)
++ if (slot->data->platform_quirks & PLFM_QUIRK_NO_EMMC_BOOT_PART)
++ slot->host->mmc->caps2 |= MMC_CAP2_BOOTPART_NOACC;
++
++ return 0;
++}
++
++static void intel_moor_emmc_remove_slot(struct sdhci_pci_slot *slot, int dead)
++{
++}
++
++static int intel_moor_sd_probe_slot(struct sdhci_pci_slot *slot)
++{
++ int ret = 0;
++
++ if (slot->data)
++ if (slot->data->platform_quirks & PLFM_QUIRK_NO_HOST_CTRL_HW)
++ ret = -ENODEV;
++
++ return ret;
++}
++
++static void intel_moor_sd_remove_slot(struct sdhci_pci_slot *slot, int dead)
++{
++}
++
++static int intel_moor_sdio_probe_slot(struct sdhci_pci_slot *slot)
++{
++ int ret = 0;
++
++ slot->host->mmc->caps |= MMC_CAP_NONREMOVABLE;
++
++ if (slot->data)
++ if (slot->data->platform_quirks & PLFM_QUIRK_NO_HOST_CTRL_HW)
++ ret = -ENODEV;
++
++ return ret;
++}
++
++static void intel_moor_sdio_remove_slot(struct sdhci_pci_slot *slot, int dead)
++{
++}
++
++static const struct sdhci_pci_fixes sdhci_intel_moor_emmc = {
++ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
++ .quirks2 = SDHCI_QUIRK2_BROKEN_AUTO_CMD23 |
++ SDHCI_QUIRK2_HIGH_SPEED_SET_LATE,
+ .allow_runtime_pm = true,
+- .probe_slot = byt_sdio_probe_slot,
++ .probe_slot = intel_moor_emmc_probe_slot,
++ .remove_slot = intel_moor_emmc_remove_slot,
+ };
+
+-static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
++static const struct sdhci_pci_fixes sdhci_intel_moor_sd = {
++ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
++ .quirks2 = SDHCI_QUIRK2_BROKEN_AUTO_CMD23 |
++ SDHCI_QUIRK2_HIGH_SPEED_SET_LATE,
++ .allow_runtime_pm = true,
++ .probe_slot = intel_moor_sd_probe_slot,
++ .remove_slot = intel_moor_sd_remove_slot,
++};
++
++static const struct sdhci_pci_fixes sdhci_intel_moor_sdio = {
++ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
++ .quirks2 = SDHCI_QUIRK2_BROKEN_AUTO_CMD23 |
++ SDHCI_QUIRK2_HIGH_SPEED_SET_LATE,
++ .allow_runtime_pm = true,
++ .probe_slot = intel_moor_sdio_probe_slot,
++ .remove_slot = intel_moor_sdio_remove_slot,
+ };
+
+ /* O2Micro extra registers */
+@@ -887,26 +1347,50 @@ static const struct pci_device_id pci_ids[] = {
+
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+- .device = PCI_DEVICE_ID_INTEL_BYT_EMMC,
++ .device = PCI_DEVICE_ID_INTEL_CLV_SDIO0,
++ .subvendor = PCI_ANY_ID,
++ .subdevice = PCI_ANY_ID,
++ .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sd,
++ },
++
++ {
++ .vendor = PCI_VENDOR_ID_INTEL,
++ .device = PCI_DEVICE_ID_INTEL_CLV_SDIO1,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc,
++ .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sdio,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+- .device = PCI_DEVICE_ID_INTEL_BYT_SDIO,
++ .device = PCI_DEVICE_ID_INTEL_CLV_SDIO2,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio,
++ .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sdio,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+- .device = PCI_DEVICE_ID_INTEL_BYT_SD,
++ .device = PCI_DEVICE_ID_INTEL_CLV_EMMC0,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd,
++ .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc,
++ },
++
++ {
++ .vendor = PCI_VENDOR_ID_INTEL,
++ .device = PCI_DEVICE_ID_INTEL_CLV_EMMC1,
++ .subvendor = PCI_ANY_ID,
++ .subdevice = PCI_ANY_ID,
++ .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc,
++ },
++
++ {
++ .vendor = PCI_VENDOR_ID_INTEL,
++ .device = PCI_DEVICE_ID_INTEL_MRFL_MMC,
++ .subvendor = PCI_ANY_ID,
++ .subdevice = PCI_ANY_ID,
++ .driver_data = (kernel_ulong_t)&sdhci_intel_mrfl_mmc,
+ },
+
+ {
+@@ -964,6 +1448,53 @@ MODULE_DEVICE_TABLE(pci, pci_ids);
+ * *
+ \*****************************************************************************/
+
++static int try_request_regulator(struct device *dev, void *data)
++{
++ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
++ struct sdhci_pci_chip *chip;
++ struct sdhci_pci_slot *slot;
++ struct sdhci_host *host;
++ int i;
++
++ chip = pci_get_drvdata(pdev);
++ if (!chip)
++ return 0;
++
++ for (i = 0; i < chip->num_slots; i++) {
++ slot = chip->slots[i];
++ if (!slot)
++ continue;
++ host = slot->host;
++ if (!host)
++ continue;
++ if (sdhci_try_get_regulator(host) == 0)
++ mmc_detect_change(host->mmc, 0);
++ }
++ return 0;
++}
++
++static struct pci_driver sdhci_driver;
++
++/**
++ * sdhci_pci_request_regulators - retry requesting regulators of
++ * all sdhci-pci devices
++ *
++ * One some platforms, the regulators associated to the mmc are available
++ * late in the boot.
++ * sdhci_pci_request_regulators() is called by platform code to retry
++ * getting the regulators associated to pci sdhcis
++ */
++
++int sdhci_pci_request_regulators(void)
++{
++ /* driver not yet registered */
++ if (!sdhci_driver.driver.p)
++ return 0;
++ return driver_for_each_device(&sdhci_driver.driver,
++ NULL, NULL, try_request_regulator);
++}
++EXPORT_SYMBOL_GPL(sdhci_pci_request_regulators);
++
+ static int sdhci_pci_enable_dma(struct sdhci_host *host)
+ {
+ struct sdhci_pci_slot *slot;
+@@ -971,6 +1502,9 @@ static int sdhci_pci_enable_dma(struct sdhci_host *host)
+ int ret;
+
+ slot = sdhci_priv(host);
++ if (slot->dma_enabled)
++ return 0;
++
+ pdev = slot->chip->pdev;
+
+ if (((pdev->class & 0xFFFF00) == (PCI_CLASS_SYSTEM_SDHCI << 8)) &&
+@@ -986,6 +1520,8 @@ static int sdhci_pci_enable_dma(struct sdhci_host *host)
+
+ pci_set_master(pdev);
+
++ slot->dma_enabled = true;
++
+ return 0;
+ }
+
+@@ -1018,21 +1554,150 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host)
+ {
+ struct sdhci_pci_slot *slot = sdhci_priv(host);
+ int rst_n_gpio = slot->rst_n_gpio;
++ u8 pwr;
++
++ if (gpio_is_valid(rst_n_gpio)) {
++ gpio_set_value_cansleep(rst_n_gpio, 0);
++ /* For eMMC, minimum is 1us but give it 10us for good measure */
++ udelay(10);
++ gpio_set_value_cansleep(rst_n_gpio, 1);
++ /*
++ * For eMMC, minimum is 200us,
++ * but give it 300us for good measure
++ */
++ usleep_range(300, 1000);
++ } else if (slot->host->mmc->caps & MMC_CAP_HW_RESET) {
++ /* first set bit4 of power control register */
++ pwr = sdhci_readb(host, SDHCI_POWER_CONTROL);
++ pwr |= SDHCI_HW_RESET;
++ sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
++ /* keep the same delay for safe */
++ usleep_range(300, 1000);
++ /* then clear bit4 of power control register */
++ pwr &= ~SDHCI_HW_RESET;
++ sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
++ /* keep the same delay for safe */
++ usleep_range(300, 1000);
++ }
++}
+
+- if (!gpio_is_valid(rst_n_gpio))
++static int sdhci_pci_power_up_host(struct sdhci_host *host)
++{
++ int ret = -ENOSYS;
++ struct sdhci_pci_slot *slot = sdhci_priv(host);
++
++ if (slot->data && slot->data->power_up)
++ ret = slot->data->power_up(host);
++ else {
++ /*
++ * use standard PCI power up function
++ */
++ ret = pci_set_power_state(slot->chip->pdev, PCI_D0);
++ mdelay(50);
++ }
++ /*
++ * If there is no power_up callbacks in platform data,
++ * return -ENOSYS;
++ */
++ if (ret)
++ return ret;
++
++ /*
++ * after power up host, let's have a little test
++ */
++
++ if (sdhci_readl(host, SDHCI_HOST_VERSION) ==
++ 0xffffffff) {
++ pr_err("%s: power up sdhci host failed\n",
++ __func__);
++ return -EPERM;
++ }
++
++ pr_info("%s: host controller power up is done\n", __func__);
++
++ return 0;
++}
++
++static void sdhci_pci_set_dev_power(struct sdhci_host *host, bool poweron)
++{
++ struct sdhci_pci_slot *slot;
++ struct sdhci_pci_chip *chip;
++
++ slot = sdhci_priv(host);
++ if (slot)
++ chip = slot->chip;
++ else
+ return;
+- gpio_set_value_cansleep(rst_n_gpio, 0);
+- /* For eMMC, minimum is 1us but give it 10us for good measure */
+- udelay(10);
+- gpio_set_value_cansleep(rst_n_gpio, 1);
+- /* For eMMC, minimum is 200us but give it 300us for good measure */
+- usleep_range(300, 1000);
++
++ /* only available for Intel CTP platform */
++ if (chip && chip->pdev &&
++ chip->pdev->device == PCI_DEVICE_ID_INTEL_CLV_SDIO0) {
++ mutex_lock(&slot->power_lock);
++ if (poweron)
++ ctp_sd_card_power_restore(slot);
++ else
++ ctp_sd_card_power_save(slot);
++ mutex_unlock(&slot->power_lock);
++ }
++}
++
++static int sdhci_pci_get_cd(struct sdhci_host *host)
++{
++ bool present;
++ struct sdhci_pci_slot *slot = sdhci_priv(host);
++
++ if (gpio_is_valid(slot->cd_gpio))
++ return gpio_get_value(slot->cd_gpio) ? 0 : 1;
++
++ /* If nonremovable or polling, assume that the card is always present */
++ if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
++ present = true;
++ else
++ present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
++ SDHCI_CARD_PRESENT;
++
++ return present;
++}
++
++static int sdhci_pci_get_tuning_count(struct sdhci_host *host)
++{
++ struct sdhci_pci_slot *slot = sdhci_priv(host);
++ int tuning_count = 0;
++
++ switch (slot->chip->pdev->device) {
++ case PCI_DEVICE_ID_INTEL_BYT_EMMC45:
++ tuning_count = 4; /* using 8 seconds, this can be tuning */
++ break;
++ case PCI_DEVICE_ID_INTEL_MRFL_MMC:
++ tuning_count = 8; /* using 128 seconds, this can be tuning */
++ break;
++ default:
++ break;
++ }
++
++ return tuning_count;
++}
++
++static int sdhci_gpio_buf_check(struct sdhci_host *host, unsigned int clk)
++{
++ int ret = -ENOSYS;
++ struct sdhci_pci_slot *slot = sdhci_priv(host);
++
++ if (slot->data && slot->data->flis_check)
++ ret = slot->data->flis_check(host, clk);
++
++ return ret;
+ }
+
+ static const struct sdhci_ops sdhci_pci_ops = {
+ .enable_dma = sdhci_pci_enable_dma,
+ .platform_bus_width = sdhci_pci_bus_width,
+ .hw_reset = sdhci_pci_hw_reset,
++ .power_up_host = sdhci_pci_power_up_host,
++ .set_dev_power = sdhci_pci_set_dev_power,
++ .get_cd = sdhci_pci_get_cd,
++ .get_tuning_count = sdhci_pci_get_tuning_count,
++ .gpio_buf_check = sdhci_gpio_buf_check,
+ };
+
+ /*****************************************************************************\
+@@ -1071,6 +1736,7 @@ static int sdhci_pci_suspend(struct device *dev)
+ sdhci_enable_irq_wakeups(slot->host);
+
+ pm_flags |= slot_pm_flags;
++ slot->dma_enabled = false;
+ }
+
+ if (chip->fixes && chip->fixes->suspend) {
+@@ -1079,19 +1745,6 @@ static int sdhci_pci_suspend(struct device *dev)
+ goto err_pci_suspend;
+ }
+
+- pci_save_state(pdev);
+- if (pm_flags & MMC_PM_KEEP_POWER) {
+- if (pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
+- pci_pme_active(pdev, true);
+- pci_enable_wake(pdev, PCI_D3hot, 1);
+- }
+- pci_set_power_state(pdev, PCI_D3hot);
+- } else {
+- pci_enable_wake(pdev, PCI_D3hot, 0);
+- pci_disable_device(pdev);
+- pci_set_power_state(pdev, PCI_D3hot);
+- }
+-
+ return 0;
+
+ err_pci_suspend:
+@@ -1111,12 +1764,6 @@ static int sdhci_pci_resume(struct device *dev)
+ if (!chip)
+ return 0;
+
+- pci_set_power_state(pdev, PCI_D0);
+- pci_restore_state(pdev);
+- ret = pci_enable_device(pdev);
+- if (ret)
+- return ret;
+-
+ if (chip->fixes && chip->fixes->resume) {
+ ret = chip->fixes->resume(chip);
+ if (ret)
+@@ -1232,6 +1879,19 @@ static const struct dev_pm_ops sdhci_pci_pm_ops = {
+ .runtime_idle = sdhci_pci_runtime_idle,
+ };
+
++static void sdhci_hsmmc_virtual_detect(void *dev_id, int carddetect)
++{
++ struct sdhci_host *host = dev_id;
++
++ if (carddetect)
++ mmc_detect_change(host->mmc,
++ msecs_to_jiffies(DELAY_CARD_INSERTED));
++ else
++ mmc_detect_change(host->mmc,
++ msecs_to_jiffies(DELAY_CARD_REMOVED));
++}
++
++
+ /*****************************************************************************\
+ * *
+ * Device probing/removal *
+@@ -1280,11 +1940,17 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
+ slot->rst_n_gpio = -EINVAL;
+ slot->cd_gpio = -EINVAL;
+
++ host->hw_name = "PCI";
++ host->ops = &sdhci_pci_ops;
++ host->quirks = chip->quirks;
++ host->quirks2 = chip->quirks2;
++
+ /* Retrieve platform data if there is any */
+ if (*sdhci_pci_get_data)
+ slot->data = sdhci_pci_get_data(pdev, slotno);
+
+ if (slot->data) {
++ slot->data->pdev = pdev;
+ if (slot->data->setup) {
+ ret = slot->data->setup(slot->data);
+ if (ret) {
+@@ -1294,12 +1960,15 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
+ }
+ slot->rst_n_gpio = slot->data->rst_n_gpio;
+ slot->cd_gpio = slot->data->cd_gpio;
++
++ if (slot->data->quirks)
++ host->quirks2 |= slot->data->quirks;
++
++ if (slot->data->register_embedded_control)
++ slot->data->register_embedded_control(host,
++ sdhci_hsmmc_virtual_detect);
+ }
+
+- host->hw_name = "PCI";
+- host->ops = &sdhci_pci_ops;
+- host->quirks = chip->quirks;
+- host->quirks2 = chip->quirks2;
+
+ host->irq = pdev->irq;
+
+@@ -1334,6 +2003,9 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
+
+ host->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
+ host->mmc->slotno = slotno;
++
++ if (host->quirks2 & SDHCI_QUIRK2_DISABLE_MMC_CAP_NONREMOVABLE)
++ host->mmc->caps &= ~MMC_CAP_NONREMOVABLE;
+ host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP;
+
+ ret = sdhci_add_host(host);
+@@ -1395,11 +2067,20 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot)
+ sdhci_free_host(slot->host);
+ }
+
+-static void sdhci_pci_runtime_pm_allow(struct device *dev)
++static void sdhci_pci_runtime_pm_allow(struct sdhci_pci_chip *chip)
+ {
++ struct device *dev;
++
++ if (!chip || !chip->pdev)
++ return;
++
++ dev = &chip->pdev->dev;
+ pm_runtime_put_noidle(dev);
+ pm_runtime_allow(dev);
+- pm_runtime_set_autosuspend_delay(dev, 50);
++ if (chip->autosuspend_delay)
++ pm_runtime_set_autosuspend_delay(dev, chip->autosuspend_delay);
++ else
++ pm_runtime_set_autosuspend_delay(dev, 50);
+ pm_runtime_use_autosuspend(dev);
+ pm_suspend_ignore_children(dev, 1);
+ }
+@@ -1434,7 +2115,10 @@ static int sdhci_pci_probe(struct pci_dev *pdev,
+ if (slots == 0)
+ return -ENODEV;
+
+- BUG_ON(slots > MAX_SLOTS);
++ if (slots > MAX_SLOTS) {
++ dev_err(&pdev->dev, "Invalid number of the slots. Aborting.\n");
++ return -ENODEV;
++ }
+
+ ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &first_bar);
+ if (ret)
+@@ -1442,7 +2126,7 @@ static int sdhci_pci_probe(struct pci_dev *pdev,
+
+ first_bar &= PCI_SLOT_INFO_FIRST_BAR_MASK;
+
+- if (first_bar > 5) {
++ if (first_bar > 4) {
+ dev_err(&pdev->dev, "Invalid first BAR. Aborting.\n");
+ return -ENODEV;
+ }
+@@ -1475,6 +2159,11 @@ static int sdhci_pci_probe(struct pci_dev *pdev,
+ }
+
+ slots = chip->num_slots; /* Quirk may have changed this */
++ /* slots maybe changed again, so check again */
++ if (slots > MAX_SLOTS) {
++ dev_err(&pdev->dev, "Invalid number of the slots. Aborting.\n");
++ goto free;
++ }
+
+ for (i = 0; i < slots; i++) {
+ slot = sdhci_pci_probe_slot(pdev, chip, first_bar, i);
+@@ -1489,7 +2178,7 @@ static int sdhci_pci_probe(struct pci_dev *pdev,
+ }
+
+ if (chip->allow_runtime_pm)
+- sdhci_pci_runtime_pm_allow(&pdev->dev);
++ sdhci_pci_runtime_pm_allow(chip);
+
+ return 0;
+
+@@ -1523,11 +2212,41 @@ static void sdhci_pci_remove(struct pci_dev *pdev)
+ pci_disable_device(pdev);
+ }
+
++static void sdhci_pci_shutdown(struct pci_dev *pdev)
++{
++ struct sdhci_pci_chip *chip;
++ int i;
++
++ chip = pci_get_drvdata(pdev);
++
++ if (!chip || !chip->pdev)
++ return;
++
++ switch (chip->pdev->device) {
++ case PCI_DEVICE_ID_INTEL_CLV_SDIO0:
++ for (i = 0; i < chip->num_slots; i++) {
++ if (chip->slots[i]->host->flags & SDHCI_POWER_CTRL_DEV)
++ ctp_sd_card_power_save(chip->slots[i]);
++ }
++ break;
++ case PCI_DEVICE_ID_INTEL_MRFL_MMC:
++ if (chip->allow_runtime_pm) {
++ pm_runtime_get_sync(&pdev->dev);
++ pm_runtime_disable(&pdev->dev);
++ pm_runtime_put_noidle(&pdev->dev);
++ }
++ break;
++ default:
++ break;
++ }
++}
++
+ static struct pci_driver sdhci_driver = {
+ .name = "sdhci-pci",
+ .id_table = pci_ids,
+ .probe = sdhci_pci_probe,
+ .remove = sdhci_pci_remove,
++ .shutdown = sdhci_pci_shutdown,
+ .driver = {
+ .pm = &sdhci_pci_pm_ops
+ },
+diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
+index 2ea429c..8289777 100644
+--- a/drivers/mmc/host/sdhci.c
++++ b/drivers/mmc/host/sdhci.c
+@@ -54,6 +54,7 @@ static void sdhci_finish_command(struct sdhci_host *);
+ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
+ static void sdhci_tuning_timer(unsigned long data);
+ static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
++static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios);
+
+ #ifdef CONFIG_PM_RUNTIME
+ static int sdhci_runtime_pm_get(struct sdhci_host *host);
+@@ -173,6 +174,21 @@ static void sdhci_disable_card_detection(struct sdhci_host *host)
+ sdhci_set_card_detection(host, false);
+ }
+
++static void sdhci_busy_wait(struct mmc_host *mmc, u32 delay)
++{
++ struct sdhci_host *host = mmc_priv(mmc);
++
++ /* totally 'delay' us, each loop 4us */
++ u32 loop = delay / 4;
++ while (loop) {
++ /* have a delay here */
++ udelay(4);
++ /* read register to make sure host won't be clock gated */
++ sdhci_readw(host, SDHCI_HOST_VERSION);
++ loop--;
++ }
++}
++
+ static void sdhci_reset(struct sdhci_host *host, u8 mask)
+ {
+ unsigned long timeout;
+@@ -196,7 +212,7 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
+ host->clock = 0;
+
+ /* Wait max 100 ms */
+- timeout = 100;
++ timeout = 10000;
+
+ /* hw clears the bit when it's done */
+ while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
+@@ -207,7 +223,7 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
+ return;
+ }
+ timeout--;
+- mdelay(1);
++ udelay(10);
+ }
+
+ if (host->ops->platform_reset_exit)
+@@ -267,6 +283,9 @@ static void sdhci_activate_led(struct sdhci_host *host)
+ {
+ u8 ctrl;
+
++ if (!(host->mmc->caps2 & MMC_CAP2_LED_SUPPORT))
++ return;
++
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+ ctrl |= SDHCI_CTRL_LED;
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+@@ -276,6 +295,9 @@ static void sdhci_deactivate_led(struct sdhci_host *host)
+ {
+ u8 ctrl;
+
++ if (!(host->mmc->caps2 & MMC_CAP2_LED_SUPPORT))
++ return;
++
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+ ctrl &= ~SDHCI_CTRL_LED;
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+@@ -288,6 +310,9 @@ static void sdhci_led_control(struct led_classdev *led,
+ struct sdhci_host *host = container_of(led, struct sdhci_host, led);
+ unsigned long flags;
+
++ if (!(host->mmc->caps2 & MMC_CAP2_LED_SUPPORT))
++ return;
++
+ spin_lock_irqsave(&host->lock, flags);
+
+ if (host->runtime_suspended)
+@@ -960,6 +985,8 @@ static void sdhci_finish_data(struct sdhci_host *host)
+ * upon error conditions.
+ */
+ if (data->error) {
++ if (host->quirks2 & SDHCI_QUIRK2_WAIT_FOR_IDLE)
++ sdhci_busy_wait(host->mmc, 1000);
+ sdhci_reset(host, SDHCI_RESET_CMD);
+ sdhci_reset(host, SDHCI_RESET_DATA);
+ }
+@@ -978,7 +1005,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
+ WARN_ON(host->cmd);
+
+ /* Wait max 10 ms */
+- timeout = 10;
++ timeout = 1000;
+
+ mask = SDHCI_CMD_INHIBIT;
+ if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
+@@ -999,12 +1026,13 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
+ return;
+ }
+ timeout--;
+- mdelay(1);
++ udelay(10);
+ }
+
+ mod_timer(&host->timer, jiffies + 10 * HZ);
+
+ host->cmd = cmd;
++ host->r1b_busy_end = 0;
+
+ sdhci_prepare_data(host, cmd);
+
+@@ -1105,6 +1133,9 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)
+ case SDHCI_CTRL_UHS_DDR50:
+ preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50);
+ break;
++ case SDHCI_CTRL_HS_DDR200:
++ preset = sdhci_readw(host, SDHCI_PRESET_FOR_HS400);
++ break;
+ default:
+ pr_warn("%s: Invalid UHS-I mode selected\n",
+ mmc_hostname(host->mmc));
+@@ -1137,6 +1168,23 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
+ if (clock == 0)
+ goto out;
+
++ /*
++ * Check and change Host Controller pin GPIO buffer setting
++ * according to the new clock will be used.
++ * For example, when the SD bus frequency is 50MHz or 200MHz,
++ * the controller SD bus CLK/CMD/DAT pin may need different
++ * driving strength and slew settings.
++ * So we add check here. And this API will also change the pin
++ * gpio buffer settings if needed after the check. Of course,
++ * it's platform specific behaviours.
++ * To ensure that the clock signal does not change when gpio
++ * buffer setting modified, we'd better disable SD bus clock
++ * first before changing any gpio pin buffer settings and
++ * enable the SD bus clock again after the changing.
++ */
++ if (host->ops->gpio_buf_check)
++ host->ops->gpio_buf_check(host, clock);
++
+ if (host->version >= SDHCI_SPEC_300) {
+ if (sdhci_readw(host, SDHCI_HOST_CONTROL2) &
+ SDHCI_CTRL_PRESET_VAL_ENABLE) {
+@@ -1210,7 +1258,7 @@ clock_set:
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+ /* Wait max 20 ms */
+- timeout = 20;
++ timeout = 2000;
+ while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
+ & SDHCI_CLOCK_INT_STABLE)) {
+ if (timeout == 0) {
+@@ -1220,7 +1268,7 @@ clock_set:
+ return;
+ }
+ timeout--;
+- mdelay(1);
++ udelay(10);
+ }
+
+ clk |= SDHCI_CLOCK_CARD_EN;
+@@ -1299,6 +1347,216 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
+ return power;
+ }
+
++/*
++ * One of the Medfield eMMC controller (PCI device id 0x0823, SDIO3) is
++ * a shared resource used by the SCU and the IA processors. SCU primarily
++ * uses the eMMC host controller to access the eMMC device's Boot Partition,
++ * while the IA CPU uses the eMMC host controller to access the eMMC device's
++ * User Partition.
++ *
++ * After the SCU hands off the system to the IA processor, the IA processor
++ * assumes ownership to the eMMC host controller. Due to absence of any
++ * arbitration at the eMMC host controller, this could result in concurrent
++ * eMMC host accesses resulting in bus contention and garbage data ending up
++ * in either of the partitions.
++ * To circumvent this from happening, eMMC host controller locking mechanism
++ * is employed, where at any one given time, only one agent, SCU or IA, may be
++ * allowed to access the host. This is achieved by implementing Dekker's
++ * Algorithm (http://en.wikipedia.org/wiki/Dekker's_algorithm) between the
++ * two processors.
++ *
++ * Before handing off the system to the IA processor, SCU must set up three
++ * housekeeping mutex variables allocated in the shared SRAM as follows:
++ *
++ * eMMC_Owner = IA (SCU and IA processors - RW, 32bit)
++ * IA_Req = FALSE (IA -RW, SCU - RO, 32bit)
++ * SCU_Req = FALSE (IA - RO, SCU - R/W, 32bit)
++ *
++ * There is no hardware based access control to these variables and so code
++ * executing on SCU and IA processors must follow below access rules
++ * (Dekker's algorithm):
++ *
++ * -----------------------------------------
++ * SCU Processor Implementation
++ * -----------------------------------------
++ * SCU_Req = TRUE;
++ * while (IA_Req == TRUE) {
++ * if (eMMC_Owner != SCU){
++ * SCU_Req = FALSE;
++ * while (eMMC_Owner != SCU);
++ * SCU_Req = TRUE;
++ * }
++ * }
++ * // SCU now performs eMMC transactions here
++ * ...
++ * // When done, relinquish control to IA
++ * eMMC_Owner = IA;
++ * SCU_Req = FALSE;
++ *
++ * -----------------------------------------
++ * IA Processor Implementation
++ * -----------------------------------------
++ * IA_Req = TRUE;
++ * while (SCU_Req == TRUE) {
++ * if (eMMC_Owner != IA){
++ * IA_Req = FALSE;
++ * while (eMMC_Owner != IA);
++ * IA_Req = TRUE;
++ * }
++ * }
++ * //IA now performs eMMC transactions here
++ * ...
++ * //When done, relinquish control to SCU
++ * eMMC_Owner = SCU;
++ * IA_Req = FALSE;
++ *
++ * ----------------------------------------
++ *
++ * sdhci_do_acquire_ownership- implement the Dekker's algorithm on IA side
++ * This function is only used for acquire ownership, not to re-cofnig host
++ * controller. Since in some scenarios, re-config is not useless. We can
++ * save some unused expenses.
++ * @mmc: mmc host
++ *
++ * @return return value:
++ * 0 - Acquried the ownership successfully. The last owner is IA
++ * 1 - Acquried the ownership successfully. The last owenr is SCU
++ * -EBUSY - failed to acquire ownership within the timeout period
++ */
++static int sdhci_do_acquire_ownership(struct mmc_host *mmc)
++{
++ struct sdhci_host *host;
++ unsigned long t1, t2;
++ unsigned long flags;
++
++ host = mmc_priv(mmc);
++
++ if (!host->sram_addr)
++ return 0;
++
++ /* if host has sram_addr, dekker_lock is initialized */
++ spin_lock_irqsave(&host->dekker_lock, flags);
++
++ host->usage_cnt++;
++
++ /* If IA has already hold the eMMC mutex, then just exit */
++ if (readl(host->sram_addr + DEKKER_IA_REQ_OFFSET)) {
++ spin_unlock_irqrestore(&host->dekker_lock, flags);
++ return 0;
++ }
++
++ DBG("Acquire ownership - eMMC owner: %d, IA req: %d, SCU req: %d\n",
++ readl(host->sram_addr + DEKKER_EMMC_OWNER_OFFSET),
++ readl(host->sram_addr + DEKKER_IA_REQ_OFFSET),
++ readl(host->sram_addr + DEKKER_SCU_REQ_OFFSET));
++
++ writel(1, host->sram_addr + DEKKER_IA_REQ_OFFSET);
++
++ t1 = jiffies + 10 * HZ;
++ t2 = 500;
++
++ while (readl(host->sram_addr + DEKKER_SCU_REQ_OFFSET)) {
++ if (readl(host->sram_addr + DEKKER_EMMC_OWNER_OFFSET) !=
++ DEKKER_OWNER_IA) {
++ writel(0, host->sram_addr + DEKKER_IA_REQ_OFFSET);
++ while (t2) {
++ if (readl(host->sram_addr +
++ DEKKER_EMMC_OWNER_OFFSET) ==
++ DEKKER_OWNER_IA)
++ break;
++ spin_unlock_irqrestore(&host->dekker_lock,
++ flags);
++ usleep_range(8000, 12000);
++ spin_lock_irqsave(&host->dekker_lock, flags);
++ t2--;
++ }
++ if (t2)
++ writel(1, host->sram_addr +
++ DEKKER_IA_REQ_OFFSET);
++ else
++ goto timeout;
++ }
++ if (time_after(jiffies, t1))
++ goto timeout;
++
++ cpu_relax();
++ }
++
++ spin_unlock_irqrestore(&host->dekker_lock, flags);
++ /*
++ * if the last owner is SCU, will do the re-config host controller
++ * in the next
++ */
++ return (readl(host->sram_addr + DEKKER_EMMC_OWNER_OFFSET) ==
++ DEKKER_OWNER_IA) ? 1 : 0;
++
++timeout:
++ pr_err(KERN_ERR "eMMC mutex timeout!\n"
++ "Dump Dekker's house keeping variables -"
++ "eMMC owner: %d, IA req: %d, SCU req: %d\n",
++ readl(host->sram_addr + DEKKER_EMMC_OWNER_OFFSET),
++ readl(host->sram_addr + DEKKER_IA_REQ_OFFSET),
++ readl(host->sram_addr + DEKKER_SCU_REQ_OFFSET));
++
++ /* Release eMMC mutex anyway */
++ writel(DEKKER_OWNER_SCU, host->sram_addr + DEKKER_EMMC_OWNER_OFFSET);
++ writel(0, host->sram_addr + DEKKER_IA_REQ_OFFSET);
++
++ spin_unlock_irqrestore(&host->dekker_lock, flags);
++
++ return -EBUSY;
++}
++
++static int sdhci_acquire_ownership(struct mmc_host *mmc)
++{
++ int ret;
++
++ ret = sdhci_do_acquire_ownership(mmc);
++ if (ret) {
++ struct sdhci_host *host;
++ host = mmc_priv(mmc);
++ /* Re-config HC in case SCU has changed HC reg already */
++ pm_runtime_get_sync(mmc->parent);
++ /*
++ * reinit host registers.
++ * include reset host controller all,
++ * reconfigure clock, pwr and other registers.
++ */
++ sdhci_init(host, 0);
++ host->clock = 0;
++ host->pwr = 0;
++ sdhci_do_set_ios(host, &host->mmc->ios);
++ pm_runtime_put(mmc->parent);
++ }
++
++ return ret;
++}
++
++static void sdhci_release_ownership(struct mmc_host *mmc)
++{
++ struct sdhci_host *host;
++ unsigned long flags;
++
++ host = mmc_priv(mmc);
++
++ if (!host->sram_addr)
++ return;
++
++ spin_lock_irqsave(&host->dekker_lock, flags);
++ BUG_ON(host->usage_cnt == 0);
++ host->usage_cnt--;
++ if (host->usage_cnt == 0) {
++ writel(DEKKER_OWNER_SCU,
++ host->sram_addr + DEKKER_EMMC_OWNER_OFFSET);
++ writel(0, host->sram_addr + DEKKER_IA_REQ_OFFSET);
++ DBG("Exit ownership-eMMC owner: %d,IA req: %d,SCU req: %d\n",
++ readl(host->sram_addr + DEKKER_EMMC_OWNER_OFFSET),
++ readl(host->sram_addr + DEKKER_IA_REQ_OFFSET),
++ readl(host->sram_addr + DEKKER_SCU_REQ_OFFSET));
++ }
++ spin_unlock_irqrestore(&host->dekker_lock, flags);
++}
++
+ /*****************************************************************************\
+ * *
+ * MMC callbacks *
+@@ -1316,8 +1574,16 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+
+ sdhci_runtime_pm_get(host);
+
++ sdhci_acquire_ownership(host->mmc);
++
+ spin_lock_irqsave(&host->lock, flags);
+
++ if (host->suspended) {
++ pr_err("%s: %s: host is in suspend state\n",
++ __func__, mmc_hostname(mmc));
++ BUG_ON(1);
++ }
++
+ WARN_ON(host->mrq != NULL);
+
+ #ifndef SDHCI_USE_LEDS_CLASS
+@@ -1367,28 +1633,51 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+ * tuning procedure before sending command.
+ */
+ if ((host->flags & SDHCI_NEEDS_RETUNING) &&
+- !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) {
++ !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ)) &&
++ mrq->cmd->opcode != MMC_SEND_STATUS) {
+ if (mmc->card) {
++ if ((mmc->card->ext_csd.part_config & 0x07) ==
++ EXT_CSD_PART_CONFIG_ACC_RPMB)
++ goto end_tuning;
+ /* eMMC uses cmd21 but sd and sdio use cmd19 */
+ tuning_opcode =
+ mmc->card->type == MMC_TYPE_MMC ?
+ MMC_SEND_TUNING_BLOCK_HS200 :
+ MMC_SEND_TUNING_BLOCK;
++ host->mrq = NULL;
+ spin_unlock_irqrestore(&host->lock, flags);
+ sdhci_execute_tuning(mmc, tuning_opcode);
+ spin_lock_irqsave(&host->lock, flags);
+-
++end_tuning:
+ /* Restore original mmc_request structure */
+ host->mrq = mrq;
+ }
+ }
+
++ if (!(sdhci_readw(host, SDHCI_CLOCK_CONTROL) &
++ SDHCI_CLOCK_CARD_EN)) {
++ /*
++ * SD bus clock is stopped. no interrupts will be
++ * generate in this case.
++ */
++ pr_warn("%s:%s: SD bus clock not enabled\n",
++ __func__, mmc_hostname(mmc));
++ pr_warn("%s:%s: host->pwr 0x%x, host->clock 0x%x\n",
++ __func__, mmc_hostname(mmc),
++ host->pwr, host->clock);
++ sdhci_dumpregs(host);
++ host->mrq->cmd->error = -EIO;
++ tasklet_schedule(&host->finish_tasklet);
++ goto out;
++ }
++
+ if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23))
+ sdhci_send_command(host, mrq->sbc);
+ else
+ sdhci_send_command(host, mrq->cmd);
+ }
+
++out:
+ mmiowb();
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
+@@ -1401,6 +1690,9 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
+
+ spin_lock_irqsave(&host->lock, flags);
+
++ if (host->quirks2 & SDHCI_QUIRK2_ADVERTISE_2V0_FORCE_1V8)
++ ios->vdd = 7;
++
+ if (host->flags & SDHCI_DEVICE_DEAD) {
+ spin_unlock_irqrestore(&host->lock, flags);
+ if (host->vmmc && ios->power_mode == MMC_POWER_OFF)
+@@ -1475,6 +1767,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
+
+ /* In case of UHS-I modes, set High Speed Enable */
+ if ((ios->timing == MMC_TIMING_MMC_HS200) ||
++ (ios->timing == MMC_TIMING_MMC_HS400) ||
+ (ios->timing == MMC_TIMING_UHS_SDR50) ||
+ (ios->timing == MMC_TIMING_UHS_SDR104) ||
+ (ios->timing == MMC_TIMING_UHS_DDR50) ||
+@@ -1526,7 +1819,9 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
+ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ /* Select Bus Speed Mode for host */
+ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+- if (ios->timing == MMC_TIMING_MMC_HS200)
++ if (ios->timing == MMC_TIMING_MMC_HS400)
++ ctrl_2 |= SDHCI_CTRL_HS_DDR200;
++ else if (ios->timing == MMC_TIMING_MMC_HS200)
+ ctrl_2 |= SDHCI_CTRL_HS_SDR200;
+ else if (ios->timing == MMC_TIMING_UHS_SDR12)
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
+@@ -1577,7 +1872,9 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+ struct sdhci_host *host = mmc_priv(mmc);
+
+ sdhci_runtime_pm_get(host);
++ sdhci_acquire_ownership(mmc);
+ sdhci_do_set_ios(host, ios);
++ sdhci_release_ownership(mmc);
+ sdhci_runtime_pm_put(host);
+ }
+
+@@ -1658,8 +1955,13 @@ static void sdhci_hw_reset(struct mmc_host *mmc)
+ {
+ struct sdhci_host *host = mmc_priv(mmc);
+
+- if (host->ops && host->ops->hw_reset)
++ if (host->ops && host->ops->hw_reset) {
++ sdhci_runtime_pm_get(host);
++ sdhci_acquire_ownership(mmc);
+ host->ops->hw_reset(host);
++ sdhci_release_ownership(mmc);
++ sdhci_runtime_pm_put(host);
++ }
+ }
+
+ static int sdhci_get_ro(struct mmc_host *mmc)
+@@ -1875,6 +2177,11 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
+ sdhci_clear_set_irqs(host, ier, SDHCI_INT_DATA_AVAIL);
+
+ /*
++ * set the data timeout register to be max value
++ */
++ sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
++
++ /*
+ * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number
+ * of loops reaches 40 times or a timeout of 150ms occurs.
+ */
+@@ -1882,6 +2189,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
+ do {
+ struct mmc_command cmd = {0};
+ struct mmc_request mrq = {NULL};
++ unsigned int intmask;
++ unsigned long t = jiffies + msecs_to_jiffies(150);
+
+ if (!tuning_loop_counter && !timeout)
+ break;
+@@ -1922,19 +2231,53 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
+ sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
+
+ sdhci_send_command(host, &cmd);
++ mmiowb();
+
+ host->cmd = NULL;
+ host->mrq = NULL;
+
+- spin_unlock(&host->lock);
+- enable_irq(host->irq);
+-
+- /* Wait for Buffer Read Ready interrupt */
+- wait_event_interruptible_timeout(host->buf_ready_int,
+- (host->tuning_done == 1),
+- msecs_to_jiffies(50));
+- disable_irq(host->irq);
+- spin_lock(&host->lock);
++ /* delete the timer created by send command */
++ del_timer(&host->timer);
++
++ if (host->quirks2 & SDHCI_QUIRK2_TUNING_POLL) {
++ while (!time_after(jiffies, t)) {
++ intmask = sdhci_readl(host, SDHCI_INT_STATUS);
++ if (intmask & SDHCI_INT_DATA_AVAIL) {
++ host->tuning_done = 1;
++ sdhci_writel(host,
++ intmask & SDHCI_INT_DATA_AVAIL,
++ SDHCI_INT_STATUS);
++ break;
++ }
++ }
++ } else {
++ intmask = sdhci_readl(host, SDHCI_INT_STATUS);
++ if (intmask & SDHCI_INT_DATA_AVAIL) {
++ host->tuning_done = 1;
++ sdhci_writel(host,
++ intmask & SDHCI_INT_DATA_AVAIL,
++ SDHCI_INT_STATUS);
++ }
++ spin_unlock(&host->lock);
++ enable_irq(host->irq);
++
++ if (!host->tuning_done)
++ /* Wait for Buffer Read Ready interrupt */
++ wait_event_interruptible_timeout(
++ host->buf_ready_int,
++ (host->tuning_done == 1),
++ msecs_to_jiffies(50));
++ disable_irq(host->irq);
++ spin_lock(&host->lock);
++
++ intmask = sdhci_readl(host, SDHCI_INT_STATUS);
++ if (intmask & SDHCI_INT_DATA_AVAIL) {
++ host->tuning_done = 1;
++ sdhci_writel(host,
++ intmask & SDHCI_INT_DATA_AVAIL,
++ SDHCI_INT_STATUS);
++ }
++ }
+
+ if (!host->tuning_done) {
+ pr_info(DRIVER_NAME ": Timeout waiting for "
+@@ -1953,9 +2296,13 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
+ host->tuning_done = 0;
+
+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+- tuning_loop_counter--;
+- timeout--;
+- mdelay(1);
++ if (tuning_loop_counter)
++ tuning_loop_counter--;
++ if (timeout)
++ timeout--;
++ spin_unlock(&host->lock);
++ usleep_range(900, 1100);
++ spin_lock(&host->lock);
+ } while (ctrl & SDHCI_CTRL_EXEC_TUNING);
+
+ /*
+@@ -2056,6 +2403,8 @@ static void sdhci_card_event(struct mmc_host *mmc)
+ pr_err("%s: Resetting controller.\n",
+ mmc_hostname(host->mmc));
+
++ if (host->quirks2 & SDHCI_QUIRK2_WAIT_FOR_IDLE)
++ sdhci_busy_wait(mmc, 1000);
+ sdhci_reset(host, SDHCI_RESET_CMD);
+ sdhci_reset(host, SDHCI_RESET_DATA);
+
+@@ -2066,6 +2415,23 @@ static void sdhci_card_event(struct mmc_host *mmc)
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
+
++static void sdhci_set_dev_power(struct mmc_host *mmc, bool poweron)
++{
++ struct sdhci_host *host = mmc_priv(mmc);
++ if (host->ops->set_dev_power)
++ host->ops->set_dev_power(host, poweron);
++}
++
++static void sdhci_init_card(struct mmc_host *mmc, struct mmc_card *card)
++{
++ struct sdhci_host *host = mmc_priv(mmc);
++
++ if (host->quirks2 & SDHCI_QUIRK2_NON_STD_CIS) {
++ card->quirks |= MMC_QUIRK_NON_STD_CIS;
++ }
++}
++
++
+ static const struct mmc_host_ops sdhci_ops = {
+ .request = sdhci_request,
+ .set_ios = sdhci_set_ios,
+@@ -2077,6 +2443,9 @@ static const struct mmc_host_ops sdhci_ops = {
+ .execute_tuning = sdhci_execute_tuning,
+ .card_event = sdhci_card_event,
+ .card_busy = sdhci_card_busy,
++ .set_dev_power = sdhci_set_dev_power,
++ .init_card = sdhci_init_card,
++ .busy_wait = sdhci_busy_wait,
+ };
+
+ /*****************************************************************************\
+@@ -2089,9 +2458,11 @@ static void sdhci_tasklet_card(unsigned long param)
+ {
+ struct sdhci_host *host = (struct sdhci_host*)param;
+
++ cancel_delayed_work(&host->mmc->detect);
++
+ sdhci_card_event(host->mmc);
+
+- mmc_detect_change(host->mmc, msecs_to_jiffies(200));
++ mmc_detect_change(host->mmc, msecs_to_jiffies(500));
+ }
+
+ static void sdhci_tasklet_finish(unsigned long param)
+@@ -2122,7 +2493,8 @@ static void sdhci_tasklet_finish(unsigned long param)
+ * upon error conditions.
+ */
+ if (!(host->flags & SDHCI_DEVICE_DEAD) &&
+- ((mrq->cmd && mrq->cmd->error) ||
++ ((mrq->cmd && mrq->cmd->error &&
++ mrq->cmd->error != -ENOMEDIUM) ||
+ (mrq->data && (mrq->data->error ||
+ (mrq->data->stop && mrq->data->stop->error))) ||
+ (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) {
+@@ -2134,6 +2506,8 @@ static void sdhci_tasklet_finish(unsigned long param)
+
+ /* Spec says we should do both at the same time, but Ricoh
+ controllers do not like that. */
++ if (host->quirks2 & SDHCI_QUIRK2_WAIT_FOR_IDLE)
++ sdhci_busy_wait(host->mmc, 1000);
+ sdhci_reset(host, SDHCI_RESET_CMD);
+ sdhci_reset(host, SDHCI_RESET_DATA);
+ }
+@@ -2149,10 +2523,25 @@ static void sdhci_tasklet_finish(unsigned long param)
+ mmiowb();
+ spin_unlock_irqrestore(&host->lock, flags);
+
++ sdhci_release_ownership(host->mmc);
+ mmc_request_done(host->mmc, mrq);
+ sdhci_runtime_pm_put(host);
+ }
+
++static void dump_rte_apic_reg(struct sdhci_host *host, void __iomem *idx_addr)
++{
++ unsigned int rte_lo, rte_hi;
++
++ writeb(0x10 + 2 * host->irq, idx_addr);
++ rte_lo = readl(host->rte_addr + 0x10);
++
++ writeb(0x10 + 2 * host->irq + 1, idx_addr);
++ rte_hi = readl(host->rte_addr + 0x10);
++
++ pr_err("%s: dump APIC RTE reg - L32: 0x%08x, H32: 0x%08x\n",
++ mmc_hostname(host->mmc), rte_lo, rte_hi);
++}
++
+ static void sdhci_timeout_timer(unsigned long data)
+ {
+ struct sdhci_host *host;
+@@ -2167,6 +2556,9 @@ static void sdhci_timeout_timer(unsigned long data)
+ "interrupt.\n", mmc_hostname(host->mmc));
+ sdhci_dumpregs(host);
+
++ if (host->rte_addr)
++ dump_rte_apic_reg(host, host->rte_addr);
++
+ if (host->data) {
+ host->data->error = -ETIMEDOUT;
+ sdhci_finish_data(host);
+@@ -2243,7 +2635,10 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
+ DBG("Cannot wait for busy signal when also "
+ "doing a data transfer");
+ else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ))
+- return;
++ if (!host->r1b_busy_end) {
++ host->r1b_busy_end = 1;
++ return;
++ }
+
+ /* The controller does not support the end-of-busy IRQ,
+ * fall through and take the SDHCI_INT_RESPONSE */
+@@ -2306,7 +2701,10 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
+ */
+ if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) {
+ if (intmask & SDHCI_INT_DATA_END) {
+- sdhci_finish_command(host);
++ if (host->r1b_busy_end)
++ sdhci_finish_command(host);
++ else
++ host->r1b_busy_end = 1;
+ return;
+ }
+ }
+@@ -2436,6 +2834,21 @@ again:
+ }
+
+ if (intmask & SDHCI_INT_CMD_MASK) {
++ /*
++ * If encounter command conflict interrupts,
++ * before clearing it, delay 64 clocks, otherwise the interrupts
++ * will be generated again.
++ * This is just experience. SDHC spec doesn't
++ * say the command conflict interrupts will be generated
++ * again without a delay before clearing them.
++ */
++ if ((intmask & SDHCI_INT_CMD_CONFLICT) ==
++ SDHCI_INT_CMD_CONFLICT) {
++ if (host->clock)
++ udelay(64 * 1000000 / host->clock);
++ else
++ udelay(500);
++ }
+ sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK,
+ SDHCI_INT_STATUS);
+ sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
+@@ -2491,94 +2904,841 @@ out:
+ return result;
+ }
+
+-/*****************************************************************************\
+- * *
+- * Suspend/resume *
+- * *
+-\*****************************************************************************/
+-
+-#ifdef CONFIG_PM
+-void sdhci_enable_irq_wakeups(struct sdhci_host *host)
+-{
+- u8 val;
+- u8 mask = SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE
+- | SDHCI_WAKE_ON_INT;
+-
+- val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL);
+- val |= mask ;
+- /* Avoid fake wake up */
+- if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
+- val &= ~(SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE);
+- sdhci_writeb(host, val, SDHCI_WAKE_UP_CONTROL);
+-}
+-EXPORT_SYMBOL_GPL(sdhci_enable_irq_wakeups);
+-
+-void sdhci_disable_irq_wakeups(struct sdhci_host *host)
++/************************************************************************\
++ * *
++ * APIs for panic record use *
++ * Note: *
++ * For panic use, please take care of sdhci_read/write. *
++ * *
++ * sdhci_read/write function are defined by sdhci host layer which *
++ * warpped the read/write function. *
++ * But before calling read/write, sdhci_read/write will try to see if *
++ * some host drivers defined special register reading/writing functions.*
++ * If do, that is means read/write function defined by kernel cannot be *
++ * used, have to use the special ones. *
++ * So, if host driver are using special ones, please make sure when in *
++ * panic mode, the special ones are still good to use *
++ * So, if not, read/write defined by kernel is safe for panic using *
++ * *
++ * @For MFLD sdhci host controller driver, no special reading/writing *
++ * funtion are used *
++ * *
++ \************************************************************************/
++
++static int panic_irq_done;
++
++static void sdhci_panic_irq_wait(struct sdhci_host *host);
++
++static inline void sdhci_panic_finish_req(struct sdhci_host *host)
+ {
+- u8 val;
+- u8 mask = SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE
+- | SDHCI_WAKE_ON_INT;
+-
+- val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL);
+- val &= ~mask;
+- sdhci_writeb(host, val, SDHCI_WAKE_UP_CONTROL);
++ host->mrq = NULL;
++ host->cmd = NULL;
++ host->data = NULL;
++ panic_irq_done = 1;
+ }
+-EXPORT_SYMBOL_GPL(sdhci_disable_irq_wakeups);
+
+-int sdhci_suspend_host(struct sdhci_host *host)
++/*
++ * assuming only use SDMA write and data length is 512Bytes
++ */
++static void sdhci_panic_send_cmd(struct sdhci_host *host,
++ struct mmc_command *cmd)
+ {
+- int ret;
+-
+- if (host->ops->platform_suspend)
+- host->ops->platform_suspend(host);
++ unsigned long timeout;
++ u32 mask;
++ int flags;
+
+- sdhci_disable_card_detection(host);
++ WARN_ON(host->cmd);
++ /* Wait max 10 ms */
++ timeout = 10;
++ mask = SDHCI_CMD_INHIBIT;
++ if ((cmd->data != 0) || (cmd->flags & MMC_RSP_BUSY))
++ mask |= SDHCI_DATA_INHIBIT;
+
+- /* Disable tuning since we are suspending */
+- if (host->flags & SDHCI_USING_RETUNING_TIMER) {
+- del_timer_sync(&host->tuning_timer);
+- host->flags &= ~SDHCI_NEEDS_RETUNING;
++ while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
++ if (timeout == 0) {
++ pr_err("%s %s: Controller never released inhibit bit(s).\n",
++ __func__, mmc_hostname(host->mmc));
++ sdhci_dumpregs(host);
++ sdhci_panic_finish_req(host);
++ return;
++ }
++ timeout--;
++ /*
++ * seems card is not ready for the next command.
++ * We can wait for 1ms and then to have a retry
++ */
++ mdelay(1);
+ }
+
+- ret = mmc_suspend_host(host->mmc);
+- if (ret) {
+- if (host->flags & SDHCI_USING_RETUNING_TIMER) {
+- host->flags |= SDHCI_NEEDS_RETUNING;
+- mod_timer(&host->tuning_timer, jiffies +
+- host->tuning_count * HZ);
++ host->cmd = cmd;
++ host->r1b_busy_end = 0;
++
++ /*
++ * set the data timeout register to be max value
++ */
++ sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
++ /*
++ * prepare data
++ */
++ if (cmd->data) {
++ unsigned int mode;
++ struct mmc_data *data = cmd->data;
++ u32 pio_irqs = SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL;
++ u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR;
++
++ host->data = data;
++ host->data_early = 0;
++ /*
++ * update DMA address
++ */
++ sdhci_writel(host, data->dmabuf, SDHCI_DMA_ADDRESS);
++
++ if (host->version >= SDHCI_SPEC_200) {
++ u8 ctrl;
++ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
++ ctrl &= ~SDHCI_CTRL_DMA_MASK;
++ if ((host->flags & SDHCI_REQ_USE_DMA) &&
++ (host->flags & SDHCI_USE_ADMA))
++ ctrl |= SDHCI_CTRL_ADMA32;
++ else
++ ctrl |= SDHCI_CTRL_SDMA;
++ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+ }
+
+- sdhci_enable_card_detection(host);
++ if (host->flags & SDHCI_REQ_USE_DMA)
++ sdhci_clear_set_irqs(host, pio_irqs, dma_irqs);
++ else
++ sdhci_clear_set_irqs(host, dma_irqs, pio_irqs);
+
+- return ret;
+- }
++ /*
++ * We do not handle DMA boundaries,
++ * so set it to max (512 KiB)
++ */
++ sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, data->blksz),
++ SDHCI_BLOCK_SIZE);
++ sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
+
+- if (!device_may_wakeup(mmc_dev(host->mmc))) {
+- sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
+- free_irq(host->irq, host);
+- } else {
+- sdhci_enable_irq_wakeups(host);
+- enable_irq_wake(host->irq);
+- }
+- return ret;
+-}
++ /*
++ * set transfer mode
++ */
++ mode = SDHCI_TRNS_BLK_CNT_EN;
++ if (data->blocks > 1) {
++ if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
++ mode |= SDHCI_TRNS_MULTI |
++ SDHCI_TRNS_AUTO_CMD12;
++ else
++ mode |= SDHCI_TRNS_MULTI;
++ }
++ if (host->flags & SDHCI_REQ_USE_DMA)
++ mode |= SDHCI_TRNS_DMA;
+
+-EXPORT_SYMBOL_GPL(sdhci_suspend_host);
++ sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
++ }
+
+-int sdhci_resume_host(struct sdhci_host *host)
+-{
+- int ret;
++ sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
+
+- if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
+- if (host->ops->enable_dma)
+- host->ops->enable_dma(host);
++ if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
++ pr_err("%s %s: Unsupported response type!\n",
++ __func__, mmc_hostname(host->mmc));
++ sdhci_panic_finish_req(host);
++ return;
++ }
++
++ if (!(cmd->flags & MMC_RSP_PRESENT))
++ flags = SDHCI_CMD_RESP_NONE;
++ else if (cmd->flags & MMC_RSP_136)
++ flags = SDHCI_CMD_RESP_LONG;
++ else if (cmd->flags & MMC_RSP_BUSY)
++ flags = SDHCI_CMD_RESP_SHORT_BUSY;
++ else
++ flags = SDHCI_CMD_RESP_SHORT;
++
++ if (cmd->flags & MMC_RSP_CRC)
++ flags |= SDHCI_CMD_CRC;
++ if (cmd->flags & MMC_RSP_OPCODE)
++ flags |= SDHCI_CMD_INDEX;
++ if (cmd->data)
++ flags |= SDHCI_CMD_DATA;
++
++ /*
++ * send command
++ */
++ sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
++
++ mmiowb();
++
++ /*
++ * polling interrupt
++ */
++ sdhci_panic_irq_wait(host);
++}
++
++static void sdhci_panic_finish_data(struct sdhci_host *host)
++{
++ struct mmc_data *data;
++
++ BUG_ON(!host->data);
++
++ data = host->data;
++ host->data = NULL;
++
++ /*
++ * panic use, will not unmap anything here
++ */
++
++ /*
++ * The specification states that the block count register must
++ * be updated, but it does not specify at what point in the
++ * data flow. That makes the register entirely useless to read
++ * back so we have to assume that nothing made it to the card
++ * in the event of an error.
++ */
++ if (data->error)
++ data->bytes_xfered = 0;
++ else
++ data->bytes_xfered = data->blksz * data->blocks;
++
++ if (data->stop) {
++ /*
++ * we will not be here since we use single block
++ * transfer when panic occured
++ */
++ sdhci_panic_send_cmd(host, data->stop);
++ } else
++ sdhci_panic_finish_req(host);
++}
++
++static void sdhci_panic_finish_command(struct sdhci_host *host)
++{
++ int i;
++
++ BUG_ON(host->cmd == NULL);
++
++ if (host->cmd->flags & MMC_RSP_PRESENT) {
++ if (host->cmd->flags & MMC_RSP_136) {
++ /* CRC is stripped so we need to do some shifting. */
++ for (i = 0; i < 4; i++) {
++ host->cmd->resp[i] = sdhci_readl(host,
++ SDHCI_RESPONSE + (3-i)*4) << 8;
++ if (i != 3)
++ host->cmd->resp[i] |=
++ sdhci_readb(host,
++ SDHCI_RESPONSE + (3-i)*4-1);
++ }
++ } else {
++ host->cmd->resp[0] = sdhci_readl(host, SDHCI_RESPONSE);
++ }
++ }
++
++ host->cmd->error = 0;
++
++ if (host->data && host->data_early)
++ sdhci_panic_finish_data(host);
++
++ if (!host->cmd->data)
++ sdhci_panic_finish_req(host);
++
++ host->cmd = NULL;
++}
++
++/*
++ * sdhci_panic_data_irq: handle data irq in panic mode
++ *
++ * When host is in panic mode, host driver need to poll its interrupt
++ * status register. Once looked up some cmd irqs, call this function
++ * to handle.
++ */
++static void sdhci_panic_cmd_irq(struct sdhci_host *host, u32 intmask)
++{
++ BUG_ON(intmask == 0);
++
++ if (intmask & SDHCI_INT_TIMEOUT)
++ host->cmd->error = -ETIMEDOUT;
++ else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT |
++ SDHCI_INT_INDEX))
++ host->cmd->error = -EILSEQ;
++
++ if (host->cmd->error) {
++ sdhci_panic_finish_req(host);
++ return;
++ }
++
++ if (host->cmd->flags & MMC_RSP_BUSY) {
++ if (host->cmd->data)
++ pr_debug("Cannot wait for busy signal when also doing a data transfer\n");
++ else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ))
++ if (!host->r1b_busy_end) {
++ host->r1b_busy_end = 1;
++ return;
++ }
++ }
++
++ if (intmask & SDHCI_INT_RESPONSE)
++ sdhci_panic_finish_command(host);
++}
++
++/*
++ * sdhci_panic_data_irq: handle data irq in panic mode
++ *
++ * When host is in panic mode, host driver need to poll its interrupt
++ * status register. Once looked up some data irqs, call this function
++ * to handle.
++ */
++static void sdhci_panic_data_irq(struct sdhci_host *host, u32 intmask)
++{
++ BUG_ON(intmask == 0);
++
++ if (!host->data) {
++ /*
++ * The "data complete" interrupt is also used to
++ * indicate that a busy state has ended. See comment
++ * above in sdhci_cmd_irq().
++ */
++ if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) {
++ if (intmask & SDHCI_INT_DATA_END) {
++ if (host->r1b_busy_end)
++ sdhci_panic_finish_command(host);
++ else
++ host->r1b_busy_end = 1;
++ return;
++ }
++ }
++
++ pr_err("%s %s: Got data interrupt 0x%08x even though no data operation was in progress.\n",
++ __func__, mmc_hostname(host->mmc), (unsigned)intmask);
++ sdhci_dumpregs(host);
++
++ return;
++ }
++
++ if (intmask & SDHCI_INT_DATA_TIMEOUT)
++ host->data->error = -ETIMEDOUT;
++ else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT))
++ host->data->error = -EILSEQ;
++ else if (intmask & SDHCI_INT_ADMA_ERROR) {
++ pr_err("%s: ADMA error\n", mmc_hostname(host->mmc));
++ host->data->error = -EIO;
++ }
++
++ if (host->data->error)
++ sdhci_panic_finish_data(host);
++ else {
++ if (intmask & SDHCI_INT_DMA_END)
++ sdhci_writel(host, sdhci_readl(host, SDHCI_DMA_ADDRESS),
++ SDHCI_DMA_ADDRESS);
++
++ if (intmask & SDHCI_INT_DATA_END) {
++ if (host->cmd)
++ host->data_early = 1;
++ else
++ sdhci_panic_finish_data(host);
++ }
++ }
++}
++
++/*
++ * sdhci_panic_irq_wait: irq handler for panic record
++ */
++static void sdhci_panic_irq_wait(struct sdhci_host *host)
++{
++ u32 intmask;
++ panic_irq_done = 0;
++retry:
++ intmask = sdhci_readl(host, SDHCI_INT_STATUS);
++
++ if (!intmask || intmask == 0xffffffff)
++ goto retry;
++
++ DBG("***%s got interrupt: 0x%08x\n",
++ __func__, intmask);
++
++ if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
++ sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
++ SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
++ /*
++ * do nothing for card detect
++ */
++ }
++
++ intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
++
++ if (intmask & SDHCI_INT_CMD_MASK) {
++ sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK,
++ SDHCI_INT_STATUS);
++ sdhci_panic_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
++ }
++
++ if (intmask & SDHCI_INT_DATA_MASK) {
++ sdhci_writel(host, intmask & SDHCI_INT_DATA_MASK,
++ SDHCI_INT_STATUS);
++ sdhci_panic_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
++ }
++
++ intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
++
++ intmask &= ~SDHCI_INT_ERROR;
++
++ if (intmask & SDHCI_INT_BUS_POWER) {
++ pr_err("%s %s: Card is consuming too much power!\n",
++ __func__, mmc_hostname(host->mmc));
++ sdhci_writel(host, SDHCI_INT_BUS_POWER, SDHCI_INT_STATUS);
++ }
++
++ intmask &= ~SDHCI_INT_BUS_POWER;
++
++ if (intmask & SDHCI_INT_CARD_INT) {
++ sdhci_writel(host, intmask & SDHCI_INT_CARD_INT,
++ SDHCI_INT_STATUS);
++ /*
++ * do nothing for this irq
++ */
++ intmask &= ~SDHCI_INT_CARD_INT;
++ }
++
++ if (intmask) {
++ pr_err("%s %s: Unexpected interrupt 0x%08x.\n",
++ __func__, mmc_hostname(host->mmc), intmask);
++ sdhci_dumpregs(host);
++
++ sdhci_writel(host, intmask, SDHCI_INT_STATUS);
++ }
++
++ mmiowb();
++ if (!panic_irq_done)
++ goto retry;
++}
++
++static void sdhci_mfld_panic_set_ios(struct mmc_panic_host *mmc)
++{
++ struct sdhci_host *host;
++ struct mmc_ios *ios;
++ u8 ctrl;
++
++ if (!mmc)
++ return;
++ ios = &mmc->ios;
++ host = (struct sdhci_host *)mmc->priv;
++
++ /*
++ * Reset the chip on each power off.
++ * Should clear out any weird states.
++ */
++ if (ios->power_mode == MMC_POWER_OFF)
++ pr_info("%s: we are in panic, why need power off?\n", __func__);
++
++ sdhci_set_clock(host, ios->clock);
++
++ if (ios->power_mode == MMC_POWER_OFF)
++ sdhci_set_power(host, -1);
++ else
++ sdhci_set_power(host, ios->vdd);
++
++ if (host->ops->platform_send_init_74_clocks)
++ host->ops->platform_send_init_74_clocks(host, ios->power_mode);
++
++ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
++
++ if (ios->bus_width == MMC_BUS_WIDTH_8)
++ ctrl |= SDHCI_CTRL_8BITBUS;
++ else
++ ctrl &= ~SDHCI_CTRL_8BITBUS;
++
++ if (ios->bus_width == MMC_BUS_WIDTH_4)
++ ctrl |= SDHCI_CTRL_4BITBUS;
++ else
++ ctrl &= ~SDHCI_CTRL_4BITBUS;
++
++ if ((ios->timing == MMC_TIMING_SD_HS ||
++ ios->timing == MMC_TIMING_MMC_HS)
++ && !(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT))
++ ctrl |= SDHCI_CTRL_HISPD;
++ else
++ ctrl &= ~SDHCI_CTRL_HISPD;
++
++ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
++
++ /*
++ * Some (ENE) controllers go apeshit on some ios operation,
++ * signalling timeout and CRC errors even on CMD0. Resetting
++ * it on each ios seems to solve the problem.
++ */
++ if (host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
++ sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
++
++ mmiowb();
++}
++
++static void sdhci_panic_reinit_host(struct mmc_panic_host *mmc)
++{
++ struct sdhci_host *host = mmc->priv;
++ sdhci_init(host, 0);
++ host->pwr = 0; /* force power reprogram */
++ host->clock = 0; /* force clock reprogram */
++ sdhci_mfld_panic_set_ios(mmc);
++ mmiowb();
++}
++
++static void sdhci_mfld_panic_request(struct mmc_panic_host *panic_mmc,
++ struct mmc_request *mrq)
++{
++ struct sdhci_host *host;
++ bool present;
++
++ if (!panic_mmc || !mrq)
++ return;
++
++ host = (struct sdhci_host *)panic_mmc->priv;
++
++ /*
++ * only support single block data DMA write
++ */
++ if (mrq->cmd->data) {
++ if (mrq->cmd->data->blocks != 1 ||
++ mrq->cmd->data->flags & MMC_DATA_READ)
++ mrq->cmd->error = -EINVAL;
++ }
++
++ if (host->flags & SDHCI_USE_ADMA)
++ host->flags &= ~SDHCI_USE_ADMA;
++
++ if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12) {
++ if (mrq->stop) {
++ mrq->data->stop = NULL;
++ mrq->stop = NULL;
++ }
++ }
++
++ host->mrq = mrq;
++
++ /* If polling, assume that the card is always present. */
++ if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
++ present = true;
++ else
++ present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
++ SDHCI_CARD_PRESENT;
++
++ if (!present) {
++ host->mrq->cmd->error = -ENOMEDIUM;
++ sdhci_panic_finish_req(host);
++ } else
++ sdhci_panic_send_cmd(host, mrq->cmd);
++
++ /*
++ * The controller needs a reset of internal state machines
++ * upon error conditions.
++ */
++ if (mrq->cmd->error || (mrq->data && (mrq->data->error ||
++ (mrq->data->stop && mrq->data->stop->error))) ||
++ (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)) {
++ pr_err("%s: request handle failed\n", __func__);
++ sdhci_dumpregs(host);
++ sdhci_panic_reinit_host(panic_mmc);
++ }
++}
++
++/*
++ * The same like sdhci_acquire_ownership, used for IA to get the ownership
++ * before using host controller. Since this function is called in panic mode,
++ * so we can not use msleep() like sdhci_acquire_ownership does, use mdelay()
++ * instead.
++ */
++static int sdhci_mfld_panic_acquire_ownership(struct sdhci_host *host)
++{
++ unsigned long t1, t2;
++
++ if (!host->sram_addr)
++ return DEKKER_OWNER_IA;
++
++ /* If IA has already hold the eMMC mutex, then just exit */
++ if (readl(host->sram_addr + DEKKER_IA_REQ_OFFSET))
++ return 0;
++
++ writel(1, host->sram_addr + DEKKER_IA_REQ_OFFSET);
++
++ t1 = 100;
++ t2 = 500;
++
++ while (readl(host->sram_addr + DEKKER_SCU_REQ_OFFSET)) {
++ if (readl(host->sram_addr + DEKKER_EMMC_OWNER_OFFSET) !=
++ DEKKER_OWNER_IA) {
++ writel(0, host->sram_addr + DEKKER_IA_REQ_OFFSET);
++ while (t2) {
++ if (readl(host->sram_addr +
++ DEKKER_EMMC_OWNER_OFFSET) ==
++ DEKKER_OWNER_IA)
++ break;
++ mdelay(10);
++ t2--;
++ }
++ if (t2)
++ writel(1, host->sram_addr +
++ DEKKER_IA_REQ_OFFSET);
++ else
++ goto timeout;
++ }
++ /*
++ * if we go to here, that means SCU FW is releasing the
++ * ownership, so we just wait for a short time here.
++ */
++ if (t1) {
++ mdelay(10);
++ t1--;
++ } else
++ goto timeout;
++ }
++
++ pr_debug("Acquire ownership - eMMC owner: %d, IA req: %d, SCU req: %d\n",
++ readl(host->sram_addr + DEKKER_EMMC_OWNER_OFFSET),
++ readl(host->sram_addr + DEKKER_IA_REQ_OFFSET),
++ readl(host->sram_addr + DEKKER_SCU_REQ_OFFSET));
++
++ return (readl(host->sram_addr + DEKKER_EMMC_OWNER_OFFSET) ==
++ DEKKER_OWNER_IA) ? DEKKER_OWNER_SCU : DEKKER_OWNER_IA;
++timeout:
++
++ pr_warn("%s: Timeout to hold eMMC mutex\n", __func__);
++ return -EBUSY;
++}
++
++static int sdhci_mfld_panic_power_on(struct mmc_panic_host *panic_host)
++{
++ int ret;
++ struct mmc_host *mmc;
++ struct sdhci_host *host;
++
++ if (!panic_host)
++ return -ENODEV;
++ mmc = panic_host->mmc;
++ host = panic_host->priv;
++
++ if (host->runtime_suspended) {
++ /*
++ * power host controller
++ */
++ pm_runtime_get_noresume(mmc->parent);
++
++ if (host->ops->power_up_host) {
++ ret = host->ops->power_up_host(host);
++ if (ret)
++ return ret;
++ }
++ sdhci_panic_reinit_host(panic_host);
++ host->runtime_suspended = false;
++ }
++
++ return 0;
++}
++
++static int sdhci_mfld_panic_hold_mutex(struct mmc_panic_host *panic_host)
++{
++ struct sdhci_host *host;
++ int ret;
++
++ if (!panic_host)
++ return -ENODEV;
++
++ host = panic_host->priv;
++
++ ret = sdhci_mfld_panic_acquire_ownership(host);
++
++ if (ret == DEKKER_OWNER_SCU) {
++ if (host->ops->power_up_host) {
++ ret = host->ops->power_up_host(host);
++ if (ret)
++ return ret;
++ }
++ sdhci_panic_reinit_host(panic_host);
++ return 0;
++ } else if (ret == DEKKER_OWNER_IA)
++ return sdhci_mfld_panic_power_on(panic_host);
++
++ return ret;
++}
++
++static void sdhci_mfld_panic_release_mutex(struct mmc_panic_host *panic_host)
++{
++ struct sdhci_host *host;
++
++ if (!panic_host)
++ return;
++ host = panic_host->priv;
++
++ if (!host->sram_addr)
++ return;
++
++ writel(DEKKER_OWNER_SCU,
++ host->sram_addr + DEKKER_EMMC_OWNER_OFFSET);
++ writel(0, host->sram_addr + DEKKER_IA_REQ_OFFSET);
++ DBG("Exit ownership - eMMC owner: %d, IA req: %d, SCU req: %d\n",
++ readl(host->sram_addr + DEKKER_EMMC_OWNER_OFFSET),
++ readl(host->sram_addr + DEKKER_IA_REQ_OFFSET),
++ readl(host->sram_addr + DEKKER_SCU_REQ_OFFSET));
++}
++
++static void sdhci_mfld_panic_prepare(struct mmc_panic_host *panic_host)
++{
++ struct sdhci_host *host;
++
++ if (!panic_host)
++ return;
++ host = panic_host->priv;
++
++ /*
++ * assume host is powered off
++ */
++ host->runtime_suspended = true;
++
++#ifdef CONFIG_PM_RUNTIME
++ /*
++ * disable runtime pm directly
++ */
++ panic_host->mmc->parent->power.disable_depth = 1;
++#endif
++}
++
++static int sdhci_mfld_panic_setup(struct mmc_panic_host *panic_host)
++{
++ struct sdhci_host *host;
++
++ if (!panic_host)
++ return 0;
++
++ host = mmc_priv(panic_host->mmc);
++ panic_host->priv = (void *)host;
++
++ return 0;
++}
++
++const struct mmc_host_panic_ops sdhci_panic_ops = {
++ .request = sdhci_mfld_panic_request,
++ .prepare = sdhci_mfld_panic_prepare,
++ .setup = sdhci_mfld_panic_setup,
++ .set_ios = sdhci_mfld_panic_set_ios,
++ .power_on = sdhci_mfld_panic_power_on,
++ .hold_mutex = sdhci_mfld_panic_hold_mutex,
++ .release_mutex = sdhci_mfld_panic_release_mutex,
++};
++
++void sdhci_alloc_panic_host(struct sdhci_host *host)
++{
++ if (!host->mmc)
++ return;
++ mmc_alloc_panic_host(host->mmc, &sdhci_panic_ops);
++}
++EXPORT_SYMBOL_GPL(sdhci_alloc_panic_host);
++
++
++/*****************************************************************************\
++ * *
++ * Suspend/resume *
++ * *
++\*****************************************************************************/
++
++static void sdhci_set_emmc_state(struct sdhci_host *host, uint32_t state)
++{
++ /* Only if there is dekker mutex available */
++ if (!host->sram_addr)
++ return;
++ writel(state, host->sram_addr + DEKKER_EMMC_STATE);
++}
++
++#ifdef CONFIG_PM
++void sdhci_enable_irq_wakeups(struct sdhci_host *host)
++{
++ u8 val;
++ u8 mask = SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE
++ | SDHCI_WAKE_ON_INT;
++
++ val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL);
++ val |= mask ;
++ /* Avoid fake wake up */
++ if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
++ val &= ~(SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE);
++ sdhci_writeb(host, val, SDHCI_WAKE_UP_CONTROL);
++}
++EXPORT_SYMBOL_GPL(sdhci_enable_irq_wakeups);
++
++void sdhci_disable_irq_wakeups(struct sdhci_host *host)
++{
++ u8 val;
++ u8 mask = SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE
++ | SDHCI_WAKE_ON_INT;
++
++ val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL);
++ val &= ~mask;
++ sdhci_writeb(host, val, SDHCI_WAKE_UP_CONTROL);
++}
++EXPORT_SYMBOL_GPL(sdhci_disable_irq_wakeups);
++
++int sdhci_suspend_host(struct sdhci_host *host)
++{
++ int ret;
++ unsigned long flags;
++
++ if (host->ops->platform_suspend)
++ host->ops->platform_suspend(host);
++
++ sdhci_acquire_ownership(host->mmc);
++
++ sdhci_disable_card_detection(host);
++
++ /* Disable tuning since we are suspending */
++ if (host->flags & SDHCI_USING_RETUNING_TIMER) {
++ del_timer_sync(&host->tuning_timer);
++ host->flags &= ~SDHCI_NEEDS_RETUNING;
++ }
++
++ ret = mmc_suspend_host(host->mmc);
++ if (ret) {
++ if (host->flags & SDHCI_USING_RETUNING_TIMER) {
++ host->flags |= SDHCI_NEEDS_RETUNING;
++ mod_timer(&host->tuning_timer, jiffies +
++ host->tuning_count * HZ);
++ }
++
++ sdhci_enable_card_detection(host);
++
++ goto out;
++ }
++
++ if (!device_may_wakeup(mmc_dev(host->mmc))) {
++ sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
++ free_irq(host->irq, host);
++ } else {
++ sdhci_enable_irq_wakeups(host);
++ enable_irq_wake(host->irq);
++ }
++
++ /* Card succesfully suspended. Tell information to SCU */
++ sdhci_set_emmc_state(host, DEKKER_EMMC_CHIP_SUSPENDED);
++
++ spin_lock_irqsave(&host->lock, flags);
++ host->suspended = true;
++ spin_unlock_irqrestore(&host->lock, flags);
++out:
++ sdhci_release_ownership(host->mmc);
++ return ret;
++}
++
++EXPORT_SYMBOL_GPL(sdhci_suspend_host);
++
++int sdhci_resume_host(struct sdhci_host *host)
++{
++ int ret;
++ unsigned long flags;
++
++ sdhci_acquire_ownership(host->mmc);
++
++ if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
++ if (host->ops->enable_dma)
++ host->ops->enable_dma(host);
+ }
+
+ if (!device_may_wakeup(mmc_dev(host->mmc))) {
+ ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
+ mmc_hostname(host->mmc), host);
+ if (ret)
+- return ret;
++ goto out;
+ } else {
+ sdhci_disable_irq_wakeups(host);
+ disable_irq_wake(host->irq);
+@@ -2596,6 +3756,10 @@ int sdhci_resume_host(struct sdhci_host *host)
+ mmiowb();
+ }
+
++ spin_lock_irqsave(&host->lock, flags);
++ host->suspended = false;
++ spin_unlock_irqrestore(&host->lock, flags);
++
+ ret = mmc_resume_host(host->mmc);
+ sdhci_enable_card_detection(host);
+
+@@ -2606,6 +3770,10 @@ int sdhci_resume_host(struct sdhci_host *host)
+ if (host->flags & SDHCI_USING_RETUNING_TIMER)
+ host->flags |= SDHCI_NEEDS_RETUNING;
+
++ /* Card back in active state */
++ sdhci_set_emmc_state(host, DEKKER_EMMC_CHIP_ACTIVE);
++out:
++ sdhci_release_ownership(host->mmc);
+ return ret;
+ }
+
+@@ -2630,6 +3798,7 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
+ unsigned long flags;
+ int ret = 0;
+
++ sdhci_do_acquire_ownership(host->mmc);
+ /* Disable tuning since we are suspending */
+ if (host->flags & SDHCI_USING_RETUNING_TIMER) {
+ del_timer_sync(&host->tuning_timer);
+@@ -2646,6 +3815,7 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
+ host->runtime_suspended = true;
+ spin_unlock_irqrestore(&host->lock, flags);
+
++ sdhci_release_ownership(host->mmc);
+ return ret;
+ }
+ EXPORT_SYMBOL_GPL(sdhci_runtime_suspend_host);
+@@ -2655,6 +3825,8 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
+ unsigned long flags;
+ int ret = 0, host_flags = host->flags;
+
++ sdhci_do_acquire_ownership(host->mmc);
++
+ if (host_flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
+ if (host->ops->enable_dma)
+ host->ops->enable_dma(host);
+@@ -2692,6 +3864,7 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
++ sdhci_release_ownership(host->mmc);
+ return ret;
+ }
+ EXPORT_SYMBOL_GPL(sdhci_runtime_resume_host);
+@@ -2724,6 +3897,36 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev,
+
+ EXPORT_SYMBOL_GPL(sdhci_alloc_host);
+
++/**
++ * sdhci_pci_request_regulators - try requesting regulator of
++ * a sdhci device
++ *
++ * We take care of race conditions here between sdhci_add_host() (probe)
++ * and platform code that may kick a retry at anytime during boot.
++ */
++int sdhci_try_get_regulator(struct sdhci_host *host)
++{
++ struct regulator *vmmc;
++ unsigned long flags;
++ if (!host->vmmc) {
++ vmmc = regulator_get(mmc_dev(host->mmc), "vmmc");
++ if (!IS_ERR(vmmc)) {
++ spin_lock_irqsave(&host->lock, flags);
++ if (!host->vmmc) {
++ host->vmmc = vmmc;
++ spin_unlock_irqrestore(&host->lock, flags);
++ return 0;
++ } else {
++ /* race! we got the regulator twice */
++ spin_unlock_irqrestore(&host->lock, flags);
++ regulator_put(vmmc);
++ }
++ }
++ }
++ return -EAGAIN;
++}
++EXPORT_SYMBOL_GPL(sdhci_try_get_regulator);
++
+ int sdhci_add_host(struct sdhci_host *host)
+ {
+ struct mmc_host *mmc;
+@@ -2897,6 +4100,8 @@ int sdhci_add_host(struct sdhci_host *host)
+
+ mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
+
++ mmc->caps |= MMC_CAP_POWER_OFF_CARD;
++
+ if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
+ host->flags |= SDHCI_AUTO_CMD12;
+
+@@ -2989,6 +4194,8 @@ int sdhci_add_host(struct sdhci_host *host)
+ /* Initial value for re-tuning timer count */
+ host->tuning_count = (caps[1] & SDHCI_RETUNING_TIMER_COUNT_MASK) >>
+ SDHCI_RETUNING_TIMER_COUNT_SHIFT;
++ if (host->tuning_count == 0 && host->ops->get_tuning_count)
++ host->tuning_count = host->ops->get_tuning_count(host);
+
+ /*
+ * In case Re-tuning Timer is not disabled, the actual value of
+@@ -3002,17 +4209,10 @@ int sdhci_add_host(struct sdhci_host *host)
+ SDHCI_RETUNING_MODE_SHIFT;
+
+ ocr_avail = 0;
+-
+- host->vmmc = regulator_get(mmc_dev(mmc), "vmmc");
+- if (IS_ERR_OR_NULL(host->vmmc)) {
+- if (PTR_ERR(host->vmmc) < 0) {
+- pr_info("%s: no vmmc regulator found\n",
+- mmc_hostname(mmc));
+- host->vmmc = NULL;
+- }
+- }
++ spin_lock_init(&host->lock);
+
+ #ifdef CONFIG_REGULATOR
++ sdhci_try_get_regulator(host);
+ /*
+ * Voltage range check makes sense only if regulator reports
+ * any voltage value.
+@@ -3080,6 +4280,11 @@ int sdhci_add_host(struct sdhci_host *host)
+ SDHCI_MAX_CURRENT_MULTIPLIER;
+ }
+
++ if (host->quirks2 & SDHCI_QUIRK2_ADVERTISE_2V0_FORCE_1V8)
++ ocr_avail |= MMC_VDD_20_21;
++ if (host->quirks2 & SDHCI_QUIRK2_ADVERTISE_3V0_FORCE_1V8)
++ ocr_avail |= MMC_VDD_32_33;
++
+ mmc->ocr_avail = ocr_avail;
+ mmc->ocr_avail_sdio = ocr_avail;
+ if (host->ocr_avail_sdio)
+@@ -3099,8 +4304,6 @@ int sdhci_add_host(struct sdhci_host *host)
+ return -ENODEV;
+ }
+
+- spin_lock_init(&host->lock);
+-
+ /*
+ * Maximum number of segments. Depends on if the hardware
+ * can do scatter/gather or not.
+@@ -3181,6 +4384,7 @@ int sdhci_add_host(struct sdhci_host *host)
+ mmc_hostname(mmc), host->irq, ret);
+ goto untasklet;
+ }
++ sdhci_do_acquire_ownership(mmc);
+
+ sdhci_init(host, 0);
+
+@@ -3189,18 +4393,20 @@ int sdhci_add_host(struct sdhci_host *host)
+ #endif
+
+ #ifdef SDHCI_USE_LEDS_CLASS
+- snprintf(host->led_name, sizeof(host->led_name),
+- "%s::", mmc_hostname(mmc));
+- host->led.name = host->led_name;
+- host->led.brightness = LED_OFF;
+- host->led.default_trigger = mmc_hostname(mmc);
+- host->led.brightness_set = sdhci_led_control;
+-
+- ret = led_classdev_register(mmc_dev(mmc), &host->led);
+- if (ret) {
+- pr_err("%s: Failed to register LED device: %d\n",
+- mmc_hostname(mmc), ret);
+- goto reset;
++ if (mmc->caps2 & MMC_CAP2_LED_SUPPORT) {
++ snprintf(host->led_name, sizeof(host->led_name),
++ "%s::", mmc_hostname(mmc));
++ host->led.name = host->led_name;
++ host->led.brightness = LED_OFF;
++ host->led.default_trigger = mmc_hostname(mmc);
++ host->led.brightness_set = sdhci_led_control;
++
++ ret = led_classdev_register(mmc_dev(mmc), &host->led);
++ if (ret) {
++ pr_err("%s: Failed to register LED device: %d\n",
++ mmc_hostname(mmc), ret);
++ goto reset;
++ }
+ }
+ #endif
+
+@@ -3215,13 +4421,18 @@ int sdhci_add_host(struct sdhci_host *host)
+
+ sdhci_enable_card_detection(host);
+
++ sdhci_release_ownership(mmc);
++
+ return 0;
+
+ #ifdef SDHCI_USE_LEDS_CLASS
+ reset:
+- sdhci_reset(host, SDHCI_RESET_ALL);
+- sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
+- free_irq(host->irq, host);
++ if (mmc->caps2 & MMC_CAP2_LED_SUPPORT) {
++ sdhci_reset(host, SDHCI_RESET_ALL);
++ sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
++ free_irq(host->irq, host);
++ }
++ sdhci_release_ownership(mmc);
+ #endif
+ untasklet:
+ tasklet_kill(&host->card_tasklet);
+@@ -3257,7 +4468,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
+ mmc_remove_host(host->mmc);
+
+ #ifdef SDHCI_USE_LEDS_CLASS
+- led_classdev_unregister(&host->led);
++ if (host->mmc->caps2 & MMC_CAP2_LED_SUPPORT)
++ led_classdev_unregister(&host->led);
+ #endif
+
+ if (!dead)
+diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
+index 379e09d..b7c49ad 100644
+--- a/drivers/mmc/host/sdhci.h
++++ b/drivers/mmc/host/sdhci.h
+@@ -89,6 +89,7 @@
+ #define SDHCI_POWER_180 0x0A
+ #define SDHCI_POWER_300 0x0C
+ #define SDHCI_POWER_330 0x0E
++#define SDHCI_HW_RESET 0x10
+
+ #define SDHCI_BLOCK_GAP_CONTROL 0x2A
+
+@@ -130,6 +131,7 @@
+ #define SDHCI_INT_ERROR 0x00008000
+ #define SDHCI_INT_TIMEOUT 0x00010000
+ #define SDHCI_INT_CRC 0x00020000
++#define SDHCI_INT_CMD_CONFLICT 0x00030000
+ #define SDHCI_INT_END_BIT 0x00040000
+ #define SDHCI_INT_INDEX 0x00080000
+ #define SDHCI_INT_DATA_TIMEOUT 0x00100000
+@@ -160,7 +162,8 @@
+ #define SDHCI_CTRL_UHS_SDR50 0x0002
+ #define SDHCI_CTRL_UHS_SDR104 0x0003
+ #define SDHCI_CTRL_UHS_DDR50 0x0004
+-#define SDHCI_CTRL_HS_SDR200 0x0005 /* reserved value in SDIO spec */
++#define SDHCI_CTRL_HS_SDR200 SDHCI_CTRL_UHS_SDR104
++#define SDHCI_CTRL_HS_DDR200 0x0005
+ #define SDHCI_CTRL_VDD_180 0x0008
+ #define SDHCI_CTRL_DRV_TYPE_MASK 0x0030
+ #define SDHCI_CTRL_DRV_TYPE_B 0x0000
+@@ -234,6 +237,7 @@
+ #define SDHCI_PRESET_FOR_SDR50 0x6A
+ #define SDHCI_PRESET_FOR_SDR104 0x6C
+ #define SDHCI_PRESET_FOR_DDR50 0x6E
++#define SDHCI_PRESET_FOR_HS400 0x74
+ #define SDHCI_PRESET_DRV_MASK 0xC000
+ #define SDHCI_PRESET_DRV_SHIFT 14
+ #define SDHCI_PRESET_CLKGEN_SEL_MASK 0x400
+@@ -294,6 +298,11 @@ struct sdhci_ops {
+ void (*platform_resume)(struct sdhci_host *host);
+ void (*adma_workaround)(struct sdhci_host *host, u32 intmask);
+ void (*platform_init)(struct sdhci_host *host);
++ int (*power_up_host)(struct sdhci_host *host);
++ void (*set_dev_power)(struct sdhci_host *, bool);
++ int (*get_cd)(struct sdhci_host *host);
++ int (*get_tuning_count)(struct sdhci_host *host);
++ int (*gpio_buf_check)(struct sdhci_host *host, unsigned int clk);
+ };
+
+ #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
+@@ -392,6 +401,7 @@ static inline void *sdhci_priv(struct sdhci_host *host)
+ extern void sdhci_card_detect(struct sdhci_host *host);
+ extern int sdhci_add_host(struct sdhci_host *host);
+ extern void sdhci_remove_host(struct sdhci_host *host, int dead);
++extern int sdhci_try_get_regulator(struct sdhci_host *host);
+
+ #ifdef CONFIG_PM
+ extern int sdhci_suspend_host(struct sdhci_host *host);
+@@ -404,4 +414,5 @@ extern int sdhci_runtime_suspend_host(struct sdhci_host *host);
+ extern int sdhci_runtime_resume_host(struct sdhci_host *host);
+ #endif
+
++extern void sdhci_alloc_panic_host(struct sdhci_host *host);
+ #endif /* __SDHCI_HW_H */
+diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
+index f8f0156..83b6a7a 100644
+--- a/drivers/net/wireless/Kconfig
++++ b/drivers/net/wireless/Kconfig
+@@ -264,6 +264,16 @@ config MWL8K
+ To compile this driver as a module, choose M here: the module
+ will be called mwl8k. If unsure, say N.
+
++config WIFI_CONTROL_FUNC
++ bool "Enable WiFi control function abstraction"
++ help
++ Enables Power/Reset/Carddetect function abstraction
++
++config WIFI_PLATFORM_DATA
++ bool "Enable WiFi platform data"
++ ---help---
++ Enables platform_wifi
++
+ source "drivers/net/wireless/ath/Kconfig"
+ source "drivers/net/wireless/b43/Kconfig"
+ source "drivers/net/wireless/b43legacy/Kconfig"
+diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
+index 0c3efcf..5651527 100644
+--- a/drivers/pci/Makefile
++++ b/drivers/pci/Makefile
+@@ -34,6 +34,7 @@ obj-$(CONFIG_PCI_IOV) += iov.o
+ # Some architectures use the generic PCI setup functions
+ #
+ obj-$(CONFIG_X86) += setup-bus.o
++obj-$(CONFIG_ATOM_SOC_POWER) += pci-atom_soc.o
+ obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o
+ obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o
+ obj-$(CONFIG_UNICORE32) += setup-bus.o setup-irq.o
+diff --git a/drivers/pci/pci-atom_soc.c b/drivers/pci/pci-atom_soc.c
+new file mode 100644
+index 0000000..edc3e23
+--- /dev/null
++++ b/drivers/pci/pci-atom_soc.c
+@@ -0,0 +1,78 @@
++/*
++ * pci-atom_soc.c - register Intel MID PCI plaform ops
++ *
++ * Copyright (c) 2013, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include <linux/init.h>
++#include <linux/intel_mid_pm.h>
++#include <linux/kernel.h>
++
++#include "pci.h"
++
++static bool mid_pci_power_manageable(struct pci_dev *dev)
++{
++ return true;
++}
++
++static pci_power_t mid_pci_choose_state(struct pci_dev *pdev)
++{
++ return PCI_D3hot;
++}
++
++static int mid_pci_sleep_wake(struct pci_dev *dev, bool enable)
++{
++ return 0;
++}
++
++static int mid_pci_run_wake(struct pci_dev *dev, bool enable)
++{
++ return 0;
++}
++
++static struct pci_platform_pm_ops mid_pci_platform_pm = {
++ .is_manageable = mid_pci_power_manageable,
++ .choose_state = mid_pci_choose_state,
++ .sleep_wake = mid_pci_sleep_wake,
++ .run_wake = mid_pci_run_wake,
++ .set_state = pmu_pci_set_power_state,
++ .choose_state = pmu_pci_choose_state,
++};
++
++/**
++ * mid_pci_init - It registers callback function for all the PCI devices
++ * for platform specific device power on/shutdown acticities.
++ */
++static int __init mid_pci_init(void)
++{
++ if (boot_cpu_data.x86 != 6)
++ return 0;
++
++ /*
++ * n.b. this model check does not uniquely identify the platform,
++ * and additional checks are necessary inside the pmu driver
++ */
++ switch (boot_cpu_data.x86_model) {
++ case INTEL_ATOM_MFLD:
++ case INTEL_ATOM_CLV:
++ case INTEL_ATOM_MRFLD:
++ pci_set_platform_pm(&mid_pci_platform_pm);
++ break;
++ }
++
++ return 0;
++}
++arch_initcall(mid_pci_init);
+diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
+index a899d8b..83f6c6a 100644
+--- a/drivers/pci/pci.c
++++ b/drivers/pci/pci.c
+@@ -562,8 +562,11 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state)
+ if (state == PCI_D3hot || dev->current_state == PCI_D3hot)
+ pci_dev_d3_sleep(dev);
+ else if (state == PCI_D2 || dev->current_state == PCI_D2)
++#ifdef CONFIG_ATOM_SOC_POWER
++ ; /* On Intel mid platforms pci delays are handled by SCU */
++#else
+ udelay(PCI_PM_D2_DELAY);
+-
++#endif
+ pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
+ dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
+ if (dev->current_state != state && printk_ratelimit())
+diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
+index df4655c..02d48ec 100644
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -3043,7 +3043,11 @@ static int __init pci_apply_final_quirks(void)
+
+ pci_apply_fixup_final_quirks = true;
+ for_each_pci_dev(dev) {
+- pci_fixup_device(pci_fixup_final, dev);
++ if (dev->device==0x119d)
++ printk("Ignore USB EHCI Tanhier (HSIC) since we do not have the driver in the kernel\n");
++ else
++ pci_fixup_device(pci_fixup_final, dev);
++
+ /*
+ * If arch hasn't set it explicitly yet, use the CLS
+ * value shared by all PCI devices. If there's a
+diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
+index 8577261..a1df080 100644
+--- a/drivers/platform/x86/Kconfig
++++ b/drivers/platform/x86/Kconfig
+@@ -651,6 +651,20 @@ config INTEL_SCU_IPC
+ IPC is used to bridge the communications between kernel and SCU on
+ some embedded Intel x86 platforms. This is not needed for PC-type
+ machines.
++choice
++ prompt "IPC access mode"
++ depends on INTEL_SCU_IPC
++ default INTEL_SCU_IPC_INTR_MODE
++ ---help---
++ Select the desired access mode for IPC call.
++
++config INTEL_SCU_IPC_INTR_MODE
++ bool "Intel SCU IPC interrupt mode"
++
++config INTEL_SCU_IPC_POLL_MODE
++ bool "Intel SCU IPC polling mode"
++
++endchoice
+
+ config INTEL_SCU_IPC_UTIL
+ tristate "Intel SCU IPC utility driver"
+@@ -789,4 +803,13 @@ config PVPANIC
+ a paravirtualized device provided by QEMU; it lets a virtual machine
+ (guest) communicate panic events to the host.
+
++config INTEL_SCU_FLIS
++ bool "scu flis driver config"
++ depends on INTEL_SCU_IPC
++ default y
++ help
++ This driver builds the SCU Flis Access Sysfs Interfaces.
++ We could read write the flis address and configure the
++ pin pull up/down using these interfaces.
++
+ endif # X86_PLATFORM_DEVICES
+diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
+index ef0ec74..c075bb2 100644
+--- a/drivers/platform/x86/Makefile
++++ b/drivers/platform/x86/Makefile
+@@ -36,9 +36,9 @@ obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
+ obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
+
+ obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o
+-obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o
++obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o intel_scu_pmic.o intel_scu_mip.o intel_scu_fw_update.o
+ obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o
+-obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
++obj-$(CONFIG_INTEL_SCU_FLIS) += intel_scu_flis.o
+ obj-$(CONFIG_INTEL_IPS) += intel_ips.o
+ obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o
+ obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o
+diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c
+index f59683a..669a254 100644
+--- a/drivers/platform/x86/intel_mid_powerbtn.c
++++ b/drivers/platform/x86/intel_mid_powerbtn.c
+@@ -21,56 +21,98 @@
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
+ #include <linux/slab.h>
++#include <linux/device.h>
+ #include <linux/platform_device.h>
+ #include <linux/input.h>
+-#include <linux/mfd/intel_msic.h>
++#include <linux/io.h>
++#include <linux/rpmsg.h>
++#include <linux/async.h>
++#include <asm/intel_mid_powerbtn.h>
++#include <asm/intel_scu_pmic.h>
++#include <asm/intel_mid_rpmsg.h>
+
+ #define DRIVER_NAME "msic_power_btn"
+
+-#define MSIC_PB_LEVEL (1 << 3) /* 1 - release, 0 - press */
++struct mid_pb_priv {
++ struct input_dev *input;
++ int irq;
++ void __iomem *pb_stat;
++ u16 pb_level;
++ u16 irq_lvl1_mask;
++ bool irq_ack;
++};
+
+-/*
+- * MSIC document ti_datasheet defines the 1st bit reg 0x21 is used to mask
+- * power button interrupt
+- */
+-#define MSIC_PWRBTNM (1 << 0)
++static inline int pb_clear_bits(u16 addr, u8 mask)
++{
++ return intel_scu_ipc_update_register(addr, 0, mask);
++}
+
+-static irqreturn_t mfld_pb_isr(int irq, void *dev_id)
++static irqreturn_t mid_pb_isr(int irq, void *dev_id)
+ {
+- struct input_dev *input = dev_id;
+- int ret;
++ struct mid_pb_priv *priv = dev_id;
+ u8 pbstat;
+
+- ret = intel_msic_reg_read(INTEL_MSIC_PBSTATUS, &pbstat);
+- dev_dbg(input->dev.parent, "PB_INT status= %d\n", pbstat);
++ pbstat = readb(priv->pb_stat);
++ dev_dbg(&priv->input->dev, "pbstat: 0x%x\n", pbstat);
+
+- if (ret < 0) {
+- dev_err(input->dev.parent, "Read error %d while reading"
+- " MSIC_PB_STATUS\n", ret);
+- } else {
+- input_event(input, EV_KEY, KEY_POWER,
+- !(pbstat & MSIC_PB_LEVEL));
+- input_sync(input);
+- }
++ input_event(priv->input, EV_KEY, KEY_POWER, !(pbstat & priv->pb_level));
++ input_sync(priv->input);
++
++ if (pbstat & priv->pb_level)
++ pr_info("[%s] power button released\n", priv->input->name);
++ else
++ pr_info("[%s] power button pressed\n", priv->input->name);
++
++ return IRQ_WAKE_THREAD;
++}
++
++static irqreturn_t mid_pb_threaded_isr(int irq, void *dev_id)
++{
++ struct mid_pb_priv *priv = dev_id;
++
++ if (priv->irq_ack)
++ pb_clear_bits(priv->irq_lvl1_mask, MSIC_PWRBTNM);
+
+ return IRQ_HANDLED;
+ }
+
+-static int mfld_pb_probe(struct platform_device *pdev)
++static int mid_pb_probe(struct platform_device *pdev)
+ {
+ struct input_dev *input;
+- int irq = platform_get_irq(pdev, 0);
+- int error;
++ struct mid_pb_priv *priv;
++ int irq;
++ int ret;
++ struct intel_msic_power_btn_platform_data *pdata;
++
++ if (pdev == NULL)
++ return -ENODEV;
++
++ pdata = pdev->dev.platform_data;
++ if (pdata == NULL) {
++ dev_err(&pdev->dev, "No power button platform data\n");
++ return -EINVAL;
++ }
++
++ dev_info(&pdev->dev, "Probed mid powerbutton devivce\n");
+
++ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return -EINVAL;
+
++ priv = kzalloc(sizeof(struct mid_pb_priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
+ input = input_allocate_device();
+ if (!input) {
+- dev_err(&pdev->dev, "Input device allocation error\n");
++ kfree(priv);
+ return -ENOMEM;
+ }
+
++ priv->input = input;
++ priv->irq = irq;
++ platform_set_drvdata(pdev, priv);
++
+ input->name = pdev->name;
+ input->phys = "power-button/input0";
+ input->id.bustype = BUS_HOST;
+@@ -78,71 +120,159 @@ static int mfld_pb_probe(struct platform_device *pdev)
+
+ input_set_capability(input, EV_KEY, KEY_POWER);
+
+- error = request_threaded_irq(irq, NULL, mfld_pb_isr, IRQF_NO_SUSPEND,
+- DRIVER_NAME, input);
+- if (error) {
+- dev_err(&pdev->dev, "Unable to request irq %d for mfld power"
+- "button\n", irq);
+- goto err_free_input;
++ priv->pb_stat = ioremap(pdata->pbstat, MSIC_PB_LEN);
++ if (!priv->pb_stat) {
++ ret = -ENOMEM;
++ goto fail;
++ }
++
++ ret = input_register_device(input);
++ if (ret) {
++ dev_err(&pdev->dev,
++ "unable to register input dev, error %d\n", ret);
++ goto out_iounmap;
+ }
+
+- error = input_register_device(input);
+- if (error) {
+- dev_err(&pdev->dev, "Unable to register input dev, error "
+- "%d\n", error);
+- goto err_free_irq;
++ priv->pb_level = pdata->pb_level;
++ priv->irq_lvl1_mask = pdata->irq_lvl1_mask;
++
++ /* Unmask the PBIRQ and MPBIRQ on Tangier */
++ if (pdata->irq_ack) {
++ pdata->irq_ack(pdata);
++ priv->irq_ack = true;
+ }
+
+- platform_set_drvdata(pdev, input);
++ ret = request_threaded_irq(priv->irq, mid_pb_isr, mid_pb_threaded_isr,
++ IRQF_NO_SUSPEND, DRIVER_NAME, priv);
+
+- /*
+- * SCU firmware might send power button interrupts to IA core before
++ if (ret) {
++ dev_err(&pdev->dev,
++ "unable to request irq %d for power button\n", irq);
++ goto out_unregister_input;
++ }
++
++ /* SCU firmware might send power button interrupts to IA core before
+ * kernel boots and doesn't get EOI from IA core. The first bit of
+- * MSIC reg 0x21 is kept masked, and SCU firmware doesn't send new
++ * MSIC lvl1 mask reg is kept masked, and SCU firmware doesn't send new
+ * power interrupt to Android kernel. Unmask the bit when probing
+ * power button in kernel.
+- * There is a very narrow race between irq handler and power button
+- * initialization. The race happens rarely. So we needn't worry
+- * about it.
+ */
+- error = intel_msic_reg_update(INTEL_MSIC_IRQLVL1MSK, 0, MSIC_PWRBTNM);
+- if (error) {
+- dev_err(&pdev->dev, "Unable to clear power button interrupt, "
+- "error: %d\n", error);
+- goto err_free_irq;
+- }
++ pb_clear_bits(priv->irq_lvl1_mask, MSIC_PWRBTNM);
+
+ return 0;
+
+-err_free_irq:
+- free_irq(irq, input);
+-err_free_input:
++out_unregister_input:
++ input_unregister_device(input);
++ input = NULL;
++out_iounmap:
++ iounmap(priv->pb_stat);
++fail:
++ platform_set_drvdata(pdev, NULL);
+ input_free_device(input);
+- return error;
++ kfree(priv);
++ return ret;
+ }
+
+-static int mfld_pb_remove(struct platform_device *pdev)
++static int mid_pb_remove(struct platform_device *pdev)
+ {
+- struct input_dev *input = platform_get_drvdata(pdev);
+- int irq = platform_get_irq(pdev, 0);
++ struct mid_pb_priv *priv = platform_get_drvdata(pdev);
+
+- free_irq(irq, input);
+- input_unregister_device(input);
++ iounmap(priv->pb_stat);
++ free_irq(priv->irq, priv);
+ platform_set_drvdata(pdev, NULL);
++ input_unregister_device(priv->input);
++ kfree(priv);
+
+ return 0;
+ }
+
+-static struct platform_driver mfld_pb_driver = {
++static const struct platform_device_id mid_pb_table[] = {
++ {"mid_powerbtn", 1},
++};
++
++static struct platform_driver mid_pb_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+- .probe = mfld_pb_probe,
+- .remove = mfld_pb_remove,
++ .probe = mid_pb_probe,
++ .remove = mid_pb_remove,
++ .id_table = mid_pb_table,
+ };
+
+-module_platform_driver(mfld_pb_driver);
++static int __init mid_pb_module_init(void)
++{
++ return platform_driver_register(&mid_pb_driver);
++}
++
++static void mid_pb_module_exit(void)
++{
++ platform_driver_unregister(&mid_pb_driver);
++}
++
++/* RPMSG related functionality */
++
++static int mid_pb_rpmsg_probe(struct rpmsg_channel *rpdev)
++{
++ int ret = 0;
++ if (rpdev == NULL) {
++ pr_err("rpmsg channel not created\n");
++ ret = -ENODEV;
++ goto out;
++ }
++
++ dev_info(&rpdev->dev, "Probed mid_pb rpmsg device\n");
++
++ ret = mid_pb_module_init();
++out:
++ return ret;
++}
++
++
++static void mid_pb_rpmsg_remove(struct rpmsg_channel *rpdev)
++{
++ mid_pb_module_exit();
++ dev_info(&rpdev->dev, "Removed mid_pb rpmsg device\n");
++}
++
++static void mid_pb_rpmsg_cb(struct rpmsg_channel *rpdev, void *data,
++ int len, void *priv, u32 src)
++{
++ dev_warn(&rpdev->dev, "unexpected, message\n");
++
++ print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
++ data, len, true);
++}
++
++static struct rpmsg_device_id mid_pb_id_table[] = {
++ { .name = "rpmsg_mid_powerbtn" },
++ { },
++};
++MODULE_DEVICE_TABLE(rpmsg, mid_pb_id_table);
++
++
++static struct rpmsg_driver mid_pb_rpmsg_driver = {
++ .drv.name = DRIVER_NAME,
++ .drv.owner = THIS_MODULE,
++ .probe = mid_pb_rpmsg_probe,
++ .callback = mid_pb_rpmsg_cb,
++ .remove = mid_pb_rpmsg_remove,
++ .id_table = mid_pb_id_table,
++};
++
++static int __init mid_pb_rpmsg_init(void)
++{
++ return register_rpmsg_driver(&mid_pb_rpmsg_driver);
++}
++
++static void __exit mid_pb_rpmsg_exit(void)
++{
++ return unregister_rpmsg_driver(&mid_pb_rpmsg_driver);
++}
++
++late_initcall(mid_pb_rpmsg_init);
++
++module_exit(mid_pb_rpmsg_exit);
+
+ MODULE_AUTHOR("Hong Liu <hong.liu@intel.com>");
+ MODULE_DESCRIPTION("Intel Medfield Power Button Driver");
+diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c
+deleted file mode 100644
+index 81c491e..0000000
+--- a/drivers/platform/x86/intel_mid_thermal.c
++++ /dev/null
+@@ -1,574 +0,0 @@
+-/*
+- * intel_mid_thermal.c - Intel MID platform thermal driver
+- *
+- * Copyright (C) 2011 Intel Corporation
+- *
+- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+- *
+- * 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; version 2 of the License.
+- *
+- * This program is distributed in the hope that it will be useful, but
+- * WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- * General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License along
+- * with this program; if not, write to the Free Software Foundation, Inc.,
+- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+- *
+- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+- * Author: Durgadoss R <durgadoss.r@intel.com>
+- */
+-
+-#define pr_fmt(fmt) "intel_mid_thermal: " fmt
+-
+-#include <linux/module.h>
+-#include <linux/init.h>
+-#include <linux/err.h>
+-#include <linux/param.h>
+-#include <linux/device.h>
+-#include <linux/platform_device.h>
+-#include <linux/slab.h>
+-#include <linux/pm.h>
+-#include <linux/thermal.h>
+-#include <linux/mfd/intel_msic.h>
+-
+-/* Number of thermal sensors */
+-#define MSIC_THERMAL_SENSORS 4
+-
+-/* ADC1 - thermal registers */
+-#define MSIC_ADC_ENBL 0x10
+-#define MSIC_ADC_START 0x08
+-
+-#define MSIC_ADCTHERM_ENBL 0x04
+-#define MSIC_ADCRRDATA_ENBL 0x05
+-#define MSIC_CHANL_MASK_VAL 0x0F
+-
+-#define MSIC_STOPBIT_MASK 16
+-#define MSIC_ADCTHERM_MASK 4
+-/* Number of ADC channels */
+-#define ADC_CHANLS_MAX 15
+-#define ADC_LOOP_MAX (ADC_CHANLS_MAX - MSIC_THERMAL_SENSORS)
+-
+-/* ADC channel code values */
+-#define SKIN_SENSOR0_CODE 0x08
+-#define SKIN_SENSOR1_CODE 0x09
+-#define SYS_SENSOR_CODE 0x0A
+-#define MSIC_DIE_SENSOR_CODE 0x03
+-
+-#define SKIN_THERM_SENSOR0 0
+-#define SKIN_THERM_SENSOR1 1
+-#define SYS_THERM_SENSOR2 2
+-#define MSIC_DIE_THERM_SENSOR3 3
+-
+-/* ADC code range */
+-#define ADC_MAX 977
+-#define ADC_MIN 162
+-#define ADC_VAL0C 887
+-#define ADC_VAL20C 720
+-#define ADC_VAL40C 508
+-#define ADC_VAL60C 315
+-
+-/* ADC base addresses */
+-#define ADC_CHNL_START_ADDR INTEL_MSIC_ADC1ADDR0 /* increments by 1 */
+-#define ADC_DATA_START_ADDR INTEL_MSIC_ADC1SNS0H /* increments by 2 */
+-
+-/* MSIC die attributes */
+-#define MSIC_DIE_ADC_MIN 488
+-#define MSIC_DIE_ADC_MAX 1004
+-
+-/* This holds the address of the first free ADC channel,
+- * among the 15 channels
+- */
+-static int channel_index;
+-
+-struct platform_info {
+- struct platform_device *pdev;
+- struct thermal_zone_device *tzd[MSIC_THERMAL_SENSORS];
+-};
+-
+-struct thermal_device_info {
+- unsigned int chnl_addr;
+- int direct;
+- /* This holds the current temperature in millidegree celsius */
+- long curr_temp;
+-};
+-
+-/**
+- * to_msic_die_temp - converts adc_val to msic_die temperature
+- * @adc_val: ADC value to be converted
+- *
+- * Can sleep
+- */
+-static int to_msic_die_temp(uint16_t adc_val)
+-{
+- return (368 * (adc_val) / 1000) - 220;
+-}
+-
+-/**
+- * is_valid_adc - checks whether the adc code is within the defined range
+- * @min: minimum value for the sensor
+- * @max: maximum value for the sensor
+- *
+- * Can sleep
+- */
+-static int is_valid_adc(uint16_t adc_val, uint16_t min, uint16_t max)
+-{
+- return (adc_val >= min) && (adc_val <= max);
+-}
+-
+-/**
+- * adc_to_temp - converts the ADC code to temperature in C
+- * @direct: true if ths channel is direct index
+- * @adc_val: the adc_val that needs to be converted
+- * @tp: temperature return value
+- *
+- * Linear approximation is used to covert the skin adc value into temperature.
+- * This technique is used to avoid very long look-up table to get
+- * the appropriate temp value from ADC value.
+- * The adc code vs sensor temp curve is split into five parts
+- * to achieve very close approximate temp value with less than
+- * 0.5C error
+- */
+-static int adc_to_temp(int direct, uint16_t adc_val, unsigned long *tp)
+-{
+- int temp;
+-
+- /* Direct conversion for die temperature */
+- if (direct) {
+- if (is_valid_adc(adc_val, MSIC_DIE_ADC_MIN, MSIC_DIE_ADC_MAX)) {
+- *tp = to_msic_die_temp(adc_val) * 1000;
+- return 0;
+- }
+- return -ERANGE;
+- }
+-
+- if (!is_valid_adc(adc_val, ADC_MIN, ADC_MAX))
+- return -ERANGE;
+-
+- /* Linear approximation for skin temperature */
+- if (adc_val > ADC_VAL0C)
+- temp = 177 - (adc_val/5);
+- else if ((adc_val <= ADC_VAL0C) && (adc_val > ADC_VAL20C))
+- temp = 111 - (adc_val/8);
+- else if ((adc_val <= ADC_VAL20C) && (adc_val > ADC_VAL40C))
+- temp = 92 - (adc_val/10);
+- else if ((adc_val <= ADC_VAL40C) && (adc_val > ADC_VAL60C))
+- temp = 91 - (adc_val/10);
+- else
+- temp = 112 - (adc_val/6);
+-
+- /* Convert temperature in celsius to milli degree celsius */
+- *tp = temp * 1000;
+- return 0;
+-}
+-
+-/**
+- * mid_read_temp - read sensors for temperature
+- * @temp: holds the current temperature for the sensor after reading
+- *
+- * reads the adc_code from the channel and converts it to real
+- * temperature. The converted value is stored in temp.
+- *
+- * Can sleep
+- */
+-static int mid_read_temp(struct thermal_zone_device *tzd, unsigned long *temp)
+-{
+- struct thermal_device_info *td_info = tzd->devdata;
+- uint16_t adc_val, addr;
+- uint8_t data = 0;
+- int ret;
+- unsigned long curr_temp;
+-
+-
+- addr = td_info->chnl_addr;
+-
+- /* Enable the msic for conversion before reading */
+- ret = intel_msic_reg_write(INTEL_MSIC_ADC1CNTL3, MSIC_ADCRRDATA_ENBL);
+- if (ret)
+- return ret;
+-
+- /* Re-toggle the RRDATARD bit (temporary workaround) */
+- ret = intel_msic_reg_write(INTEL_MSIC_ADC1CNTL3, MSIC_ADCTHERM_ENBL);
+- if (ret)
+- return ret;
+-
+- /* Read the higher bits of data */
+- ret = intel_msic_reg_read(addr, &data);
+- if (ret)
+- return ret;
+-
+- /* Shift bits to accommodate the lower two data bits */
+- adc_val = (data << 2);
+- addr++;
+-
+- ret = intel_msic_reg_read(addr, &data);/* Read lower bits */
+- if (ret)
+- return ret;
+-
+- /* Adding lower two bits to the higher bits */
+- data &= 03;
+- adc_val += data;
+-
+- /* Convert ADC value to temperature */
+- ret = adc_to_temp(td_info->direct, adc_val, &curr_temp);
+- if (ret == 0)
+- *temp = td_info->curr_temp = curr_temp;
+- return ret;
+-}
+-
+-/**
+- * configure_adc - enables/disables the ADC for conversion
+- * @val: zero: disables the ADC non-zero:enables the ADC
+- *
+- * Enable/Disable the ADC depending on the argument
+- *
+- * Can sleep
+- */
+-static int configure_adc(int val)
+-{
+- int ret;
+- uint8_t data;
+-
+- ret = intel_msic_reg_read(INTEL_MSIC_ADC1CNTL1, &data);
+- if (ret)
+- return ret;
+-
+- if (val) {
+- /* Enable and start the ADC */
+- data |= (MSIC_ADC_ENBL | MSIC_ADC_START);
+- } else {
+- /* Just stop the ADC */
+- data &= (~MSIC_ADC_START);
+- }
+- return intel_msic_reg_write(INTEL_MSIC_ADC1CNTL1, data);
+-}
+-
+-/**
+- * set_up_therm_channel - enable thermal channel for conversion
+- * @base_addr: index of free msic ADC channel
+- *
+- * Enable all the three channels for conversion
+- *
+- * Can sleep
+- */
+-static int set_up_therm_channel(u16 base_addr)
+-{
+- int ret;
+-
+- /* Enable all the sensor channels */
+- ret = intel_msic_reg_write(base_addr, SKIN_SENSOR0_CODE);
+- if (ret)
+- return ret;
+-
+- ret = intel_msic_reg_write(base_addr + 1, SKIN_SENSOR1_CODE);
+- if (ret)
+- return ret;
+-
+- ret = intel_msic_reg_write(base_addr + 2, SYS_SENSOR_CODE);
+- if (ret)
+- return ret;
+-
+- /* Since this is the last channel, set the stop bit
+- * to 1 by ORing the DIE_SENSOR_CODE with 0x10 */
+- ret = intel_msic_reg_write(base_addr + 3,
+- (MSIC_DIE_SENSOR_CODE | 0x10));
+- if (ret)
+- return ret;
+-
+- /* Enable ADC and start it */
+- return configure_adc(1);
+-}
+-
+-/**
+- * reset_stopbit - sets the stop bit to 0 on the given channel
+- * @addr: address of the channel
+- *
+- * Can sleep
+- */
+-static int reset_stopbit(uint16_t addr)
+-{
+- int ret;
+- uint8_t data;
+- ret = intel_msic_reg_read(addr, &data);
+- if (ret)
+- return ret;
+- /* Set the stop bit to zero */
+- return intel_msic_reg_write(addr, (data & 0xEF));
+-}
+-
+-/**
+- * find_free_channel - finds an empty channel for conversion
+- *
+- * If the ADC is not enabled then start using 0th channel
+- * itself. Otherwise find an empty channel by looking for a
+- * channel in which the stopbit is set to 1. returns the index
+- * of the first free channel if succeeds or an error code.
+- *
+- * Context: can sleep
+- *
+- * FIXME: Ultimately the channel allocator will move into the intel_scu_ipc
+- * code.
+- */
+-static int find_free_channel(void)
+-{
+- int ret;
+- int i;
+- uint8_t data;
+-
+- /* check whether ADC is enabled */
+- ret = intel_msic_reg_read(INTEL_MSIC_ADC1CNTL1, &data);
+- if (ret)
+- return ret;
+-
+- if ((data & MSIC_ADC_ENBL) == 0)
+- return 0;
+-
+- /* ADC is already enabled; Looking for an empty channel */
+- for (i = 0; i < ADC_CHANLS_MAX; i++) {
+- ret = intel_msic_reg_read(ADC_CHNL_START_ADDR + i, &data);
+- if (ret)
+- return ret;
+-
+- if (data & MSIC_STOPBIT_MASK) {
+- ret = i;
+- break;
+- }
+- }
+- return (ret > ADC_LOOP_MAX) ? (-EINVAL) : ret;
+-}
+-
+-/**
+- * mid_initialize_adc - initializing the ADC
+- * @dev: our device structure
+- *
+- * Initialize the ADC for reading thermistor values. Can sleep.
+- */
+-static int mid_initialize_adc(struct device *dev)
+-{
+- u8 data;
+- u16 base_addr;
+- int ret;
+-
+- /*
+- * Ensure that adctherm is disabled before we
+- * initialize the ADC
+- */
+- ret = intel_msic_reg_read(INTEL_MSIC_ADC1CNTL3, &data);
+- if (ret)
+- return ret;
+-
+- data &= ~MSIC_ADCTHERM_MASK;
+- ret = intel_msic_reg_write(INTEL_MSIC_ADC1CNTL3, data);
+- if (ret)
+- return ret;
+-
+- /* Index of the first channel in which the stop bit is set */
+- channel_index = find_free_channel();
+- if (channel_index < 0) {
+- dev_err(dev, "No free ADC channels");
+- return channel_index;
+- }
+-
+- base_addr = ADC_CHNL_START_ADDR + channel_index;
+-
+- if (!(channel_index == 0 || channel_index == ADC_LOOP_MAX)) {
+- /* Reset stop bit for channels other than 0 and 12 */
+- ret = reset_stopbit(base_addr);
+- if (ret)
+- return ret;
+-
+- /* Index of the first free channel */
+- base_addr++;
+- channel_index++;
+- }
+-
+- ret = set_up_therm_channel(base_addr);
+- if (ret) {
+- dev_err(dev, "unable to enable ADC");
+- return ret;
+- }
+- dev_dbg(dev, "ADC initialization successful");
+- return ret;
+-}
+-
+-/**
+- * initialize_sensor - sets default temp and timer ranges
+- * @index: index of the sensor
+- *
+- * Context: can sleep
+- */
+-static struct thermal_device_info *initialize_sensor(int index)
+-{
+- struct thermal_device_info *td_info =
+- kzalloc(sizeof(struct thermal_device_info), GFP_KERNEL);
+-
+- if (!td_info)
+- return NULL;
+-
+- /* Set the base addr of the channel for this sensor */
+- td_info->chnl_addr = ADC_DATA_START_ADDR + 2 * (channel_index + index);
+- /* Sensor 3 is direct conversion */
+- if (index == 3)
+- td_info->direct = 1;
+- return td_info;
+-}
+-
+-/**
+- * mid_thermal_resume - resume routine
+- * @dev: device structure
+- *
+- * mid thermal resume: re-initializes the adc. Can sleep.
+- */
+-static int mid_thermal_resume(struct device *dev)
+-{
+- return mid_initialize_adc(dev);
+-}
+-
+-/**
+- * mid_thermal_suspend - suspend routine
+- * @dev: device structure
+- *
+- * mid thermal suspend implements the suspend functionality
+- * by stopping the ADC. Can sleep.
+- */
+-static int mid_thermal_suspend(struct device *dev)
+-{
+- /*
+- * This just stops the ADC and does not disable it.
+- * temporary workaround until we have a generic ADC driver.
+- * If 0 is passed, it disables the ADC.
+- */
+- return configure_adc(0);
+-}
+-
+-static SIMPLE_DEV_PM_OPS(mid_thermal_pm,
+- mid_thermal_suspend, mid_thermal_resume);
+-
+-/**
+- * read_curr_temp - reads the current temperature and stores in temp
+- * @temp: holds the current temperature value after reading
+- *
+- * Can sleep
+- */
+-static int read_curr_temp(struct thermal_zone_device *tzd, unsigned long *temp)
+-{
+- WARN_ON(tzd == NULL);
+- return mid_read_temp(tzd, temp);
+-}
+-
+-/* Can't be const */
+-static struct thermal_zone_device_ops tzd_ops = {
+- .get_temp = read_curr_temp,
+-};
+-
+-/**
+- * mid_thermal_probe - mfld thermal initialize
+- * @pdev: platform device structure
+- *
+- * mid thermal probe initializes the hardware and registers
+- * all the sensors with the generic thermal framework. Can sleep.
+- */
+-static int mid_thermal_probe(struct platform_device *pdev)
+-{
+- static char *name[MSIC_THERMAL_SENSORS] = {
+- "skin0", "skin1", "sys", "msicdie"
+- };
+-
+- int ret;
+- int i;
+- struct platform_info *pinfo;
+-
+- pinfo = kzalloc(sizeof(struct platform_info), GFP_KERNEL);
+- if (!pinfo)
+- return -ENOMEM;
+-
+- /* Initializing the hardware */
+- ret = mid_initialize_adc(&pdev->dev);
+- if (ret) {
+- dev_err(&pdev->dev, "ADC init failed");
+- kfree(pinfo);
+- return ret;
+- }
+-
+- /* Register each sensor with the generic thermal framework*/
+- for (i = 0; i < MSIC_THERMAL_SENSORS; i++) {
+- struct thermal_device_info *td_info = initialize_sensor(i);
+-
+- if (!td_info) {
+- ret = -ENOMEM;
+- goto err;
+- }
+- pinfo->tzd[i] = thermal_zone_device_register(name[i],
+- 0, 0, td_info, &tzd_ops, NULL, 0, 0);
+- if (IS_ERR(pinfo->tzd[i])) {
+- kfree(td_info);
+- ret = PTR_ERR(pinfo->tzd[i]);
+- goto err;
+- }
+- }
+-
+- pinfo->pdev = pdev;
+- platform_set_drvdata(pdev, pinfo);
+- return 0;
+-
+-err:
+- while (--i >= 0) {
+- kfree(pinfo->tzd[i]->devdata);
+- thermal_zone_device_unregister(pinfo->tzd[i]);
+- }
+- configure_adc(0);
+- kfree(pinfo);
+- return ret;
+-}
+-
+-/**
+- * mid_thermal_remove - mfld thermal finalize
+- * @dev: platform device structure
+- *
+- * MLFD thermal remove unregisters all the sensors from the generic
+- * thermal framework. Can sleep.
+- */
+-static int mid_thermal_remove(struct platform_device *pdev)
+-{
+- int i;
+- struct platform_info *pinfo = platform_get_drvdata(pdev);
+-
+- for (i = 0; i < MSIC_THERMAL_SENSORS; i++) {
+- kfree(pinfo->tzd[i]->devdata);
+- thermal_zone_device_unregister(pinfo->tzd[i]);
+- }
+-
+- kfree(pinfo);
+- platform_set_drvdata(pdev, NULL);
+-
+- /* Stop the ADC */
+- return configure_adc(0);
+-}
+-
+-#define DRIVER_NAME "msic_thermal"
+-
+-static const struct platform_device_id therm_id_table[] = {
+- { DRIVER_NAME, 1 },
+- { "msic_thermal", 1 },
+- { }
+-};
+-
+-static struct platform_driver mid_thermal_driver = {
+- .driver = {
+- .name = DRIVER_NAME,
+- .owner = THIS_MODULE,
+- .pm = &mid_thermal_pm,
+- },
+- .probe = mid_thermal_probe,
+- .remove = mid_thermal_remove,
+- .id_table = therm_id_table,
+-};
+-
+-module_platform_driver(mid_thermal_driver);
+-
+-MODULE_AUTHOR("Durgadoss R <durgadoss.r@intel.com>");
+-MODULE_DESCRIPTION("Intel Medfield Platform Thermal Driver");
+-MODULE_LICENSE("GPL");
+diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c
+index 6f4b728..c2d271a 100644
+--- a/drivers/platform/x86/intel_pmic_gpio.c
++++ b/drivers/platform/x86/intel_pmic_gpio.c
+@@ -31,7 +31,7 @@
+ #include <linux/init.h>
+ #include <linux/io.h>
+ #include <linux/gpio.h>
+-#include <asm/intel_scu_ipc.h>
++#include <asm/intel_scu_pmic.h>
+ #include <linux/device.h>
+ #include <linux/intel_pmic_gpio.h>
+ #include <linux/platform_device.h>
+diff --git a/drivers/platform/x86/intel_scu_flis.c b/drivers/platform/x86/intel_scu_flis.c
+new file mode 100644
+index 0000000..4dc3598
+--- /dev/null
++++ b/drivers/platform/x86/intel_scu_flis.c
+@@ -0,0 +1,747 @@
++/* intel_scu_flis.c SCU FLIS INTERFACES
++ *
++ * Copyright (c) 2012, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/device.h>
++#include <linux/fs.h>
++#include <linux/rpmsg.h>
++#include <asm/intel-mid.h>
++#include <asm/intel_scu_ipc.h>
++#include <asm/intel_scu_flis.h>
++#include <asm/intel_mid_rpmsg.h>
++#include <asm/intel_mid_remoteproc.h>
++#include <linux/platform_data/intel_mid_remoteproc.h>
++
++static struct rpmsg_instance *flis_instance;
++
++static u32 shim_flis_addr;
++static u32 shim_offset;
++static u32 shim_data;
++static char shim_ops[OPS_STR_LEN];
++
++static u32 param_type; /* flis param type: PULL/PIN DIRECTION/OPEN_DRAIN */
++static u32 param_value; /* value of certain flis param */
++static unsigned int pin_name;
++static char ops[OPS_STR_LEN];
++
++struct intel_scu_flis_info {
++ struct pinstruct_t *pin_t;
++ struct pin_mmio_flis_t *mmio_flis_t;
++ int pin_num;
++ int initialized;
++ void *flis_base;
++ u32 flis_paddr;
++};
++
++static struct intel_scu_flis_info flis_info;
++
++static DEFINE_SPINLOCK(mmio_flis_lock);
++
++u32 get_flis_value(u32 offset)
++{
++ struct intel_scu_flis_info *isfi = &flis_info;
++ u32 __iomem *mem;
++
++ if (!isfi->initialized || !isfi->flis_base)
++ return -ENODEV;
++
++ mem = (void __iomem *)(isfi->flis_base + offset);
++
++ return readl(mem);
++}
++EXPORT_SYMBOL(get_flis_value);
++
++void set_flis_value(u32 value, u32 offset)
++{
++ struct intel_scu_flis_info *isfi = &flis_info;
++ u32 __iomem *mem;
++ unsigned long flags;
++
++ if (!isfi->initialized || !isfi->flis_base)
++ return;
++
++ /*
++ * There is one security region for Merrifield FLIS, which
++ * are read only to OS side. Use IPC when write access is needed.
++ */
++ if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER
++ && offset >= 0x1d00
++ && offset <= 0x1d34) {
++ /* IPC call should not be called in atomic context */
++ might_sleep();
++ rpmsg_send_generic_raw_command(RP_INDIRECT_WRITE, 0,
++ (u8 *)&value, 4,
++ NULL, 0,
++ isfi->flis_paddr + offset, 0);
++
++ } else {
++ mem = (void __iomem *)(isfi->flis_base + offset);
++ spin_lock_irqsave(&mmio_flis_lock, flags);
++ writel(value, mem);
++ spin_unlock_irqrestore(&mmio_flis_lock, flags);
++ }
++}
++EXPORT_SYMBOL(set_flis_value);
++
++/* directly write to flis address */
++int intel_scu_ipc_write_shim(u32 data, u32 flis_addr, u32 offset)
++{
++ int ret;
++ u32 ipc_wbuf[3];
++
++ /* offset 0xff means the flis is reserved, just return 0*/
++ if (offset == 0xFF)
++ return 0;
++
++ ipc_wbuf[0] = flis_addr; /* wbuf[0]: flis address */
++ ipc_wbuf[1] = offset; /* wbuf[1]: register offset */
++ ipc_wbuf[2] = data; /* wbuf[2]: data */
++
++ ret = rpmsg_send_command(flis_instance, IPCMSG_SHIM_CONFIG,
++ IPC_CMD_SHIM_WR, (u8 *)ipc_wbuf, NULL, 12, 0);
++ if (ret)
++ pr_err("%s: failed to write shim, flis addr: 0x%x, offset: 0x%x\n",
++ __func__, flis_addr, offset);
++
++ return ret;
++}
++EXPORT_SYMBOL(intel_scu_ipc_write_shim);
++
++/* directly read from flis address */
++int intel_scu_ipc_read_shim(u32 *data, u32 flis_addr, u32 offset)
++{
++ int ret;
++ u32 ipc_wbuf[2];
++
++ /* offset 0xff means the flis is reserved, just return 0 */
++ if (offset == 0xFF)
++ return 0;
++
++ ipc_wbuf[0] = flis_addr;
++ ipc_wbuf[1] = offset;
++
++ ret = rpmsg_send_command(flis_instance, IPCMSG_SHIM_CONFIG,
++ IPC_CMD_SHIM_RD, (u8 *)ipc_wbuf, data, 8, 1);
++ if (ret)
++ pr_err("%s: failed to read shim, flis addr: 0x%x, offset: 0x%x\n",
++ __func__, flis_addr, offset);
++
++ return ret;
++}
++EXPORT_SYMBOL(intel_scu_ipc_read_shim);
++
++int intel_scu_ipc_update_shim(u32 data, u32 mask, u32 flis_addr, u32 offset)
++{
++ u32 tmp = 0;
++ int ret;
++
++ ret = intel_scu_ipc_read_shim(&tmp, flis_addr, offset);
++ if (ret) {
++ pr_err("read shim failed, addr = 0x%x, off = 0x%x\n",
++ flis_addr, offset);
++ return ret;
++ }
++
++ tmp &= ~mask;
++ tmp |= (data & mask);
++
++ ret = intel_scu_ipc_write_shim(tmp, flis_addr, offset);
++ if (ret) {
++ pr_err("write shim failed, addr = 0x%x, off = 0x%x\n",
++ flis_addr, offset);
++ return ret;
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL(intel_scu_ipc_update_shim);
++
++/**
++ * config_pin_flis -- configure pin mux,
++ * pull direction and strength and open-drain enable.
++ *
++ * @name: pin name
++ * @param: flis param
++ * @val: value to be set
++ *
++ * example:
++ * config pull up/down:
++ * config_pin_flis(i2s_2_clk, PULL, UP_20K);
++ * config_pin_flis(i2s_2_clk, PULL, DOWN_20K);
++ *
++ * config pin mux:
++ * config_pin_flis(i2s_2_clk, MUX, MUX_EN_INPUT_EN);
++ * config_pin_flis(i2s_2_clk, MUX, INPUT_EN);
++ * config_pin_flis(i2s_2_clk, MUX, MUX_EN_OUTPUT_EN);
++ * config_pin_flis(i2s_2_clk, MUX, OUTPUT_EN);
++ *
++ * config pin open-drain:
++ * config_pin_flis(i2s_2_clk, OPEN_DRAIN, OD_ENABLE);
++ * config_pin_flis(i2s_2_clk, OPEN_DRAIN, OD_DISABLE);
++ *
++ */
++int config_pin_flis(unsigned int name, enum flis_param_t param, u32 val)
++{
++ u32 flis_addr, off, data, mask;
++ int ret;
++ int pos;
++ struct intel_scu_flis_info *isfi = &flis_info;
++ struct pin_mmio_flis_t *mmft;
++ u32 old_val;
++
++ if (!isfi->initialized)
++ return -ENODEV;
++
++ if (name < 0 || name >= isfi->pin_num)
++ return -EINVAL;
++
++ if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_CLOVERVIEW) {
++ /* Check if the pin is configurable */
++ if (isfi->pin_t[name].valid == false)
++ return -EINVAL;
++
++ flis_addr = isfi->pin_t[name].bus_address;
++
++ switch (param) {
++ case PULL:
++ off = isfi->pin_t[name].pullup_offset;
++ pos = isfi->pin_t[name].pullup_lsb_pos;
++ mask = (PULL_MASK << pos);
++ break;
++ case MUX:
++ off = isfi->pin_t[name].direction_offset;
++ pos = isfi->pin_t[name].direction_lsb_pos;
++ mask = (MUX_MASK << pos);
++ break;
++ case OPEN_DRAIN:
++ off = isfi->pin_t[name].open_drain_offset;
++ pos = isfi->pin_t[name].open_drain_bit;
++ mask = (OPEN_DRAIN_MASK << pos);
++ break;
++ default:
++ pr_err("Please specify valid flis param\n");
++ return -EINVAL;
++ }
++
++ data = (val << pos);
++ pr_debug("addr = 0x%x, off = 0x%x, pos = %d, mask = 0x%x, data = 0x%x\n",
++ flis_addr, off, pos, mask, data);
++
++ ret = intel_scu_ipc_update_shim(data, mask, flis_addr, off);
++ if (ret) {
++ pr_err("update shim failed\n");
++ return ret;
++ }
++ } else if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER) {
++ mmft = isfi->mmio_flis_t;
++ off = mmft[name].offset;
++
++ /* Check if the FLIS is writable by mmio access */
++ if (!(mmft[name].access_ctrl & writable))
++ return -EINVAL;
++
++ old_val = get_flis_value(off);
++
++ switch (param) {
++ case PULL:
++ mask = PULL_MASK;
++ break;
++ case MUX:
++ mask = MUX_MASK;
++ break;
++ case OPEN_DRAIN:
++ mask = OPEN_DRAIN_MASK;
++ break;
++ default:
++ pr_err("Please specify valid flis param\n");
++ return -EINVAL;
++ }
++
++ set_flis_value((old_val & ~mask) | val, off);
++
++ } else
++ return -EINVAL;
++
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(config_pin_flis);
++
++int get_pin_flis(unsigned int name, enum flis_param_t param, u32 *val)
++{
++ u32 flis_addr, off;
++ u32 data = 0;
++ int ret;
++ int pos;
++ u32 mask;
++ struct intel_scu_flis_info *isfi = &flis_info;
++ struct pin_mmio_flis_t *mmft;
++ u32 old_val;
++
++ if (!isfi->initialized)
++ return -ENODEV;
++
++ if (name < 0 || name >= isfi->pin_num)
++ return -EINVAL;
++
++ if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_CLOVERVIEW) {
++ if (isfi->pin_t[name].valid == false)
++ return -EINVAL;
++
++ flis_addr = isfi->pin_t[name].bus_address;
++
++ switch (param) {
++ case PULL:
++ off = isfi->pin_t[name].pullup_offset;
++ pos = isfi->pin_t[name].pullup_lsb_pos;
++ mask = PULL_MASK;
++ break;
++ case MUX:
++ off = isfi->pin_t[name].direction_offset;
++ pos = isfi->pin_t[name].direction_lsb_pos;
++ mask = MUX_MASK;
++ break;
++ case OPEN_DRAIN:
++ off = isfi->pin_t[name].open_drain_offset;
++ pos = isfi->pin_t[name].open_drain_bit;
++ mask = OPEN_DRAIN_MASK;
++ break;
++ default:
++ pr_err("Please specify valid flis param\n");
++ return -EINVAL;
++ }
++
++ ret = intel_scu_ipc_read_shim(&data, flis_addr, off);
++ if (ret) {
++ pr_err("read shim failed, addr = 0x%x, off = 0x%x\n",
++ flis_addr, off);
++ return ret;
++ }
++
++ *val = (data >> pos) & mask;
++
++ pr_debug("read: data = 0x%x, val = 0x%x\n", data, *val);
++ } else if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER) {
++ mmft = isfi->mmio_flis_t;
++ off = mmft[name].offset;
++
++ old_val = get_flis_value(off);
++
++ switch (param) {
++ case PULL:
++ pos = 4;
++ mask = PULL_MASK;
++ break;
++ case MUX:
++ pos = 12;
++ mask = MUX_MASK;
++ break;
++ case OPEN_DRAIN:
++ pos = 21;
++ mask = OPEN_DRAIN_MASK;
++ break;
++ default:
++ pr_err("Please specify valid flis param\n");
++ return -EINVAL;
++ }
++
++ *val = (old_val & mask) >> pos;
++
++ } else
++ return -EINVAL;
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(get_pin_flis);
++
++static void flis_generic_store(const char *buf, int type)
++{
++ u32 tmp;
++ int ret;
++
++ /* use decimal for pin number */
++ if (type == DBG_PIN_NAME)
++ ret = sscanf(buf, "%d", &tmp);
++ else
++ ret = sscanf(buf, "%x", &tmp);
++
++ if (ret != 1)
++ return;
++
++ switch (type) {
++ case DBG_SHIM_FLIS_ADDR:
++ shim_flis_addr = tmp;
++ break;
++ case DBG_SHIM_OFFSET:
++ shim_offset = tmp;
++ break;
++ case DBG_SHIM_DATA:
++ shim_data = tmp;
++ break;
++ case DBG_PARAM_VAL:
++ param_value = tmp;
++ break;
++ case DBG_PARAM_TYPE:
++ param_type = tmp;
++ break;
++ case DBG_PIN_NAME:
++ pin_name = tmp;
++ break;
++ default:
++ break;
++ }
++}
++
++static ssize_t shim_flis_addr_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ flis_generic_store(buf, DBG_SHIM_FLIS_ADDR);
++ return size;
++}
++
++static ssize_t shim_flis_addr_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "0x%x\n", shim_flis_addr);
++}
++
++static ssize_t shim_offset_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ flis_generic_store(buf, DBG_SHIM_OFFSET);
++ return size;
++}
++
++static ssize_t shim_offset_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "0x%x\n", shim_offset);
++}
++
++static ssize_t shim_data_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ flis_generic_store(buf, DBG_SHIM_DATA);
++ return size;
++}
++
++static ssize_t shim_data_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "0x%x\n", shim_data);
++}
++
++static ssize_t shim_ops_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ int ret;
++
++ memset(shim_ops, 0, sizeof(shim_ops));
++
++ ret = sscanf(buf, "%9s", shim_ops);
++ if (ret != 1)
++ return -EINVAL;
++
++ if (!strncmp("read", shim_ops, OPS_STR_LEN)) {
++ ret = intel_scu_ipc_read_shim(&shim_data, shim_flis_addr,
++ shim_offset);
++ } else if (!strncmp("write", shim_ops, OPS_STR_LEN)) {
++ ret = intel_scu_ipc_write_shim(shim_data, shim_flis_addr,
++ shim_offset);
++ } else {
++ dev_err(dev, "Not supported ops\n");
++ ret = -EINVAL;
++ }
++
++ if (ret) {
++ dev_err(dev, "shim config met error\n");
++ return ret;
++ }
++
++ return size;
++}
++
++static ssize_t param_val_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "0x%x\n", param_value);
++}
++
++static ssize_t param_val_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ flis_generic_store(buf, DBG_PARAM_VAL);
++ return size;
++}
++
++static ssize_t flis_param_type_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", param_type);
++}
++
++static ssize_t flis_param_type_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ flis_generic_store(buf, DBG_PARAM_TYPE);
++ return size;
++}
++
++static ssize_t pinname_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", pin_name);
++}
++
++static ssize_t pinname_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ flis_generic_store(buf, DBG_PIN_NAME);
++ return size;
++}
++
++static ssize_t ops_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ int ret;
++
++ memset(ops, 0, sizeof(ops));
++
++ ret = sscanf(buf, "%9s", ops);
++ if (ret != 1) {
++ dev_err(dev, "input error\n");
++ return -EINVAL;
++ }
++
++ if (!strncmp("get", ops, OPS_STR_LEN))
++ ret = get_pin_flis(pin_name, param_type, &param_value);
++ else if (!strncmp("set", ops, OPS_STR_LEN))
++ ret = config_pin_flis(pin_name, param_type, param_value);
++ else {
++ dev_err(dev, "wrong ops\n");
++ ret = -EINVAL;
++ }
++
++ if (ret) {
++ dev_err(dev, "Access flis error, ret = %d\n", ret);
++ return ret;
++ }
++
++ return size;
++}
++
++static DEVICE_ATTR(flis_addr, S_IRUGO|S_IWUSR,
++ shim_flis_addr_show, shim_flis_addr_store);
++static DEVICE_ATTR(offset, S_IRUGO|S_IWUSR,
++ shim_offset_show, shim_offset_store);
++static DEVICE_ATTR(data, S_IRUGO|S_IWUSR, shim_data_show, shim_data_store);
++static DEVICE_ATTR(flis_ops, S_IWUSR, NULL, shim_ops_store);
++
++static struct attribute *flis_attrs[] = {
++ &dev_attr_flis_addr.attr,
++ &dev_attr_offset.attr,
++ &dev_attr_data.attr,
++ &dev_attr_flis_ops.attr,
++ NULL,
++};
++
++static struct attribute_group flis_attr_group = {
++ .name = "flis_debug",
++ .attrs = flis_attrs,
++};
++
++static DEVICE_ATTR(pin_name, S_IRUGO|S_IWUSR, pinname_show, pinname_store);
++static DEVICE_ATTR(flis_param, S_IRUGO|S_IWUSR, flis_param_type_show,
++ flis_param_type_store);
++static DEVICE_ATTR(val, S_IRUGO|S_IWUSR, param_val_show, param_val_store);
++static DEVICE_ATTR(ops, S_IWUSR, NULL, ops_store);
++
++static struct attribute *pin_config_attrs[] = {
++ &dev_attr_pin_name.attr,
++ &dev_attr_flis_param.attr,
++ &dev_attr_val.attr,
++ &dev_attr_ops.attr,
++ NULL,
++};
++
++static struct attribute_group pin_config_attr_group = {
++ .name = "pin_config_debug",
++ .attrs = pin_config_attrs,
++};
++
++static int scu_flis_probe(struct platform_device *pdev)
++{
++ int ret;
++ struct intel_scu_flis_info *isfi = &flis_info;
++ struct intel_scu_flis_platform_data *pdata = pdev->dev.platform_data;
++
++ if (!pdata) {
++ dev_err(&pdev->dev, "No platform data\n");
++ ret = -EINVAL;
++ goto out;
++ }
++
++ isfi->pin_t = pdata->pin_t;
++ isfi->pin_num = pdata->pin_num;
++ isfi->mmio_flis_t = pdata->mmio_flis_t;
++ if (pdata->mmio_flis_t && pdata->flis_base) {
++ isfi->flis_paddr = pdata->flis_base;
++ isfi->flis_base = ioremap_nocache(pdata->flis_base,
++ pdata->flis_len);
++ if (!isfi->flis_base) {
++ dev_err(&pdev->dev, "error mapping flis base\n");
++ ret = -EFAULT;
++ goto out;
++ }
++ }
++
++ if ((isfi->pin_t || isfi->mmio_flis_t)&&isfi->pin_num)
++ isfi->initialized = 1;
++
++ ret = sysfs_create_group(&pdev->dev.kobj, &flis_attr_group);
++ if (ret) {
++ dev_err(&pdev->dev, "Failed to create flis sysfs interface\n");
++ goto err1;
++ }
++
++ ret = sysfs_create_group(&pdev->dev.kobj, &pin_config_attr_group);
++ if (ret) {
++ dev_err(&pdev->dev,
++ "Failed to create pin config sysfs interface\n");
++ goto err2;
++ }
++
++ dev_info(&pdev->dev, "scu flis probed\n");
++ return 0;
++
++err2:
++ sysfs_remove_group(&pdev->dev.kobj, &flis_attr_group);
++err1:
++ if (pdata->flis_base)
++ iounmap(isfi->flis_base);
++out:
++ isfi->initialized = 0;
++ return ret;
++}
++
++static int scu_flis_remove(struct platform_device *pdev)
++{
++ sysfs_remove_group(&pdev->dev.kobj, &pin_config_attr_group);
++ sysfs_remove_group(&pdev->dev.kobj, &flis_attr_group);
++
++ return 0;
++}
++
++static struct platform_driver scu_flis_driver = {
++ .driver = {
++ .name = "intel_scu_flis",
++ .owner = THIS_MODULE,
++ },
++ .probe = scu_flis_probe,
++ .remove = scu_flis_remove,
++};
++
++static int scu_flis_module_init(void)
++{
++ return platform_driver_register(&scu_flis_driver);
++}
++
++static void scu_flis_module_exit(void)
++{
++ platform_driver_unregister(&scu_flis_driver);
++}
++
++static int flis_rpmsg_probe(struct rpmsg_channel *rpdev)
++{
++ int ret = 0;
++
++ if (rpdev == NULL) {
++ pr_err("rpmsg channel not created\n");
++ ret = -ENODEV;
++ goto out;
++ }
++
++ dev_info(&rpdev->dev, "Probed flis rpmsg device\n");
++
++ /* Allocate rpmsg instance for flis*/
++ ret = alloc_rpmsg_instance(rpdev, &flis_instance);
++ if (!flis_instance) {
++ dev_err(&rpdev->dev, "kzalloc flis instance failed\n");
++ goto out;
++ }
++
++ /* Initialize rpmsg instance */
++ init_rpmsg_instance(flis_instance);
++
++ ret = scu_flis_module_init();
++ if (ret)
++ free_rpmsg_instance(rpdev, &flis_instance);
++
++out:
++ return ret;
++}
++
++static void flis_rpmsg_remove(struct rpmsg_channel *rpdev)
++{
++ scu_flis_module_exit();
++ free_rpmsg_instance(rpdev, &flis_instance);
++ dev_info(&rpdev->dev, "Removed flis rpmsg device\n");
++}
++
++static void flis_rpmsg_cb(struct rpmsg_channel *rpdev, void *data,
++ int len, void *priv, u32 src)
++{
++ dev_warn(&rpdev->dev, "unexpected, message\n");
++
++ print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
++ data, len, true);
++}
++
++static struct rpmsg_device_id flis_rpmsg_id_table[] = {
++ { .name = "rpmsg_flis" },
++ { },
++};
++MODULE_DEVICE_TABLE(rpmsg, flis_rpmsg_id_table);
++
++static struct rpmsg_driver flis_rpmsg = {
++ .drv.name = KBUILD_MODNAME,
++ .drv.owner = THIS_MODULE,
++ .id_table = flis_rpmsg_id_table,
++ .probe = flis_rpmsg_probe,
++ .callback = flis_rpmsg_cb,
++ .remove = flis_rpmsg_remove,
++};
++
++static int __init flis_rpmsg_init(void)
++{
++ return register_rpmsg_driver(&flis_rpmsg);
++}
++
++static void __exit flis_rpmsg_exit(void)
++{
++ return unregister_rpmsg_driver(&flis_rpmsg);
++}
++
++fs_initcall(flis_rpmsg_init);
++module_exit(flis_rpmsg_exit);
++
++MODULE_AUTHOR("Ning Li <ning.li@intel.com>");
++MODULE_DESCRIPTION("Intel FLIS Access Driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/platform/x86/intel_scu_fw_update.c b/drivers/platform/x86/intel_scu_fw_update.c
+new file mode 100644
+index 0000000..59f8c7f
+--- /dev/null
++++ b/drivers/platform/x86/intel_scu_fw_update.c
+@@ -0,0 +1,1087 @@
++/*
++ * fw_update.c - Intel SCU Firmware Update Driver
++ *
++ * Copyright (C) 2012 Intel Corporation
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * 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; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/io.h>
++#include <linux/delay.h>
++#include <linux/fs.h>
++#include <linux/vmalloc.h>
++#include <linux/rpmsg.h>
++#include <linux/intel_mid_pm.h>
++#include <asm/intel_scu_ipc.h>
++#include <asm/intel_mid_rpmsg.h>
++#include <asm/intel-mid.h>
++
++/* Medfield & Cloverview firmware update.
++ * The flow and communication between IA and SCU has changed for
++ * Medfield firmware update. For more details, please refer to
++ * Firmware Arch Spec.
++ * Below macros and structs apply for medfield firmware update
++ */
++
++#define IPC_CMD_FW_UPDATE_GO 0x02
++
++#define MAX_FW_CHUNK (128*1024)
++#define IFWX_CHUNK_SIZE (96*1024)
++
++#define SRAM_ADDR 0xFFFC0000
++#define MAILBOX_ADDR 0xFFFE0000
++
++#define SCU_FLAG_OFFSET 8
++#define IA_FLAG_OFFSET 12
++
++#define MIP_HEADER_OFFSET 0
++#define SUCP_OFFSET 0x1D8000
++#define VEDFW_OFFSET 0x1A6000
++
++#define DNX_HDR_LEN 24
++#define FUPH_HDR_LEN 36
++
++#define DNX_IMAGE "DXBL"
++#define FUPH_HDR_SIZE "RUPHS"
++#define FUPH "RUPH"
++#define MIP "DMIP"
++#define IFWI "IFW"
++#define LOWER_128K "LOFW"
++#define UPPER_128K "HIFW"
++#define PSFW1 "PSFW1"
++#define PSFW2 "PSFW2"
++#define SSFW "SSFW"
++#define SUCP "SuCP"
++#define VEDFW "VEDFW"
++#define UPDATE_DONE "HLT$"
++#define UPDATE_ABORT "HLT0"
++#define UPDATE_ERROR "ER"
++
++#define MAX_LEN_IFW 4
++#define MAX_LEN_PSFW 7
++#define MAX_LEN_SSFW 6
++#define MAX_LEN_SUCP 6
++#define MAX_LEN_VEDFW 7
++
++#define FUPH_MIP_OFFSET 0x04
++#define FUPH_IFWI_OFFSET 0x08
++#define FUPH_PSFW1_OFFSET 0x0c
++#define FUPH_PSFW2_OFFSET 0x10
++#define FUPH_SSFW_OFFSET 0x14
++#define FUPH_SUCP_OFFSET 0x18
++#define FUPH_VEDFW_OFFSET 0x1c
++
++#define DNX_MAX_SIZE (128*1024)
++#define IFWI_MAX_SIZE (3*1024*1024)
++#define FOTA_MEM_SIZE (4*1024*1024)
++
++#define DNX_SIZE_OFFSET 0
++#define GP_FLAG_OFFSET 4
++#define XOR_CHK_OFFSET 20
++
++#define GPF_BIT32 1
++#define FUPH_STR "UPH$"
++#define FUPH_MAX_LEN 36
++#define SKIP_BYTES 8
++
++static struct kobject *scu_fw_update_kobj;
++static struct rpmsg_instance *fw_update_instance;
++
++/* Modified IA-SCU mailbox for medfield firmware update. */
++struct ia_scu_mailbox {
++ char mail[8];
++ u32 scu_flag;
++ u32 ia_flag;
++};
++
++/* Structure to parse input from firmware-update application. */
++struct fw_ud {
++ u8 *fw_file_data;
++ u32 fsize;
++ u8 *dnx_hdr;
++ u8 *dnx_file_data;
++ u32 dnx_size;
++ u32 fuph_hdr_len;
++};
++
++struct mfld_fw_update {
++ void __iomem *sram;
++ void __iomem *mailbox;
++ u32 wscu;
++ u32 wia;
++ char mb_status[8];
++};
++
++/* Holds size parameters read from fuph header */
++struct fuph_hdr_attrs {
++ u32 mip_size;
++ u32 ifwi_size;
++ u32 psfw1_size;
++ u32 psfw2_size;
++ u32 ssfw_size;
++ u32 sucp_size;
++ u32 vedfw_size;
++};
++
++enum mailbox_status {
++ MB_DONE,
++ MB_CONTINUE,
++ MB_ERROR
++};
++
++/* Misc. firmware components that are part of integrated firmware */
++struct misc_fw {
++ const char *fw_type;
++ u8 str_len;
++};
++
++/* lock used to prevent multiple calls to fw update sysfs interface */
++static DEFINE_MUTEX(fwud_lock);
++
++static char err_buf[50];
++static u8 *pending_data;
++
++struct fw_update_info {
++ struct device *dev;
++ struct fw_ud *fwud_pending;
++};
++
++static struct fw_update_info fui;
++
++static struct misc_fw misc_fw_table[] = {
++ { .fw_type = IFWI, .str_len = MAX_LEN_IFW },
++ { .fw_type = PSFW1, .str_len = MAX_LEN_PSFW },
++ { .fw_type = SSFW, .str_len = MAX_LEN_SSFW },
++ { .fw_type = PSFW2, .str_len = MAX_LEN_PSFW },
++ { .fw_type = SUCP, .str_len = MAX_LEN_SUCP },
++ { .fw_type = VEDFW, .str_len = MAX_LEN_VEDFW }
++};
++
++static int alloc_fota_mem_early;
++
++int __init alloc_mem_fota_early_flag(char *p)
++{
++ alloc_fota_mem_early = 1;
++ return 0;
++}
++early_param("alloc_fota_mem_early", alloc_mem_fota_early_flag);
++
++/*
++ * IA will wait in busy-state, and poll mailbox, to check
++ * if SCU is done processing.
++ * If it has to wait for more than a second, it will exit with
++ * error code.
++ */
++static int busy_wait(struct mfld_fw_update *mfld_fw_upd)
++{
++ u32 count = 0;
++ u32 flag;
++
++ flag = mfld_fw_upd->wscu;
++
++ while (ioread32(mfld_fw_upd->mailbox + SCU_FLAG_OFFSET) != flag
++ && count < 500) {
++ /* There are synchronization issues between IA and SCU */
++ mb();
++ /* FIXME: we must use mdelay currently */
++ mdelay(10);
++ count++;
++ }
++
++ if (ioread32(mfld_fw_upd->mailbox + SCU_FLAG_OFFSET) != flag) {
++ dev_err(fui.dev, "IA-waited and quitting\n");
++ return -ETIMEDOUT;
++ }
++
++ return 0;
++}
++
++/* This function will
++ * 1)copy firmware chunk from user-space to kernel-space.
++ * 2) Copy from kernel-space to shared SRAM.
++ * 3) Write to mailbox.
++ * 4) And wait for SCU to process that firmware chunk.
++ * Returns 0 on success, and < 0 for failure.
++ */
++static int process_fw_chunk(u8 *fws, u8 *userptr, u32 chunklen,
++ struct mfld_fw_update *mfld_fw_upd)
++{
++ memcpy(fws, userptr, chunklen);
++
++ /* IA copy to sram */
++ memcpy_toio(mfld_fw_upd->sram, fws, chunklen);
++
++ /* There are synchronization issues between IA and SCU */
++ mb();
++ mfld_fw_upd->wia = !(mfld_fw_upd->wia);
++ iowrite32(mfld_fw_upd->wia, mfld_fw_upd->mailbox + IA_FLAG_OFFSET);
++
++ mb();
++ dev_dbg(fui.dev, "wrote ia_flag=%d\n",
++ ioread32(mfld_fw_upd->mailbox + IA_FLAG_OFFSET));
++
++ mfld_fw_upd->wscu = !mfld_fw_upd->wscu;
++ return busy_wait(mfld_fw_upd);
++}
++
++/*
++ * This function will check mailbox status flag, and return state of mailbox.
++ */
++static enum mailbox_status check_mb_status(struct mfld_fw_update *mfld_fw_upd)
++{
++
++ enum mailbox_status mb_state;
++
++ /* There are synchronization issues between IA and SCU */
++ mb();
++
++ memcpy_fromio(mfld_fw_upd->mb_status, mfld_fw_upd->mailbox, 8);
++
++ if (!strncmp(mfld_fw_upd->mb_status, UPDATE_ERROR,
++ sizeof(UPDATE_ERROR) - 1) ||
++ !strncmp(mfld_fw_upd->mb_status, UPDATE_ABORT,
++ sizeof(UPDATE_ABORT) - 1)) {
++ dev_dbg(fui.dev,
++ "mailbox error=%s\n", mfld_fw_upd->mb_status);
++ return MB_ERROR;
++ } else {
++ mb_state = (!strncmp(mfld_fw_upd->mb_status, UPDATE_DONE,
++ sizeof(UPDATE_DONE) - 1)) ? MB_DONE : MB_CONTINUE;
++ dev_dbg(fui.dev,
++ "mailbox pass=%s, mb_state=%d\n",
++ mfld_fw_upd->mb_status, mb_state);
++ }
++
++ return mb_state;
++}
++
++/* Helper function used to calculate length and offset. */
++int helper_for_calc_offset_length(struct fw_ud *fw_ud_ptr, char *scu_req,
++ void **offset, u32 *len, struct fuph_hdr_attrs *fuph,
++ const char *fw_type)
++{
++ unsigned long chunk_no;
++ u32 chunk_rem;
++ u32 max_chunk_cnt;
++ u32 fw_size;
++ u32 fw_offset;
++ u32 max_fw_chunk_size = MAX_FW_CHUNK;
++
++ if (!strncmp(fw_type, IFWI, strlen(IFWI))) {
++
++ if (kstrtoul(scu_req + strlen(IFWI), 10, &chunk_no) < 0)
++ return -EINVAL;
++
++ /* On CTP, IFWx starts from IFW1, not IFW0, thus adjust the
++ * chunk_no to make '*offset' point to the correct address.
++ * Besides, the size of each IFWx chunk is 96k, not 128k
++ */
++ chunk_no = chunk_no - 1;
++ fw_size = fuph->ifwi_size;
++ fw_offset = fuph->mip_size;
++ max_fw_chunk_size = IFWX_CHUNK_SIZE;
++ } else if (!strncmp(fw_type, PSFW1, strlen(PSFW1))) {
++
++ if (kstrtoul(scu_req + strlen(PSFW1), 10, &chunk_no) < 0)
++ return -EINVAL;
++
++ fw_size = fuph->psfw1_size;
++ fw_offset = fuph->mip_size + fuph->ifwi_size;
++ } else if (!strncmp(fw_type, PSFW2, strlen(PSFW2))) {
++
++ if (kstrtoul(scu_req + strlen(PSFW2), 10, &chunk_no) < 0)
++ return -EINVAL;
++
++ fw_size = fuph->psfw2_size;
++ fw_offset = fuph->mip_size + fuph->ifwi_size +
++ fuph->psfw1_size + fuph->ssfw_size;
++ } else if (!strncmp(fw_type, SSFW, strlen(SSFW))) {
++
++ if (kstrtoul(scu_req + strlen(SSFW), 10, &chunk_no) < 0)
++ return -EINVAL;
++
++ fw_size = fuph->ssfw_size;
++ fw_offset = fuph->mip_size + fuph->ifwi_size +
++ fuph->psfw1_size;
++ } else if (!strncmp(fw_type, SUCP, strlen(SUCP))) {
++
++ if (kstrtoul(scu_req + strlen(SUCP), 10, &chunk_no) < 0)
++ return -EINVAL;
++
++ fw_size = fuph->sucp_size;
++ fw_offset = SUCP_OFFSET;
++ } else if (!strncmp(fw_type, VEDFW, strlen(VEDFW))) {
++
++ if (kstrtoul(scu_req + strlen(VEDFW), 10, &chunk_no) < 0)
++ return -EINVAL;
++
++ fw_size = fuph->vedfw_size;
++ fw_offset = VEDFW_OFFSET;
++ } else
++ return -EINVAL;
++
++ chunk_rem = fw_size % max_fw_chunk_size;
++ max_chunk_cnt = (fw_size/max_fw_chunk_size) + (chunk_rem ? 1 : 0);
++
++ dev_dbg(fui.dev,
++ "str=%s,chunk_no=%lx, chunk_rem=%d,max_chunk_cnt=%d\n",
++ fw_type, chunk_no, chunk_rem, max_chunk_cnt);
++
++ if ((chunk_no + 1) > max_chunk_cnt)
++ return -EINVAL;
++
++ /* Note::Logic below will make sure, that we get right length if input
++ is 128K or multiple. */
++ *len = (chunk_no == (max_chunk_cnt - 1)) ?
++ (chunk_rem ? chunk_rem : max_fw_chunk_size) : max_fw_chunk_size;
++
++ *offset = fw_ud_ptr->fw_file_data + fw_offset +
++ chunk_no * max_fw_chunk_size;
++
++ return 0;
++}
++
++/*
++ * This api calculates offset and length depending on type of firmware chunk
++ * requested by SCU. Note: Intent is to follow the architecture such that,
++ * SCU controls the flow, and IA simply hands out, what is requested by SCU.
++ * IA will simply follow SCU's commands, unless SCU requests for something
++ * IA cannot give. TODO:That will be a special error case, need to figure out
++ * how to handle that.
++ */
++int calc_offset_and_length(struct fw_ud *fw_ud_ptr, char *scu_req,
++ void **offset, u32 *len, struct fuph_hdr_attrs *fuph)
++{
++ u8 cnt;
++
++ if (!strncmp(DNX_IMAGE, scu_req, strlen(scu_req))) {
++ *offset = fw_ud_ptr->dnx_file_data;
++ *len = fw_ud_ptr->dnx_size;
++ return 0;
++ } else if (!strncmp(FUPH, scu_req, strlen(scu_req))) {
++ *offset = fw_ud_ptr->fw_file_data + fw_ud_ptr->fsize
++ - fw_ud_ptr->fuph_hdr_len;
++ *len = fw_ud_ptr->fuph_hdr_len;
++ return 0;
++ } else if (!strncmp(MIP, scu_req, strlen(scu_req))) {
++ *offset = fw_ud_ptr->fw_file_data + MIP_HEADER_OFFSET;
++ *len = fuph->mip_size;
++ return 0;
++ } else if (!strncmp(LOWER_128K, scu_req, strlen(scu_req))) {
++ *offset = fw_ud_ptr->fw_file_data + fuph->mip_size;
++ *len = MAX_FW_CHUNK;
++ return 0;
++ } else if (!strncmp(UPPER_128K, scu_req, strlen(scu_req))) {
++ *offset = fw_ud_ptr->fw_file_data
++ + fuph->mip_size + MAX_FW_CHUNK;
++ *len = MAX_FW_CHUNK;
++ return 0;
++ } else {
++ for (cnt = 0; cnt < ARRAY_SIZE(misc_fw_table); cnt++) {
++
++ if (!strncmp(misc_fw_table[cnt].fw_type, scu_req,
++ strlen(misc_fw_table[cnt].fw_type))) {
++
++ if (strlen(scu_req) ==
++ misc_fw_table[cnt].str_len) {
++
++ if (helper_for_calc_offset_length
++ (fw_ud_ptr, scu_req,
++ offset, len, fuph,
++ misc_fw_table[cnt].fw_type) < 0)
++ goto error_case;
++
++ dev_dbg(fui.dev,
++ "\nmisc fw type=%s, len=%d,offset=%d",
++ misc_fw_table[cnt].fw_type, *len,
++ (int)*offset);
++
++ return 0;
++
++ } else
++ goto error_case;
++ }
++ }
++
++ }
++
++ dev_dbg(fui.dev, "Unexpected mailbox request from scu\n");
++
++error_case:
++ /* TODO::Need to test this error case..and see how SCU reacts
++ * and how IA handles
++ * subsequent error response and whether exit is graceful...
++ */
++
++ dev_dbg(fui.dev, "error case,respond back to SCU..\n");
++ dev_dbg(fui.dev, "scu_req=%s\n", scu_req);
++ *len = 0;
++ *offset = 0;
++
++ return -EINVAL;
++}
++
++/**
++ * intel_scu_ipc_medfw_upgrade - Medfield Firmware update utility
++ *
++ * The flow and communication between IA and SCU has changed for
++ * Medfield firmware update. So we have a different api below
++ * to support Medfield firmware update.
++ *
++ * On success returns 0, for failure , returns < 0.
++ */
++static int intel_scu_ipc_medfw_upgrade(void)
++{
++ struct fw_ud *fw_ud_param = fui.fwud_pending;
++ struct mfld_fw_update mfld_fw_upd;
++ u8 *fw_file_data = NULL;
++ u8 *fws = NULL;
++ u8 *fuph_start = NULL;
++ int ret_val = 0;
++
++ struct fuph_hdr_attrs fuph;
++ u32 length = 0;
++ void *offset;
++ enum mailbox_status mb_state;
++
++ /* set all devices in d0i0 before IFWI upgrade */
++ if (unlikely(pmu_set_devices_in_d0i0())) {
++ pr_debug("pmu: failed to set all devices in d0i0...\n");
++ BUG();
++ }
++
++ rpmsg_global_lock();
++ mfld_fw_upd.wscu = 0;
++ mfld_fw_upd.wia = 0;
++ memset(mfld_fw_upd.mb_status, 0, sizeof(char) * 8);
++
++ fw_file_data = fw_ud_param->fw_file_data;
++ mfld_fw_upd.sram = ioremap_nocache(SRAM_ADDR, MAX_FW_CHUNK);
++ if (mfld_fw_upd.sram == NULL) {
++ dev_err(fui.dev, "unable to map sram\n");
++ ret_val = -ENOMEM;
++ goto out_unlock;
++ }
++
++ mfld_fw_upd.mailbox = ioremap_nocache(MAILBOX_ADDR,
++ sizeof(struct ia_scu_mailbox));
++
++ if (mfld_fw_upd.mailbox == NULL) {
++ dev_err(fui.dev, "unable to map the mailbox\n");
++ ret_val = -ENOMEM;
++ goto unmap_sram;
++ }
++
++ /*IA initializes both IAFlag and SCUFlag to zero */
++ iowrite32(0, mfld_fw_upd.mailbox + SCU_FLAG_OFFSET);
++ iowrite32(0, mfld_fw_upd.mailbox + IA_FLAG_OFFSET);
++ memset_io(mfld_fw_upd.mailbox, 0, 8);
++
++ fws = kmalloc(MAX_FW_CHUNK, GFP_KERNEL);
++ if (fws == NULL) {
++ ret_val = -ENOMEM;
++ goto unmap_mb;
++ }
++
++ /* fuph header start */
++ fuph_start = fw_ud_param->fw_file_data + (fw_ud_param->fsize - 1)
++ - (fw_ud_param->fuph_hdr_len - 1);
++
++ /* Convert sizes in DWORDS to number of bytes. */
++ fuph.mip_size = (*((u32 *)(fuph_start + FUPH_MIP_OFFSET)))*4;
++ fuph.ifwi_size = (*((u32 *)(fuph_start + FUPH_IFWI_OFFSET)))*4;
++ fuph.psfw1_size = (*((u32 *)(fuph_start + FUPH_PSFW1_OFFSET)))*4;
++ fuph.psfw2_size = (*((u32 *)(fuph_start + FUPH_PSFW2_OFFSET)))*4;
++ fuph.ssfw_size = (*((u32 *)(fuph_start + FUPH_SSFW_OFFSET)))*4;
++ fuph.sucp_size = (*((u32 *)(fuph_start + FUPH_SUCP_OFFSET)))*4;
++
++ if (fw_ud_param->fuph_hdr_len == FUPH_HDR_LEN) {
++ fuph.vedfw_size =
++ (*((u32 *)(fuph_start + FUPH_VEDFW_OFFSET)))*4;
++ } else
++ fuph.vedfw_size = 0;
++
++ dev_dbg(fui.dev,
++ "ln=%d, mi=%d, if=%d, ps1=%d, ps2=%d, sfw=%d, sucp=%d, vd=%d\n",
++ fw_ud_param->fuph_hdr_len, fuph.mip_size, fuph.ifwi_size,
++ fuph.psfw1_size, fuph.psfw2_size, fuph.ssfw_size,
++ fuph.sucp_size, fuph.vedfw_size);
++
++ /* TODO_SK::There is just
++ * 1 write required from IA side for DFU.
++ * So commenting this-out, until it gets confirmed */
++ /*ipc_command(IPC_CMD_FW_UPDATE_READY); */
++
++ /*1. DNX SIZE HEADER */
++ memcpy(fws, fw_ud_param->dnx_hdr, DNX_HDR_LEN);
++
++ memcpy_toio(mfld_fw_upd.sram, fws, DNX_HDR_LEN);
++
++ /* There are synchronization issues between IA and SCU */
++ mb();
++
++ /* Write cmd to trigger an interrupt to SCU for firmware update*/
++ ret_val = rpmsg_send_simple_command(fw_update_instance,
++ IPCMSG_FW_UPDATE,
++ IPC_CMD_FW_UPDATE_GO);
++ if (ret_val) {
++ dev_err(fui.dev, "IPC_CMD_FW_UPDATE_GO failed\n");
++ goto term;
++ }
++
++ mfld_fw_upd.wscu = !mfld_fw_upd.wscu;
++
++ if (busy_wait(&mfld_fw_upd) < 0) {
++ ret_val = -1;
++ goto term;
++ }
++
++ /* TODO:Add a count for iteration, based on sizes of security firmware,
++ * so that we determine finite number of iterations to loop thro.
++ * That way at the very least, we can atleast control the number
++ * of iterations, and prevent infinite looping if there are any bugs.
++ * The only catch being for B0, SCU will request twice for each firmware
++ * chunk, since its writing to 2 partitions.
++ * TODO::Investigate if we need to increase timeout for busy_wait,
++ * since SCU is now writing to 2 partitions.
++ */
++
++ while ((mb_state = check_mb_status(&mfld_fw_upd)) != MB_DONE) {
++
++ if (mb_state == MB_ERROR) {
++ dev_dbg(fui.dev, "check_mb_status,error\n");
++ ret_val = -1;
++ goto term;
++ }
++
++ if (!strncmp(mfld_fw_upd.mb_status, FUPH_HDR_SIZE,
++ strlen(FUPH_HDR_SIZE))) {
++ iowrite32(fw_ud_param->fuph_hdr_len, mfld_fw_upd.sram);
++ /* There are synchronization issues between IA-SCU */
++ mb();
++ dev_dbg(fui.dev,
++ "copied fuph hdr size=%d\n",
++ ioread32(mfld_fw_upd.sram));
++ mfld_fw_upd.wia = !mfld_fw_upd.wia;
++ iowrite32(mfld_fw_upd.wia, mfld_fw_upd.mailbox +
++ IA_FLAG_OFFSET);
++ dev_dbg(fui.dev, "ia_flag=%d\n",
++ ioread32(mfld_fw_upd.mailbox + IA_FLAG_OFFSET));
++ mb();
++ mfld_fw_upd.wscu = !mfld_fw_upd.wscu;
++
++ if (busy_wait(&mfld_fw_upd) < 0) {
++ ret_val = -1;
++ goto term;
++ }
++
++ continue;
++ }
++
++ if (calc_offset_and_length(fw_ud_param, mfld_fw_upd.mb_status,
++ &offset, &length, &fuph) < 0) {
++ dev_err(fui.dev,
++ "calc_offset_and_length_error,error\n");
++ ret_val = -1;
++ goto term;
++ }
++
++ if ((process_fw_chunk(fws, offset, length,
++ &mfld_fw_upd)) != 0) {
++ dev_err(fui.dev,
++ "Error processing fw chunk=%s\n",
++ mfld_fw_upd.mb_status);
++ ret_val = -1;
++ goto term;
++ } else
++ dev_dbg(fui.dev,
++ "PASS processing fw chunk=%s\n",
++ mfld_fw_upd.mb_status);
++ }
++ ret_val = intel_scu_ipc_check_status();
++
++term:
++ kfree(fws);
++unmap_mb:
++ iounmap(mfld_fw_upd.mailbox);
++unmap_sram:
++ iounmap(mfld_fw_upd.sram);
++out_unlock:
++ rpmsg_global_unlock();
++ return ret_val;
++}
++
++static void cur_err(const char *err_info)
++{
++ strncpy(err_buf, err_info, sizeof(err_buf) - 1);
++}
++
++static ssize_t write_dnx(struct file *file, struct kobject *kobj,
++ struct bin_attribute *attr, char *buf, loff_t off, size_t count)
++{
++ int ret;
++
++ mutex_lock(&fwud_lock);
++
++ if (!pending_data) {
++ pending_data = vmalloc(FOTA_MEM_SIZE);
++ if (NULL == pending_data) {
++ cur_err("alloc fota memory by sysfs failed\n");
++ ret = -ENOMEM;
++ goto end;
++ }
++ }
++
++ fui.fwud_pending->dnx_file_data = pending_data + IFWI_MAX_SIZE;
++
++ if (unlikely(off >= DNX_MAX_SIZE)) {
++ fui.fwud_pending->dnx_file_data = NULL;
++ cur_err("too large dnx binary stream!");
++ ret = -EFBIG;
++ goto end;
++ }
++
++ memcpy(fui.fwud_pending->dnx_file_data + off, buf, count);
++
++ if (!off)
++ fui.fwud_pending->dnx_size = count;
++ else
++ fui.fwud_pending->dnx_size += count;
++
++ mutex_unlock(&fwud_lock);
++ return count;
++
++end:
++ mutex_unlock(&fwud_lock);
++ return ret;
++}
++
++/* Parses from the end of IFWI, and looks for UPH$,
++ * to determine length of FUPH header
++ */
++static int find_fuph_header_len(unsigned int *len,
++ unsigned char *file_data, unsigned int file_size)
++{
++ int ret = -EINVAL;
++ unsigned char *temp;
++ unsigned int cnt = 0;
++
++ if (!len || !file_data || !file_size) {
++ dev_err(fui.dev, "find_fuph_header_len: Invalid inputs\n");
++ return ret;
++ }
++
++ /* Skipping the checksum at the end, and moving to the
++ * start of the last add-on firmware size in fuph.
++ */
++ temp = file_data + file_size - SKIP_BYTES;
++
++ while (cnt <= FUPH_MAX_LEN) {
++ if (!strncmp(temp, FUPH_STR, sizeof(FUPH_STR) - 1)) {
++ pr_info("Fuph_hdr_len=%d\n", cnt + SKIP_BYTES);
++ *len = cnt + SKIP_BYTES;
++ ret = 0;
++ break;
++ }
++ temp -= 4;
++ cnt += 4;
++ }
++
++ return ret;
++}
++
++static ssize_t write_ifwi(struct file *file, struct kobject *kobj,
++ struct bin_attribute *attr, char *buf, loff_t off, size_t count)
++{
++ int ret;
++
++ mutex_lock(&fwud_lock);
++
++ if (!pending_data) {
++ pending_data = vmalloc(FOTA_MEM_SIZE);
++ if (NULL == pending_data) {
++ cur_err("alloc fota memory by sysfs failed\n");
++ ret = -ENOMEM;
++ goto end;
++ }
++ }
++
++ fui.fwud_pending->fw_file_data = pending_data;
++
++ if (unlikely(off >= IFWI_MAX_SIZE)) {
++ fui.fwud_pending->fw_file_data = NULL;
++ cur_err("too large ifwi binary stream!\n");
++ ret = -EFBIG;
++ goto end;
++ }
++
++ memcpy(fui.fwud_pending->fw_file_data + off, buf, count);
++
++ if (!off)
++ fui.fwud_pending->fsize = count;
++ else
++ fui.fwud_pending->fsize += count;
++
++ mutex_unlock(&fwud_lock);
++ return count;
++
++end:
++ mutex_unlock(&fwud_lock);
++ return ret;
++}
++
++/*
++ * intel_scu_fw_prepare - prepare dnx_hdr and fuph
++ *
++ * This function will be invoked at reboot, when DNX and IFWI data are ready.
++ */
++static int intel_scu_fw_prepare(struct fw_ud *fwud_pending)
++{
++ unsigned int size;
++ unsigned int gpFlags = 0;
++ unsigned int xorcs;
++ unsigned char dnxSH[DNX_HDR_LEN] = { 0 };
++
++ mutex_lock(&fwud_lock);
++
++ size = fui.fwud_pending->dnx_size;
++
++ /* Set GPFlags parameter */
++ gpFlags = gpFlags | (GPF_BIT32 << 31);
++ xorcs = (size ^ gpFlags);
++
++ memcpy((dnxSH + DNX_SIZE_OFFSET), (unsigned char *)(&size), 4);
++ memcpy((dnxSH + GP_FLAG_OFFSET), (unsigned char *)(&gpFlags), 4);
++ memcpy((dnxSH + XOR_CHK_OFFSET), (unsigned char *)(&xorcs), 4);
++
++ /* assign the last DNX_HDR_LEN bytes memory to dnx header */
++ fui.fwud_pending->dnx_hdr = pending_data + FOTA_MEM_SIZE - DNX_HDR_LEN;
++
++ /* directly memcpy to dnx_hdr */
++ memcpy(fui.fwud_pending->dnx_hdr, dnxSH, DNX_HDR_LEN);
++
++ if (find_fuph_header_len(&(fui.fwud_pending->fuph_hdr_len),
++ fui.fwud_pending->fw_file_data,
++ fui.fwud_pending->fsize) < 0) {
++ dev_err(fui.dev, "Error with FUPH header\n");
++ mutex_unlock(&fwud_lock);
++ return -EINVAL;
++ }
++
++ dev_dbg(fui.dev, "fupd_hdr_len=%d, fsize=%d, dnx_size=%d",
++ fui.fwud_pending->fuph_hdr_len, fui.fwud_pending->fsize,
++ fui.fwud_pending->dnx_size);
++
++ mutex_unlock(&fwud_lock);
++ return 0;
++}
++
++int intel_scu_ipc_fw_update(void)
++{
++ int ret = 0;
++
++ /* jump fw upgrade process when fota memory not allocated
++ * or when user cancels update
++ * or when one of dnx and ifwi is not written
++ * or when failure happens in writing one of dnx and ifwi
++ */
++ if (!pending_data || !fui.fwud_pending ||
++ !fui.fwud_pending->dnx_file_data ||
++ !fui.fwud_pending->fw_file_data) {
++ pr_info("Jump FW upgrade process\n");
++ goto end;
++ }
++
++ ret = intel_scu_fw_prepare(fui.fwud_pending);
++ if (ret) {
++ dev_err(fui.dev, "intel_scu_fw_prepare failed\n");
++ goto end;
++ }
++
++ ret = intel_scu_ipc_medfw_upgrade();
++ if (ret)
++ dev_err(fui.dev, "intel_scu_ipc_medfw_upgrade failed\n");
++
++end:
++ return ret;
++}
++EXPORT_SYMBOL(intel_scu_ipc_fw_update);
++
++static ssize_t fw_version_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ u8 data[16] = { 0 };
++ int ret;
++ int i;
++ int used = 0;
++
++ ret = rpmsg_send_command(fw_update_instance, IPCMSG_FW_REVISION, 0,
++ NULL, (u32 *)data, 0, 4);
++ if (ret < 0) {
++ cur_err("Error getting fw version");
++ return -EINVAL;
++ }
++
++ for (i = 0; i < 16; i++)
++ used += snprintf(buf + used, PAGE_SIZE - used, "%x ", data[i]);
++
++ if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER) {
++ ret = rpmsg_send_command(fw_update_instance,
++ IPCMSG_FW_REVISION, 1, NULL, (u32 *)data, 0, 4);
++ if (ret < 0) {
++ cur_err("Error getting fw version");
++ return -EINVAL;
++ }
++ for (i = 0; i < 16; i++)
++ used += snprintf(buf + used, PAGE_SIZE - used,
++ "%x ", data[i]);
++ }
++
++ return used;
++}
++
++static ssize_t last_error_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%s\n", err_buf);
++}
++
++static ssize_t cancel_update_store(struct kobject *kobj,
++ struct kobj_attribute *attr, const char *buf, size_t size)
++{
++ int value;
++
++ if (sscanf(buf, "%d", &value) != 1) {
++ cur_err("One argument is needed\n");
++ return -EINVAL;
++ }
++
++ if (value == 1) {
++ mutex_lock(&fwud_lock);
++ fui.fwud_pending->fw_file_data = NULL;
++ fui.fwud_pending->dnx_file_data = NULL;
++ mutex_unlock(&fwud_lock);
++ } else {
++ cur_err("input '1' to cancel fw upgrade\n");
++ return -EINVAL;
++ }
++
++ return size;
++}
++
++#define __BIN_ATTR(_name, _mode, _size, _read, _write) { \
++ .attr = {.name = __stringify(_name), .mode = _mode }, \
++ .size = _size, \
++ .read = _read, \
++ .write = _write, \
++}
++
++#define BIN_ATTR(_name, _mode, _size, _read, _write) \
++struct bin_attribute bin_attr_##_name = \
++ __BIN_ATTR(_name, _mode, _size, _read, _write)
++
++#define KOBJ_FW_UPDATE_ATTR(_name, _mode, _show, _store) \
++ struct kobj_attribute _name##_attr = __ATTR(_name, _mode, _show, _store)
++
++static KOBJ_FW_UPDATE_ATTR(cancel_update, S_IWUSR, NULL, cancel_update_store);
++static KOBJ_FW_UPDATE_ATTR(fw_version, S_IRUGO, fw_version_show, NULL);
++static KOBJ_FW_UPDATE_ATTR(last_error, S_IRUGO, last_error_show, NULL);
++static BIN_ATTR(dnx, S_IWUSR, DNX_MAX_SIZE, NULL, write_dnx);
++static BIN_ATTR(ifwi, S_IWUSR, IFWI_MAX_SIZE, NULL, write_ifwi);
++
++static struct attribute *fw_update_attrs[] = {
++ &cancel_update_attr.attr,
++ &fw_version_attr.attr,
++ &last_error_attr.attr,
++ NULL,
++};
++
++static struct attribute_group fw_update_attr_group = {
++ .name = "fw_info",
++ .attrs = fw_update_attrs,
++};
++
++static int intel_fw_update_sysfs_create(struct kobject *kobj)
++{
++ int ret;
++
++ ret = sysfs_create_group(kobj, &fw_update_attr_group);
++ if (ret) {
++ dev_err(fui.dev, "Unable to export sysfs interface\n");
++ goto out;
++ }
++
++ ret = sysfs_create_bin_file(kobj, &bin_attr_dnx);
++ if (ret) {
++ dev_err(fui.dev, "Unable to create dnx bin file\n");
++ goto err_dnx_bin;
++ }
++
++ ret = sysfs_create_bin_file(kobj, &bin_attr_ifwi);
++ if (ret) {
++ dev_err(fui.dev, "Unable to create ifwi bin file\n");
++ goto err_ifwi_bin;
++ }
++
++ return 0;
++
++err_ifwi_bin:
++ sysfs_remove_bin_file(kobj, &bin_attr_dnx);
++err_dnx_bin:
++ sysfs_remove_group(kobj, &fw_update_attr_group);
++out:
++ return ret;
++}
++
++static void intel_fw_update_sysfs_remove(struct kobject *kobj)
++{
++ sysfs_remove_bin_file(kobj, &bin_attr_ifwi);
++ sysfs_remove_bin_file(kobj, &bin_attr_dnx);
++ sysfs_remove_group(kobj, &fw_update_attr_group);
++}
++
++static int fw_update_rpmsg_probe(struct rpmsg_channel *rpdev)
++{
++ int ret;
++ struct fw_update_info *fu_info = &fui;
++
++ if (rpdev == NULL) {
++ pr_err("fw_update rpmsg channel not created\n");
++ ret = -ENODEV;
++ goto out;
++ }
++
++ dev_info(&rpdev->dev, "Probed fw_update rpmsg device\n");
++
++ /* Allocate rpmsg instance for fw_update*/
++ ret = alloc_rpmsg_instance(rpdev, &fw_update_instance);
++ if (!fw_update_instance) {
++ dev_err(&rpdev->dev, "kzalloc fw_update instance failed\n");
++ goto out;
++ }
++ /* Initialize rpmsg instance */
++ init_rpmsg_instance(fw_update_instance);
++
++ fu_info->dev = &rpdev->dev;
++
++ fui.fwud_pending = kzalloc(sizeof(struct fw_ud), GFP_KERNEL);
++ if (NULL == fui.fwud_pending) {
++ ret = -ENOMEM;
++ dev_err(fui.dev, "alloc fwud_pending memory failed\n");
++ goto err_fwud_pending;
++ }
++
++ scu_fw_update_kobj = kobject_create_and_add("fw_update", kernel_kobj);
++ if (!scu_fw_update_kobj) {
++ ret = -ENOMEM;
++ dev_err(fui.dev, "create kobject failed\n");
++ goto err_kobj;
++ }
++
++ ret = intel_fw_update_sysfs_create(scu_fw_update_kobj);
++ if (ret) {
++ dev_err(fui.dev, "creating fw update sysfs failed\n");
++ goto err_free_fwud;
++ }
++
++ /* If alloc_fota_mem_early flag is set, allocate FOTA_MEM_SIZE
++ * bytes memory.
++ * reserve the first contiguous IFWI_MAX_SIZE bytes for IFWI,
++ * the next contiguous DNX_MAX_SIZE bytes are reserved for DNX,
++ * the last DNX_HDR_LEN bytes for DNX Header
++ */
++ if (alloc_fota_mem_early) {
++ pending_data = vmalloc(FOTA_MEM_SIZE);
++ if (NULL == pending_data) {
++ ret = -ENOMEM;
++ dev_err(fui.dev, "early alloc fota memory failed\n");
++ goto err_sysfs;
++ }
++ }
++
++ return 0;
++
++err_sysfs:
++ intel_fw_update_sysfs_remove(scu_fw_update_kobj);
++err_free_fwud:
++ kobject_put(scu_fw_update_kobj);
++err_kobj:
++ kfree(fui.fwud_pending);
++ fui.fwud_pending = NULL;
++err_fwud_pending:
++ free_rpmsg_instance(rpdev, &fw_update_instance);
++out:
++ return ret;
++}
++
++static void fw_update_rpmsg_remove(struct rpmsg_channel *rpdev)
++{
++ free_rpmsg_instance(rpdev, &fw_update_instance);
++ intel_fw_update_sysfs_remove(scu_fw_update_kobj);
++ kobject_put(scu_fw_update_kobj);
++
++ vfree(pending_data);
++ pending_data = NULL;
++ kfree(fui.fwud_pending);
++ fui.fwud_pending = NULL;
++}
++
++static void fw_update_rpmsg_cb(struct rpmsg_channel *rpdev, void *data,
++ int len, void *priv, u32 src)
++{
++ dev_warn(&rpdev->dev, "unexpected, message\n");
++
++ print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
++ data, len, true);
++}
++
++static struct rpmsg_device_id fw_update_rpmsg_id_table[] = {
++ { .name = "rpmsg_fw_update" },
++ { },
++};
++MODULE_DEVICE_TABLE(rpmsg, fw_update_rpmsg_id_table);
++
++static struct rpmsg_driver fw_update_rpmsg = {
++ .drv.name = KBUILD_MODNAME,
++ .drv.owner = THIS_MODULE,
++ .id_table = fw_update_rpmsg_id_table,
++ .probe = fw_update_rpmsg_probe,
++ .callback = fw_update_rpmsg_cb,
++ .remove = fw_update_rpmsg_remove,
++};
++
++static int __init fw_update_module_init(void)
++{
++ return register_rpmsg_driver(&fw_update_rpmsg);
++}
++
++static void __exit fw_update_module_exit(void)
++{
++ unregister_rpmsg_driver(&fw_update_rpmsg);
++}
++
++module_init(fw_update_module_init);
++module_exit(fw_update_module_exit);
++
++MODULE_AUTHOR("Sreedhara DS <sreedhara.ds@intel.com>");
++MODULE_AUTHOR("Ning Li <ning.li@intel.com>");
++MODULE_DESCRIPTION("Intel SCU Firmware Update Driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
+index 9215ed7..d8d251f05 100644
+--- a/drivers/platform/x86/intel_scu_ipc.c
++++ b/drivers/platform/x86/intel_scu_ipc.c
+@@ -23,22 +23,67 @@
+ #include <linux/pm.h>
+ #include <linux/pci.h>
+ #include <linux/interrupt.h>
+-#include <linux/sfi.h>
+ #include <linux/module.h>
+-#include <asm/mrst.h>
++#include <asm/intel-mid.h>
+ #include <asm/intel_scu_ipc.h>
++#include <linux/pm_qos.h>
++#include <linux/intel_mid_pm.h>
++#include <linux/kernel.h>
++#include <linux/bitops.h>
++#include <linux/sched.h>
++#include <linux/atomic.h>
++#include <linux/notifier.h>
++#include <linux/suspend.h>
++
++enum {
++ SCU_IPC_LINCROFT,
++ SCU_IPC_PENWELL,
++ SCU_IPC_CLOVERVIEW,
++ SCU_IPC_TANGIER,
++};
+
+-/* IPC defines the following message types */
+-#define IPCMSG_WATCHDOG_TIMER 0xF8 /* Set Kernel Watchdog Threshold */
+-#define IPCMSG_BATTERY 0xEF /* Coulomb Counter Accumulator */
+-#define IPCMSG_FW_UPDATE 0xFE /* Firmware update */
+-#define IPCMSG_PCNTRL 0xFF /* Power controller unit read/write */
+-#define IPCMSG_FW_REVISION 0xF4 /* Get firmware revision */
++/* intel scu ipc driver data*/
++struct intel_scu_ipc_pdata_t {
++ u32 ipc_base;
++ u32 i2c_base;
++ u32 ipc_len;
++ u32 i2c_len;
++};
+
+-/* Command id associated with message IPCMSG_PCNTRL */
+-#define IPC_CMD_PCNTRL_W 0 /* Register write */
+-#define IPC_CMD_PCNTRL_R 1 /* Register read */
+-#define IPC_CMD_PCNTRL_M 2 /* Register read-modify-write */
++static struct intel_scu_ipc_pdata_t intel_scu_ipc_pdata[] = {
++ [SCU_IPC_LINCROFT] = {
++ .ipc_base = 0xff11c000,
++ .i2c_base = 0xff12b000,
++ .ipc_len = 0x100,
++ .i2c_len = 0x10,
++ },
++ [SCU_IPC_PENWELL] = {
++ .ipc_base = 0xff11c000,
++ .i2c_base = 0xff12b000,
++ .ipc_len = 0x100,
++ .i2c_len = 0x10,
++ },
++ [SCU_IPC_CLOVERVIEW] = {
++ .ipc_base = 0xff11c000,
++ .i2c_base = 0xff12b000,
++ .ipc_len = 0x100,
++ .i2c_len = 0x10,
++ },
++ [SCU_IPC_TANGIER] = {
++ .ipc_base = 0xff009000,
++ .i2c_base = 0xff00d000,
++ .ipc_len = 0x100,
++ .i2c_len = 0x10,
++ },
++};
++static int scu_ipc_pm_callback(struct notifier_block *nb,
++ unsigned long action,
++ void *ignored);
++
++static struct notifier_block scu_ipc_pm_notifier = {
++ .notifier_call = scu_ipc_pm_callback,
++ .priority = 1,
++};
+
+ /*
+ * IPC register summary
+@@ -58,37 +103,82 @@
+ * message handler is called within firmware.
+ */
+
+-#define IPC_BASE_ADDR 0xFF11C000 /* IPC1 base register address */
+-#define IPC_MAX_ADDR 0x100 /* Maximum IPC regisers */
+-#define IPC_WWBUF_SIZE 20 /* IPC Write buffer Size */
+-#define IPC_RWBUF_SIZE 20 /* IPC Read buffer Size */
+-#define IPC_I2C_BASE 0xFF12B000 /* I2C control register base address */
+-#define IPC_I2C_MAX_ADDR 0x10 /* Maximum I2C regisers */
+-
+-static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id);
+-static void ipc_remove(struct pci_dev *pdev);
++#define IPC_STATUS_ADDR 0X04
++#define IPC_SPTR_ADDR 0x08
++#define IPC_DPTR_ADDR 0x0C
++#define IPC_READ_BUFFER 0x90
++#define IPC_WRITE_BUFFER 0x80
++#define IPC_IOC 0x100
+
+-struct intel_scu_ipc_dev {
++struct intel_ipc_controller {
+ struct pci_dev *pdev;
+ void __iomem *ipc_base;
+ void __iomem *i2c_base;
++ int ioc;
++ int cmd;
++ struct completion cmd_complete;
+ };
+
+-static struct intel_scu_ipc_dev ipcdev; /* Only one for now */
++static struct intel_ipc_controller ipcdev; /* Only one for now */
++
++static int platform; /* Platform type */
++
++static char *ipc_err_sources[] = {
++ [IPC_ERR_NONE] =
++ "no error",
++ [IPC_ERR_CMD_NOT_SUPPORTED] =
++ "command not supported",
++ [IPC_ERR_CMD_NOT_SERVICED] =
++ "command not serviced",
++ [IPC_ERR_UNABLE_TO_SERVICE] =
++ "unable to service",
++ [IPC_ERR_CMD_INVALID] =
++ "command invalid",
++ [IPC_ERR_CMD_FAILED] =
++ "command failed",
++ [IPC_ERR_EMSECURITY] =
++ "Invalid Battery",
++ [IPC_ERR_UNSIGNEDKERNEL] =
++ "Unsigned kernel",
++};
+
+-static int platform; /* Platform type */
++/* PM Qos struct */
++static struct pm_qos_request *qos;
+
+-/*
+- * IPC Read Buffer (Read Only):
+- * 16 byte buffer for receiving data from SCU, if IPC command
+- * processing results in response data
+- */
+-#define IPC_READ_BUFFER 0x90
++/* Suspend status*/
++static bool suspend_status;
++static DEFINE_MUTEX(scu_suspend_lock);
++
++/* Suspend status get */
++bool suspend_in_progress(void)
++{
++ return suspend_status;
++}
++
++/* Suspend status set */
++void set_suspend_status(bool status)
++{
++ mutex_lock(&scu_suspend_lock);
++ suspend_status = status;
++ mutex_unlock(&scu_suspend_lock);
++}
+
+-#define IPC_I2C_CNTRL_ADDR 0
+-#define I2C_DATA_ADDR 0x04
++/* IPC PM notifier callback */
++static int scu_ipc_pm_callback(struct notifier_block *nb,
++ unsigned long action,
++ void *ignored)
++{
++ switch (action) {
++ case PM_SUSPEND_PREPARE:
++ set_suspend_status(true);
++ return NOTIFY_OK;
++ case PM_POST_SUSPEND:
++ set_suspend_status(false);
++ return NOTIFY_OK;
++ }
+
+-static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */
++ return NOTIFY_DONE;
++}
+
+ /*
+ * Command Register (Write Only):
+@@ -96,9 +186,18 @@ static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */
+ * Format:
+ * |rfu2(8) | size(8) | command id(4) | rfu1(3) | ioc(1) | command(8)|
+ */
+-static inline void ipc_command(u32 cmd) /* Send ipc command */
++void intel_scu_ipc_send_command(u32 cmd) /* Send ipc command */
+ {
+- writel(cmd, ipcdev.ipc_base);
++ ipcdev.cmd = cmd;
++ INIT_COMPLETION(ipcdev.cmd_complete);
++
++ if (system_state == SYSTEM_RUNNING && !suspend_in_progress()) {
++ ipcdev.ioc = 1;
++ writel(cmd | IPC_IOC, ipcdev.ipc_base);
++ } else {
++ ipcdev.ioc = 0;
++ writel(cmd, ipcdev.ipc_base);
++ }
+ }
+
+ /*
+@@ -108,7 +207,7 @@ static inline void ipc_command(u32 cmd) /* Send ipc command */
+ */
+ static inline void ipc_data_writel(u32 data, u32 offset) /* Write ipc data */
+ {
+- writel(data, ipcdev.ipc_base + 0x80 + offset);
++ writel(data, ipcdev.ipc_base + IPC_WRITE_BUFFER + offset);
+ }
+
+ /*
+@@ -119,9 +218,9 @@ static inline void ipc_data_writel(u32 data, u32 offset) /* Write ipc data */
+ * |rfu3(8)|error code(8)|initiator id(8)|cmd id(4)|rfu1(2)|error(1)|busy(1)|
+ */
+
+-static inline u8 ipc_read_status(void)
++static inline u32 ipc_read_status(void)
+ {
+- return __raw_readl(ipcdev.ipc_base + 0x04);
++ return __raw_readl(ipcdev.ipc_base + IPC_STATUS_ADDR);
+ }
+
+ static inline u8 ipc_data_readb(u32 offset) /* Read ipc byte data */
+@@ -134,243 +233,72 @@ static inline u32 ipc_data_readl(u32 offset) /* Read ipc u32 data */
+ return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
+ }
+
+-static inline int busy_loop(void) /* Wait till scu status is busy */
++int intel_scu_ipc_check_status(void)
+ {
+- u32 status = 0;
+- u32 loop_count = 0;
+-
+- status = ipc_read_status();
+- while (status & 1) {
+- udelay(1); /* scu processing time is in few u secods */
+- status = ipc_read_status();
+- loop_count++;
+- /* break if scu doesn't reset busy bit after huge retry */
+- if (loop_count > 100000) {
+- dev_err(&ipcdev.pdev->dev, "IPC timed out");
+- return -ETIMEDOUT;
+- }
+- }
+- if ((status >> 1) & 1)
+- return -EIO;
+-
+- return 0;
+-}
+-
+-/* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */
+-static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
+-{
+- int nc;
+- u32 offset = 0;
+- int err;
+- u8 cbuf[IPC_WWBUF_SIZE] = { };
+- u32 *wbuf = (u32 *)&cbuf;
+-
+- mutex_lock(&ipclock);
+-
+- memset(cbuf, 0, sizeof(cbuf));
+-
+- if (ipcdev.pdev == NULL) {
+- mutex_unlock(&ipclock);
+- return -ENODEV;
+- }
+-
+- for (nc = 0; nc < count; nc++, offset += 2) {
+- cbuf[offset] = addr[nc];
+- cbuf[offset + 1] = addr[nc] >> 8;
++ int i;
++ int ret = 0;
++ int status;
++ int loop_count = 3000000;
++
++ if (ipcdev.ioc && (system_state == SYSTEM_RUNNING) &&
++ (!suspend_in_progress())) {
++ if (0 == wait_for_completion_timeout(
++ &ipcdev.cmd_complete, 3 * HZ))
++ ret = -ETIMEDOUT;
++ } else {
++ while ((ipc_read_status() & 1) && --loop_count)
++ udelay(1);
++ if (loop_count == 0)
++ ret = -ETIMEDOUT;
+ }
+
+- if (id == IPC_CMD_PCNTRL_R) {
+- for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
+- ipc_data_writel(wbuf[nc], offset);
+- ipc_command((count*2) << 16 | id << 12 | 0 << 8 | op);
+- } else if (id == IPC_CMD_PCNTRL_W) {
+- for (nc = 0; nc < count; nc++, offset += 1)
+- cbuf[offset] = data[nc];
+- for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
+- ipc_data_writel(wbuf[nc], offset);
+- ipc_command((count*3) << 16 | id << 12 | 0 << 8 | op);
+- } else if (id == IPC_CMD_PCNTRL_M) {
+- cbuf[offset] = data[0];
+- cbuf[offset + 1] = data[1];
+- ipc_data_writel(wbuf[0], 0); /* Write wbuff */
+- ipc_command(4 << 16 | id << 12 | 0 << 8 | op);
++ status = ipc_read_status();
++ if (ret == -ETIMEDOUT)
++ dev_err(&ipcdev.pdev->dev,
++ "IPC timed out, IPC_STS=0x%x, IPC_CMD=0x%x\n",
++ status, ipcdev.cmd);
++
++ if (status & 0x2) {
++ ret = -EIO;
++ i = (status >> 16) & 0xFF;
++ if (i < ARRAY_SIZE(ipc_err_sources))
++ dev_err(&ipcdev.pdev->dev,
++ "IPC failed: %s, IPC_STS=0x%x, IPC_CMD=0x%x\n",
++ ipc_err_sources[i], status, ipcdev.cmd);
++ else
++ dev_err(&ipcdev.pdev->dev,
++ "IPC failed: unknown error, IPC_STS=0x%x, "
++ "IPC_CMD=0x%x\n", status, ipcdev.cmd);
++ if ((i == IPC_ERR_UNSIGNEDKERNEL) || (i == IPC_ERR_EMSECURITY))
++ ret = -EACCES;
+ }
+
+- err = busy_loop();
+- if (id == IPC_CMD_PCNTRL_R) { /* Read rbuf */
+- /* Workaround: values are read as 0 without memcpy_fromio */
+- memcpy_fromio(cbuf, ipcdev.ipc_base + 0x90, 16);
+- for (nc = 0; nc < count; nc++)
+- data[nc] = ipc_data_readb(nc);
+- }
+- mutex_unlock(&ipclock);
+- return err;
+-}
+-
+-/**
+- * intel_scu_ipc_ioread8 - read a word via the SCU
+- * @addr: register on SCU
+- * @data: return pointer for read byte
+- *
+- * Read a single register. Returns 0 on success or an error code. All
+- * locking between SCU accesses is handled for the caller.
+- *
+- * This function may sleep.
+- */
+-int intel_scu_ipc_ioread8(u16 addr, u8 *data)
+-{
+- return pwr_reg_rdwr(&addr, data, 1, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R);
+-}
+-EXPORT_SYMBOL(intel_scu_ipc_ioread8);
+-
+-/**
+- * intel_scu_ipc_ioread16 - read a word via the SCU
+- * @addr: register on SCU
+- * @data: return pointer for read word
+- *
+- * Read a register pair. Returns 0 on success or an error code. All
+- * locking between SCU accesses is handled for the caller.
+- *
+- * This function may sleep.
+- */
+-int intel_scu_ipc_ioread16(u16 addr, u16 *data)
+-{
+- u16 x[2] = {addr, addr + 1 };
+- return pwr_reg_rdwr(x, (u8 *)data, 2, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R);
+-}
+-EXPORT_SYMBOL(intel_scu_ipc_ioread16);
+-
+-/**
+- * intel_scu_ipc_ioread32 - read a dword via the SCU
+- * @addr: register on SCU
+- * @data: return pointer for read dword
+- *
+- * Read four registers. Returns 0 on success or an error code. All
+- * locking between SCU accesses is handled for the caller.
+- *
+- * This function may sleep.
+- */
+-int intel_scu_ipc_ioread32(u16 addr, u32 *data)
+-{
+- u16 x[4] = {addr, addr + 1, addr + 2, addr + 3};
+- return pwr_reg_rdwr(x, (u8 *)data, 4, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R);
+-}
+-EXPORT_SYMBOL(intel_scu_ipc_ioread32);
+-
+-/**
+- * intel_scu_ipc_iowrite8 - write a byte via the SCU
+- * @addr: register on SCU
+- * @data: byte to write
+- *
+- * Write a single register. Returns 0 on success or an error code. All
+- * locking between SCU accesses is handled for the caller.
+- *
+- * This function may sleep.
+- */
+-int intel_scu_ipc_iowrite8(u16 addr, u8 data)
+-{
+- return pwr_reg_rdwr(&addr, &data, 1, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W);
++ return ret;
+ }
+-EXPORT_SYMBOL(intel_scu_ipc_iowrite8);
+
+-/**
+- * intel_scu_ipc_iowrite16 - write a word via the SCU
+- * @addr: register on SCU
+- * @data: word to write
+- *
+- * Write two registers. Returns 0 on success or an error code. All
+- * locking between SCU accesses is handled for the caller.
+- *
+- * This function may sleep.
+- */
+-int intel_scu_ipc_iowrite16(u16 addr, u16 data)
++void intel_scu_ipc_lock(void)
+ {
+- u16 x[2] = {addr, addr + 1 };
+- return pwr_reg_rdwr(x, (u8 *)&data, 2, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W);
+-}
+-EXPORT_SYMBOL(intel_scu_ipc_iowrite16);
++ /* Prevent C-states beyond C6 */
++ pm_qos_update_request(qos, CSTATE_EXIT_LATENCY_S0i1 - 1);
+
+-/**
+- * intel_scu_ipc_iowrite32 - write a dword via the SCU
+- * @addr: register on SCU
+- * @data: dword to write
+- *
+- * Write four registers. Returns 0 on success or an error code. All
+- * locking between SCU accesses is handled for the caller.
+- *
+- * This function may sleep.
+- */
+-int intel_scu_ipc_iowrite32(u16 addr, u32 data)
+-{
+- u16 x[4] = {addr, addr + 1, addr + 2, addr + 3};
+- return pwr_reg_rdwr(x, (u8 *)&data, 4, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W);
+-}
+-EXPORT_SYMBOL(intel_scu_ipc_iowrite32);
++ /* Prevent S3 */
++ mutex_lock(&scu_suspend_lock);
+
+-/**
+- * intel_scu_ipc_readvv - read a set of registers
+- * @addr: register list
+- * @data: bytes to return
+- * @len: length of array
+- *
+- * Read registers. Returns 0 on success or an error code. All
+- * locking between SCU accesses is handled for the caller.
+- *
+- * The largest array length permitted by the hardware is 5 items.
+- *
+- * This function may sleep.
+- */
+-int intel_scu_ipc_readv(u16 *addr, u8 *data, int len)
+-{
+- return pwr_reg_rdwr(addr, data, len, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R);
+ }
+-EXPORT_SYMBOL(intel_scu_ipc_readv);
++EXPORT_SYMBOL_GPL(intel_scu_ipc_lock);
+
+-/**
+- * intel_scu_ipc_writev - write a set of registers
+- * @addr: register list
+- * @data: bytes to write
+- * @len: length of array
+- *
+- * Write registers. Returns 0 on success or an error code. All
+- * locking between SCU accesses is handled for the caller.
+- *
+- * The largest array length permitted by the hardware is 5 items.
+- *
+- * This function may sleep.
+- *
+- */
+-int intel_scu_ipc_writev(u16 *addr, u8 *data, int len)
++void intel_scu_ipc_unlock(void)
+ {
+- return pwr_reg_rdwr(addr, data, len, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W);
+-}
+-EXPORT_SYMBOL(intel_scu_ipc_writev);
++ /* Re-enable S3 */
++ mutex_unlock(&scu_suspend_lock);
+
+-
+-/**
+- * intel_scu_ipc_update_register - r/m/w a register
+- * @addr: register address
+- * @bits: bits to update
+- * @mask: mask of bits to update
+- *
+- * Read-modify-write power control unit register. The first data argument
+- * must be register value and second is mask value
+- * mask is a bitmap that indicates which bits to update.
+- * 0 = masked. Don't modify this bit, 1 = modify this bit.
+- * returns 0 on success or an error code.
+- *
+- * This function may sleep. Locking between SCU accesses is handled
+- * for the caller.
+- */
+-int intel_scu_ipc_update_register(u16 addr, u8 bits, u8 mask)
+-{
+- u8 data[2] = { bits, mask };
+- return pwr_reg_rdwr(&addr, data, 1, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_M);
++ /* Re-enable Deeper C-states beyond C6 */
++ pm_qos_update_request(qos, PM_QOS_DEFAULT_VALUE);
+ }
+-EXPORT_SYMBOL(intel_scu_ipc_update_register);
++EXPORT_SYMBOL_GPL(intel_scu_ipc_unlock);
+
+ /**
+- * intel_scu_ipc_simple_command - send a simple command
++ * intel_scu_ipc_simple_command - send a simple command
+ * @cmd: command
+ * @sub: sub type
+ *
+@@ -385,117 +313,115 @@ int intel_scu_ipc_simple_command(int cmd, int sub)
+ {
+ int err;
+
+- mutex_lock(&ipclock);
+- if (ipcdev.pdev == NULL) {
+- mutex_unlock(&ipclock);
++ if (ipcdev.pdev == NULL)
+ return -ENODEV;
+- }
+- ipc_command(sub << 12 | cmd);
+- err = busy_loop();
+- mutex_unlock(&ipclock);
++
++ intel_scu_ipc_lock();
++ intel_scu_ipc_send_command(sub << 12 | cmd);
++ err = intel_scu_ipc_check_status();
++ intel_scu_ipc_unlock();
+ return err;
+ }
+ EXPORT_SYMBOL(intel_scu_ipc_simple_command);
+
+ /**
+- * intel_scu_ipc_command - command with data
+- * @cmd: command
+- * @sub: sub type
+- * @in: input data
+- * @inlen: input length in dwords
+- * @out: output data
+- * @outlein: output length in dwords
+- *
+- * Issue a command to the SCU which involves data transfers. Do the
+- * data copies under the lock but leave it for the caller to interpret
++ * intel_scu_ipc_raw_cmd - raw ipc command with data
++ * @cmd: command
++ * @sub: sub type
++ * @in: input data
++ * @inlen: input length in bytes
++ * @out: output data
++ * @outlen: output length in dwords
++ * @sptr: data writing to SPTR register
++ * @dptr: data writing to DPTR register
++ *
++ * Issue a command to the SCU which involves data transfers. Do the
++ * data copies under the lock but leave it for the caller to interpret
++ * Note: This function should be called with the holding of ipclock
+ */
+-
+-int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
+- u32 *out, int outlen)
++int intel_scu_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen, u32 *out,
++ u32 outlen, u32 dptr, u32 sptr)
+ {
+ int i, err;
++ u32 wbuf[4] = { 0 };
+
+- mutex_lock(&ipclock);
+- if (ipcdev.pdev == NULL) {
+- mutex_unlock(&ipclock);
++ if (ipcdev.pdev == NULL)
+ return -ENODEV;
+- }
+
+- for (i = 0; i < inlen; i++)
+- ipc_data_writel(*in++, 4 * i);
+-
+- ipc_command((inlen << 16) | (sub << 12) | cmd);
+- err = busy_loop();
++ if (inlen > 16)
++ return -EINVAL;
++
++ memcpy(wbuf, in, inlen);
++
++ writel(dptr, ipcdev.ipc_base + IPC_DPTR_ADDR);
++ writel(sptr, ipcdev.ipc_base + IPC_SPTR_ADDR);
++
++ /**
++ * SRAM controller doesn't support 8bit write, it only supports
++ * 32bit write, so we have to write into the WBUF in 32bit,
++ * and SCU FW will use the inlen to determine the actual input
++ * data length in the WBUF.
++ */
++ for (i = 0; i < ((inlen + 3) / 4); i++)
++ ipc_data_writel(wbuf[i], 4 * i);
++
++ /**
++ * Watchdog IPC command is an exception here using double word
++ * as the unit of input data size because of historical reasons
++ * and SCU FW is doing so.
++ */
++ if ((cmd & 0xFF) == IPCMSG_WATCHDOG_TIMER)
++ inlen = (inlen + 3) / 4;
++ /*
++ * In case of 3 pmic writes or read-modify-writes
++ * there are holes in the middle of the buffer which are
++ * ignored by SCU. These bytes should not be included into
++ * size of the ipc msg. Holes are as follows:
++ * write: wbuf[6 & 7]
++ * read-modifu-write: wbuf[6 & 7 & 11]
++ */
++ else if ((cmd & 0xFF) == IPCMSG_PCNTRL) {
++ if (sub == IPC_CMD_PCNTRL_W && inlen == 11)
++ inlen -= 2;
++ else if (sub == IPC_CMD_PCNTRL_M && inlen == 15)
++ inlen -= 3;
++ }
++ intel_scu_ipc_send_command((inlen << 16) | (sub << 12) | cmd);
++ err = intel_scu_ipc_check_status();
+
+ for (i = 0; i < outlen; i++)
+ *out++ = ipc_data_readl(4 * i);
+
+- mutex_unlock(&ipclock);
+ return err;
+ }
+-EXPORT_SYMBOL(intel_scu_ipc_command);
++EXPORT_SYMBOL_GPL(intel_scu_ipc_raw_cmd);
+
+-/*I2C commands */
+-#define IPC_I2C_WRITE 1 /* I2C Write command */
+-#define IPC_I2C_READ 2 /* I2C Read command */
+-
+-/**
+- * intel_scu_ipc_i2c_cntrl - I2C read/write operations
+- * @addr: I2C address + command bits
+- * @data: data to read/write
+- *
+- * Perform an an I2C read/write operation via the SCU. All locking is
+- * handled for the caller. This function may sleep.
+- *
+- * Returns an error code or 0 on success.
+- *
+- * This has to be in the IPC driver for the locking.
+- */
+-int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data)
++int intel_scu_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen,
++ u32 *out, u32 outlen)
+ {
+- u32 cmd = 0;
+-
+- mutex_lock(&ipclock);
+- if (ipcdev.pdev == NULL) {
+- mutex_unlock(&ipclock);
+- return -ENODEV;
+- }
+- cmd = (addr >> 24) & 0xFF;
+- if (cmd == IPC_I2C_READ) {
+- writel(addr, ipcdev.i2c_base + IPC_I2C_CNTRL_ADDR);
+- /* Write not getting updated without delay */
+- mdelay(1);
+- *data = readl(ipcdev.i2c_base + I2C_DATA_ADDR);
+- } else if (cmd == IPC_I2C_WRITE) {
+- writel(*data, ipcdev.i2c_base + I2C_DATA_ADDR);
+- mdelay(1);
+- writel(addr, ipcdev.i2c_base + IPC_I2C_CNTRL_ADDR);
+- } else {
+- dev_err(&ipcdev.pdev->dev,
+- "intel_scu_ipc: I2C INVALID_CMD = 0x%x\n", cmd);
+-
+- mutex_unlock(&ipclock);
+- return -EIO;
+- }
+- mutex_unlock(&ipclock);
+- return 0;
++ int ret;
++ intel_scu_ipc_lock();
++ ret = intel_scu_ipc_raw_cmd(cmd, sub, in, inlen, out, outlen, 0, 0);
++ intel_scu_ipc_unlock();
++ return ret;
+ }
+-EXPORT_SYMBOL(intel_scu_ipc_i2c_cntrl);
++EXPORT_SYMBOL_GPL(intel_scu_ipc_command);
+
+ /*
+ * Interrupt handler gets called when ioc bit of IPC_COMMAND_REG set to 1
+ * When ioc bit is set to 1, caller api must wait for interrupt handler called
+- * which in turn unlocks the caller api. Currently this is not used
++ * which in turn unlocks the caller api.
+ *
+ * This is edge triggered so we need take no action to clear anything
+ */
+ static irqreturn_t ioc(int irq, void *dev_id)
+ {
++ complete(&ipcdev.cmd_complete);
+ return IRQ_HANDLED;
+ }
+
+ /**
+- * ipc_probe - probe an Intel SCU IPC
++ * ipc_probe - probe an Intel SCU IPC
+ * @dev: the PCI device matching
+ * @id: entry in the match table
+ *
+@@ -504,12 +430,16 @@ static irqreturn_t ioc(int irq, void *dev_id)
+ */
+ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id)
+ {
+- int err;
++ int err, pid;
++ struct intel_scu_ipc_pdata_t *pdata;
+ resource_size_t pci_resource;
+
+ if (ipcdev.pdev) /* We support only one SCU */
+ return -EBUSY;
+
++ pid = id->driver_data;
++ pdata = &intel_scu_ipc_pdata[pid];
++
+ ipcdev.pdev = pci_dev_get(dev);
+
+ err = pci_enable_device(dev);
+@@ -524,14 +454,17 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id)
+ if (!pci_resource)
+ return -ENOMEM;
+
+- if (request_irq(dev->irq, ioc, 0, "intel_scu_ipc", &ipcdev))
++ init_completion(&ipcdev.cmd_complete);
++
++ if (request_irq(dev->irq, ioc, IRQF_NO_SUSPEND, "intel_scu_ipc",
++ &ipcdev))
+ return -EBUSY;
+
+- ipcdev.ipc_base = ioremap_nocache(IPC_BASE_ADDR, IPC_MAX_ADDR);
++ ipcdev.ipc_base = ioremap_nocache(pdata->ipc_base, pdata->ipc_len);
+ if (!ipcdev.ipc_base)
+ return -ENOMEM;
+
+- ipcdev.i2c_base = ioremap_nocache(IPC_I2C_BASE, IPC_I2C_MAX_ADDR);
++ ipcdev.i2c_base = ioremap_nocache(pdata->i2c_base, pdata->i2c_len);
+ if (!ipcdev.i2c_base) {
+ iounmap(ipcdev.ipc_base);
+ return -ENOMEM;
+@@ -543,7 +476,7 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id)
+ }
+
+ /**
+- * ipc_remove - remove a bound IPC device
++ * ipc_remove - remove a bound IPC device
+ * @pdev: PCI device
+ *
+ * In practice the SCU is not removable but this function is also
+@@ -564,7 +497,10 @@ static void ipc_remove(struct pci_dev *pdev)
+ }
+
+ static DEFINE_PCI_DEVICE_TABLE(pci_ids) = {
+- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a)},
++ {PCI_VDEVICE(INTEL, 0x080e), SCU_IPC_PENWELL},
++ {PCI_VDEVICE(INTEL, 0x082a), SCU_IPC_LINCROFT},
++ {PCI_VDEVICE(INTEL, 0x08ea), SCU_IPC_CLOVERVIEW},
++ {PCI_VDEVICE(INTEL, 0x11a0), SCU_IPC_TANGIER},
+ { 0,}
+ };
+ MODULE_DEVICE_TABLE(pci, pci_ids);
+@@ -576,17 +512,27 @@ static struct pci_driver ipc_driver = {
+ .remove = ipc_remove,
+ };
+
+-
+-static int __init intel_scu_ipc_init(void)
++static int intel_scu_ipc_init(void)
+ {
+- platform = mrst_identify_cpu();
++ platform = intel_mid_identify_cpu();
+ if (platform == 0)
+ return -ENODEV;
++
++ qos = kzalloc(sizeof(struct pm_qos_request), GFP_KERNEL);
++ if (!qos)
++ return -ENOMEM;
++
++ pm_qos_add_request(qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
++
++ register_pm_notifier(&scu_ipc_pm_notifier);
++
+ return pci_register_driver(&ipc_driver);
+ }
+
+ static void __exit intel_scu_ipc_exit(void)
+ {
++ pm_qos_remove_request(qos);
++
+ pci_unregister_driver(&ipc_driver);
+ }
+
+@@ -594,5 +540,5 @@ MODULE_AUTHOR("Sreedhara DS <sreedhara.ds@intel.com>");
+ MODULE_DESCRIPTION("Intel SCU IPC driver");
+ MODULE_LICENSE("GPL");
+
+-module_init(intel_scu_ipc_init);
++fs_initcall(intel_scu_ipc_init);
+ module_exit(intel_scu_ipc_exit);
+diff --git a/drivers/platform/x86/intel_scu_ipcutil.c b/drivers/platform/x86/intel_scu_ipcutil.c
+index 02bc5a6..8d4c96c 100644
+--- a/drivers/platform/x86/intel_scu_ipcutil.c
++++ b/drivers/platform/x86/intel_scu_ipcutil.c
+@@ -3,6 +3,8 @@
+ *
+ * (C) Copyright 2008-2010 Intel Corporation
+ * Author: Sreedhara DS (sreedhara.ds@intel.com)
++ * (C) Copyright 2010 Intel Corporation
++ * Author: Sudha Krishnakumar (sudha.krishnakumar@intel.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+@@ -22,22 +24,420 @@
+ #include <linux/uaccess.h>
+ #include <linux/slab.h>
+ #include <linux/init.h>
++#include <linux/miscdevice.h>
++#include <linux/io.h>
++#include <linux/rpmsg.h>
+ #include <asm/intel_scu_ipc.h>
++#include <asm/intel_scu_pmic.h>
++#include <asm/intel_scu_ipcutil.h>
++#include <asm/intel-mid.h>
++#include <asm/intel_mid_rpmsg.h>
++#include <linux/platform_data/intel_mid_remoteproc.h>
++#include <linux/pm_runtime.h>
++#include <linux/debugfs.h>
++#include <linux/seq_file.h>
+
+-static int major;
++#ifdef CONFIG_COMPAT
++#include <linux/compat.h>
++#endif
+
+-/* ioctl commnds */
+-#define INTE_SCU_IPC_REGISTER_READ 0
+-#define INTE_SCU_IPC_REGISTER_WRITE 1
+-#define INTE_SCU_IPC_REGISTER_UPDATE 2
++#define MAX_FW_SIZE 264192
++
++#define PMIT_RESET1_OFFSET 14
++#define PMIT_RESET2_OFFSET 15
++
++#define IPC_RESIDENCY_CMD_ID_START 0
++#define IPC_RESIDENCY_CMD_ID_DUMP 2
++
++#define SRAM_ADDR_S0IX_RESIDENCY 0xFFFF71E0
++#define ALL_RESIDENCY_DATA_SIZE 12
++
++#define DUMP_OSNIB
++
++#define OSHOB_EXTEND_DESC_SIZE 52 /* OSHOB header+osnib+oem info: 52 bytes.*/
++
++#define OSHOB_HEADER_MAGIC_SIZE 4 /* Size (bytes) of magic number in OSHOB */
++ /* header. */
++
++#define OSHOB_MAGIC_NUMBER "$OH$" /* If found when reading the first */
++ /* 4 bytes of the OSOHB zone, it */
++ /* means that the new extended OSHOB */
++ /* is going to be used. */
++
++#define OSHOB_REV_MAJ_DEFAULT 0 /* Default revision number of OSHOB. */
++#define OSHOB_REV_MIN_DEFAULT 1 /* If 0.1 the default OSHOB is used */
++ /* instead of the extended one. */
++
++/* Defines for the SCU buffer included in OSHOB structure. */
++#define OSHOB_SCU_BUF_BASE_DW_SIZE 1 /* In dwords. By default SCU */
++ /* buffer size is 1 dword. */
++
++#define OSHOB_SCU_BUF_MRFLD_DW_SIZE (4*OSHOB_SCU_BUF_BASE_DW_SIZE)
++ /* In dwords. On Merrifield the */
++ /* SCU trace buffer size is */
++ /* 4 dwords. */
++#define OSHOB_DEF_FABRIC_ERR_MRFLD_SIZE 50 /* In DWORDS. For Merrifield.*/
++ /* Fabric error log size (in DWORDS).*/
++ /* From offs 0x44 to 0x10C. */
++ /* Used in default OSHOB. */
++
++#define OSNIB_SIZE 32 /* Size (bytes) of the default OSNIB.*/
++
++#define OSNIB_INTEL_RSVD_SIZE 24 /* Size (bytes) of Intel RESERVED in */
++ /* OSNIB. */
++#define OSNIB_OEM_RSVD_SIZE 96 /* Size (bytes) of OEM RESERVED */
++ /* in OSNIB. */
++
++#define OSNIB_NVRAM_SIZE 128 /* Size (bytes) of NVRAM */
++ /* in OSNIB. */
++
++#define OSHOB_DEF_FABRIC_ERR_SIZE 50 /* In DWORDS. */
++ /* Fabric error log size (in DWORDS).*/
++ /* From offs 0x44 to 0x10C. */
++ /* Used in default OSHOB. */
++
++#define OSHOB_FABRIC_ERROR1_SIZE 12 /* 1st part of Fabric error dump. */
++ /* Used in extended OSHOB. */
++
++#define OSHOB_FABRIC_ERROR2_SIZE 9 /* 2nd part of Fabric error dump. */
++ /* Used in extended OSHOB. */
++
++#define OSHOB_RESERVED_DEBUG_SIZE 5 /* Reserved for debug */
++
++/* Size (bytes) of the default OSHOB structure. Includes the default OSNIB */
++/* size. */
++#define OSHOB_SIZE (68 + (4*OSHOB_SCU_BUF_BASE_DW_SIZE) + \
++ (4*OSHOB_DEF_FABRIC_ERR_SIZE)) /* In bytes. */
++
++#define OSHOB_MRFLD_SIZE (68 + (4*OSHOB_SCU_BUF_MRFLD_DW_SIZE) + \
++ (4*OSHOB_DEF_FABRIC_ERR_MRFLD_SIZE))/* In bytes. */
++
++/* SCU buffer size is give in dwords. So it is x4 here to get the total */
++/* number of bytes. */
++
++#define SCU_TRACE_HEADER_SIZE 16 /* SCU trace header */
++
++#define CHAABI_DEBUG_DATA_SIZE 5 /* Reserved for chaabi debug */
++
++#define OSHOB_RESERVED_SIZE 184 /* Reserved */
++
++
++struct chip_reset_event {
++ int id;
++ const char *reset_ev1_name;
++ const char *reset_ev2_name;
++};
++
++static struct chip_reset_event chip_reset_events[] = {
++ { INTEL_MID_CPU_CHIP_TANGIER, "RESETSRC0", "RESETSRC1" },
++ { INTEL_MID_CPU_CHIP_CLOVERVIEW, "RESETIRQ1", "RESETIRQ2" },
++ { INTEL_MID_CPU_CHIP_PENWELL, "RESETIRQ1", "RESETIRQ2" },
++};
++
++struct osnib_target_os {
++ const char *target_os_name;
++ int id;
++};
++
++static struct osnib_target_os osnib_target_oses[] = {
++ { "main", SIGNED_MOS_ATTR },
++ { "charging", SIGNED_COS_ATTR },
++ { "recovery", SIGNED_RECOVERY_ATTR },
++ { "fastboot", SIGNED_POS_ATTR },
++ { "factory", SIGNED_FACTORY_ATTR },
++};
++
++
++struct osnib_wake_src {
++ u8 id;
++ const char *wakesrc_name;
++};
++
++static struct osnib_wake_src osnib_wake_srcs[] = {
++ { WAKE_BATT_INSERT, "battery inserted" },
++ { WAKE_PWR_BUTTON_PRESS, "power button pressed" },
++ { WAKE_RTC_TIMER, "rtc timer" },
++ { WAKE_USB_CHRG_INSERT, "usb charger inserted" },
++ { WAKE_RESERVED, "reserved" },
++ { WAKE_REAL_RESET, "real reset" },
++ { WAKE_COLD_BOOT, "cold boot" },
++ { WAKE_UNKNOWN, "unknown" },
++ { WAKE_KERNEL_WATCHDOG_RESET, "kernel watchdog reset" },
++ { WAKE_SECURITY_WATCHDOG_RESET, "security watchdog reset" },
++ { WAKE_WATCHDOG_COUNTER_EXCEEDED, "watchdog counter exceeded" },
++ { WAKE_POWER_SUPPLY_DETECTED, "power supply detected" },
++ { WAKE_FASTBOOT_BUTTONS_COMBO, "fastboot combo" },
++ { WAKE_NO_MATCHING_OSIP_ENTRY, "no matching osip entry" },
++ { WAKE_CRITICAL_BATTERY, "critical battery" },
++ { WAKE_INVALID_CHECKSUM, "invalid checksum" },
++ { WAKE_FORCED_RESET, "forced reset"},
++ { WAKE_ACDC_CHRG_INSERT, "ac charger inserted" },
++ { WAKE_PMIC_WATCHDOG_RESET, "pmic watchdog reset" },
++ { WAKE_PLATFORM_WATCHDOG_RESET, "HWWDT reset platform" },
++ { WAKE_SC_WATCHDOG_RESET, "HWWDT reset SC" },
++};
++
++
++/* OSNIB allocation. */
++struct scu_ipc_osnib {
++ u8 target_mode; /* Target mode. */
++ u8 wd_count; /* Software watchdog. */
++ u8 alarm; /* RTC alarm. */
++ u8 wakesrc; /* WAKESRC. */
++ u8 reset_ev1; /* RESETIRQ1 or RESETSRC0. */
++ u8 reset_ev2; /* RESETIRQ2 or RESETSRC1. */
++ u8 spare; /* Spare. */
++ u8 intel_reserved[OSNIB_INTEL_RSVD_SIZE]; /* INTEL RESERVED */
++ /* (offsets 7 to 30). */
++ u8 checksum; /* CHECKSUM. */
++ u8 oem_reserved[OSNIB_OEM_RSVD_SIZE]; /* OEM RESERVED */
++ /* (offsets 32 to 127). */
++ u8 nvram[OSNIB_NVRAM_SIZE]; /* NVRAM */
++ /* (offsets 128 to 255). */
++};
++
++/* Default OSHOB allocation. */
++struct scu_ipc_oshob {
++ u32 scutxl; /* SCUTxl offset position. */
++ u32 iatxl; /* IATxl offset. */
++ u32 bocv; /* BOCV offset. */
++ u8 osnibr[OSNIB_SIZE]; /* OSNIB area offset. */
++ u32 pmit; /* PMIT offset. */
++ u32 pemmcmhki; /* PeMMCMHKI offset. */
++ u32 osnibw_ptr; /* OSNIB Write at offset 0x34. */
++ u32 fab_err_log[OSHOB_DEF_FABRIC_ERR_SIZE]; /* Fabric */
++ /* error log buffer. */
++};
++
++/* Extended OSHOB allocation. version 1.3 */
++struct scu_ipc_oshob_extend {
++ u32 magic; /* MAGIC number. */
++ u8 rev_major; /* Revision major. */
++ u8 rev_minor; /* Revision minor. */
++ u16 oshob_size; /* OSHOB size. */
++ u32 nvram_addr; /* NVRAM phys addres */
++ u32 scutxl; /* SCUTxl offset position. */
++ /* If on MRFLD platform, next param may be */
++ /* shifted by */
++ /* (OSHOB_SCU_BUF_MRFLD_DW_SIZE - 1) bytes.*/
++ u32 iatxl; /* IATxl. */
++ u32 bocv; /* BOCV. */
++
++ u16 intel_size; /* Intel size (in OSNIB area). */
++ u16 oem_size; /* OEM size (of OEM area). */
++ u32 r_intel_ptr; /* Read Intel pointer. */
++ u32 w_intel_ptr; /* Write Intel pointer. */
++ u32 r_oem_ptr; /* Read OEM pointer. */
++ u32 w_oem_ptr; /* Write OEM pointer. */
++
++ u32 pmit; /* PMIT. */
++ u32 pemmcmhki; /* PeMMCMHKI. */
++
++ /* OSHOB as defined for CLOVERVIEW */
++ u32 nvram_size; /* NVRAM max size in bytes */
++ u32 fabricerrlog1[OSHOB_FABRIC_ERROR1_SIZE]; /* fabric error data */
++ u8 vrtc_alarm_dow; /* Alarm sync */
++ u8 vrtc_alarm_dom; /* Alarm sync */
++ u8 vrtc_alarm_month; /* Alarm sync */
++ u8 vrtc_alarm_year; /* Alarm sync */
++ u32 reserved_debug[OSHOB_RESERVED_DEBUG_SIZE];/* Reserved Debug data */
++ u32 reserved2; /* Reserved */
++ u32 fabricerrlog2[OSHOB_FABRIC_ERROR2_SIZE]; /* fabric error data2 */
++ u32 sculogbufferaddr; /* phys addr of scu log buffer */
++ u32 sculogbuffersize; /* size of scu log buffer */
++};
++
++/* Extended OSHOB allocation. version 1.4. */
++struct scu_ipc_oshob_extend_v14 {
++ u32 magic; /* MAGIC number. */
++ u8 rev_major; /* Revision major. */
++ u8 rev_minor; /* Revision minor. */
++ u16 oshob_size; /* OSHOB size. */
++
++ u32 scutxl; /* SCUTxl offset position. */
++ /* If on MRFLD platform, next param may be */
++ /* shifted by */
++ /* (OSHOB_SCU_BUF_MRFLD_DW_SIZE - 1) bytes.*/
++ u32 iatxl; /* IATxl. */
++ u32 bocv; /* BOCV. */
++
++ u32 osnib_ptr; /* The unique OSNIB pointer. */
++
++ u32 pmit; /* PMIT. */
++ u8 scutraceheader[SCU_TRACE_HEADER_SIZE]; /* SCU trace header */
++ u32 fabricerrlog[OSHOB_DEF_FABRIC_ERR_SIZE]; /* fabric error data */
++ u32 chaabidebugdata[CHAABI_DEBUG_DATA_SIZE]; /* fabric error data */
++ u32 pmuemergency; /* pmu emergency */
++ u32 sculogbufferaddr; /* scu log buffer address */
++ u32 sculogbuffersize; /* size of scu log buffer */
++ u32 oshob_reserved[OSHOB_RESERVED_SIZE]; /* oshob reserved */
++};
++
++struct scu_ipc_oshob_info {
++ __u32 oshob_base; /* Base address of OSHOB. Use ioremap to */
++ /* remap for access. */
++ __u8 oshob_majrev; /* Major revision number of OSHOB structure. */
++ __u8 oshob_minrev; /* Minor revision number of OSHOB structure. */
++ __u16 oshob_size; /* Total size (bytes) of OSHOB structure. */
++ __u32 scu_trace[OSHOB_SCU_BUF_BASE_DW_SIZE*4]; /* SCU trace buffer.*/
++ /* Set to max SCU buffer size (dwords) to */
++ /* adapt to MRFLD. On other platforms, only */
++ /* the first dword is stored and read. */
++ __u32 ia_trace; /* IA trace buffer. */
++ __u16 osnib_size; /* Total size (bytes) of OSNIB structure. */
++ __u16 oemnib_size; /* Total size (bytes) of OEMNIB area. */
++ __u32 osnibr_ptr; /* Pointer to Intel read zone. */
++ __u32 osnibw_ptr; /* Pointer to Intel write zone. */
++ __u32 oemnibr_ptr; /* Pointer to OEM read zone. */
++ __u32 oemnibw_ptr; /* Pointer to OEM write zone. */
++ __u32 scu_trace_buf; /* SCU extended trace buffer */
++ __u32 scu_trace_size; /* SCU extended trace buffer size */
++ __u32 nvram_addr; /* NV ram phys addr */
++ __u32 nvram_size; /* NV ram size in bytes */
++
++ int (*scu_ipc_write_osnib)(u8 *data, int len, int offset);
++ int (*scu_ipc_read_osnib)(u8 *data, int len, int offset);
++
++ int platform_type; /* Identifies the platform (list of supported */
++ /* platforms is given in intel-mid.h). */
++
++ u16 offs_add; /* The additional shift bytes to consider */
++ /* giving the offset at which the OSHOB params*/
++ /* will be read. If MRFLD it must be set to */
++ /* take into account the extra SCU dwords. */
+
+-struct scu_ipc_data {
+- u32 count; /* No. of registers */
+- u16 addr[5]; /* Register addresses */
+- u8 data[5]; /* Register data */
+- u8 mask; /* Valid for read-modify-write */
+ };
+
++/* Structure for OSHOB info */
++struct scu_ipc_oshob_info *oshob_info;
++
++static struct rpmsg_instance *ipcutil_instance;
++
++/* Mode for Audio clock */
++static DEFINE_MUTEX(osc_clk0_lock);
++static unsigned int osc_clk0_mode;
++
++int intel_scu_ipc_osc_clk(u8 clk, unsigned int khz)
++{
++ /* SCU IPC COMMAND(osc clk on/off) definition:
++ * ipc_wbuf[0] = clock to act on {0, 1, 2, 3}
++ * ipc_wbuf[1] =
++ * bit 0 - 1:on 0:off
++ * bit 1 - if 1, read divider setting from bits 3:2 as follows:
++ * bit [3:2] - 00: clk/1, 01: clk/2, 10: clk/4, 11: reserved
++ */
++ unsigned int base_freq;
++ unsigned int div;
++ u8 ipc_wbuf[2];
++ int ipc_ret;
++
++ if (clk > 3)
++ return -EINVAL;
++
++ ipc_wbuf[0] = clk;
++ ipc_wbuf[1] = 0;
++ if (khz) {
++#ifdef CONFIG_CTP_CRYSTAL_38M4
++ base_freq = 38400;
++#else
++ base_freq = 19200;
++#endif
++ div = fls(base_freq / khz) - 1;
++ if (div >= 3 || (1 << div) * khz != base_freq)
++ return -EINVAL; /* Allow only exact frequencies */
++ ipc_wbuf[1] = 0x03 | (div << 2);
++ }
++
++ ipc_ret = rpmsg_send_command(ipcutil_instance,
++ RP_OSC_CLK_CTRL, 0, ipc_wbuf, NULL, 2, 0);
++ if (ipc_ret != 0)
++ pr_err("%s: failed to set osc clk(%d) output\n", __func__, clk);
++
++ return ipc_ret;
++}
++EXPORT_SYMBOL_GPL(intel_scu_ipc_osc_clk);
++
++/*
++ * OSC_CLK_AUDIO is connected to the MSIC as well as Audience, so it should be
++ * turned on if any one of them requests it to be on and it should be turned off
++ * only if no one needs it on.
++ */
++int intel_scu_ipc_set_osc_clk0(unsigned int enable, enum clk0_mode mode)
++{
++ int ret = 0, clk_enable;
++ static const unsigned int clk_khz = 19200;
++
++ pr_info("set_clk0 request %s for Mode 0x%x\n",
++ enable ? "ON" : "OFF", mode);
++ mutex_lock(&osc_clk0_lock);
++ if (mode == CLK0_QUERY) {
++ ret = osc_clk0_mode;
++ goto out;
++ }
++ if (enable) {
++ /* if clock is already on, just add new user */
++ if (osc_clk0_mode) {
++ osc_clk0_mode |= mode;
++ goto out;
++ }
++ osc_clk0_mode |= mode;
++ pr_info("set_clk0: enabling clk, mode 0x%x\n", osc_clk0_mode);
++ clk_enable = 1;
++ } else {
++ osc_clk0_mode &= ~mode;
++ pr_info("set_clk0: disabling clk, mode 0x%x\n", osc_clk0_mode);
++ /* others using the clock, cannot turn it of */
++ if (osc_clk0_mode)
++ goto out;
++ clk_enable = 0;
++ }
++ pr_info("configuring OSC_CLK_AUDIO now\n");
++ ret = intel_scu_ipc_osc_clk(OSC_CLK_AUDIO, clk_enable ? clk_khz : 0);
++out:
++ mutex_unlock(&osc_clk0_lock);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(intel_scu_ipc_set_osc_clk0);
++
++#define MSIC_VPROG1_CTRL 0xD6
++#define MSIC_VPROG2_CTRL 0xD7
++
++#define MSIC_VPROG2_ON 0x36 /*1.200V and Auto mode*/
++#define MSIC_VPROG1_ON 0xF6 /*2.800V and Auto mode*/
++#define MSIC_VPROG_OFF 0x24 /*1.200V and OFF*/
++
++/* Defines specific of MRFLD platform (CONFIG_X86_MRFLD). */
++#define MSIC_VPROG1_MRFLD_CTRL 0xAC
++#define MSIC_VPROG2_MRFLD_CTRL 0xAD
++
++#define MSIC_VPROG1_MRFLD_ON 0xC1 /* 2.80V */
++#define MSIC_VPROG2_MRFLD_ON 0xC1 /* 2.80V */
++#define MSIC_VPROG_MRFLD_OFF 0 /* OFF */
++/* End of MRFLD specific.*/
++
++/* Helpers to turn on/off msic vprog1 and vprog2 */
++int intel_scu_ipc_msic_vprog1(int on)
++{
++ if (oshob_info->platform_type == INTEL_MID_CPU_CHIP_TANGIER)
++ return intel_scu_ipc_iowrite8(MSIC_VPROG1_MRFLD_CTRL,
++ on ? MSIC_VPROG1_MRFLD_ON : MSIC_VPROG_MRFLD_OFF);
++ else
++ return intel_scu_ipc_iowrite8(MSIC_VPROG1_CTRL,
++ on ? MSIC_VPROG1_ON : MSIC_VPROG_OFF);
++}
++EXPORT_SYMBOL_GPL(intel_scu_ipc_msic_vprog1);
++
++int intel_scu_ipc_msic_vprog2(int on)
++{
++ if (oshob_info->platform_type == INTEL_MID_CPU_CHIP_TANGIER)
++ return intel_scu_ipc_iowrite8(MSIC_VPROG2_MRFLD_CTRL,
++ on ? MSIC_VPROG2_MRFLD_ON : MSIC_VPROG_MRFLD_OFF);
++ else
++ return intel_scu_ipc_iowrite8(MSIC_VPROG2_CTRL,
++ on ? MSIC_VPROG2_ON : MSIC_VPROG_OFF);
++}
++EXPORT_SYMBOL_GPL(intel_scu_ipc_msic_vprog2);
++
+ /**
+ * scu_reg_access - implement register access ioctls
+ * @cmd: command we are doing (read/write/update)
+@@ -49,22 +449,169 @@ struct scu_ipc_data {
+
+ static int scu_reg_access(u32 cmd, struct scu_ipc_data *data)
+ {
+- int count = data->count;
++ int ret;
+
+- if (count == 0 || count == 3 || count > 4)
++ if (data->count == 0 || data->count > 5)
+ return -EINVAL;
+
+ switch (cmd) {
+- case INTE_SCU_IPC_REGISTER_READ:
+- return intel_scu_ipc_readv(data->addr, data->data, count);
+- case INTE_SCU_IPC_REGISTER_WRITE:
+- return intel_scu_ipc_writev(data->addr, data->data, count);
+- case INTE_SCU_IPC_REGISTER_UPDATE:
+- return intel_scu_ipc_update_register(data->addr[0],
+- data->data[0], data->mask);
++ case INTEL_SCU_IPC_REGISTER_READ:
++ ret = intel_scu_ipc_readv(data->addr, data->data, data->count);
++ break;
++ case INTEL_SCU_IPC_REGISTER_WRITE:
++ ret = intel_scu_ipc_writev(data->addr, data->data, data->count);
++ break;
++ case INTEL_SCU_IPC_REGISTER_UPDATE:
++ ret = intel_scu_ipc_update_register(data->addr[0],
++ data->data[0],
++ data->mask);
++ break;
+ default:
+ return -ENOTTY;
+ }
++ return ret;
++}
++
++#define check_pmdb_sub_cmd(x) (x == PMDB_SUB_CMD_R_OTPCTL || \
++ x == PMDB_SUB_CMD_R_WMDB || x == PMDB_SUB_CMD_W_WMDB || \
++ x == PMDB_SUB_CMD_R_OTPDB || x == PMDB_SUB_CMD_W_OTPDB)
++#define pmdb_sub_cmd_is_read(x) (x == PMDB_SUB_CMD_R_OTPCTL || \
++ x == PMDB_SUB_CMD_R_WMDB || x == PMDB_SUB_CMD_R_OTPDB)
++
++static int check_pmdb_buffer(struct scu_ipc_pmdb_buffer *p_buf)
++{
++ int size;
++
++ switch (p_buf->sub) {
++ case PMDB_SUB_CMD_R_WMDB:
++ case PMDB_SUB_CMD_W_WMDB:
++ size = PMDB_WMDB_SIZE;
++ break;
++ case PMDB_SUB_CMD_R_OTPDB:
++ case PMDB_SUB_CMD_W_OTPDB:
++ size = PMDB_OTPDB_SIZE;
++ break;
++ case PMDB_SUB_CMD_R_OTPCTL:
++ size = PMDB_OTPCTL_SIZE;
++ break;
++ default:
++ size = 0;
++ }
++
++ return check_pmdb_sub_cmd(p_buf->sub) &&
++ (p_buf->count + p_buf->offset < size) &&
++ (p_buf->count % 4 == 0);
++}
++
++/**
++ * scu_pmdb_access - access PMDB data through SCU IPC cmds
++ * @p_buf: PMDB access buffer, it describe the data to write/read.
++ * p_buf->sub - SCU IPC sub cmd of PMDB access,
++ * this sub cmd distinguish different componet
++ * in PMDB which to be accessd. (WMDB, OTPDB, OTPCTL)
++ * p_buf->count - access data's count;
++ * p_buf->offset - access data's offset for each component in PMDB;
++ * p_buf->data - data to write/read.
++ *
++ * Write/read data to/from PMDB.
++ *
++ */
++static int scu_pmdb_access(struct scu_ipc_pmdb_buffer *p_buf)
++{
++ int i, offset, ret = -EINVAL;
++ u8 *p_data;
++
++ if (!check_pmdb_buffer(p_buf)) {
++ pr_err("Invalid PMDB buffer!\n");
++ return -EINVAL;
++ }
++
++ /* 1. we use rpmsg_send_raw_command() IPC cmd interface
++ * to access PMDB data. Each call of rpmsg_send_raw_command()
++ * can only access at most PMDB_ACCESS_SIZE bytes' data.
++ * 2. There are two kinds of pmdb sub commands, read command
++ * and write command. For read command, we must transport
++ * in and out buffer to rpmsg_send_raw_command(), because
++ * in buffer length is pass as access length which must
++ * be transported to SCU.
++ */
++ p_data = p_buf->data;
++ offset = p_buf->offset;
++ for (i = 0; i < p_buf->count/PMDB_ACCESS_SIZE; i++) {
++ if (pmdb_sub_cmd_is_read(p_buf->sub))
++ ret = rpmsg_send_raw_command(ipcutil_instance,
++ RP_PMDB, p_buf->sub,
++ p_data, (u32 *)p_data,
++ PMDB_ACCESS_SIZE, PMDB_ACCESS_SIZE / 4,
++ 0, offset);
++ else
++ ret = rpmsg_send_raw_command(ipcutil_instance,
++ RP_PMDB, p_buf->sub,
++ p_data, NULL, PMDB_ACCESS_SIZE,
++ 0, 0, offset);
++ if (ret < 0) {
++ pr_err("intel_scu_ipc_raw_cmd failed!\n");
++ return ret;
++ }
++ offset += PMDB_ACCESS_SIZE;
++ p_data += PMDB_ACCESS_SIZE;
++ }
++ if (p_buf->count % PMDB_ACCESS_SIZE > 0) {
++ if (pmdb_sub_cmd_is_read(p_buf->sub))
++ ret = rpmsg_send_raw_command(ipcutil_instance,
++ RP_PMDB, p_buf->sub,
++ p_data, (u32 *)p_data,
++ p_buf->count % PMDB_ACCESS_SIZE,
++ (p_buf->count % PMDB_ACCESS_SIZE) / 4,
++ 0, offset);
++ else
++ ret = rpmsg_send_raw_command(ipcutil_instance,
++ RP_PMDB, p_buf->sub,
++ p_data, NULL,
++ p_buf->count % PMDB_ACCESS_SIZE,
++ 0, 0, offset);
++ if (ret < 0) {
++ pr_err("intel_scu_ipc_raw_cmd failed!\n");
++ return ret;
++ }
++ }
++
++ return 0;
++}
++
++static int do_pmdb_user_buf_access(void __user *argp)
++{
++ int ret;
++ struct scu_ipc_pmdb_buffer *p_buf;
++
++ p_buf = kzalloc(sizeof(struct scu_ipc_pmdb_buffer), GFP_KERNEL);
++ if (p_buf == NULL) {
++ pr_err("failed to allocate memory for pmdb buffer!\n");
++ return -ENOMEM;
++ }
++
++ ret = copy_from_user(p_buf, argp, sizeof(struct scu_ipc_pmdb_buffer));
++ if (ret < 0) {
++ pr_err("copy from user failed!!\n");
++ goto err;
++ }
++
++ ret = scu_pmdb_access(p_buf);
++ if (ret < 0) {
++ pr_err("scu_pmdb_access error!\n");
++ goto err;
++ }
++
++ if (pmdb_sub_cmd_is_read(p_buf->sub)) {
++ ret = copy_to_user(argp + 3 * sizeof(u32),
++ p_buf->data, p_buf->count);
++ if (ret < 0)
++ pr_err("copy to user failed!!\n");
++ }
++
++err:
++ kfree(p_buf);
++ return ret;
+ }
+
+ /**
+@@ -78,43 +625,2003 @@ static int scu_reg_access(u32 cmd, struct scu_ipc_data *data)
+ static long scu_ipc_ioctl(struct file *fp, unsigned int cmd,
+ unsigned long arg)
+ {
+- int ret;
++ int ret = -EINVAL;
+ struct scu_ipc_data data;
+ void __user *argp = (void __user *)arg;
+
+- if (!capable(CAP_SYS_RAWIO))
++ /* Only IOCTL cmd allowed to pass through without capability check */
++ /* is getting fw version info, all others need to check to prevent */
++ /* arbitrary access to all sort of bit of the hardware exposed here*/
++
++ if ((cmd != INTEL_SCU_IPC_FW_REVISION_GET &&
++ cmd != INTEL_SCU_IPC_FW_REVISION_EXT_GET &&
++ cmd != INTEL_SCU_IPC_S0IX_RESIDENCY) &&
++ !capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+- if (copy_from_user(&data, argp, sizeof(struct scu_ipc_data)))
+- return -EFAULT;
+- ret = scu_reg_access(cmd, &data);
++ switch (cmd) {
++ case INTEL_SCU_IPC_S0IX_RESIDENCY:
++ {
++ void __iomem *s0ix_residencies_addr;
++ u8 dump_results[ALL_RESIDENCY_DATA_SIZE] = {0};
++ u32 cmd_id;
++
++ if (copy_from_user(&cmd_id, argp, sizeof(u32))) {
++ pr_err("copy from user failed!!\n");
++ return -EFAULT;
++ }
++
++ /* Check get residency counter valid cmd range */
++
++ if (cmd_id > IPC_RESIDENCY_CMD_ID_DUMP) {
++ pr_err("invalid si0x residency sub-cmd id!\n");
++ return -EINVAL;
++ }
++
++ ret = rpmsg_send_simple_command(ipcutil_instance,
++ RP_S0IX_COUNTER, cmd_id);
++
++ if (ret < 0) {
++ pr_err("ipc_get_s0ix_counter failed!\n");
++ return ret;
++ }
++
++ if (cmd_id == IPC_RESIDENCY_CMD_ID_DUMP) {
++ s0ix_residencies_addr = ioremap_nocache(
++ SRAM_ADDR_S0IX_RESIDENCY,
++ ALL_RESIDENCY_DATA_SIZE);
++
++ if (!s0ix_residencies_addr) {
++ pr_err("ioremap SRAM address failed!!\n");
++ return -EFAULT;
++ }
++
++ memcpy(&dump_results[0], s0ix_residencies_addr,
++ ALL_RESIDENCY_DATA_SIZE);
++
++ iounmap(s0ix_residencies_addr);
++ ret = copy_to_user(argp, &dump_results[0],
++ ALL_RESIDENCY_DATA_SIZE);
++ }
++
++ break;
++ }
++ case INTEL_SCU_IPC_READ_RR_FROM_OSNIB:
++ {
++ u8 reboot_reason;
++ ret = intel_scu_ipc_read_osnib_rr(&reboot_reason);
++ if (ret < 0)
++ return ret;
++ ret = copy_to_user(argp, &reboot_reason, 1);
++ break;
++ }
++ case INTEL_SCU_IPC_WRITE_RR_TO_OSNIB:
++ {
++ u8 data;
++
++ ret = copy_from_user(&data, (u8 *)arg, 1);
++ if (ret < 0) {
++ pr_err("copy from user failed!!\n");
++ return ret;
++ }
++ ret = intel_scu_ipc_write_osnib_rr(data);
++ break;
++ }
++ case INTEL_SCU_IPC_WRITE_ALARM_FLAG_TO_OSNIB:
++ {
++ u8 flag, data;
++ ret = copy_from_user(&flag, (u8 *)arg, 1);
++ if (ret < 0) {
++ pr_err("copy from user failed!!\n");
++ return ret;
++ }
++
++ ret = oshob_info->scu_ipc_read_osnib(
++ &data,
++ 1,
++ offsetof(struct scu_ipc_osnib, alarm));
++
++ if (ret < 0)
++ return ret;
++ if (flag) {
++ data = data | 0x1; /* set alarm flag */
++ pr_info("scu_ipc_ioctl: set alarm flag\n");
++ } else {
++ data = data & 0xFE; /* clear alarm flag */
++ pr_info("scu_ipc_ioctl: clear alarm flag\n");
++ }
++
++ ret = oshob_info->scu_ipc_write_osnib(
++ &data,
++ 1,
++ offsetof(struct scu_ipc_osnib, alarm));
++
++ break;
++ }
++ case INTEL_SCU_IPC_READ_VBATTCRIT:
++ {
++ u32 value = 0;
++
++ pr_info("cmd = INTEL_SCU_IPC_READ_VBATTCRIT");
++ ret = intel_scu_ipc_read_mip((u8 *)&value, 4, 0x318, 1);
++ if (ret < 0)
++ return ret;
++ pr_info("VBATTCRIT VALUE = %x\n", value);
++ ret = copy_to_user(argp, &value, 4);
++ break;
++ }
++ case INTEL_SCU_IPC_FW_REVISION_GET:
++ case INTEL_SCU_IPC_FW_REVISION_EXT_GET:
++ {
++ struct scu_ipc_version version;
++
++ if (copy_from_user(&version, argp, sizeof(u32)))
++ return -EFAULT;
++
++ if (version.count > 16)
++ return -EINVAL;
++
++ ret = rpmsg_send_command(ipcutil_instance, RP_GET_FW_REVISION,
++ cmd & 0x1, NULL, (u32 *)version.data, 0, 4);
++ if (ret < 0)
++ return ret;
++
++ if (copy_to_user(argp + sizeof(u32),
++ version.data, version.count))
++ ret = -EFAULT;
++ break;
++ }
++ case INTEL_SCU_IPC_OSC_CLK_CNTL:
++ {
++ struct osc_clk_t osc_clk;
++
++ if (copy_from_user(&osc_clk, argp, sizeof(struct osc_clk_t)))
++ return -EFAULT;
++
++ ret = intel_scu_ipc_osc_clk(osc_clk.id, osc_clk.khz);
++ if (ret)
++ pr_err("%s: failed to set osc clk\n", __func__);
++
++ break;
++ }
++ case INTEL_SCU_IPC_PMDB_ACCESS:
++ {
++ ret = do_pmdb_user_buf_access(argp);
++
++ break;
++ }
++ default:
++ if (copy_from_user(&data, argp, sizeof(struct scu_ipc_data)))
++ return -EFAULT;
++ ret = scu_reg_access(cmd, &data);
++ if (ret < 0)
++ return ret;
++ if (copy_to_user(argp, &data, sizeof(struct scu_ipc_data)))
++ return -EFAULT;
++ return 0;
++ }
++
++ return ret;
++}
++
++int intel_scu_ipc_get_oshob_base(void)
++{
++ if (oshob_info == NULL)
++ return NULL;
++
++ return oshob_info->oshob_base;
++}
++EXPORT_SYMBOL_GPL(intel_scu_ipc_get_oshob_base);
++
++int intel_scu_ipc_get_oshob_size(void)
++{
++ if (oshob_info == NULL)
++ return 0;
++
++ return oshob_info->oshob_size;
++}
++EXPORT_SYMBOL_GPL(intel_scu_ipc_get_oshob_size);
++
++int intel_scu_ipc_read_oshob(u8 *data, int len, int offset)
++{
++ int ret = 0, i;
++ void __iomem *oshob_addr;
++ u8 *ptr = data;
++
++ oshob_addr = ioremap_nocache(
++ oshob_info->oshob_base,
++ oshob_info->oshob_size);
++
++ if (!oshob_addr) {
++ pr_err("ipc_read_oshob: addr ioremap failed!\n");
++ ret = -ENOMEM;
++ goto exit;
++ }
++
++ for (i = 0; i < len; i = i+1) {
++ *ptr = readb(oshob_addr + offset + i);
++ pr_debug("addr(remapped)=%8x, offset=%2x, value=%2x\n",
++ (u32)(oshob_addr + i),
++ offset + i, *ptr);
++ ptr++;
++ }
++
++ iounmap(oshob_addr);
++exit:
++ return ret;
++}
++
++EXPORT_SYMBOL_GPL(intel_scu_ipc_read_oshob);
++
++/* This function is used for the default OSNIB. */
++int intel_scu_ipc_read_osnib(u8 *data, int len, int offset)
++{
++ int i, ret = 0;
++ u32 osnibw_ptr;
++ u8 *ptr, check = 0;
++ u16 struct_offs;
++ void __iomem *oshob_addr, *osnibr_addr, *osnibw_addr;
++
++ pr_debug("OSHOB base addr value is %x\n", oshob_info->oshob_base);
++ oshob_addr = ioremap_nocache(oshob_info->oshob_base,
++ oshob_info->oshob_size);
++ if (!oshob_addr) {
++ pr_err("ioremap failed!\n");
++ ret = -ENOMEM;
++ goto exit;
++ }
++
++ struct_offs = offsetof(struct scu_ipc_oshob, osnibr) +
++ oshob_info->offs_add;
++ osnibr_addr = oshob_addr + struct_offs;
++
++ if (!osnibr_addr) {
++ pr_err("Bad osnib address!\n");
++ ret = -EFAULT;
++ iounmap(oshob_addr);
++ goto exit;
++ }
++
++ pr_debug("OSNIB read addr (remapped) is %x\n",
++ (unsigned int)osnibr_addr);
++
++ /* Make a chksum verification for osnib */
++ for (i = 0; i < oshob_info->osnib_size; i++)
++ check += readb(osnibr_addr + i);
++ if (check) {
++ pr_err("WARNING!!! osnib chksum verification faild, reset all osnib data!\n");
++ struct_offs = offsetof(struct scu_ipc_oshob, osnibw_ptr) +
++ oshob_info->offs_add;
++ osnibw_ptr = readl(oshob_addr + struct_offs);
++ osnibw_addr = ioremap_nocache(
++ osnibw_ptr, oshob_info->osnib_size);
++ if (osnibw_addr) {
++ for (i = 0; i < oshob_info->osnib_size; i++)
++ writeb(0, osnibw_addr + i);
++ rpmsg_send_raw_command(ipcutil_instance,
++ RP_WRITE_OSNIB, 0,
++ NULL, NULL, 0, 0,
++ 0xFFFFFFFF, 0);
++ iounmap(osnibw_addr);
++ }
++ }
++
++ ptr = data;
++ for (i = 0; i < len; i++) {
++ *ptr = readb(osnibr_addr + offset + i);
++ pr_debug("addr(remapped)=%8x, offset=%2x, value=%2x\n",
++ (u32)(osnibr_addr+offset+i), offset+i, *ptr);
++ ptr++;
++ }
++
++ iounmap(oshob_addr);
++exit:
++ return ret;
++}
++
++/* This function is used for the default OSNIB. */
++int intel_scu_ipc_write_osnib(u8 *data, int len, int offset)
++{
++ int i;
++ int ret = 0;
++ u32 osnibw_ptr;
++ u8 osnib_data[oshob_info->osnib_size];
++ u8 check = 0, chksum = 0;
++ u16 struct_offs;
++ void __iomem *oshob_addr, *osnibw_addr, *osnibr_addr;
++
++ pr_debug("OSHOB base addr value is 0x%8x\n", oshob_info->oshob_base);
++
++ rpmsg_global_lock();
++
++ oshob_addr = ioremap_nocache(oshob_info->oshob_base,
++ oshob_info->oshob_size);
++ if (!oshob_addr) {
++ pr_err("ioremap failed!\n");
++ ret = -ENOMEM;
++ goto exit;
++ }
++
++ /*Dump osnib data for generate chksum */
++ struct_offs = offsetof(struct scu_ipc_oshob, osnibr) +
++ oshob_info->offs_add;
++ osnibr_addr = oshob_addr + struct_offs;
++
++ pr_debug("OSNIB read addr (remapped) in OSHOB at %x\n",
++ (unsigned int)osnibr_addr);
++
++ for (i = 0; i < oshob_info->osnib_size; i++) {
++ osnib_data[i] = readb(osnibr_addr + i);
++ check += osnib_data[i];
++ }
++ memcpy(osnib_data + offset, data, len);
++
++ if (check) {
++ pr_err("WARNING!!! OSNIB data chksum verification FAILED!\n");
++ } else {
++ /* generate chksum */
++ for (i = 0; i < oshob_info->osnib_size - 1; i++)
++ chksum += osnib_data[i];
++ osnib_data[oshob_info->osnib_size - 1] = ~chksum + 1;
++ }
++
++ struct_offs = offsetof(struct scu_ipc_oshob, osnibw_ptr) +
++ oshob_info->offs_add;
++ osnibw_ptr = readl(oshob_addr + struct_offs);
++ if (osnibw_ptr == 0) { /* workaround here for BZ 2914 */
++ osnibw_ptr = 0xFFFF3400;
++ pr_err("ERR: osnibw ptr from oshob is 0, manually set it here\n");
++ }
++
++ pr_debug("POSNIB write address: %x\n", osnibw_ptr);
++
++ osnibw_addr = ioremap_nocache(osnibw_ptr, oshob_info->osnib_size);
++ if (!osnibw_addr) {
++ pr_err("ioremap failed!\n");
++ ret = -ENOMEM;
++ goto unmap_oshob_addr;
++ }
++
++ for (i = 0; i < oshob_info->osnib_size; i++)
++ writeb(*(osnib_data + i), (osnibw_addr + i));
++
++ ret = rpmsg_send_raw_command(ipcutil_instance,
++ RP_WRITE_OSNIB, 0,
++ NULL, NULL, 0, 0,
++ 0xFFFFFFFF, 0);
+ if (ret < 0)
+- return ret;
+- if (copy_to_user(argp, &data, sizeof(struct scu_ipc_data)))
+- return -EFAULT;
+- return 0;
++ pr_err("ipc_write_osnib failed!!\n");
++
++ iounmap(osnibw_addr);
++
++unmap_oshob_addr:
++ iounmap(oshob_addr);
++exit:
++ rpmsg_global_unlock();
++
++ return ret;
+ }
+
+-static const struct file_operations scu_ipc_fops = {
+- .unlocked_ioctl = scu_ipc_ioctl,
+-};
++/* This function is used for the extended OSHOB/OSNIB. */
++int intel_scu_ipc_read_osnib_extend(u8 *data, int len, int offset)
++{
++ int i, ret = 0;
++ u8 *ptr, check = 0;
++ void __iomem *oshob_addr, *osnibr_addr, *osnibw_addr;
++ u32 sptr_dw_mask;
+
+-static int __init ipc_module_init(void)
++ oshob_addr = ioremap_nocache(oshob_info->oshob_base,
++ oshob_info->oshob_size);
++ if (!oshob_addr) {
++ pr_err("ipc_read_osnib_extend: ioremap failed!\n");
++ ret = -ENOMEM;
++ goto exit;
++ }
++
++ pr_debug(
++ "ipc_read_osnib_extend: remap OSNIB addr=0x%x size %d\n",
++ oshob_info->osnibr_ptr, oshob_info->osnib_size);
++
++ osnibr_addr = ioremap_nocache(oshob_info->osnibr_ptr,
++ oshob_info->osnib_size);
++
++ if (!osnibr_addr) {
++ pr_err("ipc_read_osnib_extend: ioremap of osnib failed!\n");
++ ret = -ENOMEM;
++ goto unmap_oshob_addr;
++ }
++
++ /* Make a chksum verification for osnib */
++ for (i = 0; i < oshob_info->osnib_size; i++)
++ check += readb(osnibr_addr + i);
++
++ if (check) {
++ pr_err("ipc_read_osnib_extend: WARNING!!! osnib chksum verification faild, reset all osnib data!\n");
++ pr_debug(
++ "ipc_read_osnib_extend: remap osnibw ptr addr=0x%x size %d\n",
++ oshob_info->osnibw_ptr, oshob_info->osnib_size);
++
++ osnibw_addr = ioremap_nocache(oshob_info->osnibw_ptr,
++ oshob_info->osnib_size);
++ if (!osnibw_addr) {
++ pr_err("ipc_read_osnib_extend: cannot remap osnib write ptr\n");
++ goto unmap_oshob_addr;
++ }
++
++ for (i = 0; i < oshob_info->osnib_size; i++)
++ writeb(0, osnibw_addr + i);
++
++ /* Send command. The mask to be written identifies which */
++ /* double words of the OSNIB osnib_size bytes will be written.*/
++ /* So the mask is coded on 4 bytes. */
++ sptr_dw_mask = 0xFFFFFFFF;
++ rpmsg_send_raw_command(ipcutil_instance,
++ RP_WRITE_OSNIB,
++ 0, NULL, NULL, 0, 0, sptr_dw_mask, 0);
++ iounmap(osnibw_addr);
++ }
++
++ ptr = data;
++ pr_debug("ipc_read_osnib_extend: OSNIB content:\n");
++ for (i = 0; i < len; i++) {
++ *ptr = readb(osnibr_addr + offset + i);
++ pr_debug("addr(remapped)=%8x, offset=%2x, value=%2x\n",
++ (u32)(osnibr_addr+offset+i), offset+i, *ptr);
++ ptr++;
++ }
++
++ iounmap(osnibr_addr);
++
++unmap_oshob_addr:
++ iounmap(oshob_addr);
++exit:
++ return ret;
++}
++
++/* This function is used for the extended OSHOB/OSNIB. */
++int intel_scu_ipc_write_osnib_extend(u8 *data, int len, int offset)
+ {
+- major = register_chrdev(0, "intel_mid_scu", &scu_ipc_fops);
+- if (major < 0)
+- return major;
++ int i;
++ int ret = 0;
++ u8 *posnib_data, *ptr;
++ u8 check = 0, chksum = 0;
++ void __iomem *oshob_addr, *osnibw_addr, *osnibr_addr;
++ u32 sptr_dw_mask;
+
+- return 0;
++ rpmsg_global_lock();
++
++ pr_debug(
++ "ipc_write_osnib_extend: remap OSHOB addr 0x%8x size %d\n",
++ oshob_info->oshob_base, oshob_info->oshob_size);
++
++ oshob_addr = ioremap_nocache(oshob_info->oshob_base,
++ oshob_info->oshob_size);
++ if (!oshob_addr) {
++ pr_err("ipc_write_osnib_extend: ioremap failed!\n");
++ ret = -ENOMEM;
++ goto exit;
++ }
++
++ osnibr_addr = ioremap_nocache(oshob_info->osnibr_ptr,
++ oshob_info->osnib_size);
++
++ if (!osnibr_addr) {
++ pr_err("ipc_write_osnib_extend: ioremap of osnib failed!\n");
++ ret = -ENOMEM;
++ goto unmap_oshob_addr;
++ }
++
++ /* Dump osnib data for generate chksum */
++ posnib_data = kzalloc(oshob_info->osnib_size, GFP_KERNEL);
++
++ if (posnib_data == NULL) {
++ pr_err("ipc_write_osnib_extend: The buffer for getting OSNIB is NULL\n");
++ ret = -EFAULT;
++ iounmap(osnibr_addr);
++ goto unmap_oshob_addr;
++ }
++
++ ptr = posnib_data;
++ for (i = 0; i < oshob_info->osnib_size; i++) {
++ *ptr = readb(osnibr_addr + i);
++ check += *ptr;
++ ptr++;
++ }
++
++ memcpy(posnib_data + offset, data, len);
++
++ if (check) {
++ pr_err("ipc_write_osnib_extend: WARNING!!! OSNIB data chksum verification FAILED!\n");
++ } else {
++ /* generate chksum. */
++ pr_debug("ipc_write_osnib_extend: generating checksum\n");
++ for (i = 0; i < oshob_info->osnib_size - 1; i++)
++ chksum += *(posnib_data + i);
++ /* Fill checksum at the CHECKSUM offset place in OSNIB. */
++ *(posnib_data +
++ offsetof(struct scu_ipc_osnib, checksum)) = ~chksum + 1;
++ }
++
++ pr_debug(
++ "ipc_write_osnib_extend: remap osnibw ptr addr=0x%x size %d\n",
++ oshob_info->osnibw_ptr, oshob_info->osnib_size);
++
++ osnibw_addr = ioremap_nocache(oshob_info->osnibw_ptr,
++ oshob_info->osnib_size);
++ if (!osnibw_addr) {
++ pr_err("scu_ipc_write_osnib_extend: ioremap failed!\n");
++ ret = -ENOMEM;
++ goto exit_osnib;
++ }
++
++ for (i = 0; i < oshob_info->osnib_size; i++)
++ writeb(*(posnib_data + i), (osnibw_addr + i));
++
++ /* Send command. The mask to be written identifies which */
++ /* double words of the OSNIB osnib_size bytes will be written.*/
++ /* So the mask is coded on 4 bytes. */
++ sptr_dw_mask = 0xFFFFFFFF;
++ ret = rpmsg_send_raw_command(ipcutil_instance,
++ RP_WRITE_OSNIB, 0, NULL, NULL,
++ 0, 0, sptr_dw_mask, 0);
++ if (ret < 0)
++ pr_err("scu_ipc_write_osnib_extend: ipc_write_osnib failed!!\n");
++
++ iounmap(osnibw_addr);
++
++exit_osnib:
++ iounmap(osnibr_addr);
++
++ kfree(posnib_data);
++
++unmap_oshob_addr:
++ iounmap(oshob_addr);
++exit:
++ rpmsg_global_unlock();
++
++ return ret;
++}
++
++/*
++ * This writes the reboot reason in the OSNIB (factor and avoid any overlap)
++ */
++int intel_scu_ipc_write_osnib_rr(u8 rr)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(osnib_target_oses); i++) {
++ if (osnib_target_oses[i].id == rr) {
++ pr_info("intel_scu_ipc_write_osnib_rr: reboot reason: %s\n",
++ osnib_target_oses[i].target_os_name);
++ return oshob_info->scu_ipc_write_osnib(
++ &rr,
++ 1,
++ offsetof(struct scu_ipc_osnib, target_mode));
++ }
++ }
++
++ pr_warn("intel_scu_ipc_write_osnib_rr: reboot reason [0x%x] not found\n",
++ rr);
++ return -1;
++}
++EXPORT_SYMBOL_GPL(intel_scu_ipc_write_osnib_rr);
++
++/*
++ * This reads the reboot reason from the OSNIB (factor)
++ */
++int intel_scu_ipc_read_osnib_rr(u8 *rr)
++{
++ pr_debug("intel_scu_ipc_read_osnib_rr: read reboot reason\n");
++ return oshob_info->scu_ipc_read_osnib(
++ rr,
++ 1,
++ offsetof(struct scu_ipc_osnib, target_mode));
++}
++EXPORT_SYMBOL_GPL(intel_scu_ipc_read_osnib_rr);
++
++
++int intel_scu_ipc_read_oshob_extend_param(void __iomem *poshob_addr)
++{
++ u16 struct_offs;
++ int buff_size;
++
++ /* Get defined OSNIB space size. */
++ oshob_info->osnib_size = readw(
++ poshob_addr +
++ offsetof(struct scu_ipc_oshob_extend, intel_size));
++
++ if (oshob_info->osnib_size == 0) {
++ pr_err("ipc_read_oshob_extend_param: OSNIB size is null!\n");
++ return -EFAULT;
++ }
++
++ /* Get defined OEM space size. */
++ oshob_info->oemnib_size = readw(
++ poshob_addr +
++ offsetof(struct scu_ipc_oshob_extend, oem_size));
++
++ if (oshob_info->oemnib_size == 0) {
++ pr_err("ipc_read_oshob_extend_param: OEMNIB size is null!\n");
++ return -EFAULT;
++ }
++
++ /* Set SCU and IA trace buffers. Size calculated in bytes here. */
++ if (oshob_info->platform_type == INTEL_MID_CPU_CHIP_TANGIER)
++ buff_size = OSHOB_SCU_BUF_MRFLD_DW_SIZE*4;
++ else
++ buff_size = OSHOB_SCU_BUF_BASE_DW_SIZE*4;
++
++ intel_scu_ipc_read_oshob(
++ (u8 *)(oshob_info->scu_trace),
++ buff_size,
++ offsetof(struct scu_ipc_oshob_extend, scutxl));
++
++ struct_offs = offsetof(struct scu_ipc_oshob_extend, iatxl) +
++ oshob_info->offs_add;
++ oshob_info->ia_trace = readl(poshob_addr + struct_offs);
++
++ /* Set pointers */
++ struct_offs = offsetof(struct scu_ipc_oshob_extend, r_intel_ptr) +
++ oshob_info->offs_add;
++ oshob_info->osnibr_ptr = readl(poshob_addr + struct_offs);
++
++ if (!oshob_info->osnibr_ptr) {
++ pr_err("ipc_read_oshob_extend_param: R_INTEL_POINTER is NULL!\n");
++ return -ENOMEM;
++ }
++
++ struct_offs = offsetof(struct scu_ipc_oshob_extend, w_intel_ptr) +
++ oshob_info->offs_add;
++ oshob_info->osnibw_ptr = readl(poshob_addr + struct_offs);
++
++ if (oshob_info->osnibw_ptr == 0) {
++ /* workaround here for BZ 2914 */
++ oshob_info->osnibw_ptr = 0xFFFF3400;
++ pr_err(
++ "ipc_read_oshob_extend_param: ERR: osnibw from oshob is 0, manually set it here\n");
++ }
++
++ pr_info("(extend oshob) osnib read ptr = 0x%8x\n",
++ oshob_info->osnibr_ptr);
++ pr_info("(extend oshob) osnib write ptr = 0x%8x\n",
++ oshob_info->osnibw_ptr);
++
++ struct_offs = offsetof(struct scu_ipc_oshob_extend, r_oem_ptr) +
++ oshob_info->offs_add;
++ oshob_info->oemnibr_ptr = readl(poshob_addr + struct_offs);
++
++ if (!oshob_info->oemnibr_ptr) {
++ pr_err("ipc_read_oshob_extend_param: R_OEM_POINTER is NULL!\n");
++ return -ENOMEM;
++ }
++
++ struct_offs = offsetof(struct scu_ipc_oshob_extend, w_oem_ptr) +
++ oshob_info->offs_add;
++ oshob_info->oemnibw_ptr = readl(poshob_addr + struct_offs);
++
++ if (!oshob_info->oemnibw_ptr) {
++ pr_err("ipc_read_oshob_extend_param: W_OEM_POINTER is NULL!\n");
++ return -ENOMEM;
++ }
++
++ oshob_info->scu_ipc_write_osnib =
++ &intel_scu_ipc_write_osnib_extend;
++ oshob_info->scu_ipc_read_osnib =
++ &intel_scu_ipc_read_osnib_extend;
++
++ pr_info(
++ "Using extended oshob structure size = %d bytes\n",
++ oshob_info->oshob_size);
++ pr_info(
++ "OSNIB Intel size = %d bytes OEMNIB size = %d bytes\n",
++ oshob_info->osnib_size, oshob_info->oemnib_size);
++
++ if (oshob_info->platform_type == INTEL_MID_CPU_CHIP_CLOVERVIEW) {
++ if ((oshob_info->oshob_majrev >= 1) &&
++ (oshob_info->oshob_minrev >= 1)) {
++ /* CLVP and correct version of the oshob. */
++ oshob_info->scu_trace_buf =
++ readl(poshob_addr +
++ offsetof(struct scu_ipc_oshob_extend,
++ sculogbufferaddr));
++ oshob_info->scu_trace_size =
++ readl(poshob_addr +
++ offsetof(struct scu_ipc_oshob_extend,
++ sculogbuffersize));
++ }
++ if ((oshob_info->oshob_majrev >= 1) &&
++ (oshob_info->oshob_minrev >= 3)) {
++ /* CLVP and correct version of the oshob. */
++ oshob_info->nvram_addr =
++ readl(poshob_addr +
++ offsetof(struct scu_ipc_oshob_extend,
++ nvram_addr));
++ oshob_info->nvram_size =
++ readl(poshob_addr +
++ offsetof(struct scu_ipc_oshob_extend,
++ nvram_size));
++ }
++ }
++ return 0;
++}
++
++int intel_scu_ipc_read_oshob_extend_param_v14(void __iomem *poshob_addr)
++{
++ u16 struct_offs;
++ int buff_size;
++
++ /* set intel OSNIB space size. */
++ oshob_info->osnib_size = OSNIB_SIZE;
++
++ /* set OEM OSNIB space size. */
++ oshob_info->oemnib_size = OSNIB_OEM_RSVD_SIZE;
++
++ /* Set SCU and IA trace buffers. Size calculated in bytes here. */
++ if (oshob_info->platform_type == INTEL_MID_CPU_CHIP_TANGIER)
++ buff_size = OSHOB_SCU_BUF_MRFLD_DW_SIZE*4;
++ else
++ buff_size = OSHOB_SCU_BUF_BASE_DW_SIZE*4;
++
++ intel_scu_ipc_read_oshob(
++ (u8 *)(oshob_info->scu_trace),
++ buff_size,
++ offsetof(struct scu_ipc_oshob_extend_v14, scutxl));
++
++ struct_offs = offsetof(struct scu_ipc_oshob_extend_v14, iatxl) +
++ oshob_info->offs_add;
++ oshob_info->ia_trace = readl(poshob_addr + struct_offs);
++
++ /* Set pointers */
++ struct_offs = offsetof(struct scu_ipc_oshob_extend_v14, osnib_ptr) +
++ oshob_info->offs_add;
++ oshob_info->osnibr_ptr = readl(poshob_addr + struct_offs);
++
++ if (!oshob_info->osnibr_ptr) {
++ pr_err("ipc_read_oshob_extend_param_v14: R_INTEL_POINTER is NULL!\n");
++ return -ENOMEM;
++ }
++
++ /* write and read pointer are the same */
++ oshob_info->osnibw_ptr = oshob_info->osnibr_ptr;
++
++ pr_info("(latest extend oshob) osnib ptr = 0x%8x\n",
++ oshob_info->osnibr_ptr);
++
++ /* OEM NIB point at offset OSNIB_SIZE */
++ oshob_info->oemnibr_ptr = oshob_info->osnibr_ptr + OSNIB_SIZE;
++
++ /* write and read pinter are the same */
++ oshob_info->oemnibw_ptr = oshob_info->oemnibr_ptr;
++
++ /* we use tha same function for all extended OSHOB structure */
++ oshob_info->scu_ipc_write_osnib =
++ &intel_scu_ipc_write_osnib_extend;
++ oshob_info->scu_ipc_read_osnib =
++ &intel_scu_ipc_read_osnib_extend;
++
++ pr_info(
++ "Using latest extended oshob structure size = %d bytes\n",
++ oshob_info->oshob_size);
++ pr_info(
++ "OSNIB Intel size = %d bytes OEMNIB size = %d bytes\n",
++ oshob_info->osnib_size, oshob_info->oemnib_size);
++
++ struct_offs = offsetof(struct scu_ipc_oshob_extend_v14,
++ sculogbufferaddr) + oshob_info->offs_add;
++ oshob_info->scu_trace_buf = readl(poshob_addr + struct_offs);
++
++ struct_offs = offsetof(struct scu_ipc_oshob_extend_v14,
++ sculogbuffersize) + oshob_info->offs_add;
++ oshob_info->scu_trace_size = readl(poshob_addr + struct_offs);
++
++ /* NVRAM after Intel and OEM OSNIB */
++ oshob_info->nvram_addr = oshob_info->oemnibr_ptr + OSNIB_OEM_RSVD_SIZE;
++ oshob_info->nvram_size = OSNIB_NVRAM_SIZE;
++
++ return 0;
++}
++
++int intel_scu_ipc_read_oshob_def_param(void __iomem *poshob_addr)
++{
++ u16 struct_offs;
++ int ret = 0;
++ int buff_size;
++
++ oshob_info->oshob_majrev = OSHOB_REV_MAJ_DEFAULT;
++ oshob_info->oshob_minrev = OSHOB_REV_MIN_DEFAULT;
++ oshob_info->osnib_size = OSNIB_SIZE;
++ oshob_info->oemnib_size = 0;
++
++ /* Set OSHOB total size */
++ if (oshob_info->platform_type == INTEL_MID_CPU_CHIP_TANGIER)
++ oshob_info->oshob_size = OSHOB_MRFLD_SIZE;
++ else
++ oshob_info->oshob_size = OSHOB_SIZE;
++
++ /* Set SCU and IA trace buffers. Size calculated in bytes here. */
++ if (oshob_info->platform_type == INTEL_MID_CPU_CHIP_TANGIER)
++ buff_size = OSHOB_SCU_BUF_MRFLD_DW_SIZE*4;
++ else
++ buff_size = OSHOB_SCU_BUF_BASE_DW_SIZE*4;
++
++ ret = intel_scu_ipc_read_oshob(
++ (u8 *)(oshob_info->scu_trace),
++ buff_size,
++ offsetof(struct scu_ipc_oshob, scutxl));
++
++ if (ret != 0) {
++ pr_err("Cannot get scutxl data from OSHOB\n");
++ return ret;
++ }
++
++ struct_offs = offsetof(struct scu_ipc_oshob, iatxl) +
++ oshob_info->offs_add;
++ oshob_info->ia_trace = readl(poshob_addr + struct_offs);
++
++ oshob_info->scu_ipc_write_osnib =
++ &intel_scu_ipc_write_osnib;
++ oshob_info->scu_ipc_read_osnib =
++ &intel_scu_ipc_read_osnib;
++
++ struct_offs = offsetof(struct scu_ipc_oshob, osnibr) +
++ oshob_info->offs_add;
++ oshob_info->osnibr_ptr = (unsigned long)(poshob_addr + struct_offs);
++
++ pr_info("Using default oshob structure size = %d bytes\n",
++ oshob_info->oshob_size);
++
++ pr_debug("Using default oshob structure OSNIB read ptr %x\n",
++ oshob_info->osnibr_ptr);
++
++ return ret;
++}
++
++int intel_scu_ipc_read_oshob_info(void)
++{
++ int i, ret = 0;
++ u32 oshob_base = 0;
++ void __iomem *oshob_addr;
++ unsigned char oshob_magic[4];
++
++ ret = rpmsg_send_command(ipcutil_instance,
++ RP_GET_HOBADDR, 0, NULL, &oshob_base, 0, 1);
++
++ if (ret < 0) {
++ pr_err("ipc_read_oshob cmd failed!!\n");
++ goto exit;
++ }
++
++ /* At this stage, we still don't know which OSHOB type (default or */
++ /* extended) can be used, and the size of resource to be remapped */
++ /* depends on the type of OSHOB structure to be used. */
++ /* So just remap the minimum size to get the needed bytes of the */
++ /* OSHOB zone. */
++ oshob_addr = ioremap_nocache(oshob_base, OSHOB_EXTEND_DESC_SIZE);
++
++ if (!oshob_addr) {
++ pr_err("oshob addr ioremap failed!\n");
++ ret = -ENOMEM;
++ goto exit;
++ }
++
++ pr_info("(oshob) base addr = 0x%8x\n", oshob_base);
++
++ /* Store base address. */
++ oshob_info->oshob_base = oshob_base;
++
++ oshob_info->platform_type = intel_mid_identify_cpu();
++
++ /*
++ * Buffer is allocated using kmalloc. Memory is not initialized and
++ * these fields are not updated in all the branches.
++ */
++ oshob_info->scu_trace_buf = 0;
++ oshob_info->scu_trace_size = 0;
++ oshob_info->nvram_addr = 0;
++ oshob_info->nvram_size = 0;
++
++ if (oshob_info->platform_type == INTEL_MID_CPU_CHIP_TANGIER) {
++ pr_info("(oshob) identified platform = INTEL_MID_CPU_CHIP_TANGIER\n");
++
++ /* By default we already have 1 dword reserved in the OSHOB */
++ /* structures for SCU buffer. For Merrifield, SCU size to */
++ /* consider is OSHOB_SCU_BUF_MRFLD_DW_SIZE dwords. So with */
++ /* Merrifield, when calculating structures offsets, we have */
++ /* to add (OSHOB_SCU_BUF_MRFLD_DW_SIZE - 1) dwords, with */
++ /* the offsets calculated in bytes. */
++ oshob_info->offs_add = (OSHOB_SCU_BUF_MRFLD_DW_SIZE - 1)*4;
++ } else
++ oshob_info->offs_add = 0;
++
++ pr_debug("(oshob) additional offset = 0x%x\n", oshob_info->offs_add);
++
++ /* Extract magic number that will help identifying the good OSHOB */
++ /* that is going to be used. */
++ for (i = 0; i < OSHOB_HEADER_MAGIC_SIZE; i = i+1)
++ oshob_magic[i] = readb(oshob_addr + i);
++
++ pr_debug("(oshob) OSHOB magic = %x %x %x %x\n",
++ oshob_magic[0], oshob_magic[1], oshob_magic[2], oshob_magic[3]);
++
++ if (strncmp(oshob_magic, OSHOB_MAGIC_NUMBER,
++ OSHOB_HEADER_MAGIC_SIZE) == 0) {
++ /* Get OSHOB version and size which are commoon to all */
++ /* extended OSHOB structure. */
++ oshob_info->oshob_majrev = readb(oshob_addr +
++ offsetof(struct scu_ipc_oshob_extend, rev_major));
++ oshob_info->oshob_minrev = readb(oshob_addr +
++ offsetof(struct scu_ipc_oshob_extend, rev_minor));
++ oshob_info->oshob_size = readw(oshob_addr +
++ offsetof(struct scu_ipc_oshob_extend, oshob_size));
++
++ pr_info("(oshob) oshob version = %x.%x\n",
++ oshob_info->oshob_majrev, oshob_info->oshob_minrev);
++
++ if ((oshob_info->oshob_majrev >= 1) &&
++ (oshob_info->oshob_minrev >= 4)) {
++ if (intel_scu_ipc_read_oshob_extend_param_v14(
++ oshob_addr) != 0) {
++ ret = -EFAULT;
++ goto unmap_oshob;
++ }
++ } else {
++ if (intel_scu_ipc_read_oshob_extend_param(
++ oshob_addr) != 0) {
++ ret = -EFAULT;
++ goto unmap_oshob;
++ }
++ }
++
++ if (oshob_info->platform_type == INTEL_MID_CPU_CHIP_TANGIER) {
++ pr_info("(extend oshob) SCU buffer size is %d bytes\n",
++ OSHOB_SCU_BUF_MRFLD_DW_SIZE*4);
++ } else {
++ pr_debug("(extend oshob) SCU buffer size is %d bytes\n",
++ OSHOB_SCU_BUF_BASE_DW_SIZE*4);
++ }
++ } else {
++ ret = intel_scu_ipc_read_oshob_def_param(oshob_addr);
++
++ if (oshob_info->platform_type == INTEL_MID_CPU_CHIP_TANGIER) {
++ pr_debug("(default oshob) SCU buffer size is %d bytes\n",
++ OSHOB_SCU_BUF_MRFLD_DW_SIZE*4);
++ } else {
++ pr_debug("(default oshob) SCU buffer size is %d bytes\n",
++ OSHOB_SCU_BUF_BASE_DW_SIZE*4);
++ }
++ }
++
++unmap_oshob:
++ iounmap(oshob_addr);
++
++exit:
++ return ret;
++}
++
++/*
++ * This writes the OEMNIB buffer in the internal RAM of the SCU.
++ */
++int intel_scu_ipc_write_oemnib(u8 *oemnib, int len, int offset)
++{
++ int i;
++ int ret = 0;
++ void __iomem *oshob_addr, *oemnibw_addr;
++ u32 sptr_dw_mask;
++
++ if (oemnib == NULL) {
++ pr_err("ipc_write_oemnib: passed buffer for writting OEMNIB is NULL\n");
++ return -EINVAL;
++ }
++
++ rpmsg_global_lock();
++
++ pr_debug("ipc_write_oemnib: remap OSHOB addr 0x%8x size %d\n",
++ oshob_info->oshob_base, oshob_info->oshob_size);
++
++ oshob_addr = ioremap_nocache(oshob_info->oshob_base,
++ oshob_info->oshob_size);
++ if (!oshob_addr) {
++ pr_err("ipc_write_oemnib: ioremap failed!\n");
++ ret = -ENOMEM;
++ goto exit;
++ }
++
++ if ((len == 0) || (len > oshob_info->oemnib_size)) {
++ pr_err(
++ "ipc_write_oemnib: bad OEMNIB data length (%d) to write (max=%d bytes)\n",
++ len, oshob_info->oemnib_size);
++ ret = -EINVAL;
++ goto unmap_oshob_addr;
++ }
++
++ /* offset shall start at 0 from the OEMNIB base address and shall */
++ /* not exceed the OEMNIB allowed size. */
++ if ((offset < 0) || (offset >= oshob_info->oemnib_size) ||
++ (len + offset > oshob_info->oemnib_size)) {
++ pr_err(
++ "ipc_write_oemnib: Bad OEMNIB data offset/len for writing (offset=%d , len=%d)\n",
++ offset, len);
++ ret = -EINVAL;
++ goto unmap_oshob_addr;
++ }
++
++ pr_debug("ipc_write_oemnib: POEMNIB remap oemnibw ptr 0x%x size %d\n",
++ oshob_info->oemnibw_ptr, oshob_info->oemnib_size);
++
++ oemnibw_addr = ioremap_nocache(oshob_info->oemnibw_ptr,
++ oshob_info->oemnib_size);
++ if (!oemnibw_addr) {
++ pr_err("ipc_write_oemnib: ioremap failed!\n");
++ ret = -ENOMEM;
++ goto unmap_oshob_addr;
++ }
++
++ for (i = 0; i < len; i++)
++ writeb(*(oemnib + i), (oemnibw_addr + offset + i));
++
++ /* Send command. The mask to be written identifies which double */
++ /* words of the OSNIB oemnib_size bytes will be written. */
++ /* So the mask is coded on 4 bytes. */
++ sptr_dw_mask = 0xFFFFFFFF;
++ if ((oshob_info->oshob_majrev >= 1) &&
++ (oshob_info->oshob_minrev >= 4)) {
++ sptr_dw_mask = 0xFFFFFFFF;
++ /* OEM NIB lies on region 1, 2, and 3 */
++ ret = rpmsg_send_raw_command(ipcutil_instance,
++ RP_WRITE_OSNIB, 0, NULL, NULL,
++ 0, 0, sptr_dw_mask, 1);
++ if (ret < 0) {
++ pr_err("ipc_write_oemnib: ipc_write_osnib failed!!\n");
++ goto unmap_oemnibw_addr;
++ }
++ ret = rpmsg_send_raw_command(ipcutil_instance,
++ RP_WRITE_OSNIB, 0, NULL, NULL,
++ 0, 0, sptr_dw_mask, 2);
++ if (ret < 0) {
++ pr_err("ipc_write_oemnib: ipc_write_osnib failed!!\n");
++ goto unmap_oemnibw_addr;
++ }
++ ret = rpmsg_send_raw_command(ipcutil_instance,
++ RP_WRITE_OSNIB, 0, NULL, NULL,
++ 0, 0, sptr_dw_mask, 3);
++ if (ret < 0) {
++ pr_err("ipc_write_oemnib: ipc_write_osnib failed!!\n");
++ goto unmap_oemnibw_addr;
++ }
++ } else {
++ ret = rpmsg_send_raw_command(ipcutil_instance,
++ RP_WRITE_OEMNIB, 0, NULL, NULL,
++ 0, 0, sptr_dw_mask, 0);
++ if (ret < 0) {
++ pr_err("ipc_write_oemnib: ipc_write_osnib failed!!\n");
++ goto unmap_oemnibw_addr;
++ }
++ }
++
++unmap_oemnibw_addr:
++ iounmap(oemnibw_addr);
++
++unmap_oshob_addr:
++ iounmap(oshob_addr);
++exit:
++ rpmsg_global_unlock();
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(intel_scu_ipc_write_oemnib);
++
++/*
++ * This reads the OEMNIB from the internal RAM of the SCU.
++ */
++static int intel_scu_ipc_read_oemnib(u8 *oemnib, int len, int offset)
++{
++ int i, ret = 0;
++ u8 *ptr;
++ void __iomem *oshob_addr, *oemnibr_addr;
++
++ if (oemnib == NULL) {
++ pr_err("ipc_read_oemnib: passed buffer for reading OEMNIB is NULL\n");
++ return -EINVAL;
++ }
++
++ pr_debug("ipc_read_oemnib: remap OSHOB base addr 0x%x size %d\n",
++ oshob_info->oshob_base, oshob_info->oshob_size);
++
++ oshob_addr = ioremap_nocache(oshob_info->oshob_base,
++ oshob_info->oshob_size);
++ if (!oshob_addr) {
++ pr_err("ipc_read_oemnib: ioremap failed!\n");
++ ret = -ENOMEM;
++ goto exit;
++ }
++
++ if ((len == 0) || (len > oshob_info->oemnib_size)) {
++ pr_err("ipc_read_oemnib: Bad OEMNIB data length (%d) to be read (max=%d bytes)\n",
++ len, oshob_info->oemnib_size);
++ ret = -EINVAL;
++ goto unmap_oshob_addr;
++ }
++
++ /* offset shall start at 0 from the OEMNIB base address and shall */
++ /* not exceed the OEMNIB allowed size. */
++ if ((offset < 0) || (offset >= oshob_info->oemnib_size) ||
++ (len + offset > oshob_info->oemnib_size)) {
++ pr_err(
++ "ipc_read_oemnib: Bad OEMNIB data offset/len to read (offset=%d ,len=%d)\n",
++ offset, len);
++ ret = -EINVAL;
++ goto unmap_oshob_addr;
++ }
++
++ pr_debug("ipc_read_oemnib: POEMNIB remap oemnibr ptr 0x%x size %d\n",
++ oshob_info->oemnibr_ptr, oshob_info->oemnib_size);
++
++ oemnibr_addr = ioremap_nocache(oshob_info->oemnibr_ptr,
++ oshob_info->oemnib_size);
++
++ if (!oemnibr_addr) {
++ pr_err("ipc_read_oemnib: ioremap of oemnib failed!\n");
++ ret = -ENOMEM;
++ goto unmap_oshob_addr;
++ }
++
++ ptr = oemnib;
++ pr_debug("ipc_read_oemnib: OEMNIB content:\n");
++ for (i = 0; i < len; i++) {
++ *ptr = readb(oemnibr_addr + offset + i);
++ pr_debug("addr(remapped)=%8x, offset=%2x, value=%2x\n",
++ (u32)(oemnibr_addr+offset+i), offset+i, *ptr);
++ ptr++;
++ }
++
++ iounmap(oemnibr_addr);
++
++unmap_oshob_addr:
++ iounmap(oshob_addr);
++exit:
++ return ret;
++}
++EXPORT_SYMBOL_GPL(intel_scu_ipc_read_oemnib);
++
++#ifdef DUMP_OSNIB
++/*
++ * This reads the PMIT from the OSHOB (pointer to interrupt tree)
++ */
++static int intel_scu_ipc_read_oshob_it_tree(u32 *ptr)
++{
++ u16 struct_offs;
++
++ pr_debug("intel_scu_ipc_read_oshob_it_tree: read IT tree\n");
++
++ if ((oshob_info->oshob_majrev == OSHOB_REV_MAJ_DEFAULT) &&
++ (oshob_info->oshob_minrev == OSHOB_REV_MIN_DEFAULT)) {
++ struct_offs = offsetof(struct scu_ipc_oshob, pmit) +
++ oshob_info->offs_add;
++ } else if ((oshob_info->oshob_majrev >= 1) &&
++ (oshob_info->oshob_minrev >= 4)) {
++ struct_offs = offsetof(struct scu_ipc_oshob_extend_v14, pmit) +
++ oshob_info->offs_add;
++ } else {
++ struct_offs = offsetof(struct scu_ipc_oshob_extend, pmit) +
++ oshob_info->offs_add;
++ }
++ return intel_scu_ipc_read_oshob(
++ (u8 *) ptr,
++ 4,
++ struct_offs);
++}
++#endif
++
++/*
++ * This reads the RESETIRQ1 or RESETSRC0 from the OSNIB
++ */
++#ifdef DUMP_OSNIB
++static int intel_scu_ipc_read_osnib_reset_ev1(u8 *rev1)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(chip_reset_events); i++) {
++ if (chip_reset_events[i].id == oshob_info->platform_type) {
++ pr_debug(
++ "intel_scu_ipc_read_osnib_rst_ev1: read %s\n",
++ chip_reset_events[i].reset_ev1_name);
++
++ return oshob_info->scu_ipc_read_osnib(
++ rev1,
++ 1,
++ offsetof(struct scu_ipc_osnib, reset_ev1));
++ }
++ }
++
++ pr_err("intel_scu_ipc_read_osnib_reset_ev1: param not found\n");
++ return -EFAULT;
++}
++#endif
++
++/*
++ * This reads the RESETIRQ2 or RESETSRC1 from the OSNIB
++ */
++#ifdef DUMP_OSNIB
++static int intel_scu_ipc_read_osnib_reset_ev2(u8 *rev2)
++{
++ int i;
++
++ for (i = 0 ; i < ARRAY_SIZE(chip_reset_events); i++) {
++ if (chip_reset_events[i].id == oshob_info->platform_type) {
++ pr_debug(
++ "intel_scu_ipc_read_osnib_rst_ev2: read %s\n",
++ chip_reset_events[i].reset_ev2_name);
++
++ return oshob_info->scu_ipc_read_osnib(
++ rev2,
++ 1,
++ offsetof(struct scu_ipc_osnib, reset_ev2));
++ }
++ }
++
++ pr_err("intel_scu_ipc_read_osnib_reset_ev2: param not found\n");
++ return -EFAULT;
++}
++#endif
++
++/*
++ * This reads the WD from the OSNIB
++ */
++int intel_scu_ipc_read_osnib_wd(u8 *wd)
++{
++ pr_debug("intel_scu_ipc_read_osnib_wd: read WATCHDOG\n");
++
++ return oshob_info->scu_ipc_read_osnib(
++ wd,
++ 1,
++ offsetof(struct scu_ipc_osnib, wd_count));
++}
++
++/*
++ * This writes the WD in the OSNIB
++ */
++int intel_scu_ipc_write_osnib_wd(u8 *wd)
++{
++ pr_info("intel_scu_ipc_write_osnib_wd: write WATCHDOG %x\n", *wd);
++
++ return oshob_info->scu_ipc_write_osnib(
++ wd,
++ 1,
++ offsetof(struct scu_ipc_osnib, wd_count));
++}
++EXPORT_SYMBOL_GPL(intel_scu_ipc_write_osnib_wd);
++
++/*
++ * Get SCU trace buffer physical address if available
++ */
++u32 intel_scu_ipc_get_scu_trace_buffer(void)
++{
++ if (oshob_info == NULL)
++ return 0;
++ return oshob_info->scu_trace_buf;
++}
++EXPORT_SYMBOL_GPL(intel_scu_ipc_get_scu_trace_buffer);
++
++/*
++ * Get SCU trace buffer size
++ */
++u32 intel_scu_ipc_get_scu_trace_buffer_size(void)
++{
++ if (oshob_info == NULL)
++ return 0;
++ return oshob_info->scu_trace_size;
++}
++EXPORT_SYMBOL_GPL(intel_scu_ipc_get_scu_trace_buffer_size);
++
++/*
++ * Get nvram size
++ */
++u32 intel_scu_ipc_get_nvram_size(void)
++{
++ if (oshob_info == NULL)
++ return 0;
++ return oshob_info->nvram_size;
++}
++EXPORT_SYMBOL_GPL(intel_scu_ipc_get_nvram_size);
++
++/*
++ * Get nvram addr
++ */
++u32 intel_scu_ipc_get_nvram_addr(void)
++{
++ if (oshob_info == NULL)
++ return 0;
++ return oshob_info->nvram_addr;
++}
++EXPORT_SYMBOL_GPL(intel_scu_ipc_get_nvram_addr);
++
++/*
++ * Get SCU fabric error buffer1 offset
++ */
++u32 intel_scu_ipc_get_fabricerror_buf1_offset(void)
++{
++ if (oshob_info == NULL)
++ return 0;
++
++ if (oshob_info->platform_type == INTEL_MID_CPU_CHIP_CLOVERVIEW)
++ return offsetof(struct scu_ipc_oshob_extend, fabricerrlog1);
++ else if (oshob_info->platform_type == INTEL_MID_CPU_CHIP_TANGIER)
++ if ((oshob_info->oshob_majrev >= 1) &&
++ (oshob_info->oshob_minrev >= 4)) {
++ return offsetof(struct scu_ipc_oshob_extend_v14,
++ fabricerrlog) + oshob_info->offs_add;
++ } else {
++ return offsetof(struct scu_ipc_oshob,
++ fab_err_log) + oshob_info->offs_add;
++ }
++ else {
++ pr_err("scu_ipc_get_fabricerror_buf_offset: platform not recognized!\n");
++ return 0;
++ }
++}
++
++/*
++ * Get SCU fabric error buffer2 offset
++ */
++u32 intel_scu_ipc_get_fabricerror_buf2_offset(void)
++{
++ if (oshob_info == NULL)
++ return 0;
++
++ if (oshob_info->platform_type == INTEL_MID_CPU_CHIP_CLOVERVIEW)
++ return offsetof(struct scu_ipc_oshob_extend, fabricerrlog2);
++ else {
++ pr_warn("scu_ipc_get_fabricerror_buf2_offset: not supported for this platform!\n");
++ return 0;
++ }
++}
++
++
++/*
++ * This reads the ALARM from the OSNIB
++ */
++#ifdef DUMP_OSNIB
++static int intel_scu_ipc_read_osnib_alarm(u8 *alarm)
++{
++ pr_debug("intel_scu_ipc_read_osnib_alarm: read ALARM\n");
++
++ return oshob_info->scu_ipc_read_osnib(
++ alarm,
++ 1,
++ offsetof(struct scu_ipc_osnib, alarm));
++}
++#endif
++
++/*
++ * This reads the WAKESRC from the OSNIB
++ */
++#ifdef DUMP_OSNIB
++static int intel_scu_ipc_read_osnib_wakesrc(u8 *wksrc)
++{
++ pr_debug("intel_scu_ipc_read_osnib_wakesrc: read WAKESRC\n");
++
++ return oshob_info->scu_ipc_read_osnib(
++ wksrc,
++ 1,
++ offsetof(struct scu_ipc_osnib, wakesrc));
++}
++#endif
++
++
++#define OEMNIB_BUF_DESC_LEN 4096
++
++#ifdef CONFIG_DEBUG_FS
++static int intel_scu_ipc_oshob_stat(struct seq_file *m, void *unused)
++{
++ void __iomem *osnib;
++ int i, count;
++ int ret = 0;
++
++ u32 value;
++ if ((oshob_info->oshob_majrev == OSHOB_REV_MAJ_DEFAULT) &&
++ (oshob_info->oshob_minrev == OSHOB_REV_MIN_DEFAULT)) {
++ seq_printf(m, "DEFAULT OSHOB\n");
++ seq_printf(m, "OSHOB size : %d\n", oshob_info->oshob_size);
++ if (oshob_info->platform_type == INTEL_MID_CPU_CHIP_TANGIER) {
++ seq_printf(m, "SCU trace : ");
++
++ for (i = 0; i < OSHOB_SCU_BUF_MRFLD_DW_SIZE; i++)
++ seq_printf(m, "%x ", oshob_info->scu_trace[i]);
++
++ seq_printf(m, "\n");
++ } else
++ seq_printf(m, "SCU trace : %x\n",
++ oshob_info->scu_trace[0]);
++
++ seq_printf(m, "IA trace : %x\n", oshob_info->ia_trace);
++ } else {
++ seq_printf(m, "EXTENDED OSHOB v%d.%d\n",
++ oshob_info->oshob_majrev,
++ oshob_info->oshob_minrev);
++ seq_printf(m, "OSHOB size : %d\n\n", oshob_info->oshob_size);
++ if (oshob_info->platform_type == INTEL_MID_CPU_CHIP_TANGIER) {
++ seq_printf(m, "SCU trace : ");
++
++ for (i = 0; i < OSHOB_SCU_BUF_MRFLD_DW_SIZE; i++)
++ seq_printf(m, "%x ", oshob_info->scu_trace[i]);
++
++ seq_printf(m, "\n");
++ } else
++ seq_printf(m, "SCU trace : %x\n",
++ oshob_info->scu_trace[0]);
++
++ seq_printf(m, "IA trace : %x\n\n", oshob_info->ia_trace);
++
++ seq_printf(m, "OSNIB size : %d\n", oshob_info->osnib_size);
++ seq_printf(m, "OSNIB read address : %x\n",
++ oshob_info->osnibr_ptr);
++ seq_printf(m, "OSNIB write address : %x\n",
++ oshob_info->osnibw_ptr);
++ /* Dump OSNIB */
++ osnib = ioremap_nocache(oshob_info->osnibr_ptr,
++ oshob_info->osnib_size);
++ if (!osnib) {
++ pr_err("Cannot remap OSNIB\n");
++ ret = -ENOMEM;
++ return ret;
++ }
++
++ i = 0;
++ count = 0; /* used for fancy presentation */
++ while (i < oshob_info->osnib_size) {
++ if (count%4 == 0)
++ seq_printf(m, "\nOSNIB[%08x] ",
++ oshob_info->osnibr_ptr+i);
++
++ value = readl(osnib+i);
++ seq_printf(m, "%08x ", value);
++ i += 4;
++ count++;
++ }
++ seq_printf(m, "\n\n");
++ iounmap(osnib);
++
++ seq_printf(m, "OEMNIB size : %d\n",
++ oshob_info->oemnib_size);
++ seq_printf(m, "OEMNIB read address : %x\n",
++ oshob_info->oemnibr_ptr);
++ seq_printf(m, "OEMNIB write address : %x\n",
++ oshob_info->oemnibw_ptr);
++ seq_printf(m, "\n\n");
++ }
++ return 0;
++}
++
++static int intel_scu_ipc_oemnib_stat(struct seq_file *m, void *unused)
++{
++ void __iomem *oemnib;
++ int i, count;
++ u32 value;
++
++ /* Dump OEMNIB */
++ oemnib = ioremap_nocache(oshob_info->oemnibr_ptr,
++ oshob_info->oemnib_size);
++
++ if (!oemnib) {
++ pr_err("Cannot remap OEMNIB\n");
++ return -ENOMEM;
++ }
++
++ i = 0;
++ count = 0; /* used for fancy presentation */
++ while (i < oshob_info->oemnib_size) {
++ if (count%4 == 0)
++ seq_printf(m, "\nOEMNIB[%08x] ",
++ oshob_info->oemnibr_ptr+i);
++
++ value = readl(oemnib+i);
++ seq_printf(m, "%08x ", value);
++ i += 4;
++ count++;
++ }
++ seq_printf(m, "\n\n");
++ iounmap(oemnib);
++
++ return 0;
++}
++
++static ssize_t intel_scu_ipc_oshob_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, intel_scu_ipc_oshob_stat, NULL);
++}
++
++static ssize_t intel_scu_ipc_oemnib_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, intel_scu_ipc_oemnib_stat, NULL);
++}
++
++
++/*
++* debugfs interface: the "oemnib_write" stores the OEMNIB part of OSNIB,
++* starting at offset ppos.
++*/
++static ssize_t intel_scu_ipc_oemnib_write(struct file *file,
++ const char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ int ret, i;
++ u8 *posnib_data, *ptr;
++ char *ptrchar, *temp;
++
++ if ((oshob_info->oshob_majrev == OSHOB_REV_MAJ_DEFAULT) &&
++ (oshob_info->oshob_minrev == OSHOB_REV_MIN_DEFAULT)) {
++ /* OEMNIB only usable with extended OSHOB structure. */
++ pr_err(
++ "Write OEMNIB: OEMNIB only usable with extended OSHOB structure.\n");
++ return -EFAULT;
++ }
++
++ pr_info("Write OEMNIB: number bytes = %d\n", count);
++
++ /* Note: when the string is passed through debugfs interface, the */
++ /* real count value includes the end of line \n. So we must take */
++ /* care to consider count - 1 as the real number of OEM bytes. */
++
++ if (buf == NULL) {
++ pr_err("Write OEMNIB: The passed OEMNIB buffer is NULL\n");
++ return -EINVAL;
++ }
++
++ if (count == 0) {
++ pr_err("Write OEMNIB: The OEMNIB data length to write is NULL\n");
++ return -EINVAL;
++ }
++
++ posnib_data = kzalloc(count - 1, GFP_KERNEL);
++
++ if (posnib_data == NULL) {
++ pr_err("Write OEMNIB: Cannot allocate buffer for writting OEMNIB\n");
++ return -ENOMEM;
++ }
++
++ memset(posnib_data, 0, count - 1);
++
++ temp = kzalloc(count - 1, GFP_KERNEL);
++
++ if (temp == NULL) {
++ pr_err(
++ "Write OEMNIB: Cannot allocate temp buffer for writting OEMNIB\n");
++ return -ENOMEM;
++ }
++
++ memset(temp, 0, count - 1);
++
++ if (copy_from_user(temp, buf, count - 1)) {
++ pr_err(
++ "Write OEMNIB: Cannot transfer from user buf to OEMNIB buf\n");
++ kfree(posnib_data);
++ return -EFAULT;
++ }
++
++ ptrchar = temp;
++ ptr = posnib_data;
++
++ for (i = 0; i <= count - 1; i++) {
++ if (*ptrchar >= '0' && *ptrchar <= '9')
++ *ptr = *ptrchar - '0';
++ if (*ptrchar >= 'A' && *ptrchar <= 'F')
++ *ptr = *ptrchar - 'A' + 10;
++ if (*ptrchar >= 'a' && *ptrchar <= 'f')
++ *ptr = *ptrchar - 'a' + 10;
++
++ ptrchar++;
++ ptr++;
++ }
++
++ ret = intel_scu_ipc_write_oemnib(posnib_data, count - 1, *ppos);
++
++ if (ret < 0) {
++ pr_err("Write OEMNIB: ipc write of OEMNIB failed!!\n");
++ kfree(posnib_data);
++ return ret;
++ }
++
++ kfree(posnib_data);
++ kfree(temp);
++
++ pr_info("Write OEMNIB: OEMNIB updated: count=%d bytes\n", count);
++
++ return count;
++}
++
++/* Attach the debugfs operations methods */
++static const struct file_operations scu_ipc_oemnib_fops = {
++ .owner = THIS_MODULE,
++ .open = intel_scu_ipc_oemnib_open,
++ .read = seq_read,
++ .write = intel_scu_ipc_oemnib_write,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++static const struct file_operations scu_ipc_oshob_fops = {
++ .owner = THIS_MODULE,
++ .open = intel_scu_ipc_oshob_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++static struct dentry *scu_ipc_oemnib_dir;
++static struct dentry *scu_ipc_oemnib_file;
++static struct dentry *scu_ipc_oshob_file;
++
++/*
++* debugfs interface: init interface.
++*/
++static int intel_mid_scu_ipc_oemnib_debugfs_init(void)
++{
++ /* Create debugfs directory /sys/kernel/debug/intel_scu_oshob */
++ scu_ipc_oemnib_dir = debugfs_create_dir("intel_scu_oshob", NULL);
++
++ if (!scu_ipc_oemnib_dir) {
++ pr_err("cannot create OSHOB debugfs directory\n");
++ return -1;
++ }
++
++ /* Add operations /sys/kernel/debug/intel_scu_oshob to control */
++ /* the OEM. */
++ scu_ipc_oemnib_file = debugfs_create_file("oemnib_debug",
++ S_IFREG | S_IRUGO | S_IWUSR | S_IWGRP,
++ scu_ipc_oemnib_dir,
++ NULL, &scu_ipc_oemnib_fops);
++
++ if (!scu_ipc_oemnib_file) {
++ pr_err("cannot create OEMNIB debugfs file\n");
++ debugfs_remove(scu_ipc_oemnib_dir);
++ return -1;
++ }
++
++ /* Add operations /sys/kernel/debug/intel_scu_oshob to debug OSHOB */
++ /* content. */
++ scu_ipc_oshob_file = debugfs_create_file("oshob_dump",
++ S_IFREG | S_IRUGO | S_IWUSR | S_IWGRP,
++ scu_ipc_oemnib_dir, NULL, &scu_ipc_oshob_fops);
++
++ if (!scu_ipc_oshob_file) {
++ pr_err("cannot create OSHOB debugfs file\n");
++ debugfs_remove_recursive(scu_ipc_oemnib_dir);
++ return -1;
++ }
++
++ return 0;
++}
++
++/*
++* debugfs interface: exit interface.
++*/
++static void intel_mid_scu_ipc_oemnib_debugfs_exit(void)
++{
++ debugfs_remove_recursive(scu_ipc_oemnib_dir);
++}
++
++#endif /* CONFIG_DEBUG_FS */
++
++static const struct file_operations scu_ipc_fops = {
++ .unlocked_ioctl = scu_ipc_ioctl,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = scu_ipc_ioctl,
++#endif
++};
++
++static struct miscdevice scu_ipcutil = {
++ .minor = MISC_DYNAMIC_MINOR,
++ .name = "mid_ipc",
++ .fops = &scu_ipc_fops,
++};
++
++static int oshob_init(void)
++{
++ int ret, i;
++ u16 struct_offs;
++
++#ifdef DUMP_OSNIB
++ u8 rr, reset_ev1, reset_ev2, wd, alarm, wakesrc, *ptr;
++ int rr_found = 0, wksrc_found = 0;
++ u32 pmit, scu_trace[OSHOB_SCU_BUF_BASE_DW_SIZE*4], ia_trace;
++ int buff_size;
++#endif
++
++ /* Identify the type and size of OSHOB to be used. */
++ ret = intel_scu_ipc_read_oshob_info();
++
++ if (ret != 0) {
++ pr_err("Cannot init ipc module: oshob info not read\n");
++ goto exit;
++ }
++
++#ifdef DUMP_OSNIB
++ /* Dumping reset events from the interrupt tree */
++ ret = intel_scu_ipc_read_oshob_it_tree(&pmit);
++
++ if (ret != 0) {
++ pr_err("Cannot read interrupt tree\n");
++ goto exit;
++ }
++
++ ptr = ioremap_nocache(pmit + PMIT_RESET1_OFFSET, 2);
++
++ if (!ptr) {
++ pr_err("Cannot remap PMIT\n");
++ ret = -ENOMEM;
++ goto exit;
++ }
++
++ pr_debug("PMIT addr 0x%8x remapped to 0x%8x\n", pmit, (u32)ptr);
++
++ reset_ev1 = readb(ptr);
++ reset_ev2 = readb(ptr+1);
++ for (i = 0; i < ARRAY_SIZE(chip_reset_events); i++) {
++ if (chip_reset_events[i].id == oshob_info->platform_type) {
++ pr_warn("[BOOT] %s=0x%02x %s=0x%02x (PMIT interrupt tree)\n",
++ chip_reset_events[i].reset_ev1_name,
++ reset_ev1,
++ chip_reset_events[i].reset_ev2_name,
++ reset_ev2);
++ }
++ }
++ iounmap(ptr);
++
++ /* Dumping OSHOB content */
++ if ((oshob_info->oshob_majrev == OSHOB_REV_MAJ_DEFAULT) &&
++ (oshob_info->oshob_minrev == OSHOB_REV_MIN_DEFAULT)) {
++ /* Use default OSHOB here. Calculate in bytes here. */
++ if (oshob_info->platform_type == INTEL_MID_CPU_CHIP_TANGIER)
++ buff_size = OSHOB_SCU_BUF_MRFLD_DW_SIZE*4;
++ else
++ buff_size = OSHOB_SCU_BUF_BASE_DW_SIZE*4;
++
++ ret = intel_scu_ipc_read_oshob(
++ (u8 *)(scu_trace),
++ buff_size,
++ offsetof(struct scu_ipc_oshob, scutxl));
++
++ if (ret != 0) {
++ pr_err("Cannot read SCU data\n");
++ goto exit;
++ }
++
++ struct_offs = offsetof(struct scu_ipc_oshob, iatxl) +
++ oshob_info->offs_add;
++ ret = intel_scu_ipc_read_oshob(
++ (u8 *)(&ia_trace),
++ 4,
++ struct_offs);
++
++ if (ret != 0) {
++ pr_err("Cannot read IA data\n");
++ goto exit;
++ }
++ } else {
++ /* Use extended OSHOB here. Calculate in bytes here. */
++ if (oshob_info->platform_type == INTEL_MID_CPU_CHIP_TANGIER)
++ buff_size = OSHOB_SCU_BUF_MRFLD_DW_SIZE*4;
++ else
++ buff_size = OSHOB_SCU_BUF_BASE_DW_SIZE*4;
++
++ if ((oshob_info->oshob_majrev >= 1) &&
++ (oshob_info->oshob_minrev >= 4)) {
++ ret = intel_scu_ipc_read_oshob(
++ (u8 *)(scu_trace),
++ buff_size,
++ offsetof(struct scu_ipc_oshob_extend_v14,
++ scutxl));
++ } else {
++ ret = intel_scu_ipc_read_oshob(
++ (u8 *)(scu_trace),
++ buff_size,
++ offsetof(struct scu_ipc_oshob_extend, scutxl));
++ }
++
++ if (ret != 0) {
++ pr_err("Cannot read SCU data\n");
++ goto exit;
++ }
++
++ if ((oshob_info->oshob_majrev >= 1) &&
++ (oshob_info->oshob_minrev >= 4)) {
++ struct_offs = offsetof(struct scu_ipc_oshob_extend_v14,
++ iatxl) + oshob_info->offs_add;
++ } else {
++ struct_offs = offsetof(struct scu_ipc_oshob_extend,
++ iatxl) + oshob_info->offs_add;
++ }
++
++ ret = intel_scu_ipc_read_oshob(
++ (u8 *)(&ia_trace),
++ 4,
++ struct_offs);
++
++ if (ret != 0) {
++ pr_err("Cannot read IA data\n");
++ goto exit;
++ }
++ }
++
++ if (oshob_info->platform_type == INTEL_MID_CPU_CHIP_TANGIER) {
++ for (i = 0; i < OSHOB_SCU_BUF_MRFLD_DW_SIZE; i++)
++ pr_warn("[BOOT] SCU_TR[%d]=0x%08x\n", i, scu_trace[i]);
++ } else
++ pr_warn("[BOOT] SCU_TR=0x%08x (oshob)\n", scu_trace[0]);
++
++ pr_warn("[BOOT] IA_TR=0x%08x (oshob)\n", ia_trace);
++
++ /* Dumping OSNIB content */
++ ret = 0;
++ ret |= intel_scu_ipc_read_osnib_rr(&rr);
++ ret |= intel_scu_ipc_read_osnib_reset_ev1(&reset_ev1);
++ ret |= intel_scu_ipc_read_osnib_reset_ev2(&reset_ev2);
++ ret |= intel_scu_ipc_read_osnib_wd(&wd);
++ ret |= intel_scu_ipc_read_osnib_alarm(&alarm);
++ ret |= intel_scu_ipc_read_osnib_wakesrc(&wakesrc);
++
++ if (ret) {
++ pr_err("Cannot read OSNIB content\n");
++ goto exit;
++ }
++
++ for (i = 0; i < ARRAY_SIZE(osnib_target_oses); i++) {
++ if (osnib_target_oses[i].id == rr) {
++ pr_warn("[BOOT] RR=[%s] WD=0x%02x ALARM=0x%02x (osnib)\n",
++ osnib_target_oses[i].target_os_name, wd, alarm);
++ rr_found++;
++ break;
++ }
++ }
++
++ if (!rr_found)
++ pr_warn("[BOOT] RR=[UNKNOWN 0x%02x] WD=0x%02x ALARM=0x%02x (osnib)\n",
++ rr, wd, alarm);
++
++ for (i = 0; i < ARRAY_SIZE(osnib_wake_srcs); i++) {
++ if (osnib_wake_srcs[i].id == wakesrc) {
++ pr_warn("[BOOT] WAKESRC=[%s] (osnib)\n",
++ osnib_wake_srcs[i].wakesrc_name);
++ wksrc_found++;
++ break;
++ }
++ }
++
++ if (!wksrc_found)
++ pr_warn("[BOOT] WAKESRC=[UNKNOWN 0x%02x] (osnib)\n", wakesrc);
++
++ for (i = 0; i < ARRAY_SIZE(chip_reset_events); i++) {
++ if (chip_reset_events[i].id == oshob_info->platform_type) {
++ pr_warn("[BOOT] %s=0x%02x %s=0x%02x (osnib)\n",
++ chip_reset_events[i].reset_ev1_name,
++ reset_ev1,
++ chip_reset_events[i].reset_ev2_name,
++ reset_ev2);
++ break;
++ }
++ }
++
++#endif /* DUMP_OSNIB */
++
++#ifdef CONFIG_DEBUG_FS
++ if (oshob_info->oshob_majrev != OSHOB_REV_MAJ_DEFAULT) {
++ /* OEMNIB only usable with extended OSHOB structure. */
++ ret = intel_mid_scu_ipc_oemnib_debugfs_init();
++
++ if (ret != 0) {
++ pr_err("Cannot register OEMNIB interface to debugfs\n");
++ goto exit;
++ } else {
++ pr_info("OEMNIB interface registered to debugfs\n");
++ }
++ }
++#endif /* CONFIG_DEBUG_FS */
++
++exit:
++ return ret;
++}
++
++static int ipcutil_rpmsg_probe(struct rpmsg_channel *rpdev)
++{
++ int ret = 0;
++
++ oshob_info = kmalloc(sizeof(struct scu_ipc_oshob_info), GFP_KERNEL);
++ if (oshob_info == NULL) {
++ pr_err(
++ "Cannot init ipc module: oshob info struct not allocated\n");
++ return -ENOMEM;
++ }
++
++ if (rpdev == NULL) {
++ pr_err("ipcutil rpmsg channel not created\n");
++ ret = -ENODEV;
++ goto out;
++ }
++
++ dev_info(&rpdev->dev, "Probed ipcutil rpmsg device\n");
++
++ /* Allocate rpmsg instance for mip*/
++ ret = alloc_rpmsg_instance(rpdev, &ipcutil_instance);
++ if (!ipcutil_instance) {
++ dev_err(&rpdev->dev, "kzalloc ipcutil instance failed\n");
++ goto out;
++ }
++
++ /* Initialize rpmsg instance */
++ init_rpmsg_instance(ipcutil_instance);
++
++ ret = oshob_init();
++ if (ret)
++ goto misc_err;
++
++ ret = misc_register(&scu_ipcutil);
++ if (ret) {
++ pr_err("misc register failed\n");
++ goto misc_err;
++ }
++
++ return ret;
++
++misc_err:
++ free_rpmsg_instance(rpdev, &ipcutil_instance);
++out:
++ kfree(oshob_info);
++ return ret;
++}
++
++static void ipcutil_rpmsg_remove(struct rpmsg_channel *rpdev)
++{
++#ifdef CONFIG_DEBUG_FS
++ if (oshob_info->oshob_majrev != OSHOB_REV_MAJ_DEFAULT) {
++ /* OEMNIB only usable with extended OSHOB structure. */
++ /* unregister from debugfs. */
++ intel_mid_scu_ipc_oemnib_debugfs_exit();
++ }
++#endif /* CONFIG_DEBUG_FS */
++
++ kfree(oshob_info);
++
++ /* unregister scu_ipc_ioctl from sysfs. */
++ misc_deregister(&scu_ipcutil);
++ free_rpmsg_instance(rpdev, &ipcutil_instance);
++}
++
++static void ipcutil_rpmsg_cb(struct rpmsg_channel *rpdev, void *data,
++ int len, void *priv, u32 src)
++{
++ dev_warn(&rpdev->dev, "unexpected, message\n");
++
++ print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
++ data, len, true);
++}
++
++static struct rpmsg_device_id ipcutil_rpmsg_id_table[] = {
++ { .name = "rpmsg_ipc_util" },
++ { },
++};
++MODULE_DEVICE_TABLE(rpmsg, ipcutil_rpmsg_id_table);
++
++static struct rpmsg_driver ipcutil_rpmsg = {
++ .drv.name = KBUILD_MODNAME,
++ .drv.owner = THIS_MODULE,
++ .id_table = ipcutil_rpmsg_id_table,
++ .probe = ipcutil_rpmsg_probe,
++ .callback = ipcutil_rpmsg_cb,
++ .remove = ipcutil_rpmsg_remove,
++};
++
++static int __init ipcutil_rpmsg_init(void)
++{
++ return register_rpmsg_driver(&ipcutil_rpmsg);
+ }
+
+-static void __exit ipc_module_exit(void)
++static void __exit ipcutil_rpmsg_exit(void)
+ {
+- unregister_chrdev(major, "intel_mid_scu");
++ unregister_rpmsg_driver(&ipcutil_rpmsg);
+ }
+
+-module_init(ipc_module_init);
+-module_exit(ipc_module_exit);
++rootfs_initcall(ipcutil_rpmsg_init);
++module_exit(ipcutil_rpmsg_exit);
+
+ MODULE_LICENSE("GPL v2");
+ MODULE_DESCRIPTION("Utility driver for intel scu ipc");
+diff --git a/drivers/platform/x86/intel_scu_mip.c b/drivers/platform/x86/intel_scu_mip.c
+new file mode 100644
+index 0000000..ec06140
+--- /dev/null
++++ b/drivers/platform/x86/intel_scu_mip.c
+@@ -0,0 +1,776 @@
++/*
++ * intel_scu_mip.c: Driver for the Intel scu mip and umip access
++ *
++ * (C) Copyright 2012 Intel Corporation
++ * Author: Shijie Zhang (shijie.zhang@intel.com)
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/errno.h>
++#include <linux/fs.h>
++#include <linux/delay.h>
++#include <linux/rpmsg.h>
++#include <linux/blkdev.h>
++#include <linux/pagemap.h>
++#include <asm/intel_scu_ipc.h>
++#include <asm/intel_mip.h>
++#include <asm/intel_mid_rpmsg.h>
++#include <linux/platform_data/intel_mid_remoteproc.h>
++
++#define DRIVER_NAME "intel_scu_mip"
++
++#define IPC_MIP_BASE 0xFFFD8000 /* sram base address for mip accessing*/
++#define IPC_MIP_MAX_ADDR 0x1000
++
++#define KOBJ_MIP_ATTR(_name, _mode, _show, _store) \
++ struct kobj_attribute _name##_attr = __ATTR(_name, _mode, _show, _store)
++
++static struct kobject *scu_mip_kobj;
++static struct rpmsg_instance *mip_instance;
++static struct scu_mip_platform_data *pdata;
++
++static void __iomem *intel_mip_base;
++#define SECTOR_SIZE 512
++#define UMIP_TOTAL_CHKSUM_ENTRY 126
++#define UMIP_HEADER_HEADROOM_SECTOR 1
++#define UMIP_HEADER_SECTOR 0
++#define UMIP_HEADER_CHKSUM_ADDR 7
++#define UMIP_START_CHKSUM_ADDR 8
++#define UMIP_TOTAL_HEADER_SECTOR_NO 2
++
++#define UMIP_BLKDEVICE "mmcblk0boot0"
++
++static int xorblock(u32 *buf, u32 size)
++{
++ u32 cs = 0;
++
++ size >>= 2;
++ while (size--)
++ cs ^= *buf++;
++
++ return cs;
++}
++
++static u8 dword_to_byte_chksum(u32 dw)
++{
++ int n = 0;
++ u32 cs = dw;
++ for (n = 0; n < 3; n++) {
++ dw >>= 8;
++ cs ^= dw;
++ }
++
++ return (u8)cs;
++}
++
++static u8 calc_checksum(void *_buf, int size)
++{
++ int i;
++ u8 checksum = 0, *buf = (u8 *)_buf;
++
++ for (i = 0; i < size; i++)
++ checksum = checksum ^ (buf[i]);
++
++ return checksum;
++}
++
++static int mmcblk0boot0_match(struct device *dev, const void *data)
++{
++ if (strcmp(dev_name(dev), UMIP_BLKDEVICE) == 0)
++ return 1;
++
++ return 0;
++}
++
++static struct block_device *get_emmc_bdev(void)
++{
++ struct block_device *bdev;
++ struct device *emmc_disk;
++
++ emmc_disk = class_find_device(&block_class, NULL, NULL,
++ mmcblk0boot0_match);
++ if (emmc_disk == 0) {
++ pr_err("emmc not found!\n");
++ return NULL;
++ }
++
++ /* partition 0 means raw disk */
++ bdev = bdget_disk(dev_to_disk(emmc_disk), 0);
++ if (bdev == NULL) {
++ dev_err(emmc_disk, "unable to get disk\n");
++ return NULL;
++ }
++
++ /* Note: this bdev ref will be freed after first
++ * bdev_get/bdev_put cycle
++ */
++
++ return bdev;
++}
++
++
++static int read_mip(u8 *data, int len, int offset, int issigned)
++{
++ int ret;
++ u32 sptr, dptr, cmd, cmdid, data_off;
++
++ dptr = offset;
++ sptr = (len + 3) / 4;
++
++ cmdid = issigned ? IPC_CMD_SMIP_RD : IPC_CMD_UMIP_RD;
++ cmd = 4 << 16 | cmdid << 12 | IPCMSG_MIP_ACCESS;
++
++ do {
++ ret = rpmsg_send_raw_command(mip_instance, cmd, 0, NULL,
++ (u32 *)&data_off, 0, 1, sptr, dptr);
++
++ if (ret == -EIO)
++ msleep(20);
++ } while (ret == -EIO);
++
++ if (!ret)
++ memcpy(data, intel_mip_base + data_off, len);
++
++ return ret;
++}
++
++int intel_scu_ipc_read_mip(u8 *data, int len, int offset, int issigned)
++{
++ int ret = 0;
++ Sector sect;
++ struct block_device *bdev;
++ char *buffer = NULL;
++ int *holderId = NULL;
++ int sect_no, remainder;
++
++ /* Only SMIP read for Cloverview is supported */
++ if ((intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_CLOVERVIEW)
++ && (issigned != 1)) { /* CTP read UMIP from eMMC */
++
++ /* Opening the mmcblk0boot0 */
++ bdev = get_emmc_bdev();
++ if (bdev == NULL) {
++ pr_err("%s: get_emmc failed!\n", __func__);
++ return -ENODEV;
++ }
++
++ /* make sure the block device is open read only */
++ ret = blkdev_get(bdev, FMODE_READ, holderId);
++ if (ret < 0) {
++ pr_err("%s: blk_dev_get failed!\n", __func__);
++ return -ret;
++ }
++
++ /* Get sector number of where data located */
++ sect_no = offset / SECTOR_SIZE;
++ remainder = offset % SECTOR_SIZE;
++ buffer = read_dev_sector(bdev, sect_no +
++ UMIP_HEADER_HEADROOM_SECTOR, &sect);
++
++ /* Shouldn't need to access UMIP sector 0/1 */
++ if (sect_no < UMIP_TOTAL_HEADER_SECTOR_NO) {
++ pr_err("invalid umip offset\n");
++ ret = -EINVAL;
++ goto bd_put;
++ } else if (data == NULL || buffer == NULL) {
++ pr_err("buffer is empty\n");
++ ret = -ENODEV;
++ goto bd_put;
++ } else if (len > (SECTOR_SIZE - remainder)) {
++ pr_err("not enough data to read\n");
++ ret = -EINVAL;
++ goto bd_put;
++ }
++
++ memcpy(data, buffer + remainder, len);
++bd_put:
++ if (buffer)
++ put_dev_sector(sect);
++
++ blkdev_put(bdev, FMODE_READ);
++ return ret;
++ } else {
++
++ if (!intel_mip_base)
++ return -ENODEV;
++
++ if (offset + len > IPC_MIP_MAX_ADDR)
++ return -EINVAL;
++
++ rpmsg_global_lock();
++ ret = read_mip(data, len, offset, issigned);
++ rpmsg_global_unlock();
++
++ return ret;
++ }
++}
++EXPORT_SYMBOL(intel_scu_ipc_read_mip);
++
++int get_smip_property_by_name(enum platform_prop pp)
++{
++ u8 data[SMIP_MAX_PROP_LEN];
++ int i, val, ret;
++ struct smip_platform_prop prop[SMIP_NUM_CONFIG_PROPS];
++
++ if (!pdata->smip_prop)
++ return -EINVAL;
++
++ for (i = 0; i < SMIP_NUM_CONFIG_PROPS; i++)
++ prop[i] = pdata->smip_prop[i];
++
++ /* Read the property requested by the caller */
++ ret = intel_scu_ipc_read_mip(data, prop[pp].len, prop[pp].offset, 1);
++ if (ret)
++ return ret;
++
++ /* Adjust the bytes according to the length and return the int */
++ val = data[0];
++ for (i = 1; i < prop[pp].len; i++)
++ val = val << 8 | data[i];
++
++ /* If the requested property is a bit field, return that bit value */
++ if (prop[pp].is_bit_field)
++ val &= prop[pp].mask;
++
++ return val;
++}
++EXPORT_SYMBOL(get_smip_property_by_name);
++
++int intel_scu_ipc_write_umip(u8 *data, int len, int offset)
++{
++ int i, ret = 0, offset_align;
++ int remainder, len_align = 0;
++ u32 dptr, sptr, cmd;
++ u8 cs, tbl_cs = 0, *buf = NULL;
++ Sector sect;
++ struct block_device *bdev;
++ char *buffer = NULL;
++ int *holderId = NULL;
++ int sect_no;
++ u8 checksum;
++
++ if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_CLOVERVIEW) {
++
++ /* Opening the mmcblk0boot0 */
++ bdev = get_emmc_bdev();
++ if (bdev == NULL) {
++ pr_err("%s: get_emmc failed!\n", __func__);
++ return -ENODEV;
++ }
++
++ /* make sure the block device is open rw */
++ ret = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, holderId);
++ if (ret < 0) {
++ pr_err("%s: blk_dev_get failed!\n", __func__);
++ return -ret;
++ }
++
++ /* get memmap of the UMIP header */
++ sect_no = offset / SECTOR_SIZE;
++ remainder = offset % SECTOR_SIZE;
++ buffer = read_dev_sector(bdev, sect_no +
++ UMIP_HEADER_HEADROOM_SECTOR, &sect);
++
++ /* Shouldn't need to access UMIP sector 0/1 */
++ if (sect_no < UMIP_TOTAL_HEADER_SECTOR_NO) {
++ pr_err("invalid umip offset\n");
++ ret = -EINVAL;
++ goto bd_put;
++ } else if (data == NULL || buffer == NULL) {
++ pr_err("buffer is empty\n");
++ ret = -ENODEV;
++ goto bd_put;
++ } else if (len > (SECTOR_SIZE - remainder)) {
++ pr_err("too much data to write\n");
++ ret = -EINVAL;
++ goto bd_put;
++ }
++
++ lock_page(sect.v);
++ memcpy(buffer + remainder, data, len);
++ checksum = calc_checksum(buffer, SECTOR_SIZE);
++
++ set_page_dirty(sect.v);
++ unlock_page(sect.v);
++ sync_blockdev(bdev);
++ put_dev_sector(sect);
++
++ /*
++ * Updating the checksum, sector 0 (starting from UMIP
++ * offset 0x08), we maintains 4 bytes for tracking each of
++ * sector changes individually. For example, the dword at
++ * offset 0x08 is used to checksum data integrity of sector
++ * number 2, and so on so forth. It's worthnoting that only
++ * the first byte in each 4 bytes stores checksum.
++ * For detail, please check CTP FAS UMIP header definition
++ */
++
++ buffer = read_dev_sector(bdev, UMIP_HEADER_SECTOR +
++ UMIP_HEADER_HEADROOM_SECTOR, &sect);
++
++ if (buffer == NULL) {
++ pr_err("buffer is empty\n");
++ ret = -ENODEV;
++ goto bd_put;
++ }
++
++ lock_page(sect.v);
++ memcpy(buffer + 4 * (sect_no - UMIP_TOTAL_HEADER_SECTOR_NO) +
++ UMIP_START_CHKSUM_ADDR, &checksum, 1/* one byte */);
++
++ /* Change UMIP prologue chksum to zero */
++ *(buffer + UMIP_HEADER_CHKSUM_ADDR) = 0;
++
++ for (i = 0; i < UMIP_TOTAL_CHKSUM_ENTRY; i++) {
++ tbl_cs ^= *(u8 *)(buffer + 4 * i +
++ UMIP_START_CHKSUM_ADDR);
++ }
++
++ /* Finish up with re-calcuating UMIP prologue checksum */
++ cs = dword_to_byte_chksum(xorblock((u32 *)buffer,
++ SECTOR_SIZE));
++
++ *(buffer + UMIP_HEADER_CHKSUM_ADDR) = tbl_cs ^ cs;
++
++ set_page_dirty(sect.v);
++ unlock_page(sect.v);
++ sync_blockdev(bdev);
++bd_put:
++ if (buffer)
++ put_dev_sector(sect);
++
++ blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
++ return ret;
++ } else {
++
++ if (!intel_mip_base)
++ return -ENODEV;
++
++ if (offset + len > IPC_MIP_MAX_ADDR)
++ return -EINVAL;
++
++ rpmsg_global_lock();
++
++ offset_align = offset & (~0x3);
++ len_align = (len + (offset - offset_align) + 3) & (~0x3);
++
++ if (len != len_align) {
++ buf = kzalloc(len_align, GFP_KERNEL);
++ if (!buf) {
++ pr_err("Alloc memory failed\n");
++ ret = -ENOMEM;
++ goto fail;
++ }
++ ret = read_mip(buf, len_align, offset_align, 0);
++ if (ret)
++ goto fail;
++ memcpy(buf + offset - offset_align, data, len);
++ } else {
++ buf = data;
++ }
++
++ dptr = offset_align;
++ sptr = len_align / 4;
++ cmd = IPC_CMD_UMIP_WR << 12 | IPCMSG_MIP_ACCESS;
++
++ memcpy(intel_mip_base, buf, len_align);
++
++ do {
++ ret = rpmsg_send_raw_command(mip_instance, cmd, 0, NULL,
++ NULL, 0, 0, sptr, dptr);
++ if (ret == -EIO)
++ msleep(20);
++ } while (ret == -EIO);
++
++fail:
++ if (buf && len_align != len)
++ kfree(buf);
++
++ rpmsg_global_unlock();
++
++ return ret;
++ }
++}
++EXPORT_SYMBOL(intel_scu_ipc_write_umip);
++
++
++#define MAX_DATA_NR 8
++#define MIP_CMD_LEN 11
++
++enum {
++ MIP_DBG_DATA,
++ MIP_DBG_LEN,
++ MIP_DBG_OFFSET,
++ MIP_DBG_ISSIGNED,
++ MIP_DBG_ERROR,
++};
++
++static u8 mip_data[MAX_DATA_NR];
++static int valid_data_nr;
++static int mip_len;
++static int mip_offset;
++static int mip_issigned;
++static int mip_dbg_error;
++static char mip_cmd[MIP_CMD_LEN];
++
++static ssize_t mip_generic_show(char *buf, int type, int *data)
++{
++ int i;
++ ssize_t ret = 0;
++
++ switch (type) {
++ case MIP_DBG_DATA:
++ for (i = 0; i < valid_data_nr; i++) {
++ ret += snprintf(buf + ret, PAGE_SIZE - ret,
++ "data[%d]: %#x\n",
++ i, mip_data[i]);
++ }
++ break;
++ case MIP_DBG_LEN:
++ ret = snprintf(buf, PAGE_SIZE, "len: %d\n", *data);
++ break;
++ case MIP_DBG_OFFSET:
++ ret = snprintf(buf, PAGE_SIZE, "offset: %#x\n", *data);
++ break;
++ case MIP_DBG_ISSIGNED:
++ ret = snprintf(buf, PAGE_SIZE, "issigned: %d\n", *data);
++ break;
++ case MIP_DBG_ERROR:
++ ret = snprintf(buf, PAGE_SIZE, "error: %d\n", *data);
++ break;
++ default:
++ break;
++ }
++
++ return ret;
++}
++
++static void mip_generic_store(const char *buf, int type, int *data)
++{
++ int i, ret;
++
++ if (type == MIP_DBG_DATA) {
++ u32 t[MAX_DATA_NR];
++
++ valid_data_nr = 0;
++ memset(mip_data, 0, sizeof(mip_data));
++
++ ret = sscanf(buf, "%x %x %x %x %x %x %x %x", &t[0], &t[1],
++ &t[2], &t[3], &t[4], &t[5], &t[6], &t[7]);
++ if (ret == 0 || ret > MAX_DATA_NR) {
++ mip_dbg_error = -EINVAL;
++ return;
++ } else {
++ for (i = 0; i < ret; i++)
++ mip_data[i] = (u8)t[i];
++ valid_data_nr = ret;
++ }
++ } else {
++ *data = 0;
++ switch (type) {
++ case MIP_DBG_OFFSET:
++ ret = sscanf(buf, "%x", data);
++ break;
++ case MIP_DBG_LEN:
++ case MIP_DBG_ISSIGNED:
++ ret = sscanf(buf, "%d", data);
++ break;
++ default:
++ ret = -1;
++ break;
++ }
++ }
++
++ if (ret)
++ mip_dbg_error = 0;
++ else
++ mip_dbg_error = -EINVAL;
++
++ return;
++}
++
++static ssize_t mip_data_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return mip_generic_show(buf, MIP_DBG_DATA, NULL);
++}
++
++static ssize_t mip_data_store(struct kobject *kobj,
++ struct kobj_attribute *attr, const char *buf, size_t size)
++{
++ mip_generic_store(buf, MIP_DBG_DATA, NULL);
++ return size;
++}
++
++static ssize_t mip_len_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return mip_generic_show(buf, MIP_DBG_LEN, &mip_len);
++}
++
++static ssize_t mip_len_store(struct kobject *kobj,
++ struct kobj_attribute *attr, const char *buf, size_t size)
++{
++ mip_generic_store(buf, MIP_DBG_LEN, &mip_len);
++ return size;
++}
++
++static ssize_t mip_offset_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return mip_generic_show(buf, MIP_DBG_OFFSET, &mip_offset);
++}
++
++static ssize_t mip_offset_store(struct kobject *kobj,
++ struct kobj_attribute *attr, const char *buf, size_t size)
++{
++ mip_generic_store(buf, MIP_DBG_OFFSET, &mip_offset);
++ return size;
++}
++
++static ssize_t mip_issigned_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return mip_generic_show(buf, MIP_DBG_ISSIGNED, &mip_issigned);
++}
++
++static ssize_t mip_issigned_store(struct kobject *kobj,
++ struct kobj_attribute *attr, const char *buf, size_t size)
++{
++ mip_generic_store(buf, MIP_DBG_ISSIGNED, &mip_issigned);
++ return size;
++}
++
++static ssize_t mip_error_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return mip_generic_show(buf, MIP_DBG_ERROR, &mip_dbg_error);
++}
++
++static ssize_t mip_cmd_store(struct kobject *kobj,
++ struct kobj_attribute *attr, const char *buf, size_t size)
++{
++
++ int ret;
++
++ memset(mip_cmd, 0, sizeof(mip_cmd));
++
++ ret = sscanf(buf, "%10s", mip_cmd);
++ if (ret == 0) {
++ mip_dbg_error = -EINVAL;
++ goto end;
++ }
++
++ if (!strncmp("read_mip", mip_cmd, MIP_CMD_LEN)) {
++ memset(mip_data, 0, sizeof(mip_data));
++ ret = intel_scu_ipc_read_mip(mip_data, mip_len, mip_offset,
++ mip_issigned);
++ if (!ret)
++ valid_data_nr = mip_len;
++
++ } else if (!strncmp("write_umip", mip_cmd, MIP_CMD_LEN)) {
++ if (mip_len == valid_data_nr) {
++ ret = intel_scu_ipc_write_umip(mip_data, mip_len,
++ mip_offset);
++ } else
++ goto error;
++ } else
++ goto error;
++
++ if (ret)
++ goto error;
++ else
++ goto end;
++
++error:
++ mip_dbg_error = -EINVAL;
++
++end:
++ return size;
++}
++
++static KOBJ_MIP_ATTR(data, S_IRUGO|S_IWUSR, mip_data_show, mip_data_store);
++static KOBJ_MIP_ATTR(len, S_IRUGO|S_IWUSR, mip_len_show, mip_len_store);
++static KOBJ_MIP_ATTR(offset, S_IRUGO|S_IWUSR, mip_offset_show,
++ mip_offset_store);
++static KOBJ_MIP_ATTR(issigned, S_IRUGO|S_IWUSR, mip_issigned_show,
++ mip_issigned_store);
++static KOBJ_MIP_ATTR(cmd, S_IWUSR, NULL, mip_cmd_store);
++static KOBJ_MIP_ATTR(error, S_IRUGO, mip_error_show, NULL);
++
++static struct attribute *mip_attrs[] = {
++ &data_attr.attr,
++ &len_attr.attr,
++ &offset_attr.attr,
++ &issigned_attr.attr,
++ &cmd_attr.attr,
++ &error_attr.attr,
++ NULL,
++};
++
++static struct attribute_group mip_attr_group = {
++ .name = "mip_debug",
++ .attrs = mip_attrs,
++};
++
++static int scu_mip_probe(struct platform_device *pdev)
++{
++ if (intel_mid_identify_cpu() != INTEL_MID_CPU_CHIP_PENWELL) {
++ if (!pdev->dev.platform_data)
++ return -EINVAL;
++ pdata =
++ (struct scu_mip_platform_data *)pdev->dev.platform_data;
++ }
++ return 0;
++}
++
++static int scu_mip_remove(struct platform_device *pdev)
++{
++ platform_set_drvdata(pdev, NULL);
++ return 0;
++}
++
++static const struct platform_device_id scu_mip_table[] = {
++ {DRIVER_NAME, 1 },
++};
++
++static struct platform_driver scu_mip_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = scu_mip_probe,
++ .remove = scu_mip_remove,
++ .id_table = scu_mip_table,
++};
++
++static int __init scu_mip_init(void)
++{
++ return platform_driver_register(&scu_mip_driver);
++}
++
++static void scu_mip_exit(void)
++{
++ platform_driver_unregister(&scu_mip_driver);
++}
++
++static int mip_rpmsg_probe(struct rpmsg_channel *rpdev)
++{
++ int ret = 0;
++
++ if (rpdev == NULL) {
++ pr_err("rpmsg channel not created\n");
++ ret = -ENODEV;
++ goto out;
++ }
++
++ dev_info(&rpdev->dev, "Probed mip rpmsg device\n");
++
++ /* Allocate rpmsg instance for mip*/
++ ret = alloc_rpmsg_instance(rpdev, &mip_instance);
++ if (!mip_instance) {
++ dev_err(&rpdev->dev, "kzalloc mip instance failed\n");
++ goto out;
++ }
++ /* Initialize rpmsg instance */
++ init_rpmsg_instance(mip_instance);
++
++ /* Init mip base */
++ intel_mip_base = ioremap_nocache(IPC_MIP_BASE, IPC_MIP_MAX_ADDR);
++ if (!intel_mip_base) {
++ ret = -ENOMEM;
++ goto rpmsg_err;
++ }
++
++ /* Create debugfs for mip regs */
++ scu_mip_kobj = kobject_create_and_add(mip_attr_group.name,
++ kernel_kobj);
++
++ if (!scu_mip_kobj) {
++ ret = -ENOMEM;
++ goto mip_base_err;
++ }
++
++ ret = sysfs_create_group(scu_mip_kobj, &mip_attr_group);
++
++ if (ret) {
++ kobject_put(scu_mip_kobj);
++ goto mip_base_err;
++ }
++
++ ret = scu_mip_init();
++ goto out;
++mip_base_err:
++ iounmap(intel_mip_base);
++rpmsg_err:
++ free_rpmsg_instance(rpdev, &mip_instance);
++out:
++ return ret;
++}
++
++static void mip_rpmsg_remove(struct rpmsg_channel *rpdev)
++{
++ scu_mip_exit();
++ iounmap(intel_mip_base);
++ free_rpmsg_instance(rpdev, &mip_instance);
++ sysfs_remove_group(scu_mip_kobj, &mip_attr_group);
++ kobject_put(scu_mip_kobj);
++ dev_info(&rpdev->dev, "Removed mip rpmsg device\n");
++}
++
++static void mip_rpmsg_cb(struct rpmsg_channel *rpdev, void *data,
++ int len, void *priv, u32 src)
++{
++ dev_warn(&rpdev->dev, "unexpected, message\n");
++
++ print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
++ data, len, true);
++}
++
++static struct rpmsg_device_id mip_rpmsg_id_table[] = {
++ { .name = "rpmsg_mip" },
++ { },
++};
++MODULE_DEVICE_TABLE(rpmsg, mip_rpmsg_id_table);
++
++static struct rpmsg_driver mip_rpmsg = {
++ .drv.name = KBUILD_MODNAME,
++ .drv.owner = THIS_MODULE,
++ .id_table = mip_rpmsg_id_table,
++ .probe = mip_rpmsg_probe,
++ .callback = mip_rpmsg_cb,
++ .remove = mip_rpmsg_remove,
++};
++
++static int __init mip_rpmsg_init(void)
++{
++ if ((intel_mid_identify_cpu() != INTEL_MID_CPU_CHIP_PENWELL)
++ && (intel_mid_identify_cpu() != INTEL_MID_CPU_CHIP_CLOVERVIEW))
++ return -EINVAL;
++
++ return register_rpmsg_driver(&mip_rpmsg);
++}
++
++#ifdef MODULE
++module_init(mip_rpmsg_init);
++#else
++fs_initcall_sync(mip_rpmsg_init);
++#endif
++
++static void __exit mip_rpmsg_exit(void)
++{
++ return unregister_rpmsg_driver(&mip_rpmsg);
++}
++module_exit(mip_rpmsg_exit);
++
++MODULE_AUTHOR("Shijie Zhang <shijie.zhang@intel.com>");
++MODULE_DESCRIPTION("Intel SCU MIP driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/platform/x86/intel_scu_pmic.c b/drivers/platform/x86/intel_scu_pmic.c
+new file mode 100644
+index 0000000..d92e1dc
+--- /dev/null
++++ b/drivers/platform/x86/intel_scu_pmic.c
+@@ -0,0 +1,477 @@
++/*
++ * pmic.c - Intel MSIC Driver
++ *
++ * Copyright (C) 2012 Intel Corporation
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * 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; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ * Author: Bin Yang <bin.yang@intel.com>
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/io.h>
++#include <linux/uaccess.h>
++#include <linux/device.h>
++#include <linux/delay.h>
++#include <linux/fs.h>
++#include <linux/debugfs.h>
++#include <linux/rpmsg.h>
++#include <asm/intel_scu_pmic.h>
++#include <asm/intel_scu_ipc.h>
++#include <asm/intel_mid_rpmsg.h>
++#include <linux/platform_data/intel_mid_remoteproc.h>
++
++#define IPC_WWBUF_SIZE 20
++#define IPC_RWBUF_SIZE 20
++
++static struct kobject *scu_pmic_kobj;
++static struct rpmsg_instance *pmic_instance;
++
++static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 cmd, u32 sub)
++{
++ int i, err, inlen = 0, outlen = 0;
++
++ u8 wbuf[IPC_WWBUF_SIZE] = {};
++ u8 rbuf[IPC_RWBUF_SIZE] = {};
++
++ memset(wbuf, 0, sizeof(wbuf));
++
++ for (i = 0; i < count; i++) {
++ wbuf[inlen++] = addr[i] & 0xff;
++ wbuf[inlen++] = (addr[i] >> 8) & 0xff;
++ }
++
++ if (sub == IPC_CMD_PCNTRL_R) {
++ outlen = count > 0 ? ((count - 1) / 4) + 1 : 0;
++ } else if (sub == IPC_CMD_PCNTRL_W) {
++ if (count == 3)
++ inlen += 2;
++
++ for (i = 0; i < count; i++)
++ wbuf[inlen++] = data[i] & 0xff;
++
++ if (count == 3)
++ inlen -= 2;
++
++ outlen = 0;
++ } else if (sub == IPC_CMD_PCNTRL_M) {
++ wbuf[inlen++] = data[0] & 0xff;
++ wbuf[inlen++] = data[1] & 0xff;
++ outlen = 0;
++ } else
++ pr_err("IPC command not supported\n");
++
++ err = rpmsg_send_command(pmic_instance, cmd, sub, wbuf,
++ (u32 *)rbuf, inlen, outlen);
++
++ if (sub == IPC_CMD_PCNTRL_R) {
++ for (i = 0; i < count; i++)
++ data[i] = rbuf[i];
++ }
++
++ return err;
++}
++
++int intel_scu_ipc_ioread8(u16 addr, u8 *data)
++{
++ return pwr_reg_rdwr(&addr, data, 1, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R);
++}
++EXPORT_SYMBOL(intel_scu_ipc_ioread8);
++
++int intel_scu_ipc_iowrite8(u16 addr, u8 data)
++{
++ return pwr_reg_rdwr(&addr, &data, 1, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W);
++}
++EXPORT_SYMBOL(intel_scu_ipc_iowrite8);
++
++int intel_scu_ipc_iowrite32(u16 addr, u32 data)
++{
++ u16 x[4] = {addr, addr + 1, addr + 2, addr + 3};
++ return pwr_reg_rdwr(x, (u8 *)&data, 4, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W);
++}
++EXPORT_SYMBOL(intel_scu_ipc_iowrite32);
++
++int intel_scu_ipc_readv(u16 *addr, u8 *data, int len)
++{
++ if (len < 1 || len > 8)
++ return -EINVAL;
++
++ return pwr_reg_rdwr(addr, data, len, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R);
++}
++EXPORT_SYMBOL(intel_scu_ipc_readv);
++
++int intel_scu_ipc_writev(u16 *addr, u8 *data, int len)
++{
++ if (len < 1 || len > 4)
++ return -EINVAL;
++
++ return pwr_reg_rdwr(addr, data, len, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W);
++}
++EXPORT_SYMBOL(intel_scu_ipc_writev);
++
++int intel_scu_ipc_update_register(u16 addr, u8 bits, u8 mask)
++{
++ u8 data[2] = { bits, mask };
++ return pwr_reg_rdwr(&addr, data, 1, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_M);
++}
++EXPORT_SYMBOL(intel_scu_ipc_update_register);
++
++/* pmic sysfs for debug */
++
++#define MAX_PMIC_REG_NR 4
++#define PMIC_OPS_LEN 10
++
++enum {
++ PMIC_DBG_ADDR,
++ PMIC_DBG_BITS,
++ PMIC_DBG_DATA,
++ PMIC_DBG_MASK,
++};
++
++static char *pmic_msg_format[] = {
++ "addr[%d]: %#x\n",
++ "bits[%d]: %#x\n",
++ "data[%d]: %#x\n",
++ "mask[%d]: %#x\n",
++};
++
++static u16 pmic_reg_addr[MAX_PMIC_REG_NR];
++static u8 pmic_reg_bits[MAX_PMIC_REG_NR];
++static u8 pmic_reg_data[MAX_PMIC_REG_NR];
++static u8 pmic_reg_mask[MAX_PMIC_REG_NR];
++static int valid_addr_nr;
++static int valid_bits_nr;
++static int valid_data_nr;
++static int valid_mask_nr;
++static char pmic_ops[PMIC_OPS_LEN];
++
++static int pmic_dbg_error;
++
++static ssize_t pmic_generic_show(char *buf, int valid, u8 *array, int type)
++{
++ int i, buf_size;
++ ssize_t ret = 0;
++
++ switch (type) {
++ case PMIC_DBG_ADDR:
++ for (i = 0; i < valid; i++) {
++ buf_size = PAGE_SIZE - ret;
++ ret += snprintf(buf + ret, buf_size,
++ pmic_msg_format[type],
++ i, pmic_reg_addr[i]);
++ }
++ break;
++ case PMIC_DBG_BITS:
++ case PMIC_DBG_DATA:
++ case PMIC_DBG_MASK:
++ for (i = 0; i < valid; i++) {
++ buf_size = PAGE_SIZE - ret;
++ ret += snprintf(buf + ret, buf_size,
++ pmic_msg_format[type],
++ i, array[i]);
++ }
++ break;
++ default:
++ break;
++ }
++
++ return ret;
++}
++
++static void pmic_generic_store(const char *buf, int *valid, u8 *array, int type)
++{
++ u32 tmp[MAX_PMIC_REG_NR];
++ int i, ret;
++
++ ret = sscanf(buf, "%x %x %x %x", &tmp[0], &tmp[1], &tmp[2], &tmp[3]);
++ if (ret == 0 || ret > MAX_PMIC_REG_NR) {
++ *valid = 0;
++ pmic_dbg_error = -EINVAL;
++ return;
++ }
++
++ *valid = ret;
++
++ switch (type) {
++ case PMIC_DBG_ADDR:
++ memset(pmic_reg_addr, 0, sizeof(pmic_reg_addr));
++ for (i = 0; i < ret; i++)
++ pmic_reg_addr[i] = (u16)tmp[i];
++ break;
++ case PMIC_DBG_BITS:
++ case PMIC_DBG_DATA:
++ case PMIC_DBG_MASK:
++ memset(array, 0, sizeof(*array) * MAX_PMIC_REG_NR);
++ for (i = 0; i < ret; i++)
++ array[i] = (u8)tmp[i];
++ break;
++ default:
++ break;
++ }
++}
++
++static ssize_t pmic_addr_show(struct kobject *kobj, struct kobj_attribute *attr,
++ char *buf)
++{
++ return pmic_generic_show(buf, valid_addr_nr, NULL, PMIC_DBG_ADDR);
++}
++
++static ssize_t pmic_addr_store(struct kobject *kobj,
++ struct kobj_attribute *attr, const char *buf, size_t size)
++{
++ pmic_generic_store(buf, &valid_addr_nr, NULL, PMIC_DBG_ADDR);
++ return size;
++}
++
++static ssize_t pmic_bits_show(struct kobject *kobj, struct kobj_attribute *attr,
++ char *buf)
++{
++ return pmic_generic_show(buf, valid_bits_nr, pmic_reg_bits,
++ PMIC_DBG_BITS);
++}
++static ssize_t pmic_bits_store(struct kobject *kobj,
++ struct kobj_attribute *attr, const char *buf, size_t size)
++{
++ pmic_generic_store(buf, &valid_bits_nr, pmic_reg_bits, PMIC_DBG_BITS);
++ return size;
++}
++
++static ssize_t pmic_data_show(struct kobject *kobj, struct kobj_attribute *attr,
++ char *buf)
++{
++ return pmic_generic_show(buf, valid_data_nr, pmic_reg_data,
++ PMIC_DBG_DATA);
++}
++
++static ssize_t pmic_data_store(struct kobject *kobj,
++ struct kobj_attribute *attr, const char *buf, size_t size)
++{
++ pmic_generic_store(buf, &valid_data_nr, pmic_reg_data, PMIC_DBG_DATA);
++ return size;
++}
++
++static ssize_t pmic_mask_show(struct kobject *kobj, struct kobj_attribute *attr,
++ char *buf)
++{
++ return pmic_generic_show(buf, valid_mask_nr, pmic_reg_mask,
++ PMIC_DBG_MASK);
++}
++
++static ssize_t pmic_mask_store(struct kobject *kobj,
++ struct kobj_attribute *attr, const char *buf, size_t size)
++{
++ pmic_generic_store(buf, &valid_mask_nr, pmic_reg_mask, PMIC_DBG_MASK);
++ return size;
++}
++
++static ssize_t pmic_ops_store(struct kobject *kobj,
++ struct kobj_attribute *attr, const char *buf, size_t size)
++{
++ int i, ret;
++
++ memset(pmic_ops, 0, sizeof(pmic_ops));
++
++ ret = sscanf(buf, "%9s", pmic_ops);
++ if (ret == 0) {
++ pmic_dbg_error = -EINVAL;
++ goto end;
++ }
++
++ if (valid_addr_nr <= 0) {
++ pmic_dbg_error = -EINVAL;
++ goto end;
++ }
++
++ if (!strncmp("read", pmic_ops, PMIC_OPS_LEN)) {
++ valid_data_nr = valid_addr_nr;
++ for (i = 0; i < valid_addr_nr; i++) {
++ ret = intel_scu_ipc_ioread8(pmic_reg_addr[i],
++ &pmic_reg_data[i]);
++ if (ret) {
++ pmic_dbg_error = ret;
++ goto end;
++ }
++ }
++ } else if (!strncmp("write", pmic_ops, PMIC_OPS_LEN)) {
++ if (valid_addr_nr == valid_data_nr) {
++ for (i = 0; i < valid_addr_nr; i++) {
++ ret = intel_scu_ipc_iowrite8(pmic_reg_addr[i],
++ pmic_reg_data[i]);
++ if (ret) {
++ pmic_dbg_error = ret;
++ goto end;
++ }
++ }
++ } else {
++ pmic_dbg_error = -EINVAL;
++ goto end;
++ }
++ } else if (!strncmp("update", pmic_ops, PMIC_OPS_LEN)) {
++ if (valid_addr_nr == valid_mask_nr &&
++ valid_mask_nr == valid_bits_nr) {
++ for (i = 0; i < valid_addr_nr; i++) {
++ ret = intel_scu_ipc_update_register(
++ pmic_reg_addr[i],
++ pmic_reg_bits[i],
++ pmic_reg_mask[i]);
++ if (ret) {
++ pmic_dbg_error = ret;
++ goto end;
++ }
++ }
++ } else {
++ pmic_dbg_error = -EINVAL;
++ goto end;
++ }
++ } else {
++ pmic_dbg_error = -EINVAL;
++ goto end;
++ }
++
++ pmic_dbg_error = 0;
++
++end:
++ return size;
++}
++
++static ssize_t pmic_show_error(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return snprintf(buf, PAGE_SIZE, "%d\n", pmic_dbg_error);
++}
++
++static KOBJ_PMIC_ATTR(addr, S_IRUGO|S_IWUSR, pmic_addr_show, pmic_addr_store);
++static KOBJ_PMIC_ATTR(bits, S_IRUGO|S_IWUSR, pmic_bits_show, pmic_bits_store);
++static KOBJ_PMIC_ATTR(data, S_IRUGO|S_IWUSR, pmic_data_show, pmic_data_store);
++static KOBJ_PMIC_ATTR(mask, S_IRUGO|S_IWUSR, pmic_mask_show, pmic_mask_store);
++static KOBJ_PMIC_ATTR(ops, S_IWUSR, NULL, pmic_ops_store);
++static KOBJ_PMIC_ATTR(error, S_IRUGO, pmic_show_error, NULL);
++
++static struct attribute *pmic_attrs[] = {
++ &addr_attr.attr,
++ &bits_attr.attr,
++ &data_attr.attr,
++ &mask_attr.attr,
++ &ops_attr.attr,
++ &error_attr.attr,
++ NULL,
++};
++
++static struct attribute_group pmic_attr_group = {
++ .name = "pmic_debug",
++ .attrs = pmic_attrs,
++};
++
++static int pmic_rpmsg_probe(struct rpmsg_channel *rpdev)
++{
++ int ret = 0;
++
++ if (rpdev == NULL) {
++ pr_err("rpmsg channel not created\n");
++ ret = -ENODEV;
++ goto out;
++ }
++
++ dev_info(&rpdev->dev, "Probed pmic rpmsg device\n");
++
++ /* Allocate rpmsg instance for pmic*/
++ ret = alloc_rpmsg_instance(rpdev, &pmic_instance);
++ if (!pmic_instance) {
++ dev_err(&rpdev->dev, "kzalloc pmic instance failed\n");
++ goto out;
++ }
++ /* Initialize rpmsg instance */
++ init_rpmsg_instance(pmic_instance);
++
++ /* Create debugfs for pmic regs */
++ scu_pmic_kobj = kobject_create_and_add(pmic_attr_group.name,
++ kernel_kobj);
++
++ if (!scu_pmic_kobj) {
++ ret = -ENOMEM;
++ goto rpmsg_err;
++ }
++
++ ret = sysfs_create_group(scu_pmic_kobj, &pmic_attr_group);
++
++ if (ret) {
++ kobject_put(scu_pmic_kobj);
++ goto rpmsg_err;
++ }
++
++ goto out;
++
++rpmsg_err:
++ free_rpmsg_instance(rpdev, &pmic_instance);
++out:
++ return ret;
++}
++
++static void pmic_rpmsg_remove(struct rpmsg_channel *rpdev)
++{
++ free_rpmsg_instance(rpdev, &pmic_instance);
++ sysfs_remove_group(scu_pmic_kobj, &pmic_attr_group);
++ kobject_put(scu_pmic_kobj);
++ dev_info(&rpdev->dev, "Removed pmic rpmsg device\n");
++}
++
++static void pmic_rpmsg_cb(struct rpmsg_channel *rpdev, void *data,
++ int len, void *priv, u32 src)
++{
++ dev_warn(&rpdev->dev, "unexpected, message\n");
++
++ print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
++ data, len, true);
++}
++
++static struct rpmsg_device_id pmic_rpmsg_id_table[] = {
++ { .name = "rpmsg_pmic" },
++ { },
++};
++MODULE_DEVICE_TABLE(rpmsg, pmic_rpmsg_id_table);
++
++static struct rpmsg_driver pmic_rpmsg = {
++ .drv.name = KBUILD_MODNAME,
++ .drv.owner = THIS_MODULE,
++ .id_table = pmic_rpmsg_id_table,
++ .probe = pmic_rpmsg_probe,
++ .callback = pmic_rpmsg_cb,
++ .remove = pmic_rpmsg_remove,
++};
++
++static int __init pmic_rpmsg_init(void)
++{
++ return register_rpmsg_driver(&pmic_rpmsg);
++}
++
++#ifdef MODULE
++module_init(pmic_rpmsg_init);
++#else
++fs_initcall_sync(pmic_rpmsg_init);
++#endif
++
++static void __exit pmic_rpmsg_exit(void)
++{
++ return unregister_rpmsg_driver(&pmic_rpmsg);
++}
++module_exit(pmic_rpmsg_exit);
++
++MODULE_AUTHOR("Bin Yang<bin.yang@intel.com>");
++MODULE_DESCRIPTION("Intel PMIC Driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
+index 7b8979c..1c83042 100644
+--- a/drivers/power/Kconfig
++++ b/drivers/power/Kconfig
+@@ -14,6 +14,26 @@ config POWER_SUPPLY_DEBUG
+ Say Y here to enable debugging messages for power supply class
+ and drivers.
+
++config PMIC_CCSM
++ tristate "PMIC CCSM driver"
++ select POWER_SUPPLY_BATTID
++ depends on INTEL_SCU_IPC && IIO
++ help
++ Say Y to include support for PMIC Charger Control State Machine driver
++ Driver for initializing and monitoring the CCSM in PMIC
++ This driver sets the CCSM registers and handles the PMIC
++ charger interrupts.
++
++config BQ24261_CHARGER
++ tristate "BQ24261 charger driver"
++ select POWER_SUPPLY_CHARGER
++ depends on I2C
++ help
++ Say Y to include support for BQ24261 Charger driver. This driver
++ makes use of power supply charging framework. So the driver gives
++ the charger hardware abstraction only. Charging logic is abstracted
++ in the charging framework.
++
+ config PDA_POWER
+ tristate "Generic PDA/phone power driver"
+ depends on !S390
+diff --git a/drivers/power/Makefile b/drivers/power/Makefile
+index 653bf6c..ad734a2 100644
+--- a/drivers/power/Makefile
++++ b/drivers/power/Makefile
+@@ -1,12 +1,15 @@
+ ccflags-$(CONFIG_POWER_SUPPLY_DEBUG) := -DDEBUG
+
+-power_supply-y := power_supply_core.o
+-power_supply-$(CONFIG_SYSFS) += power_supply_sysfs.o
+-power_supply-$(CONFIG_LEDS_TRIGGERS) += power_supply_leds.o
++power_supply-y := power_supply_core.o
++power_supply-$(CONFIG_SYSFS) += power_supply_sysfs.o
++power_supply-$(CONFIG_LEDS_TRIGGERS) += power_supply_leds.o
++power_supply-$(CONFIG_POWER_SUPPLY_CHARGER) += power_supply_charger.o
++power_supply-$(CONFIG_POWER_SUPPLY_BATTID) += battery_id.o
+
+ obj-$(CONFIG_POWER_SUPPLY) += power_supply.o
+ obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o
+
++obj-$(CONFIG_POWER_SUPPLY_CHARGING_ALGO_PSE) += charging_algo_pse.o
+ obj-$(CONFIG_PDA_POWER) += pda_power.o
+ obj-$(CONFIG_APM_POWER) += apm_power.o
+ obj-$(CONFIG_MAX8925_POWER) += max8925_power.o
+@@ -54,3 +57,6 @@ obj-$(CONFIG_POWER_AVS) += avs/
+ obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
+ obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o
+ obj-$(CONFIG_POWER_RESET) += reset/
++
++obj-$(CONFIG_BQ24261_CHARGER) += bq24261_charger.o
++obj-$(CONFIG_PMIC_CCSM) += pmic_ccsm.o
+diff --git a/drivers/power/battery_id.c b/drivers/power/battery_id.c
+new file mode 100644
+index 0000000..13425b6
+--- /dev/null
++++ b/drivers/power/battery_id.c
+@@ -0,0 +1,68 @@
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/io.h>
++#include <linux/err.h>
++#include <linux/notifier.h>
++#include <linux/power/battery_id.h>
++
++ATOMIC_NOTIFIER_HEAD(batt_id_notifier);
++
++static struct ps_batt_chg_prof *batt_property;
++static int batt_status;
++
++int batt_id_reg_notifier(struct notifier_block *nb)
++{
++ return atomic_notifier_chain_register(&batt_id_notifier, nb);
++}
++EXPORT_SYMBOL_GPL(batt_id_reg_notifier);
++
++void batt_id_unreg_notifier(struct notifier_block *nb)
++{
++ atomic_notifier_chain_unregister(&batt_id_notifier, nb);
++}
++EXPORT_SYMBOL_GPL(batt_id_unreg_notifier);
++
++
++/**
++ * battery_prop_changed - Update properties when battery connection status
++ * changes
++ * @battery_conn_stat : The current connection status of battery
++ * @batt_prop : Address of the ps_batt_chg_prof structure with the updated
++ * values passed from the calling function
++ *
++ * Whenever the battery connection status changes this function will be called
++ * to indicate a change in the status and to update the status and value of
++ * properties
++ */
++void battery_prop_changed(int battery_conn_stat,
++ struct ps_batt_chg_prof *batt_prop)
++{
++ if (batt_status != battery_conn_stat) {
++ if (battery_conn_stat == POWER_SUPPLY_BATTERY_INSERTED)
++ batt_property = batt_prop;
++ else
++ batt_property = NULL;
++
++ batt_status = battery_conn_stat;
++ }
++
++ atomic_notifier_call_chain(&batt_id_notifier,
++ 0, &(batt_property));
++
++}
++EXPORT_SYMBOL_GPL(battery_prop_changed);
++
++/**
++ * get_batt_prop - Get the battery connection status and updated properties
++ * @batt_prop : battery properties structure copied to this address
++ */
++int get_batt_prop(struct ps_batt_chg_prof *batt_prop)
++{
++ if (batt_property)
++ memcpy(batt_prop, batt_property,
++ sizeof(struct ps_batt_chg_prof));
++ else
++ return -ENOMEM;
++ return 0;
++}
++EXPORT_SYMBOL_GPL(get_batt_prop);
+diff --git a/drivers/power/bq24261_charger.c b/drivers/power/bq24261_charger.c
+new file mode 100644
+index 0000000..0f621e1
+--- /dev/null
++++ b/drivers/power/bq24261_charger.c
+@@ -0,0 +1,1887 @@
++/*
++ * bq24261_charger.c - BQ24261 Charger I2C client driver
++ *
++ * Copyright (C) 2011 Intel Corporation
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * 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; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ * Author: Jenny TC <jenny.tc@intel.com>
++ */
++
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <linux/device.h>
++#include <linux/i2c.h>
++#include <linux/power_supply.h>
++#include <linux/pm_runtime.h>
++#include <linux/io.h>
++#include <linux/sched.h>
++#include <linux/delay.h>
++#include <linux/usb/otg.h>
++#include <linux/power/bq24261_charger.h>
++#include <linux/seq_file.h>
++#include <linux/debugfs.h>
++
++#include <asm/intel_scu_ipc.h>
++
++#define DEV_NAME "bq24261_charger"
++#define DEV_MANUFACTURER "TI"
++#define MODEL_NAME_SIZE 8
++#define DEV_MANUFACTURER_NAME_SIZE 4
++
++#define CHRG_TERM_WORKER_DELAY (30 * HZ)
++#define EXCEPTION_MONITOR_DELAY (60 * HZ)
++#define WDT_RESET_DELAY (15 * HZ)
++
++/* BQ24261 registers */
++#define BQ24261_STAT_CTRL0_ADDR 0x00
++#define BQ24261_CTRL_ADDR 0x01
++#define BQ24261_BATT_VOL_CTRL_ADDR 0x02
++#define BQ24261_VENDOR_REV_ADDR 0x03
++#define BQ24261_TERM_FCC_ADDR 0x04
++#define BQ24261_VINDPM_STAT_ADDR 0x05
++#define BQ24261_ST_NTC_MON_ADDR 0x06
++
++#define BQ24261_RESET_MASK (0x01 << 7)
++#define BQ24261_RESET_ENABLE (0x01 << 7)
++
++#define BQ24261_FAULT_MASK 0x07
++#define BQ24261_STAT_MASK (0x03 << 4)
++#define BQ24261_BOOST_MASK (0x01 << 6)
++#define BQ24261_TMR_RST_MASK (0x01 << 7)
++#define BQ24261_TMR_RST (0x01 << 7)
++
++#define BQ24261_ENABLE_BOOST (0x01 << 6)
++
++#define BQ24261_VOVP 0x01
++#define BQ24261_LOW_SUPPLY 0x02
++#define BQ24261_THERMAL_SHUTDOWN 0x03
++#define BQ24261_BATT_TEMP_FAULT 0x04
++#define BQ24261_TIMER_FAULT 0x05
++#define BQ24261_BATT_OVP 0x06
++#define BQ24261_NO_BATTERY 0x07
++#define BQ24261_STAT_READY 0x00
++
++#define BQ24261_STAT_CHRG_PRGRSS (0x01 << 4)
++#define BQ24261_STAT_CHRG_DONE (0x02 << 4)
++#define BQ24261_STAT_FAULT (0x03 << 4)
++
++#define BQ24261_CE_MASK (0x01 << 1)
++#define BQ24261_CE_DISABLE (0x01 << 1)
++
++#define BQ24261_HZ_MASK (0x01)
++#define BQ24261_HZ_ENABLE (0x01)
++
++#define BQ24261_ICHRG_MASK (0x1F << 3)
++#define BQ24261_ICHRG_100ma (0x01 << 3)
++#define BQ24261_ICHRG_200ma (0x01 << 4)
++#define BQ24261_ICHRG_400ma (0x01 << 5)
++#define BQ24261_ICHRG_800ma (0x01 << 6)
++#define BQ24261_ICHRG_1600ma (0x01 << 7)
++
++#define BQ24261_ITERM_MASK (0x03)
++#define BQ24261_ITERM_50ma (0x01 << 0)
++#define BQ24261_ITERM_100ma (0x01 << 1)
++#define BQ24261_ITERM_200ma (0x01 << 2)
++
++#define BQ24261_VBREG_MASK (0x3F << 2)
++
++#define BQ24261_INLMT_MASK (0x03 << 4)
++#define BQ24261_INLMT_100 0x00
++#define BQ24261_INLMT_150 (0x01 << 4)
++#define BQ24261_INLMT_500 (0x02 << 4)
++#define BQ24261_INLMT_900 (0x03 << 4)
++#define BQ24261_INLMT_1500 (0x04 << 4)
++#define BQ24261_INLMT_2500 (0x06 << 4)
++
++#define BQ24261_TE_MASK (0x01 << 2)
++#define BQ24261_TE_ENABLE (0x01 << 2)
++#define BQ24261_STAT_ENABLE_MASK (0x01 << 3)
++#define BQ24261_STAT_ENABLE (0x01 << 3)
++
++#define BQ24261_VENDOR_MASK (0x07 << 5)
++#define BQ24261_VENDOR (0x02 << 5)
++#define BQ24261_REV_MASK (0x07)
++#define BQ24261_2_3_REV (0x06)
++#define BQ24261_REV (0x02)
++#define BQ24260_REV (0x01)
++
++#define BQ24261_TS_MASK (0x01 << 3)
++#define BQ24261_TS_ENABLED (0x01 << 3)
++#define BQ24261_BOOST_ILIM_MASK (0x01 << 4)
++#define BQ24261_BOOST_ILIM_500ma (0x0)
++#define BQ24261_BOOST_ILIM_1A (0x01 << 4)
++
++#define BQ24261_SAFETY_TIMER_MASK (0x03 << 5)
++#define BQ24261_SAFETY_TIMER_40MIN 0x00
++#define BQ24261_SAFETY_TIMER_6HR (0x01 << 5)
++#define BQ24261_SAFETY_TIMER_9HR (0x02 << 5)
++#define BQ24261_SAFETY_TIMER_DISABLED (0x03 << 5)
++
++/* 1% above voltage max design to report over voltage */
++#define BQ24261_OVP_MULTIPLIER 1010
++#define BQ24261_OVP_RECOVER_MULTIPLIER 990
++#define BQ24261_DEF_BAT_VOLT_MAX_DESIGN 4200000
++
++/* Settings for Voltage / DPPM Register (05) */
++#define BQ24261_VBATT_LEVEL1 3700000
++#define BQ24261_VBATT_LEVEL2 3960000
++#define BQ24261_VINDPM_MASK (0x07)
++#define BQ24261_VINDPM_320MV (0x01 << 2)
++#define BQ24261_VINDPM_160MV (0x01 << 1)
++#define BQ24261_VINDPM_80MV (0x01 << 0)
++#define BQ24261_CD_STATUS_MASK (0x01 << 3)
++#define BQ24261_DPM_EN_MASK (0x01 << 4)
++#define BQ24261_DPM_EN_FORCE (0x01 << 4)
++#define BQ24261_LOW_CHG_MASK (0x01 << 5)
++#define BQ24261_LOW_CHG_EN (0x01 << 5)
++#define BQ24261_LOW_CHG_DIS (~BQ24261_LOW_CHG_EN)
++#define BQ24261_DPM_STAT_MASK (0x01 << 6)
++#define BQ24261_MINSYS_STAT_MASK (0x01 << 7)
++
++#define BQ24261_MIN_CC 500
++
++u16 bq24261_sfty_tmr[][2] = {
++ {0, BQ24261_SAFETY_TIMER_DISABLED}
++ ,
++ {40, BQ24261_SAFETY_TIMER_40MIN}
++ ,
++ {360, BQ24261_SAFETY_TIMER_6HR}
++ ,
++ {540, BQ24261_SAFETY_TIMER_9HR}
++ ,
++};
++
++
++u16 bq24261_inlmt[][2] = {
++ {100, BQ24261_INLMT_100}
++ ,
++ {150, BQ24261_INLMT_150}
++ ,
++ {500, BQ24261_INLMT_500}
++ ,
++ {900, BQ24261_INLMT_900}
++ ,
++ {1500, BQ24261_INLMT_1500}
++ ,
++ {2500, BQ24261_INLMT_2500}
++ ,
++};
++
++u16 bq24261_iterm[][2] = {
++ {0, 0x00}
++ ,
++ {50, BQ24261_ITERM_50ma}
++ ,
++ {100, BQ24261_ITERM_100ma}
++ ,
++ {150, BQ24261_ITERM_100ma | BQ24261_ITERM_50ma}
++ ,
++ {200, BQ24261_ITERM_200ma}
++ ,
++ {250, BQ24261_ITERM_200ma | BQ24261_ITERM_50ma}
++ ,
++ {300, BQ24261_ITERM_200ma | BQ24261_ITERM_100ma}
++ ,
++ {350, BQ24261_ITERM_200ma | BQ24261_ITERM_100ma | BQ24261_ITERM_50ma}
++ ,
++};
++
++u16 bq24261_cc[][2] = {
++
++ {500, 0x00}
++ ,
++ {600, BQ24261_ICHRG_100ma}
++ ,
++ {700, BQ24261_ICHRG_200ma}
++ ,
++ {800, BQ24261_ICHRG_100ma | BQ24261_ICHRG_200ma}
++ ,
++ {900, BQ24261_ICHRG_400ma}
++ ,
++ {1000, BQ24261_ICHRG_400ma | BQ24261_ICHRG_100ma}
++ ,
++ {1100, BQ24261_ICHRG_400ma | BQ24261_ICHRG_200ma}
++ ,
++ {1200, BQ24261_ICHRG_400ma | BQ24261_ICHRG_200ma | BQ24261_ICHRG_100ma}
++ ,
++ {1300, BQ24261_ICHRG_800ma}
++ ,
++ {1400, BQ24261_ICHRG_800ma | BQ24261_ICHRG_100ma}
++ ,
++ {1500, BQ24261_ICHRG_800ma | BQ24261_ICHRG_200ma}
++ ,
++};
++
++#define BQ24261_MIN_CV 3500
++#define BQ24261_MAX_CV 4440
++#define BQ24261_CV_DIV 20
++#define BQ24261_CV_BIT_POS 2
++
++static enum power_supply_property bq24261_usb_props[] = {
++ POWER_SUPPLY_PROP_PRESENT,
++ POWER_SUPPLY_PROP_ONLINE,
++ POWER_SUPPLY_PROP_TYPE,
++ POWER_SUPPLY_PROP_HEALTH,
++ POWER_SUPPLY_PROP_MAX_CHARGE_CURRENT,
++ POWER_SUPPLY_PROP_MAX_CHARGE_VOLTAGE,
++ POWER_SUPPLY_PROP_CHARGE_CURRENT,
++ POWER_SUPPLY_PROP_CHARGE_VOLTAGE,
++ POWER_SUPPLY_PROP_INLMT,
++ POWER_SUPPLY_PROP_ENABLE_CHARGING,
++ POWER_SUPPLY_PROP_ENABLE_CHARGER,
++ POWER_SUPPLY_PROP_CHARGE_TERM_CUR,
++ POWER_SUPPLY_PROP_CABLE_TYPE,
++ POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
++ POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
++ POWER_SUPPLY_PROP_MODEL_NAME,
++ POWER_SUPPLY_PROP_MANUFACTURER,
++ POWER_SUPPLY_PROP_MAX_TEMP,
++ POWER_SUPPLY_PROP_MIN_TEMP,
++};
++
++enum bq24261_chrgr_stat {
++ BQ24261_CHRGR_STAT_UNKNOWN,
++ BQ24261_CHRGR_STAT_READY,
++ BQ24261_CHRGR_STAT_CHARGING,
++ BQ24261_CHRGR_STAT_BAT_FULL,
++ BQ24261_CHRGR_STAT_FAULT,
++};
++
++struct bq24261_otg_event {
++ struct list_head node;
++ bool is_enable;
++};
++
++struct bq24261_charger {
++
++ struct mutex lock;
++ struct i2c_client *client;
++ struct bq24261_plat_data *pdata;
++ struct power_supply psy_usb;
++ struct delayed_work sw_term_work;
++ struct delayed_work wdt_work;
++ struct delayed_work low_supply_fault_work;
++ struct delayed_work exception_mon_work;
++ struct notifier_block otg_nb;
++ struct usb_phy *transceiver;
++ struct work_struct otg_work;
++ struct work_struct irq_work;
++ struct list_head otg_queue;
++ struct list_head irq_queue;
++ wait_queue_head_t wait_ready;
++ spinlock_t otg_queue_lock;
++ void __iomem *irq_iomap;
++
++ int chrgr_health;
++ int bat_health;
++ int cc;
++ int cv;
++ int inlmt;
++ int max_cc;
++ int max_cv;
++ int iterm;
++ int cable_type;
++ int cntl_state;
++ int max_temp;
++ int min_temp;
++ int revision;
++ enum bq24261_chrgr_stat chrgr_stat;
++ bool online;
++ bool present;
++ bool is_charging_enabled;
++ bool is_charger_enabled;
++ bool is_vsys_on;
++ bool boost_mode;
++ bool is_hw_chrg_term;
++ char model_name[MODEL_NAME_SIZE];
++ char manufacturer[DEV_MANUFACTURER_NAME_SIZE];
++};
++
++enum bq2426x_model_num {
++ BQ2426X = 0,
++ BQ24260,
++ BQ24261,
++};
++
++struct bq2426x_model {
++ char model_name[MODEL_NAME_SIZE];
++ enum bq2426x_model_num model;
++};
++
++static struct bq2426x_model bq24261_model_name[] = {
++ { "bq2426x", BQ2426X },
++ { "bq24260", BQ24260 },
++ { "bq24261", BQ24261 },
++};
++
++struct i2c_client *bq24261_client;
++static inline int get_battery_voltage(int *volt);
++static inline int get_battery_current(int *cur);
++static int bq24261_handle_irq(struct bq24261_charger *chip, u8 stat_reg);
++static inline int bq24261_set_iterm(struct bq24261_charger *chip, int iterm);
++
++enum power_supply_type get_power_supply_type(
++ enum power_supply_charger_cable_type cable)
++{
++
++ switch (cable) {
++
++ case POWER_SUPPLY_CHARGER_TYPE_USB_DCP:
++ return POWER_SUPPLY_TYPE_USB_DCP;
++ case POWER_SUPPLY_CHARGER_TYPE_USB_CDP:
++ return POWER_SUPPLY_TYPE_USB_CDP;
++ case POWER_SUPPLY_CHARGER_TYPE_USB_ACA:
++ case POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK:
++ return POWER_SUPPLY_TYPE_USB_ACA;
++ case POWER_SUPPLY_CHARGER_TYPE_AC:
++ return POWER_SUPPLY_TYPE_MAINS;
++ case POWER_SUPPLY_CHARGER_TYPE_NONE:
++ case POWER_SUPPLY_CHARGER_TYPE_USB_SDP:
++ default:
++ return POWER_SUPPLY_TYPE_USB;
++ }
++
++ return POWER_SUPPLY_TYPE_USB;
++}
++
++static void lookup_regval(u16 tbl[][2], size_t size, u16 in_val, u8 *out_val)
++{
++ int i;
++ for (i = 1; i < size; ++i)
++ if (in_val < tbl[i][0])
++ break;
++
++ *out_val = (u8) tbl[i - 1][1];
++}
++
++void bq24261_cc_to_reg(int cc, u8 *reg_val)
++{
++ return lookup_regval(bq24261_cc, ARRAY_SIZE(bq24261_cc), cc, reg_val);
++
++}
++
++void bq24261_cv_to_reg(int cv, u8 *reg_val)
++{
++ int val;
++
++ val = clamp_t(int, cv, BQ24261_MIN_CV, BQ24261_MAX_CV);
++ *reg_val =
++ (((val - BQ24261_MIN_CV) / BQ24261_CV_DIV)
++ << BQ24261_CV_BIT_POS);
++}
++
++void bq24261_inlmt_to_reg(int inlmt, u8 *regval)
++{
++ return lookup_regval(bq24261_inlmt, ARRAY_SIZE(bq24261_inlmt),
++ inlmt, regval);
++}
++
++static inline void bq24261_iterm_to_reg(int iterm, u8 *regval)
++{
++ return lookup_regval(bq24261_iterm, ARRAY_SIZE(bq24261_iterm),
++ iterm, regval);
++}
++
++static inline void bq24261_sfty_tmr_to_reg(int tmr, u8 *regval)
++{
++ return lookup_regval(bq24261_sfty_tmr, ARRAY_SIZE(bq24261_sfty_tmr),
++ tmr, regval);
++}
++
++static inline int bq24261_read_reg(struct i2c_client *client, u8 reg)
++{
++ int ret;
++
++ ret = i2c_smbus_read_byte_data(client, reg);
++ if (ret < 0)
++ dev_err(&client->dev, "Error(%d) in reading reg %d\n", ret,
++ reg);
++
++ return ret;
++}
++
++
++static inline void bq24261_dump_regs(bool dump_master)
++{
++ int i;
++ int ret;
++ int bat_cur, bat_volt;
++ struct bq24261_charger *chip;
++
++ if (!bq24261_client)
++ return;
++
++ chip = i2c_get_clientdata(bq24261_client);
++
++ ret = get_battery_current(&bat_cur);
++ if (ret)
++ dev_err(&bq24261_client->dev,
++ "%s: Error in getting battery current", __func__);
++ else
++ dev_info(&bq24261_client->dev, "Battery Current=%dma\n",
++ (bat_cur/1000));
++
++ ret = get_battery_voltage(&bat_volt);
++ if (ret)
++ dev_err(&bq24261_client->dev,
++ "%s: Error in getting battery voltage", __func__);
++ else
++ dev_info(&bq24261_client->dev, "Battery VOlatge=%dmV\n",
++ (bat_volt/1000));
++
++
++ dev_info(&bq24261_client->dev, "BQ24261 Register dump\n");
++
++ dev_info(&bq24261_client->dev, "*======================*\n");
++ for (i = 0; i < 7; ++i) {
++ ret = bq24261_read_reg(bq24261_client, i);
++ if (ret < 0)
++ dev_err(&bq24261_client->dev,
++ "Error in reading REG 0x%X\n", i);
++ else
++ dev_info(&bq24261_client->dev,
++ "0x%X=0x%X ", i, ret);
++ }
++ dev_info(&bq24261_client->dev, "*======================*\n");
++
++ if (chip->pdata->dump_master_regs && dump_master)
++ chip->pdata->dump_master_regs();
++
++}
++
++
++#ifdef CONFIG_DEBUG_FS
++static int bq24261_reg_show(struct seq_file *seq, void *unused)
++{
++ int val;
++ u8 reg;
++
++ reg = *((u8 *)seq->private);
++ val = bq24261_read_reg(bq24261_client, reg);
++
++ seq_printf(seq, "0x%02x\n", val);
++ return 0;
++}
++
++static int bq24261_dbgfs_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, bq24261_reg_show, inode->i_private);
++}
++
++static u32 bq24261_register_set[] = {
++ BQ24261_STAT_CTRL0_ADDR,
++ BQ24261_CTRL_ADDR,
++ BQ24261_BATT_VOL_CTRL_ADDR,
++ BQ24261_VENDOR_REV_ADDR,
++ BQ24261_TERM_FCC_ADDR,
++ BQ24261_VINDPM_STAT_ADDR,
++ BQ24261_ST_NTC_MON_ADDR,
++};
++
++static struct dentry *bq24261_dbgfs_dir;
++
++static const struct file_operations bq24261_dbg_fops = {
++ .open = bq24261_dbgfs_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release
++};
++
++static void bq24261_debugfs_init(void)
++{
++ struct dentry *fentry;
++ u32 count = ARRAY_SIZE(bq24261_register_set);
++ u32 i;
++ char name[6] = {0};
++
++ bq24261_dbgfs_dir = debugfs_create_dir(DEV_NAME, NULL);
++ if (bq24261_dbgfs_dir == NULL)
++ goto debugfs_root_exit;
++
++ for (i = 0; i < count; i++) {
++ snprintf(name, 6, "%02x", bq24261_register_set[i]);
++ fentry = debugfs_create_file(name, S_IRUGO,
++ bq24261_dbgfs_dir,
++ &bq24261_register_set[i],
++ &bq24261_dbg_fops);
++ if (fentry == NULL)
++ goto debugfs_err_exit;
++ }
++ dev_err(&bq24261_client->dev, "Debugfs created successfully!!\n");
++ return;
++
++debugfs_err_exit:
++ debugfs_remove_recursive(bq24261_dbgfs_dir);
++debugfs_root_exit:
++ dev_err(&bq24261_client->dev, "Error Creating debugfs!!\n");
++ return;
++}
++
++static void bq24261_debugfs_exit(void)
++{
++ if (bq24261_dbgfs_dir)
++ debugfs_remove_recursive(bq24261_dbgfs_dir);
++
++ return;
++}
++
++#else
++static void bq24261_debugfs_init(void)
++{
++ return;
++}
++
++static void bq24261_debugfs_exit(void)
++{
++ return;
++}
++#endif
++
++static inline int bq24261_write_reg(struct i2c_client *client, u8 reg, u8 data)
++{
++ int ret;
++
++ ret = i2c_smbus_write_byte_data(client, reg, data);
++ if (ret < 0)
++ dev_err(&client->dev, "Error(%d) in writing %d to reg %d\n",
++ ret, data, reg);
++
++ return ret;
++}
++
++static inline int bq24261_read_modify_reg(struct i2c_client *client, u8 reg,
++ u8 mask, u8 val)
++{
++ int ret;
++
++ ret = bq24261_read_reg(client, reg);
++ if (ret < 0)
++ return ret;
++ ret = (ret & ~mask) | (mask & val);
++ return bq24261_write_reg(client, reg, ret);
++}
++
++static inline int bq24261_tmr_ntc_init(struct bq24261_charger *chip)
++{
++ u8 reg_val;
++ int ret;
++
++ bq24261_sfty_tmr_to_reg(chip->pdata->safety_timer, &reg_val);
++
++ if (chip->pdata->is_ts_enabled)
++ reg_val |= BQ24261_TS_ENABLED;
++
++ /* Check if boost mode current configuration is above 1A*/
++ if (chip->pdata->boost_mode_ma >= 1000)
++ reg_val |= BQ24261_BOOST_ILIM_1A;
++
++ ret = bq24261_read_modify_reg(chip->client, BQ24261_ST_NTC_MON_ADDR,
++ BQ24261_TS_MASK|BQ24261_SAFETY_TIMER_MASK|
++ BQ24261_BOOST_ILIM_MASK, reg_val);
++
++ return ret;
++}
++
++static inline int bq24261_enable_charging(
++ struct bq24261_charger *chip, bool val)
++{
++ int ret;
++ u8 reg_val;
++ bool is_ready;
++
++ ret = bq24261_read_reg(chip->client,
++ BQ24261_STAT_CTRL0_ADDR);
++ if (ret < 0) {
++ dev_err(&chip->client->dev,
++ "Error(%d) in reading BQ24261_STAT_CTRL0_ADDR\n", ret);
++ }
++
++ is_ready = (ret & BQ24261_STAT_MASK) != BQ24261_STAT_FAULT;
++
++ /* If status is fault, wait for READY before enabling the charging */
++
++ if (!is_ready) {
++ ret = wait_event_timeout(chip->wait_ready,
++ (chip->chrgr_stat != BQ24261_CHRGR_STAT_READY),
++ HZ);
++ dev_info(&chip->client->dev,
++ "chrgr_stat=%x\n", chip->chrgr_stat);
++ if (ret == 0) {
++ dev_err(&chip->client->dev,
++ "Waiting for Charger Ready Failed.Enabling charging anyway\n");
++ }
++ }
++
++ if (chip->pdata->enable_charging)
++ chip->pdata->enable_charging(val);
++
++ if (val) {
++ reg_val = (~BQ24261_CE_DISABLE & BQ24261_CE_MASK);
++ if (chip->is_hw_chrg_term)
++ reg_val |= BQ24261_TE_ENABLE;
++ } else {
++ reg_val = BQ24261_CE_DISABLE;
++ }
++
++ reg_val |= BQ24261_STAT_ENABLE;
++
++ ret = bq24261_read_modify_reg(chip->client, BQ24261_CTRL_ADDR,
++ BQ24261_STAT_ENABLE_MASK|BQ24261_RESET_MASK|
++ BQ24261_CE_MASK|BQ24261_TE_MASK,
++ reg_val);
++ if (ret || !val)
++ return ret;
++
++ bq24261_set_iterm(chip, chip->iterm);
++ return bq24261_tmr_ntc_init(chip);
++}
++
++static inline int bq24261_reset_timer(struct bq24261_charger *chip)
++{
++ return bq24261_read_modify_reg(chip->client, BQ24261_STAT_CTRL0_ADDR,
++ BQ24261_TMR_RST_MASK, BQ24261_TMR_RST);
++}
++
++static inline int bq24261_enable_charger(
++ struct bq24261_charger *chip, int val)
++{
++
++ /* TODO: Implement enable/disable HiZ mode to enable/
++ * disable charger
++ */
++ u8 reg_val;
++ int ret;
++
++ reg_val = val ? (~BQ24261_HZ_ENABLE & BQ24261_HZ_MASK) :
++ BQ24261_HZ_ENABLE;
++
++ ret = bq24261_read_modify_reg(chip->client, BQ24261_CTRL_ADDR,
++ BQ24261_HZ_MASK|BQ24261_RESET_MASK, reg_val);
++ if (ret)
++ return ret;
++
++ return bq24261_reset_timer(chip);
++}
++
++static inline int bq24261_set_cc(struct bq24261_charger *chip, int cc)
++{
++ u8 reg_val;
++ int ret;
++
++ dev_dbg(&chip->client->dev, "cc=%d\n", cc);
++ if (chip->pdata->set_cc) {
++ ret = chip->pdata->set_cc(cc);
++ if (unlikely(ret))
++ return ret;
++ }
++
++ if (cc && (cc < BQ24261_MIN_CC)) {
++ dev_dbg(&chip->client->dev, "Set LOW_CHG bit\n");
++ reg_val = BQ24261_LOW_CHG_EN;
++ ret = bq24261_read_modify_reg(chip->client,
++ BQ24261_VINDPM_STAT_ADDR,
++ BQ24261_LOW_CHG_MASK, reg_val);
++ } else {
++ dev_dbg(&chip->client->dev, "Clear LOW_CHG bit\n");
++ reg_val = BQ24261_LOW_CHG_DIS;
++ ret = bq24261_read_modify_reg(chip->client,
++ BQ24261_VINDPM_STAT_ADDR,
++ BQ24261_LOW_CHG_MASK, reg_val);
++ }
++
++ /* Return from here since the cc setting will be done
++ by platform specific hardware */
++ if (chip->pdata->set_cc)
++ return ret;
++
++ bq24261_cc_to_reg(cc, &reg_val);
++
++ return bq24261_read_modify_reg(chip->client, BQ24261_TERM_FCC_ADDR,
++ BQ24261_ICHRG_MASK, reg_val);
++}
++
++static inline int bq24261_set_cv(struct bq24261_charger *chip, int cv)
++{
++ int bat_volt;
++ int ret;
++ u8 reg_val;
++ u8 vindpm_val = 0x0;
++
++ /*
++ * Setting VINDPM value as per the battery voltage
++ * VBatt Vindpm Register Setting
++ * < 3.7v 4.2v 0x0 (default)
++ * 3.71v - 3.96v 4.36v 0x2
++ * > 3.96v 4.6v 0x5
++ */
++ ret = get_battery_voltage(&bat_volt);
++ if (ret) {
++ dev_err(&chip->client->dev,
++ "Error getting battery voltage!!\n");
++ } else {
++ if (bat_volt > BQ24261_VBATT_LEVEL2)
++ vindpm_val =
++ (BQ24261_VINDPM_320MV | BQ24261_VINDPM_80MV);
++ else if (bat_volt > BQ24261_VBATT_LEVEL1)
++ vindpm_val = BQ24261_VINDPM_160MV;
++ }
++
++ ret = bq24261_read_modify_reg(chip->client,
++ BQ24261_VINDPM_STAT_ADDR,
++ BQ24261_VINDPM_MASK,
++ vindpm_val);
++ if (ret) {
++ dev_err(&chip->client->dev,
++ "Error setting VINDPM setting!!\n");
++ return ret;
++ }
++
++ if (chip->pdata->set_cv)
++ return chip->pdata->set_cv(cv);
++
++ bq24261_cv_to_reg(cv, &reg_val);
++
++ return bq24261_read_modify_reg(chip->client, BQ24261_BATT_VOL_CTRL_ADDR,
++ BQ24261_VBREG_MASK, reg_val);
++}
++
++static inline int bq24261_set_inlmt(struct bq24261_charger *chip, int inlmt)
++{
++ u8 reg_val;
++
++ if (chip->pdata->set_inlmt)
++ return chip->pdata->set_inlmt(inlmt);
++
++ bq24261_inlmt_to_reg(inlmt, &reg_val);
++
++ return bq24261_read_modify_reg(chip->client, BQ24261_CTRL_ADDR,
++ BQ24261_RESET_MASK|BQ24261_INLMT_MASK, reg_val);
++
++}
++
++static inline void resume_charging(struct bq24261_charger *chip)
++{
++
++ if (chip->is_charger_enabled)
++ bq24261_enable_charger(chip, true);
++ if (chip->inlmt)
++ bq24261_set_inlmt(chip, chip->inlmt);
++ if (chip->cc)
++ bq24261_set_cc(chip, chip->cc);
++ if (chip->cv)
++ bq24261_set_cv(chip, chip->cv);
++ if (chip->is_charging_enabled)
++ bq24261_enable_charging(chip, true);
++}
++
++static inline int bq24261_set_iterm(struct bq24261_charger *chip, int iterm)
++{
++ u8 reg_val;
++
++ if (chip->pdata->set_iterm)
++ return chip->pdata->set_iterm(iterm);
++
++ bq24261_iterm_to_reg(iterm, &reg_val);
++
++ return bq24261_read_modify_reg(chip->client, BQ24261_TERM_FCC_ADDR,
++ BQ24261_ITERM_MASK, reg_val);
++}
++
++static inline int bq24261_enable_hw_charge_term(
++ struct bq24261_charger *chip, bool val)
++{
++ u8 data;
++ int ret;
++
++ data = val ? BQ24261_TE_ENABLE : (~BQ24261_TE_ENABLE & BQ24261_TE_MASK);
++
++
++ ret = bq24261_read_modify_reg(chip->client, BQ24261_CTRL_ADDR,
++ BQ24261_RESET_MASK|BQ24261_TE_MASK, data);
++
++ if (ret)
++ return ret;
++
++ chip->is_hw_chrg_term = val ? true : false;
++
++ return ret;
++}
++
++static inline int bq24261_enable_boost_mode(
++ struct bq24261_charger *chip, int val)
++{
++ int ret = 0;
++
++
++ if (val) {
++
++ if ((chip->revision & BQ24261_REV_MASK) == BQ24261_REV) {
++ if (chip->pdata->enable_vbus)
++ chip->pdata->enable_vbus(true);
++ }
++
++ /* TODO: Support different Host Mode Current limits */
++
++ bq24261_enable_charger(chip, true);
++ ret =
++ bq24261_read_modify_reg(chip->client,
++ BQ24261_STAT_CTRL0_ADDR,
++ BQ24261_BOOST_MASK,
++ BQ24261_ENABLE_BOOST);
++ if (unlikely(ret))
++ return ret;
++
++ ret = bq24261_tmr_ntc_init(chip);
++ if (unlikely(ret))
++ return ret;
++ chip->boost_mode = true;
++
++ if ((chip->revision & BQ24261_REV_MASK) == BQ24261_REV)
++ schedule_delayed_work(&chip->wdt_work, 0);
++
++ dev_info(&chip->client->dev, "Boost Mode enabled\n");
++ } else {
++
++ ret =
++ bq24261_read_modify_reg(chip->client,
++ BQ24261_STAT_CTRL0_ADDR,
++ BQ24261_BOOST_MASK,
++ ~BQ24261_ENABLE_BOOST);
++
++ if (unlikely(ret))
++ return ret;
++ /* if charging need not to be enabled, disable
++ * the charger else keep the charger on
++ */
++ if (!chip->is_charging_enabled)
++ bq24261_enable_charger(chip, false);
++ chip->boost_mode = false;
++ dev_info(&chip->client->dev, "Boost Mode disabled\n");
++
++ if ((chip->revision & BQ24261_REV_MASK) == BQ24261_REV) {
++ cancel_delayed_work_sync(&chip->wdt_work);
++
++ if (chip->pdata->enable_vbus)
++ chip->pdata->enable_vbus(false);
++ }
++
++ /* Notify power supply subsystem to enable charging
++ * if needed. Eg. if DC adapter is connected
++ */
++ power_supply_changed(&chip->psy_usb);
++ }
++
++ return ret;
++}
++
++static inline bool bq24261_is_vsys_on(struct bq24261_charger *chip)
++{
++ int ret;
++ struct i2c_client *client = chip->client;
++
++ ret = bq24261_read_reg(client, BQ24261_CTRL_ADDR);
++ if (ret < 0) {
++ dev_err(&client->dev,
++ "Error(%d) in reading BQ24261_CTRL_ADDR\n", ret);
++ return false;
++ }
++
++ if (((ret & BQ24261_HZ_MASK) == BQ24261_HZ_ENABLE) &&
++ chip->is_charger_enabled) {
++ dev_err(&client->dev, "Charger in Hi Z Mode\n");
++ bq24261_dump_regs(true);
++ return false;
++ }
++
++ ret = bq24261_read_reg(client, BQ24261_VINDPM_STAT_ADDR);
++ if (ret < 0) {
++ dev_err(&client->dev,
++ "Error(%d) in reading BQ24261_VINDPM_STAT_ADDR\n", ret);
++ return false;
++ }
++
++ if (ret & BQ24261_CD_STATUS_MASK) {
++ dev_err(&client->dev, "CD line asserted\n");
++ bq24261_dump_regs(true);
++ return false;
++ }
++
++ return true;
++}
++
++
++static inline bool bq24261_is_online(struct bq24261_charger *chip)
++{
++ if (chip->cable_type == POWER_SUPPLY_CHARGER_TYPE_NONE)
++ return false;
++ else if (!chip->is_charger_enabled)
++ return false;
++ /* BQ24261 gives interrupt only on stop/resume charging.
++ * If charging is already stopped, we need to query the hardware
++ * to see charger is still active and can supply vsys or not.
++ */
++ else if ((chip->chrgr_stat == BQ24261_CHRGR_STAT_FAULT) ||
++ (!chip->is_charging_enabled))
++ return bq24261_is_vsys_on(chip);
++ else
++ return chip->is_vsys_on;
++}
++
++static int bq24261_usb_set_property(struct power_supply *psy,
++ enum power_supply_property psp,
++ const union power_supply_propval *val)
++{
++ struct bq24261_charger *chip = container_of(psy,
++ struct bq24261_charger,
++ psy_usb);
++ int ret = 0;
++
++
++ mutex_lock(&chip->lock);
++
++
++ switch (psp) {
++
++ case POWER_SUPPLY_PROP_PRESENT:
++ chip->present = val->intval;
++ /*If charging capable cable is present, then
++ hold the charger wakelock so that the target
++ does not enter suspend mode when charging is
++ in progress.
++ If charging cable has been removed, then
++ unlock the wakelock to allow the target to
++ enter the sleep mode*/
++/* if (!wake_lock_active(&chip->chrgr_en_wakelock) &&
++ val->intval)
++ wake_lock(&chip->chrgr_en_wakelock);
++ else if (wake_lock_active(&chip->chrgr_en_wakelock) &&
++ !val->intval)
++ wake_unlock(&chip->chrgr_en_wakelock);
++*/
++ break;
++ case POWER_SUPPLY_PROP_ONLINE:
++ chip->online = val->intval;
++ break;
++ case POWER_SUPPLY_PROP_ENABLE_CHARGING:
++
++ ret = bq24261_enable_charging(chip, val->intval);
++
++ if (ret)
++ dev_err(&chip->client->dev,
++ "Error(%d) in %s charging", ret,
++ (val->intval ? "enable" : "disable"));
++ else
++ chip->is_charging_enabled = val->intval;
++
++ if (val->intval)
++ bq24261_enable_hw_charge_term(chip, true);
++ else
++ cancel_delayed_work_sync(&chip->sw_term_work);
++
++ break;
++ case POWER_SUPPLY_PROP_ENABLE_CHARGER:
++
++ /* Don't enable the charger unless overvoltage is recovered */
++
++ if (chip->bat_health != POWER_SUPPLY_HEALTH_OVERVOLTAGE) {
++ ret = bq24261_enable_charger(chip, val->intval);
++
++ if (ret)
++ dev_err(&chip->client->dev,
++ "Error(%d) in %s charger", ret,
++ (val->intval ? "enable" : "disable"));
++ else
++ chip->is_charger_enabled = val->intval;
++ } else {
++ dev_info(&chip->client->dev, "Battery Over Voltage. Charger will be disabled\n");
++ }
++ break;
++ case POWER_SUPPLY_PROP_CHARGE_CURRENT:
++ ret = bq24261_set_cc(chip, val->intval);
++ if (!ret)
++ chip->cc = val->intval;
++ break;
++ case POWER_SUPPLY_PROP_CHARGE_VOLTAGE:
++ ret = bq24261_set_cv(chip, val->intval);
++ if (!ret)
++ chip->cv = val->intval;
++ break;
++ case POWER_SUPPLY_PROP_MAX_CHARGE_CURRENT:
++ chip->max_cc = val->intval;
++ break;
++ case POWER_SUPPLY_PROP_MAX_CHARGE_VOLTAGE:
++ chip->max_cv = val->intval;
++ break;
++ case POWER_SUPPLY_PROP_CHARGE_TERM_CUR:
++ ret = bq24261_set_iterm(chip, val->intval);
++ if (!ret)
++ chip->iterm = val->intval;
++ break;
++ case POWER_SUPPLY_PROP_CABLE_TYPE:
++
++ chip->cable_type = val->intval;
++ chip->psy_usb.type = get_power_supply_type(chip->cable_type);
++ if (chip->cable_type != POWER_SUPPLY_CHARGER_TYPE_NONE) {
++ chip->chrgr_health = POWER_SUPPLY_HEALTH_GOOD;
++ chip->chrgr_stat = BQ24261_CHRGR_STAT_UNKNOWN;
++
++ /* Adding this processing in order to check
++ for any faults during connect */
++
++ ret = bq24261_read_reg(chip->client,
++ BQ24261_STAT_CTRL0_ADDR);
++ if (ret < 0)
++ dev_err(&chip->client->dev,
++ "Error (%d) in reading status register(0x00)\n",
++ ret);
++ else
++ bq24261_handle_irq(chip, ret);
++ } else {
++ chip->chrgr_stat = BQ24261_CHRGR_STAT_UNKNOWN;
++ chip->chrgr_health = POWER_SUPPLY_HEALTH_UNKNOWN;
++ cancel_delayed_work_sync(&chip->low_supply_fault_work);
++ }
++
++
++ break;
++ case POWER_SUPPLY_PROP_INLMT:
++ ret = bq24261_set_inlmt(chip, val->intval);
++ if (!ret)
++ chip->inlmt = val->intval;
++ break;
++ case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
++ chip->cntl_state = val->intval;
++ break;
++ case POWER_SUPPLY_PROP_MAX_TEMP:
++ chip->max_temp = val->intval;
++ break;
++ case POWER_SUPPLY_PROP_MIN_TEMP:
++ chip->min_temp = val->intval;
++ break;
++ default:
++ ret = -ENODATA;
++ }
++
++ mutex_unlock(&chip->lock);
++ return ret;
++}
++
++static int bq24261_usb_get_property(struct power_supply *psy,
++ enum power_supply_property psp,
++ union power_supply_propval *val)
++{
++ struct bq24261_charger *chip = container_of(psy,
++ struct bq24261_charger,
++ psy_usb);
++
++ mutex_lock(&chip->lock);
++
++ switch (psp) {
++ case POWER_SUPPLY_PROP_PRESENT:
++ val->intval = chip->present;
++ break;
++ case POWER_SUPPLY_PROP_ONLINE:
++ val->intval = chip->online;
++ break;
++ case POWER_SUPPLY_PROP_HEALTH:
++ val->intval = chip->chrgr_health;
++ break;
++ case POWER_SUPPLY_PROP_MAX_CHARGE_CURRENT:
++ val->intval = chip->max_cc;
++ break;
++ case POWER_SUPPLY_PROP_MAX_CHARGE_VOLTAGE:
++ val->intval = chip->max_cv;
++ break;
++ case POWER_SUPPLY_PROP_CHARGE_CURRENT:
++ val->intval = chip->cc;
++ break;
++ case POWER_SUPPLY_PROP_CHARGE_VOLTAGE:
++ val->intval = chip->cv;
++ break;
++ case POWER_SUPPLY_PROP_INLMT:
++ val->intval = chip->inlmt;
++ break;
++ case POWER_SUPPLY_PROP_CHARGE_TERM_CUR:
++ val->intval = chip->iterm;
++ break;
++ case POWER_SUPPLY_PROP_CABLE_TYPE:
++ val->intval = chip->cable_type;
++ break;
++ case POWER_SUPPLY_PROP_ENABLE_CHARGING:
++ if (chip->boost_mode)
++ val->intval = false;
++ else
++ val->intval = (chip->is_charging_enabled &&
++ (chip->chrgr_stat == BQ24261_CHRGR_STAT_CHARGING));
++
++ break;
++ case POWER_SUPPLY_PROP_ENABLE_CHARGER:
++ val->intval = bq24261_is_online(chip);
++ break;
++ case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
++ val->intval = chip->cntl_state;
++ break;
++ case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
++ val->intval = chip->pdata->num_throttle_states;
++ break;
++ case POWER_SUPPLY_PROP_MODEL_NAME:
++ val->strval = chip->model_name;
++ break;
++ case POWER_SUPPLY_PROP_MANUFACTURER:
++ val->strval = chip->manufacturer;
++ break;
++ case POWER_SUPPLY_PROP_MAX_TEMP:
++ val->intval = chip->max_temp;
++ break;
++ case POWER_SUPPLY_PROP_MIN_TEMP:
++ val->intval = chip->min_temp;
++ break;
++ default:
++ mutex_unlock(&chip->lock);
++ return -EINVAL;
++ }
++
++ mutex_unlock(&chip->lock);
++ return 0;
++}
++
++static inline struct power_supply *get_psy_battery(void)
++{
++ struct class_dev_iter iter;
++ struct device *dev;
++ static struct power_supply *pst;
++
++ class_dev_iter_init(&iter, power_supply_class, NULL, NULL);
++ while ((dev = class_dev_iter_next(&iter))) {
++ pst = (struct power_supply *)dev_get_drvdata(dev);
++ if (pst->type == POWER_SUPPLY_TYPE_BATTERY) {
++ class_dev_iter_exit(&iter);
++ return pst;
++ }
++ }
++ class_dev_iter_exit(&iter);
++
++ return NULL;
++}
++
++static inline int get_battery_voltage(int *volt)
++{
++ struct power_supply *psy;
++ union power_supply_propval val;
++ int ret;
++
++ psy = get_psy_battery();
++ if (!psy)
++ return -EINVAL;
++
++ ret = psy->get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &val);
++ if (!ret)
++ *volt = (val.intval);
++
++ return ret;
++}
++
++static inline int get_battery_volt_max_design(int *volt)
++{
++ struct power_supply *psy;
++ union power_supply_propval val;
++ int ret;
++
++ psy = get_psy_battery();
++ if (!psy)
++ return -EINVAL;
++
++ ret = psy->get_property(psy,
++ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, &val);
++ if (!ret)
++ (*volt = val.intval);
++ return ret;
++}
++
++static inline int get_battery_current(int *cur)
++{
++ struct power_supply *psy;
++ union power_supply_propval val;
++ int ret;
++
++ psy = get_psy_battery();
++ if (!psy)
++ return -EINVAL;
++
++ ret = psy->get_property(psy, POWER_SUPPLY_PROP_CURRENT_NOW, &val);
++ if (!ret)
++ *cur = val.intval;
++
++ return ret;
++}
++
++static void bq24261_wdt_reset_worker(struct work_struct *work)
++{
++
++ struct bq24261_charger *chip = container_of(work,
++ struct bq24261_charger, wdt_work.work);
++ int ret;
++ ret = bq24261_reset_timer(chip);
++
++ if (ret)
++ dev_err(&chip->client->dev, "Error (%d) in WDT reset\n");
++ else
++ dev_info(&chip->client->dev, "WDT reset\n");
++
++ schedule_delayed_work(&chip->wdt_work, WDT_RESET_DELAY);
++}
++
++static void bq24261_sw_charge_term_worker(struct work_struct *work)
++{
++
++ struct bq24261_charger *chip = container_of(work,
++ struct bq24261_charger,
++ sw_term_work.work);
++
++ power_supply_changed(NULL);
++
++ schedule_delayed_work(&chip->sw_term_work,
++ CHRG_TERM_WORKER_DELAY);
++
++}
++
++int bq24261_get_bat_health(void)
++{
++
++ struct bq24261_charger *chip;
++
++ if (!bq24261_client)
++ return -ENODEV;
++
++ chip = i2c_get_clientdata(bq24261_client);
++
++ return chip->bat_health;
++}
++
++
++static void bq24261_low_supply_fault_work(struct work_struct *work)
++{
++ struct bq24261_charger *chip = container_of(work,
++ struct bq24261_charger,
++ low_supply_fault_work.work);
++
++ if (chip->chrgr_stat == BQ24261_CHRGR_STAT_FAULT) {
++ dev_err(&chip->client->dev, "Low Supply Fault detected!!\n");
++ chip->chrgr_health = POWER_SUPPLY_HEALTH_DEAD;
++ power_supply_changed(&chip->psy_usb);
++ bq24261_dump_regs(true);
++ }
++ return;
++}
++
++
++/* is_bat_over_voltage: check battery is over voltage or not
++* @chip: bq24261_charger context
++*
++* This function is used to verify the over voltage condition.
++* In some scenarios, HW generates Over Voltage exceptions when
++* battery voltage is normal. This function uses the over voltage
++* condition (voltage_max_design * 1.01) to verify battery is really
++* over charged or not.
++*/
++
++static bool is_bat_over_voltage(struct bq24261_charger *chip,
++ bool verify_recovery)
++{
++
++ int bat_volt, bat_volt_max_des, ret;
++
++ ret = get_battery_voltage(&bat_volt);
++ if (ret)
++ return verify_recovery ? false : true;
++
++ ret = get_battery_volt_max_design(&bat_volt_max_des);
++
++ if (ret)
++ bat_volt_max_des = BQ24261_DEF_BAT_VOLT_MAX_DESIGN;
++
++ dev_info(&chip->client->dev, "bat_volt=%d Voltage Max Design=%d OVP_VOLT=%d OVP recover volt=%d\n",
++ bat_volt, bat_volt_max_des,
++ (bat_volt_max_des/1000 * BQ24261_OVP_MULTIPLIER),
++ (bat_volt_max_des/1000 *
++ BQ24261_OVP_RECOVER_MULTIPLIER));
++ if (verify_recovery) {
++ if ((bat_volt) <= (bat_volt_max_des / 1000 *
++ BQ24261_OVP_RECOVER_MULTIPLIER))
++ return true;
++ else
++ return false;
++ } else {
++ if ((bat_volt) >= (bat_volt_max_des / 1000 *
++ BQ24261_OVP_MULTIPLIER))
++ return true;
++ else
++ return false;
++ }
++
++ return false;
++}
++
++#define IS_BATTERY_OVER_VOLTAGE(chip) \
++ is_bat_over_voltage(chip , false)
++
++#define IS_BATTERY_OVER_VOLTAGE_RECOVERED(chip) \
++ is_bat_over_voltage(chip , true)
++
++static void handle_battery_over_voltage(struct bq24261_charger *chip)
++{
++ /* Set Health to Over Voltage. Disable charger to discharge
++ * battery to reduce the battery voltage.
++ */
++ chip->bat_health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
++ bq24261_enable_charger(chip, false);
++ chip->is_charger_enabled = false;
++ cancel_delayed_work_sync(&chip->exception_mon_work);
++ schedule_delayed_work(&chip->exception_mon_work,
++ EXCEPTION_MONITOR_DELAY);
++}
++
++static void bq24261_exception_mon_work(struct work_struct *work)
++{
++ struct bq24261_charger *chip = container_of(work,
++ struct bq24261_charger,
++ exception_mon_work.work);
++ /* Only overvoltage exception need to monitor.*/
++ if (IS_BATTERY_OVER_VOLTAGE_RECOVERED(chip)) {
++ dev_info(&chip->client->dev, "Over Voltage Exception Recovered\n");
++ chip->bat_health = POWER_SUPPLY_HEALTH_GOOD;
++ bq24261_enable_charger(chip, true);
++ chip->is_charger_enabled = true;
++ resume_charging(chip);
++ } else {
++ schedule_delayed_work(&chip->exception_mon_work,
++ EXCEPTION_MONITOR_DELAY);
++ }
++}
++
++static int bq24261_handle_irq(struct bq24261_charger *chip, u8 stat_reg)
++{
++ struct i2c_client *client = chip->client;
++ bool notify = true;
++
++ dev_info(&client->dev, "%s:%d stat=0x%x\n",
++ __func__, __LINE__, stat_reg);
++
++ switch (stat_reg & BQ24261_STAT_MASK) {
++ case BQ24261_STAT_READY:
++ chip->chrgr_stat = BQ24261_CHRGR_STAT_READY;
++ chip->chrgr_health = POWER_SUPPLY_HEALTH_GOOD;
++ chip->bat_health = POWER_SUPPLY_HEALTH_GOOD;
++ dev_info(&client->dev, "Charger Status: Ready\n");
++ notify = false;
++ break;
++ case BQ24261_STAT_CHRG_PRGRSS:
++ chip->chrgr_stat = BQ24261_CHRGR_STAT_CHARGING;
++ chip->chrgr_health = POWER_SUPPLY_HEALTH_GOOD;
++ chip->bat_health = POWER_SUPPLY_HEALTH_GOOD;
++ dev_info(&client->dev, "Charger Status: Charge Progress\n");
++ bq24261_dump_regs(false);
++ break;
++ case BQ24261_STAT_CHRG_DONE:
++ chip->chrgr_health = POWER_SUPPLY_HEALTH_GOOD;
++ chip->bat_health = POWER_SUPPLY_HEALTH_GOOD;
++ dev_info(&client->dev, "Charger Status: Charge Done\n");
++
++ bq24261_enable_hw_charge_term(chip, false);
++ resume_charging(chip);
++ schedule_delayed_work(&chip->sw_term_work, 0);
++ break;
++
++ case BQ24261_STAT_FAULT:
++ break;
++ }
++
++ if (stat_reg & BQ24261_BOOST_MASK)
++ dev_info(&client->dev, "Boost Mode\n");
++
++ if ((stat_reg & BQ24261_STAT_MASK) == BQ24261_STAT_FAULT) {
++ bool dump_master = true;
++ chip->chrgr_stat = BQ24261_CHRGR_STAT_FAULT;
++
++ switch (stat_reg & BQ24261_FAULT_MASK) {
++ case BQ24261_VOVP:
++ chip->chrgr_health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
++ dev_err(&client->dev, "Charger OVP Fault\n");
++ break;
++
++ case BQ24261_LOW_SUPPLY:
++ notify = false;
++
++ if (chip->pdata->handle_low_supply)
++ chip->pdata->handle_low_supply();
++
++ if (chip->cable_type !=
++ POWER_SUPPLY_CHARGER_TYPE_NONE) {
++ schedule_delayed_work
++ (&chip->low_supply_fault_work,
++ 5*HZ);
++ dev_dbg(&client->dev,
++ "Schedule Low Supply Fault work!!\n");
++ }
++ break;
++
++ case BQ24261_THERMAL_SHUTDOWN:
++ chip->chrgr_health = POWER_SUPPLY_HEALTH_OVERHEAT;
++ dev_err(&client->dev, "Charger Thermal Fault\n");
++ break;
++
++ case BQ24261_BATT_TEMP_FAULT:
++ chip->bat_health = POWER_SUPPLY_HEALTH_OVERHEAT;
++ dev_err(&client->dev, "Battery Temperature Fault\n");
++ break;
++
++ case BQ24261_TIMER_FAULT:
++ chip->bat_health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
++ chip->chrgr_health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
++ dev_err(&client->dev, "Charger Timer Fault\n");
++ break;
++
++ case BQ24261_BATT_OVP:
++ notify = false;
++ if (chip->bat_health !=
++ POWER_SUPPLY_HEALTH_OVERVOLTAGE) {
++ if (!IS_BATTERY_OVER_VOLTAGE(chip)) {
++ chip->chrgr_stat =
++ BQ24261_CHRGR_STAT_UNKNOWN;
++ resume_charging(chip);
++ } else {
++ dev_err(&client->dev, "Battery Over Voltage Fault\n");
++ handle_battery_over_voltage(chip);
++ notify = true;
++ }
++ }
++ break;
++ case BQ24261_NO_BATTERY:
++ dev_err(&client->dev, "No Battery Connected\n");
++ break;
++
++ }
++
++ if (chip->chrgr_stat == BQ24261_CHRGR_STAT_FAULT && notify)
++ bq24261_dump_regs(dump_master);
++ }
++
++ wake_up(&chip->wait_ready);
++
++ chip->is_vsys_on = bq24261_is_vsys_on(chip);
++ if (notify)
++ power_supply_changed(&chip->psy_usb);
++
++ return 0;
++}
++
++static void bq24261_irq_worker(struct work_struct *work)
++{
++ struct bq24261_charger *chip =
++ container_of(work, struct bq24261_charger, irq_work);
++ int ret;
++
++ /*Lock to ensure that interrupt register readings are done
++ * and processed sequentially. The interrupt Fault registers
++ * are read on clear and without sequential processing double
++ * fault interrupts or fault recovery cannot be handlled propely
++ */
++
++ mutex_lock(&chip->lock);
++
++ dev_dbg(&chip->client->dev, "%s\n", __func__);
++
++ ret = bq24261_read_reg(chip->client, BQ24261_STAT_CTRL0_ADDR);
++ if (ret < 0) {
++ dev_err(&chip->client->dev,
++ "Error (%d) in reading BQ24261_STAT_CTRL0_ADDR\n", ret);
++ }
++ else {
++ bq24261_handle_irq(chip, ret);
++ }
++ mutex_unlock(&chip->lock);
++}
++
++static irqreturn_t bq24261_thread_handler(int id, void *data)
++{
++ struct bq24261_charger *chip = (struct bq24261_charger *)data;
++
++ queue_work(system_nrt_wq, &chip->irq_work);
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t bq24261_irq_handler(int irq, void *data)
++{
++ struct bq24261_charger *chip = (struct bq24261_charger *)data;
++ u8 intr_stat;
++
++ if (chip->irq_iomap) {
++ intr_stat = ioread8(chip->irq_iomap);
++ if ((intr_stat & chip->pdata->irq_mask)) {
++ dev_dbg(&chip->client->dev, "%s\n", __func__);
++ return IRQ_WAKE_THREAD;
++ }
++ }
++
++ return IRQ_NONE;
++}
++
++static void bq24261_boostmode_worker(struct work_struct *work)
++{
++ struct bq24261_charger *chip =
++ container_of(work, struct bq24261_charger, otg_work);
++ struct bq24261_otg_event *evt, *tmp;
++ unsigned long flags;
++
++ spin_lock_irqsave(&chip->otg_queue_lock, flags);
++ list_for_each_entry_safe(evt, tmp, &chip->otg_queue, node) {
++ list_del(&evt->node);
++ spin_unlock_irqrestore(&chip->otg_queue_lock, flags);
++
++ dev_info(&chip->client->dev,
++ "%s:%d state=%d\n", __FILE__, __LINE__,
++ evt->is_enable);
++ mutex_lock(&chip->lock);
++ if (evt->is_enable)
++ bq24261_enable_boost_mode(chip, 1);
++ else
++ bq24261_enable_boost_mode(chip, 0);
++
++ mutex_unlock(&chip->lock);
++ spin_lock_irqsave(&chip->otg_queue_lock, flags);
++ kfree(evt);
++
++ }
++ spin_unlock_irqrestore(&chip->otg_queue_lock, flags);
++}
++
++static int otg_handle_notification(struct notifier_block *nb,
++ unsigned long event, void *param)
++{
++
++ struct bq24261_charger *chip =
++ container_of(nb, struct bq24261_charger, otg_nb);
++ struct bq24261_otg_event *evt;
++
++ dev_dbg(&chip->client->dev, "OTG notification: %lu\n", event);
++ if (!param || event != USB_EVENT_DRIVE_VBUS)
++ return NOTIFY_DONE;
++
++ evt = kzalloc(sizeof(*evt), GFP_ATOMIC);
++ if (!evt) {
++ dev_err(&chip->client->dev,
++ "failed to allocate memory for OTG event\n");
++ return NOTIFY_DONE;
++ }
++
++ evt->is_enable = *(int *)param;
++ INIT_LIST_HEAD(&evt->node);
++
++ spin_lock(&chip->otg_queue_lock);
++ list_add_tail(&evt->node, &chip->otg_queue);
++ spin_unlock(&chip->otg_queue_lock);
++
++ queue_work(system_nrt_wq, &chip->otg_work);
++ return NOTIFY_OK;
++}
++
++static inline int register_otg_notifications(struct bq24261_charger *chip)
++{
++
++ int retval;
++
++ INIT_LIST_HEAD(&chip->otg_queue);
++ INIT_WORK(&chip->otg_work, bq24261_boostmode_worker);
++ spin_lock_init(&chip->otg_queue_lock);
++
++ chip->otg_nb.notifier_call = otg_handle_notification;
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0))
++ chip->transceiver = usb_get_transceiver();
++#else
++ chip->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
++#endif
++ if (!chip->transceiver || IS_ERR(chip->transceiver)) {
++ dev_err(&chip->client->dev, "failed to get otg transceiver\n");
++ return -EINVAL;
++ }
++ retval = usb_register_notifier(chip->transceiver, &chip->otg_nb);
++ if (retval) {
++ dev_err(&chip->client->dev,
++ "failed to register otg notifier\n");
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static enum bq2426x_model_num bq24261_get_model(int bq24261_rev_reg)
++{
++ switch (bq24261_rev_reg & BQ24261_REV_MASK) {
++ case BQ24260_REV:
++ return BQ24260;
++ case BQ24261_REV:
++ case BQ24261_2_3_REV:
++ return BQ24261;
++ default:
++ return BQ2426X;
++ }
++}
++
++static int bq24261_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ struct i2c_adapter *adapter;
++ struct bq24261_charger *chip;
++ int ret;
++ int bq2426x_rev;
++ enum bq2426x_model_num bq24261_rev_index;
++
++ adapter = to_i2c_adapter(client->dev.parent);
++
++ if (!client->dev.platform_data) {
++ dev_err(&client->dev, "platform data is null");
++ return -EFAULT;
++ }
++
++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
++ dev_err(&client->dev,
++ "I2C adapter %s doesn'tsupport BYTE DATA transfer\n",
++ adapter->name);
++ return -EIO;
++ }
++
++ bq2426x_rev = bq24261_read_reg(client, BQ24261_VENDOR_REV_ADDR);
++ if (bq2426x_rev < 0) {
++ dev_err(&client->dev,
++ "Error (%d) in reading BQ24261_VENDOR_REV_ADDR\n", bq2426x_rev);
++ return bq2426x_rev;
++ }
++ dev_info(&client->dev, "bq2426x revision: 0x%x found!!\n", bq2426x_rev);
++
++ bq24261_rev_index = bq24261_get_model(bq2426x_rev);
++ if ((bq2426x_rev & BQ24261_VENDOR_MASK) != BQ24261_VENDOR) {
++ dev_err(&client->dev,
++ "Invalid Vendor/Revision number in BQ24261_VENDOR_REV_ADDR: %d",
++ bq2426x_rev);
++ return -ENODEV;
++ }
++
++ chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
++ if (!chip) {
++ dev_err(&client->dev, "mem alloc failed\n");
++ return -ENOMEM;
++ }
++
++ init_waitqueue_head(&chip->wait_ready);
++ i2c_set_clientdata(client, chip);
++ chip->pdata = client->dev.platform_data;
++
++ /* Remap IRQ map address to read the IRQ status */
++ if ((chip->pdata->irq_map) && (chip->pdata->irq_mask)) {
++ chip->irq_iomap = ioremap_nocache(chip->pdata->irq_map, 8);
++ if (!chip->irq_iomap) {
++ dev_err(&client->dev, "Failed: ioremap_nocache\n");
++ return -EFAULT;
++ }
++ }
++
++ chip->client = client;
++ chip->pdata = client->dev.platform_data;
++
++ chip->psy_usb.name = DEV_NAME;
++ chip->psy_usb.type = POWER_SUPPLY_TYPE_USB;
++ chip->psy_usb.properties = bq24261_usb_props;
++ chip->psy_usb.num_properties = ARRAY_SIZE(bq24261_usb_props);
++ chip->psy_usb.get_property = bq24261_usb_get_property;
++ chip->psy_usb.set_property = bq24261_usb_set_property;
++ chip->psy_usb.supplied_to = chip->pdata->supplied_to;
++ chip->psy_usb.num_supplicants = chip->pdata->num_supplicants;
++ chip->psy_usb.throttle_states = chip->pdata->throttle_states;
++ chip->psy_usb.num_throttle_states = chip->pdata->num_throttle_states;
++ chip->psy_usb.supported_cables = POWER_SUPPLY_CHARGER_TYPE_USB;
++ chip->max_cc = 1500;
++ chip->chrgr_stat = BQ24261_CHRGR_STAT_UNKNOWN;
++ chip->chrgr_health = POWER_SUPPLY_HEALTH_UNKNOWN;
++ chip->revision = bq2426x_rev;
++
++ strncpy(chip->model_name,
++ bq24261_model_name[bq24261_rev_index].model_name,
++ MODEL_NAME_SIZE);
++ strncpy(chip->manufacturer, DEV_MANUFACTURER,
++ DEV_MANUFACTURER_NAME_SIZE);
++
++ mutex_init(&chip->lock);
++ ret = power_supply_register(&client->dev, &chip->psy_usb);
++ if (ret) {
++ dev_err(&client->dev, "Failed: power supply register (%d)\n",
++ ret);
++ iounmap(chip->irq_iomap);
++ return ret;
++ }
++
++ INIT_DELAYED_WORK(&chip->sw_term_work, bq24261_sw_charge_term_worker);
++ INIT_DELAYED_WORK(&chip->low_supply_fault_work,
++ bq24261_low_supply_fault_work);
++ INIT_DELAYED_WORK(&chip->exception_mon_work,
++ bq24261_exception_mon_work);
++ if ((chip->revision & BQ24261_REV_MASK) == BQ24261_REV) {
++ INIT_DELAYED_WORK(&chip->wdt_work,
++ bq24261_wdt_reset_worker);
++ }
++
++ INIT_WORK(&chip->irq_work, bq24261_irq_worker);
++ if (chip->client->irq) {
++ ret = request_threaded_irq(chip->client->irq,
++ bq24261_irq_handler,
++ bq24261_thread_handler,
++ IRQF_SHARED|IRQF_NO_SUSPEND,
++ DEV_NAME, chip);
++ if (ret) {
++ dev_err(&client->dev, "Failed: request_irq (%d)\n",
++ ret);
++ iounmap(chip->irq_iomap);
++ power_supply_unregister(&chip->psy_usb);
++ return ret;
++ }
++ }
++
++ if (IS_BATTERY_OVER_VOLTAGE(chip))
++ handle_battery_over_voltage(chip);
++ else
++ chip->bat_health = POWER_SUPPLY_HEALTH_GOOD;
++
++ if (register_otg_notifications(chip))
++ dev_err(&client->dev, "Error in registering OTG notifications. Unable to supply power to Host\n");
++
++ bq24261_client = client;
++ power_supply_changed(&chip->psy_usb);
++ bq24261_debugfs_init();
++
++ return 0;
++}
++
++static int bq24261_remove(struct i2c_client *client)
++{
++ struct bq24261_charger *chip = i2c_get_clientdata(client);
++
++ if (client->irq)
++ free_irq(client->irq, chip);
++
++ flush_scheduled_work();
++ if (chip->irq_iomap)
++ iounmap(chip->irq_iomap);
++ if (chip->transceiver)
++ usb_unregister_notifier(chip->transceiver, &chip->otg_nb);
++
++ power_supply_unregister(&chip->psy_usb);
++ bq24261_debugfs_exit();
++ return 0;
++}
++
++static int bq24261_suspend(struct device *dev)
++{
++ struct bq24261_charger *chip = dev_get_drvdata(dev);
++
++ if ((chip->revision & BQ24261_REV_MASK) == BQ24261_REV) {
++ if (chip->boost_mode)
++ cancel_delayed_work_sync(&chip->wdt_work);
++ }
++ dev_dbg(&chip->client->dev, "bq24261 suspend\n");
++ return 0;
++}
++
++static int bq24261_resume(struct device *dev)
++{
++ struct bq24261_charger *chip = dev_get_drvdata(dev);
++
++ if ((chip->revision & BQ24261_REV_MASK) == BQ24261_REV) {
++ if (chip->boost_mode)
++ bq24261_enable_boost_mode(chip, 1);
++ }
++
++ dev_dbg(&chip->client->dev, "bq24261 resume\n");
++ return 0;
++}
++
++static int bq24261_runtime_suspend(struct device *dev)
++{
++ dev_dbg(dev, "%s called\n", __func__);
++ return 0;
++}
++
++static int bq24261_runtime_resume(struct device *dev)
++{
++ dev_dbg(dev, "%s called\n", __func__);
++ return 0;
++}
++
++static int bq24261_runtime_idle(struct device *dev)
++{
++
++ dev_dbg(dev, "%s called\n", __func__);
++ return 0;
++}
++
++static const struct dev_pm_ops bq24261_pm_ops = {
++ .suspend = bq24261_suspend,
++ .resume = bq24261_resume,
++ .runtime_suspend = bq24261_runtime_suspend,
++ .runtime_resume = bq24261_runtime_resume,
++ .runtime_idle = bq24261_runtime_idle,
++};
++
++static const struct i2c_device_id bq24261_id[] = {
++ {DEV_NAME, 0},
++ {},
++};
++
++MODULE_DEVICE_TABLE(i2c, bq24261_id);
++
++static struct i2c_driver bq24261_driver = {
++ .driver = {
++ .name = DEV_NAME,
++ .pm = &bq24261_pm_ops,
++ },
++ .probe = bq24261_probe,
++ .remove = bq24261_remove,
++ .id_table = bq24261_id,
++};
++
++static int __init bq24261_init(void)
++{
++ return i2c_add_driver(&bq24261_driver);
++}
++
++module_init(bq24261_init);
++
++static void __exit bq24261_exit(void)
++{
++ i2c_del_driver(&bq24261_driver);
++}
++
++module_exit(bq24261_exit);
++
++MODULE_AUTHOR("Jenny TC <jenny.tc@intel.com>");
++MODULE_DESCRIPTION("BQ24261 Charger Driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/power/charging_algo_pse.c b/drivers/power/charging_algo_pse.c
+new file mode 100644
+index 0000000..2088594
+--- /dev/null
++++ b/drivers/power/charging_algo_pse.c
+@@ -0,0 +1,180 @@
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/device.h>
++#include <linux/err.h>
++#include <linux/power_supply.h>
++#include <linux/thermal.h>
++#include <linux/power/battery_id.h>
++#include "power_supply.h"
++#include "power_supply_charger.h"
++
++/* 98% of CV is considered as voltage to detect Full */
++#define FULL_CV_MIN 98
++
++/* Offset to exit from maintenance charging. In maintenance charging
++* if the volatge is less than the (maintenance_lower_threshold -
++* MAINT_EXIT_OFFSET) then system can switch to normal charging
++*/
++#define MAINT_EXIT_OFFSET 50 /* mV */
++
++static int get_tempzone(struct ps_pse_mod_prof *pse_mod_bprof,
++ int temp)
++{
++
++ int i = 0;
++ int temp_range_cnt = min_t(u16, pse_mod_bprof->temp_mon_ranges,
++ BATT_TEMP_NR_RNG);
++
++ if ((temp < pse_mod_bprof->temp_low_lim) ||
++ (temp > pse_mod_bprof->temp_mon_range[0].temp_up_lim))
++ return -EINVAL;
++
++ for (i = 0; i < temp_range_cnt; ++i)
++ if (temp > pse_mod_bprof->temp_mon_range[i].temp_up_lim)
++ break;
++ return i-1;
++}
++
++static inline bool __is_battery_full
++ (long volt, long cur, long iterm, unsigned long cv)
++{
++ pr_devel("%s:current=%d pse_mod_bprof->chrg_term_mA =%d voltage_now=%d full_cond=%d",
++ __func__, cur, iterm, volt * 100, (FULL_CV_MIN * cv));
++
++ return ((cur > 0) && (cur <= iterm) &&
++ ((volt * 100) >= (FULL_CV_MIN * cv)));
++
++}
++
++static inline bool is_battery_full(struct batt_props bat_prop,
++ struct ps_pse_mod_prof *pse_mod_bprof, unsigned long cv)
++{
++
++ int i;
++ /* Software full detection. Check the battery charge current to detect
++ * battery Full. The voltage also verified to avoid false charge
++ * full detection.
++ */
++ pr_devel("%s:current=%d pse_mod_bprof->chrg_term_mA =%d bat_prop.voltage_now=%d full_cond=%d",
++ __func__, bat_prop.current_now, (pse_mod_bprof->chrg_term_mA),
++ bat_prop.voltage_now * 100, (FULL_CV_MIN * cv));
++
++ for (i = (MAX_CUR_VOLT_SAMPLES - 1); i >= 0; --i) {
++
++ if (!(__is_battery_full(bat_prop.voltage_now_cache[i],
++ bat_prop.current_now_cache[i],
++ pse_mod_bprof->chrg_term_mA, cv)))
++ return false;
++ }
++
++ return true;
++}
++
++static int pse_get_bat_thresholds(struct ps_batt_chg_prof bprof,
++ struct psy_batt_thresholds *bat_thresh)
++{
++ struct ps_pse_mod_prof *pse_mod_bprof =
++ (struct ps_pse_mod_prof *) bprof.batt_prof;
++
++ if ((bprof.chrg_prof_type != PSE_MOD_CHRG_PROF) || (!pse_mod_bprof))
++ return -EINVAL;
++
++ bat_thresh->iterm = pse_mod_bprof->chrg_term_mA;
++ bat_thresh->temp_min = pse_mod_bprof->temp_low_lim;
++ bat_thresh->temp_max = pse_mod_bprof->temp_mon_range[0].temp_up_lim;
++
++ return 0;
++}
++
++static enum psy_algo_stat pse_get_next_cc_cv(struct batt_props bat_prop,
++ struct ps_batt_chg_prof bprof, unsigned long *cc, unsigned long *cv)
++{
++ int tzone;
++ struct ps_pse_mod_prof *pse_mod_bprof =
++ (struct ps_pse_mod_prof *) bprof.batt_prof;
++ enum psy_algo_stat algo_stat = bat_prop.algo_stat;
++ int maint_exit_volt;
++
++ *cc = *cv = 0;
++
++ /* If STATUS is discharging, assume that charger is not connected.
++ * If charger is not connected, no need to take any action.
++ * If charge profile type is not PSE_MOD_CHRG_PROF or the charge profile
++ * is not present, no need to take any action.
++ */
++
++ pr_devel("%s:battery status = %d algo_status=%d\n",
++ __func__, bat_prop.status, algo_stat);
++
++ if ((bprof.chrg_prof_type != PSE_MOD_CHRG_PROF) || (!pse_mod_bprof))
++ return PSY_ALGO_STAT_NOT_CHARGE;
++
++ tzone = get_tempzone(pse_mod_bprof, bat_prop.temperature);
++
++ if (tzone < 0)
++ return PSY_ALGO_STAT_NOT_CHARGE;
++
++ /* Change the algo status to not charging, if battery is
++ * not really charging or less than maintenance exit threshold.
++ * This way algorithm can switch to normal
++ * charging if current status is full/maintenace
++ */
++ maint_exit_volt = pse_mod_bprof->
++ temp_mon_range[tzone].maint_chrg_vol_ll -
++ MAINT_EXIT_OFFSET;
++
++ if ((bat_prop.status == POWER_SUPPLY_STATUS_DISCHARGING) ||
++ (bat_prop.status == POWER_SUPPLY_STATUS_NOT_CHARGING) ||
++ bat_prop.voltage_now < maint_exit_volt) {
++
++ algo_stat = PSY_ALGO_STAT_NOT_CHARGE;
++
++ }
++
++ /* read cc and cv based on temperature and algorithm status*/
++ if (algo_stat == PSY_ALGO_STAT_FULL ||
++ algo_stat == PSY_ALGO_STAT_MAINT) {
++
++ /* if status is full and voltage is lower than maintenance lower
++ * threshold change status to maintenenance
++ */
++
++ if (algo_stat == PSY_ALGO_STAT_FULL && (bat_prop.voltage_now <=
++ pse_mod_bprof->temp_mon_range[tzone].maint_chrg_vol_ll))
++ algo_stat = PSY_ALGO_STAT_MAINT;
++
++ /* Read maintenance CC and CV */
++ if (algo_stat == PSY_ALGO_STAT_MAINT) {
++ *cv = pse_mod_bprof->temp_mon_range
++ [tzone].maint_chrg_vol_ul;
++ *cc = pse_mod_bprof->temp_mon_range
++ [tzone].maint_chrg_cur;
++ }
++ } else {
++ *cv = pse_mod_bprof->temp_mon_range[tzone].full_chrg_vol;
++ *cc = pse_mod_bprof->temp_mon_range[tzone].full_chrg_cur;
++ algo_stat = PSY_ALGO_STAT_CHARGE;
++ }
++
++ if (is_battery_full(bat_prop, pse_mod_bprof, *cv)) {
++ *cc = *cv = 0;
++ algo_stat = PSY_ALGO_STAT_FULL;
++ }
++
++ return algo_stat;
++}
++
++static int __init pse_algo_init(void)
++{
++ struct charging_algo pse_algo;
++ pse_algo.chrg_prof_type = PSE_MOD_CHRG_PROF;
++ pse_algo.name = "pse_algo";
++ pse_algo.get_next_cc_cv = pse_get_next_cc_cv;
++ pse_algo.get_batt_thresholds = pse_get_bat_thresholds;
++ power_supply_register_charging_algo(&pse_algo);
++ return 0;
++}
++
++module_init(pse_algo_init);
+diff --git a/drivers/power/pmic_ccsm.c b/drivers/power/pmic_ccsm.c
+new file mode 100644
+index 0000000..e5adebe7
+--- /dev/null
++++ b/drivers/power/pmic_ccsm.c
+@@ -0,0 +1,1914 @@
++/*
++ * pmic_ccsm.c - Intel MID PMIC Charger Driver
++ *
++ * Copyright (C) 2011 Intel Corporation
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * 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; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ * Author: Jenny TC <jenny.tc@intel.com>
++ * Author: Yegnesh Iyer <yegnesh.s.iyer@intel.com>
++ */
++
++/* Includes */
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/err.h>
++#include <linux/interrupt.h>
++#include <linux/workqueue.h>
++#include <linux/jiffies.h>
++#include <linux/seq_file.h>
++#include <linux/debugfs.h>
++#include <linux/slab.h>
++#include <linux/kfifo.h>
++#include <linux/param.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/usb/otg.h>
++#include <linux/power_supply.h>
++#include <linux/power_supply.h>
++#include <linux/rpmsg.h>
++#include <linux/version.h>
++#include <asm/intel_basincove_gpadc.h>
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
++#include <linux/iio/consumer.h>
++#else
++#include "../../../kernel/drivers/staging/iio/consumer.h"
++#endif
++#include <asm/intel_scu_pmic.h>
++#include <asm/intel_mid_rpmsg.h>
++#include <asm/intel_mid_remoteproc.h>
++#include <linux/io.h>
++#include <linux/sched.h>
++#include <linux/pm_runtime.h>
++#include <linux/sfi.h>
++#include <linux/async.h>
++#include <linux/reboot.h>
++#include <linux/notifier.h>
++#include <linux/power/battery_id.h>
++#include "pmic_ccsm.h"
++
++/* Macros */
++#define DRIVER_NAME "pmic_ccsm"
++#define PMIC_SRAM_INTR_ADDR 0xFFFFF616
++#define ADC_TO_TEMP 1
++#define TEMP_TO_ADC 0
++#define is_valid_temp(tmp)\
++ (!(tmp > chc.pdata->adc_tbl[0].temp ||\
++ tmp < chc.pdata->adc_tbl[chc.pdata->max_tbl_row_cnt - 1].temp))
++#define is_valid_adc_code(val)\
++ (!(val < chc.pdata->adc_tbl[0].adc_val ||\
++ val > chc.pdata->adc_tbl[chc.pdata->max_tbl_row_cnt - 1].adc_val))
++#define CONVERT_ADC_TO_TEMP(adc_val, temp)\
++ adc_temp_conv(adc_val, temp, ADC_TO_TEMP)
++#define CONVERT_TEMP_TO_ADC(temp, adc_val)\
++ adc_temp_conv(temp, adc_val, TEMP_TO_ADC)
++#define NEED_ZONE_SPLIT(bprof)\
++ ((bprof->temp_mon_ranges < MIN_BATT_PROF))
++
++#define USB_WAKE_LOCK_TIMEOUT (5 * HZ)
++
++/* 100mA value definition for setting the inlimit in bq24261 */
++#define USBINPUTICC100VAL 100
++
++/* Type definitions */
++static void pmic_bat_zone_changed(void);
++static void pmic_battery_overheat_handler(bool);
++
++/* Extern definitions */
++
++/* Global declarations */
++static DEFINE_MUTEX(pmic_lock);
++static struct pmic_chrgr_drv_context chc;
++static struct interrupt_info chgrirq0_info[] = {
++ {
++ CHGIRQ0_BZIRQ_MASK,
++ 0,
++ "Battery temperature zone changed",
++ NULL,
++ NULL,
++ pmic_bat_zone_changed,
++ NULL,
++ },
++ {
++ CHGIRQ0_BAT_CRIT_MASK,
++ SCHGIRQ0_SBAT_CRIT_MASK,
++ NULL,
++ "Battery Over heat exception",
++ "Battery Over heat exception Recovered",
++ NULL,
++ pmic_battery_overheat_handler
++ },
++ {
++ CHGIRQ0_BAT0_ALRT_MASK,
++ SCHGIRQ0_SBAT0_ALRT_MASK,
++ NULL,
++ "Battery0 temperature inside boundary",
++ "Battery0 temperature outside boundary",
++ NULL,
++ pmic_battery_overheat_handler
++ },
++ {
++ CHGIRQ0_BAT1_ALRT_MASK,
++ SCHGIRQ0_SBAT1_ALRT_MASK,
++ NULL,
++ "Battery1 temperature inside boundary",
++ "Battery1 temperature outside boundary",
++ NULL,
++ NULL
++ },
++};
++
++u16 pmic_inlmt[][2] = {
++ { 100, CHGRCTRL1_FUSB_INLMT_100},
++ { 150, CHGRCTRL1_FUSB_INLMT_150},
++ { 500, CHGRCTRL1_FUSB_INLMT_500},
++ { 900, CHGRCTRL1_FUSB_INLMT_900},
++ { 1500, CHGRCTRL1_FUSB_INLMT_1500},
++};
++
++static inline struct power_supply *get_psy_battery(void)
++{
++ struct class_dev_iter iter;
++ struct device *dev;
++ struct power_supply *pst;
++
++ class_dev_iter_init(&iter, power_supply_class, NULL, NULL);
++ while ((dev = class_dev_iter_next(&iter))) {
++ pst = (struct power_supply *)dev_get_drvdata(dev);
++ if (pst->type == POWER_SUPPLY_TYPE_BATTERY) {
++ class_dev_iter_exit(&iter);
++ return pst;
++ }
++ }
++ class_dev_iter_exit(&iter);
++
++ return NULL;
++}
++
++
++/* Function definitions */
++static void lookup_regval(u16 tbl[][2], size_t size, u16 in_val, u8 *out_val)
++{
++ int i;
++ for (i = 1; i < size; ++i)
++ if (in_val < tbl[i][0])
++ break;
++
++ *out_val = (u8)tbl[i-1][1];
++}
++
++static int interpolate_y(int dx1x0, int dy1y0, int dxx0, int y0)
++{
++ return y0 + DIV_ROUND_CLOSEST((dxx0 * dy1y0), dx1x0);
++}
++
++static int interpolate_x(int dy1y0, int dx1x0, int dyy0, int x0)
++{
++ return x0 + DIV_ROUND_CLOSEST((dyy0 * dx1x0), dy1y0);
++}
++
++static int adc_temp_conv(int in_val, int *out_val, int conv)
++{
++ int tbl_row_cnt, i;
++ struct temp_lookup *adc_temp_tbl;
++
++ if (!chc.pdata) {
++ dev_err(chc.dev, "ADC-lookup table not yet available\n");
++ return -ERANGE;
++ }
++
++ tbl_row_cnt = chc.pdata->max_tbl_row_cnt;
++ adc_temp_tbl = chc.pdata->adc_tbl;
++
++ if (conv == ADC_TO_TEMP) {
++ if (!is_valid_adc_code(in_val))
++ return -ERANGE;
++
++ if (in_val == adc_temp_tbl[tbl_row_cnt-1].adc_val)
++ i = tbl_row_cnt - 1;
++ else {
++ for (i = 0; i < tbl_row_cnt; ++i)
++ if (in_val < adc_temp_tbl[i].adc_val)
++ break;
++ }
++
++ *out_val =
++ interpolate_y((adc_temp_tbl[i].adc_val
++ - adc_temp_tbl[i - 1].adc_val),
++ (adc_temp_tbl[i].temp
++ - adc_temp_tbl[i - 1].temp),
++ (in_val - adc_temp_tbl[i - 1].adc_val),
++ adc_temp_tbl[i - 1].temp);
++ } else {
++ if (!is_valid_temp(in_val))
++ return -ERANGE;
++
++ if (in_val == adc_temp_tbl[tbl_row_cnt-1].temp)
++ i = tbl_row_cnt - 1;
++ else {
++ for (i = 0; i < tbl_row_cnt; ++i)
++ if (in_val > adc_temp_tbl[i].temp)
++ break;
++ }
++
++ *((short int *)out_val) =
++ interpolate_x((adc_temp_tbl[i].temp
++ - adc_temp_tbl[i - 1].temp),
++ (adc_temp_tbl[i].adc_val
++ - adc_temp_tbl[i - 1].adc_val),
++ (in_val - adc_temp_tbl[i - 1].temp),
++ adc_temp_tbl[i - 1].adc_val);
++ }
++ return 0;
++}
++
++static int pmic_read_reg(u16 addr, u8 *val)
++{
++ int ret;
++
++ ret = intel_scu_ipc_ioread8(addr, val);
++ if (ret) {
++ dev_err(chc.dev,
++ "Error in intel_scu_ipc_ioread8 0x%.4x\n", addr);
++ return -EIO;
++ }
++ return 0;
++}
++
++
++static int __pmic_write_tt(u8 addr, u8 data)
++{
++ int ret;
++
++ ret = intel_scu_ipc_iowrite8(CHRTTADDR_ADDR, addr);
++ if (unlikely(ret))
++ return ret;
++
++ return intel_scu_ipc_iowrite8(CHRTTDATA_ADDR, data);
++}
++
++static inline int pmic_write_tt(u8 addr, u8 data)
++{
++ int ret;
++
++ mutex_lock(&pmic_lock);
++ ret = __pmic_write_tt(addr, data);
++ mutex_unlock(&pmic_lock);
++
++ /* If access is blocked return success to avoid additional
++ * error handling at client side
++ */
++ if (ret == -EACCES) {
++ dev_warn(chc.dev, "IPC write blocked due to unsigned kernel/invalid battery\n");
++ ret = 0;
++ }
++ return ret;
++}
++
++static int __pmic_read_tt(u8 addr, u8 *data)
++{
++ int ret;
++
++ ret = intel_scu_ipc_iowrite8(CHRTTADDR_ADDR, addr);
++ if (ret)
++ return ret;
++
++ usleep_range(2000, 3000);
++
++ return intel_scu_ipc_ioread8(CHRTTDATA_ADDR, data);
++}
++
++static inline int pmic_read_tt(u8 addr, u8 *data)
++{
++ int ret;
++
++ mutex_lock(&pmic_lock);
++ ret = __pmic_read_tt(addr, data);
++ mutex_unlock(&pmic_lock);
++
++ return ret;
++}
++
++static int pmic_update_tt(u8 addr, u8 mask, u8 data)
++{
++ u8 tdata;
++ int ret;
++
++ mutex_lock(&pmic_lock);
++ ret = __pmic_read_tt(addr, &tdata);
++ if (unlikely(ret))
++ goto exit;
++
++ tdata = (tdata & ~mask) | (data & mask);
++ ret = __pmic_write_tt(addr, tdata);
++exit:
++ mutex_unlock(&pmic_lock);
++ return ret;
++}
++
++#ifdef CONFIG_DEBUG_FS
++static int pmic_chrgr_reg_show(struct seq_file *seq, void *unused)
++{
++ int ret;
++ u16 addr;
++ u16 val1;
++ u8 val;
++
++ addr = *((u8 *)seq->private);
++
++ if (addr == CHRGRIRQ1_ADDR) {
++ val1 = ioread16(chc.pmic_intr_iomap);
++ val = (u8)(val1 >> 8);
++ } else if (addr == CHGRIRQ0_ADDR) {
++ val1 = ioread16(chc.pmic_intr_iomap);
++ val = (u8)val1;
++ } else {
++ ret = pmic_read_reg(addr, &val);
++ if (ret != 0) {
++ dev_err(chc.dev,
++ "Error reading tt register 0x%2x\n",
++ addr);
++ return -EIO;
++ }
++ }
++
++ seq_printf(seq, "0x%x\n", val);
++ return 0;
++}
++
++static int pmic_chrgr_tt_reg_show(struct seq_file *seq, void *unused)
++{
++ int ret;
++ u8 addr;
++ u8 val;
++
++ addr = *((u8 *)seq->private);
++
++ ret = pmic_read_tt(addr, &val);
++ if (ret != 0) {
++ dev_err(chc.dev,
++ "Error reading tt register 0x%2x\n",
++ addr);
++ return -EIO;
++ }
++
++ seq_printf(seq, "0x%x\n", val);
++ return 0;
++}
++
++static int pmic_chrgr_tt_reg_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, pmic_chrgr_tt_reg_show, inode->i_private);
++}
++
++static int pmic_chrgr_reg_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, pmic_chrgr_reg_show, inode->i_private);
++}
++
++static struct dentry *charger_debug_dir;
++static struct pmic_regs_def pmic_regs_bc[] = {
++ PMIC_REG_DEF(PMIC_ID_ADDR),
++ PMIC_REG_DEF(IRQLVL1_ADDR),
++ PMIC_REG_DEF(IRQLVL1_MASK_ADDR),
++ PMIC_REG_DEF(CHGRIRQ0_ADDR),
++ PMIC_REG_DEF(SCHGRIRQ0_ADDR),
++ PMIC_REG_DEF(MCHGRIRQ0_ADDR),
++ PMIC_REG_DEF(LOWBATTDET0_ADDR),
++ PMIC_REG_DEF(LOWBATTDET1_ADDR),
++ PMIC_REG_DEF(BATTDETCTRL_ADDR),
++ PMIC_REG_DEF(VBUSDETCTRL_ADDR),
++ PMIC_REG_DEF(VDCINDETCTRL_ADDR),
++ PMIC_REG_DEF(CHRGRIRQ1_ADDR),
++ PMIC_REG_DEF(SCHGRIRQ1_ADDR),
++ PMIC_REG_DEF(MCHGRIRQ1_ADDR),
++ PMIC_REG_DEF(CHGRCTRL0_ADDR),
++ PMIC_REG_DEF(CHGRCTRL1_ADDR),
++ PMIC_REG_DEF(CHGRSTATUS_ADDR),
++ PMIC_REG_DEF(USBIDCTRL_ADDR),
++ PMIC_REG_DEF(USBIDSTAT_ADDR),
++ PMIC_REG_DEF(WAKESRC_ADDR),
++ PMIC_REG_DEF(THRMBATZONE_ADDR_BC),
++ PMIC_REG_DEF(THRMZN0L_ADDR_BC),
++ PMIC_REG_DEF(THRMZN0H_ADDR_BC),
++ PMIC_REG_DEF(THRMZN1L_ADDR_BC),
++ PMIC_REG_DEF(THRMZN1H_ADDR_BC),
++ PMIC_REG_DEF(THRMZN2L_ADDR_BC),
++ PMIC_REG_DEF(THRMZN2H_ADDR_BC),
++ PMIC_REG_DEF(THRMZN3L_ADDR_BC),
++ PMIC_REG_DEF(THRMZN3H_ADDR_BC),
++ PMIC_REG_DEF(THRMZN4L_ADDR_BC),
++ PMIC_REG_DEF(THRMZN4H_ADDR_BC),
++};
++
++static struct pmic_regs_def pmic_regs_sc[] = {
++ PMIC_REG_DEF(PMIC_ID_ADDR),
++ PMIC_REG_DEF(IRQLVL1_ADDR),
++ PMIC_REG_DEF(IRQLVL1_MASK_ADDR),
++ PMIC_REG_DEF(CHGRIRQ0_ADDR),
++ PMIC_REG_DEF(SCHGRIRQ0_ADDR),
++ PMIC_REG_DEF(MCHGRIRQ0_ADDR),
++ PMIC_REG_DEF(LOWBATTDET0_ADDR),
++ PMIC_REG_DEF(LOWBATTDET1_ADDR),
++ PMIC_REG_DEF(BATTDETCTRL_ADDR),
++ PMIC_REG_DEF(VBUSDETCTRL_ADDR),
++ PMIC_REG_DEF(VDCINDETCTRL_ADDR),
++ PMIC_REG_DEF(CHRGRIRQ1_ADDR),
++ PMIC_REG_DEF(SCHGRIRQ1_ADDR),
++ PMIC_REG_DEF(MCHGRIRQ1_ADDR),
++ PMIC_REG_DEF(CHGRCTRL0_ADDR),
++ PMIC_REG_DEF(CHGRCTRL1_ADDR),
++ PMIC_REG_DEF(CHGRSTATUS_ADDR),
++ PMIC_REG_DEF(USBIDCTRL_ADDR),
++ PMIC_REG_DEF(USBIDSTAT_ADDR),
++ PMIC_REG_DEF(WAKESRC_ADDR),
++ PMIC_REG_DEF(USBPATH_ADDR),
++ PMIC_REG_DEF(USBSRCDETSTATUS_ADDR),
++ PMIC_REG_DEF(THRMBATZONE_ADDR_SC),
++ PMIC_REG_DEF(THRMZN0L_ADDR_SC),
++ PMIC_REG_DEF(THRMZN0H_ADDR_SC),
++ PMIC_REG_DEF(THRMZN1L_ADDR_SC),
++ PMIC_REG_DEF(THRMZN1H_ADDR_SC),
++ PMIC_REG_DEF(THRMZN2L_ADDR_SC),
++ PMIC_REG_DEF(THRMZN2H_ADDR_SC),
++ PMIC_REG_DEF(THRMZN3L_ADDR_SC),
++ PMIC_REG_DEF(THRMZN3H_ADDR_SC),
++ PMIC_REG_DEF(THRMZN4L_ADDR_SC),
++ PMIC_REG_DEF(THRMZN4H_ADDR_SC),
++};
++
++static struct pmic_regs_def pmic_tt_regs[] = {
++ PMIC_REG_DEF(TT_I2CDADDR_ADDR),
++ PMIC_REG_DEF(TT_CHGRINIT0OS_ADDR),
++ PMIC_REG_DEF(TT_CHGRINIT1OS_ADDR),
++ PMIC_REG_DEF(TT_CHGRINIT2OS_ADDR),
++ PMIC_REG_DEF(TT_CHGRINIT3OS_ADDR),
++ PMIC_REG_DEF(TT_CHGRINIT4OS_ADDR),
++ PMIC_REG_DEF(TT_CHGRINIT5OS_ADDR),
++ PMIC_REG_DEF(TT_CHGRINIT6OS_ADDR),
++ PMIC_REG_DEF(TT_CHGRINIT7OS_ADDR),
++ PMIC_REG_DEF(TT_USBINPUTICCOS_ADDR),
++ PMIC_REG_DEF(TT_USBINPUTICCMASK_ADDR),
++ PMIC_REG_DEF(TT_CHRCVOS_ADDR),
++ PMIC_REG_DEF(TT_CHRCVMASK_ADDR),
++ PMIC_REG_DEF(TT_CHRCCOS_ADDR),
++ PMIC_REG_DEF(TT_CHRCCMASK_ADDR),
++ PMIC_REG_DEF(TT_LOWCHROS_ADDR),
++ PMIC_REG_DEF(TT_LOWCHRMASK_ADDR),
++ PMIC_REG_DEF(TT_WDOGRSTOS_ADDR),
++ PMIC_REG_DEF(TT_WDOGRSTMASK_ADDR),
++ PMIC_REG_DEF(TT_CHGRENOS_ADDR),
++ PMIC_REG_DEF(TT_CHGRENMASK_ADDR),
++ PMIC_REG_DEF(TT_CUSTOMFIELDEN_ADDR),
++ PMIC_REG_DEF(TT_CHGRINIT0VAL_ADDR),
++ PMIC_REG_DEF(TT_CHGRINIT1VAL_ADDR),
++ PMIC_REG_DEF(TT_CHGRINIT2VAL_ADDR),
++ PMIC_REG_DEF(TT_CHGRINIT3VAL_ADDR),
++ PMIC_REG_DEF(TT_CHGRINIT4VAL_ADDR),
++ PMIC_REG_DEF(TT_CHGRINIT5VAL_ADDR),
++ PMIC_REG_DEF(TT_CHGRINIT6VAL_ADDR),
++ PMIC_REG_DEF(TT_CHGRINIT7VAL_ADDR),
++ PMIC_REG_DEF(TT_USBINPUTICC100VAL_ADDR),
++ PMIC_REG_DEF(TT_USBINPUTICC150VAL_ADDR),
++ PMIC_REG_DEF(TT_USBINPUTICC500VAL_ADDR),
++ PMIC_REG_DEF(TT_USBINPUTICC900VAL_ADDR),
++ PMIC_REG_DEF(TT_USBINPUTICC1500VAL_ADDR),
++ PMIC_REG_DEF(TT_CHRCVEMRGLOWVAL_ADDR),
++ PMIC_REG_DEF(TT_CHRCVCOLDVAL_ADDR),
++ PMIC_REG_DEF(TT_CHRCVCOOLVAL_ADDR),
++ PMIC_REG_DEF(TT_CHRCVWARMVAL_ADDR),
++ PMIC_REG_DEF(TT_CHRCVHOTVAL_ADDR),
++ PMIC_REG_DEF(TT_CHRCVEMRGHIVAL_ADDR),
++ PMIC_REG_DEF(TT_CHRCCEMRGLOWVAL_ADDR),
++ PMIC_REG_DEF(TT_CHRCCCOLDVAL_ADDR),
++ PMIC_REG_DEF(TT_CHRCCCOOLVAL_ADDR),
++ PMIC_REG_DEF(TT_CHRCCWARMVAL_ADDR),
++ PMIC_REG_DEF(TT_CHRCCHOTVAL_ADDR),
++ PMIC_REG_DEF(TT_CHRCCEMRGHIVAL_ADDR),
++ PMIC_REG_DEF(TT_LOWCHRENVAL_ADDR),
++ PMIC_REG_DEF(TT_LOWCHRDISVAL_ADDR),
++};
++
++void dump_pmic_regs(void)
++{
++ int vendor_id = chc.pmic_id & PMIC_VENDOR_ID_MASK;
++ u32 pmic_reg_cnt = 0;
++ u32 reg_index;
++ u8 data;
++ int retval;
++ struct pmic_regs_def *pmic_regs = NULL;
++
++ if (vendor_id == BASINCOVE_VENDORID) {
++ pmic_reg_cnt = ARRAY_SIZE(pmic_regs_bc);
++ pmic_regs = pmic_regs_bc;
++ } else if (vendor_id == SHADYCOVE_VENDORID) {
++ pmic_reg_cnt = ARRAY_SIZE(pmic_regs_sc);
++ pmic_regs = pmic_regs_sc;
++ }
++
++ dev_info(chc.dev, "PMIC Register dump\n");
++ dev_info(chc.dev, "====================\n");
++
++ for (reg_index = 0; reg_index < pmic_reg_cnt; reg_index++) {
++
++ retval = intel_scu_ipc_ioread8(pmic_regs[reg_index].addr,
++ &data);
++ if (retval)
++ dev_err(chc.dev, "Error in reading %x\n",
++ pmic_regs[reg_index].addr);
++ else
++ dev_info(chc.dev, "0x%x=0x%x\n",
++ pmic_regs[reg_index].addr, data);
++ }
++ dev_info(chc.dev, "====================\n");
++}
++
++void dump_pmic_tt_regs(void)
++{
++ u32 pmic_tt_reg_cnt = ARRAY_SIZE(pmic_tt_regs);
++ u32 reg_index;
++ u8 data;
++ int retval;
++
++ dev_info(chc.dev, "PMIC CHRGR TT dump\n");
++ dev_info(chc.dev, "====================\n");
++
++ for (reg_index = 0; reg_index < pmic_tt_reg_cnt; reg_index++) {
++
++ retval = pmic_read_tt(pmic_tt_regs[reg_index].addr, &data);
++ if (retval)
++ dev_err(chc.dev, "Error in reading %x\n",
++ pmic_tt_regs[reg_index].addr);
++ else
++ dev_info(chc.dev, "0x%x=0x%x\n",
++ pmic_tt_regs[reg_index].addr, data);
++ }
++
++ dev_info(chc.dev, "====================\n");
++}
++static const struct file_operations pmic_chrgr_reg_fops = {
++ .open = pmic_chrgr_reg_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release
++};
++
++static const struct file_operations pmic_chrgr_tt_reg_fops = {
++ .open = pmic_chrgr_tt_reg_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release
++};
++
++static void pmic_debugfs_init(void)
++{
++ struct dentry *fentry;
++ struct dentry *pmic_regs_dir;
++ struct dentry *pmic_tt_regs_dir;
++
++ u32 reg_index;
++ int vendor_id = chc.pmic_id & PMIC_VENDOR_ID_MASK;
++ u32 pmic_reg_cnt = 0;
++ u32 pmic_tt_reg_cnt = ARRAY_SIZE(pmic_tt_regs);
++ char name[PMIC_REG_NAME_LEN] = {0};
++ struct pmic_regs_def *pmic_regs = NULL;
++
++ if (vendor_id == BASINCOVE_VENDORID) {
++ pmic_reg_cnt = ARRAY_SIZE(pmic_regs_bc);
++ pmic_regs = pmic_regs_bc;
++ } else if (vendor_id == SHADYCOVE_VENDORID) {
++ pmic_reg_cnt = ARRAY_SIZE(pmic_regs_sc);
++ pmic_regs = pmic_regs_sc;
++ }
++
++ /* Creating a directory under debug fs for charger */
++ charger_debug_dir = debugfs_create_dir(DRIVER_NAME , NULL) ;
++ if (charger_debug_dir == NULL)
++ goto debugfs_root_exit;
++
++ /* Create a directory for pmic charger registers */
++ pmic_regs_dir = debugfs_create_dir("pmic_ccsm_regs",
++ charger_debug_dir);
++
++ if (pmic_regs_dir == NULL)
++ goto debugfs_err_exit;
++
++ for (reg_index = 0; reg_index < pmic_reg_cnt; reg_index++) {
++
++ sprintf(name, "%s",
++ pmic_regs[reg_index].reg_name);
++
++ fentry = debugfs_create_file(name,
++ S_IRUGO,
++ pmic_regs_dir,
++ &pmic_regs[reg_index].addr,
++ &pmic_chrgr_reg_fops);
++
++ if (fentry == NULL)
++ goto debugfs_err_exit;
++ }
++
++ /* Create a directory for pmic tt charger registers */
++ pmic_tt_regs_dir = debugfs_create_dir("pmic_ccsm_tt_regs",
++ charger_debug_dir);
++
++ if (pmic_tt_regs_dir == NULL)
++ goto debugfs_err_exit;
++
++ for (reg_index = 0; reg_index < pmic_tt_reg_cnt; reg_index++) {
++
++ sprintf(name, "%s", pmic_tt_regs[reg_index].reg_name);
++
++ fentry = debugfs_create_file(name,
++ S_IRUGO,
++ pmic_tt_regs_dir,
++ &pmic_tt_regs[reg_index].addr,
++ &pmic_chrgr_tt_reg_fops);
++
++ if (fentry == NULL)
++ goto debugfs_err_exit;
++ }
++
++ dev_dbg(chc.dev, "Debugfs created successfully!!");
++ return;
++
++debugfs_err_exit:
++ debugfs_remove_recursive(charger_debug_dir);
++debugfs_root_exit:
++ dev_err(chc.dev, "Error creating debugfs entry!!");
++ return;
++}
++
++static void pmic_debugfs_exit(void)
++{
++ if (charger_debug_dir != NULL)
++ debugfs_remove_recursive(charger_debug_dir);
++}
++#endif
++
++static void pmic_bat_zone_changed(void)
++{
++ int retval;
++ int cur_zone;
++ u16 addr = 0;
++ u8 data = 0;
++ struct power_supply *psy_bat;
++ int vendor_id;
++
++ vendor_id = chc.pmic_id & PMIC_VENDOR_ID_MASK;
++ if (vendor_id == BASINCOVE_VENDORID)
++ addr = THRMBATZONE_ADDR_BC;
++ else if (vendor_id == SHADYCOVE_VENDORID)
++ addr = THRMBATZONE_ADDR_SC;
++
++ retval = intel_scu_ipc_ioread8(addr, &data);
++ if (retval) {
++ dev_err(chc.dev, "Error in reading battery zone\n");
++ return;
++ }
++
++ cur_zone = data & THRMBATZONE_MASK;
++ dev_info(chc.dev, "Battery Zone changed. Current zone is %d\n",
++ (data & THRMBATZONE_MASK));
++
++ /* if current zone is the top and bottom zones then report OVERHEAT
++ */
++ if ((cur_zone == PMIC_BZONE_LOW) || (cur_zone == PMIC_BZONE_HIGH))
++ chc.health = POWER_SUPPLY_HEALTH_OVERHEAT;
++ else
++ chc.health = POWER_SUPPLY_HEALTH_GOOD;
++
++ psy_bat = get_psy_battery();
++
++ if (psy_bat && psy_bat->external_power_changed)
++ psy_bat->external_power_changed(psy_bat);
++
++ return;
++}
++
++static void pmic_battery_overheat_handler(bool stat)
++{
++ if (stat)
++ chc.health = POWER_SUPPLY_HEALTH_OVERHEAT;
++ else
++ chc.health = POWER_SUPPLY_HEALTH_GOOD;
++ return;
++}
++
++int pmic_get_health(void)
++{
++ return chc.health;
++}
++
++int pmic_enable_vbus(bool enable)
++{
++ int ret;
++ int vendor_id;
++
++ vendor_id = chc.pmic_id & PMIC_VENDOR_ID_MASK;
++
++ if (enable) {
++ ret = intel_scu_ipc_update_register(CHGRCTRL0_ADDR,
++ WDT_NOKICK_ENABLE, CHGRCTRL0_WDT_NOKICK_MASK);
++ if (ret)
++ return ret;
++
++ if (vendor_id == SHADYCOVE_VENDORID)
++ ret = intel_scu_ipc_update_register(CHGRCTRL1_ADDR,
++ CHGRCTRL1_OTGMODE_MASK,
++ CHGRCTRL1_OTGMODE_MASK);
++ } else {
++ ret = intel_scu_ipc_update_register(CHGRCTRL0_ADDR,
++ WDT_NOKICK_DISABLE, CHGRCTRL0_WDT_NOKICK_MASK);
++ if (ret)
++ return ret;
++
++ if (vendor_id == SHADYCOVE_VENDORID)
++ ret = intel_scu_ipc_update_register(CHGRCTRL1_ADDR,
++ 0x0, CHGRCTRL1_OTGMODE_MASK);
++ }
++
++ /* If access is blocked return success to avoid additional
++ * error handling at client side
++ */
++ if (ret == -EACCES) {
++ dev_warn(chc.dev, "IPC blocked due to unsigned kernel/invalid battery\n");
++ ret = 0;
++ }
++
++ return ret;
++}
++
++int pmic_enable_charging(bool enable)
++{
++ int ret;
++ u8 val;
++
++ if (enable) {
++ ret = intel_scu_ipc_update_register(CHGRCTRL1_ADDR,
++ CHGRCTRL1_FTEMP_EVENT_MASK, CHGRCTRL1_FTEMP_EVENT_MASK);
++ if (ret)
++ return ret;
++ }
++
++ val = (enable) ? 0 : EXTCHRDIS_ENABLE;
++
++ ret = intel_scu_ipc_update_register(CHGRCTRL0_ADDR,
++ val, CHGRCTRL0_EXTCHRDIS_MASK);
++ /* If access is blocked return success to avoid additional
++ * error handling at client side
++ */
++ if (ret == -EACCES) {
++ dev_warn(chc.dev, "IPC blocked due to unsigned kernel/invalid battery\n");
++ ret = 0;
++ }
++
++ return ret;
++}
++
++static inline int update_zone_cc(int zone, u8 reg_val)
++{
++ u8 addr_cc = TT_CHRCCHOTVAL_ADDR - zone;
++ dev_dbg(chc.dev, "%s:%X=%X\n", __func__, addr_cc, reg_val);
++ return pmic_write_tt(addr_cc, reg_val);
++}
++
++static inline int update_zone_cv(int zone, u8 reg_val)
++{
++ u8 addr_cv = TT_CHRCVHOTVAL_ADDR - zone;
++ dev_dbg(chc.dev, "%s:%X=%X\n", __func__, addr_cv, reg_val);
++ return pmic_write_tt(addr_cv, reg_val);
++}
++
++static inline int update_zone_temp(int zone, u16 adc_val)
++{
++ int ret;
++ u16 addr_tzone;
++ int vendor_id = chc.pmic_id & PMIC_VENDOR_ID_MASK;
++
++ if (vendor_id == BASINCOVE_VENDORID)
++ addr_tzone = THRMZN4H_ADDR_BC - (2 * zone);
++ else if (vendor_id == SHADYCOVE_VENDORID) {
++ /* to take care of address-discontinuity of zone-registers */
++ int offset_zone = zone;
++ if (zone >= 3)
++ offset_zone += 1;
++
++ addr_tzone = THRMZN4H_ADDR_SC - (2 * offset_zone);
++ } else {
++ dev_err(chc.dev, "%s: invalid vendor id %X\n", __func__, vendor_id);
++ return -EINVAL;
++ }
++
++ ret = intel_scu_ipc_iowrite8(addr_tzone, (u8)(adc_val >> 8));
++ if (unlikely(ret))
++ return ret;
++ dev_dbg(chc.dev, "%s:%X:%X=%X\n", __func__, addr_tzone,
++ (addr_tzone+1), adc_val);
++
++ return intel_scu_ipc_iowrite8(addr_tzone+1, (u8)(adc_val & 0xFF));
++}
++
++int pmic_set_cc(int new_cc)
++{
++ struct ps_pse_mod_prof *bcprof = chc.actual_bcprof;
++ struct ps_pse_mod_prof *r_bcprof = chc.runtime_bcprof;
++ int temp_mon_ranges;
++ int new_cc1;
++ int ret;
++ int i;
++ u8 reg_val = 0;
++
++ /* No need to write PMIC if CC = 0 */
++ if (!new_cc)
++ return 0;
++
++ temp_mon_ranges = min_t(u16, bcprof->temp_mon_ranges,
++ BATT_TEMP_NR_RNG);
++
++ for (i = 0; i < temp_mon_ranges; ++i) {
++ new_cc1 = min_t(int, new_cc,
++ bcprof->temp_mon_range[i].full_chrg_cur);
++
++ if (new_cc1 != r_bcprof->temp_mon_range[i].full_chrg_cur) {
++ if (chc.pdata->cc_to_reg) {
++ chc.pdata->cc_to_reg(new_cc1, &reg_val);
++ ret = update_zone_cc(i, reg_val);
++ if (unlikely(ret))
++ return ret;
++ }
++ r_bcprof->temp_mon_range[i].full_chrg_cur = new_cc1;
++ }
++ }
++
++ /* send the new CC and CV */
++ intel_scu_ipc_update_register(CHGRCTRL1_ADDR,
++ CHGRCTRL1_FTEMP_EVENT_MASK, CHGRCTRL1_FTEMP_EVENT_MASK);
++
++ return 0;
++}
++
++int pmic_set_cv(int new_cv)
++{
++ struct ps_pse_mod_prof *bcprof = chc.actual_bcprof;
++ struct ps_pse_mod_prof *r_bcprof = chc.runtime_bcprof;
++ int temp_mon_ranges;
++ int new_cv1;
++ int ret;
++ int i;
++ u8 reg_val = 0;
++
++ /* No need to write PMIC if CV = 0 */
++ if (!new_cv)
++ return 0;
++
++ temp_mon_ranges = min_t(u16, bcprof->temp_mon_ranges,
++ BATT_TEMP_NR_RNG);
++
++ for (i = 0; i < temp_mon_ranges; ++i) {
++ new_cv1 = min_t(int, new_cv,
++ bcprof->temp_mon_range[i].full_chrg_vol);
++
++ if (new_cv1 != r_bcprof->temp_mon_range[i].full_chrg_vol) {
++ if (chc.pdata->cv_to_reg) {
++ chc.pdata->cv_to_reg(new_cv1, &reg_val);
++ ret = update_zone_cv(i, reg_val);
++ if (unlikely(ret))
++ return ret;
++ }
++ r_bcprof->temp_mon_range[i].full_chrg_vol = new_cv1;
++ }
++ }
++
++ /* send the new CC and CV */
++ intel_scu_ipc_update_register(CHGRCTRL1_ADDR,
++ CHGRCTRL1_FTEMP_EVENT_MASK, CHGRCTRL1_FTEMP_EVENT_MASK);
++
++ return 0;
++}
++
++int pmic_set_ilimma(int ilim_ma)
++{
++ u8 reg_val;
++ int ret;
++
++ lookup_regval(pmic_inlmt, ARRAY_SIZE(pmic_inlmt),
++ ilim_ma, &reg_val);
++ dev_dbg(chc.dev, "Setting inlmt %d in register %x=%x\n", ilim_ma,
++ CHGRCTRL1_ADDR, reg_val);
++ ret = intel_scu_ipc_iowrite8(CHGRCTRL1_ADDR, reg_val);
++
++ /* If access is blocked return success to avoid additional
++ * error handling at client side
++ */
++ if (ret == -EACCES) {
++ dev_warn(chc.dev, "IPC blocked due to unsigned kernel/invalid battery\n");
++ ret = 0;
++ }
++
++ return ret;
++}
++
++/**
++ * pmic_read_adc_val - read ADC value of specified sensors
++ * @channel: channel of the sensor to be sampled
++ * @sensor_val: pointer to the charger property to hold sampled value
++ * @chc : battery info pointer
++ *
++ * Returns 0 if success
++ */
++static int pmic_read_adc_val(int channel, int *sensor_val,
++ struct pmic_chrgr_drv_context *chc)
++{
++ int val;
++ int ret;
++ struct iio_channel *indio_chan;
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0))
++ indio_chan = iio_st_channel_get("BATTEMP", "BATTEMP0");
++#else
++ indio_chan = iio_channel_get(NULL, "BATTEMP0");
++#endif
++ if (IS_ERR_OR_NULL(indio_chan)) {
++ ret = PTR_ERR(indio_chan);
++ goto exit;
++ }
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0))
++ ret = iio_st_read_channel_raw(indio_chan, &val);
++#else
++ ret = iio_read_channel_raw(indio_chan, &val);
++#endif
++ if (ret) {
++ dev_err(chc->dev, "IIO channel read error\n");
++ goto err_exit;
++ }
++
++ switch (channel) {
++ case GPADC_BATTEMP0:
++ ret = CONVERT_ADC_TO_TEMP(val, sensor_val);
++ break;
++ default:
++ dev_err(chc->dev, "invalid sensor%d", channel);
++ ret = -EINVAL;
++ }
++ dev_dbg(chc->dev, "pmic_ccsm pmic_ccsm.0: %s adc val=%x, %d temp=%d\n",
++ __func__, val, val, *sensor_val);
++
++err_exit:
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0))
++ iio_st_channel_release(indio_chan);
++#else
++ iio_channel_release(indio_chan);
++#endif
++exit:
++ return ret;
++}
++
++int pmic_get_battery_pack_temp(int *temp)
++{
++ if (chc.invalid_batt)
++ return -ENODEV;
++ return pmic_read_adc_val(GPADC_BATTEMP0, temp, &chc);
++}
++
++static int get_charger_type()
++{
++ int ret, i = 0;
++ u8 val;
++ int chgr_type;
++
++ do {
++ ret = pmic_read_reg(USBSRCDETSTATUS_ADDR, &val);
++ if (ret != 0) {
++ dev_err(chc.dev,
++ "Error reading USBSRCDETSTAT-register 0x%2x\n",
++ USBSRCDETSTATUS_ADDR);
++ return 0;
++ }
++
++ i++;
++ dev_info(chc.dev, "Read USBSRCDETSTATUS val: %x\n", val);
++
++ if (val & USBSRCDET_SUSBHWDET_DETSUCC)
++ break;
++ else
++ msleep(USBSRCDET_SLEEP_TIME);
++ } while (i < USBSRCDET_RETRY_CNT);
++
++ if (!(val & USBSRCDET_SUSBHWDET_DETSUCC)) {
++ dev_err(chc.dev, "Charger detection unsuccessful after %dms\n",
++ i * USBSRCDET_SLEEP_TIME);
++ return 0;
++ }
++
++ chgr_type = (val & USBSRCDET_USBSRCRSLT_MASK) >> 2;
++ dev_info(chc.dev, "Charger type after detection complete: %d\n",
++ (val & USBSRCDET_USBSRCRSLT_MASK) >> 2);
++
++ switch (chgr_type) {
++ case PMIC_CHARGER_TYPE_SDP:
++ return POWER_SUPPLY_CHARGER_TYPE_USB_SDP;
++ case PMIC_CHARGER_TYPE_DCP:
++ return POWER_SUPPLY_CHARGER_TYPE_USB_DCP;
++ case PMIC_CHARGER_TYPE_CDP:
++ return POWER_SUPPLY_CHARGER_TYPE_USB_CDP;
++ case PMIC_CHARGER_TYPE_ACA:
++ return POWER_SUPPLY_CHARGER_TYPE_USB_ACA;
++ case PMIC_CHARGER_TYPE_SE1:
++ return POWER_SUPPLY_CHARGER_TYPE_SE1;
++ case PMIC_CHARGER_TYPE_MHL:
++ return POWER_SUPPLY_CHARGER_TYPE_MHL;
++ default:
++ return POWER_SUPPLY_CHARGER_TYPE_NONE;
++ }
++}
++
++static void handle_internal_usbphy_notifications(int mask)
++{
++ struct power_supply_cable_props cap;
++
++ if (mask) {
++ cap.chrg_evt = POWER_SUPPLY_CHARGER_EVENT_CONNECT;
++ cap.chrg_type = get_charger_type();
++ chc.charger_type = cap.chrg_type;
++ } else {
++ cap.chrg_evt = POWER_SUPPLY_CHARGER_EVENT_DISCONNECT;
++ cap.chrg_type = chc.charger_type;
++ }
++
++ if (cap.chrg_type == POWER_SUPPLY_CHARGER_TYPE_USB_SDP)
++ cap.ma = 0;
++ else if ((cap.chrg_type == POWER_SUPPLY_CHARGER_TYPE_USB_DCP)
++ || (cap.chrg_type == POWER_SUPPLY_TYPE_USB_CDP)
++ || (cap.chrg_type == POWER_SUPPLY_CHARGER_TYPE_SE1))
++ cap.ma = 1500;
++
++ dev_info(chc.dev, "Notifying OTG ev:%d, evt:%d, chrg_type:%d, mA:%d\n",
++ USB_EVENT_CHARGER, cap.chrg_evt, cap.chrg_type,
++ cap.ma);
++ atomic_notifier_call_chain(&chc.otg->notifier,
++ USB_EVENT_CHARGER, &cap);
++}
++
++/* ShadyCove-WA for VBUS removal detect issue */
++int pmic_handle_low_supply(void)
++{
++ int ret;
++ u8 val;
++ int vendor_id = chc.pmic_id & PMIC_VENDOR_ID_MASK;
++
++ dev_info(chc.dev, "Low-supply event received from external-charger\n");
++ if (vendor_id == BASINCOVE_VENDORID || !chc.vbus_connect_status) {
++ dev_err(chc.dev, "Ignore Low-supply event received\n");
++ return 0;
++ }
++
++ msleep(50);
++ ret = pmic_read_reg(SCHGRIRQ1_ADDR, &val);
++ if (ret) {
++ dev_err(chc.dev,
++ "Error reading SCHGRIRQ1-register 0x%2x\n",
++ SCHGRIRQ1_ADDR);
++ return ret;
++ }
++
++ if (!(val & SCHRGRIRQ1_SVBUSDET_MASK)) {
++ int mask = 0;
++
++ dev_info(chc.dev, "USB VBUS Removed. Notifying OTG driver\n");
++ chc.vbus_connect_status = false;
++
++ if (chc.is_internal_usb_phy)
++ handle_internal_usbphy_notifications(mask);
++ else
++ atomic_notifier_call_chain(&chc.otg->notifier,
++ USB_EVENT_VBUS, &mask);
++ }
++
++ return ret;
++}
++
++static void handle_level0_interrupt(u8 int_reg, u8 stat_reg,
++ struct interrupt_info int_info[],
++ int int_info_size)
++{
++ int i;
++ bool int_stat;
++ char *log_msg;
++
++ for (i = 0; i < int_info_size; ++i) {
++
++ /*continue if interrupt register bit is not set */
++ if (!(int_reg & int_info[i].int_reg_mask))
++ continue;
++
++ /*log message if interrupt bit is set */
++ if (int_info[i].log_msg_int_reg_true)
++ dev_err(chc.dev, "%s",
++ int_info[i].log_msg_int_reg_true);
++
++ /* interrupt bit is set.call int handler. */
++ if (int_info[i].int_handle)
++ int_info[i].int_handle();
++
++ /* continue if stat_reg_mask is zero which
++ * means ignore status register
++ */
++ if (!(int_info[i].stat_reg_mask))
++ continue;
++
++ dev_dbg(chc.dev,
++ "stat_reg=%X int_info[i].stat_reg_mask=%X",
++ stat_reg, int_info[i].stat_reg_mask);
++
++ /* check if the interrupt status is true */
++ int_stat = (stat_reg & int_info[i].stat_reg_mask);
++
++ /* log message */
++ log_msg = int_stat ? int_info[i].log_msg_stat_true :
++ int_info[i].log_msg_stat_false;
++
++ if (log_msg)
++ dev_err(chc.dev, "%s", log_msg);
++
++ /* call status handler function */
++ if (int_info[i].stat_handle)
++ int_info[i].stat_handle(int_stat);
++
++ }
++
++ return ;
++}
++
++static void handle_level1_interrupt(u8 int_reg, u8 stat_reg)
++{
++ int mask;
++ u8 usb_id_sts;
++ int ret;
++
++ if (!int_reg)
++ return;
++
++ mask = !!(int_reg & stat_reg);
++ if (int_reg & CHRGRIRQ1_SUSBIDDET_MASK) {
++ if (mask)
++ dev_info(chc.dev,
++ "USB ID Detected. Notifying OTG driver\n");
++ else
++ dev_info(chc.dev,
++ "USB ID Removed. Notifying OTG driver\n");
++ atomic_notifier_call_chain(&chc.otg->notifier,
++ USB_EVENT_ID, &mask);
++ }
++
++ if (int_reg & CHRGRIRQ1_SVBUSDET_MASK) {
++ if (mask) {
++ dev_info(chc.dev,
++ "USB VBUS Detected. Notifying OTG driver\n");
++ chc.vbus_connect_status = true;
++ } else {
++ dev_info(chc.dev, "USB VBUS Removed. Notifying OTG driver\n");
++ chc.vbus_connect_status = false;
++ }
++
++ if (chc.is_internal_usb_phy)
++ handle_internal_usbphy_notifications(mask);
++ else
++ atomic_notifier_call_chain(&chc.otg->notifier,
++ USB_EVENT_VBUS, &mask);
++ }
++
++ return;
++}
++static void pmic_event_worker(struct work_struct *work)
++{
++ struct pmic_event *evt, *tmp;
++
++ dev_dbg(chc.dev, "%s\n", __func__);
++
++ mutex_lock(&chc.evt_queue_lock);
++ list_for_each_entry_safe(evt, tmp, &chc.evt_queue, node) {
++ list_del(&evt->node);
++
++ dev_dbg(chc.dev, "CHGRIRQ0=%X SCHGRIRQ0=%X CHGRIRQ1=%x SCHGRIRQ1=%X\n",
++ evt->chgrirq0_int, evt->chgrirq0_stat,
++ evt->chgrirq1_int, evt->chgrirq1_stat);
++ if (evt->chgrirq0_int)
++ handle_level0_interrupt(evt->chgrirq0_int,
++ evt->chgrirq0_stat, chgrirq0_info,
++ ARRAY_SIZE(chgrirq0_info));
++
++ if (evt->chgrirq1_stat)
++ handle_level1_interrupt(evt->chgrirq1_int,
++ evt->chgrirq1_stat);
++ kfree(evt);
++ }
++
++ mutex_unlock(&chc.evt_queue_lock);
++}
++
++static irqreturn_t pmic_isr(int irq, void *data)
++{
++ u16 pmic_intr;
++ u8 chgrirq0_int;
++ u8 chgrirq1_int;
++ u8 mask = ((CHRGRIRQ1_SVBUSDET_MASK) | (CHRGRIRQ1_SUSBIDDET_MASK));
++
++ pmic_intr = ioread16(chc.pmic_intr_iomap);
++ chgrirq0_int = (u8)pmic_intr;
++ chgrirq1_int = (u8)(pmic_intr >> 8);
++
++ if (!chgrirq1_int && !(chgrirq0_int & PMIC_CHRGR_INT0_MASK))
++ return IRQ_NONE;
++
++ dev_dbg(chc.dev, "%s", __func__);
++
++ return IRQ_WAKE_THREAD;
++}
++static irqreturn_t pmic_thread_handler(int id, void *data)
++{
++ u16 pmic_intr;
++ struct pmic_event *evt;
++ int ret;
++
++ evt = kzalloc(sizeof(*evt), GFP_ATOMIC);
++ if (evt == NULL) {
++ dev_dbg(chc.dev, "Error allocating evt structure in fn:%s\n",
++ __func__);
++ return IRQ_NONE;
++ }
++
++ pmic_intr = ioread16(chc.pmic_intr_iomap);
++ evt->chgrirq0_int = (u8)pmic_intr;
++ evt->chgrirq1_int = (u8)(pmic_intr >> 8);
++ dev_dbg(chc.dev, "irq0=%x irq1=%x\n",
++ evt->chgrirq0_int, evt->chgrirq1_int);
++
++ /*
++ In case this is an external charger interrupt, we are
++ clearing the level 1 irq register and let external charger
++ driver handle the interrupt.
++ */
++
++ if (!(evt->chgrirq1_int) &&
++ !(evt->chgrirq0_int & PMIC_CHRGR_CCSM_INT0_MASK)) {
++ intel_scu_ipc_update_register(IRQLVL1_MASK_ADDR, 0x00,
++ IRQLVL1_CHRGR_MASK);
++ if ((chc.invalid_batt) &&
++ (evt->chgrirq0_int & PMIC_CHRGR_EXT_CHRGR_INT_MASK)) {
++ dev_dbg(chc.dev, "Handling external charger interrupt!!\n");
++ kfree(evt);
++ return IRQ_HANDLED;
++ }
++ kfree(evt);
++ dev_dbg(chc.dev, "Unhandled interrupt!!\n");
++ return IRQ_NONE;
++ }
++
++ if (evt->chgrirq0_int & PMIC_CHRGR_CCSM_INT0_MASK) {
++ ret = intel_scu_ipc_ioread8(SCHGRIRQ0_ADDR,
++ &evt->chgrirq0_stat);
++ if (ret) {
++ dev_err(chc.dev,
++ "%s: Error(%d) in intel_scu_ipc_ioread8. Faile to read SCHGRIRQ0_ADDR\n",
++ __func__, ret);
++ kfree(evt);
++ goto end;
++ }
++ }
++ if (evt->chgrirq1_int) {
++ ret = intel_scu_ipc_ioread8(SCHGRIRQ1_ADDR,
++ &evt->chgrirq1_stat);
++ if (ret) {
++ dev_err(chc.dev,
++ "%s: Error(%d) in intel_scu_ipc_ioread8. Faile to read SCHGRIRQ1_ADDR\n",
++ __func__, ret);
++ kfree(evt);
++ goto end;
++ }
++ }
++
++ INIT_LIST_HEAD(&evt->node);
++
++ mutex_lock(&chc.evt_queue_lock);
++ list_add_tail(&evt->node, &chc.evt_queue);
++ mutex_unlock(&chc.evt_queue_lock);
++
++ queue_work(system_nrt_wq, &chc.evt_work);
++
++end:
++ /*clear first level IRQ */
++ dev_dbg(chc.dev, "Clearing IRQLVL1_MASK_ADDR\n");
++ intel_scu_ipc_update_register(IRQLVL1_MASK_ADDR, 0x00,
++ IRQLVL1_CHRGR_MASK);
++
++ return IRQ_HANDLED;
++}
++
++static int pmic_init(void)
++{
++ int ret = 0, i, temp_mon_ranges;
++ u16 adc_val;
++ u8 reg_val;
++ struct ps_pse_mod_prof *bcprof = chc.actual_bcprof;
++
++
++ temp_mon_ranges = min_t(u16, bcprof->temp_mon_ranges,
++ BATT_TEMP_NR_RNG);
++ for (i = 0; i < temp_mon_ranges; ++i) {
++ ret =
++ CONVERT_TEMP_TO_ADC(bcprof->temp_mon_range[i].temp_up_lim,
++ (int *)&adc_val);
++ if (unlikely(ret)) {
++ dev_err(chc.dev,
++ "Error converting temperature for zone %d!!\n",
++ i);
++ return ret;
++ }
++ ret = update_zone_temp(i, adc_val);
++ if (unlikely(ret)) {
++ dev_err(chc.dev,
++ "Error updating zone temp for zone %d\n",
++ i);
++ return ret;
++ }
++
++ if (chc.pdata->cc_to_reg)
++ chc.pdata->cc_to_reg(bcprof->temp_mon_range[i].
++ full_chrg_cur, &reg_val);
++
++ ret = update_zone_cc(i, reg_val);
++ if (unlikely(ret)) {
++ dev_err(chc.dev,
++ "Error updating zone cc for zone %d\n",
++ i);
++ return ret;
++ }
++
++ if (chc.pdata->cv_to_reg)
++ chc.pdata->cv_to_reg(bcprof->temp_mon_range[i].
++ full_chrg_vol, &reg_val);
++
++ ret = update_zone_cv(i, reg_val);
++ if (unlikely(ret)) {
++ dev_err(chc.dev,
++ "Error updating zone cv for zone %d\n",
++ i);
++ return ret;
++ }
++
++ /* Write lowest temp limit */
++ if (i == (bcprof->temp_mon_ranges - 1)) {
++ ret = CONVERT_TEMP_TO_ADC(bcprof->temp_low_lim,
++ (int *)&adc_val);
++ if (unlikely(ret)) {
++ dev_err(chc.dev,
++ "Error converting low lim temp!!\n");
++ return ret;
++ }
++
++ ret = update_zone_temp(i+1, adc_val);
++
++ if (unlikely(ret)) {
++ dev_err(chc.dev,
++ "Error updating last temp for zone %d\n",
++ i+1);
++ return ret;
++ }
++ }
++ }
++ ret = pmic_update_tt(TT_CUSTOMFIELDEN_ADDR,
++ TT_HOT_COLD_LC_MASK,
++ TT_HOT_COLD_LC_DIS);
++
++ if (unlikely(ret)) {
++ dev_err(chc.dev, "Error updating TT_CUSTOMFIELD_EN reg\n");
++ return ret;
++ }
++
++ if (chc.pdata->inlmt_to_reg)
++ chc.pdata->inlmt_to_reg(USBINPUTICC100VAL, &reg_val);
++
++ ret = pmic_write_tt(TT_USBINPUTICC100VAL_ADDR, reg_val);
++ return ret;
++}
++
++static inline void print_ps_pse_mod_prof(struct ps_pse_mod_prof *bcprof)
++{
++ int i, temp_mon_ranges;
++
++ dev_info(chc.dev, "ChrgProf: batt_id:%s\n", bcprof->batt_id);
++ dev_info(chc.dev, "ChrgProf: battery_type:%u\n", bcprof->battery_type);
++ dev_info(chc.dev, "ChrgProf: capacity:%u\n", bcprof->capacity);
++ dev_info(chc.dev, "ChrgProf: voltage_max:%u\n", bcprof->voltage_max);
++ dev_info(chc.dev, "ChrgProf: chrg_term_ma:%u\n", bcprof->chrg_term_ma);
++ dev_info(chc.dev, "ChrgProf: low_batt_mV:%u\n", bcprof->low_batt_mV);
++ dev_info(chc.dev, "ChrgProf: disch_tmp_ul:%d\n", bcprof->disch_tmp_ul);
++ dev_info(chc.dev, "ChrgProf: disch_tmp_ll:%d\n", bcprof->disch_tmp_ll);
++ dev_info(chc.dev, "ChrgProf: temp_mon_ranges:%u\n",
++ bcprof->temp_mon_ranges);
++ temp_mon_ranges = min_t(u16, bcprof->temp_mon_ranges,
++ BATT_TEMP_NR_RNG);
++
++ for (i = 0; i < temp_mon_ranges; ++i) {
++ dev_info(chc.dev, "ChrgProf: temp_up_lim[%d]:%d\n",
++ i, bcprof->temp_mon_range[i].temp_up_lim);
++ dev_info(chc.dev, "ChrgProf: full_chrg_vol[%d]:%d\n",
++ i, bcprof->temp_mon_range[i].full_chrg_vol);
++ dev_info(chc.dev, "ChrgProf: full_chrg_cur[%d]:%d\n",
++ i, bcprof->temp_mon_range[i].full_chrg_cur);
++ dev_info(chc.dev, "ChrgProf: maint_chrgr_vol_ll[%d]:%d\n",
++ i, bcprof->temp_mon_range[i].maint_chrg_vol_ll);
++ dev_info(chc.dev, "ChrgProf: maint_chrgr_vol_ul[%d]:%d\n",
++ i, bcprof->temp_mon_range[i].maint_chrg_vol_ul);
++ dev_info(chc.dev, "ChrgProf: maint_chrg_cur[%d]:%d\n",
++ i, bcprof->temp_mon_range[i].maint_chrg_cur);
++ }
++ dev_info(chc.dev, "ChrgProf: temp_low_lim:%d\n", bcprof->temp_low_lim);
++}
++
++static int find_tempzone_index(short int *interval,
++ int *num_zones,
++ short int *temp_up_lim)
++{
++ struct ps_pse_mod_prof *bprof = chc.sfi_bcprof->batt_prof;
++ int up_lim_index = 0, low_lim_index = -1;
++ int diff = 0;
++ int i;
++
++ *num_zones = MIN_BATT_PROF - bprof->temp_mon_ranges + 1;
++ if ((*num_zones) <= 0)
++ return 0;
++
++ for (i = 0 ; i < bprof->temp_mon_ranges ; i++) {
++ if (bprof->temp_mon_range[i].temp_up_lim == BATT_TEMP_WARM)
++ up_lim_index = i;
++ }
++
++ low_lim_index = up_lim_index + 1;
++
++ if (low_lim_index == bprof->temp_mon_ranges)
++ diff = bprof->temp_low_lim -
++ bprof->temp_mon_range[up_lim_index].temp_up_lim;
++ else
++ diff = bprof->temp_mon_range[low_lim_index].temp_up_lim -
++ bprof->temp_mon_range[up_lim_index].temp_up_lim;
++
++ *interval = diff / (*num_zones);
++ *temp_up_lim = bprof->temp_mon_range[up_lim_index].temp_up_lim;
++
++ return up_lim_index;
++}
++
++
++static void set_pmic_batt_prof(struct ps_pse_mod_prof *new_prof,
++ struct ps_pse_mod_prof *bprof)
++{
++ int num_zones;
++ int split_index;
++ int i, j = 0;
++ short int temp_up_lim;
++ short int interval;
++
++ if ((new_prof == NULL) || (bprof == NULL))
++ return;
++
++ if (!NEED_ZONE_SPLIT(bprof)) {
++ dev_info(chc.dev, "No need to split the zones!!\n");
++ memcpy(new_prof, bprof, sizeof(struct ps_pse_mod_prof));
++ return;
++ }
++
++ strcpy(&(new_prof->batt_id[0]), &(bprof->batt_id[0]));
++ new_prof->battery_type = bprof->battery_type;
++ new_prof->capacity = bprof->capacity;
++ new_prof->voltage_max = bprof->voltage_max;
++ new_prof->chrg_term_ma = bprof->chrg_term_ma;
++ new_prof->low_batt_mV = bprof->low_batt_mV;
++ new_prof->disch_tmp_ul = bprof->disch_tmp_ul;
++ new_prof->disch_tmp_ll = bprof->disch_tmp_ll;
++
++ split_index = find_tempzone_index(&interval, &num_zones, &temp_up_lim);
++
++ for (i = 0 ; i < bprof->temp_mon_ranges; i++) {
++ if ((i == split_index) && (num_zones > 0)) {
++ for (j = 0; j < num_zones; j++,
++ temp_up_lim += interval) {
++ memcpy(&new_prof->temp_mon_range[i+j],
++ &bprof->temp_mon_range[i],
++ sizeof(bprof->temp_mon_range[i]));
++ new_prof->temp_mon_range[i+j].temp_up_lim =
++ temp_up_lim;
++ }
++ j--;
++ } else {
++ memcpy(&new_prof->temp_mon_range[i+j],
++ &bprof->temp_mon_range[i],
++ sizeof(bprof->temp_mon_range[i]));
++ }
++ }
++
++ new_prof->temp_mon_ranges = i+j;
++ new_prof->temp_low_lim = bprof->temp_low_lim;
++
++ return;
++}
++
++
++static int pmic_check_initial_events(void)
++{
++ struct pmic_event *evt;
++ int ret;
++ u8 mask = (CHRGRIRQ1_SVBUSDET_MASK);
++
++ evt = kzalloc(sizeof(struct pmic_event), GFP_KERNEL);
++ if (evt == NULL) {
++ dev_dbg(chc.dev, "Error allocating evt structure in fn:%s\n",
++ __func__);
++ return -1;
++ }
++
++ ret = intel_scu_ipc_ioread8(SCHGRIRQ0_ADDR, &evt->chgrirq0_stat);
++ evt->chgrirq0_int = evt->chgrirq0_stat;
++ ret = intel_scu_ipc_ioread8(SCHGRIRQ1_ADDR, &evt->chgrirq1_stat);
++ evt->chgrirq1_int = evt->chgrirq1_stat;
++
++ if (evt->chgrirq1_stat || evt->chgrirq0_int) {
++ INIT_LIST_HEAD(&evt->node);
++ mutex_lock(&chc.evt_queue_lock);
++ list_add_tail(&evt->node, &chc.evt_queue);
++ mutex_unlock(&chc.evt_queue_lock);
++ schedule_work(&chc.evt_work);
++ }
++
++ pmic_bat_zone_changed();
++
++ return ret;
++}
++
++/**
++ * pmic_charger_probe - PMIC charger probe function
++ * @pdev: pmic platform device structure
++ * Context: can sleep
++ *
++ * pmic charger driver initializes its internal data
++ * structure and other infrastructure components for it
++ * to work as expected.
++ */
++static int pmic_chrgr_probe(struct platform_device *pdev)
++{
++ int retval = 0;
++ u8 val;
++
++ if (!pdev)
++ return -ENODEV;
++
++ chc.health = POWER_SUPPLY_HEALTH_UNKNOWN;
++ chc.dev = &pdev->dev;
++ chc.irq = platform_get_irq(pdev, 0);
++ chc.pdata = pdev->dev.platform_data;
++ platform_set_drvdata(pdev, &chc);
++
++ if (chc.pdata == NULL) {
++ dev_err(chc.dev, "Platform data not initialized\n");
++ return -EFAULT;
++ }
++
++ retval = intel_scu_ipc_ioread8(PMIC_ID_ADDR, &chc.pmic_id);
++ if (retval) {
++ dev_err(chc.dev,
++ "Error reading PMIC ID register\n");
++ return retval;
++ }
++
++ dev_info(chc.dev, "PMIC-ID: %x\n", chc.pmic_id);
++ if ((chc.pmic_id & PMIC_VENDOR_ID_MASK) == SHADYCOVE_VENDORID) {
++ retval = pmic_read_reg(USBPATH_ADDR, &val);
++ if (retval) {
++ dev_err(chc.dev,
++ "Error reading CHGRSTATUS-register 0x%2x\n",
++ CHGRSTATUS_ADDR);
++ return retval;
++ }
++
++ if (val & USBPATH_USBSEL_MASK) {
++ dev_info(chc.dev, "SOC-Internal-USBPHY used\n");
++ chc.is_internal_usb_phy = true;
++ } else
++ dev_info(chc.dev, "External-USBPHY used\n");
++ }
++
++ chc.sfi_bcprof = kzalloc(sizeof(struct ps_batt_chg_prof),
++ GFP_KERNEL);
++ if (chc.sfi_bcprof == NULL) {
++ dev_err(chc.dev,
++ "Error allocating memeory SFI battery profile\n");
++ return -ENOMEM;
++ }
++
++ retval = get_batt_prop(chc.sfi_bcprof);
++ if (retval) {
++ dev_err(chc.dev,
++ "Error reading battery profile from battid frmwrk\n");
++ kfree(chc.sfi_bcprof);
++ chc.invalid_batt = true;
++ chc.sfi_bcprof = NULL;
++ }
++
++ retval = intel_scu_ipc_update_register(CHGRCTRL0_ADDR, SWCONTROL_ENABLE,
++ CHGRCTRL0_SWCONTROL_MASK);
++ if (retval)
++ dev_err(chc.dev, "Error enabling sw control. Charging may continue in h/w control mode\n");
++
++ if (!chc.invalid_batt) {
++ chc.actual_bcprof = kzalloc(sizeof(struct ps_pse_mod_prof),
++ GFP_KERNEL);
++ if (chc.actual_bcprof == NULL) {
++ dev_err(chc.dev,
++ "Error allocating mem for local battery profile\n");
++ kfree(chc.sfi_bcprof);
++ return -ENOMEM;
++ }
++
++ chc.runtime_bcprof = kzalloc(sizeof(struct ps_pse_mod_prof),
++ GFP_KERNEL);
++ if (chc.runtime_bcprof == NULL) {
++ dev_err(chc.dev,
++ "Error allocating mem for runtime batt profile\n");
++ kfree(chc.sfi_bcprof);
++ kfree(chc.actual_bcprof);
++ return -ENOMEM;
++ }
++
++ set_pmic_batt_prof(chc.actual_bcprof,
++ chc.sfi_bcprof->batt_prof);
++ print_ps_pse_mod_prof(chc.actual_bcprof);
++ retval = pmic_init();
++ if (retval)
++ dev_err(chc.dev, "Error in Initializing PMIC. Continue in h/w charging mode\n");
++
++ memcpy(chc.runtime_bcprof, chc.actual_bcprof,
++ sizeof(struct ps_pse_mod_prof));
++ }
++
++ chc.pmic_intr_iomap = ioremap_nocache(PMIC_SRAM_INTR_ADDR, 8);
++ if (!chc.pmic_intr_iomap) {
++ dev_err(&pdev->dev, "ioremap Failed\n");
++ retval = -ENOMEM;
++ goto ioremap_failed;
++ }
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0))
++ chc.otg = usb_get_transceiver();
++#else
++ chc.otg = usb_get_phy(USB_PHY_TYPE_USB2);
++#endif
++ if (!chc.otg || IS_ERR(chc.otg)) {
++ dev_err(&pdev->dev, "Failed to get otg transceiver!!\n");
++ retval = -ENOMEM;
++ goto otg_req_failed;
++ }
++
++ INIT_WORK(&chc.evt_work, pmic_event_worker);
++ INIT_LIST_HEAD(&chc.evt_queue);
++ mutex_init(&chc.evt_queue_lock);
++
++ /* register interrupt */
++ retval = request_threaded_irq(chc.irq, pmic_isr,
++ pmic_thread_handler,
++ IRQF_SHARED|IRQF_NO_SUSPEND ,
++ DRIVER_NAME, &chc);
++ if (retval) {
++ dev_err(&pdev->dev,
++ "Error in request_threaded_irq(irq(%d)!!\n",
++ chc.irq);
++ goto otg_req_failed;
++ }
++
++ retval = pmic_check_initial_events();
++ if (unlikely(retval)) {
++ dev_err(&pdev->dev,
++ "Error posting initial events\n");
++ goto req_irq_failed;
++ }
++
++ /* unmask charger interrupts in second level IRQ register*/
++ retval = intel_scu_ipc_update_register(MCHGRIRQ0_ADDR, 0x00,
++ PMIC_CHRGR_INT0_MASK);
++ /* unmask charger interrupts in second level IRQ register*/
++ retval = intel_scu_ipc_iowrite8(MCHGRIRQ1_ADDR, 0x00);
++ if (unlikely(retval))
++ goto unmask_irq_failed;
++
++
++ /* unmask IRQLVL1 register */
++ retval = intel_scu_ipc_update_register(IRQLVL1_MASK_ADDR, 0x00,
++ IRQLVL1_CHRGR_MASK);
++ if (unlikely(retval))
++ goto unmask_irq_failed;
++
++ retval = intel_scu_ipc_update_register(USBIDCTRL_ADDR,
++ ACADETEN_MASK | USBIDEN_MASK,
++ ACADETEN_MASK | USBIDEN_MASK);
++ if (unlikely(retval))
++ goto unmask_irq_failed;
++
++ chc.health = POWER_SUPPLY_HEALTH_GOOD;
++#ifdef CONFIG_DEBUG_FS
++ pmic_debugfs_init();
++#endif
++ return 0;
++
++unmask_irq_failed:
++req_irq_failed:
++ free_irq(chc.irq, &chc);
++otg_req_failed:
++ iounmap(chc.pmic_intr_iomap);
++ioremap_failed:
++ kfree(chc.sfi_bcprof);
++ kfree(chc.actual_bcprof);
++ kfree(chc.runtime_bcprof);
++ return retval;
++}
++
++static void pmic_chrgr_do_exit_ops(struct pmic_chrgr_drv_context *chc)
++{
++ /*TODO:
++ * If charger is connected send IPC message to SCU to continue charging
++ */
++#ifdef CONFIG_DEBUG_FS
++ pmic_debugfs_exit();
++#endif
++}
++
++/**
++ * pmic_charger_remove - PMIC Charger driver remove
++ * @pdev: PMIC charger platform device structure
++ * Context: can sleep
++ *
++ * PMIC charger finalizes its internal data structure and other
++ * infrastructure components that it initialized in
++ * pmic_chrgr_probe.
++ */
++static int pmic_chrgr_remove(struct platform_device *pdev)
++{
++ struct pmic_chrgr_drv_context *chc = platform_get_drvdata(pdev);
++
++ if (chc) {
++ pmic_chrgr_do_exit_ops(chc);
++ free_irq(chc->irq, chc);
++ iounmap(chc->pmic_intr_iomap);
++ kfree(chc->sfi_bcprof);
++ kfree(chc->actual_bcprof);
++ kfree(chc->runtime_bcprof);
++ }
++
++ return 0;
++}
++
++#ifdef CONFIG_PM
++static int pmic_chrgr_suspend(struct device *dev)
++{
++ dev_dbg(dev, "%s called\n", __func__);
++ return 0;
++}
++
++static int pmic_chrgr_resume(struct device *dev)
++{
++ dev_dbg(dev, "%s called\n", __func__);
++ return 0;
++}
++#endif
++
++#ifdef CONFIG_PM_RUNTIME
++static int pmic_chrgr_runtime_suspend(struct device *dev)
++{
++ dev_dbg(dev, "%s called\n", __func__);
++ return 0;
++}
++
++static int pmic_chrgr_runtime_resume(struct device *dev)
++{
++ dev_dbg(dev, "%s called\n", __func__);
++ return 0;
++}
++
++static int pmic_chrgr_runtime_idle(struct device *dev)
++{
++ dev_dbg(dev, "%s called\n", __func__);
++ return 0;
++}
++#endif
++
++/*********************************************************************
++ * Driver initialisation and finalization
++ *********************************************************************/
++
++static const struct dev_pm_ops pmic_chrgr_pm_ops = {
++ SET_SYSTEM_SLEEP_PM_OPS(pmic_chrgr_suspend,
++ pmic_chrgr_resume)
++ SET_RUNTIME_PM_OPS(pmic_chrgr_runtime_suspend,
++ pmic_chrgr_runtime_resume,
++ pmic_chrgr_runtime_idle)
++};
++
++static struct platform_driver pmic_chrgr_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .pm = &pmic_chrgr_pm_ops,
++ },
++ .probe = pmic_chrgr_probe,
++ .remove = pmic_chrgr_remove,
++};
++
++static int pmic_chrgr_init(void)
++{
++ return platform_driver_register(&pmic_chrgr_driver);
++}
++
++static void pmic_chrgr_exit(void)
++{
++ platform_driver_unregister(&pmic_chrgr_driver);
++}
++
++static int pmic_ccsm_rpmsg_probe(struct rpmsg_channel *rpdev)
++{
++ int ret = 0;
++
++ if (rpdev == NULL) {
++ pr_err("rpmsg channel not created\n");
++ ret = -ENODEV;
++ goto out;
++ }
++
++ dev_info(&rpdev->dev, "Probed pmic_ccsm rpmsg device\n");
++
++ ret = pmic_chrgr_init();
++
++out:
++ return ret;
++}
++
++static void pmic_ccsm_rpmsg_remove(struct rpmsg_channel *rpdev)
++{
++ pmic_chrgr_exit();
++ dev_info(&rpdev->dev, "Removed pmic_ccsm rpmsg device\n");
++}
++
++static void pmic_ccsm_rpmsg_cb(struct rpmsg_channel *rpdev, void *data,
++ int len, void *priv, u32 src)
++{
++ dev_warn(&rpdev->dev, "unexpected, message\n");
++
++ print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
++ data, len, true);
++}
++
++static struct rpmsg_device_id pmic_ccsm_rpmsg_id_table[] = {
++ { .name = "rpmsg_pmic_ccsm" },
++ { },
++};
++MODULE_DEVICE_TABLE(rpmsg, pmic_ccsm_rpmsg_id_table);
++
++static struct rpmsg_driver pmic_ccsm_rpmsg = {
++ .drv.name = KBUILD_MODNAME,
++ .drv.owner = THIS_MODULE,
++ .id_table = pmic_ccsm_rpmsg_id_table,
++ .probe = pmic_ccsm_rpmsg_probe,
++ .callback = pmic_ccsm_rpmsg_cb,
++ .remove = pmic_ccsm_rpmsg_remove,
++};
++
++static int __init pmic_ccsm_rpmsg_init(void)
++{
++ return register_rpmsg_driver(&pmic_ccsm_rpmsg);
++}
++
++static void __exit pmic_ccsm_rpmsg_exit(void)
++{
++ return unregister_rpmsg_driver(&pmic_ccsm_rpmsg);
++}
++/* Defer init call so that dependant drivers will be loaded. Using async
++ * for parallel driver initialization */
++late_initcall(pmic_ccsm_rpmsg_init);
++module_exit(pmic_ccsm_rpmsg_exit);
++
++MODULE_AUTHOR("Jenny TC <jenny.tc@intel.com>");
++MODULE_DESCRIPTION("PMIC Charger Driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/power/pmic_ccsm.h b/drivers/power/pmic_ccsm.h
+new file mode 100644
+index 0000000..7619389
+--- /dev/null
++++ b/drivers/power/pmic_ccsm.h
+@@ -0,0 +1,356 @@
++/*
++ * pmic_ccsm.h - Intel MID PMIC CCSM Driver header file
++ *
++ * Copyright (C) 2011 Intel Corporation
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * 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; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ * Author: Jenny TC <jenny.tc@intel.com>
++ */
++
++#ifndef __PMIC_CCSM_H__
++#define __PMIC_CCSM_H__
++
++#include <asm/pmic_pdata.h>
++/*********************************************************************
++ * Generic defines
++ *********************************************************************/
++
++#define D7 (1 << 7)
++#define D6 (1 << 6)
++#define D5 (1 << 5)
++#define D4 (1 << 4)
++#define D3 (1 << 3)
++#define D2 (1 << 2)
++#define D1 (1 << 1)
++#define D0 (1 << 0)
++
++#define PMIC_ID_ADDR 0x00
++
++#define PMIC_VENDOR_ID_MASK (0x03 << 6)
++#define PMIC_MINOR_REV_MASK 0x07
++#define PMIC_MAJOR_REV_MASK (0x07 << 3)
++
++#define BASINCOVE_VENDORID (0x03 << 6)
++#define SHADYCOVE_VENDORID 0x00
++
++#define BC_PMIC_MAJOR_REV_A0 0x00
++#define BC_PMIC_MAJOR_REV_B0 (0x01 << 3)
++
++#define PMIC_BZONE_LOW 0
++#define PMIC_BZONE_HIGH 5
++
++#define IRQLVL1_ADDR 0x01
++#define IRQLVL1_MASK_ADDR 0x0c
++#define IRQLVL1_CHRGR_MASK D5
++
++#define THRMZN0H_ADDR_BC 0xCE
++#define THRMZN0L_ADDR_BC 0xCF
++#define THRMZN1H_ADDR_BC 0xD0
++#define THRMZN1L_ADDR_BC 0xD1
++#define THRMZN2H_ADDR_BC 0xD2
++#define THRMZN2L_ADDR_BC 0xD3
++#define THRMZN3H_ADDR_BC 0xD4
++#define THRMZN3L_ADDR_BC 0xD5
++#define THRMZN4H_ADDR_BC 0xD6
++#define THRMZN4L_ADDR_BC 0xD7
++
++#define THRMZN0H_ADDR_SC 0xD7
++#define THRMZN0L_ADDR_SC 0xD8
++#define THRMZN1H_ADDR_SC 0xD9
++#define THRMZN1L_ADDR_SC 0xDA
++#define THRMZN2H_ADDR_SC 0xDD
++#define THRMZN2L_ADDR_SC 0xDE
++#define THRMZN3H_ADDR_SC 0xDF
++#define THRMZN3L_ADDR_SC 0xE0
++#define THRMZN4H_ADDR_SC 0xE1
++#define THRMZN4L_ADDR_SC 0xE2
++
++#define CHGRIRQ0_ADDR 0x07
++#define CHGIRQ0_BZIRQ_MASK D7
++#define CHGIRQ0_BAT_CRIT_MASK D6
++#define CHGIRQ0_BAT1_ALRT_MASK D5
++#define CHGIRQ0_BAT0_ALRT_MASK D4
++
++#define MCHGRIRQ0_ADDR 0x12
++#define MCHGIRQ0_RSVD_MASK D7
++#define MCHGIRQ0_MBAT_CRIT_MASK D6
++#define MCHGIRQ0_MBAT1_ALRT_MASK D5
++#define MCHGIRQ0_MBAT0_ALRT_MASK D4
++
++#define SCHGRIRQ0_ADDR 0x4E
++#define SCHGIRQ0_RSVD_MASK D7
++#define SCHGIRQ0_SBAT_CRIT_MASK D6
++#define SCHGIRQ0_SBAT1_ALRT_MASK D5
++#define SCHGIRQ0_SBAT0_ALRT_MASK D4
++
++#define LOWBATTDET0_ADDR 0x2C
++#define LOWBATTDET1_ADDR 0x2D
++#define BATTDETCTRL_ADDR 0x2E
++#define VBUSDETCTRL_ADDR 0x50
++#define VDCINDETCTRL_ADDR 0x51
++
++#define CHRGRIRQ1_ADDR 0x08
++#define CHRGRIRQ1_SUSBIDDET_MASK D3
++#define CHRGRIRQ1_SBATTDET_MASK D2
++#define CHRGRIRQ1_SDCDET_MASK D1
++#define CHRGRIRQ1_SVBUSDET_MASK D0
++#define MCHGRIRQ1_ADDR 0x13
++#define MCHRGRIRQ1_SUSBIDDET_MASK D3
++#define MCHRGRIRQ1_SBATTDET_MAS D2
++#define MCHRGRIRQ1_SDCDET_MASK D1
++#define MCHRGRIRQ1_SVBUSDET_MASK D0
++#define SCHGRIRQ1_ADDR 0x4F
++#define SCHRGRIRQ1_SUSBIDDET_MASK D3
++#define SCHRGRIRQ1_SBATTDET_MASK D2
++#define SCHRGRIRQ1_SDCDET_MASK D1
++#define SCHRGRIRQ1_SVBUSDET_MASK D0
++
++#define PMIC_CHRGR_INT0_MASK 0xB1
++#define PMIC_CHRGR_CCSM_INT0_MASK 0xB0
++#define PMIC_CHRGR_EXT_CHRGR_INT_MASK 0x01
++
++#define CHGRCTRL0_ADDR 0x4B
++#define CHGRCTRL0_WDT_NOKICK_MASK D7
++#define CHGRCTRL0_DBPOFF_MASK D6
++#define CHGRCTRL0_CCSM_OFF_MASK D5
++#define CHGRCTRL0_TTLCK_MASK D4
++#define CHGRCTRL0_SWCONTROL_MASK D3
++#define CHGRCTRL0_EXTCHRDIS_MASK D2
++#define CHRCTRL0_EMRGCHREN_MASK D1
++#define CHRCTRL0_CHGRRESET_MASK D0
++
++#define WDT_NOKICK_ENABLE (0x01 << 7)
++#define WDT_NOKICK_DISABLE (~WDT_NOKICK_ENABLE & 0xFF)
++
++#define EXTCHRDIS_ENABLE (0x01 << 2)
++#define EXTCHRDIS_DISABLE (~EXTCHRDIS_ENABLE & 0xFF)
++#define SWCONTROL_ENABLE (0x01 << 3)
++#define EMRGCHREN_ENABLE (0x01 << 1)
++
++#define CHGRCTRL1_ADDR 0x4C
++#define CHGRCTRL1_DBPEN_MASK D7
++#define CHGRCTRL1_OTGMODE_MASK D6
++#define CHGRCTRL1_FTEMP_EVENT_MASK D5
++#define CHGRCTRL1_FUSB_INLMT_1500 D4
++#define CHGRCTRL1_FUSB_INLMT_900 D3
++#define CHGRCTRL1_FUSB_INLMT_500 D2
++#define CHGRCTRL1_FUSB_INLMT_150 D1
++#define CHGRCTRL1_FUSB_INLMT_100 D0
++
++#define CHGRSTATUS_ADDR 0x4D
++#define CHGRSTATUS_RSVD_MASK (D7|D6|D5|D3)
++#define CHGRSTATUS_SDPB_MASK D4
++#define CHGRSTATUS_CHGDISLVL_MASK D2
++#define CHGRSTATUS_CHGDETB_LATCH_MASK D1
++#define CHGDETB_MASK D0
++
++#define THRMBATZONE_ADDR_BC 0xB5
++#define THRMBATZONE_ADDR_SC 0xB6
++#define THRMBATZONE_MASK (D0|D1|D2)
++
++#define USBIDCTRL_ADDR 0x19
++#define USBIDEN_MASK 0x01
++#define ACADETEN_MASK (0x01 << 1)
++
++#define USBIDSTAT_ADDR 0x1A
++#define ID_SHORT D4
++#define ID_SHORT_VBUS (1 << 4)
++#define ID_NOT_SHORT_VBUS 0
++#define ID_FLOAT_STS D3
++#define R_ID_FLOAT_DETECT (1 << 3)
++#define R_ID_FLOAT_NOT_DETECT 0
++#define ID_RAR_BRC_STS ((D2 | D1))
++#define ID_ACA_NOT_DETECTED 0
++#define R_ID_A (1 << 1)
++#define R_ID_B (2 << 1)
++#define R_ID_C (3 << 1)
++#define ID_GND D0
++#define ID_TYPE_A 0
++#define ID_TYPE_B 1
++#define is_aca(x) ((x & R_ID_A) || (x & R_ID_B) || (x & R_ID_C))
++
++#define WAKESRC_ADDR 0x24
++
++#define CHRTTADDR_ADDR 0x56
++#define CHRTTDATA_ADDR 0x57
++
++#define USBSRCDET_RETRY_CNT 4
++#define USBSRCDET_SLEEP_TIME 200
++#define USBSRCDETSTATUS_ADDR 0x5D
++#define USBSRCDET_SUSBHWDET_MASK (D0|D1)
++#define USBSRCDET_USBSRCRSLT_MASK (D2|D3|D4|D5)
++#define USBSRCDET_SDCD_MASK (D6|D7)
++#define USBSRCDET_SUSBHWDET_DETON (0x01 << 0)
++#define USBSRCDET_SUSBHWDET_DETSUCC (0x01 << 1)
++#define USBSRCDET_SUSBHWDET_DETFAIL (0x03 << 0)
++
++/* Register on I2C-dev2-0x6E */
++#define USBPATH_ADDR 0x011C
++#define USBPATH_USBSEL_MASK D3
++
++#define TT_I2CDADDR_ADDR 0x00
++#define TT_CHGRINIT0OS_ADDR 0x01
++#define TT_CHGRINIT1OS_ADDR 0x02
++#define TT_CHGRINIT2OS_ADDR 0x03
++#define TT_CHGRINIT3OS_ADDR 0x04
++#define TT_CHGRINIT4OS_ADDR 0x05
++#define TT_CHGRINIT5OS_ADDR 0x06
++#define TT_CHGRINIT6OS_ADDR 0x07
++#define TT_CHGRINIT7OS_ADDR 0x08
++#define TT_USBINPUTICCOS_ADDR 0x09
++#define TT_USBINPUTICCMASK_ADDR 0x0A
++#define TT_CHRCVOS_ADDR 0X0B
++#define TT_CHRCVMASK_ADDR 0X0C
++#define TT_CHRCCOS_ADDR 0X0D
++#define TT_CHRCCMASK_ADDR 0X0E
++#define TT_LOWCHROS_ADDR 0X0F
++#define TT_LOWCHRMASK_ADDR 0X10
++#define TT_WDOGRSTOS_ADDR 0X11
++#define TT_WDOGRSTMASK_ADDR 0X12
++#define TT_CHGRENOS_ADDR 0X13
++#define TT_CHGRENMASK_ADDR 0X14
++
++#define TT_CUSTOMFIELDEN_ADDR 0X15
++#define TT_HOT_LC_EN D1
++#define TT_COLD_LC_EN D0
++#define TT_HOT_COLD_LC_MASK (TT_HOT_LC_EN | TT_COLD_LC_EN)
++#define TT_HOT_COLD_LC_EN (TT_HOT_LC_EN | TT_COLD_LC_EN)
++#define TT_HOT_COLD_LC_DIS 0
++
++#define TT_CHGRINIT0VAL_ADDR 0X20
++#define TT_CHGRINIT1VAL_ADDR 0X21
++#define TT_CHGRINIT2VAL_ADDR 0X22
++#define TT_CHGRINIT3VAL_ADDR 0X23
++#define TT_CHGRINIT4VAL_ADDR 0X24
++#define TT_CHGRINIT5VAL_ADDR 0X25
++#define TT_CHGRINIT6VAL_ADDR 0X26
++#define TT_CHGRINIT7VAL_ADDR 0X27
++#define TT_USBINPUTICC100VAL_ADDR 0X28
++#define TT_USBINPUTICC150VAL_ADDR 0X29
++#define TT_USBINPUTICC500VAL_ADDR 0X2A
++#define TT_USBINPUTICC900VAL_ADDR 0X2B
++#define TT_USBINPUTICC1500VAL_ADDR 0X2C
++#define TT_CHRCVEMRGLOWVAL_ADDR 0X2D
++#define TT_CHRCVCOLDVAL_ADDR 0X2E
++#define TT_CHRCVCOOLVAL_ADDR 0X2F
++#define TT_CHRCVWARMVAL_ADDR 0X30
++#define TT_CHRCVHOTVAL_ADDR 0X31
++#define TT_CHRCVEMRGHIVAL_ADDR 0X32
++#define TT_CHRCCEMRGLOWVAL_ADDR 0X33
++#define TT_CHRCCCOLDVAL_ADDR 0X34
++#define TT_CHRCCCOOLVAL_ADDR 0X35
++#define TT_CHRCCWARMVAL_ADDR 0X36
++#define TT_CHRCCHOTVAL_ADDR 0X37
++#define TT_CHRCCEMRGHIVAL_ADDR 0X38
++#define TT_LOWCHRENVAL_ADDR 0X39
++#define TT_LOWCHRDISVAL_ADDR 0X3A
++#define TT_WDOGRSTVAL_ADDR 0X3B
++#define TT_CHGRENVAL_ADDR 0X3C
++#define TT_CHGRDISVAL_ADDR 0X3D
++
++/*Interrupt registers*/
++#define BATT_CHR_BATTDET_MASK D2
++/*Status registers*/
++#define BATT_PRESENT 1
++#define BATT_NOT_PRESENT 0
++
++#define BATT_STRING_MAX 8
++#define BATTID_STR_LEN 8
++
++#define CHARGER_PRESENT 1
++#define CHARGER_NOT_PRESENT 0
++
++/*FIXME: Modify default values */
++#define BATT_DEAD_CUTOFF_VOLT 3400 /* 3400 mV */
++#define BATT_CRIT_CUTOFF_VOLT 3700 /* 3700 mV */
++
++#define MSIC_BATT_TEMP_MAX 60 /* 60 degrees */
++#define MSIC_BATT_TEMP_MIN 0
++
++#define BATT_TEMP_WARM 45 /* 45 degrees */
++#define MIN_BATT_PROF 4
++
++#define PMIC_REG_NAME_LEN 28
++#define PMIC_REG_DEF(x) { .reg_name = #x, .addr = x }
++
++struct interrupt_info {
++ /* Interrupt register mask*/
++ u8 int_reg_mask;
++ /* interrupt status register mask */
++ u8 stat_reg_mask;
++ /* log message if interrupt is set */
++ char *log_msg_int_reg_true;
++ /* log message if stat is true or false */
++ char *log_msg_stat_true;
++ char *log_msg_stat_false;
++ /* handle if interrupt bit is set */
++ void (*int_handle) (void);
++ /* interrupt status handler */
++ void (*stat_handle) (bool);
++};
++
++enum pmic_charger_cable_type {
++ PMIC_CHARGER_TYPE_NONE = 0,
++ PMIC_CHARGER_TYPE_SDP,
++ PMIC_CHARGER_TYPE_DCP,
++ PMIC_CHARGER_TYPE_CDP,
++ PMIC_CHARGER_TYPE_ACA,
++ PMIC_CHARGER_TYPE_SE1,
++ PMIC_CHARGER_TYPE_MHL,
++ PMIC_CHARGER_TYPE_FLOAT_DP_DN,
++ PMIC_CHARGER_TYPE_OTHER,
++ PMIC_CHARGER_TYPE_DCP_EXTPHY,
++};
++
++struct pmic_chrgr_drv_context {
++ bool invalid_batt;
++ bool is_batt_present;
++ bool current_sense_enabled;
++ unsigned int irq; /* GPE_ID or IRQ# */
++ void __iomem *pmic_intr_iomap;
++ struct device *dev;
++ int health;
++ u8 pmic_id;
++ bool is_internal_usb_phy;
++ enum pmic_charger_cable_type charger_type;
++ /* ShadyCove-WA for VBUS removal detect issue */
++ bool vbus_connect_status;
++ struct ps_batt_chg_prof *sfi_bcprof;
++ struct ps_pse_mod_prof *actual_bcprof;
++ struct ps_pse_mod_prof *runtime_bcprof;
++ struct pmic_platform_data *pdata;
++ struct usb_phy *otg;
++ struct list_head evt_queue;
++ struct work_struct evt_work;
++ struct mutex evt_queue_lock;
++};
++
++struct pmic_event {
++ struct list_head node;
++ u8 chgrirq0_int;
++ u8 chgrirq1_int;
++ u8 chgrirq0_stat;
++ u8 chgrirq1_stat;
++};
++
++struct pmic_regs_def {
++ char reg_name[PMIC_REG_NAME_LEN];
++ u16 addr;
++};
++
++#endif
+diff --git a/drivers/power/power_supply.h b/drivers/power/power_supply.h
+index cc439fd..d2b3a53 100644
+--- a/drivers/power/power_supply.h
++++ b/drivers/power/power_supply.h
+@@ -40,3 +40,24 @@ static inline int power_supply_create_triggers(struct power_supply *psy)
+ static inline void power_supply_remove_triggers(struct power_supply *psy) {}
+
+ #endif /* CONFIG_LEDS_TRIGGERS */
++#ifdef CONFIG_POWER_SUPPLY_CHARGER
++
++extern void power_supply_trigger_charging_handler(struct power_supply *psy);
++extern int power_supply_register_charger(struct power_supply *psy);
++extern int power_supply_unregister_charger(struct power_supply *psy);
++extern int psy_charger_throttle_charger(struct power_supply *psy,
++ unsigned long state);
++
++#else
++
++static inline void
++ power_supply_trigger_charging_handler(struct power_supply *psy) { }
++static inline int power_supply_register_charger(struct power_supply *psy)
++{ return 0; }
++static inline int power_supply_unregister_charger(struct power_supply *psy)
++{ return 0; }
++static inline int psy_charger_throttle_charger(struct power_supply *psy,
++ unsigned long state)
++{ return 0; }
++
++#endif
+diff --git a/drivers/power/power_supply_charger.c b/drivers/power/power_supply_charger.c
+new file mode 100644
+index 0000000..9ed83bd
+--- /dev/null
++++ b/drivers/power/power_supply_charger.c
+@@ -0,0 +1,1151 @@
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/device.h>
++#include <linux/err.h>
++#include <linux/power_supply.h>
++#include <linux/thermal.h>
++#include <linux/extcon.h>
++#include <linux/power/battery_id.h>
++#include <linux/notifier.h>
++#include <linux/usb/otg.h>
++#include "power_supply.h"
++#include "power_supply_charger.h"
++
++struct work_struct otg_work;
++#define MAX_CHARGER_COUNT 5
++
++static LIST_HEAD(algo_list);
++
++struct power_supply_charger {
++ bool is_cable_evt_reg;
++ /*cache battery and charger properties */
++ struct list_head chrgr_cache_lst;
++ struct list_head batt_cache_lst;
++ struct list_head evt_queue;
++ struct work_struct algo_trigger_work;
++ struct mutex evt_lock;
++ wait_queue_head_t wait_chrg_enable;
++};
++
++struct charger_cable {
++ struct work_struct work;
++ struct notifier_block nb;
++ struct extcon_chrgr_cbl_props cable_props;
++ enum extcon_cable_name extcon_cable_type;
++ enum power_supply_charger_cable_type psy_cable_type;
++ struct extcon_specific_cable_nb extcon_dev;
++ struct extcon_dev *edev;
++};
++
++static struct power_supply_charger psy_chrgr;
++
++static struct charger_cable cable_list[] = {
++ {
++ .psy_cable_type = POWER_SUPPLY_CHARGER_TYPE_USB_SDP,
++ .extcon_cable_type = EXTCON_SDP,
++ },
++ {
++ .psy_cable_type = POWER_SUPPLY_CHARGER_TYPE_USB_CDP,
++ .extcon_cable_type = EXTCON_CDP,
++ },
++ {
++ .psy_cable_type = POWER_SUPPLY_CHARGER_TYPE_USB_DCP,
++ .extcon_cable_type = EXTCON_DCP,
++ },
++ {
++ .psy_cable_type = POWER_SUPPLY_CHARGER_TYPE_USB_ACA,
++ .extcon_cable_type = EXTCON_ACA,
++ },
++ {
++ .psy_cable_type = POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK,
++ .extcon_cable_type = EXTCON_ACA,
++ },
++ {
++ .psy_cable_type = POWER_SUPPLY_CHARGER_TYPE_SE1,
++ .extcon_cable_type = EXTCON_TA,
++ },
++ {
++ .psy_cable_type = POWER_SUPPLY_CHARGER_TYPE_AC,
++ .extcon_cable_type = EXTCON_AC,
++ },
++};
++
++static int get_supplied_by_list(struct power_supply *psy,
++ struct power_supply *psy_lst[]);
++
++static int otg_handle_notification(struct notifier_block *nb,
++ unsigned long event, void *data);
++struct usb_phy *otg_xceiver;
++struct notifier_block otg_nb = {
++ .notifier_call = otg_handle_notification,
++ };
++static void configure_chrgr_source(struct charger_cable *cable_lst);
++
++struct charger_cable *get_cable(unsigned long usb_chrgr_type)
++{
++
++ switch (usb_chrgr_type) {
++ case POWER_SUPPLY_CHARGER_TYPE_USB_SDP:
++ pr_info("%s:%d SDP\n", __FILE__, __LINE__);
++ return &cable_list[0];
++ case POWER_SUPPLY_CHARGER_TYPE_USB_CDP:
++ pr_info("%s:%d CDP\n", __FILE__, __LINE__);
++ return &cable_list[1];
++ case POWER_SUPPLY_CHARGER_TYPE_USB_DCP:
++ pr_info("%s:%d DCP\n", __FILE__, __LINE__);
++ return &cable_list[2];
++ case POWER_SUPPLY_CHARGER_TYPE_USB_ACA:
++ pr_info("%s:%d ACA\n", __FILE__, __LINE__);
++ return &cable_list[3];
++ case POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK:
++ pr_info("%s:%d ACA DOCK\n", __FILE__, __LINE__);
++ return &cable_list[4];
++ case POWER_SUPPLY_CHARGER_TYPE_AC:
++ pr_info("%s:%d AC\n", __FILE__, __LINE__);
++ return &cable_list[6];
++ case POWER_SUPPLY_CHARGER_TYPE_SE1:
++ pr_info("%s:%d SE1\n", __FILE__, __LINE__);
++ return &cable_list[5];
++ }
++
++ return NULL;
++}
++
++
++static void otg_event_worker(struct work_struct *work)
++{
++ configure_chrgr_source(cable_list);
++
++}
++
++static int process_cable_props(struct power_supply_cable_props *cap)
++{
++
++ struct charger_cable *cable = NULL;
++
++ cable = get_cable(cap->chrg_type);
++ if (!cable) {
++
++ pr_err("%s:%d Error in getting charger cable from get_cable\n",
++ __FILE__, __LINE__);
++ return -EINVAL;
++ }
++
++ switch (cap->chrg_evt) {
++ case POWER_SUPPLY_CHARGER_EVENT_CONNECT:
++ printk(KERN_ERR "%s:%d Connected inlmt=%d\n",
++ __FILE__, __LINE__, cap->mA);
++ cable->cable_props.cable_stat = EXTCON_CHRGR_CABLE_CONNECTED;
++ break;
++ case POWER_SUPPLY_CHARGER_EVENT_UPDATE:
++ printk(KERN_ERR "%s:%d Connected\n", __FILE__, __LINE__);
++ cable->cable_props.cable_stat = EXTCON_CHRGR_CABLE_UPDATED;
++ break;
++ case POWER_SUPPLY_CHARGER_EVENT_DISCONNECT:
++ printk(KERN_ERR "%s:%d Disconnected inlmt=%d\n",
++ __FILE__, __LINE__, cap->mA);
++ cable->cable_props.cable_stat = EXTCON_CHRGR_CABLE_DISCONNECTED;
++ break;
++ case POWER_SUPPLY_CHARGER_EVENT_SUSPEND:
++ printk(KERN_ERR "%s:%d Suspended inlmt=%d\n",
++ __FILE__, __LINE__, cap->mA);
++ cable->cable_props.cable_stat = EXTCON_CHRGR_CABLE_SUSPENDED;
++ break;
++ default:
++ printk(KERN_ERR "%s:%d Invalid event\n", __FILE__, __LINE__);
++ break;
++ }
++
++ cable->cable_props.mA = cap->mA;
++ schedule_work(&otg_work);
++
++ return 0;
++
++}
++
++static int otg_handle_notification(struct notifier_block *nb,
++ unsigned long event, void *data)
++{
++
++ struct power_supply_cable_props *cap;
++
++ cap = (struct power_supply_cable_props *)data;
++
++ if (event != USB_EVENT_CHARGER)
++ return NOTIFY_DONE;
++
++ process_cable_props(cap);
++
++
++ return NOTIFY_OK;
++}
++
++int otg_register(void)
++{
++ int retval;
++
++ otg_xceiver = usb_get_transceiver();
++ if (!otg_xceiver) {
++ pr_err("%s:%d failure to get otg transceiver\n",
++ __FILE__, __LINE__);
++ goto otg_reg_failed;
++ }
++ retval = usb_register_notifier(otg_xceiver, &otg_nb);
++ if (retval) {
++ pr_err("%s:%d failure to register otg notifier\n",
++ __FILE__, __LINE__);
++ goto otg_reg_failed;
++ }
++
++ INIT_WORK(&otg_work, otg_event_worker);
++
++
++ return 0;
++
++otg_reg_failed:
++
++ return -EIO;
++}
++
++static int charger_cable_notifier(struct notifier_block *nb,
++ unsigned long event, void *ptr);
++static void charger_cable_event_worker(struct work_struct *work);
++struct charging_algo *power_supply_get_charging_algo
++ (struct power_supply *, struct ps_batt_chg_prof *);
++
++static void init_charger_cables(struct charger_cable *cable_lst, int count)
++{
++ struct charger_cable *cable;
++ struct extcon_chrgr_cbl_props cable_props;
++ const char *cable_name;
++ struct power_supply_cable_props cap;
++
++ otg_register();
++
++ while (--count) {
++ cable = cable_lst++;
++ /* initialize cable instance */
++ INIT_WORK(&cable->work, charger_cable_event_worker);
++ cable->nb.notifier_call = charger_cable_notifier;
++ cable->cable_props.cable_stat = EXTCON_CHRGR_CABLE_DISCONNECTED;
++ cable->cable_props.mA = 0;
++ cable_name = extcon_cable_name[cable->extcon_cable_type];
++
++ if (extcon_register_interest(&cable->extcon_dev,
++ NULL, cable_name, &cable->nb))
++ continue;
++
++ cable->edev = cable->extcon_dev.edev;
++
++ if (!cable->edev)
++ continue;
++
++ if (cable->edev->get_cable_properties(cable_name,
++ (void *)&cable_props)) {
++ continue;
++
++ } else if (cable_props.cable_stat !=
++ cable->cable_props.cable_stat) {
++ cable->cable_props.cable_stat = cable_props.cable_stat;
++ cable->cable_props.mA = cable_props.mA;
++ }
++ }
++
++ if (!otg_get_chrg_status(otg_xceiver, &cap))
++ process_cable_props(&cap);
++
++}
++
++static inline void get_cur_chrgr_prop(struct power_supply *psy,
++ struct charger_props *chrgr_prop)
++{
++ chrgr_prop->is_charging = IS_CHARGING_ENABLED(psy);
++ chrgr_prop->name = psy->name;
++ chrgr_prop->online = IS_ONLINE(psy);
++ chrgr_prop->present = IS_PRESENT(psy);
++ chrgr_prop->cable = CABLE_TYPE(psy);
++ chrgr_prop->health = HEALTH(psy);
++ chrgr_prop->tstamp = get_jiffies_64();
++
++}
++
++static inline int get_chrgr_prop_cache(struct power_supply *psy,
++ struct charger_props *chrgr_cache)
++{
++
++ struct charger_props *chrgr_prop;
++ int ret = -ENODEV;
++
++ list_for_each_entry(chrgr_prop, &psy_chrgr.chrgr_cache_lst, node) {
++ if (!strcmp(chrgr_prop->name, psy->name)) {
++ memcpy(chrgr_cache, chrgr_prop, sizeof(*chrgr_cache));
++ ret = 0;
++ break;
++ }
++ }
++
++ return ret;
++}
++
++static void dump_charger_props(struct charger_props *props)
++{
++ pr_devel("%s:name=%s present=%d is_charging=%d health=%d online=%d cable=%d tstamp=%d\n",
++ __func__, props->name, props->present, props->is_charging,
++ props->health, props->online, props->cable, props->tstamp);
++}
++
++static void dump_battery_props(struct batt_props *props)
++{
++ pr_devel("%s:name=%s voltage_now=%d current_now=%d temperature=%d status=%d health=%d tstamp=%d algo_stat=%d ",
++ __func__, props->name, props->voltage_now, props->current_now,
++ props->temperature, props->status, props->health,
++ props->tstamp, props->algo_stat);
++}
++
++static inline void cache_chrgr_prop(struct charger_props *chrgr_prop_new)
++{
++
++ struct charger_props *chrgr_cache;
++
++ list_for_each_entry(chrgr_cache, &psy_chrgr.chrgr_cache_lst, node) {
++ if (!strcmp(chrgr_cache->name, chrgr_prop_new->name))
++ goto update_props;
++ }
++
++ chrgr_cache = kzalloc(sizeof(*chrgr_cache), GFP_KERNEL);
++ if (chrgr_cache == NULL) {
++ pr_err("%s:%dError in allocating memory\n", __FILE__, __LINE__);
++ return;
++ }
++
++ INIT_LIST_HEAD(&chrgr_cache->node);
++ list_add_tail(&chrgr_cache->node, &psy_chrgr.chrgr_cache_lst);
++
++ chrgr_cache->name = chrgr_prop_new->name;
++
++update_props:
++ chrgr_cache->is_charging = chrgr_prop_new->is_charging;
++ chrgr_cache->online = chrgr_prop_new->online;
++ chrgr_cache->health = chrgr_prop_new->health;
++ chrgr_cache->present = chrgr_prop_new->present;
++ chrgr_cache->cable = chrgr_prop_new->cable;
++ chrgr_cache->tstamp = chrgr_prop_new->tstamp;
++}
++
++
++static inline bool is_chrgr_prop_changed(struct power_supply *psy)
++{
++
++ struct charger_props chrgr_prop_cache, chrgr_prop;
++
++ get_cur_chrgr_prop(psy, &chrgr_prop);
++ /* Get cached battery property. If no cached property available
++ * then cache the new property and return true
++ */
++ if (get_chrgr_prop_cache(psy, &chrgr_prop_cache)) {
++ cache_chrgr_prop(&chrgr_prop);
++ return true;
++ }
++
++ pr_devel("%s\n", __func__);
++ dump_charger_props(&chrgr_prop);
++ dump_charger_props(&chrgr_prop_cache);
++
++ if (!IS_CHARGER_PROP_CHANGED(chrgr_prop, chrgr_prop_cache))
++ return false;
++
++ cache_chrgr_prop(&chrgr_prop);
++ return true;
++}
++static void cache_successive_samples(long *sample_array, long new_sample)
++{
++
++ int i;
++
++ for (i = 0; i < MAX_CUR_VOLT_SAMPLES - 1; ++i)
++ *(sample_array + i) = *(sample_array + i + 1);
++
++ *(sample_array + i) = new_sample;
++
++}
++
++static inline void cache_bat_prop(struct batt_props *bat_prop_new)
++{
++
++ struct batt_props *bat_cache;
++
++ /* Find entry in cache list. If an entry is located update
++ * the existing entry else create new entry in the list */
++ list_for_each_entry(bat_cache, &psy_chrgr.batt_cache_lst, node) {
++ if (!strcmp(bat_cache->name, bat_prop_new->name))
++ goto update_props;
++ }
++
++ bat_cache = kzalloc(sizeof(*bat_cache), GFP_KERNEL);
++ if (bat_cache == NULL) {
++ pr_err("%s:%dError in allocating memory\n", __FILE__, __LINE__);
++ return;
++ }
++ INIT_LIST_HEAD(&bat_cache->node);
++ list_add_tail(&bat_cache->node, &psy_chrgr.batt_cache_lst);
++
++ bat_cache->name = bat_prop_new->name;
++
++update_props:
++ if (time_after(bat_prop_new->tstamp,
++ (bat_cache->tstamp + DEF_CUR_VOLT_SAMPLE_JIFF)) ||
++ bat_cache->tstamp == 0) {
++ cache_successive_samples(bat_cache->voltage_now_cache,
++ bat_prop_new->voltage_now);
++ cache_successive_samples(bat_cache->current_now_cache,
++ bat_prop_new->current_now);
++ bat_cache->tstamp = bat_prop_new->tstamp;
++ }
++
++ bat_cache->voltage_now = bat_prop_new->voltage_now;
++ bat_cache->current_now = bat_prop_new->current_now;
++ bat_cache->health = bat_prop_new->health;
++
++ bat_cache->temperature = bat_prop_new->temperature;
++ bat_cache->status = bat_prop_new->status;
++ bat_cache->algo_stat = bat_prop_new->algo_stat;
++ bat_cache->throttle_state = bat_prop_new->throttle_state;
++}
++
++static inline int get_bat_prop_cache(struct power_supply *psy,
++ struct batt_props *bat_cache)
++{
++
++ struct batt_props *bat_prop;
++ int ret = -ENODEV;
++
++ list_for_each_entry(bat_prop, &psy_chrgr.batt_cache_lst, node) {
++ if (!strcmp(bat_prop->name, psy->name)) {
++ memcpy(bat_cache, bat_prop, sizeof(*bat_cache));
++ ret = 0;
++ break;
++ }
++ }
++
++ return ret;
++}
++
++static inline void get_cur_bat_prop(struct power_supply *psy,
++ struct batt_props *bat_prop)
++{
++ struct batt_props bat_prop_cache;
++ int ret;
++
++ bat_prop->name = psy->name;
++ bat_prop->voltage_now = VOLTAGE_OCV(psy) / 1000;
++ bat_prop->current_now = CURRENT_NOW(psy) / 1000;
++ bat_prop->temperature = TEMPERATURE(psy) / 10;
++ bat_prop->status = STATUS(psy);
++ bat_prop->health = HEALTH(psy);
++ bat_prop->tstamp = get_jiffies_64();
++ bat_prop->throttle_state = CURRENT_THROTTLE_STATE(psy);
++
++ /* Populate cached algo data to new profile */
++ ret = get_bat_prop_cache(psy, &bat_prop_cache);
++ if (!ret)
++ bat_prop->algo_stat = bat_prop_cache.algo_stat;
++}
++
++static inline bool is_batt_prop_changed(struct power_supply *psy)
++{
++
++ struct batt_props bat_prop_cache, bat_prop;
++
++ /* Get cached battery property. If no cached property available
++ * then cache the new property and return true
++ */
++ get_cur_bat_prop(psy, &bat_prop);
++ if (get_bat_prop_cache(psy, &bat_prop_cache)) {
++ cache_bat_prop(&bat_prop);
++ return true;
++ }
++
++ pr_devel("%s\n", __func__);
++ dump_battery_props(&bat_prop);
++ dump_battery_props(&bat_prop_cache);
++
++ if (!IS_BAT_PROP_CHANGED(bat_prop, bat_prop_cache))
++ return false;
++
++ cache_bat_prop(&bat_prop);
++ return true;
++}
++
++static inline bool is_supplied_to_has_ext_pwr_changed(struct power_supply *psy)
++{
++ int i;
++ struct power_supply *psb;
++ bool is_pwr_changed_defined = true;
++
++ for (i = 0; i < psy->num_supplicants; i++) {
++ psb =
++ power_supply_get_by_name(psy->
++ supplied_to[i]);
++ if (psb && !psb->external_power_changed)
++ is_pwr_changed_defined &= false;
++ }
++
++ return is_pwr_changed_defined;
++
++}
++
++static inline bool is_supplied_by_changed(struct power_supply *psy)
++{
++
++ int cnt;
++ struct power_supply *chrgr_lst[MAX_CHARGER_COUNT];
++
++ cnt = get_supplied_by_list(psy, chrgr_lst);
++ while (cnt--) {
++ if ((IS_CHARGER(chrgr_lst[cnt])) &&
++ is_chrgr_prop_changed(chrgr_lst[cnt]))
++ return true;
++ }
++
++ return false;
++}
++
++static inline bool is_trigger_charging_algo(struct power_supply *psy)
++{
++
++ /* trigger charging alorithm if battery or
++ * charger properties are changed. Also no need to
++ * invoke algorithm for power_supply_changed from
++ * charger, if all supplied_to has the ext_port_changed defined.
++ * On invoking the ext_port_changed the supplied to can send
++ * power_supplied_changed event.
++ */
++
++ if ((IS_CHARGER(psy) && !is_supplied_to_has_ext_pwr_changed(psy)) &&
++ is_chrgr_prop_changed(psy))
++ return true;
++
++ if ((IS_BATTERY(psy)) && (is_batt_prop_changed(psy) ||
++ is_supplied_by_changed(psy)))
++ return true;
++
++ return false;
++}
++
++static int get_supplied_by_list(struct power_supply *psy,
++ struct power_supply *psy_lst[])
++{
++ struct class_dev_iter iter;
++ struct device *dev;
++ struct power_supply *pst;
++ int cnt = 0, i, j;
++
++ if (!IS_BATTERY(psy))
++ return 0;
++
++ /* Identify chargers which are supplying power to the battery */
++ class_dev_iter_init(&iter, power_supply_class, NULL, NULL);
++ while ((dev = class_dev_iter_next(&iter))) {
++ pst = (struct power_supply *)dev_get_drvdata(dev);
++ if (!IS_CHARGER(pst))
++ continue;
++ for (i = 0; i < pst->num_supplicants; i++) {
++ if (!strcmp(pst->supplied_to[i], psy->name))
++ psy_lst[cnt++] = pst;
++ }
++ }
++ class_dev_iter_exit(&iter);
++
++ if (cnt <= 1)
++ return cnt;
++
++ /*sort based on priority. 0 has the highest priority */
++ for (i = 0; i < cnt; ++i)
++ for (j = 0; j < cnt; ++j)
++ if (PRIORITY(psy_lst[j]) > PRIORITY(psy_lst[i]))
++ swap(psy_lst[j], psy_lst[i]);
++
++ return cnt;
++}
++
++static int get_battery_status(struct power_supply *psy)
++{
++ int cnt, status, ret;
++ struct power_supply *chrgr_lst[MAX_CHARGER_COUNT];
++ struct batt_props bat_prop;
++
++ if (!IS_BATTERY(psy))
++ return -EINVAL;
++
++ ret = get_bat_prop_cache(psy, &bat_prop);
++ if (ret)
++ return ret;
++
++ status = POWER_SUPPLY_STATUS_DISCHARGING;
++ cnt = get_supplied_by_list(psy, chrgr_lst);
++
++
++ while (cnt--) {
++
++
++ if (IS_PRESENT(chrgr_lst[cnt]))
++ status = POWER_SUPPLY_STATUS_NOT_CHARGING;
++
++ if (IS_CHARGING_CAN_BE_ENABLED(chrgr_lst[cnt]) &&
++ (IS_HEALTH_GOOD(psy)) &&
++ (IS_HEALTH_GOOD(chrgr_lst[cnt]))) {
++
++ if ((bat_prop.algo_stat == PSY_ALGO_STAT_FULL) ||
++ (bat_prop.algo_stat == PSY_ALGO_STAT_MAINT))
++ status = POWER_SUPPLY_STATUS_FULL;
++ else if (IS_CHARGING_ENABLED(chrgr_lst[cnt]))
++ status = POWER_SUPPLY_STATUS_CHARGING;
++ }
++ }
++ pr_devel("%s: Set status=%d for %s\n", __func__, status, psy->name);
++
++ return status;
++}
++
++static void update_charger_online(struct power_supply *psy)
++{
++ if (IS_CHARGER_ENABLED(psy))
++ set_charger_online(psy, 1);
++ else
++ set_charger_online(psy, 0);
++}
++
++static void update_sysfs(struct power_supply *psy)
++{
++ int i, cnt;
++ struct power_supply *psb;
++ struct power_supply *chrgr_lst[MAX_CHARGER_COUNT];
++
++ if (IS_BATTERY(psy)) {
++ /* set battery status */
++ set_battery_status(psy, get_battery_status(psy));
++
++ /* set charger online */
++ cnt = get_supplied_by_list(psy, chrgr_lst);
++ while (cnt--) {
++ if (!IS_PRESENT(chrgr_lst[cnt]))
++ continue;
++
++ update_charger_online(psy);
++ }
++ } else {
++ /*set battery status */
++ for (i = 0; i < psy->num_supplicants; i++) {
++ psb =
++ power_supply_get_by_name(psy->
++ supplied_to[i]);
++ if (psb && IS_BATTERY(psb) && IS_PRESENT(psb))
++ set_battery_status(psb,
++ get_battery_status(psb));
++ }
++
++ /*set charger online */
++ update_charger_online(psy);
++
++ }
++}
++
++static int trigger_algo(struct power_supply *psy)
++{
++ unsigned long cc = 0, cv = 0, cc_min;
++ struct power_supply *chrgr_lst[MAX_CHARGER_COUNT];
++ struct batt_props bat_prop;
++ struct charging_algo *algo;
++ struct ps_batt_chg_prof chrg_profile;
++ int cnt;
++
++
++ if (psy->type != POWER_SUPPLY_TYPE_BATTERY)
++ return 0;
++
++ if (get_batt_prop(&chrg_profile)) {
++ pr_err("Error in getting charge profile:%s:%d\n", __FILE__,
++ __LINE__);
++ return -EINVAL;
++ }
++
++
++ get_bat_prop_cache(psy, &bat_prop);
++
++ algo = power_supply_get_charging_algo(psy, &chrg_profile);
++ if (!algo) {
++ pr_err("Error in getting charging algo!!\n");
++ return -EINVAL;
++ }
++
++ bat_prop.algo_stat = algo->get_next_cc_cv(bat_prop,
++ chrg_profile, &cc, &cv);
++
++ switch (bat_prop.algo_stat) {
++ case PSY_ALGO_STAT_CHARGE:
++ pr_devel("%s:Algo_status: Charging Enabled\n", __func__);
++ break;
++ case PSY_ALGO_STAT_FULL:
++ pr_devel("%s:Algo_status: Battery is Full\n", __func__);
++ break;
++ case PSY_ALGO_STAT_MAINT:
++ pr_devel("%s:Algo_status: Maintenance charging started\n",
++ __func__);
++ break;
++ case PSY_ALGO_STAT_UNKNOWN:
++ pr_devel("%s:Algo Status: unknown\n", __func__);
++ break;
++ case PSY_ALGO_STAT_NOT_CHARGE:
++ pr_devel("%s:Algo Status: charging not enabled\n",
++ __func__);
++ break;
++ }
++
++ cache_bat_prop(&bat_prop);
++
++ if (!cc || !cv)
++ return -ENODATA;
++
++ /* CC needs to be updated for all chargers which are supplying
++ * power to this battery to ensure that the sum of CCs of all
++ * chargers are never more than the CC selected by the algo.
++ * The CC is set based on the charger priority.
++ */
++ cnt = get_supplied_by_list(psy, chrgr_lst);
++
++ while (cnt--) {
++ if (!IS_PRESENT(chrgr_lst[cnt]))
++ continue;
++
++ cc_min = min_t(unsigned long, MAX_CC(chrgr_lst[cnt]), cc);
++ if (cc_min < 0)
++ cc_min = 0;
++ cc -= cc_min;
++ set_cc(chrgr_lst[cnt], cc_min);
++ set_cv(chrgr_lst[cnt], cv);
++ }
++
++ return 0;
++}
++
++static inline void wait_for_charging_enabled(struct power_supply *psy)
++{
++ wait_event_timeout(psy_chrgr.wait_chrg_enable,
++ (IS_CHARGING_ENABLED(psy)), HZ);
++}
++
++static inline void enable_supplied_by_charging
++ (struct power_supply *psy, bool is_enable)
++{
++ struct power_supply *chrgr_lst[MAX_CHARGER_COUNT];
++ int cnt;
++
++ if (psy->type != POWER_SUPPLY_TYPE_BATTERY)
++ return;
++ /* Get list of chargers supplying power to this battery and
++ * disable charging for all chargers
++ */
++ cnt = get_supplied_by_list(psy, chrgr_lst);
++ if (cnt == 0)
++ return;
++ while (cnt--) {
++ if (!IS_PRESENT(chrgr_lst[cnt]))
++ continue;
++ if (is_enable && IS_CHARGING_CAN_BE_ENABLED(chrgr_lst[cnt])) {
++ enable_charging(chrgr_lst[cnt]);
++ wait_for_charging_enabled(chrgr_lst[cnt]);
++ } else
++ disable_charging(chrgr_lst[cnt]);
++ }
++}
++
++static void __power_supply_trigger_charging_handler(struct power_supply *psy)
++{
++ int i;
++ struct power_supply *psb = NULL;
++
++
++ mutex_lock(&psy_chrgr.evt_lock);
++
++ if (is_trigger_charging_algo(psy)) {
++
++ if (IS_BATTERY(psy)) {
++ if (trigger_algo(psy))
++ enable_supplied_by_charging(psy, false);
++ else
++ enable_supplied_by_charging(psy, true);
++
++ } else if (IS_CHARGER(psy)) {
++ for (i = 0; i < psy->num_supplicants; i++) {
++ psb =
++ power_supply_get_by_name(psy->
++ supplied_to[i]);
++
++ if (psb && IS_BATTERY(psb) && IS_PRESENT(psb)) {
++ if (trigger_algo(psb)) {
++ disable_charging(psy);
++ break;
++ } else if (IS_CHARGING_CAN_BE_ENABLED
++ (psy)) {
++ enable_charging(psy);
++ wait_for_charging_enabled(psy);
++ }
++ }
++ }
++ }
++ update_sysfs(psy);
++ power_supply_changed(psy);
++ }
++ mutex_unlock(&psy_chrgr.evt_lock);
++
++}
++
++static int __trigger_charging_handler(struct device *dev, void *data)
++{
++ struct power_supply *psy = dev_get_drvdata(dev);
++
++
++ __power_supply_trigger_charging_handler(psy);
++
++ return 0;
++}
++
++static void trigger_algo_psy_class(struct work_struct *work)
++{
++
++ class_for_each_device(power_supply_class, NULL, NULL,
++ __trigger_charging_handler);
++
++}
++
++static bool is_cable_connected(void)
++{
++ int i;
++ struct charger_cable *cable;
++
++ for (i = 0; i < ARRAY_SIZE(cable_list); ++i) {
++ cable = cable_list + i;
++ if (IS_CABLE_ACTIVE(cable->cable_props.cable_stat))
++ return true;
++ }
++ return false;
++}
++
++void power_supply_trigger_charging_handler(struct power_supply *psy)
++{
++
++ if (!psy_chrgr.is_cable_evt_reg || !is_cable_connected())
++ return;
++
++ wake_up(&psy_chrgr.wait_chrg_enable);
++
++ if (psy)
++ __power_supply_trigger_charging_handler(psy);
++ else
++ schedule_work(&psy_chrgr.algo_trigger_work);
++
++}
++EXPORT_SYMBOL(power_supply_trigger_charging_handler);
++
++static inline int get_battery_thresholds(struct power_supply *psy,
++ struct psy_batt_thresholds *bat_thresh)
++{
++ struct charging_algo *algo;
++ struct ps_batt_chg_prof chrg_profile;
++
++
++ /* FIXME: Get iterm only for supplied_to arguments*/
++ if (get_batt_prop(&chrg_profile)) {
++ pr_err("Error in getting charge profile:%s:%d\n", __FILE__,
++ __LINE__);
++ return -EINVAL;
++ }
++
++ algo = power_supply_get_charging_algo(psy, &chrg_profile);
++ if (!algo) {
++ pr_err("Error in getting charging algo!!\n");
++ return -EINVAL;
++ }
++
++ if (algo->get_batt_thresholds) {
++ algo->get_batt_thresholds(chrg_profile, bat_thresh);
++ } else {
++ pr_err("Error in getting battery thresholds from %s:%s\n",
++ algo->name, __func__);
++ return -EINVAL;
++ }
++ return 0;
++}
++
++static int select_chrgr_cable(struct device *dev, void *data)
++{
++ struct power_supply *psy = dev_get_drvdata(dev);
++ struct charger_cable *cable, *max_mA_cable = NULL;
++ struct charger_cable *cable_lst = (struct charger_cable *)data;
++ unsigned int max_mA = 0, iterm;
++ int i;
++
++ if (!IS_CHARGER(psy))
++ return 0;
++
++ mutex_lock(&psy_chrgr.evt_lock);
++
++ /* get cable with maximum capability */
++ for (i = 0; i < ARRAY_SIZE(cable_list); ++i) {
++ cable = cable_lst + i;
++ if ((!IS_CABLE_ACTIVE(cable->cable_props.cable_stat)) ||
++ (!IS_SUPPORTED_CABLE(psy, cable->psy_cable_type)))
++ continue;
++
++ if (cable->cable_props.mA > max_mA) {
++ max_mA_cable = cable;
++ max_mA = cable->cable_props.mA;
++ }
++ }
++
++ /* no cable connected. disable charging */
++ if (!max_mA_cable) {
++
++ if ((IS_CHARGER_ENABLED(psy) || IS_CHARGING_ENABLED(psy))) {
++ disable_charging(psy);
++ disable_charger(psy);
++ }
++ set_cc(psy, 0);
++ set_cv(psy, 0);
++ set_inlmt(psy, 0);
++
++ /* set present and online as 0 */
++ set_present(psy, 0);
++ update_charger_online(psy);
++
++ switch_cable(psy, POWER_SUPPLY_CHARGER_TYPE_NONE);
++
++ mutex_unlock(&psy_chrgr.evt_lock);
++ power_supply_changed(psy);
++ return 0;
++ }
++
++ /* cable type changed.New cable connected or existing cable
++ * capabilities changed.switch cable and enable charger and charging
++ */
++ set_present(psy, 1);
++
++ if (CABLE_TYPE(psy) != max_mA_cable->psy_cable_type)
++ switch_cable(psy, max_mA_cable->psy_cable_type);
++
++ if (IS_CHARGER_CAN_BE_ENABLED(psy)) {
++ struct psy_batt_thresholds bat_thresh;
++ memset(&bat_thresh, 0, sizeof(bat_thresh));
++ enable_charger(psy);
++
++ update_charger_online(psy);
++
++ set_inlmt(psy, max_mA_cable->cable_props.mA);
++ if (!get_battery_thresholds(psy, &bat_thresh)) {
++ SET_ITERM(psy, bat_thresh.iterm);
++ SET_MIN_TEMP(psy, bat_thresh.temp_min);
++ SET_MAX_TEMP(psy, bat_thresh.temp_max);
++ }
++
++ } else {
++
++ disable_charger(psy);
++ update_charger_online(psy);
++ }
++
++
++ mutex_unlock(&psy_chrgr.evt_lock);
++ power_supply_trigger_charging_handler(NULL);
++ /* Cable status is same as previous. No action to be taken */
++ return 0;
++
++}
++
++static void configure_chrgr_source(struct charger_cable *cable_lst)
++{
++
++ class_for_each_device(power_supply_class, NULL,
++ cable_lst, select_chrgr_cable);
++
++}
++
++static void charger_cable_event_worker(struct work_struct *work)
++{
++ struct charger_cable *cable =
++ container_of(work, struct charger_cable, work);
++ struct extcon_chrgr_cbl_props cable_props;
++
++ if (cable->edev->
++ get_cable_properties(extcon_cable_name[cable->extcon_cable_type],
++ (void *)&cable_props)) {
++ pr_err("Erron in getting cable(%s) properties from extcon device(%s):%s:%d",
++ extcon_cable_name[cable->extcon_cable_type],
++ cable->edev->name, __FILE__, __LINE__);
++ return;
++ } else {
++ if (cable_props.cable_stat != cable->cable_props.cable_stat) {
++ cable->cable_props.cable_stat = cable_props.cable_stat;
++ cable->cable_props.mA = cable_props.mA;
++ configure_chrgr_source(cable_list);
++ }
++ }
++
++}
++
++static int charger_cable_notifier(struct notifier_block *nb,
++ unsigned long stat, void *ptr)
++{
++
++ struct charger_cable *cable =
++ container_of(nb, struct charger_cable, nb);
++
++ schedule_work(&cable->work);
++
++ return NOTIFY_DONE | NOTIFY_STOP_MASK;
++}
++
++int psy_charger_throttle_charger(struct power_supply *psy,
++ unsigned long state)
++{
++ int ret = 0;
++
++ if (state < 0 || state > MAX_THROTTLE_STATE(psy))
++ return -EINVAL;
++
++ mutex_lock(&psy_chrgr.evt_lock);
++
++ switch THROTTLE_ACTION(psy, state)
++ {
++
++ case PSY_THROTTLE_DISABLE_CHARGER:
++ SET_MAX_CC(psy, 0);
++ disable_charger(psy);
++ break;
++ case PSY_THROTTLE_DISABLE_CHARGING:
++ SET_MAX_CC(psy, 0);
++ disable_charging(psy);
++ break;
++ case PSY_THROTTLE_CC_LIMIT:
++ SET_MAX_CC(psy, THROTTLE_CC_VALUE(psy, state));
++ break;
++ case PSY_THROTTLE_INPUT_LIMIT:
++ set_inlmt(psy, THROTTLE_CC_VALUE(psy, state));
++ break;
++ default:
++ pr_err("Invalid throttle action for %s\n", psy->name);
++ ret = -EINVAL;
++ break;
++ }
++ mutex_unlock(&psy_chrgr.evt_lock);
++
++ /* Configure the driver based on new state */
++ if (!ret)
++ configure_chrgr_source(cable_list);
++ return ret;
++}
++EXPORT_SYMBOL(psy_charger_throttle_charger);
++
++int power_supply_register_charger(struct power_supply *psy)
++{
++ int ret = 0;
++
++ if (!psy_chrgr.is_cable_evt_reg) {
++ mutex_init(&psy_chrgr.evt_lock);
++ init_waitqueue_head(&psy_chrgr.wait_chrg_enable);
++ init_charger_cables(cable_list, ARRAY_SIZE(cable_list));
++ INIT_LIST_HEAD(&psy_chrgr.chrgr_cache_lst);
++ INIT_LIST_HEAD(&psy_chrgr.batt_cache_lst);
++ INIT_WORK(&psy_chrgr.algo_trigger_work, trigger_algo_psy_class);
++ psy_chrgr.is_cable_evt_reg = true;
++ }
++ return ret;
++}
++EXPORT_SYMBOL(power_supply_register_charger);
++
++static inline void flush_charger_context(struct power_supply *psy)
++{
++ struct charger_props *chrgr_prop, *tmp;
++
++
++ list_for_each_entry_safe(chrgr_prop, tmp,
++ &psy_chrgr.chrgr_cache_lst, node) {
++ if (!strcmp(chrgr_prop->name, psy->name)) {
++ list_del(&chrgr_prop->node);
++ kfree(chrgr_prop);
++ }
++ }
++}
++int power_supply_unregister_charger(struct power_supply *psy)
++{
++ flush_charger_context(psy);
++ return 0;
++}
++EXPORT_SYMBOL(power_supply_unregister_charger);
++
++int power_supply_register_charging_algo(struct charging_algo *algo)
++{
++
++ struct charging_algo *algo_new;
++
++ algo_new = kzalloc(sizeof(*algo_new), GFP_KERNEL);
++ if (algo_new == NULL) {
++ pr_err("%s: Error allocating memory for algo!!", __func__);
++ return -1;
++ }
++ memcpy(algo_new, algo, sizeof(*algo_new));
++
++ list_add_tail(&algo_new->node, &algo_list);
++ return 0;
++}
++EXPORT_SYMBOL(power_supply_register_charging_algo);
++
++int power_supply_unregister_charging_algo(struct charging_algo *algo)
++{
++ struct charging_algo *algo_l, *tmp;
++
++ list_for_each_entry_safe(algo_l, tmp, &algo_list, node) {
++ if (!strcmp(algo_l->name, algo->name)) {
++ list_del(&algo_l->node);
++ kfree(algo_l);
++ }
++ }
++ return 0;
++
++}
++EXPORT_SYMBOL(power_supply_unregister_charging_algo);
++
++static struct charging_algo *get_charging_algo_byname(char *algo_name)
++{
++ struct charging_algo *algo;
++
++ list_for_each_entry(algo, &algo_list, node) {
++ if (!strcmp(algo->name, algo_name))
++ return algo;
++ }
++
++ return NULL;
++}
++
++static struct charging_algo *get_charging_algo_by_type
++ (enum batt_chrg_prof_type chrg_prof_type)
++{
++ struct charging_algo *algo;
++
++ list_for_each_entry(algo, &algo_list, node) {
++ if (algo->chrg_prof_type == chrg_prof_type)
++ return algo;
++ }
++
++ return NULL;
++}
++
++struct charging_algo *power_supply_get_charging_algo
++ (struct power_supply *psy, struct ps_batt_chg_prof *batt_prof)
++{
++
++ return get_charging_algo_by_type(batt_prof->chrg_prof_type);
++
++}
++EXPORT_SYMBOL_GPL(power_supply_get_charging_algo);
+diff --git a/drivers/power/power_supply_charger.h b/drivers/power/power_supply_charger.h
+new file mode 100644
+index 0000000..81324a4
+--- /dev/null
++++ b/drivers/power/power_supply_charger.h
+@@ -0,0 +1,244 @@
++
++#ifndef __POWER_SUPPLY_CHARGER_H__
++
++#define __POWER_SUPPLY_CHARGER_H__
++#include <linux/power/battery_id.h>
++#include <linux/power_supply.h>
++
++#define MAX_CUR_VOLT_SAMPLES 3
++#define DEF_CUR_VOLT_SAMPLE_JIFF (30*HZ)
++
++enum psy_algo_stat {
++ PSY_ALGO_STAT_UNKNOWN,
++ PSY_ALGO_STAT_NOT_CHARGE,
++ PSY_ALGO_STAT_CHARGE,
++ PSY_ALGO_STAT_FULL,
++ PSY_ALGO_STAT_MAINT,
++};
++
++struct batt_props {
++ struct list_head node;
++ const char *name;
++ long voltage_now;
++ long voltage_now_cache[MAX_CUR_VOLT_SAMPLES];
++ long current_now;
++ long current_now_cache[MAX_CUR_VOLT_SAMPLES];
++ int temperature;
++ long status;
++ unsigned long tstamp;
++ enum psy_algo_stat algo_stat;
++ int health;
++ int throttle_state;
++};
++
++struct charger_props {
++ struct list_head node;
++ const char *name;
++ bool present;
++ bool is_charging;
++ int health;
++ bool online;
++ unsigned long cable;
++ unsigned long tstamp;
++};
++
++struct psy_batt_thresholds {
++ int temp_min;
++ int temp_max;
++ unsigned int iterm;
++};
++
++struct charging_algo {
++ struct list_head node;
++ unsigned int chrg_prof_type;
++ char *name;
++ enum psy_algo_stat (*get_next_cc_cv)(struct batt_props,
++ struct ps_batt_chg_prof, unsigned long *cc,
++ unsigned long *cv);
++ int (*get_batt_thresholds)(struct ps_batt_chg_prof,
++ struct psy_batt_thresholds *bat_thr);
++};
++
++
++extern int power_supply_register_charging_algo(struct charging_algo *);
++extern int power_supply_unregister_charging_algo(struct charging_algo *);
++
++static inline int set_ps_int_property(struct power_supply *psy,
++ enum power_supply_property psp,
++ int prop_val)
++{
++
++ union power_supply_propval val;
++
++ val.intval = prop_val;
++ return psy->set_property(psy, psp, &val);
++}
++
++static inline int get_ps_int_property(struct power_supply *psy,
++ enum power_supply_property psp)
++{
++ union power_supply_propval val;
++
++ val.intval = 0;
++
++ psy->get_property(psy, psp, &val);
++ return val.intval;
++}
++/* Define a TTL for some properies to optimize the frequency of
++* algorithm calls. This can be used by properties which will be changed
++* very frequently (eg. current, volatge..)
++*/
++#define PROP_TTL (HZ*10)
++#define enable_charging(psy) \
++ ({if ((CABLE_TYPE(psy) != POWER_SUPPLY_CHARGER_TYPE_NONE) &&\
++ !IS_CHARGING_ENABLED(psy)) { \
++ enable_charger(psy); \
++ set_ps_int_property(psy, POWER_SUPPLY_PROP_ENABLE_CHARGING,\
++ true); } })
++#define disable_charging(psy) \
++ set_ps_int_property(psy,\
++ POWER_SUPPLY_PROP_ENABLE_CHARGING, false);
++
++#define enable_charger(psy) \
++ set_ps_int_property(psy, POWER_SUPPLY_PROP_ENABLE_CHARGER, true)
++#define disable_charger(psy) \
++ ({ disable_charging(psy); \
++ set_ps_int_property(psy,\
++ POWER_SUPPLY_PROP_ENABLE_CHARGER, false); })
++
++#define set_cc(psy, cc) \
++ set_ps_int_property(psy, POWER_SUPPLY_PROP_CHARGE_CURRENT, cc)
++
++#define set_cv(psy, cv) \
++ set_ps_int_property(psy, POWER_SUPPLY_PROP_CHARGE_VOLTAGE, cv)
++
++#define set_inlmt(psy, inlmt) \
++ set_ps_int_property(psy, POWER_SUPPLY_PROP_INLMT, inlmt)
++
++#define set_present(psy, present) \
++ set_ps_int_property(psy, POWER_SUPPLY_PROP_PRESENT, present)
++
++#define SET_MAX_CC(psy, max_cc) \
++ set_ps_int_property(psy,\
++ POWER_SUPPLY_PROP_MAX_CHARGE_CURRENT, max_cc)
++#define SET_ITERM(psy, iterm) \
++ set_ps_int_property(psy,\
++ POWER_SUPPLY_PROP_CHARGE_TERM_CUR, iterm)
++#define SET_MAX_TEMP(psy, temp) \
++ set_ps_int_property(psy,\
++ POWER_SUPPLY_PROP_MAX_TEMP, temp)
++#define SET_MIN_TEMP(psy, temp) \
++ set_ps_int_property(psy,\
++ POWER_SUPPLY_PROP_MIN_TEMP, temp)
++#define switch_cable(psy, new_cable) \
++ set_ps_int_property(psy,\
++ POWER_SUPPLY_PROP_CABLE_TYPE, new_cable)
++
++#define HEALTH(psy) \
++ get_ps_int_property(psy, POWER_SUPPLY_PROP_HEALTH)
++#define CV(psy) \
++ get_ps_int_property(psy, POWER_SUPPLY_PROP_CHARGE_VOLTAGE)
++#define CC(psy) \
++ get_ps_int_property(psy, POWER_SUPPLY_PROP_CHARGE_CURRENT)
++#define INLMT(psy) \
++ get_ps_int_property(psy, POWER_SUPPLY_PROP_INLMT)
++#define MAX_CC(psy) \
++ get_ps_int_property(psy, POWER_SUPPLY_PROP_MAX_CHARGE_CURRENT)
++#define MAX_CV(psy) \
++ get_ps_int_property(psy, POWER_SUPPLY_PROP_MAX_CHARGE_VOLTAGE)
++#define VOLTAGE_NOW(psy) \
++ get_ps_int_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW)
++#define VOLTAGE_OCV(psy) \
++ get_ps_int_property(psy, POWER_SUPPLY_PROP_VOLTAGE_OCV)
++#define CURRENT_NOW(psy) \
++ get_ps_int_property(psy, POWER_SUPPLY_PROP_CURRENT_NOW)
++#define STATUS(psy) \
++ get_ps_int_property(psy, POWER_SUPPLY_PROP_STATUS)
++#define TEMPERATURE(psy) \
++ get_ps_int_property(psy, POWER_SUPPLY_PROP_TEMP)
++#define BATTERY_TYPE(psy) \
++ get_ps_int_property(psy, POWER_SUPPLY_PROP_TECHNOLOGY)
++#define PRIORITY(psy) \
++ get_ps_int_property(psy, POWER_SUPPLY_PROP_PRIORITY)
++#define CABLE_TYPE(psy) \
++ get_ps_int_property(psy, POWER_SUPPLY_PROP_CABLE_TYPE)
++#define ONLINE(psy) \
++ get_ps_int_property(psy, POWER_SUPPLY_PROP_ONLINE)
++
++#define IS_CHARGING_ENABLED(psy) \
++ get_ps_int_property(psy, POWER_SUPPLY_PROP_ENABLE_CHARGING)
++#define IS_CHARGER_ENABLED(psy) \
++ get_ps_int_property(psy, POWER_SUPPLY_PROP_ENABLE_CHARGER)
++#define IS_BATTERY(psy) (psy->type == POWER_SUPPLY_TYPE_BATTERY)
++#define IS_CHARGER(psy) (psy->type == POWER_SUPPLY_TYPE_USB ||\
++ psy->type == POWER_SUPPLY_TYPE_USB_CDP || \
++ psy->type == POWER_SUPPLY_TYPE_USB_DCP ||\
++ psy->type == POWER_SUPPLY_TYPE_USB_ACA)
++#define IS_ONLINE(psy) \
++ (get_ps_int_property(psy, POWER_SUPPLY_PROP_ONLINE) == 1)
++#define IS_PRESENT(psy) \
++ (get_ps_int_property(psy, POWER_SUPPLY_PROP_PRESENT) == 1)
++#define IS_SUPPORTED_CABLE(psy, cable_type) \
++ (psy->supported_cables & cable_type)
++#define IS_CABLE_ACTIVE(status) \
++ (!((status == EXTCON_CHRGR_CABLE_DISCONNECTED) ||\
++ (status == EXTCON_CHRGR_CABLE_SUSPENDED)))
++
++#define IS_CHARGER_PROP_CHANGED(prop, cache_prop)\
++ ((cache_prop.online != prop.online) || \
++ (cache_prop.present != prop.present) || \
++ (cache_prop.is_charging != prop.is_charging) || \
++ (cache_prop.health != prop.health))
++
++#define IS_BAT_PROP_CHANGED(bat_prop, bat_cache)\
++ ((bat_cache.voltage_now != bat_prop.voltage_now) || \
++ (time_after64(bat_prop.tstamp, (bat_cache.tstamp + PROP_TTL)) &&\
++ ((bat_cache.current_now != bat_prop.current_now) || \
++ (bat_cache.voltage_now != bat_prop.voltage_now))) || \
++ (bat_cache.temperature != bat_prop.temperature) || \
++ (bat_cache.health != bat_prop.health) || \
++ (bat_cache.throttle_state != bat_prop.throttle_state))
++
++#define THROTTLE_ACTION(psy, state)\
++ (((psy->throttle_states)+state)->throttle_action)
++
++#define MAX_THROTTLE_STATE(psy)\
++ ((psy->num_throttle_states))
++
++#define CURRENT_THROTTLE_STATE(psy)\
++ (get_ps_int_property(psy,\
++ POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT))
++
++#define CURRENT_THROTTLE_ACTION(psy)\
++ THROTTLE_ACTION(psy, CURRENT_THROTTLE_STATE(psy))
++
++#define THROTTLE_CC_VALUE(psy, state)\
++ (((psy->throttle_states)+state)->throttle_val)
++
++#define IS_CHARGING_CAN_BE_ENABLED(psy) \
++ ((CURRENT_THROTTLE_ACTION(psy) != PSY_THROTTLE_DISABLE_CHARGER) &&\
++ (CURRENT_THROTTLE_ACTION(psy) != PSY_THROTTLE_DISABLE_CHARGING))
++#define IS_CHARGER_CAN_BE_ENABLED(psy) \
++ (CURRENT_THROTTLE_ACTION(psy) != PSY_THROTTLE_DISABLE_CHARGER)
++
++#define IS_HEALTH_GOOD(psy)\
++ (HEALTH(psy) == POWER_SUPPLY_HEALTH_GOOD)
++
++static inline void set_battery_status(struct power_supply *psy, int status)
++{
++
++ if (STATUS(psy) != status)
++ set_ps_int_property(psy, POWER_SUPPLY_PROP_STATUS, status);
++
++
++}
++
++static inline void set_charger_online(struct power_supply *psy, int online)
++{
++
++ if (ONLINE(psy) != online)
++ set_ps_int_property(psy, POWER_SUPPLY_PROP_ONLINE, online);
++
++}
++
++#endif
+diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
+index 1c517c3..dafad50 100644
+--- a/drivers/power/power_supply_core.c
++++ b/drivers/power/power_supply_core.c
+@@ -19,6 +19,7 @@
+ #include <linux/power_supply.h>
+ #include <linux/thermal.h>
+ #include "power_supply.h"
++#include "power_supply_charger.h"
+
+ /* exported for the APM Power driver, APM emulation */
+ struct class *power_supply_class;
+@@ -26,6 +27,13 @@ EXPORT_SYMBOL_GPL(power_supply_class);
+
+ static struct device_type power_supply_dev_type;
+
++static struct mutex ps_chrg_evt_lock;
++
++static struct power_supply_charger_cap power_supply_chrg_cap = {
++ .chrg_evt = POWER_SUPPLY_CHARGER_EVENT_DISCONNECT,
++ .chrg_type = POWER_SUPPLY_TYPE_USB,
++ .mA = 0 /* 0 mA */
++};
+ static bool __power_supply_is_supplied_by(struct power_supply *supplier,
+ struct power_supply *supply)
+ {
+@@ -75,6 +83,11 @@ static void power_supply_changed_work(struct work_struct *work)
+ class_for_each_device(power_supply_class, NULL, psy,
+ __power_supply_changed_work);
+
++ class_for_each_device(power_supply_class, NULL, psy,
++ __power_supply_changed_work);
++
++ power_supply_trigger_charging_handler(psy);
++
+ power_supply_update_leds(psy);
+
+ kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);
+@@ -82,12 +95,50 @@ static void power_supply_changed_work(struct work_struct *work)
+
+ void power_supply_changed(struct power_supply *psy)
+ {
++ unsigned long flags;
++
++ if (psy == NULL) {
++ power_supply_trigger_charging_handler(psy);
++ return;
++ }
++
+ dev_dbg(psy->dev, "%s\n", __func__);
+
+ schedule_work(&psy->changed_work);
+ }
+ EXPORT_SYMBOL_GPL(power_supply_changed);
+
++static int __power_supply_charger_event(struct device *dev, void *data)
++{
++ struct power_supply_charger_cap *cap =
++ (struct power_supply_charger_cap *)data;
++ struct power_supply *psy = dev_get_drvdata(dev);
++
++ if (psy->charging_port_changed)
++ psy->charging_port_changed(psy, cap);
++
++ return 0;
++}
++
++void power_supply_charger_event(struct power_supply_charger_cap cap)
++{
++ class_for_each_device(power_supply_class, NULL, &cap,
++ __power_supply_charger_event);
++
++ mutex_lock(&ps_chrg_evt_lock);
++ memcpy(&power_supply_chrg_cap, &cap, sizeof(power_supply_chrg_cap));
++ mutex_unlock(&ps_chrg_evt_lock);
++}
++EXPORT_SYMBOL_GPL(power_supply_charger_event);
++
++void power_supply_query_charger_caps(struct power_supply_charger_cap *cap)
++{
++ mutex_lock(&ps_chrg_evt_lock);
++ memcpy(cap, &power_supply_chrg_cap, sizeof(power_supply_chrg_cap));
++ mutex_unlock(&ps_chrg_evt_lock);
++}
++EXPORT_SYMBOL_GPL(power_supply_query_charger_caps);
++
+ #ifdef CONFIG_OF
+ #include <linux/of.h>
+
+@@ -271,12 +322,12 @@ int power_supply_is_system_supplied(void)
+ unsigned int count = 0;
+
+ error = class_for_each_device(power_supply_class, NULL, &count,
+- __power_supply_is_system_supplied);
++ __power_supply_is_system_supplied);
+
+ /*
+- * If no power class device was found at all, most probably we are
+- * running on a desktop system, so assume we are on mains power.
+- */
++ * If no power class device was found at all, most probably we are
++ * running on a desktop system, so assume we are on mains power.
++ */
+ if (count == 0)
+ return 1;
+
+@@ -284,6 +335,30 @@ int power_supply_is_system_supplied(void)
+ }
+ EXPORT_SYMBOL_GPL(power_supply_is_system_supplied);
+
++static int __power_supply_is_battery_connected(struct device *dev, void *data)
++{
++ union power_supply_propval ret = {0,};
++ struct power_supply *psy = dev_get_drvdata(dev);
++
++ if (psy->type == POWER_SUPPLY_TYPE_BATTERY) {
++ if (psy->get_property(psy, POWER_SUPPLY_PROP_PRESENT, &ret))
++ return 0;
++ if (ret.intval)
++ return ret.intval;
++ }
++ return 0;
++}
++
++int power_supply_is_battery_connected(void)
++{
++ int error;
++
++ error = class_for_each_device(power_supply_class, NULL, NULL,
++ __power_supply_is_battery_connected);
++ return error;
++}
++EXPORT_SYMBOL_GPL(power_supply_is_battery_connected);
++
+ int power_supply_set_battery_charged(struct power_supply *psy)
+ {
+ if (psy->type == POWER_SUPPLY_TYPE_BATTERY && psy->set_charged) {
+@@ -332,7 +407,8 @@ static int power_supply_read_temp(struct thermal_zone_device *tzd,
+ union power_supply_propval val;
+ int ret;
+
+- WARN_ON(tzd == NULL);
++ if (WARN_ON(tzd == NULL))
++ return -EINVAL;
+ psy = tzd->devdata;
+ ret = psy->get_property(psy, POWER_SUPPLY_PROP_TEMP, &val);
+
+@@ -379,6 +455,8 @@ static int ps_get_max_charge_cntl_limit(struct thermal_cooling_device *tcd,
+ union power_supply_propval val;
+ int ret;
+
++ if (WARN_ON(tcd == NULL))
++ return -EINVAL;
+ psy = tcd->devdata;
+ ret = psy->get_property(psy,
+ POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, &val);
+@@ -395,6 +473,8 @@ static int ps_get_cur_chrage_cntl_limit(struct thermal_cooling_device *tcd,
+ union power_supply_propval val;
+ int ret;
+
++ if (WARN_ON(tcd == NULL))
++ return -EINVAL;
+ psy = tcd->devdata;
+ ret = psy->get_property(psy,
+ POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, &val);
+@@ -411,11 +491,15 @@ static int ps_set_cur_charge_cntl_limit(struct thermal_cooling_device *tcd,
+ union power_supply_propval val;
+ int ret;
+
++ if (WARN_ON(tcd == NULL))
++ return -EINVAL;
+ psy = tcd->devdata;
+ val.intval = state;
+ ret = psy->set_property(psy,
+ POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, &val);
+
++ psy_charger_throttle_charger(psy, state);
++
+ return ret;
+ }
+
+@@ -516,10 +600,16 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
+ if (rc)
+ goto create_triggers_failed;
+
++ if (IS_CHARGER(psy))
++ rc = power_supply_register_charger(psy);
++ if (rc)
++ goto charger_register_failed;
++
+ power_supply_changed(psy);
+
+ goto success;
+
++charger_register_failed:
+ create_triggers_failed:
+ psy_unregister_cooler(psy);
+ register_cooler_failed:
+@@ -540,6 +630,9 @@ void power_supply_unregister(struct power_supply *psy)
+ cancel_work_sync(&psy->changed_work);
+ sysfs_remove_link(&psy->dev->kobj, "powers");
+ power_supply_remove_triggers(psy);
++ if (IS_CHARGER(psy))
++ power_supply_unregister_charger(psy);
++ power_supply_remove_triggers(psy);
+ psy_unregister_cooler(psy);
+ psy_unregister_thermal(psy);
+ device_unregister(psy->dev);
+@@ -555,6 +648,7 @@ static int __init power_supply_class_init(void)
+
+ power_supply_class->dev_uevent = power_supply_uevent;
+ power_supply_init_attrs(&power_supply_dev_type);
++ mutex_init(&ps_chrg_evt_lock);
+
+ return 0;
+ }
+diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
+index 29178f7..66f1c5c 100644
+--- a/drivers/power/power_supply_sysfs.c
++++ b/drivers/power/power_supply_sysfs.c
+@@ -44,7 +44,7 @@ static ssize_t power_supply_show_property(struct device *dev,
+ struct device_attribute *attr,
+ char *buf) {
+ static char *type_text[] = {
+- "Unknown", "Battery", "UPS", "Mains", "USB",
++ "Unknown", "Battery", "UPS", "Mains", "USB", "USB",
+ "USB_DCP", "USB_CDP", "USB_ACA"
+ };
+ static char *status_text[] = {
+@@ -165,8 +165,14 @@ static struct device_attribute power_supply_attrs[] = {
+ POWER_SUPPLY_ATTR(constant_charge_current_max),
+ POWER_SUPPLY_ATTR(constant_charge_voltage),
+ POWER_SUPPLY_ATTR(constant_charge_voltage_max),
++ POWER_SUPPLY_ATTR(charge_current_limit),
+ POWER_SUPPLY_ATTR(charge_control_limit),
+ POWER_SUPPLY_ATTR(charge_control_limit_max),
++ POWER_SUPPLY_ATTR(charge_current),
++ POWER_SUPPLY_ATTR(max_charge_current),
++ POWER_SUPPLY_ATTR(charge_voltage),
++ POWER_SUPPLY_ATTR(max_charge_voltage),
++ POWER_SUPPLY_ATTR(input_cur_limit),
+ POWER_SUPPLY_ATTR(energy_full_design),
+ POWER_SUPPLY_ATTR(energy_empty_design),
+ POWER_SUPPLY_ATTR(energy_full),
+@@ -180,6 +186,8 @@ static struct device_attribute power_supply_attrs[] = {
+ POWER_SUPPLY_ATTR(temp),
+ POWER_SUPPLY_ATTR(temp_alert_min),
+ POWER_SUPPLY_ATTR(temp_alert_max),
++ POWER_SUPPLY_ATTR(max_temp),
++ POWER_SUPPLY_ATTR(min_temp),
+ POWER_SUPPLY_ATTR(temp_ambient),
+ POWER_SUPPLY_ATTR(temp_ambient_alert_min),
+ POWER_SUPPLY_ATTR(temp_ambient_alert_max),
+@@ -188,6 +196,11 @@ static struct device_attribute power_supply_attrs[] = {
+ POWER_SUPPLY_ATTR(time_to_full_now),
+ POWER_SUPPLY_ATTR(time_to_full_avg),
+ POWER_SUPPLY_ATTR(type),
++ POWER_SUPPLY_ATTR(charge_term_cur),
++ POWER_SUPPLY_ATTR(enable_charging),
++ POWER_SUPPLY_ATTR(enable_charger),
++ POWER_SUPPLY_ATTR(cable_type),
++ POWER_SUPPLY_ATTR(priority),
+ POWER_SUPPLY_ATTR(scope),
+ /* Properties of type `const char *' */
+ POWER_SUPPLY_ATTR(model_name),
+diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
+index 115b644..28c0b10 100644
+--- a/drivers/pwm/Kconfig
++++ b/drivers/pwm/Kconfig
+@@ -28,6 +28,10 @@ menuconfig PWM
+
+ if PWM
+
++config PWM_SYSFS
++ bool
++ default y if SYSFS
++
+ config PWM_AB8500
+ tristate "AB8500 PWM support"
+ depends on AB8500_CORE && ARCH_U8500
+@@ -201,4 +205,13 @@ config PWM_VT8500
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-vt8500.
+
++config PWM_INTEL_MID
++ tristate "Support for Intel MID PWM"
++ help
++ This option enables support for Intel Mid PWM Driver. Say Y
++ here if you want to enable the PWM functionality.
++
++ To compile this driver as a module, choose M here. The module will
++ be called pwm-intel-mid.
++
+ endif
+diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
+index 94ba21e..b802906 100644
+--- a/drivers/pwm/Makefile
++++ b/drivers/pwm/Makefile
+@@ -1,4 +1,5 @@
+ obj-$(CONFIG_PWM) += core.o
++obj-$(CONFIG_PWM_SYSFS) += sysfs.o
+ obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o
+ obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o
+ obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
+@@ -17,3 +18,4 @@ obj-$(CONFIG_PWM_TIPWMSS) += pwm-tipwmss.o
+ obj-$(CONFIG_PWM_TWL) += pwm-twl.o
+ obj-$(CONFIG_PWM_TWL_LED) += pwm-twl-led.o
+ obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o
++obj-$(CONFIG_PWM_INTEL_MID) += pwm-intel-mid.o
+diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
+index 32221cb..9e9f5b8 100644
+--- a/drivers/pwm/core.c
++++ b/drivers/pwm/core.c
+@@ -274,6 +274,8 @@ int pwmchip_add(struct pwm_chip *chip)
+ if (IS_ENABLED(CONFIG_OF))
+ of_pwmchip_add(chip);
+
++ pwmchip_sysfs_export(chip);
++
+ out:
+ mutex_unlock(&pwm_lock);
+ return ret;
+@@ -310,6 +312,8 @@ int pwmchip_remove(struct pwm_chip *chip)
+
+ free_pwms(chip);
+
++ pwmchip_sysfs_unexport(chip);
++
+ out:
+ mutex_unlock(&pwm_lock);
+ return ret;
+@@ -402,10 +406,19 @@ EXPORT_SYMBOL_GPL(pwm_free);
+ */
+ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+ {
++ int err;
++
+ if (!pwm || duty_ns < 0 || period_ns <= 0 || duty_ns > period_ns)
+ return -EINVAL;
+
+- return pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns);
++ err = pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns);
++ if (err)
++ return err;
++
++ pwm->duty_cycle = duty_ns;
++ pwm->period = period_ns;
++
++ return 0;
+ }
+ EXPORT_SYMBOL_GPL(pwm_config);
+
+@@ -418,6 +431,8 @@ EXPORT_SYMBOL_GPL(pwm_config);
+ */
+ int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)
+ {
++ int err;
++
+ if (!pwm || !pwm->chip->ops)
+ return -EINVAL;
+
+@@ -427,7 +442,13 @@ int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)
+ if (test_bit(PWMF_ENABLED, &pwm->flags))
+ return -EBUSY;
+
+- return pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity);
++ err = pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity);
++ if (err)
++ return err;
++
++ pwm->polarity = polarity;
++
++ return 0;
+ }
+ EXPORT_SYMBOL_GPL(pwm_set_polarity);
+
+diff --git a/drivers/pwm/pwm-intel-mid.c b/drivers/pwm/pwm-intel-mid.c
+new file mode 100644
+index 0000000..5564a1b
+--- /dev/null
++++ b/drivers/pwm/pwm-intel-mid.c
+@@ -0,0 +1,405 @@
++/*
++ * pwm-intel-mid.c: Driver for PWM on Intel MID platform
++ *
++ * (C) Copyright 2014 Intel Corporation
++ * Author: Nicolas Pernas Maradei <nicolas.pernas.maradei@emutex.com>
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/device.h>
++#include <linux/module.h>
++#include <linux/pwm.h>
++#include <linux/pci.h>
++#include <linux/pm_runtime.h>
++
++#define PWM_INTEL_MID_DRIVER_NAME "pwm-intel-mid"
++#define PCI_DEVICE_ID_INTEL_MID_MRFLD 0x11a5
++#define CLOCK_RATE 19200000
++#define BASE_10 10
++#define NSECS_PER_SEC 1000000000UL
++#define PWM_PERIOD_NS_MAX 218453000 /* about 4.6 Hz */
++#define PWM_PERIOD_NS_MIN 104 /* about 9.6 MHz */
++#define PWM_ON_TIME_DIVISOR_BITS 8
++#define PWM_BASE_UNIT_FRAC_BITS 14
++#define PWM_BASE_UNIT_INT_BITS 8
++#define PWM_COMPARE_UNIT_SIZE 256UL
++#define PWM_DYNAMYC_RANGE_DEFAULT 100UL
++#define PWM_DYNAMYC_RANGE_THRESHOLD 13333
++#define PWM_DEFAULT_PERIOD 4950495 /* about 200 Hz */
++#define PWM_CONTROL_REGISTER_SIZE 0x400
++
++#define get_control_register(pwm, pwm_id) \
++ ((u8 *)pwm->regs + (pwm_id * PWM_CONTROL_REGISTER_SIZE));
++
++union pwmctrl_reg {
++ struct {
++ u32 on_time_divisor:PWM_ON_TIME_DIVISOR_BITS;
++ u32 base_unit_frac:PWM_BASE_UNIT_FRAC_BITS;
++ u32 base_unit_int:PWM_BASE_UNIT_INT_BITS;
++ u32 sw_update:1;
++ u32 enable:1;
++ } part;
++ u32 full;
++};
++
++struct intel_mid_pwm_chip {
++ struct pwm_chip chip;
++ void __iomem *regs;
++ union pwmctrl_reg *pwmctrls;
++ int num_of_pwms;
++};
++
++static inline struct intel_mid_pwm_chip *
++to_pwm(struct pwm_chip *chip)
++{
++ return container_of(chip, struct intel_mid_pwm_chip, chip);
++}
++
++static inline void
++pwm_set_enable_bit(void __iomem *reg, union pwmctrl_reg *pwmctrl, u8 value)
++{
++ pwmctrl->full = readl(reg);
++ pwmctrl->part.enable = value;
++ writel(pwmctrl->full, reg);
++}
++
++static void
++intel_mid_pwm_on_time_divisor(void __iomem *reg, union pwmctrl_reg *pwmctrl,
++ const u32 period, const u32 duty_cycle)
++{
++ u64 on_time_divisor;
++
++ /* Calculate and set on time divisor */
++ if (duty_cycle == period) {
++ on_time_divisor = 1UL;
++ } else {
++ on_time_divisor = duty_cycle *
++ (u64)(PWM_COMPARE_UNIT_SIZE - 1UL);
++ do_div(on_time_divisor, period);
++ on_time_divisor = PWM_COMPARE_UNIT_SIZE -
++ on_time_divisor - 1UL;
++ }
++
++ pwmctrl->full = readl(reg);
++ pwmctrl->part.on_time_divisor = on_time_divisor;
++ writel(pwmctrl->full, reg);
++}
++
++static int
++intel_mid_pwm_base_unit(void __iomem *reg, union pwmctrl_reg *pwmctrl,
++ const u32 period, const u32 clock_rate)
++{
++ u32 dynamic_range = PWM_DYNAMYC_RANGE_DEFAULT;
++ u64 rest;
++ u64 tmp;
++ u64 fraction = 0;
++ u64 numerator = 1;
++ u64 base_unit_integer;
++ u64 frequency = NSECS_PER_SEC;
++ u32 base_unit_fraction = 0;
++ int i;
++
++ /* The dynamic range multiplier is used to get more accurate
++ calculations when the frequency is small (less than 75 KHz) in the
++ fraction part of base unit. In some way when requesting low frequencies
++ all calculations are done using the period in nano-secs e-2. For high
++ frecuencies we use nano-secs only. */
++ if (period < PWM_DYNAMYC_RANGE_THRESHOLD)
++ dynamic_range = 1UL;
++ frequency *= dynamic_range;
++
++ /* calculate frequency: f (hz) = 1e9 (ns/ps) / p (ns/ps). Result is in
++ Hz depending on dynamic_range being 1. */
++ do_div(frequency, period);
++
++ /* base_unit is a 22 bits register composed of a fractional part (first
++ 14 bits) and an integer part (next 8 bits). The integer part
++ calculation is trivial. Done in place by do_div() below. */
++ base_unit_integer = frequency * PWM_COMPARE_UNIT_SIZE;
++
++ rest = do_div(base_unit_integer, clock_rate * dynamic_range);
++
++ /* The fractional part of base_unit needs to be calculated and converted
++ to binary fixed point notation. Two steps will be needed to do the
++ calculation. First to calculate the fraction part in decimal and
++ secondly to convert it to binary fixed point. Due to lack of float
++ support in the kernel we'll use the rest of (frequency *
++ PWM_COMPARE_UNIT_SIZE / clock_speed) division to calculate it and then
++ following the standard division algorithm the rest will be multiplied
++ by 10 and divided by clock_rate several times until the desired level
++ of precision is reached. At the end it will look like this:
++ base_unit_fraction = fraction / numerator where numerator is a power
++ of 10.
++
++ E.g.: base_unit = 1.123, base_unit_fraction = 0.123,
++ fraction = 123, numerator = 1000 */
++ for (i = 0; i < PWM_BASE_UNIT_FRAC_BITS; i++) {
++ tmp = rest * BASE_10;
++ rest = do_div(tmp, clock_rate * dynamic_range);
++ fraction += tmp;
++ fraction *= BASE_10;
++ numerator *= BASE_10;
++ }
++ do_div(fraction, BASE_10);
++
++ /* At this point we've got the fraction and numerator done following
++ the above description. The binary fixed point conversion is done by
++ repeated multiplications of the fraction (but using fractions (fra/num)
++ instead of floats). When the fraction is multipled by 2 and gets greater
++ or equal than 1 (or in our case frac/num >= 1 -> frac >= num) then we
++ know the next digit in the binary fixed point number will be a '1'.
++ Also this excess needs to be removed. In the original algorithm the
++ overflow digit is substracted. In our case we can substract the
++ numerator. */
++ for (i = 0; i < PWM_BASE_UNIT_FRAC_BITS; i++) {
++ /* Multiply fraction by 2 */
++ fraction <<= 1;
++ base_unit_fraction <<= 1;
++
++ /* frac / num >= 1 -> set next bit to '1' and remove "overflow
++ digit" */
++ if (fraction >= numerator) {
++ base_unit_fraction |= 1;
++ fraction -= numerator;
++ }
++ }
++
++ pwmctrl->full = readl(reg);
++ pwmctrl->part.base_unit_int = (u32)base_unit_integer;
++ pwmctrl->part.base_unit_frac = base_unit_fraction;
++ writel(pwmctrl->full, reg);
++
++ return 0;
++}
++
++static int
++intel_mid_pwm_setup(void __iomem *reg, union pwmctrl_reg *pwmctrl,
++ int duty_ns, int period_ns)
++{
++ int ret;
++
++ /* Calculate and set base_unit */
++ ret = intel_mid_pwm_base_unit(reg, pwmctrl, period_ns, CLOCK_RATE);
++ if (ret)
++ return ret;
++
++ /* Calculate and set on time divisor */
++ intel_mid_pwm_on_time_divisor(reg, pwmctrl, period_ns, duty_ns);
++
++ /* Set software update bit */
++ pwmctrl->part.sw_update = 1UL;
++ writel(pwmctrl->full, reg);
++
++ return 0;
++}
++
++static int
++intel_mid_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm_dev,
++ int duty_ns, int period_ns)
++{
++ struct intel_mid_pwm_chip *pwm = to_pwm(chip);
++ union pwmctrl_reg *pwmctrl = &pwm->pwmctrls[pwm_dev->hwpwm];
++ void __iomem *reg = get_control_register(pwm, pwm_dev->hwpwm);
++
++ dev_dbg(chip->dev, "%s: period_ns %d, duty_ns %d\n", __func__,
++ period_ns, duty_ns);
++
++ /* Check the period is valid within HW capabilities */
++ if (period_ns < PWM_PERIOD_NS_MIN || period_ns > PWM_PERIOD_NS_MAX) {
++ dev_err(chip->dev, "Period (ns) must be in range %u:%u\n",
++ PWM_PERIOD_NS_MIN, PWM_PERIOD_NS_MAX);
++ return -EINVAL;
++ }
++
++ return intel_mid_pwm_setup(reg, pwmctrl, duty_ns, period_ns);
++}
++
++static int
++intel_mid_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm_dev)
++{
++ struct intel_mid_pwm_chip *pwm = to_pwm(chip);
++ union pwmctrl_reg *pwmctrl = &pwm->pwmctrls[pwm_dev->hwpwm];
++ int ret;
++ void __iomem *reg = get_control_register(pwm, pwm_dev->hwpwm);
++
++ pm_runtime_get_sync(chip->dev);
++
++ ret = intel_mid_pwm_setup(reg, pwmctrl, pwm_dev->duty_cycle,
++ pwm_dev->period);
++ if (ret)
++ return ret;
++
++ pwm_set_enable_bit(reg, pwmctrl, 1U);
++
++ dev_dbg(chip->dev, "%s: pwmctrl %#x\n", __func__, pwmctrl->full);
++
++ return 0;
++}
++
++static void
++intel_mid_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm_dev)
++{
++ struct intel_mid_pwm_chip *pwm = to_pwm(chip);
++ union pwmctrl_reg *pwmctrl = &pwm->pwmctrls[pwm_dev->hwpwm];
++ void __iomem *reg = get_control_register(pwm, pwm_dev->hwpwm);
++
++ pwm_set_enable_bit(reg, pwmctrl, 0);
++ pm_runtime_put(chip->dev);
++ dev_dbg(chip->dev, "%s: pwmctrl %#x\n", __func__, pwmctrl->full);
++}
++
++static const struct pwm_ops intel_mid_pwm_ops = {
++ .config = intel_mid_pwm_config,
++ .enable = intel_mid_pwm_enable,
++ .disable = intel_mid_pwm_disable,
++ .owner = THIS_MODULE,
++};
++
++static int
++intel_mid_pwm_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
++{
++ struct intel_mid_pwm_chip *pwm;
++ int ret, i;
++ resource_size_t resource_len;
++
++ pwm = devm_kzalloc(&pci->dev, sizeof(*pwm), GFP_KERNEL);
++ if (!pwm) {
++ dev_err(&pci->dev, "Can't allocate memory for pwm\n");
++ return -ENOMEM;
++ }
++
++ /* Init the device */
++ ret = pci_enable_device(pci);
++ if (ret) {
++ dev_err(&pci->dev, "Can't enable pci device\n");
++ return ret;
++ }
++
++ ret = pci_request_regions(pci, PWM_INTEL_MID_DRIVER_NAME);
++ if (ret) {
++ dev_err(&pci->dev, "Can't request regions\n");
++ goto do_disable_device;
++ }
++ pci_dev_get(pci);
++
++ pwm->regs = pci_ioremap_bar(pci, 0);
++ if (!pwm->regs) {
++ dev_err(&pci->dev, "ioremap failed\n");
++ ret = -EIO;
++ goto do_disable_device;
++ }
++
++ /* Calculate number of available pwm modules */
++ resource_len = pci_resource_len(pci, 0);
++ do_div(resource_len, PWM_CONTROL_REGISTER_SIZE);
++ pwm->num_of_pwms = resource_len;
++
++ /* allocate memory for PWM control register images */
++ pwm->pwmctrls = devm_kzalloc(&pci->dev,
++ sizeof(*pwm->pwmctrls) * pwm->num_of_pwms, GFP_KERNEL);
++ if (!pwm->pwmctrls) {
++ dev_err(&pci->dev, "Can't allocate memory for pwm pwmctrls\n");
++ ret = -ENOMEM;
++ goto do_unmap_regs;
++ }
++
++ /* register the driver with PWM framework */
++ pwm->chip.dev = &pci->dev;
++ pwm->chip.ops = &intel_mid_pwm_ops;
++ pwm->chip.base = -1;
++ pwm->chip.npwm = pwm->num_of_pwms;
++
++ ret = pwmchip_add(&pwm->chip);
++ if (ret) {
++ dev_err(&pci->dev, "Failed to add PWM chip: %d\n", ret);
++ goto do_unmap_regs;
++ }
++
++ /* Set default frequency/period (about 200Hz) on all pwm modules. */
++ for (i = 0; i < pwm->num_of_pwms; i++)
++ pwm->chip.pwms[i].period = PWM_DEFAULT_PERIOD;
++
++ pci_set_drvdata(pci, pwm);
++ pm_runtime_allow(&pci->dev);
++ pm_runtime_put_noidle(&pci->dev);
++
++ return ret;
++
++do_unmap_regs:
++ iounmap(pwm->regs);
++ pci_release_regions(pci);
++do_disable_device:
++ pci_disable_device(pci);
++
++ return ret;
++}
++
++static void
++intel_mid_pwm_remove(struct pci_dev *pci)
++{
++ struct intel_mid_pwm_chip *pwm = pci_get_drvdata(pci);
++
++ pm_runtime_get_noresume(&pci->dev);
++ pm_runtime_forbid(&pci->dev);
++ pwmchip_remove(&pwm->chip);
++ iounmap(pwm->regs);
++ pci_release_regions(pci);
++ pci_disable_device(pci);
++ pci_set_drvdata(pci, NULL);
++}
++
++#if CONFIG_PM
++static int
++intel_mid_pwm_runtime_suspend(struct device *dev)
++{
++ return 0;
++}
++
++static int
++intel_mid_pwm_runtime_resume(struct device *dev)
++{
++ return 0;
++}
++
++static void
++intel_mid_pwm_runtime_complete(struct device *dev) {
++}
++
++static const struct dev_pm_ops intel_mid_pm_ops = {
++ .prepare = intel_mid_pwm_runtime_suspend,
++ .complete = intel_mid_pwm_runtime_complete,
++ .runtime_suspend = intel_mid_pwm_runtime_suspend,
++ .runtime_resume = intel_mid_pwm_runtime_resume,
++};
++#endif
++
++/* PCI Routines */
++static DEFINE_PCI_DEVICE_TABLE(intel_mid_pwm_pci_ids) = {
++ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MID_MRFLD), 0},
++ { 0, }
++};
++MODULE_DEVICE_TABLE(pci, intel_mid_pwm_pci_ids);
++
++static struct pci_driver intel_mid_pci_driver = {
++ .name = PWM_INTEL_MID_DRIVER_NAME,
++ .id_table = intel_mid_pwm_pci_ids,
++ .probe = intel_mid_pwm_probe,
++ .remove = intel_mid_pwm_remove,
++#ifdef CONFIG_PM
++ .driver = {
++ .pm = &intel_mid_pm_ops,
++ },
++#endif
++};
++
++module_pci_driver(intel_mid_pci_driver);
++
++MODULE_ALIAS("pci:" PWM_INTEL_MID_DRIVER_NAME);
++MODULE_DESCRIPTION("Intel(R) MID PWM driver");
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Nicolas Pernas Maradei <nicolas.pernas.maradei@emutex.com>");
++
+diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c
+new file mode 100644
+index 0000000..f98b4a0
+--- /dev/null
++++ b/drivers/pwm/sysfs.c
+@@ -0,0 +1,353 @@
++/*
++ * A simple sysfs interface for the generic PWM framework
++ *
++ * Copyright (C) 2013 H Hartley Sweeten <hsweeten@visionengravers.com>
++ *
++ * Based on previous work by Lars Poeschel <poeschel@lemonage.de>
++ *
++ * 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, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/device.h>
++#include <linux/mutex.h>
++#include <linux/err.h>
++#include <linux/slab.h>
++#include <linux/kdev_t.h>
++#include <linux/pwm.h>
++
++struct pwm_export {
++ struct device child;
++ struct pwm_device *pwm;
++};
++
++static struct pwm_export *child_to_pwm_export(struct device *child)
++{
++ return container_of(child, struct pwm_export, child);
++}
++
++static struct pwm_device *child_to_pwm_device(struct device *child)
++{
++ struct pwm_export *export = child_to_pwm_export(child);
++
++ return export->pwm;
++}
++
++static ssize_t pwm_period_show(struct device *child,
++ struct device_attribute *attr,
++ char *buf)
++{
++ const struct pwm_device *pwm = child_to_pwm_device(child);
++
++ return sprintf(buf, "%u\n", pwm->period);
++}
++
++static ssize_t pwm_period_store(struct device *child,
++ struct device_attribute *attr,
++ const char *buf, size_t size)
++{
++ struct pwm_device *pwm = child_to_pwm_device(child);
++ unsigned int val;
++ int ret;
++
++ ret = kstrtouint(buf, 0, &val);
++ if (ret)
++ return ret;
++
++ ret = pwm_config(pwm, pwm->duty_cycle, val);
++
++ return ret ? : size;
++}
++
++static ssize_t pwm_duty_cycle_show(struct device *child,
++ struct device_attribute *attr,
++ char *buf)
++{
++ const struct pwm_device *pwm = child_to_pwm_device(child);
++
++ return sprintf(buf, "%u\n", pwm->duty_cycle);
++}
++
++static ssize_t pwm_duty_cycle_store(struct device *child,
++ struct device_attribute *attr,
++ const char *buf, size_t size)
++{
++ struct pwm_device *pwm = child_to_pwm_device(child);
++ unsigned int val;
++ int ret;
++
++ ret = kstrtouint(buf, 0, &val);
++ if (ret)
++ return ret;
++
++ ret = pwm_config(pwm, val, pwm->period);
++
++ return ret ? : size;
++}
++
++static ssize_t pwm_enable_show(struct device *child,
++ struct device_attribute *attr,
++ char *buf)
++{
++ const struct pwm_device *pwm = child_to_pwm_device(child);
++ int enabled = test_bit(PWMF_ENABLED, &pwm->flags);
++
++ return sprintf(buf, "%d\n", enabled);
++}
++
++static ssize_t pwm_enable_store(struct device *child,
++ struct device_attribute *attr,
++ const char *buf, size_t size)
++{
++ struct pwm_device *pwm = child_to_pwm_device(child);
++ int val, ret;
++
++ ret = kstrtoint(buf, 0, &val);
++ if (ret)
++ return ret;
++
++ switch (val) {
++ case 0:
++ pwm_disable(pwm);
++ break;
++ case 1:
++ ret = pwm_enable(pwm);
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++
++ return ret ? : size;
++}
++
++static ssize_t pwm_polarity_show(struct device *child,
++ struct device_attribute *attr,
++ char *buf)
++{
++ const struct pwm_device *pwm = child_to_pwm_device(child);
++
++ return sprintf(buf, "%s\n", pwm->polarity ? "inversed" : "normal");
++}
++
++static ssize_t pwm_polarity_store(struct device *child,
++ struct device_attribute *attr,
++ const char *buf, size_t size)
++{
++ struct pwm_device *pwm = child_to_pwm_device(child);
++ enum pwm_polarity polarity;
++ int ret;
++
++ if (sysfs_streq(buf, "normal"))
++ polarity = PWM_POLARITY_NORMAL;
++ else if (sysfs_streq(buf, "inversed"))
++ polarity = PWM_POLARITY_INVERSED;
++ else
++ return -EINVAL;
++
++ ret = pwm_set_polarity(pwm, polarity);
++
++ return ret ? : size;
++}
++
++static DEVICE_ATTR(period, 0644, pwm_period_show, pwm_period_store);
++static DEVICE_ATTR(duty_cycle, 0644, pwm_duty_cycle_show, pwm_duty_cycle_store);
++static DEVICE_ATTR(enable, 0644, pwm_enable_show, pwm_enable_store);
++static DEVICE_ATTR(polarity, 0644, pwm_polarity_show, pwm_polarity_store);
++
++static struct attribute *pwm_attrs[] = {
++ &dev_attr_period.attr,
++ &dev_attr_duty_cycle.attr,
++ &dev_attr_enable.attr,
++ &dev_attr_polarity.attr,
++ NULL
++};
++
++static const struct attribute_group pwm_attr_group = {
++ .attrs = pwm_attrs,
++};
++
++static const struct attribute_group *pwm_attr_groups[] = {
++ &pwm_attr_group,
++ NULL,
++};
++
++static void pwm_export_release(struct device *child)
++{
++ struct pwm_export *export = child_to_pwm_export(child);
++
++ kfree(export);
++}
++
++static int pwm_export_child(struct device *parent, struct pwm_device *pwm)
++{
++ struct pwm_export *export;
++ int ret;
++
++ if (test_and_set_bit(PWMF_EXPORTED, &pwm->flags))
++ return -EBUSY;
++
++ export = kzalloc(sizeof(*export), GFP_KERNEL);
++ if (!export) {
++ clear_bit(PWMF_EXPORTED, &pwm->flags);
++ return -ENOMEM;
++ }
++
++ export->pwm = pwm;
++
++ export->child.release = pwm_export_release;
++ export->child.parent = parent;
++ export->child.devt = MKDEV(0, 0);
++ export->child.groups = pwm_attr_groups;
++ dev_set_name(&export->child, "pwm%u", pwm->hwpwm);
++
++ ret = device_register(&export->child);
++ if (ret) {
++ clear_bit(PWMF_EXPORTED, &pwm->flags);
++ kfree(export);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int pwm_unexport_match(struct device *child, void *data)
++{
++ return child_to_pwm_device(child) == data;
++}
++
++static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm)
++{
++ struct device *child;
++
++ if (!test_and_clear_bit(PWMF_EXPORTED, &pwm->flags))
++ return -ENODEV;
++
++ child = device_find_child(parent, pwm, pwm_unexport_match);
++ if (!child)
++ return -ENODEV;
++
++ /* for device_find_child() */
++ put_device(child);
++ device_unregister(child);
++ pwm_put(pwm);
++
++ return 0;
++}
++
++static ssize_t pwm_export_store(struct device *parent,
++ struct device_attribute *attr,
++ const char *buf, size_t len)
++{
++ struct pwm_chip *chip = dev_get_drvdata(parent);
++ struct pwm_device *pwm;
++ unsigned int hwpwm;
++ int ret;
++
++ ret = kstrtouint(buf, 0, &hwpwm);
++ if (ret < 0)
++ return ret;
++
++ if (hwpwm >= chip->npwm)
++ return -ENODEV;
++
++ pwm = pwm_request_from_chip(chip, hwpwm, "sysfs");
++ if (IS_ERR(pwm))
++ return PTR_ERR(pwm);
++
++ ret = pwm_export_child(parent, pwm);
++ if (ret < 0)
++ pwm_put(pwm);
++
++ return ret ? : len;
++}
++
++static ssize_t pwm_unexport_store(struct device *parent,
++ struct device_attribute *attr,
++ const char *buf, size_t len)
++{
++ struct pwm_chip *chip = dev_get_drvdata(parent);
++ unsigned int hwpwm;
++ int ret;
++
++ ret = kstrtouint(buf, 0, &hwpwm);
++ if (ret < 0)
++ return ret;
++
++ if (hwpwm >= chip->npwm)
++ return -ENODEV;
++
++ ret = pwm_unexport_child(parent, &chip->pwms[hwpwm]);
++
++ return ret ? : len;
++}
++
++static ssize_t pwm_npwm_show(struct device *parent,
++ struct device_attribute *attr,
++ char *buf)
++{
++ const struct pwm_chip *chip = dev_get_drvdata(parent);
++
++ return sprintf(buf, "%u\n", chip->npwm);
++}
++
++static struct device_attribute pwm_chip_attrs[] = {
++ __ATTR(export, 0200, NULL, pwm_export_store),
++ __ATTR(unexport, 0200, NULL, pwm_unexport_store),
++ __ATTR(npwm, 0444, pwm_npwm_show, NULL),
++ __ATTR_NULL,
++};
++
++static struct class pwm_class = {
++ .name = "pwm",
++ .owner = THIS_MODULE,
++ .dev_attrs = pwm_chip_attrs,
++};
++
++static int pwmchip_sysfs_match(struct device *parent, const void *data)
++{
++ return dev_get_drvdata(parent) == data;
++}
++
++void pwmchip_sysfs_export(struct pwm_chip *chip)
++{
++ struct device *parent;
++
++ /*
++ * If device_create() fails the pwm_chip is still usable by
++ * the kernel its just not exported.
++ */
++ parent = device_create(&pwm_class, chip->dev, MKDEV(0, 0), chip,
++ "pwmchip%d", chip->base);
++ if (IS_ERR(parent)) {
++ dev_warn(chip->dev,
++ "device_create failed for pwm_chip sysfs export\n");
++ }
++}
++
++void pwmchip_sysfs_unexport(struct pwm_chip *chip)
++{
++ struct device *parent;
++
++ parent = class_find_device(&pwm_class, NULL, chip,
++ pwmchip_sysfs_match);
++ if (parent) {
++ /* for class_find_device() */
++ put_device(parent);
++ device_unregister(parent);
++ }
++}
++
++static int __init pwm_sysfs_init(void)
++{
++ return class_register(&pwm_class);
++}
++subsys_initcall(pwm_sysfs_init);
++
+diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
+index 8bb2644..27b22de 100644
+--- a/drivers/regulator/Kconfig
++++ b/drivers/regulator/Kconfig
+@@ -514,5 +514,9 @@ config REGULATOR_AS3711
+ This driver provides support for the voltage regulators on the
+ AS3711 PMIC
+
+-endif
++config REGULATOR_PMIC_BASIN_COVE
++ tristate "PMIC Basin Cove voltage regulator"
++ help
++ This driver controls intel Basin Cove pmic voltage output regulator
+
++endif
+diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
+index 47a34ff..8b751e7 100644
+--- a/drivers/regulator/Makefile
++++ b/drivers/regulator/Makefile
+@@ -2,6 +2,7 @@
+ # Makefile for regulator drivers.
+ #
+
++CFLAGS_pmic_basin_cove.o := -Werror
+
+ obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o
+ obj-$(CONFIG_OF) += of_regulator.o
+@@ -48,6 +49,7 @@ obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
+ obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o
+ obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
+ obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
++obj-$(CONFIG_REGULATOR_PMIC_BASIN_COVE) += pmic_basin_cove.o
+ obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o
+ obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
+ obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
+diff --git a/drivers/regulator/pmic_basin_cove.c b/drivers/regulator/pmic_basin_cove.c
+new file mode 100644
+index 0000000..6f23578
+--- /dev/null
++++ b/drivers/regulator/pmic_basin_cove.c
+@@ -0,0 +1,302 @@
++/*
++ * pmic_basin_cove.c - Merrifield regulator driver
++ * Copyright (c) 2013, Intel Corporation.
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/regulator/driver.h>
++#include <linux/regulator/intel_basin_cove_pmic.h>
++#include <linux/regulator/machine.h>
++
++#include <asm/intel_scu_pmic.h>
++
++/* Intel Voltage cntrl register parameters*/
++#define REG_ENA_STATUS_MASK 0x01
++#define REG_VSEL_MASK 0xc0
++#define VSEL_SHIFT 6
++
++#define REG_ON 0x01
++#define REG_OFF 0xfe
++
++const u16 reg_addr_offset[] = { VPROG1CNT_ADDR, VPROG2CNT_ADDR,
++ VPROG3CNT_ADDR };
++
++/**
++* intel_pmic_reg_is_enabled - To check if the regulator is enabled
++* @rdev: regulator_dev structure
++* @return value : 1 - Regulator is ON
++* :0 - Regulator is OFF
++*/
++static int intel_pmic_reg_is_enabled(struct regulator_dev *rdev)
++{
++ struct intel_pmic_info *pmic_info = rdev_get_drvdata(rdev);
++ u8 reg;
++ int ret;
++
++ /*FIXME: Is it ok to use the following IPC API*/
++ ret = intel_scu_ipc_ioread8(pmic_info->pmic_reg, &reg);
++ if (ret) {
++ dev_err(&rdev->dev,
++ "intel_scu_ipc_ioread8 returns error %08x\n", ret);
++ return ret;
++ }
++
++ return reg & REG_ENA_STATUS_MASK;
++}
++/**
++* intel_pmic_reg_enable - To enable the regulator
++* @rdev: regulator_dev structure
++* @return value : 0 - Regulator enabling success
++* :1 - Regulator enabling failed
++*/
++static int intel_pmic_reg_enable(struct regulator_dev *rdev)
++{
++ struct intel_pmic_info *pmic_info = rdev_get_drvdata(rdev);
++ u8 reg;
++ int ret;
++
++ ret = intel_scu_ipc_ioread8(pmic_info->pmic_reg, &reg);
++ if (ret) {
++ dev_err(&rdev->dev,
++ "intel_scu_ipc_ioread8 returns error %08x\n", ret);
++ return ret;
++ }
++ return intel_scu_ipc_iowrite8(pmic_info->pmic_reg, (reg | REG_ON));
++}
++/**
++* intel_pmic_reg_disable - To disable the regulator
++* @rdev: regulator_dev structure
++* @return value :0 - Regulator disabling success
++* :1 - Regulator disabling failed
++*/
++static int intel_pmic_reg_disable(struct regulator_dev *rdev)
++{
++ struct intel_pmic_info *pmic_info = rdev_get_drvdata(rdev);
++ u8 reg;
++ int ret;
++
++ ret = intel_scu_ipc_ioread8(pmic_info->pmic_reg, &reg);
++ if (ret) {
++ dev_err(&rdev->dev,
++ "intel_scu_ipc_ioread8 returns error %08x\n", ret);
++ return ret;
++ }
++ return intel_scu_ipc_iowrite8(pmic_info->pmic_reg,
++ (reg & REG_OFF));
++}
++/**
++* intel_pmic_reg_listvoltage - Return the voltage value,this is called
++* from core framework
++* @rdev: regulator source
++* @index : passed on from core
++* @return value : Returns the value in micro volts.
++ */
++static int intel_pmic_reg_listvoltage(struct regulator_dev *rdev,
++ unsigned index)
++{
++ struct intel_pmic_info *pmic_info = rdev_get_drvdata(rdev);
++
++ if (index >= pmic_info->table_len) {
++ dev_err(&rdev->dev, "Index out of range in listvoltage\n");
++ return -EINVAL;
++ }
++ return pmic_info->table[index] * 1000;
++}
++/**
++* intel_pmic_reg_getvoltage - Return the current voltage value in uV
++* @rdev: regulator_dev structure
++* @return value : Returns the voltage value.
++*/
++static int intel_pmic_reg_getvoltage(struct regulator_dev *rdev)
++{
++ struct intel_pmic_info *pmic_info = rdev_get_drvdata(rdev);
++ u8 reg, vsel;
++ int ret;
++
++ ret = intel_scu_ipc_ioread8(pmic_info->pmic_reg, &reg);
++ if (ret) {
++ dev_err(&rdev->dev,
++ "intel_scu_ipc_ioread8 returns error %08x\n", ret);
++ return ret;
++ }
++ vsel = (reg & REG_VSEL_MASK) >> VSEL_SHIFT;
++ if (vsel >= pmic_info->table_len) {
++ dev_err(&rdev->dev, "vsel value is out of range\n");
++ return -EINVAL;
++ }
++ dev_dbg(&rdev->dev, "Voltage value is %d mV\n",
++ pmic_info->table[vsel]);
++ return pmic_info->table[vsel] * 1000;
++}
++
++/**
++* intel_pmic_reg_setvoltage - Set voltage to the regulator
++* @rdev: regulator_dev structure
++* @min_uV: Minimum required voltage in uV
++* @max_uV: Maximum acceptable voltage in uV
++* @selector: Voltage value passed back to core layer
++* Sets a voltage regulator to the desired output voltage
++* @return value : Returns 0 if success
++* : Return error value on failure
++*/
++static int intel_pmic_reg_setvoltage(struct regulator_dev *rdev, int min_uV,
++ int max_uV, unsigned *selector)
++{
++ struct intel_pmic_info *pmic_info = rdev_get_drvdata(rdev);
++ int ret;
++ u8 reg, vsel;
++
++ for (vsel = 0; vsel < pmic_info->table_len; vsel++) {
++ int mV = pmic_info->table[vsel];
++ int uV = mV * 1000;
++ if (min_uV > uV || uV > max_uV)
++ continue;
++
++ *selector = vsel;
++ ret = intel_scu_ipc_ioread8(pmic_info->pmic_reg, &reg);
++ if (ret) {
++ dev_err(&rdev->dev,
++ "intel_scu_ipc_ioread8 error %08x\n", ret);
++ return ret;
++ }
++ reg &= ~REG_VSEL_MASK;
++ reg |= vsel << VSEL_SHIFT;
++ dev_dbg(&rdev->dev,
++ "intel_pmic_reg_setvoltage voltage: %u uV\n", uV);
++ return intel_scu_ipc_iowrite8(pmic_info->pmic_reg, reg);
++ }
++ return -EINVAL;
++}
++
++/* regulator_ops registration */
++static struct regulator_ops intel_pmic_ops = {
++ .is_enabled = intel_pmic_reg_is_enabled,
++ .enable = intel_pmic_reg_enable,
++ .disable = intel_pmic_reg_disable,
++ .get_voltage = intel_pmic_reg_getvoltage,
++ .set_voltage = intel_pmic_reg_setvoltage,
++ .list_voltage = intel_pmic_reg_listvoltage,
++};
++/**
++* struct regulator_desc - Regulator descriptor
++* Each regulator registered with the core is described with a structure of
++* this type.
++* @name: Identifying name for the regulator.
++* @id: Numerical identifier for the regulator.
++* @n_voltages: Number of selectors available for ops.list_voltage().
++* @ops: Regulator operations table.
++* @irq: Interrupt number for the regulator.
++* @type: Indicates if the regulator is a voltage or current regulator.
++* @owner: Module providing the regulator, used for refcounting.
++*/
++static struct regulator_desc intel_pmic_desc[] = {
++ {
++ .name = "vprog1",
++ .id = VPROG1,
++ .ops = &intel_pmic_ops,
++ .n_voltages = ARRAY_SIZE(VPROG1_VSEL_table),
++ .type = REGULATOR_VOLTAGE,
++ .owner = THIS_MODULE,
++ },
++ {
++ .name = "vprog2",
++ .id = VPROG2,
++ .ops = &intel_pmic_ops,
++ .n_voltages = ARRAY_SIZE(VPROG2_VSEL_table),
++ .type = REGULATOR_VOLTAGE,
++ .owner = THIS_MODULE,
++ },
++ {
++ .name = "vprog3",
++ .id = VPROG3,
++ .ops = &intel_pmic_ops,
++ .n_voltages = ARRAY_SIZE(VPROG3_VSEL_table),
++ .type = REGULATOR_VOLTAGE,
++ .owner = THIS_MODULE,
++ },
++};
++
++static int basin_cove_pmic_probe(struct platform_device *pdev)
++{
++ struct intel_pmic_info *pdata = dev_get_platdata(&pdev->dev);
++ struct regulator_config config = { };
++ unsigned int i;
++
++ if (!pdata || !pdata->pmic_reg)
++ return -EINVAL;
++
++ config.dev = &pdev->dev;
++ config.init_data = pdata->init_data;
++ config.driver_data = pdata;
++
++ for (i = 0; i < ARRAY_SIZE(reg_addr_offset); i++) {
++ if (reg_addr_offset[i] == pdata->pmic_reg)
++ break;
++ }
++ if (i == (ARRAY_SIZE(reg_addr_offset)))
++ return -EINVAL;
++
++ pdata->intel_pmic_rdev =
++ regulator_register(&intel_pmic_desc[i], &config);
++ if (IS_ERR(pdata->intel_pmic_rdev)) {
++ dev_err(&pdev->dev, "can't register regulator..error %ld\n",
++ PTR_ERR(pdata->intel_pmic_rdev));
++ return PTR_ERR(pdata->intel_pmic_rdev);
++ }
++ platform_set_drvdata(pdev, pdata->intel_pmic_rdev);
++ dev_dbg(&pdev->dev, "registered regulator\n");
++ return 0;
++}
++
++static int basin_cove_pmic_remove(struct platform_device *pdev)
++{
++ regulator_unregister(platform_get_drvdata(pdev));
++ return 0;
++}
++
++static const struct platform_device_id basin_cove_id_table[] = {
++ { "intel_regulator", 0 },
++ { },
++};
++
++MODULE_DEVICE_TABLE(platform, basin_cove_id_table);
++
++static struct platform_driver basin_cove_pmic_driver = {
++ .driver = {
++ .name = "intel_regulator",
++ .owner = THIS_MODULE,
++ },
++ .probe = basin_cove_pmic_probe,
++ .remove = basin_cove_pmic_remove,
++ .id_table = basin_cove_id_table,
++};
++static int __init basin_cove_pmic_init(void)
++{
++ return platform_driver_register(&basin_cove_pmic_driver);
++}
++subsys_initcall(basin_cove_pmic_init);
++
++static void __exit basin_cove_pmic_exit(void)
++{
++ platform_driver_unregister(&basin_cove_pmic_driver);
++}
++module_exit(basin_cove_pmic_exit);
++
++MODULE_DESCRIPTION("Basin Cove voltage regulator driver");
++MODULE_AUTHOR("Vishwesh/Mahesh/Sudarshan");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
+index d4d377c..97d3774 100644
+--- a/drivers/remoteproc/Kconfig
++++ b/drivers/remoteproc/Kconfig
+@@ -63,4 +63,15 @@ config DA8XX_REMOTEPROC
+ It's safe to say n here if you're not interested in multimedia
+ offloading.
+
++config INTEL_MID_REMOTEPROC
++ tristate "Intel MID remoteproc support"
++ depends on X86
++ select REMOTEPROC
++ select RPMSG
++ help
++ Say y to support Intel MID's remote processors core driver
++ and SCU driver.
++ Please say y here if you want to enable x86 remoteproc core
++ driver support.
++
+ endmenu
+diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
+index ac2ff75..efb0eb8 100644
+--- a/drivers/remoteproc/Makefile
++++ b/drivers/remoteproc/Makefile
+@@ -10,3 +10,4 @@ remoteproc-y += remoteproc_elf_loader.o
+ obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o
+ obj-$(CONFIG_STE_MODEM_RPROC) += ste_modem_rproc.o
+ obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o
++obj-$(CONFIG_INTEL_MID_REMOTEPROC) += intel_mid_rproc_scu.o intel_mid_rproc_core.o
+diff --git a/drivers/remoteproc/intel_mid_rproc_core.c b/drivers/remoteproc/intel_mid_rproc_core.c
+new file mode 100644
+index 0000000..dc30ba1f
+--- /dev/null
++++ b/drivers/remoteproc/intel_mid_rproc_core.c
+@@ -0,0 +1,269 @@
++/*
++ * INTEL MID Remote Processor Core driver
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/remoteproc.h>
++#include <linux/rpmsg.h>
++#include <linux/slab.h>
++#include <linux/virtio_ring.h>
++#include <linux/virtio_ids.h>
++#include <linux/platform_data/intel_mid_remoteproc.h>
++
++#include "intel_mid_rproc_core.h"
++#include "remoteproc_internal.h"
++
++#define RPMSG_NS_ADDR 53
++
++/**
++ * rpmsg_ns_alloc() - allocate a name service annoucement structure
++ * @name: name of remote service
++ * @id: rproc type
++ * @addr: address of remote service
++ */
++struct rpmsg_ns_info *rpmsg_ns_alloc(const char *name, int id, u32 addr)
++{
++ struct rpmsg_ns_info *ns_info;
++
++ ns_info = kzalloc(sizeof(struct rpmsg_ns_info), GFP_KERNEL);
++ if (ns_info) {
++ strcpy(ns_info->name, name);
++ ns_info->type = id;
++ ns_info->addr = addr;
++ ns_info->flags = RPMSG_NS_CREATE;
++ }
++
++ return ns_info;
++};
++EXPORT_SYMBOL_GPL(rpmsg_ns_alloc);
++
++/**
++ * rpmsg_ns_add_to_list() -- add a name service node to the global list
++ * @info: name service node
++ */
++void rpmsg_ns_add_to_list(struct rpmsg_ns_info *info,
++ struct rpmsg_ns_list *nslist)
++{
++ mutex_lock(&nslist->lock);
++ list_add_tail(&info->node, &nslist->list);
++ mutex_unlock(&nslist->lock);
++}
++EXPORT_SYMBOL_GPL(rpmsg_ns_add_to_list);
++
++/**
++ * free_rpmsg_ns() -- free rpmsg name service node
++ * @info: name service node
++ */
++void free_rpmsg_ns(struct rpmsg_ns_info *info)
++{
++ kfree(info);
++}
++
++/**
++ * rpmsg_ns_del_list() -- free rpmsg name service list
++ */
++void rpmsg_ns_del_list(struct rpmsg_ns_list *nslist)
++{
++ struct rpmsg_ns_info *info, *next;
++ mutex_lock(&nslist->lock);
++ list_for_each_entry_safe(info, next, &nslist->list, node) {
++ list_del(&info->node);
++ free_rpmsg_ns(info);
++ }
++ mutex_unlock(&nslist->lock);
++}
++EXPORT_SYMBOL_GPL(rpmsg_ns_del_list);
++
++/**
++ * find_rvdev() - find the rproc state of a supported virtio device
++ * @rproc: rproc handle
++ * @id: virtio device id
++ */
++struct rproc_vdev *find_rvdev(struct rproc *rproc, int id)
++{
++ struct rproc_vdev *rvdev;
++
++ list_for_each_entry(rvdev, &rproc->rvdevs, node)
++ if (rvdev->vdev.id.device == id)
++ return rvdev;
++
++ return NULL;
++}
++
++/*
++ * Since we could not get vring structure directly from rproc_vring
++ * structure, we have to create two local vrings and identify them
++ * by matching with rproc_vrings.
++ * @id: virtio device id.
++ * Currently one rproc_vdev is supported by firmware, and the id is
++ * VIRTIO_ID_RPMSG (declared in linux/virtio_ids.h).
++ */
++int find_vring_index(struct rproc *rproc, int vqid, int id)
++{
++ struct rproc_vdev *rvdev;
++ struct device *dev = rproc->dev.parent;
++ int vring_idx = 0;
++
++ rvdev = find_rvdev(rproc, id);
++ if (rvdev == NULL) {
++ dev_err(dev, "virtio device not found\n");
++ return -EINVAL;
++ }
++
++ while (vring_idx < RVDEV_NUM_VRINGS) {
++ if (rvdev->vring[vring_idx].notifyid == vqid)
++ break;
++ vring_idx++;
++ }
++
++ /* no match found? there's a problem */
++ if (vring_idx == RVDEV_NUM_VRINGS) {
++ dev_err(dev, "Can not find vring\n");
++ return -EINVAL;
++ }
++
++ return vring_idx;
++}
++
++void intel_mid_rproc_vring_init(struct rproc *rproc,
++ struct vring *vring, enum local_vring_idx id)
++{
++ int align, len;
++ void *addr;
++ struct rproc_vdev *rvdev;
++ struct device *dev = rproc->dev.parent;
++
++ rvdev = find_rvdev(rproc, VIRTIO_ID_RPMSG);
++ if (rvdev == NULL) {
++ dev_err(dev, "virtio device not found\n");
++ return;
++ }
++
++ addr = rvdev->vring[id].va;
++ align = rvdev->vring[id].align;
++ len = rvdev->vring[id].len;
++ vring_init(vring, len, addr, align);
++}
++
++/**
++ * intel_mid_rproc_vq_interrupt() - inform a vq interrupt to rproc
++ * after vq buffers are handled
++ * @rproc: rproc handle
++ * @msg: vq notify id
++ */
++void intel_mid_rproc_vq_interrupt(struct rproc *rproc, int msg)
++{
++ struct device *dev = rproc->dev.parent;
++
++ if (rproc_vq_interrupt(rproc, msg) == IRQ_NONE)
++ dev_err(dev, "no message was found in vqid %d\n", msg);
++}
++
++/**
++ * intel_mid_rproc_msg_handle() - generic interface as a vq buffer handle
++ * during rpmsg transaction
++ * @iproc: intel mid rproc data
++ */
++int intel_mid_rproc_msg_handle(struct intel_mid_rproc *iproc)
++{
++ int ret;
++ struct vring *r_vring, *s_vring;
++ void *r_virt_addr, *s_virt_addr;
++ u16 r_idx, s_idx;
++ u64 r_dma_addr, s_dma_addr;
++ u32 r_len, s_len;
++
++ r_vring = &iproc->rx_vring;
++ s_vring = &iproc->tx_vring;
++
++ r_idx = iproc->r_vring_last_used & (r_vring->num - 1);
++ s_idx = iproc->s_vring_last_used & (s_vring->num - 1);
++
++ r_dma_addr = r_vring->desc[r_idx].addr;
++ s_dma_addr = s_vring->desc[s_idx].addr;
++
++ r_virt_addr = phys_to_virt(r_dma_addr);
++ s_virt_addr = phys_to_virt(s_dma_addr);
++
++ ret = iproc->rproc_rpmsg_handle(r_virt_addr, s_virt_addr,
++ &r_len, &s_len);
++
++ r_vring->used->ring[r_idx].id = r_idx;
++ r_vring->used->ring[r_idx].len = r_len;
++ r_vring->used->idx++;
++
++ s_vring->used->ring[s_idx].id = s_idx;
++ s_vring->used->ring[s_idx].len = s_len;
++ s_vring->used->idx++;
++
++ iproc->r_vring_last_used++;
++ iproc->s_vring_last_used++;
++
++ return ret;
++}
++
++/**
++ * Remoteproc side rx buffer handler during name service creation.
++ * @iproc: intel mid rproc data
++ * @ns_info: name service info
++ *
++ * After remote processor receives name service messages, it needs to
++ * update the elements of its virtio device's rx virtqueue buffer
++ * before next rpmsg transaction.
++ * Here we have this function simulating the above effect.
++ */
++int intel_mid_rproc_ns_handle(struct intel_mid_rproc *iproc,
++ struct rpmsg_ns_info *ns_info)
++{
++ u16 index;
++ u32 len;
++ u64 dma_addr;
++ void *virt_addr;
++
++ struct vring *r_vring;
++ struct rpmsg_hdr *msg;
++ struct rpmsg_ns_msg *nsm;
++
++ if (ns_info == NULL) {
++ pr_err("ns_info = NULL\n");
++ return -ENODEV;
++ }
++
++ r_vring = &iproc->rx_vring;
++
++ index = iproc->r_vring_last_used & (r_vring->num - 1);
++
++ len = sizeof(*msg) + sizeof(*nsm);
++
++ dma_addr = r_vring->desc[index].addr;
++ virt_addr = phys_to_virt(dma_addr);
++
++ msg = (struct rpmsg_hdr *)virt_addr;
++ nsm = (struct rpmsg_ns_msg *)(virt_addr + sizeof(*msg));
++
++ nsm->addr = ns_info->addr;
++ nsm->flags = ns_info->flags;
++ strncpy(nsm->name, ns_info->name, RPMSG_NAME_SIZE);
++
++ msg->len = sizeof(*nsm);
++ msg->src = nsm->addr;
++ msg->dst = RPMSG_NS_ADDR;
++
++ r_vring->used->ring[index].id = index;
++ r_vring->used->ring[index].len = len;
++ r_vring->used->idx++;
++
++ iproc->r_vring_last_used++;
++
++ return 0;
++}
+diff --git a/drivers/remoteproc/intel_mid_rproc_core.h b/drivers/remoteproc/intel_mid_rproc_core.h
+new file mode 100644
+index 0000000..bfe6f6c
+--- /dev/null
++++ b/drivers/remoteproc/intel_mid_rproc_core.h
+@@ -0,0 +1,82 @@
++/*
++ * INTEL MID Remote Processor Core Head File
++ *
++ * Copyright (C) 2012 Intel, Inc.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++typedef int (*rpmsg_handle_t)(void *rx_buf, void *tx_buf,
++ u32 *r_len, u32 *s_len);
++
++int scu_ipc_rpmsg_handle(void *rx_buf, void *tx_buf, u32 *r_len, u32 *s_len);
++int psh_ipc_rpmsg_handle(void *rx_buf, void *tx_buf, u32 *len);
++
++#define RPROC_FW_LOADING_TIMEOUT (3 * HZ)
++#define IPROC_NAME_SIZE 20
++
++/**
++ * struct intel_mid_rproc - intel mid remote processor
++ * @ns_enabled: name service enabled flag
++ * @name: rproc name
++ * @type: rproc type
++ * @r_vring_last_used: last used index of rx vring
++ * @s_vring_last_used: last used index of tx vring
++ * @rproc: rproc handle
++ * @rx_vring: rproc rx vring
++ * @tx_vring: rproc tx vring
++ * @ns_info: loop cursor when creating ns channels
++ * @rproc_rpmsg_handle: rproc private rpmsg handle
++ */
++struct intel_mid_rproc {
++ bool ns_enabled;
++ char name[IPROC_NAME_SIZE];
++ u32 type;
++ u32 r_vring_last_used;
++ u32 s_vring_last_used;
++ struct rproc *rproc;
++ struct vring rx_vring;
++ struct vring tx_vring;
++ struct rpmsg_ns_info *ns_info;
++ rpmsg_handle_t rproc_rpmsg_handle;
++};
++
++enum local_vring_idx {
++ RX_VRING,
++ TX_VRING,
++};
++
++extern void intel_mid_rproc_vq_interrupt(struct rproc *rproc, int msg);
++extern int intel_mid_rproc_msg_handle(struct intel_mid_rproc *iproc);
++extern int intel_mid_rproc_ns_handle(struct intel_mid_rproc *iproc,
++ struct rpmsg_ns_info *ns_info);
++
++extern struct rproc_vdev *find_rvdev(struct rproc *rproc, int id);
++extern int find_vring_index(struct rproc *rproc, int vqid, int id);
++extern void intel_mid_rproc_vring_init(struct rproc *rproc,
++ struct vring *vring, enum local_vring_idx id);
++
++extern void rpmsg_ns_del_list(struct rpmsg_ns_list *nslist);
++
++/* Please do NOT use these APIs to send ipc commands,
++ * use rpmsg commands defined in <asm/intel_mid_rpmsg.h>
++ */
++extern void intel_scu_ipc_send_command(u32 cmd);
++
++/* Issue commands to the SCU with or without data */
++extern int intel_scu_ipc_simple_command(int cmd, int sub);
++extern int intel_scu_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen,
++ u32 *out, u32 outlen);
++extern int intel_scu_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen,
++ u32 *out, u32 outlen, u32 dptr, u32 sptr);
++
++/* IPC locking */
++extern void intel_scu_ipc_lock(void);
++extern void intel_scu_ipc_unlock(void);
+diff --git a/drivers/remoteproc/intel_mid_rproc_scu.c b/drivers/remoteproc/intel_mid_rproc_scu.c
+new file mode 100644
+index 0000000..fd5023b
+--- /dev/null
++++ b/drivers/remoteproc/intel_mid_rproc_scu.c
+@@ -0,0 +1,438 @@
++/*
++ * INTEL MID Remote Processor - SCU driver
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/err.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/remoteproc.h>
++#include <linux/delay.h>
++#include <linux/rpmsg.h>
++#include <linux/slab.h>
++#include <linux/virtio_ring.h>
++#include <linux/virtio_ids.h>
++#include <linux/platform_data/intel_mid_remoteproc.h>
++
++#include <asm/intel_scu_ipc.h>
++#include <asm/scu_ipc_rpmsg.h>
++#include <asm/intel-mid.h>
++
++#include "intel_mid_rproc_core.h"
++#include "remoteproc_internal.h"
++
++static struct rpmsg_ns_list *nslist;
++
++
++static int scu_ipc_command(void *tx_buf)
++{
++ struct tx_ipc_msg *tx_msg;
++ int ret = 0;
++
++ tx_msg = (struct tx_ipc_msg *)tx_buf;
++
++ ret = intel_scu_ipc_command(tx_msg->cmd, tx_msg->sub,
++ tx_msg->in, tx_msg->inlen,
++ tx_msg->out, tx_msg->outlen);
++ return ret;
++}
++
++static int scu_ipc_raw_command(void *tx_buf)
++{
++ struct tx_ipc_msg *tx_msg;
++ int ret = 0;
++
++ tx_msg = (struct tx_ipc_msg *)tx_buf;
++
++ intel_scu_ipc_lock();
++ ret = intel_scu_ipc_raw_cmd(tx_msg->cmd, tx_msg->sub,
++ tx_msg->in, tx_msg->inlen,
++ tx_msg->out, tx_msg->outlen,
++ tx_msg->dptr, tx_msg->sptr);
++ intel_scu_ipc_unlock();
++
++ return ret;
++}
++
++static int scu_ipc_simple_command(void *tx_buf)
++{
++ struct tx_ipc_msg *tx_msg;
++ int ret = 0;
++
++ tx_msg = (struct tx_ipc_msg *)tx_buf;
++
++ ret = intel_scu_ipc_simple_command(tx_msg->cmd, tx_msg->sub);
++
++ return ret;
++}
++
++static void scu_ipc_send_command(void *tx_buf)
++{
++ struct tx_ipc_msg *tx_msg;
++
++ tx_msg = (struct tx_ipc_msg *)tx_buf;
++ intel_scu_ipc_send_command(tx_msg->sub << 12 | tx_msg->cmd);
++}
++
++static int scu_ipc_fw_command(void *tx_buf)
++{
++ struct tx_ipc_msg *tx_msg;
++ int ret = 0;
++
++ tx_msg = (struct tx_ipc_msg *)tx_buf;
++
++ switch (tx_msg->cmd) {
++ case RP_GET_FW_REVISION:
++ ret = scu_ipc_command(tx_buf);
++ break;
++ case RP_FW_UPDATE:
++ /* Only scu_ipc_send_command works for fw update */
++ scu_ipc_send_command(tx_buf);
++ break;
++ default:
++ pr_info("Command %x not supported\n", tx_msg->cmd);
++ break;
++ };
++
++ return ret;
++}
++
++static int scu_ipc_util_command(void *tx_buf)
++{
++ struct tx_ipc_msg *tx_msg;
++ int ret = 0;
++
++ tx_msg = (struct tx_ipc_msg *)tx_buf;
++
++ switch (tx_msg->cmd) {
++ case RP_GET_FW_REVISION:
++ case RP_GET_HOBADDR:
++ case RP_OSC_CLK_CTRL:
++ ret = scu_ipc_command(tx_buf);
++ break;
++ case RP_S0IX_COUNTER:
++ ret = scu_ipc_simple_command(tx_buf);
++ break;
++ case RP_WRITE_OSNIB:
++ ret = scu_ipc_raw_command(tx_buf);
++ break;
++ default:
++ pr_info("Command %x not supported\n", tx_msg->cmd);
++ break;
++ };
++
++ return ret;
++}
++
++static int scu_ipc_vrtc_command(void *tx_buf)
++{
++ struct tx_ipc_msg *tx_msg;
++ int ret = 0;
++
++ tx_msg = (struct tx_ipc_msg *)tx_buf;
++
++ switch (tx_msg->cmd) {
++ case RP_GET_HOBADDR:
++ ret = scu_ipc_command(tx_buf);
++ break;
++ case RP_VRTC:
++ ret = scu_ipc_simple_command(tx_buf);
++ break;
++ default:
++ pr_info("Command %x not supported\n", tx_msg->cmd);
++ break;
++ };
++
++ return ret;
++}
++
++static int scu_ipc_fw_logging_command(void *tx_buf)
++{
++ struct tx_ipc_msg *tx_msg;
++ int ret = 0;
++
++ tx_msg = (struct tx_ipc_msg *)tx_buf;
++
++ switch (tx_msg->cmd) {
++ case RP_GET_HOBADDR:
++ ret = scu_ipc_command(tx_buf);
++ break;
++ case RP_CLEAR_FABERROR:
++ ret = scu_ipc_simple_command(tx_buf);
++ break;
++ default:
++ pr_info("Command %x not supported\n", tx_msg->cmd);
++ break;
++ };
++
++ return ret;
++}
++
++/**
++ * scu_ipc_rpmsg_handle() - scu rproc specified ipc rpmsg handle
++ * @rx_buf: rx buffer to be add
++ * @tx_buf: tx buffer to be get
++ * @r_len: rx buffer length
++ * @s_len: tx buffer length
++ */
++int scu_ipc_rpmsg_handle(void *rx_buf, void *tx_buf, u32 *r_len, u32 *s_len)
++{
++ struct rpmsg_hdr *tx_hdr, *tmp_hdr;
++ struct tx_ipc_msg *tx_msg;
++ struct rx_ipc_msg *tmp_msg;
++ int ret = 0;
++
++ *r_len = sizeof(struct rpmsg_hdr) + sizeof(struct rx_ipc_msg);
++ *s_len = sizeof(struct rpmsg_hdr) + sizeof(struct tx_ipc_msg);
++
++ /* get tx_msg and send scu ipc command */
++ tx_hdr = (struct rpmsg_hdr *)tx_buf;
++ tx_msg = (struct tx_ipc_msg *)(tx_buf + sizeof(*tx_hdr));
++
++ tmp_hdr = (struct rpmsg_hdr *)rx_buf;
++ tmp_msg = (struct rx_ipc_msg *)tmp_hdr->data;
++
++ switch (tx_hdr->dst) {
++ case RP_PMIC_ACCESS:
++ case RP_FLIS_ACCESS:
++ case RP_IPC_COMMAND:
++ tmp_msg->status = scu_ipc_command(tx_msg);
++ break;
++ case RP_SET_WATCHDOG:
++ if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER)
++ tmp_msg->status = scu_ipc_raw_command(tx_msg);
++ else
++ tmp_msg->status = scu_ipc_command(tx_msg);
++ break;
++ case RP_MIP_ACCESS:
++ case RP_IPC_RAW_COMMAND:
++ tmp_msg->status = scu_ipc_raw_command(tx_msg);
++ break;
++ case RP_IPC_SIMPLE_COMMAND:
++ tmp_msg->status = scu_ipc_simple_command(tx_msg);
++ break;
++ case RP_IPC_UTIL:
++ tmp_msg->status = scu_ipc_util_command(tx_msg);
++ break;
++ case RP_FW_ACCESS:
++ tmp_msg->status = scu_ipc_fw_command(tx_msg);
++ break;
++ case RP_VRTC:
++ tmp_msg->status = scu_ipc_vrtc_command(tx_msg);
++ break;
++ case RP_FW_LOGGING:
++ tmp_msg->status = scu_ipc_fw_logging_command(tx_msg);
++ break;
++ default:
++ tmp_msg->status = 0;
++ pr_info("Command %x not supported yet\n", tx_hdr->dst);
++ break;
++ };
++
++ /* prepare rx buffer, switch src and dst */
++ tmp_hdr->src = tx_hdr->dst;
++ tmp_hdr->dst = tx_hdr->src;
++
++ tmp_hdr->flags = tx_hdr->flags;
++ tmp_hdr->len = sizeof(struct rx_ipc_msg);
++
++ return ret;
++}
++
++/* kick a virtqueue */
++static void intel_rproc_scu_kick(struct rproc *rproc, int vqid)
++{
++ int idx;
++ int ret;
++ struct intel_mid_rproc *iproc;
++ struct rproc_vdev *rvdev;
++ struct device *dev = rproc->dev.parent;
++
++ iproc = (struct intel_mid_rproc *)rproc->priv;
++
++ /*
++ * Remote processor virtqueue being kicked.
++ * This part simulates remote processor handling messages.
++ */
++ idx = find_vring_index(rproc, vqid, VIRTIO_ID_RPMSG);
++
++ switch (idx) {
++ case RX_VRING:
++ if (iproc->ns_enabled &&
++ !list_is_last(&iproc->ns_info->node, &nslist->list)) {
++ list_for_each_entry_continue(iproc->ns_info,
++ &nslist->list, node) {
++ ret = intel_mid_rproc_ns_handle(iproc,
++ iproc->ns_info);
++ if (ret) {
++ dev_err(dev, "ns handle error\n");
++ return;
++ }
++ break;
++ }
++
++ intel_mid_rproc_vq_interrupt(rproc, vqid);
++ }
++ break;
++
++ case TX_VRING:
++
++ dev_dbg(dev, "remote processor got the message ...\n");
++ intel_mid_rproc_msg_handle(iproc);
++ intel_mid_rproc_vq_interrupt(rproc, vqid);
++
++ /*
++ * After remoteproc handles the message, it calls
++ * the receive callback.
++ * TODO: replace this part with real remote processor
++ * operation.
++ */
++ rvdev = find_rvdev(rproc, VIRTIO_ID_RPMSG);
++ if (rvdev)
++ intel_mid_rproc_vq_interrupt(rproc,
++ rvdev->vring[RX_VRING].notifyid);
++ else
++ WARN(1, "%s: can't find given rproc state\n", __func__);
++ break;
++
++ default:
++ dev_err(dev, "invalid vring index\n");
++ break;
++ }
++}
++
++/* power up the remote processor */
++static int intel_rproc_scu_start(struct rproc *rproc)
++{
++ struct intel_mid_rproc *iproc;
++
++ pr_info("Started intel scu remote processor\n");
++ iproc = (struct intel_mid_rproc *)rproc->priv;
++ intel_mid_rproc_vring_init(rproc, &iproc->rx_vring, RX_VRING);
++ intel_mid_rproc_vring_init(rproc, &iproc->tx_vring, TX_VRING);
++
++ return 0;
++}
++
++/* power off the remote processor */
++static int intel_rproc_scu_stop(struct rproc *rproc)
++{
++ pr_info("Stopped intel scu remote processor\n");
++ return 0;
++}
++
++static struct rproc_ops intel_rproc_scu_ops = {
++ .start = intel_rproc_scu_start,
++ .stop = intel_rproc_scu_stop,
++ .kick = intel_rproc_scu_kick,
++};
++
++static int intel_rproc_scu_probe(struct platform_device *pdev)
++{
++ struct intel_mid_rproc_pdata *pdata = pdev->dev.platform_data;
++ struct intel_mid_rproc *iproc;
++ struct rproc *rproc;
++ int ret;
++
++ ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
++ if (ret) {
++ dev_err(pdev->dev.parent, "dma_set_coherent_mask: %d\n", ret);
++ return ret;
++ }
++
++ rproc = rproc_alloc(&pdev->dev, pdata->name, &intel_rproc_scu_ops,
++ pdata->firmware, sizeof(*iproc));
++ if (!rproc)
++ return -ENOMEM;
++
++ iproc = rproc->priv;
++ iproc->rproc = rproc;
++ nslist = pdata->nslist;
++
++ platform_set_drvdata(pdev, rproc);
++
++ ret = rproc_add(rproc);
++ if (ret)
++ goto free_rproc;
++
++ /*
++ * Temporarily follow the rproc framework to load firmware
++ * TODO: modify remoteproc code according to X86 architecture
++ */
++ if (0 == wait_for_completion_timeout(&rproc->firmware_loading_complete,
++ RPROC_FW_LOADING_TIMEOUT)) {
++ dev_err(pdev->dev.parent, "fw loading not complete\n");
++ goto free_rproc;
++ }
++
++ /* Initialize intel_rproc_scu private data */
++ strncpy(iproc->name, pdev->id_entry->name, sizeof(iproc->name) - 1);
++ iproc->type = pdev->id_entry->driver_data;
++ iproc->r_vring_last_used = 0;
++ iproc->s_vring_last_used = 0;
++ iproc->ns_enabled = true;
++ iproc->rproc_rpmsg_handle = scu_ipc_rpmsg_handle;
++ iproc->ns_info = list_entry(&nslist->list,
++ struct rpmsg_ns_info, node);
++
++ return 0;
++
++free_rproc:
++ rproc_put(rproc);
++ return ret;
++}
++
++static int intel_rproc_scu_remove(struct platform_device *pdev)
++{
++ struct rproc *rproc = platform_get_drvdata(pdev);
++
++ if (nslist)
++ rpmsg_ns_del_list(nslist);
++
++ rproc_del(rproc);
++ rproc_put(rproc);
++
++ return 0;
++}
++
++static const struct platform_device_id intel_rproc_scu_id_table[] = {
++ { "intel_rproc_scu", RPROC_SCU },
++ { },
++};
++
++static struct platform_driver intel_rproc_scu_driver = {
++ .probe = intel_rproc_scu_probe,
++ .remove = intel_rproc_scu_remove,
++ .driver = {
++ .name = "intel_rproc_scu",
++ .owner = THIS_MODULE,
++ },
++ .id_table = intel_rproc_scu_id_table,
++};
++
++static int __init intel_rproc_scu_init(void)
++{
++ return platform_driver_register(&intel_rproc_scu_driver);
++}
++
++static void __exit intel_rproc_scu_exit(void)
++{
++ platform_driver_unregister(&intel_rproc_scu_driver);
++}
++
++subsys_initcall(intel_rproc_scu_init);
++module_exit(intel_rproc_scu_exit);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Ning Li<ning.li@intel.com>");
++MODULE_DESCRIPTION("INTEL MID Remoteproc Core driver");
+diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
+index 69a2193..620fef5 100644
+--- a/drivers/rpmsg/Kconfig
++++ b/drivers/rpmsg/Kconfig
+@@ -6,4 +6,13 @@ config RPMSG
+ select VIRTIO
+ select VIRTUALIZATION
+
++config RPMSG_IPC
++ tristate "Build rpmsg ipc driver"
++ depends on RPMSG
++ help
++ Build an rpmsg ipc driver, which demonstrates how IA
++ communicates with remote processor through IPC rpmsg
++ over the rpmsg bus. It register a rpmsg driver matched
++ with the rpmsg device created in remoteproc framework.
++
+ endmenu
+diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
+index 7617fcb..d8f5030 100644
+--- a/drivers/rpmsg/Makefile
++++ b/drivers/rpmsg/Makefile
+@@ -1 +1,2 @@
+ obj-$(CONFIG_RPMSG) += virtio_rpmsg_bus.o
++obj-$(CONFIG_RPMSG_IPC) += intel_mid_rpmsg.o
+diff --git a/drivers/rpmsg/intel_mid_rpmsg.c b/drivers/rpmsg/intel_mid_rpmsg.c
+new file mode 100644
+index 0000000..b2660e5
+--- /dev/null
++++ b/drivers/rpmsg/intel_mid_rpmsg.c
+@@ -0,0 +1,446 @@
++/*
++ * rpmsg_mid_rpmsg.c - Intel RPMSG Driver
++ *
++ * Copyright (C) 2012 Intel Corporation
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * 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; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/device.h>
++#include <linux/rpmsg.h>
++#include <linux/fs.h>
++#include <linux/slab.h>
++#include <linux/cdev.h>
++#include <linux/uaccess.h>
++#include <linux/sched.h>
++#include <linux/platform_data/intel_mid_remoteproc.h>
++
++#include <asm/intel_mid_rpmsg.h>
++
++/* Instance for generic kernel IPC calls */
++static struct rpmsg_device_data rpmsg_ddata[RPMSG_IPC_COMMAND_TYPE_NUM] = {
++ [RPMSG_IPC_COMMAND] = {
++ .name = "rpmsg_ipc_command",
++ .rpdev = NULL, /* initialized during driver probe */
++ .rpmsg_instance = NULL, /* initialized during driver probe */
++ },
++ [RPMSG_IPC_SIMPLE_COMMAND] = {
++ .name = "rpmsg_ipc_simple_command",
++ .rpdev = NULL,
++ .rpmsg_instance = NULL,
++ },
++ [RPMSG_IPC_RAW_COMMAND] = {
++ .name = "rpmsg_ipc_raw_command",
++ .rpdev = NULL,
++ .rpmsg_instance = NULL,
++ },
++};
++
++/* Providing rpmsg ipc generic interfaces.
++ * Modules can call these API directly without registering rpmsg driver.
++ *
++ * The arg list is the same as intel_scu_ipc_command(),
++ * so simply change intel_scu_ipc_command() to rpmsg_send_generic_command()
++ */
++int rpmsg_send_generic_command(u32 cmd, u32 sub,
++ u8 *in, u32 inlen,
++ u32 *out, u32 outlen)
++{
++ struct rpmsg_instance *rpmsg_ipc_instance =
++ rpmsg_ddata[RPMSG_IPC_COMMAND].rpmsg_instance;
++
++ return rpmsg_send_command(rpmsg_ipc_instance, cmd, sub,
++ in, out, inlen, outlen);
++}
++EXPORT_SYMBOL(rpmsg_send_generic_command);
++
++int rpmsg_send_generic_simple_command(u32 cmd, u32 sub)
++{
++ struct rpmsg_instance *rpmsg_ipc_instance =
++ rpmsg_ddata[RPMSG_IPC_SIMPLE_COMMAND].rpmsg_instance;
++
++ return rpmsg_send_simple_command(rpmsg_ipc_instance, cmd, sub);
++}
++EXPORT_SYMBOL(rpmsg_send_generic_simple_command);
++
++int rpmsg_send_generic_raw_command(u32 cmd, u32 sub,
++ u8 *in, u32 inlen,
++ u32 *out, u32 outlen,
++ u32 dptr, u32 sptr)
++{
++ struct rpmsg_instance *rpmsg_ipc_instance =
++ rpmsg_ddata[RPMSG_IPC_RAW_COMMAND].rpmsg_instance;
++
++ return rpmsg_send_raw_command(rpmsg_ipc_instance, cmd, sub,
++ in, out, inlen, outlen, sptr, dptr);
++}
++EXPORT_SYMBOL(rpmsg_send_generic_raw_command);
++
++/* Global lock for rpmsg framework */
++static struct rpmsg_lock global_lock = {
++ .lock = __MUTEX_INITIALIZER(global_lock.lock),
++ .locked_prev = 0,
++ .pending = ATOMIC_INIT(0),
++};
++
++#define is_global_locked_prev (global_lock.locked_prev)
++#define set_global_locked_prev(lock) (global_lock.locked_prev = lock)
++#define global_locked_by_current (global_lock.lock.owner == current)
++
++void rpmsg_global_lock(void)
++{
++ atomic_inc(&global_lock.pending);
++ mutex_lock(&global_lock.lock);
++}
++EXPORT_SYMBOL(rpmsg_global_lock);
++
++void rpmsg_global_unlock(void)
++{
++ mutex_unlock(&global_lock.lock);
++ if (!atomic_dec_and_test(&global_lock.pending))
++ schedule();
++}
++EXPORT_SYMBOL(rpmsg_global_unlock);
++
++static void rpmsg_lock(void)
++{
++ if (!mutex_trylock(&global_lock.lock)) {
++ if (global_locked_by_current)
++ set_global_locked_prev(1);
++ else
++ rpmsg_global_lock();
++ }
++}
++
++static void rpmsg_unlock(void)
++{
++ if (!is_global_locked_prev)
++ rpmsg_global_unlock();
++ else
++ set_global_locked_prev(0);
++}
++
++int rpmsg_send_command(struct rpmsg_instance *instance, u32 cmd,
++ u32 sub, u8 *in,
++ u32 *out, u32 inlen,
++ u32 outlen)
++{
++ int ret = 0;
++
++ if (!instance) {
++ pr_err("%s: Instance is NULL\n", __func__);
++ return -EFAULT;
++ }
++
++ /* Hold global rpmsg lock */
++ rpmsg_lock();
++
++ mutex_lock(&instance->instance_lock);
++
++ /* Prepare Tx buffer */
++ instance->tx_msg->cmd = cmd;
++ instance->tx_msg->sub = sub;
++ instance->tx_msg->in = in;
++ instance->tx_msg->out = out;
++ instance->tx_msg->inlen = inlen;
++ instance->tx_msg->outlen = outlen;
++
++ /* Preapre Rx buffer */
++ mutex_lock(&instance->rx_lock);
++ instance->rx_msg->status = -1;
++ mutex_unlock(&instance->rx_lock);
++ INIT_COMPLETION(instance->reply_arrived);
++
++ /* Send message to remote processor(SCU) using rpdev channel */
++ ret = rpmsg_send_offchannel(
++ instance->rpdev,
++ instance->endpoint->addr,
++ instance->rpdev->dst,
++ instance->tx_msg,
++ sizeof(*instance->tx_msg)
++ );
++ if (ret) {
++ dev_err(&instance->rpdev->dev, "%s failed: %d\n",
++ __func__, ret);
++ goto end;
++ }
++
++ if (0 == wait_for_completion_timeout(&instance->reply_arrived,
++ RPMSG_TX_TIMEOUT)) {
++ dev_err(&instance->rpdev->dev,
++ "timeout: %d\n", ret);
++ ret = -ETIMEDOUT;
++ goto end;
++ }
++
++ mutex_lock(&instance->rx_lock);
++ ret = instance->rx_msg->status;
++ mutex_unlock(&instance->rx_lock);
++end:
++ mutex_unlock(&instance->instance_lock);
++ rpmsg_unlock();
++
++ return ret;
++}
++EXPORT_SYMBOL(rpmsg_send_command);
++
++int rpmsg_send_raw_command(struct rpmsg_instance *instance, u32 cmd,
++ u32 sub, u8 *in,
++ u32 *out, u32 inlen,
++ u32 outlen, u32 sptr,
++ u32 dptr)
++{
++ int ret = 0;
++
++ if (!instance) {
++ pr_err("%s: Instance is NULL\n", __func__);
++ return -EFAULT;
++ }
++
++ mutex_lock(&instance->instance_lock);
++ instance->tx_msg->sptr = sptr;
++ instance->tx_msg->dptr = dptr;
++ mutex_unlock(&instance->instance_lock);
++
++ ret = rpmsg_send_command(instance, cmd, sub, in, out, inlen, outlen);
++
++ return ret;
++}
++EXPORT_SYMBOL(rpmsg_send_raw_command);
++
++int rpmsg_send_simple_command(struct rpmsg_instance *instance, u32 cmd,
++ u32 sub)
++{
++ int ret;
++
++ ret = rpmsg_send_command(instance, cmd, sub, NULL, NULL, 0, 0);
++
++ return ret;
++}
++EXPORT_SYMBOL(rpmsg_send_simple_command);
++
++static void rpmsg_recv_cb(struct rpmsg_channel *rpdev, void *data,
++ int len, void *priv, u32 src)
++{
++#ifdef DEBUG_RPMSG_MSG
++ static int rx_count;
++#endif
++ struct rpmsg_instance *instance = priv;
++
++ if (len != sizeof(struct rx_ipc_msg)) {
++ dev_warn(&rpdev->dev, "%s, incorrect msg length\n", __func__);
++ return;
++ }
++
++#ifdef DEBUG_RPMSG_MSG
++ dev_info(&rpdev->dev, "incoming msg %d (src: 0x%x)\n", ++rx_count, src);
++
++ print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
++ data, len, true);
++#endif
++
++ mutex_lock(&instance->rx_lock);
++
++ memcpy(instance->rx_msg, data, len);
++
++ mutex_unlock(&instance->rx_lock);
++
++ complete(&instance->reply_arrived);
++
++}
++
++int alloc_rpmsg_instance(struct rpmsg_channel *rpdev,
++ struct rpmsg_instance **pInstance)
++{
++ int ret = 0;
++ struct rpmsg_instance *instance;
++
++ dev_info(&rpdev->dev, "Allocating rpmsg_instance\n");
++
++ instance = kzalloc(sizeof(*instance), GFP_KERNEL);
++ if (!instance) {
++ ret = -ENOMEM;
++ dev_err(&rpdev->dev, "kzalloc rpmsg_instance failed\n");
++ goto alloc_out;
++ }
++
++ instance->rpdev = rpdev;
++
++ instance->tx_msg = kzalloc(sizeof(struct tx_ipc_msg), GFP_KERNEL);
++ if (!instance->tx_msg) {
++ ret = -ENOMEM;
++ dev_err(&rpdev->dev, "kzalloc instance tx_msg failed\n");
++ goto error_tx_msg_create;
++ }
++
++ instance->rx_msg = kzalloc(sizeof(struct rx_ipc_msg), GFP_KERNEL);
++ if (!instance->rx_msg) {
++ ret = -ENOMEM;
++ dev_err(&rpdev->dev, "kzalloc instance rx_msg failed\n");
++ goto error_rx_msg_create;
++ }
++
++ instance->endpoint = rpmsg_create_ept(rpdev, rpmsg_recv_cb,
++ instance,
++ RPMSG_ADDR_ANY);
++ if (!instance->endpoint) {
++ dev_err(&rpdev->dev, "create instance endpoint failed\n");
++ ret = -ENOMEM;
++ goto error_endpoint_create;
++ }
++
++ goto alloc_out;
++
++error_endpoint_create:
++ kfree(instance->rx_msg);
++ instance->rx_msg = NULL;
++error_rx_msg_create:
++ kfree(instance->tx_msg);
++ instance->tx_msg = NULL;
++error_tx_msg_create:
++ kfree(instance);
++ instance = NULL;
++alloc_out:
++ *pInstance = instance;
++ return ret;
++
++}
++EXPORT_SYMBOL(alloc_rpmsg_instance);
++
++void free_rpmsg_instance(struct rpmsg_channel *rpdev,
++ struct rpmsg_instance **pInstance)
++{
++ struct rpmsg_instance *instance = *pInstance;
++
++ mutex_lock(&instance->instance_lock);
++ rpmsg_destroy_ept(instance->endpoint);
++ kfree(instance->tx_msg);
++ instance->tx_msg = NULL;
++ kfree(instance->rx_msg);
++ instance->rx_msg = NULL;
++ mutex_unlock(&instance->instance_lock);
++ kfree(instance);
++ *pInstance = NULL;
++ dev_info(&rpdev->dev, "Freeing rpmsg device\n");
++}
++EXPORT_SYMBOL(free_rpmsg_instance);
++
++void init_rpmsg_instance(struct rpmsg_instance *instance)
++{
++ init_completion(&instance->reply_arrived);
++ mutex_init(&instance->instance_lock);
++ mutex_init(&instance->rx_lock);
++}
++EXPORT_SYMBOL(init_rpmsg_instance);
++
++static int rpmsg_ipc_probe(struct rpmsg_channel *rpdev)
++{
++ int ret = 0;
++ int i;
++ struct rpmsg_device_data *ddata = rpmsg_ddata;
++
++ if (rpdev == NULL) {
++ pr_err("rpmsg channel %s not created\n", rpdev->id.name);
++ ret = -ENODEV;
++ goto out;
++ }
++
++ dev_info(&rpdev->dev, "Probed rpmsg_ipc device %s\n", rpdev->id.name);
++
++ for (i = RPMSG_IPC_COMMAND; i < RPMSG_IPC_COMMAND_TYPE_NUM; i++) {
++ if (!strncmp(rpdev->id.name, ddata[i].name, RPMSG_NAME_SIZE)) {
++
++ /* Allocate rpmsg instance for kernel IPC calls*/
++ ret = alloc_rpmsg_instance(rpdev,
++ &ddata[i].rpmsg_instance);
++ if (!ddata[i].rpmsg_instance) {
++ dev_err(&rpdev->dev,
++ "alloc rpmsg instance failed\n");
++ goto out;
++ }
++
++ /* Initialize rpmsg instance */
++ init_rpmsg_instance(ddata[i].rpmsg_instance);
++
++ ddata[i].rpdev = rpdev;
++ break;
++ }
++ }
++
++out:
++ return ret;
++}
++
++static void rpmsg_ipc_remove(struct rpmsg_channel *rpdev)
++{
++ int i;
++ struct rpmsg_device_data *ddata = rpmsg_ddata;
++
++ for (i = RPMSG_IPC_COMMAND; i < RPMSG_IPC_COMMAND_TYPE_NUM; i++) {
++ if (!strncmp(rpdev->id.name, ddata[i].name, RPMSG_NAME_SIZE)) {
++ free_rpmsg_instance(rpdev, &ddata[i].rpmsg_instance);
++ break;
++ }
++ }
++ dev_info(&rpdev->dev, "Removed rpmsg_ipc device\n");
++}
++
++static void rpmsg_ipc_cb(struct rpmsg_channel *rpdev, void *data,
++ int len, void *priv, u32 src)
++{
++ dev_warn(&rpdev->dev, "unexpected, message\n");
++
++ print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
++ data, len, true);
++}
++
++static struct rpmsg_device_id rpmsg_ipc_id_table[] = {
++ { .name = "rpmsg_ipc_command" },
++ { .name = "rpmsg_ipc_simple_command" },
++ { .name = "rpmsg_ipc_raw_command" },
++ { },
++};
++MODULE_DEVICE_TABLE(rpmsg, rpmsg_ipc_id_table);
++
++static struct rpmsg_driver rpmsg_ipc = {
++ .drv.name = KBUILD_MODNAME,
++ .drv.owner = THIS_MODULE,
++ .id_table = rpmsg_ipc_id_table,
++ .probe = rpmsg_ipc_probe,
++ .callback = rpmsg_ipc_cb,
++ .remove = rpmsg_ipc_remove,
++};
++
++static int __init rpmsg_ipc_init(void)
++{
++ return register_rpmsg_driver(&rpmsg_ipc);
++}
++subsys_initcall(rpmsg_ipc_init);
++
++static void __exit rpmsg_ipc_exit(void)
++{
++ return unregister_rpmsg_driver(&rpmsg_ipc);
++}
++module_exit(rpmsg_ipc_exit);
++
++MODULE_AUTHOR("Ning Li<ning.li@intel.com>");
++MODULE_DESCRIPTION("Intel IPC RPMSG Driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
+index b6135d4..a9ad4a7 100644
+--- a/drivers/rpmsg/virtio_rpmsg_bus.c
++++ b/drivers/rpmsg/virtio_rpmsg_bus.c
+@@ -749,9 +749,9 @@ int rpmsg_send_offchannel_raw(struct rpmsg_channel *rpdev, u32 src, u32 dst,
+ dev_dbg(dev, "TX From 0x%x, To 0x%x, Len %d, Flags %d, Reserved %d\n",
+ msg->src, msg->dst, msg->len,
+ msg->flags, msg->reserved);
+- print_hex_dump(KERN_DEBUG, "rpmsg_virtio TX: ", DUMP_PREFIX_NONE, 16, 1,
++/* print_hex_dump(KERN_DEBUG, "rpmsg_virtio TX: ", DUMP_PREFIX_NONE, 16, 1,
+ msg, sizeof(*msg) + msg->len, true);
+-
++*/
+ sg_init_one(&sg, msg, sizeof(*msg) + len);
+
+ mutex_lock(&vrp->tx_lock);
+@@ -786,9 +786,9 @@ static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
+ dev_dbg(dev, "From: 0x%x, To: 0x%x, Len: %d, Flags: %d, Reserved: %d\n",
+ msg->src, msg->dst, msg->len,
+ msg->flags, msg->reserved);
+- print_hex_dump(KERN_DEBUG, "rpmsg_virtio RX: ", DUMP_PREFIX_NONE, 16, 1,
++/* print_hex_dump(KERN_DEBUG, "rpmsg_virtio RX: ", DUMP_PREFIX_NONE, 16, 1,
+ msg, sizeof(*msg) + msg->len, true);
+-
++*/
+ /*
+ * We currently use fixed-sized buffers, so trivially sanitize
+ * the reported payload length.
+@@ -898,10 +898,10 @@ static void rpmsg_ns_cb(struct rpmsg_channel *rpdev, void *data, int len,
+ struct device *dev = &vrp->vdev->dev;
+ int ret;
+
+- print_hex_dump(KERN_DEBUG, "NS announcement: ",
++/* print_hex_dump(KERN_DEBUG, "NS announcement: ",
+ DUMP_PREFIX_NONE, 16, 1,
+ data, len, true);
+-
++*/
+ if (len != sizeof(*msg)) {
+ dev_err(dev, "malformed ns msg (%d)\n", len);
+ return;
+diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c
+index 578baf9..b26ff5a 100644
+--- a/drivers/rtc/rtc-mrst.c
++++ b/drivers/rtc/rtc-mrst.c
+@@ -35,11 +35,14 @@
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/sfi.h>
++#include <linux/io.h>
+
+ #include <asm-generic/rtc.h>
+ #include <asm/intel_scu_ipc.h>
+-#include <asm/mrst.h>
++#include <asm/intel-mid.h>
+ #include <asm/mrst-vrtc.h>
++#include <linux/rpmsg.h>
++#include <asm/intel_mid_rpmsg.h>
+
+ struct mrst_rtc {
+ struct rtc_device *rtc;
+@@ -51,10 +54,24 @@ struct mrst_rtc {
+ u8 suspend_ctrl;
+ };
+
++/* both platform and pnp busses use negative numbers for invalid irqs */
++#define is_valid_irq(n) ((n) >= 0)
++
+ static const char driver_name[] = "rtc_mrst";
+
+ #define RTC_IRQMASK (RTC_PF | RTC_AF)
+
++#define OSHOB_ALARM_OFFSET 0x68
++#define OSHOB_DAYW_OFFSET 0x00
++#define OSHOB_DAYM_OFFSET 0x01
++#define OSHOB_MON_OFFSET 0x02
++#define OSHOB_YEAR_OFFSET 0x03
++
++static u32 oshob_base;
++static void __iomem *oshob_addr;
++
++static struct rpmsg_instance *vrtc_mrst_instance;
++
+ static inline int is_intr(u8 rtc_intr)
+ {
+ if (!(rtc_intr & RTC_IRQF))
+@@ -73,6 +90,34 @@ static inline unsigned char vrtc_is_updating(void)
+ return uip;
+ }
+
++/* If the interrupt is of alarm-type-RTC_AF, then check if it's for
++ * the correct day. With the support for alarms more than 24-hours,
++ * alarm-date is compared with date-fields in OSHOB, as the vRTC
++ * doesn't have date-fields for alarm
++ */
++static int is_valid_af(u8 rtc_intr)
++{
++ char *p;
++ unsigned long vrtc_date, oshob_date;
++
++ if ((__intel_mid_cpu_chip == INTEL_MID_CPU_CHIP_PENWELL) ||
++ (__intel_mid_cpu_chip == INTEL_MID_CPU_CHIP_CLOVERVIEW)) {
++ if (rtc_intr & RTC_AF) {
++ p = (char *) &vrtc_date;
++ *(p+1) = vrtc_cmos_read(RTC_DAY_OF_MONTH);
++ *(p+2) = vrtc_cmos_read(RTC_MONTH);
++ *(p+3) = vrtc_cmos_read(RTC_YEAR);
++
++ oshob_date = readl(oshob_addr);
++ if ((oshob_date & 0xFFFFFF00)
++ != (vrtc_date & 0xFFFFFF00))
++ return false;
++ }
++ }
++
++ return true;
++}
++
+ /*
+ * rtc_time's year contains the increment over 1900, but vRTC's YEAR
+ * register can't be programmed to value larger than 0x64, so vRTC
+@@ -137,7 +182,8 @@ static int mrst_set_time(struct device *dev, struct rtc_time *time)
+
+ spin_unlock_irqrestore(&rtc_lock, flags);
+
+- ret = intel_scu_ipc_simple_command(IPCMSG_VRTC, IPC_CMD_VRTC_SETTIME);
++ ret = rpmsg_send_simple_command(vrtc_mrst_instance,
++ IPCMSG_VRTC, IPC_CMD_VRTC_SETTIME);
+ return ret;
+ }
+
+@@ -146,7 +192,7 @@ static int mrst_read_alarm(struct device *dev, struct rtc_wkalrm *t)
+ struct mrst_rtc *mrst = dev_get_drvdata(dev);
+ unsigned char rtc_control;
+
+- if (mrst->irq <= 0)
++ if (!is_valid_irq(mrst->irq))
+ return -EIO;
+
+ /* Basic alarms only support hour, minute, and seconds fields.
+@@ -182,7 +228,7 @@ static void mrst_checkintr(struct mrst_rtc *mrst, unsigned char rtc_control)
+ */
+ rtc_intr = vrtc_cmos_read(RTC_INTR_FLAGS);
+ rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
+- if (is_intr(rtc_intr))
++ if (is_intr(rtc_intr) && is_valid_af(rtc_intr))
+ rtc_update_irq(mrst->rtc, 1, rtc_intr);
+ }
+
+@@ -217,15 +263,21 @@ static int mrst_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+ {
+ struct mrst_rtc *mrst = dev_get_drvdata(dev);
+ unsigned char hrs, min, sec;
++ unsigned char wday, mday, mon, year;
+ int ret = 0;
+
+- if (!mrst->irq)
++ if (!is_valid_irq(mrst->irq))
+ return -EIO;
+
+ hrs = t->time.tm_hour;
+ min = t->time.tm_min;
+ sec = t->time.tm_sec;
+
++ wday = t->time.tm_wday;
++ mday = t->time.tm_mday;
++ mon = t->time.tm_mon;
++ year = t->time.tm_year;
++
+ spin_lock_irq(&rtc_lock);
+ /* Next rtc irq must not be from previous alarm setting */
+ mrst_irq_disable(mrst, RTC_AIE);
+@@ -235,13 +287,18 @@ static int mrst_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+ vrtc_cmos_write(min, RTC_MINUTES_ALARM);
+ vrtc_cmos_write(sec, RTC_SECONDS_ALARM);
+
+- spin_unlock_irq(&rtc_lock);
+-
+- ret = intel_scu_ipc_simple_command(IPCMSG_VRTC, IPC_CMD_VRTC_SETALARM);
+- if (ret)
+- return ret;
++ if ((__intel_mid_cpu_chip == INTEL_MID_CPU_CHIP_PENWELL) ||
++ (__intel_mid_cpu_chip == INTEL_MID_CPU_CHIP_CLOVERVIEW)) {
++ /* Support for date-field in Alarm using OSHOB
++ * Since, vRTC doesn't have Alarm-registers for date-fields,
++ * write date-fields into OSHOB for SCU to sync to MSIC-RTC */
++ writeb(wday, oshob_addr+OSHOB_DAYW_OFFSET);
++ writeb(mday, oshob_addr+OSHOB_DAYM_OFFSET);
++ writeb(mon+1, oshob_addr+OSHOB_MON_OFFSET);
++ /* Adjust for the 1972/1900 */
++ writeb(year-72, oshob_addr+OSHOB_YEAR_OFFSET);
++ }
+
+- spin_lock_irq(&rtc_lock);
+ if (t->enabled)
+ mrst_irq_enable(mrst, RTC_AIE);
+
+@@ -250,21 +307,42 @@ static int mrst_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+ return 0;
+ }
+
++#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE)
++
+ /* Currently, the vRTC doesn't support UIE ON/OFF */
+-static int mrst_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
++static int
++mrst_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+ {
+ struct mrst_rtc *mrst = dev_get_drvdata(dev);
+ unsigned long flags;
+
++ switch (cmd) {
++ case RTC_AIE_OFF:
++ case RTC_AIE_ON:
++ if (!is_valid_irq(mrst->irq))
++ return -EINVAL;
++ break;
++ default:
++ /* PIE ON/OFF is handled by mrst_irq_set_state() */
++ return -ENOIOCTLCMD;
++ }
++
+ spin_lock_irqsave(&rtc_lock, flags);
+- if (enabled)
+- mrst_irq_enable(mrst, RTC_AIE);
+- else
++ switch (cmd) {
++ case RTC_AIE_OFF: /* alarm off */
+ mrst_irq_disable(mrst, RTC_AIE);
++ break;
++ case RTC_AIE_ON: /* alarm on */
++ mrst_irq_enable(mrst, RTC_AIE);
++ break;
++ }
+ spin_unlock_irqrestore(&rtc_lock, flags);
+ return 0;
+ }
+
++#else
++#define mrst_rtc_ioctl NULL
++#endif
+
+ #if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE)
+
+@@ -290,13 +368,26 @@ static int mrst_procfs(struct device *dev, struct seq_file *seq)
+ #define mrst_procfs NULL
+ #endif
+
++static int mrst_alarm_irq_enable(struct device *dev, unsigned int enabled)
++{
++ struct mrst_rtc *mrst = dev_get_drvdata(dev);
++
++ if (enabled)
++ mrst_irq_enable(mrst, RTC_AIE);
++ else
++ mrst_irq_disable(mrst, RTC_AIE);
++
++ return 0;
++}
++
+ static const struct rtc_class_ops mrst_rtc_ops = {
+- .read_time = mrst_read_time,
+- .set_time = mrst_set_time,
+- .read_alarm = mrst_read_alarm,
+- .set_alarm = mrst_set_alarm,
+- .proc = mrst_procfs,
+- .alarm_irq_enable = mrst_rtc_alarm_irq_enable,
++ .ioctl = mrst_rtc_ioctl,
++ .read_time = mrst_read_time,
++ .set_time = mrst_set_time,
++ .read_alarm = mrst_read_alarm,
++ .set_alarm = mrst_set_alarm,
++ .proc = mrst_procfs,
++ .alarm_irq_enable = mrst_alarm_irq_enable,
+ };
+
+ static struct mrst_rtc mrst_rtc;
+@@ -308,22 +399,33 @@ static struct mrst_rtc mrst_rtc;
+ static irqreturn_t mrst_rtc_irq(int irq, void *p)
+ {
+ u8 irqstat;
++ int ret = 0;
+
+ spin_lock(&rtc_lock);
+ /* This read will clear all IRQ flags inside Reg C */
+ irqstat = vrtc_cmos_read(RTC_INTR_FLAGS);
++ irqstat &= RTC_IRQMASK | RTC_IRQF;
++ ret = is_valid_af(irqstat);
+ spin_unlock(&rtc_lock);
+
+- irqstat &= RTC_IRQMASK | RTC_IRQF;
+ if (is_intr(irqstat)) {
+- rtc_update_irq(p, 1, irqstat);
++ /* If it's an alarm-interrupt, update RTC-IRQ only if it's
++ * for current day. Alarms beyond 24-hours will result in
++ * interrupts at given time, everyday till actual alarm-date.
++ * From hardware perspective, it's still a valid interrupt,
++ * hence need to return IRQ_HANDLED. */
++ if (ret)
++ rtc_update_irq(p, 1, irqstat);
++
+ return IRQ_HANDLED;
++ } else {
++ pr_err("vRTC: error in IRQ handler\n");
++ return IRQ_NONE;
+ }
+- return IRQ_NONE;
+ }
+
+-static int vrtc_mrst_do_probe(struct device *dev, struct resource *iomem,
+- int rtc_irq)
++static int
++vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, int rtc_irq)
+ {
+ int retval = 0;
+ unsigned char rtc_control;
+@@ -335,8 +437,9 @@ static int vrtc_mrst_do_probe(struct device *dev, struct resource *iomem,
+ if (!iomem)
+ return -ENODEV;
+
+- iomem = request_mem_region(iomem->start, resource_size(iomem),
+- driver_name);
++ iomem = request_mem_region(iomem->start,
++ iomem->end + 1 - iomem->start,
++ driver_name);
+ if (!iomem) {
+ dev_dbg(dev, "i/o mem already in use.\n");
+ return -EBUSY;
+@@ -364,9 +467,9 @@ static int vrtc_mrst_do_probe(struct device *dev, struct resource *iomem,
+ if (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY)))
+ dev_dbg(dev, "TODO: support more than 24-hr BCD mode\n");
+
+- if (rtc_irq) {
++ if (is_valid_irq(rtc_irq)) {
+ retval = request_irq(rtc_irq, mrst_rtc_irq,
+- 0, dev_name(&mrst_rtc.rtc->dev),
++ IRQF_NO_SUSPEND, dev_name(&mrst_rtc.rtc->dev),
+ mrst_rtc.rtc);
+ if (retval < 0) {
+ dev_dbg(dev, "IRQ %d is already in use, err %d\n",
+@@ -374,7 +477,30 @@ static int vrtc_mrst_do_probe(struct device *dev, struct resource *iomem,
+ goto cleanup1;
+ }
+ }
+- dev_dbg(dev, "initialised\n");
++
++ /* make RTC device wake capable from sleep */
++ device_init_wakeup(dev, true);
++
++ if ((__intel_mid_cpu_chip == INTEL_MID_CPU_CHIP_PENWELL) ||
++ (__intel_mid_cpu_chip == INTEL_MID_CPU_CHIP_CLOVERVIEW)) {
++ retval = rpmsg_send_command(vrtc_mrst_instance,
++ IPCMSG_GET_HOBADDR, 0, NULL, &oshob_base, 0, 1);
++ if (retval < 0) {
++ dev_dbg(dev,
++ "Unable to get OSHOB base address, err %d\n",
++ retval);
++ goto cleanup1;
++ }
++
++ oshob_addr = ioremap_nocache(oshob_base+OSHOB_ALARM_OFFSET, 4);
++ if (!oshob_addr) {
++ dev_dbg(dev, "Unable to do ioremap for OSHOB\n");
++ retval = -ENOMEM;
++ goto cleanup1;
++ }
++ }
++
++ dev_info(dev, "vRTC driver initialised\n");
+ return 0;
+
+ cleanup1:
+@@ -401,9 +527,15 @@ static void rtc_mrst_do_remove(struct device *dev)
+
+ rtc_mrst_do_shutdown();
+
+- if (mrst->irq)
++ if (is_valid_irq(mrst->irq))
+ free_irq(mrst->irq, mrst->rtc);
+
++ if ((__intel_mid_cpu_chip == INTEL_MID_CPU_CHIP_PENWELL) ||
++ (__intel_mid_cpu_chip == INTEL_MID_CPU_CHIP_CLOVERVIEW)) {
++ if (oshob_addr != NULL)
++ iounmap(oshob_addr);
++ }
++
+ rtc_device_unregister(mrst->rtc);
+ mrst->rtc = NULL;
+
+@@ -416,7 +548,7 @@ static void rtc_mrst_do_remove(struct device *dev)
+ }
+
+ #ifdef CONFIG_PM
+-static int mrst_suspend(struct device *dev, pm_message_t mesg)
++static int mrst_suspend(struct device *dev)
+ {
+ struct mrst_rtc *mrst = dev_get_drvdata(dev);
+ unsigned char tmp;
+@@ -455,7 +587,7 @@ static int mrst_suspend(struct device *dev, pm_message_t mesg)
+ */
+ static inline int mrst_poweroff(struct device *dev)
+ {
+- return mrst_suspend(dev, PMSG_HIBERNATE);
++ return mrst_suspend(dev);
+ }
+
+ static int mrst_resume(struct device *dev)
+@@ -478,7 +610,7 @@ static int mrst_resume(struct device *dev)
+
+ mask = vrtc_cmos_read(RTC_INTR_FLAGS);
+ mask &= (tmp & RTC_IRQMASK) | RTC_IRQF;
+- if (!is_intr(mask))
++ if (!(is_intr(mask) && is_valid_af(mask)))
+ break;
+
+ rtc_update_irq(mrst->rtc, 1, mask);
+@@ -526,18 +658,102 @@ static void vrtc_mrst_platform_shutdown(struct platform_device *pdev)
+
+ MODULE_ALIAS("platform:vrtc_mrst");
+
++static const struct dev_pm_ops vrtc_mrst_platform_driver_pm_ops = {
++ .suspend = mrst_suspend,
++ .resume = mrst_resume,
++};
++
+ static struct platform_driver vrtc_mrst_platform_driver = {
+ .probe = vrtc_mrst_platform_probe,
+ .remove = vrtc_mrst_platform_remove,
+ .shutdown = vrtc_mrst_platform_shutdown,
+- .driver = {
+- .name = (char *) driver_name,
+- .suspend = mrst_suspend,
+- .resume = mrst_resume,
++ .driver.name = (char *) driver_name,
++ .driver.pm = &vrtc_mrst_platform_driver_pm_ops,
++};
++
++static int vrtc_mrst_init(void)
++{
++ return platform_driver_register(&vrtc_mrst_platform_driver);
++}
++
++static void vrtc_mrst_exit(void)
++{
++ platform_driver_unregister(&vrtc_mrst_platform_driver);
++}
++
++static int vrtc_mrst_rpmsg_probe(struct rpmsg_channel *rpdev)
++{
++ int ret;
++
++ if (rpdev == NULL) {
++ pr_err("vrtc_mrst rpmsg channel not created\n");
++ ret = -ENODEV;
++ goto out;
+ }
++
++ dev_info(&rpdev->dev, "Probed vrtc_mrst rpmsg device\n");
++
++ /* Allocate rpmsg instance for fw_update*/
++ ret = alloc_rpmsg_instance(rpdev, &vrtc_mrst_instance);
++ if (!vrtc_mrst_instance) {
++ dev_err(&rpdev->dev, "kzalloc vrtc_mrst instance failed\n");
++ goto out;
++ }
++
++ /* Initialize rpmsg instance */
++ init_rpmsg_instance(vrtc_mrst_instance);
++
++ ret = vrtc_mrst_init();
++ if (ret)
++ free_rpmsg_instance(rpdev, &vrtc_mrst_instance);
++
++out:
++ return ret;
++}
++
++static void vrtc_mrst_rpmsg_remove(struct rpmsg_channel *rpdev)
++{
++ vrtc_mrst_exit();
++ free_rpmsg_instance(rpdev, &vrtc_mrst_instance);
++ dev_info(&rpdev->dev, "Removed vrtc_mrst rpmsg device\n");
++}
++
++static void vrtc_mrst_rpmsg_cb(struct rpmsg_channel *rpdev, void *data,
++ int len, void *priv, u32 src)
++{
++ dev_warn(&rpdev->dev, "unexpected, message\n");
++
++ print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
++ data, len, true);
++}
++
++static struct rpmsg_device_id vrtc_mrst_rpmsg_id_table[] = {
++ { .name = "rpmsg_vrtc" },
++ { },
++};
++MODULE_DEVICE_TABLE(rpmsg, vrtc_mrst_rpmsg_id_table);
++
++static struct rpmsg_driver vrtc_mrst_rpmsg = {
++ .drv.name = KBUILD_MODNAME,
++ .drv.owner = THIS_MODULE,
++ .id_table = vrtc_mrst_rpmsg_id_table,
++ .probe = vrtc_mrst_rpmsg_probe,
++ .callback = vrtc_mrst_rpmsg_cb,
++ .remove = vrtc_mrst_rpmsg_remove,
+ };
+
+-module_platform_driver(vrtc_mrst_platform_driver);
++static int __init vrtc_mrst_rpmsg_init(void)
++{
++ return register_rpmsg_driver(&vrtc_mrst_rpmsg);
++}
++
++static void __exit vrtc_mrst_rpmsg_exit(void)
++{
++ return unregister_rpmsg_driver(&vrtc_mrst_rpmsg);
++}
++
++module_init(vrtc_mrst_rpmsg_init);
++module_exit(vrtc_mrst_rpmsg_exit);
+
+ MODULE_AUTHOR("Jacob Pan; Feng Tang");
+ MODULE_DESCRIPTION("Driver for Moorestown virtual RTC");
+diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
+index 92a9345..1c0ce9e 100644
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -198,6 +198,15 @@ config SPI_IMX
+ This enables using the Freescale i.MX SPI controllers in master
+ mode.
+
++config SPI_INTEL_MID_SSP
++ tristate "SSP SPI controller driver for Intel MID platforms (EXPERIMENTAL)"
++ depends on SPI_MASTER && INTEL_MID_DMAC
++ help
++ This is the unified SSP SPI slave controller driver for the Intel
++ MID platforms (Moorestown, Medfield, Clovertrial and
++ Merrifield), primarily used to implement a SPI host controller
++ driver over a SSP host controller.
++
+ config SPI_LM70_LLP
+ tristate "Parallel port adapter for LM70 eval board (DEVELOPMENT)"
+ depends on PARPORT
+diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
+index 33f9c09..1ab0e90 100644
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -35,6 +35,7 @@ obj-$(CONFIG_SPI_FSL_ESPI) += spi-fsl-espi.o
+ obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o
+ obj-$(CONFIG_SPI_GPIO) += spi-gpio.o
+ obj-$(CONFIG_SPI_IMX) += spi-imx.o
++obj-$(CONFIG_SPI_INTEL_MID_SSP) += intel_mid_ssp_spi.o
+ obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o
+ obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mpc512x-psc.o
+ obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o
+diff --git a/drivers/spi/intel_mid_ssp_spi.c b/drivers/spi/intel_mid_ssp_spi.c
+new file mode 100644
+index 0000000..5880718
+--- /dev/null
++++ b/drivers/spi/intel_mid_ssp_spi.c
+@@ -0,0 +1,1642 @@
++/*
++ * intel_mid_ssp_spi.c
++ * This driver supports Bulverde SSP core used on Intel MID platforms
++ * It supports SSP of Moorestown & Medfield platforms and handles clock
++ * slave & master modes.
++ *
++ * Copyright (c) 2010, Intel Corporation.
++ * Ken Mills <ken.k.mills@intel.com>
++ * Sylvain Centelles <sylvain.centelles@intel.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++/*
++ * Note:
++ *
++ * Supports DMA and non-interrupt polled transfers.
++ *
++ */
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/highmem.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/dma-mapping.h>
++#include <linux/intel_mid_dma.h>
++#include <linux/pm_qos.h>
++#include <linux/pm_runtime.h>
++#include <linux/completion.h>
++#include <asm/intel-mid.h>
++
++#include <linux/spi/spi.h>
++#include <linux/spi/intel_mid_ssp_spi.h>
++
++#define DRIVER_NAME "intel_mid_ssp_spi_unified"
++
++MODULE_AUTHOR("Ken Mills");
++MODULE_DESCRIPTION("Bulverde SSP core SPI contoller");
++MODULE_LICENSE("GPL");
++
++static int ssp_timing_wr;
++
++#ifdef DUMP_RX
++static void dump_trailer(const struct device *dev, char *buf, int len, int sz)
++{
++ int tlen1 = (len < sz ? len : sz);
++ int tlen2 = ((len - sz) > sz) ? sz : (len - sz);
++ unsigned char *p;
++ static char msg[MAX_SPI_TRANSFER_SIZE];
++
++ memset(msg, '\0', sizeof(msg));
++ p = buf;
++ while (p < buf + tlen1)
++ sprintf(msg, "%s%02x", msg, (unsigned int)*p++);
++
++ if (tlen2 > 0) {
++ sprintf(msg, "%s .....", msg);
++ p = (buf+len) - tlen2;
++ while (p < buf + len)
++ sprintf(msg, "%s%02x", msg, (unsigned int)*p++);
++ }
++
++ dev_info(dev, "DUMP: %p[0:%d ... %d:%d]:%s", buf, tlen1 - 1,
++ len-tlen2, len - 1, msg);
++}
++#endif
++
++static inline u8 ssp_cfg_get_mode(u8 ssp_cfg)
++{
++ if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER ||
++ intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_ANNIEDALE)
++ return (ssp_cfg) & 0x03;
++ else
++ return (ssp_cfg) & 0x07;
++}
++
++static inline u8 ssp_cfg_get_spi_bus_nb(u8 ssp_cfg)
++{
++ if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER ||
++ intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_ANNIEDALE)
++ return ((ssp_cfg) >> 2) & 0x07;
++ else
++ return ((ssp_cfg) >> 3) & 0x07;
++}
++
++static inline u8 ssp_cfg_is_spi_slave(u8 ssp_cfg)
++{
++ if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER ||
++ intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_ANNIEDALE)
++ return (ssp_cfg) & 0x20;
++ else
++ return (ssp_cfg) & 0x40;
++}
++
++static inline u32 is_tx_fifo_empty(struct ssp_drv_context *sspc)
++{
++ u32 sssr;
++ sssr = read_SSSR(sspc->ioaddr);
++ if ((sssr & SSSR_TFL_MASK) || (sssr & SSSR_TNF) == 0)
++ return 0;
++ else
++ return 1;
++}
++
++static inline u32 is_rx_fifo_empty(struct ssp_drv_context *sspc)
++{
++ return ((read_SSSR(sspc->ioaddr) & SSSR_RNE) == 0);
++}
++
++static inline void disable_interface(struct ssp_drv_context *sspc)
++{
++ void *reg = sspc->ioaddr;
++ write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
++}
++
++static inline void disable_triggers(struct ssp_drv_context *sspc)
++{
++ void *reg = sspc->ioaddr;
++ write_SSCR1(read_SSCR1(reg) & ~sspc->cr1_sig, reg);
++}
++
++
++static void flush(struct ssp_drv_context *sspc)
++{
++ void *reg = sspc->ioaddr;
++ u32 i = 0;
++
++ /* If the transmit fifo is not empty, reset the interface. */
++ if (!is_tx_fifo_empty(sspc)) {
++ dev_err(&sspc->pdev->dev, "TX FIFO not empty. Reset of SPI IF");
++ disable_interface(sspc);
++ return;
++ }
++
++ dev_dbg(&sspc->pdev->dev, " SSSR=%x\r\n", read_SSSR(reg));
++ while (!is_rx_fifo_empty(sspc) && (i < SPI_FIFO_SIZE + 1)) {
++ read_SSDR(reg);
++ i++;
++ }
++ WARN(i > 0, "%d words flush occured\n", i);
++
++ return;
++}
++
++static int null_writer(struct ssp_drv_context *sspc)
++{
++ void *reg = sspc->ioaddr;
++ u8 n_bytes = sspc->n_bytes;
++
++ if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
++ || (sspc->tx == sspc->tx_end))
++ return 0;
++
++ write_SSDR(0, reg);
++ sspc->tx += n_bytes;
++
++ return 1;
++}
++
++static int null_reader(struct ssp_drv_context *sspc)
++{
++ void *reg = sspc->ioaddr;
++ u8 n_bytes = sspc->n_bytes;
++
++ while ((read_SSSR(reg) & SSSR_RNE)
++ && (sspc->rx < sspc->rx_end)) {
++ read_SSDR(reg);
++ sspc->rx += n_bytes;
++ }
++
++ return sspc->rx == sspc->rx_end;
++}
++
++static int u8_writer(struct ssp_drv_context *sspc)
++{
++ void *reg = sspc->ioaddr;
++ if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
++ || (sspc->tx == sspc->tx_end))
++ return 0;
++
++ write_SSDR(*(u8 *)(sspc->tx), reg);
++ ++sspc->tx;
++
++ return 1;
++}
++
++static int u8_reader(struct ssp_drv_context *sspc)
++{
++ void *reg = sspc->ioaddr;
++ while ((read_SSSR(reg) & SSSR_RNE)
++ && (sspc->rx < sspc->rx_end)) {
++ *(u8 *)(sspc->rx) = read_SSDR(reg);
++ ++sspc->rx;
++ }
++
++ return sspc->rx == sspc->rx_end;
++}
++
++static int u16_writer(struct ssp_drv_context *sspc)
++{
++ void *reg = sspc->ioaddr;
++ if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
++ || (sspc->tx == sspc->tx_end))
++ return 0;
++
++ write_SSDR(*(u16 *)(sspc->tx), reg);
++ sspc->tx += 2;
++
++ return 1;
++}
++
++static int u16_reader(struct ssp_drv_context *sspc)
++{
++ void *reg = sspc->ioaddr;
++ while ((read_SSSR(reg) & SSSR_RNE) && (sspc->rx < sspc->rx_end)) {
++ *(u16 *)(sspc->rx) = read_SSDR(reg);
++ sspc->rx += 2;
++ }
++
++ return sspc->rx == sspc->rx_end;
++}
++
++static int u32_writer(struct ssp_drv_context *sspc)
++{
++ void *reg = sspc->ioaddr;
++ if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
++ || (sspc->tx == sspc->tx_end))
++ return 0;
++
++ write_SSDR(*(u32 *)(sspc->tx), reg);
++ sspc->tx += 4;
++
++ return 1;
++}
++
++static int u32_reader(struct ssp_drv_context *sspc)
++{
++ void *reg = sspc->ioaddr;
++ while ((read_SSSR(reg) & SSSR_RNE) && (sspc->rx < sspc->rx_end)) {
++ *(u32 *)(sspc->rx) = read_SSDR(reg);
++ sspc->rx += 4;
++ }
++
++ return sspc->rx == sspc->rx_end;
++}
++
++static bool chan_filter(struct dma_chan *chan, void *param)
++{
++ struct ssp_drv_context *sspc = param;
++ bool ret = false;
++
++ if (!sspc->dmac1)
++ return ret;
++
++ if (chan->device->dev == &sspc->dmac1->dev)
++ ret = true;
++
++ return ret;
++}
++
++/**
++ * unmap_dma_buffers() - Unmap the DMA buffers used during the last transfer.
++ * @sspc: Pointer to the private driver context
++ */
++static void unmap_dma_buffers(struct ssp_drv_context *sspc)
++{
++ struct device *dev = &sspc->pdev->dev;
++
++ if (!sspc->dma_mapped)
++ return;
++ dma_unmap_single(dev, sspc->rx_dma, sspc->len, PCI_DMA_FROMDEVICE);
++ dma_unmap_single(dev, sspc->tx_dma, sspc->len, PCI_DMA_TODEVICE);
++ sspc->dma_mapped = 0;
++}
++
++/**
++ * intel_mid_ssp_spi_dma_done() - End of DMA transfer callback
++ * @arg: Pointer to the data provided at callback registration
++ *
++ * This function is set as callback for both RX and TX DMA transfers. The
++ * RX or TX 'done' flag is set acording to the direction of the ended
++ * transfer. Then, if both RX and TX flags are set, it means that the
++ * transfer job is completed.
++ */
++static void intel_mid_ssp_spi_dma_done(void *arg)
++{
++ struct callback_param *cb_param = (struct callback_param *)arg;
++ struct ssp_drv_context *sspc = cb_param->drv_context;
++ struct device *dev = &sspc->pdev->dev;
++ void *reg = sspc->ioaddr;
++
++ if (cb_param->direction == TX_DIRECTION) {
++ dma_sync_single_for_cpu(dev, sspc->tx_dma,
++ sspc->len, DMA_TO_DEVICE);
++ sspc->txdma_done = 1;
++ } else {
++ sspc->rxdma_done = 1;
++ dma_sync_single_for_cpu(dev, sspc->rx_dma,
++ sspc->len, DMA_FROM_DEVICE);
++ }
++
++ dev_dbg(dev, "DMA callback for direction %d [RX done:%d] [TX done:%d]\n",
++ cb_param->direction, sspc->rxdma_done,
++ sspc->txdma_done);
++
++ if (sspc->txdma_done && sspc->rxdma_done) {
++ /* Clear Status Register */
++ write_SSSR(sspc->clear_sr, reg);
++ dev_dbg(dev, "DMA done\n");
++ /* Disable Triggers to DMA or to CPU*/
++ disable_triggers(sspc);
++ unmap_dma_buffers(sspc);
++
++ queue_work(sspc->dma_wq, &sspc->complete_work);
++ }
++}
++
++/**
++ * intel_mid_ssp_spi_dma_init() - Initialize DMA
++ * @sspc: Pointer to the private driver context
++ *
++ * This function is called at driver setup phase to allocate DMA
++ * ressources.
++ */
++static void intel_mid_ssp_spi_dma_init(struct ssp_drv_context *sspc)
++{
++ struct intel_mid_dma_slave *rxs, *txs;
++ struct dma_slave_config *ds;
++ dma_cap_mask_t mask;
++ struct device *dev = &sspc->pdev->dev;
++ unsigned int device_id;
++
++ /* Configure RX channel parameters */
++ rxs = &sspc->dmas_rx;
++ ds = &rxs->dma_slave;
++
++ ds->direction = DMA_FROM_DEVICE;
++ rxs->hs_mode = LNW_DMA_HW_HS;
++ rxs->cfg_mode = LNW_DMA_PER_TO_MEM;
++ ds->dst_addr_width = sspc->n_bytes;
++ ds->src_addr_width = sspc->n_bytes;
++
++ if (sspc->quirks & QUIRKS_PLATFORM_BYT) {
++ /*These are fixed HW info from Baytrail datasheet*/
++ rxs->device_instance = 1; /*DMA Req line*/
++ } else if (sspc->quirks & QUIRKS_PLATFORM_MRFL)
++ rxs->device_instance = sspc->master->bus_num;
++ else
++ rxs->device_instance = 0;
++
++ /* Use a DMA burst according to the FIFO thresholds */
++ if (sspc->rx_fifo_threshold == 8) {
++ ds->src_maxburst = LNW_DMA_MSIZE_8;
++ ds->dst_maxburst = LNW_DMA_MSIZE_8;
++ } else if (sspc->rx_fifo_threshold == 4) {
++ ds->src_maxburst = LNW_DMA_MSIZE_4;
++ ds->dst_maxburst = LNW_DMA_MSIZE_4;
++ } else {
++ ds->src_maxburst = LNW_DMA_MSIZE_1;
++ ds->dst_maxburst = LNW_DMA_MSIZE_1;
++ }
++
++ /* Configure TX channel parameters */
++ txs = &sspc->dmas_tx;
++ ds = &txs->dma_slave;
++
++ ds->direction = DMA_TO_DEVICE;
++ txs->hs_mode = LNW_DMA_HW_HS;
++ txs->cfg_mode = LNW_DMA_MEM_TO_PER;
++ ds->src_addr_width = sspc->n_bytes;
++ ds->dst_addr_width = sspc->n_bytes;
++
++ if (sspc->quirks & QUIRKS_PLATFORM_BYT) {
++ /*These are fixed HW info from Baytrail datasheet*/
++ txs->device_instance = 0;/*DMA Req Line*/
++ } else if (sspc->quirks & QUIRKS_PLATFORM_MRFL)
++ txs->device_instance = sspc->master->bus_num;
++ else
++ txs->device_instance = 0;
++
++ /* Use a DMA burst according to the FIFO thresholds */
++ if (sspc->rx_fifo_threshold == 8) {
++ ds->src_maxburst = LNW_DMA_MSIZE_8;
++ ds->dst_maxburst = LNW_DMA_MSIZE_8;
++ } else if (sspc->rx_fifo_threshold == 4) {
++ ds->src_maxburst = LNW_DMA_MSIZE_4;
++ ds->dst_maxburst = LNW_DMA_MSIZE_4;
++ } else {
++ ds->src_maxburst = LNW_DMA_MSIZE_1;
++ ds->dst_maxburst = LNW_DMA_MSIZE_1;
++ }
++
++ /* Nothing more to do if already initialized */
++ if (sspc->dma_initialized)
++ return;
++
++ /* Use DMAC1 */
++ if (sspc->quirks & QUIRKS_PLATFORM_MRST)
++ device_id = PCI_MRST_DMAC1_ID;
++ else if (sspc->quirks & QUIRKS_PLATFORM_BYT)
++ device_id = PCI_BYT_DMAC1_ID;
++ else if (sspc->quirks & QUIRKS_PLATFORM_MRFL)
++ device_id = PCI_MRFL_DMAC_ID;
++ else
++ device_id = PCI_MDFL_DMAC1_ID;
++
++ sspc->dmac1 = pci_get_device(PCI_VENDOR_ID_INTEL, device_id, NULL);
++ if (!sspc->dmac1) {
++ dev_err(dev, "Can't find DMAC1");
++ return;
++ }
++
++ if (sspc->quirks & QUIRKS_SRAM_ADDITIONAL_CPY) {
++ sspc->virt_addr_sram_rx = ioremap_nocache(SRAM_BASE_ADDR,
++ 2 * MAX_SPI_TRANSFER_SIZE);
++ if (sspc->virt_addr_sram_rx)
++ sspc->virt_addr_sram_tx = sspc->virt_addr_sram_rx +
++ MAX_SPI_TRANSFER_SIZE;
++ else
++ dev_err(dev, "Virt_addr_sram_rx is null\n");
++ }
++
++ /* 1. Allocate rx channel */
++ dma_cap_zero(mask);
++ dma_cap_set(DMA_MEMCPY, mask);
++ dma_cap_set(DMA_SLAVE, mask);
++
++ sspc->rxchan = dma_request_channel(mask, chan_filter, sspc);
++ if (!sspc->rxchan)
++ goto err_exit;
++
++ sspc->rxchan->private = rxs;
++
++ /* 2. Allocate tx channel */
++ dma_cap_set(DMA_SLAVE, mask);
++ dma_cap_set(DMA_MEMCPY, mask);
++
++ sspc->txchan = dma_request_channel(mask, chan_filter, sspc);
++ if (!sspc->txchan)
++ goto free_rxchan;
++ else
++ sspc->txchan->private = txs;
++
++ /* set the dma done bit to 1 */
++ sspc->txdma_done = 1;
++ sspc->rxdma_done = 1;
++
++ sspc->tx_param.drv_context = sspc;
++ sspc->tx_param.direction = TX_DIRECTION;
++ sspc->rx_param.drv_context = sspc;
++ sspc->rx_param.direction = RX_DIRECTION;
++
++ sspc->dma_initialized = 1;
++ return;
++
++free_rxchan:
++ dma_release_channel(sspc->rxchan);
++err_exit:
++ dev_err(dev, "Error : DMA Channel Not available\n");
++
++ if (sspc->quirks & QUIRKS_SRAM_ADDITIONAL_CPY)
++ iounmap(sspc->virt_addr_sram_rx);
++
++ pci_dev_put(sspc->dmac1);
++ return;
++}
++
++/**
++ * intel_mid_ssp_spi_dma_exit() - Release DMA ressources
++ * @sspc: Pointer to the private driver context
++ */
++static void intel_mid_ssp_spi_dma_exit(struct ssp_drv_context *sspc)
++{
++ dma_release_channel(sspc->txchan);
++ dma_release_channel(sspc->rxchan);
++
++ if (sspc->quirks & QUIRKS_SRAM_ADDITIONAL_CPY)
++ iounmap(sspc->virt_addr_sram_rx);
++
++ pci_dev_put(sspc->dmac1);
++}
++
++/**
++ * dma_transfer() - Initiate a DMA transfer
++ * @sspc: Pointer to the private driver context
++ */
++static void dma_transfer(struct ssp_drv_context *sspc)
++{
++ dma_addr_t ssdr_addr;
++ struct dma_async_tx_descriptor *txdesc = NULL, *rxdesc = NULL;
++ struct dma_chan *txchan, *rxchan;
++ enum dma_ctrl_flags flag;
++ struct device *dev = &sspc->pdev->dev;
++
++ /* get Data Read/Write address */
++ ssdr_addr = (dma_addr_t)(sspc->paddr + 0x10);
++
++ if (sspc->tx_dma)
++ sspc->txdma_done = 0;
++
++ if (sspc->rx_dma)
++ sspc->rxdma_done = 0;
++
++ /* 2. prepare the RX dma transfer */
++ txchan = sspc->txchan;
++ rxchan = sspc->rxchan;
++
++ flag = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
++
++ if (likely(sspc->quirks & QUIRKS_DMA_USE_NO_TRAIL)) {
++ /* Since the DMA is configured to do 32bits access */
++ /* to/from the DDR, the DMA transfer size must be */
++ /* a multiple of 4 bytes */
++ sspc->len_dma_rx = sspc->len & ~(4 - 1);
++ sspc->len_dma_tx = sspc->len_dma_rx;
++
++ /* In Rx direction, TRAIL Bytes are handled by memcpy */
++ if (sspc->rx_dma &&
++ (sspc->len_dma_rx >
++ sspc->rx_fifo_threshold * sspc->n_bytes))
++ sspc->len_dma_rx = TRUNCATE(sspc->len_dma_rx,
++ sspc->rx_fifo_threshold * sspc->n_bytes);
++ else if (!sspc->rx_dma)
++ dev_err(dev, "ERROR : rx_dma is null\r\n");
++ } else {
++ /* TRAIL Bytes are handled by DMA */
++ if (sspc->rx_dma) {
++ sspc->len_dma_rx = sspc->len;
++ sspc->len_dma_tx = sspc->len;
++ } else
++ dev_err(dev, "ERROR : sspc->rx_dma is null!\n");
++ }
++
++ sspc->dmas_rx.dma_slave.src_addr = ssdr_addr;
++ rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG,
++ (unsigned long)&(sspc->dmas_rx.dma_slave));
++ dma_sync_single_for_device(dev, sspc->rx_dma,
++ sspc->len, DMA_FROM_DEVICE);
++
++ rxdesc = rxchan->device->device_prep_dma_memcpy
++ (rxchan, /* DMA Channel */
++ sspc->rx_dma, /* DAR */
++ ssdr_addr, /* SAR */
++ sspc->len_dma_rx, /* Data Length */
++ flag); /* Flag */
++
++ if (rxdesc) {
++ rxdesc->callback = intel_mid_ssp_spi_dma_done;
++ rxdesc->callback_param = &sspc->rx_param;
++ } else {
++ dev_dbg(dev, "rxdesc is null! (len_dma_rx:%d)\n",
++ sspc->len_dma_rx);
++ sspc->rxdma_done = 1;
++ }
++
++ /* 3. prepare the TX dma transfer */
++ sspc->dmas_tx.dma_slave.dst_addr = ssdr_addr;
++ txchan->device->device_control(txchan, DMA_SLAVE_CONFIG,
++ (unsigned long)&(sspc->dmas_tx.dma_slave));
++ dma_sync_single_for_device(dev, sspc->tx_dma,
++ sspc->len, DMA_TO_DEVICE);
++
++ if (sspc->tx_dma) {
++ txdesc = txchan->device->device_prep_dma_memcpy
++ (txchan, /* DMA Channel */
++ ssdr_addr, /* DAR */
++ sspc->tx_dma, /* SAR */
++ sspc->len_dma_tx, /* Data Length */
++ flag); /* Flag */
++ if (txdesc) {
++ txdesc->callback = intel_mid_ssp_spi_dma_done;
++ txdesc->callback_param = &sspc->tx_param;
++ } else {
++ dev_dbg(dev, "txdesc is null! (len_dma_tx:%d)\n",
++ sspc->len_dma_tx);
++ sspc->txdma_done = 1;
++ }
++ } else {
++ dev_err(dev, "ERROR : sspc->tx_dma is null!\n");
++ return;
++ }
++
++ dev_dbg(dev, "DMA transfer len:%d len_dma_tx:%d len_dma_rx:%d\n",
++ sspc->len, sspc->len_dma_tx, sspc->len_dma_rx);
++
++ if (rxdesc || txdesc) {
++ if (rxdesc) {
++ dev_dbg(dev, "Firing DMA RX channel\n");
++ rxdesc->tx_submit(rxdesc);
++ }
++ if (txdesc) {
++ dev_dbg(dev, "Firing DMA TX channel\n");
++ txdesc->tx_submit(txdesc);
++ }
++ } else {
++ struct callback_param cb_param;
++ cb_param.drv_context = sspc;
++ dev_dbg(dev, "Bypassing DMA transfer\n");
++ intel_mid_ssp_spi_dma_done(&cb_param);
++ }
++}
++
++/**
++ * map_dma_buffers() - Map DMA buffer before a transfer
++ * @sspc: Pointer to the private drivzer context
++ */
++static int map_dma_buffers(struct ssp_drv_context *sspc)
++{
++ struct device *dev = &sspc->pdev->dev;
++
++ if (unlikely(sspc->dma_mapped)) {
++ dev_err(dev, "ERROR : DMA buffers already mapped\n");
++ return 0;
++ }
++ if (unlikely(sspc->quirks & QUIRKS_SRAM_ADDITIONAL_CPY)) {
++ /* Copy sspc->tx into sram_tx */
++ memcpy_toio(sspc->virt_addr_sram_tx, sspc->tx, sspc->len);
++#ifdef DUMP_RX
++ dump_trailer(&sspc->pdev->dev, sspc->tx, sspc->len, 16);
++#endif
++ sspc->rx_dma = SRAM_RX_ADDR;
++ sspc->tx_dma = SRAM_TX_ADDR;
++ } else {
++ /* no QUIRKS_SRAM_ADDITIONAL_CPY */
++ if (unlikely(sspc->dma_mapped))
++ return 1;
++
++ sspc->tx_dma = dma_map_single(dev, sspc->tx, sspc->len,
++ PCI_DMA_TODEVICE);
++ if (unlikely(dma_mapping_error(dev, sspc->tx_dma))) {
++ dev_err(dev, "ERROR : tx dma mapping failed\n");
++ return 0;
++ }
++
++ sspc->rx_dma = dma_map_single(dev, sspc->rx, sspc->len,
++ PCI_DMA_FROMDEVICE);
++ if (unlikely(dma_mapping_error(dev, sspc->rx_dma))) {
++ dma_unmap_single(dev, sspc->tx_dma,
++ sspc->len, DMA_TO_DEVICE);
++ dev_err(dev, "ERROR : rx dma mapping failed\n");
++ return 0;
++ }
++ }
++ return 1;
++}
++
++/**
++ * drain_trail() - Handle trailing bytes of a transfer
++ * @sspc: Pointer to the private driver context
++ *
++ * This function handles the trailing bytes of a transfer for the case
++ * they are not handled by the DMA.
++ */
++void drain_trail(struct ssp_drv_context *sspc)
++{
++ struct device *dev = &sspc->pdev->dev;
++ void *reg = sspc->ioaddr;
++
++ if (sspc->len != sspc->len_dma_rx) {
++ dev_dbg(dev, "Handling trailing bytes. SSSR:%08x\n",
++ read_SSSR(reg));
++ sspc->rx += sspc->len_dma_rx;
++ sspc->tx += sspc->len_dma_tx;
++
++ while ((sspc->tx != sspc->tx_end) ||
++ (sspc->rx != sspc->rx_end)) {
++ sspc->read(sspc);
++ sspc->write(sspc);
++ }
++ }
++}
++
++/**
++ * sram_to_ddr_cpy() - Copy data from Langwell SDRAM to DDR
++ * @sspc: Pointer to the private driver context
++ */
++static void sram_to_ddr_cpy(struct ssp_drv_context *sspc)
++{
++ u32 length = sspc->len;
++
++ if ((sspc->quirks & QUIRKS_DMA_USE_NO_TRAIL)
++ && (sspc->len > sspc->rx_fifo_threshold * sspc->n_bytes))
++ length = TRUNCATE(sspc->len,
++ sspc->rx_fifo_threshold * sspc->n_bytes);
++
++ memcpy_fromio(sspc->rx, sspc->virt_addr_sram_rx, length);
++}
++
++static void int_transfer_complete(struct ssp_drv_context *sspc)
++{
++ void *reg = sspc->ioaddr;
++ struct spi_message *msg;
++ struct device *dev = &sspc->pdev->dev;
++
++ if (unlikely(sspc->quirks & QUIRKS_USE_PM_QOS))
++ pm_qos_update_request(&sspc->pm_qos_req,
++ PM_QOS_DEFAULT_VALUE);
++
++ if (unlikely(sspc->quirks & QUIRKS_SRAM_ADDITIONAL_CPY))
++ sram_to_ddr_cpy(sspc);
++
++ if (likely(sspc->quirks & QUIRKS_DMA_USE_NO_TRAIL))
++ drain_trail(sspc);
++ else
++ /* Stop getting Time Outs */
++ write_SSTO(0, reg);
++
++ sspc->cur_msg->status = 0;
++ sspc->cur_msg->actual_length = sspc->len;
++
++#ifdef DUMP_RX
++ dump_trailer(dev, sspc->rx, sspc->len, 16);
++#endif
++
++ if (sspc->cs_control)
++ sspc->cs_control(CS_DEASSERT);
++
++ dev_dbg(dev, "End of transfer. SSSR:%08X\n", read_SSSR(reg));
++ msg = sspc->cur_msg;
++ if (likely(msg->complete))
++ msg->complete(msg->context);
++ complete(&sspc->msg_done);
++}
++
++static void int_transfer_complete_work(struct work_struct *work)
++{
++ struct ssp_drv_context *sspc = container_of(work,
++ struct ssp_drv_context, complete_work);
++
++ int_transfer_complete(sspc);
++}
++
++static void poll_transfer_complete(struct ssp_drv_context *sspc)
++{
++ struct spi_message *msg;
++
++ /* Update total byte transfered return count actual bytes read */
++ sspc->cur_msg->actual_length += sspc->len - (sspc->rx_end - sspc->rx);
++
++ sspc->cur_msg->status = 0;
++ if (sspc->cs_control)
++ sspc->cs_control(CS_DEASSERT);
++
++ msg = sspc->cur_msg;
++ if (likely(msg->complete))
++ msg->complete(msg->context);
++ complete(&sspc->msg_done);
++}
++
++/**
++ * ssp_int() - Interrupt handler
++ * @irq
++ * @dev_id
++ *
++ * The SSP interrupt is not used for transfer which are handled by
++ * DMA or polling: only under/over run are catched to detect
++ * broken transfers.
++ */
++static irqreturn_t ssp_int(int irq, void *dev_id)
++{
++ struct ssp_drv_context *sspc = dev_id;
++ void *reg = sspc->ioaddr;
++ struct device *dev = &sspc->pdev->dev;
++ u32 status = read_SSSR(reg);
++
++ /* It should never be our interrupt since SSP will */
++ /* only trigs interrupt for under/over run.*/
++ if (likely(!(status & sspc->mask_sr)))
++ return IRQ_NONE;
++
++ if (status & SSSR_ROR || status & SSSR_TUR) {
++ dev_err(dev, "--- SPI ROR or TUR occurred : SSSR=%x\n", status);
++ WARN_ON(1);
++ if (status & SSSR_ROR)
++ dev_err(dev, "we have Overrun\n");
++ if (status & SSSR_TUR)
++ dev_err(dev, "we have Underrun\n");
++ }
++
++ /* We can fall here when not using DMA mode */
++ if (!sspc->cur_msg) {
++ disable_interface(sspc);
++ disable_triggers(sspc);
++ }
++ /* clear status register */
++ write_SSSR(sspc->clear_sr, reg);
++ return IRQ_HANDLED;
++}
++
++static void poll_transfer(unsigned long data)
++{
++ struct ssp_drv_context *sspc = (void *)data;
++
++ bool delay = false;
++
++ if ((intel_mid_identify_sim() == INTEL_MID_CPU_SIMULATION_VP) ||
++ intel_mid_identify_sim() == INTEL_MID_CPU_SIMULATION_HVP) {
++ delay = true;
++ }
++
++ if (sspc->tx)
++ while (sspc->tx != sspc->tx_end) {
++ /* [REVERT ME] Tangier simulator requires a delay */
++ if (delay)
++ udelay(10);
++ if (ssp_timing_wr) {
++ int timeout = 100;
++ /* It is used as debug UART on Tangier. Since
++ baud rate = 115200, it needs at least 312us
++ for one word transferring. Becuase of silicon
++ issue, it MUST check SFIFOL here instead of
++ TNF. It is the workaround for A0 stepping*/
++ while (--timeout &&
++ ((read_SFIFOL(sspc->ioaddr)) & 0xFFFF))
++ udelay(10);
++ }
++ sspc->write(sspc);
++ sspc->read(sspc);
++ }
++
++ while (!sspc->read(sspc))
++ cpu_relax();
++
++ poll_transfer_complete(sspc);
++}
++
++/**
++ * start_bitbanging() - Clock synchronization by bit banging
++ * @sspc: Pointer to private driver context
++ *
++ * This clock synchronization will be removed as soon as it is
++ * handled by the SCU.
++ */
++static void start_bitbanging(struct ssp_drv_context *sspc)
++{
++ u32 sssr;
++ u32 count = 0;
++ u32 cr0;
++ void *i2c_reg = sspc->I2C_ioaddr;
++ struct device *dev = &sspc->pdev->dev;
++ void *reg = sspc->ioaddr;
++ struct chip_data *chip = spi_get_ctldata(sspc->cur_msg->spi);
++ cr0 = chip->cr0;
++
++ dev_warn(dev, "In %s : Starting bit banging\n",
++ __func__);
++ if (read_SSSR(reg) & SSP_NOT_SYNC)
++ dev_warn(dev, "SSP clock desynchronized.\n");
++ if (!(read_SSCR0(reg) & SSCR0_SSE))
++ dev_warn(dev, "in SSCR0, SSP disabled.\n");
++
++ dev_dbg(dev, "SSP not ready, start CLK sync\n");
++
++ write_SSCR0(cr0 & ~SSCR0_SSE, reg);
++ write_SSPSP(0x02010007, reg);
++
++ write_SSTO(chip->timeout, reg);
++ write_SSCR0(cr0, reg);
++
++ /*
++ * This routine uses the DFx block to override the SSP inputs
++ * and outputs allowing us to bit bang SSPSCLK. On Langwell,
++ * we have to generate the clock to clear busy.
++ */
++ write_I2CDATA(0x3, i2c_reg);
++ udelay(I2C_ACCESS_USDELAY);
++ write_I2CCTRL(0x01070034, i2c_reg);
++ udelay(I2C_ACCESS_USDELAY);
++ write_I2CDATA(0x00000099, i2c_reg);
++ udelay(I2C_ACCESS_USDELAY);
++ write_I2CCTRL(0x01070038, i2c_reg);
++ udelay(I2C_ACCESS_USDELAY);
++ sssr = read_SSSR(reg);
++
++ /* Bit bang the clock until CSS clears */
++ while ((sssr & 0x400000) && (count < MAX_BITBANGING_LOOP)) {
++ write_I2CDATA(0x2, i2c_reg);
++ udelay(I2C_ACCESS_USDELAY);
++ write_I2CCTRL(0x01070034, i2c_reg);
++ udelay(I2C_ACCESS_USDELAY);
++ write_I2CDATA(0x3, i2c_reg);
++ udelay(I2C_ACCESS_USDELAY);
++ write_I2CCTRL(0x01070034, i2c_reg);
++ udelay(I2C_ACCESS_USDELAY);
++ sssr = read_SSSR(reg);
++ count++;
++ }
++ if (count >= MAX_BITBANGING_LOOP)
++ dev_err(dev, "ERROR in %s : infinite loop on bit banging. Aborting\n",
++ __func__);
++
++ dev_dbg(dev, "---Bit bang count=%d\n", count);
++
++ write_I2CDATA(0x0, i2c_reg);
++ udelay(I2C_ACCESS_USDELAY);
++ write_I2CCTRL(0x01070038, i2c_reg);
++}
++
++static unsigned int ssp_get_clk_div(struct ssp_drv_context *sspc, int speed)
++{
++ if (sspc->quirks & QUIRKS_PLATFORM_MRFL)
++ return max(25000000 / speed, 4) - 1;
++ else
++ return max(100000000 / speed, 4) - 1;
++}
++
++/**
++ * transfer() - Start a SPI transfer
++ * @spi: Pointer to the spi_device struct
++ * @msg: Pointer to the spi_message struct
++ */
++static int transfer(struct spi_device *spi, struct spi_message *msg)
++{
++ struct ssp_drv_context *sspc = spi_master_get_devdata(spi->master);
++ unsigned long flags;
++
++ msg->actual_length = 0;
++ msg->status = -EINPROGRESS;
++ spin_lock_irqsave(&sspc->lock, flags);
++ list_add_tail(&msg->queue, &sspc->queue);
++ if (!sspc->suspended)
++ queue_work(sspc->workqueue, &sspc->pump_messages);
++ spin_unlock_irqrestore(&sspc->lock, flags);
++
++ return 0;
++}
++
++static int handle_message(struct ssp_drv_context *sspc)
++{
++ struct chip_data *chip = NULL;
++ struct spi_transfer *transfer = NULL;
++ void *reg = sspc->ioaddr;
++ u32 cr1;
++ struct device *dev = &sspc->pdev->dev;
++ struct spi_message *msg = sspc->cur_msg;
++ u32 clk_div;
++
++ chip = spi_get_ctldata(msg->spi);
++
++ /* We handle only one transfer message since the protocol module has to
++ control the out of band signaling. */
++ transfer = list_entry(msg->transfers.next, struct spi_transfer,
++ transfer_list);
++
++ /* Check transfer length */
++ if (unlikely((transfer->len > MAX_SPI_TRANSFER_SIZE) ||
++ (transfer->len == 0))) {
++ dev_warn(dev, "transfer length null or greater than %d\n",
++ MAX_SPI_TRANSFER_SIZE);
++ dev_warn(dev, "length = %d\n", transfer->len);
++ msg->status = -EINVAL;
++
++ if (msg->complete)
++ msg->complete(msg->context);
++ complete(&sspc->msg_done);
++ return 0;
++ }
++
++ /* Flush any remaining data (in case of failed previous transfer) */
++ flush(sspc);
++
++ sspc->tx = (void *)transfer->tx_buf;
++ sspc->rx = (void *)transfer->rx_buf;
++ sspc->len = transfer->len;
++ sspc->write = chip->write;
++ sspc->read = chip->read;
++ sspc->cs_control = chip->cs_control;
++ sspc->cs_change = transfer->cs_change;
++
++ if (likely(chip->dma_enabled)) {
++ sspc->dma_mapped = map_dma_buffers(sspc);
++ if (unlikely(!sspc->dma_mapped))
++ return 0;
++ } else {
++ sspc->write = sspc->tx ? chip->write : null_writer;
++ sspc->read = sspc->rx ? chip->read : null_reader;
++ }
++ sspc->tx_end = sspc->tx + transfer->len;
++ sspc->rx_end = sspc->rx + transfer->len;
++
++ /* [REVERT ME] Bug in status register clear for Tangier simulation */
++ if ((intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER) ||
++ (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_ANNIEDALE)) {
++ if ((intel_mid_identify_sim() != INTEL_MID_CPU_SIMULATION_VP &&
++ (intel_mid_identify_sim() != INTEL_MID_CPU_SIMULATION_HVP)))
++ write_SSSR(sspc->clear_sr, reg);
++ } else /* Clear status */
++ write_SSSR(sspc->clear_sr, reg);
++
++ /* setup the CR1 control register */
++ cr1 = chip->cr1 | sspc->cr1_sig;
++
++ if (likely(sspc->quirks & QUIRKS_DMA_USE_NO_TRAIL)) {
++ /* in case of len smaller than burst size, adjust the RX */
++ /* threshold. All other cases will use the default threshold */
++ /* value. The RX fifo threshold must be aligned with the DMA */
++ /* RX transfer size, which may be limited to a multiple of 4 */
++ /* bytes due to 32bits DDR access. */
++ if (sspc->len / sspc->n_bytes <= sspc->rx_fifo_threshold) {
++ u32 rx_fifo_threshold;
++
++ rx_fifo_threshold = (sspc->len & ~(4 - 1)) /
++ sspc->n_bytes;
++ cr1 &= ~(SSCR1_RFT);
++ cr1 |= SSCR1_RxTresh(rx_fifo_threshold) & SSCR1_RFT;
++ } else
++ write_SSTO(chip->timeout, reg);
++ }
++
++ dev_dbg(dev, "transfer len:%d n_bytes:%d cr0:%x cr1:%x",
++ sspc->len, sspc->n_bytes, chip->cr0, cr1);
++
++ /* first set CR1 */
++ write_SSCR1(cr1, reg);
++
++ if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER)
++ write_SSFS((1 << chip->chip_select), reg);
++
++ /* recalculate the frequency for each transfer */
++ clk_div = ssp_get_clk_div(sspc, transfer->speed_hz);
++ chip->cr0 |= clk_div << 8;
++
++ /* Do bitbanging only if SSP not-enabled or not-synchronized */
++ if (unlikely(((read_SSSR(reg) & SSP_NOT_SYNC) ||
++ (!(read_SSCR0(reg) & SSCR0_SSE))) &&
++ (sspc->quirks & QUIRKS_BIT_BANGING))) {
++ start_bitbanging(sspc);
++ } else {
++ /* (re)start the SSP */
++ if (ssp_timing_wr) {
++ dev_dbg(dev, "original cr0 before reset:%x",
++ chip->cr0);
++ /*we should not disable TUM and RIM interrup*/
++ write_SSCR0(0x0000000F, reg);
++ chip->cr0 &= ~(SSCR0_SSE);
++ dev_dbg(dev, "reset ssp:cr0:%x", chip->cr0);
++ write_SSCR0(chip->cr0, reg);
++ chip->cr0 |= SSCR0_SSE;
++ dev_dbg(dev, "reset ssp:cr0:%x", chip->cr0);
++ write_SSCR0(chip->cr0, reg);
++ } else
++ write_SSCR0(chip->cr0, reg);
++ }
++
++ if (sspc->cs_control)
++ sspc->cs_control(CS_ASSERT);
++
++ if (likely(chip->dma_enabled)) {
++ if (unlikely(sspc->quirks & QUIRKS_USE_PM_QOS))
++ pm_qos_update_request(&sspc->pm_qos_req,
++ MIN_EXIT_LATENCY);
++ dma_transfer(sspc);
++ } else
++ tasklet_schedule(&sspc->poll_transfer);
++
++ return 0;
++}
++
++static void pump_messages(struct work_struct *work)
++{
++ struct ssp_drv_context *sspc =
++ container_of(work, struct ssp_drv_context, pump_messages);
++ struct device *dev = &sspc->pdev->dev;
++ unsigned long flags;
++ struct spi_message *msg;
++
++ pm_runtime_get_sync(dev);
++ spin_lock_irqsave(&sspc->lock, flags);
++ while (!list_empty(&sspc->queue)) {
++ if (sspc->suspended)
++ break;
++ msg = list_entry(sspc->queue.next, struct spi_message, queue);
++ list_del_init(&msg->queue);
++ sspc->cur_msg = msg;
++ spin_unlock_irqrestore(&sspc->lock, flags);
++ INIT_COMPLETION(sspc->msg_done);
++ handle_message(sspc);
++ wait_for_completion(&sspc->msg_done);
++ spin_lock_irqsave(&sspc->lock, flags);
++ sspc->cur_msg = NULL;
++ }
++ spin_unlock_irqrestore(&sspc->lock, flags);
++ pm_runtime_put(dev);
++}
++
++/**
++ * setup() - Driver setup procedure
++ * @spi: Pointeur to the spi_device struct
++ */
++static int setup(struct spi_device *spi)
++{
++ struct intel_mid_ssp_spi_chip *chip_info = NULL;
++ struct chip_data *chip;
++ struct ssp_drv_context *sspc =
++ spi_master_get_devdata(spi->master);
++ u32 tx_fifo_threshold;
++ u32 burst_size;
++ u32 clk_div;
++ static u32 one_time_setup = 1;
++
++ if (!spi->bits_per_word)
++ spi->bits_per_word = DFLT_BITS_PER_WORD;
++
++ if ((spi->bits_per_word < MIN_BITS_PER_WORD
++ || spi->bits_per_word > MAX_BITS_PER_WORD))
++ return -EINVAL;
++
++ chip = spi_get_ctldata(spi);
++ if (!chip) {
++ chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
++ if (!chip) {
++ dev_err(&spi->dev,
++ "failed setup: can't allocate chip data\n");
++ return -ENOMEM;
++ }
++ }
++ chip->cr0 = SSCR0_Motorola | SSCR0_DataSize(spi->bits_per_word > 16 ?
++ spi->bits_per_word - 16 : spi->bits_per_word)
++ | SSCR0_SSE
++ | (spi->bits_per_word > 16 ? SSCR0_EDSS : 0);
++
++ /* protocol drivers may change the chip settings, so... */
++ /* if chip_info exists, use it */
++ chip_info = spi->controller_data;
++
++ /* chip_info isn't always needed */
++ chip->cr1 = 0;
++ if (chip_info) {
++ burst_size = chip_info->burst_size;
++ if (burst_size > IMSS_FIFO_BURST_8)
++ burst_size = DFLT_FIFO_BURST_SIZE;
++
++ chip->timeout = chip_info->timeout;
++
++ if (chip_info->enable_loopback)
++ chip->cr1 |= SSCR1_LBM;
++
++ chip->dma_enabled = chip_info->dma_enabled;
++ chip->cs_control = chip_info->cs_control;
++
++ /* Request platform-specific gpio and pinmux here since
++ * it is not possible to get the intel_mid_ssp_spi_chip
++ * structure in probe */
++ if (one_time_setup && !chip_info->dma_enabled
++ && chip_info->platform_pinmux) {
++ chip_info->platform_pinmux();
++ one_time_setup = 0;
++ }
++
++ } else {
++ /* if no chip_info provided by protocol driver, */
++ /* set default values */
++ dev_info(&spi->dev, "setting default chip values\n");
++
++ burst_size = DFLT_FIFO_BURST_SIZE;
++ chip->dma_enabled = 1;
++ if (sspc->quirks & QUIRKS_DMA_USE_NO_TRAIL)
++ chip->timeout = 0;
++ else
++ chip->timeout = DFLT_TIMEOUT_VAL;
++ }
++ /* Set FIFO thresholds according to burst_size */
++ if (burst_size == IMSS_FIFO_BURST_8)
++ sspc->rx_fifo_threshold = 8;
++ else if (burst_size == IMSS_FIFO_BURST_4)
++ sspc->rx_fifo_threshold = 4;
++ else
++ sspc->rx_fifo_threshold = 1;
++ /*FIXME:this is workaround.
++ On MRST, in DMA mode, it is very strang that RX fifo can't reach
++ burst size.*/
++ if (sspc->quirks & QUIRKS_PLATFORM_MRFL && chip->dma_enabled)
++ sspc->rx_fifo_threshold = 1;
++ tx_fifo_threshold = SPI_FIFO_SIZE - sspc->rx_fifo_threshold;
++ chip->cr1 |= (SSCR1_RxTresh(sspc->rx_fifo_threshold) &
++ SSCR1_RFT) | (SSCR1_TxTresh(tx_fifo_threshold) & SSCR1_TFT);
++
++ sspc->dma_mapped = 0;
++
++ /* setting phase and polarity. spi->mode comes from boardinfo */
++ if ((spi->mode & SPI_CPHA) != 0)
++ chip->cr1 |= SSCR1_SPH;
++ if ((spi->mode & SPI_CPOL) != 0)
++ chip->cr1 |= SSCR1_SPO;
++
++ if (sspc->quirks & QUIRKS_SPI_SLAVE_CLOCK_MODE)
++ /* set slave mode */
++ chip->cr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR;
++ chip->cr1 |= SSCR1_SCFR; /* clock is not free running */
++
++ dev_dbg(&spi->dev, "%d bits/word, mode %d\n",
++ spi->bits_per_word, spi->mode & 0x3);
++ if (spi->bits_per_word <= 8) {
++ chip->n_bytes = 1;
++ chip->read = u8_reader;
++ chip->write = u8_writer;
++ } else if (spi->bits_per_word <= 16) {
++ chip->n_bytes = 2;
++ chip->read = u16_reader;
++ chip->write = u16_writer;
++ } else if (spi->bits_per_word <= 32) {
++ if (!ssp_timing_wr)
++ chip->cr0 |= SSCR0_EDSS;
++ chip->n_bytes = 4;
++ chip->read = u32_reader;
++ chip->write = u32_writer;
++ } else {
++ dev_err(&spi->dev, "invalid wordsize\n");
++ return -EINVAL;
++ }
++
++ if ((sspc->quirks & QUIRKS_SPI_SLAVE_CLOCK_MODE) == 0) {
++ chip->speed_hz = spi->max_speed_hz;
++ clk_div = ssp_get_clk_div(sspc, chip->speed_hz);
++ chip->cr0 |= clk_div << 8;
++ dev_dbg(&spi->dev, "spi->max_speed_hz:%d clk_div:%x cr0:%x",
++ spi->max_speed_hz, clk_div, chip->cr0);
++ }
++ chip->bits_per_word = spi->bits_per_word;
++ chip->chip_select = spi->chip_select;
++
++ spi_set_ctldata(spi, chip);
++
++ /* setup of sspc members that will not change across transfers */
++ sspc->n_bytes = chip->n_bytes;
++
++ if (chip->dma_enabled) {
++ intel_mid_ssp_spi_dma_init(sspc);
++ sspc->cr1_sig = SSCR1_TSRE | SSCR1_RSRE;
++ sspc->mask_sr = SSSR_ROR | SSSR_TUR;
++ if (sspc->quirks & QUIRKS_DMA_USE_NO_TRAIL)
++ sspc->cr1_sig |= SSCR1_TRAIL;
++ } else {
++ sspc->cr1_sig = SSCR1_TINTE;
++ sspc->mask_sr = SSSR_ROR | SSSR_TUR | SSSR_TINT;
++ }
++ sspc->clear_sr = SSSR_TUR | SSSR_ROR | SSSR_TINT;
++
++ return 0;
++}
++
++/**
++ * cleanup() - Driver cleanup procedure
++ * @spi: Pointer to the spi_device struct
++ */
++static void cleanup(struct spi_device *spi)
++{
++ struct chip_data *chip = spi_get_ctldata(spi);
++ struct ssp_drv_context *sspc =
++ spi_master_get_devdata(spi->master);
++
++ if (sspc->dma_initialized)
++ intel_mid_ssp_spi_dma_exit(sspc);
++
++ /* Remove the PM_QOS request */
++ if (sspc->quirks & QUIRKS_USE_PM_QOS)
++ pm_qos_remove_request(&sspc->pm_qos_req);
++
++ kfree(chip);
++ spi_set_ctldata(spi, NULL);
++}
++
++/**
++ * intel_mid_ssp_spi_probe() - Driver probe procedure
++ * @pdev: Pointer to the pci_dev struct
++ * @ent: Pointer to the pci_device_id struct
++ */
++static int intel_mid_ssp_spi_probe(struct pci_dev *pdev,
++ const struct pci_device_id *ent)
++{
++ struct device *dev = &pdev->dev;
++ struct spi_master *master;
++ struct ssp_drv_context *sspc = 0;
++ int status;
++ u32 iolen = 0;
++ u8 ssp_cfg;
++ int pos;
++ void __iomem *syscfg_ioaddr;
++ unsigned long syscfg;
++
++ /* Check if the SSP we are probed for has been allocated */
++ /* to operate as SPI. This information is retreived from */
++ /* the field adid of the Vendor-Specific PCI capability */
++ /* which is used as a configuration register. */
++ pos = pci_find_capability(pdev, PCI_CAP_ID_VNDR);
++ if (pos > 0) {
++ pci_read_config_byte(pdev,
++ pos + VNDR_CAPABILITY_ADID_OFFSET,
++ &ssp_cfg);
++ } else {
++ dev_info(dev, "No Vendor Specific PCI capability\n");
++ goto err_abort_probe;
++ }
++
++ if (ssp_cfg_get_mode(ssp_cfg) != SSP_CFG_SPI_MODE_ID) {
++ dev_info(dev, "Unsupported SSP mode (%02xh)\n", ssp_cfg);
++ goto err_abort_probe;
++ }
++
++ dev_info(dev, "found PCI SSP controller (ID: %04xh:%04xh cfg: %02xh)\n",
++ pdev->vendor, pdev->device, ssp_cfg);
++
++ status = pci_enable_device(pdev);
++ if (status)
++ return status;
++
++ /* Allocate Slave with space for sspc and null dma buffer */
++ master = spi_alloc_master(dev, sizeof(struct ssp_drv_context));
++
++ if (!master) {
++ dev_err(dev, "cannot alloc spi_slave\n");
++ status = -ENOMEM;
++ goto err_free_0;
++ }
++
++ sspc = spi_master_get_devdata(master);
++ sspc->master = master;
++
++ sspc->pdev = pdev;
++ sspc->quirks = ent->driver_data;
++
++ /* Set platform & configuration quirks */
++ if (sspc->quirks & QUIRKS_PLATFORM_MRST) {
++ /* Apply bit banging workarround on MRST */
++ sspc->quirks |= QUIRKS_BIT_BANGING;
++ /* MRST slave mode workarrounds */
++ if (ssp_cfg_is_spi_slave(ssp_cfg))
++ sspc->quirks |= QUIRKS_USE_PM_QOS |
++ QUIRKS_SRAM_ADDITIONAL_CPY;
++ }
++ sspc->quirks |= QUIRKS_DMA_USE_NO_TRAIL;
++ if (ssp_cfg_is_spi_slave(ssp_cfg))
++ sspc->quirks |= QUIRKS_SPI_SLAVE_CLOCK_MODE;
++
++ master->mode_bits = SPI_CPOL | SPI_CPHA;
++ master->bus_num = ssp_cfg_get_spi_bus_nb(ssp_cfg);
++ master->num_chipselect = 4;
++ master->cleanup = cleanup;
++ master->setup = setup;
++ master->transfer = transfer;
++ sspc->dma_wq = create_workqueue("intel_mid_ssp_spi");
++ INIT_WORK(&sspc->complete_work, int_transfer_complete_work);
++
++ sspc->dma_initialized = 0;
++ sspc->suspended = 0;
++ sspc->cur_msg = NULL;
++
++ /* get basic io resource and map it */
++ sspc->paddr = pci_resource_start(pdev, 0);
++ iolen = pci_resource_len(pdev, 0);
++
++ status = pci_request_region(pdev, 0, dev_name(&pdev->dev));
++ if (status)
++ goto err_free_1;
++
++ sspc->ioaddr = ioremap_nocache(sspc->paddr, iolen);
++ if (!sspc->ioaddr) {
++ status = -ENOMEM;
++ goto err_free_2;
++ }
++ dev_dbg(dev, "paddr = : %08lx", sspc->paddr);
++ dev_dbg(dev, "ioaddr = : %p\n", sspc->ioaddr);
++ dev_dbg(dev, "attaching to IRQ: %04x\n", pdev->irq);
++ dev_dbg(dev, "quirks = : %08lx\n", sspc->quirks);
++
++ if (sspc->quirks & QUIRKS_BIT_BANGING) {
++ /* Bit banging on the clock is done through */
++ /* DFT which is available through I2C. */
++ /* get base address of I2C_Serbus registers */
++ sspc->I2C_paddr = 0xff12b000;
++ sspc->I2C_ioaddr = ioremap_nocache(sspc->I2C_paddr, 0x10);
++ if (!sspc->I2C_ioaddr) {
++ status = -ENOMEM;
++ goto err_free_3;
++ }
++ }
++
++ /* Attach to IRQ */
++ sspc->irq = pdev->irq;
++ status = request_irq(sspc->irq, ssp_int, IRQF_SHARED,
++ "intel_mid_ssp_spi", sspc);
++
++ if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER) {
++ if ((intel_mid_identify_sim() ==
++ INTEL_MID_CPU_SIMULATION_SLE) ||
++ (intel_mid_identify_sim() ==
++ INTEL_MID_CPU_SIMULATION_NONE)) {
++ /* [REVERT ME] Tangier SLE not supported.
++ * Requires debug before removal. Assume
++ * also required in Si. */
++ disable_irq_nosync(sspc->irq);
++ }
++ if (intel_mid_identify_sim() == INTEL_MID_CPU_SIMULATION_NONE)
++ ssp_timing_wr = 1;
++ }
++
++ if (status < 0) {
++ dev_err(&pdev->dev, "can not get IRQ\n");
++ goto err_free_4;
++ }
++
++ if (sspc->quirks & QUIRKS_PLATFORM_MDFL) {
++ /* get base address of DMA selector. */
++ syscfg = sspc->paddr - SYSCFG;
++ syscfg_ioaddr = ioremap_nocache(syscfg, 0x10);
++ if (!syscfg_ioaddr) {
++ status = -ENOMEM;
++ goto err_free_5;
++ }
++ iowrite32(ioread32(syscfg_ioaddr) | 2, syscfg_ioaddr);
++ }
++
++ INIT_LIST_HEAD(&sspc->queue);
++ init_completion(&sspc->msg_done);
++ spin_lock_init(&sspc->lock);
++ tasklet_init(&sspc->poll_transfer, poll_transfer, (unsigned long)sspc);
++ INIT_WORK(&sspc->pump_messages, pump_messages);
++ sspc->workqueue = create_singlethread_workqueue(dev_name(&pdev->dev));
++
++ /* Register with the SPI framework */
++ dev_info(dev, "register with SPI framework (bus spi%d)\n",
++ master->bus_num);
++
++ status = spi_register_master(master);
++ if (status) {
++ dev_err(dev, "problem registering spi\n");
++ goto err_free_5;
++ }
++
++ pci_set_drvdata(pdev, sspc);
++
++ /* Create the PM_QOS request */
++ if (sspc->quirks & QUIRKS_USE_PM_QOS)
++ pm_qos_add_request(&sspc->pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
++ PM_QOS_DEFAULT_VALUE);
++
++ pm_runtime_put_noidle(&pdev->dev);
++ pm_runtime_allow(&pdev->dev);
++
++ return status;
++
++err_free_5:
++ free_irq(sspc->irq, sspc);
++err_free_4:
++ iounmap(sspc->I2C_ioaddr);
++err_free_3:
++ iounmap(sspc->ioaddr);
++err_free_2:
++ pci_release_region(pdev, 0);
++err_free_1:
++ spi_master_put(master);
++err_free_0:
++ pci_disable_device(pdev);
++
++ return status;
++err_abort_probe:
++ dev_info(dev, "Abort probe for SSP %04xh:%04xh\n",
++ pdev->vendor, pdev->device);
++ return -ENODEV;
++}
++
++/**
++ * intel_mid_ssp_spi_remove() - driver remove procedure
++ * @pdev: Pointer to the pci_dev struct
++ */
++static void intel_mid_ssp_spi_remove(struct pci_dev *pdev)
++{
++ struct ssp_drv_context *sspc = pci_get_drvdata(pdev);
++
++ if (!sspc)
++ return;
++
++ pm_runtime_forbid(&pdev->dev);
++ pm_runtime_get_noresume(&pdev->dev);
++
++ if (sspc->dma_wq)
++ destroy_workqueue(sspc->dma_wq);
++ if (sspc->workqueue)
++ destroy_workqueue(sspc->workqueue);
++
++ /* Release IRQ */
++ free_irq(sspc->irq, sspc);
++
++ if (sspc->ioaddr)
++ iounmap(sspc->ioaddr);
++ if (sspc->quirks & QUIRKS_BIT_BANGING && sspc->I2C_ioaddr)
++ iounmap(sspc->I2C_ioaddr);
++
++ /* disconnect from the SPI framework */
++ if (sspc->master)
++ spi_unregister_master(sspc->master);
++
++ pci_set_drvdata(pdev, NULL);
++ pci_release_region(pdev, 0);
++ pci_disable_device(pdev);
++
++ return;
++}
++
++#ifdef CONFIG_PM
++static int intel_mid_ssp_spi_suspend(struct device *dev)
++{
++ struct pci_dev *pdev = to_pci_dev(dev);
++ struct ssp_drv_context *sspc = pci_get_drvdata(pdev);
++ unsigned long flags;
++ int loop = 26;
++
++ dev_dbg(dev, "suspend\n");
++
++ spin_lock_irqsave(&sspc->lock, flags);
++ sspc->suspended = 1;
++ /*
++ * If there is one msg being handled, wait 500ms at most,
++ * if still not done, return busy
++ */
++ while (sspc->cur_msg && --loop) {
++ spin_unlock_irqrestore(&sspc->lock, flags);
++ msleep(20);
++ spin_lock_irqsave(&sspc->lock, flags);
++ if (!loop)
++ sspc->suspended = 0;
++ }
++ spin_unlock_irqrestore(&sspc->lock, flags);
++
++ if (loop)
++ return 0;
++ else
++ return -EBUSY;
++}
++
++static int intel_mid_ssp_spi_resume(struct device *dev)
++{
++ struct pci_dev *pdev = to_pci_dev(dev);
++ struct ssp_drv_context *sspc = pci_get_drvdata(pdev);
++
++ dev_dbg(dev, "resume\n");
++ spin_lock(&sspc->lock);
++ sspc->suspended = 0;
++ if (!list_empty(&sspc->queue))
++ queue_work(sspc->workqueue, &sspc->pump_messages);
++ spin_unlock(&sspc->lock);
++ return 0;
++}
++
++static int intel_mid_ssp_spi_runtime_suspend(struct device *dev)
++{
++ dev_dbg(dev, "runtime suspend called\n");
++ return 0;
++}
++
++static int intel_mid_ssp_spi_runtime_resume(struct device *dev)
++{
++ dev_dbg(dev, "runtime resume called\n");
++ return 0;
++}
++
++static int intel_mid_ssp_spi_runtime_idle(struct device *dev)
++{
++ int err;
++
++ dev_dbg(dev, "runtime idle called\n");
++ if (system_state == SYSTEM_BOOTING)
++ /* if SSP SPI UART is set as default console and earlyprintk
++ * is enabled, it cannot shutdown SSP controller during booting.
++ */
++ err = pm_schedule_suspend(dev, 30000);
++ else
++ err = pm_schedule_suspend(dev, 500);
++
++ return err;
++}
++#else
++#define intel_mid_ssp_spi_suspend NULL
++#define intel_mid_ssp_spi_resume NULL
++#define intel_mid_ssp_spi_runtime_suspend NULL
++#define intel_mid_ssp_spi_runtime_resume NULL
++#define intel_mid_ssp_spi_runtime_idle NULL
++#endif /* CONFIG_PM */
++
++
++static DEFINE_PCI_DEVICE_TABLE(pci_ids) = {
++ /* MRST SSP0 */
++ { PCI_VDEVICE(INTEL, 0x0815), QUIRKS_PLATFORM_MRST},
++ /* MDFL SSP0 */
++ { PCI_VDEVICE(INTEL, 0x0832), QUIRKS_PLATFORM_MDFL},
++ /* MDFL SSP1 */
++ { PCI_VDEVICE(INTEL, 0x0825), QUIRKS_PLATFORM_MDFL},
++ /* MDFL SSP3 */
++ { PCI_VDEVICE(INTEL, 0x0816), QUIRKS_PLATFORM_MDFL},
++ /* MRFL SSP5 */
++ { PCI_VDEVICE(INTEL, 0x1194), QUIRKS_PLATFORM_MRFL},
++ /* BYT SSP3 */
++ { PCI_VDEVICE(INTEL, 0x0f0e), QUIRKS_PLATFORM_BYT},
++ {},
++};
++
++static const struct dev_pm_ops intel_mid_ssp_spi_pm_ops = {
++ .suspend = intel_mid_ssp_spi_suspend,
++ .resume = intel_mid_ssp_spi_resume,
++ .runtime_suspend = intel_mid_ssp_spi_runtime_suspend,
++ .runtime_resume = intel_mid_ssp_spi_runtime_resume,
++ .runtime_idle = intel_mid_ssp_spi_runtime_idle,
++};
++
++static struct pci_driver intel_mid_ssp_spi_driver = {
++ .name = DRIVER_NAME,
++ .id_table = pci_ids,
++ .probe = intel_mid_ssp_spi_probe,
++ .remove = intel_mid_ssp_spi_remove,
++ .driver = {
++ .pm = &intel_mid_ssp_spi_pm_ops,
++ },
++};
++
++static int __init intel_mid_ssp_spi_init(void)
++{
++ return pci_register_driver(&intel_mid_ssp_spi_driver);
++}
++
++late_initcall(intel_mid_ssp_spi_init);
++
++static void __exit intel_mid_ssp_spi_exit(void)
++{
++ pci_unregister_driver(&intel_mid_ssp_spi_driver);
++}
++
++module_exit(intel_mid_ssp_spi_exit);
+diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c
+index b9f0192..54700a2 100644
+--- a/drivers/spi/spi-dw-mid.c
++++ b/drivers/spi/spi-dw-mid.c
+@@ -22,7 +22,6 @@
+ #include <linux/interrupt.h>
+ #include <linux/slab.h>
+ #include <linux/spi/spi.h>
+-#include <linux/types.h>
+
+ #include "spi-dw.h"
+
+@@ -55,6 +54,8 @@ static int mid_spi_dma_init(struct dw_spi *dws)
+ dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0813, NULL);
+ if (!dws->dmac)
+ dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0827, NULL);
++ if (!dws->dmac)
++ dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x08EF, NULL);
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+@@ -111,8 +112,11 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
+ {
+ struct dma_async_tx_descriptor *txdesc = NULL, *rxdesc = NULL;
+ struct dma_chan *txchan, *rxchan;
+- struct dma_slave_config txconf, rxconf;
++ struct dma_slave_config *txconf, *rxconf;
+ u16 dma_ctrl = 0;
++ enum dma_ctrl_flags flag;
++ struct device *dev = &dws->master->dev;
++ struct intel_mid_dma_slave *rxs, *txs;
+
+ /* 1. setup DMA related registers */
+ if (cs_change) {
+@@ -131,51 +135,65 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
+ txchan = dws->txchan;
+ rxchan = dws->rxchan;
+
+- /* 2. Prepare the TX dma transfer */
+- txconf.direction = DMA_MEM_TO_DEV;
+- txconf.dst_addr = dws->dma_addr;
+- txconf.dst_maxburst = LNW_DMA_MSIZE_16;
+- txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+- txconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+- txconf.device_fc = false;
++ txs = txchan->private;
++ rxs = rxchan->private;
+
+- txchan->device->device_control(txchan, DMA_SLAVE_CONFIG,
+- (unsigned long) &txconf);
++ txconf = &txs->dma_slave;
++ rxconf = &rxs->dma_slave;
+
+- memset(&dws->tx_sgl, 0, sizeof(dws->tx_sgl));
+- dws->tx_sgl.dma_address = dws->tx_dma;
+- dws->tx_sgl.length = dws->len;
++ flag = DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP | DMA_CTRL_ACK;
+
+- txdesc = dmaengine_prep_slave_sg(txchan,
+- &dws->tx_sgl,
+- 1,
+- DMA_MEM_TO_DEV,
+- DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP);
+- txdesc->callback = dw_spi_dma_done;
+- txdesc->callback_param = dws;
++ /* 2. Prepare the TX dma transfer */
++ txconf->direction = DMA_MEM_TO_DEV;
++ txconf->dst_addr = dws->dma_addr;
++ txconf->src_maxburst = LNW_DMA_MSIZE_16;
++ txconf->dst_maxburst = LNW_DMA_MSIZE_16;
++ txconf->src_addr_width = dws->dma_width;
++ txconf->dst_addr_width = dws->dma_width;
++ txconf->device_fc = false;
++
++ txchan->device->device_control(txchan, DMA_SLAVE_CONFIG,
++ (unsigned long) txconf);
++
++ txdesc = txchan->device->device_prep_dma_memcpy
++ (txchan, /* DMA Channel */
++ dws->dma_addr, /* DAR */
++ dws->tx_dma, /* SAR */
++ dws->len, /* Data Length */
++ flag);
++ if (txdesc) {
++ txdesc->callback = dw_spi_dma_done;
++ txdesc->callback_param = dws;
++ } else {
++ dev_err(dev, "ERROR: prepare txdesc failed\n");
++ return -EINVAL;
++ }
+
+ /* 3. Prepare the RX dma transfer */
+- rxconf.direction = DMA_DEV_TO_MEM;
+- rxconf.src_addr = dws->dma_addr;
+- rxconf.src_maxburst = LNW_DMA_MSIZE_16;
+- rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+- rxconf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+- rxconf.device_fc = false;
++ rxconf->direction = DMA_DEV_TO_MEM;
++ rxconf->src_addr = dws->dma_addr;
++ rxconf->src_maxburst = LNW_DMA_MSIZE_16;
++ rxconf->dst_maxburst = LNW_DMA_MSIZE_16;
++ rxconf->dst_addr_width = dws->dma_width;
++ rxconf->src_addr_width = dws->dma_width;
++ rxconf->device_fc = false;
+
+ rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG,
+- (unsigned long) &rxconf);
+-
+- memset(&dws->rx_sgl, 0, sizeof(dws->rx_sgl));
+- dws->rx_sgl.dma_address = dws->rx_dma;
+- dws->rx_sgl.length = dws->len;
+-
+- rxdesc = dmaengine_prep_slave_sg(rxchan,
+- &dws->rx_sgl,
+- 1,
+- DMA_DEV_TO_MEM,
+- DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP);
+- rxdesc->callback = dw_spi_dma_done;
+- rxdesc->callback_param = dws;
++ (unsigned long) rxconf);
++
++ rxdesc = rxchan->device->device_prep_dma_memcpy
++ (rxchan, /* DMA Channel */
++ dws->rx_dma, /* DAR */
++ dws->dma_addr, /* SAR */
++ dws->len, /* Data Length */
++ flag);
++ if (rxdesc) {
++ rxdesc->callback = dw_spi_dma_done;
++ rxdesc->callback_param = dws;
++ } else {
++ dev_err(dev, "ERROR: prepare rxdesc failed\n");
++ return -EINVAL;
++ }
+
+ /* rx must be started before tx due to spi instinct */
+ rxdesc->tx_submit(rxdesc);
+@@ -183,10 +201,41 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
+ return 0;
+ }
+
++static int mid_spi_dma_suspend(struct dw_spi *dws)
++{
++ struct dma_chan *txchan, *rxchan;
++
++ txchan = dws->txchan;
++ rxchan = dws->rxchan;
++
++ txchan->device->device_control(txchan, DMA_TERMINATE_ALL, 0);
++ rxchan->device->device_control(rxchan, DMA_TERMINATE_ALL, 0);
++
++ txchan->device->device_control(txchan, DMA_PAUSE, 0);
++ rxchan->device->device_control(rxchan, DMA_PAUSE, 0);
++
++ return 0;
++}
++
++static int mid_spi_dma_resume(struct dw_spi *dws)
++{
++ struct dma_chan *txchan, *rxchan;
++
++ txchan = dws->txchan;
++ rxchan = dws->rxchan;
++
++ txchan->device->device_control(txchan, DMA_RESUME, 0);
++ rxchan->device->device_control(rxchan, DMA_RESUME, 0);
++
++ return 0;
++}
++
+ static struct dw_spi_dma_ops mid_dma_ops = {
+ .dma_init = mid_spi_dma_init,
+ .dma_exit = mid_spi_dma_exit,
+ .dma_transfer = mid_spi_dma_transfer,
++ .dma_suspend = mid_spi_dma_suspend,
++ .dma_resume = mid_spi_dma_resume,
+ };
+ #endif
+
+@@ -201,12 +250,12 @@ static struct dw_spi_dma_ops mid_dma_ops = {
+ #define CLK_SPI_CDIV_MASK 0x00000e00
+ #define CLK_SPI_DISABLE_OFFSET 8
+
+-int dw_spi_mid_init(struct dw_spi *dws)
++int dw_spi_mid_init(struct dw_spi *dws, int bus_num)
+ {
+ void __iomem *clk_reg;
+ u32 clk_cdiv;
+
+- clk_reg = ioremap_nocache(MRST_CLK_SPI0_REG, 16);
++ clk_reg = ioremap_nocache(MRST_CLK_SPI0_REG + bus_num * 4, 16);
+ if (!clk_reg)
+ return -ENOMEM;
+
+diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c
+index 6055c8d..c2c0756 100644
+--- a/drivers/spi/spi-dw-pci.c
++++ b/drivers/spi/spi-dw-pci.c
+@@ -20,6 +20,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/pci.h>
+ #include <linux/slab.h>
++#include <linux/pm_runtime.h>
+ #include <linux/spi/spi.h>
+ #include <linux/module.h>
+
+@@ -72,7 +73,7 @@ static int spi_pci_probe(struct pci_dev *pdev,
+ }
+
+ dws->parent_dev = &pdev->dev;
+- dws->bus_num = 0;
++ dws->bus_num = ent->driver_data;
+ dws->num_cs = 4;
+ dws->irq = pdev->irq;
+
+@@ -80,11 +81,9 @@ static int spi_pci_probe(struct pci_dev *pdev,
+ * Specific handling for Intel MID paltforms, like dma setup,
+ * clock rate, FIFO depth.
+ */
+- if (pdev->device == 0x0800) {
+- ret = dw_spi_mid_init(dws);
+- if (ret)
+- goto err_unmap;
+- }
++ ret = dw_spi_mid_init(dws, ent->driver_data);
++ if (ret)
++ goto err_unmap;
+
+ ret = dw_spi_add_host(dws);
+ if (ret)
+@@ -92,6 +91,11 @@ static int spi_pci_probe(struct pci_dev *pdev,
+
+ /* PCI hook and SPI hook use the same drv data */
+ pci_set_drvdata(pdev, dwpci);
++
++ pm_suspend_ignore_children(&pdev->dev, true);
++ pm_runtime_put_noidle(&pdev->dev);
++ pm_runtime_allow(&pdev->dev);
++
+ return 0;
+
+ err_unmap:
+@@ -111,6 +115,8 @@ static void spi_pci_remove(struct pci_dev *pdev)
+
+ pci_set_drvdata(pdev, NULL);
+ dw_spi_remove_host(&dwpci->dws);
++ pm_runtime_forbid(&pdev->dev);
++ pm_runtime_get_noresume(&pdev->dev);
+ iounmap(dwpci->dws.regs);
+ pci_release_region(pdev, 0);
+ kfree(dwpci);
+@@ -118,8 +124,9 @@ static void spi_pci_remove(struct pci_dev *pdev)
+ }
+
+ #ifdef CONFIG_PM
+-static int spi_suspend(struct pci_dev *pdev, pm_message_t state)
++static int spi_suspend(struct device *dev)
+ {
++ struct pci_dev *pdev = to_pci_dev(dev);
+ struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
+ int ret;
+
+@@ -128,12 +135,13 @@ static int spi_suspend(struct pci_dev *pdev, pm_message_t state)
+ return ret;
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+- pci_set_power_state(pdev, pci_choose_state(pdev, state));
++ pci_set_power_state(pdev, PCI_D3hot);
+ return ret;
+ }
+
+-static int spi_resume(struct pci_dev *pdev)
++static int spi_resume(struct device *dev)
+ {
++ struct pci_dev *pdev = to_pci_dev(dev);
+ struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
+ int ret;
+
+@@ -144,27 +152,93 @@ static int spi_resume(struct pci_dev *pdev)
+ return ret;
+ return dw_spi_resume_host(&dwpci->dws);
+ }
++
++static int spi_dw_pci_runtime_suspend(struct device *dev)
++{
++ struct pci_dev *pdev = to_pci_dev(dev);
++ struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
++
++ dev_dbg(dev, "PCI runtime suspend called\n");
++ return dw_spi_suspend_host(&dwpci->dws);
++}
++
++static int spi_dw_pci_runtime_resume(struct device *dev)
++{
++ struct pci_dev *pdev = to_pci_dev(dev);
++ struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
++
++ dev_dbg(dev, "pci_runtime_resume called\n");
++ return dw_spi_resume_host(&dwpci->dws);
++}
++
++static int spi_dw_pci_runtime_idle(struct device *dev)
++{
++ int err;
++
++ dev_dbg(dev, "pci_runtime_idle called\n");
++ if (system_state == SYSTEM_BOOTING)
++ /* if SPI UART is set as default console and earlyprintk
++ * is enabled, it cannot shutdown SPI controller during booting.
++ */
++ err = pm_schedule_suspend(dev, 30000);
++ else
++ err = pm_schedule_suspend(dev, 500);
++
++ if (err != 0)
++ return 0;
++
++ return -EBUSY;
++}
++
+ #else
+ #define spi_suspend NULL
+ #define spi_resume NULL
++#define spi_dw_pci_runtime_suspend NULL
++#define spi_dw_pci_runtime_resume NULL
++#define spi_dw_pci_runtime_idle NULL
+ #endif
+
+ static DEFINE_PCI_DEVICE_TABLE(pci_ids) = {
+- /* Intel MID platform SPI controller 0 */
+- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0800) },
++ /* Intel Medfield platform SPI controller 1 */
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0800), .driver_data = 0 },
++ /* Intel Cloverview platform SPI controller 1 */
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08E1), .driver_data = 0 },
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08EE), .driver_data = 1 },
++ /* Intel EVx platform SPI controller 1 */
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0812), .driver_data = 2 },
+ {},
+ };
+
++static const struct dev_pm_ops dw_spi_pm_ops = {
++ .suspend = spi_suspend,
++ .resume = spi_resume,
++ .runtime_suspend = spi_dw_pci_runtime_suspend,
++ .runtime_resume = spi_dw_pci_runtime_resume,
++ .runtime_idle = spi_dw_pci_runtime_idle,
++};
++
+ static struct pci_driver dw_spi_driver = {
+ .name = DRIVER_NAME,
+ .id_table = pci_ids,
+ .probe = spi_pci_probe,
+ .remove = spi_pci_remove,
+- .suspend = spi_suspend,
+- .resume = spi_resume,
++ .driver = {
++ .pm = &dw_spi_pm_ops,
++ },
+ };
+
+-module_pci_driver(dw_spi_driver);
++static int __init mrst_spi_init(void)
++{
++ return pci_register_driver(&dw_spi_driver);
++}
++
++static void __exit mrst_spi_exit(void)
++{
++ pci_unregister_driver(&dw_spi_driver);
++}
++
++module_init(mrst_spi_init);
++module_exit(mrst_spi_exit);
+
+ MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>");
+ MODULE_DESCRIPTION("PCI interface driver for DW SPI Core");
+diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c
+index c1abc06..ce044c5 100644
+--- a/drivers/spi/spi-dw.c
++++ b/drivers/spi/spi-dw.c
+@@ -23,6 +23,7 @@
+ #include <linux/highmem.h>
+ #include <linux/delay.h>
+ #include <linux/slab.h>
++#include <linux/pm_runtime.h>
+ #include <linux/spi/spi.h>
+
+ #include "spi-dw.h"
+@@ -63,6 +64,12 @@ struct chip_data {
+ };
+
+ #ifdef CONFIG_DEBUG_FS
++static int spi_show_regs_open(struct inode *inode, struct file *file)
++{
++ file->private_data = inode->i_private;
++ return 0;
++}
++
+ #define SPI_REGS_BUFSIZE 1024
+ static ssize_t spi_show_regs(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+@@ -122,7 +129,7 @@ static ssize_t spi_show_regs(struct file *file, char __user *user_buf,
+
+ static const struct file_operations mrst_spi_regs_ops = {
+ .owner = THIS_MODULE,
+- .open = simple_open,
++ .open = spi_show_regs_open,
+ .read = spi_show_regs,
+ .llseek = default_llseek,
+ };
+@@ -191,7 +198,7 @@ static void dw_writer(struct dw_spi *dws)
+ u16 txw = 0;
+
+ while (max--) {
+- /* Set the tx word if the transfer's original "tx" is not null */
++ /* Set the txw if the transfer's original "tx" is not null */
+ if (dws->tx_end - dws->len) {
+ if (dws->n_bytes == 1)
+ txw = *(u8 *)(dws->tx);
+@@ -256,7 +263,40 @@ static int map_dma_buffers(struct dw_spi *dws)
+ if (dws->cur_transfer->rx_dma)
+ dws->rx_dma = dws->cur_transfer->rx_dma;
+
++ /* map dma buffer if it's not mapped */
++ if (!dws->tx_dma) {
++ dws->tx_dma = dma_map_single(NULL, dws->tx,
++ dws->len, DMA_TO_DEVICE);
++ if (dma_mapping_error(NULL, dws->tx_dma)) {
++ pr_err("map tx dma buffer failed\n");
++ goto err1;
++ }
++ }
++
++ if (!dws->rx_dma) {
++ dws->rx_dma = dma_map_single(NULL, dws->rx,
++ dws->len, DMA_FROM_DEVICE);
++ if (dma_mapping_error(NULL, dws->rx_dma)) {
++ pr_err("map rx dma buffer failed\n");
++ goto err2;
++ }
++ }
++
+ return 1;
++
++err2:
++ dma_unmap_single(NULL, dws->tx_dma, dws->len, DMA_TO_DEVICE);
++err1:
++ dws->cur_msg->is_dma_mapped = 0;
++ return 0;
++}
++
++static void unmap_dma_buffers(struct dw_spi *dws)
++{
++ dma_unmap_single(NULL, dws->rx_dma,
++ dws->len, DMA_FROM_DEVICE);
++ dma_unmap_single(NULL, dws->tx_dma,
++ dws->len, DMA_TO_DEVICE);
+ }
+
+ /* Caller already set message->status; dma and pio irqs are blocked */
+@@ -267,7 +307,12 @@ static void giveback(struct dw_spi *dws)
+ struct spi_message *msg;
+
+ spin_lock_irqsave(&dws->lock, flags);
++
++ if (dws->dma_mapped)
++ unmap_dma_buffers(dws);
++
+ msg = dws->cur_msg;
++ list_del_init(&dws->cur_msg->queue);
+ dws->cur_msg = NULL;
+ dws->cur_transfer = NULL;
+ dws->prev_chip = dws->cur_chip;
+@@ -312,6 +357,7 @@ void dw_spi_xfer_done(struct dw_spi *dws)
+ giveback(dws);
+ } else
+ tasklet_schedule(&dws->pump_transfers);
++
+ }
+ EXPORT_SYMBOL_GPL(dw_spi_xfer_done);
+
+@@ -324,7 +370,7 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws)
+ dw_readw(dws, DW_SPI_TXOICR);
+ dw_readw(dws, DW_SPI_RXOICR);
+ dw_readw(dws, DW_SPI_RXUICR);
+- int_error_stop(dws, "interrupt_transfer: fifo overrun/underrun");
++ int_error_stop(dws, "interrupt_transfer: fifo over/underrun");
+ return IRQ_HANDLED;
+ }
+
+@@ -505,7 +551,8 @@ static void pump_transfers(unsigned long data)
+ txint_level = dws->fifo_len / 2;
+ txint_level = (templen > txint_level) ? txint_level : templen;
+
+- imask |= SPI_INT_TXEI | SPI_INT_TXOI | SPI_INT_RXUI | SPI_INT_RXOI;
++ imask |= SPI_INT_TXEI | SPI_INT_TXOI | SPI_INT_RXUI
++ | SPI_INT_RXOI;
+ dws->transfer_handler = interrupt_transfer;
+ }
+
+@@ -515,7 +562,8 @@ static void pump_transfers(unsigned long data)
+ * 2. clk_div is changed
+ * 3. control value changes
+ */
+- if (dw_readw(dws, DW_SPI_CTRL0) != cr0 || cs_change || clk_div || imask) {
++ if (dw_readw(dws, DW_SPI_CTRL0) != cr0 || cs_change
++ || clk_div || imask) {
+ spi_enable_chip(dws, 0);
+
+ if (dw_readw(dws, DW_SPI_CTRL0) != cr0)
+@@ -555,23 +603,19 @@ static void pump_messages(struct work_struct *work)
+ container_of(work, struct dw_spi, pump_messages);
+ unsigned long flags;
+
++ pm_runtime_get_sync(dws->parent_dev);
++
+ /* Lock queue and check for queue work */
+ spin_lock_irqsave(&dws->lock, flags);
+- if (list_empty(&dws->queue) || dws->run == QUEUE_STOPPED) {
+- dws->busy = 0;
+- spin_unlock_irqrestore(&dws->lock, flags);
+- return;
+- }
++ if (list_empty(&dws->queue) || dws->run == QUEUE_STOPPED)
++ goto exit;
+
+ /* Make sure we are not already running a message */
+- if (dws->cur_msg) {
+- spin_unlock_irqrestore(&dws->lock, flags);
+- return;
+- }
++ if (dws->cur_msg)
++ goto exit;
+
+ /* Extract head of queue */
+ dws->cur_msg = list_entry(dws->queue.next, struct spi_message, queue);
+- list_del_init(&dws->cur_msg->queue);
+
+ /* Initial message state*/
+ dws->cur_msg->state = START_STATE;
+@@ -583,8 +627,9 @@ static void pump_messages(struct work_struct *work)
+ /* Mark as busy and launch transfers */
+ tasklet_schedule(&dws->pump_transfers);
+
+- dws->busy = 1;
++exit:
+ spin_unlock_irqrestore(&dws->lock, flags);
++ pm_runtime_put_sync(dws->parent_dev);
+ }
+
+ /* spi_device use this to queue in their spi_msg */
+@@ -595,29 +640,13 @@ static int dw_spi_transfer(struct spi_device *spi, struct spi_message *msg)
+
+ spin_lock_irqsave(&dws->lock, flags);
+
+- if (dws->run == QUEUE_STOPPED) {
+- spin_unlock_irqrestore(&dws->lock, flags);
+- return -ESHUTDOWN;
+- }
+-
+ msg->actual_length = 0;
+ msg->status = -EINPROGRESS;
+ msg->state = START_STATE;
+
+ list_add_tail(&msg->queue, &dws->queue);
+
+- if (dws->run == QUEUE_RUNNING && !dws->busy) {
+-
+- if (dws->cur_transfer || dws->cur_msg)
+- queue_work(dws->workqueue,
+- &dws->pump_messages);
+- else {
+- /* If no other data transaction in air, just go */
+- spin_unlock_irqrestore(&dws->lock, flags);
+- pump_messages(&dws->pump_messages);
+- return 0;
+- }
+- }
++ queue_work(dws->workqueue, &dws->pump_messages);
+
+ spin_unlock_irqrestore(&dws->lock, flags);
+ return 0;
+@@ -696,13 +725,12 @@ static void dw_spi_cleanup(struct spi_device *spi)
+ kfree(chip);
+ }
+
+-static int init_queue(struct dw_spi *dws)
++static int dw_spi_init_queue(struct dw_spi *dws)
+ {
+ INIT_LIST_HEAD(&dws->queue);
+ spin_lock_init(&dws->lock);
+
+ dws->run = QUEUE_STOPPED;
+- dws->busy = 0;
+
+ tasklet_init(&dws->pump_transfers,
+ pump_transfers, (unsigned long)dws);
+@@ -716,13 +744,13 @@ static int init_queue(struct dw_spi *dws)
+ return 0;
+ }
+
+-static int start_queue(struct dw_spi *dws)
++static int dw_spi_start_queue(struct dw_spi *dws)
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave(&dws->lock, flags);
+
+- if (dws->run == QUEUE_RUNNING || dws->busy) {
++ if (dws->run == QUEUE_RUNNING) {
+ spin_unlock_irqrestore(&dws->lock, flags);
+ return -EBUSY;
+ }
+@@ -739,32 +767,27 @@ static int start_queue(struct dw_spi *dws)
+ return 0;
+ }
+
+-static int stop_queue(struct dw_spi *dws)
++int dw_spi_stop_queue(struct dw_spi *dws)
+ {
+ unsigned long flags;
+- unsigned limit = 50;
+ int status = 0;
+
+ spin_lock_irqsave(&dws->lock, flags);
+- dws->run = QUEUE_STOPPED;
+- while ((!list_empty(&dws->queue) || dws->busy) && limit--) {
+- spin_unlock_irqrestore(&dws->lock, flags);
+- msleep(10);
+- spin_lock_irqsave(&dws->lock, flags);
+- }
+-
+- if (!list_empty(&dws->queue) || dws->busy)
++ if (!list_empty(&dws->queue))
+ status = -EBUSY;
++ else
++ dws->run = QUEUE_STOPPED;
+ spin_unlock_irqrestore(&dws->lock, flags);
+
+ return status;
+ }
++EXPORT_SYMBOL_GPL(dw_spi_stop_queue);
+
+-static int destroy_queue(struct dw_spi *dws)
++static int dw_spi_destroy_queue(struct dw_spi *dws)
+ {
+ int status;
+
+- status = stop_queue(dws);
++ status = dw_spi_stop_queue(dws);
+ if (status != 0)
+ return status;
+ destroy_workqueue(dws->workqueue);
+@@ -772,11 +795,10 @@ static int destroy_queue(struct dw_spi *dws)
+ }
+
+ /* Restart the controller, disable all interrupts, clean rx fifo */
+-static void spi_hw_init(struct dw_spi *dws)
++static void dw_spi_hw_init(struct dw_spi *dws)
+ {
+ spi_enable_chip(dws, 0);
+ spi_mask_intr(dws, 0xff);
+- spi_enable_chip(dws, 1);
+
+ /*
+ * Try to detect the FIFO depth if not set by interface driver,
+@@ -793,6 +815,8 @@ static void spi_hw_init(struct dw_spi *dws)
+ dws->fifo_len = (fifo == 257) ? 0 : fifo;
+ dw_writew(dws, DW_SPI_TXFLTR, 0);
+ }
++
++ spi_enable_chip(dws, 1);
+ }
+
+ int dw_spi_add_host(struct dw_spi *dws)
+@@ -831,7 +855,7 @@ int dw_spi_add_host(struct dw_spi *dws)
+ master->transfer = dw_spi_transfer;
+
+ /* Basic HW init */
+- spi_hw_init(dws);
++ dw_spi_hw_init(dws);
+
+ if (dws->dma_ops && dws->dma_ops->dma_init) {
+ ret = dws->dma_ops->dma_init(dws);
+@@ -842,12 +866,12 @@ int dw_spi_add_host(struct dw_spi *dws)
+ }
+
+ /* Initial and start queue */
+- ret = init_queue(dws);
++ ret = dw_spi_init_queue(dws);
+ if (ret) {
+ dev_err(&master->dev, "problem initializing queue\n");
+ goto err_diable_hw;
+ }
+- ret = start_queue(dws);
++ ret = dw_spi_start_queue(dws);
+ if (ret) {
+ dev_err(&master->dev, "problem starting queue\n");
+ goto err_diable_hw;
+@@ -864,7 +888,7 @@ int dw_spi_add_host(struct dw_spi *dws)
+ return 0;
+
+ err_queue_alloc:
+- destroy_queue(dws);
++ dw_spi_destroy_queue(dws);
+ if (dws->dma_ops && dws->dma_ops->dma_exit)
+ dws->dma_ops->dma_exit(dws);
+ err_diable_hw:
+@@ -886,7 +910,7 @@ void dw_spi_remove_host(struct dw_spi *dws)
+ mrst_spi_debugfs_remove(dws);
+
+ /* Remove the queue */
+- status = destroy_queue(dws);
++ status = dw_spi_destroy_queue(dws);
+ if (status != 0)
+ dev_err(&dws->master->dev, "dw_spi_remove: workqueue will not "
+ "complete, message memory not freed\n");
+@@ -907,11 +931,16 @@ int dw_spi_suspend_host(struct dw_spi *dws)
+ {
+ int ret = 0;
+
+- ret = stop_queue(dws);
++ ret = dw_spi_stop_queue(dws);
+ if (ret)
+ return ret;
++
+ spi_enable_chip(dws, 0);
+ spi_set_clk(dws, 0);
++
++ if (dws->dma_inited)
++ dws->dma_ops->dma_suspend(dws);
++
+ return ret;
+ }
+ EXPORT_SYMBOL_GPL(dw_spi_suspend_host);
+@@ -920,10 +949,14 @@ int dw_spi_resume_host(struct dw_spi *dws)
+ {
+ int ret;
+
+- spi_hw_init(dws);
+- ret = start_queue(dws);
++ if (dws->dma_inited)
++ dws->dma_ops->dma_resume(dws);
++
++ dw_spi_hw_init(dws);
++ ret = dw_spi_start_queue(dws);
+ if (ret)
+ dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret);
++
+ return ret;
+ }
+ EXPORT_SYMBOL_GPL(dw_spi_resume_host);
+diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
+index 9c57c07..2aaccb7 100644
+--- a/drivers/spi/spi-dw.h
++++ b/drivers/spi/spi-dw.h
+@@ -87,6 +87,8 @@ struct dw_spi_dma_ops {
+ int (*dma_init)(struct dw_spi *dws);
+ void (*dma_exit)(struct dw_spi *dws);
+ int (*dma_transfer)(struct dw_spi *dws, int cs_change);
++ int (*dma_suspend)(struct dw_spi *dws);
++ int (*dma_resume)(struct dw_spi *dws);
+ };
+
+ struct dw_spi {
+@@ -111,7 +113,6 @@ struct dw_spi {
+ struct work_struct pump_messages;
+ spinlock_t lock;
+ struct list_head queue;
+- int busy;
+ int run;
+
+ /* Message Transfer pump */
+@@ -236,7 +237,9 @@ extern void dw_spi_remove_host(struct dw_spi *dws);
+ extern int dw_spi_suspend_host(struct dw_spi *dws);
+ extern int dw_spi_resume_host(struct dw_spi *dws);
+ extern void dw_spi_xfer_done(struct dw_spi *dws);
++extern int dw_spi_stop_queue(struct dw_spi *dws);
+
+ /* platform related setup */
+-extern int dw_spi_mid_init(struct dw_spi *dws); /* Intel MID platforms */
++/* Intel MID platforms */
++extern int dw_spi_mid_init(struct dw_spi *dws, int bus_num);
+ #endif /* DW_SPI_HEADER_H */
+diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
+index 5e3c025..e0fb348 100644
+--- a/drivers/thermal/Kconfig
++++ b/drivers/thermal/Kconfig
+@@ -169,4 +169,32 @@ config INTEL_POWERCLAMP
+ enforce idle time which results in more package C-state residency. The
+ user interface is exposed via generic thermal framework.
+
++config SENSORS_THERMAL_MRFLD
++ tristate "Thermal driver for Intel Merrifield platform"
++ depends on THERMAL && IIO && IIO_BASINCOVE_GPADC
++ help
++ Say Y here to enable thermal driver on Intel Merrifield platform.
++
++ To load this driver as a module, select M here. The module
++ will be called "mrfl_thermal"
++
++config INTEL_BYT_EC_THERMAL
++ tristate "Thermal driver for Intel Baytrail platform"
++ depends on THERMAL && INTEL_BYT_EC
++ help
++ Say Y here to enable thermal driver on Intel Baytrail-M platform.
++
++ To load this driver as a module, select M here. The module
++ will be called "byt_ec_thermal"
++
++config SOC_THERMAL
++ tristate "SoC Thermal driver"
++ depends on THERMAL
++ help
++ SoC Thermal driver registers to Generic Thermal Framework.
++ Exposes SoC DTS and aux trip point values through the framework.
++
++ Say Y here to enable thermal driver on Intel Merrifield
++ platform. To load this driver as a module, select M here.
++
+ endif
+diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
+index c054d41..46c9aa5 100644
+--- a/drivers/thermal/Makefile
++++ b/drivers/thermal/Makefile
+@@ -2,9 +2,18 @@
+ # Makefile for sensor chip drivers.
+ #
+
++CFLAGS_intel_mrfl_thermal.o := -Werror
++CFLAGS_intel_soc_thermal.o := -Werror
++CFLAGS_thermal_core.o := -Werror
++
+ obj-$(CONFIG_THERMAL) += thermal_sys.o
+ thermal_sys-y += thermal_core.o
+
++obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
++obj-$(CONFIG_INTEL_BYT_THERMAL) += intel_byt_thermal.o
++obj-$(CONFIG_SENSORS_THERMAL_MRFLD) += intel_mrfl_thermal.o
++obj-$(CONFIG_SOC_THERMAL) += intel_soc_thermal.o
++
+ # governors
+ thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += fair_share.o
+ thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE) += step_wise.o
+diff --git a/drivers/thermal/intel_mid_thermal.c b/drivers/thermal/intel_mid_thermal.c
+new file mode 100644
+index 0000000..d577046
+--- /dev/null
++++ b/drivers/thermal/intel_mid_thermal.c
+@@ -0,0 +1,754 @@
++/*
++ * intel_mid_thermal.c - Intel MID platform thermal driver
++ *
++ * Copyright (C) 2010 Intel Corporation
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * 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; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ * Author: Ananth Krishna <ananth.krishna.r@intel.com>
++ * Author: Durgadoss <durgadoss.r@intel.com>
++ */
++
++#define pr_fmt(fmt) "intel_mid_thermal: " fmt
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/err.h>
++#include <linux/param.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/rpmsg.h>
++
++#include <linux/slab.h>
++#include <linux/pm.h>
++#include <linux/thermal.h>
++
++#include <asm/intel_scu_ipc.h>
++#include <asm/intel_mid_gpadc.h>
++#include <asm/intel_mid_thermal.h>
++#include <asm/intel_mid_rpmsg.h>
++
++#define DRIVER_NAME "msic_thermal"
++
++/* Cooling device attributes */
++#define SOC_IPC_COMMAND 0xCF
++
++enum {
++ NORMAL = 0,
++ WARNING,
++ ALERT,
++ CRITICAL
++} thermal_state;
++
++enum {
++ SOC_SKIN_NORMAL = 0,
++ SOC_SKIN_WARM = 2,
++ SOC_SKIN_PROCHOT,
++ SOC_MAX_STATES
++} soc_skin_state;
++
++/* MSIC die attributes */
++#define MSIC_DIE_ADC_MIN 488
++#define MSIC_DIE_ADC_MAX 1004
++
++#define TABLE_LENGTH 24
++/*
++ * ADC code vs Temperature table
++ * This table will be different for different thermistors
++ * Row 0: ADC code
++ * Row 1: Temperature (in degree celsius)
++ */
++static const int adc_code[2][TABLE_LENGTH] = {
++ {977, 961, 941, 917, 887, 853, 813, 769, 720, 669, 615, 561, 508, 456,
++ 407, 357, 315, 277, 243, 212, 186, 162, 140, 107},
++ {-20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60,
++ 65, 70, 75, 80, 85, 90, 100},
++ };
++
++struct ts_cache_info {
++ bool is_cached_data_initialized;
++ struct mutex lock;
++ int *cached_values;
++ unsigned long last_updated;
++};
++
++struct soc_cooling_device_info {
++ unsigned long soc_state;
++ struct mutex lock_cool_state;
++};
++
++static struct soc_cooling_device_info soc_cdev_info;
++
++struct platform_info {
++ struct platform_device *pdev;
++ struct thermal_zone_device **tzd;
++ struct ts_cache_info cacheinfo;
++ /* ADC handle used to read sensor temperature values */
++ void *therm_adc_handle;
++ struct thermal_cooling_device *soc_cdev;
++ int num_sensors;
++ int soc_cooling;
++ struct intel_mid_thermal_sensor *sensors;
++};
++
++static struct platform_info *platforminfo;
++
++struct thermal_device_info {
++ struct intel_mid_thermal_sensor *sensor;
++};
++
++/* SoC cooling device callbacks */
++static int soc_get_max_state(struct thermal_cooling_device *cdev,
++ unsigned long *state)
++{
++ /* SoC has 4 levels of throttling from 0 to 3 */
++ *state = SOC_MAX_STATES - 1;
++ return 0;
++}
++
++static int soc_get_cur_state(struct thermal_cooling_device *cdev,
++ unsigned long *state)
++{
++ mutex_lock(&soc_cdev_info.lock_cool_state);
++ *state = soc_cdev_info.soc_state;
++ mutex_unlock(&soc_cdev_info.lock_cool_state);
++ return 0;
++}
++
++static int soc_set_cur_state(struct thermal_cooling_device *cdev,
++ unsigned long state)
++{
++ int ret;
++ if (state > SOC_MAX_STATES - 1) {
++ pr_err("Invalid SoC throttle state:%ld\n", state);
++ return -EINVAL;
++ }
++
++ switch (state) {
++ /* SoC De-Throttle */
++ case NORMAL:
++ state = SOC_SKIN_NORMAL;
++ break;
++ case WARNING:
++ /*
++ * New state is assigned based on present state.
++ * State 1 can be reached from state 0 or 2.
++ * State 0 to 1 means skin WARM.
++ * state 2 to 1 means skin no longer PROCHOT but WARM
++ */
++ state = SOC_SKIN_WARM;
++ break;
++ /* SoC Throttle, PROCHOT */
++ case ALERT:
++ case CRITICAL:
++ state = SOC_SKIN_PROCHOT;
++ break;
++ }
++ /* Send IPC command to throttle SoC */
++ mutex_lock(&soc_cdev_info.lock_cool_state);
++ ret = rpmsg_send_generic_command(SOC_IPC_COMMAND, 0,
++ (u8 *) &state, 4, NULL, 0);
++ if (ret)
++ pr_err("IPC_COMMAND failed: %d\n", ret);
++ else
++ soc_cdev_info.soc_state = state;
++
++ mutex_unlock(&soc_cdev_info.lock_cool_state);
++ return ret;
++}
++
++static struct thermal_cooling_device_ops soc_cooling_ops = {
++ .get_max_state = soc_get_max_state,
++ .get_cur_state = soc_get_cur_state,
++ .set_cur_state = soc_set_cur_state,
++};
++
++static int register_soc_as_cdev(void)
++{
++ int ret = 0;
++ platforminfo->soc_cdev = thermal_cooling_device_register("SoC", NULL,
++ &soc_cooling_ops);
++ if (IS_ERR(platforminfo->soc_cdev)) {
++ ret = PTR_ERR(platforminfo->soc_cdev);
++ platforminfo->soc_cdev = NULL;
++ }
++ return ret;
++}
++
++static void unregister_soc_as_cdev(void)
++{
++ thermal_cooling_device_unregister(platforminfo->soc_cdev);
++}
++
++/**
++ * is_valid_adc - checks whether the adc code is within the defined range
++ * @min: minimum value for the sensor
++ * @max: maximum value for the sensor
++ *
++ * Can sleep
++ */
++static int is_valid_adc(uint16_t adc_val, uint16_t min, uint16_t max)
++{
++ return (adc_val >= min) && (adc_val <= max);
++}
++
++/**
++ * find_adc_code - searches the ADC code using binary search
++ * @val: value to find in the array
++ *
++ * This function does binary search on an array sorted in 'descending' order
++ * Can sleep
++ */
++static int find_adc_code(uint16_t val)
++{
++ int left = 0;
++ int right = TABLE_LENGTH - 1;
++ int mid;
++ while (left <= right) {
++ mid = (left + right)/2;
++ if (val == adc_code[0][mid] ||
++ (mid > 0 &&
++ val > adc_code[0][mid] && val < adc_code[0][mid-1]))
++ return mid;
++ else if (val > adc_code[0][mid])
++ right = mid - 1;
++ else if (val < adc_code[0][mid])
++ left = mid + 1;
++ }
++ return -1;
++}
++
++/**
++ * linear_interpolate - does interpolation to find temperature
++ * Returns the temperature in milli degree celsius
++ * @adc_val: ADC code(x) at which temperature(y) should be found
++ * @indx: index of the minimum(x0) of the two ADC codes
++ *
++ * Can sleep
++ */
++static int linear_interpolate(int indx, uint16_t adc_val)
++{
++ int x = adc_val;
++ int x0 = adc_code[0][indx];
++ int x1 = adc_code[0][indx - 1];
++ int y0 = adc_code[1][indx];
++ int y1 = adc_code[1][indx - 1];
++
++ /*
++ * Find y:
++ * Of course, we can avoid these variables, but keep them
++ * for readability and maintainability.
++ */
++ int numerator = (x-x0)*y1 + (x1-x)*y0;
++ int denominator = x1-x0;
++
++ /*
++ * We have to report the temperature in milli degree celsius.
++ * So, to reduce the loss of precision, do (Nr*1000)/Dr, instead
++ * of (Nr/Dr)*1000.
++ */
++ return (numerator * 1000)/denominator;
++}
++
++/**
++ * adc_to_temp - converts the ADC code to temperature in C
++ * @direct: true if ths channel is direct index
++ * @adc_val: the adc_val that needs to be converted
++ * @tp: temperature return value
++ *
++ * Can sleep
++ */
++static int adc_to_temp(struct intel_mid_thermal_sensor *sensor,
++ uint16_t adc_val, long *tp)
++{
++ int indx;
++
++ /* Direct conversion for msic die temperature */
++ if (sensor->direct) {
++ if (is_valid_adc(adc_val, MSIC_DIE_ADC_MIN, MSIC_DIE_ADC_MAX)) {
++ *tp = sensor->slope * adc_val - sensor->intercept;
++ return 0;
++ }
++ return -ERANGE;
++ }
++
++ indx = find_adc_code(adc_val);
++ if (indx < 0)
++ return -ERANGE;
++
++ if (adc_code[0][indx] == adc_val) {
++ /* Convert temperature in celsius to milli degree celsius */
++ *tp = adc_code[1][indx] * 1000;
++ return 0;
++ }
++
++ /*
++ * The ADC code is in between two values directly defined in the
++ * table. So, do linear interpolation to calculate the temperature.
++ */
++ *tp = linear_interpolate(indx, adc_val);
++ return 0;
++}
++
++int skin0_temp_correlation(void *info, long temp, long *res)
++{
++ struct intel_mid_thermal_sensor *sensor = info;
++
++ *res = ((temp * sensor->slope) / 1000) + sensor->intercept;
++
++ return 0;
++}
++
++int bptherm_temp_correlation(void *info, long temp, long *res)
++{
++ struct intel_mid_thermal_sensor *sensor = info;
++
++ *res = ((temp * sensor->slope) / 1000) + sensor->intercept;
++
++ return 0;
++}
++
++int skin1_temp_correlation(void *info, long temp, long *res)
++{
++ struct intel_mid_thermal_sensor *sensor = info;
++ struct intel_mid_thermal_sensor *dsensor; /* dependent sensor */
++ struct skin1_private_info *skin_info;
++ long sensor_temp = 0, curr_temp;
++ int ret, index;
++
++ skin_info = sensor->priv;
++
++ *res = ((temp * sensor->slope) / 1000) + sensor->intercept;
++
++ /* If we do not have dependent sensors, just return. Not an error */
++ if (!skin_info || !skin_info->dependent || !skin_info->sensors)
++ return 0;
++
++ for (index = 0; index < skin_info->dependent; index++) {
++ if (!skin_info->sensors[index])
++ continue;
++
++ dsensor = skin_info->sensors[index];
++
++ ret = adc_to_temp(dsensor,
++ platforminfo->cacheinfo.cached_values[dsensor->index],
++ &curr_temp);
++ if (ret)
++ return ret;
++
++ if (dsensor->temp_correlation)
++ dsensor->temp_correlation(dsensor, curr_temp,
++ &sensor_temp);
++
++ if (sensor_temp > *res)
++ *res = sensor_temp;
++ }
++
++ return 0;
++}
++
++/**
++ * mid_read_temp - read sensors for temperature
++ * @temp: holds the current temperature for the sensor after reading
++ *
++ * reads the adc_code from the channel and converts it to real
++ * temperature. The converted value is stored in temp.
++ *
++ * Can sleep
++ */
++static int mid_read_temp(struct thermal_zone_device *tzd, long *temp)
++{
++ struct thermal_device_info *td_info = tzd->devdata;
++ int ret;
++ long curr_temp;
++ int indx = td_info->sensor->index; /* Required Index */
++
++ mutex_lock(&platforminfo->cacheinfo.lock);
++
++ if (!platforminfo->cacheinfo.is_cached_data_initialized ||
++ time_after(jiffies, platforminfo->cacheinfo.last_updated + HZ)) {
++ ret = get_gpadc_sample(platforminfo->therm_adc_handle, 1,
++ platforminfo->cacheinfo.cached_values);
++ if (ret)
++ goto exit;
++ platforminfo->cacheinfo.last_updated = jiffies;
++ platforminfo->cacheinfo.is_cached_data_initialized = true;
++ }
++
++ /* Convert ADC value to temperature */
++ ret = adc_to_temp(td_info->sensor,
++ platforminfo->cacheinfo.cached_values[indx], &curr_temp);
++ if (ret)
++ goto exit;
++
++ if (td_info->sensor->temp_correlation)
++ ret = td_info->sensor->temp_correlation(td_info->sensor,
++ curr_temp, temp);
++ else
++ *temp = curr_temp;
++
++exit:
++ mutex_unlock(&platforminfo->cacheinfo.lock);
++ return ret;
++}
++
++/**
++ * initialize_sensor - Initializes ADC information for each sensor.
++ * @index: index of the sensor
++ *
++ * Context: can sleep
++ */
++static struct thermal_device_info *initialize_sensor(
++ struct intel_mid_thermal_sensor *sensor)
++{
++ struct thermal_device_info *td_info =
++ kzalloc(sizeof(struct thermal_device_info), GFP_KERNEL);
++
++ if (!td_info)
++ return NULL;
++
++ td_info->sensor = sensor;
++
++ return td_info;
++}
++
++/**
++ * mid_thermal_resume - resume routine
++ * @dev: device structure
++ */
++static int mid_thermal_resume(struct device *dev)
++{
++ return 0;
++}
++
++/**
++ * mid_thermal_suspend - suspend routine
++ * @dev: device structure
++ */
++static int mid_thermal_suspend(struct device *dev)
++{
++ return 0;
++}
++
++#ifdef CONFIG_DEBUG_THERMAL
++static int read_slope(struct thermal_zone_device *tzd, long *slope)
++{
++ struct thermal_device_info *td_info = tzd->devdata;
++
++ *slope = td_info->sensor->slope;
++
++ return 0;
++}
++
++static int update_slope(struct thermal_zone_device *tzd, long slope)
++{
++ struct thermal_device_info *td_info = tzd->devdata;
++
++ td_info->sensor->slope = slope;
++
++ return 0;
++}
++
++static int read_intercept(struct thermal_zone_device *tzd, long *intercept)
++{
++ struct thermal_device_info *td_info = tzd->devdata;
++
++ *intercept = td_info->sensor->intercept;
++
++ return 0;
++}
++
++static int update_intercept(struct thermal_zone_device *tzd, long intercept)
++{
++ struct thermal_device_info *td_info = tzd->devdata;
++
++ td_info->sensor->intercept = intercept;
++
++ return 0;
++}
++#endif
++
++/**
++ * read_curr_temp - reads the current temperature and stores in temp
++ * @temp: holds the current temperature value after reading
++ *
++ * Can sleep
++ */
++static int read_curr_temp(struct thermal_zone_device *tzd, long *temp)
++{
++ return (tzd) ? mid_read_temp(tzd, temp) : -EINVAL;
++}
++
++/* Can't be const */
++static struct thermal_zone_device_ops tzd_ops = {
++ .get_temp = read_curr_temp,
++#ifdef CONFIG_DEBUG_THERMAL
++ .get_slope = read_slope,
++ .set_slope = update_slope,
++ .get_intercept = read_intercept,
++ .set_intercept = update_intercept,
++#endif
++};
++
++/**
++ * mid_thermal_probe - mfld thermal initialize
++ * @pdev: platform device structure
++ *
++ * mid thermal probe initializes the hardware and registers
++ * all the sensors with the generic thermal framework. Can sleep.
++ */
++static int mid_thermal_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++ int i;
++ int *adc_channel_info;
++ struct intel_mid_thermal_platform_data *pdata;
++
++ pdata = pdev->dev.platform_data;
++
++ if (!pdata)
++ return -EINVAL;
++
++ platforminfo = kzalloc(sizeof(struct platform_info), GFP_KERNEL);
++
++ if (!platforminfo)
++ return -ENOMEM;
++
++ platforminfo->num_sensors = pdata->num_sensors;
++ platforminfo->soc_cooling = pdata->soc_cooling;
++ platforminfo->sensors = pdata->sensors;
++
++ platforminfo->tzd = kzalloc(
++ (sizeof(struct thermal_zone_device *) * platforminfo->num_sensors),
++ GFP_KERNEL);
++
++ if (!platforminfo->tzd)
++ goto platforminfo_alloc_fail;
++
++ platforminfo->cacheinfo.cached_values =
++ kzalloc((sizeof(int) * platforminfo->num_sensors), GFP_KERNEL);
++
++ if (!platforminfo->cacheinfo.cached_values)
++ goto tzd_alloc_fail;
++
++ adc_channel_info = kzalloc((sizeof(int) * platforminfo->num_sensors),
++ GFP_KERNEL);
++
++ if (!adc_channel_info)
++ goto cachedinfo_alloc_fail;
++
++ /* initialize mutex locks */
++ mutex_init(&platforminfo->cacheinfo.lock);
++
++
++ if (platforminfo->soc_cooling)
++ mutex_init(&soc_cdev_info.lock_cool_state);
++
++ for (i = 0; i < platforminfo->num_sensors; i++)
++ adc_channel_info[i] = platforminfo->sensors[i].adc_channel;
++
++ /* Allocate ADC channels for all sensors */
++ platforminfo->therm_adc_handle = gpadc_alloc_channels(
++ platforminfo->num_sensors, adc_channel_info);
++
++ if (!platforminfo->therm_adc_handle) {
++ ret = -ENOMEM;
++ goto adc_channel_alloc_fail;
++ }
++
++ /* Register each sensor with the generic thermal framework*/
++ for (i = 0; i < platforminfo->num_sensors; i++) {
++ platforminfo->tzd[i] = thermal_zone_device_register(
++ platforminfo->sensors[i].name, 0, 0,
++ initialize_sensor(&platforminfo->sensors[i]),
++ &tzd_ops, NULL, 0, 0);
++ if (IS_ERR(platforminfo->tzd[i]))
++ goto reg_fail;
++ }
++
++ platforminfo->pdev = pdev;
++
++ platform_set_drvdata(pdev, platforminfo);
++
++ /* Register SoC as a cooling device */
++ if (platforminfo->soc_cooling) {
++ ret = register_soc_as_cdev();
++ /* Log this, but keep the driver loaded */
++ if (ret) {
++ dev_err(&pdev->dev,
++ "register_soc_as_cdev failed:%d\n", ret);
++ }
++ }
++
++ kfree(adc_channel_info);
++
++ return 0;
++
++reg_fail:
++ ret = PTR_ERR(platforminfo->tzd[i]);
++ while (--i >= 0)
++ thermal_zone_device_unregister(platforminfo->tzd[i]);
++adc_channel_alloc_fail:
++ kfree(adc_channel_info);
++cachedinfo_alloc_fail:
++ kfree(platforminfo->cacheinfo.cached_values);
++tzd_alloc_fail:
++ kfree(platforminfo->tzd);
++platforminfo_alloc_fail:
++ kfree(platforminfo);
++ return ret;
++}
++
++/**
++ * mid_thermal_remove - mfld thermal finalize
++ * @dev: platform device structure
++ *
++ * MLFD thermal remove unregisters all the sensors from the generic
++ * thermal framework. Can sleep.
++ */
++static int mid_thermal_remove(struct platform_device *pdev)
++{
++ int i;
++
++ for (i = 0; i < platforminfo->num_sensors; i++)
++ thermal_zone_device_unregister(platforminfo->tzd[i]);
++
++ /* Unregister SoC as cooling device */
++ if (platforminfo->soc_cooling)
++ unregister_soc_as_cdev();
++
++ /* Free the allocated ADC channels */
++ if (platforminfo->therm_adc_handle)
++ intel_mid_gpadc_free(platforminfo->therm_adc_handle);
++
++ kfree(platforminfo->cacheinfo.cached_values);
++ kfree(platforminfo->tzd);
++ kfree(platforminfo);
++
++ platform_set_drvdata(pdev, NULL);
++
++ return 0;
++}
++
++/*********************************************************************
++ * Driver initialisation and finalization
++ *********************************************************************/
++
++
++/* Platfrom device functionality */
++
++static const struct dev_pm_ops msic_thermal_pm_ops = {
++ .suspend = mid_thermal_suspend,
++ .resume = mid_thermal_resume,
++};
++
++static const struct platform_device_id mid_therm_table[] = {
++ { DRIVER_NAME, 1 },
++};
++
++static struct platform_driver mid_therm_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .pm = &msic_thermal_pm_ops,
++ },
++ .probe = mid_thermal_probe,
++ .remove = mid_thermal_remove,
++ .id_table = mid_therm_table,
++};
++
++static int mid_therm_module_init(void)
++{
++ return platform_driver_register(&mid_therm_driver);
++}
++
++static void mid_therm_module_exit(void)
++{
++ platform_driver_unregister(&mid_therm_driver);
++}
++
++
++/* RPMSG related functionality */
++
++static int mid_therm_rpmsg_probe(struct rpmsg_channel *rpdev)
++{
++ int ret = 0;
++ if (rpdev == NULL) {
++ pr_err("rpmsg channel not created\n");
++ ret = -ENODEV;
++ goto out;
++ }
++
++ dev_info(&rpdev->dev, "Probed mid_therm rpmsg device\n");
++
++ ret = mid_therm_module_init();
++out:
++ return ret;
++}
++
++static void mid_therm_rpmsg_remove(struct rpmsg_channel *rpdev)
++{
++ mid_therm_module_exit();
++ dev_info(&rpdev->dev, "Removed mid_therm rpmsg device\n");
++}
++
++static void mid_therm_rpmsg_cb(struct rpmsg_channel *rpdev, void *data,
++ int len, void *priv, u32 src)
++{
++ dev_warn(&rpdev->dev, "unexpected, message\n");
++
++ print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
++ data, len, true);
++}
++
++static struct rpmsg_device_id mid_therm_id_table[] = {
++ { .name = "rpmsg_mid_thermal" },
++ { },
++};
++
++MODULE_DEVICE_TABLE(rpmsg, mid_therm_id_table);
++
++static struct rpmsg_driver mid_therm_rpmsg_driver = {
++ .drv.name = DRIVER_NAME,
++ .drv.owner = THIS_MODULE,
++ .probe = mid_therm_rpmsg_probe,
++ .callback = mid_therm_rpmsg_cb,
++ .remove = mid_therm_rpmsg_remove,
++ .id_table = mid_therm_id_table,
++};
++
++static int __init mid_therm_rpmsg_init(void)
++{
++ return register_rpmsg_driver(&mid_therm_rpmsg_driver);
++}
++
++static void __exit mid_therm_rpmsg_exit(void)
++{
++ return unregister_rpmsg_driver(&mid_therm_rpmsg_driver);
++}
++
++
++/* Changing _init call to make the thermal driver
++ * load _after_ the GPADC driver
++ * module_init(mid_therm_rpmsg_init);
++ */
++late_initcall(mid_therm_rpmsg_init);
++module_exit(mid_therm_rpmsg_exit);
++
++MODULE_AUTHOR("Durgadoss R <durgadoss.r@intel.com>");
++MODULE_DESCRIPTION("Intel Medfield Platform Thermal Driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/thermal/intel_mrfl_thermal.c b/drivers/thermal/intel_mrfl_thermal.c
+new file mode 100644
+index 0000000..ab34846
+--- /dev/null
++++ b/drivers/thermal/intel_mrfl_thermal.c
+@@ -0,0 +1,909 @@
++/*
++ * intel_mrfl_thermal.c - Intel Merrifield Platform Thermal Driver
++ *
++ *
++ * Copyright (C) 2011 Intel Corporation
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * 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; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ * Author: Durgadoss R <durgadoss.r@intel.com>
++ *
++ * DEVICE_NAME: Intel Merrifield platform - PMIC: Thermal Monitor
++ */
++
++#define pr_fmt(fmt) "intel_mrfl_thermal: " fmt
++
++#include <linux/pm.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/rpmsg.h>
++#include <linux/module.h>
++#include <linux/thermal.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++
++#include <asm/intel_scu_pmic.h>
++#include <asm/intel_mid_rpmsg.h>
++#include <asm/intel_basincove_gpadc.h>
++#include <asm/intel_mid_thermal.h>
++#include <linux/iio/consumer.h>
++
++#define DRIVER_NAME "bcove_thrm"
++
++/* Number of Thermal sensors on the PMIC */
++#define PMIC_THERMAL_SENSORS 4
++
++/* Registers that govern Thermal Monitoring */
++#define THRMMONCFG 0xB3
++#define THRMMONCTL 0xB4
++#define THRMIRQ 0x04
++#define MTHRMIRQ 0x0F
++#define STHRMIRQ 0xB2
++#define IRQLVL1 0x01
++#define MIRQLVL1 0x0C
++#define IRQ_MASK_ALL 0x0F
++
++/* PMIC SRAM base address and offset for Thermal register */
++#define PMIC_SRAM_BASE_ADDR 0xFFFFF610
++#define PMIC_SRAM_THRM_OFFSET 0x03
++#define IOMAP_SIZE 0x04
++
++/* NVM BANK REGISTER */
++#define EEPROM_CTRL 0x1FE
++#define EEPROM_REG15 0x1EE
++#define EEPROM_BANK1_SELECT 0x02
++#define EEPROM_BANK1_UNSELECT 0x00
++
++#define PMICALRT (1 << 3)
++#define SYS2ALRT (1 << 2)
++#define SYS1ALRT (1 << 1)
++#define SYS0ALRT (1 << 0)
++#define THERM_EN (1 << 0)
++#define THERM_ALRT (1 << 2)
++
++/* ADC to Temperature conversion table length */
++#define TABLE_LENGTH 34
++#define TEMP_INTERVAL 5
++
++/* Default _max 85 C */
++#define DEFAULT_MAX_TEMP 85
++
++/* Constants defined in BasinCove PMIC spec */
++#define PMIC_DIE_ADC_MIN 395
++#define PMIC_DIE_ADC_MAX 661
++#define PMIC_DIE_TEMP_MIN -40
++#define PMIC_DIE_TEMP_MAX 125
++#define ADC_VAL_27C 470
++#define ADC_COEFFICIENT 675
++#define TEMP_OFFSET 27000
++
++/* 'enum' of Thermal sensors */
++enum thermal_sensors { SYS0, SYS1, SYS2, PMIC_DIE, _COUNT };
++
++/*
++ * Alert registers store the 'alert' temperature for each sensor,
++ * as 10 bit ADC code. The higher two bits are stored in bits[0:1] of
++ * alert_regs_h. The lower eight bits are stored in alert_regs_l.
++ * The hysteresis value is stored in bits[2:6] of alert_regs_h.
++ * Order: SYS0 SYS1 SYS2 PMIC_DIE
++ *
++ * static const int alert_regs_l[] = { 0xB7, 0xB9, 0xBB, 0xC1 };
++ */
++static const int alert_regs_h[] = { 0xB6, 0xB8, 0xBA, 0xC0 };
++
++/*
++ * ADC code vs Temperature table
++ * This table will be different for different thermistors
++ * Row 0: ADC code
++ * Row 1: Temperature (in degree celsius)
++ */
++static const int adc_code[2][TABLE_LENGTH] = {
++ {952, 932, 906, 877, 843, 804, 761, 714, 665, 614,
++ 563, 512, 462, 415, 370, 329, 291, 257, 226, 199,
++ 174, 153, 135, 119, 104, 92, 81, 72, 64, 56,
++ 50, 45, 40, 36},
++ {-40, -35, -30, -25, -20, -15, -10, -5, 0, 5,
++ 10, 15, 20, 25, 30, 35, 40, 45, 50, 55,
++ 60, 65, 70, 75, 80, 85, 90, 95, 100, 105,
++ 110, 115, 120, 125},
++ };
++
++static DEFINE_MUTEX(thrm_update_lock);
++
++struct thermal_device_info {
++ struct intel_mid_thermal_sensor *sensor;
++};
++
++struct thermal_data {
++ struct platform_device *pdev;
++ struct iio_channel *iio_chan;
++ struct thermal_zone_device **tzd;
++ void *thrm_addr;
++ unsigned int irq;
++ /* Caching information */
++ bool is_initialized;
++ unsigned long last_updated;
++ int cached_vals[PMIC_THERMAL_SENSORS];
++ int num_sensors;
++ struct intel_mid_thermal_sensor *sensors;
++};
++static struct thermal_data *tdata;
++
++static inline int adc_to_pmic_die_temp(unsigned int val)
++{
++ /* return temperature in mC */
++ return (val - ADC_VAL_27C) * ADC_COEFFICIENT + TEMP_OFFSET;
++}
++
++static inline int pmic_die_temp_to_adc(int temp)
++{
++ /* 'temp' is in C, convert to mC and then do calculations */
++ return ((temp * 1000) - TEMP_OFFSET) / ADC_COEFFICIENT + ADC_VAL_27C;
++}
++
++/**
++ * find_adc_code - searches the ADC code using binary search
++ * @val: value to find in the array
++ *
++ * This function does binary search on an array sorted in 'descending' order
++ * Can sleep
++ */
++static int find_adc_code(uint16_t val)
++{
++ int left = 0;
++ int right = TABLE_LENGTH - 1;
++ int mid;
++ while (left <= right) {
++ mid = (left + right)/2;
++ if (val == adc_code[0][mid] ||
++ (mid > 0 &&
++ val > adc_code[0][mid] && val < adc_code[0][mid-1]))
++ return mid;
++ else if (val > adc_code[0][mid])
++ right = mid - 1;
++ else if (val < adc_code[0][mid])
++ left = mid + 1;
++ }
++ return -EINVAL;
++}
++
++/**
++ * adc_to_temp - converts the ADC code to temperature in mC
++ * @direct: true if the sensor uses direct conversion
++ * @adc_val: the ADC code to be converted
++ * @tp: temperature return value
++ *
++ * Can sleep
++ */
++static int adc_to_temp(int direct, uint16_t adc_val, unsigned long *tp)
++{
++ int x0, x1, y0, y1;
++ int nr, dr; /* Numerator & Denominator */
++ int indx;
++ int x = adc_val;
++ int8_t pmic_temp_offset;
++
++ /* Direct conversion for pmic die temperature */
++ if (direct) {
++ if (adc_val < PMIC_DIE_ADC_MIN || adc_val > PMIC_DIE_ADC_MAX)
++ return -EINVAL;
++
++ /* An offset added for pmic temp from NVM in TNG B0 */
++ intel_scu_ipc_iowrite8(EEPROM_CTRL, EEPROM_BANK1_SELECT);
++ intel_scu_ipc_ioread8(EEPROM_REG15, &pmic_temp_offset);
++ intel_scu_ipc_iowrite8(EEPROM_CTRL, EEPROM_BANK1_UNSELECT);
++
++ adc_val = adc_val + pmic_temp_offset;
++
++ *tp = adc_to_pmic_die_temp(adc_val);
++ return 0;
++ }
++
++ indx = find_adc_code(adc_val);
++ if (indx < 0)
++ return -EINVAL;
++
++ if (adc_code[0][indx] == adc_val) {
++ *tp = adc_code[1][indx] * 1000;
++ return 0;
++ }
++
++ /*
++ * The ADC code is in between two values directly defined in the
++ * table. So, do linear interpolation to calculate the temperature.
++ */
++ x0 = adc_code[0][indx];
++ x1 = adc_code[0][indx - 1];
++ y0 = adc_code[1][indx];
++ y1 = adc_code[1][indx - 1];
++
++ /*
++ * Find y:
++ * Of course, we can avoid these variables, but keep them
++ * for readability and maintainability.
++ */
++ nr = (x-x0)*y1 + (x1-x)*y0;
++ dr = x1-x0;
++
++ if (!dr)
++ return -EINVAL;
++ /*
++ * We have to report the temperature in milli degree celsius.
++ * So, to reduce the loss of precision, do (Nr*1000)/Dr, instead
++ * of (Nr/Dr)*1000.
++ */
++ *tp = (nr * 1000)/dr;
++
++ return 0;
++}
++
++/**
++ * temp_to_adc - converts the temperature(in C) to ADC code
++ * @direct: true if the sensor uses direct conversion
++ * @temp: the temperature to be converted
++ * @adc_val: ADC code return value
++ *
++ * Can sleep
++ */
++static int temp_to_adc(int direct, int temp, int *adc_val)
++{
++ int indx;
++ int x0, x1, y0, y1;
++ int nr, dr; /* Numerator & Denominator */
++ int x = temp;
++
++ /* Direct conversion for pmic die temperature */
++ if (direct) {
++ if (temp < PMIC_DIE_TEMP_MIN || temp > PMIC_DIE_TEMP_MAX)
++ return -EINVAL;
++
++ *adc_val = pmic_die_temp_to_adc(temp);
++ return 0;
++ }
++
++ if (temp < adc_code[1][0] || temp > adc_code[1][TABLE_LENGTH - 1])
++ return -EINVAL;
++
++
++ /* Find the 'indx' of this 'temp' in the table */
++ indx = (temp - adc_code[1][0]) / TEMP_INTERVAL;
++
++ if (temp == adc_code[1][indx]) {
++ *adc_val = adc_code[0][indx];
++ return 0;
++ }
++
++ /*
++ * Temperature is not a multiple of 'TEMP_INTERVAL'. So,
++ * do linear interpolation to obtain a better ADC code.
++ */
++ x0 = adc_code[1][indx];
++ x1 = adc_code[1][indx + 1];
++ y0 = adc_code[0][indx];
++ y1 = adc_code[0][indx + 1];
++
++ nr = (x-x0)*y1 + (x1-x)*y0;
++ dr = x1-x0;
++
++ if (!dr)
++ return -EINVAL;
++
++ *adc_val = nr/dr;
++
++ return 0;
++}
++
++/**
++ * set_tmax - sets the given 'adc_val' to the 'alert_reg'
++ * @alert_reg: register address
++ * @adc_val: ADC value to be programmed
++ *
++ * Not protected. Calling function should handle synchronization.
++ * Can sleep
++ */
++static int set_tmax(int alert_reg, int adc_val)
++{
++ int ret;
++
++ /* Set bits[0:1] of alert_reg_h to bits[8:9] of 'adc_val' */
++ ret = intel_scu_ipc_update_register(alert_reg, (adc_val >> 8), 0x03);
++ if (ret)
++ return ret;
++
++ /* Extract bits[0:7] of 'adc_val' and write them into alert_reg_l */
++ return intel_scu_ipc_iowrite8(alert_reg + 1, adc_val & 0xFF);
++}
++
++/**
++ * program_tmax - programs a default _max value for each sensor
++ * @dev: device pointer
++ *
++ * Can sleep
++ */
++static int program_tmax(struct device *dev)
++{
++ int i, ret;
++ int pmic_die_val, adc_val;
++
++ ret = temp_to_adc(0, DEFAULT_MAX_TEMP, &adc_val);
++ if (ret)
++ return ret;
++
++ ret = temp_to_adc(1, DEFAULT_MAX_TEMP, &pmic_die_val);
++ if (ret)
++ return ret;
++ /*
++ * Since this function sets max value, do for all sensors even if
++ * the sensor does not register as a thermal zone.
++ */
++ for (i = 0; i < PMIC_THERMAL_SENSORS - 1; i++) {
++ ret = set_tmax(alert_regs_h[i], adc_val);
++ if (ret)
++ goto exit_err;
++ }
++
++ /* Set _max for pmic die sensor */
++ ret = set_tmax(alert_regs_h[i], pmic_die_val);
++ if (ret)
++ goto exit_err;
++
++ return ret;
++
++exit_err:
++ dev_err(dev, "set_tmax for channel %d failed:%d\n", i, ret);
++ return ret;
++}
++
++static int store_trip_hyst(struct thermal_zone_device *tzd,
++ int trip, long hyst)
++{
++ int ret;
++ uint8_t data;
++ struct thermal_device_info *td_info = tzd->devdata;
++ int alert_reg = alert_regs_h[td_info->sensor->index];
++
++ /* Hysteresis value is 5 bits wide */
++ if (hyst > 31)
++ return -EINVAL;
++
++ mutex_lock(&thrm_update_lock);
++
++ ret = intel_scu_ipc_ioread8(alert_reg, &data);
++ if (ret)
++ goto ipc_fail;
++
++ /* Set bits [2:6] to value of hyst */
++ data = (data & 0x83) | (hyst << 2);
++
++ ret = intel_scu_ipc_iowrite8(alert_reg, data);
++
++ipc_fail:
++ mutex_unlock(&thrm_update_lock);
++ return ret;
++}
++
++static int show_trip_hyst(struct thermal_zone_device *tzd,
++ int trip, long *hyst)
++{
++ int ret;
++ uint8_t data;
++ struct thermal_device_info *td_info = tzd->devdata;
++ int alert_reg = alert_regs_h[td_info->sensor->index];
++
++ mutex_lock(&thrm_update_lock);
++
++ ret = intel_scu_ipc_ioread8(alert_reg, &data);
++ if (!ret)
++ *hyst = (data >> 2) & 0x1F; /* Extract bits[2:6] of data */
++
++ mutex_unlock(&thrm_update_lock);
++
++ return ret;
++}
++
++static int store_trip_temp(struct thermal_zone_device *tzd,
++ int trip, long trip_temp)
++{
++ int ret, adc_val;
++ struct thermal_device_info *td_info = tzd->devdata;
++ int alert_reg = alert_regs_h[td_info->sensor->index];
++
++ if (trip_temp < 1000) {
++ dev_err(&tzd->device, "Temperature should be in mC\n");
++ return -EINVAL;
++ }
++
++ mutex_lock(&thrm_update_lock);
++
++ /* Convert from mC to C */
++ trip_temp /= 1000;
++
++ ret = temp_to_adc(td_info->sensor->direct, (int)trip_temp, &adc_val);
++ if (ret)
++ goto exit;
++
++ ret = set_tmax(alert_reg, adc_val);
++exit:
++ mutex_unlock(&thrm_update_lock);
++ return ret;
++}
++
++static int show_trip_temp(struct thermal_zone_device *tzd,
++ int trip, long *trip_temp)
++{
++ int ret, adc_val;
++ uint8_t l, h;
++ struct thermal_device_info *td_info = tzd->devdata;
++ int alert_reg = alert_regs_h[td_info->sensor->index];
++
++ mutex_lock(&thrm_update_lock);
++
++ ret = intel_scu_ipc_ioread8(alert_reg, &h);
++ if (ret)
++ goto exit;
++
++ ret = intel_scu_ipc_ioread8(alert_reg + 1, &l);
++ if (ret)
++ goto exit;
++
++ /* Concatenate 'h' and 'l' to get 10-bit ADC code */
++ adc_val = ((h & 0x03) << 8) | l;
++
++ ret = adc_to_temp(td_info->sensor->direct, adc_val, trip_temp);
++exit:
++ mutex_unlock(&thrm_update_lock);
++ return ret;
++}
++
++static int show_trip_type(struct thermal_zone_device *tzd,
++ int trip, enum thermal_trip_type *trip_type)
++{
++ /* All are passive trip points */
++ *trip_type = THERMAL_TRIP_PASSIVE;
++
++ return 0;
++}
++
++static int show_temp(struct thermal_zone_device *tzd, long *temp)
++{
++ int ret;
++ struct thermal_device_info *td_info = tzd->devdata;
++ int indx = td_info->sensor->index;
++
++ if (!tdata->iio_chan)
++ return -EINVAL;
++
++ mutex_lock(&thrm_update_lock);
++
++ if (!tdata->is_initialized ||
++ time_after(jiffies, tdata->last_updated + HZ)) {
++ ret = iio_read_channel_all_raw(tdata->iio_chan,
++ tdata->cached_vals);
++ if (ret) {
++ dev_err(&tzd->device, "ADC sampling failed:%d\n", ret);
++ goto exit;
++ }
++ tdata->last_updated = jiffies;
++ tdata->is_initialized = true;
++ }
++
++ ret = adc_to_temp(td_info->sensor->direct, tdata->cached_vals[indx],
++ temp);
++ if (ret)
++ goto exit;
++
++ if (td_info->sensor->temp_correlation)
++ ret = td_info->sensor->temp_correlation(td_info->sensor,
++ *temp, temp);
++exit:
++ mutex_unlock(&thrm_update_lock);
++ return ret;
++}
++
++#ifdef CONFIG_DEBUG_THERMAL
++static int read_slope(struct thermal_zone_device *tzd, long *slope)
++{
++ struct thermal_device_info *td_info = tzd->devdata;
++
++ *slope = td_info->sensor->slope;
++
++ return 0;
++}
++
++static int update_slope(struct thermal_zone_device *tzd, long slope)
++{
++ struct thermal_device_info *td_info = tzd->devdata;
++
++ td_info->sensor->slope = slope;
++
++ return 0;
++}
++
++static int read_intercept(struct thermal_zone_device *tzd, long *intercept)
++{
++ struct thermal_device_info *td_info = tzd->devdata;
++
++ *intercept = td_info->sensor->intercept;
++
++ return 0;
++}
++
++static int update_intercept(struct thermal_zone_device *tzd, long intercept)
++{
++ struct thermal_device_info *td_info = tzd->devdata;
++
++ td_info->sensor->intercept = intercept;
++
++ return 0;
++}
++#endif
++
++static int enable_tm(void)
++{
++ int ret;
++ uint8_t data;
++
++ mutex_lock(&thrm_update_lock);
++
++ ret = intel_scu_ipc_ioread8(THRMMONCTL, &data);
++ if (ret)
++ goto ipc_fail;
++
++ ret = intel_scu_ipc_iowrite8(THRMMONCTL, data | THERM_EN);
++
++ipc_fail:
++ mutex_unlock(&thrm_update_lock);
++ return ret;
++}
++
++static struct thermal_device_info *initialize_sensor(
++ struct intel_mid_thermal_sensor *sensor)
++{
++ struct thermal_device_info *td_info =
++ kzalloc(sizeof(struct thermal_device_info), GFP_KERNEL);
++
++ if (!td_info)
++ return NULL;
++
++ td_info->sensor = sensor;
++
++ return td_info;
++}
++
++static irqreturn_t thermal_intrpt(int irq, void *dev_data)
++{
++ int ret, sensor, event_type;
++ uint8_t irq_status;
++ unsigned int irq_data;
++ struct thermal_data *tdata = (struct thermal_data *)dev_data;
++
++ if (!tdata)
++ return IRQ_NONE;
++
++ mutex_lock(&thrm_update_lock);
++
++ irq_data = ioread8(tdata->thrm_addr + PMIC_SRAM_THRM_OFFSET);
++
++ ret = intel_scu_ipc_ioread8(STHRMIRQ, &irq_status);
++ if (ret)
++ goto ipc_fail;
++
++ dev_dbg(&tdata->pdev->dev, "STHRMIRQ: %.2x\n", irq_status);
++
++ /*
++ * -1 for invalid interrupt
++ * 1 for LOW to HIGH temperature alert
++ * 0 for HIGH to LOW temperature alert
++ */
++ event_type = -1;
++
++ /* Check which interrupt occured and for what event */
++ if (irq_data & PMICALRT) {
++ event_type = !!(irq_status & PMICALRT);
++ sensor = PMIC_DIE;
++ } else if (irq_data & SYS2ALRT) {
++ event_type = !!(irq_status & SYS2ALRT);
++ sensor = SYS2;
++ } else if (irq_data & SYS1ALRT) {
++ event_type = !!(irq_status & SYS1ALRT);
++ sensor = SYS1;
++ } else if (irq_data & SYS0ALRT) {
++ event_type = !!(irq_status & SYS0ALRT);
++ sensor = SYS0;
++ } else {
++ dev_err(&tdata->pdev->dev, "Invalid Interrupt\n");
++ ret = IRQ_HANDLED;
++ goto ipc_fail;
++ }
++
++ if (event_type != -1) {
++ dev_info(&tdata->pdev->dev,
++ "%s interrupt for thermal sensor %d\n",
++ event_type ? "HIGH" : "LOW", sensor);
++ }
++
++ /* Notify using UEvent */
++ kobject_uevent(&tdata->pdev->dev.kobj, KOBJ_CHANGE);
++
++ /* Unmask Thermal Interrupt in the mask register */
++ ret = intel_scu_ipc_update_register(MIRQLVL1, 0xFF, THERM_ALRT);
++ if (ret)
++ goto ipc_fail;
++
++ ret = IRQ_HANDLED;
++
++ipc_fail:
++ mutex_unlock(&thrm_update_lock);
++ return ret;
++}
++
++static struct thermal_zone_device_ops tzd_ops = {
++ .get_temp = show_temp,
++ .get_trip_type = show_trip_type,
++ .get_trip_temp = show_trip_temp,
++ .set_trip_temp = store_trip_temp,
++ .get_trip_hyst = show_trip_hyst,
++ .set_trip_hyst = store_trip_hyst,
++#ifdef CONFIG_DEBUG_THERMAL
++ .get_slope = read_slope,
++ .set_slope = update_slope,
++ .get_intercept = read_intercept,
++ .set_intercept = update_intercept,
++#endif
++};
++
++static irqreturn_t mrfl_thermal_intrpt_handler(int irq, void* dev_data)
++{
++ return IRQ_WAKE_THREAD;
++}
++
++static int mrfl_thermal_probe(struct platform_device *pdev)
++{
++ int ret, i;
++ struct intel_mid_thermal_platform_data *pdata;
++
++ pdata = pdev->dev.platform_data;
++ if (!pdata) {
++ dev_err(&pdev->dev, "platform data not found\n");
++ return -EINVAL;
++ }
++
++ tdata = kzalloc(sizeof(struct thermal_data), GFP_KERNEL);
++ if (!tdata) {
++ dev_err(&pdev->dev, "kzalloc failed\n");
++ return -ENOMEM;
++ }
++
++ tdata->pdev = pdev;
++ tdata->num_sensors = pdata->num_sensors;
++ tdata->sensors = pdata->sensors;
++ tdata->irq = platform_get_irq(pdev, 0);
++ platform_set_drvdata(pdev, tdata);
++
++ tdata->tzd = kzalloc(
++ (sizeof(struct thermal_zone_device *) * tdata->num_sensors),
++ GFP_KERNEL);
++ if (!tdata->tzd) {
++ dev_err(&pdev->dev, "kzalloc failed\n");
++ ret = -ENOMEM;
++ goto exit_free;
++ }
++
++ /* Program a default _max value for each sensor */
++ ret = program_tmax(&pdev->dev);
++ if (ret) {
++ dev_err(&pdev->dev, "Programming _max failed:%d\n", ret);
++ goto exit_tzd;
++ }
++
++ /*
++ * Register with IIO to sample temperature values
++ *
++ * Order of the channels obtained from adc:
++ * "SYSTHERM0", "SYSTHERM1", "SYSTHERM2", "PMICDIE"
++ */
++ tdata->iio_chan = iio_channel_get_all(&pdev->dev);
++ if (tdata->iio_chan == NULL) {
++ dev_err(&pdev->dev, "tdata->iio_chan is null\n");
++ ret = -EINVAL;
++ goto exit_tzd;
++ }
++
++ /* Check whether we got all the four channels */
++ ret = iio_channel_get_num(tdata->iio_chan);
++ if (ret != PMIC_THERMAL_SENSORS) {
++ dev_err(&pdev->dev, "incorrect number of channels:%d\n", ret);
++ ret = -EFAULT;
++ goto exit_iio;
++ }
++
++ /* Register each sensor with the generic thermal framework */
++ for (i = 0; i < tdata->num_sensors; i++) {
++ tdata->tzd[i] = thermal_zone_device_register(
++ tdata->sensors[i].name, 1, 1,
++ initialize_sensor(&tdata->sensors[i]), &tzd_ops, NULL, 0, 0);
++
++ if (IS_ERR(tdata->tzd[i])) {
++ ret = PTR_ERR(tdata->tzd[i]);
++ dev_err(&pdev->dev,
++ "registering thermal sensor %s failed: %d\n",
++ tdata->sensors[i].name, ret);
++ goto exit_reg;
++ }
++ }
++
++ tdata->thrm_addr = ioremap_nocache(PMIC_SRAM_BASE_ADDR, IOMAP_SIZE);
++ if (!tdata->thrm_addr) {
++ ret = -ENOMEM;
++ dev_err(&pdev->dev, "ioremap_nocache failed\n");
++ goto exit_reg;
++ }
++
++ /* Register for Interrupt Handler */
++ ret = request_threaded_irq(tdata->irq, mrfl_thermal_intrpt_handler, thermal_intrpt,
++ IRQF_TRIGGER_RISING,
++ DRIVER_NAME, tdata);
++ if (ret) {
++ dev_err(&pdev->dev, "request_threaded_irq failed:%d\n", ret);
++ goto exit_ioremap;
++ }
++
++ /* Enable Thermal Monitoring */
++ ret = enable_tm();
++ if (ret) {
++ dev_err(&pdev->dev, "Enabling TM failed:%d\n", ret);
++ goto exit_irq;
++ }
++
++ return 0;
++
++exit_irq:
++ free_irq(tdata->irq, tdata);
++exit_ioremap:
++ iounmap(tdata->thrm_addr);
++exit_reg:
++ while (--i >= 0)
++ thermal_zone_device_unregister(tdata->tzd[i]);
++exit_iio:
++ iio_channel_release_all(tdata->iio_chan);
++exit_tzd:
++ kfree(tdata->tzd);
++exit_free:
++ kfree(tdata);
++ return ret;
++}
++
++static int mrfl_thermal_resume(struct device *dev)
++{
++ dev_info(dev, "resume called.\n");
++ return 0;
++}
++
++static int mrfl_thermal_suspend(struct device *dev)
++{
++ dev_info(dev, "suspend called.\n");
++ return 0;
++}
++
++static int mrfl_thermal_remove(struct platform_device *pdev)
++{
++ int i;
++ struct thermal_data *tdata = platform_get_drvdata(pdev);
++
++ if (!tdata)
++ return 0;
++
++ for (i = 0; i < tdata->num_sensors; i++)
++ thermal_zone_device_unregister(tdata->tzd[i]);
++
++ free_irq(tdata->irq, tdata);
++ iounmap(tdata->thrm_addr);
++ iio_channel_release_all(tdata->iio_chan);
++ kfree(tdata->tzd);
++ kfree(tdata);
++ return 0;
++}
++
++/*********************************************************************
++ * Driver initialization and finalization
++ *********************************************************************/
++
++static const struct dev_pm_ops thermal_pm_ops = {
++ .suspend = mrfl_thermal_suspend,
++ .resume = mrfl_thermal_resume,
++};
++
++static struct platform_driver mrfl_thermal_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .pm = &thermal_pm_ops,
++ },
++ .probe = mrfl_thermal_probe,
++ .remove = mrfl_thermal_remove,
++};
++
++static int mrfl_thermal_module_init(void)
++{
++ return platform_driver_register(&mrfl_thermal_driver);
++}
++
++static void mrfl_thermal_module_exit(void)
++{
++ platform_driver_unregister(&mrfl_thermal_driver);
++}
++
++/* RPMSG related functionality */
++static int mrfl_thermal_rpmsg_probe(struct rpmsg_channel *rpdev)
++{
++ if (!rpdev) {
++ pr_err("rpmsg channel not created\n");
++ return -ENODEV;
++ }
++
++ dev_info(&rpdev->dev, "Probed mrfl_thermal rpmsg device\n");
++
++ return mrfl_thermal_module_init();
++}
++
++static void mrfl_thermal_rpmsg_remove(struct rpmsg_channel *rpdev)
++{
++ mrfl_thermal_module_exit();
++ dev_info(&rpdev->dev, "Removed mrfl_thermal rpmsg device\n");
++}
++
++static void mrfl_thermal_rpmsg_cb(struct rpmsg_channel *rpdev, void *data,
++ int len, void *priv, u32 src)
++{
++ dev_warn(&rpdev->dev, "unexpected, message\n");
++
++ print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
++ data, len, true);
++}
++
++static struct rpmsg_device_id mrfl_thermal_id_table[] = {
++ { .name = "rpmsg_mrfl_thermal" },
++ { },
++};
++
++MODULE_DEVICE_TABLE(rpmsg, mrfl_thermal_id_table);
++
++static struct rpmsg_driver mrfl_thermal_rpmsg = {
++ .drv.name = DRIVER_NAME,
++ .drv.owner = THIS_MODULE,
++ .probe = mrfl_thermal_rpmsg_probe,
++ .callback = mrfl_thermal_rpmsg_cb,
++ .remove = mrfl_thermal_rpmsg_remove,
++ .id_table = mrfl_thermal_id_table,
++};
++
++static int __init mrfl_thermal_rpmsg_init(void)
++{
++ return register_rpmsg_driver(&mrfl_thermal_rpmsg);
++}
++
++static void __exit mrfl_thermal_rpmsg_exit(void)
++{
++ return unregister_rpmsg_driver(&mrfl_thermal_rpmsg);
++}
++
++module_init(mrfl_thermal_rpmsg_init);
++module_exit(mrfl_thermal_rpmsg_exit);
++
++MODULE_AUTHOR("Durgadoss R <durgadoss.r@intel.com>");
++MODULE_DESCRIPTION("Intel Merrifield Platform Thermal Driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/thermal/intel_soc_thermal.c b/drivers/thermal/intel_soc_thermal.c
+new file mode 100644
+index 0000000..f30b5371
+--- /dev/null
++++ b/drivers/thermal/intel_soc_thermal.c
+@@ -0,0 +1,834 @@
++/*
++ * intel_soc_thermal.c - Intel SoC Platform Thermal Driver
++ *
++ * Copyright (C) 2012 Intel Corporation
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * 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; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ * Author: Shravan B M <shravan.k.b.m@intel.com>
++ *
++ * This driver registers to Thermal framework as SoC zone. It exposes
++ * two SoC DTS temperature with two writeable trip points.
++ */
++
++#define pr_fmt(fmt) "intel_soc_thermal: " fmt
++
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/debugfs.h>
++#include <linux/thermal.h>
++#include <linux/seq_file.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <asm/msr.h>
++#include <asm/intel-mid.h>
++#include <asm/intel_mid_thermal.h>
++
++#define DRIVER_NAME "soc_thrm"
++
++/* SOC DTS Registers */
++#define SOC_THERMAL_SENSORS 2
++#define SOC_THERMAL_TRIPS 2
++#define SOC_MAX_STATES 4
++#define DTS_ENABLE_REG 0xB0
++#define DTS_ENABLE 0x03
++#define DTS_TRIP_RW 0x03
++
++#define PUNIT_PORT 0x04
++#define PUNIT_TEMP_REG 0xB1
++#define PUNIT_AUX_REG 0xB2
++
++#define TJMAX_TEMP 90
++#define TJMAX_CODE 0x7F
++
++/* Default hysteresis values in C */
++#define DEFAULT_H2C_HYST 3
++#define MAX_HYST 7
++
++/* Power Limit registers */
++#define PKG_TURBO_POWER_LIMIT 0x610
++#define PKG_TURBO_CFG 0x670
++#define MSR_THERM_CFG1 0x673
++#define CPU_PWR_BUDGET_CTL 0x02
++
++/* PKG_TURBO_PL1 holds PL1 in terms of 32mW */
++#define PL_UNIT_MW 32
++
++/* Magic number symbolising Dynamic Turbo OFF */
++#define DISABLE_DYNAMIC_TURBO 0xB0FF
++
++/* IRQ details */
++#define SOC_DTS_CONTROL 0x80
++#define TRIP_STATUS_RO 0xB3
++#define TRIP_STATUS_RW 0xB4
++/* TE stands for THERMAL_EVENT */
++#define TE_AUX0 0xB5
++#define ENABLE_AUX_INTRPT 0x0F
++#define ENABLE_CPU0 (1 << 16)
++#define RTE_ENABLE (1 << 9)
++
++static int tjmax_temp;
++
++static DEFINE_MUTEX(thrm_update_lock);
++
++struct platform_soc_data {
++ struct thermal_zone_device *tzd[SOC_THERMAL_SENSORS];
++ struct thermal_cooling_device *soc_cdev; /* PL1 control */
++ int irq;
++};
++
++struct cooling_device_info {
++ struct soc_throttle_data *soc_data;
++ /* Lock protecting the soc_cur_state variable */
++ struct mutex lock_state;
++ unsigned long soc_cur_state;
++};
++
++struct thermal_device_info {
++ int sensor_index;
++ struct mutex lock_aux;
++};
++
++static inline u32 read_soc_reg(unsigned int addr)
++{
++ return intel_mid_msgbus_read32(PUNIT_PORT, addr);
++}
++
++static inline void write_soc_reg(unsigned int addr, u32 val)
++{
++ intel_mid_msgbus_write32(PUNIT_PORT, addr, val);
++}
++
++#ifdef CONFIG_DEBUG_FS
++struct dts_regs {
++ char *name;
++ u32 addr;
++} dts_regs[] = {
++ /* Thermal Management Registers */
++ {"PTMC", 0x80},
++ {"TRR0", 0x81},
++ {"TRR1", 0x82},
++ {"TTS", 0x83},
++ {"TELB", 0x84},
++ {"TELT", 0x85},
++ {"GFXT", 0x88},
++ {"VEDT", 0x89},
++ {"VECT", 0x8A},
++ {"VSPT", 0x8B},
++ {"ISPT", 0x8C},
++ {"SWT", 0x8D},
++ /* Trip Event Registers */
++ {"DTSC", 0xB0},
++ {"TRR", 0xB1},
++ {"PTPS", 0xB2},
++ {"PTTS", 0xB3},
++ {"PTTSS", 0xB4},
++ {"TE_AUX0", 0xB5},
++ {"TE_AUX1", 0xB6},
++ {"TE_AUX2", 0xB7},
++ {"TE_AUX3", 0xB8},
++ {"TTE_VRIcc", 0xB9},
++ {"TTE_VRHOT", 0xBA},
++ {"TTE_PROCHOT", 0xBB},
++ {"TTE_SLM0", 0xBC},
++ {"TTE_SLM1", 0xBD},
++ {"BWTE", 0xBE},
++ {"TTE_SWT", 0xBF},
++ /* MSI Message Registers */
++ {"TMA", 0xC0},
++ {"TMD", 0xC1},
++};
++
++/* /sys/kernel/debug/soc_thermal/soc_dts */
++static struct dentry *soc_dts_dent;
++static struct dentry *soc_thermal_dir;
++
++static int soc_dts_debugfs_show(struct seq_file *s, void *unused)
++{
++ int i;
++ u32 val;
++
++ for (i = 0; i < ARRAY_SIZE(dts_regs); i++) {
++ val = read_soc_reg(dts_regs[i].addr);
++ seq_printf(s,
++ "%s[0x%X] Val: 0x%X\n",
++ dts_regs[i].name, dts_regs[i].addr, val);
++ }
++ return 0;
++}
++
++static int debugfs_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, soc_dts_debugfs_show, NULL);
++}
++
++static const struct file_operations soc_dts_debugfs_fops = {
++ .open = debugfs_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
++static void create_soc_dts_debugfs(void)
++{
++ int err;
++
++ /* /sys/kernel/debug/soc_thermal/ */
++ soc_thermal_dir = debugfs_create_dir("soc_thermal", NULL);
++ if (IS_ERR(soc_thermal_dir)) {
++ err = PTR_ERR(soc_thermal_dir);
++ pr_err("debugfs_create_dir failed:%d\n", err);
++ return;
++ }
++
++ /* /sys/kernel/debug/soc_thermal/soc_dts */
++ soc_dts_dent = debugfs_create_file("soc_dts", S_IFREG | S_IRUGO,
++ soc_thermal_dir, NULL,
++ &soc_dts_debugfs_fops);
++ if (IS_ERR(soc_dts_dent)) {
++ err = PTR_ERR(soc_dts_dent);
++ debugfs_remove_recursive(soc_thermal_dir);
++ pr_err("debugfs_create_file failed:%d\n", err);
++ }
++}
++
++static void remove_soc_dts_debugfs(void)
++{
++ debugfs_remove_recursive(soc_thermal_dir);
++}
++#else
++static inline void create_soc_dts_debugfs(void) { }
++static inline void remove_soc_dts_debugfs(void) { }
++#endif
++
++static
++struct cooling_device_info *initialize_cdev(struct platform_device *pdev)
++{
++ struct cooling_device_info *cdev_info =
++ kzalloc(sizeof(struct cooling_device_info), GFP_KERNEL);
++ if (!cdev_info)
++ return NULL;
++
++ cdev_info->soc_data = pdev->dev.platform_data;
++ mutex_init(&cdev_info->lock_state);
++ return cdev_info;
++}
++
++static struct thermal_device_info *initialize_sensor(int index)
++{
++ struct thermal_device_info *td_info =
++ kzalloc(sizeof(struct thermal_device_info), GFP_KERNEL);
++
++ if (!td_info)
++ return NULL;
++ td_info->sensor_index = index;
++ mutex_init(&td_info->lock_aux);
++
++ return td_info;
++}
++
++static void enable_soc_dts(void)
++{
++ int i;
++ u32 val, eax, edx;
++
++ rdmsr_on_cpu(0, MSR_THERM_CFG1, &eax, &edx);
++
++ /* B[8:10] H2C Hyst */
++ eax = (eax & ~(0x7 << 8)) | (DEFAULT_H2C_HYST << 8);
++
++ /* Set the Hysteresis value */
++ wrmsr_on_cpu(0, MSR_THERM_CFG1, eax, edx);
++
++ /* Enable the DTS */
++ write_soc_reg(DTS_ENABLE_REG, DTS_ENABLE);
++
++ val = read_soc_reg(SOC_DTS_CONTROL);
++ write_soc_reg(SOC_DTS_CONTROL, val | ENABLE_AUX_INTRPT | ENABLE_CPU0);
++
++ /* Enable Interrupts for all the AUX trips for the DTS */
++ for (i = 0; i < SOC_THERMAL_TRIPS; i++) {
++ val = read_soc_reg(TE_AUX0 + i);
++ write_soc_reg(TE_AUX0 + i, (val | RTE_ENABLE));
++ }
++}
++
++static int show_trip_hyst(struct thermal_zone_device *tzd,
++ int trip, long *hyst)
++{
++ u32 eax, edx;
++ struct thermal_device_info *td_info = tzd->devdata;
++
++ /* Hysteresis is only supported for trip point 0 */
++ if (trip != 0) {
++ *hyst = 0;
++ return 0;
++ }
++
++ mutex_lock(&td_info->lock_aux);
++
++ rdmsr_on_cpu(0, MSR_THERM_CFG1, &eax, &edx);
++
++ /* B[8:10] H2C Hyst, for trip 0. Report hysteresis in mC */
++ *hyst = ((eax >> 8) & 0x7) * 1000;
++
++ mutex_unlock(&td_info->lock_aux);
++ return 0;
++}
++
++static int store_trip_hyst(struct thermal_zone_device *tzd,
++ int trip, long hyst)
++{
++ u32 eax, edx;
++ struct thermal_device_info *td_info = tzd->devdata;
++
++ /* Convert from mC to C */
++ hyst /= 1000;
++
++ if (trip != 0 || hyst < 0 || hyst > MAX_HYST)
++ return -EINVAL;
++
++ mutex_lock(&td_info->lock_aux);
++
++ rdmsr_on_cpu(0, MSR_THERM_CFG1, &eax, &edx);
++
++ /* B[8:10] H2C Hyst */
++ eax = (eax & ~(0x7 << 8)) | (hyst << 8);
++
++ wrmsr_on_cpu(0, MSR_THERM_CFG1, eax, edx);
++
++ mutex_unlock(&td_info->lock_aux);
++ return 0;
++}
++
++static int show_temp(struct thermal_zone_device *tzd, long *temp)
++{
++ struct thermal_device_info *td_info = tzd->devdata;
++ u32 val = read_soc_reg(PUNIT_TEMP_REG);
++
++ /* Extract bits[0:7] or [8:15] using sensor_index */
++ *temp = (val >> (8 * td_info->sensor_index)) & 0xFF;
++
++ if (*temp == 0)
++ return 0;
++
++ /* Calibrate the temperature */
++ *temp = TJMAX_CODE - *temp + tjmax_temp;
++
++ /* Convert to mC */
++ *temp *= 1000;
++
++ return 0;
++}
++
++static int show_trip_type(struct thermal_zone_device *tzd,
++ int trip, enum thermal_trip_type *trip_type)
++{
++ /* All are passive trip points */
++ *trip_type = THERMAL_TRIP_PASSIVE;
++
++ return 0;
++}
++
++static int show_trip_temp(struct thermal_zone_device *tzd,
++ int trip, long *trip_temp)
++{
++ u32 aux_value = read_soc_reg(PUNIT_AUX_REG);
++
++ /* aux0 b[0:7], aux1 b[8:15], aux2 b[16:23], aux3 b[24:31] */
++ *trip_temp = (aux_value >> (8 * trip)) & 0xFF;
++
++ /* Calibrate the trip point temperature */
++ *trip_temp = tjmax_temp - *trip_temp;
++
++ /* Convert to mC and report */
++ *trip_temp *= 1000;
++
++ return 0;
++}
++
++static int store_trip_temp(struct thermal_zone_device *tzd,
++ int trip, long trip_temp)
++{
++ u32 aux_trip, aux = 0;
++ struct thermal_device_info *td_info = tzd->devdata;
++
++ /* Convert from mC to C */
++ trip_temp /= 1000;
++
++ /* The trip temp is 8 bits wide (unsigned) */
++ if (trip_temp > 255)
++ return -EINVAL;
++
++ /* Assign last byte to unsigned 32 */
++ aux_trip = trip_temp & 0xFF;
++
++ /* Calibrate w.r.t TJMAX_TEMP */
++ aux_trip = tjmax_temp - aux_trip;
++
++ mutex_lock(&td_info->lock_aux);
++ aux = read_soc_reg(PUNIT_AUX_REG);
++ switch (trip) {
++ case 0:
++ /* aux0 bits 0:7 */
++ aux = (aux & 0xFFFFFF00) | (aux_trip << (8 * trip));
++ break;
++ case 1:
++ /* aux1 bits 8:15 */
++ aux = (aux & 0xFFFF00FF) | (aux_trip << (8 * trip));
++ break;
++ }
++ write_soc_reg(PUNIT_AUX_REG, aux);
++
++ mutex_unlock(&td_info->lock_aux);
++
++ return 0;
++}
++
++/* SoC cooling device callbacks */
++static int soc_get_max_state(struct thermal_cooling_device *cdev,
++ unsigned long *state)
++{
++ /* SoC has 4 levels of throttling from 0 to 3 */
++ *state = SOC_MAX_STATES - 1;
++ return 0;
++}
++
++static int soc_get_cur_state(struct thermal_cooling_device *cdev,
++ unsigned long *state)
++{
++ struct cooling_device_info *cdev_info =
++ (struct cooling_device_info *)cdev->devdata;
++
++ mutex_lock(&cdev_info->lock_state);
++ *state = cdev_info->soc_cur_state;
++ mutex_unlock(&cdev_info->lock_state);
++
++ return 0;
++}
++
++static void set_floor_freq(int val)
++{
++ u32 eax;
++
++ eax = read_soc_reg(CPU_PWR_BUDGET_CTL);
++
++ /* Set bits[8:14] of eax to val */
++ eax = (eax & ~(0x7F << 8)) | (val << 8);
++
++ write_soc_reg(CPU_PWR_BUDGET_CTL, eax);
++}
++
++static int disable_dynamic_turbo(struct cooling_device_info *cdev_info)
++{
++ u32 eax, edx;
++
++ mutex_lock(&cdev_info->lock_state);
++
++ rdmsr_on_cpu(0, PKG_TURBO_CFG, &eax, &edx);
++
++ /* Set bits[0:2] to 0 to enable TjMax Turbo mode */
++ eax = eax & ~0x07;
++
++ /* Set bit[8] to 0 to disable Dynamic Turbo */
++ eax = eax & ~(1 << 8);
++
++ /* Set bits[9:11] to 0 disable Dynamic Turbo Policy */
++ eax = eax & ~(0x07 << 9);
++
++ wrmsr_on_cpu(0, PKG_TURBO_CFG, eax, edx);
++
++ /*
++ * Now that we disabled Dynamic Turbo, we can
++ * make the floor frequency ratio also 0.
++ */
++ set_floor_freq(0);
++
++ cdev_info->soc_cur_state = DISABLE_DYNAMIC_TURBO;
++
++ mutex_unlock(&cdev_info->lock_state);
++ return 0;
++}
++
++static int soc_set_cur_state(struct thermal_cooling_device *cdev,
++ unsigned long state)
++{
++ u32 eax, edx;
++ struct soc_throttle_data *data;
++ struct cooling_device_info *cdev_info =
++ (struct cooling_device_info *)cdev->devdata;
++
++ if (state == DISABLE_DYNAMIC_TURBO)
++ return disable_dynamic_turbo(cdev_info);
++
++ if (state >= SOC_MAX_STATES) {
++ pr_err("Invalid SoC throttle state:%ld\n", state);
++ return -EINVAL;
++ }
++
++ mutex_lock(&cdev_info->lock_state);
++
++ data = &cdev_info->soc_data[state];
++
++ rdmsr_on_cpu(0, PKG_TURBO_POWER_LIMIT, &eax, &edx);
++
++ /* Set bits[0:14] of eax to 'data->power_limit' */
++ eax = (eax & ~0x7FFF) | data->power_limit;
++
++ wrmsr_on_cpu(0, PKG_TURBO_POWER_LIMIT, eax, edx);
++
++ set_floor_freq(data->floor_freq);
++
++ cdev_info->soc_cur_state = state;
++
++ mutex_unlock(&cdev_info->lock_state);
++ return 0;
++}
++
++#ifdef CONFIG_DEBUG_THERMAL
++static int soc_get_force_state_override(struct thermal_cooling_device *cdev,
++ char *buf)
++{
++ int i;
++ int pl1_vals_mw[SOC_MAX_STATES];
++ struct cooling_device_info *cdev_info =
++ (struct cooling_device_info *)cdev->devdata;
++
++ mutex_lock(&cdev_info->lock_state);
++
++ /* PKG_TURBO_PL1 holds PL1 in terms of 32mW. So, multiply by 32 */
++ for (i = 0; i < SOC_MAX_STATES; i++) {
++ pl1_vals_mw[i] =
++ cdev_info->soc_data[i].power_limit * PL_UNIT_MW;
++ }
++
++ mutex_unlock(&cdev_info->lock_state);
++
++ return sprintf(buf, "%d %d %d %d\n", pl1_vals_mw[0], pl1_vals_mw[1],
++ pl1_vals_mw[2], pl1_vals_mw[3]);
++}
++
++static int soc_set_force_state_override(struct thermal_cooling_device *cdev,
++ char *buf)
++{
++ int i, ret;
++ int pl1_vals_mw[SOC_MAX_STATES];
++ unsigned long cur_state;
++ struct cooling_device_info *cdev_info =
++ (struct cooling_device_info *)cdev->devdata;
++
++ /*
++ * The four space separated values entered via the sysfs node
++ * override the default values configured through platform data.
++ */
++ ret = sscanf(buf, "%d %d %d %d", &pl1_vals_mw[0], &pl1_vals_mw[1],
++ &pl1_vals_mw[2], &pl1_vals_mw[3]);
++ if (ret != SOC_MAX_STATES) {
++ pr_err("Invalid values in soc_set_force_state_override\n");
++ return -EINVAL;
++ }
++
++ mutex_lock(&cdev_info->lock_state);
++
++ /* PKG_TURBO_PL1 takes PL1 in terms of 32mW. So, divide by 32 */
++ for (i = 0; i < SOC_MAX_STATES; i++) {
++ cdev_info->soc_data[i].power_limit =
++ pl1_vals_mw[i] / PL_UNIT_MW;
++ }
++
++ /* Update the cur_state value of this cooling device */
++ cur_state = cdev_info->soc_cur_state;
++
++ mutex_unlock(&cdev_info->lock_state);
++
++ return soc_set_cur_state(cdev, cur_state);
++}
++#endif
++
++static void notify_thermal_event(struct thermal_zone_device *tzd,
++ long temp, int event, int level)
++{
++ char *thermal_event[5];
++
++ pr_info("Thermal Event: sensor: %s, cur_temp: %ld, event: %d, level: %d\n",
++ tzd->type, temp, event, level);
++
++ thermal_event[0] = kasprintf(GFP_KERNEL, "NAME=%s", tzd->type);
++ thermal_event[1] = kasprintf(GFP_KERNEL, "TEMP=%ld", temp);
++ thermal_event[2] = kasprintf(GFP_KERNEL, "EVENT=%d", event);
++ thermal_event[3] = kasprintf(GFP_KERNEL, "LEVEL=%d", level);
++ thermal_event[4] = NULL;
++
++ kobject_uevent_env(&tzd->device.kobj, KOBJ_CHANGE, thermal_event);
++
++ kfree(thermal_event[3]);
++ kfree(thermal_event[2]);
++ kfree(thermal_event[1]);
++ kfree(thermal_event[0]);
++
++ return;
++}
++
++static int get_max_temp(struct platform_soc_data *pdata, long *cur_temp)
++{
++ int i, ret;
++ long temp;
++
++ /*
++ * The SoC has two or more DTS placed, to determine the
++ * temperature of the SoC. The hardware actions are taken
++ * using T(DTS) which is MAX(T(DTS0), T(DTS1), ... T(DTSn))
++ *
++ * Do not report error, as long as we can read at least
++ * one DTS correctly.
++ */
++ ret = show_temp(pdata->tzd[0], cur_temp);
++ if (ret)
++ return ret;
++
++ for (i = 1; i < SOC_THERMAL_SENSORS; i++) {
++ ret = show_temp(pdata->tzd[i], &temp);
++ if (ret)
++ goto fail_safe;
++
++ if (temp > *cur_temp)
++ *cur_temp = temp;
++ }
++
++fail_safe:
++ /*
++ * We have one valid DTS temperature; Use that,
++ * instead of reporting error.
++ */
++ return 0;
++}
++
++static irqreturn_t soc_dts_intrpt(int irq, void *dev_data)
++{
++ u32 irq_sts, cur_sts;
++ int i, ret, event, level = -1;
++ long cur_temp;
++ struct thermal_zone_device *tzd;
++ struct platform_soc_data *pdata = (struct platform_soc_data *)dev_data;
++
++ if (!pdata || !pdata->tzd[0])
++ return IRQ_NONE;
++
++ mutex_lock(&thrm_update_lock);
++
++ tzd = pdata->tzd[0];
++
++ irq_sts = read_soc_reg(TRIP_STATUS_RW);
++ cur_sts = read_soc_reg(TRIP_STATUS_RO);
++
++ for (i = 0; i < SOC_THERMAL_TRIPS; i++) {
++ if (irq_sts & (1 << i)) {
++ level = i;
++ event = !!(cur_sts & (1 << i));
++ /* Clear the status bit by writing 1 */
++ irq_sts |= (1 << i);
++ break;
++ }
++ }
++
++ /* level == -1, indicates an invalid event */
++ if (level == -1) {
++ dev_err(&tzd->device, "Invalid event from SoC DTS\n");
++ goto exit;
++ }
++
++ ret = get_max_temp(pdata, &cur_temp);
++ if (ret) {
++ dev_err(&tzd->device, "Cannot read SoC DTS temperature\n");
++ goto exit;
++ }
++
++ /* Notify using UEvent */
++ notify_thermal_event(tzd, cur_temp, event, level);
++
++ /* Clear the status bits */
++ write_soc_reg(TRIP_STATUS_RW, irq_sts);
++
++exit:
++ mutex_unlock(&thrm_update_lock);
++ return IRQ_HANDLED;
++}
++
++static struct thermal_zone_device_ops tzd_ops = {
++ .get_temp = show_temp,
++ .get_trip_type = show_trip_type,
++ .get_trip_temp = show_trip_temp,
++ .set_trip_temp = store_trip_temp,
++ .get_trip_hyst = show_trip_hyst,
++ .set_trip_hyst = store_trip_hyst,
++};
++
++static struct thermal_cooling_device_ops soc_cooling_ops = {
++ .get_max_state = soc_get_max_state,
++ .get_cur_state = soc_get_cur_state,
++ .set_cur_state = soc_set_cur_state,
++#ifdef CONFIG_DEBUG_THERMAL
++ .get_force_state_override = soc_get_force_state_override,
++ .set_force_state_override = soc_set_force_state_override,
++#endif
++};
++
++/*********************************************************************
++ * Driver initialization and finalization
++ *********************************************************************/
++
++static irqreturn_t soc_dts_intrpt_handler(int irq, void *dev_data)
++{
++ return IRQ_WAKE_THREAD;
++}
++
++static int soc_thermal_probe(struct platform_device *pdev)
++{
++ struct platform_soc_data *pdata;
++ int i, ret;
++ u32 eax, edx;
++ static char *name[SOC_THERMAL_SENSORS] = {"SoC_DTS0", "SoC_DTS1"};
++
++ pdata = kzalloc(sizeof(struct platform_soc_data), GFP_KERNEL);
++ if (!pdata)
++ return -ENOMEM;
++
++ ret = rdmsr_safe_on_cpu(0, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
++ if (ret) {
++ tjmax_temp = TJMAX_TEMP;
++ dev_err(&pdev->dev, "TjMax read from MSR %x failed, error:%d\n",
++ MSR_IA32_TEMPERATURE_TARGET, ret);
++ } else {
++ tjmax_temp = (eax >> 16) & 0xff;
++ dev_dbg(&pdev->dev, "TjMax is %d degrees C\n", tjmax_temp);
++ }
++
++ /* Register each sensor with the generic thermal framework */
++ for (i = 0; i < SOC_THERMAL_SENSORS; i++) {
++ pdata->tzd[i] = thermal_zone_device_register(name[i],
++ SOC_THERMAL_TRIPS, DTS_TRIP_RW,
++ initialize_sensor(i),
++ &tzd_ops, NULL, 0, 0);
++ if (IS_ERR(pdata->tzd[i])) {
++ ret = PTR_ERR(pdata->tzd[i]);
++ dev_err(&pdev->dev, "tzd register failed: %d\n", ret);
++ goto exit_reg;
++ }
++ }
++
++ /* Register a cooling device for PL1 (power limit) control */
++ pdata->soc_cdev = thermal_cooling_device_register("SoC",
++ initialize_cdev(pdev),
++ &soc_cooling_ops);
++ if (IS_ERR(pdata->soc_cdev)) {
++ ret = PTR_ERR(pdata->soc_cdev);
++ pdata->soc_cdev = NULL;
++ goto exit_reg;
++ }
++
++ platform_set_drvdata(pdev, pdata);
++
++ ret = platform_get_irq(pdev, 0);
++ if (ret < 0) {
++ dev_err(&pdev->dev, "platform_get_irq failed:%d\n", ret);
++ goto exit_cdev;
++ }
++
++ pdata->irq = ret;
++
++ /* Register for Interrupt Handler */
++ ret = request_threaded_irq(pdata->irq, soc_dts_intrpt_handler,
++ soc_dts_intrpt,
++ IRQF_TRIGGER_RISING,
++ DRIVER_NAME, pdata);
++ if (ret) {
++ dev_err(&pdev->dev, "request_threaded_irq failed:%d\n", ret);
++ goto exit_cdev;
++ }
++
++ /* Enable DTS0 and DTS1 */
++ enable_soc_dts();
++
++ create_soc_dts_debugfs();
++
++ return 0;
++
++exit_cdev:
++ thermal_cooling_device_unregister(pdata->soc_cdev);
++exit_reg:
++ while (--i >= 0) {
++ struct thermal_device_info *td_info = pdata->tzd[i]->devdata;
++ kfree(td_info);
++ thermal_zone_device_unregister(pdata->tzd[i]);
++ }
++ platform_set_drvdata(pdev, NULL);
++ kfree(pdata);
++ return ret;
++}
++
++static int soc_thermal_remove(struct platform_device *pdev)
++{
++ int i;
++ struct platform_soc_data *pdata = platform_get_drvdata(pdev);
++
++ /* Unregister each sensor with the generic thermal framework */
++ for (i = 0; i < SOC_THERMAL_SENSORS; i++) {
++ struct thermal_device_info *td_info = pdata->tzd[i]->devdata;
++ kfree(td_info);
++ thermal_zone_device_unregister(pdata->tzd[i]);
++ }
++ thermal_cooling_device_unregister(pdata->soc_cdev);
++ platform_set_drvdata(pdev, NULL);
++ free_irq(pdata->irq, pdata);
++ kfree(pdata);
++
++ remove_soc_dts_debugfs();
++
++ return 0;
++}
++
++static const struct platform_device_id therm_id_table[] = {
++ { DRIVER_NAME, 1},
++};
++
++static struct platform_driver soc_thermal_driver = {
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = DRIVER_NAME,
++ },
++ .probe = soc_thermal_probe,
++ .remove = soc_thermal_remove,
++ .id_table = therm_id_table,
++};
++
++static int __init soc_thermal_module_init(void)
++{
++ return platform_driver_register(&soc_thermal_driver);
++}
++
++static void __exit soc_thermal_module_exit(void)
++{
++ platform_driver_unregister(&soc_thermal_driver);
++}
++
++module_init(soc_thermal_module_init);
++module_exit(soc_thermal_module_exit);
++
++MODULE_AUTHOR("Shravan B M <shravan.k.b.m@intel.com>");
++MODULE_DESCRIPTION("Intel SoC Thermal Driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
+index d755440..94d9b0b 100644
+--- a/drivers/thermal/thermal_core.c
++++ b/drivers/thermal/thermal_core.c
+@@ -563,7 +563,7 @@ trip_point_temp_store(struct device *dev, struct device_attribute *attr,
+ {
+ struct thermal_zone_device *tz = to_thermal_zone(dev);
+ int trip, ret;
+- unsigned long temperature;
++ long temperature;
+
+ if (!tz->ops->set_trip_temp)
+ return -EPERM;
+@@ -707,6 +707,82 @@ passive_show(struct device *dev, struct device_attribute *attr,
+ }
+
+ static ssize_t
++slope_store(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ int ret;
++ long slope;
++ struct thermal_zone_device *tz = to_thermal_zone(dev);
++
++ if (!tz->ops->set_slope)
++ return -EPERM;
++
++ if (kstrtol(buf, 10, &slope))
++ return -EINVAL;
++
++ ret = tz->ops->set_slope(tz, slope);
++ if (ret)
++ return ret;
++
++ return count;
++}
++
++static ssize_t
++slope_show(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ int ret;
++ long slope;
++ struct thermal_zone_device *tz = to_thermal_zone(dev);
++
++ if (!tz->ops->get_slope)
++ return -EINVAL;
++
++ ret = tz->ops->get_slope(tz, &slope);
++ if (ret)
++ return ret;
++
++ return sprintf(buf, "%ld\n", slope);
++}
++
++static ssize_t
++intercept_store(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ int ret;
++ long intercept;
++ struct thermal_zone_device *tz = to_thermal_zone(dev);
++
++ if (!tz->ops->set_intercept)
++ return -EPERM;
++
++ if (kstrtol(buf, 10, &intercept))
++ return -EINVAL;
++
++ ret = tz->ops->set_intercept(tz, intercept);
++ if (ret)
++ return ret;
++
++ return count;
++}
++
++static ssize_t
++intercept_show(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ int ret;
++ long intercept;
++ struct thermal_zone_device *tz = to_thermal_zone(dev);
++
++ if (!tz->ops->get_intercept)
++ return -EINVAL;
++
++ ret = tz->ops->get_intercept(tz, &intercept);
++ if (ret)
++ return ret;
++
++ return sprintf(buf, "%ld\n", intercept);
++}
++
++static ssize_t
+ policy_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+ {
+@@ -765,6 +841,9 @@ static DEVICE_ATTR(type, 0444, type_show, NULL);
+ static DEVICE_ATTR(temp, 0444, temp_show, NULL);
+ static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
+ static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store);
++static DEVICE_ATTR(slope, S_IRUGO | S_IWUSR, slope_show, slope_store);
++static DEVICE_ATTR(intercept,
++ S_IRUGO | S_IWUSR, intercept_show, intercept_store);
+ static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
+
+ /* sys I/F for cooling device */
+@@ -794,6 +873,43 @@ thermal_cooling_device_max_state_show(struct device *dev,
+ return sprintf(buf, "%ld\n", state);
+ }
+
++/*
++ * Sysfs to read the mapped values and to override
++ * the default values mapped to each state during runtime.
++ */
++static ssize_t
++thermal_cooling_device_force_state_override_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct thermal_cooling_device *cdev = to_cooling_device(dev);
++
++ return cdev->ops->get_force_state_override(cdev, buf);
++}
++
++static ssize_t
++thermal_cooling_device_force_state_override_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ int ret;
++ struct thermal_cooling_device *cdev = to_cooling_device(dev);
++
++ ret = cdev->ops->set_force_state_override(cdev, (char *) buf);
++ if (ret)
++ return ret;
++
++ return count;
++}
++
++static ssize_t
++thermal_cooling_device_available_states_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct thermal_cooling_device *cdev = to_cooling_device(dev);
++
++ return cdev->ops->get_available_states(cdev, buf);
++}
++
+ static ssize_t
+ thermal_cooling_device_cur_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+@@ -836,6 +952,11 @@ static DEVICE_ATTR(max_state, 0444,
+ static DEVICE_ATTR(cur_state, 0644,
+ thermal_cooling_device_cur_state_show,
+ thermal_cooling_device_cur_state_store);
++static DEVICE_ATTR(force_state_override, 0644,
++ thermal_cooling_device_force_state_override_show,
++ thermal_cooling_device_force_state_override_store);
++static DEVICE_ATTR(available_states, 0444,
++ thermal_cooling_device_available_states_show, NULL);
+
+ static ssize_t
+ thermal_cooling_device_trip_point_show(struct device *dev,
+@@ -1017,7 +1138,7 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
+ goto free_temp_mem;
+
+ if (tz->ops->get_crit_temp) {
+- unsigned long temperature;
++ long temperature;
+ if (!tz->ops->get_crit_temp(tz, &temperature)) {
+ snprintf(temp->temp_crit.name,
+ sizeof(temp->temp_crit.name),
+@@ -1347,13 +1468,26 @@ thermal_cooling_device_register(char *type, void *devdata,
+
+ result = device_create_file(&cdev->device, &dev_attr_max_state);
+ if (result)
+- goto unregister;
++ goto remove_type;
+
+ result = device_create_file(&cdev->device, &dev_attr_cur_state);
+ if (result)
+- goto unregister;
++ goto remove_max_state;
++
++ if (ops->get_force_state_override) {
++ result = device_create_file(&cdev->device,
++ &dev_attr_force_state_override);
++ if (result)
++ goto remove_cur_state;
++ }
+
+ /* Add 'this' new cdev to the global cdev list */
++ if (ops->get_available_states) {
++ result = device_create_file(&cdev->device,
++ &dev_attr_available_states);
++ if (result)
++ goto remove_force_override;
++ }
+ mutex_lock(&thermal_list_lock);
+ list_add(&cdev->node, &thermal_cdev_list);
+ mutex_unlock(&thermal_list_lock);
+@@ -1363,6 +1497,16 @@ thermal_cooling_device_register(char *type, void *devdata,
+
+ return cdev;
+
++remove_force_override:
++ if (cdev->ops->get_force_state_override)
++ device_remove_file(&cdev->device,
++ &dev_attr_force_state_override);
++remove_cur_state:
++ device_remove_file(&cdev->device, &dev_attr_cur_state);
++remove_max_state:
++ device_remove_file(&cdev->device, &dev_attr_max_state);
++remove_type:
++ device_remove_file(&cdev->device, &dev_attr_cdev_type);
+ unregister:
+ release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
+ device_unregister(&cdev->device);
+@@ -1423,7 +1567,12 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
+ device_remove_file(&cdev->device, &dev_attr_cdev_type);
+ device_remove_file(&cdev->device, &dev_attr_max_state);
+ device_remove_file(&cdev->device, &dev_attr_cur_state);
+-
++ if (cdev->ops->get_force_state_override)
++ device_remove_file(&cdev->device,
++ &dev_attr_force_state_override);
++ if (cdev->ops->get_available_states)
++ device_remove_file(&cdev->device,
++ &dev_attr_available_states);
+ release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
+ device_unregister(&cdev->device);
+ return;
+@@ -1690,6 +1839,19 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
+ goto unregister;
+ }
+
++ /* Create Sysfs for slope/intercept values */
++ if (tz->ops->get_slope) {
++ result = device_create_file(&tz->device, &dev_attr_slope);
++ if (result)
++ goto unregister;
++ }
++
++ if (tz->ops->get_intercept) {
++ result = device_create_file(&tz->device, &dev_attr_intercept);
++ if (result)
++ goto unregister;
++ }
++
+ #ifdef CONFIG_THERMAL_EMULATION
+ result = device_create_file(&tz->device, &dev_attr_emul_temp);
+ if (result)
+@@ -1789,6 +1951,11 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
+ device_remove_file(&tz->device, &dev_attr_temp);
+ if (tz->ops->get_mode)
+ device_remove_file(&tz->device, &dev_attr_mode);
++ if (tz->ops->get_slope)
++ device_remove_file(&tz->device, &dev_attr_slope);
++ if (tz->ops->get_intercept)
++ device_remove_file(&tz->device, &dev_attr_intercept);
++
+ device_remove_file(&tz->device, &dev_attr_policy);
+ remove_trip_attrs(tz);
+ tz->governor = NULL;
+diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
+index 7e7006f..d30915d 100644
+--- a/drivers/tty/serial/Kconfig
++++ b/drivers/tty/serial/Kconfig
+@@ -455,14 +455,14 @@ config SERIAL_MRST_MAX3110
+ driver.
+
+ config SERIAL_MFD_HSU
+- tristate "Medfield High Speed UART support"
+- depends on PCI
+- select SERIAL_CORE
++ tristate "Medfield High Speed UART support"
++ depends on PCI
++ select SERIAL_CORE
+
+ config SERIAL_MFD_HSU_CONSOLE
+- boolean "Medfile HSU serial console support"
+- depends on SERIAL_MFD_HSU=y
+- select SERIAL_CORE_CONSOLE
++ boolean "Medfield HSU serial console support"
++ depends on SERIAL_MFD_HSU=y
++ select SERIAL_CORE_CONSOLE
+
+ config SERIAL_BFIN
+ tristate "Blackfin serial port support"
+diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
+index eedfec4..569abef 100644
+--- a/drivers/tty/serial/Makefile
++++ b/drivers/tty/serial/Makefile
+@@ -72,7 +72,7 @@ obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
+ obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
+ obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o
+ obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o
+-obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o
++obj-$(CONFIG_SERIAL_MFD_HSU) += mfd_core.o mfd_dma.o mfd_pci.o mfd_plat.o
+ obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o
+ obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o
+ obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o
+diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c
+deleted file mode 100644
+index 5f4765a..0000000
+--- a/drivers/tty/serial/mfd.c
++++ /dev/null
+@@ -1,1502 +0,0 @@
+-/*
+- * mfd.c: driver for High Speed UART device of Intel Medfield platform
+- *
+- * Refer pxa.c, 8250.c and some other drivers in drivers/serial/
+- *
+- * (C) Copyright 2010 Intel Corporation
+- *
+- * 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; version 2
+- * of the License.
+- */
+-
+-/* Notes:
+- * 1. DMA channel allocation: 0/1 channel are assigned to port 0,
+- * 2/3 chan to port 1, 4/5 chan to port 3. Even number chans
+- * are used for RX, odd chans for TX
+- *
+- * 2. The RI/DSR/DCD/DTR are not pinned out, DCD & DSR are always
+- * asserted, only when the HW is reset the DDCD and DDSR will
+- * be triggered
+- */
+-
+-#include <linux/module.h>
+-#include <linux/init.h>
+-#include <linux/console.h>
+-#include <linux/sysrq.h>
+-#include <linux/slab.h>
+-#include <linux/serial_reg.h>
+-#include <linux/circ_buf.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/tty.h>
+-#include <linux/tty_flip.h>
+-#include <linux/serial_core.h>
+-#include <linux/serial_mfd.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/pci.h>
+-#include <linux/nmi.h>
+-#include <linux/io.h>
+-#include <linux/debugfs.h>
+-#include <linux/pm_runtime.h>
+-
+-#define HSU_DMA_BUF_SIZE 2048
+-
+-#define chan_readl(chan, offset) readl(chan->reg + offset)
+-#define chan_writel(chan, offset, val) writel(val, chan->reg + offset)
+-
+-#define mfd_readl(obj, offset) readl(obj->reg + offset)
+-#define mfd_writel(obj, offset, val) writel(val, obj->reg + offset)
+-
+-static int hsu_dma_enable;
+-module_param(hsu_dma_enable, int, 0);
+-MODULE_PARM_DESC(hsu_dma_enable,
+- "It is a bitmap to set working mode, if bit[x] is 1, then port[x] will work in DMA mode, otherwise in PIO mode.");
+-
+-struct hsu_dma_buffer {
+- u8 *buf;
+- dma_addr_t dma_addr;
+- u32 dma_size;
+- u32 ofs;
+-};
+-
+-struct hsu_dma_chan {
+- u32 id;
+- enum dma_data_direction dirt;
+- struct uart_hsu_port *uport;
+- void __iomem *reg;
+-};
+-
+-struct uart_hsu_port {
+- struct uart_port port;
+- unsigned char ier;
+- unsigned char lcr;
+- unsigned char mcr;
+- unsigned int lsr_break_flag;
+- char name[12];
+- int index;
+- struct device *dev;
+-
+- struct hsu_dma_chan *txc;
+- struct hsu_dma_chan *rxc;
+- struct hsu_dma_buffer txbuf;
+- struct hsu_dma_buffer rxbuf;
+- int use_dma; /* flag for DMA/PIO */
+- int running;
+- int dma_tx_on;
+-};
+-
+-/* Top level data structure of HSU */
+-struct hsu_port {
+- void __iomem *reg;
+- unsigned long paddr;
+- unsigned long iolen;
+- u32 irq;
+-
+- struct uart_hsu_port port[3];
+- struct hsu_dma_chan chans[10];
+-
+- struct dentry *debugfs;
+-};
+-
+-static inline unsigned int serial_in(struct uart_hsu_port *up, int offset)
+-{
+- unsigned int val;
+-
+- if (offset > UART_MSR) {
+- offset <<= 2;
+- val = readl(up->port.membase + offset);
+- } else
+- val = (unsigned int)readb(up->port.membase + offset);
+-
+- return val;
+-}
+-
+-static inline void serial_out(struct uart_hsu_port *up, int offset, int value)
+-{
+- if (offset > UART_MSR) {
+- offset <<= 2;
+- writel(value, up->port.membase + offset);
+- } else {
+- unsigned char val = value & 0xff;
+- writeb(val, up->port.membase + offset);
+- }
+-}
+-
+-#ifdef CONFIG_DEBUG_FS
+-
+-#define HSU_REGS_BUFSIZE 1024
+-
+-
+-static ssize_t port_show_regs(struct file *file, char __user *user_buf,
+- size_t count, loff_t *ppos)
+-{
+- struct uart_hsu_port *up = file->private_data;
+- char *buf;
+- u32 len = 0;
+- ssize_t ret;
+-
+- buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL);
+- if (!buf)
+- return 0;
+-
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "MFD HSU port[%d] regs:\n", up->index);
+-
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "=================================\n");
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "IER: \t\t0x%08x\n", serial_in(up, UART_IER));
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "IIR: \t\t0x%08x\n", serial_in(up, UART_IIR));
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "LCR: \t\t0x%08x\n", serial_in(up, UART_LCR));
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "MCR: \t\t0x%08x\n", serial_in(up, UART_MCR));
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "LSR: \t\t0x%08x\n", serial_in(up, UART_LSR));
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "MSR: \t\t0x%08x\n", serial_in(up, UART_MSR));
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "FOR: \t\t0x%08x\n", serial_in(up, UART_FOR));
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "PS: \t\t0x%08x\n", serial_in(up, UART_PS));
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "MUL: \t\t0x%08x\n", serial_in(up, UART_MUL));
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "DIV: \t\t0x%08x\n", serial_in(up, UART_DIV));
+-
+- if (len > HSU_REGS_BUFSIZE)
+- len = HSU_REGS_BUFSIZE;
+-
+- ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+- kfree(buf);
+- return ret;
+-}
+-
+-static ssize_t dma_show_regs(struct file *file, char __user *user_buf,
+- size_t count, loff_t *ppos)
+-{
+- struct hsu_dma_chan *chan = file->private_data;
+- char *buf;
+- u32 len = 0;
+- ssize_t ret;
+-
+- buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL);
+- if (!buf)
+- return 0;
+-
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "MFD HSU DMA channel [%d] regs:\n", chan->id);
+-
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "=================================\n");
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "CR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_CR));
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "DCR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_DCR));
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "BSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_BSR));
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "MOTSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_MOTSR));
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0SAR));
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0TSR));
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1SAR));
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1TSR));
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2SAR));
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2TSR));
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3SAR));
+- len += snprintf(buf + len, HSU_REGS_BUFSIZE - len,
+- "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3TSR));
+-
+- if (len > HSU_REGS_BUFSIZE)
+- len = HSU_REGS_BUFSIZE;
+-
+- ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+- kfree(buf);
+- return ret;
+-}
+-
+-static const struct file_operations port_regs_ops = {
+- .owner = THIS_MODULE,
+- .open = simple_open,
+- .read = port_show_regs,
+- .llseek = default_llseek,
+-};
+-
+-static const struct file_operations dma_regs_ops = {
+- .owner = THIS_MODULE,
+- .open = simple_open,
+- .read = dma_show_regs,
+- .llseek = default_llseek,
+-};
+-
+-static int hsu_debugfs_init(struct hsu_port *hsu)
+-{
+- int i;
+- char name[32];
+-
+- hsu->debugfs = debugfs_create_dir("hsu", NULL);
+- if (!hsu->debugfs)
+- return -ENOMEM;
+-
+- for (i = 0; i < 3; i++) {
+- snprintf(name, sizeof(name), "port_%d_regs", i);
+- debugfs_create_file(name, S_IFREG | S_IRUGO,
+- hsu->debugfs, (void *)(&hsu->port[i]), &port_regs_ops);
+- }
+-
+- for (i = 0; i < 6; i++) {
+- snprintf(name, sizeof(name), "dma_chan_%d_regs", i);
+- debugfs_create_file(name, S_IFREG | S_IRUGO,
+- hsu->debugfs, (void *)&hsu->chans[i], &dma_regs_ops);
+- }
+-
+- return 0;
+-}
+-
+-static void hsu_debugfs_remove(struct hsu_port *hsu)
+-{
+- if (hsu->debugfs)
+- debugfs_remove_recursive(hsu->debugfs);
+-}
+-
+-#else
+-static inline int hsu_debugfs_init(struct hsu_port *hsu)
+-{
+- return 0;
+-}
+-
+-static inline void hsu_debugfs_remove(struct hsu_port *hsu)
+-{
+-}
+-#endif /* CONFIG_DEBUG_FS */
+-
+-static void serial_hsu_enable_ms(struct uart_port *port)
+-{
+- struct uart_hsu_port *up =
+- container_of(port, struct uart_hsu_port, port);
+-
+- up->ier |= UART_IER_MSI;
+- serial_out(up, UART_IER, up->ier);
+-}
+-
+-void hsu_dma_tx(struct uart_hsu_port *up)
+-{
+- struct circ_buf *xmit = &up->port.state->xmit;
+- struct hsu_dma_buffer *dbuf = &up->txbuf;
+- int count;
+-
+- /* test_and_set_bit may be better, but anyway it's in lock protected mode */
+- if (up->dma_tx_on)
+- return;
+-
+- /* Update the circ buf info */
+- xmit->tail += dbuf->ofs;
+- xmit->tail &= UART_XMIT_SIZE - 1;
+-
+- up->port.icount.tx += dbuf->ofs;
+- dbuf->ofs = 0;
+-
+- /* Disable the channel */
+- chan_writel(up->txc, HSU_CH_CR, 0x0);
+-
+- if (!uart_circ_empty(xmit) && !uart_tx_stopped(&up->port)) {
+- dma_sync_single_for_device(up->port.dev,
+- dbuf->dma_addr,
+- dbuf->dma_size,
+- DMA_TO_DEVICE);
+-
+- count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+- dbuf->ofs = count;
+-
+- /* Reprogram the channel */
+- chan_writel(up->txc, HSU_CH_D0SAR, dbuf->dma_addr + xmit->tail);
+- chan_writel(up->txc, HSU_CH_D0TSR, count);
+-
+- /* Reenable the channel */
+- chan_writel(up->txc, HSU_CH_DCR, 0x1
+- | (0x1 << 8)
+- | (0x1 << 16)
+- | (0x1 << 24));
+- up->dma_tx_on = 1;
+- chan_writel(up->txc, HSU_CH_CR, 0x1);
+- }
+-
+- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+- uart_write_wakeup(&up->port);
+-}
+-
+-/* The buffer is already cache coherent */
+-void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, struct hsu_dma_buffer *dbuf)
+-{
+- dbuf->ofs = 0;
+-
+- chan_writel(rxc, HSU_CH_BSR, 32);
+- chan_writel(rxc, HSU_CH_MOTSR, 4);
+-
+- chan_writel(rxc, HSU_CH_D0SAR, dbuf->dma_addr);
+- chan_writel(rxc, HSU_CH_D0TSR, dbuf->dma_size);
+- chan_writel(rxc, HSU_CH_DCR, 0x1 | (0x1 << 8)
+- | (0x1 << 16)
+- | (0x1 << 24) /* timeout bit, see HSU Errata 1 */
+- );
+- chan_writel(rxc, HSU_CH_CR, 0x3);
+-}
+-
+-/* Protected by spin_lock_irqsave(port->lock) */
+-static void serial_hsu_start_tx(struct uart_port *port)
+-{
+- struct uart_hsu_port *up =
+- container_of(port, struct uart_hsu_port, port);
+-
+- if (up->use_dma) {
+- hsu_dma_tx(up);
+- } else if (!(up->ier & UART_IER_THRI)) {
+- up->ier |= UART_IER_THRI;
+- serial_out(up, UART_IER, up->ier);
+- }
+-}
+-
+-static void serial_hsu_stop_tx(struct uart_port *port)
+-{
+- struct uart_hsu_port *up =
+- container_of(port, struct uart_hsu_port, port);
+- struct hsu_dma_chan *txc = up->txc;
+-
+- if (up->use_dma)
+- chan_writel(txc, HSU_CH_CR, 0x0);
+- else if (up->ier & UART_IER_THRI) {
+- up->ier &= ~UART_IER_THRI;
+- serial_out(up, UART_IER, up->ier);
+- }
+-}
+-
+-/* This is always called in spinlock protected mode, so
+- * modify timeout timer is safe here */
+-void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts)
+-{
+- struct hsu_dma_buffer *dbuf = &up->rxbuf;
+- struct hsu_dma_chan *chan = up->rxc;
+- struct uart_port *port = &up->port;
+- struct tty_port *tport = &port->state->port;
+- int count;
+-
+- /*
+- * First need to know how many is already transferred,
+- * then check if its a timeout DMA irq, and return
+- * the trail bytes out, push them up and reenable the
+- * channel
+- */
+-
+- /* Timeout IRQ, need wait some time, see Errata 2 */
+- if (int_sts & 0xf00)
+- udelay(2);
+-
+- /* Stop the channel */
+- chan_writel(chan, HSU_CH_CR, 0x0);
+-
+- count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr;
+- if (!count) {
+- /* Restart the channel before we leave */
+- chan_writel(chan, HSU_CH_CR, 0x3);
+- return;
+- }
+-
+- dma_sync_single_for_cpu(port->dev, dbuf->dma_addr,
+- dbuf->dma_size, DMA_FROM_DEVICE);
+-
+- /*
+- * Head will only wrap around when we recycle
+- * the DMA buffer, and when that happens, we
+- * explicitly set tail to 0. So head will
+- * always be greater than tail.
+- */
+- tty_insert_flip_string(tport, dbuf->buf, count);
+- port->icount.rx += count;
+-
+- dma_sync_single_for_device(up->port.dev, dbuf->dma_addr,
+- dbuf->dma_size, DMA_FROM_DEVICE);
+-
+- /* Reprogram the channel */
+- chan_writel(chan, HSU_CH_D0SAR, dbuf->dma_addr);
+- chan_writel(chan, HSU_CH_D0TSR, dbuf->dma_size);
+- chan_writel(chan, HSU_CH_DCR, 0x1
+- | (0x1 << 8)
+- | (0x1 << 16)
+- | (0x1 << 24) /* timeout bit, see HSU Errata 1 */
+- );
+- tty_flip_buffer_push(tport);
+-
+- chan_writel(chan, HSU_CH_CR, 0x3);
+-
+-}
+-
+-static void serial_hsu_stop_rx(struct uart_port *port)
+-{
+- struct uart_hsu_port *up =
+- container_of(port, struct uart_hsu_port, port);
+- struct hsu_dma_chan *chan = up->rxc;
+-
+- if (up->use_dma)
+- chan_writel(chan, HSU_CH_CR, 0x2);
+- else {
+- up->ier &= ~UART_IER_RLSI;
+- up->port.read_status_mask &= ~UART_LSR_DR;
+- serial_out(up, UART_IER, up->ier);
+- }
+-}
+-
+-static inline void receive_chars(struct uart_hsu_port *up, int *status)
+-{
+- unsigned int ch, flag;
+- unsigned int max_count = 256;
+-
+- do {
+- ch = serial_in(up, UART_RX);
+- flag = TTY_NORMAL;
+- up->port.icount.rx++;
+-
+- if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
+- UART_LSR_FE | UART_LSR_OE))) {
+-
+- dev_warn(up->dev, "We really rush into ERR/BI case"
+- "status = 0x%02x", *status);
+- /* For statistics only */
+- if (*status & UART_LSR_BI) {
+- *status &= ~(UART_LSR_FE | UART_LSR_PE);
+- up->port.icount.brk++;
+- /*
+- * We do the SysRQ and SAK checking
+- * here because otherwise the break
+- * may get masked by ignore_status_mask
+- * or read_status_mask.
+- */
+- if (uart_handle_break(&up->port))
+- goto ignore_char;
+- } else if (*status & UART_LSR_PE)
+- up->port.icount.parity++;
+- else if (*status & UART_LSR_FE)
+- up->port.icount.frame++;
+- if (*status & UART_LSR_OE)
+- up->port.icount.overrun++;
+-
+- /* Mask off conditions which should be ignored. */
+- *status &= up->port.read_status_mask;
+-
+-#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
+- if (up->port.cons &&
+- up->port.cons->index == up->port.line) {
+- /* Recover the break flag from console xmit */
+- *status |= up->lsr_break_flag;
+- up->lsr_break_flag = 0;
+- }
+-#endif
+- if (*status & UART_LSR_BI) {
+- flag = TTY_BREAK;
+- } else if (*status & UART_LSR_PE)
+- flag = TTY_PARITY;
+- else if (*status & UART_LSR_FE)
+- flag = TTY_FRAME;
+- }
+-
+- if (uart_handle_sysrq_char(&up->port, ch))
+- goto ignore_char;
+-
+- uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
+- ignore_char:
+- *status = serial_in(up, UART_LSR);
+- } while ((*status & UART_LSR_DR) && max_count--);
+- tty_flip_buffer_push(&up->port.state->port);
+-}
+-
+-static void transmit_chars(struct uart_hsu_port *up)
+-{
+- struct circ_buf *xmit = &up->port.state->xmit;
+- int count;
+-
+- if (up->port.x_char) {
+- serial_out(up, UART_TX, up->port.x_char);
+- up->port.icount.tx++;
+- up->port.x_char = 0;
+- return;
+- }
+- if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+- serial_hsu_stop_tx(&up->port);
+- return;
+- }
+-
+- /* The IRQ is for TX FIFO half-empty */
+- count = up->port.fifosize / 2;
+-
+- do {
+- serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+-
+- up->port.icount.tx++;
+- if (uart_circ_empty(xmit))
+- break;
+- } while (--count > 0);
+-
+- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+- uart_write_wakeup(&up->port);
+-
+- if (uart_circ_empty(xmit))
+- serial_hsu_stop_tx(&up->port);
+-}
+-
+-static inline void check_modem_status(struct uart_hsu_port *up)
+-{
+- int status;
+-
+- status = serial_in(up, UART_MSR);
+-
+- if ((status & UART_MSR_ANY_DELTA) == 0)
+- return;
+-
+- if (status & UART_MSR_TERI)
+- up->port.icount.rng++;
+- if (status & UART_MSR_DDSR)
+- up->port.icount.dsr++;
+- /* We may only get DDCD when HW init and reset */
+- if (status & UART_MSR_DDCD)
+- uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
+- /* Will start/stop_tx accordingly */
+- if (status & UART_MSR_DCTS)
+- uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
+-
+- wake_up_interruptible(&up->port.state->port.delta_msr_wait);
+-}
+-
+-/*
+- * This handles the interrupt from one port.
+- */
+-static irqreturn_t port_irq(int irq, void *dev_id)
+-{
+- struct uart_hsu_port *up = dev_id;
+- unsigned int iir, lsr;
+- unsigned long flags;
+-
+- if (unlikely(!up->running))
+- return IRQ_NONE;
+-
+- spin_lock_irqsave(&up->port.lock, flags);
+- if (up->use_dma) {
+- lsr = serial_in(up, UART_LSR);
+- if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE |
+- UART_LSR_FE | UART_LSR_OE)))
+- dev_warn(up->dev,
+- "Got lsr irq while using DMA, lsr = 0x%2x\n",
+- lsr);
+- check_modem_status(up);
+- spin_unlock_irqrestore(&up->port.lock, flags);
+- return IRQ_HANDLED;
+- }
+-
+- iir = serial_in(up, UART_IIR);
+- if (iir & UART_IIR_NO_INT) {
+- spin_unlock_irqrestore(&up->port.lock, flags);
+- return IRQ_NONE;
+- }
+-
+- lsr = serial_in(up, UART_LSR);
+- if (lsr & UART_LSR_DR)
+- receive_chars(up, &lsr);
+- check_modem_status(up);
+-
+- /* lsr will be renewed during the receive_chars */
+- if (lsr & UART_LSR_THRE)
+- transmit_chars(up);
+-
+- spin_unlock_irqrestore(&up->port.lock, flags);
+- return IRQ_HANDLED;
+-}
+-
+-static inline void dma_chan_irq(struct hsu_dma_chan *chan)
+-{
+- struct uart_hsu_port *up = chan->uport;
+- unsigned long flags;
+- u32 int_sts;
+-
+- spin_lock_irqsave(&up->port.lock, flags);
+-
+- if (!up->use_dma || !up->running)
+- goto exit;
+-
+- /*
+- * No matter what situation, need read clear the IRQ status
+- * There is a bug, see Errata 5, HSD 2900918
+- */
+- int_sts = chan_readl(chan, HSU_CH_SR);
+-
+- /* Rx channel */
+- if (chan->dirt == DMA_FROM_DEVICE)
+- hsu_dma_rx(up, int_sts);
+-
+- /* Tx channel */
+- if (chan->dirt == DMA_TO_DEVICE) {
+- chan_writel(chan, HSU_CH_CR, 0x0);
+- up->dma_tx_on = 0;
+- hsu_dma_tx(up);
+- }
+-
+-exit:
+- spin_unlock_irqrestore(&up->port.lock, flags);
+- return;
+-}
+-
+-static irqreturn_t dma_irq(int irq, void *dev_id)
+-{
+- struct hsu_port *hsu = dev_id;
+- u32 int_sts, i;
+-
+- int_sts = mfd_readl(hsu, HSU_GBL_DMAISR);
+-
+- /* Currently we only have 6 channels may be used */
+- for (i = 0; i < 6; i++) {
+- if (int_sts & 0x1)
+- dma_chan_irq(&hsu->chans[i]);
+- int_sts >>= 1;
+- }
+-
+- return IRQ_HANDLED;
+-}
+-
+-static unsigned int serial_hsu_tx_empty(struct uart_port *port)
+-{
+- struct uart_hsu_port *up =
+- container_of(port, struct uart_hsu_port, port);
+- unsigned long flags;
+- unsigned int ret;
+-
+- spin_lock_irqsave(&up->port.lock, flags);
+- ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+- spin_unlock_irqrestore(&up->port.lock, flags);
+-
+- return ret;
+-}
+-
+-static unsigned int serial_hsu_get_mctrl(struct uart_port *port)
+-{
+- struct uart_hsu_port *up =
+- container_of(port, struct uart_hsu_port, port);
+- unsigned char status;
+- unsigned int ret;
+-
+- status = serial_in(up, UART_MSR);
+-
+- ret = 0;
+- if (status & UART_MSR_DCD)
+- ret |= TIOCM_CAR;
+- if (status & UART_MSR_RI)
+- ret |= TIOCM_RNG;
+- if (status & UART_MSR_DSR)
+- ret |= TIOCM_DSR;
+- if (status & UART_MSR_CTS)
+- ret |= TIOCM_CTS;
+- return ret;
+-}
+-
+-static void serial_hsu_set_mctrl(struct uart_port *port, unsigned int mctrl)
+-{
+- struct uart_hsu_port *up =
+- container_of(port, struct uart_hsu_port, port);
+- unsigned char mcr = 0;
+-
+- if (mctrl & TIOCM_RTS)
+- mcr |= UART_MCR_RTS;
+- if (mctrl & TIOCM_DTR)
+- mcr |= UART_MCR_DTR;
+- if (mctrl & TIOCM_OUT1)
+- mcr |= UART_MCR_OUT1;
+- if (mctrl & TIOCM_OUT2)
+- mcr |= UART_MCR_OUT2;
+- if (mctrl & TIOCM_LOOP)
+- mcr |= UART_MCR_LOOP;
+-
+- mcr |= up->mcr;
+-
+- serial_out(up, UART_MCR, mcr);
+-}
+-
+-static void serial_hsu_break_ctl(struct uart_port *port, int break_state)
+-{
+- struct uart_hsu_port *up =
+- container_of(port, struct uart_hsu_port, port);
+- unsigned long flags;
+-
+- spin_lock_irqsave(&up->port.lock, flags);
+- if (break_state == -1)
+- up->lcr |= UART_LCR_SBC;
+- else
+- up->lcr &= ~UART_LCR_SBC;
+- serial_out(up, UART_LCR, up->lcr);
+- spin_unlock_irqrestore(&up->port.lock, flags);
+-}
+-
+-/*
+- * What special to do:
+- * 1. chose the 64B fifo mode
+- * 2. start dma or pio depends on configuration
+- * 3. we only allocate dma memory when needed
+- */
+-static int serial_hsu_startup(struct uart_port *port)
+-{
+- struct uart_hsu_port *up =
+- container_of(port, struct uart_hsu_port, port);
+- unsigned long flags;
+-
+- pm_runtime_get_sync(up->dev);
+-
+- /*
+- * Clear the FIFO buffers and disable them.
+- * (they will be reenabled in set_termios())
+- */
+- serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+- serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+- UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+- serial_out(up, UART_FCR, 0);
+-
+- /* Clear the interrupt registers. */
+- (void) serial_in(up, UART_LSR);
+- (void) serial_in(up, UART_RX);
+- (void) serial_in(up, UART_IIR);
+- (void) serial_in(up, UART_MSR);
+-
+- /* Now, initialize the UART, default is 8n1 */
+- serial_out(up, UART_LCR, UART_LCR_WLEN8);
+-
+- spin_lock_irqsave(&up->port.lock, flags);
+-
+- up->port.mctrl |= TIOCM_OUT2;
+- serial_hsu_set_mctrl(&up->port, up->port.mctrl);
+-
+- /*
+- * Finally, enable interrupts. Note: Modem status interrupts
+- * are set via set_termios(), which will be occurring imminently
+- * anyway, so we don't enable them here.
+- */
+- if (!up->use_dma)
+- up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE;
+- else
+- up->ier = 0;
+- serial_out(up, UART_IER, up->ier);
+-
+- spin_unlock_irqrestore(&up->port.lock, flags);
+-
+- /* DMA init */
+- if (up->use_dma) {
+- struct hsu_dma_buffer *dbuf;
+- struct circ_buf *xmit = &port->state->xmit;
+-
+- up->dma_tx_on = 0;
+-
+- /* First allocate the RX buffer */
+- dbuf = &up->rxbuf;
+- dbuf->buf = kzalloc(HSU_DMA_BUF_SIZE, GFP_KERNEL);
+- if (!dbuf->buf) {
+- up->use_dma = 0;
+- goto exit;
+- }
+- dbuf->dma_addr = dma_map_single(port->dev,
+- dbuf->buf,
+- HSU_DMA_BUF_SIZE,
+- DMA_FROM_DEVICE);
+- dbuf->dma_size = HSU_DMA_BUF_SIZE;
+-
+- /* Start the RX channel right now */
+- hsu_dma_start_rx_chan(up->rxc, dbuf);
+-
+- /* Next init the TX DMA */
+- dbuf = &up->txbuf;
+- dbuf->buf = xmit->buf;
+- dbuf->dma_addr = dma_map_single(port->dev,
+- dbuf->buf,
+- UART_XMIT_SIZE,
+- DMA_TO_DEVICE);
+- dbuf->dma_size = UART_XMIT_SIZE;
+-
+- /* This should not be changed all around */
+- chan_writel(up->txc, HSU_CH_BSR, 32);
+- chan_writel(up->txc, HSU_CH_MOTSR, 4);
+- dbuf->ofs = 0;
+- }
+-
+-exit:
+- /* And clear the interrupt registers again for luck. */
+- (void) serial_in(up, UART_LSR);
+- (void) serial_in(up, UART_RX);
+- (void) serial_in(up, UART_IIR);
+- (void) serial_in(up, UART_MSR);
+-
+- up->running = 1;
+- return 0;
+-}
+-
+-static void serial_hsu_shutdown(struct uart_port *port)
+-{
+- struct uart_hsu_port *up =
+- container_of(port, struct uart_hsu_port, port);
+- unsigned long flags;
+-
+- /* Disable interrupts from this port */
+- up->ier = 0;
+- serial_out(up, UART_IER, 0);
+- up->running = 0;
+-
+- spin_lock_irqsave(&up->port.lock, flags);
+- up->port.mctrl &= ~TIOCM_OUT2;
+- serial_hsu_set_mctrl(&up->port, up->port.mctrl);
+- spin_unlock_irqrestore(&up->port.lock, flags);
+-
+- /* Disable break condition and FIFOs */
+- serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
+- serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+- UART_FCR_CLEAR_RCVR |
+- UART_FCR_CLEAR_XMIT);
+- serial_out(up, UART_FCR, 0);
+-
+- pm_runtime_put(up->dev);
+-}
+-
+-static void
+-serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios,
+- struct ktermios *old)
+-{
+- struct uart_hsu_port *up =
+- container_of(port, struct uart_hsu_port, port);
+- unsigned char cval, fcr = 0;
+- unsigned long flags;
+- unsigned int baud, quot;
+- u32 ps, mul;
+-
+- switch (termios->c_cflag & CSIZE) {
+- case CS5:
+- cval = UART_LCR_WLEN5;
+- break;
+- case CS6:
+- cval = UART_LCR_WLEN6;
+- break;
+- case CS7:
+- cval = UART_LCR_WLEN7;
+- break;
+- default:
+- case CS8:
+- cval = UART_LCR_WLEN8;
+- break;
+- }
+-
+- /* CMSPAR isn't supported by this driver */
+- termios->c_cflag &= ~CMSPAR;
+-
+- if (termios->c_cflag & CSTOPB)
+- cval |= UART_LCR_STOP;
+- if (termios->c_cflag & PARENB)
+- cval |= UART_LCR_PARITY;
+- if (!(termios->c_cflag & PARODD))
+- cval |= UART_LCR_EPAR;
+-
+- /*
+- * The base clk is 50Mhz, and the baud rate come from:
+- * baud = 50M * MUL / (DIV * PS * DLAB)
+- *
+- * For those basic low baud rate we can get the direct
+- * scalar from 2746800, like 115200 = 2746800/24. For those
+- * higher baud rate, we handle them case by case, mainly by
+- * adjusting the MUL/PS registers, and DIV register is kept
+- * as default value 0x3d09 to make things simple
+- */
+- baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
+-
+- quot = 1;
+- ps = 0x10;
+- mul = 0x3600;
+- switch (baud) {
+- case 3500000:
+- mul = 0x3345;
+- ps = 0xC;
+- break;
+- case 1843200:
+- mul = 0x2400;
+- break;
+- case 3000000:
+- case 2500000:
+- case 2000000:
+- case 1500000:
+- case 1000000:
+- case 500000:
+- /* mul/ps/quot = 0x9C4/0x10/0x1 will make a 500000 bps */
+- mul = baud / 500000 * 0x9C4;
+- break;
+- default:
+- /* Use uart_get_divisor to get quot for other baud rates */
+- quot = 0;
+- }
+-
+- if (!quot)
+- quot = uart_get_divisor(port, baud);
+-
+- if ((up->port.uartclk / quot) < (2400 * 16))
+- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_1B;
+- else if ((up->port.uartclk / quot) < (230400 * 16))
+- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_16B;
+- else
+- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_32B;
+-
+- fcr |= UART_FCR_HSU_64B_FIFO;
+-
+- /*
+- * Ok, we're now changing the port state. Do it with
+- * interrupts disabled.
+- */
+- spin_lock_irqsave(&up->port.lock, flags);
+-
+- /* Update the per-port timeout */
+- uart_update_timeout(port, termios->c_cflag, baud);
+-
+- up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+- if (termios->c_iflag & INPCK)
+- up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+- if (termios->c_iflag & (BRKINT | PARMRK))
+- up->port.read_status_mask |= UART_LSR_BI;
+-
+- /* Characters to ignore */
+- up->port.ignore_status_mask = 0;
+- if (termios->c_iflag & IGNPAR)
+- up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+- if (termios->c_iflag & IGNBRK) {
+- up->port.ignore_status_mask |= UART_LSR_BI;
+- /*
+- * If we're ignoring parity and break indicators,
+- * ignore overruns too (for real raw support).
+- */
+- if (termios->c_iflag & IGNPAR)
+- up->port.ignore_status_mask |= UART_LSR_OE;
+- }
+-
+- /* Ignore all characters if CREAD is not set */
+- if ((termios->c_cflag & CREAD) == 0)
+- up->port.ignore_status_mask |= UART_LSR_DR;
+-
+- /*
+- * CTS flow control flag and modem status interrupts, disable
+- * MSI by default
+- */
+- up->ier &= ~UART_IER_MSI;
+- if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+- up->ier |= UART_IER_MSI;
+-
+- serial_out(up, UART_IER, up->ier);
+-
+- if (termios->c_cflag & CRTSCTS)
+- up->mcr |= UART_MCR_AFE | UART_MCR_RTS;
+- else
+- up->mcr &= ~UART_MCR_AFE;
+-
+- serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
+- serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */
+- serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */
+- serial_out(up, UART_LCR, cval); /* reset DLAB */
+- serial_out(up, UART_MUL, mul); /* set MUL */
+- serial_out(up, UART_PS, ps); /* set PS */
+- up->lcr = cval; /* Save LCR */
+- serial_hsu_set_mctrl(&up->port, up->port.mctrl);
+- serial_out(up, UART_FCR, fcr);
+- spin_unlock_irqrestore(&up->port.lock, flags);
+-}
+-
+-static void
+-serial_hsu_pm(struct uart_port *port, unsigned int state,
+- unsigned int oldstate)
+-{
+-}
+-
+-static void serial_hsu_release_port(struct uart_port *port)
+-{
+-}
+-
+-static int serial_hsu_request_port(struct uart_port *port)
+-{
+- return 0;
+-}
+-
+-static void serial_hsu_config_port(struct uart_port *port, int flags)
+-{
+- struct uart_hsu_port *up =
+- container_of(port, struct uart_hsu_port, port);
+- up->port.type = PORT_MFD;
+-}
+-
+-static int
+-serial_hsu_verify_port(struct uart_port *port, struct serial_struct *ser)
+-{
+- /* We don't want the core code to modify any port params */
+- return -EINVAL;
+-}
+-
+-static const char *
+-serial_hsu_type(struct uart_port *port)
+-{
+- struct uart_hsu_port *up =
+- container_of(port, struct uart_hsu_port, port);
+- return up->name;
+-}
+-
+-/* Mainly for uart console use */
+-static struct uart_hsu_port *serial_hsu_ports[3];
+-static struct uart_driver serial_hsu_reg;
+-
+-#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
+-
+-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+-
+-/* Wait for transmitter & holding register to empty */
+-static inline void wait_for_xmitr(struct uart_hsu_port *up)
+-{
+- unsigned int status, tmout = 1000;
+-
+- /* Wait up to 1ms for the character to be sent. */
+- do {
+- status = serial_in(up, UART_LSR);
+-
+- if (status & UART_LSR_BI)
+- up->lsr_break_flag = UART_LSR_BI;
+-
+- if (--tmout == 0)
+- break;
+- udelay(1);
+- } while (!(status & BOTH_EMPTY));
+-
+- /* Wait up to 1s for flow control if necessary */
+- if (up->port.flags & UPF_CONS_FLOW) {
+- tmout = 1000000;
+- while (--tmout &&
+- ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
+- udelay(1);
+- }
+-}
+-
+-static void serial_hsu_console_putchar(struct uart_port *port, int ch)
+-{
+- struct uart_hsu_port *up =
+- container_of(port, struct uart_hsu_port, port);
+-
+- wait_for_xmitr(up);
+- serial_out(up, UART_TX, ch);
+-}
+-
+-/*
+- * Print a string to the serial port trying not to disturb
+- * any possible real use of the port...
+- *
+- * The console_lock must be held when we get here.
+- */
+-static void
+-serial_hsu_console_write(struct console *co, const char *s, unsigned int count)
+-{
+- struct uart_hsu_port *up = serial_hsu_ports[co->index];
+- unsigned long flags;
+- unsigned int ier;
+- int locked = 1;
+-
+- touch_nmi_watchdog();
+-
+- local_irq_save(flags);
+- if (up->port.sysrq)
+- locked = 0;
+- else if (oops_in_progress) {
+- locked = spin_trylock(&up->port.lock);
+- } else
+- spin_lock(&up->port.lock);
+-
+- /* First save the IER then disable the interrupts */
+- ier = serial_in(up, UART_IER);
+- serial_out(up, UART_IER, 0);
+-
+- uart_console_write(&up->port, s, count, serial_hsu_console_putchar);
+-
+- /*
+- * Finally, wait for transmitter to become empty
+- * and restore the IER
+- */
+- wait_for_xmitr(up);
+- serial_out(up, UART_IER, ier);
+-
+- if (locked)
+- spin_unlock(&up->port.lock);
+- local_irq_restore(flags);
+-}
+-
+-static struct console serial_hsu_console;
+-
+-static int __init
+-serial_hsu_console_setup(struct console *co, char *options)
+-{
+- struct uart_hsu_port *up;
+- int baud = 115200;
+- int bits = 8;
+- int parity = 'n';
+- int flow = 'n';
+-
+- if (co->index == -1 || co->index >= serial_hsu_reg.nr)
+- co->index = 0;
+- up = serial_hsu_ports[co->index];
+- if (!up)
+- return -ENODEV;
+-
+- if (options)
+- uart_parse_options(options, &baud, &parity, &bits, &flow);
+-
+- return uart_set_options(&up->port, co, baud, parity, bits, flow);
+-}
+-
+-static struct console serial_hsu_console = {
+- .name = "ttyMFD",
+- .write = serial_hsu_console_write,
+- .device = uart_console_device,
+- .setup = serial_hsu_console_setup,
+- .flags = CON_PRINTBUFFER,
+- .index = -1,
+- .data = &serial_hsu_reg,
+-};
+-
+-#define SERIAL_HSU_CONSOLE (&serial_hsu_console)
+-#else
+-#define SERIAL_HSU_CONSOLE NULL
+-#endif
+-
+-struct uart_ops serial_hsu_pops = {
+- .tx_empty = serial_hsu_tx_empty,
+- .set_mctrl = serial_hsu_set_mctrl,
+- .get_mctrl = serial_hsu_get_mctrl,
+- .stop_tx = serial_hsu_stop_tx,
+- .start_tx = serial_hsu_start_tx,
+- .stop_rx = serial_hsu_stop_rx,
+- .enable_ms = serial_hsu_enable_ms,
+- .break_ctl = serial_hsu_break_ctl,
+- .startup = serial_hsu_startup,
+- .shutdown = serial_hsu_shutdown,
+- .set_termios = serial_hsu_set_termios,
+- .pm = serial_hsu_pm,
+- .type = serial_hsu_type,
+- .release_port = serial_hsu_release_port,
+- .request_port = serial_hsu_request_port,
+- .config_port = serial_hsu_config_port,
+- .verify_port = serial_hsu_verify_port,
+-};
+-
+-static struct uart_driver serial_hsu_reg = {
+- .owner = THIS_MODULE,
+- .driver_name = "MFD serial",
+- .dev_name = "ttyMFD",
+- .major = TTY_MAJOR,
+- .minor = 128,
+- .nr = 3,
+- .cons = SERIAL_HSU_CONSOLE,
+-};
+-
+-#ifdef CONFIG_PM
+-static int serial_hsu_suspend(struct pci_dev *pdev, pm_message_t state)
+-{
+- void *priv = pci_get_drvdata(pdev);
+- struct uart_hsu_port *up;
+-
+- /* Make sure this is not the internal dma controller */
+- if (priv && (pdev->device != 0x081E)) {
+- up = priv;
+- uart_suspend_port(&serial_hsu_reg, &up->port);
+- }
+-
+- pci_save_state(pdev);
+- pci_set_power_state(pdev, pci_choose_state(pdev, state));
+- return 0;
+-}
+-
+-static int serial_hsu_resume(struct pci_dev *pdev)
+-{
+- void *priv = pci_get_drvdata(pdev);
+- struct uart_hsu_port *up;
+- int ret;
+-
+- pci_set_power_state(pdev, PCI_D0);
+- pci_restore_state(pdev);
+-
+- ret = pci_enable_device(pdev);
+- if (ret)
+- dev_warn(&pdev->dev,
+- "HSU: can't re-enable device, try to continue\n");
+-
+- if (priv && (pdev->device != 0x081E)) {
+- up = priv;
+- uart_resume_port(&serial_hsu_reg, &up->port);
+- }
+- return 0;
+-}
+-#else
+-#define serial_hsu_suspend NULL
+-#define serial_hsu_resume NULL
+-#endif
+-
+-#ifdef CONFIG_PM_RUNTIME
+-static int serial_hsu_runtime_idle(struct device *dev)
+-{
+- int err;
+-
+- err = pm_schedule_suspend(dev, 500);
+- if (err)
+- return -EBUSY;
+-
+- return 0;
+-}
+-
+-static int serial_hsu_runtime_suspend(struct device *dev)
+-{
+- return 0;
+-}
+-
+-static int serial_hsu_runtime_resume(struct device *dev)
+-{
+- return 0;
+-}
+-#else
+-#define serial_hsu_runtime_idle NULL
+-#define serial_hsu_runtime_suspend NULL
+-#define serial_hsu_runtime_resume NULL
+-#endif
+-
+-static const struct dev_pm_ops serial_hsu_pm_ops = {
+- .runtime_suspend = serial_hsu_runtime_suspend,
+- .runtime_resume = serial_hsu_runtime_resume,
+- .runtime_idle = serial_hsu_runtime_idle,
+-};
+-
+-/* temp global pointer before we settle down on using one or four PCI dev */
+-static struct hsu_port *phsu;
+-
+-static int serial_hsu_probe(struct pci_dev *pdev,
+- const struct pci_device_id *ent)
+-{
+- struct uart_hsu_port *uport;
+- int index, ret;
+-
+- printk(KERN_INFO "HSU: found PCI Serial controller(ID: %04x:%04x)\n",
+- pdev->vendor, pdev->device);
+-
+- switch (pdev->device) {
+- case 0x081B:
+- index = 0;
+- break;
+- case 0x081C:
+- index = 1;
+- break;
+- case 0x081D:
+- index = 2;
+- break;
+- case 0x081E:
+- /* internal DMA controller */
+- index = 3;
+- break;
+- default:
+- dev_err(&pdev->dev, "HSU: out of index!");
+- return -ENODEV;
+- }
+-
+- ret = pci_enable_device(pdev);
+- if (ret)
+- return ret;
+-
+- if (index == 3) {
+- /* DMA controller */
+- ret = request_irq(pdev->irq, dma_irq, 0, "hsu_dma", phsu);
+- if (ret) {
+- dev_err(&pdev->dev, "can not get IRQ\n");
+- goto err_disable;
+- }
+- pci_set_drvdata(pdev, phsu);
+- } else {
+- /* UART port 0~2 */
+- uport = &phsu->port[index];
+- uport->port.irq = pdev->irq;
+- uport->port.dev = &pdev->dev;
+- uport->dev = &pdev->dev;
+-
+- ret = request_irq(pdev->irq, port_irq, 0, uport->name, uport);
+- if (ret) {
+- dev_err(&pdev->dev, "can not get IRQ\n");
+- goto err_disable;
+- }
+- uart_add_one_port(&serial_hsu_reg, &uport->port);
+-
+- pci_set_drvdata(pdev, uport);
+- }
+-
+- pm_runtime_put_noidle(&pdev->dev);
+- pm_runtime_allow(&pdev->dev);
+-
+- return 0;
+-
+-err_disable:
+- pci_disable_device(pdev);
+- return ret;
+-}
+-
+-static void hsu_global_init(void)
+-{
+- struct hsu_port *hsu;
+- struct uart_hsu_port *uport;
+- struct hsu_dma_chan *dchan;
+- int i, ret;
+-
+- hsu = kzalloc(sizeof(struct hsu_port), GFP_KERNEL);
+- if (!hsu)
+- return;
+-
+- /* Get basic io resource and map it */
+- hsu->paddr = 0xffa28000;
+- hsu->iolen = 0x1000;
+-
+- if (!(request_mem_region(hsu->paddr, hsu->iolen, "HSU global")))
+- pr_warning("HSU: error in request mem region\n");
+-
+- hsu->reg = ioremap_nocache((unsigned long)hsu->paddr, hsu->iolen);
+- if (!hsu->reg) {
+- pr_err("HSU: error in ioremap\n");
+- ret = -ENOMEM;
+- goto err_free_region;
+- }
+-
+- /* Initialise the 3 UART ports */
+- uport = hsu->port;
+- for (i = 0; i < 3; i++) {
+- uport->port.type = PORT_MFD;
+- uport->port.iotype = UPIO_MEM;
+- uport->port.mapbase = (resource_size_t)hsu->paddr
+- + HSU_PORT_REG_OFFSET
+- + i * HSU_PORT_REG_LENGTH;
+- uport->port.membase = hsu->reg + HSU_PORT_REG_OFFSET
+- + i * HSU_PORT_REG_LENGTH;
+-
+- sprintf(uport->name, "hsu_port%d", i);
+- uport->port.fifosize = 64;
+- uport->port.ops = &serial_hsu_pops;
+- uport->port.line = i;
+- uport->port.flags = UPF_IOREMAP;
+- /* set the scalable maxim support rate to 2746800 bps */
+- uport->port.uartclk = 115200 * 24 * 16;
+-
+- uport->running = 0;
+- uport->txc = &hsu->chans[i * 2];
+- uport->rxc = &hsu->chans[i * 2 + 1];
+-
+- serial_hsu_ports[i] = uport;
+- uport->index = i;
+-
+- if (hsu_dma_enable & (1<<i))
+- uport->use_dma = 1;
+- else
+- uport->use_dma = 0;
+-
+- uport++;
+- }
+-
+- /* Initialise 6 dma channels */
+- dchan = hsu->chans;
+- for (i = 0; i < 6; i++) {
+- dchan->id = i;
+- dchan->dirt = (i & 0x1) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+- dchan->uport = &hsu->port[i/2];
+- dchan->reg = hsu->reg + HSU_DMA_CHANS_REG_OFFSET +
+- i * HSU_DMA_CHANS_REG_LENGTH;
+-
+- dchan++;
+- }
+-
+- phsu = hsu;
+- hsu_debugfs_init(hsu);
+- return;
+-
+-err_free_region:
+- release_mem_region(hsu->paddr, hsu->iolen);
+- kfree(hsu);
+- return;
+-}
+-
+-static void serial_hsu_remove(struct pci_dev *pdev)
+-{
+- void *priv = pci_get_drvdata(pdev);
+- struct uart_hsu_port *up;
+-
+- if (!priv)
+- return;
+-
+- pm_runtime_forbid(&pdev->dev);
+- pm_runtime_get_noresume(&pdev->dev);
+-
+- /* For port 0/1/2, priv is the address of uart_hsu_port */
+- if (pdev->device != 0x081E) {
+- up = priv;
+- uart_remove_one_port(&serial_hsu_reg, &up->port);
+- }
+-
+- pci_set_drvdata(pdev, NULL);
+- free_irq(pdev->irq, priv);
+- pci_disable_device(pdev);
+-}
+-
+-/* First 3 are UART ports, and the 4th is the DMA */
+-static const struct pci_device_id pci_ids[] = {
+- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081B) },
+- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081C) },
+- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081D) },
+- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081E) },
+- {},
+-};
+-
+-static struct pci_driver hsu_pci_driver = {
+- .name = "HSU serial",
+- .id_table = pci_ids,
+- .probe = serial_hsu_probe,
+- .remove = serial_hsu_remove,
+- .suspend = serial_hsu_suspend,
+- .resume = serial_hsu_resume,
+- .driver = {
+- .pm = &serial_hsu_pm_ops,
+- },
+-};
+-
+-static int __init hsu_pci_init(void)
+-{
+- int ret;
+-
+- hsu_global_init();
+-
+- ret = uart_register_driver(&serial_hsu_reg);
+- if (ret)
+- return ret;
+-
+- return pci_register_driver(&hsu_pci_driver);
+-}
+-
+-static void __exit hsu_pci_exit(void)
+-{
+- pci_unregister_driver(&hsu_pci_driver);
+- uart_unregister_driver(&serial_hsu_reg);
+-
+- hsu_debugfs_remove(phsu);
+-
+- kfree(phsu);
+-}
+-
+-module_init(hsu_pci_init);
+-module_exit(hsu_pci_exit);
+-
+-MODULE_LICENSE("GPL v2");
+-MODULE_ALIAS("platform:medfield-hsu");
+diff --git a/drivers/tty/serial/mfd.h b/drivers/tty/serial/mfd.h
+new file mode 100644
+index 0000000..22cb3f3
+--- /dev/null
++++ b/drivers/tty/serial/mfd.h
+@@ -0,0 +1,252 @@
++#ifndef _MFD_H
++#define _MFD_H
++
++#include <linux/serial_core.h>
++#include <linux/serial_reg.h>
++#include <linux/serial_mfd.h>
++#include <linux/intel_mid_dma.h>
++#include <linux/intel_mid_pm.h>
++#include <linux/dma-direction.h>
++#include <asm/intel_mid_hsu.h>
++
++#define HSU_PORT_MAX 8
++#define HSU_DMA_BUF_SIZE 2048
++#define HSU_Q_MAX 4096
++#define HSU_CL_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
++#define HSU_DMA_BSR 32
++#define HSU_DMA_MOTSR 4
++#define HSU_PIO_RX_ERR 0x06
++#define HSU_PIO_RX_AVB 0x04
++#define HSU_PIO_RX_TMO 0x0C
++#define HSU_PIO_TX_REQ 0x02
++
++enum {
++ flag_console = 0,
++ flag_reopen,
++ flag_suspend,
++ flag_active,
++ flag_set_alt,
++ flag_tx_on,
++ flag_rx_on,
++ flag_rx_pending,
++ flag_startup,
++ flag_cmd_on,
++ flag_cmd_off,
++};
++
++enum {
++ qcmd_overflow = 0,
++ qcmd_get_msr,
++ qcmd_set_mcr,
++ qcmd_set_ier,
++ qcmd_start_rx,
++ qcmd_stop_rx,
++ qcmd_start_tx,
++ qcmd_stop_tx,
++ qcmd_cl,
++ qcmd_port_irq,
++ qcmd_dma_irq,
++ qcmd_enable_irq,
++ qcmd_cmd_off,
++ qcmd_max,
++};
++
++enum {
++ context_save,
++ context_load,
++};
++
++struct hsu_dma_buffer {
++ u8 *buf;
++ dma_addr_t dma_addr;
++ u32 dma_size;
++ u32 ofs;
++};
++
++struct hsu_dma_chan {
++ u32 id;
++ enum dma_data_direction dirt;
++ struct uart_hsu_port *uport;
++ void __iomem *reg;
++ u32 cr;
++ u32 dcr;
++ u32 sar;
++ u32 tsr;
++};
++
++struct dw_dma_priv {
++ struct intel_mid_dma_slave txs;
++ struct intel_mid_dma_slave rxs;
++
++ struct uart_hsu_port *up;
++
++ struct dma_chan *txchan;
++ struct dma_chan *rxchan;
++
++ /* phy address of the Data register */
++ dma_addr_t dma_addr;
++ struct pci_dev *dmac;
++};
++
++struct intel_dma_priv {
++ unsigned int tx_addr;
++ struct hsu_dma_chan *txc;
++ struct hsu_dma_chan *rxc;
++};
++
++struct hsu_dma_ops {
++ int (*init)(struct uart_hsu_port *up);
++ int (*exit)(struct uart_hsu_port *up);
++ int (*suspend)(struct uart_hsu_port *up);
++ int (*resume)(struct uart_hsu_port *up);
++ void (*start_tx)(struct uart_hsu_port *up);
++ void (*stop_tx)(struct uart_hsu_port *up);
++ void (*start_rx)(struct uart_hsu_port *up);
++ void (*stop_rx)(struct uart_hsu_port *up);
++ /* op will be context_save or context_load */
++ void (*context_op)(struct uart_hsu_port *up, int op);
++};
++
++struct uart_hsu_port {
++ struct uart_port port;
++ struct mutex q_mutex;
++ int q_start;
++ struct workqueue_struct *workqueue;
++ struct work_struct work;
++ struct tasklet_struct tasklet;
++ struct circ_buf qcirc;
++ int qbuf[HSU_Q_MAX];
++ struct circ_buf cl_circ;
++ spinlock_t cl_lock;
++
++ /* Intel HSU or Designware */
++ int hw_type;
++
++ unsigned char msr;
++ unsigned char ier;
++ unsigned char lcr;
++ unsigned char mcr;
++ unsigned char lsr;
++ unsigned char dll;
++ unsigned char dlm;
++ unsigned char fcr;
++ /* intel_hsu's clk param */
++ unsigned int mul;
++ unsigned int div;
++ unsigned int ps;
++
++ /* Buffered value due to runtime PM and sharing IRQ */
++ unsigned char iir;
++
++ /* intel_dw's clk param */
++ unsigned int m;
++ unsigned int n;
++
++ unsigned int lsr_break_flag;
++ char name[24];
++ int index;
++ struct device *dev;
++
++ unsigned int tx_addr;
++ struct hsu_dma_chan *txc;
++ struct hsu_dma_chan *rxc;
++ struct hsu_dma_buffer txbuf;
++ struct hsu_dma_buffer rxbuf;
++
++ unsigned char rxc_chcr_save;
++
++ unsigned long flags;
++
++ unsigned int qcmd_num;
++ unsigned int qcmd_done;
++ unsigned int port_irq_num;
++ unsigned int port_irq_cmddone;
++ unsigned int port_irq_no_alt;
++ unsigned int port_irq_no_startup;
++ unsigned int port_irq_pio_no_irq_pend;
++ unsigned int port_irq_pio_tx_req;
++ unsigned int port_irq_pio_rx_avb;
++ unsigned int port_irq_pio_rx_err;
++ unsigned int port_irq_pio_rx_timeout;
++ unsigned int cts_status;
++ unsigned int dma_irq_num;
++ unsigned int dma_invalid_irq_num;
++ unsigned int dma_irq_cmddone;
++ unsigned int dma_tx_irq_cmddone;
++ unsigned int dma_rx_irq_cmddone;
++ unsigned int dma_rx_tmt_irq_cmddone;
++ unsigned int tasklet_done;
++ unsigned int workq_done;
++ unsigned int in_workq;
++ unsigned int in_tasklet;
++
++ unsigned int byte_delay;
++
++ int use_dma; /* flag for DMA/PIO */
++ unsigned int dma_irq;
++ unsigned int port_dma_sts;
++
++ void *dma_priv;
++ struct hsu_dma_ops *dma_ops;
++ struct pm_qos_request qos;
++ int dma_inited;
++};
++
++struct hsu_port {
++ int dma_irq;
++ int port_num;
++ int irq_port_and_dma;
++ struct hsu_port_cfg *configs[HSU_PORT_MAX];
++ void __iomem *reg;
++ struct uart_hsu_port port[HSU_PORT_MAX];
++ struct hsu_dma_chan chans[HSU_PORT_MAX * 2];
++ spinlock_t dma_lock;
++ struct dentry *debugfs;
++};
++
++#define chan_readl(chan, offset) readl(chan->reg + offset)
++#define chan_writel(chan, offset, val) writel(val, chan->reg + offset)
++
++#define mfd_readl(obj, offset) readl(obj->reg + offset)
++#define mfd_writel(obj, offset, val) writel(val, obj->reg + offset)
++
++static inline unsigned int serial_in(struct uart_hsu_port *up, int offset)
++{
++ unsigned int val;
++
++ if (offset > UART_MSR || up->hw_type == hsu_dw) {
++ offset <<= 2;
++ val = readl(up->port.membase + offset);
++ } else
++ val = (unsigned int)readb(up->port.membase + offset);
++
++ return val;
++}
++
++static inline void serial_out(struct uart_hsu_port *up, int offset, int value)
++{
++ if (offset > UART_MSR || up->hw_type == hsu_dw) {
++ offset <<= 2;
++ writel(value, up->port.membase + offset);
++ } else {
++ unsigned char val = value & 0xff;
++ writeb(val, up->port.membase + offset);
++ }
++}
++void serial_sched_cmd(struct uart_hsu_port *up, char cmd);
++extern struct hsu_dma_ops *pdw_dma_ops;
++extern struct hsu_dma_ops intel_dma_ops;
++
++struct uart_hsu_port *serial_hsu_port_setup(struct device *pdev, int port,
++ resource_size_t start, resource_size_t len, int irq);
++void serial_hsu_port_free(struct uart_hsu_port *up);
++void serial_hsu_port_shutdown(struct uart_hsu_port *up);
++int serial_hsu_dma_setup(struct device *pdev,
++ resource_size_t start, resource_size_t len, unsigned int irq, int share);
++void serial_hsu_dma_free(void);
++int serial_hsu_do_suspend(struct uart_hsu_port *up);
++int serial_hsu_do_resume(struct uart_hsu_port *up);
++int serial_hsu_do_runtime_idle(struct uart_hsu_port *up);
++
++#include "mfd_trace.h"
++#endif
+diff --git a/drivers/tty/serial/mfd_core.c b/drivers/tty/serial/mfd_core.c
+new file mode 100644
+index 0000000..bbb318d
+--- /dev/null
++++ b/drivers/tty/serial/mfd_core.c
+@@ -0,0 +1,2479 @@
++/*
++ * mfd_core.c: driver core for High Speed UART device of Intel Medfield platform
++ *
++ * Refer pxa.c, 8250.c and some other drivers in drivers/serial/
++ *
++ * (C) Copyright 2010 Intel Corporation
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++/* Notes:
++ * 1. DMA channel allocation: 0/1 channel are assigned to port 0,
++ * 2/3 chan to port 1, 4/5 chan to port 3. Even number chans
++ * are used for RX, odd chans for TX
++ *
++ * 2. The RI/DSR/DCD/DTR are not pinned out, DCD & DSR are always
++ * asserted, only when the HW is reset the DDCD and DDSR will
++ * be triggered
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/console.h>
++#include <linux/sysrq.h>
++#include <linux/slab.h>
++#include <linux/circ_buf.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/dma-mapping.h>
++#include <linux/io.h>
++#include <linux/debugfs.h>
++#include <linux/pm_runtime.h>
++#include <linux/irq.h>
++#include <linux/intel_mid_pm.h>
++#include <linux/pm_qos.h>
++
++#define CREATE_TRACE_POINTS
++#include "mfd.h"
++
++static int hsu_dma_enable = 0xff;
++module_param(hsu_dma_enable, int, 0);
++MODULE_PARM_DESC(hsu_dma_enable,
++ "It is a bitmap to set working mode, if bit[x] is 1, then port[x] will work in DMA mode, otherwise in PIO mode.");
++
++static struct hsu_port hsu;
++static struct hsu_port *phsu = &hsu;
++static struct uart_driver serial_hsu_reg;
++static struct hsu_port_cfg *hsu_port_func_cfg;
++
++static void serial_hsu_command(struct uart_hsu_port *up);
++
++int hsu_register_board_info(void *inf)
++{
++ hsu_port_func_cfg = inf;
++ return 0;
++}
++
++static inline int check_qcmd(struct uart_hsu_port *up, char *cmd)
++{
++ struct circ_buf *circ = &up->qcirc;
++ char *buf;
++
++ buf = circ->buf + circ->tail;
++ *cmd = *buf;
++ return CIRC_CNT(circ->head, circ->tail, HSU_Q_MAX);
++}
++
++static inline void insert_qcmd(struct uart_hsu_port *up, char cmd)
++{
++ struct circ_buf *circ = &up->qcirc;
++ char *buf;
++ char last_cmd;
++
++ trace_hsu_cmd_insert(up->index, cmd);
++ if (check_qcmd(up, &last_cmd) && last_cmd == cmd &&
++ cmd != qcmd_enable_irq && cmd != qcmd_port_irq &&
++ cmd != qcmd_dma_irq)
++ return;
++ trace_hsu_cmd_add(up->index, cmd);
++ up->qcmd_num++;
++ buf = circ->buf + circ->head;
++ if (CIRC_SPACE(circ->head, circ->tail, HSU_Q_MAX) < 1)
++ *buf = qcmd_overflow;
++ else {
++ *buf = cmd;
++ circ->head++;
++ if (circ->head == HSU_Q_MAX)
++ circ->head = 0;
++ }
++}
++
++static inline int get_qcmd(struct uart_hsu_port *up, char *cmd)
++{
++ struct circ_buf *circ = &up->qcirc;
++ char *buf;
++
++ if (!CIRC_CNT(circ->head, circ->tail, HSU_Q_MAX))
++ return 0;
++ buf = circ->buf + circ->tail;
++ *cmd = *buf;
++ circ->tail++;
++ if (circ->tail == HSU_Q_MAX)
++ circ->tail = 0;
++ up->qcmd_done++;
++ return 1;
++}
++
++static inline void cl_put_char(struct uart_hsu_port *up, char c)
++{
++ struct circ_buf *circ = &up->cl_circ;
++ char *buf;
++ unsigned long flags;
++
++ spin_lock_irqsave(&up->cl_lock, flags);
++ buf = circ->buf + circ->head;
++ if (CIRC_SPACE(circ->head, circ->tail, HSU_CL_BUF_LEN) > 1) {
++ *buf = c;
++ circ->head++;
++ if (circ->head == HSU_CL_BUF_LEN)
++ circ->head = 0;
++ }
++ spin_unlock_irqrestore(&up->cl_lock, flags);
++}
++
++static inline int cl_get_char(struct uart_hsu_port *up, char *c)
++{
++ struct circ_buf *circ = &up->cl_circ;
++ char *buf;
++ unsigned long flags;
++
++ spin_lock_irqsave(&up->cl_lock, flags);
++ if (!CIRC_CNT(circ->head, circ->tail, HSU_CL_BUF_LEN)) {
++ spin_unlock_irqrestore(&up->cl_lock, flags);
++ return 0;
++ }
++ buf = circ->buf + circ->tail;
++ *c = *buf;
++ circ->tail++;
++ if (circ->tail == HSU_CL_BUF_LEN)
++ circ->tail = 0;
++ spin_unlock_irqrestore(&up->cl_lock, flags);
++ return 1;
++}
++
++
++
++void serial_sched_cmd(struct uart_hsu_port *up, char cmd)
++{
++ pm_runtime_get(up->dev);
++ insert_qcmd(up, cmd);
++ if (test_bit(flag_cmd_on, &up->flags)) {
++ if (up->use_dma)
++ tasklet_schedule(&up->tasklet);
++ else
++ queue_work(up->workqueue, &up->work);
++ }
++ pm_runtime_put(up->dev);
++}
++
++static inline void serial_sched_sync(struct uart_hsu_port *up)
++{
++ mutex_lock(&up->q_mutex);
++ if (up->q_start > 0) {
++ if (up->use_dma) {
++ tasklet_disable(&up->tasklet);
++ serial_hsu_command(up);
++ tasklet_enable(&up->tasklet);
++ } else {
++ flush_workqueue(up->workqueue);
++ }
++ }
++ mutex_unlock(&up->q_mutex);
++}
++
++static inline void serial_sched_start(struct uart_hsu_port *up)
++{
++ unsigned long flags;
++
++ mutex_lock(&up->q_mutex);
++ up->q_start++;
++ if (up->q_start == 1) {
++ clear_bit(flag_cmd_off, &up->flags);
++ spin_lock_irqsave(&up->port.lock, flags);
++ set_bit(flag_cmd_on, &up->flags);
++ spin_unlock_irqrestore(&up->port.lock, flags);
++ if (up->use_dma)
++ tasklet_schedule(&up->tasklet);
++ else
++ queue_work(up->workqueue, &up->work);
++ }
++ mutex_unlock(&up->q_mutex);
++}
++
++static inline void serial_sched_stop(struct uart_hsu_port *up)
++{
++ unsigned long flags;
++
++ mutex_lock(&up->q_mutex);
++ up->q_start--;
++ if (up->q_start == 0) {
++ spin_lock_irqsave(&up->port.lock, flags);
++ clear_bit(flag_cmd_on, &up->flags);
++ insert_qcmd(up, qcmd_cmd_off);
++ spin_unlock_irqrestore(&up->port.lock, flags);
++ if (up->use_dma) {
++ tasklet_schedule(&up->tasklet);
++ while (!test_bit(flag_cmd_off, &up->flags))
++ cpu_relax();
++ } else {
++ queue_work(up->workqueue, &up->work);
++ flush_workqueue(up->workqueue);
++ }
++ }
++ mutex_unlock(&up->q_mutex);
++}
++
++static void serial_set_alt(int index)
++{
++ struct uart_hsu_port *up = phsu->port + index;
++ struct hsu_dma_chan *txc = up->txc;
++ struct hsu_dma_chan *rxc = up->rxc;
++ struct hsu_port_cfg *cfg = phsu->configs[index];
++
++ if (test_bit(flag_set_alt, &up->flags))
++ return;
++
++ trace_hsu_func_start(up->index, __func__);
++ pm_runtime_get_sync(up->dev);
++ disable_irq(up->port.irq);
++ disable_irq(up->dma_irq);
++ serial_sched_stop(up);
++ if (up->use_dma && up->hw_type == hsu_intel) {
++ txc->uport = up;
++ rxc->uport = up;
++ }
++ dev_set_drvdata(up->dev, up);
++ if (cfg->hw_set_alt)
++ cfg->hw_set_alt(index);
++ if (cfg->hw_set_rts)
++ cfg->hw_set_rts(up->index, 0);
++ set_bit(flag_set_alt, &up->flags);
++ serial_sched_start(up);
++ enable_irq(up->dma_irq);
++ enable_irq(up->port.irq);
++ pm_runtime_put(up->dev);
++ trace_hsu_func_end(up->index, __func__, "");
++}
++
++static void serial_clear_alt(int index)
++{
++ struct uart_hsu_port *up = phsu->port + index;
++ struct hsu_port_cfg *cfg = phsu->configs[index];
++
++ if (!test_bit(flag_set_alt, &up->flags))
++ return;
++
++ pm_runtime_get_sync(up->dev);
++ disable_irq(up->port.irq);
++ disable_irq(up->dma_irq);
++ serial_sched_stop(up);
++ if (cfg->hw_set_rts)
++ cfg->hw_set_rts(up->index, 1);
++ clear_bit(flag_set_alt, &up->flags);
++ serial_sched_start(up);
++ enable_irq(up->dma_irq);
++ enable_irq(up->port.irq);
++ pm_runtime_put(up->dev);
++}
++
++#ifdef CONFIG_DEBUG_FS
++
++#define HSU_DBGFS_BUFSIZE 8192
++
++static int hsu_show_regs_open(struct inode *inode, struct file *file)
++{
++ file->private_data = inode->i_private;
++ return 0;
++}
++
++static ssize_t port_show_regs(struct file *file, char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct uart_hsu_port *up = file->private_data;
++ char *buf;
++ u32 len = 0;
++ ssize_t ret;
++
++ buf = kzalloc(HSU_DBGFS_BUFSIZE, GFP_KERNEL);
++ if (!buf)
++ return 0;
++
++ pm_runtime_get_sync(up->dev);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "MFD HSU port[%d] regs:\n", up->index);
++
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "=================================\n");
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "IER: \t\t0x%08x\n", serial_in(up, UART_IER));
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "IIR: \t\t0x%08x\n", serial_in(up, UART_IIR));
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "LCR: \t\t0x%08x\n", serial_in(up, UART_LCR));
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "MCR: \t\t0x%08x\n", serial_in(up, UART_MCR));
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "LSR: \t\t0x%08x\n", serial_in(up, UART_LSR));
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "MSR: \t\t0x%08x\n", serial_in(up, UART_MSR));
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "FOR: \t\t0x%08x\n", serial_in(up, UART_FOR));
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "PS: \t\t0x%08x\n", serial_in(up, UART_PS));
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "MUL: \t\t0x%08x\n", serial_in(up, UART_MUL));
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "DIV: \t\t0x%08x\n", serial_in(up, UART_DIV));
++ pm_runtime_put(up->dev);
++
++ if (len > HSU_DBGFS_BUFSIZE)
++ len = HSU_DBGFS_BUFSIZE;
++
++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
++ kfree(buf);
++ return ret;
++}
++
++static ssize_t dma_show_regs(struct file *file, char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct hsu_dma_chan *chan = file->private_data;
++ char *buf;
++ u32 len = 0;
++ ssize_t ret;
++
++ buf = kzalloc(HSU_DBGFS_BUFSIZE, GFP_KERNEL);
++ if (!buf)
++ return 0;
++
++ pm_runtime_get_sync(chan->uport->dev);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "MFD HSU DMA channel [%d] regs:\n", chan->id);
++
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "=================================\n");
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "CR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_CR));
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "DCR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_DCR));
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "BSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_BSR));
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "MOTSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_MOTSR));
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0SAR));
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0TSR));
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1SAR));
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1TSR));
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2SAR));
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2TSR));
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3SAR));
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3TSR));
++ pm_runtime_put(chan->uport->dev);
++
++ if (len > HSU_DBGFS_BUFSIZE)
++ len = HSU_DBGFS_BUFSIZE;
++
++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
++ kfree(buf);
++ return ret;
++}
++
++static ssize_t hsu_dump_show(struct file *file, char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct uart_hsu_port *up;
++ struct hsu_port_cfg *cfg;
++ char *buf;
++ char cmd;
++ int i;
++ u32 len = 0;
++ ssize_t ret;
++ struct irq_desc *dma_irqdesc = irq_to_desc(phsu->dma_irq);
++ struct irq_desc *port_irqdesc;
++ struct circ_buf *xmit;
++
++ buf = kzalloc(HSU_DBGFS_BUFSIZE, GFP_KERNEL);
++ if (!buf)
++ return 0;
++
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "HSU status dump:\n");
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tdma irq (>0: disable): %d\n",
++ dma_irqdesc ? dma_irqdesc->depth : 0);
++ for (i = 0; i < phsu->port_num; i++) {
++ up = phsu->port + i;
++ cfg = hsu_port_func_cfg + i;
++ port_irqdesc = irq_to_desc(up->port.irq);
++ xmit = &up->port.state->xmit;
++
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "HSU port[%d] %s:\n", up->index, cfg->name);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "xmit empty[%d] xmit pending[%d]\n",
++ uart_circ_empty(xmit),
++ (int)uart_circ_chars_pending(xmit));
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tsuspend idle: %d\n", cfg->idle);
++ if (cfg->has_alt)
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\talt port: %d\n", cfg->alt);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tforce_suspend: %d\n", cfg->force_suspend);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tcts status: %d\n", up->cts_status);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tuse_dma: %s\n",
++ up->use_dma ? "yes" : "no");
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tflag_console: %s\n",
++ test_bit(flag_console, &up->flags) ? "yes" : "no");
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tflag_suspend: %s\n",
++ test_bit(flag_suspend, &up->flags) ? "yes" : "no");
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tflag_active: %s\n",
++ test_bit(flag_active, &up->flags) ? "yes" : "no");
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tflag_set_alt: %s\n",
++ test_bit(flag_set_alt, &up->flags) ? "yes" : "no");
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tflag_startup: %s\n",
++ test_bit(flag_startup, &up->flags) ? "yes" : "no");
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tqcmd q_start: %d\n", up->q_start);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tqcmd total count: %d\n", up->qcmd_num);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tqcmd done count: %d\n", up->qcmd_done);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tport irq count: %d\n", up->port_irq_num);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tport irq cmddone: %d\n", up->port_irq_cmddone);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tport irq cts: %d\n", up->port.icount.cts);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tport irq rng: %d\n", up->port.icount.rng);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tport irq dsr: %d\n", up->port.icount.dsr);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tport irq no irq pending: %d\n",
++ up->port_irq_pio_no_irq_pend);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tport irq no alt: %d\n",
++ up->port_irq_no_alt);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tport irq no startup: %d\n",
++ up->port_irq_no_startup);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tport irq pio rx error: %d\n",
++ up->port_irq_pio_rx_err);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tport irq pio rx available: %d\n",
++ up->port_irq_pio_rx_avb);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tport irq pio rx fifo timeout: %d\n",
++ up->port_irq_pio_rx_timeout);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tport irq pio tx request: %d\n",
++ up->port_irq_pio_tx_req);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tdma invalid irq count: %d\n",
++ up->dma_invalid_irq_num);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tdma irq count: %d\n", up->dma_irq_num);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tdma irq cmddone: %d\n", up->dma_irq_cmddone);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tdma tx irq cmddone: %d\n",
++ up->dma_tx_irq_cmddone);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tport&dma rx irq cmddone: %d\n",
++ up->dma_rx_irq_cmddone);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tport&dma rx timeout irq cmddone: %d\n",
++ up->dma_rx_tmt_irq_cmddone);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\ttasklet done: %d\n", up->tasklet_done);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tworkq done: %d\n", up->workq_done);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tqcmd pending count: %d\n", check_qcmd(up, &cmd));
++ if (check_qcmd(up, &cmd))
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tqcmd pending next: %d\n", cmd);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tin tasklet: %d\n", up->in_tasklet);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tin workq: %d\n", up->in_workq);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tport irq (>0: disable): %d\n",
++ port_irqdesc ? port_irqdesc->depth : 0);
++ len += snprintf(buf + len, HSU_DBGFS_BUFSIZE - len,
++ "\tbyte delay: %d\n", up->byte_delay);
++ }
++ if (len > HSU_DBGFS_BUFSIZE)
++ len = HSU_DBGFS_BUFSIZE;
++
++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
++ kfree(buf);
++ return ret;
++}
++
++
++static const struct file_operations port_regs_ops = {
++ .owner = THIS_MODULE,
++ .open = hsu_show_regs_open,
++ .read = port_show_regs,
++ .llseek = default_llseek,
++};
++
++static const struct file_operations dma_regs_ops = {
++ .owner = THIS_MODULE,
++ .open = hsu_show_regs_open,
++ .read = dma_show_regs,
++ .llseek = default_llseek,
++};
++
++static const struct file_operations hsu_dump_ops = {
++ .owner = THIS_MODULE,
++ .read = hsu_dump_show,
++ .llseek = default_llseek,
++};
++
++static int hsu_debugfs_init(struct hsu_port *hsu)
++{
++ int i;
++ char name[32];
++
++ hsu->debugfs = debugfs_create_dir("hsu", NULL);
++ if (!hsu->debugfs)
++ return -ENOMEM;
++
++ for (i = 0; i < 3; i++) {
++ snprintf(name, sizeof(name), "port_%d_regs", i);
++ debugfs_create_file(name, S_IFREG | S_IRUGO,
++ hsu->debugfs, (void *)(&hsu->port[i]), &port_regs_ops);
++ }
++
++ for (i = 0; i < 6; i++) {
++ snprintf(name, sizeof(name), "dma_chan_%d_regs", i);
++ debugfs_create_file(name, S_IFREG | S_IRUGO,
++ hsu->debugfs, (void *)&hsu->chans[i], &dma_regs_ops);
++ }
++
++ snprintf(name, sizeof(name), "dump_status");
++ debugfs_create_file(name, S_IFREG | S_IRUGO,
++ hsu->debugfs, NULL, &hsu_dump_ops);
++
++ return 0;
++}
++
++static void hsu_debugfs_remove(struct hsu_port *hsu)
++{
++ if (hsu->debugfs)
++ debugfs_remove_recursive(hsu->debugfs);
++}
++
++#else
++static inline int hsu_debugfs_init(struct hsu_port *hsu)
++{
++ return 0;
++}
++
++static inline void hsu_debugfs_remove(struct hsu_port *hsu)
++{
++}
++#endif /* CONFIG_DEBUG_FS */
++
++static void serial_hsu_enable_ms(struct uart_port *port)
++{
++ struct uart_hsu_port *up =
++ container_of(port, struct uart_hsu_port, port);
++
++ trace_hsu_func_start(up->index, __func__);
++ up->ier |= UART_IER_MSI;
++ serial_sched_cmd(up, qcmd_set_ier);
++ trace_hsu_func_end(up->index, __func__, "");
++}
++
++/* Protected by spin_lock_irqsave(port->lock) */
++static void serial_hsu_start_tx(struct uart_port *port)
++{
++ struct uart_hsu_port *up =
++ container_of(port, struct uart_hsu_port, port);
++
++ trace_hsu_func_start(up->index, __func__);
++ serial_sched_cmd(up, qcmd_start_tx);
++ trace_hsu_func_end(up->index, __func__, "");
++}
++
++static void serial_hsu_stop_tx(struct uart_port *port)
++{
++ struct uart_hsu_port *up =
++ container_of(port, struct uart_hsu_port, port);
++
++ trace_hsu_func_start(up->index, __func__);
++ serial_sched_cmd(up, qcmd_stop_tx);
++ trace_hsu_func_end(up->index, __func__, "");
++}
++
++static void hsu_stop_tx(struct uart_port *port)
++{
++ struct uart_hsu_port *up =
++ container_of(port, struct uart_hsu_port, port);
++
++ trace_hsu_func_start(up->index, __func__);
++ serial_sched_cmd(up, qcmd_stop_tx);
++ trace_hsu_func_end(up->index, __func__, "");
++}
++
++/* This is always called in spinlock protected mode, so
++ * modify timeout timer is safe here */
++void intel_dma_do_rx(struct uart_hsu_port *up, u32 int_sts)
++{
++ struct hsu_dma_buffer *dbuf = &up->rxbuf;
++ struct hsu_dma_chan *chan = up->rxc;
++ struct uart_port *port = &up->port;
++ struct tty_struct *tty;
++ struct tty_port *tport = &port->state->port;
++ int count;
++
++ trace_hsu_func_start(up->index, __func__);
++ tty = tty_port_tty_get(&up->port.state->port);
++ if (!tty) {
++ trace_hsu_func_end(up->index, __func__, "notty");
++ return;
++ }
++
++ /*
++ * First need to know how many is already transferred,
++ * then check if its a timeout DMA irq, and return
++ * the trail bytes out, push them up and reenable the
++ * channel
++ */
++
++ /* Timeout IRQ, need wait some time, see Errata 2 */
++ if (int_sts & 0xf00) {
++ up->dma_rx_tmt_irq_cmddone++;
++ udelay(2);
++ } else
++ up->dma_rx_irq_cmddone++;
++
++ /* Stop the channel */
++ chan_writel(chan, HSU_CH_CR, 0x0);
++
++ count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr;
++ if (!count) {
++ /* Restart the channel before we leave */
++ chan_writel(chan, HSU_CH_CR, 0x3);
++ tty_kref_put(tty);
++ trace_hsu_func_end(up->index, __func__, "nodata");
++ return;
++ }
++
++ dma_sync_single_for_cpu(port->dev, dbuf->dma_addr,
++ dbuf->dma_size, DMA_FROM_DEVICE);
++
++ /*
++ * Head will only wrap around when we recycle
++ * the DMA buffer, and when that happens, we
++ * explicitly set tail to 0. So head will
++ * always be greater than tail.
++ */
++ tty_insert_flip_string(tport, dbuf->buf, count);
++ port->icount.rx += count;
++
++ dma_sync_single_for_device(up->port.dev, dbuf->dma_addr,
++ dbuf->dma_size, DMA_FROM_DEVICE);
++
++ /* Reprogram the channel */
++ chan_writel(chan, HSU_CH_D0SAR, dbuf->dma_addr);
++ chan_writel(chan, HSU_CH_D0TSR, dbuf->dma_size);
++ chan_writel(chan, HSU_CH_DCR, 0x1
++ | (0x1 << 8)
++ | (0x1 << 16)
++ | (0x1 << 24) /* timeout bit, see HSU Errata 1 */
++ );
++ tty_flip_buffer_push(tport);
++
++ chan_writel(chan, HSU_CH_CR, 0x3);
++ tty_kref_put(tty);
++ trace_hsu_func_end(up->index, __func__, "");
++
++}
++
++static void serial_hsu_stop_rx(struct uart_port *port)
++{
++ struct uart_hsu_port *up =
++ container_of(port, struct uart_hsu_port, port);
++
++ trace_hsu_func_start(up->index, __func__);
++ serial_sched_cmd(up, qcmd_stop_rx);
++ trace_hsu_func_end(up->index, __func__, "");
++}
++
++static inline void receive_chars(struct uart_hsu_port *up, int *status)
++{
++ struct tty_struct *tty = up->port.state->port.tty;
++ struct tty_port *tport = &up->port.state->port;
++ unsigned int ch, flag;
++ unsigned int max_count = 256;
++
++ if (!tty)
++ return;
++
++ trace_hsu_func_start(up->index, __func__);
++ do {
++ ch = serial_in(up, UART_RX);
++ flag = TTY_NORMAL;
++ up->port.icount.rx++;
++
++ if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
++ UART_LSR_FE | UART_LSR_OE))) {
++
++ dev_warn(up->dev,
++ "We really rush into ERR/BI case"
++ "status = 0x%02x\n", *status);
++ /* For statistics only */
++ if (*status & UART_LSR_BI) {
++ *status &= ~(UART_LSR_FE | UART_LSR_PE);
++ up->port.icount.brk++;
++ /*
++ * We do the SysRQ and SAK checking
++ * here because otherwise the break
++ * may get masked by ignore_status_mask
++ * or read_status_mask.
++ */
++ if (uart_handle_break(&up->port))
++ goto ignore_char;
++ } else if (*status & UART_LSR_PE)
++ up->port.icount.parity++;
++ else if (*status & UART_LSR_FE)
++ up->port.icount.frame++;
++ if (*status & UART_LSR_OE)
++ up->port.icount.overrun++;
++
++ /* Mask off conditions which should be ignored. */
++ *status &= up->port.read_status_mask;
++
++#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
++ if (up->port.cons &&
++ up->port.cons->index == up->port.line) {
++ /* Recover the break flag from console xmit */
++ *status |= up->lsr_break_flag;
++ up->lsr_break_flag = 0;
++ }
++#endif
++ if (*status & UART_LSR_BI) {
++ flag = TTY_BREAK;
++ } else if (*status & UART_LSR_PE)
++ flag = TTY_PARITY;
++ else if (*status & UART_LSR_FE)
++ flag = TTY_FRAME;
++ }
++
++ if (uart_handle_sysrq_char(&up->port, ch))
++ goto ignore_char;
++
++ uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
++ ignore_char:
++ *status = serial_in(up, UART_LSR);
++ } while ((*status & UART_LSR_DR) && max_count--);
++
++ tty_flip_buffer_push(tport);
++ trace_hsu_func_end(up->index, __func__, "");
++}
++
++static void transmit_chars(struct uart_hsu_port *up)
++{
++ struct circ_buf *xmit = &up->port.state->xmit;
++ unsigned long flags;
++ int count;
++
++ spin_lock_irqsave(&up->port.lock, flags);
++ trace_hsu_func_start(up->index, __func__);
++ if (up->port.x_char) {
++ serial_out(up, UART_TX, up->port.x_char);
++ up->port.icount.tx++;
++ up->port.x_char = 0;
++ trace_hsu_func_end(up->index, __func__, "x_char");
++ goto out;
++ }
++ if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
++ hsu_stop_tx(&up->port);
++ if (uart_circ_empty(xmit))
++ trace_hsu_func_end(up->index, __func__, "empty");
++ else
++ trace_hsu_func_end(up->index, __func__, "stop");
++ goto out;
++ }
++
++ /* The IRQ is for TX FIFO half-empty */
++ count = up->port.fifosize / 2;
++
++ do {
++ if (uart_tx_stopped(&up->port)) {
++ hsu_stop_tx(&up->port);
++ break;
++ }
++ serial_out(up, UART_TX, xmit->buf[xmit->tail]);
++ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
++
++ up->port.icount.tx++;
++ if (uart_circ_empty(xmit))
++ break;
++ } while (--count > 0);
++
++ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
++ uart_write_wakeup(&up->port);
++
++ if (uart_circ_empty(xmit)) {
++ hsu_stop_tx(&up->port);
++ trace_hsu_func_end(up->index, __func__, "tx_complete");
++ }
++ else
++ trace_hsu_func_end(up->index, __func__, "");
++
++out:
++ spin_unlock_irqrestore(&up->port.lock, flags);
++}
++
++static void check_modem_status(struct uart_hsu_port *up)
++{
++ struct uart_port *uport = &up->port;
++ struct tty_port *port = &uport->state->port;
++ struct tty_struct *tty = port->tty;
++ struct hsu_port_cfg *cfg = phsu->configs[up->index];
++ int status;
++ int delta_msr = 0;
++
++ trace_hsu_func_start(up->index, __func__);
++ status = serial_in(up, UART_MSR);
++ trace_hsu_mctrl(up->index, status);
++ if (port->flags & ASYNC_CTS_FLOW && !cfg->hw_ctrl_cts) {
++ if (tty->hw_stopped) {
++ if (status & UART_MSR_CTS) {
++ serial_sched_cmd(up, qcmd_start_tx);
++ tty->hw_stopped = 0;
++ up->cts_status = 0;
++ uport->icount.cts++;
++ delta_msr = 1;
++ uart_write_wakeup(uport);
++ }
++ } else {
++ if (!(status & UART_MSR_CTS)) {
++ /* Is this automitically controlled */
++ if (up->use_dma)
++ up->dma_ops->stop_tx(up);
++ clear_bit(flag_tx_on, &up->flags);
++ tty->hw_stopped = 1;
++ up->cts_status = 1;
++ delta_msr = 1;
++ uport->icount.cts++;
++ }
++ }
++ }
++
++ if ((status & UART_MSR_ANY_DELTA)) {
++ if (status & UART_MSR_TERI)
++ up->port.icount.rng++;
++ if (status & UART_MSR_DDSR)
++ up->port.icount.dsr++;
++ /* We may only get DDCD when HW init and reset */
++ if (status & UART_MSR_DDCD)
++ uart_handle_dcd_change(&up->port,
++ status & UART_MSR_DCD);
++ delta_msr = 1;
++ }
++
++ if (delta_msr)
++ wake_up_interruptible(&up->port.state->port.delta_msr_wait);
++ trace_hsu_func_end(up->index, __func__, "");
++}
++
++static void hsu_dma_chan_handler(struct hsu_port *hsu, int index)
++{
++ unsigned long flags;
++ struct uart_hsu_port *up = hsu->chans[index * 2].uport;
++ struct hsu_dma_chan *txc = up->txc;
++ struct hsu_dma_chan *rxc = up->rxc;
++
++ up->dma_irq_num++;
++ if (unlikely(!up->use_dma
++ || !test_bit(flag_startup, &up->flags))) {
++ up->dma_invalid_irq_num++;
++ chan_readl(txc, HSU_CH_SR);
++ chan_readl(rxc, HSU_CH_SR);
++ return;
++ }
++ disable_irq_nosync(up->dma_irq);
++ spin_lock_irqsave(&up->port.lock, flags);
++ serial_sched_cmd(up, qcmd_dma_irq);
++ spin_unlock_irqrestore(&up->port.lock, flags);
++}
++
++/*
++ * This handles the interrupt from one port.
++ */
++static irqreturn_t hsu_port_irq(int irq, void *dev_id)
++{
++ struct uart_hsu_port *up = dev_id;
++ unsigned long flags;
++ u8 lsr;
++
++ trace_hsu_func_start(up->index, __func__);
++ up->port_irq_num++;
++
++ if (up->hw_type == hsu_intel) {
++ if (unlikely(!test_bit(flag_set_alt, &up->flags))) {
++ up->port_irq_no_alt++;
++ trace_hsu_func_end(up->index, __func__, "noalt");
++ return IRQ_NONE;
++ }
++ } else {
++ if (unlikely(test_bit(flag_suspend, &up->flags))) {
++ trace_hsu_func_end(up->index, __func__, "suspend");
++ return IRQ_NONE;
++ }
++
++ /* On BYT, this IRQ may be shared with other HW */
++ up->iir = serial_in(up, UART_IIR);
++ if (unlikely(up->iir & 0x1)) {
++ /*
++ * Read UART_BYTE_COUNT and UART_OVERFLOW
++ * registers to clear the overrun error on
++ * Tx. This is a HW issue on VLV2 B0.
++ * more information on HSD 4683358.
++ */
++ serial_in(up, 0x818 / 4);
++ serial_in(up, 0x820 / 4);
++ trace_hsu_func_end(up->index, __func__, "workaround");
++ return IRQ_NONE;
++ }
++ }
++
++ if (unlikely(!test_bit(flag_startup, &up->flags))) {
++ pr_err("recv IRQ when we are not startup yet\n");
++ /*SCU might forward it too late when it is closed already*/
++ serial_in(up, UART_LSR);
++ up->port_irq_no_startup++;
++ trace_hsu_func_end(up->index, __func__, "nostart");
++ return IRQ_HANDLED;
++ }
++
++ /* DesignWare HW's DMA mode still needs the port irq */
++ if (up->use_dma && up->hw_type == hsu_intel) {
++ lsr = serial_in(up, UART_LSR);
++ spin_lock_irqsave(&up->port.lock, flags);
++ check_modem_status(up);
++ spin_unlock_irqrestore(&up->port.lock, flags);
++ if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE |
++ UART_LSR_FE | UART_LSR_OE)))
++ dev_warn(up->dev,
++ "Got LSR irq(0x%02x) while using DMA", lsr);
++ trace_hsu_func_end(up->index, __func__, "lsr");
++ return IRQ_HANDLED;
++ }
++
++ disable_irq_nosync(up->port.irq);
++ spin_lock_irqsave(&up->port.lock, flags);
++ serial_sched_cmd(up, qcmd_port_irq);
++ spin_unlock_irqrestore(&up->port.lock, flags);
++
++ trace_hsu_func_end(up->index, __func__, "");
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t hsu_dma_irq(int irq, void *dev_id)
++{
++ struct uart_hsu_port *up;
++ unsigned long flags;
++ unsigned int dmairq;
++ int i;
++
++ spin_lock_irqsave(&phsu->dma_lock, flags);
++ dmairq = mfd_readl(phsu, HSU_GBL_DMAISR);
++ if (phsu->irq_port_and_dma) {
++ up = dev_id;
++ up->port_dma_sts = dmairq;
++ if (up->port_dma_sts & (3 << (up->index * 2)))
++ hsu_dma_chan_handler(phsu, up->index);
++ } else {
++ for (i = 0; i < 3; i++)
++ if (dmairq & (3 << (i * 2))) {
++ up = phsu->chans[i * 2].uport;
++ up->port_dma_sts = dmairq;
++ hsu_dma_chan_handler(phsu, i);
++ }
++ }
++ spin_unlock_irqrestore(&phsu->dma_lock, flags);
++
++ return IRQ_HANDLED;
++}
++
++static unsigned int serial_hsu_tx_empty(struct uart_port *port)
++{
++ struct uart_hsu_port *up =
++ container_of(port, struct uart_hsu_port, port);
++ int ret = 1;
++
++ trace_hsu_func_start(up->index, __func__);
++ pm_runtime_get_sync(up->dev);
++ serial_sched_stop(up);
++
++ if (up->use_dma && test_bit(flag_tx_on, &up->flags))
++ ret = 0;
++ ret = ret &&
++ (serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0);
++ serial_sched_start(up);
++ pm_runtime_put(up->dev);
++ trace_hsu_func_end(up->index, __func__, "");
++ return ret;
++}
++
++static unsigned int serial_hsu_get_mctrl(struct uart_port *port)
++{
++ struct uart_hsu_port *up =
++ container_of(port, struct uart_hsu_port, port);
++ unsigned char status = up->msr;
++ unsigned int ret = 0;
++
++ trace_hsu_func_start(up->index, __func__);
++ if (status & UART_MSR_DCD)
++ ret |= TIOCM_CAR;
++ if (status & UART_MSR_RI)
++ ret |= TIOCM_RNG;
++ if (status & UART_MSR_DSR)
++ ret |= TIOCM_DSR;
++ if (status & UART_MSR_CTS)
++ ret |= TIOCM_CTS;
++ trace_hsu_func_end(up->index, __func__, "");
++ return ret;
++}
++
++static void set_mctrl(struct uart_hsu_port *up, unsigned int mctrl)
++{
++ trace_hsu_func_start(up->index, __func__);
++ if (mctrl & TIOCM_RTS)
++ up->mcr |= UART_MCR_RTS;
++ if (mctrl & TIOCM_DTR)
++ up->mcr |= UART_MCR_DTR;
++ if (mctrl & TIOCM_OUT1)
++ up->mcr |= UART_MCR_OUT1;
++ if (mctrl & TIOCM_OUT2)
++ up->mcr |= UART_MCR_OUT2;
++ if (mctrl & TIOCM_LOOP)
++ up->mcr |= UART_MCR_LOOP;
++ trace_hsu_mctrl(up->index, mctrl);
++ serial_out(up, UART_MCR, up->mcr);
++ udelay(100);
++ trace_hsu_func_end(up->index, __func__, "");
++}
++
++static void serial_hsu_set_mctrl(struct uart_port *port, unsigned int mctrl)
++{
++ struct uart_hsu_port *up =
++ container_of(port, struct uart_hsu_port, port);
++
++ trace_hsu_func_start(up->index, __func__);
++ if (mctrl & TIOCM_RTS)
++ up->mcr |= UART_MCR_RTS;
++ if (mctrl & TIOCM_DTR)
++ up->mcr |= UART_MCR_DTR;
++ if (mctrl & TIOCM_OUT1)
++ up->mcr |= UART_MCR_OUT1;
++ if (mctrl & TIOCM_OUT2)
++ up->mcr |= UART_MCR_OUT2;
++ if (mctrl & TIOCM_LOOP)
++ up->mcr |= UART_MCR_LOOP;
++ serial_sched_cmd(up, qcmd_set_mcr);
++ trace_hsu_func_end(up->index, __func__, "");
++}
++
++static void serial_hsu_break_ctl(struct uart_port *port, int break_state)
++{
++ struct uart_hsu_port *up =
++ container_of(port, struct uart_hsu_port, port);
++
++ trace_hsu_func_start(up->index, __func__);
++ pm_runtime_get_sync(up->dev);
++ serial_sched_stop(up);
++ if (break_state == -1)
++ up->lcr |= UART_LCR_SBC;
++ else
++ up->lcr &= ~UART_LCR_SBC;
++ serial_out(up, UART_LCR, up->lcr);
++ serial_sched_start(up);
++ pm_runtime_put(up->dev);
++ trace_hsu_func_end(up->index, __func__, "");
++}
++
++/*
++ * What special to do:
++ * 1. chose the 64B fifo mode
++ * 2. start dma or pio depends on configuration
++ * 3. we only allocate dma memory when needed
++ */
++static int serial_hsu_startup(struct uart_port *port)
++{
++ static int console_first_init = 1;
++ int ret = 0;
++ unsigned long flags;
++ static DEFINE_MUTEX(lock);
++ struct uart_hsu_port *up =
++ container_of(port, struct uart_hsu_port, port);
++ struct hsu_port_cfg *cfg = phsu->configs[up->index];
++
++ trace_hsu_func_start(up->index, __func__);
++ mutex_lock(&lock);
++
++ pm_runtime_get_sync(up->dev);
++
++ /* HW start it */
++ if (cfg->hw_reset)
++ cfg->hw_reset(up->port.membase);
++
++ if (console_first_init && test_bit(flag_console, &up->flags)) {
++ serial_sched_stop(up);
++ console_first_init = 0;
++ }
++ clear_bit(flag_reopen, &up->flags);
++ if (cfg->has_alt) {
++ struct hsu_port_cfg *alt_cfg = hsu_port_func_cfg + cfg->alt;
++ struct uart_hsu_port *alt_up = phsu->port + alt_cfg->index;
++
++ if (test_bit(flag_startup, &alt_up->flags) &&
++ alt_up->port.state->port.tty) {
++ if (alt_cfg->force_suspend) {
++ uart_suspend_port(&serial_hsu_reg,
++ &alt_up->port);
++ serial_clear_alt(alt_up->index);
++ set_bit(flag_reopen, &alt_up->flags);
++ } else {
++ int loop = 50;
++
++ while (test_bit(flag_startup,
++ &alt_up->flags) && --loop)
++ msleep(20);
++ if (test_bit(flag_startup, &alt_up->flags)) {
++ WARN(1, "Share port open timeout\n");
++ ret = -EBUSY;
++ goto out;
++ }
++ }
++ }
++ }
++ serial_set_alt(up->index);
++ serial_sched_start(up);
++ serial_sched_stop(up);
++
++ /*
++ * Clear the FIFO buffers and disable them.
++ * (they will be reenabled in set_termios())
++ */
++ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
++ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
++ UART_FCR_CLEAR_RCVR |
++ UART_FCR_CLEAR_XMIT);
++ serial_out(up, UART_FCR, 0);
++
++ /* Clear the interrupt registers. */
++ (void) serial_in(up, UART_LSR);
++ (void) serial_in(up, UART_RX);
++ (void) serial_in(up, UART_IIR);
++ (void) serial_in(up, UART_MSR);
++
++ /* Now, initialize the UART, default is 8n1 */
++ serial_out(up, UART_LCR, UART_LCR_WLEN8);
++ up->port.mctrl |= TIOCM_OUT2;
++ set_mctrl(up, up->port.mctrl);
++
++ /* DMA init */
++ if (up->use_dma) {
++ ret = up->dma_ops->init ? up->dma_ops->init(up) : -ENODEV;
++ if (ret) {
++ dev_warn(up->dev, "Fail to init DMA, will use PIO\n");
++ up->use_dma = 0;
++ }
++ }
++
++ /*
++ * Finally, enable interrupts. Note: Modem status
++ * interrupts are set via set_termios(), which will
++ * be occurring imminently
++ * anyway, so we don't enable them here.
++ */
++ /* bit 4 for DW is reserved, but SEG need it to be set */
++ if (!up->use_dma || up->hw_type == hsu_dw)
++ up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE;
++ else
++ up->ier = 0;
++ serial_out(up, UART_IER, up->ier);
++
++ /* And clear the interrupt registers again for luck. */
++ (void) serial_in(up, UART_LSR);
++ (void) serial_in(up, UART_RX);
++ (void) serial_in(up, UART_IIR);
++ (void) serial_in(up, UART_MSR);
++
++ set_bit(flag_startup, &up->flags);
++ serial_sched_start(up);
++ spin_lock_irqsave(&up->port.lock, flags);
++ serial_sched_cmd(up, qcmd_get_msr);
++ spin_unlock_irqrestore(&up->port.lock, flags);
++ serial_sched_sync(up);
++
++out:
++ pm_runtime_put(up->dev);
++ mutex_unlock(&lock);
++ trace_hsu_func_end(up->index, __func__, "");
++ return ret;
++}
++
++static void serial_hsu_shutdown(struct uart_port *port)
++{
++ static DEFINE_MUTEX(lock);
++ struct uart_hsu_port *up =
++ container_of(port, struct uart_hsu_port, port);
++ struct hsu_port_cfg *cfg = phsu->configs[up->index];
++
++ trace_hsu_func_start(up->index, __func__);
++ mutex_lock(&lock);
++ pm_runtime_get_sync(up->dev);
++ serial_sched_stop(up);
++ clear_bit(flag_startup, &up->flags);
++
++ /* Disable interrupts from this port */
++ up->ier = 0;
++ serial_out(up, UART_IER, 0);
++
++ clear_bit(flag_tx_on, &up->flags);
++
++ up->port.mctrl &= ~TIOCM_OUT2;
++ set_mctrl(up, up->port.mctrl);
++
++ /* Disable break condition and FIFOs */
++ serial_out(up, UART_LCR,
++ serial_in(up, UART_LCR) & ~UART_LCR_SBC);
++ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
++ UART_FCR_CLEAR_RCVR |
++ UART_FCR_CLEAR_XMIT);
++ serial_out(up, UART_FCR, 0);
++
++ /* Free allocated dma buffer */
++ if (up->use_dma)
++ up->dma_ops->exit(up);
++
++ if (cfg->has_alt) {
++ struct hsu_port_cfg *alt_cfg = hsu_port_func_cfg + cfg->alt;
++ struct uart_hsu_port *alt_up = phsu->port + alt_cfg->index;
++
++ if (test_bit(flag_reopen, &alt_up->flags)) {
++ serial_clear_alt(up->index);
++ uart_resume_port(&serial_hsu_reg, &alt_up->port);
++ }
++ }
++
++ pm_runtime_put_sync(up->dev);
++ mutex_unlock(&lock);
++ trace_hsu_func_end(up->index, __func__, "");
++}
++
++/* calculate mul,div for low fref e.g. TNG B0 38.4M
++ * finally the fref will swith to high fref e.g. 100M
++*/
++static bool calc_for_low_fref(u32 clock, u32 baud, u32 *mul, u32 *div)
++{
++ if (clock == 38400) {
++ switch (baud) {
++ case 3500000:
++ /* ps: 10 */
++ *mul = 350;
++ *div = 384;
++ break;
++ case 3000000:
++ /* ps: 12 */
++ *mul = 360;
++ *div = 384;
++ break;
++ case 2500000:
++ /* ps: 12 */
++ *mul = 300;
++ *div = 384;
++ break;
++ case 2000000:
++ /* ps: 16 */
++ *mul = 320;
++ *div = 384;
++ break;
++ case 1843200:
++ /* ps: 16 */
++ *mul = 294912;
++ *div = 384000;
++ break;
++ case 1500000:
++ /* ps: 16 */
++ *mul = 240;
++ *div = 384;
++ break;
++ case 1000000:
++ /* ps: 16 */
++ *mul = 160;
++ *div = 384;
++ break;
++ case 500000:
++ /* ps: 16 */
++ *mul = 80;
++ *div = 384;
++ break;
++ }
++ return true;
++ } else
++ return false;
++}
++
++static void
++serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios,
++ struct ktermios *old)
++{
++ struct uart_hsu_port *up =
++ container_of(port, struct uart_hsu_port, port);
++ struct hsu_port_cfg *cfg = phsu->configs[up->index];
++ unsigned char cval, fcr = 0;
++ unsigned long flags;
++ unsigned int baud, quot, clock, bits;
++ /* 0x3d09 is default dividor value refer for deatils
++ * please refer high speed UART HAS documents.
++ */
++ u32 ps = 0, mul = 0, div = 0x3D09, m = 0, n = 0;
++
++ trace_hsu_func_start(up->index, __func__);
++ switch (termios->c_cflag & CSIZE) {
++ case CS5:
++ cval = UART_LCR_WLEN5;
++ bits = 7;
++ break;
++ case CS6:
++ cval = UART_LCR_WLEN6;
++ bits = 8;
++ break;
++ case CS7:
++ cval = UART_LCR_WLEN7;
++ bits = 9;
++ break;
++ default:
++ case CS8:
++ cval = UART_LCR_WLEN8;
++ bits = 10;
++ break;
++ }
++
++ /* CMSPAR isn't supported by this driver */
++ termios->c_cflag &= ~CMSPAR;
++
++ if (termios->c_cflag & CSTOPB) {
++ cval |= UART_LCR_STOP;
++ bits++;
++ }
++ if (termios->c_cflag & PARENB) {
++ cval |= UART_LCR_PARITY;
++ bits++;
++ }
++ if (!(termios->c_cflag & PARODD))
++ cval |= UART_LCR_EPAR;
++
++ baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
++ trace_hsu_set_termios(up->index, baud, termios->c_cflag & CRTSCTS ? 1 : 0);
++
++ if (up->hw_type == hsu_intel) {
++ /*
++ * If base clk is 50Mhz, and the baud rate come from:
++ * baud = 50M * MUL / (DIV * PS * DLAB)
++ *
++ * For those basic low baud rate we can get the direct
++ * scalar from 2746800, like 115200 = 2746800/24. For those
++ * higher baud rate, we handle them case by case, mainly by
++ * adjusting the MUL/PS registers, and DIV register is kept
++ * as default value 0x3d09 to make things simple
++ */
++
++ if (cfg->hw_get_clk)
++ clock = cfg->hw_get_clk();
++ else
++ clock = 50000;
++ /* ps = 16 is prefered, if not have to use 12, l0 */
++ if (baud * 16 <= clock * 1000)
++ ps = 16;
++ else if (baud * 12 <= clock * 1000)
++ ps = 12;
++ else if (baud * 10 <= clock * 1000)
++ ps = 10;
++ else
++ pr_err("port:%d baud:%d is too high for clock:%u M\n",
++ up->index, baud, clock / 1000);
++
++ switch (baud) {
++ case 3500000:
++ case 3000000:
++ case 2500000:
++ case 2000000:
++ case 1843200:
++ case 1500000:
++ case 1000000:
++ case 500000:
++ quot = 1;
++ if (!calc_for_low_fref(clock, baud, &mul, &div))
++ /*
++ * mul = baud * 0x3d09 * ps / 1000 / clock
++ * change the formula order to avoid overflow
++ */
++ mul = (0x3d09 * ps / 100) * (baud / 100)
++ * 10 / clock;
++ break;
++ default:
++ /* Use uart_get_divisor to get quot for other baud rates
++ * avoid overflow: mul = uartclk * 0x3d09 / clock / 1000
++ * uartclk is multiply of 115200 * n * 16 */
++ mul = (up->port.uartclk / 1600) * 0x3d09 /
++ clock * 16 / 10;
++ quot = 0;
++ }
++
++ if (!quot)
++ quot = uart_get_divisor(port, baud);
++
++ if ((up->port.uartclk / quot) < (2400 * 16))
++ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_1B;
++ else if ((up->port.uartclk / quot) < (230400 * 16))
++ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_16B;
++ else
++ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_32B;
++
++ fcr |= UART_FCR_HSU_64B_FIFO;
++ } else {
++ /* need calc quot here */
++ switch (baud) {
++ case 3000000:
++ case 1500000:
++ case 1000000:
++ case 500000:
++ m = 48;
++ n = 100;
++ quot = 3000000 / baud;
++ break;
++ default:
++ m = 9216;
++ n = 15625;
++ quot = 0;
++ }
++ if (!quot)
++ quot = uart_get_divisor(port, baud);
++
++ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 |
++ UART_FCR_T_TRIG_11;
++ if (baud < 2400) {
++ fcr &= ~UART_FCR_TRIGGER_MASK;
++ fcr |= UART_FCR_TRIGGER_1;
++ }
++ }
++
++ /* one byte transfer duration unit microsecond */
++ up->byte_delay = (bits * 1000000 + baud - 1) / baud;
++
++ pm_runtime_get_sync(up->dev);
++ serial_sched_stop(up);
++ /*
++ * Ok, we're now changing the port state. Do it with
++ * interrupts disabled.
++ */
++ spin_lock_irqsave(&up->port.lock, flags);
++
++ /* Update the per-port timeout */
++ uart_update_timeout(port, termios->c_cflag, baud);
++
++ up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
++ if (termios->c_iflag & INPCK)
++ up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
++ if (termios->c_iflag & (BRKINT | PARMRK))
++ up->port.read_status_mask |= UART_LSR_BI;
++
++ /* Characters to ignore */
++ up->port.ignore_status_mask = 0;
++ if (termios->c_iflag & IGNPAR)
++ up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
++ if (termios->c_iflag & IGNBRK) {
++ up->port.ignore_status_mask |= UART_LSR_BI;
++ /*
++ * If we're ignoring parity and break indicators,
++ * ignore overruns too (for real raw support).
++ */
++ if (termios->c_iflag & IGNPAR)
++ up->port.ignore_status_mask |= UART_LSR_OE;
++ }
++
++ /* Ignore all characters if CREAD is not set */
++ if ((termios->c_cflag & CREAD) == 0)
++ up->port.ignore_status_mask |= UART_LSR_DR;
++
++ /*
++ * CTS flow control flag and modem status interrupts, disable
++ * MSI by default
++ */
++ up->ier &= ~UART_IER_MSI;
++ if (UART_ENABLE_MS(&up->port, termios->c_cflag))
++ up->ier |= UART_IER_MSI;
++
++ serial_out(up, UART_IER, up->ier);
++
++ if (termios->c_cflag & CRTSCTS)
++ up->mcr |= UART_MCR_AFE | UART_MCR_RTS;
++ else
++ up->mcr &= ~UART_MCR_AFE;
++
++ up->dll = quot & 0xff;
++ up->dlm = quot >> 8;
++ up->fcr = fcr;
++ up->lcr = cval; /* Save LCR */
++
++ serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
++ serial_out(up, UART_DLL, up->dll); /* LS of divisor */
++ serial_out(up, UART_DLM, up->dlm); /* MS of divisor */
++ serial_out(up, UART_LCR, cval); /* reset DLAB */
++
++ if (up->hw_type == hsu_intel) {
++ up->mul = mul;
++ up->div = div;
++ up->ps = ps;
++ serial_out(up, UART_MUL, up->mul); /* set MUL */
++ serial_out(up, UART_DIV, up->div); /* set DIV */
++ serial_out(up, UART_PS, up->ps); /* set PS */
++ } else {
++ if (m != up->m || n != up->n) {
++ if (cfg->set_clk)
++ cfg->set_clk(m, n, up->port.membase);
++ up->m = m;
++ up->n = n;
++ }
++ }
++
++ serial_out(up, UART_FCR, fcr);
++ set_mctrl(up, up->port.mctrl);
++ serial_sched_cmd(up, qcmd_get_msr);
++ spin_unlock_irqrestore(&up->port.lock, flags);
++ serial_sched_start(up);
++ serial_sched_sync(up);
++ pm_runtime_put(up->dev);
++ trace_hsu_func_end(up->index, __func__, "");
++}
++
++static void
++serial_hsu_pm(struct uart_port *port, unsigned int state,
++ unsigned int oldstate)
++{
++}
++
++static void serial_hsu_release_port(struct uart_port *port)
++{
++}
++
++static int serial_hsu_request_port(struct uart_port *port)
++{
++ return 0;
++}
++
++static void serial_hsu_config_port(struct uart_port *port, int flags)
++{
++ struct uart_hsu_port *up =
++ container_of(port, struct uart_hsu_port, port);
++ up->port.type = PORT_MFD;
++}
++
++static int
++serial_hsu_verify_port(struct uart_port *port, struct serial_struct *ser)
++{
++ /* We don't want the core code to modify any port params */
++ return -EINVAL;
++}
++
++static const char *
++serial_hsu_type(struct uart_port *port)
++{
++ struct uart_hsu_port *up =
++ container_of(port, struct uart_hsu_port, port);
++ return up->name;
++}
++
++struct device *intel_mid_hsu_set_wake_peer(int port,
++ void (*wake_peer)(struct device *))
++{
++ struct hsu_port_cfg *cfg = phsu->configs[port];
++
++ cfg->wake_peer = wake_peer;
++ return cfg->dev;
++}
++EXPORT_SYMBOL(intel_mid_hsu_set_wake_peer);
++
++static void serial_hsu_wake_peer(struct uart_port *port)
++{
++ struct uart_hsu_port *up =
++ container_of(port, struct uart_hsu_port, port);
++ struct hsu_port_cfg *cfg = phsu->configs[up->index];
++
++ trace_hsu_func_start(up->index, __func__);
++ if (cfg->wake_peer)
++ cfg->wake_peer(cfg->dev);
++ trace_hsu_func_end(up->index, __func__, "");
++}
++
++#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
++/* Wait for transmitter & holding register to empty */
++static inline int wait_for_xmitr(struct uart_hsu_port *up)
++{
++ unsigned int status, tmout = 10000;
++
++ while (--tmout) {
++ status = serial_in(up, UART_LSR);
++ if (status & UART_LSR_BI)
++ up->lsr_break_flag = UART_LSR_BI;
++ udelay(1);
++ if (status & BOTH_EMPTY)
++ break;
++ }
++ if (tmout == 0)
++ return 0;
++
++ if (up->port.flags & UPF_CONS_FLOW) {
++ tmout = 10000;
++ while (--tmout &&
++ ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
++ udelay(1);
++ if (tmout == 0)
++ return 0;
++ }
++ return 1;
++}
++
++#ifdef CONFIG_CONSOLE_POLL
++static int serial_hsu_get_poll_char(struct uart_port *port)
++{
++ struct uart_hsu_port *up =
++ container_of(port, struct uart_hsu_port, port);
++ u8 lsr;
++
++ lsr = serial_in(up, UART_LSR);
++ if (!(lsr & UART_LSR_DR))
++ return NO_POLL_CHAR;
++ return serial_in(up, UART_RX);
++}
++
++static void serial_hsu_put_poll_char(struct uart_port *port,
++ unsigned char c)
++{
++ struct uart_hsu_port *up =
++ container_of(port, struct uart_hsu_port, port);
++
++ serial_out(up, UART_IER, 0);
++ while (!wait_for_xmitr(up))
++ cpu_relax();
++ serial_out(up, UART_TX, c);
++ while (!wait_for_xmitr(up))
++ cpu_relax();
++ serial_out(up, UART_IER, up->ier);
++}
++#endif
++
++#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
++static void serial_hsu_console_putchar(struct uart_port *port, int ch)
++{
++ struct uart_hsu_port *up =
++ container_of(port, struct uart_hsu_port, port);
++ cl_put_char(up, ch);
++}
++
++/*
++ * Print a string to the serial port trying not to disturb
++ * any possible real use of the port...
++ *
++ * The console_lock must be held when we get here.
++ */
++static void
++serial_hsu_console_write(struct console *co, const char *s, unsigned int count)
++{
++ struct uart_hsu_port *up = phsu->port + co->index;
++ unsigned long flags;
++
++ uart_console_write(&up->port, s, count, serial_hsu_console_putchar);
++ spin_lock_irqsave(&up->cl_lock, flags);
++ serial_sched_cmd(up, qcmd_cl);
++ spin_unlock_irqrestore(&up->cl_lock, flags);
++}
++
++static struct console serial_hsu_console;
++
++static int __init
++serial_hsu_console_setup(struct console *co, char *options)
++{
++ struct uart_hsu_port *up = phsu->port + co->index;
++ int baud = 115200;
++ int bits = 8;
++ int parity = 'n';
++ int flow = 'n';
++ unsigned long flags;
++
++ if (co->index < 0 || co->index >= hsu_port_max)
++ return -ENODEV;
++
++ if (options)
++ uart_parse_options(options, &baud, &parity, &bits, &flow);
++
++ pm_runtime_get_sync(up->dev);
++ set_bit(flag_console, &up->flags);
++ set_bit(flag_startup, &up->flags);
++ serial_set_alt(up->index);
++ serial_sched_start(up);
++ spin_lock_irqsave(&up->port.lock, flags);
++ serial_sched_cmd(up, qcmd_get_msr);
++ spin_unlock_irqrestore(&up->port.lock, flags);
++ serial_sched_sync(up);
++ pm_runtime_put(up->dev);
++ up->cl_circ.buf = kzalloc(HSU_CL_BUF_LEN, GFP_KERNEL);
++ if (up->cl_circ.buf == NULL)
++ return -ENOMEM;
++ return uart_set_options(&up->port, co, baud, parity, bits, flow);
++}
++
++static struct console serial_hsu_console = {
++ .name = "ttyMFD",
++ .write = serial_hsu_console_write,
++ .device = uart_console_device,
++ .setup = serial_hsu_console_setup,
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
++ .data = &serial_hsu_reg,
++};
++
++#define SERIAL_HSU_CONSOLE (&serial_hsu_console)
++#else
++#define SERIAL_HSU_CONSOLE NULL
++#endif
++
++struct uart_ops serial_hsu_pops = {
++ .tx_empty = serial_hsu_tx_empty,
++ .set_mctrl = serial_hsu_set_mctrl,
++ .get_mctrl = serial_hsu_get_mctrl,
++ .stop_tx = serial_hsu_stop_tx,
++ .start_tx = serial_hsu_start_tx,
++ .stop_rx = serial_hsu_stop_rx,
++ .enable_ms = serial_hsu_enable_ms,
++ .break_ctl = serial_hsu_break_ctl,
++ .startup = serial_hsu_startup,
++ .shutdown = serial_hsu_shutdown,
++ .set_termios = serial_hsu_set_termios,
++ .pm = serial_hsu_pm,
++ .type = serial_hsu_type,
++ .release_port = serial_hsu_release_port,
++ .request_port = serial_hsu_request_port,
++ .config_port = serial_hsu_config_port,
++ .verify_port = serial_hsu_verify_port,
++ .wake_peer = serial_hsu_wake_peer,
++#ifdef CONFIG_CONSOLE_POLL
++ .poll_get_char = serial_hsu_get_poll_char,
++ .poll_put_char = serial_hsu_put_poll_char,
++#endif
++};
++
++static struct uart_driver serial_hsu_reg = {
++ .owner = THIS_MODULE,
++ .driver_name = "MFD serial",
++ .dev_name = "ttyMFD",
++ .major = TTY_MAJOR,
++ .minor = 128,
++ .nr = HSU_PORT_MAX,
++};
++
++static irqreturn_t wakeup_irq(int irq, void *dev)
++{
++ struct uart_hsu_port *up = dev_get_drvdata(dev);
++ struct hsu_port_cfg *cfg = phsu->configs[up->index];
++
++ trace_hsu_func_start(up->index, __func__);
++ set_bit(flag_active, &up->flags);
++ if (cfg->preamble && cfg->hw_set_rts)
++ cfg->hw_set_rts(up->index, 1);
++ pm_runtime_get(dev);
++ pm_runtime_put(dev);
++ trace_hsu_func_end(up->index, __func__, "");
++ return IRQ_HANDLED;
++}
++
++#if defined(CONFIG_PM) || defined(CONFIG_PM_RUNTIME)
++static void hsu_flush_rxfifo(struct uart_hsu_port *up)
++{
++ unsigned int lsr, cnt;
++
++ if (up->hw_type == hsu_intel) {
++ cnt = serial_in(up, UART_FOR) & 0x7F;
++ if (cnt)
++ dev_dbg(up->dev,
++ "Warning: %d bytes are received"
++ " in RX fifo after RTS active for %d us\n",
++ cnt, up->byte_delay);
++ lsr = serial_in(up, UART_LSR);
++ if (lsr & UART_LSR_DR && cnt)
++ dev_dbg(up->dev,
++ "flush abnormal data in rx fifo\n");
++ while (cnt) {
++ serial_in(up, UART_RX);
++ cnt--;
++ }
++ }
++}
++
++static void hsu_regs_context(struct uart_hsu_port *up, int op)
++{
++ struct hsu_port_cfg *cfg = phsu->configs[up->index];
++
++ if (op == context_load) {
++ /*
++ * Delay a while before HW get stable. Without this the
++ * resume will just fail, as the value you write to the
++ * HW register will not be really written.
++ *
++ * This is only needed for Tangier, which really powers gate
++ * the HSU HW in runtime suspend. While in Penwell/CLV it is
++ * only clock gated.
++ */
++ usleep_range(500, 510);
++
++ if (cfg->hw_reset)
++ cfg->hw_reset(up->port.membase);
++
++ serial_out(up, UART_LCR, up->lcr);
++ serial_out(up, UART_LCR, up->lcr | UART_LCR_DLAB);
++ serial_out(up, UART_DLL, up->dll);
++ serial_out(up, UART_DLM, up->dlm);
++ serial_out(up, UART_LCR, up->lcr);
++
++ if (up->hw_type == hsu_intel) {
++ serial_out(up, UART_MUL, up->mul);
++ serial_out(up, UART_DIV, up->div);
++ serial_out(up, UART_PS, up->ps);
++ } else {
++ if (cfg->set_clk)
++ cfg->set_clk(up->m, up->n, up->port.membase);
++ }
++
++ serial_out(up, UART_MCR, up->mcr);
++ serial_out(up, UART_FCR, up->fcr);
++ serial_out(up, UART_IER, up->ier);
++ }
++
++ if (up->use_dma && up->dma_ops->context_op)
++ up->dma_ops->context_op(up, op);
++}
++
++int serial_hsu_do_suspend(struct uart_hsu_port *up)
++{
++ struct hsu_port_cfg *cfg = phsu->configs[up->index];
++ struct uart_port *uport = &up->port;
++ struct tty_port *tport = &uport->state->port;
++ struct tty_struct *tty = tport->tty;
++ struct circ_buf *xmit = &up->port.state->xmit;
++ char cmd;
++ unsigned long flags;
++
++ trace_hsu_func_start(up->index, __func__);
++
++ if (test_bit(flag_startup, &up->flags)) {
++ if (up->hw_type == hsu_intel &&
++ serial_in(up, UART_FOR) & 0x7F)
++ goto busy;
++ else if (up->hw_type == hsu_dw &&
++ serial_in(up, 0x7c / 4) & BIT(3))
++ goto busy;
++ }
++
++ if (up->use_dma) {
++ if (up->hw_type == hsu_intel) {
++ if (chan_readl(up->rxc, HSU_CH_D0SAR) >
++ up->rxbuf.dma_addr)
++ goto busy;
++ }
++ }
++
++ if (cfg->hw_set_rts)
++ cfg->hw_set_rts(up->index, 1);
++
++ disable_irq(up->port.irq);
++ disable_irq(up->dma_irq);
++
++ if (cfg->hw_set_rts)
++ usleep_range(up->byte_delay, up->byte_delay + 1);
++
++ serial_sched_stop(up);
++ set_bit(flag_suspend, &up->flags);
++
++ if (test_bit(flag_startup, &up->flags) && check_qcmd(up, &cmd)) {
++ dev_info(up->dev, "ignore suspend cmd: %d\n", cmd);
++ goto err;
++ }
++
++ if (test_bit(flag_tx_on, &up->flags)) {
++ dev_info(up->dev, "ignore suspend for tx on\n");
++ dev_info(up->dev,
++ "xmit pending:%d, stopped:%d, hw_stopped:%d, MSR:%x\n",
++ (int)uart_circ_chars_pending(xmit), tty->stopped,
++ tty->hw_stopped, serial_in(up, UART_MSR));
++ goto err;
++ }
++
++ if (test_bit(flag_startup, &up->flags) && !uart_circ_empty(xmit) &&
++ !uart_tx_stopped(&up->port)) {
++ dev_info(up->dev, "ignore suspend for xmit\n");
++ dev_info(up->dev,
++ "xmit pending:%d, stopped:%d, hw_stopped:%d, MSR:%x\n",
++ (int)uart_circ_chars_pending(xmit),
++ tty->stopped,
++ tty->hw_stopped,
++ serial_in(up, UART_MSR));
++ goto err;
++ }
++
++ if (up->use_dma) {
++ if (up->dma_ops->suspend(up))
++ goto err;
++ } else if (test_bit(flag_startup, &up->flags)) {
++ if (up->hw_type == hsu_intel &&
++ serial_in(up, UART_FOR) & 0x7F)
++ goto err;
++ else if (up->hw_type == hsu_dw &&
++ serial_in(up, 0x7c / 4) & BIT(3))
++ goto err;
++ }
++
++ if (cfg->hw_suspend)
++ cfg->hw_suspend(up->index, up->dev, wakeup_irq);
++ if (cfg->hw_context_save)
++ hsu_regs_context(up, context_save);
++ if (cfg->preamble && cfg->hw_suspend_post)
++ cfg->hw_suspend_post(up->index);
++ enable_irq(up->dma_irq);
++ if (up->hw_type == hsu_dw)
++ enable_irq(up->port.irq);
++
++ trace_hsu_func_end(up->index, __func__, "");
++ return 0;
++err:
++ if (cfg->hw_set_rts)
++ cfg->hw_set_rts(up->index, 0);
++ clear_bit(flag_suspend, &up->flags);
++ enable_irq(up->port.irq);
++ if (up->use_dma && up->hw_type == hsu_intel)
++ intel_dma_do_rx(up, 0);
++ enable_irq(up->dma_irq);
++ serial_sched_start(up);
++ spin_lock_irqsave(&up->port.lock, flags);
++ serial_sched_cmd(up, qcmd_get_msr);
++ spin_unlock_irqrestore(&up->port.lock, flags);
++ serial_sched_sync(up);
++busy:
++ pm_schedule_suspend(up->dev, cfg->idle);
++ trace_hsu_func_end(up->index, __func__, "busy");
++ return -EBUSY;
++}
++EXPORT_SYMBOL(serial_hsu_do_suspend);
++
++int serial_hsu_do_resume(struct uart_hsu_port *up)
++{
++ struct hsu_port_cfg *cfg = phsu->configs[up->index];
++ unsigned long flags;
++
++ trace_hsu_func_start(up->index, __func__);
++ if (!test_and_clear_bit(flag_suspend, &up->flags)) {
++ trace_hsu_func_end(up->index, __func__, "ignore");
++ return 0;
++ }
++ if (up->hw_type == hsu_dw)
++ disable_irq(up->port.irq);
++ if (cfg->hw_context_save)
++ hsu_regs_context(up, context_load);
++ if (cfg->hw_resume)
++ cfg->hw_resume(up->index, up->dev);
++ if (test_bit(flag_startup, &up->flags))
++ hsu_flush_rxfifo(up);
++ if (up->use_dma)
++ up->dma_ops->resume(up);
++ if (cfg->hw_set_rts)
++ cfg->hw_set_rts(up->index, 0);
++ enable_irq(up->port.irq);
++
++ serial_sched_start(up);
++ spin_lock_irqsave(&up->port.lock, flags);
++ serial_sched_cmd(up, qcmd_get_msr);
++ spin_unlock_irqrestore(&up->port.lock, flags);
++ serial_sched_sync(up);
++ trace_hsu_func_end(up->index, __func__, "");
++ return 0;
++}
++EXPORT_SYMBOL(serial_hsu_do_resume);
++#endif
++
++#ifdef CONFIG_PM_RUNTIME
++int serial_hsu_do_runtime_idle(struct uart_hsu_port *up)
++{
++ struct hsu_port_cfg *cfg = phsu->configs[up->index];
++
++ trace_hsu_func_start(up->index, __func__);
++ if (cfg->type == debug_port
++ && system_state == SYSTEM_BOOTING)
++ /* if HSU is set as default console, but earlyprintk is not hsu,
++ * then it will enter suspend and can not get back since system
++ * is on boot up, no contex switch to let it resume, here just
++ * postpone the suspend retry 30 seconds, then system should
++ * have finished booting
++ */
++ pm_schedule_suspend(up->dev, 30000);
++ else
++ pm_schedule_suspend(up->dev, cfg->idle);
++ trace_hsu_func_end(up->index, __func__, "");
++ return -EBUSY;
++}
++EXPORT_SYMBOL(serial_hsu_do_runtime_idle);
++#endif
++
++static void serial_hsu_command(struct uart_hsu_port *up)
++{
++ char cmd, c;
++ unsigned long flags;
++ unsigned int iir, lsr;
++ int status;
++ struct hsu_dma_chan *txc = up->txc;
++ struct hsu_dma_chan *rxc = up->rxc;
++ struct hsu_port_cfg *cfg = phsu->configs[up->index];
++
++ trace_hsu_func_start(up->index, __func__);
++ if (unlikely(test_bit(flag_cmd_off, &up->flags))) {
++ trace_hsu_func_end(up->index, __func__, "cmd_off");
++ return;
++ }
++ if (unlikely(test_bit(flag_suspend, &up->flags))) {
++ dev_err(up->dev,
++ "Error to handle cmd while port is suspended\n");
++ if (check_qcmd(up, &cmd))
++ dev_err(up->dev, "Command pending: %d\n", cmd);
++ trace_hsu_func_end(up->index, __func__, "suspend");
++ return;
++ }
++ set_bit(flag_active, &up->flags);
++ spin_lock_irqsave(&up->port.lock, flags);
++ while (get_qcmd(up, &cmd)) {
++ spin_unlock_irqrestore(&up->port.lock, flags);
++ trace_hsu_cmd_start(up->index, cmd);
++ switch (cmd) {
++ case qcmd_overflow:
++ dev_err(up->dev, "queue overflow!!\n");
++ break;
++ case qcmd_set_mcr:
++ serial_out(up, UART_MCR, up->mcr);
++ break;
++ case qcmd_set_ier:
++ serial_out(up, UART_IER, up->ier);
++ break;
++ case qcmd_start_rx:
++ /* use for DW DMA RX only */
++ if (test_and_clear_bit(flag_rx_pending, &up->flags)) {
++ if (up->use_dma)
++ up->dma_ops->start_rx(up);
++ }
++ break;
++ case qcmd_stop_rx:
++ if (!up->use_dma || up->hw_type == hsu_dw) {
++ up->ier &= ~UART_IER_RLSI;
++ up->port.read_status_mask &= ~UART_LSR_DR;
++ serial_out(up, UART_IER, up->ier);
++ }
++
++ if (up->use_dma)
++ up->dma_ops->stop_rx(up);
++ break;
++ case qcmd_start_tx:
++ if (up->use_dma) {
++ if (!test_bit(flag_tx_on, &up->flags))
++ up->dma_ops->start_tx(up);
++ } else if (!(up->ier & UART_IER_THRI)) {
++ up->ier |= UART_IER_THRI;
++ serial_out(up, UART_IER, up->ier);
++ }
++ break;
++ case qcmd_stop_tx:
++ if (up->use_dma) {
++ spin_lock_irqsave(&up->port.lock, flags);
++ up->dma_ops->stop_tx(up);
++ clear_bit(flag_tx_on, &up->flags);
++ spin_unlock_irqrestore(&up->port.lock, flags);
++ } else if (up->ier & UART_IER_THRI) {
++ up->ier &= ~UART_IER_THRI;
++ serial_out(up, UART_IER, up->ier);
++ }
++ break;
++ case qcmd_cl:
++ serial_out(up, UART_IER, 0);
++ while (cl_get_char(up, &c)) {
++ while (!wait_for_xmitr(up))
++ schedule();
++ serial_out(up, UART_TX, c);
++ }
++ serial_out(up, UART_IER, up->ier);
++ break;
++ case qcmd_port_irq:
++ up->port_irq_cmddone++;
++
++ /* Baytrail patform use shared IRQ and need more care */
++ if (up->hw_type == hsu_intel) {
++ iir = serial_in(up, UART_IIR);
++ } else {
++ if (up->iir & 0x1)
++ up->iir = serial_in(up, UART_IIR);
++ iir = up->iir;
++ up->iir = 1;
++ }
++
++ if (iir & UART_IIR_NO_INT) {
++ enable_irq(up->port.irq);
++ up->port_irq_pio_no_irq_pend++;
++ break;
++ }
++
++ if (iir & HSU_PIO_RX_ERR)
++ up->port_irq_pio_rx_err++;
++ if (iir & HSU_PIO_RX_AVB)
++ up->port_irq_pio_rx_avb++;
++ if (iir & HSU_PIO_RX_TMO)
++ up->port_irq_pio_rx_timeout++;
++ if (iir & HSU_PIO_TX_REQ)
++ up->port_irq_pio_tx_req++;
++
++ lsr = serial_in(up, UART_LSR);
++
++ /* We need to judge it's timeout or data available */
++ if (lsr & UART_LSR_DR) {
++ if (!up->use_dma) {
++ receive_chars(up, &lsr);
++ } else if (up->hw_type == hsu_dw) {
++ if ((iir & 0xf) == 0xc) {
++ /*
++ * RX timeout IRQ, the DMA
++ * channel may be stalled
++ */
++ up->dma_ops->stop_rx(up);
++ receive_chars(up, &lsr);
++ } else
++ up->dma_ops->start_rx(up);
++ }
++ }
++
++ /* lsr will be renewed during the receive_chars */
++ if (!up->use_dma && (lsr & UART_LSR_THRE))
++ transmit_chars(up);
++
++ spin_lock_irqsave(&up->port.lock, flags);
++ serial_sched_cmd(up, qcmd_enable_irq);
++ spin_unlock_irqrestore(&up->port.lock, flags);
++ break;
++ case qcmd_enable_irq:
++ enable_irq(up->port.irq);
++ break;
++ case qcmd_dma_irq:
++ /* Only hsu_intel has this irq */
++ up->dma_irq_cmddone++;
++ if (up->port_dma_sts & (1 << txc->id)) {
++ up->dma_tx_irq_cmddone++;
++ status = chan_readl(txc, HSU_CH_SR);
++ up->dma_ops->start_tx(up);
++ }
++
++ if (up->port_dma_sts & (1 << rxc->id)) {
++ status = chan_readl(rxc, HSU_CH_SR);
++ intel_dma_do_rx(up, status);
++ }
++ enable_irq(up->dma_irq);
++ break;
++ case qcmd_cmd_off:
++ set_bit(flag_cmd_off, &up->flags);
++ break;
++ case qcmd_get_msr:
++ break;
++ default:
++ dev_err(up->dev, "invalid command!!\n");
++ break;
++ }
++ trace_hsu_cmd_end(up->index, cmd);
++ spin_lock_irqsave(&up->port.lock, flags);
++ if (unlikely(test_bit(flag_cmd_off, &up->flags)))
++ break;
++ }
++ up->msr = serial_in(up, UART_MSR);
++ if (cfg->hw_ctrl_cts)
++ up->msr |= UART_MSR_CTS;
++ check_modem_status(up);
++ spin_unlock_irqrestore(&up->port.lock, flags);
++ trace_hsu_func_end(up->index, __func__, "");
++}
++
++static void serial_hsu_tasklet(unsigned long data)
++{
++ struct uart_hsu_port *up = (struct uart_hsu_port *)data;
++
++ up->in_tasklet = 1;
++ serial_hsu_command(up);
++ up->tasklet_done++;
++ up->in_tasklet = 0;
++}
++
++static void serial_hsu_work(struct work_struct *work)
++{
++ struct uart_hsu_port *uport =
++ container_of(work, struct uart_hsu_port, work);
++
++ uport->in_workq = 1;
++ serial_hsu_command(uport);
++ uport->workq_done++;
++ uport->in_workq = 0;
++}
++
++static int serial_port_setup(struct uart_hsu_port *up,
++ struct hsu_port_cfg *cfg)
++{
++ int ret;
++ int index = cfg->index;
++
++ phsu->configs[index] = cfg;
++ up->port.line = index;
++ snprintf(up->name, sizeof(up->name) - 1, "%s_p", cfg->name);
++ up->index = index;
++
++ if ((hsu_dma_enable & (1 << index)) && up->dma_ops)
++ up->use_dma = 1;
++ else
++ up->use_dma = 0;
++
++ if (cfg->hw_init)
++ cfg->hw_init(up->dev, index);
++ mutex_init(&up->q_mutex);
++ tasklet_init(&up->tasklet, serial_hsu_tasklet,
++ (unsigned long)up);
++ up->workqueue =
++ create_singlethread_workqueue(up->name);
++ INIT_WORK(&up->work, serial_hsu_work);
++ up->qcirc.buf = (char *)up->qbuf;
++ spin_lock_init(&up->cl_lock);
++ set_bit(flag_cmd_off, &up->flags);
++
++ if (cfg->type == debug_port) {
++ serial_hsu_reg.cons = SERIAL_HSU_CONSOLE;
++ if (serial_hsu_reg.cons)
++ serial_hsu_reg.cons->index = index;
++ } else
++ serial_hsu_reg.cons = NULL;
++
++ uart_add_one_port(&serial_hsu_reg, &up->port);
++
++ if (phsu->irq_port_and_dma) {
++ up->dma_irq = up->port.irq;
++ ret = request_irq(up->dma_irq, hsu_dma_irq, IRQF_SHARED,
++ "hsu dma", up);
++ if (ret) {
++ dev_err(up->dev, "can not get dma IRQ\n");
++ return ret;
++ }
++ ret = request_irq(up->port.irq, hsu_port_irq, IRQF_SHARED,
++ up->name, up);
++ if (ret) {
++ dev_err(up->dev, "can not get port IRQ\n");
++ return ret;
++ }
++ } else {
++ up->dma_irq = phsu->dma_irq;
++ ret = request_irq(up->port.irq, hsu_port_irq, IRQF_SHARED,
++ up->name, up);
++ if (ret) {
++ dev_err(up->dev, "can not get port IRQ\n");
++ return ret;
++ }
++ }
++
++ return 0;
++}
++
++struct uart_hsu_port *serial_hsu_port_setup(struct device *pdev, int port,
++ resource_size_t start, resource_size_t len, int irq)
++{
++ struct uart_hsu_port *up;
++ int index;
++ unsigned int uclk, clock;
++ struct hsu_port_cfg *cfg;
++
++ cfg = hsu_port_func_cfg + port;
++ if (!cfg)
++ return ERR_PTR(-EINVAL);
++
++ pr_info("Found a %s HSU\n", cfg->hw_ip ? "Designware" : "Intel");
++
++ index = cfg->index;
++ up = phsu->port + index;
++
++ up->dev = pdev;
++ up->port.type = PORT_MFD;
++ up->port.iotype = UPIO_MEM;
++ up->port.mapbase = start;
++ up->port.membase = ioremap_nocache(up->port.mapbase, len);
++ up->port.fifosize = 64;
++ up->port.ops = &serial_hsu_pops;
++ up->port.flags = UPF_IOREMAP;
++ up->hw_type = cfg->hw_ip;
++ /* calculate if DLAB=1, the ideal uartclk */
++ if (cfg->hw_get_clk)
++ clock = cfg->hw_get_clk();
++ else
++ clock = 50000;
++ uclk = clock * 1000 / (115200 * 16); /* 16 is default ps */
++ if (uclk >= 24)
++ uclk = 24;
++ else if (uclk >= 16)
++ uclk = 16;
++ else if (uclk >= 8)
++ uclk = 8;
++ else
++ uclk = 1;
++
++ if (up->hw_type == hsu_intel)
++ up->port.uartclk = 115200 * uclk * 16;
++ else
++ up->port.uartclk = 115200 * 32 * 16;
++
++ up->port.irq = irq;
++ up->port.dev = pdev;
++
++ if (up->hw_type == hsu_intel) {
++ up->txc = &phsu->chans[index * 2];
++ up->rxc = &phsu->chans[index * 2 + 1];
++ up->dma_ops = &intel_dma_ops;
++ } else {
++ up->dma_ops = pdw_dma_ops;
++ }
++
++ if (cfg->has_alt) {
++ struct hsu_port_cfg *alt_cfg =
++ hsu_port_func_cfg + cfg->alt;
++ struct uart_hsu_port *alt_up =
++ phsu->port + alt_cfg->index;
++
++ memcpy(alt_up, up, sizeof(*up));
++ serial_port_setup(alt_up, alt_cfg);
++ phsu->port_num++;
++ }
++
++ serial_port_setup(up, cfg);
++ phsu->port_num++;
++
++ return up;
++}
++EXPORT_SYMBOL(serial_hsu_port_setup);
++
++void serial_hsu_port_free(struct uart_hsu_port *up)
++{
++ struct hsu_port_cfg *cfg = phsu->configs[up->index];
++
++ uart_remove_one_port(&serial_hsu_reg, &up->port);
++ free_irq(up->port.irq, up);
++ if (cfg->has_alt) {
++ struct hsu_port_cfg *alt_cfg = phsu->configs[cfg->alt];
++ struct uart_hsu_port *alt_up =
++ phsu->port + alt_cfg->index;
++ uart_remove_one_port(&serial_hsu_reg, &alt_up->port);
++ free_irq(up->port.irq, alt_up);
++ }
++}
++EXPORT_SYMBOL(serial_hsu_port_free);
++
++void serial_hsu_port_shutdown(struct uart_hsu_port *up)
++{
++ uart_suspend_port(&serial_hsu_reg, &up->port);
++}
++EXPORT_SYMBOL(serial_hsu_port_shutdown);
++
++int serial_hsu_dma_setup(struct device *pdev,
++ resource_size_t start, resource_size_t len, unsigned int irq, int share)
++{
++ struct hsu_dma_chan *dchan;
++ int i, ret;
++
++ phsu->reg = ioremap_nocache(start, len);
++ dchan = phsu->chans;
++ for (i = 0; i < 6; i++) {
++ dchan->id = i;
++ dchan->dirt = (i & 0x1) ? DMA_FROM_DEVICE :
++ DMA_TO_DEVICE;
++ dchan->uport = &phsu->port[i/2];
++ dchan->reg = phsu->reg + HSU_DMA_CHANS_REG_OFFSET +
++ i * HSU_DMA_CHANS_REG_LENGTH;
++
++ dchan++;
++ }
++
++ /* will share irq with port if irq < 0 */
++ if (share)
++ phsu->irq_port_and_dma = 1;
++ else {
++ phsu->dma_irq = irq;
++ ret = request_irq(irq, hsu_dma_irq, 0, "hsu dma", phsu);
++ if (ret) {
++ dev_err(pdev, "can not get dma IRQ\n");
++ goto err;
++ }
++ }
++
++ dev_set_drvdata(pdev, phsu);
++
++ return 0;
++err:
++ iounmap(phsu->reg);
++ return ret;
++}
++EXPORT_SYMBOL(serial_hsu_dma_setup);
++
++void serial_hsu_dma_free(void)
++{
++ free_irq(phsu->dma_irq, phsu);
++}
++EXPORT_SYMBOL(serial_hsu_dma_free);
++
++static int __init hsu_init(void)
++{
++ int ret;
++
++ ret = uart_register_driver(&serial_hsu_reg);
++ if (ret)
++ return ret;
++
++ spin_lock_init(&phsu->dma_lock);
++ return hsu_debugfs_init(phsu);
++}
++
++static void __exit hsu_exit(void)
++{
++ uart_unregister_driver(&serial_hsu_reg);
++ hsu_debugfs_remove(phsu);
++}
++
++module_init(hsu_init);
++module_exit(hsu_exit);
++
++MODULE_AUTHOR("Yang Bin <bin.yang@intel.com>");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:medfield-hsu");
+diff --git a/drivers/tty/serial/mfd_dma.c b/drivers/tty/serial/mfd_dma.c
+new file mode 100644
+index 0000000..a9371fb
+--- /dev/null
++++ b/drivers/tty/serial/mfd_dma.c
+@@ -0,0 +1,753 @@
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/console.h>
++#include <linux/sysrq.h>
++#include <linux/slab.h>
++#include <linux/serial_reg.h>
++#include <linux/circ_buf.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/serial_core.h>
++#include <linux/serial_mfd.h>
++#include <linux/dma-mapping.h>
++#include <linux/pci.h>
++#include <linux/io.h>
++#include <linux/debugfs.h>
++#include <linux/pm_runtime.h>
++#include <linux/intel_mid_pm.h>
++#include <linux/intel_mid_dma.h>
++#include <linux/irq.h>
++#include <linux/acpi.h>
++#include <asm/intel_mid_hsu.h>
++#include <linux/intel_mid_pm.h>
++#include <linux/pm_qos.h>
++
++#include "mfd.h"
++
++static int dma_init_common(struct uart_hsu_port *up)
++{
++ struct hsu_dma_buffer *dbuf;
++ struct circ_buf *xmit = &up->port.state->xmit;
++
++ /* 1. Allocate the RX buffer */
++ dbuf = &up->rxbuf;
++ dbuf->buf = kzalloc(HSU_DMA_BUF_SIZE, GFP_KERNEL);
++ if (!dbuf->buf) {
++ up->use_dma = 0;
++ dev_err(up->dev, "allocate DMA buffer failed!!\n");
++ return -ENOMEM;
++ }
++
++ dbuf->dma_addr = dma_map_single(up->dev,
++ dbuf->buf,
++ HSU_DMA_BUF_SIZE,
++ DMA_FROM_DEVICE);
++ dbuf->dma_size = HSU_DMA_BUF_SIZE;
++
++ /* 2. prepare teh TX buffer */
++ dbuf = &up->txbuf;
++ dbuf->buf = xmit->buf;
++ dbuf->dma_addr = dma_map_single(up->dev,
++ dbuf->buf,
++ UART_XMIT_SIZE,
++ DMA_TO_DEVICE);
++ dbuf->dma_size = UART_XMIT_SIZE;
++ dbuf->ofs = 0;
++ return 0;
++}
++
++static void dma_exit_common(struct uart_hsu_port *up)
++{
++ struct hsu_dma_buffer *dbuf;
++ struct uart_port *port = &up->port;
++
++ /* Free and unmap rx dma buffer */
++ dbuf = &up->rxbuf;
++ dma_unmap_single(port->dev,
++ dbuf->dma_addr,
++ dbuf->dma_size,
++ DMA_FROM_DEVICE);
++ kfree(dbuf->buf);
++
++ /* Next unmap tx dma buffer*/
++ dbuf = &up->txbuf;
++ dma_unmap_single(port->dev,
++ dbuf->dma_addr,
++ dbuf->dma_size,
++ DMA_TO_DEVICE);
++}
++
++#ifdef CONFIG_INTEL_MID_DMAC
++static bool dw_dma_chan_filter(struct dma_chan *chan, void *param)
++{
++ struct dw_dma_priv *dw_dma = param;
++
++ if (dw_dma->dmac && (&dw_dma->dmac->dev == chan->device->dev))
++ return true;
++ else {
++#ifdef CONFIG_ACPI
++ acpi_handle handle = ACPI_HANDLE(chan->device->dev);
++ struct acpi_device *device;
++ int ret;
++ const char *hid;
++ ret = acpi_bus_get_device(handle, &device);
++ if (ret) {
++ pr_warn("DW HSU: no acpi entry\n");
++ return false;
++ }
++ hid = acpi_device_hid(device);
++ if (!strncmp(hid, "INTL9C60", strlen(hid))) {
++ acpi_status status;
++ unsigned long long tmp;
++ status = acpi_evaluate_integer(handle,
++ "_UID", NULL, &tmp);
++ if (!ACPI_FAILURE(status) && (tmp == 1))
++ return true;
++ }
++ if (!strncmp(hid, "80862286", strlen(hid))) {
++ return true;
++ }
++
++#endif
++ return false;
++ }
++}
++
++/* the RX/TX buffer init should be a common stuff */
++static int dw_dma_init(struct uart_hsu_port *up)
++{
++ struct dw_dma_priv *dw_dma;
++ struct intel_mid_dma_slave *rxs, *txs;
++ dma_cap_mask_t mask;
++ int ret = 0;
++
++ dw_dma = kzalloc(sizeof(*dw_dma), GFP_KERNEL);
++ if (!dw_dma) {
++ pr_warn("DW HSU: Can't alloc memory for dw_dm_priv\n");
++ return -1;
++ }
++
++ up->dma_priv = dw_dma;
++
++ /*
++ * Get pci device for DMA controller, currently it could only
++ * be the DMA controller of baytrail
++ */
++ dw_dma->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0f06, NULL);
++ if (!dw_dma->dmac) {
++ /* still have chance to get from ACPI dev */
++ pr_warn("DW HSU: Can't find LPIO1 DMA controller by PCI, try ACPI\n");
++ }
++
++ ret = dma_init_common(up);
++ if (ret)
++ return ret;
++
++ dma_cap_zero(mask);
++ dma_cap_set(DMA_SLAVE, mask);
++
++ /* 1. Init rx channel */
++ dw_dma->rxchan = dma_request_channel(mask, dw_dma_chan_filter, dw_dma);
++ if (!dw_dma->rxchan)
++ goto err_exit;
++ rxs = &dw_dma->rxs;
++ rxs->dma_slave.direction = DMA_FROM_DEVICE;
++ rxs->hs_mode = LNW_DMA_HW_HS;
++ rxs->cfg_mode = LNW_DMA_PER_TO_MEM;
++ rxs->dma_slave.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
++
++ /* These are fixed HW info from Baytrail datasheet */
++ if (up->index == 0)
++ rxs->device_instance = 3;
++ else
++ rxs->device_instance = 5;
++ dw_dma->rxchan->private = rxs;
++
++ /* 2. Init tx channel */
++ dw_dma->txchan = dma_request_channel(mask, dw_dma_chan_filter, dw_dma);
++ if (!dw_dma->txchan)
++ goto free_rxchan;
++
++ txs = &dw_dma->txs;
++ txs->dma_slave.direction = DMA_TO_DEVICE;
++ txs->hs_mode = LNW_DMA_HW_HS;
++ txs->cfg_mode = LNW_DMA_MEM_TO_PER;
++ txs->dma_slave.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
++ if (up->index == 0)
++ txs->device_instance = 2;
++ else
++ txs->device_instance = 4;
++ dw_dma->txchan->private = txs;
++
++ /* TX/RX reg share the same addr */
++ dw_dma->dma_addr = up->port.mapbase + UART_RX;
++
++ pm_qos_add_request(&up->qos, PM_QOS_CPU_DMA_LATENCY,
++ PM_QOS_DEFAULT_VALUE);
++
++ dw_dma->up = up;
++ up->dma_inited = 1;
++ return 0;
++
++free_rxchan:
++ dma_release_channel(dw_dma->rxchan);
++err_exit:
++ return -1;
++
++}
++
++static int dw_dma_suspend(struct uart_hsu_port *up)
++{
++ struct dw_dma_priv *dw_dma = up->dma_priv;
++ struct dma_chan *txchan;
++ struct dma_chan *rxchan;
++
++ if (!up->dma_inited)
++ return 0;
++
++ txchan = dw_dma->txchan;
++ rxchan = dw_dma->rxchan;
++
++ if (test_bit(flag_rx_on, &up->flags) ||
++ test_bit(flag_rx_pending, &up->flags)) {
++ dev_warn(up->dev, "ignore suspend for rx dma is running\n");
++ return -1;
++ }
++
++ txchan->device->device_control(txchan, DMA_TERMINATE_ALL, 0);
++ rxchan->device->device_control(rxchan, DMA_TERMINATE_ALL, 0);
++
++ txchan->device->device_control(txchan, DMA_PAUSE, 0);
++ rxchan->device->device_control(rxchan, DMA_PAUSE, 0);
++ pm_qos_update_request(&up->qos, PM_QOS_DEFAULT_VALUE);
++ return 0;
++}
++
++static int dw_dma_resume(struct uart_hsu_port *up)
++{
++ struct dw_dma_priv *dw_dma = up->dma_priv;
++ struct dma_chan *txchan;
++ struct dma_chan *rxchan;
++
++ if (!up->dma_inited)
++ return 0;
++
++ txchan = dw_dma->txchan;
++ rxchan = dw_dma->rxchan;
++
++ rxchan->device->device_control(rxchan, DMA_RESUME, 0);
++ txchan->device->device_control(txchan, DMA_RESUME, 0);
++ pm_qos_update_request(&up->qos, CSTATE_EXIT_LATENCY_C2);
++ return 0;
++}
++
++
++static int dw_dma_exit(struct uart_hsu_port *up)
++{
++ struct dw_dma_priv *dw_dma = up->dma_priv;
++ struct dma_chan *txchan = dw_dma->txchan;
++ struct dma_chan *rxchan = dw_dma->rxchan;
++
++ pm_qos_remove_request(&up->qos);
++ txchan->device->device_control(txchan, DMA_TERMINATE_ALL, 0);
++ rxchan->device->device_control(rxchan, DMA_TERMINATE_ALL, 0);
++ dma_release_channel(dw_dma->txchan);
++ dma_release_channel(dw_dma->rxchan);
++
++ dma_exit_common(up);
++
++ kfree(dw_dma);
++
++ up->dma_inited = 0;
++ up->dma_priv = NULL;
++ return 0;
++}
++
++static void dw_dma_tx_done(void *arg)
++{
++ struct dw_dma_priv *dw_dma = arg;
++ struct uart_hsu_port *up = dw_dma->up;
++ struct circ_buf *xmit = &up->port.state->xmit;
++ struct hsu_dma_buffer *dbuf = &up->txbuf;
++ unsigned long flags;
++ int count = 0;
++
++ count = intel_dma_get_src_addr(dw_dma->txchan) - dbuf->dma_addr
++ - xmit->tail;
++
++ /* Update the circ buf info */
++ xmit->tail += dbuf->ofs;
++ xmit->tail &= UART_XMIT_SIZE - 1;
++ up->port.icount.tx += dbuf->ofs;
++
++ dbuf->ofs = 0;
++
++ clear_bit(flag_tx_on, &up->flags);
++
++ if (!uart_circ_empty(xmit) && !uart_tx_stopped(&up->port)) {
++ spin_lock_irqsave(&up->port.lock, flags);
++ serial_sched_cmd(up, qcmd_start_tx);
++ spin_unlock_irqrestore(&up->port.lock, flags);
++ }
++
++ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
++ uart_write_wakeup(&up->port);
++}
++
++static void dw_dma_start_tx(struct uart_hsu_port *up)
++{
++ struct dw_dma_priv *dw_dma = up->dma_priv;
++ struct dma_async_tx_descriptor *txdesc = NULL;
++ struct dma_chan *txchan;
++ struct dma_slave_config *txconf;
++ struct hsu_dma_buffer *dbuf = &up->txbuf;
++ struct circ_buf *xmit = &up->port.state->xmit;
++ int count;
++ enum dma_ctrl_flags flag;
++
++ txchan = dw_dma->txchan;
++ txconf = &dw_dma->txs.dma_slave;
++
++ if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
++ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
++ uart_write_wakeup(&up->port);
++ return;
++ }
++
++ /*
++ * Need to check if FCR is set, better to be set only once when
++ * use_dma == 1
++ */
++
++ set_bit(flag_tx_on, &up->flags);
++ count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
++
++ if (count >= 2000)
++ count = 2000;
++
++ dbuf->ofs = count;
++
++
++ if (!count) {
++ pr_err("we see a case of TX Len == 0!!!\n\n");
++ dump_stack();
++ clear_bit(flag_tx_on, &up->flags);
++ return;
++ }
++
++ /* 2. Prepare the TX dma transfer */
++ txconf->direction = DMA_TO_DEVICE;
++ txconf->dst_addr = dw_dma->dma_addr;
++ txconf->src_maxburst = LNW_DMA_MSIZE_8;
++ txconf->dst_maxburst = LNW_DMA_MSIZE_8;
++ txconf->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
++ txconf->dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
++
++ txchan->device->device_control(txchan, DMA_SLAVE_CONFIG,
++ (unsigned long) txconf);
++
++ dma_sync_single_for_device(up->port.dev,
++ dbuf->dma_addr,
++ dbuf->dma_size,
++ DMA_TO_DEVICE);
++
++ flag = DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP | DMA_CTRL_ACK;
++
++ txdesc = txchan->device->device_prep_dma_memcpy(
++ txchan, /* DMA Channel */
++ dw_dma->dma_addr, /* DAR */
++ dbuf->dma_addr + xmit->tail, /* SAR */
++ count, /* Data len */
++ flag); /* Flag */
++ if (!txdesc) {
++ pr_warn("DW HSU: fail to prepare TX DMA operation\n");
++ return;
++ }
++
++ txdesc->callback = dw_dma_tx_done;
++ txdesc->callback_param = dw_dma;
++ txdesc->tx_submit(txdesc);
++}
++
++static void dw_dma_stop_tx(struct uart_hsu_port *up)
++{
++ struct dw_dma_priv *dw_dma = up->dma_priv;
++ struct dma_chan *txchan = dw_dma->txchan;
++ struct hsu_dma_buffer *dbuf = &up->txbuf;
++ int ret;
++ int count;
++
++ if (!test_bit(flag_tx_on, &up->flags))
++ return;
++
++ count = intel_dma_get_src_addr(dw_dma->txchan) - dbuf->dma_addr;
++
++ /* ? this may be sleepable */
++ ret = txchan->device->device_control(txchan, DMA_TERMINATE_ALL, 0);
++ if (ret)
++ dev_warn(up->dev, "Fail to stop DMA RX channel!\n");
++}
++
++static void dw_dma_rx_done(void *arg)
++{
++ struct dw_dma_priv *dw_dma = arg;
++ struct uart_hsu_port *up = dw_dma->up;
++ struct hsu_dma_buffer *dbuf = &up->rxbuf;
++ struct uart_port *port = &up->port;
++ struct tty_struct *tty;
++ struct tty_port *tport = &port->state->port;
++ int count;
++ unsigned long flags;
++
++ tty = tty_port_tty_get(&up->port.state->port);
++ if (!tty)
++ return;
++
++ dma_sync_single_for_cpu(port->dev, dbuf->dma_addr,
++ dbuf->dma_size, DMA_FROM_DEVICE);
++
++ count = dbuf->ofs;
++ tty_insert_flip_string(tport, dbuf->buf, count);
++ port->icount.rx += count;
++
++ /* Do we really need it for x86? */
++ dma_sync_single_for_device(up->port.dev, dbuf->dma_addr,
++ dbuf->dma_size, DMA_FROM_DEVICE);
++
++ tty_flip_buffer_push(tport);
++ tty_kref_put(tty);
++
++ clear_bit(flag_rx_on, &up->flags);
++
++ spin_lock_irqsave(&up->port.lock, flags);
++ if (test_bit(flag_rx_pending, &up->flags))
++ serial_sched_cmd(up, qcmd_start_rx);
++ spin_unlock_irqrestore(&up->port.lock, flags);
++
++}
++
++
++static void dw_dma_start_rx(struct uart_hsu_port *up)
++{
++ struct dma_async_tx_descriptor *rxdesc = NULL;
++ struct dw_dma_priv *dw_dma = up->dma_priv;
++ struct hsu_dma_buffer *dbuf = &up->rxbuf;
++ struct dma_chan *rxchan = dw_dma->rxchan;
++ struct dma_slave_config *rxconf = &dw_dma->rxs.dma_slave;
++ enum dma_ctrl_flags flag;
++
++ if (test_and_set_bit(flag_rx_on, &up->flags)) {
++ set_bit(flag_rx_pending, &up->flags);
++ return;
++ }
++
++ dbuf->ofs = 2048 - 64;
++
++ /* Prepare the RX dma transfer */
++ rxconf->direction = DMA_FROM_DEVICE;
++ rxconf->src_addr = dw_dma->dma_addr;
++ rxconf->dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
++ rxconf->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
++
++ /* feng: better to calculate a best size */
++ rxconf->src_maxburst = LNW_DMA_MSIZE_8;
++ rxconf->dst_maxburst = LNW_DMA_MSIZE_8;
++
++ rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG,
++ (unsigned long) rxconf);
++ flag = DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP | DMA_CTRL_ACK;
++ rxdesc = rxchan->device->device_prep_dma_memcpy(
++ rxchan, /* DMA chan */
++ dbuf->dma_addr, /* DAR */
++ dw_dma->dma_addr, /* SAR */
++ dbuf->ofs, /* data len */
++ flag);
++ if (!rxdesc) {
++ pr_warn("DW HSU: fail to prepare TX DMA operation\n");
++ return;
++ }
++
++ rxdesc->callback = dw_dma_rx_done;
++ rxdesc->callback_param = dw_dma;
++ rxdesc->tx_submit(rxdesc);
++}
++
++static void dw_dma_stop_rx(struct uart_hsu_port *up)
++{
++ struct dw_dma_priv *dw_dma = up->dma_priv;
++ struct hsu_dma_buffer *dbuf = &up->rxbuf;
++ struct dma_chan *rxchan = dw_dma->rxchan;
++ int count, ret;
++ struct uart_port *port = &up->port;
++ struct tty_struct *tty;
++ struct tty_port *tport = &port->state->port;
++
++ if (!test_bit(flag_rx_on, &up->flags)) {
++ clear_bit(flag_rx_pending, &up->flags);
++ return;
++ }
++
++ ret = rxchan->device->device_control(rxchan, DMA_TERMINATE_ALL, 0);
++ if (ret) {
++ WARN(1, "DMA TERMINATE of TX returns error\n");
++ return;
++ }
++
++ tty = tty_port_tty_get(&up->port.state->port);
++ if (!tty)
++ return;
++
++ count = intel_dma_get_dst_addr(rxchan) - dbuf->dma_addr;
++ if (!count)
++ goto exit;
++
++ dma_sync_single_for_cpu(port->dev, dbuf->dma_addr,
++ dbuf->dma_size, DMA_FROM_DEVICE);
++
++ tty_insert_flip_string(tport, dbuf->buf, count);
++ port->icount.rx += count;
++
++ /* Do we really need it for x86? */
++ dma_sync_single_for_device(up->port.dev, dbuf->dma_addr,
++ dbuf->dma_size, DMA_FROM_DEVICE);
++
++ tty_flip_buffer_push(tport);
++
++exit:
++ tty_kref_put(tty);
++ clear_bit(flag_rx_on, &up->flags);
++ clear_bit(flag_rx_pending, &up->flags);
++}
++
++struct hsu_dma_ops dw_dma_ops = {
++ .init = dw_dma_init,
++ .exit = dw_dma_exit,
++ .suspend = dw_dma_suspend,
++ .resume = dw_dma_resume,
++ .start_tx = dw_dma_start_tx,
++ .stop_tx = dw_dma_stop_tx,
++ .start_rx = dw_dma_start_rx,
++ .stop_rx = dw_dma_stop_rx,
++};
++
++struct hsu_dma_ops *pdw_dma_ops = &dw_dma_ops;
++
++#else
++struct hsu_dma_ops *pdw_dma_ops = NULL;
++#endif
++
++/* Intel DMA ops */
++
++/* The buffer is already cache coherent */
++void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc,
++ struct hsu_dma_buffer *dbuf)
++{
++ dbuf->ofs = 0;
++
++ chan_writel(rxc, HSU_CH_BSR, HSU_DMA_BSR);
++ chan_writel(rxc, HSU_CH_MOTSR, HSU_DMA_MOTSR);
++
++ chan_writel(rxc, HSU_CH_D0SAR, dbuf->dma_addr);
++ chan_writel(rxc, HSU_CH_D0TSR, dbuf->dma_size);
++ chan_writel(rxc, HSU_CH_DCR, 0x1 | (0x1 << 8)
++ | (0x1 << 16)
++ | (0x1 << 24) /* timeout, Errata 1 */
++ );
++ chan_writel(rxc, HSU_CH_CR, 0x3);
++}
++
++static int intel_dma_init(struct uart_hsu_port *up)
++{
++ int ret;
++
++ clear_bit(flag_tx_on, &up->flags);
++
++ ret = dma_init_common(up);
++ if (ret)
++ return ret;
++
++ /* This should not be changed all around */
++ chan_writel(up->txc, HSU_CH_BSR, HSU_DMA_BSR);
++ chan_writel(up->txc, HSU_CH_MOTSR, HSU_DMA_MOTSR);
++
++ /* Start the RX channel right now */
++ hsu_dma_start_rx_chan(up->rxc, &up->rxbuf);
++
++ up->dma_inited = 1;
++ return 0;
++}
++
++static int intel_dma_exit(struct uart_hsu_port *up)
++{
++ chan_writel(up->txc, HSU_CH_CR, 0x0);
++ clear_bit(flag_tx_on, &up->flags);
++ chan_writel(up->rxc, HSU_CH_CR, 0x2);
++ dma_exit_common(up);
++
++ up->dma_inited = 0;
++ return 0;
++}
++
++
++static void intel_dma_start_tx(struct uart_hsu_port *up)
++{
++ struct circ_buf *xmit = &up->port.state->xmit;
++ struct hsu_dma_buffer *dbuf = &up->txbuf;
++ unsigned long flags;
++ int count;
++
++ spin_lock_irqsave(&up->port.lock, flags);
++ chan_writel(up->txc, HSU_CH_CR, 0x0);
++ while (chan_readl(up->txc, HSU_CH_CR))
++ cpu_relax();
++ clear_bit(flag_tx_on, &up->flags);
++ if (dbuf->ofs) {
++ u32 real = chan_readl(up->txc, HSU_CH_D0SAR) - up->tx_addr;
++
++ /* we found in flow control case, TX irq came without sending
++ * all TX buffer
++ */
++ if (real < dbuf->ofs)
++ dbuf->ofs = real; /* adjust to real chars sent */
++
++ /* Update the circ buf info */
++ xmit->tail += dbuf->ofs;
++ xmit->tail &= UART_XMIT_SIZE - 1;
++
++ up->port.icount.tx += dbuf->ofs;
++ dbuf->ofs = 0;
++ }
++
++ if (!uart_circ_empty(xmit) && !uart_tx_stopped(&up->port)) {
++ set_bit(flag_tx_on, &up->flags);
++ dma_sync_single_for_device(up->port.dev,
++ dbuf->dma_addr,
++ dbuf->dma_size,
++ DMA_TO_DEVICE);
++
++ count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
++ dbuf->ofs = count;
++
++ /* Reprogram the channel */
++ up->tx_addr = dbuf->dma_addr + xmit->tail;
++ chan_writel(up->txc, HSU_CH_D0SAR, up->tx_addr);
++ chan_writel(up->txc, HSU_CH_D0TSR, count);
++
++ /* Reenable the channel */
++ chan_writel(up->txc, HSU_CH_DCR, 0x1
++ | (0x1 << 8)
++ | (0x1 << 16));
++ chan_writel(up->txc, HSU_CH_CR, 0x1);
++ }
++
++ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
++ uart_write_wakeup(&up->port);
++
++ spin_unlock_irqrestore(&up->port.lock, flags);
++ return;
++}
++
++static void intel_dma_stop_tx(struct uart_hsu_port *up)
++{
++ chan_writel(up->txc, HSU_CH_CR, 0x0);
++ return;
++}
++
++static void intel_dma_start_rx(struct uart_hsu_port *up)
++{
++ return;
++}
++
++static void intel_dma_stop_rx(struct uart_hsu_port *up)
++{
++ chan_writel(up->rxc, HSU_CH_CR, 0x2);
++ return;
++}
++
++static void intel_dma_context_op(struct uart_hsu_port *up, int op)
++{
++ if (op == context_save) {
++ up->txc->cr = chan_readl(up->txc, HSU_CH_CR);
++ up->txc->dcr = chan_readl(up->txc, HSU_CH_DCR);
++ up->txc->sar = chan_readl(up->txc, HSU_CH_D0SAR);
++ up->txc->tsr = chan_readl(up->txc, HSU_CH_D0TSR);
++
++ up->rxc->cr = chan_readl(up->rxc, HSU_CH_CR);
++ up->rxc->dcr = chan_readl(up->rxc, HSU_CH_DCR);
++ up->rxc->sar = chan_readl(up->rxc, HSU_CH_D0SAR);
++ up->rxc->tsr = chan_readl(up->rxc, HSU_CH_D0TSR);
++ } else {
++ chan_writel(up->txc, HSU_CH_DCR, up->txc->dcr);
++ chan_writel(up->txc, HSU_CH_D0SAR, up->txc->sar);
++ chan_writel(up->txc, HSU_CH_D0TSR, up->txc->tsr);
++ chan_writel(up->txc, HSU_CH_BSR, HSU_DMA_BSR);
++ chan_writel(up->txc, HSU_CH_MOTSR, HSU_DMA_MOTSR);
++
++ chan_writel(up->rxc, HSU_CH_DCR, up->rxc->dcr);
++ chan_writel(up->rxc, HSU_CH_D0SAR, up->rxc->sar);
++ chan_writel(up->rxc, HSU_CH_D0TSR, up->rxc->tsr);
++ chan_writel(up->rxc, HSU_CH_BSR, HSU_DMA_BSR);
++ chan_writel(up->rxc, HSU_CH_MOTSR, HSU_DMA_MOTSR);
++ }
++}
++
++
++static int intel_dma_resume(struct uart_hsu_port *up)
++{
++ chan_writel(up->rxc, HSU_CH_CR, up->rxc_chcr_save);
++ return 0;
++}
++
++static int intel_dma_suspend(struct uart_hsu_port *up)
++{
++ int loop = 100000;
++ struct hsu_dma_chan *chan = up->rxc;
++
++ up->rxc_chcr_save = chan_readl(up->rxc, HSU_CH_CR);
++
++ if (test_bit(flag_startup, &up->flags)
++ && serial_in(up, UART_FOR) & 0x7F) {
++ dev_err(up->dev, "ignore suspend for rx fifo\n");
++ return -1;
++ }
++
++ if (chan_readl(up->txc, HSU_CH_CR)) {
++ dev_info(up->dev, "ignore suspend for tx dma\n");
++ return -1;
++ }
++
++ chan_writel(up->rxc, HSU_CH_CR, 0x2);
++ while (--loop) {
++ if (chan_readl(up->rxc, HSU_CH_CR) == 0x2)
++ break;
++ cpu_relax();
++ }
++
++ if (!loop) {
++ dev_err(up->dev, "Can't stop rx dma\n");
++ return -1;
++ }
++
++ if (chan_readl(chan, HSU_CH_D0SAR) - up->rxbuf.dma_addr) {
++ dev_err(up->dev, "ignore suspend for dma pointer\n");
++ return -1;
++ }
++
++ return 0;
++}
++
++struct hsu_dma_ops intel_dma_ops = {
++ .init = intel_dma_init,
++ .exit = intel_dma_exit,
++ .suspend = intel_dma_suspend,
++ .resume = intel_dma_resume,
++ .start_tx = intel_dma_start_tx,
++ .stop_tx = intel_dma_stop_tx,
++ .start_rx = intel_dma_start_rx,
++ .stop_rx = intel_dma_stop_rx,
++ .context_op = intel_dma_context_op,
++};
++
++
+diff --git a/drivers/tty/serial/mfd_pci.c b/drivers/tty/serial/mfd_pci.c
+new file mode 100644
+index 0000000..66c7138
+--- /dev/null
++++ b/drivers/tty/serial/mfd_pci.c
+@@ -0,0 +1,298 @@
++/*
++ * mfd_pci.c: driver for High Speed UART device of Intel Medfield platform
++ *
++ * Refer pxa.c, 8250.c and some other drivers in drivers/serial/
++ *
++ * (C) Copyright 2010 Intel Corporation
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++/* Notes:
++ * 1. DMA channel allocation: 0/1 channel are assigned to port 0,
++ * 2/3 chan to port 1, 4/5 chan to port 3. Even number chans
++ * are used for RX, odd chans for TX
++ *
++ * 2. The RI/DSR/DCD/DTR are not pinned out, DCD & DSR are always
++ * asserted, only when the HW is reset the DDCD and DDSR will
++ * be triggered
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <linux/io.h>
++#include <linux/pm_runtime.h>
++#include <linux/intel_mid_pm.h>
++#include <linux/pm_qos.h>
++
++#include "mfd.h"
++
++#ifdef CONFIG_PM
++static int serial_hsu_pci_suspend(struct device *dev)
++{
++ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
++ struct uart_hsu_port *up = pci_get_drvdata(pdev);
++ int ret = 0;
++
++ if (up) {
++ trace_hsu_func_start(up->index, __func__);
++ ret = serial_hsu_do_suspend(up);
++ trace_hsu_func_end(up->index, __func__, "");
++ }
++ return ret;
++}
++
++static int serial_hsu_pci_resume(struct device *dev)
++{
++ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
++ struct uart_hsu_port *up = pci_get_drvdata(pdev);
++ int ret = 0;
++
++ if (up) {
++ trace_hsu_func_start(up->index, __func__);
++ ret = serial_hsu_do_resume(up);
++ trace_hsu_func_end(up->index, __func__, "");
++ }
++ return ret;
++}
++#else
++#define serial_hsu_pci_suspend NULL
++#define serial_hsu_pci_resume NULL
++#endif
++
++#ifdef CONFIG_PM_RUNTIME
++static int serial_hsu_pci_runtime_idle(struct device *dev)
++{
++ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
++ struct uart_hsu_port *up = pci_get_drvdata(pdev);
++
++ return serial_hsu_do_runtime_idle(up);
++}
++
++static int serial_hsu_pci_runtime_suspend(struct device *dev)
++{
++ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
++ struct uart_hsu_port *up = pci_get_drvdata(pdev);
++ int ret = 0;
++
++ trace_hsu_func_start(up->index, __func__);
++ ret = serial_hsu_do_suspend(up);
++ trace_hsu_func_end(up->index, __func__, "");
++ return ret;
++}
++
++static int serial_hsu_pci_runtime_resume(struct device *dev)
++{
++ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
++ struct uart_hsu_port *up = pci_get_drvdata(pdev);
++ int ret = 0;
++
++ trace_hsu_func_start(up->index, __func__);
++ ret = serial_hsu_do_resume(up);
++ trace_hsu_func_end(up->index, __func__, "");
++ return ret;
++}
++#else
++#define serial_hsu_pci_runtime_idle NULL
++#define serial_hsu_pci_runtime_suspend NULL
++#define serial_hsu_pci_runtime_resume NULL
++#endif
++
++static const struct dev_pm_ops serial_hsu_pci_pm_ops = {
++
++ SET_SYSTEM_SLEEP_PM_OPS(serial_hsu_pci_suspend,
++ serial_hsu_pci_resume)
++ SET_RUNTIME_PM_OPS(serial_hsu_pci_runtime_suspend,
++ serial_hsu_pci_runtime_resume,
++ serial_hsu_pci_runtime_idle)
++};
++
++DEFINE_PCI_DEVICE_TABLE(hsuart_port_pci_ids) = {
++ { PCI_VDEVICE(INTEL, 0x081B), hsu_port0 },
++ { PCI_VDEVICE(INTEL, 0x081C), hsu_port1 },
++ { PCI_VDEVICE(INTEL, 0x081D), hsu_port2 },
++ /* Cloverview support */
++ { PCI_VDEVICE(INTEL, 0x08FC), hsu_port0 },
++ { PCI_VDEVICE(INTEL, 0x08FD), hsu_port1 },
++ { PCI_VDEVICE(INTEL, 0x08FE), hsu_port2 },
++ /* Tangier support */
++ { PCI_VDEVICE(INTEL, 0x1191), hsu_port0 },
++ /* VLV2 support */
++ { PCI_VDEVICE(INTEL, 0x0F0A), hsu_port0 },
++ { PCI_VDEVICE(INTEL, 0x0F0C), hsu_port1 },
++ /* CHV support */
++ { PCI_VDEVICE(INTEL, 0x228A), hsu_port0 },
++ { PCI_VDEVICE(INTEL, 0x228C), hsu_port1 },
++ {},
++};
++
++DEFINE_PCI_DEVICE_TABLE(hsuart_dma_pci_ids) = {
++ { PCI_VDEVICE(INTEL, 0x081E), hsu_dma },
++ /* Cloverview support */
++ { PCI_VDEVICE(INTEL, 0x08FF), hsu_dma },
++ /* Tangier support */
++ { PCI_VDEVICE(INTEL, 0x1192), hsu_dma },
++ {},
++};
++
++static int serial_hsu_pci_port_probe(struct pci_dev *pdev,
++ const struct pci_device_id *ent)
++{
++ struct uart_hsu_port *up;
++ int ret, port, hw_type;
++ resource_size_t start, len;
++
++ start = pci_resource_start(pdev, 0);
++ len = pci_resource_len(pdev, 0);
++
++ dev_info(&pdev->dev,
++ "FUNC: %d driver: %ld addr:%lx len:%lx\n",
++ PCI_FUNC(pdev->devfn), ent->driver_data,
++ (unsigned long) start, (unsigned long) len);
++
++ port = intel_mid_hsu_func_to_port(PCI_FUNC(pdev->devfn));
++ if (port == -1)
++ return 0;
++
++ ret = pci_enable_device(pdev);
++ if (ret)
++ return ret;
++
++ ret = pci_request_region(pdev, 0, "hsu");
++ if (ret)
++ goto err;
++
++ up = serial_hsu_port_setup(&pdev->dev, port, start, len,
++ pdev->irq);
++ if (IS_ERR(up))
++ goto err;
++
++ pci_set_drvdata(pdev, up);
++
++ pm_runtime_put_noidle(&pdev->dev);
++ pm_runtime_forbid(&pdev->dev);
++ return 0;
++err:
++ pci_disable_device(pdev);
++ return ret;
++}
++
++static void serial_hsu_pci_port_remove(struct pci_dev *pdev)
++{
++ struct uart_hsu_port *up = pci_get_drvdata(pdev);
++
++ pm_runtime_forbid(&pdev->dev);
++ pm_runtime_get_noresume(&pdev->dev);
++ serial_hsu_port_free(up);
++ pci_set_drvdata(pdev, NULL);
++ pci_disable_device(pdev);
++}
++
++static void serial_hsu_pci_port_shutdown(struct pci_dev *pdev)
++{
++ struct uart_hsu_port *up = pci_get_drvdata(pdev);
++
++ if (!up)
++ return;
++
++ serial_hsu_port_shutdown(up);
++}
++
++static struct pci_driver hsu_port_pci_driver = {
++ .name = "HSU serial",
++ .id_table = hsuart_port_pci_ids,
++ .probe = serial_hsu_pci_port_probe,
++ .remove = serial_hsu_pci_port_remove,
++ .shutdown = serial_hsu_pci_port_shutdown,
++/* Disable PM only when kgdb(poll mode uart) is enabled */
++#if defined(CONFIG_PM) && !defined(CONFIG_CONSOLE_POLL)
++ .driver = {
++ .pm = &serial_hsu_pci_pm_ops,
++ },
++#endif
++};
++
++static int serial_hsu_pci_dma_probe(struct pci_dev *pdev,
++ const struct pci_device_id *ent)
++{
++ struct hsu_dma_chan *dchan;
++ int ret, share_irq = 0;
++ resource_size_t start, len;
++
++ start = pci_resource_start(pdev, 0);
++ len = pci_resource_len(pdev, 0);
++
++ dev_info(&pdev->dev,
++ "FUNC: %d driver: %ld addr:%lx len:%lx\n",
++ PCI_FUNC(pdev->devfn), ent->driver_data,
++ (unsigned long) pci_resource_start(pdev, 0),
++ (unsigned long) pci_resource_len(pdev, 0));
++
++ ret = pci_enable_device(pdev);
++ if (ret)
++ return ret;
++
++ ret = pci_request_region(pdev, 0, "hsu dma");
++ if (ret)
++ goto err;
++
++ /* share irq with port? ANN all and TNG chip from B0 stepping */
++ if ((intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER &&
++ pdev->revision >= 0x1) ||
++ intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_ANNIEDALE)
++ share_irq = 1;
++
++ ret = serial_hsu_dma_setup(&pdev->dev, start, len, pdev->irq, share_irq);
++ if (ret)
++ goto err;
++
++ return 0;
++err:
++ pci_disable_device(pdev);
++ return ret;
++}
++
++static void serial_hsu_pci_dma_remove(struct pci_dev *pdev)
++{
++ serial_hsu_dma_free();
++ pci_disable_device(pdev);
++ pci_unregister_driver(&hsu_port_pci_driver);
++}
++
++static struct pci_driver hsu_dma_pci_driver = {
++ .name = "HSU DMA",
++ .id_table = hsuart_dma_pci_ids,
++ .probe = serial_hsu_pci_dma_probe,
++ .remove = serial_hsu_pci_dma_remove,
++};
++
++static int __init hsu_pci_init(void)
++{
++ int ret;
++
++ ret = pci_register_driver(&hsu_dma_pci_driver);
++ if (!ret) {
++ ret = pci_register_driver(&hsu_port_pci_driver);
++ if (ret)
++ pci_unregister_driver(&hsu_dma_pci_driver);
++ }
++
++ return ret;
++}
++
++static void __exit hsu_pci_exit(void)
++{
++ pci_unregister_driver(&hsu_port_pci_driver);
++ pci_unregister_driver(&hsu_dma_pci_driver);
++}
++
++module_init(hsu_pci_init);
++module_exit(hsu_pci_exit);
++
++MODULE_AUTHOR("Yang Bin <bin.yang@intel.com>");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:medfield-hsu");
+diff --git a/drivers/tty/serial/mfd_plat.c b/drivers/tty/serial/mfd_plat.c
+new file mode 100644
+index 0000000..261acd5
+--- /dev/null
++++ b/drivers/tty/serial/mfd_plat.c
+@@ -0,0 +1,244 @@
++/*
++ * mfd_plat.c: driver for High Speed UART device of Intel Medfield platform
++ *
++ * (C) Copyright 2013 Intel Corporation
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/pm_runtime.h>
++#include <linux/acpi.h>
++#include <linux/intel_mid_pm.h>
++#include <linux/pm_qos.h>
++#include <linux/pci.h>
++
++#include "mfd.h"
++
++#ifdef CONFIG_ACPI
++static const struct acpi_device_id hsu_acpi_ids[] = {
++ { "80860F0A", 0 },
++ { "8086228A", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(acpi, hsu_acpi_ids);
++#endif
++
++#ifdef CONFIG_PM
++static int serial_hsu_plat_suspend(struct device *dev)
++{
++ struct uart_hsu_port *up = dev_get_drvdata(dev);
++ int ret = 0;
++
++ if (up) {
++ trace_hsu_func_start(up->index, __func__);
++ ret = serial_hsu_do_suspend(up);
++ trace_hsu_func_end(up->index, __func__, "");
++ }
++ return ret;
++}
++
++static int serial_hsu_plat_resume(struct device *dev)
++{
++ struct uart_hsu_port *up = dev_get_drvdata(dev);
++ int ret = 0;
++
++ if (up) {
++ trace_hsu_func_start(up->index, __func__);
++ ret = serial_hsu_do_resume(up);
++ trace_hsu_func_end(up->index, __func__, "");
++ }
++ return ret;
++}
++#else
++#define serial_hsu_plat_suspend NULL
++#define serial_hsu_plat_resume NULL
++#endif
++
++#ifdef CONFIG_PM_RUNTIME
++static int serial_hsu_plat_runtime_idle(struct device *dev)
++{
++ struct uart_hsu_port *up = dev_get_drvdata(dev);
++
++ return serial_hsu_do_runtime_idle(up);
++}
++
++static int serial_hsu_plat_runtime_suspend(struct device *dev)
++{
++ struct uart_hsu_port *up = dev_get_drvdata(dev);
++ int ret = 0;
++
++ trace_hsu_func_start(up->index, __func__);
++ ret = serial_hsu_do_suspend(up);
++ trace_hsu_func_end(up->index, __func__, "");
++ return ret;
++}
++
++static int serial_hsu_plat_runtime_resume(struct device *dev)
++{
++ struct uart_hsu_port *up = dev_get_drvdata(dev);
++ int ret = 0;
++
++ trace_hsu_func_start(up->index, __func__);
++ ret = serial_hsu_do_resume(up);
++ trace_hsu_func_end(up->index, __func__, "");
++ return ret;
++}
++#else
++#define serial_hsu_plat_runtime_idle NULL
++#define serial_hsu_plat_runtime_suspend NULL
++#define serial_hsu_plat_runtime_resume NULL
++#endif
++
++static const struct dev_pm_ops serial_hsu_plat_pm_ops = {
++
++ SET_SYSTEM_SLEEP_PM_OPS(serial_hsu_plat_suspend,
++ serial_hsu_plat_resume)
++ SET_RUNTIME_PM_OPS(serial_hsu_plat_runtime_suspend,
++ serial_hsu_plat_runtime_resume,
++ serial_hsu_plat_runtime_idle)
++};
++
++static int serial_hsu_plat_port_probe(struct platform_device *pdev)
++{
++ struct uart_hsu_port *up;
++ int port = pdev->id, irq;
++ struct resource *mem, *ioarea;
++ const struct acpi_device_id *id;
++ resource_size_t start, len;
++
++#ifdef CONFIG_ACPI
++ for (id = hsu_acpi_ids; id->id[0]; id++)
++ if (!strncmp(id->id, dev_name(&pdev->dev), strlen(id->id))) {
++ acpi_status status;
++ unsigned long long tmp;
++
++ status = acpi_evaluate_integer(ACPI_HANDLE(&pdev->dev),
++ "_UID", NULL, &tmp);
++ if (ACPI_FAILURE(status))
++ return -ENODEV;
++ port = tmp - 1;
++ }
++#endif
++
++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!mem) {
++ dev_err(&pdev->dev, "no mem resource?\n");
++ return -EINVAL;
++ }
++ start = mem->start;
++ len = resource_size(mem);
++
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0) {
++ dev_err(&pdev->dev, "no irq resource?\n");
++ return irq; /* -ENXIO */
++ }
++
++ ioarea = request_mem_region(mem->start, resource_size(mem),
++ pdev->name);
++ if (!ioarea) {
++ dev_err(&pdev->dev, "HSU region already claimed\n");
++ return -EBUSY;
++ }
++
++ up = serial_hsu_port_setup(&pdev->dev, port, start, len,
++ irq);
++ if (IS_ERR(up)) {
++ release_mem_region(mem->start, resource_size(mem));
++ dev_err(&pdev->dev, "failed to setup HSU\n");
++ return -EINVAL;
++ }
++
++ platform_set_drvdata(pdev, up);
++
++ if (!pdev->dev.dma_mask) {
++ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
++ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
++ }
++ dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
++
++ pm_runtime_set_active(&pdev->dev);
++ pm_runtime_enable(&pdev->dev);
++ pm_runtime_allow(&pdev->dev);
++
++ return 0;
++}
++
++static int serial_hsu_plat_port_remove(struct platform_device *pdev)
++{
++ struct uart_hsu_port *up = platform_get_drvdata(pdev);
++ struct resource *mem;
++
++ pm_runtime_forbid(&pdev->dev);
++ serial_hsu_port_free(up);
++ platform_set_drvdata(pdev, NULL);
++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (mem)
++ release_mem_region(mem->start, resource_size(mem));
++
++ return 0;
++}
++
++static void serial_hsu_plat_port_shutdown(struct platform_device *pdev)
++{
++ struct uart_hsu_port *up = platform_get_drvdata(pdev);
++
++ if (!up)
++ return;
++
++ serial_hsu_port_shutdown(up);
++}
++
++static struct platform_driver hsu_plat_driver = {
++ .remove = serial_hsu_plat_port_remove,
++ .shutdown = serial_hsu_plat_port_shutdown,
++ .driver = {
++ .name = "HSU serial",
++ .owner = THIS_MODULE,
++/* Disable PM only when kgdb(poll mode uart) is enabled */
++#if defined(CONFIG_PM) && !defined(CONFIG_CONSOLE_POLL)
++ .pm = &serial_hsu_plat_pm_ops,
++#endif
++#ifdef CONFIG_ACPI
++ .acpi_match_table = ACPI_PTR(hsu_acpi_ids),
++#endif
++ },
++};
++
++static int __init hsu_plat_init(void)
++{
++ struct pci_dev *hsu_pci;
++
++ /*
++ * Try to get pci device, if exist, then exit ACPI platform
++ * register, On BYT FDK, include two enum mode: PCI, ACPI,
++ * ignore ACPI enum mode.
++ */
++ hsu_pci = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0F0A, NULL);
++ if (hsu_pci) {
++ pr_info("HSU serial: Find HSU controller in PCI device, "
++ "exit ACPI platform register!\n");
++ return 0;
++ }
++
++ return platform_driver_probe(&hsu_plat_driver, serial_hsu_plat_port_probe);
++}
++
++static void __exit hsu_plat_exit(void)
++{
++ platform_driver_unregister(&hsu_plat_driver);
++}
++
++module_init(hsu_plat_init);
++module_exit(hsu_plat_exit);
++
++MODULE_AUTHOR("Jason Chen <jason.cj.chen@intel.com>");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:medfield-hsu-plat");
+diff --git a/drivers/tty/serial/mfd_trace.h b/drivers/tty/serial/mfd_trace.h
+new file mode 100644
+index 0000000..49afd9b
+--- /dev/null
++++ b/drivers/tty/serial/mfd_trace.h
+@@ -0,0 +1,197 @@
++#undef TRACE_INCLUDE_PATH
++#undef TRACE_INCLUDE_FILE
++#define TRACE_INCLUDE_PATH .
++#define TRACE_INCLUDE_FILE mfd_trace
++
++#define TRACE_SYSTEM hsu
++
++#if !defined(_TRACE_HSU_H) || defined(TRACE_HEADER_MULTI_READ)
++#define _TRACE_HSU_H
++
++#include <linux/tracepoint.h>
++
++#define hsucmd_name(cmd) { cmd, #cmd }
++#define show_hsucmd_name(val) \
++ __print_symbolic(val, \
++ hsucmd_name(qcmd_overflow), \
++ hsucmd_name(qcmd_get_msr), \
++ hsucmd_name(qcmd_set_mcr), \
++ hsucmd_name(qcmd_set_ier), \
++ hsucmd_name(qcmd_start_rx), \
++ hsucmd_name(qcmd_stop_rx), \
++ hsucmd_name(qcmd_start_tx), \
++ hsucmd_name(qcmd_stop_tx), \
++ hsucmd_name(qcmd_cl), \
++ hsucmd_name(qcmd_port_irq), \
++ hsucmd_name(qcmd_dma_irq), \
++ hsucmd_name(qcmd_enable_irq), \
++ hsucmd_name(qcmd_cmd_off))
++
++
++TRACE_EVENT(hsu_cmd_insert,
++
++ TP_PROTO(unsigned port, char cmd),
++
++ TP_ARGS(port, cmd),
++
++ TP_STRUCT__entry(
++ __field(unsigned, port)
++ __field(char, cmd)
++ ),
++
++ TP_fast_assign(
++ __entry->port = port;
++ __entry->cmd = cmd;
++ ),
++
++ TP_printk("port=%u cmd=%s", __entry->port,
++ show_hsucmd_name(__entry->cmd))
++);
++
++TRACE_EVENT(hsu_cmd_add,
++
++ TP_PROTO(unsigned port, char cmd),
++
++ TP_ARGS(port, cmd),
++
++ TP_STRUCT__entry(
++ __field(unsigned, port)
++ __field(char, cmd)
++ ),
++
++ TP_fast_assign(
++ __entry->port = port;
++ __entry->cmd = cmd;
++ ),
++
++ TP_printk("port=%u cmd=%s", __entry->port,
++ show_hsucmd_name(__entry->cmd))
++);
++
++TRACE_EVENT(hsu_cmd_start,
++
++ TP_PROTO(unsigned port, char cmd),
++
++ TP_ARGS(port, cmd),
++
++ TP_STRUCT__entry(
++ __field(unsigned, port)
++ __field(char, cmd)
++ ),
++
++ TP_fast_assign(
++ __entry->port = port;
++ __entry->cmd = cmd;
++ ),
++
++ TP_printk("port=%u cmd=%s", __entry->port,
++ show_hsucmd_name(__entry->cmd))
++);
++
++TRACE_EVENT(hsu_cmd_end,
++
++ TP_PROTO(unsigned port, char cmd),
++
++ TP_ARGS(port, cmd),
++
++ TP_STRUCT__entry(
++ __field(unsigned, port)
++ __field(char, cmd)
++ ),
++
++ TP_fast_assign(
++ __entry->port = port;
++ __entry->cmd = cmd;
++ ),
++
++ TP_printk("port=%u cmd=%s", __entry->port,
++ show_hsucmd_name(__entry->cmd))
++);
++
++TRACE_EVENT(hsu_func_start,
++
++ TP_PROTO(unsigned port, const char *func),
++
++ TP_ARGS(port, func),
++
++ TP_STRUCT__entry(
++ __field(unsigned, port)
++ __string(name, func)
++ ),
++
++ TP_fast_assign(
++ __entry->port = port;
++ __assign_str(name, func);
++ ),
++
++ TP_printk("port=%u func=%s", __entry->port,
++ __get_str(name))
++);
++
++TRACE_EVENT(hsu_func_end,
++
++ TP_PROTO(unsigned port, const char *func, char *err),
++
++ TP_ARGS(port, func, err),
++
++ TP_STRUCT__entry(
++ __field(unsigned, port)
++ __string(name, func)
++ __string(ret, err)
++ ),
++
++ TP_fast_assign(
++ __entry->port = port;
++ __assign_str(name, func);
++ __assign_str(ret, err);
++ ),
++
++ TP_printk("port=%u func=%s err=%s", __entry->port,
++ __get_str(name), __get_str(ret))
++);
++
++TRACE_EVENT(hsu_mctrl,
++
++ TP_PROTO(unsigned port, unsigned mctrl),
++
++ TP_ARGS(port, mctrl),
++
++ TP_STRUCT__entry(
++ __field(unsigned, port)
++ __field(unsigned, mctrl)
++ ),
++
++ TP_fast_assign(
++ __entry->port = port;
++ __entry->mctrl = mctrl;
++ ),
++
++ TP_printk("port=%u mctrl=%d", __entry->port, __entry->mctrl)
++);
++
++TRACE_EVENT(hsu_set_termios,
++
++ TP_PROTO(unsigned port, unsigned int baud, int ctsrts),
++
++ TP_ARGS(port, baud, ctsrts),
++
++ TP_STRUCT__entry(
++ __field(unsigned, port)
++ __field(unsigned int, baud)
++ __field(int, ctsrts)
++ ),
++
++ TP_fast_assign(
++ __entry->port = port;
++ __entry->baud = baud;
++ __entry->ctsrts = ctsrts;
++ ),
++
++ TP_printk("port=%u baud=%d ctsrts=%d", __entry->port,
++ __entry->baud, __entry->ctsrts)
++);
++
++#endif /* if !defined(_TRACE_HSU_H) || defined(TRACE_HEADER_MULTI_READ) */
++
++/* This part must be outside protection */
++#include <trace/define_trace.h>
+diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c
+index 9b6ef20..09f437c 100644
+--- a/drivers/tty/serial/mrst_max3110.c
++++ b/drivers/tty/serial/mrst_max3110.c
+@@ -40,9 +40,11 @@
+ #include <linux/tty_flip.h>
+ #include <linux/serial_core.h>
+ #include <linux/serial_reg.h>
++#include <linux/serial_max3110.h>
+
+ #include <linux/kthread.h>
+ #include <linux/spi/spi.h>
++#include <linux/pm.h>
+
+ #include "mrst_max3110.h"
+
+@@ -61,12 +63,14 @@ struct uart_max3110 {
+ struct task_struct *main_thread;
+ struct task_struct *read_thread;
+ struct mutex thread_mutex;
++ struct mutex io_mutex;
+
+ u32 baud;
+ u16 cur_conf;
+ u8 clock;
+ u8 parity, word_7bits;
+ u16 irq;
++ u16 irq_edge_triggered;
+
+ unsigned long uart_flags;
+
+@@ -90,6 +94,7 @@ static int max3110_write_then_read(struct uart_max3110 *max,
+ struct spi_transfer x;
+ int ret;
+
++ mutex_lock(&max->io_mutex);
+ spi_message_init(&message);
+ memset(&x, 0, sizeof x);
+ x.len = len;
+@@ -104,6 +109,7 @@ static int max3110_write_then_read(struct uart_max3110 *max,
+
+ /* Do the i/o */
+ ret = spi_sync(spi, &message);
++ mutex_unlock(&max->io_mutex);
+ return ret;
+ }
+
+@@ -259,7 +265,6 @@ static void serial_m3110_stop_rx(struct uart_port *port)
+ return;
+ }
+
+-#define WORDS_PER_XFER 128
+ static void send_circ_buf(struct uart_max3110 *max,
+ struct circ_buf *xmit)
+ {
+@@ -268,7 +273,7 @@ static void send_circ_buf(struct uart_max3110 *max,
+ int i, len, blen, dma_size, left, ret = 0;
+
+
+- dma_size = WORDS_PER_XFER * sizeof(u16) * 2;
++ dma_size = M3110_RX_FIFO_DEPTH * sizeof(u16) * 2;
+ buf = kzalloc(dma_size, GFP_KERNEL | GFP_DMA);
+ if (!buf)
+ return;
+@@ -278,7 +283,7 @@ static void send_circ_buf(struct uart_max3110 *max,
+ while (!uart_circ_empty(xmit)) {
+ left = uart_circ_chars_pending(xmit);
+ while (left) {
+- len = min(left, WORDS_PER_XFER);
++ len = min(left, M3110_RX_FIFO_DEPTH);
+ blen = len * sizeof(u16);
+ memset(ibuf, 0, blen);
+
+@@ -414,8 +419,8 @@ static int max3110_main_thread(void *_max)
+ max->uart_flags || kthread_should_stop());
+
+ mutex_lock(&max->thread_mutex);
+-
+- if (test_and_clear_bit(BIT_IRQ_PENDING, &max->uart_flags))
++ if (max->irq_edge_triggered &&
++ test_and_clear_bit(BIT_IRQ_PENDING, &max->uart_flags))
+ max3110_con_receive(max);
+
+ /* first handle console output */
+@@ -437,11 +442,15 @@ static irqreturn_t serial_m3110_irq(int irq, void *dev_id)
+ {
+ struct uart_max3110 *max = dev_id;
+
+- /* max3110's irq is a falling edge, not level triggered,
+- * so no need to disable the irq */
++ if (max->irq_edge_triggered) {
++ /* max3110's irq is a falling edge, not level triggered,
++ * so no need to disable the irq */
+
+- if (!test_and_set_bit(BIT_IRQ_PENDING, &max->uart_flags))
+- wake_up(&max->wq);
++ if (!test_and_set_bit(BIT_IRQ_PENDING, &max->uart_flags))
++ wake_up(&max->wq);
++ } else {
++ max3110_con_receive(max);
++ }
+
+ return IRQ_HANDLED;
+ }
+@@ -490,20 +499,10 @@ static int serial_m3110_startup(struct uart_port *port)
+ /* as we use thread to handle tx/rx, need set low latency */
+ port->state->port.low_latency = 1;
+
+- if (max->irq) {
+- max->read_thread = NULL;
+- ret = request_irq(max->irq, serial_m3110_irq,
+- IRQ_TYPE_EDGE_FALLING, "max3110", max);
+- if (ret) {
+- max->irq = 0;
+- pr_err(PR_FMT "unable to allocate IRQ, polling\n");
+- } else {
+- /* Enable RX IRQ only */
+- config |= WC_RXA_IRQ_ENABLE;
+- }
+- }
+-
+- if (max->irq == 0) {
++ if (max->irq > 0) {
++ /* Enable RX IRQ only */
++ config |= WC_RXA_IRQ_ENABLE;
++ } else {
+ /* If IRQ is disabled, start a read thread for input data */
+ max->read_thread =
+ kthread_run(max3110_read_thread, max, "max3110_read");
+@@ -517,8 +516,6 @@ static int serial_m3110_startup(struct uart_port *port)
+
+ ret = max3110_out(max, config);
+ if (ret) {
+- if (max->irq)
+- free_irq(max->irq, max);
+ if (max->read_thread)
+ kthread_stop(max->read_thread);
+ max->read_thread = NULL;
+@@ -540,9 +537,6 @@ static void serial_m3110_shutdown(struct uart_port *port)
+ max->read_thread = NULL;
+ }
+
+- if (max->irq)
+- free_irq(max->irq, max);
+-
+ /* Disable interrupts from this port */
+ config = WC_TAG | WC_SW_SHDI;
+ max3110_out(max, config);
+@@ -749,7 +743,8 @@ static int serial_m3110_suspend(struct device *dev)
+ struct spi_device *spi = to_spi_device(dev);
+ struct uart_max3110 *max = spi_get_drvdata(spi);
+
+- disable_irq(max->irq);
++ if (max->irq > 0)
++ disable_irq(max->irq);
+ uart_suspend_port(&serial_m3110_reg, &max->port);
+ max3110_out(max, max->cur_conf | WC_SW_SHDI);
+ return 0;
+@@ -762,7 +757,8 @@ static int serial_m3110_resume(struct device *dev)
+
+ max3110_out(max, max->cur_conf);
+ uart_resume_port(&serial_m3110_reg, &max->port);
+- enable_irq(max->irq);
++ if (max->irq > 0)
++ enable_irq(max->irq);
+ return 0;
+ }
+
+@@ -780,6 +776,10 @@ static int serial_m3110_probe(struct spi_device *spi)
+ void *buffer;
+ u16 res;
+ int ret = 0;
++ struct plat_max3110 *pdata = spi->dev.platform_data;
++
++ if (!pdata)
++ return -EINVAL;
+
+ max = kzalloc(sizeof(*max), GFP_KERNEL);
+ if (!max)
+@@ -803,6 +803,7 @@ static int serial_m3110_probe(struct spi_device *spi)
+ max->irq = (u16)spi->irq;
+
+ mutex_init(&max->thread_mutex);
++ mutex_init(&max->io_mutex);
+
+ max->word_7bits = 0;
+ max->parity = 0;
+@@ -840,6 +841,25 @@ static int serial_m3110_probe(struct spi_device *spi)
+ goto err_kthread;
+ }
+
++ max->irq_edge_triggered = pdata->irq_edge_triggered;
++
++ if (max->irq > 0) {
++ if (max->irq_edge_triggered) {
++ ret = request_irq(max->irq, serial_m3110_irq,
++ IRQ_TYPE_EDGE_FALLING, "max3110", max);
++ } else {
++ ret = request_threaded_irq(max->irq, NULL,
++ serial_m3110_irq,
++ IRQF_ONESHOT, "max3110", max);
++ }
++
++ if (ret) {
++ max->irq = 0;
++ dev_warn(&spi->dev,
++ "unable to allocate IRQ, will use polling method\n");
++ }
++ }
++
+ spi_set_drvdata(spi, max);
+ pmax = max;
+
+@@ -867,6 +887,9 @@ static int serial_m3110_remove(struct spi_device *dev)
+
+ free_page((unsigned long)max->con_xmit.buf);
+
++ if (max->irq)
++ free_irq(max->irq, max);
++
+ if (max->main_thread)
+ kthread_stop(max->main_thread);
+
+diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
+index f87dbfd..7855f3a 100644
+--- a/drivers/tty/serial/serial_core.c
++++ b/drivers/tty/serial/serial_core.c
+@@ -95,6 +95,9 @@ static void __uart_start(struct tty_struct *tty)
+ struct uart_state *state = tty->driver_data;
+ struct uart_port *port = state->uart_port;
+
++ if (port->ops->wake_peer)
++ port->ops->wake_peer(port);
++
+ if (!uart_circ_empty(&state->xmit) && state->xmit.buf &&
+ !tty->stopped && !tty->hw_stopped)
+ port->ops->start_tx(port);
+diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
+index d53547d..5955503 100644
+--- a/drivers/usb/core/hcd.c
++++ b/drivers/usb/core/hcd.c
+@@ -2136,6 +2136,11 @@ static void hcd_resume_work(struct work_struct *work)
+ usb_lock_device(udev);
+ usb_remote_wakeup(udev);
+ usb_unlock_device(udev);
++ if (HCD_IRQ_DISABLED(hcd)) {
++ /* We can now process IRQs so enable IRQ */
++ clear_bit(HCD_FLAG_IRQ_DISABLED, &hcd->flags);
++ enable_irq(hcd->irq);
++ }
+ }
+
+ /**
+@@ -2223,9 +2228,23 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)
+ */
+ local_irq_save(flags);
+
+- if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd)))
++ if (unlikely(HCD_DEAD(hcd)))
+ rc = IRQ_NONE;
+- else if (hcd->driver->irq(hcd) == IRQ_NONE)
++ else if (unlikely(!HCD_HW_ACCESSIBLE(hcd))) {
++ if (hcd->has_wakeup_irq) {
++ /*
++ * We got a wakeup interrupt while the controller was
++ * suspending or suspended. We can't handle it now, so
++ * disable the IRQ and resume the root hub (and hence
++ * the controller too).
++ */
++ disable_irq_nosync(hcd->irq);
++ set_bit(HCD_FLAG_IRQ_DISABLED, &hcd->flags);
++ usb_hcd_resume_root_hub(hcd);
++ rc = IRQ_HANDLED;
++ } else
++ rc = IRQ_NONE;
++ } else if (hcd->driver->irq(hcd) == IRQ_NONE)
+ rc = IRQ_NONE;
+ else
+ rc = IRQ_HANDLED;
+diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
+index 757aa18..7aaa51f 100644
+--- a/drivers/usb/dwc3/Kconfig
++++ b/drivers/usb/dwc3/Kconfig
+@@ -40,6 +40,72 @@ config USB_DWC3_DUAL_ROLE
+
+ endchoice
+
++comment "Platform Glue Driver Support"
++
++config USB_DWC3_PCI
++ tristate "PCIe-based Platforms"
++ depends on PCI
++ default USB_DWC3
++ help
++ If you're using the DesignWare Core IP with a PCIe, please say
++ 'Y' or 'M' here.
++
++ One such PCIe-based platform is Synopsys' PCIe HAPS model of
++ this IP.
++
++config USB_DWC3_OTG
++ tristate "DWC3 OTG mode support"
++ depends on USB && PCI
++ select USB_OTG
++ help
++ Say Y here to enable DWC3 OTG driver.
++ This driver implement OTG framework for DWC3 OTG controller.
++ Support role switch and charger detection feature. And maintain
++ one state machine. This driver should be work with platform
++ speical driver. Because every platform has their own hardware design.
++
++config USB_DWC3_INTEL_MRFL
++ tristate "DWC OTG 3.0 for Intel Merrifield platforms"
++ depends on USB && USB_DWC3_OTG
++ select USB_DWC3_DEVICE_INTEL
++ help
++ Say Y here to enable DWC3 OTG driver for Intel Merrifield platforms.
++ It implement OTG feature on DWC3 OTG controller.
++ Support role switch and charger detection feature.
++ This driver is must be set if you want to enable host mode on Intel
++ Merrifield platforms.
++
++config USB_DWC3_INTEL_BYT
++ tristate "DWC OTG 3.0 for Intel Baytrail platforms"
++ depends on USB && USB_DWC3_OTG
++ select USB_DWC3_DEVICE_INTEL
++ help
++ Say Y here to enable DWC3 OTG driver for Intel Baytrail platforms.
++ It implement OTG feature on DWC3 OTG controller.
++ Support role switch and charger detection feature.
++ This driver is must be set if you want to enable device mode on Intel
++ Baytrial platforms.
++
++config USB_DWC3_DEVICE_INTEL
++ bool "DWC3 Device Mode support on Intel platform"
++ depends on USB_DWC3_OTG
++ help
++ Support Device mode of DWC3 controller on Intel platform.
++ It implement device mode feature on DWC3 OTG controller.
++ This driver is must be set if you want to enable device mode for Intel
++ platforms(e.g Baytrail and Merrifield)
++
++config USB_DWC3_HOST_INTEL
++ bool "DWC3 Host Mode support on Intel Merrifield platform"
++ depends on USB_ARCH_HAS_XHCI && USB_DWC3_INTEL_MRFL
++ help
++ Support Host mode of DWC3 controller on Intel Merrifield platform.
++ It is should be enable with DWC3 INTEL driver. Because Intel platform
++ use different design with standard USB_DWC3_HOST. So if you want to
++ enable host mode on Intel platform, then you have to enable this config.
++
++comment "Debugging features"
++
+ config USB_DWC3_DEBUG
+ bool "Enable Debugging Messages"
+ help
+diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
+index 0c7ac92..1bc7013 100644
+--- a/drivers/usb/dwc3/Makefile
++++ b/drivers/usb/dwc3/Makefile
+@@ -1,6 +1,13 @@
+ ccflags-$(CONFIG_USB_DWC3_DEBUG) := -DDEBUG
+ ccflags-$(CONFIG_USB_DWC3_VERBOSE) += -DVERBOSE_DEBUG
+
++obj-$(CONFIG_USB_DWC3_DEVICE_INTEL) += dwc3-device-intel.o
++obj-$(CONFIG_USB_DWC3_INTEL_MRFL) += dwc3-intel-mrfl.o
++ifneq ($(CONFIG_DEBUG_FS),)
++ obj-$(CONFIG_USB_DWC3_DEVICE_INTEL) += debugfs.o
++endif
++
++ifeq ($(CONFIG_USB_DWC3_DEVICE_INTEL),)
+ obj-$(CONFIG_USB_DWC3) += dwc3.o
+
+ dwc3-y := core.o
+@@ -16,6 +23,7 @@ endif
+ ifneq ($(CONFIG_DEBUG_FS),)
+ dwc3-y += debugfs.o
+ endif
++endif
+
+ ##
+ # Platform-specific glue layers go here
+@@ -36,6 +44,6 @@ obj-$(CONFIG_USB_DWC3) += dwc3-omap.o
+ obj-$(CONFIG_USB_DWC3) += dwc3-exynos.o
+
+ ifneq ($(CONFIG_PCI),)
++ obj-$(CONFIG_USB_DWC3_OTG) += otg.o
+ obj-$(CONFIG_USB_DWC3) += dwc3-pci.o
+ endif
+-
+diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
+index 358375e..6c1cc98 100644
+--- a/drivers/usb/dwc3/core.c
++++ b/drivers/usb/dwc3/core.c
+@@ -53,6 +53,7 @@
+ #include <linux/usb/otg.h>
+ #include <linux/usb/ch9.h>
+ #include <linux/usb/gadget.h>
++#include <linux/usb/ulpi.h>
+
+ #include "core.h"
+ #include "gadget.h"
+@@ -256,7 +257,8 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
+ dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
+ dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
+ dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0);
+- dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
++ dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n),
++ dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(n)));
+ }
+ }
+
+@@ -297,6 +299,7 @@ static int dwc3_core_init(struct dwc3 *dwc)
+ unsigned long timeout;
+ u32 reg;
+ int ret;
++ struct usb_phy *usb_phy;
+
+ reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
+ /* This should read as U3 followed by revision number */
+@@ -307,6 +310,13 @@ static int dwc3_core_init(struct dwc3 *dwc)
+ }
+ dwc->revision = reg;
+
++ dwc3_core_soft_reset(dwc);
++
++ /* Delay 1 ms Before DCTL soft reset to make it safer from hitting
++ * Tx-CMD PHY hang issue.
++ */
++ mdelay(1);
++
+ /* issue device SoftReset too */
+ timeout = jiffies + msecs_to_jiffies(500);
+ dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
+@@ -324,7 +334,14 @@ static int dwc3_core_init(struct dwc3 *dwc)
+ cpu_relax();
+ } while (true);
+
+- dwc3_core_soft_reset(dwc);
++ /* DCTL core soft reset may cause PHY hang, delay 1 ms and check ulpi */
++ mdelay(1);
++ usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
++ if (usb_phy &&
++ usb_phy_io_read(usb_phy, ULPI_VENDOR_ID_LOW) < 0)
++ dev_err(dwc->dev,
++ "ULPI not working after DCTL soft reset\n");
++ usb_put_phy(usb_phy);
+
+ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+ reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
+diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
+index 27dad99..4e49c0d 100644
+--- a/drivers/usb/dwc3/core.h
++++ b/drivers/usb/dwc3/core.h
+@@ -51,6 +51,7 @@
+ #include <linux/usb/gadget.h>
+
+ /* Global constants */
++#define DWC3_SCRATCH_BUF_SIZE 4096
+ #define DWC3_EP0_BOUNCE_SIZE 512
+ #define DWC3_ENDPOINTS_NUM 32
+ #define DWC3_XHCI_RESOURCES_NUM 2
+@@ -194,6 +195,10 @@
+ #define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff)
+ #define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000)
+
++/* Global Event Size Registers */
++#define DWC3_GEVNTSIZ_INTMASK (1 << 31)
++#define DWC3_GEVNTSIZ_SIZE(n) ((n) & 0xffff)
++
+ /* Global HWPARAMS1 Register */
+ #define DWC3_GHWPARAMS1_EN_PWROPT(n) (((n) & (3 << 24)) >> 24)
+ #define DWC3_GHWPARAMS1_EN_PWROPT_NO 0
+@@ -309,6 +314,7 @@
+ #define DWC3_DGCMD_SET_LMP 0x01
+ #define DWC3_DGCMD_SET_PERIODIC_PAR 0x02
+ #define DWC3_DGCMD_XMIT_FUNCTION 0x03
++#define DWC3_DGCMD_SET_SCRATCH_ADDR_LO 0x04
+
+ /* These apply for core versions 1.94a and later */
+ #define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO 0x04
+@@ -408,9 +414,11 @@ struct dwc3_event_buffer {
+ * @trb_pool_dma: dma address of @trb_pool
+ * @free_slot: next slot which is going to be used
+ * @busy_slot: first slot which is owned by HW
++ * @ep_state: endpoint state
+ * @desc: usb_endpoint_descriptor pointer
+ * @dwc: pointer to DWC controller
+ * @flags: endpoint flags (wedged, stalled, ...)
++ * @flags_backup: backup endpoint flags
+ * @current_trb: index of current used trb
+ * @number: endpoint number (1 - 15)
+ * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
+@@ -429,16 +437,23 @@ struct dwc3_ep {
+ dma_addr_t trb_pool_dma;
+ u32 free_slot;
+ u32 busy_slot;
++ u32 ep_state;
+ const struct usb_ss_ep_comp_descriptor *comp_desc;
+ struct dwc3 *dwc;
+
++ struct ebc_io *ebc;
++#define DWC3_EP_EBC_OUT_NB 16
++#define DWC3_EP_EBC_IN_NB 17
++
+ unsigned flags;
++ unsigned flags_backup;
+ #define DWC3_EP_ENABLED (1 << 0)
+ #define DWC3_EP_STALL (1 << 1)
+ #define DWC3_EP_WEDGE (1 << 2)
+ #define DWC3_EP_BUSY (1 << 4)
+ #define DWC3_EP_PENDING_REQUEST (1 << 5)
+ #define DWC3_EP_MISSED_ISOC (1 << 6)
++#define DWC3_EP_HIBERNATION (1 << 7)
+
+ /* This last one is specific to EP0 */
+ #define DWC3_EP0_DIR_IN (1 << 31)
+@@ -495,6 +510,13 @@ enum dwc3_link_state {
+ DWC3_LINK_STATE_MASK = 0x0f,
+ };
+
++enum dwc3_pm_state {
++ PM_DISCONNECTED = 0,
++ PM_ACTIVE,
++ PM_SUSPENDED,
++ PM_RESUMING,
++};
++
+ /* TRB Length, PCM and Status */
+ #define DWC3_TRB_SIZE_MASK (0x00ffffff)
+ #define DWC3_TRB_SIZE_LENGTH(n) ((n) & DWC3_TRB_SIZE_MASK)
+@@ -600,6 +622,7 @@ struct dwc3_request {
+ unsigned direction:1;
+ unsigned mapped:1;
+ unsigned queued:1;
++ unsigned short_packet:1;
+ };
+
+ /*
+@@ -611,6 +634,22 @@ struct dwc3_scratchpad_array {
+ };
+
+ /**
++ * struct dwc3_hwregs - registers saved when entering hibernation
++ */
++struct dwc3_hwregs {
++ u32 guctl;
++ u32 dcfg;
++ u32 devten;
++ u32 gctl;
++ u32 gusb3pipectl0;
++ u32 gusb2phycfg0;
++ u32 gevntadrlo;
++ u32 gevntadrhi;
++ u32 gevntsiz;
++ u32 grxthrcfg;
++};
++
++/**
+ * struct dwc3 - representation of our controller
+ * @ctrl_req: usb control request which is used for ep0
+ * @ep0_trb: trb which is used for the ctrl_req
+@@ -727,6 +766,7 @@ struct dwc3 {
+ unsigned needs_fifo_resize:1;
+ unsigned resize_fifos:1;
+ unsigned pullups_connected:1;
++ unsigned quirks_disable_irqthread:1;
+
+ enum dwc3_ep0_next ep0_next_event;
+ enum dwc3_ep0_state ep0state;
+@@ -748,9 +788,23 @@ struct dwc3 {
+ struct dwc3_hwparams hwparams;
+ struct dentry *root;
+ struct debugfs_regset32 *regset;
++ enum dwc3_pm_state pm_state;
++ u8 is_otg;
++ u8 soft_connected;
+
+ u8 test_mode;
+ u8 test_mode_nr;
++
++ /* delayed work for handling Link State Change */
++ struct delayed_work link_work;
++
++ u8 is_ebc;
++
++ struct dwc3_scratchpad_array *scratch_array;
++ dma_addr_t scratch_array_dma;
++ void *scratch_buffer[DWC3_MAX_HIBER_SCRATCHBUFS];
++ struct dwc3_hwregs hwregs;
++ bool hiber_enabled;
+ };
+
+ /* -------------------------------------------------------------------------- */
+@@ -877,6 +931,23 @@ union dwc3_event {
+ struct dwc3_event_gevt gevt;
+ };
+
++struct ebc_io {
++ const char *name;
++ const char *epname;
++ u8 epnum;
++ u8 is_ondemand;
++ u8 static_trb_pool_size;
++ struct list_head list;
++ int (*init) (void);
++ void *(*alloc_static_trb_pool) (dma_addr_t *dma_addr);
++ void (*free_static_trb_pool) (void);
++ int (*xfer_start) (void);
++ int (*xfer_stop) (void);
++};
++
++void dwc3_register_io_ebc(struct ebc_io *ebc);
++void dwc3_unregister_io_ebc(struct ebc_io *ebc);
++
+ /*
+ * DWC3 Features to be used as Driver Data
+ */
+diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
+index 9e9f122..ea38e22 100644
+--- a/drivers/usb/dwc3/debugfs.c
++++ b/drivers/usb/dwc3/debugfs.c
+@@ -638,6 +638,48 @@ static const struct file_operations dwc3_link_state_fops = {
+ .release = single_release,
+ };
+
++static int dwc3_hiber_enabled_show(struct seq_file *s, void *unused)
++{
++ struct dwc3 *dwc = s->private;
++
++ if (dwc->hiber_enabled)
++ seq_puts(s, "hibernation enabled\n");
++ else
++ seq_puts(s, "hibernation disabled\n");
++
++ return 0;
++}
++
++static int dwc3_hiber_enabled_open(struct inode *inode, struct file *file)
++{
++ return single_open(file, dwc3_hiber_enabled_show, inode->i_private);
++}
++
++static ssize_t dwc3_hiber_enabled_write(struct file *file,
++ const char __user *ubuf, size_t count, loff_t *ppos)
++{
++ struct seq_file *s = file->private_data;
++ struct dwc3 *dwc = s->private;
++ char buf[32];
++ int enabled = 0;
++
++ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
++ return -EFAULT;
++
++ sscanf(buf, "%d", &enabled);
++ dwc->hiber_enabled = enabled;
++
++ return count;
++}
++
++static const struct file_operations dwc3_hiber_enabled_fops = {
++ .open = dwc3_hiber_enabled_open,
++ .write = dwc3_hiber_enabled_write,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
+ int dwc3_debugfs_init(struct dwc3 *dwc)
+ {
+ struct dentry *root;
+@@ -692,6 +734,13 @@ int dwc3_debugfs_init(struct dwc3 *dwc)
+ ret = -ENOMEM;
+ goto err1;
+ }
++
++ file = debugfs_create_file("hiber_enabled", S_IRUGO | S_IWUSR,
++ root, dwc, &dwc3_hiber_enabled_fops);
++ if (!file) {
++ ret = -ENOMEM;
++ goto err1;
++ }
+ }
+
+ return 0;
+diff --git a/drivers/usb/dwc3/dwc3-device-intel.c b/drivers/usb/dwc3/dwc3-device-intel.c
+new file mode 100644
+index 0000000..0ffde5c
+--- /dev/null
++++ b/drivers/usb/dwc3/dwc3-device-intel.c
+@@ -0,0 +1,648 @@
++/**
++ * Copyright (C) 2012 Intel Corp.
++ * Author: Jiebing Li
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software Foundation,
++ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++
++#include <linux/usb/dwc3-intel-mid.h>
++#include <linux/usb/phy.h>
++
++#include "core.h"
++#include "gadget.h"
++#include "io.h"
++#include "otg.h"
++
++#include "debug.h"
++
++#include "core.c"
++#include "ep0.c"
++#include "gadget.c"
++
++/* FLIS register */
++#define APBFC_EXIOTG3_MISC0_REG 0xF90FF85C
++
++/* Global User Control Register Auto Retry bit*/
++#define DWC3_GUCTL_USB_HST_IN_AUTO_RETRY_EN (1 << 14)
++
++/* Global Configuration Register */
++#define DWC3_GRXTHRCFG_USBRXPKTCNTSEL (1 << 29)
++#define DWC3_GRXTHRCFG_USBRXPKTCNT(n) (n << 24)
++#define DWC3_GRXTHRCFG_USBRXPKTCNT_MASK (0xf << 24)
++#define DWC3_GRXTHRCFG_USBMAXRXBURSTSIZE(n) (n << 19)
++#define DWC3_GRXTHRCFG_USBMAXRXBURSTSIZE_MASK (0x1f << 19)
++
++/**
++ * struct dwc3_dev_data - Structure holding platform related
++ * information
++ * @flis_reg: FLIS register
++ * @grxthrcfg: DWC3 GRXTHCFG register
++ */
++struct dwc3_dev_data {
++ struct dwc3 *dwc;
++ void __iomem *flis_reg;
++ u32 grxthrcfg;
++ struct mutex mutex;
++};
++
++static struct dwc3_dev_data *_dev_data;
++
++/*
++ * dwc3_set_fils_reg - set FLIS register
++ *
++ * This is a workaround for OTG3 IP bug of using EP #8 for host mode
++ */
++static void dwc3_set_flis_reg(void)
++{
++ u32 reg;
++ void __iomem *flis_reg;
++
++ flis_reg = _dev_data->flis_reg;
++
++ reg = dwc3_readl(flis_reg, DWC3_GLOBALS_REGS_START);
++ reg &= ~(1 << 3);
++ dwc3_writel(flis_reg, DWC3_GLOBALS_REGS_START, reg);
++}
++
++/*
++ * dwc3_disable_multi_packet - set GRXTHRCFG register to disable
++ * reception multi-packet thresholdingfor DWC2.50a.
++ */
++static void dwc3_disable_multi_packet(struct dwc3 *dwc)
++{
++ u32 reg;
++
++ reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG);
++ _dev_data->grxthrcfg = reg;
++ if (reg) {
++ reg &= ~DWC3_GRXTHRCFG_USBRXPKTCNTSEL;
++ reg &= ~DWC3_GRXTHRCFG_USBRXPKTCNT_MASK;
++ reg &= ~DWC3_GRXTHRCFG_USBMAXRXBURSTSIZE_MASK;
++
++ dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg);
++ }
++}
++
++/*
++ * dwc3_enable_host_auto_retry - clear Auto Retry Enable bit
++ * for device mode
++ */
++static void dwc3_enable_host_auto_retry(struct dwc3 *dwc, bool enable)
++{
++ u32 reg;
++
++ reg = dwc3_readl(dwc->regs, DWC3_GUCTL);
++
++ if (enable)
++ reg |= DWC3_GUCTL_USB_HST_IN_AUTO_RETRY_EN;
++ else
++ reg &= ~DWC3_GUCTL_USB_HST_IN_AUTO_RETRY_EN;
++
++ dwc3_writel(dwc->regs, DWC3_GUCTL, reg);
++}
++
++static void dwc3_do_extra_change(struct dwc3 *dwc)
++{
++ dwc3_set_flis_reg();
++
++ if (dwc->revision == DWC3_REVISION_250A)
++ dwc3_disable_multi_packet(dwc);
++
++ dwc3_enable_host_auto_retry(dwc, false);
++}
++
++static void dwc3_enable_hibernation(struct dwc3 *dwc)
++{
++ u32 num, reg;
++
++ if (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)
++ != DWC3_GHWPARAMS1_EN_PWROPT_HIB) {
++ dev_err(dwc->dev, "Device Mode Hibernation is not supported\n");
++ return;
++ }
++
++ num = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(
++ dwc->hwparams.hwparams4);
++ if (num != 1)
++ dev_err(dwc->dev, "number of scratchpad buffer: %d\n", num);
++
++ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
++ reg |= DWC3_GCTL_GBLHIBERNATIONEN;
++ dwc3_writel(dwc->regs, DWC3_GCTL, reg);
++
++ dwc3_send_gadget_generic_command(dwc, DWC3_DGCMD_SET_SCRATCH_ADDR_LO,
++ dwc->scratch_array_dma & 0xffffffffU);
++}
++
++/*
++ * Re-write irq functions. Not use irq thread. Because irqthread has negative
++ * impact on usb performance, especially for usb network performance, USB3 UDP
++ * download performance will drop from 80MB/s to 40MB/s if irqthread is enabled.
++ */
++static irqreturn_t dwc3_quirks_process_event_buf(struct dwc3 *dwc, u32 buf)
++{
++ struct dwc3_event_buffer *evt;
++ u32 count;
++ u32 reg;
++ int left;
++
++ evt = dwc->ev_buffs[buf];
++
++ count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf));
++ count &= DWC3_GEVNTCOUNT_MASK;
++ if (!count)
++ return IRQ_NONE;
++
++ evt->count = count;
++
++ /* WORKAROUND: Add 4 us delay workaround to A-unit issue in A0 stepping.
++ * Can be removed after B0.
++ */
++ if (dwc->is_otg && dwc->revision == DWC3_REVISION_210A)
++ udelay(4);
++
++ left = evt->count;
++
++ while (left > 0) {
++ union dwc3_event event;
++
++ event.raw = *(u32 *) (evt->buf + evt->lpos);
++
++ dwc3_process_event_entry(dwc, &event);
++
++ /*
++ * FIXME we wrap around correctly to the next entry as
++ * almost all entries are 4 bytes in size. There is one
++ * entry which has 12 bytes which is a regular entry
++ * followed by 8 bytes data. ATM I don't know how
++ * things are organized if we get next to the a
++ * boundary so I worry about that once we try to handle
++ * that.
++ */
++ evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
++ left -= 4;
++
++ dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
++ }
++
++ evt->count = 0;
++
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t dwc3_quirks_interrupt(int irq, void *_dwc)
++{
++ struct dwc3 *dwc = _dwc;
++ int i;
++ irqreturn_t ret = IRQ_NONE;
++
++ spin_lock(&dwc->lock);
++ if (dwc->pm_state != PM_ACTIVE) {
++ if (dwc->pm_state == PM_SUSPENDED) {
++ dev_info(dwc->dev, "u2/u3 pmu is received\n");
++ pm_runtime_get(dwc->dev);
++ dwc->pm_state = PM_RESUMING;
++ ret = IRQ_HANDLED;
++ }
++ goto out;
++ }
++
++ for (i = 0; i < dwc->num_event_buffers; i++) {
++ irqreturn_t status;
++
++ status = dwc3_quirks_process_event_buf(dwc, i);
++ if (status == IRQ_HANDLED)
++ ret = status;
++ }
++
++out:
++ spin_unlock(&dwc->lock);
++
++ return ret;
++}
++
++int dwc3_start_peripheral(struct usb_gadget *g)
++{
++ struct dwc3 *dwc = gadget_to_dwc(g);
++ unsigned long flags;
++ int irq;
++ int ret = 0;
++
++ pm_runtime_get_sync(dwc->dev);
++
++ mutex_lock(&_dev_data->mutex);
++ spin_lock_irqsave(&dwc->lock, flags);
++
++ if (dwc->gadget_driver && dwc->soft_connected) {
++ spin_unlock_irqrestore(&dwc->lock, flags);
++ dwc3_core_init(dwc);
++ spin_lock_irqsave(&dwc->lock, flags);
++
++ if (dwc->hiber_enabled)
++ dwc3_enable_hibernation(dwc);
++ dwc3_do_extra_change(dwc);
++ dwc3_event_buffers_setup(dwc);
++ ret = dwc3_init_for_enumeration(dwc);
++ if (ret)
++ goto err1;
++
++ if (dwc->soft_connected)
++ dwc3_gadget_run_stop(dwc, 1);
++ }
++
++ dwc->pm_state = PM_ACTIVE;
++
++ spin_unlock_irqrestore(&dwc->lock, flags);
++
++ irq = platform_get_irq(to_platform_device(dwc->dev), 0);
++ if (dwc->quirks_disable_irqthread)
++ ret = request_irq(irq, dwc3_quirks_interrupt,
++ IRQF_SHARED, "dwc3", dwc);
++ else
++ ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
++ IRQF_SHARED, "dwc3", dwc);
++ if (ret) {
++ dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
++ irq, ret);
++ goto err0;
++ }
++ mutex_unlock(&_dev_data->mutex);
++
++ return 0;
++
++err1:
++ spin_unlock_irqrestore(&dwc->lock, flags);
++err0:
++ mutex_unlock(&_dev_data->mutex);
++
++ return ret;
++}
++
++int dwc3_stop_peripheral(struct usb_gadget *g)
++{
++ struct dwc3 *dwc = gadget_to_dwc(g);
++ unsigned long flags;
++ u8 epnum;
++ int irq;
++
++ mutex_lock(&_dev_data->mutex);
++ spin_lock_irqsave(&dwc->lock, flags);
++
++ dwc3_stop_active_transfers(dwc);
++
++ if (dwc->gadget.speed != USB_SPEED_UNKNOWN) {
++ dwc3_disconnect_gadget(dwc);
++
++ dwc->gadget.speed = USB_SPEED_UNKNOWN;
++ }
++
++ dwc->start_config_issued = false;
++
++ /* Clear Run/Stop bit */
++ dwc3_gadget_run_stop(dwc, 0);
++ dwc3_gadget_keep_conn(dwc, 0);
++
++ for (epnum = 0; epnum < 2; epnum++) {
++ struct dwc3_ep *dep;
++
++ dep = dwc->eps[epnum];
++
++ if (dep->flags & DWC3_EP_ENABLED)
++ __dwc3_gadget_ep_disable(dep);
++ }
++
++ dwc3_gadget_disable_irq(dwc);
++
++ dwc3_event_buffers_cleanup(dwc);
++
++ if (_dev_data->grxthrcfg && dwc->revision == DWC3_REVISION_250A) {
++ dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, _dev_data->grxthrcfg);
++ _dev_data->grxthrcfg = 0;
++ }
++
++ dwc3_enable_host_auto_retry(dwc, true);
++
++ if (dwc->pm_state != PM_SUSPENDED)
++ pm_runtime_put(dwc->dev);
++
++ dwc->pm_state = PM_DISCONNECTED;
++ spin_unlock_irqrestore(&dwc->lock, flags);
++
++ irq = platform_get_irq(to_platform_device(dwc->dev), 0);
++ free_irq(irq, dwc);
++
++ mutex_unlock(&_dev_data->mutex);
++
++ cancel_delayed_work_sync(&dwc->link_work);
++
++ return 0;
++}
++
++static int dwc3_device_gadget_pullup(struct usb_gadget *g, int is_on)
++{
++ struct dwc3 *dwc = gadget_to_dwc(g);
++ unsigned long flags;
++ int ret;
++
++ /*
++ * FIXME If pm_state is PM_RESUMING, we should wait for it to
++ * become PM_ACTIVE before continue. The chance of hitting
++ * PM_RESUMING is rare, but if so, we'll return directly.
++ *
++ * If some gadget reaches here in atomic context,
++ * pm_runtime_get_sync will cause a sleep problem.
++ */
++ if (dwc->pm_state == PM_RESUMING) {
++ dev_err(dwc->dev, "%s: PM_RESUMING, return -EIO\n", __func__);
++ return -EIO;
++ }
++
++ if (dwc->pm_state == PM_SUSPENDED)
++ pm_runtime_get_sync(dwc->dev);
++
++ is_on = !!is_on;
++
++ mutex_lock(&_dev_data->mutex);
++
++ if (dwc->soft_connected == is_on)
++ goto done;
++
++ dwc->soft_connected = is_on;
++
++ spin_lock_irqsave(&dwc->lock, flags);
++ if (dwc->pm_state == PM_DISCONNECTED) {
++ spin_unlock_irqrestore(&dwc->lock, flags);
++ goto done;
++ }
++
++ if (is_on) {
++ /* Per dwc3 databook 2.40a section 8.1.9, re-connection
++ * should follow steps described section 8.1.1 power on
++ * or soft reset.
++ */
++ spin_unlock_irqrestore(&dwc->lock, flags);
++ dwc3_core_init(dwc);
++ spin_lock_irqsave(&dwc->lock, flags);
++
++ if (dwc->hiber_enabled)
++ dwc3_enable_hibernation(dwc);
++ dwc3_do_extra_change(dwc);
++ dwc3_event_buffers_setup(dwc);
++ dwc3_init_for_enumeration(dwc);
++ ret = dwc3_gadget_run_stop(dwc, 1);
++ if (dwc->hiber_enabled)
++ dwc3_gadget_keep_conn(dwc, 1);
++ } else {
++ u8 epnum;
++
++ for (epnum = 0; epnum < 2; epnum++) {
++ struct dwc3_ep *dep;
++
++ dep = dwc->eps[epnum];
++
++ if (dep->flags & DWC3_EP_ENABLED)
++ __dwc3_gadget_ep_disable(dep);
++ }
++
++ dwc3_stop_active_transfers(dwc);
++ dwc3_gadget_keep_conn(dwc, 0);
++ ret = dwc3_gadget_run_stop(dwc, 0);
++ dwc3_gadget_disable_irq(dwc);
++ }
++
++ spin_unlock_irqrestore(&dwc->lock, flags);
++ mutex_unlock(&_dev_data->mutex);
++
++ return ret;
++
++done:
++ mutex_unlock(&_dev_data->mutex);
++
++ return 0;
++}
++
++static const struct usb_gadget_ops dwc3_device_gadget_ops = {
++ .get_frame = dwc3_gadget_get_frame,
++ .wakeup = dwc3_gadget_wakeup,
++ .set_selfpowered = dwc3_gadget_set_selfpowered,
++ .pullup = dwc3_device_gadget_pullup,
++ .udc_start = dwc3_gadget_start,
++ .udc_stop = dwc3_gadget_stop,
++ .vbus_draw = dwc3_vbus_draw,
++};
++
++static int dwc3_device_intel_probe(struct platform_device *pdev)
++{
++ struct device_node *node = pdev->dev.of_node;
++ struct dwc3 *dwc;
++ struct device *dev = &pdev->dev;
++ int ret = -ENOMEM;
++ void *mem;
++
++ struct dwc_device_par *pdata;
++ struct usb_phy *usb_phy;
++ struct dwc_otg2 *otg;
++
++ mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
++ if (!mem) {
++ dev_err(dev, "not enough memory\n");
++ return -ENOMEM;
++ }
++ dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
++ dwc->mem = mem;
++
++ _dev_data = kzalloc(sizeof(*_dev_data), GFP_KERNEL);
++ if (!_dev_data) {
++ dev_err(dev, "not enough memory\n");
++ return -ENOMEM;
++ }
++
++ _dev_data->dwc = dwc;
++
++ pdata = (struct dwc_device_par *)pdev->dev.platform_data;
++ if (!pdata) {
++ dev_err(&pdev->dev, "No platform data for %s.\n",
++ dev_name(&pdev->dev));
++ return -ENODEV;
++ }
++
++ if (node) {
++ dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
++ dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);
++ } else {
++ dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
++ dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
++ }
++
++ if (IS_ERR(dwc->usb2_phy)) {
++ ret = PTR_ERR(dwc->usb2_phy);
++
++ /*
++ * if -ENXIO is returned, it means PHY layer wasn't
++ * enabled, so it makes no sense to return -EPROBE_DEFER
++ * in that case, since no PHY driver will ever probe.
++ */
++ if (ret == -ENXIO)
++ return ret;
++
++ dev_err(dev, "no usb2 phy configured\n");
++ return -EPROBE_DEFER;
++ }
++
++ if (IS_ERR(dwc->usb3_phy)) {
++ ret = PTR_ERR(dwc->usb2_phy);
++
++ /*
++ * if -ENXIO is returned, it means PHY layer wasn't
++ * enabled, so it makes no sense to return -EPROBE_DEFER
++ * in that case, since no PHY driver will ever probe.
++ */
++ if (ret == -ENXIO)
++ return ret;
++
++ dev_err(dev, "no usb3 phy configured\n");
++ return -EPROBE_DEFER;
++ }
++
++ mutex_init(&_dev_data->mutex);
++ spin_lock_init(&dwc->lock);
++ platform_set_drvdata(pdev, dwc);
++
++ dwc->regs = pdata->io_addr + DWC3_GLOBALS_REGS_START;
++ dwc->regs_size = pdata->len - DWC3_GLOBALS_REGS_START;
++ dwc->dev = dev;
++
++ dev->dma_mask = dev->parent->dma_mask;
++ dev->dma_parms = dev->parent->dma_parms;
++ dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
++
++ if (!strncmp("super", maximum_speed, 5))
++ dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
++ else if (!strncmp("high", maximum_speed, 4))
++ dwc->maximum_speed = DWC3_DCFG_HIGHSPEED;
++ else if (!strncmp("full", maximum_speed, 4))
++ dwc->maximum_speed = DWC3_DCFG_FULLSPEED1;
++ else if (!strncmp("low", maximum_speed, 3))
++ dwc->maximum_speed = DWC3_DCFG_LOWSPEED;
++ else
++ dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
++
++ dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
++
++ pm_runtime_set_active(&pdev->dev);
++ pm_runtime_enable(dev);
++ pm_runtime_set_suspended(&pdev->dev);
++ pm_runtime_get_sync(dev);
++ pm_runtime_forbid(dev);
++
++ dwc3_cache_hwparams(dwc);
++ dwc3_core_num_eps(dwc);
++
++ _dev_data->flis_reg =
++ ioremap_nocache(APBFC_EXIOTG3_MISC0_REG, 4);
++
++ ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
++ if (ret) {
++ dev_err(dwc->dev, "failed to allocate event buffers\n");
++ ret = -ENOMEM;
++ goto err0;
++ }
++
++ /*
++ * Not use irq thread, because irqthread has negative impact
++ * on usb performance, especially for usb network performance.
++ */
++ dwc->quirks_disable_irqthread = 1;
++
++ usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
++ otg = container_of(usb_phy, struct dwc_otg2, usb2_phy);
++ otg->start_device = dwc3_start_peripheral;
++ otg->stop_device = dwc3_stop_peripheral;
++ otg->vbus_draw = dwc3_vbus_draw;
++ usb_put_phy(usb_phy);
++ dwc->is_otg = 1;
++
++ dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
++ ret = dwc3_gadget_init(dwc);
++ if (ret) {
++ dev_err(dev, "failed to initialize gadget\n");
++ goto err0;
++ }
++ dwc->gadget.ops = &dwc3_device_gadget_ops;
++ dwc->gadget.is_otg = 1;
++
++ dwc->mode = DWC3_MODE_DEVICE;
++
++ ret = dwc3_debugfs_init(dwc);
++ if (ret) {
++ dev_err(dev, "failed to initialize debugfs\n");
++ goto err1;
++ }
++
++ pm_runtime_allow(dev);
++ pm_runtime_put(dev);
++
++ return 0;
++
++err1:
++ dwc3_gadget_exit(dwc);
++
++err0:
++ dwc3_free_event_buffers(dwc);
++
++ return ret;
++}
++
++static int dwc3_device_intel_remove(struct platform_device *pdev)
++{
++ iounmap(_dev_data->flis_reg);
++
++ dwc3_remove(pdev);
++
++ kfree(_dev_data);
++ _dev_data = NULL;
++
++ return 0;
++}
++
++#ifdef CONFIG_PM_RUNTIME
++static const struct dev_pm_ops dwc3_device_pm_ops = {
++ .runtime_suspend = dwc3_runtime_suspend,
++ .runtime_resume = dwc3_runtime_resume,
++};
++#define DWC3_DEVICE_PM_OPS (&dwc3_device_pm_ops)
++#else
++#define DWC3_DEVICE_PM_OPS NULL
++#endif
++
++static struct platform_driver dwc3_device_intel_driver = {
++ .probe = dwc3_device_intel_probe,
++ .remove = dwc3_device_intel_remove,
++ .driver = {
++ .name = "dwc3-device",
++ .of_match_table = of_match_ptr(of_dwc3_match),
++ .pm = DWC3_DEVICE_PM_OPS,
++ },
++};
++
++module_platform_driver(dwc3_device_intel_driver);
++
++MODULE_ALIAS("platform:dwc3");
++MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
+diff --git a/drivers/usb/dwc3/dwc3-host-intel.c b/drivers/usb/dwc3/dwc3-host-intel.c
+new file mode 100644
+index 0000000..558547b
+--- /dev/null
++++ b/drivers/usb/dwc3/dwc3-host-intel.c
+@@ -0,0 +1,724 @@
++/*
++ * Copyright (C) 2012 Intel Corp.
++ * Author: Yu Wang
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software Foundation,
++ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/kernel.h>
++#include <linux/device.h>
++#include <linux/dma-mapping.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <linux/pm.h>
++#include <linux/pm_runtime.h>
++#include <linux/usb/otg.h>
++#include <linux/platform_device.h>
++#include <linux/usb/dwc3-intel-mid.h>
++#include "../host/xhci.h"
++#include "core.h"
++#include "otg.h"
++
++#define WAIT_DISC_EVENT_COMPLETE_TIMEOUT 5 /* 100ms */
++
++static int otg_irqnum;
++
++static int dwc3_start_host(struct usb_hcd *hcd);
++static int dwc3_stop_host(struct usb_hcd *hcd);
++static struct platform_driver dwc3_xhci_driver;
++
++static void xhci_dwc3_quirks(struct device *dev, struct xhci_hcd *xhci)
++{
++ /*
++ * As of now platform drivers don't provide MSI support so we ensure
++ * here that the generic code does not try to make a pci_dev from our
++ * dev struct in order to setup MSI
++ *
++ * Synopsys DWC3 controller will generate PLC when link transfer to
++ * compliance/loopback mode.
++ */
++ xhci->quirks |= XHCI_PLAT;
++}
++
++/* called during probe() after chip reset completes */
++static int xhci_dwc3_setup(struct usb_hcd *hcd)
++{
++ return xhci_gen_setup(hcd, xhci_dwc3_quirks);
++}
++
++static int xhci_dwc_bus_resume(struct usb_hcd *hcd)
++{
++ int ret;
++
++ /* before resume bus, delay 1ms to waiting core stable */
++ mdelay(1);
++
++ ret = xhci_bus_resume(hcd);
++ return ret;
++}
++
++static const struct hc_driver xhci_dwc_hc_driver = {
++ .description = "dwc-xhci",
++ .product_desc = "xHCI Host Controller",
++ .hcd_priv_size = sizeof(struct xhci_hcd *),
++
++ /*
++ * generic hardware linkage
++ */
++ .irq = xhci_irq,
++ .flags = HCD_MEMORY | HCD_USB3 | HCD_SHARED,
++
++ /*
++ * basic lifecycle operations
++ */
++ .reset = xhci_dwc3_setup,
++ .start = xhci_run,
++ .stop = xhci_stop,
++ .shutdown = xhci_shutdown,
++
++ /*
++ * managing i/o requests and associated device resources
++ */
++ .urb_enqueue = xhci_urb_enqueue,
++ .urb_dequeue = xhci_urb_dequeue,
++ .alloc_dev = xhci_alloc_dev,
++ .free_dev = xhci_free_dev,
++ .alloc_streams = xhci_alloc_streams,
++ .free_streams = xhci_free_streams,
++ .add_endpoint = xhci_add_endpoint,
++ .drop_endpoint = xhci_drop_endpoint,
++ .endpoint_reset = xhci_endpoint_reset,
++ .check_bandwidth = xhci_check_bandwidth,
++ .reset_bandwidth = xhci_reset_bandwidth,
++ .address_device = xhci_address_device,
++ .update_hub_device = xhci_update_hub_device,
++ .reset_device = xhci_discover_or_reset_device,
++
++ /*
++ * scheduling support
++ */
++ .get_frame_number = xhci_get_frame,
++
++ /* Root hub support */
++ .hub_control = xhci_hub_control,
++ .hub_status_data = xhci_hub_status_data,
++ .bus_suspend = xhci_bus_suspend,
++ .bus_resume = xhci_dwc_bus_resume,
++};
++
++static int if_usb_devices_connected(struct xhci_hcd *xhci)
++{
++ struct usb_device *usb_dev;
++ int i, connected_devices = 0;
++
++ if (!xhci)
++ return -EINVAL;
++
++ usb_dev = xhci->main_hcd->self.root_hub;
++ for (i = 1; i <= usb_dev->maxchild; ++i) {
++ if (usb_hub_find_child(usb_dev, i))
++ connected_devices++;
++ }
++
++ usb_dev = xhci->shared_hcd->self.root_hub;
++ for (i = 1; i <= usb_dev->maxchild; ++i) {
++ if (usb_hub_find_child(usb_dev, i))
++ connected_devices++;
++ }
++
++ if (connected_devices)
++ return 1;
++
++ return 0;
++}
++
++static void dwc_xhci_enable_phy_auto_resume(struct usb_hcd *hcd, bool enable)
++{
++ u32 val;
++
++ val = readl(hcd->regs + GUSB2PHYCFG0);
++ val |= GUSB2PHYCFG_ULPI_EXT_VBUS_DRV;
++ if (enable)
++ val |= GUSB2PHYCFG_ULPI_AUTO_RESUME;
++ else
++ val &= ~GUSB2PHYCFG_ULPI_AUTO_RESUME;
++ writel(val, hcd->regs + GUSB2PHYCFG0);
++}
++
++static void dwc_xhci_enable_phy_suspend(struct usb_hcd *hcd, bool enable)
++{
++ u32 val;
++
++ val = readl(hcd->regs + GUSB3PIPECTL0);
++ if (enable)
++ val |= GUSB3PIPECTL_SUS_EN;
++ else
++ val &= ~GUSB3PIPECTL_SUS_EN;
++ writel(val, hcd->regs + GUSB3PIPECTL0);
++
++ val = readl(hcd->regs + GUSB2PHYCFG0);
++ if (enable)
++ val |= GUSB2PHYCFG_SUS_PHY;
++ else
++ val &= ~GUSB2PHYCFG_SUS_PHY;
++ writel(val, hcd->regs + GUSB2PHYCFG0);
++}
++
++static void dwc_silicon_wa(struct usb_hcd *hcd)
++{
++ void __iomem *addr;
++ u32 val;
++
++ /* Clear GUCTL bit 15 as workaround of DWC controller Bugs
++ * This Bug cause the xHCI driver does not see any
++ * transfer complete events for certain EP after exit
++ * from hibernation mode.*/
++ val = readl(hcd->regs + GUCTL);
++ val &= ~GUCTL_CMDEVADDR;
++ writel(val, hcd->regs + GUCTL);
++
++ /* Disable OTG3-EXI interface by default. It is one
++ * workaround for silicon BUG. It will cause transfer
++ * failed on EP#8 of any USB device.
++ */
++ addr = ioremap_nocache(APBFC_EXIOTG3_MISC0_REG, 4);
++ val = readl(addr);
++ val |= (1 << 3);
++ writel(val, addr);
++ iounmap(addr);
++}
++
++static void dwc_core_reset(struct usb_hcd *hcd)
++{
++ u32 val;
++
++ val = readl(hcd->regs + GCTL);
++ val |= GCTL_CORESOFTRESET;
++ writel(val, hcd->regs + GCTL);
++
++ val = readl(hcd->regs + GUSB3PIPECTL0);
++ val |= GUSB3PIPECTL_PHYSOFTRST;
++ writel(val, hcd->regs + GUSB3PIPECTL0);
++
++ val = readl(hcd->regs + GUSB2PHYCFG0);
++ val |= GUSB2PHYCFG_PHYSOFTRST;
++ writel(val, hcd->regs + GUSB2PHYCFG0);
++
++ msleep(100);
++
++ val = readl(hcd->regs + GUSB3PIPECTL0);
++ val &= ~GUSB3PIPECTL_PHYSOFTRST;
++ writel(val, hcd->regs + GUSB3PIPECTL0);
++
++ val = readl(hcd->regs + GUSB2PHYCFG0);
++ val &= ~GUSB2PHYCFG_PHYSOFTRST;
++ writel(val, hcd->regs + GUSB2PHYCFG0);
++
++ msleep(20);
++
++ val = readl(hcd->regs + GCTL);
++ val &= ~GCTL_CORESOFTRESET;
++ writel(val, hcd->regs + GCTL);
++}
++
++/*
++ * On MERR platform, the suspend clock is 19.2MHz.
++ * Hence PwrDnScale = 19200 / 16 = 1200 (= 0x4B0).
++ * To account for possible jitter of suspend clock and to have margin,
++ * So recommend it to be set to 1250 (= 0x4E2).
++ * */
++static void dwc_set_ssphy_p3_clockrate(struct usb_hcd *hcd)
++{
++ u32 gctl;
++
++ gctl = readl(hcd->regs + GCTL);
++ gctl &= ~GCTL_PWRDNSCALE_MASK;
++ gctl |= GCTL_PWRDNSCALE(0x4E2);
++ writel(gctl, hcd->regs + GCTL);
++}
++
++static ssize_t
++show_pm_get(struct device *_dev, struct device_attribute *attr, char *buf)
++{
++ struct platform_device *pdev = to_platform_device(_dev);
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++
++ pm_runtime_put(hcd->self.controller);
++ return 0;
++
++}
++static ssize_t store_pm_get(struct device *_dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct platform_device *pdev = to_platform_device(_dev);
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++
++ pm_runtime_get(hcd->self.controller);
++ return count;
++
++}
++static DEVICE_ATTR(pm_get, S_IRUGO|S_IWUSR|S_IWGRP,
++ show_pm_get, store_pm_get);
++
++static void dwc_set_host_mode(struct usb_hcd *hcd)
++{
++ writel(0x45801000, hcd->regs + GCTL);
++
++ msleep(20);
++}
++
++static int dwc3_start_host(struct usb_hcd *hcd)
++{
++ int ret = -EINVAL;
++ struct xhci_hcd *xhci;
++ struct usb_hcd *xhci_shared_hcd;
++
++ if (!hcd)
++ return ret;
++
++ if (hcd->rh_registered) {
++ dev_dbg(hcd->self.controller,
++ "%s() - Already registered", __func__);
++ return 0;
++ }
++
++ pm_runtime_get_sync(hcd->self.controller);
++
++ dwc_core_reset(hcd);
++ dwc_silicon_wa(hcd);
++ dwc_set_host_mode(hcd);
++ dwc_set_ssphy_p3_clockrate(hcd);
++
++ /* Clear the hcd->flags.
++ * To prevent incorrect flags set during last time. */
++ hcd->flags = 0;
++
++ ret = usb_add_hcd(hcd, otg_irqnum, IRQF_SHARED);
++ if (ret)
++ return -EINVAL;
++
++ xhci = hcd_to_xhci(hcd);
++ xhci->shared_hcd = usb_create_shared_hcd(&xhci_dwc_hc_driver,
++ hcd->self.controller, dev_name(hcd->self.controller), hcd);
++ if (!xhci->shared_hcd) {
++ ret = -ENOMEM;
++ goto dealloc_usb2_hcd;
++ }
++
++ xhci->quirks |= XHCI_PLAT;
++
++ /* Set the xHCI pointer before xhci_pci_setup() (aka hcd_driver.reset)
++ * is called by usb_add_hcd().
++ */
++ *((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci;
++
++ xhci->shared_hcd->regs = hcd->regs;
++
++ xhci->shared_hcd->rsrc_start = hcd->rsrc_start;
++ xhci->shared_hcd->rsrc_len = hcd->rsrc_len;
++
++ ret = usb_add_hcd(xhci->shared_hcd, otg_irqnum, IRQF_SHARED);
++ if (ret)
++ goto put_usb3_hcd;
++
++ pm_runtime_put(hcd->self.controller);
++
++ ret = device_create_file(hcd->self.controller, &dev_attr_pm_get);
++ if (ret < 0)
++ dev_err(hcd->self.controller,
++ "Can't register sysfs attribute: %d\n", ret);
++
++ dwc3_xhci_driver.shutdown = usb_hcd_platform_shutdown;
++
++ return ret;
++
++put_usb3_hcd:
++ if (xhci->shared_hcd) {
++ xhci_shared_hcd = xhci->shared_hcd;
++ usb_remove_hcd(xhci_shared_hcd);
++ usb_put_hcd(xhci_shared_hcd);
++ }
++
++dealloc_usb2_hcd:
++ local_irq_disable();
++ usb_hcd_irq(0, hcd);
++ local_irq_enable();
++ usb_remove_hcd(hcd);
++
++ kfree(xhci);
++ *((struct xhci_hcd **) hcd->hcd_priv) = NULL;
++
++ pm_runtime_put(hcd->self.controller);
++ return ret;
++}
++
++static int dwc3_stop_host(struct usb_hcd *hcd)
++{
++ int count = 0;
++ struct xhci_hcd *xhci;
++ struct usb_hcd *xhci_shared_hcd;
++
++ if (!hcd)
++ return -EINVAL;
++
++ xhci = hcd_to_xhci(hcd);
++
++ pm_runtime_get_sync(hcd->self.controller);
++
++ /* When plug out micro A cable, there will be two flows be executed.
++ * The first one is xHCI controller get disconnect event. The
++ * second one is PMIC get ID change event. During these events
++ * handling, they both try to call usb_disconnect. Then met some
++ * conflicts and cause kernel panic.
++ * So treat disconnect event as first priority, handle the ID change
++ * event until disconnect event handled done.*/
++ while (if_usb_devices_connected(xhci)) {
++ msleep(20);
++ if (count++ > WAIT_DISC_EVENT_COMPLETE_TIMEOUT)
++ break;
++ };
++ dwc3_xhci_driver.shutdown = NULL;
++
++ if (xhci->shared_hcd) {
++ xhci_shared_hcd = xhci->shared_hcd;
++ usb_remove_hcd(xhci_shared_hcd);
++ usb_put_hcd(xhci_shared_hcd);
++ }
++
++ usb_remove_hcd(hcd);
++
++ kfree(xhci);
++ *((struct xhci_hcd **) hcd->hcd_priv) = NULL;
++
++ dwc_xhci_enable_phy_suspend(hcd, false);
++
++ pm_runtime_put(hcd->self.controller);
++ device_remove_file(hcd->self.controller, &dev_attr_pm_get);
++ return 0;
++}
++static int xhci_dwc_drv_probe(struct platform_device *pdev)
++{
++ struct dwc_otg2 *otg;
++ struct usb_phy *usb_phy;
++ struct dwc_device_par *pdata;
++ struct usb_hcd *hcd;
++ struct resource *res;
++ int retval = 0;
++
++ if (usb_disabled())
++ return -ENODEV;
++
++ pr_debug("initializing FSL-SOC USB Controller\n");
++
++ /* Need platform data for setup */
++ pdata = (struct dwc_device_par *)pdev->dev.platform_data;
++ if (!pdata) {
++ dev_err(&pdev->dev,
++ "No platform data for %s.\n", dev_name(&pdev->dev));
++ return -ENODEV;
++ }
++
++ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++ if (!res) {
++ dev_err(&pdev->dev,
++ "Found HC with no IRQ. Check %s setup!\n",
++ dev_name(&pdev->dev));
++ return -ENODEV;
++ }
++ otg_irqnum = res->start;
++
++ hcd = usb_create_hcd(&xhci_dwc_hc_driver,
++ &pdev->dev, dev_name(&pdev->dev));
++ if (!hcd) {
++ retval = -ENOMEM;
++ return retval;
++ }
++
++ hcd->regs = pdata->io_addr;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ dev_err(&pdev->dev,
++ "Found HC with no IRQ. Check %s setup!\n",
++ dev_name(&pdev->dev));
++ return -ENODEV;
++ }
++ hcd->rsrc_start = res->start;
++ hcd->rsrc_len = res->end - res->start;
++
++ usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
++ if (usb_phy)
++ otg_set_host(usb_phy->otg, &hcd->self);
++
++ otg = container_of(usb_phy->otg, struct dwc_otg2, otg);
++ if (otg) {
++ otg->start_host = dwc3_start_host;
++ otg->stop_host = dwc3_stop_host;
++ }
++
++
++ usb_put_phy(usb_phy);
++
++ /* Enable wakeup irq */
++ hcd->has_wakeup_irq = 1;
++
++ platform_set_drvdata(pdev, hcd);
++ pm_runtime_enable(hcd->self.controller);
++
++ return retval;
++}
++
++static int xhci_dwc_drv_remove(struct platform_device *pdev)
++{
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++ struct usb_phy *usb_phy;
++ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
++
++ usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
++ otg_set_host(usb_phy->otg, NULL);
++ usb_put_phy(usb_phy);
++
++ if (xhci)
++ dwc3_stop_host(hcd);
++ usb_put_hcd(hcd);
++
++ pm_runtime_disable(hcd->self.controller);
++ pm_runtime_set_suspended(hcd->self.controller);
++ return 0;
++}
++
++
++#ifdef CONFIG_PM
++
++#ifdef CONFIG_PM_RUNTIME
++/*
++ * Do nothing in runtime pm callback.
++ * On HVP platform, if make controller go to hibernation mode.
++ * controller will not send IRQ until restore status which
++ * implement in pm runtime resume callback. So there is no
++ * any one can trigger pm_runtime_get to resume USB3 device.
++ * This issue need to continue investigate. So just implement SW logic at here.
++ */
++static int dwc_hcd_runtime_idle(struct device *dev)
++{
++ return 0;
++}
++
++/* dwc_hcd_suspend_common and dwc_hcd_resume_common are refer to
++ * suspend_common and resume_common in usb core.
++ * Because the usb core function just support PCI device.
++ * So re-write them in here to support platform devices.
++ */
++static int dwc_hcd_suspend_common(struct device *dev)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
++ int retval = 0;
++ u32 data = 0;
++
++ if (!xhci) {
++ dev_dbg(dev, "%s: host already stop!\n", __func__);
++ return 0;
++ }
++
++ /* Root hub suspend should have stopped all downstream traffic,
++ * and all bus master traffic. And done so for both the interface
++ * and the stub usb_device (which we check here). But maybe it
++ * didn't; writing sysfs power/state files ignores such rules...
++ */
++ if (HCD_RH_RUNNING(hcd)) {
++ dev_warn(dev, "Root hub is not suspended\n");
++ return -EBUSY;
++ }
++ if (hcd->shared_hcd) {
++ hcd = hcd->shared_hcd;
++ if (HCD_RH_RUNNING(hcd)) {
++ dev_warn(dev, "Secondary root hub is not suspended\n");
++ return -EBUSY;
++ }
++ }
++
++ if (!HCD_DEAD(hcd)) {
++ /* Optimization: Don't suspend if a root-hub wakeup is
++ * pending and it would cause the HCD to wake up anyway.
++ */
++ if (HCD_WAKEUP_PENDING(hcd))
++ return -EBUSY;
++ if (hcd->shared_hcd &&
++ HCD_WAKEUP_PENDING(hcd->shared_hcd))
++ return -EBUSY;
++ if (hcd->state != HC_STATE_SUSPENDED ||
++ xhci->shared_hcd->state != HC_STATE_SUSPENDED)
++ retval = -EINVAL;
++
++ if (!retval) {
++ /* The auto-resume is diabled by default. Need enable it
++ * if there have valid connection. To ensure that when
++ * device resumes, host does resume reflect within
++ * 900 usec as in USB spec.
++ */
++ if (if_usb_devices_connected(xhci) == 1)
++ dwc_xhci_enable_phy_auto_resume(
++ xhci->main_hcd, true);
++
++ /* Ensure that suspend enable are set for
++ * USB2 and USB3 PHY
++ */
++ dwc_xhci_enable_phy_suspend(hcd, true);
++
++ data = readl(hcd->regs + GCTL);
++ data |= GCTL_GBL_HIBERNATION_EN;
++ writel(data, hcd->regs + GCTL);
++ dev_dbg(hcd->self.controller, "set xhci hibernation enable!\n");
++ retval = xhci_suspend(xhci);
++ }
++
++ /* Check again in case wakeup raced with pci_suspend */
++ if ((retval == 0 && HCD_WAKEUP_PENDING(hcd)) ||
++ (retval == 0 && hcd->shared_hcd &&
++ HCD_WAKEUP_PENDING(hcd->shared_hcd))) {
++ xhci_resume(xhci, false);
++ retval = -EBUSY;
++ }
++ if (retval)
++ return retval;
++ }
++
++ synchronize_irq(otg_irqnum);
++
++ return retval;
++
++}
++
++static int dwc_hcd_resume_common(struct device *dev)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
++ int retval = 0;
++
++ if (!xhci)
++ return 0;
++
++ if (HCD_RH_RUNNING(hcd) ||
++ (hcd->shared_hcd &&
++ HCD_RH_RUNNING(hcd->shared_hcd))) {
++ dev_dbg(dev, "can't resume, not suspended!\n");
++ return 0;
++ }
++
++ if (!HCD_DEAD(hcd)) {
++ retval = xhci_resume(xhci, false);
++ if (retval) {
++ dev_err(dev, "PCI post-resume error %d!\n", retval);
++ if (hcd->shared_hcd)
++ usb_hc_died(hcd->shared_hcd);
++ usb_hc_died(hcd);
++ }
++ }
++
++ dev_dbg(dev, "hcd_pci_runtime_resume: %d\n", retval);
++
++ return retval;
++}
++
++static int dwc_hcd_runtime_suspend(struct device *dev)
++{
++ int retval;
++ struct platform_device *pdev = to_platform_device(dev);
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++
++ retval = dwc_hcd_suspend_common(dev);
++
++ if (retval)
++ dwc_xhci_enable_phy_auto_resume(
++ hcd, false);
++
++ dev_dbg(dev, "hcd_pci_runtime_suspend: %d\n", retval);
++ return retval;
++}
++
++static int dwc_hcd_runtime_resume(struct device *dev)
++{
++ int retval;
++ struct platform_device *pdev = to_platform_device(dev);
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++
++ dwc_xhci_enable_phy_auto_resume(
++ hcd, false);
++
++ retval = dwc_hcd_resume_common(dev);
++ dev_dbg(dev, "hcd_pci_runtime_resume: %d\n", retval);
++
++ return retval;
++}
++#else
++#define dwc_hcd_runtime_idle NULL
++#define dwc_hcd_runtime_suspend NULL
++#define dwc_hcd_runtime_resume NULL
++#endif
++
++
++static int dwc_hcd_suspend(struct device *dev)
++{
++ int retval;
++ struct platform_device *pdev = to_platform_device(dev);
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++
++ retval = dwc_hcd_suspend_common(dev);
++
++ if (retval)
++ dwc_xhci_enable_phy_auto_resume(
++ hcd, false);
++
++ dev_dbg(dev, "hcd_pci_runtime_suspend: %d\n", retval);
++ return retval;
++}
++
++static int dwc_hcd_resume(struct device *dev)
++{
++ int retval;
++ struct platform_device *pdev = to_platform_device(dev);
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++
++ dwc_xhci_enable_phy_auto_resume(
++ hcd, false);
++
++ retval = dwc_hcd_resume_common(dev);
++ dev_dbg(dev, "hcd_pci_runtime_resume: %d\n", retval);
++
++ return retval;
++}
++
++static const struct dev_pm_ops dwc_usb_hcd_pm_ops = {
++ .runtime_suspend = dwc_hcd_runtime_suspend,
++ .runtime_resume = dwc_hcd_runtime_resume,
++ .runtime_idle = dwc_hcd_runtime_idle,
++ .suspend = dwc_hcd_suspend,
++ .resume = dwc_hcd_resume,
++};
++#endif
++
++static struct platform_driver dwc3_xhci_driver = {
++ .probe = xhci_dwc_drv_probe,
++ .remove = xhci_dwc_drv_remove,
++ .driver = {
++ .name = "dwc3-host",
++#ifdef CONFIG_PM
++ .pm = &dwc_usb_hcd_pm_ops,
++#endif
++ },
++};
+diff --git a/drivers/usb/dwc3/dwc3-intel-byt.c b/drivers/usb/dwc3/dwc3-intel-byt.c
+new file mode 100644
+index 0000000..adae9ef
+--- /dev/null
++++ b/drivers/usb/dwc3/dwc3-intel-byt.c
+@@ -0,0 +1,970 @@
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/usb/otg.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/freezer.h>
++#include <linux/delay.h>
++#include <linux/kthread.h>
++#include <linux/version.h>
++#include <linux/gpio.h>
++
++#include <linux/usb.h>
++#include <linux/usb/hcd.h>
++#include <linux/usb/gadget.h>
++#include <linux/usb/dwc3-intel-mid.h>
++#include "otg.h"
++
++#define VERSION "2.10a"
++
++static int otg_id = -1;
++static int enable_usb_phy(struct dwc_otg2 *otg, bool on_off);
++static int dwc3_intel_byt_notify_charger_type(struct dwc_otg2 *otg,
++ enum power_supply_charger_event event);
++
++static int charger_detect_enable(struct dwc_otg2 *otg)
++{
++ struct intel_dwc_otg_pdata *data;
++
++ if (!otg || !otg->otg_data)
++ return 0;
++
++ data = (struct intel_dwc_otg_pdata *)otg->otg_data;
++
++ return data->charger_detect_enable;
++}
++
++static int sdp_charging(struct dwc_otg2 *otg)
++{
++ struct intel_dwc_otg_pdata *data;
++
++ if (!otg || !otg->otg_data)
++ return 0;
++
++ data = (struct intel_dwc_otg_pdata *)otg->otg_data;
++
++ return data->sdp_charging;
++}
++
++static void usb2phy_eye_optimization(struct dwc_otg2 *otg)
++{
++ struct usb_phy *phy;
++
++ phy = usb_get_phy(USB_PHY_TYPE_USB2);
++ if (!phy)
++ return;
++
++ /* Set 0x7f for better quality in eye diagram
++ * It means ZHSDRV = 0b11 and IHSTX = 0b1111*/
++ usb_phy_io_write(phy, 0x4f, TUSB1211_VENDOR_SPECIFIC1_SET);
++
++ usb_put_phy(phy);
++}
++
++static int dwc_otg_charger_hwdet(bool enable)
++{
++ int retval;
++ struct usb_phy *phy;
++ struct dwc_otg2 *otg = dwc3_get_otg();
++
++ /* Just return if charger detection is not enabled */
++ if (!charger_detect_enable(otg))
++ return 0;
++
++ phy = usb_get_phy(USB_PHY_TYPE_USB2);
++ if (!phy)
++ return -ENODEV;
++
++ if (enable) {
++ retval = usb_phy_io_write(phy, PWCTRL_HWDETECT,
++ TUSB1211_POWER_CONTROL_SET);
++ if (retval)
++ return retval;
++ otg_dbg(otg, "set HWDETECT\n");
++ } else {
++ retval = usb_phy_io_write(phy, PWCTRL_HWDETECT,
++ TUSB1211_POWER_CONTROL_CLR);
++ if (retval)
++ return retval;
++ otg_dbg(otg, "clear HWDETECT\n");
++ }
++ usb_put_phy(phy);
++
++ return 0;
++}
++
++static ssize_t store_vbus_evt(struct device *_dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ unsigned long flags;
++ struct dwc_otg2 *otg = dwc3_get_otg();
++
++ if (count != 2) {
++ otg_err(otg, "return EINVAL\n");
++ return -EINVAL;
++ }
++
++ if (count > 0 && buf[count-1] == '\n')
++ ((char *) buf)[count-1] = 0;
++
++ switch (buf[0]) {
++ case '1':
++ otg_dbg(otg, "Change the VBUS to High\n");
++ otg->otg_events |= OEVT_B_DEV_SES_VLD_DET_EVNT;
++ spin_lock_irqsave(&otg->lock, flags);
++ dwc3_wakeup_otg_thread(otg);
++ spin_unlock_irqrestore(&otg->lock, flags);
++ return count;
++ case '0':
++ otg_dbg(otg, "Change the VBUS to Low\n");
++ otg->otg_events |= OEVT_A_DEV_SESS_END_DET_EVNT;
++ spin_lock_irqsave(&otg->lock, flags);
++ dwc3_wakeup_otg_thread(otg);
++ spin_unlock_irqrestore(&otg->lock, flags);
++ return count;
++ default:
++ return -EINVAL;
++ }
++
++ return count;
++}
++static DEVICE_ATTR(vbus_evt, S_IWUSR|S_IWGRP,
++ NULL, store_vbus_evt);
++
++
++static ssize_t store_otg_id(struct device *_dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ unsigned long flags;
++ struct dwc_otg2 *otg = dwc3_get_otg();
++
++ if (!otg)
++ return 0;
++ if (count != 2) {
++ otg_err(otg, "return EINVAL\n");
++ return -EINVAL;
++ }
++
++ if (count > 0 && buf[count-1] == '\n')
++ ((char *) buf)[count-1] = 0;
++
++ switch (buf[0]) {
++ case 'a':
++ case 'A':
++ otg_dbg(otg, "Change ID to A\n");
++ otg->user_events |= USER_ID_A_CHANGE_EVENT;
++ spin_lock_irqsave(&otg->lock, flags);
++ dwc3_wakeup_otg_thread(otg);
++ otg_id = 0;
++ spin_unlock_irqrestore(&otg->lock, flags);
++ return count;
++ case 'b':
++ case 'B':
++ otg_dbg(otg, "Change ID to B\n");
++ otg->user_events |= USER_ID_B_CHANGE_EVENT;
++ spin_lock_irqsave(&otg->lock, flags);
++ dwc3_wakeup_otg_thread(otg);
++ otg_id = 1;
++ spin_unlock_irqrestore(&otg->lock, flags);
++ return count;
++ default:
++ otg_err(otg, "Just support change ID to A!\n");
++ return -EINVAL;
++ }
++
++ return count;
++}
++
++static ssize_t
++show_otg_id(struct device *_dev, struct device_attribute *attr, char *buf)
++{
++ char *next;
++ unsigned size, t;
++
++ next = buf;
++ size = PAGE_SIZE;
++
++ t = scnprintf(next, size,
++ "USB OTG ID: %s\n",
++ (otg_id ? "B" : "A")
++ );
++ size -= t;
++ next += t;
++
++ return PAGE_SIZE - size;
++}
++
++static DEVICE_ATTR(otg_id, S_IRUGO|S_IWUSR|S_IWGRP,
++ show_otg_id, store_otg_id);
++
++static void set_sus_phy(struct dwc_otg2 *otg, int bit)
++{
++ u32 data = 0;
++
++ data = otg_read(otg, GUSB2PHYCFG0);
++ if (bit)
++ data |= GUSB2PHYCFG_SUS_PHY;
++ else
++ data &= ~GUSB2PHYCFG_SUS_PHY;
++
++ otg_write(otg, GUSB2PHYCFG0, data);
++
++ data = otg_read(otg, GUSB3PIPECTL0);
++ if (bit)
++ data |= GUSB3PIPECTL_SUS_EN;
++ else
++ data &= ~GUSB3PIPECTL_SUS_EN;
++ otg_write(otg, GUSB3PIPECTL0, data);
++}
++
++static int dwc3_check_gpio_id(struct dwc_otg2 *otg2)
++{
++ struct dwc_otg2 *otg = dwc3_get_otg();
++ struct intel_dwc_otg_pdata *data;
++ int id = 0;
++ int next = 0;
++ int count = 0;
++ unsigned long timeout;
++
++ otg_dbg(otg, "start check gpio id\n");
++
++ data = (struct intel_dwc_otg_pdata *)otg->otg_data;
++
++ /* Polling ID GPIO PIN value for SW debounce as HW debouce chip
++ * is not connected on BYT CR board */
++ if (data && data->gpio_id) {
++ id = gpio_get_value(data->gpio_id);
++
++ /* If get 20 of the same value in a row by GPIO read,
++ * then end SW debouce and return the ID value.
++ * the total length of debouce time is 80ms~100ms for
++ * 20 times GPIO read on BYT CR, which is longer than
++ * normal debounce time done by HW chip.
++ * Also set 200ms timeout value to avoid impact from
++ * pin unstable cases */
++ timeout = jiffies + msecs_to_jiffies(200);
++ while ((count < 20) && (!time_after(jiffies, timeout))) {
++ next = gpio_get_value(data->gpio_id);
++ otg_dbg(otg, "id value pin %d = %d\n",
++ data->gpio_id, next);
++ if (next < 0)
++ return -EINVAL;
++ else if (id == next)
++ count++;
++ else {
++ id = next;
++ count = 0;
++ }
++ }
++ if (count >= 20) {
++ otg_dbg(otg, "id debounce done = %d\n", id);
++ return id;
++ }
++ }
++
++ return -ENODEV;
++}
++
++static irqreturn_t dwc3_gpio_id_irq(int irq, void *dev)
++{
++ struct dwc_otg2 *otg = dwc3_get_otg();
++ struct intel_dwc_otg_pdata *data;
++ int id;
++
++ data = (struct intel_dwc_otg_pdata *)otg->otg_data;
++
++ id = dwc3_check_gpio_id(otg);
++ if (id == 0 || id == 1) {
++ if (data->id != id) {
++ data->id = id;
++ dev_info(otg->dev, "ID notification (id = %d)\n",
++ data->id);
++ atomic_notifier_call_chain(&otg->usb2_phy.notifier,
++ USB_EVENT_ID, &id);
++ }
++ }
++
++ return IRQ_HANDLED;
++}
++
++static void dwc_otg_suspend_discon_work(struct work_struct *work)
++{
++ struct dwc_otg2 *otg = dwc3_get_otg();
++ unsigned long flags;
++
++ otg_dbg(otg, "start suspend_disconn work\n");
++
++ spin_lock_irqsave(&otg->lock, flags);
++ otg->otg_events |= OEVT_A_DEV_SESS_END_DET_EVNT;
++ otg->otg_events &= ~OEVT_B_DEV_SES_VLD_DET_EVNT;
++ dwc3_wakeup_otg_thread(otg);
++ spin_unlock_irqrestore(&otg->lock, flags);
++}
++
++int dwc3_intel_byt_platform_init(struct dwc_otg2 *otg)
++{
++ u32 gctl;
++ int id_value;
++ int retval;
++
++ data = (struct intel_dwc_otg_pdata *)otg->otg_data;
++
++ if (data)
++ INIT_DELAYED_WORK(&data->suspend_discon_work,
++ dwc_otg_suspend_discon_work);
++
++ if (data && data->gpio_cs && data->gpio_reset) {
++ retval = gpio_request(data->gpio_cs, "phy_cs");
++ if (retval < 0) {
++ otg_err(otg, "failed to request CS pin %d\n",
++ data->gpio_cs);
++ return retval;
++ }
++
++ retval = gpio_request(data->gpio_reset, "phy_reset");
++ if (retval < 0) {
++ otg_err(otg, "failed to request RESET pin %d\n",
++ data->gpio_reset);
++ return retval;
++ }
++ }
++
++ if (data && data->gpio_id) {
++ dev_info(otg->dev, "USB ID detection - Enabled - GPIO\n");
++
++ /* Set ID default value to 1 Floating */
++ data->id = 1;
++
++ retval = gpio_request(data->gpio_id, "gpio_id");
++ if (retval < 0) {
++ otg_err(otg, "failed to request ID pin %d\n",
++ data->gpio_id);
++ return retval;
++ }
++
++ retval = gpio_direction_input(data->gpio_id);
++ if (retval < 0) {
++ otg_err(otg, "failed to request ID pin %d\n",
++ data->gpio_id);
++ return retval;
++ }
++
++ retval = request_threaded_irq(gpio_to_irq(data->gpio_id),
++ NULL, dwc3_gpio_id_irq,
++ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
++ IRQF_ONESHOT, "dwc-gpio-id", otg->dev);
++
++ if (retval < 0) {
++ otg_err(otg, "failed to request interrupt gpio ID\n");
++ return retval;
++ }
++
++ otg_dbg(otg, "GPIO ID request/Interrupt reuqest Done\n");
++
++ id_value = dwc3_check_gpio_id(otg);
++ if ((id_value == 0 || id_value == 1) &&
++ (data->id != id_value)) {
++ data->id = id_value;
++ dev_info(otg->dev, "ID notification (id = %d)\n",
++ data->id);
++
++ atomic_notifier_call_chain(&otg->usb2_phy.notifier,
++ USB_EVENT_ID, &id_value);
++ } else
++ otg_dbg(otg, "Get incorrect ID value %d\n", id_value);
++ }
++
++ /* Don't let phy go to suspend mode, which
++ * will cause FS/LS devices enum failed in host mode.
++ */
++ set_sus_phy(otg, 0);
++
++ retval = device_create_file(otg->dev, &dev_attr_otg_id);
++ if (retval < 0) {
++ otg_dbg(otg,
++ "Can't register sysfs attribute: %d\n", retval);
++ return -ENOMEM;
++ }
++
++ retval = device_create_file(otg->dev, &dev_attr_vbus_evt);
++ if (retval < 0) {
++ otg_dbg(otg,
++ "Can't register sysfs attribute: %d\n", retval);
++ return -ENOMEM;
++ }
++
++ otg_dbg(otg, "\n");
++ otg_write(otg, OEVTEN, 0);
++ otg_write(otg, OCTL, 0);
++ gctl = otg_read(otg, GCTL);
++ gctl |= GCTL_PRT_CAP_DIR_OTG << GCTL_PRT_CAP_DIR_SHIFT;
++ otg_write(otg, GCTL, gctl);
++
++ return 0;
++}
++
++/* Disable auto-resume feature for USB2 PHY. This is one
++ * silicon workaround. It will cause fabric timeout error
++ * for LS case after resume from hibernation */
++static void disable_phy_auto_resume(struct dwc_otg2 *otg)
++{
++ u32 data = 0;
++
++ data = otg_read(otg, GUSB2PHYCFG0);
++ data &= ~GUSB2PHYCFG_ULPI_AUTO_RESUME;
++ otg_write(otg, GUSB2PHYCFG0, data);
++}
++
++/* This function will control VUSBPHY to power gate/ungate USBPHY */
++static int enable_usb_phy(struct dwc_otg2 *otg, bool on_off)
++{
++ struct intel_dwc_otg_pdata *data;
++
++ data = (struct intel_dwc_otg_pdata *)otg->otg_data;
++
++ if (data && data->gpio_cs && data->gpio_reset) {
++ if (on_off) {
++ /* Turn ON phy via CS pin */
++ gpio_direction_output(data->gpio_cs, 1);
++ usleep_range(200, 300);
++
++ /* Do PHY reset after enable the PHY */
++ gpio_direction_output(data->gpio_reset, 0);
++ usleep_range(200, 500);
++ gpio_set_value(data->gpio_reset, 1);
++ msleep(30);
++ } else {
++ /* Turn OFF phy via CS pin */
++ gpio_direction_output(data->gpio_cs, 0);
++ }
++ }
++ return 0;
++}
++
++int dwc3_intel_byt_get_id(struct dwc_otg2 *otg)
++{
++ /* For BYT ID is not connected to USB, always FLOAT */
++ return RID_FLOAT;
++}
++
++int dwc3_intel_byt_b_idle(struct dwc_otg2 *otg)
++{
++ u32 gctl, tmp;
++
++ enable_usb_phy(otg, false);
++ dwc_otg_charger_hwdet(false);
++
++ /* Disable hibernation mode by default */
++ gctl = otg_read(otg, GCTL);
++ gctl &= ~GCTL_GBL_HIBERNATION_EN;
++ otg_write(otg, GCTL, gctl);
++
++ /* Reset ADP related registers */
++ otg_write(otg, ADPCFG, 0);
++ otg_write(otg, ADPCTL, 0);
++ otg_write(otg, ADPEVTEN, 0);
++ tmp = otg_read(otg, ADPEVT);
++ otg_write(otg, ADPEVT, tmp);
++
++ otg_write(otg, OCFG, 0);
++ otg_write(otg, OEVTEN, 0);
++ tmp = otg_read(otg, OEVT);
++ otg_write(otg, OEVT, tmp);
++ otg_write(otg, OCTL, OCTL_PERI_MODE);
++
++ /* Force config to device mode as default */
++ gctl = otg_read(otg, GCTL);
++ gctl &= ~GCTL_PRT_CAP_DIR;
++ gctl |= GCTL_PRT_CAP_DIR_DEV << GCTL_PRT_CAP_DIR_SHIFT;
++ otg_write(otg, GCTL, gctl);
++
++ mdelay(100);
++
++ return 0;
++}
++
++static int dwc3_intel_byt_set_power(struct usb_phy *_otg,
++ unsigned ma)
++{
++ unsigned long flags;
++ struct dwc_otg2 *otg = dwc3_get_otg();
++ struct power_supply_cable_props cap;
++ struct intel_dwc_otg_pdata *data;
++
++ /* Just return if charger detection is not enabled */
++ if (!charger_detect_enable(otg))
++ return 0;
++
++ data = (struct intel_dwc_otg_pdata *)otg->otg_data;
++
++ /* Needn't notify charger capability if charger_detection disable */
++ if (!charger_detect_enable(otg) && !sdp_charging(otg))
++ return 0;
++ else if (otg->charging_cap.chrg_type !=
++ POWER_SUPPLY_CHARGER_TYPE_USB_SDP) {
++ otg_err(otg, "%s: currently, chrg type is not SDP!\n",
++ __func__);
++ return -EINVAL;
++ }
++
++ if (ma == OTG_DEVICE_SUSPEND) {
++ spin_lock_irqsave(&otg->lock, flags);
++ cap.chrg_type = otg->charging_cap.chrg_type;
++ cap.ma = otg->charging_cap.ma;
++ cap.chrg_evt = POWER_SUPPLY_CHARGER_EVENT_SUSPEND;
++ spin_unlock_irqrestore(&otg->lock, flags);
++
++ /* ma is zero mean D+/D- opened cable.
++ * If SMIP set, then notify 500ma.
++ * Otherwise, notify 0ma.
++ */
++ if (!cap.ma) {
++ if (data->charging_compliance) {
++ cap.ma = 500;
++ cap.chrg_evt =
++ POWER_SUPPLY_CHARGER_EVENT_CONNECT;
++ }
++ /* For standard SDP, if SMIP set, then ignore suspend */
++ } else if (data->charging_compliance)
++ return 0;
++ /* Stander SDP(cap.ma != 0) and SMIP not set.
++ * Should send 0ma with SUSPEND event
++ */
++ else
++ cap.ma = 2;
++
++ if (sdp_charging(otg))
++ atomic_notifier_call_chain(&otg->usb2_phy.notifier,
++ USB_EVENT_ENUMERATED, &cap.ma);
++ else
++ atomic_notifier_call_chain(&otg->usb2_phy.notifier,
++ USB_EVENT_CHARGER, &cap);
++ otg_dbg(otg, "Notify EM CHARGER_EVENT_SUSPEND\n");
++
++ return 0;
++ } else if (ma == OTG_DEVICE_RESUME) {
++ otg_dbg(otg, "Notify EM CHARGER_EVENT_CONNECT\n");
++ dwc3_intel_byt_notify_charger_type(otg,
++ POWER_SUPPLY_CHARGER_EVENT_CONNECT);
++
++ return 0;
++ }
++
++ /* For SMIP set case, only need to report 500/900ma */
++ if (data->charging_compliance) {
++ if ((ma != OTG_USB2_500MA) &&
++ (ma != OTG_USB3_900MA))
++ return 0;
++ }
++
++ /* Covert macro to integer number*/
++ switch (ma) {
++ case OTG_USB2_100MA:
++ ma = 100;
++ break;
++ case OTG_USB3_150MA:
++ ma = 150;
++ break;
++ case OTG_USB2_500MA:
++ ma = 500;
++ break;
++ case OTG_USB3_900MA:
++ ma = 900;
++ break;
++ default:
++ otg_err(otg, "Device driver set invalid SDP current value!\n");
++ return -EINVAL;
++ }
++
++ spin_lock_irqsave(&otg->lock, flags);
++ otg->charging_cap.ma = ma;
++ spin_unlock_irqrestore(&otg->lock, flags);
++
++ dwc3_intel_byt_notify_charger_type(otg,
++ POWER_SUPPLY_CHARGER_EVENT_CONNECT);
++
++ return 0;
++}
++
++int dwc3_intel_byt_enable_vbus(struct dwc_otg2 *otg, int enable)
++{
++ /* Return 0, as VBUS is controlled by FSA in BYT */
++ return 0;
++}
++
++static int dwc3_intel_byt_notify_charger_type(struct dwc_otg2 *otg,
++ enum power_supply_charger_event event)
++{
++ struct power_supply_cable_props cap;
++ unsigned long flags;
++
++ /* Just return if charger detection is not enabled */
++ if (!charger_detect_enable(otg) && !sdp_charging(otg))
++ return 0;
++
++ if (event > POWER_SUPPLY_CHARGER_EVENT_DISCONNECT) {
++ otg_err(otg,
++ "%s: Invalid power_supply_charger_event!\n", __func__);
++ return -EINVAL;
++ }
++
++ if ((otg->charging_cap.chrg_type ==
++ POWER_SUPPLY_CHARGER_TYPE_USB_SDP) &&
++ ((otg->charging_cap.ma != 100) &&
++ (otg->charging_cap.ma != 150) &&
++ (otg->charging_cap.ma != 500) &&
++ (otg->charging_cap.ma != 900))) {
++ otg_err(otg, "%s: invalid SDP current!\n", __func__);
++ return -EINVAL;
++ }
++
++ spin_lock_irqsave(&otg->lock, flags);
++ cap.chrg_type = otg->charging_cap.chrg_type;
++ cap.ma = otg->charging_cap.ma;
++ cap.chrg_evt = event;
++ spin_unlock_irqrestore(&otg->lock, flags);
++
++ if (sdp_charging(otg))
++ atomic_notifier_call_chain(&otg->usb2_phy.notifier,
++ USB_EVENT_ENUMERATED, &cap.ma);
++ else
++ atomic_notifier_call_chain(&otg->usb2_phy.notifier,
++ USB_EVENT_CHARGER, &cap);
++
++ return 0;
++}
++
++static enum power_supply_charger_cable_type
++ dwc3_intel_byt_get_charger_type(struct dwc_otg2 *otg)
++{
++ struct usb_phy *phy;
++ u8 val, vdat_det, chgd_serx_dm;
++ unsigned long timeout, interval;
++ enum power_supply_charger_cable_type type =
++ POWER_SUPPLY_CHARGER_TYPE_NONE;
++
++ /* No need to do charger detection if not enabled */
++ if (!charger_detect_enable(otg))
++ return POWER_SUPPLY_CHARGER_TYPE_USB_SDP;
++
++ phy = usb_get_phy(USB_PHY_TYPE_USB2);
++ if (!phy) {
++ otg_err(otg, "Get USB2 PHY failed\n");
++ return POWER_SUPPLY_CHARGER_TYPE_NONE;
++ }
++
++ /* PHY Enable:
++ * Power on PHY
++ */
++ enable_usb_phy(otg, true);
++
++ /* Wait 10ms (~5ms before PHY de-asserts DIR,
++ * XXus for initial Link reg sync-up).*/
++ msleep(20);
++
++ /* DCD Enable: Change OPMODE to 01 (Non-driving),
++ * TermSel to 0, &
++ * XcvrSel to 01 (enable FS xcvr)
++ */
++ usb_phy_io_write(phy, FUNCCTRL_OPMODE(1) | FUNCCTRL_XCVRSELECT(1),
++ TUSB1211_FUNC_CTRL_SET);
++
++ usb_phy_io_write(phy, FUNCCTRL_OPMODE(2) | FUNCCTRL_XCVRSELECT(2)
++ | FUNCCTRL_TERMSELECT,
++ TUSB1211_FUNC_CTRL_CLR);
++
++ /*Enable SW control*/
++ usb_phy_io_write(phy, PWCTRL_SW_CONTROL, TUSB1211_POWER_CONTROL_SET);
++
++ /* Enable IDPSRC */
++ usb_phy_io_write(phy, VS3_CHGD_IDP_SRC_EN,
++ TUSB1211_VENDOR_SPECIFIC3_SET);
++
++ /* Check DCD result, use same polling parameter */
++ timeout = jiffies + msecs_to_jiffies(DATACON_TIMEOUT);
++ interval = DATACON_INTERVAL * 1000; /* us */
++
++ /* DCD Check:
++ * Delay 66.5 ms. (Note:
++ * TIDP_SRC_ON + TCHGD_SERX_DEB =
++ * 347.8us + 66.1ms).
++ */
++ usleep_range(66500, 67000);
++
++ while (!time_after(jiffies, timeout)) {
++ /* Read DP logic level. */
++ val = usb_phy_io_read(phy, TUSB1211_VENDOR_SPECIFIC4);
++ if (val < 0) {
++ otg_err(otg, "ULPI read error! try again\n");
++ continue;
++ }
++
++ if (!(val & VS4_CHGD_SERX_DP)) {
++ otg_info(otg, "Data contact detected!\n");
++ break;
++ }
++
++ /* Polling interval */
++ usleep_range(interval, interval + 2000);
++ }
++
++ /* Disable DP pullup (Idp_src) */
++ usb_phy_io_write(phy, VS3_CHGD_IDP_SRC_EN,
++ TUSB1211_VENDOR_SPECIFIC3_CLR);
++
++ /* SE1 Det Enable:
++ * Read DP/DM logic level. Note: use DEBUG
++ * because VS4 isn’t enabled in this situation.
++ */
++ val = usb_phy_io_read(phy, TUSB1211_DEBUG);
++ if (val < 0)
++ otg_err(otg, "ULPI read error!\n");
++
++ val &= DEBUG_LINESTATE;
++
++ /* If '11': SE1 detected; goto 'Cleanup'.
++ * Else: goto 'Pri Det Enable'.
++ */
++ if (val == 3) {
++ type = POWER_SUPPLY_CHARGER_TYPE_SE1;
++ goto cleanup;
++ }
++
++ /* Pri Det Enable:
++ * Enable VDPSRC.
++ */
++ usb_phy_io_write(phy, PWCTRL_DP_VSRC_EN, TUSB1211_POWER_CONTROL_SET);
++
++ /* Wait >106.1ms (40ms for BC
++ * Tvdpsrc_on, 66.1ms for TI CHGD_SERX_DEB).
++ */
++ msleep(107);
++
++ /* Pri Det Check:
++ * Check if DM > VDATREF.
++ */
++ vdat_det = usb_phy_io_read(phy, TUSB1211_POWER_CONTROL);
++ if (vdat_det < 0)
++ otg_err(otg, "ULPI read error!\n");
++
++ vdat_det &= PWCTRL_VDAT_DET;
++
++ /* Check if DM<VLGC */
++ chgd_serx_dm = usb_phy_io_read(phy, TUSB1211_VENDOR_SPECIFIC4);
++ if (chgd_serx_dm < 0)
++ otg_err(otg, "ULPI read error!\n");
++
++ chgd_serx_dm &= VS4_CHGD_SERX_DM;
++
++ /* If VDAT_DET==0 || CHGD_SERX_DM==1: SDP detected
++ * If VDAT_DET==1 && CHGD_SERX_DM==0: CDP/DCP
++ */
++ if (vdat_det == 0 || chgd_serx_dm == 1)
++ type = POWER_SUPPLY_CHARGER_TYPE_USB_SDP;
++
++ /* Disable VDPSRC. */
++ usb_phy_io_write(phy, PWCTRL_DP_VSRC_EN, TUSB1211_POWER_CONTROL_CLR);
++
++ /* If SDP, goto “Cleanup”.
++ * Else, goto “Sec Det Enable”
++ */
++ if (type == POWER_SUPPLY_CHARGER_TYPE_USB_SDP)
++ goto cleanup;
++
++ /* Sec Det Enable:
++ * delay 1ms.
++ */
++ usleep_range(1000, 1500);
++
++ /* Swap DP & DM */
++ usb_phy_io_write(phy, VS1_DATAPOLARITY, TUSB1211_VENDOR_SPECIFIC1_CLR);
++
++ /* Enable 'VDMSRC'. */
++ usb_phy_io_write(phy, PWCTRL_DP_VSRC_EN, TUSB1211_POWER_CONTROL_SET);
++
++ /* Wait >73ms (40ms for BC Tvdmsrc_on, 33ms for TI TVDPSRC_DEB) */
++ msleep(80);
++
++ /* Sec Det Check:
++ * Check if DP>VDATREF.
++ */
++ val = usb_phy_io_read(phy, TUSB1211_POWER_CONTROL);
++ if (val < 0)
++ otg_err(otg, "ULPI read error!\n");
++
++ val &= PWCTRL_VDAT_DET;
++
++ /* If VDAT_DET==0: CDP detected.
++ * If VDAT_DET==1: DCP detected.
++ */
++ if (!val)
++ type = POWER_SUPPLY_CHARGER_TYPE_USB_CDP;
++ else
++ type = POWER_SUPPLY_CHARGER_TYPE_USB_DCP;
++
++ /* Disable VDMSRC. */
++ usb_phy_io_write(phy, PWCTRL_DP_VSRC_EN, TUSB1211_POWER_CONTROL_CLR);
++
++ /* Swap DP & DM. */
++ usb_phy_io_write(phy, VS1_DATAPOLARITY, TUSB1211_VENDOR_SPECIFIC1_SET);
++
++cleanup:
++
++ /* If DCP detected, assert VDPSRC. */
++ if (type == POWER_SUPPLY_CHARGER_TYPE_USB_DCP)
++ usb_phy_io_write(phy, PWCTRL_SW_CONTROL | PWCTRL_DP_VSRC_EN,
++ TUSB1211_POWER_CONTROL_SET);
++
++ usb_put_phy(phy);
++
++ switch (type) {
++ case POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK:
++ case POWER_SUPPLY_CHARGER_TYPE_ACA_A:
++ case POWER_SUPPLY_CHARGER_TYPE_ACA_B:
++ case POWER_SUPPLY_CHARGER_TYPE_ACA_C:
++ case POWER_SUPPLY_CHARGER_TYPE_USB_DCP:
++ case POWER_SUPPLY_CHARGER_TYPE_USB_CDP:
++ case POWER_SUPPLY_CHARGER_TYPE_SE1:
++ dwc_otg_charger_hwdet(true);
++ break;
++ default:
++ break;
++ };
++
++ return type;
++}
++
++static int dwc3_intel_byt_handle_notification(struct notifier_block *nb,
++ unsigned long event, void *data)
++{
++ struct dwc_otg2 *otg = dwc3_get_otg();
++ int state, val;
++ unsigned long flags;
++
++ if (!otg)
++ return NOTIFY_BAD;
++
++ val = *(int *)data;
++
++ spin_lock_irqsave(&otg->lock, flags);
++ switch (event) {
++ case USB_EVENT_VBUS:
++ if (val) {
++ otg->otg_events |= OEVT_B_DEV_SES_VLD_DET_EVNT;
++ otg->otg_events &= ~OEVT_A_DEV_SESS_END_DET_EVNT;
++ } else {
++ otg->otg_events |= OEVT_A_DEV_SESS_END_DET_EVNT;
++ otg->otg_events &= ~OEVT_B_DEV_SES_VLD_DET_EVNT;
++ }
++ state = NOTIFY_OK;
++ break;
++ default:
++ otg_dbg(otg, "DWC OTG Notify unknow notify message\n");
++ state = NOTIFY_DONE;
++ }
++ dwc3_wakeup_otg_thread(otg);
++ spin_unlock_irqrestore(&otg->lock, flags);
++
++ return state;
++
++}
++
++int dwc3_intel_byt_prepare_start_host(struct dwc_otg2 *otg)
++{
++ return 0;
++}
++
++int dwc3_intel_byt_prepare_start_peripheral(struct dwc_otg2 *otg)
++{
++ enable_usb_phy(otg, true);
++ usb2phy_eye_optimization(otg);
++ disable_phy_auto_resume(otg);
++
++ return 0;
++}
++
++int dwc3_intel_byt_suspend(struct dwc_otg2 *otg)
++{
++ struct pci_dev *pci_dev;
++ pci_power_t state = PCI_D3hot;
++
++ if (!otg)
++ return 0;
++
++ pci_dev = to_pci_dev(otg->dev);
++
++ set_sus_phy(otg, 1);
++
++ if (pci_save_state(pci_dev)) {
++ otg_err(otg, "pci_save_state failed!\n");
++ return -EIO;
++ }
++
++ pci_disable_device(pci_dev);
++ pci_set_power_state(pci_dev, state);
++
++ return 0;
++}
++
++int dwc3_intel_byt_resume(struct dwc_otg2 *otg)
++{
++ struct pci_dev *pci_dev = to_pci_dev(otg->dev);
++
++ if (!otg)
++ return 0;
++
++ /* From synopsys spec 12.2.11.
++ * Software cannot access memory-mapped I/O space
++ * for 10ms.
++ */
++ mdelay(10);
++
++ pci_restore_state(pci_dev);
++ if (pci_enable_device(pci_dev) < 0) {
++ otg_err(otg, "pci_enable_device failed.\n");
++ return -EIO;
++ }
++
++ set_sus_phy(otg, 0);
++
++ return 0;
++}
++
++struct dwc3_otg_hw_ops dwc3_intel_byt_otg_pdata = {
++ .mode = DWC3_DEVICE_ONLY,
++ .bus = DWC3_PCI,
++ .get_id = dwc3_intel_byt_get_id,
++ .b_idle = dwc3_intel_byt_b_idle,
++ .set_power = dwc3_intel_byt_set_power,
++ .enable_vbus = dwc3_intel_byt_enable_vbus,
++ .platform_init = dwc3_intel_byt_platform_init,
++ .get_charger_type = dwc3_intel_byt_get_charger_type,
++ .otg_notifier_handler = dwc3_intel_byt_handle_notification,
++ .prepare_start_peripheral = dwc3_intel_byt_prepare_start_peripheral,
++ .prepare_start_host = dwc3_intel_byt_prepare_start_host,
++ .notify_charger_type = dwc3_intel_byt_notify_charger_type,
++
++ .suspend = dwc3_intel_byt_suspend,
++ .resume = dwc3_intel_byt_resume,
++};
++
++static int __init dwc3_intel_byt_init(void)
++{
++ return dwc3_otg_register(&dwc3_intel_byt_otg_pdata);
++}
++module_init(dwc3_intel_byt_init);
++
++static void __exit dwc3_intel_byt_exit(void)
++{
++ dwc3_otg_unregister(&dwc3_intel_byt_otg_pdata);
++}
++module_exit(dwc3_intel_byt_exit);
++
++MODULE_AUTHOR("Wang Yu <yu.y.wang@intel.com>");
++MODULE_AUTHOR("Wu, Hao <hao.wu@intel.com>");
++MODULE_DESCRIPTION("DWC3 Intel BYT OTG Driver");
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_VERSION(VERSION);
+diff --git a/drivers/usb/dwc3/dwc3-intel-mrfl.c b/drivers/usb/dwc3/dwc3-intel-mrfl.c
+new file mode 100644
+index 0000000..981c841
+--- /dev/null
++++ b/drivers/usb/dwc3/dwc3-intel-mrfl.c
+@@ -0,0 +1,992 @@
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/usb/otg.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/freezer.h>
++#include <linux/delay.h>
++#include <linux/kthread.h>
++#include <linux/version.h>
++
++#include <linux/usb.h>
++#include <linux/usb/hcd.h>
++#include <linux/usb/gadget.h>
++#include <linux/usb/dwc3-intel-mid.h>
++#include <asm/intel_scu_pmic.h>
++#include "otg.h"
++
++#define VERSION "2.10a"
++
++static int otg_id = -1;
++static int enable_usb_phy(struct dwc_otg2 *otg, bool on_off);
++static int dwc3_intel_notify_charger_type(struct dwc_otg2 *otg,
++ enum power_supply_charger_event event);
++static struct power_supply_cable_props cap_record;
++
++static int charger_detect_enable(struct dwc_otg2 *otg)
++{
++ struct intel_dwc_otg_pdata *data;
++
++ if (!otg || !otg->otg_data)
++ return 0;
++
++ data = (struct intel_dwc_otg_pdata *)otg->otg_data;
++
++ return data->charger_detect_enable;
++}
++
++static int is_basin_cove(struct dwc_otg2 *otg)
++{
++ struct intel_dwc_otg_pdata *data;
++ if (!otg || !otg->otg_data)
++ return -EINVAL;
++
++ data = (struct intel_dwc_otg_pdata *)otg->otg_data;
++
++ return data->pmic_type == BASIN_COVE;
++}
++
++static int is_hybridvp(struct dwc_otg2 *otg)
++{
++ struct intel_dwc_otg_pdata *data;
++ if (!otg || !otg->otg_data)
++ return -EINVAL;
++
++ data = (struct intel_dwc_otg_pdata *)otg->otg_data;
++
++ return data->is_hvp;
++}
++
++static void usb2phy_eye_optimization(struct dwc_otg2 *otg)
++{
++ struct usb_phy *phy;
++
++ phy = usb_get_phy(USB_PHY_TYPE_USB2);
++ if (!phy)
++ return;
++
++ /* Set 0x7f for better quality in eye diagram
++ * It means ZHSDRV = 0b11 and IHSTX = 0b1111*/
++ usb_phy_io_write(phy, 0x7f, TUSB1211_VENDOR_SPECIFIC1_SET);
++
++ usb_put_phy(phy);
++}
++
++
++/* As we use SW mode to do charger detection, need to notify HW
++ * the result SW get, charging port or not */
++static int dwc_otg_charger_hwdet(bool enable)
++{
++ int retval;
++ struct usb_phy *phy;
++ struct dwc_otg2 *otg = dwc3_get_otg();
++
++ /* Just return if charger detection is not enabled */
++ if (!charger_detect_enable(otg))
++ return 0;
++
++ phy = usb_get_phy(USB_PHY_TYPE_USB2);
++ if (!phy)
++ return -ENODEV;
++
++ if (enable) {
++ retval = usb_phy_io_write(phy, PWCTRL_HWDETECT,
++ TUSB1211_POWER_CONTROL_SET);
++ if (retval)
++ return retval;
++ otg_dbg(otg, "set HWDETECT\n");
++ } else {
++ retval = usb_phy_io_write(phy, PWCTRL_HWDETECT,
++ TUSB1211_POWER_CONTROL_CLR);
++ if (retval)
++ return retval;
++ otg_dbg(otg, "clear HWDETECT\n");
++ }
++ usb_put_phy(phy);
++
++ return 0;
++}
++
++static enum power_supply_charger_cable_type
++ basin_cove_aca_check(struct dwc_otg2 *otg)
++{
++ u8 rarbrc;
++ int ret;
++ enum power_supply_charger_cable_type type =
++ POWER_SUPPLY_CHARGER_TYPE_NONE;
++
++ ret = intel_scu_ipc_update_register(PMIC_USBIDCTRL,
++ USBIDCTRL_ACA_DETEN_D1,
++ USBIDCTRL_ACA_DETEN_D1);
++ if (ret)
++ otg_err(otg, "Fail to enable ACA&ID detection logic\n");
++
++ /* Wait >66.1ms (for TCHGD_SERX_DEB) */
++ msleep(66);
++
++ /* Read decoded RID value */
++ ret = intel_scu_ipc_ioread8(PMIC_USBIDSTS, &rarbrc);
++ if (ret)
++ otg_err(otg, "Fail to read decoded RID value\n");
++ rarbrc &= USBIDSTS_ID_RARBRC_STS(3);
++ rarbrc >>= 1;
++
++ /* If ID_RARBRC_STS==01: ACA-Dock detected
++ * If ID_RARBRC_STS==00: MHL detected
++ */
++ if (rarbrc == 1) {
++ /* ACA-Dock */
++ type = POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK;
++ } else if (!rarbrc) {
++ /* MHL */
++ type = POWER_SUPPLY_CHARGER_TYPE_MHL;
++ }
++
++ ret = intel_scu_ipc_update_register(PMIC_USBIDCTRL,
++ USBIDCTRL_ACA_DETEN_D1,
++ 0);
++ if (ret)
++ otg_err(otg, "Fail to enable ACA&ID detection logic\n");
++
++ return type;
++}
++
++static enum power_supply_charger_cable_type
++ dwc3_intel_aca_check(struct dwc_otg2 *otg)
++{
++ return basin_cove_aca_check(otg);
++}
++
++static ssize_t store_otg_id(struct device *_dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ unsigned long flags;
++ struct dwc_otg2 *otg = dwc3_get_otg();
++
++ if (!otg)
++ return 0;
++ if (count != 2) {
++ otg_err(otg, "return EINVAL\n");
++ return -EINVAL;
++ }
++
++ if (count > 0 && buf[count-1] == '\n')
++ ((char *) buf)[count-1] = 0;
++
++ switch (buf[0]) {
++ case 'a':
++ case 'A':
++ otg_dbg(otg, "Change ID to A\n");
++ otg->user_events |= USER_ID_A_CHANGE_EVENT;
++ spin_lock_irqsave(&otg->lock, flags);
++ dwc3_wakeup_otg_thread(otg);
++ otg_id = 0;
++ spin_unlock_irqrestore(&otg->lock, flags);
++ return count;
++ case 'b':
++ case 'B':
++ otg_dbg(otg, "Change ID to B\n");
++ otg->user_events |= USER_ID_B_CHANGE_EVENT;
++ spin_lock_irqsave(&otg->lock, flags);
++ dwc3_wakeup_otg_thread(otg);
++ otg_id = 1;
++ spin_unlock_irqrestore(&otg->lock, flags);
++ return count;
++ default:
++ otg_err(otg, "Just support change ID to A!\n");
++ return -EINVAL;
++ }
++
++ return count;
++}
++
++static ssize_t
++show_otg_id(struct device *_dev, struct device_attribute *attr, char *buf)
++{
++ char *next;
++ unsigned size, t;
++
++ next = buf;
++ size = PAGE_SIZE;
++
++ t = scnprintf(next, size,
++ "USB OTG ID: %s\n",
++ (otg_id ? "B" : "A")
++ );
++ size -= t;
++ next += t;
++
++ return PAGE_SIZE - size;
++}
++
++static DEVICE_ATTR(otg_id, S_IRUGO|S_IWUSR|S_IWGRP,
++ show_otg_id, store_otg_id);
++
++static void set_sus_phy(struct dwc_otg2 *otg, int bit)
++{
++ u32 data = 0;
++
++ data = otg_read(otg, GUSB2PHYCFG0);
++ if (bit)
++ data |= GUSB2PHYCFG_SUS_PHY;
++ else
++ data &= ~GUSB2PHYCFG_SUS_PHY;
++
++ otg_write(otg, GUSB2PHYCFG0, data);
++
++ data = otg_read(otg, GUSB3PIPECTL0);
++ if (bit)
++ data |= GUSB3PIPECTL_SUS_EN;
++ else
++ data &= ~GUSB3PIPECTL_SUS_EN;
++ otg_write(otg, GUSB3PIPECTL0, data);
++}
++
++int dwc3_intel_platform_init(struct dwc_otg2 *otg)
++{
++ u32 gctl;
++ int retval;
++
++ otg_info(otg, "De-assert USBRST# to enable PHY\n");
++ retval = intel_scu_ipc_iowrite8(PMIC_USBPHYCTRL,
++ PMIC_USBPHYCTRL_D0);
++ if (retval)
++ otg_err(otg, "Fail to de-assert USBRST#\n");
++
++ /* Don't let phy go to suspend mode, which
++ * will cause FS/LS devices enum failed in host mode.
++ */
++ set_sus_phy(otg, 0);
++
++ retval = device_create_file(otg->dev, &dev_attr_otg_id);
++ if (retval < 0) {
++ otg_dbg(otg,
++ "Can't register sysfs attribute: %d\n", retval);
++ return -ENOMEM;
++ }
++
++ otg_dbg(otg, "\n");
++ otg_write(otg, OEVTEN, 0);
++ otg_write(otg, OCTL, 0);
++ gctl = otg_read(otg, GCTL);
++ gctl |= GCTL_PRT_CAP_DIR_OTG << GCTL_PRT_CAP_DIR_SHIFT;
++ otg_write(otg, GCTL, gctl);
++
++ return 0;
++}
++
++/* Disable auto-resume feature for USB2 PHY. This is one
++ * silicon workaround. It will cause fabric timeout error
++ * for LS case after resume from hibernation */
++static void disable_phy_auto_resume(struct dwc_otg2 *otg)
++{
++ u32 data = 0;
++
++ data = otg_read(otg, GUSB2PHYCFG0);
++ data &= ~GUSB2PHYCFG_ULPI_AUTO_RESUME;
++ otg_write(otg, GUSB2PHYCFG0, data);
++}
++
++/* This function will control VUSBPHY to power gate/ungate USBPHY */
++static int enable_usb_phy(struct dwc_otg2 *otg, bool on_off)
++{
++ int ret;
++
++ if (on_off) {
++ ret = intel_scu_ipc_update_register(PMIC_VLDOCNT,
++ 0xff, PMIC_VLDOCNT_VUSBPHYEN);
++ if (ret)
++ otg_err(otg, "Fail to enable VBUSPHY\n");
++
++ msleep(20);
++ } else {
++ ret = intel_scu_ipc_update_register(PMIC_VLDOCNT,
++ 0x00, PMIC_VLDOCNT_VUSBPHYEN);
++ if (ret)
++ otg_err(otg, "Fail to disable VBUSPHY\n");
++ }
++
++ return 0;
++}
++
++int basin_cove_get_id(struct dwc_otg2 *otg)
++{
++ int ret, id = RID_UNKNOWN;
++ u8 idsts, pmic_id;
++
++ ret = intel_scu_ipc_update_register(PMIC_USBIDCTRL,
++ USBIDCTRL_ACA_DETEN_D1 | PMIC_USBPHYCTRL_D0,
++ USBIDCTRL_ACA_DETEN_D1 | PMIC_USBPHYCTRL_D0);
++ if (ret)
++ otg_err(otg, "Fail to enable ACA&ID detection logic\n");
++
++ mdelay(50);
++
++ ret = intel_scu_ipc_ioread8(PMIC_USBIDSTS, &idsts);
++ if (ret) {
++ otg_err(otg, "Fail to read id\n");
++ return id;
++ }
++
++ if (idsts & USBIDSTS_ID_FLOAT_STS)
++ id = RID_FLOAT;
++ else if (idsts & USBIDSTS_ID_RARBRC_STS(1))
++ id = RID_A;
++ else if (idsts & USBIDSTS_ID_RARBRC_STS(2))
++ id = RID_B;
++ else if (idsts & USBIDSTS_ID_RARBRC_STS(3))
++ id = RID_C;
++ else {
++ /* PMIC A0 reports ID_GND = 0 for RID_GND but PMIC B0 reports
++ * ID_GND = 1 for RID_GND
++ */
++ ret = intel_scu_ipc_ioread8(0x00, &pmic_id);
++ if (ret) {
++ otg_err(otg, "Fail to read PMIC ID register\n");
++ } else if (((pmic_id & VENDOR_ID_MASK) == BASIN_COVE_PMIC_ID) &&
++ ((pmic_id & PMIC_MAJOR_REV) == PMIC_A0_MAJOR_REV)) {
++ if (idsts & USBIDSTS_ID_GND)
++ id = RID_GND;
++ } else {
++ if (!(idsts & USBIDSTS_ID_GND))
++ id = RID_GND;
++ }
++ }
++
++ ret = intel_scu_ipc_update_register(PMIC_USBIDCTRL,
++ USBIDCTRL_ACA_DETEN_D1 | PMIC_USBPHYCTRL_D0,
++ 0);
++ if (ret)
++ otg_err(otg, "Fail to enable ACA&ID detection logic\n");
++
++ return id;
++}
++
++int dwc3_intel_get_id(struct dwc_otg2 *otg)
++{
++ return basin_cove_get_id(otg);
++}
++
++int dwc3_intel_b_idle(struct dwc_otg2 *otg)
++{
++ u32 gctl, tmp;
++
++ /* Disable hibernation mode by default */
++ gctl = otg_read(otg, GCTL);
++ gctl &= ~GCTL_GBL_HIBERNATION_EN;
++ otg_write(otg, GCTL, gctl);
++
++ /* Reset ADP related registers */
++ otg_write(otg, ADPCFG, 0);
++ otg_write(otg, ADPCTL, 0);
++ otg_write(otg, ADPEVTEN, 0);
++ tmp = otg_read(otg, ADPEVT);
++ otg_write(otg, ADPEVT, tmp);
++
++ otg_write(otg, OCFG, 0);
++ otg_write(otg, OEVTEN, 0);
++ tmp = otg_read(otg, OEVT);
++ otg_write(otg, OEVT, tmp);
++ otg_write(otg, OCTL, OCTL_PERI_MODE);
++
++ /* Force config to device mode as default */
++ gctl = otg_read(otg, GCTL);
++ gctl &= ~GCTL_PRT_CAP_DIR;
++ gctl |= GCTL_PRT_CAP_DIR_DEV << GCTL_PRT_CAP_DIR_SHIFT;
++ otg_write(otg, GCTL, gctl);
++
++ if (!is_hybridvp(otg)) {
++ dwc_otg_charger_hwdet(false);
++ enable_usb_phy(otg, false);
++ }
++
++ mdelay(100);
++
++ return 0;
++}
++
++static int dwc3_intel_set_power(struct usb_phy *_otg,
++ unsigned ma)
++{
++ unsigned long flags;
++ struct dwc_otg2 *otg = dwc3_get_otg();
++ struct power_supply_cable_props cap;
++ struct intel_dwc_otg_pdata *data;
++
++ data = (struct intel_dwc_otg_pdata *)otg->otg_data;
++
++ if (otg->charging_cap.chrg_type ==
++ POWER_SUPPLY_CHARGER_TYPE_USB_CDP)
++ return 0;
++ else if (otg->charging_cap.chrg_type !=
++ POWER_SUPPLY_CHARGER_TYPE_USB_SDP) {
++ otg_err(otg, "%s: currently, chrg type is not SDP!\n",
++ __func__);
++ return -EINVAL;
++ }
++
++ if (ma == OTG_DEVICE_SUSPEND) {
++ spin_lock_irqsave(&otg->lock, flags);
++ cap.chrg_type = otg->charging_cap.chrg_type;
++ cap.ma = otg->charging_cap.ma;
++ cap.chrg_evt = POWER_SUPPLY_CHARGER_EVENT_SUSPEND;
++ spin_unlock_irqrestore(&otg->lock, flags);
++
++ /* mA is zero mean D+/D- opened cable.
++ * If SMIP set, then notify 500mA.
++ * Otherwise, notify 0mA.
++ */
++ if (!cap.ma) {
++ if (data->charging_compliance) {
++ cap.ma = 500;
++ cap.chrg_evt =
++ POWER_SUPPLY_CHARGER_EVENT_CONNECT;
++ }
++ /* For standard SDP, if SMIP set, then ignore suspend */
++ } else if (data->charging_compliance)
++ return 0;
++ /* Stander SDP(cap.mA != 0) and SMIP not set.
++ * Should send 0mA with SUSPEND event
++ */
++ else
++ cap.ma = 0;
++
++ atomic_notifier_call_chain(&otg->usb2_phy.notifier,
++ USB_EVENT_CHARGER, &cap);
++ otg_dbg(otg, "Notify EM");
++ otg_dbg(otg, "POWER_SUPPLY_CHARGER_EVENT_SUSPEND\n");
++
++ return 0;
++ } else if (ma == OTG_DEVICE_RESUME) {
++ otg_dbg(otg, "Notify EM");
++ otg_dbg(otg, "POWER_SUPPLY_CHARGER_EVENT_CONNECT\n");
++ dwc3_intel_notify_charger_type(otg,
++ POWER_SUPPLY_CHARGER_EVENT_CONNECT);
++
++ return 0;
++ }
++
++ /* For SMIP set case, only need to report 500/900mA */
++ if (data->charging_compliance) {
++ if ((ma != OTG_USB2_500MA) &&
++ (ma != OTG_USB3_900MA))
++ return 0;
++ }
++
++ /* Covert macro to integer number*/
++ switch (ma) {
++ case OTG_USB2_100MA:
++ ma = 100;
++ break;
++ case OTG_USB3_150MA:
++ ma = 150;
++ break;
++ case OTG_USB2_500MA:
++ ma = 500;
++ break;
++ case OTG_USB3_900MA:
++ ma = 900;
++ break;
++ default:
++ otg_err(otg, "Device driver set invalid SDP current value!\n");
++ return -EINVAL;
++ }
++
++ spin_lock_irqsave(&otg->lock, flags);
++ otg->charging_cap.ma = ma;
++ spin_unlock_irqrestore(&otg->lock, flags);
++
++ dwc3_intel_notify_charger_type(otg,
++ POWER_SUPPLY_CHARGER_EVENT_CONNECT);
++
++ return 0;
++}
++
++int dwc3_intel_enable_vbus(struct dwc_otg2 *otg, int enable)
++{
++ atomic_notifier_call_chain(&otg->usb2_phy.notifier,
++ USB_EVENT_DRIVE_VBUS, &enable);
++
++ return 0;
++}
++
++static int dwc3_intel_notify_charger_type(struct dwc_otg2 *otg,
++ enum power_supply_charger_event event)
++{
++ struct power_supply_cable_props cap;
++ int ret = 0;
++ unsigned long flags;
++
++ if (!charger_detect_enable(otg) &&
++ (otg->charging_cap.chrg_type !=
++ POWER_SUPPLY_CHARGER_TYPE_USB_SDP))
++ return 0;
++
++ if (event > POWER_SUPPLY_CHARGER_EVENT_DISCONNECT) {
++ otg_err(otg,
++ "%s: Invalid power_supply_charger_event!\n", __func__);
++ return -EINVAL;
++ }
++
++ if ((otg->charging_cap.chrg_type ==
++ POWER_SUPPLY_CHARGER_TYPE_USB_SDP) &&
++ ((otg->charging_cap.ma != 0) &&
++ (otg->charging_cap.ma != 100) &&
++ (otg->charging_cap.ma != 150) &&
++ (otg->charging_cap.ma != 500) &&
++ (otg->charging_cap.ma != 900))) {
++ otg_err(otg, "%s: invalid SDP current!\n", __func__);
++ return -EINVAL;
++ }
++
++ spin_lock_irqsave(&otg->lock, flags);
++ cap.chrg_type = otg->charging_cap.chrg_type;
++ cap.ma = otg->charging_cap.ma;
++ cap.chrg_evt = event;
++ spin_unlock_irqrestore(&otg->lock, flags);
++
++ atomic_notifier_call_chain(&otg->usb2_phy.notifier, USB_EVENT_CHARGER,
++ &cap);
++
++ return ret;
++}
++
++static void dwc3_phy_soft_reset(struct dwc_otg2 *otg)
++{
++ u32 val;
++
++ val = otg_read(otg, GCTL);
++ val |= GCTL_CORESOFTRESET;
++ otg_write(otg, GCTL, val);
++
++ val = otg_read(otg, GUSB3PIPECTL0);
++ val |= GUSB3PIPECTL_PHYSOFTRST;
++ otg_write(otg, GUSB3PIPECTL0, val);
++
++ val = otg_read(otg, GUSB2PHYCFG0);
++ val |= GUSB2PHYCFG_PHYSOFTRST;
++ otg_write(otg, GUSB2PHYCFG0, val);
++
++ msleep(50);
++
++ val = otg_read(otg, GUSB3PIPECTL0);
++ val &= ~GUSB3PIPECTL_PHYSOFTRST;
++ otg_write(otg, GUSB3PIPECTL0, val);
++
++ val = otg_read(otg, GUSB2PHYCFG0);
++ val &= ~GUSB2PHYCFG_PHYSOFTRST;
++ otg_write(otg, GUSB2PHYCFG0, val);
++
++ msleep(100);
++
++ val = otg_read(otg, GCTL);
++ val &= ~GCTL_CORESOFTRESET;
++ otg_write(otg, GCTL, val);
++}
++
++static enum power_supply_charger_cable_type
++ dwc3_intel_get_charger_type(struct dwc_otg2 *otg)
++{
++ int ret;
++ struct usb_phy *phy;
++ u8 val, vdat_det, chgd_serx_dm;
++ unsigned long timeout, interval;
++ enum power_supply_charger_cable_type type =
++ POWER_SUPPLY_CHARGER_TYPE_NONE;
++
++ if (!charger_detect_enable(otg))
++ return cap_record.chrg_type;
++
++ phy = usb_get_phy(USB_PHY_TYPE_USB2);
++ if (!phy) {
++ otg_err(otg, "Get USB2 PHY failed\n");
++ return POWER_SUPPLY_CHARGER_TYPE_NONE;
++ }
++
++ /* PHY Enable:
++ * Power on PHY
++ */
++ enable_usb_phy(otg, true);
++ dwc3_phy_soft_reset(otg);
++
++ /* Enable ACA:
++ * Enable ACA & ID detection logic.
++ */
++ ret = intel_scu_ipc_update_register(PMIC_USBIDCTRL,
++ USBIDCTRL_ACA_DETEN_D1 | PMIC_USBPHYCTRL_D0,
++ USBIDCTRL_ACA_DETEN_D1 | PMIC_USBPHYCTRL_D0);
++ if (ret)
++ otg_err(otg, "Fail to enable ACA&ID detection logic\n");
++
++ /* DCD Enable: Change OPMODE to 01 (Non-driving),
++ * TermSel to 0, &
++ * XcvrSel to 01 (enable FS xcvr)
++ */
++ usb_phy_io_write(phy, FUNCCTRL_OPMODE(1) | FUNCCTRL_XCVRSELECT(1),
++ TUSB1211_FUNC_CTRL_SET);
++
++ usb_phy_io_write(phy, FUNCCTRL_OPMODE(2) | FUNCCTRL_XCVRSELECT(2)
++ | FUNCCTRL_TERMSELECT,
++ TUSB1211_FUNC_CTRL_CLR);
++
++ /*Enable SW control*/
++ usb_phy_io_write(phy, PWCTRL_SW_CONTROL, TUSB1211_POWER_CONTROL_SET);
++
++ /* Enable IDPSRC */
++ usb_phy_io_write(phy, VS3_CHGD_IDP_SRC_EN,
++ TUSB1211_VENDOR_SPECIFIC3_SET);
++
++ /* Check DCD result, use same polling parameter */
++ timeout = jiffies + msecs_to_jiffies(DATACON_TIMEOUT);
++ interval = DATACON_INTERVAL * 1000; /* us */
++
++ /* DCD Check:
++ * Delay 66.5 ms. (Note:
++ * TIDP_SRC_ON + TCHGD_SERX_DEB =
++ * 347.8us + 66.1ms).
++ */
++ usleep_range(66500, 67000);
++
++ while (!time_after(jiffies, timeout)) {
++ /* Read DP logic level. */
++ val = usb_phy_io_read(phy, TUSB1211_VENDOR_SPECIFIC4);
++ if (val < 0) {
++ otg_err(otg, "ULPI read error! try again\n");
++ continue;
++ }
++
++ if (!(val & VS4_CHGD_SERX_DP)) {
++ otg_info(otg, "Data contact detected!\n");
++ break;
++ }
++
++ /* Polling interval */
++ usleep_range(interval, interval + 2000);
++ }
++
++ /* Disable DP pullup (Idp_src) */
++ usb_phy_io_write(phy, VS3_CHGD_IDP_SRC_EN,
++ TUSB1211_VENDOR_SPECIFIC3_CLR);
++
++ /* ID Check:
++ * Check ID pin state.
++ */
++ val = dwc3_intel_get_id(otg);
++ if (val != RID_FLOAT) {
++ type = dwc3_intel_aca_check(otg);
++ goto cleanup;
++ }
++
++ /* SE1 Det Enable:
++ * Read DP/DM logic level. Note: use DEBUG
++ * because VS4 isn’t enabled in this situation.
++ */
++ val = usb_phy_io_read(phy, TUSB1211_DEBUG);
++ if (val < 0)
++ otg_err(otg, "ULPI read error!\n");
++
++ val &= DEBUG_LINESTATE;
++
++ /* If '11': SE1 detected; goto 'Cleanup'.
++ * Else: goto 'Pri Det Enable'.
++ */
++ if (val == 3) {
++ type = POWER_SUPPLY_CHARGER_TYPE_SE1;
++ goto cleanup;
++ }
++
++ /* Pri Det Enable:
++ * Enable VDPSRC.
++ */
++ usb_phy_io_write(phy, PWCTRL_DP_VSRC_EN, TUSB1211_POWER_CONTROL_SET);
++
++ /* Wait >106.1ms (40ms for BC
++ * Tvdpsrc_on, 66.1ms for TI CHGD_SERX_DEB).
++ */
++ msleep(107);
++
++ /* Pri Det Check:
++ * Check if DM > VDATREF.
++ */
++ vdat_det = usb_phy_io_read(phy, TUSB1211_POWER_CONTROL);
++ if (vdat_det < 0)
++ otg_err(otg, "ULPI read error!\n");
++
++ vdat_det &= PWCTRL_VDAT_DET;
++
++ /* Check if DM<VLGC */
++ chgd_serx_dm = usb_phy_io_read(phy, TUSB1211_VENDOR_SPECIFIC4);
++ if (chgd_serx_dm < 0)
++ otg_err(otg, "ULPI read error!\n");
++
++ chgd_serx_dm &= VS4_CHGD_SERX_DM;
++
++ /* If VDAT_DET==0 || CHGD_SERX_DM==1: SDP detected
++ * If VDAT_DET==1 && CHGD_SERX_DM==0: CDP/DCP
++ */
++ if (vdat_det == 0 || chgd_serx_dm == 1)
++ type = POWER_SUPPLY_CHARGER_TYPE_USB_SDP;
++
++ /* Disable VDPSRC. */
++ usb_phy_io_write(phy, PWCTRL_DP_VSRC_EN, TUSB1211_POWER_CONTROL_CLR);
++
++ /* If SDP, goto “Cleanup”.
++ * Else, goto “Sec Det Enable”
++ */
++ if (type == POWER_SUPPLY_CHARGER_TYPE_USB_SDP)
++ goto cleanup;
++
++ /* Sec Det Enable:
++ * delay 1ms.
++ */
++ usleep_range(1000, 1500);
++
++ /* Swap DP & DM */
++ usb_phy_io_write(phy, VS1_DATAPOLARITY, TUSB1211_VENDOR_SPECIFIC1_CLR);
++
++ /* Enable 'VDMSRC'. */
++ usb_phy_io_write(phy, PWCTRL_DP_VSRC_EN, TUSB1211_POWER_CONTROL_SET);
++
++ /* Wait >73ms (40ms for BC Tvdmsrc_on, 33ms for TI TVDPSRC_DEB) */
++ msleep(80);
++
++ /* Sec Det Check:
++ * Check if DP>VDATREF.
++ */
++ val = usb_phy_io_read(phy, TUSB1211_POWER_CONTROL);
++ if (val < 0)
++ otg_err(otg, "ULPI read error!\n");
++
++ val &= PWCTRL_VDAT_DET;
++
++ /* If VDAT_DET==0: CDP detected.
++ * If VDAT_DET==1: DCP detected.
++ */
++ if (!val)
++ type = POWER_SUPPLY_CHARGER_TYPE_USB_CDP;
++ else
++ type = POWER_SUPPLY_CHARGER_TYPE_USB_DCP;
++
++ /* Disable VDMSRC. */
++ usb_phy_io_write(phy, PWCTRL_DP_VSRC_EN, TUSB1211_POWER_CONTROL_CLR);
++
++ /* Swap DP & DM. */
++ usb_phy_io_write(phy, VS1_DATAPOLARITY, TUSB1211_VENDOR_SPECIFIC1_SET);
++
++cleanup:
++
++ /* If DCP detected, assert VDPSRC. */
++ if (type == POWER_SUPPLY_CHARGER_TYPE_USB_DCP)
++ usb_phy_io_write(phy, PWCTRL_SW_CONTROL | PWCTRL_DP_VSRC_EN,
++ TUSB1211_POWER_CONTROL_SET);
++
++ usb_put_phy(phy);
++
++ switch (type) {
++ case POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK:
++ case POWER_SUPPLY_CHARGER_TYPE_ACA_A:
++ case POWER_SUPPLY_CHARGER_TYPE_ACA_B:
++ case POWER_SUPPLY_CHARGER_TYPE_ACA_C:
++ case POWER_SUPPLY_CHARGER_TYPE_USB_DCP:
++ case POWER_SUPPLY_CHARGER_TYPE_USB_CDP:
++ case POWER_SUPPLY_CHARGER_TYPE_SE1:
++ dwc_otg_charger_hwdet(true);
++ break;
++ default:
++ break;
++ };
++
++ return type;
++}
++
++static int dwc3_intel_handle_notification(struct notifier_block *nb,
++ unsigned long event, void *data)
++{
++ int state;
++ unsigned long flags, valid_chrg_type;
++ struct dwc_otg2 *otg = dwc3_get_otg();
++ struct power_supply_cable_props *cap;
++
++ if (!otg)
++ return NOTIFY_BAD;
++
++ valid_chrg_type = POWER_SUPPLY_CHARGER_TYPE_USB_SDP |
++ POWER_SUPPLY_CHARGER_TYPE_USB_CDP |
++ POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK;
++
++ spin_lock_irqsave(&otg->lock, flags);
++ switch (event) {
++ case USB_EVENT_ID:
++ otg->otg_events |= OEVT_CONN_ID_STS_CHNG_EVNT;
++ state = NOTIFY_OK;
++ break;
++ case USB_EVENT_VBUS:
++ if (*(int *)data) {
++ otg->otg_events |= OEVT_B_DEV_SES_VLD_DET_EVNT;
++ otg->otg_events &= ~OEVT_A_DEV_SESS_END_DET_EVNT;
++ } else {
++ otg->otg_events |= OEVT_A_DEV_SESS_END_DET_EVNT;
++ otg->otg_events &= ~OEVT_B_DEV_SES_VLD_DET_EVNT;
++ }
++ state = NOTIFY_OK;
++ break;
++ case USB_EVENT_CHARGER:
++ if (charger_detect_enable(otg)) {
++ state = NOTIFY_DONE;
++ goto done;
++ }
++ cap = (struct power_supply_cable_props *)data;
++ if (!(cap->chrg_type & valid_chrg_type)) {
++ otg_err(otg, "Invalid charger type!\n");
++ state = NOTIFY_BAD;
++ }
++ if (cap->chrg_evt == POWER_SUPPLY_CHARGER_EVENT_CONNECT) {
++ otg->otg_events |= OEVT_B_DEV_SES_VLD_DET_EVNT;
++ otg->otg_events &= ~OEVT_A_DEV_SESS_END_DET_EVNT;
++
++ cap_record.chrg_type = cap->chrg_type;
++ cap_record.ma = cap->ma;
++ cap_record.chrg_evt = cap->chrg_evt;
++ } else if (cap->chrg_evt ==
++ POWER_SUPPLY_CHARGER_EVENT_DISCONNECT) {
++ otg->otg_events |= OEVT_A_DEV_SESS_END_DET_EVNT;
++ otg->otg_events &= ~OEVT_B_DEV_SES_VLD_DET_EVNT;
++
++ cap_record.chrg_type = POWER_SUPPLY_CHARGER_TYPE_NONE;
++ cap_record.ma = 0;
++ cap_record.chrg_evt =
++ POWER_SUPPLY_CHARGER_EVENT_DISCONNECT;
++ }
++ state = NOTIFY_OK;
++ break;
++ default:
++ otg_dbg(otg, "DWC OTG Notify unknow notify message\n");
++ state = NOTIFY_DONE;
++ }
++
++done:
++ dwc3_wakeup_otg_thread(otg);
++ spin_unlock_irqrestore(&otg->lock, flags);
++
++ return state;
++
++}
++
++int dwc3_intel_prepare_start_host(struct dwc_otg2 *otg)
++{
++ if (!is_hybridvp(otg)) {
++ enable_usb_phy(otg, true);
++ usb2phy_eye_optimization(otg);
++ disable_phy_auto_resume(otg);
++ }
++
++ return 0;
++}
++
++int dwc3_intel_prepare_start_peripheral(struct dwc_otg2 *otg)
++{
++ if (!is_hybridvp(otg)) {
++ enable_usb_phy(otg, true);
++ usb2phy_eye_optimization(otg);
++ disable_phy_auto_resume(otg);
++ }
++
++ return 0;
++}
++
++int dwc3_intel_suspend(struct dwc_otg2 *otg)
++{
++ struct pci_dev *pci_dev;
++ pci_power_t state = PCI_D3cold;
++
++ if (!otg)
++ return 0;
++
++ pci_dev = to_pci_dev(otg->dev);
++
++ if (otg->state == DWC_STATE_B_PERIPHERAL ||
++ otg->state == DWC_STATE_A_HOST)
++ state = PCI_D3hot;
++
++ set_sus_phy(otg, 1);
++
++ if (pci_save_state(pci_dev)) {
++ otg_err(otg, "pci_save_state failed!\n");
++ return -EIO;
++ }
++
++ pci_disable_device(pci_dev);
++ pci_set_power_state(pci_dev, state);
++
++ return 0;
++}
++
++int dwc3_intel_resume(struct dwc_otg2 *otg)
++{
++ struct pci_dev *pci_dev;
++
++ if (!otg)
++ return 0;
++
++ pci_dev = to_pci_dev(otg->dev);
++
++ /* From synopsys spec 12.2.11.
++ * Software cannot access memory-mapped I/O space
++ * for 10ms. Delay 5 ms here should be enough. Too
++ * long a delay causes hibernation exit failure.
++ */
++ mdelay(5);
++
++ pci_restore_state(pci_dev);
++ if (pci_enable_device(pci_dev) < 0) {
++ otg_err(otg, "pci_enable_device failed.\n");
++ return -EIO;
++ }
++
++ set_sus_phy(otg, 0);
++
++ /* Delay 1ms waiting PHY clock debounce.
++ * Without this debounce, will met fabric error randomly.
++ **/
++ mdelay(1);
++
++ return 0;
++}
++
++struct dwc3_otg_hw_ops dwc3_intel_otg_pdata = {
++ .mode = DWC3_DRD,
++ .bus = DWC3_PCI,
++ .get_id = dwc3_intel_get_id,
++ .b_idle = dwc3_intel_b_idle,
++ .set_power = dwc3_intel_set_power,
++ .enable_vbus = dwc3_intel_enable_vbus,
++ .platform_init = dwc3_intel_platform_init,
++ .get_charger_type = dwc3_intel_get_charger_type,
++ .otg_notifier_handler = dwc3_intel_handle_notification,
++ .prepare_start_peripheral = dwc3_intel_prepare_start_peripheral,
++ .prepare_start_host = dwc3_intel_prepare_start_host,
++ .notify_charger_type = dwc3_intel_notify_charger_type,
++
++ .suspend = dwc3_intel_suspend,
++ .resume = dwc3_intel_resume,
++};
++
++static int __init dwc3_intel_init(void)
++{
++ return dwc3_otg_register(&dwc3_intel_otg_pdata);
++}
++module_init(dwc3_intel_init);
++
++static void __exit dwc3_intel_exit(void)
++{
++ dwc3_otg_unregister(&dwc3_intel_otg_pdata);
++}
++module_exit(dwc3_intel_exit);
++
++MODULE_AUTHOR("Wang Yu <yu.y.wang@intel.com>");
++MODULE_DESCRIPTION("DWC3 Intel OTG Driver");
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_VERSION(VERSION);
+diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
+index 2357c4e..2a36798 100644
+--- a/drivers/usb/dwc3/dwc3-pci.c
++++ b/drivers/usb/dwc3/dwc3-pci.c
+@@ -209,6 +209,10 @@ static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
+ PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
++ /* FIXME: move to pci_ids.h */
++ }, {
++#define PCI_DEVICE_ID_INTEL_DWC_TNG 0x119e
++ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DWC_TNG),
+ },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), },
+diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
+index 5acbb94..50d28e7 100644
+--- a/drivers/usb/dwc3/ep0.c
++++ b/drivers/usb/dwc3/ep0.c
+@@ -417,6 +417,9 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
+ if (dwc->speed != DWC3_DSTS_SUPERSPEED)
+ return -EINVAL;
+
++ if (dwc->is_ebc)
++ break;
++
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ if (set)
+ reg |= DWC3_DCTL_INITU1ENA;
+@@ -431,6 +434,9 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
+ if (dwc->speed != DWC3_DSTS_SUPERSPEED)
+ return -EINVAL;
+
++ if (dwc->is_ebc)
++ break;
++
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ if (set)
+ reg |= DWC3_DCTL_INITU2ENA;
+@@ -560,9 +566,12 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+ * Enable transition to U1/U2 state when
+ * nothing is pending from application.
+ */
+- reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+- reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA);
+- dwc3_writel(dwc->regs, DWC3_DCTL, reg);
++ if (!dwc->is_ebc) {
++ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
++ reg |= (DWC3_DCTL_ACCEPTU1ENA
++ | DWC3_DCTL_ACCEPTU2ENA);
++ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
++ }
+
+ dwc->resize_fifos = true;
+ dev_dbg(dwc->dev, "resize fifos flag SET\n");
+@@ -776,6 +785,9 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
+
+ dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
+
++ if (list_empty(&ep0->request_list))
++ return;
++
+ r = next_request(&ep0->request_list);
+ ur = &r->request;
+
+@@ -1016,6 +1028,25 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
+ return;
+ }
+
++ /*
++ * Per databook, if an XferNotready(Data) is received after
++ * XferComplete(Data), one possible reason is host is trying
++ * to complete data stage by moving a 0-length packet.
++ *
++ * REVISIT in case of other cases
++ */
++ if (dwc->ep0_next_event == DWC3_EP0_NRDY_STATUS) {
++ u32 size = 0;
++ struct dwc3_ep *dep = dwc->eps[event->endpoint_number];
++
++ if (dep->number == 0)
++ size = dep->endpoint.maxpacket;
++
++ dwc3_ep0_start_trans(dwc, dep->number,
++ dwc->ctrl_req_addr, size,
++ DWC3_TRBCTL_CONTROL_DATA);
++ }
++
+ break;
+
+ case DEPEVT_STATUS_CONTROL_STATUS:
+diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
+index 14d28d6..d5418ac 100644
+--- a/drivers/usb/dwc3/gadget.c
++++ b/drivers/usb/dwc3/gadget.c
+@@ -49,10 +49,16 @@
+
+ #include <linux/usb/ch9.h>
+ #include <linux/usb/gadget.h>
++#include <linux/usb/phy.h>
++#include <linux/usb/otg.h>
++#include <linux/usb/ulpi.h>
+
+ #include "core.h"
+ #include "gadget.h"
+ #include "io.h"
++#include "otg.h"
++
++static LIST_HEAD(ebc_io_ops);
+
+ /**
+ * dwc3_gadget_set_test_mode - Enables USB2 Test Modes
+@@ -267,7 +273,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
+
+ if (dwc->ep0_bounced && dep->number == 0)
+ dwc->ep0_bounced = false;
+- else
++ else if (!dep->ebc)
+ usb_gadget_unmap_request(&dwc->gadget, &req->request,
+ req->direction);
+
+@@ -337,7 +343,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
+ unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
+ {
+ struct dwc3_ep *dep = dwc->eps[ep];
+- u32 timeout = 500;
++ u32 timeout = 5000;
+ u32 reg;
+
+ dev_vdbg(dwc->dev, "%s: cmd '%s' params %08x %08x %08x\n",
+@@ -388,9 +394,13 @@ static int dwc3_alloc_trb_pool(struct dwc3_ep *dep)
+ if (dep->number == 0 || dep->number == 1)
+ return 0;
+
+- dep->trb_pool = dma_alloc_coherent(dwc->dev,
+- sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
+- &dep->trb_pool_dma, GFP_KERNEL);
++ if (dep->ebc)
++ dep->trb_pool = dep->ebc->alloc_static_trb_pool(
++ &dep->trb_pool_dma);
++ else
++ dep->trb_pool = dma_alloc_coherent(dwc->dev,
++ sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
++ &dep->trb_pool_dma, GFP_KERNEL);
+ if (!dep->trb_pool) {
+ dev_err(dep->dwc->dev, "failed to allocate trb pool for %s\n",
+ dep->name);
+@@ -404,7 +414,11 @@ static void dwc3_free_trb_pool(struct dwc3_ep *dep)
+ {
+ struct dwc3 *dwc = dep->dwc;
+
+- dma_free_coherent(dwc->dev, sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
++ if (dep->ebc)
++ dep->ebc->free_static_trb_pool();
++ else
++ dma_free_coherent(dwc->dev,
++ sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
+ dep->trb_pool, dep->trb_pool_dma);
+
+ dep->trb_pool = NULL;
+@@ -437,35 +451,58 @@ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
+ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
+ const struct usb_endpoint_descriptor *desc,
+ const struct usb_ss_ep_comp_descriptor *comp_desc,
+- bool ignore)
++ bool ignore, u32 cfg_action)
+ {
+ struct dwc3_gadget_ep_cmd_params params;
+
+ memset(&params, 0x00, sizeof(params));
+
+ params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc))
+- | DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc));
++ | DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc))
++ | cfg_action;
+
+- /* Burst size is only needed in SuperSpeed mode */
+- if (dwc->gadget.speed == USB_SPEED_SUPER) {
+- u32 burst = dep->endpoint.maxburst - 1;
++ if (dep->ebc) {
++ if (dwc->gadget.speed == USB_SPEED_SUPER) {
++ u32 burst = 0;
+
+- params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst);
+- }
++ params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst);
++ }
+
+- if (ignore)
+ params.param0 |= DWC3_DEPCFG_IGN_SEQ_NUM;
+
+- params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN
+- | DWC3_DEPCFG_XFER_NOT_READY_EN;
++ params.param1 = DWC3_DEPCFG_EBC_MODE_EN;
++
++ if (dep->ebc->is_ondemand)
++ params.param1 |= DWC3_DEPCFG_XFER_NOT_READY_EN;
++
++ dep->stream_capable = false;
++ } else {
++ /* Burst size is only needed in SuperSpeed mode */
++ if (dwc->gadget.speed == USB_SPEED_SUPER) {
++ /* In case a function forgets to set maxburst, maxburst
++ * may be still 0, and we shouldn't minus 1 for it.
++ */
++ u32 burst = dep->endpoint.maxburst ?
++ dep->endpoint.maxburst - 1 : 0;
++
++ params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst);
++ }
++
++ if (ignore)
++ params.param0 |= DWC3_DEPCFG_IGN_SEQ_NUM;
++
++ params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN
++ | DWC3_DEPCFG_XFER_NOT_READY_EN;
+
+- if (usb_ss_max_streams(comp_desc) && usb_endpoint_xfer_bulk(desc)) {
+- params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE
+- | DWC3_DEPCFG_STREAM_EVENT_EN;
+- dep->stream_capable = true;
++ if (usb_ss_max_streams(comp_desc) &&
++ usb_endpoint_xfer_bulk(desc)) {
++ params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE
++ | DWC3_DEPCFG_STREAM_EVENT_EN;
++ dep->stream_capable = true;
++ }
+ }
+
+- if (usb_endpoint_xfer_isoc(desc))
++ if (usb_endpoint_xfer_isoc(desc) || usb_endpoint_is_bulk_out(desc))
+ params.param1 |= DWC3_DEPCFG_XFER_IN_PROGRESS_EN;
+
+ /*
+@@ -488,6 +525,56 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
+ dep->interval = 1 << (desc->bInterval - 1);
+ }
+
++ if (cfg_action == DWC3_DEPCFG_ACTION_RESTORE)
++ params.param2 = dep->ep_state;
++
++ return dwc3_send_gadget_ep_cmd(dwc, dep->number,
++ DWC3_DEPCMD_SETEPCONFIG, &params);
++}
++
++static int dwc3_gadget_update_ebc_ep_config(struct dwc3 *dwc,
++ struct dwc3_ep *dep,
++ const struct usb_endpoint_descriptor *desc,
++ const struct usb_ss_ep_comp_descriptor *comp_desc,
++ bool ignore_nrdy)
++{
++ u16 maxp;
++ struct dwc3_gadget_ep_cmd_params params;
++
++ if (!dep->ebc)
++ return -EINVAL;
++
++ memset(&params, 0x00, sizeof(params));
++
++ maxp = usb_endpoint_maxp(desc);
++
++ params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc))
++ | DWC3_DEPCFG_MAX_PACKET_SIZE(maxp)
++ | DWC3_DEPCFG_ACTION_MODIFY;
++
++ if (dwc->gadget.speed == USB_SPEED_SUPER) {
++ u32 burst = 0;
++
++ params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst);
++ }
++ params.param0 |= DWC3_DEPCFG_IGN_SEQ_NUM;
++ params.param1 = DWC3_DEPCFG_EBC_MODE_EN;
++
++ if (!ignore_nrdy)
++ params.param1 |= DWC3_DEPCFG_XFER_NOT_READY_EN;
++
++ dep->stream_capable = false;
++
++ params.param1 |= DWC3_DEPCFG_EP_NUMBER(dep->number);
++
++ if (dep->direction)
++ params.param0 |= DWC3_DEPCFG_FIFO_NUMBER(dep->number >> 1);
++
++ if (desc->bInterval) {
++ params.param1 |= DWC3_DEPCFG_BINTERVAL_M1(desc->bInterval - 1);
++ dep->interval = 1 << (desc->bInterval - 1);
++ }
++
+ return dwc3_send_gadget_ep_cmd(dwc, dep->number,
+ DWC3_DEPCMD_SETEPCONFIG, &params);
+ }
+@@ -526,7 +613,8 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
+ return ret;
+ }
+
+- ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, ignore);
++ ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, ignore,
++ DWC3_DEPCFG_ACTION_INIT);
+ if (ret)
+ return ret;
+
+@@ -547,6 +635,9 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
+ reg |= DWC3_DALEPENA_EP(dep->number);
+ dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
+
++ if (dep->ebc)
++ dwc->is_ebc = 1;
++
+ if (!usb_endpoint_xfer_isoc(desc))
+ return 0;
+
+@@ -566,13 +657,13 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
+ return 0;
+ }
+
+-static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum);
++static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, int forcerm);
+ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
+ {
+ struct dwc3_request *req;
+
+ if (!list_empty(&dep->req_queued)) {
+- dwc3_stop_active_transfer(dwc, dep->number);
++ dwc3_stop_active_transfer(dwc, dep->number, 1);
+
+ /* - giveback all requests to gadget driver */
+ while (!list_empty(&dep->req_queued)) {
+@@ -600,8 +691,16 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
+ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
+ {
+ struct dwc3 *dwc = dep->dwc;
++ struct ebc_io *ebc = dep->ebc;
+ u32 reg;
+
++ if (ebc) {
++ dwc->is_ebc = 0;
++
++ if (ebc->is_ondemand && ebc->xfer_stop)
++ ebc->xfer_stop();
++ }
++
+ dwc3_remove_requests(dwc, dep);
+
+ reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
+@@ -614,6 +713,10 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
+ dep->type = 0;
+ dep->flags = 0;
+
++ /* set normal endpoint maxpacket to default value */
++ if (dep->number > 1)
++ dep->endpoint.maxpacket = 1024;
++
+ return 0;
+ }
+
+@@ -700,7 +803,8 @@ static int dwc3_gadget_ep_disable(struct usb_ep *ep)
+ dep = to_dwc3_ep(ep);
+ dwc = dep->dwc;
+
+- if (!(dep->flags & DWC3_EP_ENABLED)) {
++ if (!(dep->flags & DWC3_EP_ENABLED) &&
++ dep->flags != DWC3_EP_HIBERNATION) {
+ dev_WARN_ONCE(dwc->dev, true, "%s is already disabled\n",
+ dep->name);
+ return 0;
+@@ -751,7 +855,8 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
+ */
+ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
+ struct dwc3_request *req, dma_addr_t dma,
+- unsigned length, unsigned last, unsigned chain, unsigned node)
++ unsigned length, unsigned last, unsigned chain,
++ unsigned node, unsigned csp)
+ {
+ struct dwc3 *dwc = dep->dwc;
+ struct dwc3_trb *trb;
+@@ -818,6 +923,12 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
+ if (chain)
+ trb->ctrl |= DWC3_TRB_CTRL_CHN;
+
++ if (csp) {
++ trb->ctrl |= DWC3_TRB_CTRL_CSP;
++ trb->ctrl |= DWC3_TRB_CTRL_IOC;
++ }
++
++
+ if (usb_endpoint_xfer_bulk(dep->endpoint.desc) && dep->stream_capable)
+ trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id);
+
+@@ -882,7 +993,8 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
+ }
+
+ /* The last TRB is a link TRB, not used for xfer */
+- if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->endpoint.desc))
++ if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
++ (dep->free_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1)
+ return;
+
+ list_for_each_entry_safe(req, n, &dep->request_list, list) {
+@@ -918,12 +1030,14 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
+ chain = false;
+
+ dwc3_prepare_one_trb(dep, req, dma, length,
+- last_one, chain, i);
++ last_one, chain, i, false);
+
+ if (last_one)
+ break;
+ }
+ } else {
++ unsigned csp = false;
++
+ dma = req->request.dma;
+ length = req->request.length;
+ trbs_left--;
+@@ -935,8 +1049,13 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
+ if (list_is_last(&req->list, &dep->request_list))
+ last_one = 1;
+
++ /* For bulk-out ep, if req is the short packet and
++ * not the last one, enable CSP. */
++ if (req->short_packet && !last_one)
++ csp = true;
++
+ dwc3_prepare_one_trb(dep, req, dma, length,
+- last_one, false, 0);
++ last_one, false, 0, csp);
+
+ if (last_one)
+ break;
+@@ -944,6 +1063,115 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
+ }
+ }
+
++/*
++ * dwc3_prepare_ebc_trbs - setup TRBs from DvC endpoint requests
++ * @dep: endpoint for which requests are being prepared
++ * @starting: true if the endpoint is idle and no requests are queued.
++ *
++ * The functions goes through the requests list and setups TRBs for the
++ * transfers.
++ */
++static void dwc3_prepare_ebc_trbs(struct dwc3_ep *dep,
++ bool starting)
++{
++ struct dwc3_request *req, *n;
++ struct dwc3_trb *trb_st_hw;
++ struct dwc3_trb *trb_link;
++ struct dwc3_trb *trb;
++ u32 trbs_left;
++ u32 trbs_num;
++ u32 trbs_mask;
++
++ /* BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);*/
++ trbs_num = dep->ebc->static_trb_pool_size;
++ trbs_mask = trbs_num - 1;
++
++ /* the first request must not be queued */
++ trbs_left = (dep->busy_slot - dep->free_slot) & trbs_mask;
++ /*
++ * if busy & slot are equal than it is either full or empty. If we are
++ * starting to proceed requests then we are empty. Otherwise we ar
++ * full and don't do anything
++ */
++ if (!trbs_left) {
++ if (!starting)
++ return;
++ trbs_left = trbs_num;
++ dep->busy_slot = 0;
++ dep->free_slot = 0;
++ }
++
++ /* The tailed TRB is a link TRB, not used for xfer */
++ if ((trbs_left <= 1))
++ return;
++
++ list_for_each_entry_safe(req, n, &dep->request_list, list) {
++ unsigned int last_one = 0;
++ unsigned int cur_slot;
++
++ /* revisit: dont use specific TRB buffer for Debug class? */
++ trb = &dep->trb_pool[dep->free_slot & trbs_mask];
++ cur_slot = dep->free_slot;
++ dep->free_slot++;
++
++ /* Skip the LINK-TRB */
++ if (((cur_slot & trbs_mask) == trbs_num - 1))
++ continue;
++
++ dwc3_gadget_move_request_queued(req);
++ trbs_left--;
++
++ /* Is our TRB pool empty? */
++ if (!trbs_left)
++ last_one = 1;
++ /* Is this the last request? */
++ if (list_empty(&dep->request_list))
++ last_one = 1;
++
++ req->trb = trb;
++ req->trb_dma = dwc3_trb_dma_offset(dep, trb);
++
++ trb->size = DWC3_TRB_SIZE_LENGTH(req->request.length);
++ trb->bpl = lower_32_bits(req->request.dma);
++ trb->bph = upper_32_bits(req->request.dma);
++
++ switch (usb_endpoint_type(dep->endpoint.desc)) {
++ case USB_ENDPOINT_XFER_BULK:
++ trb->ctrl = DWC3_TRBCTL_NORMAL;
++ break;
++
++ case USB_ENDPOINT_XFER_CONTROL:
++ case USB_ENDPOINT_XFER_ISOC:
++ case USB_ENDPOINT_XFER_INT:
++ default:
++ /*
++ * This is only possible with faulty memory because we
++ * checked it already :)
++ */
++ BUG();
++ }
++
++ trb->ctrl |= DWC3_TRB_CTRL_HWO | DWC3_TRB_CTRL_CHN;
++
++ if (last_one) {
++ if (trbs_left >= 1) {
++ trb_st_hw = &dep->trb_pool[0];
++
++ trb_link = &dep->trb_pool[dep->free_slot &
++ trbs_mask];
++ trb_link->bpl = lower_32_bits(
++ dwc3_trb_dma_offset(dep, trb_st_hw));
++ trb_link->bph = upper_32_bits(
++ dwc3_trb_dma_offset(dep, trb_st_hw));
++ trb_link->ctrl = DWC3_TRBCTL_LINK_TRB;
++ trb_link->ctrl |= DWC3_TRB_CTRL_HWO;
++ trb_link->size = 0;
++ }
++ break;
++ }
++ }
++}
++
+ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
+ int start_new)
+ {
+@@ -964,8 +1192,11 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
+ * new requests as we try to set the IOC bit only on the last request.
+ */
+ if (start_new) {
+- if (list_empty(&dep->req_queued))
+- dwc3_prepare_trbs(dep, start_new);
++ if (dep->ebc)
++ dwc3_prepare_ebc_trbs(dep, start_new);
++ else
++ if (list_empty(&dep->req_queued))
++ dwc3_prepare_trbs(dep, start_new);
+
+ /* req points to the first request which will be sent */
+ req = next_request(&dep->req_queued);
+@@ -1002,8 +1233,9 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
+ * here and stop, unmap, free and del each of the linked
+ * requests instead of what we do now.
+ */
+- usb_gadget_unmap_request(&dwc->gadget, &req->request,
+- req->direction);
++ if (!dep->ebc)
++ usb_gadget_unmap_request(&dwc->gadget, &req->request,
++ req->direction);
+ list_del(&req->list);
+ return ret;
+ }
+@@ -1016,6 +1248,26 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
+ WARN_ON_ONCE(!dep->resource_index);
+ }
+
++ if (dep->ebc) {
++ if (dep->ebc->is_ondemand == 1) {
++ ret = dwc3_gadget_update_ebc_ep_config(dwc, dep,
++ dep->endpoint.desc, dep->comp_desc, true);
++
++ if (ret < 0) {
++ dev_dbg(dwc->dev,
++ "DEPCFG command failed on %s\n",
++ dep->name);
++ return ret;
++ }
++ dev_dbg(dwc->dev,
++ "successfully udpated DEPCFG command on %s\n",
++ dep->name);
++ }
++
++ if (dep->ebc->xfer_start)
++ dep->ebc->xfer_start();
++ }
++
+ return 0;
+ }
+
+@@ -1058,6 +1310,29 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
+ req->direction = dep->direction;
+ req->epnum = dep->number;
+
++ /* specific handling for debug class */
++ if (dep->ebc) {
++ list_add_tail(&req->list, &dep->request_list);
++
++ if ((dep->ebc->is_ondemand == 1) &&
++ (!(dep->flags & DWC3_EP_PENDING_REQUEST))) {
++ dev_dbg(dwc->dev, "%s: delayed to kick ebc transfers\n",
++ dep->name);
++ return 0;
++ }
++
++ if (dep->flags & DWC3_EP_BUSY) {
++ dwc3_stop_active_transfer(dwc, dep->number, 1);
++ dep->flags = DWC3_EP_ENABLED;
++ }
++
++ ret = __dwc3_gadget_kick_transfer(dep, 0, true);
++ if (ret)
++ dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
++ dep->name);
++ return ret;
++ }
++
+ /*
+ * We only add to our list of requests now and
+ * start consuming the list once we get XferNotReady
+@@ -1097,7 +1372,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
+ */
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
+ if (list_empty(&dep->req_queued)) {
+- dwc3_stop_active_transfer(dwc, dep->number);
++ dwc3_stop_active_transfer(dwc, dep->number, 1);
+ dep->flags = DWC3_EP_ENABLED;
+ }
+ return 0;
+@@ -1141,16 +1416,28 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
+
+ int ret;
+
++ spin_lock_irqsave(&dwc->lock, flags);
+ if (!dep->endpoint.desc) {
+ dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
+ request, ep->name);
++ spin_unlock_irqrestore(&dwc->lock, flags);
+ return -ESHUTDOWN;
+ }
+
+ dev_vdbg(dwc->dev, "queing request %p to %s length %d\n",
+ request, ep->name, request->length);
+
+- spin_lock_irqsave(&dwc->lock, flags);
++ /* pad OUT endpoint buffer to MaxPacketSize per databook requirement*/
++ req->short_packet = false;
++ if (!IS_ALIGNED(request->length, ep->desc->wMaxPacketSize)
++ && !(dep->number & 1) && (dep->number != DWC3_EP_EBC_OUT_NB)) {
++ request->length = roundup(request->length,
++ (u32) ep->desc->wMaxPacketSize);
++ /* set flag for bulk-out short request */
++ if (usb_endpoint_is_bulk_out(dep->endpoint.desc))
++ req->short_packet = true;
++ }
++
+ ret = __dwc3_gadget_ep_queue(dep, req);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+@@ -1183,7 +1470,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
+ }
+ if (r == req) {
+ /* wait until it is processed */
+- dwc3_stop_active_transfer(dwc, dep->number);
++ dwc3_stop_active_transfer(dwc, dep->number, 1);
+ goto out1;
+ }
+ dev_err(dwc->dev, "request %p was not queued to %s\n",
+@@ -1410,13 +1697,44 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
+ return 0;
+ }
+
++static int __dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
++{
++ u32 reg;
++ u32 timeout = 500;
++
++ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
++ if (is_on)
++ reg |= DWC3_DCTL_RUN_STOP;
++ else
++ reg &= ~DWC3_DCTL_RUN_STOP;
++ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
++
++ do {
++ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
++ if (is_on) {
++ if (!(reg & DWC3_DSTS_DEVCTRLHLT))
++ break;
++ } else {
++ if (reg & DWC3_DSTS_DEVCTRLHLT)
++ break;
++ }
++ timeout--;
++ if (!timeout)
++ return -ETIMEDOUT;
++ udelay(1);
++ } while (1);
++
++ return 0;
++}
++
+ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
+ {
+ u32 reg;
+ u32 timeout = 500;
++ struct usb_phy *usb_phy;
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+- if (is_on) {
++ if (is_on && !dwc->pullups_connected) {
+ if (dwc->revision <= DWC3_REVISION_187A) {
+ reg &= ~DWC3_DCTL_TRGTULST_MASK;
+ reg |= DWC3_DCTL_TRGTULST_RX_DET;
+@@ -1426,10 +1744,20 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
+ reg &= ~DWC3_DCTL_KEEP_CONNECT;
+ reg |= DWC3_DCTL_RUN_STOP;
+ dwc->pullups_connected = true;
+- } else {
++ } else if (!is_on && dwc->pullups_connected) {
+ reg &= ~DWC3_DCTL_RUN_STOP;
+ dwc->pullups_connected = false;
+- }
++
++ /* WORKAROUND: reset PHY via FUNC_CTRL before disconnect
++ * to avoid PHY hang
++ */
++ usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
++ if (usb_phy)
++ usb_phy_io_write(usb_phy,
++ 0x6D, ULPI_FUNC_CTRL);
++ usb_put_phy(usb_phy);
++ } else
++ return 0;
+
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+@@ -1464,6 +1792,11 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
+
+ is_on = !!is_on;
+
++ if (dwc->soft_connected == is_on)
++ return 0;
++
++ dwc->soft_connected = is_on;
++
+ spin_lock_irqsave(&dwc->lock, flags);
+ ret = dwc3_gadget_run_stop(dwc, is_on);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+@@ -1480,6 +1813,7 @@ static void dwc3_gadget_enable_irq(struct dwc3 *dwc)
+ DWC3_DEVTEN_EVNTOVERFLOWEN |
+ DWC3_DEVTEN_CMDCMPLTEN |
+ DWC3_DEVTEN_ERRTICERREN |
++ DWC3_DEVTEN_HIBERNATIONREQEVTEN |
+ DWC3_DEVTEN_WKUPEVTEN |
+ DWC3_DEVTEN_ULSTCNGEN |
+ DWC3_DEVTEN_CONNECTDONEEN |
+@@ -1498,37 +1832,12 @@ static void dwc3_gadget_disable_irq(struct dwc3 *dwc)
+ static irqreturn_t dwc3_interrupt(int irq, void *_dwc);
+ static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc);
+
+-static int dwc3_gadget_start(struct usb_gadget *g,
+- struct usb_gadget_driver *driver)
++static int dwc3_init_for_enumeration(struct dwc3 *dwc)
+ {
+- struct dwc3 *dwc = gadget_to_dwc(g);
+ struct dwc3_ep *dep;
+- unsigned long flags;
+ int ret = 0;
+- int irq;
+ u32 reg;
+
+- irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+- ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
+- IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc);
+- if (ret) {
+- dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
+- irq, ret);
+- goto err0;
+- }
+-
+- spin_lock_irqsave(&dwc->lock, flags);
+-
+- if (dwc->gadget_driver) {
+- dev_err(dwc->dev, "%s is already bound to %s\n",
+- dwc->gadget.name,
+- dwc->gadget_driver->driver.name);
+- ret = -EBUSY;
+- goto err1;
+- }
+-
+- dwc->gadget_driver = driver;
+-
+ reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+ reg &= ~(DWC3_DCFG_SPEED_MASK);
+
+@@ -1551,6 +1860,7 @@ static int dwc3_gadget_start(struct usb_gadget *g,
+ reg |= dwc->maximum_speed;
+ dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
++ dwc->is_ebc = 0;
+ dwc->start_config_issued = false;
+
+ /* Start with SuperSpeed Default */
+@@ -1560,14 +1870,14 @@ static int dwc3_gadget_start(struct usb_gadget *g,
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
+ if (ret) {
+ dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+- goto err2;
++ return ret;
+ }
+
+ dep = dwc->eps[1];
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
+ if (ret) {
+ dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+- goto err3;
++ goto err0;
+ }
+
+ /* begin to receive SETUP packets */
+@@ -1576,20 +1886,74 @@ static int dwc3_gadget_start(struct usb_gadget *g,
+
+ dwc3_gadget_enable_irq(dwc);
+
++ return 0;
++err0:
++ __dwc3_gadget_ep_disable(dwc->eps[0]);
++
++ return ret;
++}
++
++static int dwc3_gadget_start(struct usb_gadget *g,
++ struct usb_gadget_driver *driver)
++{
++ struct dwc3 *dwc = gadget_to_dwc(g);
++ unsigned long flags;
++ int ret = 0;
++ int irq = 0;
++ struct usb_phy *usb_phy;
++
++ if (dwc->is_otg) {
++ usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
++ if (!usb_phy) {
++ dev_err(dwc->dev, "OTG driver not available\n");
++ ret = -ENODEV;
++ goto err0;
++ }
++
++ otg_set_peripheral(usb_phy->otg, &dwc->gadget);
++ usb_put_phy(usb_phy);
++ } else {
++ irq = platform_get_irq(to_platform_device(dwc->dev), 0);
++ ret = request_threaded_irq(irq, dwc3_interrupt,
++ dwc3_thread_interrupt, IRQF_SHARED,
++ "dwc3", dwc);
++ if (ret) {
++ dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
++ irq, ret);
++ goto err0;
++ }
++ }
++
++ spin_lock_irqsave(&dwc->lock, flags);
++
++ if (dwc->gadget_driver) {
++ dev_err(dwc->dev, "%s is already bound to %s\n",
++ dwc->gadget.name,
++ dwc->gadget_driver->driver.name);
++ ret = -EBUSY;
++ goto err1;
++ }
++
++ dwc->gadget_driver = driver;
++
++ if (!dwc->is_otg) {
++ ret = dwc3_init_for_enumeration(dwc);
++ if (ret)
++ goto err2;
++ }
++
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return 0;
+
+-err3:
+- __dwc3_gadget_ep_disable(dwc->eps[0]);
+-
+ err2:
+ dwc->gadget_driver = NULL;
+
+ err1:
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+- free_irq(irq, dwc);
++ if (!dwc->is_otg)
++ free_irq(irq, dwc);
+
+ err0:
+ return ret;
+@@ -1618,21 +1982,67 @@ static int dwc3_gadget_stop(struct usb_gadget *g,
+ return 0;
+ }
+
+-static const struct usb_gadget_ops dwc3_gadget_ops = {
+- .get_frame = dwc3_gadget_get_frame,
+- .wakeup = dwc3_gadget_wakeup,
+- .set_selfpowered = dwc3_gadget_set_selfpowered,
+- .pullup = dwc3_gadget_pullup,
+- .udc_start = dwc3_gadget_start,
+- .udc_stop = dwc3_gadget_stop,
+-};
++static int __dwc3_vbus_draw(struct dwc3 *dwc, unsigned ma)
++{
++ int ret;
++ struct usb_phy *usb_phy;
+
+-/* -------------------------------------------------------------------------- */
++ usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
++ if (!usb_phy) {
++ dev_err(dwc->dev, "OTG driver not available\n");
++ return -ENODEV;
++ }
++
++ ret = usb_phy_set_power(usb_phy, ma);
++ usb_put_phy(usb_phy);
++
++ return ret;
++}
++
++static int dwc3_vbus_draw(struct usb_gadget *g, unsigned ma)
++{
++ unsigned ma_otg = 0;
++ struct dwc3 *dwc = gadget_to_dwc(g);
++
++ dev_dbg(dwc->dev, "otg_set_power: %d mA\n", ma);
++
++ switch (ma) {
++ case USB3_I_MAX_OTG:
++ ma_otg = OTG_USB3_900MA;
++ break;
++ case USB3_I_UNIT_OTG:
++ ma_otg = OTG_USB3_150MA;
++ break;
++ case USB2_I_MAX_OTG:
++ ma_otg = OTG_USB2_500MA;
++ break;
++ case USB2_I_UNIT_OTG:
++ ma_otg = OTG_USB2_100MA;
++ break;
++ default:
++ dev_err(dwc->dev,
++ "wrong charging current reported: %dmA\n", ma);
++ }
++
++ return __dwc3_vbus_draw(dwc, ma_otg);
++}
++
++static const struct usb_gadget_ops dwc3_gadget_ops = {
++ .get_frame = dwc3_gadget_get_frame,
++ .wakeup = dwc3_gadget_wakeup,
++ .set_selfpowered = dwc3_gadget_set_selfpowered,
++ .pullup = dwc3_gadget_pullup,
++ .udc_start = dwc3_gadget_start,
++ .udc_stop = dwc3_gadget_stop,
++};
++
++/* -------------------------------------------------------------------------- */
+
+ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
+ u8 num, u32 direction)
+ {
+ struct dwc3_ep *dep;
++ struct ebc_io *ebc, *n;
+ u8 i;
+
+ for (i = 0; i < num; i++) {
+@@ -1655,6 +2065,17 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
+ dep->endpoint.name = dep->name;
+ dep->direction = (epnum & 1);
+
++ list_for_each_entry_safe(ebc, n, &ebc_io_ops, list) {
++ if (epnum == ebc->epnum) {
++ dep->ebc = ebc;
++ if (ebc->init)
++ if (ebc->init() == -ENODEV)
++ dev_err(dwc->dev,
++ "debug class init fail %d\n",
++ epnum);
++ }
++ }
++
+ if (epnum == 0 || epnum == 1) {
+ dep->endpoint.maxpacket = 512;
+ dep->endpoint.maxburst = 1;
+@@ -1855,7 +2276,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
+ */
+ dep->flags = DWC3_EP_PENDING_REQUEST;
+ } else {
+- dwc3_stop_active_transfer(dwc, dep->number);
++ dwc3_stop_active_transfer(dwc, dep->number, 1);
+ dep->flags = DWC3_EP_ENABLED;
+ }
+ return 1;
+@@ -1939,8 +2360,9 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
+ dwc3_endpoint_transfer_complete(dwc, dep, event, 1);
+ break;
+ case DWC3_DEPEVT_XFERINPROGRESS:
+- if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
+- dev_dbg(dwc->dev, "%s is not an Isochronous endpoint\n",
++ if ((!usb_endpoint_xfer_isoc(dep->endpoint.desc)) &&
++ (!usb_endpoint_xfer_bulk(dep->endpoint.desc))) {
++ dev_dbg(dwc->dev, "%s is not an Isochronous/bulk endpoint\n",
+ dep->name);
+ return;
+ }
+@@ -2005,7 +2427,7 @@ static void dwc3_disconnect_gadget(struct dwc3 *dwc)
+ }
+ }
+
+-static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
++static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, int forcerm)
+ {
+ struct dwc3_ep *dep;
+ struct dwc3_gadget_ep_cmd_params params;
+@@ -2014,6 +2436,31 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
+
+ dep = dwc->eps[epnum];
+
++ if (dep->ebc) {
++ if (dep->ebc->is_ondemand == 1) {
++ ret = dwc3_gadget_update_ebc_ep_config(dwc, dep,
++ dep->endpoint.desc, dep->comp_desc, false);
++ if (ret < 0) {
++ dev_dbg(dwc->dev,
++ "DEPCFG failed on %s\n",
++ dep->name);
++ return;
++ }
++ dev_dbg(dwc->dev,
++ "successfully udpated DEPCFG command on %s\n",
++ dep->name);
++ }
++
++ if (dep->ebc->xfer_stop)
++ dep->ebc->xfer_stop();
++ else
++ dev_dbg(dwc->dev, "%s xfer_stop() NULL\n", dep->name);
++ }
++
++ if (usb_endpoint_xfer_isoc(dep->endpoint.desc))
++ dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc,
++ dep->number);
++
+ if (!dep->resource_index)
+ return;
+
+@@ -2037,8 +2484,10 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
+ */
+
+ cmd = DWC3_DEPCMD_ENDTRANSFER;
+- cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC;
++ cmd |= DWC3_DEPCMD_CMDIOC;
+ cmd |= DWC3_DEPCMD_PARAM(dep->resource_index);
++ if (forcerm)
++ cmd |= DWC3_DEPCMD_HIPRI_FORCERM;
+ memset(&params, 0, sizeof(params));
+ ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
+ WARN_ON_ONCE(ret);
+@@ -2138,6 +2587,17 @@ static void dwc3_gadget_usb2_phy_suspend(struct dwc3 *dwc, int suspend)
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+ }
+
++static void link_state_change_work(struct work_struct *data)
++{
++ struct dwc3 *dwc = container_of((struct delayed_work *)data,
++ struct dwc3, link_work);
++
++ if (dwc->link_state == DWC3_LINK_STATE_U3) {
++ dev_info(dwc->dev, "device suspended; notify OTG\n");
++ __dwc3_vbus_draw(dwc, OTG_DEVICE_SUSPEND);
++ }
++}
++
+ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
+ {
+ u32 reg;
+@@ -2278,22 +2738,26 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
+ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+ dwc->gadget.ep0->maxpacket = 512;
+ dwc->gadget.speed = USB_SPEED_SUPER;
++ __dwc3_vbus_draw(dwc, OTG_USB3_150MA);
+ break;
+ case DWC3_DCFG_HIGHSPEED:
+ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
+ dwc->gadget.ep0->maxpacket = 64;
+ dwc->gadget.speed = USB_SPEED_HIGH;
++ __dwc3_vbus_draw(dwc, OTG_USB2_100MA);
+ break;
+ case DWC3_DCFG_FULLSPEED2:
+ case DWC3_DCFG_FULLSPEED1:
+ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
+ dwc->gadget.ep0->maxpacket = 64;
+ dwc->gadget.speed = USB_SPEED_FULL;
++ __dwc3_vbus_draw(dwc, OTG_USB2_100MA);
+ break;
+ case DWC3_DCFG_LOWSPEED:
+ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(8);
+ dwc->gadget.ep0->maxpacket = 8;
+ dwc->gadget.speed = USB_SPEED_LOW;
++ __dwc3_vbus_draw(dwc, OTG_USB2_100MA);
+ break;
+ }
+
+@@ -2324,16 +2788,20 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
+ }
+
+ dep = dwc->eps[0];
+- ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true);
++ ret = dwc3_gadget_set_ep_config(dwc, dep,
++ &dwc3_gadget_ep0_desc, NULL, false,
++ DWC3_DEPCFG_ACTION_MODIFY);
+ if (ret) {
+- dev_err(dwc->dev, "failed to enable %s\n", dep->name);
++ dev_err(dwc->dev, "failed to update %s\n", dep->name);
+ return;
+ }
+
+ dep = dwc->eps[1];
+- ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true);
++ ret = dwc3_gadget_set_ep_config(dwc, dep,
++ &dwc3_gadget_ep0_desc, NULL, false,
++ DWC3_DEPCFG_ACTION_MODIFY);
+ if (ret) {
+- dev_err(dwc->dev, "failed to enable %s\n", dep->name);
++ dev_err(dwc->dev, "failed to update %s\n", dep->name);
+ return;
+ }
+
+@@ -2350,6 +2818,9 @@ static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
+ {
+ dev_vdbg(dwc->dev, "%s\n", __func__);
+
++ dev_info(dwc->dev, "device resumed; notify OTG\n");
++ __dwc3_vbus_draw(dwc, OTG_DEVICE_RESUME);
++
+ /*
+ * TODO take core out of low power mode when that's
+ * implemented.
+@@ -2439,12 +2910,26 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
+
+ dwc->link_state = next;
+
++ if (next == DWC3_LINK_STATE_U3)
++ schedule_delayed_work(
++ &dwc->link_work, msecs_to_jiffies(1000));
++
+ dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);
+ }
+
++static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc)
++{
++ dev_vdbg(dwc->dev, "%s\n", __func__);
++
++ if (dwc->hiber_enabled)
++ pm_runtime_put(dwc->dev);
++}
++
+ static void dwc3_gadget_interrupt(struct dwc3 *dwc,
+ const struct dwc3_event_devt *event)
+ {
++ u32 reg;
++
+ switch (event->type) {
+ case DWC3_DEVICE_EVENT_DISCONNECT:
+ dwc3_gadget_disconnect_interrupt(dwc);
+@@ -2461,6 +2946,9 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc,
+ case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
+ dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
+ break;
++ case DWC3_DEVICE_EVENT_HIBER_REQ:
++ dwc3_gadget_hibernation_interrupt(dwc);
++ break;
+ case DWC3_DEVICE_EVENT_EOPF:
+ dev_vdbg(dwc->dev, "End of Periodic Frame\n");
+ break;
+@@ -2469,6 +2957,14 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc,
+ break;
+ case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
+ dev_vdbg(dwc->dev, "Erratic Error\n");
++
++ /* Controller may generate too many Erratic Errors Messages,
++ * Disable it until we find a way to recover the failure.
++ */
++ reg = dwc3_readl(dwc->regs, DWC3_DEVTEN);
++ reg &= ~DWC3_DEVTEN_ERRTICERREN;
++ dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
++ dev_info(dwc->dev, "Erratic Error Event disabled\n");
+ break;
+ case DWC3_DEVICE_EVENT_CMD_CMPL:
+ dev_vdbg(dwc->dev, "Command Complete\n");
+@@ -2505,6 +3001,7 @@ static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
+ struct dwc3 *dwc = _dwc;
+ unsigned long flags;
+ irqreturn_t ret = IRQ_NONE;
++ u32 reg;
+ int i;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+@@ -2544,6 +3041,11 @@ static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
+ evt->count = 0;
+ evt->flags &= ~DWC3_EVENT_PENDING;
+ ret = IRQ_HANDLED;
++
++ /* Unmask interrupt */
++ reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(i));
++ reg &= ~DWC3_GEVNTSIZ_INTMASK;
++ dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(i), reg);
+ }
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+@@ -2555,6 +3057,7 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
+ {
+ struct dwc3_event_buffer *evt;
+ u32 count;
++ u32 reg;
+
+ evt = dwc->ev_buffs[buf];
+
+@@ -2566,6 +3069,11 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
+ evt->count = count;
+ evt->flags |= DWC3_EVENT_PENDING;
+
++ /* Mask interrupt */
++ reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf));
++ reg |= DWC3_GEVNTSIZ_INTMASK;
++ dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg);
++
+ return IRQ_WAKE_THREAD;
+ }
+
+@@ -2576,6 +3084,15 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
+ irqreturn_t ret = IRQ_NONE;
+
+ spin_lock(&dwc->lock);
++ if (dwc->pm_state != PM_ACTIVE) {
++ if (dwc->pm_state == PM_SUSPENDED) {
++ dev_info(dwc->dev, "u2/u3 pmu is received\n");
++ pm_runtime_get(dwc->dev);
++ dwc->pm_state = PM_RESUMING;
++ ret = IRQ_HANDLED;
++ }
++ goto out;
++ }
+
+ for (i = 0; i < dwc->num_event_buffers; i++) {
+ irqreturn_t status;
+@@ -2585,6 +3102,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
+ ret = status;
+ }
+
++out:
+ spin_unlock(&dwc->lock);
+
+ return ret;
+@@ -2601,6 +3119,23 @@ int dwc3_gadget_init(struct dwc3 *dwc)
+ u32 reg;
+ int ret;
+
++ dwc->scratch_array = dma_alloc_coherent(dwc->dev,
++ sizeof(*dwc->scratch_array),
++ &dwc->scratch_array_dma, GFP_KERNEL);
++ if (!dwc->scratch_array) {
++ dev_err(dwc->dev, "failed to allocate scratch_arrary\n");
++ return -ENOMEM;
++ }
++
++ dwc->scratch_buffer[0] = dma_alloc_coherent(dwc->dev,
++ DWC3_SCRATCH_BUF_SIZE,
++ &dwc->scratch_array->dma_adr[0], GFP_KERNEL);
++ if (!dwc->scratch_buffer[0]) {
++ dev_err(dwc->dev, "failed to allocate scratch_buffer\n");
++ ret = -ENOMEM;
++ goto err;
++ }
++
+ dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
+ &dwc->ctrl_req_addr, GFP_KERNEL);
+ if (!dwc->ctrl_req) {
+@@ -2639,6 +3174,8 @@ int dwc3_gadget_init(struct dwc3 *dwc)
+ dwc->gadget.sg_supported = true;
+ dwc->gadget.name = "dwc3-gadget";
+
++ INIT_DELAYED_WORK(&dwc->link_work, link_state_change_work);
++
+ /*
+ * REVISIT: Here we should clear all pending IRQs to be
+ * sure we're starting from a well known location.
+@@ -2685,6 +3222,13 @@ err1:
+ dwc->ctrl_req, dwc->ctrl_req_addr);
+
+ err0:
++ dma_free_coherent(dwc->dev,
++ DWC3_SCRATCH_BUF_SIZE, dwc->scratch_buffer[0],
++ (dma_addr_t)dwc->scratch_array->dma_adr[0]);
++
++err:
++ dma_free_coherent(dwc->dev, sizeof(*dwc->scratch_array),
++ dwc->scratch_array, dwc->scratch_array_dma);
+ return ret;
+ }
+
+@@ -2706,6 +3250,13 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
+
+ dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
+ dwc->ctrl_req, dwc->ctrl_req_addr);
++
++ dma_free_coherent(dwc->dev,
++ DWC3_SCRATCH_BUF_SIZE, dwc->scratch_buffer[0],
++ (dma_addr_t)dwc->scratch_array->dma_adr[0]);
++
++ dma_free_coherent(dwc->dev, sizeof(*dwc->scratch_array),
++ dwc->scratch_array, dwc->scratch_array_dma);
+ }
+
+ int dwc3_gadget_prepare(struct dwc3 *dwc)
+@@ -2766,3 +3317,359 @@ err1:
+ err0:
+ return ret;
+ }
++
++void dwc3_register_io_ebc(struct ebc_io *ebc)
++{
++ list_add_tail(&ebc->list, &ebc_io_ops);
++}
++
++void dwc3_unregister_io_ebc(struct ebc_io *ebc)
++{
++ list_del(&ebc->list);
++}
++
++#ifdef CONFIG_PM_RUNTIME
++static void dwc3_gadget_get_ep_state(struct dwc3 *dwc, struct dwc3_ep *dep)
++{
++ struct dwc3_gadget_ep_cmd_params params;
++ int ret;
++
++ dev_vdbg(dwc->dev, "%s\n", __func__);
++
++ memset(&params, 0, sizeof(params));
++ ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
++ DWC3_DEPCMD_GETEPSTATE, &params);
++ WARN_ON_ONCE(ret);
++
++ dep->ep_state = dwc3_readl(dwc->regs, DWC3_DEPCMDPAR2(dep->number));
++}
++
++static void dwc3_cache_hwregs(struct dwc3 *dwc)
++{
++ struct dwc3_hwregs *regs = &dwc->hwregs;
++
++ dev_vdbg(dwc->dev, "%s\n", __func__);
++
++ regs->guctl = dwc3_readl(dwc->regs, DWC3_GUCTL);
++ regs->grxthrcfg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG);
++ regs->dcfg = dwc3_readl(dwc->regs, DWC3_DCFG);
++ regs->devten = dwc3_readl(dwc->regs, DWC3_DEVTEN);
++ regs->gctl = dwc3_readl(dwc->regs, DWC3_GCTL);
++ regs->gusb3pipectl0 = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
++ regs->gusb2phycfg0 = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
++ regs->gevntadrlo = dwc3_readl(dwc->regs, DWC3_GEVNTADRLO(0));
++ regs->gevntadrhi = dwc3_readl(dwc->regs, DWC3_GEVNTADRHI(0));
++ regs->gevntsiz = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(0));
++}
++
++static void dwc3_restore_hwregs(struct dwc3 *dwc)
++{
++ struct dwc3_hwregs *regs = &dwc->hwregs;
++
++ dev_vdbg(dwc->dev, "%s\n", __func__);
++
++ dwc3_writel(dwc->regs, DWC3_GUCTL, regs->guctl);
++ dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, regs->grxthrcfg);
++ dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), regs->gusb3pipectl0);
++ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), regs->gusb2phycfg0);
++ dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0), regs->gevntadrlo);
++ dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0), regs->gevntadrhi);
++ dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), regs->gevntsiz);
++ dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
++ dwc3_writel(dwc->regs, DWC3_DCFG, regs->dcfg);
++ dwc3_writel(dwc->regs, DWC3_DEVTEN, regs->devten);
++ dwc3_writel(dwc->regs, DWC3_GCTL, regs->gctl);
++}
++
++static int dwc3_gadget_controller_save_state(struct dwc3 *dwc)
++{
++ u32 reg;
++ u32 timeout = 1000;
++
++ dev_vdbg(dwc->dev, "---> %s()\n", __func__);
++
++ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
++
++ reg |= DWC3_DCTL_CSS;
++ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
++
++ do {
++ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
++ if (!(reg & DWC3_DSTS_SSS))
++ return 0;
++
++ timeout--;
++ if (!timeout)
++ return -ETIMEDOUT;
++ udelay(1);
++ } while (1);
++
++ dev_vdbg(dwc->dev, "<--- %s()\n", __func__);
++}
++
++static int dwc3_gadget_controller_restore_state(struct dwc3 *dwc)
++{
++ u32 reg;
++ u32 timeout = 1000;
++
++ dev_vdbg(dwc->dev, "---> %s()\n", __func__);
++
++ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
++
++ reg |= DWC3_DCTL_CRS;
++ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
++
++ do {
++ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
++ if (!(reg & DWC3_DSTS_RSS))
++ return 0;
++
++ timeout--;
++ if (!timeout)
++ return -ETIMEDOUT;
++ udelay(1);
++ } while (1);
++
++ dev_vdbg(dwc->dev, "<--- %s()\n", __func__);
++}
++
++void dwc3_gadget_keep_conn(struct dwc3 *dwc, int is_on)
++{
++ u32 reg;
++
++ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
++ if (is_on)
++ reg |= DWC3_DCTL_KEEP_CONNECT;
++ else
++ reg &= ~DWC3_DCTL_KEEP_CONNECT;
++ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
++}
++
++int dwc3_runtime_suspend(struct device *device)
++{
++ struct dwc3 *dwc;
++ struct platform_device *pdev;
++ unsigned long flags;
++ u32 epnum;
++ struct dwc3_ep *dep;
++
++ pdev = to_platform_device(device);
++ dwc = platform_get_drvdata(pdev);
++
++ if (!dwc || !dwc->hiber_enabled)
++ return 0;
++
++ dev_vdbg(dwc->dev, "---> %s()\n", __func__);
++
++ spin_lock_irqsave(&dwc->lock, flags);
++
++ if (dwc->pm_state != PM_ACTIVE) {
++ spin_unlock_irqrestore(&dwc->lock, flags);
++ return 0;
++ }
++
++
++ for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
++ dep = dwc->eps[epnum];
++ if (!(dep->flags & DWC3_EP_ENABLED))
++ continue;
++
++ dep->flags_backup = dep->flags;
++ if (dep->flags & DWC3_EP_BUSY)
++ dwc3_stop_active_transfer(dwc, epnum, 0);
++
++ dwc3_gadget_get_ep_state(dwc, dep);
++
++ dep->flags = DWC3_EP_HIBERNATION;
++ }
++
++ __dwc3_gadget_run_stop(dwc, 0);
++ dwc3_gadget_keep_conn(dwc, 1);
++
++ dwc3_cache_hwregs(dwc);
++
++ dwc3_gadget_disable_irq(dwc);
++ dwc3_event_buffers_cleanup(dwc);
++
++ dwc3_gadget_controller_save_state(dwc);
++
++ dwc->pm_state = PM_SUSPENDED;
++
++ spin_unlock_irqrestore(&dwc->lock, flags);
++
++ schedule_delayed_work(&dwc->link_work, msecs_to_jiffies(1000));
++ dev_info(dwc->dev, "suspended\n");
++ dev_vdbg(dwc->dev, "<--- %s()\n", __func__);
++
++ return 0;
++}
++
++int dwc3_runtime_resume(struct device *device)
++{
++ struct dwc3 *dwc;
++ struct platform_device *pdev;
++ unsigned long flags;
++ int ret;
++ u32 epnum;
++ u32 timeout = 500;
++ u32 reg;
++ u8 link_state;
++ struct dwc3_ep *dep;
++
++ pdev = to_platform_device(device);
++ dwc = platform_get_drvdata(pdev);
++
++ if (!dwc || !dwc->hiber_enabled)
++ return 0;
++
++ dev_vdbg(dwc->dev, "---> %s()\n", __func__);
++
++ spin_lock_irqsave(&dwc->lock, flags);
++
++ if (dwc->pm_state == PM_ACTIVE ||
++ dwc->pm_state == PM_DISCONNECTED) {
++ spin_unlock_irqrestore(&dwc->lock, flags);
++ return 0;
++ }
++
++ dwc3_send_gadget_generic_command(dwc, DWC3_DGCMD_SET_SCRATCH_ADDR_LO,
++ dwc->scratch_array_dma & 0xffffffffU);
++
++ dwc3_gadget_controller_restore_state(dwc);
++
++ dwc3_restore_hwregs(dwc);
++
++ dep = dwc->eps[0];
++ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
++ if (ret) {
++ dev_err(dwc->dev, "failed to enable %s during runtime resume\n",
++ dep->name);
++ goto err0;
++ }
++
++ dep = dwc->eps[1];
++ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
++ if (ret) {
++ dev_err(dwc->dev, "failed to enable %s during runtime resume\n",
++ dep->name);
++ goto err1;
++ }
++
++ for (epnum = 0; epnum < 2; epnum++) {
++ struct dwc3_gadget_ep_cmd_params params;
++
++ dep = dwc->eps[epnum];
++ if (dep->flags_backup & DWC3_EP_BUSY) {
++ dwc->ep0_trb->ctrl |= DWC3_TRB_CTRL_HWO;
++
++ memset(&params, 0, sizeof(params));
++ params.param0 = upper_32_bits(dwc->ep0_trb_addr);
++ params.param1 = lower_32_bits(dwc->ep0_trb_addr);
++
++ ret = dwc3_send_gadget_ep_cmd(dwc, epnum,
++ DWC3_DEPCMD_STARTTRANSFER, &params);
++ WARN_ON_ONCE(ret);
++ }
++
++ dep->flags = dep->flags_backup;
++ dep->flags_backup = 0;
++ }
++
++ __dwc3_gadget_run_stop(dwc, 1);
++ dwc3_gadget_keep_conn(dwc, 1);
++
++ do {
++ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
++ if (!(reg & DWC3_DSTS_DCNRD))
++ break;
++
++ timeout--;
++ if (!timeout)
++ break;
++ udelay(1);
++ } while (1);
++
++ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
++ link_state = DWC3_DSTS_USBLNKST(reg);
++ switch (link_state) {
++ case DWC3_LINK_STATE_U3:
++ case DWC3_LINK_STATE_RESUME:
++ dwc3_gadget_conndone_interrupt(dwc);
++
++ for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
++ dep = dwc->eps[epnum];
++ if (!(dep->flags_backup & DWC3_EP_ENABLED))
++ continue;
++ if (dep->endpoint.desc)
++ dwc3_gadget_set_ep_config(dwc,
++ dep, dep->endpoint.desc, dep->comp_desc,
++ false, DWC3_DEPCFG_ACTION_RESTORE);
++
++ dwc3_gadget_set_xfer_resource(dwc, dep);
++
++ reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
++ reg |= DWC3_DALEPENA_EP(epnum);
++ dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
++
++ if (dep->flags_backup & DWC3_EP_STALL)
++ __dwc3_gadget_ep_set_halt(dep, 1);
++
++ if (dep->flags_backup & DWC3_EP_BUSY) {
++ struct dwc3_request *req;
++ struct dwc3_gadget_ep_cmd_params params;
++
++ req = next_request(&dep->req_queued);
++ if (!req)
++ break;
++ req->trb->ctrl |= DWC3_TRB_CTRL_HWO;
++ memset(&params, 0, sizeof(params));
++ params.param0 = upper_32_bits(req->trb_dma);
++ params.param1 = lower_32_bits(req->trb_dma);
++
++ ret = dwc3_send_gadget_ep_cmd(dwc, epnum,
++ DWC3_DEPCMD_STARTTRANSFER,
++ &params);
++ WARN_ON_ONCE(ret);
++
++ }
++
++ dep->flags = dep->flags_backup;
++ dep->flags_backup = 0;
++ }
++
++ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
++ reg |= DWC3_DCTL_ULSTCHNG_RECOVERY;
++ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
++
++ break;
++ case DWC3_LINK_STATE_RESET:
++ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
++ reg |= DWC3_DCTL_ULSTCHNG_RECOVERY;
++ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
++
++ break;
++ default:
++ /* wait for USB Reset or Connect Done event */
++ break;
++ }
++
++ dwc->pm_state = PM_ACTIVE;
++
++ spin_unlock_irqrestore(&dwc->lock, flags);
++
++ __dwc3_vbus_draw(dwc, OTG_DEVICE_RESUME);
++ dev_info(dwc->dev, "resumed\n");
++ dev_vdbg(dwc->dev, "<--- %s()\n", __func__);
++ return 0;
++
++err1:
++ __dwc3_gadget_ep_disable(dwc->eps[0]);
++
++err0:
++ spin_unlock_irqrestore(&dwc->lock, flags);
++
++ return ret;
++}
++#else
++void dwc3_gadget_keep_conn(struct dwc3 *dwc, int is_on) {}
++#endif
+diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
+index 99e6d72..a691b7b 100644
+--- a/drivers/usb/dwc3/gadget.h
++++ b/drivers/usb/dwc3/gadget.h
+@@ -47,6 +47,12 @@ struct dwc3;
+ #define to_dwc3_ep(ep) (container_of(ep, struct dwc3_ep, endpoint))
+ #define gadget_to_dwc(g) (container_of(g, struct dwc3, gadget))
+
++/* max power consumption of the device from the bus */
++#define USB3_I_MAX_OTG 896
++#define USB3_I_UNIT_OTG 144
++#define USB2_I_MAX_OTG 500
++#define USB2_I_UNIT_OTG 100
++
+ /* DEPCFG parameter 1 */
+ #define DWC3_DEPCFG_INT_NUM(n) ((n) << 0)
+ #define DWC3_DEPCFG_XFER_COMPLETE_EN (1 << 8)
+@@ -54,6 +60,7 @@ struct dwc3;
+ #define DWC3_DEPCFG_XFER_NOT_READY_EN (1 << 10)
+ #define DWC3_DEPCFG_FIFO_ERROR_EN (1 << 11)
+ #define DWC3_DEPCFG_STREAM_EVENT_EN (1 << 13)
++#define DWC3_DEPCFG_EBC_MODE_EN (1 << 15)
+ #define DWC3_DEPCFG_BINTERVAL_M1(n) ((n) << 16)
+ #define DWC3_DEPCFG_STREAM_CAPABLE (1 << 24)
+ #define DWC3_DEPCFG_EP_NUMBER(n) ((n) << 25)
+diff --git a/drivers/usb/dwc3/otg.c b/drivers/usb/dwc3/otg.c
+new file mode 100644
+index 0000000..31ee4b9
+--- /dev/null
++++ b/drivers/usb/dwc3/otg.c
+@@ -0,0 +1,1509 @@
++/*
++ * otg.c - Designware USB3 DRD Controller OTG driver
++ *
++ * Authors: Wang Yu <yu.y.wang@intel.com>
++ * Synopsys inc
++ *
++ * Description:
++ *
++ * This driver is developed base on dwc_otg3.c which provided by
++ * Synopsys company. Yu removed some unused features from it,
++ * for example: HNP/SRP/ADP support. Because haven't use these features
++ * so far. And add charger detection support into the state machine.
++ * Support SDP/CDP/DCP/Micro-ACA/ACA-Dock and SE1 USB charger type.
++ *
++ * Beside that, make all hardware dependence as arguments, which need
++ * vendor to implemented by themselves. For example: VBus drive, USB ID
++ * pin value and so on.
++ *
++ * To enable this OTG driver, user have to call dwc3_otg_register API to
++ * regiter one dwc3_otg_hw_ops object which include all hardware
++ * dependent code.
++ *
++ * License:
++ * Below declaration is copy from Synopsys DWC3 SW 2.10a released README.txt.
++ *
++ * IMPORTANT:
++ *
++ * Synopsys SS USB3 Linux Driver Software and documentation (hereinafter,
++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
++ * otherwise expressly agreed to in writing between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product under
++ * any End User Software License Agreement or Agreement for Licensed Product
++ * with Synopsys or any supplement thereto. You are permitted to use and
++ * redistribute this Software in source and binary forms, with or without
++ * modification, provided that redistributions of source code must retain this
++ * notice. You may not view, use, disclose, copy or distribute this file or
++ * any information contained herein except pursuant to this license grant from
++ * Synopsys. If you do not agree with this notice, including the disclaimer
++ * below, then you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/usb/otg.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/freezer.h>
++#include <linux/delay.h>
++#include <linux/kthread.h>
++#include <linux/version.h>
++
++#include "otg.h"
++
++#define VERSION "2.10a"
++
++struct dwc3_otg_hw_ops *dwc3_otg_pdata;
++struct dwc_device_par *platform_par;
++
++static struct mutex lock;
++static const char driver_name[] = "dwc3_otg";
++static struct dwc_otg2 *the_transceiver;
++static void dwc_otg_remove(struct pci_dev *pdev);
++
++
++static inline struct dwc_otg2 *xceiv_to_dwc_otg2(struct usb_otg *x)
++{
++ return container_of(x, struct dwc_otg2, otg);
++}
++
++struct dwc_otg2 *dwc3_get_otg(void)
++{
++ return the_transceiver;
++}
++EXPORT_SYMBOL_GPL(dwc3_get_otg);
++
++/* Caller must hold otg->lock */
++void dwc3_wakeup_otg_thread(struct dwc_otg2 *otg)
++{
++ if (!otg->main_thread)
++ return;
++
++ otg_dbg(otg, "\n");
++ /* Tell the main thread that something has happened */
++ otg->main_wakeup_needed = 1;
++ wake_up_interruptible(&otg->main_wq);
++}
++EXPORT_SYMBOL_GPL(dwc3_wakeup_otg_thread);
++
++static int sleep_main_thread_timeout(struct dwc_otg2 *otg, int msecs)
++{
++ signed long jiffies;
++ int rc = msecs;
++
++ if (otg->state == DWC_STATE_EXIT) {
++ otg_dbg(otg, "Main thread exiting\n");
++ rc = -EINTR;
++ goto done;
++ }
++
++ if (signal_pending(current)) {
++ otg_dbg(otg, "Main thread signal pending\n");
++ rc = -EINTR;
++ goto done;
++ }
++ if (otg->main_wakeup_needed) {
++ otg_dbg(otg, "Main thread wakeup needed\n");
++ rc = msecs;
++ goto done;
++ }
++
++ jiffies = msecs_to_jiffies(msecs);
++ rc = wait_event_freezable_timeout(otg->main_wq,
++ otg->main_wakeup_needed,
++ jiffies);
++
++ if (otg->state == DWC_STATE_EXIT) {
++ otg_dbg(otg, "Main thread exiting\n");
++ rc = -EINTR;
++ goto done;
++ }
++
++ if (rc > 0)
++ rc = jiffies_to_msecs(rc);
++
++done:
++ otg->main_wakeup_needed = 0;
++ return rc;
++}
++
++static int sleep_main_thread(struct dwc_otg2 *otg)
++{
++ int rc = 0;
++
++ do {
++ rc = sleep_main_thread_timeout(otg, 5000);
++ } while (rc == 0);
++
++ return rc;
++}
++
++static void get_and_clear_events(struct dwc_otg2 *otg,
++ u32 otg_mask,
++ u32 user_mask,
++ u32 *otg_events,
++ u32 *user_events)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&otg->lock, flags);
++
++ if (otg_events) {
++ if (otg->otg_events & otg_mask) {
++ *otg_events = otg->otg_events;
++ otg->otg_events &= ~otg_mask;
++ } else
++ *otg_events = 0;
++ }
++
++ if (user_events) {
++ if (otg->user_events & user_mask) {
++ *user_events = otg->user_events;
++ otg->user_events &= ~user_mask;
++ } else
++ *user_events = 0;
++ }
++
++ spin_unlock_irqrestore(&otg->lock, flags);
++}
++
++static int check_event(struct dwc_otg2 *otg,
++ u32 otg_mask,
++ u32 user_mask,
++ u32 *otg_events,
++ u32 *user_events)
++{
++ get_and_clear_events(otg, otg_mask, user_mask,
++ otg_events, user_events);
++
++ otg_dbg(otg, "Event occurred:");
++
++ if (otg_events && (*otg_events & otg_mask)) {
++ otg_dbg(otg, "otg_events=0x%x, otg_mask=0x%x",
++ *otg_events, otg_mask);
++ return 1;
++ }
++
++ if (user_events && (*user_events & user_mask)) {
++ otg_dbg(otg, "user_events=0x%x, user_mask=0x%x",
++ *user_events, user_mask);
++ return 1;
++ }
++
++ return 0;
++}
++
++static int sleep_until_event(struct dwc_otg2 *otg,
++ u32 otg_mask, u32 user_mask,
++ u32 *otg_events, u32 *user_events,
++ int timeout)
++{
++ int rc = 0;
++
++ pm_runtime_mark_last_busy(otg->dev);
++ pm_runtime_put_autosuspend(otg->dev);
++ /* Wait until it occurs, or timeout, or interrupt. */
++ if (timeout) {
++ otg_dbg(otg, "Waiting for event (timeout=%d)...\n", timeout);
++ rc = sleep_main_thread_until_condition_timeout(otg,
++ check_event(otg, otg_mask,
++ user_mask, otg_events, user_events), timeout);
++ } else {
++ otg_dbg(otg, "Waiting for event (no timeout)...\n");
++ rc = sleep_main_thread_until_condition(otg,
++ check_event(otg, otg_mask,
++ user_mask, otg_events, user_events));
++ }
++ pm_runtime_get_sync(otg->dev);
++
++ /* Disable the events */
++ otg_write(otg, OEVTEN, 0);
++ otg_write(otg, ADPEVTEN, 0);
++
++ otg_dbg(otg, "Woke up rc=%d\n", rc);
++
++ return rc;
++}
++
++
++static int start_host(struct dwc_otg2 *otg)
++{
++ int ret = 0;
++ struct usb_hcd *hcd = NULL;
++
++ otg_dbg(otg, "\n");
++
++ if (!otg->otg.host) {
++ otg_err(otg, "Haven't set host yet!\n");
++ return -ENODEV;
++ }
++
++ if (dwc3_otg_pdata->prepare_start_host)
++ ret = dwc3_otg_pdata->prepare_start_host(otg);
++
++ /* Start host driver */
++ hcd = container_of(otg->otg.host, struct usb_hcd, self);
++ ret = otg->start_host(hcd);
++
++ return ret;
++}
++
++static int stop_host(struct dwc_otg2 *otg)
++{
++ int ret = -1;
++ struct usb_hcd *hcd = NULL;
++
++ otg_dbg(otg, "\n");
++
++ hcd = container_of(otg->otg.host, struct usb_hcd, self);
++ if (otg->otg.host)
++ ret = otg->stop_host(hcd);
++
++ if (dwc3_otg_pdata->after_stop_host)
++ ret = dwc3_otg_pdata->after_stop_host(otg);
++
++ return ret;
++}
++
++static void start_peripheral(struct dwc_otg2 *otg)
++{
++ struct usb_gadget *gadget;
++ int ret;
++
++ if (dwc3_otg_pdata->prepare_start_peripheral)
++ ret = dwc3_otg_pdata->prepare_start_peripheral(otg);
++
++ gadget = otg->otg.gadget;
++ if (!gadget) {
++ otg_err(otg, "Haven't set gadget yet!\n");
++ return;
++ }
++
++ otg->start_device(gadget);
++}
++
++static void stop_peripheral(struct dwc_otg2 *otg)
++{
++ struct usb_gadget *gadget = otg->otg.gadget;
++ int ret;
++
++ if (!gadget)
++ return;
++
++ otg->stop_device(gadget);
++
++ if (dwc3_otg_pdata->after_stop_peripheral)
++ ret = dwc3_otg_pdata->after_stop_peripheral(otg);
++}
++
++static int get_id(struct dwc_otg2 *otg)
++{
++ if (dwc3_otg_pdata->get_id)
++ return dwc3_otg_pdata->get_id(otg);
++ return RID_UNKNOWN;
++}
++
++static int dwc_otg_notify_charger_type(struct dwc_otg2 *otg,
++ enum power_supply_charger_event event)
++{
++ if (dwc3_otg_pdata->notify_charger_type)
++ return dwc3_otg_pdata->notify_charger_type(otg, event);
++
++ return 0;
++}
++
++static int dwc_otg_get_chrg_status(struct usb_phy *x, void *data)
++{
++ unsigned long flags;
++ struct power_supply_cable_props *cap =
++ (struct power_supply_cable_props *)data;
++ struct dwc_otg2 *otg = the_transceiver;
++
++ if (!x)
++ return -ENODEV;
++
++ if (!data)
++ return -EINVAL;
++
++ spin_lock_irqsave(&otg->lock, flags);
++ cap->chrg_type = otg->charging_cap.chrg_type;
++ cap->chrg_evt = otg->charging_cap.chrg_evt;
++ cap->ma = otg->charging_cap.ma;
++ spin_unlock_irqrestore(&otg->lock, flags);
++
++ return 0;
++}
++
++static int dwc_otg_enable_vbus(struct dwc_otg2 *otg, int enable)
++{
++ if (dwc3_otg_pdata->enable_vbus)
++ return dwc3_otg_pdata->enable_vbus(otg, enable);
++
++ return -EINVAL;
++}
++
++static int is_self_powered_b_device(struct dwc_otg2 *otg)
++{
++ return get_id(otg) == RID_GND;
++}
++
++static enum dwc_otg_state do_wait_vbus_raise(struct dwc_otg2 *otg)
++{
++ int ret;
++ u32 otg_events = 0;
++ u32 user_events = 0;
++ u32 otg_mask = 0;
++ u32 user_mask = 0;
++
++ otg_mask = OEVT_B_DEV_SES_VLD_DET_EVNT;
++
++ ret = sleep_until_event(otg, otg_mask,
++ user_mask, &otg_events,
++ &user_events, VBUS_TIMEOUT);
++ if (ret < 0)
++ return DWC_STATE_EXIT;
++
++ if (otg_events & OEVT_B_DEV_SES_VLD_DET_EVNT) {
++ otg_dbg(otg, "OEVT_B_SES_VLD_EVT\n");
++ return DWC_STATE_CHARGER_DETECTION;
++ }
++
++ /* timeout*/
++ if (!ret)
++ return DWC_STATE_A_HOST;
++
++ return DWC_STATE_B_IDLE;
++}
++
++static enum dwc_otg_state do_wait_vbus_fall(struct dwc_otg2 *otg)
++{
++ int ret;
++
++ u32 otg_events = 0;
++ u32 user_events = 0;
++ u32 otg_mask = 0;
++ u32 user_mask = 0;
++
++ otg_mask = OEVT_A_DEV_SESS_END_DET_EVNT;
++
++ ret = sleep_until_event(otg, otg_mask,
++ user_mask, &otg_events,
++ &user_events, VBUS_TIMEOUT);
++ if (ret < 0)
++ return DWC_STATE_EXIT;
++
++ if (otg_events & OEVT_A_DEV_SESS_END_DET_EVNT) {
++ otg_dbg(otg, "OEVT_A_DEV_SESS_END_DET_EVNT\n");
++ if (otg->charging_cap.chrg_type ==
++ POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK)
++ dwc_otg_notify_charger_type(otg,
++ POWER_SUPPLY_CHARGER_EVENT_DISCONNECT);
++ return DWC_STATE_B_IDLE;
++ }
++
++ /* timeout*/
++ if (!ret) {
++ otg_err(otg, "Haven't get VBus drop event! Maybe something wrong\n");
++ return DWC_STATE_B_IDLE;
++ }
++
++ return DWC_STATE_INVALID;
++}
++
++static enum dwc_otg_state do_charging(struct dwc_otg2 *otg)
++{
++ int ret;
++ u32 otg_events = 0;
++ u32 user_events = 0;
++ u32 otg_mask = 0;
++ u32 user_mask = 0;
++
++ otg_mask = OEVT_A_DEV_SESS_END_DET_EVNT;
++
++ if (dwc3_otg_pdata->do_charging)
++ dwc3_otg_pdata->do_charging(otg);
++
++ ret = sleep_until_event(otg, otg_mask,
++ user_mask, &otg_events,
++ &user_events, 0);
++ if (ret < 0)
++ return DWC_STATE_EXIT;
++
++ if (otg_events & OEVT_A_DEV_SESS_END_DET_EVNT) {
++ otg_dbg(otg, "OEVT_A_DEV_SESS_END_DET_EVNT\n");
++ dwc_otg_notify_charger_type(otg,
++ POWER_SUPPLY_CHARGER_EVENT_DISCONNECT);
++ return DWC_STATE_B_IDLE;
++ }
++
++ return DWC_STATE_INVALID;
++}
++
++static enum power_supply_charger_cable_type
++ get_charger_type(struct dwc_otg2 *otg)
++{
++ if (dwc3_otg_pdata->get_charger_type)
++ return dwc3_otg_pdata->get_charger_type(otg);
++
++ return POWER_SUPPLY_CHARGER_TYPE_NONE;
++}
++
++static enum dwc_otg_state do_charger_detection(struct dwc_otg2 *otg)
++{
++ enum dwc_otg_state state = DWC_STATE_INVALID;
++ enum power_supply_charger_cable_type charger =
++ POWER_SUPPLY_CHARGER_TYPE_NONE;
++ unsigned long flags, ma = 0;
++
++ charger = get_charger_type(otg);
++ switch (charger) {
++ case POWER_SUPPLY_CHARGER_TYPE_ACA_A:
++ case POWER_SUPPLY_CHARGER_TYPE_ACA_B:
++ case POWER_SUPPLY_CHARGER_TYPE_ACA_C:
++ otg_err(otg, "Ignore micro ACA charger.\n");
++ charger = POWER_SUPPLY_CHARGER_TYPE_NONE;
++ break;
++ case POWER_SUPPLY_CHARGER_TYPE_USB_SDP:
++ case POWER_SUPPLY_CHARGER_TYPE_USB_CDP:
++ state = DWC_STATE_B_PERIPHERAL;
++ break;
++ case POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK:
++ state = DWC_STATE_A_HOST;
++ break;
++ case POWER_SUPPLY_CHARGER_TYPE_USB_DCP:
++ case POWER_SUPPLY_CHARGER_TYPE_SE1:
++ state = DWC_STATE_CHARGING;
++ break;
++ case POWER_SUPPLY_CHARGER_TYPE_NONE:
++ default:
++ if (is_self_powered_b_device(otg)) {
++ state = DWC_STATE_A_HOST;
++ charger = POWER_SUPPLY_CHARGER_TYPE_B_DEVICE;
++ break;
++ }
++ };
++
++ switch (charger) {
++ case POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK:
++ case POWER_SUPPLY_CHARGER_TYPE_ACA_A:
++ case POWER_SUPPLY_CHARGER_TYPE_ACA_B:
++ case POWER_SUPPLY_CHARGER_TYPE_ACA_C:
++ case POWER_SUPPLY_CHARGER_TYPE_USB_DCP:
++ case POWER_SUPPLY_CHARGER_TYPE_USB_CDP:
++ case POWER_SUPPLY_CHARGER_TYPE_SE1:
++ ma = 1500;
++ break;
++ case POWER_SUPPLY_CHARGER_TYPE_USB_SDP:
++ /* Notify SDP current is 100ma before enumeration. */
++ ma = 100;
++ break;
++ default:
++ otg_err(otg, "Charger type is not valid to notify battery\n");
++ return -EINVAL;
++ }
++
++ spin_lock_irqsave(&otg->lock, flags);
++ otg->charging_cap.chrg_type = charger;
++ otg->charging_cap.ma = ma;
++ spin_unlock_irqrestore(&otg->lock, flags);
++
++ switch (charger) {
++ case POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK:
++ case POWER_SUPPLY_CHARGER_TYPE_USB_DCP:
++ case POWER_SUPPLY_CHARGER_TYPE_USB_CDP:
++ case POWER_SUPPLY_CHARGER_TYPE_SE1:
++ if (dwc_otg_notify_charger_type(otg,
++ POWER_SUPPLY_CHARGER_EVENT_CONNECT) < 0)
++ otg_err(otg, "Notify battery type failed!\n");
++ break;
++ case POWER_SUPPLY_CHARGER_TYPE_USB_SDP:
++ /* SDP is complicate, it will be handle in set_power */
++ default:
++ break;
++ }
++
++ return state;
++}
++
++static enum dwc_otg_state do_connector_id_status(struct dwc_otg2 *otg)
++{
++ int ret;
++ unsigned long flags;
++ u32 events = 0, user_events = 0;
++ u32 otg_mask = 0, user_mask = 0;
++
++ otg_dbg(otg, "\n");
++ spin_lock_irqsave(&otg->lock, flags);
++ otg->charging_cap.chrg_type = POWER_SUPPLY_CHARGER_TYPE_NONE;
++ otg->charging_cap.ma = 0;
++ otg->charging_cap.chrg_evt = POWER_SUPPLY_CHARGER_EVENT_DISCONNECT;
++ spin_unlock_irqrestore(&otg->lock, flags);
++
++stay_b_idle:
++ otg_mask = OEVT_CONN_ID_STS_CHNG_EVNT |
++ OEVT_B_DEV_SES_VLD_DET_EVNT;
++
++ user_mask = USER_ID_B_CHANGE_EVENT |
++ USER_ID_A_CHANGE_EVENT;
++
++ if (dwc3_otg_pdata->b_idle)
++ dwc3_otg_pdata->b_idle(otg);
++
++ ret = sleep_until_event(otg, otg_mask,
++ user_mask, &events,
++ &user_events, 0);
++ if (ret < 0)
++ return DWC_STATE_EXIT;
++
++ if (events & OEVT_B_DEV_SES_VLD_DET_EVNT) {
++ otg_dbg(otg, "OEVT_B_DEV_SES_VLD_DET_EVNT\n");
++ return DWC_STATE_CHARGER_DETECTION;
++ }
++
++ if (events & OEVT_CONN_ID_STS_CHNG_EVNT) {
++ otg_dbg(otg, "OEVT_CONN_ID_STS_CHNG_EVNT\n");
++
++ /* Prevent user fast plug out after plug in.
++ * It will cause the first ID change event lost.
++ * So need to check real ID currently.
++ */
++ if (get_id(otg) == RID_FLOAT) {
++ otg_dbg(otg, "Stay DWC_STATE_INIT\n");
++ goto stay_b_idle;
++ }
++ return DWC_STATE_WAIT_VBUS_RAISE;
++ }
++
++ if (user_events & USER_ID_A_CHANGE_EVENT) {
++ otg_dbg(otg, "events is user id A change\n");
++ return DWC_STATE_A_HOST;
++ }
++
++ if (user_events & USER_ID_B_CHANGE_EVENT) {
++ otg_dbg(otg, "events is user id B change\n");
++ return DWC_STATE_B_PERIPHERAL;
++ }
++
++ return DWC_STATE_B_IDLE;
++}
++
++static enum dwc_otg_state do_a_host(struct dwc_otg2 *otg)
++{
++ int rc = 0;
++ u32 otg_events, user_events, otg_mask, user_mask;
++ int id = RID_UNKNOWN;
++ unsigned long flags;
++
++ if (otg->charging_cap.chrg_type !=
++ POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK) {
++ dwc_otg_enable_vbus(otg, 1);
++
++ /* meant receive vbus valid event*/
++ if (do_wait_vbus_raise(otg) == DWC_STATE_A_HOST)
++ otg_err(otg, "Drive VBUS maybe fail!\n");
++ }
++
++ rc = start_host(otg);
++ if (rc < 0) {
++ stop_host(otg);
++ otg_err(otg, "start_host failed!");
++ return DWC_STATE_INVALID;
++ }
++
++stay_host:
++ otg_events = 0;
++ user_events = 0;
++
++ user_mask = USER_A_BUS_DROP |
++ USER_ID_B_CHANGE_EVENT;
++ otg_mask = OEVT_CONN_ID_STS_CHNG_EVNT |
++ OEVT_A_DEV_SESS_END_DET_EVNT;
++
++ rc = sleep_until_event(otg,
++ otg_mask, user_mask,
++ &otg_events, &user_events, 0);
++ if (rc < 0) {
++ stop_host(otg);
++ return DWC_STATE_EXIT;
++ }
++
++ /* Higher priority first */
++ if (otg_events & OEVT_A_DEV_SESS_END_DET_EVNT) {
++ otg_dbg(otg, "OEVT_A_DEV_SESS_END_DET_EVNT\n");
++
++ /* ACA-Dock plug out */
++ if (otg->charging_cap.chrg_type ==
++ POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK)
++ dwc_otg_notify_charger_type(otg,
++ POWER_SUPPLY_CHARGER_EVENT_DISCONNECT);
++ else
++ dwc_otg_enable_vbus(otg, 0);
++
++ stop_host(otg);
++ return DWC_STATE_B_IDLE;
++ }
++
++ if (user_events & USER_A_BUS_DROP) {
++ /* Due to big consume by DUT, even ACA-Dock connected,
++ * the battery capability still maybe decrease. For this
++ * case, still save host mode. Because DUT haven't drive VBus.*/
++ if (otg->charging_cap.chrg_type ==
++ POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK)
++ goto stay_host;
++
++ dwc_otg_enable_vbus(otg, 0);
++ stop_host(otg);
++ return DWC_STATE_B_IDLE;
++ }
++
++ if (otg_events & OEVT_CONN_ID_STS_CHNG_EVNT) {
++ otg_dbg(otg, "OEVT_CONN_ID_STS_CHNG_EVNT\n");
++ id = get_id(otg);
++
++ /* Plug out ACA_DOCK/USB device */
++ if (id == RID_FLOAT) {
++ if (otg->charging_cap.chrg_type ==
++ POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK) {
++ /* ACA_DOCK plug out, receive
++ * id change prior to vBus change
++ */
++ stop_host(otg);
++ } else {
++ /* Normal USB device plug out */
++ spin_lock_irqsave(&otg->lock, flags);
++ otg->charging_cap.chrg_type =
++ POWER_SUPPLY_CHARGER_TYPE_NONE;
++ spin_unlock_irqrestore(&otg->lock, flags);
++
++ stop_host(otg);
++ dwc_otg_enable_vbus(otg, 0);
++ }
++ } else if (id == RID_GND || id == RID_A) {
++ otg_dbg(otg, "Stay DWC_STATE_A_HOST!!\n");
++ /* Prevent user fast plug in after plug out.
++ * It will cause the first ID change event lost.
++ * So need to check real ID currently.
++ */
++ goto stay_host;
++ } else {
++ otg_err(otg, "Meet invalid charger cases!");
++ spin_lock_irqsave(&otg->lock, flags);
++ otg->charging_cap.chrg_type =
++ POWER_SUPPLY_CHARGER_TYPE_NONE;
++ spin_unlock_irqrestore(&otg->lock, flags);
++
++ stop_host(otg);
++ }
++ return DWC_STATE_WAIT_VBUS_FALL;
++ }
++
++ /* Higher priority first */
++ if (user_events & USER_ID_B_CHANGE_EVENT) {
++ otg_dbg(otg, "USER_ID_B_CHANGE_EVENT\n");
++ stop_host(otg);
++ otg->user_events |= USER_ID_B_CHANGE_EVENT;
++ return DWC_STATE_B_IDLE;
++ }
++
++ /* Invalid state */
++ return DWC_STATE_INVALID;
++}
++
++static int do_b_peripheral(struct dwc_otg2 *otg)
++{
++ int rc = 0;
++ u32 otg_mask, user_mask, otg_events, user_events;
++
++ otg_mask = 0;
++ user_mask = 0;
++ otg_events = 0;
++ user_events = 0;
++
++ otg_mask = OEVT_A_DEV_SESS_END_DET_EVNT;
++ user_mask = USER_ID_A_CHANGE_EVENT;
++
++ rc = sleep_until_event(otg,
++ otg_mask, user_mask,
++ &otg_events, &user_events, 0);
++ if (rc < 0)
++ return DWC_STATE_EXIT;
++
++ if (otg_events & OEVT_A_DEV_SESS_END_DET_EVNT) {
++ otg_dbg(otg, "OEVT_A_DEV_SESS_END_DET_EVNT\n");
++ dwc_otg_notify_charger_type(otg,
++ POWER_SUPPLY_CHARGER_EVENT_DISCONNECT);
++ return DWC_STATE_B_IDLE;
++ }
++
++ if (user_events & USER_ID_A_CHANGE_EVENT) {
++ otg_dbg(otg, "USER_ID_A_CHANGE_EVENT\n");
++ otg->user_events |= USER_ID_A_CHANGE_EVENT;
++ return DWC_STATE_B_IDLE;
++ }
++
++ return DWC_STATE_INVALID;
++}
++
++/* Charger driver may send ID change and VBus change event to OTG driver.
++ * This is like IRQ handler, just the event source is from charger driver.
++ * Because on Merrifield platform, the ID line and VBus line are connect to
++ * PMic which can make USB controller and PHY power off to save power.
++ */
++static int dwc_otg_handle_notification(struct notifier_block *nb,
++ unsigned long event, void *data)
++{
++ if (dwc3_otg_pdata->otg_notifier_handler)
++ return dwc3_otg_pdata->otg_notifier_handler(nb, event, data);
++
++ return NOTIFY_DONE;
++}
++
++int otg_main_thread(void *data)
++{
++ struct dwc_otg2 *otg = (struct dwc_otg2 *)data;
++
++ /* Allow the thread to be killed by a signal, but set the signal mask
++ * to block everything but INT, TERM, KILL, and USR1. */
++ allow_signal(SIGINT);
++ allow_signal(SIGTERM);
++ allow_signal(SIGKILL);
++ allow_signal(SIGUSR1);
++
++ pm_runtime_get_sync(otg->dev);
++
++ /* Allow the thread to be frozen */
++ set_freezable();
++
++ otg_dbg(otg, "Thread running\n");
++ while (otg->state != DWC_STATE_TERMINATED) {
++ int next = DWC_STATE_B_IDLE;
++ otg_dbg(otg, "\n\n\nMain thread entering state\n");
++
++ switch (otg->state) {
++ case DWC_STATE_B_IDLE:
++ otg_dbg(otg, "DWC_STATE_B_IDLE\n");
++ next = do_connector_id_status(otg);
++ break;
++ case DWC_STATE_CHARGER_DETECTION:
++ otg_dbg(otg, "DWC_STATE_CHARGER_DETECTION\n");
++ next = do_charger_detection(otg);
++ break;
++ case DWC_STATE_WAIT_VBUS_RAISE:
++ otg_dbg(otg, "DWC_STATE_WAIT_VBUS_RAISE\n");
++ next = do_wait_vbus_raise(otg);
++ break;
++ case DWC_STATE_WAIT_VBUS_FALL:
++ otg_dbg(otg, "DWC_STATE_WAIT_VBUS_FALL\n");
++ next = do_wait_vbus_fall(otg);
++ break;
++ case DWC_STATE_CHARGING:
++ otg_dbg(otg, "DWC_STATE_CHARGING\n");
++ next = do_charging(otg);
++ break;
++ case DWC_STATE_A_HOST:
++ otg_dbg(otg, "DWC_STATE_A_HOST\n");
++ next = do_a_host(otg);
++ break;
++ case DWC_STATE_B_PERIPHERAL:
++ otg_dbg(otg, "DWC_STATE_B_PERIPHERAL\n");
++ start_peripheral(otg);
++ next = do_b_peripheral(otg);
++
++ stop_peripheral(otg);
++ break;
++ case DWC_STATE_EXIT:
++ otg_dbg(otg, "DWC_STATE_EXIT\n");
++ next = DWC_STATE_TERMINATED;
++ break;
++ case DWC_STATE_INVALID:
++ otg_dbg(otg, "DWC_STATE_INVALID!!!\n");
++ default:
++ otg_dbg(otg, "Unknown State %d, sleeping...\n",
++ otg->state);
++ sleep_main_thread(otg);
++ break;
++ }
++
++ otg->prev = otg->state;
++ otg->state = next;
++ }
++
++ pm_runtime_mark_last_busy(otg->dev);
++ pm_runtime_put_autosuspend(otg->dev);
++ otg->main_thread = NULL;
++ otg_dbg(otg, "OTG main thread exiting....\n");
++
++ return 0;
++}
++
++static void start_main_thread(struct dwc_otg2 *otg)
++{
++ enum dwc3_otg_mode mode = dwc3_otg_pdata->mode;
++ bool children_ready = false;
++
++ mutex_lock(&lock);
++
++ if ((mode == DWC3_DEVICE_ONLY) &&
++ otg->otg.gadget)
++ children_ready = true;
++
++ if ((mode == DWC3_HOST_ONLY) &&
++ otg->otg.host)
++ children_ready = true;
++
++ if ((mode == DWC3_DRD) &&
++ otg->otg.host && otg->otg.gadget)
++ children_ready = true;
++
++ if (!otg->main_thread && children_ready) {
++ otg_dbg(otg, "Starting OTG main thread\n");
++ otg->main_thread = kthread_create(otg_main_thread, otg, "otg");
++ wake_up_process(otg->main_thread);
++ }
++ mutex_unlock(&lock);
++}
++
++static void stop_main_thread(struct dwc_otg2 *otg)
++{
++ mutex_lock(&lock);
++ if (otg->main_thread) {
++ otg_dbg(otg, "Stopping OTG main thread\n");
++ otg->state = DWC_STATE_EXIT;
++ dwc3_wakeup_otg_thread(otg);
++ }
++ mutex_unlock(&lock);
++}
++
++static int dwc_otg2_set_peripheral(struct usb_otg *x,
++ struct usb_gadget *gadget)
++{
++ struct dwc_otg2 *otg;
++
++ if (!x) {
++ otg_err(otg, "otg is NULL!\n");
++ return -ENODEV;
++ }
++
++ otg = xceiv_to_dwc_otg2(x);
++ otg_dbg(otg, "\n");
++
++ if (!gadget) {
++ otg->otg.gadget = NULL;
++ stop_main_thread(otg);
++ return -ENODEV;
++ }
++
++ otg->otg.gadget = gadget;
++ otg->usb2_phy.state = OTG_STATE_B_IDLE;
++ start_main_thread(otg);
++ return 0;
++}
++
++static int dwc_otg2_set_host(struct usb_otg *x, struct usb_bus *host)
++{
++ struct dwc_otg2 *otg;
++
++ if (!x) {
++ otg_dbg(otg, "otg is NULL!\n");
++ return -ENODEV;
++ }
++
++ otg = xceiv_to_dwc_otg2(x);
++ otg_dbg(otg, "\n");
++
++ if (!host) {
++ otg->otg.host = NULL;
++ stop_main_thread(otg);
++ return -ENODEV;
++ }
++
++ otg->otg.host = host;
++ start_main_thread(otg);
++ return 0;
++}
++
++static int ulpi_read(struct usb_phy *phy, u32 reg)
++{
++ struct dwc_otg2 *otg = container_of(phy, struct dwc_otg2, usb2_phy);
++ u32 val32 = 0, count = 200;
++ u8 val, tmp;
++
++ reg &= 0xFF;
++
++ while (count) {
++ if (otg_read(otg, GUSB2PHYACC0) & GUSB2PHYACC0_VSTSBSY)
++ udelay(5);
++ else
++ break;
++
++ count--;
++ }
++
++ if (!count) {
++ otg_err(otg, "USB2 PHY always busy!!\n");
++ return -EBUSY;
++ }
++
++ count = 200;
++ /* Determine if use extend registers access */
++ if (reg & EXTEND_ULPI_REGISTER_ACCESS_MASK) {
++ otg_dbg(otg, "Access extend registers 0x%x\n", reg);
++ val32 = GUSB2PHYACC0_NEWREGREQ
++ | GUSB2PHYACC0_REGADDR(ULPI_ACCESS_EXTENDED)
++ | GUSB2PHYACC0_VCTRL(reg);
++ } else {
++ otg_dbg(otg, "Access normal registers 0x%x\n", reg);
++ val32 = GUSB2PHYACC0_NEWREGREQ | GUSB2PHYACC0_REGADDR(reg)
++ | GUSB2PHYACC0_VCTRL(0x00);
++ }
++ otg_write(otg, GUSB2PHYACC0, val32);
++
++ while (count) {
++ if (otg_read(otg, GUSB2PHYACC0) & GUSB2PHYACC0_VSTSDONE) {
++ val = otg_read(otg, GUSB2PHYACC0) &
++ GUSB2PHYACC0_REGDATA_MASK;
++ otg_dbg(otg, "%s - reg 0x%x data 0x%x\n",
++ __func__, reg, val);
++ goto cleanup;
++ }
++
++ count--;
++ }
++
++ otg_err(otg, "%s read PHY data failed.\n", __func__);
++
++ return -ETIMEDOUT;
++
++cleanup:
++ /* Clear GUSB2PHYACC0[16:21] before return.
++ * Otherwise, it will cause PHY can't in workable
++ * state. This is one dwc3 controller silicon bug. */
++ tmp = otg_read(otg, GUSB2PHYACC0);
++ otg_write(otg, GUSB2PHYACC0, tmp &
++ ~GUSB2PHYACC0_REGADDR(0x3F));
++ return val;
++}
++
++static int ulpi_write(struct usb_phy *phy, u32 val, u32 reg)
++{
++ struct dwc_otg2 *otg = container_of(phy, struct dwc_otg2, usb2_phy);
++ u32 val32 = 0, count = 200;
++ u8 tmp;
++
++ val &= 0xFF;
++ reg &= 0xFF;
++
++ while (count) {
++ if (otg_read(otg, GUSB2PHYACC0) & GUSB2PHYACC0_VSTSBSY)
++ udelay(5);
++ else
++ break;
++
++ count--;
++ }
++
++ if (!count) {
++ otg_err(otg, "USB2 PHY always busy!!\n");
++ return -EBUSY;
++ }
++
++ count = 200;
++
++ if (reg & EXTEND_ULPI_REGISTER_ACCESS_MASK) {
++ otg_dbg(otg, "Access extend registers 0x%x\n", reg);
++ val32 = GUSB2PHYACC0_NEWREGREQ
++ | GUSB2PHYACC0_REGADDR(ULPI_ACCESS_EXTENDED)
++ | GUSB2PHYACC0_VCTRL(reg)
++ | GUSB2PHYACC0_REGWR | GUSB2PHYACC0_REGDATA(val);
++ } else {
++ otg_dbg(otg, "Access normal registers 0x%x\n", reg);
++ val32 = GUSB2PHYACC0_NEWREGREQ
++ | GUSB2PHYACC0_REGADDR(reg)
++ | GUSB2PHYACC0_REGWR
++ | GUSB2PHYACC0_REGDATA(val);
++ }
++ otg_write(otg, GUSB2PHYACC0, val32);
++
++ while (count) {
++ if (otg_read(otg, GUSB2PHYACC0) & GUSB2PHYACC0_VSTSDONE) {
++ otg_dbg(otg, "%s - reg 0x%x data 0x%x write done\n",
++ __func__, reg, val);
++ goto cleanup;
++ }
++
++ count--;
++ }
++
++ otg_err(otg, "%s read PHY data failed.\n", __func__);
++
++ return -ETIMEDOUT;
++
++cleanup:
++ /* Clear GUSB2PHYACC0[16:21] before return.
++ * Otherwise, it will cause PHY can't in workable
++ * state. This is one dwc3 controller silicon bug. */
++ tmp = otg_read(otg, GUSB2PHYACC0);
++ otg_write(otg, GUSB2PHYACC0, tmp &
++ ~GUSB2PHYACC0_REGADDR(0x3F));
++ return 0;
++}
++
++static struct usb_phy_io_ops dwc_otg_io_ops = {
++ .read = ulpi_read,
++ .write = ulpi_write,
++};
++
++static struct dwc_otg2 *dwc3_otg_alloc(struct device *dev)
++{
++ struct dwc_otg2 *otg = NULL;
++ struct usb_phy *usb_phy;
++ int retval;
++
++ otg = kzalloc(sizeof(*otg), GFP_KERNEL);
++ if (!otg) {
++ otg_err(otg, "Alloc otg failed\n");
++ return NULL;
++ }
++
++ the_transceiver = otg;
++ otg->otg_data = dev->platform_data;
++
++ usb_phy = &otg->usb2_phy;
++ otg->otg.phy = usb_phy;
++ otg->usb2_phy.otg = &otg->otg;
++
++ otg->dev = dev;
++ otg->usb3_phy.dev = otg->dev;
++ otg->usb3_phy.label = "dwc-usb3-phy";
++ otg->usb3_phy.state = OTG_STATE_UNDEFINED;
++ otg->usb3_phy.otg = &otg->otg;
++ otg->usb2_phy.dev = otg->dev;
++ otg->usb2_phy.label = "dwc-usb2-phy";
++ otg->usb2_phy.state = OTG_STATE_UNDEFINED;
++ otg->usb2_phy.set_power = dwc3_otg_pdata->set_power;
++ otg->usb2_phy.get_chrg_status = dwc_otg_get_chrg_status;
++ otg->usb2_phy.io_ops = &dwc_otg_io_ops;
++ otg->usb2_phy.otg = &otg->otg;
++ otg->otg.set_host = dwc_otg2_set_host;
++ otg->otg.set_peripheral = dwc_otg2_set_peripheral;
++ ATOMIC_INIT_NOTIFIER_HEAD(&otg->usb2_phy.notifier);
++ ATOMIC_INIT_NOTIFIER_HEAD(&otg->usb3_phy.notifier);
++
++ otg->state = DWC_STATE_B_IDLE;
++ spin_lock_init(&otg->lock);
++ init_waitqueue_head(&otg->main_wq);
++
++ /* Register otg notifier to monitor ID and VBus change events */
++ otg->nb.notifier_call = dwc_otg_handle_notification;
++ usb_register_notifier(&otg->usb2_phy, &otg->nb);
++
++ otg_dbg(otg, "Version: %s\n", VERSION);
++ retval = usb_add_phy(&otg->usb2_phy, USB_PHY_TYPE_USB2);
++ if (retval) {
++ otg_err(otg, "can't register transceiver, err: %d\n",
++ retval);
++ goto err1;
++ }
++
++ retval = usb_add_phy(&otg->usb3_phy, USB_PHY_TYPE_USB3);
++ if (retval) {
++ otg_err(otg, "can't register transceiver, err: %d\n",
++ retval);
++ goto err2;
++ }
++
++ return otg;
++
++err2:
++ usb_remove_phy(&otg->usb2_phy);
++
++err1:
++ kfree(otg);
++ otg = NULL;
++
++ return otg;
++}
++
++static int dwc3_otg_create_children(struct dwc_otg2 *otg,
++ struct resource *res, int num)
++{
++ struct platform_device *dwc_host, *dwc_gadget;
++ enum dwc3_otg_mode mode = dwc3_otg_pdata->mode;
++ int retval = 0, i;
++
++ if (!otg || !res)
++ return -EINVAL;
++
++ if (num != 2)
++ return -EINVAL;
++
++ dwc_host = dwc_gadget = NULL;
++
++ for (i = 0; i < 2; i++) {
++ if (res[i].flags == IORESOURCE_MEM) {
++ otg->usb2_phy.io_priv = ioremap_nocache(
++ res[i].start, res[i].end - res[i].start);
++ if (!otg->usb2_phy.io_priv) {
++ otg_err(otg, "dwc3 otg ioremap failed\n");
++ return -ENOMEM;
++ }
++ break;
++ }
++ }
++
++ /* resource have no mem io resource */
++ if (!otg->usb2_phy.io_priv)
++ return -EINVAL;
++
++ platform_par = kzalloc(sizeof(*platform_par), GFP_KERNEL);
++ if (!platform_par) {
++ otg_err(otg, "alloc dwc_device_par failed\n");
++ goto err1;
++ }
++
++ platform_par->io_addr = otg->usb2_phy.io_priv;
++ platform_par->len = res[i].end - res[i].start;
++
++ if (mode == DWC3_DEVICE_ONLY)
++ goto device_only;
++
++ dwc_host = platform_device_alloc(DWC3_HOST_NAME,
++ HOST_DEVID);
++ if (!dwc_host) {
++ otg_err(otg, "couldn't allocate dwc3 host device\n");
++ goto err2;
++ }
++
++ retval = platform_device_add_resources(dwc_host, res, num);
++ if (retval) {
++ otg_err(otg, "couldn't add resources to dwc3 device\n");
++ goto err3;
++ }
++
++ platform_device_add_data(dwc_host, platform_par,
++ sizeof(struct dwc_device_par));
++
++ dwc_host->dev.dma_mask = otg->dev->dma_mask;
++ dwc_host->dev.dma_parms = otg->dev->dma_parms;
++ dwc_host->dev.parent = otg->dev;
++
++ retval = platform_device_add(dwc_host);
++ if (retval) {
++ otg_err(otg, "failed to register dwc3 host\n");
++ goto err1;
++ }
++
++ otg->host = dwc_host;
++
++ if (mode != DWC3_DRD)
++ return 0;
++
++device_only:
++ dwc_gadget = platform_device_alloc(DWC3_DEVICE_NAME,
++ GADGET_DEVID);
++ if (!dwc_gadget) {
++ otg_err(otg, "couldn't allocate dwc3 device\n");
++ goto err3;
++ }
++
++ retval = platform_device_add_resources(dwc_gadget,
++ res, num);
++ if (retval) {
++ otg_err(otg, "couldn't add resources to dwc3 device\n");
++ goto err3;
++ }
++
++ dwc_gadget->dev.dma_mask = otg->dev->dma_mask;
++ dwc_gadget->dev.dma_parms = otg->dev->dma_parms;
++ dwc_gadget->dev.parent = otg->dev;
++
++ platform_device_add_data(dwc_gadget, platform_par,
++ sizeof(struct dwc_device_par));
++ retval = platform_device_add(dwc_gadget);
++ if (retval) {
++ otg_err(otg, "failed to register dwc3 gadget\n");
++ goto err3;
++ }
++ otg->gadget = dwc_gadget;
++
++ return 0;
++
++err3:
++ if (mode == DWC3_DRD)
++ platform_device_unregister(dwc_host);
++
++err2:
++ kfree(platform_par);
++
++err1:
++ iounmap(otg->usb2_phy.io_priv);
++
++ return retval;
++}
++
++#ifdef CONFIG_PCI
++
++static int dwc_otg_probe(struct pci_dev *pdev,
++ const struct pci_device_id *id)
++{
++ int retval = 0;
++ struct resource res[2];
++ struct dwc_otg2 *otg = NULL;
++ unsigned long resource, len;
++
++ if (!dwc3_otg_pdata)
++ return -ENODEV;
++
++ if (pci_enable_device(pdev) < 0) {
++ dev_err(&pdev->dev, "pci device enable failed\n");
++ return -ENODEV;
++ }
++
++ pci_set_power_state(pdev, PCI_D0);
++ pci_set_master(pdev);
++
++ otg = dwc3_otg_alloc(&pdev->dev);
++ if (!otg) {
++ otg_err(otg, "dwc3 otg init failed\n");
++ goto err;
++ }
++
++ /* control register: BAR 0 */
++ resource = pci_resource_start(pdev, 0);
++ len = pci_resource_len(pdev, 0);
++ if (!request_mem_region(resource, len, driver_name)) {
++ otg_err(otg, "Request memory region failed\n");
++ retval = -EBUSY;
++ goto err;
++ }
++
++ otg_dbg(otg, "dwc otg pci resouce: 0x%lu, len: 0x%lu\n",
++ resource, len);
++ otg_dbg(otg, "vendor: 0x%x, device: 0x%x\n",
++ pdev->vendor, pdev->device);
++
++ memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
++
++ res[0].start = pci_resource_start(pdev, 0);
++ res[0].end = pci_resource_end(pdev, 0);
++ res[0].name = "dwc_usb3_io";
++ res[0].flags = IORESOURCE_MEM;
++
++ res[1].start = pdev->irq;
++ res[1].name = "dwc_usb3_irq";
++ res[1].flags = IORESOURCE_IRQ;
++
++ retval = dwc3_otg_create_children(otg, res, ARRAY_SIZE(res));
++ if (retval) {
++ otg_err(otg, "dwc3 otg create alloc children failed\n");
++ goto err;
++ }
++
++ otg->irqnum = pdev->irq;
++
++ if (dwc3_otg_pdata->platform_init) {
++ retval = dwc3_otg_pdata->platform_init(otg);
++ if (retval)
++ goto err;
++ }
++
++ pm_runtime_set_autosuspend_delay(&pdev->dev, 100);
++ pm_runtime_use_autosuspend(&pdev->dev);
++ pm_runtime_allow(&pdev->dev);
++ pm_runtime_mark_last_busy(otg->dev);
++ pm_runtime_put_autosuspend(&pdev->dev);
++
++ return 0;
++
++err:
++ if (the_transceiver)
++ dwc_otg_remove(pdev);
++
++ return retval;
++}
++
++static void dwc_otg_remove(struct pci_dev *pdev)
++{
++ struct dwc_otg2 *otg = the_transceiver;
++ int resource, len;
++
++ if (otg->gadget)
++ platform_device_unregister(otg->gadget);
++ if (otg->host)
++ platform_device_unregister(otg->host);
++
++ pm_runtime_forbid(&pdev->dev);
++ pm_runtime_set_suspended(&pdev->dev);
++
++ kfree(platform_par);
++ iounmap(otg->usb2_phy.io_priv);
++
++ usb_remove_phy(&otg->usb2_phy);
++ usb_remove_phy(&otg->usb3_phy);
++ kfree(otg);
++ otg = NULL;
++
++ resource = pci_resource_start(pdev, 0);
++ len = pci_resource_len(pdev, 0);
++ release_mem_region(resource, len);
++
++ pci_disable_device(pdev);
++
++ the_transceiver = NULL;
++}
++
++static void dwc_otg_shutdown(struct pci_dev *pdev)
++{
++ struct dwc_otg2 *otg = the_transceiver;
++
++ /* stop main thread, ignore notification events */
++ stop_main_thread(otg);
++
++ pci_disable_device(pdev);
++}
++
++static int dwc_otg_runtime_idle(struct device *dev)
++{
++ if (dwc3_otg_pdata->idle)
++ return dwc3_otg_pdata->idle(the_transceiver);
++
++ return 0;
++}
++
++static int dwc_otg_runtime_suspend(struct device *dev)
++{
++ if (dwc3_otg_pdata->suspend)
++ return dwc3_otg_pdata->suspend(the_transceiver);
++
++ return 0;
++}
++
++static int dwc_otg_runtime_resume(struct device *dev)
++{
++ if (dwc3_otg_pdata->resume)
++ return dwc3_otg_pdata->resume(the_transceiver);
++ return 0;
++}
++
++static int dwc_otg_suspend(struct device *dev)
++{
++ if (dwc3_otg_pdata->suspend)
++ return dwc3_otg_pdata->suspend(the_transceiver);
++ return 0;
++}
++
++static int dwc_otg_resume(struct device *dev)
++{
++ if (dwc3_otg_pdata->resume)
++ return dwc3_otg_pdata->resume(the_transceiver);
++ return 0;
++}
++
++static const struct dev_pm_ops dwc_usb_otg_pm_ops = {
++ .runtime_suspend = dwc_otg_runtime_suspend,
++ .runtime_resume = dwc_otg_runtime_resume,
++ .runtime_idle = dwc_otg_runtime_idle,
++ .suspend = dwc_otg_suspend,
++ .resume = dwc_otg_resume
++};
++
++static DEFINE_PCI_DEVICE_TABLE(pci_ids) = {
++ { PCI_DEVICE_CLASS(((PCI_CLASS_SERIAL_USB << 8) | 0x20), ~0),
++ .vendor = PCI_VENDOR_ID_INTEL,
++ .device = PCI_DEVICE_ID_DWC,
++ },
++ { PCI_DEVICE_CLASS(((PCI_CLASS_SERIAL_USB << 8) | 0x80), ~0),
++ .vendor = PCI_VENDOR_ID_INTEL,
++ .device = PCI_DEVICE_ID_DWC,
++ },
++ { /* end: all zeroes */ }
++};
++
++static struct pci_driver dwc_otg_pci_driver = {
++ .name = (char *) driver_name,
++ .id_table = pci_ids,
++ .probe = dwc_otg_probe,
++ .remove = dwc_otg_remove,
++ .shutdown = dwc_otg_shutdown,
++ .driver = {
++ .name = (char *) driver_name,
++ .pm = &dwc_usb_otg_pm_ops,
++ .owner = THIS_MODULE,
++ },
++};
++#endif
++
++int dwc3_otg_register(struct dwc3_otg_hw_ops *pdata)
++{
++ int retval;
++
++ if (!pdata)
++ return -EINVAL;
++
++ if (dwc3_otg_pdata)
++ return -EBUSY;
++
++ dwc3_otg_pdata = pdata;
++
++#ifdef CONFIG_PCI
++ retval = pci_register_driver(&dwc_otg_pci_driver);
++#endif
++ mutex_init(&lock);
++
++ return retval;
++}
++EXPORT_SYMBOL_GPL(dwc3_otg_register);
++
++int dwc3_otg_unregister(struct dwc3_otg_hw_ops *pdata)
++{
++ if (!pdata)
++ return -EINVAL;
++
++ if (dwc3_otg_pdata != pdata)
++ return -EINVAL;
++
++ dwc3_otg_pdata = NULL;
++
++#ifdef CONFIG_PCI
++ pci_unregister_driver(&dwc_otg_pci_driver);
++#endif
++ mutex_destroy(&lock);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(dwc3_otg_unregister);
++
++static int __init dwc_otg_init(void)
++{
++ return 0;
++}
++module_init(dwc_otg_init);
++
++static void __exit dwc_otg_exit(void)
++{
++}
++module_exit(dwc_otg_exit);
++
++MODULE_AUTHOR("Synopsys, Inc and Wang Yu <yu.y.wang@intel.com>");
++MODULE_DESCRIPTION("DWC3 OTG Driver");
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_VERSION("1.0");
+diff --git a/drivers/usb/dwc3/otg.h b/drivers/usb/dwc3/otg.h
+new file mode 100644
+index 0000000..a1bcd97
+--- /dev/null
++++ b/drivers/usb/dwc3/otg.h
+@@ -0,0 +1,432 @@
++/*
++ * Intel Penwell USB OTG transceiver driver
++ * Copyright (C) 2009 - 2010, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#ifndef __DWC3_OTG_H
++#define __DWC3_OTG_H
++
++#include <linux/usb.h>
++#include <linux/device.h>
++#include <linux/compiler.h>
++#include <linux/power_supply.h>
++#include <linux/usb/gadget.h>
++#include <linux/usb/hcd.h>
++#include <linux/usb/ulpi.h>
++
++
++struct dwc_device_par {
++ void __iomem *io_addr;
++ int len;
++};
++
++#define DWC3_DEVICE_NAME "dwc3-device"
++#define DWC3_HOST_NAME "dwc3-host"
++#define GADGET_DEVID 1
++#define HOST_DEVID 2
++#define DRIVER_VERSION "0.1"
++
++#ifdef CONFIG_USB_DWC3_OTG_DEBUG
++#define DWC_OTG_DEBUG 1
++#else
++#define DWC_OTG_DEBUG 0
++#endif
++
++#define otg_dbg(d, fmt, args...) \
++ do { if (DWC_OTG_DEBUG) dev_dbg((d)->dev, \
++ "%s(): " fmt , __func__, ## args); } while (0)
++#define otg_vdbg(d, fmt, args...) \
++ do { if (DWC_OTG_DEBUG) dev_dbg((d)->dev, \
++ "%s(): " fmt , __func__, ## args); } while (0)
++#define otg_err(d, fmt, args...) \
++ do { if (DWC_OTG_DEBUG) dev_err((d)->dev, \
++ "%s(): " fmt , __func__, ## args); } while (0)
++#define otg_warn(d, fmt, args...) \
++ do { if (DWC_OTG_DEBUG) dev_warn((d)->dev, \
++ "%s(): " fmt , __func__, ## args); } while (0)
++#define otg_info(d, fmt, args...) \
++ do { if (DWC_OTG_DEBUG) dev_info((d)->dev, \
++ "%s(): " fmt , __func__, ## args); } while (0)
++
++#ifdef DEBUG
++#define otg_write(o, reg, val) do { \
++ otg_dbg(o, "OTG_WRITE: reg=0x%05x, val=0x%08x\n", reg, val); \
++ writel(val, ((void *)((o)->usb2_phy.io_priv)) + reg); \
++ } while (0)
++
++#define otg_read(o, reg) ({ \
++ u32 __r; \
++ __r = readl(((void *)((o)->usb2_phy.io_priv)) + reg); \
++ otg_dbg(o, "OTG_READ: reg=0x%05x, val=0x%08x\n", reg, __r); \
++ __r; \
++ })
++#else
++#define otg_write(o, reg, val) \
++ writel(val, ((void *)((o)->usb2_phy.io_priv)) + reg);
++
++#define otg_read(o, reg) ({ \
++ readl(((void *)((o)->usb2_phy.io_priv)) + reg); \
++ })
++#endif
++
++#define GUSB2PHYCFG0 0xc200
++#define GUSB2PHYCFG_SUS_PHY 0x40
++#define GUSB2PHYCFG_PHYSOFTRST (1 << 31)
++#define GUSB2PHYCFG_ULPI_AUTO_RESUME (1 << 15)
++#define GUSB2PHYCFG_ULPI_EXT_VBUS_DRV (1 << 17)
++
++#define EXTEND_ULPI_REGISTER_ACCESS_MASK 0xC0
++#define GUSB2PHYACC0 0xc280
++#define GUSB2PHYACC0_DISULPIDRVR (1 << 26)
++#define GUSB2PHYACC0_NEWREGREQ (1 << 25)
++#define GUSB2PHYACC0_VSTSDONE (1 << 24)
++#define GUSB2PHYACC0_VSTSBSY (1 << 23)
++#define GUSB2PHYACC0_REGWR (1 << 22)
++#define GUSB2PHYACC0_REGADDR(v) ((v & 0x3F) << 16)
++#define GUSB2PHYACC0_EXTREGADDR(v) ((v & 0x3F) << 8)
++#define GUSB2PHYACC0_VCTRL(v) ((v & 0xFF) << 8)
++#define GUSB2PHYACC0_REGDATA(v) (v & 0xFF)
++#define GUSB2PHYACC0_REGDATA_MASK 0xFF
++
++#define GUSB3PIPECTL0 0xc2c0
++#define GUSB3PIPECTL_SUS_EN 0x20000
++#define GUSB3PIPE_DISRXDETP3 (1 << 28)
++#define GUSB3PIPECTL_PHYSOFTRST (1 << 31)
++
++#define GHWPARAMS6 0xc158
++#define GHWPARAMS6_SRP_SUPPORT_ENABLED 0x0400
++#define GHWPARAMS6_HNP_SUPPORT_ENABLED 0x0800
++#define GHWPARAMS6_ADP_SUPPORT_ENABLED 0x1000
++
++#define GUCTL 0xC12C
++#define GUCTL_CMDEVADDR (1 << 15)
++
++#define GCTL 0xc110
++#define GCTL_PRT_CAP_DIR 0x3000
++#define GCTL_PRT_CAP_DIR_SHIFT 12
++#define GCTL_PRT_CAP_DIR_HOST 1
++#define GCTL_PRT_CAP_DIR_DEV 2
++#define GCTL_PRT_CAP_DIR_OTG 3
++#define GCTL_GBL_HIBERNATION_EN 0x2
++#define GCTL_CORESOFTRESET (1 << 11)
++#define GCTL_PWRDNSCALE(x) (x << 19)
++#define GCTL_PWRDNSCALE_MASK (0x1fff << 19)
++
++#define OCFG 0xcc00
++#define OCFG_SRP_CAP 0x01
++#define OCFG_SRP_CAP_SHIFT 0
++#define OCFG_HNP_CAP 0x02
++#define OCFG_HNP_CAP_SHIFT 1
++#define OCFG_OTG_VERSION 0x04
++#define OCFG_OTG_VERSION_SHIFT 2
++
++#define GCTL 0xc110
++#define OCTL 0xcc04
++#define OCTL_HST_SET_HNP_EN 0x01
++#define OCTL_HST_SET_HNP_EN_SHIFT 0
++#define OCTL_DEV_SET_HNP_EN 0x02
++#define OCTL_DEV_SET_HNP_EN_SHIFT 1
++#define OCTL_TERM_SEL_DL_PULSE 0x04
++#define OCTL_TERM_SEL_DL_PULSE_SHIFT 2
++#define OCTL_SES_REQ 0x08
++#define OCTL_SES_REQ_SHIFT 3
++#define OCTL_HNP_REQ 0x10
++#define OCTL_HNP_REQ_SHIFT 4
++#define OCTL_PRT_PWR_CTL 0x20
++#define OCTL_PRT_PWR_CTL_SHIFT 5
++#define OCTL_PERI_MODE 0x40
++#define OCTL_PERI_MODE_SHIFT 6
++
++#define OEVT 0xcc08
++#define OEVT_ERR 0x00000001
++#define OEVT_ERR_SHIFT 0
++#define OEVT_SES_REQ_SCS 0x00000002
++#define OEVT_SES_REQ_SCS_SHIFT 1
++#define OEVT_HST_NEG_SCS 0x00000004
++#define OEVT_HST_NEG_SCS_SHIFT 2
++#define OEVT_B_SES_VLD_EVT 0x00000008
++#define OEVT_B_SES_VLD_EVT_SHIFT 3
++#define OEVT_B_DEV_VBUS_CHNG_EVNT 0x00000100
++#define OEVT_B_DEV_VBUS_CHNG_EVNT_SHIFT 8
++#define OEVT_B_DEV_SES_VLD_DET_EVNT 0x00000200
++#define OEVT_B_DEV_SES_VLD_DET_EVNT_SHIFT 9
++#define OEVT_B_DEV_HNP_CHNG_EVNT 0x00000400
++#define OEVT_B_DEV_HNP_CHNG_EVNT_SHIFT 10
++#define OEVT_B_DEV_B_HOST_END_EVNT 0x00000800
++#define OEVT_B_DEV_B_HOST_END_EVNT_SHIFT 11
++#define OEVT_A_DEV_SESS_END_DET_EVNT 0x00010000
++#define OEVT_A_DEV_SESS_END_DET_EVNT_SHIFT 16
++#define OEVT_A_DEV_SRP_DET_EVNT 0x00020000
++#define OEVT_A_DEV_SRP_DET_EVNT_SHIFT 17
++#define OEVT_A_DEV_HNP_CHNG_EVNT 0x00040000
++#define OEVT_A_DEV_HNP_CHNG_EVNT_SHIFT 18
++#define OEVT_A_DEV_HOST_EVNT 0x00080000
++#define OEVT_A_DEV_HOST_EVNT_SHIFT 19
++#define OEVT_A_DEV_B_DEV_HOST_END_EVNT 0x00100000
++#define OEVT_A_DEV_B_DEV_HOST_END_EVNT_SHIFT 20
++#define OEVT_HOST_ROLE_REQ_INIT_EVNT 0x00400000
++#define OEVT_HOST_ROLE_REQ_INIT_EVNT_SHIFT 22
++#define OEVT_HOST_ROLE_REQ_CONFIRM_EVNT 0x00800000
++#define OEVT_HOST_ROLE_REQ_CONFIRM_EVNT_SHIFT 23
++#define OEVT_CONN_ID_STS_CHNG_EVNT 0x01000000
++#define OEVT_CONN_ID_STS_CHNG_EVNT_SHIFT 24
++#define OEVT_DEV_MOD_EVNT 0x80000000
++#define OEVT_DEV_MOD_EVNT_SHIFT 31
++
++#define OEVTEN 0xcc0c
++
++#define OEVT_ALL (OEVT_CONN_ID_STS_CHNG_EVNT | \
++ OEVT_HOST_ROLE_REQ_INIT_EVNT | \
++ OEVT_HOST_ROLE_REQ_CONFIRM_EVNT | \
++ OEVT_A_DEV_B_DEV_HOST_END_EVNT | \
++ OEVT_A_DEV_HOST_EVNT | \
++ OEVT_A_DEV_HNP_CHNG_EVNT | \
++ OEVT_A_DEV_SRP_DET_EVNT | \
++ OEVT_A_DEV_SESS_END_DET_EVNT | \
++ OEVT_B_DEV_B_HOST_END_EVNT | \
++ OEVT_B_DEV_HNP_CHNG_EVNT | \
++ OEVT_B_DEV_SES_VLD_DET_EVNT | \
++ OEVT_B_DEV_VBUS_CHNG_EVNT)
++
++#define OSTS 0xcc10
++#define OSTS_CONN_ID_STS 0x0001
++#define OSTS_CONN_ID_STS_SHIFT 0
++#define OSTS_A_SES_VLD 0x0002
++#define OSTS_A_SES_VLD_SHIFT 1
++#define OSTS_B_SES_VLD 0x0004
++#define OSTS_B_SES_VLD_SHIFT 2
++#define OSTS_XHCI_PRT_PWR 0x0008
++#define OSTS_XHCI_PRT_PWR_SHIFT 3
++#define OSTS_PERIP_MODE 0x0010
++#define OSTS_PERIP_MODE_SHIFT 4
++#define OSTS_OTG_STATES 0x0f00
++#define OSTS_OTG_STATE_SHIFT 8
++
++#define ADPCFG 0xcc20
++#define ADPCFG_PRB_DSCHGS 0x0c000000
++#define ADPCFG_PRB_DSCHG_SHIFT 26
++#define ADPCFG_PRB_DELTAS 0x30000000
++#define ADPCFG_PRB_DELTA_SHIFT 28
++#define ADPCFG_PRB_PERS 0xc0000000
++#define ADPCFG_PRB_PER_SHIFT 30
++
++#define ADPCTL 0xcc24
++#define ADPCTL_WB 0x01000000
++#define ADPCTL_WB_SHIFT 24
++#define ADPCTL_ADP_RES 0x02000000
++#define ADPCTL_ADP_RES_SHIFT 25
++#define ADPCTL_ADP_EN 0x04000000
++#define ADPCTL_ADP_EN_SHIFT 26
++#define ADPCTL_ENA_SNS 0x08000000
++#define ADPCTL_ENA_SNS_SHIFT 27
++#define ADPCTL_ENA_PRB 0x10000000
++#define ADPCTL_ENA_PRB_SHIFT 28
++
++#define ADPEVT 0xcc28
++#define ADPEVT_RTIM_EVNTS 0x000007ff
++#define ADPEVT_RTIM_EVNT_SHIFT 0
++#define ADPEVT_ADP_RST_CMPLT_EVNT 0x02000000
++#define ADPEVT_ADP_RST_CMPLT_EVNT_SHIFT 25
++#define ADPEVT_ADP_TMOUT_EVNT 0x04000000
++#define ADPEVT_ADP_TMOUT_EVNT_SHIFT 26
++#define ADPEVT_ADP_SNS_EVNT 0x08000000
++#define ADPEVT_ADP_SNS_EVNT_SHIFT 27
++#define ADPEVT_ADP_PRB_EVNT 0x10000000
++#define ADPEVT_ADP_PRB_EVNT_SHIFT 28
++
++#define ADPEVTEN 0xcc2c
++#define ADPEVTEN_ACC_DONE_EN 0x01000000
++#define ADPEVTEN_ACC_DONE_EN_SHIFT 24
++#define ADPEVTEN_ADP_RST_CMPLT_EVNT_EN 0x02000000
++#define ADPEVTEN_ADP_RST_CMPLT_EVNT_EN_SHIFT 25
++#define ADPEVTEN_ADP_TMOUT_EVNT_EN 0x04000000
++#define ADPEVTEN_ADP_TMOUT_EVNT_EN_SHIFT 26
++#define ADPEVTEN_ADP_SNS_EVNT_EN 0x08000000
++#define ADPEVTEN_ADP_SNS_EVNT_EN_SHIFT 27
++#define ADPEVTEN_ADP_PRB_EVNT_EN 0x10000000
++#define ADPEVTEN_ADP_PRB_EVNT_EN_SHIFT 28
++
++#define RID_A 0x01
++#define RID_B 0x02
++#define RID_C 0x03
++#define RID_FLOAT 0x04
++#define RID_GND 0x05
++#define RID_UNKNOWN 0x00
++
++/** The states for the OTG driver */
++enum dwc_otg_state {
++ DWC_STATE_INVALID = -1,
++
++ /** The initial state, check the connector
++ * id status and determine what mode
++ * (A-device or B-device) to operate in. */
++ DWC_STATE_B_IDLE = 0,
++
++ /* A-Host states */
++ DWC_STATE_A_PROBE,
++ DWC_STATE_A_HOST,
++ DWC_STATE_A_HNP_INIT,
++
++ /* A-Peripheral states */
++ DWC_STATE_A_PERIPHERAL,
++
++ /* B-Peripheral states */
++ DWC_STATE_B_SENSE,
++ DWC_STATE_B_PROBE,
++ DWC_STATE_B_PERIPHERAL,
++ DWC_STATE_B_HNP_INIT,
++
++ /* B-Host states */
++ DWC_STATE_B_HOST,
++
++ /* RSP */
++ DWC_STATE_B_RSP_INIT,
++
++ /* USB charger detection */
++ DWC_STATE_CHARGER_DETECTION,
++
++ /* VBUS */
++ DWC_STATE_WAIT_VBUS_RAISE,
++ DWC_STATE_WAIT_VBUS_FALL,
++
++ /* Charging*/
++ DWC_STATE_CHARGING,
++
++ /* Exit */
++ DWC_STATE_EXIT,
++ DWC_STATE_TERMINATED
++};
++
++/** The main structure to keep track of OTG driver state. */
++struct dwc_otg2 {
++ /** OTG transceiver */
++ struct usb_otg otg;
++ struct usb_phy usb2_phy;
++ struct usb_phy usb3_phy;
++ struct device *dev;
++ int irqnum;
++
++ int main_wakeup_needed;
++ struct task_struct *main_thread;
++ wait_queue_head_t main_wq;
++
++ spinlock_t lock;
++
++ /* Events */
++ u32 otg_events;
++ u32 user_events;
++
++ /** User space ID switch event */
++#define USER_ID_A_CHANGE_EVENT 0x01
++#define USER_ID_B_CHANGE_EVENT 0x02
++ /** a_bus_drop event from userspace */
++#define USER_A_BUS_DROP 0x40
++
++ /* States */
++ enum dwc_otg_state prev;
++ enum dwc_otg_state state;
++ struct platform_device *host;
++ struct platform_device *gadget;
++
++ /* Charger detection */
++ struct power_supply_cable_props charging_cap;
++ struct notifier_block nb;
++
++ /* Interfaces between host/device driver */
++ int (*start_host) (struct usb_hcd *hcd);
++ int (*stop_host) (struct usb_hcd *hcd);
++ int (*start_device)(struct usb_gadget *);
++ int (*stop_device)(struct usb_gadget *);
++ int (*vbus_draw) (struct usb_gadget *, unsigned ma);
++
++ /* Vendor driver private date */
++ void *otg_data;
++};
++
++#define sleep_main_thread_until_condition_timeout(otg, condition, msecs) ({ \
++ int __timeout = msecs; \
++ while (!(condition)) { \
++ otg_dbg(otg, " ... sleeping for %d\n", __timeout); \
++ __timeout = sleep_main_thread_timeout(otg, __timeout); \
++ if (__timeout <= 0) { \
++ break; \
++ } \
++ } \
++ __timeout; \
++ })
++
++#define sleep_main_thread_until_condition(otg, condition) ({ \
++ int __rc = 0; \
++ do { \
++ __rc = sleep_main_thread_until_condition_timeout(otg, \
++ condition, 50000); \
++ } while (__rc == 0); \
++ __rc; \
++ })
++
++#define VBUS_TIMEOUT 300
++#define PCI_DEVICE_ID_DWC 0x119E
++
++enum dwc3_otg_mode {
++ DWC3_DEVICE_ONLY,
++ DWC3_HOST_ONLY,
++ DWC3_DRD,
++};
++
++enum driver_bus_type {
++ DWC3_PLAT,
++ DWC3_PCI,
++};
++
++struct dwc3_otg_hw_ops {
++ enum dwc3_otg_mode mode;
++ enum driver_bus_type bus;
++
++ int (*set_power)(struct usb_phy *_otg, unsigned ma);
++ int (*platform_init)(struct dwc_otg2 *otg);
++ int (*otg_notifier_handler)(struct notifier_block *nb,
++ unsigned long event, void *data);
++ int (*prepare_start_peripheral)(struct dwc_otg2 *otg);
++ int (*prepare_start_host)(struct dwc_otg2 *otg);
++ int (*after_stop_peripheral)(struct dwc_otg2 *otg);
++ int (*after_stop_host)(struct dwc_otg2 *otg);
++ int (*b_idle)(struct dwc_otg2 *otg);
++ int (*do_charging)(struct dwc_otg2 *otg);
++ int (*notify_charger_type)(struct dwc_otg2 *otg,
++ enum power_supply_charger_event event);
++ enum power_supply_charger_cable_type
++ (*get_charger_type)(struct dwc_otg2 *otg);
++ int (*enable_vbus)(struct dwc_otg2 *otg, int enable);
++ int (*get_id)(struct dwc_otg2 *otg);
++
++ int (*idle)(struct dwc_otg2 *otg);
++ int (*suspend)(struct dwc_otg2 *otg);
++ int (*resume)(struct dwc_otg2 *otg);
++};
++
++#define OTG_USB2_100MA 0xfff1
++#define OTG_USB3_150MA 0xfff2
++#define OTG_USB2_500MA 0xfff3
++#define OTG_USB3_900MA 0xfff4
++#define OTG_DEVICE_SUSPEND 0xfffe
++#define OTG_DEVICE_RESUME 0xffff
++
++void dwc3_wakeup_otg_thread(struct dwc_otg2 *otg);
++struct dwc_otg2 *dwc3_get_otg(void);
++int dwc3_otg_register(struct dwc3_otg_hw_ops *pdata);
++int dwc3_otg_unregister(struct dwc3_otg_hw_ops *pdata);
++#endif /* __DWC3_OTG_H */
+diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
+index a777f7b..3f10698 100644
+--- a/drivers/usb/gadget/epautoconf.c
++++ b/drivers/usb/gadget/epautoconf.c
+@@ -188,6 +188,8 @@ ep_matches (
+ ep->address = desc->bEndpointAddress;
+ return 1;
+ }
++EXPORT_SYMBOL_GPL(ep_matches);
++
+
+ static struct usb_ep *
+ find_ep (struct usb_gadget *gadget, const char *name)
+@@ -200,6 +202,7 @@ find_ep (struct usb_gadget *gadget, const char *name)
+ }
+ return NULL;
+ }
++EXPORT_SYMBOL_GPL(find_ep);
+
+ /**
+ * usb_ep_autoconfig_ss() - choose an endpoint matching the ep
+@@ -253,7 +256,11 @@ struct usb_ep *usb_ep_autoconfig_ss(
+ {
+ struct usb_ep *ep;
+ u8 type;
++#ifdef CONFIG_USB_DWC3_GADGET
++ u8 addr;
+
++ addr = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
++#endif
+ type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+ /* First, apply chip-specific "best usage" knowledge.
+@@ -301,10 +308,45 @@ struct usb_ep *usb_ep_autoconfig_ss(
+ if (ep && ep_matches(gadget, ep, desc, ep_comp))
+ goto found_ep;
+ #endif
++
++#ifdef CONFIG_USB_DWC3_GADGET
++ } else if (gadget_is_middwc3tng(gadget)) {
++ if (addr == 0x1) {
++ /* statically assigned ebc-ep1 in/out */
++ if ((desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
++ & USB_DIR_IN)
++ ep = find_ep(gadget, "ep1in");
++ else
++ ep = NULL;
++ } else if (addr == 0x8) {
++ /* statically assigned ebc-ep8 in/out */
++ if ((desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
++ & USB_DIR_IN)
++ ep = find_ep (gadget, "ep8in");
++ else
++ ep = find_ep (gadget, "ep8out");
++ } else
++ ep = NULL;
++ if (ep && ep_matches(gadget, ep, desc, ep_comp))
++ goto found_ep;
++#endif
++
+ }
+
+ /* Second, look at endpoints until an unclaimed one looks usable */
+ list_for_each_entry (ep, &gadget->ep_list, ep_list) {
++
++#ifdef CONFIG_USB_DWC3_GADGET
++ /* ep1in and ep8in are reserved for DWC3 device controller */
++ if (!strncmp(ep->name, "ep1in", 5) ||
++ !strncmp(ep->name, "ep8in", 5))
++ continue;
++ if (gadget_is_middwc3tng(gadget))
++ /* ep1out and ep8out are also reserved */
++ if (!strncmp(ep->name, "ep1out", 6) ||
++ !strncmp(ep->name, "ep8out", 6))
++ continue;
++#endif
+ if (ep_matches(gadget, ep, desc, ep_comp))
+ goto found_ep;
+ }
+diff --git a/drivers/usb/gadget/f_dvc_dfx.c b/drivers/usb/gadget/f_dvc_dfx.c
+new file mode 100644
+index 0000000..6137e11
+--- /dev/null
++++ b/drivers/usb/gadget/f_dvc_dfx.c
+@@ -0,0 +1,922 @@
++/*
++ * Gadget Driver for Android DvC.Dfx Debug Capability
++ *
++ * Copyright (C) 2008-2010, Intel Corporation.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/poll.h>
++#include <linux/delay.h>
++#include <linux/wait.h>
++#include <linux/err.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include <linux/types.h>
++#include <linux/device.h>
++#include <linux/miscdevice.h>
++#include <linux/usb/debug.h>
++#include <linux/sdm.h>
++#include <asm/intel_soc_debug.h>
++
++#define DFX_RX_REQ_MAX 1
++#define DFX_TX_REQ_MAX 2
++#define DFX_BULK_REQ_SIZE 64
++
++#define CONFIG_BOARD_MRFLD_VV
++
++struct dvc_dfx_dev {
++ struct usb_function function;
++ struct usb_composite_dev *cdev;
++ spinlock_t lock;
++ u8 ctrl_id, data_id;
++
++ struct usb_ep *ep_in;
++ struct usb_ep *ep_out;
++
++ int transfering;
++ int online;
++ int online_ctrl;
++ int online_data;
++ int error;
++
++ atomic_t read_excl;
++ atomic_t write_excl;
++ atomic_t open_excl;
++
++ wait_queue_head_t read_wq;
++ wait_queue_head_t write_wq;
++
++ struct usb_request *rx_req[DFX_RX_REQ_MAX];
++
++ struct list_head tx_idle;
++ struct list_head tx_xfer;
++};
++
++static struct usb_interface_assoc_descriptor dfx_iad_desc = {
++ .bLength = sizeof(dfx_iad_desc),
++ .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
++ /* .bFirstInterface = DYNAMIC, */
++ .bInterfaceCount = 2, /* debug control + data */
++ .bFunctionClass = USB_CLASS_DEBUG,
++ .bFunctionSubClass = USB_SUBCLASS_DVC_DFX,
++ /* .bFunctionProtocol = DC_PROTOCOL_VENDOR, */
++ /* .iFunction = 0, */
++};
++
++static struct usb_interface_descriptor dfx_interface_desc = {
++ .bLength = USB_DT_INTERFACE_SIZE,
++ .bDescriptorType = USB_DT_INTERFACE,
++ .bNumEndpoints = 0,
++ .bInterfaceClass = USB_CLASS_DEBUG,
++ .bInterfaceSubClass = USB_SUBCLASS_DEBUG_CONTROL,
++ /* .bInterfaceProtocol = DC_PROTOCOL_VENDOR, */
++};
++
++#define DC_DBG_ATTRI_LENGTH DC_DBG_ATTRI_SIZE(2, 32)
++/* 1 input terminal, 1 output terminal and 1 feature unit */
++#define DC_DBG_TOTAL_LENGTH (DC_DBG_ATTRI_LENGTH)
++
++DECLARE_DC_DEBUG_ATTR_DESCR(DVCD, 2, 32);
++
++static struct DC_DEBUG_ATTR_DESCR(DVCD) dfx_debug_attri_desc = {
++ .bLength = DC_DBG_ATTRI_LENGTH,
++ .bDescriptorType = USB_DT_CS_INTERFACE,
++ .bDescriptorSubtype = DC_DEBUG_ATTRIBUTES,
++ .bcdDC = __constant_cpu_to_le16(0x0100),
++ .wTotalLength = __constant_cpu_to_le16(DC_DBG_TOTAL_LENGTH),
++ .bmSupportedFeatures = 0, /* Debug Event Supported, per SAS */
++ .bControlSize = 2,
++ .bmControl = { /* per SAS */
++ [0] = 0xFF,
++ [1] = 0x3F,
++ },
++ .wAuxDataSize = __constant_cpu_to_le16(0x20),
++/* per SAS v0.3*/
++ .dInputBufferSize = __constant_cpu_to_le32(0x40),
++ .dOutputBufferSize = __constant_cpu_to_le32(0x80),
++ .qBaseAddress = 0, /* revision */
++ .hGlobalID = { /* revision */
++ [0] = 0,
++ [1] = 0,
++ }
++};
++
++static struct usb_interface_descriptor dfx_data_interface_desc = {
++ .bLength = USB_DT_INTERFACE_SIZE,
++ .bDescriptorType = USB_DT_INTERFACE,
++ .bAlternateSetting = 0,
++ .bNumEndpoints = 2,
++ .bInterfaceClass = USB_CLASS_DEBUG,
++ .bInterfaceSubClass = USB_SUBCLASS_DVC_DFX,
++ /* .bInterfaceProtocol = DC_PROTOCOL_VENDOR, */
++};
++
++static struct usb_endpoint_descriptor dfx_fullspeed_in_desc = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_IN,
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_endpoint_descriptor dfx_fullspeed_out_desc = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_OUT,
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_endpoint_descriptor dfx_highspeed_in_desc = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_IN,
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++ .wMaxPacketSize = __constant_cpu_to_le16(512),
++};
++
++static struct usb_endpoint_descriptor dfx_highspeed_out_desc = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_OUT,
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++ .wMaxPacketSize = __constant_cpu_to_le16(512),
++};
++
++static struct usb_endpoint_descriptor dfx_superspeed_in_desc = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_IN,
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++ .wMaxPacketSize = __constant_cpu_to_le16(1024),
++};
++
++static struct usb_ss_ep_comp_descriptor dfx_superspeed_in_comp_desc = {
++ .bLength = USB_DT_SS_EP_COMP_SIZE,
++ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
++ .bMaxBurst = 0,
++ .bmAttributes = 0,
++};
++
++static struct usb_endpoint_descriptor dfx_superspeed_out_desc = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_OUT,
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++ .wMaxPacketSize = __constant_cpu_to_le16(1024),
++};
++
++static struct usb_ss_ep_comp_descriptor dfx_superspeed_out_comp_desc = {
++ .bLength = USB_DT_SS_EP_COMP_SIZE,
++ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
++ .bMaxBurst = 0,
++ .bmAttributes = 0,
++};
++
++/* no INPUT/OUTPUT CONNECTION and UNIT descriptors for DvC.DFx */
++static struct usb_descriptor_header *fs_dfx_descs[] = {
++ (struct usb_descriptor_header *) &dfx_iad_desc,
++ (struct usb_descriptor_header *) &dfx_data_interface_desc,
++ (struct usb_descriptor_header *) &dfx_fullspeed_in_desc,
++ (struct usb_descriptor_header *) &dfx_fullspeed_out_desc,
++
++ (struct usb_descriptor_header *) &dfx_interface_desc,
++ (struct usb_descriptor_header *) &dfx_debug_attri_desc,
++ NULL,
++};
++
++static struct usb_descriptor_header *hs_dfx_descs[] = {
++ (struct usb_descriptor_header *) &dfx_iad_desc,
++ (struct usb_descriptor_header *) &dfx_data_interface_desc,
++ (struct usb_descriptor_header *) &dfx_highspeed_in_desc,
++ (struct usb_descriptor_header *) &dfx_highspeed_out_desc,
++
++ (struct usb_descriptor_header *) &dfx_interface_desc,
++ (struct usb_descriptor_header *) &dfx_debug_attri_desc,
++ NULL,
++};
++
++static struct usb_descriptor_header *ss_dfx_descs[] = {
++ (struct usb_descriptor_header *) &dfx_iad_desc,
++ (struct usb_descriptor_header *) &dfx_data_interface_desc,
++ (struct usb_descriptor_header *) &dfx_superspeed_in_desc,
++ (struct usb_descriptor_header *) &dfx_superspeed_in_comp_desc,
++ (struct usb_descriptor_header *) &dfx_superspeed_out_desc,
++ (struct usb_descriptor_header *) &dfx_superspeed_out_comp_desc,
++
++ (struct usb_descriptor_header *) &dfx_interface_desc,
++ (struct usb_descriptor_header *) &dfx_debug_attri_desc,
++ NULL,
++};
++
++/* string descriptors: */
++
++#define DVCDFX_CTRL_IDX 0
++#define DVCDFX_DATA_IDX 1
++#define DVCDFX_IAD_IDX 2
++
++/* static strings, in UTF-8 */
++static struct usb_string dfx_string_defs[] = {
++ [DVCDFX_CTRL_IDX].s = "Debug Sub-Class DvC.DFx (Control)",
++ [DVCDFX_DATA_IDX].s = "Debug Sub-Class DvC.DFx (Data)",
++ [DVCDFX_IAD_IDX].s = "Debug Sub-Class DvC.DFx",
++ { /* ZEROES END LIST */ },
++};
++
++static struct usb_gadget_strings dfx_string_table = {
++ .language = 0x0409, /* en-us */
++ .strings = dfx_string_defs,
++};
++
++static struct usb_gadget_strings *dfx_strings[] = {
++ &dfx_string_table,
++ NULL,
++};
++
++/*-------------------------------------------------------------------------*/
++
++/* temporary variable used between dvc_dfx_open() and dvc_dfx_gadget_bind() */
++static struct dvc_dfx_dev *_dvc_dfx_dev;
++
++static inline struct dvc_dfx_dev *func_to_dvc_dfx(struct usb_function *f)
++{
++ return container_of(f, struct dvc_dfx_dev, function);
++}
++
++static int dvc_dfx_is_enabled(void)
++{
++ if ((!cpu_has_debug_feature(DEBUG_FEATURE_USB3DFX)) ||
++ (!stm_is_enabled())) {
++ pr_info("%s STM and/or USB3DFX is not enabled\n", __func__);
++ return 0;
++ }
++ return 1;
++}
++
++static struct usb_request *dvc_dfx_request_new(struct usb_ep *ep,
++ int buffer_size, dma_addr_t dma)
++{
++ struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL);
++ if (!req)
++ return NULL;
++
++
++ req->dma = dma;
++ /* now allocate buffers for the requests */
++ req->buf = kmalloc(buffer_size, GFP_KERNEL);
++ if (!req->buf) {
++ usb_ep_free_request(ep, req);
++ return NULL;
++ }
++
++ return req;
++}
++
++static void dvc_dfx_request_free(struct usb_request *req, struct usb_ep *ep)
++{
++ if (req) {
++ kfree(req->buf);
++ usb_ep_free_request(ep, req);
++ }
++}
++
++/* add a request to the tail of a list */
++static void dvc_dfx_req_put(struct dvc_dfx_dev *dev, struct list_head *head,
++ struct usb_request *req)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&dev->lock, flags);
++ list_add_tail(&req->list, head);
++ spin_unlock_irqrestore(&dev->lock, flags);
++}
++
++/* remove a request from the head of a list */
++static struct usb_request *dvc_dfx_req_get(struct dvc_dfx_dev *dev,
++ struct list_head *head)
++{
++ unsigned long flags;
++ struct usb_request *req;
++
++ spin_lock_irqsave(&dev->lock, flags);
++ if (list_empty(head)) {
++ req = 0;
++ } else {
++ req = list_first_entry(head, struct usb_request, list);
++ list_del(&req->list);
++ }
++ spin_unlock_irqrestore(&dev->lock, flags);
++ return req;
++}
++
++static void dvc_dfx_set_disconnected(struct dvc_dfx_dev *dev)
++{
++ dev->transfering = 0;
++}
++
++static void dvc_dfx_complete_in(struct usb_ep *ep, struct usb_request *req)
++{
++ struct dvc_dfx_dev *dev = _dvc_dfx_dev;
++
++ if (req->status != 0)
++ dvc_dfx_set_disconnected(dev);
++
++ dvc_dfx_req_put(dev, &dev->tx_idle, req);
++
++ wake_up(&dev->write_wq);
++}
++
++static void dvc_dfx_complete_out(struct usb_ep *ep, struct usb_request *req)
++{
++ struct dvc_dfx_dev *dev = _dvc_dfx_dev;
++
++ if (req->status != 0)
++ dvc_dfx_set_disconnected(dev);
++ wake_up(&dev->read_wq);
++}
++
++
++static inline int dvc_dfx_lock(atomic_t *excl)
++{
++ if (atomic_inc_return(excl) == 1) {
++ return 0;
++ } else {
++ atomic_dec(excl);
++ return -1;
++ }
++}
++
++static inline void dvc_dfx_unlock(atomic_t *excl)
++{
++ atomic_dec(excl);
++}
++
++static int dfx_create_bulk_endpoints(struct dvc_dfx_dev *dev,
++ struct usb_endpoint_descriptor *in_desc,
++ struct usb_endpoint_descriptor *out_desc,
++ struct usb_ss_ep_comp_descriptor *in_comp_desc,
++ struct usb_ss_ep_comp_descriptor *out_comp_desc
++ )
++{
++ struct usb_composite_dev *cdev = dev->cdev;
++ struct usb_request *req;
++ struct usb_ep *ep;
++ int i;
++
++ pr_debug("%s dev: %p\n", __func__, dev);
++
++ in_desc->bEndpointAddress |= 0x8;
++ ep = usb_ep_autoconfig_ss(cdev->gadget, in_desc, in_comp_desc);
++ if (!ep) {
++ pr_debug("%s for ep_in failed\n", __func__);
++ return -ENODEV;
++ }
++ pr_debug("%s for ep_in got %s\n", __func__, ep->name);
++
++ ep->driver_data = dev; /* claim the endpoint */
++ dev->ep_in = ep;
++
++ out_desc->bEndpointAddress |= 0x8;
++ ep = usb_ep_autoconfig_ss(cdev->gadget, out_desc, out_comp_desc);
++ if (!ep) {
++ pr_debug("%s for ep_out failed\n", __func__);
++ return -ENODEV;
++ }
++ pr_debug("%s for ep_out got %s\n", __func__, ep->name);
++
++ ep->driver_data = dev; /* claim the endpoint */
++ dev->ep_out = ep;
++
++ /* now allocate requests for our endpoints */
++ for (i = 0; i < DFX_TX_REQ_MAX; i++) {
++ if (!(i % 2))
++ req = dvc_dfx_request_new(dev->ep_in,
++ DFX_BULK_BUFFER_SIZE,
++ (dma_addr_t)DFX_BULK_IN_BUFFER_ADDR);
++ else
++ req = dvc_dfx_request_new(dev->ep_in,
++ DFX_BULK_BUFFER_SIZE,
++ (dma_addr_t)DFX_BULK_IN_BUFFER_ADDR_2);
++ if (!req)
++ goto fail;
++ req->complete = dvc_dfx_complete_in;
++ dvc_dfx_req_put(dev, &dev->tx_idle, req);
++ }
++ for (i = 0; i < DFX_RX_REQ_MAX; i++) {
++ req = dvc_dfx_request_new(dev->ep_out, DFX_BULK_BUFFER_SIZE,
++ (dma_addr_t)DFX_BULK_OUT_BUFFER_ADDR);
++ if (!req)
++ goto fail;
++ req->complete = dvc_dfx_complete_out;
++ dev->rx_req[i] = req;
++ }
++
++ return 0;
++
++fail:
++ pr_err("%s could not allocate requests\n", __func__);
++ while ((req = dvc_dfx_req_get(dev, &dev->tx_idle)))
++ dvc_dfx_request_free(req, dev->ep_out);
++ for (i = 0; i < DFX_RX_REQ_MAX; i++)
++ dvc_dfx_request_free(dev->rx_req[i], dev->ep_out);
++ return -1;
++}
++
++static ssize_t dvc_dfx_start_transfer(size_t count)
++{
++ struct dvc_dfx_dev *dev = _dvc_dfx_dev;
++ struct usb_request *req;
++ int r = count, xfer;
++ int ret = -ENODEV;
++
++
++ pr_info("%s start\n", __func__);
++ if (!_dvc_dfx_dev)
++ return ret;
++
++ if (dvc_dfx_lock(&dev->read_excl)
++ && dvc_dfx_lock(&dev->write_excl))
++ return -EBUSY;
++
++ /* we will block until enumeration completes */
++ while (!(dev->online || dev->error)) {
++ pr_debug("%s waiting for online state\n", __func__);
++ ret = wait_event_interruptible(dev->read_wq,
++ (dev->online || dev->error));
++
++ if (ret < 0) {
++ /* not at CONFIGURED state */
++ pr_info("%s USB not at CONFIGURED\n", __func__);
++ dvc_dfx_unlock(&dev->read_excl);
++ dvc_dfx_unlock(&dev->write_excl);
++ return ret;
++ }
++ }
++
++ /* queue a ep_in endless request */
++ while (r > 0) {
++ if (dev->error) {
++ pr_debug("%s dev->error\n", __func__);
++ r = -EIO;
++ break;
++ }
++
++ if (!dev->online) {
++ pr_debug("%s !dev->online issue\n", __func__);
++ r = -EIO;
++ break;
++ }
++
++ /* get an idle tx request to use */
++ req = 0;
++ ret = wait_event_interruptible(dev->write_wq,
++ dev->error || !dev->online ||
++ (req = dvc_dfx_req_get(dev, &dev->tx_idle)));
++
++ if (ret < 0) {
++ r = ret;
++ break;
++ }
++
++ if (req != 0) {
++ if (count > DFX_BULK_BUFFER_SIZE)
++ xfer = DFX_BULK_BUFFER_SIZE;
++ else
++ xfer = count;
++
++ req->no_interrupt = 1;
++ req->context = &dev->function;
++ req->length = xfer;
++ pr_debug("%s queue tx_idle list req to dev->ep_in\n",
++ __func__);
++ ret = usb_ep_queue(dev->ep_in, req, GFP_ATOMIC);
++ if (ret < 0) {
++ pr_err("%s xfer error %d\n", __func__, ret);
++ dev->error = 1;
++ r = -EIO;
++ break;
++ }
++ pr_debug("%s xfer=%d/%d queued req/%x\n", __func__,
++ xfer, r, (uint)req);
++ dvc_dfx_req_put(dev, &dev->tx_xfer, req);
++ r -= xfer;
++
++ /* zero this so we don't try to free it on error exit */
++ req = 0;
++ }
++ }
++ if (req) {
++ pr_debug("%s req re-added to tx_idle on error\n", __func__);
++ dvc_dfx_req_put(dev, &dev->tx_idle, req);
++ }
++
++ pr_debug("%s rx_req to dev->ep_out\n", __func__);
++ /* queue a ep_out endless request */
++ req = dev->rx_req[0];
++ req->length = DFX_BULK_BUFFER_SIZE;
++ req->no_interrupt = 1;
++ req->context = &dev->function;
++ ret = usb_ep_queue(dev->ep_out, req, GFP_ATOMIC);
++ if (ret < 0) {
++ pr_err("%s failed to queue out req %p (%d)\n",
++ __func__, req, req->length);
++ r = -EIO;
++ } else {
++ dev->transfering = 1;
++ }
++
++ dvc_dfx_unlock(&dev->read_excl);
++ dvc_dfx_unlock(&dev->write_excl);
++ pr_debug("%s returning\n", __func__);
++ return r;
++}
++
++static int dvc_dfx_disable_transfer(void)
++{
++ struct dvc_dfx_dev *dev = _dvc_dfx_dev;
++ struct usb_request *req;
++ int r = 1;
++ int ret;
++
++
++ pr_info("%s start\n", __func__);
++ if (!_dvc_dfx_dev)
++ return -ENODEV;
++
++ if (dvc_dfx_lock(&dev->read_excl)
++ && dvc_dfx_lock(&dev->write_excl))
++ return -EBUSY;
++
++ if (dev->error) {
++ pr_debug("%s dev->error\n", __func__);
++ r = -EIO;
++ goto end;
++ }
++
++ if ((!dev->online) || (!dev->transfering)) {
++ pr_debug("%s !dev->online OR !dev->transfering\n", __func__);
++ r = -EIO;
++ goto end;
++ }
++
++ /* get an xfer tx request to use */
++ while ((req = dvc_dfx_req_get(dev, &dev->tx_xfer))) {
++ ret = usb_ep_dequeue(dev->ep_in, req);
++ if (ret < 0) {
++ pr_err("%s dequeue error %d\n", __func__, ret);
++ dev->error = 1;
++ r = -EIO;
++ goto end;
++ }
++ pr_debug("%s dequeued tx req/%x\n", __func__, (uint)req);
++ }
++ ret = usb_ep_dequeue(dev->ep_out, dev->rx_req[0]);
++ if (ret < 0) {
++ pr_err("%s dequeue rx error %d\n", __func__, ret);
++ dev->error = 1;
++ r = -EIO;
++ goto end;
++ }
++
++end:
++ dvc_dfx_unlock(&dev->read_excl);
++ dvc_dfx_unlock(&dev->write_excl);
++ return r;
++}
++
++static int dvc_dfx_open(struct inode *ip, struct file *fp)
++{
++ pr_info("%s\n", __func__);
++ if (!_dvc_dfx_dev)
++ return -ENODEV;
++
++ if (dvc_dfx_lock(&_dvc_dfx_dev->open_excl))
++ return -EBUSY;
++
++ fp->private_data = _dvc_dfx_dev;
++
++ /* clear the error latch */
++ _dvc_dfx_dev->error = 0;
++ _dvc_dfx_dev->transfering = 0;
++
++ return 0;
++}
++
++static int dvc_dfx_release(struct inode *ip, struct file *fp)
++{
++ pr_info("%s\n", __func__);
++
++ dvc_dfx_unlock(&_dvc_dfx_dev->open_excl);
++ return 0;
++}
++
++/* file operations for DvC.Dfx device /dev/usb_dvc_dfx */
++static const struct file_operations dvc_dfx_fops = {
++ .owner = THIS_MODULE,
++ .open = dvc_dfx_open,
++ .release = dvc_dfx_release,
++};
++
++static struct miscdevice dvc_dfx_device = {
++ .minor = MISC_DYNAMIC_MINOR,
++ .name = "usb_dvc_dfx",
++ .fops = &dvc_dfx_fops,
++};
++
++static int dvc_dfx_ctrlrequest(struct usb_composite_dev *cdev,
++ const struct usb_ctrlrequest *ctrl)
++{
++ struct dvc_dfx_dev *dev = _dvc_dfx_dev;
++ int value = -EOPNOTSUPP;
++ u16 w_index = le16_to_cpu(ctrl->wIndex);
++ u16 w_value = le16_to_cpu(ctrl->wValue);
++ u16 w_length = le16_to_cpu(ctrl->wLength);
++
++ pr_debug("%s %02x.%02x v%04x i%04x l%u\n", __func__,
++ ctrl->bRequestType, ctrl->bRequest,
++ w_value, w_index, w_length);
++
++ switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
++
++ /* DC_REQUEST_SET_RESET ... stop active transfer */
++ case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
++ | DC_REQUEST_SET_RESET:
++ if (w_index != dev->data_id)
++ goto invalid;
++
++ pr_info("%s DC_REQUEST_SET_RESET v%04x i%04x l%u\n", __func__,
++ w_value, w_index, w_length);
++
++ dvc_dfx_disable_transfer();
++ value = 0;
++ break;
++
++ default:
++invalid:
++ pr_debug("unknown class-specific control req "
++ "%02x.%02x v%04x i%04x l%u\n",
++ ctrl->bRequestType, ctrl->bRequest,
++ w_value, w_index, w_length);
++ }
++
++ /* respond with data transfer or status phase? */
++ if (value >= 0) {
++ cdev->req->zero = 0;
++ cdev->req->length = value;
++ value = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
++ if (value < 0)
++ pr_err("%s setup response queue error\n", __func__);
++ }
++
++ /* device either stalls (value < 0) or reports success */
++ return value;
++}
++
++static int
++dvc_dfx_function_bind(struct usb_configuration *c, struct usb_function *f)
++{
++ struct usb_composite_dev *cdev = c->cdev;
++ struct dvc_dfx_dev *dev = func_to_dvc_dfx(f);
++ int id;
++ int ret;
++
++ dev->cdev = cdev;
++ pr_info("%s dev: %p\n", __func__, dev);
++
++ /* allocate interface ID(s) */
++ id = usb_interface_id(c, f);
++ if (id < 0)
++ return id;
++ dev->data_id = id;
++ dfx_data_interface_desc.bInterfaceNumber = id;
++ dfx_iad_desc.bFirstInterface = id;
++
++ id = usb_interface_id(c, f);
++ if (id < 0)
++ return id;
++ dev->ctrl_id = id;
++ dfx_interface_desc.bInterfaceNumber = id;
++
++ /* allocate endpoints */
++ ret = dfx_create_bulk_endpoints(dev, &dfx_fullspeed_in_desc,
++ &dfx_fullspeed_out_desc,
++ &dfx_superspeed_in_comp_desc,
++ &dfx_superspeed_out_comp_desc
++ );
++ if (ret)
++ return ret;
++
++ /* support high speed hardware */
++ if (gadget_is_dualspeed(c->cdev->gadget)) {
++ dfx_highspeed_in_desc.bEndpointAddress =
++ dfx_fullspeed_in_desc.bEndpointAddress;
++ dfx_highspeed_out_desc.bEndpointAddress =
++ dfx_fullspeed_out_desc.bEndpointAddress;
++ }
++
++ if (gadget_is_superspeed(c->cdev->gadget)) {
++ dfx_superspeed_in_desc.bEndpointAddress =
++ dfx_fullspeed_in_desc.bEndpointAddress;
++
++ dfx_superspeed_out_desc.bEndpointAddress =
++ dfx_fullspeed_out_desc.bEndpointAddress;
++ }
++
++ pr_info("%s speed %s: IN/%s, OUT/%s\n",
++ gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
++ f->name, dev->ep_in->name, dev->ep_out->name);
++ return 0;
++}
++
++static void
++dvc_dfx_function_unbind(struct usb_configuration *c, struct usb_function *f)
++{
++ struct dvc_dfx_dev *dev = func_to_dvc_dfx(f);
++ struct usb_request *req;
++ int i;
++
++ dev->online = 0;
++ dev->online_ctrl = 0;
++ dev->online_data = 0;
++ dev->transfering = 0;
++ dev->error = 0;
++
++ dfx_string_defs[DVCDFX_CTRL_IDX].id = 0;
++
++ wake_up(&dev->read_wq);
++
++ for (i = 0; i < DFX_RX_REQ_MAX; i++)
++ dvc_dfx_request_free(dev->rx_req[i], dev->ep_out);
++ while ((req = dvc_dfx_req_get(dev, &dev->tx_idle)))
++ dvc_dfx_request_free(req, dev->ep_in);
++
++}
++
++static int dvc_dfx_function_set_alt(struct usb_function *f,
++ unsigned intf, unsigned alt)
++{
++ struct dvc_dfx_dev *dev = func_to_dvc_dfx(f);
++ struct usb_composite_dev *cdev = f->config->cdev;
++ int ret;
++
++ pr_info("%s intf: %d alt: %d\n", __func__, intf, alt);
++ if (intf == dfx_data_interface_desc.bInterfaceNumber) {
++ ret = config_ep_by_speed(cdev->gadget, f, dev->ep_in);
++ if (ret) {
++ pr_err("%s intf: %d alt: %d ep_by_speed in error %d\n",
++ __func__, intf, alt, ret);
++ return ret;
++ }
++ ret = usb_ep_enable(dev->ep_in);
++ if (ret) {
++ pr_err("%s intf: %d alt: %d ep_enable in err %d\n",
++ __func__, intf, alt, ret);
++ return ret;
++ }
++
++ ret = config_ep_by_speed(cdev->gadget, f, dev->ep_out);
++ if (ret) {
++ pr_err("%s intf: %d alt: %d ep_enable out error %d\n",
++ __func__, intf, alt, ret);
++ return ret;
++ }
++
++ ret = usb_ep_enable(dev->ep_out);
++ if (ret) {
++ pr_err("%s intf: %d alt: %d ep_enable out err %d\n",
++ __func__, intf, alt, ret);
++ usb_ep_disable(dev->ep_in);
++ return ret;
++ }
++ dev->online_data = 1;
++ }
++ if (intf == dfx_interface_desc.bInterfaceNumber)
++ dev->online_ctrl = 1;
++
++ if (dev->online_data && dev->online_ctrl) {
++ dev->online = 1;
++ dev->error = 0;
++ }
++
++ /* readers may be blocked waiting for us to go online */
++ wake_up(&dev->read_wq);
++ return 0;
++}
++
++static void dvc_dfx_function_disable(struct usb_function *f)
++{
++ struct dvc_dfx_dev *dev = func_to_dvc_dfx(f);
++ struct usb_composite_dev *cdev = dev->cdev;
++
++ pr_info("%s cdev %p\n", __func__, cdev);
++
++ if (dev->transfering)
++ dvc_dfx_disable_transfer();
++
++ dev->online = 0;
++ dev->online_ctrl = 0;
++ dev->online_data = 0;
++ dev->error = 0;
++ usb_ep_disable(dev->ep_in);
++ usb_ep_disable(dev->ep_out);
++
++ /* readers may be blocked waiting for us to go online */
++ wake_up(&dev->read_wq);
++
++ pr_debug("%s disabled\n", dev->function.name);
++}
++
++static int dvc_dfx_bind_config(struct usb_configuration *c)
++{
++ struct dvc_dfx_dev *dev = _dvc_dfx_dev;
++ int status;
++
++ pr_info("%s\n", __func__);
++
++ if (dfx_string_defs[DVCDFX_CTRL_IDX].id == 0) {
++ status = usb_string_id(c->cdev);
++ if (status < 0)
++ return status;
++ dfx_string_defs[DVCDFX_CTRL_IDX].id = status;
++
++ dfx_interface_desc.iInterface = status;
++
++ status = usb_string_id(c->cdev);
++ if (status < 0)
++ return status;
++ dfx_string_defs[DVCDFX_DATA_IDX].id = status;
++
++ dfx_data_interface_desc.iInterface = status;
++
++ status = usb_string_id(c->cdev);
++ if (status < 0)
++ return status;
++ dfx_string_defs[DVCDFX_IAD_IDX].id = status;
++
++ dfx_iad_desc.iFunction = status;
++ }
++
++ dev->cdev = c->cdev;
++ dev->function.name = "dvcdfx";
++ dev->function.fs_descriptors = fs_dfx_descs;
++ dev->function.hs_descriptors = hs_dfx_descs;
++ dev->function.ss_descriptors = ss_dfx_descs;
++ dev->function.strings = dfx_strings;
++ dev->function.bind = dvc_dfx_function_bind;
++ dev->function.unbind = dvc_dfx_function_unbind;
++ dev->function.set_alt = dvc_dfx_function_set_alt;
++ dev->function.disable = dvc_dfx_function_disable;
++
++ return usb_add_function(c, &dev->function);
++}
++
++static int dvc_dfx_setup(void)
++{
++ struct dvc_dfx_dev *dev;
++ int ret;
++
++ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
++ if (!dev)
++ return -ENOMEM;
++
++ spin_lock_init(&dev->lock);
++
++ init_waitqueue_head(&dev->read_wq);
++ init_waitqueue_head(&dev->write_wq);
++
++ INIT_LIST_HEAD(&dev->tx_idle);
++ INIT_LIST_HEAD(&dev->tx_xfer);
++
++ atomic_set(&dev->open_excl, 0);
++ atomic_set(&dev->read_excl, 0);
++ atomic_set(&dev->write_excl, 0);
++
++ _dvc_dfx_dev = dev;
++
++ ret = misc_register(&dvc_dfx_device);
++ if (ret)
++ goto err;
++
++ return 0;
++
++err:
++ kfree(dev);
++ pr_err("DvC.Dfx gadget driver failed to initialize\n");
++ return ret;
++}
++
++static void dvc_dfx_cleanup(void)
++{
++ misc_deregister(&dvc_dfx_device);
++
++ kfree(_dvc_dfx_dev);
++ _dvc_dfx_dev = NULL;
++}
+diff --git a/drivers/usb/gadget/f_dvc_trace.c b/drivers/usb/gadget/f_dvc_trace.c
+new file mode 100644
+index 0000000..4837bf1
+--- /dev/null
++++ b/drivers/usb/gadget/f_dvc_trace.c
+@@ -0,0 +1,887 @@
++/*
++ * Gadget Driver for Android DvC.Trace Debug Capability
++ *
++ * Copyright (C) 2008-2010, Intel Corporation.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/poll.h>
++#include <linux/delay.h>
++#include <linux/wait.h>
++#include <linux/err.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include <linux/types.h>
++#include <linux/device.h>
++#include <linux/miscdevice.h>
++#include <linux/usb/debug.h>
++#include <linux/sdm.h>
++
++#define TRACE_TX_REQ_MAX 3
++
++#define CONFIG_BOARD_MRFLD_VV
++
++struct dvc_trace_dev {
++ struct usb_function function;
++ struct usb_composite_dev *cdev;
++ spinlock_t lock;
++ u8 ctrl_id, data_id;
++ u8 class_id, subclass_id;
++
++ struct usb_ep *ep_in;
++
++ int online;
++ int online_data;
++ int online_ctrl;
++ int transfering;
++ int error;
++
++ atomic_t write_excl;
++ atomic_t open_excl;
++
++ wait_queue_head_t write_wq;
++
++ struct list_head tx_idle;
++ struct list_head tx_xfer;
++};
++
++static struct usb_interface_assoc_descriptor trace_iad_desc = {
++ .bLength = sizeof(trace_iad_desc),
++ .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
++ /* .bFirstInterface = DYNAMIC, */
++ .bInterfaceCount = 2, /* debug control + data */
++ .bFunctionClass = USB_CLASS_DEBUG,
++ .bFunctionSubClass = USB_SUBCLASS_DVC_TRACE,
++ /* .bFunctionProtocol = 0, */
++ /* .iFunction = DYNAMIC, */
++};
++
++static struct usb_interface_descriptor trace_interface_desc = {
++ .bLength = USB_DT_INTERFACE_SIZE,
++ .bDescriptorType = USB_DT_INTERFACE,
++ .bNumEndpoints = 0,
++ .bInterfaceClass = USB_CLASS_DEBUG,
++ .bInterfaceSubClass = USB_SUBCLASS_DEBUG_CONTROL,
++ /* .bInterfaceProtocol = 0, */
++};
++
++#define DC_DVCTRACE_ATTRI_LENGTH DC_DBG_ATTRI_SIZE(2, 32)
++/* 1 input terminal, 1 output terminal and 1 feature unit */
++#define DC_DVCTRACE_TOTAL_LENGTH (DC_DVCTRACE_ATTRI_LENGTH \
++ + DC_OUTPUT_CONNECTION_SIZE \
++ + DC_OUTPUT_CONNECTION_SIZE \
++ + DC_DBG_UNIT_SIZE(STM_NB_IN_PINS, 2, 2, 24))
++
++DECLARE_DC_DEBUG_ATTR_DESCR(DVCT, 2, 32);
++
++static struct DC_DEBUG_ATTR_DESCR(DVCT) trace_debug_attri_desc = {
++ .bLength = DC_DVCTRACE_ATTRI_LENGTH,
++ .bDescriptorType = USB_DT_CS_INTERFACE,
++ .bDescriptorSubtype = DC_DEBUG_ATTRIBUTES,
++ .bcdDC = __constant_cpu_to_le16(0x0100),
++ .wTotalLength = __constant_cpu_to_le16(DC_DVCTRACE_TOTAL_LENGTH),
++ .bmSupportedFeatures = 0, /* Debug Event Supported, per SAS */
++ .bControlSize = 2,
++ .bmControl = { /* per SAS */
++ [0] = 0xFF,
++ [1] = 0x3F,
++ },
++ .wAuxDataSize = __constant_cpu_to_le16(0x20),
++ .dInputBufferSize = __constant_cpu_to_le32(0x00), /* per SAS */
++ .dOutputBufferSize = __constant_cpu_to_le32(TRACE_BULK_BUFFER_SIZE),
++ .qBaseAddress = 0, /* revision */
++ .hGlobalID = { /* revision */
++ [0] = 0,
++ [1] = 0,
++ }
++};
++
++static struct dc_output_connection_descriptor trace_output_conn_usb_desc = {
++ .bLength = DC_OUTPUT_CONNECTION_SIZE,
++ .bDescriptorType = USB_DT_CS_INTERFACE,
++ .bDescriptorSubtype = DC_OUTPUT_CONNECTION,
++ .bConnectionID = 0x01, /* USB */
++ .bConnectionType = DC_CONNECTION_USB,
++ .bAssocConnection = 0, /* No related input-connection */
++ .wSourceID = __constant_cpu_to_le16(0x01),
++ /* .iConnection = DYNAMIC, */
++};
++
++static struct dc_output_connection_descriptor trace_output_conn_pti_desc = {
++ .bLength = DC_OUTPUT_CONNECTION_SIZE,
++ .bDescriptorType = USB_DT_CS_INTERFACE,
++ .bDescriptorSubtype = DC_OUTPUT_CONNECTION,
++ .bConnectionID = 0, /* PTI */
++ .bConnectionType = DC_CONNECTION_DEBUG_DATA,
++ .bAssocConnection = 0, /* No related input-connection */
++ .wSourceID = __constant_cpu_to_le16(0x01),
++ /* .iConnection = DYNAMIC, */
++};
++
++#define DC_DVCTRACE_UNIT_LENGTH DC_DBG_UNIT_SIZE(STM_NB_IN_PINS, 2, 2, 24)
++
++DECLARE_DC_DEBUG_UNIT_DESCRIPTOR(STM_NB_IN_PINS, 2, 2, 24);
++
++static struct DC_DEBUG_UNIT_DESCRIPTOR(STM_NB_IN_PINS, 2, 2, 24)
++ trace_debug_unit_stm_desc = {
++ .bLength = DC_DVCTRACE_UNIT_LENGTH,
++ .bDescriptorType = USB_DT_CS_INTERFACE,
++ .bDescriptorSubtype = DC_DEBUG_UNIT,
++ .bUnitID = 0x01, /* per SAS */
++/* STM Trace Unit processor: revision */
++ .bDebugUnitType = DC_UNIT_TYPE_TRACE_PROC,
++ /* STM: Trace compressor controller */
++ .bDebugSubUnitType = DC_UNIT_SUBTYPE_TRACEZIP,
++ .bAliasUnitID = 0, /* no associated debug unit */
++ .bNrInPins = STM_NB_IN_PINS, /* p */
++/* wSourceID contains STM_NB_IN_PINS elements */
++/* .wSourceID = {0}, */
++ .bNrOutPins = 0x02, /* q */
++ .dTraceFormat = {
++ [0] = __constant_cpu_to_le32(DC_TRACE_MIPI_FORMATED_STPV1),
++ [1] = __constant_cpu_to_le32(DC_TRACE_MIPI_FORMATED_STPV1),
++ },
++ .dStreamID = __constant_cpu_to_le32(0xFFFFFFFF),
++ .bControlSize = 0x02, /* n */
++ .bmControl = {
++ [0] = 0xFF,
++ [1] = 0x3F,
++ },
++ .wAuxDataSize = __constant_cpu_to_le16(24), /* m */
++ .qBaseAddress = 0, /* revision */
++ .hIPID = {
++ [0] = 0,
++ [1] = 0,
++ },
++ /* .iDebugUnitType = DYNAMIC, */
++};
++
++static struct usb_interface_descriptor trace_data_interface_desc = {
++ .bLength = USB_DT_INTERFACE_SIZE,
++ .bDescriptorType = USB_DT_INTERFACE,
++ .bAlternateSetting = 0,
++ .bNumEndpoints = 1,
++ .bInterfaceClass = USB_CLASS_DEBUG,
++ .bInterfaceSubClass = USB_SUBCLASS_DVC_TRACE,
++ /* .bInterfaceProtocol = 0, */
++};
++
++static struct usb_endpoint_descriptor trace_fullspeed_in_desc = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_IN,
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_endpoint_descriptor trace_highspeed_in_desc = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_IN,
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++ .wMaxPacketSize = __constant_cpu_to_le16(512),
++};
++
++static struct usb_endpoint_descriptor trace_superspeed_in_desc = {
++ .bLength = USB_DT_ENDPOINT_SIZE,
++ .bDescriptorType = USB_DT_ENDPOINT,
++ .bEndpointAddress = USB_DIR_IN,
++ .bmAttributes = USB_ENDPOINT_XFER_BULK,
++ .wMaxPacketSize = __constant_cpu_to_le16(1024),
++};
++
++static struct usb_ss_ep_comp_descriptor trace_superspeed_in_comp_desc = {
++ .bLength = USB_DT_SS_EP_COMP_SIZE,
++ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
++ .bMaxBurst = 0,
++ .bmAttributes = 0,
++};
++
++static struct usb_descriptor_header *fs_trace_descs[] = {
++ (struct usb_descriptor_header *) &trace_iad_desc,
++ (struct usb_descriptor_header *) &trace_data_interface_desc,
++ (struct usb_descriptor_header *) &trace_fullspeed_in_desc,
++ (struct usb_descriptor_header *) &trace_interface_desc,
++ (struct usb_descriptor_header *) &trace_debug_attri_desc,
++ (struct usb_descriptor_header *) &trace_output_conn_pti_desc,
++ (struct usb_descriptor_header *) &trace_output_conn_usb_desc,
++ (struct usb_descriptor_header *) &trace_debug_unit_stm_desc,
++ NULL,
++};
++
++static struct usb_descriptor_header *hs_trace_descs[] = {
++ (struct usb_descriptor_header *) &trace_iad_desc,
++ (struct usb_descriptor_header *) &trace_data_interface_desc,
++ (struct usb_descriptor_header *) &trace_highspeed_in_desc,
++ (struct usb_descriptor_header *) &trace_interface_desc,
++ (struct usb_descriptor_header *) &trace_debug_attri_desc,
++ (struct usb_descriptor_header *) &trace_output_conn_pti_desc,
++ (struct usb_descriptor_header *) &trace_output_conn_usb_desc,
++ (struct usb_descriptor_header *) &trace_debug_unit_stm_desc,
++ NULL,
++};
++
++static struct usb_descriptor_header *ss_trace_descs[] = {
++ (struct usb_descriptor_header *) &trace_iad_desc,
++ (struct usb_descriptor_header *) &trace_data_interface_desc,
++ (struct usb_descriptor_header *) &trace_superspeed_in_desc,
++ (struct usb_descriptor_header *) &trace_superspeed_in_comp_desc,
++ (struct usb_descriptor_header *) &trace_interface_desc,
++ (struct usb_descriptor_header *) &trace_debug_attri_desc,
++ (struct usb_descriptor_header *) &trace_output_conn_pti_desc,
++ (struct usb_descriptor_header *) &trace_output_conn_usb_desc,
++ (struct usb_descriptor_header *) &trace_debug_unit_stm_desc,
++ NULL,
++};
++
++/* string descriptors: */
++#define DVCTRACE_CTRL_IDX 0
++#define DVCTRACE_DATA_IDX 1
++#define DVCTRACE_IAD_IDX 2
++#define DVCTRACE_CONN_PTI_IDX 3
++#define DVCTRACE_CONN_USB_IDX 4
++#define DVCTRACE_UNIT_STM_IDX 5
++
++/* static strings, in UTF-8 */
++static struct usb_string trace_string_defs[] = {
++ [DVCTRACE_CTRL_IDX].s = "Debug Sub-Class DvC.Trace (Control)",
++ [DVCTRACE_DATA_IDX].s = "Debug Sub-Class DvC.Trace (Data)",
++ [DVCTRACE_IAD_IDX].s = "Debug Sub-Class DvC.Trace",
++ [DVCTRACE_CONN_PTI_IDX].s = "MIPI PTIv1 output Connector ",
++ [DVCTRACE_CONN_USB_IDX].s = "USB Device output connector",
++ [DVCTRACE_UNIT_STM_IDX].s = "MIPI STM Debug Unit",
++ { /* ZEROES END LIST */ },
++};
++
++static struct usb_gadget_strings trace_string_table = {
++ .language = 0x0409, /* en-us */
++ .strings = trace_string_defs,
++};
++
++static struct usb_gadget_strings *trace_strings[] = {
++ &trace_string_table,
++ NULL,
++};
++
++/* temporary var used between dvc_trace_open() and dvc_trace_gadget_bind() */
++static struct dvc_trace_dev *_dvc_trace_dev;
++
++static inline struct dvc_trace_dev *func_to_dvc_trace(struct usb_function *f)
++{
++ return container_of(f, struct dvc_trace_dev, function);
++}
++
++static int dvc_trace_is_enabled(void)
++{
++ if (!stm_is_enabled()) {
++ pr_info("%s STM/PTI block is not enabled\n", __func__);
++ return 0;
++ }
++ return 1;
++}
++
++static struct usb_request *dvc_trace_request_new(struct usb_ep *ep,
++ int buffer_size, dma_addr_t dma)
++{
++ struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL);
++ if (!req)
++ return NULL;
++
++ req->dma = dma;
++ /* now allocate buffers for the requests */
++ req->buf = kmalloc(buffer_size, GFP_KERNEL);
++ if (!req->buf) {
++ usb_ep_free_request(ep, req);
++ return NULL;
++ }
++
++ return req;
++}
++
++static void dvc_trace_request_free(struct usb_request *req, struct usb_ep *ep)
++{
++ if (req) {
++ kfree(req->buf);
++ usb_ep_free_request(ep, req);
++ }
++}
++
++/* add a request to the tail of a list */
++static void dvc_trace_req_put(struct dvc_trace_dev *dev, struct list_head *head,
++ struct usb_request *req)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&dev->lock, flags);
++ list_add_tail(&req->list, head);
++ spin_unlock_irqrestore(&dev->lock, flags);
++}
++
++/* remove a request from the head of a list */
++static struct usb_request *dvc_trace_req_get(struct dvc_trace_dev *dev,
++ struct list_head *head)
++{
++ unsigned long flags;
++ struct usb_request *req;
++
++ spin_lock_irqsave(&dev->lock, flags);
++ if (list_empty(head)) {
++ req = 0;
++ } else {
++ req = list_first_entry(head, struct usb_request, list);
++ list_del(&req->list);
++ }
++ spin_unlock_irqrestore(&dev->lock, flags);
++ return req;
++}
++
++static void dvc_trace_set_disconnected(struct dvc_trace_dev *dev)
++{
++ dev->transfering = 0;
++}
++
++static void dvc_trace_complete_in(struct usb_ep *ep, struct usb_request *req)
++{
++ struct dvc_trace_dev *dev = _dvc_trace_dev;
++
++ if (req->status != 0)
++ dvc_trace_set_disconnected(dev);
++
++ dvc_trace_req_put(dev, &dev->tx_idle, req);
++
++ wake_up(&dev->write_wq);
++}
++
++static inline int dvc_trace_lock(atomic_t *excl)
++{
++ if (atomic_inc_return(excl) == 1) {
++ return 0;
++ } else {
++ atomic_dec(excl);
++ return -1;
++ }
++}
++
++static inline void dvc_trace_unlock(atomic_t *excl)
++{
++ atomic_dec(excl);
++}
++
++static int trace_create_bulk_endpoints(struct dvc_trace_dev *dev,
++ struct usb_endpoint_descriptor *in_desc,
++ struct usb_ss_ep_comp_descriptor *in_comp_desc
++ )
++{
++ struct usb_composite_dev *cdev = dev->cdev;
++ struct usb_request *req;
++ struct usb_ep *ep;
++ int i;
++
++ pr_debug("%s dev: %p\n", __func__, dev);
++
++ in_desc->bEndpointAddress |= 0x1;
++ ep = usb_ep_autoconfig_ss(cdev->gadget, in_desc, in_comp_desc);
++ if (!ep) {
++ pr_err("%s usb_ep_autoconfig for ep_in failed\n", __func__);
++ return -ENODEV;
++ }
++ pr_debug("%s usb_ep_autoconfig for ep_in got %s\n", __func__, ep->name);
++
++ ep->driver_data = dev; /* claim the endpoint */
++ dev->ep_in = ep;
++
++ for (i = 0; i < TRACE_TX_REQ_MAX; i++) {
++ req = dvc_trace_request_new(dev->ep_in, TRACE_BULK_BUFFER_SIZE,
++ (dma_addr_t)TRACE_BULK_IN_BUFFER_ADDR);
++ if (!req)
++ goto fail;
++ req->complete = dvc_trace_complete_in;
++ dvc_trace_req_put(dev, &dev->tx_idle, req);
++ pr_debug("%s req= %x : for %s predefined TRB\n", __func__,
++ (uint)req, ep->name);
++ }
++
++ return 0;
++
++fail:
++ pr_err("%s could not allocate requests\n", __func__);
++ return -1;
++}
++
++static ssize_t dvc_trace_start_transfer(size_t count)
++{
++ struct dvc_trace_dev *dev = _dvc_trace_dev;
++ struct usb_request *req = 0;
++ int r = count, xfer;
++ int ret;
++
++ pr_debug("%s\n", __func__);
++ if (!_dvc_trace_dev)
++ return -ENODEV;
++
++ if (dvc_trace_lock(&dev->write_excl))
++ return -EBUSY;
++
++ /* we will block until enumeration completes */
++ while (!(dev->online || dev->error)) {
++ pr_debug("%s: waiting for online state\n", __func__);
++ ret = wait_event_interruptible(dev->write_wq,
++ (dev->online || dev->error));
++
++ if (ret < 0) {
++ /* not at CONFIGURED state */
++ pr_info("%s !dev->online already\n", __func__);
++ dvc_trace_unlock(&dev->write_excl);
++ return ret;
++ }
++ }
++
++ /* queue a ep_in endless request */
++ while (r > 0) {
++ if (dev->error) {
++ pr_debug("%s dev->error\n", __func__);
++ r = -EIO;
++ break;
++ }
++
++ if (!dev->online) {
++ pr_debug("%s !dev->online\n", __func__);
++ r = -EIO;
++ break;
++ }
++
++ /* get an idle tx request to use */
++ req = 0;
++ ret = wait_event_interruptible(dev->write_wq,
++ dev->error || !dev->online ||
++ (req = dvc_trace_req_get(dev, &dev->tx_idle)));
++
++ if (ret < 0) {
++ r = ret;
++ break;
++ }
++
++ if (req != 0) {
++ if (count > TRACE_BULK_BUFFER_SIZE)
++ xfer = TRACE_BULK_BUFFER_SIZE;
++ else
++ xfer = count;
++ pr_debug("%s queue tx_idle list req to dev->ep_in\n",
++ __func__);
++ req->no_interrupt = 1;
++ req->context = &dev->function;
++ req->length = xfer;
++ ret = usb_ep_queue(dev->ep_in, req, GFP_ATOMIC);
++ if (ret < 0) {
++ pr_err("%s: xfer error %d\n", __func__, ret);
++ dev->error = 1;
++ dev->transfering = 0;
++ r = -EIO;
++ break;
++ }
++ pr_debug("%s: xfer=%d/%d queued req/%x\n", __func__,
++ xfer, r, (uint)req);
++ dvc_trace_req_put(dev, &dev->tx_xfer, req);
++ r -= xfer;
++
++ /* zero this so we don't try to free it on error exit */
++ req = 0;
++ }
++ }
++ if (req) {
++ pr_debug("%s req re-added to tx_idle on error\n", __func__);
++ dvc_trace_req_put(dev, &dev->tx_idle, req);
++ } else {
++ dev->transfering = 1;
++ }
++ dvc_trace_unlock(&dev->write_excl);
++ pr_debug("%s end\n", __func__);
++ return ret;
++}
++
++static int dvc_trace_disable_transfer(void)
++{
++ struct dvc_trace_dev *dev = _dvc_trace_dev;
++ struct usb_request *req = 0;
++ int ret;
++
++ pr_debug("%s\n", __func__);
++ if (!_dvc_trace_dev)
++ return -ENODEV;
++
++ if (dvc_trace_lock(&dev->write_excl))
++ return -EBUSY;
++
++ if (dev->error) {
++ pr_debug("%s dev->error\n", __func__);
++ dvc_trace_unlock(&dev->write_excl);
++ return -EIO;
++ }
++
++ if ((!dev->online) || (!dev->transfering)) {
++ pr_debug("%s !dev->online OR !dev->transfering\n", __func__);
++ dvc_trace_unlock(&dev->write_excl);
++ return -EIO;
++ }
++
++ /* get an xfer tx request to use */
++ while ((req = dvc_trace_req_get(dev, &dev->tx_xfer))) {
++ ret = usb_ep_dequeue(dev->ep_in, req);
++ if (ret < 0) {
++ pr_err("%s: dequeue error %d\n", __func__, ret);
++ dev->error = 1;
++ dvc_trace_unlock(&dev->write_excl);
++ return -EIO;
++ }
++ pr_debug("%s: dequeued req/%x\n", __func__, (uint)req);
++ }
++
++ dvc_trace_unlock(&dev->write_excl);
++ return 1;
++}
++
++static int dvc_trace_open(struct inode *ip, struct file *fp)
++{
++ pr_debug("%s\n", __func__);
++ if (!_dvc_trace_dev)
++ return -ENODEV;
++
++ if (dvc_trace_lock(&_dvc_trace_dev->open_excl))
++ return -EBUSY;
++
++ fp->private_data = _dvc_trace_dev;
++
++ /* clear the error latch */
++ _dvc_trace_dev->error = 0;
++ _dvc_trace_dev->transfering = 0;
++
++ return 0;
++}
++
++static int dvc_trace_release(struct inode *ip, struct file *fp)
++{
++ pr_debug("%s\n", __func__);
++
++ dvc_trace_unlock(&_dvc_trace_dev->open_excl);
++ return 0;
++}
++
++/* file operations for DvC.Trace device /dev/usb_dvc_trace */
++static const struct file_operations dvc_trace_fops = {
++ .owner = THIS_MODULE,
++ .open = dvc_trace_open,
++ .release = dvc_trace_release,
++};
++
++static struct miscdevice dvc_trace_device = {
++ .minor = MISC_DYNAMIC_MINOR,
++ .name = "usb_dvc_trace",
++ .fops = &dvc_trace_fops,
++};
++
++static int dvc_trace_ctrlrequest(struct usb_composite_dev *cdev,
++ const struct usb_ctrlrequest *ctrl)
++{
++
++ struct dvc_trace_dev *dev = _dvc_trace_dev;
++ int value = -EOPNOTSUPP;
++ int ret;
++ u16 w_index = le16_to_cpu(ctrl->wIndex);
++ u16 w_value = le16_to_cpu(ctrl->wValue);
++ u16 w_length = le16_to_cpu(ctrl->wLength);
++
++ pr_debug("%s %02x.%02x v%04x i%04x l%u\n", __func__,
++ ctrl->bRequestType, ctrl->bRequest,
++ w_value, w_index, w_length);
++
++ switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
++
++ /* DC_REQUEST_SET_RESET ... stop active transfer */
++ case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
++ | DC_REQUEST_SET_RESET:
++ if (w_index != dev->data_id)
++ goto invalid;
++
++ pr_info("%s DC_REQUEST_SET_RESET v%04x i%04x l%u\n", __func__,
++ w_value, w_index, w_length);
++
++ dvc_trace_disable_transfer();
++ value = 0;
++ break;
++
++ /* DC_REQUEST_SET_TRACE ... start trace transfer */
++ case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
++ | DC_REQUEST_SET_TRACE:
++
++ pr_info("%s DC_REQUEST_SET_TRACE v%04x i%04x l%u\n", __func__,
++ w_value, w_index, w_length);
++
++ if (!w_index)
++ ret = dvc_trace_disable_transfer();
++ else
++ ret = dvc_trace_start_transfer(4096);
++
++ if (ret < 0)
++ value = -EINVAL;
++ else
++ value = (int) w_index;
++ break;
++
++ default:
++invalid:
++ pr_debug("unknown class-specific control req "
++ "%02x.%02x v%04x i%04x l%u\n",
++ ctrl->bRequestType, ctrl->bRequest,
++ w_value, w_index, w_length);
++ }
++
++ /* respond with data transfer or status phase? */
++ if (value >= 0) {
++ cdev->req->zero = 0;
++ cdev->req->length = value;
++ value = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
++ if (value < 0)
++ pr_err("%s setup response queue error\n", __func__);
++ }
++
++ /* device either stalls (value < 0) or reports success */
++ return value;
++}
++
++static int
++dvc_trace_function_bind(struct usb_configuration *c, struct usb_function *f)
++{
++ struct usb_composite_dev *cdev = c->cdev;
++ struct dvc_trace_dev *dev = func_to_dvc_trace(f);
++ int id;
++ int ret;
++ int status;
++
++ dev->cdev = cdev;
++ pr_debug("%s dev: %p\n", __func__, dev);
++
++ /* maybe allocate device-global string IDs, and patch descriptors */
++ if (trace_string_defs[DVCTRACE_CTRL_IDX].id == 0) {
++ status = usb_string_id(cdev);
++ if (status < 0)
++ return status;
++ trace_string_defs[DVCTRACE_DATA_IDX].id = status;
++ trace_data_interface_desc.iInterface = status;
++
++ status = usb_string_id(cdev);
++ if (status < 0)
++ return status;
++ trace_string_defs[DVCTRACE_CTRL_IDX].id = status;
++ trace_interface_desc.iInterface = status;
++
++ status = usb_string_id(cdev);
++ if (status < 0)
++ return status;
++ trace_string_defs[DVCTRACE_IAD_IDX].id = status;
++ trace_iad_desc.iFunction = status;
++
++ status = usb_string_id(cdev);
++ if (status < 0)
++ return status;
++ trace_string_defs[DVCTRACE_CONN_PTI_IDX].id = status;
++ trace_output_conn_pti_desc.iConnection = status;
++
++ status = usb_string_id(cdev);
++ if (status < 0)
++ return status;
++ trace_string_defs[DVCTRACE_CONN_USB_IDX].id = status;
++ trace_output_conn_usb_desc.iConnection = status;
++
++ status = usb_string_id(cdev);
++ if (status < 0)
++ return status;
++ trace_string_defs[DVCTRACE_UNIT_STM_IDX].id = status;
++ trace_debug_unit_stm_desc.iDebugUnitType = status;
++ }
++
++ /* allocate interface ID(s) */
++ id = usb_interface_id(c, f);
++ if (id < 0)
++ return id;
++ dev->data_id = id;
++ trace_data_interface_desc.bInterfaceNumber = id;
++ trace_iad_desc.bFirstInterface = id;
++
++ id = usb_interface_id(c, f);
++ if (id < 0)
++ return id;
++ dev->ctrl_id = id;
++ trace_interface_desc.bInterfaceNumber = id;
++
++ /* allocate endpoints */
++ ret = trace_create_bulk_endpoints(dev, &trace_fullspeed_in_desc,
++ &trace_superspeed_in_comp_desc);
++ if (ret)
++ return ret;
++
++ /* support high speed hardware */
++ if (gadget_is_dualspeed(c->cdev->gadget)) {
++ trace_highspeed_in_desc.bEndpointAddress =
++ trace_fullspeed_in_desc.bEndpointAddress;
++ }
++
++ if (gadget_is_superspeed(c->cdev->gadget)) {
++ trace_superspeed_in_desc.bEndpointAddress =
++ trace_fullspeed_in_desc.bEndpointAddress;
++ }
++
++ pr_debug("%s speed %s: IN/%s\n",
++ gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
++ f->name, dev->ep_in->name);
++ return 0;
++}
++
++static void
++dvc_trace_function_unbind(struct usb_configuration *c, struct usb_function *f)
++{
++ struct dvc_trace_dev *dev = func_to_dvc_trace(f);
++ struct usb_request *req;
++
++ dev->online = 0;
++ dev->online_data = 0;
++ dev->online_ctrl = 0;
++ dev->error = 0;
++ trace_string_defs[DVCTRACE_CTRL_IDX].id = 0;
++
++ wake_up(&dev->write_wq);
++
++ while ((req = dvc_trace_req_get(dev, &dev->tx_idle)))
++ dvc_trace_request_free(req, dev->ep_in);
++}
++
++static int dvc_trace_function_set_alt(struct usb_function *f,
++ unsigned intf, unsigned alt)
++{
++ struct dvc_trace_dev *dev = func_to_dvc_trace(f);
++ struct usb_composite_dev *cdev = f->config->cdev;
++ int ret;
++
++ pr_debug("%s intf: %d alt: %d\n", __func__, intf, alt);
++
++ if (intf == trace_interface_desc.bInterfaceNumber)
++ dev->online_ctrl = 1;
++
++ if (intf == trace_data_interface_desc.bInterfaceNumber) {
++ ret = config_ep_by_speed(cdev->gadget, f, dev->ep_in);
++ if (ret) {
++ pr_err("%s intf: %d alt: %d ep_by_speed in err %d\n",
++ __func__, intf, alt, ret);
++ return ret;
++ }
++
++ ret = usb_ep_enable(dev->ep_in);
++ if (ret) {
++ pr_err("%s intf: %d alt: %d ep_enable in err %d\n",
++ __func__, intf, alt, ret);
++ return ret;
++ }
++ dev->online_data = 1;
++ }
++
++ if (dev->online_data && dev->online_ctrl) {
++ dev->online = 1;
++ dev->transfering = 0;
++ }
++
++ /* readers may be blocked waiting for us to go online */
++ wake_up(&dev->write_wq);
++ return 0;
++}
++
++static void dvc_trace_function_disable(struct usb_function *f)
++{
++ struct dvc_trace_dev *dev = func_to_dvc_trace(f);
++ struct usb_composite_dev *cdev = dev->cdev;
++
++ pr_debug("%s dev %p\n", __func__, cdev);
++
++ if (dev->transfering)
++ dvc_trace_disable_transfer();
++
++ dev->online = 0;
++ dev->online_data = 0;
++ dev->online_ctrl = 0;
++ dev->error = 0;
++ usb_ep_disable(dev->ep_in);
++
++ /* writer may be blocked waiting for us to go online */
++ wake_up(&dev->write_wq);
++
++ pr_debug("%s : %s disabled\n", __func__, dev->function.name);
++}
++
++static int dvc_trace_bind_config(struct usb_configuration *c)
++{
++ struct dvc_trace_dev *dev = _dvc_trace_dev;
++
++ pr_debug("%s\n", __func__);
++
++ dev->cdev = c->cdev;
++ dev->function.name = "dvctrace";
++ dev->function.strings = trace_strings;
++ dev->function.fs_descriptors = fs_trace_descs;
++ dev->function.hs_descriptors = hs_trace_descs;
++ dev->function.ss_descriptors = ss_trace_descs;
++ dev->function.bind = dvc_trace_function_bind;
++ dev->function.unbind = dvc_trace_function_unbind;
++ dev->function.set_alt = dvc_trace_function_set_alt;
++ dev->function.disable = dvc_trace_function_disable;
++
++ return usb_add_function(c, &dev->function);
++}
++
++static int dvc_trace_setup(void)
++{
++ struct dvc_trace_dev *dev;
++ int ret;
++
++ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
++ if (!dev)
++ return -ENOMEM;
++
++ spin_lock_init(&dev->lock);
++
++ INIT_LIST_HEAD(&dev->tx_idle);
++ INIT_LIST_HEAD(&dev->tx_xfer);
++
++ init_waitqueue_head(&dev->write_wq);
++
++ atomic_set(&dev->open_excl, 0);
++ atomic_set(&dev->write_excl, 0);
++
++ _dvc_trace_dev = dev;
++
++ ret = misc_register(&dvc_trace_device);
++ if (ret)
++ goto err;
++
++ return 0;
++
++err:
++ kfree(dev);
++ pr_err("DvC.Trace gadget driver failed to initialize\n");
++ return ret;
++}
++
++static void dvc_trace_cleanup(void)
++{
++ misc_deregister(&dvc_trace_device);
++
++ kfree(_dvc_trace_dev);
++ _dvc_trace_dev = NULL;
++}
+diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
+index c35a9ec..1a847b7 100644
+--- a/drivers/usb/gadget/f_mass_storage.c
++++ b/drivers/usb/gadget/f_mass_storage.c
+@@ -2871,7 +2871,7 @@ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
+ fsg->common->new_fsg = NULL;
+ raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
+ /* FIXME: make interruptible or killable somehow? */
+- wait_event(common->fsg_wait, common->fsg != fsg);
++ wait_event_timeout(common->fsg_wait, common->fsg != fsg, msecs_to_jiffies(1000));
+ }
+
+ fsg_common_put(common);
+diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
+index bcd04bc..a3b44f2 100644
+--- a/drivers/usb/gadget/gadget_chips.h
++++ b/drivers/usb/gadget/gadget_chips.h
+@@ -16,6 +16,7 @@
+ #define __GADGET_CHIPS_H
+
+ #include <linux/usb/gadget.h>
++#include <asm/intel-mid.h>
+
+ /*
+ * NOTICE: the entries below are alphabetical and should be kept
+@@ -29,11 +30,13 @@
+ */
+ #define gadget_is_at91(g) (!strcmp("at91_udc", (g)->name))
+ #define gadget_is_goku(g) (!strcmp("goku_udc", (g)->name))
++#define gadget_is_middwc3tng(g) ((!strcmp("dwc3-gadget", (g)->name)) && \
++ (intel_mid_identify_cpu() == \
++ INTEL_MID_CPU_CHIP_TANGIER))
+ #define gadget_is_musbhdrc(g) (!strcmp("musb-hdrc", (g)->name))
+ #define gadget_is_net2280(g) (!strcmp("net2280", (g)->name))
+ #define gadget_is_pxa(g) (!strcmp("pxa25x_udc", (g)->name))
+ #define gadget_is_pxa27x(g) (!strcmp("pxa27x_udc", (g)->name))
+-
+ /**
+ * gadget_supports_altsettings - return true if altsettings work
+ * @gadget: the gadget in question
+diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
+index 4b76124..0d130b4 100644
+--- a/drivers/usb/gadget/u_ether.c
++++ b/drivers/usb/gadget/u_ether.c
+@@ -223,8 +223,6 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
+ */
+ size += sizeof(struct ethhdr) + dev->net->mtu + RX_EXTRA;
+ size += dev->port_usb->header_len;
+- size += out->maxpacket - 1;
+- size -= size % out->maxpacket;
+
+ if (dev->port_usb->is_fixed)
+ size = max_t(size_t, size, dev->port_usb->fixed_out_len);
+diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
+index b369292..f0ab6cd 100644
+--- a/drivers/usb/gadget/u_serial.c
++++ b/drivers/usb/gadget/u_serial.c
+@@ -1075,7 +1075,7 @@ static void gserial_free_port(struct gs_port *port)
+ {
+ tasklet_kill(&port->push);
+ /* wait for old opens to finish */
+- wait_event(port->port.close_wait, gs_closed(port));
++ wait_event_timeout(port->port.close_wait, gs_closed(port), msecs_to_jiffies(1000));
+ WARN_ON(port->port_usb != NULL);
+ tty_port_destroy(&port->port);
+ kfree(port);
+diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c
+index 5514822..eed8503 100644
+--- a/drivers/usb/gadget/udc-core.c
++++ b/drivers/usb/gadget/udc-core.c
+@@ -23,6 +23,7 @@
+ #include <linux/list.h>
+ #include <linux/err.h>
+ #include <linux/dma-mapping.h>
++#include <linux/workqueue.h>
+
+ #include <linux/usb/ch9.h>
+ #include <linux/usb/gadget.h>
+@@ -101,11 +102,18 @@ EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
+
+ /* ------------------------------------------------------------------------- */
+
++static void usb_gadget_state_work(struct work_struct *work)
++{
++ struct usb_gadget *gadget = work_to_gadget(work);
++
++ sysfs_notify(&gadget->dev.kobj, NULL, "status");
++}
++
+ void usb_gadget_set_state(struct usb_gadget *gadget,
+ enum usb_device_state state)
+ {
+ gadget->state = state;
+- sysfs_notify(&gadget->dev.kobj, NULL, "state");
++ schedule_work(&gadget->work);
+ }
+ EXPORT_SYMBOL_GPL(usb_gadget_set_state);
+
+@@ -192,6 +200,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
+ goto err1;
+
+ dev_set_name(&gadget->dev, "gadget");
++ INIT_WORK(&gadget->work, usb_gadget_state_work);
+ gadget->dev.parent = parent;
+
+ dma_set_coherent_mask(&gadget->dev, parent->coherent_dma_mask);
+@@ -309,6 +318,7 @@ found:
+ usb_gadget_remove_driver(udc);
+
+ kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
++ flush_work(&gadget->work);
+ device_unregister(&udc->dev);
+ device_unregister(&gadget->dev);
+ }
+diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
+index 8fe401c..b74b77d 100644
+--- a/drivers/usb/host/ehci-pci.c
++++ b/drivers/usb/host/ehci-pci.c
+@@ -412,7 +412,7 @@ static struct pci_driver ehci_pci_driver = {
+
+ static int __init ehci_pci_init(void)
+ {
+- if (usb_disabled())
++ //if (usb_disabled())
+ return -ENODEV;
+
+ pr_info("%s: " DRIVER_DESC "\n", hcd_name);
+diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
+index 6e70ce9..37003c8 100644
+--- a/drivers/usb/host/xhci-plat.c
++++ b/drivers/usb/host/xhci-plat.c
+@@ -195,12 +195,23 @@ static struct platform_driver usb_xhci_driver = {
+ };
+ MODULE_ALIAS("platform:xhci-hcd");
+
++#ifdef CONFIG_USB_DWC3_HOST_INTEL
++#include "../dwc3/dwc3-host-intel.c"
++#endif
++
+ int xhci_register_plat(void)
+ {
++#ifdef CONFIG_USB_DWC3_HOST_INTEL
++ return platform_driver_register(&dwc3_xhci_driver);
++#endif
+ return platform_driver_register(&usb_xhci_driver);
+ }
+
+ void xhci_unregister_plat(void)
+ {
++#ifdef CONFIG_USB_DWC3_HOST_INTEL
++ platform_driver_unregister(&dwc3_xhci_driver);
++ return;
++#endif
+ platform_driver_unregister(&usb_xhci_driver);
+ }
+diff --git a/drivers/usb/phy/penwell_otg.c b/drivers/usb/phy/penwell_otg.c
+new file mode 100644
+index 0000000..14b7d42
+--- /dev/null
++++ b/drivers/usb/phy/penwell_otg.c
+@@ -0,0 +1,5780 @@
++/*
++ * Intel Penwell USB OTG transceiver driver
++ * Copyright (C) 2009 - 2010, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++/* This driver helps to switch Penwell OTG controller function between host
++ * and peripheral. It works with EHCI driver and Penwell client controller
++ * driver together.
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/device.h>
++#include <linux/moduleparam.h>
++#include <linux/gpio.h>
++#include <linux/usb/ch9.h>
++#include <linux/usb/gadget.h>
++#include <linux/usb.h>
++#include <linux/usb/hcd.h>
++#include <linux/usb/otg.h>
++#include <linux/notifier.h>
++#include <linux/delay.h>
++#include <linux/pm_runtime.h>
++#include <linux/wakelock.h>
++#include <asm/intel_scu_pmic.h>
++#include <asm/intel_scu_ipc.h>
++#include <asm/intel-mid.h>
++#include "../core/usb.h"
++#include <linux/intel_mid_pm.h>
++
++#include <linux/usb/penwell_otg.h>
++
++#define DRIVER_DESC "Intel Penwell USB OTG transceiver driver"
++#define DRIVER_VERSION "0.8"
++
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_AUTHOR("Henry Yuan <hang.yuan@intel.com>, Hao Wu <hao.wu@intel.com>");
++MODULE_VERSION(DRIVER_VERSION);
++MODULE_LICENSE("GPL");
++
++static const char driver_name[] = "penwell_otg";
++
++static void penwell_otg_remove(struct pci_dev *pdev);
++
++static int penwell_otg_set_host(struct usb_otg *otg, struct usb_bus *host);
++static int penwell_otg_set_peripheral(struct usb_otg *otg,
++ struct usb_gadget *gadget);
++static int penwell_otg_start_srp(struct usb_otg *otg);
++static void penwell_otg_mon_bus(void);
++
++static int penwell_otg_msic_write(u16 addr, u8 data);
++
++static void penwell_otg_phy_low_power(int on);
++static int penwell_otg_ulpi_read(struct intel_mid_otg_xceiv *iotg,
++ u8 reg, u8 *val);
++static int penwell_otg_ulpi_write(struct intel_mid_otg_xceiv *iotg,
++ u8 reg, u8 val);
++static void penwell_spi_reset_phy(void);
++static int penwell_otg_charger_hwdet(bool enable);
++static void update_hsm(void);
++static void set_client_mode(void);
++
++#ifdef CONFIG_DEBUG_FS
++unsigned int *pm_sss0_base;
++
++int check_pm_otg(void)
++{
++ /* check whether bit 12 and 13 are 0 */
++ /* printk(">>>>leon, pm_sss0_base:0x%x\n", *(pm_sss0_base)); */
++ if (pm_sss0_base)
++ return (*pm_sss0_base) & 0x3000;
++ else
++ return 0;
++}
++#ifdef readl
++#undef readl
++#endif
++#ifdef writel
++#undef writel
++#endif
++#define readl(addr) ({ if (check_pm_otg()) { \
++ panic("usb otg, read reg:%p, pm_sss0_base:0x%x", \
++ addr, *(pm_sss0_base)); }; __le32_to_cpu(__raw_readl(addr)); })
++#define writel(b, addr) ({ if (check_pm_otg()) { \
++ panic("usb otg, write reg:%p, pm_sss0_base:0x%x", \
++ addr, *(pm_sss0_base)); }; __raw_writel(__cpu_to_le32(b), addr); })
++#endif
++
++#ifdef CONFIG_PM_SLEEP
++#include <linux/suspend.h>
++DECLARE_WAIT_QUEUE_HEAD(stop_host_wait);
++atomic_t pnw_sys_suspended;
++
++static int pnw_sleep_pm_callback(struct notifier_block *nfb,
++ unsigned long action, void *ignored)
++{
++ switch (action) {
++ case PM_SUSPEND_PREPARE:
++ atomic_set(&pnw_sys_suspended, 1);
++ return NOTIFY_OK;
++ case PM_POST_SUSPEND:
++ atomic_set(&pnw_sys_suspended, 0);
++ return NOTIFY_OK;
++ }
++ return NOTIFY_DONE;
++}
++
++static struct notifier_block pnw_sleep_pm_notifier = {
++ .notifier_call = pnw_sleep_pm_callback,
++ .priority = 0
++};
++
++/* the root hub will call this callback when device added/removed */
++static int otg_notify(struct notifier_block *nb, unsigned long action,
++ struct usb_device *udev)
++{
++ struct usb_phy *otg;
++ struct intel_mid_otg_xceiv *iotg;
++
++ /* skip bus add/remove notification, else access udev->parent could
++ * panic if bus register and unregister quickly(setup failed). And we
++ * do not care bus event.
++ */
++ if (action == USB_BUS_ADD || action == USB_BUS_REMOVE)
++ return NOTIFY_DONE;
++
++ /* Ignore root hub add/remove event */
++ if (!udev->parent) {
++ pr_debug("%s Ignore root hub otg_notify\n", __func__);
++ return NOTIFY_DONE;
++ }
++
++ /* Ignore USB devices on external hub */
++ if (udev->parent && udev->parent->parent) {
++ pr_debug("%s Ignore USB devices on external hub\n", __func__);
++ return NOTIFY_DONE;
++ }
++
++ otg = usb_get_phy(USB_PHY_TYPE_USB2);
++ if (otg == NULL) {
++ pr_err("%s: failed to get otg transceiver\n", __func__);
++ return NOTIFY_BAD;
++ }
++ iotg = otg_to_mid_xceiv(otg);
++
++ switch (action) {
++ case USB_DEVICE_ADD:
++ pr_debug("Notify OTG HNP add device\n");
++ atomic_notifier_call_chain(&iotg->iotg_notifier,
++ MID_OTG_NOTIFY_CONNECT, iotg);
++ break;
++ case USB_DEVICE_REMOVE:
++ pr_debug("Notify OTG HNP delete device\n");
++ atomic_notifier_call_chain(&iotg->iotg_notifier,
++ MID_OTG_NOTIFY_DISCONN, iotg);
++ break;
++ case USB_OTG_TESTDEV:
++ pr_debug("Notify OTG test device\n");
++ atomic_notifier_call_chain(&iotg->iotg_notifier,
++ MID_OTG_NOTIFY_TEST, iotg);
++ break;
++ case USB_OTG_TESTDEV_VBUSOFF:
++ pr_debug("Notify OTG test device, Vbusoff mode\n");
++ atomic_notifier_call_chain(&iotg->iotg_notifier,
++ MID_OTG_NOTIFY_TEST_VBUS_OFF, iotg);
++ break;
++ default:
++ usb_put_phy(otg);
++ return NOTIFY_DONE;
++ }
++ usb_put_phy(otg);
++ return NOTIFY_OK;
++}
++
++static struct notifier_block otg_nb = {
++ .notifier_call = otg_notify,
++};
++
++#define PNW_PM_RESUME_WAIT(a) do { \
++ while (atomic_read(&pnw_sys_suspended)) { \
++ wait_event_timeout(a, false, HZ/100); \
++ } \
++ } while (0)
++#else
++
++#define PNW_PM_RESUME_WAIT(a)
++
++#endif
++
++#define PNW_STOP_HOST(pnw) do { \
++ if ((pnw)->iotg.stop_host) { \
++ PNW_PM_RESUME_WAIT(stop_host_wait); \
++ (pnw)->iotg.stop_host(&(pnw)->iotg); \
++ } \
++ } while (0)
++
++inline int is_clovertrail(struct pci_dev *pdev)
++{
++ return (pdev->vendor == 0x8086 && pdev->device == 0xE006);
++}
++EXPORT_SYMBOL_GPL(is_clovertrail);
++
++static const char *state_string(enum usb_otg_state state)
++{
++ switch (state) {
++ case OTG_STATE_A_IDLE:
++ return "a_idle";
++ case OTG_STATE_A_WAIT_VRISE:
++ return "a_wait_vrise";
++ case OTG_STATE_A_WAIT_BCON:
++ return "a_wait_bcon";
++ case OTG_STATE_A_HOST:
++ return "a_host";
++ case OTG_STATE_A_SUSPEND:
++ return "a_suspend";
++ case OTG_STATE_A_PERIPHERAL:
++ return "a_peripheral";
++ case OTG_STATE_A_WAIT_VFALL:
++ return "a_wait_vfall";
++ case OTG_STATE_A_VBUS_ERR:
++ return "a_vbus_err";
++ case OTG_STATE_B_IDLE:
++ return "b_idle";
++ case OTG_STATE_B_PERIPHERAL:
++ return "b_peripheral";
++ case OTG_STATE_B_WAIT_ACON:
++ return "b_wait_acon";
++ case OTG_STATE_B_HOST:
++ return "b_host";
++ default:
++ return "UNDEFINED";
++ }
++}
++
++static const char *charger_string(enum usb_charger_type charger)
++{
++ switch (charger) {
++ case CHRG_SDP:
++ return "Standard Downstream Port";
++ case CHRG_SDP_INVAL:
++ return "Invalid Standard Downstream Port";
++ case CHRG_CDP:
++ return "Charging Downstream Port";
++ case CHRG_DCP:
++ return "Dedicated Charging Port";
++ case CHRG_ACA:
++ return "Accessory Charger Adaptor";
++ case CHRG_SE1:
++ return "SE1 Charger";
++ case CHRG_UNKNOWN:
++ return "Unknown";
++ default:
++ return "Undefined";
++ }
++}
++
++static const char *psc_string(enum power_supply_charger_cable_type charger)
++{
++ switch (charger) {
++ case POWER_SUPPLY_CHARGER_TYPE_USB_SDP:
++ return "Standard Downstream Port";
++ case POWER_SUPPLY_CHARGER_TYPE_USB_CDP:
++ return "Charging Downstream Port";
++ case POWER_SUPPLY_CHARGER_TYPE_USB_DCP:
++ return "Dedicated Charging Port";
++ case POWER_SUPPLY_CHARGER_TYPE_USB_ACA:
++ return "Accessory Charger Adaptor";
++ case POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK:
++ return "Accessory Charger Adaptor Dock";
++ case POWER_SUPPLY_CHARGER_TYPE_ACA_A:
++ return "Accessory Charger Adaptor Type A";
++ case POWER_SUPPLY_CHARGER_TYPE_ACA_B:
++ return "Accessory Charger Adaptor Type B";
++ case POWER_SUPPLY_CHARGER_TYPE_ACA_C:
++ return "Accessory Charger Adaptor Type C";
++ case POWER_SUPPLY_CHARGER_TYPE_SE1:
++ return "SE1 Charger";
++ case POWER_SUPPLY_CHARGER_TYPE_NONE:
++ return "Unknown";
++ default:
++ return "Undefined";
++ }
++}
++
++
++static struct penwell_otg *the_transceiver;
++
++void penwell_update_transceiver(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ unsigned long flags;
++
++
++ if (!pnw->qwork) {
++ dev_warn(pnw->dev, "no workqueue for state machine\n");
++ return;
++ }
++
++ spin_lock_irqsave(&pnw->lock, flags);
++ if (!pnw->queue_stop) {
++ queue_work(pnw->qwork, &pnw->work);
++ dev_dbg(pnw->dev, "transceiver is updated\n");
++ }
++ spin_unlock_irqrestore(&pnw->lock, flags);
++}
++
++static int penwell_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
++{
++ otg->host = host;
++
++ return 0;
++}
++
++static int penwell_otg_set_peripheral(struct usb_otg *otg,
++ struct usb_gadget *gadget)
++{
++ otg->gadget = gadget;
++
++ return 0;
++}
++
++static void penwell_otg_set_charger(enum usb_charger_type charger)
++{
++ struct penwell_otg *pnw = the_transceiver;
++
++ dev_dbg(pnw->dev, "%s ---> %s\n", __func__,
++ charger_string(charger));
++
++ switch (charger) {
++ case CHRG_SDP:
++ case CHRG_DCP:
++ case CHRG_CDP:
++ case CHRG_ACA:
++ case CHRG_SDP_INVAL:
++ case CHRG_SE1:
++ case CHRG_UNKNOWN:
++ pnw->charging_cap.chrg_type = charger;
++ break;
++ default:
++ dev_warn(pnw->dev, "undefined charger type\n");
++ break;
++ }
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++}
++
++static void _penwell_otg_update_chrg_cap(enum usb_charger_type charger,
++ unsigned ma)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ int flag = 0;
++ int event, retval;
++
++ dev_dbg(pnw->dev, "%s = %s, %d --->\n", __func__,
++ charger_string(charger), ma);
++
++ /* Check charger type information */
++ if (pnw->charging_cap.chrg_type != charger) {
++ if (pnw->charging_cap.chrg_type == CHRG_UNKNOWN ||
++ charger == CHRG_UNKNOWN) {
++ penwell_otg_set_charger(charger);
++ } else if (pnw->charging_cap.chrg_type == CHRG_SDP &&
++ charger == CHRG_SDP_INVAL) {
++ penwell_otg_set_charger(charger);
++ } else
++ return;
++ } else {
++ /* Do nothing if no update for current */
++ if (pnw->charging_cap.ma == ma)
++ return;
++ }
++
++ /* set current */
++ switch (pnw->charging_cap.chrg_type) {
++ case CHRG_SDP:
++ if (pnw->charging_cap.ma == CHRG_CURR_DISCONN
++ && (ma == CHRG_CURR_SDP_LOW
++ || ma == CHRG_CURR_SDP_HIGH)) {
++ /* SDP event: charger connect */
++ event = USBCHRG_EVENT_CONNECT;
++ flag = 1;
++ } else if (pnw->charging_cap.ma == CHRG_CURR_SDP_LOW
++ && ma == CHRG_CURR_SDP_HIGH) {
++ /* SDP event: configuration update */
++ event = USBCHRG_EVENT_UPDATE;
++ flag = 1;
++ } else if (pnw->charging_cap.ma == CHRG_CURR_SDP_HIGH
++ && ma == CHRG_CURR_SDP_LOW) {
++ /* SDP event: configuration update */
++ event = USBCHRG_EVENT_UPDATE;
++ flag = 1;
++ } else if (pnw->charging_cap.ma == CHRG_CURR_SDP_SUSP
++ && (ma == CHRG_CURR_SDP_LOW
++ || ma == CHRG_CURR_SDP_HIGH)) {
++ /* SDP event: resume from suspend state */
++ event = USBCHRG_EVENT_RESUME;
++ flag = 1;
++ } else if ((pnw->charging_cap.ma == CHRG_CURR_SDP_LOW
++ || pnw->charging_cap.ma == CHRG_CURR_SDP_HIGH)
++ && ma == CHRG_CURR_SDP_SUSP) {
++ /* SDP event: enter suspend state */
++ event = USBCHRG_EVENT_SUSPEND;
++ flag = 1;
++ } else if (ma == 0) {
++ event = USBCHRG_EVENT_DISCONN;
++ flag = 1;
++ } else
++ dev_dbg(pnw->dev, "SDP: no need to update EM\n");
++ break;
++ case CHRG_DCP:
++ if (ma == CHRG_CURR_DCP) {
++ /* DCP event: charger connect */
++ event = USBCHRG_EVENT_CONNECT;
++ flag = 1;
++ } else
++ dev_dbg(pnw->dev, "DCP: no need to update EM\n");
++ break;
++ case CHRG_SE1:
++ if (ma == CHRG_CURR_SE1) {
++ /* SE1 event: charger connect */
++ event = USBCHRG_EVENT_CONNECT;
++ flag = 1;
++ } else
++ dev_dbg(pnw->dev, "SE1: no need to update EM\n");
++ break;
++ case CHRG_CDP:
++ if (pnw->charging_cap.ma == CHRG_CURR_DISCONN
++ && ma == CHRG_CURR_CDP) {
++ /* CDP event: charger connect */
++ event = USBCHRG_EVENT_CONNECT;
++ flag = 1;
++ } else
++ dev_dbg(pnw->dev, "CDP: no need to update EM\n");
++ break;
++ case CHRG_UNKNOWN:
++ if (ma == CHRG_CURR_DISCONN) {
++ /* event: chargers disconnect */
++ event = USBCHRG_EVENT_DISCONN;
++ flag = 1;
++ } else
++ dev_dbg(pnw->dev, "UNKNOWN: no need to update EM\n");
++ break;
++ case CHRG_SDP_INVAL:
++ if (ma == CHRG_CURR_SDP_INVAL) {
++ event = USBCHRG_EVENT_UPDATE;
++ flag = 1;
++ } else
++ dev_dbg(pnw->dev, "SDP_INVAL: no need to update EM\n");
++ default:
++ break;
++ }
++
++ if (flag) {
++ pnw->charging_cap.ma = ma;
++ pnw->charging_cap.current_event = event;
++
++ /* Notify EM the charging current update */
++ dev_dbg(pnw->dev, "Notify EM charging capability change\n");
++ dev_dbg(pnw->dev, "%s event = %d ma = %d\n",
++ charger_string(pnw->charging_cap.chrg_type), event, ma);
++
++ if (pnw->bc_callback) {
++ retval = pnw->bc_callback(pnw->bc_arg, event,
++ &pnw->charging_cap);
++ if (retval)
++ dev_dbg(pnw->dev,
++ "bc callback return %d\n", retval);
++ }
++ }
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++}
++
++static enum power_supply_charger_cable_type usb_chrg_to_power_supply_chrg(
++ enum usb_charger_type chrg_type)
++{
++ switch (chrg_type) {
++ case CHRG_UNKNOWN: return POWER_SUPPLY_CHARGER_TYPE_NONE;
++ case CHRG_SDP: return POWER_SUPPLY_CHARGER_TYPE_USB_SDP;
++ case CHRG_CDP: return POWER_SUPPLY_CHARGER_TYPE_USB_CDP;
++ case CHRG_SDP_INVAL: return POWER_SUPPLY_CHARGER_TYPE_USB_SDP;
++ case CHRG_DCP: return POWER_SUPPLY_CHARGER_TYPE_USB_DCP;
++ case CHRG_ACA: return POWER_SUPPLY_CHARGER_TYPE_USB_ACA;
++ case CHRG_ACA_DOCK: return POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK;
++ case CHRG_ACA_A: return POWER_SUPPLY_CHARGER_TYPE_ACA_A;
++ case CHRG_ACA_B: return POWER_SUPPLY_CHARGER_TYPE_ACA_B;
++ case CHRG_ACA_C: return POWER_SUPPLY_CHARGER_TYPE_ACA_C;
++ case CHRG_SE1: return POWER_SUPPLY_CHARGER_TYPE_SE1;
++ case CHRG_MHL: return POWER_SUPPLY_CHARGER_TYPE_MHL;
++ default: return POWER_SUPPLY_CHARGER_TYPE_NONE;
++ }
++}
++
++static enum power_supply_charger_event check_psc_event(
++ struct power_supply_cable_props old,
++ struct power_supply_cable_props new)
++{
++ struct penwell_otg *pnw = the_transceiver;
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++
++ /* Check charger type information */
++ if (old.chrg_type != new.chrg_type) {
++ if (old.chrg_type == POWER_SUPPLY_CHARGER_TYPE_NONE
++ && new.ma != 0)
++ return POWER_SUPPLY_CHARGER_EVENT_CONNECT;
++ else if (new.chrg_type == POWER_SUPPLY_CHARGER_TYPE_NONE)
++ return POWER_SUPPLY_CHARGER_EVENT_DISCONNECT;
++ else {
++ dev_dbg(pnw->dev, "not a valid event\n");
++ return -1;
++ }
++ }
++
++ /* Check the charging current limit */
++ if (old.ma == new.ma) {
++ dev_dbg(pnw->dev, "not a valid event\n");
++ return -1;
++ }
++
++ switch (new.chrg_type) {
++ case POWER_SUPPLY_CHARGER_TYPE_USB_SDP:
++ if (old.ma == CHRG_CURR_DISCONN &&
++ (new.ma == CHRG_CURR_SDP_LOW ||
++ new.ma == CHRG_CURR_SDP_HIGH)) {
++ /* SDP event: charger connect */
++ return POWER_SUPPLY_CHARGER_EVENT_CONNECT;
++ } else if (old.ma == CHRG_CURR_SDP_LOW &&
++ new.ma == CHRG_CURR_SDP_HIGH) {
++ /* SDP event: configuration update */
++ return POWER_SUPPLY_CHARGER_EVENT_UPDATE;
++ } else if (old.ma == CHRG_CURR_SDP_HIGH &&
++ new.ma == CHRG_CURR_SDP_LOW) {
++ /* SDP event: configuration update */
++ return POWER_SUPPLY_CHARGER_EVENT_UPDATE;
++ } else if (old.ma == CHRG_CURR_SDP_SUSP &&
++ (new.ma == CHRG_CURR_SDP_LOW ||
++ new.ma == CHRG_CURR_SDP_HIGH)) {
++ /* SDP event: resume from suspend state */
++ return POWER_SUPPLY_CHARGER_EVENT_RESUME;
++ } else if ((old.ma == CHRG_CURR_SDP_LOW ||
++ old.ma == CHRG_CURR_SDP_HIGH) &&
++ new.ma == CHRG_CURR_SDP_SUSP) {
++ /* SDP event: enter suspend state */
++ return POWER_SUPPLY_CHARGER_EVENT_SUSPEND;
++ } else
++ dev_dbg(pnw->dev, "SDP: no need to update EM\n");
++ break;
++ case POWER_SUPPLY_CHARGER_TYPE_USB_DCP:
++ if (new.ma == CHRG_CURR_DCP) {
++ /* DCP event: charger connect */
++ return POWER_SUPPLY_CHARGER_EVENT_CONNECT;
++ } else
++ dev_dbg(pnw->dev, "DCP: no need to update EM\n");
++ break;
++ case POWER_SUPPLY_CHARGER_TYPE_USB_CDP:
++ if (pnw->charging_cap.ma == CHRG_CURR_DISCONN &&
++ new.ma == CHRG_CURR_CDP) {
++ /* CDP event: charger connect */
++ return POWER_SUPPLY_CHARGER_EVENT_CONNECT;
++ } else
++ dev_dbg(pnw->dev, "CDP: no need to update EM\n");
++ break;
++ case POWER_SUPPLY_CHARGER_TYPE_NONE:
++ if (new.ma == CHRG_CURR_DISCONN) {
++ /* event: chargers disconnect */
++ return POWER_SUPPLY_CHARGER_EVENT_DISCONNECT;
++ } else
++ dev_dbg(pnw->dev, "UNKNOWN: no need to update EM\n");
++ break;
++ default:
++ break;
++ }
++
++ return -1;
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++}
++
++static void penwell_otg_update_chrg_cap(enum usb_charger_type charger,
++ unsigned ma)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct pci_dev *pdev;
++ unsigned long flags;
++ struct otg_bc_event *event;
++
++ pdev = to_pci_dev(pnw->dev);
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++
++ if (!is_clovertrail(pdev)) {
++ spin_lock_irqsave(&pnw->charger_lock, flags);
++ _penwell_otg_update_chrg_cap(charger, ma);
++ spin_unlock_irqrestore(&pnw->charger_lock, flags);
++ } else {
++ dev_dbg(pnw->dev, "clv cable_props_update\n");
++
++ event = kzalloc(sizeof(*event), GFP_ATOMIC);
++ if (!event) {
++ dev_err(pnw->dev, "no memory for charging event");
++ return;
++ }
++
++ event->cap.chrg_type = usb_chrg_to_power_supply_chrg(charger);
++ event->cap.ma = ma;
++ INIT_LIST_HEAD(&event->node);
++
++ spin_lock_irqsave(&pnw->charger_lock, flags);
++ list_add_tail(&event->node, &pnw->chrg_evt_queue);
++ spin_unlock_irqrestore(&pnw->charger_lock, flags);
++
++ queue_work(pnw->chrg_qwork, &pnw->psc_notify);
++ }
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++}
++
++static int penwell_otg_set_power(struct usb_phy *otg, unsigned ma)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ unsigned long flags;
++ struct pci_dev *pdev;
++ struct otg_bc_event *event;
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++
++ pdev = to_pci_dev(pnw->dev);
++
++ if (!is_clovertrail(pdev)) {
++ spin_lock_irqsave(&pnw->charger_lock, flags);
++
++ if (pnw->charging_cap.chrg_type != CHRG_SDP) {
++ spin_unlock_irqrestore(&pnw->charger_lock, flags);
++ return 0;
++ }
++
++ if (!pnw->otg_pdata->charging_compliance)
++ ma = CHRG_CURR_SDP_HIGH;
++
++ _penwell_otg_update_chrg_cap(CHRG_SDP, ma);
++
++ spin_unlock_irqrestore(&pnw->charger_lock, flags);
++ } else {
++ dev_dbg(pnw->dev, "clv charger_set_power\n");
++
++ if (pnw->psc_cap.chrg_type != POWER_SUPPLY_CHARGER_TYPE_USB_SDP)
++ return 0;
++
++ if (!pnw->otg_pdata->charging_compliance)
++ ma = CHRG_CURR_SDP_HIGH;
++
++ event = kzalloc(sizeof(*event), GFP_ATOMIC);
++ if (!event) {
++ dev_err(pnw->dev, "no memory for charging event");
++ return -ENOMEM;
++ }
++
++ event->cap.chrg_type = POWER_SUPPLY_CHARGER_TYPE_USB_SDP;
++ event->cap.ma = ma;
++ INIT_LIST_HEAD(&event->node);
++
++ spin_lock_irqsave(&pnw->charger_lock, flags);
++ list_add_tail(&event->node, &pnw->chrg_evt_queue);
++ spin_unlock_irqrestore(&pnw->charger_lock, flags);
++
++ queue_work(pnw->chrg_qwork, &pnw->psc_notify);
++ }
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++
++ return 0;
++}
++
++int penwell_otg_get_chrg_status(struct usb_phy *x, void *data)
++{
++ unsigned long flags;
++ struct power_supply_cable_props *cap =
++ (struct power_supply_cable_props *)data;
++ struct penwell_otg *pnw = the_transceiver;
++
++ if (pnw == NULL)
++ return -ENODEV;
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++
++ if (data == NULL)
++ return -EINVAL;
++
++ spin_lock_irqsave(&pnw->cap_lock, flags);
++ cap->chrg_evt = pnw->psc_cap.chrg_evt;
++ cap->chrg_type = pnw->psc_cap.chrg_type;
++ cap->ma = pnw->psc_cap.ma;
++ spin_unlock_irqrestore(&pnw->cap_lock, flags);
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++ return 0;
++}
++
++int penwell_otg_query_charging_cap(struct otg_bc_cap *cap)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ unsigned long flags;
++
++ if (pnw == NULL)
++ return -ENODEV;
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++
++ if (cap == NULL)
++ return -EINVAL;
++
++ if (is_clovertrail(to_pci_dev(pnw->dev)))
++ return -ENODEV;
++
++ spin_lock_irqsave(&pnw->charger_lock, flags);
++ cap->chrg_type = pnw->charging_cap.chrg_type;
++ cap->ma = pnw->charging_cap.ma;
++ cap->current_event = pnw->charging_cap.current_event;
++ spin_unlock_irqrestore(&pnw->charger_lock, flags);
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++ return 0;
++}
++EXPORT_SYMBOL_GPL(penwell_otg_query_charging_cap);
++
++/* Register/unregister battery driver callback */
++void *penwell_otg_register_bc_callback(
++ int (*cb)(void *, int, struct otg_bc_cap *), void *arg)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ unsigned long flags;
++
++ if (pnw == NULL)
++ return pnw;
++
++ if (is_clovertrail(to_pci_dev(pnw->dev)))
++ return NULL;
++
++ spin_lock_irqsave(&pnw->charger_lock, flags);
++
++ if (pnw->bc_callback != NULL)
++ dev_dbg(pnw->dev, "callback has already registered\n");
++
++ pnw->bc_callback = cb;
++ pnw->bc_arg = arg;
++ spin_unlock_irqrestore(&pnw->charger_lock, flags);
++
++ return pnw;
++}
++EXPORT_SYMBOL_GPL(penwell_otg_register_bc_callback);
++
++int penwell_otg_unregister_bc_callback(void *handler)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ unsigned long flags;
++
++ if (pnw == NULL)
++ return -ENODEV;
++
++ if (pnw != handler)
++ return -EINVAL;
++
++ if (is_clovertrail(to_pci_dev(pnw->dev)))
++ return -ENODEV;
++
++ spin_lock_irqsave(&pnw->charger_lock, flags);
++ pnw->bc_callback = NULL;
++ pnw->bc_arg = NULL;
++ spin_unlock_irqrestore(&pnw->charger_lock, flags);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(penwell_otg_unregister_bc_callback);
++
++/* After probe, it should enable the power of USB PHY */
++static void penwell_otg_phy_enable(int on)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ u8 data;
++
++ dev_dbg(pnw->dev, "%s ---> %s\n", __func__, on ? "on" : "off");
++
++ data = on ? 0x37 : 0x24;
++
++ mutex_lock(&pnw->msic_mutex);
++
++ if (penwell_otg_msic_write(MSIC_VUSB330CNT, data)) {
++ mutex_unlock(&pnw->msic_mutex);
++ dev_err(pnw->dev, "Fail to enable PHY power\n");
++ return;
++ }
++
++ mutex_unlock(&pnw->msic_mutex);
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++}
++
++/* A-device drives vbus, controlled through MSIC register */
++static int penwell_otg_set_vbus(struct usb_otg *otg, bool enabled)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ u8 data;
++ unsigned long flags;
++ int retval = 0;
++ struct otg_bc_event *evt;
++
++ dev_dbg(pnw->dev, "%s ---> %s\n", __func__, enabled ? "on" : "off");
++
++ /*
++ * For Clovertrail, VBUS is driven by TPS2052 power switch chip.
++ * But TPS2052 is controlled by ULPI PHY.
++ */
++ if (is_clovertrail(to_pci_dev(pnw->dev))) {
++ penwell_otg_phy_low_power(0);
++ if (enabled)
++ penwell_otg_ulpi_write(&pnw->iotg,
++ ULPI_OTGCTRLSET, DRVVBUS | DRVVBUS_EXTERNAL);
++ else
++ penwell_otg_ulpi_write(&pnw->iotg,
++ ULPI_OTGCTRLCLR, DRVVBUS | DRVVBUS_EXTERNAL);
++
++ evt = kzalloc(sizeof(*evt), GFP_KERNEL);
++ if (!evt) {
++ dev_err(pnw->dev, "no memory for charging event");
++ return -ENOMEM;
++ }
++
++ evt->cap.chrg_type = POWER_SUPPLY_CHARGER_TYPE_NONE;
++ INIT_LIST_HEAD(&evt->node);
++
++ if ((!enabled) && (pnw->iotg.hsm.id == ID_ACA_A
++ || pnw->iotg.hsm.id == ID_ACA_B
++ || pnw->iotg.hsm.id == ID_ACA_C)) {
++ evt->cap.chrg_type = POWER_SUPPLY_CHARGER_TYPE_USB_ACA;
++ evt->cap.ma = CHRG_CURR_ACA;
++ evt->cap.chrg_evt = POWER_SUPPLY_CHARGER_EVENT_CONNECT;
++ } else {
++ dev_info(pnw->dev, "notification: turn %s VBUS\n",
++ enabled ? "ON" : "OFF");
++ atomic_notifier_call_chain(&pnw->iotg.otg.notifier,
++ USB_EVENT_DRIVE_VBUS, &enabled);
++ kfree(evt);
++ goto done;
++ }
++
++ dev_dbg(pnw->dev, "set_vbus ma = %d, event = %d, type = %s\n",
++ evt->cap.ma, evt->cap.chrg_evt,
++ psc_string(evt->cap.chrg_type));
++
++ spin_lock_irqsave(&pnw->charger_lock, flags);
++ list_add_tail(&evt->node, &pnw->chrg_evt_queue);
++ spin_unlock_irqrestore(&pnw->charger_lock, flags);
++
++ queue_work(pnw->chrg_qwork, &pnw->psc_notify);
++
++ goto done;
++ }
++
++ if (pnw->otg_pdata->gpio_vbus) {
++ dev_info(pnw->dev, "Turn %s VBUS using GPIO pin %d\n",
++ enabled ? "on" : "off", pnw->otg_pdata->gpio_vbus);
++ gpio_direction_output(pnw->otg_pdata->gpio_vbus,
++ enabled ? 1 : 0);
++ goto done;
++ }
++
++ data = enabled ? VOTGEN : 0;
++
++ mutex_lock(&pnw->msic_mutex);
++
++ retval = intel_scu_ipc_update_register(MSIC_VOTGCNT, data, VOTGEN);
++
++ if (retval)
++ dev_err(pnw->dev, "Fail to set power on OTG Port\n");
++
++ mutex_unlock(&pnw->msic_mutex);
++
++done:
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++
++ return retval;
++}
++
++static int penwell_otg_ulpi_run(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ u32 val;
++
++ val = readl(pnw->iotg.base + CI_ULPIVP);
++
++ if (val & ULPI_RUN)
++ return 1;
++
++ dev_dbg(pnw->dev, "%s: ULPI command done\n", __func__);
++ return 0;
++}
++
++/* io_ops to access ulpi registers */
++static int
++penwell_otg_ulpi_read(struct intel_mid_otg_xceiv *iotg, u8 reg, u8 *val)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ u32 val32 = 0;
++ int count;
++ unsigned long flags;
++
++ dev_dbg(pnw->dev, "%s - addr 0x%x\n", __func__, reg);
++
++ spin_lock_irqsave(&pnw->lock, flags);
++
++ /* Port = 0 */
++ val32 = ULPI_RUN | reg << 16;
++ writel(val32, pnw->iotg.base + CI_ULPIVP);
++
++ /* Polling at least 2ms for read operation to complete*/
++ count = 400;
++
++ while (count) {
++ val32 = readl(pnw->iotg.base + CI_ULPIVP);
++ if (val32 & ULPI_RUN) {
++ count--;
++ udelay(5);
++ } else {
++ *val = (u8)((val32 & ULPI_DATRD) >> 8);
++ dev_dbg(pnw->dev,
++ "%s - done data 0x%x\n", __func__, *val);
++ spin_unlock_irqrestore(&pnw->lock, flags);
++ return 0;
++ }
++ }
++
++ dev_warn(pnw->dev, "%s - addr 0x%x timeout\n", __func__, reg);
++
++ spin_unlock_irqrestore(&pnw->lock, flags);
++ return -ETIMEDOUT;
++
++}
++
++static int
++penwell_otg_ulpi_write(struct intel_mid_otg_xceiv *iotg, u8 reg, u8 val)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ u32 val32 = 0;
++ int count;
++ unsigned long flags;
++
++ dev_dbg(pnw->dev,
++ "%s - addr 0x%x - data 0x%x\n", __func__, reg, val);
++
++ spin_lock_irqsave(&pnw->lock, flags);
++
++ /* Port = 0 */
++ val32 = ULPI_RUN | ULPI_RW | reg << 16 | val;
++ writel(val32, pnw->iotg.base + CI_ULPIVP);
++
++ /* Polling at least 2ms for write operation to complete*/
++ count = 400;
++
++ while (count && penwell_otg_ulpi_run()) {
++ count--;
++ udelay(5);
++ }
++
++ dev_dbg(pnw->dev, "%s - addr 0x%x %s\n", __func__, reg,
++ count ? "complete" : "timeout");
++
++ spin_unlock_irqrestore(&pnw->lock, flags);
++ return count ? 0 : -ETIMEDOUT;
++}
++
++int pnw_otg_ulpi_write(u8 reg, u8 val)
++{
++ return penwell_otg_ulpi_write(&the_transceiver->iotg,
++ reg, val);
++}
++EXPORT_SYMBOL_GPL(pnw_otg_ulpi_write);
++
++static enum msic_vendor penwell_otg_check_msic(void)
++{
++ /* Return MSIC_VD_TI directly */
++ return MSIC_VD_TI;
++}
++
++/* Monitor function check if SRP initial conditions. Use polling on current
++ * status for b_ssend_srp, b_se0_srp */
++static void penwell_otg_mon_bus(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ int count = 6;
++ int interval = 300; /* ms */
++ u32 val = 0;
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++ pnw->iotg.hsm.b_ssend_srp = 0;
++ pnw->iotg.hsm.b_se0_srp = 0;
++
++ while (count) {
++ msleep(interval);
++
++ /* Check VBus status */
++ val = readl(pnw->iotg.base + CI_OTGSC);
++ if (!(val & OTGSC_BSE))
++ return;
++
++ val = readl(pnw->iotg.base + CI_PORTSC1);
++ if (val & PORTSC_LS)
++ return;
++
++ count--;
++ }
++
++ pnw->iotg.hsm.b_ssend_srp = 1;
++ pnw->iotg.hsm.b_se0_srp = 1;
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++}
++
++/* HNP polling function */
++/* The timeout callback function which polls the host request flag for HNP */
++static void penwell_otg_hnp_poll_fn(unsigned long indicator)
++{
++ struct penwell_otg *pnw = the_transceiver;
++
++ queue_work(pnw->qwork, &pnw->hnp_poll_work);
++}
++
++/* Start HNP polling */
++/* Call this function with iotg->hnp_poll_lock held */
++static int penwell_otg_add_hnp_poll_timer(struct intel_mid_otg_xceiv *iotg,
++ unsigned long delay)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ unsigned long j = jiffies;
++
++ pnw->hnp_poll_timer.data = 1;
++ pnw->hnp_poll_timer.function = penwell_otg_hnp_poll_fn;
++ pnw->hnp_poll_timer.expires = j + msecs_to_jiffies(delay);
++
++ add_timer(&pnw->hnp_poll_timer);
++
++ return 0;
++}
++
++static int penwell_otg_start_hnp_poll(struct intel_mid_otg_xceiv *iotg)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ unsigned long flags;
++
++ spin_lock_irqsave(&pnw->iotg.hnp_poll_lock, flags);
++
++ if (pnw->iotg.hsm.hnp_poll_enable) {
++ spin_unlock_irqrestore(&pnw->iotg.hnp_poll_lock, flags);
++ dev_dbg(pnw->dev, "HNP polling is already enabled\n");
++ return 0;
++ }
++
++ /* mark HNP polling enabled and start HNP polling in 50ms */
++ pnw->iotg.hsm.hnp_poll_enable = 1;
++ penwell_otg_add_hnp_poll_timer(&pnw->iotg, 50);
++
++ spin_unlock_irqrestore(&pnw->iotg.hnp_poll_lock, flags);
++
++ return 0;
++}
++
++static int penwell_otg_continue_hnp_poll(struct intel_mid_otg_xceiv *iotg)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ unsigned long flags;
++
++ spin_lock_irqsave(&pnw->iotg.hnp_poll_lock, flags);
++
++ if (!pnw->iotg.hsm.hnp_poll_enable) {
++ spin_unlock_irqrestore(&pnw->iotg.hnp_poll_lock, flags);
++ dev_dbg(pnw->dev, "HNP polling is disabled, stop polling\n");
++ return 0;
++ }
++
++ penwell_otg_add_hnp_poll_timer(&pnw->iotg, THOS_REQ_POL);
++
++ spin_unlock_irqrestore(&pnw->iotg.hnp_poll_lock, flags);
++
++ return 0;
++}
++
++/* Stop HNP polling */
++static int penwell_otg_stop_hnp_poll(struct intel_mid_otg_xceiv *iotg)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ unsigned long flags;
++
++ spin_lock_irqsave(&pnw->iotg.hnp_poll_lock, flags);
++
++ if (!pnw->iotg.hsm.hnp_poll_enable) {
++ spin_unlock_irqrestore(&pnw->iotg.hnp_poll_lock, flags);
++ dev_dbg(pnw->dev, "HNP polling is already disabled\n");
++ return 0;
++ }
++
++ pnw->iotg.hsm.hnp_poll_enable = 0;
++ del_timer_sync(&pnw->hnp_poll_timer);
++
++ spin_unlock_irqrestore(&pnw->iotg.hnp_poll_lock, flags);
++
++ return 0;
++}
++
++/* Start SRP function */
++static int penwell_otg_start_srp(struct usb_otg *otg)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ u32 val;
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++
++ val = readl(pnw->iotg.base + CI_OTGSC);
++
++ writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HADP,
++ pnw->iotg.base + CI_OTGSC);
++
++ /* Check if the data plus is finished or not */
++ msleep(8);
++ val = readl(pnw->iotg.base + CI_OTGSC);
++ if (val & (OTGSC_HADP | OTGSC_DP))
++ dev_warn(pnw->dev, "DataLine SRP Error\n");
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++ return 0;
++}
++
++/* stop SOF via bus_suspend */
++static void penwell_otg_loc_sof(int on)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct usb_hcd *hcd;
++ int err;
++
++ dev_dbg(pnw->dev, "%s ---> %s\n", __func__, on ? "resume" : "suspend");
++
++ hcd = bus_to_hcd(pnw->iotg.otg.otg->host);
++ if (on)
++ err = hcd->driver->bus_resume(hcd);
++ else
++ err = hcd->driver->bus_suspend(hcd);
++
++ if (err)
++ dev_warn(pnw->dev, "Fail to resume/suspend USB bus -%d\n", err);
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++}
++
++static void penwell_otg_phy_low_power(int on)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ u32 val;
++
++ dev_dbg(pnw->dev, "%s ---> %s\n", __func__, on ? "on" : "off");
++
++ val = readl(pnw->iotg.base + CI_USBMODE);
++ if (!(val & USBMODE_CM)) {
++ dev_err(pnw->dev,
++ "PHY can't enter low power mode "
++ "when UDC is in idle mode\n");
++ set_client_mode();
++ }
++
++ val = readl(pnw->iotg.base + CI_HOSTPC1);
++ dev_dbg(pnw->dev, "---> Register CI_HOSTPC1 = %x\n", val);
++
++ if (on) {
++ if (val & HOSTPC1_PHCD) {
++ dev_dbg(pnw->dev, "already in Low power mode\n");
++ return;
++ }
++ writel(val | HOSTPC1_PHCD, pnw->iotg.base + CI_HOSTPC1);
++ } else {
++ if (!(val & HOSTPC1_PHCD)) {
++ dev_dbg(pnw->dev, "already in Normal mode\n");
++ return;
++ }
++ writel(val & ~HOSTPC1_PHCD, pnw->iotg.base + CI_HOSTPC1);
++ }
++
++ val = readl(pnw->iotg.base + CI_HOSTPC1);
++
++ dev_dbg(pnw->dev, "<--- Register CI_HOSTPC1 = %x\n", val);
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++}
++
++/*
++ * For Penwell, VBUS330 is the power rail to otg PHY inside MSIC, set it
++ * into low power mode or normal mode according to pm state.
++ * Call this function when spi access to MSIC registers is enabled.
++ *
++ * For Clovertrail, we don't have a controllable power rail to the PHY -
++ * it's always on.
++ */
++static int penwell_otg_vusb330_low_power(int on)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ u8 data;
++ int retval = 0;
++
++ dev_dbg(pnw->dev, "%s ---> %s\n", __func__, on ? "on" : "off");
++
++ if (!is_clovertrail(to_pci_dev(pnw->dev))) {
++ if (on)
++ data = 0x5; /* Low power mode */
++ else
++ data = 0x7; /* Normal mode */
++ retval = penwell_otg_msic_write(MSIC_VUSB330CNT, data);
++ }
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++
++ return retval;
++}
++
++/* Enable/Disable OTG interrupt */
++static void penwell_otg_intr(int on)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ u32 val;
++
++ dev_dbg(pnw->dev, "%s ---> %s\n", __func__, on ? "on" : "off");
++
++ val = readl(pnw->iotg.base + CI_OTGSC);
++ /* mask W/C bits to avoid clearing them when
++ * val is written back to OTGSC */
++ val &= ~OTGSC_INTSTS_MASK;
++ if (on) {
++ val = val | (OTGSC_INTEN_MASK);
++ writel(val, pnw->iotg.base + CI_OTGSC);
++ } else {
++ val = val & ~(OTGSC_INTEN_MASK);
++ writel(val, pnw->iotg.base + CI_OTGSC);
++ }
++}
++
++/* set HAAR: Hardware Assist Auto-Reset */
++static void penwell_otg_HAAR(int on)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ u32 val;
++
++ dev_dbg(pnw->dev, "%s ---> %s\n", __func__, on ? "on" : "off");
++
++ val = readl(pnw->iotg.base + CI_OTGSC);
++ if (on)
++ writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HAAR,
++ pnw->iotg.base + CI_OTGSC);
++ else
++ writel((val & ~OTGSC_INTSTS_MASK) & ~OTGSC_HAAR,
++ pnw->iotg.base + CI_OTGSC);
++}
++
++/* set HABA: Hardware Assist B-Disconnect to A-Connect */
++static void penwell_otg_HABA(int on)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ u32 val;
++
++ dev_dbg(pnw->dev, "%s ---> %s\n", __func__, on ? "on" : "off");
++
++ val = readl(pnw->iotg.base + CI_OTGSC);
++ if (on)
++ writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HABA,
++ pnw->iotg.base + CI_OTGSC);
++ else
++ writel((val & ~OTGSC_INTSTS_MASK) & ~OTGSC_HABA,
++ pnw->iotg.base + CI_OTGSC);
++}
++
++/* read 8bit msic register */
++static int penwell_otg_msic_read(u16 addr, u8 *data)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ int retval = intel_scu_ipc_ioread8(addr, data);
++ if (retval)
++ dev_warn(pnw->dev, "Failed to read MSIC register %x\n", addr);
++
++ return retval;
++}
++
++/* write 8bit msic register */
++static int penwell_otg_msic_write(u16 addr, u8 data)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ int retval = 0;
++
++ retval = intel_scu_ipc_iowrite8(addr, data);
++ if (retval)
++ dev_warn(pnw->dev, "Failed to write MSIC register %x\n", addr);
++
++ return retval;
++}
++
++/* USB related register in MSIC can be access via SPI address and ulpi address
++ * Access the control register to switch */
++static void penwell_otg_msic_spi_access(bool enabled)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ u8 data;
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++
++ /* Set ULPI ACCESS MODE */
++ data = enabled ? SPIMODE : 0;
++
++ penwell_otg_msic_write(MSIC_ULPIACCESSMODE, data);
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++}
++
++/* USB Battery Charger detection related functions */
++/* Data contact detection is the first step for charger detection */
++static int penwell_otg_data_contact_detect(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ u8 data;
++ int count = 50;
++ int retval = 0;
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++
++ /* Enable SPI access */
++ penwell_otg_msic_spi_access(true);
++
++ /* Set POWER_CTRL_CLR */
++ retval = penwell_otg_msic_write(MSIC_PWRCTRLCLR, DPVSRCEN);
++ if (retval)
++ return retval;
++
++ /* Set FUNC_CTRL_SET */
++ retval = penwell_otg_msic_write(MSIC_FUNCTRLSET, OPMODE0);
++ if (retval)
++ return retval;
++
++ /* Set FUNC_CTRL_CLR */
++ retval = penwell_otg_msic_write(MSIC_FUNCTRLCLR, OPMODE1);
++ if (retval)
++ return retval;
++
++ /* Set OTG_CTRL_CLR */
++ retval = penwell_otg_msic_write(MSIC_OTGCTRLCLR,
++ DMPULLDOWN | DPPULLDOWN);
++ if (retval)
++ return retval;
++
++ /* Set POWER_CTRL_CLR */
++ retval = penwell_otg_msic_write(MSIC_PWRCTRLCLR, SWCNTRL);
++ if (retval)
++ return retval;
++
++ retval = penwell_otg_msic_write(MSIC_VS3SET, DATACONEN | SWUSBDET);
++ if (retval)
++ return retval;
++
++ dev_dbg(pnw->dev, "Start Polling for Data contact detection!\n");
++
++ while (count) {
++ retval = intel_scu_ipc_ioread8(MSIC_USB_MISC, &data);
++ if (retval) {
++ dev_warn(pnw->dev, "Failed to read MSIC register\n");
++ return retval;
++ }
++
++ if (data & MISC_CHGDSERXDPINV) {
++ dev_dbg(pnw->dev, "Data contact detected!\n");
++ return 0;
++ }
++ count--;
++ /* Interval is 10 - 11ms */
++ usleep_range(10000, 11000);
++ }
++
++ dev_dbg(pnw->dev, "Data contact Timeout\n");
++
++ retval = penwell_otg_msic_write(MSIC_VS3CLR, DATACONEN | SWUSBDET);
++ if (retval)
++ return retval;
++
++ udelay(100);
++
++ retval = penwell_otg_msic_write(MSIC_VS3SET, SWUSBDET);
++ if (retval)
++ return retval;
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++ return 0;
++}
++
++static int penwell_otg_charger_detect(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++
++ msleep(125);
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++
++ return 0;
++}
++
++static int penwell_otg_charger_type_detect(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ enum usb_charger_type charger;
++ u8 data;
++ int retval;
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++
++ retval = penwell_otg_msic_write(MSIC_VS3CLR, DATACONEN);
++ if (retval)
++ return retval;
++
++ retval = penwell_otg_msic_write(MSIC_PWRCTRLSET, DPWKPUEN | SWCNTRL);
++ if (retval)
++ return retval;
++
++ retval = penwell_otg_msic_write(MSIC_PWRCTRLCLR, DPVSRCEN);
++ if (retval)
++ return retval;
++
++ retval = penwell_otg_msic_write(MSIC_OTGCTRLCLR,
++ DMPULLDOWN | DPPULLDOWN);
++ if (retval)
++ return retval;
++
++ msleep(55);
++
++ retval = penwell_otg_msic_write(MSIC_PWRCTRLCLR,
++ SWCNTRL | DPWKPUEN | HWDET);
++ if (retval)
++ return retval;
++
++ msleep(1);
++
++ /* Enable ULPI mode */
++ penwell_otg_msic_spi_access(false);
++
++ retval = intel_scu_ipc_ioread8(MSIC_SPWRSRINT1, &data);
++ if (retval) {
++ dev_warn(pnw->dev, "Failed to read MSIC register\n");
++ return retval;
++ }
++
++ switch (data & MSIC_SPWRSRINT1_MASK) {
++ case SPWRSRINT1_SDP:
++ charger = CHRG_SDP;
++ break;
++ case SPWRSRINT1_DCP:
++ charger = CHRG_DCP;
++ break;
++ case SPWRSRINT1_CDP:
++ charger = CHRG_CDP;
++ break;
++ default:
++ charger = CHRG_UNKNOWN;
++ break;
++ }
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++
++ return charger;
++}
++
++/* manual charger detection by ULPI access */
++static int penwell_otg_manual_chrg_det(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg;
++ int retval;
++ u8 data, data1, data2;
++ unsigned long timeout, interval;
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++
++ iotg = &pnw->iotg;
++
++ dev_info(pnw->dev, "USB charger detection start...\n");
++
++ /* WA for invalid (SE1) charger: add DCD & SE1 detection over SPI
++ * instead of ULPI interface to avoid any ulpi read/write failures
++ * with SE1 charger */
++ penwell_otg_msic_spi_access(true);
++
++ retval = penwell_otg_msic_write(MSIC_FUNCTRLCLR,
++ OPMODE1 | TERMSELECT | XCVRSELECT1);
++ if (retval) {
++ penwell_otg_msic_spi_access(false);
++ return retval;
++ }
++
++ retval = penwell_otg_msic_write(MSIC_FUNCTRLSET, OPMODE0 | XCVRSELECT0);
++ if (retval) {
++ penwell_otg_msic_spi_access(false);
++ return retval;
++ }
++
++ retval = penwell_otg_msic_write(MSIC_PWRCTRLSET, SWCNTRL);
++ if (retval) {
++ penwell_otg_msic_spi_access(false);
++ return retval;
++ }
++
++ retval = penwell_otg_msic_write(MSIC_VS3SET, CHGD_IDP_SRC);
++ if (retval) {
++ penwell_otg_msic_spi_access(false);
++ return retval;
++ }
++
++ dev_info(pnw->dev, "charger detection DCD start...\n");
++
++ /* Check DCD result, use same polling parameter */
++ timeout = jiffies + msecs_to_jiffies(DATACON_TIMEOUT);
++ interval = DATACON_INTERVAL * 1000; /* us */
++
++ dev_info(pnw->dev, "DCD started!\n");
++
++ /* Delay TIDP_SRC_ON + TCHGD_SERX_DEB */
++ usleep_range(66500, 67000);
++
++ while (!time_after(jiffies, timeout)) {
++ retval = penwell_otg_msic_read(MSIC_VS4, &data);
++ if (retval) {
++ penwell_otg_msic_spi_access(false);
++ return retval;
++ }
++ if (!(data & CHRG_SERX_DP)) {
++ dev_info(pnw->dev, "Data contact detected!\n");
++ break;
++ }
++
++ /* Polling interval */
++ usleep_range(interval, interval + 2000);
++ }
++
++ retval = penwell_otg_msic_write(MSIC_VS3CLR, CHGD_IDP_SRC);
++ if (retval) {
++ penwell_otg_msic_spi_access(false);
++ return retval;
++ }
++
++ dev_info(pnw->dev, "DCD complete\n");
++
++ /* Check for SE1, Linestate = '11' */
++ retval = penwell_otg_msic_read(MSIC_DEBUG, &data);
++ if (retval) {
++ penwell_otg_msic_spi_access(false);
++ return retval;
++ }
++ dev_info(pnw->dev, "MSIC.DEBUG.LINESTATE.D[1:0] = 0x%02X\n", data);
++
++ data &= LINESTATE_MSK;
++ if (data == LINESTATE_SE1) {
++ dev_info(pnw->dev, "SE1 Detected\n");
++ penwell_otg_msic_spi_access(false);
++ return CHRG_SE1;
++ }
++
++ penwell_otg_msic_spi_access(false);
++
++ dev_info(pnw->dev, "Primary Detection start...\n");
++
++ /* Primary Dection config */
++ /* ulpi_write(0x0b, 0x06) */
++ retval = penwell_otg_ulpi_write(iotg, ULPI_OTGCTRLSET,
++ DMPULLDOWN | DPPULLDOWN);
++ if (retval)
++ return retval;
++
++ retval = penwell_otg_ulpi_write(iotg, ULPI_PWRCTRLSET, DPVSRCEN);
++ if (retval)
++ return retval;
++
++ msleep(125);
++
++ /* Check result SDP vs CDP/DCP */
++ retval = penwell_otg_ulpi_read(iotg, ULPI_PWRCTRL, &data1);
++ if (retval)
++ return retval;
++
++ data1 = data1 & VDATDET;
++
++ retval = penwell_otg_ulpi_read(iotg, ULPI_VS4, &data2);
++ if (retval)
++ return retval;
++
++ data2 = data2 & CHRG_SERX_DM;
++
++ if (!data1 || data2) {
++ retval = penwell_otg_ulpi_write(iotg, ULPI_PWRCTRLCLR,
++ DPVSRCEN);
++ if (retval)
++ return retval;
++
++ dev_info(pnw->dev, "USB Charger Detection done\n");
++ return CHRG_SDP;
++ }
++
++ /* start detection on CDP vs DCP */
++ retval = penwell_otg_ulpi_write(iotg, ULPI_PWRCTRLCLR, DPVSRCEN);
++ if (retval)
++ return retval;
++
++ /* sleep 1ms between Primary and Secondary detection */
++ usleep_range(1000, 1200);
++
++ retval = penwell_otg_ulpi_write(iotg, ULPI_VS1CLR, DATAPOLARITY);
++ if (retval)
++ return retval;
++
++ retval = penwell_otg_ulpi_write(iotg, ULPI_PWRCTRLSET, DPVSRCEN);
++ if (retval)
++ return retval;
++
++ msleep(85);
++
++ /* read result on CDP vs DCP */
++ retval = penwell_otg_ulpi_read(iotg, ULPI_PWRCTRL, &data);
++ if (retval)
++ return retval;
++
++ data = data & VDATDET;
++
++ retval = penwell_otg_ulpi_write(iotg, ULPI_PWRCTRLCLR, DPVSRCEN);
++ if (retval)
++ return retval;
++
++ retval = penwell_otg_ulpi_write(iotg, ULPI_VS1SET, DATAPOLARITY);
++ if (retval)
++ return retval;
++
++ dev_info(pnw->dev, "USB Charger Detection done\n");
++
++ if (data) {
++ retval = penwell_otg_ulpi_write(iotg, ULPI_PWRCTRLSET,
++ DPVSRCEN);
++ if (retval)
++ return retval;
++
++ return CHRG_DCP;
++ } else
++ return CHRG_CDP;
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++};
++
++static int penwell_otg_charger_det_dcd_clt(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ int retval;
++ unsigned long timeout, interval;
++ u8 data;
++
++ /* Change OPMODE to '01' Non-driving */
++ retval = penwell_otg_ulpi_write(iotg, ULPI_FUNCTRLSET,
++ OPMODE0 | XCVRSELECT0);
++ if (retval)
++ return retval;
++
++ retval = penwell_otg_ulpi_write(iotg, ULPI_FUNCTRLCLR,
++ OPMODE1 | XCVRSELECT1 | TERMSELECT);
++ if (retval)
++ return retval;
++
++ /* Enable SW control */
++ retval = penwell_otg_ulpi_write(iotg, ULPI_PWRCTRLSET, SWCNTRL);
++ if (retval)
++ return retval;
++
++ /* Clear HWDETECT result for safety */
++ penwell_otg_charger_hwdet(false);
++
++ /* Enable IDPSRC */
++ retval = penwell_otg_ulpi_write(iotg, ULPI_VS3SET, CHGD_IDP_SRC);
++ if (retval)
++ return retval;
++
++ /* Check DCD result, use same polling parameter */
++ timeout = jiffies + msecs_to_jiffies(DATACON_TIMEOUT);
++ interval = DATACON_INTERVAL * 1000; /* us */
++
++ dev_info(pnw->dev, "DCD started\n");
++
++ /* Delay TIDP_SRC_ON + TCHGD_SERX_DEB = 347.8us + 66.1ms max */
++ usleep_range(66500, 67000);
++
++ while (!time_after(jiffies, timeout)) {
++ retval = penwell_otg_ulpi_read(iotg, ULPI_VS4, &data);
++ if (retval) {
++ dev_warn(pnw->dev, "Failed to read ULPI register\n");
++ return retval;
++ }
++
++ dev_dbg(pnw->dev, "VS4 = 0x%02x.. DP = bit1\n", data);
++
++ if (!(data & CHRG_SERX_DP)) {
++ dev_info(pnw->dev, "Data contact detected!\n");
++ break;
++ }
++
++ /* Polling interval */
++ usleep_range(interval, interval + 2000);
++ }
++
++ /* ulpi_write(0x87, 0x40)*/
++ retval = penwell_otg_ulpi_write(iotg, ULPI_VS3CLR, CHGD_IDP_SRC);
++ if (retval)
++ return retval;
++
++ dev_info(pnw->dev, "DCD complete\n");
++
++ return 0;
++}
++
++static int penwell_otg_charger_det_aca_clt(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ int retval;
++ u8 data;
++ u8 usb_vs2_sts = 0;
++ u8 usb_vs2_latch = 0;
++ u8 usb_vdat_det = 0;
++ u8 usb_vdm = 0;
++
++ retval = penwell_otg_ulpi_read(iotg, ULPI_VS2LATCH, &usb_vs2_latch);
++ dev_dbg(pnw->dev, "%s: usb_vs2_latch = 0x%x\n",
++ __func__, usb_vs2_latch);
++ if (retval) {
++ dev_warn(pnw->dev, "ULPI read failed, exit\n");
++ return retval;
++ }
++
++ retval = penwell_otg_ulpi_read(iotg, ULPI_VS2STS, &usb_vs2_sts);
++ dev_dbg(pnw->dev, "%s: usb_vs2_sts = 0x%x\n",
++ __func__, usb_vs2_sts);
++ if (retval) {
++ dev_warn(pnw->dev, "ULPI read failed, exit\n");
++ return retval;
++ }
++
++ if (usb_vs2_latch & IDRARBRC_MSK) {
++ switch (IDRARBRC_STS(usb_vs2_sts)) {
++ case IDRARBRC_A:
++ iotg->hsm.id = ID_ACA_A;
++ break;
++ case IDRARBRC_B:
++ iotg->hsm.id = ID_ACA_B;
++ dev_info(pnw->dev, "ACA-B detected\n");
++ break;
++ case IDRARBRC_C:
++ iotg->hsm.id = ID_ACA_C;
++ dev_info(pnw->dev, "ACA-C detected\n");
++ break;
++ default:
++ break;
++ }
++ }
++
++ if (iotg->hsm.id == ID_ACA_A) {
++ retval = penwell_otg_ulpi_write(iotg,
++ ULPI_PWRCTRLSET, DPVSRCEN);
++ if (retval)
++ return retval;
++
++ msleep(70);
++
++ retval = penwell_otg_ulpi_read(iotg, ULPI_PWRCTRL, &data);
++ usb_vdat_det = data & VDATDET;
++ if (retval) {
++ dev_warn(pnw->dev, "ULPI read failed, exit\n");
++ return retval;
++ }
++
++ retval = penwell_otg_ulpi_read(iotg, ULPI_VS4, &data);
++ usb_vdm = data & CHRG_SERX_DM;
++ if (retval) {
++ dev_warn(pnw->dev, "ULPI read failed, exit\n");
++ return retval;
++ }
++
++ retval = penwell_otg_ulpi_write(iotg,
++ ULPI_PWRCTRLCLR, DPVSRCEN);
++ if (retval)
++ return retval;
++
++ if (usb_vdat_det && !usb_vdm)
++ dev_info(pnw->dev, "ACA-Dock detected\n");
++ else if (!usb_vdat_det && usb_vdm)
++ dev_info(pnw->dev, "ACA-A detected\n");
++ }
++
++ if (iotg->hsm.id == ID_ACA_A || iotg->hsm.id == ID_ACA_B
++ || iotg->hsm.id == ID_ACA_C) {
++ return CHRG_ACA;
++ }
++
++ return 0;
++}
++
++static int penwell_otg_charger_det_se1_clt(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ int retval;
++ u8 data;
++
++ retval = penwell_otg_ulpi_read(iotg, ULPI_DEBUG, &data);
++ if (retval) {
++ dev_warn(pnw->dev, "ULPI read failed, exit\n");
++ return -EBUSY;
++ }
++
++ if ((data & CHRG_SERX_DP) && (data & CHRG_SERX_DM))
++ return CHRG_SE1;
++
++ return 0;
++}
++
++static int penwell_otg_charger_det_pri_clt(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ int retval;
++ u8 vdat_det, serx_dm;
++
++ retval = penwell_otg_ulpi_write(iotg, ULPI_PWRCTRLSET, DPVSRCEN);
++ if (retval)
++ return retval;
++
++ msleep(110);
++
++ retval = penwell_otg_ulpi_read(iotg, ULPI_PWRCTRL, &vdat_det);
++ if (retval) {
++ dev_warn(pnw->dev, "ULPI read failed, exit\n");
++ return -EBUSY;
++ }
++
++ retval = penwell_otg_ulpi_read(iotg, ULPI_VS4, &serx_dm);
++ if (retval) {
++ dev_warn(pnw->dev, "ULPI read failed, exit\n");
++ return -EBUSY;
++ }
++
++ retval = penwell_otg_ulpi_write(iotg, ULPI_PWRCTRLCLR, DPVSRCEN);
++ if (retval)
++ return retval;
++
++ vdat_det &= VDATDET;
++ serx_dm &= CHRG_SERX_DM;
++
++ if ((!vdat_det) || serx_dm)
++ return CHRG_SDP;
++
++ return 0;
++}
++
++static int penwell_otg_charger_det_sec_clt(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ int retval;
++ u8 vdat_det;
++
++ usleep_range(1000, 1500);
++
++ retval = penwell_otg_ulpi_write(iotg, ULPI_VS1CLR, DATAPOLARITY);
++ if (retval)
++ return retval;
++
++ retval = penwell_otg_ulpi_write(iotg, ULPI_PWRCTRLSET, DPVSRCEN);
++ if (retval)
++ return retval;
++
++ msleep(80);
++
++ retval = penwell_otg_ulpi_read(iotg, ULPI_PWRCTRL, &vdat_det);
++ if (retval) {
++ dev_warn(pnw->dev, "ULPI read failed, exit\n");
++ return retval;
++ }
++
++ retval = penwell_otg_ulpi_write(iotg, ULPI_PWRCTRLCLR, DPVSRCEN);
++ if (retval)
++ return retval;
++
++ retval = penwell_otg_ulpi_write(iotg, ULPI_VS1SET, DATAPOLARITY);
++ if (retval)
++ return retval;
++
++ vdat_det &= VDATDET;
++
++ if (vdat_det)
++ return CHRG_DCP;
++ else
++ return CHRG_CDP;
++
++ return 0;
++}
++
++static int penwell_otg_charger_det_clean_clt(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ int retval;
++
++ retval = penwell_otg_ulpi_write(iotg, ULPI_PWRCTRLSET,
++ DPVSRCEN | SWCNTRL);
++ if (retval)
++ return retval;
++
++ return 0;
++}
++
++/* As we use SW mode to do charger detection, need to notify HW
++ * the result SW get, charging port or not */
++static int penwell_otg_charger_hwdet(bool enable)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ int retval;
++
++ /* This is for CLV only */
++ if (!is_clovertrail(to_pci_dev(pnw->dev)))
++ return 0;
++
++ if (enable) {
++ retval = penwell_otg_ulpi_write(iotg, ULPI_PWRCTRLSET, HWDET);
++ if (retval)
++ return retval;
++ dev_dbg(pnw->dev, "set HWDETECT\n");
++ } else {
++ retval = penwell_otg_ulpi_write(iotg, ULPI_PWRCTRLCLR, HWDET);
++ if (retval)
++ return retval;
++ dev_dbg(pnw->dev, "clear HWDETECT\n");
++ }
++
++ return 0;
++}
++
++static int penwell_otg_charger_det_clt(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ int retval;
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++
++ /* DCD */
++ retval = penwell_otg_charger_det_dcd_clt();
++ if (retval) {
++ dev_warn(pnw->dev, "DCD failed, exit\n");
++ return retval;
++ }
++
++ /* ACA Detection */
++ retval = penwell_otg_charger_det_aca_clt();
++ if (retval < 0) {
++ dev_warn(pnw->dev, "ACA Det failed, exit\n");
++ return retval;
++ } else if (retval == CHRG_ACA) {
++ dev_info(pnw->dev, "ACA detected\n");
++ penwell_otg_charger_hwdet(true);
++ return CHRG_ACA;
++ }
++
++ /* SE1 Detection */
++ retval = penwell_otg_charger_det_se1_clt();
++ if (retval < 0) {
++ dev_warn(pnw->dev, "SE1 Det failed, exit\n");
++ return retval;
++ } else if (retval == CHRG_SE1) {
++ dev_info(pnw->dev, "SE1 detected\n");
++ penwell_otg_charger_hwdet(true);
++ return CHRG_SE1;
++ }
++
++ /* Pri Det */
++ retval = penwell_otg_charger_det_pri_clt();
++ if (retval < 0) {
++ dev_warn(pnw->dev, "Pri Det failed, exit\n");
++ return retval;
++ } else if (retval == CHRG_SDP) {
++ dev_info(pnw->dev, "SDP detected\n");
++ return CHRG_SDP;
++ }
++
++ /* Sec Det */
++ retval = penwell_otg_charger_det_sec_clt();
++ if (retval < 0) {
++ dev_warn(pnw->dev, "Sec Det failed, exit\n");
++ return retval;
++ } else if (retval == CHRG_CDP) {
++ dev_info(pnw->dev, "CDP detected\n");
++ penwell_otg_charger_hwdet(true);
++ return CHRG_CDP;
++ } else if (retval == CHRG_DCP) {
++ dev_info(pnw->dev, "DCP detected\n");
++ penwell_otg_charger_det_clean_clt();
++ penwell_otg_charger_hwdet(true);
++ return CHRG_DCP;
++ }
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++
++ return 0;
++}
++
++void penwell_otg_phy_vbus_wakeup(bool on)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ u8 flag = 0;
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++
++ penwell_otg_msic_spi_access(true);
++
++ flag = VBUSVLD | SESSVLD | SESSEND;
++
++ if (is_clovertrail(to_pci_dev(pnw->dev))) {
++ if (on) {
++ penwell_otg_ulpi_write(iotg, ULPI_USBINTEN_RISINGSET,
++ flag);
++ penwell_otg_ulpi_write(iotg, ULPI_USBINTEN_FALLINGSET,
++ flag);
++ } else {
++ penwell_otg_ulpi_write(iotg, ULPI_USBINTEN_RISINGCLR,
++ flag);
++ penwell_otg_ulpi_write(iotg, ULPI_USBINTEN_FALLINGCLR,
++ flag);
++ }
++ } else {
++ if (on) {
++ penwell_otg_msic_write(MSIC_USBINTEN_RISESET, flag);
++ penwell_otg_msic_write(MSIC_USBINTEN_FALLSET, flag);
++ } else {
++ penwell_otg_msic_write(MSIC_USBINTEN_RISECLR, flag);
++ penwell_otg_msic_write(MSIC_USBINTEN_FALLCLR, flag);
++ }
++ }
++
++ penwell_otg_msic_spi_access(false);
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++}
++
++void penwell_otg_phy_intr(bool on)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ u8 flag = 0;
++ int retval;
++ u8 data;
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++
++ penwell_otg_msic_spi_access(true);
++
++ flag = VBUSVLD | IDGND;
++
++ if (on) {
++ dev_info(pnw->dev, "enable VBUSVLD & IDGND\n");
++ penwell_otg_msic_write(MSIC_USBINTEN_RISESET, flag);
++ penwell_otg_msic_write(MSIC_USBINTEN_FALLSET, flag);
++ } else {
++ dev_info(pnw->dev, "disable VBUSVLD & IDGND\n");
++ penwell_otg_msic_write(MSIC_USBINTEN_RISECLR, flag);
++ penwell_otg_msic_write(MSIC_USBINTEN_FALLCLR, flag);
++ }
++
++ retval = intel_scu_ipc_ioread8(MSIC_USBINTEN_RISE, &data);
++ if (retval)
++ dev_warn(pnw->dev, "Failed to read MSIC register\n");
++ else
++ dev_info(pnw->dev, "MSIC_USBINTEN_RISE = 0x%x", data);
++
++ retval = intel_scu_ipc_ioread8(MSIC_USBINTEN_FALL, &data);
++ if (retval)
++ dev_warn(pnw->dev, "Failed to read MSIC register\n");
++ else
++ dev_info(pnw->dev, "MSIC_USBINTEN_FALL = 0x%x", data);
++
++ penwell_otg_msic_spi_access(false);
++}
++
++void penwell_otg_phy_power(int on)
++{
++ struct penwell_otg *pnw = the_transceiver;
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++
++ if (is_clovertrail(to_pci_dev(pnw->dev))) {
++ dev_dbg(pnw->dev, "turn %s USB PHY by gpio_cs(%d)\n",
++ on ? "on" : "off",
++ pnw->otg_pdata->gpio_cs);
++ gpio_direction_output(pnw->otg_pdata->gpio_cs, on);
++ }
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++}
++
++void penwell_otg_phy_reset(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++
++ if (is_clovertrail(to_pci_dev(pnw->dev))) {
++ gpio_direction_output(pnw->otg_pdata->gpio_reset, 0);
++ usleep_range(200, 500);
++ gpio_set_value(pnw->otg_pdata->gpio_reset, 1);
++ }
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++}
++
++#if 0
++knext_wa: usb_notify_warning should be implemented again instead of in hub.c
++static void penwell_otg_notify_warning(int warning_code)
++{
++ struct penwell_otg *pnw = the_transceiver;
++
++ dev_dbg(pnw->dev, "%s ---> %d\n", __func__, warning_code);
++
++ if (pnw && pnw->iotg.otg.otg->host && pnw->iotg.otg.otg->host->root_hub)
++ usb_notify_warning(pnw->iotg.otg.otg->host->root_hub,
++ warning_code);
++ else
++ dev_dbg(pnw->dev, "no valid device for notification\n");
++
++ dev_dbg(pnw->dev, "%s <--- %d\n", __func__, warning_code);
++}
++#else
++#define penwell_otg_notify_warning(x)
++#endif
++
++void penwell_otg_nsf_msg(unsigned long indicator)
++{
++ switch (indicator) {
++ case 2:
++ case 4:
++ case 6:
++ case 7:
++ dev_warn(the_transceiver->dev,
++ "NSF-%lu - device not responding\n", indicator);
++ break;
++ case 3:
++ dev_warn(the_transceiver->dev,
++ "NSF-%lu - device not supported\n", indicator);
++ break;
++ default:
++ dev_warn(the_transceiver->dev,
++ "Do not have this kind of NSF\n");
++ break;
++ }
++}
++
++/* The timeout callback function to set time out bit */
++static void penwell_otg_timer_fn(unsigned long indicator)
++{
++ struct penwell_otg *pnw = the_transceiver;
++
++ *(int *)indicator = 1;
++
++ dev_dbg(pnw->dev, "kernel timer - timeout\n");
++
++ penwell_update_transceiver();
++}
++
++/* kernel timer used for OTG timing */
++static void penwell_otg_add_timer(enum penwell_otg_timer_type timers)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ unsigned long j = jiffies;
++ unsigned long data, time;
++
++ if (timer_pending(&pnw->hsm_timer))
++ return;
++
++ switch (timers) {
++ case TA_WAIT_VRISE_TMR:
++ iotg->hsm.a_wait_vrise_tmout = 0;
++ data = (unsigned long)&iotg->hsm.a_wait_vrise_tmout;
++ /* Charger HW limitation workaround for CLV */
++ time = is_clovertrail(to_pci_dev(pnw->dev)) ?
++ 400 : TA_WAIT_VRISE;
++ dev_dbg(pnw->dev,
++ "Add timer TA_WAIT_VRISE = %lu\n", time);
++ break;
++ case TA_WAIT_BCON_TMR:
++ iotg->hsm.a_wait_bcon_tmout = 0;
++ data = (unsigned long)&iotg->hsm.a_wait_bcon_tmout;
++ time = TA_WAIT_BCON;
++ dev_dbg(pnw->dev,
++ "Add timer TA_WAIT_BCON = %d\n", TA_WAIT_BCON);
++ break;
++ case TA_AIDL_BDIS_TMR:
++ iotg->hsm.a_aidl_bdis_tmout = 0;
++ data = (unsigned long)&iotg->hsm.a_aidl_bdis_tmout;
++ time = TA_AIDL_BDIS;
++ dev_dbg(pnw->dev,
++ "Add timer TA_AIDL_BDIS = %d\n", TA_AIDL_BDIS);
++ break;
++ case TA_BIDL_ADIS_TMR:
++ iotg->hsm.a_bidl_adis_tmout = 0;
++ iotg->hsm.a_bidl_adis_tmr = 1;
++ data = (unsigned long)&iotg->hsm.a_bidl_adis_tmout;
++ time = TA_BIDL_ADIS;
++ dev_dbg(pnw->dev,
++ "Add timer TA_BIDL_ADIS = %d\n", TA_BIDL_ADIS);
++ break;
++ case TA_WAIT_VFALL_TMR:
++ iotg->hsm.a_wait_vfall_tmout = 0;
++ data = (unsigned long)&iotg->hsm.a_wait_vfall_tmout;
++ time = TA_WAIT_VFALL;
++ dev_dbg(pnw->dev,
++ "Add timer TA_WAIT_VFALL = %d\n", TA_WAIT_VFALL);
++ break;
++ case TB_ASE0_BRST_TMR:
++ iotg->hsm.b_ase0_brst_tmout = 0;
++ data = (unsigned long)&iotg->hsm.b_ase0_brst_tmout;
++ time = TB_ASE0_BRST;
++ dev_dbg(pnw->dev,
++ "Add timer TB_ASE0_BRST = %d\n", TB_ASE0_BRST);
++ break;
++ case TB_SRP_FAIL_TMR:
++ iotg->hsm.b_srp_fail_tmout = 0;
++ iotg->hsm.b_srp_fail_tmr = 1;
++ data = (unsigned long)&iotg->hsm.b_srp_fail_tmout;
++ time = TB_SRP_FAIL;
++ dev_dbg(pnw->dev,
++ "Add timer TB_SRP_FAIL = %d\n", TB_SRP_FAIL);
++ break;
++ /* support OTG test mode */
++ case TTST_MAINT_TMR:
++ iotg->hsm.tst_maint_tmout = 0;
++ data = (unsigned long)&iotg->hsm.tst_maint_tmout;
++ time = TTST_MAINT;
++ dev_dbg(pnw->dev,
++ "Add timer TTST_MAINT = %d\n", TTST_MAINT);
++ break;
++ case TTST_NOADP_TMR:
++ iotg->hsm.tst_noadp_tmout = 0;
++ data = (unsigned long)&iotg->hsm.tst_noadp_tmout;
++ time = TTST_NOADP;
++ dev_dbg(pnw->dev,
++ "Add timer TTST_NOADP = %d\n", TTST_NOADP);
++ break;
++ default:
++ dev_dbg(pnw->dev,
++ "unkown timer, can not enable such timer\n");
++ return;
++ }
++
++ pnw->hsm_timer.data = data;
++ pnw->hsm_timer.function = penwell_otg_timer_fn;
++ pnw->hsm_timer.expires = j + time * HZ / 1000; /* milliseconds */
++
++ add_timer(&pnw->hsm_timer);
++}
++
++static inline void penwell_otg_del_timer(enum penwell_otg_timer_type timers)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++
++ switch (timers) {
++ case TA_BIDL_ADIS_TMR:
++ iotg->hsm.a_bidl_adis_tmr = 0;
++ break;
++ case TB_SRP_FAIL_TMR:
++ iotg->hsm.b_srp_fail_tmr = 0;
++ break;
++ case TA_WAIT_BCON_TMR:
++ iotg->hsm.a_wait_bcon_tmout = 0;
++ break;
++ case TTST_MAINT_TMR:
++ iotg->hsm.tst_maint_tmout = 0;
++ break;
++ case TTST_NOADP_TMR:
++ iotg->hsm.tst_noadp_tmout = 0;
++ break;
++ default:
++ break;
++ }
++
++ dev_dbg(pnw->dev, "state machine timer deleted\n");
++ del_timer_sync(&pnw->hsm_timer);
++}
++
++static void reset_otg(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ u32 val;
++ int delay_time = 1000;
++
++ dev_dbg(pnw->dev, "reseting OTG controller ...\n");
++ val = readl(pnw->iotg.base + CI_USBCMD);
++ writel(val | USBCMD_RST, pnw->iotg.base + CI_USBCMD);
++ do {
++ udelay(100);
++ if (!delay_time--)
++ dev_dbg(pnw->dev, "reset timeout\n");
++ val = readl(pnw->iotg.base + CI_USBCMD);
++ val &= USBCMD_RST;
++ } while (val != 0);
++ dev_dbg(pnw->dev, "reset done.\n");
++}
++
++static void pnw_phy_ctrl_rst(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct pci_dev *pdev;
++
++ pdev = to_pci_dev(pnw->dev);
++
++ /* mask id intr before reset and delay for 4 ms
++ * before unmasking id intr to avoid wrongly
++ * detecting ID_A which is a side-effect of reset
++ * PHY
++ */
++ penwell_otg_intr(0);
++ synchronize_irq(pdev->irq);
++
++ penwell_otg_phy_reset();
++
++ reset_otg();
++
++ msleep(50);
++ penwell_otg_intr(1);
++
++ /* after reset, need to sync to OTGSC status bits to hsm */
++ update_hsm();
++ penwell_update_transceiver();
++}
++
++static void set_host_mode(void)
++{
++ u32 val;
++
++ reset_otg();
++ val = readl(the_transceiver->iotg.base + CI_USBMODE);
++ val = (val & (~USBMODE_CM)) | USBMODE_HOST;
++ writel(val, the_transceiver->iotg.base + CI_USBMODE);
++}
++
++static void set_client_mode(void)
++{
++ u32 val;
++
++ reset_otg();
++ val = readl(the_transceiver->iotg.base + CI_USBMODE);
++ val = (val & (~USBMODE_CM)) | USBMODE_DEVICE;
++ writel(val, the_transceiver->iotg.base + CI_USBMODE);
++}
++
++static void init_hsm(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ u32 val32;
++
++ /* read OTGSC after reset */
++ val32 = readl(iotg->base + CI_OTGSC);
++ dev_dbg(pnw->dev,
++ "%s: OTGSC init value = 0x%x\n", __func__, val32);
++
++ /* set init state */
++ if (val32 & OTGSC_ID) {
++ iotg->hsm.id = ID_B;
++ iotg->otg.otg->default_a = 0;
++ set_client_mode();
++ iotg->otg.state = OTG_STATE_B_IDLE;
++ } else {
++ iotg->hsm.id = ID_A;
++ iotg->otg.otg->default_a = 1;
++ set_host_mode();
++ iotg->otg.state = OTG_STATE_A_IDLE;
++ }
++
++ /* set session indicator */
++ if (val32 & OTGSC_BSE)
++ iotg->hsm.b_sess_end = 1;
++ if (val32 & OTGSC_BSV)
++ iotg->hsm.b_sess_vld = 1;
++ if (val32 & OTGSC_ASV)
++ iotg->hsm.a_sess_vld = 1;
++ if (val32 & OTGSC_AVV)
++ iotg->hsm.a_vbus_vld = 1;
++
++ /* default user is not request the bus */
++ iotg->hsm.a_bus_req = 1;
++ iotg->hsm.a_bus_drop = 0;
++ /* init hsm means power_up case */
++ iotg->hsm.power_up = 0;
++ /* defautly don't request bus as B device */
++ iotg->hsm.b_bus_req = 0;
++ /* no system error */
++ iotg->hsm.a_clr_err = 0;
++
++ if (iotg->otg.state == OTG_STATE_A_IDLE) {
++ wake_lock(&pnw->wake_lock);
++ pm_runtime_get(pnw->dev);
++ }
++}
++
++static void update_hsm(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ u32 val32;
++
++ /* read OTGSC */
++ val32 = readl(iotg->base + CI_OTGSC);
++ dev_dbg(pnw->dev,
++ "%s OTGSC current value = 0x%x\n", __func__, val32);
++
++ iotg->hsm.id = !!(val32 & OTGSC_ID) ? ID_B : ID_A;
++ iotg->hsm.b_sess_end = !!(val32 & OTGSC_BSE);
++ iotg->hsm.b_sess_vld = !!(val32 & OTGSC_BSV);
++ iotg->hsm.a_sess_vld = !!(val32 & OTGSC_ASV);
++ iotg->hsm.a_vbus_vld = !!(val32 & OTGSC_AVV);
++}
++
++static void penwell_otg_eye_diagram_optimize(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ int retval;
++ u8 value = 0;
++
++ /* Check platform value as different value will be used*/
++ if (is_clovertrail(to_pci_dev(pnw->dev))) {
++ /* Set 0x7f for better quality in eye diagram
++ * It means ZHSDRV = 0b11 and IHSTX = 0b1111*/
++ value = 0x7f;
++ } else {
++ /* Set 0x77 for better quality in eye diagram
++ * It means ZHSDRV = 0b11 and IHSTX = 0b0111*/
++ value = 0x77;
++ }
++
++ retval = penwell_otg_ulpi_write(iotg, ULPI_VS1SET, value);
++ if (retval)
++ dev_warn(pnw->dev,
++ "eye diagram optimize failed with ulpi failure\n");
++}
++
++static irqreturn_t otg_dummy_irq(int irq, void *_dev)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ void __iomem *reg_base = _dev;
++ u32 val;
++ u32 int_mask = 0;
++
++ val = readl(reg_base + CI_USBMODE);
++ if ((val & USBMODE_CM) != USBMODE_DEVICE)
++ return IRQ_NONE;
++
++ val = readl(reg_base + CI_USBSTS);
++ int_mask = val & INTR_DUMMY_MASK;
++
++ if (int_mask == 0)
++ return IRQ_NONE;
++
++ /* clear hsm.b_conn here since host driver can't detect it
++ * otg_dummy_irq called means B-disconnect happened.
++ */
++ if (pnw->iotg.hsm.b_conn) {
++ pnw->iotg.hsm.b_conn = 0;
++ penwell_update_transceiver();
++ }
++
++ /* Clear interrupts */
++ writel(int_mask, reg_base + CI_USBSTS);
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t otg_irq_handle(struct penwell_otg *pnw,
++ struct intel_mid_otg_xceiv *iotg)
++{
++ int id = 0;
++ int flag = 0;
++ u32 int_sts, int_en, int_mask = 0;
++ u8 usb_vs2_latch = 0;
++ u8 usb_vs2_sts = 0;
++ struct iotg_ulpi_access_ops *ops;
++
++ /* Check VBUS/SRP interrup */
++ int_sts = readl(pnw->iotg.base + CI_OTGSC);
++ int_en = (int_sts & OTGSC_INTEN_MASK) >> 8;
++ int_mask = int_sts & int_en;
++
++ if (int_mask == 0)
++ return IRQ_NONE;
++
++ ops = &iotg->ulpi_ops;
++ ops->read(iotg, ULPI_VS2LATCH, &usb_vs2_latch);
++ dev_dbg(pnw->dev, "usb_vs2_latch = 0x%x\n", usb_vs2_latch);
++ if (usb_vs2_latch & IDRARBRC_MSK) {
++ ops->read(iotg, ULPI_VS2STS, &usb_vs2_sts);
++ dev_dbg(pnw->dev, "%s: usb_vs2_sts = 0x%x\n",
++ __func__, usb_vs2_sts);
++
++ switch (IDRARBRC_STS(usb_vs2_sts)) {
++ case IDRARBRC_A:
++ id = ID_ACA_A;
++ dev_dbg(pnw->dev, "ACA-A interrupt detected\n");
++ break;
++ case IDRARBRC_B:
++ id = ID_ACA_B;
++ dev_dbg(pnw->dev, "ACA-B interrupt detected\n");
++ break;
++ case IDRARBRC_C:
++ id = ID_ACA_C;
++ dev_dbg(pnw->dev, "ACA-C interrupt detected\n");
++ break;
++ default:
++ break;
++ }
++
++ if (id) {
++ iotg->hsm.id = id;
++ flag = 1;
++ dev_dbg(pnw->dev, "%s: id change int = %d\n",
++ __func__, iotg->hsm.id);
++ } else {
++ iotg->hsm.id = (int_sts & OTGSC_ID) ?
++ ID_B : ID_A;
++ flag = 1;
++ dev_dbg(pnw->dev, "%s: id change int = %d\n",
++ __func__, iotg->hsm.id);
++ }
++ }
++
++ if (int_mask) {
++ dev_dbg(pnw->dev,
++ "OTGSC = 0x%x, mask =0x%x\n", int_sts, int_mask);
++
++ if (int_mask & OTGSC_IDIS) {
++ if (!id)
++ iotg->hsm.id = (int_sts & OTGSC_ID) ?
++ ID_B : ID_A;
++ flag = 1;
++ dev_dbg(pnw->dev, "%s: id change int = %d\n",
++ __func__, iotg->hsm.id);
++
++ /* Update a_vbus_valid once ID changed */
++ iotg->hsm.a_vbus_vld = (int_sts & OTGSC_AVV) ? 1 : 0;
++ }
++ if (int_mask & OTGSC_DPIS) {
++ iotg->hsm.a_srp_det = (int_sts & OTGSC_DPS) ? 1 : 0;
++ flag = 1;
++ dev_dbg(pnw->dev, "%s: data pulse int = %d\n",
++ __func__, iotg->hsm.a_srp_det);
++ }
++ if (int_mask & OTGSC_BSEIS) {
++ iotg->hsm.b_sess_end = (int_sts & OTGSC_BSE) ? 1 : 0;
++ flag = 1;
++ dev_dbg(pnw->dev, "%s: b sess end int = %d\n",
++ __func__, iotg->hsm.b_sess_end);
++ }
++ if (int_mask & OTGSC_BSVIS) {
++ iotg->hsm.b_sess_vld = (int_sts & OTGSC_BSV) ? 1 : 0;
++ flag = 1;
++ dev_dbg(pnw->dev, "%s: b sess valid int = %d\n",
++ __func__, iotg->hsm.b_sess_vld);
++ }
++ if (int_mask & OTGSC_ASVIS) {
++ iotg->hsm.a_sess_vld = (int_sts & OTGSC_ASV) ? 1 : 0;
++ flag = 1;
++ dev_dbg(pnw->dev, "%s: a sess valid int = %d\n",
++ __func__, iotg->hsm.a_sess_vld);
++ }
++ if (int_mask & OTGSC_AVVIS) {
++ iotg->hsm.a_vbus_vld = (int_sts & OTGSC_AVV) ? 1 : 0;
++ flag = 1;
++ dev_dbg(pnw->dev, "%s: a vbus valid int = %d\n",
++ __func__, iotg->hsm.a_vbus_vld);
++ }
++
++ writel((int_sts & ~OTGSC_INTSTS_MASK) | int_mask,
++ pnw->iotg.base + CI_OTGSC);
++ }
++
++ if (flag)
++ penwell_update_transceiver();
++
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t otg_irq(int irq, void *_dev)
++{
++ struct penwell_otg *pnw = _dev;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ unsigned long flags;
++
++#ifdef CONFIG_PM_RUNTIME
++ if (pnw->rt_resuming)
++ return IRQ_HANDLED;
++
++ /* If it's not active, resume device first before access regs */
++ if (pnw->rt_quiesce) {
++ spin_lock_irqsave(&pnw->lock, flags);
++ if (pnw->rt_quiesce) {
++ dev_dbg(pnw->dev, "Wake up? Interrupt detected in suspended\n");
++ pnw->rt_resuming = 1;
++ pm_runtime_get(pnw->dev);
++ }
++ spin_unlock_irqrestore(&pnw->lock, flags);
++
++ return IRQ_HANDLED;
++ }
++#endif /* CONFIG_PM_RUNTIME */
++
++ return otg_irq_handle(pnw, iotg);
++}
++
++static void penwell_otg_start_ulpi_poll(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ int retval = 0;
++
++ retval = penwell_otg_ulpi_write(&pnw->iotg, 0x16, 0x5a);
++ if (retval)
++ dev_err(pnw->dev, "ulpi write in init failed\n");
++
++ schedule_delayed_work(&pnw->ulpi_poll_work, HZ);
++}
++
++static void penwell_otg_continue_ulpi_poll(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++
++ schedule_delayed_work(&pnw->ulpi_poll_work, HZ);
++}
++
++static void penwell_otg_stop_ulpi_poll(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++
++ /* we have to use this version because this function can
++ * be called in irq handler */
++ __cancel_delayed_work(&pnw->ulpi_poll_work);
++}
++
++
++static int penwell_otg_iotg_notify(struct notifier_block *nb,
++ unsigned long action, void *data)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = data;
++ int flag = 0;
++ struct pci_dev *pdev;
++
++ if (iotg == NULL)
++ return NOTIFY_BAD;
++
++ if (pnw == NULL)
++ return NOTIFY_BAD;
++
++ pdev = to_pci_dev(pnw->dev);
++
++ switch (action) {
++ case MID_OTG_NOTIFY_CONNECT:
++ dev_dbg(pnw->dev, "PNW OTG Notify Connect Event\n");
++ if (iotg->otg.otg->default_a == 1)
++ iotg->hsm.b_conn = 1;
++ else
++ iotg->hsm.a_conn = 1;
++ flag = 1;
++ break;
++ case MID_OTG_NOTIFY_DISCONN:
++ dev_dbg(pnw->dev, "PNW OTG Notify Disconnect Event\n");
++ if (iotg->otg.otg->default_a == 1)
++ iotg->hsm.b_conn = 0;
++ else
++ iotg->hsm.a_conn = 0;
++ flag = 1;
++ break;
++ case MID_OTG_NOTIFY_HSUSPEND:
++ dev_dbg(pnw->dev, "PNW OTG Notify Host Bus suspend Event\n");
++ break;
++ case MID_OTG_NOTIFY_HRESUME:
++ dev_dbg(pnw->dev, "PNW OTG Notify Host Bus resume Event\n");
++ if (iotg->otg.otg->default_a == 1 && iotg->hsm.a_bus_req == 0) {
++ iotg->hsm.a_bus_req = 1;
++ flag = 1;
++ }
++ break;
++ case MID_OTG_NOTIFY_CSUSPEND:
++ dev_dbg(pnw->dev, "PNW OTG Notify Client Bus suspend Event\n");
++ if (iotg->otg.otg->default_a == 1) {
++ iotg->hsm.b_bus_suspend = 1;
++ flag = 1;
++ } else {
++ penwell_otg_stop_ulpi_poll();
++ if (iotg->hsm.a_bus_suspend == 0) {
++ iotg->hsm.a_bus_suspend = 1;
++ flag = 1;
++ } else
++ flag = 0;
++ }
++ break;
++ case MID_OTG_NOTIFY_CRESUME:
++ dev_dbg(pnw->dev, "PNW OTG Notify Client Bus resume Event\n");
++ if (iotg->otg.otg->default_a == 1) {
++ /* in A_PERIPHERAL state */
++ iotg->hsm.b_bus_suspend = 0;
++ flag = 1;
++ } else {
++ /* in B_PERIPHERAL state */
++ if (!is_clovertrail(pdev))
++ penwell_otg_start_ulpi_poll();
++ iotg->hsm.a_bus_suspend = 0;
++ flag = 0;
++ }
++ break;
++ case MID_OTG_NOTIFY_CRESET:
++ dev_dbg(pnw->dev, "PNW OTG Notify Client Bus reset Event\n");
++ penwell_otg_set_power(&pnw->iotg.otg, CHRG_CURR_SDP_SUSP);
++ flag = 0;
++ break;
++ case MID_OTG_NOTIFY_HOSTADD:
++ dev_dbg(pnw->dev, "PNW OTG Nofity Host Driver Add\n");
++ flag = 1;
++ break;
++ case MID_OTG_NOTIFY_HOSTREMOVE:
++ dev_dbg(pnw->dev, "PNW OTG Nofity Host Driver remove\n");
++ flag = 1;
++ break;
++ case MID_OTG_NOTIFY_CLIENTADD:
++ dev_dbg(pnw->dev, "PNW OTG Nofity Client Driver Add\n");
++ flag = 1;
++ break;
++ case MID_OTG_NOTIFY_CLIENTREMOVE:
++ dev_dbg(pnw->dev, "PNW OTG Nofity Client Driver remove\n");
++ flag = 1;
++ break;
++ /* Test mode support */
++ case MID_OTG_NOTIFY_TEST_MODE_START:
++ dev_dbg(pnw->dev, "PNW OTG Notfiy Client Testmode Start\n");
++ iotg->hsm.in_test_mode = 1;
++ flag = 0;
++ break;
++ case MID_OTG_NOTIFY_TEST_MODE_STOP:
++ dev_dbg(pnw->dev, "PNW OTG Notfiy Client Testmode Stop\n");
++ iotg->hsm.in_test_mode = 0;
++ flag = 0;
++ break;
++ case MID_OTG_NOTIFY_TEST_SRP_REQD:
++ dev_dbg(pnw->dev, "PNW OTG Notfiy Client SRP REQD\n");
++ iotg->hsm.otg_srp_reqd = 1;
++ flag = 1;
++ break;
++ case MID_OTG_NOTIFY_TEST:
++ dev_dbg(pnw->dev, "PNW OTG Notfiy Test device detected\n");
++ iotg->hsm.test_device = 1;
++ flag = 0;
++ break;
++ case MID_OTG_NOTIFY_TEST_VBUS_OFF:
++ dev_dbg(pnw->dev, "PNW OTG Notfiy Test device Vbus off mode\n");
++ iotg->hsm.test_device = 1;
++ iotg->hsm.otg_vbus_off = 1;
++ flag = 1;
++ break;
++ default:
++ dev_dbg(pnw->dev, "PNW OTG Nofity unknown notify message\n");
++ return NOTIFY_DONE;
++ }
++
++ if (flag)
++ penwell_update_transceiver();
++
++ return NOTIFY_OK;
++}
++
++static void penwell_otg_hnp_poll_work(struct work_struct *work)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ struct usb_device *udev;
++ int err = 0;
++ u8 data;
++
++ if (iotg->otg.otg->host && iotg->otg.otg->host->root_hub) {
++ udev = usb_hub_find_child(iotg->otg.otg->host->root_hub, 1);
++ } else {
++ dev_warn(pnw->dev, "no host or root_hub registered\n");
++ return;
++ }
++
++ if (iotg->otg.state != OTG_STATE_A_HOST
++ && iotg->otg.state != OTG_STATE_B_HOST)
++ return;
++
++ if (!udev) {
++ dev_warn(pnw->dev,
++ "no usb dev connected, stop HNP polling\n");
++ return;
++ }
++
++ /* Skip HS Electrical Test Device */
++ if (le16_to_cpu(udev->descriptor.idVendor) == 0x1A0A &&
++ le16_to_cpu(udev->descriptor.idProduct) > 0x0100 &&
++ le16_to_cpu(udev->descriptor.idProduct) < 0x0109) {
++ return;
++ }
++
++ /* get host request flag from connected USB device */
++ err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
++ USB_REQ_GET_STATUS, USB_DIR_IN, 0, 0xF000, &data, 1, 5000);
++
++ if (err < 0) {
++ dev_warn(pnw->dev,
++ "ERR in HNP polling = %d, stop HNP polling\n", err);
++ return;
++ }
++
++ if (data & HOST_REQUEST_FLAG) {
++ /* start HNP sequence to switch role */
++ dev_dbg(pnw->dev, "host_request_flag = 1\n");
++
++ if (iotg->hsm.id == ID_B) {
++ dev_dbg(pnw->dev,
++ "Device B host - start HNP - b_bus_req = 0\n");
++ iotg->hsm.b_bus_req = 0;
++ } else if (iotg->hsm.id == ID_A) {
++ dev_dbg(pnw->dev,
++ "Device A host - start HNP - a_bus_req = 0\n");
++ iotg->hsm.a_bus_req = 0;
++ }
++ penwell_update_transceiver();
++ } else {
++ dev_dbg(pnw->dev, "host_request_flag = 0\n");
++ penwell_otg_continue_hnp_poll(&pnw->iotg);
++ }
++}
++
++static int penwell_otg_ulpi_check(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ u8 data;
++ int retval;
++
++ retval = penwell_otg_ulpi_read(iotg, 0x16, &data);
++ if (retval) {
++ dev_err(pnw->dev,
++ "%s: [ ULPI hang ] detected\n"
++ "reset PHY & ctrl to recover\n",
++ __func__);
++ pnw_phy_ctrl_rst();
++ return retval;
++ }
++ return 0;
++}
++
++static void penwell_otg_ulpi_check_work(struct work_struct *work)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ int status;
++
++ status = pm_runtime_get_sync(pnw->dev);
++ if (status < 0) {
++ dev_err(pnw->dev, "%s: pm_runtime_get_sync FAILED err = %d\n",
++ __func__, status);
++ pm_runtime_put_sync(pnw->dev);
++ return;
++ }
++
++ if (iotg->otg.state == OTG_STATE_B_IDLE) {
++ /* Before charger detection or charger detection done */
++ dev_dbg(pnw->dev, "ulpi_check health\n");
++ penwell_otg_ulpi_check();
++ } else if (iotg->otg.state == OTG_STATE_B_PERIPHERAL) {
++ /* After charger detection, SDP/CDP is detected */
++ dev_dbg(pnw->dev, "ulpi_check health\n");
++ status = penwell_otg_ulpi_check();
++ if (status) {
++ /* After phy rst then restart peripheral stack */
++ if (iotg->stop_peripheral)
++ iotg->stop_peripheral(iotg);
++ else
++ dev_dbg(pnw->dev,
++ "client driver not support\n");
++
++ if (iotg->start_peripheral)
++ iotg->start_peripheral(iotg);
++ else
++ dev_dbg(pnw->dev,
++ "client driver not support\n");
++ }
++ }
++
++ pm_runtime_put(pnw->dev);
++}
++
++static void penwell_otg_uevent_work(struct work_struct *work)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ char *uevent_envp[2] = { "USB_INTR=BOGUS", NULL };
++
++ dev_info(pnw->dev, "%s: send uevent USB_INTR=BOGUS\n", __func__);
++ kobject_uevent_env(&pnw->dev->kobj, KOBJ_CHANGE, uevent_envp);
++}
++
++static void penwell_otg_ulpi_poll_work(struct work_struct *work)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ u8 data;
++
++ if (iotg->otg.state != OTG_STATE_B_PERIPHERAL)
++ return;
++
++ if (iotg->hsm.in_test_mode)
++ return;
++
++ if (penwell_otg_ulpi_read(iotg, 0x16, &data)) {
++ dev_err(pnw->dev, "ulpi read time out by polling\n");
++ iotg->hsm.ulpi_error = 1;
++ iotg->hsm.ulpi_polling = 0;
++ penwell_update_transceiver();
++ } else if (data != 0x5A) {
++ dev_err(pnw->dev, "ulpi read value incorrect by polling\n");
++ iotg->hsm.ulpi_error = 1;
++ iotg->hsm.ulpi_polling = 0;
++ penwell_update_transceiver();
++ } else {
++ dev_dbg(pnw->dev, "ulpi fine by polling\n");
++ iotg->hsm.ulpi_error = 0;
++ iotg->hsm.ulpi_polling = 1;
++ penwell_otg_continue_ulpi_poll();
++ }
++}
++
++static void penwell_otg_psc_notify_work(struct work_struct *work)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ struct power_supply_cable_props psc_cap;
++ enum power_supply_charger_event chrg_event;
++ unsigned long flags;
++ struct otg_bc_event *event, *temp;
++
++ spin_lock_irqsave(&pnw->charger_lock, flags);
++ list_for_each_entry_safe(event, temp, &pnw->chrg_evt_queue, node) {
++ list_del(&event->node);
++ spin_unlock_irqrestore(&pnw->charger_lock, flags);
++
++ spin_lock_irqsave(&pnw->cap_lock, flags);
++ chrg_event = check_psc_event(pnw->psc_cap, event->cap);
++ if (chrg_event == -1)
++ dev_dbg(pnw->dev, "no need to notify\n");
++ else if (chrg_event == POWER_SUPPLY_CHARGER_EVENT_DISCONNECT) {
++ /* In Disconnect case, EM driver needs same chrg type
++ * like Connect even, construct one here */
++ psc_cap = event->cap;
++ psc_cap.chrg_evt = chrg_event;
++ psc_cap.chrg_type = pnw->psc_cap.chrg_type;
++ pnw->psc_cap = event->cap;
++ pnw->psc_cap.chrg_evt = chrg_event;
++ } else {
++ pnw->psc_cap = event->cap;
++ pnw->psc_cap.chrg_evt = chrg_event;
++ psc_cap = pnw->psc_cap;
++ }
++ spin_unlock_irqrestore(&pnw->cap_lock, flags);
++
++ if (chrg_event != -1) {
++ dev_dbg(pnw->dev, "ma = %d, evt = %d, type = %s\n",
++ psc_cap.ma, psc_cap.chrg_evt,
++ psc_string(psc_cap.chrg_type));
++
++ atomic_notifier_call_chain(&iotg->otg.notifier,
++ USB_EVENT_CHARGER, &psc_cap);
++ }
++
++ kfree(event);
++ spin_lock_irqsave(&pnw->charger_lock, flags);
++ }
++ spin_unlock_irqrestore(&pnw->charger_lock, flags);
++}
++
++static void penwell_otg_sdp_check_work(struct work_struct *work)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct otg_bc_cap cap;
++
++ /* Need to handle MFLD/CLV differently per different interface */
++ if (!is_clovertrail(to_pci_dev(pnw->dev))) {
++ if (penwell_otg_query_charging_cap(&cap)) {
++ dev_warn(pnw->dev, "SDP checking failed\n");
++ return;
++ }
++
++ /* If current charging cap is still 100ma SDP,
++ * assume this is a invalid charger and do 500ma
++ * charging */
++ if (cap.ma != 100 || cap.chrg_type != CHRG_SDP)
++ return;
++ } else
++ return;
++
++ dev_info(pnw->dev, "Notify invalid SDP at %dma\n", CHRG_CURR_SDP_INVAL);
++ penwell_otg_update_chrg_cap(CHRG_SDP_INVAL, CHRG_CURR_SDP_INVAL);
++}
++
++static void penwell_otg_work(struct work_struct *work)
++{
++ struct penwell_otg *pnw = container_of(work,
++ struct penwell_otg, work);
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ struct otg_hsm *hsm = &iotg->hsm;
++ enum usb_charger_type charger_type;
++ enum power_supply_charger_cable_type type;
++ int retval;
++ struct pci_dev *pdev;
++ unsigned long flags;
++
++ dev_dbg(pnw->dev,
++ "old state = %s\n", state_string(iotg->otg.state));
++
++ pm_runtime_get_sync(pnw->dev);
++
++ pdev = to_pci_dev(pnw->dev);
++
++ switch (iotg->otg.state) {
++ case OTG_STATE_UNDEFINED:
++ case OTG_STATE_B_IDLE:
++ if (hsm->id == ID_A || hsm->id == ID_ACA_A) {
++ /* Move to A_IDLE state, ID changes */
++
++ /* Delete current timer */
++ penwell_otg_del_timer(TB_SRP_FAIL_TMR);
++
++ iotg->otg.otg->default_a = 1;
++ hsm->a_srp_det = 0;
++ set_host_mode();
++ penwell_otg_phy_low_power(0);
++
++ /* Always set a_bus_req to 1, in case no ADP */
++ hsm->a_bus_req = 1;
++
++ /* Prevent device enter D0i1 or S3*/
++ wake_lock(&pnw->wake_lock);
++ pm_runtime_get(pnw->dev);
++
++ iotg->otg.state = OTG_STATE_A_IDLE;
++ penwell_update_transceiver();
++ } else if (hsm->b_adp_sense_tmout) {
++ hsm->b_adp_sense_tmout = 0;
++ } else if (hsm->b_srp_fail_tmout) {
++ hsm->b_srp_fail_tmr = 0;
++ hsm->b_srp_fail_tmout = 0;
++ hsm->b_bus_req = 0;
++ penwell_otg_nsf_msg(6);
++
++ penwell_update_transceiver();
++ } else if (hsm->b_sess_vld) {
++ /* Check if DCP is detected */
++ spin_lock_irqsave(&pnw->charger_lock, flags);
++ charger_type = pnw->charging_cap.chrg_type;
++ type = pnw->psc_cap.chrg_type;
++ if (charger_type == CHRG_DCP ||
++ type == POWER_SUPPLY_CHARGER_TYPE_USB_DCP) {
++ spin_unlock_irqrestore(&pnw->charger_lock,
++ flags);
++ break;
++ }
++ spin_unlock_irqrestore(&pnw->charger_lock, flags);
++
++ penwell_otg_phy_low_power(0);
++
++ /* Clear power_up */
++ hsm->power_up = 0;
++
++ /* Move to B_PERIPHERAL state, Session Valid */
++
++ /* Delete current timer */
++ penwell_otg_del_timer(TB_SRP_FAIL_TMR);
++
++ hsm->b_sess_end = 0;
++ hsm->a_bus_suspend = 0;
++
++ /* Start USB Battery charger detection flow */
++
++ /* We need new charger detection flow for Clovertrail.
++ * But for now(power-on), we just skip it.
++ * Later on we'll figure it out.
++ */
++ if (!is_clovertrail(pdev)) {
++ mutex_lock(&pnw->msic_mutex);
++ if (pdev->revision >= 0x8) {
++ retval = penwell_otg_manual_chrg_det();
++ if (retval < 0) {
++ /* if failed, reset controller
++ * and try charger detection
++ * flow again */
++ dev_warn(pnw->dev,
++ "detection failed, retry");
++ set_client_mode();
++ msleep(100);
++ penwell_otg_phy_low_power(0);
++ penwell_spi_reset_phy();
++ retval = penwell_otg_manual_chrg_det();
++ }
++ } else {
++ /* Enable data contact detection */
++ penwell_otg_data_contact_detect();
++ /* Enable charger detection */
++ penwell_otg_charger_detect();
++ retval =
++ penwell_otg_charger_type_detect();
++ }
++ mutex_unlock(&pnw->msic_mutex);
++ if (retval < 0) {
++ dev_warn(pnw->dev, "Charger detect failure\n");
++ break;
++ } else {
++ charger_type = retval;
++ }
++ } else {
++ /* Clovertrail charger detection flow */
++ retval = penwell_otg_charger_det_clt();
++ if (retval < 0) {
++ dev_warn(pnw->dev, "detect failed\n");
++ /* Reset PHY and redo the detection */
++ pnw_phy_ctrl_rst();
++ /* Restart charger detection */
++ retval = penwell_otg_charger_det_clt();
++ if (retval)
++ dev_warn(pnw->dev,
++ "detect fail again\n");
++ break;
++ } else
++ charger_type = retval;
++ }
++
++ /* This is a workaround for self-powered hub case,
++ * vbus valid event comes several ms before id change */
++ if (hsm->id == ID_A) {
++ dev_warn(pnw->dev, "ID changed\n");
++ break;
++ }
++
++ if (charger_type == CHRG_SE1) {
++ dev_info(pnw->dev, "SE1 detected\n");
++
++ /* SE1: set charger type, current, notify EM */
++ penwell_otg_update_chrg_cap(CHRG_SE1,
++ CHRG_CURR_SE1);
++ dev_info(pnw->dev,
++ "reset PHY via SPI if SE1 detected\n");
++
++ if (!is_clovertrail(pdev)) {
++ /* Reset PHY for MFLD only */
++ penwell_otg_msic_spi_access(true);
++ penwell_otg_msic_write(MSIC_FUNCTRLSET,
++ PHYRESET);
++ penwell_otg_msic_spi_access(false);
++ }
++ break;
++ } else if (charger_type == CHRG_DCP) {
++ dev_info(pnw->dev, "DCP detected\n");
++
++ /* DCP: set charger type, current, notify EM */
++ penwell_otg_update_chrg_cap(CHRG_DCP,
++ CHRG_CURR_DCP);
++ set_client_mode();
++ break;
++
++ } else if (charger_type == CHRG_ACA) {
++ dev_info(pnw->dev, "ACA detected\n");
++ if (hsm->id == ID_ACA_A) {
++ /* Move to A_IDLE state, ID changes */
++ penwell_otg_update_chrg_cap(CHRG_ACA,
++ CHRG_CURR_ACA);
++
++ /* Delete current timer */
++ penwell_otg_del_timer(TB_SRP_FAIL_TMR);
++
++ iotg->otg.otg->default_a = 1;
++ hsm->a_srp_det = 0;
++ set_host_mode();
++ penwell_otg_phy_low_power(0);
++
++ /* Always set a_bus_req to 1,
++ * in case no ADP */
++ hsm->a_bus_req = 1;
++
++ /* Prevent device enter D0i1 or S3*/
++ wake_lock(&pnw->wake_lock);
++ pm_runtime_get(pnw->dev);
++
++ iotg->otg.state = OTG_STATE_A_IDLE;
++ penwell_update_transceiver();
++ break;
++ } else if (hsm->id == ID_ACA_B) {
++ penwell_otg_update_chrg_cap(CHRG_ACA,
++ CHRG_CURR_ACA);
++ break;
++ } else if (hsm->id == ID_ACA_C) {
++ penwell_otg_update_chrg_cap(CHRG_ACA,
++ CHRG_CURR_ACA);
++ /* Clear HNP polling flag */
++ if (iotg->otg.otg->gadget)
++ iotg->otg.otg->gadget->
++ host_request_flag = 0;
++
++ penwell_otg_phy_low_power(0);
++ set_client_mode();
++
++ if (iotg->start_peripheral) {
++ iotg->start_peripheral(iotg);
++ } else {
++ dev_dbg(pnw->dev,
++ "client driver not support\n");
++ break;
++ }
++ }
++ } else if (charger_type == CHRG_CDP) {
++ dev_info(pnw->dev, "CDP detected\n");
++
++ /* MFLD WA: MSIC issue need disable phy intr */
++ if (!is_clovertrail(pdev)) {
++ dev_dbg(pnw->dev,
++ "MFLD WA: enable PHY int\n");
++ penwell_otg_phy_intr(0);
++ }
++
++ /* CDP: set charger type, current, notify EM */
++ penwell_otg_update_chrg_cap(CHRG_CDP,
++ CHRG_CURR_CDP);
++
++ /* Clear HNP polling flag */
++ if (iotg->otg.otg->gadget)
++ iotg->otg.otg->gadget->
++ host_request_flag = 0;
++
++ if (iotg->start_peripheral) {
++ iotg->start_peripheral(iotg);
++ } else {
++ dev_dbg(pnw->dev,
++ "client driver not support\n");
++ break;
++ }
++ } else if (charger_type == CHRG_SDP) {
++ dev_info(pnw->dev, "SDP detected\n");
++
++ /* MFLD WA: MSIC issue need disable phy intr */
++ if (!is_clovertrail(pdev)) {
++ dev_dbg(pnw->dev,
++ "MFLD WA: enable PHY int\n");
++ penwell_otg_phy_intr(0);
++ }
++
++ /* SDP: set charger type and 100ma by default */
++ penwell_otg_update_chrg_cap(CHRG_SDP, 100);
++
++ /* Clear HNP polling flag */
++ if (iotg->otg.otg->gadget)
++ iotg->otg.otg->gadget->
++ host_request_flag = 0;
++
++ penwell_otg_phy_low_power(0);
++ set_client_mode();
++
++ if (iotg->start_peripheral) {
++ iotg->start_peripheral(iotg);
++ } else {
++ dev_dbg(pnw->dev,
++ "client driver not support\n");
++ break;
++ }
++
++ /* Schedule the SDP checking after TIMEOUT */
++ queue_delayed_work(pnw->qwork,
++ &pnw->sdp_check_work,
++ INVALID_SDP_TIMEOUT);
++ } else if (charger_type == CHRG_UNKNOWN) {
++ dev_info(pnw->dev, "Unknown Charger Found\n");
++
++ /* Unknown: set charger type */
++ penwell_otg_update_chrg_cap(CHRG_UNKNOWN, 0);
++ }
++
++ penwell_otg_eye_diagram_optimize();
++
++ /* MFLD WA for PHY issue */
++ iotg->hsm.in_test_mode = 0;
++ iotg->hsm.ulpi_error = 0;
++
++ if (!is_clovertrail(pdev))
++ penwell_otg_start_ulpi_poll();
++
++ iotg->otg.state = OTG_STATE_B_PERIPHERAL;
++
++ } else if ((hsm->b_bus_req || hsm->power_up || hsm->adp_change
++ || hsm->otg_srp_reqd) && !hsm->b_srp_fail_tmr) {
++
++ penwell_otg_mon_bus();
++
++ if (hsm->b_ssend_srp && hsm->b_se0_srp) {
++
++ hsm->power_up = 0;
++ hsm->adp_change = 0;
++
++ /* clear the PHCD before start srp */
++ penwell_otg_phy_low_power(0);
++
++ /* Start SRP */
++ if (pnw->iotg.otg.otg->start_srp)
++ pnw->iotg.otg.otg->start_srp(
++ pnw->iotg.otg.otg);
++ penwell_otg_add_timer(TB_SRP_FAIL_TMR);
++
++ } else {
++ hsm->b_bus_req = 0;
++ dev_info(pnw->dev,
++ "BUS is active, try SRP later\n");
++ }
++
++ /* clear after SRP attemp */
++ if (hsm->otg_srp_reqd) {
++ dev_dbg(pnw->dev, "Test mode: SRP done\n");
++ hsm->otg_srp_reqd = 0;
++ }
++ } else if (!hsm->b_sess_vld && hsm->id == ID_B) {
++ spin_lock_irqsave(&pnw->charger_lock, flags);
++ charger_type = pnw->charging_cap.chrg_type;
++ type = pnw->psc_cap.chrg_type;
++ spin_unlock_irqrestore(&pnw->charger_lock, flags);
++
++ if (charger_type == CHRG_DCP) {
++ /* Notify EM charger remove event */
++ penwell_otg_update_chrg_cap(CHRG_UNKNOWN,
++ CHRG_CURR_DISCONN);
++
++ retval = penwell_otg_ulpi_write(iotg,
++ ULPI_PWRCTRLCLR, DPVSRCEN);
++ if (retval)
++ dev_warn(pnw->dev, "ulpi failed\n");
++ penwell_otg_charger_hwdet(false);
++ } else if (charger_type == CHRG_SE1) {
++ /* Notify EM charger remove event */
++ penwell_otg_update_chrg_cap(CHRG_UNKNOWN,
++ CHRG_CURR_DISCONN);
++
++ /* WA: on SE1 detach, reset PHY over SPI */
++ dev_info(pnw->dev,
++ "reset PHY over SPI if SE1 detached\n");
++ penwell_otg_msic_spi_access(true);
++ penwell_otg_msic_write(MSIC_FUNCTRLSET,
++ PHYRESET);
++ penwell_otg_msic_spi_access(false);
++ } else if (type == POWER_SUPPLY_CHARGER_TYPE_USB_ACA) {
++ /* Notify EM charger remove event */
++ penwell_otg_update_chrg_cap(CHRG_UNKNOWN,
++ CHRG_CURR_DISCONN);
++ penwell_otg_charger_hwdet(false);
++ } else if (type == POWER_SUPPLY_CHARGER_TYPE_USB_DCP) {
++ /* Notify EM charger remove event */
++ penwell_otg_update_chrg_cap(CHRG_UNKNOWN,
++ CHRG_CURR_DISCONN);
++
++ retval = penwell_otg_ulpi_write(iotg,
++ ULPI_PWRCTRLCLR, DPVSRCEN);
++ if (retval)
++ dev_warn(pnw->dev, "ulpi failed\n");
++ penwell_otg_charger_hwdet(false);
++ } else if (type == POWER_SUPPLY_CHARGER_TYPE_SE1) {
++ /* Notify EM charger remove event */
++ penwell_otg_update_chrg_cap(CHRG_UNKNOWN,
++ CHRG_CURR_DISCONN);
++ }
++ }
++ break;
++
++ case OTG_STATE_B_PERIPHERAL:
++ /* FIXME: Check if ID_ACA_A event will happened in this state */
++ if (hsm->id == ID_A) {
++ iotg->otg.otg->default_a = 1;
++ hsm->a_srp_det = 0;
++
++ cancel_delayed_work_sync(&pnw->ulpi_poll_work);
++ cancel_delayed_work_sync(&pnw->sdp_check_work);
++ penwell_otg_charger_hwdet(false);
++
++ if (iotg->stop_peripheral)
++ iotg->stop_peripheral(iotg);
++ else
++ dev_dbg(pnw->dev,
++ "client driver has been removed.\n");
++
++ set_host_mode();
++
++ /* Always set a_bus_req to 1, in case no ADP */
++ hsm->a_bus_req = 1;
++
++ /* Notify EM charger remove event */
++ penwell_otg_update_chrg_cap(CHRG_UNKNOWN,
++ CHRG_CURR_DISCONN);
++
++ /* Prevent device enter D0i1 or S3*/
++ wake_lock(&pnw->wake_lock);
++ pm_runtime_get(pnw->dev);
++
++ iotg->otg.state = OTG_STATE_A_IDLE;
++ penwell_update_transceiver();
++ } else if (hsm->ulpi_error && !hsm->in_test_mode) {
++ /* WA: try to recover once detected PHY issue */
++ hsm->ulpi_error = 0;
++
++ cancel_delayed_work_sync(&pnw->ulpi_poll_work);
++ cancel_delayed_work_sync(&pnw->sdp_check_work);
++
++ if (iotg->stop_peripheral)
++ iotg->stop_peripheral(iotg);
++
++ msleep(2000);
++
++ if (iotg->start_peripheral)
++ iotg->start_peripheral(iotg);
++
++ if (!is_clovertrail(pdev))
++ penwell_otg_start_ulpi_poll();
++
++ } else if (!hsm->b_sess_vld || hsm->id == ID_ACA_B) {
++ /* Move to B_IDLE state, VBUS off/ACA */
++
++ cancel_delayed_work(&pnw->ulpi_poll_work);
++ cancel_delayed_work_sync(&pnw->sdp_check_work);
++
++ hsm->b_bus_req = 0;
++
++ if (is_clovertrail(pdev)) {
++ queue_delayed_work(pnw->qwork,
++ &pnw->ulpi_check_work, HZ);
++ }
++
++ if (iotg->stop_peripheral)
++ iotg->stop_peripheral(iotg);
++ else
++ dev_dbg(pnw->dev,
++ "client driver has been removed.\n");
++
++ /* MFLD WA: reenable it for unplug event */
++ if (!is_clovertrail(pdev)) {
++ dev_dbg(pnw->dev, "MFLD WA: disable PHY int\n");
++ penwell_otg_phy_intr(1);
++ }
++
++ if (hsm->id == ID_ACA_B)
++ penwell_otg_update_chrg_cap(CHRG_ACA,
++ CHRG_CURR_ACA);
++ else if (hsm->id == ID_B) {
++ /* Notify EM charger remove event */
++ penwell_otg_update_chrg_cap(CHRG_UNKNOWN,
++ CHRG_CURR_DISCONN);
++ penwell_otg_charger_hwdet(false);
++ }
++
++ iotg->otg.state = OTG_STATE_B_IDLE;
++ } else if (hsm->b_bus_req && hsm->a_bus_suspend
++ && iotg->otg.otg->gadget
++ && iotg->otg.otg->gadget->b_hnp_enable) {
++
++ penwell_otg_phy_low_power(0);
++ msleep(10);
++
++ if (iotg->stop_peripheral)
++ iotg->stop_peripheral(iotg);
++ else
++ dev_dbg(pnw->dev,
++ "client driver has been removed.\n");
++
++ penwell_otg_phy_low_power(0);
++
++ hsm->a_conn = 0;
++ hsm->a_bus_resume = 0;
++
++ if (iotg->start_host) {
++ iotg->start_host(iotg);
++ hsm->test_device = 0;
++
++ /* FIXME: can we allow D3 and D0i3
++ * in B_WAIT_ACON?
++ * Now just disallow it
++ */
++ /* disallow D3 or D0i3 */
++ pm_runtime_get(pnw->dev);
++ wake_lock(&pnw->wake_lock);
++ iotg->otg.state = OTG_STATE_B_WAIT_ACON;
++ penwell_otg_add_timer(TB_ASE0_BRST_TMR);
++ } else
++ dev_dbg(pnw->dev, "host driver not loaded.\n");
++
++ } else if (hsm->id == ID_ACA_C) {
++ cancel_delayed_work_sync(&pnw->sdp_check_work);
++
++ /* Make sure current limit updated */
++ penwell_otg_update_chrg_cap(CHRG_ACA, CHRG_CURR_ACA);
++ } else if (hsm->id == ID_B) {
++ spin_lock_irqsave(&pnw->charger_lock, flags);
++ type = pnw->psc_cap.chrg_type;
++ spin_unlock_irqrestore(&pnw->charger_lock, flags);
++
++ if (type == POWER_SUPPLY_CHARGER_TYPE_USB_ACA) {
++ /* Notify EM charger ACA removal event */
++ penwell_otg_update_chrg_cap(CHRG_UNKNOWN,
++ CHRG_CURR_DISCONN);
++ penwell_otg_charger_hwdet(false);
++ /* Set current when switch from ACA to SDP */
++ if (!hsm->a_bus_suspend && iotg->otg.set_power)
++ iotg->otg.set_power(&iotg->otg, 500);
++ }
++ }
++ break;
++
++ case OTG_STATE_B_WAIT_ACON:
++ if (hsm->id == ID_A) {
++ /* Move to A_IDLE state, ID changes */
++
++ /* Delete current timer */
++ penwell_otg_del_timer(TB_ASE0_BRST_TMR);
++
++ iotg->otg.otg->default_a = 1;
++ hsm->a_srp_det = 0;
++
++ penwell_otg_HAAR(0);
++
++ PNW_STOP_HOST(pnw);
++
++ set_host_mode();
++
++ /* Always set a_bus_req to 1, in case no ADP */
++ iotg->hsm.a_bus_req = 1;
++
++ iotg->otg.state = OTG_STATE_A_IDLE;
++ penwell_update_transceiver();
++ } else if (!hsm->b_sess_vld || hsm->id == ID_ACA_B) {
++ /* Move to B_IDLE state, VBUS off/ACA */
++
++ if (hsm->id == ID_ACA_B)
++ penwell_otg_update_chrg_cap(CHRG_ACA,
++ CHRG_CURR_ACA);
++ else if (hsm->id == ID_B) {
++ /* Notify EM charger remove event */
++ penwell_otg_update_chrg_cap(CHRG_UNKNOWN,
++ CHRG_CURR_DISCONN);
++ }
++
++ /* Delete current timer */
++ penwell_otg_del_timer(TB_ASE0_BRST_TMR);
++
++ hsm->b_hnp_enable = 0;
++ hsm->b_bus_req = 0;
++ penwell_otg_HAAR(0);
++
++ PNW_STOP_HOST(pnw);
++
++ set_client_mode();
++
++ /* allow D3 and D0i3 */
++ pm_runtime_put(pnw->dev);
++ wake_unlock(&pnw->wake_lock);
++ iotg->otg.state = OTG_STATE_B_IDLE;
++ } else if (hsm->a_conn) {
++ /* Move to B_HOST state, A connected */
++
++ /* Delete current timer */
++ penwell_otg_del_timer(TB_ASE0_BRST_TMR);
++
++ penwell_otg_HAAR(0);
++
++ iotg->otg.state = OTG_STATE_B_HOST;
++ penwell_update_transceiver();
++ } else if (hsm->a_bus_resume || hsm->b_ase0_brst_tmout) {
++ /* Move to B_HOST state, A connected */
++
++ /* Delete current timer */
++ penwell_otg_del_timer(TB_ASE0_BRST_TMR);
++
++ penwell_otg_HAAR(0);
++ penwell_otg_nsf_msg(7);
++
++ PNW_STOP_HOST(pnw);
++
++ hsm->a_bus_suspend = 0;
++ hsm->b_bus_req = 0;
++
++ if (iotg->start_peripheral)
++ iotg->start_peripheral(iotg);
++ else
++ dev_dbg(pnw->dev, "client driver not loaded\n");
++
++ /* allow D3 and D0i3 in A_WAIT_BCON */
++ pm_runtime_put(pnw->dev);
++ wake_unlock(&pnw->wake_lock);
++ iotg->otg.state = OTG_STATE_B_PERIPHERAL;
++ } else if (hsm->id == ID_ACA_C) {
++ /* Make sure current limit updated */
++ penwell_otg_update_chrg_cap(CHRG_ACA, CHRG_CURR_ACA);
++ } else if (hsm->id == ID_B) {
++#if 0
++ /* only set 2ma due to client function stopped */
++ if (iotg->otg.set_power)
++ iotg->otg.set_power(&iotg->otg, 2);
++#endif
++ }
++ break;
++
++ case OTG_STATE_B_HOST:
++ if (hsm->id == ID_A) {
++ iotg->otg.otg->default_a = 1;
++ hsm->a_srp_det = 0;
++
++ /* Stop HNP polling */
++ if (iotg->stop_hnp_poll)
++ iotg->stop_hnp_poll(iotg);
++
++ PNW_STOP_HOST(pnw);
++
++ set_host_mode();
++
++ /* Always set a_bus_req to 1, in case no ADP */
++ hsm->a_bus_req = 1;
++
++ iotg->otg.state = OTG_STATE_A_IDLE;
++ penwell_update_transceiver();
++ } else if (!hsm->b_sess_vld || hsm->id == ID_ACA_B) {
++ /* Move to B_IDLE state, VBUS off/ACA */
++
++ if (hsm->id == ID_ACA_B)
++ penwell_otg_update_chrg_cap(CHRG_ACA,
++ CHRG_CURR_ACA);
++ else if (hsm->id == ID_B) {
++ /* Notify EM charger remove event */
++ penwell_otg_update_chrg_cap(CHRG_UNKNOWN,
++ CHRG_CURR_DISCONN);
++ }
++
++ hsm->b_hnp_enable = 0;
++ hsm->b_bus_req = 0;
++
++ /* Stop HNP polling */
++ if (iotg->stop_hnp_poll)
++ iotg->stop_hnp_poll(iotg);
++
++ PNW_STOP_HOST(pnw);
++
++ set_client_mode();
++
++ /* allow D3 and D0i3 in A_WAIT_BCON */
++ pm_runtime_put(pnw->dev);
++ wake_unlock(&pnw->wake_lock);
++ iotg->otg.state = OTG_STATE_B_IDLE;
++ } else if (!hsm->b_bus_req || !hsm->a_conn
++ || hsm->test_device) {
++ hsm->b_bus_req = 0;
++
++ /* Stop HNP polling */
++ if (iotg->stop_hnp_poll)
++ iotg->stop_hnp_poll(iotg);
++
++ PNW_STOP_HOST(pnw);
++ hsm->a_bus_suspend = 0;
++
++ /* Clear HNP polling flag */
++ if (iotg->otg.otg->gadget)
++ iotg->otg.otg->gadget->host_request_flag = 0;
++
++ if (iotg->start_peripheral)
++ iotg->start_peripheral(iotg);
++ else
++ dev_dbg(pnw->dev,
++ "client driver not loaded.\n");
++
++ /* allow D3 and D0i3 in A_WAIT_BCON */
++ pm_runtime_put(pnw->dev);
++ wake_unlock(&pnw->wake_lock);
++ iotg->otg.state = OTG_STATE_B_PERIPHERAL;
++ } else if (hsm->id == ID_ACA_C) {
++ /* Make sure current limit updated */
++ penwell_otg_update_chrg_cap(CHRG_ACA, CHRG_CURR_ACA);
++ }
++ break;
++
++ case OTG_STATE_A_IDLE:
++ if (hsm->id == ID_B || hsm->id == ID_ACA_B) {
++ pnw->iotg.otg.otg->default_a = 0;
++ hsm->b_bus_req = 0;
++
++ if (hsm->id == ID_ACA_B)
++ penwell_otg_update_chrg_cap(CHRG_ACA,
++ CHRG_CURR_ACA);
++
++ hsm->b_bus_req = 0;
++
++ set_client_mode();
++
++ iotg->otg.state = OTG_STATE_B_IDLE;
++ penwell_update_transceiver();
++
++ /* Decrement the device usage counter */
++ pm_runtime_put(pnw->dev);
++ wake_unlock(&pnw->wake_lock);
++ } else if (hsm->id == ID_ACA_A) {
++
++ penwell_otg_update_chrg_cap(CHRG_ACA, CHRG_CURR_ACA);
++
++ if (hsm->power_up)
++ hsm->power_up = 0;
++
++ if (hsm->adp_change)
++ hsm->adp_change = 0;
++
++ if (hsm->a_srp_det)
++ hsm->a_srp_det = 0;
++
++ hsm->b_conn = 0;
++ hsm->hnp_poll_enable = 0;
++
++ if (iotg->start_host)
++ iotg->start_host(iotg);
++ else {
++ dev_dbg(pnw->dev, "host driver not loaded.\n");
++ break;
++ }
++
++ /* allow D3 and D0i3 in A_WAIT_BCON */
++ pm_runtime_put(pnw->dev);
++ wake_unlock(&pnw->wake_lock);
++
++ iotg->otg.state = OTG_STATE_A_WAIT_BCON;
++
++ } else if (!hsm->a_bus_drop && (hsm->power_up || hsm->a_bus_req
++ || hsm->a_srp_det || hsm->adp_change)) {
++ /* power up / adp changes / srp detection should be
++ * cleared at once after handled. */
++ if (hsm->power_up)
++ hsm->power_up = 0;
++
++ if (hsm->adp_change)
++ hsm->adp_change = 0;
++
++ if (hsm->a_srp_det) {
++ hsm->a_srp_det = 0;
++ /* wait SRP done, then enable VBUS */
++ usleep_range(10000, 11000);
++ }
++
++ otg_set_vbus(iotg->otg.otg, true);
++
++ penwell_otg_add_timer(TA_WAIT_VRISE_TMR);
++
++ iotg->otg.state = OTG_STATE_A_WAIT_VRISE;
++
++ penwell_update_transceiver();
++ } else if (hsm->b_sess_end || hsm->a_sess_vld ||
++ hsm->a_srp_det || !hsm->b_sess_vld) {
++ hsm->a_srp_det = 0;
++ dev_dbg(pnw->dev, "reconfig...\n");
++ }
++ break;
++
++ case OTG_STATE_A_WAIT_VRISE:
++ if (hsm->a_bus_drop ||
++ hsm->id == ID_B || hsm->id == ID_ACA_B) {
++ /* Move to A_WAIT_VFALL, over current/user request */
++
++ /* Delete current timer */
++ penwell_otg_del_timer(TA_WAIT_VRISE_TMR);
++
++ /* Turn off VBUS */
++ otg_set_vbus(iotg->otg.otg, false);
++
++ penwell_otg_add_timer(TA_WAIT_VFALL_TMR);
++ iotg->otg.state = OTG_STATE_A_WAIT_VFALL;
++ } else if (hsm->a_vbus_vld || hsm->a_wait_vrise_tmout
++ || hsm->id == ID_ACA_A) {
++ /* Move to A_WAIT_BCON state, a vbus vld */
++ /* Delete current timer and clear flags */
++ penwell_otg_del_timer(TA_WAIT_VRISE_TMR);
++
++ if (!hsm->a_vbus_vld) {
++ dev_warn(pnw->dev, "vbus can't rise to vbus vld, overcurrent!\n");
++ /* Turn off VBUS */
++ otg_set_vbus(iotg->otg.otg, false);
++
++ penwell_otg_add_timer(TA_WAIT_VFALL_TMR);
++ iotg->otg.state = OTG_STATE_A_WAIT_VFALL;
++ break;
++ }
++
++ if (hsm->id == ID_ACA_A) {
++ otg_set_vbus(iotg->otg.otg, false);
++
++ penwell_otg_update_chrg_cap(CHRG_ACA,
++ CHRG_CURR_ACA);
++ }
++
++ hsm->a_bus_req = 1;
++ hsm->b_conn = 0;
++ hsm->hnp_poll_enable = 0;
++
++ penwell_otg_eye_diagram_optimize();
++
++ if (iotg->start_host) {
++ dev_dbg(pnw->dev, "host_ops registered!\n");
++ iotg->start_host(iotg);
++ } else {
++ dev_dbg(pnw->dev, "host driver not loaded.\n");
++ break;
++ }
++
++ penwell_otg_add_timer(TA_WAIT_BCON_TMR);
++
++ /* allow D3 and D0i3 in A_WAIT_BCON */
++ pm_runtime_put(pnw->dev);
++ wake_unlock(&pnw->wake_lock);
++ /* at least give some time to USB HOST to enumerate
++ * devices before trying to suspend the system*/
++ wake_lock_timeout(&pnw->wake_lock, 5 * HZ);
++
++ iotg->otg.state = OTG_STATE_A_WAIT_BCON;
++ }
++ break;
++ case OTG_STATE_A_WAIT_BCON:
++ if (hsm->id == ID_B || hsm->id == ID_ACA_B || hsm->a_bus_drop ||
++ hsm->a_wait_bcon_tmout) {
++ /* Move to A_WAIT_VFALL state, user request */
++
++ /* Delete current timer and clear flags for B-Device */
++ penwell_otg_del_timer(TA_WAIT_BCON_TMR);
++
++ hsm->b_bus_req = 0;
++
++ PNW_STOP_HOST(pnw);
++
++ /* Turn off VBUS */
++ otg_set_vbus(iotg->otg.otg, false);
++
++ penwell_otg_add_timer(TA_WAIT_VFALL_TMR);
++
++ /* disallow D3 or D0i3 */
++ pm_runtime_get(pnw->dev);
++ wake_lock(&pnw->wake_lock);
++ iotg->otg.state = OTG_STATE_A_WAIT_VFALL;
++ } else if (!hsm->a_vbus_vld) {
++ /* Move to A_VBUS_ERR state, over-current detected */
++
++ /* CTP SW Workaround, add 300ms debouce on VBUS drop */
++ if (is_clovertrail(pdev)) {
++ msleep(300);
++ if (hsm->a_vbus_vld)
++ break;
++ }
++
++ /* Notify user space for vbus invalid event */
++ penwell_otg_notify_warning(USB_WARNING_VBUS_INVALID);
++
++ /* Delete current timer and disable host function */
++ penwell_otg_del_timer(TA_WAIT_BCON_TMR);
++
++ PNW_STOP_HOST(pnw);
++
++ /* Turn off VBUS and enter PHY low power mode */
++ otg_set_vbus(iotg->otg.otg, false);
++
++ /* disallow D3 or D0i3 */
++ pm_runtime_get(pnw->dev);
++ wake_lock(&pnw->wake_lock);
++ iotg->otg.state = OTG_STATE_A_VBUS_ERR;
++ } else if (hsm->b_conn) {
++ /* Move to A_HOST state, device connected */
++
++ /* Delete current timer and disable host function */
++ penwell_otg_del_timer(TA_WAIT_BCON_TMR);
++
++ /* Start HNP polling */
++ if (iotg->start_hnp_poll)
++ iotg->start_hnp_poll(iotg);
++
++ if (!hsm->a_bus_req)
++ hsm->a_bus_req = 1;
++
++ if (hsm->test_device)
++ penwell_otg_add_timer(TTST_MAINT_TMR);
++
++ iotg->otg.state = OTG_STATE_A_HOST;
++ } else if (hsm->id == ID_ACA_A) {
++ penwell_otg_update_chrg_cap(CHRG_ACA, CHRG_CURR_ACA);
++
++ /* Turn off VBUS */
++ otg_set_vbus(iotg->otg.otg, false);
++ }
++ break;
++
++ case OTG_STATE_A_HOST:
++ if (hsm->id == ID_B || hsm->id == ID_ACA_B || hsm->a_bus_drop) {
++ /* Move to A_WAIT_VFALL state, timeout/user request */
++
++ /* Delete current timer and clear flags */
++ if (hsm->test_device) {
++ hsm->test_device = 0;
++ penwell_otg_del_timer(TTST_MAINT_TMR);
++ }
++
++ if (hsm->id == ID_ACA_B)
++ penwell_otg_update_chrg_cap(CHRG_ACA,
++ CHRG_CURR_ACA);
++
++ /* Stop HNP polling */
++ if (iotg->stop_hnp_poll)
++ iotg->stop_hnp_poll(iotg);
++
++ penwell_otg_phy_low_power(0);
++
++ PNW_STOP_HOST(pnw);
++
++ /* Turn off VBUS */
++ otg_set_vbus(iotg->otg.otg, false);
++
++ penwell_otg_add_timer(TA_WAIT_VFALL_TMR);
++
++ /* disallow D3 or D0i3 */
++ pm_runtime_get(pnw->dev);
++ wake_lock(&pnw->wake_lock);
++ iotg->otg.state = OTG_STATE_A_WAIT_VFALL;
++ } else if (hsm->test_device && hsm->tst_maint_tmout) {
++
++ hsm->test_device = 0;
++
++ /* Stop HNP polling */
++ if (iotg->stop_hnp_poll)
++ iotg->stop_hnp_poll(iotg);
++
++ penwell_otg_phy_low_power(0);
++
++ PNW_STOP_HOST(pnw);
++
++ /* Turn off VBUS */
++ otg_set_vbus(iotg->otg.otg, false);
++
++ /* Clear states and wait for SRP */
++ hsm->a_srp_det = 0;
++ hsm->a_bus_req = 0;
++
++ /* disallow D3 or D0i3 */
++ pm_runtime_get(pnw->dev);
++ wake_lock(&pnw->wake_lock);
++ iotg->otg.state = OTG_STATE_A_IDLE;
++ } else if (!hsm->a_vbus_vld) {
++ /* Move to A_VBUS_ERR state */
++
++ /* CTP SW Workaround, add 300ms debouce on VBUS drop */
++ if (is_clovertrail(pdev)) {
++ msleep(300);
++ if (hsm->a_vbus_vld)
++ break;
++ }
++
++ /* Notify user space for vbus invalid event */
++ penwell_otg_notify_warning(USB_WARNING_VBUS_INVALID);
++
++ /* Delete current timer and clear flags */
++ if (hsm->test_device) {
++ hsm->test_device = 0;
++ penwell_otg_del_timer(TTST_MAINT_TMR);
++ }
++
++ /* Stop HNP polling */
++ if (iotg->stop_hnp_poll)
++ iotg->stop_hnp_poll(iotg);
++
++ PNW_STOP_HOST(pnw);
++
++ /* Turn off VBUS */
++ otg_set_vbus(iotg->otg.otg, false);
++
++ /* disallow D3 or D0i3 */
++ pm_runtime_get(pnw->dev);
++ wake_lock(&pnw->wake_lock);
++ iotg->otg.state = OTG_STATE_A_VBUS_ERR;
++ } else if (!hsm->a_bus_req &&
++ iotg->otg.otg->host->b_hnp_enable) {
++ /* Move to A_SUSPEND state */
++
++ /* Stop HNP polling */
++ if (iotg->stop_hnp_poll)
++ iotg->stop_hnp_poll(iotg);
++
++ /* According to Spec 7.1.5 */
++ penwell_otg_add_timer(TA_AIDL_BDIS_TMR);
++
++ /* Set HABA to enable hardware assistance to
++ * signal A-connect after receiver B-disconnect
++ * Hardware will then set client mode and
++ * enable URE, SLE and PCE after the assistance
++ * otg_dummy_irq is used to clean these ints
++ * when client driver is not resumed.
++ */
++ if (request_irq(pdev->irq, otg_dummy_irq,
++ IRQF_SHARED, driver_name,
++ iotg->base) != 0) {
++ dev_dbg(pnw->dev,
++ "request interrupt %d failed\n",
++ pdev->irq);
++ }
++ penwell_otg_HABA(1);
++
++ penwell_otg_loc_sof(0);
++ penwell_otg_phy_low_power(0);
++
++ /* disallow D3 or D0i3 */
++ pm_runtime_get(pnw->dev);
++ wake_lock(&pnw->wake_lock);
++ iotg->otg.state = OTG_STATE_A_SUSPEND;
++ } else if (!hsm->b_conn && hsm->test_device
++ && hsm->otg_vbus_off) {
++ /* If it is a test device with otg_vbus_off bit set,
++ * turn off VBUS on disconnect event and stay for
++ * TTST_NOADP without ADP */
++
++ penwell_otg_del_timer(TTST_MAINT_TMR);
++
++ /* Stop HNP polling */
++ if (iotg->stop_hnp_poll)
++ iotg->stop_hnp_poll(iotg);
++
++ penwell_otg_phy_low_power(0);
++
++ PNW_STOP_HOST(pnw);
++
++ /* Turn off VBUS */
++ otg_set_vbus(iotg->otg.otg, false);
++
++ penwell_otg_add_timer(TTST_NOADP_TMR);
++
++ /* disallow D3 or D0i3 */
++ pm_runtime_get(pnw->dev);
++ wake_lock(&pnw->wake_lock);
++ iotg->otg.state = OTG_STATE_A_WAIT_VFALL;
++
++ } else if (!hsm->b_conn) {
++
++ /* Delete current timer and clear flags */
++ if (hsm->test_device) {
++ hsm->test_device = 0;
++ penwell_otg_del_timer(TTST_MAINT_TMR);
++ }
++
++ /* Stop HNP polling */
++ if (iotg->stop_hnp_poll)
++ iotg->stop_hnp_poll(iotg);
++
++ /* add kernel timer */
++ iotg->otg.state = OTG_STATE_A_WAIT_BCON;
++ } else if (hsm->id == ID_ACA_A) {
++ penwell_otg_update_chrg_cap(CHRG_ACA, CHRG_CURR_ACA);
++
++ /* Turn off VBUS */
++ otg_set_vbus(iotg->otg.otg, false);
++ } else if (hsm->id == ID_A) {
++ /* Turn on VBUS */
++ otg_set_vbus(iotg->otg.otg, true);
++ }
++ break;
++
++ case OTG_STATE_A_SUSPEND:
++ if (hsm->id == ID_B || hsm->id == ID_ACA_B ||
++ hsm->a_bus_drop || hsm->a_aidl_bdis_tmout) {
++ /* Move to A_WAIT_VFALL state, timeout/user request */
++ penwell_otg_HABA(0);
++ free_irq(pdev->irq, iotg->base);
++
++ /* Delete current timer and clear HW assist */
++ if (hsm->a_aidl_bdis_tmout)
++ hsm->a_aidl_bdis_tmout = 0;
++ penwell_otg_del_timer(TA_AIDL_BDIS_TMR);
++
++ if (hsm->id == ID_ACA_B)
++ penwell_otg_update_chrg_cap(CHRG_ACA,
++ CHRG_CURR_ACA);
++
++ /* Stop HNP polling */
++ if (iotg->stop_hnp_poll)
++ iotg->stop_hnp_poll(iotg);
++
++ PNW_STOP_HOST(pnw);
++
++ /* Turn off VBUS */
++ otg_set_vbus(iotg->otg.otg, false);
++
++ penwell_otg_add_timer(TA_WAIT_VFALL_TMR);
++ iotg->otg.state = OTG_STATE_A_WAIT_VFALL;
++ } else if (!hsm->a_vbus_vld) {
++ /* Move to A_VBUS_ERR state, Over-current */
++ penwell_otg_HABA(0);
++ free_irq(pdev->irq, iotg->base);
++
++ /* Delete current timer and clear flags */
++ penwell_otg_del_timer(TA_AIDL_BDIS_TMR);
++
++ PNW_STOP_HOST(pnw);
++
++ /* Turn off VBUS */
++ otg_set_vbus(iotg->otg.otg, false);
++ iotg->otg.state = OTG_STATE_A_VBUS_ERR;
++ } else if (!hsm->b_conn &&
++ !pnw->iotg.otg.otg->host->b_hnp_enable) {
++ /* Move to A_WAIT_BCON */
++
++ /* delete current timer */
++ penwell_otg_del_timer(TA_AIDL_BDIS_TMR);
++
++ /* add kernel timer */
++ penwell_otg_add_timer(TA_WAIT_BCON_TMR);
++
++ /* allow D3 and D0i3 in A_WAIT_BCON */
++ pm_runtime_put(pnw->dev);
++ wake_unlock(&pnw->wake_lock);
++ iotg->otg.state = OTG_STATE_A_WAIT_BCON;
++ } else if (!hsm->b_conn &&
++ pnw->iotg.otg.otg->host->b_hnp_enable) {
++ /* Move to A_PERIPHERAL state, HNP */
++ penwell_otg_HABA(0);
++ free_irq(pdev->irq, iotg->base);
++
++ /* Delete current timer and clear flags */
++ penwell_otg_del_timer(TA_AIDL_BDIS_TMR);
++ penwell_otg_phy_low_power(0);
++
++ PNW_STOP_HOST(pnw);
++
++ penwell_otg_phy_low_power(0);
++ hsm->b_bus_suspend = 0;
++
++ /* Clear HNP polling flag */
++ if (iotg->otg.otg->gadget)
++ iotg->otg.otg->gadget->host_request_flag = 0;
++
++ penwell_otg_phy_low_power(0);
++
++ if (iotg->start_peripheral)
++ iotg->start_peripheral(iotg);
++ else
++ dev_dbg(pnw->dev,
++ "client driver not loaded.\n");
++
++ penwell_otg_add_timer(TA_BIDL_ADIS_TMR);
++ iotg->otg.state = OTG_STATE_A_PERIPHERAL;
++ } else if (hsm->a_bus_req) {
++ /* Move to A_HOST state, user request */
++ penwell_otg_HABA(0);
++ free_irq(pdev->irq, iotg->base);
++
++ /* Delete current timer and clear flags */
++ penwell_otg_del_timer(TA_AIDL_BDIS_TMR);
++
++ penwell_otg_loc_sof(1);
++
++ /* Start HNP polling */
++ if (iotg->start_hnp_poll)
++ iotg->start_hnp_poll(iotg);
++
++ /* allow D3 and D0i3 in A_HOST */
++ pm_runtime_put(pnw->dev);
++ wake_unlock(&pnw->wake_lock);
++ iotg->otg.state = OTG_STATE_A_HOST;
++ } else if (hsm->id == ID_ACA_A) {
++ penwell_otg_update_chrg_cap(CHRG_ACA, CHRG_CURR_ACA);
++
++ /* Turn off VBUS */
++ otg_set_vbus(iotg->otg.otg, false);
++ }
++ break;
++ case OTG_STATE_A_PERIPHERAL:
++ if (hsm->id == ID_B || hsm->a_bus_drop) {
++ /* Move to A_WAIT_VFALL state */
++
++ /* Delete current timer and clear flags */
++ penwell_otg_del_timer(TA_BIDL_ADIS_TMR);
++
++ if (iotg->stop_peripheral)
++ iotg->stop_peripheral(iotg);
++ else
++ dev_dbg(pnw->dev,
++ "client driver has been removed.\n");
++
++ /* Turn off VBUS */
++ otg_set_vbus(iotg->otg.otg, false);
++ set_host_mode();
++
++ penwell_otg_add_timer(TA_WAIT_VFALL_TMR);
++ iotg->otg.state = OTG_STATE_A_WAIT_VFALL;
++ } else if (!hsm->a_vbus_vld) {
++ /* Move to A_VBUS_ERR state, over-current detected */
++
++ /* Delete current timer and disable client function */
++ penwell_otg_del_timer(TA_BIDL_ADIS_TMR);
++
++ if (iotg->stop_peripheral)
++ iotg->stop_peripheral(iotg);
++ else
++ dev_dbg(pnw->dev,
++ "client driver has been removed.\n");
++
++ /* Turn off the VBUS and enter PHY low power mode */
++ otg_set_vbus(iotg->otg.otg, false);
++
++ iotg->otg.state = OTG_STATE_A_VBUS_ERR;
++ } else if (hsm->a_bidl_adis_tmout) {
++ /* Move to A_WAIT_BCON state */
++ hsm->a_bidl_adis_tmr = 0;
++
++ msleep(10);
++ penwell_otg_phy_low_power(0);
++
++ /* Disable client function and switch to host mode */
++ if (iotg->stop_peripheral)
++ iotg->stop_peripheral(iotg);
++ else
++ dev_dbg(pnw->dev,
++ "client driver has been removed.\n");
++
++ hsm->hnp_poll_enable = 0;
++ hsm->b_conn = 0;
++
++ penwell_otg_phy_low_power(0);
++
++ if (iotg->start_host)
++ iotg->start_host(iotg);
++ else
++ dev_dbg(pnw->dev,
++ "host driver not loaded.\n");
++
++ penwell_otg_add_timer(TA_WAIT_BCON_TMR);
++
++ /* allow D3 and D0i3 in A_WAIT_BCON */
++ pm_runtime_put(pnw->dev);
++ wake_unlock(&pnw->wake_lock);
++ iotg->otg.state = OTG_STATE_A_WAIT_BCON;
++ } else if (hsm->id == ID_A && hsm->b_bus_suspend) {
++ if (!timer_pending(&pnw->hsm_timer))
++ penwell_otg_add_timer(TA_BIDL_ADIS_TMR);
++ } else if (hsm->id == ID_A && !hsm->b_bus_suspend) {
++ penwell_otg_del_timer(TA_BIDL_ADIS_TMR);
++ } else if (hsm->id == ID_ACA_A) {
++ penwell_otg_update_chrg_cap(CHRG_ACA, CHRG_CURR_ACA);
++
++ /* Turn off VBUS */
++ otg_set_vbus(iotg->otg.otg, false);
++ }
++ break;
++ case OTG_STATE_A_VBUS_ERR:
++ if (hsm->id == ID_B || hsm->id == ID_ACA_B ||
++ hsm->id == ID_ACA_A || hsm->a_bus_drop ||
++ hsm->a_clr_err) {
++ if (hsm->a_clr_err)
++ hsm->a_clr_err = 0;
++
++ penwell_otg_add_timer(TA_WAIT_VFALL_TMR);
++ iotg->otg.state = OTG_STATE_A_WAIT_VFALL;
++ }
++ break;
++ case OTG_STATE_A_WAIT_VFALL:
++ if (hsm->a_wait_vfall_tmout) {
++ hsm->a_srp_det = 0;
++ hsm->a_wait_vfall_tmout = 0;
++
++ /* Move to A_IDLE state, vbus falls */
++ /* Always set a_bus_req to 1, in case no ADP */
++ hsm->a_bus_req = 1;
++
++ iotg->otg.state = OTG_STATE_A_IDLE;
++ penwell_update_transceiver();
++ } else if (hsm->test_device && hsm->otg_vbus_off
++ && hsm->tst_noadp_tmout) {
++ /* After noadp timeout, switch back to normal mode */
++ hsm->test_device = 0;
++ hsm->otg_vbus_off = 0;
++ hsm->tst_noadp_tmout = 0;
++
++ hsm->a_bus_req = 1;
++
++ iotg->otg.state = OTG_STATE_A_IDLE;
++ penwell_update_transceiver();
++ }
++ break;
++ default:
++ break;
++ ;
++ }
++
++ pm_runtime_put_sync(pnw->dev);
++
++ dev_dbg(pnw->dev,
++ "new state = %s\n", state_string(iotg->otg.state));
++}
++
++static ssize_t
++show_registers(struct device *_dev, struct device_attribute *attr, char *buf)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ char *next;
++ unsigned size;
++ unsigned t;
++
++ next = buf;
++ size = PAGE_SIZE;
++
++ pm_runtime_get_sync(pnw->dev);
++
++ t = scnprintf(next, size,
++ "\n"
++ "USBCMD = 0x%08x\n"
++ "USBSTS = 0x%08x\n"
++ "USBINTR = 0x%08x\n"
++ "ASYNCLISTADDR = 0x%08x\n"
++ "PORTSC1 = 0x%08x\n"
++ "HOSTPC1 = 0x%08x\n"
++ "OTGSC = 0x%08x\n"
++ "USBMODE = 0x%08x\n",
++ readl(pnw->iotg.base + 0x30),
++ readl(pnw->iotg.base + 0x34),
++ readl(pnw->iotg.base + 0x38),
++ readl(pnw->iotg.base + 0x48),
++ readl(pnw->iotg.base + 0x74),
++ readl(pnw->iotg.base + 0xb4),
++ readl(pnw->iotg.base + 0xf4),
++ readl(pnw->iotg.base + 0xf8)
++ );
++
++ pm_runtime_put_sync(pnw->dev);
++
++ size -= t;
++ next += t;
++
++ return PAGE_SIZE - size;
++}
++static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL);
++
++static ssize_t
++show_hsm(struct device *_dev, struct device_attribute *attr, char *buf)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ char *next;
++ unsigned size, t;
++
++ next = buf;
++ size = PAGE_SIZE;
++
++ if (iotg->otg.otg->host)
++ iotg->hsm.a_set_b_hnp_en = iotg->otg.otg->host->b_hnp_enable;
++
++ if (iotg->otg.otg->gadget)
++ iotg->hsm.b_hnp_enable = iotg->otg.otg->gadget->b_hnp_enable;
++
++ t = scnprintf(next, size,
++ "\n"
++ "current state = %s\n"
++ "a_bus_resume = \t%d\n"
++ "a_bus_suspend = \t%d\n"
++ "a_conn = \t%d\n"
++ "a_sess_vld = \t%d\n"
++ "a_srp_det = \t%d\n"
++ "a_vbus_vld = \t%d\n"
++ "b_bus_suspend = \t%d\n"
++ "b_conn = \t%d\n"
++ "b_se0_srp = \t%d\n"
++ "b_ssend_srp = \t%d\n"
++ "b_sess_end = \t%d\n"
++ "b_sess_vld = \t%d\n"
++ "id = \t%d\n"
++ "power_up = \t%d\n"
++ "adp_change = \t%d\n"
++ "test_device = \t%d\n"
++ "a_set_b_hnp_en = \t%d\n"
++ "b_srp_done = \t%d\n"
++ "b_hnp_enable = \t%d\n"
++ "hnp_poll_enable = \t%d\n"
++ "a_wait_vrise_tmout = \t%d\n"
++ "a_wait_bcon_tmout = \t%d\n"
++ "a_aidl_bdis_tmout = \t%d\n"
++ "a_bidl_adis_tmout = \t%d\n"
++ "a_bidl_adis_tmr = \t%d\n"
++ "a_wait_vfall_tmout = \t%d\n"
++ "b_ase0_brst_tmout = \t%d\n"
++ "b_srp_fail_tmout = \t%d\n"
++ "b_srp_fail_tmr = \t%d\n"
++ "b_adp_sense_tmout = \t%d\n"
++ "tst_maint_tmout = \t%d\n"
++ "tst_noadp_tmout = \t%d\n"
++ "a_bus_drop = \t%d\n"
++ "a_bus_req = \t%d\n"
++ "a_clr_err = \t%d\n"
++ "b_bus_req = \t%d\n"
++ "ulpi_error = \t%d\n"
++ "ulpi_polling = \t%d\n",
++ state_string(iotg->otg.state),
++ iotg->hsm.a_bus_resume,
++ iotg->hsm.a_bus_suspend,
++ iotg->hsm.a_conn,
++ iotg->hsm.a_sess_vld,
++ iotg->hsm.a_srp_det,
++ iotg->hsm.a_vbus_vld,
++ iotg->hsm.b_bus_suspend,
++ iotg->hsm.b_conn,
++ iotg->hsm.b_se0_srp,
++ iotg->hsm.b_ssend_srp,
++ iotg->hsm.b_sess_end,
++ iotg->hsm.b_sess_vld,
++ iotg->hsm.id,
++ iotg->hsm.power_up,
++ iotg->hsm.adp_change,
++ iotg->hsm.test_device,
++ iotg->hsm.a_set_b_hnp_en,
++ iotg->hsm.b_srp_done,
++ iotg->hsm.b_hnp_enable,
++ iotg->hsm.hnp_poll_enable,
++ iotg->hsm.a_wait_vrise_tmout,
++ iotg->hsm.a_wait_bcon_tmout,
++ iotg->hsm.a_aidl_bdis_tmout,
++ iotg->hsm.a_bidl_adis_tmout,
++ iotg->hsm.a_bidl_adis_tmr,
++ iotg->hsm.a_wait_vfall_tmout,
++ iotg->hsm.b_ase0_brst_tmout,
++ iotg->hsm.b_srp_fail_tmout,
++ iotg->hsm.b_srp_fail_tmr,
++ iotg->hsm.b_adp_sense_tmout,
++ iotg->hsm.tst_maint_tmout,
++ iotg->hsm.tst_noadp_tmout,
++ iotg->hsm.a_bus_drop,
++ iotg->hsm.a_bus_req,
++ iotg->hsm.a_clr_err,
++ iotg->hsm.b_bus_req,
++ iotg->hsm.ulpi_error,
++ iotg->hsm.ulpi_polling
++ );
++ size -= t;
++ next += t;
++
++ return PAGE_SIZE - size;
++}
++static DEVICE_ATTR(hsm, S_IRUGO, show_hsm, NULL);
++
++static ssize_t
++show_chargers(struct device *_dev, struct device_attribute *attr, char *buf)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ char *next;
++ unsigned size, t;
++ enum usb_charger_type type;
++ unsigned int ma;
++ unsigned long flags;
++ struct pci_dev *pdev;
++ struct power_supply_cable_props psc_cap;
++
++ pdev = to_pci_dev(pnw->dev);
++
++ next = buf;
++ size = PAGE_SIZE;
++
++ if (!is_clovertrail(pdev)) {
++ spin_lock_irqsave(&pnw->charger_lock, flags);
++ type = pnw->charging_cap.chrg_type;
++ ma = pnw->charging_cap.ma;
++ spin_unlock_irqrestore(&pnw->charger_lock, flags);
++
++ t = scnprintf(next, size,
++ "USB Battery Charging Capability\n"
++ "\tUSB Charger Type: %s\n"
++ "\tMax Charging Current: %u\n",
++ charger_string(type),
++ ma
++ );
++ } else {
++ spin_lock_irqsave(&pnw->charger_lock, flags);
++ psc_cap = pnw->psc_cap;
++ spin_unlock_irqrestore(&pnw->charger_lock, flags);
++
++ t = scnprintf(next, size,
++ "USB Battery Charging Capability(CLV)\n"
++ "\tUSB Charger Type: %s\n"
++ "\tMax Charging Current: %u\n",
++ psc_string(psc_cap.chrg_type),
++ psc_cap.ma
++ );
++
++ }
++ size -= t;
++ next += t;
++
++ return PAGE_SIZE - size;
++}
++static DEVICE_ATTR(chargers, S_IRUGO, show_chargers, NULL);
++
++static ssize_t
++get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ char *next;
++ unsigned size, t;
++
++ next = buf;
++ size = PAGE_SIZE;
++
++ t = scnprintf(next, size, "%d", pnw->iotg.hsm.a_bus_req);
++ size -= t;
++ next += t;
++
++ return PAGE_SIZE - size;
++}
++
++static ssize_t
++set_a_bus_req(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++
++ if (!iotg->otg.otg->default_a)
++ return -1;
++ if (count > 2)
++ return -1;
++
++ if (buf[0] == '0') {
++ iotg->hsm.a_bus_req = 0;
++ dev_dbg(pnw->dev, "a_bus_req = 0\n");
++ } else if (buf[0] == '1') {
++ /* If a_bus_drop is TRUE, a_bus_req can't be set */
++ if (iotg->hsm.a_bus_drop)
++ return -1;
++ iotg->hsm.a_bus_req = 1;
++ dev_dbg(pnw->dev, "a_bus_req = 1\n");
++ if (iotg->otg.state == OTG_STATE_A_PERIPHERAL) {
++ dev_warn(pnw->dev, "Role switch will be "
++ "performed soon, if connected OTG device "
++ "supports role switch request.\n");
++ dev_warn(pnw->dev, "It may cause data"
++ "corruption during data transfer\n");
++ }
++ }
++
++ penwell_update_transceiver();
++
++ return count;
++}
++static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUSR | S_IWGRP,
++ get_a_bus_req, set_a_bus_req);
++
++static ssize_t
++get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ char *next;
++ unsigned size;
++ unsigned t;
++
++ next = buf;
++ size = PAGE_SIZE;
++
++ t = scnprintf(next, size, "%d", pnw->iotg.hsm.a_bus_drop);
++ size -= t;
++ next += t;
++
++ return PAGE_SIZE - size;
++}
++
++static ssize_t
++set_a_bus_drop(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++
++ if (!iotg->otg.otg->default_a)
++ return -1;
++ if (count > 2)
++ return -1;
++
++ if (buf[0] == '0') {
++ iotg->hsm.a_bus_drop = 0;
++ dev_dbg(pnw->dev, "a_bus_drop = 0\n");
++ } else if (buf[0] == '1') {
++ iotg->hsm.a_bus_drop = 1;
++ iotg->hsm.a_bus_req = 0;
++ dev_dbg(pnw->dev, "a_bus_drop = 1, so a_bus_req = 0\n");
++ }
++
++ penwell_update_transceiver();
++
++ return count;
++}
++static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUSR | S_IWGRP,
++ get_a_bus_drop, set_a_bus_drop);
++
++static ssize_t
++get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ char *next;
++ unsigned size;
++ unsigned t;
++
++ next = buf;
++ size = PAGE_SIZE;
++
++ t = scnprintf(next, size, "%d", pnw->iotg.hsm.b_bus_req);
++ size -= t;
++ next += t;
++
++ return PAGE_SIZE - size;
++}
++
++static ssize_t
++set_b_bus_req(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++
++ if (iotg->otg.otg->default_a)
++ return -1;
++
++ if (count > 2)
++ return -1;
++
++ if (buf[0] == '0') {
++ iotg->hsm.b_bus_req = 0;
++ dev_dbg(pnw->dev, "b_bus_req = 0\n");
++
++ if (iotg->otg.otg->gadget)
++ iotg->otg.otg->gadget->host_request_flag = 0;
++ } else if (buf[0] == '1') {
++ iotg->hsm.b_bus_req = 1;
++ dev_dbg(pnw->dev, "b_bus_req = 1\n");
++
++ if (iotg->otg.state == OTG_STATE_B_PERIPHERAL) {
++ if (iotg->otg.otg->gadget)
++ iotg->otg.otg->gadget->host_request_flag = 1;
++
++ dev_warn(pnw->dev, "Role switch will be "
++ "performed soon, if connected OTG device "
++ "supports role switch request.\n");
++ dev_warn(pnw->dev, "It may cause data "
++ "corruption during data transfer\n");
++ }
++ }
++
++ penwell_update_transceiver();
++
++ return count;
++}
++static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUSR | S_IWGRP,
++ get_b_bus_req, set_b_bus_req);
++
++static ssize_t
++set_a_clr_err(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++
++ if (!iotg->otg.otg->default_a)
++ return -1;
++ if (iotg->otg.state != OTG_STATE_A_VBUS_ERR)
++ return -1;
++ if (count > 2)
++ return -1;
++
++ if (buf[0] == '1') {
++ iotg->hsm.a_clr_err = 1;
++ dev_dbg(pnw->dev, "a_clr_err = 1\n");
++ }
++
++ penwell_update_transceiver();
++
++ return count;
++}
++static DEVICE_ATTR(a_clr_err, S_IRUGO | S_IWUSR | S_IWGRP, NULL, set_a_clr_err);
++
++static ssize_t
++set_ulpi_err(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++
++ dev_dbg(pnw->dev, "trigger ulpi error manually\n");
++
++ iotg->hsm.ulpi_error = 1;
++
++ penwell_update_transceiver();
++
++ return count;
++}
++static DEVICE_ATTR(ulpi_err, S_IRUGO | S_IWUSR | S_IWGRP, NULL, set_ulpi_err);
++
++static struct attribute *inputs_attrs[] = {
++ &dev_attr_a_bus_req.attr,
++ &dev_attr_a_bus_drop.attr,
++ &dev_attr_b_bus_req.attr,
++ &dev_attr_a_clr_err.attr,
++ &dev_attr_ulpi_err.attr,
++ NULL,
++};
++
++static struct attribute_group debug_dev_attr_group = {
++ .name = "inputs",
++ .attrs = inputs_attrs,
++};
++
++static int penwell_otg_aca_enable(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ int retval = 0;
++ struct pci_dev *pdev;
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++
++ pdev = to_pci_dev(pnw->dev);
++
++ if (!is_clovertrail(pdev)) {
++ penwell_otg_msic_spi_access(true);
++
++ retval = intel_scu_ipc_update_register(SPI_TI_VS4,
++ TI_ACA_DET_EN, TI_ACA_DET_EN);
++ if (retval)
++ goto done;
++
++ retval = intel_scu_ipc_update_register(SPI_TI_VS5,
++ TI_ID_FLOAT_EN | TI_ID_RES_EN,
++ TI_ID_FLOAT_EN | TI_ID_RES_EN);
++ if (retval)
++ goto done;
++ } else {
++ retval = penwell_otg_ulpi_write(iotg, ULPI_VS4SET,
++ ACADET);
++ if (retval)
++ goto done;
++
++ retval = penwell_otg_ulpi_write(iotg, ULPI_VS5SET,
++ IDFLOAT_EN | IDRES_EN);
++ }
++done:
++ if (!is_clovertrail(pdev))
++ penwell_otg_msic_spi_access(false);
++
++ if (retval)
++ dev_warn(pnw->dev, "Failed to enable ACA device detection\n");
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++
++ return retval;
++}
++
++static int penwell_otg_aca_disable(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ int retval = 0;
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++
++ retval = penwell_otg_ulpi_write(iotg, ULPI_VS5CLR,
++ IDFLOAT_EN | IDRES_EN);
++ if (retval)
++ goto done;
++
++ retval = penwell_otg_ulpi_write(iotg, ULPI_VS4CLR,
++ ACADET);
++
++done:
++ if (retval)
++ dev_warn(pnw->dev, "Failed to disable ACA device detection\n");
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++
++ return retval;
++}
++
++static void penwell_spi_reset_phy(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++
++ dev_dbg(pnw->dev, "Reset Phy over SPI\n");
++ penwell_otg_msic_spi_access(true);
++ penwell_otg_msic_write(MSIC_FUNCTRLSET, PHYRESET);
++ penwell_otg_msic_spi_access(false);
++ dev_dbg(pnw->dev, "Reset Phy over SPI Done\n");
++}
++
++static int penwell_otg_probe(struct pci_dev *pdev,
++ const struct pci_device_id *id)
++{
++ unsigned long resource, len;
++ void __iomem *base = NULL;
++ int retval;
++ u32 val32;
++ struct penwell_otg *pnw;
++ char qname[] = "penwell_otg_queue";
++ char chrg_qname[] = "penwell_otg_chrg_queue";
++
++ retval = 0;
++
++ dev_info(&pdev->dev, "Intel OTG2.0 controller is detected.\n");
++ dev_info(&pdev->dev, "Driver version: " DRIVER_VERSION "\n");
++
++ if (pci_enable_device(pdev) < 0) {
++ retval = -ENODEV;
++ goto done;
++ }
++
++ pnw = kzalloc(sizeof(*pnw), GFP_KERNEL);
++ if (pnw == NULL) {
++ retval = -ENOMEM;
++ goto done;
++ }
++ the_transceiver = pnw;
++
++ /* control register: BAR 0 */
++ resource = pci_resource_start(pdev, 0);
++ len = pci_resource_len(pdev, 0);
++ if (!request_mem_region(resource, len, driver_name)) {
++ retval = -EBUSY;
++ goto err;
++ }
++ pnw->region = 1;
++
++ base = ioremap_nocache(resource, len);
++ if (base == NULL) {
++ retval = -EFAULT;
++ goto err;
++ }
++ pnw->iotg.base = base;
++
++ if (!request_mem_region(USBCFG_ADDR, USBCFG_LEN, driver_name)) {
++ retval = -EBUSY;
++ goto err;
++ }
++ pnw->cfg_region = 1;
++
++ if (!pdev->irq) {
++ dev_dbg(&pdev->dev, "No IRQ.\n");
++ retval = -ENODEV;
++ goto err;
++ }
++
++ pnw->qwork = create_singlethread_workqueue(qname);
++ if (!pnw->qwork) {
++ dev_dbg(&pdev->dev, "cannot create workqueue %s\n", qname);
++ retval = -ENOMEM;
++ goto err;
++ }
++
++ pnw->chrg_qwork = create_singlethread_workqueue(chrg_qname);
++ if (!pnw->chrg_qwork) {
++ dev_dbg(&pdev->dev, "cannot create workqueue %s\n", chrg_qname);
++ retval = -ENOMEM;
++ goto err;
++ }
++
++ INIT_LIST_HEAD(&pnw->chrg_evt_queue);
++ INIT_WORK(&pnw->work, penwell_otg_work);
++ INIT_WORK(&pnw->psc_notify, penwell_otg_psc_notify_work);
++ INIT_WORK(&pnw->hnp_poll_work, penwell_otg_hnp_poll_work);
++ INIT_WORK(&pnw->uevent_work, penwell_otg_uevent_work);
++ INIT_DELAYED_WORK(&pnw->ulpi_poll_work, penwell_otg_ulpi_poll_work);
++ INIT_DELAYED_WORK(&pnw->ulpi_check_work, penwell_otg_ulpi_check_work);
++ INIT_DELAYED_WORK(&pnw->sdp_check_work, penwell_otg_sdp_check_work);
++
++ /* OTG common part */
++ pnw->dev = &pdev->dev;
++ pnw->iotg.otg.dev = &pdev->dev;
++ pnw->iotg.otg.label = driver_name;
++ pnw->iotg.otg.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
++ if (!pnw->iotg.otg.otg) {
++ retval = -ENOMEM;
++ goto err;
++ }
++ pnw->iotg.otg.otg->set_host = penwell_otg_set_host;
++ pnw->iotg.otg.otg->set_peripheral = penwell_otg_set_peripheral;
++ pnw->iotg.otg.set_power = penwell_otg_set_power;
++ pnw->iotg.otg.otg->set_vbus = penwell_otg_set_vbus;
++ pnw->iotg.otg.otg->start_srp = penwell_otg_start_srp;
++ pnw->iotg.otg.get_chrg_status = penwell_otg_get_chrg_status;
++ pnw->iotg.set_adp_probe = NULL;
++ pnw->iotg.set_adp_sense = NULL;
++ pnw->iotg.start_hnp_poll = NULL;
++ pnw->iotg.stop_hnp_poll = NULL;
++ pnw->iotg.otg.state = OTG_STATE_UNDEFINED;
++ pnw->rt_resuming = 0;
++ pnw->rt_quiesce = 0;
++ pnw->queue_stop = 0;
++ pnw->phy_power_state = 1;
++ if (usb_add_phy(&pnw->iotg.otg, USB_PHY_TYPE_USB2)) {
++ dev_err(pnw->dev, "can't set transceiver\n");
++ retval = -EBUSY;
++ goto err;
++ }
++
++ pnw->iotg.ulpi_ops.read = penwell_otg_ulpi_read;
++ pnw->iotg.ulpi_ops.write = penwell_otg_ulpi_write;
++
++ spin_lock_init(&pnw->iotg.hnp_poll_lock);
++ spin_lock_init(&pnw->lock);
++
++ wake_lock_init(&pnw->wake_lock, WAKE_LOCK_SUSPEND, "pnw_wake_lock");
++
++ init_timer(&pnw->hsm_timer);
++ init_timer(&pnw->bus_mon_timer);
++ init_timer(&pnw->hnp_poll_timer);
++ init_completion(&pnw->adp.adp_comp);
++
++ /* Battery Charging part */
++ spin_lock_init(&pnw->charger_lock);
++ spin_lock_init(&pnw->cap_lock);
++ pnw->charging_cap.ma = CHRG_CURR_DISCONN;
++ pnw->charging_cap.chrg_type = CHRG_UNKNOWN;
++ pnw->charging_cap.current_event = USBCHRG_EVENT_DISCONN;
++ pnw->psc_cap.ma = CHRG_CURR_DISCONN;
++ pnw->psc_cap.chrg_type = POWER_SUPPLY_CHARGER_TYPE_NONE;
++ pnw->psc_cap.chrg_evt = POWER_SUPPLY_CHARGER_EVENT_DISCONNECT;
++
++ ATOMIC_INIT_NOTIFIER_HEAD(&pnw->iotg.iotg_notifier);
++ /* For generic otg notifications */
++ ATOMIC_INIT_NOTIFIER_HEAD(&pnw->iotg.otg.notifier);
++
++ pnw->iotg_notifier.notifier_call = penwell_otg_iotg_notify;
++ if (intel_mid_otg_register_notifier(&pnw->iotg, &pnw->iotg_notifier)) {
++ dev_dbg(pnw->dev, "Failed to register notifier\n");
++ retval = -EBUSY;
++ goto err;
++ }
++ if (register_pm_notifier(&pnw_sleep_pm_notifier)) {
++ dev_dbg(pnw->dev, "Fail to register PM notifier\n");
++ retval = -EBUSY;
++ goto err;
++ }
++
++ /* listen usb core events */
++ usb_register_notify(&otg_nb);
++
++ pnw->otg_pdata = pdev->dev.platform_data;
++ if (pnw->otg_pdata == NULL) {
++ dev_err(pnw->dev, "Failed to get OTG platform data.\n");
++ retval = -ENODEV;
++ goto err;
++ }
++
++ if (pnw->otg_pdata->hnp_poll_support) {
++ pnw->iotg.start_hnp_poll = penwell_otg_start_hnp_poll;
++ pnw->iotg.stop_hnp_poll = penwell_otg_stop_hnp_poll;
++ }
++
++ /* FIXME: Reads Charging compliance bit from scu mip.
++ * This snippet needs to be cleaned up after EM inteface is ready
++ */
++ if (is_clovertrail(pdev)) {
++ u8 smip_data = 0;
++ if (!intel_scu_ipc_read_mip(&smip_data, 1, 0x2e7, 1)) {
++ pnw->otg_pdata->charging_compliance =
++ !(smip_data & 0x40);
++ dev_info(pnw->dev, "charging_compliance = %d\n",
++ pnw->otg_pdata->charging_compliance);
++ } else
++ dev_err(pnw->dev, "scu mip read error\n");
++ }
++
++ if (!is_clovertrail(pdev)) {
++ if (pnw->otg_pdata->gpio_vbus) {
++ retval = gpio_request(pnw->otg_pdata->gpio_vbus,
++ "usb_otg_phy_reset");
++ if (retval < 0) {
++ dev_err(pnw->dev, "request gpio(%d) failed\n",
++ pnw->otg_pdata->gpio_vbus);
++ retval = -ENODEV;
++ goto err;
++ }
++ }
++ }
++
++ if (is_clovertrail(pdev)) {
++ /* Set up gpio for Clovertrail */
++ retval = gpio_request(pnw->otg_pdata->gpio_reset,
++ "usb_otg_phy_reset");
++ if (retval < 0) {
++ dev_err(pnw->dev, "request phy reset gpio(%d) failed\n",
++ pnw->otg_pdata->gpio_reset);
++ retval = -ENODEV;
++ goto err;
++ }
++ retval = gpio_request(pnw->otg_pdata->gpio_cs,
++ "usb_otg_phy_cs");
++ if (retval < 0) {
++ dev_err(pnw->dev, "request phy cs gpio(%d) failed\n",
++ pnw->otg_pdata->gpio_cs);
++ gpio_free(pnw->otg_pdata->gpio_reset);
++ retval = -ENODEV;
++ goto err;
++ }
++ }
++
++ penwell_otg_phy_power(1);
++ penwell_otg_phy_reset();
++
++ mutex_init(&pnw->msic_mutex);
++ pnw->msic = penwell_otg_check_msic();
++
++ penwell_otg_phy_low_power(0);
++
++ if (!is_clovertrail(pdev)) {
++ /* Workaround for ULPI lockup issue, need turn off PHY 4ms */
++ penwell_otg_phy_enable(0);
++ usleep_range(4000, 4500);
++ penwell_otg_phy_enable(1);
++ /* reset phy */
++ dev_dbg(pnw->dev, "Reset Phy over SPI\n");
++ penwell_otg_msic_spi_access(true);
++ penwell_otg_msic_write(MSIC_FUNCTRLSET, PHYRESET);
++ penwell_otg_msic_spi_access(false);
++ dev_dbg(pnw->dev, "Reset Phy over SPI Done\n");
++ }
++
++ /* Enable ID pullup immediately after reeable PHY */
++ val32 = readl(pnw->iotg.base + CI_OTGSC);
++ writel(val32 | OTGSC_IDPU, pnw->iotg.base + CI_OTGSC);
++
++ /* Wait correct value to be synced */
++ set_host_mode();
++ usleep_range(2000, 3000);
++ penwell_otg_phy_low_power(1);
++ msleep(100);
++
++ /* enable ACA device detection for CTP */
++ if (is_clovertrail(pdev))
++ penwell_otg_aca_enable();
++
++ reset_otg();
++ init_hsm();
++
++ /* we need to set active early or the first irqs will be ignored */
++ pm_runtime_set_active(&pdev->dev);
++
++ if (request_irq(pdev->irq, otg_irq, IRQF_SHARED,
++ driver_name, pnw) != 0) {
++ dev_dbg(pnw->dev,
++ "request interrupt %d failed\n", pdev->irq);
++ retval = -EBUSY;
++ goto err;
++ }
++
++ /* enable OTGSC int */
++ val32 = OTGSC_DPIE | OTGSC_BSEIE | OTGSC_BSVIE |
++ OTGSC_ASVIE | OTGSC_AVVIE | OTGSC_IDIE | OTGSC_IDPU;
++ writel(val32, pnw->iotg.base + CI_OTGSC);
++
++ retval = device_create_file(&pdev->dev, &dev_attr_registers);
++ if (retval < 0) {
++ dev_dbg(pnw->dev,
++ "Can't register sysfs attribute: %d\n", retval);
++ goto err;
++ }
++
++ retval = device_create_file(&pdev->dev, &dev_attr_hsm);
++ if (retval < 0) {
++ dev_dbg(pnw->dev,
++ "Can't hsm sysfs attribute: %d\n", retval);
++ goto err;
++ }
++
++ retval = device_create_file(&pdev->dev, &dev_attr_chargers);
++ if (retval < 0) {
++ dev_dbg(pnw->dev,
++ "Can't chargers sysfs attribute: %d\n", retval);
++ goto err;
++ }
++
++ retval = sysfs_create_group(&pdev->dev.kobj, &debug_dev_attr_group);
++ if (retval < 0) {
++ dev_dbg(pnw->dev,
++ "Can't register sysfs attr group: %d\n", retval);
++ goto err;
++ }
++
++ pm_runtime_put_noidle(&pdev->dev);
++ pm_runtime_allow(&pdev->dev);
++
++ penwell_update_transceiver();
++
++ return 0;
++
++err:
++ if (the_transceiver)
++ penwell_otg_remove(pdev);
++done:
++ return retval;
++}
++
++static void penwell_otg_remove(struct pci_dev *pdev)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct otg_bc_event *evt, *tmp;
++
++ /* ACA device detection disable */
++ penwell_otg_aca_disable();
++
++ pm_runtime_get_noresume(&pdev->dev);
++ pm_runtime_forbid(&pdev->dev);
++
++ if (pnw->qwork) {
++ flush_workqueue(pnw->qwork);
++ destroy_workqueue(pnw->qwork);
++ }
++
++ if (pnw->chrg_qwork) {
++ flush_workqueue(pnw->chrg_qwork);
++ destroy_workqueue(pnw->chrg_qwork);
++ list_for_each_entry_safe(evt, tmp, &pnw->chrg_evt_queue, node) {
++ list_del(&evt->node);
++ kfree(evt);
++ }
++ }
++
++ /* disable OTGSC interrupt as OTGSC doesn't change in reset */
++ writel(0, pnw->iotg.base + CI_OTGSC);
++
++ wake_lock_destroy(&pnw->wake_lock);
++
++ if (pdev->irq)
++ free_irq(pdev->irq, pnw);
++ if (pnw->cfg_region)
++ release_mem_region(USBCFG_ADDR, USBCFG_LEN);
++ if (pnw->iotg.base)
++ iounmap(pnw->iotg.base);
++ kfree(pnw->iotg.otg.otg);
++ if (pnw->region)
++ release_mem_region(pci_resource_start(pdev, 0),
++ pci_resource_len(pdev, 0));
++
++ usb_remove_phy(&pnw->iotg.otg);
++ pci_disable_device(pdev);
++ sysfs_remove_group(&pdev->dev.kobj, &debug_dev_attr_group);
++ device_remove_file(&pdev->dev, &dev_attr_chargers);
++ device_remove_file(&pdev->dev, &dev_attr_hsm);
++ device_remove_file(&pdev->dev, &dev_attr_registers);
++ usb_unregister_notify(&otg_nb);
++ kfree(pnw);
++ pnw = NULL;
++}
++
++void penwell_otg_shutdown(struct pci_dev *pdev)
++{
++ struct penwell_otg *pnw = the_transceiver;
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++
++ if (!is_clovertrail(pdev)) {
++ /* Disable MSIC Interrupt Notifications */
++ penwell_otg_msic_spi_access(true);
++
++ penwell_otg_msic_write(MSIC_INT_EN_RISE_CLR, 0x1F);
++ penwell_otg_msic_write(MSIC_INT_EN_FALL_CLR, 0x1F);
++
++ penwell_otg_msic_spi_access(false);
++ }
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++}
++
++
++static int penwell_otg_suspend_noirq(struct device *dev)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ int ret = 0;
++ unsigned long flags;
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++
++ switch (iotg->otg.state) {
++ case OTG_STATE_A_VBUS_ERR:
++ set_host_mode();
++ iotg->otg.state = OTG_STATE_A_IDLE;
++ break;
++ case OTG_STATE_A_WAIT_VFALL:
++ penwell_otg_del_timer(TA_WAIT_VFALL_TMR);
++ iotg->otg.state = OTG_STATE_A_IDLE;
++ case OTG_STATE_A_IDLE:
++ case OTG_STATE_B_IDLE:
++ break;
++ case OTG_STATE_A_WAIT_VRISE:
++ penwell_otg_del_timer(TA_WAIT_VRISE_TMR);
++ iotg->hsm.a_srp_det = 0;
++
++ /* Turn off VBus */
++ otg_set_vbus(iotg->otg.otg, false);
++ iotg->otg.state = OTG_STATE_A_IDLE;
++ break;
++ case OTG_STATE_A_WAIT_BCON:
++ case OTG_STATE_A_HOST:
++ if (pnw->iotg.suspend_noirq_host)
++ ret = pnw->iotg.suspend_noirq_host(&pnw->iotg);
++ goto done;
++ break;
++ case OTG_STATE_A_SUSPEND:
++ penwell_otg_del_timer(TA_AIDL_BDIS_TMR);
++ penwell_otg_HABA(0);
++ PNW_STOP_HOST(pnw);
++ iotg->hsm.a_srp_det = 0;
++
++ penwell_otg_phy_vbus_wakeup(false);
++
++ /* Turn off VBus */
++ otg_set_vbus(iotg->otg.otg, false);
++ iotg->otg.state = OTG_STATE_A_IDLE;
++ break;
++ case OTG_STATE_A_PERIPHERAL:
++ penwell_otg_del_timer(TA_BIDL_ADIS_TMR);
++
++ if (pnw->iotg.stop_peripheral)
++ pnw->iotg.stop_peripheral(&pnw->iotg);
++ else
++ dev_dbg(pnw->dev, "client driver has been stopped.\n");
++
++ /* Turn off VBus */
++ otg_set_vbus(iotg->otg.otg, false);
++ iotg->hsm.a_srp_det = 0;
++ iotg->otg.state = OTG_STATE_A_IDLE;
++ break;
++ case OTG_STATE_B_HOST:
++ /* Stop HNP polling */
++ if (iotg->stop_hnp_poll)
++ iotg->stop_hnp_poll(iotg);
++
++ PNW_STOP_HOST(pnw);
++ iotg->hsm.b_bus_req = 0;
++ iotg->otg.state = OTG_STATE_B_IDLE;
++ break;
++ case OTG_STATE_B_PERIPHERAL:
++ dev_dbg(pnw->dev, "don't suspend, client still alive\n");
++ ret = -EBUSY;
++ break;
++ case OTG_STATE_B_WAIT_ACON:
++ penwell_otg_del_timer(TB_ASE0_BRST_TMR);
++
++ penwell_otg_HAAR(0);
++
++ PNW_STOP_HOST(pnw);
++ iotg->hsm.b_bus_req = 0;
++ iotg->otg.state = OTG_STATE_B_IDLE;
++ break;
++ default:
++ dev_dbg(pnw->dev, "error state before suspend\n");
++ break;
++ }
++
++
++ if (ret) {
++ spin_lock_irqsave(&pnw->lock, flags);
++ pnw->queue_stop = 0;
++ spin_unlock_irqrestore(&pnw->lock, flags);
++
++ penwell_update_transceiver();
++ } else {
++ penwell_otg_phy_low_power(1);
++ penwell_otg_vusb330_low_power(1);
++#ifdef CONFIG_USB_PENWELL_OTG_PHY_OFF
++ if (iotg->otg.state == OTG_STATE_B_IDLE) {
++ penwell_otg_phy_power(0);
++ pnw->phy_power_state = 0;
++ }
++#endif
++ }
++
++done:
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++ return ret;
++}
++
++static int penwell_otg_suspend(struct device *dev)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ int ret = 0;
++ unsigned long flags;
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++
++ if (iotg->otg.state == OTG_STATE_B_PERIPHERAL) {
++ dev_dbg(pnw->dev, "still alive, don't suspend\n");
++ ret = -EBUSY;
++ goto done;
++ }
++
++ /* quiesce any work scheduled */
++ spin_lock_irqsave(&pnw->lock, flags);
++ pnw->queue_stop = 1;
++ spin_unlock_irqrestore(&pnw->lock, flags);
++ flush_workqueue(pnw->qwork);
++ if (delayed_work_pending(&pnw->ulpi_check_work)) {
++ spin_lock_irqsave(&pnw->lock, flags);
++ pnw->queue_stop = 0;
++ spin_unlock_irqrestore(&pnw->lock, flags);
++ ret = -EBUSY;
++ goto done;
++ } else
++ flush_delayed_work_sync(&pnw->ulpi_check_work);
++
++ switch (iotg->otg.state) {
++ case OTG_STATE_A_WAIT_BCON:
++ penwell_otg_del_timer(TA_WAIT_BCON_TMR);
++ iotg->hsm.a_srp_det = 0;
++ if (iotg->suspend_host)
++ ret = iotg->suspend_host(iotg);
++ break;
++ case OTG_STATE_A_HOST:
++ if (iotg->stop_hnp_poll)
++ iotg->stop_hnp_poll(iotg);
++ if (iotg->suspend_host)
++ ret = iotg->suspend_host(iotg);
++ break;
++ default:
++ break;
++ }
++
++done:
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++ return ret;
++}
++
++static void penwell_otg_dump_bogus_wake(void)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ int addr = 0x2C8, retval;
++ u8 val;
++
++ /* Enable SPI access */
++ penwell_otg_msic_spi_access(true);
++
++ retval = penwell_otg_msic_read(addr, &val);
++ if (retval) {
++ dev_err(pnw->dev, "msic read failed\n");
++ goto out;
++ }
++ dev_info(pnw->dev, "0x%03x: 0x%02x", addr, val);
++
++ for (addr = 0x340; addr <= 0x348; addr++) {
++ retval = penwell_otg_msic_read(addr, &val);
++ if (retval) {
++ dev_err(pnw->dev, "msic read failed\n");
++ goto out;
++ }
++ dev_info(pnw->dev, "0x%03x: 0x%02x", addr, val);
++ }
++
++ for (addr = 0x394; addr <= 0x3BF; addr++) {
++ retval = penwell_otg_msic_read(addr, &val);
++ if (retval) {
++ dev_err(pnw->dev, "msic read failed\n");
++ goto out;
++ }
++ dev_info(pnw->dev, "0x%03x: 0x%02x", addr, val);
++ }
++
++ addr = 0x192;
++ retval = penwell_otg_msic_read(addr, &val);
++ if (retval) {
++ dev_err(pnw->dev, "msic read failed\n");
++ goto out;
++ }
++
++ dev_info(pnw->dev, "0x%03x: 0x%02x", addr, val);
++out:
++ penwell_otg_msic_spi_access(false);
++}
++
++static int penwell_otg_resume_noirq(struct device *dev)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ struct pci_dev *pdev;
++ int ret = 0;
++ u32 val;
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++
++ pdev = to_pci_dev(pnw->dev);
++
++ /* If USB PHY is in OFF state, power on it and do basic init work */
++ if (!pnw->phy_power_state) {
++ penwell_otg_phy_power(1);
++ /* Change phy_power_state to 1 again */
++ pnw->phy_power_state = 1;
++ penwell_otg_phy_reset();
++
++ /* Reset controller and clear PHY low power mode setting */
++ reset_otg();
++ penwell_otg_phy_low_power(0);
++
++ /* Wait ID value to be synced */
++ msleep(60);
++ }
++
++ /* add delay in case controller is back to D0, controller
++ * needs time to sync/latch value for OTGSC register */
++ usleep_range(2000, 2500);
++
++ if (mid_pmu_is_wake_source(PMU_OTG_WAKE_SOURCE)) {
++ /* dump OTGSC register for wakeup event */
++ val = readl(pnw->iotg.base + CI_OTGSC);
++ dev_info(pnw->dev, "%s: CI_OTGSC=0x%x\n", __func__, val);
++ if (val & OTGSC_IDIS)
++ dev_info(pnw->dev, "%s: id change\n", __func__);
++ if (val & OTGSC_DPIS)
++ dev_info(pnw->dev, "%s: data pulse\n", __func__);
++ if (val & OTGSC_BSEIS)
++ dev_info(pnw->dev, "%s: b sess end\n", __func__);
++ if (val & OTGSC_BSVIS)
++ dev_info(pnw->dev, "%s: b sess valid\n", __func__);
++ if (val & OTGSC_ASVIS)
++ dev_info(pnw->dev, "%s: a sess valid\n", __func__);
++ if (val & OTGSC_AVVIS)
++ dev_info(pnw->dev, "%s: a vbus valid\n", __func__);
++
++ if (!(val & OTGSC_INTSTS_MASK)) {
++ static bool uevent_reported;
++ dev_info(pnw->dev,
++ "%s: waking up from USB source, but not a OTG wakeup event\n",
++ __func__);
++ if (!uevent_reported) {
++ if (!is_clovertrail(pdev))
++ penwell_otg_dump_bogus_wake();
++ queue_work(pnw->qwork, &pnw->uevent_work);
++ uevent_reported = true;
++ }
++ }
++ }
++
++ if (iotg->otg.state != OTG_STATE_A_WAIT_BCON &&
++ iotg->otg.state != OTG_STATE_A_HOST) {
++ penwell_otg_vusb330_low_power(0);
++ penwell_otg_phy_low_power(0);
++ }
++
++ /* D3->D0 controller will be reset, so reset work mode and PHY state
++ * which is cleared by the reset */
++
++ switch (pnw->iotg.otg.state) {
++ case OTG_STATE_B_IDLE:
++ break;
++ case OTG_STATE_A_WAIT_BCON:
++ case OTG_STATE_A_HOST:
++ if (iotg->resume_noirq_host)
++ ret = iotg->resume_noirq_host(iotg);
++ break;
++ default:
++ break;
++ }
++
++
++ /* We didn't disable otgsc interrupt, to prevent intr from happening
++ * before penwell_otg_resume, intr is disabled here, and can be enabled
++ * by penwell_otg_resume
++ */
++ penwell_otg_intr(0);
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++ return ret;
++}
++
++static int penwell_otg_resume(struct device *dev)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct intel_mid_otg_xceiv *iotg = &pnw->iotg;
++ int ret = 0;
++ unsigned long flags;
++
++ dev_dbg(pnw->dev, "%s --->\n", __func__);
++ switch (iotg->otg.state) {
++ case OTG_STATE_A_WAIT_BCON:
++ if (iotg->resume_host)
++ ret = iotg->resume_host(iotg);
++ penwell_otg_add_timer(TA_WAIT_BCON_TMR);
++ break;
++ case OTG_STATE_A_HOST:
++ if (iotg->resume_host)
++ ret = iotg->resume_host(iotg);
++
++ /* FIXME: Ideally here should re-start HNP polling,
++ * no start HNP here, because it blocks the resume
++ */
++ break;
++ default:
++ break;
++ }
++
++ if (ret)
++ return ret;
++
++ /* allow queue work from notifier */
++ spin_lock_irqsave(&pnw->lock, flags);
++ pnw->queue_stop = 0;
++ spin_unlock_irqrestore(&pnw->lock, flags);
++
++ penwell_otg_intr(1);
++
++ /* If a plugging in or pluggout event happens during D3,
++ * we will miss the interrupt, so check OTGSC here to check
++ * if any ID change and update hsm correspondingly
++ */
++ update_hsm();
++ penwell_update_transceiver();
++
++ dev_dbg(pnw->dev, "%s <---\n", __func__);
++ return ret;
++}
++
++
++#ifdef CONFIG_PM_RUNTIME
++/* Runtime PM */
++static int penwell_otg_runtime_suspend(struct device *dev)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ struct pci_dev *pdev = to_pci_dev(dev);
++ int ret = 0;
++ u32 val;
++ unsigned long flags;
++
++ dev_dbg(dev, "%s --->\n", __func__);
++
++ pnw->rt_quiesce = 1;
++
++ /* Flush any pending otg irq on local or any other CPUs.
++ *
++ * Host mode or Device mode irq should be synchronized by itself in
++ * their runtime_suspend handler. In fact, Host mode does so. For
++ * device mode, we don't care as its runtime PM is disabled.
++ *
++ * As device's runtime_status is already RPM_SUSPENDING, after flushing,
++ * any new irq handling will be rejected (otg irq handler only continues
++ * if runtime_status is RPM_ACTIVE).
++ * Thus, now it's safe to put PHY into low power mode and gate the
++ * fabric later in pci_set_power_state().
++ */
++ synchronize_irq(pdev->irq);
++
++ switch (pnw->iotg.otg.state) {
++ case OTG_STATE_A_IDLE:
++ break;
++ case OTG_STATE_B_IDLE:
++ val = readl(pnw->iotg.base + CI_USBMODE);
++ if (!(val & USBMODE_CM)) {
++ /* Controller needs to reset & set mode */
++ dev_dbg(dev, "reset to client mode\n");
++ set_client_mode();
++ }
++ break;
++ case OTG_STATE_A_WAIT_BCON:
++ case OTG_STATE_A_HOST:
++ case OTG_STATE_A_SUSPEND:
++ if (pnw->iotg.runtime_suspend_host)
++ ret = pnw->iotg.runtime_suspend_host(&pnw->iotg);
++ break;
++ case OTG_STATE_A_PERIPHERAL:
++ case OTG_STATE_B_PERIPHERAL:
++ if (pnw->iotg.runtime_suspend_peripheral)
++ ret = pnw->iotg.runtime_suspend_peripheral(&pnw->iotg);
++ break;
++ default:
++ break;
++ }
++
++ if (ret) {
++ spin_lock_irqsave(&pnw->lock, flags);
++ pnw->rt_quiesce = 0;
++ if (pnw->rt_resuming) {
++ pnw->rt_resuming = 0;
++ pm_runtime_put(pnw->dev);
++ }
++ spin_unlock_irqrestore(&pnw->lock, flags);
++ goto DONE;
++ }
++
++ penwell_otg_phy_low_power(1);
++
++ msleep(2);
++
++ penwell_otg_vusb330_low_power(1);
++
++DONE:
++ dev_dbg(dev, "%s <---: ret = %d\n", __func__, ret);
++ return ret;
++}
++
++static int penwell_otg_runtime_resume(struct device *dev)
++{
++ struct penwell_otg *pnw = the_transceiver;
++ int ret = 0;
++ u32 val;
++ unsigned long flags;
++
++ dev_dbg(dev, "%s --->\n", __func__);
++
++ penwell_otg_phy_low_power(0);
++ penwell_otg_vusb330_low_power(0);
++ /* waiting for hardware stable */
++ usleep_range(2000, 4000);
++
++ switch (pnw->iotg.otg.state) {
++ case OTG_STATE_A_IDLE:
++ break;
++ case OTG_STATE_B_IDLE:
++ val = readl(pnw->iotg.base + CI_USBMODE);
++ if (!(val & USBMODE_CM)) {
++ /* Controller needs to reset & set mode */
++ dev_dbg(dev, "reset to client mode\n");
++ set_client_mode();
++ }
++ break;
++ case OTG_STATE_A_WAIT_BCON:
++ case OTG_STATE_A_HOST:
++ case OTG_STATE_A_SUSPEND:
++ if (pnw->iotg.runtime_resume_host)
++ ret = pnw->iotg.runtime_resume_host(&pnw->iotg);
++ break;
++ case OTG_STATE_A_PERIPHERAL:
++ case OTG_STATE_B_PERIPHERAL:
++ if (pnw->iotg.runtime_resume_peripheral)
++ ret = pnw->iotg.runtime_resume_peripheral(&pnw->iotg);
++ break;
++ default:
++ break;
++ }
++
++ spin_lock_irqsave(&pnw->lock, flags);
++ pnw->rt_quiesce = 0;
++ if (pnw->rt_resuming) {
++ pnw->rt_resuming = 0;
++ pm_runtime_put(pnw->dev);
++ }
++ spin_unlock_irqrestore(&pnw->lock, flags);
++
++ dev_dbg(dev, "%s <---\n", __func__);
++
++ return ret;
++}
++
++static int penwell_otg_runtime_idle(struct device *dev)
++{
++ struct penwell_otg *pnw = the_transceiver;
++
++ dev_dbg(dev, "%s --->\n", __func__);
++
++ switch (pnw->iotg.otg.state) {
++ case OTG_STATE_A_WAIT_VRISE:
++ case OTG_STATE_A_WAIT_VFALL:
++ case OTG_STATE_A_VBUS_ERR:
++ case OTG_STATE_B_WAIT_ACON:
++ case OTG_STATE_B_HOST:
++ dev_dbg(dev, "Keep in active\n");
++ dev_dbg(dev, "%s <---\n", __func__);
++ return -EBUSY;
++ case OTG_STATE_A_WAIT_BCON:
++ case OTG_STATE_A_HOST:
++ /* Schedule runtime_suspend without delay */
++ pm_schedule_suspend(dev, 0);
++ dev_dbg(dev, "%s <---\n", __func__);
++ return -EBUSY;
++ default:
++ break;
++ }
++
++ /* some delay for stability */
++ pm_schedule_suspend(dev, 500);
++
++ dev_dbg(dev, "%s <---\n", __func__);
++
++ return -EBUSY;
++}
++
++#else
++
++#define penwell_otg_runtime_suspend NULL
++#define penwell_otg_runtime_resume NULL
++#define penwell_otg_runtime_idle NULL
++
++#endif
++
++/*----------------------------------------------------------*/
++
++DEFINE_PCI_DEVICE_TABLE(pci_ids) = {{
++ .class = ((PCI_CLASS_SERIAL_USB << 8) | 0x20),
++ .class_mask = ~0,
++ .vendor = 0x8086,
++ .device = 0x0829,
++ .subvendor = PCI_ANY_ID,
++ .subdevice = PCI_ANY_ID,
++ },
++ { /* Cloverview */
++ .class = ((PCI_CLASS_SERIAL_USB << 8) | 0x20),
++ .class_mask = ~0,
++ .vendor = 0x8086,
++ .device = 0xE006,
++ .subvendor = PCI_ANY_ID,
++ .subdevice = PCI_ANY_ID,
++ },
++ { /* end: all zeroes */ }
++};
++
++static const struct dev_pm_ops penwell_otg_pm_ops = {
++ .runtime_suspend = penwell_otg_runtime_suspend,
++ .runtime_resume = penwell_otg_runtime_resume,
++ .runtime_idle = penwell_otg_runtime_idle,
++ .suspend = penwell_otg_suspend,
++ .suspend_noirq = penwell_otg_suspend_noirq,
++ .resume = penwell_otg_resume,
++ .resume_noirq = penwell_otg_resume_noirq,
++};
++
++static struct pci_driver otg_pci_driver = {
++ .name = (char *) driver_name,
++ .id_table = pci_ids,
++
++ .probe = penwell_otg_probe,
++ .remove = penwell_otg_remove,
++ .shutdown = penwell_otg_shutdown,
++ .driver = {
++ .pm = &penwell_otg_pm_ops
++ },
++};
++
++static int __init penwell_otg_init(void)
++{
++#ifdef CONFIG_DEBUG_FS
++ pm_sss0_base = ioremap_nocache(0xFF11D030, 0x100);
++#endif
++ return pci_register_driver(&otg_pci_driver);
++}
++module_init(penwell_otg_init);
++
++static void __exit penwell_otg_cleanup(void)
++{
++#ifdef CONFIG_DEBUG_FS
++ iounmap(pm_sss0_base);
++#endif
++ pci_unregister_driver(&otg_pci_driver);
++}
++module_exit(penwell_otg_cleanup);
+diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
+index e89fc31..8b660e7 100644
+--- a/drivers/watchdog/Kconfig
++++ b/drivers/watchdog/Kconfig
+@@ -615,6 +615,27 @@ config INTEL_SCU_WATCHDOG
+
+ To compile this driver as a module, choose M here.
+
++config INTEL_SCU_WATCHDOG_EVO
++ bool "Intel SCU Watchdog Evolution for Mobile Platforms"
++ depends on X86_INTEL_MID
++ ---help---
++ Hardware driver evolution for the watchdog timer built into the Intel
++ SCU for Intel Mobile Platforms.
++
++ This driver supports the watchdog evolution implementation in SCU,
++ available for Merrifield generation.
++
++ To compile this driver as a module, choose M here.
++
++config DISABLE_SCU_WATCHDOG
++ bool "De-activate Intel SCU Watchdog by cmdline for Mobile Platforms"
++ depends on INTEL_SCU_WATCHDOG || INTEL_SCU_WATCHDOG_EVO
++ ---help---
++ De-activate the watchdog by cmdline for Intel Mobile Platforms.
++ This allows to use breakpoints without resetting.
++
++ Only for debug purpose.
++
+ config ITCO_WDT
+ tristate "Intel TCO Timer/Watchdog"
+ depends on (X86 || IA64) && PCI
+diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
+index a300b94..2d3cdd5 100644
+--- a/drivers/watchdog/Makefile
++++ b/drivers/watchdog/Makefile
+@@ -110,6 +110,7 @@ obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
+ obj-$(CONFIG_MACHZ_WDT) += machzwd.o
+ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
+ obj-$(CONFIG_INTEL_SCU_WATCHDOG) += intel_scu_watchdog.o
++obj-$(CONFIG_INTEL_SCU_WATCHDOG_EVO) += intel_scu_watchdog_evo.o
+
+ # M32R Architecture
+
+diff --git a/drivers/watchdog/intel_scu_watchdog.c b/drivers/watchdog/intel_scu_watchdog.c
+deleted file mode 100644
+index 9dda2d0..0000000
+--- a/drivers/watchdog/intel_scu_watchdog.c
++++ /dev/null
+@@ -1,568 +0,0 @@
+-/*
+- * Intel_SCU 0.2: An Intel SCU IOH Based Watchdog Device
+- * for Intel part #(s):
+- * - AF82MP20 PCH
+- *
+- * Copyright (C) 2009-2010 Intel Corporation. All rights reserved.
+- *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of version 2 of the GNU General
+- * Public License as published by the Free Software Foundation.
+- *
+- * This program is distributed in the hope that it will be
+- * useful, but WITHOUT ANY WARRANTY; without even the implied
+- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+- * PURPOSE. See the GNU General Public License for more details.
+- * You should have received a copy of the GNU General Public
+- * License along with this program; if not, write to the Free
+- * Software Foundation, Inc., 59 Temple Place - Suite 330,
+- * Boston, MA 02111-1307, USA.
+- * The full GNU General Public License is included in this
+- * distribution in the file called COPYING.
+- *
+- */
+-
+-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+-
+-#include <linux/compiler.h>
+-#include <linux/module.h>
+-#include <linux/kernel.h>
+-#include <linux/moduleparam.h>
+-#include <linux/types.h>
+-#include <linux/miscdevice.h>
+-#include <linux/watchdog.h>
+-#include <linux/fs.h>
+-#include <linux/notifier.h>
+-#include <linux/reboot.h>
+-#include <linux/init.h>
+-#include <linux/jiffies.h>
+-#include <linux/uaccess.h>
+-#include <linux/slab.h>
+-#include <linux/io.h>
+-#include <linux/interrupt.h>
+-#include <linux/delay.h>
+-#include <linux/sched.h>
+-#include <linux/signal.h>
+-#include <linux/sfi.h>
+-#include <asm/irq.h>
+-#include <linux/atomic.h>
+-#include <asm/intel_scu_ipc.h>
+-#include <asm/apb_timer.h>
+-#include <asm/mrst.h>
+-
+-#include "intel_scu_watchdog.h"
+-
+-/* Bounds number of times we will retry loading time count */
+-/* This retry is a work around for a silicon bug. */
+-#define MAX_RETRY 16
+-
+-#define IPC_SET_WATCHDOG_TIMER 0xF8
+-
+-static int timer_margin = DEFAULT_SOFT_TO_HARD_MARGIN;
+-module_param(timer_margin, int, 0);
+-MODULE_PARM_DESC(timer_margin,
+- "Watchdog timer margin"
+- "Time between interrupt and resetting the system"
+- "The range is from 1 to 160"
+- "This is the time for all keep alives to arrive");
+-
+-static int timer_set = DEFAULT_TIME;
+-module_param(timer_set, int, 0);
+-MODULE_PARM_DESC(timer_set,
+- "Default Watchdog timer setting"
+- "Complete cycle time"
+- "The range is from 1 to 170"
+- "This is the time for all keep alives to arrive");
+-
+-/* After watchdog device is closed, check force_boot. If:
+- * force_boot == 0, then force boot on next watchdog interrupt after close,
+- * force_boot == 1, then force boot immediately when device is closed.
+- */
+-static int force_boot;
+-module_param(force_boot, int, 0);
+-MODULE_PARM_DESC(force_boot,
+- "A value of 1 means that the driver will reboot"
+- "the system immediately if the /dev/watchdog device is closed"
+- "A value of 0 means that when /dev/watchdog device is closed"
+- "the watchdog timer will be refreshed for one more interval"
+- "of length: timer_set. At the end of this interval, the"
+- "watchdog timer will reset the system."
+- );
+-
+-/* there is only one device in the system now; this can be made into
+- * an array in the future if we have more than one device */
+-
+-static struct intel_scu_watchdog_dev watchdog_device;
+-
+-/* Forces restart, if force_reboot is set */
+-static void watchdog_fire(void)
+-{
+- if (force_boot) {
+- pr_crit("Initiating system reboot\n");
+- emergency_restart();
+- pr_crit("Reboot didn't ?????\n");
+- }
+-
+- else {
+- pr_crit("Immediate Reboot Disabled\n");
+- pr_crit("System will reset when watchdog timer times out!\n");
+- }
+-}
+-
+-static int check_timer_margin(int new_margin)
+-{
+- if ((new_margin < MIN_TIME_CYCLE) ||
+- (new_margin > MAX_TIME - timer_set)) {
+- pr_debug("value of new_margin %d is out of the range %d to %d\n",
+- new_margin, MIN_TIME_CYCLE, MAX_TIME - timer_set);
+- return -EINVAL;
+- }
+- return 0;
+-}
+-
+-/*
+- * IPC operations
+- */
+-static int watchdog_set_ipc(int soft_threshold, int threshold)
+-{
+- u32 *ipc_wbuf;
+- u8 cbuf[16] = { '\0' };
+- int ipc_ret = 0;
+-
+- ipc_wbuf = (u32 *)&cbuf;
+- ipc_wbuf[0] = soft_threshold;
+- ipc_wbuf[1] = threshold;
+-
+- ipc_ret = intel_scu_ipc_command(
+- IPC_SET_WATCHDOG_TIMER,
+- 0,
+- ipc_wbuf,
+- 2,
+- NULL,
+- 0);
+-
+- if (ipc_ret != 0)
+- pr_err("Error setting SCU watchdog timer: %x\n", ipc_ret);
+-
+- return ipc_ret;
+-};
+-
+-/*
+- * Intel_SCU operations
+- */
+-
+-/* timer interrupt handler */
+-static irqreturn_t watchdog_timer_interrupt(int irq, void *dev_id)
+-{
+- int int_status;
+- int_status = ioread32(watchdog_device.timer_interrupt_status_addr);
+-
+- pr_debug("irq, int_status: %x\n", int_status);
+-
+- if (int_status != 0)
+- return IRQ_NONE;
+-
+- /* has the timer been started? If not, then this is spurious */
+- if (watchdog_device.timer_started == 0) {
+- pr_debug("spurious interrupt received\n");
+- return IRQ_HANDLED;
+- }
+-
+- /* temporarily disable the timer */
+- iowrite32(0x00000002, watchdog_device.timer_control_addr);
+-
+- /* set the timer to the threshold */
+- iowrite32(watchdog_device.threshold,
+- watchdog_device.timer_load_count_addr);
+-
+- /* allow the timer to run */
+- iowrite32(0x00000003, watchdog_device.timer_control_addr);
+-
+- return IRQ_HANDLED;
+-}
+-
+-static int intel_scu_keepalive(void)
+-{
+-
+- /* read eoi register - clears interrupt */
+- ioread32(watchdog_device.timer_clear_interrupt_addr);
+-
+- /* temporarily disable the timer */
+- iowrite32(0x00000002, watchdog_device.timer_control_addr);
+-
+- /* set the timer to the soft_threshold */
+- iowrite32(watchdog_device.soft_threshold,
+- watchdog_device.timer_load_count_addr);
+-
+- /* allow the timer to run */
+- iowrite32(0x00000003, watchdog_device.timer_control_addr);
+-
+- return 0;
+-}
+-
+-static int intel_scu_stop(void)
+-{
+- iowrite32(0, watchdog_device.timer_control_addr);
+- return 0;
+-}
+-
+-static int intel_scu_set_heartbeat(u32 t)
+-{
+- int ipc_ret;
+- int retry_count;
+- u32 soft_value;
+- u32 hw_pre_value;
+- u32 hw_value;
+-
+- watchdog_device.timer_set = t;
+- watchdog_device.threshold =
+- timer_margin * watchdog_device.timer_tbl_ptr->freq_hz;
+- watchdog_device.soft_threshold =
+- (watchdog_device.timer_set - timer_margin)
+- * watchdog_device.timer_tbl_ptr->freq_hz;
+-
+- pr_debug("set_heartbeat: timer freq is %d\n",
+- watchdog_device.timer_tbl_ptr->freq_hz);
+- pr_debug("set_heartbeat: timer_set is %x (hex)\n",
+- watchdog_device.timer_set);
+- pr_debug("set_hearbeat: timer_margin is %x (hex)\n", timer_margin);
+- pr_debug("set_heartbeat: threshold is %x (hex)\n",
+- watchdog_device.threshold);
+- pr_debug("set_heartbeat: soft_threshold is %x (hex)\n",
+- watchdog_device.soft_threshold);
+-
+- /* Adjust thresholds by FREQ_ADJUSTMENT factor, to make the */
+- /* watchdog timing come out right. */
+- watchdog_device.threshold =
+- watchdog_device.threshold / FREQ_ADJUSTMENT;
+- watchdog_device.soft_threshold =
+- watchdog_device.soft_threshold / FREQ_ADJUSTMENT;
+-
+- /* temporarily disable the timer */
+- iowrite32(0x00000002, watchdog_device.timer_control_addr);
+-
+- /* send the threshold and soft_threshold via IPC to the processor */
+- ipc_ret = watchdog_set_ipc(watchdog_device.soft_threshold,
+- watchdog_device.threshold);
+-
+- if (ipc_ret != 0) {
+- /* Make sure the watchdog timer is stopped */
+- intel_scu_stop();
+- return ipc_ret;
+- }
+-
+- /* Soft Threshold set loop. Early versions of silicon did */
+- /* not always set this count correctly. This loop checks */
+- /* the value and retries if it was not set correctly. */
+-
+- retry_count = 0;
+- soft_value = watchdog_device.soft_threshold & 0xFFFF0000;
+- do {
+-
+- /* Make sure timer is stopped */
+- intel_scu_stop();
+-
+- if (MAX_RETRY < retry_count++) {
+- /* Unable to set timer value */
+- pr_err("Unable to set timer\n");
+- return -ENODEV;
+- }
+-
+- /* set the timer to the soft threshold */
+- iowrite32(watchdog_device.soft_threshold,
+- watchdog_device.timer_load_count_addr);
+-
+- /* read count value before starting timer */
+- hw_pre_value = ioread32(watchdog_device.timer_load_count_addr);
+- hw_pre_value = hw_pre_value & 0xFFFF0000;
+-
+- /* Start the timer */
+- iowrite32(0x00000003, watchdog_device.timer_control_addr);
+-
+- /* read the value the time loaded into its count reg */
+- hw_value = ioread32(watchdog_device.timer_load_count_addr);
+- hw_value = hw_value & 0xFFFF0000;
+-
+-
+- } while (soft_value != hw_value);
+-
+- watchdog_device.timer_started = 1;
+-
+- return 0;
+-}
+-
+-/*
+- * /dev/watchdog handling
+- */
+-
+-static int intel_scu_open(struct inode *inode, struct file *file)
+-{
+-
+- /* Set flag to indicate that watchdog device is open */
+- if (test_and_set_bit(0, &watchdog_device.driver_open))
+- return -EBUSY;
+-
+- /* Check for reopen of driver. Reopens are not allowed */
+- if (watchdog_device.driver_closed)
+- return -EPERM;
+-
+- return nonseekable_open(inode, file);
+-}
+-
+-static int intel_scu_release(struct inode *inode, struct file *file)
+-{
+- /*
+- * This watchdog should not be closed, after the timer
+- * is started with the WDIPC_SETTIMEOUT ioctl
+- * If force_boot is set watchdog_fire() will cause an
+- * immediate reset. If force_boot is not set, the watchdog
+- * timer is refreshed for one more interval. At the end
+- * of that interval, the watchdog timer will reset the system.
+- */
+-
+- if (!test_and_clear_bit(0, &watchdog_device.driver_open)) {
+- pr_debug("intel_scu_release, without open\n");
+- return -ENOTTY;
+- }
+-
+- if (!watchdog_device.timer_started) {
+- /* Just close, since timer has not been started */
+- pr_debug("closed, without starting timer\n");
+- return 0;
+- }
+-
+- pr_crit("Unexpected close of /dev/watchdog!\n");
+-
+- /* Since the timer was started, prevent future reopens */
+- watchdog_device.driver_closed = 1;
+-
+- /* Refresh the timer for one more interval */
+- intel_scu_keepalive();
+-
+- /* Reboot system (if force_boot is set) */
+- watchdog_fire();
+-
+- /* We should only reach this point if force_boot is not set */
+- return 0;
+-}
+-
+-static ssize_t intel_scu_write(struct file *file,
+- char const *data,
+- size_t len,
+- loff_t *ppos)
+-{
+-
+- if (watchdog_device.timer_started)
+- /* Watchdog already started, keep it alive */
+- intel_scu_keepalive();
+- else
+- /* Start watchdog with timer value set by init */
+- intel_scu_set_heartbeat(watchdog_device.timer_set);
+-
+- return len;
+-}
+-
+-static long intel_scu_ioctl(struct file *file,
+- unsigned int cmd,
+- unsigned long arg)
+-{
+- void __user *argp = (void __user *)arg;
+- u32 __user *p = argp;
+- u32 new_margin;
+-
+-
+- static const struct watchdog_info ident = {
+- .options = WDIOF_SETTIMEOUT
+- | WDIOF_KEEPALIVEPING,
+- .firmware_version = 0, /* @todo Get from SCU via
+- ipc_get_scu_fw_version()? */
+- .identity = "Intel_SCU IOH Watchdog" /* len < 32 */
+- };
+-
+- switch (cmd) {
+- case WDIOC_GETSUPPORT:
+- return copy_to_user(argp,
+- &ident,
+- sizeof(ident)) ? -EFAULT : 0;
+- case WDIOC_GETSTATUS:
+- case WDIOC_GETBOOTSTATUS:
+- return put_user(0, p);
+- case WDIOC_KEEPALIVE:
+- intel_scu_keepalive();
+-
+- return 0;
+- case WDIOC_SETTIMEOUT:
+- if (get_user(new_margin, p))
+- return -EFAULT;
+-
+- if (check_timer_margin(new_margin))
+- return -EINVAL;
+-
+- if (intel_scu_set_heartbeat(new_margin))
+- return -EINVAL;
+- return 0;
+- case WDIOC_GETTIMEOUT:
+- return put_user(watchdog_device.soft_threshold, p);
+-
+- default:
+- return -ENOTTY;
+- }
+-}
+-
+-/*
+- * Notifier for system down
+- */
+-static int intel_scu_notify_sys(struct notifier_block *this,
+- unsigned long code,
+- void *another_unused)
+-{
+- if (code == SYS_DOWN || code == SYS_HALT)
+- /* Turn off the watchdog timer. */
+- intel_scu_stop();
+- return NOTIFY_DONE;
+-}
+-
+-/*
+- * Kernel Interfaces
+- */
+-static const struct file_operations intel_scu_fops = {
+- .owner = THIS_MODULE,
+- .llseek = no_llseek,
+- .write = intel_scu_write,
+- .unlocked_ioctl = intel_scu_ioctl,
+- .open = intel_scu_open,
+- .release = intel_scu_release,
+-};
+-
+-static int __init intel_scu_watchdog_init(void)
+-{
+- int ret;
+- u32 __iomem *tmp_addr;
+-
+- /*
+- * We don't really need to check this as the SFI timer get will fail
+- * but if we do so we can exit with a clearer reason and no noise.
+- *
+- * If it isn't an intel MID device then it doesn't have this watchdog
+- */
+- if (!mrst_identify_cpu())
+- return -ENODEV;
+-
+- /* Check boot parameters to verify that their initial values */
+- /* are in range. */
+- /* Check value of timer_set boot parameter */
+- if ((timer_set < MIN_TIME_CYCLE) ||
+- (timer_set > MAX_TIME - MIN_TIME_CYCLE)) {
+- pr_err("value of timer_set %x (hex) is out of range from %x to %x (hex)\n",
+- timer_set, MIN_TIME_CYCLE, MAX_TIME - MIN_TIME_CYCLE);
+- return -EINVAL;
+- }
+-
+- /* Check value of timer_margin boot parameter */
+- if (check_timer_margin(timer_margin))
+- return -EINVAL;
+-
+- watchdog_device.timer_tbl_ptr = sfi_get_mtmr(sfi_mtimer_num-1);
+-
+- if (watchdog_device.timer_tbl_ptr == NULL) {
+- pr_debug("timer is not available\n");
+- return -ENODEV;
+- }
+- /* make sure the timer exists */
+- if (watchdog_device.timer_tbl_ptr->phys_addr == 0) {
+- pr_debug("timer %d does not have valid physical memory\n",
+- sfi_mtimer_num);
+- return -ENODEV;
+- }
+-
+- if (watchdog_device.timer_tbl_ptr->irq == 0) {
+- pr_debug("timer %d invalid irq\n", sfi_mtimer_num);
+- return -ENODEV;
+- }
+-
+- tmp_addr = ioremap_nocache(watchdog_device.timer_tbl_ptr->phys_addr,
+- 20);
+-
+- if (tmp_addr == NULL) {
+- pr_debug("timer unable to ioremap\n");
+- return -ENOMEM;
+- }
+-
+- watchdog_device.timer_load_count_addr = tmp_addr++;
+- watchdog_device.timer_current_value_addr = tmp_addr++;
+- watchdog_device.timer_control_addr = tmp_addr++;
+- watchdog_device.timer_clear_interrupt_addr = tmp_addr++;
+- watchdog_device.timer_interrupt_status_addr = tmp_addr++;
+-
+- /* Set the default time values in device structure */
+-
+- watchdog_device.timer_set = timer_set;
+- watchdog_device.threshold =
+- timer_margin * watchdog_device.timer_tbl_ptr->freq_hz;
+- watchdog_device.soft_threshold =
+- (watchdog_device.timer_set - timer_margin)
+- * watchdog_device.timer_tbl_ptr->freq_hz;
+-
+-
+- watchdog_device.intel_scu_notifier.notifier_call =
+- intel_scu_notify_sys;
+-
+- ret = register_reboot_notifier(&watchdog_device.intel_scu_notifier);
+- if (ret) {
+- pr_err("cannot register notifier %d)\n", ret);
+- goto register_reboot_error;
+- }
+-
+- watchdog_device.miscdev.minor = WATCHDOG_MINOR;
+- watchdog_device.miscdev.name = "watchdog";
+- watchdog_device.miscdev.fops = &intel_scu_fops;
+-
+- ret = misc_register(&watchdog_device.miscdev);
+- if (ret) {
+- pr_err("cannot register miscdev %d err =%d\n",
+- WATCHDOG_MINOR, ret);
+- goto misc_register_error;
+- }
+-
+- ret = request_irq((unsigned int)watchdog_device.timer_tbl_ptr->irq,
+- watchdog_timer_interrupt,
+- IRQF_SHARED, "watchdog",
+- &watchdog_device.timer_load_count_addr);
+- if (ret) {
+- pr_err("error requesting irq %d\n", ret);
+- goto request_irq_error;
+- }
+- /* Make sure timer is disabled before returning */
+- intel_scu_stop();
+- return 0;
+-
+-/* error cleanup */
+-
+-request_irq_error:
+- misc_deregister(&watchdog_device.miscdev);
+-misc_register_error:
+- unregister_reboot_notifier(&watchdog_device.intel_scu_notifier);
+-register_reboot_error:
+- intel_scu_stop();
+- iounmap(watchdog_device.timer_load_count_addr);
+- return ret;
+-}
+-
+-static void __exit intel_scu_watchdog_exit(void)
+-{
+-
+- misc_deregister(&watchdog_device.miscdev);
+- unregister_reboot_notifier(&watchdog_device.intel_scu_notifier);
+- /* disable the timer */
+- iowrite32(0x00000002, watchdog_device.timer_control_addr);
+- iounmap(watchdog_device.timer_load_count_addr);
+-}
+-
+-late_initcall(intel_scu_watchdog_init);
+-module_exit(intel_scu_watchdog_exit);
+-
+-MODULE_AUTHOR("Intel Corporation");
+-MODULE_DESCRIPTION("Intel SCU Watchdog Device Driver");
+-MODULE_LICENSE("GPL");
+-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+-MODULE_VERSION(WDT_VER);
+diff --git a/drivers/watchdog/intel_scu_watchdog_evo.c b/drivers/watchdog/intel_scu_watchdog_evo.c
+new file mode 100644
+index 0000000..8aeecc4
+--- /dev/null
++++ b/drivers/watchdog/intel_scu_watchdog_evo.c
+@@ -0,0 +1,1403 @@
++/*
++ * Intel_SCU 0.3: An Intel SCU IOH Based Watchdog Device
++ * for Intel part #(s):
++ * - AF82MP20 PCH
++ *
++ * Copyright (C) 2009-2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General
++ * Public License as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be
++ * useful, but WITHOUT ANY WARRANTY; without even the implied
++ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
++ * PURPOSE. See the GNU General Public License for more details.
++ * You should have received a copy of the GNU General Public
++ * License along with this program; if not, write to the Free
++ * Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ * The full GNU General Public License is included in this
++ * distribution in the file called COPYING.
++ *
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++/* See Documentation/watchdog/intel-scu-watchdog.txt */
++
++#include <linux/module.h>
++#include <linux/device.h>
++#include <linux/miscdevice.h>
++#include <linux/watchdog.h>
++#include <linux/reboot.h>
++#include <linux/interrupt.h>
++#include <linux/kernel_stat.h>
++#include <linux/rpmsg.h>
++#include <linux/nmi.h>
++#include <asm/intel_scu_ipcutil.h>
++#include <asm/intel_mid_rpmsg.h>
++#include <asm/intel-mid.h>
++
++#include "intel_scu_watchdog_evo.h"
++
++/* Adjustment flags */
++#define CONFIG_INTEL_SCU_SOFT_LOCKUP
++#define CONFIG_DEBUG_WATCHDOG
++
++/* Defines */
++#define STRING_RESET_TYPE_MAX_LEN 11
++#define STRING_COLD_OFF "COLD_OFF"
++#define STRING_COLD_RESET "COLD_RESET"
++#define STRING_COLD_BOOT "COLD_BOOT"
++
++#define EXT_TIMER0_MSI 12
++
++#define IPC_WATCHDOG 0xF8
++
++enum {
++ SCU_WATCHDOG_START = 0,
++ SCU_WATCHDOG_STOP,
++ SCU_WATCHDOG_KEEPALIVE,
++ SCU_WATCHDOG_SET_ACTION_ON_TIMEOUT
++};
++
++enum {
++ SCU_COLD_OFF_ON_TIMEOUT = 0,
++ SCU_COLD_RESET_ON_TIMEOUT,
++ SCU_COLD_BOOT_ON_TIMEOUT,
++ SCU_DO_NOTHING_ON_TIMEOUT
++};
++
++#ifdef CONFIG_DEBUG_FS
++#define SECURITY_WATCHDOG_ADDR 0xFF222230
++#define STRING_NONE "NONE"
++#endif
++
++/* Statics */
++static int reset_type_to_string(int reset_type, char *string);
++static int string_to_reset_type(const char *string, int *reset_type);
++static struct intel_scu_watchdog_dev watchdog_device;
++static unsigned char osnib_reset = OSNIB_WRITE_VALUE;
++
++/* Module params */
++static bool kicking_active = true;
++#ifdef CONFIG_DEBUG_WATCHDOG
++module_param(kicking_active, bool, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(kicking_active,
++ "Deactivate the kicking will result in a cold reset"
++ "after a while");
++#endif
++
++static bool disable_kernel_watchdog = false;
++#ifdef CONFIG_DISABLE_SCU_WATCHDOG
++/*
++ * Please note that we are using a config CONFIG_DISABLE_SCU_WATCHDOG
++ * because this boot parameter should only be settable in a developement
++ */
++module_param(disable_kernel_watchdog, bool, S_IRUGO);
++MODULE_PARM_DESC(disable_kernel_watchdog,
++ "Disable kernel watchdog"
++ "Set to 0, watchdog started at boot"
++ "and left running; Set to 1; watchdog"
++ "is not started until user space"
++ "watchdog daemon is started; also if the"
++ "timer is started by the iafw firmware, it"
++ "will be disabled upon initialization of this"
++ "driver if disable_kernel_watchdog is set");
++#endif
++
++static int pre_timeout = DEFAULT_PRETIMEOUT;
++
++static int timeout = DEFAULT_TIMEOUT;
++module_param(timeout, int, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(timeout,
++ "Default Watchdog timer setting"
++ "Complete cycle time"
++ "The range is from 35 to 170"
++ "This is the time for all keep alives to arrive");
++
++static bool reset_on_release = true;
++
++#ifdef CONFIG_INTEL_SCU_SOFT_LOCKUP
++/*
++ * heartbeats: cpu last kstat.system times
++ * beattime : jiffies at the sample time of heartbeats.
++ * SOFT_LOCK_TIME : some time out in sec after warning interrupt.
++ * dump_softloc_debug : called on SOFT_LOCK_TIME time out after scu
++ * interrupt to log data to logbuffer and emmc-panic code,
++ * SOFT_LOCK_TIME needs to be < SCU warn to reset time
++ * which is currently thats 15 sec.
++ *
++ * The soft lock works be taking a snapshot of kstat_cpu(i).cpustat.system at
++ * the time of the warning interrupt for each cpu. Then at SOFT_LOCK_TIME the
++ * amount of time spend in system is computed and if its within 10 ms of the
++ * total SOFT_LOCK_TIME on any cpu it will dump the stack on that cpu and then
++ * calls panic.
++ *
++ */
++static u64 heartbeats[NR_CPUS];
++static u64 beattime;
++#define SOFT_LOCK_TIME 10
++static void dump_softlock_debug(unsigned long data);
++DEFINE_TIMER(softlock_timer, dump_softlock_debug, 0, 0);
++
++static struct rpmsg_instance *watchdog_instance;
++
++/* time is about to run out and the scu will reset soon. quickly
++ * dump debug data to logbuffer and emmc via calling panic before lights
++ * go out.
++ */
++static void smp_dumpstack(void *info)
++{
++ dump_stack();
++}
++
++static void dump_softlock_debug(unsigned long data)
++{
++ int i, reboot;
++ u64 system[NR_CPUS], num_jifs;
++
++ memset(system, 0, NR_CPUS*sizeof(u64));
++
++ num_jifs = jiffies - beattime;
++ for_each_possible_cpu(i) {
++ system[i] = kcpustat_cpu(i).cpustat[CPUTIME_SYSTEM] -
++ heartbeats[i];
++ }
++
++ reboot = 0;
++
++ for_each_possible_cpu(i) {
++ if ((num_jifs - cputime_to_jiffies(system[i])) <
++ msecs_to_jiffies(10)) {
++ WARN(1, "cpu %d wedged\n", i);
++ smp_call_function_single(i, smp_dumpstack, NULL, 1);
++ reboot = 1;
++ }
++ }
++
++ if (reboot) {
++ panic_timeout = 10;
++ trigger_all_cpu_backtrace();
++ panic("Soft lock on CPUs\n");
++ }
++}
++#endif /* CONFIG_INTEL_SCU_SOFT_LOCKUP */
++
++/* Check current timeouts */
++/* Timeout bounds come from the MODULE_PARAM_DESC description */
++static int check_timeouts(int pre_timeout_time, int timeout_time)
++{
++ if (pre_timeout_time >= timeout_time)
++ return -EINVAL;
++ if (pre_timeout_time > 155 || pre_timeout_time < 1)
++ return -EINVAL;
++ if (timeout_time > 170 || timeout_time < 35)
++ return -EINVAL;
++
++ return 0;
++}
++
++/* Set the different timeouts needed by the SCU FW and start the
++ * kernel watchdog */
++static int watchdog_set_timeouts_and_start(int pretimeout,
++ int timeout)
++{
++ int ret, error = 0;
++ struct ipc_wd_start {
++ u32 pretimeout;
++ u32 timeout;
++ } ipc_wd_start = { pretimeout, timeout };
++
++ ret = rpmsg_send_command(watchdog_instance, IPC_WATCHDOG,
++ SCU_WATCHDOG_START, (u8 *)&ipc_wd_start,
++ NULL, sizeof(ipc_wd_start), 0);
++ if (ret) {
++ pr_crit("Error configuring and starting watchdog: %d\n",
++ ret);
++ error = -EIO;
++ }
++
++ return error;
++}
++
++/* Provisioning function for future enhancement : allow to fine tune timing
++ according to watchdog action settings */
++static int watchdog_set_appropriate_timeouts(void)
++{
++ pr_debug("Setting shutdown timeouts\n");
++ return watchdog_set_timeouts_and_start(pre_timeout, timeout);
++}
++
++/* Keep alive */
++static int watchdog_keepalive(void)
++{
++ int ret, error = 0;
++
++ pr_debug("%s\n", __func__);
++
++ if (unlikely(!kicking_active)) {
++ /* Close our eyes */
++ pr_err("Transparent kicking\n");
++ return 0;
++ }
++
++ /* Really kick it */
++ ret = rpmsg_send_simple_command(watchdog_instance, IPC_WATCHDOG,
++ SCU_WATCHDOG_KEEPALIVE);
++ if (ret) {
++ pr_crit("Error executing keepalive: %x\n", ret);
++ error = -EIO;
++ }
++
++ return error;
++}
++
++/* stops the timer */
++static int watchdog_stop(void)
++{
++ int ret = 0;
++ int error = 0;
++
++ pr_crit("%s\n", __func__);
++
++ ret = rpmsg_send_simple_command(watchdog_instance, IPC_WATCHDOG,
++ SCU_WATCHDOG_STOP);
++ if (ret) {
++ pr_crit("Error stopping watchdog: %x\n", ret);
++ error = -EIO;
++ }
++
++ watchdog_device.started = false;
++
++ return error;
++}
++
++/* warning interrupt handler */
++static irqreturn_t watchdog_warning_interrupt(int irq, void *dev_id)
++{
++ if (unlikely(!kicking_active))
++ pr_warn("[SHTDWN] WATCHDOG TIMEOUT for test!, %s\n", __func__);
++
++ else
++ pr_warn("[SHTDWN] %s, WATCHDOG TIMEOUT!\n", __func__);
++
++ /* Let's reset the platform after dumping some data */
++ trigger_all_cpu_backtrace();
++ panic("Kernel Watchdog");
++
++ /* This code should not be reached */
++ return IRQ_HANDLED;
++}
++
++/* Program and starts the timer */
++static int watchdog_config_and_start(u32 newtimeout, u32 newpretimeout)
++{
++ int ret;
++
++ timeout = newtimeout;
++ pre_timeout = newpretimeout;
++
++ pr_debug("timeout=%ds, pre_timeout=%ds\n", timeout, pre_timeout);
++
++ /* Configure the watchdog */
++ ret = watchdog_set_timeouts_and_start(pre_timeout, timeout);
++ if (ret) {
++ pr_err("%s: Cannot configure the watchdog\n", __func__);
++
++ /* Make sure the watchdog timer is stopped */
++ watchdog_stop();
++ return ret;
++ }
++
++ watchdog_device.started = true;
++
++ return 0;
++}
++
++/* Open */
++static int intel_scu_open(struct inode *inode, struct file *file)
++{
++ /* Set flag to indicate that watchdog device is open */
++ if (test_and_set_bit(0, &watchdog_device.driver_open)) {
++ pr_err("watchdog device is busy\n");
++ return -EBUSY;
++ }
++
++ /* Check for reopen of driver. Reopens are not allowed */
++ if (watchdog_device.driver_closed) {
++ pr_err("watchdog device has been closed\n");
++ return -EPERM;
++ }
++
++ return nonseekable_open(inode, file);
++}
++
++/* Release */
++static int intel_scu_release(struct inode *inode, struct file *file)
++{
++ /*
++ * This watchdog should not be closed, after the timer
++ * is started with the WDIPC_SETTIMEOUT ioctl
++ * If reset_on_release is set this will cause an
++ * immediate reset. If reset_on_release is not set, the watchdog
++ * timer is refreshed for one more interval. At the end
++ * of that interval, the watchdog timer will reset the system.
++ */
++
++ if (!test_bit(0, &watchdog_device.driver_open)) {
++ pr_err("intel_scu_release, without open\n");
++ return -ENOTTY;
++ }
++
++ if (!watchdog_device.started) {
++ /* Just close, since timer has not been started */
++ pr_err("Closed, without starting timer\n");
++ return 0;
++ }
++
++ pr_crit("Unexpected close of /dev/watchdog!\n");
++
++ /* Since the timer was started, prevent future reopens */
++ watchdog_device.driver_closed = 1;
++
++ /* Refresh the timer for one more interval */
++ watchdog_keepalive();
++
++ /* Reboot system if requested */
++ if (reset_on_release) {
++ pr_crit("Initiating system reboot.\n");
++ emergency_restart();
++ }
++
++ pr_crit("Immediate Reboot Disabled\n");
++ pr_crit("System will reset when watchdog timer expire!\n");
++
++ return 0;
++}
++
++/* Write */
++static ssize_t intel_scu_write(struct file *file, char const *data, size_t len,
++ loff_t *ppos)
++{
++ pr_debug("watchdog %s\n", __func__);
++
++ if (watchdog_device.shutdown_flag == true)
++ /* do nothing if we are shutting down */
++ return len;
++
++ if (watchdog_device.started) {
++ /* Watchdog already started, keep it alive */
++ watchdog_keepalive();
++ }
++
++ return len;
++}
++
++/* ioctl */
++static long intel_scu_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ void __user *argp = (void __user *)arg;
++ u32 __user *p = argp;
++ u32 val;
++ u32 new_pre_timeout;
++ int options;
++
++ static const struct watchdog_info ident = {
++ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
++ /* @todo Get from SCU via ipc_get_scu_fw_version()? */
++ .firmware_version = 0,
++ /* len < 32 */
++ .identity = "Intel_SCU IOH Watchdog"
++ };
++
++ switch (cmd) {
++ case WDIOC_GETSUPPORT:
++ return copy_to_user(argp, &ident,
++ sizeof(ident)) ? -EFAULT : 0;
++ case WDIOC_GETSTATUS:
++ case WDIOC_GETBOOTSTATUS:
++ return put_user(0, p);
++ case WDIOC_KEEPALIVE:
++ pr_debug("%s: KeepAlive ioctl\n", __func__);
++ if (!watchdog_device.started)
++ return -EINVAL;
++
++ watchdog_keepalive();
++ return 0;
++ case WDIOC_SETTIMEOUT:
++ pr_debug("%s: SetTimeout ioctl\n", __func__);
++
++ if (watchdog_device.started)
++ return -EBUSY;
++
++ if (get_user(val, p))
++ return -EFAULT;
++ new_pre_timeout = val-15;
++ if (check_timeouts(new_pre_timeout, val)) {
++ pr_warn("%s: Invalid timeout thresholds (timeout: %d, pretimeout: %d) \n", __func__, val, new_pre_timeout);
++ return -EINVAL;
++ }
++
++ pre_timeout = new_pre_timeout;
++ timeout = val;
++ return 0;
++ case WDIOC_GETTIMEOUT:
++ return put_user(timeout, p);
++ case WDIOC_SETOPTIONS:
++ if (get_user(options, p))
++ return -EFAULT;
++
++ if (options & WDIOS_DISABLECARD) {
++ pr_debug("%s: Stopping the watchdog\n", __func__);
++ watchdog_stop();
++ return 0;
++ }
++
++ if (options & WDIOS_ENABLECARD) {
++ pr_debug("%s: Starting the watchdog\n", __func__);
++
++ if (watchdog_device.started)
++ return -EBUSY;
++
++ if (check_timeouts(pre_timeout, timeout)) {
++ pr_warn("%s: Invalid thresholds\n",
++ __func__);
++ return -EINVAL;
++ }
++ if (watchdog_config_and_start(timeout, pre_timeout))
++ return -EINVAL;
++ return 0;
++ }
++ return 0;
++ default:
++ return -ENOTTY;
++ }
++}
++
++static int watchdog_set_reset_type(int reset_type)
++{
++ int ret;
++ struct ipc_wd_on_timeout {
++ u32 reset_type;
++ } ipc_wd_on_timeout = { reset_type };
++
++ ret = rpmsg_send_command(watchdog_instance, IPC_WATCHDOG,
++ SCU_WATCHDOG_SET_ACTION_ON_TIMEOUT,
++ (u8 *)&ipc_wd_on_timeout, NULL,
++ sizeof(ipc_wd_on_timeout), 0);
++ if (ret) {
++ pr_crit("Error setting watchdog action: %d\n", ret);
++ return -EIO;
++ }
++
++ watchdog_device.normal_wd_action = reset_type;
++
++ return 0;
++}
++
++/* Reboot notifier */
++static int reboot_notifier(struct notifier_block *this,
++ unsigned long code,
++ void *another_unused)
++{
++ int ret;
++
++ if (code == SYS_RESTART || code == SYS_HALT || code == SYS_POWER_OFF) {
++ pr_warn("Reboot notifier\n");
++
++ if (watchdog_set_appropriate_timeouts())
++ pr_crit("reboot notifier cant set time\n");
++
++ switch (code) {
++ case SYS_RESTART:
++ ret = watchdog_set_reset_type(
++ watchdog_device.reboot_wd_action);
++ break;
++
++ case SYS_HALT:
++ case SYS_POWER_OFF:
++ ret = watchdog_set_reset_type(
++ watchdog_device.shutdown_wd_action);
++ break;
++ }
++ if (ret)
++ pr_err("%s: could not set reset type\n", __func__);
++
++#ifdef CONFIG_DEBUG_FS
++ /* debugfs entry to generate a BUG during
++ any shutdown/reboot call */
++ if (watchdog_device.panic_reboot_notifier)
++ BUG();
++#endif
++ /* Don't do instant reset on close */
++ reset_on_release = false;
++
++ /* Kick once again */
++ if (disable_kernel_watchdog == false) {
++ ret = watchdog_keepalive();
++ if (ret)
++ pr_warn("%s: no keep alive\n", __func__);
++
++ /* Don't allow any more keep-alives */
++ watchdog_device.shutdown_flag = true;
++ }
++ }
++ return NOTIFY_DONE;
++}
++
++#ifdef CONFIG_DEBUG_FS
++/* This code triggers a Security Watchdog */
++int open_security(struct inode *i, struct file *f)
++{
++ int ret = 0;
++ u64 *ptr;
++ u32 value;
++
++ ptr = ioremap_nocache(SECURITY_WATCHDOG_ADDR, sizeof(u32));
++
++ if (!ptr) {
++ pr_err("cannot open secwd's debugfile\n");
++ ret = -ENODEV;
++ goto error;
++ }
++ value = readl(ptr); /* trigger */
++
++ pr_err("%s: This code should never be reached but it got %x\n",
++ __func__, (unsigned int)value);
++
++error:
++ return ret;
++}
++
++static const struct file_operations security_watchdog_fops = {
++ .open = open_security,
++};
++
++static int kwd_trigger_write(struct file *file, const char __user *buff,
++ size_t count, loff_t *ppos)
++{
++ pr_debug("kwd_trigger_write\n");
++ panic("Kernel watchdog triggered\n");
++ return 0;
++}
++
++static const struct file_operations kwd_trigger_fops = {
++ .open = nonseekable_open,
++ .write = kwd_trigger_write,
++ .llseek = no_llseek,
++};
++
++static int kwd_reset_type_release(struct inode *inode, struct file *file)
++{
++ return 0;
++}
++
++static ssize_t kwd_reset_type_read(struct file *file, char __user *buff,
++ size_t count, loff_t *ppos)
++{
++ ssize_t len;
++ int ret;
++ char str[STRING_RESET_TYPE_MAX_LEN + 1];
++
++ pr_debug("reading reset_type of %x\n",
++ watchdog_device.normal_wd_action);
++
++ if (*ppos > 0)
++ return 0;
++
++ ret = reset_type_to_string(watchdog_device.normal_wd_action, str);
++ if (ret)
++ return -EINVAL;
++ else {
++ for (len = 0; len < (STRING_RESET_TYPE_MAX_LEN - 1)
++ && str[len] != '\0'; len++)
++ ;
++ str[len++] = '\n';
++ ret = copy_to_user(buff, str, len);
++ }
++
++ *ppos += len;
++ return len;
++}
++
++static ssize_t kwd_reset_type_write(struct file *file, const char __user *buff,
++ size_t count, loff_t *ppos)
++{
++ char str[STRING_RESET_TYPE_MAX_LEN];
++ unsigned long res;
++ int ret, reset_type;
++
++ if (count > STRING_RESET_TYPE_MAX_LEN) {
++ pr_err("Invalid size: count=%d\n", count);
++ return -EINVAL;
++ }
++
++ memset(str, 0x00, STRING_RESET_TYPE_MAX_LEN);
++
++ res = copy_from_user((void *)str,
++ (void __user *)buff,
++ (unsigned long)min((unsigned long)(count-1),
++ (unsigned long)(STRING_RESET_TYPE_MAX_LEN-1)));
++
++ if (res) {
++ pr_err("%s: copy to user failed\n", __func__);
++ return -EINVAL;
++ }
++
++ pr_debug("writing reset_type of %s\n", str);
++
++ ret = string_to_reset_type(str, &reset_type);
++ if (ret) {
++ pr_err("Invalid value\n");
++ return -EINVAL;
++ }
++
++ ret = watchdog_set_reset_type(reset_type);
++ if (ret) {
++ pr_err("%s: could not set reset type\n", __func__);
++ return -EINVAL;
++ }
++
++ return count;
++}
++
++static const struct file_operations kwd_reset_type_fops = {
++ .open = nonseekable_open,
++ .release = kwd_reset_type_release,
++ .read = kwd_reset_type_read,
++ .write = kwd_reset_type_write,
++ .llseek = no_llseek,
++};
++
++static ssize_t kwd_panic_reboot_read(struct file *file, char __user *buff,
++ size_t count, loff_t *ppos)
++{
++ # define RET_SIZE 3 /* prints only 2 chars : '0' or '1', plus '\n' */
++ char str[RET_SIZE];
++
++ int res;
++
++ if (*ppos > 0)
++ return 0;
++
++ strcpy(str, watchdog_device.panic_reboot_notifier ? "1\n" : "0\n");
++
++ res = copy_to_user(buff, str, RET_SIZE);
++ if (res) {
++ pr_err("%s: copy to user failed\n", __func__);
++ return -EINVAL;
++ }
++
++ *ppos += RET_SIZE-1;
++ return RET_SIZE-1;
++}
++
++
++static ssize_t kwd_panic_reboot_write(struct file *file,
++ const char __user *buff, size_t count, loff_t *ppos)
++{
++ /* whatever is written, simply set flag to TRUE */
++ watchdog_device.panic_reboot_notifier = true;
++
++ return count;
++}
++
++
++static const struct file_operations kwd_panic_reboot_fops = {
++ .open = nonseekable_open,
++ .read = kwd_panic_reboot_read,
++ .write = kwd_panic_reboot_write,
++ .llseek = no_llseek,
++};
++
++static int remove_debugfs_entries(void)
++{
++struct intel_scu_watchdog_dev *dev = &watchdog_device;
++
++ /* /sys/kernel/debug/watchdog */
++ debugfs_remove_recursive(dev->dfs_wd);
++
++ return 0;
++}
++
++static int create_debugfs_entries(void)
++{
++ struct intel_scu_watchdog_dev *dev = &watchdog_device;
++
++ /* /sys/kernel/debug/watchdog */
++ dev->dfs_wd = debugfs_create_dir("watchdog", NULL);
++ if (!dev->dfs_wd) {
++ pr_err("%s: Error, cannot create main dir\n", __func__);
++ goto error;
++ }
++
++ /* /sys/kernel/debug/watchdog/security_watchdog */
++ dev->dfs_secwd = debugfs_create_dir("security_watchdog", dev->dfs_wd);
++ if (!dev->dfs_secwd) {
++ pr_err("%s: Error, cannot create sec dir\n", __func__);
++ goto error;
++ }
++
++ /* /sys/kernel/debug/watchdog/security_watchdog/trigger */
++ dev->dfs_secwd_trigger = debugfs_create_file("trigger",
++ S_IFREG | S_IRUGO | S_IWUSR | S_IWGRP,
++ dev->dfs_secwd, NULL,
++ &security_watchdog_fops);
++
++ if (!dev->dfs_secwd_trigger) {
++ pr_err("%s: Error, cannot create sec file\n", __func__);
++ goto error;
++ }
++
++ /* /sys/kernel/debug/watchdog/kernel_watchdog */
++ dev->dfs_kwd = debugfs_create_dir("kernel_watchdog", dev->dfs_wd);
++ if (!dev->dfs_kwd) {
++ pr_err("%s: Error, cannot create kwd dir\n", __func__);
++ goto error;
++ }
++
++ /* /sys/kernel/debug/watchdog/kernel_watchdog/trigger */
++ dev->dfs_kwd_trigger = debugfs_create_file("trigger",
++ S_IFREG | S_IWUSR | S_IWGRP,
++ dev->dfs_kwd, NULL,
++ &kwd_trigger_fops);
++
++ if (!dev->dfs_kwd_trigger) {
++ pr_err("%s: Error, cannot create kwd trigger file\n",
++ __func__);
++ goto error;
++ }
++
++ /* /sys/kernel/debug/watchdog/kernel_watchdog/reset_type */
++ dev->dfs_kwd_trigger = debugfs_create_file("reset_type",
++ S_IFREG | S_IRUGO | S_IWUSR | S_IWGRP,
++ dev->dfs_kwd, NULL,
++ &kwd_reset_type_fops);
++
++ if (!dev->dfs_kwd_trigger) {
++ pr_err("%s: Error, cannot create kwd trigger file\n",
++ __func__);
++ goto error;
++ }
++
++ /* /sys/kernel/debug/watchdog/kernel_watchdog/panic_reboot_notifier */
++ dev->dfs_kwd_panic_reboot = debugfs_create_file("panic_reboot_notifier",
++ S_IFREG | S_IRUGO | S_IWUSR | S_IWGRP,
++ dev->dfs_kwd, NULL,
++ &kwd_panic_reboot_fops);
++
++ if (!dev->dfs_kwd_panic_reboot) {
++ pr_err("%s: Error, cannot create kwd panic_reboot_notifier file\n",
++ __func__);
++ goto error;
++ }
++
++
++ return 0;
++error:
++ remove_debugfs_entries();
++ return 1;
++}
++#endif /* CONFIG_DEBUG_FS*/
++
++/* Kernel Interfaces */
++static const struct file_operations intel_scu_fops = {
++ .owner = THIS_MODULE,
++ .llseek = no_llseek,
++ .write = intel_scu_write,
++ .unlocked_ioctl = intel_scu_ioctl,
++#ifdef CONFIG_COMPAT
++ .compat_ioctl = intel_scu_ioctl,
++#endif
++ .open = intel_scu_open,
++ .release = intel_scu_release,
++};
++
++/* sysfs entry to disable watchdog */
++#ifdef CONFIG_DISABLE_SCU_WATCHDOG
++static ssize_t disable_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ int ret;
++
++ if (!strtobool(buf, &disable_kernel_watchdog)) {
++ if (disable_kernel_watchdog) {
++ ret = watchdog_stop();
++ if (ret)
++ pr_err("cannot disable the timer\n");
++ } else {
++ ret = watchdog_config_and_start(timeout, pre_timeout);
++ if (ret)
++ return -EINVAL;
++ }
++ } else {
++ pr_err("got invalid value\n");
++ return -EINVAL;
++ }
++
++ return size;
++}
++
++static ssize_t disable_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ pr_debug("%s\n", __func__);
++ if (disable_kernel_watchdog)
++ return sprintf(buf, "1\n");
++
++ return sprintf(buf, "0\n");
++}
++
++static DEVICE_ATTR(disable, S_IWUSR | S_IRUGO,
++ disable_show, disable_store);
++
++#endif
++
++#define OSNIB_WDOG_COUNTER_MASK 0xF0
++#define OSNIB_WDOG_COUNTER_SHIFT 4
++#define WDOG_COUNTER_MAX_VALUE 3
++static ssize_t counter_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ int ret;
++
++ pr_debug("%s\n", __func__);
++
++ ret = sscanf(buf, "%hhu", &osnib_reset);
++ if (ret != 1) {
++ pr_err(PFX "cannot get counter value\n");
++ if (ret == 0)
++ ret = -EINVAL;
++ return ret;
++ }
++ if (osnib_reset > WDOG_COUNTER_MAX_VALUE)
++ osnib_reset = WDOG_COUNTER_MAX_VALUE;
++ osnib_reset = ((osnib_reset << OSNIB_WDOG_COUNTER_SHIFT) &
++ OSNIB_WDOG_COUNTER_MASK);
++ ret = intel_scu_ipc_write_osnib_wd(&osnib_reset);
++
++ if (ret != 0) {
++ pr_err(PFX "cannot write OSNIB\n");
++ return -EINVAL;
++ }
++
++ return size;
++}
++
++
++static ssize_t counter_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ unsigned char osnib_read = (unsigned char)0;
++ int ret;
++ pr_debug("%s\n", __func__);
++
++ ret = intel_scu_ipc_read_osnib_wd(&osnib_read);
++
++ if (ret != 0)
++ return -EIO;
++
++ return sprintf(buf, "%d\n", (int)((osnib_read & OSNIB_WDOG_COUNTER_MASK)
++ >> OSNIB_WDOG_COUNTER_SHIFT));
++}
++
++static int reset_type_to_string(int reset_type, char *string)
++{
++ switch (reset_type) {
++ case SCU_COLD_BOOT_ON_TIMEOUT:
++ strcpy(string, STRING_COLD_BOOT);
++ break;
++ case SCU_COLD_RESET_ON_TIMEOUT:
++ strcpy(string, STRING_COLD_RESET);
++ break;
++ case SCU_COLD_OFF_ON_TIMEOUT:
++ strcpy(string, STRING_COLD_OFF);
++ break;
++#ifdef CONFIG_DEBUG_FS
++ case SCU_DO_NOTHING_ON_TIMEOUT:
++ /* The IPC command DONOTHING is provided */
++ /* for debug purpose only. */
++ strcpy(string, STRING_NONE);
++ break;
++#endif
++ default:
++ return 1;
++ }
++
++ return 0;
++}
++
++static int string_to_reset_type(const char *string, int *reset_type)
++{
++ if (!reset_type || !string)
++ return 1;
++
++ if (strncmp(string, STRING_COLD_RESET,
++ sizeof(STRING_COLD_RESET) - 1) == 0) {
++ *reset_type = SCU_COLD_RESET_ON_TIMEOUT;
++ return 0;
++ }
++ if (strncmp(string, STRING_COLD_BOOT,
++ sizeof(STRING_COLD_BOOT) - 1) == 0) {
++ *reset_type = SCU_COLD_BOOT_ON_TIMEOUT;
++ return 0;
++ }
++ if (strncmp(string, STRING_COLD_OFF,
++ sizeof(STRING_COLD_OFF) - 1) == 0) {
++ *reset_type = SCU_COLD_OFF_ON_TIMEOUT;
++ return 0;
++ }
++#ifdef CONFIG_DEBUG_FS
++ if (strncmp(string, STRING_NONE,
++ sizeof(STRING_NONE) - 1) == 0) {
++ *reset_type = SCU_DO_NOTHING_ON_TIMEOUT;
++ return 0;
++ }
++#endif
++ /* We should not be here, this is an error case */
++ pr_debug("Invalid reset type value\n");
++ return 1;
++}
++
++static ssize_t reboot_ongoing_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ int ret;
++
++ pr_debug("%s\n", __func__);
++ /* reprogram timeouts. if error : continue */
++ ret = watchdog_set_appropriate_timeouts();
++ if (ret)
++ pr_err("%s: could not set timeouts\n", __func__);
++
++ /* restore reset type */
++ watchdog_set_reset_type(watchdog_device.reboot_wd_action);
++ if (ret) {
++ pr_err("%s: could not set reset type\n", __func__);
++ return -EINVAL;
++ }
++
++ return size;
++}
++
++static ssize_t shutdown_ongoing_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ int ret;
++
++ pr_debug("%s\n", __func__);
++ /* reprogram timeouts. if error : continue */
++ ret = watchdog_set_appropriate_timeouts();
++ if (ret)
++ pr_err("%s: could not set timeouts\n", __func__);
++
++ /* restore reset type */
++ watchdog_set_reset_type(watchdog_device.shutdown_wd_action);
++ if (ret) {
++ pr_err("%s: could not set reset type\n", __func__);
++ return -EINVAL;
++ }
++
++ return size;
++}
++
++static ssize_t normal_config_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ if (reset_type_to_string(watchdog_device.normal_wd_action, buf) != 0)
++ return -EINVAL;
++ strcat(buf, "\n");
++ return strlen(buf);
++}
++
++static ssize_t normal_config_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ if (string_to_reset_type(buf, &watchdog_device.normal_wd_action) != 0)
++ return -EINVAL;
++ if (watchdog_set_reset_type(watchdog_device.normal_wd_action) != 0)
++ return -EINVAL;
++
++ return size;
++}
++
++static ssize_t reboot_config_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ if (reset_type_to_string(watchdog_device.reboot_wd_action, buf) != 0)
++ return -EINVAL;
++ strcat(buf, "\n");
++ return strlen(buf);
++}
++
++static ssize_t reboot_config_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ if (string_to_reset_type(buf, &watchdog_device.reboot_wd_action) != 0)
++ return -EINVAL;
++
++ return size;
++}
++
++static ssize_t shutdown_config_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ if (reset_type_to_string(watchdog_device.shutdown_wd_action, buf) != 0)
++ return -EINVAL;
++ strcat(buf, "\n");
++ return strlen(buf);
++}
++
++static ssize_t shutdown_config_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ if (string_to_reset_type(buf, &watchdog_device.shutdown_wd_action) != 0)
++ return -EINVAL;
++
++ return size;
++}
++
++/* Watchdog behavior depending on system phase */
++static DEVICE_ATTR(normal_config, S_IWUSR | S_IRUGO,
++ normal_config_show, normal_config_store);
++static DEVICE_ATTR(reboot_config, S_IWUSR | S_IRUGO,
++ reboot_config_show, reboot_config_store);
++static DEVICE_ATTR(shutdown_config, S_IWUSR | S_IRUGO,
++ shutdown_config_show, shutdown_config_store);
++static DEVICE_ATTR(reboot_ongoing, S_IWUSR,
++ NULL, reboot_ongoing_store);
++static DEVICE_ATTR(shutdown_ongoing, S_IWUSR,
++ NULL, shutdown_ongoing_store);
++
++/* Reset counter watchdog entry */
++static DEVICE_ATTR(counter, S_IWUSR | S_IRUGO,
++ counter_show, counter_store);
++
++
++int create_watchdog_sysfs_files(void)
++{
++ int ret;
++
++#ifdef CONFIG_DISABLE_SCU_WATCHDOG
++ ret = device_create_file(watchdog_device.miscdev.this_device,
++ &dev_attr_disable);
++ if (ret) {
++ pr_warn("cant register dev file for disable\n");
++ return ret;
++ }
++#endif
++
++ ret = device_create_file(watchdog_device.miscdev.this_device,
++ &dev_attr_normal_config);
++ if (ret) {
++ pr_warn("cant register dev file for normal_config\n");
++ return ret;
++ }
++
++ ret = device_create_file(watchdog_device.miscdev.this_device,
++ &dev_attr_reboot_config);
++ if (ret) {
++ pr_warn("cant register dev file for reboot_config\n");
++ return ret;
++ }
++
++ ret = device_create_file(watchdog_device.miscdev.this_device,
++ &dev_attr_shutdown_config);
++ if (ret) {
++ pr_warn("cant register dev file for shutdown_config\n");
++ return ret;
++ }
++
++ ret = device_create_file(watchdog_device.miscdev.this_device,
++ &dev_attr_counter);
++ if (ret) {
++ pr_warn("cant register dev file for counter\n");
++ return ret;
++ }
++
++ ret = device_create_file(watchdog_device.miscdev.this_device,
++ &dev_attr_reboot_ongoing);
++ if (ret) {
++ pr_warn("cant register dev file for reboot_ongoing\n");
++ return ret;
++ }
++
++ ret = device_create_file(watchdog_device.miscdev.this_device,
++ &dev_attr_shutdown_ongoing);
++ if (ret) {
++ pr_warn("cant register dev file for shutdown_ongoing\n");
++ return ret;
++ }
++ return 0;
++}
++
++int remove_watchdog_sysfs_files(void)
++{
++#ifdef CONFIG_DISABLE_SCU_WATCHDOG
++ device_remove_file(watchdog_device.miscdev.this_device,
++ &dev_attr_disable);
++#endif
++ device_remove_file(watchdog_device.miscdev.this_device,
++ &dev_attr_normal_config);
++
++ device_remove_file(watchdog_device.miscdev.this_device,
++ &dev_attr_reboot_config);
++
++ device_remove_file(watchdog_device.miscdev.this_device,
++ &dev_attr_shutdown_config);
++
++ device_remove_file(watchdog_device.miscdev.this_device,
++ &dev_attr_counter);
++
++ device_remove_file(watchdog_device.miscdev.this_device,
++ &dev_attr_reboot_ongoing);
++
++ device_remove_file(watchdog_device.miscdev.this_device,
++ &dev_attr_shutdown_ongoing);
++ return 0;
++}
++
++static int handle_mrfl_dev_ioapic(int irq)
++{
++ int ret = 0;
++ int ioapic;
++ struct io_apic_irq_attr irq_attr;
++
++ ioapic = mp_find_ioapic(irq);
++ if (ioapic >= 0) {
++ irq_attr.ioapic = ioapic;
++ irq_attr.ioapic_pin = irq;
++ irq_attr.trigger = 1;
++ irq_attr.polarity = 0; /* Active high */
++ io_apic_set_pci_routing(NULL, irq, &irq_attr);
++ } else {
++ pr_warn("can not find interrupt %d in ioapic\n", irq);
++ ret = -EINVAL;
++ }
++
++ return ret;
++}
++
++/* Init code */
++static int intel_scu_watchdog_init(void)
++{
++ int ret = 0;
++
++ watchdog_device.normal_wd_action = SCU_COLD_RESET_ON_TIMEOUT;
++ watchdog_device.reboot_wd_action = SCU_COLD_RESET_ON_TIMEOUT;
++ watchdog_device.shutdown_wd_action = SCU_COLD_OFF_ON_TIMEOUT;
++
++#ifdef CONFIG_DEBUG_FS
++ watchdog_device.panic_reboot_notifier = false;
++#endif /* CONFIG_DEBUG_FS */
++
++ /* Initially, we are not in shutdown mode */
++ watchdog_device.shutdown_flag = false;
++
++ /* Since timeout can be set by MODULE_PARAM, need to reset pre_timeout */
++ pre_timeout = timeout-15;
++
++ /* Check timeouts boot parameter */
++ if (check_timeouts(pre_timeout, timeout)) {
++ pr_err("%s: Invalid timeouts\n", __func__);
++ return -EINVAL;
++ }
++
++ /* Reboot notifier */
++ watchdog_device.reboot_notifier.notifier_call = reboot_notifier;
++ watchdog_device.reboot_notifier.priority = 1;
++ ret = register_reboot_notifier(&watchdog_device.reboot_notifier);
++ if (ret) {
++ pr_crit("cannot register reboot notifier %d\n", ret);
++ goto error_stop_timer;
++ }
++
++ /* Do not publish the watchdog device when disable (TO BE REMOVED) */
++ if (!disable_kernel_watchdog) {
++ watchdog_device.miscdev.minor = WATCHDOG_MINOR;
++ watchdog_device.miscdev.name = "watchdog";
++ watchdog_device.miscdev.fops = &intel_scu_fops;
++
++ ret = misc_register(&watchdog_device.miscdev);
++ if (ret) {
++ pr_crit("Cannot register miscdev %d err =%d\n",
++ WATCHDOG_MINOR, ret);
++ goto error_reboot_notifier;
++ }
++ }
++
++ /* MSI #12 handler to dump registers */
++ handle_mrfl_dev_ioapic(EXT_TIMER0_MSI);
++ ret = request_irq((unsigned int)EXT_TIMER0_MSI,
++ watchdog_warning_interrupt,
++ IRQF_SHARED|IRQF_NO_SUSPEND, "watchdog",
++ &watchdog_device);
++ if (ret) {
++ pr_err("error requesting warning irq %d\n",
++ EXT_TIMER0_MSI);
++ pr_err("error value returned is %d\n", ret);
++ goto error_misc_register;
++ }
++
++#ifdef CONFIG_INTEL_SCU_SOFT_LOCKUP
++ init_timer(&softlock_timer);
++#endif
++
++ if (disable_kernel_watchdog) {
++ pr_err("%s: Disable kernel watchdog\n", __func__);
++
++ /* Make sure timer is stopped */
++ ret = watchdog_stop();
++ if (ret != 0)
++ pr_debug("cant disable timer\n");
++ }
++
++#ifdef CONFIG_DEBUG_FS
++ ret = create_debugfs_entries();
++ if (ret) {
++ pr_err("%s: Error creating debugfs entries\n", __func__);
++ goto error_debugfs_entry;
++ }
++#endif
++
++ watchdog_device.started = false;
++
++ ret = create_watchdog_sysfs_files();
++ if (ret) {
++ pr_err("%s: Error creating debugfs entries\n", __func__);
++ goto error_sysfs_entry;
++ }
++
++ return ret;
++
++error_sysfs_entry:
++ /* Nothing special to do */
++#ifdef CONFIG_DEBUG_FS
++error_debugfs_entry:
++ /* Remove entries done by create function */
++#endif
++
++error_misc_register:
++ misc_deregister(&watchdog_device.miscdev);
++
++error_reboot_notifier:
++ unregister_reboot_notifier(&watchdog_device.reboot_notifier);
++
++error_stop_timer:
++ watchdog_stop();
++
++ return ret;
++}
++
++static void intel_scu_watchdog_exit(void)
++{
++ int ret = 0;
++
++ remove_watchdog_sysfs_files();
++#ifdef CONFIG_DEBUG_FS
++ remove_debugfs_entries();
++#endif
++
++#ifdef CONFIG_INTEL_SCU_SOFT_LOCKUP
++ del_timer_sync(&softlock_timer);
++#endif
++
++ ret = watchdog_stop();
++ if (ret != 0)
++ pr_err("cant disable timer\n");
++
++ misc_deregister(&watchdog_device.miscdev);
++ unregister_reboot_notifier(&watchdog_device.reboot_notifier);
++}
++
++static int watchdog_rpmsg_probe(struct rpmsg_channel *rpdev)
++{
++ int ret = 0;
++
++ if (rpdev == NULL) {
++ pr_err("rpmsg channel not created\n");
++ ret = -ENODEV;
++ goto out;
++ }
++
++ dev_info(&rpdev->dev, "Probed watchdog rpmsg device\n");
++
++ /* Allocate rpmsg instance for watchdog*/
++ ret = alloc_rpmsg_instance(rpdev, &watchdog_instance);
++ if (!watchdog_instance) {
++ dev_err(&rpdev->dev, "kzalloc watchdog instance failed\n");
++ goto out;
++ }
++ /* Initialize rpmsg instance */
++ init_rpmsg_instance(watchdog_instance);
++ /* Init scu watchdog */
++ ret = intel_scu_watchdog_init();
++
++ if (ret)
++ free_rpmsg_instance(rpdev, &watchdog_instance);
++out:
++ return ret;
++}
++
++static void watchdog_rpmsg_remove(struct rpmsg_channel *rpdev)
++{
++ intel_scu_watchdog_exit();
++ free_rpmsg_instance(rpdev, &watchdog_instance);
++ dev_info(&rpdev->dev, "Removed watchdog rpmsg device\n");
++}
++
++static void watchdog_rpmsg_cb(struct rpmsg_channel *rpdev, void *data,
++ int len, void *priv, u32 src)
++{
++ dev_warn(&rpdev->dev, "unexpected, message\n");
++
++ print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
++ data, len, true);
++}
++
++static struct rpmsg_device_id watchdog_rpmsg_id_table[] = {
++ { .name = "rpmsg_watchdog" },
++ { },
++};
++MODULE_DEVICE_TABLE(rpmsg, watchdog_rpmsg_id_table);
++
++static struct rpmsg_driver watchdog_rpmsg = {
++ .drv.name = KBUILD_MODNAME,
++ .drv.owner = THIS_MODULE,
++ .id_table = watchdog_rpmsg_id_table,
++ .probe = watchdog_rpmsg_probe,
++ .callback = watchdog_rpmsg_cb,
++ .remove = watchdog_rpmsg_remove,
++};
++
++static int __init watchdog_rpmsg_init(void)
++{
++ if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER)
++ return register_rpmsg_driver(&watchdog_rpmsg);
++ else {
++ pr_err("%s: watchdog driver: bad platform\n", __func__);
++ return -ENODEV;
++ }
++}
++
++#ifdef MODULE
++module_init(watchdog_rpmsg_init);
++#else
++rootfs_initcall(watchdog_rpmsg_init);
++#endif
++
++static void __exit watchdog_rpmsg_exit(void)
++{
++ return unregister_rpmsg_driver(&watchdog_rpmsg);
++}
++module_exit(watchdog_rpmsg_exit);
++
++MODULE_AUTHOR("Intel Corporation");
++MODULE_AUTHOR("mark.a.allyn@intel.com");
++MODULE_AUTHOR("yannx.puech@intel.com");
++MODULE_DESCRIPTION("Intel SCU Watchdog Device Driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
++MODULE_VERSION(WDT_VER);
+diff --git a/drivers/watchdog/intel_scu_watchdog_evo.h b/drivers/watchdog/intel_scu_watchdog_evo.h
+new file mode 100644
+index 0000000..2176974
+--- /dev/null
++++ b/drivers/watchdog/intel_scu_watchdog_evo.h
+@@ -0,0 +1,68 @@
++/*
++ * Intel_SCU 0.3: An Intel SCU IOH Based Watchdog Device
++ * for Intel part #(s):
++ * - AF82MP20 PCH
++ *
++ * Copyright (C) 2009-2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General
++ * Public License as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be
++ * useful, but WITHOUT ANY WARRANTY; without even the implied
++ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
++ * PURPOSE. See the GNU General Public License for more details.
++ * You should have received a copy of the GNU General Public
++ * License along with this program; if not, write to the Free
++ * Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ * The full GNU General Public License is included in this
++ * distribution in the file called COPYING.
++ *
++ */
++
++#ifndef __INTEL_SCU_WATCHDOG_H
++#define __INTEL_SCU_WATCHDOG_H
++
++#ifdef CONFIG_COMPAT
++#include <linux/compat.h>
++#endif
++
++#ifdef CONFIG_DEBUG_FS
++#include <linux/debugfs.h>
++#endif
++
++#define PFX "intel_scu_watchdog: "
++#define WDT_VER "0.3"
++
++#define DEFAULT_PRETIMEOUT 75
++#define DEFAULT_TIMEOUT 90
++
++/* Value 0 to reset the reset counter */
++#define OSNIB_WRITE_VALUE 0
++
++struct intel_scu_watchdog_dev {
++ ulong driver_open;
++ ulong driver_closed;
++ bool started;
++ struct notifier_block reboot_notifier;
++ struct miscdevice miscdev;
++ bool shutdown_flag;
++ int reset_type;
++ int normal_wd_action;
++ int reboot_wd_action;
++ int shutdown_wd_action;
++#ifdef CONFIG_DEBUG_FS
++ bool panic_reboot_notifier;
++ struct dentry *dfs_wd;
++ struct dentry *dfs_secwd;
++ struct dentry *dfs_secwd_trigger;
++ struct dentry *dfs_kwd;
++ struct dentry *dfs_kwd_trigger;
++ struct dentry *dfs_kwd_reset_type;
++ struct dentry *dfs_kwd_panic_reboot;
++#endif /* CONFIG_DEBUG_FS */
++};
++
++#endif /* __INTEL_SCU_WATCHDOG_H */
+diff --git a/firmware/Makefile b/firmware/Makefile
+index cbb09ce..6e1dca7 100644
+--- a/firmware/Makefile
++++ b/firmware/Makefile
+@@ -135,6 +135,7 @@ fw-shipped-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda/xircom_pgs.fw
+ fw-shipped-$(CONFIG_USB_VICAM) += vicam/firmware.fw
+ fw-shipped-$(CONFIG_VIDEO_CPIA2) += cpia2/stv0672_vp4.bin
+ fw-shipped-$(CONFIG_YAM) += yam/1200.bin yam/9600.bin
++fw-shipped-$(CONFIG_INTEL_MID_REMOTEPROC) += intel_mid/intel_mid_remoteproc.fw
+
+ fw-shipped-all := $(fw-shipped-y) $(fw-shipped-m) $(fw-shipped-)
+
+diff --git a/firmware/intel_mid/intel_mid_remoteproc.fw.ihex b/firmware/intel_mid/intel_mid_remoteproc.fw.ihex
+new file mode 100644
+index 0000000..998c4f2
+--- /dev/null
++++ b/firmware/intel_mid/intel_mid_remoteproc.fw.ihex
+@@ -0,0 +1,280 @@
++:100000007F454C4601010100000000000000000097
++:100010000200030001000000240000003400000082
++:10002000F010000000000000340020000100280053
++:1000300003000200040000000000000000000000B7
++:1000400000000000000000000000000007000000A9
++:10005000040000000000000000000000000000009C
++:100060000000000000000000000000000000000090
++:100070000000000000000000000000000000000080
++:100080000000000000000000000000000000000070
++:100090000000000000000000000000000000000060
++:1000A0000000000000000000000000000000000050
++:1000B0000000000000000000000000000000000040
++:1000C0000000000000000000000000000000000030
++:1000D0000000000000000000000000000000000020
++:1000E0000000000000000000000000000000000010
++:1000F0000000000000000000000000000000000000
++:1001000000000000000000000000000000000000EF
++:1001100000000000000000000000000000000000DF
++:1001200000000000000000000000000000000000CF
++:1001300000000000000000000000000000000000BF
++:1001400000000000000000000000000000000000AF
++:10015000000000000000000000000000000000009F
++:10016000000000000000000000000000000000008F
++:10017000000000000000000000000000000000007F
++:10018000000000000000000000000000000000006F
++:10019000000000000000000000000000000000005F
++:1001A000000000000000000000000000000000004F
++:1001B000000000000000000000000000000000003F
++:1001C000000000000000000000000000000000002F
++:1001D000000000000000000000000000000000001F
++:1001E000000000000000000000000000000000000F
++:1001F00000000000000000000000000000000000FF
++:1002000000000000000000000000000000000000EE
++:1002100000000000000000000000000000000000DE
++:1002200000000000000000000000000000000000CE
++:1002300000000000000000000000000000000000BE
++:1002400000000000000000000000000000000000AE
++:10025000000000000000000000000000000000009E
++:10026000000000000000000000000000000000008E
++:10027000000000000000000000000000000000007E
++:10028000000000000000000000000000000000006E
++:10029000000000000000000000000000000000005E
++:1002A000000000000000000000000000000000004E
++:1002B000000000000000000000000000000000003E
++:1002C000000000000000000000000000000000002E
++:1002D000000000000000000000000000000000001E
++:1002E000000000000000000000000000000000000E
++:1002F00000000000000000000000000000000000FE
++:1003000000000000000000000000000000000000ED
++:1003100000000000000000000000000000000000DD
++:1003200000000000000000000000000000000000CD
++:1003300000000000000000000000000000000000BD
++:1003400000000000000000000000000000000000AD
++:10035000000000000000000000000000000000009D
++:10036000000000000000000000000000000000008D
++:10037000000000000000000000000000000000007D
++:10038000000000000000000000000000000000006D
++:10039000000000000000000000000000000000005D
++:1003A000000000000000000000000000000000004D
++:1003B000000000000000000000000000000000003D
++:1003C000000000000000000000000000000000002D
++:1003D000000000000000000000000000000000001D
++:1003E000000000000000000000000000000000000D
++:1003F00000000000000000000000000000000000FD
++:1004000000000000000000000000000000000000EC
++:1004100000000000000000000000000000000000DC
++:1004200000000000000000000000000000000000CC
++:1004300000000000000000000000000000000000BC
++:1004400000000000000000000000000000000000AC
++:10045000000000000000000000000000000000009C
++:10046000000000000000000000000000000000008C
++:10047000000000000000000000000000000000007C
++:10048000000000000000000000000000000000006C
++:10049000000000000000000000000000000000005C
++:1004A000000000000000000000000000000000004C
++:1004B000000000000000000000000000000000003C
++:1004C000000000000000000000000000000000002C
++:1004D000000000000000000000000000000000001C
++:1004E000000000000000000000000000000000000C
++:1004F00000000000000000000000000000000000FC
++:1005000000000000000000000000000000000000EB
++:1005100000000000000000000000000000000000DB
++:1005200000000000000000000000000000000000CB
++:1005300000000000000000000000000000000000BB
++:1005400000000000000000000000000000000000AB
++:10055000000000000000000000000000000000009B
++:10056000000000000000000000000000000000008B
++:10057000000000000000000000000000000000007B
++:10058000000000000000000000000000000000006B
++:10059000000000000000000000000000000000005B
++:1005A000000000000000000000000000000000004B
++:1005B000000000000000000000000000000000003B
++:1005C000000000000000000000000000000000002B
++:1005D000000000000000000000000000000000001B
++:1005E000000000000000000000000000000000000B
++:1005F00000000000000000000000000000000000FB
++:1006000000000000000000000000000000000000EA
++:1006100000000000000000000000000000000000DA
++:1006200000000000000000000000000000000000CA
++:1006300000000000000000000000000000000000BA
++:1006400000000000000000000000000000000000AA
++:10065000000000000000000000000000000000009A
++:10066000000000000000000000000000000000008A
++:10067000000000000000000000000000000000007A
++:10068000000000000000000000000000000000006A
++:10069000000000000000000000000000000000005A
++:1006A000000000000000000000000000000000004A
++:1006B000000000000000000000000000000000003A
++:1006C000000000000000000000000000000000002A
++:1006D000000000000000000000000000000000001A
++:1006E000000000000000000000000000000000000A
++:1006F00000000000000000000000000000000000FA
++:1007000000000000000000000000000000000000E9
++:1007100000000000000000000000000000000000D9
++:1007200000000000000000000000000000000000C9
++:1007300000000000000000000000000000000000B9
++:1007400000000000000000000000000000000000A9
++:100750000000000000000000000000000000000099
++:100760000000000000000000000000000000000089
++:100770000000000000000000000000000000000079
++:100780000000000000000000000000000000000069
++:100790000000000000000000000000000000000059
++:1007A0000000000000000000000000000000000049
++:1007B0000000000000000000000000000000000039
++:1007C0000000000000000000000000000000000029
++:1007D0000000000000000000000000000000000019
++:1007E0000000000000000000000000000000000009
++:1007F00000000000000000000000000000000000F9
++:1008000000000000000000000000000000000000E8
++:1008100000000000000000000000000000000000D8
++:1008200000000000000000000000000000000000C8
++:1008300000000000000000000000000000000000B8
++:1008400000000000000000000000000000000000A8
++:100850000000000000000000000000000000000098
++:100860000000000000000000000000000000000088
++:100870000000000000000000000000000000000078
++:100880000000000000000000000000000000000068
++:100890000000000000000000000000000000000058
++:1008A0000000000000000000000000000000000048
++:1008B0000000000000000000000000000000000038
++:1008C0000000000000000000000000000000000028
++:1008D0000000000000000000000000000000000018
++:1008E0000000000000000000000000000000000008
++:1008F00000000000000000000000000000000000F8
++:1009000000000000000000000000000000000000E7
++:1009100000000000000000000000000000000000D7
++:1009200000000000000000000000000000000000C7
++:1009300000000000000000000000000000000000B7
++:1009400000000000000000000000000000000000A7
++:100950000000000000000000000000000000000097
++:100960000000000000000000000000000000000087
++:100970000000000000000000000000000000000077
++:100980000000000000000000000000000000000067
++:100990000000000000000000000000000000000057
++:1009A0000000000000000000000000000000000047
++:1009B0000000000000000000000000000000000037
++:1009C0000000000000000000000000000000000027
++:1009D0000000000000000000000000000000000017
++:1009E0000000000000000000000000000000000007
++:1009F00000000000000000000000000000000000F7
++:100A000000000000000000000000000000000000E6
++:100A100000000000000000000000000000000000D6
++:100A200000000000000000000000000000000000C6
++:100A300000000000000000000000000000000000B6
++:100A400000000000000000000000000000000000A6
++:100A50000000000000000000000000000000000096
++:100A60000000000000000000000000000000000086
++:100A70000000000000000000000000000000000076
++:100A80000000000000000000000000000000000066
++:100A90000000000000000000000000000000000056
++:100AA0000000000000000000000000000000000046
++:100AB0000000000000000000000000000000000036
++:100AC0000000000000000000000000000000000026
++:100AD0000000000000000000000000000000000016
++:100AE0000000000000000000000000000000000006
++:100AF00000000000000000000000000000000000F6
++:100B000000000000000000000000000000000000E5
++:100B100000000000000000000000000000000000D5
++:100B200000000000000000000000000000000000C5
++:100B300000000000000000000000000000000000B5
++:100B400000000000000000000000000000000000A5
++:100B50000000000000000000000000000000000095
++:100B60000000000000000000000000000000000085
++:100B70000000000000000000000000000000000075
++:100B80000000000000000000000000000000000065
++:100B90000000000000000000000000000000000055
++:100BA0000000000000000000000000000000000045
++:100BB0000000000000000000000000000000000035
++:100BC0000000000000000000000000000000000025
++:100BD0000000000000000000000000000000000015
++:100BE0000000000000000000000000000000000005
++:100BF00000000000000000000000000000000000F5
++:100C000000000000000000000000000000000000E4
++:100C100000000000000000000000000000000000D4
++:100C200000000000000000000000000000000000C4
++:100C300000000000000000000000000000000000B4
++:100C400000000000000000000000000000000000A4
++:100C50000000000000000000000000000000000094
++:100C60000000000000000000000000000000000084
++:100C70000000000000000000000000000000000074
++:100C80000000000000000000000000000000000064
++:100C90000000000000000000000000000000000054
++:100CA0000000000000000000000000000000000044
++:100CB0000000000000000000000000000000000034
++:100CC0000000000000000000000000000000000024
++:100CD0000000000000000000000000000000000014
++:100CE0000000000000000000000000000000000004
++:100CF00000000000000000000000000000000000F4
++:100D000000000000000000000000000000000000E3
++:100D100000000000000000000000000000000000D3
++:100D200000000000000000000000000000000000C3
++:100D300000000000000000000000000000000000B3
++:100D400000000000000000000000000000000000A3
++:100D50000000000000000000000000000000000093
++:100D60000000000000000000000000000000000083
++:100D70000000000000000000000000000000000073
++:100D80000000000000000000000000000000000063
++:100D90000000000000000000000000000000000053
++:100DA0000000000000000000000000000000000043
++:100DB0000000000000000000000000000000000033
++:100DC0000000000000000000000000000000000023
++:100DD0000000000000000000000000000000000013
++:100DE0000000000000000000000000000000000003
++:100DF00000000000000000000000000000000000F3
++:100E000000000000000000000000000000000000E2
++:100E100000000000000000000000000000000000D2
++:100E200000000000000000000000000000000000C2
++:100E300000000000000000000000000000000000B2
++:100E400000000000000000000000000000000000A2
++:100E50000000000000000000000000000000000092
++:100E60000000000000000000000000000000000082
++:100E70000000000000000000000000000000000072
++:100E80000000000000000000000000000000000062
++:100E90000000000000000000000000000000000052
++:100EA0000000000000000000000000000000000042
++:100EB0000000000000000000000000000000000032
++:100EC0000000000000000000000000000000000022
++:100ED0000000000000000000000000000000000012
++:100EE0000000000000000000000000000000000002
++:100EF00000000000000000000000000000000000F2
++:100F000000000000000000000000000000000000E1
++:100F100000000000000000000000000000000000D1
++:100F200000000000000000000000000000000000C1
++:100F300000000000000000000000000000000000B1
++:100F400000000000000000000000000000000000A1
++:100F50000000000000000000000000000000000091
++:100F60000000000000000000000000000000000081
++:100F70000000000000000000000000000000000071
++:100F80000000000000000000000000000000000061
++:100F90000000000000000000000000000000000051
++:100FA0000000000000000000000000000000000041
++:100FB0000000000000000000000000000000000031
++:100FC0000000000000000000000000000000000021
++:100FD0000000000000000000000000000000000011
++:100FE0000000000000000000000000000000000001
++:100FF00000000000000000000000000000000000F1
++:1010000000000000000000000000000000000000E0
++:1010100000000000000000000000000000000000D0
++:1010200000000000000000000000000000000000C0
++:1010300000000000000000000000000000000000B0
++:10104000010000000200000000000000000000009D
++:10105000180000005C000000030000000700000012
++:10106000010000000100000001000000000000007D
++:10107000000200000000000001000000000100006C
++:10108000000000000000000000000000010000005F
++:10109000000100000000000000000000000000004F
++:1010A000000000000000000000020000000000003E
++:1010B0000000000000000000000000000000000030
++:1010C0000000000000000000000000000000000020
++:1010D00000000000002E7368737472746162002E49
++:1010E0007265736F757263655F7461626C65000031
++:1010F00000000000000000000000000000000000F0
++:1011000000000000000000000000000000000000DF
++:1011100000000000000000000B00000007000000BD
++:101120000300000040000000401000009400000098
++:10113000000000000000000020000000000000008F
++:10114000010000000300000000000000000000009B
++:10115000D41000001B000000000000000000000090
++:08116000010000000000000086
++:00000001FF
+diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
+index f71ec12..f7b07a3 100644
+--- a/fs/ecryptfs/crypto.c
++++ b/fs/ecryptfs/crypto.c
+@@ -1023,8 +1023,10 @@ int ecryptfs_new_file_context(struct inode *ecryptfs_inode)
+ "to the inode key sigs; rc = [%d]\n", rc);
+ goto out;
+ }
++ /* TODO: Investigate side effect of truncating name if too long */
+ cipher_name_len =
+- strlen(mount_crypt_stat->global_default_cipher_name);
++ min(strlen(mount_crypt_stat->global_default_cipher_name),
++ sizeof(crypt_stat->cipher)-1);
+ memcpy(crypt_stat->cipher,
+ mount_crypt_stat->global_default_cipher_name,
+ cipher_name_len);
+diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
+index bde6469..6f708bd 100644
+--- a/include/asm-generic/gpio.h
++++ b/include/asm-generic/gpio.h
+@@ -118,6 +118,9 @@ struct gpio_chip {
+ int (*set_debounce)(struct gpio_chip *chip,
+ unsigned offset, unsigned debounce);
+
++ void (*set_pinmux)(int gpio, int alt);
++ int (*get_pinmux)(int gpio);
++
+ void (*set)(struct gpio_chip *chip,
+ unsigned offset, int value);
+
+diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
+index 833926c..14f8aac 100644
+--- a/include/linux/iio/consumer.h
++++ b/include/linux/iio/consumer.h
+@@ -183,4 +183,7 @@ int iio_read_channel_scale(struct iio_channel *chan, int *val,
+ int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
+ int *processed, unsigned int scale);
+
++int iio_read_channel_all_raw(struct iio_channel *chan, int *val);
++int iio_channel_get_name(const struct iio_channel *chan, char **chan_name);
++int iio_channel_get_num(const struct iio_channel *chan);
+ #endif
+diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
+index 3d35b70..58cb6e1 100644
+--- a/include/linux/iio/iio.h
++++ b/include/linux/iio/iio.h
+@@ -287,6 +287,9 @@ struct iio_info {
+ int *val2,
+ long mask);
+
++ int (*read_all_raw)(struct iio_channel *chan,
++ int *val);
++
+ int (*write_raw)(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
+index 88bf0f0..2a50d36 100644
+--- a/include/linux/iio/types.h
++++ b/include/linux/iio/types.h
+@@ -29,6 +29,7 @@ enum iio_chan_type {
+ IIO_ALTVOLTAGE,
+ IIO_CCT,
+ IIO_PRESSURE,
++ IIO_RESISTANCE,
+ };
+
+ enum iio_modifier {
+diff --git a/include/linux/intel_mid_dma.h b/include/linux/intel_mid_dma.h
+index 10496bd..374514e 100644
+--- a/include/linux/intel_mid_dma.h
++++ b/include/linux/intel_mid_dma.h
+@@ -29,6 +29,10 @@
+
+ #define DMA_PREP_CIRCULAR_LIST (1 << 10)
+
++#define SST_MAX_DMA_LEN 4095
++#define SST_MAX_DMA_LEN_MRFLD 131071 /* 2^17 - 1 */
++
++
+ /*DMA mode configurations*/
+ enum intel_mid_dma_mode {
+ LNW_DMA_PER_TO_MEM = 0, /*periphral to memory configuration*/
+@@ -73,4 +77,7 @@ struct intel_mid_dma_slave {
+ struct dma_slave_config dma_slave;
+ };
+
++struct device *intel_mid_get_acpi_dma(void);
++dma_addr_t intel_dma_get_src_addr(struct dma_chan *chan);
++dma_addr_t intel_dma_get_dst_addr(struct dma_chan *chan);
+ #endif /*__INTEL_MID_DMA_H__*/
+diff --git a/include/linux/intel_mid_pm.h b/include/linux/intel_mid_pm.h
+new file mode 100644
+index 0000000..4dfaa81
+--- /dev/null
++++ b/include/linux/intel_mid_pm.h
+@@ -0,0 +1,234 @@
++/*
++ * intel_mid_pm.h
++ * Copyright (c) 2010, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++#include <linux/errno.h>
++
++#ifndef INTEL_MID_PM_H
++#define INTEL_MID_PM_H
++
++#include <asm/intel-mid.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++
++
++/* Chip ID of Intel Atom SOC*/
++#define INTEL_ATOM_MRST 0x26
++#define INTEL_ATOM_MFLD 0x27
++#define INTEL_ATOM_CLV 0x35
++#define INTEL_ATOM_MRFLD 0x4a
++#define INTEL_ATOM_BYT 0x37
++
++static inline int platform_is(u8 model)
++{
++ return (boot_cpu_data.x86_model == model);
++}
++
++/* Register Type definitions */
++#define OSPM_REG_TYPE 0x0
++#define APM_REG_TYPE 0x1
++#define OSPM_MAX_POWER_ISLANDS 16
++#define OSPM_ISLAND_UP 0x0
++#define OSPM_ISLAND_DOWN 0x1
++/*Soft reset*/
++#define OSPM_ISLAND_SR 0x2
++
++/* North complex power islands definitions for APM block*/
++#define APM_GRAPHICS_ISLAND 0x1
++#define APM_VIDEO_DEC_ISLAND 0x2
++#define APM_VIDEO_ENC_ISLAND 0x4
++#define APM_GL3_CACHE_ISLAND 0x8
++#define APM_ISP_ISLAND 0x10
++#define APM_IPH_ISLAND 0x20
++
++/* North complex power islands definitions for OSPM block*/
++#define OSPM_DISPLAY_A_ISLAND 0x2
++#define OSPM_DISPLAY_B_ISLAND 0x80
++#define OSPM_DISPLAY_C_ISLAND 0x100
++#define OSPM_MIPI_ISLAND 0x200
++
++/* North Complex power islands definitions for Tangier */
++#define TNG_ISP_ISLAND 0x1
++/* North Complex Register definitions for Tangier */
++#define ISP_SS_PM0 0x39
++
++#define C4_STATE_IDX 3
++#define C6_STATE_IDX 4
++#define S0I1_STATE_IDX 5
++#define LPMP3_STATE_IDX 6
++#define S0I3_STATE_IDX 7
++
++#define C4_HINT (0x30)
++#define C6_HINT (0x52)
++
++#define CSTATE_EXIT_LATENCY_C1 1
++#define CSTATE_EXIT_LATENCY_C2 20
++#define CSTATE_EXIT_LATENCY_C4 100
++#define CSTATE_EXIT_LATENCY_C6 140
++
++/* Since entry latency is substantial
++ * put exit_latency = entry+exit latency
++ */
++#ifdef CONFIG_REMOVEME_INTEL_ATOM_MRFLD_POWER
++#define CSTATE_EXIT_LATENCY_S0i1 1200
++#define CSTATE_EXIT_LATENCY_S0i2 2000
++#define CSTATE_EXIT_LATENCY_S0i3 10000
++#else
++#define CSTATE_EXIT_LATENCY_LPMP3 1040
++#define CSTATE_EXIT_LATENCY_S0i1 1040
++#define CSTATE_EXIT_LATENCY_S0i3 2800
++#endif
++#define BYT_S0I1_STATE 0x60
++#define BYT_S0I2_STATE 0x62
++#define BYT_LPMP3_STATE 0x62
++#define BYT_S0I3_STATE 0x64
++
++enum s3_parts {
++ PROC_FRZ,
++ DEV_SUS,
++ NB_CPU_OFF,
++ NB_CPU_ON,
++ DEV_RES,
++ PROC_UNFRZ,
++ MAX_S3_PARTS
++};
++
++#ifdef CONFIG_ATOM_SOC_POWER
++#define LOG_PMU_EVENTS
++
++/* Error codes for pmu */
++#define PMU_SUCCESS 0
++#define PMU_FAILED -1
++#define PMU_BUSY_STATUS 0
++#define PMU_MODE_ID 1
++#define SET_MODE 1
++#define SET_AOAC_S0i1 2
++#define SET_AOAC_S0i3 3
++#define SET_LPAUDIO 4
++#define SET_AOAC_S0i2 7
++
++#ifdef CONFIG_REMOVEME_INTEL_ATOM_MRFLD_POWER
++#define MID_S0I1_STATE 0x60
++#define MID_S0I2_STATE 0x62
++#define MID_LPMP3_STATE 0x62
++#define MID_S0I3_STATE 0x64
++#else
++#define MID_S0I1_STATE 0x1
++#define MID_LPMP3_STATE 0x3
++#define MID_S0I2_STATE 0x7
++#define MID_S0I3_STATE 0x7
++#endif
++
++#define MID_S0IX_STATE 0xf
++#define MID_S3_STATE 0x1f
++#define MID_FAST_ON_OFF_STATE 0x3f
++
++/* combinations */
++#define MID_LPI1_STATE 0x1f
++#define MID_LPI3_STATE 0x7f
++#define MID_I1I3_STATE 0xff
++
++#define REMOVE_LP_FROM_LPIX 4
++
++/* Power number for MID_POWER */
++#define C0_POWER_USAGE 450
++#define C6_POWER_USAGE 200
++#define LPMP3_POWER_USAGE 130
++#define S0I1_POWER_USAGE 50
++#define S0I3_POWER_USAGE 31
++
++extern unsigned int enable_s3;
++extern unsigned int enable_s0ix;
++
++extern void pmu_s0ix_demotion_stat(int req_state, int grant_state);
++extern unsigned int pmu_get_new_cstate(unsigned int cstate, int *index);
++extern int get_target_platform_state(unsigned long *eax);
++extern int mid_s0ix_enter(int);
++extern int pmu_set_devices_in_d0i0(void);
++extern int pmu_pci_set_power_state(struct pci_dev *pdev, pci_power_t state);
++extern pci_power_t pmu_pci_choose_state(struct pci_dev *pdev);
++
++extern void time_stamp_in_suspend_flow(int mark, bool start);
++extern void time_stamp_for_sleep_state_latency(int sleep_state,
++ bool start, bool entry);
++extern int mid_state_to_sys_state(int mid_state);
++extern void pmu_power_off(void);
++extern void pmu_set_s0ix_complete(void);
++extern bool pmu_is_s0ix_in_progress(void);
++extern int pmu_nc_set_power_state
++ (int islands, int state_type, int reg_type);
++extern int pmu_nc_get_power_state(int island, int reg_type);
++extern int pmu_set_emmc_to_d0i0_atomic(void);
++
++#ifdef LOG_PMU_EVENTS
++extern void pmu_log_ipc(u32 command);
++extern void pmu_log_ipc_irq(void);
++#else
++static inline void pmu_log_ipc(u32 command) { return; };
++static inline void pmu_log_ipc_irq(void) { return; };
++#endif
++extern void dump_nc_power_history(void);
++
++extern bool mid_pmu_is_wake_source(u32 lss_number);
++
++extern void (*nc_report_power_state) (u32, int);
++#else
++
++/*
++ * If CONFIG_ATOM_SOC_POWER is not defined
++ * fall back to C6
++ */
++
++#define MID_S0I1_STATE C6_HINT
++#define MID_LPMP3_STATE C6_HINT
++#define MID_S0I3_STATE C6_HINT
++#define MID_S3_STATE C6_HINT
++#define MID_FAST_ON_OFF_STATE C6_HINT
++
++/* Power usage unknown if MID_POWER not defined */
++#define C0_POWER_USAGE 0
++#define C6_POWER_USAGE 0
++#define LPMP3_POWER_USAGE 0
++#define S0I1_POWER_USAGE 0
++#define S0I3_POWER_USAGE 0
++
++#define TEMP_DTS_ID 43
++
++static inline int pmu_nc_set_power_state
++ (int islands, int state_type, int reg_type) { return 0; }
++static inline int pmu_nc_get_power_state(int island, int reg_type) { return 0; }
++
++static inline void pmu_set_s0ix_complete(void) { return; }
++static inline bool pmu_is_s0ix_in_progress(void) { return false; };
++static inline unsigned int pmu_get_new_cstate
++ (unsigned int cstate, int *index) { return cstate; };
++
++/*returns function not implemented*/
++static inline void time_stamp_in_suspend_flow(int mark, bool start) {}
++static inline void time_stamp_for_sleep_state_latency(int sleep_state,
++ bool start, bool entry) {}
++static inline int mid_state_to_sys_state(int mid_state) { return 0; }
++
++static inline int pmu_set_devices_in_d0i0(void) { return 0; }
++static inline void pmu_log_ipc(u32 command) { return; };
++static inline void pmu_log_ipc_irq(void) { return; };
++static inline int pmu_set_emmc_to_d0i0_atomic(void) { return -ENOSYS; }
++static inline void pmu_power_off(void) { return; }
++static inline bool mid_pmu_is_wake_source(u32 lss_number) { return false; }
++#endif /* #ifdef CONFIG_ATOM_SOC_POWER */
++
++#endif /* #ifndef INTEL_MID_PM_H */
+diff --git a/include/linux/intel_pidv_acpi.h b/include/linux/intel_pidv_acpi.h
+new file mode 100644
+index 0000000..77f0178
+--- /dev/null
++++ b/include/linux/intel_pidv_acpi.h
+@@ -0,0 +1,54 @@
++/*
++ * include/linux/intel_pidv_acpi.h
++ *
++ * Copyright (C) 2013 Intel Corp
++ * Author: Vincent Tinelli (vincent.tinelli@intel.com)
++ *
++ * 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; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ */
++
++#ifndef _INTEL_PIDV_ACPI_H
++#define _INTEL_PIDV_ACPI_H
++
++#include <linux/acpi.h>
++#ifdef CONFIG_ACPI
++#define ACPI_SIG_PIDV "PIDV"
++
++#define pidv_attr(_name) \
++static struct kobj_attribute _name##_attr = { \
++ .attr = { \
++ .name = __stringify(_name), \
++ .mode = 0440, \
++ }, \
++ .show = _name##_show, \
++}
++
++struct platform_id {
++ u8 part_number[32];
++ u8 ext_id_1[32];
++ u8 ext_id_2[32];
++ u8 uuid[16];
++ u8 iafw_major;
++ u8 iafw_minor;
++ u8 secfw_major;
++ u8 secfw_minor;
++};
++
++struct acpi_table_pidv {
++ struct acpi_table_header header;
++ struct platform_id pidv;
++};
++
++#endif
++#endif
+diff --git a/include/linux/irq.h b/include/linux/irq.h
+index bc4e066..5864ea8 100644
+--- a/include/linux/irq.h
++++ b/include/linux/irq.h
+@@ -94,6 +94,7 @@ enum {
+ IRQ_NESTED_THREAD = (1 << 15),
+ IRQ_NOTHREAD = (1 << 16),
+ IRQ_PER_CPU_DEVID = (1 << 17),
++ IRQ_CHAINED = (1 << 18),
+ };
+
+ #define IRQF_MODIFY_MASK \
+diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
+index 623325e..d394f78 100644
+--- a/include/linux/irqdesc.h
++++ b/include/linux/irqdesc.h
+@@ -123,6 +123,13 @@ static inline int irq_has_action(unsigned int irq)
+ return desc->action != NULL;
+ }
+
++/* Test to see if the IRQ is chained */
++static inline int irq_is_chained(unsigned int irq)
++{
++ struct irq_desc *desc = irq_to_desc(irq);
++ return desc->status_use_accessors & IRQ_CHAINED;
++}
++
+ /* caller has locked the irq_desc and both params are valid */
+ static inline void __irq_set_handler_locked(unsigned int irq,
+ irq_flow_handler_t handler)
+diff --git a/include/linux/lnw_gpio.h b/include/linux/lnw_gpio.h
+new file mode 100644
+index 0000000..2e9f6b2
+--- /dev/null
++++ b/include/linux/lnw_gpio.h
+@@ -0,0 +1,14 @@
++#ifndef _H_LANGWELL_GPIO_H
++#define _H_LANGWELL_GPIO_H
++
++enum {
++ LNW_GPIO = 0,
++ LNW_ALT_1 = 1,
++ LNW_ALT_2 = 2,
++ LNW_ALT_3 = 3,
++};
++
++void lnw_gpio_set_alt(int gpio, int alt);
++int gpio_get_alt(int gpio);
++
++#endif
+diff --git a/include/linux/mfd/intel_msic.h b/include/linux/mfd/intel_msic.h
+index 439a7a6..5121763 100644
+--- a/include/linux/mfd/intel_msic.h
++++ b/include/linux/mfd/intel_msic.h
+@@ -12,6 +12,8 @@
+ #ifndef __LINUX_MFD_INTEL_MSIC_H__
+ #define __LINUX_MFD_INTEL_MSIC_H__
+
++#include <asm/intel_mid_gpadc.h>
++
+ /* ID */
+ #define INTEL_MSIC_ID0 0x000 /* RO */
+ #define INTEL_MSIC_ID1 0x001 /* RO */
+@@ -52,6 +54,15 @@
+ #define INTEL_MSIC_PBCONFIG 0x03e
+ #define INTEL_MSIC_PBSTATUS 0x03f /* RO */
+
++/*
++ * MSIC interrupt tree is readable from SRAM at INTEL_MSIC_IRQ_PHYS_BASE.
++ * Since IRQ block starts from address 0x002 we need to substract that from
++ * the actual IRQ status register address.
++ */
++#define MSIC_IRQ_STATUS(x) (INTEL_MSIC_IRQ_PHYS_BASE + ((x) - 2))
++#define MSIC_IRQ_STATUS_ACCDET MSIC_IRQ_STATUS(INTEL_MSIC_ACCDET)
++#define MSIC_IRQ_STATUS_OCAUDIO MSIC_IRQ_STATUS(INTEL_MSIC_OCAUDIO)
++
+ /* GPIO */
+ #define INTEL_MSIC_GPIO0LV7CTLO 0x040
+ #define INTEL_MSIC_GPIO0LV6CTLO 0x041
+@@ -377,9 +388,39 @@
+ /**
+ * struct intel_msic_gpio_pdata - platform data for the MSIC GPIO driver
+ * @gpio_base: base number for the GPIOs
++ * @ngpio_lv: number of low voltage GPIOs
++ * @ngpio_hv: number of high voltage GPIOs
++ * @gpio0_lv_ctlo: low voltage GPIO0 output control register
++ * @gpio0_lv_ctli: low voltage GPIO0 input control register
++ * @gpio0_hv_ctlo: high voltage GPIO0 output control register
++ * @gpio0_hv_ctli: high voltage GPIO0 input control register
++ * @can_sleep: flag for gpio chip
+ */
+ struct intel_msic_gpio_pdata {
+ unsigned gpio_base;
++ int ngpio_lv;
++ int ngpio_hv;
++ u16 gpio0_lv_ctlo;
++ u16 gpio0_lv_ctli;
++ u16 gpio0_hv_ctlo;
++ u16 gpio0_hv_ctli;
++ int can_sleep;
++};
++
++#define DISABLE_VCRIT 0x01
++#define DISABLE_VWARNB 0x02
++#define DISABLE_VWARNA 0x04
++/**
++ * struct intel_msic_vdd_pdata - platform data for the MSIC VDD driver
++ * @msi: MSI number used for VDD interrupts
++ *
++ * The MSIC CTP driver converts @msi into an IRQ number and passes it to
++ * the VDD driver as %IORESOURCE_IRQ.
++ */
++struct intel_msic_vdd_pdata {
++ unsigned msi;
++ /* 1 = VCRIT, 2 = WARNB, 4 = WARNA */
++ u8 disable_unused_comparator;
+ };
+
+ /**
+@@ -429,6 +470,7 @@ struct intel_msic_platform_data {
+ int irq[INTEL_MSIC_BLOCK_LAST];
+ struct intel_msic_gpio_pdata *gpio;
+ struct intel_msic_ocd_pdata *ocd;
++ struct intel_mid_gpadc_platform_data *gpadc;
+ };
+
+ struct intel_msic;
+diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
+index f31725b..39e8279 100644
+--- a/include/linux/mmc/card.h
++++ b/include/linux/mmc/card.h
+@@ -67,6 +67,7 @@ struct mmc_ext_csd {
+ #define MMC_HIGH_52_MAX_DTR 52000000
+ #define MMC_HIGH_DDR_MAX_DTR 52000000
+ #define MMC_HS200_MAX_DTR 200000000
++#define MMC_HS400_MAX_DTR 200000000
+ unsigned int sectors;
+ unsigned int card_type;
+ unsigned int hc_erase_size; /* In sectors */
+@@ -248,6 +249,7 @@ struct mmc_card {
+ #define MMC_CARD_SDXC (1<<6) /* card is SDXC */
+ #define MMC_CARD_REMOVED (1<<7) /* card has been removed */
+ #define MMC_STATE_HIGHSPEED_200 (1<<8) /* card is in HS200 mode */
++#define MMC_STATE_HIGHSPEED_400 (1<<9) /* card is in HS400 mode */
+ #define MMC_STATE_DOING_BKOPS (1<<10) /* card is doing BKOPS */
+ unsigned int quirks; /* card quirks */
+ #define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */
+@@ -264,6 +266,7 @@ struct mmc_card {
+ #define MMC_QUIRK_LONG_READ_TIME (1<<9) /* Data read time > CSD says */
+ #define MMC_QUIRK_SEC_ERASE_TRIM_BROKEN (1<<10) /* Skip secure for erase/trim */
+ /* byte mode */
++#define MMC_QUIRK_NON_STD_CIS (1<<11)
+
+ unsigned int erase_size; /* erase size in sectors */
+ unsigned int erase_shift; /* if erase unit is power 2 */
+@@ -409,6 +412,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
+ #define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
+ #define mmc_card_highspeed(c) ((c)->state & MMC_STATE_HIGHSPEED)
+ #define mmc_card_hs200(c) ((c)->state & MMC_STATE_HIGHSPEED_200)
++#define mmc_card_hs400(c) ((c)->state & MMC_STATE_HIGHSPEED_400)
+ #define mmc_card_blockaddr(c) ((c)->state & MMC_STATE_BLOCKADDR)
+ #define mmc_card_ddr_mode(c) ((c)->state & MMC_STATE_HIGHSPEED_DDR)
+ #define mmc_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
+@@ -421,6 +425,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
+ #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
+ #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
+ #define mmc_card_set_hs200(c) ((c)->state |= MMC_STATE_HIGHSPEED_200)
++#define mmc_card_set_hs400(c) ((c)->state |= MMC_STATE_HIGHSPEED_400)
+ #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
+ #define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
+ #define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
+diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
+index 39613b9..3e3b95e 100644
+--- a/include/linux/mmc/core.h
++++ b/include/linux/mmc/core.h
+@@ -121,6 +121,7 @@ struct mmc_data {
+ unsigned int sg_len; /* size of scatter list */
+ struct scatterlist *sg; /* I/O scatter list */
+ s32 host_cookie; /* host private data */
++ dma_addr_t dmabuf; /* used in panic mode */
+ };
+
+ struct mmc_host;
+diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
+index e326ae2..1416210 100644
+--- a/include/linux/mmc/host.h
++++ b/include/linux/mmc/host.h
+@@ -59,6 +59,7 @@ struct mmc_ios {
+ #define MMC_TIMING_UHS_SDR104 6
+ #define MMC_TIMING_UHS_DDR50 7
+ #define MMC_TIMING_MMC_HS200 8
++#define MMC_TIMING_MMC_HS400 9
+
+ #define MMC_SDR_MODE 0
+ #define MMC_1_2V_DDR_MODE 1
+@@ -80,6 +81,19 @@ struct mmc_ios {
+ #define MMC_SET_DRIVER_TYPE_D 3
+ };
+
++struct mmc_panic_host;
++
++struct mmc_host_panic_ops {
++ void (*request)(struct mmc_panic_host *, struct mmc_request *);
++ void (*prepare)(struct mmc_panic_host *);
++ int (*setup)(struct mmc_panic_host *);
++ void (*set_ios)(struct mmc_panic_host *);
++ void (*dumpregs)(struct mmc_panic_host *);
++ int (*power_on)(struct mmc_panic_host *);
++ int (*hold_mutex)(struct mmc_panic_host *);
++ void (*release_mutex)(struct mmc_panic_host *);
++};
++
+ struct mmc_host_ops {
+ /*
+ * 'enable' is called when the host is claimed and 'disable' is called
+@@ -139,6 +153,9 @@ struct mmc_host_ops {
+ int (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
+ void (*hw_reset)(struct mmc_host *host);
+ void (*card_event)(struct mmc_host *host);
++ void (*set_dev_power)(struct mmc_host *, bool);
++ /* Prevent host controller from Auto Clock Gating by busy reading */
++ void (*busy_wait)(struct mmc_host *mmc, u32 delay);
+ };
+
+ struct mmc_card;
+@@ -195,6 +212,27 @@ struct mmc_supply {
+ struct regulator *vqmmc; /* Optional Vccq supply */
+ };
+
++struct mmc_panic_host {
++ /*
++ * DMA buffer for the log
++ */
++ dma_addr_t dmabuf;
++ void *logbuf;
++ const struct mmc_host_panic_ops *panic_ops;
++ unsigned int panic_ready;
++ unsigned int totalsecs;
++ unsigned int max_blk_size;
++ unsigned int max_blk_count;
++ unsigned int max_req_size;
++ unsigned int blkaddr;
++ unsigned int caps;
++ u32 ocr; /* the current OCR setting */
++ struct mmc_ios ios; /* current io bus settings */
++ struct mmc_card *card;
++ struct mmc_host *mmc;
++ void *priv;
++};
++
+ struct mmc_host {
+ struct device *parent;
+ struct device class_dev;
+@@ -281,6 +319,17 @@ struct mmc_host {
+ #define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \
+ MMC_CAP2_PACKED_WR)
+ #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14) /* Don't power up before scan */
++#define MMC_CAP2_INIT_CARD_SYNC (1 << 15) /* init card in sync mode */
++#define MMC_CAP2_POLL_R1B_BUSY (1 << 16) /* host poll R1B busy*/
++#define MMC_CAP2_RPMBPART_NOACC (1 << 17) /* RPMB partition no access */
++#define MMC_CAP2_LED_SUPPORT (1 << 18) /* led support */
++#define MMC_CAP2_PWCTRL_POWER (1 << 19) /* power control card power */
++#define MMC_CAP2_FIXED_NCRC (1 << 20) /* fixed NCRC */
++#define MMC_CAP2_HS200_WA (1 << 21) /* WA: 100MHz clock in HS200 */
++#define MMC_CAP2_HS400_1_8V_DDR (1 << 22) /* support HS400 */
++#define MMC_CAP2_HS400_1_2V_DDR (1 << 23) /* support HS400 */
++#define MMC_CAP2_HS400 (MMC_CAP2_HS400_1_8V_DDR | \
++ MMC_CAP2_HS400_1_2V_DDR)
+
+ mmc_pm_flag_t pm_caps; /* supported pm features */
+
+@@ -362,9 +411,24 @@ struct mmc_host {
+
+ unsigned int slotno; /* used for sdio acpi binding */
+
++#ifdef CONFIG_MMC_EMBEDDED_SDIO
++ struct {
++ struct sdio_cis *cis;
++ struct sdio_cccr *cccr;
++ struct sdio_embedded_func *funcs;
++ int num_funcs;
++ } embedded_sdio_data;
++#endif
++ struct mmc_panic_host *phost;
+ unsigned long private[0] ____cacheline_aligned;
+ };
+
++#define SECTOR_SIZE 512
++int mmc_emergency_init(void);
++int mmc_emergency_write(char *, unsigned int);
++void mmc_alloc_panic_host(struct mmc_host *, const struct mmc_host_panic_ops *);
++void mmc_emergency_setup(struct mmc_host *host);
++
+ struct mmc_host *mmc_alloc_host(int extra, struct device *);
+ int mmc_add_host(struct mmc_host *);
+ void mmc_remove_host(struct mmc_host *);
+diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
+index 50bcde3..3633133 100644
+--- a/include/linux/mmc/mmc.h
++++ b/include/linux/mmc/mmc.h
+@@ -325,6 +325,7 @@ struct _mmc_csd {
+ #define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */
+ #define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */
+ #define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */
++#define EXT_CSD_PWR_CL_200_DDR_195 253 /* RO, support HS400 */
+ #define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */
+ #define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */
+ #define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */
+@@ -357,6 +358,7 @@ struct _mmc_csd {
+ #define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */
+ #define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */
+ #define EXT_CSD_CARD_TYPE_MASK 0x3F /* Mask out reserved bits */
++#define EXT_CSD_CARD_TYPE_MASK_FULL 0xFF /* Support HS400 */
+ #define EXT_CSD_CARD_TYPE_DDR_1_8V (1<<2) /* Card can run at 52MHz */
+ /* DDR mode @1.8V or 3V I/O */
+ #define EXT_CSD_CARD_TYPE_DDR_1_2V (1<<3) /* Card can run at 52MHz */
+@@ -366,6 +368,9 @@ struct _mmc_csd {
+ #define EXT_CSD_CARD_TYPE_SDR_1_8V (1<<4) /* Card can run at 200MHz */
+ #define EXT_CSD_CARD_TYPE_SDR_1_2V (1<<5) /* Card can run at 200MHz */
+ /* SDR mode @1.2V I/O */
++#define EXT_CSD_CARD_TYPE_HS400_1_8V (1<<6) /* Card can run at 200MHz */
++#define EXT_CSD_CARD_TYPE_HS400_1_2V (1<<7) /* Card can run at 200MHz */
++ /* DDR mode @1.8/1.2v I/O */
+
+ #define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
+ #define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
+diff --git a/include/linux/mmc/sdhci-pci-data.h b/include/linux/mmc/sdhci-pci-data.h
+index 8959604..a4c8606 100644
+--- a/include/linux/mmc/sdhci-pci-data.h
++++ b/include/linux/mmc/sdhci-pci-data.h
+@@ -8,10 +8,26 @@ struct sdhci_pci_data {
+ int slotno;
+ int rst_n_gpio; /* Set to -EINVAL if unused */
+ int cd_gpio; /* Set to -EINVAL if unused */
++ int quirks;
++ int quirks2;
++ int platform_quirks; /* Platform related quirks */
+ int (*setup)(struct sdhci_pci_data *data);
+ void (*cleanup)(struct sdhci_pci_data *data);
++ int (*power_up)(void *data);
++ void (*register_embedded_control)(void *dev_id,
++ void (*virtual_cd)(void *dev_id, int card_present));
++ int (*flis_check)(void *data, unsigned int clk);
+ };
+
++/* Some Pre-Silicon platform not support all SDHCI HCs of the SoC */
++#define PLFM_QUIRK_NO_HOST_CTRL_HW (1<<0)
++/* Some Pre-Silicon platform do not support eMMC boot partition access */
++#define PLFM_QUIRK_NO_EMMC_BOOT_PART (1<<1)
++/* Some Pre-Silicon platform do not support eMMC or SD High Speed */
++#define PLFM_QUIRK_NO_HIGH_SPEED (1<<2)
++/* For the platform which don't have the SD card slot */
++#define PLFM_QUIRK_NO_SDCARD_SLOT (1<<3)
++
+ extern struct sdhci_pci_data *(*sdhci_pci_get_data)(struct pci_dev *pdev,
+ int slotno);
+
+diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
+index b838ffc..d4c124b 100644
+--- a/include/linux/mmc/sdhci.h
++++ b/include/linux/mmc/sdhci.h
+@@ -96,9 +96,57 @@ struct sdhci_host {
+ #define SDHCI_QUIRK2_NO_1_8_V (1<<2)
+ #define SDHCI_QUIRK2_PRESET_VALUE_BROKEN (1<<3)
+
++/* Intel private quirk2 starts on 15 */
++
++/* V2.0 host controller support DDR50 */
++#define SDHCI_QUIRK2_V2_0_SUPPORT_DDR50 (1<<15)
++/* Controller has bug when enabling Auto CMD23 */
++#define SDHCI_QUIRK2_BROKEN_AUTO_CMD23 (1<<16)
++/* HC Reg High Speed must be set later than HC2 Reg 1.8v Signaling Enable */
++#define SDHCI_QUIRK2_HIGH_SPEED_SET_LATE (1<<17)
++/* BRCM voltage support: advertise 2.0v support and force using 1.8v instead */
++#define SDHCI_QUIRK2_ADVERTISE_2V0_FORCE_1V8 (1<<18)
++/* to allow mmc_detect to detach the bus */
++#define SDHCI_QUIRK2_DISABLE_MMC_CAP_NONREMOVABLE (1<<19)
++/* avoid detect/rescan/poweoff operations on suspend/resume. */
++#define SDHCI_QUIRK2_ENABLE_MMC_PM_IGNORE_PM_NOTIFY (1<<20)
++/* Disable eMMC/SD card High speed feature. */
++#define SDHCI_QUIRK2_DISABLE_HIGH_SPEED (1<<21)
++#define SDHCI_QUIRK2_CAN_VDD_300 (1<<22)
++#define SDHCI_QUIRK2_CAN_VDD_330 (1<<23)
++#define SDHCI_QUIRK2_2MS_DELAY (1<<24)
++#define SDHCI_QUIRK2_WAIT_FOR_IDLE (1<<25)
++/* BAD sd cd in HOST IC. This will cause system hang when removing SD */
++#define SDHCI_QUIRK2_BAD_SD_CD (1<<26)
++#define SDHCI_QUIRK2_POWER_PIN_GPIO_MODE (1<<27)
++#define SDHCI_QUIRK2_ADVERTISE_3V0_FORCE_1V8 (1<<28)
++#define SDHCI_QUIRK2_NON_STD_CIS (1<<29)
++#define SDHCI_QUIRK2_TUNING_POLL (1<<30)
++
+ int irq; /* Device IRQ */
+ void __iomem *ioaddr; /* Mapped address */
+
++ /*
++ * XXX: SCU/X86 mutex variables base address in shared SRAM
++ * NOTE: Max size of this struct is 16 bytes
++ * without shared SRAM re-organization.
++ */
++ void __iomem *sram_addr; /* Shared SRAM address */
++
++ void __iomem *rte_addr; /* IOAPIC RTE register address */
++
++#define DEKKER_EMMC_OWNER_OFFSET 0
++#define DEKKER_IA_REQ_OFFSET 0x04
++#define DEKKER_SCU_REQ_OFFSET 0x08
++/* 0xc offset: state of the emmc chip to SCU. */
++#define DEKKER_EMMC_STATE 0x0c
++#define DEKKER_OWNER_IA 0
++#define DEKKER_OWNER_SCU 1
++#define DEKKER_EMMC_CHIP_ACTIVE 0
++#define DEKKER_EMMC_CHIP_SUSPENDED 1
++
++ unsigned int usage_cnt; /* eMMC mutex usage count */
++
+ const struct sdhci_ops *ops; /* Low level hw interface */
+
+ struct regulator *vmmc; /* Power regulator (vmmc) */
+@@ -114,6 +162,7 @@ struct sdhci_host {
+ #endif
+
+ spinlock_t lock; /* Mutex */
++ spinlock_t dekker_lock; /* eMMC Dekker Mutex lock */
+
+ int flags; /* Host attributes */
+ #define SDHCI_USE_SDMA (1<<0) /* Host is SDMA capable */
+@@ -128,6 +177,7 @@ struct sdhci_host {
+ #define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */
+ #define SDHCI_HS200_NEEDS_TUNING (1<<10) /* HS200 needs tuning */
+ #define SDHCI_USING_RETUNING_TIMER (1<<11) /* Host is using a retuning timer for the card */
++#define SDHCI_POWER_CTRL_DEV (1<<12) /* ctrl dev power */
+
+ unsigned int version; /* SDHCI spec. version */
+
+@@ -139,11 +189,13 @@ struct sdhci_host {
+ u8 pwr; /* Current voltage */
+
+ bool runtime_suspended; /* Host is runtime suspended */
++ bool suspended; /* Host is suspended */
+
+ struct mmc_request *mrq; /* Current request */
+ struct mmc_command *cmd; /* Current command */
+ struct mmc_data *data; /* Current data request */
+ unsigned int data_early:1; /* Data finished before cmd */
++ unsigned int r1b_busy_end:1; /* R1B busy end */
+
+ struct sg_mapping_iter sg_miter; /* SG state for PIO */
+ unsigned int blocks; /* remaining PIO blocks */
+diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h
+index 9f03fee..b3933db 100644
+--- a/include/linux/mmc/sdio_ids.h
++++ b/include/linux/mmc/sdio_ids.h
+@@ -23,6 +23,8 @@
+ /*
+ * Vendors and devices. Sort key: vendor first, device next.
+ */
++#define IWL_SDIO_DEVICE_ID_WKP1 0x3160
++#define IWL_SDIO_DEVICE_ID_WKP2 0x7260
+ #define SDIO_VENDOR_ID_INTEL 0x0089
+ #define SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX 0x1402
+ #define SDIO_DEVICE_ID_INTEL_IWMC3200WIFI 0x1403
+diff --git a/include/linux/panic_gbuffer.h b/include/linux/panic_gbuffer.h
+new file mode 100644
+index 0000000..c0580e5
+--- /dev/null
++++ b/include/linux/panic_gbuffer.h
+@@ -0,0 +1,37 @@
++/*
++ * panic_gbuffer.h
++ *
++ * Copyright (C) 2013 Intel Corp
++ *
++ * Expose a generic buffer header to be passed to the panic handler in
++ * order to dump buffer content in case of kernel panic.
++ *
++ * -----------------------------------------------------------------------
++ *
++ * 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; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ */
++
++#ifndef _LINUX_PANIC_GBUFFER_H
++#define _LINUX_PANIC_GBUFFER_H
++
++struct g_buffer_header {
++ unsigned char *base;
++ size_t size;
++ size_t woff;
++ size_t head;
++};
++
++void panic_set_gbuffer(struct g_buffer_header *gbuffer);
++
++#endif /* _LINUX_PANIC_GBUFFER_H */
+diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
+index cb45b70..eacb93b 100644
+--- a/include/linux/pci_ids.h
++++ b/include/linux/pci_ids.h
+@@ -2551,6 +2551,19 @@
+ #define PCI_DEVICE_ID_INTEL_MFD_EMMC1 0x0824
+ #define PCI_DEVICE_ID_INTEL_MRST_SD2 0x084F
+ #define PCI_DEVICE_ID_INTEL_I960 0x0960
++#define PCI_DEVICE_ID_INTEL_CLV_SDIO0 0x08F9
++#define PCI_DEVICE_ID_INTEL_CLV_SDIO1 0x08FA
++#define PCI_DEVICE_ID_INTEL_CLV_SDIO2 0x08FB
++#define PCI_DEVICE_ID_INTEL_CLV_EMMC0 0x08E5
++#define PCI_DEVICE_ID_INTEL_CLV_EMMC1 0x08E6
++#define PCI_DEVICE_ID_INTEL_CLV_OTG 0xE006
++#define PCI_DEVICE_ID_INTEL_MRFL_MMC 0x1190
++#define PCI_DEVICE_ID_INTEL_MRFL_DWC3_OTG 0x119E
++#define PCI_DEVICE_ID_INTEL_BYT_EMMC 0x0f14
++#define PCI_DEVICE_ID_INTEL_BYT_SDIO 0x0f15
++#define PCI_DEVICE_ID_INTEL_BYT_SD 0x0f16
++#define PCI_DEVICE_ID_INTEL_BYT_EMMC45 0x0f50
++#define PCI_DEVICE_ID_INTEL_BYT_OTG 0x0f37
+ #define PCI_DEVICE_ID_INTEL_I960RM 0x0962
+ #define PCI_DEVICE_ID_INTEL_CENTERTON_ILB 0x0c60
+ #define PCI_DEVICE_ID_INTEL_8257X_SOL 0x1062
+diff --git a/include/linux/platform_data/intel_mid_remoteproc.h b/include/linux/platform_data/intel_mid_remoteproc.h
+new file mode 100644
+index 0000000..a16dffb
+--- /dev/null
++++ b/include/linux/platform_data/intel_mid_remoteproc.h
+@@ -0,0 +1,119 @@
++/*
++ * INTEL MID Remote Processor Head File
++ *
++ * Copyright (C) 2012 Intel, Inc.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++#ifndef _ASM_INTEL_MID_REMOTEPROC_H
++#define _ASM_INTEL_MID_REMOTEPROC_H
++
++#define RP_IPC_COMMAND 0xA0
++#define RP_IPC_SIMPLE_COMMAND 0xA1
++#define RP_IPC_RAW_COMMAND 0xA2
++
++#define RP_PMIC_ACCESS 0xFF
++#define RP_DFU_REQUEST 0xFE
++#define RP_SET_WATCHDOG 0xF8
++#define RP_FLIS_ACCESS 0xF5
++#define RP_GET_FW_REVISION 0xF4
++#define RP_COLD_BOOT 0xF3
++#define RP_COLD_RESET 0xF1
++#define RP_COLD_OFF 0x80
++#define RP_MIP_ACCESS 0xEC
++#define RP_GET_HOBADDR 0xE5
++#define RP_OSC_CLK_CTRL 0xE6
++#define RP_S0IX_COUNTER 0xE8
++#define RP_WRITE_OSNIB 0xE4
++#define RP_CLEAR_FABERROR 0xE3
++#define RP_FW_UPDATE 0xFE
++#define RP_VRTC 0xFA
++#define RP_PMDB 0xE0
++#define RP_WRITE_OEMNIB 0xDF /* Command is used to write OEMNIB */
++ /* data. Used with extended OSHOB */
++ /* OSNIB only. */
++/*
++ * Assigning some temp ids for following devices
++ * TODO: Need to change it to some meaningful
++ * values.
++ */
++#define RP_PMIC_GPIO 0X02
++#define RP_PMIC_AUDIO 0x03
++#define RP_MSIC_GPIO 0x05
++#define RP_MSIC_AUDIO 0x06
++#define RP_MSIC_OCD 0x07
++#define RP_MSIC_BATTERY 0XEF
++#define RP_MSIC_THERMAL 0x09
++#define RP_MSIC_POWER_BTN 0x10
++#define RP_IPC 0X11
++#define RP_IPC_UTIL 0X12
++#define RP_FW_ACCESS 0X13
++#define RP_UMIP_ACCESS 0x14
++#define RP_OSIP_ACCESS 0x15
++#define RP_MSIC_ADC 0x16
++#define RP_BQ24192 0x17
++#define RP_MSIC_CLV_AUDIO 0x18
++#define RP_PMIC_CCSM 0x19
++#define RP_PMIC_I2C 0x20
++#define RP_MSIC_MRFLD_AUDIO 0x21
++#define RP_MSIC_PWM 0x22
++#define RP_MSIC_KPD_LED 0x23
++#define RP_BCOVE_ADC 0x24
++#define RP_BCOVE_THERMAL 0x25
++#define RP_MRFL_OCD 0x26
++#define RP_FW_LOGGING 0x27
++#define RP_PMIC_CHARGER 0x28
++
++enum rproc_type {
++ RPROC_SCU = 0,
++ RPROC_PSH,
++ RPROC_NUM,
++};
++
++struct rproc_ops;
++struct platform_device;
++struct rpmsg_ns_msg;
++
++struct rpmsg_ns_info {
++ enum rproc_type type;
++ char name[RPMSG_NAME_SIZE];
++ u32 addr;
++ u32 flags;
++ struct list_head node;
++};
++
++struct rpmsg_ns_list {
++ struct list_head list;
++ struct mutex lock;
++};
++
++extern struct rpmsg_ns_info *rpmsg_ns_alloc(const char *name,
++ int id, u32 addr);
++extern void rpmsg_ns_add_to_list(struct rpmsg_ns_info *info,
++ struct rpmsg_ns_list *nslist);
++
++/*
++ * struct intel_mid_rproc_pdata - intel mid remoteproc's platform data
++ * @name: the remoteproc's name
++ * @firmware: name of firmware file to load
++ * @ops: start/stop rproc handlers
++ * @device_enable: handler for enabling a device
++ * @device_shutdown: handler for shutting down a device
++ */
++struct intel_mid_rproc_pdata {
++ const char *name;
++ const char *firmware;
++ const struct rproc_ops *ops;
++ int (*device_enable) (struct platform_device *pdev);
++ int (*device_shutdown) (struct platform_device *pdev);
++ struct rpmsg_ns_list *nslist;
++};
++
++#endif /* _ASM_INTEL_MID_REMOTEPROC_H */
+diff --git a/include/linux/platform_data/ti-ads7955.h b/include/linux/platform_data/ti-ads7955.h
+new file mode 100644
+index 0000000..da1451e
+--- /dev/null
++++ b/include/linux/platform_data/ti-ads7955.h
+@@ -0,0 +1,21 @@
++/*
++ * ADS7955 SPI ADC driver
++ *
++ * (C) Copyright 2014 Intel Corporation
++ * Author: Dave Hunt <dave.hunt@emutex.com>
++ *
++ * Licensed under the GPL-2.
++ */
++
++#ifndef __LINUX_PLATFORM_DATA_TI_ADS7955_H__
++#define __LINUX_PLATFORM_DATA_TI_ADS7955_H__
++
++/**
++ * struct ads7955_platform_data - Platform data for the ads7955 ADC driver
++ * @ext_ref: Whether to use an external reference voltage.
++ **/
++struct ads7955_platform_data {
++ bool ext_ref;
++};
++
++#endif /* __LINUX_PLATFORM_DATA_TI_ADS7955_H__ */
+diff --git a/include/linux/power/battery_id.h b/include/linux/power/battery_id.h
+new file mode 100644
+index 0000000..417160d
+--- /dev/null
++++ b/include/linux/power/battery_id.h
+@@ -0,0 +1,78 @@
++#ifndef __BATTERY_ID_H__
++
++#define __BATTERY_ID_H__
++
++enum {
++ POWER_SUPPLY_BATTERY_REMOVED = 0,
++ POWER_SUPPLY_BATTERY_INSERTED,
++};
++
++enum batt_chrg_prof_type {
++ PSE_MOD_CHRG_PROF = 0,
++};
++
++/* charging profile structure definition */
++struct ps_batt_chg_prof {
++ enum batt_chrg_prof_type chrg_prof_type;
++ void *batt_prof;
++};
++
++/* PSE Modified Algo Structure */
++/* Parameters defining the charging range */
++struct ps_temp_chg_table {
++ /* upper temperature limit for each zone */
++ short int temp_up_lim;
++ /* charge current and voltage */
++ short int full_chrg_vol;
++ short int full_chrg_cur;
++ /* maintenance thresholds */
++ /* maintenance lower threshold. Once battery hits full, charging
++ * charging will be resumed when battery voltage <= this voltage
++ */
++ short int maint_chrg_vol_ll;
++ /* Charge current and voltage in maintenance mode */
++ short int maint_chrg_vol_ul;
++ short int maint_chrg_cur;
++} __packed;
++
++
++#define BATTID_STR_LEN 8
++#define BATT_TEMP_NR_RNG 6
++/* Charging Profile */
++struct ps_pse_mod_prof {
++ /* battery id */
++ char batt_id[BATTID_STR_LEN];
++ /* type of battery */
++ u16 battery_type;
++ u16 capacity;
++ u16 voltage_max;
++ /* charge termination current */
++ u16 chrg_term_ma;
++ /* Low battery level voltage */
++ u16 low_batt_mV;
++ /* upper and lower temperature limits on discharging */
++ u8 disch_tmp_ul;
++ u8 disch_tmp_ll;
++ /* number of temperature monitoring ranges */
++ u16 temp_mon_ranges;
++ struct ps_temp_chg_table temp_mon_range[BATT_TEMP_NR_RNG];
++ /* Lowest temperature supported */
++ short int temp_low_lim;
++} __packed;
++
++/*For notification during battery change event*/
++extern struct atomic_notifier_head batt_id_notifier;
++
++extern void battery_prop_changed(int battery_conn_stat,
++ struct ps_batt_chg_prof *batt_prop);
++#ifdef CONFIG_POWER_SUPPLY_BATTID
++extern int get_batt_prop(struct ps_batt_chg_prof *batt_prop);
++#else
++static inline int get_batt_prop(struct ps_batt_chg_prof *batt_prop)
++{
++ return -ENOMEM;
++}
++#endif
++extern int batt_id_reg_notifier(struct notifier_block *nb);
++extern void batt_id_unreg_notifier(struct notifier_block *nb);
++#endif
+diff --git a/include/linux/power/bq24261_charger.h b/include/linux/power/bq24261_charger.h
+new file mode 100644
+index 0000000..f185659
+--- /dev/null
++++ b/include/linux/power/bq24261_charger.h
+@@ -0,0 +1,56 @@
++/*
++ * bq24261_charger.h: platform data structure for bq24261 driver
++ *
++ * (C) Copyright 2012 Intel Corporation
++ *
++ * 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; version 2
++ * of the License.
++ */
++
++#ifndef __BQ24261_CHARGER_H__
++#define __BQ24261_CHARGER_H__
++
++struct bq24261_plat_data {
++ u32 irq_map;
++ u8 irq_mask;
++ char **supplied_to;
++ size_t num_supplicants;
++ struct power_supply_throttle *throttle_states;
++ size_t num_throttle_states;
++ int safety_timer;
++ int boost_mode_ma;
++ bool is_ts_enabled;
++
++ int (*enable_charging) (bool val);
++ int (*enable_charger) (bool val);
++ int (*set_inlmt) (int val);
++ int (*set_cc) (int val);
++ int (*set_cv) (int val);
++ int (*set_iterm) (int val);
++ int (*enable_vbus) (bool val);
++ /* WA for ShadyCove VBUS removal detect issue */
++ int (*handle_low_supply) (void);
++ void (*dump_master_regs) (void);
++};
++
++extern void bq24261_cv_to_reg(int, u8*);
++extern void bq24261_cc_to_reg(int, u8*);
++extern void bq24261_inlmt_to_reg(int, u8*);
++
++#ifdef CONFIG_BQ24261_CHARGER
++extern int bq24261_get_bat_health(void);
++extern int bq24261_get_bat_status(void);
++#else
++static int bq24261_get_bat_health(void)
++{
++ return 0;
++}
++static int bq24261_get_bat_status(void)
++{
++ return 0;
++}
++#endif
++
++#endif
+diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
+index 3828cef..28b401e 100644
+--- a/include/linux/power_supply.h
++++ b/include/linux/power_supply.h
+@@ -83,6 +83,14 @@ enum {
+ POWER_SUPPLY_SCOPE_DEVICE,
+ };
+
++enum {
++ POWER_SUPPLY_CHARGE_CURRENT_LIMIT_ZERO = 0,
++ POWER_SUPPLY_CHARGE_CURRENT_LIMIT_LOW,
++ POWER_SUPPLY_CHARGE_CURRENT_LIMIT_MEDIUM,
++ POWER_SUPPLY_CHARGE_CURRENT_LIMIT_HIGH,
++ POWER_SUPPLY_CHARGE_CURRENT_LIMIT_NONE,
++};
++
+ enum power_supply_property {
+ /* Properties of type `int' */
+ POWER_SUPPLY_PROP_STATUS = 0,
+@@ -116,8 +124,14 @@ enum power_supply_property {
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
++ POWER_SUPPLY_CHARGE_CURRENT_LIMIT,
+ POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
+ POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
++ POWER_SUPPLY_PROP_CHARGE_CURRENT,
++ POWER_SUPPLY_PROP_MAX_CHARGE_CURRENT,
++ POWER_SUPPLY_PROP_CHARGE_VOLTAGE,
++ POWER_SUPPLY_PROP_MAX_CHARGE_VOLTAGE,
++ POWER_SUPPLY_PROP_INLMT,
+ POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
+ POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN,
+ POWER_SUPPLY_PROP_ENERGY_FULL,
+@@ -131,6 +145,8 @@ enum power_supply_property {
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_TEMP_ALERT_MIN,
+ POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
++ POWER_SUPPLY_PROP_MAX_TEMP,
++ POWER_SUPPLY_PROP_MIN_TEMP,
+ POWER_SUPPLY_PROP_TEMP_AMBIENT,
+ POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN,
+ POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX,
+@@ -139,6 +155,11 @@ enum power_supply_property {
+ POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
+ POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
+ POWER_SUPPLY_PROP_TYPE, /* use power_supply.type instead */
++ POWER_SUPPLY_PROP_CHARGE_TERM_CUR,
++ POWER_SUPPLY_PROP_ENABLE_CHARGING,
++ POWER_SUPPLY_PROP_ENABLE_CHARGER,
++ POWER_SUPPLY_PROP_CABLE_TYPE,
++ POWER_SUPPLY_PROP_PRIORITY,
+ POWER_SUPPLY_PROP_SCOPE,
+ /* Properties of type `const char *' */
+ POWER_SUPPLY_PROP_MODEL_NAME,
+@@ -152,16 +173,75 @@ enum power_supply_type {
+ POWER_SUPPLY_TYPE_UPS,
+ POWER_SUPPLY_TYPE_MAINS,
+ POWER_SUPPLY_TYPE_USB, /* Standard Downstream Port */
++ POWER_SUPPLY_TYPE_USB_INVAL, /* Invalid Standard Downstream Port */
+ POWER_SUPPLY_TYPE_USB_DCP, /* Dedicated Charging Port */
+ POWER_SUPPLY_TYPE_USB_CDP, /* Charging Downstream Port */
+ POWER_SUPPLY_TYPE_USB_ACA, /* Accessory Charger Adapters */
++ POWER_SUPPLY_TYPE_USB_HOST, /* To support OTG devices */
++};
++
++enum power_supply_charger_event {
++ POWER_SUPPLY_CHARGER_EVENT_CONNECT = 0,
++ POWER_SUPPLY_CHARGER_EVENT_UPDATE,
++ POWER_SUPPLY_CHARGER_EVENT_RESUME,
++ POWER_SUPPLY_CHARGER_EVENT_SUSPEND,
++ POWER_SUPPLY_CHARGER_EVENT_DISCONNECT,
++};
++
++struct power_supply_charger_cap {
++ enum power_supply_charger_event chrg_evt;
++ enum power_supply_type chrg_type;
++ unsigned int mA; /* input current limit */
++};
++
++enum power_supply_charger_cable_type {
++ POWER_SUPPLY_CHARGER_TYPE_NONE = 0,
++ POWER_SUPPLY_CHARGER_TYPE_USB_SDP = 1 << 0,
++ POWER_SUPPLY_CHARGER_TYPE_USB_DCP = 1 << 1,
++ POWER_SUPPLY_CHARGER_TYPE_USB_CDP = 1 << 2,
++ POWER_SUPPLY_CHARGER_TYPE_USB_ACA = 1 << 3,
++ POWER_SUPPLY_CHARGER_TYPE_AC = 1 << 4,
++ POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK = 1 << 5,
++ POWER_SUPPLY_CHARGER_TYPE_ACA_A = 1 << 6,
++ POWER_SUPPLY_CHARGER_TYPE_ACA_B = 1 << 7,
++ POWER_SUPPLY_CHARGER_TYPE_ACA_C = 1 << 8,
++ POWER_SUPPLY_CHARGER_TYPE_SE1 = 1 << 9,
++ POWER_SUPPLY_CHARGER_TYPE_MHL = 1 << 10,
++ POWER_SUPPLY_CHARGER_TYPE_B_DEVICE = 1 << 11,
+ };
+
++struct power_supply_cable_props {
++ enum power_supply_charger_event chrg_evt;
++ enum power_supply_charger_cable_type chrg_type;
++ unsigned int ma; /* input current limit */
++};
++
++#define POWER_SUPPLY_CHARGER_TYPE_USB \
++ (POWER_SUPPLY_CHARGER_TYPE_USB_SDP | \
++ POWER_SUPPLY_CHARGER_TYPE_USB_DCP | \
++ POWER_SUPPLY_CHARGER_TYPE_USB_CDP | \
++ POWER_SUPPLY_CHARGER_TYPE_USB_ACA | \
++ POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK| \
++ POWER_SUPPLY_CHARGER_TYPE_SE1)
++
+ union power_supply_propval {
+ int intval;
+ const char *strval;
+ };
+
++enum psy_throttle_action {
++
++ PSY_THROTTLE_DISABLE_CHARGER = 0,
++ PSY_THROTTLE_DISABLE_CHARGING,
++ PSY_THROTTLE_CC_LIMIT,
++ PSY_THROTTLE_INPUT_LIMIT,
++};
++
++struct power_supply_throttle {
++ enum psy_throttle_action throttle_action;
++ unsigned throttle_val;
++};
++
+ struct power_supply {
+ const char *name;
+ enum power_supply_type type;
+@@ -169,8 +249,10 @@ struct power_supply {
+ size_t num_properties;
+
+ char **supplied_to;
++ unsigned long supported_cables;
+ size_t num_supplicants;
+-
++ struct power_supply_throttle *throttle_states;
++ size_t num_throttle_states;
+ char **supplied_from;
+ size_t num_supplies;
+ #ifdef CONFIG_OF
+@@ -187,6 +269,8 @@ struct power_supply {
+ enum power_supply_property psp);
+ void (*external_power_changed)(struct power_supply *psy);
+ void (*set_charged)(struct power_supply *psy);
++ void (*charging_port_changed)(struct power_supply *psy,
++ struct power_supply_charger_cap *cap);
+
+ /* For APM emulation, think legacy userspace. */
+ int use_for_apm;
+@@ -235,9 +319,13 @@ struct power_supply_info {
+ extern struct power_supply *power_supply_get_by_name(const char *name);
+ extern void power_supply_changed(struct power_supply *psy);
+ extern int power_supply_am_i_supplied(struct power_supply *psy);
++extern int power_supply_is_battery_connected(void);
+ extern int power_supply_set_battery_charged(struct power_supply *psy);
++extern void power_supply_charger_event(struct power_supply_charger_cap cap);
++extern void power_supply_query_charger_caps(struct power_supply_charger_cap
++ *cap);
+
+-#ifdef CONFIG_POWER_SUPPLY
++#if defined(CONFIG_POWER_SUPPLY) || defined(CONFIG_POWER_SUPPLY_MODULE)
+ extern int power_supply_is_system_supplied(void);
+ #else
+ static inline int power_supply_is_system_supplied(void) { return -ENOSYS; }
+diff --git a/include/linux/pwm.h b/include/linux/pwm.h
+index a4df204..69375b7 100644
+--- a/include/linux/pwm.h
++++ b/include/linux/pwm.h
+@@ -76,6 +76,7 @@ enum pwm_polarity {
+ enum {
+ PWMF_REQUESTED = 1 << 0,
+ PWMF_ENABLED = 1 << 1,
++ PWMF_EXPORTED = 1 << 2,
+ };
+
+ struct pwm_device {
+@@ -86,7 +87,9 @@ struct pwm_device {
+ struct pwm_chip *chip;
+ void *chip_data;
+
+- unsigned int period; /* in nanoseconds */
++ unsigned int period; /* in nanoseconds */
++ unsigned int duty_cycle; /* in nanoseconds */
++ enum pwm_polarity polarity;
+ };
+
+ static inline void pwm_set_period(struct pwm_device *pwm, unsigned int period)
+@@ -100,6 +103,17 @@ static inline unsigned int pwm_get_period(struct pwm_device *pwm)
+ return pwm ? pwm->period : 0;
+ }
+
++static inline void pwm_set_duty_cycle(struct pwm_device *pwm, unsigned int duty)
++{
++ if (pwm)
++ pwm->duty_cycle = duty;
++}
++
++static inline unsigned int pwm_get_duty_cycle(struct pwm_device *pwm)
++{
++ return pwm ? pwm->duty_cycle : 0;
++}
++
+ /*
+ * pwm_set_polarity - configure the polarity of a PWM signal
+ */
+@@ -278,4 +292,18 @@ static inline void pwm_add_table(struct pwm_lookup *table, size_t num)
+ }
+ #endif
+
++#ifdef CONFIG_PWM_SYSFS
++void pwmchip_sysfs_export(struct pwm_chip *chip);
++void pwmchip_sysfs_unexport(struct pwm_chip *chip);
++#else
++static inline void pwmchip_sysfs_export(struct pwm_chip *chip)
++{
++}
++
++static inline void pwmchip_sysfs_unexport(struct pwm_chip *chip)
++{
++}
++#endif /* CONFIG_PWM_SYSFS */
++
++
+ #endif /* __LINUX_PWM_H */
+diff --git a/include/linux/regulator/intel_basin_cove_pmic.h b/include/linux/regulator/intel_basin_cove_pmic.h
+new file mode 100644
+index 0000000..8dcdfa7
+--- /dev/null
++++ b/include/linux/regulator/intel_basin_cove_pmic.h
+@@ -0,0 +1,59 @@
++/*
++ * intel_basin_cove_pmic.h - Support for Basin Cove pmic VR
++ * Copyright (c) 2012, Intel Corporation.
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++#ifndef __INTEL_BASIN_COVE_PMIC_H_
++#define __INTEL_BASIN_COVE_PMIC_H_
++
++struct regulator_init_data;
++
++enum intel_regulator_id {
++ VPROG1,
++ VPROG2,
++ VPROG3,
++};
++
++/* Voltage tables for Regulators */
++static const u16 VPROG1_VSEL_table[] = {
++ 1500, 1800, 2500, 2800,
++};
++
++static const u16 VPROG2_VSEL_table[] = {
++ 1500, 1800, 2500, 2850,
++};
++
++static const u16 VPROG3_VSEL_table[] = {
++ 1050, 1800, 2500, 2800,
++};
++
++/* Slave Address for all regulators */
++#define VPROG1CNT_ADDR 0x0ac
++#define VPROG2CNT_ADDR 0x0ad
++#define VPROG3CNT_ADDR 0x0ae
++/**
++ * intel_pmic_info - platform data for intel pmic
++ * @pmic_reg: pmic register that is to be used for this VR
++ */
++struct intel_pmic_info {
++ struct regulator_init_data *init_data;
++ struct regulator_dev *intel_pmic_rdev;
++ const u16 *table;
++ u16 pmic_reg;
++ u8 table_len;
++};
++
++#endif /* __INTEL_BASIN_COVE_PMIC_H_ */
+diff --git a/include/linux/regulator/intel_pmic.h b/include/linux/regulator/intel_pmic.h
+new file mode 100644
+index 0000000..f972d60
+--- /dev/null
++++ b/include/linux/regulator/intel_pmic.h
+@@ -0,0 +1,54 @@
++/*
++*Support for intel pmic
++*Copyright (c) 2012, Intel Corporation.
++*This program is free software; you can redistribute it and/or modify
++*it under the terms of the GNU General Public License version 2 as
++*published by the Free Software Foundation.
++*
++*/
++
++struct regulator_init_data;
++
++enum intel_regulator_id {
++ VPROG1,
++ VPROG2,
++ VEMMC1,
++ VEMMC2,
++};
++
++/* Voltage tables for Regulators */
++static const u16 VPROG1_VSEL_table[] = {
++ 1200, 1800, 2500, 2800,
++};
++
++static const u16 VPROG2_VSEL_table[] = {
++ 1200, 1800, 2500, 2800,
++};
++
++static const u16 VEMMC1_VSEL_table[] = {
++ 2850,
++};
++static const u16 VEMMC2_VSEL_table[] = {
++ 2850,
++};
++
++static const u16 V180AON_VSEL_table[] = {
++ 1800, 1817, 1836, 1854,
++};
++
++/* Slave Address for all regulators */
++#define VPROG1CNT_ADDR 0x0D6
++#define VPROG2CNT_ADDR 0x0D7
++#define VEMMC1CNT_ADDR 0x0D9
++#define VEMMC2CNT_ADDR 0x0DA
++/**
++ * intel_pmic_info - platform data for intel pmic
++ * @pmic_reg: pmic register that is to be used for this VR
++ */
++struct intel_pmic_info {
++ struct regulator_init_data *init_data;
++ struct regulator_dev *intel_pmic_rdev;
++ const u16 *table;
++ u16 pmic_reg;
++ u8 table_len;
++};
+diff --git a/include/linux/sdm.h b/include/linux/sdm.h
+new file mode 100644
+index 0000000..0a75ffb
+--- /dev/null
++++ b/include/linux/sdm.h
+@@ -0,0 +1,60 @@
++/*
++ * Copyright (C) Intel 2011
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * The SDM (System Debug Monitor) directs trace data routed from
++ * various parts in the system out through the Intel Tangier PTI port and
++ * out of the mobile device for analysis with a debugging tool
++ * (Lauterbach, Fido). This is part of a solution for the MIPI P1149.7,
++ * compact JTAG, standard and USB Debug-Class
++ *
++ * This header file will allow other parts of the OS to use the
++ * interface to write out it's contents for debugging a mobile system.
++ */
++
++#ifndef SDM_H_
++#define SDM_H_
++
++#ifdef CONFIG_INTEL_PTI_STM
++/* the following functions are defined in drivers/misc/stm.c */
++int stm_kernel_get_out(void);
++int stm_kernel_set_out(int bus_type);
++int stm_is_enabled(void);
++#else
++static inline int stm_kernel_get_out(void) { return -EOPNOTSUPP; };
++static inline int stm_kernel_set_out(int bus_type) { return -EOPNOTSUPP; };
++static inline int stm_is_enabled(void) { return 0; };
++#endif
++
++/* Temporary : To be replace later with dynamic*/
++#define STM_NB_IN_PINS 0
++
++/* STM output configurations */
++#define STM_PTI_4BIT_LEGACY 0
++#define STM_PTI_4BIT_NIDNT 1
++#define STM_PTI_16BIT 2
++#define STM_PTI_12BIT 3
++#define STM_PTI_8BIT 4
++#define STM_USB 15
++
++/* Buffer configurations */
++#define DFX_BULK_BUFFER_SIZE 64 /* for Tangier A0 */
++#define DFX_BULK_OUT_BUFFER_ADDR 0xF90B0000
++#define DFX_BULK_IN_BUFFER_ADDR 0xF90B0000
++#define DFX_BULK_IN_BUFFER_ADDR_2 0xF90B0400
++
++#define TRACE_BULK_BUFFER_SIZE 65536 /* revision */
++#define TRACE_BULK_IN_BUFFER_ADDR 0xF90A0000 /* revision */
++
++#endif /*SDM_H_*/
++
+diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
+index 87d4bbc..a782f3c 100644
+--- a/include/linux/serial_core.h
++++ b/include/linux/serial_core.h
+@@ -60,6 +60,7 @@ struct uart_ops {
+ void (*pm)(struct uart_port *, unsigned int state,
+ unsigned int oldstate);
+ int (*set_wake)(struct uart_port *, unsigned int state);
++ void (*wake_peer)(struct uart_port *);
+
+ /*
+ * Return a string describing the type of the port
+diff --git a/include/linux/serial_max3110.h b/include/linux/serial_max3110.h
+new file mode 100644
+index 0000000..5470556
+--- /dev/null
++++ b/include/linux/serial_max3110.h
+@@ -0,0 +1,16 @@
++#ifndef _LINUX_SERIAL_MAX3110_H
++#define _LINUX_SERIAL_MAX3110_H
++
++/**
++ * struct plat_max3110 - MAX3110 SPI UART platform data
++ * @irq_edge_trigger: if IRQ is edge triggered
++ *
++ * You should use this structure in your machine description to specify
++ * how the MAX3110 is connected.
++ *
++ */
++struct plat_max3110 {
++ int irq_edge_triggered;
++};
++
++#endif
+diff --git a/include/linux/serial_mfd.h b/include/linux/serial_mfd.h
+index 2b071e0..0c0ba99 100644
+--- a/include/linux/serial_mfd.h
++++ b/include/linux/serial_mfd.h
+@@ -3,6 +3,7 @@
+
+ /* HW register offset definition */
+ #define UART_FOR 0x08
++#define UART_ABR 0x09
+ #define UART_PS 0x0C
+ #define UART_MUL 0x0D
+ #define UART_DIV 0x0E
+@@ -18,8 +19,8 @@
+ #define HSU_GBL_INT_BIT_DMA 0x5
+
+ #define HSU_GBL_ISR 0x8
+-#define HSU_GBL_DMASR 0x400
+-#define HSU_GBL_DMAISR 0x404
++#define HSU_GBL_DMASR 0x0
++#define HSU_GBL_DMAISR 0x4
+
+ #define HSU_PORT_REG_OFFSET 0x80
+ #define HSU_PORT0_REG_OFFSET 0x80
+@@ -27,7 +28,7 @@
+ #define HSU_PORT2_REG_OFFSET 0x180
+ #define HSU_PORT_REG_LENGTH 0x80
+
+-#define HSU_DMA_CHANS_REG_OFFSET 0x500
++#define HSU_DMA_CHANS_REG_OFFSET 0x100
+ #define HSU_DMA_CHANS_REG_LENGTH 0x40
+
+ #define HSU_CH_SR 0x0 /* channel status reg */
+diff --git a/include/linux/sfi.h b/include/linux/sfi.h
+index fe81791..cd50488 100644
+--- a/include/linux/sfi.h
++++ b/include/linux/sfi.h
+@@ -72,6 +72,7 @@
+ #define SFI_SIG_WAKE "WAKE"
+ #define SFI_SIG_DEVS "DEVS"
+ #define SFI_SIG_GPIO "GPIO"
++#define SFI_SIG_OEMB "OEMB"
+
+ #define SFI_SIGNATURE_SIZE 4
+ #define SFI_OEM_ID_SIZE 6
+@@ -85,6 +86,9 @@
+ #define SFI_GET_NUM_ENTRIES(ptable, entry_type) \
+ ((ptable->header.len - sizeof(struct sfi_table_header)) / \
+ (sizeof(entry_type)))
++
++#define SPID_FRU_SIZE 10
++
+ /*
+ * Table structures must be byte-packed to match the SFI specification,
+ * as they are provided by the BIOS.
+@@ -153,6 +157,7 @@ struct sfi_device_table_entry {
+ #define SFI_DEV_TYPE_UART 2
+ #define SFI_DEV_TYPE_HSI 3
+ #define SFI_DEV_TYPE_IPC 4
++#define SFI_DEV_TYPE_SD 5
+
+ u8 host_num; /* attached to host 0, 1...*/
+ u16 addr;
+diff --git a/include/linux/spi/intel_mid_ssp_spi.h b/include/linux/spi/intel_mid_ssp_spi.h
+new file mode 100644
+index 0000000..453c40b
+--- /dev/null
++++ b/include/linux/spi/intel_mid_ssp_spi.h
+@@ -0,0 +1,352 @@
++/*
++ * Copyright (C) Intel 2009
++ * Ken Mills <ken.k.mills@intel.com>
++ * Sylvain Centelles <sylvain.centelles@intel.com>
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ */
++#ifndef INTEL_MID_SSP_SPI_H_
++#define INTEL_MID_SSP_SPI_H_
++
++#include <linux/intel_mid_dma.h>
++#include <linux/pm_qos.h>
++#include <linux/spi/spi.h>
++#include <linux/interrupt.h>
++#include <linux/completion.h>
++
++#define PCI_MRST_DMAC1_ID 0x0814
++#define PCI_MDFL_DMAC1_ID 0x0827
++#define PCI_BYT_DMAC1_ID 0x0f06
++#define PCI_MRFL_DMAC_ID 0x11A2
++
++#define SSP_NOT_SYNC 0x400000
++#define MAX_SPI_TRANSFER_SIZE 8192
++#define MAX_BITBANGING_LOOP 10000
++#define SPI_FIFO_SIZE 16
++
++/* PM QoS define */
++#define MIN_EXIT_LATENCY 20
++
++/* SSP assignement configuration from PCI config */
++
++#define SSP_CFG_SPI_MODE_ID 1
++/* adid field offset is 6 inside the vendor specific capability */
++#define VNDR_CAPABILITY_ADID_OFFSET 6
++
++/* Driver's quirk flags */
++/* This workarround bufferizes data in the audio fabric SDRAM from */
++/* where the DMA transfers will operate. Should be enabled only for */
++/* SPI slave mode. */
++#define QUIRKS_SRAM_ADDITIONAL_CPY 1
++/* If set the trailing bytes won't be handled by the DMA. */
++/* Trailing byte feature not fully available. */
++#define QUIRKS_DMA_USE_NO_TRAIL 2
++/* If set, the driver will use PM_QOS to reduce the latency */
++/* introduced by the deeper C-states which may produce over/under */
++/* run issues. Must be used in slave mode. In master mode, the */
++/* latency is not critical, but setting this workarround may */
++/* improve the SPI throughput. */
++#define QUIRKS_USE_PM_QOS 4
++/* This quirks is set on Moorestown */
++#define QUIRKS_PLATFORM_MRST 8
++/* This quirks is set on Medfield */
++#define QUIRKS_PLATFORM_MDFL 16
++/* If set, the driver will apply the bitbanging workarround needed */
++/* to enable defective Langwell stepping A SSP. The defective SSP */
++/* can be enabled only once, and should never be disabled. */
++#define QUIRKS_BIT_BANGING 32
++/* If set, SPI is in slave clock mode */
++#define QUIRKS_SPI_SLAVE_CLOCK_MODE 64
++/* Add more platform here. */
++/* This quirks is set on Baytrail. */
++#define QUIRKS_PLATFORM_BYT 128
++#define QUIRKS_PLATFORM_MRFL 256
++
++/* Uncomment to get RX and TX short dumps after each transfer */
++/* #define DUMP_RX 1 */
++#define MAX_TRAILING_BYTE_RETRY 16
++#define MAX_TRAILING_BYTE_LOOP 100
++#define DELAY_TO_GET_A_WORD 3
++#define DFLT_TIMEOUT_VAL 500
++
++#define DEFINE_SSP_REG(reg, off) \
++static inline u32 read_##reg(void *p) { return __raw_readl(p + (off)); } \
++static inline void write_##reg(u32 v, void *p) { __raw_writel(v, p + (off)); }
++
++#define RX_DIRECTION 0
++#define TX_DIRECTION 1
++
++#define I2C_ACCESS_USDELAY 10
++
++#define DFLT_BITS_PER_WORD 16
++#define MIN_BITS_PER_WORD 4
++#define MAX_BITS_PER_WORD 32
++#define DFLT_FIFO_BURST_SIZE IMSS_FIFO_BURST_8
++
++#define TRUNCATE(x, a) ((x) & ~((a)-1))
++
++DEFINE_SSP_REG(SSCR0, 0x00)
++DEFINE_SSP_REG(SSCR1, 0x04)
++DEFINE_SSP_REG(SSSR, 0x08)
++DEFINE_SSP_REG(SSITR, 0x0c)
++DEFINE_SSP_REG(SSDR, 0x10)
++DEFINE_SSP_REG(SSTO, 0x28)
++DEFINE_SSP_REG(SSPSP, 0x2c)
++DEFINE_SSP_REG(SSFS, 0x44)
++DEFINE_SSP_REG(SFIFOL, 0x68)
++
++DEFINE_SSP_REG(I2CCTRL, 0x00);
++DEFINE_SSP_REG(I2CDATA, 0x04);
++
++DEFINE_SSP_REG(GPLR1, 0x04);
++DEFINE_SSP_REG(GPDR1, 0x0c);
++DEFINE_SSP_REG(GPSR1, 0x14);
++DEFINE_SSP_REG(GPCR1, 0x1C);
++DEFINE_SSP_REG(GAFR1_U, 0x44);
++
++#define SYSCFG 0x20bc0
++
++#define SRAM_BASE_ADDR 0xfffdc000
++#define SRAM_RX_ADDR SRAM_BASE_ADDR
++#define SRAM_TX_ADDR (SRAM_BASE_ADDR + MAX_SPI_TRANSFER_SIZE)
++
++#define SSCR0_DSS (0x0000000f) /* Data Size Select (mask) */
++#define SSCR0_DataSize(x) ((x) - 1) /* Data Size Select [4..16] */
++#define SSCR0_FRF (0x00000030) /* FRame Format (mask) */
++#define SSCR0_Motorola (0x0 << 4) /* Motorola's SPI mode */
++#define SSCR0_ECS (1 << 6) /* External clock select */
++#define SSCR0_SSE (1 << 7) /* Synchronous Serial Port Enable */
++
++#define SSCR0_SCR (0x000fff00) /* Serial Clock Rate (mask) */
++#define SSCR0_SerClkDiv(x) (((x) - 1) << 8) /* Divisor [1..4096] */
++#define SSCR0_EDSS (1 << 20) /* Extended data size select */
++#define SSCR0_NCS (1 << 21) /* Network clock select */
++#define SSCR0_RIM (1 << 22) /* Receive FIFO overrrun int mask */
++#define SSCR0_TUM (1 << 23) /* Transmit FIFO underrun int mask */
++#define SSCR0_FRDC (0x07000000) /* Frame rate divider control (mask) */
++#define SSCR0_SlotsPerFrm(x) (((x) - 1) << 24) /* Time slots per frame */
++#define SSCR0_ADC (1 << 30) /* Audio clock select */
++#define SSCR0_MOD (1 << 31) /* Mode (normal or network) */
++
++#define SSCR1_RIE (1 << 0) /* Receive FIFO Interrupt Enable */
++#define SSCR1_TIE (1 << 1) /* Transmit FIFO Interrupt Enable */
++#define SSCR1_LBM (1 << 2) /* Loop-Back Mode */
++#define SSCR1_SPO (1 << 3) /* SSPSCLK polarity setting */
++#define SSCR1_SPH (1 << 4) /* Motorola SPI SSPSCLK phase setting */
++#define SSCR1_MWDS (1 << 5) /* Microwire Transmit Data Size */
++#define SSCR1_TFT (0x000003c0) /* Transmit FIFO Threshold (mask) */
++#define SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..16] */
++#define SSCR1_RFT (0x00003c00) /* Receive FIFO Threshold (mask) */
++#define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..16] */
++
++#define SSSR_TNF (1 << 2) /* Tx FIFO Not Full */
++#define SSSR_RNE (1 << 3) /* Rx FIFO Not Empty */
++#define SSSR_BSY (1 << 4) /* SSP Busy */
++#define SSSR_TFS (1 << 5) /* Tx FIFO Service Request */
++#define SSSR_RFS (1 << 6) /* Rx FIFO Service Request */
++#define SSSR_ROR (1 << 7) /* Rx FIFO Overrun */
++#define SSSR_TFL_MASK (0x0F << 8) /* Tx FIFO level field mask */
++#define SSSR_RFL_SHIFT 12 /* Rx FIFO MASK shift */
++#define SSSR_RFL_MASK (0x0F << SSSR_RFL_SHIFT)/* RxFIFOlevel mask */
++
++#define SSCR0_TIM (1 << 23) /* Transmit FIFO Under Run Int Mask */
++#define SSCR0_RIM (1 << 22) /* Receive FIFO Over Run int Mask */
++#define SSCR0_NCS (1 << 21) /* Network Clock Select */
++#define SSCR0_EDSS (1 << 20) /* Extended Data Size Select */
++
++#define SSCR0_TISSP (1 << 4) /* TI Sync Serial Protocol */
++#define SSCR0_PSP (3 << 4) /* PSP - Programmable Serial Protocol */
++#define SSCR1_TTELP (1 << 31) /* TXD Tristate Enable Last Phase */
++#define SSCR1_TTE (1 << 30) /* TXD Tristate Enable */
++#define SSCR1_EBCEI (1 << 29) /* Enable Bit Count Error interrupt */
++#define SSCR1_SCFR (1 << 28) /* Slave Clock free Running */
++#define SSCR1_ECRA (1 << 27) /* Enable Clock Request A */
++#define SSCR1_ECRB (1 << 26) /* Enable Clock request B */
++#define SSCR1_SCLKDIR (1 << 25) /* Serial Bit Rate Clock Direction */
++#define SSCR1_SFRMDIR (1 << 24) /* Frame Direction */
++#define SSCR1_RWOT (1 << 23) /* Receive Without Transmit */
++#define SSCR1_TRAIL (1 << 22) /* Trailing Byte */
++#define SSCR1_TSRE (1 << 21) /* Transmit Service Request Enable */
++#define SSCR1_RSRE (1 << 20) /* Receive Service Request Enable */
++#define SSCR1_TINTE (1 << 19) /* Receiver Time-out Interrupt enable */
++#define SSCR1_PINTE (1 << 18) /* Trailing Byte Interupt Enable */
++#define SSCR1_STRF (1 << 15) /* Select FIFO or EFWR */
++#define SSCR1_EFWR (1 << 14) /* Enable FIFO Write/Read */
++#define SSCR1_IFS (1 << 16) /* Invert Frame Signal */
++
++#define SSSR_BCE (1 << 23) /* Bit Count Error */
++#define SSSR_CSS (1 << 22) /* Clock Synchronisation Status */
++#define SSSR_TUR (1 << 21) /* Transmit FIFO Under Run */
++#define SSSR_EOC (1 << 20) /* End Of Chain */
++#define SSSR_TINT (1 << 19) /* Receiver Time-out Interrupt */
++#define SSSR_PINT (1 << 18) /* Peripheral Trailing Byte Interrupt */
++
++#define SSPSP_FSRT (1 << 25) /* Frame Sync Relative Timing */
++#define SSPSP_DMYSTOP(x) ((x) << 23) /* Dummy Stop */
++#define SSPSP_SFRMWDTH(x)((x) << 16) /* Serial Frame Width */
++#define SSPSP_SFRMDLY(x) ((x) << 9) /* Serial Frame Delay */
++#define SSPSP_DMYSTRT(x) ((x) << 7) /* Dummy Start */
++#define SSPSP_STRTDLY(x) ((x) << 4) /* Start Delay */
++#define SSPSP_ETDS (1 << 3) /* End of Transfer data State */
++#define SSPSP_SFRMP (1 << 2) /* Serial Frame Polarity */
++#define SSPSP_SCMODE(x) ((x) << 0) /* Serial Bit Rate Clock Mode */
++
++/*
++ * For testing SSCR1 changes that require SSP restart, basically
++ * everything except the service and interrupt enables
++ */
++
++#define SSCR1_CHANGE_MASK (SSCR1_TTELP | SSCR1_TTE | SSCR1_SCFR \
++ | SSCR1_ECRA | SSCR1_ECRB | SSCR1_SCLKDIR \
++ | SSCR1_SFRMDIR | SSCR1_RWOT | SSCR1_TRAIL \
++ | SSCR1_IFS | SSCR1_STRF | SSCR1_EFWR \
++ | SSCR1_RFT | SSCR1_TFT | SSCR1_MWDS \
++ | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
++
++/* add CS control call back feature to give user capability
++to control CS signal by themselves*/
++#define CS_DEASSERT 0
++#define CS_ASSERT 1
++
++struct callback_param {
++ void *drv_context;
++ u32 direction;
++};
++
++struct ssp_drv_context {
++ /* Driver model hookup */
++ struct pci_dev *pdev;
++
++ /* SPI framework hookup */
++ struct spi_master *master;
++
++ /* SSP register addresses */
++ unsigned long paddr;
++ void *ioaddr;
++ int irq;
++
++ /* I2C registers */
++ dma_addr_t I2C_paddr;
++ void *I2C_ioaddr;
++
++ /* SSP masks*/
++ u32 cr1_sig;
++ u32 cr1;
++ u32 clear_sr;
++ u32 mask_sr;
++
++ /* PM_QOS request */
++ struct pm_qos_request pm_qos_req;
++
++ struct tasklet_struct poll_transfer;
++
++ spinlock_t lock;
++ struct workqueue_struct *workqueue;
++ struct work_struct pump_messages;
++ struct list_head queue;
++ struct completion msg_done;
++
++ int suspended;
++
++ /* Current message transfer state info */
++ struct spi_message *cur_msg;
++ size_t len;
++ size_t len_dma_rx;
++ size_t len_dma_tx;
++ void *tx;
++ void *tx_end;
++ void *rx;
++ void *rx_end;
++ bool dma_initialized;
++ int dma_mapped;
++ dma_addr_t rx_dma;
++ dma_addr_t tx_dma;
++ u8 n_bytes;
++ int (*write)(struct ssp_drv_context *sspc);
++ int (*read)(struct ssp_drv_context *sspc);
++
++ struct intel_mid_dma_slave dmas_tx;
++ struct intel_mid_dma_slave dmas_rx;
++ struct dma_chan *txchan;
++ struct dma_chan *rxchan;
++ struct workqueue_struct *dma_wq;
++ struct work_struct complete_work;
++
++ u8 __iomem *virt_addr_sram_tx;
++ u8 __iomem *virt_addr_sram_rx;
++
++ int txdma_done;
++ int rxdma_done;
++ struct callback_param tx_param;
++ struct callback_param rx_param;
++ struct pci_dev *dmac1;
++
++ unsigned long quirks;
++ u32 rx_fifo_threshold;
++
++ int cs_change;
++ void (*cs_control)(u32 command);
++};
++
++struct chip_data {
++ u32 cr0;
++ u32 cr1;
++ u32 timeout;
++ u8 chip_select;
++ u8 n_bytes;
++ u8 dma_enabled;
++ u8 bits_per_word;
++ u32 speed_hz;
++ int (*write)(struct ssp_drv_context *sspc);
++ int (*read)(struct ssp_drv_context *sspc);
++ void (*cs_control)(u32 command);
++};
++
++
++enum intel_mid_ssp_spi_fifo_burst {
++ IMSS_FIFO_BURST_1,
++ IMSS_FIFO_BURST_4,
++ IMSS_FIFO_BURST_8
++};
++
++/* spi_board_info.controller_data for SPI slave devices,
++ * copied to spi_device.platform_data ... mostly for dma tuning
++ */
++struct intel_mid_ssp_spi_chip {
++ enum intel_mid_ssp_spi_fifo_burst burst_size;
++ u32 timeout;
++ u8 enable_loopback;
++ u8 dma_enabled;
++ void (*cs_control)(u32 command);
++ void (*platform_pinmux)(void);
++};
++
++#define SPI_DIB_NAME_LEN 16
++#define SPI_DIB_SPEC_INFO_LEN 10
++
++struct spi_dib_header {
++ u32 signature;
++ u32 length;
++ u8 rev;
++ u8 checksum;
++ u8 dib[0];
++} __packed;
++
++#endif /*INTEL_MID_SSP_SPI_H_*/
+diff --git a/include/linux/thermal.h b/include/linux/thermal.h
+index a386a1c..04b08a6 100644
+--- a/include/linux/thermal.h
++++ b/include/linux/thermal.h
+@@ -110,22 +110,22 @@ struct thermal_zone_device_ops {
+ struct thermal_cooling_device *);
+ int (*unbind) (struct thermal_zone_device *,
+ struct thermal_cooling_device *);
+- int (*get_temp) (struct thermal_zone_device *, unsigned long *);
++ int (*get_temp) (struct thermal_zone_device *, long *);
+ int (*get_mode) (struct thermal_zone_device *,
+ enum thermal_device_mode *);
+ int (*set_mode) (struct thermal_zone_device *,
+ enum thermal_device_mode);
+ int (*get_trip_type) (struct thermal_zone_device *, int,
+ enum thermal_trip_type *);
+- int (*get_trip_temp) (struct thermal_zone_device *, int,
+- unsigned long *);
+- int (*set_trip_temp) (struct thermal_zone_device *, int,
+- unsigned long);
+- int (*get_trip_hyst) (struct thermal_zone_device *, int,
+- unsigned long *);
+- int (*set_trip_hyst) (struct thermal_zone_device *, int,
+- unsigned long);
+- int (*get_crit_temp) (struct thermal_zone_device *, unsigned long *);
++ int (*get_trip_temp) (struct thermal_zone_device *, int, long *);
++ int (*set_trip_temp) (struct thermal_zone_device *, int, long);
++ int (*get_trip_hyst) (struct thermal_zone_device *, int, long *);
++ int (*set_trip_hyst) (struct thermal_zone_device *, int, long);
++ int (*get_slope) (struct thermal_zone_device *, long *);
++ int (*set_slope) (struct thermal_zone_device *, long);
++ int (*get_intercept) (struct thermal_zone_device *, long *);
++ int (*set_intercept) (struct thermal_zone_device *, long);
++ int (*get_crit_temp) (struct thermal_zone_device *, long *);
+ int (*set_emul_temp) (struct thermal_zone_device *, unsigned long);
+ int (*get_trend) (struct thermal_zone_device *, int,
+ enum thermal_trend *);
+@@ -137,6 +137,12 @@ struct thermal_cooling_device_ops {
+ int (*get_max_state) (struct thermal_cooling_device *, unsigned long *);
+ int (*get_cur_state) (struct thermal_cooling_device *, unsigned long *);
+ int (*set_cur_state) (struct thermal_cooling_device *, unsigned long);
++ int (*get_force_state_override) (struct thermal_cooling_device *,
++ char *);
++ int (*set_force_state_override) (struct thermal_cooling_device *,
++ char *);
++ int (*get_available_states) (struct thermal_cooling_device *,
++ char *);
+ };
+
+ struct thermal_cooling_device {
+diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h
+index 58390c7..ae4a779 100644
+--- a/include/linux/tty_ldisc.h
++++ b/include/linux/tty_ldisc.h
+@@ -91,7 +91,10 @@
+ * This function is called by the low-level tty driver to signal
+ * that line discpline should try to send more characters to the
+ * low-level driver for transmission. If the line discpline does
+- * not have any more data to send, it can just return.
++ * not have any more data to send, it can just return. If the line
++ * discpline does have some data to send, please arise a tasklet
++ * or workqueue to do the real data transfer. Do not send data in
++ * this hook, it may lead to a deadlock.
+ *
+ * int (*hangup)(struct tty_struct *)
+ *
+diff --git a/include/linux/usb/debug.h b/include/linux/usb/debug.h
+new file mode 100644
+index 0000000..2a08e36
+--- /dev/null
++++ b/include/linux/usb/debug.h
+@@ -0,0 +1,253 @@
++/*
++ * <linux/usb/debug.h> -- USB Debug Class definitions.
++ *
++ * Copyright (C) 2008-2010, Intel Corporation.
++ *
++ * This software is distributed under the terms of the GNU General Public
++ * License ("GPL") version 2, as published by the Free Software Foundation.
++ *
++ */
++
++#ifndef __LINUX_USB_DEBUG_H
++#define __LINUX_USB_DEBUG_H
++
++#include <linux/types.h>
++
++/* Debug Interface Subclass Codes */
++#define USB_SUBCLASS_DVC_GP 0x05
++#define USB_SUBCLASS_DVC_DFX 0x06
++#define USB_SUBCLASS_DVC_TRACE 0x07
++#define USB_SUBCLASS_DEBUG_CONTROL 0x08
++
++/* Debug Interface Function Protocol */
++#define DC_PROTOCOL_VENDOR 0x00
++#define DC_PROTOCOL_LAUTERBACH 0x01
++#define DC_PROTOCOL_ITP 0x02
++
++/* Debug Class-Specific Interface Descriptor Subtypes */
++#define DC_UNDEFINED 0x00
++#define DC_INPUT_CONNECTION 0x01
++#define DC_OUTPUT_CONNECTION 0x02
++#define DC_DEBUG_UNIT 0x03
++#define DC_DEBUG_ATTRIBUTES 0x04 /* revision: per SAS */
++
++/* Debug-Class Input/Output Connection Type */
++#define DC_CONNECTION_USB 0x00
++#define DC_CONNECTION_JTAG 0x01
++#define DC_CONNECTION_DEBUG_DATA_CONTROL 0x02
++#define DC_CONNECTION_DEBUG_DATA 0x03
++#define DC_CONNECTION_DEBUG_CONTROL 0x04
++
++/*
++ * Debug-class (rev 0.88r2) section 4.4.3
++ * Attibute Descriptor, bmControl
++ */
++#define DC_CTL_SET_CFG_DATA_SG (1 << 0)
++#define DC_CTL_SET_CFG_DATA (1 << 1)
++#define DC_CTL_GET_CFG_DATA (1 << 2)
++#define DC_CTL_SET_CFG_ADDR (1 << 3)
++#define DC_CTL_GET_CFG_ADDR (1 << 4)
++#define DC_CTL_SET_ALT_STACK (1 << 5)
++#define DC_CTL_GET_ALT_STACK (1 << 6)
++#define DC_CTL_SET_OP_MODE (1 << 7)
++#define DC_CTL_GET_OP_MODE (1 << 8)
++#define DC_CTL_SET_TRACE_CFG (1 << 9)
++#define DC_CTL_GET_TRACE_CFG (1 << 10)
++#define DC_CTL_SET_BUFF_INFO (1 << 11)
++#define DC_CTL_GET_BUFF_INFO (1 << 12)
++#define DC_CTL_SET_RESET (1 << 13)
++
++/* Debug-class (rev 0.88r2) section 4.4.6
++ * Unit/Input/Output connection Descriptors,
++ * dTraceFormat
++ */
++#define DC_TRACE_NOT_FORMATED_PASSTHROUGH 0x00000000
++#define DC_TRACE_NOT_FORMATED_HEADER 0x00000001
++#define DC_TRACE_NOT_FORMATED_FOOTER 0x00000002
++#define DC_TRACE_NOT_FORMATED_GUID 0x00000005
++#define DC_TRACE_NOT_FORMATED_UTF8 0x00000006
++#define DC_TRACE_INTEL_FORMATED_VENDOR 0x01000000
++#define DC_TRACE_MIPI_FORMATED_STPV1 0x80000000
++#define DC_TRACE_MIPI_FORMATED_STPV2 0x80000001
++#define DC_TRACE_MIPI_FORMATED_TWP 0x80000100
++#define DC_TRACE_MIPI_FORMATED_OST 0x80001000
++#define DC_TRACE_NEXUS_FORMATED 0x81000000
++
++/* Debug-class (rev 0.88r2) section 4.4.6
++ * Unit connection Descriptors, dDebugUnitType
++ */
++#define DC_UNIT_TYPE_DFX 0x00
++#define DC_UNIT_TYPE_SELECT 0x01
++#define DC_UNIT_TYPE_TRACE_ROUTE 0x02
++#define DC_UNIT_TYPE_TRACE_PROC 0x03
++#define DC_UNIT_TYPE_TRACE_GEN 0x04
++#define DC_UNIT_TYPE_TRACE_SINK 0x05
++#define DC_UNIT_TYPE_CONTROL 0x06
++#define DC_UNIT_TYPE_VENDOR 0x40
++
++/* Debug-class (rev 0.88r2) section 4.4.6
++ * Unit connection Descriptors, dDebugUnitSubType
++ */
++#define DC_UNIT_SUBTYPE_NO 0x00
++#define DC_UNIT_SUBTYPE_CPU 0x01
++#define DC_UNIT_SUBTYPE_GFX 0x02
++#define DC_UNIT_SUBTYPE_VIDEO 0x03
++#define DC_UNIT_SUBTYPE_IMAGING 0x04
++#define DC_UNIT_SUBTYPE_AUDIO 0x05
++#define DC_UNIT_SUBTYPE_MODEM 0x06
++#define DC_UNIT_SUBTYPE_BLUETOOTH 0x07
++#define DC_UNIT_SUBTYPE_PWR_MGT 0x08
++#define DC_UNIT_SUBTYPE_SECURITY 0x09
++#define DC_UNIT_SUBTYPE_SENSOR 0x0A
++#define DC_UNIT_SUBTYPE_BUSWATCH 0x0B
++#define DC_UNIT_SUBTYPE_GPS 0x0C
++#define DC_UNIT_SUBTYPE_TRACEZIP 0x0D
++#define DC_UNIT_SUBTYPE_TAPCTL 0x0E
++#define DC_UNIT_SUBTYPE_MEMACC 0x0F
++#define DC_UNIT_SUBTYPE_SWLOGGER 0x40
++#define DC_UNIT_SUBTYPE_SWROUTER 0x41
++#define DC_UNIT_SUBTYPE_SWDRIVER 0x42
++#define DC_UNIT_SUBTYPE_VENDOR 0x80
++
++/* USB DBG requests values */
++#define DC_REQUEST_SET_CONFIG_DATA 0x01
++#define DC_REQUEST_SET_CONFIG_DATA_SINGLE 0x02
++#define DC_REQUEST_SET_CONFIG_ADDRESS 0x03
++#define DC_REQUEST_SET_ALT_STACK 0x04
++#define DC_REQUEST_SET_OPERATING 0x05
++#define DC_REQUEST_SET_TRACE 0x08
++#define DC_REQUEST_SET_BUFFER_INFO 0x09
++#define DC_REQUEST_SET_RESET 0x0A
++#define DC_REQUEST_GET_CONFIG_DATA 0x81
++#define DC_REQUEST_GET_CONFIG_DATA_SINGLE 0x82
++#define DC_REQUEST_GET_CONFIG_ADDRESS 0x83
++#define DC_REQUEST_GET_ALT_STACK 0x84
++#define DC_REQUEST_GET_OPERATING 0x85
++#define DC_REQUEST_GET_TRACE 0x86
++#define DC_REQUEST_GET_INFO 0x87
++#define DC_REQUEST_GET_ERROR 0x88
++#define DC_REQUEST_GET_BUFFER_INFO 0x89
++
++/* Debug-Class Debug-Attributes Descriptor */
++struct dc_debug_attributes_descriptor {
++ __u8 bLength;
++ __u8 bDescriptorType;
++ __u8 bDescriptorSubtype;
++ __le16 bcdDC;
++ __le16 wTotalLength;
++ __u8 bmSupportedFeatures;
++ __u8 bControlSize; /* n */
++ __u8 bmControl[0]; /* [n] */
++ __le16 wAuxDataSize; /* m */
++ __le32 dInputBufferSize;
++ __le32 dOutputBufferSize;
++ __le64 qBaseAddress;
++ __le64 hGlobalID[2];
++ __u8 Supplementary[0]; /* [m-32] */
++} __attribute__((__packed__));
++
++#define DC_DEBUG_ATTR_DESCR(name) \
++ dc_debug_attributes_descriptor_##name
++
++#define DECLARE_DC_DEBUG_ATTR_DESCR(name, n, m) \
++struct DC_DEBUG_ATTR_DESCR(name) { \
++ __u8 bLength; \
++ __u8 bDescriptorType; \
++ __u8 bDescriptorSubtype; \
++ __le16 bcdDC; \
++ __le16 wTotalLength; \
++ __u8 bmSupportedFeatures; \
++ __u8 bControlSize; \
++ __u8 bmControl[n]; \
++ __le16 wAuxDataSize; \
++ __le32 dInputBufferSize; \
++ __le32 dOutputBufferSize; \
++ __le64 qBaseAddress; \
++ __le64 hGlobalID[2]; \
++ __u8 Supplementary[m-32]; \
++} __attribute__((__packed__));
++
++#define DC_DBG_ATTRI_SIZE(n, m) (9 + (n) + 2 + (m))
++
++/* Debug-Class Input Connection Descriptor */
++struct dc_input_connection_descriptor {
++ __u8 bLength;
++ __u8 bDescriptorType;
++ __u8 bDescriptorSubtype;
++ __u8 bConnectionID;
++ __u8 bConnectionType;
++ __u8 bAssocConnection;
++ __u8 iConnection;
++ __le32 dTraceFormat;
++ __le32 dStreamID;
++} __attribute__((__packed__));
++
++#define DC_INPUT_CONNECTION_SIZE 15
++
++/* Debug-Class Output Connection Descriptor */
++struct dc_output_connection_descriptor {
++ __u8 bLength;
++ __u8 bDescriptorType;
++ __u8 bDescriptorSubtype;
++ __u8 bConnectionID;
++ __u8 bConnectionType;
++ __u8 bAssocConnection;
++ __le16 wSourceID;
++ __u8 iConnection;
++} __attribute__((__packed__));
++
++#define DC_OUTPUT_CONNECTION_SIZE 9
++
++/* Debug-Class Debug-Unit Descriptor */
++struct dc_debug_unit_descriptor {
++ __u8 bLength;
++ __u8 bDescriptorType;
++ __u8 bDescriptorSubtype;
++ __u8 bUnitID;
++ __u8 bDebugUnitType;
++ __u8 bDebugSubUnitType;
++ __u8 bAliasUnitID;
++ __u8 bNrInPins; /* p */
++ __le16 wSourceID[0]; /* [p] */
++ __u8 bNrOutPins; /* q */
++ __le32 dTraceFormat[0]; /* [q] */
++ __le32 dStreamID;
++ __u8 bControlSize; /* n */
++ __u8 bmControl[0]; /* [n] */
++ __le16 wAuxDataSize; /* m */
++ __le64 qBaseAddress;
++ __le64 hIPID[2];
++ __u8 Supplementary[0]; /* [m-24] */
++ __u8 iDebugUnitType;
++} __attribute__((__packed__));
++
++#define DC_DEBUG_UNIT_DESCRIPTOR(p, q, n, m) \
++ dc_debug_unit_descriptor_##p_##q##n_##m
++
++#define DECLARE_DC_DEBUG_UNIT_DESCRIPTOR(p, q, n, m) \
++struct DC_DEBUG_UNIT_DESCRIPTOR(p, q, n, m) { \
++ __u8 bLength; \
++ __u8 bDescriptorType; \
++ __u8 bDescriptorSubtype; \
++ __u8 bUnitID; \
++ __u8 bDebugUnitType; \
++ __u8 bDebugSubUnitType; \
++ __u8 bAliasUnitID; \
++ __u8 bNrInPins; \
++ __le16 wSourceID[p]; \
++ __u8 bNrOutPins; \
++ __le32 dTraceFormat[q]; \
++ __le32 dStreamID; \
++ __u8 bControlSize; \
++ __u8 bmControl[n]; \
++ __le16 wAuxDataSize; \
++ __le64 qBaseAddress; \
++ __le64 hIPID[2]; \
++ __u8 Supplementary[m-24]; \
++ __u8 iDebugUnitType; \
++} __attribute__((__packed__));
++
++#define DC_DBG_UNIT_SIZE(p, q, n, m) \
++(8 + (p * 2) + 1 + (q * 4) + 5 + (n) + 2 + (m) + 1)
++
++#endif /* __LINUX_USB_DEBUG_H */
+diff --git a/include/linux/usb/dwc3-intel-mid.h b/include/linux/usb/dwc3-intel-mid.h
+new file mode 100644
+index 0000000..376b01e
+--- /dev/null
++++ b/include/linux/usb/dwc3-intel-mid.h
+@@ -0,0 +1,190 @@
++/*
++ * Intel Penwell USB OTG transceiver driver
++ * Copyright (C) 2009 - 2010, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#ifndef __DWC3_INTEL_H
++#define __DWC3_INTEL_H
++
++#include "otg.h"
++
++enum intel_mid_pmic_type {
++ NO_PMIC,
++ SHADY_COVE,
++ BASIN_COVE
++};
++
++struct intel_dwc_otg_pdata {
++ int is_hvp;
++ enum intel_mid_pmic_type pmic_type;
++ int charger_detect_enable;
++ int gpio_cs;
++ int gpio_reset;
++ int gpio_id;
++ int id;
++ int charging_compliance;
++ struct delayed_work suspend_discon_work;
++ u8 ti_phy_vs1;
++ int sdp_charging;
++};
++
++#define TUSB1211_VENDOR_ID_LO 0x00
++#define TUSB1211_VENDOR_ID_HI 0x01
++#define TUSB1211_PRODUCT_ID_LO 0x02
++#define TUSB1211_PRODUCT_ID_HI 0x03
++#define TUSB1211_FUNC_CTRL 0x04
++#define TUSB1211_FUNC_CTRL_SET 0x05
++#define TUSB1211_FUNC_CTRL_CLR 0x06
++#define TUSB1211_IFC_CTRL 0x07
++#define TUSB1211_IFC_CTRL_SET 0x08
++#define TUSB1211_IFC_CTRL_CLR 0x09
++#define TUSB1211_OTG_CTRL 0x0A
++#define TUSB1211_OTG_CTRL_SET 0x0B
++#define TUSB1211_OTG_CTRL_CLR 0x0C
++#define TUSB1211_USB_INT_EN_RISE 0x0D
++#define TUSB1211_USB_INT_EN_RISE_SET 0x0E
++#define TUSB1211_USB_INT_EN_RISE_CLR 0x0F
++#define TUSB1211_USB_INT_EN_FALL 0x10
++#define TUSB1211_USB_INT_EN_FALL_SET 0x11
++#define TUSB1211_USB_INT_EN_FALL_CLR 0x12
++#define TUSB1211_USB_INT_STS 0x13
++#define TUSB1211_USB_INT_LATCH 0x14
++#define TUSB1211_DEBUG 0x15
++#define TUSB1211_SCRATCH_REG 0x16
++#define TUSB1211_SCRATCH_REG_SET 0x17
++#define TUSB1211_SCRATCH_REG_CLR 0x18
++#define TUSB1211_ACCESS_EXT_REG_SET 0x2F
++
++#define TUSB1211_VENDOR_SPECIFIC1 0x80
++#define TUSB1211_VENDOR_SPECIFIC1_SET 0x81
++#define TUSB1211_VENDOR_SPECIFIC1_CLR 0x82
++#define TUSB1211_POWER_CONTROL 0x3D
++#define TUSB1211_POWER_CONTROL_SET 0x3E
++#define TUSB1211_POWER_CONTROL_CLR 0x3F
++
++#define TUSB1211_VENDOR_SPECIFIC2 0x80
++#define TUSB1211_VENDOR_SPECIFIC2_SET 0x81
++#define TUSB1211_VENDOR_SPECIFIC2_CLR 0x82
++#define TUSB1211_VENDOR_SPECIFIC2_STS 0x83
++#define TUSB1211_VENDOR_SPECIFIC2_LATCH 0x84
++#define TUSB1211_VENDOR_SPECIFIC3 0x85
++#define TUSB1211_VENDOR_SPECIFIC3_SET 0x86
++#define TUSB1211_VENDOR_SPECIFIC3_CLR 0x87
++#define TUSB1211_VENDOR_SPECIFIC4 0x88
++#define TUSB1211_VENDOR_SPECIFIC4_SET 0x89
++#define TUSB1211_VENDOR_SPECIFIC4_CLR 0x8A
++#define TUSB1211_VENDOR_SPECIFIC5 0x8B
++#define TUSB1211_VENDOR_SPECIFIC5_SET 0x8C
++#define TUSB1211_VENDOR_SPECIFIC5_CLR 0x8D
++#define TUSB1211_VENDOR_SPECIFIC6 0x8E
++#define TUSB1211_VENDOR_SPECIFIC6_SET 0x8F
++#define TUSB1211_VENDOR_SPECIFIC6_CLR 0x90
++
++#define VS1_DATAPOLARITY (1 << 6)
++#define VS1_ZHSDRV(v) ((v & 0x3) << 5)
++#define VS1_IHSTX(v) ((v & 0x7))
++
++#define VS2STS_VBUS_MNTR_STS (1 << 7)
++#define VS2STS_REG3V3IN_MNTR_STS (1 << 6)
++#define VS2STS_SVLDCONWKB_WDOG_STS (1 << 5)
++#define VS2STS_ID_FLOAT_STS (1 << 4)
++#define VS2STS_ID_RARBRC_STS(v) ((v & 0x3) << 2)
++#define VS2STS_BVALID_STS (1 << 0)
++
++#define VS3_CHGD_IDP_SRC_EN (1 << 6)
++#define VS3_IDPULLUP_WK_EN (1 << 5)
++#define VS3_SW_USB_DET (1 << 4)
++#define VS3_DATA_CONTACT_DET_EN (1 << 3)
++#define VS3_REG3V3_VSEL(v) (v & 0x7)
++
++#define VS4_ACA_DET_EN (1 << 6)
++#define VS4_RABUSIN_EN (1 << 5)
++#define VS4_R1KSERIES (1 << 4)
++#define VS4_PSW_OSOD (1 << 3)
++#define VS4_PSW_CMOS (1 << 2)
++#define VS4_CHGD_SERX_DP (1 << 1)
++#define VS4_CHGD_SERX_DM (1 << 0)
++
++#define VS5_AUTORESUME_WDOG_EN (1 << 6)
++#define VS5_ID_FLOAT_EN (1 << 5)
++#define VS5_ID_RES_EN (1 << 4)
++#define VS5_SVLDCONWKB_WDOG_EN (1 << 3)
++#define VS5_VBUS_MNTR_RISE_EN (1 << 2)
++#define VS5_VBUS_MNTR_FALL_EN (1 << 1)
++#define VS5_REG3V3IN_MNTR_EN (1 << 0)
++
++#define DEBUG_LINESTATE (0x3 << 0)
++
++#define OTGCTRL_USEEXTVBUS_INDICATOR (1 << 7)
++#define OTGCTRL_DRVVBUSEXTERNAL (1 << 6)
++#define OTGCTRL_DRVVBUS (1 << 5)
++#define OTGCTRL_CHRGVBUS (1 << 4)
++#define OTGCTRL_DISCHRGVBUS (1 << 3)
++#define OTGCTRL_DMPULLDOWN (1 << 2)
++#define OTGCTRL_DPPULLDOWN (1 << 1)
++#define OTGCTRL_IDPULLUP (1 << 0)
++
++#define FUNCCTRL_SUSPENDM (1 << 6)
++#define FUNCCTRL_RESET (1 << 5)
++#define FUNCCTRL_OPMODE(v) ((v & 0x3) << 3)
++#define FUNCCTRL_TERMSELECT (1 << 2)
++#define FUNCCTRL_XCVRSELECT(v) (v & 0x3)
++
++#define PWCTRL_HWDETECT (1 << 7)
++#define PWCTRL_DP_VSRC_EN (1 << 6)
++#define PWCTRL_VDAT_DET (1 << 5)
++#define PWCTRL_DP_WKPU_EN (1 << 4)
++#define PWCTRL_BVALID_FALL (1 << 3)
++#define PWCTRL_BVALID_RISE (1 << 2)
++#define PWCTRL_DET_COMP (1 << 1)
++#define PWCTRL_SW_CONTROL (1 << 0)
++
++
++#define PMIC_VLDOCNT 0xAF
++#define PMIC_VLDOCNT_VUSBPHYEN (1 << 2)
++
++#define PMIC_TLP1ESBS0I1VNNBASE 0X6B
++#define PMIC_I2COVRDADDR 0x59
++#define PMIC_I2COVROFFSET 0x5A
++#define PMIC_USBPHYCTRL 0x30
++#define PMIC_I2COVRWRDATA 0x5B
++#define PMIC_I2COVRCTRL 0x58
++#define PMIC_I2COVRCTL_I2CWR 0x01
++
++#define USBPHYCTRL_D0 (1 << 0)
++#define PMIC_USBIDCTRL 0x19
++#define USBIDCTRL_ACA_DETEN_D1 (1 << 1)
++#define USBIDCTRL_USB_IDEN_D0 (1 << 0)
++#define PMIC_USBIDSTS 0x1A
++#define USBIDSTS_ID_GND (1 << 0)
++#define USBIDSTS_ID_RARBRC_STS(v) ((v & 0x3) << 1)
++#define USBIDSTS_ID_FLOAT_STS (1 << 3)
++#define PMIC_USBPHYCTRL_D0 (1 << 0)
++#define APBFC_EXIOTG3_MISC0_REG 0xF90FF85C
++
++#define DATACON_TIMEOUT 750
++#define DATACON_INTERVAL 10
++#define VBUS_TIMEOUT 300
++#define PCI_DEVICE_ID_DWC 0x119E
++
++#define VENDOR_ID_MASK (0x03 << 6)
++#define BASIN_COVE_PMIC_ID (0x03 << 6)
++
++#define PMIC_MAJOR_REV (0x07 << 3)
++#define PMIC_A0_MAJOR_REV 0x00
++
++#endif /* __DWC3_INTEL_H */
+diff --git a/include/linux/usb/dwc3-intel-mrfl.h b/include/linux/usb/dwc3-intel-mrfl.h
+new file mode 100644
+index 0000000..82f3099
+--- /dev/null
++++ b/include/linux/usb/dwc3-intel-mrfl.h
+@@ -0,0 +1,168 @@
++/*
++ * Intel Penwell USB OTG transceiver driver
++ * Copyright (C) 2009 - 2010, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#ifndef __DWC3_INTEL_H
++#define __DWC3_INTEL_H
++
++#include "otg.h"
++
++struct intel_dwc_otg_pdata {
++ int is_hvp;
++ int charging_compliance;
++};
++
++#define TUSB1211_VENDOR_ID_LO 0x00
++#define TUSB1211_VENDOR_ID_HI 0x01
++#define TUSB1211_PRODUCT_ID_LO 0x02
++#define TUSB1211_PRODUCT_ID_HI 0x03
++#define TUSB1211_FUNC_CTRL 0x04
++#define TUSB1211_FUNC_CTRL_SET 0x05
++#define TUSB1211_FUNC_CTRL_CLR 0x06
++#define TUSB1211_IFC_CTRL 0x07
++#define TUSB1211_IFC_CTRL_SET 0x08
++#define TUSB1211_IFC_CTRL_CLR 0x09
++#define TUSB1211_OTG_CTRL 0x0A
++#define TUSB1211_OTG_CTRL_SET 0x0B
++#define TUSB1211_OTG_CTRL_CLR 0x0C
++#define TUSB1211_USB_INT_EN_RISE 0x0D
++#define TUSB1211_USB_INT_EN_RISE_SET 0x0E
++#define TUSB1211_USB_INT_EN_RISE_CLR 0x0F
++#define TUSB1211_USB_INT_EN_FALL 0x10
++#define TUSB1211_USB_INT_EN_FALL_SET 0x11
++#define TUSB1211_USB_INT_EN_FALL_CLR 0x12
++#define TUSB1211_USB_INT_STS 0x13
++#define TUSB1211_USB_INT_LATCH 0x14
++#define TUSB1211_DEBUG 0x15
++#define TUSB1211_SCRATCH_REG 0x16
++#define TUSB1211_SCRATCH_REG_SET 0x17
++#define TUSB1211_SCRATCH_REG_CLR 0x18
++#define TUSB1211_ACCESS_EXT_REG_SET 0x2F
++
++#define TUSB1211_VENDOR_SPECIFIC1 0x80
++#define TUSB1211_VENDOR_SPECIFIC1_SET 0x81
++#define TUSB1211_VENDOR_SPECIFIC1_CLR 0x82
++#define TUSB1211_POWER_CONTROL 0x3D
++#define TUSB1211_POWER_CONTROL_SET 0x3E
++#define TUSB1211_POWER_CONTROL_CLR 0x3F
++
++#define TUSB1211_VENDOR_SPECIFIC2 0x80
++#define TUSB1211_VENDOR_SPECIFIC2_SET 0x81
++#define TUSB1211_VENDOR_SPECIFIC2_CLR 0x82
++#define TUSB1211_VENDOR_SPECIFIC2_STS 0x83
++#define TUSB1211_VENDOR_SPECIFIC2_LATCH 0x84
++#define TUSB1211_VENDOR_SPECIFIC3 0x85
++#define TUSB1211_VENDOR_SPECIFIC3_SET 0x86
++#define TUSB1211_VENDOR_SPECIFIC3_CLR 0x87
++#define TUSB1211_VENDOR_SPECIFIC4 0x88
++#define TUSB1211_VENDOR_SPECIFIC4_SET 0x89
++#define TUSB1211_VENDOR_SPECIFIC4_CLR 0x8A
++#define TUSB1211_VENDOR_SPECIFIC5 0x8B
++#define TUSB1211_VENDOR_SPECIFIC5_SET 0x8C
++#define TUSB1211_VENDOR_SPECIFIC5_CLR 0x8D
++#define TUSB1211_VENDOR_SPECIFIC6 0x8E
++#define TUSB1211_VENDOR_SPECIFIC6_SET 0x8F
++#define TUSB1211_VENDOR_SPECIFIC6_CLR 0x90
++
++#define VS1_DATAPOLARITY (1 << 6)
++#define VS1_ZHSDRV(v) ((v & 0x3) << 5)
++#define VS1_IHSTX(v) ((v & 0x7))
++
++#define VS2STS_VBUS_MNTR_STS (1 << 7)
++#define VS2STS_REG3V3IN_MNTR_STS (1 << 6)
++#define VS2STS_SVLDCONWKB_WDOG_STS (1 << 5)
++#define VS2STS_ID_FLOAT_STS (1 << 4)
++#define VS2STS_ID_RARBRC_STS(v) ((v & 0x3) << 2)
++#define VS2STS_BVALID_STS (1 << 0)
++
++#define VS3_CHGD_IDP_SRC_EN (1 << 6)
++#define VS3_IDPULLUP_WK_EN (1 << 5)
++#define VS3_SW_USB_DET (1 << 4)
++#define VS3_DATA_CONTACT_DET_EN (1 << 3)
++#define VS3_REG3V3_VSEL(v) (v & 0x7)
++
++#define VS4_ACA_DET_EN (1 << 6)
++#define VS4_RABUSIN_EN (1 << 5)
++#define VS4_R1KSERIES (1 << 4)
++#define VS4_PSW_OSOD (1 << 3)
++#define VS4_PSW_CMOS (1 << 2)
++#define VS4_CHGD_SERX_DP (1 << 1)
++#define VS4_CHGD_SERX_DM (1 << 0)
++
++#define VS5_AUTORESUME_WDOG_EN (1 << 6)
++#define VS5_ID_FLOAT_EN (1 << 5)
++#define VS5_ID_RES_EN (1 << 4)
++#define VS5_SVLDCONWKB_WDOG_EN (1 << 3)
++#define VS5_VBUS_MNTR_RISE_EN (1 << 2)
++#define VS5_VBUS_MNTR_FALL_EN (1 << 1)
++#define VS5_REG3V3IN_MNTR_EN (1 << 0)
++
++#define DEBUG_LINESTATE (0x3 << 0)
++
++#define OTGCTRL_USEEXTVBUS_INDICATOR (1 << 7)
++#define OTGCTRL_DRVVBUSEXTERNAL (1 << 6)
++#define OTGCTRL_DRVVBUS (1 << 5)
++#define OTGCTRL_CHRGVBUS (1 << 4)
++#define OTGCTRL_DISCHRGVBUS (1 << 3)
++#define OTGCTRL_DMPULLDOWN (1 << 2)
++#define OTGCTRL_DPPULLDOWN (1 << 1)
++#define OTGCTRL_IDPULLUP (1 << 0)
++
++#define FUNCCTRL_SUSPENDM (1 << 6)
++#define FUNCCTRL_RESET (1 << 5)
++#define FUNCCTRL_OPMODE(v) ((v & 0x3) << 3)
++#define FUNCCTRL_TERMSELECT (1 << 2)
++#define FUNCCTRL_XCVRSELECT(v) (v & 0x3)
++
++#define PWCTRL_HWDETECT (1 << 7)
++#define PWCTRL_DP_VSRC_EN (1 << 6)
++#define PWCTRL_VDAT_DET (1 << 5)
++#define PWCTRL_DP_WKPU_EN (1 << 4)
++#define PWCTRL_BVALID_FALL (1 << 3)
++#define PWCTRL_BVALID_RISE (1 << 2)
++#define PWCTRL_DET_COMP (1 << 1)
++#define PWCTRL_SW_CONTROL (1 << 0)
++
++
++#define PMIC_VLDOCNT 0xAF
++#define PMIC_VLDOCNT_VUSBPHYEN (1 << 2)
++
++#define PMIC_TLP1ESBS0I1VNNBASE 0X6B
++#define PMIC_I2COVRDADDR 0x59
++#define PMIC_I2COVROFFSET 0x5A
++#define PMIC_USBPHYCTRL 0x30
++#define PMIC_I2COVRWRDATA 0x5B
++#define PMIC_I2COVRCTRL 0x58
++#define PMIC_I2COVRCTL_I2CWR 0x01
++
++#define USBPHYCTRL_D0 (1 << 0)
++#define PMIC_USBIDCTRL 0x19
++#define USBIDCTRL_ACA_DETEN_D1 (1 << 1)
++#define USBIDCTRL_USB_IDEN_D0 (1 << 0)
++#define PMIC_USBIDSTS 0x1A
++#define USBIDSTS_ID_GND (1 << 0)
++#define USBIDSTS_ID_RARBRC_STS(v) ((v & 0x3) << 0)
++#define USBIDSTS_ID_FLOAT_STS (1 << 3)
++#define PMIC_USBPHYCTRL_D0 (1 << 0)
++#define APBFC_EXIOTG3_MISC0_REG 0xF90FF85C
++
++#define DATACON_TIMEOUT 750
++#define DATACON_INTERVAL 10
++#define VBUS_TIMEOUT 300
++#define PCI_DEVICE_ID_DWC 0x119E
++#endif /* __DWC3_INTEL_H */
+diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
+index f1b0dca..942ef5e 100644
+--- a/include/linux/usb/gadget.h
++++ b/include/linux/usb/gadget.h
+@@ -22,6 +22,7 @@
+ #include <linux/slab.h>
+ #include <linux/scatterlist.h>
+ #include <linux/types.h>
++#include <linux/workqueue.h>
+ #include <linux/usb/ch9.h>
+
+ struct usb_ep;
+@@ -475,6 +476,7 @@ struct usb_gadget_ops {
+
+ /**
+ * struct usb_gadget - represents a usb slave device
++ * @work: (internal use) Workqueue to be used for sysfs_notify()
+ * @ops: Function pointers used to access hardware-specific operations.
+ * @ep0: Endpoint zero, used when reading or writing responses to
+ * driver setup() requests
+@@ -520,6 +522,7 @@ struct usb_gadget_ops {
+ * device is acting as a B-Peripheral (so is_a_peripheral is false).
+ */
+ struct usb_gadget {
++ struct work_struct work;
+ /* readonly to gadget driver */
+ const struct usb_gadget_ops *ops;
+ struct usb_ep *ep0;
+@@ -538,6 +541,7 @@ struct usb_gadget {
+ unsigned out_epnum;
+ unsigned in_epnum;
+ };
++#define work_to_gadget(w) (container_of((w), struct usb_gadget, work))
+
+ static inline void set_gadget_data(struct usb_gadget *gadget, void *data)
+ { dev_set_drvdata(&gadget->dev, data); }
+diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
+index 0fdff28..39aa5c5 100644
+--- a/include/linux/usb/hcd.h
++++ b/include/linux/usb/hcd.h
+@@ -110,6 +110,7 @@ struct usb_hcd {
+ #define HCD_FLAG_WAKEUP_PENDING 4 /* root hub is resuming? */
+ #define HCD_FLAG_RH_RUNNING 5 /* root hub is running? */
+ #define HCD_FLAG_DEAD 6 /* controller has died? */
++#define HCD_FLAG_IRQ_DISABLED 7 /* Interrupt was disabled */
+
+ /* The flags can be tested using these macros; they are likely to
+ * be slightly faster than test_bit().
+@@ -120,6 +121,7 @@ struct usb_hcd {
+ #define HCD_WAKEUP_PENDING(hcd) ((hcd)->flags & (1U << HCD_FLAG_WAKEUP_PENDING))
+ #define HCD_RH_RUNNING(hcd) ((hcd)->flags & (1U << HCD_FLAG_RH_RUNNING))
+ #define HCD_DEAD(hcd) ((hcd)->flags & (1U << HCD_FLAG_DEAD))
++#define HCD_IRQ_DISABLED(hcd) ((hcd)->flags & (1U << HCD_FLAG_IRQ_DISABLED))
+
+ /* Flags that get set only during HCD registration or removal. */
+ unsigned rh_registered:1;/* is root hub registered? */
+@@ -132,6 +134,7 @@ struct usb_hcd {
+ unsigned wireless:1; /* Wireless USB HCD */
+ unsigned authorized_default:1;
+ unsigned has_tt:1; /* Integrated TT in root hub */
++ unsigned has_wakeup_irq:1; /* Can IRQ when suspended */
+
+ unsigned int irq; /* irq allocated */
+ void __iomem *regs; /* device memory/io */
+diff --git a/include/linux/usb/penwell_otg.h b/include/linux/usb/penwell_otg.h
+new file mode 100644
+index 0000000..bf80b75
+--- /dev/null
++++ b/include/linux/usb/penwell_otg.h
+@@ -0,0 +1,515 @@
++/*
++ * Intel Penwell USB OTG transceiver driver
++ * Copyright (C) 2009 - 2010, Intel Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#ifndef __PENWELL_OTG_H__
++#define __PENWELL_OTG_H__
++
++#include <linux/usb/intel_mid_otg.h>
++#include <linux/power_supply.h>
++#include <linux/wakelock.h>
++
++#define PMU_OTG_WAKE_SOURCE 6
++#define CI_USBCMD 0x30
++# define USBCMD_RST BIT(1)
++# define USBCMD_RS BIT(0)
++#define CI_USBSTS 0x34
++# define USBSTS_SLI BIT(8)
++# define USBSTS_URI BIT(6)
++# define USBSTS_PCI BIT(2)
++#define CI_USBINTR 0x38
++# define USBINTR_PCE BIT(2)
++#define CI_ULPIVP 0x60
++# define ULPI_WU BIT(31)
++# define ULPI_RUN BIT(30)
++# define ULPI_RW BIT(29)
++# define ULPI_SS BIT(27)
++# define ULPI_PORT (BIT(26) | BIT(25) | BIT(24))
++# define ULPI_ADDR (0xff << 16)
++# define ULPI_DATRD (0xff << 8)
++# define ULPI_DATWR (0xff << 0)
++#define CI_PORTSC1 0x74
++# define PORTSC_PP BIT(12)
++# define PORTSC_LS (BIT(11) | BIT(10))
++# define PORTSC_SUSP BIT(7)
++# define PORTSC_CCS BIT(0)
++#define CI_HOSTPC1 0xb4
++# define HOSTPC1_PHCD BIT(22)
++#define CI_OTGSC 0xf4
++# define OTGSC_DPIE BIT(30)
++# define OTGSC_1MSE BIT(29)
++# define OTGSC_BSEIE BIT(28)
++# define OTGSC_BSVIE BIT(27)
++# define OTGSC_ASVIE BIT(26)
++# define OTGSC_AVVIE BIT(25)
++# define OTGSC_IDIE BIT(24)
++# define OTGSC_DPIS BIT(22)
++# define OTGSC_1MSS BIT(21)
++# define OTGSC_BSEIS BIT(20)
++# define OTGSC_BSVIS BIT(19)
++# define OTGSC_ASVIS BIT(18)
++# define OTGSC_AVVIS BIT(17)
++# define OTGSC_IDIS BIT(16)
++# define OTGSC_DPS BIT(14)
++# define OTGSC_1MST BIT(13)
++# define OTGSC_BSE BIT(12)
++# define OTGSC_BSV BIT(11)
++# define OTGSC_ASV BIT(10)
++# define OTGSC_AVV BIT(9)
++# define OTGSC_ID BIT(8)
++# define OTGSC_HABA BIT(7)
++# define OTGSC_HADP BIT(6)
++# define OTGSC_IDPU BIT(5)
++# define OTGSC_DP BIT(4)
++# define OTGSC_OT BIT(3)
++# define OTGSC_HAAR BIT(2)
++# define OTGSC_VC BIT(1)
++# define OTGSC_VD BIT(0)
++#define CI_USBMODE 0xf8
++# define USBMODE_CM (BIT(1) | BIT(0))
++# define USBMODE_IDLE 0
++# define USBMODE_DEVICE 0x2
++# define USBMODE_HOST 0x3
++#define USBCFG_ADDR 0xff10801c
++#define USBCFG_LEN 4
++# define USBCFG_VBUSVAL BIT(14)
++# define USBCFG_AVALID BIT(13)
++# define USBCFG_BVALID BIT(12)
++# define USBCFG_SESEND BIT(11)
++
++#define OTGSC_INTEN_MASK \
++ (OTGSC_DPIE | OTGSC_BSEIE | OTGSC_BSVIE \
++ | OTGSC_ASVIE | OTGSC_AVVIE | OTGSC_IDIE)
++
++#define OTGSC_INTSTS_MASK \
++ (OTGSC_DPIS | OTGSC_BSEIS | OTGSC_BSVIS \
++ | OTGSC_ASVIS | OTGSC_AVVIS | OTGSC_IDIS)
++
++#define INTR_DUMMY_MASK (USBSTS_SLI | USBSTS_URI | USBSTS_PCI)
++
++#define HOST_REQUEST_FLAG BIT(0)
++
++/* MSIC register for vbus power control */
++#define MSIC_ID 0x00
++# define ID0_VENDID0 (BIT(7) | BIT(6))
++#define MSIC_ID1 0x01
++# define ID1_VENDID1 (BIT(7) | BIT(6))
++#define MSIC_VUSB330CNT 0xd4
++#define MSIC_VOTGCNT 0xdf
++# define VOTGEN BIT(7)
++# define VOTGRAMP BIT(4)
++#define MSIC_SPWRSRINT1 0x193
++# define SUSBCHPDET BIT(6)
++# define SUSBDCDET BIT(2)
++# define MSIC_SPWRSRINT1_MASK (BIT(6) | BIT(2))
++# define SPWRSRINT1_CDP BIT(6)
++# define SPWRSRINT1_SDP 0
++# define SPWRSRINT1_DCP BIT(2)
++#define MSIC_USB_MISC 0x2c8 /* Intel Specific */
++# define MISC_CHGDSERXDPINV BIT(5)
++#define MSIC_OTGCTRL 0x39c
++#define MSIC_OTGCTRLSET 0x340
++#define MSIC_OTGCTRLCLR 0x341
++#define ULPI_OTGCTRL 0x0a
++#define ULPI_OTGCTRLSET 0x0b
++#define ULPI_OTGCTRLCLR 0x0c
++# define DRVVBUS_EXTERNAL BIT(6)
++# define DRVVBUS BIT(5)
++# define DMPULLDOWN BIT(2)
++# define DPPULLDOWN BIT(1)
++#define MSIC_USBINTEN_RISE 0x39d
++#define MSIC_USBINTEN_RISESET 0x39e
++#define MSIC_USBINTEN_RISECLR 0x39f
++#define MSIC_USBINTEN_FALL 0x3a0
++#define MSIC_USBINTEN_FALLSET 0x3a1
++#define MSIC_USBINTEN_FALLCLR 0x3a2
++
++/*
++ * For Clovertrail, due to change of USB PHY from MSIC to external standalone
++ * chip, USB Interrupt Enable Rising/Falling registers can be accessed only
++ * from ULPI interface.
++ */
++#define ULPI_USBINTEN_RISING 0xd
++#define ULPI_USBINTEN_RISINGSET 0xe
++#define ULPI_USBINTEN_RISINGCLR 0xf
++#define ULPI_USBINTEN_FALLING 0x10
++#define ULPI_USBINTEN_FALLINGSET 0x11
++#define ULPI_USBINTEN_FALLINGCLR 0x12
++
++# define IDGND BIT(4)
++# define SESSEND BIT(3)
++# define SESSVLD BIT(2)
++# define VBUSVLD BIT(1)
++# define HOSTDISCON BIT(0)
++#define MSIC_PWRCTRL 0x3b5
++#define MSIC_PWRCTRLSET 0x342
++#define MSIC_PWRCTRLCLR 0x343
++#define ULPI_PWRCTRL 0x3d
++#define ULPI_PWRCTRLSET 0x3e
++#define ULPI_PWRCTRLCLR 0x3f
++# define HWDET BIT(7)
++# define DPVSRCEN BIT(6)
++# define VDATDET BIT(5)
++# define DPWKPUEN BIT(4)
++# define SWCNTRL BIT(0)
++#define MSIC_FUNCTRL 0x398
++#define MSIC_FUNCTRLSET 0x344
++#define MSIC_FUNCTRLCLR 0x345
++#define ULPI_FUNCTRL 0x04
++#define ULPI_FUNCTRLSET 0x05
++#define ULPI_FUNCTRLCLR 0x06
++# define PHYRESET BIT(5)
++# define OPMODE1 BIT(4)
++# define OPMODE0 BIT(3)
++# define TERMSELECT BIT(2)
++# define XCVRSELECT1 BIT(1)
++# define XCVRSELECT0 BIT(0)
++#define MSIC_DEBUG 0x3a5
++#define ULPI_DEBUG 0x15
++# define LINESTATE_MSK (BIT(0) | BIT(1))
++# define LINESTATE_SE1 (BIT(0) | BIT(1))
++# define LINESTATE_SE0 (0)
++# define LINESTATE_FSJ BIT(0)
++# define LINESTATE_FSK BIT(1)
++#define MSIC_VS1 0x3b6
++#define MSIC_VS1SET 0x3a9
++#define MSIC_VS1CLR 0x3aa
++#define ULPI_VS1 0x80
++#define ULPI_VS1SET 0x81
++#define ULPI_VS1CLR 0x82
++# define DATAPOLARITY BIT(6)
++#define ULPI_VS2STS 0x83
++#define ULPI_VS2LATCH 0x84
++# define VBUS_MNTR_STS BIT(7)
++# define REG3V3_MNTR_STS BIT(6)
++# define SVLDCONWKB_WDOG_STS BIT(5)
++# define IDFLOAT_STS BIT(4)
++# define IDRARBRC_STS(d) (((d)>>2)&3)
++# define IDRARBRC_STS1 BIT(3)
++# define IDRARBRC_STS2 BIT(2)
++# define IDRARBRC_MSK (BIT(2) | BIT(3))
++# define IDRARBRC_A 1
++# define IDRARBRC_B 2
++# define IDRARBRC_C 3
++# define BVALID_STS BIT(0)
++#define MSIC_VS3 0x3b9
++#define MSIC_VS3SET 0x346 /* Vendor Specific */
++#define MSIC_VS3CLR 0x347
++# define SWUSBDET BIT(4)
++# define DATACONEN BIT(3)
++#define ULPI_VS3 0x85
++#define ULPI_VS3SET 0x86
++#define ULPI_VS3CLR 0x87
++# define CHGD_IDP_SRC BIT(6)
++# define IDPULLUP_WK BIT(5)
++# define SWUSBDET BIT(4)
++# define DATACONEN BIT(3)
++#define MSIC_VS4 0x3ba
++#define MSIC_VS4SET 0x3ab
++#define MSIC_VS4CLR 0x3ac
++#define ULPI_VS4 0x88
++#define ULPI_VS4SET 0x89
++#define ULPI_VS4CLR 0x8a
++# define ACADET BIT(6)
++# define RABUSIN BIT(5)
++# define R1KERIES BIT(4)
++# define CHRG_SERX_DP BIT(1)
++# define CHRG_SERX_DM BIT(0)
++#define ULPI_VS5 0x8b
++#define ULPI_VS5SET 0x8c
++#define ULPI_VS5CLR 0x8d
++# define AUTORESUME_WDOG BIT(6)
++# define IDFLOAT_EN BIT(5)
++# define IDRES_EN BIT(4)
++# define SVLDCONWKB_WDOG BIT(3)
++# define VBUS_MNTR_RISEEN BIT(2)
++# define VBUS_MNTR_FALLEN BIT(1)
++# define REG3V3IN_MNTR_EN BIT(0)
++#define ULPI_VS6 0x8e
++#define ULPI_VS6SET 0x8f
++#define ULPI_VS6CLR 0x90
++# define ACA_RID_B_CFG BIT(7)
++# define ACA_RID_A_CFG BIT(6)
++# define SOF_EN BIT(5)
++#define MSIC_ULPIACCESSMODE 0x348
++# define SPIMODE BIT(0)
++#define MSIC_INT_EN_RISE 0x39D
++#define MSIC_INT_EN_RISE_SET 0x39E
++#define MSIC_INT_EN_RISE_CLR 0x39F
++#define MSIC_INT_EN_FALL 0x3A0
++#define MSIC_INT_EN_FALL_SET 0x3A1
++#define MSIC_INT_EN_FALL_CLR 0x3A2
++
++/* MSIC TI implementation for ADP/ACA */
++#define SPI_TI_VS2 0x3B7
++#define SPI_TI_VS2_LATCH 0x3B8
++#define SPI_TI_VS4 0x3BA
++#define SPI_TI_VS5 0x3BB
++#define ULPI_TI_USB_INT_STS 0x13
++#define ULPI_TI_USB_INT_LAT 0x14
++# define USB_INT_IDGND BIT(4)
++# define USB_INT_SESSEND BIT(3)
++# define USB_INT_SESSVLD BIT(2)
++# define USB_INT_VBUSVLD BIT(1)
++#define ULPI_TI_VS2 0x83
++# define TI_ID_FLOAT_STS BIT(4)
++# define TI_ID_RARBRC_STS(d) (((d)>>2)&3)
++# define TI_ID_RARBRC_STS_MASK (BIT(3) | BIT(2))
++# define TI_ID_RARBRC_NONE 0
++# define TI_ID_RARBRC_A 1
++# define TI_ID_RARBRC_B 2
++# define TI_ID_RARBRC_C 3
++# define TI_ADP_INT_STS BIT(1)
++#define ULPI_TI_VS4 0x88
++# define TI_ACA_DET_EN BIT(6)
++#define ULPI_TI_VS5 0x8b
++# define TI_ADP_INT_EN BIT(7)
++# define TI_ID_FLOAT_EN BIT(5)
++# define TI_ID_RES_EN BIT(4)
++#define ULPI_TI_VS6 0x8e
++# define TI_HS_TXPREN BIT(4)
++# define TI_ADP_MODE(d) (((d)>>2)&3)
++# define TI_ADP_MODE_MASK (BIT(3) | BIT(2))
++# define TI_ADP_MODE_DISABLE 0
++# define TI_ADP_MODE_SENSE 1
++# define TI_ADP_MODE_PRB_A 2
++# define TI_ADP_MODE_PRB_B 3
++# define TI_VBUS_IADP_SRC BIT(1)
++# define TI_VBUS_IADP_SINK BIT(0)
++#define ULPI_TI_VS7 0x91
++# define TI_T_ADP_HIGH (0xff)
++#define ULPI_TI_VS8 0x94
++# define TI_T_ADP_LOW (0xff)
++#define ULPI_TI_VS9 0x97
++# define TI_T_ADP_RISE (0xff)
++
++#define TI_PRB_DELTA 0x08
++
++/* MSIC FreeScale Implementation for ADP */
++#define ULPI_FS_ADPCL 0x28
++# define ADPCL_PRBDSCHG (BIT(5) | BIT(6))
++# define ADPCL_PRBDSCHG_4 0
++# define ADPCL_PRBDSCHG_8 1
++# define ADPCL_PRBDSCHG_16 2
++# define ADPCL_PRBDSCHG_32 3
++# define ADPCL_PRBPRD (BIT(3) | BIT(4))
++# define ADPCL_PRBPRD_A_HALF 0
++# define ADPCL_PRBPRD_B_HALF 1
++# define ADPCL_PRBPRD_A 2
++# define ADPCL_PRBPRD_B 3
++# define ADPCL_SNSEN BIT(2)
++# define ADPCL_PRBEN BIT(1)
++# define ADPCL_ADPEN BIT(0)
++#define ULPI_FS_ADPCH 0x29
++# define ADPCH_PRBDELTA (0x1f << 0)
++#define ULPI_FS_ADPIE 0x2a
++# define ADPIE_ADPRAMPIE BIT(2)
++# define ADPIE_SNSMISSIE BIT(1)
++# define ADPIE_PRBTRGIE BIT(0)
++#define ULPI_FS_ADPIS 0x2b
++# define ADPIS_ADPRAMPS BIT(5)
++# define ADPIS_SNSMISSS BIT(4)
++# define ADPIS_PRBTRGS BIT(3)
++# define ADPIS_ADPRAMPI BIT(2)
++# define ADPIS_SNSMISSI BIT(1)
++# define ADPIS_PRBTRGI BIT(0)
++#define ULPI_FS_ADPRL 0x2c
++# define ADPRL_ADPRAMP (0xff << 0)
++#define ULPI_FS_ADPRH 0x2d
++# define ADPRH_ADPRAMP (0x7 << 0)
++
++#define FS_ADPI_MASK (ADPIS_ADPRAMPI | ADPIS_SNSMISSI | ADPIS_PRBTRGI)
++
++/* define Data connect checking timeout and polling interval */
++#define DATACON_TIMEOUT 750
++#define DATACON_INTERVAL 20
++
++enum penwell_otg_timer_type {
++ TA_WAIT_VRISE_TMR,
++ TA_WAIT_BCON_TMR,
++ TA_AIDL_BDIS_TMR,
++ TA_BIDL_ADIS_TMR,
++ TA_WAIT_VFALL_TMR,
++ TB_ASE0_BRST_TMR,
++ TB_SE0_SRP_TMR,
++ TB_SRP_FAIL_TMR, /* wait for response of SRP */
++ TB_BUS_SUSPEND_TMR,
++ TTST_MAINT_TMR,
++ TTST_NOADP_TMR,
++};
++
++#define TA_WAIT_VRISE 100
++#define TA_WAIT_BCON 50000
++#define TA_AIDL_BDIS 1500
++#define TA_BIDL_ADIS 300
++#define TA_WAIT_VFALL 950
++#define TB_ASE0_BRST 300
++#define TB_SE0_SRP 1200
++#define TB_SSEND_SRP 1800
++# define SRP_MON_INVAL 300 /* TODO: interval needs more tuning */
++#define TB_SRP_FAIL 5500
++#define TB_BUS_SUSPEND 500
++#define THOS_REQ_POL 1500
++/* Test mode */
++#define TTST_MAINT 9900
++#define TTST_NOADP 5000
++
++/* MSIC vendor information */
++enum msic_vendor {
++ MSIC_VD_FS,
++ MSIC_VD_TI,
++ MSIC_VD_UNKNOWN
++};
++
++/* charger defined in BC 1.2 */
++enum usb_charger_type {
++ CHRG_UNKNOWN,
++ CHRG_SDP, /* Standard Downstream Port */
++ CHRG_CDP, /* Charging Downstream Port */
++ CHRG_SDP_INVAL, /* Invaild Standard Downstream Port */
++ CHRG_DCP, /* Dedicated Charging Port */
++ CHRG_ACA, /* Accessory Charger Adapter */
++ CHRG_ACA_DOCK, /* Accessory Charger Adapter - Dock */
++ CHRG_ACA_A, /* Accessory Charger Adapter - RID_A */
++ CHRG_ACA_B, /* Accessory Charger Adapter - RID_B */
++ CHRG_ACA_C, /* Accessory Charger Adapter - RID_C */
++ CHRG_SE1, /* SE1 (Apple)*/
++ CHRG_MHL /* Moblie High-Definition Link */
++};
++
++struct adp_status {
++ struct completion adp_comp;
++ u8 t_adp_rise;
++};
++
++/* Invalid SDP checking timeout */
++#define INVALID_SDP_TIMEOUT (HZ * 15)
++
++/* OTG Battery Charging capability is used in charger capability detection */
++struct otg_bc_cap {
++ enum usb_charger_type chrg_type;
++ unsigned int ma;
++#define CHRG_CURR_UNKNOWN 0
++#define CHRG_CURR_DISCONN 0
++#define CHRG_CURR_SDP_SUSP 2
++#define CHRG_CURR_SDP_UNCONFIG 100
++#define CHRG_CURR_SDP_LOW 100
++#define CHRG_CURR_SDP_HIGH 500
++#define CHRG_CURR_SDP_INVAL 500
++#define CHRG_CURR_CDP 1500
++#define CHRG_CURR_DCP 1500
++#define CHRG_CURR_SE1 1500
++#define CHRG_CURR_ACA 1500
++ unsigned int current_event;
++};
++
++struct otg_bc_event {
++ struct list_head node;
++ struct power_supply_cable_props cap;
++};
++
++/* Bus monitor action for b_ssend_srp/b_se0_srp */
++#define BUS_MON_STOP 0
++#define BUS_MON_START 1
++#define BUS_MON_CONTINUE 2
++
++/* define event ids to notify battery driver */
++#define USBCHRG_EVENT_CONNECT 1
++#define USBCHRG_EVENT_DISCONN 2
++#define USBCHRG_EVENT_SUSPEND 3
++#define USBCHRG_EVENT_RESUME 4
++#define USBCHRG_EVENT_UPDATE 5
++
++struct intel_mid_otg_pdata {
++ int gpio_vbus;
++ int gpio_cs;
++ int gpio_reset;
++ int charging_compliance;
++ int hnp_poll_support;
++ unsigned power_budget;
++};
++
++struct penwell_otg {
++ struct intel_mid_otg_xceiv iotg;
++ struct device *dev;
++
++ unsigned region;
++ unsigned cfg_region;
++
++ struct work_struct work;
++ struct work_struct hnp_poll_work;
++ struct work_struct psc_notify;
++ struct work_struct uevent_work;
++ struct delayed_work ulpi_poll_work;
++ struct delayed_work ulpi_check_work;
++ struct delayed_work sdp_check_work;
++ struct workqueue_struct *qwork;
++ struct workqueue_struct *chrg_qwork;
++
++
++ struct timer_list hsm_timer;
++ struct timer_list hnp_poll_timer;
++ struct timer_list bus_mon_timer;
++
++ unsigned long b_se0_srp_time;
++ unsigned long b_ssend_srp_time;
++
++ struct mutex msic_mutex;
++ enum msic_vendor msic;
++
++ struct notifier_block iotg_notifier;
++ int queue_stop;
++
++ struct adp_status adp;
++
++ spinlock_t charger_lock;
++ struct list_head chrg_evt_queue;
++ struct otg_bc_cap charging_cap;
++ spinlock_t cap_lock;
++ struct power_supply_cable_props psc_cap;
++ int (*bc_callback)(void *arg, int event, struct otg_bc_cap *cap);
++ void *bc_arg;
++
++ unsigned rt_resuming;
++
++ unsigned rt_quiesce;
++ struct intel_mid_otg_pdata *otg_pdata;
++
++ struct wake_lock wake_lock;
++ spinlock_t lock;
++
++ int phy_power_state;
++};
++
++static inline
++struct penwell_otg *iotg_to_penwell(struct intel_mid_otg_xceiv *iotg)
++{
++ return container_of(iotg, struct penwell_otg, iotg);
++}
++
++extern int penwell_otg_query_charging_cap(struct otg_bc_cap *cap);
++extern int penwell_otg_query_power_supply_cap(
++ struct power_supply_cable_props *cap);
++extern void *penwell_otg_register_bc_callback(
++ int (*cb)(void *, int, struct otg_bc_cap *), void *arg);
++extern int penwell_otg_unregister_bc_callback(void *handler);
++
++extern int pnw_otg_ulpi_write(u8 reg, u8 val);
++extern int is_clovertrail(struct pci_dev *pdev);
++
++#endif /* __PENWELL_OTG_H__ */
+diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h
+index 6b5978f..fe5cb1e 100644
+--- a/include/linux/usb/phy.h
++++ b/include/linux/usb/phy.h
+@@ -18,6 +18,7 @@ enum usb_phy_events {
+ USB_EVENT_ID, /* id was grounded */
+ USB_EVENT_CHARGER, /* usb dedicated charger */
+ USB_EVENT_ENUMERATED, /* gadget driver enumerated */
++ USB_EVENT_DRIVE_VBUS, /* drive vbus request */
+ };
+
+ /* associate a type with PHY */
+@@ -107,6 +108,9 @@ struct usb_phy {
+ enum usb_device_speed speed);
+ int (*notify_disconnect)(struct usb_phy *x,
+ enum usb_device_speed speed);
++
++ /* check charger status */
++ int (*get_chrg_status)(struct usb_phy *x, void *data);
+ };
+
+ /**
+@@ -297,4 +301,14 @@ static inline const char *usb_phy_type_string(enum usb_phy_type type)
+ return "UNKNOWN PHY TYPE";
+ }
+ }
++
++static inline int
++otg_get_chrg_status(struct usb_phy *x, void *data)
++{
++ if (x && x->get_chrg_status)
++ return x->get_chrg_status(x, data);
++
++ return -ENOTSUPP;
++}
++
+ #endif /* __LINUX_USB_PHY_H */
+diff --git a/include/linux/wl12xx.h b/include/linux/wl12xx.h
+index a54fe82..5020662 100644
+--- a/include/linux/wl12xx.h
++++ b/include/linux/wl12xx.h
+@@ -50,8 +50,13 @@ enum {
+
+ struct wl12xx_platform_data {
+ void (*set_power)(bool enable);
++ int (*hw_init)(struct wl12xx_platform_data *pdata);
++ void (*hw_deinit)(struct wl12xx_platform_data *pdata);
+ /* SDIO only: IRQ number if WLAN_IRQ line is used, 0 for SDIO IRQs */
+ int irq;
++ /* gpio must be set to -EINVAL by platform code if gpio based irq is
++ not used */
++ int gpio;
+ bool use_eeprom;
+ int board_ref_clock;
+ int board_tcxo_clock;
+diff --git a/include/linux/wlan_plat.h b/include/linux/wlan_plat.h
+new file mode 100644
+index 0000000..98bbea0
+--- /dev/null
++++ b/include/linux/wlan_plat.h
+@@ -0,0 +1,29 @@
++/* include/linux/wlan_plat.h
++ *
++ * Copyright (C) 2010 Google, Inc.
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ */
++#ifndef _LINUX_WLAN_PLAT_H_
++#define _LINUX_WLAN_PLAT_H_
++
++struct wifi_platform_data {
++ int (*set_power)(int val);
++ int (*set_reset)(int val);
++ int (*set_carddetect)(int val);
++ void *(*mem_prealloc)(int section, unsigned long size);
++ int (*get_mac_addr)(unsigned char *buf);
++ void *(*get_country_code)(char *ccode);
++ char *nvram_id;
++ bool use_fast_irq;
++};
++
++#endif
+diff --git a/include/uapi/linux/usb/ch9.h b/include/uapi/linux/usb/ch9.h
+index aa33fd1..29860d6 100644
+--- a/include/uapi/linux/usb/ch9.h
++++ b/include/uapi/linux/usb/ch9.h
+@@ -294,6 +294,7 @@ struct usb_device_descriptor {
+ #define USB_CLASS_CSCID 0x0b /* chip+ smart card */
+ #define USB_CLASS_CONTENT_SEC 0x0d /* content security */
+ #define USB_CLASS_VIDEO 0x0e
++#define USB_CLASS_DEBUG 0xdc
+ #define USB_CLASS_WIRELESS_CONTROLLER 0xe0
+ #define USB_CLASS_MISC 0xef
+ #define USB_CLASS_APP_SPEC 0xfe
+diff --git a/init/main.c b/init/main.c
+index fc071a6..beddd35 100644
+--- a/init/main.c
++++ b/init/main.c
+@@ -665,11 +665,13 @@ static int __init_or_module do_one_initcall_debug(initcall_t fn)
+ int ret;
+
+ pr_debug("calling %pF @ %i\n", fn, task_pid_nr(current));
++
+ calltime = ktime_get();
+ ret = fn();
+ rettime = ktime_get();
+ delta = ktime_sub(rettime, calltime);
+ duration = (unsigned long long) ktime_to_ns(delta) >> 10;
++
+ pr_debug("initcall %pF returned %d after %lld usecs\n",
+ fn, ret, duration);
+
+diff --git a/kernel/cgroup.c b/kernel/cgroup.c
+index 2e9b387..b6b26fa 100644
+--- a/kernel/cgroup.c
++++ b/kernel/cgroup.c
+@@ -1995,7 +1995,7 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,
+
+ /* @tsk either already exited or can't exit until the end */
+ if (tsk->flags & PF_EXITING)
+- continue;
++ goto next;
+
+ /* as per above, nr_threads may decrease, but not increase. */
+ BUG_ON(i >= group_size);
+@@ -2003,7 +2003,7 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,
+ ent.cgrp = task_cgroup_from_root(tsk, root);
+ /* nothing to do if this task is already in the cgroup */
+ if (ent.cgrp == cgrp)
+- continue;
++ goto next;
+ /*
+ * saying GFP_ATOMIC has no effect here because we did prealloc
+ * earlier, but it's good form to communicate our expectations.
+@@ -2011,7 +2011,7 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,
+ retval = flex_array_put(group, i, &ent, GFP_ATOMIC);
+ BUG_ON(retval != 0);
+ i++;
+-
++ next:
+ if (!threadgroup)
+ break;
+ } while_each_thread(leader, tsk);
+diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
+index cbd97ce..63af23a 100644
+--- a/kernel/irq/chip.c
++++ b/kernel/irq/chip.c
+@@ -672,6 +672,7 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
+ irq_settings_set_noprobe(desc);
+ irq_settings_set_norequest(desc);
+ irq_settings_set_nothread(desc);
++ irq_settings_set_chained(desc);
+ irq_startup(desc, true);
+ }
+ out:
+diff --git a/kernel/irq/settings.h b/kernel/irq/settings.h
+index 1162f10..4ea2f96 100644
+--- a/kernel/irq/settings.h
++++ b/kernel/irq/settings.h
+@@ -15,6 +15,7 @@ enum {
+ _IRQ_NESTED_THREAD = IRQ_NESTED_THREAD,
+ _IRQ_PER_CPU_DEVID = IRQ_PER_CPU_DEVID,
+ _IRQF_MODIFY_MASK = IRQF_MODIFY_MASK,
++ _IRQ_CHAINED = IRQ_CHAINED,
+ };
+
+ #define IRQ_PER_CPU GOT_YOU_MORON
+@@ -28,6 +29,7 @@ enum {
+ #define IRQ_PER_CPU_DEVID GOT_YOU_MORON
+ #undef IRQF_MODIFY_MASK
+ #define IRQF_MODIFY_MASK GOT_YOU_MORON
++#define IRQ_CHAINED GOT_YOU_MORON
+
+ static inline void
+ irq_settings_clr_and_set(struct irq_desc *desc, u32 clr, u32 set)
+@@ -147,3 +149,8 @@ static inline bool irq_settings_is_nested_thread(struct irq_desc *desc)
+ {
+ return desc->status_use_accessors & _IRQ_NESTED_THREAD;
+ }
++
++static inline bool irq_settings_set_chained(struct irq_desc *desc)
++{
++ return desc->status_use_accessors |= _IRQ_CHAINED;
++}
+diff --git a/kernel/power/process.c b/kernel/power/process.c
+index 98088e0..4ea5ad3 100644
+--- a/kernel/power/process.c
++++ b/kernel/power/process.c
+@@ -33,6 +33,8 @@ static int try_to_freeze_tasks(bool user_only)
+ u64 elapsed_csecs64;
+ unsigned int elapsed_csecs;
+ bool wakeup = false;
++ int sleep_usecs = USEC_PER_MSEC;
++ char *busy_wq_name = NULL;
+
+ do_gettimeofday(&start);
+
+diff --git a/kernel/printk.c b/kernel/printk.c
+index d37d45c..38e709f 100644
+--- a/kernel/printk.c
++++ b/kernel/printk.c
+@@ -363,6 +363,13 @@ static void log_store(int facility, int level,
+ log_next_seq++;
+ }
+
++/* Clears the ring-buffer */
++void log_buf_clear(void)
++{
++ clear_seq = log_next_seq;
++ clear_idx = log_next_idx;
++}
++
+ #ifdef CONFIG_SECURITY_DMESG_RESTRICT
+ int dmesg_restrict = 1;
+ #else
+@@ -1353,7 +1360,7 @@ static int console_trylock_for_printk(unsigned int cpu)
+ {
+ int retval = 0, wake = 0;
+
+- if (console_trylock()) {
++ if (!in_nmi() && console_trylock()) {
+ retval = 1;
+
+ /*
+@@ -1532,7 +1539,13 @@ asmlinkage int vprintk_emit(int facility, int level,
+ }
+
+ lockdep_off();
+- raw_spin_lock(&logbuf_lock);
++ if (unlikely(in_nmi())) {
++ if (!raw_spin_trylock(&logbuf_lock))
++ goto out_restore_lockdep_irqs;
++ } else {
++ raw_spin_lock(&logbuf_lock);
++ }
++
+ logbuf_cpu = this_cpu;
+
+ if (recursion_bug) {
+@@ -1628,6 +1641,7 @@ asmlinkage int vprintk_emit(int facility, int level,
+ if (console_trylock_for_printk(this_cpu))
+ console_unlock();
+
++out_restore_lockdep_irqs:
+ lockdep_on();
+ out_restore_irqs:
+ local_irq_restore(flags);
+diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
+index 0582a01..5546ae9 100644
+--- a/kernel/trace/trace.c
++++ b/kernel/trace/trace.c
+@@ -826,9 +826,12 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
+ if (isspace(ch)) {
+ parser->buffer[parser->idx] = 0;
+ parser->cont = false;
+- } else {
++ } else if (parser->idx < parser->size - 1) {
+ parser->cont = true;
+ parser->buffer[parser->idx++] = ch;
++ } else {
++ ret = -EINVAL;
++ goto out;
+ }
+
+ *ppos += read;
+diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c
+index d1ae869d..fc12d6e 100644
+--- a/sound/soc/codecs/sn95031.c
++++ b/sound/soc/codecs/sn95031.c
+@@ -30,7 +30,7 @@
+ #include <linux/slab.h>
+ #include <linux/module.h>
+
+-#include <asm/intel_scu_ipc.h>
++#include <asm/intel_scu_pmic.h>
+ #include <sound/pcm.h>
+ #include <sound/pcm_params.h>
+ #include <sound/soc.h>
+--
+1.8.3.2
+
diff --git a/meta-edison/recipes-kernel/linux/linux-yocto_3.10.bbappend b/meta-edison/recipes-kernel/linux/linux-yocto_3.10.bbappend
new file mode 100644
index 0000000..422c09d
--- /dev/null
+++ b/meta-edison/recipes-kernel/linux/linux-yocto_3.10.bbappend
@@ -0,0 +1,8 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
+COMPATIBLE_MACHINE = "edison"
+LINUX_VERSION = "3.10.17"
+SRCREV_machine = "c03195ed6e3066494e3fb4be69154a57066e845b"
+SRCREV_meta = "6ad20f049abd52b515a8e0a4664861cfd331f684"
+
+SRC_URI += "file://defconfig"
+SRC_URI += "file://upstream_to_edison.patch"
diff --git a/meta-mingw/conf/layer.conf b/meta-mingw/conf/layer.conf
new file mode 100644
index 0000000..fdb5eab
--- /dev/null
+++ b/meta-mingw/conf/layer.conf
@@ -0,0 +1,5 @@
+# We have a conf and classes directory, add to BBPATH
+BBPATH := "${BBPATH}:${LAYERDIR}"
+
+# We have a packages directory, add to BBFILES
+BBFILES += "${LAYERDIR}/recipes*/*/*.bb ${LAYERDIR}/recipes*/*/*.bbappend"
diff --git a/meta-mingw/recipes-devtools/pthreads-win32/pthreads-win32_2.9.1.bbappend b/meta-mingw/recipes-devtools/pthreads-win32/pthreads-win32_2.9.1.bbappend
new file mode 100644
index 0000000..523d4a7
--- /dev/null
+++ b/meta-mingw/recipes-devtools/pthreads-win32/pthreads-win32_2.9.1.bbappend
@@ -0,0 +1 @@
+SRC_URI = "http://mirrors.kernel.org/sourceware/pthreads-win32/pthreads-w32-${PVdash}-release.tar.gz"
diff --git a/setup.sh b/setup.sh
new file mode 100755
index 0000000..9d89394
--- /dev/null
+++ b/setup.sh
@@ -0,0 +1,300 @@
+#!/bin/bash
+
+# Copyright(c) 2013 Intel Corporation. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+# fabien.chereau@intel.com
+
+set -e
+
+do_local_conf () {
+ cat > $yocto_conf_dir/local.conf <<EOF
+BB_NUMBER_THREADS = "$my_bb_number_thread"
+PARALLEL_MAKE = "-j $my_parallel_make"
+MACHINE = "edison"
+DISTRO = "poky-edison"
+USER_CLASSES ?= "buildstats image-mklibs image-prelink"
+PATCHRESOLVE = "noop"
+CONF_VERSION = "1"
+EDISONREPO_TOP_DIR = "$top_repo_dir"
+DL_DIR ?= "$my_dl_dir"
+SSTATE_DIR ?= "$my_sstate_dir"
+BUILDNAME = "$my_build_name"
+LICENSE_FLAGS_WHITELIST += "commercial"
+COPY_LIC_MANIFEST = "1"
+COPY_LIC_DIRS = "1"
+FILESYSTEM_PERMS_TABLES = "$top_repo_dir/device-software/meta-edison-distro/files/fs-perms.txt"
+$extra_package_type
+$extra_archiving
+$extra_conf
+EOF
+}
+
+do_append_layer (){
+ if [[ $extra_layers == \\ ]]; then
+ extra_layers="$1 \\"
+ else
+ extra_layers+=$'\n'
+ extra_layers+=" $1 \\"
+ fi
+}
+
+extra_layers="\\"
+
+do_bblayers_conf () {
+ cat > $yocto_conf_dir/bblayers.conf <<EOF
+# LAYER_CONF_VERSION is increased each time build/conf/bblayers.conf
+# changes incompatibly
+LCONF_VERSION = "6"
+
+BBPATH = "\${TOPDIR}"
+BBFILES ?= ""
+BBLAYERS ?= " \\
+ $poky_dir/meta \\
+ $poky_dir/meta-yocto \\
+ $poky_dir/meta-yocto-bsp \\
+ $top_repo_dir/device-software/meta-edison \\
+ $top_repo_dir/device-software/meta-edison-distro \\
+ $top_repo_dir/device-software/meta-edison-middleware \\
+ $top_repo_dir/device-software/meta-edison-arduino \\
+ $top_repo_dir/device-software/meta-edison-devtools \\
+ $extra_layers
+ "
+BBLAYERS_NON_REMOVABLE ?= " \\
+ $poky_dir/meta \\
+ $poky_dir/meta-yocto \\
+ "
+EOF
+}
+
+function check_path()
+{
+ if [ "${VALUE:0:1}" = "~" ]; then
+ echo "ERROR: '~' not allowed in directory path"
+ usage
+ exit 1
+ fi
+ if [ ! -d "$VALUE" ]; then
+ echo "ERROR: '$VALUE' directory does not exist"
+ usage
+ exit 1
+ fi
+}
+
+function usage()
+{
+ echo "Setup build environment for building the Edison Device Software"
+ echo ""
+ echo "./setup.sh"
+ echo -e "\t-h --help\t\t\tdisplay this help and exit"
+ echo -e "\t--dl_dir=$my_dl_dir\tdefine the directory (absolute path) where bitbake places downloaded files"
+ echo -e "\t--sstate_dir=$my_sstate_dir\tdefine the directory (absolute path) where bitbake places shared-state files"
+ echo -e "\t--bb_number_thread=$my_bb_number_thread\t\tdefine how many tasks bitbake should run in parallel"
+ echo -e "\t--parallel_make=$my_parallel_make\t\tdefine how many processes make should run in parallel when running compile tasks"
+ echo -e "\t--mode=$my_mode\t\t\tdefine whether we are working in development mode, i.e. with local version of the yocto recipes. Possible values are 'devenv' for setupping a development environment and 'external' for a regular build."
+ echo -e "\t--build_name=$my_build_name\t\tdefines custom build name which can then be retrieved on a running linux in /etc/version"
+ echo -e "\t--sdk_host=$my_sdk_host\t\tchoose host machine on which the generated SDK and cross compiler will be run. Must be one of [$all_sdk_hosts]"
+ echo -e "\t-l --list_sdk_hosts\t\tlist availables sdk host supported machines"
+ echo -e "\t--create_src_archive\t\twhen set, copies sources of all deployed packages into build/tmp/deploy/sources"
+ echo -e "\t--deb_packages\t\twhen set, use .deb package format instead of .ipk"
+ echo ""
+}
+
+main() {
+ top_repo_dir=$(dirname $(dirname $(readlink -f $0)))
+ my_build_dir=$top_repo_dir
+ my_dl_dir="\${TOPDIR}/downloads"
+ my_sstate_dir="\${TOPDIR}/sstate-cache"
+ my_bb_number_thread=4
+ my_parallel_make=4
+ my_build_name="Custom Edison build by $USER@$HOSTNAME "$(date +"%F %H:%M:%S %Z")
+ all_sdk_hosts="linux32 linux64 win32 win64 macosx"
+ extra_package_type=""
+
+ #probe my_sdk_host from uname
+ plat=$(uname -s | tr '[:upper:]' '[:lower:]')
+ arch=$(uname -m)
+ case "$arch" in
+ i?86) arch="32" ;;
+ x86_64) arch="64" ;;
+ *) arch="unknow" ;;
+ esac
+ my_sdk_host="$plat$arch"
+
+ my_mode="external"
+ if [ -d "$top_repo_dir/linux-kernel" ]; then
+ my_mode="devenv"
+ fi
+
+ while [ "$1" != "" ]; do
+ PARAM=`echo $1 | awk -F= '{print $1}'`
+ VALUE=`echo $1 | awk -F= '{print $2}'`
+ case $PARAM in
+ -h | --help)
+ usage
+ exit
+ ;;
+ --create_src_archive)
+ extra_archiving="INHERIT += \"archiver\"
+ARCHIVER_MODE[src] = \"original\"
+COPYLEFT_LICENSE_INCLUDE = 'GPL* LGPL*'
+"
+ ;;
+ --deb_packages)
+ extra_package_type="PACKAGE_CLASSES = \"package_deb\""
+ ;;
+ --dl_dir)
+ check_path
+ my_dl_dir=$(readlink -f "$VALUE")
+ ;;
+ --sstate_dir)
+ check_path
+ my_sstate_dir=$(readlink -f "$VALUE")
+ ;;
+ --bb_number_thread)
+ my_bb_number_thread=$VALUE
+ ;;
+ --parallel_make)
+ my_parallel_make=$VALUE
+ ;;
+ --mode)
+ my_mode=$VALUE
+ ;;
+ --build_name)
+ my_build_name=$VALUE
+ ;;
+ --build_dir)
+ my_build_dir=$VALUE
+ ;;
+ -l | --list_sdk_hosts)
+ echo $all_sdk_hosts
+ exit
+ ;;
+ --sdk_host)
+ my_sdk_host=$VALUE
+ ;;
+ *)
+ echo "ERROR: unknown parameter \"$PARAM\""
+ usage
+ exit 1
+ ;;
+ esac
+ shift
+ done
+
+ # Validate setup mode, can be devenv or external
+ if [ "$my_mode" = "devenv" ]
+ then
+ echo "We are building in devenv mode, i.e. with dependency on teamforge internal servers"
+ echo "and yocto recipes assuming local sources for some package."
+ echo "You can change this by passing the --mode=external option to this script."
+ do_append_layer $top_repo_dir/device-software/meta-edison-devenv
+ else
+ if [ "$my_mode" = "external" ]
+ then
+ echo "We are building in external mode"
+ else
+ echo "Invalid mode, can be external or devenv. Default to external excepted if the linux-kernel"
+ echo "directory is present, in which case a developer environment is assumed."
+ fi
+ fi
+
+ case $my_sdk_host in
+ win32)
+ extra_conf="SDKMACHINE = \"i686-mingw32\""
+ ;;
+ win64)
+ extra_conf="SDKMACHINE = \"x86_64-mingw32\""
+ ;;
+ macosx)
+ extra_conf="SDKMACHINE = \"i386-darwin\""
+ ;;
+ linux32)
+ extra_conf="SDKMACHINE = \"i686\""
+ ;;
+ linux64)
+ extra_conf="SDKMACHINE = \"x86_64\""
+ ;;
+ *)
+ echo "Unknow host: $my_sdk_host chooses one in [$all_sdk_hosts]"
+ exit
+ ;;
+ esac
+
+ poky_dir=$my_build_dir/poky
+
+ # Re-create the poky dir from archive
+ echo "Extracting upstream Yocto tools in the $poky_dir directory from archive"
+ rm -rf $poky_dir
+ tar -xjf $top_repo_dir/device-software/utils/poky-daisy-11.0.1.tar.bz2
+ mv poky-daisy-11.0.1 $poky_dir
+
+ # Apply patch on top of it allowing to perform build in external source directory
+ #echo "Applying patch on it"
+ cd $poky_dir
+ git apply $top_repo_dir/device-software/utils/0001-kernel-kernel-yocto-fix-external-src-builds-when-S-B-poky-dora.patch
+ git apply $top_repo_dir/device-software/utils/sdk-populate-clean-broken-links.patch
+ git apply --whitespace=nowarn $top_repo_dir/device-software/utils/0001-bash-fix-CVE-2014-6271.patch
+ git apply --whitespace=nowarn $top_repo_dir/device-software/utils/0002-bash-Fix-CVE-2014-7169.patch
+ git apply $top_repo_dir/device-software/utils/0001-libarchive-avoid-dependency-on-e2fsprogs.patch
+ git apply --whitespace=nowarn $top_repo_dir/device-software/utils/0001-busybox-handle-syslog-related-files-properly.patch
+ git apply $top_repo_dir/device-software/utils/0001-openssh-avoid-screen-sessions-being-killed-on-discon.patch
+ git apply $top_repo_dir/device-software/utils/handle_bash_func.patch
+
+ mingw_dir=$poky_dir/meta-mingw
+ echo "Unpacking Mingw layer to poky/meta-mingw/ directory from archive"
+ mkdir -p $mingw_dir
+ ( cd $mingw_dir && tar -xjf $top_repo_dir/device-software/utils/mingw-daisy.tar.bz2)
+
+ darwin_dir=$poky_dir/meta-darwin
+ echo "Unpacking Darwin layer to poky/meta-darwin/ directory from archive"
+ mkdir -p $darwin_dir
+ ( cd $darwin_dir && tar -xjf $top_repo_dir/device-software/utils/darwin-daisy.tar.bz2)
+
+ if [[ $my_sdk_host == win* ]]
+ then
+ do_append_layer $top_repo_dir/device-software/meta-mingw
+ do_append_layer $mingw_dir
+ fi
+
+ if [[ $my_sdk_host == macosx ]]
+ then
+ do_append_layer $darwin_dir
+ fi
+
+ echo "Initializing yocto build environment"
+ source oe-init-build-env $my_build_dir/build > /dev/null
+
+ yocto_conf_dir=$my_build_dir/build/conf
+
+ echo "Setting up yocto configuration file (in build/conf/local.conf)"
+ do_bblayers_conf
+ do_local_conf
+
+ echo "** Success **"
+ echo "SDK will be generated for $my_sdk_host host"
+ echo "Now run these two commands to setup and build the flashable image:"
+ echo "cd $my_build_dir"
+ echo "source poky/oe-init-build-env"
+ echo "bitbake edison-image"
+ echo "*************"
+}
+
+main "$@"
diff --git a/utils/0001-bash-fix-CVE-2014-6271.patch b/utils/0001-bash-fix-CVE-2014-6271.patch
new file mode 100644
index 0000000..93dc307
--- /dev/null
+++ b/utils/0001-bash-fix-CVE-2014-6271.patch
@@ -0,0 +1,254 @@
+From 215e7b98ae4865b0f24b1cb9c53161fef170b270 Mon Sep 17 00:00:00 2001
+From: Ross Burton <ross.burton@intel.com>
+Date: Fri, 26 Sep 2014 00:05:18 +0100
+Subject: [PATCH] bash: fix CVE-2014-6271
+
+CVE-2014-6271 aka ShellShock.
+
+"GNU Bash through 4.3 processes trailing strings after function definitions in
+the values of environment variables, which allows remote attackers to execute
+arbitrary code via a crafted environment."
+
+(From OE-Core rev: 798d833c9d4bd9ab287fa86b85b4d5f128170ed3)
+
+Signed-off-by: Ross Burton <ross.burton@intel.com>
+Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
+---
+ .../bash/bash-3.2.48/cve-2014-6271.patch | 77 +++++++++++++
+ .../recipes-extended/bash/bash/cve-2014-6271.patch | 114 ++++++++++++++++++++
+ meta/recipes-extended/bash/bash_3.2.48.bb | 1 +
+ meta/recipes-extended/bash/bash_4.3.bb | 1 +
+ 4 files changed, 193 insertions(+)
+ create mode 100644 meta/recipes-extended/bash/bash-3.2.48/cve-2014-6271.patch
+ create mode 100644 meta/recipes-extended/bash/bash/cve-2014-6271.patch
+
+diff --git a/meta/recipes-extended/bash/bash-3.2.48/cve-2014-6271.patch b/meta/recipes-extended/bash/bash-3.2.48/cve-2014-6271.patch
+new file mode 100644
+index 0000000..7226ffb
+--- /dev/null
++++ b/meta/recipes-extended/bash/bash-3.2.48/cve-2014-6271.patch
+@@ -0,0 +1,77 @@
++Fix CVE-2014-6271, aka ShellShock.
++
++Upstream-Status: Backport
++Signed-off-by: Ross Burton <ross.burton@intel.com>
++
++*** ../bash-3.2.51/builtins/common.h 2006-03-06 09:38:44.000000000 -0500
++--- builtins/common.h 2014-09-16 19:08:02.000000000 -0400
++***************
++*** 34,37 ****
++--- 34,39 ----
++
++ /* Flags for describe_command, shared between type.def and command.def */
+++ #define SEVAL_FUNCDEF 0x080 /* only allow function definitions */
+++ #define SEVAL_ONECMD 0x100 /* only allow a single command */
++ #define CDESC_ALL 0x001 /* type -a */
++ #define CDESC_SHORTDESC 0x002 /* command -V */
++*** ../bash-3.2.51/builtins/evalstring.c 2008-11-15 17:47:04.000000000 -0500
++--- builtins/evalstring.c 2014-09-16 19:08:02.000000000 -0400
++***************
++*** 235,238 ****
++--- 235,246 ----
++ struct fd_bitmap *bitmap;
++
+++ if ((flags & SEVAL_FUNCDEF) && command->type != cm_function_def)
+++ {
+++ internal_warning ("%s: ignoring function definition attempt", from_file);
+++ should_jump_to_top_level = 0;
+++ last_result = last_command_exit_value = EX_BADUSAGE;
+++ break;
+++ }
+++
++ bitmap = new_fd_bitmap (FD_BITMAP_SIZE);
++ begin_unwind_frame ("pe_dispose");
++***************
++*** 292,295 ****
++--- 300,306 ----
++ dispose_fd_bitmap (bitmap);
++ discard_unwind_frame ("pe_dispose");
+++
+++ if (flags & SEVAL_ONECMD)
+++ break;
++ }
++ }
++*** ../bash-3.2.51/variables.c 2008-11-15 17:15:06.000000000 -0500
++--- variables.c 2014-09-16 19:10:39.000000000 -0400
++***************
++*** 319,328 ****
++ strcpy (temp_string + char_index + 1, string);
++
++! parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST);
++!
++! /* Ancient backwards compatibility. Old versions of bash exported
++! functions like name()=() {...} */
++! if (name[char_index - 1] == ')' && name[char_index - 2] == '(')
++! name[char_index - 2] = '\0';
++
++ if (temp_var = find_function (name))
++--- 319,326 ----
++ strcpy (temp_string + char_index + 1, string);
++
++! /* Don't import function names that are invalid identifiers from the
++! environment. */
++! if (legal_identifier (name))
++! parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
++
++ if (temp_var = find_function (name))
++***************
++*** 333,340 ****
++ else
++ report_error (_("error importing function definition for `%s'"), name);
++-
++- /* ( */
++- if (name[char_index - 1] == ')' && name[char_index - 2] == '\0')
++- name[char_index - 2] = '('; /* ) */
++ }
++ #if defined (ARRAY_VARS)
++--- 331,334 ----
+diff --git a/meta/recipes-extended/bash/bash/cve-2014-6271.patch b/meta/recipes-extended/bash/bash/cve-2014-6271.patch
+new file mode 100644
+index 0000000..d33a5c8
+--- /dev/null
++++ b/meta/recipes-extended/bash/bash/cve-2014-6271.patch
+@@ -0,0 +1,114 @@
++Fix CVE-2014-6271, aka ShellShock. This is the upstream 4.3 patchlevel 25, minus the hunk to
++set the patch level.
++
++Upstream-Status: Backport
++Signed-off-by: Ross Burton <ross.burton@intel.com>
++
++ BASH PATCH REPORT
++ =================
++
++Bash-Release: 4.3
++Patch-ID: bash43-025
++
++Bug-Reported-by: Stephane Chazelas <stephane.chazelas@gmail.com>
++Bug-Reference-ID:
++Bug-Reference-URL:
++
++Bug-Description:
++
++Under certain circumstances, bash will execute user code while processing the
++environment for exported function definitions.
++
++Patch (apply with `patch -p0'):
++
++*** ../bash-4.3-patched/builtins/common.h 2013-07-08 16:54:47.000000000 -0400
++--- builtins/common.h 2014-09-12 14:25:47.000000000 -0400
++***************
++*** 34,37 ****
++--- 49,54 ----
++ #define SEVAL_PARSEONLY 0x020
++ #define SEVAL_NOLONGJMP 0x040
+++ #define SEVAL_FUNCDEF 0x080 /* only allow function definitions */
+++ #define SEVAL_ONECMD 0x100 /* only allow a single command */
++
++ /* Flags for describe_command, shared between type.def and command.def */
++*** ../bash-4.3-patched/builtins/evalstring.c 2014-02-11 09:42:10.000000000 -0500
++--- builtins/evalstring.c 2014-09-14 14:15:13.000000000 -0400
++***************
++*** 309,312 ****
++--- 313,324 ----
++ struct fd_bitmap *bitmap;
++
+++ if ((flags & SEVAL_FUNCDEF) && command->type != cm_function_def)
+++ {
+++ internal_warning ("%s: ignoring function definition attempt", from_file);
+++ should_jump_to_top_level = 0;
+++ last_result = last_command_exit_value = EX_BADUSAGE;
+++ break;
+++ }
+++
++ bitmap = new_fd_bitmap (FD_BITMAP_SIZE);
++ begin_unwind_frame ("pe_dispose");
++***************
++*** 369,372 ****
++--- 381,387 ----
++ dispose_fd_bitmap (bitmap);
++ discard_unwind_frame ("pe_dispose");
+++
+++ if (flags & SEVAL_ONECMD)
+++ break;
++ }
++ }
++*** ../bash-4.3-patched/variables.c 2014-05-15 08:26:50.000000000 -0400
++--- variables.c 2014-09-14 14:23:35.000000000 -0400
++***************
++*** 359,369 ****
++ strcpy (temp_string + char_index + 1, string);
++
++! if (posixly_correct == 0 || legal_identifier (name))
++! parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST);
++!
++! /* Ancient backwards compatibility. Old versions of bash exported
++! functions like name()=() {...} */
++! if (name[char_index - 1] == ')' && name[char_index - 2] == '(')
++! name[char_index - 2] = '\0';
++
++ if (temp_var = find_function (name))
++--- 364,372 ----
++ strcpy (temp_string + char_index + 1, string);
++
++! /* Don't import function names that are invalid identifiers from the
++! environment, though we still allow them to be defined as shell
++! variables. */
++! if (legal_identifier (name))
++! parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
++
++ if (temp_var = find_function (name))
++***************
++*** 382,389 ****
++ report_error (_("error importing function definition for `%s'"), name);
++ }
++-
++- /* ( */
++- if (name[char_index - 1] == ')' && name[char_index - 2] == '\0')
++- name[char_index - 2] = '('; /* ) */
++ }
++ #if defined (ARRAY_VARS)
++--- 385,388 ----
++*** ../bash-4.3-patched/subst.c 2014-08-11 11:16:35.000000000 -0400
++--- subst.c 2014-09-12 15:31:04.000000000 -0400
++***************
++*** 8048,8052 ****
++ goto return0;
++ }
++! else if (var = find_variable_last_nameref (temp1))
++ {
++ temp = nameref_cell (var);
++--- 8118,8124 ----
++ goto return0;
++ }
++! else if (var && (invisible_p (var) || var_isset (var) == 0))
++! temp = (char *)NULL;
++! else if ((var = find_variable_last_nameref (temp1)) && var_isset (var) && invisible_p (var) == 0)
++ {
++ temp = nameref_cell (var);
+diff --git a/meta/recipes-extended/bash/bash_3.2.48.bb b/meta/recipes-extended/bash/bash_3.2.48.bb
+index fe04b28..5849ed0 100644
+--- a/meta/recipes-extended/bash/bash_3.2.48.bb
++++ b/meta/recipes-extended/bash/bash_3.2.48.bb
+@@ -12,6 +12,7 @@ SRC_URI = "${GNU_MIRROR}/bash/bash-${PV}.tar.gz;name=tarball \
+ file://mkbuiltins_have_stringize.patch \
+ file://build-tests.patch \
+ file://test-output.patch \
++ file://cve-2014-6271.patch;striplevel=0 \
+ file://run-ptest \
+ "
+
+diff --git a/meta/recipes-extended/bash/bash_4.3.bb b/meta/recipes-extended/bash/bash_4.3.bb
+index 25b7410..febaf33 100644
+--- a/meta/recipes-extended/bash/bash_4.3.bb
++++ b/meta/recipes-extended/bash/bash_4.3.bb
+@@ -9,6 +9,7 @@ SRC_URI = "${GNU_MIRROR}/bash/${BPN}-${PV}.tar.gz;name=tarball \
+ file://mkbuiltins_have_stringize.patch \
+ file://build-tests.patch \
+ file://test-output.patch \
++ file://cve-2014-6271.patch;striplevel=0 \
+ file://run-ptest \
+ "
+
+--
+1.7.9.5
+
diff --git a/utils/0001-busybox-handle-syslog-related-files-properly.patch b/utils/0001-busybox-handle-syslog-related-files-properly.patch
new file mode 100644
index 0000000..4ce90ef
--- /dev/null
+++ b/utils/0001-busybox-handle-syslog-related-files-properly.patch
@@ -0,0 +1,74 @@
+From 5d6ffdc47565cb7405edabcf8cb8ba1fe3c84f31 Mon Sep 17 00:00:00 2001
+From: Chen Qi <Qi.Chen@windriver.com>
+Date: Fri, 13 Jun 2014 13:42:33 +0800
+Subject: [PATCH] busybox: handle syslog related files properly
+
+If CONFIG_SYSLOGD is not enabled, then the related service file should
+not be installed as it will always fail at system start-up. The error
+message is as following.
+
+ [FAILED] Failed to start System Logging Service.
+
+The same logic applies to CONFIG_KLOGD.
+
+So we should first check the configuration before we install these
+service files.
+
+[YOCTO #5302]
+
+(From OE-Core rev: b44e291a87539fbb8e6da1a16c56f425a417e7bd)
+
+Signed-off-by: Chen Qi <Qi.Chen@windriver.com>
+Signed-off-by: Saul Wold <sgw@linux.intel.com>
+Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
+---
+ meta/recipes-core/busybox/busybox.inc | 25 ++++++++++++++-----------
+ 1 file changed, 14 insertions(+), 14 deletions(-)
+
+diff --git a/meta/recipes-core/busybox/busybox.inc b/meta/recipes-core/busybox/busybox.inc
+index f6cb039..bd66e4f 100644
+--- a/meta/recipes-core/busybox/busybox.inc
++++ b/meta/recipes-core/busybox/busybox.inc
+@@ -40,6 +40,3 @@
+ INITSCRIPT_NAME_${PN}-udhcpd = "busybox-udhcpd"
+
+-SYSTEMD_PACKAGES = "${PN}-syslog"
+-SYSTEMD_SERVICE_${PN}-syslog = "busybox-syslog.service"
+-
+ CONFFILES_${PN}-syslog = "${sysconfdir}/syslog-startup.conf.${BPN}"
+@@ -274,18 +274,21 @@ do_install () {
+ fi
+
+ if ${@base_contains('DISTRO_FEATURES','systemd','true','false',d)}; then
+- install -d ${D}${systemd_unitdir}/system
+- sed 's,@base_sbindir@,${base_sbindir},g' < ${WORKDIR}/busybox-syslog.service.in \
+- > ${D}${systemd_unitdir}/system/busybox-syslog.service
+- sed 's,@base_sbindir@,${base_sbindir},g' < ${WORKDIR}/busybox-klogd.service.in \
+- > ${D}${systemd_unitdir}/system/busybox-klogd.service
+-
+- if [ -f ${WORKDIR}/busybox-syslog.default ] ; then
+- install -d ${D}${sysconfdir}/default
+- install -m 0644 ${WORKDIR}/busybox-syslog.default ${D}${sysconfdir}/default/busybox-syslog
++ if grep -q "CONFIG_SYSLOGD=y" ${B}/.config; then
++ install -d ${D}${systemd_unitdir}/system
++ sed 's,@base_sbindir@,${base_sbindir},g' < ${WORKDIR}/busybox-syslog.service.in \
++ > ${D}${systemd_unitdir}/system/busybox-syslog.service
++ if [ -f ${WORKDIR}/busybox-syslog.default ] ; then
++ install -d ${D}${sysconfdir}/default
++ install -m 0644 ${WORKDIR}/busybox-syslog.default ${D}${sysconfdir}/default/busybox-syslog
++ fi
++ ln -sf /dev/null ${D}${systemd_unitdir}/system/syslog.service
++ fi
++ if grep -q "CONFIG_KLOGD=y" ${B}/.config; then
++ install -d ${D}${systemd_unitdir}/system
++ sed 's,@base_sbindir@,${base_sbindir},g' < ${WORKDIR}/busybox-klogd.service.in \
++ > ${D}${systemd_unitdir}/system/busybox-klogd.service
+ fi
+-
+- ln -sf /dev/null ${D}${systemd_unitdir}/system/syslog.service
+ fi
+
+ # Remove the sysvinit specific configuration file for systemd systems to avoid confusion
+--
+1.7.9.5
+
diff --git a/utils/0001-kernel-kernel-yocto-fix-external-src-builds-when-S-B-poky-dora.patch b/utils/0001-kernel-kernel-yocto-fix-external-src-builds-when-S-B-poky-dora.patch
new file mode 100644
index 0000000..1b62161
--- /dev/null
+++ b/utils/0001-kernel-kernel-yocto-fix-external-src-builds-when-S-B-poky-dora.patch
@@ -0,0 +1,170 @@
+From 3bb54b908b10ef4b225dcdbfb40c8cdc2d1c2db1 Mon Sep 17 00:00:00 2001
+From: Fabien Chereau <fabien.chereau@intel.com>
+Date: Thu, 22 May 2014 17:15:01 +0200
+Subject: [PATCH] kernel/kernel-yocto: fix external src builds when S != B
+
+Based on the original patch from Khem Raj, modified by Bruce Ashfield.
+
+When inheriting kernel.bbclass (and not kernel-yocto.bbclass), externalsrc
+builds were broken when S != B for the kernel.
+Additional fixes make sure that we do not assume directory paths when
+accessing files.
+
+[YOCTO: #5992]
+
+Signed-off-by: Khem Raj <raj.khem@gmail.com>
+Signed-off-by: Bruce Ashfield <bruce.ashfield@windriver.com>
+Signed-off-by: Fabien Chereau <fabien.chereau@intel.com>
+Signed-off-by: Simon Desfarges <simonx.desfarges@intel.com>
+---
+ meta/classes/kernel.bbclass | 63 +++++++++++++++++++++++++--------------------
+ 1 file changed, 35 insertions(+), 28 deletions(-)
+
+diff --git a/meta/classes/kernel.bbclass b/meta/classes/kernel.bbclass
+index 19b159b..8914f04 100644
+--- a/meta/classes/kernel.bbclass
++++ b/meta/classes/kernel.bbclass
+@@ -157,6 +157,7 @@ kernel_do_compile() {
+ # different initramfs image. The way to do that in the kernel
+ # is to specify:
+ # make ...args... CONFIG_INITRAMFS_SOURCE=some_other_initramfs.cpio
++ cd ${S}
+ if [ "$use_alternate_initrd" = "" ] && [ "${INITRAMFS_TASK}" != "" ] ; then
+ # The old style way of copying an prebuilt image and building it
+ # is turned on via INTIRAMFS_TASK != ""
+@@ -165,7 +166,7 @@ kernel_do_compile() {
+ fi
+ oe_runmake ${KERNEL_IMAGETYPE_FOR_MAKE} ${KERNEL_ALT_IMAGETYPE} CC="${KERNEL_CC}" LD="${KERNEL_LD}" ${KERNEL_EXTRA_ARGS} $use_alternate_initrd
+ if test "${KERNEL_IMAGETYPE_FOR_MAKE}.gz" = "${KERNEL_IMAGETYPE}"; then
+- gzip -9c < "${KERNEL_IMAGETYPE_FOR_MAKE}" > "${KERNEL_OUTPUT}"
++ gzip -9c < "${B}/${KERNEL_IMAGETYPE_FOR_MAKE}" > "${KERNEL_OUTPUT}"
+ fi
+ }
+
+@@ -199,11 +200,11 @@ kernel_do_install() {
+ #
+ install -d ${D}/${KERNEL_IMAGEDEST}
+ install -d ${D}/boot
+- install -m 0644 ${KERNEL_OUTPUT} ${D}/${KERNEL_IMAGEDEST}/${KERNEL_IMAGETYPE}-${KERNEL_VERSION}
+- install -m 0644 System.map ${D}/boot/System.map-${KERNEL_VERSION}
+- install -m 0644 .config ${D}/boot/config-${KERNEL_VERSION}
+- install -m 0644 vmlinux ${D}/boot/vmlinux-${KERNEL_VERSION}
+- [ -e Module.symvers ] && install -m 0644 Module.symvers ${D}/boot/Module.symvers-${KERNEL_VERSION}
++ install -m 0644 ${B}/${KERNEL_OUTPUT} ${D}/${KERNEL_IMAGEDEST}/${KERNEL_IMAGETYPE}-${KERNEL_VERSION}
++ install -m 0644 ${B}/System.map ${D}/boot/System.map-${KERNEL_VERSION}
++ install -m 0644 ${B}/.config ${D}/boot/config-${KERNEL_VERSION}
++ install -m 0644 ${B}/vmlinux ${D}/boot/vmlinux-${KERNEL_VERSION}
++ [ -e ${B}/Module.symvers ] && install -m 0644 ${B}/Module.symvers ${D}/boot/Module.symvers-${KERNEL_VERSION}
+ install -d ${D}${sysconfdir}/modules-load.d
+ install -d ${D}${sysconfdir}/modprobe.d
+
+@@ -232,20 +233,22 @@ kernel_do_install() {
+ # dir. This ensures the original Makefiles are used and not the
+ # redirecting Makefiles in the build directory.
+ #
++ pwd="$PWD"
++ cd "${B}"
+ find . -depth -not -name "*.cmd" -not -name "*.o" -not -path "./Documentation*" -not -path "./source*" -not -path "./.*" -print0 | cpio --null -pdlu $kerneldir
+- cp .config $kerneldir
++ cp ${B}/.config $kerneldir
+ if [ "${S}" != "${B}" ]; then
+- pwd="$PWD"
+ cd "${S}"
+ find . -depth -not -path "./Documentation*" -not -path "./.*" -print0 | cpio --null -pdlu $kerneldir
+- cd "$pwd"
+ fi
+
++ cd "$pwd"
++
+ # Test to ensure that the output file and image type are not actually
+ # the same file. If hardlinking is used, they will be the same, and there's
+ # no need to install.
+- ! [ ${KERNEL_OUTPUT} -ef $kerneldir/${KERNEL_IMAGETYPE} ] && install -m 0644 ${KERNEL_OUTPUT} $kerneldir/${KERNEL_IMAGETYPE}
+- install -m 0644 System.map $kerneldir/System.map-${KERNEL_VERSION}
++ ! [ ${B}/${KERNEL_OUTPUT} -ef $kerneldir/${KERNEL_IMAGETYPE} ] && install -m 0644 ${B}/${KERNEL_OUTPUT} $kerneldir/${KERNEL_IMAGETYPE}
++ install -m 0644 ${B}/System.map $kerneldir/System.map-${KERNEL_VERSION}
+
+ # Dummy Makefile so the clean below works
+ mkdir $kerneldir/Documentation
+@@ -260,7 +263,9 @@ kernel_do_install() {
+ # we clean the scripts dir while leaving the generated config
+ # and include files.
+ #
+- oe_runmake -C $kerneldir CC="${KERNEL_CC}" LD="${KERNEL_LD}" clean _mrproper_scripts
++ # Note: we clear KBUILD_OUTPUT to ensure we operate on the right kernel source
++ # since it overrides -C to make.
++ KBUILD_OUTPUT="" oe_runmake -C $kerneldir CC="${KERNEL_CC}" LD="${KERNEL_LD}" clean _mrproper_scripts
+
+ # hide directories that shouldn't have their .c, s and S files deleted
+ for d in tools scripts lib; do
+@@ -280,16 +285,16 @@ kernel_do_install() {
+ # arch/powerpc/lib/crtsavres.o which is present in
+ # KBUILD_LDFLAGS_MODULE, making it required to build external modules.
+ if [ ${ARCH} = "powerpc" ]; then
+- cp -l arch/powerpc/lib/crtsavres.o $kerneldir/arch/powerpc/lib/crtsavres.o
++ cp -l ${B}/arch/powerpc/lib/crtsavres.o $kerneldir/arch/powerpc/lib/crtsavres.o
+ fi
+
+ # Necessary for building modules like compat-wireless.
+- if [ -f include/generated/bounds.h ]; then
+- cp -l include/generated/bounds.h $kerneldir/include/generated/bounds.h
++ if [ -f ${B}/include/generated/bounds.h ]; then
++ cp -l ${B}/include/generated/bounds.h $kerneldir/include/generated/bounds.h
+ fi
+- if [ -d arch/${ARCH}/include/generated ]; then
++ if [ -d ${B}/arch/${ARCH}/include/generated ]; then
+ mkdir -p $kerneldir/arch/${ARCH}/include/generated/
+- cp -flR arch/${ARCH}/include/generated/* $kerneldir/arch/${ARCH}/include/generated/
++ cp -flR ${B}/arch/${ARCH}/include/generated/* $kerneldir/arch/${ARCH}/include/generated/
+ fi
+
+ # Remove the following binaries which cause strip or arch QA errors
+@@ -449,19 +454,19 @@ do_uboot_mkimage() {
+ if test "x${KEEPUIMAGE}" != "xyes" ; then
+ ENTRYPOINT=${UBOOT_ENTRYPOINT}
+ if test -n "${UBOOT_ENTRYSYMBOL}"; then
+- ENTRYPOINT=`${HOST_PREFIX}nm ${S}/vmlinux | \
++ ENTRYPOINT=`${HOST_PREFIX}nm ${B}/vmlinux | \
+ awk '$3=="${UBOOT_ENTRYSYMBOL}" {print $1}'`
+ fi
+- if test -e arch/${ARCH}/boot/compressed/vmlinux ; then
+- ${OBJCOPY} -O binary -R .note -R .comment -S arch/${ARCH}/boot/compressed/vmlinux linux.bin
+- uboot-mkimage -A ${UBOOT_ARCH} -O linux -T kernel -C none -a ${UBOOT_LOADADDRESS} -e $ENTRYPOINT -n "${DISTRO_NAME}/${PV}/${MACHINE}" -d linux.bin arch/${ARCH}/boot/uImage
++ if test -e ${B}/arch/${ARCH}/boot/compressed/vmlinux ; then
++ ${OBJCOPY} -O binary -R .note -R .comment -S ${B}/arch/${ARCH}/boot/compressed/vmlinux ${B}/linux.bin
++ uboot-mkimage -A ${UBOOT_ARCH} -O linux -T kernel -C none -a ${UBOOT_LOADADDRESS} -e $ENTRYPOINT -n "${DISTRO_NAME}/${PV}/${MACHINE}" -d ${B}/linux.bin ${B}/arch/${ARCH}/boot/uImage
+ rm -f linux.bin
+ else
+- ${OBJCOPY} -O binary -R .note -R .comment -S vmlinux linux.bin
+- rm -f linux.bin.gz
+- gzip -9 linux.bin
+- uboot-mkimage -A ${UBOOT_ARCH} -O linux -T kernel -C gzip -a ${UBOOT_LOADADDRESS} -e $ENTRYPOINT -n "${DISTRO_NAME}/${PV}/${MACHINE}" -d linux.bin.gz arch/${ARCH}/boot/uImage
+- rm -f linux.bin.gz
++ ${OBJCOPY} -O binary -R .note -R .comment -S ${B}/vmlinux ${B}/linux.bin
++ rm -f ${B}/linux.bin.gz
++ gzip -9 ${B}/linux.bin
++ uboot-mkimage -A ${UBOOT_ARCH} -O linux -T kernel -C gzip -a ${UBOOT_LOADADDRESS} -e $ENTRYPOINT -n "${DISTRO_NAME}/${PV}/${MACHINE}" -d ${B}/linux.bin.gz ${B}/arch/${ARCH}/boot/uImage
++ rm -f ${B}/linux.bin.gz
+ fi
+ fi
+ fi
+@@ -470,8 +475,8 @@ do_uboot_mkimage() {
+ addtask uboot_mkimage before do_install after do_compile
+
+ kernel_do_deploy() {
+- install -m 0644 ${KERNEL_OUTPUT} ${DEPLOYDIR}/${KERNEL_IMAGE_BASE_NAME}.bin
+- if [ ${MODULE_TARBALL_DEPLOY} = "1" ] && (grep -q -i -e '^CONFIG_MODULES=y$' .config); then
++ install -m 0644 ${D}/${KERNEL_IMAGEDEST}/${KERNEL_IMAGETYPE}-${KERNEL_VERSION} ${DEPLOYDIR}/${KERNEL_IMAGE_BASE_NAME}.bin
++ if [ ${MODULE_TARBALL_DEPLOY} = "1" ] && (grep -q -i -e '^CONFIG_MODULES=y$' ${B}/.config); then
+ mkdir -p ${D}/lib
+ tar -cvzf ${DEPLOYDIR}/${MODULE_TARBALL_BASE_NAME} -C ${D} lib
+ ln -sf ${MODULE_TARBALL_BASE_NAME} ${DEPLOYDIR}/${MODULE_TARBALL_SYMLINK_NAME}
+@@ -500,3 +505,5 @@ addtask deploy before do_build after do_install
+
+ EXPORT_FUNCTIONS do_deploy
+
++OE_TERMINAL_EXPORTS += "KBUILD_OUTPUT"
++export KBUILD_OUTPUT = "${B}"
+--
+1.8.3.2
+
diff --git a/utils/0001-libarchive-avoid-dependency-on-e2fsprogs.patch b/utils/0001-libarchive-avoid-dependency-on-e2fsprogs.patch
new file mode 100644
index 0000000..5bbe1f0
--- /dev/null
+++ b/utils/0001-libarchive-avoid-dependency-on-e2fsprogs.patch
@@ -0,0 +1,55 @@
+From f0b9a7cf9f80be1917e45266fa201f464a28c1e5 Mon Sep 17 00:00:00 2001
+From: Paul Eggleton <paul.eggleton@linux.intel.com>
+Date: Thu, 5 Jun 2014 10:46:16 +0100
+Subject: [PATCH] libarchive: avoid dependency on e2fsprogs
+
+libarchive's configure script looks for ext2fs/ext2_fs.h in order to use
+some defines for file attributes support if present (but doesn't link to
+any additional libraries.) There is no configure option to disable this,
+and if e2fsprogs is rebuilding between do_configure and do_compile you
+can currently get a failure. Because it doesn't need anything else from
+e2fsprogs, and e2fsprogs isn't currently buildable for nativesdk anyway,
+copy the headers in from e2fsprogs-native which we're likely to have
+built already (and add it to DEPENDS just to be sure we have.)
+
+Fixes [YOCTO #6268].
+
+(From OE-Core rev: ad754e46ad477acfbe7543187a5c38bc333b8612)
+
+Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
+Signed-off-by: Saul Wold <sgw@linux.intel.com>
+Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
+---
+ .../libarchive/libarchive_3.1.2.bb | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/meta/recipes-extended/libarchive/libarchive_3.1.2.bb b/meta/recipes-extended/libarchive/libarchive_3.1.2.bb
+index 3e6cdb4..2a2d0f9 100644
+--- a/meta/recipes-extended/libarchive/libarchive_3.1.2.bb
++++ b/meta/recipes-extended/libarchive/libarchive_3.1.2.bb
+@@ -5,6 +5,8 @@ SECTION = "devel"
+ LICENSE = "BSD"
+ LIC_FILES_CHKSUM = "file://COPYING;md5=b4e3ffd607d6686c6cb2f63394370841"
+
++DEPENDS = "e2fsprogs-native"
++
+ PACKAGECONFIG ?= "libxml2 zlib bz2"
+
+ PACKAGECONFIG_append_class-target = "\
+@@ -36,4 +38,13 @@ SRC_URI[sha256sum] = "eb87eacd8fe49e8d90c8fdc189813023ccc319c5e752b01fb6ad0cc7b2
+
+ inherit autotools-brokensep lib_package
+
++CPPFLAGS += "-I${WORKDIR}/extra-includes"
++
++do_configure[cleandirs] += "${WORKDIR}/extra-includes"
++do_configure_prepend() {
++ # We just need the headers for some type constants, so no need to
++ # build all of e2fsprogs for the target
++ cp -R ${STAGING_INCDIR_NATIVE}/ext2fs ${WORKDIR}/extra-includes/
++}
++
+ BBCLASSEXTEND = "native nativesdk"
+--
+1.7.9.5
+
diff --git a/utils/0001-openssh-avoid-screen-sessions-being-killed-on-discon.patch b/utils/0001-openssh-avoid-screen-sessions-being-killed-on-discon.patch
new file mode 100644
index 0000000..acc7162
--- /dev/null
+++ b/utils/0001-openssh-avoid-screen-sessions-being-killed-on-discon.patch
@@ -0,0 +1,36 @@
+From 6c576a4ac85307a5c851bee91a567cae3ea5a43b Mon Sep 17 00:00:00 2001
+From: Paul Eggleton <paul.eggleton@linux.intel.com>
+Date: Wed, 5 Nov 2014 21:08:51 -0800
+Subject: [PATCH] openssh: avoid screen sessions being killed on disconnect
+ with systemd
+
+Tell systemd just to kill the sshd process when the ssh connection drops
+instead of the entire cgroup for sshd, so that any screen sessions (and
+more to the point, processes within them) do not get killed.
+
+(This is what the Fedora sshd service file does, and what we're already
+doing in the dropbear service file).
+
+(From OE-Core master rev: 3c238dff41fbd3687457989c7b17d22b2cc844be)
+
+(From OE-Core rev: 6e6aeb7cca52b92a0c8013473e2b8bb18738a119)
+
+Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
+Signed-off-by: Ross Burton <ross.burton@intel.com>
+Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
+---
+ .../openssh/openssh/sshd@.service | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/meta/recipes-connectivity/openssh/openssh/sshd@.service b/meta/recipes-connectivity/openssh/openssh/sshd@.service
+index 4eda659..bb2d68e 100644
+--- a/meta/recipes-connectivity/openssh/openssh/sshd@.service
++++ b/meta/recipes-connectivity/openssh/openssh/sshd@.service
+@@ -8,3 +8,4 @@ ExecStart=-@SBINDIR@/sshd -i
+ ExecReload=@BASE_BINDIR@/kill -HUP $MAINPID
+ StandardInput=socket
+ StandardError=syslog
++KillMode=process
+--
+1.7.9.5
+
diff --git a/utils/0002-bash-Fix-CVE-2014-7169.patch b/utils/0002-bash-Fix-CVE-2014-7169.patch
new file mode 100644
index 0000000..683a2c7
--- /dev/null
+++ b/utils/0002-bash-Fix-CVE-2014-7169.patch
@@ -0,0 +1,93 @@
+From d6709b013364737bec7d59edd949db3891a6a8fa Mon Sep 17 00:00:00 2001
+From: Khem Raj <raj.khem@gmail.com>
+Date: Fri, 26 Sep 2014 13:21:19 -0700
+Subject: [PATCH] bash: Fix CVE-2014-7169
+
+This is a followup patch to incomplete CVE-2014-6271 fix
+code execution via specially-crafted environment
+
+Change-Id: Ibb0a587ee6e09b8174e92d005356e822ad40d4ed
+(From OE-Core rev: 76a2d6b83472995edbe967aed80f0fcbb784b3fc)
+
+Signed-off-by: Khem Raj <raj.khem@gmail.com>
+Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
+---
+ .../bash/bash-3.2.48/cve-2014-7169.patch | 16 ++++++++++++++++
+ .../recipes-extended/bash/bash/cve-2014-7169.patch | 16 ++++++++++++++++
+ meta/recipes-extended/bash/bash_3.2.48.bb | 1 +
+ meta/recipes-extended/bash/bash_4.3.bb | 1 +
+ 4 files changed, 34 insertions(+)
+ create mode 100644 meta/recipes-extended/bash/bash-3.2.48/cve-2014-7169.patch
+ create mode 100644 meta/recipes-extended/bash/bash/cve-2014-7169.patch
+
+diff --git a/meta/recipes-extended/bash/bash-3.2.48/cve-2014-7169.patch b/meta/recipes-extended/bash/bash-3.2.48/cve-2014-7169.patch
+new file mode 100644
+index 0000000..2e734de
+--- /dev/null
++++ b/meta/recipes-extended/bash/bash-3.2.48/cve-2014-7169.patch
+@@ -0,0 +1,16 @@
++Taken from http://www.openwall.com/lists/oss-security/2016/09/25/10
++
++Upstream-Status: Backport
++Index: bash-3.2.48/parse.y
++===================================================================
++--- bash-3.2.48.orig/parse.y 2008-04-29 18:24:55.000000000 -0700
+++++ bash-3.2.48/parse.y 2014-09-26 13:07:31.956080056 -0700
++@@ -2503,6 +2503,8 @@
++ FREE (word_desc_to_read);
++ word_desc_to_read = (WORD_DESC *)NULL;
++
+++ eol_ungetc_lookahead = 0;
+++
++ last_read_token = '\n';
++ token_to_read = '\n';
++ }
+diff --git a/meta/recipes-extended/bash/bash/cve-2014-7169.patch b/meta/recipes-extended/bash/bash/cve-2014-7169.patch
+new file mode 100644
+index 0000000..3c69121
+--- /dev/null
++++ b/meta/recipes-extended/bash/bash/cve-2014-7169.patch
+@@ -0,0 +1,16 @@
++Taken from http://www.openwall.com/lists/oss-security/2016/09/25/10
++
++Upstream-Status: Backport
++Index: bash-4.3/parse.y
++===================================================================
++--- bash-4.3.orig/parse.y 2014-09-26 13:10:44.340080056 -0700
+++++ bash-4.3/parse.y 2014-09-26 13:11:44.764080056 -0700
++@@ -2953,6 +2953,8 @@
++ FREE (word_desc_to_read);
++ word_desc_to_read = (WORD_DESC *)NULL;
++
+++ eol_ungetc_lookahead = 0;
+++
++ current_token = '\n'; /* XXX */
++ last_read_token = '\n';
++ token_to_read = '\n';
+diff --git a/meta/recipes-extended/bash/bash_3.2.48.bb b/meta/recipes-extended/bash/bash_3.2.48.bb
+index 5849ed0..e6a04cd 100644
+--- a/meta/recipes-extended/bash/bash_3.2.48.bb
++++ b/meta/recipes-extended/bash/bash_3.2.48.bb
+@@ -13,6 +13,7 @@ SRC_URI = "${GNU_MIRROR}/bash/bash-${PV}.tar.gz;name=tarball \
+ file://build-tests.patch \
+ file://test-output.patch \
+ file://cve-2014-6271.patch;striplevel=0 \
++ file://cve-2014-7169.patch \
+ file://run-ptest \
+ "
+
+diff --git a/meta/recipes-extended/bash/bash_4.3.bb b/meta/recipes-extended/bash/bash_4.3.bb
+index febaf33..69ddecc 100644
+--- a/meta/recipes-extended/bash/bash_4.3.bb
++++ b/meta/recipes-extended/bash/bash_4.3.bb
+@@ -10,6 +10,7 @@ SRC_URI = "${GNU_MIRROR}/bash/${BPN}-${PV}.tar.gz;name=tarball \
+ file://build-tests.patch \
+ file://test-output.patch \
+ file://cve-2014-6271.patch;striplevel=0 \
++ file://cve-2014-7169.patch \
+ file://run-ptest \
+ "
+
+--
+1.7.9.5
+
diff --git a/utils/Makefile.mk b/utils/Makefile.mk
new file mode 100644
index 0000000..674b962
--- /dev/null
+++ b/utils/Makefile.mk
@@ -0,0 +1,182 @@
+# Top level makefile, repo tool should create a link on this file at the root
+# of the build environement.
+
+.DEFAULT_GOAL := image
+
+# Parallelism is managed by bitbake for this project
+.NOTPARALLEL:
+
+# In this makefile, all targets are phony because dependencies are managed at the bitbake level.
+# We don't need to specify all targets here because no files named like them exist at the top level directory.
+.PHONY : bbcache
+
+# Use a default build tag when none is set by the caller
+NOWDATE := $(shell date +"%Y%m%d%H%M%S")
+BUILD_TAG ?= custom_build_$(USER)@$(HOSTNAME)$(NOWDATE)
+BB_DL_DIR ?= $(CURDIR)/bbcache/downloads
+BB_SSTATE_DIR ?= $(CURDIR)/bbcache/sstate-cache
+
+###############################################################################
+# Main targets
+###############################################################################
+setup: _setup-sdkhost_linux64
+
+cleansstate: _check_setup_was_done
+ /bin/bash -c "source out/current/poky/oe-init-build-env $(CURDIR)/out/current/build ; $(CURDIR)/device-software/utils/invalidate_sstate.sh $(CURDIR)/out/current/build"
+
+devtools_package: _check_setup_was_done
+ /bin/bash -c "source out/current/poky/oe-init-build-env $(CURDIR)/out/current/build ; $(CURDIR)/device-software/utils/create_devtools_package.sh $(CURDIR)/out/current/build"
+
+sdk: _check_setup_was_done
+ /bin/bash -c "source out/current/poky/oe-init-build-env $(CURDIR)/out/current/build ; bitbake edison-image -c populate_sdk"
+
+src-package: pub
+ ./device-software/utils/create_src_package.sh
+ mv edison-src.tgz $(CURDIR)/pub/edison-src-$(BUILD_TAG).tgz
+
+clean:
+ rm -rf out
+
+u-boot linux-externalsrc edison-image meta-toolchain bootimg: _check_setup_was_done
+ /bin/bash -c "source out/current/poky/oe-init-build-env $(CURDIR)/out/current/build ; bitbake -c cleansstate $@ ; bitbake $@"
+ ./device-software/utils/flash/postBuild.sh $(CURDIR)/out/current/build
+
+bootloader: u-boot
+
+image: edison-image
+
+kernel: linux-externalsrc bootimg
+
+toolchain: meta-toolchain
+
+flash: _check_postbuild_was_done
+ ./out/current/build/toFlash/flashall.sh
+
+flash-kernel: _check_postbuild_was_done
+ dd if=./out/current/build/toFlash/edison-image-edison.hddimg | ssh root@192.168.2.15 "dd of=/dev/disk/by-partlabel/boot bs=1M"
+ ssh root@192.168.2.15 "/sbin/reboot -f"
+
+flash-bootloader: _check_postbuild_was_done
+ dfu-util -d 8087:0a99 --alt u-boot0 -D ./out/current/build/toFlash/u-boot-edison.bin -R
+
+cscope:
+ find linux-kernel/ u-boot -regex '.*\.\(c\|cpp\|h\)$\' > cscope.files
+ cscope -R -b -k
+
+list:
+ @sh -c "$(MAKE) -p _no_targets | awk -F':' '/^[a-zA-Z0-9][^\$$#\/\\t=]*:([^=]|$$)/ {split(\$$1,A,/ /);for(i in A)print A[i]}' | sort"
+
+debian_image:
+ $(MAKE) setup SETUP_ARGS="$(SETUP_ARGS) --deb_packages"
+ $(MAKE) image
+ @echo '*******************************'
+ @echo '*******************************'
+ @echo 'Now run the following command to create the debian rootfs:'
+ @echo 'sudo $(CURDIR)/device-software/utils/create-debian-image.sh --build_dir=$(CURDIR)/out/current/build'
+ @echo 'and run a regular make flash'
+ @echo '*******************************'
+
+help:
+ @echo 'Main targets:'
+ @echo ' help - show this help'
+ @echo ' clean - remove the out and pub directory'
+ @echo ' setup - prepare the build env for later build operations'
+ @echo ' cleansstate - clean the sstate for some recipes to work-around some bitbake limitations'
+ @echo ' image - build the flashable edison image, results are in out/current/build/toFlash'
+ @echo ' flash - flash the current build image'
+ @echo ' sdk - build the SDK for the current build'
+ @echo ' toolchain - build the cross compilation toolchain for the current build'
+ @echo ' src-package - create the external source package'
+ @echo ' devtools_package - build some extra dev tools packages, results are in out/current/build/devtools_packages/'
+ @echo
+ @echo 'Continuous Integration targets:'
+ @sh -c "$(MAKE) -p _no_targets | awk -F':' '/^ci_[a-zA-Z0-9][^\$$#\/\\t=]*:([^=]|$$)/ {split(\$$1,A,/ /);for(i in A)print \" \"A[i]}' | sort"
+ @echo
+ @echo 'Environment variables:'
+ @echo ' BUILD_TAG - set the build name used for e.g. artifact file naming'
+ @echo ' BB_DL_DIR - defines the directory (absolute path) where bitbake places downloaded files (defaults to bbcache/downloads)'
+ @echo ' BB_SSTATE_DIR - defines the directory (absolute path) where bitbake places shared-state files (defaults to bbcache/sstate-cache)'
+ @echo ' SETUP_ARGS - control advanced behaviour of the setup script (run ./device-software/setup.sh --help for more details)'
+
+###############################################################################
+# Private targets
+###############################################################################
+
+_no_targets:
+
+_check_setup_was_done:
+ @if [ ! -f $(CURDIR)/out/current/build/conf/local.conf ]; then echo Please run \"make setup\" first ; exit 1 ; fi
+
+_check_postbuild_was_done:
+ @if [ ! -f $(CURDIR)/out/current/build/toFlash/flashall.sh ]; then echo Please run \"make image/bootloader/kernel\" first ; exit 1 ; fi
+
+_setup-sdkhost_%: pub bbcache
+ @echo Setup buildenv for SDK host $*
+ @mkdir -p out/$*
+ ./device-software/setup.sh $(SETUP_ARGS) --dl_dir=$(BB_DL_DIR) --sstate_dir=$(BB_SSTATE_DIR) --build_dir=$(CURDIR)/out/$* --build_name=$(BUILD_TAG) --sdk_host=$*
+ @rm -f out/current
+ @ln -s $(CURDIR)/out/$* $(CURDIR)/out/current
+ @if [ $* = macosx ]; then /bin/bash -c "source out/current/poky/oe-init-build-env $(CURDIR)/out/current/build ; bitbake odcctools2-crosssdk -c cleansstate" ; echo "Please make sure that OSX-sdk.zip is available in your bitbake download directory" ; fi
+
+pub:
+ @mkdir -p $@
+
+bbcache:
+ @mkdir -p bbcache
+ @mkdir -p $(BB_DL_DIR)
+ @mkdir -p $(BB_SSTATE_DIR)
+
+_image_archive:
+ cd $(CURDIR)/out/current/build/toFlash ; zip -r $(CURDIR)/pub/edison-image-$(BUILD_TAG).zip `ls`
+ cd $(CURDIR)/out/current/build/symbols ; zip -r $(CURDIR)/pub/symbols-$(BUILD_TAG).zip `ls`
+
+_devtools_package_archive:
+ cd $(CURDIR)/out/current/build/devtools_packages ; zip -r $(CURDIR)/pub/edison-devtools-packages-$(BUILD_TAG).zip `ls`
+
+_sdk_archive_%:
+ cd $(CURDIR)/out/$*/build/tmp/deploy/sdk ; zip -r $(CURDIR)/pub/edison-sdk-$*-$(BUILD_TAG).zip `ls *-edison-image-*`
+
+_toolchain_archive_%:
+ cd $(CURDIR)/out/$*/build/tmp/deploy/sdk ; zip -r $(CURDIR)/pub/edison-meta-toolchain-$*-$(BUILD_TAG).zip `ls *-meta-toolchain-*`
+
+
+###############################################################################
+# Continuous Integration targets: one per checkbox available in jenkins
+# Each target places the the end-user artifact in the pub/ directory
+###############################################################################
+
+ci_image: setup cleansstate devtools_package _devtools_package_archive image _image_archive
+
+_ci_sdk_%:
+ $(MAKE) _setup-sdkhost_$* cleansstate sdk _sdk_archive_$*
+
+_ci_toolchain_%:
+ $(MAKE) _setup-sdkhost_$* cleansstate toolchain _toolchain_archive_$*
+
+ci_sdk_win32: _ci_sdk_win32
+ci_sdk_win64: _ci_sdk_win64
+ci_sdk_linux32: _ci_sdk_linux32
+ci_sdk_linux64: _ci_sdk_linux64
+ci_sdk_macosx: _ci_sdk_macosx
+ci_toolchain_win32: _ci_toolchain_win32
+ci_toolchain_win64: _ci_toolchain_win64
+ci_toolchain_linux32: _ci_toolchain_linux32
+ci_toolchain_linux64: _ci_toolchain_linux64
+ci_toolchain_macosx: _ci_toolchain_macosx
+
+ci_image-from-src-package-and-GPL-LGPL-sources_archive: setup src-package
+ cp $(CURDIR)/pub/edison-src-$(BUILD_TAG).tgz $(CURDIR)/out/current
+ cd $(CURDIR)/out/current ; tar -xvf edison-src-$(BUILD_TAG).tgz
+ cd $(CURDIR)/out/current/edison-src ; /bin/bash -c "SETUP_ARGS=\"$(SETUP_ARGS) --create_src_archive\" make setup cleansstate image _image_archive"
+ cd $(CURDIR)/out/current/edison-src/out/current/build/toFlash ; zip -r $(CURDIR)/pub/edison-image-from-src-package-$(BUILD_TAG).zip `ls`
+ cd $(CURDIR)/out/current/edison-src/out/current/build/tmp/deploy/sources ; zip -r $(CURDIR)/pub/edison-GPL_LGPL-sources-$(BUILD_TAG).zip `ls`
+
+ci_full:
+ $(MAKE) ci_image BUILD_TAG=$(BUILD_TAG)
+ $(MAKE) ci_image-from-src-package-and-GPL-LGPL-sources_archive BUILD_TAG=$(BUILD_TAG)
+ $(MAKE) ci_sdk_win32 ci_toolchain_win32 BUILD_TAG=$(BUILD_TAG)
+ $(MAKE) ci_sdk_win64 ci_toolchain_win64 BUILD_TAG=$(BUILD_TAG)
+ $(MAKE) ci_sdk_linux32 ci_toolchain_linux32 BUILD_TAG=$(BUILD_TAG)
+ $(MAKE) ci_sdk_linux64 ci_toolchain_linux64 BUILD_TAG=$(BUILD_TAG)
+ $(MAKE) ci_sdk_macosx ci_toolchain_macosx BUILD_TAG=$(BUILD_TAG)
+
diff --git a/utils/create-debian-image.sh b/utils/create-debian-image.sh
new file mode 100755
index 0000000..6cf1aee
--- /dev/null
+++ b/utils/create-debian-image.sh
@@ -0,0 +1,226 @@
+#!/bin/bash
+
+# Creates a debian rootfs image which can be flashed on Edison
+# Requires that the host system has the following packages: debootstrap debian-archive-keyring python
+
+top_repo_dir=$(dirname $(dirname $(dirname $(readlink -f $0))))
+build_dir=$top_repo_dir/build
+
+function usage()
+{
+ echo "Creates a debian image starting from a sucessful yocto build"
+ echo "This needs to be run as root. It was tested successfully on Ubuntu 14.04+"
+ echo "On older versions, please install manually debootstrap >= 1.0.59"
+ echo "Options:"
+ echo -e "\t-h --help\t\tdisplay this help and exit"
+ echo -e "\t--skip_debootstrap\tavoids running deboostrap from scratch to save time."
+ echo -e "\t--build_dir\tspecify the yocto build directory. Defaults to ../../build"
+ echo ""
+}
+
+skip_debootstrap="false"
+add_graphical_packages="false"
+
+while [ "$1" != "" ]; do
+ PARAM=`echo $1 | awk -F= '{print $1}'`
+ VALUE=`echo $1 | awk -F= '{print $2}'`
+ case $PARAM in
+ -h | --help)
+ usage
+ exit
+ ;;
+ --skip_debootstrap)
+ echo "Skip running deboostrap from scratch to save time in case of re-run"
+ skip_debootstrap="true"
+ ;;
+ --add_graphical_packages)
+ echo "Add graphical packages in the rootfs. Requires a larger rootfs"
+ add_graphical_packages="true"
+ ;;
+ --build_dir)
+ build_dir=$(readlink -f "$VALUE")
+ ;;
+ *)
+ echo "ERROR: unknown parameter \"$PARAM\""
+ usage
+ exit 1
+ ;;
+ esac
+ shift
+done
+
+cd $build_dir
+
+# Check the version of host debootstrap
+debootstrap_version=`debootstrap --version | cut -d' ' -f2`
+echo """import sys
+from distutils.version import LooseVersion
+if LooseVersion('1.0.59') <= LooseVersion(sys.argv[1]):
+ exit(0)
+else:
+ exit(1)""" > tmp.py
+python tmp.py $debootstrap_version
+ok="$?"
+rm tmp.py
+if [ ! $ok -eq 0 ]; then
+ echo "Bootstrap version too old: needs >= 1.0.59, found $debootstrap_version"
+ exit -1
+fi
+
+# Check that .deb packages were properly created
+if ! grep -q "package_deb" ./conf/local.conf; then
+ echo "No .deb packages were generated by bitbake (only .ipk). Please re-run setup.sh using the --deb_packages option."
+ exit -1
+fi
+
+# Re-run post build to avoid losing hairs
+rm -rf ./toFlash
+$top_repo_dir/device-software/utils/flash/postBuild.sh $build_dir
+
+echo "*** Start creating a debian rootfs image ***"
+
+ROOTDIR=jessie-chroot
+
+if [ "$skip_debootstrap" != "true" ]; then
+ rm -rf $ROOTDIR
+ mkdir $ROOTDIR
+ debootstrap --arch i386 --no-check-gpg jessie $ROOTDIR http://http.debian.net/debian/
+fi
+
+mkdir -p $ROOTDIR/home/root
+
+mount sysfs $ROOTDIR/sys -t sysfs
+mount proc $ROOTDIR/proc -t proc
+
+# Backup config
+cp $ROOTDIR/etc/environment $ROOTDIR/etc/environment.sav
+cp $ROOTDIR/etc/resolv.conf $ROOTDIR/etc/resolv.conf.sav
+cp $ROOTDIR/etc/hosts $ROOTDIR/etc/hosts.sav
+
+# Use host system network config to be able to apt-get later on
+echo `export | grep http_proxy | sed 's/declare -x http_proxy=/Acquire::http::proxy /'`\; >> $ROOTDIR/etc/apt/apt.conf.d/50proxy
+echo `export | grep https_proxy | sed 's/declare -x https_proxy=/Acquire::https::proxy /'`\; >> $ROOTDIR/etc/apt/apt.conf.d/50proxy
+echo `export | grep HTTP_PROXY | sed 's/declare -x HTTP_PROXY=/Acquire::http::proxy /'`\; >> $ROOTDIR/etc/apt/apt.conf.d/50proxy
+echo `export | grep HTTPS_PROXY | sed 's/declare -x HTTPS_PROXY=/Acquire::https::proxy /'`\; >> $ROOTDIR/etc/apt/apt.conf.d/50proxy
+cp /etc/resolv.conf $ROOTDIR/etc/resolv.conf
+cp /etc/hosts $ROOTDIR/etc/hosts
+
+CHROOTCMD="eval LC_ALL=C LANGUAGE=C LANG=C chroot $ROOTDIR"
+
+# Install necessary packages
+$CHROOTCMD apt-get clean
+$CHROOTCMD apt-get update
+$CHROOTCMD apt-get -y --force-yes install dbus nano openssh-server sudo bash-completion dosfstools
+$CHROOTCMD apt-get -y --force-yes install bluez hostapd file ethtool network-manager
+$CHROOTCMD apt-get -y --force-yes install python
+
+# Necessary for the resize-rootfs service
+$CHROOTCMD apt-get -y --force-yes install e2fsprogs
+
+# This service is added by the network-manager debian package but we don't want it activated
+# as it causes an UART console corruption at boot
+$CHROOTCMD rm /etc/systemd/system/multi-user.target.wants/ModemManager.service /etc/systemd/system/dbus-org.freedesktop.ModemManager1.service
+
+# Create a default user "user" with password "edison"
+# Encrypted password is created with mkpasswd
+$CHROOTCMD useradd -m user -p YyleQbUNcJwao
+$CHROOTCMD adduser user sudo
+$CHROOTCMD adduser user netdev
+$CHROOTCMD chsh -s /bin/bash user
+
+
+# Fixup watchdog in systemd
+echo "RuntimeWatchdogSec=90" >> $ROOTDIR/etc/systemd/system.conf
+
+# Install kernel/modules/firmware base packages generated by yocto
+cp -r tmp/deploy/deb $ROOTDIR/tmp/
+$CHROOTCMD dpkg -i /tmp/deb/edison/kernel-image-3.10.17-poky-edison+_1.0-r2_i386.deb
+$CHROOTCMD dpkg -i /tmp/deb/edison/kernel-3.10.17-poky-edison+_1.0-r2_i386.deb
+$CHROOTCMD dpkg -i /tmp/deb/edison/kernel-module-bcm4334x_1.141-r47_i386.deb
+$CHROOTCMD dpkg -i /tmp/deb/edison/kernel-module-bcm-bt-lpm_1.0-r2_i386.deb
+$CHROOTCMD dpkg -i /tmp/deb/edison/kernel-module-libcomposite_1.0-r2_i386.deb
+$CHROOTCMD dpkg -i /tmp/deb/edison/kernel-module-u-serial_1.0-r2_i386.deb
+$CHROOTCMD dpkg -i /tmp/deb/edison/kernel-module-usb-f-acm_1.0-r2_i386.deb
+$CHROOTCMD dpkg -i /tmp/deb/edison/kernel-module-g-multi_1.0-r2_i386.deb
+$CHROOTCMD dpkg -i /tmp/deb/edison/kernel-module-aufs_1.0-r2_i386.deb
+$CHROOTCMD dpkg -i /tmp/deb/all/bcm43340-fw_6.20.190-r2_all.deb
+$CHROOTCMD dpkg -i /tmp/deb/core2-32/bcm43340-bt_1.0-r0_i386.deb
+
+# Enables USB networking at startup
+cat > $ROOTDIR/lib/systemd/network/usb0.network <<EOF
+[Match]
+Name=usb0
+
+[Network]
+Address=192.168.2.15/24
+EOF
+$CHROOTCMD ln -s /lib/systemd/system/systemd-networkd.service /etc/systemd/system/multi-user.target.wants/
+
+
+# Provides fw_setenv/fw_printenv
+$CHROOTCMD dpkg -i /tmp/deb/edison/u-boot-fw-utils_2014.04-1-r0_i386.deb
+
+# First install script, probably not much needed for a debian
+$CHROOTCMD dpkg -i /tmp/deb/core2-32/first-install_1.0-r0_i386.deb
+$CHROOTCMD dpkg -i --force-depends /tmp/deb/core2-32/resize-rootfs_1.0-r0_i386.deb
+
+# Add this service as it's not present on debian, but is required by the first-install script
+cat > $ROOTDIR/lib/systemd/system/sshdgenkeys.service <<EOF
+[Unit]
+Description=OpenSSH Key Generation
+[Service]
+ExecStart=/bin/sh -c "if ! sshd -t &> /dev/null ; then rm /etc/ssh/*_key* ; ssh-keygen -A ; sync ; fi"
+Type=oneshot
+RemainAfterExit=yes
+EOF
+
+# Set up uboot env configuration
+cat > $ROOTDIR/etc/fw_env.config <<EOF
+# MTD device name Device offset Env. size Flash sector size Number of sectors
+# On Edison, the u-boot environments are located on partitions 2 and 4 and both have a size of 64kB
+/dev/mmcblk0p2 0x0000 0x10000
+/dev/mmcblk0p4 0x0000 0x10000
+EOF
+
+if [ "$add_graphical_packages" == "true" ]; then
+ # Add X.org, mesa, wayland and graphical stuff
+ $CHROOTCMD apt-get -y --force-yes install xorg mesa-utils weston
+fi
+
+# Cleanup space on rootfs
+$CHROOTCMD apt-get clean
+
+# Setup config files with final versions
+mv $ROOTDIR/etc/environment.sav $ROOTDIR/etc/environment
+mv $ROOTDIR/etc/resolv.conf.sav $ROOTDIR/etc/resolv.conf
+mv $ROOTDIR/etc/hosts.sav $ROOTDIR/etc/hosts.conf
+echo "127.0.0.1 localhost.localdomain edison" >> $ROOTDIR/etc/hosts
+echo "edison" > $ROOTDIR/etc/hostname
+echo "rootfs / auto nodev,noatime,discard,barrier=1,data=ordered,noauto_da_alloc 1 1" > $ROOTDIR/etc/fstab
+echo "/dev/disk/by-partlabel/boot /boot auto noauto,comment=systemd.automount,nosuid,nodev,noatime,discard 1 1" >> $ROOTDIR/etc/fstab
+
+# Clean up
+umount -l -f $ROOTDIR/sys
+# Kill remaining processes making use of the /proc before unmounting it
+lsof | grep $ROOTDIR/proc | awk '{print $2}' | xargs kill -9
+umount -l -f $ROOTDIR/proc
+rm -rf $ROOTDIR/tmp/deb
+
+# Create the rootfs ext4 image
+rm edison-image-edison.ext4
+fsize=$((`stat --printf="%s" toFlash/edison-image-edison.ext4` / 524288))
+dd if=/dev/zero of=edison-image-edison.ext4 bs=512K count=$fsize
+mkfs.ext4 -F -L rootfs edison-image-edison.ext4
+
+# Copy the rootfs content in the ext4 image
+rm -rf tmpext4
+mkdir tmpext4
+mount -o loop edison-image-edison.ext4 tmpext4
+cp -a $ROOTDIR/* tmpext4/
+umount tmpext4
+rmdir tmpext4
+
+cp edison-image-edison.ext4 toFlash/
+# Make sure that non-root users can read write the flash files
+# This seems to fix a strange flashing issue in some cases
+chmod -R a+rw toFlash
diff --git a/utils/create_devtools_package.sh b/utils/create_devtools_package.sh
new file mode 100755
index 0000000..d1d74b0
--- /dev/null
+++ b/utils/create_devtools_package.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+echo "*** Start creating the dev tools ipk packages ***"
+
+top_repo_dir=$(dirname $(dirname $(dirname $(readlink -f $0))))
+
+build_dir=""
+if [ $# -eq 0 ]; then
+ build_dir=$top_repo_dir/build
+else
+ build_dir=$1
+fi
+
+cd $build_dir
+
+bitbake peeknpoke
+bitbake powertop
+bitbake bonnie++
+bitbake wfa-tool
+# for iotkit-comm ACS sanity tests
+bitbake gcc
+bitbake iotkit-comm-c
+bitbake iotkit-comm-js
+
+rm -rf devtools_packages
+mkdir devtools_packages
+
+cp tmp/deploy/ipk/core2-32/peeknpoke_1.1-r0_core2-32.ipk devtools_packages/
+cp tmp/deploy/ipk/core2-32/powertop_2.5-r0_core2-32.ipk devtools_packages/
+cp tmp/deploy/ipk/core2-32/bonnie++_1.03c-r0_core2-32.ipk devtools_packages/
+cp tmp/deploy/ipk/core2-32/wfa-tool_r4.0-0_core2-32.ipk devtools_packages/
+# for iotkit-comm ACS sanity tests
+cp tmp/deploy/ipk/core2-32/gcov_4.8.2-r0_core2-32.ipk devtools_packages/gcov_core2-32.ipk
+cp tmp/deploy/ipk/core2-32/iotkit-comm-c-tests_0.1.1-r2_core2-32.ipk devtools_packages/iotkit-comm-c-tests_core2-32.ipk
+cp tmp/deploy/ipk/core2-32/iotkit-comm-js-test-dependencies_0.1.1-r2_core2-32.ipk devtools_packages/iotkit-comm-js-test-dependencies_core2-32.ipk
diff --git a/utils/create_src_package.sh b/utils/create_src_package.sh
new file mode 100755
index 0000000..69e3a1e
--- /dev/null
+++ b/utils/create_src_package.sh
@@ -0,0 +1,69 @@
+#!/bin/bash
+
+echo "*** Start creating the Edison BSP source release ***"
+
+top_repo_dir=$(dirname $(dirname $(dirname $(readlink -f $0))))
+
+# Allows to copy a temporary directory and clean up it's non-versioned content
+# without wiping out the current work of the developer
+function clean_and_copy_dir {
+ cp -rL $1 tmp
+ ORIGDIR=$(pwd)
+ cd tmp/$3
+ git clean -xdf
+ git reset --hard
+ cd $ORIGDIR
+ cp -r tmp $2/$1
+ rm -rf tmp
+}
+
+
+cd $top_repo_dir
+rm -rf edison-src
+mkdir edison-src
+
+echo "*** Synchronize patches in external sources recipes ***"
+$top_repo_dir/device-software/utils/generate-recipes-patches.sh
+
+echo "*** Copy files in archive ***"
+
+# Copy all external sources directories as-is in the package for now
+cp -r device-software edison-src/
+cp Makefile edison-src/
+clean_and_copy_dir broadcom_cws edison-src/
+
+# Copy middleware stuff in src dir
+cd $top_repo_dir
+mkdir edison-src/mw
+clean_and_copy_dir mw/oobe edison-src/
+
+# Copy Arduino stuff in src dir
+cd $top_repo_dir
+mkdir edison-src/arduino
+clean_and_copy_dir arduino/clloader edison-src/
+
+###############################################################################
+# Remove this script from source package
+rm $top_repo_dir/edison-src/device-software/utils/create_src_package.sh
+rm $top_repo_dir/edison-src/device-software/utils/generate-recipes-patches.sh
+
+# Remove the devenv layer from source package
+rm -r $top_repo_dir/edison-src/device-software/meta-edison-devenv
+sed -i -e "s/\$my_dir\/device-software\/meta-edison-devenv//g" $top_repo_dir/edison-src/device-software/setup.sh
+
+###############################################################################
+# Cleanups
+# Remove all .git directories
+echo "*** Cleanup ***"
+cd $top_repo_dir/edison-src
+find . -name .gitignore -exec rm -rf {} \;
+find . -name .git -prune -execdir rm -rf .git \;
+
+# Create archive
+cd $top_repo_dir
+tar -czf edison-src.tgz edison-src
+
+rm -rf edison-src
+
+echo "*** Archive created in $top_repo_dir/edison-src.tgz ***"
+
diff --git a/utils/darwin-daisy.tar.bz2 b/utils/darwin-daisy.tar.bz2
new file mode 100644
index 0000000..5b295b8
--- /dev/null
+++ b/utils/darwin-daisy.tar.bz2
Binary files differ
diff --git a/utils/flash/.gitignore b/utils/flash/.gitignore
new file mode 100644
index 0000000..be1970b
--- /dev/null
+++ b/utils/flash/.gitignore
@@ -0,0 +1 @@
+PRIVATE
diff --git a/utils/flash/filter-dfu-out.js b/utils/flash/filter-dfu-out.js
new file mode 100644
index 0000000..d5d5de9
--- /dev/null
+++ b/utils/flash/filter-dfu-out.js
@@ -0,0 +1,38 @@
+/* filter output of dfu-util and handle tee feature */
+var stdin = WScript.StdIn;
+var stdout = WScript.StdOut;
+var fs = WScript.CreateObject("Scripting.FileSystemObject");
+if ( WScript.arguments.length < 2 ) {
+ WScript.Quit(3) ;
+}
+
+var f = fs.OpenTextFile(WScript.arguments(0), 8,true, 0);
+var filterout = false
+if ( WScript.arguments(1) == "on") {
+ filterout = true;
+}
+
+while (!stdin.AtEndOfStream) {
+ line = "";
+ while (!stdin.AtEndOfLine) {
+ carac = stdin.Read(1);
+ line += carac;
+ if ((carac == '\r')) {
+ stdout.Write(line);
+ line = ""
+ }
+
+ }
+ stdin.Read(1);
+ if (filterout) {
+ if (line.indexOf("Download") >= 0 ) {
+ stdout.write(line + '\n');
+ }
+ }
+ else {
+ stdout.write(line + '\n')
+ }
+ f.write(line + '\n');
+}
+
+f.Close();
diff --git a/utils/flash/flashall.bat b/utils/flash/flashall.bat
new file mode 100644
index 0000000..70100ea
--- /dev/null
+++ b/utils/flash/flashall.bat
@@ -0,0 +1,234 @@
+::batch file for win platform
+@echo off
+set BASE_DIR=%~dp0
+set USB_VID=8087
+set USB_PID=0a99
+set /a TIMEOUT=60
+
+::Phone flash tools configuration part
+set DO_RECOVERY=0
+set EDISON_XML_FILE="%BASE_DIR%pft-config-edison.xml"
+set PFT_XML_FILE="%BASE_DIR%pft-config-edison.xml"
+
+:: Handle Ifwi file for DFU update
+set IFWI_DFU_FILE=%BASE_DIR%edison_ifwi-dbg
+
+set VAR_DIR=%BASE_DIR%u-boot-envs\
+set VARIANT_NAME_DEFAULT=edison-defaultrndis
+set VARIANT_NAME_BLANK=edison-blankrndis
+set VARIANT_NAME=%VARIANT_NAME_BLANK%
+
+set LOG_FILENAME=flash.log
+set /a verbose_output=0
+:: ********************************************************************
+:: parse arg
+set show_help=0
+set argcount=0
+set appname=%0
+:parse_arg_start
+if -%1-==-- goto parse_arg_end
+if -%1- == ---recovery- (
+ set /a DO_RECOVERY=1
+)
+if -%1- == ---keep-data- (
+ set VARIANT_NAME=%VARIANT_NAME_DEFAULT%
+)
+if -%1- == -/?- set /a show_help=1
+if -%1- == --h- set /a show_help=1
+if -%1- == ---help- set /a show_help=1
+if -%1- == --v- set /a verbose_output=1
+set /a argcount+= 1
+shift
+goto :parse_arg_start
+:parse_arg_end
+
+:: handle help on cmd arg
+if %show_help% == 1 (
+ call:print-usage %appname%
+ exit /b
+)
+
+if %verbose_output% == 1 goto skip_init_log
+echo ** Flashing Edison Board %date% %time% ** >> %LOG_FILENAME%
+:skip_init_log
+
+:: ********************************************************************
+:: Ifwi flashing part
+if %DO_RECOVERY% == 0 goto :skip_flash_ifwi
+echo Starting Recovery mode
+echo Please plug and reboot the board
+if not exist %PFT_XML_FILE% (
+ echo %PFT_XML_FILE% does not exist
+ exit /b 3
+)
+echo Flashing IFWI
+call:flash-ifwi
+if %errorlevel% neq 0 ( exit /b %errorlevel%)
+echo Recovery Success...
+echo You can now try a regular flash
+goto :skip_flash_kernel
+:skip_flash_ifwi
+
+:: ********************************************************************
+:: Kernel & rootfs flashing part
+echo Using U-boot target: %VARIANT_NAME%
+set VARIANT_FILE="%VAR_DIR%%VARIANT_NAME%.bin"
+ if not exist %VARIANT_FILE% (
+ echo U-boot target %VARIANT_NAME%: %VARIANT_FILE% not found aborting
+ exit /b 5
+)
+
+echo Now waiting for dfu device %USB_VID%:%USB_PID%
+echo Please plug and reboot the board
+call:dfu-wait
+if %errorlevel% neq 0 ( exit /b %errorlevel%)
+
+echo Flashing IFWI
+call:flash-dfu-ifwi ifwi00 "%IFWI_DFU_FILE%-00-dfu.bin"
+if %errorlevel% neq 0 ( exit /b %errorlevel%)
+call:flash-dfu-ifwi ifwib00 "%IFWI_DFU_FILE%-00-dfu.bin"
+if %errorlevel% neq 0 ( exit /b %errorlevel%)
+
+call:flash-dfu-ifwi ifwi01 "%IFWI_DFU_FILE%-01-dfu.bin"
+if %errorlevel% neq 0 ( exit /b %errorlevel%)
+call:flash-dfu-ifwi ifwib01 "%IFWI_DFU_FILE%-01-dfu.bin"
+if %errorlevel% neq 0 ( exit /b %errorlevel%)
+
+call:flash-dfu-ifwi ifwi02 "%IFWI_DFU_FILE%-02-dfu.bin"
+if %errorlevel% neq 0 ( exit /b %errorlevel%)
+call:flash-dfu-ifwi ifwib02 "%IFWI_DFU_FILE%-02-dfu.bin"
+if %errorlevel% neq 0 ( exit /b %errorlevel%)
+
+call:flash-dfu-ifwi ifwi03 "%IFWI_DFU_FILE%-03-dfu.bin"
+if %errorlevel% neq 0 ( exit /b %errorlevel%)
+call:flash-dfu-ifwi ifwib03 "%IFWI_DFU_FILE%-03-dfu.bin"
+if %errorlevel% neq 0 ( exit /b %errorlevel%)
+
+call:flash-dfu-ifwi ifwi04 "%IFWI_DFU_FILE%-04-dfu.bin"
+if %errorlevel% neq 0 ( exit /b %errorlevel%)
+call:flash-dfu-ifwi ifwib04 "%IFWI_DFU_FILE%-04-dfu.bin"
+if %errorlevel% neq 0 ( exit /b %errorlevel%)
+
+call:flash-dfu-ifwi ifwi05 "%IFWI_DFU_FILE%-05-dfu.bin"
+if %errorlevel% neq 0 ( exit /b %errorlevel%)
+call:flash-dfu-ifwi ifwib05 "%IFWI_DFU_FILE%-05-dfu.bin"
+if %errorlevel% neq 0 ( exit /b %errorlevel%)
+
+call:flash-dfu-ifwi ifwi06 "%IFWI_DFU_FILE%-06-dfu.bin"
+if %errorlevel% neq 0 ( exit /b %errorlevel%)
+call:flash-dfu-ifwi ifwib06 "%IFWI_DFU_FILE%-06-dfu.bin"
+if %errorlevel% neq 0 ( exit /b %errorlevel%)
+
+echo Flashing U-Boot
+call:flash-command --alt u-boot0 -D "%BASE_DIR%u-boot-edison.bin"
+if %errorlevel% neq 0 ( exit /b %errorlevel%)
+
+echo Flashing U-Boot Environment
+call:flash-command --alt u-boot-env0 -D %VARIANT_FILE%
+if %errorlevel% neq 0 ( exit /b %errorlevel%)
+
+echo Flashing U-Boot Environment Backup
+call:flash-command --alt u-boot-env1 -D %VARIANT_FILE% -R
+if %errorlevel% neq 0 ( exit /b %errorlevel%)
+echo Rebooting to apply partiton changes
+call:dfu-wait
+if %errorlevel% neq 0 ( exit /b %errorlevel%)
+
+
+echo Flashing boot partition ^(kernel^)
+call:flash-command --alt boot -D "%BASE_DIR%edison-image-edison.hddimg"
+if %errorlevel% neq 0 ( exit /b %errorlevel%)
+
+echo Flashing rootfs, ^(it can take up to 5 minutes... Please be patient^)
+call:flash-command --alt rootfs -D "%BASE_DIR%edison-image-edison.ext4" -R
+if %errorlevel% neq 0 ( exit /b %errorlevel% )
+
+echo Rebooting
+echo U-boot ^& Kernel System Flash Success...
+if %VARIANT_NAME% == %VARIANT_NAME_BLANK% (
+ echo Your board needs to reboot to complete the flashing procedure, please do not unplug it for 2 minutes.
+)
+:skip_flash_kernel
+
+:: ********************************************************************
+:: The End
+exit /b 0
+
+
+:print-usage
+ echo Usage: %1 [-h] [--help] [--recovery] [--keep-data]
+ echo Update all software and restore board to its initial state.
+ echo -h,--help display this help and exit.
+ echo -v verbose output
+ echo --recovery recover the board to DFU mode using a dedicated tool,
+ echo available only on linux and window hosts.
+ echo --keep-data preserve user data when flashing.
+ exit /b 5
+
+:flash-dfu-ifwi
+ dfu-util -d %USB_VID%:%USB_PID% -l | findstr "%1" > NUL 2>&1
+ if %errorlevel% == 0 (
+ call:flash-command --alt %1 -D %2
+ exit /b %errorlevel%
+ )
+ exit /b 0
+
+:flash-command
+ set filterout="on"
+ if %verbose_output% == 1 ( set filterout="off")
+
+ dfu-util -d %USB_VID%:%USB_PID% %* 2>&1 | cscript.exe /E:JScript //B filter-dfu-out.js %LOG_FILENAME% %filterout%
+
+ set /a err_num=%errorlevel%
+ if %err_num% neq 0 echo Flash failed on %*
+ exit /b %err_num%
+
+:flash-debug
+ echo DEBUG: dfu-util -l
+ dfu-util -l
+ exit /b
+
+:flash-ifwi
+ for %%X in (xfstk-dldr-solo.exe) do (set xfstk_tool_found=%%~$PATH:X)
+ for %%X in (cflasher.exe) do (set pft_tool_found=%%~$PATH:X)
+ if defined pft_tool_found (
+ call:flash-ifwi-pft
+ exit /b %errorlevel%
+ )
+ if defined xfstk_tool_found (
+ call:flash-ifwi-xfstk
+ exit /b %errorlevel%
+ )
+ echo !!! You should install xfstk tools, please visit http://xfstk.sourceforge.net/
+ exit /b 3
+
+:flash-ifwi-xfstk
+ xfstk-dldr-solo.exe --gpflags 0x80000007 --osimage "%BASE_DIR%u-boot-edison.img" --fwdnx "%BASE_DIR%edison_dnx_fwr.bin" --fwimage "%BASE_DIR%edison_ifwi-dbg-00.bin" --osdnx "%BASE_DIR%edison_dnx_osr.bin"
+ set /a err_num=%errorlevel%
+ if %err_num% neq 0 echo Ifwi Flash failed
+ exit /b %err_num%
+
+:flash-ifwi-pft
+ cflasher -f %PFT_XML_FILE%
+ set /a err_num=%errorlevel%
+ if %err_num% neq 0 echo Ifwi Flash failed
+ exit /b %err_num%
+
+:dfu-wait
+ setlocal
+ set /a currtime=%TIMEOUT%
+:start_wait
+ dfu-util -l -d %USB_VID%:%USB_PID% | findstr "Found" | findstr "%USB_VID%" > NUL 2>&1
+ if %errorlevel% == 0 (
+ echo Dfu device found
+ exit /b 0
+ ) else (
+ set /a currtime-= 1
+ timeout /t 1 /nobreak > nul
+ if %currtime% gtr 0 goto:start_wait
+ )
+ echo Dfu device not found Timeout
+ echo Did you plug and reboot your board?
+ echo If yes, please try a recovery by calling this script with the --recovery option
+ exit /b 3
+
diff --git a/utils/flash/flashall.sh b/utils/flash/flashall.sh
new file mode 100755
index 0000000..563769d
--- /dev/null
+++ b/utils/flash/flashall.sh
@@ -0,0 +1,240 @@
+#!/bin/bash
+
+
+BACKUP_IFS=$IFS
+IFS=$(echo -en "\n\b")
+
+GETOPTS="$(which getopt)"
+if [[ "$OSTYPE" == "darwin"* ]] ; then READLINK=greadlink; GETOPTS="$(brew list gnu-getopt | grep bin/getopt)"; else READLINK=readlink;fi;
+
+if [[ "$OSTYPE" == "cygwin" ]] ;
+then
+ TEMP_DIR="$(dirname $($READLINK -f $0))"
+ ESC_BASE_DIR="$(cygpath -m ${TEMP_DIR})"
+ BASE_DIR="$(cygpath -m ${TEMP_DIR})"
+else
+ BASE_DIR="$(dirname $($READLINK -f $0))"
+ ESC_BASE_DIR=${BASE_DIR/' '/'\ '}
+fi;
+
+USB_VID=8087
+USB_PID=0a99
+TIMEOUT_SEC=60
+
+DO_RECOVERY=0
+# Phone Flash tools configuration files
+PFT_XML_FILE="${BASE_DIR}/pft-config-edison.xml"
+
+# Handle Ifwi file for DFU update
+IFWI_DFU_FILE=${ESC_BASE_DIR}/edison_ifwi-dbg
+
+VAR_DIR="${BASE_DIR}/u-boot-envs"
+if [[ "$OSTYPE" == "cygwin" ]] ; then
+ VARIANT_NAME_DEFAULT="edison-defaultrndis"
+ VARIANT_NAME_BLANK="edison-blankrndis"
+else
+ VARIANT_NAME_DEFAULT="edison-defaultcdc"
+ VARIANT_NAME_BLANK="edison-blankcdc"
+fi
+VARIANT_NAME=$VARIANT_NAME_BLANK
+
+LOG_FILENAME="flash.log"
+OUTPUT_LOG_CMD="2>&1 | tee -a ${LOG_FILENAME} | ( sed -n '19 q'; head -n 1; cat >/dev/null )"
+
+function print-usage {
+ cat << EOF
+Usage: ${0##*/} [-h][--help][--recovery] [--keep-data]
+Update all software and restore board to its initial state.
+ -h,--help display this help and exit.
+ -v verbose output
+ --recovery recover the board to DFU mode using a dedicated tool,
+ available only on linux and window hosts.
+ --keep-data preserve user data when flashing.
+EOF
+ exit -5
+}
+
+function flash-command-try {
+ eval dfu-util -v -d ${USB_VID}:${USB_PID} $@ $OUTPUT_LOG_CMD
+}
+
+function flash-dfu-ifwi {
+ ifwi_hwid_found=`dfu-util -l -d ${USB_VID}:${USB_PID} | grep -c $1`
+ if [ $ifwi_hwid_found -ne 0 ];
+ then
+ flash-command ${@:2}
+ fi
+}
+
+function flash-command {
+ flash-command-try $@
+ if [ $? -ne 0 ] ;
+ then
+ echo "Flash failed on $@"
+ exit -1
+ fi
+}
+
+function flash-debug {
+ echo "DEBUG: lsusb"
+ lsusb
+ echo "DEBUG: dfu-util -l"
+ dfu-util -l
+}
+
+function flash-ifwi {
+ if [ -x "$(which phoneflashtool)" ]; then
+ flash-ifwi-pft
+ elif [ -x "$(which xfstk-dldr-solo)" ]; then
+ flash-ifwi-xfstk
+ else
+ echo "!!! You should install xfstk tools, please visit http://xfstk.sourceforge.net/"
+ exit -1
+ fi
+}
+
+function flash-ifwi-pft {
+ eval phoneflashtool --cli -f "$PFT_XML_FILE"
+ if [ $? -ne 0 ];
+ then
+ echo "Phoneflashtool error"
+ flash-debug
+ exit -1
+ fi
+}
+
+function flash-ifwi-xfstk {
+ XFSTK_PARAMS=" --gpflags 0x80000007 --osimage ${ESC_BASE_DIR}/u-boot-edison.img"
+ XFSTK_PARAMS="${XFSTK_PARAMS} --fwdnx ${ESC_BASE_DIR}/edison_dnx_fwr.bin"
+ XFSTK_PARAMS="${XFSTK_PARAMS} --fwimage ${ESC_BASE_DIR}/edison_ifwi-dbg-00.bin"
+ XFSTK_PARAMS="${XFSTK_PARAMS} --osdnx ${ESC_BASE_DIR}/edison_dnx_osr.bin"
+
+ eval xfstk-dldr-solo ${XFSTK_PARAMS}
+ if [ $? -ne 0 ];
+ then
+ echo "Xfstk tool error"
+ flash-debug
+ exit -1
+ fi
+}
+
+function dfu-wait {
+ echo "Now waiting for dfu device ${USB_VID}:${USB_PID}"
+ if [ -z "$@" ]; then
+ echo "Please plug and reboot the board"
+ fi
+ while [ `dfu-util -l -d ${USB_VID}:${USB_PID} | grep Found | grep -c ${USB_VID}` -eq 0 ] \
+ && [ $TIMEOUT_SEC -gt 0 ] && [ $(( TIMEOUT_SEC-- )) ];
+ do
+ sleep 1
+ done
+
+ if [ $TIMEOUT_SEC -eq 0 ];
+ then
+ echo "Timed out while waiting for dfu device ${USB_VID}:${USB_PID}"
+ flash-debug
+ if [ -z "$@" ]; then
+ echo "Did you plug and reboot your board?"
+ echo "If yes, please try a recovery by calling this script with the --recovery option"
+ fi
+ exit -2
+ fi
+}
+
+# Execute old getopt to have long options support
+ARGS=$($GETOPTS -o hv -l "keep-data,recovery,help" -n "${0##*/}" -- "$@");
+#Bad arguments
+if [ $? -ne 0 ]; then print-usage ; fi;
+eval set -- "$ARGS";
+
+while true; do
+ case "$1" in
+ -h|--help) shift; print-usage;;
+ -v) shift; OUTPUT_LOG_CMD=" 2>&1 | tee -a ${LOG_FILENAME}";;
+ --recovery) shift; DO_RECOVERY=1;;
+ --keep-data) shift; VARIANT_NAME=$VARIANT_NAME_DEFAULT;;
+ --) shift; break;;
+ esac
+done
+
+echo "** Flashing Edison Board $(date) **" >> ${LOG_FILENAME}
+
+
+if [ ${DO_RECOVERY} -eq 1 ];
+then
+ if [[ "$OSTYPE" == "darwin"* ]] ; then
+ echo "Recovery mode is only available on windows and linux";
+ exit -3
+ fi
+
+ echo "Starting Recovery mode"
+ echo "Please plug and reboot the board"
+ if [ ! -f "${PFT_XML_FILE}" ];
+ then
+ echo "${PFT_XML_FILE} does not exist"
+ exit -3
+ fi
+ echo "Flashing IFWI"
+ flash-ifwi
+ echo "Recovery Success..."
+ echo "You can now try a regular flash"
+
+else
+ echo "Using U-Boot target: ${VARIANT_NAME}"
+ VARIANT_FILE="${VAR_DIR}/${VARIANT_NAME}.bin"
+ if [ ! -f "${VARIANT_FILE}" ]; then
+ echo "U-boot target ${VARIANT_NAME}: ${VARIANT_FILE} not found aborting"
+ exit -5
+ fi
+ VARIANT_FILE=${VARIANT_FILE/' '/'\ '}
+
+ dfu-wait
+
+ echo "Flashing IFWI"
+
+ flash-dfu-ifwi ifwi00 --alt ifwi00 -D "${IFWI_DFU_FILE}-00-dfu.bin"
+ flash-dfu-ifwi ifwib00 --alt ifwib00 -D "${IFWI_DFU_FILE}-00-dfu.bin"
+
+ flash-dfu-ifwi ifwi01 --alt ifwi01 -D "${IFWI_DFU_FILE}-01-dfu.bin"
+ flash-dfu-ifwi ifwib01 --alt ifwib01 -D "${IFWI_DFU_FILE}-01-dfu.bin"
+
+ flash-dfu-ifwi ifwi02 --alt ifwi02 -D "${IFWI_DFU_FILE}-02-dfu.bin"
+ flash-dfu-ifwi ifwib02 --alt ifwib02 -D "${IFWI_DFU_FILE}-02-dfu.bin"
+
+ flash-dfu-ifwi ifwi03 --alt ifwi03 -D "${IFWI_DFU_FILE}-03-dfu.bin"
+ flash-dfu-ifwi ifwib03 --alt ifwib03 -D "${IFWI_DFU_FILE}-03-dfu.bin"
+
+ flash-dfu-ifwi ifwi04 --alt ifwi04 -D "${IFWI_DFU_FILE}-04-dfu.bin"
+ flash-dfu-ifwi ifwib04 --alt ifwib04 -D "${IFWI_DFU_FILE}-04-dfu.bin"
+
+ flash-dfu-ifwi ifwi05 --alt ifwi05 -D "${IFWI_DFU_FILE}-05-dfu.bin"
+ flash-dfu-ifwi ifwib05 --alt ifwib05 -D "${IFWI_DFU_FILE}-05-dfu.bin"
+
+ flash-dfu-ifwi ifwi06 --alt ifwi06 -D "${IFWI_DFU_FILE}-06-dfu.bin"
+ flash-dfu-ifwi ifwib06 --alt ifwib06 -D "${IFWI_DFU_FILE}-06-dfu.bin"
+
+ echo "Flashing U-Boot"
+ flash-command --alt u-boot0 -D "${ESC_BASE_DIR}/u-boot-edison.bin"
+
+ echo "Flashing U-Boot Environment"
+ flash-command --alt u-boot-env0 -D "${VARIANT_FILE}"
+
+ echo "Flashing U-Boot Environment Backup"
+ flash-command --alt u-boot-env1 -D "${VARIANT_FILE}" -R
+ echo "Rebooting to apply partition changes"
+ dfu-wait no-prompt
+
+ echo "Flashing boot partition (kernel)"
+ flash-command --alt boot -D "${ESC_BASE_DIR}/edison-image-edison.hddimg"
+
+ echo "Flashing rootfs, (it can take up to 5 minutes... Please be patient)"
+ flash-command --alt rootfs -D "${ESC_BASE_DIR}/edison-image-edison.ext4" -R
+
+ echo "Rebooting"
+ echo "U-boot & Kernel System Flash Success..."
+ if [ $VARIANT_NAME == $VARIANT_NAME_BLANK ] ; then
+ echo "Your board needs to reboot to complete the flashing procedure, please do not unplug it for 2 minutes."
+ fi
+fi
+
+IFS=${BACKUP_IFS}
diff --git a/utils/flash/ifwi/edison/edison_dnx_fwr.bin b/utils/flash/ifwi/edison/edison_dnx_fwr.bin
new file mode 100644
index 0000000..e646293
--- /dev/null
+++ b/utils/flash/ifwi/edison/edison_dnx_fwr.bin
Binary files differ
diff --git a/utils/flash/ifwi/edison/edison_dnx_osr.bin b/utils/flash/ifwi/edison/edison_dnx_osr.bin
new file mode 100644
index 0000000..a0e41b5
--- /dev/null
+++ b/utils/flash/ifwi/edison/edison_dnx_osr.bin
Binary files differ
diff --git a/utils/flash/ifwi/edison/edison_ifwi-dbg-00.bin b/utils/flash/ifwi/edison/edison_ifwi-dbg-00.bin
new file mode 100644
index 0000000..942490a
--- /dev/null
+++ b/utils/flash/ifwi/edison/edison_ifwi-dbg-00.bin
Binary files differ
diff --git a/utils/flash/ifwi/edison/edison_ifwi-dbg-01.bin b/utils/flash/ifwi/edison/edison_ifwi-dbg-01.bin
new file mode 100644
index 0000000..e9b8211
--- /dev/null
+++ b/utils/flash/ifwi/edison/edison_ifwi-dbg-01.bin
Binary files differ
diff --git a/utils/flash/ifwi/edison/edison_ifwi-dbg-02.bin b/utils/flash/ifwi/edison/edison_ifwi-dbg-02.bin
new file mode 100644
index 0000000..29523b6
--- /dev/null
+++ b/utils/flash/ifwi/edison/edison_ifwi-dbg-02.bin
Binary files differ
diff --git a/utils/flash/ifwi/edison/edison_ifwi-dbg-03.bin b/utils/flash/ifwi/edison/edison_ifwi-dbg-03.bin
new file mode 100644
index 0000000..46c6816
--- /dev/null
+++ b/utils/flash/ifwi/edison/edison_ifwi-dbg-03.bin
Binary files differ
diff --git a/utils/flash/ifwi/edison/edison_ifwi-dbg-04.bin b/utils/flash/ifwi/edison/edison_ifwi-dbg-04.bin
new file mode 100644
index 0000000..8c6fbe6
--- /dev/null
+++ b/utils/flash/ifwi/edison/edison_ifwi-dbg-04.bin
Binary files differ
diff --git a/utils/flash/ifwi/edison/edison_ifwi-dbg-05.bin b/utils/flash/ifwi/edison/edison_ifwi-dbg-05.bin
new file mode 100644
index 0000000..8414303
--- /dev/null
+++ b/utils/flash/ifwi/edison/edison_ifwi-dbg-05.bin
Binary files differ
diff --git a/utils/flash/ifwi/edison/edison_ifwi-dbg-06.bin b/utils/flash/ifwi/edison/edison_ifwi-dbg-06.bin
new file mode 100644
index 0000000..1d2113c
--- /dev/null
+++ b/utils/flash/ifwi/edison/edison_ifwi-dbg-06.bin
Binary files differ
diff --git a/utils/flash/ota_update.cmd b/utils/flash/ota_update.cmd
new file mode 100644
index 0000000..24875be
--- /dev/null
+++ b/utils/flash/ota_update.cmd
@@ -0,0 +1,338 @@
+echo === OTA update script ===
+# Global configuration
+setenv ota_done 0
+setenv ota_abort 0
+setenv ota_verbose 1
+
+# Remove ota_abort_reason which is used to report error in case of failure
+env delete ota_abort_reason
+
+# Define some u-boot functions
+# before running theses functions check for ota_abort var
+# in case of failure theses functions set ota_abort and ota_abort_reason var
+# the function verbosity is controlled by ota_verbose var
+
+# function ota_conv_sizes
+# Convert a bytes size to a block size
+# input bytesize : size in bytes to convert
+# input blksize : size of a block in bytes
+# output numblk : converted size in blocks
+setenv ota_conv_sizes 'setexpr num_blk $bytesize / $blksize ; setexpr mod_blk $bytesize % $blksize ; if itest $mod_blk > 0 ; then setexpr num_blk $num_blk + 1; fi;'
+
+# function ota_mmc_write
+# Write a memory buffer to mmc drive
+# input floadaddr : address of buffer to write
+# input u_part_start : block start in mmc
+# input num_blk : number of block to write
+setenv ota_mmc_write 'if itest $ota_verbose == 1 ; then echo "mmc write ${floadaddr} ${u_part_start} ${num_blk};"; fi; mmc write $floadaddr $u_part_start $num_blk; ret=$?; if itest $ret != 0 ; then setenv ota_abort_reason "mmc write ${floadaddr} ${u_part_start} ${num_blk} failed"; setenv ota_abort 1; fi;'
+
+# function ota_load_image
+# Load partition binary image from update partition to memory
+# input ota_drive : ota drive name
+# input ota_image_name : filename of image to load
+# input floadaddr : memory address destination
+# output filesize : size of image in bytes
+setenv ota_load_image 'if itest $ota_verbose == 1 ; then echo "fatload ${ota_drive} ${floadaddr} ${ota_image_name};"; fi; fatload ${ota_drive} ${floadaddr} ${ota_image_name};ret=$?; if itest $ret != 0 ; then setenv ota_abort_reason "fatload ${ota_drive} ${floadaddr} ${ota_image_name} failed: ${ret}"; setenv ota_abort 1; fi;'
+
+# function ota_compute_hash
+# Compute Sha1 of a Loaded image in memory
+# input floadaddr : memory address destination
+# input filesize : size of image in bytes
+# output sha1_sum : sha1 sum of loaded file
+setenv ota_compute_hash 'if itest $ota_verbose == 1 ; then echo "hash sha1 $floadaddr $filesize sha1_sum;"; fi; hash sha1 $floadaddr $filesize sha1_sum;ret=$?; if itest $ret != 0 ; then setenv ota_abort_reason "hash sha1 $floadaddr $filesize sha1_sum failed: ${ret}"; setenv ota_abort 1; fi;'
+
+# function ota_test_image_and_partition_sizes
+# Test if image fit partition
+# input num_blk : image size in blocks
+# input u_part_sz : partition size in blocks
+setenv ota_test_image_and_partition_sizes 'if itest $num_blk > $u_part_sz ; then setenv ota_abort_reason "Partition ${u_part_lbl} too small for ${ota_image_name}"; setenv ota_abort 1; fi;'
+
+# function ota_find_partition
+# Find a partition by label
+# input u_part_lbl : partition label
+# output u_part_num : partition number
+setenv ota_find_partition 'if itest $ota_verbose == 1 ; then echo "part find mmc 0 label:${u_part_lbl} u_part_num;"; fi; part find mmc 0 label:${u_part_lbl} u_part_num;ret=$?; if itest $ret != 0 ; then setenv ota_abort_reason "part find mmc 0 label:${u_part_lbl} u_part_num failed: ${ret}"; setenv ota_abort 1; fi;'
+
+# function ota_get_partition_attributes
+# Retrieve partition attribute
+# input u_part_num : partition number
+# output u_part_start : partition start block number
+# output u_part_sz : partition size in blocks
+# output u_part_blksz : partition block size in bytes
+setenv ota_get_partition_attributes 'if itest $ota_verbose == 1 ; then echo "part info mmc 0:${u_part_num} u_part_start u_part_sz u_part_blksz;"; fi; part info mmc 0:${u_part_num} u_part_start u_part_sz u_part_blksz;ret=$?; if itest $ret != 0 ; then setenv ota_abort_reason "part info mmc 0:${u_part_num} u_part_start u_part_sz u_part_blksz failed: ${ret}"; setenv ota_abort 1; fi;'
+
+# function ota_exec_verbose_cmd
+# Execute a command when verbosity is set
+# input vb_cmd : contains code to run verbosily
+setenv ota_exec_verbose_cmd 'if itest $ota_verbose == 1 ; then run vb_cmd ; fi;'
+
+
+# function ota_cleans_script
+# remove from environment all variables and functions in this script
+setenv ota_cleans_script 'env delete -f sha1_sum sha1_sum_ref; env delete -f u_part_blksz u_part_lbl u_part_num u_part_start u_part_sz updt_part_num ota_drive; env delete -f mod_blk num_blk filesize bytesize blksize floadaddr vb_cmd; env delete -f floadaddr; env delete -f ota_conv_sizes ota_mmc_write ota_load_image ota_compute_hash; env delete -f ota_test_image_and_partition_sizes ota_find_partition ota_get_partition_attributes ota_exec_verbose_cmd ota_cleans_script;'
+
+# handle two pass validation of script
+if env exist ota_checked ; then if itest $ota_checked == 0; then echo "Ota previously failed retry"; fi; else setenv ota_checked 0; fi;
+if itest $ota_checked == 0; then echo "Validating Ota package" ; else echo "Processing Ota update"; fi;
+
+setenv floadaddr 0x6400000
+
+# Find update partition on emmc drive
+setenv u_part_lbl update;
+run ota_find_partition ;
+if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+
+setenv ota_drive mmc 0:${u_part_num}
+if itest $ota_verbose == 1 ; then echo "ota drive is $ota_drive"; fi
+
+# Start update of edison_ifwi-dbg-dfu.bin on ifwi 1 and 2
+setenv ota_image_name edison_ifwi-dbg-${hardware_id}-dfu.bin ;
+# Tell user what's going on
+echo " "
+if itest $ota_checked == 1 ; then
+echo "Update IFWI on boot0 and boot1 partitions";
+else
+echo "Validating ${ota_image_name} hash for boot0 and boot1 partitions";
+fi;
+echo " "
+
+# Load binary image from update partition to memory
+run ota_load_image;
+if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+
+if itest $ota_checked == 0 ; then
+ # Select sha1_sum_ref according to corresponding hardware_id
+ if itest.s ${hardware_id} == "00" ; then setenv sha1_sum_ref @@sha1_edison_ifwi-dbg-00-dfu.bin ; fi;
+ if itest.s ${hardware_id} == "01" ; then setenv sha1_sum_ref @@sha1_edison_ifwi-dbg-01-dfu.bin ; fi;
+ if itest.s ${hardware_id} == "02" ; then setenv sha1_sum_ref @@sha1_edison_ifwi-dbg-02-dfu.bin ; fi;
+ if itest.s ${hardware_id} == "03" ; then setenv sha1_sum_ref @@sha1_edison_ifwi-dbg-03-dfu.bin ; fi;
+ if itest.s ${hardware_id} == "04" ; then setenv sha1_sum_ref @@sha1_edison_ifwi-dbg-04-dfu.bin ; fi;
+ if itest.s ${hardware_id} == "05" ; then setenv sha1_sum_ref @@sha1_edison_ifwi-dbg-05-dfu.bin ; fi;
+ if itest.s ${hardware_id} == "06" ; then setenv sha1_sum_ref @@sha1_edison_ifwi-dbg-06-dfu.bin ; fi;
+
+ # Verify data integrity
+ run ota_compute_hash;
+ if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+ if itest.s $sha1_sum_ref != $sha1_sum ; then setenv ota_abort_reason "${ota_image_name} hash mismatch ($sha1_sum / $sha1_sum_ref)"; setenv ota_abort 1; fi;
+ if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+fi;
+
+# Convert file size in byte to block, for ifwi used hardcoded values
+setenv bytesize $filesize ;
+setenv blksize 0x200 ;
+run ota_conv_sizes ;
+
+setenv vb_cmd 'echo "${ota_image_name} size is 0x$filesize bytes and 0x$num_blk block";'
+run ota_exec_verbose_cmd ;
+
+# Test if image fit partition
+if itest $num_blk > 0x2000 ; then echo "${ota_image_name} Shrinked to fit partition ifwi "; setenv num_blk 2000 ; fi;
+
+if itest $ota_checked == 1 ; then
+# Set MMC ifwi partition to 1
+ if itest $ota_verbose == 1 ; then echo "mmc dev 0 1;"; fi;
+ mmc dev 0 1 ; ret=$?
+ if itest $ret != 0 ; then setenv ota_abort_reason "mmc dev 0 1 failed: $ret"; setenv ota_abort 1; run ota_cleans_script; exit; fi;
+
+ # Write image to partition
+ setenv u_part_start 0x0;
+ run ota_mmc_write;
+ if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+
+ # Set MMC ifwi partition to 2
+ if itest $ota_verbose == 1 ; then echo "mmc dev 0 2;"; fi;
+ mmc dev 0 2 ; ret=$?
+ if itest $ret != 0 ; then setenv ota_abort_reason "mmc dev 0 2 failed: $ret"; setenv ota_abort 1; run ota_cleans_script; exit; fi;
+
+ # Write image to partition
+ setenv u_part_start 0x00;
+ run ota_mmc_write;
+ if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+
+ # Set back MMC partition 0
+ mmc dev 0 0 ;
+
+ # Tell user about the status
+ echo " "
+ echo "Update of ${ota_image_name} to boot0 and boot1 partitions Done";
+fi;
+
+# Start update of u-boot-edison.bin on u-boot0
+setenv ota_image_name u-boot-edison.bin
+setenv u_part_lbl u-boot0
+setenv sha1_sum_ref @@sha1_u-boot-edison.bin
+# Tell user what's going on
+echo " "
+if itest $ota_checked == 1 ; then
+echo "Update of ${ota_image_name} to ${u_part_lbl} partition";
+else
+echo "Validating ${ota_image_name} hash for ${u_part_lbl} partition";
+fi;
+echo " "
+
+# Load partition binary image from update partition to memory
+run ota_load_image;
+if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+
+# Find partition u-boot0
+run ota_find_partition ;
+if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+
+# Retrieve partition attribute
+run ota_get_partition_attributes ;
+if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+
+# Convert file size in byte to block
+setenv bytesize $filesize ;
+setenv blksize $u_part_blksz ;
+run ota_conv_sizes ;
+
+setenv vb_cmd 'echo "Partition ${u_part_lbl} Start:0x${u_part_start} Size:0x${u_part_sz} BlockSize:0x${u_part_blksz}"; echo "${ota_image_name} size is 0x${filesize} bytes and 0x${num_blk} block"; echo " ";'
+run ota_exec_verbose_cmd ;
+
+if itest $ota_checked == 0 ; then
+ # Test if image fit partition
+ run ota_test_image_and_partition_sizes ;
+ if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+
+ # Verify data integrity
+ run ota_compute_hash;
+ if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+ if itest.s $sha1_sum_ref != $sha1_sum ; then setenv ota_abort_reason "${ota_image_name} hash mismatch ($sha1_sum / $sha1_sum_ref)"; setenv ota_abort 1; fi;
+ if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+else
+ # Write image to partition
+ run ota_mmc_write;
+ if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+
+ # Tell user about the status
+ echo " "
+ echo "Update of ${ota_image_name} to ${u_part_lbl} partition Done";
+fi;
+
+if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+# Start update of edison-image-edison.hddimg on boot
+setenv ota_image_name edison-image-edison.hddimg
+setenv u_part_lbl boot
+setenv sha1_sum_ref @@sha1_edison-image-edison.hddimg
+
+# Tell user what's going on
+echo " "
+if itest $ota_checked == 1 ; then
+echo "Update of ${ota_image_name} to ${u_part_lbl} partition";
+else
+echo "Validating ${ota_image_name} hash for ${u_part_lbl} partition";
+fi;
+
+# Load partition binary image from update partition to memory
+run ota_load_image ;
+if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+
+# Find partition boot
+run ota_find_partition ;
+if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+
+# Retrieve partition attribute
+run ota_get_partition_attributes ;
+if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+
+# Convert file size in byte to block
+setenv bytesize $filesize ;
+setenv blksize $u_part_blksz ;
+run ota_conv_sizes ;
+
+setenv vb_cmd 'echo "Partition ${u_part_lbl} Start:0x${u_part_start} Size:0x${u_part_sz} BlockSize:0x${u_part_blksz}"; echo "${ota_image_name} size is 0x${filesize} bytes and 0x${num_blk} block"; echo " ";'
+run ota_exec_verbose_cmd ;
+
+if itest $ota_checked == 0 ; then
+ # Test if image fit partition
+ run ota_test_image_and_partition_sizes ;
+ if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+
+ # Verify data integrity
+ run ota_compute_hash;
+ if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+ if itest.s $sha1_sum_ref != $sha1_sum ; then setenv ota_abort_reason "${ota_image_name} hash mismatch ($sha1_sum / $sha1_sum_ref)"; setenv ota_abort 1; fi;
+ if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+else
+ # Write image to partition
+ run ota_mmc_write;
+ if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+
+ # Tell user about the status
+ echo " "
+ echo "Update of ${ota_image_name} to ${u_part_lbl} partition Done";
+fi;
+
+# Start update of edison-image-edison.ext4 on rootfs
+setenv ota_image_name edison-image-edison.ext4
+setenv u_part_lbl rootfs
+setenv sha1_sum_ref @@sha1_edison-image-edison.ext4
+
+# Tell user what's going on
+echo " "
+if itest $ota_checked == 1 ; then
+echo "Update of ${ota_image_name} to ${u_part_lbl} partition";
+else
+echo "Validating ${ota_image_name} hash for ${u_part_lbl} partition";
+fi;
+echo " "
+
+# Load partition binary image from update partition to memory
+run ota_load_image;
+if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+
+# Find partition rootfs
+run ota_find_partition ;
+if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+
+# Retrieve partition attribute
+run ota_get_partition_attributes ;
+if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+
+# Convert file size in byte to block
+setenv bytesize $filesize ;
+setenv blksize $u_part_blksz ;
+run ota_conv_sizes ;
+
+setenv vb_cmd 'echo "Partition ${u_part_lbl} Start:0x${u_part_start} Size:0x${u_part_sz} BlockSize:0x${u_part_blksz}"; echo "${ota_image_name} size is 0x${filesize} bytes and 0x${num_blk} block"; echo " ";'
+run ota_exec_verbose_cmd ;
+
+
+if itest $ota_checked == 0; then
+ # Test if image fit partition
+ run ota_test_image_and_partition_sizes ;
+ if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+
+ # Verify data integrity
+ run ota_compute_hash;
+ if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+ if itest.s $sha1_sum_ref != $sha1_sum ; then setenv ota_abort_reason "$ota_image_name bad hash $sha1_sum != $sha1_sum_ref"; setenv ota_abort 1; fi;
+ if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+else
+ # Write image to partition
+ run ota_mmc_write;
+ if itest $ota_abort == 1 ; then run ota_cleans_script; exit ; fi;
+
+ # Tell user about the status
+ echo " "
+ echo "Update of ${ota_image_name} to ${u_part_lbl} partition Done";
+fi;
+
+run ota_cleans_script;
+
+echo " "
+if itest $ota_checked == 0; then
+ echo "Ota Pakage validated going to process it";
+ setenv ota_checked 1;
+ source $ota_script_addr;
+else
+ # Overall sumup and end of update cycle
+ echo " "
+ echo "Ota Success going to reboot";
+ setenv ota_done 1 ;
+ env delete -f ota_checked;
+ setenv bootargs_target ota-update
+ saveenv
+ exit;
+fi;
diff --git a/utils/flash/pft-config-edison-00.xml b/utils/flash/pft-config-edison-00.xml
new file mode 100644
index 0000000..0323526
--- /dev/null
+++ b/utils/flash/pft-config-edison-00.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<flashfile version="1">
+ <id>system</id>
+ <platform>edison</platform>
+ <gpflag>
+ <value>0x80000007</value>
+ </gpflag>
+ <code_group name="FIRMWARE">
+ <file TYPE="IFWI">
+ <name>edison_ifwi-dbg.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ <file TYPE="FW_DNX">
+ <name>edison_dnx_fwr.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ <file TYPE="OS_DNX">
+ <name>edison_dnx_osr.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ </code_group>
+ <code_group name="BOOTLOADER">
+ <file TYPE="KBOOT">
+ <name>u-boot-edison.img</name>
+ <version>edison</version>
+ </file>
+ </code_group>
+</flashfile>
diff --git a/utils/flash/pft-config-edison-01.xml b/utils/flash/pft-config-edison-01.xml
new file mode 100644
index 0000000..5193b6a
--- /dev/null
+++ b/utils/flash/pft-config-edison-01.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<flashfile version="1">
+ <id>system</id>
+ <platform>edison</platform>
+ <gpflag>
+ <value>0x80000007</value>
+ </gpflag>
+ <code_group name="FIRMWARE">
+ <file TYPE="IFWI">
+ <name>edison_ifwi-dbg-01.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ <file TYPE="FW_DNX">
+ <name>edison_dnx_fwr.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ <file TYPE="OS_DNX">
+ <name>edison_dnx_osr.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ </code_group>
+ <code_group name="BOOTLOADER">
+ <file TYPE="KBOOT">
+ <name>u-boot-edison.img</name>
+ <version>edison</version>
+ </file>
+ </code_group>
+</flashfile>
diff --git a/utils/flash/pft-config-edison-02.xml b/utils/flash/pft-config-edison-02.xml
new file mode 100644
index 0000000..20e4820
--- /dev/null
+++ b/utils/flash/pft-config-edison-02.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<flashfile version="1">
+ <id>system</id>
+ <platform>edison</platform>
+ <gpflag>
+ <value>0x80000007</value>
+ </gpflag>
+ <code_group name="FIRMWARE">
+ <file TYPE="IFWI">
+ <name>edison_ifwi-dbg-02.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ <file TYPE="FW_DNX">
+ <name>edison_dnx_fwr.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ <file TYPE="OS_DNX">
+ <name>edison_dnx_osr.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ </code_group>
+ <code_group name="BOOTLOADER">
+ <file TYPE="KBOOT">
+ <name>u-boot-edison.img</name>
+ <version>edison</version>
+ </file>
+ </code_group>
+</flashfile>
diff --git a/utils/flash/pft-config-edison-03.xml b/utils/flash/pft-config-edison-03.xml
new file mode 100644
index 0000000..acedd8d
--- /dev/null
+++ b/utils/flash/pft-config-edison-03.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<flashfile version="1">
+ <id>system</id>
+ <platform>edison</platform>
+ <gpflag>
+ <value>0x80000007</value>
+ </gpflag>
+ <code_group name="FIRMWARE">
+ <file TYPE="IFWI">
+ <name>edison_ifwi-dbg-03.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ <file TYPE="FW_DNX">
+ <name>edison_dnx_fwr.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ <file TYPE="OS_DNX">
+ <name>edison_dnx_osr.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ </code_group>
+ <code_group name="BOOTLOADER">
+ <file TYPE="KBOOT">
+ <name>u-boot-edison.img</name>
+ <version>edison</version>
+ </file>
+ </code_group>
+</flashfile>
diff --git a/utils/flash/pft-config-edison-04.xml b/utils/flash/pft-config-edison-04.xml
new file mode 100644
index 0000000..13c2794
--- /dev/null
+++ b/utils/flash/pft-config-edison-04.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<flashfile version="1">
+ <id>system</id>
+ <platform>edison</platform>
+ <gpflag>
+ <value>0x80000007</value>
+ </gpflag>
+ <code_group name="FIRMWARE">
+ <file TYPE="IFWI">
+ <name>edison_ifwi-dbg-04.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ <file TYPE="FW_DNX">
+ <name>edison_dnx_fwr.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ <file TYPE="OS_DNX">
+ <name>edison_dnx_osr.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ </code_group>
+ <code_group name="BOOTLOADER">
+ <file TYPE="KBOOT">
+ <name>u-boot-edison.img</name>
+ <version>edison</version>
+ </file>
+ </code_group>
+</flashfile>
diff --git a/utils/flash/pft-config-edison-05.xml b/utils/flash/pft-config-edison-05.xml
new file mode 100644
index 0000000..154bcdc
--- /dev/null
+++ b/utils/flash/pft-config-edison-05.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<flashfile version="1">
+ <id>system</id>
+ <platform>edison</platform>
+ <gpflag>
+ <value>0x80000007</value>
+ </gpflag>
+ <code_group name="FIRMWARE">
+ <file TYPE="IFWI">
+ <name>edison_ifwi-dbg-05.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ <file TYPE="FW_DNX">
+ <name>edison_dnx_fwr.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ <file TYPE="OS_DNX">
+ <name>edison_dnx_osr.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ </code_group>
+ <code_group name="BOOTLOADER">
+ <file TYPE="KBOOT">
+ <name>u-boot-edison.img</name>
+ <version>edison</version>
+ </file>
+ </code_group>
+</flashfile>
diff --git a/utils/flash/pft-config-edison-06.xml b/utils/flash/pft-config-edison-06.xml
new file mode 100644
index 0000000..b5a0f17
--- /dev/null
+++ b/utils/flash/pft-config-edison-06.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<flashfile version="1">
+ <id>system</id>
+ <platform>edison</platform>
+ <gpflag>
+ <value>0x80000007</value>
+ </gpflag>
+ <code_group name="FIRMWARE">
+ <file TYPE="IFWI">
+ <name>edison_ifwi-dbg-06.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ <file TYPE="FW_DNX">
+ <name>edison_dnx_fwr.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ <file TYPE="OS_DNX">
+ <name>edison_dnx_osr.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ </code_group>
+ <code_group name="BOOTLOADER">
+ <file TYPE="KBOOT">
+ <name>u-boot-edison.img</name>
+ <version>edison</version>
+ </file>
+ </code_group>
+</flashfile>
diff --git a/utils/flash/pft-config-edison.xml b/utils/flash/pft-config-edison.xml
new file mode 100644
index 0000000..a27ef4e
--- /dev/null
+++ b/utils/flash/pft-config-edison.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<flashfile version="1">
+ <id>system</id>
+ <platform>edison</platform>
+ <gpflag>
+ <value>0x80000007</value>
+ </gpflag>
+ <code_group name="FIRMWARE">
+ <file TYPE="IFWI">
+ <name>edison_ifwi-dbg-00.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ <file TYPE="FW_DNX">
+ <name>edison_dnx_fwr.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ <file TYPE="OS_DNX">
+ <name>edison_dnx_osr.bin</name>
+ <version>00ED.1D01</version>
+ </file>
+ </code_group>
+ <code_group name="BOOTLOADER">
+ <file TYPE="KBOOT">
+ <name>u-boot-edison.img</name>
+ <version>edison</version>
+ </file>
+ </code_group>
+</flashfile>
diff --git a/utils/flash/postBuild.sh b/utils/flash/postBuild.sh
new file mode 100755
index 0000000..7f44fdc
--- /dev/null
+++ b/utils/flash/postBuild.sh
@@ -0,0 +1,89 @@
+#!/bin/bash
+
+# On ubuntu you need to install libqt4-core:i386 and libqt4-gui:i386 to run this script
+
+top_repo_dir=$(dirname $(dirname $(dirname $(dirname $(readlink -f $0)))))
+
+build_dir=""
+if [ $# -eq 0 ]; then
+ build_dir=$top_repo_dir/build
+else
+ build_dir=$1
+fi
+
+# Cleanup previous builds
+rm -rf $build_dir/toFlash/*
+mkdir -p $build_dir/toFlash
+
+# Copy boot partition (contains kernel and ramdisk)
+cp $build_dir/tmp/deploy/images/edison/edison-image-edison.hddimg $build_dir/toFlash/
+
+# Copy u-boot
+cp $build_dir/tmp/deploy/images/edison/u-boot-edison.img $build_dir/toFlash/
+cp $build_dir/tmp/deploy/images/edison/u-boot-edison.bin $build_dir/toFlash/
+
+# Copy u-boot environments files binary
+cp -R $build_dir/tmp/deploy/images/edison/u-boot-envs $build_dir/toFlash
+
+# Copy IFWI
+cp $top_repo_dir/device-software/utils/flash/ifwi/edison/*.bin $build_dir/toFlash/
+
+# build Ifwi file for using in DFU mode
+# Remove FUP footer (144 bytes) as it's not needed when we directly write to boot partitions
+for ifwi in $build_dir/toFlash/*ifwi*.bin ;
+do
+ dfu_ifwi_name="`basename $ifwi .bin`-dfu.bin"
+ dd if=$ifwi of=$build_dir/toFlash/$dfu_ifwi_name bs=4194304 count=1
+done
+
+# Copy rootfs
+cp $build_dir/tmp/deploy/images/edison/edison-image-edison.ext4 $build_dir/toFlash/
+
+# Copy symbols files
+mkdir -p $build_dir/symbols
+cp $build_dir/tmp/deploy/images/edison/vmlinux $build_dir/symbols/
+cp $build_dir/tmp/deploy/images/edison/u-boot-edison.bin $build_dir/symbols/
+
+
+# copy phoneflashtool xml file
+cp $top_repo_dir/device-software/utils/flash/pft-config-edison.xml $build_dir/toFlash/
+
+# Copy flashing script
+cp $top_repo_dir/device-software/utils/flash/flashall.sh $build_dir/toFlash/
+cp $top_repo_dir/device-software/utils/flash/flashall.bat $build_dir/toFlash/
+cp $top_repo_dir/device-software/utils/flash/filter-dfu-out.js $build_dir/toFlash/
+
+# Look for mkimage tool path
+mkimage_tool_path=$(find $top_repo_dir/u-boot -name mkimage)
+if [ -z $mkimage_tool_path ]; then
+ mkimage_tool_path=$(find $build_dir/tmp/work/edison-poky-linux/u-boot -name mkimage)
+ if [ -z "$mkimage_tool_path" ]; then
+ echo "Error : ota_update.scr creation failed, mkimage tool not found"
+ exit 0
+ fi
+fi
+
+# copy OTA update
+cp $top_repo_dir/device-software/utils/flash/ota_update.cmd $build_dir/toFlash/
+
+# Preprocess OTA script
+# Compute sha1sum of each file under build/toFlash and build an array containing
+# @@sha1_filename:SHA1VALUE
+pth_out=$build_dir/toFlash/
+tab_size=$(for fil in $(find $pth_out -maxdepth 1 -type f -printf "%f\n") ; do sha1_hex=$(sha1sum "$pth_out$fil" | cut -c -40); echo "@@sha1_$fil:$sha1_hex" ; done ;)
+# iterate the array and do tag -> value substitution in ota_update.cmd
+for elem in $tab_size ; do IFS=':' read -a fld_elem <<< "$elem"; sed -i "s/${fld_elem[0]}/${fld_elem[1]}/g" $build_dir/toFlash/ota_update.cmd; done;
+
+# Convert OTA script to u-boot script
+$mkimage_tool_path -a 0x10000 -T script -C none -n 'Edison Updater script' -d $build_dir/toFlash/ota_update.cmd $build_dir/toFlash/ota_update.scr
+
+# Supress Preprocessed OTA script
+rm $build_dir/toFlash/ota_update.cmd
+
+# Generates a formatted list of all packages included in the image
+awk '{print $1 " " $3}' $build_dir/tmp/deploy/images/edison/edison-image-edison.manifest > $build_dir/toFlash/package-list.txt
+
+echo "**** Done ***"
+echo "Files ready to flash in $build_dir/toFlash/"
+echo "Run the flashall script there to start flashing."
+echo "*************"
diff --git a/utils/generate-recipes-patches.sh b/utils/generate-recipes-patches.sh
new file mode 100755
index 0000000..3667fdb
--- /dev/null
+++ b/utils/generate-recipes-patches.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+
+# Refresh the patches for various git projects used in the developer environment
+# The patches are used in the external Yocto recipes seen by users
+
+echo "*** Will refresh the patches for various git projects ***"
+
+top_repo_dir=$(dirname $(dirname $(dirname $(readlink -f $0))))
+
+
+# Create a squashed patch between the passed ref and the HEAD of passed branch name
+# $1 REF from which to diff
+function create_squashed_patch {
+ # Make sure we do have a local version of the branch (with repo we are usually on detached HEAD)
+ git branch edisonhead
+ # Create a temporary branch tmpsquash from our REF and create the patch on the top of it
+ git branch tmpsquash $1
+ git checkout tmpsquash
+ git merge --squash edisonhead
+ git commit -m"Squashed all commits from upstream to Edison" > /dev/null
+ git format-patch edisonhead --stdout > upstream_to_edison.patch
+ # Clean up by suppressing both branches
+ git checkout edisonhead
+ git branch -D tmpsquash
+ repo abandon edisonhead
+}
+
+
+###############################################################################
+# Special treatment for u-boot
+# Rev dda0dbfc69f3d560c87f5be85f127ed862ea6721 is the revision where we diverged from u-boot
+# Create the mega patch by squashing all commits between upstream yocto u-boot code and Edison version
+
+echo "*** Create squashed patch of u-boot changes ***"
+cd $top_repo_dir/u-boot
+
+create_squashed_patch dda0dbfc69f3d560c87f5be85f127ed862ea6721
+# And move it in our new recipe
+mv $top_repo_dir/u-boot/upstream_to_edison.patch $top_repo_dir/device-software/meta-edison/recipes-bsp/u-boot/files/
+
+###############################################################################
+# Special treatment for the linux-kernel: we switch back to basic yocto recipe
+# with the addition of our huge patch and our defconfig
+# Rev c03195ed is the revision where we diverged from yocto 1.5.1 upstream kernels
+# Create the mega patch by squashing all commits between upstream yocto kernel and Edison version
+
+echo "*** Create squashed patch of edison linux kernel ***"
+cd $top_repo_dir/linux-kernel
+# Make sure we grab the REFs from base branch on Yocto servers
+git fetch git://git.yoctoproject.org/linux-yocto-3.10.git standard/base
+
+create_squashed_patch c03195ed6e3066494e3fb4be69154a57066e845b
+# And move it with our defconfig in our special linux kernel recipe (based on standard yocto 3.10 kernel)
+mv $top_repo_dir/linux-kernel/upstream_to_edison.patch $top_repo_dir/device-software/meta-edison/recipes-kernel/linux/files/
+cp $top_repo_dir/linux-kernel/arch/x86/configs/i386_edison_defconfig $top_repo_dir/device-software/meta-edison/recipes-kernel/linux/files/defconfig
+
diff --git a/utils/handle_bash_func.patch b/utils/handle_bash_func.patch
new file mode 100755
index 0000000..f4411bc
--- /dev/null
+++ b/utils/handle_bash_func.patch
@@ -0,0 +1,41 @@
+commit becb32bb30a9fc8ffe3bf59bbe346297a5a8899a
+Author: Richard Purdie <richard.purdie@linuxfoundation.org>
+Date: Mon Dec 8 16:37:26 2014 +0000
+
+ bitbake: data: Handle BASH_FUNC shellshock implication
+
+ The shellshock patches changed the way bash functions are exported.
+ Unfortunately different distros used slightly different formats,
+ Fedora went with BASH_FUNC_XXX()=() { echo foo; } and Ubuntu went with
+ BASH_FUNC_foo%%=() { echo foo; }.
+
+ The former causes errors in dealing with out output from emit_env,
+ the functions are not exported in either case any more.
+
+ This patch handles things so the functions work as expected in either
+ case.
+
+ [YOCTO #6880]
+
+ (Bitbake rev: 4d4baf20487271aa83bd9f1a778e4ea9af6f6681)
+
+ Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
+
+diff --git a/bitbake/lib/bb/data.py b/bitbake/lib/bb/data.py
+index 91b1eb1..eb628c7 100644
+--- a/bitbake/lib/bb/data.py
++++ b/bitbake/lib/bb/data.py
+@@ -219,6 +219,13 @@ def emit_var(var, o=sys.__stdout__, d = init(), all=False):
+
+ val = str(val)
+
++ if varExpanded.startswith("BASH_FUNC_"):
++ varExpanded = varExpanded[10:-2]
++ val = val[3:] # Strip off "() "
++ o.write("%s() %s\n" % (varExpanded, val))
++ o.write("export -f %s\n" % (varExpanded))
++ return 1
++
+ if func:
+ # NOTE: should probably check for unbalanced {} within the var
+ o.write("%s() {\n%s\n}\n" % (varExpanded, val))
diff --git a/utils/invalidate_sstate.sh b/utils/invalidate_sstate.sh
new file mode 100755
index 0000000..8947c48
--- /dev/null
+++ b/utils/invalidate_sstate.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# This script will call a couple of bitbake targets to clean up the sstate
+# (Yocto cache) for some projects.
+# Calling this script before each build allows to work around some limitations
+# of using the external_src / repo / gerrit workflow.
+
+top_repo_dir=$(dirname $(dirname $(dirname $(readlink -f $0))))
+
+if [ $# -eq 0 ]; then
+ cd $top_repo_dir/build
+else
+ cd $1
+fi
+
+
+bitbake -c cleansstate virtual/kernel
+bitbake -c cleansstate u-boot
+bitbake -c cleansstate bcm43340-mod
+bitbake -c cleansstate oobe
diff --git a/utils/mingw-daisy.tar.bz2 b/utils/mingw-daisy.tar.bz2
new file mode 100644
index 0000000..05a21a5
--- /dev/null
+++ b/utils/mingw-daisy.tar.bz2
Binary files differ
diff --git a/utils/poky-daisy-11.0.1.tar.bz2 b/utils/poky-daisy-11.0.1.tar.bz2
new file mode 100644
index 0000000..501faca
--- /dev/null
+++ b/utils/poky-daisy-11.0.1.tar.bz2
Binary files differ
diff --git a/utils/sdk-populate-clean-broken-links.patch b/utils/sdk-populate-clean-broken-links.patch
new file mode 100644
index 0000000..a0a8561
--- /dev/null
+++ b/utils/sdk-populate-clean-broken-links.patch
@@ -0,0 +1,29 @@
+diff --git a/meta/lib/oe/sdk.py b/meta/lib/oe/sdk.py
+index ca349c4..576cae8 100644
+--- a/meta/lib/oe/sdk.py
++++ b/meta/lib/oe/sdk.py
+@@ -49,6 +49,24 @@ class Sdk(object):
+ self.d.getVar('libdir_nativesdk', True).strip('/'),
+ "*.la"))
+
++ # Remove any broken links in sdk target sysroot
++ bb.note("SDK scanning Link in %s" % self.sdk_target_sysroot)
++ lnk_pths = []
++ for root, dirs, files in os.walk(self.sdk_target_sysroot):
++ lnk_pths += [os.path.join(root, d) for d in dirs
++ if os.path.islink(os.path.join(root, d))]
++ lnk_pths += [os.path.join(root, f) for f in files
++ if os.path.islink(os.path.join(root, f))]
++
++ for lnk in lnk_pths:
++ try:
++ os.stat(lnk)
++ except OSError:
++ bb.note("SDK Broken Link Removing: %s -> %s" %
++ (lnk, os.readlink(lnk)))
++ os.unlink(lnk)
++ pass
++
+ # Link the ld.so.cache file into the hosts filesystem
+ link_name = os.path.join(self.sdk_output, self.sdk_native_path,
+ self.sysconfdir, "ld.so.cache")