diff options
24 files changed, 3784 insertions, 1409 deletions
diff --git a/conf/machine/quark.conf b/conf/machine/quark.conf index 0b85b81..476ffef 100644 --- a/conf/machine/quark.conf +++ b/conf/machine/quark.conf @@ -14,7 +14,7 @@ MACHINE_ESSENTIAL_EXTRA_RDEPENDS = "" MACHINE_FEATURES = "efi usb pci" -SERIAL_CONSOLE = "115200 ttyS1" +SERIAL_CONSOLE = "115200 ttyQRK1" #SERIAL_CONSOLES = "115200;ttyS0 115200;ttyS1" EXTRA_IMAGEDEPENDS = "grub" diff --git a/recipes-kernel/linux/files/0001-tty-don-t-deadlock-while-flushing-workqueue-quark.patch b/recipes-kernel/linux/files/0001-tty-don-t-deadlock-while-flushing-workqueue-quark.patch index 4d0fd37..b4c3b77 100644 --- a/recipes-kernel/linux/files/0001-tty-don-t-deadlock-while-flushing-workqueue-quark.patch +++ b/recipes-kernel/linux/files/0001-tty-don-t-deadlock-while-flushing-workqueue-quark.patch @@ -107,8 +107,8 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> (cherry picked from commit 852e4a8152b427c3f318bb0e1b5e938d64dcdc32) --- - drivers/tty/tty_ldisc.c | 10 +++++----- - 1 files changed, 5 insertions(+), 5 deletions(-) + drivers/tty/tty_ldisc.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index c578229..78f1be2 100644 @@ -137,6 +137,3 @@ index c578229..78f1be2 100644 if (o_tty) tty_ldisc_kill(o_tty); --- -1.7.4.1 - diff --git a/recipes-kernel/linux/files/0002-driver-core-constify-data-for-class_find_devic-quark.patch b/recipes-kernel/linux/files/0002-driver-core-constify-data-for-class_find_devic-quark.patch index bf633cd..9829454 100644 --- a/recipes-kernel/linux/files/0002-driver-core-constify-data-for-class_find_devic-quark.patch +++ b/recipes-kernel/linux/files/0002-driver-core-constify-data-for-class_find_devic-quark.patch @@ -23,25 +23,25 @@ Acked-by: Grant Likely <grant.likely@secretlab.ca> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> (cherry picked from commit 9f3b795a626ee79574595e06d1437fe0c7d51d29) --- - drivers/base/class.c | 4 ++-- - drivers/base/core.c | 4 ++-- - drivers/gpio/gpiolib.c | 2 +- - drivers/isdn/mISDN/core.c | 4 ++-- - drivers/net/phy/mdio_bus.c | 2 +- - drivers/power/power_supply_core.c | 4 ++-- - drivers/rtc/interface.c | 6 +++--- - drivers/scsi/hosts.c | 4 ++-- - drivers/scsi/osd/osd_uld.c | 26 +++++++++----------------- - drivers/scsi/scsi_transport_iscsi.c | 4 ++-- - drivers/spi/spi.c | 4 ++-- - drivers/uwb/lc-rc.c | 21 ++++++++++----------- - include/linux/device.h | 4 ++-- - include/linux/power_supply.h | 2 +- - include/linux/rtc.h | 2 +- - init/do_mounts.c | 4 ++-- - kernel/power/suspend_test.c | 11 +++++------ - net/ieee802154/wpan-class.c | 5 ++--- - net/nfc/core.c | 4 ++-- + drivers/base/class.c | 4 ++-- + drivers/base/core.c | 4 ++-- + drivers/gpio/gpiolib.c | 2 +- + drivers/isdn/mISDN/core.c | 4 ++-- + drivers/net/phy/mdio_bus.c | 2 +- + drivers/power/power_supply_core.c | 4 ++-- + drivers/rtc/interface.c | 6 +++--- + drivers/scsi/hosts.c | 4 ++-- + drivers/scsi/osd/osd_uld.c | 26 +++++++++----------------- + drivers/scsi/scsi_transport_iscsi.c | 4 ++-- + drivers/spi/spi.c | 4 ++-- + drivers/uwb/lc-rc.c | 21 ++++++++++----------- + include/linux/device.h | 4 ++-- + include/linux/power_supply.h | 2 +- + include/linux/rtc.h | 2 +- + init/do_mounts.c | 4 ++-- + kernel/power/suspend_test.c | 11 +++++------ + net/ieee802154/wpan-class.c | 5 ++--- + net/nfc/core.c | 4 ++-- 19 files changed, 53 insertions(+), 64 deletions(-) diff --git a/drivers/base/class.c b/drivers/base/class.c @@ -490,6 +490,3 @@ index aa64ea4..0f4a6de 100644 return dev->idx == *idx; } --- -1.7.4.1 - diff --git a/recipes-kernel/linux/files/0003-TTY-mark-tty_get_device-call-with-the-proper-c-quark.patch b/recipes-kernel/linux/files/0003-TTY-mark-tty_get_device-call-with-the-proper-c-quark.patch index ab3eb1e..7dc7701 100644 --- a/recipes-kernel/linux/files/0003-TTY-mark-tty_get_device-call-with-the-proper-c-quark.patch +++ b/recipes-kernel/linux/files/0003-TTY-mark-tty_get_device-call-with-the-proper-c-quark.patch @@ -1,7 +1,8 @@ From xxxx Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Date: Wed, 6 Feb 2013 15:59:18 -0800 -Subject: [PATCH 03/21] TTY: mark tty_get_device call with the proper const values +Subject: [PATCH 03/21] TTY: mark tty_get_device call with the proper const + values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -14,8 +15,8 @@ Cc: Michał Mirosław <mirq-linux@rere.qmqm.pl> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> (cherry picked from commit 6e9430ac57e8c1f41ab24ef7fbb3d452c7eb7246) --- - drivers/tty/tty_io.c | 4 ++-- - 1 files changed, 2 insertions(+), 2 deletions(-) + drivers/tty/tty_io.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index da9fde8..6b20fd6 100644 @@ -33,6 +34,3 @@ index da9fde8..6b20fd6 100644 return dev->devt == *devt; } --- -1.7.4.1 - diff --git a/recipes-kernel/linux/files/0004-pwm-Add-sysfs-interface-quark.patch b/recipes-kernel/linux/files/0004-pwm-Add-sysfs-interface-quark.patch index fb4ee30..f19eb64 100644 --- a/recipes-kernel/linux/files/0004-pwm-Add-sysfs-interface-quark.patch +++ b/recipes-kernel/linux/files/0004-pwm-Add-sysfs-interface-quark.patch @@ -26,13 +26,13 @@ Cc: Rob Landley <rob@landley.net> Signed-off-by: Thierry Reding <thierry.reding@gmail.com> (cherry picked from commit 76abbdde2d95a3807d0dc6bf9f84d03d0dbd4f3d) --- - Documentation/ABI/testing/sysfs-class-pwm | 79 +++++++ - Documentation/pwm.txt | 37 +++ - drivers/pwm/Kconfig | 4 + - drivers/pwm/Makefile | 1 + - drivers/pwm/core.c | 25 ++- - drivers/pwm/sysfs.c | 352 +++++++++++++++++++++++++++++ - include/linux/pwm.h | 29 +++- + Documentation/ABI/testing/sysfs-class-pwm | 79 +++++++ + Documentation/pwm.txt | 37 ++++ + drivers/pwm/Kconfig | 4 + + drivers/pwm/Makefile | 1 + + drivers/pwm/core.c | 25 ++- + drivers/pwm/sysfs.c | 352 ++++++++++++++++++++++++++++++ + include/linux/pwm.h | 29 ++- 7 files changed, 524 insertions(+), 3 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-class-pwm create mode 100644 drivers/pwm/sysfs.c @@ -679,6 +679,3 @@ index 6d661f3..6842d11 100644 +#endif /* CONFIG_PWM_SYSFS */ + #endif /* __LINUX_PWM_H */ --- -1.7.4.1 - diff --git a/recipes-kernel/linux/files/0005-drivers-pwm-sysfs.c-add-export.h-RTC-50404-quark.patch b/recipes-kernel/linux/files/0005-drivers-pwm-sysfs.c-add-export.h-RTC-50404-quark.patch index 3d2ade0..8d44b83 100644 --- a/recipes-kernel/linux/files/0005-drivers-pwm-sysfs.c-add-export.h-RTC-50404-quark.patch +++ b/recipes-kernel/linux/files/0005-drivers-pwm-sysfs.c-add-export.h-RTC-50404-quark.patch @@ -6,8 +6,8 @@ Subject: [PATCH 05/21] drivers/pwm/sysfs.c: add export.h - RTC #50404 Resolve THIS_MODULE macro. (cherry picked from commit b594e3ef2c9f7a2c61188e76a1c228f1d30556eb) --- - drivers/pwm/sysfs.c | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) + drivers/pwm/sysfs.c | 1 + + 1 file changed, 1 insertion(+) diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c index 8ca5de3..4cd6d78 100644 @@ -21,6 +21,3 @@ index 8ca5de3..4cd6d78 100644 #include <linux/device.h> #include <linux/mutex.h> #include <linux/err.h> --- -1.7.4.1 - diff --git a/recipes-kernel/linux/files/0006-core-Quark-patch-quark.patch b/recipes-kernel/linux/files/0006-core-Quark-patch-quark.patch index 81841a5..37c57f6 100644 --- a/recipes-kernel/linux/files/0006-core-Quark-patch-quark.patch +++ b/recipes-kernel/linux/files/0006-core-Quark-patch-quark.patch @@ -1,23 +1,25 @@ From xxxx Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue <bryan.odonoghue@intel.com> -Date: Thu, 13 Feb 2014 16:41:02 +0000 +Date: Fri, 18 Apr 2014 10:11:00 +0100 Subject: [PATCH 06/21] core Quark patch --- - arch/x86/Kconfig | 23 + + arch/x86/Kconfig | 25 +- arch/x86/include/asm/imr.h | 22 + - arch/x86/include/asm/qrk.h | 85 + + arch/x86/include/asm/qrk.h | 78 + arch/x86/include/asm/serial.h | 6 + arch/x86/kernel/cpu/intel.c | 11 + arch/x86/kernel/setup.c | 5 +- arch/x86/platform/efi/efi-bgrt.c | 20 +- include/linux/efi-bgrt.h | 2 + - 8 files changed, 168 insertions(+), 6 deletions(-) + meta/cfg/kernel-cache/bsp/quark/quark.cfg | 3063 +++++++++++++++++++++++++++++ + 9 files changed, 3225 insertions(+), 7 deletions(-) create mode 100644 arch/x86/include/asm/imr.h create mode 100644 arch/x86/include/asm/qrk.h + create mode 100644 meta/cfg/kernel-cache/bsp/quark/quark.cfg diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index 0694d09..2c881ac 100644 +index 0694d09..a10027f 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -417,6 +417,15 @@ config X86_INTEL_CE @@ -50,6 +52,15 @@ index 0694d09..2c881ac 100644 config X86_VISWS bool "SGI 320/540 (Visual Workstation)" depends on X86_32 && PCI && X86_MPPARSE && PCI_GODIRECT +@@ -1169,7 +1185,7 @@ config ARCH_PHYS_ADDR_T_64BIT + + config ARCH_DMA_ADDR_T_64BIT + def_bool y +- depends on X86_64 || HIGHMEM64G ++ depends on X86_64 || HIGHMEM64G && !INTEL_QUARK_X1000_SOC + + config DIRECT_GBPAGES + bool "Enable 1GB pages for kernel pagetables" if EXPERT @@ -1524,6 +1540,13 @@ config EFI_STUB See Documentation/x86/efi-stub.txt for more information. @@ -94,28 +105,21 @@ index 0000000..876d499 +#endif /* _ASM_X86_IMR_H */ diff --git a/arch/x86/include/asm/qrk.h b/arch/x86/include/asm/qrk.h new file mode 100644 -index 0000000..bd65b86 +index 0000000..ed4dab4 --- /dev/null +++ b/arch/x86/include/asm/qrk.h -@@ -0,0 +1,85 @@ +@@ -0,0 +1,78 @@ +/* + * Copyright(c) 2013 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. ++ * 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. + * -+ * 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. -+ * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +#ifndef _ASM_X86_QRK_H +#define _ASM_X86_QRK_H @@ -316,4 +320,4 @@ index 051b21f..165426b 100644 +static inline bool efi_bgrt_probe(void) { return false; } #endif /* !CONFIG_ACPI_BGRT */ - + diff --git a/recipes-kernel/linux/files/0007-Quark-Platform-Code-quark.patch b/recipes-kernel/linux/files/0007-Quark-Platform-Code-quark.patch index 21f2d7f..d8797fc 100644 --- a/recipes-kernel/linux/files/0007-Quark-Platform-Code-quark.patch +++ b/recipes-kernel/linux/files/0007-Quark-Platform-Code-quark.patch @@ -1,34 +1,35 @@ From xxxx Mon Sep 17 00:00:00 2001 From: Quark Team <noreply@intel.com> -Date: Wed, 26 Feb 2014 14:40:08 +0000 +Date: Thu, 10 Apr 2014 11:58:52 +0100 Subject: [PATCH 07/21] Quark Platform Code --- drivers/platform/x86/Kconfig | 4 + drivers/platform/x86/Makefile | 1 + drivers/platform/x86/quark/Kconfig | 41 + - drivers/platform/x86/quark/Makefile | 14 + - drivers/platform/x86/quark/intel_qrk_audio_ctrl.c | 514 +++++++++ - drivers/platform/x86/quark/intel_qrk_audio_ctrl.h | 45 + - drivers/platform/x86/quark/intel_qrk_board_data.c | 260 +++++ - drivers/platform/x86/quark/intel_qrk_esram.c | 1144 ++++++++++++++++++++ - drivers/platform/x86/quark/intel_qrk_esram.h | 107 ++ - drivers/platform/x86/quark/intel_qrk_esram_test.c | 602 ++++++++++ - drivers/platform/x86/quark/intel_qrk_esram_test.h | 43 + - drivers/platform/x86/quark/intel_qrk_imr.c | 697 ++++++++++++ - drivers/platform/x86/quark/intel_qrk_imr.h | 157 +++ - drivers/platform/x86/quark/intel_qrk_imr_kernel.c | 139 +++ - drivers/platform/x86/quark/intel_qrk_imr_test.c | 357 ++++++ - .../x86/quark/intel_qrk_plat_clanton_hill.c | 226 ++++ - .../x86/quark/intel_qrk_plat_clanton_peak.c | 227 ++++ - .../platform/x86/quark/intel_qrk_plat_cross_hill.c | 392 +++++++ - .../platform/x86/quark/intel_qrk_plat_galileo.c | 398 +++++++ - .../platform/x86/quark/intel_qrk_plat_kips_bay.c | 176 +++ - drivers/platform/x86/quark/intel_qrk_sb.c | 253 +++++ - drivers/platform/x86/quark/intel_qrk_thermal.c | 360 ++++++ - include/linux/intel_qrk_sb.h | 92 ++ - include/linux/platform_data/quark.h | 44 + - 24 files changed, 6293 insertions(+), 0 deletions(-) + drivers/platform/x86/quark/Makefile | 15 + + drivers/platform/x86/quark/intel_qrk_audio_ctrl.c | 507 +++++++++ + drivers/platform/x86/quark/intel_qrk_audio_ctrl.h | 38 + + drivers/platform/x86/quark/intel_qrk_board_data.c | 257 +++++ + drivers/platform/x86/quark/intel_qrk_esram.c | 1137 ++++++++++++++++++++ + drivers/platform/x86/quark/intel_qrk_esram.h | 100 ++ + drivers/platform/x86/quark/intel_qrk_esram_test.c | 595 ++++++++++ + drivers/platform/x86/quark/intel_qrk_esram_test.h | 36 + + drivers/platform/x86/quark/intel_qrk_imr.c | 690 ++++++++++++ + drivers/platform/x86/quark/intel_qrk_imr.h | 150 +++ + drivers/platform/x86/quark/intel_qrk_imr_kernel.c | 132 +++ + drivers/platform/x86/quark/intel_qrk_imr_test.c | 350 ++++++ + .../x86/quark/intel_qrk_plat_clanton_hill.c | 219 ++++ + .../x86/quark/intel_qrk_plat_clanton_peak.c | 220 ++++ + .../platform/x86/quark/intel_qrk_plat_cross_hill.c | 430 ++++++++ + .../platform/x86/quark/intel_qrk_plat_galileo.c | 391 +++++++ + .../x86/quark/intel_qrk_plat_galileo_gen2.c | 392 +++++++ + .../platform/x86/quark/intel_qrk_plat_kips_bay.c | 169 +++ + drivers/platform/x86/quark/intel_qrk_sb.c | 246 +++++ + drivers/platform/x86/quark/intel_qrk_thermal.c | 353 ++++++ + include/linux/intel_qrk_sb.h | 85 ++ + include/linux/platform_data/quark.h | 37 + + 25 files changed, 6595 insertions(+) create mode 100644 drivers/platform/x86/quark/Kconfig create mode 100644 drivers/platform/x86/quark/Makefile create mode 100644 drivers/platform/x86/quark/intel_qrk_audio_ctrl.c @@ -46,6 +47,7 @@ Subject: [PATCH 07/21] Quark Platform Code create mode 100644 drivers/platform/x86/quark/intel_qrk_plat_clanton_peak.c create mode 100644 drivers/platform/x86/quark/intel_qrk_plat_cross_hill.c create mode 100644 drivers/platform/x86/quark/intel_qrk_plat_galileo.c + create mode 100644 drivers/platform/x86/quark/intel_qrk_plat_galileo_gen2.c create mode 100644 drivers/platform/x86/quark/intel_qrk_plat_kips_bay.c create mode 100644 drivers/platform/x86/quark/intel_qrk_sb.c create mode 100644 drivers/platform/x86/quark/intel_qrk_thermal.c @@ -125,16 +127,17 @@ index 0000000..0e2c722 + diff --git a/drivers/platform/x86/quark/Makefile b/drivers/platform/x86/quark/Makefile new file mode 100644 -index 0000000..0a03469 +index 0000000..8c917a5 --- /dev/null +++ b/drivers/platform/x86/quark/Makefile -@@ -0,0 +1,14 @@ +@@ -0,0 +1,15 @@ +obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_qrk_board_data.o +obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_qrk_plat_clanton_hill.o +obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_qrk_plat_clanton_peak.o +obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_qrk_plat_cross_hill.o +obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_qrk_plat_kips_bay.o +obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_qrk_plat_galileo.o ++obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_qrk_plat_galileo_gen2.o +obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_qrk_sb.o +obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_qrk_imr.o +obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_qrk_imr_kernel.o @@ -145,30 +148,23 @@ index 0000000..0a03469 +obj-$(CONFIG_INTEL_QRK_AUDIO_CTRL) += intel_qrk_audio_ctrl.o diff --git a/drivers/platform/x86/quark/intel_qrk_audio_ctrl.c b/drivers/platform/x86/quark/intel_qrk_audio_ctrl.c new file mode 100644 -index 0000000..ffc3791 +index 0000000..8d03f76 --- /dev/null +++ b/drivers/platform/x86/quark/intel_qrk_audio_ctrl.c -@@ -0,0 +1,514 @@ +@@ -0,0 +1,507 @@ +/* + * Intel Quark platform audio control driver + * + * Copyright(c) 2013 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 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 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. -+ * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + * + * The Intel Clanton Hill platform hardware design includes an audio subsystem + * with a number of interconnected audio interfaces. This driver enables @@ -665,30 +661,23 @@ index 0000000..ffc3791 +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/platform/x86/quark/intel_qrk_audio_ctrl.h b/drivers/platform/x86/quark/intel_qrk_audio_ctrl.h new file mode 100644 -index 0000000..581d0e2 +index 0000000..d4f05ad --- /dev/null +++ b/drivers/platform/x86/quark/intel_qrk_audio_ctrl.h -@@ -0,0 +1,45 @@ +@@ -0,0 +1,38 @@ +/* + * Intel Quark platform audio control driver + * + * Copyright(c) 2013 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. ++ * 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. + * -+ * 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. -+ * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + * + * See intel_qrk_audio_ctrl.c for a detailed description + * @@ -716,28 +705,21 @@ index 0000000..581d0e2 +#endif /* __INTEL_QRK_AUDIO_CTRL_H__ */ diff --git a/drivers/platform/x86/quark/intel_qrk_board_data.c b/drivers/platform/x86/quark/intel_qrk_board_data.c new file mode 100644 -index 0000000..db7f76a +index 0000000..c9d4f99 --- /dev/null +++ b/drivers/platform/x86/quark/intel_qrk_board_data.c -@@ -0,0 +1,260 @@ +@@ -0,0 +1,257 @@ +/* + * Copyright(c) 2013 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * 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. + * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +/* + * Intel Quark Legacy Platform Data accessor layer @@ -849,6 +831,10 @@ index 0000000..db7f76a + .name = "Galileo", + .id = -1, + }, ++ { ++ .name = "GalileoGen2", ++ .id = -1, ++ }, + +}; + @@ -982,28 +968,21 @@ index 0000000..db7f76a + diff --git a/drivers/platform/x86/quark/intel_qrk_esram.c b/drivers/platform/x86/quark/intel_qrk_esram.c new file mode 100644 -index 0000000..55adb41 +index 0000000..62ae521 --- /dev/null +++ b/drivers/platform/x86/quark/intel_qrk_esram.c -@@ -0,0 +1,1144 @@ +@@ -0,0 +1,1137 @@ +/* + * Copyright(c) 2013 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * 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. + * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +/* + * Intel Quark eSRAM overlay driver @@ -2132,28 +2111,21 @@ index 0000000..55adb41 + diff --git a/drivers/platform/x86/quark/intel_qrk_esram.h b/drivers/platform/x86/quark/intel_qrk_esram.h new file mode 100644 -index 0000000..71aaba1 +index 0000000..a4c9636 --- /dev/null +++ b/drivers/platform/x86/quark/intel_qrk_esram.h -@@ -0,0 +1,107 @@ +@@ -0,0 +1,100 @@ +/* + * Copyright(c) 2013 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 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 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. -+ * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +/* + * Intel Quark eSRAM overlay driver @@ -2245,28 +2217,21 @@ index 0000000..71aaba1 +#endif /* __INTEL_QRK_ESRAM_H__ */ diff --git a/drivers/platform/x86/quark/intel_qrk_esram_test.c b/drivers/platform/x86/quark/intel_qrk_esram_test.c new file mode 100644 -index 0000000..544ad57 +index 0000000..c337dc5 --- /dev/null +++ b/drivers/platform/x86/quark/intel_qrk_esram_test.c -@@ -0,0 +1,602 @@ +@@ -0,0 +1,595 @@ +/* + * Copyright(c) 2013 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. ++ * 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. + * -+ * 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. -+ * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +/** + * intel_qrk_esram_test.c @@ -2853,28 +2818,21 @@ index 0000000..544ad57 +module_exit(intel_qrk_esram_test_exit); diff --git a/drivers/platform/x86/quark/intel_qrk_esram_test.h b/drivers/platform/x86/quark/intel_qrk_esram_test.h new file mode 100644 -index 0000000..35ad2d8 +index 0000000..5adf7ca --- /dev/null +++ b/drivers/platform/x86/quark/intel_qrk_esram_test.h -@@ -0,0 +1,43 @@ +@@ -0,0 +1,36 @@ +/* + * Copyright(c) 2013 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * 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. + * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +/** + * intel_qrk_esram_test.h @@ -2902,28 +2860,21 @@ index 0000000..35ad2d8 + diff --git a/drivers/platform/x86/quark/intel_qrk_imr.c b/drivers/platform/x86/quark/intel_qrk_imr.c new file mode 100644 -index 0000000..8865307 +index 0000000..fcae59a --- /dev/null +++ b/drivers/platform/x86/quark/intel_qrk_imr.c -@@ -0,0 +1,697 @@ +@@ -0,0 +1,690 @@ +/* + * Copyright(c) 2013 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 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 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. -+ * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +/* + * Intel Quark IMR driver @@ -3605,28 +3556,21 @@ index 0000000..8865307 + diff --git a/drivers/platform/x86/quark/intel_qrk_imr.h b/drivers/platform/x86/quark/intel_qrk_imr.h new file mode 100644 -index 0000000..9f16c61 +index 0000000..a6f4730 --- /dev/null +++ b/drivers/platform/x86/quark/intel_qrk_imr.h -@@ -0,0 +1,157 @@ +@@ -0,0 +1,150 @@ +/* + * Copyright(c) 2013 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. ++ * 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. + * -+ * 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. -+ * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +/* + * Intel Quark IMR driver @@ -3768,28 +3712,21 @@ index 0000000..9f16c61 +#endif diff --git a/drivers/platform/x86/quark/intel_qrk_imr_kernel.c b/drivers/platform/x86/quark/intel_qrk_imr_kernel.c new file mode 100644 -index 0000000..fdfaea3 +index 0000000..1cf922d --- /dev/null +++ b/drivers/platform/x86/quark/intel_qrk_imr_kernel.c -@@ -0,0 +1,139 @@ +@@ -0,0 +1,132 @@ +/* + * Copyright(c) 2013 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. ++ * 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. + * -+ * 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. -+ * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +/* + * Intel Quark IMR driver @@ -3913,28 +3850,21 @@ index 0000000..fdfaea3 +module_exit(intel_qrk_imr_runt_exit); diff --git a/drivers/platform/x86/quark/intel_qrk_imr_test.c b/drivers/platform/x86/quark/intel_qrk_imr_test.c new file mode 100644 -index 0000000..4f2096a +index 0000000..549bb61 --- /dev/null +++ b/drivers/platform/x86/quark/intel_qrk_imr_test.c -@@ -0,0 +1,357 @@ +@@ -0,0 +1,350 @@ +/* + * Copyright(c) 2013 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * 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. + * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +/* + * Intel Quark IMR Test module @@ -4276,28 +4206,21 @@ index 0000000..4f2096a + diff --git a/drivers/platform/x86/quark/intel_qrk_plat_clanton_hill.c b/drivers/platform/x86/quark/intel_qrk_plat_clanton_hill.c new file mode 100644 -index 0000000..3c489e8 +index 0000000..baa277c --- /dev/null +++ b/drivers/platform/x86/quark/intel_qrk_plat_clanton_hill.c -@@ -0,0 +1,226 @@ +@@ -0,0 +1,219 @@ +/* + * Copyright(c) 2013 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 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 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. -+ * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +/* + * Intel Quark Legacy Platform Data Layout.conf accessor @@ -4508,28 +4431,21 @@ index 0000000..3c489e8 + diff --git a/drivers/platform/x86/quark/intel_qrk_plat_clanton_peak.c b/drivers/platform/x86/quark/intel_qrk_plat_clanton_peak.c new file mode 100644 -index 0000000..9edcef7 +index 0000000..b0a8255 --- /dev/null +++ b/drivers/platform/x86/quark/intel_qrk_plat_clanton_peak.c -@@ -0,0 +1,227 @@ +@@ -0,0 +1,220 @@ +/* + * Copyright(c) 2013 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. ++ * 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. + * -+ * 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. -+ * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +/* + * Clanton Peak board entry point @@ -4741,28 +4657,21 @@ index 0000000..9edcef7 +MODULE_ALIAS("platform:"DRIVER_NAME); diff --git a/drivers/platform/x86/quark/intel_qrk_plat_cross_hill.c b/drivers/platform/x86/quark/intel_qrk_plat_cross_hill.c new file mode 100644 -index 0000000..eb1960a +index 0000000..74cb09f --- /dev/null +++ b/drivers/platform/x86/quark/intel_qrk_plat_cross_hill.c -@@ -0,0 +1,392 @@ +@@ -0,0 +1,430 @@ +/* + * Copyright(c) 2013 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. ++ * 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. + * -+ * 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. -+ * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +/* + * CrossHill board entry point @@ -4791,10 +4700,28 @@ index 0000000..eb1960a +#define SPI_BPEAK_ID2_GPIO 15 +#define SPI_BPEAK_ID3_GPIO 14 + ++/* ++ * GPIO number for eADC interrupt (MAX78M6610+LMU) ++ */ ++#define GPIO_78M6610_INT 2 ++ +static int nc_gpio_reg; +static int sc_gpio_reg; + +static int cross_hill_probe; ++/* ++ * GPIOs used as interrupts by MAX78M6610+LMU eADC ++ * ++ * Extend this array adding new elements at the end. ++ */ ++static struct gpio crh_eadc_int_gpios[] = { ++ { ++ GPIO_78M6610_INT, ++ GPIOF_IN, ++ "max78m6610-int" ++ }, ++}; ++ + +/* + * Blackburn Peak SPI daughterboard ID values @@ -4872,6 +4799,7 @@ index 0000000..eb1960a + +}; + ++/* For compatibility reason, new SPI energy modules must be added at the end */ +static struct spi_board_info spi_energy_adc_devs[] = { + { + .modalias = "max78m6610_lmu", @@ -4881,6 +4809,7 @@ index 0000000..eb1960a + .bus_num = 1, + .chip_select = 0, + .controller_data = &qrk_ffrd_spi_1_cs_0, ++ .irq = -1, + }, +}; + @@ -5004,8 +4933,33 @@ index 0000000..eb1960a + + case QRK_SPI_BPEAK_ID_ADC_MAXIM: + { -+ return spi_register_board_info(spi_energy_adc_devs, ++ ret = gpio_request_array(crh_eadc_int_gpios, ++ ARRAY_SIZE(crh_eadc_int_gpios)); ++ if (ret) { ++ pr_err("%s: Failed to allocate eADC interrupt GPIO pins!\n", ++ __func__); ++ return ret; ++ } ++ ret = gpio_to_irq(GPIO_78M6610_INT); ++ if (ret < 0) { ++ pr_err("%s: Failed to request IRQ for GPIO %u!\n", ++ __func__, GPIO_78M6610_INT); ++ goto error_gpio_free; ++ } ++ spi_energy_adc_devs[0].irq = ret; ++ ret = spi_register_board_info(spi_energy_adc_devs, + ARRAY_SIZE(spi_energy_adc_devs)); ++ if (ret) { ++ pr_err("%s: Failed to register eADC module!\n", ++ __func__); ++ goto error_gpio_free; ++ } ++ return 0; ++error_gpio_free: ++ gpio_free_array(crh_eadc_int_gpios, ++ ARRAY_SIZE(crh_eadc_int_gpios)); ++ spi_energy_adc_devs[0].irq = -1; ++ return ret; + } + case QRK_SPI_BPEAK_ID_ZB_EXEGIN_ATMEL: + { @@ -5139,28 +5093,21 @@ index 0000000..eb1960a + diff --git a/drivers/platform/x86/quark/intel_qrk_plat_galileo.c b/drivers/platform/x86/quark/intel_qrk_plat_galileo.c new file mode 100644 -index 0000000..0df0ac0 +index 0000000..a45f6a0 --- /dev/null +++ b/drivers/platform/x86/quark/intel_qrk_plat_galileo.c -@@ -0,0 +1,398 @@ +@@ -0,0 +1,391 @@ +/* + * Copyright(c) 2013 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * 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. + * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +/* + * Intel Quark Legacy Platform Data Layout.conf accessor @@ -5541,30 +5488,421 @@ index 0000000..0df0ac0 +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_ALIAS("platform:"DRIVER_NAME); + -diff --git a/drivers/platform/x86/quark/intel_qrk_plat_kips_bay.c b/drivers/platform/x86/quark/intel_qrk_plat_kips_bay.c +diff --git a/drivers/platform/x86/quark/intel_qrk_plat_galileo_gen2.c b/drivers/platform/x86/quark/intel_qrk_plat_galileo_gen2.c new file mode 100644 -index 0000000..5e94b4b +index 0000000..7c09add --- /dev/null -+++ b/drivers/platform/x86/quark/intel_qrk_plat_kips_bay.c -@@ -0,0 +1,176 @@ ++++ b/drivers/platform/x86/quark/intel_qrk_plat_galileo_gen2.c +@@ -0,0 +1,392 @@ +/* ++ * Intel Quark Legacy Platform Data Layout.conf accessor ++ * ++ * Simple Legacy SPI flash access layer ++ * + * Copyright(c) 2013 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 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 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. ++ * 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. ++ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com> 2013 ++ */ ++ ++#include <linux/errno.h> ++#include <linux/gpio.h> ++#include <linux/i2c.h> ++#include <linux/i2c/at24.h> ++#include <linux/io.h> ++#include <linux/ioport.h> ++#include <linux/module.h> ++#include <linux/mfd/intel_qrk_gip_pdata.h> ++#include <linux/mtd/partitions.h> ++#include <linux/mtd/physmap.h> ++#include <linux/platform_device.h> ++#include <linux/printk.h> ++#include <linux/spi/pxa2xx_spi.h> ++#include <linux/spi/spi.h> ++#include <linux/spi/flash.h> ++#include <linux/i2c/pca953x.h> ++ ++#define DRIVER_NAME "GalileoGen2" ++#define GPIO_RESTRICT_NAME "qrk-gpio-restrict-sc" ++#define LPC_SCH_SPINAME "spi-lpc-sch" ++ ++#define GPIO_PCAL9555A_EXP2_INT 9 ++ ++/* Option to allow GPIO 10 to be used for SPI1 chip-select */ ++static int gpio_cs; ++ ++module_param(gpio_cs, int, S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC(gpio_cs, "Enable GPIO chip-select for SPI channel 1"); ++ ++/* Galileo Gen2 boards require i2c master to operate @400kHz 'fast mode' */ ++static struct intel_qrk_gip_pdata gip_pdata = { ++ .i2c_std_mode = 0, ++}; ++static struct intel_qrk_gip_pdata *galileo_gen2_gip_get_pdata(void) ++{ ++ return &gip_pdata; ++} ++ ++/****************************************************************************** ++ * Texas Instruments ADC1x8S102 SPI Device Platform Data ++ ******************************************************************************/ ++#include "linux/platform_data/adc1x8s102.h" ++ ++/* Maximum input voltage allowed for each ADC input, in milliVolts */ ++#define ADC1x8S102_MAX_EXT_VIN 5000 ++ ++static const struct adc1x8s102_platform_data adc1x8s102_platform_data = { ++ .ext_vin = ADC1x8S102_MAX_EXT_VIN ++}; ++ ++#include "linux/i2c/pca953x.h" ++#define PCAL9555A_GPIO_BASE_OFFSET 16 ++ ++static struct pca953x_platform_data pcal9555a_platform_data_exp0 = { ++ .gpio_base = PCAL9555A_GPIO_BASE_OFFSET, ++ .irq_base = -1, ++}; ++ ++static struct pca953x_platform_data pcal9555a_platform_data_exp1 = { ++ .gpio_base = PCAL9555A_GPIO_BASE_OFFSET + 16, ++ .irq_base = -1, ++}; ++ ++static struct pca953x_platform_data pcal9555a_platform_data_exp2 = { ++ .gpio_base = PCAL9555A_GPIO_BASE_OFFSET + 32, ++}; ++ ++#include "linux/platform_data/pca9685.h" ++ ++static struct pca9685_pdata pca9685_platform_data = { ++ .chan_mapping = { ++ PWM_CH_GPIO, PWM_CH_PWM, ++ PWM_CH_GPIO, PWM_CH_PWM, ++ PWM_CH_GPIO, PWM_CH_PWM, ++ PWM_CH_GPIO, PWM_CH_PWM, ++ PWM_CH_GPIO, PWM_CH_PWM, ++ PWM_CH_GPIO, PWM_CH_PWM, ++ PWM_CH_GPIO, PWM_CH_GPIO, ++ PWM_CH_GPIO, PWM_CH_GPIO, ++ PWM_CH_DISABLED /* ALL_LED disabled */ ++ }, ++ .gpio_base = PCAL9555A_GPIO_BASE_OFFSET + 48, ++}; ++ ++/****************************************************************************** ++ * Intel Galileo Gen2 i2c clients ++ ******************************************************************************/ ++#define EEPROM_ADDR 0x54 ++#define PCAL9555A_EXP0_ADDR 0x25 ++#define PCAL9555A_EXP1_ADDR 0x26 ++#define PCAL9555A_EXP2_ADDR 0x27 ++#define PCA9685_ADDR 0x47 ++ ++static struct i2c_board_info probed_i2c_eeprom; ++static struct i2c_board_info probed_i2c_pcal9555a_exp0 = { ++ .platform_data = &pcal9555a_platform_data_exp0, ++}; ++static struct i2c_board_info probed_i2c_pcal9555a_exp1 = { ++ .platform_data = &pcal9555a_platform_data_exp1, ++}; ++static struct i2c_board_info probed_i2c_pcal9555a_exp2 = { ++ .platform_data = &pcal9555a_platform_data_exp2, ++}; ++static struct i2c_board_info probed_i2c_pca9685 = { ++ .platform_data = &pca9685_platform_data, ++}; ++ ++static const unsigned short eeprom_i2c_addr[] = { ++ EEPROM_ADDR, I2C_CLIENT_END ++}; ++static const unsigned short pcal9555a_exp0_i2c_addr[] = { ++ PCAL9555A_EXP0_ADDR, I2C_CLIENT_END ++}; ++static const unsigned short pcal9555a_exp1_i2c_addr[] = { ++ PCAL9555A_EXP1_ADDR, I2C_CLIENT_END ++}; ++static const unsigned short pcal9555a_exp2_i2c_addr[] = { ++ PCAL9555A_EXP2_ADDR, I2C_CLIENT_END ++}; ++static const unsigned short pca9685_i2c_addr[] = { ++ PCA9685_ADDR, I2C_CLIENT_END ++}; ++ ++static int i2c_probe(struct i2c_adapter *adap, unsigned short addr) ++{ ++ /* Always return success: the I2C clients are already known. */ ++ return 1; ++} ++ ++/****************************************************************************** ++ * Intel Quark SPI Controller Data ++ ******************************************************************************/ ++static struct pxa2xx_spi_chip qrk_ffrd_spi_0_cs_0 = { ++ .gpio_cs = 8, ++}; ++ ++static struct pxa2xx_spi_chip qrk_ffrd_spi_1_cs_0 = { ++ .gpio_cs = 10, ++}; ++ ++#define LPC_SCH_SPI_BUS_ID 0x03 ++ ++/* TODO: extract this data from layout.conf encoded in flash */ ++struct mtd_partition galileo_gen2_ilb_partitions[] = { ++ { ++ .name = "grub", ++ .size = 4096, ++ .offset = 0, ++ }, ++ { ++ .name = "grub.conf", ++ .size = 0xA00, ++ .offset = 0x50500, ++ }, ++ { ++ .name = "layout.conf", ++ .size = 4096, ++ .offset = 0x708000, ++ }, ++ { ++ .name = "sketch", ++ .size = 0x40000, ++ .offset = 0x750000, ++ }, ++ { ++ .name = "raw", ++ .size = 8192000, ++ .offset = 0, ++ ++ }, ++}; ++ ++static struct flash_platform_data ilb_flash = { ++ .type = "s25fl064k", ++ .parts = galileo_gen2_ilb_partitions, ++ .nr_parts = ARRAY_SIZE(galileo_gen2_ilb_partitions), ++}; ++ ++static struct spi_board_info spi0_onboard_devs[] = { ++ { ++ .modalias = "m25p80", ++ .platform_data = &ilb_flash, ++ .bus_num = LPC_SCH_SPI_BUS_ID, ++ .chip_select = 0, ++ }, ++ { ++ .modalias = "adc1x8s102", ++ .max_speed_hz = 16667000, ++ .platform_data = &adc1x8s102_platform_data, ++ .mode = SPI_MODE_3, ++ .bus_num = 0, ++ .chip_select = 0, ++ .controller_data = &qrk_ffrd_spi_0_cs_0, ++ }, ++}; ++ ++static struct spi_board_info spi1_onboard_devs_gpiocs[] = { ++ { ++ .modalias = "spidev", ++ .chip_select = 0, ++ .controller_data = NULL, ++ .max_speed_hz = 50000000, ++ .bus_num = 1, ++ .controller_data = &qrk_ffrd_spi_1_cs_0, ++ }, ++}; ++ ++static struct spi_board_info spi1_onboard_devs[] = { ++ { ++ .modalias = "spidev", ++ .chip_select = 0, ++ .controller_data = NULL, ++ .max_speed_hz = 50000000, ++ .bus_num = 1, ++ }, ++}; ++ ++ ++/** ++ * intel_qrk_spi_add_onboard_devs ++ * ++ * @return 0 on success or standard errnos on failure ++ * ++ * Registers onboard SPI device(s) present on the Izmir platform ++ */ ++static int intel_qrk_spi_add_onboard_devs(void) ++{ ++ int ret = 0; ++ ++ ret = spi_register_board_info(spi0_onboard_devs, ++ ARRAY_SIZE(spi0_onboard_devs)); ++ if (ret) ++ return ret; ++ ++ if (gpio_cs) ++ return spi_register_board_info(spi1_onboard_devs_gpiocs, ++ ARRAY_SIZE(spi1_onboard_devs_gpiocs)); ++ else ++ return spi_register_board_info(spi1_onboard_devs, ++ ARRAY_SIZE(spi1_onboard_devs)); ++} ++ ++ ++static struct gpio reserved_gpios[] = { ++ { ++ GPIO_PCAL9555A_EXP2_INT, ++ GPIOF_IN, ++ "pcal9555a-exp2-int", ++ }, ++}; ++ ++/** ++ * intel_qrk_gpio_restrict_probe ++ * ++ * Make GPIOs pertaining to Firmware inaccessible by requesting them. The ++ * GPIOs are never released nor accessed by this driver. ++ * ++ * Registers devices which are dependent on this GPIO driver ++ */ ++static int intel_qrk_gpio_restrict_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct i2c_adapter *i2c_adap = NULL; ++ struct i2c_client *client = NULL; ++ ++ /* Need to tell the PCA953X driver which GPIO IRQ to use for signalling ++ * interrupts. We can't get the IRQ until the GPIO driver is loaded. ++ * Hence, we defer registration of the I2C devices until now ++ */ ++ i2c_adap = i2c_get_adapter(0); ++ if (NULL == i2c_adap) { ++ pr_info("%s: i2c adapter not ready yet. Deferring..\n", ++ __func__); ++ return -EPROBE_DEFER; ++ } ++ ++ ret = gpio_request_array(reserved_gpios, ARRAY_SIZE(reserved_gpios)); ++ if (ret) { ++ dev_err(&client->dev, "failed to request reserved gpios\n"); ++ goto end; ++ } ++ ++ strlcpy(probed_i2c_eeprom.type, "24c08", I2C_NAME_SIZE); ++ client = i2c_new_probed_device(i2c_adap, &probed_i2c_eeprom, ++ eeprom_i2c_addr, i2c_probe); ++ if (client == NULL) { ++ pr_err("%s: Failed to probe 24c08 I2C device\n", __func__); ++ ret = -ENODEV; ++ goto end; ++ } ++ ++ strlcpy(probed_i2c_pcal9555a_exp0.type, "pcal9555a", I2C_NAME_SIZE); ++ client = i2c_new_probed_device(i2c_adap, &probed_i2c_pcal9555a_exp0, ++ pcal9555a_exp0_i2c_addr, i2c_probe); ++ if (client == NULL) { ++ pr_err("%s: Failed to probe pcal9555a I2C device\n", __func__); ++ ret = -ENODEV; ++ goto end; ++ } ++ ++ strlcpy(probed_i2c_pcal9555a_exp1.type, "pcal9555a", I2C_NAME_SIZE); ++ client = i2c_new_probed_device(i2c_adap, &probed_i2c_pcal9555a_exp1, ++ pcal9555a_exp1_i2c_addr, i2c_probe); ++ if (client == NULL) { ++ pr_err("%s: Failed to probe pcal9555a I2C device\n", __func__); ++ ret = -ENODEV; ++ goto end; ++ } ++ ++ strlcpy(probed_i2c_pcal9555a_exp2.type, "pcal9555a", I2C_NAME_SIZE); ++ probed_i2c_pcal9555a_exp2.irq = gpio_to_irq(GPIO_PCAL9555A_EXP2_INT); ++ client = i2c_new_probed_device(i2c_adap, &probed_i2c_pcal9555a_exp2, ++ pcal9555a_exp2_i2c_addr, i2c_probe); ++ if (client == NULL) { ++ pr_err("%s: Failed to probe pcal9555a I2C device\n", __func__); ++ ret = -ENODEV; ++ goto end; ++ } ++ ++ strlcpy(probed_i2c_pca9685.type, "pca9685", I2C_NAME_SIZE); ++ client = i2c_new_probed_device(i2c_adap, &probed_i2c_pca9685, ++ pca9685_i2c_addr, i2c_probe); ++ if (client == NULL) { ++ pr_err("%s: Failed to probe pca9685 I2C device\n", __func__); ++ ret = -ENODEV; ++ goto end; ++ } ++ ++ ret = intel_qrk_spi_add_onboard_devs(); ++ ++end: ++ i2c_put_adapter(i2c_adap); ++ ++ return ret; ++} ++ ++static struct platform_driver gpio_restrict_pdriver = { ++ .driver = { ++ .name = GPIO_RESTRICT_NAME, ++ .owner = THIS_MODULE, ++ }, ++ .probe = intel_qrk_gpio_restrict_probe, ++}; ++ ++static int intel_qrk_plat_galileo_gen2_probe(struct platform_device *pdev) ++{ ++ /* Assign GIP driver handle for board-specific settings */ ++ intel_qrk_gip_get_pdata = galileo_gen2_gip_get_pdata; ++ ++ /* gpio */ ++ return platform_driver_register(&gpio_restrict_pdriver); ++} ++ ++static int intel_qrk_plat_galileo_gen2_remove(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static struct platform_driver qrk_galileo_driver = { ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ }, ++ .probe = intel_qrk_plat_galileo_gen2_probe, ++ .remove = intel_qrk_plat_galileo_gen2_remove, ++}; ++ ++module_platform_driver(qrk_galileo_driver); ++ ++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@intel.com>"); ++MODULE_DESCRIPTION("Galileo Gen2 BSP Data"); ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_ALIAS("platform:"DRIVER_NAME); +diff --git a/drivers/platform/x86/quark/intel_qrk_plat_kips_bay.c b/drivers/platform/x86/quark/intel_qrk_plat_kips_bay.c +new file mode 100644 +index 0000000..7a33d36 +--- /dev/null ++++ b/drivers/platform/x86/quark/intel_qrk_plat_kips_bay.c +@@ -0,0 +1,169 @@ ++/* ++ * Copyright(c) 2013 Intel Corporation. + * -+ * Contact Information: -+ * 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. + */ +/* + * Intel Quark Legacy Platform Data Layout.conf accessor @@ -5725,28 +6063,21 @@ index 0000000..5e94b4b + diff --git a/drivers/platform/x86/quark/intel_qrk_sb.c b/drivers/platform/x86/quark/intel_qrk_sb.c new file mode 100644 -index 0000000..658c41f +index 0000000..17e4ddd --- /dev/null +++ b/drivers/platform/x86/quark/intel_qrk_sb.c -@@ -0,0 +1,253 @@ +@@ -0,0 +1,246 @@ +/* + * Copyright(c) 2013 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * 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. + * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +/* + * Intel Quark side-band driver @@ -5984,28 +6315,21 @@ index 0000000..658c41f +subsys_initcall(intel_qrk_sb_init); diff --git a/drivers/platform/x86/quark/intel_qrk_thermal.c b/drivers/platform/x86/quark/intel_qrk_thermal.c new file mode 100644 -index 0000000..d603d8b +index 0000000..189bb5c --- /dev/null +++ b/drivers/platform/x86/quark/intel_qrk_thermal.c -@@ -0,0 +1,360 @@ +@@ -0,0 +1,353 @@ +/* + * Copyright(c) 2013 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * 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. + * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +/* + * Intel Quark Thermal driver @@ -6350,28 +6674,21 @@ index 0000000..d603d8b +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/include/linux/intel_qrk_sb.h b/include/linux/intel_qrk_sb.h new file mode 100644 -index 0000000..65d9b5e +index 0000000..4290070 --- /dev/null +++ b/include/linux/intel_qrk_sb.h -@@ -0,0 +1,92 @@ +@@ -0,0 +1,85 @@ +/* + * Copyright(c) 2013 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 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 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. -+ * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +/* + * Intel Quark side-band driver @@ -6448,28 +6765,21 @@ index 0000000..65d9b5e +#endif /* __INTEL_QRK_SB_H__ */ diff --git a/include/linux/platform_data/quark.h b/include/linux/platform_data/quark.h new file mode 100644 -index 0000000..85f5508 +index 0000000..e9b2d55d --- /dev/null +++ b/include/linux/platform_data/quark.h -@@ -0,0 +1,44 @@ +@@ -0,0 +1,37 @@ +/* + * Copyright(c) 2013 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. ++ * 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. + * -+ * 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. -+ * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +/* + * Intel Quark platform data definition @@ -6496,6 +6806,3 @@ index 0000000..85f5508 +}plat_dataid_t; + +#endif /* _PDATA_QUARK_H */ --- -1.7.4.1 - diff --git a/recipes-kernel/linux/files/0008-Quark-UART-quark.patch b/recipes-kernel/linux/files/0008-Quark-UART-quark.patch index 15b0ffd..336e171 100644 --- a/recipes-kernel/linux/files/0008-Quark-UART-quark.patch +++ b/recipes-kernel/linux/files/0008-Quark-UART-quark.patch @@ -1,6 +1,6 @@ From xxxx Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue <bryan.odonoghue@intel.com> -Date: Thu, 13 Feb 2014 13:03:44 +0000 +Date: Thu, 24 Apr 2014 13:32:03 +0100 Subject: [PATCH 08/21] Quark UART --- @@ -8,23 +8,23 @@ Subject: [PATCH 08/21] Quark UART drivers/dma/Makefile | 1 + drivers/dma/intel_mid_dma.c | 1460 ----------------------- drivers/dma/intel_mid_dma/Makefile | 3 + - drivers/dma/intel_mid_dma_core.c | 1295 +++++++++++++++++++++ - drivers/dma/intel_mid_dma_pci.c | 290 +++++ - drivers/dma/intel_mid_dma_regs.h | 107 +-- - drivers/dma/intel_qrk_dma_pci.c | 155 +++ + drivers/dma/intel_mid_dma_core.c | 1336 ++++++++++++++++++++++ + drivers/dma/intel_mid_dma_pci.c | 292 +++++ + drivers/dma/intel_mid_dma_regs.h | 109 +- + drivers/dma/intel_qrk_dma_pci.c | 147 +++ drivers/tty/serial/8250/8250.c | 53 + drivers/tty/serial/8250/8250_pci.c | 52 +- drivers/tty/serial/Kconfig | 20 + drivers/tty/serial/Makefile | 1 + - drivers/tty/serial/intel_quark_uart.c | 2032 +++++++++++++++++++++++++++++++++ - include/linux/intel_mid_dma.h | 186 +++ - 14 files changed, 4099 insertions(+), 1562 deletions(-) + drivers/tty/serial/intel_quark_uart.c | 2034 +++++++++++++++++++++++++++++++++ + include/linux/intel_mid_dma.h | 189 +++ + 14 files changed, 4147 insertions(+), 1556 deletions(-) delete mode 100644 drivers/dma/intel_mid_dma.c create mode 100644 drivers/dma/intel_mid_dma/Makefile create mode 100644 drivers/dma/intel_mid_dma_core.c create mode 100644 drivers/dma/intel_mid_dma_pci.c create mode 100644 drivers/dma/intel_qrk_dma_pci.c - create mode 100644 drivers/tty/serial/intel_quark_uart.c + create mode 100755 drivers/tty/serial/intel_quark_uart.c diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index d4c1218..9867547 100644 @@ -1536,10 +1536,10 @@ index 0000000..6ec8b97 + diff --git a/drivers/dma/intel_mid_dma_core.c b/drivers/dma/intel_mid_dma_core.c new file mode 100644 -index 0000000..aeb7fd3 +index 0000000..b869d6c --- /dev/null +++ b/drivers/dma/intel_mid_dma_core.c -@@ -0,0 +1,1295 @@ +@@ -0,0 +1,1336 @@ +/* + * intel_mid_dma_core.c - Intel Langwell DMA Drivers + * @@ -1585,13 +1585,6 @@ index 0000000..aeb7fd3 +#define LNW_PERIPHRAL_STATUS 0x0 +#define LNW_PERIPHRAL_MASK 0x8 + -+#define INFO(_max_chan, _ch_base, _block_size, _pimr_mask) \ -+ ((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), \ -+ }) + +/***************************************************************************** +Utility Functions*/ @@ -1677,7 +1670,7 @@ index 0000000..aeb7fd3 + * + * UnMasks the DMA periphral interrupt, + * this is valid for DMAC1 family controllers only -+ * This controller should have periphral mask registers already mapped ++ * This controller should have peripheral mask registers already mapped + */ +void dmac1_unmask_periphral_intr(struct intel_mid_dma_chan *midc) +{ @@ -1770,6 +1763,7 @@ index 0000000..aeb7fd3 + spin_unlock_bh(&midc->lock); + } +} ++ +/** + * midc_dostart - begin a DMA transaction + * @midc: channel for which txn is to be started @@ -1790,8 +1784,9 @@ index 0000000..aeb7fd3 + /* The tasklet will hopefully advance the queue... */ + return; + } -+ midc->busy = true; ++ + /*write registers and en*/ ++ midc->busy = true; + iowrite32(first->sar, midc->ch_regs + SAR); + iowrite32(first->dar, midc->ch_regs + DAR); + iowrite32(first->lli_phys, midc->ch_regs + LLP); @@ -1828,7 +1823,6 @@ index 0000000..aeb7fd3 + dma_cookie_complete(txd); + callback_txd = txd->callback; + param_txd = txd->callback_param; -+ + if (desc->lli != NULL) { + /*clear the DONE bit of completed LLI in memory*/ + llitem = desc->lli + desc->current_lli; @@ -1857,6 +1851,7 @@ index 0000000..aeb7fd3 + spin_lock_bh(&midc->lock); + +} ++ +/** + * midc_scan_descriptors - check the descriptors in channel + * mark completed when tx is completete @@ -1877,7 +1872,8 @@ index 0000000..aeb7fd3 + midc_descriptor_complete(midc, desc); + } + return; -+ } ++} ++ +/** + * midc_lli_fill_sg - Helper function to convert + * SG list to Linked List Items. @@ -1923,7 +1919,7 @@ index 0000000..aeb7fd3 + pr_debug("MDMA: LLI is configured in circular mode\n"); + lli_next = desc->lli_phys; + } else { -+ lli_next = 0; ++ lli_next = (dma_addr_t)lli_bloc_desc; /* Needs to be !0 */ + ctl_lo.ctlx.llp_dst_en = 0; + ctl_lo.ctlx.llp_src_en = 0; + } @@ -1941,11 +1937,10 @@ index 0000000..aeb7fd3 + lli_bloc_desc->sar = mids->dma_slave.src_addr; + lli_bloc_desc->dar = sg_phy_addr; + } -+ /*Copy values into block descriptor in system memroy*/ ++ /*Copy values into block descriptor in system memory*/ + 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++; + } + /*Copy very first LLI values to descriptor*/ @@ -2094,7 +2089,6 @@ index 0000000..aeb7fd3 + return 0; +} + -+ +/** + * intel_mid_dma_prep_memcpy - Prep memcpy txn + * @chan: chan for DMA transfer @@ -2131,11 +2125,11 @@ index 0000000..aeb7fd3 + mids = midc->mid_slave; + BUG_ON(!mids); + -+ 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", ++ pr_debug("MDMA:called for DMA %x CH %d Length %zu src_addr 0x%08x dst 0x%08x\n", ++ midc->dma->pci_id, midc->ch_id, len, (u32)src, (u32)dest); ++ pr_debug("MDMA:Cfg passed Mode %x, Dirn %d, Handshake %s, Width %x\n", + mids->cfg_mode, mids->dma_slave.direction, -+ mids->hs_mode, mids->dma_slave.src_addr_width); ++ mids->hs_mode == LNW_DMA_HW_HS ? "hardware" : "software" , mids->dma_slave.src_addr_width); + + /*calculate CFG_LO*/ + if (mids->hs_mode == LNW_DMA_SW_HS) { @@ -2171,6 +2165,13 @@ index 0000000..aeb7fd3 + cfg_hi.cfgx.protctl = 0x1; /*default value*/ + cfg_hi.cfgx.src_per = cfg_hi.cfgx.dst_per = + midc->ch_id - midc->dma->chan_base; ++ /* Quark - set polarity active low - make a param */ ++ if(midc->dma->is_quark){ ++ cfg_lo.cfgx.dst_hs_pol = 0x1; ++ cfg_lo.cfgx.src_hs_pol = 0x1; ++ cfg_lo.cfgx.hs_sel_dst = 0x00; ++ cfg_lo.cfgx.hs_sel_src = 0x01; ++ } + } + } + @@ -2180,13 +2181,18 @@ index 0000000..aeb7fd3 + width = mids->dma_slave.src_addr_width; + + ctl_hi.ctlx.block_ts = get_block_ts(len, width, midc->dma->block_size); -+ pr_debug("MDMA:calc len %d for block size %d\n", ++ pr_debug("MDMA:calc len (block_ts) %d for block size %d\n", + ctl_hi.ctlx.block_ts, midc->dma->block_size); + /*calculate CTL_LO*/ + ctl_lo.ctl_lo = 0; + ctl_lo.ctlx.int_en = 1; -+ ctl_lo.ctlx.dst_msize = mids->dma_slave.src_maxburst; -+ ctl_lo.ctlx.src_msize = mids->dma_slave.dst_maxburst; ++ /* Note Quark: original driver inverted these two values - need to ++ * resolve before integration - have we missed a trick ? */ ++ ctl_lo.ctlx.dst_msize = mids->dma_slave.dst_maxburst; ++ ctl_lo.ctlx.src_msize = mids->dma_slave.src_maxburst; ++ pr_debug("MDMA:Cfg dst_msize 0x%x src_msize 0x%x\n", ctl_lo.ctlx.src_msize, ctl_lo.ctlx.dst_msize); ++ pr_debug("MDMA:Cfg mids->dma_slave.dst_maxburst 0x%x mids->dma_slave.src_maxburst 0x%x\n", mids->dma_slave.src_maxburst, ++mids->dma_slave.dst_maxburst); + + /* + * Here we need some translation from "enum dma_slave_buswidth" @@ -2215,9 +2221,8 @@ index 0000000..aeb7fd3 + } + } + -+ pr_debug("MDMA:Calc CTL LO %x, CTL HI %x, CFG LO %x, CFG HI %x\n", ++ pr_debug("MDMA:Calc CTL LO 0x%x, CTL HI 0x%x, CFG LO 0x%x CFG HI 0x%x\n", + ctl_lo.ctl_lo, ctl_hi.ctl_hi, cfg_lo.cfg_lo, cfg_hi.cfg_hi); -+ + enable_dma_interrupt(midc); + + desc = midc_desc_get(midc); @@ -2276,7 +2281,7 @@ index 0000000..aeb7fd3 + mids = midc->mid_slave; + BUG_ON(!mids); + -+ if (!midc->dma->pimr_mask) { ++ if (!midc->dma->is_quark && !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, @@ -2294,7 +2299,8 @@ index 0000000..aeb7fd3 + 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 = intel_mid_dma_prep_memcpy(chan, mids->dma_slave.dst_addr, ++ mids->dma_slave.src_addr, sg_dma_len(sgl), flags); + if (NULL == txd) { + pr_err("MDMA: Prep memcpy failed\n"); + return NULL; @@ -2553,23 +2559,21 @@ index 0000000..aeb7fd3 +irqreturn_t intel_mid_dma_interrupt(int irq, void *data) +{ + struct middma_device *mid = data; -+ u32 tfr_status, err_status; ++ u32 tfr_status, err_status, block_status; + int call_tasklet = 0; + + tfr_status = ioread32(mid->dma_base + RAW_TFR); ++ block_status = ioread32(mid->dma_base + RAW_BLOCK); + err_status = ioread32(mid->dma_base + RAW_ERR); -+ if (!tfr_status && !err_status) ++ if (!tfr_status && !err_status && !block_status){ + return IRQ_NONE; ++ } + + /*DMA Interrupt*/ -+#if 0 + pr_debug("MDMA:Got an interrupt on irq %d\n", irq); -+ pr_debug("MDMA: Status %x, Mask %x\n", tfr_status, mid->intr_mask); -+#else -+ pr_info("MDMA:Got an interrupt on irq %d\n", irq); -+ pr_info("MDMA: Status %x, Mask %x\n", tfr_status, mid->intr_mask); ++ pr_debug("MDMA: raw_tfr %x, raw_err %x raw_block %x Mask %x\n", ++ tfr_status, err_status, block_status, mid->intr_mask); + -+#endif + tfr_status &= mid->intr_mask; + if (tfr_status) { + /*need to disable intr*/ @@ -2586,7 +2590,7 @@ index 0000000..aeb7fd3 + } + if (call_tasklet) + tasklet_schedule(&mid->tasklet); -+ ++ + return IRQ_HANDLED; +} +EXPORT_SYMBOL(intel_mid_dma_interrupt); @@ -2763,7 +2767,9 @@ index 0000000..aeb7fd3 +* @state: PM message +* +* This function is called by OS when a power event occurs ++* TBD in 1.1 release +*/ ++#if 0 +static int dma_suspend(struct device *dev) +{ + struct pci_dev *pci = to_pci_dev(dev); @@ -2775,15 +2781,18 @@ index 0000000..aeb7fd3 + if (device->ch[i].in_use) + return -EAGAIN; + } -+#if 0 -+ dmac1_mask_periphral_intr(device); -+#endif ++ ++ if(!device->is_quark){ ++ 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; +} ++#endif + +/** +* dma_resume - PCI resume function @@ -2802,6 +2811,16 @@ index 0000000..aeb7fd3 + return 0; +} + ++/* ++* dma_runtime_suspend - PCI suspend function ++* ++* @pci: PCI device structure ++* @state: PM message ++* ++* This function is called by OS when a power event occurs ++* TBD in 1.1 release ++*/ ++#if 0 +static int dma_runtime_suspend(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); @@ -2810,7 +2829,18 @@ index 0000000..aeb7fd3 + device->state = SUSPENDED; + return 0; +} ++#endif + ++/* ++* dma_runtime_resume - PCI suspend function ++* ++* @pci: PCI device structure ++* @state: PM message ++* ++* This function is called by OS when a power event occurs ++* TBD in 1.1 release ++*/ ++#if 0 +static int dma_runtime_resume(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); @@ -2820,7 +2850,18 @@ index 0000000..aeb7fd3 + iowrite32(REG_BIT0, device->dma_base + DMA_CFG); + return 0; +} ++#endif + ++/* ++* dma_runtime_idle - PCI suspend function ++* ++* @pci: PCI device structure ++* @state: PM message ++* ++* This function is called by OS when a power event occurs ++* TBD in 1.1 release ++*/ ++#if 0 +static int dma_runtime_idle(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); @@ -2834,13 +2875,13 @@ index 0000000..aeb7fd3 + + return pm_schedule_suspend(dev, 0); +} -+ ++#endif diff --git a/drivers/dma/intel_mid_dma_pci.c b/drivers/dma/intel_mid_dma_pci.c new file mode 100644 -index 0000000..bd753b9 +index 0000000..b0d3ab1 --- /dev/null +++ b/drivers/dma/intel_mid_dma_pci.c -@@ -0,0 +1,290 @@ +@@ -0,0 +1,292 @@ +/* + * intel_mid_dma.c - Intel Langwell DMA Drivers + * @@ -2866,6 +2907,7 @@ index 0000000..bd753b9 + * + * + */ ++#define DEBUG +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/pm_runtime.h> @@ -2873,19 +2915,19 @@ index 0000000..bd753b9 +#include <linux/module.h> + +#include "intel_mid_dma_regs.h" -+//#include "intel_mid_dma_core.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 INFO(_max_chan, _ch_base, _block_size, _pimr_mask) \ ++#define INFO(_max_chan, _ch_base, _block_size, _pimr_mask, _is_quark) \ + ((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), \ ++ .is_quark = (_is_quark), \ + }) + +/** @@ -2948,6 +2990,7 @@ index 0000000..bd753b9 + device->chan_base = info->ch_base; + device->block_size = info->block_size; + device->pimr_mask = info->pimr_mask; ++ device->is_quark = info->is_quark; + + err = mid_setup_dma(pdev, device); + if (err) @@ -3085,10 +3128,10 @@ index 0000000..bd753b9 +* 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, 4095, 0x200020, 0)}, ++ { PCI_VDEVICE(INTEL, INTEL_MID_DMAC2_ID), INFO(2, 0, 2047, 0, 0)}, ++ { PCI_VDEVICE(INTEL, INTEL_MID_GP_DMAC2_ID), INFO(2, 0, 2047, 0, 0)}, ++ { PCI_VDEVICE(INTEL, INTEL_MFLD_DMAC1_ID), INFO(4, 0, 4095, 0x400040, 0)}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, intel_mid_dma_ids); @@ -3132,7 +3175,7 @@ index 0000000..bd753b9 +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(INTEL_MID_DMA_DRIVER_VERSION); diff --git a/drivers/dma/intel_mid_dma_regs.h b/drivers/dma/intel_mid_dma_regs.h -index 17b4219..4b2ba69 100644 +index 17b4219..f3d5597 100644 --- a/drivers/dma/intel_mid_dma_regs.h +++ b/drivers/dma/intel_mid_dma_regs.h @@ -27,6 +27,7 @@ @@ -3143,7 +3186,7 @@ index 17b4219..4b2ba69 100644 #include <linux/pci_ids.h> #define INTEL_MID_DMA_DRIVER_VERSION "1.1.0" -@@ -158,115 +159,17 @@ union intel_mid_dma_cfg_hi { +@@ -158,114 +159,29 @@ union intel_mid_dma_cfg_hi { }; @@ -3237,12 +3280,15 @@ index 17b4219..4b2ba69 100644 - struct list_head desc_node; - struct dma_async_tx_descriptor txd; - size_t len; -- dma_addr_t sar; -- dma_addr_t dar; ++#if CONFIG_INTEL_QUARK_X1000_SOC ++struct intel_mid_dma_lli { + dma_addr_t sar; + dma_addr_t dar; - u32 cfg_hi; - u32 cfg_lo; -- u32 ctl_lo; -- u32 ctl_hi; ++ dma_addr_t llp; + u32 ctl_lo; + u32 ctl_hi; - struct pci_pool *lli_pool; - struct intel_mid_dma_lli *lli; - dma_addr_t lli_phys; @@ -3253,13 +3299,24 @@ index 17b4219..4b2ba69 100644 - enum dma_status status; - enum dma_slave_buswidth width; /*width of DMA txn*/ - enum intel_mid_dma_mode cfg_mode; /*mode configuration*/ -- ++ u32 sstatx; ++ u32 dstatx; ++} __attribute__ ((packed)); + -}; -- ++#else + struct intel_mid_dma_lli { dma_addr_t sar; - dma_addr_t dar; -@@ -294,6 +197,14 @@ static inline struct intel_mid_dma_slave *to_intel_mid_dma_slave +@@ -275,6 +191,7 @@ struct intel_mid_dma_lli { + u32 ctl_hi; + } __attribute__ ((packed)); + ++#endif + static inline int test_ch_en(void __iomem *dma, u32 ch_no) + { + u32 en_reg = ioread32(dma + DMA_CHAN_EN); +@@ -294,6 +211,14 @@ static inline struct intel_mid_dma_slave *to_intel_mid_dma_slave } @@ -3276,28 +3333,21 @@ index 17b4219..4b2ba69 100644 #endif /*__INTEL_MID_DMAC_REGS_H__*/ diff --git a/drivers/dma/intel_qrk_dma_pci.c b/drivers/dma/intel_qrk_dma_pci.c new file mode 100644 -index 0000000..cbac334 +index 0000000..c826ad7 --- /dev/null +++ b/drivers/dma/intel_qrk_dma_pci.c -@@ -0,0 +1,155 @@ +@@ -0,0 +1,147 @@ +/* + * Copyright(c) 2013 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * 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. + * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ + +/* @@ -3316,7 +3366,6 @@ index 0000000..cbac334 +#include <linux/intel_mid_dma.h> +#include <linux/module.h> + -+//#include "intel_mid_dma_core.h" +#include "intel_mid_dma_regs.h" + +/** @@ -3648,11 +3697,11 @@ index df1b998..ccbc063 100644 obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o diff --git a/drivers/tty/serial/intel_quark_uart.c b/drivers/tty/serial/intel_quark_uart.c -new file mode 100644 -index 0000000..5c0a01a +new file mode 100755 +index 0000000..5bb6a00 --- /dev/null +++ b/drivers/tty/serial/intel_quark_uart.c -@@ -0,0 +1,2032 @@ +@@ -0,0 +1,2034 @@ +/* + *Copyright (C) 2011 LAPIS Semiconductor Co., Ltd. + *Copyright (C) 2014 Intel Corporation. @@ -3693,6 +3742,9 @@ index 0000000..5c0a01a +#include <linux/intel_mid_dma.h> +#include <linux/debugfs.h> +#include <linux/dmaengine.h> ++#include <linux/spinlock.h> ++#include <linux/wait.h> ++#include <linux/workqueue.h> + +enum { + QUARK_UART_HANDLED_RX_INT_SHIFT, @@ -3708,25 +3760,27 @@ index 0000000..5c0a01a + QUARK_UART_2LINE, +}; + -+#define INFO(_max_chan, _ch_base, _block_size, _pimr_mask) \ ++#define INFO(_max_chan, _ch_base, _block_size, _pimr_mask, _is_quark) \ + ((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), \ ++ .is_quark = (_is_quark), \ + }) + +#define QUARK_UART_DRIVER_DEVICE "ttyQRK" +#define QUARK_UART_FIFO_LEN 16 -+//#define __QRK_DMA_DEBUG /* TODO: remove all code of this type */ -+ ++#define QUARK_UART_MAXBURST 0x20 ++#define QUARK_FIFO_FASTER_LEN (QUARK_UART_MAXBURST/2) +/* Set the max number of UART port -+ * Intel EG20T QUARK: 4 port -+ * LAPIS Semiconductor ML7213 IOH: 3 port -+ * LAPIS Semiconductor ML7223 IOH: 2 port ++ * Intel QUARK X1000 : 2 port +*/ +#define QUARK_UART_NR 2 + ++/* Set the AHB address for DMA transfers */ ++#define QUARK_UART_AHB_REG_BASE 0xFFFFF000 ++ +#define QUARK_UART_HANDLED_RX_INT (1<<((QUARK_UART_HANDLED_RX_INT_SHIFT)<<1)) +#define QUARK_UART_HANDLED_TX_INT (1<<((QUARK_UART_HANDLED_TX_INT_SHIFT)<<1)) +#define QUARK_UART_HANDLED_RX_ERR_INT (1<<((\ @@ -3737,17 +3791,17 @@ index 0000000..5c0a01a + +#define QUARK_UART_HANDLED_LS_INT (1<<((QUARK_UART_HANDLED_LS_INT_SHIFT)<<1)) + -+#define QUARK_UART_RBR 0x00 -+#define QUARK_UART_THR 0x00 ++#define QUARK_UART_RBR 0x00 ++#define QUARK_UART_THR 0x00 + -+#define QUARK_UART_IER_MASK (QUARK_UART_IER_ERBFI|QUARK_UART_IER_ETBEI|\ -+ QUARK_UART_IER_ELSI|QUARK_UART_IER_EDSSI) -+#define QUARK_UART_IER_ERBFI 0x00000001 -+#define QUARK_UART_IER_ETBEI 0x00000002 -+#define QUARK_UART_IER_ELSI 0x00000004 -+#define QUARK_UART_IER_EDSSI 0x00000008 ++#define QUARK_UART_IER_MASK (QUARK_UART_IER_ERBFI|QUARK_UART_IER_ETBEI|\ ++ QUARK_UART_IER_ELSI|QUARK_UART_IER_EDSSI) ++#define QUARK_UART_IER_ERBFI 0x00000001 ++#define QUARK_UART_IER_ETBEI 0x00000002 ++#define QUARK_UART_IER_ELSI 0x00000004 ++#define QUARK_UART_IER_EDSSI 0x00000008 + -+#define QUARK_UART_IIR_IP 0x00000001 ++#define QUARK_UART_IIR_IP 0x00000001 +#define QUARK_UART_IIR_IID 0x00000006 +#define QUARK_UART_IIR_MSI 0x00000000 +#define QUARK_UART_IIR_TRI 0x00000002 @@ -3756,7 +3810,7 @@ index 0000000..5c0a01a +#define QUARK_UART_IIR_TOI 0x00000008 +#define QUARK_UART_IIR_FIFO256 0x00000020 +#define QUARK_UART_IIR_FIFO64 QUARK_UART_IIR_FIFO256 -+#define QUARK_UART_IIR_FE 0x000000C0 ++#define QUARK_UART_IIR_FE 0x000000C0 + +#define QUARK_UART_FCR_FIFOE 0x00000001 +#define QUARK_UART_FCR_RFR 0x00000002 @@ -3775,56 +3829,56 @@ index 0000000..5c0a01a +#define QUARK_UART_FCR_RFTL4 QUARK_UART_FCR_RFTL64 +#define QUARK_UART_FCR_RFTL8 QUARK_UART_FCR_RFTL128 +#define QUARK_UART_FCR_RFTL14 QUARK_UART_FCR_RFTL224 -+#define QUARK_UART_FCR_RFTL_SHIFT 6 ++#define QUARK_UART_FCR_RFTL_SHIFT 6 + -+#define QUARK_UART_LCR_WLS 0x00000003 -+#define QUARK_UART_LCR_STB 0x00000004 -+#define QUARK_UART_LCR_PEN 0x00000008 -+#define QUARK_UART_LCR_EPS 0x00000010 ++#define QUARK_UART_LCR_WLS 0x00000003 ++#define QUARK_UART_LCR_STB 0x00000004 ++#define QUARK_UART_LCR_PEN 0x00000008 ++#define QUARK_UART_LCR_EPS 0x00000010 +#define QUARK_UART_LCR_SP 0x00000020 +#define QUARK_UART_LCR_SB 0x00000040 -+#define QUARK_UART_LCR_DLAB 0x00000080 ++#define QUARK_UART_LCR_DLAB 0x00000080 +#define QUARK_UART_LCR_NP 0x00000000 +#define QUARK_UART_LCR_OP QUARK_UART_LCR_PEN +#define QUARK_UART_LCR_EP (QUARK_UART_LCR_PEN | QUARK_UART_LCR_EPS) +#define QUARK_UART_LCR_1P (QUARK_UART_LCR_PEN | QUARK_UART_LCR_SP) +#define QUARK_UART_LCR_0P (QUARK_UART_LCR_PEN | QUARK_UART_LCR_EPS |\ -+ QUARK_UART_LCR_SP) ++ QUARK_UART_LCR_SP) + -+#define QUARK_UART_LCR_5BIT 0x00000000 -+#define QUARK_UART_LCR_6BIT 0x00000001 -+#define QUARK_UART_LCR_7BIT 0x00000002 -+#define QUARK_UART_LCR_8BIT 0x00000003 ++#define QUARK_UART_LCR_5BIT 0x00000000 ++#define QUARK_UART_LCR_6BIT 0x00000001 ++#define QUARK_UART_LCR_7BIT 0x00000002 ++#define QUARK_UART_LCR_8BIT 0x00000003 + -+#define QUARK_UART_MCR_DTR 0x00000001 -+#define QUARK_UART_MCR_RTS 0x00000002 -+#define QUARK_UART_MCR_OUT 0x0000000C -+#define QUARK_UART_MCR_LOOP 0x00000010 -+#define QUARK_UART_MCR_AFE 0x00000020 ++#define QUARK_UART_MCR_DTR 0x00000001 ++#define QUARK_UART_MCR_RTS 0x00000002 ++#define QUARK_UART_MCR_OUT 0x0000000C ++#define QUARK_UART_MCR_LOOP 0x00000010 ++#define QUARK_UART_MCR_AFE 0x00000020 + +#define QUARK_UART_LSR_DR 0x00000001 -+#define QUARK_UART_LSR_ERR (1<<7) -+ -+#define QUARK_UART_MSR_DCTS 0x00000001 -+#define QUARK_UART_MSR_DDSR 0x00000002 -+#define QUARK_UART_MSR_TERI 0x00000004 -+#define QUARK_UART_MSR_DDCD 0x00000008 -+#define QUARK_UART_MSR_CTS 0x00000010 -+#define QUARK_UART_MSR_DSR 0x00000020 ++#define QUARK_UART_LSR_ERR (1<<7) ++ ++#define QUARK_UART_MSR_DCTS 0x00000001 ++#define QUARK_UART_MSR_DDSR 0x00000002 ++#define QUARK_UART_MSR_TERI 0x00000004 ++#define QUARK_UART_MSR_DDCD 0x00000008 ++#define QUARK_UART_MSR_CTS 0x00000010 ++#define QUARK_UART_MSR_DSR 0x00000020 +#define QUARK_UART_MSR_RI 0x00000040 -+#define QUARK_UART_MSR_DCD 0x00000080 -+#define QUARK_UART_MSR_DELTA (QUARK_UART_MSR_DCTS | QUARK_UART_MSR_DDSR |\ -+ QUARK_UART_MSR_TERI | QUARK_UART_MSR_DDCD) ++#define QUARK_UART_MSR_DCD 0x00000080 ++#define QUARK_UART_MSR_DELTA (QUARK_UART_MSR_DCTS | QUARK_UART_MSR_DDSR |\ ++ QUARK_UART_MSR_TERI | QUARK_UART_MSR_DDCD) + -+#define QUARK_UART_DLL 0x00 -+#define QUARK_UART_DLM 0x01 ++#define QUARK_UART_DLL 0x00 ++#define QUARK_UART_DLM 0x01 + +#define QUARK_UART_BRCSR 0x0E + -+#define QUARK_UART_IID_RLS (QUARK_UART_IIR_REI) -+#define QUARK_UART_IID_RDR (QUARK_UART_IIR_RRI) -+#define QUARK_UART_IID_RDR_TO (QUARK_UART_IIR_RRI | QUARK_UART_IIR_TOI) -+#define QUARK_UART_IID_THRE (QUARK_UART_IIR_TRI) ++#define QUARK_UART_IID_RLS (QUARK_UART_IIR_REI) ++#define QUARK_UART_IID_RDR (QUARK_UART_IIR_RRI) ++#define QUARK_UART_IID_RDR_TO (QUARK_UART_IIR_RRI | QUARK_UART_IIR_TOI) ++#define QUARK_UART_IID_THRE (QUARK_UART_IIR_TRI) +#define QUARK_UART_IID_MS (QUARK_UART_IIR_MSI) + +#define QUARK_UART_HAL_PARITY_NONE (QUARK_UART_LCR_NP) @@ -3844,29 +3898,29 @@ index 0000000..5c0a01a +#define QUARK_UART_HAL_CLR_ALL_FIFO (QUARK_UART_HAL_CLR_TX_FIFO | \ + QUARK_UART_HAL_CLR_RX_FIFO) + -+#define QUARK_UART_HAL_DMA_MODE0 0 ++#define QUARK_UART_HAL_DMA_MODE0 0 +#define QUARK_UART_HAL_FIFO_DIS 0 +#define QUARK_UART_HAL_FIFO16 (QUARK_UART_FCR_FIFOE) +#define QUARK_UART_HAL_FIFO256 (QUARK_UART_FCR_FIFOE | \ + QUARK_UART_FCR_FIFO256) +#define QUARK_UART_HAL_FIFO64 (QUARK_UART_HAL_FIFO256) +#define QUARK_UART_HAL_TRIGGER1 (QUARK_UART_FCR_RFTL1) -+#define QUARK_UART_HAL_TRIGGER64 (QUARK_UART_FCR_RFTL64) -+#define QUARK_UART_HAL_TRIGGER128 (QUARK_UART_FCR_RFTL128) -+#define QUARK_UART_HAL_TRIGGER224 (QUARK_UART_FCR_RFTL224) -+#define QUARK_UART_HAL_TRIGGER16 (QUARK_UART_FCR_RFTL16) -+#define QUARK_UART_HAL_TRIGGER32 (QUARK_UART_FCR_RFTL32) -+#define QUARK_UART_HAL_TRIGGER56 (QUARK_UART_FCR_RFTL56) ++#define QUARK_UART_HAL_TRIGGER64 (QUARK_UART_FCR_RFTL64) ++#define QUARK_UART_HAL_TRIGGER128 (QUARK_UART_FCR_RFTL128) ++#define QUARK_UART_HAL_TRIGGER224 (QUARK_UART_FCR_RFTL224) ++#define QUARK_UART_HAL_TRIGGER16 (QUARK_UART_FCR_RFTL16) ++#define QUARK_UART_HAL_TRIGGER32 (QUARK_UART_FCR_RFTL32) ++#define QUARK_UART_HAL_TRIGGER56 (QUARK_UART_FCR_RFTL56) +#define QUARK_UART_HAL_TRIGGER4 (QUARK_UART_FCR_RFTL4) +#define QUARK_UART_HAL_TRIGGER8 (QUARK_UART_FCR_RFTL8) -+#define QUARK_UART_HAL_TRIGGER14 (QUARK_UART_FCR_RFTL14) -+#define QUARK_UART_HAL_TRIGGER_L (QUARK_UART_FCR_RFTL64) -+#define QUARK_UART_HAL_TRIGGER_M (QUARK_UART_FCR_RFTL128) -+#define QUARK_UART_HAL_TRIGGER_H (QUARK_UART_FCR_RFTL224) ++#define QUARK_UART_HAL_TRIGGER14 (QUARK_UART_FCR_RFTL14) ++#define QUARK_UART_HAL_TRIGGER_L (QUARK_UART_FCR_RFTL64) ++#define QUARK_UART_HAL_TRIGGER_M (QUARK_UART_FCR_RFTL128) ++#define QUARK_UART_HAL_TRIGGER_H (QUARK_UART_FCR_RFTL224) + +#define QUARK_UART_HAL_RX_INT (QUARK_UART_IER_ERBFI) +#define QUARK_UART_HAL_TX_INT (QUARK_UART_IER_ETBEI) -+#define QUARK_UART_HAL_RX_ERR_INT (QUARK_UART_IER_ELSI) ++#define QUARK_UART_HAL_RX_ERR_INT (QUARK_UART_IER_ELSI) +#define QUARK_UART_HAL_MS_INT (QUARK_UART_IER_EDSSI) +#define QUARK_UART_HAL_ALL_INT (QUARK_UART_IER_MASK) + @@ -3910,36 +3964,36 @@ index 0000000..5c0a01a + unsigned int dmsr; + unsigned int fcr; + unsigned int mcr; -+ unsigned int use_dma; ++ unsigned int ier; ++ bool use_dma; + struct dma_async_tx_descriptor *desc_tx; + struct dma_async_tx_descriptor *desc_rx; -+#if 1 -+ struct dma_chan *chan_tx; -+ struct dma_chan *chan_rx; ++ struct dma_chan *tx_chan; ++ struct dma_chan *rx_chan; + struct middma_device mid_dma; + struct quark_uart_buffer txbuf; + struct quark_uart_buffer rxbuf; + struct intel_mid_dma_slave dmas_rx; + struct intel_mid_dma_slave dmas_tx; -+#else -+ struct quark_dma_slave param_tx; -+ struct quark_dma_slave param_rx; -+ struct dma_chan *chan_tx; -+ struct dma_chan *chan_rx; -+#endif + struct scatterlist *sg_tx_p; + int nent; + struct scatterlist sg_rx; + int tx_dma_use; + void *rx_buf_virt; + dma_addr_t rx_buf_dma; -+ + struct dentry *debugfs; -+ ++ struct work_struct work; ++ int dma_tx_in_flight; + /* protect the x1000_port private structure and io access to membase */ + spinlock_t lock; ++ struct dma_slave_config tx_conf; ++ struct dma_slave_config rx_conf; ++ wait_queue_head_t w_queue; ++ +}; + ++static struct uart_driver quark_uart_driver; ++ +/** + * struct quark_uart_driver_data - private data structure for UART-DMA + * @port_type: The number of DMA channel @@ -3950,19 +4004,16 @@ index 0000000..5c0a01a + int line_no; +}; + -+#if 0 -+static unsigned int mem_serial_in(struct uart_port *p, int offset) ++/** ++ * intel_qrk_dma_chan_filter ++ * ++ * Simple descriptor disjunct function ++ */ ++static bool intel_qrk_dma_chan_filter(struct dma_chan * chan, void *param) +{ -+ offset = offset << p->regshift; -+ return readb(p->membase + offset); ++ return 1; +} + -+static void mem_serial_out(struct uart_port *p, int offset, int value) -+{ -+ offset = offset << p->regshift; -+ writeb(value, p->membase + offset); -+} -+#endif + +/** + * serial_in @@ -3999,6 +4050,7 @@ index 0000000..5c0a01a +static struct x1000_port *quark_uart_ports[QUARK_UART_NR]; +#endif +static unsigned int default_baud = 115200; ++static bool use_dma = true; +static const int trigger_level_256[4] = { 1, 64, 128, 224 }; +static const int trigger_level_64[4] = { 1, 16, 32, 56 }; +static const int trigger_level_16[4] = { 1, 4, 8, 14 }; @@ -4008,7 +4060,6 @@ index 0000000..5c0a01a + +#define QUARK_REGS_BUFSIZE 1024 + -+ +static ssize_t port_show_regs(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ @@ -4059,6 +4110,7 @@ index 0000000..5c0a01a + return ret; +} + ++ +static const struct file_operations port_regs_ops = { + .owner = THIS_MODULE, + .open = simple_open, @@ -4077,24 +4129,17 @@ index 0000000..5c0a01a + unsigned int flag) +{ + u8 ier = serial_in(priv, UART_IER); -+#ifdef __QRK_DMA_DEBUG -+// pr_info("%s read IER %x\n", __func__, ier); -+#endif + ier |= flag & QUARK_UART_IER_MASK; ++ priv->ier = ier; + serial_out(priv, UART_IER, ier); -+#ifdef __QRK_DMA_DEBUG -+// pr_info("%s wrote IER %x\n", __func__, ier); -+#endif +} + +static void quark_uart_hal_disable_interrupt(struct x1000_port *priv, + unsigned int flag) +{ -+#ifdef __QRK_DMA_DEBUG -+// pr_info("%s entry\n", __func__); -+#endif + u8 ier = serial_in(priv, UART_IER); + ier &= ~(flag & QUARK_UART_IER_MASK); ++ priv->ier = ier; + serial_out(priv, UART_IER, ier); +} + @@ -4133,11 +4178,6 @@ index 0000000..5c0a01a + lcr |= bits; + lcr |= stb; + -+#ifdef __QRK_DMA_DEBUG -+ /* TODO: change this back to dev_dbg - BOD */ -+ dev_info(priv->port.dev, "%s:baud = %u, div = %04x, lcr = %02x (%lu)\n", -+ __func__, baud, div, lcr, jiffies); -+#endif + serial_out(priv, UART_LCR, QUARK_UART_LCR_DLAB); + serial_out(priv, QUARK_UART_DLL, dll); + serial_out(priv, QUARK_UART_DLM, dlm); @@ -4205,22 +4245,15 @@ index 0000000..5c0a01a + trigger_level_1[trigger >> QUARK_UART_FCR_RFTL_SHIFT]; + break; + } -+#if 0 + fcr = + dmamode | fifo_size | trigger | QUARK_UART_FCR_RFR | QUARK_UART_FCR_TFR; -+#else -+ fcr = -+ fifo_size | trigger | QUARK_UART_FCR_RFR | QUARK_UART_FCR_TFR; + -+#endif + serial_out(priv, UART_FCR, QUARK_UART_FCR_FIFOE); + serial_out(priv, + UART_FCR, QUARK_UART_FCR_FIFOE | QUARK_UART_FCR_RFR | QUARK_UART_FCR_TFR); + serial_out(priv, UART_FCR, fcr); + priv->fcr = fcr; -+#ifdef __QRK_DMA_DEBUG -+ pr_info("%s FCR set to %x\n", __func__, priv->fcr); -+#endif ++ + return 0; +} + @@ -4346,101 +4379,6 @@ index 0000000..5c0a01a + return room; +} + -+static void quark_free_dma(struct uart_port *port) -+{ -+ struct x1000_port *priv; -+ priv = container_of(port, struct x1000_port, port); -+ -+ if (priv->chan_tx) { -+ dma_release_channel(priv->chan_tx); -+ priv->chan_tx = NULL; -+ } -+ if (priv->chan_rx) { -+ dma_release_channel(priv->chan_rx); -+ priv->chan_rx = NULL; -+ } -+ -+ if (priv->rx_buf_dma) { -+ dma_free_coherent(port->dev, port->fifosize, priv->rx_buf_virt, -+ priv->rx_buf_dma); -+ priv->rx_buf_virt = NULL; -+ priv->rx_buf_dma = 0; -+ } -+ -+ return; -+} -+ -+static bool filter(struct dma_chan *chan, void *slave) -+{ -+ #if 0 -+ struct quark_dma_slave *param = slave; -+ -+ if ((chan->chan_id == param->chan_id) && (param->dma_dev == -+ chan->device->dev)) { -+ chan->private = param; -+ return true; -+ } else { -+ return false; -+ } -+ #else -+ return true; -+ #endif -+} -+ -+static void quark_request_dma(struct uart_port *port) -+{ -+ dma_cap_mask_t mask; -+ struct dma_chan *chan; -+ struct pci_dev *dma_dev; -+#if 0 -+ struct quark_dma_slave *param; -+#endif -+ struct x1000_port *priv = -+ container_of(port, struct x1000_port, port); -+ dma_cap_zero(mask); -+ dma_cap_set(DMA_SLAVE, mask); -+ -+ dma_dev = pci_get_bus_and_slot(priv->pdev->bus->number, -+ PCI_DEVFN(0xa, 0)); /* Get DMA's dev -+ information */ -+ /* Set Tx DMA */ -+#if 0 -+ param = &priv->param_tx; -+ param->dma_dev = &dma_dev->dev; -+ param->chan_id = priv->port.line * 2; /* Tx = 0, 2, 4, ... */ -+ -+ param->tx_reg = port->mapbase + UART_TX; -+#endif -+ chan = dma_request_channel(mask, filter, &priv->dmas_tx); -+ if (!chan) { -+ dev_err(priv->port.dev, "%s:dma_request_channel FAILS(Tx)\n", -+ __func__); -+ return; -+ } -+ priv->chan_tx = chan; -+#if 0 -+ /* Set Rx DMA */ -+ param = &priv->param_rx; -+ param->dma_dev = &dma_dev->dev; -+ param->chan_id = priv->port.line * 2 + 1; /* Rx = Tx + 1 */ -+ -+ param->rx_reg = port->mapbase + UART_RX; -+#endif -+ chan = dma_request_channel(mask, filter, &priv->dmas_rx); -+ if (!chan) { -+ dev_err(priv->port.dev, "%s:dma_request_channel FAILS(Rx)\n", -+ __func__); -+ dma_release_channel(priv->chan_tx); -+ priv->chan_tx = NULL; -+ return; -+ } -+ -+ /* Get Consistent memory for DMA */ -+ priv->rx_buf_virt = dma_alloc_coherent(port->dev, port->fifosize, -+ &priv->rx_buf_dma, GFP_KERNEL); -+ priv->chan_rx = chan; -+} -+ +static void quark_dma_rx_complete(void *arg) +{ + struct x1000_port *priv = arg; @@ -4464,18 +4402,32 @@ index 0000000..5c0a01a + struct circ_buf *xmit = &port->state->xmit; + struct scatterlist *sg = priv->sg_tx_p; + int i; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->lock, flags); + + for (i = 0; i < priv->nent; i++, sg++) { + xmit->tail += sg_dma_len(sg); + port->icount.tx += sg_dma_len(sg); + } -+ xmit->tail &= UART_XMIT_SIZE - 1; ++ /* Make sure that xmit->head and xmit->tail are equal ++ to zero at the end of a transaction */ ++ if(priv->tx_dma_use == 0) ++ xmit->head = xmit->tail = 0; ++ else ++ xmit->tail &= UART_XMIT_SIZE - 1; + async_tx_ack(priv->desc_tx); + dma_unmap_sg(port->dev, sg, priv->nent, DMA_TO_DEVICE); + priv->tx_dma_use = 0; + priv->nent = 0; ++ priv->tx_empty = 1; + kfree(priv->sg_tx_p); ++ + quark_uart_hal_enable_interrupt(priv, QUARK_UART_HAL_TX_INT); ++ priv->dma_tx_in_flight = 0; ++ wake_up(&priv->w_queue); ++ ++ spin_unlock_irqrestore(&priv->lock, flags); +} + +static int pop_tx(struct x1000_port *priv, int size) @@ -4548,10 +4500,21 @@ index 0000000..5c0a01a + + sg_dma_address(sg) = priv->rx_buf_dma; + -+ desc = dmaengine_prep_slave_sg(priv->chan_rx, -+ sg, 1, DMA_DEV_TO_MEM, -+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK); ++ /* Configure RX */ ++ priv->rx_conf.dst_addr = sg_dma_address(sg); ++ priv->rx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ priv->rx_conf.dst_maxburst = LNW_DMA_MSIZE_1; ++ ++ priv->rx_conf.src_addr = QUARK_UART_AHB_REG_BASE + QUARK_UART_THR; /* Wants an AHB address */ ++ priv->rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; ++ priv->rx_conf.src_maxburst = LNW_DMA_MSIZE_4; ++ priv->rx_conf.direction = DMA_DEV_TO_MEM; ++ priv->rx_conf.device_fc = false; + ++ dmaengine_slave_config(priv->rx_chan, &priv->rx_conf); ++ desc = dmaengine_prep_slave_sg(priv->rx_chan, ++ sg, 1, DMA_DEV_TO_MEM, ++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) + return 0; + @@ -4559,7 +4522,7 @@ index 0000000..5c0a01a + desc->callback = quark_dma_rx_complete; + desc->callback_param = priv; + desc->tx_submit(desc); -+ dma_async_issue_pending(priv->chan_rx); ++ dma_async_issue_pending(priv->rx_chan); + + return QUARK_UART_HANDLED_RX_INT; +} @@ -4574,9 +4537,10 @@ index 0000000..5c0a01a + int tx_empty; + + if (!priv->start_tx) { -+ dev_info(priv->port.dev, "%s:Tx isn't started. (%lu)\n", ++ dev_dbg(priv->port.dev, "%s:Tx isn't started. (%lu)\n", + __func__, jiffies); + quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_TX_INT); ++ wake_up(&priv->w_queue); + priv->tx_empty = 1; + return 0; + } @@ -4600,15 +4564,17 @@ index 0000000..5c0a01a + } + + priv->tx_empty = tx_empty; -+ + if (tx_empty) { + quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_TX_INT); -+ uart_write_wakeup(port); ++ wake_up(&priv->w_queue); ++ if (port->state->port.tty != NULL) ++ uart_write_wakeup(port); + } + + return QUARK_UART_HANDLED_TX_INT; +} + ++ +static unsigned int dma_handle_tx(struct x1000_port *priv) +{ + struct uart_port *port = &priv->port; @@ -4617,17 +4583,18 @@ index 0000000..5c0a01a + int nent; + int fifo_size; + int tx_empty; -+ struct dma_async_tx_descriptor *desc; + int num; + int i; + int bytes; + int size; + int rem; ++ int ret; + + if (!priv->start_tx) { -+ dev_info(priv->port.dev, "%s:Tx isn't started. (%lu)\n", ++ dev_dbg(priv->port.dev, "%s:Tx isn't started. (%lu)\n", + __func__, jiffies); + quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_TX_INT); ++ wake_up(&priv->w_queue); + priv->tx_empty = 1; + return 0; + } @@ -4636,11 +4603,12 @@ index 0000000..5c0a01a + dev_dbg(priv->port.dev, "%s:Tx is not completed. (%lu)\n", + __func__, jiffies); + quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_TX_INT); ++ wake_up(&priv->w_queue); + priv->tx_empty = 1; + return 0; + } + -+ fifo_size = max(priv->fifo_size, 1); ++ fifo_size = QUARK_UART_MAXBURST; + tx_empty = 1; + if (pop_tx_x(priv, xmit->buf)) { + quark_uart_hal_write(priv, xmit->buf, 1); @@ -4652,15 +4620,37 @@ index 0000000..5c0a01a + bytes = min((int)CIRC_CNT(xmit->head, xmit->tail, + UART_XMIT_SIZE), CIRC_CNT_TO_END(xmit->head, + xmit->tail, UART_XMIT_SIZE)); ++ + if (!bytes) { + dev_dbg(priv->port.dev, "%s 0 bytes return\n", __func__); + quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_TX_INT); -+ uart_write_wakeup(port); ++ wake_up(&priv->w_queue); ++ if (port->state->port.tty != NULL) ++ uart_write_wakeup(port); + return 0; + } + ++ /* DMA block doesn't do !dword aligned */ ++ if (bytes % 0x04){ ++ if (bytes < 4){ ++ ret = handle_tx(priv); ++ /* DMA transactions want to start DWORD aligned */ ++ xmit->head = xmit->tail = 0; ++ return ret; ++ } ++ bytes &= 0xFFFFFFFC; ++ } ++ ++ /* For small payloads its just faster to write the FIFO directly */ ++ if (bytes < QUARK_FIFO_FASTER_LEN){ ++ ret = handle_tx(priv); ++ /* DMA transactions want to start DWORD aligned */ ++ xmit->head = xmit->tail = 0; ++ return ret; ++ } ++ + if (bytes > fifo_size) { -+ num = bytes / fifo_size + 1; ++ num = bytes / fifo_size; + size = fifo_size; + rem = bytes % fifo_size; + } else { @@ -4684,6 +4674,7 @@ index 0000000..5c0a01a + sg = priv->sg_tx_p; + + for (i = 0; i < num; i++, sg++) { ++ BUG_ON((int)xmit->buf & ~PAGE_MASK); + if (i == (num - 1)) + sg_set_page(sg, virt_to_page(xmit->buf), + rem, fifo_size * i); @@ -4705,28 +4696,18 @@ index 0000000..5c0a01a + fifo_size * i; + sg_dma_address(sg) = (sg_dma_address(sg) & + ~(UART_XMIT_SIZE - 1)) + sg->offset; ++ + if (i == (nent - 1)) -+ sg_dma_len(sg) = rem; ++ sg_dma_len(sg) = bytes; + else + sg_dma_len(sg) = size; ++ bytes -= size; + } + -+ desc = dmaengine_prep_slave_sg(priv->chan_tx, -+ priv->sg_tx_p, nent, DMA_MEM_TO_DEV, -+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK); -+ if (!desc) { -+ dev_err(priv->port.dev, "%s:device_prep_slave_sg Failed\n", -+ __func__); -+ return 0; -+ } -+ dma_sync_sg_for_device(port->dev, priv->sg_tx_p, nent, DMA_TO_DEVICE); -+ priv->desc_tx = desc; -+ desc->callback = quark_dma_tx_complete; -+ desc->callback_param = priv; -+ -+ desc->tx_submit(desc); -+ -+ dma_async_issue_pending(priv->chan_tx); ++ priv->dma_tx_in_flight = 1; ++ quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_TX_INT); ++ wake_up(&priv->w_queue); ++ schedule_work(&priv->work); + + return QUARK_UART_HANDLED_TX_INT; +} @@ -4772,6 +4753,42 @@ index 0000000..5c0a01a + #define unmask_pvm(x) +#endif + ++static void quark_uart_work(struct work_struct *work) ++{ ++ struct x1000_port *priv = container_of(work, struct x1000_port,work); ++ struct dma_async_tx_descriptor *desc; ++ ++ if (priv == NULL) { ++ pr_err("ERR_X1000: tasklet Null param\n"); ++ return; ++ } ++ /* Configure TX */ ++ priv->tx_conf.src_addr = sg_dma_address(priv->sg_tx_p); ++ priv->tx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ priv->tx_conf.src_maxburst = LNW_DMA_MSIZE_1; ++ priv->tx_conf.dst_addr = QUARK_UART_AHB_REG_BASE + QUARK_UART_THR; /* Wants an AHB address */ ++ priv->tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; ++ priv->tx_conf.dst_maxburst = LNW_DMA_MSIZE_4; ++ priv->tx_conf.direction = DMA_MEM_TO_DEV; ++ priv->tx_conf.device_fc = false; ++ ++ dmaengine_slave_config(priv->tx_chan, &priv->tx_conf); ++ desc = dmaengine_prep_slave_sg(priv->tx_chan, ++ priv->sg_tx_p, priv->nent, DMA_MEM_TO_DEV, ++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK); ++ if (!desc) { ++ dev_err(priv->port.dev, "%s:device_prep_slave_sg Failed\n", ++ __func__); ++ return; ++ } ++ dma_sync_sg_for_device(priv->port.dev, priv->sg_tx_p, priv->nent, DMA_TO_DEVICE); ++ priv->desc_tx = desc; ++ desc->callback = quark_dma_tx_complete; ++ desc->callback_param = priv; ++ desc->tx_submit(desc); ++ dma_async_issue_pending(priv->tx_chan); ++} ++ +static irqreturn_t quark_uart_interrupt(int irq, void *dev_id) +{ + struct x1000_port *priv = dev_id; @@ -4801,18 +4818,9 @@ index 0000000..5c0a01a + } + break; + case QUARK_UART_IID_RDR: /* Received Data Ready */ -+ if (priv->use_dma) { -+ quark_uart_hal_disable_interrupt(priv, -+ QUARK_UART_HAL_RX_INT | -+ QUARK_UART_HAL_RX_ERR_INT); -+ ret = dma_handle_rx(priv); -+ if (!ret) -+ quark_uart_hal_enable_interrupt(priv, -+ QUARK_UART_HAL_RX_INT | -+ QUARK_UART_HAL_RX_ERR_INT); -+ } else { -+ ret = handle_rx(priv); -+ } ++ ++ (void)dma_handle_rx; /*Not worth setup time*/ ++ ret = handle_rx(priv); + break; + case QUARK_UART_IID_RDR_TO: /* Received Data Ready + (FIFO Timeout) */ @@ -4821,7 +4829,6 @@ index 0000000..5c0a01a + case QUARK_UART_IID_THRE: /* Transmitter Holding Register + Empty */ + if (priv->use_dma) -+ + ret = dma_handle_tx(priv); + else + ret = handle_tx(priv); @@ -4909,45 +4916,48 @@ index 0000000..5c0a01a +static void quark_uart_stop_tx(struct uart_port *port) +{ + struct x1000_port *priv; ++ unsigned long flags; + priv = container_of(port, struct x1000_port, port); ++ ++ spin_lock_irqsave(&priv->lock, flags); + priv->start_tx = 0; + priv->tx_dma_use = 0; ++ ++ spin_unlock_irqrestore(&priv->lock, flags); +} + +static void quark_uart_start_tx(struct uart_port *port) +{ + struct x1000_port *priv; + ++ unsigned long flags; + priv = container_of(port, struct x1000_port, port); + ++ spin_lock_irqsave(&priv->lock, flags); + if (priv->use_dma) { + if (priv->tx_dma_use) { + dev_dbg(priv->port.dev, "%s : Tx DMA is NOT empty.\n", + __func__); -+ return; ++ goto done; + } + } + -+#ifdef __QRK_DMA_DEBUG -+ unsigned char iid = quark_uart_hal_get_iid(priv); -+ pr_info("%s enable interrupt IER %x FCR %x iid %x\n", __func__, serial_in(priv, UART_IER), -+ serial_in(priv, UART_FCR), iid); -+#endif + priv->start_tx = 1; -+ quark_uart_hal_enable_interrupt(priv, QUARK_UART_HAL_TX_INT); ++ if( priv->dma_tx_in_flight == 0) ++ quark_uart_hal_enable_interrupt(priv, QUARK_UART_HAL_TX_INT); ++ ++done: ++ spin_unlock_irqrestore(&priv->lock, flags); ++ +} + +static void quark_uart_stop_rx(struct uart_port *port) +{ + struct x1000_port *priv; -+ + priv = container_of(port, struct x1000_port, port); ++ ++ wait_event(priv->w_queue,!(priv->ier & QUARK_UART_HAL_TX_INT) && !priv->dma_tx_in_flight); + priv->start_rx = 0; -+#ifdef __QRK_DMA_DEBUG -+ unsigned char iid; -+ iid = quark_uart_hal_get_iid(priv); -+ pr_info("%s IID is 0x%x USR 0x%x LSR 0x%x MSR 0x%x\n", __func__, iid, serial_in(priv,31), serial_in(priv, UART_LSR), serial_in(priv, UART_MSR)); -+#endif + quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_RX_INT | + QUARK_UART_HAL_RX_ERR_INT); +} @@ -4987,9 +4997,7 @@ index 0000000..5c0a01a + priv->uartclk = port->uartclk; + else + port->uartclk = priv->uartclk; -+#ifdef __QRK_DMA_DEBUG -+ pr_info("%s entry fifo size %d!\n", __func__, priv->fifo_size); -+#endif ++ + quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_ALL_INT); + ret = quark_uart_hal_set_line(priv, default_baud, + QUARK_UART_HAL_PARITY_NONE, QUARK_UART_HAL_8BIT, @@ -5031,28 +5039,14 @@ index 0000000..5c0a01a + } + + priv->trigger_level = trigger_level; -+#ifdef __QRK_DMA_DEBUG -+ pr_info("%s setting FCR fifo_size %d FIFO trig %d\n", __func__, fifo_size, priv->trigger); -+#endif + ret = quark_uart_hal_set_fifo(priv, QUARK_UART_HAL_DMA_MODE0, + fifo_size, priv->trigger); + if (ret < 0) + return ret; -+ -+ if (priv->use_dma) -+ quark_request_dma(port); -+ -+#ifdef __QRK_DMA_DEBUG -+ pr_info("%s enable interrupt IER %x FCR %x USR %x\n", __func__, serial_in(priv, UART_IER), -+ serial_in(priv, UART_FCR), serial_in(priv, 31)); -+#endif + priv->start_rx = 1; + quark_uart_hal_enable_interrupt(priv, QUARK_UART_HAL_RX_INT | + QUARK_UART_HAL_RX_ERR_INT); + uart_update_timeout(port, CS8, default_baud); -+#ifdef __QRK_DMA_DEBUG -+ pr_info("%s exit IER %x FCR %x USR %x\n", __func__, serial_in(priv, UART_IER), serial_in(priv, UART_FCR), serial_in(priv, 31)); -+#endif + return 0; +} + @@ -5061,10 +5055,10 @@ index 0000000..5c0a01a + struct x1000_port *priv; + int ret; + -+#ifdef __QRK_DMA_DEBUG -+ pr_info("%s called!\n", __func__); -+#endif + priv = container_of(port, struct x1000_port, port); ++ ++ wait_event(priv->w_queue, !(priv->dma_tx_in_flight)); ++ + quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_ALL_INT); + quark_uart_hal_fifo_reset(priv, QUARK_UART_HAL_CLR_ALL_FIFO); + ret = quark_uart_hal_set_fifo(priv, QUARK_UART_HAL_DMA_MODE0, @@ -5072,8 +5066,6 @@ index 0000000..5c0a01a + if (ret) + dev_err(priv->port.dev, + "quark_uart_hal_set_fifo Failed(ret=%d)\n", ret); -+ -+ quark_free_dma(port); +} + +/* Change the port parameters, including word length, parity, stop @@ -5125,7 +5117,6 @@ index 0000000..5c0a01a + termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */ + + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); -+ + spin_lock_irqsave(&priv->lock, flags); + spin_lock(&port->lock); + @@ -5160,23 +5151,6 @@ index 0000000..5c0a01a + +static int quark_uart_request_port(struct uart_port *port) +{ -+#if 0 -+ struct x1000_port *priv; -+ int ret; -+ void __iomem *membase; -+ -+ priv = container_of(port, struct x1000_port, port); -+ ret = pci_request_regions(priv->pdev, KBUILD_MODNAME); -+ if (ret < 0) -+ return -EBUSY; -+ -+ membase = pci_iomap(priv->pdev, 1, 0); -+ if (!membase) { -+ pci_release_regions(priv->pdev); -+ return -EBUSY; -+ } -+ priv->membase = port->membase = membase; -+#endif + return 0; +} + @@ -5184,9 +5158,6 @@ index 0000000..5c0a01a +{ + struct x1000_port *priv; + -+#ifdef __QRK_DMA_DEBUG -+ pr_info("%s entry!\n", __func__); -+#endif + priv = container_of(port, struct x1000_port, port); + if (type & UART_CONFIG_TYPE) { + port->type = priv->port_type; @@ -5198,25 +5169,20 @@ index 0000000..5c0a01a + struct serial_struct *serinfo) +{ + struct x1000_port *priv; -+#ifdef __QRK_DMA_DEBUG -+ pr_info("%s entry point !\n", __func__); -+#endif + priv = container_of(port, struct x1000_port, port); ++ + if (serinfo->flags & UPF_LOW_LATENCY) { + dev_info(priv->port.dev, + "QUARK UART : Use PIO Mode (without DMA)\n"); -+ priv->use_dma = 0; ++ priv->use_dma = false; + serinfo->flags &= ~UPF_LOW_LATENCY; + } else { -+#ifndef CONFIG_QUARK_DMA -+ dev_err(priv->port.dev, "%s : QUARK DMA is not Loaded.\n", -+ __func__); -+ return -EOPNOTSUPP; -+#endif + dev_info(priv->port.dev, "QUARK UART : Use DMA Mode\n"); ++ #if 0 + if (!priv->use_dma) + quark_request_dma(port); -+ priv->use_dma = 1; ++ #endif ++ priv->use_dma = true; + } + + return 0; @@ -5318,7 +5284,7 @@ index 0000000..5c0a01a + .startup = quark_uart_startup, + .shutdown = quark_uart_shutdown, + .set_termios = quark_uart_set_termios, -+/* .pm = quark_uart_pm, Not supported yet */ ++/* .pm = quark_uart_pm, Not supported yet */ +/* .set_wake = quark_uart_set_wake, Not supported yet */ + .type = quark_uart_type, + .release_port = quark_uart_release_port, @@ -5365,7 +5331,7 @@ index 0000000..5c0a01a + if (priv->port.sysrq) { + /* call to uart_handle_sysrq_char already took the priv lock */ + priv_locked = 0; -+ /* serial8250_handle_port() already took the port lock */ ++ /* serialquark_uart_handle_port() already took the port lock */ + port_locked = 0; + } else if (oops_in_progress) { + priv_locked = spin_trylock(&priv->lock); @@ -5426,8 +5392,6 @@ index 0000000..5c0a01a + return uart_set_options(port, co, baud, parity, bits, flow); +} + -+static struct uart_driver quark_uart_driver; -+ +static struct console quark_console = { + .name = QUARK_UART_DRIVER_DEVICE, + .write = quark_console_write, @@ -5447,31 +5411,29 @@ index 0000000..5c0a01a + .owner = THIS_MODULE, + .driver_name = KBUILD_MODNAME, + .dev_name = QUARK_UART_DRIVER_DEVICE, -+ .major = 0, -+ .minor = 0, + .nr = QUARK_UART_NR, + .cons = QUARK_CONSOLE, +}; + ++static int line_no; /* eek! TODO */ ++ +static struct x1000_port *quark_uart_init_port(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct x1000_port *priv; + int ret, len; ++ dma_cap_mask_t mask; + unsigned char *rxbuf; + char name[32]; /* for debugfs file name */ + struct intel_mid_dma_probe_info * info = NULL; + -+ dev_info(&pdev->dev,"QUARK UART-DMA (ID: %04x:%04x) pdev->irq %d\n", ++ dev_dbg(&pdev->dev,"QUARK UART-DMA (ID: %04x:%04x) pdev->irq %d\n", + pdev->vendor, pdev->device, pdev->irq); + + info = (void*)id->driver_data; + dev_info(&pdev->dev,"QUARK UART-DMA : CH %d base %d block len %d per mask %x\n", + info->max_chan, info->ch_base, info->block_size, info->pimr_mask); -+#if 0 -+ board = &drv_dat[id->driver_data]; -+ port_type = board->port_type; -+#endif ++ + priv = kzalloc(sizeof(struct x1000_port), GFP_KERNEL); + if (priv == NULL) + goto init_port_alloc_err; @@ -5480,10 +5442,12 @@ index 0000000..5c0a01a + if (!rxbuf) + goto init_port_free_txbuf; + ++ priv->mid_dma.pdev = pci_dev_get(pdev); + pci_set_master(pdev); + + spin_lock_init(&priv->lock); + ++ /* UART regs */ + priv->mapbase = pci_resource_start(pdev, 0); + len = pci_resource_len(pdev, 0); + priv->membase = ioremap_nocache(priv->mapbase, len); @@ -5492,6 +5456,54 @@ index 0000000..5c0a01a + goto init_port_free_txbuf; + } + ++ /* DMA driver */ ++ priv->mid_dma.max_chan = info->max_chan; /* Max channels */ ++ priv->mid_dma.chan_base = info->ch_base; /* Index start */ ++ priv->mid_dma.block_size = info->block_size; /* MAX DMA block */ ++ priv->mid_dma.pimr_mask = info->pimr_mask; /* Per int regs bool */ ++ priv->mid_dma.is_quark = info->is_quark; ++ ++ ret = intel_qrk_dma_probe(pdev, &priv->mid_dma); ++ if(ret != 0){ ++ dev_err(&pdev->dev, "Unable to init DMA sub-system\n"); ++ goto init_port_free_uart_iomem; ++ } ++ ++ /* Request DMA channels TODO: move to startup() once debugged on hw */ ++ dma_cap_zero(mask); ++ dma_cap_set(DMA_SLAVE, mask); ++ ++ priv->rx_chan = dma_request_channel(mask, intel_qrk_dma_chan_filter, &priv->dmas_rx); ++ if(priv->rx_chan == NULL){ ++ dev_err(&pdev->dev, "Unable to hook DMA RX channel\n"); ++ goto init_port_free_dma_iomem; ++ }; ++ priv->rx_buf_virt = dma_alloc_coherent(&pdev->dev, QUARK_UART_FIFO_LEN, ++ &priv->rx_buf_dma, GFP_KERNEL); ++ if (priv->rx_buf_virt == NULL){ ++ dev_err(&pdev->dev, "Unable to allocate %d bytes for DMA\n", ++ QUARK_UART_FIFO_LEN); ++ goto init_port_free_dma_iomem; ++ } ++ ++ priv->dmas_rx.hs_mode = LNW_DMA_HW_HS; ++ priv->dmas_rx.cfg_mode = LNW_DMA_PER_TO_MEM; ++ /* Configure RX */ ++ ++ priv->tx_chan = dma_request_channel(mask, intel_qrk_dma_chan_filter, &priv->dmas_tx); ++ if(priv->tx_chan == NULL){ ++ dev_err(&pdev->dev, "Unable to hook DMA RX channel\n"); ++ goto init_port_free_dma_iomem; ++ }; ++ priv->dmas_tx.hs_mode = LNW_DMA_HW_HS; ++ priv->dmas_tx.cfg_mode = LNW_DMA_MEM_TO_PER; ++ ++ dev_info(&pdev->dev, "using %s for DMA RX %s for DMA TX DMA %s\n", ++ dev_name(&priv->rx_chan->dev->device), ++ dev_name(&priv->tx_chan->dev->device), use_dma ? ++ "enabled" : "disabled"); ++ ++ /* Setup UART port descriptor */ + priv->pdev = pdev; + priv->tx_empty = 1; + priv->rxbuf.buf = rxbuf; @@ -5507,8 +5519,10 @@ index 0000000..5c0a01a + priv->port.ops = &quark_uart_ops; + priv->port.flags = UPF_BOOT_AUTOCONF; + priv->port.fifosize = QUARK_UART_FIFO_LEN; -+ priv->port.line = pdev->dev.id; -+ priv->trigger = QUARK_UART_HAL_TRIGGER_M; ++ priv->port.line = line_no; ++ priv->trigger = QUARK_UART_HAL_TRIGGER_L; ++ priv->use_dma = use_dma; ++ use_dma = 0; + + spin_lock_init(&priv->port.lock); + pci_set_drvdata(pdev, priv); @@ -5517,33 +5531,41 @@ index 0000000..5c0a01a + + ret = request_irq(pdev->irq, quark_uart_interrupt, IRQF_SHARED, + KBUILD_MODNAME, priv); -+#ifdef __QRK_DMA_DEBUG -+ pr_info("%s request_irq %d use_dma %d irq=%d\n", __func__, ret, priv->use_dma, pdev->irq); -+#endif -+ if (ret < 0) ++ if (ret < 0){ ++ dev_err(&pdev->dev, "Unable to request irq %d err %d\n", ++ pdev->irq, ret); + goto init_port_hal_free; ++ } + +#ifdef CONFIG_SERIAL_QUARK_UART_CONSOLE -+ quark_uart_ports[board->line_no] = priv; ++ quark_uart_ports[line_no++] = priv; +#endif + ret = uart_add_one_port(&quark_uart_driver, &priv->port); + -+ if (ret < 0) ++ if (ret < 0){ ++ dev_err(&pdev->dev, "uart_add_one_port fail %d\n", ret); + goto init_port_hal_free; ++ } + +#ifdef CONFIG_DEBUG_FS + snprintf(name, sizeof(name), "uart%d_regs", pdev->dev.id); + priv->debugfs = debugfs_create_file(name, S_IFREG | S_IRUGO, + NULL, priv, &port_regs_ops); +#endif -+ ++ INIT_WORK(&priv->work, quark_uart_work); ++ init_waitqueue_head(&priv->w_queue); + return priv; + +init_port_hal_free: -+#ifdef CONFIG_SERIAL_QUARK_UART_CONSOLE -+ quark_uart_ports[board->line_no] = NULL; -+#endif + free_page((unsigned long)rxbuf); ++init_port_free_dma_iomem: ++init_port_free_uart_iomem: ++ if (sg_dma_address(&priv->sg_rx)) ++ dma_free_coherent(priv->port.dev, priv->port.fifosize, ++ sg_virt(&priv->sg_rx), ++ sg_dma_address(&priv->sg_rx)); ++ ++ iounmap(priv->membase); +init_port_free_txbuf: + kfree(priv); +init_port_alloc_err: @@ -5551,13 +5573,31 @@ index 0000000..5c0a01a + return NULL; +} + -+static void quark_uart_exit_port(struct x1000_port *priv) ++static void quark_uart_exit_port(struct pci_dev *pdev, struct x1000_port *priv) +{ + +#ifdef CONFIG_DEBUG_FS + if (priv->debugfs) + debugfs_remove(priv->debugfs); +#endif ++ /* Shutdown DMA */ ++ intel_qrk_dma_remove(pdev, &priv->mid_dma); ++ ++ /* TODO: move to remove() when h/w proved out */ ++ if (priv->tx_chan) { ++ dma_release_channel(priv->tx_chan); ++ priv->tx_chan = NULL; ++ } ++ if (priv->rx_chan) { ++ dma_release_channel(priv->rx_chan); ++ priv->rx_chan = NULL; ++ } ++ ++ if (sg_dma_address(&priv->sg_rx)) ++ dma_free_coherent(priv->port.dev, priv->port.fifosize, ++ sg_virt(&priv->sg_rx), ++ sg_dma_address(&priv->sg_rx)); ++ + free_irq(priv->port.irq, priv); + uart_remove_one_port(&quark_uart_driver, &priv->port); + pci_set_drvdata(priv->pdev, NULL); @@ -5573,7 +5613,7 @@ index 0000000..5c0a01a +#ifdef CONFIG_SERIAL_QUARK_UART_CONSOLE + quark_uart_ports[priv->port.line] = NULL; +#endif -+ quark_uart_exit_port(priv); ++ quark_uart_exit_port(pdev, priv); + pci_disable_device(pdev); + kfree(priv); + return; @@ -5583,6 +5623,10 @@ index 0000000..5c0a01a +{ + struct x1000_port *priv = pci_get_drvdata(pdev); + ++ /* Suspend DMA regs */ ++ intel_qrk_dma_suspend(&priv->mid_dma); ++ ++ /* Suspend UART regs */ + uart_suspend_port(&quark_uart_driver, &priv->port); + + pci_save_state(pdev); @@ -5605,8 +5649,12 @@ index 0000000..5c0a01a + return ret; + } + ++ /* Resume UART regs */ + uart_resume_port(&quark_uart_driver, &priv->port); + ++ /* Resume DMA regs */ ++ intel_qrk_dma_resume(&priv->mid_dma); ++ + return 0; +} +#else @@ -5616,7 +5664,7 @@ index 0000000..5c0a01a + +struct pci_device_id quark_uart_pci_ids[] = { + /* channels = 2, offset = 0, block size = FIFO_LEN, pimr = 0 */ -+ { PCI_VDEVICE(INTEL, 0x0936), INFO(2, 0, QUARK_UART_FIFO_LEN, 0)}, ++ { PCI_VDEVICE(INTEL, 0x0936), INFO(2, 0, QUARK_UART_FIFO_LEN, 0, 1)}, + { 0 } +}; + @@ -5685,8 +5733,11 @@ index 0000000..5c0a01a +module_param(default_baud, uint, S_IRUGO); +MODULE_PARM_DESC(default_baud, + "Default BAUD for initial driver state and console (default 115200)"); ++module_param(use_dma, bool, S_IRUGO); ++MODULE_PARM_DESC(use_dma, ++ "Use DMA (default true)"); diff --git a/include/linux/intel_mid_dma.h b/include/linux/intel_mid_dma.h -index 10496bd..8dd64e9 100644 +index 10496bd..717458b 100644 --- a/include/linux/intel_mid_dma.h +++ b/include/linux/intel_mid_dma.h @@ -26,8 +26,10 @@ @@ -5700,7 +5751,7 @@ index 10496bd..8dd64e9 100644 /*DMA mode configurations*/ enum intel_mid_dma_mode { -@@ -73,4 +75,188 @@ struct intel_mid_dma_slave { +@@ -73,4 +75,191 @@ struct intel_mid_dma_slave { struct dma_slave_config dma_slave; }; @@ -5801,6 +5852,7 @@ index 10496bd..8dd64e9 100644 + int block_size; + bool ispci_fn; + unsigned int pimr_mask; ++ unsigned int is_quark; + enum intel_mid_dma_state state; +}; + @@ -5811,12 +5863,14 @@ index 10496bd..8dd64e9 100644 + * @ch_base: offset from register base + * @block_size: TBD + * @pimr_mask: indicates if mask registers to be mapped ++ * @is_quark: indicates if this is quark silicon + */ +struct intel_mid_dma_probe_info { + u8 max_chan; + u8 ch_base; + u16 block_size; + u32 pimr_mask; ++ u8 is_quark; +}; + + @@ -5889,6 +5943,3 @@ index 10496bd..8dd64e9 100644 + + #endif /*__INTEL_MID_DMA_H__*/ --- -1.7.4.1 - diff --git a/recipes-kernel/linux/files/0009-EFI-capsule-update-quark.patch b/recipes-kernel/linux/files/0009-EFI-capsule-update-quark.patch index ff299ee..1f7e88f 100644 --- a/recipes-kernel/linux/files/0009-EFI-capsule-update-quark.patch +++ b/recipes-kernel/linux/files/0009-EFI-capsule-update-quark.patch @@ -4,10 +4,10 @@ Date: Mon, 24 Feb 2014 18:41:59 +0000 Subject: [PATCH 09/21] EFI capsule update --- - arch/x86/platform/efi/Makefile | 3 +- - arch/x86/platform/efi/efi.c | 12 +- - arch/x86/platform/efi/efi_capsule_update.c | 331 ++++++++++++++++++++++++++++ - 3 files changed, 342 insertions(+), 4 deletions(-) + arch/x86/platform/efi/Makefile | 3 +- + arch/x86/platform/efi/efi.c | 12 +- + arch/x86/platform/efi/efi_capsule_update.c | 324 +++++++++++++++++++++++++++++ + 3 files changed, 335 insertions(+), 4 deletions(-) create mode 100644 arch/x86/platform/efi/efi_capsule_update.c diff --git a/arch/x86/platform/efi/Makefile b/arch/x86/platform/efi/Makefile @@ -58,28 +58,21 @@ index e2cd38f..0e22b5f4 100644 size = md->num_pages << EFI_PAGE_SHIFT; diff --git a/arch/x86/platform/efi/efi_capsule_update.c b/arch/x86/platform/efi/efi_capsule_update.c new file mode 100644 -index 0000000..3420e35 +index 0000000..c380392 --- /dev/null +++ b/arch/x86/platform/efi/efi_capsule_update.c -@@ -0,0 +1,331 @@ +@@ -0,0 +1,324 @@ +/* + * Copyright(c) 2013 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 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 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. -+ * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +#define DEBUG +#include <asm/qrk.h> @@ -393,6 +386,3 @@ index 0000000..3420e35 + +module_init(efi_capsule_update_init); +module_exit(efi_capsule_update_exit); --- -1.7.4.1 - diff --git a/recipes-kernel/linux/files/0010-Quark-SDIO-host-controller-quark.patch b/recipes-kernel/linux/files/0010-Quark-SDIO-host-controller-quark.patch index 990af2d..a5a7c21 100644 --- a/recipes-kernel/linux/files/0010-Quark-SDIO-host-controller-quark.patch +++ b/recipes-kernel/linux/files/0010-Quark-SDIO-host-controller-quark.patch @@ -4,9 +4,9 @@ Date: Thu, 20 Feb 2014 15:16:30 +0000 Subject: [PATCH 10/21] Quark SDIO host controller --- - drivers/mmc/host/sdhci-pci.c | 12 ++++++++++++ - include/linux/pci_ids.h | 2 ++ - 2 files changed, 14 insertions(+), 0 deletions(-) + drivers/mmc/host/sdhci-pci.c | 12 ++++++++++++ + include/linux/pci_ids.h | 2 ++ + 2 files changed, 14 insertions(+) diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index c7dd0cb..e5759b7 100644 @@ -58,6 +58,3 @@ index 0eb6579..b5bb350 100644 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN 0x1c41 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX 0x1c5f #define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_0 0x1d40 --- -1.7.4.1 - diff --git a/recipes-kernel/linux/files/0011-Quark-USB-host-quark.patch b/recipes-kernel/linux/files/0011-Quark-USB-host-quark.patch index 62a97a1..bff26cd 100644 --- a/recipes-kernel/linux/files/0011-Quark-USB-host-quark.patch +++ b/recipes-kernel/linux/files/0011-Quark-USB-host-quark.patch @@ -4,10 +4,10 @@ Date: Thu, 13 Feb 2014 13:03:44 +0000 Subject: [PATCH 11/21] Quark USB host --- - drivers/usb/host/ehci-pci.c | 4 +++ - drivers/usb/host/pci-quirks.c | 42 +++++++++++++++++++++++++++++++++++++++++ - drivers/usb/host/pci-quirks.h | 2 + - 3 files changed, 48 insertions(+), 0 deletions(-) + drivers/usb/host/ehci-pci.c | 4 ++++ + drivers/usb/host/pci-quirks.c | 42 ++++++++++++++++++++++++++++++++++++++++++ + drivers/usb/host/pci-quirks.h | 2 ++ + 3 files changed, 48 insertions(+) diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 170b939..5eac9db 100644 @@ -90,6 +90,3 @@ index 7f69a39..80ffdee 100644 void usb_enable_xhci_ports(struct pci_dev *xhci_pdev); void usb_disable_xhci_ports(struct pci_dev *xhci_pdev); #else --- -1.7.4.1 - diff --git a/recipes-kernel/linux/files/0012-USB-gadget-serial-quark.patch b/recipes-kernel/linux/files/0012-USB-gadget-serial-quark.patch index 2d7d88f..804281a 100644 --- a/recipes-kernel/linux/files/0012-USB-gadget-serial-quark.patch +++ b/recipes-kernel/linux/files/0012-USB-gadget-serial-quark.patch @@ -1,14 +1,14 @@ From xxxx Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue <bryan.odonoghue@intel.com> -Date: Thu, 13 Feb 2014 16:41:02 +0000 +Date: Thu, 8 May 2014 14:28:54 +0100 Subject: [PATCH 12/21] USB gadget serial --- - Documentation/usb/linux-cdc-acm.inf | 4 +- - drivers/usb/gadget/Kconfig | 5 +- - drivers/usb/gadget/pch_udc.c | 142 ++++++++++++++++++++++------------ - drivers/usb/gadget/serial.c | 24 +++++- - 4 files changed, 118 insertions(+), 57 deletions(-) + Documentation/usb/linux-cdc-acm.inf | 4 +- + drivers/usb/gadget/Kconfig | 5 +- + drivers/usb/gadget/pch_udc.c | 147 ++++++++++++++++++++++++------------ + drivers/usb/gadget/serial.c | 24 +++++- + 4 files changed, 123 insertions(+), 57 deletions(-) diff --git a/Documentation/usb/linux-cdc-acm.inf b/Documentation/usb/linux-cdc-acm.inf index f0ffc27..e56f074 100644 @@ -51,7 +51,7 @@ index 14625fd..1ab9996 100644 # LAST -- dummy/emulated controller # diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c -index 6490c00..df96b3b 100644 +index 6490c00..618261f 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -6,6 +6,7 @@ @@ -99,7 +99,7 @@ index 6490c00..df96b3b 100644 #define PCI_VENDOR_ID_ROHM 0x10DB #define PCI_DEVICE_ID_ML7213_IOH_UDC 0x801D #define PCI_DEVICE_ID_ML7831_IOH_UDC 0x8808 -@@ -2779,55 +2788,70 @@ static irqreturn_t pch_udc_isr(int irq, void *pdev) +@@ -2779,55 +2788,75 @@ static irqreturn_t pch_udc_isr(int irq, void *pdev) { struct pch_udc_dev *dev = (struct pch_udc_dev *) pdev; u32 dev_intr, ep_intr; @@ -115,7 +115,7 @@ index 6490c00..df96b3b 100644 - /* The controller is reset */ - pch_udc_writel(dev, UDC_SRST, UDC_SRST_ADDR); - return IRQ_HANDLED; -+ int i, events = 0; ++ int i, events = 0, count = 0; + + mask_pvm(dev->pdev); + do { @@ -136,6 +136,7 @@ index 6490c00..df96b3b 100644 + /* Clear device interrupts */ + pch_udc_write_device_interrupts(dev, dev_intr); + events = 1; ++ count = 1; } - if (dev_intr) - /* Clear device interrupts */ @@ -158,6 +159,7 @@ index 6490c00..df96b3b 100644 + /* Clear ep interrupts */ + pch_udc_write_ep_interrupts(dev, ep_intr); + events = 1; ++ count = 1; } - /* Process Control Out interrupts, if present */ - if (ep_intr & UDC_EPINT_OUT_EP0) @@ -169,7 +171,10 @@ index 6490c00..df96b3b 100644 - pch_udc_postsvc_epinters(dev, i); + if (!dev_intr && !ep_intr){ + unmask_pvm(dev->pdev); -+ return IRQ_NONE; ++ if (count) ++ return IRQ_HANDLED; ++ else ++ return IRQ_NONE; + } + spin_lock(&dev->lock); + if (dev_intr){ @@ -181,7 +186,7 @@ index 6490c00..df96b3b 100644 + if (ep_intr & UDC_EPINT_IN_EP0) { + pch_udc_svc_control_in(dev); + pch_udc_postsvc_epinters(dev, 0); -+ } + } + /* Process Control Out interrupts, if present */ + if (ep_intr & UDC_EPINT_OUT_EP0) + pch_udc_svc_control_out(dev); @@ -191,7 +196,7 @@ index 6490c00..df96b3b 100644 + pch_udc_svc_data_in(dev, i); + pch_udc_postsvc_epinters(dev, i); + } - } ++ } + /* Process data out end point interrupts */ + for (i = UDC_EPINT_OUT_SHIFT + 1; + i < (UDC_EPINT_OUT_SHIFT + PCH_UDC_USED_EP_NUM); @@ -215,7 +220,7 @@ index 6490c00..df96b3b 100644 return IRQ_HANDLED; } -@@ -3108,7 +3132,7 @@ static void pch_udc_remove(struct pci_dev *pdev) +@@ -3108,7 +3137,7 @@ static void pch_udc_remove(struct pci_dev *pdev) iounmap(dev->base_addr); if (dev->mem_region) release_mem_region(dev->phys_addr, @@ -224,7 +229,7 @@ index 6490c00..df96b3b 100644 if (dev->active) pci_disable_device(pdev); if (dev->registered) -@@ -3184,9 +3208,16 @@ static int pch_udc_probe(struct pci_dev *pdev, +@@ -3184,9 +3213,16 @@ static int pch_udc_probe(struct pci_dev *pdev, dev->active = 1; pci_set_drvdata(pdev, dev); @@ -243,7 +248,7 @@ index 6490c00..df96b3b 100644 if (!request_mem_region(resource, len, KBUILD_MODNAME)) { dev_err(&pdev->dev, "%s: pci device used already\n", __func__); -@@ -3213,6 +3244,12 @@ static int pch_udc_probe(struct pci_dev *pdev, +@@ -3213,6 +3249,12 @@ static int pch_udc_probe(struct pci_dev *pdev, retval = -ENODEV; goto finished; } @@ -256,7 +261,7 @@ index 6490c00..df96b3b 100644 if (request_irq(pdev->irq, pch_udc_isr, IRQF_SHARED, KBUILD_MODNAME, dev)) { dev_err(&pdev->dev, "%s: request_irq(%d) fail\n", __func__, -@@ -3223,7 +3260,7 @@ static int pch_udc_probe(struct pci_dev *pdev, +@@ -3223,7 +3265,7 @@ static int pch_udc_probe(struct pci_dev *pdev, dev->irq = pdev->irq; dev->irq_registered = 1; @@ -265,7 +270,7 @@ index 6490c00..df96b3b 100644 pci_try_set_mwi(pdev); /* device struct setup */ -@@ -3261,6 +3298,11 @@ finished: +@@ -3261,6 +3303,11 @@ finished: static DEFINE_PCI_DEVICE_TABLE(pch_udc_pcidev_id) = { { @@ -343,6 +348,3 @@ index 44752f5..e02a4c9 100644 device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC; device_desc.idProduct = cpu_to_le16(GS_PRODUCT_ID); --- -1.7.4.1 - diff --git a/recipes-kernel/linux/files/0013-Quark-stmmac-Ethernet-quark.patch b/recipes-kernel/linux/files/0013-Quark-stmmac-Ethernet-quark.patch index 99ce791..45ab5a1 100644 --- a/recipes-kernel/linux/files/0013-Quark-stmmac-Ethernet-quark.patch +++ b/recipes-kernel/linux/files/0013-Quark-stmmac-Ethernet-quark.patch @@ -1,24 +1,24 @@ From xxxx Mon Sep 17 00:00:00 2001 From: Krzysztof Sywula <krzysztof.m.sywula@intel.com> -Date: Thu, 20 Feb 2014 15:16:30 +0000 +Date: Wed, 9 Apr 2014 15:29:52 +0100 Subject: [PATCH 13/21] Quark stmmac Ethernet --- - drivers/net/ethernet/stmicro/stmmac/Kconfig | 25 +- - drivers/net/ethernet/stmicro/stmmac/Makefile | 1 + - drivers/net/ethernet/stmicro/stmmac/common.h | 14 +- - drivers/net/ethernet/stmicro/stmmac/descs.h | 45 ++- - drivers/net/ethernet/stmicro/stmmac/dwmac1000.h | 64 ++- - .../net/ethernet/stmicro/stmmac/dwmac1000_core.c | 139 ++++- - .../net/ethernet/stmicro/stmmac/dwmac1000_dma.c | 9 +- - .../net/ethernet/stmicro/stmmac/dwmac100_core.c | 6 +- - drivers/net/ethernet/stmicro/stmmac/mmc_core.c | 1 + - drivers/net/ethernet/stmicro/stmmac/stmmac.h | 76 ++ - .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 21 +- - drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 163 ++++- - drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 263 +++++++- - drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c | 723 ++++++++++++++++++++ - 14 files changed, 1476 insertions(+), 74 deletions(-) + drivers/net/ethernet/stmicro/stmmac/Kconfig | 25 +- + drivers/net/ethernet/stmicro/stmmac/Makefile | 1 + + drivers/net/ethernet/stmicro/stmmac/common.h | 14 +- + drivers/net/ethernet/stmicro/stmmac/descs.h | 45 +- + drivers/net/ethernet/stmicro/stmmac/dwmac1000.h | 64 +- + .../net/ethernet/stmicro/stmmac/dwmac1000_core.c | 139 +++- + .../net/ethernet/stmicro/stmmac/dwmac1000_dma.c | 9 +- + .../net/ethernet/stmicro/stmmac/dwmac100_core.c | 6 +- + drivers/net/ethernet/stmicro/stmmac/mmc_core.c | 1 + + drivers/net/ethernet/stmicro/stmmac/stmmac.h | 76 +++ + .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 21 +- + drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 163 ++++- + drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 275 +++++++- + drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c | 723 +++++++++++++++++++++ + 14 files changed, 1488 insertions(+), 74 deletions(-) create mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -1153,10 +1153,10 @@ index b75f4b2..aaccd3a 100644 free_netdev(ndev); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c -index 064eaac..f7afcad 100644 +index 064eaac..ac32842 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c -@@ -23,32 +23,194 @@ +@@ -23,31 +23,205 @@ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> *******************************************************************************/ @@ -1183,7 +1183,9 @@ index 064eaac..f7afcad 100644 +MODULE_PARM_DESC(enable_msi, "Enable PCI MSI mode"); + +static int bus_id = 1; ++#if 0 +static char stmmac_mac_data[MAX_INTERFACES][ETH_ALEN]; ++#endif + +struct stmmac_qrk_mac_data { + int phy_addr; @@ -1252,6 +1254,16 @@ index 064eaac..f7afcad 100644 + .bus_id = 2, + .name = "Galileo", + }, ++ { ++ .phy_addr = 1, ++ .bus_id = 1, ++ .name = "GalileoGen2", ++ }, ++ { ++ .phy_addr = -1, /* not connected */ ++ .bus_id = 2, ++ .name = "GalileoGen2", ++ }, +}; + + @@ -1270,26 +1282,10 @@ index 064eaac..f7afcad 100644 + + return -1; +} - --static void stmmac_default_data(void) ++ +static int stmmac_default_data(struct plat_stmmacenet_data *plat_dat, + int mdio_bus_id, const struct pci_device_id *id) - { -- memset(&plat_dat, 0, sizeof(struct plat_stmmacenet_data)); -- plat_dat.bus_id = 1; -- plat_dat.phy_addr = 0; -- plat_dat.interface = PHY_INTERFACE_MODE_GMII; -- plat_dat.clk_csr = 2; /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */ -- plat_dat.has_gmac = 1; -- plat_dat.force_sf_dma_mode = 1; -- -- mdio_data.phy_reset = NULL; -- mdio_data.phy_mask = 0; -- plat_dat.mdio_bus_data = &mdio_data; -- -- dma_cfg.pbl = 32; -- dma_cfg.burst_len = DMA_AXI_BLEN_256; -- plat_dat.dma_cfg = &dma_cfg; ++{ + int phy_addr = 0; + memset(plat_dat, 0, sizeof(struct plat_stmmacenet_data)); + @@ -1342,8 +1338,9 @@ index 064eaac..f7afcad 100644 + } + + return 0; - } ++} +-static void stmmac_default_data(void) +#if 0 +/** + * stmmac_pci_find_mac @@ -1355,7 +1352,22 @@ index 064eaac..f7afcad 100644 + * a random one for itself in any case + */ +void stmmac_pci_find_mac (struct stmmac_priv * priv, unsigned int mdio_bus_id) -+{ + { +- memset(&plat_dat, 0, sizeof(struct plat_stmmacenet_data)); +- plat_dat.bus_id = 1; +- plat_dat.phy_addr = 0; +- plat_dat.interface = PHY_INTERFACE_MODE_GMII; +- plat_dat.clk_csr = 2; /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */ +- plat_dat.has_gmac = 1; +- plat_dat.force_sf_dma_mode = 1; +- +- mdio_data.phy_reset = NULL; +- mdio_data.phy_mask = 0; +- plat_dat.mdio_bus_data = &mdio_data; +- +- dma_cfg.pbl = 32; +- dma_cfg.burst_len = DMA_AXI_BLEN_256; +- plat_dat.dma_cfg = &dma_cfg; + unsigned int id = mdio_bus_id - 1; + if (priv == NULL || id >= MAX_INTERFACES) + return; @@ -1364,13 +1376,12 @@ index 064eaac..f7afcad 100644 + (char*)&stmmac_mac_data[id]) == 0){ + memcpy(priv->dev->dev_addr, &stmmac_mac_data[id], ETH_ALEN); + } -+} + } +#endif -+ + /** * stmmac_pci_probe - * -@@ -67,8 +229,21 @@ static int stmmac_pci_probe(struct pci_dev *pdev, +@@ -67,8 +241,21 @@ static int stmmac_pci_probe(struct pci_dev *pdev, int ret = 0; void __iomem *addr = NULL; struct stmmac_priv *priv = NULL; @@ -1392,7 +1403,7 @@ index 064eaac..f7afcad 100644 /* Enable pci device */ ret = pci_enable_device(pdev); if (ret) { -@@ -96,30 +271,51 @@ static int stmmac_pci_probe(struct pci_dev *pdev, +@@ -96,30 +283,51 @@ static int stmmac_pci_probe(struct pci_dev *pdev, break; } pci_set_master(pdev); @@ -1449,7 +1460,7 @@ index 064eaac..f7afcad 100644 return ret; } -@@ -138,6 +334,21 @@ static void stmmac_pci_remove(struct pci_dev *pdev) +@@ -138,6 +346,21 @@ static void stmmac_pci_remove(struct pci_dev *pdev) stmmac_dvr_remove(ndev); pci_set_drvdata(pdev, NULL); @@ -1471,7 +1482,7 @@ index 064eaac..f7afcad 100644 pci_iounmap(pdev, priv->ioaddr); pci_release_regions(pdev); pci_disable_device(pdev); -@@ -167,12 +378,10 @@ static int stmmac_pci_resume(struct pci_dev *pdev) +@@ -167,12 +390,10 @@ static int stmmac_pci_resume(struct pci_dev *pdev) } #endif @@ -2214,6 +2225,3 @@ index 0000000..8552d0c + } +} + --- -1.7.4.1 - diff --git a/recipes-kernel/linux/files/0014-Quark-GPIO-2-2-quark.patch b/recipes-kernel/linux/files/0014-Quark-GPIO-2-2-quark.patch index 9017515..bc6490e 100644 --- a/recipes-kernel/linux/files/0014-Quark-GPIO-2-2-quark.patch +++ b/recipes-kernel/linux/files/0014-Quark-GPIO-2-2-quark.patch @@ -1,18 +1,21 @@ From xxxx Mon Sep 17 00:00:00 2001 From: Dan O'Donovan <danielx.o'donovan@intel.com> -Date: Thu, 13 Feb 2014 16:42:31 +0000 +Date: Wed, 26 Mar 2014 17:36:09 +0000 Subject: [PATCH 14/21] Quark GPIO 2/2 --- - drivers/gpio/gpio-sch.c | 749 ++++++++++++++++++++++++++++++++++++++++------- - 1 files changed, 638 insertions(+), 111 deletions(-) + drivers/gpio/gpio-sch.c | 783 +++++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 672 insertions(+), 111 deletions(-) diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c -index edae963..faabd97 100644 +index edae963..a2b5bdc 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c -@@ -28,6 +28,8 @@ +@@ -26,8 +26,11 @@ + #include <linux/acpi.h> + #include <linux/platform_device.h> #include <linux/pci_ids.h> ++#include <linux/uio_driver.h> #include <linux/gpio.h> +#include <linux/interrupt.h> @@ -20,7 +23,7 @@ index edae963..faabd97 100644 static DEFINE_SPINLOCK(gpio_lock); -@@ -35,83 +37,168 @@ static DEFINE_SPINLOCK(gpio_lock); +@@ -35,83 +38,170 @@ static DEFINE_SPINLOCK(gpio_lock); #define CGIO (0x04) #define CGLV (0x08) @@ -49,6 +52,8 @@ index edae963..faabd97 100644 + +static unsigned long gpio_ba; + ++static struct uio_info *info; ++ +static int irq_num; + +struct sch_gpio_core_int_regvals { @@ -223,7 +228,7 @@ index edae963..faabd97 100644 static struct gpio_chip sch_gpio_core = { .label = "sch_gpio_core", .owner = THIS_MODULE, -@@ -119,63 +206,198 @@ static struct gpio_chip sch_gpio_core = { +@@ -119,63 +209,198 @@ static struct gpio_chip sch_gpio_core = { .get = sch_gpio_core_get, .direction_output = sch_gpio_core_direction_out, .set = sch_gpio_core_set, @@ -236,29 +241,29 @@ index edae963..faabd97 100644 { - u8 curr_dirs; + u32 gpio_num = 0; - -- spin_lock(&gpio_lock); ++ + gpio_num = d->irq - chip_ptr->irq_base_core; + sch_gpio_reg_set_if_clear(CGGPE, gpio_num); +} -- curr_dirs = inb(gpio_ba + RGIO); +- spin_lock(&gpio_lock); +static void sch_gpio_core_irq_disable(struct irq_data *d) +{ + u32 gpio_num = 0; -- if (!(curr_dirs & (1 << gpio_num))) -- outb(curr_dirs | (1 << gpio_num) , gpio_ba + RGIO); +- curr_dirs = inb(gpio_ba + RGIO); + gpio_num = d->irq - chip_ptr->irq_base_core; + sch_gpio_reg_clear_if_set(CGGPE, gpio_num); +} -- spin_unlock(&gpio_lock); -- return 0; +- if (!(curr_dirs & (1 << gpio_num))) +- outb(curr_dirs | (1 << gpio_num) , gpio_ba + RGIO); +static void sch_gpio_core_irq_ack(struct irq_data *d) +{ + u32 gpio_num = 0; -+ + +- spin_unlock(&gpio_lock); +- return 0; + gpio_num = d->irq - chip_ptr->irq_base_core; + sch_gpio_reg_set(CGTS, gpio_num, 1); } @@ -305,8 +310,10 @@ index edae963..faabd97 100644 + spin_unlock_irqrestore(&gpio_lock, flags); + + return ret; -+} -+ + } + +-static void sch_gpio_resume_set(struct gpio_chip *gc, +- unsigned gpio_num, int val) +static struct irq_chip sch_irq_core = { + .irq_ack = sch_gpio_core_irq_ack, + .irq_set_type = sch_gpio_core_irq_type, @@ -315,7 +322,8 @@ index edae963..faabd97 100644 +}; + +static void sch_gpio_core_irqs_init(struct sch_gpio *chip, unsigned int num) -+{ + { +- u8 curr_vals; + int i; + + for (i = 0; i < num; i++) { @@ -325,16 +333,14 @@ index edae963..faabd97 100644 + handle_simple_irq, + "sch_gpio_irq_core"); + } - } ++} --static void sch_gpio_resume_set(struct gpio_chip *gc, -- unsigned gpio_num, int val) +- spin_lock(&gpio_lock); +static void sch_gpio_core_irqs_deinit(struct sch_gpio *chip, unsigned int num) - { -- u8 curr_vals; ++{ + int i; -- spin_lock(&gpio_lock); +- curr_vals = inb(gpio_ba + RGLV); + for (i = 0; i < num; i++) { + irq_set_chip_data(i + chip->irq_base_core, 0); + irq_set_chip_and_handler_name(i + chip->irq_base_core, @@ -342,7 +348,10 @@ index edae963..faabd97 100644 + } +} -- curr_vals = inb(gpio_ba + RGLV); +- if (val) +- outb(curr_vals | (1 << gpio_num), gpio_ba + RGLV); +- else +- outb((curr_vals & ~(1 << gpio_num)), gpio_ba + RGLV); +static void sch_gpio_core_irq_disable_all(struct sch_gpio *chip, + unsigned int num) +{ @@ -360,11 +369,7 @@ index edae963..faabd97 100644 + /* clear any pending interrupt */ + sch_gpio_reg_set(CGTS, gpio_num, 1); + } - -- if (val) -- outb(curr_vals | (1 << gpio_num), gpio_ba + RGLV); -- else -- outb((curr_vals & ~(1 << gpio_num)), gpio_ba + RGLV); ++ + spin_unlock_irqrestore(&gpio_lock, flags); - spin_unlock(&gpio_lock); @@ -387,26 +392,26 @@ index edae963..faabd97 100644 - sch_gpio_resume_set(gc, gpio_num, val); + spin_unlock_irqrestore(&gpio_lock, flags); +} - -- spin_lock(&gpio_lock); ++ +void sch_gpio_core_restore_state(struct sch_gpio_core_int_regvals *regs) +{ + unsigned long flags = 0; + spin_lock_irqsave(&gpio_lock, flags); -- curr_dirs = inb(gpio_ba + RGIO); -- if (curr_dirs & (1 << gpio_num)) -- outb(curr_dirs & ~(1 << gpio_num), gpio_ba + RGIO); +- spin_lock(&gpio_lock); + outb(regs->cgtpe, gpio_ba + CGTPE); + outb(regs->cgtne, gpio_ba + CGTNE); + outb(regs->cggpe, gpio_ba + CGGPE); + outb(regs->cgsmi, gpio_ba + CGSMI); + outb(regs->cgnmien, gpio_ba + CGNMIEN); -- spin_unlock(&gpio_lock); +- curr_dirs = inb(gpio_ba + RGIO); +- if (curr_dirs & (1 << gpio_num)) +- outb(curr_dirs & ~(1 << gpio_num), gpio_ba + RGIO); + spin_unlock_irqrestore(&gpio_lock, flags); +} -+ + +- spin_unlock(&gpio_lock); +static int sch_gpio_resume_direction_in(struct gpio_chip *gc, + unsigned gpio_num) +{ @@ -414,9 +419,9 @@ index edae963..faabd97 100644 + spin_lock_irqsave(&gpio_lock, flags); + sch_gpio_reg_set_if_clear(RGIO, gpio_num); + spin_unlock_irqrestore(&gpio_lock, flags); - return 0; - } - ++ return 0; ++} ++ +static int sch_gpio_resume_get(struct gpio_chip *gc, unsigned gpio_num) +{ + int res; @@ -441,9 +446,9 @@ index edae963..faabd97 100644 + spin_lock_irqsave(&gpio_lock, flags); + sch_gpio_reg_clear_if_set(RGIO, gpio_num); + spin_unlock_irqrestore(&gpio_lock, flags); -+ return 0; -+} -+ + return 0; + } + +static int sch_gpio_resume_to_irq(struct gpio_chip *gc, unsigned offset) +{ + return chip_ptr->irq_base_resume + offset; @@ -452,13 +457,13 @@ index edae963..faabd97 100644 static struct gpio_chip sch_gpio_resume = { .label = "sch_gpio_resume", .owner = THIS_MODULE, -@@ -183,13 +405,203 @@ static struct gpio_chip sch_gpio_resume = { +@@ -183,17 +408,212 @@ static struct gpio_chip sch_gpio_resume = { .get = sch_gpio_resume_get, .direction_output = sch_gpio_resume_direction_out, .set = sch_gpio_resume_set, + .to_irq = sch_gpio_resume_to_irq, -+}; -+ + }; + +static void sch_gpio_resume_irq_enable(struct irq_data *d) +{ + u32 gpio_num = 0; @@ -530,8 +535,8 @@ index edae963..faabd97 100644 + .irq_set_type = sch_gpio_resume_irq_type, + .irq_enable = sch_gpio_resume_irq_enable, + .irq_disable = sch_gpio_resume_irq_disable, - }; - ++}; ++ +static void sch_gpio_resume_irqs_init(struct sch_gpio *chip, unsigned int num) +{ + int i; @@ -656,7 +661,16 @@ index edae963..faabd97 100644 id = pdev->id; if (!id) return -ENODEV; -@@ -203,46 +615,56 @@ static int sch_gpio_probe(struct platform_device *pdev) + ++ /* Get UIO memory */ ++ info = kzalloc(sizeof(struct uio_info), GFP_KERNEL); ++ if (!info) ++ return -ENOMEM; ++ + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) + return -EBUSY; +@@ -203,46 +623,56 @@ static int sch_gpio_probe(struct platform_device *pdev) gpio_ba = res->start; @@ -752,7 +766,7 @@ index edae963..faabd97 100644 } sch_gpio_core.dev = &pdev->dev; -@@ -256,44 +678,147 @@ static int sch_gpio_probe(struct platform_device *pdev) +@@ -256,44 +686,173 @@ static int sch_gpio_probe(struct platform_device *pdev) if (err < 0) goto err_sch_gpio_resume; @@ -796,8 +810,26 @@ index edae963..faabd97 100644 + sch_gpio_core_irqs_init(chip, sch_gpio_core.ngpio); + sch_gpio_resume_irqs_init(chip, sch_gpio_resume.ngpio); + ++ /* UIO */ ++ info->port[0].name = "gpio_regs"; ++ info->port[0].start = res->start; ++ info->port[0].size = resource_size(res); ++ info->port[0].porttype = UIO_PORT_X86; ++ info->name = "sch_gpio"; ++ info->version = "0.0.1"; ++ ++ if (uio_register_device(&pdev->dev, info)) ++ goto err_sch_uio_register; ++ ++ pr_info("%s UIO port addr 0x%04x size %lu porttype %d\n", ++ __func__, (unsigned int)info->port[0].start, ++ info->port[0].size, info->port[0].porttype); ++ return 0; ++err_sch_uio_register: ++ free_irq(irq_num, chip); ++ +err_sch_request_irq: + platform_device_unregister(&qrk_gpio_restrict_pdev); + @@ -830,6 +862,9 @@ index edae963..faabd97 100644 + kfree(chip); + chip_ptr = 0; + ++ if (info != NULL) ++ kfree(info); ++ return err; } @@ -844,6 +879,11 @@ index edae963..faabd97 100644 - int err; - err = gpiochip_remove(&sch_gpio_core); ++ if (info != NULL) { ++ uio_unregister_device(info); ++ kfree(info); ++ } ++ + sch_gpio_resume_irqs_deinit(chip, sch_gpio_resume.ngpio); + sch_gpio_core_irqs_deinit(chip, sch_gpio_core.ngpio); + @@ -908,7 +948,7 @@ index edae963..faabd97 100644 return 0; } -@@ -304,6 +829,8 @@ static struct platform_driver sch_gpio_driver = { +@@ -304,6 +863,8 @@ static struct platform_driver sch_gpio_driver = { }, .probe = sch_gpio_probe, .remove = sch_gpio_remove, @@ -917,6 +957,3 @@ index edae963..faabd97 100644 }; module_platform_driver(sch_gpio_driver); --- -1.7.4.1 - diff --git a/recipes-kernel/linux/files/0015-Quark-GPIO-1-2-quark.patch b/recipes-kernel/linux/files/0015-Quark-GPIO-1-2-quark.patch index ec541dc..4fabc14 100644 --- a/recipes-kernel/linux/files/0015-Quark-GPIO-1-2-quark.patch +++ b/recipes-kernel/linux/files/0015-Quark-GPIO-1-2-quark.patch @@ -1,17 +1,18 @@ From xxxx Mon Sep 17 00:00:00 2001 From: Josef Ahmad <josef.ahmad@linux.intel.com> -Date: Tue, 11 Feb 2014 16:28:26 +0000 +Date: Wed, 9 Apr 2014 16:57:30 +0100 Subject: [PATCH 15/21] Quark GPIO 1/2 --- - drivers/gpio/Kconfig | 7 ++- - drivers/gpio/gpiolib.c | 130 ++++++++++++++++++++++++++++++++++++++++++++ - include/asm-generic/gpio.h | 4 ++ - include/linux/gpio.h | 10 ++++ - 4 files changed, 149 insertions(+), 2 deletions(-) + drivers/gpio/Kconfig | 9 +- + drivers/gpio/gpio-pca953x.c | 235 ++++++++++++++++++++++++++++++++++---------- + drivers/gpio/gpiolib.c | 130 ++++++++++++++++++++++++ + include/asm-generic/gpio.h | 4 + + include/linux/gpio.h | 10 ++ + 5 files changed, 332 insertions(+), 56 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig -index 682de75..afab416 100644 +index 682de75..447e51a 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -243,13 +243,14 @@ config GPIO_VR41XX @@ -40,6 +41,430 @@ index 682de75..afab416 100644 config GPIO_ICH tristate "Intel ICH GPIO" +@@ -363,7 +366,7 @@ config GPIO_PCA953X + + config GPIO_PCA953X_IRQ + bool "Interrupt controller support for PCA953x" +- depends on GPIO_PCA953X=y ++ depends on GPIO_PCA953X + help + Say yes here to enable the pca953x to be used as an interrupt + controller. It requires the driver to be built in the kernel. +diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c +index cc102d2..6ac3b87 100644 +--- a/drivers/gpio/gpio-pca953x.c ++++ b/drivers/gpio/gpio-pca953x.c +@@ -29,6 +29,12 @@ + #define PCA953X_INVERT 2 + #define PCA953X_DIRECTION 3 + ++#define PCAL953X_IN_LATCH 34 ++#define PCAL953X_PUPD_EN 35 ++#define PCAL953X_PUPD_SEL 36 ++#define PCAL953X_INT_MASK 37 ++#define PCAL953X_INT_STAT 38 ++ + #define REG_ADDR_AI 0x80 + + #define PCA957X_IN 0 +@@ -44,29 +50,32 @@ + #define PCA_INT 0x0100 + #define PCA953X_TYPE 0x1000 + #define PCA957X_TYPE 0x2000 ++#define PCAL953X_TYPE 0x4000 ++ + + static const struct i2c_device_id pca953x_id[] = { +- { "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, }, ++ { "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, }, ++ { "pcal9555a", 16 | PCAL953X_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, }, + { } + }; + MODULE_DEVICE_TABLE(i2c, pca953x_id); +@@ -75,6 +84,8 @@ struct pca953x_chip { + unsigned gpio_start; + u32 reg_output; + u32 reg_direction; ++ u32 reg_pupd_en; ++ u32 reg_pupd_sel; + struct mutex i2c_lock; + + #ifdef CONFIG_GPIO_PCA953X_IRQ +@@ -105,9 +116,9 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val) + (reg << 2) | REG_ADDR_AI, + 3, + (u8 *) &val); +- } +- else { ++ } else { + switch (chip->chip_type) { ++ case PCAL953X_TYPE: + case PCA953X_TYPE: + ret = i2c_smbus_write_word_data(chip->client, + reg << 1, val); +@@ -139,8 +150,7 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val) + if (chip->gpio_chip.ngpio <= 8) { + ret = i2c_smbus_read_byte_data(chip->client, reg); + *val = ret; +- } +- else if (chip->gpio_chip.ngpio == 24) { ++ } else if (chip->gpio_chip.ngpio == 24) { + *val = 0; + ret = i2c_smbus_read_i2c_block_data(chip->client, + (reg << 2) | REG_ADDR_AI, +@@ -172,6 +182,7 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) + reg_val = chip->reg_direction | (1u << off); + + switch (chip->chip_type) { ++ case PCAL953X_TYPE: + case PCA953X_TYPE: + offset = PCA953X_DIRECTION; + break; +@@ -207,6 +218,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, + reg_val = chip->reg_output & ~(1u << off); + + switch (chip->chip_type) { ++ case PCAL953X_TYPE: + case PCA953X_TYPE: + offset = PCA953X_OUTPUT; + break; +@@ -223,6 +235,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, + /* then direction */ + reg_val = chip->reg_direction & ~(1u << off); + switch (chip->chip_type) { ++ case PCAL953X_TYPE: + case PCA953X_TYPE: + offset = PCA953X_DIRECTION; + break; +@@ -251,6 +264,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; +@@ -286,6 +300,7 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) + reg_val = chip->reg_output & ~(1u << off); + + switch (chip->chip_type) { ++ case PCAL953X_TYPE: + case PCA953X_TYPE: + offset = PCA953X_OUTPUT; + break; +@@ -302,6 +317,60 @@ exit: + mutex_unlock(&chip->i2c_lock); + } + ++static int pca953x_gpio_set_drive(struct gpio_chip *gc, ++ unsigned off, unsigned mode) ++{ ++ struct pca953x_chip *chip; ++ u32 pupd_en_reg_val, pupd_sel_reg_val; ++ int ret = 0; ++ ++ chip = container_of(gc, struct pca953x_chip, gpio_chip); ++ ++ if (chip->chip_type != PCAL953X_TYPE) ++ return -EINVAL; ++ ++ mutex_lock(&chip->i2c_lock); ++ ++ switch (mode) { ++ case GPIOF_DRIVE_PULLUP: ++ pupd_en_reg_val = chip->reg_pupd_en | (1u << off); ++ pupd_sel_reg_val = chip->reg_pupd_sel | (1u << off); ++ break; ++ case GPIOF_DRIVE_PULLDOWN: ++ pupd_en_reg_val = chip->reg_pupd_en | (1u << off); ++ pupd_sel_reg_val = chip->reg_pupd_sel & ~(1u << off); ++ break; ++ case GPIOF_DRIVE_STRONG: ++ case GPIOF_DRIVE_HIZ: ++ pupd_en_reg_val = chip->reg_pupd_en & ~(1u << off); ++ pupd_sel_reg_val = chip->reg_pupd_sel; ++ break; ++ default: ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (pupd_en_reg_val != chip->reg_pupd_en) { ++ ret = pca953x_write_reg(chip, PCAL953X_PUPD_EN, ++ pupd_en_reg_val); ++ if (ret) ++ goto exit; ++ chip->reg_pupd_en = pupd_en_reg_val; ++ } ++ ++ if (pupd_sel_reg_val != chip->reg_pupd_sel) { ++ ret = pca953x_write_reg(chip, PCAL953X_PUPD_SEL, ++ pupd_sel_reg_val); ++ if (ret) ++ goto exit; ++ chip->reg_pupd_sel = pupd_sel_reg_val; ++ } ++ ++exit: ++ mutex_unlock(&chip->i2c_lock); ++ return ret; ++} ++ + static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) + { + struct gpio_chip *gc; +@@ -320,6 +389,9 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) + gc->dev = &chip->client->dev; + gc->owner = THIS_MODULE; + gc->names = chip->names; ++ ++ if (chip->chip_type == PCAL953X_TYPE) ++ gc->set_drive = pca953x_gpio_set_drive; + } + + #ifdef CONFIG_GPIO_PCA953X_IRQ +@@ -368,6 +440,15 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) + new_irqs &= ~(1 << level); + } + ++ if (chip->chip_type == PCAL953X_TYPE) { ++ /* Enable latch on interrupt-enabled inputs */ ++ pca953x_write_reg(chip, PCAL953X_IN_LATCH, ++ chip->irq_mask); ++ /* Unmask enabled interrupts */ ++ pca953x_write_reg(chip, PCAL953X_INT_MASK, ++ ~chip->irq_mask); ++ } ++ + mutex_unlock(&chip->irq_lock); + } + +@@ -412,6 +493,24 @@ static u32 pca953x_irq_pending(struct pca953x_chip *chip) + u32 trigger; + int ret, offset = 0; + ++ if (chip->chip_type == PCAL953X_TYPE) { ++ /* Read the current interrupt status from the device */ ++ ret = pca953x_read_reg(chip, PCAL953X_INT_STAT, &pending); ++ if (ret) ++ return 0; ++ ++ /* Check latched inputs and clear interrupt status */ ++ ret = pca953x_read_reg(chip, PCA953X_INPUT, &cur_stat); ++ if (ret) ++ return 0; ++ ++ /* Apply filter for rising/falling edge selection */ ++ pending &= (~cur_stat & chip->irq_trig_fall) | ++ (cur_stat & chip->irq_trig_raise); ++ ++ return pending; ++ } ++ + switch (chip->chip_type) { + case PCA953X_TYPE: + offset = PCA953X_INPUT; +@@ -468,37 +567,43 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, + int irq_base) + { + struct i2c_client *client = chip->client; +- int ret, offset = 0; ++ int ret = 0, offset = 0; ++ unsigned long flags; + u32 temporary; + + if (irq_base != -1 + && (id->driver_data & PCA_INT)) { + int lvl; + +- 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_reg(chip, offset, &temporary); ++ chip->irq_stat = temporary; ++ if (ret) ++ goto out_failed; ++ ++ /* ++ * There is no way to know which GPIO line generated the ++ * interrupt. We have to rely on the previous read for ++ * this purpose. ++ */ ++ chip->irq_stat &= chip->reg_direction; + } +- ret = pca953x_read_reg(chip, offset, &temporary); +- chip->irq_stat = temporary; +- if (ret) +- goto out_failed; +- +- /* +- * There is no way to know which GPIO line generated the +- * interrupt. We have to rely on the previous read for +- * this purpose. +- */ +- chip->irq_stat &= chip->reg_direction; + mutex_init(&chip->irq_lock); + +- chip->irq_base = irq_alloc_descs(-1, irq_base, chip->gpio_chip.ngpio, -1); +- if (chip->irq_base < 0) ++ chip->irq_base = irq_alloc_descs(-1, irq_base, ++ chip->gpio_chip.ngpio, -1); ++ if (chip->irq_base < 0) { ++ ret = chip->irq_base; + goto out_failed; ++ } + + chip->domain = irq_domain_add_legacy(client->dev.of_node, + chip->gpio_chip.ngpio, +@@ -525,10 +630,15 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, + #endif + } + ++ if (chip->chip_type == PCAL953X_TYPE) ++ flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; ++ else ++ flags = IRQF_TRIGGER_LOW | IRQF_ONESHOT; ++ + ret = request_threaded_irq(client->irq, + NULL, + pca953x_irq_handler, +- IRQF_TRIGGER_LOW | IRQF_ONESHOT, ++ flags, + dev_name(&client->dev), chip); + if (ret) { + dev_err(&client->dev, "failed to request irq %d\n", +@@ -537,6 +647,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, + } + + chip->gpio_chip.to_irq = pca953x_gpio_to_irq; ++ } else { ++ chip->irq_base = -1; + } + + return 0; +@@ -594,7 +706,8 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert) + + *gpio_base = -1; + val = of_get_property(node, "linux,gpio-base", &size); +- WARN(val, "%s: device-tree property 'linux,gpio-base' is deprecated!", __func__); ++ WARN(val, "%s: device-tree property 'linux,gpio-base' is deprecated!", ++ __func__); + if (val) { + if (size != sizeof(*val)) + dev_warn(&client->dev, "%s: wrong linux,gpio-base\n", +@@ -604,7 +717,8 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert) + } + + val = of_get_property(node, "polarity", NULL); +- WARN(val, "%s: device-tree property 'polarity' is deprecated!", __func__); ++ WARN(val, "%s: device-tree property 'polarity' is deprecated!", ++ __func__); + if (val) + *invert = *val; + } +@@ -620,6 +734,18 @@ static int device_pca953x_init(struct pca953x_chip *chip, u32 invert) + { + int ret; + ++ if (chip->chip_type == PCAL953X_TYPE) { ++ ret = pca953x_read_reg(chip, PCAL953X_PUPD_EN, ++ &chip->reg_pupd_en); ++ if (ret) ++ goto out; ++ ++ ret = pca953x_read_reg(chip, PCAL953X_PUPD_SEL, ++ &chip->reg_pupd_sel); ++ if (ret) ++ goto out; ++ } ++ + ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output); + if (ret) + goto out; +@@ -688,15 +814,18 @@ static int pca953x_probe(struct i2c_client *client, + } else { + pca953x_get_alt_pdata(client, &chip->gpio_start, &invert); + #ifdef CONFIG_OF_GPIO +- /* If I2C node has no interrupts property, disable GPIO interrupts */ +- if (of_find_property(client->dev.of_node, "interrupts", NULL) == NULL) ++ /* If I2C node has no interrupts property, disable ++ * GPIO interrupts */ ++ if (of_find_property(client->dev.of_node, ++ "interrupts", NULL) == NULL) + irq_base = -1; + #endif + } + + 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); + +@@ -705,7 +834,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); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 5359ca7..5e897ff 100644 --- a/drivers/gpio/gpiolib.c @@ -267,6 +692,3 @@ index bfe6656..cadd9d2 100644 static inline int gpio_get_value(unsigned gpio) { /* GPIO can never have been requested or set as {in,out}put */ --- -1.7.4.1 - diff --git a/recipes-kernel/linux/files/0016-Quark-GIP-Cypress-I-O-expander-quark.patch b/recipes-kernel/linux/files/0016-Quark-GIP-Cypress-I-O-expander-quark.patch index 8488759..811e609 100644 --- a/recipes-kernel/linux/files/0016-Quark-GIP-Cypress-I-O-expander-quark.patch +++ b/recipes-kernel/linux/files/0016-Quark-GIP-Cypress-I-O-expander-quark.patch @@ -1,22 +1,27 @@ From xxxx Mon Sep 17 00:00:00 2001 From: Josef Ahmad <josef.ahmad@linux.intel.com> -Date: Tue, 25 Feb 2014 12:09:04 +0000 +Date: Mon, 31 Mar 2014 18:03:09 +0100 Subject: [PATCH 16/21] Quark GIP + Cypress I/O expander --- - drivers/mfd/Kconfig | 38 + - drivers/mfd/Makefile | 8 + - drivers/mfd/cy8c9540a.c | 970 ++++++++++++++++++++++++++ - drivers/mfd/intel_qrk_gip.h | 104 +++ - drivers/mfd/intel_qrk_gip_core.c | 335 +++++++++ - drivers/mfd/intel_qrk_gip_gpio.c | 659 ++++++++++++++++++ - drivers/mfd/intel_qrk_gip_i2c.c | 248 +++++++ - drivers/mfd/intel_qrk_gip_pdata.c | 25 + - drivers/mfd/intel_qrk_gip_test.c | 1131 +++++++++++++++++++++++++++++++ + drivers/mfd/Kconfig | 48 ++ + drivers/mfd/Makefile | 10 + + drivers/mfd/cy8c9540a.c | 963 ++++++++++++++++++++++++++ + drivers/mfd/intel_qrk_gip.h | 97 +++ + drivers/mfd/intel_qrk_gip_core.c | 328 +++++++++ + drivers/mfd/intel_qrk_gip_gpio.c | 652 ++++++++++++++++++ + drivers/mfd/intel_qrk_gip_i2c.c | 241 +++++++ + drivers/mfd/intel_qrk_gip_pdata.c | 18 + + drivers/mfd/intel_qrk_gip_test.c | 1124 +++++++++++++++++++++++++++++++ drivers/mfd/lpc_sch.c | 76 ++- - include/linux/mfd/cy8c9540a.h | 38 + - include/linux/mfd/intel_qrk_gip_pdata.h | 32 + - 12 files changed, 3651 insertions(+), 13 deletions(-) + drivers/mfd/pca9685-core.c | 283 ++++++++ + drivers/mfd/pca9685-gpio.c | 108 +++ + drivers/mfd/pca9685-pwm.c | 262 +++++++ + drivers/mfd/pca9685.h | 110 +++ + include/linux/mfd/cy8c9540a.h | 31 + + include/linux/mfd/intel_qrk_gip_pdata.h | 25 + + include/linux/platform_data/pca9685.h | 51 ++ + 17 files changed, 4414 insertions(+), 13 deletions(-) create mode 100644 drivers/mfd/cy8c9540a.c create mode 100644 drivers/mfd/intel_qrk_gip.h create mode 100644 drivers/mfd/intel_qrk_gip_core.c @@ -24,14 +29,19 @@ Subject: [PATCH 16/21] Quark GIP + Cypress I/O expander create mode 100644 drivers/mfd/intel_qrk_gip_i2c.c create mode 100644 drivers/mfd/intel_qrk_gip_pdata.c create mode 100644 drivers/mfd/intel_qrk_gip_test.c + create mode 100644 drivers/mfd/pca9685-core.c + create mode 100644 drivers/mfd/pca9685-gpio.c + create mode 100644 drivers/mfd/pca9685-pwm.c + create mode 100644 drivers/mfd/pca9685.h create mode 100644 include/linux/mfd/cy8c9540a.h create mode 100644 include/linux/mfd/intel_qrk_gip_pdata.h + create mode 100644 include/linux/platform_data/pca9685.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig -index ff553ba..b8029bd 100644 +index ff553ba..74358c2 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig -@@ -907,6 +907,44 @@ config MFD_TIMBERDALE +@@ -907,6 +907,54 @@ config MFD_TIMBERDALE The timberdale FPGA can be found on the Intel Atom development board for in-vehicle infontainment, called Russellville. @@ -44,6 +54,16 @@ index ff553ba..b8029bd 100644 + Select this option to enable support for the CY8C9540 I/O expander. + This device provides 40 interrupt-capable GPIOs, 8 PWMs and an EEPROM. + ++config MFD_PCA9685 ++ tristate "NPX Semiconductors PCA9685 (PWM/GPIO) driver" ++ depends on GPIOLIB && I2C && PWM ++ select REGMAP_I2C ++ help ++ NPX PCA9685 I2C-bus PWM controller with GPIO output interface support. ++ The I2C-bus LED controller provides 16-channel, 12-bit PWM Fm+. ++ Additionally, the driver allows the channels to be configured as GPIO ++ interface (output only). ++ +config INTEL_QRK_GIP + tristate "Intel Quark GIP" + depends on PCI && X86 && INTEL_QUARK_X1000_SOC @@ -77,14 +97,16 @@ index ff553ba..b8029bd 100644 tristate "Intel SCH LPC" depends on PCI diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile -index 8b977f8..b17d50c 100644 +index 8b977f8..38706ff 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile -@@ -123,6 +123,14 @@ obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o +@@ -123,6 +123,16 @@ obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o obj-$(CONFIG_PMIC_ADP5520) += adp5520.o +obj-$(CONFIG_CY8C9540A) += cy8c9540a.o ++pca9685-objs := pca9685-core.o pca9685-gpio.o pca9685-pwm.o ++obj-$(CONFIG_MFD_PCA9685) += pca9685.o +obj-$(CONFIG_INTEL_QRK_GIP) += intel_qrk_gip.o +intel_qrk_gip-objs := intel_qrk_gip_core.o \ + intel_qrk_gip_gpio.o \ @@ -97,28 +119,21 @@ index 8b977f8..b17d50c 100644 obj-$(CONFIG_MFD_RDC321X) += rdc321x-southbridge.o diff --git a/drivers/mfd/cy8c9540a.c b/drivers/mfd/cy8c9540a.c new file mode 100644 -index 0000000..444e5ab +index 0000000..9e3966a --- /dev/null +++ b/drivers/mfd/cy8c9540a.c -@@ -0,0 +1,970 @@ +@@ -0,0 +1,963 @@ +/* + * Copyright(c) 2013 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. ++ * 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. + * -+ * 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. -+ * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ + +/* @@ -1073,28 +1088,21 @@ index 0000000..444e5ab + diff --git a/drivers/mfd/intel_qrk_gip.h b/drivers/mfd/intel_qrk_gip.h new file mode 100644 -index 0000000..d1e8316 +index 0000000..3dfc487 --- /dev/null +++ b/drivers/mfd/intel_qrk_gip.h -@@ -0,0 +1,104 @@ +@@ -0,0 +1,97 @@ +/* + * Copyright(c) 2013 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * 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. + * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +/* + * Intel Quark GIP (GPIO/I2C) driver @@ -1183,28 +1191,21 @@ index 0000000..d1e8316 +#endif /* __INTEL_QRKGIP_H__ */ diff --git a/drivers/mfd/intel_qrk_gip_core.c b/drivers/mfd/intel_qrk_gip_core.c new file mode 100644 -index 0000000..8b8727b +index 0000000..44209f0 --- /dev/null +++ b/drivers/mfd/intel_qrk_gip_core.c -@@ -0,0 +1,335 @@ +@@ -0,0 +1,328 @@ +/* + * Copyright(c) 2013 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 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 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. -+ * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +/* + * Intel Quark GIP (GPIO/I2C) PCI driver @@ -1524,28 +1525,21 @@ index 0000000..8b8727b +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/mfd/intel_qrk_gip_gpio.c b/drivers/mfd/intel_qrk_gip_gpio.c new file mode 100644 -index 0000000..ef19e2f +index 0000000..f823957 --- /dev/null +++ b/drivers/mfd/intel_qrk_gip_gpio.c -@@ -0,0 +1,659 @@ +@@ -0,0 +1,652 @@ +/* + * Copyright(c) 2013 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. ++ * 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. + * -+ * 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. -+ * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +/* + * Intel Quark GIP (GPIO/I2C) - GPIO-specific PCI and core driver @@ -2189,28 +2183,21 @@ index 0000000..ef19e2f +} diff --git a/drivers/mfd/intel_qrk_gip_i2c.c b/drivers/mfd/intel_qrk_gip_i2c.c new file mode 100644 -index 0000000..9ecbeb5 +index 0000000..08e8f9d --- /dev/null +++ b/drivers/mfd/intel_qrk_gip_i2c.c -@@ -0,0 +1,248 @@ +@@ -0,0 +1,241 @@ +/* + * Copyright(c) 2013 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. ++ * 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. + * -+ * 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. -+ * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +/* + * Intel Quark GIP (GPIO/I2C) - I2C-specific PCI driver @@ -2443,28 +2430,21 @@ index 0000000..9ecbeb5 +} diff --git a/drivers/mfd/intel_qrk_gip_pdata.c b/drivers/mfd/intel_qrk_gip_pdata.c new file mode 100644 -index 0000000..a764215 +index 0000000..cc230be --- /dev/null +++ b/drivers/mfd/intel_qrk_gip_pdata.c -@@ -0,0 +1,25 @@ +@@ -0,0 +1,18 @@ +/* + * Copyright(c) 2013 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. ++ * 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. + * -+ * 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. -+ * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ + +#include <linux/module.h> @@ -2474,28 +2454,21 @@ index 0000000..a764215 +EXPORT_SYMBOL_GPL(intel_qrk_gip_get_pdata); diff --git a/drivers/mfd/intel_qrk_gip_test.c b/drivers/mfd/intel_qrk_gip_test.c new file mode 100644 -index 0000000..2b07e9e +index 0000000..e444c81 --- /dev/null +++ b/drivers/mfd/intel_qrk_gip_test.c -@@ -0,0 +1,1131 @@ +@@ -0,0 +1,1124 @@ +/* + * Copyright(c) 2013 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. ++ * 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. + * -+ * 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. -+ * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ +/* + * Intel Quark GIP (GPIO/I2C) Test module @@ -3735,30 +3708,810 @@ index 5624fcb..4afc687 100644 if (id->device == PCI_DEVICE_ID_INTEL_ITC_LPC || id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) { pci_read_config_dword(dev, WDTBASE, &base_addr_cfg); -diff --git a/include/linux/mfd/cy8c9540a.h b/include/linux/mfd/cy8c9540a.h +diff --git a/drivers/mfd/pca9685-core.c b/drivers/mfd/pca9685-core.c new file mode 100644 -index 0000000..a32c6f0 +index 0000000..11cb8d9 --- /dev/null -+++ b/include/linux/mfd/cy8c9540a.h -@@ -0,0 +1,38 @@ ++++ b/drivers/mfd/pca9685-core.c +@@ -0,0 +1,283 @@ +/* ++ * Driver for NPX PCA9685 I2C-bus PWM controller with GPIO output interface ++ * support. ++ * + * Copyright(c) 2013 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 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. ++ * ++ * The I2C-bus LED controller provides 16-channel, 12-bit PWM Fm+. ++ * Additionally, the driver allows the channels to be configured as GPIO ++ * interface (output only). ++ */ ++ ++#include <linux/i2c.h> ++#include <linux/module.h> ++#include <linux/pwm.h> ++#include <linux/gpio.h> ++#include <linux/regmap.h> ++#include <linux/slab.h> ++ ++#include "pca9685.h" ++ ++static unsigned int en_invrt; ++module_param(en_invrt, uint, 0); ++MODULE_PARM_DESC(en_invrt, "Enable output logic state inverted mode"); ++ ++static unsigned int en_open_dr; ++module_param(en_open_dr, uint, 0); ++MODULE_PARM_DESC(en_open_dr, ++ "The outputs are configured with an open-drain structure"); ++ ++static int gpio_base = -1; /* requests dynamic ID allocation */ ++module_param(gpio_base, int, 0); ++MODULE_PARM_DESC(gpio_base, "GPIO base number"); ++ ++static unsigned int pwm_period = PWM_PERIOD_DEF; /* PWM clock period */ ++module_param(pwm_period, uint, 0); ++MODULE_PARM_DESC(pwm_period, "PWM clock period (nanoseconds)"); ++ ++static bool pca9685_register_volatile(struct device *dev, unsigned int reg) ++{ ++ if (unlikely(reg == PCA9685_MODE1)) ++ return true; ++ else ++ return false; ++} ++ ++static struct regmap_config pca9685_regmap_i2c_config = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ .max_register = PCA9685_NUMREGS, ++ .volatile_reg = pca9685_register_volatile, ++ .cache_type = REGCACHE_RBTREE, ++}; ++ ++ssize_t pca9685_pwm_period_sysfs_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct pca9685 *pca = dev_get_drvdata(dev); ++ ++ return scnprintf(buf, PAGE_SIZE, "%u\n", pca->pwm_period); ++} ++ ++ssize_t pca9685_pwm_period_sysfs_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct pca9685 *pca = dev_get_drvdata(dev); ++ unsigned period_ns; ++ int ret; ++ ++ sscanf(buf, "%u", &period_ns); ++ ++ ret = pca9685_update_prescale(pca, period_ns, true); ++ if (ret) ++ return ret; ++ ++ return count; ++} ++ ++/* Sysfs attribute to allow PWM clock period adjustment at run-time ++ * NOTE: All active channels will switch off momentarily if the ++ * PWM clock period is changed ++ */ ++static DEVICE_ATTR(pwm_period, S_IWUSR | S_IRUGO, ++ pca9685_pwm_period_sysfs_show, ++ pca9685_pwm_period_sysfs_store); ++ ++static int pca9685_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct pca9685_pdata *pdata; ++ struct pca9685 *pca; ++ int ret; ++ int mode2; ++ ++ pca = devm_kzalloc(&client->dev, sizeof(*pca), GFP_KERNEL); ++ if (unlikely(!pca)) ++ return -ENOMEM; ++ ++ pdata = client->dev.platform_data; ++ if (likely(pdata)) { ++ memcpy(pca->chan_mapping, pdata->chan_mapping, ++ ARRAY_SIZE(pca->chan_mapping)); ++ pca->gpio_base = pdata->gpio_base; ++ en_invrt = pdata->en_invrt; ++ en_open_dr = pdata->en_open_dr; ++ } else { ++ dev_warn(&client->dev, ++ "Platform data not provided." ++ "Using default or mod params configuration.\n"); ++ pca->gpio_base = gpio_base; ++ memset(pca->chan_mapping, PWM_CH_UNDEFINED, ++ ARRAY_SIZE(pca->chan_mapping)); ++ } ++ ++ if (unlikely(!i2c_check_functionality(client->adapter, ++ I2C_FUNC_I2C | ++ I2C_FUNC_SMBUS_BYTE_DATA))) { ++ dev_err(&client->dev, ++ "i2c adapter doesn't support required functionality\n"); ++ return -EIO; ++ } ++ ++ pca->regmap = devm_regmap_init_i2c(client, &pca9685_regmap_i2c_config); ++ if (IS_ERR(pca->regmap)) { ++ ret = PTR_ERR(pca->regmap); ++ dev_err(&client->dev, "Failed to initialize register map: %d\n", ++ ret); ++ return ret; ++ } ++ ++ i2c_set_clientdata(client, pca); ++ ++ /* registration of GPIO chip */ ++ pca->gpio_chip.label = "pca9685-gpio"; ++ pca->gpio_chip.owner = THIS_MODULE; ++ pca->gpio_chip.set = pca9685_gpio_set; ++ pca->gpio_chip.get = pca9685_gpio_get; ++ pca->gpio_chip.can_sleep = 1; ++ pca->gpio_chip.ngpio = PCA9685_MAXCHAN; ++ pca->gpio_chip.base = pca->gpio_base; ++ pca->gpio_chip.request = pca9685_gpio_request; ++ pca->gpio_chip.free = pca9685_gpio_free; ++ ++ mutex_init(&pca->lock); ++ ++ ret = gpiochip_add(&pca->gpio_chip); ++ if (unlikely(ret < 0)) { ++ dev_err(&client->dev, "Could not register gpiochip, %d\n", ret); ++ goto err; ++ } ++ ++ /* configure initial PWM settings */ ++ ret = pca9685_init_pwm_regs(pca, pwm_period); ++ if (ret) { ++ pr_err("Failed to initialize PWM registers\n"); ++ goto err_gpiochip; ++ } ++ ++ /* registration of PWM chip */ ++ ++ regmap_read(pca->regmap, PCA9685_MODE2, &mode2); ++ ++ /* update mode2 register */ ++ if (en_invrt) ++ mode2 |= MODE2_INVRT; ++ else ++ mode2 &= ~MODE2_INVRT; ++ ++ if (en_open_dr) ++ mode2 &= ~MODE2_OUTDRV; ++ else ++ mode2 |= MODE2_OUTDRV; ++ ++ regmap_write(pca->regmap, PCA9685_MODE2, mode2); ++ ++ pca->pwm_chip.ops = &pca9685_pwm_ops; ++ /* add an extra channel for ALL_LED */ ++ pca->pwm_chip.npwm = PCA9685_MAXCHAN + 1; ++ pca->pwm_chip.dev = &client->dev; ++ pca->pwm_chip.base = -1; ++ ++ ret = pwmchip_add(&pca->pwm_chip); ++ if (unlikely(ret < 0)) { ++ dev_err(&client->dev, "pwmchip_add failed %d\n", ret); ++ goto err_gpiochip; ++ } ++ ++ /* Also create a sysfs interface, providing a cmd line config option */ ++ ret = sysfs_create_file(&client->dev.kobj, &dev_attr_pwm_period.attr); ++ if (unlikely(ret < 0)) { ++ dev_err(&client->dev, "sysfs_create_file failed %d\n", ret); ++ goto err_pwmchip; ++ } ++ ++ return ret; ++ ++err_pwmchip: ++ if (unlikely(pwmchip_remove(&pca->pwm_chip))) ++ dev_warn(&client->dev, "%s failed\n", "pwmchip_remove()"); ++ ++err_gpiochip: ++ if (unlikely(gpiochip_remove(&pca->gpio_chip))) ++ dev_warn(&client->dev, "%s failed\n", "gpiochip_remove()"); ++err: ++ mutex_destroy(&pca->lock); ++ ++ return ret; ++} ++ ++static int pca9685_remove(struct i2c_client *client) ++{ ++ struct pca9685 *pca = i2c_get_clientdata(client); ++ int ret; ++ ++ regmap_update_bits(pca->regmap, PCA9685_MODE1, MODE1_SLEEP, ++ MODE1_SLEEP); ++ ++ ret = gpiochip_remove(&pca->gpio_chip); ++ if (unlikely(ret)) ++ dev_err(&client->dev, "%s failed, %d\n", ++ "gpiochip_remove()", ret); ++ ++ sysfs_remove_file(&client->dev.kobj, &dev_attr_pwm_period.attr); ++ ++ ret = pwmchip_remove(&pca->pwm_chip); ++ if (unlikely(ret)) ++ dev_err(&client->dev, "%s failed, %d\n", ++ "pwmchip_remove()", ret); ++ ++ mutex_destroy(&pca->lock); ++ ++ return ret; ++} ++ ++static const struct i2c_device_id pca9685_id[] = { ++ { "pca9685", 0 }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(i2c, pca9685_id); ++ ++static struct i2c_driver pca9685_i2c_driver = { ++ .driver = { ++ .name = "mfd-pca9685", ++ .owner = THIS_MODULE, ++ }, ++ .probe = pca9685_probe, ++ .remove = pca9685_remove, ++ .id_table = pca9685_id, ++}; ++ ++static int __init pca9685_init(void) ++{ ++ if (unlikely((pwm_period < PWM_PERIOD_MIN) || ++ (PWM_PERIOD_MAX < pwm_period))) { ++ pr_err("Invalid PWM period specified (valid range: %d-%d)\n", ++ PWM_PERIOD_MIN, PWM_PERIOD_MAX); ++ return -EINVAL; ++ } ++ ++ return i2c_add_driver(&pca9685_i2c_driver); ++} ++/* register after i2c postcore initcall */ ++subsys_initcall(pca9685_init); ++ ++static void __exit pca9685_exit(void) ++{ ++ i2c_del_driver(&pca9685_i2c_driver); ++} ++module_exit(pca9685_exit); ++ ++MODULE_AUTHOR("Wojciech Ziemba <wojciech.ziemba@emutex.com>"); ++MODULE_DESCRIPTION("NPX Semiconductors PCA9685 (PWM/GPIO) driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/mfd/pca9685-gpio.c b/drivers/mfd/pca9685-gpio.c +new file mode 100644 +index 0000000..7cfff86 +--- /dev/null ++++ b/drivers/mfd/pca9685-gpio.c +@@ -0,0 +1,108 @@ ++/* ++ * Driver for NPX PCA9685 I2C-bus PWM controller with GPIO output interface ++ * support. ++ * ++ * Copyright(c) 2013 Intel Corporation. + * -+ * 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. ++ * 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. + * -+ * 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 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. + * -+ * Contact Information: -+ * Intel Corporation ++ * The I2C-bus LED controller provides 16-channel, 12-bit PWM Fm+. ++ * Additionally, the driver allows the channels to be configured as GPIO ++ * interface (output only). ++ */ ++ ++#include <linux/device.h> ++#include <linux/module.h> ++#include <linux/gpio.h> ++#include <linux/pwm.h> ++#include <linux/regmap.h> ++ ++#include "pca9685.h" ++ ++static inline struct pca9685 *gpio_to_pca(struct gpio_chip *gpio_chip) ++{ ++ return container_of(gpio_chip, struct pca9685, gpio_chip); ++} ++ ++static inline int is_gpio_allowed(const struct pca9685 *pca, unsigned channel) ++{ ++ return pca->chan_mapping[channel] & PWM_CH_GPIO; ++} ++ ++int pca9685_gpio_request(struct gpio_chip *chip, unsigned offset) ++{ ++ struct pca9685 *pca; ++ struct pwm_device *pwm; ++ int ret = 0; ++ pca = gpio_to_pca(chip); ++ ++ /* validate channel constrains */ ++ if (!is_gpio_allowed(pca, offset)) ++ return -ENODEV; ++ ++ /* return busy if channel is already allocated for pwm */ ++ pwm = &pca->pwm_chip.pwms[offset]; ++ if (test_bit(PWMF_REQUESTED, &pwm->flags)) ++ return -EBUSY; ++ ++ /* clear the on counter */ ++ regmap_write(pca->regmap, LED_N_ON_L(offset), 0x0); ++ regmap_write(pca->regmap, LED_N_ON_H(offset), 0x0); ++ ++ /* clear the off counter */ ++ regmap_write(pca->regmap, LED_N_OFF_L(offset), 0x0); ++ ret = regmap_write(pca->regmap, LED_N_OFF_H(offset), 0x0); ++ ++ clear_sleep_bit(pca); ++ ++ return ret; ++} ++ ++void pca9685_gpio_free(struct gpio_chip *chip, unsigned offset) ++{ ++ struct pca9685 *pca; ++ ++ pca = gpio_to_pca(chip); ++ ++ /* clear the on counter reg */ ++ regmap_write(pca->regmap, LED_N_ON_L(offset), 0x0); ++ regmap_write(pca->regmap, LED_N_ON_H(offset), 0x0); ++ ++ set_sleep_bit(pca); ++ ++ return; ++} ++ ++void pca9685_gpio_set(struct gpio_chip *chip, unsigned offset, int value) ++{ ++ struct pca9685 *pca; ++ ++ pca = gpio_to_pca(chip); ++ ++ /* set the full-on bit */ ++ regmap_write(pca->regmap, LED_N_ON_H(offset), (value << 4) & LED_FULL); ++ ++ return; ++} ++ ++int pca9685_gpio_get(struct gpio_chip *chip, unsigned offset) ++{ ++ struct pca9685 *pca; ++ unsigned int val; ++ ++ pca = gpio_to_pca(chip); ++ ++ /* read the full-on bit */ ++ regmap_read(pca->regmap, LED_N_ON_H(offset), &val); ++ ++ return !!val; ++} ++ ++MODULE_LICENSE("GPL"); +diff --git a/drivers/mfd/pca9685-pwm.c b/drivers/mfd/pca9685-pwm.c +new file mode 100644 +index 0000000..13f82b8 +--- /dev/null ++++ b/drivers/mfd/pca9685-pwm.c +@@ -0,0 +1,262 @@ ++/* ++ * Driver for NPX PCA9685 I2C-bus PWM controller with GPIO output interface ++ * support. ++ * ++ * 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. ++ * ++ * The I2C-bus LED controller provides 16-channel, 12-bit PWM Fm+. ++ * Additionally, the driver allows the channels to be configured as GPIO ++ * interface (output only). ++ */ ++ ++#include <linux/module.h> ++#include <linux/pwm.h> ++#include <linux/gpio.h> ++#include <linux/regmap.h> ++#include <linux/platform_device.h> ++#include <linux/delay.h> ++ ++#include "pca9685.h" ++ ++static inline struct pca9685 *pwm_to_pca(struct pwm_chip *pwm_chip) ++{ ++ return container_of(pwm_chip, struct pca9685, pwm_chip); ++} ++ ++static inline int period_ns_to_prescale(unsigned period_ns) ++{ ++ return (DIV_ROUND_CLOSEST(OSC_CLK_MHZ * period_ns, ++ SAMPLE_RES * 1000)) - 1; ++} ++ ++static inline int is_pwm_allowed(const struct pca9685 *pca, unsigned channel) ++{ ++ return pca->chan_mapping[channel] & PWM_CH_PWM; ++} ++ ++int pca9685_update_prescale(struct pca9685 *pca, unsigned period_ns, ++ bool reconfigure_channels) ++{ ++ int pre_scale, i; ++ struct pwm_device *pwm; ++ unsigned long long duty_scale; ++ unsigned long long new_duty_ns; ++ ++ if (unlikely((period_ns < PWM_PERIOD_MIN) || ++ (PWM_PERIOD_MAX < period_ns))) { ++ pr_err("Invalid PWM period specified (valid range: %d-%d)\n", ++ PWM_PERIOD_MIN, PWM_PERIOD_MAX); ++ return -EINVAL; ++ } ++ ++ mutex_lock(&pca->lock); ++ ++ /* update pre_scale to the closest period */ ++ pre_scale = period_ns_to_prescale(period_ns); ++ /* ensure sleep-mode bit is set ++ * NOTE: All active channels will switch off for at least 500 usecs ++ */ ++ regmap_update_bits(pca->regmap, PCA9685_MODE1, ++ MODE1_SLEEP, MODE1_SLEEP); ++ regmap_write(pca->regmap, PCA9685_PRESCALE, pre_scale); ++ /* clear sleep mode flag if at least 1 channel is active */ ++ if (pca->active_cnt > 0) { ++ regmap_update_bits(pca->regmap, PCA9685_MODE1, ++ MODE1_SLEEP, 0x0); ++ usleep_range(MODE1_RESTART_DELAY, MODE1_RESTART_DELAY * 2); ++ regmap_update_bits(pca->regmap, PCA9685_MODE1, ++ MODE1_RESTART, MODE1_RESTART); ++ } ++ ++ if (reconfigure_channels) { ++ for (i = 0; i < pca->pwm_chip.npwm; i++) { ++ pwm = &pca->pwm_chip.pwms[i]; ++ pwm->period = period_ns; ++ if (pwm->duty_cycle > 0) { ++ /* Scale the rise time to maintain duty cycle */ ++ duty_scale = period_ns; ++ duty_scale *= 1000000; ++ do_div(duty_scale, pca->pwm_period); ++ new_duty_ns = duty_scale * pwm->duty_cycle; ++ do_div(new_duty_ns, 1000000); ++ /* Update the duty_cycle */ ++ pwm_config(pwm, (int)new_duty_ns, pwm->period); ++ } ++ } ++ } ++ pca->pwm_period = period_ns; ++ ++ mutex_unlock(&pca->lock); ++ return 0; ++} ++ ++int pca9685_init_pwm_regs(struct pca9685 *pca, unsigned period_ns) ++{ ++ int ret, chan; ++ ++ /* set MODE1_SLEEP */ ++ ret = regmap_update_bits(pca->regmap, PCA9685_MODE1, ++ MODE1_SLEEP, MODE1_SLEEP); ++ if (unlikely(ret < 0)) ++ return ret; ++ ++ /* configure the initial PWM clock period */ ++ ret = pca9685_update_prescale(pca, period_ns, false); ++ if (unlikely(ret < 0)) ++ return ret; ++ ++ /* reset PWM channel registers to power-on default values */ ++ for (chan = 0; chan < PCA9685_MAXCHAN; chan++) { ++ ret = regmap_write(pca->regmap, LED_N_ON_L(chan), 0); ++ if (unlikely(ret < 0)) ++ return ret; ++ ret = regmap_write(pca->regmap, LED_N_ON_H(chan), 0); ++ if (unlikely(ret < 0)) ++ return ret; ++ ret = regmap_write(pca->regmap, LED_N_OFF_L(chan), 0); ++ if (unlikely(ret < 0)) ++ return ret; ++ ret = regmap_write(pca->regmap, LED_N_OFF_H(chan), LED_FULL); ++ if (unlikely(ret < 0)) ++ return ret; ++ } ++ /* reset ALL_LED registers to power-on default values */ ++ ret = regmap_write(pca->regmap, PCA9685_ALL_LED_ON_L, 0); ++ if (unlikely(ret < 0)) ++ return ret; ++ ret = regmap_write(pca->regmap, PCA9685_ALL_LED_ON_H, 0); ++ if (unlikely(ret < 0)) ++ return ret; ++ ret = regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_L, 0); ++ if (unlikely(ret < 0)) ++ return ret; ++ ret = regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_H, LED_FULL); ++ if (unlikely(ret < 0)) ++ return ret; ++ ++ return ret; ++} ++ ++static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, ++ int duty_ns, int period_ns) ++{ ++ struct pca9685 *pca = pwm_to_pca(chip); ++ unsigned long long duty; ++ unsigned int reg_on_h, ++ reg_off_l, ++ reg_off_h; ++ int full_off; ++ ++ /* Changing PWM period for a single channel at run-time not allowed. ++ * The PCA9685 PWM clock is shared across all PWM channels ++ */ ++ if (unlikely(period_ns != pwm->period)) ++ return -EPERM; ++ ++ if (unlikely(pwm->hwpwm >= PCA9685_MAXCHAN)) { ++ reg_on_h = PCA9685_ALL_LED_ON_H; ++ reg_off_l = PCA9685_ALL_LED_OFF_L; ++ reg_off_h = PCA9685_ALL_LED_OFF_H; ++ } else { ++ reg_on_h = LED_N_ON_H(pwm->hwpwm); ++ reg_off_l = LED_N_OFF_L(pwm->hwpwm); ++ reg_off_h = LED_N_OFF_H(pwm->hwpwm); ++ } ++ ++ duty = SAMPLE_RES * (unsigned long long)duty_ns; ++ duty = DIV_ROUND_UP_ULL(duty, period_ns); ++ ++ if (duty >= SAMPLE_RES) /* set the LED_FULL bit */ ++ return regmap_write(pca->regmap, reg_on_h, LED_FULL); ++ else /* clear the LED_FULL bit */ ++ regmap_write(pca->regmap, reg_on_h, 0x00); ++ ++ full_off = !test_bit(PWMF_ENABLED, &pwm->flags) << 4; ++ ++ regmap_write(pca->regmap, reg_off_l, (int)duty & 0xff); ++ ++ return regmap_write(pca->regmap, reg_off_h, ++ ((int)duty >> 8 | full_off) & 0x1f); ++} ++ ++static int pca9685_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) ++{ ++ struct pca9685 *pca = pwm_to_pca(chip); ++ int ret; ++ ++ unsigned int reg_off_h; ++ ++ if (unlikely(pwm->hwpwm >= PCA9685_MAXCHAN)) ++ reg_off_h = PCA9685_ALL_LED_OFF_H; ++ else ++ reg_off_h = LED_N_OFF_H(pwm->hwpwm); ++ ++ /* clear the full-off bit */ ++ ret = regmap_update_bits(pca->regmap, reg_off_h, LED_FULL, 0x0); ++ ++ clear_sleep_bit(pca); ++ ++ return ret; ++} ++ ++static void pca9685_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) ++{ ++ struct pca9685 *pca = pwm_to_pca(chip); ++ ++ unsigned int reg_off_h; ++ ++ if (unlikely(pwm->hwpwm >= PCA9685_MAXCHAN)) ++ reg_off_h = PCA9685_ALL_LED_OFF_H; ++ else ++ reg_off_h = LED_N_OFF_H(pwm->hwpwm); ++ ++ /* set the LED_OFF counter. */ ++ regmap_update_bits(pca->regmap, reg_off_h, LED_FULL, LED_FULL); ++ ++ set_sleep_bit(pca); ++ ++ return; ++} ++ ++static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) ++{ ++ struct pca9685 *pca; ++ struct gpio_chip *gpio_chip; ++ unsigned channel = pwm->hwpwm; ++ ++ pca = pwm_to_pca(chip); ++ ++ /* validate channel constrains */ ++ if (!is_pwm_allowed(pca, channel)) ++ return -ENODEV; ++ ++ /* return busy if channel is already allocated for gpio */ ++ gpio_chip = &pca->gpio_chip; ++ ++ if ((channel < PCA9685_MAXCHAN) && ++ (gpiochip_is_requested(gpio_chip, channel))) ++ return -EBUSY; ++ ++ pwm->period = pca->pwm_period; ++ ++ return 0; ++} ++ ++const struct pwm_ops pca9685_pwm_ops = { ++ .enable = pca9685_pwm_enable, ++ .disable = pca9685_pwm_disable, ++ .config = pca9685_pwm_config, ++ .request = pca9685_pwm_request, ++ .owner = THIS_MODULE, ++}; ++ ++MODULE_LICENSE("GPL"); +diff --git a/drivers/mfd/pca9685.h b/drivers/mfd/pca9685.h +new file mode 100644 +index 0000000..3627097 +--- /dev/null ++++ b/drivers/mfd/pca9685.h +@@ -0,0 +1,110 @@ ++/* ++ * Driver for NPX PCA9685 I2C-bus PWM controller with GPIO output interface ++ * support. ++ * ++ * 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. ++ * ++ * The I2C-bus LED controller provides 16-channel, 12-bit PWM Fm+. ++ * Additionally, the driver allows the channels to be configured as GPIO ++ * interface (output only). ++ */ ++ ++#ifndef __LINUX_MFD_PCA9685_H ++#define __LINUX_MFD_PCA9685_H ++ ++#include <linux/mutex.h> ++#include <linux/gpio.h> ++#include <linux/pwm.h> ++#include <linux/platform_data/pca9685.h> ++ ++#define PCA9685_MODE1 0x00 ++#define PCA9685_MODE2 0x01 ++#define PCA9685_SUBADDR1 0x02 ++#define PCA9685_SUBADDR2 0x03 ++#define PCA9685_SUBADDR3 0x04 ++#define PCA9685_LEDX_ON_L 0x06 ++#define PCA9685_LEDX_ON_H 0x07 ++#define PCA9685_LEDX_OFF_L 0x08 ++#define PCA9685_LEDX_OFF_H 0x09 ++ ++#define PCA9685_ALL_LED_ON_L 0xFA ++#define PCA9685_ALL_LED_ON_H 0xFB ++#define PCA9685_ALL_LED_OFF_L 0xFC ++#define PCA9685_ALL_LED_OFF_H 0xFD ++#define PCA9685_PRESCALE 0xFE ++ ++#define PCA9685_NUMREGS 0xFF ++ ++#define LED_FULL (1 << 4) ++#define MODE1_SLEEP (1 << 4) ++#define MODE1_RESTART (1 << 7) ++ ++#define MODE1_RESTART_DELAY 500 ++ ++#define LED_N_ON_H(N) (PCA9685_LEDX_ON_H + (4 * (N))) ++#define LED_N_ON_L(N) (PCA9685_LEDX_ON_L + (4 * (N))) ++#define LED_N_OFF_H(N) (PCA9685_LEDX_OFF_H + (4 * (N))) ++#define LED_N_OFF_L(N) (PCA9685_LEDX_OFF_L + (4 * (N))) ++ ++#define OSC_CLK_MHZ 25 /* 25 MHz */ ++#define SAMPLE_RES 4096 /* 12 bits */ ++#define PWM_PERIOD_MIN 666666 /* ~1525 Hz */ ++#define PWM_PERIOD_MAX 41666666 /* 24 Hz */ ++#define PWM_PERIOD_DEF 5000000 /* default 200 Hz */ ++ ++struct pca9685 { ++ struct gpio_chip gpio_chip; ++ struct pwm_chip pwm_chip; ++ struct regmap *regmap; ++ struct mutex lock; /* mutual exclusion semaphore */ ++ /* Array of channel allocation constrains */ ++ /* add an extra channel for ALL_LED */ ++ u8 chan_mapping[PCA9685_MAXCHAN + 1]; ++ int gpio_base; ++ int active_cnt; ++ int pwm_exported_cnt; ++ int pwm_period; ++}; ++ ++extern const struct pwm_ops pca9685_pwm_ops; ++ ++int pca9685_gpio_request(struct gpio_chip *chip, unsigned offset); ++void pca9685_gpio_free(struct gpio_chip *chip, unsigned offset); ++void pca9685_gpio_set(struct gpio_chip *chip, unsigned offset, int value); ++int pca9685_gpio_get(struct gpio_chip *chip, unsigned offset); ++ ++int pca9685_init_pwm_regs(struct pca9685 *pca, unsigned period_ns); ++int pca9685_update_prescale(struct pca9685 *pca, unsigned period_ns, ++ bool reconfigure_channels); ++ ++static inline void set_sleep_bit(struct pca9685 *pca) ++{ ++ mutex_lock(&pca->lock); ++ /* set sleep mode flag if no more active LED channel*/ ++ if (--pca->active_cnt == 0) ++ regmap_update_bits(pca->regmap, PCA9685_MODE1, MODE1_SLEEP, ++ MODE1_SLEEP); ++ mutex_unlock(&pca->lock); ++} ++ ++static inline void clear_sleep_bit(struct pca9685 *pca) ++{ ++ mutex_lock(&pca->lock); ++ /* clear sleep mode flag if at least 1 LED channel is active */ ++ if (pca->active_cnt++ == 0) ++ regmap_update_bits(pca->regmap, PCA9685_MODE1, ++ MODE1_SLEEP, 0x0); ++ ++ mutex_unlock(&pca->lock); ++} ++ ++#endif /* __LINUX_MFD_PCA9685_H */ +diff --git a/include/linux/mfd/cy8c9540a.h b/include/linux/mfd/cy8c9540a.h +new file mode 100644 +index 0000000..4d79825 +--- /dev/null ++++ b/include/linux/mfd/cy8c9540a.h +@@ -0,0 +1,31 @@ ++/* ++ * 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. + */ + +#ifndef LINUX_CY8C9540A_PDATA_H @@ -3781,28 +4534,21 @@ index 0000000..a32c6f0 +#endif diff --git a/include/linux/mfd/intel_qrk_gip_pdata.h b/include/linux/mfd/intel_qrk_gip_pdata.h new file mode 100644 -index 0000000..1378f5c +index 0000000..eab17d9 --- /dev/null +++ b/include/linux/mfd/intel_qrk_gip_pdata.h -@@ -0,0 +1,32 @@ +@@ -0,0 +1,25 @@ +/* + * Copyright(c) 2013 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * 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. + * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ + +#ifndef LINUX_INTEL_QRK_GIP_DATA_H @@ -3817,6 +4563,60 @@ index 0000000..1378f5c +extern struct intel_qrk_gip_pdata *(*intel_qrk_gip_get_pdata)(void); + +#endif --- -1.7.4.1 - +diff --git a/include/linux/platform_data/pca9685.h b/include/linux/platform_data/pca9685.h +new file mode 100644 +index 0000000..903d30d +--- /dev/null ++++ b/include/linux/platform_data/pca9685.h +@@ -0,0 +1,51 @@ ++/* ++ * Platform data for pca9685 driver ++ * ++ * 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. ++ */ ++ ++#ifndef _PLAT_PCA9685_H_ ++#define _PLAT_PCA9685_H_ ++ ++#define PCA9685_MAXCHAN 16 ++#define MODE2_INVRT (1 << 4) ++#define MODE2_OUTDRV (1 << 2) ++ ++/* PWM channel allocation flags */ ++enum { ++ PWM_CH_DISABLED = 0, ++ PWM_CH_PWM = 1 << 0, ++ PWM_CH_GPIO = 1 << 1, ++ /* allow PWM or GPIO */ ++ PWM_CH_UNDEFINED = PWM_CH_PWM | PWM_CH_GPIO, ++}; ++ ++/** ++ * struct pca9685_pdata - Platform data for pca9685 driver ++ * @chan_mapping: Array of channel allocation constrains ++ * @gpio_base: GPIO base ++ * mode2_flags: mode2 register modification flags: INVRT and OUTDRV ++ **/ ++struct pca9685_pdata { ++ /* Array of channel allocation constrains */ ++ /* add an extra channel for ALL_LED */ ++ u8 chan_mapping[PCA9685_MAXCHAN + 1]; ++ /* GPIO base */ ++ int gpio_base; ++ /* mode2 flags */ ++ u8 en_invrt:1, /* enable output logic state inverted mode */ ++ en_open_dr:1, /* enable if outputs are configured with an ++ open-drain structure */ ++ unused:6; ++}; ++ ++#endif /* _PLAT_PCA9685_H_ */ diff --git a/recipes-kernel/linux/files/0017-Quark-I2C-quark.patch b/recipes-kernel/linux/files/0017-Quark-I2C-quark.patch index a730cca..03a3ada 100644 --- a/recipes-kernel/linux/files/0017-Quark-I2C-quark.patch +++ b/recipes-kernel/linux/files/0017-Quark-I2C-quark.patch @@ -4,10 +4,10 @@ Date: Tue, 13 Aug 2013 10:22:38 +0100 Subject: [PATCH 17/21] Quark I2C --- - drivers/i2c/busses/Kconfig | 19 +++--- - drivers/i2c/busses/i2c-designware-core.c | 99 ++++++++++++++++++++++++++-- - drivers/i2c/busses/i2c-designware-core.h | 12 ++++ - drivers/i2c/busses/i2c-designware-pcidrv.c | 18 +++-- + drivers/i2c/busses/Kconfig | 19 +++--- + drivers/i2c/busses/i2c-designware-core.c | 99 +++++++++++++++++++++++++++--- + drivers/i2c/busses/i2c-designware-core.h | 12 ++++ + drivers/i2c/busses/i2c-designware-pcidrv.c | 18 +++--- 4 files changed, 123 insertions(+), 25 deletions(-) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig @@ -412,6 +412,3 @@ index 6add851..62ad7dc 100644 r = i2c_dw_init(dev); if (r) goto err_iounmap; --- -1.7.4.1 - diff --git a/recipes-kernel/linux/files/0018-Quark-sensors-quark.patch b/recipes-kernel/linux/files/0018-Quark-sensors-quark.patch index e59a7de..7f9de6c 100644 --- a/recipes-kernel/linux/files/0018-Quark-sensors-quark.patch +++ b/recipes-kernel/linux/files/0018-Quark-sensors-quark.patch @@ -4,24 +4,24 @@ Date: Mon, 24 Feb 2014 18:41:59 +0000 Subject: [PATCH 18/21] Quark sensors --- - drivers/iio/accel/Kconfig | 8 + - drivers/iio/accel/Makefile | 2 + - drivers/iio/accel/lis331dlh_intel_qrk.c | 735 ++++++++++++++++++++ - drivers/iio/common/Kconfig | 1 + - drivers/iio/common/Makefile | 1 + - drivers/iio/common/st_sensors/Kconfig | 14 + - drivers/iio/common/st_sensors/Makefile | 10 + - drivers/iio/common/st_sensors/st_sensors_buffer.c | 115 +++ - drivers/iio/common/st_sensors/st_sensors_core.c | 447 ++++++++++++ - drivers/iio/common/st_sensors/st_sensors_i2c.c | 81 +++ - drivers/iio/common/st_sensors/st_sensors_spi.c | 128 ++++ - drivers/iio/common/st_sensors/st_sensors_trigger.c | 77 ++ - drivers/iio/industrialio-buffer.c | 6 +- - include/linux/iio/common/st_sensors.h | 289 ++++++++ - include/linux/iio/common/st_sensors_i2c.h | 20 + - include/linux/iio/common/st_sensors_spi.h | 20 + - include/linux/platform_data/lis331dlh_intel_qrk.h | 36 + - 17 files changed, 1987 insertions(+), 3 deletions(-) + drivers/iio/accel/Kconfig | 8 + + drivers/iio/accel/Makefile | 2 + + drivers/iio/accel/lis331dlh_intel_qrk.c | 728 +++++++++++++++++++++ + drivers/iio/common/Kconfig | 1 + + drivers/iio/common/Makefile | 1 + + drivers/iio/common/st_sensors/Kconfig | 14 + + drivers/iio/common/st_sensors/Makefile | 10 + + drivers/iio/common/st_sensors/st_sensors_buffer.c | 115 ++++ + drivers/iio/common/st_sensors/st_sensors_core.c | 447 +++++++++++++ + drivers/iio/common/st_sensors/st_sensors_i2c.c | 81 +++ + drivers/iio/common/st_sensors/st_sensors_spi.c | 128 ++++ + drivers/iio/common/st_sensors/st_sensors_trigger.c | 77 +++ + drivers/iio/industrialio-buffer.c | 6 +- + include/linux/iio/common/st_sensors.h | 289 ++++++++ + include/linux/iio/common/st_sensors_i2c.h | 20 + + include/linux/iio/common/st_sensors_spi.h | 20 + + include/linux/platform_data/lis331dlh_intel_qrk.h | 29 + + 17 files changed, 1973 insertions(+), 3 deletions(-) create mode 100644 drivers/iio/accel/lis331dlh_intel_qrk.c create mode 100644 drivers/iio/common/st_sensors/Kconfig create mode 100644 drivers/iio/common/st_sensors/Makefile @@ -65,30 +65,23 @@ index 5bc6855..81f8085 100644 +obj-$(CONFIG_IIO_LIS331DLH_INTEL_QRK) += lis331dlh_intel_qrk.o diff --git a/drivers/iio/accel/lis331dlh_intel_qrk.c b/drivers/iio/accel/lis331dlh_intel_qrk.c new file mode 100644 -index 0000000..6b49c6f +index 0000000..fe868fd --- /dev/null +++ b/drivers/iio/accel/lis331dlh_intel_qrk.c -@@ -0,0 +1,735 @@ +@@ -0,0 +1,728 @@ +/* + * Intel Clanton Hill platform accelerometer driver + * + * Copyright(c) 2013 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 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 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. -+ * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + * + * Derived from STMicroelectronics accelerometers driver by Denis Ciocca + * @@ -2110,30 +2103,23 @@ index 0000000..d964a35 +#endif /* ST_SENSORS_SPI_H */ diff --git a/include/linux/platform_data/lis331dlh_intel_qrk.h b/include/linux/platform_data/lis331dlh_intel_qrk.h new file mode 100644 -index 0000000..703c927 +index 0000000..f0d914c --- /dev/null +++ b/include/linux/platform_data/lis331dlh_intel_qrk.h -@@ -0,0 +1,36 @@ +@@ -0,0 +1,29 @@ +/* + * Platform data for Intel Clanton Hill platform accelerometer driver + * + * Copyright(c) 2013 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. ++ * 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. + * -+ * 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. -+ * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + * + */ + @@ -2150,6 +2136,3 @@ index 0000000..703c927 +}; + +#endif /* LINUX_PLATFORM_DATA_LIS331DLH_INTEL_QRK_H_ */ --- -1.7.4.1 - diff --git a/recipes-kernel/linux/files/0019-Quark-SC-SPI-quark.patch b/recipes-kernel/linux/files/0019-Quark-SC-SPI-quark.patch index 7c89b92..417f57f 100644 --- a/recipes-kernel/linux/files/0019-Quark-SC-SPI-quark.patch +++ b/recipes-kernel/linux/files/0019-Quark-SC-SPI-quark.patch @@ -4,10 +4,10 @@ Date: Thu, 13 Feb 2014 16:41:02 +0000 Subject: [PATCH 19/21] Quark SC SPI --- - drivers/spi/Kconfig | 39 ++- + drivers/spi/Kconfig | 39 +- drivers/spi/Makefile | 1 + drivers/spi/spi-gpio.c | 2 +- - drivers/spi/spi-pxa2xx-pci.c | 129 ++++- + drivers/spi/spi-pxa2xx-pci.c | 129 +++- drivers/spi/spi-pxa2xx.c | 1290 +++++++++++++++++++++++++++------------- include/linux/pxa2xx_ssp.h | 25 + include/linux/spi/pxa2xx_spi.h | 15 +- @@ -2344,6 +2344,3 @@ index f629189..307d218 100644 #define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */ #define SPI_3WIRE 0x10 /* SI/SO signals shared */ #define SPI_LOOP 0x20 /* loopback mode */ --- -1.7.4.1 - diff --git a/recipes-kernel/linux/files/0020-Quark-IIO-quark.patch b/recipes-kernel/linux/files/0020-Quark-IIO-quark.patch index 809c203..03622f9 100644 --- a/recipes-kernel/linux/files/0020-Quark-IIO-quark.patch +++ b/recipes-kernel/linux/files/0020-Quark-IIO-quark.patch @@ -1,21 +1,25 @@ From xxxx Mon Sep 17 00:00:00 2001 From: Dan O'Donovan <dan.odonovan@emutex.com> -Date: Fri, 14 Feb 2014 14:10:33 +0000 +Date: Wed, 9 Apr 2014 15:34:37 +0100 Subject: [PATCH 20/21] Quark IIO --- drivers/iio/adc/ad7298.c | 20 +- - drivers/staging/iio/adc/Kconfig | 13 + - drivers/staging/iio/adc/Makefile | 1 + - drivers/staging/iio/adc/max78m6610_lmu.c | 2235 ++++++++++++++++++++++++ + drivers/staging/iio/adc/Kconfig | 24 + + drivers/staging/iio/adc/Makefile | 2 + + drivers/staging/iio/adc/adc1x8s102.c | 387 ++++ + drivers/staging/iio/adc/max78m6610_lmu.c | 2575 ++++++++++++++++++++++++ drivers/staging/iio/trigger/Kconfig | 11 + drivers/staging/iio/trigger/Makefile | 1 + drivers/staging/iio/trigger/iio-trig-hrtimer.c | 288 +++ include/linux/platform_data/ad7298.h | 5 + - include/linux/platform_data/max78m6610_lmu.h | 34 + - 9 files changed, 2603 insertions(+), 5 deletions(-) + include/linux/platform_data/adc1x8s102.h | 30 + + include/linux/platform_data/max78m6610_lmu.h | 27 + + 11 files changed, 3365 insertions(+), 5 deletions(-) + create mode 100644 drivers/staging/iio/adc/adc1x8s102.c create mode 100644 drivers/staging/iio/adc/max78m6610_lmu.c create mode 100644 drivers/staging/iio/trigger/iio-trig-hrtimer.c + create mode 100644 include/linux/platform_data/adc1x8s102.h create mode 100644 include/linux/platform_data/max78m6610_lmu.h diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c @@ -78,10 +82,10 @@ index b34d754..60491e4 100644 if (st->ext_ref) { st->reg = regulator_get(&spi->dev, "vref"); diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig -index fb8c239..1309fac 100644 +index fb8c239..d9fef7a 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig -@@ -137,4 +137,17 @@ config SPEAR_ADC +@@ -137,4 +137,28 @@ config SPEAR_ADC Say yes here to build support for the integrated ADC inside the ST SPEAr SoC. Provides direct access via sysfs. @@ -97,43 +101,441 @@ index fb8c239..1309fac 100644 + To compile this driver as a module, choose M here: the + module will be called max78m6610_lmu. + ++config ADC1x8S102 ++ tristate "Texas Instruments ADC1x8S102 driver" ++ depends on SPI ++ select IIO_BUFFER ++ select IIO_TRIGGERED_BUFFER ++ help ++ Say yes here to build support for Texas Instruments ADC1x8S102 ADC. ++ Provides direct access via sysfs. ++ ++ To compile this driver as a module, choose M here: the module will ++ be called adc1x8s102 + endmenu diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile -index d285596..2c4e7e1 100644 +index d285596..5a2f486 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile -@@ -21,3 +21,4 @@ obj-$(CONFIG_AD7280) += ad7280a.o +@@ -21,3 +21,5 @@ obj-$(CONFIG_AD7280) += ad7280a.o obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o obj-$(CONFIG_SPEAR_ADC) += spear_adc.o +obj-$(CONFIG_MAX78M6610_LMU) += max78m6610_lmu.o ++obj-$(CONFIG_ADC1x8S102) += adc1x8s102.o +diff --git a/drivers/staging/iio/adc/adc1x8s102.c b/drivers/staging/iio/adc/adc1x8s102.c +new file mode 100644 +index 0000000..b4de3a9 +--- /dev/null ++++ b/drivers/staging/iio/adc/adc1x8s102.c +@@ -0,0 +1,387 @@ ++/* ++ * ADC1x8S102 SPI ADC driver ++ * ++ * 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. ++ * ++ * This IIO device driver is is designed to work with the following ++ * analog to digital converters from Texas Instruments: ++ * ADC108S102 ++ * ADC128S102 ++ * The communication with ADC chip is via the SPI bus (mode 3). ++ */ ++ ++ ++#include <linux/iio/iio.h> ++#include <linux/iio/buffer.h> ++#include <linux/iio/types.h> ++#include <linux/iio/triggered_buffer.h> ++#include <linux/iio/trigger_consumer.h> ++ ++#include <linux/interrupt.h> ++#include <linux/module.h> ++#include <linux/spi/spi.h> ++ ++#include <linux/platform_data/adc1x8s102.h> ++#include <linux/regulator/consumer.h> ++ ++/* ++ * Defining the ADC resolution being 12 bits, we can use the same driver for ++ * both ADC108S102 (10 bits resolution) and ADC128S102 (12 bits resolution) ++ * chips. The ADC108S102 effectively returns a 12-bit result with the 2 ++ * least-significant bits unset. ++ */ ++#define ADC1x8S102_BITS 12 ++#define ADC1x8S102_MAX_CHANNELS 8 ++ ++/* 16-bit SPI command format: ++ * [15:14] Ignored ++ * [13:11] 3-bit channel address ++ * [10:0] Ignored ++ */ ++#define ADC1x8S102_CMD(ch) (((ch) << (8)) << (3)) ++ ++/* ++ * 16-bit SPI response format: ++ * [15:12] Zeros ++ * [11:0] 12-bit ADC sample (for ADC108S102, [1:0] will always be 0). ++ */ ++#define ADC1x8S102_RES_DATA(res) (res & ((1 << ADC1x8S102_BITS) - 1)) ++ ++struct adc1x8s102_state { ++ struct spi_device *spi; ++ struct regulator *reg; ++ u16 ext_vin; ++ /* SPI transfer used by triggered buffer handler*/ ++ struct spi_transfer ring_xfer; ++ /* SPI transfer used by direct scan */ ++ struct spi_transfer scan_single_xfer; ++ /* SPI message used by ring_xfer SPI transfer */ ++ struct spi_message ring_msg; ++ /* SPI message used by scan_single_xfer SPI transfer */ ++ struct spi_message scan_single_msg; ++ ++ /* SPI message buffers: ++ * tx_buf: |C0|C1|C2|C3|C4|C5|C6|C7|XX| ++ * rx_buf: |XX|R0|R1|R2|R3|R4|R5|R6|R7|tt|tt|tt|tt| ++ * ++ * tx_buf: 8 channel read commands, plus 1 dummy command ++ * rx_buf: 1 dummy response, 8 channel responses, plus 64-bit timestamp ++ */ ++ __be16 rx_buf[13] ____cacheline_aligned; ++ __be16 tx_buf[9]; ++ ++}; ++ ++#define ADC1X8S102_V_CHAN(index) \ ++ { \ ++ .type = IIO_VOLTAGE, \ ++ .indexed = 1, \ ++ .channel = index, \ ++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ ++ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ ++ .address = index, \ ++ .scan_index = index, \ ++ .scan_type = { \ ++ .sign = 'u', \ ++ .realbits = ADC1x8S102_BITS, \ ++ .storagebits = 16, \ ++ .endianness = IIO_BE, \ ++ }, \ ++ } ++ ++static const struct iio_chan_spec adc1x8s102_channels[] = { ++ ADC1X8S102_V_CHAN(0), ++ ADC1X8S102_V_CHAN(1), ++ ADC1X8S102_V_CHAN(2), ++ ADC1X8S102_V_CHAN(3), ++ ADC1X8S102_V_CHAN(4), ++ ADC1X8S102_V_CHAN(5), ++ ADC1X8S102_V_CHAN(6), ++ ADC1X8S102_V_CHAN(7), ++ IIO_CHAN_SOFT_TIMESTAMP(8), ++}; ++ ++ ++static int adc1x8s102_update_scan_mode(struct iio_dev *indio_dev, ++ unsigned long const *active_scan_mask) ++{ ++ struct adc1x8s102_state *st; ++ int i, j; ++ ++ st = iio_priv(indio_dev); ++ ++ /* Fill in the first x shorts of tx_buf with the number of channels ++ * enabled for sampling by the triggered buffer ++ */ ++ for (i = 0, j = 0; i < ADC1x8S102_MAX_CHANNELS; i++) { ++ if (test_bit(i, active_scan_mask)) { ++ st->tx_buf[j] = cpu_to_be16(ADC1x8S102_CMD(i)); ++ j++; ++ } ++ } ++ /* One dummy command added, to clock in the last response */ ++ st->tx_buf[j] = 0x00; ++ ++ /* build SPI ring message */ ++ st->ring_xfer.tx_buf = &st->tx_buf[0]; ++ st->ring_xfer.rx_buf = &st->rx_buf[0]; ++ st->ring_xfer.len = (j + 1) * sizeof(__be16); ++ ++ spi_message_init(&st->ring_msg); ++ spi_message_add_tail(&st->ring_xfer, &st->ring_msg); ++ ++ return 0; ++} ++ ++ ++static irqreturn_t adc1x8s102_trigger_handler(int irq, void *p) ++{ ++ struct iio_poll_func *pf = p; ++ struct iio_dev *indio_dev; ++ struct adc1x8s102_state *st; ++ s64 time_ns = 0; ++ int b_sent; ++ ++ indio_dev = pf->indio_dev; ++ st = iio_priv(indio_dev); ++ ++ b_sent = spi_sync(st->spi, &st->ring_msg); ++ if (b_sent) ++ goto done; ++ if (indio_dev->scan_timestamp) { ++ time_ns = iio_get_time_ns(); ++ memcpy((u8 *)st->rx_buf + st->ring_xfer.len, &time_ns, ++ sizeof(time_ns)); ++ } ++ ++ /* Skip the dummy response in the first slot */ ++ iio_push_to_buffers(indio_dev, (u8 *)&st->rx_buf[1]); ++done: ++ iio_trigger_notify_done(indio_dev->trig); ++ ++ return IRQ_HANDLED; ++} ++ ++ ++/* ++ * returns: ++ * positive (>=0) value => SUCCESS ++ * negative value => FAILURE ++ */ ++static int adc1x8s102_scan_direct(struct adc1x8s102_state *st, unsigned ch) ++{ ++ int ret; ++ ++ if (ch >= ADC1x8S102_MAX_CHANNELS) { ++ dev_err(&st->spi->dev, "AD channel number too big: %u\n", ch); ++ return -1; ++ } ++ ++ st->tx_buf[0] = cpu_to_be16(ADC1x8S102_CMD(ch)); ++ ret = spi_sync(st->spi, &st->scan_single_msg); ++ if (ret) ++ return ret; ++ ++ /* Skip the dummy response in the first slot */ ++ return be16_to_cpu(st->rx_buf[1]); ++} ++ ++ ++/* ++ * returns: ++ * positive (>=0) value => SUCCESS ++ * negative value => FAILURE ++ */ ++static int adc1x8s102_read_raw(struct iio_dev *indio_dev, ++ struct iio_chan_spec const *chan, ++ int *val, ++ int *val2, ++ long m) ++{ ++ int ret; ++ struct adc1x8s102_state *st; ++ ++ 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; ++ dev_warn(&st->spi->dev, ++ "indio_dev->currentmode is INDIO_BUFFER_TRIGGERED\n"); ++ } else { ++ ret = adc1x8s102_scan_direct(st, chan->address); ++ } ++ mutex_unlock(&indio_dev->mlock); ++ ++ if (ret < 0) ++ return ret; ++ *val = ADC1x8S102_RES_DATA(ret); ++ ++ return IIO_VAL_INT; ++ case IIO_CHAN_INFO_SCALE: ++ switch (chan->type) { ++ case IIO_VOLTAGE: ++ if (NULL != st->reg) ++ *val = regulator_get_voltage(st->reg) / 1000; ++ else ++ *val = st->ext_vin; ++ ++ *val2 = chan->scan_type.realbits; ++ return IIO_VAL_FRACTIONAL_LOG2; ++ default: ++ dev_warn(&st->spi->dev, ++ "Invalid channel type %u for channel %d\n", ++ chan->type, chan->channel); ++ return -EINVAL; ++ } ++ default: ++ dev_warn(&st->spi->dev, "Invalid IIO_CHAN_INFO: %lu\n", m); ++ return -EINVAL; ++ } ++} ++ ++ ++ ++static const struct iio_info adc1x8s102_info = { ++ .read_raw = &adc1x8s102_read_raw, ++ .update_scan_mode = &adc1x8s102_update_scan_mode, ++ .driver_module = THIS_MODULE, ++}; ++ ++ ++static int adc1x8s102_probe(struct spi_device *spi) ++{ ++ struct adc1x8s102_platform_data *pdata = spi->dev.platform_data; ++ struct adc1x8s102_state *st; ++ struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); ++ int ret; ++ ++ if (NULL == indio_dev) { ++ dev_crit(&spi->dev, "Cannot allocate memory for indio_dev\n"); ++ return -ENOMEM; ++ } ++ ++ st = iio_priv(indio_dev); ++ if (NULL == pdata) { ++ dev_err(&spi->dev, "Cannot get adc1x8s102 platform data\n"); ++ return -EFAULT; ++ } ++ st->ext_vin = pdata->ext_vin; ++ ++ /* Use regulator, if available. */ ++ st->reg = regulator_get(&spi->dev, "vref"); ++ if (IS_ERR(st->reg)) { ++ ret = PTR_ERR(st->reg); ++ dev_warn(&spi->dev, ++ "Cannot get 'vref' regulator\n"); ++ goto error_free; ++ } ++ ret = regulator_enable(st->reg); ++ if (ret < 0) { ++ dev_warn(&spi->dev, ++ "Cannot enable vref regulator\n"); ++ 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 = adc1x8s102_channels; ++ indio_dev->num_channels = ARRAY_SIZE(adc1x8s102_channels); ++ indio_dev->info = &adc1x8s102_info; ++ ++ /* Setup default message */ ++ st->scan_single_xfer.tx_buf = st->tx_buf; ++ st->scan_single_xfer.rx_buf = st->rx_buf; ++ st->scan_single_xfer.len = 2 * sizeof(__be16); ++ st->scan_single_xfer.cs_change = 0; ++ ++ spi_message_init(&st->scan_single_msg); ++ spi_message_add_tail(&st->scan_single_xfer, &st->scan_single_msg); ++ ++ ret = iio_triggered_buffer_setup(indio_dev, NULL, ++ &adc1x8s102_trigger_handler, NULL); ++ if (ret) ++ goto error_disable_reg; ++ ++ ret = iio_device_register(indio_dev); ++ if (ret) { ++ dev_err(&spi->dev, ++ "Failed to register IIO device\n"); ++ goto error_cleanup_ring; ++ } ++ return 0; ++ ++error_cleanup_ring: ++ iio_triggered_buffer_cleanup(indio_dev); ++error_disable_reg: ++ regulator_disable(st->reg); ++error_put_reg: ++ regulator_put(st->reg); ++error_free: ++ iio_device_free(indio_dev); ++ ++ return ret; ++} ++ ++ ++static int adc1x8s102_remove(struct spi_device *spi) ++{ ++ struct iio_dev *indio_dev; ++ struct adc1x8s102_state *st; ++ ++ indio_dev = spi_get_drvdata(spi); ++ if (NULL == indio_dev) { ++ dev_err(&spi->dev, "Cannot get spi_device drvdata\n"); ++ return -EFAULT; ++ } ++ ++ st = iio_priv(indio_dev); ++ ++ iio_device_unregister(indio_dev); ++ ++ iio_triggered_buffer_cleanup(indio_dev); ++ ++ regulator_disable(st->reg); ++ regulator_put(st->reg); ++ ++ iio_device_free(indio_dev); ++ ++ return 0; ++} ++ ++ ++static const struct spi_device_id adc1x8s102_id[] = { ++ {"adc1x8s102", 0}, ++ {} ++}; ++MODULE_DEVICE_TABLE(spi, adc1x8s102_id); ++ ++static struct spi_driver adc1x8s102_driver = { ++ .driver = { ++ .name = "adc1x8s102", ++ .owner = THIS_MODULE, ++ }, ++ .probe = adc1x8s102_probe, ++ .remove = adc1x8s102_remove, ++ .id_table = adc1x8s102_id, ++}; ++module_spi_driver(adc1x8s102_driver); ++ ++MODULE_AUTHOR("Bogdan Pricop <bogdan.pricop@emutex.com>"); ++MODULE_DESCRIPTION("Texas Instruments ADC1x8S102 driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/adc/max78m6610_lmu.c b/drivers/staging/iio/adc/max78m6610_lmu.c new file mode 100644 -index 0000000..c427517 +index 0000000..ebb2a85 --- /dev/null +++ b/drivers/staging/iio/adc/max78m6610_lmu.c -@@ -0,0 +1,2235 @@ +@@ -0,0 +1,2575 @@ +/* + * max78m6610+lmu SPI protocol driver + * + * Copyright(c) 2013 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * 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. + * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + * + * This SPI protocol driver is developed for the Maxim 78M6610+LMU (eADC). + * The driver is developed as a part of the Quark BSP where integrated into @@ -219,8 +621,8 @@ index 0000000..c427517 +#define STATUS_MASK_RELAY1 (1 << 2) +#define STATUS_MASK_RELAY2 (1 << 1) +#define STATUS_MASK_RESET (1) -+#define STATUS_MASK_STICKY (0x73FFF0) -+#define STATUS_MASK_IGNORE (0x00000F) ++#define STATUS_MASK_STICKY (0x73FFF1) ++#define STATUS_MASK_IGNORE (0x00000E) + +#define VSURG_VAL 0x13 /* Voltage surge alarm threshold */ +#define VSAG_VAL 0x14 /* Voltage sag alarm threshold */ @@ -283,6 +685,23 @@ index 0000000..c427517 +#define SPI_TB_WRITE(x) ((SPI_TB_ADDR_MASK_5_0(x) << 2)\ + | SPI_OP_WRITE) + ++#define TIMER_PERIOD_MS 90 ++#define TIMER_PERIOD msecs_to_jiffies(TIMER_PERIOD_MS) ++ ++#define MASK0_INT (STATUS_MASK_OV_AMP2 \ ++ | STATUS_MASK_OV_AMP1 \ ++ | STATUS_MASK_OV_WATT2 \ ++ | STATUS_MASK_OV_WATT1 \ ++ | STATUS_MASK_VB_SURGE \ ++ | STATUS_MASK_VA_SURGE \ ++ | STATUS_MASK_UN_VRMSB \ ++ | STATUS_MASK_OV_VRMSB \ ++ | STATUS_MASK_UN_VRMSA \ ++ | STATUS_MASK_OV_VRMSA \ ++ | STATUS_MASK_VB_SAG \ ++ | STATUS_MASK_VA_SAG) ++ ++ +/** + * max78m6610_lmu_channels structure maps eADC measurement features to + * IIO channels on the IIO sysfs user interface @@ -930,6 +1349,7 @@ index 0000000..c427517 + dev_t cdev_no; + struct class *cl; + u8 *bbuffer; ++ struct timer_list max78m6610_timer; +}; + +/** @@ -1090,7 +1510,7 @@ index 0000000..c427517 + ret = -EIO; + } + -+ return 0; ++ return ret; +} + +/** @@ -1630,8 +2050,11 @@ index 0000000..c427517 + return -1; +} + ++static inline int __max78m6610_lmu_mask0_set(struct max78m6610_lmu_state *st); ++static inline int __max78m6610_lmu_mask0_reset(struct max78m6610_lmu_state *st); ++ +/** -+ * max78m6610_lmu_flash_save_cmd ++ * max78m6610_lmu_status_scan + * + * @param indio_dev: iio_dev pointer + * @@ -1644,9 +2067,12 @@ index 0000000..c427517 +static int max78m6610_lmu_status_scan(struct iio_dev *indio_dev) +{ + struct max78m6610_lmu_state *st = iio_priv(indio_dev); -+ unsigned status; + int ret; + u64 timestamp_ns = iio_get_time_ns(); ++ static unsigned old_status; ++ unsigned new_status = 0x00; ++ u16 event_active; ++ + + mutex_lock(&indio_dev->mlock); + if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) { @@ -1654,151 +2080,228 @@ index 0000000..c427517 + goto exit_unlock; + } + -+ ret = __max78m6610_lmu_spi_reg_read(st, STATUS, &status); ++ /* Disable eADC interrupts - special-reset MASK0 */ ++ ret = __max78m6610_lmu_mask0_reset(st); + if (ret) { -+ pr_err("Failed to read STATUS register\n"); ++ pr_err("Failed to disable interrupts from MASK0!\n"); + goto exit_unlock; + } + -+ status &= ~STATUS_MASK_IGNORE; -+ -+ /* Nothing more to do if no interesting status bits are set */ -+ if (!status) ++ ret = __max78m6610_lmu_spi_reg_read(st, STATUS, &new_status); ++ if (ret) { ++ pr_err("Failed to read STATUS register\n"); + goto exit_unlock; ++ } ++ new_status &= ~STATUS_MASK_IGNORE; + + /* Not all of the event types used below are ideal, but there is a + * limited set available and we want to use different event types for + * the different events (e.g sag vs. min-threshold) to allow user + * applications to distinguish them + */ -+ if (status & STATUS_MASK_VA_SAG) { ++ if ((new_status & STATUS_MASK_VA_SAG) ^ ++ (old_status & STATUS_MASK_VA_SAG)) { ++ event_active = !!(new_status & STATUS_MASK_VA_SAG); + iio_push_event(indio_dev, -+ IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 0, -+ IIO_EV_TYPE_MAG, -+ IIO_EV_DIR_FALLING), -+ timestamp_ns); ++ IIO_EVENT_CODE(IIO_VOLTAGE, ++ 0 /* diff */, ++ IIO_NO_MOD, ++ IIO_EV_DIR_FALLING, ++ IIO_EV_TYPE_MAG, ++ 0 /* chan */, ++ 0 /* chan1 */, ++ event_active /* chan2 */), ++ timestamp_ns); + } -+ if (status & STATUS_MASK_VB_SAG) { ++ if ((new_status & STATUS_MASK_VB_SAG) ^ ++ (old_status & STATUS_MASK_VB_SAG)) { ++ event_active = !!(new_status & STATUS_MASK_VB_SAG); + iio_push_event(indio_dev, -+ IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 1, -+ IIO_EV_TYPE_MAG, -+ IIO_EV_DIR_FALLING), -+ timestamp_ns); ++ IIO_EVENT_CODE(IIO_VOLTAGE, ++ 0 /* diff */, ++ IIO_NO_MOD, ++ IIO_EV_DIR_FALLING, ++ IIO_EV_TYPE_MAG, ++ 1 /* chan */, ++ 0 /* chan1 */, ++ event_active /* chan2 */), ++ timestamp_ns); + } -+ if (status & STATUS_MASK_OV_VRMSA) { ++ if ((new_status & STATUS_MASK_OV_VRMSA) ^ ++ (old_status & STATUS_MASK_OV_VRMSA)) { ++ event_active = !!(new_status & STATUS_MASK_OV_VRMSA); + iio_push_event(indio_dev, -+ IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 0, -+ IIO_EV_TYPE_THRESH, -+ IIO_EV_DIR_RISING), -+ timestamp_ns); ++ IIO_EVENT_CODE(IIO_VOLTAGE, ++ 0 /* diff */, ++ IIO_NO_MOD, ++ IIO_EV_DIR_RISING, ++ IIO_EV_TYPE_THRESH, ++ 0 /* chan */, ++ 0 /* chan1 */, ++ event_active /* chan2 */), ++ timestamp_ns); + } -+ if (status & STATUS_MASK_UN_VRMSA) { ++ if ((new_status & STATUS_MASK_UN_VRMSA) ^ ++ (old_status & STATUS_MASK_UN_VRMSA)) { ++ event_active = !!(new_status & STATUS_MASK_UN_VRMSA); + iio_push_event(indio_dev, -+ IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 0, -+ IIO_EV_TYPE_THRESH, -+ IIO_EV_DIR_FALLING), -+ timestamp_ns); ++ IIO_EVENT_CODE(IIO_VOLTAGE, ++ 0 /* diff */, ++ IIO_NO_MOD, ++ IIO_EV_DIR_FALLING, ++ IIO_EV_TYPE_THRESH, ++ 0 /* chan */, ++ 0 /* chan1 */, ++ event_active /* chan2 */), ++ timestamp_ns); + } -+ if (status & STATUS_MASK_OV_VRMSB) { ++ if ((new_status & STATUS_MASK_OV_VRMSB) ^ ++ (old_status & STATUS_MASK_OV_VRMSB)) { ++ event_active = !!(new_status & STATUS_MASK_OV_VRMSB); + iio_push_event(indio_dev, -+ IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 1, -+ IIO_EV_TYPE_THRESH, -+ IIO_EV_DIR_RISING), -+ timestamp_ns); ++ IIO_EVENT_CODE(IIO_VOLTAGE, ++ 0 /* diff */, ++ IIO_NO_MOD, ++ IIO_EV_DIR_RISING, ++ IIO_EV_TYPE_THRESH, ++ 1 /* chan */, ++ 0 /* chan1 */, ++ event_active /* chan2 */), ++ timestamp_ns); + } -+ if (status & STATUS_MASK_UN_VRMSB) { ++ if ((new_status & STATUS_MASK_UN_VRMSB) ^ ++ (old_status & STATUS_MASK_UN_VRMSB)) { ++ event_active = !!(new_status & STATUS_MASK_UN_VRMSB); + iio_push_event(indio_dev, -+ IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 1, -+ IIO_EV_TYPE_THRESH, -+ IIO_EV_DIR_FALLING), -+ timestamp_ns); ++ IIO_EVENT_CODE(IIO_VOLTAGE, ++ 0 /* diff */, ++ IIO_NO_MOD, ++ IIO_EV_DIR_FALLING, ++ IIO_EV_TYPE_THRESH, ++ 1 /* chan */, ++ 0 /* chan1 */, ++ event_active /* chan2 */), ++ timestamp_ns); + } -+ if (status & STATUS_MASK_VA_SURGE) { ++ if ((new_status & STATUS_MASK_VA_SURGE) ^ ++ (old_status & STATUS_MASK_VA_SURGE)) { ++ event_active = !!(new_status & STATUS_MASK_VA_SURGE); + iio_push_event(indio_dev, -+ IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 0, -+ IIO_EV_TYPE_MAG, -+ IIO_EV_DIR_RISING), -+ timestamp_ns); ++ IIO_EVENT_CODE(IIO_VOLTAGE, ++ 0 /* diff */, ++ IIO_NO_MOD, ++ IIO_EV_DIR_RISING, ++ IIO_EV_TYPE_MAG, ++ 0 /* chan */, ++ 0 /* chan1 */, ++ event_active /* chan2 */), ++ timestamp_ns); + } -+ if (status & STATUS_MASK_VB_SURGE) { ++ if ((new_status & STATUS_MASK_VB_SURGE) ^ ++ (old_status & STATUS_MASK_VB_SURGE)) { ++ event_active = !!(new_status & STATUS_MASK_VB_SURGE); + iio_push_event(indio_dev, -+ IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 1, -+ IIO_EV_TYPE_MAG, -+ IIO_EV_DIR_RISING), -+ timestamp_ns); ++ IIO_EVENT_CODE(IIO_VOLTAGE, ++ 0 /* diff */, ++ IIO_NO_MOD, ++ IIO_EV_DIR_RISING, ++ IIO_EV_TYPE_MAG, ++ 1 /* chan */, ++ 0 /* chan1 */, ++ event_active /* chan2 */), ++ timestamp_ns); + } -+ if (status & STATUS_MASK_OV_WATT1) { ++ if ((new_status & STATUS_MASK_OV_WATT1) ^ ++ (old_status & STATUS_MASK_OV_WATT1)) { ++ event_active = !!(new_status & STATUS_MASK_OV_WATT1); + iio_push_event(indio_dev, -+ IIO_UNMOD_EVENT_CODE(IIO_POWER, 0, -+ IIO_EV_TYPE_THRESH, -+ IIO_EV_DIR_RISING), -+ timestamp_ns); ++ IIO_EVENT_CODE(IIO_POWER, ++ 0 /* diff */, ++ IIO_NO_MOD, ++ IIO_EV_DIR_RISING, ++ IIO_EV_TYPE_THRESH, ++ 0 /* chan */, ++ 0 /* chan1 */, ++ event_active /* chan2 */), ++ timestamp_ns); + } -+ if (status & STATUS_MASK_OV_WATT2) { ++ if ((new_status & STATUS_MASK_OV_WATT2) ^ ++ (old_status & STATUS_MASK_OV_WATT2)) { ++ event_active = !!(new_status & STATUS_MASK_OV_WATT2); + iio_push_event(indio_dev, -+ IIO_UNMOD_EVENT_CODE(IIO_POWER, 1, -+ IIO_EV_TYPE_THRESH, -+ IIO_EV_DIR_RISING), -+ timestamp_ns); ++ IIO_EVENT_CODE(IIO_POWER, ++ 0 /* diff */, ++ IIO_NO_MOD, ++ IIO_EV_DIR_RISING, ++ IIO_EV_TYPE_THRESH, ++ 1 /* chan */, ++ 0 /* chan1 */, ++ event_active /* chan2 */), ++ timestamp_ns); + } -+ if (status & STATUS_MASK_OV_AMP1) { ++ if ((new_status & STATUS_MASK_OV_AMP1) ^ ++ (old_status & STATUS_MASK_OV_AMP1)) { ++ event_active = !!(new_status & STATUS_MASK_OV_AMP1); + iio_push_event(indio_dev, -+ IIO_UNMOD_EVENT_CODE(IIO_CURRENT, 0, -+ IIO_EV_TYPE_THRESH, -+ IIO_EV_DIR_RISING), -+ timestamp_ns); ++ IIO_EVENT_CODE(IIO_CURRENT, ++ 0 /* diff */, ++ IIO_NO_MOD, ++ IIO_EV_DIR_RISING, ++ IIO_EV_TYPE_THRESH, ++ 0 /* chan */, ++ 0 /* chan1 */, ++ event_active /* chan2 */), ++ timestamp_ns); + } -+ if (status & STATUS_MASK_OV_AMP2) { ++ if ((new_status & STATUS_MASK_OV_AMP2) ^ ++ (old_status & STATUS_MASK_OV_AMP2)) { ++ event_active = !!(new_status & STATUS_MASK_OV_AMP2); + iio_push_event(indio_dev, -+ IIO_UNMOD_EVENT_CODE(IIO_CURRENT, 1, -+ IIO_EV_TYPE_THRESH, -+ IIO_EV_DIR_RISING), -+ timestamp_ns); ++ IIO_EVENT_CODE(IIO_CURRENT, ++ 0 /* diff */, ++ IIO_NO_MOD, ++ IIO_EV_DIR_RISING, ++ IIO_EV_TYPE_THRESH, ++ 1 /* chan */, ++ 0 /* chan1 */, ++ event_active /* chan2 */), ++ timestamp_ns); + } + ++ /* Write reset register, clearing only bits that we've processed and ++ * RESET bit if it was set at the time of the last read of STATUS */ + ret = __max78m6610_lmu_spi_reg_write(st, STATUS_RESET, -+ status & STATUS_MASK_STICKY); ++ new_status & STATUS_MASK_STICKY); + if (ret) { + pr_err("Failed to write STATUS_RESET register\n"); + goto exit_unlock; + } + ++ /* Save the current state of STATUS to be used next time as reference*/ ++ old_status = new_status; ++ if (new_status & STATUS_MASK_STICKY) { ++ mod_timer(&st->max78m6610_timer, jiffies + TIMER_PERIOD); ++ } else { ++ del_timer(&st->max78m6610_timer); ++ /* Re-enable eADC interrupts by restoring the content ++ * of MASK0 register */ ++ ret = __max78m6610_lmu_mask0_set(st); ++ if (ret) { ++ pr_err("Failed to restore MASK0 register!\n"); ++ goto exit_unlock; ++ } ++ } ++ mutex_unlock(&indio_dev->mlock); ++ return ret; ++ +exit_unlock: ++ /* if something failed setup the timer to fire again no matter what */ ++ mod_timer(&st->max78m6610_timer, jiffies + TIMER_PERIOD); + mutex_unlock(&indio_dev->mlock); + + return ret; +} + -+/** -+ * max78m6610_lmu_write_status_scan -+ * -+ * @param dev: device descriptor associated with sysfs attribute node -+ * @param attr: device sysfs attribute descriptor -+ * @param buf: data written by user to the attribute node -+ * @param len: length in bytes of data written by user -+ * -+ * This handles a write to this sysfs node from user-space, and invokes a -+ * read of the status register on the MAX78M6610+LMU if an appropriate value -+ * is written. Valid input character values are 1, y and Y -+ */ -+static ssize_t max78m6610_lmu_write_status_scan(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t len) -+{ -+ struct iio_dev *indio_dev = dev_to_iio_dev(dev); -+ int ret = 0; -+ -+ if (len < 1) -+ return -1; -+ switch (buf[0]) { -+ case '1': -+ case 'y': -+ case 'Y': -+ ret = max78m6610_lmu_status_scan(indio_dev); -+ return ret ? ret : len; -+ } -+ return -1; -+} + +/** + * max78m6610_lmu_write_int @@ -1852,16 +2355,20 @@ index 0000000..c427517 + .attrs = max78m6610_lmu_attributes, +}; + -+/* Provides an option to poll for events (useful if interrupts unavailable) */ -+static IIO_DEVICE_ATTR(do_status_scan, S_IWUSR, NULL, -+ max78m6610_lmu_write_status_scan, 0); ++/* Provides an option to poll for events (useful if interrupts unavailable) ++ * The option to poll for events is no longer supported, but we need to have at ++ * least 1 event attribute to enable the IIO events. ++ * That's why this attribute is created with no _show and no _store handlers. ++ * */ ++static IIO_DEVICE_ATTR(null, S_IWUSR, NULL, NULL, 0); ++ + +/* Need to have at least 1 event attribute to enable IIO events. + * Purposely not setting .event_mask for the channels because that would + * enable the IIO events sysfs entries which are not suitable for this driver + */ +static struct attribute *max78m6610_lmu_event_attributes[] = { -+ &iio_dev_attr_do_status_scan.dev_attr.attr, ++ &iio_dev_attr_null.dev_attr.attr, + NULL, +}; + @@ -2212,11 +2719,239 @@ index 0000000..c427517 + return 0; +} + ++ ++/* Spinlock used to lock the external and timer interrupt handlers */ ++static DEFINE_SPINLOCK(max78m6610_spinlock); ++ ++/* Pointer used to pass iio_dev from top-half to bottom-half handler */ ++static void *wq_indio_dev; ++ ++/* Workqueue used for deffering the work in the bottom-half handler */ ++static void max78m6610_lmu_irq_do_work(struct work_struct *max78m6610_lmu_wq); ++static DECLARE_WORK(max78m6610_lmu_wq, max78m6610_lmu_irq_do_work); ++ ++ ++/* max78m6610_lmu_irq_do_work ++ * ++ * @param max78m6610_lmu_wq: working item ++ * ++ * Worker function of the work queue which does the bottom-half processing of ++ * MAX78M6610 IRQ. ++ */ ++static void max78m6610_lmu_irq_do_work(struct work_struct *max78m6610_lmu_wq) ++{ ++ int ret = 0x00; ++ ++ ret = max78m6610_lmu_status_scan((struct iio_dev *)wq_indio_dev); ++ ++ if (ret) ++ pr_err("MAX78M6610 status scan failed; return code: %d\n", ret); ++} ++ ++ ++ ++/* max78m6610_lmu_irq_handler ++ * ++ * @param irq: IRQ number ++ * @param private: The dev_id cookie passed to request_irq() ++ * ++ * @return: ++ * IRQ_NONE interrupt was not from this device ++ * IRQ_HANDLED interrupt was handled by this device ++ * IRQ_WAKE_THREAD handler requests to wake the handler thread ++ * ++ * Interrupt handler for eADC IRQ. ++ */ ++static irqreturn_t max78m6610_lmu_irq_handler(int irq, void *private) ++{ ++ spin_lock(&max78m6610_spinlock); ++ ++ wq_indio_dev = private; ++ schedule_work(&max78m6610_lmu_wq); ++ ++ spin_unlock(&max78m6610_spinlock); ++ return IRQ_HANDLED; ++} ++ ++ ++/* __max78m6610_lmu_mask0_reset ++ * ++ * @param indio_dev: iio_dev pointer ++ * @return 0 on success, non-zero errno otherwise ++ * ++ * Clears all bits of MASK0 register except RELAY2 bit. ++ * ++ * If MASK0 register is completely cleared (write 0x00 to it) while the MP0 ++ * bit is already active, the MP0 bit is not de-activated. ++ * If MASK0 register's value != 0x00 and MASK0 & STATUS == 0, the MP0 bit is ++ * de-activated. ++ * ++ * (MP0 pin == 0) && (MASK0 & STATUS == 0) && (MASK0 != 0) => MP0 = 1 ++ * (interrupt line is de-asserted) ++ */ ++static inline int __max78m6610_lmu_mask0_reset(struct max78m6610_lmu_state *st) ++{ ++ return __max78m6610_lmu_spi_reg_write(st, MASK0, STATUS_MASK_RELAY2); ++} ++ ++ ++/* __max78m6610_lmu_mask0_set ++ * ++ * @param st: eADC state structure ++ * @return 0 on success, non-zero errno otherwise ++ * ++ * Sets on eADC chip the MASK0 bits corresponding to the events we want to ++ * receive an interrupt for. ++ * If one wants to modify the events which the driver receives interrupt for, he ++ * must modify MASK0_INT macro ++ */ ++static inline int __max78m6610_lmu_mask0_set(struct max78m6610_lmu_state *st) ++{ ++ return __max78m6610_lmu_spi_reg_write(st, MASK0, MASK0_INT); ++} ++ ++ ++/* max78m6610_lmu_mask0_set_default ++ * ++ * @param indio_dev: IIO device ++ * @return 0 on success, non-zero errno otherwise ++ * ++ * Read MASK0 register, check if it's default value is already MASK0_INT, ++ * otherwise set MASK0 = MASK0_INT and save defaults into flash in order to ++ * change MASK0 default value. ++ */ ++static int max78m6610_lmu_mask0_set_default(struct iio_dev *indio_dev) ++{ ++ int ret = 0; ++ unsigned mask0 = 0x00; ++ struct max78m6610_lmu_state *st = iio_priv(indio_dev); ++ ++ /* Read MASK0 value */ ++ mutex_lock(&indio_dev->mlock); ++ ret = __max78m6610_lmu_spi_reg_read(st, MASK0, &mask0); ++ if (ret) { ++ pr_err("Failed to read MASK0 register! ret: %d\n", ret); ++ goto error_unlock; ++ } ++ mutex_unlock(&indio_dev->mlock); ++ if (mask0 != MASK0_INT) { ++ /* Tell eADC what events to generate interrupt for */ ++ mutex_lock(&indio_dev->mlock); ++ ret = __max78m6610_lmu_mask0_set(st); ++ if (ret) { ++ pr_err("Failed to enable interrupts on eADC side!\n"); ++ goto error_unlock; ++ } ++ mutex_unlock(&indio_dev->mlock); ++ ++ /* Save MASK0 default to flash */ ++ ret = max78m6610_lmu_flash_save_cmd(indio_dev); ++ if (ret) { ++ pr_err("Failed to save MASK0 default to flash!\n"); ++ goto error_ret; ++ } ++ } ++ return 0; ++ ++error_unlock: ++ mutex_unlock(&indio_dev->mlock); ++error_ret: ++ return ret; ++} ++ ++ ++/* ++ * max78m6610_lmu_irq_init ++ * ++ * @param indio_dev: IIO device ++ * @return 0 on success, non-zero errno otherwise ++ * ++ * Allocate memory for IIO triger, request the IRQ for eADC, set IIO triger ++ * parent and operations; register IIO trigger; set this trigger as default ++ * trigger; configure MASK0 default value. ++ */ ++static int max78m6610_lmu_irq_init(struct iio_dev *indio_dev) ++{ ++ struct max78m6610_lmu_state *st = iio_priv(indio_dev); ++ int ret = 0; ++ ++ if (st->spi->irq < 0) { ++ pr_warn("MAX78M6610+LMU IRQ not set. spi->irq: %d\n", ++ st->spi->irq); ++ return 0; ++ } ++ ++ ret = request_irq(st->spi->irq, max78m6610_lmu_irq_handler, ++ IRQF_TRIGGER_FALLING, spi_get_device_id(st->spi)->name, ++ indio_dev); ++ if (ret) { ++ pr_err("Failed to request IRQ %d: request_irg returned %d.\n", ++ st->spi->irq, ret); ++ goto error_ret; ++ } ++ ++ /* Check and set MASK0 default */ ++ ret = max78m6610_lmu_mask0_set_default(indio_dev); ++ if (ret) { ++ pr_err("Failed to set MASK0 default!\n"); ++ goto error_free_irq; ++ } ++ ++ return 0; ++ ++error_free_irq: ++ free_irq(st->spi->irq, indio_dev); ++error_ret: ++ return ret; ++} ++ ++ ++/* max78m6610_lmu_irq_remove ++ * ++ * @param indio_dev: IIO device ++ * @return N/A ++ * ++ * Unregister IIO trigger, release the IRQ and free IIO triger memory ++ */ ++static void max78m6610_lmu_irq_remove(struct iio_dev *indio_dev) ++{ ++ int ret; ++ u32 mask0 = 0x00; ++ struct max78m6610_lmu_state *st = iio_priv(indio_dev); ++ ++ if (st->spi->irq < 0) ++ return; ++ /* Instruct MAX78M6610+LMU chip to stop generating interrupts on MP0 */ ++ mutex_lock(&indio_dev->mlock); ++ ret = __max78m6610_lmu_spi_reg_write(st, MASK0, mask0); ++ if (ret) ++ pr_warn("Failed to write MASK0 register.\n"); ++ mutex_unlock(&indio_dev->mlock); ++ ++ free_irq(st->spi->irq, indio_dev); ++} ++ ++/* max78m6610_lmu_timer_handler ++ * ++ * @param data: unused ++ * @reutnr N/A ++ * ++ * max78m6610_timer interrupt handler ++ */ ++static void max78m6610_lmu_timer_handler(unsigned long data) ++{ ++ spin_lock(&max78m6610_spinlock); ++ if (NULL != wq_indio_dev) ++ schedule_work(&max78m6610_lmu_wq); ++ spin_unlock(&max78m6610_spinlock); ++} ++ ++ +/** + * max78m6610_lmu_probe + * + * @param spi: spi device pointer -+ * @return: return 0 or standard errorids if failure ++ * @return: return 0 or standard error ids if failure + * + * device driver probe funciton for iio_dev struct initialisation. + */ @@ -2269,9 +3004,17 @@ index 0000000..c427517 + ret = max78m6610_lmu_chrdev_init(st); + if (ret) + goto error_cleanup_ring; ++ /* Init the external GPIO interrupt */ ++ ret = max78m6610_lmu_irq_init(indio_dev); ++ if (ret) ++ goto error_cleanup_chrdev; ++ /* Initialise the timer */ ++ setup_timer(&st->max78m6610_timer, max78m6610_lmu_timer_handler, 0); + + return 0; + ++error_cleanup_chrdev: ++ max78m6610_lmu_chrdev_remove(st); +error_cleanup_ring: + iio_triggered_buffer_cleanup(indio_dev); +error_free: @@ -2293,8 +3036,14 @@ index 0000000..c427517 + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct max78m6610_lmu_state *st = iio_priv(indio_dev); + ++ del_timer(&st->max78m6610_timer); ++ ++ max78m6610_lmu_irq_remove(indio_dev); ++ + max78m6610_lmu_chrdev_remove(st); ++ + iio_device_unregister(indio_dev); ++ + iio_triggered_buffer_cleanup(indio_dev); + iio_device_free(indio_dev); + @@ -2697,31 +3446,60 @@ index fbf8adf..721ed6f 100644 }; #endif /* IIO_ADC_AD7298_H_ */ +diff --git a/include/linux/platform_data/adc1x8s102.h b/include/linux/platform_data/adc1x8s102.h +new file mode 100644 +index 0000000..a32a499 +--- /dev/null ++++ b/include/linux/platform_data/adc1x8s102.h +@@ -0,0 +1,30 @@ ++/* ++ * ADC1x8S102 SPI ADC driver ++ * ++ * 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. ++ */ ++ ++ ++#ifndef __LINUX_PLATFORM_DATA_ADC1x8S102_H__ ++#define __LINUX_PLATFORM_DATA_ADC1x8S102_H__ ++ ++ ++/** ++ * struct adc1x8s102_platform_data - Platform data for the adc1x8s102 ADC driver ++ * @ext_vin: External input voltage range for all voltage input channels ++ * This is the voltage level of pin VA in millivolts ++ **/ ++struct adc1x8s102_platform_data { ++ u16 ext_vin; ++}; ++ ++#endif /* __LINUX_PLATFORM_DATA_ADC1x8S102_H__ */ diff --git a/include/linux/platform_data/max78m6610_lmu.h b/include/linux/platform_data/max78m6610_lmu.h new file mode 100644 -index 0000000..d05d513 +index 0000000..457124d --- /dev/null +++ b/include/linux/platform_data/max78m6610_lmu.h -@@ -0,0 +1,34 @@ +@@ -0,0 +1,27 @@ +/* + * Platform data for max78m6610+lmu SPI protocol driver + * Copyright(c) 2013 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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * 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. + * -+ * Contact Information: -+ * Intel Corporation ++ * 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. + */ + +#ifndef __LINUX_PLATFORM_DATA_MAX78M6610_LMU_H__ @@ -2737,6 +3515,3 @@ index 0000000..d05d513 +}; + +#endif /* IIO_ADC_MAX78M6610_LMU_H_ */ --- -1.7.4.1 - diff --git a/recipes-kernel/linux/files/0021-Quark-SPI-flash-quark.patch b/recipes-kernel/linux/files/0021-Quark-SPI-flash-quark.patch index 3d493cb..9cbc396 100644 --- a/recipes-kernel/linux/files/0021-Quark-SPI-flash-quark.patch +++ b/recipes-kernel/linux/files/0021-Quark-SPI-flash-quark.patch @@ -4,8 +4,8 @@ Date: Tue, 11 Feb 2014 16:28:26 +0000 Subject: [PATCH 21/21] Quark SPI flash --- - drivers/mtd/devices/Kconfig | 5 +++++ - drivers/mtd/devices/Makefile | 3 +-- + drivers/mtd/devices/Kconfig | 5 +++++ + drivers/mtd/devices/Makefile | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig @@ -36,6 +36,3 @@ index 395733a..4c8e399 100644 -CFLAGS_docg3.o += -I$(src) \ No newline at end of file +CFLAGS_docg3.o += -I$(src) --- -1.7.4.1 - diff --git a/recipes-kernel/linux/files/quark-standard.scc b/recipes-kernel/linux/files/quark-standard.scc new file mode 100644 index 0000000..0aaa7dd --- /dev/null +++ b/recipes-kernel/linux/files/quark-standard.scc @@ -0,0 +1,6 @@ +define KMACHINE quark +define KTYPE standard +define KARCH i386 + +kconf hardware quark.cfg + diff --git a/recipes-kernel/linux/files/quark.cfg b/recipes-kernel/linux/files/quark.cfg index 30b2e33..2a4db12 100644 --- a/recipes-kernel/linux/files/quark.cfg +++ b/recipes-kernel/linux/files/quark.cfg @@ -388,7 +388,6 @@ 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 @@ -657,7 +656,18 @@ CONFIG_BQL=y # # CONFIG_NET_PKTGEN is not set # CONFIG_HAMRADIO is not set -# CONFIG_CAN is not set +CONFIG_CAN=m +CONFIG_CAN_RAW=m +CONFIG_CAN_BCM=m +# CONFIG_CAN_GW is not set + +# +# CAN Device Drivers +# +CONFIG_CAN_VCAN=m +CONFIG_CAN_SLCAN=m +# CONFIG_CAN_DEV is not set +# CONFIG_CAN_DEBUG_DEVICES is not set # CONFIG_IRDA is not set CONFIG_BT=m CONFIG_BT_RFCOMM=m @@ -733,6 +743,8 @@ CONFIG_EXTRA_FIRMWARE="" CONFIG_DEBUG_DEVRES=y # CONFIG_SYS_HYPERVISOR is not set # CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=m CONFIG_DMA_SHARED_BUFFER=y # CONFIG_CMA is not set @@ -1212,7 +1224,7 @@ CONFIG_SERIAL_8250=y # CONFIG_SERIAL_8250_PNP is not set CONFIG_SERIAL_8250_CONSOLE=y CONFIG_FIX_EARLYCON_MEM=y -CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_PCI=m CONFIG_SERIAL_8250_NR_UARTS=8 CONFIG_SERIAL_8250_RUNTIME_UARTS=2 CONFIG_SERIAL_8250_EXTENDED=y @@ -1235,7 +1247,8 @@ CONFIG_SERIAL_CORE_CONSOLE=y # CONFIG_SERIAL_ALTERA_JTAGUART is not set # CONFIG_SERIAL_ALTERA_UART is not set # CONFIG_SERIAL_IFX6X60 is not set -CONFIG_SERIAL_QUARK_UART=m +CONFIG_SERIAL_QUARK_UART=y +CONFIG_SERIAL_QUARK_UART_CONSOLE=y # CONFIG_SERIAL_PCH_UART is not set # CONFIG_SERIAL_ARC is not set # CONFIG_TTY_PRINTK is not set @@ -1394,7 +1407,8 @@ CONFIG_GPIO_SCH=m # # CONFIG_GPIO_MAX7300 is not set # CONFIG_GPIO_MAX732X is not set -# CONFIG_GPIO_PCA953X is not set +CONFIG_GPIO_PCA953X=m +CONFIG_GPIO_PCA953X_IRQ=y # CONFIG_GPIO_PCF857X is not set # CONFIG_GPIO_SX150X is not set # CONFIG_GPIO_ADP5588 is not set @@ -1526,6 +1540,7 @@ CONFIG_MFD_CORE=y # CONFIG_MFD_CS5535 is not set # CONFIG_MFD_TIMBERDALE is not set CONFIG_CY8C9540A=m +CONFIG_MFD_PCA9685=m CONFIG_INTEL_QRK_GIP=m CONFIG_INTEL_QRK_GIP_TEST=m CONFIG_LPC_SCH=y @@ -2279,7 +2294,7 @@ CONFIG_DMADEVICES=y # # DMA Devices # -CONFIG_INTEL_MID_DMAC=m +CONFIG_INTEL_MID_DMAC=y # CONFIG_INTEL_IOATDMA is not set # CONFIG_TIMB_DMA is not set # CONFIG_PCH_DMA is not set @@ -2363,6 +2378,7 @@ CONFIG_STAGING=y # CONFIG_ADT7410 is not set # CONFIG_AD7280 is not set CONFIG_MAX78M6610_LMU=m +CONFIG_ADC1x8S102=m # # Analog digital bi-direction converters @@ -2997,6 +3013,7 @@ CONFIG_CRYPTO_ANSI_CPRNG=m CONFIG_CRYPTO_HW=y # CONFIG_CRYPTO_DEV_PADLOCK is not set # CONFIG_CRYPTO_DEV_GEODE is not set +# CONFIG_CRYPTO_DEV_HIFN_795X is not set # CONFIG_ASYMMETRIC_KEY_TYPE is not set CONFIG_HAVE_KVM=y # CONFIG_VIRTUALIZATION is not set @@ -3028,6 +3045,8 @@ CONFIG_CRC32_SLICEBY8=y # CONFIG_CRC8 is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=m +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y # CONFIG_XZ_DEC is not set # CONFIG_XZ_DEC_BCJ is not set CONFIG_DECOMPRESS_GZIP=y |